aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/IR/ir-rc5-decoder.c
diff options
context:
space:
mode:
authorDavid Härdeman <david@hardeman.nu>2010-04-08 12:10:00 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-05-19 11:57:03 -0400
commit724e2495502a98aaa3f93c404472a991da8ff857 (patch)
treedfdc90b4408fa95f7757b1c6e5b36c2789da0df2 /drivers/media/IR/ir-rc5-decoder.c
parentd22e546ea18ee66c255af906f2714d3ee82d4b42 (diff)
V4L/DVB: Teach drivers/media/IR/ir-raw-event.c to use durations
drivers/media/IR/ir-raw-event.c is currently written with the assumption that all "raw" hardware will generate events only on state change (i.e. when a pulse or space starts). However, some hardware (like mceusb, probably the most popular IR receiver out there) only generates duration data (and that data is buffered so using any kind of timing on the data is futile). Furthermore, using signed int's to represent pulse/space durations is a well-known approach when writing ir decoders. With this patch: - s64 int's are used to represent pulse/space durations in ns - a workqueue is used to decode the ir protocols outside of interrupt context - #defines are added to make decoders clearer - decoder reset is implemented by passing a zero duration to the kfifo queue and decoders are updated accordingly Signed-off-by: David Härdeman <david@hardeman.nu> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/IR/ir-rc5-decoder.c')
-rw-r--r--drivers/media/IR/ir-rc5-decoder.c150
1 files changed, 75 insertions, 75 deletions
diff --git a/drivers/media/IR/ir-rc5-decoder.c b/drivers/media/IR/ir-rc5-decoder.c
index 6323066438b5..1d0857b69089 100644
--- a/drivers/media/IR/ir-rc5-decoder.c
+++ b/drivers/media/IR/ir-rc5-decoder.c
@@ -21,11 +21,8 @@
21 21
22#include <media/ir-core.h> 22#include <media/ir-core.h>
23 23
24static unsigned int ir_rc5_remote_gap = 888888;
25
26#define RC5_NBITS 14 24#define RC5_NBITS 14
27#define RC5_BIT (ir_rc5_remote_gap * 2) 25#define RC5_UNIT 888888 /* ns */
28#define RC5_DURATION (ir_rc5_remote_gap * RC5_NBITS)
29 26
30/* Used to register rc5_decoder clients */ 27/* Used to register rc5_decoder clients */
31static LIST_HEAD(decoder_list); 28static LIST_HEAD(decoder_list);
@@ -33,13 +30,9 @@ static DEFINE_SPINLOCK(decoder_lock);
33 30
34enum rc5_state { 31enum rc5_state {
35 STATE_INACTIVE, 32 STATE_INACTIVE,
36 STATE_MARKSPACE, 33 STATE_BIT_START,
37 STATE_TRAILER, 34 STATE_BIT_END,
38}; 35 STATE_FINISHED,
39
40struct rc5_code {
41 u8 address;
42 u8 command;
43}; 36};
44 37
45struct decoder_data { 38struct decoder_data {
@@ -49,8 +42,9 @@ struct decoder_data {
49 42
50 /* State machine control */ 43 /* State machine control */
51 enum rc5_state state; 44 enum rc5_state state;
52 struct rc5_code rc5_code; 45 u32 rc5_bits;
53 unsigned code, elapsed, last_bit, last_code; 46 int last_unit;
47 unsigned count;
54}; 48};
55 49
56 50
@@ -122,18 +116,19 @@ static struct attribute_group decoder_attribute_group = {
122}; 116};
123 117
124/** 118/**
125 * handle_event() - Decode one RC-5 pulse or space 119 * ir_rc5_decode() - Decode one RC-5 pulse or space
126 * @input_dev: the struct input_dev descriptor of the device 120 * @input_dev: the struct input_dev descriptor of the device
127 * @ev: event array with type/duration of pulse/space 121 * @duration: duration of pulse/space in ns
128 * 122 *
129 * This function returns -EINVAL if the pulse violates the state machine 123 * This function returns -EINVAL if the pulse violates the state machine
130 */ 124 */
131static int ir_rc5_decode(struct input_dev *input_dev, 125static int ir_rc5_decode(struct input_dev *input_dev, s64 duration)
132 struct ir_raw_event *ev)
133{ 126{
134 struct decoder_data *data; 127 struct decoder_data *data;
135 struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); 128 struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
136 int is_pulse, scancode, delta, toggle; 129 u8 command, system, toggle;
130 u32 scancode;
131 int u;
137 132
138 data = get_decoder_data(ir_dev); 133 data = get_decoder_data(ir_dev);
139 if (!data) 134 if (!data)
@@ -142,79 +137,84 @@ static int ir_rc5_decode(struct input_dev *input_dev,
142 if (!data->enabled) 137 if (!data->enabled)
143 return 0; 138 return 0;
144 139
145 delta = DIV_ROUND_CLOSEST(ev->delta.tv_nsec, ir_rc5_remote_gap); 140 if (IS_RESET(duration)) {
146
147 /* The duration time refers to the last bit time */
148 is_pulse = (ev->type & IR_PULSE) ? 1 : 0;
149
150 /* Very long delays are considered as start events */
151 if (delta > RC5_DURATION || (ev->type & IR_START_EVENT))
152 data->state = STATE_INACTIVE; 141 data->state = STATE_INACTIVE;
153
154 switch (data->state) {
155 case STATE_INACTIVE:
156 IR_dprintk(2, "currently inative. Start bit (%s) @%uus\n",
157 is_pulse ? "pulse" : "space",
158 (unsigned)(ev->delta.tv_nsec + 500) / 1000);
159
160 /* Discards the initial start space */
161 if (!is_pulse)
162 goto err;
163 data->code = 1;
164 data->last_bit = 1;
165 data->elapsed = 0;
166 memset(&data->rc5_code, 0, sizeof(data->rc5_code));
167 data->state = STATE_MARKSPACE;
168 return 0; 142 return 0;
169 case STATE_MARKSPACE: 143 }
170 if (delta != 1)
171 data->last_bit = data->last_bit ? 0 : 1;
172 144
173 data->elapsed += delta; 145 u = TO_UNITS(duration, RC5_UNIT);
146 if (DURATION(u) == 0)
147 goto out;
174 148
175 if ((data->elapsed % 2) == 1) 149again:
176 return 0; 150 IR_dprintk(2, "RC5 decode started at state %i (%i units, %ius)\n",
151 data->state, u, TO_US(duration));
177 152
178 data->code <<= 1; 153 if (DURATION(u) == 0 && data->state != STATE_FINISHED)
179 data->code |= data->last_bit; 154 return 0;
180
181 /* Fill the 2 unused bits at the command with 0 */
182 if (data->elapsed / 2 == 6)
183 data->code <<= 2;
184 155
185 if (data->elapsed >= (RC5_NBITS - 1) * 2) { 156 switch (data->state) {
186 scancode = data->code;
187 157
188 /* Check for the start bits */ 158 case STATE_INACTIVE:
189 if ((scancode & 0xc000) != 0xc000) { 159 if (IS_PULSE(u)) {
190 IR_dprintk(1, "Code 0x%04x doesn't have two start bits. It is not RC-5\n", scancode); 160 data->state = STATE_BIT_START;
191 goto err; 161 data->count = 1;
162 DECREASE_DURATION(u, 1);
163 goto again;
164 }
165 break;
166
167 case STATE_BIT_START:
168 if (DURATION(u) == 1) {
169 data->rc5_bits <<= 1;
170 if (IS_SPACE(u))
171 data->rc5_bits |= 1;
172 data->count++;
173 data->last_unit = u;
174
175 /*
176 * If the last bit is zero, a space will merge
177 * with the silence after the command.
178 */
179 if (IS_PULSE(u) && data->count == RC5_NBITS) {
180 data->state = STATE_FINISHED;
181 goto again;
192 } 182 }
193 183
194 toggle = (scancode & 0x2000) ? 1 : 0; 184 data->state = STATE_BIT_END;
185 return 0;
186 }
187 break;
195 188
196 if (scancode == data->last_code) { 189 case STATE_BIT_END:
197 IR_dprintk(1, "RC-5 repeat\n"); 190 if (IS_TRANSITION(u, data->last_unit)) {
198 ir_repeat(input_dev); 191 if (data->count == RC5_NBITS)
199 } else { 192 data->state = STATE_FINISHED;
200 data->last_code = scancode; 193 else
201 scancode &= 0x1fff; 194 data->state = STATE_BIT_START;
202 IR_dprintk(1, "RC-5 scancode 0x%04x\n", scancode);
203 195
204 ir_keydown(input_dev, scancode, 0); 196 DECREASE_DURATION(u, 1);
205 } 197 goto again;
206 data->state = STATE_TRAILER;
207 } 198 }
208 return 0; 199 break;
209 case STATE_TRAILER: 200
201 case STATE_FINISHED:
202 command = (data->rc5_bits & 0x0003F) >> 0;
203 system = (data->rc5_bits & 0x007C0) >> 6;
204 toggle = (data->rc5_bits & 0x00800) ? 1 : 0;
205 command += (data->rc5_bits & 0x01000) ? 0 : 0x40;
206 scancode = system << 8 | command;
207
208 IR_dprintk(1, "RC5 scancode 0x%04x (toggle: %u)\n",
209 scancode, toggle);
210 ir_keydown(input_dev, scancode, toggle);
210 data->state = STATE_INACTIVE; 211 data->state = STATE_INACTIVE;
211 return 0; 212 return 0;
212 } 213 }
213 214
214err: 215out:
215 IR_dprintk(1, "RC-5 decoded failed at %s @ %luus\n", 216 IR_dprintk(1, "RC5 decode failed at state %i (%i units, %ius)\n",
216 is_pulse ? "pulse" : "space", 217 data->state, u, TO_US(duration));
217 (ev->delta.tv_nsec + 500) / 1000);
218 data->state = STATE_INACTIVE; 218 data->state = STATE_INACTIVE;
219 return -EINVAL; 219 return -EINVAL;
220} 220}