aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hid')
-rw-r--r--drivers/hid/hid-core.c10
-rw-r--r--drivers/hid/hidraw.c46
-rw-r--r--drivers/hid/usbhid/hiddev.c14
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 */
781static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value) 781static __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:
105static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) 105static 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
219static int hidraw_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) 220static 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
268static const struct file_operations hidraw_ops = { 270static 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
278void hidraw_report_event(struct hid_device *hid, u8 *data, int len) 280void 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
503goodreturn: 504goodreturn:
505 unlock_kernel();
504 kfree(uref_multi); 506 kfree(uref_multi);
505 return 0; 507 return 0;
506fault: 508fault:
509 unlock_kernel();
507 kfree(uref_multi); 510 kfree(uref_multi);
508 return -EFAULT; 511 return -EFAULT;
509inval: 512inval:
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
543static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) 547static 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
757static long hiddev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 764static 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,