Fix force feedback uploading for 32-bit apps on 64-bit kernel
Subsystems (2)
PATCH 1/1 Fix force feedback uploading for 32-bit apps on 64-bit kernel
Hello,
Force feedback upload of effects through the event device (ioctl EVIOCSFF) is not working in 32 bit apps like wine on a 64-bit kernel. 64 bit apps like fftest work.
This is due to the fact that struct ff_effect contains a pointer, resulting in the structure having different sizes in 64 and 32 bit programs. This means that the ioctl issued from 32 bit code isn't handled, because it has a different number.
Attached patch (against 2.6.24.3) fixes this. Tested on x86_64.
Is this ok or are there some alignment issues, which forbid this simple zero-copy solution?
PS. Please keep me in the CC list, as I'm not subscribing this list.
drivers/input/evdev.c +22 -1
@@ -577,6 +577,9 @@ static long evdev_do_ioctl(struct file *struct input_dev *dev = evdev->handle.dev;struct input_absinfo abs;struct ff_effect effect; +#ifdef CONFIG_COMPAT +struct ff_effect32 *effect32; +#endif int __user *ip = (int __user *)p;int i, t, u, v;int error;
@@ -632,10 +635,28 @@ static long evdev_do_ioctl(struct file *return dev->setkeycode (dev, t, v); +#ifdef CONFIG_COMPAT +case EVIOCSFF32 : +#endif case EVIOCSFF : -if (copy_from_user (&effect, p,sizeof (effect))) +if (copy_from_user (&effect, p,_IOC_SIZE (cmd)))return -EFAULT ; +#ifdef CONFIG_COMPAT +/* +* It so happens that the pointer which needs to be changed +* is the last field in the structure, so we can copy the +* whole thing and replace just the pointer. +*/ +if (cmd ==EVIOCSFF32 ) { + effect32 = (struct ff_effect32 *)&effect; +if (effect32->type ==FF_PERIODIC && + effect32->u.periodic.waveform ==FF_CUSTOM ) + effect.u.periodic.custom_data =compat_ptr ( + effect32->u.periodic.custom_data); + } +#endif + error =input_ff_upload (dev, &effect, file);if (put_user (effect.id, &(((struct ff_effect __user *)p)->id)))
include/linux/input.h +38 -1
@@ -12,6 +12,7 @@#ifdef __KERNEL__#include <linux/time.h> #include <linux/list.h> +#include <linux/compat.h> #else #include <sys/time.h> #include <sys/ioctl.h>
@@ -75,7 +76,10 @@ struct input_absinfo {#define EVIOCGABS (abs) _IOR('E', 0x40 + abs, struct input_absinfo)/* get abs value/limits */ #define EVIOCSABS (abs) _IOW('E', 0xc0 + abs, struct input_absinfo)/* set abs value/limits */ -#define EVIOCSFF _IOC(_IOC_WRITE, 'E', 0x80, sizeof(struct ff_effect))/* send a force effect to a force feedback device */ +#define EVIOCSFF _IOW('E', 0x80, struct ff_effect)/* send a force effect to a force feedback device */ +#ifdef CONFIG_COMPAT +#define EVIOCSFF32 _IOW('E', 0x80, struct ff_effect32) +#endif #define EVIOCRMFF _IOW('E', 0x81, int)/* Erase a force effect */ #define EVIOCGEFFECTS _IOR('E', 0x84, int)/* Report number of effects playable at the same time */
@@ -846,6 +850,21 @@ struct ff_periodic_effect {__s16 *custom_data; }; +#ifdef CONFIG_COMPAT +struct ff_periodic_effect32 { +__u16 waveform; +__u16 period; +__s16 magnitude; +__s16 offset; +__u16 phase; + +struct ff_envelope envelope; + +__u32 custom_len; +compat_uptr_t custom_data; +}; +#endif +/** * struct ff_rumble_effect - defines parameters of a periodic force-feedback effect * @strong_magnitude: magnitude of the heavy motor
@@ -898,6 +917,24 @@ struct ff_effect { } u; }; +#ifdef CONFIG_COMPAT +struct ff_effect32 { +__u16 type; +__s16 id; +__u16 direction; +struct ff_trigger trigger; +struct ff_replay replay; + +union { +struct ff_constant_effect constant; +struct ff_ramp_effect ramp; +struct ff_periodic_effect32 periodic; +struct ff_condition_effect condition[2 ];/* One for each axis */ +struct ff_rumble_effect rumble; + } u; +}; +#endif +/* * Force feedback effect types */