summaryrefslogtreecommitdiff
path: root/common/usb.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/usb.c')
-rw-r--r--common/usb.c46
1 files changed, 30 insertions, 16 deletions
diff --git a/common/usb.c b/common/usb.c
index 99e6b857c74..7a8435296c6 100644
--- a/common/usb.c
+++ b/common/usb.c
@@ -25,7 +25,6 @@
*
* For each transfer (except "Interrupt") we wait for completion.
*/
-#include <common.h>
#include <command.h>
#include <dm.h>
#include <dm/device_compat.h>
@@ -191,7 +190,6 @@ int usb_disable_asynch(int disable)
}
#endif /* !CONFIG_IS_ENABLED(DM_USB) */
-
/*-------------------------------------------------------------------
* Message wrappers.
*
@@ -215,8 +213,9 @@ int usb_int_msg(struct usb_device *dev, unsigned long pipe,
* clear keyboards LEDs). For data transfers, (storage transfers) we don't
* allow control messages with 0 timeout, by previousely resetting the flag
* asynch_allowed (usb_disable_asynch(1)).
- * returns the transferred length if OK or -1 if error. The transferred length
- * and the current status are stored in the dev->act_len and dev->status.
+ * returns the transferred length if OK, otherwise a negative error code. The
+ * transferred length and the current status are stored in the dev->act_len and
+ * dev->status.
*/
int usb_control_msg(struct usb_device *dev, unsigned int pipe,
unsigned char request, unsigned char requesttype,
@@ -258,11 +257,14 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe,
break;
mdelay(1);
}
+
+ if (timeout == 0)
+ return -ETIMEDOUT;
+
if (dev->status)
return -1;
return dev->act_len;
-
}
/*-------------------------------------------------------------------
@@ -290,7 +292,6 @@ int usb_bulk_msg(struct usb_device *dev, unsigned int pipe,
return -EIO;
}
-
/*-------------------------------------------------------------------
* Max Packet stuff
*/
@@ -556,17 +557,35 @@ int usb_clear_halt(struct usb_device *dev, int pipe)
return 0;
}
-
/**********************************************************************
* get_descriptor type
*/
static int usb_get_descriptor(struct usb_device *dev, unsigned char type,
unsigned char index, void *buf, int size)
{
- return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
- USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
- (type << 8) + index, 0, buf, size,
- USB_CNTL_TIMEOUT);
+ int i;
+ int result;
+
+ if (size <= 0) /* No point in asking for no data */
+ return -EINVAL;
+
+ memset(buf, 0, size); /* Make sure we parse really received data */
+
+ for (i = 0; i < 3; ++i) {
+ /* retry on length 0 or error; some devices are flakey */
+ result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
+ (type << 8) + index, 0, buf, size,
+ USB_CNTL_TIMEOUT);
+ if (result <= 0 && result != -ETIMEDOUT)
+ continue;
+ if (result > 1 && ((u8 *)buf)[1] != type) {
+ result = -ENODATA;
+ continue;
+ }
+ break;
+ }
+ return result;
}
/**********************************************************************
@@ -746,7 +765,6 @@ static int usb_get_string(struct usb_device *dev, unsigned short langid,
return result;
}
-
static void usb_try_string_workarounds(unsigned char *buf, int *length)
{
int newlength, oldlength = *length;
@@ -761,7 +779,6 @@ static void usb_try_string_workarounds(unsigned char *buf, int *length)
}
}
-
static int usb_string_sub(struct usb_device *dev, unsigned int langid,
unsigned int index, unsigned char *buf)
{
@@ -796,7 +813,6 @@ static int usb_string_sub(struct usb_device *dev, unsigned int langid,
return rc;
}
-
/********************************************************************
* usb_string:
* Get string index and translate it to ascii.
@@ -852,7 +868,6 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
return err;
}
-
/********************************************************************
* USB device handling:
* the USB device are static allocated [USB_MAX_DEVICE].
@@ -1366,5 +1381,4 @@ void usb_find_usb2_hub_address_port(struct usb_device *udev,
}
#endif
-
/* EOF */