Blame view

drivers/input/evdev.c 22.3 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
  /*
   * Event char devices, giving access to raw input device events.
   *
   * Copyright (c) 1999-2002 Vojtech Pavlik
   *
   * This program is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 as published by
   * the Free Software Foundation.
   */
da0c49011   Joe Perches   Input: use pr_fmt...
10
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
12
  #define EVDEV_MINOR_BASE	64
  #define EVDEV_MINORS		32
63a6404d8   Henrik Rydberg   Input: evdev - us...
13
14
  #define EVDEV_MIN_BUFFER_SIZE	64U
  #define EVDEV_BUF_PACKETS	8
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
16
  
  #include <linux/poll.h>
a99bbaf5e   Alexey Dobriyan   headers: remove s...
17
  #include <linux/sched.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
19
20
21
22
  #include <linux/slab.h>
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/input.h>
  #include <linux/major.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
  #include <linux/device.h>
2d56f3a32   Philip Langdale   Input: refactor e...
24
  #include "input-compat.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
26
  
  struct evdev {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
  	int open;
  	int minor;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
30
  	struct input_handle handle;
  	wait_queue_head_t wait;
2be852792   Arnd Bergmann   input: __rcu anno...
31
  	struct evdev_client __rcu *grab;
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
32
  	struct list_head client_list;
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
33
34
  	spinlock_t client_lock; /* protects client_list */
  	struct mutex mutex;
9657d75c5   Dmitry Torokhov   Input: convert fr...
35
  	struct device dev;
20da92de8   Dmitry Torokhov   Input: change inp...
36
  	bool exist;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
  };
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
38
  struct evdev_client {
9fb0f14e3   Jeff Brown   Input: evdev - in...
39
40
  	unsigned int head;
  	unsigned int tail;
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
41
  	spinlock_t buffer_lock; /* protects access to buffer, head and tail */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
44
  	struct fasync_struct *fasync;
  	struct evdev *evdev;
  	struct list_head node;
9fb0f14e3   Jeff Brown   Input: evdev - in...
45
  	unsigned int bufsize;
b58f7086d   Henrik Rydberg   Input: evdev - co...
46
  	struct input_event buffer[];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
48
49
  };
  
  static struct evdev *evdev_table[EVDEV_MINORS];
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
50
  static DEFINE_MUTEX(evdev_table_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51

6addb1d6d   Dmitry Torokhov   Input: evdev - im...
52
53
54
  static void evdev_pass_event(struct evdev_client *client,
  			     struct input_event *event)
  {
9fb0f14e3   Jeff Brown   Input: evdev - in...
55
  	/* Interrupts are disabled, just acquire the lock. */
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
56
  	spin_lock(&client->buffer_lock);
9fb0f14e3   Jeff Brown   Input: evdev - in...
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
  
  	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;
  	}
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
73
  	spin_unlock(&client->buffer_lock);
30a589fde   Adam Jackson   Input: evdev - be...
74
75
  	if (event->type == EV_SYN)
  		kill_fasync(&client->fasync, SIGIO, POLL_IN);
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
76
77
78
  }
  
  /*
82ba56c27   Dmitry Torokhov   Input: use full R...
79
   * Pass incoming event to all connected clients.
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
80
81
82
   */
  static void evdev_event(struct input_handle *handle,
  			unsigned int type, unsigned int code, int value)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83
84
  {
  	struct evdev *evdev = handle->private;
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
85
  	struct evdev_client *client;
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
86
  	struct input_event event;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
87

6addb1d6d   Dmitry Torokhov   Input: evdev - im...
88
89
90
91
  	do_gettimeofday(&event.time);
  	event.type = type;
  	event.code = code;
  	event.value = value;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92

82ba56c27   Dmitry Torokhov   Input: use full R...
93
  	rcu_read_lock();
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
94
95
96
97
98
99
  	client = rcu_dereference(evdev->grab);
  	if (client)
  		evdev_pass_event(client, &event);
  	else
  		list_for_each_entry_rcu(client, &evdev->client_list, node)
  			evdev_pass_event(client, &event);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100

82ba56c27   Dmitry Torokhov   Input: use full R...
101
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
103
104
105
106
  	wake_up_interruptible(&evdev->wait);
  }
  
  static int evdev_fasync(int fd, struct file *file, int on)
  {
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
107
  	struct evdev_client *client = file->private_data;
1e0afb288   Dmitry Torokhov   Input: fix format...
108

60aa49243   Jonathan Corbet   Rationalize fasyn...
109
  	return fasync_helper(fd, file, on, &client->fasync);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
  }
1e0afb288   Dmitry Torokhov   Input: fix format...
111
  static int evdev_flush(struct file *file, fl_owner_t id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
  {
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
113
114
  	struct evdev_client *client = file->private_data;
  	struct evdev *evdev = client->evdev;
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
115
116
117
118
119
  	int retval;
  
  	retval = mutex_lock_interruptible(&evdev->mutex);
  	if (retval)
  		return retval;
1e0afb288   Dmitry Torokhov   Input: fix format...
120

d0ffb9be8   Dmitry Torokhov   Input: handlers -...
121
  	if (!evdev->exist)
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
122
123
124
  		retval = -ENODEV;
  	else
  		retval = input_flush_device(&evdev->handle, file);
1e0afb288   Dmitry Torokhov   Input: fix format...
125

6addb1d6d   Dmitry Torokhov   Input: evdev - im...
126
127
  	mutex_unlock(&evdev->mutex);
  	return retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128
  }
9657d75c5   Dmitry Torokhov   Input: convert fr...
129
  static void evdev_free(struct device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130
  {
9657d75c5   Dmitry Torokhov   Input: convert fr...
131
  	struct evdev *evdev = container_of(dev, struct evdev, dev);
a7097ff89   Dmitry Torokhov   Input: make sure ...
132
  	input_put_device(evdev->handle.dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
133
134
  	kfree(evdev);
  }
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
  /*
   * Grabs an event device (along with underlying input device).
   * This function is called with evdev->mutex taken.
   */
  static int evdev_grab(struct evdev *evdev, struct evdev_client *client)
  {
  	int error;
  
  	if (evdev->grab)
  		return -EBUSY;
  
  	error = input_grab_device(&evdev->handle);
  	if (error)
  		return error;
  
  	rcu_assign_pointer(evdev->grab, client);
82ba56c27   Dmitry Torokhov   Input: use full R...
151
  	synchronize_rcu();
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
152
153
154
155
156
157
158
159
160
161
  
  	return 0;
  }
  
  static int evdev_ungrab(struct evdev *evdev, struct evdev_client *client)
  {
  	if (evdev->grab != client)
  		return  -EINVAL;
  
  	rcu_assign_pointer(evdev->grab, NULL);
82ba56c27   Dmitry Torokhov   Input: use full R...
162
  	synchronize_rcu();
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
163
164
165
166
167
168
169
170
171
172
173
  	input_release_device(&evdev->handle);
  
  	return 0;
  }
  
  static void evdev_attach_client(struct evdev *evdev,
  				struct evdev_client *client)
  {
  	spin_lock(&evdev->client_lock);
  	list_add_tail_rcu(&client->node, &evdev->client_list);
  	spin_unlock(&evdev->client_lock);
82ba56c27   Dmitry Torokhov   Input: use full R...
174
  	synchronize_rcu();
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
175
176
177
178
179
180
181
182
  }
  
  static void evdev_detach_client(struct evdev *evdev,
  				struct evdev_client *client)
  {
  	spin_lock(&evdev->client_lock);
  	list_del_rcu(&client->node);
  	spin_unlock(&evdev->client_lock);
82ba56c27   Dmitry Torokhov   Input: use full R...
183
  	synchronize_rcu();
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
184
185
186
187
188
189
190
191
192
193
194
195
  }
  
  static int evdev_open_device(struct evdev *evdev)
  {
  	int retval;
  
  	retval = mutex_lock_interruptible(&evdev->mutex);
  	if (retval)
  		return retval;
  
  	if (!evdev->exist)
  		retval = -ENODEV;
064450140   Oliver Neukum   Input: fix open c...
196
  	else if (!evdev->open++) {
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
197
  		retval = input_open_device(&evdev->handle);
064450140   Oliver Neukum   Input: fix open c...
198
199
200
  		if (retval)
  			evdev->open--;
  	}
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
  
  	mutex_unlock(&evdev->mutex);
  	return retval;
  }
  
  static void evdev_close_device(struct evdev *evdev)
  {
  	mutex_lock(&evdev->mutex);
  
  	if (evdev->exist && !--evdev->open)
  		input_close_device(&evdev->handle);
  
  	mutex_unlock(&evdev->mutex);
  }
  
  /*
   * Wake up users waiting for IO so they can disconnect from
   * dead device.
   */
  static void evdev_hangup(struct evdev *evdev)
  {
  	struct evdev_client *client;
  
  	spin_lock(&evdev->client_lock);
  	list_for_each_entry(client, &evdev->client_list, node)
  		kill_fasync(&client->fasync, SIGIO, POLL_HUP);
  	spin_unlock(&evdev->client_lock);
  
  	wake_up_interruptible(&evdev->wait);
  }
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
231
  static int evdev_release(struct inode *inode, struct file *file)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232
  {
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
233
234
  	struct evdev_client *client = file->private_data;
  	struct evdev *evdev = client->evdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235

6addb1d6d   Dmitry Torokhov   Input: evdev - im...
236
237
238
239
  	mutex_lock(&evdev->mutex);
  	if (evdev->grab == client)
  		evdev_ungrab(evdev, client);
  	mutex_unlock(&evdev->mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240

6addb1d6d   Dmitry Torokhov   Input: evdev - im...
241
  	evdev_detach_client(evdev, client);
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
242
  	kfree(client);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
243

6addb1d6d   Dmitry Torokhov   Input: evdev - im...
244
  	evdev_close_device(evdev);
9657d75c5   Dmitry Torokhov   Input: convert fr...
245
  	put_device(&evdev->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
246

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
248
  	return 0;
  }
b58f7086d   Henrik Rydberg   Input: evdev - co...
249
250
  static unsigned int evdev_compute_buffer_size(struct input_dev *dev)
  {
63a6404d8   Henrik Rydberg   Input: evdev - us...
251
252
253
254
255
  	unsigned int n_events =
  		max(dev->hint_events_per_packet * EVDEV_BUF_PACKETS,
  		    EVDEV_MIN_BUFFER_SIZE);
  
  	return roundup_pow_of_two(n_events);
b58f7086d   Henrik Rydberg   Input: evdev - co...
256
  }
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
257
  static int evdev_open(struct inode *inode, struct file *file)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
258
  {
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
259
  	struct evdev *evdev;
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
260
  	struct evdev_client *client;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261
  	int i = iminor(inode) - EVDEV_MINOR_BASE;
b58f7086d   Henrik Rydberg   Input: evdev - co...
262
  	unsigned int bufsize;
d542ed82f   Dmitry Torokhov   Input: handlers -...
263
  	int error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
264

d0ffb9be8   Dmitry Torokhov   Input: handlers -...
265
  	if (i >= EVDEV_MINORS)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266
  		return -ENODEV;
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
267
268
269
  	error = mutex_lock_interruptible(&evdev_table_mutex);
  	if (error)
  		return error;
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
270
  	evdev = evdev_table[i];
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
271
272
273
  	if (evdev)
  		get_device(&evdev->dev);
  	mutex_unlock(&evdev_table_mutex);
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
274

6addb1d6d   Dmitry Torokhov   Input: evdev - im...
275
  	if (!evdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
  		return -ENODEV;
b58f7086d   Henrik Rydberg   Input: evdev - co...
277
278
279
280
281
  	bufsize = evdev_compute_buffer_size(evdev->handle.dev);
  
  	client = kzalloc(sizeof(struct evdev_client) +
  				bufsize * sizeof(struct input_event),
  			 GFP_KERNEL);
9657d75c5   Dmitry Torokhov   Input: convert fr...
282
283
284
285
  	if (!client) {
  		error = -ENOMEM;
  		goto err_put_evdev;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286

b58f7086d   Henrik Rydberg   Input: evdev - co...
287
  	client->bufsize = bufsize;
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
288
  	spin_lock_init(&client->buffer_lock);
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
289
  	client->evdev = evdev;
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
290
  	evdev_attach_client(evdev, client);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291

6addb1d6d   Dmitry Torokhov   Input: evdev - im...
292
293
294
  	error = evdev_open_device(evdev);
  	if (error)
  		goto err_free_client;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295

d0ffb9be8   Dmitry Torokhov   Input: handlers -...
296
  	file->private_data = client;
3d7bbd457   Dmitry Torokhov   Input: mark input...
297
  	nonseekable_open(inode, file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
298
  	return 0;
9657d75c5   Dmitry Torokhov   Input: convert fr...
299
300
  
   err_free_client:
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
301
  	evdev_detach_client(evdev, client);
9657d75c5   Dmitry Torokhov   Input: convert fr...
302
303
304
305
  	kfree(client);
   err_put_evdev:
  	put_device(&evdev->dev);
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306
  }
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
307
308
  static ssize_t evdev_write(struct file *file, const char __user *buffer,
  			   size_t count, loff_t *ppos)
3a51f7c40   Dmitry Torokhov   Input: evdev - co...
309
  {
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
310
311
  	struct evdev_client *client = file->private_data;
  	struct evdev *evdev = client->evdev;
3a51f7c40   Dmitry Torokhov   Input: evdev - co...
312
  	struct input_event event;
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
313
  	int retval;
52658bb68   Juergen Kreileder   Input: Add suppor...
314

439581ec0   Peter Korsgaard   Input: evdev - fi...
315
316
  	if (count < input_event_size())
  		return -EINVAL;
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
317
318
319
320
321
322
323
324
  	retval = mutex_lock_interruptible(&evdev->mutex);
  	if (retval)
  		return retval;
  
  	if (!evdev->exist) {
  		retval = -ENODEV;
  		goto out;
  	}
52658bb68   Juergen Kreileder   Input: Add suppor...
325

439581ec0   Peter Korsgaard   Input: evdev - fi...
326
  	do {
2d56f3a32   Philip Langdale   Input: refactor e...
327
  		if (input_event_from_user(buffer + retval, &event)) {
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
328
329
330
  			retval = -EFAULT;
  			goto out;
  		}
439581ec0   Peter Korsgaard   Input: evdev - fi...
331
  		retval += input_event_size();
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
332
333
334
  
  		input_inject_event(&evdev->handle,
  				   event.type, event.code, event.value);
439581ec0   Peter Korsgaard   Input: evdev - fi...
335
  	} while (retval + input_event_size() <= count);
52658bb68   Juergen Kreileder   Input: Add suppor...
336

6addb1d6d   Dmitry Torokhov   Input: evdev - im...
337
338
   out:
  	mutex_unlock(&evdev->mutex);
52658bb68   Juergen Kreileder   Input: Add suppor...
339
340
  	return retval;
  }
52658bb68   Juergen Kreileder   Input: Add suppor...
341

6addb1d6d   Dmitry Torokhov   Input: evdev - im...
342
343
344
345
346
347
348
349
350
351
  static int evdev_fetch_next_event(struct evdev_client *client,
  				  struct input_event *event)
  {
  	int have_event;
  
  	spin_lock_irq(&client->buffer_lock);
  
  	have_event = client->head != client->tail;
  	if (have_event) {
  		*event = client->buffer[client->tail++];
b58f7086d   Henrik Rydberg   Input: evdev - co...
352
  		client->tail &= client->bufsize - 1;
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
353
354
355
356
357
358
359
360
361
  	}
  
  	spin_unlock_irq(&client->buffer_lock);
  
  	return have_event;
  }
  
  static ssize_t evdev_read(struct file *file, char __user *buffer,
  			  size_t count, loff_t *ppos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
362
  {
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
363
364
  	struct evdev_client *client = file->private_data;
  	struct evdev *evdev = client->evdev;
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
365
  	struct input_event event;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
  	int retval;
2d56f3a32   Philip Langdale   Input: refactor e...
367
  	if (count < input_event_size())
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368
  		return -EINVAL;
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
369
370
  	if (client->head == client->tail && evdev->exist &&
  	    (file->f_flags & O_NONBLOCK))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371
  		return -EAGAIN;
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
372
373
  	retval = wait_event_interruptible(evdev->wait,
  		client->head != client->tail || !evdev->exist);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
375
  	if (retval)
  		return retval;
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
376
  	if (!evdev->exist)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
377
  		return -ENODEV;
2d56f3a32   Philip Langdale   Input: refactor e...
378
  	while (retval + input_event_size() <= count &&
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
379
  	       evdev_fetch_next_event(client, &event)) {
3a51f7c40   Dmitry Torokhov   Input: evdev - co...
380

2d56f3a32   Philip Langdale   Input: refactor e...
381
  		if (input_event_to_user(buffer + retval, &event))
3a51f7c40   Dmitry Torokhov   Input: evdev - co...
382
  			return -EFAULT;
2d56f3a32   Philip Langdale   Input: refactor e...
383
  		retval += input_event_size();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
384
385
386
387
388
389
390
391
  	}
  
  	return retval;
  }
  
  /* No kernel lock - fine */
  static unsigned int evdev_poll(struct file *file, poll_table *wait)
  {
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
392
393
  	struct evdev_client *client = file->private_data;
  	struct evdev *evdev = client->evdev;
c18fb1396   Dmitry Torokhov   Input: evdev - si...
394
  	unsigned int mask;
1e0afb288   Dmitry Torokhov   Input: fix format...
395

d0ffb9be8   Dmitry Torokhov   Input: handlers -...
396
  	poll_wait(file, &evdev->wait, wait);
c18fb1396   Dmitry Torokhov   Input: evdev - si...
397
398
399
400
401
402
  
  	mask = evdev->exist ? POLLOUT | POLLWRNORM : POLLHUP | POLLERR;
  	if (client->head != client->tail)
  		mask |= POLLIN | POLLRDNORM;
  
  	return mask;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
403
  }
3a51f7c40   Dmitry Torokhov   Input: evdev - co...
404
405
406
  #ifdef CONFIG_COMPAT
  
  #define BITS_PER_LONG_COMPAT (sizeof(compat_long_t) * 8)
7b19ada2e   Jiri Slaby   get rid of input ...
407
  #define BITS_TO_LONGS_COMPAT(x) ((((x) - 1) / BITS_PER_LONG_COMPAT) + 1)
3a51f7c40   Dmitry Torokhov   Input: evdev - co...
408
409
410
411
412
413
414
415
  
  #ifdef __BIG_ENDIAN
  static int bits_to_user(unsigned long *bits, unsigned int maxbit,
  			unsigned int maxlen, void __user *p, int compat)
  {
  	int len, i;
  
  	if (compat) {
7b19ada2e   Jiri Slaby   get rid of input ...
416
  		len = BITS_TO_LONGS_COMPAT(maxbit) * sizeof(compat_long_t);
bf61f8d35   Kenichi Nagai   Input: evdev - fi...
417
  		if (len > maxlen)
3a51f7c40   Dmitry Torokhov   Input: evdev - co...
418
419
420
421
422
423
424
425
426
  			len = maxlen;
  
  		for (i = 0; i < len / sizeof(compat_long_t); i++)
  			if (copy_to_user((compat_long_t __user *) p + i,
  					 (compat_long_t *) bits +
  						i + 1 - ((i % 2) << 1),
  					 sizeof(compat_long_t)))
  				return -EFAULT;
  	} else {
7b19ada2e   Jiri Slaby   get rid of input ...
427
  		len = BITS_TO_LONGS(maxbit) * sizeof(long);
3a51f7c40   Dmitry Torokhov   Input: evdev - co...
428
429
430
431
432
433
434
435
436
437
438
439
440
441
  		if (len > maxlen)
  			len = maxlen;
  
  		if (copy_to_user(p, bits, len))
  			return -EFAULT;
  	}
  
  	return len;
  }
  #else
  static int bits_to_user(unsigned long *bits, unsigned int maxbit,
  			unsigned int maxlen, void __user *p, int compat)
  {
  	int len = compat ?
7b19ada2e   Jiri Slaby   get rid of input ...
442
443
  			BITS_TO_LONGS_COMPAT(maxbit) * sizeof(compat_long_t) :
  			BITS_TO_LONGS(maxbit) * sizeof(long);
3a51f7c40   Dmitry Torokhov   Input: evdev - co...
444
445
446
447
448
449
450
451
452
453
454
455
456
  
  	if (len > maxlen)
  		len = maxlen;
  
  	return copy_to_user(p, bits, len) ? -EFAULT : len;
  }
  #endif /* __BIG_ENDIAN */
  
  #else
  
  static int bits_to_user(unsigned long *bits, unsigned int maxbit,
  			unsigned int maxlen, void __user *p, int compat)
  {
7b19ada2e   Jiri Slaby   get rid of input ...
457
  	int len = BITS_TO_LONGS(maxbit) * sizeof(long);
3a51f7c40   Dmitry Torokhov   Input: evdev - co...
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
  
  	if (len > maxlen)
  		len = maxlen;
  
  	return copy_to_user(p, bits, len) ? -EFAULT : len;
  }
  
  #endif /* CONFIG_COMPAT */
  
  static int str_to_user(const char *str, unsigned int maxlen, void __user *p)
  {
  	int len;
  
  	if (!str)
  		return -ENOENT;
  
  	len = strlen(str) + 1;
  	if (len > maxlen)
  		len = maxlen;
  
  	return copy_to_user(p, str, len) ? -EFAULT : len;
  }
f2afa7711   Dmitry Torokhov   Input: paper over...
480
  #define OLD_KEY_MAX	0x1ff
448cd1664   Dmitry Torokhov   Input: evdev - re...
481
482
483
  static int handle_eviocgbit(struct input_dev *dev,
  			    unsigned int type, unsigned int size,
  			    void __user *p, int compat_mode)
5402a7349   Linus Torvalds   Input: evdev - sp...
484
  {
f2afa7711   Dmitry Torokhov   Input: paper over...
485
  	static unsigned long keymax_warn_time;
5402a7349   Linus Torvalds   Input: evdev - sp...
486
487
  	unsigned long *bits;
  	int len;
448cd1664   Dmitry Torokhov   Input: evdev - re...
488
  	switch (type) {
5402a7349   Linus Torvalds   Input: evdev - sp...
489
490
491
492
493
494
495
496
497
498
499
500
  
  	case      0: bits = dev->evbit;  len = EV_MAX;  break;
  	case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
  	case EV_REL: bits = dev->relbit; len = REL_MAX; break;
  	case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
  	case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break;
  	case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
  	case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
  	case EV_FF:  bits = dev->ffbit;  len = FF_MAX;  break;
  	case EV_SW:  bits = dev->swbit;  len = SW_MAX;  break;
  	default: return -EINVAL;
  	}
f2afa7711   Dmitry Torokhov   Input: paper over...
501
502
503
504
505
506
  
  	/*
  	 * 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.
  	 */
448cd1664   Dmitry Torokhov   Input: evdev - re...
507
  	if (type == EV_KEY && size == OLD_KEY_MAX) {
f2afa7711   Dmitry Torokhov   Input: paper over...
508
509
  		len = OLD_KEY_MAX;
  		if (printk_timed_ratelimit(&keymax_warn_time, 10 * 1000))
da0c49011   Joe Perches   Input: use pr_fmt...
510
511
512
513
514
515
  			pr_warning("(EVIOCGBIT): Suspicious buffer size %u, "
  				   "limiting output to %zu bytes. See "
  				   "http://userweb.kernel.org/~dtor/eviocgbit-bug.html
  ",
  				   OLD_KEY_MAX,
  				   BITS_TO_LONGS(OLD_KEY_MAX) * sizeof(long));
f2afa7711   Dmitry Torokhov   Input: paper over...
516
  	}
448cd1664   Dmitry Torokhov   Input: evdev - re...
517
  	return bits_to_user(bits, len, size, p, compat_mode);
5402a7349   Linus Torvalds   Input: evdev - sp...
518
  }
f2afa7711   Dmitry Torokhov   Input: paper over...
519
  #undef OLD_KEY_MAX
5402a7349   Linus Torvalds   Input: evdev - sp...
520

ab4e01921   Dmitry Torokhov   Input: define sep...
521
  static int evdev_handle_get_keycode(struct input_dev *dev, void __user *p)
8613e4c28   Mauro Carvalho Chehab   Input: add suppor...
522
  {
ab4e01921   Dmitry Torokhov   Input: define sep...
523
524
525
526
527
  	struct input_keymap_entry ke = {
  		.len	= sizeof(unsigned int),
  		.flags	= 0,
  	};
  	int __user *ip = (int __user *)p;
8613e4c28   Mauro Carvalho Chehab   Input: add suppor...
528
  	int error;
ab4e01921   Dmitry Torokhov   Input: define sep...
529
530
531
  	/* legacy case */
  	if (copy_from_user(ke.scancode, p, sizeof(unsigned int)))
  		return -EFAULT;
8613e4c28   Mauro Carvalho Chehab   Input: add suppor...
532

ab4e01921   Dmitry Torokhov   Input: define sep...
533
534
535
  	error = input_get_keycode(dev, &ke);
  	if (error)
  		return error;
8613e4c28   Mauro Carvalho Chehab   Input: add suppor...
536

ab4e01921   Dmitry Torokhov   Input: define sep...
537
538
  	if (put_user(ke.keycode, ip + 1))
  		return -EFAULT;
8613e4c28   Mauro Carvalho Chehab   Input: add suppor...
539

ab4e01921   Dmitry Torokhov   Input: define sep...
540
541
  	return 0;
  }
8613e4c28   Mauro Carvalho Chehab   Input: add suppor...
542

ab4e01921   Dmitry Torokhov   Input: define sep...
543
544
545
546
  static int evdev_handle_get_keycode_v2(struct input_dev *dev, void __user *p)
  {
  	struct input_keymap_entry ke;
  	int error;
8613e4c28   Mauro Carvalho Chehab   Input: add suppor...
547

ab4e01921   Dmitry Torokhov   Input: define sep...
548
549
  	if (copy_from_user(&ke, p, sizeof(ke)))
  		return -EFAULT;
8613e4c28   Mauro Carvalho Chehab   Input: add suppor...
550

ab4e01921   Dmitry Torokhov   Input: define sep...
551
552
553
  	error = input_get_keycode(dev, &ke);
  	if (error)
  		return error;
8613e4c28   Mauro Carvalho Chehab   Input: add suppor...
554

ab4e01921   Dmitry Torokhov   Input: define sep...
555
556
  	if (copy_to_user(p, &ke, sizeof(ke)))
  		return -EFAULT;
8613e4c28   Mauro Carvalho Chehab   Input: add suppor...
557

8613e4c28   Mauro Carvalho Chehab   Input: add suppor...
558
559
  	return 0;
  }
ab4e01921   Dmitry Torokhov   Input: define sep...
560
  static int evdev_handle_set_keycode(struct input_dev *dev, void __user *p)
8613e4c28   Mauro Carvalho Chehab   Input: add suppor...
561
  {
ab4e01921   Dmitry Torokhov   Input: define sep...
562
563
564
565
566
  	struct input_keymap_entry ke = {
  		.len	= sizeof(unsigned int),
  		.flags	= 0,
  	};
  	int __user *ip = (int __user *)p;
8613e4c28   Mauro Carvalho Chehab   Input: add suppor...
567

ab4e01921   Dmitry Torokhov   Input: define sep...
568
569
  	if (copy_from_user(ke.scancode, p, sizeof(unsigned int)))
  		return -EFAULT;
8613e4c28   Mauro Carvalho Chehab   Input: add suppor...
570

ab4e01921   Dmitry Torokhov   Input: define sep...
571
572
  	if (get_user(ke.keycode, ip + 1))
  		return -EFAULT;
8613e4c28   Mauro Carvalho Chehab   Input: add suppor...
573

ab4e01921   Dmitry Torokhov   Input: define sep...
574
575
  	return input_set_keycode(dev, &ke);
  }
8613e4c28   Mauro Carvalho Chehab   Input: add suppor...
576

ab4e01921   Dmitry Torokhov   Input: define sep...
577
578
579
  static int evdev_handle_set_keycode_v2(struct input_dev *dev, void __user *p)
  {
  	struct input_keymap_entry ke;
8613e4c28   Mauro Carvalho Chehab   Input: add suppor...
580

ab4e01921   Dmitry Torokhov   Input: define sep...
581
582
  	if (copy_from_user(&ke, p, sizeof(ke)))
  		return -EFAULT;
8613e4c28   Mauro Carvalho Chehab   Input: add suppor...
583

ab4e01921   Dmitry Torokhov   Input: define sep...
584
585
  	if (ke.len > sizeof(ke.scancode))
  		return -EINVAL;
8613e4c28   Mauro Carvalho Chehab   Input: add suppor...
586
587
588
  
  	return input_set_keycode(dev, &ke);
  }
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
589
590
  static long evdev_do_ioctl(struct file *file, unsigned int cmd,
  			   void __user *p, int compat_mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
591
  {
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
592
593
  	struct evdev_client *client = file->private_data;
  	struct evdev *evdev = client->evdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
594
595
  	struct input_dev *dev = evdev->handle.dev;
  	struct input_absinfo abs;
509ca1a93   Anssi Hannula   Input: implement ...
596
  	struct ff_effect effect;
3a51f7c40   Dmitry Torokhov   Input: evdev - co...
597
  	int __user *ip = (int __user *)p;
58b939959   Dmitry Torokhov   Input: scancode i...
598
  	unsigned int i, t, u, v;
448cd1664   Dmitry Torokhov   Input: evdev - re...
599
  	unsigned int size;
509ca1a93   Anssi Hannula   Input: implement ...
600
  	int error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
601

448cd1664   Dmitry Torokhov   Input: evdev - re...
602
  	/* First we check for fixed-length commands */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
603
  	switch (cmd) {
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
604
605
  	case EVIOCGVERSION:
  		return put_user(EV_VERSION, ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
606

6addb1d6d   Dmitry Torokhov   Input: evdev - im...
607
608
609
610
  	case EVIOCGID:
  		if (copy_to_user(p, &dev->id, sizeof(struct input_id)))
  			return -EFAULT;
  		return 0;
08791e5cf   Dmitry Torokhov   Input: ressurect ...
611

6addb1d6d   Dmitry Torokhov   Input: evdev - im...
612
613
614
615
616
617
618
619
  	case EVIOCGREP:
  		if (!test_bit(EV_REP, dev->evbit))
  			return -ENOSYS;
  		if (put_user(dev->rep[REP_DELAY], ip))
  			return -EFAULT;
  		if (put_user(dev->rep[REP_PERIOD], ip + 1))
  			return -EFAULT;
  		return 0;
08791e5cf   Dmitry Torokhov   Input: ressurect ...
620

6addb1d6d   Dmitry Torokhov   Input: evdev - im...
621
622
623
624
625
626
627
  	case EVIOCSREP:
  		if (!test_bit(EV_REP, dev->evbit))
  			return -ENOSYS;
  		if (get_user(u, ip))
  			return -EFAULT;
  		if (get_user(v, ip + 1))
  			return -EFAULT;
08791e5cf   Dmitry Torokhov   Input: ressurect ...
628

6addb1d6d   Dmitry Torokhov   Input: evdev - im...
629
630
  		input_inject_event(&evdev->handle, EV_REP, REP_DELAY, u);
  		input_inject_event(&evdev->handle, EV_REP, REP_PERIOD, v);
3a51f7c40   Dmitry Torokhov   Input: evdev - co...
631

6addb1d6d   Dmitry Torokhov   Input: evdev - im...
632
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
633

6addb1d6d   Dmitry Torokhov   Input: evdev - im...
634
635
  	case EVIOCRMFF:
  		return input_ff_erase(dev, (int)(unsigned long) p, file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
636

6addb1d6d   Dmitry Torokhov   Input: evdev - im...
637
638
639
640
641
642
643
644
645
646
647
648
  	case EVIOCGEFFECTS:
  		i = test_bit(EV_FF, dev->evbit) ?
  				dev->ff->max_effects : 0;
  		if (put_user(i, ip))
  			return -EFAULT;
  		return 0;
  
  	case EVIOCGRAB:
  		if (p)
  			return evdev_grab(evdev, client);
  		else
  			return evdev_ungrab(evdev, client);
ab4e01921   Dmitry Torokhov   Input: define sep...
649
650
651
652
653
654
655
656
657
658
659
660
  
  	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);
448cd1664   Dmitry Torokhov   Input: evdev - re...
661
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
662

448cd1664   Dmitry Torokhov   Input: evdev - re...
663
  	size = _IOC_SIZE(cmd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
664

448cd1664   Dmitry Torokhov   Input: evdev - re...
665
666
  	/* Now check variable-length commands */
  #define EVIOC_MASK_SIZE(nr)	((nr) & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT))
448cd1664   Dmitry Torokhov   Input: evdev - re...
667
  	switch (EVIOC_MASK_SIZE(cmd)) {
41e979f82   Vojtech Pavlik   Input: Make EVIOS...
668

85b772003   Henrik Rydberg   Input: introduce ...
669
670
671
  	case EVIOCGPROP(0):
  		return bits_to_user(dev->propbit, INPUT_PROP_MAX,
  				    size, p, compat_mode);
448cd1664   Dmitry Torokhov   Input: evdev - re...
672
673
  	case EVIOCGKEY(0):
  		return bits_to_user(dev->key, KEY_MAX, size, p, compat_mode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
674

448cd1664   Dmitry Torokhov   Input: evdev - re...
675
676
  	case EVIOCGLED(0):
  		return bits_to_user(dev->led, LED_MAX, size, p, compat_mode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
677

448cd1664   Dmitry Torokhov   Input: evdev - re...
678
679
  	case EVIOCGSND(0):
  		return bits_to_user(dev->snd, SND_MAX, size, p, compat_mode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
680

448cd1664   Dmitry Torokhov   Input: evdev - re...
681
682
  	case EVIOCGSW(0):
  		return bits_to_user(dev->sw, SW_MAX, size, p, compat_mode);
315810668   Richard Purdie   [PATCH] Input: Ad...
683

448cd1664   Dmitry Torokhov   Input: evdev - re...
684
685
  	case EVIOCGNAME(0):
  		return str_to_user(dev->name, size, p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
686

448cd1664   Dmitry Torokhov   Input: evdev - re...
687
688
  	case EVIOCGPHYS(0):
  		return str_to_user(dev->phys, size, p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
689

448cd1664   Dmitry Torokhov   Input: evdev - re...
690
691
  	case EVIOCGUNIQ(0):
  		return str_to_user(dev->uniq, size, p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
692

448cd1664   Dmitry Torokhov   Input: evdev - re...
693
694
695
  	case EVIOC_MASK_SIZE(EVIOCSFF):
  		if (input_ff_effect_from_user(p, size, &effect))
  			return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
696

448cd1664   Dmitry Torokhov   Input: evdev - re...
697
  		error = input_ff_upload(dev, &effect, file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
698

448cd1664   Dmitry Torokhov   Input: evdev - re...
699
700
  		if (put_user(effect.id, &(((struct ff_effect __user *)p)->id)))
  			return -EFAULT;
41e979f82   Vojtech Pavlik   Input: Make EVIOS...
701

448cd1664   Dmitry Torokhov   Input: evdev - re...
702
703
  		return error;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
704

448cd1664   Dmitry Torokhov   Input: evdev - re...
705
706
707
  	/* Multi-number variable-length handlers */
  	if (_IOC_TYPE(cmd) != 'E')
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
708

448cd1664   Dmitry Torokhov   Input: evdev - re...
709
  	if (_IOC_DIR(cmd) == _IOC_READ) {
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
710

448cd1664   Dmitry Torokhov   Input: evdev - re...
711
712
713
714
  		if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0, 0)))
  			return handle_eviocgbit(dev,
  						_IOC_NR(cmd) & EV_MAX, size,
  						p, compat_mode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
715

448cd1664   Dmitry Torokhov   Input: evdev - re...
716
  		if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
f2278f31d   Adam Dawidowski   Input: fix force ...
717

0a74a1df3   Daniel Mack   Input: evdev - fi...
718
719
  			if (!dev->absinfo)
  				return -EINVAL;
448cd1664   Dmitry Torokhov   Input: evdev - re...
720
721
  			t = _IOC_NR(cmd) & ABS_MAX;
  			abs = dev->absinfo[t];
f2278f31d   Adam Dawidowski   Input: fix force ...
722

448cd1664   Dmitry Torokhov   Input: evdev - re...
723
724
725
  			if (copy_to_user(p, &abs, min_t(size_t,
  					size, sizeof(struct input_absinfo))))
  				return -EFAULT;
f2278f31d   Adam Dawidowski   Input: fix force ...
726

448cd1664   Dmitry Torokhov   Input: evdev - re...
727
728
729
  			return 0;
  		}
  	}
f2278f31d   Adam Dawidowski   Input: fix force ...
730

f9ce6eb5b   Daniel Mack   Input: evdev - fi...
731
  	if (_IOC_DIR(cmd) == _IOC_WRITE) {
f2278f31d   Adam Dawidowski   Input: fix force ...
732

448cd1664   Dmitry Torokhov   Input: evdev - re...
733
  		if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
734

0a74a1df3   Daniel Mack   Input: evdev - fi...
735
736
  			if (!dev->absinfo)
  				return -EINVAL;
448cd1664   Dmitry Torokhov   Input: evdev - re...
737
  			t = _IOC_NR(cmd) & ABS_MAX;
41e979f82   Vojtech Pavlik   Input: Make EVIOS...
738

448cd1664   Dmitry Torokhov   Input: evdev - re...
739
740
741
  			if (copy_from_user(&abs, p, min_t(size_t,
  					size, sizeof(struct input_absinfo))))
  				return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
742

448cd1664   Dmitry Torokhov   Input: evdev - re...
743
744
  			if (size < sizeof(struct input_absinfo))
  				abs.resolution = 0;
d31b2865a   Daniel Mack   Input: dynamicall...
745

448cd1664   Dmitry Torokhov   Input: evdev - re...
746
747
748
  			/* We can't change number of reserved MT slots */
  			if (t == ABS_MT_SLOT)
  				return -EINVAL;
40d007e7d   Henrik Rydberg   Input: introduce ...
749

448cd1664   Dmitry Torokhov   Input: evdev - re...
750
751
752
753
754
755
756
757
  			/*
  			 * 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);
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
758

448cd1664   Dmitry Torokhov   Input: evdev - re...
759
  			return 0;
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
760
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
761
  	}
448cd1664   Dmitry Torokhov   Input: evdev - re...
762

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
763
764
  	return -EINVAL;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
765

6addb1d6d   Dmitry Torokhov   Input: evdev - im...
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
  static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
  				void __user *p, int compat_mode)
  {
  	struct evdev_client *client = file->private_data;
  	struct evdev *evdev = client->evdev;
  	int retval;
  
  	retval = mutex_lock_interruptible(&evdev->mutex);
  	if (retval)
  		return retval;
  
  	if (!evdev->exist) {
  		retval = -ENODEV;
  		goto out;
  	}
  
  	retval = evdev_do_ioctl(file, cmd, p, compat_mode);
  
   out:
  	mutex_unlock(&evdev->mutex);
  	return retval;
  }
3a51f7c40   Dmitry Torokhov   Input: evdev - co...
788
789
790
791
  static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  {
  	return evdev_ioctl_handler(file, cmd, (void __user *)arg, 0);
  }
41e979f82   Vojtech Pavlik   Input: Make EVIOS...
792

3a51f7c40   Dmitry Torokhov   Input: evdev - co...
793
  #ifdef CONFIG_COMPAT
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
794
795
  static long evdev_ioctl_compat(struct file *file,
  				unsigned int cmd, unsigned long arg)
52658bb68   Juergen Kreileder   Input: Add suppor...
796
  {
3a51f7c40   Dmitry Torokhov   Input: evdev - co...
797
  	return evdev_ioctl_handler(file, cmd, compat_ptr(arg), 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
798
  }
52658bb68   Juergen Kreileder   Input: Add suppor...
799
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
800

66e661188   Dmitry Torokhov   Input: constify i...
801
  static const struct file_operations evdev_fops = {
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
802
803
804
805
806
807
808
  	.owner		= THIS_MODULE,
  	.read		= evdev_read,
  	.write		= evdev_write,
  	.poll		= evdev_poll,
  	.open		= evdev_open,
  	.release	= evdev_release,
  	.unlocked_ioctl	= evdev_ioctl,
52658bb68   Juergen Kreileder   Input: Add suppor...
809
  #ifdef CONFIG_COMPAT
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
810
  	.compat_ioctl	= evdev_ioctl_compat,
52658bb68   Juergen Kreileder   Input: Add suppor...
811
  #endif
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
812
  	.fasync		= evdev_fasync,
6038f373a   Arnd Bergmann   llseek: automatic...
813
814
  	.flush		= evdev_flush,
  	.llseek		= no_llseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
815
  };
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
  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
   * blocking reads will stay, however new ones will fail.
   */
  static void evdev_mark_dead(struct evdev *evdev)
  {
  	mutex_lock(&evdev->mutex);
20da92de8   Dmitry Torokhov   Input: change inp...
844
  	evdev->exist = false;
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
  	mutex_unlock(&evdev->mutex);
  }
  
  static void evdev_cleanup(struct evdev *evdev)
  {
  	struct input_handle *handle = &evdev->handle;
  
  	evdev_mark_dead(evdev);
  	evdev_hangup(evdev);
  	evdev_remove_chrdev(evdev);
  
  	/* evdev is marked dead so no one else accesses evdev->open */
  	if (evdev->open) {
  		input_flush_device(handle, NULL);
  		input_close_device(handle);
  	}
  }
  
  /*
   * Create new evdev device. Note that input core serializes calls
   * to connect and disconnect so we don't need to lock evdev_table here.
   */
5b2a08262   Dmitry Torokhov   Input: rework han...
867
868
  static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
  			 const struct input_device_id *id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
869
870
871
  {
  	struct evdev *evdev;
  	int minor;
5b2a08262   Dmitry Torokhov   Input: rework han...
872
  	int error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
873

6addb1d6d   Dmitry Torokhov   Input: evdev - im...
874
875
876
  	for (minor = 0; minor < EVDEV_MINORS; minor++)
  		if (!evdev_table[minor])
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
877
  	if (minor == EVDEV_MINORS) {
da0c49011   Joe Perches   Input: use pr_fmt...
878
879
  		pr_err("no more free evdev devices
  ");
5b2a08262   Dmitry Torokhov   Input: rework han...
880
  		return -ENFILE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
881
  	}
5b2a08262   Dmitry Torokhov   Input: rework han...
882
883
884
  	evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);
  	if (!evdev)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
885

d0ffb9be8   Dmitry Torokhov   Input: handlers -...
886
  	INIT_LIST_HEAD(&evdev->client_list);
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
887
888
  	spin_lock_init(&evdev->client_lock);
  	mutex_init(&evdev->mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
889
  	init_waitqueue_head(&evdev->wait);
3d5cb60ef   Thadeu Lima de Souza Cascardo   Input: simplify n...
890
  	dev_set_name(&evdev->dev, "event%d", minor);
20da92de8   Dmitry Torokhov   Input: change inp...
891
  	evdev->exist = true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
892
  	evdev->minor = minor;
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
893

a7097ff89   Dmitry Torokhov   Input: make sure ...
894
  	evdev->handle.dev = input_get_device(dev);
3d5cb60ef   Thadeu Lima de Souza Cascardo   Input: simplify n...
895
  	evdev->handle.name = dev_name(&evdev->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
896
897
  	evdev->handle.handler = handler;
  	evdev->handle.private = evdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
898

6addb1d6d   Dmitry Torokhov   Input: evdev - im...
899
  	evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);
9657d75c5   Dmitry Torokhov   Input: convert fr...
900
901
  	evdev->dev.class = &input_class;
  	evdev->dev.parent = &dev->dev;
9657d75c5   Dmitry Torokhov   Input: convert fr...
902
903
  	evdev->dev.release = evdev_free;
  	device_initialize(&evdev->dev);
5b2a08262   Dmitry Torokhov   Input: rework han...
904

6addb1d6d   Dmitry Torokhov   Input: evdev - im...
905
  	error = input_register_handle(&evdev->handle);
5b2a08262   Dmitry Torokhov   Input: rework han...
906
  	if (error)
9657d75c5   Dmitry Torokhov   Input: convert fr...
907
  		goto err_free_evdev;
5b2a08262   Dmitry Torokhov   Input: rework han...
908

6addb1d6d   Dmitry Torokhov   Input: evdev - im...
909
910
911
912
913
  	error = evdev_install_chrdev(evdev);
  	if (error)
  		goto err_unregister_handle;
  
  	error = device_add(&evdev->dev);
5b2a08262   Dmitry Torokhov   Input: rework han...
914
  	if (error)
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
915
  		goto err_cleanup_evdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
916

5b2a08262   Dmitry Torokhov   Input: rework han...
917
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
918

6addb1d6d   Dmitry Torokhov   Input: evdev - im...
919
920
921
922
   err_cleanup_evdev:
  	evdev_cleanup(evdev);
   err_unregister_handle:
  	input_unregister_handle(&evdev->handle);
5b2a08262   Dmitry Torokhov   Input: rework han...
923
   err_free_evdev:
9657d75c5   Dmitry Torokhov   Input: convert fr...
924
  	put_device(&evdev->dev);
5b2a08262   Dmitry Torokhov   Input: rework han...
925
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
926
927
928
929
930
  }
  
  static void evdev_disconnect(struct input_handle *handle)
  {
  	struct evdev *evdev = handle->private;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
931

9657d75c5   Dmitry Torokhov   Input: convert fr...
932
  	device_del(&evdev->dev);
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
933
934
  	evdev_cleanup(evdev);
  	input_unregister_handle(handle);
9657d75c5   Dmitry Torokhov   Input: convert fr...
935
  	put_device(&evdev->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
936
  }
66e661188   Dmitry Torokhov   Input: constify i...
937
  static const struct input_device_id evdev_ids[] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
938
939
940
941
942
943
944
  	{ .driver_info = 1 },	/* Matches all devices */
  	{ },			/* Terminating zero entry */
  };
  
  MODULE_DEVICE_TABLE(input, evdev_ids);
  
  static struct input_handler evdev_handler = {
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
945
946
947
948
949
950
951
  	.event		= evdev_event,
  	.connect	= evdev_connect,
  	.disconnect	= evdev_disconnect,
  	.fops		= &evdev_fops,
  	.minor		= EVDEV_MINOR_BASE,
  	.name		= "evdev",
  	.id_table	= evdev_ids,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
952
953
954
955
  };
  
  static int __init evdev_init(void)
  {
4263cf0fa   Dmitry Torokhov   Input: make input...
956
  	return input_register_handler(&evdev_handler);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
957
958
959
960
961
962
963
964
965
966
967
968
969
  }
  
  static void __exit evdev_exit(void)
  {
  	input_unregister_handler(&evdev_handler);
  }
  
  module_init(evdev_init);
  module_exit(evdev_exit);
  
  MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
  MODULE_DESCRIPTION("Input driver event char devices");
  MODULE_LICENSE("GPL");