mirror of
https://github.com/torvalds/linux.git
synced 2026-06-07 14:04:54 +02:00
FROMGIT: usb: udc: core: Introduce started state
For some UDCs, the initialization sequence by udc_start() should not be
repeated until it is properly cleaned up with udc_stop() and vise versa.
We may run into some cleanup failure as seen with the DWC3 driver during
the irq cleanup. This issue can occur when the user triggers
soft-connect/soft-disconnect from the soft_connect sysfs. To avoid
adding checks to every UDC driver, at the UDC framework, introduce a
"started" state to track and prevent the UDC from repeating the
udc_start() and udc_stop() if it had already started/stopped.
Acked-by: Felipe Balbi <balbi@kernel.org>
Signed-off-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
Link: https://lore.kernel.org/r/a7c4112fcd4dc2f0169af94a24f5685ca77f09fd.1610395599.git.Thinh.Nguyen@synopsys.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
(cherry picked from commit 49d08cfc78
https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git usb-next)
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Change-Id: Ifc92710e1d1b2ed6e3dfe0768efcb30a14a9a2ff
This commit is contained in:
parent
af76098432
commit
b013254308
|
|
@ -29,6 +29,7 @@
|
|||
* @list: for use by the udc class driver
|
||||
* @vbus: for udcs who care about vbus status, this value is real vbus status;
|
||||
* for udcs who do not care about vbus status, this value is always true
|
||||
* @started: the UDC's started state. True if the UDC had started.
|
||||
*
|
||||
* This represents the internal data structure which is used by the UDC-class
|
||||
* to hold information about udc driver and gadget together.
|
||||
|
|
@ -39,6 +40,7 @@ struct usb_udc {
|
|||
struct device dev;
|
||||
struct list_head list;
|
||||
bool vbus;
|
||||
bool started;
|
||||
};
|
||||
|
||||
static struct class *udc_class;
|
||||
|
|
@ -1085,7 +1087,18 @@ EXPORT_SYMBOL_GPL(usb_gadget_udc_reset);
|
|||
*/
|
||||
static inline int usb_gadget_udc_start(struct usb_udc *udc)
|
||||
{
|
||||
return udc->gadget->ops->udc_start(udc->gadget, udc->driver);
|
||||
int ret;
|
||||
|
||||
if (udc->started) {
|
||||
dev_err(&udc->dev, "UDC had already started\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
ret = udc->gadget->ops->udc_start(udc->gadget, udc->driver);
|
||||
if (!ret)
|
||||
udc->started = true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1101,7 +1114,13 @@ static inline int usb_gadget_udc_start(struct usb_udc *udc)
|
|||
*/
|
||||
static inline void usb_gadget_udc_stop(struct usb_udc *udc)
|
||||
{
|
||||
if (!udc->started) {
|
||||
dev_err(&udc->dev, "UDC had already stopped\n");
|
||||
return;
|
||||
}
|
||||
|
||||
udc->gadget->ops->udc_stop(udc->gadget);
|
||||
udc->started = false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1225,6 +1244,8 @@ int usb_add_gadget(struct usb_gadget *gadget)
|
|||
udc->gadget = gadget;
|
||||
gadget->udc = udc;
|
||||
|
||||
udc->started = false;
|
||||
|
||||
mutex_lock(&udc_lock);
|
||||
list_add_tail(&udc->list, &udc_list);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user