aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/evdev.c
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2010-09-10 00:54:22 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2010-09-10 01:00:50 -0400
commit8613e4c2872a87cc309a42de2c7091744dc54d0e (patch)
tree75b6513268aca8b614f3b2a55421c7a07b4a9899 /drivers/input/evdev.c
parenta4e6aad64735702256e4feaa4724eb776ca4e637 (diff)
Input: add support for large scancodes
Several devices use a high number of bits for scancodes. One important group is the Remote Controllers. Some new protocols like RC-6 define a scancode space of 64 bits. The current EVIO[CS]GKEYCODE ioctls allow replace the scancode/keycode translation tables, but it is limited to up to 32 bits for scancode. Also, if userspace wants to clean the existing table, replacing it by a new one, it needs to run a loop calling the ioctls over the entire sparse scancode space. To solve those problems, this patch extends the ioctls to allow drivers handle scancodes up to 32 bytes long (the length could be extended in the future should such need arise) and allow userspace to query and set scancode to keycode mappings not only by scancode but also by index. Compatibility code were also added to handle the old format of EVIO[CS]GKEYCODE ioctls. Folded fixes by: - Dan Carpenter: locking fixes for the original implementation - Jarod Wilson: fix crash when setting keycode and wiring up get/set handlers in original implementation. - Dmitry Torokhov: rework to consolidate old and new scancode handling, provide options to act either by index or scancode. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> Signed-off-by: Dan Carpenter <error27@gmail.com> Signed-off-by: Jarod Wilson <jarod@redhat.com> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input/evdev.c')
-rw-r--r--drivers/input/evdev.c100
1 files changed, 80 insertions, 20 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index c908c5f83645..1ce9bf663206 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -534,6 +534,80 @@ static int handle_eviocgbit(struct input_dev *dev,
534} 534}
535#undef OLD_KEY_MAX 535#undef OLD_KEY_MAX
536 536
537static int evdev_handle_get_keycode(struct input_dev *dev,
538 void __user *p, size_t size)
539{
540 struct input_keymap_entry ke;
541 int error;
542
543 memset(&ke, 0, sizeof(ke));
544
545 if (size == sizeof(unsigned int[2])) {
546 /* legacy case */
547 int __user *ip = (int __user *)p;
548
549 if (copy_from_user(ke.scancode, p, sizeof(unsigned int)))
550 return -EFAULT;
551
552 ke.len = sizeof(unsigned int);
553 ke.flags = 0;
554
555 error = input_get_keycode(dev, &ke);
556 if (error)
557 return error;
558
559 if (put_user(ke.keycode, ip + 1))
560 return -EFAULT;
561
562 } else {
563 size = min(size, sizeof(ke));
564
565 if (copy_from_user(&ke, p, size))
566 return -EFAULT;
567
568 error = input_get_keycode(dev, &ke);
569 if (error)
570 return error;
571
572 if (copy_to_user(p, &ke, size))
573 return -EFAULT;
574 }
575 return 0;
576}
577
578static int evdev_handle_set_keycode(struct input_dev *dev,
579 void __user *p, size_t size)
580{
581 struct input_keymap_entry ke;
582
583 memset(&ke, 0, sizeof(ke));
584
585 if (size == sizeof(unsigned int[2])) {
586 /* legacy case */
587 int __user *ip = (int __user *)p;
588
589 if (copy_from_user(ke.scancode, p, sizeof(unsigned int)))
590 return -EFAULT;
591
592 if (get_user(ke.keycode, ip + 1))
593 return -EFAULT;
594
595 ke.len = sizeof(unsigned int);
596 ke.flags = 0;
597
598 } else {
599 size = min(size, sizeof(ke));
600
601 if (copy_from_user(&ke, p, size))
602 return -EFAULT;
603
604 if (ke.len > sizeof(ke.scancode))
605 return -EINVAL;
606 }
607
608 return input_set_keycode(dev, &ke);
609}
610
537static long evdev_do_ioctl(struct file *file, unsigned int cmd, 611static long evdev_do_ioctl(struct file *file, unsigned int cmd,
538 void __user *p, int compat_mode) 612 void __user *p, int compat_mode)
539{ 613{
@@ -580,25 +654,6 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
580 654
581 return 0; 655 return 0;
582 656
583 case EVIOCGKEYCODE:
584 if (get_user(t, ip))
585 return -EFAULT;
586
587 error = input_get_keycode(dev, t, &v);
588 if (error)
589 return error;
590
591 if (put_user(v, ip + 1))
592 return -EFAULT;
593
594 return 0;
595
596 case EVIOCSKEYCODE:
597 if (get_user(t, ip) || get_user(v, ip + 1))
598 return -EFAULT;
599
600 return input_set_keycode(dev, t, v);
601
602 case EVIOCRMFF: 657 case EVIOCRMFF:
603 return input_ff_erase(dev, (int)(unsigned long) p, file); 658 return input_ff_erase(dev, (int)(unsigned long) p, file);
604 659
@@ -620,7 +675,6 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
620 675
621 /* Now check variable-length commands */ 676 /* Now check variable-length commands */
622#define EVIOC_MASK_SIZE(nr) ((nr) & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) 677#define EVIOC_MASK_SIZE(nr) ((nr) & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT))
623
624 switch (EVIOC_MASK_SIZE(cmd)) { 678 switch (EVIOC_MASK_SIZE(cmd)) {
625 679
626 case EVIOCGKEY(0): 680 case EVIOCGKEY(0):
@@ -654,6 +708,12 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
654 return -EFAULT; 708 return -EFAULT;
655 709
656 return error; 710 return error;
711
712 case EVIOC_MASK_SIZE(EVIOCGKEYCODE):
713 return evdev_handle_get_keycode(dev, p, size);
714
715 case EVIOC_MASK_SIZE(EVIOCSKEYCODE):
716 return evdev_handle_set_keycode(dev, p, size);
657 } 717 }
658 718
659 /* Multi-number variable-length handlers */ 719 /* Multi-number variable-length handlers */