diff options
author | David Härdeman <david@hardeman.nu> | 2010-04-15 17:46:00 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-05-19 11:57:42 -0400 |
commit | e40b1127f994a427568319d1be9b9e5ab1f58dd1 (patch) | |
tree | 5d4f892dbe90588f8932cd4e1768b953814f3f47 /drivers/media/IR/ir-rc6-decoder.c | |
parent | 21677cfc562a27e099719d413287bc8d1d24deb7 (diff) |
V4L/DVB: ir-core: change duration to be coded as a u32 integer
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>
Diffstat (limited to 'drivers/media/IR/ir-rc6-decoder.c')
-rw-r--r-- | drivers/media/IR/ir-rc6-decoder.c | 221 |
1 files changed, 114 insertions, 107 deletions
diff --git a/drivers/media/IR/ir-rc6-decoder.c b/drivers/media/IR/ir-rc6-decoder.c index ccc5be240f82..2bf479f4f1bc 100644 --- a/drivers/media/IR/ir-rc6-decoder.c +++ b/drivers/media/IR/ir-rc6-decoder.c | |||
@@ -26,8 +26,12 @@ | |||
26 | #define RC6_0_NBITS 16 | 26 | #define RC6_0_NBITS 16 |
27 | #define RC6_6A_SMALL_NBITS 24 | 27 | #define RC6_6A_SMALL_NBITS 24 |
28 | #define RC6_6A_LARGE_NBITS 32 | 28 | #define RC6_6A_LARGE_NBITS 32 |
29 | #define RC6_PREFIX_PULSE PULSE(6) | 29 | #define RC6_PREFIX_PULSE (6 * RC6_UNIT) |
30 | #define RC6_PREFIX_SPACE SPACE(2) | 30 | #define RC6_PREFIX_SPACE (2 * RC6_UNIT) |
31 | #define RC6_BIT_START (1 * RC6_UNIT) | ||
32 | #define RC6_BIT_END (1 * RC6_UNIT) | ||
33 | #define RC6_TOGGLE_START (2 * RC6_UNIT) | ||
34 | #define RC6_TOGGLE_END (2 * RC6_UNIT) | ||
31 | #define RC6_MODE_MASK 0x07 /* for the header bits */ | 35 | #define RC6_MODE_MASK 0x07 /* for the header bits */ |
32 | #define RC6_STARTBIT_MASK 0x08 /* for the header bits */ | 36 | #define RC6_STARTBIT_MASK 0x08 /* for the header bits */ |
33 | #define RC6_6A_MCE_TOGGLE_MASK 0x8000 /* for the body bits */ | 37 | #define RC6_6A_MCE_TOGGLE_MASK 0x8000 /* for the body bits */ |
@@ -63,7 +67,7 @@ struct decoder_data { | |||
63 | enum rc6_state state; | 67 | enum rc6_state state; |
64 | u8 header; | 68 | u8 header; |
65 | u32 body; | 69 | u32 body; |
66 | int last_unit; | 70 | struct ir_raw_event prev_ev; |
67 | bool toggle; | 71 | bool toggle; |
68 | unsigned count; | 72 | unsigned count; |
69 | unsigned wanted_bits; | 73 | unsigned wanted_bits; |
@@ -152,17 +156,16 @@ static enum rc6_mode rc6_mode(struct decoder_data *data) { | |||
152 | /** | 156 | /** |
153 | * ir_rc6_decode() - Decode one RC6 pulse or space | 157 | * ir_rc6_decode() - Decode one RC6 pulse or space |
154 | * @input_dev: the struct input_dev descriptor of the device | 158 | * @input_dev: the struct input_dev descriptor of the device |
155 | * @duration: duration of pulse/space in ns | 159 | * @ev: the struct ir_raw_event descriptor of the pulse/space |
156 | * | 160 | * |
157 | * This function returns -EINVAL if the pulse violates the state machine | 161 | * This function returns -EINVAL if the pulse violates the state machine |
158 | */ | 162 | */ |
159 | static int ir_rc6_decode(struct input_dev *input_dev, s64 duration) | 163 | static int ir_rc6_decode(struct input_dev *input_dev, struct ir_raw_event ev) |
160 | { | 164 | { |
161 | struct decoder_data *data; | 165 | struct decoder_data *data; |
162 | struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); | 166 | struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); |
163 | u32 scancode; | 167 | u32 scancode; |
164 | u8 toggle; | 168 | u8 toggle; |
165 | int u; | ||
166 | 169 | ||
167 | data = get_decoder_data(ir_dev); | 170 | data = get_decoder_data(ir_dev); |
168 | if (!data) | 171 | if (!data) |
@@ -171,140 +174,144 @@ static int ir_rc6_decode(struct input_dev *input_dev, s64 duration) | |||
171 | if (!data->enabled) | 174 | if (!data->enabled) |
172 | return 0; | 175 | return 0; |
173 | 176 | ||
174 | if (IS_RESET(duration)) { | 177 | if (IS_RESET(ev)) { |
175 | data->state = STATE_INACTIVE; | 178 | data->state = STATE_INACTIVE; |
176 | return 0; | 179 | return 0; |
177 | } | 180 | } |
178 | 181 | ||
179 | u = TO_UNITS(duration, RC6_UNIT); | 182 | if (!geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2)) |
180 | if (DURATION(u) == 0) | ||
181 | goto out; | 183 | goto out; |
182 | 184 | ||
183 | again: | 185 | again: |
184 | IR_dprintk(2, "RC6 decode started at state %i (%i units, %ius)\n", | 186 | IR_dprintk(2, "RC6 decode started at state %i (%uus %s)\n", |
185 | data->state, u, TO_US(duration)); | 187 | data->state, TO_US(ev.duration), TO_STR(ev.pulse)); |
186 | 188 | ||
187 | if (DURATION(u) == 0 && data->state != STATE_FINISHED) | 189 | if (!geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2)) |
188 | return 0; | 190 | return 0; |
189 | 191 | ||
190 | switch (data->state) { | 192 | switch (data->state) { |
191 | 193 | ||
192 | case STATE_INACTIVE: | 194 | case STATE_INACTIVE: |
193 | if (u >= RC6_PREFIX_PULSE - 1 && u <= RC6_PREFIX_PULSE + 1) { | 195 | if (!ev.pulse) |
194 | data->state = STATE_PREFIX_SPACE; | 196 | break; |
195 | data->count = 0; | 197 | |
196 | return 0; | 198 | /* Note: larger margin on first pulse since each RC6_UNIT |
197 | } | 199 | is quite short and some hardware takes some time to |
198 | break; | 200 | adjust to the signal */ |
201 | if (!eq_margin(ev.duration, RC6_PREFIX_PULSE, RC6_UNIT)) | ||
202 | break; | ||
203 | |||
204 | data->state = STATE_PREFIX_SPACE; | ||
205 | data->count = 0; | ||
206 | return 0; | ||
199 | 207 | ||
200 | case STATE_PREFIX_SPACE: | 208 | case STATE_PREFIX_SPACE: |
201 | if (u == RC6_PREFIX_SPACE) { | 209 | if (ev.pulse) |
202 | data->state = STATE_HEADER_BIT_START; | 210 | break; |
203 | return 0; | 211 | |
204 | } | 212 | if (!eq_margin(ev.duration, RC6_PREFIX_SPACE, RC6_UNIT / 2)) |
205 | break; | 213 | break; |
214 | |||
215 | data->state = STATE_HEADER_BIT_START; | ||
216 | return 0; | ||
206 | 217 | ||
207 | case STATE_HEADER_BIT_START: | 218 | case STATE_HEADER_BIT_START: |
208 | if (DURATION(u) == 1) { | 219 | if (!eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2)) |
209 | data->header <<= 1; | 220 | break; |
210 | if (IS_PULSE(u)) | 221 | |
211 | data->header |= 1; | 222 | data->header <<= 1; |
212 | data->count++; | 223 | if (ev.pulse) |
213 | data->last_unit = u; | 224 | data->header |= 1; |
214 | data->state = STATE_HEADER_BIT_END; | 225 | data->count++; |
215 | return 0; | 226 | data->prev_ev = ev; |
216 | } | 227 | data->state = STATE_HEADER_BIT_END; |
217 | break; | 228 | return 0; |
218 | 229 | ||
219 | case STATE_HEADER_BIT_END: | 230 | case STATE_HEADER_BIT_END: |
220 | if (IS_TRANSITION(u, data->last_unit)) { | 231 | if (!is_transition(&ev, &data->prev_ev)) |
221 | if (data->count == RC6_HEADER_NBITS) | 232 | break; |
222 | data->state = STATE_TOGGLE_START; | ||
223 | else | ||
224 | data->state = STATE_HEADER_BIT_START; | ||
225 | 233 | ||
226 | DECREASE_DURATION(u, 1); | 234 | if (data->count == RC6_HEADER_NBITS) |
227 | goto again; | 235 | data->state = STATE_TOGGLE_START; |
228 | } | 236 | else |
229 | break; | 237 | data->state = STATE_HEADER_BIT_START; |
238 | |||
239 | decrease_duration(&ev, RC6_BIT_END); | ||
240 | goto again; | ||
230 | 241 | ||
231 | case STATE_TOGGLE_START: | 242 | case STATE_TOGGLE_START: |
232 | if (DURATION(u) == 2) { | 243 | if (!eq_margin(ev.duration, RC6_TOGGLE_START, RC6_UNIT / 2)) |
233 | data->toggle = IS_PULSE(u); | 244 | break; |
234 | data->last_unit = u; | 245 | |
235 | data->state = STATE_TOGGLE_END; | 246 | data->toggle = ev.pulse; |
236 | return 0; | 247 | data->prev_ev = ev; |
237 | } | 248 | data->state = STATE_TOGGLE_END; |
238 | break; | 249 | return 0; |
239 | 250 | ||
240 | case STATE_TOGGLE_END: | 251 | case STATE_TOGGLE_END: |
241 | if (IS_TRANSITION(u, data->last_unit) && DURATION(u) >= 2) { | 252 | if (!is_transition(&ev, &data->prev_ev) || |
242 | data->state = STATE_BODY_BIT_START; | 253 | !geq_margin(ev.duration, RC6_TOGGLE_END, RC6_UNIT / 2)) |
243 | data->last_unit = u; | 254 | break; |
244 | DECREASE_DURATION(u, 2); | ||
245 | data->count = 0; | ||
246 | 255 | ||
247 | if (!(data->header & RC6_STARTBIT_MASK)) { | 256 | if (!(data->header & RC6_STARTBIT_MASK)) { |
248 | IR_dprintk(1, "RC6 invalid start bit\n"); | 257 | IR_dprintk(1, "RC6 invalid start bit\n"); |
249 | break; | 258 | break; |
250 | } | 259 | } |
251 | 260 | ||
252 | switch (rc6_mode(data)) { | 261 | data->state = STATE_BODY_BIT_START; |
253 | case RC6_MODE_0: | 262 | data->prev_ev = ev; |
254 | data->wanted_bits = RC6_0_NBITS; | 263 | decrease_duration(&ev, RC6_TOGGLE_END); |
255 | break; | 264 | data->count = 0; |
256 | case RC6_MODE_6A: | 265 | |
257 | /* This might look weird, but we basically | 266 | switch (rc6_mode(data)) { |
258 | check the value of the first body bit to | 267 | case RC6_MODE_0: |
259 | determine the number of bits in mode 6A */ | 268 | data->wanted_bits = RC6_0_NBITS; |
260 | if ((DURATION(u) == 0 && IS_SPACE(data->last_unit)) || DURATION(u) > 0) | 269 | break; |
261 | data->wanted_bits = RC6_6A_LARGE_NBITS; | 270 | case RC6_MODE_6A: |
262 | else | 271 | /* This might look weird, but we basically |
263 | data->wanted_bits = RC6_6A_SMALL_NBITS; | 272 | check the value of the first body bit to |
264 | break; | 273 | determine the number of bits in mode 6A */ |
265 | default: | 274 | if ((!ev.pulse && !geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2)) || |
266 | IR_dprintk(1, "RC6 unknown mode\n"); | 275 | geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2)) |
267 | goto out; | 276 | data->wanted_bits = RC6_6A_LARGE_NBITS; |
268 | } | 277 | else |
269 | goto again; | 278 | data->wanted_bits = RC6_6A_SMALL_NBITS; |
279 | break; | ||
280 | default: | ||
281 | IR_dprintk(1, "RC6 unknown mode\n"); | ||
282 | goto out; | ||
270 | } | 283 | } |
271 | break; | 284 | goto again; |
272 | 285 | ||
273 | case STATE_BODY_BIT_START: | 286 | case STATE_BODY_BIT_START: |
274 | if (DURATION(u) == 1) { | 287 | if (!eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2)) |
275 | data->body <<= 1; | 288 | break; |
276 | if (IS_PULSE(u)) | ||
277 | data->body |= 1; | ||
278 | data->count++; | ||
279 | data->last_unit = u; | ||
280 | |||
281 | /* | ||
282 | * If the last bit is one, a space will merge | ||
283 | * with the silence after the command. | ||
284 | */ | ||
285 | if (IS_PULSE(u) && data->count == data->wanted_bits) { | ||
286 | data->state = STATE_FINISHED; | ||
287 | goto again; | ||
288 | } | ||
289 | 289 | ||
290 | data->state = STATE_BODY_BIT_END; | 290 | data->body <<= 1; |
291 | return 0; | 291 | if (ev.pulse) |
292 | } | 292 | data->body |= 1; |
293 | break; | 293 | data->count++; |
294 | data->prev_ev = ev; | ||
295 | |||
296 | data->state = STATE_BODY_BIT_END; | ||
297 | return 0; | ||
294 | 298 | ||
295 | case STATE_BODY_BIT_END: | 299 | case STATE_BODY_BIT_END: |
296 | if (IS_TRANSITION(u, data->last_unit)) { | 300 | if (!is_transition(&ev, &data->prev_ev)) |
297 | if (data->count == data->wanted_bits) | 301 | break; |
298 | data->state = STATE_FINISHED; | ||
299 | else | ||
300 | data->state = STATE_BODY_BIT_START; | ||
301 | 302 | ||
302 | DECREASE_DURATION(u, 1); | 303 | if (data->count == data->wanted_bits) |
303 | goto again; | 304 | data->state = STATE_FINISHED; |
304 | } | 305 | else |
305 | break; | 306 | data->state = STATE_BODY_BIT_START; |
307 | |||
308 | decrease_duration(&ev, RC6_BIT_END); | ||
309 | goto again; | ||
306 | 310 | ||
307 | case STATE_FINISHED: | 311 | case STATE_FINISHED: |
312 | if (ev.pulse) | ||
313 | break; | ||
314 | |||
308 | switch (rc6_mode(data)) { | 315 | switch (rc6_mode(data)) { |
309 | case RC6_MODE_0: | 316 | case RC6_MODE_0: |
310 | scancode = data->body & 0xffff; | 317 | scancode = data->body & 0xffff; |
@@ -335,8 +342,8 @@ again: | |||
335 | } | 342 | } |
336 | 343 | ||
337 | out: | 344 | out: |
338 | IR_dprintk(1, "RC6 decode failed at state %i (%i units, %ius)\n", | 345 | IR_dprintk(1, "RC6 decode failed at state %i (%uus %s)\n", |
339 | data->state, u, TO_US(duration)); | 346 | data->state, TO_US(ev.duration), TO_STR(ev.pulse)); |
340 | data->state = STATE_INACTIVE; | 347 | data->state = STATE_INACTIVE; |
341 | return -EINVAL; | 348 | return -EINVAL; |
342 | } | 349 | } |