V4L/DVB: ir-core: change duration to be coded as a u32 integer
authorDavid Härdeman <david@hardeman.nu>
Thu, 15 Apr 2010 21:46:00 +0000 (18:46 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Wed, 19 May 2010 15:57:42 +0000 (12:57 -0300)
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: David Härdeman <david@hardeman.nu>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/IR/ir-core-priv.h
drivers/media/IR/ir-nec-decoder.c
drivers/media/IR/ir-raw-event.c
drivers/media/IR/ir-rc5-decoder.c
drivers/media/IR/ir-rc6-decoder.c
include/media/ir-core.h

index 8c1f846..77d0b94 100644 (file)
@@ -22,7 +22,7 @@
 struct ir_raw_handler {
        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_unregister)(struct input_dev *input_dev);
 };
@@ -36,26 +36,28 @@ struct ir_raw_event_ctrl {
 };
 
 /* macros for IR decoders */
-#define PULSE(units)                           ((units))
-#define SPACE(units)                           (-(units))
-#define IS_RESET(duration)                     ((duration) == 0)
-#define IS_PULSE(duration)                     ((duration) > 0)
-#define IS_SPACE(duration)                     ((duration) < 0)
-#define DURATION(duration)                     (abs((duration)))
-#define IS_TRANSITION(x, y)                    ((x) * (y) < 0)
-#define DECREASE_DURATION(duration, amount)                    \
-       do {                                                    \
-               if (IS_SPACE(duration))                         \
-                       duration += (amount);                   \
-               else if (IS_PULSE(duration))                    \
-                       duration -= (amount);                   \
-       } while (0)
-
-#define TO_UNITS(duration, unit_len)                           \
-       ((int)((duration) > 0 ?                                 \
-               DIV_ROUND_CLOSEST(abs((duration)), (unit_len)) :\
-               -DIV_ROUND_CLOSEST(abs((duration)), (unit_len))))
-#define TO_US(duration)                ((int)TO_UNITS(duration, 1000))
+static inline bool geq_margin(unsigned d1, unsigned d2, unsigned margin) {
+       return d1 > (d2 - margin);
+}
+
+static inline bool eq_margin(unsigned d1, unsigned d2, unsigned margin) {
+       return ((d1 > (d2 - margin)) && (d1 < (d2 + margin)));
+}
+
+static inline bool is_transition(struct ir_raw_event *x, struct ir_raw_event *y) {
+       return x->pulse != y->pulse;
+}
+
+static inline void decrease_duration(struct ir_raw_event *ev, unsigned duration) {
+       if (duration > ev->duration)
+               ev->duration = 0;
+       else
+               ev->duration -= duration;
+}
+
+#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
@@ -70,11 +72,6 @@ void ir_unregister_class(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);
-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);
 void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler);
 void ir_raw_init(void);
index 14609d9..ba79233 100644 (file)
 
 #define NEC_NBITS              32
 #define NEC_UNIT               562500  /* ns */
-#define NEC_HEADER_PULSE       PULSE(16)
-#define NECX_HEADER_PULSE      PULSE(8) /* Less common NEC variant */
-#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)
+#define NEC_HEADER_PULSE       (16 * NEC_UNIT)
+#define NECX_HEADER_PULSE      (8  * NEC_UNIT) /* Less common NEC variant */
+#define NEC_HEADER_SPACE       (8  * NEC_UNIT)
+#define NEC_REPEAT_SPACE       (8  * NEC_UNIT)
+#define NEC_BIT_PULSE          (1  * NEC_UNIT)
+#define NEC_BIT_0_SPACE                (1  * NEC_UNIT)
+#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 */
 static LIST_HEAD(decoder_list);
@@ -119,15 +121,14 @@ static struct attribute_group decoder_attribute_group = {
 /**
  * ir_nec_decode() - Decode one NEC pulse or space
  * @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
  */
-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 ir_input_dev *ir_dev = input_get_drvdata(input_dev);
-       int u;
        u32 scancode;
        u8 address, not_address, command, not_command;
 
@@ -138,59 +139,88 @@ static int ir_nec_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, NEC_UNIT);
-       if (DURATION(u) == 0)
-               goto out;
-
-       IR_dprintk(2, "NEC decode started at state %d (%i units, %ius)\n",
-                  data->state, u, TO_US(duration));
+       IR_dprintk(2, "NEC decode started at state %d (%uus %s)\n",
+                  data->state, TO_US(ev.duration), TO_STR(ev.pulse));
 
        switch (data->state) {
 
        case STATE_INACTIVE:
-               if (u == NEC_HEADER_PULSE || u == NECX_HEADER_PULSE) {
-                       data->count = 0;
-                       data->state = STATE_HEADER_SPACE;
-               }
+               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->state = STATE_HEADER_SPACE;
                return 0;
 
        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;
                        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_dprintk(1, "Repeat last key\n");
                        data->state = STATE_TRAILER_PULSE;
                        return 0;
                }
+
                break;
 
        case STATE_BIT_PULSE:
-               if (u == NEC_BIT_PULSE) {
-                       data->state = STATE_BIT_SPACE;
-                       return 0;
-               }
-               break;
+               if (!ev.pulse)
+                       break;
+
+               if (!eq_margin(ev.duration, NEC_BIT_PULSE, NEC_UNIT / 2))
+                       break;
+
+               data->state = STATE_BIT_SPACE;
+               return 0;
 
        case STATE_BIT_SPACE:
-               if (u != NEC_BIT_0_SPACE && u != NEC_BIT_1_SPACE)
+               if (ev.pulse)
                        break;
 
                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;
+               else if (!eq_margin(ev.duration, NEC_BIT_0_SPACE, NEC_UNIT / 2))
+                       break;
                data->count++;
 
-               if (data->count != NEC_NBITS) {
+               if (data->count == NEC_NBITS)
+                       data->state = STATE_TRAILER_PULSE;
+               else
                        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);
                not_address = bitrev8((data->nec_bits >> 16) & 0xff);
@@ -210,34 +240,18 @@ static int ir_nec_decode(struct input_dev *input_dev, s64 duration)
                                   command;
                        IR_dprintk(1, "NEC (Ext) scancode 0x%06x\n", scancode);
                } else {
-                       /* normal NEC */
+                       /* 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;
+               data->state = STATE_INACTIVE;
                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;
-                       return 0;
-               }
-
-               break;
        }
 
-out:
-       IR_dprintk(1, "NEC decode failed at state %d (%i units, %ius)\n",
-                  data->state, u, TO_US(duration));
+       IR_dprintk(1, "NEC decode failed at state %d (%uus %s)\n",
+                  data->state, TO_US(ev.duration), TO_STR(ev.pulse));
        data->state = STATE_INACTIVE;
        return -EINVAL;
 }
index 674442b..59f173c 100644 (file)
@@ -57,12 +57,12 @@ static struct work_struct wq_load;
 
 static void ir_raw_event_work(struct work_struct *work)
 {
-       s64 d;
+       struct ir_raw_event ev;
        struct ir_raw_event_ctrl *raw =
                container_of(work, struct ir_raw_event_ctrl, rx_work);
 
-       while (kfifo_out(&raw->kfifo, &d, sizeof(d)) == sizeof(d))
-               RUN_DECODER(decode, raw->input_dev, d);
+       while (kfifo_out(&raw->kfifo, &ev, sizeof(ev)) == sizeof(ev))
+               RUN_DECODER(decode, raw->input_dev, ev);
 }
 
 int ir_raw_event_register(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
  * @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
  * pulse/space duration for the raw ir decoding state machines. Pulses are
  * signalled as positive values and spaces as negative values. A zero value
  * 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);
 
        if (!ir->raw)
                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 0;
@@ -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);
        ktime_t                 now;
        s64                     delta; /* ns */
+       struct ir_raw_event     ev;
        int                     rc = 0;
 
        if (!ir->raw)
@@ -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
         * 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;
+       else
+               ev.duration = delta;
 
        if (type & IR_START_EVENT)
                ir_raw_event_reset(input_dev);
-       else if (ir->raw->last_type & IR_SPACE)
-               rc = ir_raw_event_store(input_dev, -delta);
-       else if (ir->raw->last_type & IR_PULSE)
-               rc = ir_raw_event_store(input_dev, delta);
-       else
+       else if (ir->raw->last_type & IR_SPACE) {
+               ev.pulse = false;
+               rc = ir_raw_event_store(input_dev, &ev);
+       } else if (ir->raw->last_type & IR_PULSE) {
+               ev.pulse = true;
+               rc = ir_raw_event_store(input_dev, &ev);
+       } else
                return 0;
 
        ir->raw->last_event = now;
index dd5a4d5..23cdb1b 100644 (file)
 #define RC5_NBITS              14
 #define RC5X_NBITS             20
 #define CHECK_RC5X_NBITS       8
-#define RC5X_SPACE             SPACE(4)
 #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 */
 static LIST_HEAD(decoder_list);
@@ -48,7 +50,7 @@ struct decoder_data {
        /* State machine control */
        enum rc5_state          state;
        u32                     rc5_bits;
-       int                     last_unit;
+       struct ir_raw_event     prev_ev;
        unsigned                count;
        unsigned                wanted_bits;
 };
@@ -124,17 +126,16 @@ static struct attribute_group decoder_attribute_group = {
 /**
  * ir_rc5_decode() - Decode one RC-5 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_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 ir_input_dev *ir_dev = input_get_drvdata(input_dev);
        u8 toggle;
        u32 scancode;
-       int u;
 
        data = get_decoder_data(ir_dev);
        if (!data)
@@ -143,76 +144,65 @@ static int ir_rc5_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, RC5_UNIT);
-       if (DURATION(u) == 0)
+       if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
                goto out;
 
 again:
-       IR_dprintk(2, "RC5(x) decode started at state %i (%i units, %ius)\n",
-                  data->state, u, TO_US(duration));
+       IR_dprintk(2, "RC5(x) 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, RC5_UNIT, RC5_UNIT / 2))
                return 0;
 
        switch (data->state) {
 
        case STATE_INACTIVE:
-               if (IS_PULSE(u)) {
-                       data->state = STATE_BIT_START;
-                       data->count = 1;
-                       /* We just need enough bits to get to STATE_CHECK_RC5X */
-                       data->wanted_bits = RC5X_NBITS;
-                       DECREASE_DURATION(u, 1);
-                       goto again;
-               }
-               break;
+               if (!ev.pulse)
+                       break;
+
+               data->state = STATE_BIT_START;
+               data->count = 1;
+               /* We just need enough bits to get to STATE_CHECK_RC5X */
+               data->wanted_bits = RC5X_NBITS;
+               decrease_duration(&ev, RC5_BIT_START);
+               goto again;
 
        case STATE_BIT_START:
-               if (DURATION(u) == 1) {
-                       data->rc5_bits <<= 1;
-                       if (IS_SPACE(u))
-                               data->rc5_bits |= 1;
-                       data->count++;
-                       data->last_unit = u;
-
-                       /*
-                        * 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;
-                       return 0;
-               }
-               break;
+               if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2))
+                       break;
+
+               data->rc5_bits <<= 1;
+               if (!ev.pulse)
+                       data->rc5_bits |= 1;
+               data->count++;
+               data->prev_ev = ev;
+               data->state = STATE_BIT_END;
+               return 0;
 
        case STATE_BIT_END:
-               if (IS_TRANSITION(u, data->last_unit)) {
-                       if (data->count == data->wanted_bits)
-                               data->state = STATE_FINISHED;
-                       else if (data->count == CHECK_RC5X_NBITS)
-                               data->state = STATE_CHECK_RC5X;
-                       else
-                               data->state = STATE_BIT_START;
-
-                       DECREASE_DURATION(u, 1);
-                       goto again;
-               }
-               break;
+               if (!is_transition(&ev, &data->prev_ev))
+                       break;
+
+               if (data->count == data->wanted_bits)
+                       data->state = STATE_FINISHED;
+               else if (data->count == CHECK_RC5X_NBITS)
+                       data->state = STATE_CHECK_RC5X;
+               else
+                       data->state = STATE_BIT_START;
+
+               decrease_duration(&ev, RC5_BIT_END);
+               goto again;
 
        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 */
                        data->wanted_bits = RC5X_NBITS;
-                       DECREASE_DURATION(u, DURATION(RC5X_SPACE));
+                       decrease_duration(&ev, RC5X_SPACE);
                } else {
                        /* RC5 */
                        data->wanted_bits = RC5_NBITS;
@@ -221,6 +211,9 @@ again:
                goto again;
 
        case STATE_FINISHED:
+               if (ev.pulse)
+                       break;
+
                if (data->wanted_bits == RC5X_NBITS) {
                        /* RC5X */
                        u8 xdata, command, system;
@@ -253,8 +246,8 @@ again:
        }
 
 out:
-       IR_dprintk(1, "RC5(x) decode failed at state %i (%i units, %ius)\n",
-                  data->state, u, TO_US(duration));
+       IR_dprintk(1, "RC5(x) decode failed at state %i (%uus %s)\n",
+                  data->state, TO_US(ev.duration), TO_STR(ev.pulse));
        data->state = STATE_INACTIVE;
        return -EINVAL;
 }
index ccc5be2..2bf479f 100644 (file)
 #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;
 }
index 51e8eb3..ad1303f 100644 (file)
@@ -128,9 +128,21 @@ u32 ir_g_keycode_from_table(struct input_dev *input_dev, u32 scancode);
 
 /* 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);
-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);
-
+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 */