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 | ||
