diff options
| -rw-r--r-- | common/cmd_usb.c | 35 | ||||
| -rw-r--r-- | common/usb.c | 254 | ||||
| -rw-r--r-- | common/usb_storage.c | 117 | ||||
| -rw-r--r-- | cpu/arm920t/s3c24x0/usb_ohci.c | 68 | ||||
| -rw-r--r-- | cpu/arm920t/s3c24x0/usb_ohci.h | 2 | ||||
| -rw-r--r-- | cpu/mpc5xxx/usb_ohci.c | 58 | ||||
| -rw-r--r-- | cpu/mpc5xxx/usb_ohci.h | 1 | ||||
| -rw-r--r-- | include/usb.h | 2 | ||||
| -rw-r--r-- | include/usb_defs.h | 14 | 
9 files changed, 399 insertions, 152 deletions
| diff --git a/common/cmd_usb.c b/common/cmd_usb.c index 4747592c7..3af861942 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; ++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" diff --git a/common/usb.c b/common/usb.c index 4136f8d77..1738d9506 100644 --- a/common/usb.c +++ b/common/usb.c @@ -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 */ diff --git a/common/usb_storage.c b/common/usb_storage.c index 605a1ceb9..5397bb2bb 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;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; +	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) +	/* 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 c5dac2768..fa6abeb54 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 fab0e65a3..5e9a0fdfc 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 880682620..2f19d7e92 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 11b361af0..884f1d5e5 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 6940d3251..39d7f23cc 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 33d1e46f2..353019fc1 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 */ |