Message ID | 1386947579-26703-7-git-send-email-james.hogan@imgtec.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Em Fri, 13 Dec 2013 15:12:54 +0000 James Hogan <james.hogan@imgtec.com> escreveu: > Add an img-ir module for decoding the NEC and extended NEC infrared > protocols. > > Signed-off-by: James Hogan <james.hogan@imgtec.com> > Cc: Mauro Carvalho Chehab <m.chehab@samsung.com> > Cc: linux-media@vger.kernel.org > --- > drivers/media/rc/img-ir/Kconfig | 7 ++ > drivers/media/rc/img-ir/Makefile | 1 + > drivers/media/rc/img-ir/img-ir-nec.c | 149 +++++++++++++++++++++++++++++++++++ > 3 files changed, 157 insertions(+) > create mode 100644 drivers/media/rc/img-ir/img-ir-nec.c > > diff --git a/drivers/media/rc/img-ir/Kconfig b/drivers/media/rc/img-ir/Kconfig > index 60eaba6a0843..44d00227c6c4 100644 > --- a/drivers/media/rc/img-ir/Kconfig > +++ b/drivers/media/rc/img-ir/Kconfig > @@ -24,3 +24,10 @@ config IR_IMG_HW > signals in hardware. This is more reliable, consumes less processing > power since only a single interrupt is received for each scancode, > and allows an IR scancode to be used as a wake event. > + > +config IR_IMG_NEC > + tristate "NEC protocol support" > + depends on IR_IMG && IR_IMG_HW > + help > + Say Y or M here to enable support for the NEC and extended NEC > + protocols in the ImgTec infrared decoder block. > diff --git a/drivers/media/rc/img-ir/Makefile b/drivers/media/rc/img-ir/Makefile > index 4ef86edec873..f3052878f092 100644 > --- a/drivers/media/rc/img-ir/Makefile > +++ b/drivers/media/rc/img-ir/Makefile > @@ -4,3 +4,4 @@ img-ir-$(CONFIG_IR_IMG_HW) += img-ir-hw.o > img-ir-objs := $(img-ir-y) > > obj-$(CONFIG_IR_IMG) += img-ir.o > +obj-$(CONFIG_IR_IMG_NEC) += img-ir-nec.o > diff --git a/drivers/media/rc/img-ir/img-ir-nec.c b/drivers/media/rc/img-ir/img-ir-nec.c > new file mode 100644 > index 000000000000..ba376caafaf2 > --- /dev/null > +++ b/drivers/media/rc/img-ir/img-ir-nec.c > @@ -0,0 +1,149 @@ > +/* > + * ImgTec IR Decoder setup for NEC protocol. > + * > + * Copyright 2010-2013 Imagination Technologies Ltd. > + */ > + > +#include <linux/module.h> > + > +#include "img-ir-hw.h" > + > +/* Convert NEC data to a scancode */ > +static int img_ir_nec_scancode(int len, u64 raw, u64 protocols) > +{ > + unsigned int addr, addr_inv, data, data_inv; > + int scancode; > + /* a repeat code has no data */ > + if (!len) > + return IMG_IR_REPEATCODE; > + if (len != 32) > + return IMG_IR_ERR_INVALID; > + addr = (raw >> 0) & 0xff; > + addr_inv = (raw >> 8) & 0xff; > + data = (raw >> 16) & 0xff; > + data_inv = (raw >> 24) & 0xff; > + /* Validate data */ > + if ((data_inv ^ data) != 0xff) > + return IMG_IR_ERR_INVALID; > + > + if ((addr_inv ^ addr) != 0xff) { > + /* Extended NEC */ > + scancode = addr << 16 | > + addr_inv << 8 | > + data; > + } else { > + /* Normal NEC */ > + scancode = addr << 8 | > + data; > + } There are some types of NEC extended that uses the full 32 bits as scancodes. Those are used at least on Apple and TiVo remote controllers. > + return scancode; > +} > + > +/* Convert NEC scancode to NEC data filter */ > +static int img_ir_nec_filter(const struct img_ir_sc_filter *in, > + struct img_ir_filter *out, u64 protocols) > +{ > + unsigned int addr, addr_inv, data, data_inv; > + unsigned int addr_m, addr_inv_m, data_m; > + > + data = in->data & 0xff; > + data_m = in->mask & 0xff; > + data_inv = data ^ 0xff; > + > + if (in->data & 0xff000000) > + return -EINVAL; > + > + if (in->data & 0x00ff0000) { > + /* Extended NEC */ > + addr = (in->data >> 16) & 0xff; > + addr_m = (in->mask >> 16) & 0xff; > + addr_inv = (in->data >> 8) & 0xff; > + addr_inv_m = (in->mask >> 8) & 0xff; > + } else { > + /* Normal NEC */ > + addr = (in->data >> 8) & 0xff; > + addr_m = (in->mask >> 8) & 0xff; > + addr_inv = addr ^ 0xff; > + addr_inv_m = addr_m; > + } > + > + out->data = data_inv << 24 | > + data << 16 | > + addr_inv << 8 | > + addr; > + out->mask = data_m << 24 | > + data_m << 16 | > + addr_inv_m << 8 | > + addr_m; > + return 0; > +} > + > +/* > + * NEC decoder > + * See also http://www.sbprojects.com/knowledge/ir/nec.php > + * http://wiki.altium.com/display/ADOH/NEC+Infrared+Transmission+Protocol > + */ > +static struct img_ir_decoder img_ir_nec = { > + .type = RC_BIT_NEC, > + .control = { > + .decoden = 1, > + .code_type = IMG_IR_CODETYPE_PULSEDIST, > + }, > + /* main timings */ > + .unit = 562500, /* 562.5 us */ > + .timings = { > + /* leader symbol */ > + .ldr = { > + .pulse = { 16 /* 9ms */ }, > + .space = { 8 /* 4.5ms */ }, > + }, > + /* 0 symbol */ > + .s00 = { > + .pulse = { 1 /* 562.5 us */ }, > + .space = { 1 /* 562.5 us */ }, > + }, > + /* 1 symbol */ > + .s01 = { > + .pulse = { 1 /* 562.5 us */ }, > + .space = { 3 /* 1687.5 us */ }, > + }, > + /* free time */ > + .ft = { > + .minlen = 32, > + .maxlen = 32, > + .ft_min = 10, /* 5.625 ms */ > + }, > + }, > + /* repeat codes */ > + .repeat = 108, /* 108 ms */ > + .rtimings = { > + /* leader symbol */ > + .ldr = { > + .space = { 4 /* 2.25 ms */ }, > + }, > + /* free time */ > + .ft = { > + .minlen = 0, /* repeat code has no data */ > + .maxlen = 0, > + }, > + }, > + /* scancode logic */ > + .scancode = img_ir_nec_scancode, > + .filter = img_ir_nec_filter, > +}; > + > +static int __init img_ir_nec_init(void) > +{ > + return img_ir_register_decoder(&img_ir_nec); > +} > +module_init(img_ir_nec_init); > + > +static void __exit img_ir_nec_exit(void) > +{ > + img_ir_unregister_decoder(&img_ir_nec); > +} > +module_exit(img_ir_nec_exit); > + > +MODULE_AUTHOR("Imagination Technologies Ltd."); > +MODULE_DESCRIPTION("ImgTec IR NEC protocol support"); > +MODULE_LICENSE("GPL");
On 22/12/13 13:49, Mauro Carvalho Chehab wrote: > Em Fri, 13 Dec 2013 15:12:54 +0000 > James Hogan <james.hogan@imgtec.com> escreveu: >> +/* Convert NEC data to a scancode */ >> +static int img_ir_nec_scancode(int len, u64 raw, u64 protocols) >> +{ >> + unsigned int addr, addr_inv, data, data_inv; >> + int scancode; >> + /* a repeat code has no data */ >> + if (!len) >> + return IMG_IR_REPEATCODE; >> + if (len != 32) >> + return IMG_IR_ERR_INVALID; >> + addr = (raw >> 0) & 0xff; >> + addr_inv = (raw >> 8) & 0xff; >> + data = (raw >> 16) & 0xff; >> + data_inv = (raw >> 24) & 0xff; >> + /* Validate data */ >> + if ((data_inv ^ data) != 0xff) >> + return IMG_IR_ERR_INVALID; >> + >> + if ((addr_inv ^ addr) != 0xff) { >> + /* Extended NEC */ >> + scancode = addr << 16 | >> + addr_inv << 8 | >> + data; >> + } else { >> + /* Normal NEC */ >> + scancode = addr << 8 | >> + data; >> + } > > There are some types of NEC extended that uses the full 32 bits as > scancodes. Those are used at least on Apple and TiVo remote controllers. Ooh, I hadn't spotted that patch. I'll make the necessary changes. I notice that the scancode produced by the raw NEC decoder is the raw non-bit-reversed version of the bits received, whereas for normal and extended NEC the scancode fields are bit reversed. The TiVo keymap appears to confirm that this is essentially backwards: NEC:0xAAaaCCcc (AA=address, aa=not A, CC=command, cc=not command) bitrev(CCcc): { 0xa10c140b, KEY_NUMERIC_1 }, d028 { 0xa10c940b, KEY_NUMERIC_2 }, d029 { 0xa10c540b, KEY_NUMERIC_3 }, d02a { 0xa10cd40b, KEY_NUMERIC_4 }, d02b { 0xa10c340b, KEY_NUMERIC_5 }, d02c { 0xa10cb40b, KEY_NUMERIC_6 }, d02d { 0xa10c740b, KEY_NUMERIC_7 }, d02e { 0xa10cf40b, KEY_NUMERIC_8 }, d02f { 0x0085302f, KEY_NUMERIC_8 }, { 0xa10c0c03, KEY_NUMERIC_9 }, c030 { 0xa10c8c03, KEY_NUMERIC_0 }, c031 Clearly CC is supposed to be the LSB of the command. Is it possible to reverse the bits in these scancode encodings (and of course update the keymaps) or does this constitute a stable ABI that is now too late to change? IMO the following encoding would make much better sense for 32bit NEC scancodes: bits 31:16 = bitrev(AAaa) bits 15:0 = bitrev(CCcc) I.e. just bit reverse each 16bit half. This puts the LSB of the command field in the LSB of the scancode which I think is important, and treats the address field as a continuous 16bits (even though the extended NEC scancodes have address bytes swapped for some reason - although for address it doesn't really matter). If we assume the high byte of the address (aa) is always non-zero, then the scancodes can be distinguished. Cheers James -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/drivers/media/rc/img-ir/Kconfig b/drivers/media/rc/img-ir/Kconfig index 60eaba6a0843..44d00227c6c4 100644 --- a/drivers/media/rc/img-ir/Kconfig +++ b/drivers/media/rc/img-ir/Kconfig @@ -24,3 +24,10 @@ config IR_IMG_HW signals in hardware. This is more reliable, consumes less processing power since only a single interrupt is received for each scancode, and allows an IR scancode to be used as a wake event. + +config IR_IMG_NEC + tristate "NEC protocol support" + depends on IR_IMG && IR_IMG_HW + help + Say Y or M here to enable support for the NEC and extended NEC + protocols in the ImgTec infrared decoder block. diff --git a/drivers/media/rc/img-ir/Makefile b/drivers/media/rc/img-ir/Makefile index 4ef86edec873..f3052878f092 100644 --- a/drivers/media/rc/img-ir/Makefile +++ b/drivers/media/rc/img-ir/Makefile @@ -4,3 +4,4 @@ img-ir-$(CONFIG_IR_IMG_HW) += img-ir-hw.o img-ir-objs := $(img-ir-y) obj-$(CONFIG_IR_IMG) += img-ir.o +obj-$(CONFIG_IR_IMG_NEC) += img-ir-nec.o diff --git a/drivers/media/rc/img-ir/img-ir-nec.c b/drivers/media/rc/img-ir/img-ir-nec.c new file mode 100644 index 000000000000..ba376caafaf2 --- /dev/null +++ b/drivers/media/rc/img-ir/img-ir-nec.c @@ -0,0 +1,149 @@ +/* + * ImgTec IR Decoder setup for NEC protocol. + * + * Copyright 2010-2013 Imagination Technologies Ltd. + */ + +#include <linux/module.h> + +#include "img-ir-hw.h" + +/* Convert NEC data to a scancode */ +static int img_ir_nec_scancode(int len, u64 raw, u64 protocols) +{ + unsigned int addr, addr_inv, data, data_inv; + int scancode; + /* a repeat code has no data */ + if (!len) + return IMG_IR_REPEATCODE; + if (len != 32) + return IMG_IR_ERR_INVALID; + addr = (raw >> 0) & 0xff; + addr_inv = (raw >> 8) & 0xff; + data = (raw >> 16) & 0xff; + data_inv = (raw >> 24) & 0xff; + /* Validate data */ + if ((data_inv ^ data) != 0xff) + return IMG_IR_ERR_INVALID; + + if ((addr_inv ^ addr) != 0xff) { + /* Extended NEC */ + scancode = addr << 16 | + addr_inv << 8 | + data; + } else { + /* Normal NEC */ + scancode = addr << 8 | + data; + } + return scancode; +} + +/* Convert NEC scancode to NEC data filter */ +static int img_ir_nec_filter(const struct img_ir_sc_filter *in, + struct img_ir_filter *out, u64 protocols) +{ + unsigned int addr, addr_inv, data, data_inv; + unsigned int addr_m, addr_inv_m, data_m; + + data = in->data & 0xff; + data_m = in->mask & 0xff; + data_inv = data ^ 0xff; + + if (in->data & 0xff000000) + return -EINVAL; + + if (in->data & 0x00ff0000) { + /* Extended NEC */ + addr = (in->data >> 16) & 0xff; + addr_m = (in->mask >> 16) & 0xff; + addr_inv = (in->data >> 8) & 0xff; + addr_inv_m = (in->mask >> 8) & 0xff; + } else { + /* Normal NEC */ + addr = (in->data >> 8) & 0xff; + addr_m = (in->mask >> 8) & 0xff; + addr_inv = addr ^ 0xff; + addr_inv_m = addr_m; + } + + out->data = data_inv << 24 | + data << 16 | + addr_inv << 8 | + addr; + out->mask = data_m << 24 | + data_m << 16 | + addr_inv_m << 8 | + addr_m; + return 0; +} + +/* + * NEC decoder + * See also http://www.sbprojects.com/knowledge/ir/nec.php + * http://wiki.altium.com/display/ADOH/NEC+Infrared+Transmission+Protocol + */ +static struct img_ir_decoder img_ir_nec = { + .type = RC_BIT_NEC, + .control = { + .decoden = 1, + .code_type = IMG_IR_CODETYPE_PULSEDIST, + }, + /* main timings */ + .unit = 562500, /* 562.5 us */ + .timings = { + /* leader symbol */ + .ldr = { + .pulse = { 16 /* 9ms */ }, + .space = { 8 /* 4.5ms */ }, + }, + /* 0 symbol */ + .s00 = { + .pulse = { 1 /* 562.5 us */ }, + .space = { 1 /* 562.5 us */ }, + }, + /* 1 symbol */ + .s01 = { + .pulse = { 1 /* 562.5 us */ }, + .space = { 3 /* 1687.5 us */ }, + }, + /* free time */ + .ft = { + .minlen = 32, + .maxlen = 32, + .ft_min = 10, /* 5.625 ms */ + }, + }, + /* repeat codes */ + .repeat = 108, /* 108 ms */ + .rtimings = { + /* leader symbol */ + .ldr = { + .space = { 4 /* 2.25 ms */ }, + }, + /* free time */ + .ft = { + .minlen = 0, /* repeat code has no data */ + .maxlen = 0, + }, + }, + /* scancode logic */ + .scancode = img_ir_nec_scancode, + .filter = img_ir_nec_filter, +}; + +static int __init img_ir_nec_init(void) +{ + return img_ir_register_decoder(&img_ir_nec); +} +module_init(img_ir_nec_init); + +static void __exit img_ir_nec_exit(void) +{ + img_ir_unregister_decoder(&img_ir_nec); +} +module_exit(img_ir_nec_exit); + +MODULE_AUTHOR("Imagination Technologies Ltd."); +MODULE_DESCRIPTION("ImgTec IR NEC protocol support"); +MODULE_LICENSE("GPL");
Add an img-ir module for decoding the NEC and extended NEC infrared protocols. Signed-off-by: James Hogan <james.hogan@imgtec.com> Cc: Mauro Carvalho Chehab <m.chehab@samsung.com> Cc: linux-media@vger.kernel.org --- drivers/media/rc/img-ir/Kconfig | 7 ++ drivers/media/rc/img-ir/Makefile | 1 + drivers/media/rc/img-ir/img-ir-nec.c | 149 +++++++++++++++++++++++++++++++++++ 3 files changed, 157 insertions(+) create mode 100644 drivers/media/rc/img-ir/img-ir-nec.c