diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2007-11-04 00:41:12 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2008-01-21 01:11:06 -0500 |
commit | f4f37c8ec7d2491c8885c890ba74254b9adfbeee (patch) | |
tree | ecd4cb10af7fd7aa4fb02fe2a106608e9d64c3fe /drivers/input/input.c | |
parent | 554101e3e5f396b987c846332863a3fcdc87b1d6 (diff) |
Input: Add proper locking when changing device's keymap
Take dev->event_lock to make sure that we don't race with input_event() and
also force key up event when removing a key from keymap table.
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input/input.c')
-rw-r--r-- | drivers/input/input.c | 78 |
1 files changed, 72 insertions, 6 deletions
diff --git a/drivers/input/input.c b/drivers/input/input.c index a0be978501ff..e1729e1dd9b2 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c | |||
@@ -493,7 +493,7 @@ static void input_disconnect_device(struct input_dev *dev) | |||
493 | if (is_event_supported(EV_KEY, dev->evbit, EV_MAX)) { | 493 | if (is_event_supported(EV_KEY, dev->evbit, EV_MAX)) { |
494 | for (code = 0; code <= KEY_MAX; code++) { | 494 | for (code = 0; code <= KEY_MAX; code++) { |
495 | if (is_event_supported(code, dev->keybit, KEY_MAX) && | 495 | if (is_event_supported(code, dev->keybit, KEY_MAX) && |
496 | test_bit(code, dev->key)) { | 496 | __test_and_clear_bit(code, dev->key)) { |
497 | input_pass_event(dev, EV_KEY, code, 0); | 497 | input_pass_event(dev, EV_KEY, code, 0); |
498 | } | 498 | } |
499 | } | 499 | } |
@@ -526,7 +526,7 @@ static int input_default_getkeycode(struct input_dev *dev, | |||
526 | if (!dev->keycodesize) | 526 | if (!dev->keycodesize) |
527 | return -EINVAL; | 527 | return -EINVAL; |
528 | 528 | ||
529 | if (scancode < 0 || scancode >= dev->keycodemax) | 529 | if (scancode >= dev->keycodemax) |
530 | return -EINVAL; | 530 | return -EINVAL; |
531 | 531 | ||
532 | *keycode = input_fetch_keycode(dev, scancode); | 532 | *keycode = input_fetch_keycode(dev, scancode); |
@@ -540,10 +540,7 @@ static int input_default_setkeycode(struct input_dev *dev, | |||
540 | int old_keycode; | 540 | int old_keycode; |
541 | int i; | 541 | int i; |
542 | 542 | ||
543 | if (scancode < 0 || scancode >= dev->keycodemax) | 543 | if (scancode >= dev->keycodemax) |
544 | return -EINVAL; | ||
545 | |||
546 | if (keycode < 0 || keycode > KEY_MAX) | ||
547 | return -EINVAL; | 544 | return -EINVAL; |
548 | 545 | ||
549 | if (!dev->keycodesize) | 546 | if (!dev->keycodesize) |
@@ -586,6 +583,75 @@ static int input_default_setkeycode(struct input_dev *dev, | |||
586 | return 0; | 583 | return 0; |
587 | } | 584 | } |
588 | 585 | ||
586 | /** | ||
587 | * input_get_keycode - retrieve keycode currently mapped to a given scancode | ||
588 | * @dev: input device which keymap is being queried | ||
589 | * @scancode: scancode (or its equivalent for device in question) for which | ||
590 | * keycode is needed | ||
591 | * @keycode: result | ||
592 | * | ||
593 | * This function should be called by anyone interested in retrieving current | ||
594 | * keymap. Presently keyboard and evdev handlers use it. | ||
595 | */ | ||
596 | int input_get_keycode(struct input_dev *dev, int scancode, int *keycode) | ||
597 | { | ||
598 | if (scancode < 0) | ||
599 | return -EINVAL; | ||
600 | |||
601 | return dev->getkeycode(dev, scancode, keycode); | ||
602 | } | ||
603 | EXPORT_SYMBOL(input_get_keycode); | ||
604 | |||
605 | /** | ||
606 | * input_get_keycode - assign new keycode to a given scancode | ||
607 | * @dev: input device which keymap is being updated | ||
608 | * @scancode: scancode (or its equivalent for device in question) | ||
609 | * @keycode: new keycode to be assigned to the scancode | ||
610 | * | ||
611 | * This function should be called by anyone needing to update current | ||
612 | * keymap. Presently keyboard and evdev handlers use it. | ||
613 | */ | ||
614 | int input_set_keycode(struct input_dev *dev, int scancode, int keycode) | ||
615 | { | ||
616 | unsigned long flags; | ||
617 | int old_keycode; | ||
618 | int retval; | ||
619 | |||
620 | if (scancode < 0) | ||
621 | return -EINVAL; | ||
622 | |||
623 | if (keycode < 0 || keycode > KEY_MAX) | ||
624 | return -EINVAL; | ||
625 | |||
626 | spin_lock_irqsave(&dev->event_lock, flags); | ||
627 | |||
628 | retval = dev->getkeycode(dev, scancode, &old_keycode); | ||
629 | if (retval) | ||
630 | goto out; | ||
631 | |||
632 | retval = dev->setkeycode(dev, scancode, keycode); | ||
633 | if (retval) | ||
634 | goto out; | ||
635 | |||
636 | /* | ||
637 | * Simulate keyup event if keycode is not present | ||
638 | * in the keymap anymore | ||
639 | */ | ||
640 | if (test_bit(EV_KEY, dev->evbit) && | ||
641 | !is_event_supported(old_keycode, dev->keybit, KEY_MAX) && | ||
642 | __test_and_clear_bit(old_keycode, dev->key)) { | ||
643 | |||
644 | input_pass_event(dev, EV_KEY, old_keycode, 0); | ||
645 | if (dev->sync) | ||
646 | input_pass_event(dev, EV_SYN, SYN_REPORT, 1); | ||
647 | } | ||
648 | |||
649 | out: | ||
650 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
651 | |||
652 | return retval; | ||
653 | } | ||
654 | EXPORT_SYMBOL(input_set_keycode); | ||
589 | 655 | ||
590 | #define MATCH_BIT(bit, max) \ | 656 | #define MATCH_BIT(bit, max) \ |
591 | for (i = 0; i < BITS_TO_LONGS(max); i++) \ | 657 | for (i = 0; i < BITS_TO_LONGS(max); i++) \ |