aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/input/joydev.c106
1 files changed, 74 insertions, 32 deletions
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c
index 9a1d55b74d7a..901b2525993e 100644
--- a/drivers/input/joydev.c
+++ b/drivers/input/joydev.c
@@ -452,6 +452,76 @@ static unsigned int joydev_poll(struct file *file, poll_table *wait)
(joydev->exist ? 0 : (POLLHUP | POLLERR));
}
+static int joydev_handle_JSIOCSAXMAP(struct joydev *joydev,
+ void __user *argp, size_t len)
+{
+ __u8 *abspam;
+ int i;
+ int retval = 0;
+
+ len = min(len, sizeof(joydev->abspam));
+
+ /* Validate the map. */
+ abspam = kmalloc(len, GFP_KERNEL);
+ if (!abspam)
+ return -ENOMEM;
+
+ if (copy_from_user(abspam, argp, len)) {
+ retval = -EFAULT;
+ goto out;
+ }
+
+ for (i = 0; i < joydev->nabs; i++) {
+ if (abspam[i] > ABS_MAX) {
+ retval = -EINVAL;
+ goto out;
+ }
+ }
+
+ memcpy(joydev->abspam, abspam, len);
+
+ out:
+ kfree(abspam);
+ return retval;
+}
+
+static int joydev_handle_JSIOCSBTNMAP(struct joydev *joydev,
+ void __user *argp, size_t len)
+{
+ __u16 *keypam;
+ int i;
+ int retval = 0;
+
+ len = min(len, sizeof(joydev->keypam));
+
+ /* Validate the map. */
+ keypam = kmalloc(len, GFP_KERNEL);
+ if (!keypam)
+ return -ENOMEM;
+
+ if (copy_from_user(keypam, argp, len)) {
+ retval = -EFAULT;
+ goto out;
+ }
+
+ for (i = 0; i < joydev->nkey; i++) {
+ if (keypam[i] > KEY_MAX || keypam[i] < BTN_MISC) {
+ retval = -EINVAL;
+ goto out;
+ }
+ }
+
+ memcpy(joydev->keypam, keypam, len);
+
+ for (i = 0; i < joydev->nkey; i++)
+ joydev->keymap[keypam[i] - BTN_MISC] = i;
+
+ out:
+ kfree(keypam);
+ return retval;
+}
+
+
static int joydev_ioctl_common(struct joydev *joydev,
unsigned int cmd, void __user *argp)
{
@@ -512,46 +582,18 @@ static int joydev_ioctl_common(struct joydev *joydev,
switch (cmd & ~IOCSIZE_MASK) {
case (JSIOCSAXMAP & ~IOCSIZE_MASK):
- len = min_t(size_t, _IOC_SIZE(cmd), sizeof(joydev->abspam));
- /*
- * FIXME: we should not copy into our axis map before
- * validating the data.
- */
- if (copy_from_user(joydev->abspam, argp, len))
- 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;
+ return joydev_handle_JSIOCSAXMAP(joydev, argp, _IOC_SIZE(cmd));
case (JSIOCGAXMAP & ~IOCSIZE_MASK):
len = min_t(size_t, _IOC_SIZE(cmd), sizeof(joydev->abspam));
- return copy_to_user(argp, joydev->abspam, len) ? -EFAULT : 0;
+ return copy_to_user(argp, joydev->abspam, len) ? -EFAULT : len;
case (JSIOCSBTNMAP & ~IOCSIZE_MASK):
- len = min_t(size_t, _IOC_SIZE(cmd), sizeof(joydev->keypam));
- /*
- * FIXME: we should not copy into our keymap before
- * validating the data.
- */
- if (copy_from_user(joydev->keypam, argp, len))
- 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;
+ return joydev_handle_JSIOCSBTNMAP(joydev, argp, _IOC_SIZE(cmd));
case (JSIOCGBTNMAP & ~IOCSIZE_MASK):
len = min_t(size_t, _IOC_SIZE(cmd), sizeof(joydev->keypam));
- return copy_to_user(argp, joydev->keypam, len) ? -EFAULT : 0;
+ return copy_to_user(argp, joydev->keypam, len) ? -EFAULT : len;
case JSIOCGNAME(0):
name = dev->name;