Blame view
drivers/input/evdev.c
17 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
/* * Event char devices, giving access to raw input device events. * * Copyright (c) 1999-2002 Vojtech Pavlik * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published by * the Free Software Foundation. */ #define EVDEV_MINOR_BASE 64 #define EVDEV_MINORS 32 #define EVDEV_BUFFER_SIZE 64 #include <linux/poll.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/init.h> #include <linux/input.h> #include <linux/major.h> #include <linux/smp_lock.h> #include <linux/device.h> |
52658bb68 Input: Add suppor... |
23 |
#include <linux/compat.h> |
1da177e4c Linux-2.6.12-rc2 |
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 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 |
struct evdev { int exist; int open; int minor; char name[16]; struct input_handle handle; wait_queue_head_t wait; struct evdev_list *grab; struct list_head list; }; struct evdev_list { struct input_event buffer[EVDEV_BUFFER_SIZE]; int head; int tail; struct fasync_struct *fasync; struct evdev *evdev; struct list_head node; }; static struct evdev *evdev_table[EVDEV_MINORS]; static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) { struct evdev *evdev = handle->private; struct evdev_list *list; if (evdev->grab) { list = evdev->grab; do_gettimeofday(&list->buffer[list->head].time); list->buffer[list->head].type = type; list->buffer[list->head].code = code; list->buffer[list->head].value = value; list->head = (list->head + 1) & (EVDEV_BUFFER_SIZE - 1); kill_fasync(&list->fasync, SIGIO, POLL_IN); } else list_for_each_entry(list, &evdev->list, node) { do_gettimeofday(&list->buffer[list->head].time); list->buffer[list->head].type = type; list->buffer[list->head].code = code; list->buffer[list->head].value = value; list->head = (list->head + 1) & (EVDEV_BUFFER_SIZE - 1); kill_fasync(&list->fasync, SIGIO, POLL_IN); } wake_up_interruptible(&evdev->wait); } static int evdev_fasync(int fd, struct file *file, int on) { int retval; struct evdev_list *list = file->private_data; |
1e0afb288 Input: fix format... |
81 |
|
1da177e4c Linux-2.6.12-rc2 |
82 |
retval = fasync_helper(fd, file, on, &list->fasync); |
1e0afb288 Input: fix format... |
83 |
|
1da177e4c Linux-2.6.12-rc2 |
84 85 |
return retval < 0 ? retval : 0; } |
1e0afb288 Input: fix format... |
86 |
static int evdev_flush(struct file *file, fl_owner_t id) |
1da177e4c Linux-2.6.12-rc2 |
87 88 |
{ struct evdev_list *list = file->private_data; |
1e0afb288 Input: fix format... |
89 90 91 |
if (!list->evdev->exist) return -ENODEV; |
1da177e4c Linux-2.6.12-rc2 |
92 93 94 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 123 124 125 126 127 |
return input_flush_device(&list->evdev->handle, file); } static void evdev_free(struct evdev *evdev) { evdev_table[evdev->minor] = NULL; kfree(evdev); } static int evdev_release(struct inode * inode, struct file * file) { struct evdev_list *list = file->private_data; if (list->evdev->grab == list) { input_release_device(&list->evdev->handle); list->evdev->grab = NULL; } evdev_fasync(-1, file, 0); list_del(&list->node); if (!--list->evdev->open) { if (list->evdev->exist) input_close_device(&list->evdev->handle); else evdev_free(list->evdev); } kfree(list); return 0; } static int evdev_open(struct inode * inode, struct file * file) { struct evdev_list *list; int i = iminor(inode) - EVDEV_MINOR_BASE; |
1da177e4c Linux-2.6.12-rc2 |
128 129 130 |
if (i >= EVDEV_MINORS || !evdev_table[i] || !evdev_table[i]->exist) return -ENODEV; |
b39787a97 Input: use kzallo... |
131 |
if (!(list = kzalloc(sizeof(struct evdev_list), GFP_KERNEL))) |
1da177e4c Linux-2.6.12-rc2 |
132 |
return -ENOMEM; |
1da177e4c Linux-2.6.12-rc2 |
133 134 135 136 137 138 139 140 141 142 143 |
list->evdev = evdev_table[i]; list_add_tail(&list->node, &evdev_table[i]->list); file->private_data = list; if (!list->evdev->open++) if (list->evdev->exist) input_open_device(&list->evdev->handle); return 0; } |
52658bb68 Input: Add suppor... |
144 |
#ifdef CONFIG_COMPAT |
3a51f7c40 Input: evdev - co... |
145 |
|
52658bb68 Input: Add suppor... |
146 147 148 149 150 151 |
struct input_event_compat { struct compat_timeval time; __u16 type; __u16 code; __s32 value; }; |
bf2fcc6fd [PATCH] x86_64: I... |
152 153 |
/* Note to the author of this code: did it ever occur to you why the ifdefs are needed? Think about it again. -AK */ |
52658bb68 Input: Add suppor... |
154 |
#ifdef CONFIG_X86_64 |
bf2fcc6fd [PATCH] x86_64: I... |
155 |
# define COMPAT_TEST is_compat_task() |
52658bb68 Input: Add suppor... |
156 |
#elif defined(CONFIG_IA64) |
6450578f3 [PATCH] ia64: tas... |
157 |
# define COMPAT_TEST IS_IA32_PROCESS(task_pt_regs(current)) |
347a8dc3b [PATCH] s390: cle... |
158 |
#elif defined(CONFIG_S390) |
52658bb68 Input: Add suppor... |
159 |
# define COMPAT_TEST test_thread_flag(TIF_31BIT) |
59df6bbf3 [PATCH] mips: klu... |
160 161 |
#elif defined(CONFIG_MIPS) # define COMPAT_TEST (current->thread.mflags & MF_32BIT_ADDR) |
52658bb68 Input: Add suppor... |
162 163 164 |
#else # define COMPAT_TEST test_thread_flag(TIF_32BIT) #endif |
3a51f7c40 Input: evdev - co... |
165 |
static inline size_t evdev_event_size(void) |
52658bb68 Input: Add suppor... |
166 |
{ |
3a51f7c40 Input: evdev - co... |
167 168 169 |
return COMPAT_TEST ? sizeof(struct input_event_compat) : sizeof(struct input_event); } |
52658bb68 Input: Add suppor... |
170 |
|
3a51f7c40 Input: evdev - co... |
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
static int evdev_event_from_user(const char __user *buffer, struct input_event *event) { if (COMPAT_TEST) { struct input_event_compat compat_event; if (copy_from_user(&compat_event, buffer, sizeof(struct input_event_compat))) return -EFAULT; event->time.tv_sec = compat_event.time.tv_sec; event->time.tv_usec = compat_event.time.tv_usec; event->type = compat_event.type; event->code = compat_event.code; event->value = compat_event.value; } else { if (copy_from_user(event, buffer, sizeof(struct input_event))) |
52658bb68 Input: Add suppor... |
187 |
return -EFAULT; |
52658bb68 Input: Add suppor... |
188 |
} |
3a51f7c40 Input: evdev - co... |
189 |
return 0; |
52658bb68 Input: Add suppor... |
190 |
} |
52658bb68 Input: Add suppor... |
191 |
|
3a51f7c40 Input: evdev - co... |
192 |
static int evdev_event_to_user(char __user *buffer, const struct input_event *event) |
1da177e4c Linux-2.6.12-rc2 |
193 |
{ |
3a51f7c40 Input: evdev - co... |
194 195 |
if (COMPAT_TEST) { struct input_event_compat compat_event; |
1da177e4c Linux-2.6.12-rc2 |
196 |
|
3a51f7c40 Input: evdev - co... |
197 198 199 200 201 |
compat_event.time.tv_sec = event->time.tv_sec; compat_event.time.tv_usec = event->time.tv_usec; compat_event.type = event->type; compat_event.code = event->code; compat_event.value = event->value; |
52658bb68 Input: Add suppor... |
202 |
|
3a51f7c40 Input: evdev - co... |
203 204 |
if (copy_to_user(buffer, &compat_event, sizeof(struct input_event_compat))) return -EFAULT; |
1da177e4c Linux-2.6.12-rc2 |
205 |
|
3a51f7c40 Input: evdev - co... |
206 207 |
} else { if (copy_to_user(buffer, event, sizeof(struct input_event))) |
1da177e4c Linux-2.6.12-rc2 |
208 |
return -EFAULT; |
1da177e4c Linux-2.6.12-rc2 |
209 |
} |
3a51f7c40 Input: evdev - co... |
210 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
211 |
} |
3a51f7c40 Input: evdev - co... |
212 213 214 |
#else static inline size_t evdev_event_size(void) |
52658bb68 Input: Add suppor... |
215 |
{ |
3a51f7c40 Input: evdev - co... |
216 217 |
return sizeof(struct input_event); } |
52658bb68 Input: Add suppor... |
218 |
|
3a51f7c40 Input: evdev - co... |
219 220 221 222 |
static int evdev_event_from_user(const char __user *buffer, struct input_event *event) { if (copy_from_user(event, buffer, sizeof(struct input_event))) return -EFAULT; |
52658bb68 Input: Add suppor... |
223 |
|
3a51f7c40 Input: evdev - co... |
224 225 |
return 0; } |
52658bb68 Input: Add suppor... |
226 |
|
3a51f7c40 Input: evdev - co... |
227 228 229 230 |
static int evdev_event_to_user(char __user *buffer, const struct input_event *event) { if (copy_to_user(buffer, event, sizeof(struct input_event))) return -EFAULT; |
52658bb68 Input: Add suppor... |
231 |
|
3a51f7c40 Input: evdev - co... |
232 233 234 235 236 237 238 239 240 241 |
return 0; } #endif /* CONFIG_COMPAT */ static ssize_t evdev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos) { struct evdev_list *list = file->private_data; struct input_event event; int retval = 0; |
52658bb68 Input: Add suppor... |
242 243 244 |
if (!list->evdev->exist) return -ENODEV; |
3a51f7c40 Input: evdev - co... |
245 246 247 248 |
while (retval < count) { if (evdev_event_from_user(buffer + retval, &event)) return -EFAULT; |
0e739d287 Input: introduce ... |
249 |
input_inject_event(&list->evdev->handle, event.type, event.code, event.value); |
3a51f7c40 Input: evdev - co... |
250 |
retval += evdev_event_size(); |
52658bb68 Input: Add suppor... |
251 252 253 254 |
} return retval; } |
52658bb68 Input: Add suppor... |
255 |
|
1da177e4c Linux-2.6.12-rc2 |
256 257 258 259 |
static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos) { struct evdev_list *list = file->private_data; int retval; |
3a51f7c40 Input: evdev - co... |
260 |
if (count < evdev_event_size()) |
1da177e4c Linux-2.6.12-rc2 |
261 262 263 264 265 266 267 268 269 270 271 272 273 |
return -EINVAL; if (list->head == list->tail && list->evdev->exist && (file->f_flags & O_NONBLOCK)) return -EAGAIN; retval = wait_event_interruptible(list->evdev->wait, list->head != list->tail || (!list->evdev->exist)); if (retval) return retval; if (!list->evdev->exist) return -ENODEV; |
3a51f7c40 Input: evdev - co... |
274 275 276 277 278 279 |
while (list->head != list->tail && retval + evdev_event_size() <= count) { struct input_event *event = (struct input_event *) list->buffer + list->tail; if (evdev_event_to_user(buffer + retval, event)) return -EFAULT; |
1da177e4c Linux-2.6.12-rc2 |
280 |
list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1); |
3a51f7c40 Input: evdev - co... |
281 |
retval += evdev_event_size(); |
1da177e4c Linux-2.6.12-rc2 |
282 283 284 285 286 287 288 289 290 |
} return retval; } /* No kernel lock - fine */ static unsigned int evdev_poll(struct file *file, poll_table *wait) { struct evdev_list *list = file->private_data; |
1e0afb288 Input: fix format... |
291 |
|
1da177e4c Linux-2.6.12-rc2 |
292 293 294 295 |
poll_wait(file, &list->evdev->wait, wait); return ((list->head == list->tail) ? 0 : (POLLIN | POLLRDNORM)) | (list->evdev->exist ? 0 : (POLLHUP | POLLERR)); } |
3a51f7c40 Input: evdev - co... |
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 |
#ifdef CONFIG_COMPAT #define BITS_PER_LONG_COMPAT (sizeof(compat_long_t) * 8) #define NBITS_COMPAT(x) ((((x) - 1) / BITS_PER_LONG_COMPAT) + 1) #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) { len = NBITS_COMPAT(maxbit) * sizeof(compat_long_t); if (len < maxlen) 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 { len = NBITS(maxbit) * sizeof(long); if (len > maxlen) len = maxlen; if (copy_to_user(p, bits, len)) return -EFAULT; } return len; } #else static int bits_to_user(unsigned long *bits, unsigned int maxbit, unsigned int maxlen, void __user *p, int compat) { int len = compat ? NBITS_COMPAT(maxbit) * sizeof(compat_long_t) : NBITS(maxbit) * sizeof(long); if (len > maxlen) len = maxlen; return copy_to_user(p, bits, len) ? -EFAULT : len; } #endif /* __BIG_ENDIAN */ #else static int bits_to_user(unsigned long *bits, unsigned int maxbit, unsigned int maxlen, void __user *p, int compat) { int len = NBITS(maxbit) * sizeof(long); if (len > maxlen) len = maxlen; return copy_to_user(p, bits, len) ? -EFAULT : len; } #endif /* CONFIG_COMPAT */ static int str_to_user(const char *str, unsigned int maxlen, void __user *p) { int len; if (!str) return -ENOENT; len = strlen(str) + 1; if (len > maxlen) len = maxlen; return copy_to_user(p, str, len) ? -EFAULT : len; } static long evdev_ioctl_handler(struct file *file, unsigned int cmd, void __user *p, int compat_mode) |
1da177e4c Linux-2.6.12-rc2 |
375 376 377 378 379 |
{ struct evdev_list *list = file->private_data; struct evdev *evdev = list->evdev; struct input_dev *dev = evdev->handle.dev; struct input_absinfo abs; |
509ca1a93 Input: implement ... |
380 |
struct ff_effect effect; |
3a51f7c40 Input: evdev - co... |
381 |
int __user *ip = (int __user *)p; |
1da177e4c Linux-2.6.12-rc2 |
382 |
int i, t, u, v; |
509ca1a93 Input: implement ... |
383 |
int error; |
1da177e4c Linux-2.6.12-rc2 |
384 |
|
3a51f7c40 Input: evdev - co... |
385 386 |
if (!evdev->exist) return -ENODEV; |
1da177e4c Linux-2.6.12-rc2 |
387 388 389 390 391 392 393 |
switch (cmd) { case EVIOCGVERSION: return put_user(EV_VERSION, ip); case EVIOCGID: |
3a51f7c40 Input: evdev - co... |
394 395 |
if (copy_to_user(p, &dev->id, sizeof(struct input_id))) return -EFAULT; |
08791e5cf Input: ressurect ... |
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 |
return 0; 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; 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; |
0e739d287 Input: introduce ... |
414 415 |
input_inject_event(&evdev->handle, EV_REP, REP_DELAY, u); input_inject_event(&evdev->handle, EV_REP, REP_PERIOD, v); |
3a51f7c40 Input: evdev - co... |
416 417 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
418 419 |
case EVIOCGKEYCODE: |
3a51f7c40 Input: evdev - co... |
420 421 |
if (get_user(t, ip)) return -EFAULT; |
c8e4c7727 Input: add getkey... |
422 423 424 425 426 427 |
error = dev->getkeycode(dev, t, &v); if (error) return error; if (put_user(v, ip + 1)) |
3a51f7c40 Input: evdev - co... |
428 |
return -EFAULT; |
c8e4c7727 Input: add getkey... |
429 |
|
1da177e4c Linux-2.6.12-rc2 |
430 431 432 |
return 0; case EVIOCSKEYCODE: |
c8e4c7727 Input: add getkey... |
433 |
if (get_user(t, ip) || get_user(v, ip + 1)) |
3a51f7c40 Input: evdev - co... |
434 |
return -EFAULT; |
3a51f7c40 Input: evdev - co... |
435 |
|
c8e4c7727 Input: add getkey... |
436 |
return dev->setkeycode(dev, t, v); |
1da177e4c Linux-2.6.12-rc2 |
437 438 |
case EVIOCSFF: |
509ca1a93 Input: implement ... |
439 440 |
if (copy_from_user(&effect, p, sizeof(effect))) return -EFAULT; |
1da177e4c Linux-2.6.12-rc2 |
441 |
|
509ca1a93 Input: implement ... |
442 |
error = input_ff_upload(dev, &effect, file); |
3a51f7c40 Input: evdev - co... |
443 |
|
509ca1a93 Input: implement ... |
444 445 446 447 448 449 450 |
if (put_user(effect.id, &(((struct ff_effect __user *)p)->id))) return -EFAULT; return error; case EVIOCRMFF: return input_ff_erase(dev, (int)(unsigned long) p, file); |
1da177e4c Linux-2.6.12-rc2 |
451 452 |
case EVIOCGEFFECTS: |
509ca1a93 Input: implement ... |
453 454 |
i = test_bit(EV_FF, dev->evbit) ? dev->ff->max_effects : 0; if (put_user(i, ip)) |
1da177e4c Linux-2.6.12-rc2 |
455 456 457 458 |
return -EFAULT; return 0; case EVIOCGRAB: |
3a51f7c40 Input: evdev - co... |
459 |
if (p) { |
1da177e4c Linux-2.6.12-rc2 |
460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 |
if (evdev->grab) return -EBUSY; if (input_grab_device(&evdev->handle)) return -EBUSY; evdev->grab = list; return 0; } else { if (evdev->grab != list) return -EINVAL; input_release_device(&evdev->handle); evdev->grab = NULL; return 0; } default: |
41e979f82 Input: Make EVIOS... |
475 |
if (_IOC_TYPE(cmd) != 'E') |
1da177e4c Linux-2.6.12-rc2 |
476 |
return -EINVAL; |
41e979f82 Input: Make EVIOS... |
477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 |
if (_IOC_DIR(cmd) == _IOC_READ) { if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) { long *bits; int len; switch (_IOC_NR(cmd) & EV_MAX) { 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; |
315810668 [PATCH] Input: Ad... |
493 |
case EV_SW: bits = dev->swbit; len = SW_MAX; break; |
41e979f82 Input: Make EVIOS... |
494 495 |
default: return -EINVAL; } |
3a51f7c40 Input: evdev - co... |
496 |
return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode); |
1da177e4c Linux-2.6.12-rc2 |
497 |
} |
1da177e4c Linux-2.6.12-rc2 |
498 |
|
3a51f7c40 Input: evdev - co... |
499 500 501 |
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) return bits_to_user(dev->key, KEY_MAX, _IOC_SIZE(cmd), p, compat_mode); |
1da177e4c Linux-2.6.12-rc2 |
502 |
|
3a51f7c40 Input: evdev - co... |
503 504 505 |
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) return bits_to_user(dev->led, LED_MAX, _IOC_SIZE(cmd), p, compat_mode); |
1da177e4c Linux-2.6.12-rc2 |
506 |
|
3a51f7c40 Input: evdev - co... |
507 508 509 |
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) return bits_to_user(dev->snd, SND_MAX, _IOC_SIZE(cmd), p, compat_mode); |
1da177e4c Linux-2.6.12-rc2 |
510 |
|
3a51f7c40 Input: evdev - co... |
511 512 513 |
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0))) return bits_to_user(dev->sw, SW_MAX, _IOC_SIZE(cmd), p, compat_mode); |
315810668 [PATCH] Input: Ad... |
514 |
|
3a51f7c40 Input: evdev - co... |
515 516 |
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) return str_to_user(dev->name, _IOC_SIZE(cmd), p); |
1da177e4c Linux-2.6.12-rc2 |
517 |
|
3a51f7c40 Input: evdev - co... |
518 519 |
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) return str_to_user(dev->phys, _IOC_SIZE(cmd), p); |
1da177e4c Linux-2.6.12-rc2 |
520 |
|
3a51f7c40 Input: evdev - co... |
521 522 |
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) return str_to_user(dev->uniq, _IOC_SIZE(cmd), p); |
1da177e4c Linux-2.6.12-rc2 |
523 |
|
41e979f82 Input: Make EVIOS... |
524 |
if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) { |
1da177e4c Linux-2.6.12-rc2 |
525 |
|
41e979f82 Input: Make EVIOS... |
526 |
int t = _IOC_NR(cmd) & ABS_MAX; |
1da177e4c Linux-2.6.12-rc2 |
527 |
|
41e979f82 Input: Make EVIOS... |
528 529 530 531 532 |
abs.value = dev->abs[t]; abs.minimum = dev->absmin[t]; abs.maximum = dev->absmax[t]; abs.fuzz = dev->absfuzz[t]; abs.flat = dev->absflat[t]; |
1da177e4c Linux-2.6.12-rc2 |
533 |
|
41e979f82 Input: Make EVIOS... |
534 535 536 537 538 |
if (copy_to_user(p, &abs, sizeof(struct input_absinfo))) return -EFAULT; return 0; } |
1da177e4c Linux-2.6.12-rc2 |
539 |
|
1da177e4c Linux-2.6.12-rc2 |
540 |
} |
41e979f82 Input: Make EVIOS... |
541 |
if (_IOC_DIR(cmd) == _IOC_WRITE) { |
1da177e4c Linux-2.6.12-rc2 |
542 |
|
41e979f82 Input: Make EVIOS... |
543 |
if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) { |
1da177e4c Linux-2.6.12-rc2 |
544 |
|
41e979f82 Input: Make EVIOS... |
545 546 547 548 |
int t = _IOC_NR(cmd) & ABS_MAX; if (copy_from_user(&abs, p, sizeof(struct input_absinfo))) return -EFAULT; |
1da177e4c Linux-2.6.12-rc2 |
549 |
|
41e979f82 Input: Make EVIOS... |
550 551 552 553 554 |
dev->abs[t] = abs.value; dev->absmin[t] = abs.minimum; dev->absmax[t] = abs.maximum; dev->absfuzz[t] = abs.fuzz; dev->absflat[t] = abs.flat; |
1da177e4c Linux-2.6.12-rc2 |
555 |
|
41e979f82 Input: Make EVIOS... |
556 557 |
return 0; } |
1da177e4c Linux-2.6.12-rc2 |
558 |
} |
1da177e4c Linux-2.6.12-rc2 |
559 560 561 |
} return -EINVAL; } |
1da177e4c Linux-2.6.12-rc2 |
562 |
|
3a51f7c40 Input: evdev - co... |
563 564 565 566 |
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... |
567 |
|
3a51f7c40 Input: evdev - co... |
568 |
#ifdef CONFIG_COMPAT |
52658bb68 Input: Add suppor... |
569 570 |
static long evdev_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) { |
3a51f7c40 Input: evdev - co... |
571 |
return evdev_ioctl_handler(file, cmd, compat_ptr(arg), 1); |
1da177e4c Linux-2.6.12-rc2 |
572 |
} |
52658bb68 Input: Add suppor... |
573 |
#endif |
1da177e4c Linux-2.6.12-rc2 |
574 |
|
66e661188 Input: constify i... |
575 |
static const struct file_operations evdev_fops = { |
1da177e4c Linux-2.6.12-rc2 |
576 577 578 579 580 581 |
.owner = THIS_MODULE, .read = evdev_read, .write = evdev_write, .poll = evdev_poll, .open = evdev_open, .release = evdev_release, |
52658bb68 Input: Add suppor... |
582 583 584 585 |
.unlocked_ioctl = evdev_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = evdev_ioctl_compat, #endif |
1da177e4c Linux-2.6.12-rc2 |
586 587 588 |
.fasync = evdev_fasync, .flush = evdev_flush }; |
5b2a08262 Input: rework han... |
589 590 |
static int evdev_connect(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id) |
1da177e4c Linux-2.6.12-rc2 |
591 592 |
{ struct evdev *evdev; |
c9bcd582d [PATCH] INPUT: Cr... |
593 |
struct class_device *cdev; |
5b2a08262 Input: rework han... |
594 |
dev_t devt; |
1da177e4c Linux-2.6.12-rc2 |
595 |
int minor; |
5b2a08262 Input: rework han... |
596 |
int error; |
1da177e4c Linux-2.6.12-rc2 |
597 598 599 600 601 |
for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++); if (minor == EVDEV_MINORS) { printk(KERN_ERR "evdev: no more free evdev devices "); |
5b2a08262 Input: rework han... |
602 |
return -ENFILE; |
1da177e4c Linux-2.6.12-rc2 |
603 |
} |
5b2a08262 Input: rework han... |
604 605 606 |
evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL); if (!evdev) return -ENOMEM; |
1da177e4c Linux-2.6.12-rc2 |
607 608 609 610 611 612 613 614 615 616 617 618 619 |
INIT_LIST_HEAD(&evdev->list); init_waitqueue_head(&evdev->wait); evdev->exist = 1; evdev->minor = minor; evdev->handle.dev = dev; evdev->handle.name = evdev->name; evdev->handle.handler = handler; evdev->handle.private = evdev; sprintf(evdev->name, "event%d", minor); evdev_table[minor] = evdev; |
5b2a08262 Input: rework han... |
620 621 622 623 624 625 626 627 |
devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor), cdev = class_device_create(&input_class, &dev->cdev, devt, dev->cdev.dev, evdev->name); if (IS_ERR(cdev)) { error = PTR_ERR(cdev); goto err_free_evdev; } |
c9bcd582d [PATCH] INPUT: Cr... |
628 629 |
/* temporary symlink to keep userspace happy */ |
5b2a08262 Input: rework han... |
630 631 632 633 634 635 636 637 |
error = sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj, evdev->name); if (error) goto err_cdev_destroy; error = input_register_handle(&evdev->handle); if (error) goto err_remove_link; |
1da177e4c Linux-2.6.12-rc2 |
638 |
|
5b2a08262 Input: rework han... |
639 640 641 642 643 644 645 646 647 648 |
return 0; err_remove_link: sysfs_remove_link(&input_class.subsys.kset.kobj, evdev->name); err_cdev_destroy: class_device_destroy(&input_class, devt); err_free_evdev: kfree(evdev); evdev_table[minor] = NULL; return error; |
1da177e4c Linux-2.6.12-rc2 |
649 650 651 652 653 654 |
} static void evdev_disconnect(struct input_handle *handle) { struct evdev *evdev = handle->private; struct evdev_list *list; |
5b2a08262 Input: rework han... |
655 |
input_unregister_handle(handle); |
c9bcd582d [PATCH] INPUT: Cr... |
656 |
sysfs_remove_link(&input_class.subsys.kset.kobj, evdev->name); |
ea9f240bd [PATCH] INPUT: re... |
657 |
class_device_destroy(&input_class, |
1235686f6 [PATCH] INPUT: mo... |
658 |
MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + evdev->minor)); |
1da177e4c Linux-2.6.12-rc2 |
659 660 661 |
evdev->exist = 0; if (evdev->open) { |
509ca1a93 Input: implement ... |
662 |
input_flush_device(handle, NULL); |
1da177e4c Linux-2.6.12-rc2 |
663 664 665 666 667 668 669 |
input_close_device(handle); wake_up_interruptible(&evdev->wait); list_for_each_entry(list, &evdev->list, node) kill_fasync(&list->fasync, SIGIO, POLL_HUP); } else evdev_free(evdev); } |
66e661188 Input: constify i... |
670 |
static const struct input_device_id evdev_ids[] = { |
1da177e4c Linux-2.6.12-rc2 |
671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 |
{ .driver_info = 1 }, /* Matches all devices */ { }, /* Terminating zero entry */ }; MODULE_DEVICE_TABLE(input, evdev_ids); static struct input_handler evdev_handler = { .event = evdev_event, .connect = evdev_connect, .disconnect = evdev_disconnect, .fops = &evdev_fops, .minor = EVDEV_MINOR_BASE, .name = "evdev", .id_table = evdev_ids, }; static int __init evdev_init(void) { |
4263cf0fa Input: make input... |
689 |
return input_register_handler(&evdev_handler); |
1da177e4c Linux-2.6.12-rc2 |
690 691 692 693 694 695 696 697 698 699 700 701 702 |
} 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"); |