Commit 448cd166 authored by Dmitry Torokhov's avatar Dmitry Torokhov

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: default avatarDmitry Torokhov <dtor@mail.ru>
parent d31b2865
...@@ -492,13 +492,15 @@ static int str_to_user(const char *str, unsigned int maxlen, void __user *p) ...@@ -492,13 +492,15 @@ static int str_to_user(const char *str, unsigned int maxlen, void __user *p)
} }
#define OLD_KEY_MAX 0x1ff #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; static unsigned long keymax_warn_time;
unsigned long *bits; unsigned long *bits;
int len; int len;
switch (_IOC_NR(cmd) & EV_MAX) { switch (type) {
case 0: bits = dev->evbit; len = EV_MAX; break; case 0: bits = dev->evbit; len = EV_MAX; break;
case EV_KEY: bits = dev->keybit; len = KEY_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 ...@@ -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' * EVIOCGBIT(EV_KEY, KEY_MAX) and not realize that 'len'
* should be in bytes, not in bits. * 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; len = OLD_KEY_MAX;
if (printk_timed_ratelimit(&keymax_warn_time, 10 * 1000)) if (printk_timed_ratelimit(&keymax_warn_time, 10 * 1000))
printk(KERN_WARNING printk(KERN_WARNING
...@@ -528,7 +530,7 @@ static int handle_eviocgbit(struct input_dev *dev, unsigned int cmd, void __user ...@@ -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)); 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 #undef OLD_KEY_MAX
...@@ -542,8 +544,10 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, ...@@ -542,8 +544,10 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
struct ff_effect effect; struct ff_effect effect;
int __user *ip = (int __user *)p; int __user *ip = (int __user *)p;
unsigned int i, t, u, v; unsigned int i, t, u, v;
unsigned int size;
int error; int error;
/* First we check for fixed-length commands */
switch (cmd) { switch (cmd) {
case EVIOCGVERSION: case EVIOCGVERSION:
...@@ -610,101 +614,102 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, ...@@ -610,101 +614,102 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
return evdev_grab(evdev, client); return evdev_grab(evdev, client);
else else
return evdev_ungrab(evdev, client); return evdev_ungrab(evdev, client);
}
default: size = _IOC_SIZE(cmd);
if (_IOC_TYPE(cmd) != 'E') /* Now check variable-length commands */
return -EINVAL; #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))) case EVIOCGKEY(0):
return handle_eviocgbit(dev, cmd, p, compat_mode); return bits_to_user(dev->key, KEY_MAX, size, p, compat_mode);
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) case EVIOCGLED(0):
return bits_to_user(dev->key, KEY_MAX, _IOC_SIZE(cmd), return bits_to_user(dev->led, LED_MAX, size, p, compat_mode);
p, compat_mode);
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) case EVIOCGSND(0):
return bits_to_user(dev->led, LED_MAX, _IOC_SIZE(cmd), return bits_to_user(dev->snd, SND_MAX, size, p, compat_mode);
p, compat_mode);
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) case EVIOCGSW(0):
return bits_to_user(dev->snd, SND_MAX, _IOC_SIZE(cmd), return bits_to_user(dev->sw, SW_MAX, size, p, compat_mode);
p, compat_mode);
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0))) case EVIOCGNAME(0):
return bits_to_user(dev->sw, SW_MAX, _IOC_SIZE(cmd), return str_to_user(dev->name, size, p);
p, compat_mode);
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) case EVIOCGPHYS(0):
return str_to_user(dev->name, _IOC_SIZE(cmd), p); return str_to_user(dev->phys, size, p);
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) case EVIOCGUNIQ(0):
return str_to_user(dev->phys, _IOC_SIZE(cmd), p); return str_to_user(dev->uniq, size, p);
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) case EVIOC_MASK_SIZE(EVIOCSFF):
return str_to_user(dev->uniq, _IOC_SIZE(cmd), p); 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; if (put_user(effect.id, &(((struct ff_effect __user *)p)->id)))
abs = dev->absinfo[t]; return -EFAULT;
if (copy_to_user(p, &abs, min_t(size_t, return error;
_IOC_SIZE(cmd), }
sizeof(struct input_absinfo))))
return -EFAULT;
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)) t = _IOC_NR(cmd) & ABS_MAX;
return -EFAULT; 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 0;
return -EFAULT; }
}
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, if (copy_from_user(&abs, p, min_t(size_t,
_IOC_SIZE(cmd), size, sizeof(struct input_absinfo))))
sizeof(struct input_absinfo)))) return -EFAULT;
return -EFAULT;
if (_IOC_SIZE(cmd) < sizeof(struct input_absinfo)) if (size < sizeof(struct input_absinfo))
abs.resolution = 0; abs.resolution = 0;
/* We can't change number of reserved MT slots */ /* We can't change number of reserved MT slots */
if (t == ABS_MT_SLOT) if (t == ABS_MT_SLOT)
return -EINVAL; return -EINVAL;
/* /*
* Take event lock to ensure that we are not * Take event lock to ensure that we are not
* changing device parameters in the middle * changing device parameters in the middle
* of event. * of event.
*/ */
spin_lock_irq(&dev->event_lock); spin_lock_irq(&dev->event_lock);
dev->absinfo[t] = abs; dev->absinfo[t] = abs;
spin_unlock_irq(&dev->event_lock); spin_unlock_irq(&dev->event_lock);
return 0; return 0;
}
} }
} }
return -EINVAL; return -EINVAL;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment