xref: /linux-6.15/drivers/input/evdev.c (revision 293c5bd1)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * Event char devices, giving access to raw input device events.
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * Copyright (c) 1999-2002 Vojtech Pavlik
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  * This program is free software; you can redistribute it and/or modify it
71da177e4SLinus Torvalds  * under the terms of the GNU General Public License version 2 as published by
81da177e4SLinus Torvalds  * the Free Software Foundation.
91da177e4SLinus Torvalds  */
101da177e4SLinus Torvalds 
111da177e4SLinus Torvalds #define EVDEV_MINOR_BASE	64
121da177e4SLinus Torvalds #define EVDEV_MINORS		32
131da177e4SLinus Torvalds #define EVDEV_BUFFER_SIZE	64
141da177e4SLinus Torvalds 
151da177e4SLinus Torvalds #include <linux/poll.h>
161da177e4SLinus Torvalds #include <linux/slab.h>
171da177e4SLinus Torvalds #include <linux/module.h>
181da177e4SLinus Torvalds #include <linux/init.h>
191da177e4SLinus Torvalds #include <linux/input.h>
201da177e4SLinus Torvalds #include <linux/major.h>
211da177e4SLinus Torvalds #include <linux/device.h>
2252658bb6SJuergen Kreileder #include <linux/compat.h>
231da177e4SLinus Torvalds 
241da177e4SLinus Torvalds struct evdev {
251da177e4SLinus Torvalds 	int exist;
261da177e4SLinus Torvalds 	int open;
271da177e4SLinus Torvalds 	int minor;
281da177e4SLinus Torvalds 	char name[16];
291da177e4SLinus Torvalds 	struct input_handle handle;
301da177e4SLinus Torvalds 	wait_queue_head_t wait;
31d0ffb9beSDmitry Torokhov 	struct evdev_client *grab;
32d0ffb9beSDmitry Torokhov 	struct list_head client_list;
339657d75cSDmitry Torokhov 	struct device dev;
341da177e4SLinus Torvalds };
351da177e4SLinus Torvalds 
36d0ffb9beSDmitry Torokhov struct evdev_client {
371da177e4SLinus Torvalds 	struct input_event buffer[EVDEV_BUFFER_SIZE];
381da177e4SLinus Torvalds 	int head;
391da177e4SLinus Torvalds 	int tail;
401da177e4SLinus Torvalds 	struct fasync_struct *fasync;
411da177e4SLinus Torvalds 	struct evdev *evdev;
421da177e4SLinus Torvalds 	struct list_head node;
431da177e4SLinus Torvalds };
441da177e4SLinus Torvalds 
451da177e4SLinus Torvalds static struct evdev *evdev_table[EVDEV_MINORS];
461da177e4SLinus Torvalds 
471da177e4SLinus Torvalds static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
481da177e4SLinus Torvalds {
491da177e4SLinus Torvalds 	struct evdev *evdev = handle->private;
50d0ffb9beSDmitry Torokhov 	struct evdev_client *client;
511da177e4SLinus Torvalds 
521da177e4SLinus Torvalds 	if (evdev->grab) {
53d0ffb9beSDmitry Torokhov 		client = evdev->grab;
541da177e4SLinus Torvalds 
55d0ffb9beSDmitry Torokhov 		do_gettimeofday(&client->buffer[client->head].time);
56d0ffb9beSDmitry Torokhov 		client->buffer[client->head].type = type;
57d0ffb9beSDmitry Torokhov 		client->buffer[client->head].code = code;
58d0ffb9beSDmitry Torokhov 		client->buffer[client->head].value = value;
59d0ffb9beSDmitry Torokhov 		client->head = (client->head + 1) & (EVDEV_BUFFER_SIZE - 1);
601da177e4SLinus Torvalds 
61d0ffb9beSDmitry Torokhov 		kill_fasync(&client->fasync, SIGIO, POLL_IN);
621da177e4SLinus Torvalds 	} else
63d0ffb9beSDmitry Torokhov 		list_for_each_entry(client, &evdev->client_list, node) {
641da177e4SLinus Torvalds 
65d0ffb9beSDmitry Torokhov 			do_gettimeofday(&client->buffer[client->head].time);
66d0ffb9beSDmitry Torokhov 			client->buffer[client->head].type = type;
67d0ffb9beSDmitry Torokhov 			client->buffer[client->head].code = code;
68d0ffb9beSDmitry Torokhov 			client->buffer[client->head].value = value;
69d0ffb9beSDmitry Torokhov 			client->head = (client->head + 1) & (EVDEV_BUFFER_SIZE - 1);
701da177e4SLinus Torvalds 
71d0ffb9beSDmitry Torokhov 			kill_fasync(&client->fasync, SIGIO, POLL_IN);
721da177e4SLinus Torvalds 		}
731da177e4SLinus Torvalds 
741da177e4SLinus Torvalds 	wake_up_interruptible(&evdev->wait);
751da177e4SLinus Torvalds }
761da177e4SLinus Torvalds 
771da177e4SLinus Torvalds static int evdev_fasync(int fd, struct file *file, int on)
781da177e4SLinus Torvalds {
79d0ffb9beSDmitry Torokhov 	struct evdev_client *client = file->private_data;
801da177e4SLinus Torvalds 	int retval;
811e0afb28SDmitry Torokhov 
82d0ffb9beSDmitry Torokhov 	retval = fasync_helper(fd, file, on, &client->fasync);
831e0afb28SDmitry Torokhov 
841da177e4SLinus Torvalds 	return retval < 0 ? retval : 0;
851da177e4SLinus Torvalds }
861da177e4SLinus Torvalds 
8775e1fcc0SMiklos Szeredi static int evdev_flush(struct file *file, fl_owner_t id)
881da177e4SLinus Torvalds {
89d0ffb9beSDmitry Torokhov 	struct evdev_client *client = file->private_data;
90d0ffb9beSDmitry Torokhov 	struct evdev *evdev = client->evdev;
911e0afb28SDmitry Torokhov 
92d0ffb9beSDmitry Torokhov 	if (!evdev->exist)
931e0afb28SDmitry Torokhov 		return -ENODEV;
941e0afb28SDmitry Torokhov 
95d0ffb9beSDmitry Torokhov 	return input_flush_device(&evdev->handle, file);
961da177e4SLinus Torvalds }
971da177e4SLinus Torvalds 
989657d75cSDmitry Torokhov static void evdev_free(struct device *dev)
991da177e4SLinus Torvalds {
1009657d75cSDmitry Torokhov 	struct evdev *evdev = container_of(dev, struct evdev, dev);
1019657d75cSDmitry Torokhov 
1021da177e4SLinus Torvalds 	evdev_table[evdev->minor] = NULL;
1031da177e4SLinus Torvalds 	kfree(evdev);
1041da177e4SLinus Torvalds }
1051da177e4SLinus Torvalds 
1061da177e4SLinus Torvalds static int evdev_release(struct inode *inode, struct file *file)
1071da177e4SLinus Torvalds {
108d0ffb9beSDmitry Torokhov 	struct evdev_client *client = file->private_data;
109d0ffb9beSDmitry Torokhov 	struct evdev *evdev = client->evdev;
1101da177e4SLinus Torvalds 
111d0ffb9beSDmitry Torokhov 	if (evdev->grab == client) {
112d0ffb9beSDmitry Torokhov 		input_release_device(&evdev->handle);
113d0ffb9beSDmitry Torokhov 		evdev->grab = NULL;
1141da177e4SLinus Torvalds 	}
1151da177e4SLinus Torvalds 
1161da177e4SLinus Torvalds 	evdev_fasync(-1, file, 0);
117d0ffb9beSDmitry Torokhov 	list_del(&client->node);
118d0ffb9beSDmitry Torokhov 	kfree(client);
1191da177e4SLinus Torvalds 
1209657d75cSDmitry Torokhov 	if (!--evdev->open && evdev->exist)
121d0ffb9beSDmitry Torokhov 		input_close_device(&evdev->handle);
1229657d75cSDmitry Torokhov 
1239657d75cSDmitry Torokhov 	put_device(&evdev->dev);
1241da177e4SLinus Torvalds 
1251da177e4SLinus Torvalds 	return 0;
1261da177e4SLinus Torvalds }
1271da177e4SLinus Torvalds 
1281da177e4SLinus Torvalds static int evdev_open(struct inode *inode, struct file *file)
1291da177e4SLinus Torvalds {
130d0ffb9beSDmitry Torokhov 	struct evdev_client *client;
131d0ffb9beSDmitry Torokhov 	struct evdev *evdev;
1321da177e4SLinus Torvalds 	int i = iminor(inode) - EVDEV_MINOR_BASE;
133d542ed82SDmitry Torokhov 	int error;
1341da177e4SLinus Torvalds 
135d0ffb9beSDmitry Torokhov 	if (i >= EVDEV_MINORS)
1361da177e4SLinus Torvalds 		return -ENODEV;
1371da177e4SLinus Torvalds 
138d0ffb9beSDmitry Torokhov 	evdev = evdev_table[i];
139d0ffb9beSDmitry Torokhov 
140d0ffb9beSDmitry Torokhov 	if (!evdev || !evdev->exist)
141d0ffb9beSDmitry Torokhov 		return -ENODEV;
142d0ffb9beSDmitry Torokhov 
1439657d75cSDmitry Torokhov 	get_device(&evdev->dev);
1449657d75cSDmitry Torokhov 
145d0ffb9beSDmitry Torokhov 	client = kzalloc(sizeof(struct evdev_client), GFP_KERNEL);
1469657d75cSDmitry Torokhov 	if (!client) {
1479657d75cSDmitry Torokhov 		error = -ENOMEM;
1489657d75cSDmitry Torokhov 		goto err_put_evdev;
1499657d75cSDmitry Torokhov 	}
1501da177e4SLinus Torvalds 
151d0ffb9beSDmitry Torokhov 	client->evdev = evdev;
152d0ffb9beSDmitry Torokhov 	list_add_tail(&client->node, &evdev->client_list);
1531da177e4SLinus Torvalds 
154d542ed82SDmitry Torokhov 	if (!evdev->open++ && evdev->exist) {
155d542ed82SDmitry Torokhov 		error = input_open_device(&evdev->handle);
1569657d75cSDmitry Torokhov 		if (error)
1579657d75cSDmitry Torokhov 			goto err_free_client;
158d542ed82SDmitry Torokhov 	}
1591da177e4SLinus Torvalds 
160d0ffb9beSDmitry Torokhov 	file->private_data = client;
1611da177e4SLinus Torvalds 	return 0;
1629657d75cSDmitry Torokhov 
1639657d75cSDmitry Torokhov  err_free_client:
1649657d75cSDmitry Torokhov 	list_del(&client->node);
1659657d75cSDmitry Torokhov 	kfree(client);
1669657d75cSDmitry Torokhov  err_put_evdev:
1679657d75cSDmitry Torokhov 	put_device(&evdev->dev);
1689657d75cSDmitry Torokhov 	return error;
1691da177e4SLinus Torvalds }
1701da177e4SLinus Torvalds 
17152658bb6SJuergen Kreileder #ifdef CONFIG_COMPAT
1723a51f7c4SDmitry Torokhov 
17352658bb6SJuergen Kreileder struct input_event_compat {
17452658bb6SJuergen Kreileder 	struct compat_timeval time;
17552658bb6SJuergen Kreileder 	__u16 type;
17652658bb6SJuergen Kreileder 	__u16 code;
17752658bb6SJuergen Kreileder 	__s32 value;
17852658bb6SJuergen Kreileder };
17952658bb6SJuergen Kreileder 
180bf2fcc6fSAndi Kleen /* Note to the author of this code: did it ever occur to
181bf2fcc6fSAndi Kleen    you why the ifdefs are needed? Think about it again. -AK */
18252658bb6SJuergen Kreileder #ifdef CONFIG_X86_64
183bf2fcc6fSAndi Kleen #  define COMPAT_TEST is_compat_task()
18452658bb6SJuergen Kreileder #elif defined(CONFIG_IA64)
1856450578fSAl Viro #  define COMPAT_TEST IS_IA32_PROCESS(task_pt_regs(current))
186347a8dc3SMartin Schwidefsky #elif defined(CONFIG_S390)
18752658bb6SJuergen Kreileder #  define COMPAT_TEST test_thread_flag(TIF_31BIT)
18859df6bbfSRalf Baechle #elif defined(CONFIG_MIPS)
189*293c5bd1SRalf Baechle #  define COMPAT_TEST test_thread_flag(TIF_32BIT_ADDR)
19052658bb6SJuergen Kreileder #else
19152658bb6SJuergen Kreileder #  define COMPAT_TEST test_thread_flag(TIF_32BIT)
19252658bb6SJuergen Kreileder #endif
19352658bb6SJuergen Kreileder 
1943a51f7c4SDmitry Torokhov static inline size_t evdev_event_size(void)
19552658bb6SJuergen Kreileder {
1963a51f7c4SDmitry Torokhov 	return COMPAT_TEST ?
1973a51f7c4SDmitry Torokhov 		sizeof(struct input_event_compat) : sizeof(struct input_event);
1983a51f7c4SDmitry Torokhov }
19952658bb6SJuergen Kreileder 
2003a51f7c4SDmitry Torokhov static int evdev_event_from_user(const char __user *buffer, struct input_event *event)
2013a51f7c4SDmitry Torokhov {
2023a51f7c4SDmitry Torokhov 	if (COMPAT_TEST) {
2033a51f7c4SDmitry Torokhov 		struct input_event_compat compat_event;
2043a51f7c4SDmitry Torokhov 
2053a51f7c4SDmitry Torokhov 		if (copy_from_user(&compat_event, buffer, sizeof(struct input_event_compat)))
20652658bb6SJuergen Kreileder 			return -EFAULT;
2073a51f7c4SDmitry Torokhov 
2083a51f7c4SDmitry Torokhov 		event->time.tv_sec = compat_event.time.tv_sec;
2093a51f7c4SDmitry Torokhov 		event->time.tv_usec = compat_event.time.tv_usec;
2103a51f7c4SDmitry Torokhov 		event->type = compat_event.type;
2113a51f7c4SDmitry Torokhov 		event->code = compat_event.code;
2123a51f7c4SDmitry Torokhov 		event->value = compat_event.value;
2133a51f7c4SDmitry Torokhov 
2143a51f7c4SDmitry Torokhov 	} else {
2153a51f7c4SDmitry Torokhov 		if (copy_from_user(event, buffer, sizeof(struct input_event)))
2163a51f7c4SDmitry Torokhov 			return -EFAULT;
21752658bb6SJuergen Kreileder 	}
21852658bb6SJuergen Kreileder 
2193a51f7c4SDmitry Torokhov 	return 0;
22052658bb6SJuergen Kreileder }
2213a51f7c4SDmitry Torokhov 
2223a51f7c4SDmitry Torokhov static int evdev_event_to_user(char __user *buffer, const struct input_event *event)
2233a51f7c4SDmitry Torokhov {
2243a51f7c4SDmitry Torokhov 	if (COMPAT_TEST) {
2253a51f7c4SDmitry Torokhov 		struct input_event_compat compat_event;
2263a51f7c4SDmitry Torokhov 
2273a51f7c4SDmitry Torokhov 		compat_event.time.tv_sec = event->time.tv_sec;
2283a51f7c4SDmitry Torokhov 		compat_event.time.tv_usec = event->time.tv_usec;
2293a51f7c4SDmitry Torokhov 		compat_event.type = event->type;
2303a51f7c4SDmitry Torokhov 		compat_event.code = event->code;
2313a51f7c4SDmitry Torokhov 		compat_event.value = event->value;
2323a51f7c4SDmitry Torokhov 
2333a51f7c4SDmitry Torokhov 		if (copy_to_user(buffer, &compat_event, sizeof(struct input_event_compat)))
2343a51f7c4SDmitry Torokhov 			return -EFAULT;
2353a51f7c4SDmitry Torokhov 
2363a51f7c4SDmitry Torokhov 	} else {
2373a51f7c4SDmitry Torokhov 		if (copy_to_user(buffer, event, sizeof(struct input_event)))
2383a51f7c4SDmitry Torokhov 			return -EFAULT;
2393a51f7c4SDmitry Torokhov 	}
2403a51f7c4SDmitry Torokhov 
2413a51f7c4SDmitry Torokhov 	return 0;
2423a51f7c4SDmitry Torokhov }
2433a51f7c4SDmitry Torokhov 
2443a51f7c4SDmitry Torokhov #else
2453a51f7c4SDmitry Torokhov 
2463a51f7c4SDmitry Torokhov static inline size_t evdev_event_size(void)
2473a51f7c4SDmitry Torokhov {
2483a51f7c4SDmitry Torokhov 	return sizeof(struct input_event);
2493a51f7c4SDmitry Torokhov }
2503a51f7c4SDmitry Torokhov 
2513a51f7c4SDmitry Torokhov static int evdev_event_from_user(const char __user *buffer, struct input_event *event)
2523a51f7c4SDmitry Torokhov {
2533a51f7c4SDmitry Torokhov 	if (copy_from_user(event, buffer, sizeof(struct input_event)))
2543a51f7c4SDmitry Torokhov 		return -EFAULT;
2553a51f7c4SDmitry Torokhov 
2563a51f7c4SDmitry Torokhov 	return 0;
2573a51f7c4SDmitry Torokhov }
2583a51f7c4SDmitry Torokhov 
2593a51f7c4SDmitry Torokhov static int evdev_event_to_user(char __user *buffer, const struct input_event *event)
2603a51f7c4SDmitry Torokhov {
2613a51f7c4SDmitry Torokhov 	if (copy_to_user(buffer, event, sizeof(struct input_event)))
2623a51f7c4SDmitry Torokhov 		return -EFAULT;
2633a51f7c4SDmitry Torokhov 
2643a51f7c4SDmitry Torokhov 	return 0;
2653a51f7c4SDmitry Torokhov }
2663a51f7c4SDmitry Torokhov 
2673a51f7c4SDmitry Torokhov #endif /* CONFIG_COMPAT */
26852658bb6SJuergen Kreileder 
2691da177e4SLinus Torvalds static ssize_t evdev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
2701da177e4SLinus Torvalds {
271d0ffb9beSDmitry Torokhov 	struct evdev_client *client = file->private_data;
272d0ffb9beSDmitry Torokhov 	struct evdev *evdev = client->evdev;
2731da177e4SLinus Torvalds 	struct input_event event;
2741da177e4SLinus Torvalds 	int retval = 0;
2751da177e4SLinus Torvalds 
276d0ffb9beSDmitry Torokhov 	if (!evdev->exist)
27752658bb6SJuergen Kreileder 		return -ENODEV;
27852658bb6SJuergen Kreileder 
2793a51f7c4SDmitry Torokhov 	while (retval < count) {
28052658bb6SJuergen Kreileder 
2813a51f7c4SDmitry Torokhov 		if (evdev_event_from_user(buffer + retval, &event))
2823a51f7c4SDmitry Torokhov 			return -EFAULT;
283d0ffb9beSDmitry Torokhov 		input_inject_event(&evdev->handle, event.type, event.code, event.value);
2843a51f7c4SDmitry Torokhov 		retval += evdev_event_size();
28552658bb6SJuergen Kreileder 	}
28652658bb6SJuergen Kreileder 
28752658bb6SJuergen Kreileder 	return retval;
28852658bb6SJuergen Kreileder }
28952658bb6SJuergen Kreileder 
2901da177e4SLinus Torvalds static ssize_t evdev_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
2911da177e4SLinus Torvalds {
292d0ffb9beSDmitry Torokhov 	struct evdev_client *client = file->private_data;
293d0ffb9beSDmitry Torokhov 	struct evdev *evdev = client->evdev;
2941da177e4SLinus Torvalds 	int retval;
2951da177e4SLinus Torvalds 
2963a51f7c4SDmitry Torokhov 	if (count < evdev_event_size())
2971da177e4SLinus Torvalds 		return -EINVAL;
2981da177e4SLinus Torvalds 
299d0ffb9beSDmitry Torokhov 	if (client->head == client->tail && evdev->exist && (file->f_flags & O_NONBLOCK))
3001da177e4SLinus Torvalds 		return -EAGAIN;
3011da177e4SLinus Torvalds 
302d0ffb9beSDmitry Torokhov 	retval = wait_event_interruptible(evdev->wait,
303d0ffb9beSDmitry Torokhov 		client->head != client->tail || !evdev->exist);
3041da177e4SLinus Torvalds 	if (retval)
3051da177e4SLinus Torvalds 		return retval;
3061da177e4SLinus Torvalds 
307d0ffb9beSDmitry Torokhov 	if (!evdev->exist)
3081da177e4SLinus Torvalds 		return -ENODEV;
3091da177e4SLinus Torvalds 
310d0ffb9beSDmitry Torokhov 	while (client->head != client->tail && retval + evdev_event_size() <= count) {
3113a51f7c4SDmitry Torokhov 
312d0ffb9beSDmitry Torokhov 		struct input_event *event = (struct input_event *) client->buffer + client->tail;
3133a51f7c4SDmitry Torokhov 
3143a51f7c4SDmitry Torokhov 		if (evdev_event_to_user(buffer + retval, event))
3153a51f7c4SDmitry Torokhov 			return -EFAULT;
3163a51f7c4SDmitry Torokhov 
317d0ffb9beSDmitry Torokhov 		client->tail = (client->tail + 1) & (EVDEV_BUFFER_SIZE - 1);
3183a51f7c4SDmitry Torokhov 		retval += evdev_event_size();
3191da177e4SLinus Torvalds 	}
3201da177e4SLinus Torvalds 
3211da177e4SLinus Torvalds 	return retval;
3221da177e4SLinus Torvalds }
3231da177e4SLinus Torvalds 
3241da177e4SLinus Torvalds /* No kernel lock - fine */
3251da177e4SLinus Torvalds static unsigned int evdev_poll(struct file *file, poll_table *wait)
3261da177e4SLinus Torvalds {
327d0ffb9beSDmitry Torokhov 	struct evdev_client *client = file->private_data;
328d0ffb9beSDmitry Torokhov 	struct evdev *evdev = client->evdev;
3291e0afb28SDmitry Torokhov 
330d0ffb9beSDmitry Torokhov 	poll_wait(file, &evdev->wait, wait);
331d0ffb9beSDmitry Torokhov 	return ((client->head == client->tail) ? 0 : (POLLIN | POLLRDNORM)) |
332d0ffb9beSDmitry Torokhov 		(evdev->exist ? 0 : (POLLHUP | POLLERR));
3331da177e4SLinus Torvalds }
3341da177e4SLinus Torvalds 
3353a51f7c4SDmitry Torokhov #ifdef CONFIG_COMPAT
3363a51f7c4SDmitry Torokhov 
3373a51f7c4SDmitry Torokhov #define BITS_PER_LONG_COMPAT (sizeof(compat_long_t) * 8)
3383a51f7c4SDmitry Torokhov #define NBITS_COMPAT(x) ((((x) - 1) / BITS_PER_LONG_COMPAT) + 1)
3393a51f7c4SDmitry Torokhov 
3403a51f7c4SDmitry Torokhov #ifdef __BIG_ENDIAN
3413a51f7c4SDmitry Torokhov static int bits_to_user(unsigned long *bits, unsigned int maxbit,
3423a51f7c4SDmitry Torokhov 			unsigned int maxlen, void __user *p, int compat)
3433a51f7c4SDmitry Torokhov {
3443a51f7c4SDmitry Torokhov 	int len, i;
3453a51f7c4SDmitry Torokhov 
3463a51f7c4SDmitry Torokhov 	if (compat) {
3473a51f7c4SDmitry Torokhov 		len = NBITS_COMPAT(maxbit) * sizeof(compat_long_t);
348bf61f8d3SKenichi Nagai 		if (len > maxlen)
3493a51f7c4SDmitry Torokhov 			len = maxlen;
3503a51f7c4SDmitry Torokhov 
3513a51f7c4SDmitry Torokhov 		for (i = 0; i < len / sizeof(compat_long_t); i++)
3523a51f7c4SDmitry Torokhov 			if (copy_to_user((compat_long_t __user *) p + i,
3533a51f7c4SDmitry Torokhov 					 (compat_long_t *) bits +
3543a51f7c4SDmitry Torokhov 						i + 1 - ((i % 2) << 1),
3553a51f7c4SDmitry Torokhov 					 sizeof(compat_long_t)))
3563a51f7c4SDmitry Torokhov 				return -EFAULT;
3573a51f7c4SDmitry Torokhov 	} else {
3583a51f7c4SDmitry Torokhov 		len = NBITS(maxbit) * sizeof(long);
3593a51f7c4SDmitry Torokhov 		if (len > maxlen)
3603a51f7c4SDmitry Torokhov 			len = maxlen;
3613a51f7c4SDmitry Torokhov 
3623a51f7c4SDmitry Torokhov 		if (copy_to_user(p, bits, len))
3633a51f7c4SDmitry Torokhov 			return -EFAULT;
3643a51f7c4SDmitry Torokhov 	}
3653a51f7c4SDmitry Torokhov 
3663a51f7c4SDmitry Torokhov 	return len;
3673a51f7c4SDmitry Torokhov }
3683a51f7c4SDmitry Torokhov #else
3693a51f7c4SDmitry Torokhov static int bits_to_user(unsigned long *bits, unsigned int maxbit,
3703a51f7c4SDmitry Torokhov 			unsigned int maxlen, void __user *p, int compat)
3713a51f7c4SDmitry Torokhov {
3723a51f7c4SDmitry Torokhov 	int len = compat ?
3733a51f7c4SDmitry Torokhov 			NBITS_COMPAT(maxbit) * sizeof(compat_long_t) :
3743a51f7c4SDmitry Torokhov 			NBITS(maxbit) * sizeof(long);
3753a51f7c4SDmitry Torokhov 
3763a51f7c4SDmitry Torokhov 	if (len > maxlen)
3773a51f7c4SDmitry Torokhov 		len = maxlen;
3783a51f7c4SDmitry Torokhov 
3793a51f7c4SDmitry Torokhov 	return copy_to_user(p, bits, len) ? -EFAULT : len;
3803a51f7c4SDmitry Torokhov }
3813a51f7c4SDmitry Torokhov #endif /* __BIG_ENDIAN */
3823a51f7c4SDmitry Torokhov 
3833a51f7c4SDmitry Torokhov #else
3843a51f7c4SDmitry Torokhov 
3853a51f7c4SDmitry Torokhov static int bits_to_user(unsigned long *bits, unsigned int maxbit,
3863a51f7c4SDmitry Torokhov 			unsigned int maxlen, void __user *p, int compat)
3873a51f7c4SDmitry Torokhov {
3883a51f7c4SDmitry Torokhov 	int len = NBITS(maxbit) * sizeof(long);
3893a51f7c4SDmitry Torokhov 
3903a51f7c4SDmitry Torokhov 	if (len > maxlen)
3913a51f7c4SDmitry Torokhov 		len = maxlen;
3923a51f7c4SDmitry Torokhov 
3933a51f7c4SDmitry Torokhov 	return copy_to_user(p, bits, len) ? -EFAULT : len;
3943a51f7c4SDmitry Torokhov }
3953a51f7c4SDmitry Torokhov 
3963a51f7c4SDmitry Torokhov #endif /* CONFIG_COMPAT */
3973a51f7c4SDmitry Torokhov 
3983a51f7c4SDmitry Torokhov static int str_to_user(const char *str, unsigned int maxlen, void __user *p)
3993a51f7c4SDmitry Torokhov {
4003a51f7c4SDmitry Torokhov 	int len;
4013a51f7c4SDmitry Torokhov 
4023a51f7c4SDmitry Torokhov 	if (!str)
4033a51f7c4SDmitry Torokhov 		return -ENOENT;
4043a51f7c4SDmitry Torokhov 
4053a51f7c4SDmitry Torokhov 	len = strlen(str) + 1;
4063a51f7c4SDmitry Torokhov 	if (len > maxlen)
4073a51f7c4SDmitry Torokhov 		len = maxlen;
4083a51f7c4SDmitry Torokhov 
4093a51f7c4SDmitry Torokhov 	return copy_to_user(p, str, len) ? -EFAULT : len;
4103a51f7c4SDmitry Torokhov }
4113a51f7c4SDmitry Torokhov 
4123a51f7c4SDmitry Torokhov static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
4133a51f7c4SDmitry Torokhov 				void __user *p, int compat_mode)
4141da177e4SLinus Torvalds {
415d0ffb9beSDmitry Torokhov 	struct evdev_client *client = file->private_data;
416d0ffb9beSDmitry Torokhov 	struct evdev *evdev = client->evdev;
4171da177e4SLinus Torvalds 	struct input_dev *dev = evdev->handle.dev;
4181da177e4SLinus Torvalds 	struct input_absinfo abs;
419509ca1a9SAnssi Hannula 	struct ff_effect effect;
4203a51f7c4SDmitry Torokhov 	int __user *ip = (int __user *)p;
4211da177e4SLinus Torvalds 	int i, t, u, v;
422509ca1a9SAnssi Hannula 	int error;
4231da177e4SLinus Torvalds 
4243a51f7c4SDmitry Torokhov 	if (!evdev->exist)
4253a51f7c4SDmitry Torokhov 		return -ENODEV;
4261da177e4SLinus Torvalds 
4271da177e4SLinus Torvalds 	switch (cmd) {
4281da177e4SLinus Torvalds 
4291da177e4SLinus Torvalds 		case EVIOCGVERSION:
4301da177e4SLinus Torvalds 			return put_user(EV_VERSION, ip);
4311da177e4SLinus Torvalds 
4321da177e4SLinus Torvalds 		case EVIOCGID:
4333a51f7c4SDmitry Torokhov 			if (copy_to_user(p, &dev->id, sizeof(struct input_id)))
4343a51f7c4SDmitry Torokhov 				return -EFAULT;
43508791e5cSDmitry Torokhov 			return 0;
43608791e5cSDmitry Torokhov 
43708791e5cSDmitry Torokhov 		case EVIOCGREP:
43808791e5cSDmitry Torokhov 			if (!test_bit(EV_REP, dev->evbit))
43908791e5cSDmitry Torokhov 				return -ENOSYS;
44008791e5cSDmitry Torokhov 			if (put_user(dev->rep[REP_DELAY], ip))
44108791e5cSDmitry Torokhov 				return -EFAULT;
44208791e5cSDmitry Torokhov 			if (put_user(dev->rep[REP_PERIOD], ip + 1))
44308791e5cSDmitry Torokhov 				return -EFAULT;
44408791e5cSDmitry Torokhov 			return 0;
44508791e5cSDmitry Torokhov 
44608791e5cSDmitry Torokhov 		case EVIOCSREP:
44708791e5cSDmitry Torokhov 			if (!test_bit(EV_REP, dev->evbit))
44808791e5cSDmitry Torokhov 				return -ENOSYS;
44908791e5cSDmitry Torokhov 			if (get_user(u, ip))
45008791e5cSDmitry Torokhov 				return -EFAULT;
45108791e5cSDmitry Torokhov 			if (get_user(v, ip + 1))
45208791e5cSDmitry Torokhov 				return -EFAULT;
45308791e5cSDmitry Torokhov 
4540e739d28SDmitry Torokhov 			input_inject_event(&evdev->handle, EV_REP, REP_DELAY, u);
4550e739d28SDmitry Torokhov 			input_inject_event(&evdev->handle, EV_REP, REP_PERIOD, v);
4563a51f7c4SDmitry Torokhov 
4573a51f7c4SDmitry Torokhov 			return 0;
4581da177e4SLinus Torvalds 
4591da177e4SLinus Torvalds 		case EVIOCGKEYCODE:
4603a51f7c4SDmitry Torokhov 			if (get_user(t, ip))
4613a51f7c4SDmitry Torokhov 				return -EFAULT;
462c8e4c772SMarvin Raaijmakers 
463c8e4c772SMarvin Raaijmakers 			error = dev->getkeycode(dev, t, &v);
464c8e4c772SMarvin Raaijmakers 			if (error)
465c8e4c772SMarvin Raaijmakers 				return error;
466c8e4c772SMarvin Raaijmakers 
467c8e4c772SMarvin Raaijmakers 			if (put_user(v, ip + 1))
4683a51f7c4SDmitry Torokhov 				return -EFAULT;
469c8e4c772SMarvin Raaijmakers 
4701da177e4SLinus Torvalds 			return 0;
4711da177e4SLinus Torvalds 
4721da177e4SLinus Torvalds 		case EVIOCSKEYCODE:
473c8e4c772SMarvin Raaijmakers 			if (get_user(t, ip) || get_user(v, ip + 1))
4743a51f7c4SDmitry Torokhov 				return -EFAULT;
4753a51f7c4SDmitry Torokhov 
476c8e4c772SMarvin Raaijmakers 			return dev->setkeycode(dev, t, v);
4771da177e4SLinus Torvalds 
4781da177e4SLinus Torvalds 		case EVIOCSFF:
4791da177e4SLinus Torvalds 			if (copy_from_user(&effect, p, sizeof(effect)))
4801da177e4SLinus Torvalds 				return -EFAULT;
481509ca1a9SAnssi Hannula 
482509ca1a9SAnssi Hannula 			error = input_ff_upload(dev, &effect, file);
483509ca1a9SAnssi Hannula 
4843a51f7c4SDmitry Torokhov 			if (put_user(effect.id, &(((struct ff_effect __user *)p)->id)))
4851da177e4SLinus Torvalds 				return -EFAULT;
486509ca1a9SAnssi Hannula 
487509ca1a9SAnssi Hannula 			return error;
4881da177e4SLinus Torvalds 
4891da177e4SLinus Torvalds 		case EVIOCRMFF:
490509ca1a9SAnssi Hannula 			return input_ff_erase(dev, (int)(unsigned long) p, file);
4911da177e4SLinus Torvalds 
4921da177e4SLinus Torvalds 		case EVIOCGEFFECTS:
493509ca1a9SAnssi Hannula 			i = test_bit(EV_FF, dev->evbit) ? dev->ff->max_effects : 0;
494509ca1a9SAnssi Hannula 			if (put_user(i, ip))
4951da177e4SLinus Torvalds 				return -EFAULT;
4961da177e4SLinus Torvalds 			return 0;
4971da177e4SLinus Torvalds 
4981da177e4SLinus Torvalds 		case EVIOCGRAB:
4993a51f7c4SDmitry Torokhov 			if (p) {
5001da177e4SLinus Torvalds 				if (evdev->grab)
5011da177e4SLinus Torvalds 					return -EBUSY;
5021da177e4SLinus Torvalds 				if (input_grab_device(&evdev->handle))
5031da177e4SLinus Torvalds 					return -EBUSY;
504d0ffb9beSDmitry Torokhov 				evdev->grab = client;
5051da177e4SLinus Torvalds 				return 0;
5061da177e4SLinus Torvalds 			} else {
507d0ffb9beSDmitry Torokhov 				if (evdev->grab != client)
5081da177e4SLinus Torvalds 					return -EINVAL;
5091da177e4SLinus Torvalds 				input_release_device(&evdev->handle);
5101da177e4SLinus Torvalds 				evdev->grab = NULL;
5111da177e4SLinus Torvalds 				return 0;
5121da177e4SLinus Torvalds 			}
5131da177e4SLinus Torvalds 
5141da177e4SLinus Torvalds 		default:
5151da177e4SLinus Torvalds 
51641e979f8SVojtech Pavlik 			if (_IOC_TYPE(cmd) != 'E')
5171da177e4SLinus Torvalds 				return -EINVAL;
5181da177e4SLinus Torvalds 
51941e979f8SVojtech Pavlik 			if (_IOC_DIR(cmd) == _IOC_READ) {
52041e979f8SVojtech Pavlik 
5211da177e4SLinus Torvalds 				if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) {
5221da177e4SLinus Torvalds 
523ce305b6aSDmitry Torokhov 					unsigned long *bits;
5241da177e4SLinus Torvalds 					int len;
5251da177e4SLinus Torvalds 
5261da177e4SLinus Torvalds 					switch (_IOC_NR(cmd) & EV_MAX) {
5271da177e4SLinus Torvalds 						case      0: bits = dev->evbit;  len = EV_MAX;  break;
5281da177e4SLinus Torvalds 						case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
5291da177e4SLinus Torvalds 						case EV_REL: bits = dev->relbit; len = REL_MAX; break;
5301da177e4SLinus Torvalds 						case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
5311da177e4SLinus Torvalds 						case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break;
5321da177e4SLinus Torvalds 						case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
5331da177e4SLinus Torvalds 						case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
5341da177e4SLinus Torvalds 						case EV_FF:  bits = dev->ffbit;  len = FF_MAX;  break;
53531581066SRichard Purdie 						case EV_SW:  bits = dev->swbit;  len = SW_MAX;  break;
5361da177e4SLinus Torvalds 						default: return -EINVAL;
5371da177e4SLinus Torvalds 					}
5383a51f7c4SDmitry Torokhov 					return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode);
53952658bb6SJuergen Kreileder 				}
54052658bb6SJuergen Kreileder 
54141e979f8SVojtech Pavlik 				if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0)))
5423a51f7c4SDmitry Torokhov 					return bits_to_user(dev->key, KEY_MAX, _IOC_SIZE(cmd),
5433a51f7c4SDmitry Torokhov 							    p, compat_mode);
54452658bb6SJuergen Kreileder 
54541e979f8SVojtech Pavlik 				if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0)))
5463a51f7c4SDmitry Torokhov 					return bits_to_user(dev->led, LED_MAX, _IOC_SIZE(cmd),
5473a51f7c4SDmitry Torokhov 							    p, compat_mode);
54852658bb6SJuergen Kreileder 
54941e979f8SVojtech Pavlik 				if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0)))
5503a51f7c4SDmitry Torokhov 					return bits_to_user(dev->snd, SND_MAX, _IOC_SIZE(cmd),
5513a51f7c4SDmitry Torokhov 							    p, compat_mode);
55252658bb6SJuergen Kreileder 
5537972720aSDmitry Torokhov 				if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0)))
5543a51f7c4SDmitry Torokhov 					return bits_to_user(dev->sw, SW_MAX, _IOC_SIZE(cmd),
5553a51f7c4SDmitry Torokhov 							    p, compat_mode);
5567972720aSDmitry Torokhov 
5573a51f7c4SDmitry Torokhov 				if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0)))
5583a51f7c4SDmitry Torokhov 					return str_to_user(dev->name, _IOC_SIZE(cmd), p);
55952658bb6SJuergen Kreileder 
5603a51f7c4SDmitry Torokhov 				if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0)))
5613a51f7c4SDmitry Torokhov 					return str_to_user(dev->phys, _IOC_SIZE(cmd), p);
56252658bb6SJuergen Kreileder 
5633a51f7c4SDmitry Torokhov 				if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0)))
5643a51f7c4SDmitry Torokhov 					return str_to_user(dev->uniq, _IOC_SIZE(cmd), p);
56552658bb6SJuergen Kreileder 
56652658bb6SJuergen Kreileder 				if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
56752658bb6SJuergen Kreileder 
568ce305b6aSDmitry Torokhov 					t = _IOC_NR(cmd) & ABS_MAX;
56952658bb6SJuergen Kreileder 
57052658bb6SJuergen Kreileder 					abs.value = dev->abs[t];
57152658bb6SJuergen Kreileder 					abs.minimum = dev->absmin[t];
57252658bb6SJuergen Kreileder 					abs.maximum = dev->absmax[t];
57352658bb6SJuergen Kreileder 					abs.fuzz = dev->absfuzz[t];
57452658bb6SJuergen Kreileder 					abs.flat = dev->absflat[t];
57552658bb6SJuergen Kreileder 
57652658bb6SJuergen Kreileder 					if (copy_to_user(p, &abs, sizeof(struct input_absinfo)))
57752658bb6SJuergen Kreileder 						return -EFAULT;
57852658bb6SJuergen Kreileder 
57952658bb6SJuergen Kreileder 					return 0;
58052658bb6SJuergen Kreileder 				}
5813a51f7c4SDmitry Torokhov 
58241e979f8SVojtech Pavlik 			}
58341e979f8SVojtech Pavlik 
58441e979f8SVojtech Pavlik 			if (_IOC_DIR(cmd) == _IOC_WRITE) {
58552658bb6SJuergen Kreileder 
58652658bb6SJuergen Kreileder 				if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
58752658bb6SJuergen Kreileder 
588ce305b6aSDmitry Torokhov 					t = _IOC_NR(cmd) & ABS_MAX;
58952658bb6SJuergen Kreileder 
59052658bb6SJuergen Kreileder 					if (copy_from_user(&abs, p, sizeof(struct input_absinfo)))
59152658bb6SJuergen Kreileder 						return -EFAULT;
59252658bb6SJuergen Kreileder 
59352658bb6SJuergen Kreileder 					dev->abs[t] = abs.value;
59452658bb6SJuergen Kreileder 					dev->absmin[t] = abs.minimum;
59552658bb6SJuergen Kreileder 					dev->absmax[t] = abs.maximum;
59652658bb6SJuergen Kreileder 					dev->absfuzz[t] = abs.fuzz;
59752658bb6SJuergen Kreileder 					dev->absflat[t] = abs.flat;
59852658bb6SJuergen Kreileder 
59952658bb6SJuergen Kreileder 					return 0;
60052658bb6SJuergen Kreileder 				}
60152658bb6SJuergen Kreileder 			}
60241e979f8SVojtech Pavlik 	}
60352658bb6SJuergen Kreileder 	return -EINVAL;
60452658bb6SJuergen Kreileder }
6053a51f7c4SDmitry Torokhov 
6063a51f7c4SDmitry Torokhov static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
6073a51f7c4SDmitry Torokhov {
6083a51f7c4SDmitry Torokhov 	return evdev_ioctl_handler(file, cmd, (void __user *)arg, 0);
6093a51f7c4SDmitry Torokhov }
6103a51f7c4SDmitry Torokhov 
6113a51f7c4SDmitry Torokhov #ifdef CONFIG_COMPAT
6123a51f7c4SDmitry Torokhov static long evdev_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
6133a51f7c4SDmitry Torokhov {
6143a51f7c4SDmitry Torokhov 	return evdev_ioctl_handler(file, cmd, compat_ptr(arg), 1);
6153a51f7c4SDmitry Torokhov }
61652658bb6SJuergen Kreileder #endif
61752658bb6SJuergen Kreileder 
61866e66118SDmitry Torokhov static const struct file_operations evdev_fops = {
6191da177e4SLinus Torvalds 	.owner =	THIS_MODULE,
6201da177e4SLinus Torvalds 	.read =		evdev_read,
6211da177e4SLinus Torvalds 	.write =	evdev_write,
6221da177e4SLinus Torvalds 	.poll =		evdev_poll,
6231da177e4SLinus Torvalds 	.open =		evdev_open,
6241da177e4SLinus Torvalds 	.release =	evdev_release,
62552658bb6SJuergen Kreileder 	.unlocked_ioctl = evdev_ioctl,
62652658bb6SJuergen Kreileder #ifdef CONFIG_COMPAT
62752658bb6SJuergen Kreileder 	.compat_ioctl =	evdev_ioctl_compat,
62852658bb6SJuergen Kreileder #endif
6291da177e4SLinus Torvalds 	.fasync =	evdev_fasync,
6301da177e4SLinus Torvalds 	.flush =	evdev_flush
6311da177e4SLinus Torvalds };
6321da177e4SLinus Torvalds 
6335b2a0826SDmitry Torokhov static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
63466e66118SDmitry Torokhov 			 const struct input_device_id *id)
6351da177e4SLinus Torvalds {
6361da177e4SLinus Torvalds 	struct evdev *evdev;
6371da177e4SLinus Torvalds 	int minor;
6385b2a0826SDmitry Torokhov 	int error;
6391da177e4SLinus Torvalds 
6401da177e4SLinus Torvalds 	for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++);
6411da177e4SLinus Torvalds 	if (minor == EVDEV_MINORS) {
6421da177e4SLinus Torvalds 		printk(KERN_ERR "evdev: no more free evdev devices\n");
6435b2a0826SDmitry Torokhov 		return -ENFILE;
6441da177e4SLinus Torvalds 	}
6451da177e4SLinus Torvalds 
6465b2a0826SDmitry Torokhov 	evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);
6475b2a0826SDmitry Torokhov 	if (!evdev)
6485b2a0826SDmitry Torokhov 		return -ENOMEM;
6491da177e4SLinus Torvalds 
650d0ffb9beSDmitry Torokhov 	INIT_LIST_HEAD(&evdev->client_list);
6511da177e4SLinus Torvalds 	init_waitqueue_head(&evdev->wait);
6521da177e4SLinus Torvalds 
6531da177e4SLinus Torvalds 	evdev->exist = 1;
6541da177e4SLinus Torvalds 	evdev->minor = minor;
6551da177e4SLinus Torvalds 	evdev->handle.dev = dev;
6561da177e4SLinus Torvalds 	evdev->handle.name = evdev->name;
6571da177e4SLinus Torvalds 	evdev->handle.handler = handler;
6581da177e4SLinus Torvalds 	evdev->handle.private = evdev;
6599657d75cSDmitry Torokhov 	snprintf(evdev->name, sizeof(evdev->name), "event%d", minor);
6609657d75cSDmitry Torokhov 
6619657d75cSDmitry Torokhov 	snprintf(evdev->dev.bus_id, sizeof(evdev->dev.bus_id),
6629657d75cSDmitry Torokhov 		 "event%d", minor);
6639657d75cSDmitry Torokhov 	evdev->dev.class = &input_class;
6649657d75cSDmitry Torokhov 	evdev->dev.parent = &dev->dev;
6659657d75cSDmitry Torokhov 	evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);
6669657d75cSDmitry Torokhov 	evdev->dev.release = evdev_free;
6679657d75cSDmitry Torokhov 	device_initialize(&evdev->dev);
6681da177e4SLinus Torvalds 
6691da177e4SLinus Torvalds 	evdev_table[minor] = evdev;
6701da177e4SLinus Torvalds 
6719657d75cSDmitry Torokhov 	error = device_add(&evdev->dev);
6725b2a0826SDmitry Torokhov 	if (error)
6739657d75cSDmitry Torokhov 		goto err_free_evdev;
6741da177e4SLinus Torvalds 
6755b2a0826SDmitry Torokhov 	error = input_register_handle(&evdev->handle);
6765b2a0826SDmitry Torokhov 	if (error)
6779657d75cSDmitry Torokhov 		goto err_delete_evdev;
6785b2a0826SDmitry Torokhov 
6795b2a0826SDmitry Torokhov 	return 0;
6805b2a0826SDmitry Torokhov 
6819657d75cSDmitry Torokhov  err_delete_evdev:
6829657d75cSDmitry Torokhov 	device_del(&evdev->dev);
6835b2a0826SDmitry Torokhov  err_free_evdev:
6849657d75cSDmitry Torokhov 	put_device(&evdev->dev);
6855b2a0826SDmitry Torokhov 	return error;
6861da177e4SLinus Torvalds }
6871da177e4SLinus Torvalds 
6881da177e4SLinus Torvalds static void evdev_disconnect(struct input_handle *handle)
6891da177e4SLinus Torvalds {
6901da177e4SLinus Torvalds 	struct evdev *evdev = handle->private;
691d0ffb9beSDmitry Torokhov 	struct evdev_client *client;
6921da177e4SLinus Torvalds 
6935b2a0826SDmitry Torokhov 	input_unregister_handle(handle);
6949657d75cSDmitry Torokhov 	device_del(&evdev->dev);
6951da177e4SLinus Torvalds 
6961da177e4SLinus Torvalds 	evdev->exist = 0;
6971da177e4SLinus Torvalds 
6981da177e4SLinus Torvalds 	if (evdev->open) {
699509ca1a9SAnssi Hannula 		input_flush_device(handle, NULL);
7001da177e4SLinus Torvalds 		input_close_device(handle);
701d0ffb9beSDmitry Torokhov 		list_for_each_entry(client, &evdev->client_list, node)
702d0ffb9beSDmitry Torokhov 			kill_fasync(&client->fasync, SIGIO, POLL_HUP);
7031dfa2812SDmitry Torokhov 		wake_up_interruptible(&evdev->wait);
7049657d75cSDmitry Torokhov 	}
7059657d75cSDmitry Torokhov 
7069657d75cSDmitry Torokhov 	put_device(&evdev->dev);
7071da177e4SLinus Torvalds }
7081da177e4SLinus Torvalds 
70966e66118SDmitry Torokhov static const struct input_device_id evdev_ids[] = {
7101da177e4SLinus Torvalds 	{ .driver_info = 1 },	/* Matches all devices */
7111da177e4SLinus Torvalds 	{ },			/* Terminating zero entry */
7121da177e4SLinus Torvalds };
7131da177e4SLinus Torvalds 
7141da177e4SLinus Torvalds MODULE_DEVICE_TABLE(input, evdev_ids);
7151da177e4SLinus Torvalds 
7161da177e4SLinus Torvalds static struct input_handler evdev_handler = {
7171da177e4SLinus Torvalds 	.event =	evdev_event,
7181da177e4SLinus Torvalds 	.connect =	evdev_connect,
7191da177e4SLinus Torvalds 	.disconnect =	evdev_disconnect,
7201da177e4SLinus Torvalds 	.fops =		&evdev_fops,
7211da177e4SLinus Torvalds 	.minor =	EVDEV_MINOR_BASE,
7221da177e4SLinus Torvalds 	.name =		"evdev",
7231da177e4SLinus Torvalds 	.id_table =	evdev_ids,
7241da177e4SLinus Torvalds };
7251da177e4SLinus Torvalds 
7261da177e4SLinus Torvalds static int __init evdev_init(void)
7271da177e4SLinus Torvalds {
7284263cf0fSDmitry Torokhov 	return input_register_handler(&evdev_handler);
7291da177e4SLinus Torvalds }
7301da177e4SLinus Torvalds 
7311da177e4SLinus Torvalds static void __exit evdev_exit(void)
7321da177e4SLinus Torvalds {
7331da177e4SLinus Torvalds 	input_unregister_handler(&evdev_handler);
7341da177e4SLinus Torvalds }
7351da177e4SLinus Torvalds 
7361da177e4SLinus Torvalds module_init(evdev_init);
7371da177e4SLinus Torvalds module_exit(evdev_exit);
7381da177e4SLinus Torvalds 
7391da177e4SLinus Torvalds MODULE_AUTHOR("Vojtech Pavlik <[email protected]>");
7401da177e4SLinus Torvalds MODULE_DESCRIPTION("Input driver event char devices");
7411da177e4SLinus Torvalds MODULE_LICENSE("GPL");
742