aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAdam Dawidowski <drake_ster@wp.pl>2008-06-02 01:08:10 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2008-06-30 09:37:06 -0400
commitf2278f31d6feb9036eaa79f2e8abcce850420abd (patch)
tree85b6f3abd9f6e77c5073a8951e3ac5452bbabfb9 /drivers
parent82547e9074a23d9d722a5f6053f4734566127da6 (diff)
Input: fix force feedback upload issue in compat mode
Force feedback upload of effects through the event device (ioctl EVIOCSFF) is not working in 32 bit applications running on 64-bit kernel due to the fact that struct ff_effect contains a pointer, resulting in the structure having different sizes in 64 and 32 bit programs and causing difference in ioctl numbers. [dtor@mail.ru: refactor to keep all ugliness in evdev] Signed-off-by: Adam Dawidowski <drake_ster@wp.pl> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/input/evdev.c101
1 files changed, 90 insertions, 11 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index b32984bc516f..2d65411f6763 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -300,6 +300,35 @@ struct input_event_compat {
300 __s32 value; 300 __s32 value;
301}; 301};
302 302
303struct ff_periodic_effect_compat {
304 __u16 waveform;
305 __u16 period;
306 __s16 magnitude;
307 __s16 offset;
308 __u16 phase;
309
310 struct ff_envelope envelope;
311
312 __u32 custom_len;
313 compat_uptr_t custom_data;
314};
315
316struct ff_effect_compat {
317 __u16 type;
318 __s16 id;
319 __u16 direction;
320 struct ff_trigger trigger;
321 struct ff_replay replay;
322
323 union {
324 struct ff_constant_effect constant;
325 struct ff_ramp_effect ramp;
326 struct ff_periodic_effect_compat periodic;
327 struct ff_condition_effect condition[2]; /* One for each axis */
328 struct ff_rumble_effect rumble;
329 } u;
330};
331
303/* Note to the author of this code: did it ever occur to 332/* Note to the author of this code: did it ever occur to
304 you why the ifdefs are needed? Think about it again. -AK */ 333 you why the ifdefs are needed? Think about it again. -AK */
305#ifdef CONFIG_X86_64 334#ifdef CONFIG_X86_64
@@ -368,6 +397,42 @@ static int evdev_event_to_user(char __user *buffer,
368 return 0; 397 return 0;
369} 398}
370 399
400static int evdev_ff_effect_from_user(const char __user *buffer, size_t size,
401 struct ff_effect *effect)
402{
403 if (COMPAT_TEST) {
404 struct ff_effect_compat *compat_effect;
405
406 if (size != sizeof(struct ff_effect_compat))
407 return -EINVAL;
408
409 /*
410 * It so happens that the pointer which needs to be changed
411 * is the last field in the structure, so we can copy the
412 * whole thing and replace just the pointer.
413 */
414
415 compat_effect = (struct ff_effect_compat *)effect;
416
417 if (copy_from_user(compat_effect, buffer,
418 sizeof(struct ff_effect_compat)))
419 return -EFAULT;
420
421 if (compat_effect->type == FF_PERIODIC &&
422 compat_effect->u.periodic.waveform == FF_CUSTOM)
423 effect->u.periodic.custom_data =
424 compat_ptr(compat_effect->u.periodic.custom_data);
425 } else {
426 if (size != sizeof(struct ff_effect))
427 return -EINVAL;
428
429 if (copy_from_user(effect, buffer, sizeof(struct ff_effect)))
430 return -EFAULT;
431 }
432
433 return 0;
434}
435
371#else 436#else
372 437
373static inline size_t evdev_event_size(void) 438static inline size_t evdev_event_size(void)
@@ -393,6 +458,18 @@ static int evdev_event_to_user(char __user *buffer,
393 return 0; 458 return 0;
394} 459}
395 460
461static int evdev_ff_effect_from_user(const char __user *buffer, size_t size,
462 struct ff_effect *effect)
463{
464 if (size != sizeof(struct ff_effect))
465 return -EINVAL;
466
467 if (copy_from_user(effect, buffer, sizeof(struct ff_effect)))
468 return -EFAULT;
469
470 return 0;
471}
472
396#endif /* CONFIG_COMPAT */ 473#endif /* CONFIG_COMPAT */
397 474
398static ssize_t evdev_write(struct file *file, const char __user *buffer, 475static ssize_t evdev_write(struct file *file, const char __user *buffer,
@@ -633,17 +710,6 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
633 710
634 return input_set_keycode(dev, t, v); 711 return input_set_keycode(dev, t, v);
635 712
636 case EVIOCSFF:
637 if (copy_from_user(&effect, p, sizeof(effect)))
638 return -EFAULT;
639
640 error = input_ff_upload(dev, &effect, file);
641
642 if (put_user(effect.id, &(((struct ff_effect __user *)p)->id)))
643 return -EFAULT;
644
645 return error;
646
647 case EVIOCRMFF: 713 case EVIOCRMFF:
648 return input_ff_erase(dev, (int)(unsigned long) p, file); 714 return input_ff_erase(dev, (int)(unsigned long) p, file);
649 715
@@ -733,6 +799,19 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
733 799
734 if (_IOC_DIR(cmd) == _IOC_WRITE) { 800 if (_IOC_DIR(cmd) == _IOC_WRITE) {
735 801
802 if (_IOC_NR(cmd) == _IOC_NR(EVIOCSFF)) {
803
804 if (evdev_ff_effect_from_user(p, _IOC_SIZE(cmd), &effect))
805 return -EFAULT;
806
807 error = input_ff_upload(dev, &effect, file);
808
809 if (put_user(effect.id, &(((struct ff_effect __user *)p)->id)))
810 return -EFAULT;
811
812 return error;
813 }
814
736 if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) { 815 if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
737 816
738 t = _IOC_NR(cmd) & ABS_MAX; 817 t = _IOC_NR(cmd) & ABS_MAX;