]> git.kernelconcepts.de Git - karo-tx-uboot.git/commitdiff
Fix low-level OHCI transfers for ARM920t and MPC5xxx
authorWolfgang Denk <wd@castor.denx.de>
Thu, 21 Jul 2005 09:57:57 +0000 (11:57 +0200)
committerWolfgang Denk <wd@castor.denx.de>
Thu, 21 Jul 2005 09:57:57 +0000 (11:57 +0200)
A new, Windows compatible init sequence was also backported from Linux 2.6,
but disabled with #undef NEW_INIT_SEQ as it wouldn't change the behaviour
of the memopry sticks we tested. Maybe it's not relevant for mass storage
devices. For recerence, see file common/usb.c, function usb_new_device(),
section #ifdef NEW_INIT_SEQ.

common/cmd_usb.c
common/usb.c
common/usb_storage.c
cpu/arm920t/s3c24x0/usb_ohci.c
cpu/arm920t/s3c24x0/usb_ohci.h
cpu/mpc5xxx/usb_ohci.c
cpu/mpc5xxx/usb_ohci.h
include/usb.h
include/usb_defs.h

index 4747592c7682a636abda01b1baee34de2922ab7b..3af861942863cc0c6a7b90638b7699c8fc3bf072 100644 (file)
@@ -448,11 +448,17 @@ int do_usb (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
        block_dev_desc_t *stor_dev;
 #endif
 
-       if ((strncmp(argv[1],"reset",5) == 0) ||
-                (strncmp(argv[1],"start",5) == 0)){
+       if ((strncmp(argv[1], "reset", 5) == 0) ||
+                (strncmp(argv[1], "start", 5) == 0)){
                usb_stop();
                printf("(Re)start USB...\n");
-               usb_init();
+               i = usb_init();
+#ifdef CONFIG_USB_STORAGE
+               /* try to recognize storage devices immediately */
+               if (i >= 0) 
+                       usb_stor_curr_dev = usb_stor_scan(1);
+               
+#endif
                return 0;
        }
        if (strncmp(argv[1],"stop",4) == 0) {
@@ -513,15 +519,18 @@ int do_usb (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
                return 0;
        }
 #ifdef CONFIG_USB_STORAGE
-       if (strncmp(argv[1],"scan",4) == 0) {
-               printf("Scan for storage device:\n");
-               usb_stor_curr_dev=usb_stor_scan(1);
-               if (usb_stor_curr_dev==-1) {
-                       printf("No device found. Not initialized?\n");
-                       return 1;
-               }
+       if (strncmp(argv[1], "scan", 4) == 0) {
+               printf("  NOTE: this command is obsolete and will be phased out\n");
+               printf("  please use 'usb storage' for USB storage devices information\n\n");
+               usb_stor_info();
                return 0;
        }
+
+       if (strncmp(argv[1], "stor", 4) == 0) {
+               usb_stor_info();
+               return 0;
+       }
+
        if (strncmp(argv[1],"part",4) == 0) {
                int devno, ok;
                for (ok=0, devno=0; devno<USB_MAX_STOR_DEV; ++devno) {
@@ -560,8 +569,8 @@ int do_usb (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
                        return 1;
                }
        }
-       if (strcmp(argv[1],"dev") == 0) {
-               if (argc==3) {
+       if (strncmp(argv[1], "dev", 3) == 0) {
+               if (argc == 3) {
                        int dev = (int)simple_strtoul(argv[2], NULL, 10);
                        printf ("\nUSB device %d: ", dev);
                        if (dev >= USB_MAX_STOR_DEV) {
@@ -608,7 +617,7 @@ U_BOOT_CMD(
        "usb stop [f]  - stop USB [f]=force stop\n"
        "usb tree  - show USB device tree\n"
        "usb info [dev] - show available USB devices\n"
-       "usb scan  - (re-)scan USB bus for storage devices\n"
+       "usb storage  - show details of USB storage devices\n"
        "usb dev [dev] - show or set current USB storage device\n"
        "usb part [dev] - print partition table of one or all USB storage devices\n"
        "usb read addr blk# cnt - read `cnt' blocks starting at block `blk#'\n"
index 4136f8d77656a6c2149ac38037b2afc88487b259..1738d950614154374b0a7a72fefe448a0d95920e 100644 (file)
@@ -37,6 +37,7 @@
 #include <common.h>
 #include <command.h>
 #include <asm/processor.h>
+#include <linux/ctype.h>
 
 #if (CONFIG_COMMANDS & CFG_CMD_USB)
 
@@ -46,7 +47,7 @@
 #endif
 
 
-/* #define USB_DEBUG */
+#undef USB_DEBUG 
 
 #ifdef USB_DEBUG
 #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);
 void usb_hub_reset(void);
 
+
 /***********************************************************************
  * 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 */
                return -1;
+
        /* set setup command */
        setup_packet.requesttype = requesttype;
        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 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 +341,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;
@@ -423,7 +424,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;
@@ -439,8 +440,6 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
            interface, NULL, 0, USB_CNTL_TIMEOUT * 5)) < 0)
                return ret;
 
-       if_face->act_altsetting = (unsigned char)alternate;
-       usb_set_maxpacket(dev);
        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)
 {
-       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.
@@ -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 */
        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;
@@ -550,22 +612,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);
 
-       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)
                return err;
+
        size--;         /* leave room for trailing NULL char in output buffer */
        for (idx = 0, u = 2; u < err; u += 2) {
                if (idx >= size)
@@ -641,11 +692,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) {
@@ -723,7 +829,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();
@@ -821,39 +927,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);
@@ -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) {
                        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);
@@ -873,10 +955,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);
        }
@@ -884,10 +968,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 */
index 605a1ceb9b55be0d388df82e749884be3bd61cd1..5397bb2bb49188e0702d88cd87169cc1b86e1483 100644 (file)
@@ -121,7 +121,7 @@ typedef struct {
 #define UMASS_BBB_CSW_SIZE     13
 
 #define USB_MAX_STOR_DEV 5
-static int usb_max_devs; /* number of highest available usb device */
+static int usb_max_devs = 0; /* number of highest available usb device */
 
 static block_dev_desc_t usb_dev_desc[USB_MAX_STOR_DEV];
 
@@ -177,7 +177,24 @@ void usb_show_progress(void)
 }
 
 /*********************************************************************************
- * (re)-scan the usb and reports device info
+ * show info on storage devices; 'usb start/init' must be invoked earlier
+ * as we only retrieve structures populated during devices initialization
+ */
+void usb_stor_info(void)
+{
+       int i;
+
+       if (usb_max_devs > 0)
+               for (i = 0; i < usb_max_devs; i++) {
+                       printf ("  Device %d: ", i);
+                       dev_print(&usb_dev_desc[i]);
+               }
+       else
+               printf("No storage devices, perhaps not 'usb start'ed..?\n");
+}
+
+/*********************************************************************************
+ * scan the usb and reports device info
  * to the user if mode = 1
  * returns current device or -1 if no
  */
@@ -190,7 +207,7 @@ int usb_stor_scan(int mode)
        memset(usb_stor_buf, 0, sizeof(usb_stor_buf));
 
        if(mode==1) {
-               printf("       scanning bus for storage devices...\n");
+               printf("       scanning bus for storage devices... ");
        }
        usb_disable_asynch(1); /* asynch transfer not allowed */
 
@@ -202,6 +219,7 @@ int usb_stor_scan(int mode)
                usb_dev_desc[i].part_type=PART_TYPE_UNKNOWN;
                usb_dev_desc[i].block_read=usb_stor_read;
        }
+
        usb_max_devs=0;
        for(i=0;i<USB_MAX_DEVICE;i++) {
                dev=usb_get_dev_index(i); /* get device */
@@ -211,21 +229,17 @@ int usb_stor_scan(int mode)
                }
                if(usb_storage_probe(dev,0,&usb_stor[usb_max_devs])) { /* ok, it is a storage devices */
                        /* get info and fill it in */
-
-                       if(usb_stor_get_info(dev, &usb_stor[usb_max_devs], &usb_dev_desc[usb_max_devs])) {
-                               if(mode==1) {
-                                       printf ("  Device %d: ", usb_max_devs);
-                                       dev_print(&usb_dev_desc[usb_max_devs]);
-                               } /* if mode */
+                       if(usb_stor_get_info(dev, &usb_stor[usb_max_devs], &usb_dev_desc[usb_max_devs])) 
                                usb_max_devs++;
-                       } /* if get info ok */
                } /* if storage device */
                if(usb_max_devs==USB_MAX_STOR_DEV) {
                        printf("max USB Storage Device reached: %d stopping\n",usb_max_devs);
                        break;
                }
        } /* for */
+       
        usb_disable_asynch(0); /* asynch transfer allowed */
+       printf("%d Storage Device(s) found\n", usb_max_devs);
        if(usb_max_devs>0)
                return 0;
        else
@@ -367,11 +381,13 @@ static int usb_stor_BBB_reset(struct us_data *us)
        result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
                                 US_BBB_RESET, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
                                 0, us->ifnum, 0, 0, USB_CNTL_TIMEOUT*5);
+
        if((result < 0) && (us->pusb_dev->status & USB_ST_STALLED))
        {
                USB_STOR_PRINTF("RESET:stall\n");
                return -1;
        }
+
        /* long wait for reset */
        wait_ms(150);
        USB_STOR_PRINTF("BBB_reset result %d: status %X reset\n",result,us->pusb_dev->status);
@@ -640,7 +656,9 @@ int usb_stor_BBB_transport(ccb *srb, struct us_data *us)
        retry = 0;
    again:
        USB_STOR_PRINTF("STATUS phase\n");
-       result = usb_bulk_msg(us->pusb_dev, pipein, &csw, UMASS_BBB_CSW_SIZE, &actlen, USB_CNTL_TIMEOUT*5);
+       result = usb_bulk_msg(us->pusb_dev, pipein, &csw, UMASS_BBB_CSW_SIZE, 
+                               &actlen, USB_CNTL_TIMEOUT*5);
+
        /* special handling of STALL in STATUS phase */
        if((result < 0) && (retry < 1) && (us->pusb_dev->status & USB_ST_STALLED)) {
                USB_STOR_PRINTF("STATUS:stall\n");
@@ -797,7 +815,7 @@ do_retry:
 static int usb_inquiry(ccb *srb,struct us_data *ss)
 {
        int retry,i;
-       retry=3;
+       retry=5;
        do {
                memset(&srb->cmd[0],0,12);
                srb->cmd[0]=SCSI_INQUIRY;
@@ -838,7 +856,7 @@ static int usb_request_sense(ccb *srb,struct us_data *ss)
 
 static int usb_test_unit_ready(ccb *srb,struct us_data *ss)
 {
-       int retries=10;
+       int retries = 10;
 
        do {
                memset(&srb->cmd[0],0,12);
@@ -859,7 +877,7 @@ static int usb_test_unit_ready(ccb *srb,struct us_data *ss)
 static int usb_read_capacity(ccb *srb,struct us_data *ss)
 {
        int retry;
-       retry=2; /* retries */
+       retry = 3; /* retries */
        do {
                memset(&srb->cmd[0],0,12);
                srb->cmd[0]=SCSI_RD_CAPAC;
@@ -972,9 +990,6 @@ int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,struct us_data
        int protocol = 0;
        int subclass = 0;
 
-
-       memset(ss, 0, sizeof(struct us_data));
-
        /* let's examine the device now */
        iface = &dev->config.if_desc[ifnum];
 
@@ -996,6 +1011,8 @@ int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,struct us_data
                return 0;
        }
 
+       memset(ss, 0, sizeof(struct us_data));
+
        /* At this point, we know we've got a live one */
        USB_STOR_PRINTF("\n\nUSB Mass Storage device detected\n");
 
@@ -1103,50 +1120,62 @@ int usb_stor_get_info(struct usb_device *dev,struct us_data *ss,block_dev_desc_t
        unsigned char perq,modi;
        unsigned long cap[2];
        unsigned long *capacity,*blksz;
-       ccb *pccb=&usb_ccb;
-
-       /* For some mysterious reason the 256MB flash disk of Ours Technology, Inc
-        * doesn't survive this reset */
-       if (dev->descriptor.idVendor != 0xea0 || dev->descriptor.idProduct != 0x6828)
+       ccb *pccb = &usb_ccb;
+
+       /* for some reasons a couple of devices would not survive this reset */
+       if (
+           /* Sony USM256E */
+           (dev->descriptor.idVendor == 0x054c &&
+            dev->descriptor.idProduct == 0x019e)
+
+           ||
+           /* USB007 Mini-USB2 Flash Drive */
+           (dev->descriptor.idVendor == 0x066f &&
+            dev->descriptor.idProduct == 0x2010)
+           )
+               USB_STOR_PRINTF("usb_stor_get_info: skipping RESET..\n");
+       else 
                ss->transport_reset(ss);
-       pccb->pdata=usb_stor_buf;
 
-       dev_desc->target=dev->devnum;
-       pccb->lun=dev_desc->lun;
+       pccb->pdata = usb_stor_buf;
+
+       dev_desc->target = dev->devnum;
+       pccb->lun = dev_desc->lun;
        USB_STOR_PRINTF(" address %d\n",dev_desc->target);
 
        if(usb_inquiry(pccb,ss))
                return -1;
-       perq=usb_stor_buf[0];
-       modi=usb_stor_buf[1];
-       if((perq & 0x1f)==0x1f) {
+               
+       perq = usb_stor_buf[0];
+       modi = usb_stor_buf[1];
+       if((perq & 0x1f) == 0x1f) {
                return 0; /* skip unknown devices */
        }
-       if((modi&0x80)==0x80) {/* drive is removable */
-               dev_desc->removable=1;
+       if((modi&0x80) == 0x80) {/* drive is removable */
+               dev_desc->removable = 1;
        }
        memcpy(&dev_desc->vendor[0], &usb_stor_buf[8], 8);
        memcpy(&dev_desc->product[0], &usb_stor_buf[16], 16);
        memcpy(&dev_desc->revision[0], &usb_stor_buf[32], 4);
-       dev_desc->vendor[8]=0;
-       dev_desc->product[16]=0;
-       dev_desc->revision[4]=0;
+       dev_desc->vendor[8] = 0;
+       dev_desc->product[16] = 0;
+       dev_desc->revision[4] = 0;
        USB_STOR_PRINTF("ISO Vers %X, Response Data %X\n",usb_stor_buf[2],usb_stor_buf[3]);
        if(usb_test_unit_ready(pccb,ss)) {
                printf("Device NOT ready\n   Request Sense returned %02X %02X %02X\n",pccb->sense_buf[2],pccb->sense_buf[12],pccb->sense_buf[13]);
-               if(dev_desc->removable==1) {
-                       dev_desc->type=perq;
+               if(dev_desc->removable == 1) {
+                       dev_desc->type = perq;
                        return 1;
                }
                else
                        return 0;
        }
-       pccb->pdata=(unsigned char *)&cap[0];
+       pccb->pdata = (unsigned char *)&cap[0];
        memset(pccb->pdata,0,8);
-       if(usb_read_capacity(pccb,ss)!=0) {
+       if(usb_read_capacity(pccb,ss) != 0) {
                printf("READ_CAP ERROR\n");
-               cap[0]=2880;
-               cap[1]=0x200;
+               cap[0] = 2880;
+               cap[1] = 0x200;
        }
        USB_STOR_PRINTF("Read Capacity returns: 0x%lx, 0x%lx\n",cap[0],cap[1]);
 #if 0
@@ -1166,13 +1195,13 @@ int usb_stor_get_info(struct usb_device *dev,struct us_data *ss,block_dev_desc_t
                (((unsigned long)(cap[1]) & (unsigned long)0xff000000UL) >> 24) ));
 #endif
        /* this assumes bigendian! */
-       cap[0]+=1;
-       capacity=&cap[0];
-       blksz=&cap[1];
+       cap[0] += 1;
+       capacity = &cap[0];
+       blksz = &cap[1];
        USB_STOR_PRINTF("Capacity = 0x%lx, blocksz = 0x%lx\n",*capacity,*blksz);
-       dev_desc->lba=*capacity;
-       dev_desc->blksz=*blksz;
-       dev_desc->type=perq;
+       dev_desc->lba = *capacity;
+       dev_desc->blksz = *blksz;
+       dev_desc->type = perq;
        USB_STOR_PRINTF(" address %d\n",dev_desc->target);
        USB_STOR_PRINTF("partype: %d\n",dev_desc->part_type);
 
index c5dac27680ea943b82532f24c436f461d4f6152b..fa6abeb546bc138d7a98d9ed213133d257543807 100644 (file)
@@ -94,6 +94,8 @@ urb_priv_t urb_priv;
 int got_rhsc;
 /* device which was disconnected */
 struct usb_device *devgone;
+/* flag guarding URB transation */
+int urb_finished = 0;
 
 /*-------------------------------------------------------------------------*/
 
@@ -398,6 +400,16 @@ int sohci_submit_job(struct usb_device *dev, unsigned long pipe, void *buffer,
                return -1;
        }
 
+       /* if we have an unfinished URB from previous transaction let's
+        * fail and scream as quickly as possible so as not to corrupt
+        * further communication */
+       if (!urb_finished) {
+               err("sohci_submit_job: URB NOT FINISHED");
+               return -1;
+       }
+       /* we're about to begin a new transaction here so mark the URB unfinished */
+       urb_finished = 0;
+
        /* every endpoint has a ed, locate and fill it */
        if (!(ed = ep_add_ed (dev, pipe))) {
                err("sohci_submit_job: ENOMEM");
@@ -658,7 +670,6 @@ static void td_fill (ohci_t *ohci, unsigned int info,
        else
                td->hwBE = 0;
        td->hwNextTD = m32_swap (td_pt);
-       td->hwPSW [0] = m16_swap (((__u32)data & 0x0FFF) | 0xE000);
 
        /* append to queue */
        td->ed->hwTailP = td->hwNextTD;
@@ -793,6 +804,7 @@ static td_t * dl_reverse_done_list (ohci_t *ohci)
                td_rev = td_list;
                td_list_hc = m32_swap (td_list->hwNextTD) & 0xfffffff0;
        }
+
        return td_list;
 }
 
@@ -826,6 +838,17 @@ static int dl_done_list (ohci_t *ohci, td_t *td_list)
                        stat = cc_to_error[cc];
                }
 
+               /* see if this done list makes for all TD's of current URB,
+                * and mark the URB finished if so */
+               if (++(lurb_priv->td_cnt) == lurb_priv->length) {
+                       if ((ed->state & (ED_OPER | ED_UNLINK)))
+                               urb_finished = 1;
+                       else
+                               dbg("dl_done_list: strange.., ED state %x, ed->state\n");
+               } else
+                       dbg("dl_done_list: processing TD %x, len %x\n", lurb_priv->td_cnt,
+                               lurb_priv->length);
+
                if (ed->state != ED_NEW) {
                        edHeadP = m32_swap (ed->hwHeadP) & 0xfffffff0;
                        edTailP = m32_swap (ed->hwTailP);
@@ -1197,6 +1220,8 @@ pkt_print(dev, pipe, buffer, transfer_len, cmd, "SUB(rh)", usb_pipein(pipe));
        return stat;
 }
 
+
+
 /*-------------------------------------------------------------------------*/
 
 /* common code for handling submit messages - used for all but root hub */
@@ -1245,22 +1270,41 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
        for (;;) {
                /* check whether the controller is done */
                stat = hc_interrupt();
+
                if (stat < 0) {
                        stat = USB_ST_CRC_ERR;
                        break;
                }
-               if (stat >= 0 && stat != 0xff) {
+
+               /* NOTE: since we are not interrupt driven in U-Boot and always
+                * handle only one URB at a time, we cannot assume the
+                * transaction finished on the first successful return from
+                * hc_interrupt().. unless the flag for current URB is set,
+                * meaning that all TD's to/from device got actually
+                * transferred and processed. If the current URB is not
+                * finished we need to re-iterate this loop so as
+                * hc_interrupt() gets called again as there needs to be some
+                * more TD's to process still */
+               if ((stat >= 0) && (stat != 0xff) && (urb_finished)) {
                        /* 0xff is returned for an SF-interrupt */
                        break;
                }
+
                if (--timeout) {
                        wait_ms(1);
+                       if (!urb_finished)
+                               dbg("\%");
+                       
                } else {
                        err("CTL:TIMEOUT ");
+                       dbg("submit_common_msg: TO status %x\n", stat);
                        stat = USB_ST_CRC_ERR;
+                       urb_finished = 1;
                        break;
                }
        }
+
+#if 0
        /* we got an Root Hub Status Change interrupt */
        if (got_rhsc) {
 #ifdef DEBUG
@@ -1282,6 +1326,7 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
                        devgone = dev;
                }
        }
+#endif
 
        dev->status = stat;
        dev->act_len = transfer_len;
@@ -1457,16 +1502,26 @@ hc_interrupt (void)
        int ints;
        int stat = -1;
 
-       if ((ohci->hcca->done_head != 0) && !(m32_swap (ohci->hcca->done_head) & 0x01)) {
+       if ((ohci->hcca->done_head != 0) &&
+            !(m32_swap (ohci->hcca->done_head) & 0x01)) {
+
                ints =  OHCI_INTR_WDH;
-       } else {
-               ints = readl (&regs->intrstatus);
+
+       } else if ((ints = readl (&regs->intrstatus)) == ~(u32)0) {
+               ohci->disabled++;
+               err ("%s device removed!", ohci->slot_name);
+               return -1;
+       
+       } else if ((ints &= readl (&regs->intrenable)) == 0) {
+               dbg("hc_interrupt: returning..\n");
+               return 0xff;
        }
 
        /* dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no)); */
 
        if (ints & OHCI_INTR_RHSC) {
                got_rhsc = 1;
+               stat = 0xff;
        }
 
        if (ints & OHCI_INTR_UE) {
@@ -1490,6 +1545,7 @@ hc_interrupt (void)
 
        if (ints & OHCI_INTR_WDH) {
                wait_ms(1);
+
                writel (OHCI_INTR_WDH, &regs->intrdisable);
                stat = dl_done_list (&gohci, dl_reverse_done_list (&gohci));
                writel (OHCI_INTR_WDH, &regs->intrenable);
@@ -1610,6 +1666,8 @@ int usb_lowlevel_init(void)
        wait_ms(1);
 #endif
        ohci_inited = 1;
+       urb_finished = 1;
+
        return 0;
 }
 
index fab0e65a381cdb5ac85bd2458bfcae4073a7fe47..5e9a0fdfc4e3e5a76b56c4bdeacc1c80877b593a 100644 (file)
@@ -30,7 +30,6 @@ static int cc_to_error[16] = {
 };
 
 /* ED States */
-
 #define ED_NEW                 0x00
 #define ED_UNLINK      0x01
 #define ED_OPER                0x02
@@ -104,7 +103,6 @@ struct td {
        __u32 hwNextTD;         /* Next TD Pointer */
        __u32 hwBE;             /* Memory Buffer End Pointer */
 
-       __u16 hwPSW[MAXPSW];
        __u8 unused;
        __u8 index;
        struct ed *ed;
index 880682620698c9219ffc250fe01475534dfd81d0..2f19d7e9220fa4cabd2c06978a552abcfca417a5 100644 (file)
@@ -98,6 +98,8 @@ urb_priv_t urb_priv;
 int got_rhsc;
 /* device which was disconnected */
 struct usb_device *devgone;
+/* flag guarding URB transation */
+int urb_finished = 0;
 
 /*-------------------------------------------------------------------------*/
 
@@ -402,6 +404,16 @@ int sohci_submit_job(struct usb_device *dev, unsigned long pipe, void *buffer,
                return -1;
        }
 
+       /* if we have an unfinished URB from previous transaction let's
+        * fail and scream as quickly as possible so as not to corrupt
+        * further communication */
+       if (!urb_finished) {
+               err("sohci_submit_job: URB NOT FINISHED");
+               return -1;
+       }
+       /* we're about to begin a new transaction here so mark the URB unfinished */
+       urb_finished = 0;
+
        /* every endpoint has a ed, locate and fill it */
        if (!(ed = ep_add_ed (dev, pipe))) {
                err("sohci_submit_job: ENOMEM");
@@ -664,7 +676,6 @@ static void td_fill (ohci_t *ohci, unsigned int info,
        else
                td->hwBE = 0;
        td->hwNextTD = ohci_cpu_to_le32 ((unsigned long)td_pt);
-       td->hwPSW [0] = ohci_cpu_to_le16 (((__u32)data & 0x0FFF) | 0xE000);
 
        /* append to queue */
        td->ed->hwTailP = td->hwNextTD;
@@ -673,7 +684,6 @@ static void td_fill (ohci_t *ohci, unsigned int info,
 /*-------------------------------------------------------------------------*/
 
 /* prepare all TDs of a transfer */
-
 static void td_submit_job (struct usb_device *dev, unsigned long pipe, void *buffer,
        int transfer_len, struct devrequest *setup, urb_priv_t *urb, int interval)
 {
@@ -813,7 +823,7 @@ static int dl_done_list (ohci_t *ohci, td_t *td_list)
        td_t *td_list_next = NULL;
        ed_t *ed;
        int cc = 0;
-       int stat = 0xff;
+       int stat = 0;
        /* urb_t *urb; */
        urb_priv_t *lurb_priv;
        __u32 tdINFO, edHeadP, edTailP;
@@ -835,6 +845,7 @@ static int dl_done_list (ohci_t *ohci, td_t *td_list)
                                        && (lurb_priv->state != URB_DEL)) {
                                dbg("ConditionCode %#x", cc);
                                stat = cc_to_error[cc];
+                               urb_finished = 1;
                        }
                }
 
@@ -1250,18 +1261,35 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
                        stat = USB_ST_CRC_ERR;
                        break;
                }
-               if (stat >= 0 && stat < 0xff) {
+               
+               /* NOTE: since we are not interrupt driven in U-Boot and always
+                * handle only one URB at a time, we cannot assume the
+                * transaction finished on the first successful return from
+                * hc_interrupt().. unless the flag for current URB is set,
+                * meaning that all TD's to/from device got actually
+                * transferred and processed. If the current URB is not
+                * finished we need to re-iterate this loop so as
+                * hc_interrupt() gets called again as there needs to be some
+                * more TD's to process still */
+               if ((stat >= 0) && (stat != 0xff) && (urb_finished)) {
                        /* 0xff is returned for an SF-interrupt */
                        break;
                }
+
                if (--timeout) {
                        wait_ms(1);
+                       if (!urb_finished)
+                               dbg("\%");
+
                } else {
                        err("CTL:TIMEOUT ");
+                       dbg("submit_common_msg: TO status %x\n", stat);
                        stat = USB_ST_CRC_ERR;
+                       urb_finished = 1;
                        break;
                }
        }
+#if 0
        /* we got an Root Hub Status Change interrupt */
        if (got_rhsc) {
 #ifdef DEBUG
@@ -1283,6 +1311,7 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
                        devgone = dev;
                }
        }
+#endif
 
        dev->status = stat;
        dev->act_len = transfer_len;
@@ -1454,17 +1483,27 @@ hc_interrupt (void)
        struct ohci_regs *regs = ohci->regs;
        int ints;
        int stat = -1;
+       
+       if ((ohci->hcca->done_head != 0) &&
+            !(ohci_cpu_to_le32(ohci->hcca->done_head) & 0x01)) {
 
-       if ((ohci->hcca->done_head != 0) && !(ohci_cpu_to_le32 (ohci->hcca->done_head) & 0x01)) {
-               ints =  OHCI_INTR_WDH;
-       } else {
-               ints = readl (&regs->intrstatus);
+               ints =  OHCI_INTR_WDH;
+
+       } else if ((ints = readl (&regs->intrstatus)) == ~(u32)0) {
+               ohci->disabled++;
+               err ("%s device removed!", ohci->slot_name);
+               return -1;
+       
+       } else if ((ints &= readl (&regs->intrenable)) == 0) {
+               dbg("hc_interrupt: returning..\n");
+               return 0xff;
        }
 
        /* dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no)); */
 
        if (ints & OHCI_INTR_RHSC) {
                got_rhsc = 1;
+               stat = 0xff;
        }
 
        if (ints & OHCI_INTR_UE) {
@@ -1499,6 +1538,7 @@ hc_interrupt (void)
        /* FIXME:  this assumes SOF (1/ms) interrupts don't get lost... */
        if (ints & OHCI_INTR_SF) {
                unsigned int frame = ohci_cpu_to_le16 (ohci->hcca->frame_no) & 1;
+               wait_ms(1);
                writel (OHCI_INTR_SF, &regs->intrdisable);
                if (ohci->ed_rm_list[frame] != NULL)
                        writel (OHCI_INTR_SF, &regs->intrenable);
@@ -1589,6 +1629,8 @@ int usb_lowlevel_init(void)
        ohci_dump (&gohci, 1);
 #endif
        ohci_inited = 1;
+       urb_finished = 1;
+
        return 0;
 }
 
index 11b361af0445971429e3157f6dc7696d0ce72986..884f1d5e519cf3266279b12de7708ab5c42ca4b9 100644 (file)
@@ -104,7 +104,6 @@ struct td {
        __u32 hwNextTD;         /* Next TD Pointer */
        __u32 hwBE;             /* Memory Buffer End Pointer */
 
-       __u16 hwPSW[MAXPSW];
        __u8 unused;
        __u8 index;
        struct ed *ed;
index 6940d3251095b0b05802f195f41cba70b3fdc3c7..39d7f23cc71d5e265129a561aeb626be06be02a7 100644 (file)
@@ -41,7 +41,6 @@
 
 #define USB_CNTL_TIMEOUT 100 /* 100ms timeout */
 
-
 /* String descriptor */
 struct usb_string_descriptor {
        unsigned char  bLength;
@@ -191,6 +190,7 @@ int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
 #define USB_MAX_STOR_DEV 5
 block_dev_desc_t *usb_stor_get_dev(int index);
 int usb_stor_scan(int mode);
+void usb_stor_info(void);
 
 #endif
 
index 33d1e46f2d86fbf5c9f0735636c21aeb8bce8ff4..353019fc1660f228f09b48c0fb1be41cb886a98a 100644 (file)
 #ifndef _USB_DEFS_H_
 #define _USB_DEFS_H_
 
-
-/* Everything is aribtrary */
-#define USB_ALTSETTINGALLOC          4
-#define USB_MAXALTSETTING                 128  /* Hard limit */
-
-#define USB_MAX_DEVICE              32
-#define USB_MAXCONFIG                      8
-#define USB_MAXINTERFACES                8
-#define USB_MAXENDPOINTS                 16
-#define USB_MAXCHILDREN                                                8       /* This is arbitrary */
-#define USB_MAX_HUB                                                                    16
-
-#define USB_CNTL_TIMEOUT 100 /* 100ms timeout */
-
 /* USB constants */
 
 /* Device and/or Interface Class codes */