Commit 9c998aa8 authored by Wolfgang Denk's avatar Wolfgang Denk
Browse files

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.
parent f530187d
......@@ -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"
......
......@@ -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 */
......
......@@ -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);