aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/gadget
diff options
context:
space:
mode:
authorFelipe Balbi <balbi@ti.com>2013-07-17 04:09:49 -0400
committerFelipe Balbi <balbi@ti.com>2013-07-29 06:57:02 -0400
commit5702f75375aa9ecf8ad3431aef3fe6ce8c8dbd15 (patch)
tree92a45aca9238a714ca0472436e3563e6033de1f6 /drivers/usb/gadget
parentc75f52fb26aa9c10b3f5ee157bc0c6c8e8e9bb1a (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.c12
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
109static 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
108void usb_gadget_set_state(struct usb_gadget *gadget, 116void 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}
114EXPORT_SYMBOL_GPL(usb_gadget_set_state); 122EXPORT_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}