usb: gadget: udc-core: Rescan pending list on driver unbind
Since: commit855ed04a37
("usb: gadget: udc-core: independent registration of gadgets and gadget drivers") if we load gadget module but there is no free udc available then it will be stored on a pending gadgets list. $ modprobe g_zero.ko $ modprobe g_ether.ko [] udc-core: couldn't find an available UDC - added [g_ether] to list of pending drivers We scan this list each time when new UDC appears in system. But we can get a free UDC each time after gadget unbind. This commit add scanning of that list directly after unbinding gadget from udc. Thanks to this, when we unload first gadget: $ rmmod g_zero.ko gadget which is pending is automatically attached to that UDC (if name matches). Fixes:855ed04a37
("usb: gadget: udc-core: independent registration of gadgets and gadget drivers") Cc: stable <stable@vger.kernel.org> Signed-off-by: Krzysztof Opasiak <k.opasiak@samsung.com> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
This commit is contained in:
Родитель
49def18533
Коммит
8236800da1
|
@ -1080,6 +1080,24 @@ static void usb_udc_nop_release(struct device *dev)
|
|||
dev_vdbg(dev, "%s\n", __func__);
|
||||
}
|
||||
|
||||
/* should be called with udc_lock held */
|
||||
static int check_pending_gadget_drivers(struct usb_udc *udc)
|
||||
{
|
||||
struct usb_gadget_driver *driver;
|
||||
int ret = 0;
|
||||
|
||||
list_for_each_entry(driver, &gadget_driver_pending_list, pending)
|
||||
if (!driver->udc_name || strcmp(driver->udc_name,
|
||||
dev_name(&udc->dev)) == 0) {
|
||||
ret = udc_bind_to_driver(udc, driver);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
list_del(&driver->pending);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_add_gadget_udc_release - adds a new gadget to the udc class driver list
|
||||
* @parent: the parent device to this udc. Usually the controller driver's
|
||||
|
@ -1093,7 +1111,6 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
|
|||
void (*release)(struct device *dev))
|
||||
{
|
||||
struct usb_udc *udc;
|
||||
struct usb_gadget_driver *driver;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
udc = kzalloc(sizeof(*udc), GFP_KERNEL);
|
||||
|
@ -1136,17 +1153,9 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
|
|||
udc->vbus = true;
|
||||
|
||||
/* pick up one of pending gadget drivers */
|
||||
list_for_each_entry(driver, &gadget_driver_pending_list, pending) {
|
||||
if (!driver->udc_name || strcmp(driver->udc_name,
|
||||
dev_name(&udc->dev)) == 0) {
|
||||
ret = udc_bind_to_driver(udc, driver);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
list_del(&driver->pending);
|
||||
if (ret)
|
||||
goto err5;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ret = check_pending_gadget_drivers(udc);
|
||||
if (ret)
|
||||
goto err5;
|
||||
|
||||
mutex_unlock(&udc_lock);
|
||||
|
||||
|
@ -1356,14 +1365,22 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
|||
return -EINVAL;
|
||||
|
||||
mutex_lock(&udc_lock);
|
||||
list_for_each_entry(udc, &udc_list, list)
|
||||
list_for_each_entry(udc, &udc_list, list) {
|
||||
if (udc->driver == driver) {
|
||||
usb_gadget_remove_driver(udc);
|
||||
usb_gadget_set_state(udc->gadget,
|
||||
USB_STATE_NOTATTACHED);
|
||||
USB_STATE_NOTATTACHED);
|
||||
|
||||
/* Maybe there is someone waiting for this UDC? */
|
||||
check_pending_gadget_drivers(udc);
|
||||
/*
|
||||
* For now we ignore bind errors as probably it's
|
||||
* not a valid reason to fail other's gadget unbind
|
||||
*/
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
list_del(&driver->pending);
|
||||
|
|
Загрузка…
Ссылка в новой задаче