diff options
Diffstat (limited to 'drivers/input/evdev.c')
-rw-r--r-- | drivers/input/evdev.c | 152 |
1 files changed, 73 insertions, 79 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 054edf346e0b..c908c5f83645 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c | |||
@@ -492,13 +492,15 @@ static int str_to_user(const char *str, unsigned int maxlen, void __user *p) | |||
492 | } | 492 | } |
493 | 493 | ||
494 | #define OLD_KEY_MAX 0x1ff | 494 | #define OLD_KEY_MAX 0x1ff |
495 | static int handle_eviocgbit(struct input_dev *dev, unsigned int cmd, void __user *p, int compat_mode) | 495 | static int handle_eviocgbit(struct input_dev *dev, |
496 | unsigned int type, unsigned int size, | ||
497 | void __user *p, int compat_mode) | ||
496 | { | 498 | { |
497 | static unsigned long keymax_warn_time; | 499 | static unsigned long keymax_warn_time; |
498 | unsigned long *bits; | 500 | unsigned long *bits; |
499 | int len; | 501 | int len; |
500 | 502 | ||
501 | switch (_IOC_NR(cmd) & EV_MAX) { | 503 | switch (type) { |
502 | 504 | ||
503 | case 0: bits = dev->evbit; len = EV_MAX; break; | 505 | case 0: bits = dev->evbit; len = EV_MAX; break; |
504 | case EV_KEY: bits = dev->keybit; len = KEY_MAX; break; | 506 | case EV_KEY: bits = dev->keybit; len = KEY_MAX; break; |
@@ -517,7 +519,7 @@ static int handle_eviocgbit(struct input_dev *dev, unsigned int cmd, void __user | |||
517 | * EVIOCGBIT(EV_KEY, KEY_MAX) and not realize that 'len' | 519 | * EVIOCGBIT(EV_KEY, KEY_MAX) and not realize that 'len' |
518 | * should be in bytes, not in bits. | 520 | * should be in bytes, not in bits. |
519 | */ | 521 | */ |
520 | if ((_IOC_NR(cmd) & EV_MAX) == EV_KEY && _IOC_SIZE(cmd) == OLD_KEY_MAX) { | 522 | if (type == EV_KEY && size == OLD_KEY_MAX) { |
521 | len = OLD_KEY_MAX; | 523 | len = OLD_KEY_MAX; |
522 | if (printk_timed_ratelimit(&keymax_warn_time, 10 * 1000)) | 524 | if (printk_timed_ratelimit(&keymax_warn_time, 10 * 1000)) |
523 | printk(KERN_WARNING | 525 | printk(KERN_WARNING |
@@ -528,7 +530,7 @@ static int handle_eviocgbit(struct input_dev *dev, unsigned int cmd, void __user | |||
528 | BITS_TO_LONGS(OLD_KEY_MAX) * sizeof(long)); | 530 | BITS_TO_LONGS(OLD_KEY_MAX) * sizeof(long)); |
529 | } | 531 | } |
530 | 532 | ||
531 | return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode); | 533 | return bits_to_user(bits, len, size, p, compat_mode); |
532 | } | 534 | } |
533 | #undef OLD_KEY_MAX | 535 | #undef OLD_KEY_MAX |
534 | 536 | ||
@@ -542,8 +544,10 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, | |||
542 | struct ff_effect effect; | 544 | struct ff_effect effect; |
543 | int __user *ip = (int __user *)p; | 545 | int __user *ip = (int __user *)p; |
544 | unsigned int i, t, u, v; | 546 | unsigned int i, t, u, v; |
547 | unsigned int size; | ||
545 | int error; | 548 | int error; |
546 | 549 | ||
550 | /* First we check for fixed-length commands */ | ||
547 | switch (cmd) { | 551 | switch (cmd) { |
548 | 552 | ||
549 | case EVIOCGVERSION: | 553 | case EVIOCGVERSION: |
@@ -610,112 +614,102 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, | |||
610 | return evdev_grab(evdev, client); | 614 | return evdev_grab(evdev, client); |
611 | else | 615 | else |
612 | return evdev_ungrab(evdev, client); | 616 | return evdev_ungrab(evdev, client); |
617 | } | ||
613 | 618 | ||
614 | default: | 619 | size = _IOC_SIZE(cmd); |
615 | |||
616 | if (_IOC_TYPE(cmd) != 'E') | ||
617 | return -EINVAL; | ||
618 | |||
619 | if (_IOC_DIR(cmd) == _IOC_READ) { | ||
620 | 620 | ||
621 | if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0, 0))) | 621 | /* Now check variable-length commands */ |
622 | return handle_eviocgbit(dev, cmd, p, compat_mode); | 622 | #define EVIOC_MASK_SIZE(nr) ((nr) & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) |
623 | 623 | ||
624 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) | 624 | switch (EVIOC_MASK_SIZE(cmd)) { |
625 | return bits_to_user(dev->key, KEY_MAX, _IOC_SIZE(cmd), | ||
626 | p, compat_mode); | ||
627 | 625 | ||
628 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) | 626 | case EVIOCGKEY(0): |
629 | return bits_to_user(dev->led, LED_MAX, _IOC_SIZE(cmd), | 627 | return bits_to_user(dev->key, KEY_MAX, size, p, compat_mode); |
630 | p, compat_mode); | ||
631 | 628 | ||
632 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) | 629 | case EVIOCGLED(0): |
633 | return bits_to_user(dev->snd, SND_MAX, _IOC_SIZE(cmd), | 630 | return bits_to_user(dev->led, LED_MAX, size, p, compat_mode); |
634 | p, compat_mode); | ||
635 | 631 | ||
636 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0))) | 632 | case EVIOCGSND(0): |
637 | return bits_to_user(dev->sw, SW_MAX, _IOC_SIZE(cmd), | 633 | return bits_to_user(dev->snd, SND_MAX, size, p, compat_mode); |
638 | p, compat_mode); | ||
639 | 634 | ||
640 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) | 635 | case EVIOCGSW(0): |
641 | return str_to_user(dev->name, _IOC_SIZE(cmd), p); | 636 | return bits_to_user(dev->sw, SW_MAX, size, p, compat_mode); |
642 | 637 | ||
643 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) | 638 | case EVIOCGNAME(0): |
644 | return str_to_user(dev->phys, _IOC_SIZE(cmd), p); | 639 | return str_to_user(dev->name, size, p); |
645 | 640 | ||
646 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) | 641 | case EVIOCGPHYS(0): |
647 | return str_to_user(dev->uniq, _IOC_SIZE(cmd), p); | 642 | return str_to_user(dev->phys, size, p); |
648 | 643 | ||
649 | if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) { | 644 | case EVIOCGUNIQ(0): |
645 | return str_to_user(dev->uniq, size, p); | ||
650 | 646 | ||
651 | t = _IOC_NR(cmd) & ABS_MAX; | 647 | case EVIOC_MASK_SIZE(EVIOCSFF): |
648 | if (input_ff_effect_from_user(p, size, &effect)) | ||
649 | return -EFAULT; | ||
652 | 650 | ||
653 | abs.value = dev->abs[t]; | 651 | error = input_ff_upload(dev, &effect, file); |
654 | abs.minimum = dev->absmin[t]; | ||
655 | abs.maximum = dev->absmax[t]; | ||
656 | abs.fuzz = dev->absfuzz[t]; | ||
657 | abs.flat = dev->absflat[t]; | ||
658 | abs.resolution = dev->absres[t]; | ||
659 | 652 | ||
660 | if (copy_to_user(p, &abs, min_t(size_t, | 653 | if (put_user(effect.id, &(((struct ff_effect __user *)p)->id))) |
661 | _IOC_SIZE(cmd), | 654 | return -EFAULT; |
662 | sizeof(struct input_absinfo)))) | ||
663 | return -EFAULT; | ||
664 | 655 | ||
665 | return 0; | 656 | return error; |
666 | } | 657 | } |
667 | 658 | ||
668 | } | 659 | /* Multi-number variable-length handlers */ |
660 | if (_IOC_TYPE(cmd) != 'E') | ||
661 | return -EINVAL; | ||
669 | 662 | ||
670 | if (_IOC_DIR(cmd) == _IOC_WRITE) { | 663 | if (_IOC_DIR(cmd) == _IOC_READ) { |
671 | 664 | ||
672 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCSFF)) { | 665 | if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0, 0))) |
666 | return handle_eviocgbit(dev, | ||
667 | _IOC_NR(cmd) & EV_MAX, size, | ||
668 | p, compat_mode); | ||
673 | 669 | ||
674 | if (input_ff_effect_from_user(p, _IOC_SIZE(cmd), &effect)) | 670 | if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) { |
675 | return -EFAULT; | ||
676 | 671 | ||
677 | error = input_ff_upload(dev, &effect, file); | 672 | t = _IOC_NR(cmd) & ABS_MAX; |
673 | abs = dev->absinfo[t]; | ||
678 | 674 | ||
679 | if (put_user(effect.id, &(((struct ff_effect __user *)p)->id))) | 675 | if (copy_to_user(p, &abs, min_t(size_t, |
680 | return -EFAULT; | 676 | size, sizeof(struct input_absinfo)))) |
677 | return -EFAULT; | ||
681 | 678 | ||
682 | return error; | 679 | return 0; |
683 | } | 680 | } |
681 | } | ||
684 | 682 | ||
685 | if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) { | 683 | if (_IOC_DIR(cmd) == _IOC_READ) { |
686 | 684 | ||
687 | t = _IOC_NR(cmd) & ABS_MAX; | 685 | if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) { |
688 | 686 | ||
689 | if (copy_from_user(&abs, p, min_t(size_t, | 687 | t = _IOC_NR(cmd) & ABS_MAX; |
690 | _IOC_SIZE(cmd), | ||
691 | sizeof(struct input_absinfo)))) | ||
692 | return -EFAULT; | ||
693 | 688 | ||
694 | /* We can't change number of reserved MT slots */ | 689 | if (copy_from_user(&abs, p, min_t(size_t, |
695 | if (t == ABS_MT_SLOT) | 690 | size, sizeof(struct input_absinfo)))) |
696 | return -EINVAL; | 691 | return -EFAULT; |
697 | 692 | ||
698 | /* | 693 | if (size < sizeof(struct input_absinfo)) |
699 | * Take event lock to ensure that we are not | 694 | abs.resolution = 0; |
700 | * changing device parameters in the middle | ||
701 | * of event. | ||
702 | */ | ||
703 | spin_lock_irq(&dev->event_lock); | ||
704 | 695 | ||
705 | dev->abs[t] = abs.value; | 696 | /* We can't change number of reserved MT slots */ |
706 | dev->absmin[t] = abs.minimum; | 697 | if (t == ABS_MT_SLOT) |
707 | dev->absmax[t] = abs.maximum; | 698 | return -EINVAL; |
708 | dev->absfuzz[t] = abs.fuzz; | ||
709 | dev->absflat[t] = abs.flat; | ||
710 | dev->absres[t] = _IOC_SIZE(cmd) < sizeof(struct input_absinfo) ? | ||
711 | 0 : abs.resolution; | ||
712 | 699 | ||
713 | spin_unlock_irq(&dev->event_lock); | 700 | /* |
701 | * Take event lock to ensure that we are not | ||
702 | * changing device parameters in the middle | ||
703 | * of event. | ||
704 | */ | ||
705 | spin_lock_irq(&dev->event_lock); | ||
706 | dev->absinfo[t] = abs; | ||
707 | spin_unlock_irq(&dev->event_lock); | ||
714 | 708 | ||
715 | return 0; | 709 | return 0; |
716 | } | ||
717 | } | 710 | } |
718 | } | 711 | } |
712 | |||
719 | return -EINVAL; | 713 | return -EINVAL; |
720 | } | 714 | } |
721 | 715 | ||