diff options
| author | wdenk <wdenk> | 2003-09-10 18:20:28 +0000 | 
|---|---|---|
| committer | wdenk <wdenk> | 2003-09-10 18:20:28 +0000 | 
| commit | 149dded2b178bc0fb62cb6f61b87968d914b580a (patch) | |
| tree | 6322023840b11a7210e3030262dc5e6ee42953f0 | |
| parent | 7152b1d0b3f8beec8c297d64664e41b4c4ef610a (diff) | |
| download | olio-uboot-2014.01-149dded2b178bc0fb62cb6f61b87968d914b580a.tar.xz olio-uboot-2014.01-149dded2b178bc0fb62cb6f61b87968d914b580a.zip | |
* Add support for USB Mass Storage Devices (BBB)
  (tested with USB memory sticks only)
* Avoid flicker on TRAB's VFD
35 files changed, 2532 insertions, 57 deletions
| @@ -1,7 +1,12 @@  ====================================================================== -Changes for U-Boot 0.4.7: +Changes for U-Boot 0.4.8:  ====================================================================== +* Add support for USB Mass Storage Devices (BBB) +  (tested with USB memory sticks only) + +* Avoid flicker on TRAB's VFD +  * Add support for SK98xx driver  * Add PCI support for SL8245 board @@ -27,6 +32,10 @@ Changes for U-Boot 0.4.7:  * Patch by Yuli Barcohen, 7 Aug 2003:    check BCSR to detect if the board is configured in PCI mode +====================================================================== +Changes for U-Boot 0.4.7: +====================================================================== +  * Patch by Raghu Krishnaprasad, 7 Aug 2003:    add support for Adder II MPC852T module @@ -263,7 +272,7 @@ Changes for U-Boot 0.4.1:    - PIC on LWMON board needs delay after power-on    - Add missing RSR definitions for MPC8xx    - Improve log buffer handling: guarantee clean reset after power-on -  - Add support for EXBITGEN board +  - Add support for EXBITGEN board (aka "genie")    - Add support for SL8245 board  * Code cleanup: diff --git a/MAINTAINERS b/MAINTAINERS index 2e748efbe..20e68a831 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -89,6 +89,7 @@ Wolfgang Denk <wd@denx.de>  	TQM8255			MPC8255  	CPU86			MPC8260 +	PM825			MPC8250  	PM826			MPC8260  	TQM8260			MPC8260 diff --git a/board/mpc8260ads/mpc8260ads.c b/board/mpc8260ads/mpc8260ads.c index 98ae66005..14a93be09 100644 --- a/board/mpc8260ads/mpc8260ads.c +++ b/board/mpc8260ads/mpc8260ads.c @@ -238,7 +238,9 @@ int board_pre_init (void)  long int initdram (int board_type)  { +#if CONFIG_ADSTYPE == CFG_PQ2FADS  	vu_long *bcsr = (vu_long *)CFG_BCSR; +#endif  	volatile immap_t *immap = (immap_t *) CFG_IMMR;  	volatile memctl8260_t *memctl = &immap->im_memctl;  	volatile uchar *ramaddr, c = 0xff; diff --git a/board/trab/trab.c b/board/trab/trab.c index 029fbde8c..71b3cbe11 100644 --- a/board/trab/trab.c +++ b/board/trab/trab.c @@ -105,6 +105,10 @@ int board_init ()  	gpio->PGUP  = 0x0;  	gpio->OPENCR= 0x0; +	/* suppress flicker of the VFDs */ +	gpio->MISCCR = 0x40; +	gpio->PFCON |= (2<<12); +  	/* arch number of SAMSUNG-Board */  	/* MACH_TYPE_SMDK2400 */  	/* XXX this isn't really correct, but keep it for now */ diff --git a/common/cmd_nand.c b/common/cmd_nand.c index ce7b5ff02..60cdd8eb4 100644 --- a/common/cmd_nand.c +++ b/common/cmd_nand.c @@ -38,7 +38,7 @@ struct nand_oob_config {  	int eccvalid_pos;	/* position of ECC valid flag inside oob -1 = inactive */  } oob_config = { {0}, 0, 0}; -#undef	NAND_DEBUG +#define	NAND_DEBUG  #undef	PSYCHO_DEBUG  /* ****************** WARNING ********************* diff --git a/common/usb_storage.c b/common/usb_storage.c index a7944b573..70890361b 100644 --- a/common/usb_storage.c +++ b/common/usb_storage.c @@ -2,8 +2,12 @@   * (C) Copyright 2001   * Denis Peter, MPL AG Switzerland   * + * For BBB support (C) Copyright 2003 + * Gary Jennejohn, DENX Software Engineering <gj@denx.de> + *   * Most of this source has been derived from the Linux USB - * project. + * project. BBB support based on /sys/dev/usb/umass.c from + * FreeBSD.   *   * See file CREDITS for list of people who contributed to this   * project. @@ -30,6 +34,13 @@   * is only tested with a TEAC USB Floppy. Other Massstorages with CBI or CB   * transport protocoll may work as well.   */ +/* + * New Note: + * Support for USB Mass Storage Devices (BBB) has been added. It has + * only been tested with USB memory sticks. + * Nota bene: if you are using the BBB support with a little-endian + * CPU then you MUST define LITTLEENDIAN in the configuration file! + */  #include <common.h> @@ -71,6 +82,41 @@ static ccb usb_ccb;  #define US_CBI_ADSC		0 +/* + * BULK only + */ +#define US_BBB_RESET		0xff +#define US_BBB_GET_MAX_LUN	0xfe + +/* Command Block Wrapper */ +typedef struct { +	__u32		dCBWSignature; +#	define CBWSIGNATURE	0x43425355 +	__u32		dCBWTag; +	__u32		dCBWDataTransferLength; +	__u8		bCBWFlags; +#	define CBWFLAGS_OUT	0x00 +#	define CBWFLAGS_IN	0x80 +	__u8		bCBWLUN; +	__u8		bCDBLength; +#	define CBWCDBLENGTH	16 +	__u8		CBWCDB[CBWCDBLENGTH]; +} umass_bbb_cbw_t; +#define	UMASS_BBB_CBW_SIZE	31 +static __u32 CBWTag = 0; + +/* Command Status Wrapper */ +typedef struct { +	__u32		dCSWSignature; +#	define CSWSIGNATURE	0x53425355 +	__u32		dCSWTag; +	__u32		dCSWDataResidue; +	__u8		bCSWStatus; +#	define CSWSTATUS_GOOD	0x0 +#	define CSWSTATUS_FAILED	0x1 +#	define CSWSTATUS_PHASE	0x2 +} umass_bbb_csw_t; +#define	UMASS_BBB_CSW_SIZE	13  #define USB_MAX_STOR_DEV 5  static int usb_max_devs; /* number of highest available usb device */ @@ -138,6 +184,9 @@ int usb_stor_scan(int mode)  	unsigned char i;  	struct usb_device *dev; +	/* GJ */ +	memset(usb_stor_buf, 0, sizeof(usb_stor_buf)); +  	if(mode==1) {  		printf("scanning bus for storage devices...\n");  	} @@ -293,6 +342,51 @@ static int us_one_transfer(struct us_data *us, int pipe, char *buf, int length)  	return 0;  } +static int usb_stor_BBB_reset(struct us_data *us) +{ +	int result; +	unsigned int pipe; + +	/* +	 * Reset recovery (5.3.4 in Universal Serial Bus Mass Storage Class) +	 * +	 * For Reset Recovery the host shall issue in the following order: +	 * a) a Bulk-Only Mass Storage Reset +	 * b) a Clear Feature HALT to the Bulk-In endpoint +	 * c) a Clear Feature HALT to the Bulk-Out endpoint +	 * +	 * This is done in 3 steps. +	 * +	 * If the reset doesn't succeed, the device should be port reset. +	 * +	 * This comment stolen from FreeBSD's /sys/dev/usb/umass.c. +	 */ +	USB_STOR_PRINTF("BBB_reset\n"); +	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); +	pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); +	result = usb_clear_halt(us->pusb_dev, pipe); +	/* long wait for reset */ +	wait_ms(150); +	USB_STOR_PRINTF("BBB_reset result %d: status %X clearing IN endpoint\n",result,us->pusb_dev->status); +	/* long wait for reset */ +	pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); +	result = usb_clear_halt(us->pusb_dev, pipe); +	wait_ms(150); +	USB_STOR_PRINTF("BBB_reset result %d: status %X clearing OUT endpoint\n",result,us->pusb_dev->status); +	USB_STOR_PRINTF("BBB_reset done\n"); +	return 0; +} +  /* FIXME: this reset function doesn't really reset the port, and it   * should. Actually it should probably do what it's doing here, and   * reset the port physically @@ -320,6 +414,52 @@ static int usb_stor_CB_reset(struct us_data *us)  	return 0;  } +/* + * Set up the command for a BBB device. Note that the actual SCSI + * command is copied into cbw.CBWCDB. + */ +int usb_stor_BBB_comdat(ccb *srb, struct us_data *us) +{ +	int result; +	int actlen; +	int dir_in; +	unsigned int pipe; +	umass_bbb_cbw_t cbw; + +	dir_in = US_DIRECTION(srb->cmd[0]); + +#ifdef BBB_COMDAT_TRACE +	printf("dir %d lun %d cmdlen %d cmd %p datalen %d pdata %p\n", dir_in, srb->lun, srb->cmdlen, srb->cmd, srb->datalen, srb->pdata); +	if (srb->cmdlen) { +		for(result = 0;result < srb->cmdlen;result++) +			printf("cmd[%d] %#x ", result, srb->cmd[result]); +		printf("\n"); +	} +#endif +	/* sanity checks */ +	if (!(srb->cmdlen <= CBWCDBLENGTH)) { +		USB_STOR_PRINTF("usb_stor_BBB_comdat:cmdlen too large\n"); +		return -1; +	} + +	/* always OUT to the ep */ +	pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); + +	cbw.dCBWSignature = swap_32(CBWSIGNATURE); +	cbw.dCBWTag = swap_32(CBWTag++); +	cbw.dCBWDataTransferLength = swap_32(srb->datalen); +	cbw.bCBWFlags = (dir_in? CBWFLAGS_IN : CBWFLAGS_OUT); +	cbw.bCBWLUN = srb->lun; +	cbw.bCDBLength = srb->cmdlen; +	/* copy the command data into the CBW command data buffer */ +	/* DST SRC LEN!!! */ +	memcpy(cbw.CBWCDB, srb->cmd, srb->cmdlen); +	result = usb_bulk_msg(us->pusb_dev, pipe, &cbw, UMASS_BBB_CBW_SIZE, &actlen, USB_CNTL_TIMEOUT*5); +	if (result < 0) +		USB_STOR_PRINTF("usb_stor_BBB_comdat:usb_bulk_msg error\n"); +	return result; +} +  /* FIXME: we also need a CBI_command which sets up the completion   * interrupt, and waits for it   */ @@ -422,6 +562,134 @@ int usb_stor_CBI_get_status(ccb *srb, struct us_data *us)  #define USB_TRANSPORT_UNKNOWN_RETRY 5  #define USB_TRANSPORT_NOT_READY_RETRY 10 +/* clear a stall on an endpoint - special for BBB devices */ +int usb_stor_BBB_clear_endpt_stall(struct us_data *us, __u8 endpt) +{ +	int result; + +	/* ENDPOINT_HALT = 0, so set value to 0 */ +	result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), +				USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, +				0, endpt, 0, 0, USB_CNTL_TIMEOUT*5); +	return result; +} + +int usb_stor_BBB_transport(ccb *srb, struct us_data *us) +{ +	int result, retry; +	int dir_in; +	int actlen, data_actlen; +	unsigned int pipe, pipein, pipeout; +	umass_bbb_csw_t csw; +#ifdef BBB_XPORT_TRACE +	unsigned char *ptr; +	int index; +#endif + +	dir_in = US_DIRECTION(srb->cmd[0]); + +	/* COMMAND phase */ +	USB_STOR_PRINTF("COMMAND phase\n"); +	result = usb_stor_BBB_comdat(srb, us); +	if (result < 0) { +		USB_STOR_PRINTF("failed to send CBW status %ld\n", +			us->pusb_dev->status); +		usb_stor_BBB_reset(us); +		return USB_STOR_TRANSPORT_FAILED; +	} +	wait_ms(5); +	pipein = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); +	pipeout = usb_sndbulkpipe(us->pusb_dev, us->ep_out); +	/* DATA phase + error handling */ +	USB_STOR_PRINTF("DATA phase\n"); +	data_actlen = 0; +	/* no data, go immediately to the STATUS phase */ +	if (srb->datalen == 0) +		goto st; +	if (dir_in) +		pipe = pipein; +	else +		pipe = pipeout; +	result = usb_bulk_msg(us->pusb_dev, pipe, srb->pdata, srb->datalen, &data_actlen, USB_CNTL_TIMEOUT*5); +	/* special handling of STALL in DATA phase */ +	if((result < 0) && (us->pusb_dev->status & USB_ST_STALLED)) { +		printf("DATA:stall\n"); +		/* clear the STALL on the endpoint */ +		result = usb_stor_BBB_clear_endpt_stall(us, dir_in? us->ep_in : us->ep_out); +		if (result >= 0) +			/* continue on to STATUS phase */ +			goto st; +	} +	if (result < 0) { +		USB_STOR_PRINTF("usb_bulk_msg error status %ld\n", +			us->pusb_dev->status); +		usb_stor_BBB_reset(us); +		return USB_STOR_TRANSPORT_FAILED; +	} +#ifdef BBB_XPORT_TRACE +	for (index = 0; index < data_actlen; index++) +		printf("pdata[%d] %#x ", index, srb->pdata[index]); +	printf("\n"); +#endif +	/* STATUS phase + error handling */ +   st: +	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); +	/* 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"); +		/* clear the STALL on the endpoint */ +		result = usb_stor_BBB_clear_endpt_stall(us, us->ep_in); +		if (result >= 0 && (retry++ < 1)) +			/* do a retry */ +			goto again; +	} +	if (result < 0) { +		USB_STOR_PRINTF("usb_bulk_msg error status %ld\n", +			us->pusb_dev->status); +		usb_stor_BBB_reset(us); +		return USB_STOR_TRANSPORT_FAILED; +	} +#ifdef BBB_XPORT_TRACE +	ptr = (unsigned char *)&csw; +	for (index = 0; index < UMASS_BBB_CSW_SIZE; index++) +		printf("ptr[%d] %#x ", index, ptr[index]); +	printf("\n"); +#endif +	/* misuse pipe to get the residue */ +	pipe = swap_32(csw.dCSWDataResidue); +	if (pipe == 0 && srb->datalen != 0 && srb->datalen - data_actlen != 0) +		pipe = srb->datalen - data_actlen; +	if (CSWSIGNATURE != swap_32(csw.dCSWSignature)) { +		USB_STOR_PRINTF("!CSWSIGNATURE\n"); +		usb_stor_BBB_reset(us); +		return USB_STOR_TRANSPORT_FAILED; +	} else if ((CBWTag - 1) != swap_32(csw.dCSWTag)) { +		USB_STOR_PRINTF("!Tag\n"); +		usb_stor_BBB_reset(us); +		return USB_STOR_TRANSPORT_FAILED; +	} else if (csw.bCSWStatus > CSWSTATUS_PHASE) { +		USB_STOR_PRINTF(">PHASE\n"); +		usb_stor_BBB_reset(us); +		return USB_STOR_TRANSPORT_FAILED; +	} else if (csw.bCSWStatus == CSWSTATUS_PHASE) { +		USB_STOR_PRINTF("=PHASE\n"); +		usb_stor_BBB_reset(us); +		return USB_STOR_TRANSPORT_FAILED; +	} else if (data_actlen > srb->datalen) { +		USB_STOR_PRINTF("transferred %dB instead of %dB\n", +			data_actlen, srb->datalen); +		return USB_STOR_TRANSPORT_FAILED; +	} else if (csw.bCSWStatus == CSWSTATUS_FAILED) { +		USB_STOR_PRINTF("FAILED\n"); +		return USB_STOR_TRANSPORT_FAILED; +	} + +	return result; +} +  int usb_stor_CB_transport(ccb *srb, struct us_data *us)  {  	int result,status; @@ -495,29 +763,28 @@ do_retry:  		return USB_STOR_TRANSPORT_GOOD;  	/* Check the auto request result */  	switch(srb->sense_buf[2]) { -		case 0x01: /* Recovered Error */ -			return USB_STOR_TRANSPORT_GOOD; -		 	break; -		case 0x02: /* Not Ready */ -			if(notready++ > USB_TRANSPORT_NOT_READY_RETRY) { -				printf("cmd 0x%02X returned 0x%02X 0x%02X 0x%02X 0x%02X (NOT READY)\n", -					srb->cmd[0],srb->sense_buf[0],srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]); -				return USB_STOR_TRANSPORT_FAILED; -			} -			else { -				wait_ms(100); -				goto do_retry; -			} -			break; -		default: -			if(retry++ > USB_TRANSPORT_UNKNOWN_RETRY) { -				printf("cmd 0x%02X returned 0x%02X 0x%02X 0x%02X 0x%02X\n", -					srb->cmd[0],srb->sense_buf[0],srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]); -				return USB_STOR_TRANSPORT_FAILED; -			} -			else -				goto do_retry; -			break; +	case 0x01: /* Recovered Error */ +		return USB_STOR_TRANSPORT_GOOD; +	 	break; +	case 0x02: /* Not Ready */ +		if(notready++ > USB_TRANSPORT_NOT_READY_RETRY) { +			printf("cmd 0x%02X returned 0x%02X 0x%02X 0x%02X 0x%02X (NOT READY)\n", +				srb->cmd[0],srb->sense_buf[0],srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]); +			return USB_STOR_TRANSPORT_FAILED; +		} else { +			wait_ms(100); +			goto do_retry; +		} +		break; +	default: +		if(retry++ > USB_TRANSPORT_UNKNOWN_RETRY) { +			printf("cmd 0x%02X returned 0x%02X 0x%02X 0x%02X 0x%02X\n", +				srb->cmd[0],srb->sense_buf[0],srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]); +			return USB_STOR_TRANSPORT_FAILED; +		} else { +			goto do_retry; +		} +		break;  	}  	return USB_STOR_TRANSPORT_FAILED;  } @@ -538,7 +805,8 @@ static int usb_inquiry(ccb *srb,struct us_data *ss)  		USB_STOR_PRINTF("inquiry returns %d\n",i);  		if(i==0)  			break; -	}while(retry--); +	} while(retry--); +  	if(!retry) {  		printf("error in inquiry\n");  		return -1; @@ -567,17 +835,18 @@ 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; +  	do {  		memset(&srb->cmd[0],0,12);  		srb->cmd[0]=SCSI_TST_U_RDY;  		srb->cmd[1]=srb->lun<<5;  		srb->datalen=0;  		srb->cmdlen=12; -		if(ss->transport(srb,ss)==USB_STOR_TRANSPORT_GOOD) -		{ +		if(ss->transport(srb,ss)==USB_STOR_TRANSPORT_GOOD) {  			return 0;  		}  	} while(retries--); +  	return -1;  } @@ -594,7 +863,8 @@ static int usb_read_capacity(ccb *srb,struct us_data *ss)  		if(ss->transport(srb,ss)==USB_STOR_TRANSPORT_GOOD) {  			return 0;  		} -	}while(retry--); +	} while(retry--); +  	return -1;  } @@ -654,8 +924,7 @@ unsigned long usb_stor_read(int device, unsigned long blknr, unsigned long blkcn  		srb->pdata=(unsigned char *)buf_addr;  		if(blks>USB_MAX_READ_BLK) {  			smallblks=USB_MAX_READ_BLK; -		} -		else { +		} else {  			smallblks=(unsigned short) blks;  		}  retry_it: @@ -751,6 +1020,11 @@ int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,struct us_data  		ss->transport = usb_stor_CB_transport;  		ss->transport_reset = usb_stor_CB_reset;  		break; +	case US_PR_BULK: +		USB_STOR_PRINTF("Bulk/Bulk/Bulk\n"); +		ss->transport = usb_stor_BBB_transport; +		ss->transport_reset = usb_stor_BBB_reset; +		break;  	default:  		printf("USB Starage Transport unknown / not yet implemented\n");  		return 0; @@ -793,15 +1067,14 @@ int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,struct us_data  		return 0;  	}  	/* set class specific stuff */ -	/* We only handle certain protocols.  Currently, this is -	 * the only one. +	/* We only handle certain protocols.  Currently, these are +	 * the only ones.  	 */ -	if (ss->subclass != US_SC_UFI) { +	if (ss->subclass != US_SC_UFI && ss->subclass != US_SC_SCSI) {  		printf("Sorry, protocol %d not yet supported.\n",ss->subclass);  		return 0;  	} -	if(ss->ep_int) /* we had found an interrupt endpoint, prepare irq pipe */ -	{ +	if(ss->ep_int) { /* we had found an interrupt endpoint, prepare irq pipe */  		/* set up the IRQ pipe and handler */  		ss->irqinterval = (ss->irqinterval > 0) ? ss->irqinterval : 255; @@ -865,6 +1138,19 @@ int usb_stor_get_info(struct usb_device *dev,struct us_data *ss,block_dev_desc_t  	if(cap[0]>(0x200000 * 10)) /* greater than 10 GByte */  		cap[0]>>=16;  #endif +#ifdef LITTLEENDIAN +	cap[0] = ((unsigned long)( +		(((unsigned long)(cap[0]) & (unsigned long)0x000000ffUL) << 24) | +		(((unsigned long)(cap[0]) & (unsigned long)0x0000ff00UL) <<  8) | +		(((unsigned long)(cap[0]) & (unsigned long)0x00ff0000UL) >>  8) | +		(((unsigned long)(cap[0]) & (unsigned long)0xff000000UL) >> 24) )); +	cap[1] = ((unsigned long)( +		(((unsigned long)(cap[1]) & (unsigned long)0x000000ffUL) << 24) | +		(((unsigned long)(cap[1]) & (unsigned long)0x0000ff00UL) <<  8) | +		(((unsigned long)(cap[1]) & (unsigned long)0x00ff0000UL) >>  8) | +		(((unsigned long)(cap[1]) & (unsigned long)0xff000000UL) >> 24) )); +#endif +	/* this assumes bigendian! */  	cap[0]+=1;  	capacity=&cap[0];  	blksz=&cap[1]; @@ -881,5 +1167,5 @@ int usb_stor_get_info(struct usb_device *dev,struct us_data *ss,block_dev_desc_t  	return 1;  } -#endif  #endif /* CONFIG_USB_STORAGE */ +#endif /* CFG_CMD_USB */ diff --git a/cpu/arm920t/Makefile b/cpu/arm920t/Makefile index e5ec81d95..605adf301 100644 --- a/cpu/arm920t/Makefile +++ b/cpu/arm920t/Makefile @@ -26,7 +26,7 @@ include $(TOPDIR)/config.mk  LIB	= lib$(CPU).a  START	= start.o -OBJS	= serial.o interrupts.o cpu.o speed.o +OBJS	= serial.o interrupts.o cpu.o speed.o usb_ohci.o  all:	.depend $(START) $(LIB) diff --git a/cpu/arm920t/usb_ohci.c b/cpu/arm920t/usb_ohci.c new file mode 100644 index 000000000..41ba233c4 --- /dev/null +++ b/cpu/arm920t/usb_ohci.c @@ -0,0 +1,1553 @@ +/* + * URB OHCI HCD (Host Controller Driver) for USB on the S3C2400. + * + * (C) Copyright 2003 + * Gary Jennejohn, DENX Software Engineering <gj@denx.de> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Note: Part of this code has been derived from linux + * + */ +/* + * IMPORTANT NOTES + * 1 - you MUST define LITTLEENDIAN in the configuration file for the + *     board or this driver will NOT work! + * 2 - this driver is intended for use with USB Mass Storage Devices + *     (BBB) ONLY. There is NO support for Interrupt or Isochronous pipes! + */ + +#include <common.h> +/* #include <pci.h> no PCI on the S3C2400 */ + +#ifdef CONFIG_USB_OHCI + +#include <s3c2400.h> +#include <malloc.h> +#include <usb.h> +#include "usb_ohci.h" + +#define OHCI_USE_NPS		/* force NoPowerSwitching mode */ +#undef OHCI_VERBOSE_DEBUG	/* not always helpful */ + + +/* For initializing controller (mask in an HCFS mode too) */ +#define	OHCI_CONTROL_INIT \ +	(OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE + +#define OHCI_UNLINK_TIMEOUT	(CFG_HZ / 10) + +#define readl(a) (*((vu_long *)(a))) +#define writel(a, b) (*((vu_long *)(b)) = ((vu_long)a)) + +#define min_t(type,x,y) ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; }) + +#undef DEBUG +#ifdef DEBUG +#define dbg(format, arg...) printf("DEBUG: " format "\n", ## arg) +#else +#define dbg(format, arg...) do {} while(0) +#endif /* DEBUG */ +#define err(format, arg...) printf("ERROR: " format "\n", ## arg) +#undef SHOW_INFO +#ifdef SHOW_INFO +#define info(format, arg...) printf("INFO: " format "\n", ## arg) +#else +#define info(format, arg...) do {} while(0) +#endif + +#define m16_swap(x) swap_16(x) +#define m32_swap(x) swap_32(x) + +/* global ohci_t */ +static ohci_t gohci; +/* this must be aligned to a 256 byte boundary */ +struct ohci_hcca ghcca[1]; +/* a pointer to the aligned storage */ +struct ohci_hcca *phcca; +/* this allocates EDs for all possible endpoints */ +struct ohci_device ohci_dev; +/* urb_priv */ +urb_priv_t urb_priv; + +/*-------------------------------------------------------------------------*/ + +/* AMD-756 (D2 rev) reports corrupt register contents in some cases. + * The erratum (#4) description is incorrect.  AMD's workaround waits + * till some bits (mostly reserved) are clear; ok for all revs. + */ +#define OHCI_QUIRK_AMD756 0xabcd +#define read_roothub(hc, register, mask) ({ \ +	u32 temp = readl (&hc->regs->roothub.register); \ +	if (hc->flags & OHCI_QUIRK_AMD756) \ +		while (temp & mask) \ +			temp = readl (&hc->regs->roothub.register); \ +	temp; }) + +static u32 roothub_a (struct ohci *hc) +	{ return read_roothub (hc, a, 0xfc0fe000); } +static inline u32 roothub_b (struct ohci *hc) +	{ return readl (&hc->regs->roothub.b); } +static inline u32 roothub_status (struct ohci *hc) +	{ return readl (&hc->regs->roothub.status); } +static u32 roothub_portstatus (struct ohci *hc, int i) +	{ return read_roothub (hc, portstatus [i], 0xffe0fce0); } + + +/* forward declaration */ +static int hc_interrupt (void); +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); + +/*-------------------------------------------------------------------------* + * URB support functions + *-------------------------------------------------------------------------*/ + +/* free HCD-private data associated with this URB */ + +static void urb_free_priv (urb_priv_t * urb) +{ +	int		i; +	int		last; +	struct td	* td; + +	last = urb->length - 1; +	if (last >= 0) { +		for (i = 0; i <= last; i++) { +			td = urb->td[i]; +			if (td) { +				td->usb_dev = NULL; +				urb->td[i] = NULL; +			} +		} +	} +} + +/*-------------------------------------------------------------------------*/ + +#ifdef DEBUG +static int sohci_get_current_frame_number (struct usb_device * dev); + +/* debug| print the main components of an URB + * small: 0) header + data packets 1) just header */ + +static void pkt_print (struct usb_device * dev, unsigned long pipe, void * buffer, +	int transfer_len, struct devrequest * setup, char * str, int small) +{ +	urb_priv_t * purb = &urb_priv; + +	dbg("%s URB:[%4x] dev:%2d,ep:%2d-%c,type:%s,len:%d/%d stat:%#lx", +			str, +		 	sohci_get_current_frame_number (dev), +		 	usb_pipedevice (pipe), +		 	usb_pipeendpoint (pipe), +		 	usb_pipeout (pipe)? 'O': 'I', +		 	usb_pipetype (pipe) < 2? (usb_pipeint (pipe)? "INTR": "ISOC"): +		 		(usb_pipecontrol (pipe)? "CTRL": "BULK"), +		 	purb->actual_length, +		 	transfer_len, dev->status); +#ifdef	OHCI_VERBOSE_DEBUG +	if (!small) { +		int i, len; + +		if (usb_pipecontrol (pipe)) { +			printf (__FILE__ ": cmd(8):"); +			for (i = 0; i < 8 ; i++) +				printf (" %02x", ((__u8 *) setup) [i]); +			printf ("\n"); +		} +		if (transfer_len > 0 && buffer) { +			printf (__FILE__ ": data(%d/%d):", +				purb->actual_length, +				transfer_len); +			len = usb_pipeout (pipe)? +					transfer_len: purb->actual_length; +			for (i = 0; i < 16 && i < len; i++) +				printf (" %02x", ((__u8 *) buffer) [i]); +			printf ("%s\n", i < len? "...": ""); +		} +	} +#endif +} + +/* just for debugging; prints non-empty branches of the int ed tree inclusive iso eds*/ +void ep_print_int_eds (ohci_t *ohci, char * str) { +	int i, j; +	 __u32 * ed_p; +	for (i= 0; i < 32; i++) { +		j = 5; +		ed_p = &(ohci->hcca->int_table [i]); +		if (*ed_p == 0) +		    continue; +		printf (__FILE__ ": %s branch int %2d(%2x):", str, i, i); +		while (*ed_p != 0 && j--) { +			ed_t *ed = (ed_t *)m32_swap(ed_p); +			printf (" ed: %4x;", ed->hwINFO); +			ed_p = &ed->hwNextED; +		} +		printf ("\n"); +	} +} + +static void ohci_dump_intr_mask (char *label, __u32 mask) +{ +	dbg ("%s: 0x%08x%s%s%s%s%s%s%s%s%s", +		label, +		mask, +		(mask & OHCI_INTR_MIE) ? " MIE" : "", +		(mask & OHCI_INTR_OC) ? " OC" : "", +		(mask & OHCI_INTR_RHSC) ? " RHSC" : "", +		(mask & OHCI_INTR_FNO) ? " FNO" : "", +		(mask & OHCI_INTR_UE) ? " UE" : "", +		(mask & OHCI_INTR_RD) ? " RD" : "", +		(mask & OHCI_INTR_SF) ? " SF" : "", +		(mask & OHCI_INTR_WDH) ? " WDH" : "", +		(mask & OHCI_INTR_SO) ? " SO" : "" +		); +} + +static void maybe_print_eds (char *label, __u32 value) +{ +	ed_t *edp = (ed_t *)value; + +	if (value) { +		dbg ("%s %08x", label, value); +		dbg ("%08x", edp->hwINFO); +		dbg ("%08x", edp->hwTailP); +		dbg ("%08x", edp->hwHeadP); +		dbg ("%08x", edp->hwNextED); +	} +} + +static char * hcfs2string (int state) +{ +	switch (state) { +		case OHCI_USB_RESET:	return "reset"; +		case OHCI_USB_RESUME:	return "resume"; +		case OHCI_USB_OPER:	return "operational"; +		case OHCI_USB_SUSPEND:	return "suspend"; +	} +	return "?"; +} + +/* dump control and status registers */ +static void ohci_dump_status (ohci_t *controller) +{ +	struct ohci_regs	*regs = controller->regs; +	__u32			temp; + +	temp = readl (®s->revision) & 0xff; +	if (temp != 0x10) +		dbg ("spec %d.%d", (temp >> 4), (temp & 0x0f)); + +	temp = readl (®s->control); +	dbg ("control: 0x%08x%s%s%s HCFS=%s%s%s%s%s CBSR=%d", temp, +		(temp & OHCI_CTRL_RWE) ? " RWE" : "", +		(temp & OHCI_CTRL_RWC) ? " RWC" : "", +		(temp & OHCI_CTRL_IR) ? " IR" : "", +		hcfs2string (temp & OHCI_CTRL_HCFS), +		(temp & OHCI_CTRL_BLE) ? " BLE" : "", +		(temp & OHCI_CTRL_CLE) ? " CLE" : "", +		(temp & OHCI_CTRL_IE) ? " IE" : "", +		(temp & OHCI_CTRL_PLE) ? " PLE" : "", +		temp & OHCI_CTRL_CBSR +		); + +	temp = readl (®s->cmdstatus); +	dbg ("cmdstatus: 0x%08x SOC=%d%s%s%s%s", temp, +		(temp & OHCI_SOC) >> 16, +		(temp & OHCI_OCR) ? " OCR" : "", +		(temp & OHCI_BLF) ? " BLF" : "", +		(temp & OHCI_CLF) ? " CLF" : "", +		(temp & OHCI_HCR) ? " HCR" : "" +		); + +	ohci_dump_intr_mask ("intrstatus", readl (®s->intrstatus)); +	ohci_dump_intr_mask ("intrenable", readl (®s->intrenable)); + +	maybe_print_eds ("ed_periodcurrent", readl (®s->ed_periodcurrent)); + +	maybe_print_eds ("ed_controlhead", readl (®s->ed_controlhead)); +	maybe_print_eds ("ed_controlcurrent", readl (®s->ed_controlcurrent)); + +	maybe_print_eds ("ed_bulkhead", readl (®s->ed_bulkhead)); +	maybe_print_eds ("ed_bulkcurrent", readl (®s->ed_bulkcurrent)); + +	maybe_print_eds ("donehead", readl (®s->donehead)); +} + +static void ohci_dump_roothub (ohci_t *controller, int verbose) +{ +	__u32			temp, ndp, i; + +	temp = roothub_a (controller); +	ndp = (temp & RH_A_NDP); + +	if (verbose) { +		dbg ("roothub.a: %08x POTPGT=%d%s%s%s%s%s NDP=%d", temp, +			((temp & RH_A_POTPGT) >> 24) & 0xff, +			(temp & RH_A_NOCP) ? " NOCP" : "", +			(temp & RH_A_OCPM) ? " OCPM" : "", +			(temp & RH_A_DT) ? " DT" : "", +			(temp & RH_A_NPS) ? " NPS" : "", +			(temp & RH_A_PSM) ? " PSM" : "", +			ndp +			); +		temp = roothub_b (controller); +		dbg ("roothub.b: %08x PPCM=%04x DR=%04x", +			temp, +			(temp & RH_B_PPCM) >> 16, +			(temp & RH_B_DR) +			); +		temp = roothub_status (controller); +		dbg ("roothub.status: %08x%s%s%s%s%s%s", +			temp, +			(temp & RH_HS_CRWE) ? " CRWE" : "", +			(temp & RH_HS_OCIC) ? " OCIC" : "", +			(temp & RH_HS_LPSC) ? " LPSC" : "", +			(temp & RH_HS_DRWE) ? " DRWE" : "", +			(temp & RH_HS_OCI) ? " OCI" : "", +			(temp & RH_HS_LPS) ? " LPS" : "" +			); +	} + +	for (i = 0; i < ndp; i++) { +		temp = roothub_portstatus (controller, i); +		dbg ("roothub.portstatus [%d] = 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s", +			i, +			temp, +			(temp & RH_PS_PRSC) ? " PRSC" : "", +			(temp & RH_PS_OCIC) ? " OCIC" : "", +			(temp & RH_PS_PSSC) ? " PSSC" : "", +			(temp & RH_PS_PESC) ? " PESC" : "", +			(temp & RH_PS_CSC) ? " CSC" : "", + +			(temp & RH_PS_LSDA) ? " LSDA" : "", +			(temp & RH_PS_PPS) ? " PPS" : "", +			(temp & RH_PS_PRS) ? " PRS" : "", +			(temp & RH_PS_POCI) ? " POCI" : "", +			(temp & RH_PS_PSS) ? " PSS" : "", + +			(temp & RH_PS_PES) ? " PES" : "", +			(temp & RH_PS_CCS) ? " CCS" : "" +			); +	} +} + +static void ohci_dump (ohci_t *controller, int verbose) +{ +	dbg ("OHCI controller usb-%s state", controller->slot_name); + +	/* dumps some of the state we know about */ +	ohci_dump_status (controller); +	if (verbose) +		ep_print_int_eds (controller, "hcca"); +	dbg ("hcca frame #%04x", controller->hcca->frame_no); +	ohci_dump_roothub (controller, 1); +} + + +#endif /* DEBUG */ + +/*-------------------------------------------------------------------------* + * Interface functions (URB) + *-------------------------------------------------------------------------*/ + +/* get a transfer request */ + +int sohci_submit_job(struct usb_device *dev, unsigned long pipe, void *buffer, +		int transfer_len, struct devrequest *setup, int interval) +{ +	ohci_t *ohci; +	ed_t * ed; +	urb_priv_t *purb_priv; +	int i, size = 0; + +	ohci = &gohci; + +	/* when controller's hung, permit only roothub cleanup attempts +	 * such as powering down ports */ +	if (ohci->disabled) { +		err("sohci_submit_job: EPIPE"); +		return -1; +	} + +	/* every endpoint has a ed, locate and fill it */ +	if (!(ed = ep_add_ed (dev, pipe))) { +		err("sohci_submit_job: ENOMEM"); +		return -1; +	} + +	/* for the private part of the URB we need the number of TDs (size) */ +	switch (usb_pipetype (pipe)) { +		case PIPE_BULK:	/* one TD for every 4096 Byte */ +			size = (transfer_len - 1) / 4096 + 1; +			break; +		case PIPE_CONTROL: /* 1 TD for setup, 1 for ACK and 1 for every 4096 B */ +			size = (transfer_len == 0)? 2: +						(transfer_len - 1) / 4096 + 3; +			break; +	} + +	if (size >= (N_URB_TD - 1)) { +		err("need %d TDs, only have %d", size, N_URB_TD); +		return -1; +	} +	purb_priv = &urb_priv; +	purb_priv->pipe = pipe; + +	/* fill the private part of the URB */ +	purb_priv->length = size; +	purb_priv->ed = ed; +	purb_priv->actual_length = 0; + +	/* allocate the TDs */ +	/* note that td[0] was allocated in ep_add_ed */ +	for (i = 0; i < size; i++) { +		purb_priv->td[i] = td_alloc (dev); +		if (!purb_priv->td[i]) { +			purb_priv->length = i; +			urb_free_priv (purb_priv); +			err("sohci_submit_job: ENOMEM"); +			return -1; +		} +	} + +	if (ed->state == ED_NEW || (ed->state & ED_DEL)) { +		urb_free_priv (purb_priv); +		err("sohci_submit_job: EINVAL"); +		return -1; +	} + +	/* link the ed into a chain if is not already */ +	if (ed->state != ED_OPER) +		ep_link (ohci, ed); + +	/* fill the TDs and link it to the ed */ +	td_submit_job(dev, pipe, buffer, transfer_len, setup, purb_priv, interval); + +	return 0; +} + +/*-------------------------------------------------------------------------*/ + +#ifdef DEBUG +/* tell us the current USB frame number */ + +static int sohci_get_current_frame_number (struct usb_device *usb_dev) +{ +	ohci_t *ohci = &gohci; + +	return m16_swap (ohci->hcca->frame_no); +} +#endif + +/*-------------------------------------------------------------------------* + * ED handling functions + *-------------------------------------------------------------------------*/ + +/* link an ed into one of the HC chains */ + +static int ep_link (ohci_t *ohci, ed_t *edi) +{ +	volatile ed_t *ed = edi; + +	ed->state = ED_OPER; + +	switch (ed->type) { +	case PIPE_CONTROL: +		ed->hwNextED = 0; +		if (ohci->ed_controltail == NULL) { +			writel (ed, &ohci->regs->ed_controlhead); +		} else { +			ohci->ed_controltail->hwNextED = m32_swap (ed); +		} +		ed->ed_prev = ohci->ed_controltail; +		if (!ohci->ed_controltail && !ohci->ed_rm_list[0] && +			!ohci->ed_rm_list[1] && !ohci->sleeping) { +			ohci->hc_control |= OHCI_CTRL_CLE; +			writel (ohci->hc_control, &ohci->regs->control); +		} +		ohci->ed_controltail = edi; +		break; + +	case PIPE_BULK: +		ed->hwNextED = 0; +		if (ohci->ed_bulktail == NULL) { +			writel (ed, &ohci->regs->ed_bulkhead); +		} else { +			ohci->ed_bulktail->hwNextED = m32_swap (ed); +		} +		ed->ed_prev = ohci->ed_bulktail; +		if (!ohci->ed_bulktail && !ohci->ed_rm_list[0] && +			!ohci->ed_rm_list[1] && !ohci->sleeping) { +			ohci->hc_control |= OHCI_CTRL_BLE; +			writel (ohci->hc_control, &ohci->regs->control); +		} +		ohci->ed_bulktail = edi; +		break; +	} +	return 0; +} + +/*-------------------------------------------------------------------------*/ + +/* unlink an ed from one of the HC chains. + * just the link to the ed is unlinked. + * the link from the ed still points to another operational ed or 0 + * so the HC can eventually finish the processing of the unlinked ed */ + +static int ep_unlink (ohci_t *ohci, ed_t *ed) +{ +	ed->hwINFO |= m32_swap (OHCI_ED_SKIP); + +	switch (ed->type) { +	case PIPE_CONTROL: +		if (ed->ed_prev == NULL) { +			if (!ed->hwNextED) { +				ohci->hc_control &= ~OHCI_CTRL_CLE; +				writel (ohci->hc_control, &ohci->regs->control); +			} +			writel (m32_swap (*((__u32 *)&ed->hwNextED)), &ohci->regs->ed_controlhead); +		} else { +			ed->ed_prev->hwNextED = ed->hwNextED; +		} +		if (ohci->ed_controltail == ed) { +			ohci->ed_controltail = ed->ed_prev; +		} else { +			((ed_t *)m32_swap (*((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev; +		} +		break; + +	case PIPE_BULK: +		if (ed->ed_prev == NULL) { +			if (!ed->hwNextED) { +				ohci->hc_control &= ~OHCI_CTRL_BLE; +				writel (ohci->hc_control, &ohci->regs->control); +			} +			writel (m32_swap (*((__u32 *)&ed->hwNextED)), &ohci->regs->ed_bulkhead); +		} else { +			ed->ed_prev->hwNextED = ed->hwNextED; +		} +		if (ohci->ed_bulktail == ed) { +			ohci->ed_bulktail = ed->ed_prev; +		} else { +			((ed_t *)m32_swap (*((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev; +		} +		break; +	} +	ed->state = ED_UNLINK; +	return 0; +} + + +/*-------------------------------------------------------------------------*/ + +/* add/reinit an endpoint; this should be done once at the usb_set_configuration command, + * but the USB stack is a little bit stateless  so we do it at every transaction + * if the state of the ed is ED_NEW then a dummy td is added and the state is changed to ED_UNLINK + * in all other cases the state is left unchanged + * the ed info fields are setted anyway even though most of them should not change */ + +static ed_t * ep_add_ed (struct usb_device *usb_dev, unsigned long pipe) +{ +	td_t *td; +	ed_t *ed_ret; +	volatile ed_t *ed; + +	ed = ed_ret = &ohci_dev.ed[(usb_pipeendpoint (pipe) << 1) | +			(usb_pipecontrol (pipe)? 0: usb_pipeout (pipe))]; + +	if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) { +		err("ep_add_ed: pending delete"); +		/* pending delete request */ +		return NULL; +	} + +	if (ed->state == ED_NEW) { +		ed->hwINFO = m32_swap (OHCI_ED_SKIP); /* skip ed */ +  		/* dummy td; end of td list for ed */ +		td = td_alloc (usb_dev); +		ed->hwTailP = m32_swap (td); +		ed->hwHeadP = ed->hwTailP; +		ed->state = ED_UNLINK; +		ed->type = usb_pipetype (pipe); +		ohci_dev.ed_cnt++; +	} + +	ed->hwINFO = m32_swap (usb_pipedevice (pipe) +			| usb_pipeendpoint (pipe) << 7 +			| (usb_pipeisoc (pipe)? 0x8000: 0) +			| (usb_pipecontrol (pipe)? 0: (usb_pipeout (pipe)? 0x800: 0x1000)) +			| usb_pipeslow (pipe) << 13 +			| usb_maxpacket (usb_dev, pipe) << 16); + +	return ed_ret; +} + +/*-------------------------------------------------------------------------* + * TD handling functions + *-------------------------------------------------------------------------*/ + +/* enqueue next TD for this URB (OHCI spec 5.2.8.2) */ + +static void td_fill (ohci_t *ohci, unsigned int info, +	void *data, int len, +	struct usb_device *dev, int index, urb_priv_t *urb_priv) +{ +	volatile td_t  *td, *td_pt; +#ifdef OHCI_FILL_TRACE +	int i; +#endif + +	if (index > urb_priv->length) { +		err("index > length"); +		return; +	} +	/* use this td as the next dummy */ +	td_pt = urb_priv->td [index]; +	td_pt->hwNextTD = 0; + +	/* fill the old dummy TD */ +	td = urb_priv->td [index] = (td_t *)(m32_swap (urb_priv->ed->hwTailP) & ~0xf); + +	td->ed = urb_priv->ed; +	td->next_dl_td = NULL; +	td->index = index; +	td->data = (__u32)data; +#ifdef OHCI_FILL_TRACE +	if ((usb_pipetype(urb_priv->pipe) == PIPE_BULK) && usb_pipeout(urb_priv->pipe)) { +		for (i = 0; i < len; i++) +		printf("td->data[%d] %#2x ",i, ((unsigned char *)td->data)[i]); +		printf("\n"); +	} +#endif +	if (!len) +		data = 0; + +	td->hwINFO = m32_swap (info); +	td->hwCBP = m32_swap (data); +	if (data) +		td->hwBE = m32_swap (data + len - 1); +	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; +} + +/*-------------------------------------------------------------------------*/ + +/* 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) +{ +	ohci_t *ohci = &gohci; +	int data_len = transfer_len; +	void *data; +	int cnt = 0; +	__u32 info = 0; +  	unsigned int toggle = 0; + +	/* OHCI handles the DATA-toggles itself, we just use the USB-toggle bits for reseting */ +  	if(usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) { +  		toggle = TD_T_TOGGLE; +	} else { +  		toggle = TD_T_DATA0; +		usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 1); +	} +	urb->td_cnt = 0; +	if (data_len) +		data = buffer; +	else +		data = 0; + +	switch (usb_pipetype (pipe)) { +	case PIPE_BULK: +		info = usb_pipeout (pipe)? +			TD_CC | TD_DP_OUT : TD_CC | TD_DP_IN ; +		while(data_len > 4096) { +			td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, 4096, dev, cnt, urb); +			data += 4096; data_len -= 4096; cnt++; +		} +		info = usb_pipeout (pipe)? +			TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ; +		td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, data_len, dev, cnt, urb); +		cnt++; + +		if (!ohci->sleeping) +			writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */ +		break; + +	case PIPE_CONTROL: +		info = TD_CC | TD_DP_SETUP | TD_T_DATA0; +		td_fill (ohci, info, setup, 8, dev, cnt++, urb); +		if (data_len > 0) { +			info = usb_pipeout (pipe)? +				TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 : TD_CC | TD_R | TD_DP_IN | TD_T_DATA1; +			/* NOTE:  mishandles transfers >8K, some >4K */ +			td_fill (ohci, info, data, data_len, dev, cnt++, urb); +		} +		info = usb_pipeout (pipe)? +			TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1; +		td_fill (ohci, info, data, 0, dev, cnt++, urb); +		if (!ohci->sleeping) +			writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */ +		break; +	} +	if (urb->length != cnt) +		dbg("TD LENGTH %d != CNT %d", urb->length, cnt); +} + +/*-------------------------------------------------------------------------* + * Done List handling functions + *-------------------------------------------------------------------------*/ + + +/* calculate the transfer length and update the urb */ + +static void dl_transfer_length(td_t * td) +{ +	__u32 tdINFO, tdBE, tdCBP; + 	urb_priv_t *lurb_priv = &urb_priv; + +	tdINFO = m32_swap (td->hwINFO); +  	tdBE   = m32_swap (td->hwBE); +  	tdCBP  = m32_swap (td->hwCBP); + + +	if (!(usb_pipetype (lurb_priv->pipe) == PIPE_CONTROL && +	    ((td->index == 0) || (td->index == lurb_priv->length - 1)))) { +		if (tdBE != 0) { +			if (td->hwCBP == 0) +				lurb_priv->actual_length += tdBE - td->data + 1; +			else +				lurb_priv->actual_length += tdCBP - td->data; +		} +	} +} + +/*-------------------------------------------------------------------------*/ + +/* replies to the request have to be on a FIFO basis so + * we reverse the reversed done-list */ + +static td_t * dl_reverse_done_list (ohci_t *ohci) +{ +	__u32 td_list_hc; +	td_t *td_rev = NULL; +	td_t *td_list = NULL; +  	urb_priv_t *lurb_priv = NULL; + +	td_list_hc = m32_swap (ohci->hcca->done_head) & 0xfffffff0; +	ohci->hcca->done_head = 0; + +	while (td_list_hc) { +		td_list = (td_t *)td_list_hc; + +		if (TD_CC_GET (m32_swap (td_list->hwINFO))) { +			lurb_priv = &urb_priv; +			dbg(" USB-error/status: %x : %p", +					TD_CC_GET (m32_swap (td_list->hwINFO)), td_list); +			if (td_list->ed->hwHeadP & m32_swap (0x1)) { +				if (lurb_priv && ((td_list->index + 1) < lurb_priv->length)) { +					td_list->ed->hwHeadP = +						(lurb_priv->td[lurb_priv->length - 1]->hwNextTD & m32_swap (0xfffffff0)) | +									(td_list->ed->hwHeadP & m32_swap (0x2)); +					lurb_priv->td_cnt += lurb_priv->length - td_list->index - 1; +				} else +					td_list->ed->hwHeadP &= m32_swap (0xfffffff2); +			} +		} + +		td_list->next_dl_td = td_rev; +		td_rev = td_list; +		td_list_hc = m32_swap (td_list->hwNextTD) & 0xfffffff0; +	} +	return td_list; +} + +/*-------------------------------------------------------------------------*/ + +/* td done list */ +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 = 0; +	/* urb_t *urb; */ +	urb_priv_t *lurb_priv; + 	__u32 tdINFO, edHeadP, edTailP; + +  	while (td_list) { +   		td_list_next = td_list->next_dl_td; + +  		lurb_priv = &urb_priv; +  		tdINFO = m32_swap (td_list->hwINFO); + +   		ed = td_list->ed; + +   		dl_transfer_length(td_list); + +  		/* error code of transfer */ +  		cc = TD_CC_GET (tdINFO); +		if (cc != 0) { +			dbg("ConditionCode %#x", cc); +			stat = cc_to_error[cc]; +		} + +  		if (ed->state != ED_NEW) { +  			edHeadP = m32_swap (ed->hwHeadP) & 0xfffffff0; +  			edTailP = m32_swap (ed->hwTailP); + +			/* unlink eds if they are not busy */ +     			if ((edHeadP == edTailP) && (ed->state == ED_OPER)) +     				ep_unlink (ohci, ed); +     		} + +    		td_list = td_list_next; +  	} +	return stat; +} + +/*-------------------------------------------------------------------------* + * Virtual Root Hub + *-------------------------------------------------------------------------*/ + +/* Device descriptor */ +static __u8 root_hub_dev_des[] = +{ +	0x12,       /*  __u8  bLength; */ +	0x01,       /*  __u8  bDescriptorType; Device */ +	0x10,	    /*  __u16 bcdUSB; v1.1 */ +	0x01, +	0x09,	    /*  __u8  bDeviceClass; HUB_CLASSCODE */ +	0x00,	    /*  __u8  bDeviceSubClass; */ +	0x00,       /*  __u8  bDeviceProtocol; */ +	0x08,       /*  __u8  bMaxPacketSize0; 8 Bytes */ +	0x00,       /*  __u16 idVendor; */ +	0x00, +	0x00,       /*  __u16 idProduct; */ + 	0x00, +	0x00,       /*  __u16 bcdDevice; */ + 	0x00, +	0x00,       /*  __u8  iManufacturer; */ +	0x01,       /*  __u8  iProduct; */ +	0x00,       /*  __u8  iSerialNumber; */ +	0x01        /*  __u8  bNumConfigurations; */ +}; + + +/* Configuration descriptor */ +static __u8 root_hub_config_des[] = +{ +	0x09,       /*  __u8  bLength; */ +	0x02,       /*  __u8  bDescriptorType; Configuration */ +	0x19,       /*  __u16 wTotalLength; */ +	0x00, +	0x01,       /*  __u8  bNumInterfaces; */ +	0x01,       /*  __u8  bConfigurationValue; */ +	0x00,       /*  __u8  iConfiguration; */ +	0x40,       /*  __u8  bmAttributes; +                 Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */ +	0x00,       /*  __u8  MaxPower; */ + +	/* interface */ +	0x09,       /*  __u8  if_bLength; */ +	0x04,       /*  __u8  if_bDescriptorType; Interface */ +	0x00,       /*  __u8  if_bInterfaceNumber; */ +	0x00,       /*  __u8  if_bAlternateSetting; */ +	0x01,       /*  __u8  if_bNumEndpoints; */ +	0x09,       /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */ +	0x00,       /*  __u8  if_bInterfaceSubClass; */ +	0x00,       /*  __u8  if_bInterfaceProtocol; */ +	0x00,       /*  __u8  if_iInterface; */ + +	/* endpoint */ +	0x07,       /*  __u8  ep_bLength; */ +	0x05,       /*  __u8  ep_bDescriptorType; Endpoint */ +	0x81,       /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */ + 	0x03,       /*  __u8  ep_bmAttributes; Interrupt */ + 	0x02,       /*  __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */ + 	0x00, +	0xff        /*  __u8  ep_bInterval; 255 ms */ +}; + +static unsigned char root_hub_str_index0[] = +{ +	0x04,			/*  __u8  bLength; */ +	0x03,			/*  __u8  bDescriptorType; String-descriptor */ +	0x09,			/*  __u8  lang ID */ +	0x04,			/*  __u8  lang ID */ +}; + +static unsigned char root_hub_str_index1[] = +{ +	28,			/*  __u8  bLength; */ +	0x03,			/*  __u8  bDescriptorType; String-descriptor */ +	'O',			/*  __u8  Unicode */ +	0,				/*  __u8  Unicode */ +	'H',			/*  __u8  Unicode */ +	0,				/*  __u8  Unicode */ +	'C',			/*  __u8  Unicode */ +	0,				/*  __u8  Unicode */ +	'I',			/*  __u8  Unicode */ +	0,				/*  __u8  Unicode */ +	' ',			/*  __u8  Unicode */ +	0,				/*  __u8  Unicode */ +	'R',			/*  __u8  Unicode */ +	0,				/*  __u8  Unicode */ +	'o',			/*  __u8  Unicode */ +	0,				/*  __u8  Unicode */ +	'o',			/*  __u8  Unicode */ +	0,				/*  __u8  Unicode */ +	't',			/*  __u8  Unicode */ +	0,				/*  __u8  Unicode */ +	' ',			/*  __u8  Unicode */ +	0,				/*  __u8  Unicode */ +	'H',			/*  __u8  Unicode */ +	0,				/*  __u8  Unicode */ +	'u',			/*  __u8  Unicode */ +	0,				/*  __u8  Unicode */ +	'b',			/*  __u8  Unicode */ +	0,				/*  __u8  Unicode */ +}; + +/* Hub class-specific descriptor is constructed dynamically */ + + +/*-------------------------------------------------------------------------*/ + +#define OK(x) 			len = (x); break +#ifdef DEBUG +#define WR_RH_STAT(x) 		{info("WR:status %#8x", (x));writel((x), &gohci.regs->roothub.status);} +#define WR_RH_PORTSTAT(x) 	{info("WR:portstatus[%d] %#8x", wIndex-1, (x));writel((x), &gohci.regs->roothub.portstatus[wIndex-1]);} +#else +#define WR_RH_STAT(x) 		writel((x), &gohci.regs->roothub.status) +#define WR_RH_PORTSTAT(x) 	writel((x), &gohci.regs->roothub.portstatus[wIndex-1]) +#endif +#define RD_RH_STAT		roothub_status(&gohci) +#define RD_RH_PORTSTAT		roothub_portstatus(&gohci,wIndex-1) + +/* request to virtual root hub */ + +static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe, void *buffer, +		int transfer_len, struct devrequest *cmd) +{ +	void * data = buffer; +	int leni = transfer_len; +	int len = 0; +	int stat = 0; +	__u32 datab[4]; +	__u8 *data_buf = (__u8 *)datab; + 	__u16 bmRType_bReq; +	__u16 wValue; +	__u16 wIndex; +	__u16 wLength; + +#ifdef DEBUG +urb_priv.actual_length = 0; +pkt_print(dev, pipe, buffer, transfer_len, cmd, "SUB(rh)", usb_pipein(pipe)); +#else +	wait_ms(1); +#endif +	if ((pipe & PIPE_INTERRUPT) == PIPE_INTERRUPT) { +		info("Root-Hub submit IRQ: NOT implemented"); +		return 0; +	} + +	bmRType_bReq  = cmd->requesttype | (cmd->request << 8); +	wValue        = m16_swap (cmd->value); +	wIndex        = m16_swap (cmd->index); +	wLength       = m16_swap (cmd->length); + +	info("Root-Hub: adr: %2x cmd(%1x): %08x %04x %04x %04x", +		dev->devnum, 8, bmRType_bReq, wValue, wIndex, wLength); + +	switch (bmRType_bReq) { +	/* Request Destination: +	   without flags: Device, +	   RH_INTERFACE: interface, +	   RH_ENDPOINT: endpoint, +	   RH_CLASS means HUB here, +	   RH_OTHER | RH_CLASS  almost ever means HUB_PORT here +	*/ + +	case RH_GET_STATUS: +			*(__u16 *) data_buf = m16_swap (1); OK (2); +	case RH_GET_STATUS | RH_INTERFACE: +			*(__u16 *) data_buf = m16_swap (0); OK (2); +	case RH_GET_STATUS | RH_ENDPOINT: +			*(__u16 *) data_buf = m16_swap (0); OK (2); +	case RH_GET_STATUS | RH_CLASS: +			*(__u32 *) data_buf = m32_swap ( +				RD_RH_STAT & ~(RH_HS_CRWE | RH_HS_DRWE)); +			OK (4); +	case RH_GET_STATUS | RH_OTHER | RH_CLASS: +			*(__u32 *) data_buf = m32_swap (RD_RH_PORTSTAT); OK (4); + +	case RH_CLEAR_FEATURE | RH_ENDPOINT: +		switch (wValue) { +			case (RH_ENDPOINT_STALL): OK (0); +		} +		break; + +	case RH_CLEAR_FEATURE | RH_CLASS: +		switch (wValue) { +			case RH_C_HUB_LOCAL_POWER: +				OK(0); +			case (RH_C_HUB_OVER_CURRENT): +					WR_RH_STAT(RH_HS_OCIC); OK (0); +		} +		break; + +	case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS: +		switch (wValue) { +			case (RH_PORT_ENABLE): +					WR_RH_PORTSTAT (RH_PS_CCS ); OK (0); +			case (RH_PORT_SUSPEND): +					WR_RH_PORTSTAT (RH_PS_POCI); OK (0); +			case (RH_PORT_POWER): +					WR_RH_PORTSTAT (RH_PS_LSDA); OK (0); +			case (RH_C_PORT_CONNECTION): +					WR_RH_PORTSTAT (RH_PS_CSC ); OK (0); +			case (RH_C_PORT_ENABLE): +					WR_RH_PORTSTAT (RH_PS_PESC); OK (0); +			case (RH_C_PORT_SUSPEND): +					WR_RH_PORTSTAT (RH_PS_PSSC); OK (0); +			case (RH_C_PORT_OVER_CURRENT): +					WR_RH_PORTSTAT (RH_PS_OCIC); OK (0); +			case (RH_C_PORT_RESET): +					WR_RH_PORTSTAT (RH_PS_PRSC); OK (0); +		} +		break; + +	case RH_SET_FEATURE | RH_OTHER | RH_CLASS: +		switch (wValue) { +			case (RH_PORT_SUSPEND): +					WR_RH_PORTSTAT (RH_PS_PSS ); OK (0); +			case (RH_PORT_RESET): /* BUG IN HUP CODE *********/ +					if (RD_RH_PORTSTAT & RH_PS_CCS) +					    WR_RH_PORTSTAT (RH_PS_PRS); +					OK (0); +			case (RH_PORT_POWER): +					WR_RH_PORTSTAT (RH_PS_PPS ); OK (0); +			case (RH_PORT_ENABLE): /* BUG IN HUP CODE *********/ +					if (RD_RH_PORTSTAT & RH_PS_CCS) +					    WR_RH_PORTSTAT (RH_PS_PES ); +					OK (0); +		} +		break; + +	case RH_SET_ADDRESS: gohci.rh.devnum = wValue; OK(0); + +	case RH_GET_DESCRIPTOR: +		switch ((wValue & 0xff00) >> 8) { +			case (0x01): /* device descriptor */ +				len = min_t(unsigned int, +					  leni, +					  min_t(unsigned int, +					      sizeof (root_hub_dev_des), +					      wLength)); +				data_buf = root_hub_dev_des; OK(len); +			case (0x02): /* configuration descriptor */ +				len = min_t(unsigned int, +					  leni, +					  min_t(unsigned int, +					      sizeof (root_hub_config_des), +					      wLength)); +				data_buf = root_hub_config_des; OK(len); +			case (0x03): /* string descriptors */ +				if(wValue==0x0300) { +					len = min_t(unsigned int, +						  leni, +						  min_t(unsigned int, +						      sizeof (root_hub_str_index0), +						      wLength)); +					data_buf = root_hub_str_index0; +					OK(len); +				} +				if(wValue==0x0301) { +					len = min_t(unsigned int, +						  leni, +						  min_t(unsigned int, +						      sizeof (root_hub_str_index1), +						      wLength)); +					data_buf = root_hub_str_index1; +					OK(len); +			} +			default: +				stat = USB_ST_STALLED; +		} +		break; + +	case RH_GET_DESCRIPTOR | RH_CLASS: +	    { +		    __u32 temp = roothub_a (&gohci); + +		    data_buf [0] = 9;		/* min length; */ +		    data_buf [1] = 0x29; +		    data_buf [2] = temp & RH_A_NDP; +		    data_buf [3] = 0; +		    if (temp & RH_A_PSM) 	/* per-port power switching? */ +			data_buf [3] |= 0x1; +		    if (temp & RH_A_NOCP)	/* no overcurrent reporting? */ +			data_buf [3] |= 0x10; +		    else if (temp & RH_A_OCPM)	/* per-port overcurrent reporting? */ +			data_buf [3] |= 0x8; + +		    /* corresponds to data_buf[4-7] */ +		    datab [1] = 0; +		    data_buf [5] = (temp & RH_A_POTPGT) >> 24; +		    temp = roothub_b (&gohci); +		    data_buf [7] = temp & RH_B_DR; +		    if (data_buf [2] < 7) { +			data_buf [8] = 0xff; +		    } else { +			data_buf [0] += 2; +			data_buf [8] = (temp & RH_B_DR) >> 8; +			data_buf [10] = data_buf [9] = 0xff; +		    } + +		    len = min_t(unsigned int, leni, +			      min_t(unsigned int, data_buf [0], wLength)); +		    OK (len); +		} + +	case RH_GET_CONFIGURATION: 	*(__u8 *) data_buf = 0x01; OK (1); + +	case RH_SET_CONFIGURATION: 	WR_RH_STAT (0x10000); OK (0); + +	default: +		dbg ("unsupported root hub command"); +		stat = USB_ST_STALLED; +	} + +#ifdef	DEBUG +	ohci_dump_roothub (&gohci, 1); +#else +	wait_ms(1); +#endif + +	len = min_t(int, len, leni); +	if (data != data_buf) +	    memcpy (data, data_buf, len); +  	dev->act_len = len; +	dev->status = stat; + +#ifdef DEBUG +	if (transfer_len) +		urb_priv.actual_length = transfer_len; +	pkt_print(dev, pipe, buffer, transfer_len, cmd, "RET(rh)", 0/*usb_pipein(pipe)*/); +#else +	wait_ms(1); +#endif + +	return stat; +} + +/*-------------------------------------------------------------------------*/ + +/* common code for handling submit messages - used for all but root hub */ +/* accesses. */ +int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer, +		int transfer_len, struct devrequest *setup, int interval) +{ +	int stat = 0; +	int maxsize = usb_maxpacket(dev, pipe); +	int timeout; + +#ifdef DEBUG +	urb_priv.actual_length = 0; +	pkt_print(dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe)); +#else +	wait_ms(1); +#endif +	if (!maxsize) { +		err("submit_common_message: pipesize for pipe %lx is zero", +			pipe); +		return -1; +	} + +	if (sohci_submit_job(dev, pipe, buffer, transfer_len, setup, interval) < 0) { +		err("sohci_submit_job failed"); +		return -1; +	} + +	wait_ms(10); +	/* ohci_dump_status(&gohci); */ +	/* wait for it to complete */ +	timeout = 100; +	for (;;) { +		/* check whether the controller is done */ +		stat = hc_interrupt(); +		if (stat < 0) { +			stat = 1; +			break; +		} +		if (stat >= 0 && stat != 0xff) { +			/* 0xff is returned for an SF-interrupt */ +			break; +		} +		if (--timeout) { +			wait_ms(1); +		} else { +			err("CTL:TIMEOUT"); +			stat = 1; +			break; +		} +	} +	dev->status = stat; +  	dev->act_len = transfer_len; + +#ifdef DEBUG +	pkt_print(dev, pipe, buffer, transfer_len, setup, "RET(ctlr)", usb_pipein(pipe)); +#else +	wait_ms(1); +#endif + +	/* free TDs in urb_priv */ +	urb_free_priv (&urb_priv); +	return 0; +} + +/* submit routines called from usb.c */ +int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, +		int transfer_len) +{ +	info("submit_bulk_msg"); +	return submit_common_msg(dev, pipe, buffer, transfer_len, NULL, 0); +} + +int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, +		int transfer_len, struct devrequest *setup) +{ +	int maxsize = usb_maxpacket(dev, pipe); + +	info("submit_control_msg"); +#ifdef DEBUG +	urb_priv.actual_length = 0; +	pkt_print(dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe)); +#else +	wait_ms(1); +#endif +	if (!maxsize) { +		err("submit_control_message: pipesize for pipe %lx is zero", +			pipe); +		return -1; +	} +	if (((pipe >> 8) & 0x7f) == gohci.rh.devnum) +		/* root hub - redirect */ +		return ohci_submit_rh_msg(dev, pipe, buffer, transfer_len, +			setup); + +	return submit_common_msg(dev, pipe, buffer, transfer_len, setup, 0); +} + +int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, +		int transfer_len, int interval) +{ +	info("submit_int_msg"); +	return -1; +} + +/*-------------------------------------------------------------------------* + * HC functions + *-------------------------------------------------------------------------*/ + +/* reset the HC and BUS */ + +static int hc_reset (ohci_t *ohci) +{ +	int timeout = 30; +	int smm_timeout = 50; /* 0,5 sec */ + +	if (readl (&ohci->regs->control) & OHCI_CTRL_IR) { /* SMM owns the HC */ +		writel (OHCI_OCR, &ohci->regs->cmdstatus); /* request ownership */ +		info("USB HC TakeOver from SMM"); +		while (readl (&ohci->regs->control) & OHCI_CTRL_IR) { +			wait_ms (10); +			if (--smm_timeout == 0) { +				err("USB HC TakeOver failed!"); +				return -1; +			} +		} +	} + +	/* Disable HC interrupts */ +	writel (OHCI_INTR_MIE, &ohci->regs->intrdisable); + +	dbg("USB HC reset_hc usb-%s: ctrl = 0x%X ;", +		ohci->slot_name, +		readl (&ohci->regs->control)); + +  	/* Reset USB (needed by some controllers) */ +	writel (0, &ohci->regs->control); + +	/* HC Reset requires max 10 us delay */ +	writel (OHCI_HCR,  &ohci->regs->cmdstatus); +	while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) { +		if (--timeout == 0) { +			err("USB HC reset timed out!"); +			return -1; +		} +		udelay (1); +	} +	return 0; +} + +/*-------------------------------------------------------------------------*/ + +/* Start an OHCI controller, set the BUS operational + * enable interrupts + * connect the virtual root hub */ + +static int hc_start (ohci_t * ohci) +{ +  	__u32 mask; +  	unsigned int fminterval; + +	ohci->disabled = 1; + +	/* Tell the controller where the control and bulk lists are +	 * The lists are empty now. */ + +	writel (0, &ohci->regs->ed_controlhead); +	writel (0, &ohci->regs->ed_bulkhead); + +	writel ((__u32)ohci->hcca, &ohci->regs->hcca); /* a reset clears this */ + +  	fminterval = 0x2edf; +	writel ((fminterval * 9) / 10, &ohci->regs->periodicstart); +	fminterval |= ((((fminterval - 210) * 6) / 7) << 16); +	writel (fminterval, &ohci->regs->fminterval); +	writel (0x628, &ohci->regs->lsthresh); + + 	/* start controller operations */ + 	ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER; +	ohci->disabled = 0; + 	writel (ohci->hc_control, &ohci->regs->control); + +	/* Choose the interrupts we care about now, others later on demand */ +	mask = OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_WDH | OHCI_INTR_SO; +	writel (mask, &ohci->regs->intrstatus); + +#ifdef	OHCI_USE_NPS +	/* required for AMD-756 and some Mac platforms */ +	writel ((roothub_a (ohci) | RH_A_NPS) & ~RH_A_PSM, +		&ohci->regs->roothub.a); +	writel (RH_HS_LPSC, &ohci->regs->roothub.status); +#endif	/* OHCI_USE_NPS */ + +#define mdelay(n) ({unsigned long msec=(n); while (msec--) udelay(1000);}) +	/* POTPGT delay is bits 24-31, in 2 ms units. */ +	mdelay ((roothub_a (ohci) >> 23) & 0x1fe); + +	/* connect the virtual root hub */ +	ohci->rh.devnum = 0; + +	return 0; +} + +/*-------------------------------------------------------------------------*/ + +/* an interrupt happens */ + +static int +hc_interrupt (void) +{ +	ohci_t *ohci = &gohci; +	struct ohci_regs *regs = ohci->regs; + 	int ints; +	int stat = -1; + +	if ((ohci->hcca->done_head != 0) && !(m32_swap (ohci->hcca->done_head) & 0x01)) { +		ints =  OHCI_INTR_WDH; +	} else { +		ints = readl (®s->intrstatus); +	} + +	/* dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no)); */ + +	if (ints & OHCI_INTR_UE) { +		ohci->disabled++; +		err ("OHCI Unrecoverable Error, controller usb-%s disabled", +			ohci->slot_name); +		/* e.g. due to PCI Master/Target Abort */ + +#ifdef	DEBUG +		ohci_dump (ohci, 1); +#else +	wait_ms(1); +#endif +		/* FIXME: be optimistic, hope that bug won't repeat often. */ +		/* Make some non-interrupt context restart the controller. */ +		/* Count and limit the retries though; either hardware or */ +		/* software errors can go forever... */ +		hc_reset (ohci); +		return -1; +	} + +	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); +	} + +	if (ints & OHCI_INTR_SO) { +		dbg("USB Schedule overrun\n"); +		writel (OHCI_INTR_SO, ®s->intrenable); +		stat = -1; +	} + +	/* FIXME:  this assumes SOF (1/ms) interrupts don't get lost... */ +	if (ints & OHCI_INTR_SF) { +		unsigned int frame = m16_swap (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); +		stat = 0xff; +	} + +	writel (ints, ®s->intrstatus); +	return stat; +} + +/*-------------------------------------------------------------------------*/ + +/*-------------------------------------------------------------------------*/ + +/* De-allocate all resources.. */ + +static void hc_release_ohci (ohci_t *ohci) +{ +	dbg ("USB HC release ohci usb-%s", ohci->slot_name); + +	if (!ohci->disabled) +		hc_reset (ohci); +} + +/*-------------------------------------------------------------------------*/ + +/* + * low level initalisation routine, called from usb.c + */ +static char ohci_inited = 0; + +int usb_lowlevel_init(void) +{ +	S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER(); +	S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO(); + +        /* +         * Set the 48 MHz UPLL clocking. Values are taken from +         * "PLL value selection guide", 6-23, s3c2400_UM.pdf. +         */ +        clk_power->UPLLCON = ((40 << 12) + (1 << 4) + 2); +        gpio->MISCCR |= 0x8; /* 1 = use pads related USB for USB host */ + +        /* +         * Enable USB host clock. +         */ +        clk_power->CLKCON |= (1 << 4); + +	memset (&gohci, 0, sizeof (ohci_t)); +	memset (&urb_priv, 0, sizeof (urb_priv_t)); + +	/* align the storage */ +	if ((__u32)&ghcca[0] & 0xff) { +		err("HCCA not aligned!!"); +		return -1; +	} +	phcca = &ghcca[0]; +	info("aligned ghcca %p", phcca); +	memset(&ohci_dev, 0, sizeof(struct ohci_device)); +	if ((__u32)&ohci_dev.ed[0] & 0x7) { +		err("EDs not aligned!!"); +		return -1; +	} +	memset(gtd, 0, sizeof(td_t) * (NUM_TD + 1)); +	if ((__u32)gtd & 0x7) { +		err("TDs not aligned!!"); +		return -1; +	} +	ptd = gtd; +	gohci.hcca = phcca; +        memset (phcca, 0, sizeof (struct ohci_hcca)); + +	gohci.disabled = 1; +	gohci.sleeping = 0; +	gohci.irq = -1; +	gohci.regs = (struct ohci_regs *)S3C24X0_USB_HOST_BASE; + +	gohci.flags = 0; +	gohci.slot_name = "s3c2400"; + +	if (hc_reset (&gohci) < 0) { +		hc_release_ohci (&gohci); +                /* Initialization failed */ +                clk_power->CLKCON &= ~(1 << 4); +		return -1; +	} + +	/* FIXME this is a second HC reset; why?? */ +	writel (gohci.hc_control = OHCI_USB_RESET, &gohci.regs->control); +	wait_ms (10); + +	if (hc_start (&gohci) < 0) { +		err ("can't start usb-%s", gohci.slot_name); +		hc_release_ohci (&gohci); +                /* Initialization failed */ +                clk_power->CLKCON &= ~(1 << 4); +		return -1; +	} + +#ifdef	DEBUG +	ohci_dump (&gohci, 1); +#else +	wait_ms(1); +#endif +	ohci_inited = 1; +	return 0; +} + +int usb_lowlevel_stop(void) +{ +	S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER(); + +	/* this gets called really early - before the controller has */ +	/* even been initialized! */ +	if (!ohci_inited) +		return 0; +	/* TODO release any interrupts, etc. */ +	/* call hc_release_ohci() here ? */ +	hc_reset (&gohci); +	/* may not want to do this */ +	clk_power->CLKCON &= ~(1 << 4); +	return 0; +} + +#endif /* CONFIG_USB_OHCI */ diff --git a/cpu/arm920t/usb_ohci.h b/cpu/arm920t/usb_ohci.h new file mode 100644 index 000000000..26b84e66f --- /dev/null +++ b/cpu/arm920t/usb_ohci.h @@ -0,0 +1,420 @@ +/* + * URB OHCI HCD (Host Controller Driver) for USB. + * + * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> + * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net> + * + * usb-ohci.h + */ + + +static int cc_to_error[16] = { + +/* mapping of the OHCI CC status to error codes */ +	/* No  Error  */               0, +	/* CRC Error  */               USB_ST_CRC_ERR, +	/* Bit Stuff  */               USB_ST_BIT_ERR, +	/* Data Togg  */               USB_ST_CRC_ERR, +	/* Stall      */               USB_ST_STALLED, +	/* DevNotResp */               -1, +	/* PIDCheck   */               USB_ST_BIT_ERR, +	/* UnExpPID   */               USB_ST_BIT_ERR, +	/* DataOver   */               USB_ST_BUF_ERR, +	/* DataUnder  */               USB_ST_BUF_ERR, +	/* reservd    */               -1, +	/* reservd    */               -1, +	/* BufferOver */               USB_ST_BUF_ERR, +	/* BuffUnder  */               USB_ST_BUF_ERR, +	/* Not Access */               -1, +	/* Not Access */               -1 +}; + +/* ED States */ + +#define ED_NEW 		0x00 +#define ED_UNLINK 	0x01 +#define ED_OPER		0x02 +#define ED_DEL		0x04 +#define ED_URB_DEL  	0x08 + +/* usb_ohci_ed */ +struct ed { +	__u32 hwINFO; +	__u32 hwTailP; +	__u32 hwHeadP; +	__u32 hwNextED; + +	struct ed *ed_prev; +	__u8 int_period; +	__u8 int_branch; +	__u8 int_load; +	__u8 int_interval; +	__u8 state; +	__u8 type; +	__u16 last_iso; +	struct ed *ed_rm_list; + +	struct usb_device *usb_dev; +	__u32 unused[3]; +} __attribute((aligned(16))); +typedef struct ed ed_t; + + +/* TD info field */ +#define TD_CC       0xf0000000 +#define TD_CC_GET(td_p) ((td_p >>28) & 0x0f) +#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28) +#define TD_EC       0x0C000000 +#define TD_T        0x03000000 +#define TD_T_DATA0  0x02000000 +#define TD_T_DATA1  0x03000000 +#define TD_T_TOGGLE 0x00000000 +#define TD_R        0x00040000 +#define TD_DI       0x00E00000 +#define TD_DI_SET(X) (((X) & 0x07)<< 21) +#define TD_DP       0x00180000 +#define TD_DP_SETUP 0x00000000 +#define TD_DP_IN    0x00100000 +#define TD_DP_OUT   0x00080000 + +#define TD_ISO	    0x00010000 +#define TD_DEL      0x00020000 + +/* CC Codes */ +#define TD_CC_NOERROR      0x00 +#define TD_CC_CRC          0x01 +#define TD_CC_BITSTUFFING  0x02 +#define TD_CC_DATATOGGLEM  0x03 +#define TD_CC_STALL        0x04 +#define TD_DEVNOTRESP      0x05 +#define TD_PIDCHECKFAIL    0x06 +#define TD_UNEXPECTEDPID   0x07 +#define TD_DATAOVERRUN     0x08 +#define TD_DATAUNDERRUN    0x09 +#define TD_BUFFEROVERRUN   0x0C +#define TD_BUFFERUNDERRUN  0x0D +#define TD_NOTACCESSED     0x0F + + +#define MAXPSW 1 + +struct td { +	__u32 hwINFO; +  	__u32 hwCBP;		/* Current Buffer Pointer */ +  	__u32 hwNextTD;		/* Next TD Pointer */ +  	__u32 hwBE;		/* Memory Buffer End Pointer */ + +  	__u16 hwPSW[MAXPSW]; +  	__u8 unused; +  	__u8 index; +  	struct ed *ed; +  	struct td *next_dl_td; +	struct usb_device *usb_dev; +	int transfer_len; +	__u32 data; + +	__u32 unused2[2]; +} __attribute((aligned(32))); +typedef struct td td_t; + +#define OHCI_ED_SKIP	(1 << 14) + +/* + * The HCCA (Host Controller Communications Area) is a 256 byte + * structure defined in the OHCI spec. that the host controller is + * told the base address of.  It must be 256-byte aligned. + */ + +#define NUM_INTS 32	/* part of the OHCI standard */ +struct ohci_hcca { +	__u32	int_table[NUM_INTS];	/* Interrupt ED table */ +	__u16	frame_no;		/* current frame number */ +	__u16	pad1;			/* set to 0 on each frame_no change */ +	__u32	done_head;		/* info returned for an interrupt */ +	u8		reserved_for_hc[116]; +} __attribute((aligned(256))); + + +/* + * Maximum number of root hub ports. + */ +#define MAX_ROOT_PORTS	15	/* maximum OHCI root hub ports */ + +/* + * This is the structure of the OHCI controller's memory mapped I/O + * region.  This is Memory Mapped I/O.  You must use the readl() and + * writel() macros defined in asm/io.h to access these!! + */ +struct ohci_regs { +	/* control and status registers */ +	__u32	revision; +	__u32	control; +	__u32	cmdstatus; +	__u32	intrstatus; +	__u32	intrenable; +	__u32	intrdisable; +	/* memory pointers */ +	__u32	hcca; +	__u32	ed_periodcurrent; +	__u32	ed_controlhead; +	__u32	ed_controlcurrent; +	__u32	ed_bulkhead; +	__u32	ed_bulkcurrent; +	__u32	donehead; +	/* frame counters */ +	__u32	fminterval; +	__u32	fmremaining; +	__u32	fmnumber; +	__u32	periodicstart; +	__u32	lsthresh; +	/* Root hub ports */ +	struct	ohci_roothub_regs { +		__u32	a; +		__u32	b; +		__u32	status; +		__u32	portstatus[MAX_ROOT_PORTS]; +	} roothub; +} __attribute((aligned(32))); + + +/* OHCI CONTROL AND STATUS REGISTER MASKS */ + +/* + * HcControl (control) register masks + */ +#define OHCI_CTRL_CBSR	(3 << 0)	/* control/bulk service ratio */ +#define OHCI_CTRL_PLE	(1 << 2)	/* periodic list enable */ +#define OHCI_CTRL_IE	(1 << 3)	/* isochronous enable */ +#define OHCI_CTRL_CLE	(1 << 4)	/* control list enable */ +#define OHCI_CTRL_BLE	(1 << 5)	/* bulk list enable */ +#define OHCI_CTRL_HCFS	(3 << 6)	/* host controller functional state */ +#define OHCI_CTRL_IR	(1 << 8)	/* interrupt routing */ +#define OHCI_CTRL_RWC	(1 << 9)	/* remote wakeup connected */ +#define OHCI_CTRL_RWE	(1 << 10)	/* remote wakeup enable */ + +/* pre-shifted values for HCFS */ +#	define OHCI_USB_RESET	(0 << 6) +#	define OHCI_USB_RESUME	(1 << 6) +#	define OHCI_USB_OPER	(2 << 6) +#	define OHCI_USB_SUSPEND	(3 << 6) + +/* + * HcCommandStatus (cmdstatus) register masks + */ +#define OHCI_HCR	(1 << 0)	/* host controller reset */ +#define OHCI_CLF  	(1 << 1)	/* control list filled */ +#define OHCI_BLF  	(1 << 2)	/* bulk list filled */ +#define OHCI_OCR  	(1 << 3)	/* ownership change request */ +#define OHCI_SOC  	(3 << 16)	/* scheduling overrun count */ + +/* + * masks used with interrupt registers: + * HcInterruptStatus (intrstatus) + * HcInterruptEnable (intrenable) + * HcInterruptDisable (intrdisable) + */ +#define OHCI_INTR_SO	(1 << 0)	/* scheduling overrun */ +#define OHCI_INTR_WDH	(1 << 1)	/* writeback of done_head */ +#define OHCI_INTR_SF	(1 << 2)	/* start frame */ +#define OHCI_INTR_RD	(1 << 3)	/* resume detect */ +#define OHCI_INTR_UE	(1 << 4)	/* unrecoverable error */ +#define OHCI_INTR_FNO	(1 << 5)	/* frame number overflow */ +#define OHCI_INTR_RHSC	(1 << 6)	/* root hub status change */ +#define OHCI_INTR_OC	(1 << 30)	/* ownership change */ +#define OHCI_INTR_MIE	(1 << 31)	/* master interrupt enable */ + + + +/* Virtual Root HUB */ +struct virt_root_hub { +	int devnum; /* Address of Root Hub endpoint */ +	void *dev;  /* was urb */ +	void *int_addr; +	int send; +	int interval; +}; + +/* USB HUB CONSTANTS (not OHCI-specific; see hub.h) */ + +/* destination of request */ +#define RH_INTERFACE               0x01 +#define RH_ENDPOINT                0x02 +#define RH_OTHER                   0x03 + +#define RH_CLASS                   0x20 +#define RH_VENDOR                  0x40 + +/* Requests: bRequest << 8 | bmRequestType */ +#define RH_GET_STATUS           0x0080 +#define RH_CLEAR_FEATURE        0x0100 +#define RH_SET_FEATURE          0x0300 +#define RH_SET_ADDRESS		0x0500 +#define RH_GET_DESCRIPTOR	0x0680 +#define RH_SET_DESCRIPTOR       0x0700 +#define RH_GET_CONFIGURATION	0x0880 +#define RH_SET_CONFIGURATION	0x0900 +#define RH_GET_STATE            0x0280 +#define RH_GET_INTERFACE        0x0A80 +#define RH_SET_INTERFACE        0x0B00 +#define RH_SYNC_FRAME           0x0C80 +/* Our Vendor Specific Request */ +#define RH_SET_EP               0x2000 + + +/* Hub port features */ +#define RH_PORT_CONNECTION         0x00 +#define RH_PORT_ENABLE             0x01 +#define RH_PORT_SUSPEND            0x02 +#define RH_PORT_OVER_CURRENT       0x03 +#define RH_PORT_RESET              0x04 +#define RH_PORT_POWER              0x08 +#define RH_PORT_LOW_SPEED          0x09 + +#define RH_C_PORT_CONNECTION       0x10 +#define RH_C_PORT_ENABLE           0x11 +#define RH_C_PORT_SUSPEND          0x12 +#define RH_C_PORT_OVER_CURRENT     0x13 +#define RH_C_PORT_RESET            0x14 + +/* Hub features */ +#define RH_C_HUB_LOCAL_POWER       0x00 +#define RH_C_HUB_OVER_CURRENT      0x01 + +#define RH_DEVICE_REMOTE_WAKEUP    0x00 +#define RH_ENDPOINT_STALL          0x01 + +#define RH_ACK                     0x01 +#define RH_REQ_ERR                 -1 +#define RH_NACK                    0x00 + + +/* OHCI ROOT HUB REGISTER MASKS */ + +/* roothub.portstatus [i] bits */ +#define RH_PS_CCS            0x00000001   	/* current connect status */ +#define RH_PS_PES            0x00000002   	/* port enable status*/ +#define RH_PS_PSS            0x00000004   	/* port suspend status */ +#define RH_PS_POCI           0x00000008   	/* port over current indicator */ +#define RH_PS_PRS            0x00000010  	/* port reset status */ +#define RH_PS_PPS            0x00000100   	/* port power status */ +#define RH_PS_LSDA           0x00000200    	/* low speed device attached */ +#define RH_PS_CSC            0x00010000 	/* connect status change */ +#define RH_PS_PESC           0x00020000   	/* port enable status change */ +#define RH_PS_PSSC           0x00040000    	/* port suspend status change */ +#define RH_PS_OCIC           0x00080000    	/* over current indicator change */ +#define RH_PS_PRSC           0x00100000   	/* port reset status change */ + +/* roothub.status bits */ +#define RH_HS_LPS	     0x00000001		/* local power status */ +#define RH_HS_OCI	     0x00000002		/* over current indicator */ +#define RH_HS_DRWE	     0x00008000		/* device remote wakeup enable */ +#define RH_HS_LPSC	     0x00010000		/* local power status change */ +#define RH_HS_OCIC	     0x00020000		/* over current indicator change */ +#define RH_HS_CRWE	     0x80000000		/* clear remote wakeup enable */ + +/* roothub.b masks */ +#define RH_B_DR		0x0000ffff		/* device removable flags */ +#define RH_B_PPCM	0xffff0000		/* port power control mask */ + +/* roothub.a masks */ +#define	RH_A_NDP	(0xff << 0)		/* number of downstream ports */ +#define	RH_A_PSM	(1 << 8)		/* power switching mode */ +#define	RH_A_NPS	(1 << 9)		/* no power switching */ +#define	RH_A_DT		(1 << 10)		/* device type (mbz) */ +#define	RH_A_OCPM	(1 << 11)		/* over current protection mode */ +#define	RH_A_NOCP	(1 << 12)		/* no over current protection */ +#define	RH_A_POTPGT	(0xff << 24)		/* power on to power good time */ + +/* urb */ +#define N_URB_TD 48 +typedef struct +{ +	ed_t *ed; +	__u16 length;	/* number of tds associated with this request */ +	__u16 td_cnt;	/* number of tds already serviced */ +	int   state; +	unsigned long pipe; +	int actual_length; +	td_t *td[N_URB_TD];	/* list pointer to all corresponding TDs associated with this request */ +} urb_priv_t; +#define URB_DEL 1 + +/* + * This is the full ohci controller description + * + * Note how the "proper" USB information is just + * a subset of what the full implementation needs. (Linus) + */ + + +typedef struct ohci { +	struct ohci_hcca *hcca;		/* hcca */ +	/*dma_addr_t hcca_dma;*/ + +	int irq; +	int disabled;			/* e.g. got a UE, we're hung */ +	int sleeping; +	unsigned long flags;		/* for HC bugs */ + +	struct ohci_regs *regs;	/* OHCI controller's memory */ + +	ed_t *ed_rm_list[2];     /* lists of all endpoints to be removed */ +	ed_t *ed_bulktail;       /* last endpoint of bulk list */ +	ed_t *ed_controltail;    /* last endpoint of control list */ +	int intrstatus; +	__u32 hc_control;		/* copy of the hc control reg */ +	struct usb_device *dev[32]; +	struct virt_root_hub rh; + +	const char	*slot_name; +} ohci_t; + +#define NUM_EDS 8		/* num of preallocated endpoint descriptors */ + +struct ohci_device { +	ed_t 	ed[NUM_EDS]; +	int ed_cnt; +}; + +/* hcd */ +/* endpoint */ +static int ep_link(ohci_t * ohci, ed_t * ed); +static int ep_unlink(ohci_t * ohci, ed_t * ed); +static ed_t * ep_add_ed(struct usb_device * usb_dev, unsigned long pipe); + +/*-------------------------------------------------------------------------*/ + +/* we need more TDs than EDs */ +#define NUM_TD 64 + +/* +1 so we can align the storage */ +td_t gtd[NUM_TD+1]; +/* pointers to aligned storage */ +td_t *ptd; + +/* TDs ... */ +static inline struct td * +td_alloc (struct usb_device *usb_dev) +{ +	int i; +	struct td	*td; + +	td = NULL; +	for (i = 0; i < NUM_TD; i++) +	{ +		if (ptd[i].usb_dev == NULL) +		{ +			td = &ptd[i]; +			td->usb_dev = usb_dev; +			break; +		} +	} + +	return td; +} + +static inline void +ed_free (struct ed *ed) +{ +	ed->usb_dev = NULL; +} diff --git a/cpu/ppc4xx/405gp_enet.c b/cpu/ppc4xx/405gp_enet.c index 9639c92e9..c222c719e 100644 --- a/cpu/ppc4xx/405gp_enet.c +++ b/cpu/ppc4xx/405gp_enet.c @@ -83,7 +83,7 @@  #if defined(CONFIG_405GP) || defined(CONFIG_440) || defined(CONFIG_405EP)  #define EMAC_RESET_TIMEOUT 1000	/* 1000 ms reset timeout */ -#define PHY_AUTONEGOTIATE_TIMEOUT 2000	/* 2000 ms autonegotiate timeout */ +#define PHY_AUTONEGOTIATE_TIMEOUT 4000	/* 4000 ms autonegotiate timeout */  #define NUM_TX_BUFF 1  /* AS.HARNOIS @@ -271,18 +271,18 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)  		puts ("Waiting for PHY auto negotiation to complete");  		i = 0;  		while (!(reg_short & PHY_BMSR_AUTN_COMP)) { -			if ((i++ % 100) == 0) -				putc ('.'); -			udelay (10000);		/* 10 ms */ -			miiphy_read (CONFIG_PHY_ADDR, PHY_BMSR, ®_short); -  			/*  			 * Timeout reached ?  			 */ -			if (i * 10 > PHY_AUTONEGOTIATE_TIMEOUT) { +			if (i > PHY_AUTONEGOTIATE_TIMEOUT) {  				puts (" TIMEOUT !\n");  				break;  			} + +			if ((i++ % 1000) == 0) +				putc ('.'); +			udelay (1000);	/* 1 ms */ +			miiphy_read (CONFIG_PHY_ADDR, PHY_BMSR, ®_short);  		}  		puts (" done\n");  		udelay (500000);	/* another 500 ms (results in faster booting) */ diff --git a/disk/part.c b/disk/part.c index 97ed91865..7bd48e070 100644 --- a/disk/part.c +++ b/disk/part.c @@ -33,7 +33,9 @@  #define PRINTF(fmt,args...)  #endif -#if (CONFIG_COMMANDS & CFG_CMD_IDE) || (CONFIG_COMMANDS & CFG_CMD_SCSI) +#if ((CONFIG_COMMANDS & CFG_CMD_IDE)	|| \ +     (CONFIG_COMMANDS & CFG_CMD_SCSI)	|| \ +     (CONFIG_COMMANDS & CFG_CMD_USB)	)  /* ------------------------------------------------------------------------- */  /* diff --git a/disk/part_dos.c b/disk/part_dos.c index db2c23bc5..32333c797 100644 --- a/disk/part_dos.c +++ b/disk/part_dos.c @@ -35,7 +35,9 @@  #include <ide.h>  #include "part_dos.h" -#if ((CONFIG_COMMANDS & CFG_CMD_IDE) || (CONFIG_COMMANDS & CFG_CMD_SCSI)) && defined(CONFIG_DOS_PARTITION) +#if ((CONFIG_COMMANDS & CFG_CMD_IDE)	|| \ +     (CONFIG_COMMANDS & CFG_CMD_SCSI)	|| \ +     (CONFIG_COMMANDS & CFG_CMD_USB)	) && defined(CONFIG_DOS_PARTITION)  /* Convert char[4] in little endian format to the host format integer   */ diff --git a/drivers/sk98lin/h/ski2c.h b/drivers/sk98lin/h/ski2c.h index db2d4e65c..5316bbacb 100644 --- a/drivers/sk98lin/h/ski2c.h +++ b/drivers/sk98lin/h/ski2c.h @@ -161,6 +161,8 @@ typedef struct  s_Sensor SK_SENSOR;  /*   * Define READ and WRITE Constants.   */ +#undef	I2C_READ		/* just in case */ +#undef	I2C_WRITE		/* just in case */  #define I2C_READ	0  #define I2C_WRITE	1  #define I2C_BURST	1 diff --git a/drivers/sk98lin/skaddr.c b/drivers/sk98lin/skaddr.c index 467711183..f2486032e 100644 --- a/drivers/sk98lin/skaddr.c +++ b/drivers/sk98lin/skaddr.c @@ -218,6 +218,10 @@   *   ******************************************************************************/ +#include <config.h> + +#ifdef CONFIG_SK98 +  #ifndef	lint  static const char SysKonnectFileId[] =  	"@(#) $Id: skaddr.c,v 1.48 2003/02/12 17:09:37 tschilli Exp $ (C) SysKonnect."; @@ -1872,3 +1876,4 @@ SK_U32	ToPortNumber)		/* Port2 Index */  }  #endif	/* __cplusplus */ +#endif /* CONFIG_SK98 */ diff --git a/drivers/sk98lin/skcsum.c b/drivers/sk98lin/skcsum.c index 9630fad0d..0fd70301b 100644 --- a/drivers/sk98lin/skcsum.c +++ b/drivers/sk98lin/skcsum.c @@ -70,6 +70,10 @@   *   ******************************************************************************/ +#include <config.h> + +#ifdef CONFIG_SK98 +  #ifdef SK_USE_CSUM	/* Check if CSUM is to be used. */  #ifndef lint @@ -921,3 +925,5 @@ SK_EVPARA	Param)	/* Event dependent parameter. */  }	/* SkCsEvent */  #endif	/* SK_USE_CSUM */ + +#endif /* CONFIG_SK98 */ diff --git a/drivers/sk98lin/skge.c b/drivers/sk98lin/skge.c index 49ef8b310..01a72e13c 100644 --- a/drivers/sk98lin/skge.c +++ b/drivers/sk98lin/skge.c @@ -340,6 +340,10 @@   *   ******************************************************************************/ +#include <config.h> + +#ifdef CONFIG_SK98 +  #include	"h/skversion.h"  #if 0  #include	<linux/module.h> @@ -4862,6 +4866,8 @@ int	l;  #endif +#endif /* CONFIG_SK98 */ +  /*   * Local variables:   * compile-command: "make" diff --git a/drivers/sk98lin/skgehwt.c b/drivers/sk98lin/skgehwt.c index 8996b7fae..10c366d01 100644 --- a/drivers/sk98lin/skgehwt.c +++ b/drivers/sk98lin/skgehwt.c @@ -73,6 +73,10 @@   ******************************************************************************/ +#include <config.h> + +#ifdef CONFIG_SK98 +  /*  	Event queue and dispatcher  */ @@ -211,4 +215,6 @@ SK_IOC	Ioc)	/* IoContext */  	SkTimerDone(pAC,Ioc) ;  } +#endif /* CONFIG_SK98 */ +  /* End of file */ diff --git a/drivers/sk98lin/skgeinit.c b/drivers/sk98lin/skgeinit.c index 42a64248a..cb6e20f02 100644 --- a/drivers/sk98lin/skgeinit.c +++ b/drivers/sk98lin/skgeinit.c @@ -393,6 +393,10 @@   *   ******************************************************************************/ +#include <config.h> + +#ifdef CONFIG_SK98 +  #include "h/skdrv1st.h"  #include "h/skdrv2nd.h" @@ -2364,3 +2368,5 @@ int		Port)		/* Port to configure */  	return(0);  }	/* SkGeInitPort */ + +#endif /* CONFIG_SK98 */ diff --git a/drivers/sk98lin/skgemib.c b/drivers/sk98lin/skgemib.c index 3f5a7f5b9..ab85ccd4e 100644 --- a/drivers/sk98lin/skgemib.c +++ b/drivers/sk98lin/skgemib.c @@ -50,6 +50,10 @@   *	   ****************************************************************************/ +#include <config.h> + +#ifdef CONFIG_SK98 +  /*   * PRIVATE OID handler function prototypes   */ @@ -1054,3 +1058,4 @@ PNMI_STATIC const SK_PNMI_TAB_ENTRY IdTable[] = {  		SK_PNMI_RO, Vct, 0},  }; +#endif /* CONFIG_SK98 */ diff --git a/drivers/sk98lin/skgepnmi.c b/drivers/sk98lin/skgepnmi.c index 498c85d3c..d1c1a3e7d 100644 --- a/drivers/sk98lin/skgepnmi.c +++ b/drivers/sk98lin/skgepnmi.c @@ -432,6 +432,10 @@   ****************************************************************************/ +#include <config.h> + +#ifdef CONFIG_SK98 +  static const char SysKonnectFileId[] =  	"@(#) $Id: skgepnmi.c,v 1.102 2002/12/16 14:03:24 tschilli Exp $"  	" (C) SysKonnect."; @@ -8303,3 +8307,5 @@ SK_U32		PhysPortIndex)  	}  } /* CheckVctStatus */ + +#endif /* CONFIG_SK98 */ diff --git a/drivers/sk98lin/skgesirq.c b/drivers/sk98lin/skgesirq.c index 581368ea2..c7c04b70e 100644 --- a/drivers/sk98lin/skgesirq.c +++ b/drivers/sk98lin/skgesirq.c @@ -337,6 +337,10 @@   *   ******************************************************************************/ +#include <config.h> + +#ifdef CONFIG_SK98 +  /*   *	Special Interrupt handler   * @@ -2408,4 +2412,6 @@ SK_U16	IStatus)	/* Interrupt Status */  }	/* SkPhyIsrLone */  #endif /* OTHER_PHY */ +#endif /* CONFIG_SK98 */ +  /* End of File */ diff --git a/drivers/sk98lin/ski2c.c b/drivers/sk98lin/ski2c.c index 671f76ea5..b262f29a8 100644 --- a/drivers/sk98lin/ski2c.c +++ b/drivers/sk98lin/ski2c.c @@ -228,6 +228,10 @@   ******************************************************************************/ +#include <config.h> + +#ifdef CONFIG_SK98 +  /*   *	I2C Protocol   */ @@ -1497,3 +1501,5 @@ SK_EVPARA	Para)	/* Event specific Parameter */  }	/* SkI2cEvent*/  #endif	/* !SK_DIAG */ + +#endif /* CONFIG_SK98 */ diff --git a/drivers/sk98lin/sklm80.c b/drivers/sk98lin/sklm80.c index 51c7cc46a..1c96ee3a3 100644 --- a/drivers/sk98lin/sklm80.c +++ b/drivers/sk98lin/sklm80.c @@ -98,6 +98,10 @@   ******************************************************************************/ +#include <config.h> + +#ifdef CONFIG_SK98 +  /*  	LM80 functions  */ @@ -284,3 +288,5 @@ SK_SENSOR	*pSen)	/* Sensor to be read */  	/* Not completed */  	return(0);  } + +#endif /* CONFIG_SK98 */ diff --git a/drivers/sk98lin/skproc.c b/drivers/sk98lin/skproc.c index a23e55c50..ecba70481 100644 --- a/drivers/sk98lin/skproc.c +++ b/drivers/sk98lin/skproc.c @@ -70,6 +70,10 @@   *   ******************************************************************************/ +#include <config.h> + +#ifdef CONFIG_SK98 +  #include <linux/proc_fs.h>  #include "h/skdrv1st.h" @@ -511,5 +515,4 @@ char * SkNumber(char * str, long long num, int base, int size, int precision  	return strorg;  } - - +#endif /* CONFIG_SK98 */ diff --git a/drivers/sk98lin/skqueue.c b/drivers/sk98lin/skqueue.c index c279cd17a..c9740e316 100644 --- a/drivers/sk98lin/skqueue.c +++ b/drivers/sk98lin/skqueue.c @@ -87,6 +87,10 @@   ******************************************************************************/ +#include <config.h> + +#ifdef CONFIG_SK98 +  /*  	Event queue and dispatcher  */ @@ -233,4 +237,6 @@ SK_IOC	Ioc)	/* Io context */  	return(0) ;  } +#endif /* CONFIG_SK98 */ +  /* End of file */ diff --git a/drivers/sk98lin/skrlmt.c b/drivers/sk98lin/skrlmt.c index 26b3f7400..1e707c997 100644 --- a/drivers/sk98lin/skrlmt.c +++ b/drivers/sk98lin/skrlmt.c @@ -280,6 +280,10 @@   *   ******************************************************************************/ +#include <config.h> + +#ifdef CONFIG_SK98 +  #ifndef	lint  static const char SysKonnectFileId[] =  	"@(#) $Id: skrlmt.c,v 1.68 2003/01/31 15:26:56 rschmidt Exp $ (C) SysKonnect."; @@ -3500,3 +3504,5 @@ SK_EVPARA	Para)	/* Event-specific parameter */  #ifdef __cplusplus  }  #endif	/* __cplusplus */ + +#endif /* CONFIG_SK98 */ diff --git a/drivers/sk98lin/sktimer.c b/drivers/sk98lin/sktimer.c index e8894d24e..67431d96a 100644 --- a/drivers/sk98lin/sktimer.c +++ b/drivers/sk98lin/sktimer.c @@ -72,6 +72,10 @@   ******************************************************************************/ +#include <config.h> + +#ifdef CONFIG_SK98 +  /*  	Event queue and dispatcher  */ @@ -288,4 +292,6 @@ int	Restart)	/* Do we need to restart the Hardware timer ? */  	}  } +#endif /* CONFIG_SK98 */ +  /* End of file */ diff --git a/drivers/sk98lin/skvpd.c b/drivers/sk98lin/skvpd.c index 68c65d16b..f4558fabf 100644 --- a/drivers/sk98lin/skvpd.c +++ b/drivers/sk98lin/skvpd.c @@ -160,6 +160,10 @@   *   ******************************************************************************/ +#include <config.h> + +#ifdef CONFIG_SK98 +  /*  	Please refer skvpd.txt for infomation how to include this module   */ @@ -1323,3 +1327,4 @@ char	*msg)	/* error log message */  	(void)VpdUpdate(pAC, IoC);  } +#endif /* CONFIG_SK98 */ diff --git a/drivers/sk98lin/skxmac2.c b/drivers/sk98lin/skxmac2.c index c339ecaa8..9c87b2393 100644 --- a/drivers/sk98lin/skxmac2.c +++ b/drivers/sk98lin/skxmac2.c @@ -410,6 +410,10 @@   *   ******************************************************************************/ +#include <config.h> + +#ifdef CONFIG_SK98 +  #include "h/skdrv1st.h"  #include "h/skdrv2nd.h" @@ -4389,4 +4393,6 @@ SK_BOOL	StartTest)	/* flag for start / get result */  	return(0);  }	/* SkGmCableDiagStatus */ +#endif /* CONFIG_SK98 */ +  /* End of file */ diff --git a/drivers/sk98lin/uboot_skb.c b/drivers/sk98lin/uboot_skb.c index 9d86beabd..b87ad163f 100644 --- a/drivers/sk98lin/uboot_skb.c +++ b/drivers/sk98lin/uboot_skb.c @@ -23,6 +23,10 @@   * MA 02111-1307 USA   */ +#include <config.h> + +#ifdef CONFIG_SK98 +  #include <common.h>  #include "u-boot_compat.h" @@ -114,3 +118,5 @@ void skb_put(struct sk_buff *skb, unsigned int len)  {  	skb->len+=len;  } + +#endif /* CONFIG_SK98 */ diff --git a/include/configs/P3G4.h b/include/configs/P3G4.h index 17774a391..77123842d 100644 --- a/include/configs/P3G4.h +++ b/include/configs/P3G4.h @@ -99,6 +99,7 @@  #define CONFIG_BOOTP_MASK	(CONFIG_BOOTP_DEFAULT | \  				 CONFIG_BOOTP_BOOTFILESIZE) +#define	CONFIG_TIMESTAMP		/* Print image info with timestamp */  #define CONFIG_COMMANDS	(CONFIG_CMD_DFL | CFG_CMD_ASKENV) diff --git a/include/configs/SL8245.h b/include/configs/SL8245.h index 4b69456e4..61896d0d7 100644 --- a/include/configs/SL8245.h +++ b/include/configs/SL8245.h @@ -51,6 +51,8 @@  #define CONFIG_BOOTDELAY	5 +#define	CONFIG_TIMESTAMP		/* Print image info with timestamp */ +  #define CONFIG_COMMANDS		(CONFIG_CMD_DFL | CFG_CMD_PCI)  /* this must be included AFTER the definition of CONFIG_COMMANDS (if any) 	*/ @@ -68,7 +70,7 @@  /* Print Buffer Size   */  #define CFG_PBSIZE	(CFG_CBSIZE + sizeof(CFG_PROMPT) + 16) -#define CFG_MAXARGS	8		/* Max number of command args	*/ +#define CFG_MAXARGS	32		/* Max number of command args	*/  #define CFG_BARGSIZE	CFG_CBSIZE	/* Boot Argument Buffer Size	*/  #define CFG_LOAD_ADDR	0x00400000	/* Default load address		*/ diff --git a/include/configs/Sandpoint8240.h b/include/configs/Sandpoint8240.h index 799d5d65b..5bf184ea9 100644 --- a/include/configs/Sandpoint8240.h +++ b/include/configs/Sandpoint8240.h @@ -46,8 +46,39 @@  #endif  #define CONFIG_CONS_INDEX	1 -#define CONFIG_BAUDRATE		115200 -#define CONFIG_DRAM_SPEED	100		/* MHz				*/ +#define CONFIG_BAUDRATE		9600 + +#define CONFIG_BOOTDELAY	5	/* autoboot after 5 seconds	*/ + +#define	CONFIG_TIMESTAMP		/* Print image info with timestamp */ + +#define CONFIG_PREBOOT	"echo;"	\ +	"echo Type \"run net_nfs\" to mount root filesystem over NFS;" \ +	"echo" + +#undef	CONFIG_BOOTARGS + +#define	CONFIG_EXTRA_ENV_SETTINGS					\ +	"netdev=eth0\0"							\ +	"nfsargs=setenv bootargs root=/dev/nfs rw "			\ +		"nfsroot=$(serverip):$(rootpath)\0"			\ +	"ramargs=setenv bootargs root=/dev/ram rw\0"			\ +	"addip=setenv bootargs $(bootargs) "				\ +		"ip=$(ipaddr):$(serverip):$(gatewayip):$(netmask)"	\ +		":$(hostname):$(netdev):off panic=1\0"			\ +	"net_self=tftp $(kernel_addr) $(bootfile);"			\ +		"tftp $(ramdisk_addr) $(ramdisk);"			\ +		"run ramargs addip;"					\ +		"bootm $(kernel_addr) $(ramdisk_addr)\0"		\ +	"net_nfs=tftp $(kernel_addr) $(bootfile);"			\ +		"run nfsargs addip;bootm\0"				\ +	"rootpath=/opt/eldk/ppc_82xx\0"					\ +	"bootfile=/tftpboot/SP8240/uImage\0"				\ +	"ramdisk=/tftpboot/SP8240/uRamdisk\0"				\ +	"kernel_addr=200000\0"						\ +	"ramdisk_addr=400000\0"						\ +	"" +#define CONFIG_BOOTCOMMAND	"run flash_self"  #define CONFIG_COMMANDS		( (CONFIG_CMD_DFL & ~CFG_CMD_AUTOSCRIPT) | \  				  CFG_CMD_ELF    | \ @@ -59,6 +90,7 @@  /* this must be included AFTER the definition of CONFIG_COMMANDS (if any)	*/  #include <cmd_confdefs.h> +#define CONFIG_DRAM_SPEED	100		/* MHz				*/  /*   * Miscellaneous configurable options diff --git a/include/configs/trab.h b/include/configs/trab.h index 4c33bdb43..d96241a2b 100644 --- a/include/configs/trab.h +++ b/include/configs/trab.h @@ -1,5 +1,5 @@  /* - * (C) Copyright 2002 + * (C) Copyright 2002-2003   * Gary Jennejohn <gj@denx.de>   *   * Configuation settings for the TRAB board. @@ -40,6 +40,7 @@  #define CONFIG_S3C2400		1	/* in a SAMSUNG S3C2400 SoC	*/  #define CONFIG_TRAB		1	/* on a TRAB Board		*/  #undef CONFIG_TRAB_50MHZ		/* run the CPU at 50 MHz	*/ +#define LITTLEENDIAN		1	/* used by usb_ohci.c		*/  /* input clock of PLL */  #define CONFIG_SYS_CLK_FREQ	12000000 /* TRAB has 12 MHz input clock */ @@ -67,6 +68,11 @@  #define CFG_EEPROM_PAGE_WRITE_BITS 3	/* 8 bytes page write mode on 24C04 */  #define CFG_EEPROM_PAGE_WRITE_DELAY_MS 10 +/* USB stuff */ +#define CONFIG_USB_OHCI		1 +#define CONFIG_USB_STORAGE	1 +#define CONFIG_DOS_PARTITION	1 +  /*   * Size of malloc() pool   */ @@ -139,6 +145,8 @@  				 CONFIG_COMMANDS_ADD_HWFLOW	| \  				 CONFIG_COMMANDS_ADD_VFD	| \  				 CONFIG_COMMANDS_ADD_EEPROM	| \ +				 CFG_CMD_USB			| \ +				 CFG_CMD_FAT			| \  				 CONFIG_COMMANDS_I2C		)  #else  #define CONFIG_COMMANDS		(CONFIG_CMD_DFL			| \ @@ -147,9 +155,14 @@  				 CONFIG_COMMANDS_ADD_HWFLOW	| \  				 CONFIG_COMMANDS_ADD_VFD	| \  				 CONFIG_COMMANDS_ADD_EEPROM	| \ +				 CFG_CMD_USB			| \ +				 CFG_CMD_FAT			| \  				 CONFIG_COMMANDS_I2C		)  #endif +/* moved up */ +#define CFG_HUSH_PARSER		1	/* use "hush" command parser	*/ +  /* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */  #include <cmd_confdefs.h> @@ -164,6 +177,28 @@  #define CONFIG_BOOTCOMMAND	"run flash_nfs"  #ifndef CONFIG_BIG_FLASH +#ifdef CFG_HUSH_PARSER +#define	CONFIG_EXTRA_ENV_SETTINGS	\ +	"nfs_args=setenv bootargs root=/dev/nfs rw " \ +		"nfsroot=$serverip:$rootpath\0" \ +	"rootpath=/opt/eldk/arm_920TDI\0" \ +	"ram_args=setenv bootargs root=/dev/ram rw\0" \ +	"add_net=setenv bootargs $bootargs ethaddr=$ethaddr " \ +		"ip=$ipaddr:$serverip:$gatewayip:$netmask:$hostname::off\0" \ +	"add_misc=setenv bootargs $bootargs console=ttyS0 panic=1\0" \ +	"load=tftp 0xC100000 /tftpboot/TRAB/u-boot.bin\0" \ +	"update=protect off 1:0-8;era 1:0-8;cp.b 0xc100000 0 $filesize;" \ +		"setenv filesize;saveenv\0" \ +	"loadfile=/tftpboot/TRAB/uImage\0" \ +	"loadaddr=c400000\0" \ +	"net_load=tftpboot $loadaddr $loadfile\0" \ +	"net_nfs=run net_load nfs_args add_net add_misc;bootm\0" \ +	"kernel_addr=00040000\0" \ +	"flash_nfs=run nfs_args add_net add_misc;bootm $kernel_addr\0" \ +	"mdm_init1=ATZ\0" \ +	"mdm_init2=ATS0=1\0" \ +	"mdm_flow_control=rts/cts\0" +#else /* !CFG_HUSH_PARSER */  #define	CONFIG_EXTRA_ENV_SETTINGS	\  	"nfs_args=setenv bootargs root=/dev/nfs rw " \  		"nfsroot=$(serverip):$(rootpath)\0" \ @@ -184,7 +219,29 @@  	"mdm_init1=ATZ\0" \  	"mdm_init2=ATS0=1\0" \  	"mdm_flow_control=rts/cts\0" +#endif /* CFG_HUSH_PARSER */  #else	/* CONFIG_BIG_FLASH */ +#ifdef CFG_HUSH_PARSER +#define	CONFIG_EXTRA_ENV_SETTINGS	\ +	"nfs_args=setenv bootargs root=/dev/nfs rw " \ +		"nfsroot=$serverip:$rootpath\0" \ +	"rootpath=/opt/eldk/arm_920TDI\0" \ +	"ram_args=setenv bootargs root=/dev/ram rw\0" \ +	"add_net=setenv bootargs $bootargs ethaddr=$ethaddr " \ +		"ip=$ipaddr:$serverip:$gatewayip:$netmask:$hostname::off\0" \ +	"add_misc=setenv bootargs $bootargs console=ttyS0 panic=1\0" \ +	"load=tftp 0xC100000 /tftpboot/TRAB/u-boot.bin\0" \ +	"update=protect off 1:0;era 1:0;cp.b 0xc100000 0 $filesize\0" \ +	"loadfile=/tftpboot/TRAB/uImage\0" \ +	"loadaddr=c400000\0" \ +	"net_load=tftpboot $loadaddr $loadfile\0" \ +	"net_nfs=run net_load nfs_args add_net add_misc;bootm\0" \ +	"kernel_addr=00040000\0" \ +	"flash_nfs=run nfs_args add_net add_misc;bootm $kernel_addr\0" \ +	"mdm_init1=ATZ\0" \ +	"mdm_init2=ATS0=1\0" \ +	"mdm_flow_control=rts/cts\0" +#else /* !CFG_HUSH_PARSER */  #define	CONFIG_EXTRA_ENV_SETTINGS	\  	"nfs_args=setenv bootargs root=/dev/nfs rw " \  		"nfsroot=$(serverip):$(rootpath)\0" \ @@ -204,6 +261,7 @@  	"mdm_init1=ATZ\0" \  	"mdm_init2=ATS0=1\0" \  	"mdm_flow_control=rts/cts\0" +#endif /* CFG_HUSH_PARSER */  #endif	/* CONFIG_BIG_FLASH */  #if 0	/* disabled for development */ @@ -223,7 +281,6 @@   */  #define	CFG_LONGHELP				/* undef to save memory		*/  #define	CFG_PROMPT		"TRAB # "	/* Monitor Command Prompt	*/ -/* #define CFG_HUSH_PARSER		1 */	/* use "hush" command parser	*/  #ifdef	CFG_HUSH_PARSER  #define CFG_PROMPT_HUSH_PS2	"> "  #endif diff --git a/include/usb.h b/include/usb.h index edb61201a..0008a9a74 100644 --- a/include/usb.h +++ b/include/usb.h @@ -169,7 +169,7 @@ struct usb_device {   * this is how the lowlevel part communicate with the outer world   */ -#ifdef CONFIG_USB_UHCI +#if defined(CONFIG_USB_UHCI) || defined(CONFIG_USB_OHCI)  int usb_lowlevel_init(void);  int usb_lowlevel_stop(void);  int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,int transfer_len); @@ -228,6 +228,11 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size);  int usb_set_interface(struct usb_device *dev, int interface, int alternate);  /* big endian -> little endian conversion */ +/* some CPUs are already little endian e.g. the ARM920T */ +#ifdef LITTLEENDIAN +#define swap_16(x) ((unsigned short)(x)) +#define swap_32(x) ((unsigned long)(x)) +#else  #define swap_16(x) \  	((unsigned short)( \  		(((unsigned short)(x) & (unsigned short)0x00ffU) << 8) | \ @@ -238,6 +243,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate);  		(((unsigned long)(x) & (unsigned long)0x0000ff00UL) <<  8) | \  		(((unsigned long)(x) & (unsigned long)0x00ff0000UL) >>  8) | \  		(((unsigned long)(x) & (unsigned long)0xff000000UL) >> 24) )) +#endif /* LITTLEENDIAN */  /*   * Calling this entity a "pipe" is glorifying it. A USB pipe |