diff options
Diffstat (limited to 'drivers/hid/usbhid/hiddev.c')
-rw-r--r-- | drivers/hid/usbhid/hiddev.c | 34 |
1 files changed, 14 insertions, 20 deletions
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index af0a7c1002af..ff3c644888b1 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c | |||
@@ -242,6 +242,7 @@ static int hiddev_release(struct inode * inode, struct file * file) | |||
242 | list_del(&list->node); | 242 | list_del(&list->node); |
243 | spin_unlock_irqrestore(&list->hiddev->list_lock, flags); | 243 | spin_unlock_irqrestore(&list->hiddev->list_lock, flags); |
244 | 244 | ||
245 | mutex_lock(&list->hiddev->existancelock); | ||
245 | if (!--list->hiddev->open) { | 246 | if (!--list->hiddev->open) { |
246 | if (list->hiddev->exist) { | 247 | if (list->hiddev->exist) { |
247 | usbhid_close(list->hiddev->hid); | 248 | usbhid_close(list->hiddev->hid); |
@@ -252,6 +253,7 @@ static int hiddev_release(struct inode * inode, struct file * file) | |||
252 | } | 253 | } |
253 | 254 | ||
254 | kfree(list); | 255 | kfree(list); |
256 | mutex_unlock(&list->hiddev->existancelock); | ||
255 | 257 | ||
256 | return 0; | 258 | return 0; |
257 | } | 259 | } |
@@ -300,17 +302,21 @@ static int hiddev_open(struct inode *inode, struct file *file) | |||
300 | list_add_tail(&list->node, &hiddev->list); | 302 | list_add_tail(&list->node, &hiddev->list); |
301 | spin_unlock_irq(&list->hiddev->list_lock); | 303 | spin_unlock_irq(&list->hiddev->list_lock); |
302 | 304 | ||
305 | mutex_lock(&hiddev->existancelock); | ||
303 | if (!list->hiddev->open++) | 306 | if (!list->hiddev->open++) |
304 | if (list->hiddev->exist) { | 307 | if (list->hiddev->exist) { |
305 | struct hid_device *hid = hiddev->hid; | 308 | struct hid_device *hid = hiddev->hid; |
306 | res = usbhid_get_power(hid); | 309 | res = usbhid_get_power(hid); |
307 | if (res < 0) { | 310 | if (res < 0) { |
308 | res = -EIO; | 311 | res = -EIO; |
309 | goto bail; | 312 | goto bail_unlock; |
310 | } | 313 | } |
311 | usbhid_open(hid); | 314 | usbhid_open(hid); |
312 | } | 315 | } |
316 | mutex_unlock(&hiddev->existancelock); | ||
313 | return 0; | 317 | return 0; |
318 | bail_unlock: | ||
319 | mutex_unlock(&hiddev->existancelock); | ||
314 | bail: | 320 | bail: |
315 | file->private_data = NULL; | 321 | file->private_data = NULL; |
316 | kfree(list); | 322 | kfree(list); |
@@ -367,8 +373,10 @@ static ssize_t hiddev_read(struct file * file, char __user * buffer, size_t coun | |||
367 | /* let O_NONBLOCK tasks run */ | 373 | /* let O_NONBLOCK tasks run */ |
368 | mutex_unlock(&list->thread_lock); | 374 | mutex_unlock(&list->thread_lock); |
369 | schedule(); | 375 | schedule(); |
370 | if (mutex_lock_interruptible(&list->thread_lock)) | 376 | if (mutex_lock_interruptible(&list->thread_lock)) { |
377 | finish_wait(&list->hiddev->wait, &wait); | ||
371 | return -EINTR; | 378 | return -EINTR; |
379 | } | ||
372 | set_current_state(TASK_INTERRUPTIBLE); | 380 | set_current_state(TASK_INTERRUPTIBLE); |
373 | } | 381 | } |
374 | finish_wait(&list->hiddev->wait, &wait); | 382 | finish_wait(&list->hiddev->wait, &wait); |
@@ -509,7 +517,7 @@ static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd, | |||
509 | (uref_multi->num_values > HID_MAX_MULTI_USAGES || | 517 | (uref_multi->num_values > HID_MAX_MULTI_USAGES || |
510 | uref->usage_index + uref_multi->num_values > field->report_count)) | 518 | uref->usage_index + uref_multi->num_values > field->report_count)) |
511 | goto inval; | 519 | goto inval; |
512 | } | 520 | } |
513 | 521 | ||
514 | switch (cmd) { | 522 | switch (cmd) { |
515 | case HIDIOCGUSAGE: | 523 | case HIDIOCGUSAGE: |
@@ -801,14 +809,7 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
801 | break; | 809 | break; |
802 | 810 | ||
803 | if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGNAME(0))) { | 811 | if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGNAME(0))) { |
804 | int len; | 812 | int len = strlen(hid->name) + 1; |
805 | |||
806 | if (!hid->name) { | ||
807 | r = 0; | ||
808 | break; | ||
809 | } | ||
810 | |||
811 | len = strlen(hid->name) + 1; | ||
812 | if (len > _IOC_SIZE(cmd)) | 813 | if (len > _IOC_SIZE(cmd)) |
813 | len = _IOC_SIZE(cmd); | 814 | len = _IOC_SIZE(cmd); |
814 | r = copy_to_user(user_arg, hid->name, len) ? | 815 | r = copy_to_user(user_arg, hid->name, len) ? |
@@ -817,14 +818,7 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
817 | } | 818 | } |
818 | 819 | ||
819 | if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGPHYS(0))) { | 820 | if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGPHYS(0))) { |
820 | int len; | 821 | int len = strlen(hid->phys) + 1; |
821 | |||
822 | if (!hid->phys) { | ||
823 | r = 0; | ||
824 | break; | ||
825 | } | ||
826 | |||
827 | len = strlen(hid->phys) + 1; | ||
828 | if (len > _IOC_SIZE(cmd)) | 822 | if (len > _IOC_SIZE(cmd)) |
829 | len = _IOC_SIZE(cmd); | 823 | len = _IOC_SIZE(cmd); |
830 | r = copy_to_user(user_arg, hid->phys, len) ? | 824 | r = copy_to_user(user_arg, hid->phys, len) ? |
@@ -925,7 +919,6 @@ void hiddev_disconnect(struct hid_device *hid) | |||
925 | 919 | ||
926 | mutex_lock(&hiddev->existancelock); | 920 | mutex_lock(&hiddev->existancelock); |
927 | hiddev->exist = 0; | 921 | hiddev->exist = 0; |
928 | mutex_unlock(&hiddev->existancelock); | ||
929 | 922 | ||
930 | usb_deregister_dev(usbhid->intf, &hiddev_class); | 923 | usb_deregister_dev(usbhid->intf, &hiddev_class); |
931 | 924 | ||
@@ -935,4 +928,5 @@ void hiddev_disconnect(struct hid_device *hid) | |||
935 | } else { | 928 | } else { |
936 | kfree(hiddev); | 929 | kfree(hiddev); |
937 | } | 930 | } |
931 | mutex_unlock(&hiddev->existancelock); | ||
938 | } | 932 | } |