X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fmedia%2FIR%2Fir-nec-decoder.c;h=02682e617fae886daab93441fe301c5f443feb40;hb=724e2495502a98aaa3f93c404472a991da8ff857;hp=0b50060ffbafae18cb5e76af93f477943fe71f93;hpb=a374fef4437abd0a1ee27afe0cca7a55425c1c3c;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/media/IR/ir-nec-decoder.c b/drivers/media/IR/ir-nec-decoder.c index 0b50060..02682e6 100644 --- a/drivers/media/IR/ir-nec-decoder.c +++ b/drivers/media/IR/ir-nec-decoder.c @@ -13,40 +13,39 @@ */ #include +#include -/* Start time: 4.5 ms + 560 us of the next pulse */ -#define MIN_START_TIME (3900000 + 560000) -#define MAX_START_TIME (5100000 + 560000) - -/* Bit 1 time: 2.25ms us */ -#define MIN_BIT1_TIME 2050000 -#define MAX_BIT1_TIME 2450000 - -/* Bit 0 time: 1.12ms us */ -#define MIN_BIT0_TIME 920000 -#define MAX_BIT0_TIME 1320000 - -/* Total IR code is 110 ms, including the 9 ms for the start pulse */ -#define MAX_NEC_TIME 4000000 - -/* Total IR code is 110 ms, including the 9 ms for the start pulse */ -#define MIN_REPEAT_TIME 99000000 -#define MAX_REPEAT_TIME 112000000 - -/* Repeat time: 2.25ms us */ -#define MIN_REPEAT_START_TIME 2050000 -#define MAX_REPEAT_START_TIME 3000000 - -#define REPEAT_TIME 240 /* ms */ +#define NEC_NBITS 32 +#define NEC_UNIT 562500 /* ns */ +#define NEC_HEADER_PULSE PULSE(16) +#define NEC_HEADER_SPACE SPACE(8) +#define NEC_REPEAT_SPACE SPACE(4) +#define NEC_BIT_PULSE PULSE(1) +#define NEC_BIT_0_SPACE SPACE(1) +#define NEC_BIT_1_SPACE SPACE(3) /* Used to register nec_decoder clients */ static LIST_HEAD(decoder_list); -static spinlock_t decoder_lock; +static DEFINE_SPINLOCK(decoder_lock); + +enum nec_state { + STATE_INACTIVE, + STATE_HEADER_SPACE, + STATE_BIT_PULSE, + STATE_BIT_SPACE, + STATE_TRAILER_PULSE, + STATE_TRAILER_SPACE, +}; struct decoder_data { struct list_head list; struct ir_input_dev *ir_dev; int enabled:1; + + /* State machine control */ + enum nec_state state; + u32 nec_bits; + unsigned count; }; @@ -56,7 +55,6 @@ struct decoder_data { * * Returns the struct decoder_data that corresponds to a device */ - static struct decoder_data *get_decoder_data(struct ir_input_dev *ir_dev) { struct decoder_data *data = NULL; @@ -117,163 +115,130 @@ static struct attribute_group decoder_attribute_group = { .attrs = decoder_attributes, }; - -/** is_repeat - Check if it is a NEC repeat event +/** + * ir_nec_decode() - Decode one NEC pulse or space * @input_dev: the struct input_dev descriptor of the device - * @pos: the position of the first event - * @len: the length of the buffer + * @duration: duration in ns of pulse/space + * + * This function returns -EINVAL if the pulse violates the state machine */ -static int is_repeat(struct ir_raw_event *evs, int len, int pos) +static int ir_nec_decode(struct input_dev *input_dev, s64 duration) { - if ((evs[pos].delta.tv_nsec < MIN_REPEAT_START_TIME) || - (evs[pos].delta.tv_nsec > MAX_REPEAT_START_TIME)) - return 0; + struct decoder_data *data; + struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); + int u; + u32 scancode; + u8 address, not_address, command, not_command; - if (++pos >= len) - return 0; + data = get_decoder_data(ir_dev); + if (!data) + return -EINVAL; - if ((evs[pos].delta.tv_nsec < MIN_REPEAT_TIME) || - (evs[pos].delta.tv_nsec > MAX_REPEAT_TIME)) + if (!data->enabled) return 0; - return 1; -} + if (IS_RESET(duration)) { + data->state = STATE_INACTIVE; + return 0; + } -/** - * __ir_nec_decode() - Decode one NEC pulsecode - * @input_dev: the struct input_dev descriptor of the device - * @evs: event array with type/duration of pulse/space - * @len: length of the array - * @pos: position to start seeking for a code - * This function returns -EINVAL if no pulse got decoded, - * 0 if buffer is empty and 1 if one keycode were handled. - */ -static int __ir_nec_decode(struct input_dev *input_dev, - struct ir_raw_event *evs, - int len, int *pos) -{ - struct ir_input_dev *ir = input_get_drvdata(input_dev); - int count = -1; - int ircode = 0, not_code = 0; - - /* Be sure that the first event is an start one and is a pulse */ - for (; *pos < len; (*pos)++) { - /* Very long delays are considered as start events */ - if (evs[*pos].delta.tv_nsec > MAX_NEC_TIME) - break; - if (evs[*pos].type & IR_START_EVENT) - break; - IR_dprintk(1, "%luus: Spurious NEC %s\n", - (evs[*pos].delta.tv_nsec + 500) / 1000, - (evs[*pos].type & IR_SPACE) ? "space" : "pulse"); + u = TO_UNITS(duration, NEC_UNIT); + if (DURATION(u) == 0) + goto out; - } - if (*pos >= len) - return 0; + IR_dprintk(2, "NEC decode started at state %d (%i units, %ius)\n", + data->state, u, TO_US(duration)); - (*pos)++; /* First event doesn't contain data */ + switch (data->state) { - if (evs[*pos].type != IR_PULSE) - goto err; + case STATE_INACTIVE: + if (u == NEC_HEADER_PULSE) { + data->count = 0; + data->state = STATE_HEADER_SPACE; + } + return 0; - /* Check if it is a NEC repeat event */ - if (is_repeat(evs, len, *pos)) { - *pos += 2; - if (ir->keypressed) { + case STATE_HEADER_SPACE: + if (u == NEC_HEADER_SPACE) { + data->state = STATE_BIT_PULSE; + return 0; + } else if (u == NEC_REPEAT_SPACE) { ir_repeat(input_dev); - IR_dprintk(1, "NEC repeat event\n"); - return 1; - } else { - IR_dprintk(1, "missing NEC repeat event\n"); + IR_dprintk(1, "Repeat last key\n"); + data->state = STATE_TRAILER_PULSE; return 0; } - } + break; - /* First space should have 4.5 ms otherwise is not NEC protocol */ - if ((evs[*pos].delta.tv_nsec < MIN_START_TIME) || - (evs[*pos].delta.tv_nsec > MAX_START_TIME)) - goto err; - - count = 0; - for ((*pos)++; *pos < len; (*pos)++) { - int bit; - if ((evs[*pos].delta.tv_nsec > MIN_BIT1_TIME) && - (evs[*pos].delta.tv_nsec < MAX_BIT1_TIME)) - bit = 1; - else if ((evs[*pos].delta.tv_nsec > MIN_BIT0_TIME) && - (evs[*pos].delta.tv_nsec < MAX_BIT0_TIME)) - bit = 0; - else - goto err; - - if (bit) { - int shift = count; - /* Address first, then command */ - if (shift < 8) { - shift += 8; - ircode |= 1 << shift; - } else if (shift < 16) { - not_code |= 1 << shift; - } else if (shift < 24) { - shift -= 16; - ircode |= 1 << shift; - } else { - shift -= 24; - not_code |= 1 << shift; - } + case STATE_BIT_PULSE: + if (u == NEC_BIT_PULSE) { + data->state = STATE_BIT_SPACE; + return 0; } - if (++count == 32) + break; + + case STATE_BIT_SPACE: + if (u != NEC_BIT_0_SPACE && u != NEC_BIT_1_SPACE) break; - } - (*pos)++; - - /* - * Fixme: may need to accept Extended NEC protocol? - */ - if ((ircode & ~not_code) != ircode) { - IR_dprintk(1, "NEC checksum error: code 0x%04x, not-code 0x%04x\n", - ircode, not_code); - return -EINVAL; - } - IR_dprintk(1, "NEC scancode 0x%04x\n", ircode); - ir_keydown(input_dev, ircode, 0); + data->nec_bits <<= 1; + if (u == NEC_BIT_1_SPACE) + data->nec_bits |= 1; + data->count++; - return 1; -err: - IR_dprintk(1, "NEC decoded failed at bit %d (%s) while decoding %luus time\n", - count, - (evs[*pos].type & IR_SPACE) ? "space" : "pulse", - (evs[*pos].delta.tv_nsec + 500) / 1000); + if (data->count != NEC_NBITS) { + data->state = STATE_BIT_PULSE; + return 0; + } - return -EINVAL; -} + address = bitrev8((data->nec_bits >> 24) & 0xff); + not_address = bitrev8((data->nec_bits >> 16) & 0xff); + command = bitrev8((data->nec_bits >> 8) & 0xff); + not_command = bitrev8((data->nec_bits >> 0) & 0xff); -/** - * __ir_nec_decode() - Decodes all NEC pulsecodes on a given array - * @input_dev: the struct input_dev descriptor of the device - * @evs: event array with type/duration of pulse/space - * @len: length of the array - * This function returns the number of decoded pulses - */ -static int ir_nec_decode(struct input_dev *input_dev, - struct ir_raw_event *evs, - int len) -{ - struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); - struct decoder_data *data; - int pos = 0; - int rc = 0; + if ((command ^ not_command) != 0xff) { + IR_dprintk(1, "NEC checksum error: received 0x%08x\n", + data->nec_bits); + break; + } - data = get_decoder_data(ir_dev); - if (!data || !data->enabled) + if ((address ^ not_address) != 0xff) { + /* Extended NEC */ + scancode = address << 16 | + not_address << 8 | + command; + IR_dprintk(1, "NEC (Ext) scancode 0x%06x\n", scancode); + } else { + /* normal NEC */ + scancode = address << 8 | command; + IR_dprintk(1, "NEC scancode 0x%04x\n", scancode); + } + + ir_keydown(input_dev, scancode, 0); + data->state = STATE_TRAILER_PULSE; return 0; - while (pos < len) { - if (__ir_nec_decode(input_dev, evs, len, &pos) > 0) - rc++; + case STATE_TRAILER_PULSE: + if (u > 0) { + data->state = STATE_TRAILER_SPACE; + return 0; + } + break; + + case STATE_TRAILER_SPACE: + if (u < 0) { + data->state = STATE_INACTIVE; + return 0; + } + + break; } - return rc; + +out: + IR_dprintk(1, "NEC decode failed at state %d (%i units, %ius)\n", + data->state, u, TO_US(duration)); + data->state = STATE_INACTIVE; + return -EINVAL; } static int ir_nec_register(struct input_dev *input_dev)