diff options
| -rw-r--r-- | drivers/input/evdev.c | 141 |
1 files changed, 73 insertions, 68 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 08f48c03eec4..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,101 +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 | 620 | ||
| 616 | if (_IOC_TYPE(cmd) != 'E') | 621 | /* Now check variable-length commands */ |
| 617 | return -EINVAL; | 622 | #define EVIOC_MASK_SIZE(nr) ((nr) & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) |
| 618 | 623 | ||
| 619 | if (_IOC_DIR(cmd) == _IOC_READ) { | 624 | switch (EVIOC_MASK_SIZE(cmd)) { |
| 620 | 625 | ||
| 621 | if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0, 0))) | 626 | case EVIOCGKEY(0): |
| 622 | return handle_eviocgbit(dev, cmd, p, compat_mode); | 627 | return bits_to_user(dev->key, KEY_MAX, size, p, compat_mode); |
| 623 | 628 | ||
| 624 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) | 629 | case EVIOCGLED(0): |
| 625 | return bits_to_user(dev->key, KEY_MAX, _IOC_SIZE(cmd), | 630 | return bits_to_user(dev->led, LED_MAX, size, p, compat_mode); |
| 626 | p, compat_mode); | ||
| 627 | 631 | ||
| 628 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) | 632 | case EVIOCGSND(0): |
| 629 | return bits_to_user(dev->led, LED_MAX, _IOC_SIZE(cmd), | 633 | return bits_to_user(dev->snd, SND_MAX, size, p, compat_mode); |
| 630 | p, compat_mode); | ||
| 631 | 634 | ||
| 632 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) | 635 | case EVIOCGSW(0): |
| 633 | return bits_to_user(dev->snd, SND_MAX, _IOC_SIZE(cmd), | 636 | return bits_to_user(dev->sw, SW_MAX, size, p, compat_mode); |
| 634 | p, compat_mode); | ||
| 635 | 637 | ||
| 636 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0))) | 638 | case EVIOCGNAME(0): |
| 637 | return bits_to_user(dev->sw, SW_MAX, _IOC_SIZE(cmd), | 639 | return str_to_user(dev->name, size, p); |
| 638 | p, compat_mode); | ||
| 639 | 640 | ||
| 640 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) | 641 | case EVIOCGPHYS(0): |
| 641 | return str_to_user(dev->name, _IOC_SIZE(cmd), p); | 642 | return str_to_user(dev->phys, size, p); |
| 642 | 643 | ||
| 643 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) | 644 | case EVIOCGUNIQ(0): |
| 644 | return str_to_user(dev->phys, _IOC_SIZE(cmd), p); | 645 | return str_to_user(dev->uniq, size, p); |
| 645 | 646 | ||
| 646 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) | 647 | case EVIOC_MASK_SIZE(EVIOCSFF): |
| 647 | return str_to_user(dev->uniq, _IOC_SIZE(cmd), p); | 648 | if (input_ff_effect_from_user(p, size, &effect)) |
| 649 | return -EFAULT; | ||
| 648 | 650 | ||
| 649 | if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) { | 651 | error = input_ff_upload(dev, &effect, file); |
| 650 | 652 | ||
| 651 | t = _IOC_NR(cmd) & ABS_MAX; | 653 | if (put_user(effect.id, &(((struct ff_effect __user *)p)->id))) |
| 652 | abs = dev->absinfo[t]; | 654 | return -EFAULT; |
| 653 | 655 | ||
| 654 | if (copy_to_user(p, &abs, min_t(size_t, | 656 | return error; |
| 655 | _IOC_SIZE(cmd), | 657 | } |
| 656 | sizeof(struct input_absinfo)))) | ||
| 657 | return -EFAULT; | ||
| 658 | 658 | ||
| 659 | return 0; | 659 | /* Multi-number variable-length handlers */ |
| 660 | } | 660 | if (_IOC_TYPE(cmd) != 'E') |
| 661 | return -EINVAL; | ||
| 661 | 662 | ||
| 662 | } | 663 | if (_IOC_DIR(cmd) == _IOC_READ) { |
| 663 | 664 | ||
| 664 | if (_IOC_DIR(cmd) == _IOC_WRITE) { | 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); | ||
| 665 | 669 | ||
| 666 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCSFF)) { | 670 | if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) { |
| 667 | 671 | ||
| 668 | if (input_ff_effect_from_user(p, _IOC_SIZE(cmd), &effect)) | 672 | t = _IOC_NR(cmd) & ABS_MAX; |
| 669 | return -EFAULT; | 673 | abs = dev->absinfo[t]; |
| 670 | 674 | ||
| 671 | error = input_ff_upload(dev, &effect, file); | 675 | if (copy_to_user(p, &abs, min_t(size_t, |
| 676 | size, sizeof(struct input_absinfo)))) | ||
| 677 | return -EFAULT; | ||
| 672 | 678 | ||
| 673 | if (put_user(effect.id, &(((struct ff_effect __user *)p)->id))) | 679 | return 0; |
| 674 | return -EFAULT; | 680 | } |
| 681 | } | ||
| 675 | 682 | ||
| 676 | return error; | 683 | if (_IOC_DIR(cmd) == _IOC_READ) { |
| 677 | } | ||
| 678 | 684 | ||
| 679 | if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) { | 685 | if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) { |
| 680 | 686 | ||
| 681 | t = _IOC_NR(cmd) & ABS_MAX; | 687 | t = _IOC_NR(cmd) & ABS_MAX; |
| 682 | 688 | ||
| 683 | if (copy_from_user(&abs, p, min_t(size_t, | 689 | if (copy_from_user(&abs, p, min_t(size_t, |
| 684 | _IOC_SIZE(cmd), | 690 | size, sizeof(struct input_absinfo)))) |
| 685 | sizeof(struct input_absinfo)))) | 691 | return -EFAULT; |
| 686 | return -EFAULT; | ||
| 687 | 692 | ||
| 688 | if (_IOC_SIZE(cmd) < sizeof(struct input_absinfo)) | 693 | if (size < sizeof(struct input_absinfo)) |
| 689 | abs.resolution = 0; | 694 | abs.resolution = 0; |
| 690 | 695 | ||
| 691 | /* We can't change number of reserved MT slots */ | 696 | /* We can't change number of reserved MT slots */ |
| 692 | if (t == ABS_MT_SLOT) | 697 | if (t == ABS_MT_SLOT) |
| 693 | return -EINVAL; | 698 | return -EINVAL; |
| 694 | 699 | ||
| 695 | /* | 700 | /* |
| 696 | * Take event lock to ensure that we are not | 701 | * Take event lock to ensure that we are not |
| 697 | * changing device parameters in the middle | 702 | * changing device parameters in the middle |
| 698 | * of event. | 703 | * of event. |
| 699 | */ | 704 | */ |
| 700 | spin_lock_irq(&dev->event_lock); | 705 | spin_lock_irq(&dev->event_lock); |
| 701 | dev->absinfo[t] = abs; | 706 | dev->absinfo[t] = abs; |
| 702 | spin_unlock_irq(&dev->event_lock); | 707 | spin_unlock_irq(&dev->event_lock); |
| 703 | 708 | ||
| 704 | return 0; | 709 | return 0; |
| 705 | } | ||
| 706 | } | 710 | } |
| 707 | } | 711 | } |
| 712 | |||
| 708 | return -EINVAL; | 713 | return -EINVAL; |
| 709 | } | 714 | } |
| 710 | 715 | ||
