From b58f7086d52c0ac6c879ee5aaf7c276e17768e5b Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Wed, 23 Jun 2010 09:17:56 -0700 Subject: Input: evdev - convert to dynamic event buffer Allocate the event buffer dynamically, and prepare to compute the buffer size in a separate function. This patch defines the size computation to be identical to the current code, and does not contain any logical changes. Signed-off-by: Henrik Rydberg Signed-off-by: Dmitry Torokhov --- drivers/input/evdev.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'drivers/input/evdev.c') diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 2ee6c7a68bdc..cff7bf9351a8 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -10,7 +10,7 @@ #define EVDEV_MINOR_BASE 64 #define EVDEV_MINORS 32 -#define EVDEV_BUFFER_SIZE 64 +#define EVDEV_MIN_BUFFER_SIZE 64 #include #include @@ -36,13 +36,14 @@ struct evdev { }; struct evdev_client { - struct input_event buffer[EVDEV_BUFFER_SIZE]; int head; int tail; spinlock_t buffer_lock; /* protects access to buffer, head and tail */ struct fasync_struct *fasync; struct evdev *evdev; struct list_head node; + int bufsize; + struct input_event buffer[]; }; static struct evdev *evdev_table[EVDEV_MINORS]; @@ -56,7 +57,7 @@ static void evdev_pass_event(struct evdev_client *client, */ spin_lock(&client->buffer_lock); client->buffer[client->head++] = *event; - client->head &= EVDEV_BUFFER_SIZE - 1; + client->head &= client->bufsize - 1; spin_unlock(&client->buffer_lock); if (event->type == EV_SYN) @@ -242,11 +243,17 @@ static int evdev_release(struct inode *inode, struct file *file) return 0; } +static unsigned int evdev_compute_buffer_size(struct input_dev *dev) +{ + return EVDEV_MIN_BUFFER_SIZE; +} + static int evdev_open(struct inode *inode, struct file *file) { struct evdev *evdev; struct evdev_client *client; int i = iminor(inode) - EVDEV_MINOR_BASE; + unsigned int bufsize; int error; if (i >= EVDEV_MINORS) @@ -263,12 +270,17 @@ static int evdev_open(struct inode *inode, struct file *file) if (!evdev) return -ENODEV; - client = kzalloc(sizeof(struct evdev_client), GFP_KERNEL); + bufsize = evdev_compute_buffer_size(evdev->handle.dev); + + client = kzalloc(sizeof(struct evdev_client) + + bufsize * sizeof(struct input_event), + GFP_KERNEL); if (!client) { error = -ENOMEM; goto err_put_evdev; } + client->bufsize = bufsize; spin_lock_init(&client->buffer_lock); client->evdev = evdev; evdev_attach_client(evdev, client); @@ -334,7 +346,7 @@ static int evdev_fetch_next_event(struct evdev_client *client, have_event = client->head != client->tail; if (have_event) { *event = client->buffer[client->tail++]; - client->tail &= EVDEV_BUFFER_SIZE - 1; + client->tail &= client->bufsize - 1; } spin_unlock_irq(&client->buffer_lock); -- cgit v1.2.3 From 63a6404d8ae693e71ab27c4f9c4032aa29113e92 Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Thu, 10 Jun 2010 12:05:24 -0700 Subject: Input: evdev - use driver hint to compute size of event buffer Some devices, in particular MT devices, produce a lot of data. This may lead to overflowing of the event queues in evdev driver, which by default are fairly small. Let the drivers hint the average number of events per packet generated by the device, and use that information when computing the buffer size evdev should use for the device. Signed-off-by: Henrik Rydberg Acked-by: Chase Douglas Signed-off-by: Dmitry Torokhov --- drivers/input/evdev.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/input/evdev.c') diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index cff7bf9351a8..30836c05edd7 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -10,7 +10,8 @@ #define EVDEV_MINOR_BASE 64 #define EVDEV_MINORS 32 -#define EVDEV_MIN_BUFFER_SIZE 64 +#define EVDEV_MIN_BUFFER_SIZE 64U +#define EVDEV_BUF_PACKETS 8 #include #include @@ -245,7 +246,11 @@ static int evdev_release(struct inode *inode, struct file *file) static unsigned int evdev_compute_buffer_size(struct input_dev *dev) { - return EVDEV_MIN_BUFFER_SIZE; + unsigned int n_events = + max(dev->hint_events_per_packet * EVDEV_BUF_PACKETS, + EVDEV_MIN_BUFFER_SIZE); + + return roundup_pow_of_two(n_events); } static int evdev_open(struct inode *inode, struct file *file) -- cgit v1.2.3 From e725a4945d6eedd400dd5d0ead293d980a2f76ec Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Wed, 23 Jun 2010 10:09:26 -0700 Subject: Input: evdev - never leave the client buffer empty after write When the client buffer is very small and wraps around a lot, it may well be that a write increases the head such that head == tail. If this happens between the point where a poll is triggered and the actual data is being read, there will be no data to read. This is confusing to applications, which might end up closing the file. This patch solves the problem by making sure the client buffer is never empty after writing to it. Signed-off-by: Henrik Rydberg Signed-off-by: Dmitry Torokhov --- drivers/input/evdev.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/input/evdev.c') diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 30836c05edd7..cd323254ca6f 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -54,11 +54,15 @@ static void evdev_pass_event(struct evdev_client *client, struct input_event *event) { /* - * Interrupts are disabled, just acquire the lock + * Interrupts are disabled, just acquire the lock. + * Make sure we don't leave with the client buffer + * "empty" by having client->head == client->tail. */ spin_lock(&client->buffer_lock); - client->buffer[client->head++] = *event; - client->head &= client->bufsize - 1; + do { + client->buffer[client->head++] = *event; + client->head &= client->bufsize - 1; + } while (client->head == client->tail); spin_unlock(&client->buffer_lock); if (event->type == EV_SYN) -- cgit v1.2.3 From 40d007e7df1dab17bf1ecf91e718218354d963d7 Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Thu, 15 Jul 2010 23:10:10 -0700 Subject: Input: introduce MT event slots With the rapidly increasing number of intelligent multi-contact and multi-user devices, the need to send digested, filtered information from a set of different sources within the same device is imminent. This patch adds the concept of slots to the MT protocol. The slots enumerate a set of identified sources, such that all MT events can be passed independently and selectively per identified source. The protocol works like this: Instead of sending a SYN_MT_REPORT event immediately after the contact data, one sends an ABS_MT_SLOT event immediately before the contact data. The input core will only emit events for slots with modified MT events. It is assumed that the same slot is used for the duration of an initiated contact. Acked-by: Ping Cheng Acked-by: Chase Douglas Acked-by: Rafi Rubin Signed-off-by: Henrik Rydberg Signed-off-by: Dmitry Torokhov --- drivers/input/evdev.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/input/evdev.c') diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index cd323254ca6f..fc5afbd78625 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -686,6 +686,10 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, sizeof(struct input_absinfo)))) return -EFAULT; + /* 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 -- cgit v1.2.3 From 20da92de8ec3c1d4ba7e5aca322d38b6ce634932 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 15 Jul 2010 23:27:36 -0700 Subject: Input: change input handlers to use bool when possible Signed-off-by: Dmitry Torokhov --- drivers/input/evdev.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/input/evdev.c') diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index fc5afbd78625..70c0eb52ca96 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -24,7 +24,6 @@ #include "input-compat.h" struct evdev { - int exist; int open; int minor; struct input_handle handle; @@ -34,6 +33,7 @@ struct evdev { spinlock_t client_lock; /* protects client_list */ struct mutex mutex; struct device dev; + bool exist; }; struct evdev_client { @@ -793,7 +793,7 @@ static void evdev_remove_chrdev(struct evdev *evdev) static void evdev_mark_dead(struct evdev *evdev) { mutex_lock(&evdev->mutex); - evdev->exist = 0; + evdev->exist = false; mutex_unlock(&evdev->mutex); } @@ -842,7 +842,7 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, init_waitqueue_head(&evdev->wait); dev_set_name(&evdev->dev, "event%d", minor); - evdev->exist = 1; + evdev->exist = true; evdev->minor = minor; evdev->handle.dev = input_get_device(dev); -- cgit v1.2.3 From c18fb1396eb809dbc16e51da273a1789f9d799bf Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 15 Jul 2010 23:28:42 -0700 Subject: Input: evdev - signal that device is writable in evdev_poll() Signed-off-by: Dmitry Torokhov --- drivers/input/evdev.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/input/evdev.c') diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 70c0eb52ca96..054edf346e0b 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -403,10 +403,15 @@ static unsigned int evdev_poll(struct file *file, poll_table *wait) { struct evdev_client *client = file->private_data; struct evdev *evdev = client->evdev; + unsigned int mask; poll_wait(file, &evdev->wait, wait); - return ((client->head == client->tail) ? 0 : (POLLIN | POLLRDNORM)) | - (evdev->exist ? 0 : (POLLHUP | POLLERR)); + + mask = evdev->exist ? POLLOUT | POLLWRNORM : POLLHUP | POLLERR; + if (client->head != client->tail) + mask |= POLLIN | POLLRDNORM; + + return mask; } #ifdef CONFIG_COMPAT -- cgit v1.2.3 From 987a6c0298260b7aa40702b349282554d6180e4b Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Mon, 2 Aug 2010 20:15:17 -0700 Subject: Input: switch to input_abs_*() access functions Change all call sites in drivers/input to not access the ABS axis information directly anymore. Make them use the access helpers instead. Also use input_set_abs_params() when possible. Did some code refactoring as I was on it. Signed-off-by: Daniel Mack Cc: Dmitry Torokhov Signed-off-by: Dmitry Torokhov --- drivers/input/evdev.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers/input/evdev.c') diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 054edf346e0b..9807c8ff6a84 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -650,12 +650,12 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, t = _IOC_NR(cmd) & ABS_MAX; - abs.value = dev->abs[t]; - abs.minimum = dev->absmin[t]; - abs.maximum = dev->absmax[t]; - abs.fuzz = dev->absfuzz[t]; - abs.flat = dev->absflat[t]; - abs.resolution = dev->absres[t]; + abs.value = input_abs_get_val(dev, t); + abs.minimum = input_abs_get_min(dev, t); + abs.maximum = input_abs_get_max(dev, t); + abs.fuzz = input_abs_get_fuzz(dev, t); + abs.flat = input_abs_get_flat(dev, t); + abs.resolution = input_abs_get_res(dev, t); if (copy_to_user(p, &abs, min_t(size_t, _IOC_SIZE(cmd), @@ -702,13 +702,13 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, */ spin_lock_irq(&dev->event_lock); - dev->abs[t] = abs.value; - dev->absmin[t] = abs.minimum; - dev->absmax[t] = abs.maximum; - dev->absfuzz[t] = abs.fuzz; - dev->absflat[t] = abs.flat; - dev->absres[t] = _IOC_SIZE(cmd) < sizeof(struct input_absinfo) ? - 0 : abs.resolution; + input_abs_set_val(dev, t, abs.value); + input_abs_set_min(dev, t, abs.minimum); + input_abs_set_max(dev, t, abs.maximum); + input_abs_set_fuzz(dev, t, abs.fuzz); + input_abs_set_flat(dev, t, abs.flat); + input_abs_set_res(dev, t, _IOC_SIZE(cmd) < sizeof(struct input_absinfo) ? + 0 : abs.resolution); spin_unlock_irq(&dev->event_lock); -- cgit v1.2.3 From d31b2865a4e8a9dd02f39e56c8fadb824c5e187b Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Mon, 2 Aug 2010 20:18:21 -0700 Subject: Input: dynamically allocate ABS information As all callers are now changed to only use the input_abs_*() access helpers, switching over to dynamically allocated ABS information is easy. This reduces size of struct input_dev from 3152 to 1640 on 64 bit architectures. Signed-off-by: Daniel Mack Signed-off-by: Dmitry Torokhov --- drivers/input/evdev.c | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) (limited to 'drivers/input/evdev.c') diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 9807c8ff6a84..08f48c03eec4 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -649,13 +649,7 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) { t = _IOC_NR(cmd) & ABS_MAX; - - abs.value = input_abs_get_val(dev, t); - abs.minimum = input_abs_get_min(dev, t); - abs.maximum = input_abs_get_max(dev, t); - abs.fuzz = input_abs_get_fuzz(dev, t); - abs.flat = input_abs_get_flat(dev, t); - abs.resolution = input_abs_get_res(dev, t); + abs = dev->absinfo[t]; if (copy_to_user(p, &abs, min_t(size_t, _IOC_SIZE(cmd), @@ -691,6 +685,9 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, sizeof(struct input_absinfo)))) return -EFAULT; + if (_IOC_SIZE(cmd) < sizeof(struct input_absinfo)) + abs.resolution = 0; + /* We can't change number of reserved MT slots */ if (t == ABS_MT_SLOT) return -EINVAL; @@ -701,15 +698,7 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, * of event. */ spin_lock_irq(&dev->event_lock); - - input_abs_set_val(dev, t, abs.value); - input_abs_set_min(dev, t, abs.minimum); - input_abs_set_max(dev, t, abs.maximum); - input_abs_set_fuzz(dev, t, abs.fuzz); - input_abs_set_flat(dev, t, abs.flat); - input_abs_set_res(dev, t, _IOC_SIZE(cmd) < sizeof(struct input_absinfo) ? - 0 : abs.resolution); - + dev->absinfo[t] = abs; spin_unlock_irq(&dev->event_lock); return 0; -- cgit v1.2.3 From 448cd1664a573e69f54bfd32f3bb7220212b6cf5 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 2 Aug 2010 20:29:10 -0700 Subject: 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 --- drivers/input/evdev.c | 141 ++++++++++++++++++++++++++------------------------ 1 file changed, 73 insertions(+), 68 deletions(-) (limited to 'drivers/input/evdev.c') 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) } #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; } -- cgit v1.2.3