diff options
Diffstat (limited to 'drivers/usb/core/devio.c')
-rw-r--r-- | drivers/usb/core/devio.c | 93 |
1 files changed, 25 insertions, 68 deletions
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 8df4b76465a..e0f107948eb 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c | |||
@@ -333,17 +333,14 @@ static struct async *async_getcompleted(struct dev_state *ps) | |||
333 | static struct async *async_getpending(struct dev_state *ps, | 333 | static struct async *async_getpending(struct dev_state *ps, |
334 | void __user *userurb) | 334 | void __user *userurb) |
335 | { | 335 | { |
336 | unsigned long flags; | ||
337 | struct async *as; | 336 | struct async *as; |
338 | 337 | ||
339 | spin_lock_irqsave(&ps->lock, flags); | ||
340 | list_for_each_entry(as, &ps->async_pending, asynclist) | 338 | list_for_each_entry(as, &ps->async_pending, asynclist) |
341 | if (as->userurb == userurb) { | 339 | if (as->userurb == userurb) { |
342 | list_del_init(&as->asynclist); | 340 | list_del_init(&as->asynclist); |
343 | spin_unlock_irqrestore(&ps->lock, flags); | ||
344 | return as; | 341 | return as; |
345 | } | 342 | } |
346 | spin_unlock_irqrestore(&ps->lock, flags); | 343 | |
347 | return NULL; | 344 | return NULL; |
348 | } | 345 | } |
349 | 346 | ||
@@ -398,6 +395,7 @@ static void cancel_bulk_urbs(struct dev_state *ps, unsigned bulk_addr) | |||
398 | __releases(ps->lock) | 395 | __releases(ps->lock) |
399 | __acquires(ps->lock) | 396 | __acquires(ps->lock) |
400 | { | 397 | { |
398 | struct urb *urb; | ||
401 | struct async *as; | 399 | struct async *as; |
402 | 400 | ||
403 | /* Mark all the pending URBs that match bulk_addr, up to but not | 401 | /* Mark all the pending URBs that match bulk_addr, up to but not |
@@ -420,8 +418,11 @@ __acquires(ps->lock) | |||
420 | list_for_each_entry(as, &ps->async_pending, asynclist) { | 418 | list_for_each_entry(as, &ps->async_pending, asynclist) { |
421 | if (as->bulk_status == AS_UNLINK) { | 419 | if (as->bulk_status == AS_UNLINK) { |
422 | as->bulk_status = 0; /* Only once */ | 420 | as->bulk_status = 0; /* Only once */ |
421 | urb = as->urb; | ||
422 | usb_get_urb(urb); | ||
423 | spin_unlock(&ps->lock); /* Allow completions */ | 423 | spin_unlock(&ps->lock); /* Allow completions */ |
424 | usb_unlink_urb(as->urb); | 424 | usb_unlink_urb(urb); |
425 | usb_put_urb(urb); | ||
425 | spin_lock(&ps->lock); | 426 | spin_lock(&ps->lock); |
426 | goto rescan; | 427 | goto rescan; |
427 | } | 428 | } |
@@ -472,6 +473,7 @@ static void async_completed(struct urb *urb) | |||
472 | 473 | ||
473 | static void destroy_async(struct dev_state *ps, struct list_head *list) | 474 | static void destroy_async(struct dev_state *ps, struct list_head *list) |
474 | { | 475 | { |
476 | struct urb *urb; | ||
475 | struct async *as; | 477 | struct async *as; |
476 | unsigned long flags; | 478 | unsigned long flags; |
477 | 479 | ||
@@ -479,10 +481,13 @@ static void destroy_async(struct dev_state *ps, struct list_head *list) | |||
479 | while (!list_empty(list)) { | 481 | while (!list_empty(list)) { |
480 | as = list_entry(list->next, struct async, asynclist); | 482 | as = list_entry(list->next, struct async, asynclist); |
481 | list_del_init(&as->asynclist); | 483 | list_del_init(&as->asynclist); |
484 | urb = as->urb; | ||
485 | usb_get_urb(urb); | ||
482 | 486 | ||
483 | /* drop the spinlock so the completion handler can run */ | 487 | /* drop the spinlock so the completion handler can run */ |
484 | spin_unlock_irqrestore(&ps->lock, flags); | 488 | spin_unlock_irqrestore(&ps->lock, flags); |
485 | usb_kill_urb(as->urb); | 489 | usb_kill_urb(urb); |
490 | usb_put_urb(urb); | ||
486 | spin_lock_irqsave(&ps->lock, flags); | 491 | spin_lock_irqsave(&ps->lock, flags); |
487 | } | 492 | } |
488 | spin_unlock_irqrestore(&ps->lock, flags); | 493 | spin_unlock_irqrestore(&ps->lock, flags); |
@@ -727,17 +732,6 @@ static int usbdev_open(struct inode *inode, struct file *file) | |||
727 | if (imajor(inode) == USB_DEVICE_MAJOR) | 732 | if (imajor(inode) == USB_DEVICE_MAJOR) |
728 | dev = usbdev_lookup_by_devt(inode->i_rdev); | 733 | dev = usbdev_lookup_by_devt(inode->i_rdev); |
729 | 734 | ||
730 | #ifdef CONFIG_USB_DEVICEFS | ||
731 | /* procfs file */ | ||
732 | if (!dev) { | ||
733 | dev = inode->i_private; | ||
734 | if (dev && dev->usbfs_dentry && | ||
735 | dev->usbfs_dentry->d_inode == inode) | ||
736 | usb_get_dev(dev); | ||
737 | else | ||
738 | dev = NULL; | ||
739 | } | ||
740 | #endif | ||
741 | mutex_unlock(&usbfs_mutex); | 735 | mutex_unlock(&usbfs_mutex); |
742 | 736 | ||
743 | if (!dev) | 737 | if (!dev) |
@@ -1410,12 +1404,24 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg) | |||
1410 | 1404 | ||
1411 | static int proc_unlinkurb(struct dev_state *ps, void __user *arg) | 1405 | static int proc_unlinkurb(struct dev_state *ps, void __user *arg) |
1412 | { | 1406 | { |
1407 | struct urb *urb; | ||
1413 | struct async *as; | 1408 | struct async *as; |
1409 | unsigned long flags; | ||
1414 | 1410 | ||
1411 | spin_lock_irqsave(&ps->lock, flags); | ||
1415 | as = async_getpending(ps, arg); | 1412 | as = async_getpending(ps, arg); |
1416 | if (!as) | 1413 | if (!as) { |
1414 | spin_unlock_irqrestore(&ps->lock, flags); | ||
1417 | return -EINVAL; | 1415 | return -EINVAL; |
1418 | usb_kill_urb(as->urb); | 1416 | } |
1417 | |||
1418 | urb = as->urb; | ||
1419 | usb_get_urb(urb); | ||
1420 | spin_unlock_irqrestore(&ps->lock, flags); | ||
1421 | |||
1422 | usb_kill_urb(urb); | ||
1423 | usb_put_urb(urb); | ||
1424 | |||
1419 | return 0; | 1425 | return 0; |
1420 | } | 1426 | } |
1421 | 1427 | ||
@@ -2062,44 +2068,13 @@ static void usbdev_remove(struct usb_device *udev) | |||
2062 | } | 2068 | } |
2063 | } | 2069 | } |
2064 | 2070 | ||
2065 | #ifdef CONFIG_USB_DEVICE_CLASS | ||
2066 | static struct class *usb_classdev_class; | ||
2067 | |||
2068 | static int usb_classdev_add(struct usb_device *dev) | ||
2069 | { | ||
2070 | struct device *cldev; | ||
2071 | |||
2072 | cldev = device_create(usb_classdev_class, &dev->dev, dev->dev.devt, | ||
2073 | NULL, "usbdev%d.%d", dev->bus->busnum, | ||
2074 | dev->devnum); | ||
2075 | if (IS_ERR(cldev)) | ||
2076 | return PTR_ERR(cldev); | ||
2077 | dev->usb_classdev = cldev; | ||
2078 | return 0; | ||
2079 | } | ||
2080 | |||
2081 | static void usb_classdev_remove(struct usb_device *dev) | ||
2082 | { | ||
2083 | if (dev->usb_classdev) | ||
2084 | device_unregister(dev->usb_classdev); | ||
2085 | } | ||
2086 | |||
2087 | #else | ||
2088 | #define usb_classdev_add(dev) 0 | ||
2089 | #define usb_classdev_remove(dev) do {} while (0) | ||
2090 | |||
2091 | #endif | ||
2092 | |||
2093 | static int usbdev_notify(struct notifier_block *self, | 2071 | static int usbdev_notify(struct notifier_block *self, |
2094 | unsigned long action, void *dev) | 2072 | unsigned long action, void *dev) |
2095 | { | 2073 | { |
2096 | switch (action) { | 2074 | switch (action) { |
2097 | case USB_DEVICE_ADD: | 2075 | case USB_DEVICE_ADD: |
2098 | if (usb_classdev_add(dev)) | ||
2099 | return NOTIFY_BAD; | ||
2100 | break; | 2076 | break; |
2101 | case USB_DEVICE_REMOVE: | 2077 | case USB_DEVICE_REMOVE: |
2102 | usb_classdev_remove(dev); | ||
2103 | usbdev_remove(dev); | 2078 | usbdev_remove(dev); |
2104 | break; | 2079 | break; |
2105 | } | 2080 | } |
@@ -2129,21 +2104,6 @@ int __init usb_devio_init(void) | |||
2129 | USB_DEVICE_MAJOR); | 2104 | USB_DEVICE_MAJOR); |
2130 | goto error_cdev; | 2105 | goto error_cdev; |
2131 | } | 2106 | } |
2132 | #ifdef CONFIG_USB_DEVICE_CLASS | ||
2133 | usb_classdev_class = class_create(THIS_MODULE, "usb_device"); | ||
2134 | if (IS_ERR(usb_classdev_class)) { | ||
2135 | printk(KERN_ERR "Unable to register usb_device class\n"); | ||
2136 | retval = PTR_ERR(usb_classdev_class); | ||
2137 | cdev_del(&usb_device_cdev); | ||
2138 | usb_classdev_class = NULL; | ||
2139 | goto out; | ||
2140 | } | ||
2141 | /* devices of this class shadow the major:minor of their parent | ||
2142 | * device, so clear ->dev_kobj to prevent adding duplicate entries | ||
2143 | * to /sys/dev | ||
2144 | */ | ||
2145 | usb_classdev_class->dev_kobj = NULL; | ||
2146 | #endif | ||
2147 | usb_register_notify(&usbdev_nb); | 2107 | usb_register_notify(&usbdev_nb); |
2148 | out: | 2108 | out: |
2149 | return retval; | 2109 | return retval; |
@@ -2156,9 +2116,6 @@ error_cdev: | |||
2156 | void usb_devio_cleanup(void) | 2116 | void usb_devio_cleanup(void) |
2157 | { | 2117 | { |
2158 | usb_unregister_notify(&usbdev_nb); | 2118 | usb_unregister_notify(&usbdev_nb); |
2159 | #ifdef CONFIG_USB_DEVICE_CLASS | ||
2160 | class_destroy(usb_classdev_class); | ||
2161 | #endif | ||
2162 | cdev_del(&usb_device_cdev); | 2119 | cdev_del(&usb_device_cdev); |
2163 | unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX); | 2120 | unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX); |
2164 | } | 2121 | } |