diff options
Diffstat (limited to 'drivers/hid')
-rw-r--r-- | drivers/hid/hid-core.c | 10 | ||||
-rw-r--r-- | drivers/hid/hidraw.c | 46 | ||||
-rw-r--r-- | drivers/hid/usbhid/hiddev.c | 14 |
3 files changed, 39 insertions, 31 deletions
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index f43d6d3cf2f..426ac5add58 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -780,7 +780,7 @@ static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n) */ static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value) { - __le64 x; + u64 x; u64 m = (1ULL << n) - 1; if (n > 32) @@ -796,10 +796,10 @@ static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u3 report += offset >> 3; offset &= 7; - x = get_unaligned((__le64 *)report); - x &= cpu_to_le64(~(m << offset)); - x |= cpu_to_le64(((u64) value) << offset); - put_unaligned(x, (__le64 *) report); + x = get_unaligned_le64(report); + x &= ~(m << offset); + x |= ((u64)value) << offset; + put_unaligned_le64(x, report); } /* diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index 8ecd7752510..c40f0403eda 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -105,6 +105,7 @@ out: static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { unsigned int minor = iminor(file->f_path.dentry->d_inode); + /* FIXME: What stops hidraw_table going NULL */ struct hid_device *dev = hidraw_table[minor]->hid; __u8 *buf; int ret = 0; @@ -216,35 +217,38 @@ static int hidraw_release(struct inode * inode, struct file * file) return 0; } -static int hidraw_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +static long hidraw_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) { + struct inode *inode = file->f_path.dentry->d_inode; unsigned int minor = iminor(inode); + long ret = 0; + /* FIXME: What stops hidraw_table going NULL */ struct hidraw *dev = hidraw_table[minor]; void __user *user_arg = (void __user*) arg; + lock_kernel(); switch (cmd) { case HIDIOCGRDESCSIZE: if (put_user(dev->hid->rsize, (int __user *)arg)) - return -EFAULT; - return 0; + ret = -EFAULT; + break; case HIDIOCGRDESC: { __u32 len; if (get_user(len, (int __user *)arg)) - return -EFAULT; - - if (len > HID_MAX_DESCRIPTOR_SIZE - 1) - return -EINVAL; - - if (copy_to_user(user_arg + offsetof( - struct hidraw_report_descriptor, - value[0]), - dev->hid->rdesc, - min(dev->hid->rsize, len))) - return -EFAULT; - return 0; + ret = -EFAULT; + else if (len > HID_MAX_DESCRIPTOR_SIZE - 1) + ret = -EINVAL; + else if (copy_to_user(user_arg + offsetof( + struct hidraw_report_descriptor, + value[0]), + dev->hid->rdesc, + min(dev->hid->rsize, len))) + ret = -EFAULT; + break; } case HIDIOCGRAWINFO: { @@ -254,15 +258,13 @@ static int hidraw_ioctl(struct inode *inode, struct file *file, unsigned int cmd dinfo.vendor = dev->hid->vendor; dinfo.product = dev->hid->product; if (copy_to_user(user_arg, &dinfo, sizeof(dinfo))) - return -EFAULT; - - return 0; + ret = -EFAULT; + break; } default: - printk(KERN_EMERG "hidraw: unsupported ioctl() %x\n", - cmd); + ret = -ENOTTY; } - return -EINVAL; + return ret; } static const struct file_operations hidraw_ops = { @@ -272,7 +274,7 @@ static const struct file_operations hidraw_ops = { .poll = hidraw_poll, .open = hidraw_open, .release = hidraw_release, - .ioctl = hidraw_ioctl, + .unlocked_ioctl = hidraw_ioctl, }; void hidraw_report_event(struct hid_device *hid, u8 *data, int len) diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index 95cc192bc7a..842e9edb888 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -406,6 +406,7 @@ static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd, uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL); if (!uref_multi) return -ENOMEM; + lock_kernel(); uref = &uref_multi->uref; if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) { if (copy_from_user(uref_multi, user_arg, @@ -501,12 +502,15 @@ static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd, } goodreturn: + unlock_kernel(); kfree(uref_multi); return 0; fault: + unlock_kernel(); kfree(uref_multi); return -EFAULT; inval: + unlock_kernel(); kfree(uref_multi); return -EINVAL; } @@ -540,7 +544,7 @@ static noinline int hiddev_ioctl_string(struct hiddev *hiddev, unsigned int cmd, return len; } -static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct hiddev_list *list = file->private_data; struct hiddev *hiddev = list->hiddev; @@ -555,7 +559,10 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd struct usbhid_device *usbhid = hid->driver_data; void __user *user_arg = (void __user *)arg; int i; + + /* Called without BKL by compat methods so no BKL taken */ + /* FIXME: Who or what stop this racing with a disconnect ?? */ if (!hiddev->exist) return -EIO; @@ -756,8 +763,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd #ifdef CONFIG_COMPAT static long hiddev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - struct inode *inode = file->f_path.dentry->d_inode; - return hiddev_ioctl(inode, file, cmd, (unsigned long)compat_ptr(arg)); + return hiddev_ioctl(file, cmd, (unsigned long)compat_ptr(arg)); } #endif @@ -768,7 +774,7 @@ static const struct file_operations hiddev_fops = { .poll = hiddev_poll, .open = hiddev_open, .release = hiddev_release, - .ioctl = hiddev_ioctl, + .unlocked_ioctl = hiddev_ioctl, .fasync = hiddev_fasync, #ifdef CONFIG_COMPAT .compat_ioctl = hiddev_compat_ioctl, |