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

Commit ebe1703a authored by Felipe Balbi's avatar Felipe Balbi Committed by Stephen Boyd
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>
Git-commit: 5702f75375aa9ecf8ad3431aef3fe6ce8c8dbd15
Git-repo: https://git.kernel.org/cgit/linux/kernel/git/next/linux-next.git


Signed-off-by: default avatarStephen Boyd <sboyd@codeaurora.org>
parent 5aa70c22
Loading
Loading
Loading
Loading
+11 −1
Original line number Original line Diff line number Diff line
@@ -23,6 +23,7 @@
#include <linux/list.h>
#include <linux/list.h>
#include <linux/err.h>
#include <linux/err.h>
#include <linux/dma-mapping.h>
#include <linux/dma-mapping.h>
#include <linux/workqueue.h>


#include <linux/usb/ch9.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/usb/gadget.h>
@@ -101,11 +102,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,
void usb_gadget_set_state(struct usb_gadget *gadget,
		enum usb_device_state state)
		enum usb_device_state state)
{
{
	gadget->state = state;
	gadget->state = state;
	sysfs_notify(&gadget->dev.kobj, NULL, "status");
	schedule_work(&gadget->work);
}
}
EXPORT_SYMBOL_GPL(usb_gadget_set_state);
EXPORT_SYMBOL_GPL(usb_gadget_set_state);


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


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


	dma_set_coherent_mask(&gadget->dev, parent->coherent_dma_mask);
	dma_set_coherent_mask(&gadget->dev, parent->coherent_dma_mask);
@@ -309,6 +318,7 @@ found:
		usb_gadget_remove_driver(udc);
		usb_gadget_remove_driver(udc);


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


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


/**
/**
 * struct usb_gadget - represents a usb slave device
 * 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.
 * @ops: Function pointers used to access hardware-specific operations.
 * @ep0: Endpoint zero, used when reading or writing responses to
 * @ep0: Endpoint zero, used when reading or writing responses to
 *	driver setup() requests
 *	driver setup() requests
@@ -520,6 +522,7 @@ struct usb_gadget_ops {
 * device is acting as a B-Peripheral (so is_a_peripheral is false).
 * device is acting as a B-Peripheral (so is_a_peripheral is false).
 */
 */
struct usb_gadget {
struct usb_gadget {
	struct work_struct		work;
	/* readonly to gadget driver */
	/* readonly to gadget driver */
	const struct usb_gadget_ops	*ops;
	const struct usb_gadget_ops	*ops;
	struct usb_ep			*ep0;
	struct usb_ep			*ep0;
@@ -538,6 +541,7 @@ struct usb_gadget {
	unsigned			out_epnum;
	unsigned			out_epnum;
	unsigned			in_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)
static inline void set_gadget_data(struct usb_gadget *gadget, void *data)
	{ dev_set_drvdata(&gadget->dev, data); }
	{ dev_set_drvdata(&gadget->dev, data); }