aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/host/usb-uclass.c42
1 files changed, 34 insertions, 8 deletions
diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c
index 749257cf6d8..963464cff94 100644
--- a/drivers/usb/host/usb-uclass.c
+++ b/drivers/usb/host/usb-uclass.c
@@ -21,6 +21,10 @@ DECLARE_GLOBAL_DATA_PTR;
extern bool usb_started; /* flag for the started/stopped USB status */
static bool asynch_allowed;
+struct usb_uclass_priv {
+ int companion_device_count;
+};
+
int usb_disable_asynch(int disable)
{
int old_value = asynch_allowed;
@@ -46,11 +50,22 @@ int submit_control_msg(struct usb_device *udev, unsigned long pipe,
{
struct udevice *bus = udev->controller_dev;
struct dm_usb_ops *ops = usb_get_ops(bus);
+ struct usb_uclass_priv *uc_priv = bus->uclass->priv;
+ int err;
if (!ops->control)
return -ENOSYS;
- return ops->control(bus, udev, pipe, buffer, length, setup);
+ err = ops->control(bus, udev, pipe, buffer, length, setup);
+ if (setup->request == USB_REQ_SET_FEATURE &&
+ setup->requesttype == USB_RT_PORT &&
+ setup->value == cpu_to_le16(USB_PORT_FEAT_RESET) &&
+ err == -ENXIO) {
+ /* Device handed over to companion after port reset */
+ uc_priv->companion_device_count++;
+ }
+
+ return err;
}
int submit_bulk_msg(struct usb_device *udev, unsigned long pipe, void *buffer,
@@ -117,12 +132,16 @@ int usb_stop(void)
{
struct udevice *bus;
struct uclass *uc;
+ struct usb_uclass_priv *uc_priv;
int err = 0, ret;
/* De-activate any devices that have been activated */
ret = uclass_get(UCLASS_USB, &uc);
if (ret)
return ret;
+
+ uc_priv = uc->priv;
+
uclass_foreach_dev(bus, uc) {
ret = device_remove(bus);
if (ret && !err)
@@ -142,6 +161,7 @@ int usb_stop(void)
#endif
usb_stor_reset();
usb_hub_reset();
+ uc_priv->companion_device_count = 0;
usb_started = 0;
return err;
@@ -171,6 +191,7 @@ static void usb_scan_bus(struct udevice *bus, bool recurse)
int usb_init(void)
{
int controllers_initialized = 0;
+ struct usb_uclass_priv *uc_priv;
struct usb_bus_priv *priv;
struct udevice *bus;
struct uclass *uc;
@@ -184,6 +205,8 @@ int usb_init(void)
if (ret)
return ret;
+ uc_priv = uc->priv;
+
uclass_foreach_dev(bus, uc) {
/* init low_level USB */
printf("USB%d: ", count);
@@ -219,15 +242,17 @@ int usb_init(void)
/*
* Now that the primary controllers have been scanned and have handed
* over any devices they do not understand to their companions, scan
- * the companions.
+ * the companions if necessary.
*/
- uclass_foreach_dev(bus, uc) {
- if (!device_active(bus))
- continue;
+ if (uc_priv->companion_device_count) {
+ uclass_foreach_dev(bus, uc) {
+ if (!device_active(bus))
+ continue;
- priv = dev_get_uclass_priv(bus);
- if (priv->companion)
- usb_scan_bus(bus, true);
+ priv = dev_get_uclass_priv(bus);
+ if (priv->companion)
+ usb_scan_bus(bus, true);
+ }
}
debug("scan end\n");
@@ -685,6 +710,7 @@ UCLASS_DRIVER(usb) = {
.name = "usb",
.flags = DM_UC_FLAG_SEQ_ALIAS,
.post_bind = usb_post_bind,
+ .priv_auto_alloc_size = sizeof(struct usb_uclass_priv),
.per_child_auto_alloc_size = sizeof(struct usb_device),
.per_device_auto_alloc_size = sizeof(struct usb_bus_priv),
.child_post_bind = usb_child_post_bind,