From 9c998aa83148c75cd734a18958218926313bd54c Mon Sep 17 00:00:00 2001 From: Wolfgang Denk Date: Thu, 21 Jul 2005 11:57:57 +0200 Subject: Fix low-level OHCI transfers for ARM920t and MPC5xxx 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. diff --git a/common/cmd_usb.c b/common/cmd_usb.c index 4747592..3af8619 100644 --- a/common/cmd_usb.c +++ b/common/cmd_usb.c @@ -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) { @@ -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" diff --git a/common/usb.c b/common/usb.c index 4136f8d..1738d95 100644 --- a/common/usb.c +++ b/common/usb.c @@ -37,6 +37,7 @@ #include #include #include +#include #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; 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; @@ -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<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;triesstatus); - 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<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 */ diff --git a/common/usb_storage.c b/common/usb_storage.c index 605a1ce..5397bb2 100644 --- a/common/usb_storage.c +++ b/common/usb_storage.c @@ -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;i0) 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); diff --git a/cpu/arm920t/s3c24x0/usb_ohci.c b/cpu/arm920t/s3c24x0/usb_ohci.c index c5dac27..fa6abeb 100644 --- a/cpu/arm920t/s3c24x0/usb_ohci.c +++ b/cpu/arm920t/s3c24x0/usb_ohci.c @@ -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 (®s->intrstatus); + + } else if ((ints = readl (®s->intrstatus)) == ~(u32)0) { + ohci->disabled++; + err ("%s device removed!", ohci->slot_name); + return -1; + + } else if ((ints &= readl (®s->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, ®s->intrdisable); stat = dl_done_list (&gohci, dl_reverse_done_list (&gohci)); writel (OHCI_INTR_WDH, ®s->intrenable); @@ -1610,6 +1666,8 @@ int usb_lowlevel_init(void) wait_ms(1); #endif ohci_inited = 1; + urb_finished = 1; + return 0; } diff --git a/cpu/arm920t/s3c24x0/usb_ohci.h b/cpu/arm920t/s3c24x0/usb_ohci.h index fab0e65..5e9a0fd 100644 --- a/cpu/arm920t/s3c24x0/usb_ohci.h +++ b/cpu/arm920t/s3c24x0/usb_ohci.h @@ -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; diff --git a/cpu/mpc5xxx/usb_ohci.c b/cpu/mpc5xxx/usb_ohci.c index 8806826..2f19d7e 100644 --- a/cpu/mpc5xxx/usb_ohci.c +++ b/cpu/mpc5xxx/usb_ohci.c @@ -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 (®s->intrstatus); + ints = OHCI_INTR_WDH; + + } else if ((ints = readl (®s->intrstatus)) == ~(u32)0) { + ohci->disabled++; + err ("%s device removed!", ohci->slot_name); + return -1; + + } else if ((ints &= readl (®s->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, ®s->intrdisable); if (ohci->ed_rm_list[frame] != NULL) writel (OHCI_INTR_SF, ®s->intrenable); @@ -1589,6 +1629,8 @@ int usb_lowlevel_init(void) ohci_dump (&gohci, 1); #endif ohci_inited = 1; + urb_finished = 1; + return 0; } diff --git a/cpu/mpc5xxx/usb_ohci.h b/cpu/mpc5xxx/usb_ohci.h index 11b361a..884f1d5 100644 --- a/cpu/mpc5xxx/usb_ohci.h +++ b/cpu/mpc5xxx/usb_ohci.h @@ -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; diff --git a/include/usb.h b/include/usb.h index 6940d32..39d7f23 100644 --- a/include/usb.h +++ b/include/usb.h @@ -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 diff --git a/include/usb_defs.h b/include/usb_defs.h index 33d1e46..353019f 100644 --- a/include/usb_defs.h +++ b/include/usb_defs.h @@ -26,20 +26,6 @@ #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 */ -- cgit v0.10.2