Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5702f753 authored by Felipe Balbi's avatar Felipe Balbi
Browse files

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: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarFelipe Balbi <balbi@ti.com>
parent c75f52fb
Loading
Loading
Loading
Loading
+11 −1
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include <linux/list.h>
#include <linux/err.h>
#include <linux/dma-mapping.h>
#include <linux/workqueue.h>

#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
@@ -105,11 +106,18 @@ EXPORT_SYMBOL_GPL(usb_gadget_unmap_request);

/* ------------------------------------------------------------------------- */

static void usb_gadget_state_work(struct work_struct *work)
{
	struct usb_gadget	*gadget = work_to_gadget(work);

	sysfs_notify(&gadget->dev.kobj, NULL, "status");
}

void usb_gadget_set_state(struct usb_gadget *gadget,
		enum usb_device_state state)
{
	gadget->state = state;
	sysfs_notify(&gadget->dev.kobj, NULL, "status");
	schedule_work(&gadget->work);
}
EXPORT_SYMBOL_GPL(usb_gadget_set_state);

@@ -196,6 +204,7 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
		goto err1;

	dev_set_name(&gadget->dev, "gadget");
	INIT_WORK(&gadget->work, usb_gadget_state_work);
	gadget->dev.parent = parent;

#ifdef	CONFIG_HAS_DMA
@@ -315,6 +324,7 @@ void usb_del_gadget_udc(struct usb_gadget *gadget)
		usb_gadget_remove_driver(udc);

	kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE);
	flush_work(&gadget->work);
	device_unregister(&udc->dev);
	device_unregister(&gadget->dev);
}
+4 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
#include <linux/slab.h>
#include <linux/scatterlist.h>
#include <linux/types.h>
#include <linux/workqueue.h>
#include <linux/usb/ch9.h>

struct usb_ep;
@@ -475,6 +476,7 @@ struct usb_gadget_ops {

/**
 * struct usb_gadget - represents a usb slave device
 * @work: (internal use) Workqueue to be used for sysfs_notify()
 * @ops: Function pointers used to access hardware-specific operations.
 * @ep0: Endpoint zero, used when reading or writing responses to
 *	driver setup() requests
@@ -520,6 +522,7 @@ struct usb_gadget_ops {
 * device is acting as a B-Peripheral (so is_a_peripheral is false).
 */
struct usb_gadget {
	struct work_struct		work;
	/* readonly to gadget driver */
	const struct usb_gadget_ops	*ops;
	struct usb_ep			*ep0;
@@ -538,6 +541,7 @@ struct usb_gadget {
	unsigned			out_epnum;
	unsigned			in_epnum;
};
#define work_to_gadget(w)	(container_of((w), struct usb_gadget, work))

static inline void set_gadget_data(struct usb_gadget *gadget, void *data)
	{ dev_set_drvdata(&gadget->dev, data); }