diff options
author | Krzysztof Opasiak <k.opasiak@samsung.com> | 2017-01-16 02:40:57 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-03-12 00:41:49 -0500 |
commit | 881b5225558e2bad2f02aca4058b269dce0a834d (patch) | |
tree | d7258caa57263f6bd6c91b78ae5ff519909af2df | |
parent | 82bd560d9552a7b30ad1123591de63684fe0a63e (diff) |
usb: gadget: udc-core: Rescan pending list on driver unbind
commit 8236800da115a3e24b9165c573067343f51cf5ea upstream.
Since:
commit 855ed04a3758 ("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: 855ed04a3758 ("usb: gadget: udc-core: independent registration of gadgets and gadget drivers")
Signed-off-by: Krzysztof Opasiak <k.opasiak@samsung.com>
Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/usb/gadget/udc/core.c | 45 |
1 files changed, 31 insertions, 14 deletions
diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index 0402177f93cd..d685d82dcf48 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c | |||
@@ -1080,6 +1080,24 @@ static void usb_udc_nop_release(struct device *dev) | |||
1080 | dev_vdbg(dev, "%s\n", __func__); | 1080 | dev_vdbg(dev, "%s\n", __func__); |
1081 | } | 1081 | } |
1082 | 1082 | ||
1083 | /* should be called with udc_lock held */ | ||
1084 | static int check_pending_gadget_drivers(struct usb_udc *udc) | ||
1085 | { | ||
1086 | struct usb_gadget_driver *driver; | ||
1087 | int ret = 0; | ||
1088 | |||
1089 | list_for_each_entry(driver, &gadget_driver_pending_list, pending) | ||
1090 | if (!driver->udc_name || strcmp(driver->udc_name, | ||
1091 | dev_name(&udc->dev)) == 0) { | ||
1092 | ret = udc_bind_to_driver(udc, driver); | ||
1093 | if (ret != -EPROBE_DEFER) | ||
1094 | list_del(&driver->pending); | ||
1095 | break; | ||
1096 | } | ||
1097 | |||
1098 | return ret; | ||
1099 | } | ||
1100 | |||
1083 | /** | 1101 | /** |
1084 | * usb_add_gadget_udc_release - adds a new gadget to the udc class driver list | 1102 | * usb_add_gadget_udc_release - adds a new gadget to the udc class driver list |
1085 | * @parent: the parent device to this udc. Usually the controller driver's | 1103 | * @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, | |||
1093 | void (*release)(struct device *dev)) | 1111 | void (*release)(struct device *dev)) |
1094 | { | 1112 | { |
1095 | struct usb_udc *udc; | 1113 | struct usb_udc *udc; |
1096 | struct usb_gadget_driver *driver; | ||
1097 | int ret = -ENOMEM; | 1114 | int ret = -ENOMEM; |
1098 | 1115 | ||
1099 | udc = kzalloc(sizeof(*udc), GFP_KERNEL); | 1116 | udc = kzalloc(sizeof(*udc), GFP_KERNEL); |
@@ -1136,17 +1153,9 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, | |||
1136 | udc->vbus = true; | 1153 | udc->vbus = true; |
1137 | 1154 | ||
1138 | /* pick up one of pending gadget drivers */ | 1155 | /* pick up one of pending gadget drivers */ |
1139 | list_for_each_entry(driver, &gadget_driver_pending_list, pending) { | 1156 | ret = check_pending_gadget_drivers(udc); |
1140 | if (!driver->udc_name || strcmp(driver->udc_name, | 1157 | if (ret) |
1141 | dev_name(&udc->dev)) == 0) { | 1158 | goto err5; |
1142 | ret = udc_bind_to_driver(udc, driver); | ||
1143 | if (ret != -EPROBE_DEFER) | ||
1144 | list_del(&driver->pending); | ||
1145 | if (ret) | ||
1146 | goto err5; | ||
1147 | break; | ||
1148 | } | ||
1149 | } | ||
1150 | 1159 | ||
1151 | mutex_unlock(&udc_lock); | 1160 | mutex_unlock(&udc_lock); |
1152 | 1161 | ||
@@ -1356,14 +1365,22 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) | |||
1356 | return -EINVAL; | 1365 | return -EINVAL; |
1357 | 1366 | ||
1358 | mutex_lock(&udc_lock); | 1367 | mutex_lock(&udc_lock); |
1359 | list_for_each_entry(udc, &udc_list, list) | 1368 | list_for_each_entry(udc, &udc_list, list) { |
1360 | if (udc->driver == driver) { | 1369 | if (udc->driver == driver) { |
1361 | usb_gadget_remove_driver(udc); | 1370 | usb_gadget_remove_driver(udc); |
1362 | usb_gadget_set_state(udc->gadget, | 1371 | usb_gadget_set_state(udc->gadget, |
1363 | USB_STATE_NOTATTACHED); | 1372 | USB_STATE_NOTATTACHED); |
1373 | |||
1374 | /* Maybe there is someone waiting for this UDC? */ | ||
1375 | check_pending_gadget_drivers(udc); | ||
1376 | /* | ||
1377 | * For now we ignore bind errors as probably it's | ||
1378 | * not a valid reason to fail other's gadget unbind | ||
1379 | */ | ||
1364 | ret = 0; | 1380 | ret = 0; |
1365 | break; | 1381 | break; |
1366 | } | 1382 | } |
1383 | } | ||
1367 | 1384 | ||
1368 | if (ret) { | 1385 | if (ret) { |
1369 | list_del(&driver->pending); | 1386 | list_del(&driver->pending); |