[PATCH] Re: Implement compat_ioctl for joydev (updated)

From: Jeremy Fitzhardinge
Date: Mon Mar 07 2005 - 05:10:35 EST


Andrew Morton wrote:

Jeremy Fitzhardinge <jeremy@xxxxxxxx> wrote:


+ if (!joydev->exist) return -ENODEV;



eww.


How's this? First patch is a (not particularly thorough) indentation/whitespace cleanup, second implements compat_ioctl.

J Index: local-2.6/drivers/input/joydev.c
===================================================================
--- local-2.6.orig/drivers/input/joydev.c 2005-03-07 01:48:33.000000000 -0800
+++ local-2.6/drivers/input/joydev.c 2005-03-07 01:53:10.000000000 -0800
@@ -72,20 +72,22 @@

static int joydev_correct(int value, struct js_corr *corr)
{
- switch (corr->type) {
- case JS_CORR_NONE:
- break;
- case JS_CORR_BROKEN:
- value = value > corr->coef[0] ? (value < corr->coef[1] ? 0 :
- ((corr->coef[3] * (value - corr->coef[1])) >> 14)) :
- ((corr->coef[2] * (value - corr->coef[0])) >> 14);
- break;
- default:
- return 0;
+ switch(corr->type) {
+ case JS_CORR_NONE:
+ break;
+ case JS_CORR_BROKEN:
+ value = value > corr->coef[0] ? (value < corr->coef[1] ? 0 :
+ ((corr->coef[3] * (value - corr->coef[1])) >> 14)) :
+ ((corr->coef[2] * (value - corr->coef[0])) >> 14);
+ break;
+ default:
+ return 0;
}

- if (value < -32767) return -32767;
- if (value > 32767) return 32767;
+ if (value < -32767)
+ return -32767;
+ if (value > 32767)
+ return 32767;

return value;
}
@@ -97,24 +99,23 @@
struct js_event event;

switch (type) {
+ case EV_KEY:
+ if (code < BTN_MISC || value == 2) return;
+ event.type = JS_EVENT_BUTTON;
+ event.number = joydev->keymap[code - BTN_MISC];
+ event.value = value;
+ break;
+
+ case EV_ABS:
+ event.type = JS_EVENT_AXIS;
+ event.number = joydev->absmap[code];
+ event.value = joydev_correct(value, joydev->corr + event.number);
+ if (event.value == joydev->abs[event.number]) return;
+ joydev->abs[event.number] = event.value;
+ break;

- case EV_KEY:
- if (code < BTN_MISC || value == 2) return;
- event.type = JS_EVENT_BUTTON;
- event.number = joydev->keymap[code - BTN_MISC];
- event.value = value;
- break;
-
- case EV_ABS:
- event.type = JS_EVENT_AXIS;
- event.number = joydev->absmap[code];
- event.value = joydev_correct(value, joydev->corr + event.number);
- if (event.value == joydev->abs[event.number]) return;
- joydev->abs[event.number] = event.value;
- break;
-
- default:
- return;
+ default:
+ return;
}

event.time = MSECS(jiffies);
@@ -294,80 +295,97 @@
void __user *argp = (void __user *)arg;
int i, j;

- if (!joydev->exist) return -ENODEV;
+ if (!joydev->exist)
+ return -ENODEV;

switch (cmd) {
+ case JS_SET_CAL:
+ return copy_from_user(&joydev->glue.JS_CORR, argp,
+ sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
+
+ case JS_GET_CAL:
+ return copy_to_user(argp, &joydev->glue.JS_CORR,
+ sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
+
+ case JS_SET_TIMEOUT:
+ return get_user(joydev->glue.JS_TIMEOUT, (int __user *) arg);
+
+ case JS_GET_TIMEOUT:
+ return put_user(joydev->glue.JS_TIMEOUT, (int __user *) arg);
+
+ case JS_SET_TIMELIMIT:
+ return get_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
+
+ case JS_GET_TIMELIMIT:
+ return put_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
+
+ case JS_SET_ALL:
+ return copy_from_user(&joydev->glue, argp,
+ sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0;
+
+ case JS_GET_ALL:
+ return copy_to_user(argp, &joydev->glue,
+ sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0;
+
+
+ case JSIOCGVERSION:
+ return put_user(JS_VERSION, (__u32 __user *) arg);
+
+ case JSIOCGAXES:
+ return put_user(joydev->nabs, (__u8 __user *) arg);
+
+ case JSIOCGBUTTONS:
+ return put_user(joydev->nkey, (__u8 __user *) arg);

- case JS_SET_CAL:
- return copy_from_user(&joydev->glue.JS_CORR, argp,
- sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
- case JS_GET_CAL:
- return copy_to_user(argp, &joydev->glue.JS_CORR,
- sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
- case JS_SET_TIMEOUT:
- return get_user(joydev->glue.JS_TIMEOUT, (int __user *) arg);
- case JS_GET_TIMEOUT:
- return put_user(joydev->glue.JS_TIMEOUT, (int __user *) arg);
- case JS_SET_TIMELIMIT:
- return get_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
- case JS_GET_TIMELIMIT:
- return put_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
- case JS_SET_ALL:
- return copy_from_user(&joydev->glue, argp,
- sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0;
- case JS_GET_ALL:
- return copy_to_user(argp, &joydev->glue,
- sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0;
-
- case JSIOCGVERSION:
- return put_user(JS_VERSION, (__u32 __user *) arg);
- case JSIOCGAXES:
- return put_user(joydev->nabs, (__u8 __user *) arg);
- case JSIOCGBUTTONS:
- return put_user(joydev->nkey, (__u8 __user *) arg);
- case JSIOCSCORR:
- if (copy_from_user(joydev->corr, argp,
- sizeof(struct js_corr) * joydev->nabs))
- return -EFAULT;
- for (i = 0; i < joydev->nabs; i++) {
- j = joydev->abspam[i];
- joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i);
- }
- return 0;
- case JSIOCGCORR:
- return copy_to_user(argp, joydev->corr,
- sizeof(struct js_corr) * joydev->nabs) ? -EFAULT : 0;
- case JSIOCSAXMAP:
- if (copy_from_user(joydev->abspam, argp, sizeof(__u8) * ABS_MAX))
- return -EFAULT;
- for (i = 0; i < joydev->nabs; i++) {
- if (joydev->abspam[i] > ABS_MAX) return -EINVAL;
- joydev->absmap[joydev->abspam[i]] = i;
- }
- return 0;
- case JSIOCGAXMAP:
- return copy_to_user(argp, joydev->abspam,
- sizeof(__u8) * ABS_MAX) ? -EFAULT : 0;
- case JSIOCSBTNMAP:
- if (copy_from_user(joydev->keypam, argp, sizeof(__u16) * (KEY_MAX - BTN_MISC)))
- return -EFAULT;
- for (i = 0; i < joydev->nkey; i++) {
- if (joydev->keypam[i] > KEY_MAX || joydev->keypam[i] < BTN_MISC) return -EINVAL;
- joydev->keymap[joydev->keypam[i] - BTN_MISC] = i;
- }
- return 0;
- case JSIOCGBTNMAP:
- return copy_to_user(argp, joydev->keypam,
- sizeof(__u16) * (KEY_MAX - BTN_MISC)) ? -EFAULT : 0;
- default:
- if ((cmd & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) == JSIOCGNAME(0)) {
- int len;
- if (!dev->name) return 0;
- len = strlen(dev->name) + 1;
- if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
- if (copy_to_user(argp, dev->name, len)) return -EFAULT;
- return len;
- }
+ case JSIOCSCORR:
+ if (copy_from_user(joydev->corr, argp,
+ sizeof(struct js_corr) * joydev->nabs))
+ return -EFAULT;
+ for (i = 0; i < joydev->nabs; i++) {
+ j = joydev->abspam[i];
+ joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i);
+ }
+ return 0;
+
+ case JSIOCGCORR:
+ return copy_to_user(argp, joydev->corr,
+ sizeof(struct js_corr) * joydev->nabs) ? -EFAULT : 0;
+
+ case JSIOCSAXMAP:
+ if (copy_from_user(joydev->abspam, argp, sizeof(__u8) * ABS_MAX))
+ return -EFAULT;
+ for (i = 0; i < joydev->nabs; i++) {
+ if (joydev->abspam[i] > ABS_MAX) return -EINVAL;
+ joydev->absmap[joydev->abspam[i]] = i;
+ }
+ return 0;
+
+ case JSIOCGAXMAP:
+ return copy_to_user(argp, joydev->abspam,
+ sizeof(__u8) * ABS_MAX) ? -EFAULT : 0;
+
+ case JSIOCSBTNMAP:
+ if (copy_from_user(joydev->keypam, argp, sizeof(__u16) * (KEY_MAX - BTN_MISC)))
+ return -EFAULT;
+ for (i = 0; i < joydev->nkey; i++) {
+ if (joydev->keypam[i] > KEY_MAX || joydev->keypam[i] < BTN_MISC) return -EINVAL;
+ joydev->keymap[joydev->keypam[i] - BTN_MISC] = i;
+ }
+ return 0;
+
+ case JSIOCGBTNMAP:
+ return copy_to_user(argp, joydev->keypam,
+ sizeof(__u16) * (KEY_MAX - BTN_MISC)) ? -EFAULT : 0;
+
+ default:
+ if ((cmd & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) == JSIOCGNAME(0)) {
+ int len;
+ if (!dev->name) return 0;
+ len = strlen(dev->name) + 1;
+ if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+ if (copy_to_user(argp, dev->name, len)) return -EFAULT;
+ return len;
+ }
}
return -EINVAL;
}
@@ -383,12 +401,15 @@
.fasync = joydev_fasync,
};

-static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id)
+static struct input_handle *joydev_connect(struct input_handler *handler,
+ struct input_dev *dev, struct input_device_id *id)
{
struct joydev *joydev;
int i, j, t, minor;

- for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++);
+ for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++)
+ ;
+
if (minor == JOYDEV_MINORS) {
printk(KERN_ERR "joydev: no more free joydev devices\n");
return NULL;
This patch implements compat_ioctl for joydev. I've tested it with a
Logitech WingMan Rumblepad on an x86-64 machine, and on an ia32
machine to make sure I didn't break anything.

Patch against stock 2.6.11, but also tested with 2.6.11-mm1.

Signed-off-by: Jeremy Fitzhardinge <jeremy@xxxxxxxx>

Index: local-2.6/include/linux/joystick.h
===================================================================
--- local-2.6.orig/include/linux/joystick.h 2005-03-07 01:46:38.000000000 -0800
+++ local-2.6/include/linux/joystick.h 2005-03-07 01:54:25.000000000 -0800
@@ -111,18 +111,35 @@
#define JS_SET_ALL 8

struct JS_DATA_TYPE {
- int buttons;
- int x;
- int y;
+ __s32 buttons;
+ __s32 x;
+ __s32 y;
};

-struct JS_DATA_SAVE_TYPE {
- int JS_TIMEOUT;
- int BUSY;
- long JS_EXPIRETIME;
- long JS_TIMELIMIT;
+struct JS_DATA_SAVE_TYPE_32 {
+ __s32 JS_TIMEOUT;
+ __s32 BUSY;
+ __s32 JS_EXPIRETIME;
+ __s32 JS_TIMELIMIT;
struct JS_DATA_TYPE JS_SAVE;
struct JS_DATA_TYPE JS_CORR;
};

+struct JS_DATA_SAVE_TYPE_64 {
+ __s32 JS_TIMEOUT;
+ __s32 BUSY;
+ __s64 JS_EXPIRETIME;
+ __s64 JS_TIMELIMIT;
+ struct JS_DATA_TYPE JS_SAVE;
+ struct JS_DATA_TYPE JS_CORR;
+};
+
+#if BITS_PER_LONG == 64
+#define JS_DATA_SAVE_TYPE JS_DATA_SAVE_TYPE_64
+#elif BITS_PER_LONG == 32
+#define JS_DATA_SAVE_TYPE JS_DATA_SAVE_TYPE_32
+#else
+#error Unexpected BITS_PER_LONG
+#endif
+
#endif /* _LINUX_JOYSTICK_H */
Index: local-2.6/drivers/input/joydev.c
===================================================================
--- local-2.6.orig/drivers/input/joydev.c 2005-03-07 01:53:10.000000000 -0800
+++ local-2.6/drivers/input/joydev.c 2005-03-07 01:59:35.000000000 -0800
@@ -287,59 +287,39 @@
return 0;
}

-static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __user *argp)
{
- struct joydev_list *list = file->private_data;
- struct joydev *joydev = list->joydev;
struct input_dev *dev = joydev->handle.dev;
- void __user *argp = (void __user *)arg;
int i, j;

- if (!joydev->exist)
- return -ENODEV;
-
switch (cmd) {
case JS_SET_CAL:
return copy_from_user(&joydev->glue.JS_CORR, argp,
- sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
+ sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0;

case JS_GET_CAL:
return copy_to_user(argp, &joydev->glue.JS_CORR,
- sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
+ sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0;

case JS_SET_TIMEOUT:
- return get_user(joydev->glue.JS_TIMEOUT, (int __user *) arg);
+ return get_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);

case JS_GET_TIMEOUT:
- return put_user(joydev->glue.JS_TIMEOUT, (int __user *) arg);
-
- case JS_SET_TIMELIMIT:
- return get_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
-
- case JS_GET_TIMELIMIT:
- return put_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
-
- case JS_SET_ALL:
- return copy_from_user(&joydev->glue, argp,
- sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0;
-
- case JS_GET_ALL:
- return copy_to_user(argp, &joydev->glue,
- sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0;
+ return put_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);


case JSIOCGVERSION:
- return put_user(JS_VERSION, (__u32 __user *) arg);
+ return put_user(JS_VERSION, (__u32 __user *) argp);

case JSIOCGAXES:
- return put_user(joydev->nabs, (__u8 __user *) arg);
+ return put_user(joydev->nabs, (__u8 __user *) argp);

case JSIOCGBUTTONS:
- return put_user(joydev->nkey, (__u8 __user *) arg);
+ return put_user(joydev->nkey, (__u8 __user *) argp);

case JSIOCSCORR:
if (copy_from_user(joydev->corr, argp,
- sizeof(struct js_corr) * joydev->nabs))
+ sizeof(joydev->corr[0]) * joydev->nabs))
return -EFAULT;
for (i = 0; i < joydev->nabs; i++) {
j = joydev->abspam[i];
@@ -390,6 +370,92 @@
return -EINVAL;
}

+#ifdef CONFIG_COMPAT
+static long joydev_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg)
+{
+ struct joydev_list *list = file->private_data;
+ struct joydev *joydev = list->joydev;
+ void __user *argp = (void __user *)arg;
+ s32 tmp32;
+ struct JS_DATA_SAVE_TYPE_32 ds32;
+ int err;
+
+ if (!joydev->exist)
+ return -ENODEV;
+
+ switch(cmd) {
+ case JS_SET_TIMELIMIT:
+ err = get_user(tmp32, (s32 __user *) arg);
+ if (err == 0)
+ joydev->glue.JS_TIMELIMIT = tmp32;
+ break;
+
+ case JS_GET_TIMELIMIT:
+ tmp32 = joydev->glue.JS_TIMELIMIT;
+ err = put_user(tmp32, (s32 __user *) arg);
+ break;
+
+ case JS_SET_ALL:
+ err = copy_from_user(&ds32, argp,
+ sizeof(ds32)) ? -EFAULT : 0;
+ if (err == 0) {
+ joydev->glue.JS_TIMEOUT = ds32.JS_TIMEOUT;
+ joydev->glue.BUSY = ds32.BUSY;
+ joydev->glue.JS_EXPIRETIME = ds32.JS_EXPIRETIME;
+ joydev->glue.JS_TIMELIMIT = ds32.JS_TIMELIMIT;
+ joydev->glue.JS_SAVE = ds32.JS_SAVE;
+ joydev->glue.JS_CORR = ds32.JS_CORR;
+ }
+ break;
+
+ case JS_GET_ALL:
+ ds32.JS_TIMEOUT = joydev->glue.JS_TIMEOUT;
+ ds32.BUSY = joydev->glue.BUSY;
+ ds32.JS_EXPIRETIME = joydev->glue.JS_EXPIRETIME;
+ ds32.JS_TIMELIMIT = joydev->glue.JS_TIMELIMIT;
+ ds32.JS_SAVE = joydev->glue.JS_SAVE;
+ ds32.JS_CORR = joydev->glue.JS_CORR;
+
+ err = copy_to_user(argp, &ds32,
+ sizeof(ds32)) ? -EFAULT : 0;
+ break;
+
+ default:
+ err = joydev_ioctl_common(joydev, cmd, argp);
+ }
+ return err;
+}
+#endif /* CONFIG_COMPAT */
+
+static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct joydev_list *list = file->private_data;
+ struct joydev *joydev = list->joydev;
+ void __user *argp = (void __user *)arg;
+
+ if (!joydev->exist)
+ return -ENODEV;
+
+ switch(cmd) {
+ case JS_SET_TIMELIMIT:
+ return get_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
+
+ case JS_GET_TIMELIMIT:
+ return put_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
+
+ case JS_SET_ALL:
+ return copy_from_user(&joydev->glue, argp,
+ sizeof(joydev->glue)) ? -EFAULT : 0;
+
+ case JS_GET_ALL:
+ return copy_to_user(argp, &joydev->glue,
+ sizeof(joydev->glue)) ? -EFAULT : 0;
+
+ default:
+ return joydev_ioctl_common(joydev, cmd, argp);
+ }
+}
+
static struct file_operations joydev_fops = {
.owner = THIS_MODULE,
.read = joydev_read,
@@ -398,6 +464,9 @@
.open = joydev_open,
.release = joydev_release,
.ioctl = joydev_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = joydev_compat_ioctl,
+#endif
.fasync = joydev_fasync,
};