diff options
Diffstat (limited to 'drivers/input/evdev.c')
| -rw-r--r-- | drivers/input/evdev.c | 630 | 
1 files changed, 425 insertions, 205 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index e3f7fc6f956..fd325ec9f06 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -8,6 +8,8 @@   * the Free Software Foundation.   */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +  #define EVDEV_MINOR_BASE	64  #define EVDEV_MINORS		32  #define EVDEV_MIN_BUFFER_SIZE	64U @@ -16,16 +18,18 @@  #include <linux/poll.h>  #include <linux/sched.h>  #include <linux/slab.h> +#include <linux/vmalloc.h> +#include <linux/mm.h>  #include <linux/module.h>  #include <linux/init.h> -#include <linux/input.h> +#include <linux/input/mt.h>  #include <linux/major.h>  #include <linux/device.h> +#include <linux/cdev.h>  #include "input-compat.h"  struct evdev {  	int open; -	int minor;  	struct input_handle handle;  	wait_queue_head_t wait;  	struct evdev_client __rcu *grab; @@ -33,69 +37,196 @@ struct evdev {  	spinlock_t client_lock; /* protects client_list */  	struct mutex mutex;  	struct device dev; +	struct cdev cdev;  	bool exist;  };  struct evdev_client { -	int head; -	int tail; +	unsigned int head; +	unsigned int tail; +	unsigned int packet_head; /* [future] position of the first element of next packet */  	spinlock_t buffer_lock; /* protects access to buffer, head and tail */  	struct fasync_struct *fasync;  	struct evdev *evdev;  	struct list_head node; -	int bufsize; +	int clkid; +	bool revoked; +	unsigned int bufsize;  	struct input_event buffer[];  }; -static struct evdev *evdev_table[EVDEV_MINORS]; -static DEFINE_MUTEX(evdev_table_mutex); +/* flush queued events of type @type, caller must hold client->buffer_lock */ +static void __evdev_flush_queue(struct evdev_client *client, unsigned int type) +{ +	unsigned int i, head, num; +	unsigned int mask = client->bufsize - 1; +	bool is_report; +	struct input_event *ev; + +	BUG_ON(type == EV_SYN); + +	head = client->tail; +	client->packet_head = client->tail; + +	/* init to 1 so a leading SYN_REPORT will not be dropped */ +	num = 1; + +	for (i = client->tail; i != client->head; i = (i + 1) & mask) { +		ev = &client->buffer[i]; +		is_report = ev->type == EV_SYN && ev->code == SYN_REPORT; + +		if (ev->type == type) { +			/* drop matched entry */ +			continue; +		} else if (is_report && !num) { +			/* drop empty SYN_REPORT groups */ +			continue; +		} else if (head != i) { +			/* move entry to fill the gap */ +			client->buffer[head].time = ev->time; +			client->buffer[head].type = ev->type; +			client->buffer[head].code = ev->code; +			client->buffer[head].value = ev->value; +		} + +		num++; +		head = (head + 1) & mask; -static void evdev_pass_event(struct evdev_client *client, -			     struct input_event *event) +		if (is_report) { +			num = 0; +			client->packet_head = head; +		} +	} + +	client->head = head; +} + +/* queue SYN_DROPPED event */ +static void evdev_queue_syn_dropped(struct evdev_client *client)  { -	/* -	 * Interrupts are disabled, just acquire the lock. -	 * Make sure we don't leave with the client buffer -	 * "empty" by having client->head == client->tail. -	 */ +	unsigned long flags; +	struct input_event ev; +	ktime_t time; + +	time = ktime_get(); +	if (client->clkid != CLOCK_MONOTONIC) +		time = ktime_sub(time, ktime_get_monotonic_offset()); + +	ev.time = ktime_to_timeval(time); +	ev.type = EV_SYN; +	ev.code = SYN_DROPPED; +	ev.value = 0; + +	spin_lock_irqsave(&client->buffer_lock, flags); + +	client->buffer[client->head++] = ev; +	client->head &= client->bufsize - 1; + +	if (unlikely(client->head == client->tail)) { +		/* drop queue but keep our SYN_DROPPED event */ +		client->tail = (client->head - 1) & (client->bufsize - 1); +		client->packet_head = client->tail; +	} + +	spin_unlock_irqrestore(&client->buffer_lock, flags); +} + +static void __pass_event(struct evdev_client *client, +			 const struct input_event *event) +{ +	client->buffer[client->head++] = *event; +	client->head &= client->bufsize - 1; + +	if (unlikely(client->head == client->tail)) { +		/* +		 * This effectively "drops" all unconsumed events, leaving +		 * EV_SYN/SYN_DROPPED plus the newest event in the queue. +		 */ +		client->tail = (client->head - 2) & (client->bufsize - 1); + +		client->buffer[client->tail].time = event->time; +		client->buffer[client->tail].type = EV_SYN; +		client->buffer[client->tail].code = SYN_DROPPED; +		client->buffer[client->tail].value = 0; + +		client->packet_head = client->tail; +	} + +	if (event->type == EV_SYN && event->code == SYN_REPORT) { +		client->packet_head = client->head; +		kill_fasync(&client->fasync, SIGIO, POLL_IN); +	} +} + +static void evdev_pass_values(struct evdev_client *client, +			const struct input_value *vals, unsigned int count, +			ktime_t mono, ktime_t real) +{ +	struct evdev *evdev = client->evdev; +	const struct input_value *v; +	struct input_event event; +	bool wakeup = false; + +	if (client->revoked) +		return; + +	event.time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ? +				      mono : real); + +	/* Interrupts are disabled, just acquire the lock. */  	spin_lock(&client->buffer_lock); -	do { -		client->buffer[client->head++] = *event; -		client->head &= client->bufsize - 1; -	} while (client->head == client->tail); + +	for (v = vals; v != vals + count; v++) { +		event.type = v->type; +		event.code = v->code; +		event.value = v->value; +		__pass_event(client, &event); +		if (v->type == EV_SYN && v->code == SYN_REPORT) +			wakeup = true; +	} +  	spin_unlock(&client->buffer_lock); -	if (event->type == EV_SYN) -		kill_fasync(&client->fasync, SIGIO, POLL_IN); +	if (wakeup) +		wake_up_interruptible(&evdev->wait);  }  /* - * Pass incoming event to all connected clients. + * Pass incoming events to all connected clients.   */ -static void evdev_event(struct input_handle *handle, -			unsigned int type, unsigned int code, int value) +static void evdev_events(struct input_handle *handle, +			 const struct input_value *vals, unsigned int count)  {  	struct evdev *evdev = handle->private;  	struct evdev_client *client; -	struct input_event event; +	ktime_t time_mono, time_real; -	do_gettimeofday(&event.time); -	event.type = type; -	event.code = code; -	event.value = value; +	time_mono = ktime_get(); +	time_real = ktime_sub(time_mono, ktime_get_monotonic_offset());  	rcu_read_lock();  	client = rcu_dereference(evdev->grab); +  	if (client) -		evdev_pass_event(client, &event); +		evdev_pass_values(client, vals, count, time_mono, time_real);  	else  		list_for_each_entry_rcu(client, &evdev->client_list, node) -			evdev_pass_event(client, &event); +			evdev_pass_values(client, vals, count, +					  time_mono, time_real);  	rcu_read_unlock(); +} -	wake_up_interruptible(&evdev->wait); +/* + * Pass incoming event to all connected clients. + */ +static void evdev_event(struct input_handle *handle, +			unsigned int type, unsigned int code, int value) +{ +	struct input_value vals[] = { { type, code, value } }; + +	evdev_events(handle, vals, 1);  }  static int evdev_fasync(int fd, struct file *file, int on) @@ -115,7 +246,7 @@ static int evdev_flush(struct file *file, fl_owner_t id)  	if (retval)  		return retval; -	if (!evdev->exist) +	if (!evdev->exist || client->revoked)  		retval = -ENODEV;  	else  		retval = input_flush_device(&evdev->handle, file); @@ -148,14 +279,16 @@ static int evdev_grab(struct evdev *evdev, struct evdev_client *client)  		return error;  	rcu_assign_pointer(evdev->grab, client); -	synchronize_rcu();  	return 0;  }  static int evdev_ungrab(struct evdev *evdev, struct evdev_client *client)  { -	if (evdev->grab != client) +	struct evdev_client *grab = rcu_dereference_protected(evdev->grab, +					lockdep_is_held(&evdev->mutex)); + +	if (grab != client)  		return  -EINVAL;  	rcu_assign_pointer(evdev->grab, NULL); @@ -171,7 +304,6 @@ static void evdev_attach_client(struct evdev *evdev,  	spin_lock(&evdev->client_lock);  	list_add_tail_rcu(&client->node, &evdev->client_list);  	spin_unlock(&evdev->client_lock); -	synchronize_rcu();  }  static void evdev_detach_client(struct evdev *evdev, @@ -235,15 +367,17 @@ static int evdev_release(struct inode *inode, struct file *file)  	struct evdev *evdev = client->evdev;  	mutex_lock(&evdev->mutex); -	if (evdev->grab == client) -		evdev_ungrab(evdev, client); +	evdev_ungrab(evdev, client);  	mutex_unlock(&evdev->mutex);  	evdev_detach_client(evdev, client); -	kfree(client); + +	if (is_vmalloc_addr(client)) +		vfree(client); +	else +		kfree(client);  	evdev_close_device(evdev); -	put_device(&evdev->dev);  	return 0;  } @@ -259,35 +393,18 @@ static unsigned int evdev_compute_buffer_size(struct input_dev *dev)  static int evdev_open(struct inode *inode, struct file *file)  { -	struct evdev *evdev; +	struct evdev *evdev = container_of(inode->i_cdev, struct evdev, cdev); +	unsigned int bufsize = evdev_compute_buffer_size(evdev->handle.dev); +	unsigned int size = sizeof(struct evdev_client) + +					bufsize * sizeof(struct input_event);  	struct evdev_client *client; -	int i = iminor(inode) - EVDEV_MINOR_BASE; -	unsigned int bufsize;  	int error; -	if (i >= EVDEV_MINORS) -		return -ENODEV; - -	error = mutex_lock_interruptible(&evdev_table_mutex); -	if (error) -		return error; -	evdev = evdev_table[i]; -	if (evdev) -		get_device(&evdev->dev); -	mutex_unlock(&evdev_table_mutex); - -	if (!evdev) -		return -ENODEV; - -	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 = kzalloc(size, GFP_KERNEL | __GFP_NOWARN); +	if (!client) +		client = vzalloc(size); +	if (!client) +		return -ENOMEM;  	client->bufsize = bufsize;  	spin_lock_init(&client->buffer_lock); @@ -306,8 +423,6 @@ static int evdev_open(struct inode *inode, struct file *file)   err_free_client:  	evdev_detach_client(evdev, client);  	kfree(client); - err_put_evdev: -	put_device(&evdev->dev);  	return error;  } @@ -317,27 +432,30 @@ static ssize_t evdev_write(struct file *file, const char __user *buffer,  	struct evdev_client *client = file->private_data;  	struct evdev *evdev = client->evdev;  	struct input_event event; -	int retval; +	int retval = 0; + +	if (count != 0 && count < input_event_size()) +		return -EINVAL;  	retval = mutex_lock_interruptible(&evdev->mutex);  	if (retval)  		return retval; -	if (!evdev->exist) { +	if (!evdev->exist || client->revoked) {  		retval = -ENODEV;  		goto out;  	} -	while (retval < count) { +	while (retval + input_event_size() <= count) {  		if (input_event_from_user(buffer + retval, &event)) {  			retval = -EFAULT;  			goto out;  		} +		retval += input_event_size();  		input_inject_event(&evdev->handle,  				   event.type, event.code, event.value); -		retval += input_event_size();  	}   out: @@ -352,7 +470,7 @@ static int evdev_fetch_next_event(struct evdev_client *client,  	spin_lock_irq(&client->buffer_lock); -	have_event = client->head != client->tail; +	have_event = client->packet_head != client->tail;  	if (have_event) {  		*event = client->buffer[client->tail++];  		client->tail &= client->bufsize - 1; @@ -369,33 +487,49 @@ static ssize_t evdev_read(struct file *file, char __user *buffer,  	struct evdev_client *client = file->private_data;  	struct evdev *evdev = client->evdev;  	struct input_event event; -	int retval; +	size_t read = 0; +	int error; -	if (count < input_event_size()) +	if (count != 0 && count < input_event_size())  		return -EINVAL; -	if (client->head == client->tail && evdev->exist && -	    (file->f_flags & O_NONBLOCK)) -		return -EAGAIN; +	for (;;) { +		if (!evdev->exist || client->revoked) +			return -ENODEV; -	retval = wait_event_interruptible(evdev->wait, -		client->head != client->tail || !evdev->exist); -	if (retval) -		return retval; +		if (client->packet_head == client->tail && +		    (file->f_flags & O_NONBLOCK)) +			return -EAGAIN; -	if (!evdev->exist) -		return -ENODEV; +		/* +		 * count == 0 is special - no IO is done but we check +		 * for error conditions (see above). +		 */ +		if (count == 0) +			break; -	while (retval + input_event_size() <= count && -	       evdev_fetch_next_event(client, &event)) { +		while (read + input_event_size() <= count && +		       evdev_fetch_next_event(client, &event)) { -		if (input_event_to_user(buffer + retval, &event)) -			return -EFAULT; +			if (input_event_to_user(buffer + read, &event)) +				return -EFAULT; -		retval += input_event_size(); +			read += input_event_size(); +		} + +		if (read) +			break; + +		if (!(file->f_flags & O_NONBLOCK)) { +			error = wait_event_interruptible(evdev->wait, +					client->packet_head != client->tail || +					!evdev->exist || client->revoked); +			if (error) +				return error; +		}  	} -	return retval; +	return read;  }  /* No kernel lock - fine */ @@ -407,8 +541,12 @@ static unsigned int evdev_poll(struct file *file, poll_table *wait)  	poll_wait(file, &evdev->wait, wait); -	mask = evdev->exist ? POLLOUT | POLLWRNORM : POLLHUP | POLLERR; -	if (client->head != client->tail) +	if (evdev->exist && !client->revoked) +		mask = POLLOUT | POLLWRNORM; +	else +		mask = POLLHUP | POLLERR; + +	if (client->packet_head != client->tail)  		mask |= POLLIN | POLLRDNORM;  	return mask; @@ -491,12 +629,10 @@ static int str_to_user(const char *str, unsigned int maxlen, void __user *p)  	return copy_to_user(p, str, len) ? -EFAULT : len;  } -#define OLD_KEY_MAX	0x1ff  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; @@ -514,98 +650,158 @@ static int handle_eviocgbit(struct input_dev *dev,  	default: return -EINVAL;  	} -	/* -	 * Work around bugs in userspace programs that like to do -	 * EVIOCGBIT(EV_KEY, KEY_MAX) and not realize that 'len' -	 * should be in bytes, not in bits. -	 */ -	if (type == EV_KEY && size == OLD_KEY_MAX) { -		len = OLD_KEY_MAX; -		if (printk_timed_ratelimit(&keymax_warn_time, 10 * 1000)) -			printk(KERN_WARNING -				"evdev.c(EVIOCGBIT): Suspicious buffer size %u, " -				"limiting output to %zu bytes. See " -				"http://userweb.kernel.org/~dtor/eviocgbit-bug.html\n", -				OLD_KEY_MAX, -				BITS_TO_LONGS(OLD_KEY_MAX) * sizeof(long)); -	} -  	return bits_to_user(bits, len, size, p, compat_mode);  } -#undef OLD_KEY_MAX -static int evdev_handle_get_keycode(struct input_dev *dev, -				    void __user *p, size_t size) +static int evdev_handle_get_keycode(struct input_dev *dev, void __user *p)  { -	struct input_keymap_entry ke; +	struct input_keymap_entry ke = { +		.len	= sizeof(unsigned int), +		.flags	= 0, +	}; +	int __user *ip = (int __user *)p;  	int error; -	memset(&ke, 0, sizeof(ke)); - -	if (size == sizeof(unsigned int[2])) { -		/* legacy case */ -		int __user *ip = (int __user *)p; +	/* legacy case */ +	if (copy_from_user(ke.scancode, p, sizeof(unsigned int))) +		return -EFAULT; -		if (copy_from_user(ke.scancode, p, sizeof(unsigned int))) -			return -EFAULT; +	error = input_get_keycode(dev, &ke); +	if (error) +		return error; -		ke.len = sizeof(unsigned int); -		ke.flags = 0; +	if (put_user(ke.keycode, ip + 1)) +		return -EFAULT; -		error = input_get_keycode(dev, &ke); -		if (error) -			return error; +	return 0; +} -		if (put_user(ke.keycode, ip + 1)) -			return -EFAULT; +static int evdev_handle_get_keycode_v2(struct input_dev *dev, void __user *p) +{ +	struct input_keymap_entry ke; +	int error; -	} else { -		size = min(size, sizeof(ke)); +	if (copy_from_user(&ke, p, sizeof(ke))) +		return -EFAULT; -		if (copy_from_user(&ke, p, size)) -			return -EFAULT; +	error = input_get_keycode(dev, &ke); +	if (error) +		return error; -		error = input_get_keycode(dev, &ke); -		if (error) -			return error; +	if (copy_to_user(p, &ke, sizeof(ke))) +		return -EFAULT; -		if (copy_to_user(p, &ke, size)) -			return -EFAULT; -	}  	return 0;  } -static int evdev_handle_set_keycode(struct input_dev *dev, -				    void __user *p, size_t size) +static int evdev_handle_set_keycode(struct input_dev *dev, void __user *p) +{ +	struct input_keymap_entry ke = { +		.len	= sizeof(unsigned int), +		.flags	= 0, +	}; +	int __user *ip = (int __user *)p; + +	if (copy_from_user(ke.scancode, p, sizeof(unsigned int))) +		return -EFAULT; + +	if (get_user(ke.keycode, ip + 1)) +		return -EFAULT; + +	return input_set_keycode(dev, &ke); +} + +static int evdev_handle_set_keycode_v2(struct input_dev *dev, void __user *p)  {  	struct input_keymap_entry ke; -	memset(&ke, 0, sizeof(ke)); +	if (copy_from_user(&ke, p, sizeof(ke))) +		return -EFAULT; -	if (size == sizeof(unsigned int[2])) { -		/* legacy case */ -		int __user *ip = (int __user *)p; +	if (ke.len > sizeof(ke.scancode)) +		return -EINVAL; -		if (copy_from_user(ke.scancode, p, sizeof(unsigned int))) -			return -EFAULT; +	return input_set_keycode(dev, &ke); +} -		if (get_user(ke.keycode, ip + 1)) -			return -EFAULT; +/* + * If we transfer state to the user, we should flush all pending events + * of the same type from the client's queue. Otherwise, they might end up + * with duplicate events, which can screw up client's state tracking. + * If bits_to_user fails after flushing the queue, we queue a SYN_DROPPED + * event so user-space will notice missing events. + * + * LOCKING: + * We need to take event_lock before buffer_lock to avoid dead-locks. But we + * need the even_lock only to guarantee consistent state. We can safely release + * it while flushing the queue. This allows input-core to handle filters while + * we flush the queue. + */ +static int evdev_handle_get_val(struct evdev_client *client, +				struct input_dev *dev, unsigned int type, +				unsigned long *bits, unsigned int max, +				unsigned int size, void __user *p, int compat) +{ +	int ret; +	unsigned long *mem; + +	mem = kmalloc(sizeof(unsigned long) * max, GFP_KERNEL); +	if (!mem) +		return -ENOMEM; -		ke.len = sizeof(unsigned int); -		ke.flags = 0; +	spin_lock_irq(&dev->event_lock); +	spin_lock(&client->buffer_lock); -	} else { -		size = min(size, sizeof(ke)); +	memcpy(mem, bits, sizeof(unsigned long) * max); -		if (copy_from_user(&ke, p, size)) -			return -EFAULT; +	spin_unlock(&dev->event_lock); -		if (ke.len > sizeof(ke.scancode)) -			return -EINVAL; +	__evdev_flush_queue(client, type); + +	spin_unlock_irq(&client->buffer_lock); + +	ret = bits_to_user(mem, max, size, p, compat); +	if (ret < 0) +		evdev_queue_syn_dropped(client); + +	kfree(mem); + +	return ret; +} + +static int evdev_handle_mt_request(struct input_dev *dev, +				   unsigned int size, +				   int __user *ip) +{ +	const struct input_mt *mt = dev->mt; +	unsigned int code; +	int max_slots; +	int i; + +	if (get_user(code, &ip[0])) +		return -EFAULT; +	if (!mt || !input_is_mt_value(code)) +		return -EINVAL; + +	max_slots = (size - sizeof(__u32)) / sizeof(__s32); +	for (i = 0; i < mt->num_slots && i < max_slots; i++) { +		int value = input_mt_get_value(&mt->slots[i], code); +		if (put_user(value, &ip[1 + i])) +			return -EFAULT;  	} -	return input_set_keycode(dev, &ke); +	return 0; +} + +static int evdev_revoke(struct evdev *evdev, struct evdev_client *client, +			struct file *file) +{ +	client->revoked = true; +	evdev_ungrab(evdev, client); +	input_flush_device(&evdev->handle, file); +	wake_up_interruptible(&evdev->wait); + +	return 0;  }  static long evdev_do_ioctl(struct file *file, unsigned int cmd, @@ -669,6 +865,32 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,  			return evdev_grab(evdev, client);  		else  			return evdev_ungrab(evdev, client); + +	case EVIOCREVOKE: +		if (p) +			return -EINVAL; +		else +			return evdev_revoke(evdev, client, file); + +	case EVIOCSCLOCKID: +		if (copy_from_user(&i, p, sizeof(unsigned int))) +			return -EFAULT; +		if (i != CLOCK_MONOTONIC && i != CLOCK_REALTIME) +			return -EINVAL; +		client->clkid = i; +		return 0; + +	case EVIOCGKEYCODE: +		return evdev_handle_get_keycode(dev, p); + +	case EVIOCSKEYCODE: +		return evdev_handle_set_keycode(dev, p); + +	case EVIOCGKEYCODE_V2: +		return evdev_handle_get_keycode_v2(dev, p); + +	case EVIOCSKEYCODE_V2: +		return evdev_handle_set_keycode_v2(dev, p);  	}  	size = _IOC_SIZE(cmd); @@ -677,17 +899,28 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,  #define EVIOC_MASK_SIZE(nr)	((nr) & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT))  	switch (EVIOC_MASK_SIZE(cmd)) { +	case EVIOCGPROP(0): +		return bits_to_user(dev->propbit, INPUT_PROP_MAX, +				    size, p, compat_mode); + +	case EVIOCGMTSLOTS(0): +		return evdev_handle_mt_request(dev, size, ip); +  	case EVIOCGKEY(0): -		return bits_to_user(dev->key, KEY_MAX, size, p, compat_mode); +		return evdev_handle_get_val(client, dev, EV_KEY, dev->key, +					    KEY_MAX, size, p, compat_mode);  	case EVIOCGLED(0): -		return bits_to_user(dev->led, LED_MAX, size, p, compat_mode); +		return evdev_handle_get_val(client, dev, EV_LED, dev->led, +					    LED_MAX, size, p, compat_mode);  	case EVIOCGSND(0): -		return bits_to_user(dev->snd, SND_MAX, size, p, compat_mode); +		return evdev_handle_get_val(client, dev, EV_SND, dev->snd, +					    SND_MAX, size, p, compat_mode);  	case EVIOCGSW(0): -		return bits_to_user(dev->sw, SW_MAX, size, p, compat_mode); +		return evdev_handle_get_val(client, dev, EV_SW, dev->sw, +					    SW_MAX, size, p, compat_mode);  	case EVIOCGNAME(0):  		return str_to_user(dev->name, size, p); @@ -703,17 +936,13 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,  			return -EFAULT;  		error = input_ff_upload(dev, &effect, file); +		if (error) +			return error;  		if (put_user(effect.id, &(((struct ff_effect __user *)p)->id)))  			return -EFAULT; -		return error; - -	case EVIOC_MASK_SIZE(EVIOCGKEYCODE): -		return evdev_handle_get_keycode(dev, p, size); - -	case EVIOC_MASK_SIZE(EVIOCSKEYCODE): -		return evdev_handle_set_keycode(dev, p, size); +		return 0;  	}  	/* Multi-number variable-length handlers */ @@ -790,7 +1019,7 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd,  	if (retval)  		return retval; -	if (!evdev->exist) { +	if (!evdev->exist || client->revoked) {  		retval = -ENODEV;  		goto out;  	} @@ -831,26 +1060,6 @@ static const struct file_operations evdev_fops = {  	.llseek		= no_llseek,  }; -static int evdev_install_chrdev(struct evdev *evdev) -{ -	/* -	 * No need to do any locking here as calls to connect and -	 * disconnect are serialized by the input core -	 */ -	evdev_table[evdev->minor] = evdev; -	return 0; -} - -static void evdev_remove_chrdev(struct evdev *evdev) -{ -	/* -	 * Lock evdev table to prevent race with evdev_open() -	 */ -	mutex_lock(&evdev_table_mutex); -	evdev_table[evdev->minor] = NULL; -	mutex_unlock(&evdev_table_mutex); -} -  /*   * Mark device non-existent. This disables writes, ioctls and   * prevents new users from opening the device. Already posted @@ -869,7 +1078,8 @@ static void evdev_cleanup(struct evdev *evdev)  	evdev_mark_dead(evdev);  	evdev_hangup(evdev); -	evdev_remove_chrdev(evdev); + +	cdev_del(&evdev->cdev);  	/* evdev is marked dead so no one else accesses evdev->open */  	if (evdev->open) { @@ -880,43 +1090,47 @@ static void evdev_cleanup(struct evdev *evdev)  /*   * Create new evdev device. Note that input core serializes calls - * to connect and disconnect so we don't need to lock evdev_table here. + * to connect and disconnect.   */  static int evdev_connect(struct input_handler *handler, struct input_dev *dev,  			 const struct input_device_id *id)  {  	struct evdev *evdev;  	int minor; +	int dev_no;  	int error; -	for (minor = 0; minor < EVDEV_MINORS; minor++) -		if (!evdev_table[minor]) -			break; - -	if (minor == EVDEV_MINORS) { -		printk(KERN_ERR "evdev: no more free evdev devices\n"); -		return -ENFILE; +	minor = input_get_new_minor(EVDEV_MINOR_BASE, EVDEV_MINORS, true); +	if (minor < 0) { +		error = minor; +		pr_err("failed to reserve new minor: %d\n", error); +		return error;  	}  	evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL); -	if (!evdev) -		return -ENOMEM; +	if (!evdev) { +		error = -ENOMEM; +		goto err_free_minor; +	}  	INIT_LIST_HEAD(&evdev->client_list);  	spin_lock_init(&evdev->client_lock);  	mutex_init(&evdev->mutex);  	init_waitqueue_head(&evdev->wait); - -	dev_set_name(&evdev->dev, "event%d", minor);  	evdev->exist = true; -	evdev->minor = minor; + +	dev_no = minor; +	/* Normalize device number if it falls into legacy range */ +	if (dev_no < EVDEV_MINOR_BASE + EVDEV_MINORS) +		dev_no -= EVDEV_MINOR_BASE; +	dev_set_name(&evdev->dev, "event%d", dev_no);  	evdev->handle.dev = input_get_device(dev);  	evdev->handle.name = dev_name(&evdev->dev);  	evdev->handle.handler = handler;  	evdev->handle.private = evdev; -	evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor); +	evdev->dev.devt = MKDEV(INPUT_MAJOR, minor);  	evdev->dev.class = &input_class;  	evdev->dev.parent = &dev->dev;  	evdev->dev.release = evdev_free; @@ -926,7 +1140,9 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev,  	if (error)  		goto err_free_evdev; -	error = evdev_install_chrdev(evdev); +	cdev_init(&evdev->cdev, &evdev_fops); +	evdev->cdev.kobj.parent = &evdev->dev.kobj; +	error = cdev_add(&evdev->cdev, evdev->dev.devt, 1);  	if (error)  		goto err_unregister_handle; @@ -942,6 +1158,8 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev,  	input_unregister_handle(&evdev->handle);   err_free_evdev:  	put_device(&evdev->dev); + err_free_minor: +	input_free_minor(minor);  	return error;  } @@ -951,6 +1169,7 @@ static void evdev_disconnect(struct input_handle *handle)  	device_del(&evdev->dev);  	evdev_cleanup(evdev); +	input_free_minor(MINOR(evdev->dev.devt));  	input_unregister_handle(handle);  	put_device(&evdev->dev);  } @@ -964,9 +1183,10 @@ MODULE_DEVICE_TABLE(input, evdev_ids);  static struct input_handler evdev_handler = {  	.event		= evdev_event, +	.events		= evdev_events,  	.connect	= evdev_connect,  	.disconnect	= evdev_disconnect, -	.fops		= &evdev_fops, +	.legacy_minors	= true,  	.minor		= EVDEV_MINOR_BASE,  	.name		= "evdev",  	.id_table	= evdev_ids,  | 
