|
@@ -37,6 +37,7 @@
|
|
#include <common.h>
|
|
#include <common.h>
|
|
#include <command.h>
|
|
#include <command.h>
|
|
#include <asm/processor.h>
|
|
#include <asm/processor.h>
|
|
|
|
+#include <linux/ctype.h>
|
|
|
|
|
|
#if (CONFIG_COMMANDS & CFG_CMD_USB)
|
|
#if (CONFIG_COMMANDS & CFG_CMD_USB)
|
|
|
|
|
|
@@ -46,7 +47,7 @@
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
|
|
-/* #define USB_DEBUG */
|
|
|
|
|
|
+#undef USB_DEBUG
|
|
|
|
|
|
#ifdef USB_DEBUG
|
|
#ifdef USB_DEBUG
|
|
#define USB_PRINTF(fmt,args...) printf (fmt ,##args)
|
|
#define USB_PRINTF(fmt,args...) printf (fmt ,##args)
|
|
@@ -70,6 +71,7 @@ void usb_scan_devices(void);
|
|
int usb_hub_probe(struct usb_device *dev, int ifnum);
|
|
int usb_hub_probe(struct usb_device *dev, int ifnum);
|
|
void usb_hub_reset(void);
|
|
void usb_hub_reset(void);
|
|
|
|
|
|
|
|
+
|
|
/***********************************************************************
|
|
/***********************************************************************
|
|
* wait_ms
|
|
* wait_ms
|
|
*/
|
|
*/
|
|
@@ -157,6 +159,7 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe,
|
|
{
|
|
{
|
|
if((timeout==0)&&(!asynch_allowed)) /* request for a asynch control pipe is not allowed */
|
|
if((timeout==0)&&(!asynch_allowed)) /* request for a asynch control pipe is not allowed */
|
|
return -1;
|
|
return -1;
|
|
|
|
+
|
|
/* set setup command */
|
|
/* set setup command */
|
|
setup_packet.requesttype = requesttype;
|
|
setup_packet.requesttype = requesttype;
|
|
setup_packet.request = request;
|
|
setup_packet.request = request;
|
|
@@ -330,8 +333,7 @@ int usb_parse_config(struct usb_device *dev, unsigned char *buffer, int cfgno)
|
|
int usb_clear_halt(struct usb_device *dev, int pipe)
|
|
int usb_clear_halt(struct usb_device *dev, int pipe)
|
|
{
|
|
{
|
|
int result;
|
|
int result;
|
|
- unsigned short status;
|
|
|
|
- int endp=usb_pipeendpoint(pipe)|(usb_pipein(pipe)<<7);
|
|
|
|
|
|
+ int endp = usb_pipeendpoint(pipe)|(usb_pipein(pipe)<<7);
|
|
|
|
|
|
result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
|
|
result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
|
|
USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, endp, NULL, 0, USB_CNTL_TIMEOUT * 3);
|
|
USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, endp, NULL, 0, USB_CNTL_TIMEOUT * 3);
|
|
@@ -339,15 +341,14 @@ int usb_clear_halt(struct usb_device *dev, int pipe)
|
|
/* don't clear if failed */
|
|
/* don't clear if failed */
|
|
if (result < 0)
|
|
if (result < 0)
|
|
return result;
|
|
return result;
|
|
- result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
|
|
|
|
- USB_REQ_GET_STATUS, USB_DIR_IN | USB_RECIP_ENDPOINT, 0, endp,
|
|
|
|
- &status, sizeof(status), USB_CNTL_TIMEOUT * 3);
|
|
|
|
- if (result < 0)
|
|
|
|
- return result;
|
|
|
|
- USB_PRINTF("usb_clear_halt: status 0x%x\n",status);
|
|
|
|
- if (status & 1)
|
|
|
|
- return -1; /* still halted */
|
|
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * NOTE: we do not get status and verify reset was successful
|
|
|
|
+ * as some devices are reported to lock up upon this check..
|
|
|
|
+ */
|
|
|
|
+
|
|
usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
|
|
usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
|
|
|
|
+
|
|
/* toggle is reset on clear */
|
|
/* toggle is reset on clear */
|
|
usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0);
|
|
usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0);
|
|
return 0;
|
|
return 0;
|
|
@@ -423,7 +424,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
|
|
struct usb_interface_descriptor *if_face = NULL;
|
|
struct usb_interface_descriptor *if_face = NULL;
|
|
int ret, i;
|
|
int ret, i;
|
|
|
|
|
|
- for (i=0; i<dev->config.bNumInterfaces; i++) {
|
|
|
|
|
|
+ for (i = 0; i < dev->config.bNumInterfaces; i++) {
|
|
if (dev->config.if_desc[i].bInterfaceNumber == interface) {
|
|
if (dev->config.if_desc[i].bInterfaceNumber == interface) {
|
|
if_face = &dev->config.if_desc[i];
|
|
if_face = &dev->config.if_desc[i];
|
|
break;
|
|
break;
|
|
@@ -439,8 +440,6 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
|
|
interface, NULL, 0, USB_CNTL_TIMEOUT * 5)) < 0)
|
|
interface, NULL, 0, USB_CNTL_TIMEOUT * 5)) < 0)
|
|
return ret;
|
|
return ret;
|
|
|
|
|
|
- if_face->act_altsetting = (unsigned char)alternate;
|
|
|
|
- usb_set_maxpacket(dev);
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -511,11 +510,74 @@ int usb_get_class_descriptor(struct usb_device *dev, int ifnum,
|
|
*/
|
|
*/
|
|
int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char index, void *buf, int size)
|
|
int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char index, void *buf, int size)
|
|
{
|
|
{
|
|
- return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
|
|
|
|
- USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
|
|
|
|
- (USB_DT_STRING << 8) + index, langid, buf, size, USB_CNTL_TIMEOUT);
|
|
|
|
|
|
+ int i;
|
|
|
|
+ int result;
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < 3; ++i) {
|
|
|
|
+ /* some devices are flaky */
|
|
|
|
+ result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
|
|
|
|
+ USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
|
|
|
|
+ (USB_DT_STRING << 8) + index, langid, buf, size,
|
|
|
|
+ USB_CNTL_TIMEOUT);
|
|
|
|
+
|
|
|
|
+ if (result > 0)
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return result;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static void usb_try_string_workarounds(unsigned char *buf, int *length)
|
|
|
|
+{
|
|
|
|
+ int newlength, oldlength = *length;
|
|
|
|
+
|
|
|
|
+ for (newlength = 2; newlength + 1 < oldlength; newlength += 2)
|
|
|
|
+ if (!isprint(buf[newlength]) || buf[newlength + 1])
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ if (newlength > 2) {
|
|
|
|
+ buf[0] = newlength;
|
|
|
|
+ *length = newlength;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+
|
|
|
|
+static int usb_string_sub(struct usb_device *dev, unsigned int langid,
|
|
|
|
+ unsigned int index, unsigned char *buf)
|
|
|
|
+{
|
|
|
|
+ int rc;
|
|
|
|
+
|
|
|
|
+ /* Try to read the string descriptor by asking for the maximum
|
|
|
|
+ * possible number of bytes */
|
|
|
|
+ rc = usb_get_string(dev, langid, index, buf, 255);
|
|
|
|
+
|
|
|
|
+ /* If that failed try to read the descriptor length, then
|
|
|
|
+ * ask for just that many bytes */
|
|
|
|
+ if (rc < 2) {
|
|
|
|
+ rc = usb_get_string(dev, langid, index, buf, 2);
|
|
|
|
+ if (rc == 2)
|
|
|
|
+ rc = usb_get_string(dev, langid, index, buf, buf[0]);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (rc >= 2) {
|
|
|
|
+ if (!buf[0] && !buf[1])
|
|
|
|
+ usb_try_string_workarounds(buf, &rc);
|
|
|
|
+
|
|
|
|
+ /* There might be extra junk at the end of the descriptor */
|
|
|
|
+ if (buf[0] < rc)
|
|
|
|
+ rc = buf[0];
|
|
|
|
+
|
|
|
|
+ rc = rc - (rc & 1); /* force a multiple of two */
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (rc < 2)
|
|
|
|
+ rc = -1;
|
|
|
|
+
|
|
|
|
+ return rc;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
/********************************************************************
|
|
/********************************************************************
|
|
* usb_string:
|
|
* usb_string:
|
|
* Get string index and translate it to ascii.
|
|
* Get string index and translate it to ascii.
|
|
@@ -535,7 +597,7 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
|
|
|
|
|
|
/* get langid for strings if it's not yet known */
|
|
/* get langid for strings if it's not yet known */
|
|
if (!dev->have_langid) {
|
|
if (!dev->have_langid) {
|
|
- err = usb_get_string(dev, 0, 0, tbuf, 4);
|
|
|
|
|
|
+ err = usb_string_sub(dev, 0, 0, tbuf);
|
|
if (err < 0) {
|
|
if (err < 0) {
|
|
USB_PRINTF("error getting string descriptor 0 (error=%x)\n",dev->status);
|
|
USB_PRINTF("error getting string descriptor 0 (error=%x)\n",dev->status);
|
|
return -1;
|
|
return -1;
|
|
@@ -550,22 +612,11 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
|
|
dev->devnum, dev->string_langid);
|
|
dev->devnum, dev->string_langid);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- /* Just ask for a maximum length string and then take the length
|
|
|
|
- * that was returned. */
|
|
|
|
- err = usb_get_string(dev, dev->string_langid, index, tbuf, 4);
|
|
|
|
- if (err < 0)
|
|
|
|
- return err;
|
|
|
|
- u=tbuf[0];
|
|
|
|
- USB_PRINTF("Strn Len %d, index %d\n",u,index);
|
|
|
|
|
|
|
|
- if (u > USB_BUFSIZ) {
|
|
|
|
- USB_PRINTF("usb_string: failed to get string - too long: %d\n", u);
|
|
|
|
- return -1;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- err = usb_get_string(dev, dev->string_langid, index, tbuf, u);
|
|
|
|
|
|
+ err = usb_string_sub(dev, dev->string_langid, index, tbuf);
|
|
if (err < 0)
|
|
if (err < 0)
|
|
return err;
|
|
return err;
|
|
|
|
+
|
|
size--; /* leave room for trailing NULL char in output buffer */
|
|
size--; /* leave room for trailing NULL char in output buffer */
|
|
for (idx = 0, u = 2; u < err; u += 2) {
|
|
for (idx = 0, u = 2; u < err; u += 2) {
|
|
if (idx >= size)
|
|
if (idx >= size)
|
|
@@ -641,11 +692,66 @@ int usb_new_device(struct usb_device *dev)
|
|
/* We still haven't set the Address yet */
|
|
/* We still haven't set the Address yet */
|
|
addr = dev->devnum;
|
|
addr = dev->devnum;
|
|
dev->devnum = 0;
|
|
dev->devnum = 0;
|
|
|
|
+
|
|
|
|
+#undef NEW_INIT_SEQ
|
|
|
|
+#ifdef NEW_INIT_SEQ
|
|
|
|
+ /* this is a Windows scheme of initialization sequence, with double
|
|
|
|
+ * reset of the device. Some equipment is said to work only with such
|
|
|
|
+ * init sequence; this patch is based on the work by Alan Stern:
|
|
|
|
+ * http://sourceforge.net/mailarchive/forum.php?thread_id=5729457&forum_id=5398
|
|
|
|
+ */
|
|
|
|
+ int j;
|
|
|
|
+ struct usb_device_descriptor *desc;
|
|
|
|
+ int port = -1;
|
|
|
|
+ struct usb_device *parent = dev->parent;
|
|
|
|
+ unsigned short portstatus;
|
|
|
|
+
|
|
|
|
+ /* send 64-byte GET-DEVICE-DESCRIPTOR request. Since the descriptor is
|
|
|
|
+ * only 18 bytes long, this will terminate with a short packet. But if
|
|
|
|
+ * the maxpacket size is 8 or 16 the device may be waiting to transmit
|
|
|
|
+ * some more. */
|
|
|
|
+
|
|
|
|
+ desc = (struct usb_device_descriptor *)tmpbuf;
|
|
|
|
+ desc->bMaxPacketSize0 = 0;
|
|
|
|
+ for (j = 0; j < 3; ++j) {
|
|
|
|
+ err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, 64);
|
|
|
|
+ if (err < 0) {
|
|
|
|
+ USB_PRINTF("usb_new_device: 64 byte descr\n");
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ dev->descriptor.bMaxPacketSize0 = desc->bMaxPacketSize0;
|
|
|
|
+
|
|
|
|
+ /* find the port number we're at */
|
|
|
|
+ if (parent) {
|
|
|
|
+
|
|
|
|
+ for (j = 0; j < parent->maxchild; j++) {
|
|
|
|
+ if (parent->children[j] == dev) {
|
|
|
|
+ port = j;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (port < 0) {
|
|
|
|
+ printf("usb_new_device: cannot locate device's port..\n");
|
|
|
|
+ return 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* reset the port for the second time */
|
|
|
|
+ err = hub_port_reset(dev->parent, port, &portstatus);
|
|
|
|
+ if (err < 0) {
|
|
|
|
+ printf("\n Couldn't reset port %i\n", port);
|
|
|
|
+ return 1;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+#else
|
|
|
|
+ /* and this is the old and known way of initializing devices */
|
|
err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8);
|
|
err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8);
|
|
if (err < 8) {
|
|
if (err < 8) {
|
|
printf("\n USB device not responding, giving up (status=%lX)\n",dev->status);
|
|
printf("\n USB device not responding, giving up (status=%lX)\n",dev->status);
|
|
return 1;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
+#endif
|
|
|
|
+
|
|
dev->epmaxpacketin [0] = dev->descriptor.bMaxPacketSize0;
|
|
dev->epmaxpacketin [0] = dev->descriptor.bMaxPacketSize0;
|
|
dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0;
|
|
dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0;
|
|
switch (dev->descriptor.bMaxPacketSize0) {
|
|
switch (dev->descriptor.bMaxPacketSize0) {
|
|
@@ -723,7 +829,7 @@ void usb_scan_devices(void)
|
|
/* device 0 is always present (root hub, so let it analyze) */
|
|
/* device 0 is always present (root hub, so let it analyze) */
|
|
dev=usb_alloc_new_device();
|
|
dev=usb_alloc_new_device();
|
|
usb_new_device(dev);
|
|
usb_new_device(dev);
|
|
- printf("%d USB Devices found\n",dev_index);
|
|
|
|
|
|
+ printf("%d USB Device(s) found\n",dev_index);
|
|
/* insert "driver" if possible */
|
|
/* insert "driver" if possible */
|
|
#ifdef CONFIG_USB_KEYBOARD
|
|
#ifdef CONFIG_USB_KEYBOARD
|
|
drv_usb_kbd_init();
|
|
drv_usb_kbd_init();
|
|
@@ -821,39 +927,15 @@ struct usb_hub_device *usb_hub_allocate(void)
|
|
|
|
|
|
#define MAX_TRIES 5
|
|
#define MAX_TRIES 5
|
|
|
|
|
|
-void usb_hub_port_connect_change(struct usb_device *dev, int port)
|
|
|
|
|
|
+static int hub_port_reset(struct usb_device *dev, int port,
|
|
|
|
+ unsigned short *portstat)
|
|
{
|
|
{
|
|
- struct usb_device *usb;
|
|
|
|
|
|
+ int tries;
|
|
struct usb_port_status portsts;
|
|
struct usb_port_status portsts;
|
|
unsigned short portstatus, portchange;
|
|
unsigned short portstatus, portchange;
|
|
- int tries;
|
|
|
|
|
|
|
|
- /* Check status */
|
|
|
|
- if (usb_get_port_status(dev, port + 1, &portsts)<0) {
|
|
|
|
- USB_HUB_PRINTF("get_port_status failed\n");
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- portstatus = swap_16(portsts.wPortStatus);
|
|
|
|
- portchange = swap_16(portsts.wPortChange);
|
|
|
|
- USB_HUB_PRINTF("portstatus %x, change %x, %s\n", portstatus, portchange,
|
|
|
|
- portstatus&(1<<USB_PORT_FEAT_LOWSPEED) ? "Low Speed" : "High Speed");
|
|
|
|
-
|
|
|
|
- /* Clear the connection change status */
|
|
|
|
- usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_C_CONNECTION);
|
|
|
|
-
|
|
|
|
- /* Disconnect any existing devices under this port */
|
|
|
|
- if (((!(portstatus & USB_PORT_STAT_CONNECTION)) &&
|
|
|
|
- (!(portstatus & USB_PORT_STAT_ENABLE)))|| (dev->children[port])) {
|
|
|
|
- USB_HUB_PRINTF("usb_disconnect(&hub->children[port]);\n");
|
|
|
|
- /* Return now if nothing is connected */
|
|
|
|
- if (!(portstatus & USB_PORT_STAT_CONNECTION))
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- wait_ms(200);
|
|
|
|
-
|
|
|
|
- /* Reset the port */
|
|
|
|
|
|
|
|
|
|
+ USB_HUB_PRINTF("hub_port_reset: resetting port %d...\n", port);
|
|
for(tries=0;tries<MAX_TRIES;tries++) {
|
|
for(tries=0;tries<MAX_TRIES;tries++) {
|
|
|
|
|
|
usb_set_port_feature(dev, port + 1, USB_PORT_FEAT_RESET);
|
|
usb_set_port_feature(dev, port + 1, USB_PORT_FEAT_RESET);
|
|
@@ -861,7 +943,7 @@ void usb_hub_port_connect_change(struct usb_device *dev, int port)
|
|
|
|
|
|
if (usb_get_port_status(dev, port + 1, &portsts)<0) {
|
|
if (usb_get_port_status(dev, port + 1, &portsts)<0) {
|
|
USB_HUB_PRINTF("get_port_status failed status %lX\n",dev->status);
|
|
USB_HUB_PRINTF("get_port_status failed status %lX\n",dev->status);
|
|
- return;
|
|
|
|
|
|
+ return -1;
|
|
}
|
|
}
|
|
portstatus = swap_16(portsts.wPortStatus);
|
|
portstatus = swap_16(portsts.wPortStatus);
|
|
portchange = swap_16(portsts.wPortChange);
|
|
portchange = swap_16(portsts.wPortChange);
|
|
@@ -873,10 +955,12 @@ void usb_hub_port_connect_change(struct usb_device *dev, int port)
|
|
(portstatus & USB_PORT_STAT_ENABLE) ? 1 : 0);
|
|
(portstatus & USB_PORT_STAT_ENABLE) ? 1 : 0);
|
|
if ((portchange & USB_PORT_STAT_C_CONNECTION) ||
|
|
if ((portchange & USB_PORT_STAT_C_CONNECTION) ||
|
|
!(portstatus & USB_PORT_STAT_CONNECTION))
|
|
!(portstatus & USB_PORT_STAT_CONNECTION))
|
|
- return;
|
|
|
|
|
|
+ return -1;
|
|
|
|
|
|
- if (portstatus & USB_PORT_STAT_ENABLE)
|
|
|
|
|
|
+ if (portstatus & USB_PORT_STAT_ENABLE) {
|
|
|
|
+
|
|
break;
|
|
break;
|
|
|
|
+ }
|
|
|
|
|
|
wait_ms(200);
|
|
wait_ms(200);
|
|
}
|
|
}
|
|
@@ -884,10 +968,52 @@ void usb_hub_port_connect_change(struct usb_device *dev, int port)
|
|
if (tries==MAX_TRIES) {
|
|
if (tries==MAX_TRIES) {
|
|
USB_HUB_PRINTF("Cannot enable port %i after %i retries, disabling port.\n", port+1, MAX_TRIES);
|
|
USB_HUB_PRINTF("Cannot enable port %i after %i retries, disabling port.\n", port+1, MAX_TRIES);
|
|
USB_HUB_PRINTF("Maybe the USB cable is bad?\n");
|
|
USB_HUB_PRINTF("Maybe the USB cable is bad?\n");
|
|
- return;
|
|
|
|
|
|
+ return -1;
|
|
}
|
|
}
|
|
|
|
|
|
usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_C_RESET);
|
|
usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_C_RESET);
|
|
|
|
+ *portstat = portstatus;
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+void usb_hub_port_connect_change(struct usb_device *dev, int port)
|
|
|
|
+{
|
|
|
|
+ struct usb_device *usb;
|
|
|
|
+ struct usb_port_status portsts;
|
|
|
|
+ unsigned short portstatus, portchange;
|
|
|
|
+
|
|
|
|
+ /* Check status */
|
|
|
|
+ if (usb_get_port_status(dev, port + 1, &portsts)<0) {
|
|
|
|
+ USB_HUB_PRINTF("get_port_status failed\n");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ portstatus = swap_16(portsts.wPortStatus);
|
|
|
|
+ portchange = swap_16(portsts.wPortChange);
|
|
|
|
+ USB_HUB_PRINTF("portstatus %x, change %x, %s\n", portstatus, portchange,
|
|
|
|
+ portstatus&(1<<USB_PORT_FEAT_LOWSPEED) ? "Low Speed" : "High Speed");
|
|
|
|
+
|
|
|
|
+ /* Clear the connection change status */
|
|
|
|
+ usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_C_CONNECTION);
|
|
|
|
+
|
|
|
|
+ /* Disconnect any existing devices under this port */
|
|
|
|
+ if (((!(portstatus & USB_PORT_STAT_CONNECTION)) &&
|
|
|
|
+ (!(portstatus & USB_PORT_STAT_ENABLE)))|| (dev->children[port])) {
|
|
|
|
+ USB_HUB_PRINTF("usb_disconnect(&hub->children[port]);\n");
|
|
|
|
+ /* Return now if nothing is connected */
|
|
|
|
+ if (!(portstatus & USB_PORT_STAT_CONNECTION))
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ wait_ms(200);
|
|
|
|
+
|
|
|
|
+ /* Reset the port */
|
|
|
|
+ if (hub_port_reset(dev, port, &portstatus) < 0) {
|
|
|
|
+ printf("cannot reset port %i!?\n", port + 1);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
wait_ms(200);
|
|
wait_ms(200);
|
|
|
|
|
|
/* Allocate a new device struct for it */
|
|
/* Allocate a new device struct for it */
|