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 f43d6d3cf2fa..426ac5add585 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) | |||
780 | */ | 780 | */ |
781 | static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value) | 781 | static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value) |
782 | { | 782 | { |
783 | __le64 x; | 783 | u64 x; |
784 | u64 m = (1ULL << n) - 1; | 784 | u64 m = (1ULL << n) - 1; |
785 | 785 | ||
786 | if (n > 32) | 786 | if (n > 32) |
@@ -796,10 +796,10 @@ static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u3 | |||
796 | report += offset >> 3; | 796 | report += offset >> 3; |
797 | offset &= 7; | 797 | offset &= 7; |
798 | 798 | ||
799 | x = get_unaligned((__le64 *)report); | 799 | x = get_unaligned_le64(report); |
800 | x &= cpu_to_le64(~(m << offset)); | 800 | x &= ~(m << offset); |
801 | x |= cpu_to_le64(((u64) value) << offset); | 801 | x |= ((u64)value) << offset; |
802 | put_unaligned(x, (__le64 *) report); | 802 | put_unaligned_le64(x, report); |
803 | } | 803 | } |
804 | 804 | ||
805 | /* | 805 | /* |
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index 8ecd77525103..c40f0403edaf 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c | |||
@@ -105,6 +105,7 @@ out: | |||
105 | static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) | 105 | static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) |
106 | { | 106 | { |
107 | unsigned int minor = iminor(file->f_path.dentry->d_inode); | 107 | unsigned int minor = iminor(file->f_path.dentry->d_inode); |
108 | /* FIXME: What stops hidraw_table going NULL */ | ||
108 | struct hid_device *dev = hidraw_table[minor]->hid; | 109 | struct hid_device *dev = hidraw_table[minor]->hid; |
109 | __u8 *buf; | 110 | __u8 *buf; |
110 | int ret = 0; | 111 | int ret = 0; |
@@ -216,35 +217,38 @@ static int hidraw_release(struct inode * inode, struct file * file) | |||
216 | return 0; | 217 | return 0; |
217 | } | 218 | } |
218 | 219 | ||
219 | static int hidraw_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) | 220 | static long hidraw_ioctl(struct file *file, unsigned int cmd, |
221 | unsigned long arg) | ||
220 | { | 222 | { |
223 | struct inode *inode = file->f_path.dentry->d_inode; | ||
221 | unsigned int minor = iminor(inode); | 224 | unsigned int minor = iminor(inode); |
225 | long ret = 0; | ||
226 | /* FIXME: What stops hidraw_table going NULL */ | ||
222 | struct hidraw *dev = hidraw_table[minor]; | 227 | struct hidraw *dev = hidraw_table[minor]; |
223 | void __user *user_arg = (void __user*) arg; | 228 | void __user *user_arg = (void __user*) arg; |
224 | 229 | ||
230 | lock_kernel(); | ||
225 | switch (cmd) { | 231 | switch (cmd) { |
226 | case HIDIOCGRDESCSIZE: | 232 | case HIDIOCGRDESCSIZE: |
227 | if (put_user(dev->hid->rsize, (int __user *)arg)) | 233 | if (put_user(dev->hid->rsize, (int __user *)arg)) |
228 | return -EFAULT; | 234 | ret = -EFAULT; |
229 | return 0; | 235 | break; |
230 | 236 | ||
231 | case HIDIOCGRDESC: | 237 | case HIDIOCGRDESC: |
232 | { | 238 | { |
233 | __u32 len; | 239 | __u32 len; |
234 | 240 | ||
235 | if (get_user(len, (int __user *)arg)) | 241 | if (get_user(len, (int __user *)arg)) |
236 | return -EFAULT; | 242 | ret = -EFAULT; |
237 | 243 | else if (len > HID_MAX_DESCRIPTOR_SIZE - 1) | |
238 | if (len > HID_MAX_DESCRIPTOR_SIZE - 1) | 244 | ret = -EINVAL; |
239 | return -EINVAL; | 245 | else if (copy_to_user(user_arg + offsetof( |
240 | 246 | struct hidraw_report_descriptor, | |
241 | if (copy_to_user(user_arg + offsetof( | 247 | value[0]), |
242 | struct hidraw_report_descriptor, | 248 | dev->hid->rdesc, |
243 | value[0]), | 249 | min(dev->hid->rsize, len))) |
244 | dev->hid->rdesc, | 250 | ret = -EFAULT; |
245 | min(dev->hid->rsize, len))) | 251 | break; |
246 | return -EFAULT; | ||
247 | return 0; | ||
248 | } | 252 | } |
249 | case HIDIOCGRAWINFO: | 253 | case HIDIOCGRAWINFO: |
250 | { | 254 | { |
@@ -254,15 +258,13 @@ static int hidraw_ioctl(struct inode *inode, struct file *file, unsigned int cmd | |||
254 | dinfo.vendor = dev->hid->vendor; | 258 | dinfo.vendor = dev->hid->vendor; |
255 | dinfo.product = dev->hid->product; | 259 | dinfo.product = dev->hid->product; |
256 | if (copy_to_user(user_arg, &dinfo, sizeof(dinfo))) | 260 | if (copy_to_user(user_arg, &dinfo, sizeof(dinfo))) |
257 | return -EFAULT; | 261 | ret = -EFAULT; |
258 | 262 | break; | |
259 | return 0; | ||
260 | } | 263 | } |
261 | default: | 264 | default: |
262 | printk(KERN_EMERG "hidraw: unsupported ioctl() %x\n", | 265 | ret = -ENOTTY; |
263 | cmd); | ||
264 | } | 266 | } |
265 | return -EINVAL; | 267 | return ret; |
266 | } | 268 | } |
267 | 269 | ||
268 | static const struct file_operations hidraw_ops = { | 270 | static const struct file_operations hidraw_ops = { |
@@ -272,7 +274,7 @@ static const struct file_operations hidraw_ops = { | |||
272 | .poll = hidraw_poll, | 274 | .poll = hidraw_poll, |
273 | .open = hidraw_open, | 275 | .open = hidraw_open, |
274 | .release = hidraw_release, | 276 | .release = hidraw_release, |
275 | .ioctl = hidraw_ioctl, | 277 | .unlocked_ioctl = hidraw_ioctl, |
276 | }; | 278 | }; |
277 | 279 | ||
278 | void hidraw_report_event(struct hid_device *hid, u8 *data, int len) | 280 | 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 95cc192bc7af..842e9edb888e 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, | |||
406 | uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL); | 406 | uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL); |
407 | if (!uref_multi) | 407 | if (!uref_multi) |
408 | return -ENOMEM; | 408 | return -ENOMEM; |
409 | lock_kernel(); | ||
409 | uref = &uref_multi->uref; | 410 | uref = &uref_multi->uref; |
410 | if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) { | 411 | if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) { |
411 | if (copy_from_user(uref_multi, user_arg, | 412 | if (copy_from_user(uref_multi, user_arg, |
@@ -501,12 +502,15 @@ static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd, | |||
501 | } | 502 | } |
502 | 503 | ||
503 | goodreturn: | 504 | goodreturn: |
505 | unlock_kernel(); | ||
504 | kfree(uref_multi); | 506 | kfree(uref_multi); |
505 | return 0; | 507 | return 0; |
506 | fault: | 508 | fault: |
509 | unlock_kernel(); | ||
507 | kfree(uref_multi); | 510 | kfree(uref_multi); |
508 | return -EFAULT; | 511 | return -EFAULT; |
509 | inval: | 512 | inval: |
513 | unlock_kernel(); | ||
510 | kfree(uref_multi); | 514 | kfree(uref_multi); |
511 | return -EINVAL; | 515 | return -EINVAL; |
512 | } | 516 | } |
@@ -540,7 +544,7 @@ static noinline int hiddev_ioctl_string(struct hiddev *hiddev, unsigned int cmd, | |||
540 | return len; | 544 | return len; |
541 | } | 545 | } |
542 | 546 | ||
543 | static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) | 547 | static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
544 | { | 548 | { |
545 | struct hiddev_list *list = file->private_data; | 549 | struct hiddev_list *list = file->private_data; |
546 | struct hiddev *hiddev = list->hiddev; | 550 | struct hiddev *hiddev = list->hiddev; |
@@ -555,7 +559,10 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd | |||
555 | struct usbhid_device *usbhid = hid->driver_data; | 559 | struct usbhid_device *usbhid = hid->driver_data; |
556 | void __user *user_arg = (void __user *)arg; | 560 | void __user *user_arg = (void __user *)arg; |
557 | int i; | 561 | int i; |
562 | |||
563 | /* Called without BKL by compat methods so no BKL taken */ | ||
558 | 564 | ||
565 | /* FIXME: Who or what stop this racing with a disconnect ?? */ | ||
559 | if (!hiddev->exist) | 566 | if (!hiddev->exist) |
560 | return -EIO; | 567 | return -EIO; |
561 | 568 | ||
@@ -756,8 +763,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd | |||
756 | #ifdef CONFIG_COMPAT | 763 | #ifdef CONFIG_COMPAT |
757 | static long hiddev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | 764 | static long hiddev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
758 | { | 765 | { |
759 | struct inode *inode = file->f_path.dentry->d_inode; | 766 | return hiddev_ioctl(file, cmd, (unsigned long)compat_ptr(arg)); |
760 | return hiddev_ioctl(inode, file, cmd, (unsigned long)compat_ptr(arg)); | ||
761 | } | 767 | } |
762 | #endif | 768 | #endif |
763 | 769 | ||
@@ -768,7 +774,7 @@ static const struct file_operations hiddev_fops = { | |||
768 | .poll = hiddev_poll, | 774 | .poll = hiddev_poll, |
769 | .open = hiddev_open, | 775 | .open = hiddev_open, |
770 | .release = hiddev_release, | 776 | .release = hiddev_release, |
771 | .ioctl = hiddev_ioctl, | 777 | .unlocked_ioctl = hiddev_ioctl, |
772 | .fasync = hiddev_fasync, | 778 | .fasync = hiddev_fasync, |
773 | #ifdef CONFIG_COMPAT | 779 | #ifdef CONFIG_COMPAT |
774 | .compat_ioctl = hiddev_compat_ioctl, | 780 | .compat_ioctl = hiddev_compat_ioctl, |