summaryrefslogtreecommitdiffstats
path: root/drivers/usb/core
diff options
context:
space:
mode:
authorAndrey Smirnov <andrew.smirnov@gmail.com>2018-08-28 23:33:33 -0700
committerSascha Hauer <s.hauer@pengutronix.de>2018-08-29 09:36:26 +0200
commit0a6a3b4601a89c12bf22bef382083cbbbe8582b5 (patch)
tree33388281a8adb39f86e75e9deca72d5f6bb1e1e9 /drivers/usb/core
parentc1b48bc21dbcfbb7d4539bef5ddc223051bc73fe (diff)
downloadbarebox-0a6a3b4601a89c12bf22bef382083cbbbe8582b5.tar.gz
barebox-0a6a3b4601a89c12bf22bef382083cbbbe8582b5.tar.xz
USB: host: hub: Adjust device speed after every port reset
To account for the possibility of a device coming out of second reset operating at different speed compared to first, move the code that stores device speed to be a part of hub_port_reset(). This way any speed change happening as a result of port reset could be accounted for. The above behaviour was observed on i.MX51 ZII RDU1, on USBH2 port connected to SMSC2660 USB Hub/SD card reader. For reasons unclear, first reset would put it into Full Speed mode whereas second would result in switch to High Speed. Artifically disabling second reset would result in the device operating at Full Speed. Not doing second speed adjustement on that board result would result in un-processed control transfer and failure to execute usb_set_address(). Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'drivers/usb/core')
-rw-r--r--drivers/usb/core/hub.c34
-rw-r--r--drivers/usb/core/hub.h2
-rw-r--r--drivers/usb/core/usb.c3
3 files changed, 19 insertions, 20 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 6c73bcf129..39e5fe67d4 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -112,8 +112,7 @@ static inline char *portspeed(int portstatus)
return "12 Mb/s";
}
-int hub_port_reset(struct usb_device *hub, int port,
- unsigned short *portstat)
+int hub_port_reset(struct usb_device *hub, int port, struct usb_device *usb)
{
int tries;
struct usb_port_status portsts;
@@ -161,7 +160,14 @@ int hub_port_reset(struct usb_device *hub, int port,
}
usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_RESET);
- *portstat = portstatus;
+
+ if (portstatus & USB_PORT_STAT_HIGH_SPEED)
+ usb->speed = USB_SPEED_HIGH;
+ else if (portstatus & USB_PORT_STAT_LOW_SPEED)
+ usb->speed = USB_SPEED_LOW;
+ else
+ usb->speed = USB_SPEED_FULL;
+
return 0;
}
@@ -203,26 +209,20 @@ static void usb_hub_port_connect_change(struct usb_device *dev, int port)
mdelay(200);
- /* Reset the port */
- if (hub_port_reset(dev, port, &portstatus) < 0) {
+ /* Allocate a new device struct for the port */
+ usb = usb_alloc_new_device();
+ usb->dev.parent = &dev->dev;
+ usb->host = dev->host;
+
+ /* Reset it */
+ if (hub_port_reset(dev, port, usb) < 0) {
dev_warn(&dev->dev, "cannot reset port %i!?\n", port + 1);
+ usb_free_device(usb);
return;
}
mdelay(200);
- /* Allocate a new device struct for it */
- usb = usb_alloc_new_device();
- usb->dev.parent = &dev->dev;
- usb->host = dev->host;
-
- if (portstatus & USB_PORT_STAT_HIGH_SPEED)
- usb->speed = USB_SPEED_HIGH;
- else if (portstatus & USB_PORT_STAT_LOW_SPEED)
- usb->speed = USB_SPEED_LOW;
- else
- usb->speed = USB_SPEED_FULL;
-
dev->children[port] = usb;
usb->parent = dev;
usb->portnr = port + 1;
diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h
index 41c7ff499b..74921b66fd 100644
--- a/drivers/usb/core/hub.h
+++ b/drivers/usb/core/hub.h
@@ -2,6 +2,6 @@
#define __CORE_HUB_H
int hub_port_reset(struct usb_device *hub, int port,
- unsigned short *portstat);
+ struct usb_device *usb);
#endif /* __CORE_HUB_H */
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 9170ba4d53..70ded6ded1 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -312,7 +312,6 @@ int usb_new_device(struct usb_device *dev)
void *buf;
struct usb_device_descriptor *desc;
struct usb_device *parent = dev->parent;
- unsigned short portstatus;
char str[16];
buf = dma_alloc(USB_BUFSIZ);
@@ -352,7 +351,7 @@ int usb_new_device(struct usb_device *dev)
/* find the port number we're at */
if (parent) {
/* reset the port for the second time */
- err = hub_port_reset(dev->parent, dev->portnr - 1, &portstatus);
+ err = hub_port_reset(dev->parent, dev->portnr - 1, dev);
if (err < 0) {
printf("\n Couldn't reset port %i\n", dev->portnr);
goto err_out;