]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - common/usb.c
common/ non-cmd: Augment CONFIG_COMMANDS tests with defined(CONFIG_CMD_*).
[karo-tx-uboot.git] / common / usb.c
index a96052a0c0e5dab1bae0816a8a23f9f4313c4e60..282c1d97b7434c77ff025369060719327a27814c 100644 (file)
@@ -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:
  *
 #include <common.h>
 #include <command.h>
 #include <asm/processor.h>
+#include <linux/ctype.h>
 
-#if (CONFIG_COMMANDS & CFG_CMD_USB)
+#if (CONFIG_COMMANDS & CFG_CMD_USB) || defined(CONFIG_CMD_USB)
 
 #include <usb.h>
 #ifdef CONFIG_4xx
 #include <405gp_pci.h>
 #endif
 
-
 #undef USB_DEBUG
 
 #ifdef USB_DEBUG
 #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...
  */
@@ -69,6 +82,7 @@ void usb_scan_devices(void);
 int usb_hub_probe(struct usb_device *dev, int ifnum);
 void usb_hub_reset(void);
 
+
 /***********************************************************************
  * wait_ms
  */
@@ -98,10 +112,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,6 +128,7 @@ int usb_init(void)
 int usb_stop(void)
 {
        asynch_allowed=1;
+       usb_started = 0;
        usb_hub_reset();
        return usb_lowlevel_stop();
 }
@@ -156,6 +173,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 */
                return -1;
+
        /* set setup command */
        setup_packet.requesttype = requesttype;
        setup_packet.request = request;
@@ -267,56 +285,68 @@ 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]);
+       dev->config.wTotalLength = swap_16(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]);
+                               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);
                                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;i<head->bLength; 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;
 }
@@ -329,8 +359,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);
@@ -338,15 +367,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;
@@ -387,6 +415,12 @@ int usb_get_configuration_no(struct usb_device *dev,unsigned char *buffer,int cf
        }
        tmp=swap_16(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);
        return result;
@@ -416,7 +450,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; i<dev->config.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;
@@ -426,14 +460,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;
 }
 
@@ -504,11 +544,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.
@@ -516,8 +619,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;
@@ -529,7 +631,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 */
        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;
@@ -544,16 +646,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)
@@ -619,7 +716,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 */
@@ -629,11 +726,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) {
@@ -711,7 +863,7 @@ void usb_scan_devices(void)
        /* device 0 is always present (root hub, so let it analyze) */
        dev=usb_alloc_new_device();
        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 */
 #ifdef CONFIG_USB_KEYBOARD
        drv_usb_kbd_init();
@@ -809,39 +961,15 @@ struct usb_hub_device *usb_hub_allocate(void)
 
 #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;
        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++) {
 
                usb_set_port_feature(dev, port + 1, USB_PORT_FEAT_RESET);
@@ -849,7 +977,7 @@ void usb_hub_port_connect_change(struct usb_device *dev, int port)
 
                if (usb_get_port_status(dev, port + 1, &portsts)<0) {
                        USB_HUB_PRINTF("get_port_status failed status %lX\n",dev->status);
-                       return;
+                       return -1;
                }
                portstatus = swap_16(portsts.wPortStatus);
                portchange = swap_16(portsts.wPortChange);
@@ -861,10 +989,12 @@ void usb_hub_port_connect_change(struct usb_device *dev, int port)
                        (portstatus & USB_PORT_STAT_ENABLE) ? 1 : 0);
                if ((portchange & USB_PORT_STAT_C_CONNECTION) ||
                    !(portstatus & USB_PORT_STAT_CONNECTION))
-                       return;
+                       return -1;
+
+               if (portstatus & USB_PORT_STAT_ENABLE) {
 
-               if (portstatus & USB_PORT_STAT_ENABLE)
                        break;
+               }
 
                wait_ms(200);
        }
@@ -872,10 +1002,52 @@ void usb_hub_port_connect_change(struct usb_device *dev, int port)
        if (tries==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");
-               return;
+               return -1;
        }
 
        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);
 
        /* Allocate a new device struct for it */
@@ -895,7 +1067,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;
@@ -912,6 +1084,15 @@ 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;
@@ -968,6 +1149,12 @@ 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;