V4L/DVB: Teach drivers/media/IR/ir-raw-event.c to use durations
[safe/jmp/linux-2.6] / drivers / media / IR / ir-nec-decoder.c
index 0b50060..02682e6 100644 (file)
  */
 
 #include <media/ir-core.h>
+#include <linux/bitrev.h>
 
-/* 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)