aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2010-08-02 23:29:10 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2010-08-02 23:30:44 -0400
commit448cd1664a573e69f54bfd32f3bb7220212b6cf5 (patch)
tree530ca61b1cd6205a79eecc6c04b6d0da70e07f40 /drivers/input
parentd31b2865a4e8a9dd02f39e56c8fadb824c5e187b (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.c141
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
495static int handle_eviocgbit(struct input_dev *dev, unsigned int cmd, void __user *p, int compat_mode) 495static 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