Blame view
drivers/input/evdev.c
32.4 KB
d2912cb15 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-only |
1da177e4c 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 Linux-2.6.12-rc2 |
6 |
*/ |
da0c49011 Input: use pr_fmt... |
7 |
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
1da177e4c Linux-2.6.12-rc2 |
8 9 |
#define EVDEV_MINOR_BASE 64 #define EVDEV_MINORS 32 |
63a6404d8 Input: evdev - us... |
10 11 |
#define EVDEV_MIN_BUFFER_SIZE 64U #define EVDEV_BUF_PACKETS 8 |
1da177e4c Linux-2.6.12-rc2 |
12 13 |
#include <linux/poll.h> |
a99bbaf5e headers: remove s... |
14 |
#include <linux/sched.h> |
1da177e4c Linux-2.6.12-rc2 |
15 |
#include <linux/slab.h> |
92eb77d0f Input: evdev - fa... |
16 17 |
#include <linux/vmalloc.h> #include <linux/mm.h> |
1da177e4c Linux-2.6.12-rc2 |
18 19 |
#include <linux/module.h> #include <linux/init.h> |
1cf0c6e69 Input: Add EVIOC ... |
20 |
#include <linux/input/mt.h> |
1da177e4c Linux-2.6.12-rc2 |
21 |
#include <linux/major.h> |
1da177e4c Linux-2.6.12-rc2 |
22 |
#include <linux/device.h> |
7f8d4cad1 Input: extend the... |
23 |
#include <linux/cdev.h> |
2d56f3a32 Input: refactor e... |
24 |
#include "input-compat.h" |
1da177e4c Linux-2.6.12-rc2 |
25 26 |
struct evdev { |
1da177e4c Linux-2.6.12-rc2 |
27 |
int open; |
1da177e4c Linux-2.6.12-rc2 |
28 |
struct input_handle handle; |
2be852792 input: __rcu anno... |
29 |
struct evdev_client __rcu *grab; |
d0ffb9be8 Input: handlers -... |
30 |
struct list_head client_list; |
6addb1d6d Input: evdev - im... |
31 32 |
spinlock_t client_lock; /* protects client_list */ struct mutex mutex; |
9657d75c5 Input: convert fr... |
33 |
struct device dev; |
7f8d4cad1 Input: extend the... |
34 |
struct cdev cdev; |
20da92de8 Input: change inp... |
35 |
bool exist; |
1da177e4c Linux-2.6.12-rc2 |
36 |
}; |
d0ffb9be8 Input: handlers -... |
37 |
struct evdev_client { |
9fb0f14e3 Input: evdev - in... |
38 39 |
unsigned int head; unsigned int tail; |
cdda911c3 Input: evdev - on... |
40 |
unsigned int packet_head; /* [future] position of the first element of next packet */ |
6addb1d6d Input: evdev - im... |
41 |
spinlock_t buffer_lock; /* protects access to buffer, head and tail */ |
4ba8b8aec Input: evdev - pe... |
42 |
wait_queue_head_t wait; |
1da177e4c Linux-2.6.12-rc2 |
43 44 45 |
struct fasync_struct *fasync; struct evdev *evdev; struct list_head node; |
3b51c44bd Input: allow driv... |
46 |
enum input_clock_type clk_type; |
c7dc65737 Input: evdev - ad... |
47 |
bool revoked; |
06a16293f Input: evdev - ad... |
48 |
unsigned long *evmasks[EV_CNT]; |
9fb0f14e3 Input: evdev - in... |
49 |
unsigned int bufsize; |
b58f7086d Input: evdev - co... |
50 |
struct input_event buffer[]; |
1da177e4c Linux-2.6.12-rc2 |
51 |
}; |
06a16293f 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 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 Input: extend usa... |
123 |
client->buffer[head] = *ev; |
483180281 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 Input: evdev - do... |
137 |
static void __evdev_queue_syn_dropped(struct evdev_client *client) |
483180281 Input: evdev - fl... |
138 |
{ |
3b51c44bd 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 Input: evdev - fl... |
141 |
struct input_event ev; |
483180281 Input: evdev - fl... |
142 |
|
152194fe9 Input: extend usa... |
143 144 |
ev.input_event_sec = ts.tv_sec; ev.input_event_usec = ts.tv_nsec / NSEC_PER_USEC; |
483180281 Input: evdev - fl... |
145 146 147 |
ev.type = EV_SYN; ev.code = SYN_DROPPED; ev.value = 0; |
483180281 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 Input: evdev - do... |
156 157 158 159 160 |
} static void evdev_queue_syn_dropped(struct evdev_client *client) { unsigned long flags; |
483180281 Input: evdev - fl... |
161 |
|
b881d5377 Input: evdev - do... |
162 163 |
spin_lock_irqsave(&client->buffer_lock, flags); __evdev_queue_syn_dropped(client); |
483180281 Input: evdev - fl... |
164 165 |
spin_unlock_irqrestore(&client->buffer_lock, flags); } |
0c3e99437 Input: evdev - fl... |
166 167 |
static int evdev_set_clk_type(struct evdev_client *client, unsigned int clkid) { |
b881d5377 Input: evdev - do... |
168 |
unsigned long flags; |
3b51c44bd Input: allow driv... |
169 |
enum input_clock_type clk_type; |
0c3e99437 Input: evdev - fl... |
170 171 172 173 |
switch (clkid) { case CLOCK_REALTIME: |
3b51c44bd Input: allow driv... |
174 |
clk_type = INPUT_CLK_REAL; |
0c3e99437 Input: evdev - fl... |
175 176 |
break; case CLOCK_MONOTONIC: |
3b51c44bd Input: allow driv... |
177 |
clk_type = INPUT_CLK_MONO; |
0c3e99437 Input: evdev - fl... |
178 179 |
break; case CLOCK_BOOTTIME: |
3b51c44bd Input: allow driv... |
180 |
clk_type = INPUT_CLK_BOOT; |
0c3e99437 Input: evdev - fl... |
181 182 183 184 |
break; default: return -EINVAL; } |
bf5f18d70 Input: evdev - fi... |
185 186 |
if (client->clk_type != clk_type) { client->clk_type = clk_type; |
b881d5377 Input: evdev - do... |
187 |
|
bf5f18d70 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 Input: evdev - do... |
193 |
|
bf5f18d70 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 Input: evdev - fl... |
201 202 203 |
return 0; } |
a274ac15e Input: evdev - Ad... |
204 205 |
static void __pass_event(struct evdev_client *client, const struct input_event *event) |
6addb1d6d Input: evdev - im... |
206 |
{ |
9fb0f14e3 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 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 Input: evdev - in... |
223 |
|
cdda911c3 Input: evdev - on... |
224 225 |
client->packet_head = client->tail; } |
6addb1d6d Input: evdev - im... |
226 |
|
cdda911c3 Input: evdev - on... |
227 228 |
if (event->type == EV_SYN && event->code == SYN_REPORT) { client->packet_head = client->head; |
30a589fde Input: evdev - be... |
229 |
kill_fasync(&client->fasync, SIGIO, POLL_IN); |
cdda911c3 Input: evdev - on... |
230 |
} |
a274ac15e 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 Input: evdev - ad... |
235 |
ktime_t *ev_time) |
a274ac15e Input: evdev - Ad... |
236 |
{ |
a274ac15e Input: evdev - Ad... |
237 238 |
const struct input_value *v; struct input_event event; |
152194fe9 Input: extend usa... |
239 |
struct timespec64 ts; |
a274ac15e Input: evdev - Ad... |
240 |
bool wakeup = false; |
c7dc65737 Input: evdev - ad... |
241 242 |
if (client->revoked) return; |
152194fe9 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 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 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 Input: evdev - Ad... |
261 262 263 264 |
event.type = v->type; event.code = v->code; event.value = v->value; __pass_event(client, &event); |
a274ac15e Input: evdev - Ad... |
265 |
} |
cdda911c3 Input: evdev - on... |
266 267 |
spin_unlock(&client->buffer_lock); |
a274ac15e Input: evdev - Ad... |
268 269 |
if (wakeup) |
4ba8b8aec Input: evdev - pe... |
270 |
wake_up_interruptible_poll(&client->wait, |
81b4d1d22 Input: evdev - us... |
271 |
EPOLLIN | EPOLLOUT | EPOLLRDNORM | EPOLLWRNORM); |
6addb1d6d Input: evdev - im... |
272 273 274 |
} /* |
a274ac15e Input: evdev - Ad... |
275 |
* Pass incoming events to all connected clients. |
6addb1d6d Input: evdev - im... |
276 |
*/ |
a274ac15e Input: evdev - Ad... |
277 278 |
static void evdev_events(struct input_handle *handle, const struct input_value *vals, unsigned int count) |
1da177e4c Linux-2.6.12-rc2 |
279 280 |
{ struct evdev *evdev = handle->private; |
d0ffb9be8 Input: handlers -... |
281 |
struct evdev_client *client; |
3b51c44bd Input: allow driv... |
282 |
ktime_t *ev_time = input_get_timestamp(handle->dev); |
1da177e4c Linux-2.6.12-rc2 |
283 |
|
82ba56c27 Input: use full R... |
284 |
rcu_read_lock(); |
6addb1d6d Input: evdev - im... |
285 |
client = rcu_dereference(evdev->grab); |
a80b83b7b Input: add infras... |
286 |
|
6addb1d6d Input: evdev - im... |
287 |
if (client) |
aac8bcf1e Input: evdev - ad... |
288 |
evdev_pass_values(client, vals, count, ev_time); |
6addb1d6d Input: evdev - im... |
289 290 |
else list_for_each_entry_rcu(client, &evdev->client_list, node) |
aac8bcf1e Input: evdev - ad... |
291 |
evdev_pass_values(client, vals, count, ev_time); |
1da177e4c Linux-2.6.12-rc2 |
292 |
|
82ba56c27 Input: use full R... |
293 |
rcu_read_unlock(); |
a274ac15e Input: evdev - Ad... |
294 |
} |
82ba56c27 Input: use full R... |
295 |
|
a274ac15e 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 Linux-2.6.12-rc2 |
305 306 307 308 |
} static int evdev_fasync(int fd, struct file *file, int on) { |
d0ffb9be8 Input: handlers -... |
309 |
struct evdev_client *client = file->private_data; |
1e0afb288 Input: fix format... |
310 |
|
60aa49243 Rationalize fasyn... |
311 |
return fasync_helper(fd, file, on, &client->fasync); |
1da177e4c Linux-2.6.12-rc2 |
312 |
} |
9657d75c5 Input: convert fr... |
313 |
static void evdev_free(struct device *dev) |
1da177e4c Linux-2.6.12-rc2 |
314 |
{ |
9657d75c5 Input: convert fr... |
315 |
struct evdev *evdev = container_of(dev, struct evdev, dev); |
a7097ff89 Input: make sure ... |
316 |
input_put_device(evdev->handle.dev); |
1da177e4c Linux-2.6.12-rc2 |
317 318 |
kfree(evdev); } |
6addb1d6d 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 Input: evdev - im... |
335 336 337 338 339 340 |
return 0; } static int evdev_ungrab(struct evdev *evdev, struct evdev_client *client) { |
dba425806 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 Input: evdev - im... |
345 346 347 |
return -EINVAL; rcu_assign_pointer(evdev->grab, NULL); |
82ba56c27 Input: use full R... |
348 |
synchronize_rcu(); |
6addb1d6d 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 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 Input: use full R... |
368 |
synchronize_rcu(); |
6addb1d6d 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 Input: fix open c... |
381 |
else if (!evdev->open++) { |
6addb1d6d Input: evdev - im... |
382 |
retval = input_open_device(&evdev->handle); |
064450140 Input: fix open c... |
383 384 385 |
if (retval) evdev->open--; } |
6addb1d6d 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 Input: evdev - pe... |
410 |
list_for_each_entry(client, &evdev->client_list, node) { |
6addb1d6d Input: evdev - im... |
411 |
kill_fasync(&client->fasync, SIGIO, POLL_HUP); |
4ba8b8aec Input: evdev - pe... |
412 413 |
wake_up_interruptible_poll(&client->wait, EPOLLHUP | EPOLLERR); } |
6addb1d6d Input: evdev - im... |
414 |
spin_unlock(&evdev->client_lock); |
6addb1d6d Input: evdev - im... |
415 |
} |
d0ffb9be8 Input: handlers -... |
416 |
static int evdev_release(struct inode *inode, struct file *file) |
1da177e4c Linux-2.6.12-rc2 |
417 |
{ |
d0ffb9be8 Input: handlers -... |
418 419 |
struct evdev_client *client = file->private_data; struct evdev *evdev = client->evdev; |
06a16293f Input: evdev - ad... |
420 |
unsigned int i; |
1da177e4c Linux-2.6.12-rc2 |
421 |
|
6addb1d6d Input: evdev - im... |
422 |
mutex_lock(&evdev->mutex); |
09264098f Input: evdev - ca... |
423 424 425 |
if (evdev->exist && !client->revoked) input_flush_device(&evdev->handle, file); |
dba425806 Input: evdev - pr... |
426 |
evdev_ungrab(evdev, client); |
6addb1d6d Input: evdev - im... |
427 |
mutex_unlock(&evdev->mutex); |
1da177e4c Linux-2.6.12-rc2 |
428 |
|
6addb1d6d Input: evdev - im... |
429 |
evdev_detach_client(evdev, client); |
92eb77d0f Input: evdev - fa... |
430 |
|
06a16293f Input: evdev - ad... |
431 |
for (i = 0; i < EV_CNT; ++i) |
6078091c9 Input: evdev - sw... |
432 |
bitmap_free(client->evmasks[i]); |
06a16293f Input: evdev - ad... |
433 |
|
67367fd25 Input: evdev - us... |
434 |
kvfree(client); |
1da177e4c Linux-2.6.12-rc2 |
435 |
|
6addb1d6d Input: evdev - im... |
436 |
evdev_close_device(evdev); |
1da177e4c Linux-2.6.12-rc2 |
437 |
|
1da177e4c Linux-2.6.12-rc2 |
438 439 |
return 0; } |
b58f7086d Input: evdev - co... |
440 441 |
static unsigned int evdev_compute_buffer_size(struct input_dev *dev) { |
63a6404d8 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 Input: evdev - co... |
447 |
} |
d0ffb9be8 Input: handlers -... |
448 |
static int evdev_open(struct inode *inode, struct file *file) |
1da177e4c Linux-2.6.12-rc2 |
449 |
{ |
7f8d4cad1 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 Input: evdev - im... |
452 |
struct evdev_client *client; |
d542ed82f Input: handlers -... |
453 |
int error; |
1da177e4c Linux-2.6.12-rc2 |
454 |
|
7f439bc2d Input: evdev - co... |
455 |
client = kvzalloc(struct_size(client, buffer, bufsize), GFP_KERNEL); |
7f8d4cad1 Input: extend the... |
456 457 |
if (!client) return -ENOMEM; |
1da177e4c Linux-2.6.12-rc2 |
458 |
|
4ba8b8aec Input: evdev - pe... |
459 |
init_waitqueue_head(&client->wait); |
b58f7086d Input: evdev - co... |
460 |
client->bufsize = bufsize; |
6addb1d6d Input: evdev - im... |
461 |
spin_lock_init(&client->buffer_lock); |
d0ffb9be8 Input: handlers -... |
462 |
client->evdev = evdev; |
6addb1d6d Input: evdev - im... |
463 |
evdev_attach_client(evdev, client); |
1da177e4c Linux-2.6.12-rc2 |
464 |
|
6addb1d6d Input: evdev - im... |
465 466 467 |
error = evdev_open_device(evdev); if (error) goto err_free_client; |
1da177e4c Linux-2.6.12-rc2 |
468 |
|
d0ffb9be8 Input: handlers -... |
469 |
file->private_data = client; |
c5bf68fe0 *: convert stream... |
470 |
stream_open(inode, file); |
3d7bbd457 Input: mark input... |
471 |
|
1da177e4c Linux-2.6.12-rc2 |
472 |
return 0; |
9657d75c5 Input: convert fr... |
473 474 |
err_free_client: |
6addb1d6d Input: evdev - im... |
475 |
evdev_detach_client(evdev, client); |
92788ac1e drivers/input/evd... |
476 |
kvfree(client); |
9657d75c5 Input: convert fr... |
477 |
return error; |
1da177e4c Linux-2.6.12-rc2 |
478 |
} |
6addb1d6d Input: evdev - im... |
479 480 |
static ssize_t evdev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) |
3a51f7c40 Input: evdev - co... |
481 |
{ |
d0ffb9be8 Input: handlers -... |
482 483 |
struct evdev_client *client = file->private_data; struct evdev *evdev = client->evdev; |
3a51f7c40 Input: evdev - co... |
484 |
struct input_event event; |
02dfc4968 Input: evdev - fi... |
485 |
int retval = 0; |
52658bb68 Input: Add suppor... |
486 |
|
2872a9b52 Input: evdev - pr... |
487 |
if (count != 0 && count < input_event_size()) |
439581ec0 Input: evdev - fi... |
488 |
return -EINVAL; |
6addb1d6d Input: evdev - im... |
489 490 491 |
retval = mutex_lock_interruptible(&evdev->mutex); if (retval) return retval; |
c7dc65737 Input: evdev - ad... |
492 |
if (!evdev->exist || client->revoked) { |
6addb1d6d Input: evdev - im... |
493 494 495 |
retval = -ENODEV; goto out; } |
52658bb68 Input: Add suppor... |
496 |
|
2872a9b52 Input: evdev - pr... |
497 |
while (retval + input_event_size() <= count) { |
2d56f3a32 Input: refactor e... |
498 |
if (input_event_from_user(buffer + retval, &event)) { |
6addb1d6d Input: evdev - im... |
499 500 501 |
retval = -EFAULT; goto out; } |
439581ec0 Input: evdev - fi... |
502 |
retval += input_event_size(); |
6addb1d6d Input: evdev - im... |
503 504 505 |
input_inject_event(&evdev->handle, event.type, event.code, event.value); |
36d2582ff Input: evdev - ad... |
506 |
cond_resched(); |
2872a9b52 Input: evdev - pr... |
507 |
} |
52658bb68 Input: Add suppor... |
508 |
|
6addb1d6d Input: evdev - im... |
509 510 |
out: mutex_unlock(&evdev->mutex); |
52658bb68 Input: Add suppor... |
511 512 |
return retval; } |
52658bb68 Input: Add suppor... |
513 |
|
6addb1d6d 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 Input: evdev - on... |
520 |
have_event = client->packet_head != client->tail; |
6addb1d6d Input: evdev - im... |
521 522 |
if (have_event) { *event = client->buffer[client->tail++]; |
b58f7086d Input: evdev - co... |
523 |
client->tail &= client->bufsize - 1; |
6addb1d6d 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 Linux-2.6.12-rc2 |
533 |
{ |
d0ffb9be8 Input: handlers -... |
534 535 |
struct evdev_client *client = file->private_data; struct evdev *evdev = client->evdev; |
6addb1d6d Input: evdev - im... |
536 |
struct input_event event; |
2872a9b52 Input: evdev - pr... |
537 538 |
size_t read = 0; int error; |
1da177e4c Linux-2.6.12-rc2 |
539 |
|
2872a9b52 Input: evdev - pr... |
540 |
if (count != 0 && count < input_event_size()) |
1da177e4c Linux-2.6.12-rc2 |
541 |
return -EINVAL; |
2872a9b52 Input: evdev - pr... |
542 |
for (;;) { |
c7dc65737 Input: evdev - ad... |
543 |
if (!evdev->exist || client->revoked) |
2872a9b52 Input: evdev - pr... |
544 |
return -ENODEV; |
1da177e4c Linux-2.6.12-rc2 |
545 |
|
2872a9b52 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 Linux-2.6.12-rc2 |
556 |
|
2872a9b52 Input: evdev - pr... |
557 558 |
while (read + input_event_size() <= count && evdev_fetch_next_event(client, &event)) { |
3a51f7c40 Input: evdev - co... |
559 |
|
2872a9b52 Input: evdev - pr... |
560 561 |
if (input_event_to_user(buffer + read, &event)) return -EFAULT; |
3a51f7c40 Input: evdev - co... |
562 |
|
2872a9b52 Input: evdev - pr... |
563 564 |
read += input_event_size(); } |
1da177e4c Linux-2.6.12-rc2 |
565 |
|
2872a9b52 Input: evdev - pr... |
566 567 |
if (read) break; |
e90f869ca Input: evdev - if... |
568 |
|
2872a9b52 Input: evdev - pr... |
569 |
if (!(file->f_flags & O_NONBLOCK)) { |
4ba8b8aec Input: evdev - pe... |
570 |
error = wait_event_interruptible(client->wait, |
2872a9b52 Input: evdev - pr... |
571 |
client->packet_head != client->tail || |
c7dc65737 Input: evdev - ad... |
572 |
!evdev->exist || client->revoked); |
2872a9b52 Input: evdev - pr... |
573 574 575 576 577 578 |
if (error) return error; } } return read; |
1da177e4c Linux-2.6.12-rc2 |
579 580 581 |
} /* No kernel lock - fine */ |
afc9a42b7 the rest of drive... |
582 |
static __poll_t evdev_poll(struct file *file, poll_table *wait) |
1da177e4c Linux-2.6.12-rc2 |
583 |
{ |
d0ffb9be8 Input: handlers -... |
584 585 |
struct evdev_client *client = file->private_data; struct evdev *evdev = client->evdev; |
afc9a42b7 the rest of drive... |
586 |
__poll_t mask; |
1e0afb288 Input: fix format... |
587 |
|
4ba8b8aec Input: evdev - pe... |
588 |
poll_wait(file, &client->wait, wait); |
c18fb1396 Input: evdev - si... |
589 |
|
c7dc65737 Input: evdev - ad... |
590 |
if (evdev->exist && !client->revoked) |
a9a08845e vfs: do bulk POLL... |
591 |
mask = EPOLLOUT | EPOLLWRNORM; |
c7dc65737 Input: evdev - ad... |
592 |
else |
a9a08845e vfs: do bulk POLL... |
593 |
mask = EPOLLHUP | EPOLLERR; |
c7dc65737 Input: evdev - ad... |
594 |
|
cdda911c3 Input: evdev - on... |
595 |
if (client->packet_head != client->tail) |
a9a08845e vfs: do bulk POLL... |
596 |
mask |= EPOLLIN | EPOLLRDNORM; |
c18fb1396 Input: evdev - si... |
597 598 |
return mask; |
1da177e4c Linux-2.6.12-rc2 |
599 |
} |
3a51f7c40 Input: evdev - co... |
600 601 602 |
#ifdef CONFIG_COMPAT #define BITS_PER_LONG_COMPAT (sizeof(compat_long_t) * 8) |
7b19ada2e get rid of input ... |
603 |
#define BITS_TO_LONGS_COMPAT(x) ((((x) - 1) / BITS_PER_LONG_COMPAT) + 1) |
3a51f7c40 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 get rid of input ... |
612 |
len = BITS_TO_LONGS_COMPAT(maxbit) * sizeof(compat_long_t); |
bf61f8d35 Input: evdev - fi... |
613 |
if (len > maxlen) |
3a51f7c40 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 get rid of input ... |
623 |
len = BITS_TO_LONGS(maxbit) * sizeof(long); |
3a51f7c40 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 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 Input: evdev - co... |
670 |
#else |
06a16293f Input: evdev - ad... |
671 |
|
3a51f7c40 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 get rid of input ... |
676 677 |
BITS_TO_LONGS_COMPAT(maxbit) * sizeof(compat_long_t) : BITS_TO_LONGS(maxbit) * sizeof(long); |
3a51f7c40 Input: evdev - co... |
678 679 680 681 682 683 |
if (len > maxlen) len = maxlen; return copy_to_user(p, bits, len) ? -EFAULT : len; } |
06a16293f 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 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 get rid of input ... |
708 |
int len = BITS_TO_LONGS(maxbit) * sizeof(long); |
3a51f7c40 Input: evdev - co... |
709 710 711 712 713 714 |
if (len > maxlen) len = maxlen; return copy_to_user(p, bits, len) ? -EFAULT : len; } |
06a16293f 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 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 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 Input: evdev - sp... |
747 748 749 |
{ unsigned long *bits; int len; |
448cd1664 Input: evdev - re... |
750 |
switch (type) { |
5402a7349 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 Input: paper over... |
763 |
|
448cd1664 Input: evdev - re... |
764 |
return bits_to_user(bits, len, size, p, compat_mode); |
5402a7349 Input: evdev - sp... |
765 |
} |
5402a7349 Input: evdev - sp... |
766 |
|
ab4e01921 Input: define sep... |
767 |
static int evdev_handle_get_keycode(struct input_dev *dev, void __user *p) |
8613e4c28 Input: add suppor... |
768 |
{ |
ab4e01921 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 Input: add suppor... |
774 |
int error; |
ab4e01921 Input: define sep... |
775 776 777 |
/* legacy case */ if (copy_from_user(ke.scancode, p, sizeof(unsigned int))) return -EFAULT; |
8613e4c28 Input: add suppor... |
778 |
|
ab4e01921 Input: define sep... |
779 780 781 |
error = input_get_keycode(dev, &ke); if (error) return error; |
8613e4c28 Input: add suppor... |
782 |
|
ab4e01921 Input: define sep... |
783 784 |
if (put_user(ke.keycode, ip + 1)) return -EFAULT; |
8613e4c28 Input: add suppor... |
785 |
|
ab4e01921 Input: define sep... |
786 787 |
return 0; } |
8613e4c28 Input: add suppor... |
788 |
|
ab4e01921 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 Input: add suppor... |
793 |
|
ab4e01921 Input: define sep... |
794 795 |
if (copy_from_user(&ke, p, sizeof(ke))) return -EFAULT; |
8613e4c28 Input: add suppor... |
796 |
|
ab4e01921 Input: define sep... |
797 798 799 |
error = input_get_keycode(dev, &ke); if (error) return error; |
8613e4c28 Input: add suppor... |
800 |
|
ab4e01921 Input: define sep... |
801 802 |
if (copy_to_user(p, &ke, sizeof(ke))) return -EFAULT; |
8613e4c28 Input: add suppor... |
803 |
|
8613e4c28 Input: add suppor... |
804 805 |
return 0; } |
ab4e01921 Input: define sep... |
806 |
static int evdev_handle_set_keycode(struct input_dev *dev, void __user *p) |
8613e4c28 Input: add suppor... |
807 |
{ |
ab4e01921 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 Input: add suppor... |
813 |
|
ab4e01921 Input: define sep... |
814 815 |
if (copy_from_user(ke.scancode, p, sizeof(unsigned int))) return -EFAULT; |
8613e4c28 Input: add suppor... |
816 |
|
ab4e01921 Input: define sep... |
817 818 |
if (get_user(ke.keycode, ip + 1)) return -EFAULT; |
8613e4c28 Input: add suppor... |
819 |
|
ab4e01921 Input: define sep... |
820 821 |
return input_set_keycode(dev, &ke); } |
8613e4c28 Input: add suppor... |
822 |
|
ab4e01921 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 Input: add suppor... |
826 |
|
ab4e01921 Input: define sep... |
827 828 |
if (copy_from_user(&ke, p, sizeof(ke))) return -EFAULT; |
8613e4c28 Input: add suppor... |
829 |
|
ab4e01921 Input: define sep... |
830 831 |
if (ke.len > sizeof(ke.scancode)) return -EINVAL; |
8613e4c28 Input: add suppor... |
832 833 834 |
return input_set_keycode(dev, &ke); } |
483180281 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 Input: evdev - fi... |
850 851 852 |
unsigned long *bits, unsigned int maxbit, unsigned int maxlen, void __user *p, int compat) |
483180281 Input: evdev - fl... |
853 854 855 |
{ int ret; unsigned long *mem; |
6078091c9 Input: evdev - sw... |
856 |
mem = bitmap_alloc(maxbit, GFP_KERNEL); |
483180281 Input: evdev - fl... |
857 858 859 860 861 |
if (!mem) return -ENOMEM; spin_lock_irq(&dev->event_lock); spin_lock(&client->buffer_lock); |
6078091c9 Input: evdev - sw... |
862 |
bitmap_copy(mem, bits, maxbit); |
483180281 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 Input: evdev - fi... |
869 |
ret = bits_to_user(mem, maxbit, maxlen, p, compat); |
483180281 Input: evdev - fl... |
870 |
if (ret < 0) |
b881d5377 Input: evdev - do... |
871 |
evdev_queue_syn_dropped(client); |
483180281 Input: evdev - fl... |
872 |
|
6078091c9 Input: evdev - sw... |
873 |
bitmap_free(mem); |
483180281 Input: evdev - fl... |
874 875 876 |
return ret; } |
1cf0c6e69 Input: Add EVIOC ... |
877 878 879 880 |
static int evdev_handle_mt_request(struct input_dev *dev, unsigned int size, int __user *ip) { |
8d18fba28 Input: Break out ... |
881 |
const struct input_mt *mt = dev->mt; |
1cf0c6e69 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 Input: Break out ... |
888 |
if (!mt || !input_is_mt_value(code)) |
1cf0c6e69 Input: Add EVIOC ... |
889 890 891 |
return -EINVAL; max_slots = (size - sizeof(__u32)) / sizeof(__s32); |
8d18fba28 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 Input: Add EVIOC ... |
895 |
return -EFAULT; |
8d18fba28 Input: Break out ... |
896 |
} |
1cf0c6e69 Input: Add EVIOC ... |
897 898 899 |
return 0; } |
c7dc65737 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 Input: evdev - pe... |
906 |
wake_up_interruptible_poll(&client->wait, EPOLLHUP | EPOLLERR); |
c7dc65737 Input: evdev - ad... |
907 908 909 |
return 0; } |
06a16293f 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 Input: evdev - sw... |
925 |
mask = bitmap_zalloc(cnt, GFP_KERNEL); |
06a16293f 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 Input: evdev - sw... |
931 |
bitmap_free(mask); |
06a16293f 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 Input: evdev - sw... |
939 |
bitmap_free(oldmask); |
06a16293f 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 Input: evdev - im... |
982 983 |
static long evdev_do_ioctl(struct file *file, unsigned int cmd, void __user *p, int compat_mode) |
1da177e4c Linux-2.6.12-rc2 |
984 |
{ |
d0ffb9be8 Input: handlers -... |
985 986 |
struct evdev_client *client = file->private_data; struct evdev *evdev = client->evdev; |
1da177e4c Linux-2.6.12-rc2 |
987 988 |
struct input_dev *dev = evdev->handle.dev; struct input_absinfo abs; |
06a16293f Input: evdev - ad... |
989 |
struct input_mask mask; |
509ca1a93 Input: implement ... |
990 |
struct ff_effect effect; |
3a51f7c40 Input: evdev - co... |
991 |
int __user *ip = (int __user *)p; |
58b939959 Input: scancode i... |
992 |
unsigned int i, t, u, v; |
448cd1664 Input: evdev - re... |
993 |
unsigned int size; |
509ca1a93 Input: implement ... |
994 |
int error; |
1da177e4c Linux-2.6.12-rc2 |
995 |
|
448cd1664 Input: evdev - re... |
996 |
/* First we check for fixed-length commands */ |
1da177e4c Linux-2.6.12-rc2 |
997 |
switch (cmd) { |
6addb1d6d Input: evdev - im... |
998 999 |
case EVIOCGVERSION: return put_user(EV_VERSION, ip); |
1da177e4c Linux-2.6.12-rc2 |
1000 |
|
6addb1d6d 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 Input: ressurect ... |
1005 |
|
6addb1d6d 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 Input: ressurect ... |
1014 |
|
6addb1d6d 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 Input: ressurect ... |
1022 |
|
6addb1d6d 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 Input: evdev - co... |
1025 |
|
6addb1d6d Input: evdev - im... |
1026 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
1027 |
|
6addb1d6d Input: evdev - im... |
1028 1029 |
case EVIOCRMFF: return input_ff_erase(dev, (int)(unsigned long) p, file); |
1da177e4c Linux-2.6.12-rc2 |
1030 |
|
6addb1d6d 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 Input: define sep... |
1043 |
|
c7dc65737 Input: evdev - ad... |
1044 1045 1046 1047 1048 |
case EVIOCREVOKE: if (p) return -EINVAL; else return evdev_revoke(evdev, client, file); |
06a16293f 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 Input: add infras... |
1072 1073 1074 |
case EVIOCSCLOCKID: if (copy_from_user(&i, p, sizeof(unsigned int))) return -EFAULT; |
aac8bcf1e Input: evdev - ad... |
1075 1076 |
return evdev_set_clk_type(client, i); |
a80b83b7b Input: add infras... |
1077 |
|
ab4e01921 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 Input: evdev - re... |
1089 |
} |
1da177e4c Linux-2.6.12-rc2 |
1090 |
|
448cd1664 Input: evdev - re... |
1091 |
size = _IOC_SIZE(cmd); |
1da177e4c Linux-2.6.12-rc2 |
1092 |
|
448cd1664 Input: evdev - re... |
1093 1094 |
/* Now check variable-length commands */ #define EVIOC_MASK_SIZE(nr) ((nr) & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) |
448cd1664 Input: evdev - re... |
1095 |
switch (EVIOC_MASK_SIZE(cmd)) { |
41e979f82 Input: Make EVIOS... |
1096 |
|
85b772003 Input: introduce ... |
1097 1098 1099 |
case EVIOCGPROP(0): return bits_to_user(dev->propbit, INPUT_PROP_MAX, size, p, compat_mode); |
1cf0c6e69 Input: Add EVIOC ... |
1100 1101 |
case EVIOCGMTSLOTS(0): return evdev_handle_mt_request(dev, size, ip); |
448cd1664 Input: evdev - re... |
1102 |
case EVIOCGKEY(0): |
483180281 Input: evdev - fl... |
1103 1104 |
return evdev_handle_get_val(client, dev, EV_KEY, dev->key, KEY_MAX, size, p, compat_mode); |
1da177e4c Linux-2.6.12-rc2 |
1105 |
|
448cd1664 Input: evdev - re... |
1106 |
case EVIOCGLED(0): |
483180281 Input: evdev - fl... |
1107 1108 |
return evdev_handle_get_val(client, dev, EV_LED, dev->led, LED_MAX, size, p, compat_mode); |
1da177e4c Linux-2.6.12-rc2 |
1109 |
|
448cd1664 Input: evdev - re... |
1110 |
case EVIOCGSND(0): |
483180281 Input: evdev - fl... |
1111 1112 |
return evdev_handle_get_val(client, dev, EV_SND, dev->snd, SND_MAX, size, p, compat_mode); |
1da177e4c Linux-2.6.12-rc2 |
1113 |
|
448cd1664 Input: evdev - re... |
1114 |
case EVIOCGSW(0): |
483180281 Input: evdev - fl... |
1115 1116 |
return evdev_handle_get_val(client, dev, EV_SW, dev->sw, SW_MAX, size, p, compat_mode); |
315810668 [PATCH] Input: Ad... |
1117 |
|
448cd1664 Input: evdev - re... |
1118 1119 |
case EVIOCGNAME(0): return str_to_user(dev->name, size, p); |
1da177e4c Linux-2.6.12-rc2 |
1120 |
|
448cd1664 Input: evdev - re... |
1121 1122 |
case EVIOCGPHYS(0): return str_to_user(dev->phys, size, p); |
1da177e4c Linux-2.6.12-rc2 |
1123 |
|
448cd1664 Input: evdev - re... |
1124 1125 |
case EVIOCGUNIQ(0): return str_to_user(dev->uniq, size, p); |
1da177e4c Linux-2.6.12-rc2 |
1126 |
|
448cd1664 Input: evdev - re... |
1127 1128 1129 |
case EVIOC_MASK_SIZE(EVIOCSFF): if (input_ff_effect_from_user(p, size, &effect)) return -EFAULT; |
1da177e4c Linux-2.6.12-rc2 |
1130 |
|
448cd1664 Input: evdev - re... |
1131 |
error = input_ff_upload(dev, &effect, file); |
fc7392aa1 Input: don't modi... |
1132 1133 |
if (error) return error; |
1da177e4c Linux-2.6.12-rc2 |
1134 |
|
448cd1664 Input: evdev - re... |
1135 1136 |
if (put_user(effect.id, &(((struct ff_effect __user *)p)->id))) return -EFAULT; |
41e979f82 Input: Make EVIOS... |
1137 |
|
fc7392aa1 Input: don't modi... |
1138 |
return 0; |
448cd1664 Input: evdev - re... |
1139 |
} |
1da177e4c Linux-2.6.12-rc2 |
1140 |
|
448cd1664 Input: evdev - re... |
1141 1142 1143 |
/* Multi-number variable-length handlers */ if (_IOC_TYPE(cmd) != 'E') return -EINVAL; |
1da177e4c Linux-2.6.12-rc2 |
1144 |
|
448cd1664 Input: evdev - re... |
1145 |
if (_IOC_DIR(cmd) == _IOC_READ) { |
6addb1d6d Input: evdev - im... |
1146 |
|
448cd1664 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 Linux-2.6.12-rc2 |
1151 |
|
448cd1664 Input: evdev - re... |
1152 |
if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) { |
f2278f31d Input: fix force ... |
1153 |
|
0a74a1df3 Input: evdev - fi... |
1154 1155 |
if (!dev->absinfo) return -EINVAL; |
448cd1664 Input: evdev - re... |
1156 1157 |
t = _IOC_NR(cmd) & ABS_MAX; abs = dev->absinfo[t]; |
f2278f31d Input: fix force ... |
1158 |
|
448cd1664 Input: evdev - re... |
1159 1160 1161 |
if (copy_to_user(p, &abs, min_t(size_t, size, sizeof(struct input_absinfo)))) return -EFAULT; |
f2278f31d Input: fix force ... |
1162 |
|
448cd1664 Input: evdev - re... |
1163 1164 1165 |
return 0; } } |
f2278f31d Input: fix force ... |
1166 |
|
f9ce6eb5b Input: evdev - fi... |
1167 |
if (_IOC_DIR(cmd) == _IOC_WRITE) { |
f2278f31d Input: fix force ... |
1168 |
|
448cd1664 Input: evdev - re... |
1169 |
if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) { |
1da177e4c Linux-2.6.12-rc2 |
1170 |
|
0a74a1df3 Input: evdev - fi... |
1171 1172 |
if (!dev->absinfo) return -EINVAL; |
448cd1664 Input: evdev - re... |
1173 |
t = _IOC_NR(cmd) & ABS_MAX; |
41e979f82 Input: Make EVIOS... |
1174 |
|
448cd1664 Input: evdev - re... |
1175 1176 1177 |
if (copy_from_user(&abs, p, min_t(size_t, size, sizeof(struct input_absinfo)))) return -EFAULT; |
1da177e4c Linux-2.6.12-rc2 |
1178 |
|
448cd1664 Input: evdev - re... |
1179 1180 |
if (size < sizeof(struct input_absinfo)) abs.resolution = 0; |
d31b2865a Input: dynamicall... |
1181 |
|
448cd1664 Input: evdev - re... |
1182 1183 1184 |
/* We can't change number of reserved MT slots */ if (t == ABS_MT_SLOT) return -EINVAL; |
40d007e7d Input: introduce ... |
1185 |
|
448cd1664 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 Input: evdev - im... |
1194 |
|
448cd1664 Input: evdev - re... |
1195 |
return 0; |
6addb1d6d Input: evdev - im... |
1196 |
} |
1da177e4c Linux-2.6.12-rc2 |
1197 |
} |
448cd1664 Input: evdev - re... |
1198 |
|
1da177e4c Linux-2.6.12-rc2 |
1199 1200 |
return -EINVAL; } |
1da177e4c Linux-2.6.12-rc2 |
1201 |
|
6addb1d6d 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 Input: evdev - ad... |
1212 |
if (!evdev->exist || client->revoked) { |
6addb1d6d 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 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 Input: Make EVIOS... |
1227 |
|
3a51f7c40 Input: evdev - co... |
1228 |
#ifdef CONFIG_COMPAT |
6addb1d6d Input: evdev - im... |
1229 1230 |
static long evdev_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) |
52658bb68 Input: Add suppor... |
1231 |
{ |
3a51f7c40 Input: evdev - co... |
1232 |
return evdev_ioctl_handler(file, cmd, compat_ptr(arg), 1); |
1da177e4c Linux-2.6.12-rc2 |
1233 |
} |
52658bb68 Input: Add suppor... |
1234 |
#endif |
1da177e4c Linux-2.6.12-rc2 |
1235 |
|
66e661188 Input: constify i... |
1236 |
static const struct file_operations evdev_fops = { |
6addb1d6d 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 Input: Add suppor... |
1244 |
#ifdef CONFIG_COMPAT |
6addb1d6d Input: evdev - im... |
1245 |
.compat_ioctl = evdev_ioctl_compat, |
52658bb68 Input: Add suppor... |
1246 |
#endif |
6addb1d6d Input: evdev - im... |
1247 |
.fasync = evdev_fasync, |
6038f373a llseek: automatic... |
1248 |
.llseek = no_llseek, |
1da177e4c Linux-2.6.12-rc2 |
1249 |
}; |
6addb1d6d 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 Input: change inp... |
1258 |
evdev->exist = false; |
6addb1d6d 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 Input: extend the... |
1268 |
|
6addb1d6d 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 Input: extend the... |
1278 |
* to connect and disconnect. |
6addb1d6d Input: evdev - im... |
1279 |
*/ |
5b2a08262 Input: rework han... |
1280 1281 |
static int evdev_connect(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id) |
1da177e4c Linux-2.6.12-rc2 |
1282 1283 1284 |
{ struct evdev *evdev; int minor; |
7f8d4cad1 Input: extend the... |
1285 |
int dev_no; |
5b2a08262 Input: rework han... |
1286 |
int error; |
1da177e4c Linux-2.6.12-rc2 |
1287 |
|
7f8d4cad1 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 Linux-2.6.12-rc2 |
1294 |
} |
5b2a08262 Input: rework han... |
1295 |
evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL); |
7f8d4cad1 Input: extend the... |
1296 1297 1298 1299 |
if (!evdev) { error = -ENOMEM; goto err_free_minor; } |
1da177e4c Linux-2.6.12-rc2 |
1300 |
|
d0ffb9be8 Input: handlers -... |
1301 |
INIT_LIST_HEAD(&evdev->client_list); |
6addb1d6d Input: evdev - im... |
1302 1303 |
spin_lock_init(&evdev->client_lock); mutex_init(&evdev->mutex); |
20da92de8 Input: change inp... |
1304 |
evdev->exist = true; |
7f8d4cad1 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 Input: evdev - im... |
1311 |
|
a7097ff89 Input: make sure ... |
1312 |
evdev->handle.dev = input_get_device(dev); |
3d5cb60ef Input: simplify n... |
1313 |
evdev->handle.name = dev_name(&evdev->dev); |
1da177e4c Linux-2.6.12-rc2 |
1314 1315 |
evdev->handle.handler = handler; evdev->handle.private = evdev; |
1da177e4c Linux-2.6.12-rc2 |
1316 |
|
7f8d4cad1 Input: extend the... |
1317 |
evdev->dev.devt = MKDEV(INPUT_MAJOR, minor); |
9657d75c5 Input: convert fr... |
1318 1319 |
evdev->dev.class = &input_class; evdev->dev.parent = &dev->dev; |
9657d75c5 Input: convert fr... |
1320 1321 |
evdev->dev.release = evdev_free; device_initialize(&evdev->dev); |
5b2a08262 Input: rework han... |
1322 |
|
6addb1d6d Input: evdev - im... |
1323 |
error = input_register_handle(&evdev->handle); |
5b2a08262 Input: rework han... |
1324 |
if (error) |
9657d75c5 Input: convert fr... |
1325 |
goto err_free_evdev; |
5b2a08262 Input: rework han... |
1326 |
|
7f8d4cad1 Input: extend the... |
1327 |
cdev_init(&evdev->cdev, &evdev_fops); |
6addb1d6d Input: evdev - im... |
1328 |
|
358a89ca2 input: utilize ne... |
1329 |
error = cdev_device_add(&evdev->cdev, &evdev->dev); |
5b2a08262 Input: rework han... |
1330 |
if (error) |
6addb1d6d Input: evdev - im... |
1331 |
goto err_cleanup_evdev; |
1da177e4c Linux-2.6.12-rc2 |
1332 |
|
5b2a08262 Input: rework han... |
1333 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
1334 |
|
6addb1d6d Input: evdev - im... |
1335 1336 |
err_cleanup_evdev: evdev_cleanup(evdev); |
6addb1d6d Input: evdev - im... |
1337 |
input_unregister_handle(&evdev->handle); |
5b2a08262 Input: rework han... |
1338 |
err_free_evdev: |
9657d75c5 Input: convert fr... |
1339 |
put_device(&evdev->dev); |
7f8d4cad1 Input: extend the... |
1340 1341 |
err_free_minor: input_free_minor(minor); |
5b2a08262 Input: rework han... |
1342 |
return error; |
1da177e4c Linux-2.6.12-rc2 |
1343 1344 1345 1346 1347 |
} static void evdev_disconnect(struct input_handle *handle) { struct evdev *evdev = handle->private; |
1da177e4c Linux-2.6.12-rc2 |
1348 |
|
358a89ca2 input: utilize ne... |
1349 |
cdev_device_del(&evdev->cdev, &evdev->dev); |
6addb1d6d Input: evdev - im... |
1350 |
evdev_cleanup(evdev); |
7f8d4cad1 Input: extend the... |
1351 |
input_free_minor(MINOR(evdev->dev.devt)); |
6addb1d6d Input: evdev - im... |
1352 |
input_unregister_handle(handle); |
9657d75c5 Input: convert fr... |
1353 |
put_device(&evdev->dev); |
1da177e4c Linux-2.6.12-rc2 |
1354 |
} |
66e661188 Input: constify i... |
1355 |
static const struct input_device_id evdev_ids[] = { |
1da177e4c 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 Input: evdev - im... |
1363 |
.event = evdev_event, |
a274ac15e Input: evdev - Ad... |
1364 |
.events = evdev_events, |
6addb1d6d Input: evdev - im... |
1365 1366 |
.connect = evdev_connect, .disconnect = evdev_disconnect, |
7f8d4cad1 Input: extend the... |
1367 |
.legacy_minors = true, |
6addb1d6d Input: evdev - im... |
1368 1369 1370 |
.minor = EVDEV_MINOR_BASE, .name = "evdev", .id_table = evdev_ids, |
1da177e4c Linux-2.6.12-rc2 |
1371 1372 1373 1374 |
}; static int __init evdev_init(void) { |
4263cf0fa Input: make input... |
1375 |
return input_register_handler(&evdev_handler); |
1da177e4c 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"); |