X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=common%2Fusb.c;h=4d64ccb43850e42089fb8d2b242472581c388716;hb=be19d324edc1a1d7f393d24e10d164cd94c91a00;hp=a5b29a56b462ebafbf058e89abe16fc20e744f87;hpb=affae2bff825c1a8d2cfeaf7b270188d251d39d2;p=platform%2Fkernel%2Fu-boot.git diff --git a/common/usb.c b/common/usb.c index a5b29a5..4d64ccb 100644 --- a/common/usb.c +++ b/common/usb.c @@ -1,9 +1,19 @@ /* - * (C) Copyright 2001 - * Denis Peter, MPL AG Switzerland * * Most of this source has been derived from the Linux USB - * project. + * project: + * (C) Copyright Linus Torvalds 1999 + * (C) Copyright Johannes Erdfelt 1999-2001 + * (C) Copyright Andreas Gal 1999 + * (C) Copyright Gregory P. Smith 1999 + * (C) Copyright Deti Fliegl 1999 (new USB architecture) + * (C) Copyright Randy Dunlap 2000 + * (C) Copyright David Brownell 2000 (kernel hotplug, usb_device_id) + * (C) Copyright Yggdrasil Computing, Inc. 2000 + * (usb_device_id matching changes by Adam J. Richter) + * + * Adapted for U-Boot: + * (C) Copyright 2001 Denis Peter, MPL AG Switzerland * * See file CREDITS for list of people who contributed to this * project. @@ -25,7 +35,6 @@ * */ - /* * How it works: * @@ -38,16 +47,14 @@ #include #include #include - -#if (CONFIG_COMMANDS & CFG_CMD_USB) +#include +#include #include #ifdef CONFIG_4xx -#include <405gp_pci.h> +#include #endif - - #undef USB_DEBUG #ifdef USB_DEBUG @@ -56,12 +63,16 @@ #define USB_PRINTF(fmt,args...) #endif +#define USB_BUFSIZ 512 + static struct usb_device usb_dev[USB_MAX_DEVICE]; static int dev_index; static int running; static int asynch_allowed; static struct devrequest setup_packet; +char usb_started; /* flag for the started/stopped USB status */ + /********************************************************************** * some forward declerations... */ @@ -70,6 +81,7 @@ void usb_scan_devices(void); int usb_hub_probe(struct usb_device *dev, int ifnum); void usb_hub_reset(void); + /*********************************************************************** * wait_ms */ @@ -99,10 +111,12 @@ int usb_init(void) printf("scanning bus for devices... "); running=1; usb_scan_devices(); + usb_started = 1; return 0; } else { printf("Error, couldn't init Lowlevel part\n"); + usb_started = 0; return -1; } } @@ -112,9 +126,15 @@ int usb_init(void) */ int usb_stop(void) { - asynch_allowed=1; - usb_hub_reset(); - return usb_lowlevel_stop(); + int res = 0; + + if (usb_started) { + asynch_allowed = 1; + usb_started = 0; + usb_hub_reset(); + res = usb_lowlevel_stop(); + } + return res; } /* @@ -157,13 +177,14 @@ 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 */ return -1; + /* set setup command */ setup_packet.requesttype = requesttype; setup_packet.request = request; - setup_packet.value = swap_16(value); - setup_packet.index = swap_16(index); - setup_packet.length = swap_16(size); - USB_PRINTF("usb_control_msg: request: 0x%X, requesttype: 0x%X\nvalue 0x%X index 0x%X length 0x%X\n", + setup_packet.value = cpu_to_le16(value); + setup_packet.index = cpu_to_le16(index); + setup_packet.length = cpu_to_le16(size); + USB_PRINTF("usb_control_msg: request: 0x%X, requesttype: 0x%X, value 0x%X index 0x%X length 0x%X\n", request,requesttype,value,index,size); dev->status=USB_ST_NOT_PROC; /*not yet processed */ @@ -224,40 +245,59 @@ int usb_maxpacket(struct usb_device *dev,unsigned long pipe) return(dev->epmaxpacketin[((pipe>>15) & 0xf)]); } +/* The routine usb_set_maxpacket_ep() is extracted from the loop of routine + * usb_set_maxpacket(), because the optimizer of GCC 4.x chokes on this routine + * when it is inlined in 1 single routine. What happens is that the register r3 + * is used as loop-count 'i', but gets overwritten later on. + * This is clearly a compiler bug, but it is easier to workaround it here than + * to update the compiler (Occurs with at least several GCC 4.{1,2},x + * CodeSourcery compilers like e.g. 2007q3, 2008q1, 2008q3 lite editions on ARM) + */ +static void __attribute__((noinline)) +usb_set_maxpacket_ep(struct usb_device *dev, struct usb_endpoint_descriptor *ep) +{ + int b; + + b = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + + if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_CONTROL) { + /* Control => bidirectional */ + dev->epmaxpacketout[b] = ep->wMaxPacketSize; + dev->epmaxpacketin [b] = ep->wMaxPacketSize; + USB_PRINTF("##Control EP epmaxpacketout/in[%d] = %d\n", + b, dev->epmaxpacketin[b]); + } else { + if ((ep->bEndpointAddress & 0x80) == 0) { + /* OUT Endpoint */ + if (ep->wMaxPacketSize > dev->epmaxpacketout[b]) { + dev->epmaxpacketout[b] = ep->wMaxPacketSize; + USB_PRINTF("##EP epmaxpacketout[%d] = %d\n", + b, dev->epmaxpacketout[b]); + } + } else { + /* IN Endpoint */ + if (ep->wMaxPacketSize > dev->epmaxpacketin[b]) { + dev->epmaxpacketin[b] = ep->wMaxPacketSize; + USB_PRINTF("##EP epmaxpacketin[%d] = %d\n", + b, dev->epmaxpacketin[b]); + } + } /* if out */ + } /* if control */ +} + /* * set the max packed value of all endpoints in the given configuration */ int usb_set_maxpacket(struct usb_device *dev) { - int i,ii,b; - struct usb_endpoint_descriptor *ep; + int i, ii; - for(i=0; iconfig.bNumInterfaces;i++) { - for(ii=0; iiconfig.if_desc[i].bNumEndpoints; ii++) { - ep=&dev->config.if_desc[i].ep_desc[ii]; - b=ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + for (i = 0; i < dev->config.bNumInterfaces; i++) + for (ii = 0; ii < dev->config.if_desc[i].bNumEndpoints; ii++) + usb_set_maxpacket_ep(dev, + &dev->config.if_desc[i].ep_desc[ii]); - if((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)==USB_ENDPOINT_XFER_CONTROL) { /* Control => bidirectional */ - dev->epmaxpacketout[b] = ep->wMaxPacketSize; - dev->epmaxpacketin [b] = ep->wMaxPacketSize; - USB_PRINTF("##Control EP epmaxpacketout/in[%d] = %d\n",b,dev->epmaxpacketin[b]); - } - else { - if ((ep->bEndpointAddress & 0x80)==0) { /* OUT Endpoint */ - if(ep->wMaxPacketSize > dev->epmaxpacketout[b]) { - dev->epmaxpacketout[b] = ep->wMaxPacketSize; - USB_PRINTF("##EP epmaxpacketout[%d] = %d\n",b,dev->epmaxpacketout[b]); - } - } - else { /* IN Endpoint */ - if(ep->wMaxPacketSize > dev->epmaxpacketin[b]) { - dev->epmaxpacketin[b] = ep->wMaxPacketSize; - USB_PRINTF("##EP epmaxpacketin[%d] = %d\n",b,dev->epmaxpacketin[b]); - } - } /* if out */ - } /* if control */ - } /* for each endpoint */ - } return 0; } @@ -268,56 +308,67 @@ int usb_set_maxpacket(struct usb_device *dev) int usb_parse_config(struct usb_device *dev, unsigned char *buffer, int cfgno) { struct usb_descriptor_header *head; - int index,ifno,epno; - ifno=-1; - epno=-1; - - dev->configno=cfgno; - head =(struct usb_descriptor_header *)&buffer[0]; - if(head->bDescriptorType!=USB_DT_CONFIG) { - printf(" ERROR: NOT USB_CONFIG_DESC %x\n",head->bDescriptorType); + int index, ifno, epno, curr_if_num; + int i; + unsigned char *ch; + + ifno = -1; + epno = -1; + curr_if_num = -1; + + dev->configno = cfgno; + head = (struct usb_descriptor_header *) &buffer[0]; + if(head->bDescriptorType != USB_DT_CONFIG) { + printf(" ERROR: NOT USB_CONFIG_DESC %x\n", head->bDescriptorType); return -1; } - memcpy(&dev->config,buffer,buffer[0]); - dev->config.wTotalLength=swap_16(dev->config.wTotalLength); - dev->config.no_of_if=0; + memcpy(&dev->config, buffer, buffer[0]); + le16_to_cpus(&(dev->config.wTotalLength)); + dev->config.no_of_if = 0; - index=dev->config.bLength; + index = dev->config.bLength; /* Ok the first entry must be a configuration entry, now process the others */ - head=(struct usb_descriptor_header *)&buffer[index]; - while(index+1 < dev->config.wTotalLength) { + head = (struct usb_descriptor_header *) &buffer[index]; + while(index + 1 < dev->config.wTotalLength) { switch(head->bDescriptorType) { case USB_DT_INTERFACE: - ifno=dev->config.no_of_if; - dev->config.no_of_if++; /* found an interface desc, increase numbers */ - memcpy(&dev->config.if_desc[ifno],&buffer[index],buffer[index]); /* copy new desc */ - dev->config.if_desc[ifno].no_of_ep=0; - + if(((struct usb_interface_descriptor *) &buffer[index])-> + bInterfaceNumber != curr_if_num) { + /* this is a new interface, copy new desc */ + ifno = dev->config.no_of_if; + dev->config.no_of_if++; + memcpy(&dev->config.if_desc[ifno], + &buffer[index], buffer[index]); + dev->config.if_desc[ifno].no_of_ep = 0; + dev->config.if_desc[ifno].num_altsetting = 1; + curr_if_num = dev->config.if_desc[ifno].bInterfaceNumber; + } else { + /* found alternate setting for the interface */ + dev->config.if_desc[ifno].num_altsetting++; + } break; case USB_DT_ENDPOINT: - epno=dev->config.if_desc[ifno].no_of_ep; + epno = dev->config.if_desc[ifno].no_of_ep; dev->config.if_desc[ifno].no_of_ep++; /* found an endpoint */ - memcpy(&dev->config.if_desc[ifno].ep_desc[epno],&buffer[index],buffer[index]); - dev->config.if_desc[ifno].ep_desc[epno].wMaxPacketSize - =swap_16(dev->config.if_desc[ifno].ep_desc[epno].wMaxPacketSize); - USB_PRINTF("if %d, ep %d\n",ifno,epno); + memcpy(&dev->config.if_desc[ifno].ep_desc[epno], + &buffer[index], buffer[index]); + le16_to_cpus(&(dev->config.if_desc[ifno].ep_desc[epno].wMaxPacketSize)); + USB_PRINTF("if %d, ep %d\n", ifno, epno); break; default: - if(head->bLength==0) + if(head->bLength == 0) return 1; - USB_PRINTF("unknown Description Type : %x\n",head->bDescriptorType); + USB_PRINTF("unknown Description Type : %x\n", head->bDescriptorType); { - int i; - unsigned char *ch; - ch=(unsigned char *)head; - for(i=0;ibLength; i++) - USB_PRINTF("%02X ",*ch++); + ch = (unsigned char *)head; + for(i = 0; i < head->bLength; i++) + USB_PRINTF("%02X ", *ch++); USB_PRINTF("\n\n\n"); } break; } - index+=head->bLength; - head=(struct usb_descriptor_header *)&buffer[index]; + index += head->bLength; + head = (struct usb_descriptor_header *)&buffer[index]; } return 1; } @@ -330,8 +381,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 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), USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, endp, NULL, 0, USB_CNTL_TIMEOUT * 3); @@ -339,15 +389,14 @@ int usb_clear_halt(struct usb_device *dev, int pipe) /* don't clear if failed */ if (result < 0) 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)); + /* toggle is reset on clear */ usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0); return 0; @@ -360,7 +409,7 @@ int usb_clear_halt(struct usb_device *dev, int pipe) int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size) { int res; - res = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + res = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, (type << 8) + index, 0, buf, size, USB_CNTL_TIMEOUT); @@ -372,7 +421,7 @@ int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char */ int usb_get_configuration_no(struct usb_device *dev,unsigned char *buffer,int cfgno) { - int result; + int result; unsigned int tmp; struct usb_config_descriptor *config; @@ -386,7 +435,13 @@ int usb_get_configuration_no(struct usb_device *dev,unsigned char *buffer,int cf printf("config descriptor too short (expected %i, got %i)\n",8,result); return -1; } - tmp=swap_16(config->wTotalLength); + tmp = le16_to_cpu(config->wTotalLength); + + if (tmp > USB_BUFSIZ) { + USB_PRINTF("usb_get_configuration_no: failed to get descriptor - too long: %d\n", + tmp); + return -1; + } result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, tmp); USB_PRINTF("get_conf_no %d Result %d, wLength %d\n",cfgno,result,tmp); @@ -417,7 +472,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) struct usb_interface_descriptor *if_face = NULL; int ret, i; - for (i=0; iconfig.bNumInterfaces; i++) { + for (i = 0; i < dev->config.bNumInterfaces; i++) { if (dev->config.if_desc[i].bInterfaceNumber == interface) { if_face = &dev->config.if_desc[i]; break; @@ -427,14 +482,20 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) printf("selecting invalid interface %d", interface); return -1; } + /* + * We should return now for devices with only one alternate setting. + * According to 9.4.10 of the Universal Serial Bus Specification Revision 2.0 + * such devices can return with a STALL. This results in some USB sticks + * timeouting during initialization and then being unusable in U-Boot. + */ + if (if_face->num_altsetting == 1) + return 0; if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE, alternate, interface, NULL, 0, USB_CNTL_TIMEOUT * 5)) < 0) return ret; - if_face->act_altsetting = (unsigned char)alternate; - usb_set_maxpacket(dev); return 0; } @@ -505,11 +566,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) { - 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: * Get string index and translate it to ascii. @@ -517,8 +641,7 @@ int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char */ int usb_string(struct usb_device *dev, int index, char *buf, size_t size) { - - unsigned char mybuf[256]; + unsigned char mybuf[USB_BUFSIZ]; unsigned char *tbuf; int err; unsigned int u, idx; @@ -526,11 +649,11 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size) if (size <= 0 || !buf || !index) return -1; buf[0] = 0; - tbuf=&mybuf[0]; + tbuf = &mybuf[0]; /* get langid for strings if it's not yet known */ if (!dev->have_langid) { - err = usb_get_string(dev, 0, 0, tbuf, 4); + err = usb_string_sub(dev, 0, 0, tbuf); if (err < 0) { USB_PRINTF("error getting string descriptor 0 (error=%x)\n",dev->status); return -1; @@ -545,16 +668,11 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size) 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); - err = usb_get_string(dev, dev->string_langid, index, tbuf, u); + + err = usb_string_sub(dev, dev->string_langid, index, tbuf); if (err < 0) return err; + size--; /* leave room for trailing NULL char in output buffer */ for (idx = 0, u = 2; u < err; u += 2) { if (idx >= size) @@ -596,7 +714,7 @@ struct usb_device * usb_alloc_new_device(void) int i; USB_PRINTF("New Device %d\n",dev_index); if(dev_index==USB_MAX_DEVICE) { - printf("ERROR, to many USB Devices max=%d\n",USB_MAX_DEVICE); + printf("ERROR, too many USB Devices, max=%d\n",USB_MAX_DEVICE); return NULL; } usb_dev[dev_index].devnum=dev_index+1; /* default Address is 0, real addresses start with 1 */ @@ -620,7 +738,7 @@ int usb_new_device(struct usb_device *dev) { int addr, err; int tmp; - unsigned char tmpbuf[256]; + unsigned char tmpbuf[USB_BUFSIZ]; dev->descriptor.bMaxPacketSize0 = 8; /* Start off at 8 bytes */ dev->maxpacketsize = 0; /* Default to 8 byte max packet size */ @@ -630,11 +748,66 @@ int usb_new_device(struct usb_device *dev) /* We still haven't set the Address yet */ addr = dev->devnum; 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); if (err < 8) { printf("\n USB device not responding, giving up (status=%lX)\n",dev->status); return 1; } +#endif + dev->epmaxpacketin [0] = dev->descriptor.bMaxPacketSize0; dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0; switch (dev->descriptor.bMaxPacketSize0) { @@ -665,10 +838,10 @@ int usb_new_device(struct usb_device *dev) return 1; } /* correct le values */ - dev->descriptor.bcdUSB=swap_16(dev->descriptor.bcdUSB); - dev->descriptor.idVendor=swap_16(dev->descriptor.idVendor); - dev->descriptor.idProduct=swap_16(dev->descriptor.idProduct); - dev->descriptor.bcdDevice=swap_16(dev->descriptor.bcdDevice); + le16_to_cpus(&dev->descriptor.bcdUSB); + le16_to_cpus(&dev->descriptor.idVendor); + le16_to_cpus(&dev->descriptor.idProduct); + le16_to_cpus(&dev->descriptor.bcdDevice); /* only support for one config for now */ usb_get_configuration_no(dev,&tmpbuf[0],0); usb_parse_config(dev,&tmpbuf[0],0); @@ -706,13 +879,13 @@ void usb_scan_devices(void) /* first make all devices unknown */ for(i=0;ichildren[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;triesstatus); - return; + return -1; } - portstatus = swap_16(portsts.wPortStatus); - portchange = swap_16(portsts.wPortChange); + portstatus = le16_to_cpu(portsts.wPortStatus); + portchange = le16_to_cpu(portsts.wPortChange); USB_HUB_PRINTF("portstatus %x, change %x, %s\n", portstatus ,portchange, portstatus&(1<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); /* Allocate a new device struct for it */ @@ -896,7 +1089,7 @@ void usb_hub_port_connect_change(struct usb_device *dev, int port) int usb_hub_configure(struct usb_device *dev) { - unsigned char buffer[256], *bitmap; + unsigned char buffer[USB_BUFSIZ], *bitmap; struct usb_hub_descriptor *descriptor; struct usb_hub_status *hubsts; int i; @@ -913,13 +1106,22 @@ int usb_hub_configure(struct usb_device *dev) return -1; } descriptor = (struct usb_hub_descriptor *)buffer; + + /* silence compiler warning if USB_BUFSIZ is > 256 [= sizeof(char)] */ + i = descriptor->bLength; + if (i > USB_BUFSIZ) { + USB_HUB_PRINTF("usb_hub_configure: failed to get hub descriptor - too long: %d\n", + descriptor->bLength); + return -1; + } + if (usb_get_hub_descriptor(dev, buffer, descriptor->bLength) < 0) { USB_HUB_PRINTF("usb_hub_configure: failed to get hub descriptor 2nd giving up %lX\n",dev->status); return -1; } memcpy((unsigned char *)&hub->desc,buffer,descriptor->bLength); /* adjust 16bit values */ - hub->desc.wHubCharacteristics=swap_16(descriptor->wHubCharacteristics); + hub->desc.wHubCharacteristics = le16_to_cpu(descriptor->wHubCharacteristics); /* set the bitmap */ bitmap=(unsigned char *)&hub->desc.DeviceRemovable[0]; memset(bitmap,0xff,(USB_MAXCHILDREN+1+7)/8); /* devices not removable by default */ @@ -969,17 +1171,23 @@ int usb_hub_configure(struct usb_device *dev) for (i = 0; i < dev->maxchild; i++) USB_HUB_PRINTF("port %d is%s removable\n", i + 1, hub->desc.DeviceRemovable[(i + 1)/8] & (1 << ((i + 1)%8)) ? " not" : ""); + if (sizeof(struct usb_hub_status) > USB_BUFSIZ) { + USB_HUB_PRINTF("usb_hub_configure: failed to get Status - too long: %d\n", + descriptor->bLength); + return -1; + } + if (usb_get_hub_status(dev, buffer) < 0) { USB_HUB_PRINTF("usb_hub_configure: failed to get Status %lX\n",dev->status); return -1; } hubsts = (struct usb_hub_status *)buffer; USB_HUB_PRINTF("get_hub_status returned status %X, change %X\n", - swap_16(hubsts->wHubStatus),swap_16(hubsts->wHubChange)); + le16_to_cpu(hubsts->wHubStatus),le16_to_cpu(hubsts->wHubChange)); USB_HUB_PRINTF("local power source is %s\n", - (swap_16(hubsts->wHubStatus) & HUB_STATUS_LOCAL_POWER) ? "lost (inactive)" : "good"); + (le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_LOCAL_POWER) ? "lost (inactive)" : "good"); USB_HUB_PRINTF("%sover-current condition exists\n", - (swap_16(hubsts->wHubStatus) & HUB_STATUS_OVERCURRENT) ? "" : "no "); + (le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_OVERCURRENT) ? "" : "no "); usb_hub_power_on(hub); for (i = 0; i < dev->maxchild; i++) { struct usb_port_status portsts; @@ -989,8 +1197,8 @@ int usb_hub_configure(struct usb_device *dev) USB_HUB_PRINTF("get_port_status failed\n"); continue; } - portstatus = swap_16(portsts.wPortStatus); - portchange = swap_16(portsts.wPortChange); + portstatus = le16_to_cpu(portsts.wPortStatus); + portchange = le16_to_cpu(portsts.wPortChange); USB_HUB_PRINTF("Port %d Status %X Change %X\n",i+1,portstatus,portchange); if (portchange & USB_PORT_STAT_C_CONNECTION) { USB_HUB_PRINTF("port %d connection change\n", i + 1); @@ -1061,6 +1269,4 @@ int usb_hub_probe(struct usb_device *dev, int ifnum) return ret; } -#endif /* (CONFIG_COMMANDS & CFG_CMD_USB) */ - /* EOF */