aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/rc
diff options
context:
space:
mode:
authorlawrence rust <lawrence@softsystem.co.uk>2011-10-31 07:39:32 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-11-23 19:23:15 -0500
commitdb9bc660cf4d1a09565f5db2bab9d3b86e3e32a5 (patch)
treef14fea3ad632f63a541821b663f0277241dcba8a /drivers/media/rc
parent12cbfd0a3c52a52c2948c91b9e62e73c468d1572 (diff)
[media] ir-rc6-decoder: Support RC6-6A variable length data
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>
Diffstat (limited to 'drivers/media/rc')
-rw-r--r--drivers/media/rc/ir-rc6-decoder.c67
1 files changed, 41 insertions, 26 deletions
diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c
index 140fb67e2f89..4cfdd7fa4bbd 100644
--- a/drivers/media/rc/ir-rc6-decoder.c
+++ b/drivers/media/rc/ir-rc6-decoder.c
@@ -18,24 +18,31 @@
18/* 18/*
19 * This decoder currently supports: 19 * This decoder currently supports:
20 * RC6-0-16 (standard toggle bit in header) 20 * RC6-0-16 (standard toggle bit in header)
21 * RC6-6A-20 (no toggle bit)
21 * RC6-6A-24 (no toggle bit) 22 * RC6-6A-24 (no toggle bit)
22 * RC6-6A-32 (MCE version with toggle bit in body) 23 * RC6-6A-32 (MCE version with toggle bit in body)
23 */ 24 */
24 25
25#define RC6_UNIT 444444 /* us */ 26#define RC6_UNIT 444444 /* nanosecs */
26#define RC6_HEADER_NBITS 4 /* not including toggle bit */ 27#define RC6_HEADER_NBITS 4 /* not including toggle bit */
27#define RC6_0_NBITS 16 28#define RC6_0_NBITS 16
28#define RC6_6A_SMALL_NBITS 24 29#define RC6_6A_32_NBITS 32
29#define RC6_6A_LARGE_NBITS 32 30#define RC6_6A_NBITS 128 /* Variable 8..128 */
30#define RC6_PREFIX_PULSE (6 * RC6_UNIT) 31#define RC6_PREFIX_PULSE (6 * RC6_UNIT)
31#define RC6_PREFIX_SPACE (2 * RC6_UNIT) 32#define RC6_PREFIX_SPACE (2 * RC6_UNIT)
32#define RC6_BIT_START (1 * RC6_UNIT) 33#define RC6_BIT_START (1 * RC6_UNIT)
33#define RC6_BIT_END (1 * RC6_UNIT) 34#define RC6_BIT_END (1 * RC6_UNIT)
34#define RC6_TOGGLE_START (2 * RC6_UNIT) 35#define RC6_TOGGLE_START (2 * RC6_UNIT)
35#define RC6_TOGGLE_END (2 * RC6_UNIT) 36#define RC6_TOGGLE_END (2 * RC6_UNIT)
37#define RC6_SUFFIX_SPACE (6 * RC6_UNIT)
36#define RC6_MODE_MASK 0x07 /* for the header bits */ 38#define RC6_MODE_MASK 0x07 /* for the header bits */
37#define RC6_STARTBIT_MASK 0x08 /* for the header bits */ 39#define RC6_STARTBIT_MASK 0x08 /* for the header bits */
38#define RC6_6A_MCE_TOGGLE_MASK 0x8000 /* for the body bits */ 40#define RC6_6A_MCE_TOGGLE_MASK 0x8000 /* for the body bits */
41#define RC6_6A_LCC_MASK 0xffff0000 /* RC6-6A-32 long customer code mask */
42#define RC6_6A_MCE_CC 0x800f0000 /* MCE customer code */
43#ifndef CHAR_BIT
44#define CHAR_BIT 8 /* Normally in <limits.h> */
45#endif
39 46
40enum rc6_mode { 47enum rc6_mode {
41 RC6_MODE_0, 48 RC6_MODE_0,
@@ -125,6 +132,7 @@ again:
125 break; 132 break;
126 133
127 data->state = STATE_HEADER_BIT_START; 134 data->state = STATE_HEADER_BIT_START;
135 data->header = 0;
128 return 0; 136 return 0;
129 137
130 case STATE_HEADER_BIT_START: 138 case STATE_HEADER_BIT_START:
@@ -171,20 +179,14 @@ again:
171 data->state = STATE_BODY_BIT_START; 179 data->state = STATE_BODY_BIT_START;
172 decrease_duration(&ev, RC6_TOGGLE_END); 180 decrease_duration(&ev, RC6_TOGGLE_END);
173 data->count = 0; 181 data->count = 0;
182 data->body = 0;
174 183
175 switch (rc6_mode(data)) { 184 switch (rc6_mode(data)) {
176 case RC6_MODE_0: 185 case RC6_MODE_0:
177 data->wanted_bits = RC6_0_NBITS; 186 data->wanted_bits = RC6_0_NBITS;
178 break; 187 break;
179 case RC6_MODE_6A: 188 case RC6_MODE_6A:
180 /* This might look weird, but we basically 189 data->wanted_bits = RC6_6A_NBITS;
181 check the value of the first body bit to
182 determine the number of bits in mode 6A */
183 if ((!ev.pulse && !geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2)) ||
184 geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2))
185 data->wanted_bits = RC6_6A_LARGE_NBITS;
186 else
187 data->wanted_bits = RC6_6A_SMALL_NBITS;
188 break; 190 break;
189 default: 191 default:
190 IR_dprintk(1, "RC6 unknown mode\n"); 192 IR_dprintk(1, "RC6 unknown mode\n");
@@ -193,15 +195,21 @@ again:
193 goto again; 195 goto again;
194 196
195 case STATE_BODY_BIT_START: 197 case STATE_BODY_BIT_START:
196 if (!eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2)) 198 if (eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2)) {
197 break; 199 /* Discard LSB's that won't fit in data->body */
198 200 if (data->count++ < CHAR_BIT * sizeof data->body) {
199 data->body <<= 1; 201 data->body <<= 1;
200 if (ev.pulse) 202 if (ev.pulse)
201 data->body |= 1; 203 data->body |= 1;
202 data->count++; 204 }
203 data->state = STATE_BODY_BIT_END; 205 data->state = STATE_BODY_BIT_END;
204 return 0; 206 return 0;
207 } else if (RC6_MODE_6A == rc6_mode(data) && !ev.pulse &&
208 geq_margin(ev.duration, RC6_SUFFIX_SPACE, RC6_UNIT / 2)) {
209 data->state = STATE_FINISHED;
210 goto again;
211 }
212 break;
205 213
206 case STATE_BODY_BIT_END: 214 case STATE_BODY_BIT_END:
207 if (!is_transition(&ev, &dev->raw->prev_ev)) 215 if (!is_transition(&ev, &dev->raw->prev_ev))
@@ -221,20 +229,27 @@ again:
221 229
222 switch (rc6_mode(data)) { 230 switch (rc6_mode(data)) {
223 case RC6_MODE_0: 231 case RC6_MODE_0:
224 scancode = data->body & 0xffff; 232 scancode = data->body;
225 toggle = data->toggle; 233 toggle = data->toggle;
226 IR_dprintk(1, "RC6(0) scancode 0x%04x (toggle: %u)\n", 234 IR_dprintk(1, "RC6(0) scancode 0x%04x (toggle: %u)\n",
227 scancode, toggle); 235 scancode, toggle);
228 break; 236 break;
229 case RC6_MODE_6A: 237 case RC6_MODE_6A:
230 if (data->wanted_bits == RC6_6A_LARGE_NBITS) { 238 if (data->count > CHAR_BIT * sizeof data->body) {
231 toggle = data->body & RC6_6A_MCE_TOGGLE_MASK ? 1 : 0; 239 IR_dprintk(1, "RC6 too many (%u) data bits\n",
232 scancode = data->body & ~RC6_6A_MCE_TOGGLE_MASK; 240 data->count);
241 goto out;
242 }
243
244 scancode = data->body;
245 if (data->count == RC6_6A_32_NBITS &&
246 (scancode & RC6_6A_LCC_MASK) == RC6_6A_MCE_CC) {
247 /* MCE RC */
248 toggle = (scancode & RC6_6A_MCE_TOGGLE_MASK) ? 1 : 0;
249 scancode &= ~RC6_6A_MCE_TOGGLE_MASK;
233 } else { 250 } else {
234 toggle = 0; 251 toggle = 0;
235 scancode = data->body & 0xffffff;
236 } 252 }
237
238 IR_dprintk(1, "RC6(6A) scancode 0x%08x (toggle: %u)\n", 253 IR_dprintk(1, "RC6(6A) scancode 0x%08x (toggle: %u)\n",
239 scancode, toggle); 254 scancode, toggle);
240 break; 255 break;