aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2007-11-04 00:41:12 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2008-01-21 01:11:06 -0500
commitf4f37c8ec7d2491c8885c890ba74254b9adfbeee (patch)
treeecd4cb10af7fd7aa4fb02fe2a106608e9d64c3fe /drivers/input
parent554101e3e5f396b987c846332863a3fcdc87b1d6 (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')
-rw-r--r--drivers/input/evdev.c6
-rw-r--r--drivers/input/input.c78
2 files changed, 75 insertions, 9 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index e5b4e9bfbdc5..0727b0a12557 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -617,7 +617,7 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
617 if (get_user(t, ip)) 617 if (get_user(t, ip))
618 return -EFAULT; 618 return -EFAULT;
619 619
620 error = dev->getkeycode(dev, t, &v); 620 error = input_get_keycode(dev, t, &v);
621 if (error) 621 if (error)
622 return error; 622 return error;
623 623
@@ -630,7 +630,7 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
630 if (get_user(t, ip) || get_user(v, ip + 1)) 630 if (get_user(t, ip) || get_user(v, ip + 1))
631 return -EFAULT; 631 return -EFAULT;
632 632
633 return dev->setkeycode(dev, t, v); 633 return input_set_keycode(dev, t, v);
634 634
635 case EVIOCSFF: 635 case EVIOCSFF:
636 if (copy_from_user(&effect, p, sizeof(effect))) 636 if (copy_from_user(&effect, p, sizeof(effect)))
@@ -683,7 +683,7 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
683 case EV_FF: bits = dev->ffbit; len = FF_MAX; break; 683 case EV_FF: bits = dev->ffbit; len = FF_MAX; break;
684 case EV_SW: bits = dev->swbit; len = SW_MAX; break; 684 case EV_SW: bits = dev->swbit; len = SW_MAX; break;
685 default: return -EINVAL; 685 default: return -EINVAL;
686 } 686 }
687 return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode); 687 return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode);
688 } 688 }
689 689
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 */
596int 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}
603EXPORT_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 */
614int 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}
654EXPORT_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++) \