diff options
author | David Härdeman <david@hardeman.nu> | 2010-04-02 14:58:29 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-05-19 11:56:54 -0400 |
commit | a374fef4437abd0a1ee27afe0cca7a55425c1c3c (patch) | |
tree | 652e36573ac29d360d7f59cfb64a160c08390a54 | |
parent | 354389467b6b2a3b36666b6e933d78bbd9e23577 (diff) |
V4L/DVB: ir-core: improve keyup/keydown logic
Rewrites the keyup/keydown logic in drivers/media/IR/ir-keytable.c.
All knowledge of keystates etc is now internal to ir-keytable.c
and not scattered around ir-raw-event.c and ir-nec-decoder.c (where
it doesn't belong).
In addition, I've changed the API slightly so that ir_input_dev is
passed as the first argument rather than input_dev. If we're ever
going to support multiple keytables we need to move towards making
ir_input_dev the main interface from a driver POV and obscure away
the input_dev as an implementational detail in ir-core.
Signed-off-by: David Härdeman <david@hardeman.nu>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r-- | drivers/media/IR/ir-keytable.c | 125 | ||||
-rw-r--r-- | drivers/media/IR/ir-nec-decoder.c | 7 | ||||
-rw-r--r-- | drivers/media/IR/ir-raw-event.c | 14 | ||||
-rw-r--r-- | include/media/ir-core.h | 15 |
4 files changed, 113 insertions, 48 deletions
diff --git a/drivers/media/IR/ir-keytable.c b/drivers/media/IR/ir-keytable.c index a0aa5c1b6b41..a89456932f7c 100644 --- a/drivers/media/IR/ir-keytable.c +++ b/drivers/media/IR/ir-keytable.c | |||
@@ -21,6 +21,9 @@ | |||
21 | #define IR_TAB_MIN_SIZE 256 | 21 | #define IR_TAB_MIN_SIZE 256 |
22 | #define IR_TAB_MAX_SIZE 8192 | 22 | #define IR_TAB_MAX_SIZE 8192 |
23 | 23 | ||
24 | /* FIXME: IR_KEYPRESS_TIMEOUT should be protocol specific */ | ||
25 | #define IR_KEYPRESS_TIMEOUT 250 | ||
26 | |||
24 | /** | 27 | /** |
25 | * ir_resize_table() - resizes a scancode table if necessary | 28 | * ir_resize_table() - resizes a scancode table if necessary |
26 | * @rc_tab: the ir_scancode_table to resize | 29 | * @rc_tab: the ir_scancode_table to resize |
@@ -263,56 +266,124 @@ EXPORT_SYMBOL_GPL(ir_g_keycode_from_table); | |||
263 | 266 | ||
264 | /** | 267 | /** |
265 | * ir_keyup() - generates input event to cleanup a key press | 268 | * ir_keyup() - generates input event to cleanup a key press |
266 | * @input_dev: the struct input_dev descriptor of the device | 269 | * @ir: the struct ir_input_dev descriptor of the device |
267 | * | 270 | * |
268 | * This routine is used by the input routines when a key is pressed at the | 271 | * This routine is used to signal that a key has been released on the |
269 | * IR. It reports a keyup input event via input_report_key(). | 272 | * remote control. It reports a keyup input event via input_report_key(). |
273 | */ | ||
274 | static void ir_keyup(struct ir_input_dev *ir) | ||
275 | { | ||
276 | if (!ir->keypressed) | ||
277 | return; | ||
278 | |||
279 | IR_dprintk(1, "keyup key 0x%04x\n", ir->last_keycode); | ||
280 | input_report_key(ir->input_dev, ir->last_keycode, 0); | ||
281 | input_sync(ir->input_dev); | ||
282 | ir->keypressed = false; | ||
283 | } | ||
284 | |||
285 | /** | ||
286 | * ir_timer_keyup() - generates a keyup event after a timeout | ||
287 | * @cookie: a pointer to struct ir_input_dev passed to setup_timer() | ||
288 | * | ||
289 | * This routine will generate a keyup event some time after a keydown event | ||
290 | * is generated when no further activity has been detected. | ||
270 | */ | 291 | */ |
271 | void ir_keyup(struct input_dev *dev) | 292 | static void ir_timer_keyup(unsigned long cookie) |
272 | { | 293 | { |
294 | struct ir_input_dev *ir = (struct ir_input_dev *)cookie; | ||
295 | unsigned long flags; | ||
296 | |||
297 | /* | ||
298 | * ir->keyup_jiffies is used to prevent a race condition if a | ||
299 | * hardware interrupt occurs at this point and the keyup timer | ||
300 | * event is moved further into the future as a result. | ||
301 | * | ||
302 | * The timer will then be reactivated and this function called | ||
303 | * again in the future. We need to exit gracefully in that case | ||
304 | * to allow the input subsystem to do its auto-repeat magic or | ||
305 | * a keyup event might follow immediately after the keydown. | ||
306 | */ | ||
307 | spin_lock_irqsave(&ir->keylock, flags); | ||
308 | if (time_is_after_eq_jiffies(ir->keyup_jiffies)) | ||
309 | ir_keyup(ir); | ||
310 | spin_unlock_irqrestore(&ir->keylock, flags); | ||
311 | } | ||
312 | |||
313 | /** | ||
314 | * ir_repeat() - notifies the IR core that a key is still pressed | ||
315 | * @dev: the struct input_dev descriptor of the device | ||
316 | * | ||
317 | * This routine is used by IR decoders when a repeat message which does | ||
318 | * not include the necessary bits to reproduce the scancode has been | ||
319 | * received. | ||
320 | */ | ||
321 | void ir_repeat(struct input_dev *dev) | ||
322 | { | ||
323 | unsigned long flags; | ||
273 | struct ir_input_dev *ir = input_get_drvdata(dev); | 324 | struct ir_input_dev *ir = input_get_drvdata(dev); |
274 | 325 | ||
326 | spin_lock_irqsave(&ir->keylock, flags); | ||
327 | |||
275 | if (!ir->keypressed) | 328 | if (!ir->keypressed) |
276 | return; | 329 | goto out; |
277 | 330 | ||
278 | IR_dprintk(1, "keyup key 0x%04x\n", ir->keycode); | 331 | ir->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT); |
279 | input_report_key(dev, ir->keycode, 0); | 332 | mod_timer(&ir->timer_keyup, ir->keyup_jiffies); |
280 | input_sync(dev); | 333 | |
281 | ir->keypressed = 0; | 334 | out: |
335 | spin_unlock_irqrestore(&ir->keylock, flags); | ||
282 | } | 336 | } |
283 | EXPORT_SYMBOL_GPL(ir_keyup); | 337 | EXPORT_SYMBOL_GPL(ir_repeat); |
284 | 338 | ||
285 | /** | 339 | /** |
286 | * ir_keydown() - generates input event for a key press | 340 | * ir_keydown() - generates input event for a key press |
287 | * @input_dev: the struct input_dev descriptor of the device | 341 | * @dev: the struct input_dev descriptor of the device |
288 | * @scancode: the scancode that we're seeking | 342 | * @scancode: the scancode that we're seeking |
343 | * @toggle: the toggle value (protocol dependent, if the protocol doesn't | ||
344 | * support toggle values, this should be set to zero) | ||
289 | * | 345 | * |
290 | * This routine is used by the input routines when a key is pressed at the | 346 | * This routine is used by the input routines when a key is pressed at the |
291 | * IR. It gets the keycode for a scancode and reports an input event via | 347 | * IR. It gets the keycode for a scancode and reports an input event via |
292 | * input_report_key(). | 348 | * input_report_key(). |
293 | */ | 349 | */ |
294 | void ir_keydown(struct input_dev *dev, int scancode) | 350 | void ir_keydown(struct input_dev *dev, int scancode, u8 toggle) |
295 | { | 351 | { |
352 | unsigned long flags; | ||
296 | struct ir_input_dev *ir = input_get_drvdata(dev); | 353 | struct ir_input_dev *ir = input_get_drvdata(dev); |
297 | 354 | ||
298 | u32 keycode = ir_g_keycode_from_table(dev, scancode); | 355 | u32 keycode = ir_g_keycode_from_table(dev, scancode); |
299 | 356 | ||
300 | /* If already sent a keydown, do a keyup */ | 357 | spin_lock_irqsave(&ir->keylock, flags); |
301 | if (ir->keypressed) | ||
302 | ir_keyup(dev); | ||
303 | 358 | ||
304 | if (KEY_RESERVED == keycode) | 359 | /* Repeat event? */ |
305 | return; | 360 | if (ir->keypressed && |
361 | ir->last_scancode == scancode && | ||
362 | ir->last_toggle == toggle) | ||
363 | goto set_timer; | ||
306 | 364 | ||
307 | ir->keycode = keycode; | 365 | /* Release old keypress */ |
308 | ir->keypressed = 1; | 366 | ir_keyup(ir); |
309 | 367 | ||
310 | IR_dprintk(1, "%s: key down event, key 0x%04x, scancode 0x%04x\n", | 368 | ir->last_scancode = scancode; |
311 | dev->name, keycode, scancode); | 369 | ir->last_toggle = toggle; |
370 | ir->last_keycode = keycode; | ||
371 | |||
372 | if (keycode == KEY_RESERVED) | ||
373 | goto out; | ||
312 | 374 | ||
313 | input_report_key(dev, ir->keycode, 1); | 375 | /* Register a keypress */ |
376 | ir->keypressed = true; | ||
377 | IR_dprintk(1, "%s: key down event, key 0x%04x, scancode 0x%04x\n", | ||
378 | dev->name, keycode, scancode); | ||
379 | input_report_key(dev, ir->last_keycode, 1); | ||
314 | input_sync(dev); | 380 | input_sync(dev); |
315 | 381 | ||
382 | set_timer: | ||
383 | ir->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT); | ||
384 | mod_timer(&ir->timer_keyup, ir->keyup_jiffies); | ||
385 | out: | ||
386 | spin_unlock_irqrestore(&ir->keylock, flags); | ||
316 | } | 387 | } |
317 | EXPORT_SYMBOL_GPL(ir_keydown); | 388 | EXPORT_SYMBOL_GPL(ir_keydown); |
318 | 389 | ||
@@ -365,8 +436,12 @@ int __ir_input_register(struct input_dev *input_dev, | |||
365 | input_dev->getkeycode = ir_getkeycode; | 436 | input_dev->getkeycode = ir_getkeycode; |
366 | input_dev->setkeycode = ir_setkeycode; | 437 | input_dev->setkeycode = ir_setkeycode; |
367 | input_set_drvdata(input_dev, ir_dev); | 438 | input_set_drvdata(input_dev, ir_dev); |
439 | ir_dev->input_dev = input_dev; | ||
368 | 440 | ||
369 | spin_lock_init(&ir_dev->rc_tab.lock); | 441 | spin_lock_init(&ir_dev->rc_tab.lock); |
442 | spin_lock_init(&ir_dev->keylock); | ||
443 | setup_timer(&ir_dev->timer_keyup, ir_timer_keyup, (unsigned long)ir_dev); | ||
444 | |||
370 | ir_dev->rc_tab.name = rc_tab->name; | 445 | ir_dev->rc_tab.name = rc_tab->name; |
371 | ir_dev->rc_tab.ir_type = rc_tab->ir_type; | 446 | ir_dev->rc_tab.ir_type = rc_tab->ir_type; |
372 | ir_dev->rc_tab.alloc = roundup_pow_of_two(rc_tab->size * | 447 | ir_dev->rc_tab.alloc = roundup_pow_of_two(rc_tab->size * |
@@ -383,6 +458,8 @@ int __ir_input_register(struct input_dev *input_dev, | |||
383 | ir_dev->rc_tab.size, ir_dev->rc_tab.alloc); | 458 | ir_dev->rc_tab.size, ir_dev->rc_tab.alloc); |
384 | 459 | ||
385 | set_bit(EV_KEY, input_dev->evbit); | 460 | set_bit(EV_KEY, input_dev->evbit); |
461 | set_bit(EV_REP, input_dev->evbit); | ||
462 | |||
386 | if (ir_setkeytable(input_dev, &ir_dev->rc_tab, rc_tab)) { | 463 | if (ir_setkeytable(input_dev, &ir_dev->rc_tab, rc_tab)) { |
387 | rc = -ENOMEM; | 464 | rc = -ENOMEM; |
388 | goto out_table; | 465 | goto out_table; |
@@ -428,7 +505,7 @@ void ir_input_unregister(struct input_dev *dev) | |||
428 | return; | 505 | return; |
429 | 506 | ||
430 | IR_dprintk(1, "Freed keycode table\n"); | 507 | IR_dprintk(1, "Freed keycode table\n"); |
431 | 508 | del_timer_sync(&ir_dev->timer_keyup); | |
432 | rc_tab = &ir_dev->rc_tab; | 509 | rc_tab = &ir_dev->rc_tab; |
433 | rc_tab->size = 0; | 510 | rc_tab->size = 0; |
434 | kfree(rc_tab->scan); | 511 | kfree(rc_tab->scan); |
diff --git a/drivers/media/IR/ir-nec-decoder.c b/drivers/media/IR/ir-nec-decoder.c index 83a9912722f4..0b50060ffbaf 100644 --- a/drivers/media/IR/ir-nec-decoder.c +++ b/drivers/media/IR/ir-nec-decoder.c | |||
@@ -180,8 +180,7 @@ static int __ir_nec_decode(struct input_dev *input_dev, | |||
180 | if (is_repeat(evs, len, *pos)) { | 180 | if (is_repeat(evs, len, *pos)) { |
181 | *pos += 2; | 181 | *pos += 2; |
182 | if (ir->keypressed) { | 182 | if (ir->keypressed) { |
183 | mod_timer(&ir->raw->timer_keyup, | 183 | ir_repeat(input_dev); |
184 | jiffies + msecs_to_jiffies(REPEAT_TIME)); | ||
185 | IR_dprintk(1, "NEC repeat event\n"); | 184 | IR_dprintk(1, "NEC repeat event\n"); |
186 | return 1; | 185 | return 1; |
187 | } else { | 186 | } else { |
@@ -238,9 +237,7 @@ static int __ir_nec_decode(struct input_dev *input_dev, | |||
238 | } | 237 | } |
239 | 238 | ||
240 | IR_dprintk(1, "NEC scancode 0x%04x\n", ircode); | 239 | IR_dprintk(1, "NEC scancode 0x%04x\n", ircode); |
241 | ir_keydown(input_dev, ircode); | 240 | ir_keydown(input_dev, ircode, 0); |
242 | mod_timer(&ir->raw->timer_keyup, | ||
243 | jiffies + msecs_to_jiffies(REPEAT_TIME)); | ||
244 | 241 | ||
245 | return 1; | 242 | return 1; |
246 | err: | 243 | err: |
diff --git a/drivers/media/IR/ir-raw-event.c b/drivers/media/IR/ir-raw-event.c index 371d88e5a586..59f20541b03e 100644 --- a/drivers/media/IR/ir-raw-event.c +++ b/drivers/media/IR/ir-raw-event.c | |||
@@ -53,13 +53,6 @@ static spinlock_t ir_raw_handler_lock; | |||
53 | /* Used to load the decoders */ | 53 | /* Used to load the decoders */ |
54 | static struct work_struct wq_load; | 54 | static struct work_struct wq_load; |
55 | 55 | ||
56 | static void ir_keyup_timer(unsigned long data) | ||
57 | { | ||
58 | struct input_dev *input_dev = (struct input_dev *)data; | ||
59 | |||
60 | ir_keyup(input_dev); | ||
61 | } | ||
62 | |||
63 | int ir_raw_event_register(struct input_dev *input_dev) | 56 | int ir_raw_event_register(struct input_dev *input_dev) |
64 | { | 57 | { |
65 | struct ir_input_dev *ir = input_get_drvdata(input_dev); | 58 | struct ir_input_dev *ir = input_get_drvdata(input_dev); |
@@ -72,11 +65,6 @@ int ir_raw_event_register(struct input_dev *input_dev) | |||
72 | size = sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE * 2; | 65 | size = sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE * 2; |
73 | size = roundup_pow_of_two(size); | 66 | size = roundup_pow_of_two(size); |
74 | 67 | ||
75 | init_timer(&ir->raw->timer_keyup); | ||
76 | ir->raw->timer_keyup.function = ir_keyup_timer; | ||
77 | ir->raw->timer_keyup.data = (unsigned long)input_dev; | ||
78 | set_bit(EV_REP, input_dev->evbit); | ||
79 | |||
80 | rc = kfifo_alloc(&ir->raw->kfifo, size, GFP_KERNEL); | 68 | rc = kfifo_alloc(&ir->raw->kfifo, size, GFP_KERNEL); |
81 | if (rc < 0) { | 69 | if (rc < 0) { |
82 | kfree(ir->raw); | 70 | kfree(ir->raw); |
@@ -103,8 +91,6 @@ void ir_raw_event_unregister(struct input_dev *input_dev) | |||
103 | if (!ir->raw) | 91 | if (!ir->raw) |
104 | return; | 92 | return; |
105 | 93 | ||
106 | del_timer_sync(&ir->raw->timer_keyup); | ||
107 | |||
108 | RUN_DECODER(raw_unregister, input_dev); | 94 | RUN_DECODER(raw_unregister, input_dev); |
109 | 95 | ||
110 | kfifo_free(&ir->raw->kfifo); | 96 | kfifo_free(&ir->raw->kfifo); |
diff --git a/include/media/ir-core.h b/include/media/ir-core.h index 7a0be8d4999d..b452a478c12c 100644 --- a/include/media/ir-core.h +++ b/include/media/ir-core.h | |||
@@ -76,7 +76,6 @@ struct ir_raw_event { | |||
76 | struct ir_raw_event_ctrl { | 76 | struct ir_raw_event_ctrl { |
77 | struct kfifo kfifo; /* fifo for the pulse/space events */ | 77 | struct kfifo kfifo; /* fifo for the pulse/space events */ |
78 | struct timespec last_event; /* when last event occurred */ | 78 | struct timespec last_event; /* when last event occurred */ |
79 | struct timer_list timer_keyup; /* timer for key release */ | ||
80 | }; | 79 | }; |
81 | 80 | ||
82 | struct ir_input_dev { | 81 | struct ir_input_dev { |
@@ -86,10 +85,16 @@ struct ir_input_dev { | |||
86 | unsigned long devno; /* device number */ | 85 | unsigned long devno; /* device number */ |
87 | const struct ir_dev_props *props; /* Device properties */ | 86 | const struct ir_dev_props *props; /* Device properties */ |
88 | struct ir_raw_event_ctrl *raw; /* for raw pulse/space events */ | 87 | struct ir_raw_event_ctrl *raw; /* for raw pulse/space events */ |
88 | struct input_dev *input_dev; /* the input device associated with this device */ | ||
89 | 89 | ||
90 | /* key info - needed by IR keycode handlers */ | 90 | /* key info - needed by IR keycode handlers */ |
91 | u32 keycode; /* linux key code */ | 91 | spinlock_t keylock; /* protects the below members */ |
92 | int keypressed; /* current state */ | 92 | bool keypressed; /* current state */ |
93 | unsigned long keyup_jiffies; /* when should the current keypress be released? */ | ||
94 | struct timer_list timer_keyup; /* timer for releasing a keypress */ | ||
95 | u32 last_keycode; /* keycode of last command */ | ||
96 | u32 last_scancode; /* scancode of last command */ | ||
97 | u8 last_toggle; /* toggle of last command */ | ||
93 | }; | 98 | }; |
94 | 99 | ||
95 | struct ir_raw_handler { | 100 | struct ir_raw_handler { |
@@ -115,8 +120,8 @@ void rc_map_init(void); | |||
115 | 120 | ||
116 | u32 ir_g_keycode_from_table(struct input_dev *input_dev, | 121 | u32 ir_g_keycode_from_table(struct input_dev *input_dev, |
117 | u32 scancode); | 122 | u32 scancode); |
118 | void ir_keyup(struct input_dev *dev); | 123 | void ir_repeat(struct input_dev *dev); |
119 | void ir_keydown(struct input_dev *dev, int scancode); | 124 | void ir_keydown(struct input_dev *dev, int scancode, u8 toggle); |
120 | int __ir_input_register(struct input_dev *dev, | 125 | int __ir_input_register(struct input_dev *dev, |
121 | const struct ir_scancode_table *ir_codes, | 126 | const struct ir_scancode_table *ir_codes, |
122 | const struct ir_dev_props *props, | 127 | const struct ir_dev_props *props, |