Input: evdev - rearrange ioctl handling
authorDmitry Torokhov <dmitry.torokhov@gmail.com>
Tue, 3 Aug 2010 03:29:10 +0000 (20:29 -0700)
committerDmitry Torokhov <dmitry.torokhov@gmail.com>
Tue, 3 Aug 2010 03:30:44 +0000 (20:30 -0700)
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>
drivers/input/evdev.c

index 08f48c03eec4a0c383d81a358b01d780fe2e90ec..c908c5f83645c901f87823e2a587ba65d9b5ee97 100644 (file)
@@ -492,13 +492,15 @@ static int str_to_user(const char *str, unsigned int maxlen, void __user *p)
 }
 
 #define OLD_KEY_MAX    0x1ff
-static int handle_eviocgbit(struct input_dev *dev, unsigned int cmd, void __user *p, int compat_mode)
+static int handle_eviocgbit(struct input_dev *dev,
+                           unsigned int type, unsigned int size,
+                           void __user *p, int compat_mode)
 {
        static unsigned long keymax_warn_time;
        unsigned long *bits;
        int len;
 
-       switch (_IOC_NR(cmd) & EV_MAX) {
+       switch (type) {
 
        case      0: bits = dev->evbit;  len = EV_MAX;  break;
        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
         * EVIOCGBIT(EV_KEY, KEY_MAX) and not realize that 'len'
         * should be in bytes, not in bits.
         */
-       if ((_IOC_NR(cmd) & EV_MAX) == EV_KEY && _IOC_SIZE(cmd) == OLD_KEY_MAX) {
+       if (type == EV_KEY && size == OLD_KEY_MAX) {
                len = OLD_KEY_MAX;
                if (printk_timed_ratelimit(&keymax_warn_time, 10 * 1000))
                        printk(KERN_WARNING
@@ -528,7 +530,7 @@ static int handle_eviocgbit(struct input_dev *dev, unsigned int cmd, void __user
                                BITS_TO_LONGS(OLD_KEY_MAX) * sizeof(long));
        }
 
-       return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode);
+       return bits_to_user(bits, len, size, p, compat_mode);
 }
 #undef OLD_KEY_MAX
 
@@ -542,8 +544,10 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
        struct ff_effect effect;
        int __user *ip = (int __user *)p;
        unsigned int i, t, u, v;
+       unsigned int size;
        int error;
 
+       /* First we check for fixed-length commands */
        switch (cmd) {
 
        case EVIOCGVERSION:
@@ -610,101 +614,102 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
                        return evdev_grab(evdev, client);
                else
                        return evdev_ungrab(evdev, client);
+       }
 
-       default:
+       size = _IOC_SIZE(cmd);
 
-               if (_IOC_TYPE(cmd) != 'E')
-                       return -EINVAL;
+       /* Now check variable-length commands */
+#define EVIOC_MASK_SIZE(nr)    ((nr) & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT))
 
-               if (_IOC_DIR(cmd) == _IOC_READ) {
+       switch (EVIOC_MASK_SIZE(cmd)) {
 
-                       if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0, 0)))
-                               return handle_eviocgbit(dev, cmd, p, compat_mode);
+       case EVIOCGKEY(0):
+               return bits_to_user(dev->key, KEY_MAX, size, p, compat_mode);
 
-                       if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0)))
-                               return bits_to_user(dev->key, KEY_MAX, _IOC_SIZE(cmd),
-                                                   p, compat_mode);
+       case EVIOCGLED(0):
+               return bits_to_user(dev->led, LED_MAX, size, p, compat_mode);
 
-                       if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0)))
-                               return bits_to_user(dev->led, LED_MAX, _IOC_SIZE(cmd),
-                                                   p, compat_mode);
+       case EVIOCGSND(0):
+               return bits_to_user(dev->snd, SND_MAX, size, p, compat_mode);
 
-                       if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0)))
-                               return bits_to_user(dev->snd, SND_MAX, _IOC_SIZE(cmd),
-                                                   p, compat_mode);
+       case EVIOCGSW(0):
+               return bits_to_user(dev->sw, SW_MAX, size, p, compat_mode);
 
-                       if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0)))
-                               return bits_to_user(dev->sw, SW_MAX, _IOC_SIZE(cmd),
-                                                   p, compat_mode);
+       case EVIOCGNAME(0):
+               return str_to_user(dev->name, size, p);
 
-                       if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0)))
-                               return str_to_user(dev->name, _IOC_SIZE(cmd), p);
+       case EVIOCGPHYS(0):
+               return str_to_user(dev->phys, size, p);
 
-                       if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0)))
-                               return str_to_user(dev->phys, _IOC_SIZE(cmd), p);
+       case EVIOCGUNIQ(0):
+               return str_to_user(dev->uniq, size, p);
 
-                       if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0)))
-                               return str_to_user(dev->uniq, _IOC_SIZE(cmd), p);
+       case EVIOC_MASK_SIZE(EVIOCSFF):
+               if (input_ff_effect_from_user(p, size, &effect))
+                       return -EFAULT;
 
-                       if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
+               error = input_ff_upload(dev, &effect, file);
 
-                               t = _IOC_NR(cmd) & ABS_MAX;
-                               abs = dev->absinfo[t];
+               if (put_user(effect.id, &(((struct ff_effect __user *)p)->id)))
+                       return -EFAULT;
 
-                               if (copy_to_user(p, &abs, min_t(size_t,
-                                                               _IOC_SIZE(cmd),
-                                                               sizeof(struct input_absinfo))))
-                                       return -EFAULT;
+               return error;
+       }
 
-                               return 0;
-                       }
+       /* Multi-number variable-length handlers */
+       if (_IOC_TYPE(cmd) != 'E')
+               return -EINVAL;
 
-               }
+       if (_IOC_DIR(cmd) == _IOC_READ) {
 
-               if (_IOC_DIR(cmd) == _IOC_WRITE) {
+               if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0, 0)))
+                       return handle_eviocgbit(dev,
+                                               _IOC_NR(cmd) & EV_MAX, size,
+                                               p, compat_mode);
 
-                       if (_IOC_NR(cmd) == _IOC_NR(EVIOCSFF)) {
+               if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
 
-                               if (input_ff_effect_from_user(p, _IOC_SIZE(cmd), &effect))
-                                       return -EFAULT;
+                       t = _IOC_NR(cmd) & ABS_MAX;
+                       abs = dev->absinfo[t];
 
-                               error = input_ff_upload(dev, &effect, file);
+                       if (copy_to_user(p, &abs, min_t(size_t,
+                                       size, sizeof(struct input_absinfo))))
+                               return -EFAULT;
 
-                               if (put_user(effect.id, &(((struct ff_effect __user *)p)->id)))
-                                       return -EFAULT;
+                       return 0;
+               }
+       }
 
-                               return error;
-                       }
+       if (_IOC_DIR(cmd) == _IOC_READ) {
 
-                       if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
+               if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
 
-                               t = _IOC_NR(cmd) & ABS_MAX;
+                       t = _IOC_NR(cmd) & ABS_MAX;
 
-                               if (copy_from_user(&abs, p, min_t(size_t,
-                                                                 _IOC_SIZE(cmd),
-                                                                 sizeof(struct input_absinfo))))
-                                       return -EFAULT;
+                       if (copy_from_user(&abs, p, min_t(size_t,
+                                       size, sizeof(struct input_absinfo))))
+                               return -EFAULT;
 
-                               if (_IOC_SIZE(cmd) < sizeof(struct input_absinfo))
-                                       abs.resolution = 0;
+                       if (size < sizeof(struct input_absinfo))
+                               abs.resolution = 0;
 
-                               /* We can't change number of reserved MT slots */
-                               if (t == ABS_MT_SLOT)
-                                       return -EINVAL;
+                       /* We can't change number of reserved MT slots */
+                       if (t == ABS_MT_SLOT)
+                               return -EINVAL;
 
-                               /*
-                                * Take event lock to ensure that we are not
-                                * changing device parameters in the middle
-                                * of event.
-                                */
-                               spin_lock_irq(&dev->event_lock);
-                               dev->absinfo[t] = abs;
-                               spin_unlock_irq(&dev->event_lock);
+                       /*
+                        * Take event lock to ensure that we are not
+                        * changing device parameters in the middle
+                        * of event.
+                        */
+                       spin_lock_irq(&dev->event_lock);
+                       dev->absinfo[t] = abs;
+                       spin_unlock_irq(&dev->event_lock);
 
-                               return 0;
-                       }
+                       return 0;
                }
        }
+
        return -EINVAL;
 }