[media] ir-rc6-decoder: Support RC6-6A variable length data
authorlawrence rust <lawrence@softsystem.co.uk>
Mon, 31 Oct 2011 11:39:32 +0000 (08:39 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Thu, 24 Nov 2011 00:23:15 +0000 (22:23 -0200)
This patch to the IR RC6 decoder adds support for variable length
mode-6A frames which can range in size from 8 to 128 bits.  Please refer
to the following link for a detailed explanation or RC6 frames:
http://slydiman.narod.ru/scr/kb/rc6.htm

This change removes the assumption that frames are fixed length
(currently either 24 or 32 data bits) and actually counts the number of
bits until an end of frame marker is seen.

[mchehab@redhat.com: Tested with a RC-6(0) IR - 16 bits]
Tested-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/rc/ir-rc6-decoder.c

index 140fb67e2f89d9be9ce79a1b475a2fb24a900140..4cfdd7fa4bbd56b7d04f130b78020f8977ebaec6 100644 (file)
 /*
  * This decoder currently supports:
  * RC6-0-16    (standard toggle bit in header)
+ * RC6-6A-20   (no toggle bit)
  * RC6-6A-24   (no toggle bit)
  * RC6-6A-32   (MCE version with toggle bit in body)
  */
 
-#define RC6_UNIT               444444  /* us */
+#define RC6_UNIT               444444  /* nanosecs */
 #define RC6_HEADER_NBITS       4       /* not including toggle bit */
 #define RC6_0_NBITS            16
-#define RC6_6A_SMALL_NBITS     24
-#define RC6_6A_LARGE_NBITS     32
+#define RC6_6A_32_NBITS                32
+#define RC6_6A_NBITS           128     /* Variable 8..128 */
 #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_SUFFIX_SPACE       (6 * 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 */
+#define RC6_6A_LCC_MASK                0xffff0000 /* RC6-6A-32 long customer code mask */
+#define RC6_6A_MCE_CC          0x800f0000 /* MCE customer code */
+#ifndef CHAR_BIT
+#define CHAR_BIT 8     /* Normally in <limits.h> */
+#endif
 
 enum rc6_mode {
        RC6_MODE_0,
@@ -125,6 +132,7 @@ again:
                        break;
 
                data->state = STATE_HEADER_BIT_START;
+               data->header = 0;
                return 0;
 
        case STATE_HEADER_BIT_START:
@@ -171,20 +179,14 @@ again:
                data->state = STATE_BODY_BIT_START;
                decrease_duration(&ev, RC6_TOGGLE_END);
                data->count = 0;
+               data->body = 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;
+                       data->wanted_bits = RC6_6A_NBITS;
                        break;
                default:
                        IR_dprintk(1, "RC6 unknown mode\n");
@@ -193,15 +195,21 @@ again:
                goto again;
 
        case STATE_BODY_BIT_START:
-               if (!eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2))
-                       break;
-
-               data->body <<= 1;
-               if (ev.pulse)
-                       data->body |= 1;
-               data->count++;
-               data->state = STATE_BODY_BIT_END;
-               return 0;
+               if (eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2)) {
+                       /* Discard LSB's that won't fit in data->body */
+                       if (data->count++ < CHAR_BIT * sizeof data->body) {
+                               data->body <<= 1;
+                               if (ev.pulse)
+                                       data->body |= 1;
+                       }
+                       data->state = STATE_BODY_BIT_END;
+                       return 0;
+               } else if (RC6_MODE_6A == rc6_mode(data) && !ev.pulse &&
+                               geq_margin(ev.duration, RC6_SUFFIX_SPACE, RC6_UNIT / 2)) {
+                       data->state = STATE_FINISHED;
+                       goto again;
+               }
+               break;
 
        case STATE_BODY_BIT_END:
                if (!is_transition(&ev, &dev->raw->prev_ev))
@@ -221,20 +229,27 @@ again:
 
                switch (rc6_mode(data)) {
                case RC6_MODE_0:
-                       scancode = data->body & 0xffff;
+                       scancode = data->body;
                        toggle = data->toggle;
                        IR_dprintk(1, "RC6(0) scancode 0x%04x (toggle: %u)\n",
                                   scancode, toggle);
                        break;
                case RC6_MODE_6A:
-                       if (data->wanted_bits == RC6_6A_LARGE_NBITS) {
-                               toggle = data->body & RC6_6A_MCE_TOGGLE_MASK ? 1 : 0;
-                               scancode = data->body & ~RC6_6A_MCE_TOGGLE_MASK;
+                       if (data->count > CHAR_BIT * sizeof data->body) {
+                               IR_dprintk(1, "RC6 too many (%u) data bits\n",
+                                       data->count);
+                               goto out;
+                       }
+
+                       scancode = data->body;
+                       if (data->count == RC6_6A_32_NBITS &&
+                                       (scancode & RC6_6A_LCC_MASK) == RC6_6A_MCE_CC) {
+                               /* MCE RC */
+                               toggle = (scancode & RC6_6A_MCE_TOGGLE_MASK) ? 1 : 0;
+                               scancode &= ~RC6_6A_MCE_TOGGLE_MASK;
                        } else {
                                toggle = 0;
-                               scancode = data->body & 0xffffff;
                        }
-
                        IR_dprintk(1, "RC6(6A) scancode 0x%08x (toggle: %u)\n",
                                   scancode, toggle);
                        break;