Blame view

drivers/input/evdev.c 32.4 KB
d2912cb15   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
  /*
   * Event char devices, giving access to raw input device events.
   *
   * Copyright (c) 1999-2002 Vojtech Pavlik
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6
   */
da0c49011   Joe Perches   Input: use pr_fmt...
7
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
9
  #define EVDEV_MINOR_BASE	64
  #define EVDEV_MINORS		32
63a6404d8   Henrik Rydberg   Input: evdev - us...
10
11
  #define EVDEV_MIN_BUFFER_SIZE	64U
  #define EVDEV_BUF_PACKETS	8
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
13
  
  #include <linux/poll.h>
a99bbaf5e   Alexey Dobriyan   headers: remove s...
14
  #include <linux/sched.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
  #include <linux/slab.h>
92eb77d0f   Daniel Stone   Input: evdev - fa...
16
17
  #include <linux/vmalloc.h>
  #include <linux/mm.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
19
  #include <linux/module.h>
  #include <linux/init.h>
1cf0c6e69   Henrik Rydberg   Input: Add EVIOC ...
20
  #include <linux/input/mt.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
  #include <linux/major.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
  #include <linux/device.h>
7f8d4cad1   Dmitry Torokhov   Input: extend the...
23
  #include <linux/cdev.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
  	int open;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
  	struct input_handle handle;
2be852792   Arnd Bergmann   input: __rcu anno...
29
  	struct evdev_client __rcu *grab;
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
30
  	struct list_head client_list;
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
31
32
  	spinlock_t client_lock; /* protects client_list */
  	struct mutex mutex;
9657d75c5   Dmitry Torokhov   Input: convert fr...
33
  	struct device dev;
7f8d4cad1   Dmitry Torokhov   Input: extend the...
34
  	struct cdev cdev;
20da92de8   Dmitry Torokhov   Input: change inp...
35
  	bool exist;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
  };
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
37
  struct evdev_client {
9fb0f14e3   Jeff Brown   Input: evdev - in...
38
39
  	unsigned int head;
  	unsigned int tail;
cdda911c3   Jeff Brown   Input: evdev - on...
40
  	unsigned int packet_head; /* [future] position of the first element of next packet */
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
41
  	spinlock_t buffer_lock; /* protects access to buffer, head and tail */
4ba8b8aec   Kenny Levinsen   Input: evdev - pe...
42
  	wait_queue_head_t wait;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
44
45
  	struct fasync_struct *fasync;
  	struct evdev *evdev;
  	struct list_head node;
3b51c44bd   Atif Niyaz   Input: allow driv...
46
  	enum input_clock_type clk_type;
c7dc65737   David Herrmann   Input: evdev - ad...
47
  	bool revoked;
06a16293f   David Herrmann   Input: evdev - ad...
48
  	unsigned long *evmasks[EV_CNT];
9fb0f14e3   Jeff Brown   Input: evdev - in...
49
  	unsigned int bufsize;
b58f7086d   Henrik Rydberg   Input: evdev - co...
50
  	struct input_event buffer[];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51
  };
06a16293f   David Herrmann   Input: evdev - ad...
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
  static size_t evdev_get_mask_cnt(unsigned int type)
  {
  	static const size_t counts[EV_CNT] = {
  		/* EV_SYN==0 is EV_CNT, _not_ SYN_CNT, see EVIOCGBIT */
  		[EV_SYN]	= EV_CNT,
  		[EV_KEY]	= KEY_CNT,
  		[EV_REL]	= REL_CNT,
  		[EV_ABS]	= ABS_CNT,
  		[EV_MSC]	= MSC_CNT,
  		[EV_SW]		= SW_CNT,
  		[EV_LED]	= LED_CNT,
  		[EV_SND]	= SND_CNT,
  		[EV_FF]		= FF_CNT,
  	};
  
  	return (type < EV_CNT) ? counts[type] : 0;
  }
  
  /* requires the buffer lock to be held */
  static bool __evdev_is_filtered(struct evdev_client *client,
  				unsigned int type,
  				unsigned int code)
  {
  	unsigned long *mask;
  	size_t cnt;
  
  	/* EV_SYN and unknown codes are never filtered */
  	if (type == EV_SYN || type >= EV_CNT)
  		return false;
  
  	/* first test whether the type is filtered */
  	mask = client->evmasks[0];
  	if (mask && !test_bit(type, mask))
  		return true;
  
  	/* unknown values are never filtered */
  	cnt = evdev_get_mask_cnt(type);
  	if (!cnt || code >= cnt)
  		return false;
  
  	mask = client->evmasks[type];
  	return mask && !test_bit(code, mask);
  }
483180281   David Herrmann   Input: evdev - fl...
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
  /* 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 */
152194fe9   Deepa Dinamani   Input: extend usa...
123
  			client->buffer[head] = *ev;
483180281   David Herrmann   Input: evdev - fl...
124
125
126
127
128
129
130
131
132
133
134
135
136
  		}
  
  		num++;
  		head = (head + 1) & mask;
  
  		if (is_report) {
  			num = 0;
  			client->packet_head = head;
  		}
  	}
  
  	client->head = head;
  }
b881d5377   Dmitry Torokhov   Input: evdev - do...
137
  static void __evdev_queue_syn_dropped(struct evdev_client *client)
483180281   David Herrmann   Input: evdev - fl...
138
  {
3b51c44bd   Atif Niyaz   Input: allow driv...
139
140
  	ktime_t *ev_time = input_get_timestamp(client->evdev->handle.dev);
  	struct timespec64 ts = ktime_to_timespec64(ev_time[client->clk_type]);
483180281   David Herrmann   Input: evdev - fl...
141
  	struct input_event ev;
483180281   David Herrmann   Input: evdev - fl...
142

152194fe9   Deepa Dinamani   Input: extend usa...
143
144
  	ev.input_event_sec = ts.tv_sec;
  	ev.input_event_usec = ts.tv_nsec / NSEC_PER_USEC;
483180281   David Herrmann   Input: evdev - fl...
145
146
147
  	ev.type = EV_SYN;
  	ev.code = SYN_DROPPED;
  	ev.value = 0;
483180281   David Herrmann   Input: evdev - fl...
148
149
150
151
152
153
154
155
  	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;
  	}
b881d5377   Dmitry Torokhov   Input: evdev - do...
156
157
158
159
160
  }
  
  static void evdev_queue_syn_dropped(struct evdev_client *client)
  {
  	unsigned long flags;
483180281   David Herrmann   Input: evdev - fl...
161

b881d5377   Dmitry Torokhov   Input: evdev - do...
162
163
  	spin_lock_irqsave(&client->buffer_lock, flags);
  	__evdev_queue_syn_dropped(client);
483180281   David Herrmann   Input: evdev - fl...
164
165
  	spin_unlock_irqrestore(&client->buffer_lock, flags);
  }
0c3e99437   Anshul Garg   Input: evdev - fl...
166
167
  static int evdev_set_clk_type(struct evdev_client *client, unsigned int clkid)
  {
b881d5377   Dmitry Torokhov   Input: evdev - do...
168
  	unsigned long flags;
3b51c44bd   Atif Niyaz   Input: allow driv...
169
  	enum input_clock_type clk_type;
0c3e99437   Anshul Garg   Input: evdev - fl...
170
171
172
173
  
  	switch (clkid) {
  
  	case CLOCK_REALTIME:
3b51c44bd   Atif Niyaz   Input: allow driv...
174
  		clk_type = INPUT_CLK_REAL;
0c3e99437   Anshul Garg   Input: evdev - fl...
175
176
  		break;
  	case CLOCK_MONOTONIC:
3b51c44bd   Atif Niyaz   Input: allow driv...
177
  		clk_type = INPUT_CLK_MONO;
0c3e99437   Anshul Garg   Input: evdev - fl...
178
179
  		break;
  	case CLOCK_BOOTTIME:
3b51c44bd   Atif Niyaz   Input: allow driv...
180
  		clk_type = INPUT_CLK_BOOT;
0c3e99437   Anshul Garg   Input: evdev - fl...
181
182
183
184
  		break;
  	default:
  		return -EINVAL;
  	}
bf5f18d70   Aniroop Mathur   Input: evdev - fi...
185
186
  	if (client->clk_type != clk_type) {
  		client->clk_type = clk_type;
b881d5377   Dmitry Torokhov   Input: evdev - do...
187

bf5f18d70   Aniroop Mathur   Input: evdev - fi...
188
189
190
191
192
  		/*
  		 * Flush pending events and queue SYN_DROPPED event,
  		 * but only if the queue is not empty.
  		 */
  		spin_lock_irqsave(&client->buffer_lock, flags);
b881d5377   Dmitry Torokhov   Input: evdev - do...
193

bf5f18d70   Aniroop Mathur   Input: evdev - fi...
194
195
196
197
198
199
200
  		if (client->head != client->tail) {
  			client->packet_head = client->head = client->tail;
  			__evdev_queue_syn_dropped(client);
  		}
  
  		spin_unlock_irqrestore(&client->buffer_lock, flags);
  	}
0c3e99437   Anshul Garg   Input: evdev - fl...
201
202
203
  
  	return 0;
  }
a274ac15e   Henrik Rydberg   Input: evdev - Ad...
204
205
  static void __pass_event(struct evdev_client *client,
  			 const struct input_event *event)
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
206
  {
9fb0f14e3   Jeff Brown   Input: evdev - in...
207
208
209
210
211
212
213
214
215
  	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);
f729a1b0f   Arnd Bergmann   Input: input_even...
216
217
218
219
220
221
222
  		client->buffer[client->tail] = (struct input_event) {
  			.input_event_sec = event->input_event_sec,
  			.input_event_usec = event->input_event_usec,
  			.type = EV_SYN,
  			.code = SYN_DROPPED,
  			.value = 0,
  		};
9fb0f14e3   Jeff Brown   Input: evdev - in...
223

cdda911c3   Jeff Brown   Input: evdev - on...
224
225
  		client->packet_head = client->tail;
  	}
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
226

cdda911c3   Jeff Brown   Input: evdev - on...
227
228
  	if (event->type == EV_SYN && event->code == SYN_REPORT) {
  		client->packet_head = client->head;
30a589fde   Adam Jackson   Input: evdev - be...
229
  		kill_fasync(&client->fasync, SIGIO, POLL_IN);
cdda911c3   Jeff Brown   Input: evdev - on...
230
  	}
a274ac15e   Henrik Rydberg   Input: evdev - Ad...
231
232
233
234
  }
  
  static void evdev_pass_values(struct evdev_client *client,
  			const struct input_value *vals, unsigned int count,
aac8bcf1e   Aniroop Mathur   Input: evdev - ad...
235
  			ktime_t *ev_time)
a274ac15e   Henrik Rydberg   Input: evdev - Ad...
236
  {
a274ac15e   Henrik Rydberg   Input: evdev - Ad...
237
238
  	const struct input_value *v;
  	struct input_event event;
152194fe9   Deepa Dinamani   Input: extend usa...
239
  	struct timespec64 ts;
a274ac15e   Henrik Rydberg   Input: evdev - Ad...
240
  	bool wakeup = false;
c7dc65737   David Herrmann   Input: evdev - ad...
241
242
  	if (client->revoked)
  		return;
152194fe9   Deepa Dinamani   Input: extend usa...
243
244
245
  	ts = ktime_to_timespec64(ev_time[client->clk_type]);
  	event.input_event_sec = ts.tv_sec;
  	event.input_event_usec = ts.tv_nsec / NSEC_PER_USEC;
a274ac15e   Henrik Rydberg   Input: evdev - Ad...
246
247
248
249
250
  
  	/* Interrupts are disabled, just acquire the lock. */
  	spin_lock(&client->buffer_lock);
  
  	for (v = vals; v != vals + count; v++) {
06a16293f   David Herrmann   Input: evdev - ad...
251
252
253
254
255
256
257
258
259
260
  		if (__evdev_is_filtered(client, v->type, v->code))
  			continue;
  
  		if (v->type == EV_SYN && v->code == SYN_REPORT) {
  			/* drop empty SYN_REPORT */
  			if (client->packet_head == client->head)
  				continue;
  
  			wakeup = true;
  		}
a274ac15e   Henrik Rydberg   Input: evdev - Ad...
261
262
263
264
  		event.type = v->type;
  		event.code = v->code;
  		event.value = v->value;
  		__pass_event(client, &event);
a274ac15e   Henrik Rydberg   Input: evdev - Ad...
265
  	}
cdda911c3   Jeff Brown   Input: evdev - on...
266
267
  
  	spin_unlock(&client->buffer_lock);
a274ac15e   Henrik Rydberg   Input: evdev - Ad...
268
269
  
  	if (wakeup)
4ba8b8aec   Kenny Levinsen   Input: evdev - pe...
270
  		wake_up_interruptible_poll(&client->wait,
81b4d1d22   Kenny Levinsen   Input: evdev - us...
271
  			EPOLLIN | EPOLLOUT | EPOLLRDNORM | EPOLLWRNORM);
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
272
273
274
  }
  
  /*
a274ac15e   Henrik Rydberg   Input: evdev - Ad...
275
   * Pass incoming events to all connected clients.
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
276
   */
a274ac15e   Henrik Rydberg   Input: evdev - Ad...
277
278
  static void evdev_events(struct input_handle *handle,
  			 const struct input_value *vals, unsigned int count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279
280
  {
  	struct evdev *evdev = handle->private;
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
281
  	struct evdev_client *client;
3b51c44bd   Atif Niyaz   Input: allow driv...
282
  	ktime_t *ev_time = input_get_timestamp(handle->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283

82ba56c27   Dmitry Torokhov   Input: use full R...
284
  	rcu_read_lock();
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
285
  	client = rcu_dereference(evdev->grab);
a80b83b7b   John Stultz   Input: add infras...
286

6addb1d6d   Dmitry Torokhov   Input: evdev - im...
287
  	if (client)
aac8bcf1e   Aniroop Mathur   Input: evdev - ad...
288
  		evdev_pass_values(client, vals, count, ev_time);
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
289
290
  	else
  		list_for_each_entry_rcu(client, &evdev->client_list, node)
aac8bcf1e   Aniroop Mathur   Input: evdev - ad...
291
  			evdev_pass_values(client, vals, count, ev_time);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292

82ba56c27   Dmitry Torokhov   Input: use full R...
293
  	rcu_read_unlock();
a274ac15e   Henrik Rydberg   Input: evdev - Ad...
294
  }
82ba56c27   Dmitry Torokhov   Input: use full R...
295

a274ac15e   Henrik Rydberg   Input: evdev - Ad...
296
297
298
299
300
301
302
303
304
  /*
   * 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);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305
306
307
308
  }
  
  static int evdev_fasync(int fd, struct file *file, int on)
  {
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
309
  	struct evdev_client *client = file->private_data;
1e0afb288   Dmitry Torokhov   Input: fix format...
310

60aa49243   Jonathan Corbet   Rationalize fasyn...
311
  	return fasync_helper(fd, file, on, &client->fasync);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
312
  }
9657d75c5   Dmitry Torokhov   Input: convert fr...
313
  static void evdev_free(struct device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314
  {
9657d75c5   Dmitry Torokhov   Input: convert fr...
315
  	struct evdev *evdev = container_of(dev, struct evdev, dev);
a7097ff89   Dmitry Torokhov   Input: make sure ...
316
  	input_put_device(evdev->handle.dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
317
318
  	kfree(evdev);
  }
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
  /*
   * 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);
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
335
336
337
338
339
340
  
  	return 0;
  }
  
  static int evdev_ungrab(struct evdev *evdev, struct evdev_client *client)
  {
dba425806   Dmitry Torokhov   Input: evdev - pr...
341
342
343
344
  	struct evdev_client *grab = rcu_dereference_protected(evdev->grab,
  					lockdep_is_held(&evdev->mutex));
  
  	if (grab != client)
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
345
346
347
  		return  -EINVAL;
  
  	rcu_assign_pointer(evdev->grab, NULL);
82ba56c27   Dmitry Torokhov   Input: use full R...
348
  	synchronize_rcu();
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
349
350
351
352
353
354
355
356
357
358
359
  	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);
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
360
361
362
363
364
365
366
367
  }
  
  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...
368
  	synchronize_rcu();
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
369
370
371
372
373
374
375
376
377
378
379
380
  }
  
  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...
381
  	else if (!evdev->open++) {
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
382
  		retval = input_open_device(&evdev->handle);
064450140   Oliver Neukum   Input: fix open c...
383
384
385
  		if (retval)
  			evdev->open--;
  	}
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
  
  	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);
4ba8b8aec   Kenny Levinsen   Input: evdev - pe...
410
  	list_for_each_entry(client, &evdev->client_list, node) {
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
411
  		kill_fasync(&client->fasync, SIGIO, POLL_HUP);
4ba8b8aec   Kenny Levinsen   Input: evdev - pe...
412
413
  		wake_up_interruptible_poll(&client->wait, EPOLLHUP | EPOLLERR);
  	}
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
414
  	spin_unlock(&evdev->client_lock);
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
415
  }
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
416
  static int evdev_release(struct inode *inode, struct file *file)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
417
  {
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
418
419
  	struct evdev_client *client = file->private_data;
  	struct evdev *evdev = client->evdev;
06a16293f   David Herrmann   Input: evdev - ad...
420
  	unsigned int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
421

6addb1d6d   Dmitry Torokhov   Input: evdev - im...
422
  	mutex_lock(&evdev->mutex);
09264098f   Brendan Shanks   Input: evdev - ca...
423
424
425
  
  	if (evdev->exist && !client->revoked)
  		input_flush_device(&evdev->handle, file);
dba425806   Dmitry Torokhov   Input: evdev - pr...
426
  	evdev_ungrab(evdev, client);
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
427
  	mutex_unlock(&evdev->mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
428

6addb1d6d   Dmitry Torokhov   Input: evdev - im...
429
  	evdev_detach_client(evdev, client);
92eb77d0f   Daniel Stone   Input: evdev - fa...
430

06a16293f   David Herrmann   Input: evdev - ad...
431
  	for (i = 0; i < EV_CNT; ++i)
6078091c9   Andy Shevchenko   Input: evdev - sw...
432
  		bitmap_free(client->evmasks[i]);
06a16293f   David Herrmann   Input: evdev - ad...
433

67367fd25   Pekka Enberg   Input: evdev - us...
434
  	kvfree(client);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
435

6addb1d6d   Dmitry Torokhov   Input: evdev - im...
436
  	evdev_close_device(evdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
437

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
438
439
  	return 0;
  }
b58f7086d   Henrik Rydberg   Input: evdev - co...
440
441
  static unsigned int evdev_compute_buffer_size(struct input_dev *dev)
  {
63a6404d8   Henrik Rydberg   Input: evdev - us...
442
443
444
445
446
  	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...
447
  }
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
448
  static int evdev_open(struct inode *inode, struct file *file)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
449
  {
7f8d4cad1   Dmitry Torokhov   Input: extend the...
450
451
  	struct evdev *evdev = container_of(inode->i_cdev, struct evdev, cdev);
  	unsigned int bufsize = evdev_compute_buffer_size(evdev->handle.dev);
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
452
  	struct evdev_client *client;
d542ed82f   Dmitry Torokhov   Input: handlers -...
453
  	int error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
454

7f439bc2d   Miles Chen   Input: evdev - co...
455
  	client = kvzalloc(struct_size(client, buffer, bufsize), GFP_KERNEL);
7f8d4cad1   Dmitry Torokhov   Input: extend the...
456
457
  	if (!client)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
458

4ba8b8aec   Kenny Levinsen   Input: evdev - pe...
459
  	init_waitqueue_head(&client->wait);
b58f7086d   Henrik Rydberg   Input: evdev - co...
460
  	client->bufsize = bufsize;
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
461
  	spin_lock_init(&client->buffer_lock);
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
462
  	client->evdev = evdev;
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
463
  	evdev_attach_client(evdev, client);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
464

6addb1d6d   Dmitry Torokhov   Input: evdev - im...
465
466
467
  	error = evdev_open_device(evdev);
  	if (error)
  		goto err_free_client;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
468

d0ffb9be8   Dmitry Torokhov   Input: handlers -...
469
  	file->private_data = client;
c5bf68fe0   Kirill Smelkov   *: convert stream...
470
  	stream_open(inode, file);
3d7bbd457   Dmitry Torokhov   Input: mark input...
471

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472
  	return 0;
9657d75c5   Dmitry Torokhov   Input: convert fr...
473
474
  
   err_free_client:
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
475
  	evdev_detach_client(evdev, client);
92788ac1e   Andrew Morton   drivers/input/evd...
476
  	kvfree(client);
9657d75c5   Dmitry Torokhov   Input: convert fr...
477
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
478
  }
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
479
480
  static ssize_t evdev_write(struct file *file, const char __user *buffer,
  			   size_t count, loff_t *ppos)
3a51f7c40   Dmitry Torokhov   Input: evdev - co...
481
  {
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
482
483
  	struct evdev_client *client = file->private_data;
  	struct evdev *evdev = client->evdev;
3a51f7c40   Dmitry Torokhov   Input: evdev - co...
484
  	struct input_event event;
02dfc4968   Heiko Stübner   Input: evdev - fi...
485
  	int retval = 0;
52658bb68   Juergen Kreileder   Input: Add suppor...
486

2872a9b52   Dmitry Torokhov   Input: evdev - pr...
487
  	if (count != 0 && count < input_event_size())
439581ec0   Peter Korsgaard   Input: evdev - fi...
488
  		return -EINVAL;
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
489
490
491
  	retval = mutex_lock_interruptible(&evdev->mutex);
  	if (retval)
  		return retval;
c7dc65737   David Herrmann   Input: evdev - ad...
492
  	if (!evdev->exist || client->revoked) {
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
493
494
495
  		retval = -ENODEV;
  		goto out;
  	}
52658bb68   Juergen Kreileder   Input: Add suppor...
496

2872a9b52   Dmitry Torokhov   Input: evdev - pr...
497
  	while (retval + input_event_size() <= count) {
2d56f3a32   Philip Langdale   Input: refactor e...
498
  		if (input_event_from_user(buffer + retval, &event)) {
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
499
500
501
  			retval = -EFAULT;
  			goto out;
  		}
439581ec0   Peter Korsgaard   Input: evdev - fi...
502
  		retval += input_event_size();
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
503
504
505
  
  		input_inject_event(&evdev->handle,
  				   event.type, event.code, event.value);
36d2582ff   Dmitry Torokhov   Input: evdev - ad...
506
  		cond_resched();
2872a9b52   Dmitry Torokhov   Input: evdev - pr...
507
  	}
52658bb68   Juergen Kreileder   Input: Add suppor...
508

6addb1d6d   Dmitry Torokhov   Input: evdev - im...
509
510
   out:
  	mutex_unlock(&evdev->mutex);
52658bb68   Juergen Kreileder   Input: Add suppor...
511
512
  	return retval;
  }
52658bb68   Juergen Kreileder   Input: Add suppor...
513

6addb1d6d   Dmitry Torokhov   Input: evdev - im...
514
515
516
517
518
519
  static int evdev_fetch_next_event(struct evdev_client *client,
  				  struct input_event *event)
  {
  	int have_event;
  
  	spin_lock_irq(&client->buffer_lock);
566cf5b6e   Dima Zavin   Input: evdev - on...
520
  	have_event = client->packet_head != client->tail;
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
521
522
  	if (have_event) {
  		*event = client->buffer[client->tail++];
b58f7086d   Henrik Rydberg   Input: evdev - co...
523
  		client->tail &= client->bufsize - 1;
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
524
525
526
527
528
529
530
531
532
  	}
  
  	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
533
  {
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
534
535
  	struct evdev_client *client = file->private_data;
  	struct evdev *evdev = client->evdev;
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
536
  	struct input_event event;
2872a9b52   Dmitry Torokhov   Input: evdev - pr...
537
538
  	size_t read = 0;
  	int error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539

2872a9b52   Dmitry Torokhov   Input: evdev - pr...
540
  	if (count != 0 && count < input_event_size())
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541
  		return -EINVAL;
2872a9b52   Dmitry Torokhov   Input: evdev - pr...
542
  	for (;;) {
c7dc65737   David Herrmann   Input: evdev - ad...
543
  		if (!evdev->exist || client->revoked)
2872a9b52   Dmitry Torokhov   Input: evdev - pr...
544
  			return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
545

2872a9b52   Dmitry Torokhov   Input: evdev - pr...
546
547
548
549
550
551
552
553
554
555
  		if (client->packet_head == client->tail &&
  		    (file->f_flags & O_NONBLOCK))
  			return -EAGAIN;
  
  		/*
  		 * count == 0 is special - no IO is done but we check
  		 * for error conditions (see above).
  		 */
  		if (count == 0)
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
556

2872a9b52   Dmitry Torokhov   Input: evdev - pr...
557
558
  		while (read + input_event_size() <= count &&
  		       evdev_fetch_next_event(client, &event)) {
3a51f7c40   Dmitry Torokhov   Input: evdev - co...
559

2872a9b52   Dmitry Torokhov   Input: evdev - pr...
560
561
  			if (input_event_to_user(buffer + read, &event))
  				return -EFAULT;
3a51f7c40   Dmitry Torokhov   Input: evdev - co...
562

2872a9b52   Dmitry Torokhov   Input: evdev - pr...
563
564
  			read += input_event_size();
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
565

2872a9b52   Dmitry Torokhov   Input: evdev - pr...
566
567
  		if (read)
  			break;
e90f869ca   Dima Zavin   Input: evdev - if...
568

2872a9b52   Dmitry Torokhov   Input: evdev - pr...
569
  		if (!(file->f_flags & O_NONBLOCK)) {
4ba8b8aec   Kenny Levinsen   Input: evdev - pe...
570
  			error = wait_event_interruptible(client->wait,
2872a9b52   Dmitry Torokhov   Input: evdev - pr...
571
  					client->packet_head != client->tail ||
c7dc65737   David Herrmann   Input: evdev - ad...
572
  					!evdev->exist || client->revoked);
2872a9b52   Dmitry Torokhov   Input: evdev - pr...
573
574
575
576
577
578
  			if (error)
  				return error;
  		}
  	}
  
  	return read;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
579
580
581
  }
  
  /* No kernel lock - fine */
afc9a42b7   Al Viro   the rest of drive...
582
  static __poll_t evdev_poll(struct file *file, poll_table *wait)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
583
  {
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
584
585
  	struct evdev_client *client = file->private_data;
  	struct evdev *evdev = client->evdev;
afc9a42b7   Al Viro   the rest of drive...
586
  	__poll_t mask;
1e0afb288   Dmitry Torokhov   Input: fix format...
587

4ba8b8aec   Kenny Levinsen   Input: evdev - pe...
588
  	poll_wait(file, &client->wait, wait);
c18fb1396   Dmitry Torokhov   Input: evdev - si...
589

c7dc65737   David Herrmann   Input: evdev - ad...
590
  	if (evdev->exist && !client->revoked)
a9a08845e   Linus Torvalds   vfs: do bulk POLL...
591
  		mask = EPOLLOUT | EPOLLWRNORM;
c7dc65737   David Herrmann   Input: evdev - ad...
592
  	else
a9a08845e   Linus Torvalds   vfs: do bulk POLL...
593
  		mask = EPOLLHUP | EPOLLERR;
c7dc65737   David Herrmann   Input: evdev - ad...
594

cdda911c3   Jeff Brown   Input: evdev - on...
595
  	if (client->packet_head != client->tail)
a9a08845e   Linus Torvalds   vfs: do bulk POLL...
596
  		mask |= EPOLLIN | EPOLLRDNORM;
c18fb1396   Dmitry Torokhov   Input: evdev - si...
597
598
  
  	return mask;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
599
  }
3a51f7c40   Dmitry Torokhov   Input: evdev - co...
600
601
602
  #ifdef CONFIG_COMPAT
  
  #define BITS_PER_LONG_COMPAT (sizeof(compat_long_t) * 8)
7b19ada2e   Jiri Slaby   get rid of input ...
603
  #define BITS_TO_LONGS_COMPAT(x) ((((x) - 1) / BITS_PER_LONG_COMPAT) + 1)
3a51f7c40   Dmitry Torokhov   Input: evdev - co...
604
605
606
607
608
609
610
611
  
  #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 ...
612
  		len = BITS_TO_LONGS_COMPAT(maxbit) * sizeof(compat_long_t);
bf61f8d35   Kenichi Nagai   Input: evdev - fi...
613
  		if (len > maxlen)
3a51f7c40   Dmitry Torokhov   Input: evdev - co...
614
615
616
617
618
619
620
621
622
  			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 ...
623
  		len = BITS_TO_LONGS(maxbit) * sizeof(long);
3a51f7c40   Dmitry Torokhov   Input: evdev - co...
624
625
626
627
628
629
630
631
632
  		if (len > maxlen)
  			len = maxlen;
  
  		if (copy_to_user(p, bits, len))
  			return -EFAULT;
  	}
  
  	return len;
  }
06a16293f   David Herrmann   Input: evdev - ad...
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
  
  static int bits_from_user(unsigned long *bits, unsigned int maxbit,
  			  unsigned int maxlen, const void __user *p, int compat)
  {
  	int len, i;
  
  	if (compat) {
  		if (maxlen % sizeof(compat_long_t))
  			return -EINVAL;
  
  		len = BITS_TO_LONGS_COMPAT(maxbit) * sizeof(compat_long_t);
  		if (len > maxlen)
  			len = maxlen;
  
  		for (i = 0; i < len / sizeof(compat_long_t); i++)
  			if (copy_from_user((compat_long_t *) bits +
  						i + 1 - ((i % 2) << 1),
  					   (compat_long_t __user *) p + i,
  					   sizeof(compat_long_t)))
  				return -EFAULT;
  		if (i % 2)
  			*((compat_long_t *) bits + i - 1) = 0;
  
  	} else {
  		if (maxlen % sizeof(long))
  			return -EINVAL;
  
  		len = BITS_TO_LONGS(maxbit) * sizeof(long);
  		if (len > maxlen)
  			len = maxlen;
  
  		if (copy_from_user(bits, p, len))
  			return -EFAULT;
  	}
  
  	return len;
  }
3a51f7c40   Dmitry Torokhov   Input: evdev - co...
670
  #else
06a16293f   David Herrmann   Input: evdev - ad...
671

3a51f7c40   Dmitry Torokhov   Input: evdev - co...
672
673
674
675
  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 ...
676
677
  			BITS_TO_LONGS_COMPAT(maxbit) * sizeof(compat_long_t) :
  			BITS_TO_LONGS(maxbit) * sizeof(long);
3a51f7c40   Dmitry Torokhov   Input: evdev - co...
678
679
680
681
682
683
  
  	if (len > maxlen)
  		len = maxlen;
  
  	return copy_to_user(p, bits, len) ? -EFAULT : len;
  }
06a16293f   David Herrmann   Input: evdev - ad...
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
  
  static int bits_from_user(unsigned long *bits, unsigned int maxbit,
  			  unsigned int maxlen, const void __user *p, int compat)
  {
  	size_t chunk_size = compat ? sizeof(compat_long_t) : sizeof(long);
  	int len;
  
  	if (maxlen % chunk_size)
  		return -EINVAL;
  
  	len = compat ? BITS_TO_LONGS_COMPAT(maxbit) : BITS_TO_LONGS(maxbit);
  	len *= chunk_size;
  	if (len > maxlen)
  		len = maxlen;
  
  	return copy_from_user(bits, p, len) ? -EFAULT : len;
  }
3a51f7c40   Dmitry Torokhov   Input: evdev - co...
701
702
703
704
705
706
707
  #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 ...
708
  	int len = BITS_TO_LONGS(maxbit) * sizeof(long);
3a51f7c40   Dmitry Torokhov   Input: evdev - co...
709
710
711
712
713
714
  
  	if (len > maxlen)
  		len = maxlen;
  
  	return copy_to_user(p, bits, len) ? -EFAULT : len;
  }
06a16293f   David Herrmann   Input: evdev - ad...
715
716
717
718
719
720
721
722
723
724
725
726
727
728
  static int bits_from_user(unsigned long *bits, unsigned int maxbit,
  			  unsigned int maxlen, const void __user *p, int compat)
  {
  	int len;
  
  	if (maxlen % sizeof(long))
  		return -EINVAL;
  
  	len = BITS_TO_LONGS(maxbit) * sizeof(long);
  	if (len > maxlen)
  		len = maxlen;
  
  	return copy_from_user(bits, p, len) ? -EFAULT : len;
  }
3a51f7c40   Dmitry Torokhov   Input: evdev - co...
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
  #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;
  }
448cd1664   Dmitry Torokhov   Input: evdev - re...
744
745
746
  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...
747
748
749
  {
  	unsigned long *bits;
  	int len;
448cd1664   Dmitry Torokhov   Input: evdev - re...
750
  	switch (type) {
5402a7349   Linus Torvalds   Input: evdev - sp...
751
752
753
754
755
756
757
758
759
760
761
762
  
  	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...
763

448cd1664   Dmitry Torokhov   Input: evdev - re...
764
  	return bits_to_user(bits, len, size, p, compat_mode);
5402a7349   Linus Torvalds   Input: evdev - sp...
765
  }
5402a7349   Linus Torvalds   Input: evdev - sp...
766

ab4e01921   Dmitry Torokhov   Input: define sep...
767
  static int evdev_handle_get_keycode(struct input_dev *dev, void __user *p)
8613e4c28   Mauro Carvalho Chehab   Input: add suppor...
768
  {
ab4e01921   Dmitry Torokhov   Input: define sep...
769
770
771
772
773
  	struct input_keymap_entry ke = {
  		.len	= sizeof(unsigned int),
  		.flags	= 0,
  	};
  	int __user *ip = (int __user *)p;
8613e4c28   Mauro Carvalho Chehab   Input: add suppor...
774
  	int error;
ab4e01921   Dmitry Torokhov   Input: define sep...
775
776
777
  	/* legacy case */
  	if (copy_from_user(ke.scancode, p, sizeof(unsigned int)))
  		return -EFAULT;
8613e4c28   Mauro Carvalho Chehab   Input: add suppor...
778

ab4e01921   Dmitry Torokhov   Input: define sep...
779
780
781
  	error = input_get_keycode(dev, &ke);
  	if (error)
  		return error;
8613e4c28   Mauro Carvalho Chehab   Input: add suppor...
782

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

ab4e01921   Dmitry Torokhov   Input: define sep...
786
787
  	return 0;
  }
8613e4c28   Mauro Carvalho Chehab   Input: add suppor...
788

ab4e01921   Dmitry Torokhov   Input: define sep...
789
790
791
792
  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...
793

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

ab4e01921   Dmitry Torokhov   Input: define sep...
797
798
799
  	error = input_get_keycode(dev, &ke);
  	if (error)
  		return error;
8613e4c28   Mauro Carvalho Chehab   Input: add suppor...
800

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

8613e4c28   Mauro Carvalho Chehab   Input: add suppor...
804
805
  	return 0;
  }
ab4e01921   Dmitry Torokhov   Input: define sep...
806
  static int evdev_handle_set_keycode(struct input_dev *dev, void __user *p)
8613e4c28   Mauro Carvalho Chehab   Input: add suppor...
807
  {
ab4e01921   Dmitry Torokhov   Input: define sep...
808
809
810
811
812
  	struct input_keymap_entry ke = {
  		.len	= sizeof(unsigned int),
  		.flags	= 0,
  	};
  	int __user *ip = (int __user *)p;
8613e4c28   Mauro Carvalho Chehab   Input: add suppor...
813

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

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

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

ab4e01921   Dmitry Torokhov   Input: define sep...
823
824
825
  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...
826

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

ab4e01921   Dmitry Torokhov   Input: define sep...
830
831
  	if (ke.len > sizeof(ke.scancode))
  		return -EINVAL;
8613e4c28   Mauro Carvalho Chehab   Input: add suppor...
832
833
834
  
  	return input_set_keycode(dev, &ke);
  }
483180281   David Herrmann   Input: evdev - fl...
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
  /*
   * 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,
7c4f56070   Dmitry Torokhov   Input: evdev - fi...
850
851
852
  				unsigned long *bits, unsigned int maxbit,
  				unsigned int maxlen, void __user *p,
  				int compat)
483180281   David Herrmann   Input: evdev - fl...
853
854
855
  {
  	int ret;
  	unsigned long *mem;
6078091c9   Andy Shevchenko   Input: evdev - sw...
856
  	mem = bitmap_alloc(maxbit, GFP_KERNEL);
483180281   David Herrmann   Input: evdev - fl...
857
858
859
860
861
  	if (!mem)
  		return -ENOMEM;
  
  	spin_lock_irq(&dev->event_lock);
  	spin_lock(&client->buffer_lock);
6078091c9   Andy Shevchenko   Input: evdev - sw...
862
  	bitmap_copy(mem, bits, maxbit);
483180281   David Herrmann   Input: evdev - fl...
863
864
865
866
867
868
  
  	spin_unlock(&dev->event_lock);
  
  	__evdev_flush_queue(client, type);
  
  	spin_unlock_irq(&client->buffer_lock);
7c4f56070   Dmitry Torokhov   Input: evdev - fi...
869
  	ret = bits_to_user(mem, maxbit, maxlen, p, compat);
483180281   David Herrmann   Input: evdev - fl...
870
  	if (ret < 0)
b881d5377   Dmitry Torokhov   Input: evdev - do...
871
  		evdev_queue_syn_dropped(client);
483180281   David Herrmann   Input: evdev - fl...
872

6078091c9   Andy Shevchenko   Input: evdev - sw...
873
  	bitmap_free(mem);
483180281   David Herrmann   Input: evdev - fl...
874
875
876
  
  	return ret;
  }
1cf0c6e69   Henrik Rydberg   Input: Add EVIOC ...
877
878
879
880
  static int evdev_handle_mt_request(struct input_dev *dev,
  				   unsigned int size,
  				   int __user *ip)
  {
8d18fba28   Henrik Rydberg   Input: Break out ...
881
  	const struct input_mt *mt = dev->mt;
1cf0c6e69   Henrik Rydberg   Input: Add EVIOC ...
882
883
884
885
886
887
  	unsigned int code;
  	int max_slots;
  	int i;
  
  	if (get_user(code, &ip[0]))
  		return -EFAULT;
8d18fba28   Henrik Rydberg   Input: Break out ...
888
  	if (!mt || !input_is_mt_value(code))
1cf0c6e69   Henrik Rydberg   Input: Add EVIOC ...
889
890
891
  		return -EINVAL;
  
  	max_slots = (size - sizeof(__u32)) / sizeof(__s32);
8d18fba28   Henrik Rydberg   Input: Break out ...
892
893
894
  	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]))
1cf0c6e69   Henrik Rydberg   Input: Add EVIOC ...
895
  			return -EFAULT;
8d18fba28   Henrik Rydberg   Input: Break out ...
896
  	}
1cf0c6e69   Henrik Rydberg   Input: Add EVIOC ...
897
898
899
  
  	return 0;
  }
c7dc65737   David Herrmann   Input: evdev - ad...
900
901
902
903
904
905
  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);
4ba8b8aec   Kenny Levinsen   Input: evdev - pe...
906
  	wake_up_interruptible_poll(&client->wait, EPOLLHUP | EPOLLERR);
c7dc65737   David Herrmann   Input: evdev - ad...
907
908
909
  
  	return 0;
  }
06a16293f   David Herrmann   Input: evdev - ad...
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
  /* must be called with evdev-mutex held */
  static int evdev_set_mask(struct evdev_client *client,
  			  unsigned int type,
  			  const void __user *codes,
  			  u32 codes_size,
  			  int compat)
  {
  	unsigned long flags, *mask, *oldmask;
  	size_t cnt;
  	int error;
  
  	/* we allow unknown types and 'codes_size > size' for forward-compat */
  	cnt = evdev_get_mask_cnt(type);
  	if (!cnt)
  		return 0;
6078091c9   Andy Shevchenko   Input: evdev - sw...
925
  	mask = bitmap_zalloc(cnt, GFP_KERNEL);
06a16293f   David Herrmann   Input: evdev - ad...
926
927
928
929
930
  	if (!mask)
  		return -ENOMEM;
  
  	error = bits_from_user(mask, cnt - 1, codes_size, codes, compat);
  	if (error < 0) {
6078091c9   Andy Shevchenko   Input: evdev - sw...
931
  		bitmap_free(mask);
06a16293f   David Herrmann   Input: evdev - ad...
932
933
934
935
936
937
938
  		return error;
  	}
  
  	spin_lock_irqsave(&client->buffer_lock, flags);
  	oldmask = client->evmasks[type];
  	client->evmasks[type] = mask;
  	spin_unlock_irqrestore(&client->buffer_lock, flags);
6078091c9   Andy Shevchenko   Input: evdev - sw...
939
  	bitmap_free(oldmask);
06a16293f   David Herrmann   Input: evdev - ad...
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
  
  	return 0;
  }
  
  /* must be called with evdev-mutex held */
  static int evdev_get_mask(struct evdev_client *client,
  			  unsigned int type,
  			  void __user *codes,
  			  u32 codes_size,
  			  int compat)
  {
  	unsigned long *mask;
  	size_t cnt, size, xfer_size;
  	int i;
  	int error;
  
  	/* we allow unknown types and 'codes_size > size' for forward-compat */
  	cnt = evdev_get_mask_cnt(type);
  	size = sizeof(unsigned long) * BITS_TO_LONGS(cnt);
  	xfer_size = min_t(size_t, codes_size, size);
  
  	if (cnt > 0) {
  		mask = client->evmasks[type];
  		if (mask) {
  			error = bits_to_user(mask, cnt - 1,
  					     xfer_size, codes, compat);
  			if (error < 0)
  				return error;
  		} else {
  			/* fake mask with all bits set */
  			for (i = 0; i < xfer_size; i++)
  				if (put_user(0xffU, (u8 __user *)codes + i))
  					return -EFAULT;
  		}
  	}
  
  	if (xfer_size < codes_size)
  		if (clear_user(codes + xfer_size, codes_size - xfer_size))
  			return -EFAULT;
  
  	return 0;
  }
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
982
983
  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
984
  {
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
985
986
  	struct evdev_client *client = file->private_data;
  	struct evdev *evdev = client->evdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
987
988
  	struct input_dev *dev = evdev->handle.dev;
  	struct input_absinfo abs;
06a16293f   David Herrmann   Input: evdev - ad...
989
  	struct input_mask mask;
509ca1a93   Anssi Hannula   Input: implement ...
990
  	struct ff_effect effect;
3a51f7c40   Dmitry Torokhov   Input: evdev - co...
991
  	int __user *ip = (int __user *)p;
58b939959   Dmitry Torokhov   Input: scancode i...
992
  	unsigned int i, t, u, v;
448cd1664   Dmitry Torokhov   Input: evdev - re...
993
  	unsigned int size;
509ca1a93   Anssi Hannula   Input: implement ...
994
  	int error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
995

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

6addb1d6d   Dmitry Torokhov   Input: evdev - im...
1001
1002
1003
1004
  	case EVIOCGID:
  		if (copy_to_user(p, &dev->id, sizeof(struct input_id)))
  			return -EFAULT;
  		return 0;
08791e5cf   Dmitry Torokhov   Input: ressurect ...
1005

6addb1d6d   Dmitry Torokhov   Input: evdev - im...
1006
1007
1008
1009
1010
1011
1012
1013
  	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 ...
1014

6addb1d6d   Dmitry Torokhov   Input: evdev - im...
1015
1016
1017
1018
1019
1020
1021
  	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 ...
1022

6addb1d6d   Dmitry Torokhov   Input: evdev - im...
1023
1024
  		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...
1025

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

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

6addb1d6d   Dmitry Torokhov   Input: evdev - im...
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
  	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...
1043

c7dc65737   David Herrmann   Input: evdev - ad...
1044
1045
1046
1047
1048
  	case EVIOCREVOKE:
  		if (p)
  			return -EINVAL;
  		else
  			return evdev_revoke(evdev, client, file);
06a16293f   David Herrmann   Input: evdev - ad...
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
  	case EVIOCGMASK: {
  		void __user *codes_ptr;
  
  		if (copy_from_user(&mask, p, sizeof(mask)))
  			return -EFAULT;
  
  		codes_ptr = (void __user *)(unsigned long)mask.codes_ptr;
  		return evdev_get_mask(client,
  				      mask.type, codes_ptr, mask.codes_size,
  				      compat_mode);
  	}
  
  	case EVIOCSMASK: {
  		const void __user *codes_ptr;
  
  		if (copy_from_user(&mask, p, sizeof(mask)))
  			return -EFAULT;
  
  		codes_ptr = (const void __user *)(unsigned long)mask.codes_ptr;
  		return evdev_set_mask(client,
  				      mask.type, codes_ptr, mask.codes_size,
  				      compat_mode);
  	}
a80b83b7b   John Stultz   Input: add infras...
1072
1073
1074
  	case EVIOCSCLOCKID:
  		if (copy_from_user(&i, p, sizeof(unsigned int)))
  			return -EFAULT;
aac8bcf1e   Aniroop Mathur   Input: evdev - ad...
1075
1076
  
  		return evdev_set_clk_type(client, i);
a80b83b7b   John Stultz   Input: add infras...
1077

ab4e01921   Dmitry Torokhov   Input: define sep...
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
  	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...
1089
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1090

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

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

85b772003   Henrik Rydberg   Input: introduce ...
1097
1098
1099
  	case EVIOCGPROP(0):
  		return bits_to_user(dev->propbit, INPUT_PROP_MAX,
  				    size, p, compat_mode);
1cf0c6e69   Henrik Rydberg   Input: Add EVIOC ...
1100
1101
  	case EVIOCGMTSLOTS(0):
  		return evdev_handle_mt_request(dev, size, ip);
448cd1664   Dmitry Torokhov   Input: evdev - re...
1102
  	case EVIOCGKEY(0):
483180281   David Herrmann   Input: evdev - fl...
1103
1104
  		return evdev_handle_get_val(client, dev, EV_KEY, dev->key,
  					    KEY_MAX, size, p, compat_mode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1105

448cd1664   Dmitry Torokhov   Input: evdev - re...
1106
  	case EVIOCGLED(0):
483180281   David Herrmann   Input: evdev - fl...
1107
1108
  		return evdev_handle_get_val(client, dev, EV_LED, dev->led,
  					    LED_MAX, size, p, compat_mode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1109

448cd1664   Dmitry Torokhov   Input: evdev - re...
1110
  	case EVIOCGSND(0):
483180281   David Herrmann   Input: evdev - fl...
1111
1112
  		return evdev_handle_get_val(client, dev, EV_SND, dev->snd,
  					    SND_MAX, size, p, compat_mode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1113

448cd1664   Dmitry Torokhov   Input: evdev - re...
1114
  	case EVIOCGSW(0):
483180281   David Herrmann   Input: evdev - fl...
1115
1116
  		return evdev_handle_get_val(client, dev, EV_SW, dev->sw,
  					    SW_MAX, size, p, compat_mode);
315810668   Richard Purdie   [PATCH] Input: Ad...
1117

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

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

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

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

448cd1664   Dmitry Torokhov   Input: evdev - re...
1131
  		error = input_ff_upload(dev, &effect, file);
fc7392aa1   Elias Vanderstuyft   Input: don't modi...
1132
1133
  		if (error)
  			return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1134

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

fc7392aa1   Elias Vanderstuyft   Input: don't modi...
1138
  		return 0;
448cd1664   Dmitry Torokhov   Input: evdev - re...
1139
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1140

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

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

448cd1664   Dmitry Torokhov   Input: evdev - re...
1147
1148
1149
1150
  		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
1151

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

0a74a1df3   Daniel Mack   Input: evdev - fi...
1154
1155
  			if (!dev->absinfo)
  				return -EINVAL;
448cd1664   Dmitry Torokhov   Input: evdev - re...
1156
1157
  			t = _IOC_NR(cmd) & ABS_MAX;
  			abs = dev->absinfo[t];
f2278f31d   Adam Dawidowski   Input: fix force ...
1158

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

448cd1664   Dmitry Torokhov   Input: evdev - re...
1163
1164
1165
  			return 0;
  		}
  	}
f2278f31d   Adam Dawidowski   Input: fix force ...
1166

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

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

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

448cd1664   Dmitry Torokhov   Input: evdev - re...
1175
1176
1177
  			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
1178

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

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

448cd1664   Dmitry Torokhov   Input: evdev - re...
1186
1187
1188
1189
1190
1191
1192
1193
  			/*
  			 * 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...
1194

448cd1664   Dmitry Torokhov   Input: evdev - re...
1195
  			return 0;
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
1196
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1197
  	}
448cd1664   Dmitry Torokhov   Input: evdev - re...
1198

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1199
1200
  	return -EINVAL;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1201

6addb1d6d   Dmitry Torokhov   Input: evdev - im...
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
  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;
c7dc65737   David Herrmann   Input: evdev - ad...
1212
  	if (!evdev->exist || client->revoked) {
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
  		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...
1223
1224
1225
1226
  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...
1227

3a51f7c40   Dmitry Torokhov   Input: evdev - co...
1228
  #ifdef CONFIG_COMPAT
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
1229
1230
  static long evdev_ioctl_compat(struct file *file,
  				unsigned int cmd, unsigned long arg)
52658bb68   Juergen Kreileder   Input: Add suppor...
1231
  {
3a51f7c40   Dmitry Torokhov   Input: evdev - co...
1232
  	return evdev_ioctl_handler(file, cmd, compat_ptr(arg), 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1233
  }
52658bb68   Juergen Kreileder   Input: Add suppor...
1234
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1235

66e661188   Dmitry Torokhov   Input: constify i...
1236
  static const struct file_operations evdev_fops = {
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
1237
1238
1239
1240
1241
1242
1243
  	.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...
1244
  #ifdef CONFIG_COMPAT
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
1245
  	.compat_ioctl	= evdev_ioctl_compat,
52658bb68   Juergen Kreileder   Input: Add suppor...
1246
  #endif
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
1247
  	.fasync		= evdev_fasync,
6038f373a   Arnd Bergmann   llseek: automatic...
1248
  	.llseek		= no_llseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1249
  };
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
1250
1251
1252
1253
1254
1255
1256
1257
  /*
   * 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...
1258
  	evdev->exist = false;
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
1259
1260
1261
1262
1263
1264
1265
1266
1267
  	mutex_unlock(&evdev->mutex);
  }
  
  static void evdev_cleanup(struct evdev *evdev)
  {
  	struct input_handle *handle = &evdev->handle;
  
  	evdev_mark_dead(evdev);
  	evdev_hangup(evdev);
7f8d4cad1   Dmitry Torokhov   Input: extend the...
1268

6addb1d6d   Dmitry Torokhov   Input: evdev - im...
1269
1270
1271
1272
1273
1274
1275
1276
1277
  	/* 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
7f8d4cad1   Dmitry Torokhov   Input: extend the...
1278
   * to connect and disconnect.
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
1279
   */
5b2a08262   Dmitry Torokhov   Input: rework han...
1280
1281
  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
1282
1283
1284
  {
  	struct evdev *evdev;
  	int minor;
7f8d4cad1   Dmitry Torokhov   Input: extend the...
1285
  	int dev_no;
5b2a08262   Dmitry Torokhov   Input: rework han...
1286
  	int error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1287

7f8d4cad1   Dmitry Torokhov   Input: extend the...
1288
1289
1290
1291
1292
1293
  	minor = input_get_new_minor(EVDEV_MINOR_BASE, EVDEV_MINORS, true);
  	if (minor < 0) {
  		error = minor;
  		pr_err("failed to reserve new minor: %d
  ", error);
  		return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1294
  	}
5b2a08262   Dmitry Torokhov   Input: rework han...
1295
  	evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);
7f8d4cad1   Dmitry Torokhov   Input: extend the...
1296
1297
1298
1299
  	if (!evdev) {
  		error = -ENOMEM;
  		goto err_free_minor;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1300

d0ffb9be8   Dmitry Torokhov   Input: handlers -...
1301
  	INIT_LIST_HEAD(&evdev->client_list);
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
1302
1303
  	spin_lock_init(&evdev->client_lock);
  	mutex_init(&evdev->mutex);
20da92de8   Dmitry Torokhov   Input: change inp...
1304
  	evdev->exist = true;
7f8d4cad1   Dmitry Torokhov   Input: extend the...
1305
1306
1307
1308
1309
1310
  
  	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);
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
1311

a7097ff89   Dmitry Torokhov   Input: make sure ...
1312
  	evdev->handle.dev = input_get_device(dev);
3d5cb60ef   Thadeu Lima de Souza Cascardo   Input: simplify n...
1313
  	evdev->handle.name = dev_name(&evdev->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1314
1315
  	evdev->handle.handler = handler;
  	evdev->handle.private = evdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1316

7f8d4cad1   Dmitry Torokhov   Input: extend the...
1317
  	evdev->dev.devt = MKDEV(INPUT_MAJOR, minor);
9657d75c5   Dmitry Torokhov   Input: convert fr...
1318
1319
  	evdev->dev.class = &input_class;
  	evdev->dev.parent = &dev->dev;
9657d75c5   Dmitry Torokhov   Input: convert fr...
1320
1321
  	evdev->dev.release = evdev_free;
  	device_initialize(&evdev->dev);
5b2a08262   Dmitry Torokhov   Input: rework han...
1322

6addb1d6d   Dmitry Torokhov   Input: evdev - im...
1323
  	error = input_register_handle(&evdev->handle);
5b2a08262   Dmitry Torokhov   Input: rework han...
1324
  	if (error)
9657d75c5   Dmitry Torokhov   Input: convert fr...
1325
  		goto err_free_evdev;
5b2a08262   Dmitry Torokhov   Input: rework han...
1326

7f8d4cad1   Dmitry Torokhov   Input: extend the...
1327
  	cdev_init(&evdev->cdev, &evdev_fops);
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
1328

358a89ca2   Logan Gunthorpe   input: utilize ne...
1329
  	error = cdev_device_add(&evdev->cdev, &evdev->dev);
5b2a08262   Dmitry Torokhov   Input: rework han...
1330
  	if (error)
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
1331
  		goto err_cleanup_evdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1332

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

6addb1d6d   Dmitry Torokhov   Input: evdev - im...
1335
1336
   err_cleanup_evdev:
  	evdev_cleanup(evdev);
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
1337
  	input_unregister_handle(&evdev->handle);
5b2a08262   Dmitry Torokhov   Input: rework han...
1338
   err_free_evdev:
9657d75c5   Dmitry Torokhov   Input: convert fr...
1339
  	put_device(&evdev->dev);
7f8d4cad1   Dmitry Torokhov   Input: extend the...
1340
1341
   err_free_minor:
  	input_free_minor(minor);
5b2a08262   Dmitry Torokhov   Input: rework han...
1342
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1343
1344
1345
1346
1347
  }
  
  static void evdev_disconnect(struct input_handle *handle)
  {
  	struct evdev *evdev = handle->private;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1348

358a89ca2   Logan Gunthorpe   input: utilize ne...
1349
  	cdev_device_del(&evdev->cdev, &evdev->dev);
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
1350
  	evdev_cleanup(evdev);
7f8d4cad1   Dmitry Torokhov   Input: extend the...
1351
  	input_free_minor(MINOR(evdev->dev.devt));
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
1352
  	input_unregister_handle(handle);
9657d75c5   Dmitry Torokhov   Input: convert fr...
1353
  	put_device(&evdev->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1354
  }
66e661188   Dmitry Torokhov   Input: constify i...
1355
  static const struct input_device_id evdev_ids[] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1356
1357
1358
1359
1360
1361
1362
  	{ .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...
1363
  	.event		= evdev_event,
a274ac15e   Henrik Rydberg   Input: evdev - Ad...
1364
  	.events		= evdev_events,
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
1365
1366
  	.connect	= evdev_connect,
  	.disconnect	= evdev_disconnect,
7f8d4cad1   Dmitry Torokhov   Input: extend the...
1367
  	.legacy_minors	= true,
6addb1d6d   Dmitry Torokhov   Input: evdev - im...
1368
1369
1370
  	.minor		= EVDEV_MINOR_BASE,
  	.name		= "evdev",
  	.id_table	= evdev_ids,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1371
1372
1373
1374
  };
  
  static int __init evdev_init(void)
  {
4263cf0fa   Dmitry Torokhov   Input: make input...
1375
  	return input_register_handler(&evdev_handler);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
  }
  
  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");