diff options
Diffstat (limited to 'drivers/media/IR/ir-rc6-decoder.c')
-rw-r--r-- | drivers/media/IR/ir-rc6-decoder.c | 221 |
1 files changed, 114 insertions, 107 deletions
diff --git a/drivers/media/IR/ir-rc6-decoder.c b/drivers/media/IR/ir-rc6-decoder.c index ccc5be240f82..2bf479f4f1bc 100644 --- a/drivers/media/IR/ir-rc6-decoder.c +++ b/drivers/media/IR/ir-rc6-decoder.c @@ -26,8 +26,12 @@ #define RC6_0_NBITS 16 #define RC6_6A_SMALL_NBITS 24 #define RC6_6A_LARGE_NBITS 32 -#define RC6_PREFIX_PULSE PULSE(6) -#define RC6_PREFIX_SPACE SPACE(2) +#define RC6_PREFIX_PULSE (6 * RC6_UNIT) +#define RC6_PREFIX_SPACE (2 * RC6_UNIT) +#define RC6_BIT_START (1 * RC6_UNIT) +#define RC6_BIT_END (1 * RC6_UNIT) +#define RC6_TOGGLE_START (2 * RC6_UNIT) +#define RC6_TOGGLE_END (2 * RC6_UNIT) #define RC6_MODE_MASK 0x07 /* for the header bits */ #define RC6_STARTBIT_MASK 0x08 /* for the header bits */ #define RC6_6A_MCE_TOGGLE_MASK 0x8000 /* for the body bits */ @@ -63,7 +67,7 @@ struct decoder_data { enum rc6_state state; u8 header; u32 body; - int last_unit; + struct ir_raw_event prev_ev; bool toggle; unsigned count; unsigned wanted_bits; @@ -152,17 +156,16 @@ static enum rc6_mode rc6_mode(struct decoder_data *data) { /** * ir_rc6_decode() - Decode one RC6 pulse or space * @input_dev: the struct input_dev descriptor of the device - * @duration: duration of pulse/space in ns + * @ev: the struct ir_raw_event descriptor of the pulse/space * * This function returns -EINVAL if the pulse violates the state machine */ -static int ir_rc6_decode(struct input_dev *input_dev, s64 duration) +static int ir_rc6_decode(struct input_dev *input_dev, struct ir_raw_event ev) { struct decoder_data *data; struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); u32 scancode; u8 toggle; - int u; data = get_decoder_data(ir_dev); if (!data) @@ -171,140 +174,144 @@ static int ir_rc6_decode(struct input_dev *input_dev, s64 duration) if (!data->enabled) return 0; - if (IS_RESET(duration)) { + if (IS_RESET(ev)) { data->state = STATE_INACTIVE; return 0; } - u = TO_UNITS(duration, RC6_UNIT); - if (DURATION(u) == 0) + if (!geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2)) goto out; again: - IR_dprintk(2, "RC6 decode started at state %i (%i units, %ius)\n", - data->state, u, TO_US(duration)); + IR_dprintk(2, "RC6 decode started at state %i (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); - if (DURATION(u) == 0 && data->state != STATE_FINISHED) + if (!geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2)) return 0; switch (data->state) { case STATE_INACTIVE: - if (u >= RC6_PREFIX_PULSE - 1 && u <= RC6_PREFIX_PULSE + 1) { - data->state = STATE_PREFIX_SPACE; - data->count = 0; - return 0; - } - break; + if (!ev.pulse) + break; + + /* Note: larger margin on first pulse since each RC6_UNIT + is quite short and some hardware takes some time to + adjust to the signal */ + if (!eq_margin(ev.duration, RC6_PREFIX_PULSE, RC6_UNIT)) + break; + + data->state = STATE_PREFIX_SPACE; + data->count = 0; + return 0; case STATE_PREFIX_SPACE: - if (u == RC6_PREFIX_SPACE) { - data->state = STATE_HEADER_BIT_START; - return 0; - } - break; + if (ev.pulse) + break; + + if (!eq_margin(ev.duration, RC6_PREFIX_SPACE, RC6_UNIT / 2)) + break; + + data->state = STATE_HEADER_BIT_START; + return 0; case STATE_HEADER_BIT_START: - if (DURATION(u) == 1) { - data->header <<= 1; - if (IS_PULSE(u)) - data->header |= 1; - data->count++; - data->last_unit = u; - data->state = STATE_HEADER_BIT_END; - return 0; - } - break; + if (!eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2)) + break; + + data->header <<= 1; + if (ev.pulse) + data->header |= 1; + data->count++; + data->prev_ev = ev; + data->state = STATE_HEADER_BIT_END; + return 0; case STATE_HEADER_BIT_END: - if (IS_TRANSITION(u, data->last_unit)) { - if (data->count == RC6_HEADER_NBITS) - data->state = STATE_TOGGLE_START; - else - data->state = STATE_HEADER_BIT_START; + if (!is_transition(&ev, &data->prev_ev)) + break; - DECREASE_DURATION(u, 1); - goto again; - } - break; + if (data->count == RC6_HEADER_NBITS) + data->state = STATE_TOGGLE_START; + else + data->state = STATE_HEADER_BIT_START; + + decrease_duration(&ev, RC6_BIT_END); + goto again; case STATE_TOGGLE_START: - if (DURATION(u) == 2) { - data->toggle = IS_PULSE(u); - data->last_unit = u; - data->state = STATE_TOGGLE_END; - return 0; - } - break; + if (!eq_margin(ev.duration, RC6_TOGGLE_START, RC6_UNIT / 2)) + break; + + data->toggle = ev.pulse; + data->prev_ev = ev; + data->state = STATE_TOGGLE_END; + return 0; case STATE_TOGGLE_END: - if (IS_TRANSITION(u, data->last_unit) && DURATION(u) >= 2) { - data->state = STATE_BODY_BIT_START; - data->last_unit = u; - DECREASE_DURATION(u, 2); - data->count = 0; + if (!is_transition(&ev, &data->prev_ev) || + !geq_margin(ev.duration, RC6_TOGGLE_END, RC6_UNIT / 2)) + break; - if (!(data->header & RC6_STARTBIT_MASK)) { - IR_dprintk(1, "RC6 invalid start bit\n"); - break; - } + if (!(data->header & RC6_STARTBIT_MASK)) { + IR_dprintk(1, "RC6 invalid start bit\n"); + break; + } - switch (rc6_mode(data)) { - case RC6_MODE_0: - data->wanted_bits = RC6_0_NBITS; - break; - case RC6_MODE_6A: - /* This might look weird, but we basically - check the value of the first body bit to - determine the number of bits in mode 6A */ - if ((DURATION(u) == 0 && IS_SPACE(data->last_unit)) || DURATION(u) > 0) - data->wanted_bits = RC6_6A_LARGE_NBITS; - else - data->wanted_bits = RC6_6A_SMALL_NBITS; - break; - default: - IR_dprintk(1, "RC6 unknown mode\n"); - goto out; - } - goto again; + data->state = STATE_BODY_BIT_START; + data->prev_ev = ev; + decrease_duration(&ev, RC6_TOGGLE_END); + data->count = 0; + + switch (rc6_mode(data)) { + case RC6_MODE_0: + data->wanted_bits = RC6_0_NBITS; + break; + case RC6_MODE_6A: + /* This might look weird, but we basically + check the value of the first body bit to + determine the number of bits in mode 6A */ + if ((!ev.pulse && !geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2)) || + geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2)) + data->wanted_bits = RC6_6A_LARGE_NBITS; + else + data->wanted_bits = RC6_6A_SMALL_NBITS; + break; + default: + IR_dprintk(1, "RC6 unknown mode\n"); + goto out; } - break; + goto again; case STATE_BODY_BIT_START: - if (DURATION(u) == 1) { - data->body <<= 1; - if (IS_PULSE(u)) - data->body |= 1; - data->count++; - data->last_unit = u; - - /* - * If the last bit is one, a space will merge - * with the silence after the command. - */ - if (IS_PULSE(u) && data->count == data->wanted_bits) { - data->state = STATE_FINISHED; - goto again; - } + if (!eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2)) + break; - data->state = STATE_BODY_BIT_END; - return 0; - } - break; + data->body <<= 1; + if (ev.pulse) + data->body |= 1; + data->count++; + data->prev_ev = ev; + + data->state = STATE_BODY_BIT_END; + return 0; case STATE_BODY_BIT_END: - if (IS_TRANSITION(u, data->last_unit)) { - if (data->count == data->wanted_bits) - data->state = STATE_FINISHED; - else - data->state = STATE_BODY_BIT_START; + if (!is_transition(&ev, &data->prev_ev)) + break; - DECREASE_DURATION(u, 1); - goto again; - } - break; + if (data->count == data->wanted_bits) + data->state = STATE_FINISHED; + else + data->state = STATE_BODY_BIT_START; + + decrease_duration(&ev, RC6_BIT_END); + goto again; case STATE_FINISHED: + if (ev.pulse) + break; + switch (rc6_mode(data)) { case RC6_MODE_0: scancode = data->body & 0xffff; @@ -335,8 +342,8 @@ again: } out: - IR_dprintk(1, "RC6 decode failed at state %i (%i units, %ius)\n", - data->state, u, TO_US(duration)); + IR_dprintk(1, "RC6 decode failed at state %i (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); data->state = STATE_INACTIVE; return -EINVAL; } |