diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2010-08-02 23:29:10 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2010-08-02 23:30:44 -0400 |
commit | 448cd1664a573e69f54bfd32f3bb7220212b6cf5 (patch) | |
tree | 530ca61b1cd6205a79eecc6c04b6d0da70e07f40 /drivers/input | |
parent | d31b2865a4e8a9dd02f39e56c8fadb824c5e187b (diff) |
Input: evdev - rearrange ioctl handling
Split ioctl handling into 3 separate sections: fixed-length ioctls,
variable-length ioctls and multi-number variable length handlers.
This reduces identation and makes the code a bit clearer.
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input')
-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 | ||