Commit e40b1127 authored by David Härdeman's avatar David Härdeman Committed by Mauro Carvalho Chehab

V4L/DVB: ir-core: change duration to be coded as a u32 integer

This patch implements the agreed upon 1:31 integer encoded pulse/duration
struct for ir-core raw decoders. All decoders have been tested after the
change. Comments are welcome.
Signed-off-by: default avatarDavid Härdeman <david@hardeman.nu>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 21677cfc
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
struct ir_raw_handler { struct ir_raw_handler {
struct list_head list; struct list_head list;
int (*decode)(struct input_dev *input_dev, s64 duration); int (*decode)(struct input_dev *input_dev, struct ir_raw_event event);
int (*raw_register)(struct input_dev *input_dev); int (*raw_register)(struct input_dev *input_dev);
int (*raw_unregister)(struct input_dev *input_dev); int (*raw_unregister)(struct input_dev *input_dev);
}; };
...@@ -36,26 +36,28 @@ struct ir_raw_event_ctrl { ...@@ -36,26 +36,28 @@ struct ir_raw_event_ctrl {
}; };
/* macros for IR decoders */ /* macros for IR decoders */
#define PULSE(units) ((units)) static inline bool geq_margin(unsigned d1, unsigned d2, unsigned margin) {
#define SPACE(units) (-(units)) return d1 > (d2 - margin);
#define IS_RESET(duration) ((duration) == 0) }
#define IS_PULSE(duration) ((duration) > 0)
#define IS_SPACE(duration) ((duration) < 0) static inline bool eq_margin(unsigned d1, unsigned d2, unsigned margin) {
#define DURATION(duration) (abs((duration))) return ((d1 > (d2 - margin)) && (d1 < (d2 + margin)));
#define IS_TRANSITION(x, y) ((x) * (y) < 0) }
#define DECREASE_DURATION(duration, amount) \
do { \ static inline bool is_transition(struct ir_raw_event *x, struct ir_raw_event *y) {
if (IS_SPACE(duration)) \ return x->pulse != y->pulse;
duration += (amount); \ }
else if (IS_PULSE(duration)) \
duration -= (amount); \ static inline void decrease_duration(struct ir_raw_event *ev, unsigned duration) {
} while (0) if (duration > ev->duration)
ev->duration = 0;
#define TO_UNITS(duration, unit_len) \ else
((int)((duration) > 0 ? \ ev->duration -= duration;
DIV_ROUND_CLOSEST(abs((duration)), (unit_len)) :\ }
-DIV_ROUND_CLOSEST(abs((duration)), (unit_len))))
#define TO_US(duration) ((int)TO_UNITS(duration, 1000)) #define TO_US(duration) (((duration) + 500) / 1000)
#define TO_STR(is_pulse) ((is_pulse) ? "pulse" : "space")
#define IS_RESET(ev) (ev.duration == 0)
/* /*
* Routines from ir-sysfs.c - Meant to be called only internally inside * Routines from ir-sysfs.c - Meant to be called only internally inside
...@@ -70,11 +72,6 @@ void ir_unregister_class(struct input_dev *input_dev); ...@@ -70,11 +72,6 @@ void ir_unregister_class(struct input_dev *input_dev);
*/ */
int ir_raw_event_register(struct input_dev *input_dev); int ir_raw_event_register(struct input_dev *input_dev);
void ir_raw_event_unregister(struct input_dev *input_dev); void ir_raw_event_unregister(struct input_dev *input_dev);
static inline void ir_raw_event_reset(struct input_dev *input_dev)
{
ir_raw_event_store(input_dev, 0);
ir_raw_event_handle(input_dev);
}
int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler); int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler);
void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler); void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler);
void ir_raw_init(void); void ir_raw_init(void);
......
...@@ -17,13 +17,15 @@ ...@@ -17,13 +17,15 @@
#define NEC_NBITS 32 #define NEC_NBITS 32
#define NEC_UNIT 562500 /* ns */ #define NEC_UNIT 562500 /* ns */
#define NEC_HEADER_PULSE PULSE(16) #define NEC_HEADER_PULSE (16 * NEC_UNIT)
#define NECX_HEADER_PULSE PULSE(8) /* Less common NEC variant */ #define NECX_HEADER_PULSE (8 * NEC_UNIT) /* Less common NEC variant */
#define NEC_HEADER_SPACE SPACE(8) #define NEC_HEADER_SPACE (8 * NEC_UNIT)
#define NEC_REPEAT_SPACE SPACE(4) #define NEC_REPEAT_SPACE (8 * NEC_UNIT)
#define NEC_BIT_PULSE PULSE(1) #define NEC_BIT_PULSE (1 * NEC_UNIT)
#define NEC_BIT_0_SPACE SPACE(1) #define NEC_BIT_0_SPACE (1 * NEC_UNIT)
#define NEC_BIT_1_SPACE SPACE(3) #define NEC_BIT_1_SPACE (3 * NEC_UNIT)
#define NEC_TRAILER_PULSE (1 * NEC_UNIT)
#define NEC_TRAILER_SPACE (10 * NEC_UNIT) /* even longer in reality */
/* Used to register nec_decoder clients */ /* Used to register nec_decoder clients */
static LIST_HEAD(decoder_list); static LIST_HEAD(decoder_list);
...@@ -119,15 +121,14 @@ static struct attribute_group decoder_attribute_group = { ...@@ -119,15 +121,14 @@ static struct attribute_group decoder_attribute_group = {
/** /**
* ir_nec_decode() - Decode one NEC pulse or space * ir_nec_decode() - Decode one NEC pulse or space
* @input_dev: the struct input_dev descriptor of the device * @input_dev: the struct input_dev descriptor of the device
* @duration: duration in ns of pulse/space * @duration: the struct ir_raw_event descriptor of the pulse/space
* *
* This function returns -EINVAL if the pulse violates the state machine * This function returns -EINVAL if the pulse violates the state machine
*/ */
static int ir_nec_decode(struct input_dev *input_dev, s64 duration) static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev)
{ {
struct decoder_data *data; struct decoder_data *data;
struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
int u;
u32 scancode; u32 scancode;
u8 address, not_address, command, not_command; u8 address, not_address, command, not_command;
...@@ -138,59 +139,88 @@ static int ir_nec_decode(struct input_dev *input_dev, s64 duration) ...@@ -138,59 +139,88 @@ static int ir_nec_decode(struct input_dev *input_dev, s64 duration)
if (!data->enabled) if (!data->enabled)
return 0; return 0;
if (IS_RESET(duration)) { if (IS_RESET(ev)) {
data->state = STATE_INACTIVE; data->state = STATE_INACTIVE;
return 0; return 0;
} }
u = TO_UNITS(duration, NEC_UNIT); IR_dprintk(2, "NEC decode started at state %d (%uus %s)\n",
if (DURATION(u) == 0) data->state, TO_US(ev.duration), TO_STR(ev.pulse));
goto out;
IR_dprintk(2, "NEC decode started at state %d (%i units, %ius)\n",
data->state, u, TO_US(duration));
switch (data->state) { switch (data->state) {
case STATE_INACTIVE: case STATE_INACTIVE:
if (u == NEC_HEADER_PULSE || u == NECX_HEADER_PULSE) { if (!ev.pulse)
break;
if (!eq_margin(ev.duration, NEC_HEADER_PULSE, NEC_UNIT / 2) &&
!eq_margin(ev.duration, NECX_HEADER_PULSE, NEC_UNIT / 2))
break;
data->count = 0; data->count = 0;
data->state = STATE_HEADER_SPACE; data->state = STATE_HEADER_SPACE;
}
return 0; return 0;
case STATE_HEADER_SPACE: case STATE_HEADER_SPACE:
if (u == NEC_HEADER_SPACE) { if (ev.pulse)
break;
if (eq_margin(ev.duration, NEC_HEADER_SPACE, NEC_UNIT / 2)) {
data->state = STATE_BIT_PULSE; data->state = STATE_BIT_PULSE;
return 0; return 0;
} else if (u == NEC_REPEAT_SPACE) { } else if (eq_margin(ev.duration, NEC_REPEAT_SPACE, NEC_UNIT / 2)) {
ir_repeat(input_dev); ir_repeat(input_dev);
IR_dprintk(1, "Repeat last key\n"); IR_dprintk(1, "Repeat last key\n");
data->state = STATE_TRAILER_PULSE; data->state = STATE_TRAILER_PULSE;
return 0; return 0;
} }
break; break;
case STATE_BIT_PULSE: case STATE_BIT_PULSE:
if (u == NEC_BIT_PULSE) { if (!ev.pulse)
break;
if (!eq_margin(ev.duration, NEC_BIT_PULSE, NEC_UNIT / 2))
break;
data->state = STATE_BIT_SPACE; data->state = STATE_BIT_SPACE;
return 0; return 0;
}
break;
case STATE_BIT_SPACE: case STATE_BIT_SPACE:
if (u != NEC_BIT_0_SPACE && u != NEC_BIT_1_SPACE) if (ev.pulse)
break; break;
data->nec_bits <<= 1; data->nec_bits <<= 1;
if (u == NEC_BIT_1_SPACE) if (eq_margin(ev.duration, NEC_BIT_1_SPACE, NEC_UNIT / 2))
data->nec_bits |= 1; data->nec_bits |= 1;
else if (!eq_margin(ev.duration, NEC_BIT_0_SPACE, NEC_UNIT / 2))
break;
data->count++; data->count++;
if (data->count != NEC_NBITS) { if (data->count == NEC_NBITS)
data->state = STATE_TRAILER_PULSE;
else
data->state = STATE_BIT_PULSE; data->state = STATE_BIT_PULSE;
return 0; return 0;
}
case STATE_TRAILER_PULSE:
if (!ev.pulse)
break;
if (!eq_margin(ev.duration, NEC_TRAILER_PULSE, NEC_UNIT / 2))
break;
data->state = STATE_TRAILER_SPACE;
return 0;
case STATE_TRAILER_SPACE:
if (ev.pulse)
break;
if (!geq_margin(ev.duration, NEC_TRAILER_SPACE, NEC_UNIT / 2))
break;
address = bitrev8((data->nec_bits >> 24) & 0xff); address = bitrev8((data->nec_bits >> 24) & 0xff);
not_address = bitrev8((data->nec_bits >> 16) & 0xff); not_address = bitrev8((data->nec_bits >> 16) & 0xff);
...@@ -210,34 +240,18 @@ static int ir_nec_decode(struct input_dev *input_dev, s64 duration) ...@@ -210,34 +240,18 @@ static int ir_nec_decode(struct input_dev *input_dev, s64 duration)
command; command;
IR_dprintk(1, "NEC (Ext) scancode 0x%06x\n", scancode); IR_dprintk(1, "NEC (Ext) scancode 0x%06x\n", scancode);
} else { } else {
/* normal NEC */ /* Normal NEC */
scancode = address << 8 | command; scancode = address << 8 | command;
IR_dprintk(1, "NEC scancode 0x%04x\n", scancode); IR_dprintk(1, "NEC scancode 0x%04x\n", scancode);
} }
ir_keydown(input_dev, scancode, 0); ir_keydown(input_dev, scancode, 0);
data->state = STATE_TRAILER_PULSE;
return 0;
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; data->state = STATE_INACTIVE;
return 0; return 0;
} }
break; IR_dprintk(1, "NEC decode failed at state %d (%uus %s)\n",
} data->state, TO_US(ev.duration), TO_STR(ev.pulse));
out:
IR_dprintk(1, "NEC decode failed at state %d (%i units, %ius)\n",
data->state, u, TO_US(duration));
data->state = STATE_INACTIVE; data->state = STATE_INACTIVE;
return -EINVAL; return -EINVAL;
} }
......
...@@ -57,12 +57,12 @@ static struct work_struct wq_load; ...@@ -57,12 +57,12 @@ static struct work_struct wq_load;
static void ir_raw_event_work(struct work_struct *work) static void ir_raw_event_work(struct work_struct *work)
{ {
s64 d; struct ir_raw_event ev;
struct ir_raw_event_ctrl *raw = struct ir_raw_event_ctrl *raw =
container_of(work, struct ir_raw_event_ctrl, rx_work); container_of(work, struct ir_raw_event_ctrl, rx_work);
while (kfifo_out(&raw->kfifo, &d, sizeof(d)) == sizeof(d)) while (kfifo_out(&raw->kfifo, &ev, sizeof(ev)) == sizeof(ev))
RUN_DECODER(decode, raw->input_dev, d); RUN_DECODER(decode, raw->input_dev, ev);
} }
int ir_raw_event_register(struct input_dev *input_dev) int ir_raw_event_register(struct input_dev *input_dev)
...@@ -114,21 +114,21 @@ void ir_raw_event_unregister(struct input_dev *input_dev) ...@@ -114,21 +114,21 @@ void ir_raw_event_unregister(struct input_dev *input_dev)
/** /**
* ir_raw_event_store() - pass a pulse/space duration to the raw ir decoders * ir_raw_event_store() - pass a pulse/space duration to the raw ir decoders
* @input_dev: the struct input_dev device descriptor * @input_dev: the struct input_dev device descriptor
* @duration: duration of the pulse or space in ns * @ev: the struct ir_raw_event descriptor of the pulse/space
* *
* This routine (which may be called from an interrupt context) stores a * This routine (which may be called from an interrupt context) stores a
* pulse/space duration for the raw ir decoding state machines. Pulses are * pulse/space duration for the raw ir decoding state machines. Pulses are
* signalled as positive values and spaces as negative values. A zero value * signalled as positive values and spaces as negative values. A zero value
* will reset the decoding state machines. * will reset the decoding state machines.
*/ */
int ir_raw_event_store(struct input_dev *input_dev, s64 duration) int ir_raw_event_store(struct input_dev *input_dev, struct ir_raw_event *ev)
{ {
struct ir_input_dev *ir = input_get_drvdata(input_dev); struct ir_input_dev *ir = input_get_drvdata(input_dev);
if (!ir->raw) if (!ir->raw)
return -EINVAL; return -EINVAL;
if (kfifo_in(&ir->raw->kfifo, &duration, sizeof(duration)) != sizeof(duration)) if (kfifo_in(&ir->raw->kfifo, ev, sizeof(*ev)) != sizeof(*ev))
return -ENOMEM; return -ENOMEM;
return 0; return 0;
...@@ -151,6 +151,7 @@ int ir_raw_event_store_edge(struct input_dev *input_dev, enum raw_event_type typ ...@@ -151,6 +151,7 @@ int ir_raw_event_store_edge(struct input_dev *input_dev, enum raw_event_type typ
struct ir_input_dev *ir = input_get_drvdata(input_dev); struct ir_input_dev *ir = input_get_drvdata(input_dev);
ktime_t now; ktime_t now;
s64 delta; /* ns */ s64 delta; /* ns */
struct ir_raw_event ev;
int rc = 0; int rc = 0;
if (!ir->raw) if (!ir->raw)
...@@ -163,16 +164,21 @@ int ir_raw_event_store_edge(struct input_dev *input_dev, enum raw_event_type typ ...@@ -163,16 +164,21 @@ int ir_raw_event_store_edge(struct input_dev *input_dev, enum raw_event_type typ
* being called for the first time, note that delta can't * being called for the first time, note that delta can't
* possibly be negative. * possibly be negative.
*/ */
if (delta > NSEC_PER_SEC || !ir->raw->last_type) ev.duration = 0;
if (delta > IR_MAX_DURATION || !ir->raw->last_type)
type |= IR_START_EVENT; type |= IR_START_EVENT;
else
ev.duration = delta;
if (type & IR_START_EVENT) if (type & IR_START_EVENT)
ir_raw_event_reset(input_dev); ir_raw_event_reset(input_dev);
else if (ir->raw->last_type & IR_SPACE) else if (ir->raw->last_type & IR_SPACE) {
rc = ir_raw_event_store(input_dev, -delta); ev.pulse = false;
else if (ir->raw->last_type & IR_PULSE) rc = ir_raw_event_store(input_dev, &ev);
rc = ir_raw_event_store(input_dev, delta); } else if (ir->raw->last_type & IR_PULSE) {
else ev.pulse = true;
rc = ir_raw_event_store(input_dev, &ev);
} else
return 0; return 0;
ir->raw->last_event = now; ir->raw->last_event = now;
......
...@@ -25,8 +25,10 @@ ...@@ -25,8 +25,10 @@
#define RC5_NBITS 14 #define RC5_NBITS 14
#define RC5X_NBITS 20 #define RC5X_NBITS 20
#define CHECK_RC5X_NBITS 8 #define CHECK_RC5X_NBITS 8
#define RC5X_SPACE SPACE(4)
#define RC5_UNIT 888888 /* ns */ #define RC5_UNIT 888888 /* ns */
#define RC5_BIT_START (1 * RC5_UNIT)
#define RC5_BIT_END (1 * RC5_UNIT)
#define RC5X_SPACE (4 * RC5_UNIT)
/* Used to register rc5_decoder clients */ /* Used to register rc5_decoder clients */
static LIST_HEAD(decoder_list); static LIST_HEAD(decoder_list);
...@@ -48,7 +50,7 @@ struct decoder_data { ...@@ -48,7 +50,7 @@ struct decoder_data {
/* State machine control */ /* State machine control */
enum rc5_state state; enum rc5_state state;
u32 rc5_bits; u32 rc5_bits;
int last_unit; struct ir_raw_event prev_ev;
unsigned count; unsigned count;
unsigned wanted_bits; unsigned wanted_bits;
}; };
...@@ -124,17 +126,16 @@ static struct attribute_group decoder_attribute_group = { ...@@ -124,17 +126,16 @@ static struct attribute_group decoder_attribute_group = {
/** /**
* ir_rc5_decode() - Decode one RC-5 pulse or space * ir_rc5_decode() - Decode one RC-5 pulse or space
* @input_dev: the struct input_dev descriptor of the device * @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 * This function returns -EINVAL if the pulse violates the state machine
*/ */
static int ir_rc5_decode(struct input_dev *input_dev, s64 duration) static int ir_rc5_decode(struct input_dev *input_dev, struct ir_raw_event ev)
{ {
struct decoder_data *data; struct decoder_data *data;
struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
u8 toggle; u8 toggle;
u32 scancode; u32 scancode;
int u;
data = get_decoder_data(ir_dev); data = get_decoder_data(ir_dev);
if (!data) if (!data)
...@@ -143,59 +144,50 @@ static int ir_rc5_decode(struct input_dev *input_dev, s64 duration) ...@@ -143,59 +144,50 @@ static int ir_rc5_decode(struct input_dev *input_dev, s64 duration)
if (!data->enabled) if (!data->enabled)
return 0; return 0;
if (IS_RESET(duration)) { if (IS_RESET(ev)) {
data->state = STATE_INACTIVE; data->state = STATE_INACTIVE;
return 0; return 0;
} }
u = TO_UNITS(duration, RC5_UNIT); if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
if (DURATION(u) == 0)
goto out; goto out;
again: again:
IR_dprintk(2, "RC5(x) decode started at state %i (%i units, %ius)\n", IR_dprintk(2, "RC5(x) decode started at state %i (%uus %s)\n",
data->state, u, TO_US(duration)); data->state, TO_US(ev.duration), TO_STR(ev.pulse));
if (DURATION(u) == 0 && data->state != STATE_FINISHED) if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
return 0; return 0;
switch (data->state) { switch (data->state) {
case STATE_INACTIVE: case STATE_INACTIVE:
if (IS_PULSE(u)) { if (!ev.pulse)
break;
data->state = STATE_BIT_START; data->state = STATE_BIT_START;
data->count = 1; data->count = 1;
/* We just need enough bits to get to STATE_CHECK_RC5X */ /* We just need enough bits to get to STATE_CHECK_RC5X */
data->wanted_bits = RC5X_NBITS; data->wanted_bits = RC5X_NBITS;
DECREASE_DURATION(u, 1); decrease_duration(&ev, RC5_BIT_START);
goto again; goto again;
}
break;
case STATE_BIT_START: case STATE_BIT_START:
if (DURATION(u) == 1) { if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2))
break;
data->rc5_bits <<= 1; data->rc5_bits <<= 1;
if (IS_SPACE(u)) if (!ev.pulse)
data->rc5_bits |= 1; data->rc5_bits |= 1;
data->count++; data->count++;
data->last_unit = u; data->prev_ev = ev;
/*
* If the last bit is zero, 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;
}
data->state = STATE_BIT_END; data->state = STATE_BIT_END;
return 0; return 0;
}
break;
case STATE_BIT_END: case STATE_BIT_END:
if (IS_TRANSITION(u, data->last_unit)) { if (!is_transition(&ev, &data->prev_ev))
break;
if (data->count == data->wanted_bits) if (data->count == data->wanted_bits)
data->state = STATE_FINISHED; data->state = STATE_FINISHED;
else if (data->count == CHECK_RC5X_NBITS) else if (data->count == CHECK_RC5X_NBITS)
...@@ -203,16 +195,14 @@ static int ir_rc5_decode(struct input_dev *input_dev, s64 duration) ...@@ -203,16 +195,14 @@ static int ir_rc5_decode(struct input_dev *input_dev, s64 duration)
else else
data->state = STATE_BIT_START; data->state = STATE_BIT_START;
DECREASE_DURATION(u, 1); decrease_duration(&ev, RC5_BIT_END);
goto again; goto again;
}
break;
case STATE_CHECK_RC5X: case STATE_CHECK_RC5X:
if (IS_SPACE(u) && DURATION(u) >= DURATION(RC5X_SPACE)) { if (!ev.pulse && geq_margin(ev.duration, RC5X_SPACE, RC5_UNIT / 2)) {
/* RC5X */ /* RC5X */
data->wanted_bits = RC5X_NBITS; data->wanted_bits = RC5X_NBITS;
DECREASE_DURATION(u, DURATION(RC5X_SPACE)); decrease_duration(&ev, RC5X_SPACE);
} else { } else {
/* RC5 */ /* RC5 */
data->wanted_bits = RC5_NBITS; data->wanted_bits = RC5_NBITS;
...@@ -221,6 +211,9 @@ static int ir_rc5_decode(struct input_dev *input_dev, s64 duration) ...@@ -221,6 +211,9 @@ static int ir_rc5_decode(struct input_dev *input_dev, s64 duration)
goto again; goto again;
case STATE_FINISHED: case STATE_FINISHED:
if (ev.pulse)
break;
if (data->wanted_bits == RC5X_NBITS) { if (data->wanted_bits == RC5X_NBITS) {
/* RC5X */ /* RC5X */
u8 xdata, command, system; u8 xdata, command, system;
...@@ -253,8 +246,8 @@ static int ir_rc5_decode(struct input_dev *input_dev, s64 duration) ...@@ -253,8 +246,8 @@ static int ir_rc5_decode(struct input_dev *input_dev, s64 duration)
} }
out: out:
IR_dprintk(1, "RC5(x) decode failed at state %i (%i units, %ius)\n", IR_dprintk(1, "RC5(x) decode failed at state %i (%uus %s)\n",
data->state, u, TO_US(duration)); data->state, TO_US(ev.duration), TO_STR(ev.pulse));
data->state = STATE_INACTIVE; data->state = STATE_INACTIVE;
return -EINVAL; return -EINVAL;
} }
......
...@@ -26,8 +26,12 @@ ...@@ -26,8 +26,12 @@
#define RC6_0_NBITS 16 #define RC6_0_NBITS 16
#define RC6_6A_SMALL_NBITS 24 #define RC6_6A_SMALL_NBITS 24
#define RC6_6A_LARGE_NBITS 32 #define RC6_6A_LARGE_NBITS 32
#define RC6_PREFIX_PULSE PULSE(6) #define RC6_PREFIX_PULSE (6 * RC6_UNIT)
#define RC6_PREFIX_SPACE SPACE(2) #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_MODE_MASK 0x07 /* for the header bits */
#define RC6_STARTBIT_MASK 0x08 /* for the header bits */ #define RC6_STARTBIT_MASK 0x08 /* for the header bits */
#define RC6_6A_MCE_TOGGLE_MASK 0x8000 /* for the body bits */ #define RC6_6A_MCE_TOGGLE_MASK 0x8000 /* for the body bits */
...@@ -63,7 +67,7 @@ struct decoder_data { ...@@ -63,7 +67,7 @@ struct decoder_data {
enum rc6_state state; enum rc6_state state;
u8 header; u8 header;
u32 body; u32 body;
int last_unit; struct ir_raw_event prev_ev;
bool toggle; bool toggle;
unsigned count; unsigned count;
unsigned wanted_bits; unsigned wanted_bits;
...@@ -152,17 +156,16 @@ static enum rc6_mode rc6_mode(struct decoder_data *data) { ...@@ -152,17 +156,16 @@ static enum rc6_mode rc6_mode(struct decoder_data *data) {
/** /**
* ir_rc6_decode() - Decode one RC6 pulse or space * ir_rc6_decode() - Decode one RC6 pulse or space
* @input_dev: the struct input_dev descriptor of the device * @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 * 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 decoder_data *data;
struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
u32 scancode; u32 scancode;
u8 toggle; u8 toggle;
int u;
data = get_decoder_data(ir_dev); data = get_decoder_data(ir_dev);
if (!data) if (!data)
...@@ -171,84 +174,95 @@ static int ir_rc6_decode(struct input_dev *input_dev, s64 duration) ...@@ -171,84 +174,95 @@ static int ir_rc6_decode(struct input_dev *input_dev, s64 duration)
if (!data->enabled) if (!data->enabled)
return 0; return 0;
if (IS_RESET(duration)) { if (IS_RESET(ev)) {
data->state = STATE_INACTIVE; data->state = STATE_INACTIVE;
return 0; return 0;
} }
u = TO_UNITS(duration, RC6_UNIT); if (!geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2))
if (DURATION(u) == 0)
goto out; goto out;
again: again:
IR_dprintk(2, "RC6 decode started at state %i (%i units, %ius)\n", IR_dprintk(2, "RC6 decode started at state %i (%uus %s)\n",
data->state, u, TO_US(duration)); 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; return 0;
switch (data->state) { switch (data->state) {
case STATE_INACTIVE: case STATE_INACTIVE:
if (u >= RC6_PREFIX_PULSE - 1 && u <= RC6_PREFIX_PULSE + 1) { 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->state = STATE_PREFIX_SPACE;
data->count = 0; data->count = 0;
return 0; return 0;
}
break;
case STATE_PREFIX_SPACE: case STATE_PREFIX_SPACE:
if (u == RC6_PREFIX_SPACE) { if (ev.pulse)
break;
if (!eq_margin(ev.duration, RC6_PREFIX_SPACE, RC6_UNIT / 2))
break;
data->state = STATE_HEADER_BIT_START; data->state = STATE_HEADER_BIT_START;
return 0; return 0;
}
break;
case STATE_HEADER_BIT_START: case STATE_HEADER_BIT_START:
if (DURATION(u) == 1) { if (!eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2))
break;
data->header <<= 1; data->header <<= 1;
if (IS_PULSE(u)) if (ev.pulse)
data->header |= 1; data->header |= 1;
data->count++; data->count++;
data->last_unit = u; data->prev_ev = ev;
data->state = STATE_HEADER_BIT_END; data->state = STATE_HEADER_BIT_END;
return 0; return 0;
}
break;
case STATE_HEADER_BIT_END: case STATE_HEADER_BIT_END:
if (IS_TRANSITION(u, data->last_unit)) { if (!is_transition(&ev, &data->prev_ev))
break;
if (data->count == RC6_HEADER_NBITS) if (data->count == RC6_HEADER_NBITS)
data->state = STATE_TOGGLE_START; data->state = STATE_TOGGLE_START;
else else
data->state = STATE_HEADER_BIT_START; data->state = STATE_HEADER_BIT_START;
DECREASE_DURATION(u, 1); decrease_duration(&ev, RC6_BIT_END);
goto again; goto again;
}
break;
case STATE_TOGGLE_START: case STATE_TOGGLE_START:
if (DURATION(u) == 2) { if (!eq_margin(ev.duration, RC6_TOGGLE_START, RC6_UNIT / 2))
data->toggle = IS_PULSE(u); break;
data->last_unit = u;
data->toggle = ev.pulse;
data->prev_ev = ev;
data->state = STATE_TOGGLE_END; data->state = STATE_TOGGLE_END;
return 0; return 0;
}
break;
case STATE_TOGGLE_END: case STATE_TOGGLE_END:
if (IS_TRANSITION(u, data->last_unit) && DURATION(u) >= 2) { if (!is_transition(&ev, &data->prev_ev) ||
data->state = STATE_BODY_BIT_START; !geq_margin(ev.duration, RC6_TOGGLE_END, RC6_UNIT / 2))
data->last_unit = u; break;
DECREASE_DURATION(u, 2);
data->count = 0;
if (!(data->header & RC6_STARTBIT_MASK)) { if (!(data->header & RC6_STARTBIT_MASK)) {
IR_dprintk(1, "RC6 invalid start bit\n"); IR_dprintk(1, "RC6 invalid start bit\n");
break; break;
} }
data->state = STATE_BODY_BIT_START;
data->prev_ev = ev;
decrease_duration(&ev, RC6_TOGGLE_END);
data->count = 0;
switch (rc6_mode(data)) { switch (rc6_mode(data)) {
case RC6_MODE_0: case RC6_MODE_0:
data->wanted_bits = RC6_0_NBITS; data->wanted_bits = RC6_0_NBITS;
...@@ -257,7 +271,8 @@ static int ir_rc6_decode(struct input_dev *input_dev, s64 duration) ...@@ -257,7 +271,8 @@ static int ir_rc6_decode(struct input_dev *input_dev, s64 duration)
/* This might look weird, but we basically /* This might look weird, but we basically
check the value of the first body bit to check the value of the first body bit to
determine the number of bits in mode 6A */ determine the number of bits in mode 6A */
if ((DURATION(u) == 0 && IS_SPACE(data->last_unit)) || DURATION(u) > 0) 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; data->wanted_bits = RC6_6A_LARGE_NBITS;
else else
data->wanted_bits = RC6_6A_SMALL_NBITS; data->wanted_bits = RC6_6A_SMALL_NBITS;
...@@ -267,44 +282,36 @@ static int ir_rc6_decode(struct input_dev *input_dev, s64 duration) ...@@ -267,44 +282,36 @@ static int ir_rc6_decode(struct input_dev *input_dev, s64 duration)
goto out; goto out;
} }
goto again; goto again;
}
break;
case STATE_BODY_BIT_START: case STATE_BODY_BIT_START:
if (DURATION(u) == 1) { if (!eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2))
break;
data->body <<= 1; data->body <<= 1;
if (IS_PULSE(u)) if (ev.pulse)
data->body |= 1; data->body |= 1;
data->count++; data->count++;
data->last_unit = u; data->prev_ev = ev;
/*
* 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;
}
data->state = STATE_BODY_BIT_END; data->state = STATE_BODY_BIT_END;
return 0; return 0;
}
break;
case STATE_BODY_BIT_END: case STATE_BODY_BIT_END:
if (IS_TRANSITION(u, data->last_unit)) { if (!is_transition(&ev, &data->prev_ev))
break;
if (data->count == data->wanted_bits) if (data->count == data->wanted_bits)
data->state = STATE_FINISHED; data->state = STATE_FINISHED;
else else
data->state = STATE_BODY_BIT_START; data->state = STATE_BODY_BIT_START;
DECREASE_DURATION(u, 1); decrease_duration(&ev, RC6_BIT_END);
goto again; goto again;
}
break;
case STATE_FINISHED: case STATE_FINISHED:
if (ev.pulse)
break;
switch (rc6_mode(data)) { switch (rc6_mode(data)) {
case RC6_MODE_0: case RC6_MODE_0:
scancode = data->body & 0xffff; scancode = data->body & 0xffff;
...@@ -335,8 +342,8 @@ static int ir_rc6_decode(struct input_dev *input_dev, s64 duration) ...@@ -335,8 +342,8 @@ static int ir_rc6_decode(struct input_dev *input_dev, s64 duration)
} }
out: out:
IR_dprintk(1, "RC6 decode failed at state %i (%i units, %ius)\n", IR_dprintk(1, "RC6 decode failed at state %i (%uus %s)\n",
data->state, u, TO_US(duration)); data->state, TO_US(ev.duration), TO_STR(ev.pulse));
data->state = STATE_INACTIVE; data->state = STATE_INACTIVE;
return -EINVAL; return -EINVAL;
} }
......
...@@ -128,9 +128,21 @@ u32 ir_g_keycode_from_table(struct input_dev *input_dev, u32 scancode); ...@@ -128,9 +128,21 @@ u32 ir_g_keycode_from_table(struct input_dev *input_dev, u32 scancode);
/* From ir-raw-event.c */ /* From ir-raw-event.c */
struct ir_raw_event {
unsigned pulse:1;
unsigned duration:31;
};
#define IR_MAX_DURATION 0x7FFFFFFF /* a bit more than 2 seconds */
void ir_raw_event_handle(struct input_dev *input_dev); void ir_raw_event_handle(struct input_dev *input_dev);
int ir_raw_event_store(struct input_dev *input_dev, s64 duration); int ir_raw_event_store(struct input_dev *input_dev, struct ir_raw_event *ev);
int ir_raw_event_store_edge(struct input_dev *input_dev, enum raw_event_type type); int ir_raw_event_store_edge(struct input_dev *input_dev, enum raw_event_type type);
static inline void ir_raw_event_reset(struct input_dev *input_dev)
{
struct ir_raw_event ev = { .pulse = false, .duration = 0 };
ir_raw_event_store(input_dev, &ev);
ir_raw_event_handle(input_dev);
}
#endif /* _IR_CORE */ #endif /* _IR_CORE */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment