diff options
37 files changed, 3042 insertions, 422 deletions
| @@ -2443,9 +2443,27 @@ Date:	Sat Oct 28 02:29:14 2006 +0200      Enable commandline editing and hush shell on all TQM boards. +<<<<<<< master +* Code cleanup + +* Various USB related patches +  - Add support for mpc8xx USB device. +  - Add support for Common Device Class - Abstract Control Model USB console. +  - Add support for flow control in USB slave devices. +  - Add support for switching between gserial and cdc_acm using environment. +  - Minor changes to usbdcore_omap1510.c usbdcore_omap1510.h +  - Update usbcore slightly to ease host enumeration. +  - Fix non-portable endian problems in usbdcore and usbdcore_ep0. +  - Add AdderUSB_config as a defconfig to enable usage of the USB console +    by default with the Adder87x U-Boot port. +  Patch by Bryan O'Donoghue <bodonoghue@codehermit.ie>, 29 May 2006 + +* Cleanup trab board for GCC-4.x +=======  commit 8078f1a5f63a739b8533478f6c2b62fb1e2f79d7  Author: Wolfgang Denk <wd@pollux.denx.de>  Date:	Sat Oct 28 02:28:02 2006 +0200 +>>>>>>> trunk      README says CFG_AUTO_COMPLETE, but ocde uses CONFIG_AUTO_COMPLETE @@ -122,7 +122,7 @@ ifeq ($(HOSTARCH),$(ARCH))  CROSS_COMPILE =  else  ifeq ($(ARCH),ppc) -CROSS_COMPILE = powerpc-linux- +CROSS_COMPILE = ppc_8xx-  endif  ifeq ($(ARCH),arm)  CROSS_COMPILE = arm-linux- @@ -636,6 +636,9 @@ AdderII_config  \  	@echo "#define CONFIG_MPC852T" > $(obj)include/config.h)  	@$(MKCONFIG) -a Adder ppc mpc8xx adder +AdderUSB_config:	unconfig +	@./mkconfig -a AdderUSB ppc mpc8xx adder +  ADS860_config     \  FADS823_config    \  FADS850SAR_config \ @@ -883,6 +883,68 @@ The following options need to be configured:  				for differential drivers: 0x00001000  				for single ended drivers: 0x00005000 +- USB Device: +		Define the below if you wish to use the USB console. +		Once firmware is rebuilt from a serial console issue the +		command "setenv stdin usbtty; setenv stdout usbtty" and +		attach your usb cable. The Unix command "dmesg" should print +		it has found a new device. The environment variable usbtty +		can be set to gserial or cdc_acm to enable your device to +		appear to a USB host as a Linux gserial device or a +		Common Device Class Abstract Control Model serial device. +		If you select usbtty = gserial you should be able to enumerate +		a Linux host by +		# modprobe usbserial vendor=0xVendorID product=0xProductID +		else if using cdc_acm, simply setting the environment +		variable usbtty to be cdc_acm should suffice. The following +		might be defined in YourBoardName.h + +			CONFIG_USB_DEVICE +			Define this to build a UDC device + +			CONFIG_USB_TTY +			Define this to have a tty type of device available to +			talk to the UDC device + +			CFG_CONSOLE_IS_IN_ENV +			Define this if you want stdin, stdout &/or stderr to +			be set to usbtty. + +			mpc8xx: +				CFG_USB_EXTC_CLK 0xBLAH +				Derive USB clock from external clock "blah" +				- CFG_USB_EXTC_CLK 0x02 + +				CFG_USB_BRG_CLK 0xBLAH +				Derive USB clock from brgclk +				- CFG_USB_BRG_CLK 0x04 + +		If you have a USB-IF assigned VendorID then you may wish to +		define your own vendor specific values either in BoardName.h +		or directly in usbd_vendor_info.h. If you don't define +		CONFIG_USBD_MANUFACTURER, CONFIG_USBD_PRODUCT_NAME, +		CONFIG_USBD_VENDORID and CONFIG_USBD_PRODUCTID, then U-Boot +		should pretend to be a Linux device to it's target host. + +			CONFIG_USBD_MANUFACTURER +			Define this string as the name of your company for +			- CONFIG_USBD_MANUFACTURER "my company" + +			CONFIG_USBD_PRODUCT_NAME +			Define this string as the name of your product +			- CONFIG_USBD_PRODUCT_NAME "acme usb device" + +			CONFIG_USBD_VENDORID +			Define this as your assigned Vendor ID from the USB +			Implementors Forum. This *must* be a genuine Vendor ID +			to avoid polluting the USB namespace. +			- CONFIG_USBD_VENDORID 0xFFFF + +			CONFIG_USBD_PRODUCTID +			Define this as the unique Product ID +			for your device +			- CONFIG_USBD_PRODUCTID 0xFFFF +  - MMC Support:  		The MMC controller on the Intel PXA is supported. To diff --git a/board/delta/delta.c b/board/delta/delta.c index b127ac8ca..6e227748b 100644 --- a/board/delta/delta.c +++ b/board/delta/delta.c @@ -1,10 +1,6 @@  /* - * (C) Copyright 2002 - * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net - * - * (C) Copyright 2002 - * Sysgo Real-Time Solutions, GmbH <www.elinos.com> - * Marius Groeger <mgroeger@sysgo.de> + * (C) Copyright 2006 + * DENX Software Engineering   *   * See file CREDITS for list of people who contributed to this   * project. @@ -98,7 +94,6 @@ int board_late_init(void)  	return 0;  } -  /*   * Magic Key Handling, mainly copied from board/lwmon/lwmon.c   */ @@ -324,6 +319,12 @@ static void init_DA9030()  		return;  	} +	val = 0x80; +	if(i2c_write(addr, IRQ_MASK_B, 1, &val, 1)) { +		printf("Error accessing DA9030 via i2c.\n"); +		return; +	} +  	i2c_reg_write(addr, REG_CONTROL_1_97, 0xfd); /* disable LDO1, enable LDO6 */  	i2c_reg_write(addr, LDO2_3, 0xd1);	/* LDO2 =1,9V, LDO3=3,1V */  	i2c_reg_write(addr, LDO4_5, 0xcc);	/* LDO2 =1,9V, LDO3=3,1V */ diff --git a/board/trab/auto_update.c b/board/trab/auto_update.c index f4074aecb..6f903d2b0 100644 --- a/board/trab/auto_update.c +++ b/board/trab/auto_update.c @@ -34,7 +34,7 @@  #ifdef CONFIG_AUTO_UPDATE -#ifndef CONFIG_USB_OHCI +#ifndef CONFIG_USB_OHCI_NEW  #error "must define CONFIG_USB_OHCI"  #endif diff --git a/cpu/arm920t/at91rm9200/Makefile b/cpu/arm920t/at91rm9200/Makefile index 8d4e478fb..eaabad26a 100644 --- a/cpu/arm920t/at91rm9200/Makefile +++ b/cpu/arm920t/at91rm9200/Makefile @@ -26,7 +26,7 @@ include $(TOPDIR)/config.mk  LIB	= $(obj)lib$(SOC).a  COBJS	= bcm5221.o dm9161.o ether.o i2c.o interrupts.o \ -	  lxt972.o serial.o usb_ohci.o +	  lxt972.o serial.o usb.o  SOBJS	= lowlevel_init.o  SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c) diff --git a/cpu/arm920t/at91rm9200/usb.c b/cpu/arm920t/at91rm9200/usb.c new file mode 100644 index 000000000..366262e4c --- /dev/null +++ b/cpu/arm920t/at91rm9200/usb.c @@ -0,0 +1,53 @@ +/* + * (C) Copyright 2006 + * DENX Software Engineering <mk@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 + */ + +#include <common.h> + +#if defined(CONFIG_USB_OHCI_NEW) && defined(CFG_USB_OHCI_CPU_INIT) +# ifdef CONFIG_AT91RM9200 + +#include <asm/arch/hardware.h> + +int usb_cpu_init() +{ +	/* Enable USB host clock. */ +	*AT91C_PMC_SCER = AT91C_PMC_UHP;	/* 48MHz clock enabled for UHP */ +	*AT91C_PMC_PCER = 1 << AT91C_ID_UHP;	/* Peripheral Clock Enable Register */ +	return 0; +} + +int usb_cpu_stop() +{ +	/* Initialization failed */ +	*AT91C_PMC_PCDR = 1 << AT91C_ID_UHP;	/* Peripheral Clock Disable Register */ +	*AT91C_PMC_SCDR = AT91C_PMC_UHP;	/* 48MHz clock disabled for UHP */ +	return 0; +} + +int usb_cpu_init_fail() +{ +	usb_cpu_stop(); +} + +# endif /* CONFIG_AT91RM9200 */ +#endif /* defined(CONFIG_USB_OHCI) && defined(CFG_USB_OHCI_CPU_INIT) */ diff --git a/cpu/arm920t/s3c24x0/Makefile b/cpu/arm920t/s3c24x0/Makefile index 3a7c4b35f..0ff36c596 100644 --- a/cpu/arm920t/s3c24x0/Makefile +++ b/cpu/arm920t/s3c24x0/Makefile @@ -26,7 +26,7 @@ include $(TOPDIR)/config.mk  LIB	= $(obj)lib$(SOC).a  COBJS	= i2c.o interrupts.o serial.o speed.o \ -	  usb_ohci.o +	  usb.o  SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)  OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS)) diff --git a/cpu/arm920t/s3c24x0/usb.c b/cpu/arm920t/s3c24x0/usb.c new file mode 100644 index 000000000..ef5d5bf71 --- /dev/null +++ b/cpu/arm920t/s3c24x0/usb.c @@ -0,0 +1,72 @@ +/* + * (C) Copyright 2006 + * DENX Software Engineering <mk@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 + */ + +#include <common.h> + +#if defined(CONFIG_USB_OHCI_NEW) && defined(CFG_USB_OHCI_CPU_INIT) +# if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410) + +#if defined(CONFIG_S3C2400) +# include <s3c2400.h> +#elif defined(CONFIG_S3C2410) +# include <s3c2410.h> +#endif + +int usb_cpu_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); + +	return 0; +} + +int usb_cpu_stop (void) +{ +	S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER(); +	/* may not want to do this */ +	clk_power->CLKCON &= ~(1 << 4); +	return 0; +} + +int usb_cpu_init_fail (void) +{ +	S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER(); +	clk_power->CLKCON &= ~(1 << 4); +	return 0; +} + +# endif /* defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410) */ +#endif /* defined(CONFIG_USB_OHCI) && defined(CFG_USB_OHCI_CPU_INIT) */ diff --git a/cpu/mpc5xxx/Makefile b/cpu/mpc5xxx/Makefile index 235adb7c0..312b0bfc6 100644 --- a/cpu/mpc5xxx/Makefile +++ b/cpu/mpc5xxx/Makefile @@ -28,7 +28,7 @@ LIB	= $(obj)lib$(CPU).a  START	= start.o  SOBJS	= io.o firmware_sc_task_bestcomm.impl.o firmware_sc_task.impl.o  COBJS	= i2c.o traps.o cpu.o cpu_init.o fec.o ide.o interrupts.o \ -	  loadtask.o pci_mpc5200.o serial.o speed.o usb_ohci.o +	  loadtask.o pci_mpc5200.o serial.o speed.o usb_ohci.o usb.o  SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)  OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS)) diff --git a/cpu/ppc4xx/Makefile b/cpu/ppc4xx/Makefile index 96f0f62eb..1347e0f9f 100644 --- a/cpu/ppc4xx/Makefile +++ b/cpu/ppc4xx/Makefile @@ -27,12 +27,12 @@ LIB	= $(obj)lib$(CPU).a  START	= start.o resetvec.o kgdb.o  SOBJS	= dcr.o -COBJS	= 405gp_pci.o 4xx_enet.o \ +COBJS	= 405gp_pci.o 440spe_pcie.o 4xx_enet.o \  	  bedbug_405.o commproc.o \  	  cpu.o cpu_init.o i2c.o interrupts.o \  	  miiphy.o ndfc.o sdram.o serial.o \  	  40x_spd_sdram.o 44x_spd_ddr.o 44x_spd_ddr2.o speed.o \ -	  tlb.o traps.o usb_ohci.o usbdev.o \ +	  tlb.o traps.o usb_ohci.o usbdev.o usb.o \  	  440spe_pcie.o  SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) diff --git a/cpu/pxa/Makefile b/cpu/pxa/Makefile index cded7ffd3..8b4367e20 100644 --- a/cpu/pxa/Makefile +++ b/cpu/pxa/Makefile @@ -26,7 +26,7 @@ include $(TOPDIR)/config.mk  LIB	= $(obj)lib$(CPU).a  START	= start.o -COBJS	= serial.o interrupts.o cpu.o i2c.o pxafb.o mmc.o +COBJS	= serial.o interrupts.o cpu.o i2c.o pxafb.o mmc.o usb.o  SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)  OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS)) diff --git a/cpu/pxa/usb.c b/cpu/pxa/usb.c new file mode 100644 index 000000000..5d273cb35 --- /dev/null +++ b/cpu/pxa/usb.c @@ -0,0 +1,78 @@ +/* + * (C) Copyright 2006 + * Markus Klotzbuecher, DENX Software Engineering <mk@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 + */ + +#include <common.h> + +#if defined(CONFIG_USB_OHCI_NEW) && defined(CFG_USB_OHCI_CPU_INIT) +# ifdef CONFIG_CPU_MONAHANS + +#include <asm/arch/pxa-regs.h> + +int usb_cpu_init() +{ +	/* Enable USB host clock. */ +	CKENA |= (CKENA_2_USBHOST |  CKENA_20_UDC); +	udelay(100); + +	/* Configure Port 2 for Host (USB Client Registers) */ +	UP2OCR = 0x3000c; + +#if 0 +	GPIO2_2 = 0x801; /* USBHPEN - Alt. Fkt. 1 */ +	GPIO3_2 = 0x801; /* USBHPWR - Alt. Fkt. 1 */ +#endif + +	UHCHR |= UHCHR_FHR; +	wait_ms(11); +	UHCHR &= ~UHCHR_FHR; + +	UHCHR |= UHCHR_FSBIR; +	while (UHCHR & UHCHR_FSBIR) +		udelay(1); + +#if 0 +	UHCHR |= UHCHR_PCPL; /* USBHPEN is active low */ +	UHCHR |= UHCHR_PSPL; /* USBHPWR is active low */ +#endif + +	UHCHR &= ~UHCHR_SSEP0; +	UHCHR &= ~UHCHR_SSEP1; +	UHCHR &= ~UHCHR_SSE; + +	return 0; +} + +int usb_cpu_stop() +{ +	/* may not want to do this */ +	/* CKENA &= ~(CKENA_2_USBHOST |  CKENA_20_UDC); */ +	return 0; +} + +int usb_cpu_init_fail() +{ +	return 0; +} + +# endif /* CONFIG_CPU_MONAHANS */ +#endif /* defined(CONFIG_USB_OHCI) && defined(CFG_USB_OHCI_CPU_INIT) */ diff --git a/doc/README.generic_usb_ohci b/doc/README.generic_usb_ohci new file mode 100644 index 000000000..017c69ab0 --- /dev/null +++ b/doc/README.generic_usb_ohci @@ -0,0 +1,43 @@ +Notes on the the generic USB-OHCI driver +======================================== + +This driver (drivers/usb_ohci.[ch]) is the result of the merge of +various existing OHCI drivers that were basically identical beside +cpu/board dependant initalization. This initalization has been moved +into cpu/board directories and are called via the hooks below. + +Configuration options +---------------------- + +CONFIG_USB_OHCI_NEW: enable the new OHCI driver + +CFG_USB_OHCI_BOARD_INIT: call the board dependant hooks: + +  - extern int usb_board_init(void); +  - extern int usb_board_stop(void); +  - extern int usb_cpu_init_fail(void); + +CFG_USB_OHCI_CPU_INIT: call the cpu dependant hooks: + +  - extern int usb_cpu_init(void); +  - extern int usb_cpu_stop(void); +  - extern int usb_cpu_init_fail(void); + +CFG_USB_OHCI_REGS_BASE: defines the base address of the OHCI registers + +CFG_USB_OHCI_SLOT_NAME: slot name + +CFG_USB_OHCI_MAX_ROOT_PORTS: maximal number of ports of the root hub. + + +Endianness issues +------------------ + +The LITTLEENDIAN #define determines if the 'swap_16' and 'swap_32' +macros do byte swapping or not. But some cpus OHCI-controllers such as +ppc4xx and mpc5xxx operate in little endian mode, so some extra ifdefs +were necessary to make this work. + + + + diff --git a/drivers/Makefile b/drivers/Makefile index fffc22a5e..0ca400c68 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -46,7 +46,9 @@ COBJS	= 3c589.o 5701rls.o ali512x.o atmel_usart.o \  	  sl811_usb.o sm501.o smc91111.o smiLynxEM.o \  	  status_led.o sym53c8xx.o systemace.o ahci.o \  	  ti_pci1410a.o tigon3.o tsec.o \ -	  usbdcore.o usbdcore_ep0.o usbdcore_omap1510.o usbtty.o \ +	  usb_ohci.o \ +	  usbdcore.o usbdcore_ep0.o usbdcore_mpc8xx.o usbdcore_omap1510.o \ +	  usbtty.o \  	  videomodes.o w83c553f.o \  	  ks8695eth.o \  	  pxa_pcmcia.o mpc8xx_pcmcia.o tqm8xx_pcmcia.o	\ diff --git a/cpu/arm920t/at91rm9200/usb_ohci.c b/drivers/usb_ohci.c index 5b2c56cff..c5e4c38ef 100644 --- a/cpu/arm920t/at91rm9200/usb_ohci.c +++ b/drivers/usb_ohci.c @@ -21,7 +21,7 @@   *   * 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 + * 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 @@ -43,16 +43,39 @@  #include <common.h>  /* #include <pci.h> no PCI on the S3C24X0 */ -#ifdef CONFIG_USB_OHCI +#ifdef CONFIG_USB_OHCI_NEW -#include <asm/arch/hardware.h> +/* mk: are these really required? */ +#if defined(CONFIG_S3C2400) +# include <s3c2400.h> +#elif defined(CONFIG_S3C2410) +# include <s3c2410.h> +#elif defined(CONFIG_ARM920T) +# include <asm/arch/hardware.h> +#elif defined(CONFIG_CPU_MONAHANS) +# include <asm/arch/pxa-regs.h> +#elif defined(CONFIG_MPC5200) +# include <mpc5xxx.h> +#endif  #include <malloc.h>  #include <usb.h>  #include "usb_ohci.h" -#define OHCI_USE_NPS		/* force NoPowerSwitching mode */ +#define S3C24X0_merge + +#if defined(CONFIG_ARM920T) || \ +    defined(CONFIG_S3C2400) || \ +    defined(CONFIG_S3C2410) || \ +    defined(CONFIG_440EP) || \ +    defined(CONFIG_MPC5200) +# define OHCI_USE_NPS		/* force NoPowerSwitching mode */ +#endif +  #undef OHCI_VERBOSE_DEBUG	/* not always helpful */ +#undef DEBUG +#undef SHOW_INFO +#undef OHCI_FILL_TRACE  /* For initializing controller (mask in an HCFS mode too) */  #define OHCI_CONTROL_INIT \ @@ -77,8 +100,13 @@  #define info(format, arg...) do {} while(0)  #endif -#define m16_swap(x) swap_16(x) -#define m32_swap(x) swap_32(x) +#if defined(CONFIG_440EP) || defined(CONFIG_MPC5200) +# define m16_swap(x) (x) +# define m32_swap(x) (x) +#else +# define m16_swap(x) swap_16(x) +# define m32_swap(x) swap_32(x) +#endif  /* global ohci_t */  static ohci_t gohci; @@ -95,6 +123,12 @@ int got_rhsc;  /* device which was disconnected */  struct usb_device *devgone; +#ifdef S3C24X0_merge +/* flag guarding URB transation */ +int urb_finished = 0; +#endif + +  /*-------------------------------------------------------------------------*/  /* AMD-756 (D2 rev) reports corrupt register contents in some cases. @@ -399,6 +433,17 @@ int sohci_submit_job(struct usb_device *dev, unsigned long pipe, void *buffer,  		err("sohci_submit_job: EPIPE");  		return -1;  	} +#ifdef S3C24X0_merge +	/* if we have an unfinished URB from previous transaction let's +	 * fail and scream as quickly as possible so as not to corrupt +	 * further communication */ +	if (!urb_finished) { +		err("sohci_submit_job: URB NOT FINISHED"); +		return -1; +	} +	/* we're about to begin a new transaction here so mark the URB unfinished */ +	urb_finished = 0; +#endif  	/* every endpoint has a ed, locate and fill it */  	if (!(ed = ep_add_ed (dev, pipe))) { @@ -488,7 +533,7 @@ static int ep_link (ohci_t *ohci, ed_t *edi)  		if (ohci->ed_controltail == NULL) {  			writel (ed, &ohci->regs->ed_controlhead);  		} else { -			ohci->ed_controltail->hwNextED = m32_swap (ed); +			ohci->ed_controltail->hwNextED = m32_swap ((unsigned long)ed);  		}  		ed->ed_prev = ohci->ed_controltail;  		if (!ohci->ed_controltail && !ohci->ed_rm_list[0] && @@ -504,7 +549,7 @@ static int ep_link (ohci_t *ohci, ed_t *edi)  		if (ohci->ed_bulktail == NULL) {  			writel (ed, &ohci->regs->ed_bulkhead);  		} else { -			ohci->ed_bulktail->hwNextED = m32_swap (ed); +			ohci->ed_bulktail->hwNextED = m32_swap ((unsigned long)ed);  		}  		ed->ed_prev = ohci->ed_bulktail;  		if (!ohci->ed_bulktail && !ohci->ed_rm_list[0] && @@ -525,8 +570,10 @@ static int ep_link (ohci_t *ohci, ed_t *edi)   * 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) +static int ep_unlink (ohci_t *ohci, ed_t *edi)  { +	volatile ed_t *ed = edi; +  	ed->hwINFO |= m32_swap (OHCI_ED_SKIP);  	switch (ed->type) { @@ -571,12 +618,14 @@ static int ep_unlink (ohci_t *ohci, ed_t *ed)  /*-------------------------------------------------------------------------*/ -/* 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 */ - +/* 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; @@ -596,7 +645,7 @@ static ed_t * ep_add_ed (struct usb_device *usb_dev, unsigned long pipe)  		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->hwTailP = m32_swap ((unsigned long)td);  		ed->hwHeadP = ed->hwTailP;  		ed->state = ED_UNLINK;  		ed->type = usb_pipetype (pipe); @@ -654,13 +703,15 @@ static void td_fill (ohci_t *ohci, unsigned int info,  		data = 0;  	td->hwINFO = m32_swap (info); -	td->hwCBP = m32_swap (data); +	td->hwCBP = m32_swap ((unsigned long)data);  	if (data) -		td->hwBE = m32_swap (data + len - 1); +		td->hwBE = m32_swap ((unsigned long)(data + len - 1));  	else  		td->hwBE = 0; -	td->hwNextTD = m32_swap (td_pt); +	td->hwNextTD = m32_swap ((unsigned long)td_pt); +#ifndef S3C24X0_merge  	td->hwPSW [0] = m16_swap (((__u32)data & 0x0FFF) | 0xE000); +#endif  	/* append to queue */  	td->ed->hwTailP = td->hwNextTD; @@ -789,6 +840,9 @@ static td_t * dl_reverse_done_list (ohci_t *ohci)  				} else  					td_list->ed->hwHeadP &= m32_swap (0xfffffff2);  			} +#ifdef CONFIG_MPC5200 +			td_list->hwNextTD = 0; +#endif  		}  		td_list->next_dl_td = td_rev; @@ -827,7 +881,23 @@ static int dl_done_list (ohci_t *ohci, td_t *td_list)  			dbg("ConditionCode %#x", cc);  			stat = cc_to_error[cc];  		} - +#ifdef S3C24X0_merge +		/* see if this done list makes for all TD's of current URB, +		 * and mark the URB finished if so */ +		if (++(lurb_priv->td_cnt) == lurb_priv->length) { +#if 1 +			if ((ed->state & (ED_OPER | ED_UNLINK)) && +			    (lurb_priv->state != URB_DEL)) +#else +			if ((ed->state & (ED_OPER | ED_UNLINK))) +#endif +				urb_finished = 1; +			else +				dbg("dl_done_list: strange.., ED state %x, ed->state\n"); +		} else +			dbg("dl_done_list: processing TD %x, len %x\n", lurb_priv->td_cnt, +				lurb_priv->length); +#endif  		if (ed->state != ED_NEW) {  			edHeadP = m32_swap (ed->hwHeadP) & 0xfffffff0;  			edTailP = m32_swap (ed->hwTailP); @@ -974,7 +1044,6 @@ int rh_check_port_status(ohci_t *controller)  #ifdef CONFIG_AT91C_PQFP_UHPBUG  	ndp = (ndp == 2) ? 1:0;  #endif -  	for (i = 0; i < ndp; i++) {  		temp = roothub_portstatus (controller, i);  		/* check for a device disconnect */ @@ -1014,9 +1083,15 @@ pkt_print(dev, pipe, buffer, transfer_len, cmd, "SUB(rh)", usb_pipein(pipe));  	}  	bmRType_bReq  = cmd->requesttype | (cmd->request << 8); +#if defined(CONFIG_440EP) || defined(CONFIG_MPC5200) +	wValue	      = __swap_16(cmd->value); +	wIndex	      = __swap_16(cmd->index); +	wLength	      = __swap_16(cmd->length); +#else  	wValue	      = m16_swap (cmd->value);  	wIndex	      = m16_swap (cmd->index);  	wLength	      = m16_swap (cmd->length); +#endif /* CONFIG_440EP || CONFIG_MPC5200 */  	info("Root-Hub: adr: %2x cmd(%1x): %08x %04x %04x %04x",  		dev->devnum, 8, bmRType_bReq, wValue, wIndex, wLength); @@ -1030,6 +1105,20 @@ pkt_print(dev, pipe, buffer, transfer_len, cmd, "SUB(rh)", usb_pipein(pipe));  	   RH_OTHER | RH_CLASS	almost ever means HUB_PORT here  	*/ +#if defined(CONFIG_440EP) || defined(CONFIG_MPC5200) +	case RH_GET_STATUS: +			*(__u16 *) data_buf = __swap_16(1); OK (2); +	case RH_GET_STATUS | RH_INTERFACE: +			*(__u16 *) data_buf = __swap_16(0); OK (2); +	case RH_GET_STATUS | RH_ENDPOINT: +			*(__u16 *) data_buf = __swap_16(0); OK (2); +	case RH_GET_STATUS | RH_CLASS: +			*(__u32 *) data_buf = __swap_32( +				RD_RH_STAT & ~(RH_HS_CRWE | RH_HS_DRWE)); +			OK (4); +	case RH_GET_STATUS | RH_OTHER | RH_CLASS: +			*(__u32 *) data_buf = __swap_32(RD_RH_PORTSTAT); OK (4); +#else  	case RH_GET_STATUS:  			*(__u16 *) data_buf = m16_swap (1); OK (2);  	case RH_GET_STATUS | RH_INTERFACE: @@ -1042,6 +1131,7 @@ pkt_print(dev, pipe, buffer, transfer_len, cmd, "SUB(rh)", usb_pipein(pipe));  			OK (4);  	case RH_GET_STATUS | RH_OTHER | RH_CLASS:  			*(__u32 *) data_buf = m32_swap (RD_RH_PORTSTAT); OK (4); +#endif /* CONFIG_440EP || CONFIG_MPC5200 */  	case RH_CLEAR_FEATURE | RH_ENDPOINT:  		switch (wValue) { @@ -1170,7 +1260,7 @@ pkt_print(dev, pipe, buffer, transfer_len, cmd, "SUB(rh)", usb_pipein(pipe));  		}  		len = min_t(unsigned int, leni, -		min_t(unsigned int, data_buf [0], wLength)); +			    min_t(unsigned int, data_buf [0], wLength));  		OK (len);  	} @@ -1240,8 +1330,10 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,  		return -1;  	} +#if 0  	wait_ms(10);  	/* ohci_dump_status(&gohci); */ +#endif  	/* allow more time for a BULK device to react - some are slow */  #define BULK_TO	 5000	/* timeout in milliseconds */ @@ -1258,18 +1350,39 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,  			stat = USB_ST_CRC_ERR;  			break;  		} + +#ifdef S3C24X0_merge +		/* NOTE: since we are not interrupt driven in U-Boot and always +		 * handle only one URB at a time, we cannot assume the +		 * transaction finished on the first successful return from +		 * hc_interrupt().. unless the flag for current URB is set, +		 * meaning that all TD's to/from device got actually +		 * transferred and processed. If the current URB is not +		 * finished we need to re-iterate this loop so as +		 * hc_interrupt() gets called again as there needs to be some +		 * more TD's to process still */ +		if ((stat >= 0) && (stat != 0xff) && (urb_finished)) { +#else  		if (stat >= 0 && stat != 0xff) { +#endif  			/* 0xff is returned for an SF-interrupt */  			break;  		} +  		if (--timeout) {  			wait_ms(1);  		} else {  			err("CTL:TIMEOUT "); +#ifdef S3C24X0_merge +			dbg("submit_common_msg: TO status %x\n", stat); +			stat = USB_ST_CRC_ERR; +			urb_finished = 1; +#endif  			stat = USB_ST_CRC_ERR;  			break;  		}  	} +#ifndef S3C24X0_merge  	/* we got an Root Hub Status Change interrupt */  	if (got_rhsc) {  #ifdef DEBUG @@ -1291,6 +1404,7 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,  			devgone = dev;  		}  	} +#endif /* S3C24X0_merge */  	dev->status = stat;  	dev->act_len = transfer_len; @@ -1381,7 +1495,8 @@ static int hc_reset (ohci_t *ohci)  		readl(&ohci->regs->control));  	/* Reset USB (needed by some controllers) */ -	writel (0, &ohci->regs->control); +	ohci->hc_control = 0; +	writel (ohci->hc_control, &ohci->regs->control);  	/* HC Reset requires max 10 us delay */  	writel (OHCI_HCR,  &ohci->regs->cmdstatus); @@ -1460,24 +1575,40 @@ static int hc_start (ohci_t * ohci)  /* an interrupt happens */ -static int -hc_interrupt (void) +static int hc_interrupt (void)  {  	ohci_t *ohci = &gohci;  	struct ohci_regs *regs = ohci->regs;  	int ints;  	int stat = -1; +#ifdef S3C24X0_merge + +	if ((ohci->hcca->done_head != 0) && +	    !(m32_swap (ohci->hcca->done_head) & 0x01)) { +		ints =  OHCI_INTR_WDH; +	} else if ((ints = readl (®s->intrstatus)) == ~(u32)0) { +		ohci->disabled++; +		err ("%s device removed!", ohci->slot_name); +		return -1; +	} else if ((ints &= readl (®s->intrenable)) == 0) { +		dbg("hc_interrupt: returning..\n"); +		return 0xff; +	} +#else  	if ((ohci->hcca->done_head != 0) && !(m32_swap (ohci->hcca->done_head) & 0x01)) {  		ints =	OHCI_INTR_WDH;  	} else {  		ints = readl (®s->intrstatus);  	} - +#endif  	/* dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no)); */  	if (ints & OHCI_INTR_RHSC) {  		got_rhsc = 1; +#ifdef S3C24X0_merge +		stat = 0xff; +#endif  	}  	if (ints & OHCI_INTR_UE) { @@ -1549,12 +1680,18 @@ static char ohci_inited = 0;  int usb_lowlevel_init(void)  { -	/* -	 * Enable USB host clock. -	 */ -	*AT91C_PMC_SCER = AT91C_PMC_UHP;	/* 48MHz clock enabled for UHP */ -	*AT91C_PMC_PCER = 1 << AT91C_ID_UHP;	/* Peripheral Clock Enable Register */ +#ifdef CFG_USB_OHCI_CPU_INIT +	/* cpu dependant init */ +	if(usb_cpu_init()) +		return -1; +#endif + +#ifdef CFG_USB_OHCI_BOARD_INIT +	/*  board dependant init */ +	if(usb_board_init()) +		return -1; +#endif  	memset (&gohci, 0, sizeof (ohci_t));  	memset (&urb_priv, 0, sizeof (urb_priv_t)); @@ -1582,29 +1719,42 @@ int usb_lowlevel_init(void)  	gohci.disabled = 1;  	gohci.sleeping = 0;  	gohci.irq = -1; -	gohci.regs = (struct ohci_regs *)AT91_USB_HOST_BASE; +	gohci.regs = (struct ohci_regs *)CFG_USB_OHCI_REGS_BASE;  	gohci.flags = 0; -	gohci.slot_name = "at91rm9200"; +	gohci.slot_name = CFG_USB_OHCI_SLOT_NAME;  	if (hc_reset (&gohci) < 0) {  		hc_release_ohci (&gohci); -		/* Initialization failed */ -		*AT91C_PMC_PCER = AT91C_ID_UHP; -		*AT91C_PMC_SCDR = 1 << AT91C_PMC_UHP;	/* 48MHz clock disabled for UHP */ +		err ("can't reset usb-%s", gohci.slot_name); +#ifdef CFG_USB_OHCI_BOARD_INIT +		/* board dependant cleanup */ +		usb_board_init_fail(); +#endif + +#ifdef CFG_USB_OHCI_CPU_INIT +		/* cpu dependant cleanup */ +		usb_cpu_init_fail(); +#endif  		return -1;  	}  	/* FIXME this is a second HC reset; why?? */ -/*	writel (gohci.hc_control = OHCI_USB_RESET, &gohci.regs->control); -	wait_ms (10);*/ - +	/* 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 */ -		*AT91C_PMC_PCER = AT91C_ID_UHP; -		*AT91C_PMC_SCDR = 1 << AT91C_PMC_UHP;	/* 48MHz clock disabled for UHP */ +#ifdef CFG_USB_OHCI_BOARD_INIT +		/* board dependant cleanup */ +		usb_board_stop(); +#endif + +#ifdef CFG_USB_OHCI_CPU_INIT +		/* cpu dependant cleanup */ +		usb_cpu_stop(); +#endif  		return -1;  	} @@ -1612,6 +1762,9 @@ int usb_lowlevel_init(void)  	ohci_dump (&gohci, 1);  #else  	wait_ms(1); +# ifdef S3C24X0_merge +	urb_finished = 1; +# endif  #endif  	ohci_inited = 1;  	return 0; @@ -1626,10 +1779,19 @@ int usb_lowlevel_stop(void)  	/* TODO release any interrupts, etc. */  	/* call hc_release_ohci() here ? */  	hc_reset (&gohci); -	/* may not want to do this */ -	*AT91C_PMC_PCER = 1 << AT91C_ID_UHP; -	*AT91C_PMC_SCDR = 1 << AT91C_PMC_UHP;	/* 48MHz clock disabled for UHP */ + +#ifdef CFG_USB_OHCI_BOARD_INIT +	/* board dependant cleanup */ +	if(usb_board_stop()) +		return -1; +#endif + +#ifdef CFG_USB_OHCI_CPU_INIT +	/* cpu dependant cleanup */ +	if(usb_cpu_stop()) +		return -1; +#endif +  	return 0;  } - -#endif /* CONFIG_USB_OHCI */ +#endif /* CONFIG_USB_OHCI_NEW */ diff --git a/cpu/arm920t/at91rm9200/usb_ohci.h b/drivers/usb_ohci.h index ecb4e937b..95fbc4465 100644 --- a/cpu/arm920t/at91rm9200/usb_ohci.h +++ b/drivers/usb_ohci.h @@ -7,6 +7,15 @@   * usb-ohci.h   */ +/* functions for doing board or CPU specific setup/cleanup */ +extern int usb_board_init(void); +extern int usb_board_stop(void); +extern int usb_cpu_init_fail(void); + +extern int usb_cpu_init(void); +extern int usb_cpu_stop(void); +extern int usb_cpu_init_fail(void); +  static int cc_to_error[16] = { @@ -104,7 +113,9 @@ struct td {  	__u32 hwNextTD;		/* Next TD Pointer */  	__u32 hwBE;		/* Memory Buffer End Pointer */ +/* #ifndef CONFIG_MPC5200 /\* this seems wrong *\/ */  	__u16 hwPSW[MAXPSW]; +/* #endif */  	__u8 unused;  	__u8 index;  	struct ed *ed; @@ -128,8 +139,13 @@ typedef struct td td_t;  #define NUM_INTS 32	/* part of the OHCI standard */  struct ohci_hcca {  	__u32	int_table[NUM_INTS];	/* Interrupt ED table */ +#if defined(CONFIG_MPC5200) +	__u16	pad1;			/* set to 0 on each frame_no change */ +	__u16	frame_no;		/* current frame number */ +#else  	__u16	frame_no;		/* current frame number */  	__u16	pad1;			/* set to 0 on each frame_no change */ +#endif  	__u32	done_head;		/* info returned for an interrupt */  	u8		reserved_for_hc[116];  } __attribute((aligned(256))); @@ -138,7 +154,9 @@ struct ohci_hcca {  /*   * Maximum number of root hub ports.   */ -#define MAX_ROOT_PORTS	15	/* maximum OHCI root hub ports */ +#ifndef CFG_USB_OHCI_MAX_ROOT_PORTS +# error "CFG_USB_OHCI_MAX_ROOT_PORTS undefined!" +#endif  /*   * This is the structure of the OHCI controller's memory mapped I/O @@ -172,7 +190,7 @@ struct ohci_regs {  		__u32	a;  		__u32	b;  		__u32	status; -		__u32	portstatus[MAX_ROOT_PORTS]; +		__u32	portstatus[CFG_USB_OHCI_MAX_ROOT_PORTS];  	} roothub;  } __attribute((aligned(32))); diff --git a/drivers/usbdcore_ep0.c b/drivers/usbdcore_ep0.c index 260befe97..1e44f322a 100644 --- a/drivers/usbdcore_ep0.c +++ b/drivers/usbdcore_ep0.c @@ -2,6 +2,9 @@   * (C) Copyright 2003   * Gerry Hamel, geh@ti.com, Texas Instruments   * + * (C) Copyright 2006 + * Bryan O'Donoghue, deckard@CodeHermit.ie + *   * Based on   * linux/drivers/usbd/ep0.c   * @@ -39,11 +42,17 @@   * function driver. This may need to change.   *   * XXX + * + * As alluded to above, a simple callback cdc_recv_setup has been implemented + * in the usb_device data structure to facilicate passing + * Common Device Class packets to a function driver. + * + * XXX   */  #include <common.h> -#if defined(CONFIG_OMAP1510) && defined(CONFIG_USB_DEVICE) +#if defined(CONFIG_USB_DEVICE)  #include "usbdcore.h"  #if 0 @@ -69,7 +78,7 @@ static int ep0_get_status (struct usb_device_instance *device,  	char *cp;  	urb->actual_length = 2; -	cp = urb->buffer; +	cp = (char*)urb->buffer;  	cp[0] = cp[1] = 0;  	switch (requesttype) { @@ -115,7 +124,7 @@ static int ep0_get_one (struct usb_device_instance *device, struct urb *urb,   *   * Copy configuration data to urb transfer buffer if there is room for it.   */ -static void copy_config (struct urb *urb, void *data, int max_length, +void copy_config (struct urb *urb, void *data, int max_length,  			 int max_buf)  {  	int available; @@ -128,10 +137,7 @@ static void copy_config (struct urb *urb, void *data, int max_length,  		dbg_ep0 (1, "data is NULL");  		return;  	} -	if (!(length = *(unsigned char *) data)) { -		dbg_ep0 (1, "length is zero"); -		return; -	} +	length = max_length;  	if (length > max_length) {  		dbg_ep0 (1, "length: %d >= max_length: %d", length, @@ -192,7 +198,7 @@ static int ep0_get_descriptor (struct usb_device_instance *device,  	/* setup tx urb */  	urb->actual_length = 0; -	cp = urb->buffer; +	cp = (char*)urb->buffer;  	dbg_ep0 (2, "%s", USBD_DEVICE_DESCRIPTORS (descriptor_type)); @@ -200,7 +206,6 @@ static int ep0_get_descriptor (struct usb_device_instance *device,  	case USB_DESCRIPTOR_TYPE_DEVICE:  		{  			struct usb_device_descriptor *device_descriptor; -  			if (!  			    (device_descriptor =  			     usbd_device_device_descriptor (device, port))) { @@ -214,20 +219,16 @@ static int ep0_get_descriptor (struct usb_device_instance *device,  			/* correct the correct control endpoint 0 max packet size into the descriptor */  			device_descriptor =  				(struct usb_device_descriptor *) urb->buffer; -			device_descriptor->bMaxPacketSize0 = -				urb->device->bus->maxpacketsize;  		} -		/*dbg_ep0(3, "copied device configuration, actual_length: %x", urb->actual_length); */ +		dbg_ep0(3, "copied device configuration, actual_length: 0x%x", urb->actual_length);  		break;  	case USB_DESCRIPTOR_TYPE_CONFIGURATION:  		{ -			int bNumInterface;  			struct usb_configuration_descriptor  				*configuration_descriptor;  			struct usb_device_descriptor *device_descriptor; -  			if (!  			    (device_descriptor =  			     usbd_device_device_descriptor (device, port))) { @@ -251,130 +252,35 @@ static int ep0_get_descriptor (struct usb_device_instance *device,  					 index);  				return -1;  			} +			dbg_ep0(0, "attempt to copy %d bytes to urb\n",cpu_to_le16(configuration_descriptor->wTotalLength));  			copy_config (urb, configuration_descriptor, -				     sizeof (struct -					     usb_configuration_descriptor), -				     max); - - -			/* iterate across interfaces for specified configuration */ -			dbg_ep0 (0, "bNumInterfaces: %d", -				 configuration_descriptor->bNumInterfaces); -			for (bNumInterface = 0; -			     bNumInterface < -			     configuration_descriptor->bNumInterfaces; -			     bNumInterface++) { - -				int bAlternateSetting; -				struct usb_interface_instance -					*interface_instance; - -				dbg_ep0 (3, "[%d] bNumInterfaces: %d", -					 bNumInterface, -					 configuration_descriptor->bNumInterfaces); - -				if (! (interface_instance = usbd_device_interface_instance (device, -								     port, index, bNumInterface))) -				{ -					dbg_ep0 (3, "[%d] interface_instance NULL", -						 bNumInterface); -					return -1; -				} -				/* iterate across interface alternates */ -				for (bAlternateSetting = 0; -				     bAlternateSetting < interface_instance->alternates; -				     bAlternateSetting++) { -					/*int class; */ -					int bNumEndpoint; -					struct usb_interface_descriptor *interface_descriptor; -					struct usb_alternate_instance *alternate_instance; - -					dbg_ep0 (3, "[%d:%d] alternates: %d", -						 bNumInterface, -						 bAlternateSetting, -						 interface_instance->alternates); - -					if (! (alternate_instance = usbd_device_alternate_instance (device, port, index, bNumInterface, bAlternateSetting))) { -						dbg_ep0 (3, "[%d] alternate_instance NULL", -							 bNumInterface); -						return -1; -					} -					/* copy descriptor for this interface */ -					copy_config (urb, alternate_instance->interface_descriptor, -						     sizeof (struct usb_interface_descriptor), -						     max); - -					/*dbg_ep0(3, "[%d:%d] classes: %d endpoints: %d", bNumInterface, bAlternateSetting, */ -					/*        alternate_instance->classes, alternate_instance->endpoints); */ - -					/* iterate across classes for this alternate interface */ -#if 0 -					for (class = 0; -					     class < alternate_instance->classes; -					     class++) { -						struct usb_class_descriptor *class_descriptor; -						/*dbg_ep0(3, "[%d:%d:%d] classes: %d", bNumInterface, bAlternateSetting, */ -						/*        class, alternate_instance->classes); */ -						if (!(class_descriptor = usbd_device_class_descriptor_index (device, port, index, bNumInterface, bAlternateSetting, class))) { -							dbg_ep0 (3, "[%d] class NULL", -								 class); -							return -1; -						} -						/* copy descriptor for this class */ -						copy_config (urb, class_descriptor, -							sizeof (struct usb_class_descriptor), -							max); -					} -#endif - -					/* iterate across endpoints for this alternate interface */ -					interface_descriptor = alternate_instance->interface_descriptor; -					for (bNumEndpoint = 0; -					     bNumEndpoint < alternate_instance->endpoints; -					     bNumEndpoint++) { -						struct usb_endpoint_descriptor *endpoint_descriptor; -						dbg_ep0 (3, "[%d:%d:%d] endpoint: %d", -							 bNumInterface, -							 bAlternateSetting, -							 bNumEndpoint, -							 interface_descriptor-> -							 bNumEndpoints); -						if (!(endpoint_descriptor = usbd_device_endpoint_descriptor_index (device, port, index, bNumInterface, bAlternateSetting, bNumEndpoint))) { -							dbg_ep0 (3, "[%d] endpoint NULL", -								 bNumEndpoint); -							return -1; -						} -						/* copy descriptor for this endpoint */ -						copy_config (urb, endpoint_descriptor, -							     sizeof (struct usb_endpoint_descriptor), -							     max); -					} -				} -			} -			dbg_ep0 (3, "lengths: %d %d", -				 le16_to_cpu (configuration_descriptor->wTotalLength), -				 urb->actual_length); +					cpu_to_le16(configuration_descriptor->wTotalLength), +				     max);  		} +  		break;  	case USB_DESCRIPTOR_TYPE_STRING:  		{  			struct usb_string_descriptor *string_descriptor; -  			if (!(string_descriptor = usbd_get_string (index))) { +				serial_printf("Invalid string index %d\n", index);  				return -1;  			} -			/*dbg_ep0(3, "string_descriptor: %p", string_descriptor); */ +			dbg_ep0(3, "string_descriptor: %p length %d", string_descriptor, string_descriptor->bLength);  			copy_config (urb, string_descriptor, string_descriptor->bLength, max);  		}  		break;  	case USB_DESCRIPTOR_TYPE_INTERFACE: +	serial_printf("USB_DESCRIPTOR_TYPE_INTERFACE - error not implemented\n");  		return -1;  	case USB_DESCRIPTOR_TYPE_ENDPOINT: +		serial_printf("USB_DESCRIPTOR_TYPE_ENDPOINT - error not implemented\n");  		return -1;  	case USB_DESCRIPTOR_TYPE_HID:  		{ +			serial_printf("USB_DESCRIPTOR_TYPE_HID - error not implemented\n");  			return -1;	/* unsupported at this time */  #if 0  			int bNumInterface = @@ -403,6 +309,7 @@ static int ep0_get_descriptor (struct usb_device_instance *device,  		break;  	case USB_DESCRIPTOR_TYPE_REPORT:  		{ +			serial_printf("USB_DESCRIPTOR_TYPE_REPORT - error not implemented\n");  			return -1;	/* unsupported at this time */  #if 0  			int bNumInterface = @@ -434,12 +341,19 @@ static int ep0_get_descriptor (struct usb_device_instance *device,  #endif  		}  		break; +	case USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER: +		{ +			/* If a USB device supports both a full speed and low speed operation +			 * we must send a Device_Qualifier descriptor here +			 */ +			return -1; +		}  	default:  		return -1;  	} -	dbg_ep0 (1, "urb: buffer: %p buffer_length: %2d actual_length: %2d packet size: %2d", +	dbg_ep0 (1, "urb: buffer: %p buffer_length: %2d actual_length: %2d tx_packetSize: %2d",  		 urb->buffer, urb->buffer_length, urb->actual_length,  		 device->bus->endpoint_array[0].tx_packetSize);  /* @@ -495,6 +409,12 @@ int ep0_recv_setup (struct urb *urb)  	/* handle USB Standard Request (c.f. USB Spec table 9-2) */  	if ((request->bmRequestType & USB_REQ_TYPE_MASK) != 0) { +		if(device->device_state <= STATE_CONFIGURED){ +			/*	Attempt to handle a CDC specific request if we are +			 *	in the configured state. +			 */ +			return device->cdc_recv_setup(request,urb); +		}  		dbg_ep0 (1, "non standard request: %x",  			 request->bmRequestType & USB_REQ_TYPE_MASK);  		return -1;	/* Stall here */ @@ -567,6 +487,7 @@ int ep0_recv_setup (struct urb *urb)  						   le16_to_cpu (request->wValue) & 0xff);  		case USB_REQ_GET_CONFIGURATION: +			serial_printf("get config %d\n", device->configuration);  			return ep0_get_one (device, urb,  					    device->configuration); @@ -642,7 +563,6 @@ int ep0_recv_setup (struct urb *urb)  			/*dbg_ep0(2, "address: %d %d %d", */  			/*        request->wValue, le16_to_cpu(request->wValue), device->address); */ -			serial_printf ("DEVICE_ADDRESS_ASSIGNED.. event?\n");  			return 0;  		case USB_REQ_SET_DESCRIPTOR:	/* XXX should we support this? */ @@ -653,9 +573,10 @@ int ep0_recv_setup (struct urb *urb)  			/* c.f. 9.4.7 - the top half of wValue is reserved */  			/* */  			if ((device->configuration = -			     le16_to_cpu (request->wValue) & 0x7f) != 0) { +				le16_to_cpu (request->wValue) & 0xFF80) != 0) {  				/* c.f. 9.4.7 - zero is the default or addressed state, in our case this */  				/* is the same is configuration zero */ +				serial_printf("error setting dev->config to zero!\n");  				device->configuration = 0;	/* TBR - ?????? */  			}  			/* reset interface and alternate settings */ diff --git a/drivers/usbdcore_mpc8xx.c b/drivers/usbdcore_mpc8xx.c new file mode 100644 index 000000000..e87284b17 --- /dev/null +++ b/drivers/usbdcore_mpc8xx.c @@ -0,0 +1,1400 @@ +/* + * Copyright (C) 2006 by Bryan O'Donoghue, CodeHermit + * bodonoghue@CodeHermit.ie + * + * References + * DasUBoot/drivers/usbdcore_omap1510.c, for design and implementation ideas. + * + * 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. + * + */ + +/* + * Notes : + * 1.	#define __SIMULATE_ERROR__ to inject a CRC error into every 2nd TX + *		packet to force the USB re-transmit protocol. + * + * 2.	#define __DEBUG_UDC__ to switch on debug tracing to serial console + *	be careful that tracing doesn't create Hiesen-bugs with respect to + *	response timeouts to control requests. + * + * 3.	This driver should be able to support any higher level driver that + *	that wants to do either of the two standard UDC implementations + *	Control-Bulk-Interrupt or  Bulk-IN/Bulk-Out standards. Hence + *	gserial and cdc_acm should work with this code. + * + * 4.	NAK events never actually get raised at all, the documentation + *	is just wrong ! + * + * 5.	For some reason, cbd_datlen is *always* +2 the value it should be. + *	this means that having an RX cbd of 16 bytes is not possible, since + *	the same size is reported for 14 bytes received as 16 bytes received + *	until we can find out why this happens, RX cbds must be limited to 8 + *	bytes. TODO: check errata for this behaviour. + * + * 6.	Right now this code doesn't support properly powering up with the USB + *	cable attached to the USB host my development board the Adder87x doesn't + *	have a pull-up fitted to allow this, so it is necessary to power the + *	board and *then* attached the USB cable to the host. However somebody + *	with a different design in their board may be able to keep the cable + *	constantly connected and simply enable/disable a pull-up  re + *	figure 31.1 in MPC885RM.pdf instead of having to power up the board and + *	then attach the cable ! + * + */ +#include <common.h> +#include <config.h> + +#if defined(CONFIG_MPC885_FAMILY) && defined(CONFIG_USB_DEVICE) +#include <commproc.h> +#include "usbdcore.h" +#include "usbdcore_mpc8xx.h" +#include "usbdcore_ep0.h" + +#define ERR(fmt, args...)\ +	serial_printf("ERROR : [%s] %s:%d: "fmt,\ +				__FILE__,__FUNCTION__,__LINE__, ##args) +#ifdef __DEBUG_UDC__ +#define DBG(fmt,args...)\ +		serial_printf("[%s] %s:%d: "fmt,\ +				__FILE__,__FUNCTION__,__LINE__, ##args) +#else +#define DBG(fmt,args...) +#endif + +/* Static Data */ +#ifdef __SIMULATE_ERROR__ +static char err_poison_test = 0; +#endif +static struct mpc8xx_ep ep_ref[MAX_ENDPOINTS]; +static u32 address_base = STATE_NOT_READY; +static mpc8xx_udc_state_t udc_state = 0; +static struct usb_device_instance *udc_device = 0; +static volatile usb_epb_t *endpoints[MAX_ENDPOINTS]; +static volatile cbd_t *tx_cbd[TX_RING_SIZE]; +static volatile cbd_t *rx_cbd[RX_RING_SIZE]; +static volatile immap_t *immr = 0; +static volatile cpm8xx_t *cp = 0; +static volatile usb_pram_t *usb_paramp = 0; +static volatile usb_t *usbp = 0; +static int rx_ct = 0; +static int tx_ct = 0; + +/* Static Function Declarations */ +static void mpc8xx_udc_state_transition_up (usb_device_state_t initial, +					    usb_device_state_t final); +static void mpc8xx_udc_state_transition_down (usb_device_state_t initial, +					      usb_device_state_t final); +static void mpc8xx_udc_stall (unsigned int ep); +static void mpc8xx_udc_flush_tx_fifo (int epid); +static void mpc8xx_udc_flush_rx_fifo (void); +static void mpc8xx_udc_clear_rxbd (volatile cbd_t * rx_cbdp); +static void mpc8xx_udc_init_tx (struct usb_endpoint_instance *epi, +				struct urb *tx_urb); +static void mpc8xx_udc_dump_request (struct usb_device_request *request); +static void mpc8xx_udc_clock_init (volatile immap_t * immr, +				   volatile cpm8xx_t * cp); +static int mpc8xx_udc_ep_tx (struct usb_endpoint_instance *epi); +static int mpc8xx_udc_epn_rx (unsigned int epid, volatile cbd_t * rx_cbdp); +static void mpc8xx_udc_ep0_rx (volatile cbd_t * rx_cbdp); +static void mpc8xx_udc_cbd_init (void); +static void mpc8xx_udc_endpoint_init (void); +static void mpc8xx_udc_cbd_attach (int ep, uchar tx_size, uchar rx_size); +static u32 mpc8xx_udc_alloc (u32 data_size, u32 alignment); +static int mpc8xx_udc_ep0_rx_setup (volatile cbd_t * rx_cbdp); +static void mpc8xx_udc_set_nak (unsigned int ep); +static short mpc8xx_udc_handle_txerr (void); +static void mpc8xx_udc_advance_rx (volatile cbd_t ** rx_cbdp, int epid); + +/****************************************************************************** +			       Global Linkage + *****************************************************************************/ + +/* udc_init + * + * Do initial bus gluing + */ +int udc_init (void) +{ +	/* Init various pointers */ +	immr = (immap_t *) CFG_IMMR; +	cp = (cpm8xx_t *) & (immr->im_cpm); +	usb_paramp = (usb_pram_t *) & (cp->cp_dparam[PROFF_USB]); +	usbp = (usb_t *) & (cp->cp_scc[0]); + +	memset (ep_ref, 0x00, (sizeof (struct mpc8xx_ep) * MAX_ENDPOINTS)); + +	udc_device = 0; +	udc_state = STATE_NOT_READY; + +	usbp->usmod = 0x00; +	usbp->uscom = 0; + +	/* Set USB Frame #0, Respond at Address & Get a clock source  */ +	usbp->usaddr = 0x00; +	mpc8xx_udc_clock_init (immr, cp); + +	/* PA15, PA14 as perhiperal USBRXD and USBOE */ +	immr->im_ioport.iop_padir &= ~0x0003; +	immr->im_ioport.iop_papar |= 0x0003; + +	/* PC11/PC10 as peripheral USBRXP USBRXN */ +	immr->im_ioport.iop_pcso |= 0x0030; + +	/* PC7/PC6 as perhiperal USBTXP and USBTXN */ +	immr->im_ioport.iop_pcdir |= 0x0300; +	immr->im_ioport.iop_pcpar |= 0x0300; + +	/* Set the base address */ +	address_base = (u32) (cp->cp_dpmem + CPM_USB_BASE); + +	/* Initialise endpoints and circular buffers */ +	mpc8xx_udc_endpoint_init (); +	mpc8xx_udc_cbd_init (); + +	/* Assign allocated Dual Port Endpoint descriptors */ +	usb_paramp->ep0ptr = (u32) endpoints[0]; +	usb_paramp->ep1ptr = (u32) endpoints[1]; +	usb_paramp->ep2ptr = (u32) endpoints[2]; +	usb_paramp->ep3ptr = (u32) endpoints[3]; +	usb_paramp->frame_n = 0; + +	DBG ("ep0ptr=0x%08x ep1ptr=0x%08x ep2ptr=0x%08x ep3ptr=0x%08x\n", +	     usb_paramp->ep0ptr, usb_paramp->ep1ptr, usb_paramp->ep2ptr, +	     usb_paramp->ep3ptr); + +	return 0; +} + +/* udc_irq + * + * Poll for whatever events may have occured + */ +void udc_irq (void) +{ +	int epid = 0; +	volatile cbd_t *rx_cbdp = 0; +	volatile cbd_t *rx_cbdp_base = 0; + +	if (udc_state != STATE_READY) { +		return; +	} + +	if (usbp->usber & USB_E_BSY) { +		/* This shouldn't happen. If it does then it's a bug ! */ +		usbp->usber |= USB_E_BSY; +		mpc8xx_udc_flush_rx_fifo (); +	} + +	/* Scan all RX/Bidirectional Endpoints for RX data. */ +	for (epid = 0; epid < MAX_ENDPOINTS; epid++) { +		if (!ep_ref[epid].prx) { +			continue; +		} +		rx_cbdp = rx_cbdp_base = ep_ref[epid].prx; + +		do { +			if (!(rx_cbdp->cbd_sc & RX_BD_E)) { + +				if (rx_cbdp->cbd_sc & 0x1F) { +					/* Corrupt data discard it. +					 * Controller has NAK'd this packet. +					 */ +					mpc8xx_udc_clear_rxbd (rx_cbdp); + +				} else { +					if (!epid) { +						mpc8xx_udc_ep0_rx (rx_cbdp); + +					} else { +						/* Process data */ +						mpc8xx_udc_set_nak (epid); +						mpc8xx_udc_epn_rx (epid, rx_cbdp); +						mpc8xx_udc_clear_rxbd (rx_cbdp); +					} +				} + +				/* Advance RX CBD pointer */ +				mpc8xx_udc_advance_rx (&rx_cbdp, epid); +				ep_ref[epid].prx = rx_cbdp; +			} else { +				/* Advance RX CBD pointer */ +				mpc8xx_udc_advance_rx (&rx_cbdp, epid); +			} + +		} while (rx_cbdp != rx_cbdp_base); +	} + +	/* Handle TX events as appropiate, the correct place to do this is +	 * in a tx routine. Perhaps TX on epn was pre-empted by ep0 +	 */ + +	if (usbp->usber & USB_E_TXB) { +		usbp->usber |= USB_E_TXB; +	} + +	if (usbp->usber & (USB_TX_ERRMASK)) { +		mpc8xx_udc_handle_txerr (); +	} + +	/* Switch to the default state, respond at the default address */ +	if (usbp->usber & USB_E_RESET) { +		usbp->usber |= USB_E_RESET; +		usbp->usaddr = 0x00; +		udc_device->device_state = STATE_DEFAULT; +	} + +	/* if(usbp->usber&USB_E_IDLE){ +	   We could suspend here ! +	   usbp->usber|=USB_E_IDLE; +	   DBG("idle state change\n"); +	   } +	   if(usbp->usbs){ +	   We could resume here when IDLE is deasserted ! +	   Not worth doing, so long as we are self powered though. +	   } +	*/ + +	return; +} + +/* udc_endpoint_write + * + * Write some data to an endpoint + */ +int udc_endpoint_write (struct usb_endpoint_instance *epi) +{ +	int ep = 0; +	short epid = 1, unnak = 0, ret = 0; + +	if (udc_state != STATE_READY) { +		ERR ("invalid udc_state != STATE_READY!\n"); +		return -1; +	} + +	if (!udc_device || !epi) { +		return -1; +	} + +	if (udc_device->device_state != STATE_CONFIGURED) { +		return -1; +	} + +	ep = epi->endpoint_address & 0x03; +	if (ep >= MAX_ENDPOINTS) { +		return -1; +	} + +	/* Set NAK for all RX endpoints during TX */ +	for (epid = 1; epid < MAX_ENDPOINTS; epid++) { + +		/* Don't set NAK on DATA IN/CONTROL endpoints */ +		if (ep_ref[epid].sc & USB_DIR_IN) { +			continue; +		} + +		if (!(usbp->usep[epid] & (USEP_THS_NAK | USEP_RHS_NAK))) { +			unnak |= 1 << epid; +		} + +		mpc8xx_udc_set_nak (epid); +	} + +	mpc8xx_udc_init_tx (&udc_device->bus->endpoint_array[ep], +			    epi->tx_urb); +	ret = mpc8xx_udc_ep_tx (&udc_device->bus->endpoint_array[ep]); + +	/* Remove temporary NAK */ +	for (epid = 1; epid < MAX_ENDPOINTS; epid++) { +		if (unnak & (1 << epid)) { +			udc_unset_nak (epid); +		} +	} + +	return ret; +} + +/* mpc8xx_udc_assign_urb + * + * Associate a given urb to an endpoint TX or RX transmit/receive buffers + */ +static int mpc8xx_udc_assign_urb (int ep, char direction) +{ +	struct usb_endpoint_instance *epi = 0; + +	if (ep >= MAX_ENDPOINTS) { +		goto err; +	} +	epi = &udc_device->bus->endpoint_array[ep]; +	if (!epi) { +		goto err; +	} + +	if (!ep_ref[ep].urb) { +		ep_ref[ep].urb = usbd_alloc_urb (udc_device, udc_device->bus->endpoint_array); +		if (!ep_ref[ep].urb) { +			goto err; +		} +	} else { +		ep_ref[ep].urb->actual_length = 0; +	} + +	switch (direction) { +	case USB_DIR_IN: +		epi->tx_urb = ep_ref[ep].urb; +		break; +	case USB_DIR_OUT: +		epi->rcv_urb = ep_ref[ep].urb; +		break; +	default: +		goto err; +	} +	return 0; + +      err: +	udc_state = STATE_ERROR; +	return -1; +} + +/* udc_setup_ep + * + * Associate U-Boot software endpoints to mpc8xx endpoint parameter ram + * Isochronous endpoints aren't yet supported! + */ +void udc_setup_ep (struct usb_device_instance *device, unsigned int ep, +		   struct usb_endpoint_instance *epi) +{ +	uchar direction = 0; +	int ep_attrib = 0; + +	if (epi && (ep < MAX_ENDPOINTS)) { + +		if (ep == 0) { +			if (epi->rcv_attributes != USB_ENDPOINT_XFER_CONTROL +			    || epi->tx_attributes != +			    USB_ENDPOINT_XFER_CONTROL) { + +				/* ep0 must be a control endpoint */ +				udc_state = STATE_ERROR; +				return; + +			} +			if (!(ep_ref[ep].sc & EP_ATTACHED)) { +				mpc8xx_udc_cbd_attach (ep, epi->tx_packetSize, +						       epi->rcv_packetSize); +			} +			usbp->usep[ep] = 0x0000; +			return; +		} + +		if ((epi->endpoint_address & USB_ENDPOINT_DIR_MASK) +		    == USB_DIR_IN) { + +			direction = 1; +			ep_attrib = epi->tx_attributes; +			epi->rcv_packetSize = 0; +			ep_ref[ep].sc |= USB_DIR_IN; +		} else { + +			direction = 0; +			ep_attrib = epi->rcv_attributes; +			epi->tx_packetSize = 0; +			ep_ref[ep].sc &= ~USB_DIR_IN; +		} + +		if (mpc8xx_udc_assign_urb (ep, epi->endpoint_address +					   & USB_ENDPOINT_DIR_MASK)) { +			return; +		} + +		switch (ep_attrib) { +		case USB_ENDPOINT_XFER_CONTROL: +			if (!(ep_ref[ep].sc & EP_ATTACHED)) { +				mpc8xx_udc_cbd_attach (ep, +						       epi->tx_packetSize, +						       epi->rcv_packetSize); +			} +			usbp->usep[ep] = ep << 12; +			epi->rcv_urb = epi->tx_urb = ep_ref[ep].urb; + +			break; +		case USB_ENDPOINT_XFER_BULK: +		case USB_ENDPOINT_XFER_INT: +			if (!(ep_ref[ep].sc & EP_ATTACHED)) { +				if (direction) { +					mpc8xx_udc_cbd_attach (ep, +							       epi->tx_packetSize, +							       0); +				} else { +					mpc8xx_udc_cbd_attach (ep, +							       0, +							       epi->rcv_packetSize); +				} +			} +			usbp->usep[ep] = (ep << 12) | ((ep_attrib) << 8); + +			break; +		case USB_ENDPOINT_XFER_ISOC: +		default: +			serial_printf ("Error endpoint attrib %d>3\n", ep_attrib); +			udc_state = STATE_ERROR; +			break; +		} +	} + +} + +/* udc_connect + * + * Move state, switch on the USB + */ +void udc_connect (void) +{ +	/* Enable pull-up resistor on D+ +	 * TODO: fit a pull-up resistor to drive SE0 for > 2.5us +	 */ + +	if (udc_state != STATE_ERROR) { +		udc_state = STATE_READY; +		usbp->usmod |= USMOD_EN; +	} +} + +/* udc_disconnect + * + * Disconnect is not used but, is included for completeness + */ +void udc_disconnect (void) +{ +	/* Disable pull-up resistor on D- +	 * TODO: fix a pullup resistor to control this +	 */ + +	if (udc_state != STATE_ERROR) { +		udc_state = STATE_NOT_READY; +	} +	usbp->usmod &= ~USMOD_EN; +} + +/* udc_enable + * + * Grab an EP0 URB, register interest in a subset of USB events + */ +void udc_enable (struct usb_device_instance *device) +{ +	if (udc_state == STATE_ERROR) { +		return; +	} + +	udc_device = device; + +	if (!ep_ref[0].urb) { +		ep_ref[0].urb = usbd_alloc_urb (device, device->bus->endpoint_array); +	} + +	/* Register interest in all events except SOF, enable transceiver */ +	usbp->usber = 0x03FF; +	usbp->usbmr = 0x02F7; + +	return; +} + +/* udc_disable + * + * disable the currently hooked device + */ +void udc_disable (void) +{ +	int i = 0; + +	if (udc_state == STATE_ERROR) { +		DBG ("Won't disable UDC. udc_state==STATE_ERROR !\n"); +		return; +	} + +	udc_device = 0; + +	for (; i < MAX_ENDPOINTS; i++) { +		if (ep_ref[i].urb) { +			usbd_dealloc_urb (ep_ref[i].urb); +			ep_ref[i].urb = 0; +		} +	} + +	usbp->usbmr = 0x00; +	usbp->usmod = ~USMOD_EN; +	udc_state = STATE_NOT_READY; +} + +/* udc_startup_events + * + * Enable the specified device + */ +void udc_startup_events (struct usb_device_instance *device) +{ +	udc_enable (device); +	if (udc_state == STATE_READY) { +		usbd_device_event_irq (device, DEVICE_CREATE, 0); +	} +} + +/* udc_set_nak + * + * Allow upper layers to signal lower layers should not accept more RX data + * + */ +void udc_set_nak (int epid) +{ +	if (epid) { +		mpc8xx_udc_set_nak (epid); +	} +} + +/* udc_unset_nak + * + * Suspend sending of NAK tokens for DATA OUT tokens on a given endpoint. + * Switch off NAKing on this endpoint to accept more data output from host. + * + */ +void udc_unset_nak (int epid) +{ +	if (epid > MAX_ENDPOINTS) { +		return; +	} + +	if (usbp->usep[epid] & (USEP_THS_NAK | USEP_RHS_NAK)) { +		usbp->usep[epid] &= ~(USEP_THS_NAK | USEP_RHS_NAK); +		__asm__ ("eieio"); +	} +} + +/****************************************************************************** +			      Static Linkage +******************************************************************************/ + +/* udc_state_transition_up + * udc_state_transition_down + * + * Helper functions to implement device state changes.	The device states and + * the events that transition between them are: + * + *				STATE_ATTACHED + *				||	/\ + *				\/	|| + *	DEVICE_HUB_CONFIGURED			DEVICE_HUB_RESET + *				||	/\ + *				\/	|| + *				STATE_POWERED + *				||	/\ + *				\/	|| + *	DEVICE_RESET				DEVICE_POWER_INTERRUPTION + *				||	/\ + *				\/	|| + *				STATE_DEFAULT + *				||	/\ + *				\/	|| + *	DEVICE_ADDRESS_ASSIGNED			DEVICE_RESET + *				||	/\ + *				\/	|| + *				STATE_ADDRESSED + *				||	/\ + *				\/	|| + *	DEVICE_CONFIGURED			DEVICE_DE_CONFIGURED + *				||	/\ + *				\/	|| + *				STATE_CONFIGURED + * + * udc_state_transition_up transitions up (in the direction from STATE_ATTACHED + * to STATE_CONFIGURED) from the specified initial state to the specified final + * state, passing through each intermediate state on the way.  If the initial + * state is at or above (i.e. nearer to STATE_CONFIGURED) the final state, then + * no state transitions will take place. + * + * udc_state_transition_down transitions down (in the direction from + * STATE_CONFIGURED to STATE_ATTACHED) from the specified initial state to the + * specified final state, passing through each intermediate state on the way. + * If the initial state is at or below (i.e. nearer to STATE_ATTACHED) the final + * state, then no state transitions will take place. + * + */ + +static void mpc8xx_udc_state_transition_up (usb_device_state_t initial, +					    usb_device_state_t final) +{ +	if (initial < final) { +		switch (initial) { +		case STATE_ATTACHED: +			usbd_device_event_irq (udc_device, +					       DEVICE_HUB_CONFIGURED, 0); +			if (final == STATE_POWERED) +				break; +		case STATE_POWERED: +			usbd_device_event_irq (udc_device, DEVICE_RESET, 0); +			if (final == STATE_DEFAULT) +				break; +		case STATE_DEFAULT: +			usbd_device_event_irq (udc_device, +					       DEVICE_ADDRESS_ASSIGNED, 0); +			if (final == STATE_ADDRESSED) +				break; +		case STATE_ADDRESSED: +			usbd_device_event_irq (udc_device, DEVICE_CONFIGURED, +					       0); +		case STATE_CONFIGURED: +			break; +		default: +			break; +		} +	} +} + +static void mpc8xx_udc_state_transition_down (usb_device_state_t initial, +					      usb_device_state_t final) +{ +	if (initial > final) { +		switch (initial) { +		case STATE_CONFIGURED: +			usbd_device_event_irq (udc_device, +					       DEVICE_DE_CONFIGURED, 0); +			if (final == STATE_ADDRESSED) +				break; +		case STATE_ADDRESSED: +			usbd_device_event_irq (udc_device, DEVICE_RESET, 0); +			if (final == STATE_DEFAULT) +				break; +		case STATE_DEFAULT: +			usbd_device_event_irq (udc_device, +					       DEVICE_POWER_INTERRUPTION, 0); +			if (final == STATE_POWERED) +				break; +		case STATE_POWERED: +			usbd_device_event_irq (udc_device, DEVICE_HUB_RESET, +					       0); +		case STATE_ATTACHED: +			break; +		default: +			break; +		} +	} +} + +/* mpc8xx_udc_stall + * + * Force returning of STALL tokens on the given endpoint. Protocol or function + * STALL conditions are permissable here + */ +static void mpc8xx_udc_stall (unsigned int ep) +{ +	usbp->usep[ep] |= STALL_BITMASK; +} + +/* mpc8xx_udc_set_nak + * + * Force returning of NAK responses for the given endpoint as a kind of very + * simple flow control + */ +static void mpc8xx_udc_set_nak (unsigned int ep) +{ +	usbp->usep[ep] |= NAK_BITMASK; +	__asm__ ("eieio"); +} + +/* mpc8xx_udc_handle_txerr + * + * Handle errors relevant to TX. Return a status code to allow calling + * indicative of what if anything happened + */ +static short mpc8xx_udc_handle_txerr () +{ +	short ep = 0, ret = 0; + +	for (; ep < TX_RING_SIZE; ep++) { +		if (usbp->usber & (0x10 << ep)) { + +			/* Timeout or underrun */ +			if (tx_cbd[ep]->cbd_sc & 0x06) { +				ret = 1; +				mpc8xx_udc_flush_tx_fifo (ep); + +			} else { +				if (usbp->usep[ep] & STALL_BITMASK) { +					if (!ep) { +						usbp->usep[ep] &= ~STALL_BITMASK; +					} +				}	/* else NAK */ +			} +			usbp->usber |= (0x10 << ep); +		} +	} +	return ret; +} + +/* mpc8xx_udc_advance_rx + * + * Advance cbd rx + */ +static void mpc8xx_udc_advance_rx (volatile cbd_t ** rx_cbdp, int epid) +{ +	if ((*rx_cbdp)->cbd_sc & RX_BD_W) { +		*rx_cbdp = (volatile cbd_t *) (endpoints[epid]->rbase + CFG_IMMR); + +	} else { +		(*rx_cbdp)++; +	} +} + + +/* mpc8xx_udc_flush_tx_fifo + * + * Flush a given TX fifo. Assumes one tx cbd per endpoint + */ +static void mpc8xx_udc_flush_tx_fifo (int epid) +{ +	volatile cbd_t *tx_cbdp = 0; + +	if (epid > MAX_ENDPOINTS) { +		return; +	} + +	/* TX stop */ +	immr->im_cpm.cp_cpcr = ((epid << 2) | 0x1D01); +	__asm__ ("eieio"); +	while (immr->im_cpm.cp_cpcr & 0x01); + +	usbp->uscom = 0x40 | 0; + +	/* reset ring */ +	tx_cbdp = (cbd_t *) (endpoints[epid]->tbptr + CFG_IMMR); +	tx_cbdp->cbd_sc = (TX_BD_I | TX_BD_W); + + +	endpoints[epid]->tptr = endpoints[epid]->tbase; +	endpoints[epid]->tstate = 0x00; +	endpoints[epid]->tbcnt = 0x00; + +	/* TX start */ +	immr->im_cpm.cp_cpcr = ((epid << 2) | 0x2D01); +	__asm__ ("eieio"); +	while (immr->im_cpm.cp_cpcr & 0x01); + +	return; +} + +/* mpc8xx_udc_flush_rx_fifo + * + * For the sake of completeness of the namespace, it seems like + * a good-design-decision (tm) to include mpc8xx_udc_flush_rx_fifo(); + * If RX_BD_E is true => a driver bug either here or in an upper layer + * not polling frequently enough. If RX_BD_E is true we have told the host + * we have accepted data but, the CPM found it had no-where to put that data + * which needless to say would be a bad thing. + */ +static void mpc8xx_udc_flush_rx_fifo () +{ +	int i = 0; + +	for (i = 0; i < RX_RING_SIZE; i++) { +		if (!(rx_cbd[i]->cbd_sc & RX_BD_E)) { +			ERR ("buf %p used rx data len = 0x%x sc=0x%x!\n", +			     rx_cbd[i], rx_cbd[i]->cbd_datlen, +			     rx_cbd[i]->cbd_sc); + +		} +	} +	ERR ("BUG : Input over-run\n"); +} + +/* mpc8xx_udc_clear_rxbd + * + * Release control of RX CBD to CP. + */ +static void mpc8xx_udc_clear_rxbd (volatile cbd_t * rx_cbdp) +{ +	rx_cbdp->cbd_datlen = 0x0000; +	rx_cbdp->cbd_sc = ((rx_cbdp->cbd_sc & RX_BD_W) | (RX_BD_E | RX_BD_I)); +	__asm__ ("eieio"); +} + +/* mpc8xx_udc_tx_irq + * + * Parse for tx timeout, control RX or USB reset/busy conditions + * Return -1 on timeout, -2 on fatal error, else return zero + */ +static int mpc8xx_udc_tx_irq (int ep) +{ +	int i = 0; + +	if (usbp->usber & (USB_TX_ERRMASK)) { +		if (mpc8xx_udc_handle_txerr ()) { +			/* Timeout, controlling function must retry send */ +			return -1; +		} +	} + +	if (usbp->usber & (USB_E_RESET | USB_E_BSY)) { +		/* Fatal, abandon TX transaction */ +		return -2; +	} + +	if (usbp->usber & USB_E_RXB) { +		for (i = 0; i < RX_RING_SIZE; i++) { +			if (!(rx_cbd[i]->cbd_sc & RX_BD_E)) { +				if ((rx_cbd[i] == ep_ref[0].prx) || ep) { +					return -2; +				} +			} +		} +	} + +	return 0; +} + +/* mpc8xx_udc_ep_tx + * + * Transmit in a re-entrant fashion outbound USB packets. + * Implement retry/timeout mechanism described in USB specification + * Toggle DATA0/DATA1 pids as necessary + * Introduces non-standard tx_retry. The USB standard has no scope for slave + * devices to give up TX, however tx_retry stops us getting stuck in an endless + * TX loop. + */ +static int mpc8xx_udc_ep_tx (struct usb_endpoint_instance *epi) +{ +	struct urb *urb = epi->tx_urb; +	volatile cbd_t *tx_cbdp = 0; +	unsigned int ep = 0, pkt_len = 0, x = 0, tx_retry = 0; +	int ret = 0; + +	if (!epi || (epi->endpoint_address & 0x03) >= MAX_ENDPOINTS || !urb) { +		return -1; +	} + +	ep = epi->endpoint_address & 0x03; +	tx_cbdp = (cbd_t *) (endpoints[ep]->tbptr + CFG_IMMR); + +	if (tx_cbdp->cbd_sc & TX_BD_R || usbp->usber & USB_E_TXB) { +		mpc8xx_udc_flush_tx_fifo (ep); +		usbp->usber |= USB_E_TXB; +	}; + +	while (tx_retry++ < 100) { +		ret = mpc8xx_udc_tx_irq (ep); +		if (ret == -1) { +			/* ignore timeout here */ +		} else if (ret == -2) { +			/* Abandon TX */ +			mpc8xx_udc_flush_tx_fifo (ep); +			return -1; +		} + +		tx_cbdp = (cbd_t *) (endpoints[ep]->tbptr + CFG_IMMR); +		while (tx_cbdp->cbd_sc & TX_BD_R) { +		}; +		tx_cbdp->cbd_sc = (tx_cbdp->cbd_sc & TX_BD_W); + +		pkt_len = urb->actual_length - epi->sent; + +		if (pkt_len > epi->tx_packetSize || pkt_len > EP_MAX_PKT) { +			pkt_len = MIN (epi->tx_packetSize, EP_MAX_PKT); +		} + +		for (x = 0; x < pkt_len; x++) { +			*((unsigned char *) (tx_cbdp->cbd_bufaddr + x)) = +				urb->buffer[epi->sent + x]; +		} +		tx_cbdp->cbd_datlen = pkt_len; +		tx_cbdp->cbd_sc |= (CBD_TX_BITMASK | ep_ref[ep].pid); +		__asm__ ("eieio"); + +#ifdef __SIMULATE_ERROR__ +		if (++err_poison_test == 2) { +			err_poison_test = 0; +			tx_cbdp->cbd_sc &= ~TX_BD_TC; +		} +#endif + +		usbp->uscom = (USCOM_STR | ep); + +		while (!(usbp->usber & USB_E_TXB)) { +			ret = mpc8xx_udc_tx_irq (ep); +			if (ret == -1) { +				/* TX timeout */ +				break; +			} else if (ret == -2) { +				if (usbp->usber & USB_E_TXB) { +					usbp->usber |= USB_E_TXB; +				} +				mpc8xx_udc_flush_tx_fifo (ep); +				return -1; +			} +		}; + +		if (usbp->usber & USB_E_TXB) { +			usbp->usber |= USB_E_TXB; +		} + +		/* ACK must be present <= 18bit times from TX */ +		if (ret == -1) { +			continue; +		} + +		/* TX ACK : USB 2.0 8.7.2, Toggle PID, Advance TX */ +		epi->sent += pkt_len; +		epi->last = MIN (urb->actual_length - epi->sent, epi->tx_packetSize); +		TOGGLE_TX_PID (ep_ref[ep].pid); + +		if (epi->sent >= epi->tx_urb->actual_length) { + +			epi->tx_urb->actual_length = 0; +			epi->sent = 0; + +			if (ep_ref[ep].sc & EP_SEND_ZLP) { +				ep_ref[ep].sc &= ~EP_SEND_ZLP; +			} else { +				return 0; +			} +		} +	} + +	ERR ("TX fail, endpoint 0x%x tx bytes 0x%x/0x%x\n", ep, epi->sent, +	     epi->tx_urb->actual_length); + +	return -1; +} + +/* mpc8xx_udc_dump_request + * + * Dump a control request to console + */ +static void mpc8xx_udc_dump_request (struct usb_device_request *request) +{ +	DBG ("bmRequestType:%02x bRequest:%02x wValue:%04x " +	     "wIndex:%04x wLength:%04x ?\n", +	     request->bmRequestType, +	     request->bRequest, +	     request->wValue, request->wIndex, request->wLength); + +	return; +} + +/* mpc8xx_udc_ep0_rx_setup + * + * Decode received ep0 SETUP packet. return non-zero on error + */ +static int mpc8xx_udc_ep0_rx_setup (volatile cbd_t * rx_cbdp) +{ +	unsigned int x = 0; +	struct urb *purb = ep_ref[0].urb; +	struct usb_endpoint_instance *epi = +		&udc_device->bus->endpoint_array[0]; + +	for (; x < rx_cbdp->cbd_datlen; x++) { +		*(((unsigned char *) &ep_ref[0].urb->device_request) + x) = +			*((unsigned char *) (rx_cbdp->cbd_bufaddr + x)); +	} + +	mpc8xx_udc_clear_rxbd (rx_cbdp); + +	if (ep0_recv_setup (purb)) { +		mpc8xx_udc_dump_request (&purb->device_request); +		return -1; +	} + +	if ((purb->device_request.bmRequestType & USB_REQ_DIRECTION_MASK) +	    == USB_REQ_HOST2DEVICE) { + +		switch (purb->device_request.bRequest) { +		case USB_REQ_SET_ADDRESS: +			/* Send the Status OUT ZLP */ +			ep_ref[0].pid = TX_BD_PID_DATA1; +			purb->actual_length = 0; +			mpc8xx_udc_init_tx (epi, purb); +			mpc8xx_udc_ep_tx (epi); + +			/* Move to the addressed state */ +			usbp->usaddr = udc_device->address; +			mpc8xx_udc_state_transition_up (udc_device->device_state, +							STATE_ADDRESSED); +			return 0; + +		case USB_REQ_SET_CONFIGURATION: +			if (!purb->device_request.wValue) { +				/* Respond at default address */ +				usbp->usaddr = 0x00; +				mpc8xx_udc_state_transition_down (udc_device->device_state, +								  STATE_ADDRESSED); +			} else { +				/* TODO: Support multiple configurations */ +				mpc8xx_udc_state_transition_up (udc_device->device_state, +								STATE_CONFIGURED); +				for (x = 1; x < MAX_ENDPOINTS; x++) { +					if ((udc_device->bus->endpoint_array[x].endpoint_address & USB_ENDPOINT_DIR_MASK) +					    == USB_DIR_IN) { +						ep_ref[x].pid = TX_BD_PID_DATA0; +					} else { +						ep_ref[x].pid = RX_BD_PID_DATA0; +					} +					/* Set configuration must unstall endpoints */ +					usbp->usep[x] &= ~STALL_BITMASK; +				} +			} +			break; +		default: +			/* CDC/Vendor specific */ +			break; +		} + +		/* Send ZLP as ACK in Status OUT phase */ +		ep_ref[0].pid = TX_BD_PID_DATA1; +		purb->actual_length = 0; +		mpc8xx_udc_init_tx (epi, purb); +		mpc8xx_udc_ep_tx (epi); + +	} else { + +		if (purb->actual_length) { +			ep_ref[0].pid = TX_BD_PID_DATA1; +			mpc8xx_udc_init_tx (epi, purb); + +			if (!(purb->actual_length % EP0_MAX_PACKET_SIZE)) { +				ep_ref[0].sc |= EP_SEND_ZLP; +			} + +			if (purb->device_request.wValue == +			    USB_DESCRIPTOR_TYPE_DEVICE) { +				if (le16_to_cpu (purb->device_request.wLength) +				    > purb->actual_length) { +					/* Send EP0_MAX_PACKET_SIZE bytes +					 * unless correct size requested. +					 */ +					if (purb->actual_length > epi->tx_packetSize) { +						purb->actual_length = epi->tx_packetSize; +					} +				} +			} +			mpc8xx_udc_ep_tx (epi); + +		} else { +			/* Corrupt SETUP packet? */ +			ERR ("Zero length data or SETUP with DATA-IN phase ?\n"); +			return 1; +		} +	} +	return 0; +} + +/* mpc8xx_udc_init_tx + * + * Setup some basic parameters for a TX transaction + */ +static void mpc8xx_udc_init_tx (struct usb_endpoint_instance *epi, +				struct urb *tx_urb) +{ +	epi->sent = 0; +	epi->last = 0; +	epi->tx_urb = tx_urb; +} + +/* mpc8xx_udc_ep0_rx + * + * Receive ep0/control USB data. Parse and possibly send a response. + */ +static void mpc8xx_udc_ep0_rx (volatile cbd_t * rx_cbdp) +{ +	if (rx_cbdp->cbd_sc & RX_BD_PID_SETUP) { + +		/* Unconditionally accept SETUP packets */ +		if (mpc8xx_udc_ep0_rx_setup (rx_cbdp)) { +			mpc8xx_udc_stall (0); +		} + +	} else { + +		mpc8xx_udc_clear_rxbd (rx_cbdp); + +		if ((rx_cbdp->cbd_datlen - 2)) { +			/* SETUP with a DATA phase +			 * outside of SETUP packet. +			 * Reply with STALL. +			 */ +			mpc8xx_udc_stall (0); +		} +	} +} + +/* mpc8xx_udc_epn_rx + * + * Receive some data from cbd into USB system urb data abstraction + * Upper layers should NAK if there is insufficient RX data space + */ +static int mpc8xx_udc_epn_rx (unsigned int epid, volatile cbd_t * rx_cbdp) +{ +	struct usb_endpoint_instance *epi = 0; +	struct urb *urb = 0; +	unsigned int x = 0; + +	if (epid >= MAX_ENDPOINTS || !rx_cbdp->cbd_datlen) { +		return 0; +	} + +	/* USB 2.0 PDF section 8.6.4 +	 * Discard data with invalid PID it is a resend. +	 */ +	if (ep_ref[epid].pid != (rx_cbdp->cbd_sc & 0xC0)) { +		return 1; +	} +	TOGGLE_RX_PID (ep_ref[epid].pid); + +	epi = &udc_device->bus->endpoint_array[epid]; +	urb = epi->rcv_urb; + +	for (; x < (rx_cbdp->cbd_datlen - 2); x++) { +		*((unsigned char *) (urb->buffer + urb->actual_length + x)) = +			*((unsigned char *) (rx_cbdp->cbd_bufaddr + x)); +	} + +	if (x) { +		usbd_rcv_complete (epi, x, 0); +		if (ep_ref[epid].urb->status == RECV_ERROR) { +			DBG ("RX error unset NAK\n"); +			udc_unset_nak (epid); +		} +	} +	return x; +} + +/* mpc8xx_udc_clock_init + * + * Obtain a clock reference for Full Speed Signaling + */ +static void mpc8xx_udc_clock_init (volatile immap_t * immr, +				   volatile cpm8xx_t * cp) +{ + +#if defined(CFG_USB_EXTC_CLK) + +	/* This has been tested with a 48MHz crystal on CLK6 */ +	switch (CFG_USB_EXTC_CLK) { +	case 1: +		immr->im_ioport.iop_papar |= 0x0100; +		immr->im_ioport.iop_padir &= ~0x0100; +		cp->cp_sicr |= 0x24; +		break; +	case 2: +		immr->im_ioport.iop_papar |= 0x0200; +		immr->im_ioport.iop_padir &= ~0x0200; +		cp->cp_sicr |= 0x2D; +		break; +	case 3: +		immr->im_ioport.iop_papar |= 0x0400; +		immr->im_ioport.iop_padir &= ~0x0400; +		cp->cp_sicr |= 0x36; +		break; +	case 4: +		immr->im_ioport.iop_papar |= 0x0800; +		immr->im_ioport.iop_padir &= ~0x0800; +		cp->cp_sicr |= 0x3F; +		break; +	default: +		udc_state = STATE_ERROR; +		break; +	} + +#elif defined(CFG_USB_BRGCLK) + +	/* This has been tested with brgclk == 50MHz */ +	DECLARE_GLOBAL_DATA_PTR; +	int divisor = 0; + +	if (gd->cpu_clk < 48000000L) { +		ERR ("brgclk is too slow for full-speed USB!\n"); +		udc_state = STATE_ERROR; +		return; +	} + +	/* Assume the brgclk is 'good enough', we want !(gd->cpu_clk%48Mhz) +	 * but, can /probably/ live with close-ish alternative rates. +	 */ +	divisor = (gd->cpu_clk / 48000000L) - 1; +	cp->cp_sicr &= ~0x0000003F; + +	switch (CFG_USB_BRGCLK) { +	case 1: +		cp->cp_brgc1 |= (divisor | CPM_BRG_EN); +		cp->cp_sicr &= ~0x2F; +		break; +	case 2: +		cp->cp_brgc2 |= (divisor | CPM_BRG_EN); +		cp->cp_sicr |= 0x00000009; +		break; +	case 3: +		cp->cp_brgc3 |= (divisor | CPM_BRG_EN); +		cp->cp_sicr |= 0x00000012; +		break; +	case 4: +		cp->cp_brgc4 = (divisor | CPM_BRG_EN); +		cp->cp_sicr |= 0x0000001B; +		break; +	default: +		udc_state = STATE_ERROR; +		break; +	} + +#else +#error "CFG_USB_EXTC_CLK or CFG_USB_BRGCLK must be defined" +#endif + +} + +/* mpc8xx_udc_cbd_attach + * + * attach a cbd to and endpoint + */ +static void mpc8xx_udc_cbd_attach (int ep, uchar tx_size, uchar rx_size) +{ + +	if (!tx_cbd[ep] || !rx_cbd[ep] || ep >= MAX_ENDPOINTS) { +		udc_state = STATE_ERROR; +		return; +	} + +	if (tx_size > USB_MAX_PKT || rx_size > USB_MAX_PKT || +	    (!tx_size && !rx_size)) { +		udc_state = STATE_ERROR; +		return; +	} + +	/* Attach CBD to appropiate Parameter RAM Endpoint data structure */ +	if (rx_size) { +		endpoints[ep]->rbase = (u32) rx_cbd[rx_ct]; +		endpoints[ep]->rbptr = (u32) rx_cbd[rx_ct]; +		rx_ct++; + +		if (!ep) { + +			endpoints[ep]->rbptr = (u32) rx_cbd[rx_ct]; +			rx_cbd[rx_ct]->cbd_sc |= RX_BD_W; +			rx_ct++; + +		} else { +			rx_ct += 2; +			endpoints[ep]->rbptr = (u32) rx_cbd[rx_ct]; +			rx_cbd[rx_ct]->cbd_sc |= RX_BD_W; +			rx_ct++; +		} + +		/* Where we expect to RX data on this endpoint */ +		ep_ref[ep].prx = rx_cbd[rx_ct - 1]; +	} else { + +		ep_ref[ep].prx = 0; +		endpoints[ep]->rbase = 0; +		endpoints[ep]->rbptr = 0; +	} + +	if (tx_size) { +		endpoints[ep]->tbase = (u32) tx_cbd[tx_ct]; +		endpoints[ep]->tbptr = (u32) tx_cbd[tx_ct]; +		tx_ct++; +	} else { +		endpoints[ep]->tbase = 0; +		endpoints[ep]->tbptr = 0; +	} + +	endpoints[ep]->tstate = 0; +	endpoints[ep]->tbcnt = 0; +	endpoints[ep]->mrblr = EP_MAX_PKT; +	endpoints[ep]->rfcr = 0x18; +	endpoints[ep]->tfcr = 0x18; +	ep_ref[ep].sc |= EP_ATTACHED; + +	DBG ("ep %d rbase 0x%08x rbptr 0x%08x tbase 0x%08x tbptr 0x%08x prx = %p\n", +		ep, endpoints[ep]->rbase, endpoints[ep]->rbptr, +		endpoints[ep]->tbase, endpoints[ep]->tbptr, +		ep_ref[ep].prx); + +	return; +} + +/* mpc8xx_udc_cbd_init + * + * Allocate space for a cbd and allocate TX/RX data space + */ +static void mpc8xx_udc_cbd_init (void) +{ +	int i = 0; + +	for (; i < TX_RING_SIZE; i++) { +		tx_cbd[i] = (cbd_t *) +			mpc8xx_udc_alloc (sizeof (cbd_t), sizeof (int)); +	} + +	for (i = 0; i < RX_RING_SIZE; i++) { +		rx_cbd[i] = (cbd_t *) +			mpc8xx_udc_alloc (sizeof (cbd_t), sizeof (int)); +	} + +	for (i = 0; i < TX_RING_SIZE; i++) { +		tx_cbd[i]->cbd_bufaddr = +			mpc8xx_udc_alloc (EP_MAX_PKT, sizeof (int)); + +		tx_cbd[i]->cbd_sc = (TX_BD_I | TX_BD_W); +		tx_cbd[i]->cbd_datlen = 0x0000; +	} + + +	for (i = 0; i < RX_RING_SIZE; i++) { +		rx_cbd[i]->cbd_bufaddr = +			mpc8xx_udc_alloc (EP_MAX_PKT, sizeof (int)); +		rx_cbd[i]->cbd_sc = (RX_BD_I | RX_BD_E); +		rx_cbd[i]->cbd_datlen = 0x0000; + +	} + +	return; +} + +/* mpc8xx_udc_endpoint_init + * + * Attach an endpoint to some dpram + */ +static void mpc8xx_udc_endpoint_init (void) +{ +	int i = 0; + +	for (; i < MAX_ENDPOINTS; i++) { +		endpoints[i] = (usb_epb_t *) +			mpc8xx_udc_alloc (sizeof (usb_epb_t), 32); +	} +} + +/* mpc8xx_udc_alloc + * + * Grab the address of some dpram + */ +static u32 mpc8xx_udc_alloc (u32 data_size, u32 alignment) +{ +	u32 retaddr = address_base; + +	while (retaddr % alignment) { +		retaddr++; +	} +	address_base += data_size; + +	return retaddr; +} + +#endif /* CONFIG_MPC885_FAMILY && CONFIG_USB_DEVICE) */ diff --git a/drivers/usbdcore_omap1510.c b/drivers/usbdcore_omap1510.c index 1d54a6357..84bb936d8 100644 --- a/drivers/usbdcore_omap1510.c +++ b/drivers/usbdcore_omap1510.c @@ -1517,4 +1517,31 @@ void udc_startup_events (struct usb_device_instance *device)  	udc_enable (device);  } +/** + * udc_irq - do pseudo interrupts + */ +void udc_irq(void) +{ +	/* Loop while we have interrupts. +	 * If we don't do this, the input chain +	 * polling delay is likely to miss +	 * host requests. +	 */ +	while (inw (UDC_IRQ_SRC) & ~UDC_SOF_Flg) { +		/* Handle any new IRQs */ +		omap1510_udc_irq (); +		omap1510_udc_noniso_irq (); +	} +} + +/* Flow control */ +void udc_set_nak(int epid) +{ +	/* TODO: implement this functionality in omap1510 */ +} + +void udc_unset_nak (int epid) +{ +	/* TODO: implement this functionality in omap1510 */ +}  #endif diff --git a/drivers/usbtty.c b/drivers/usbtty.c index ce4a12e16..d41a00b8c 100644 --- a/drivers/usbtty.c +++ b/drivers/usbtty.c @@ -2,6 +2,9 @@   * (C) Copyright 2003   * Gerry Hamel, geh@ti.com, Texas Instruments   * + * (C) Copyright 2006 + * Bryan O'Donoghue, bodonoghue@codehermit.ie + *   * 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 @@ -25,20 +28,42 @@  #include <circbuf.h>  #include <devices.h>  #include "usbtty.h" +#include "usb_cdc_acm.h" +#include "usbdescriptors.h" +#include <config.h>		/* If defined, override Linux identifiers with +			   	 * vendor specific ones */  #if 0 -#define TTYDBG(fmt,args...) serial_printf("[%s] %s %d: "fmt, __FILE__,__FUNCTION__,__LINE__,##args) +#define TTYDBG(fmt,args...)\ +	serial_printf("[%s] %s %d: "fmt, __FILE__,__FUNCTION__,__LINE__,##args)  #else  #define TTYDBG(fmt,args...) do{}while(0)  #endif -#if 0 -#define TTYERR(fmt,args...) serial_printf("ERROR![%s] %s %d: "fmt, __FILE__,__FUNCTION__,__LINE__,##args) +#if 1 +#define TTYERR(fmt,args...)\ +	serial_printf("ERROR![%s] %s %d: "fmt, __FILE__,__FUNCTION__,\ +	__LINE__,##args)  #else  #define TTYERR(fmt,args...) do{}while(0)  #endif  /* + * Defines + */ +#define NUM_CONFIGS    1 +#define MAX_INTERFACES 2 +#define NUM_ENDPOINTS  3 +#define ACM_TX_ENDPOINT 3 +#define ACM_RX_ENDPOINT 2 +#define GSERIAL_TX_ENDPOINT 2 +#define GSERIAL_RX_ENDPOINT 1 +#define NUM_ACM_INTERFACES 2 +#define NUM_GSERIAL_INTERFACES 1 +#define CONFIG_USBD_DATA_INTERFACE_STR "Bulk Data Interface" +#define CONFIG_USBD_CTRL_INTERFACE_STR "Control Interface" + +/*   * Buffers to hold input and output data   */  #define USBTTY_BUFFER_SIZE 256 @@ -50,157 +75,336 @@ static circbuf_t usbtty_output;   * Instance variables   */  static device_t usbttydev; -static struct usb_device_instance	 device_instance[1]; -static struct usb_bus_instance		 bus_instance[1]; +static struct usb_device_instance device_instance[1]; +static struct usb_bus_instance bus_instance[1];  static struct usb_configuration_instance config_instance[NUM_CONFIGS]; -static struct usb_interface_instance	 interface_instance[NUM_INTERFACES]; -static struct usb_alternate_instance	 alternate_instance[NUM_INTERFACES]; -static struct usb_endpoint_instance	 endpoint_instance[NUM_ENDPOINTS+1]; /* one extra for control endpoint */ - -/* - * Static allocation of urbs - */ -#define RECV_ENDPOINT 1 -#define TX_ENDPOINT 2 +static struct usb_interface_instance interface_instance[MAX_INTERFACES]; +static struct usb_alternate_instance alternate_instance[MAX_INTERFACES]; +/* one extra for control endpoint */ +static struct usb_endpoint_instance endpoint_instance[NUM_ENDPOINTS+1];  /*   * Global flag   */  int usbtty_configured_flag = 0; -  /*   * Serial number   */  static char serial_number[16]; +  /* - * Descriptors + * Descriptors, Strings, Local variables.   */ + +/* defined and used by usbdcore_ep0.c */ +extern struct usb_string_descriptor **usb_strings; + +/* Indicies, References */ +static unsigned short rx_endpoint = 0; +static unsigned short tx_endpoint = 0; +static unsigned short interface_count = 0; +static struct usb_string_descriptor *usbtty_string_table[STR_COUNT]; + +/* USB Descriptor Strings */  static u8 wstrLang[4] = {4,USB_DT_STRING,0x9,0x4};  static u8 wstrManufacturer[2 + 2*(sizeof(CONFIG_USBD_MANUFACTURER)-1)];  static u8 wstrProduct[2 + 2*(sizeof(CONFIG_USBD_PRODUCT_NAME)-1)];  static u8 wstrSerial[2 + 2*(sizeof(serial_number) - 1)];  static u8 wstrConfiguration[2 + 2*(sizeof(CONFIG_USBD_CONFIGURATION_STR)-1)]; -static u8 wstrInterface[2 + 2*(sizeof(CONFIG_USBD_INTERFACE_STR)-1)]; - -static struct usb_string_descriptor *usbtty_string_table[] = { -  (struct usb_string_descriptor*)wstrLang, -  (struct usb_string_descriptor*)wstrManufacturer, -  (struct usb_string_descriptor*)wstrProduct, -  (struct usb_string_descriptor*)wstrSerial, -  (struct usb_string_descriptor*)wstrConfiguration, -  (struct usb_string_descriptor*)wstrInterface -}; -extern struct usb_string_descriptor **usb_strings; /* defined and used by omap1510_ep0.c */ +static u8 wstrDataInterface[2 + 2*(sizeof(CONFIG_USBD_DATA_INTERFACE_STR)-1)]; +static u8 wstrCtrlInterface[2 + 2*(sizeof(CONFIG_USBD_DATA_INTERFACE_STR)-1)]; +/* Standard USB Data Structures */ +static struct usb_interface_descriptor interface_descriptors[MAX_INTERFACES]; +static struct usb_endpoint_descriptor *ep_descriptor_ptrs[NUM_ENDPOINTS]; +static struct usb_configuration_descriptor	*configuration_descriptor = 0;  static struct usb_device_descriptor device_descriptor = { -  bLength:	      sizeof(struct usb_device_descriptor), -  bDescriptorType:    USB_DT_DEVICE, -  bcdUSB:	      USB_BCD_VERSION, -  bDeviceClass:	      USBTTY_DEVICE_CLASS, -  bDeviceSubClass:    USBTTY_DEVICE_SUBCLASS, -  bDeviceProtocol:    USBTTY_DEVICE_PROTOCOL, -  bMaxPacketSize0:    EP0_MAX_PACKET_SIZE, -  idVendor:	      CONFIG_USBD_VENDORID, -  idProduct:	      CONFIG_USBD_PRODUCTID, -  bcdDevice:	      USBTTY_BCD_DEVICE, -  iManufacturer:      STR_MANUFACTURER, -  iProduct:	      STR_PRODUCT, -  iSerialNumber:      STR_SERIAL, -  bNumConfigurations: NUM_CONFIGS -  }; -static struct usb_configuration_descriptor config_descriptors[NUM_CONFIGS] = { -  { -    bLength:		 sizeof(struct usb_configuration_descriptor), -    bDescriptorType:	 USB_DT_CONFIG, -    wTotalLength:	 (sizeof(struct usb_configuration_descriptor)*NUM_CONFIGS) + -			 (sizeof(struct usb_interface_descriptor)*NUM_INTERFACES) + -			 (sizeof(struct usb_endpoint_descriptor)*NUM_ENDPOINTS), -    bNumInterfaces:	 NUM_INTERFACES, -    bConfigurationValue: 1, -    iConfiguration:	 STR_CONFIG, -    bmAttributes:	 BMATTRIBUTE_SELF_POWERED | BMATTRIBUTE_RESERVED, -    bMaxPower:		 USBTTY_MAXPOWER -  }, +	.bLength = sizeof(struct usb_device_descriptor), +	.bDescriptorType =	USB_DT_DEVICE, +	.bcdUSB = 		cpu_to_le16(USB_BCD_VERSION), +	.bDeviceSubClass =	0x00, +	.bDeviceProtocol =	0x00, +	.bMaxPacketSize0 =	EP0_MAX_PACKET_SIZE, +	.idVendor =		cpu_to_le16(CONFIG_USBD_VENDORID), +	.bcdDevice =		cpu_to_le16(USBTTY_BCD_DEVICE), +	.iManufacturer =	STR_MANUFACTURER, +	.iProduct =		STR_PRODUCT, +	.iSerialNumber =	STR_SERIAL, +	.bNumConfigurations =	NUM_CONFIGS  }; -static struct usb_interface_descriptor interface_descriptors[NUM_INTERFACES] = { -  { -    bLength:		 sizeof(struct usb_interface_descriptor), -    bDescriptorType:	 USB_DT_INTERFACE, -    bInterfaceNumber:	 0, -    bAlternateSetting:	 0, -    bNumEndpoints:	 NUM_ENDPOINTS, -    bInterfaceClass:	 USBTTY_INTERFACE_CLASS, -    bInterfaceSubClass:	 USBTTY_INTERFACE_SUBCLASS, -    bInterfaceProtocol:	 USBTTY_INTERFACE_PROTOCOL, -    iInterface:		 STR_INTERFACE -  }, -}; -static struct usb_endpoint_descriptor ep_descriptors[NUM_ENDPOINTS] = { -  { -    bLength:		 sizeof(struct usb_endpoint_descriptor), -    bDescriptorType:	 USB_DT_ENDPOINT, -    bEndpointAddress:	 CONFIG_USBD_SERIAL_OUT_ENDPOINT | USB_DIR_OUT, -    bmAttributes:	 USB_ENDPOINT_XFER_BULK, -    wMaxPacketSize:	 CONFIG_USBD_SERIAL_OUT_PKTSIZE, -    bInterval:		 0 -  }, -  { -    bLength:		 sizeof(struct usb_endpoint_descriptor), -    bDescriptorType:	 USB_DT_ENDPOINT, -    bEndpointAddress:	 CONFIG_USBD_SERIAL_IN_ENDPOINT | USB_DIR_IN, -    bmAttributes:	 USB_ENDPOINT_XFER_BULK, -    wMaxPacketSize:	 CONFIG_USBD_SERIAL_IN_PKTSIZE, -    bInterval:		 0 -  }, -  { -    bLength:		 sizeof(struct usb_endpoint_descriptor), -    bDescriptorType:	 USB_DT_ENDPOINT, -    bEndpointAddress:	 CONFIG_USBD_SERIAL_INT_ENDPOINT | USB_DIR_IN, -    bmAttributes:	 USB_ENDPOINT_XFER_INT, -    wMaxPacketSize:	 CONFIG_USBD_SERIAL_INT_PKTSIZE, -    bInterval:		 0 -  }, + + +/* + * Static CDC ACM specific descriptors + */ + +struct acm_config_desc { +	struct usb_configuration_descriptor configuration_desc; + +	/* Master Interface */ +	struct usb_interface_descriptor interface_desc; + +	struct usb_class_header_function_descriptor usb_class_header; +	struct usb_class_call_management_descriptor usb_class_call_mgt; +	struct usb_class_abstract_control_descriptor usb_class_acm; +	struct usb_class_union_function_descriptor usb_class_union; +	struct usb_endpoint_descriptor notification_endpoint; + +	/* Slave Interface */ +	struct usb_interface_descriptor data_class_interface; +	struct usb_endpoint_descriptor +		data_endpoints[NUM_ENDPOINTS-1] __attribute__((packed)); +} __attribute__((packed)); + +static struct acm_config_desc acm_configuration_descriptors[NUM_CONFIGS] = { +	{ +		.configuration_desc ={ +			.bLength = +				sizeof(struct usb_configuration_descriptor), +    			.bDescriptorType = USB_DT_CONFIG, +			.wTotalLength = +				cpu_to_le16(sizeof(struct acm_config_desc)), +	    		.bNumInterfaces = NUM_ACM_INTERFACES, +    			.bConfigurationValue = 1, +			.iConfiguration = STR_CONFIG, +			.bmAttributes = +				BMATTRIBUTE_SELF_POWERED|BMATTRIBUTE_RESERVED, +			.bMaxPower = USBTTY_MAXPOWER +		}, +		/* Interface 1 */ +		.interface_desc = { +			.bLength  = sizeof(struct usb_interface_descriptor), +			.bDescriptorType = USB_DT_INTERFACE, +			.bInterfaceNumber = 0, +			.bAlternateSetting = 0, +			.bNumEndpoints = 0x01, +			.bInterfaceClass = +				COMMUNICATIONS_INTERFACE_CLASS_CONTROL, +			.bInterfaceSubClass = COMMUNICATIONS_ACM_SUBCLASS, +			.bInterfaceProtocol = COMMUNICATIONS_V25TER_PROTOCOL, +			.iInterface = STR_CTRL_INTERFACE, +		}, +		.usb_class_header = { +			.bFunctionLength	= +				sizeof(struct usb_class_header_function_descriptor), +			.bDescriptorType	= CS_INTERFACE, +			.bDescriptorSubtype	= USB_ST_HEADER, +			.bcdCDC	= cpu_to_le16(110), +		}, +		.usb_class_call_mgt = { +			.bFunctionLength	= +				sizeof(struct usb_class_call_management_descriptor), +			.bDescriptorType	= CS_INTERFACE, +			.bDescriptorSubtype	= USB_ST_CMF, +			.bmCapabilities		= 0x00, +			.bDataInterface		= 0x01, +		}, +		.usb_class_acm = { +			.bFunctionLength	= +				sizeof(struct usb_class_abstract_control_descriptor), +			.bDescriptorType	= CS_INTERFACE, +			.bDescriptorSubtype	= USB_ST_ACMF, +			.bmCapabilities		= 0x00, +		}, +		.usb_class_union = { +			.bFunctionLength	= +				sizeof(struct usb_class_union_function_descriptor), +			.bDescriptorType	= CS_INTERFACE, +			.bDescriptorSubtype	= USB_ST_UF, +			.bMasterInterface	= 0x00, +			.bSlaveInterface0	= 0x01, +		}, +		.notification_endpoint = { +			.bLength = +				sizeof(struct usb_endpoint_descriptor), +			.bDescriptorType	= USB_DT_ENDPOINT, +			.bEndpointAddress	= 0x01 | USB_DIR_IN, +			.bmAttributes		= USB_ENDPOINT_XFER_INT, +			.wMaxPacketSize +				= cpu_to_le16(CONFIG_USBD_SERIAL_INT_PKTSIZE), +			.bInterval		= 0xFF, +		}, + +		/* Interface 2 */ +		.data_class_interface = { +			.bLength		= +				sizeof(struct usb_interface_descriptor), +			.bDescriptorType	= USB_DT_INTERFACE, +			.bInterfaceNumber	= 0x01, +			.bAlternateSetting	= 0x00, +			.bNumEndpoints		= 0x02, +			.bInterfaceClass	= +				COMMUNICATIONS_INTERFACE_CLASS_DATA, +			.bInterfaceSubClass	= DATA_INTERFACE_SUBCLASS_NONE, +			.bInterfaceProtocol	= DATA_INTERFACE_PROTOCOL_NONE, +			.iInterface		= STR_DATA_INTERFACE, +		}, +		.data_endpoints = { +			{ +				.bLength		= +					sizeof(struct usb_endpoint_descriptor), +				.bDescriptorType	= USB_DT_ENDPOINT, +				.bEndpointAddress	= 0x02 | USB_DIR_OUT, +				.bmAttributes		= +					USB_ENDPOINT_XFER_BULK, +				.wMaxPacketSize		= +					cpu_to_le16(CONFIG_USBD_SERIAL_BULK_PKTSIZE), +				.bInterval		= 0xFF, +			}, +			{ +				.bLength		= +					sizeof(struct usb_endpoint_descriptor), +				.bDescriptorType	= USB_DT_ENDPOINT, +				.bEndpointAddress	= 0x03 | USB_DIR_IN, +				.bmAttributes		= +					USB_ENDPOINT_XFER_BULK, +				.wMaxPacketSize		= +					cpu_to_le16(CONFIG_USBD_SERIAL_BULK_PKTSIZE), +				.bInterval		= 0xFF, +			}, +		}, +	},  }; -static struct usb_endpoint_descriptor *ep_descriptor_ptrs[NUM_ENDPOINTS] = { -  &(ep_descriptors[0]), -  &(ep_descriptors[1]), -  &(ep_descriptors[2]), + +static struct rs232_emu rs232_desc={ +		.dter 		=  	115200, +	   	.stop_bits	=	0x00, +	   	.parity		=	0x00, +		.data_bits	=	0x08  }; -/* utility function for converting char* to wide string used by USB */ -static void str2wide (char *str, u16 * wide) -{ -	int i; -	for (i = 0; i < strlen (str) && str[i]; i++) -		wide[i] = (u16) str[i]; -} +/* + * Static Generic Serial specific data + */ + + +struct gserial_config_desc { + +	struct usb_configuration_descriptor configuration_desc; +	struct usb_interface_descriptor +		interface_desc[NUM_GSERIAL_INTERFACES] __attribute__((packed)); +	struct usb_endpoint_descriptor +		data_endpoints[NUM_ENDPOINTS] __attribute__((packed)); + +} __attribute__((packed)); + +static struct gserial_config_desc +gserial_configuration_descriptors[NUM_CONFIGS] ={ +	{ +		.configuration_desc ={ +			.bLength = sizeof(struct usb_configuration_descriptor), +			.bDescriptorType = USB_DT_CONFIG, +			.wTotalLength = +				cpu_to_le16(sizeof(struct gserial_config_desc)), +			.bNumInterfaces = NUM_GSERIAL_INTERFACES, +			.bConfigurationValue = 1, +			.iConfiguration = STR_CONFIG, +			.bmAttributes = +				BMATTRIBUTE_SELF_POWERED|BMATTRIBUTE_RESERVED, +			.bMaxPower = USBTTY_MAXPOWER +		}, +		.interface_desc = { +			{ +				.bLength  = +					sizeof(struct usb_interface_descriptor), +				.bDescriptorType = USB_DT_INTERFACE, +				.bInterfaceNumber = 0, +				.bAlternateSetting = 0, +				.bNumEndpoints = NUM_ENDPOINTS, +				.bInterfaceClass = +					COMMUNICATIONS_INTERFACE_CLASS_VENDOR, +				.bInterfaceSubClass = +					COMMUNICATIONS_NO_SUBCLASS, +				.bInterfaceProtocol = +					COMMUNICATIONS_NO_PROTOCOL, +				.iInterface = STR_DATA_INTERFACE +			}, +  		}, +		.data_endpoints  = { +			{ +				.bLength = +					sizeof(struct usb_endpoint_descriptor), +				.bDescriptorType =	USB_DT_ENDPOINT, +				.bEndpointAddress =	0x01 | USB_DIR_OUT, +				.bmAttributes =		USB_ENDPOINT_XFER_BULK, +				.wMaxPacketSize = +					cpu_to_le16(CONFIG_USBD_SERIAL_OUT_PKTSIZE), +				.bInterval=		0xFF, +			}, +			{ +				.bLength = +					sizeof(struct usb_endpoint_descriptor), +				.bDescriptorType =	USB_DT_ENDPOINT, +				.bEndpointAddress =	0x02 | USB_DIR_IN, +				.bmAttributes =		USB_ENDPOINT_XFER_BULK, +				.wMaxPacketSize = +					cpu_to_le16(CONFIG_USBD_SERIAL_IN_PKTSIZE), +				.bInterval = 		0xFF, +			}, +			{ +				.bLength = +					sizeof(struct usb_endpoint_descriptor), +				.bDescriptorType =	USB_DT_ENDPOINT, +				.bEndpointAddress =	0x03 | USB_DIR_IN, +				.bmAttributes =		USB_ENDPOINT_XFER_INT, +    				.wMaxPacketSize = +					cpu_to_le16(CONFIG_USBD_SERIAL_INT_PKTSIZE), +				.bInterval =		0xFF, +			}, +		}, +	}, +};  /* - * Prototypes + * Static Function Prototypes   */ +  static void usbtty_init_strings (void);  static void usbtty_init_instances (void);  static void usbtty_init_endpoints (void); - +static void usbtty_init_terminal_type(short type);  static void usbtty_event_handler (struct usb_device_instance *device, -				  usb_device_event_t event, int data); +				usb_device_event_t event, int data); +static int usbtty_cdc_setup(struct usb_device_request *request, +				struct urb *urb);  static int usbtty_configured (void); -  static int write_buffer (circbuf_t * buf);  static int fill_buffer (circbuf_t * buf);  void usbtty_poll (void); -static void pretend_interrupts (void); +/* utility function for converting char* to wide string used by USB */ +static void str2wide (char *str, u16 * wide) +{ +	int i; +	for (i = 0; i < strlen (str) && str[i]; i++){ +		#if defined(__LITTLE_ENDIAN__) +			wide[i] = (u16) str[i]; +		#elif defined(__BIG_ENDIAN__) +			wide[i] = ((u16)(str[i])<<8); +		#else +			#error "__LITTLE_ENDIAN__ or __BIG_ENDIAN__ undefined" +		#endif +	} +}  /*   * Test whether a character is in the RX buffer   */ +  int usbtty_tstc (void)  { +	struct usb_endpoint_instance *endpoint = +		&endpoint_instance[rx_endpoint]; + +	/* If no input data exists, allow more RX to be accepted */ +	if(usbtty_input.size <= 0){ +		udc_unset_nak(endpoint->endpoint_address&0x03); +	} +  	usbtty_poll ();  	return (usbtty_input.size > 0);  } @@ -210,15 +414,21 @@ int usbtty_tstc (void)   * otherwise. When the function is succesfull, the character read is   * written into its argument c.   */ +  int usbtty_getc (void)  {  	char c; +	struct usb_endpoint_instance *endpoint = +		&endpoint_instance[rx_endpoint];  	while (usbtty_input.size <= 0) { +		udc_unset_nak(endpoint->endpoint_address&0x03);  		usbtty_poll ();  	}  	buf_pop (&usbtty_input, &c, 1); +	udc_set_nak(endpoint->endpoint_address&0x03); +  	return c;  } @@ -238,7 +448,6 @@ void usbtty_putc (const char c)  	}  } -  /* usbtty_puts() helper function for finding the next '\n' in a string */  static int next_nl_pos (const char *s)  { @@ -252,8 +461,9 @@ static int next_nl_pos (const char *s)  }  /* - * Output a string to the usb client port. + * Output a string to the usb client port - implementing flow control   */ +  static void __usbtty_puts (const char *str, int len)  {  	int maxlen = usbtty_output.totalsize; @@ -261,22 +471,19 @@ static void __usbtty_puts (const char *str, int len)  	/* break str into chunks < buffer size, if needed */  	while (len > 0) { -		space = maxlen - usbtty_output.size; +		usbtty_poll (); +		space = maxlen - usbtty_output.size;  		/* Empty buffer here, if needed, to ensure space... */ -		if (space <= 0) { +		if (space) {  			write_buffer (&usbtty_output); -			space = maxlen - usbtty_output.size; -			if (space <= 0) { -				space = len;	/* allow old data to be overwritten. */ -			} -		} -		n = MIN (space, MIN (len, maxlen)); -		buf_push (&usbtty_output, str, n); +			n = MIN (space, MIN (len, maxlen)); +			buf_push (&usbtty_output, str, n); -		str += n; -		len -= n; +			str += n; +			len -= n; +		}  	}  } @@ -313,8 +520,10 @@ int drv_usbtty_init (void)  {  	int rc;  	char * sn; +	char * tt;  	int snlen; +	/* Ger seiral number */  	if (!(sn = getenv("serial#"))) {  		sn = "000000000000";  	} @@ -327,6 +536,14 @@ int drv_usbtty_init (void)  	memcpy (serial_number, sn, snlen);  	serial_number[snlen] = '\0'; +	/* Decide on which type of UDC device to be. +	 */ + +	if(!(tt = getenv("usbtty"))) { +		tt = "generic"; +	} +	usbtty_init_terminal_type(strcmp(tt,"cdc_acm")); +  	/* prepare buffers... */  	buf_init (&usbtty_input, USBTTY_BUFFER_SIZE);  	buf_init (&usbtty_output, USBTTY_BUFFER_SIZE); @@ -337,7 +554,7 @@ int drv_usbtty_init (void)  	usbtty_init_strings ();  	usbtty_init_instances (); -	udc_startup_events (device_instance);	/* Enable our device, initialize udc pointers */ +	udc_startup_events (device_instance);/* Enable dev, init udc pointers */  	udc_connect ();		/* Enable pullup for host detection */  	usbtty_init_endpoints (); @@ -362,30 +579,48 @@ static void usbtty_init_strings (void)  {  	struct usb_string_descriptor *string; +	usbtty_string_table[STR_LANG] = +		(struct usb_string_descriptor*)wstrLang; +  	string = (struct usb_string_descriptor *) wstrManufacturer; -	string->bLength = sizeof (wstrManufacturer); +	string->bLength = sizeof(wstrManufacturer);  	string->bDescriptorType = USB_DT_STRING;  	str2wide (CONFIG_USBD_MANUFACTURER, string->wData); +	usbtty_string_table[STR_MANUFACTURER]=string; +  	string = (struct usb_string_descriptor *) wstrProduct; -	string->bLength = sizeof (wstrProduct); +	string->bLength = sizeof(wstrProduct);  	string->bDescriptorType = USB_DT_STRING;  	str2wide (CONFIG_USBD_PRODUCT_NAME, string->wData); +	usbtty_string_table[STR_PRODUCT]=string; +  	string = (struct usb_string_descriptor *) wstrSerial; -	string->bLength = 2 + 2*strlen(serial_number); +	string->bLength = sizeof(serial_number);  	string->bDescriptorType = USB_DT_STRING;  	str2wide (serial_number, string->wData); +	usbtty_string_table[STR_SERIAL]=string; +  	string = (struct usb_string_descriptor *) wstrConfiguration; -	string->bLength = sizeof (wstrConfiguration); +	string->bLength = sizeof(wstrConfiguration);  	string->bDescriptorType = USB_DT_STRING;  	str2wide (CONFIG_USBD_CONFIGURATION_STR, string->wData); +	usbtty_string_table[STR_CONFIG]=string; -	string = (struct usb_string_descriptor *) wstrInterface; -	string->bLength = sizeof (wstrInterface); + +	string = (struct usb_string_descriptor *) wstrDataInterface; +	string->bLength = sizeof(wstrDataInterface);  	string->bDescriptorType = USB_DT_STRING; -	str2wide (CONFIG_USBD_INTERFACE_STR, string->wData); +	str2wide (CONFIG_USBD_DATA_INTERFACE_STR, string->wData); +	usbtty_string_table[STR_DATA_INTERFACE]=string; + +	string = (struct usb_string_descriptor *) wstrCtrlInterface; +	string->bLength = sizeof(wstrCtrlInterface); +	string->bDescriptorType = USB_DT_STRING; +	str2wide (CONFIG_USBD_CTRL_INTERFACE_STR, string->wData); +	usbtty_string_table[STR_CTRL_INTERFACE]=string;  	/* Now, initialize the string table for ep0 handling */  	usb_strings = usbtty_string_table; @@ -400,6 +635,7 @@ static void usbtty_init_instances (void)  	device_instance->device_state = STATE_INIT;  	device_instance->device_descriptor = &device_descriptor;  	device_instance->event = usbtty_event_handler; +	device_instance->cdc_recv_setup = usbtty_cdc_setup;  	device_instance->bus = bus_instance;  	device_instance->configurations = NUM_CONFIGS;  	device_instance->configuration_instance_array = config_instance; @@ -415,8 +651,8 @@ static void usbtty_init_instances (void)  	/* configuration instance */  	memset (config_instance, 0,  		sizeof (struct usb_configuration_instance)); -	config_instance->interfaces = NUM_INTERFACES; -	config_instance->configuration_descriptor = config_descriptors; +	config_instance->interfaces = interface_count; +	config_instance->configuration_descriptor = configuration_descriptor;  	config_instance->interface_instance_array = interface_instance;  	/* interface instance */ @@ -447,17 +683,22 @@ static void usbtty_init_instances (void)  			sizeof (struct usb_endpoint_instance));  		endpoint_instance[i].endpoint_address = -			ep_descriptors[i - 1].bEndpointAddress; +			ep_descriptor_ptrs[i - 1]->bEndpointAddress; -		endpoint_instance[i].rcv_packetSize = -			ep_descriptors[i - 1].wMaxPacketSize;  		endpoint_instance[i].rcv_attributes = -			ep_descriptors[i - 1].bmAttributes; +			ep_descriptor_ptrs[i - 1]->bmAttributes; + +		endpoint_instance[i].rcv_packetSize = +			le16_to_cpu(ep_descriptor_ptrs[i - 1]->wMaxPacketSize); + +		endpoint_instance[i].tx_attributes = +			ep_descriptor_ptrs[i - 1]->bmAttributes;  		endpoint_instance[i].tx_packetSize = -			ep_descriptors[i - 1].wMaxPacketSize; +			le16_to_cpu(ep_descriptor_ptrs[i - 1]->wMaxPacketSize); +  		endpoint_instance[i].tx_attributes = -			ep_descriptors[i - 1].bmAttributes; +			ep_descriptor_ptrs[i - 1]->bmAttributes;  		urb_link_init (&endpoint_instance[i].rcv);  		urb_link_init (&endpoint_instance[i].rdy); @@ -480,13 +721,79 @@ static void usbtty_init_endpoints (void)  	int i;  	bus_instance->max_endpoints = NUM_ENDPOINTS + 1; -	for (i = 0; i <= NUM_ENDPOINTS; i++) { +	for (i = 1; i <= NUM_ENDPOINTS; i++) {  		udc_setup_ep (device_instance, i, &endpoint_instance[i]);  	}  } +/* usbtty_init_terminal_type + * + * Do some late binding for our device type. + */ +static void usbtty_init_terminal_type(short type) +{ +	switch(type){ +		/* CDC ACM */ +		case 0: +			/* Assign endpoint descriptors */ +			ep_descriptor_ptrs[0] = +				&acm_configuration_descriptors[0].notification_endpoint; +			ep_descriptor_ptrs[1] = +				&acm_configuration_descriptors[0].data_endpoints[0]; +			ep_descriptor_ptrs[2] = +				&acm_configuration_descriptors[0].data_endpoints[1]; + +			/* Enumerate Device Descriptor */ +			device_descriptor.bDeviceClass = +				COMMUNICATIONS_DEVICE_CLASS; +			device_descriptor.idProduct = +				cpu_to_le16(CONFIG_USBD_PRODUCTID_CDCACM); + +			/* Assign endpoint indices */ +			tx_endpoint = ACM_TX_ENDPOINT; +			rx_endpoint = ACM_RX_ENDPOINT; + +			/* Configuration Descriptor */ +			configuration_descriptor = +				(struct usb_configuration_descriptor*) +				&acm_configuration_descriptors; + +			/* Interface count */ +			interface_count = NUM_ACM_INTERFACES; +		break; + +		/* BULK IN/OUT & Default */ +		case 1: +		default: +			/* Assign endpoint descriptors */ +			ep_descriptor_ptrs[0] = +				&gserial_configuration_descriptors[0].data_endpoints[0]; +			ep_descriptor_ptrs[1] = +				&gserial_configuration_descriptors[0].data_endpoints[1]; +			ep_descriptor_ptrs[2] = +				&gserial_configuration_descriptors[0].data_endpoints[2]; + +			/* Enumerate Device Descriptor */ +			device_descriptor.bDeviceClass = 0xFF; +			device_descriptor.idProduct = +				cpu_to_le16(CONFIG_USBD_PRODUCTID_GSERIAL); + +			/* Assign endpoint indices */ +			tx_endpoint = GSERIAL_TX_ENDPOINT; +			rx_endpoint = GSERIAL_RX_ENDPOINT; + +			/* Configuration Descriptor */ +			configuration_descriptor = +				(struct usb_configuration_descriptor*) +				&gserial_configuration_descriptors; + +			/* Interface count */ +			interface_count = NUM_GSERIAL_INTERFACES; +		break; +	} +} -/*********************************************************************************/ +/******************************************************************************/  static struct urb *next_urb (struct usb_device_instance *device,  			     struct usb_endpoint_instance *endpoint) @@ -526,27 +833,39 @@ static int write_buffer (circbuf_t * buf)  		return 0;  	} -	if (buf->size) { +	struct usb_endpoint_instance *endpoint = +			&endpoint_instance[tx_endpoint]; +	struct urb *current_urb = NULL; -		struct usb_endpoint_instance *endpoint = -			&endpoint_instance[TX_ENDPOINT]; -		struct urb *current_urb = NULL; +	current_urb = next_urb (device_instance, endpoint); +	/* TX data still exists - send it now +	 */ +	if(endpoint->sent < current_urb->actual_length){ +		if(udc_endpoint_write (endpoint)){ +			/* Write pre-empted by RX */ +			return -1; +		} +	} + +	if (buf->size) {  		char *dest;  		int space_avail;  		int popnum, popped;  		int total = 0; -		/* Break buffer into urb sized pieces, and link each to the endpoint */ +		/* Break buffer into urb sized pieces, +		 * and link each to the endpoint +		 */  		while (buf->size > 0) { -			current_urb = next_urb (device_instance, endpoint); +  			if (!current_urb) {  				TTYERR ("current_urb is NULL, buf->size %d\n",  					buf->size);  				return total;  			} -			dest = current_urb->buffer + +			dest = (char*)current_urb->buffer +  				current_urb->actual_length;  			space_avail = @@ -562,14 +881,19 @@ static int write_buffer (circbuf_t * buf)  			current_urb->actual_length += popped;  			total += popped; -			/* If endpoint->last == 0, then transfers have not started on this endpoint */ +			/* If endpoint->last == 0, then transfers have +			 * not started on this endpoint +			 */  			if (endpoint->last == 0) { -				udc_endpoint_write (endpoint); +				if(udc_endpoint_write (endpoint)){ +					/* Write pre-empted by RX */ +					return -1; +				}  			} -		}		/* end while */ +		}/* end while */  		return total; -	}			/* end if tx_urb */ +	}  	return 0;  } @@ -577,18 +901,22 @@ static int write_buffer (circbuf_t * buf)  static int fill_buffer (circbuf_t * buf)  {  	struct usb_endpoint_instance *endpoint = -		&endpoint_instance[RECV_ENDPOINT]; +		&endpoint_instance[rx_endpoint];  	if (endpoint->rcv_urb && endpoint->rcv_urb->actual_length) { -		unsigned int nb = endpoint->rcv_urb->actual_length; +		unsigned int nb = 0;  		char *src = (char *) endpoint->rcv_urb->buffer; +		unsigned int rx_avail = buf->totalsize - buf->size; + +		if(rx_avail >= endpoint->rcv_urb->actual_length){ -		buf_push (buf, src, nb); -		endpoint->rcv_urb->actual_length = 0; +			nb = endpoint->rcv_urb->actual_length; +			buf_push (buf, src, nb); +			endpoint->rcv_urb->actual_length = 0; +		}  		return nb;  	} -  	return 0;  } @@ -597,7 +925,7 @@ static int usbtty_configured (void)  	return usbtty_configured_flag;  } -/*********************************************************************************/ +/******************************************************************************/  static void usbtty_event_handler (struct usb_device_instance *device,  				  usb_device_event_t event, int data) @@ -619,8 +947,34 @@ static void usbtty_event_handler (struct usb_device_instance *device,  	}  } -/*********************************************************************************/ +/******************************************************************************/ +int usbtty_cdc_setup(struct usb_device_request *request, struct urb *urb) +{ +	switch (request->bRequest){ + +	   	case ACM_SET_CONTROL_LINE_STATE:	/* Implies DTE ready */ +			break; +	   	case ACM_SEND_ENCAPSULATED_COMMAND :	/* Required */ +			break; +		case ACM_SET_LINE_ENCODING :		/* DTE stop/parity bits +							 * per character */ +			break; +	   	case ACM_GET_ENCAPSULATED_RESPONSE :	/* request response */ +			break; +		case ACM_GET_LINE_ENCODING :		/* request DTE rate, +							 * stop/parity bits */ +			memcpy (urb->buffer , &rs232_desc, sizeof(rs232_desc)); +			urb->actual_length = sizeof(rs232_desc); + +			break; +	 	default: +			return 1; +	} +	return 0; +} + +/******************************************************************************/  /*   * Since interrupt handling has not yet been implemented, we use this function @@ -630,36 +984,29 @@ static void usbtty_event_handler (struct usb_device_instance *device,  void usbtty_poll (void)  {  	/* New interrupts? */ -	pretend_interrupts (); +	udc_irq(); -	/* Write any output data to host buffer (do this before checking interrupts to avoid missing one) */ +	/* Write any output data to host buffer +	 * (do this before checking interrupts to avoid missing one) +	 */  	if (usbtty_configured ()) {  		write_buffer (&usbtty_output);  	}  	/* New interrupts? */ -	pretend_interrupts (); +	udc_irq(); -	/* Check for new data from host.. (do this after checking interrupts to get latest data) */ +	/* Check for new data from host.. +	 * (do this after checking interrupts to get latest data) +	 */  	if (usbtty_configured ()) {  		fill_buffer (&usbtty_input);  	}  	/* New interrupts? */ -	pretend_interrupts (); -} +	udc_irq(); -static void pretend_interrupts (void) -{ -	/* Loop while we have interrupts. -	 * If we don't do this, the input chain -	 * polling delay is likely to miss -	 * host requests. -	 */ -	while (inw (UDC_IRQ_SRC) & ~UDC_SOF_Flg) { -		/* Handle any new IRQs */ -		omap1510_udc_irq (); -		omap1510_udc_noniso_irq (); -	}  } + +  #endif diff --git a/drivers/usbtty.h b/drivers/usbtty.h index 79c2fe57d..8154e3072 100644 --- a/drivers/usbtty.h +++ b/drivers/usbtty.h @@ -2,6 +2,9 @@   * (C) Copyright 2003   * Gerry Hamel, geh@ti.com, Texas Instruments   * + * (C) Copyright 2006 + * Bryan O'Donoghue, bodonoghue@codehermit.ie, CodeHermit + *   * 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 @@ -21,44 +24,47 @@  #ifndef __USB_TTY_H__  #define __USB_TTY_H__ -  #include "usbdcore.h" +#if defined(CONFIG_PPC) +#include "usbdcore_mpc8xx.h" +#elif defined(CONFIG_ARM)  #include "usbdcore_omap1510.h" +#endif +#include <version_autogenerated.h> -#define NUM_CONFIGS    1 -#define NUM_INTERFACES 1 -#define NUM_ENDPOINTS  3 +/* If no VendorID/ProductID is defined in config.h, pretend to be Linux + * DO NOT Reuse this Vendor/Product setup with protocol incompatible devices */ -#define EP0_MAX_PACKET_SIZE 64 +#define CONFIG_USBD_VENDORID 0x0525 	/* Linux/NetChip */ +#define CONFIG_USBD_PRODUCTID_GSERIAL 0xa4a6	/* gserial */ +#define CONFIG_USBD_PRODUCTID_CDCACM  0xa4a7	/* CDC ACM */ +#define CONFIG_USBD_MANUFACTURER "Das U-Boot" +#define CONFIG_USBD_PRODUCT_NAME U_BOOT_VERSION -#define CONFIG_USBD_CONFIGURATION_STR "TTY via USB" -#define CONFIG_USBD_INTERFACE_STR     "Simple Serial Data Interface - Bulk Mode" +#define CONFIG_USBD_CONFIGURATION_STR "TTY via USB" -#define CONFIG_USBD_SERIAL_OUT_ENDPOINT 2 -#define CONFIG_USBD_SERIAL_OUT_PKTSIZE	64 -#define CONFIG_USBD_SERIAL_IN_ENDPOINT	1 -#define CONFIG_USBD_SERIAL_IN_PKTSIZE	64 -#define CONFIG_USBD_SERIAL_INT_ENDPOINT 5 -#define CONFIG_USBD_SERIAL_INT_PKTSIZE	16 - +#define CONFIG_USBD_SERIAL_OUT_ENDPOINT UDC_OUT_ENDPOINT +#define CONFIG_USBD_SERIAL_OUT_PKTSIZE	UDC_OUT_PACKET_SIZE +#define CONFIG_USBD_SERIAL_IN_ENDPOINT	UDC_IN_ENDPOINT +#define CONFIG_USBD_SERIAL_IN_PKTSIZE	UDC_IN_PACKET_SIZE +#define CONFIG_USBD_SERIAL_INT_ENDPOINT UDC_INT_ENDPOINT +#define CONFIG_USBD_SERIAL_INT_PKTSIZE	UDC_INT_PACKET_SIZE +#define CONFIG_USBD_SERIAL_BULK_PKTSIZE	UDC_BULK_PACKET_SIZE  #define USBTTY_DEVICE_CLASS	COMMUNICATIONS_DEVICE_CLASS -#define USBTTY_DEVICE_SUBCLASS	COMMUNICATIONS_NO_SUBCLASS -#define USBTTY_DEVICE_PROTOCOL	COMMUNICATIONS_NO_PROTOCOL - -#define USBTTY_INTERFACE_CLASS	   0xFF /* Vendor Specific */ -#define USBTTY_INTERFACE_SUBCLASS  0x02 -#define USBTTY_INTERFACE_PROTOCOL  0x01 -#define USBTTY_BCD_DEVICE 0x0 -#define USBTTY_MAXPOWER	  0x0 +#define USBTTY_BCD_DEVICE 	0x00 +#define USBTTY_MAXPOWER	  	0x00 -#define STR_MANUFACTURER 1 -#define STR_PRODUCT	 2 -#define STR_SERIAL	 3 -#define STR_CONFIG	 4 -#define STR_INTERFACE	 5 +#define STR_LANG		0x00 +#define STR_MANUFACTURER	0x01 +#define STR_PRODUCT		0x02 +#define STR_SERIAL		0x03 +#define STR_CONFIG		0x04 +#define STR_DATA_INTERFACE	0x05 +#define STR_CTRL_INTERFACE	0x06 +#define STR_COUNT		0x07  #endif diff --git a/include/asm-arm/arch-pxa/pxa-regs.h b/include/asm-arm/arch-pxa/pxa-regs.h index ebda7192e..e8cb29903 100644 --- a/include/asm-arm/arch-pxa/pxa-regs.h +++ b/include/asm-arm/arch-pxa/pxa-regs.h @@ -592,9 +592,11 @@ typedef void		(*ExcpHndlr) (void) ;  #define PMC_REG_BASE	__REG(0x40500400)  /* Primary Modem Codec */  #define SMC_REG_BASE	__REG(0x40500500)  /* Secondary Modem Codec */ +  /*   * USB Device Controller   */ +#ifndef CONFIG_CPU_MONAHANS  #define UDC_RES1	__REG(0x40600004)  /* UDC Undocumented - Reserved1 */  #define UDC_RES2	__REG(0x40600008)  /* UDC Undocumented - Reserved2 */  #define UDC_RES3	__REG(0x4060000C)  /* UDC Undocumented - Reserved3 */ @@ -749,11 +751,28 @@ typedef void		(*ExcpHndlr) (void) ;  #define USIR1_IR13	(1 << 5)	/* Interrup request ep 13 */  #define USIR1_IR14	(1 << 6)	/* Interrup request ep 14 */  #define USIR1_IR15	(1 << 7)	/* Interrup request ep 15 */ +#endif /* ! CONFIG_CPU_MONAHANS */ + +#if defined(CONFIG_PXA27X) || defined(CONFIG_CPU_MONAHANS) + +/* + * USB Client Controller (incomplete) + */ +#define UDCCR		__REG(0x40600000) +#define UDCICR0		__REG(0x40600004) +#define UDCCIR0		__REG(0x40600008) +#define UDCISR0		__REG(0x4060000c) +#define UDCSIR1		__REG(0x40600010) +#define UDCFNR		__REG(0x40600014) +#define UDCOTGICR	__REG(0x40600018) +#define UDCOTGISR	__REG(0x4060001c) +#define UP2OCR		__REG(0x40600020) +#define UP3OCR		__REG(0x40600024) -#if defined(CONFIG_PXA27X)  /*   * USB Host Controller   */ +#define OHCI_REGS_BASE	0x4C000000	/* required for ohci driver */  #define UHCREV		__REG(0x4C000000)  #define UHCHCON		__REG(0x4C000004)  #define UHCCOMS		__REG(0x4C000008) diff --git a/include/configs/AdderUSB.h b/include/configs/AdderUSB.h new file mode 100644 index 000000000..a4f7f9a28 --- /dev/null +++ b/include/configs/AdderUSB.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2006 CodeHermit. + * Bryan O'Donoghue <bodonoghue@codehermit.ie> + * + * Provides support for USB console on the Analogue & Micro Adder87x + * + * 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 + */ + +#ifndef __ADDERUSB__ +#define __ADDERUSB__ + +/* Include the board port */ +#include "Adder.h" + +#define CONFIG_USB_DEVICE		/* Include UDC driver */ +#define CONFIG_USB_TTY			/* Bind the TTY driver to UDC */ +#define CFG_USB_EXTC_CLK 0x02		/* Oscillator on EXTC_CLK 2 */ +#define CFG_USB_BRG_CLK	0x04		/* or use Baud rate generator 0x04 */ +#define CFG_CONSOLE_IS_IN_ENV		/* Console is in env */ + +/* If you have a USB-IF assigned VendorID then you may wish to define + * your own vendor specific values either in BoardName.h or directly in + * usbd_vendor_info.h + */ + +/* +#define CONFIG_USBD_MANUFACTURER	"CodeHermit.ie" +#define CONFIG_USBD_PRODUCT_NAME	"Das U-Boot" +#define CONFIG_USBD_VENDORID		0xFFFF +#define CONFIG_USBD_PRODUCTID_GSERIAL	0xFFFF +#define CONFIG_USBD_PRODUCTID_CDCACM	0xFFFE +*/ + +#endif /* __ADDERUSB_H__ */ diff --git a/include/configs/IceCube.h b/include/configs/IceCube.h index 0d3825413..c380c5459 100644 --- a/include/configs/IceCube.h +++ b/include/configs/IceCube.h @@ -94,9 +94,16 @@  /* USB */  #if 1 -#define CONFIG_USB_OHCI +#define CONFIG_USB_OHCI_NEW  #define ADD_USB_CMD             CFG_CMD_USB | CFG_CMD_FAT  #define CONFIG_USB_STORAGE + +#undef CFG_USB_OHCI_BOARD_INIT +#define CFG_USB_OHCI_CPU_INIT +#define CFG_USB_OHCI_REGS_BASE	MPC5XXX_USB +#define CFG_USB_OHCI_SLOT_NAME	"mpc5200" +#define CFG_USB_OHCI_MAX_ROOT_PORTS	15 +  #else  #define ADD_USB_CMD             0  #endif diff --git a/include/configs/TQM5200.h b/include/configs/TQM5200.h index 7069b35ad..5b011e82a 100644 --- a/include/configs/TQM5200.h +++ b/include/configs/TQM5200.h @@ -146,9 +146,16 @@  /* USB */  #if defined(CONFIG_STK52XX) || defined(CONFIG_FO300) -#define CONFIG_USB_OHCI +#define CONFIG_USB_OHCI_NEW  #define ADD_USB_CMD		CFG_CMD_USB | CFG_CMD_FAT  #define CONFIG_USB_STORAGE + +#undef CFG_USB_OHCI_BOARD_INIT +#define CFG_USB_OHCI_CPU_INIT +#define CFG_USB_OHCI_REGS_BASE	MPC5XXX_USB +#define CFG_USB_OHCI_SLOT_NAME	"mpc5200" +#define CFG_USB_OHCI_MAX_ROOT_PORTS	15 +  #else  #define ADD_USB_CMD		0  #endif diff --git a/include/configs/delta.h b/include/configs/delta.h index 91284fdac..4038f2196 100644 --- a/include/configs/delta.h +++ b/include/configs/delta.h @@ -94,12 +94,26 @@  # define CONFIG_COMMANDS	((CONFIG_CMD_DFL \  				  | CFG_CMD_ENV \  				  | CFG_CMD_NAND \ -				  | CFG_CMD_I2C) \ +				  | CFG_CMD_I2C \ +				  | CFG_CMD_USB \ +				  | CFG_CMD_FAT) \  				 & ~(CFG_CMD_NET \  				     | CFG_CMD_FLASH \  				     | CFG_CMD_IMLS))  #endif +/* USB */ +#define CONFIG_USB_OHCI_NEW	1 +#define CONFIG_USB_STORAGE      1 +#define CONFIG_DOS_PARTITION    1 + +#undef CFG_USB_OHCI_BOARD_INIT +#define CFG_USB_OHCI_CPU_INIT	1 +#define CFG_USB_OHCI_REGS_BASE	OHCI_REGS_BASE +#define CFG_USB_OHCI_SLOT_NAME	"delta" +#define CFG_USB_OHCI_MAX_ROOT_PORTS	3 + +#define LITTLEENDIAN            1       /* used by usb_ohci.c  */  /* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */  #include <cmd_confdefs.h> diff --git a/include/configs/mp2usb.h b/include/configs/mp2usb.h index 04f1f2408..2cf78a3b1 100644 --- a/include/configs/mp2usb.h +++ b/include/configs/mp2usb.h @@ -101,12 +101,18 @@  #undef	CONFIG_MODEM_SUPPORT		/* disable modem initialization stuff */ -#define CONFIG_USB_OHCI		1 +#define CONFIG_USB_OHCI_NEW	1  #define CONFIG_USB_KEYBOARD	1  #define CONFIG_USB_STORAGE	1  #define CONFIG_DOS_PARTITION	1  #define CONFIG_AT91C_PQFP_UHPBUG 1 +#undef CFG_USB_OHCI_BOARD_INIT +#define CFG_USB_OHCI_CPU_INIT		1 +#define CFG_USB_OHCI_REGS_BASE		AT91_USB_HOST_BASE +#define CFG_USB_OHCI_SLOT_NAME		"at91rm9200" +#define CFG_USB_OHCI_MAX_ROOT_PORTS	15 +  #undef CONFIG_HARD_I2C  #ifdef CONFIG_HARD_I2C @@ -127,7 +133,7 @@  #define CONFIG_COMMANDS		\  		       ((CONFIG_CMD_DFL	| \  			CFG_CMD_DATE	| \ -			CFG_CMD_DHCP 	| \ +			CFG_CMD_DHCP	| \  			CFG_CMD_EEPROM	| \  			CFG_CMD_I2C	| \  			CFG_CMD_NFS	| \ @@ -136,7 +142,7 @@  #else  #define CONFIG_COMMANDS		\  		       ((CONFIG_CMD_DFL	| \ -			CFG_CMD_DHCP 	| \ +			CFG_CMD_DHCP	| \  			CFG_CMD_NFS	| \  			CFG_CMD_SNTP	| \  			CFG_CMD_USB      | \ @@ -156,7 +162,7 @@  #define CONFIG_NR_DRAM_BANKS	1  #define PHYS_SDRAM		0x20000000 -#define PHYS_SDRAM_SIZE		0x08000000 	/* 128 megs */ +#define PHYS_SDRAM_SIZE		0x08000000	/* 128 megs */  #define CFG_MEMTEST_START	PHYS_SDRAM  #define CFG_MEMTEST_END		CFG_MEMTEST_START + PHYS_SDRAM_SIZE - 262144 diff --git a/include/configs/trab.h b/include/configs/trab.h index a2dc8e7bf..acf86d08a 100644 --- a/include/configs/trab.h +++ b/include/configs/trab.h @@ -80,10 +80,16 @@  #define CFG_EEPROM_PAGE_WRITE_DELAY_MS 10  /* USB stuff */ -#define CONFIG_USB_OHCI		1 +#define CONFIG_USB_OHCI_NEW	1  #define CONFIG_USB_STORAGE	1  #define CONFIG_DOS_PARTITION	1 +#undef CFG_USB_OHCI_BOARD_INIT +#define CFG_USB_OHCI_CPU_INIT	1 +#define CFG_USB_OHCI_REGS_BASE	S3C24X0_USB_HOST_BASE +#define CFG_USB_OHCI_SLOT_NAME	"s3c2400" +#define CFG_USB_OHCI_MAX_ROOT_PORTS	15 +  /*   * Size of malloc() pool   */ diff --git a/include/configs/yosemite.h b/include/configs/yosemite.h index 818462eed..b59f75b9d 100644 --- a/include/configs/yosemite.h +++ b/include/configs/yosemite.h @@ -233,9 +233,15 @@  #ifdef CONFIG_440EP  /* USB */ -#define CONFIG_USB_OHCI +#define CONFIG_USB_OHCI_NEW  #define CONFIG_USB_STORAGE +#undef CFG_USB_OHCI_BOARD_INIT +#define CFG_USB_OHCI_CPU_INIT	1 +#define CFG_USB_OHCI_REGS_BASE	(CFG_PERIPHERAL_BASE | 0x1000) +#define CFG_USB_OHCI_SLOT_NAME	"ppc440" +#define CFG_USB_OHCI_MAX_ROOT_PORTS	15 +  /* Comment this out to enable USB 1.1 device */  #define USB_2_0_DEVICE diff --git a/include/da9030.h b/include/da9030.h index 41108b9b3..3e3b20241 100644 --- a/include/da9030.h +++ b/include/da9030.h @@ -104,3 +104,15 @@  #define SYS_CONTROL_A_HWRES_ENABLE		(1<<2)  #define SYS_CONTROL_A_WDOG_ACTION		(1<<3)  #define SYS_CONTROL_A_WATCHDOG			(1<<7) + +#define MISC_CONTROLB_USB_INT_RISING		(1<<2) +#define MISC_CONTROLB_SESSION_VALID_EN		(1<<3) + +#define USB_PUMP_USBVE				(1<<0) +#define USB_PUMP_USBVEP				(1<<1) +#define USB_PUMP_SRP_DETECT			(1<<2) +#define USB_PUMP_SESSION_VALID			(1<<3) +#define USB_PUMP_VBUS_VALID_4_0			(1<<4) +#define USB_PUMP_VBUS_VALID_4_4			(1<<5) +#define USB_PUMP_EN_USBVE			(1<<6) +#define USB_PUMP_EN_USBVEP			(1<<7) diff --git a/include/usb.h b/include/usb.h index bf7155404..419a7e364 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   */ -#if defined(CONFIG_USB_UHCI) || defined(CONFIG_USB_OHCI) || defined (CONFIG_USB_SL811HS) +#if defined(CONFIG_USB_UHCI) || defined(CONFIG_USB_OHCI) || defined (CONFIG_USB_SL811HS) || defined(CONFIG_USB_OHCI_NEW)  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); @@ -230,16 +230,12 @@ 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) \ +#define __swap_16(x) \  	({ unsigned short x_ = (unsigned short)x; \  	 (unsigned short)( \  		((x_ & 0x00FFU) << 8) | ((x_ & 0xFF00U) >> 8) ); \  	}) -#define swap_32(x) \ +#define __swap_32(x) \  	({ unsigned long x_ = (unsigned long)x; \  	 (unsigned long)( \  		((x_ & 0x000000FFUL) << 24) | \ @@ -247,6 +243,13 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate);  		((x_ & 0x00FF0000UL) >>	 8) | \  		((x_ & 0xFF000000UL) >> 24) ); \  	}) + +#ifdef LITTLEENDIAN +# define swap_16(x) (x) +# define swap_32(x) (x) +#else +# define swap_16(x) __swap_16(x) +# define swap_32(x) __swap_32(x)  #endif /* LITTLEENDIAN */  /* diff --git a/include/usb_cdc_acm.h b/include/usb_cdc_acm.h new file mode 100644 index 000000000..87bf50c52 --- /dev/null +++ b/include/usb_cdc_acm.h @@ -0,0 +1,43 @@ +/* + * (C) Copyright 2006 + * Bryan O'Donoghue, deckard@codehermit.ie, CodeHermit + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* ACM Control Requests */ +#define ACM_SEND_ENCAPSULATED_COMMAND	0x00 +#define ACM_GET_ENCAPSULATED_RESPONSE	0x01 +#define ACM_SET_COMM_FEATURE		0x02 +#define ACM_GET_COMM_FEATRUE		0x03 +#define ACM_CLEAR_COMM_FEATURE		0x04 +#define ACM_SET_LINE_ENCODING		0x20 +#define ACM_GET_LINE_ENCODING		0x21 +#define ACM_SET_CONTROL_LINE_STATE	0x22 +#define ACM_SEND_BREAK			0x23 + +/* ACM Notification Codes */ +#define ACM_NETWORK_CONNECTION		0x00 +#define ACM_RESPONSE_AVAILABLE		0x01 +#define ACM_SERIAL_STATE		0x20 + +/* Format of response expected by a ACM_GET_LINE_ENCODING request */ +struct rs232_emu{ +		unsigned long dter; +		unsigned char stop_bits; +		unsigned char parity; +		unsigned char data_bits; +}__attribute__((packed)); diff --git a/include/usbdcore.h b/include/usbdcore.h index 6e92df13b..cb2be7280 100644 --- a/include/usbdcore.h +++ b/include/usbdcore.h @@ -576,6 +576,9 @@ struct usb_device_instance {  	void (*event) (struct usb_device_instance *device, usb_device_event_t event, int data); +	/* Do cdc device specific control requests */ +	int (*cdc_recv_setup)(struct usb_device_request *request, struct urb *urb); +  	/* bus interface */  	struct usb_bus_instance *bus;	/* which bus interface driver */ diff --git a/include/usbdcore_mpc8xx.h b/include/usbdcore_mpc8xx.h new file mode 100644 index 000000000..9df62f4ca --- /dev/null +++ b/include/usbdcore_mpc8xx.h @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2006 Bryan O'Donoghue, CodeHermit + * bodonoghue@codehermit.ie + * + * + * 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. + * + */ + +#include <commproc.h> + +/* Mode Register */ +#define USMOD_EN	0x01 +#define USMOD_HOST	0x02 +#define USMOD_TEST	0x04 +#define USMOD_SFTE	0x08 +#define USMOD_RESUME	0x40 +#define USMOD_LSS	0x80 + +/* Endpoint Registers */ +#define USEP_RHS_NORM	0x00 +#define USEP_RHS_IGNORE	0x01 +#define USEP_RHS_NAK	0x02 +#define USEP_RHS_STALL	0x03 + +#define USEP_THS_NORM	0x00 +#define USEP_THS_IGNORE	0x04 +#define USEP_THS_NAK	0x08 +#define USEP_THS_STALL	0x0C + +#define USEP_RTE	0x10 +#define USEP_MF		0x20 + +#define USEP_TM_CONTROL	0x00 +#define USEP_TM_INT	0x100 +#define USEP_TM_BULK	0x200 +#define USEP_TM_ISO	0x300 + +/* Command Register */ +#define USCOM_EP0	0x00 +#define USCOM_EP1	0x01 +#define USCOM_EP2	0x02 +#define USCOM_EP3	0x03 + +#define USCOM_FLUSH	0x40 +#define USCOM_STR	0x80 + +/* Event Register */ +#define USB_E_RXB	0x0001 +#define USB_E_TXB	0x0002 +#define USB_E_BSY	0x0004 +#define USB_E_SOF	0x0008 +#define USB_E_TXE1	0x0010 +#define USB_E_TXE2	0x0020 +#define USB_E_TXE3	0x0040 +#define USB_E_TXE4	0x0080 +#define USB_TX_ERRMASK (USB_E_TXE1|USB_E_TXE2|USB_E_TXE3|USB_E_TXE4) +#define USB_E_IDLE	0x0100 +#define USB_E_RESET	0x0200 + +/* Mask Register */ +#define USBS_IDLE	0x01 + +/* RX Buffer Descriptor */ +#define RX_BD_OV	0x02 +#define RX_BD_CR	0x04 +#define RX_BD_AB	0x08 +#define RX_BD_NO	0x10 +#define RX_BD_PID_DATA0	0x00 +#define RX_BD_PID_DATA1	0x40 +#define RX_BD_PID_SETUP	0x80 +#define RX_BD_F		0x400 +#define RX_BD_L		0x800 +#define RX_BD_I		0x1000 +#define RX_BD_W		0x2000 +#define RX_BD_E		0x8000 + +/* Useful masks */ +#define RX_BD_PID_BITMASK (RX_BD_PID_DATA1 | RX_BD_PID_SETUP) +#define STALL_BITMASK (USEP_THS_STALL | USEP_RHS_STALL) +#define NAK_BITMASK (USEP_THS_NAK | USEP_RHS_NAK) +#define CBD_TX_BITMASK (TX_BD_R | TX_BD_L | TX_BD_TC | TX_BD_I | TX_BD_CNF) + +/* TX Buffer Descriptor */ +#define TX_BD_UN	0x02 +#define TX_BD_TO	0x04 +#define TX_BD_NO_PID	0x00 +#define TX_BD_PID_DATA0	0x80 +#define TX_BD_PID_DATA1	0xC0 +#define TX_BD_CNF	0x200 +#define TX_BD_TC	0x400 +#define TX_BD_L		0x800 +#define TX_BD_I		0x1000 +#define TX_BD_W		0x2000 +#define TX_BD_R		0x8000 + +/* Implementation specific defines */ + +#define EP_MIN_PACKET_SIZE 0x08 +#define MAX_ENDPOINTS	0x04 +#define FIFO_SIZE	0x10 +#define EP_MAX_PKT	FIFO_SIZE +#define TX_RING_SIZE	0x04 +#define RX_RING_SIZE	0x06 +#define USB_MAX_PKT	0x40 +#define TOGGLE_TX_PID(x) x= ((~x)&0x40)|0x80 +#define TOGGLE_RX_PID(x) x^= 0x40 +#define EP_ATTACHED	0x01	/* Endpoint has a urb attached or not */ +#define EP_SEND_ZLP	0x02	/* Send ZLP y/n ? */ + +#define PROFF_USB	0x00000000 +#define CPM_USB_BASE	0x00000A00 + +/* UDC device defines */ +#define EP0_MAX_PACKET_SIZE	EP_MAX_PKT +#define UDC_OUT_ENDPOINT	0x02 +#define UDC_OUT_PACKET_SIZE	EP_MIN_PACKET_SIZE +#define UDC_IN_ENDPOINT		0x03 +#define UDC_IN_PACKET_SIZE	EP_MIN_PACKET_SIZE +#define UDC_INT_ENDPOINT	0x01 +#define UDC_INT_PACKET_SIZE	UDC_IN_PACKET_SIZE +#define UDC_BULK_PACKET_SIZE	EP_MIN_PACKET_SIZE + +struct mpc8xx_ep { +	struct urb * urb; +	unsigned char pid; +	unsigned char sc; +	volatile cbd_t * prx; +}; + +typedef struct mpc8xx_usb{ +	char usmod;	/* Mode Register */ +	char usaddr;	/* Slave Address Register */ +	char uscom;	/* Command Register */ +	char res1;	/* Reserved */ +	ushort usep[4]; +	ulong res2;	/* Reserved */ +	ushort usber;	/* Event Register */ +	ushort res3;	/* Reserved */ +	ushort usbmr;	/* Mask Register */ +	char res4;	/* Reserved */ +	char usbs;	/* Status Register */ +	char res5[8];	/* Reserved */ +}usb_t; + +typedef struct mpc8xx_parameter_ram{ +	ushort ep0ptr;	/* Endpoint Pointer Register 0 */ +	ushort ep1ptr;	/* Endpoint Pointer Register 1 */ +	ushort ep2ptr;	/* Endpoint Pointer Register 2 */ +	ushort ep3ptr;	/* Endpoint Pointer Register 3 */ +	uint rstate;	/* Receive state */ +	uint rptr;	/* Receive internal data pointer */ +	ushort frame_n;	/* Frame number */ +	ushort rbcnt;	/* Receive byte count */ +	uint rtemp;	/* Receive temp cp use only */ +	uint rxusb;	/* Rx Data Temp */ +	ushort rxuptr;	/* Rx microcode return address temp */ +}usb_pram_t; + +typedef struct endpoint_parameter_block_pointer{ +	ushort rbase;	/* RxBD base address */ +	ushort tbase;	/* TxBD base address */ +	char rfcr;	/* Rx Function code */ +	char tfcr;	/* Tx Function code */ +	ushort mrblr;	/* Maximum Receive Buffer Length */ +	ushort rbptr; 	/* RxBD pointer Next Buffer Descriptor */ +	ushort tbptr;	/* TxBD pointer Next Buffer Descriptor  */ +	ulong tstate;	/* Transmit internal state */ +	ulong tptr;	/* Transmit internal data pointer */ +	ushort tcrc;	/* Transmit temp CRC */ +	ushort tbcnt;	/* Transmit internal bye count */ +	ulong ttemp;	/* Tx temp */ +	ushort txuptr;	/* Tx microcode return address */ +	ushort res1;	/* Reserved */ +}usb_epb_t; + +typedef enum mpc8xx_udc_state{ +	STATE_NOT_READY, +	STATE_ERROR, +	STATE_READY, +}mpc8xx_udc_state_t; + +/* Declarations */ +int udc_init(void); +void udc_irq(void); +int udc_endpoint_write(struct usb_endpoint_instance *endpoint); +void udc_setup_ep(struct usb_device_instance *device, unsigned int ep, +		  struct usb_endpoint_instance *endpoint); +void udc_connect(void); +void udc_disconnect(void); +void udc_enable(struct usb_device_instance *device); +void udc_disable(void); +void udc_startup_events(struct usb_device_instance *device); + +/* Flow control */ +void udc_set_nak(int epid); +void udc_unset_nak (int epid); diff --git a/include/usbdcore_omap1510.h b/include/usbdcore_omap1510.h index 6ea333122..526fcd920 100644 --- a/include/usbdcore_omap1510.h +++ b/include/usbdcore_omap1510.h @@ -161,10 +161,20 @@  #define UDC_VBUS_CTRL	    (1 << 19)  #define UDC_VBUS_MODE	    (1 << 18) +/* OMAP Endpoint parameters */ +#define EP0_MAX_PACKET_SIZE 64 +#define UDC_OUT_ENDPOINT 2 +#define UDC_OUT_PACKET_SIZE 64 +#define UDC_IN_ENDPOINT	1 +#define UDC_IN_PACKET_SIZE 64 +#define UDC_INT_ENDPOINT 5 +#define UDC_INT_PKTSIZE	16 +#define UDC_BULK_PKTSIZE 16 -void omap1510_udc_irq(void); -void omap1510_udc_noniso_irq(void); - +void udc_irq (void); +/* Flow control */ +void udc_set_nak(int epid); +void udc_unset_nak (int epid);  /* Higher level functions for abstracting away from specific device */  void udc_endpoint_write(struct usb_endpoint_instance *endpoint); diff --git a/include/usbdescriptors.h b/include/usbdescriptors.h index 2d9f73934..a752097e5 100644 --- a/include/usbdescriptors.h +++ b/include/usbdescriptors.h @@ -92,33 +92,42 @@  #define COMMUNICATIONS_DEVICE_CLASS	0x02  /* c.f. CDC 4.2 Table 15 */ -#define COMMUNICATIONS_INTERFACE_CLASS	0x02 +#define COMMUNICATIONS_INTERFACE_CLASS_CONTROL	0x02 +#define COMMUNICATIONS_INTERFACE_CLASS_DATA		0x0A +#define COMMUNICATIONS_INTERFACE_CLASS_VENDOR	0x0FF  /* c.f. CDC 4.3 Table 16 */ -#define COMMUNICATIONS_NO_SUBCLASS	0x00 +#define COMMUNICATIONS_NO_SUBCLASS		0x00  #define COMMUNICATIONS_DLCM_SUBCLASS	0x01 -#define COMMUNICATIONS_ACM_SUBCLASS	0x02 -#define COMMUNICATIONS_TCM_SUBCLASS	0x03 +#define COMMUNICATIONS_ACM_SUBCLASS		0x02 +#define COMMUNICATIONS_TCM_SUBCLASS		0x03  #define COMMUNICATIONS_MCCM_SUBCLASS	0x04 -#define COMMUNICATIONS_CCM_SUBCLASS	0x05 +#define COMMUNICATIONS_CCM_SUBCLASS		0x05  #define COMMUNICATIONS_ENCM_SUBCLASS	0x06  #define COMMUNICATIONS_ANCM_SUBCLASS	0x07  /* c.f. WMCD 5.1 */  #define COMMUNICATIONS_WHCM_SUBCLASS	0x08 -#define COMMUNICATIONS_DMM_SUBCLASS	0x09 +#define COMMUNICATIONS_DMM_SUBCLASS		0x09  #define COMMUNICATIONS_MDLM_SUBCLASS	0x0a  #define COMMUNICATIONS_OBEX_SUBCLASS	0x0b -/* c.f. CDC 4.6 Table 18 */ +/* c.f. CDC 4.4 Table 17 */ +#define COMMUNICATIONS_NO_PROTOCOL		0x00 +#define COMMUNICATIONS_V25TER_PROTOCOL	0x01	/*Common AT Hayes compatible*/ + +/* c.f. CDC 4.5 Table 18 */  #define DATA_INTERFACE_CLASS		0x0a +/* c.f. CDC 4.6 No Table */ +#define DATA_INTERFACE_SUBCLASS_NONE	0x00	/* No subclass pertinent */ +  /* c.f. CDC 4.7 Table 19 */ -#define COMMUNICATIONS_NO_PROTOCOL	0x00 +#define DATA_INTERFACE_PROTOCOL_NONE	0x00	/* No class protcol required */  /* c.f. CDC 5.2.3 Table 24 */ -#define CS_INTERFACE			0x24 +#define CS_INTERFACE		0x24  #define CS_ENDPOINT			0x25  /* @@ -128,7 +137,7 @@   * c.f. WMCD 5.3 Table 5.3   */ -#define USB_ST_HEADER			0x00 +#define USB_ST_HEADER		0x00  #define USB_ST_CMF			0x01  #define USB_ST_ACMF			0x02  #define USB_ST_DLMF			0x03 @@ -137,18 +146,18 @@  #define USB_ST_UF			0x06  #define USB_ST_CSF			0x07  #define USB_ST_TOMF			0x08 -#define USB_ST_USBTF			0x09 +#define USB_ST_USBTF		0x09  #define USB_ST_NCT			0x0a  #define USB_ST_PUF			0x0b  #define USB_ST_EUF			0x0c  #define USB_ST_MCMF			0x0d  #define USB_ST_CCMF			0x0e  #define USB_ST_ENF			0x0f -#define USB_ST_ATMNF			0x10 +#define USB_ST_ATMNF		0x10  #define USB_ST_WHCM			0x11  #define USB_ST_MDLM			0x12 -#define USB_ST_MDLMD			0x13 +#define USB_ST_MDLMD		0x13  #define USB_ST_DMM			0x14  #define USB_ST_OBEX			0x15  #define USB_ST_CS			0x16 @@ -312,7 +321,8 @@ struct usb_class_union_function_descriptor {  	u8 bDescriptorType;  	u8 bDescriptorSubtype;	/* 0x06 */  	u8 bMasterInterface; -	u8 bSlaveInterface0[0]; +	/* u8 bSlaveInterface0[0]; */ +	u8 bSlaveInterface0;  } __attribute__ ((packed));  struct usb_class_country_selection_descriptor { |