diff options
Diffstat (limited to 'drivers/input/evdev.c')
-rw-r--r-- | drivers/input/evdev.c | 199 |
1 files changed, 9 insertions, 190 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 1070db330d35..ed8baa0aec3c 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c | |||
@@ -19,7 +19,7 @@ | |||
19 | #include <linux/input.h> | 19 | #include <linux/input.h> |
20 | #include <linux/major.h> | 20 | #include <linux/major.h> |
21 | #include <linux/device.h> | 21 | #include <linux/device.h> |
22 | #include <linux/compat.h> | 22 | #include "input-compat.h" |
23 | 23 | ||
24 | struct evdev { | 24 | struct evdev { |
25 | int exist; | 25 | int exist; |
@@ -290,187 +290,6 @@ static int evdev_open(struct inode *inode, struct file *file) | |||
290 | return error; | 290 | return error; |
291 | } | 291 | } |
292 | 292 | ||
293 | #ifdef CONFIG_COMPAT | ||
294 | |||
295 | struct input_event_compat { | ||
296 | struct compat_timeval time; | ||
297 | __u16 type; | ||
298 | __u16 code; | ||
299 | __s32 value; | ||
300 | }; | ||
301 | |||
302 | struct ff_periodic_effect_compat { | ||
303 | __u16 waveform; | ||
304 | __u16 period; | ||
305 | __s16 magnitude; | ||
306 | __s16 offset; | ||
307 | __u16 phase; | ||
308 | |||
309 | struct ff_envelope envelope; | ||
310 | |||
311 | __u32 custom_len; | ||
312 | compat_uptr_t custom_data; | ||
313 | }; | ||
314 | |||
315 | struct ff_effect_compat { | ||
316 | __u16 type; | ||
317 | __s16 id; | ||
318 | __u16 direction; | ||
319 | struct ff_trigger trigger; | ||
320 | struct ff_replay replay; | ||
321 | |||
322 | union { | ||
323 | struct ff_constant_effect constant; | ||
324 | struct ff_ramp_effect ramp; | ||
325 | struct ff_periodic_effect_compat periodic; | ||
326 | struct ff_condition_effect condition[2]; /* One for each axis */ | ||
327 | struct ff_rumble_effect rumble; | ||
328 | } u; | ||
329 | }; | ||
330 | |||
331 | /* Note to the author of this code: did it ever occur to | ||
332 | you why the ifdefs are needed? Think about it again. -AK */ | ||
333 | #ifdef CONFIG_X86_64 | ||
334 | # define COMPAT_TEST is_compat_task() | ||
335 | #elif defined(CONFIG_IA64) | ||
336 | # define COMPAT_TEST IS_IA32_PROCESS(task_pt_regs(current)) | ||
337 | #elif defined(CONFIG_S390) | ||
338 | # define COMPAT_TEST test_thread_flag(TIF_31BIT) | ||
339 | #elif defined(CONFIG_MIPS) | ||
340 | # define COMPAT_TEST test_thread_flag(TIF_32BIT_ADDR) | ||
341 | #else | ||
342 | # define COMPAT_TEST test_thread_flag(TIF_32BIT) | ||
343 | #endif | ||
344 | |||
345 | static inline size_t evdev_event_size(void) | ||
346 | { | ||
347 | return COMPAT_TEST ? | ||
348 | sizeof(struct input_event_compat) : sizeof(struct input_event); | ||
349 | } | ||
350 | |||
351 | static int evdev_event_from_user(const char __user *buffer, | ||
352 | struct input_event *event) | ||
353 | { | ||
354 | if (COMPAT_TEST) { | ||
355 | struct input_event_compat compat_event; | ||
356 | |||
357 | if (copy_from_user(&compat_event, buffer, | ||
358 | sizeof(struct input_event_compat))) | ||
359 | return -EFAULT; | ||
360 | |||
361 | event->time.tv_sec = compat_event.time.tv_sec; | ||
362 | event->time.tv_usec = compat_event.time.tv_usec; | ||
363 | event->type = compat_event.type; | ||
364 | event->code = compat_event.code; | ||
365 | event->value = compat_event.value; | ||
366 | |||
367 | } else { | ||
368 | if (copy_from_user(event, buffer, sizeof(struct input_event))) | ||
369 | return -EFAULT; | ||
370 | } | ||
371 | |||
372 | return 0; | ||
373 | } | ||
374 | |||
375 | static int evdev_event_to_user(char __user *buffer, | ||
376 | const struct input_event *event) | ||
377 | { | ||
378 | if (COMPAT_TEST) { | ||
379 | struct input_event_compat compat_event; | ||
380 | |||
381 | compat_event.time.tv_sec = event->time.tv_sec; | ||
382 | compat_event.time.tv_usec = event->time.tv_usec; | ||
383 | compat_event.type = event->type; | ||
384 | compat_event.code = event->code; | ||
385 | compat_event.value = event->value; | ||
386 | |||
387 | if (copy_to_user(buffer, &compat_event, | ||
388 | sizeof(struct input_event_compat))) | ||
389 | return -EFAULT; | ||
390 | |||
391 | } else { | ||
392 | if (copy_to_user(buffer, event, sizeof(struct input_event))) | ||
393 | return -EFAULT; | ||
394 | } | ||
395 | |||
396 | return 0; | ||
397 | } | ||
398 | |||
399 | static int evdev_ff_effect_from_user(const char __user *buffer, size_t size, | ||
400 | struct ff_effect *effect) | ||
401 | { | ||
402 | if (COMPAT_TEST) { | ||
403 | struct ff_effect_compat *compat_effect; | ||
404 | |||
405 | if (size != sizeof(struct ff_effect_compat)) | ||
406 | return -EINVAL; | ||
407 | |||
408 | /* | ||
409 | * It so happens that the pointer which needs to be changed | ||
410 | * is the last field in the structure, so we can copy the | ||
411 | * whole thing and replace just the pointer. | ||
412 | */ | ||
413 | |||
414 | compat_effect = (struct ff_effect_compat *)effect; | ||
415 | |||
416 | if (copy_from_user(compat_effect, buffer, | ||
417 | sizeof(struct ff_effect_compat))) | ||
418 | return -EFAULT; | ||
419 | |||
420 | if (compat_effect->type == FF_PERIODIC && | ||
421 | compat_effect->u.periodic.waveform == FF_CUSTOM) | ||
422 | effect->u.periodic.custom_data = | ||
423 | compat_ptr(compat_effect->u.periodic.custom_data); | ||
424 | } else { | ||
425 | if (size != sizeof(struct ff_effect)) | ||
426 | return -EINVAL; | ||
427 | |||
428 | if (copy_from_user(effect, buffer, sizeof(struct ff_effect))) | ||
429 | return -EFAULT; | ||
430 | } | ||
431 | |||
432 | return 0; | ||
433 | } | ||
434 | |||
435 | #else | ||
436 | |||
437 | static inline size_t evdev_event_size(void) | ||
438 | { | ||
439 | return sizeof(struct input_event); | ||
440 | } | ||
441 | |||
442 | static int evdev_event_from_user(const char __user *buffer, | ||
443 | struct input_event *event) | ||
444 | { | ||
445 | if (copy_from_user(event, buffer, sizeof(struct input_event))) | ||
446 | return -EFAULT; | ||
447 | |||
448 | return 0; | ||
449 | } | ||
450 | |||
451 | static int evdev_event_to_user(char __user *buffer, | ||
452 | const struct input_event *event) | ||
453 | { | ||
454 | if (copy_to_user(buffer, event, sizeof(struct input_event))) | ||
455 | return -EFAULT; | ||
456 | |||
457 | return 0; | ||
458 | } | ||
459 | |||
460 | static int evdev_ff_effect_from_user(const char __user *buffer, size_t size, | ||
461 | struct ff_effect *effect) | ||
462 | { | ||
463 | if (size != sizeof(struct ff_effect)) | ||
464 | return -EINVAL; | ||
465 | |||
466 | if (copy_from_user(effect, buffer, sizeof(struct ff_effect))) | ||
467 | return -EFAULT; | ||
468 | |||
469 | return 0; | ||
470 | } | ||
471 | |||
472 | #endif /* CONFIG_COMPAT */ | ||
473 | |||
474 | static ssize_t evdev_write(struct file *file, const char __user *buffer, | 293 | static ssize_t evdev_write(struct file *file, const char __user *buffer, |
475 | size_t count, loff_t *ppos) | 294 | size_t count, loff_t *ppos) |
476 | { | 295 | { |
@@ -490,14 +309,14 @@ static ssize_t evdev_write(struct file *file, const char __user *buffer, | |||
490 | 309 | ||
491 | while (retval < count) { | 310 | while (retval < count) { |
492 | 311 | ||
493 | if (evdev_event_from_user(buffer + retval, &event)) { | 312 | if (input_event_from_user(buffer + retval, &event)) { |
494 | retval = -EFAULT; | 313 | retval = -EFAULT; |
495 | goto out; | 314 | goto out; |
496 | } | 315 | } |
497 | 316 | ||
498 | input_inject_event(&evdev->handle, | 317 | input_inject_event(&evdev->handle, |
499 | event.type, event.code, event.value); | 318 | event.type, event.code, event.value); |
500 | retval += evdev_event_size(); | 319 | retval += input_event_size(); |
501 | } | 320 | } |
502 | 321 | ||
503 | out: | 322 | out: |
@@ -531,7 +350,7 @@ static ssize_t evdev_read(struct file *file, char __user *buffer, | |||
531 | struct input_event event; | 350 | struct input_event event; |
532 | int retval; | 351 | int retval; |
533 | 352 | ||
534 | if (count < evdev_event_size()) | 353 | if (count < input_event_size()) |
535 | return -EINVAL; | 354 | return -EINVAL; |
536 | 355 | ||
537 | if (client->head == client->tail && evdev->exist && | 356 | if (client->head == client->tail && evdev->exist && |
@@ -546,13 +365,13 @@ static ssize_t evdev_read(struct file *file, char __user *buffer, | |||
546 | if (!evdev->exist) | 365 | if (!evdev->exist) |
547 | return -ENODEV; | 366 | return -ENODEV; |
548 | 367 | ||
549 | while (retval + evdev_event_size() <= count && | 368 | while (retval + input_event_size() <= count && |
550 | evdev_fetch_next_event(client, &event)) { | 369 | evdev_fetch_next_event(client, &event)) { |
551 | 370 | ||
552 | if (evdev_event_to_user(buffer + retval, &event)) | 371 | if (input_event_to_user(buffer + retval, &event)) |
553 | return -EFAULT; | 372 | return -EFAULT; |
554 | 373 | ||
555 | retval += evdev_event_size(); | 374 | retval += input_event_size(); |
556 | } | 375 | } |
557 | 376 | ||
558 | return retval; | 377 | return retval; |
@@ -823,7 +642,7 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, | |||
823 | 642 | ||
824 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCSFF)) { | 643 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCSFF)) { |
825 | 644 | ||
826 | if (evdev_ff_effect_from_user(p, _IOC_SIZE(cmd), &effect)) | 645 | if (input_ff_effect_from_user(p, _IOC_SIZE(cmd), &effect)) |
827 | return -EFAULT; | 646 | return -EFAULT; |
828 | 647 | ||
829 | error = input_ff_upload(dev, &effect, file); | 648 | error = input_ff_upload(dev, &effect, file); |
@@ -1000,7 +819,7 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, | |||
1000 | evdev->handle.handler = handler; | 819 | evdev->handle.handler = handler; |
1001 | evdev->handle.private = evdev; | 820 | evdev->handle.private = evdev; |
1002 | 821 | ||
1003 | strlcpy(evdev->dev.bus_id, evdev->name, sizeof(evdev->dev.bus_id)); | 822 | dev_set_name(&evdev->dev, evdev->name); |
1004 | evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor); | 823 | evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor); |
1005 | evdev->dev.class = &input_class; | 824 | evdev->dev.class = &input_class; |
1006 | evdev->dev.parent = &dev->dev; | 825 | evdev->dev.parent = &dev->dev; |