diff options
author | Felipe Balbi <balbi@ti.com> | 2013-07-17 04:09:49 -0400 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2013-07-29 06:57:02 -0400 |
commit | 5702f75375aa9ecf8ad3431aef3fe6ce8c8dbd15 (patch) | |
tree | 92a45aca9238a714ca0472436e3563e6033de1f6 /drivers/usb/gadget | |
parent | c75f52fb26aa9c10b3f5ee157bc0c6c8e8e9bb1a (diff) |
usb: gadget: udc-core: move sysfs_notify() to a workqueue
usb_gadget_set_state() will call sysfs_notify()
which might sleep. Some users might want to call
usb_gadget_set_state() from the very IRQ handler
which actually changes the gadget state.
Instead of having every UDC driver add their own
workqueue for such a simple notification, we're
adding it generically to our struct usb_gadget,
so the details are hidden from all UDC drivers.
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r-- | drivers/usb/gadget/udc-core.c | 12 |
1 files changed, 11 insertions, 1 deletions
diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c index c28ac9872030..3122ab942f75 100644 --- a/drivers/usb/gadget/udc-core.c +++ b/drivers/usb/gadget/udc-core.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/list.h> | 23 | #include <linux/list.h> |
24 | #include <linux/err.h> | 24 | #include <linux/err.h> |
25 | #include <linux/dma-mapping.h> | 25 | #include <linux/dma-mapping.h> |
26 | #include <linux/workqueue.h> | ||
26 | 27 | ||
27 | #include <linux/usb/ch9.h> | 28 | #include <linux/usb/ch9.h> |
28 | #include <linux/usb/gadget.h> | 29 | #include <linux/usb/gadget.h> |
@@ -105,11 +106,18 @@ EXPORT_SYMBOL_GPL(usb_gadget_unmap_request); | |||
105 | 106 | ||
106 | /* ------------------------------------------------------------------------- */ | 107 | /* ------------------------------------------------------------------------- */ |
107 | 108 | ||
109 | static void usb_gadget_state_work(struct work_struct *work) | ||
110 | { | ||
111 | struct usb_gadget *gadget = work_to_gadget(work); | ||
112 | |||
113 | sysfs_notify(&gadget->dev.kobj, NULL, "status"); | ||
114 | } | ||
115 | |||
108 | void usb_gadget_set_state(struct usb_gadget *gadget, | 116 | void usb_gadget_set_state(struct usb_gadget *gadget, |
109 | enum usb_device_state state) | 117 | enum usb_device_state state) |
110 | { | 118 | { |
111 | gadget->state = state; | 119 | gadget->state = state; |
112 | sysfs_notify(&gadget->dev.kobj, NULL, "status"); | 120 | schedule_work(&gadget->work); |
113 | } | 121 | } |
114 | EXPORT_SYMBOL_GPL(usb_gadget_set_state); | 122 | EXPORT_SYMBOL_GPL(usb_gadget_set_state); |
115 | 123 | ||
@@ -196,6 +204,7 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, | |||
196 | goto err1; | 204 | goto err1; |
197 | 205 | ||
198 | dev_set_name(&gadget->dev, "gadget"); | 206 | dev_set_name(&gadget->dev, "gadget"); |
207 | INIT_WORK(&gadget->work, usb_gadget_state_work); | ||
199 | gadget->dev.parent = parent; | 208 | gadget->dev.parent = parent; |
200 | 209 | ||
201 | #ifdef CONFIG_HAS_DMA | 210 | #ifdef CONFIG_HAS_DMA |
@@ -315,6 +324,7 @@ found: | |||
315 | usb_gadget_remove_driver(udc); | 324 | usb_gadget_remove_driver(udc); |
316 | 325 | ||
317 | kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE); | 326 | kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE); |
327 | flush_work(&gadget->work); | ||
318 | device_unregister(&udc->dev); | 328 | device_unregister(&udc->dev); |
319 | device_unregister(&gadget->dev); | 329 | device_unregister(&gadget->dev); |
320 | } | 330 | } |