diff options
Diffstat (limited to 'drivers/input/evdev.c')
-rw-r--r-- | drivers/input/evdev.c | 407 |
1 files changed, 327 insertions, 80 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 556264b43425..374f404e81da 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/smp_lock.h> | 21 | #include <linux/smp_lock.h> |
22 | #include <linux/device.h> | 22 | #include <linux/device.h> |
23 | #include <linux/devfs_fs_kernel.h> | 23 | #include <linux/devfs_fs_kernel.h> |
24 | #include <linux/compat.h> | ||
24 | 25 | ||
25 | struct evdev { | 26 | struct evdev { |
26 | int exist; | 27 | int exist; |
@@ -145,6 +146,41 @@ static int evdev_open(struct inode * inode, struct file * file) | |||
145 | return 0; | 146 | return 0; |
146 | } | 147 | } |
147 | 148 | ||
149 | #ifdef CONFIG_COMPAT | ||
150 | struct input_event_compat { | ||
151 | struct compat_timeval time; | ||
152 | __u16 type; | ||
153 | __u16 code; | ||
154 | __s32 value; | ||
155 | }; | ||
156 | |||
157 | #ifdef CONFIG_X86_64 | ||
158 | # define COMPAT_TEST test_thread_flag(TIF_IA32) | ||
159 | #elif defined(CONFIG_IA64) | ||
160 | # define COMPAT_TEST IS_IA32_PROCESS(ia64_task_regs(current)) | ||
161 | #elif defined(CONFIG_ARCH_S390) | ||
162 | # define COMPAT_TEST test_thread_flag(TIF_31BIT) | ||
163 | #else | ||
164 | # define COMPAT_TEST test_thread_flag(TIF_32BIT) | ||
165 | #endif | ||
166 | |||
167 | static ssize_t evdev_write_compat(struct file * file, const char __user * buffer, size_t count, loff_t *ppos) | ||
168 | { | ||
169 | struct evdev_list *list = file->private_data; | ||
170 | struct input_event_compat event; | ||
171 | int retval = 0; | ||
172 | |||
173 | while (retval < count) { | ||
174 | if (copy_from_user(&event, buffer + retval, sizeof(struct input_event_compat))) | ||
175 | return -EFAULT; | ||
176 | input_event(list->evdev->handle.dev, event.type, event.code, event.value); | ||
177 | retval += sizeof(struct input_event_compat); | ||
178 | } | ||
179 | |||
180 | return retval; | ||
181 | } | ||
182 | #endif | ||
183 | |||
148 | static ssize_t evdev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos) | 184 | static ssize_t evdev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos) |
149 | { | 185 | { |
150 | struct evdev_list *list = file->private_data; | 186 | struct evdev_list *list = file->private_data; |
@@ -153,6 +189,11 @@ static ssize_t evdev_write(struct file * file, const char __user * buffer, size_ | |||
153 | 189 | ||
154 | if (!list->evdev->exist) return -ENODEV; | 190 | if (!list->evdev->exist) return -ENODEV; |
155 | 191 | ||
192 | #ifdef CONFIG_COMPAT | ||
193 | if (COMPAT_TEST) | ||
194 | return evdev_write_compat(file, buffer, count, ppos); | ||
195 | #endif | ||
196 | |||
156 | while (retval < count) { | 197 | while (retval < count) { |
157 | 198 | ||
158 | if (copy_from_user(&event, buffer + retval, sizeof(struct input_event))) | 199 | if (copy_from_user(&event, buffer + retval, sizeof(struct input_event))) |
@@ -164,11 +205,56 @@ static ssize_t evdev_write(struct file * file, const char __user * buffer, size_ | |||
164 | return retval; | 205 | return retval; |
165 | } | 206 | } |
166 | 207 | ||
208 | #ifdef CONFIG_COMPAT | ||
209 | static ssize_t evdev_read_compat(struct file * file, char __user * buffer, size_t count, loff_t *ppos) | ||
210 | { | ||
211 | struct evdev_list *list = file->private_data; | ||
212 | int retval; | ||
213 | |||
214 | if (count < sizeof(struct input_event_compat)) | ||
215 | return -EINVAL; | ||
216 | |||
217 | if (list->head == list->tail && list->evdev->exist && (file->f_flags & O_NONBLOCK)) | ||
218 | return -EAGAIN; | ||
219 | |||
220 | retval = wait_event_interruptible(list->evdev->wait, | ||
221 | list->head != list->tail || (!list->evdev->exist)); | ||
222 | |||
223 | if (retval) | ||
224 | return retval; | ||
225 | |||
226 | if (!list->evdev->exist) | ||
227 | return -ENODEV; | ||
228 | |||
229 | while (list->head != list->tail && retval + sizeof(struct input_event_compat) <= count) { | ||
230 | struct input_event *event = (struct input_event *) list->buffer + list->tail; | ||
231 | struct input_event_compat event_compat; | ||
232 | event_compat.time.tv_sec = event->time.tv_sec; | ||
233 | event_compat.time.tv_usec = event->time.tv_usec; | ||
234 | event_compat.type = event->type; | ||
235 | event_compat.code = event->code; | ||
236 | event_compat.value = event->value; | ||
237 | |||
238 | if (copy_to_user(buffer + retval, &event_compat, | ||
239 | sizeof(struct input_event_compat))) return -EFAULT; | ||
240 | list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1); | ||
241 | retval += sizeof(struct input_event_compat); | ||
242 | } | ||
243 | |||
244 | return retval; | ||
245 | } | ||
246 | #endif | ||
247 | |||
167 | static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos) | 248 | static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos) |
168 | { | 249 | { |
169 | struct evdev_list *list = file->private_data; | 250 | struct evdev_list *list = file->private_data; |
170 | int retval; | 251 | int retval; |
171 | 252 | ||
253 | #ifdef CONFIG_COMPAT | ||
254 | if (COMPAT_TEST) | ||
255 | return evdev_read_compat(file, buffer, count, ppos); | ||
256 | #endif | ||
257 | |||
172 | if (count < sizeof(struct input_event)) | 258 | if (count < sizeof(struct input_event)) |
173 | return -EINVAL; | 259 | return -EINVAL; |
174 | 260 | ||
@@ -186,7 +272,7 @@ static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count | |||
186 | 272 | ||
187 | while (list->head != list->tail && retval + sizeof(struct input_event) <= count) { | 273 | while (list->head != list->tail && retval + sizeof(struct input_event) <= count) { |
188 | if (copy_to_user(buffer + retval, list->buffer + list->tail, | 274 | if (copy_to_user(buffer + retval, list->buffer + list->tail, |
189 | sizeof(struct input_event))) return -EFAULT; | 275 | sizeof(struct input_event))) return -EFAULT; |
190 | list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1); | 276 | list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1); |
191 | retval += sizeof(struct input_event); | 277 | retval += sizeof(struct input_event); |
192 | } | 278 | } |
@@ -203,7 +289,7 @@ static unsigned int evdev_poll(struct file *file, poll_table *wait) | |||
203 | (list->evdev->exist ? 0 : (POLLHUP | POLLERR)); | 289 | (list->evdev->exist ? 0 : (POLLHUP | POLLERR)); |
204 | } | 290 | } |
205 | 291 | ||
206 | static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) | 292 | static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
207 | { | 293 | { |
208 | struct evdev_list *list = file->private_data; | 294 | struct evdev_list *list = file->private_data; |
209 | struct evdev *evdev = list->evdev; | 295 | struct evdev *evdev = list->evdev; |
@@ -285,109 +371,267 @@ static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
285 | 371 | ||
286 | default: | 372 | default: |
287 | 373 | ||
288 | if (_IOC_TYPE(cmd) != 'E' || _IOC_DIR(cmd) != _IOC_READ) | 374 | if (_IOC_TYPE(cmd) != 'E') |
289 | return -EINVAL; | 375 | return -EINVAL; |
290 | 376 | ||
291 | if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) { | 377 | if (_IOC_DIR(cmd) == _IOC_READ) { |
292 | 378 | ||
293 | long *bits; | 379 | if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) { |
294 | int len; | 380 | |
295 | 381 | long *bits; | |
296 | switch (_IOC_NR(cmd) & EV_MAX) { | 382 | int len; |
297 | case 0: bits = dev->evbit; len = EV_MAX; break; | 383 | |
298 | case EV_KEY: bits = dev->keybit; len = KEY_MAX; break; | 384 | switch (_IOC_NR(cmd) & EV_MAX) { |
299 | case EV_REL: bits = dev->relbit; len = REL_MAX; break; | 385 | case 0: bits = dev->evbit; len = EV_MAX; break; |
300 | case EV_ABS: bits = dev->absbit; len = ABS_MAX; break; | 386 | case EV_KEY: bits = dev->keybit; len = KEY_MAX; break; |
301 | case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break; | 387 | case EV_REL: bits = dev->relbit; len = REL_MAX; break; |
302 | case EV_LED: bits = dev->ledbit; len = LED_MAX; break; | 388 | case EV_ABS: bits = dev->absbit; len = ABS_MAX; break; |
303 | case EV_SND: bits = dev->sndbit; len = SND_MAX; break; | 389 | case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break; |
304 | case EV_FF: bits = dev->ffbit; len = FF_MAX; break; | 390 | case EV_LED: bits = dev->ledbit; len = LED_MAX; break; |
305 | default: return -EINVAL; | 391 | case EV_SND: bits = dev->sndbit; len = SND_MAX; break; |
392 | case EV_FF: bits = dev->ffbit; len = FF_MAX; break; | ||
393 | default: return -EINVAL; | ||
394 | } | ||
395 | len = NBITS(len) * sizeof(long); | ||
396 | if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); | ||
397 | return copy_to_user(p, bits, len) ? -EFAULT : len; | ||
306 | } | 398 | } |
307 | len = NBITS(len) * sizeof(long); | ||
308 | if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); | ||
309 | return copy_to_user(p, bits, len) ? -EFAULT : len; | ||
310 | } | ||
311 | 399 | ||
312 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) { | 400 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) { |
313 | int len; | 401 | int len; |
314 | len = NBITS(KEY_MAX) * sizeof(long); | 402 | len = NBITS(KEY_MAX) * sizeof(long); |
315 | if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); | 403 | if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); |
316 | return copy_to_user(p, dev->key, len) ? -EFAULT : len; | 404 | return copy_to_user(p, dev->key, len) ? -EFAULT : len; |
317 | } | 405 | } |
318 | 406 | ||
319 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) { | 407 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) { |
320 | int len; | 408 | int len; |
321 | len = NBITS(LED_MAX) * sizeof(long); | 409 | len = NBITS(LED_MAX) * sizeof(long); |
322 | if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); | 410 | if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); |
323 | return copy_to_user(p, dev->led, len) ? -EFAULT : len; | 411 | return copy_to_user(p, dev->led, len) ? -EFAULT : len; |
324 | } | 412 | } |
325 | 413 | ||
326 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) { | 414 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) { |
327 | int len; | 415 | int len; |
328 | len = NBITS(SND_MAX) * sizeof(long); | 416 | len = NBITS(SND_MAX) * sizeof(long); |
329 | if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); | 417 | if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); |
330 | return copy_to_user(p, dev->snd, len) ? -EFAULT : len; | 418 | return copy_to_user(p, dev->snd, len) ? -EFAULT : len; |
331 | } | 419 | } |
332 | 420 | ||
333 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) { | 421 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) { |
334 | int len; | 422 | int len; |
335 | if (!dev->name) return -ENOENT; | 423 | if (!dev->name) return -ENOENT; |
336 | len = strlen(dev->name) + 1; | 424 | len = strlen(dev->name) + 1; |
337 | if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); | 425 | if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); |
338 | return copy_to_user(p, dev->name, len) ? -EFAULT : len; | 426 | return copy_to_user(p, dev->name, len) ? -EFAULT : len; |
339 | } | 427 | } |
428 | |||
429 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) { | ||
430 | int len; | ||
431 | if (!dev->phys) return -ENOENT; | ||
432 | len = strlen(dev->phys) + 1; | ||
433 | if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); | ||
434 | return copy_to_user(p, dev->phys, len) ? -EFAULT : len; | ||
435 | } | ||
436 | |||
437 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) { | ||
438 | int len; | ||
439 | if (!dev->uniq) return -ENOENT; | ||
440 | len = strlen(dev->uniq) + 1; | ||
441 | if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); | ||
442 | return copy_to_user(p, dev->uniq, len) ? -EFAULT : len; | ||
443 | } | ||
444 | |||
445 | if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) { | ||
446 | |||
447 | int t = _IOC_NR(cmd) & ABS_MAX; | ||
448 | |||
449 | abs.value = dev->abs[t]; | ||
450 | abs.minimum = dev->absmin[t]; | ||
451 | abs.maximum = dev->absmax[t]; | ||
452 | abs.fuzz = dev->absfuzz[t]; | ||
453 | abs.flat = dev->absflat[t]; | ||
454 | |||
455 | if (copy_to_user(p, &abs, sizeof(struct input_absinfo))) | ||
456 | return -EFAULT; | ||
457 | |||
458 | return 0; | ||
459 | } | ||
340 | 460 | ||
341 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) { | ||
342 | int len; | ||
343 | if (!dev->phys) return -ENOENT; | ||
344 | len = strlen(dev->phys) + 1; | ||
345 | if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); | ||
346 | return copy_to_user(p, dev->phys, len) ? -EFAULT : len; | ||
347 | } | 461 | } |
348 | 462 | ||
349 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) { | 463 | if (_IOC_DIR(cmd) == _IOC_WRITE) { |
350 | int len; | 464 | |
351 | if (!dev->uniq) return -ENOENT; | 465 | if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) { |
352 | len = strlen(dev->uniq) + 1; | 466 | |
353 | if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); | 467 | int t = _IOC_NR(cmd) & ABS_MAX; |
354 | return copy_to_user(p, dev->uniq, len) ? -EFAULT : len; | 468 | |
469 | if (copy_from_user(&abs, p, sizeof(struct input_absinfo))) | ||
470 | return -EFAULT; | ||
471 | |||
472 | dev->abs[t] = abs.value; | ||
473 | dev->absmin[t] = abs.minimum; | ||
474 | dev->absmax[t] = abs.maximum; | ||
475 | dev->absfuzz[t] = abs.fuzz; | ||
476 | dev->absflat[t] = abs.flat; | ||
477 | |||
478 | return 0; | ||
479 | } | ||
355 | } | 480 | } |
481 | } | ||
482 | return -EINVAL; | ||
483 | } | ||
356 | 484 | ||
357 | if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) { | 485 | #ifdef CONFIG_COMPAT |
486 | |||
487 | #define BITS_PER_LONG_COMPAT (sizeof(compat_long_t) * 8) | ||
488 | #define NBITS_COMPAT(x) ((((x)-1)/BITS_PER_LONG_COMPAT)+1) | ||
489 | #define OFF_COMPAT(x) ((x)%BITS_PER_LONG_COMPAT) | ||
490 | #define BIT_COMPAT(x) (1UL<<OFF_COMPAT(x)) | ||
491 | #define LONG_COMPAT(x) ((x)/BITS_PER_LONG_COMPAT) | ||
492 | #define test_bit_compat(bit, array) ((array[LONG_COMPAT(bit)] >> OFF_COMPAT(bit)) & 1) | ||
493 | |||
494 | #ifdef __BIG_ENDIAN | ||
495 | #define bit_to_user(bit, max) \ | ||
496 | do { \ | ||
497 | int i; \ | ||
498 | int len = NBITS_COMPAT((max)) * sizeof(compat_long_t); \ | ||
499 | if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); \ | ||
500 | for (i = 0; i < len / sizeof(compat_long_t); i++) \ | ||
501 | if (copy_to_user((compat_long_t*) p + i, \ | ||
502 | (compat_long_t*) (bit) + i + 1 - ((i % 2) << 1), \ | ||
503 | sizeof(compat_long_t))) \ | ||
504 | return -EFAULT; \ | ||
505 | return len; \ | ||
506 | } while (0) | ||
507 | #else | ||
508 | #define bit_to_user(bit, max) \ | ||
509 | do { \ | ||
510 | int len = NBITS_COMPAT((max)) * sizeof(compat_long_t); \ | ||
511 | if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); \ | ||
512 | return copy_to_user(p, (bit), len) ? -EFAULT : len; \ | ||
513 | } while (0) | ||
514 | #endif | ||
515 | |||
516 | static long evdev_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) | ||
517 | { | ||
518 | struct evdev_list *list = file->private_data; | ||
519 | struct evdev *evdev = list->evdev; | ||
520 | struct input_dev *dev = evdev->handle.dev; | ||
521 | struct input_absinfo abs; | ||
522 | void __user *p = compat_ptr(arg); | ||
358 | 523 | ||
359 | int t = _IOC_NR(cmd) & ABS_MAX; | 524 | if (!evdev->exist) return -ENODEV; |
360 | 525 | ||
361 | abs.value = dev->abs[t]; | 526 | switch (cmd) { |
362 | abs.minimum = dev->absmin[t]; | ||
363 | abs.maximum = dev->absmax[t]; | ||
364 | abs.fuzz = dev->absfuzz[t]; | ||
365 | abs.flat = dev->absflat[t]; | ||
366 | 527 | ||
367 | if (copy_to_user(p, &abs, sizeof(struct input_absinfo))) | 528 | case EVIOCGVERSION: |
368 | return -EFAULT; | 529 | case EVIOCGID: |
530 | case EVIOCGKEYCODE: | ||
531 | case EVIOCSKEYCODE: | ||
532 | case EVIOCSFF: | ||
533 | case EVIOCRMFF: | ||
534 | case EVIOCGEFFECTS: | ||
535 | case EVIOCGRAB: | ||
536 | return evdev_ioctl(file, cmd, (unsigned long) p); | ||
369 | 537 | ||
370 | return 0; | 538 | default: |
539 | |||
540 | if (_IOC_TYPE(cmd) != 'E') | ||
541 | return -EINVAL; | ||
542 | |||
543 | if (_IOC_DIR(cmd) == _IOC_READ) { | ||
544 | |||
545 | if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) { | ||
546 | long *bits; | ||
547 | int max; | ||
548 | |||
549 | switch (_IOC_NR(cmd) & EV_MAX) { | ||
550 | case 0: bits = dev->evbit; max = EV_MAX; break; | ||
551 | case EV_KEY: bits = dev->keybit; max = KEY_MAX; break; | ||
552 | case EV_REL: bits = dev->relbit; max = REL_MAX; break; | ||
553 | case EV_ABS: bits = dev->absbit; max = ABS_MAX; break; | ||
554 | case EV_MSC: bits = dev->mscbit; max = MSC_MAX; break; | ||
555 | case EV_LED: bits = dev->ledbit; max = LED_MAX; break; | ||
556 | case EV_SND: bits = dev->sndbit; max = SND_MAX; break; | ||
557 | case EV_FF: bits = dev->ffbit; max = FF_MAX; break; | ||
558 | default: return -EINVAL; | ||
559 | } | ||
560 | bit_to_user(bits, max); | ||
561 | } | ||
562 | |||
563 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) | ||
564 | bit_to_user(dev->key, KEY_MAX); | ||
565 | |||
566 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) | ||
567 | bit_to_user(dev->led, LED_MAX); | ||
568 | |||
569 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) | ||
570 | bit_to_user(dev->snd, SND_MAX); | ||
571 | |||
572 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) { | ||
573 | int len; | ||
574 | if (!dev->name) return -ENOENT; | ||
575 | len = strlen(dev->name) + 1; | ||
576 | if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); | ||
577 | return copy_to_user(p, dev->name, len) ? -EFAULT : len; | ||
578 | } | ||
579 | |||
580 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) { | ||
581 | int len; | ||
582 | if (!dev->phys) return -ENOENT; | ||
583 | len = strlen(dev->phys) + 1; | ||
584 | if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); | ||
585 | return copy_to_user(p, dev->phys, len) ? -EFAULT : len; | ||
586 | } | ||
587 | |||
588 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) { | ||
589 | int len; | ||
590 | if (!dev->uniq) return -ENOENT; | ||
591 | len = strlen(dev->uniq) + 1; | ||
592 | if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); | ||
593 | return copy_to_user(p, dev->uniq, len) ? -EFAULT : len; | ||
594 | } | ||
595 | |||
596 | if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) { | ||
597 | |||
598 | int t = _IOC_NR(cmd) & ABS_MAX; | ||
599 | |||
600 | abs.value = dev->abs[t]; | ||
601 | abs.minimum = dev->absmin[t]; | ||
602 | abs.maximum = dev->absmax[t]; | ||
603 | abs.fuzz = dev->absfuzz[t]; | ||
604 | abs.flat = dev->absflat[t]; | ||
605 | |||
606 | if (copy_to_user(p, &abs, sizeof(struct input_absinfo))) | ||
607 | return -EFAULT; | ||
608 | |||
609 | return 0; | ||
610 | } | ||
371 | } | 611 | } |
372 | 612 | ||
373 | if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) { | 613 | if (_IOC_DIR(cmd) == _IOC_WRITE) { |
374 | 614 | ||
375 | int t = _IOC_NR(cmd) & ABS_MAX; | 615 | if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) { |
376 | 616 | ||
377 | if (copy_from_user(&abs, p, sizeof(struct input_absinfo))) | 617 | int t = _IOC_NR(cmd) & ABS_MAX; |
378 | return -EFAULT; | ||
379 | 618 | ||
380 | dev->abs[t] = abs.value; | 619 | if (copy_from_user(&abs, p, sizeof(struct input_absinfo))) |
381 | dev->absmin[t] = abs.minimum; | 620 | return -EFAULT; |
382 | dev->absmax[t] = abs.maximum; | ||
383 | dev->absfuzz[t] = abs.fuzz; | ||
384 | dev->absflat[t] = abs.flat; | ||
385 | 621 | ||
386 | return 0; | 622 | dev->abs[t] = abs.value; |
623 | dev->absmin[t] = abs.minimum; | ||
624 | dev->absmax[t] = abs.maximum; | ||
625 | dev->absfuzz[t] = abs.fuzz; | ||
626 | dev->absflat[t] = abs.flat; | ||
627 | |||
628 | return 0; | ||
629 | } | ||
387 | } | 630 | } |
388 | } | 631 | } |
389 | return -EINVAL; | 632 | return -EINVAL; |
390 | } | 633 | } |
634 | #endif | ||
391 | 635 | ||
392 | static struct file_operations evdev_fops = { | 636 | static struct file_operations evdev_fops = { |
393 | .owner = THIS_MODULE, | 637 | .owner = THIS_MODULE, |
@@ -396,7 +640,10 @@ static struct file_operations evdev_fops = { | |||
396 | .poll = evdev_poll, | 640 | .poll = evdev_poll, |
397 | .open = evdev_open, | 641 | .open = evdev_open, |
398 | .release = evdev_release, | 642 | .release = evdev_release, |
399 | .ioctl = evdev_ioctl, | 643 | .unlocked_ioctl = evdev_ioctl, |
644 | #ifdef CONFIG_COMPAT | ||
645 | .compat_ioctl = evdev_ioctl_compat, | ||
646 | #endif | ||
400 | .fasync = evdev_fasync, | 647 | .fasync = evdev_fasync, |
401 | .flush = evdev_flush | 648 | .flush = evdev_flush |
402 | }; | 649 | }; |