diff options
Diffstat (limited to 'drivers/input/evdev.c')
-rw-r--r-- | drivers/input/evdev.c | 100 |
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 | ||
537 | static 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 | |||
578 | static 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 | |||
537 | static long evdev_do_ioctl(struct file *file, unsigned int cmd, | 611 | static 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 */ |