|
@@ -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);
|