diff options
-rw-r--r-- | drivers/hid/hid-core.c | 23 | ||||
-rw-r--r-- | drivers/hid/hid-magicmouse.c | 5 | ||||
-rw-r--r-- | drivers/hid/hidraw.c | 48 | ||||
-rw-r--r-- | drivers/hid/usbhid/hid-core.c | 24 | ||||
-rw-r--r-- | drivers/hid/usbhid/hiddev.c | 19 | ||||
-rw-r--r-- | include/linux/hid.h | 8 |
6 files changed, 86 insertions, 41 deletions
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 69fdf1e2347b..33cac4890ca4 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c | |||
@@ -1081,35 +1081,28 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i | |||
1081 | 1081 | ||
1082 | buf = kmalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_ATOMIC); | 1082 | buf = kmalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_ATOMIC); |
1083 | 1083 | ||
1084 | if (!buf) { | 1084 | if (!buf) |
1085 | report = hid_get_report(report_enum, data); | ||
1086 | goto nomem; | 1085 | goto nomem; |
1087 | } | ||
1088 | |||
1089 | snprintf(buf, HID_DEBUG_BUFSIZE - 1, | ||
1090 | "\nreport (size %u) (%snumbered)\n", size, report_enum->numbered ? "" : "un"); | ||
1091 | hid_debug_event(hid, buf); | ||
1092 | |||
1093 | report = hid_get_report(report_enum, data); | ||
1094 | if (!report) { | ||
1095 | kfree(buf); | ||
1096 | return -1; | ||
1097 | } | ||
1098 | 1086 | ||
1099 | /* dump the report */ | 1087 | /* dump the report */ |
1100 | snprintf(buf, HID_DEBUG_BUFSIZE - 1, | 1088 | snprintf(buf, HID_DEBUG_BUFSIZE - 1, |
1101 | "report %d (size %u) = ", report->id, size); | 1089 | "\nreport (size %u) (%snumbered) = ", size, report_enum->numbered ? "" : "un"); |
1102 | hid_debug_event(hid, buf); | 1090 | hid_debug_event(hid, buf); |
1091 | |||
1103 | for (i = 0; i < size; i++) { | 1092 | for (i = 0; i < size; i++) { |
1104 | snprintf(buf, HID_DEBUG_BUFSIZE - 1, | 1093 | snprintf(buf, HID_DEBUG_BUFSIZE - 1, |
1105 | " %02x", data[i]); | 1094 | " %02x", data[i]); |
1106 | hid_debug_event(hid, buf); | 1095 | hid_debug_event(hid, buf); |
1107 | } | 1096 | } |
1108 | hid_debug_event(hid, "\n"); | 1097 | hid_debug_event(hid, "\n"); |
1109 | |||
1110 | kfree(buf); | 1098 | kfree(buf); |
1111 | 1099 | ||
1112 | nomem: | 1100 | nomem: |
1101 | report = hid_get_report(report_enum, data); | ||
1102 | |||
1103 | if (!report) | ||
1104 | return -1; | ||
1105 | |||
1113 | if (hdrv && hdrv->raw_event && hid_match_report(hid, report)) { | 1106 | if (hdrv && hdrv->raw_event && hid_match_report(hid, report)) { |
1114 | ret = hdrv->raw_event(hid, report, data, size); | 1107 | ret = hdrv->raw_event(hid, report, data, size); |
1115 | if (ret != 0) | 1108 | if (ret != 0) |
diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index 0d471fc2ab82..f10d56a15f21 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c | |||
@@ -354,12 +354,15 @@ static int magicmouse_probe(struct hid_device *hdev, | |||
354 | goto err_free; | 354 | goto err_free; |
355 | } | 355 | } |
356 | 356 | ||
357 | ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_HIDINPUT); | 357 | ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); |
358 | if (ret) { | 358 | if (ret) { |
359 | dev_err(&hdev->dev, "magicmouse hw start failed\n"); | 359 | dev_err(&hdev->dev, "magicmouse hw start failed\n"); |
360 | goto err_free; | 360 | goto err_free; |
361 | } | 361 | } |
362 | 362 | ||
363 | /* we are handling the input ourselves */ | ||
364 | hidinput_disconnect(hdev); | ||
365 | |||
363 | report = hid_register_report(hdev, HID_INPUT_REPORT, TOUCH_REPORT_ID); | 366 | report = hid_register_report(hdev, HID_INPUT_REPORT, TOUCH_REPORT_ID); |
364 | if (!report) { | 367 | if (!report) { |
365 | dev_err(&hdev->dev, "unable to register touch report\n"); | 368 | dev_err(&hdev->dev, "unable to register touch report\n"); |
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index a9becf9cd0f6..3ccd47850677 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c | |||
@@ -106,38 +106,48 @@ out: | |||
106 | static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) | 106 | static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) |
107 | { | 107 | { |
108 | unsigned int minor = iminor(file->f_path.dentry->d_inode); | 108 | unsigned int minor = iminor(file->f_path.dentry->d_inode); |
109 | /* FIXME: What stops hidraw_table going NULL */ | 109 | struct hid_device *dev; |
110 | struct hid_device *dev = hidraw_table[minor]->hid; | ||
111 | __u8 *buf; | 110 | __u8 *buf; |
112 | int ret = 0; | 111 | int ret = 0; |
113 | 112 | ||
114 | if (!dev->hid_output_raw_report) | 113 | mutex_lock(&minors_lock); |
115 | return -ENODEV; | 114 | dev = hidraw_table[minor]->hid; |
115 | |||
116 | if (!dev->hid_output_raw_report) { | ||
117 | ret = -ENODEV; | ||
118 | goto out; | ||
119 | } | ||
116 | 120 | ||
117 | if (count > HID_MAX_BUFFER_SIZE) { | 121 | if (count > HID_MAX_BUFFER_SIZE) { |
118 | printk(KERN_WARNING "hidraw: pid %d passed too large report\n", | 122 | printk(KERN_WARNING "hidraw: pid %d passed too large report\n", |
119 | task_pid_nr(current)); | 123 | task_pid_nr(current)); |
120 | return -EINVAL; | 124 | ret = -EINVAL; |
125 | goto out; | ||
121 | } | 126 | } |
122 | 127 | ||
123 | if (count < 2) { | 128 | if (count < 2) { |
124 | printk(KERN_WARNING "hidraw: pid %d passed too short report\n", | 129 | printk(KERN_WARNING "hidraw: pid %d passed too short report\n", |
125 | task_pid_nr(current)); | 130 | task_pid_nr(current)); |
126 | return -EINVAL; | 131 | ret = -EINVAL; |
132 | goto out; | ||
127 | } | 133 | } |
128 | 134 | ||
129 | buf = kmalloc(count * sizeof(__u8), GFP_KERNEL); | 135 | buf = kmalloc(count * sizeof(__u8), GFP_KERNEL); |
130 | if (!buf) | 136 | if (!buf) { |
131 | return -ENOMEM; | 137 | ret = -ENOMEM; |
138 | goto out; | ||
139 | } | ||
132 | 140 | ||
133 | if (copy_from_user(buf, buffer, count)) { | 141 | if (copy_from_user(buf, buffer, count)) { |
134 | ret = -EFAULT; | 142 | ret = -EFAULT; |
135 | goto out; | 143 | goto out_free; |
136 | } | 144 | } |
137 | 145 | ||
138 | ret = dev->hid_output_raw_report(dev, buf, count, HID_OUTPUT_REPORT); | 146 | ret = dev->hid_output_raw_report(dev, buf, count, HID_OUTPUT_REPORT); |
139 | out: | 147 | out_free: |
140 | kfree(buf); | 148 | kfree(buf); |
149 | out: | ||
150 | mutex_unlock(&minors_lock); | ||
141 | return ret; | 151 | return ret; |
142 | } | 152 | } |
143 | 153 | ||
@@ -165,11 +175,8 @@ static int hidraw_open(struct inode *inode, struct file *file) | |||
165 | goto out; | 175 | goto out; |
166 | } | 176 | } |
167 | 177 | ||
168 | lock_kernel(); | ||
169 | mutex_lock(&minors_lock); | 178 | mutex_lock(&minors_lock); |
170 | if (!hidraw_table[minor]) { | 179 | if (!hidraw_table[minor]) { |
171 | printk(KERN_EMERG "hidraw device with minor %d doesn't exist\n", | ||
172 | minor); | ||
173 | kfree(list); | 180 | kfree(list); |
174 | err = -ENODEV; | 181 | err = -ENODEV; |
175 | goto out_unlock; | 182 | goto out_unlock; |
@@ -197,7 +204,6 @@ static int hidraw_open(struct inode *inode, struct file *file) | |||
197 | 204 | ||
198 | out_unlock: | 205 | out_unlock: |
199 | mutex_unlock(&minors_lock); | 206 | mutex_unlock(&minors_lock); |
200 | unlock_kernel(); | ||
201 | out: | 207 | out: |
202 | return err; | 208 | return err; |
203 | 209 | ||
@@ -209,11 +215,8 @@ static int hidraw_release(struct inode * inode, struct file * file) | |||
209 | struct hidraw *dev; | 215 | struct hidraw *dev; |
210 | struct hidraw_list *list = file->private_data; | 216 | struct hidraw_list *list = file->private_data; |
211 | 217 | ||
212 | if (!hidraw_table[minor]) { | 218 | if (!hidraw_table[minor]) |
213 | printk(KERN_EMERG "hidraw device with minor %d doesn't exist\n", | ||
214 | minor); | ||
215 | return -ENODEV; | 219 | return -ENODEV; |
216 | } | ||
217 | 220 | ||
218 | list_del(&list->node); | 221 | list_del(&list->node); |
219 | dev = hidraw_table[minor]; | 222 | dev = hidraw_table[minor]; |
@@ -238,11 +241,12 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd, | |||
238 | struct inode *inode = file->f_path.dentry->d_inode; | 241 | struct inode *inode = file->f_path.dentry->d_inode; |
239 | unsigned int minor = iminor(inode); | 242 | unsigned int minor = iminor(inode); |
240 | long ret = 0; | 243 | long ret = 0; |
241 | /* FIXME: What stops hidraw_table going NULL */ | 244 | struct hidraw *dev; |
242 | struct hidraw *dev = hidraw_table[minor]; | ||
243 | void __user *user_arg = (void __user*) arg; | 245 | void __user *user_arg = (void __user*) arg; |
244 | 246 | ||
245 | lock_kernel(); | 247 | mutex_lock(&minors_lock); |
248 | dev = hidraw_table[minor]; | ||
249 | |||
246 | switch (cmd) { | 250 | switch (cmd) { |
247 | case HIDIOCGRDESCSIZE: | 251 | case HIDIOCGRDESCSIZE: |
248 | if (put_user(dev->hid->rsize, (int __user *)arg)) | 252 | if (put_user(dev->hid->rsize, (int __user *)arg)) |
@@ -315,7 +319,7 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd, | |||
315 | 319 | ||
316 | ret = -ENOTTY; | 320 | ret = -ENOTTY; |
317 | } | 321 | } |
318 | unlock_kernel(); | 322 | mutex_unlock(&minors_lock); |
319 | return ret; | 323 | return ret; |
320 | } | 324 | } |
321 | 325 | ||
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index a2ebe1996740..ca3751fd4473 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c | |||
@@ -1313,6 +1313,11 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message) | |||
1313 | { | 1313 | { |
1314 | set_bit(HID_REPORTED_IDLE, &usbhid->iofl); | 1314 | set_bit(HID_REPORTED_IDLE, &usbhid->iofl); |
1315 | spin_unlock_irq(&usbhid->lock); | 1315 | spin_unlock_irq(&usbhid->lock); |
1316 | if (hid->driver && hid->driver->suspend) { | ||
1317 | status = hid->driver->suspend(hid, message); | ||
1318 | if (status < 0) | ||
1319 | return status; | ||
1320 | } | ||
1316 | } else { | 1321 | } else { |
1317 | usbhid_mark_busy(usbhid); | 1322 | usbhid_mark_busy(usbhid); |
1318 | spin_unlock_irq(&usbhid->lock); | 1323 | spin_unlock_irq(&usbhid->lock); |
@@ -1320,6 +1325,11 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message) | |||
1320 | } | 1325 | } |
1321 | 1326 | ||
1322 | } else { | 1327 | } else { |
1328 | if (hid->driver && hid->driver->suspend) { | ||
1329 | status = hid->driver->suspend(hid, message); | ||
1330 | if (status < 0) | ||
1331 | return status; | ||
1332 | } | ||
1323 | spin_lock_irq(&usbhid->lock); | 1333 | spin_lock_irq(&usbhid->lock); |
1324 | set_bit(HID_REPORTED_IDLE, &usbhid->iofl); | 1334 | set_bit(HID_REPORTED_IDLE, &usbhid->iofl); |
1325 | spin_unlock_irq(&usbhid->lock); | 1335 | spin_unlock_irq(&usbhid->lock); |
@@ -1374,6 +1384,11 @@ static int hid_resume(struct usb_interface *intf) | |||
1374 | hid_io_error(hid); | 1384 | hid_io_error(hid); |
1375 | usbhid_restart_queues(usbhid); | 1385 | usbhid_restart_queues(usbhid); |
1376 | 1386 | ||
1387 | if (status >= 0 && hid->driver && hid->driver->resume) { | ||
1388 | int ret = hid->driver->resume(hid); | ||
1389 | if (ret < 0) | ||
1390 | status = ret; | ||
1391 | } | ||
1377 | dev_dbg(&intf->dev, "resume status %d\n", status); | 1392 | dev_dbg(&intf->dev, "resume status %d\n", status); |
1378 | return 0; | 1393 | return 0; |
1379 | } | 1394 | } |
@@ -1382,9 +1397,16 @@ static int hid_reset_resume(struct usb_interface *intf) | |||
1382 | { | 1397 | { |
1383 | struct hid_device *hid = usb_get_intfdata(intf); | 1398 | struct hid_device *hid = usb_get_intfdata(intf); |
1384 | struct usbhid_device *usbhid = hid->driver_data; | 1399 | struct usbhid_device *usbhid = hid->driver_data; |
1400 | int status; | ||
1385 | 1401 | ||
1386 | clear_bit(HID_REPORTED_IDLE, &usbhid->iofl); | 1402 | clear_bit(HID_REPORTED_IDLE, &usbhid->iofl); |
1387 | return hid_post_reset(intf); | 1403 | status = hid_post_reset(intf); |
1404 | if (status >= 0 && hid->driver && hid->driver->reset_resume) { | ||
1405 | int ret = hid->driver->reset_resume(hid); | ||
1406 | if (ret < 0) | ||
1407 | status = ret; | ||
1408 | } | ||
1409 | return status; | ||
1388 | } | 1410 | } |
1389 | 1411 | ||
1390 | #endif /* CONFIG_PM */ | 1412 | #endif /* CONFIG_PM */ |
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index 433602aed468..c24d2fa3e3b6 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c | |||
@@ -267,6 +267,7 @@ static int hiddev_open(struct inode *inode, struct file *file) | |||
267 | struct hiddev_list *list; | 267 | struct hiddev_list *list; |
268 | int res, i; | 268 | int res, i; |
269 | 269 | ||
270 | /* See comment in hiddev_connect() for BKL explanation */ | ||
270 | lock_kernel(); | 271 | lock_kernel(); |
271 | i = iminor(inode) - HIDDEV_MINOR_BASE; | 272 | i = iminor(inode) - HIDDEV_MINOR_BASE; |
272 | 273 | ||
@@ -894,8 +895,22 @@ int hiddev_connect(struct hid_device *hid, unsigned int force) | |||
894 | hiddev->hid = hid; | 895 | hiddev->hid = hid; |
895 | hiddev->exist = 1; | 896 | hiddev->exist = 1; |
896 | 897 | ||
897 | /* when lock_kernel() usage is fixed in usb_open(), | 898 | /* |
898 | * we could also fix it here */ | 899 | * BKL here is used to avoid race after usb_register_dev(). |
900 | * Once the device node has been created, open() could happen on it. | ||
901 | * The code below will then fail, as hiddev_table hasn't been | ||
902 | * updated. | ||
903 | * | ||
904 | * The obvious fix -- introducing mutex to guard hiddev_table[] | ||
905 | * doesn't work, as usb_open() and usb_register_dev() both take | ||
906 | * minor_rwsem, thus we'll have ABBA deadlock. | ||
907 | * | ||
908 | * Before BKL pushdown, usb_open() had been acquiring it in right | ||
909 | * order, so _open() was safe to use it to protect from this race. | ||
910 | * Now the order is different, but AB-BA deadlock still doesn't occur | ||
911 | * as BKL is dropped on schedule() (i.e. while sleeping on | ||
912 | * minor_rwsem). Fugly. | ||
913 | */ | ||
899 | lock_kernel(); | 914 | lock_kernel(); |
900 | retval = usb_register_dev(usbhid->intf, &hiddev_class); | 915 | retval = usb_register_dev(usbhid->intf, &hiddev_class); |
901 | if (retval) { | 916 | if (retval) { |
diff --git a/include/linux/hid.h b/include/linux/hid.h index f1f2b6f0d1c4..895001f7f4b2 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h | |||
@@ -591,6 +591,9 @@ struct hid_usage_id { | |||
591 | * @report_fixup: called before report descriptor parsing (NULL means nop) | 591 | * @report_fixup: called before report descriptor parsing (NULL means nop) |
592 | * @input_mapping: invoked on input registering before mapping an usage | 592 | * @input_mapping: invoked on input registering before mapping an usage |
593 | * @input_mapped: invoked on input registering after mapping an usage | 593 | * @input_mapped: invoked on input registering after mapping an usage |
594 | * @suspend: invoked on suspend (NULL means nop) | ||
595 | * @resume: invoked on resume if device was not reset (NULL means nop) | ||
596 | * @reset_resume: invoked on resume if device was reset (NULL means nop) | ||
594 | * | 597 | * |
595 | * raw_event and event should return 0 on no action performed, 1 when no | 598 | * raw_event and event should return 0 on no action performed, 1 when no |
596 | * further processing should be done and negative on error | 599 | * further processing should be done and negative on error |
@@ -631,6 +634,11 @@ struct hid_driver { | |||
631 | int (*input_mapped)(struct hid_device *hdev, | 634 | int (*input_mapped)(struct hid_device *hdev, |
632 | struct hid_input *hidinput, struct hid_field *field, | 635 | struct hid_input *hidinput, struct hid_field *field, |
633 | struct hid_usage *usage, unsigned long **bit, int *max); | 636 | struct hid_usage *usage, unsigned long **bit, int *max); |
637 | #ifdef CONFIG_PM | ||
638 | int (*suspend)(struct hid_device *hdev, pm_message_t message); | ||
639 | int (*resume)(struct hid_device *hdev); | ||
640 | int (*reset_resume)(struct hid_device *hdev); | ||
641 | #endif | ||
634 | /* private: */ | 642 | /* private: */ |
635 | struct device_driver driver; | 643 | struct device_driver driver; |
636 | }; | 644 | }; |