diff options
| -rw-r--r-- | CHANGELOG | 5 | ||||
| -rw-r--r-- | Makefile | 3 | ||||
| -rw-r--r-- | board/sx1/Makefile | 47 | ||||
| -rw-r--r-- | board/sx1/config.mk | 19 | ||||
| -rw-r--r-- | board/sx1/flash.c | 436 | ||||
| -rw-r--r-- | board/sx1/platform.S | 406 | ||||
| -rw-r--r-- | board/sx1/sx1.c | 125 | ||||
| -rw-r--r-- | board/sx1/u-boot.lds | 56 | ||||
| -rw-r--r-- | common/Makefile | 8 | ||||
| -rw-r--r-- | common/circbuf.c | 110 | ||||
| -rw-r--r-- | common/cmd_load.c | 42 | ||||
| -rw-r--r-- | common/devices.c | 3 | ||||
| -rw-r--r-- | cpu/arm925t/interrupts.c | 38 | ||||
| -rw-r--r-- | drivers/Makefile | 11 | ||||
| -rw-r--r-- | drivers/ns16550.c | 9 | ||||
| -rw-r--r-- | drivers/omap1510_i2c.c | 281 | ||||
| -rw-r--r-- | drivers/usbdcore.c | 684 | ||||
| -rw-r--r-- | drivers/usbdcore_ep0.c | 686 | ||||
| -rw-r--r-- | drivers/usbdcore_omap1510.c | 1494 | ||||
| -rw-r--r-- | drivers/usbtty.c | 647 | ||||
| -rw-r--r-- | drivers/usbtty.h | 64 | ||||
| -rw-r--r-- | include/circbuf.h | 40 | ||||
| -rw-r--r-- | include/configs/SX1.h | 177 | ||||
| -rw-r--r-- | include/configs/omap1510.h | 94 | ||||
| -rw-r--r-- | include/devices.h | 3 | ||||
| -rw-r--r-- | include/usbdcore.h | 671 | ||||
| -rw-r--r-- | include/usbdcore_ep0.h | 39 | ||||
| -rw-r--r-- | include/usbdcore_omap1510.h | 183 | ||||
| -rw-r--r-- | include/usbdescriptors.h | 497 | ||||
| -rw-r--r-- | lib_arm/armlinux.c | 11 | ||||
| -rw-r--r-- | net/bootp.c | 512 | 
31 files changed, 7088 insertions, 313 deletions
| @@ -2,6 +2,9 @@  Changes for U-Boot 1.0.2:  ====================================================================== +* Add support for SX1 mobile phone; add support for USB-based console +  (enable with "setenv stdout usbtty; setenv stdin usbtty") +  * Fix LOWBOOT configuration for MPC5200 with DDR memory  * Fix SDRAM timings for LITE5200 / IceCube board @@ -15,7 +18,7 @@ Changes for U-Boot 1.0.2:  * Patch by Stephan Linz, 26 Feb 2004:    Bug fix for NFS code on NIOS targets -   +  * Patch by Stephen Williams, 26 Feb 2004:    Break up SystemACE reads of large block counts @@ -921,6 +921,9 @@ xtract_trab = $(subst _bigram,,$(subst _bigflash,,$(subst _old,,$(subst _config,  xtract_omap1610xxx = $(subst _cs0boot,,$(subst _cs3boot,, $(subst _config,,$1))) +SX1_config :		unconfig +	@./mkconfig $(@:_config=) arm arm925t sx1 +  omap1510inn_config :	unconfig  	@./mkconfig $(@:_config=) arm arm925t omap1510inn diff --git a/board/sx1/Makefile b/board/sx1/Makefile new file mode 100644 index 000000000..808c76afe --- /dev/null +++ b/board/sx1/Makefile @@ -0,0 +1,47 @@ +# +# (C) Copyright 2004 +# Wolfgang Denk, DENX Software Engineering, wd@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 $(TOPDIR)/config.mk + +LIB	= lib$(BOARD).a + +OBJS	:= sx1.o flash.o +SOBJS	:= platform.o + +$(LIB):	$(OBJS) $(SOBJS) +	$(AR) crv $@ $^ + +clean: +	rm -f $(SOBJS) $(OBJS) + +distclean:	clean +	rm -f $(LIB) core *.bak .depend + +######################################################################### + +.depend:	Makefile $(SOBJS:.o=.S) $(OBJS:.o=.c) +		$(CC) -M $(CPPFLAGS) $(SOBJS:.o=.S) $(OBJS:.o=.c) > $@ + +-include .depend + +######################################################################### diff --git a/board/sx1/config.mk b/board/sx1/config.mk new file mode 100644 index 000000000..4902e8233 --- /dev/null +++ b/board/sx1/config.mk @@ -0,0 +1,19 @@ +# +# (C) Copyright 2004 +# Wolfgang Denk, DENX Software Engineering, <wd@denx.de> +# +# SX1 board with OMAP1510 (ARM925T) cpu +# see http://www.ti.com/ for more information on Texas Insturments +# +# SX1 has 1 bank of 256 MB SDRAM +# Physical Address: +# 1000'0000 to 2000'0000 +# +# +# Linux-Kernel is expected to be at 1000'8000, entry 1000'8000  (mem base + reserved) +# +# we load ourself to 1108'0000 +# +# + +TEXT_BASE = 0x11080000 diff --git a/board/sx1/flash.c b/board/sx1/flash.c new file mode 100644 index 000000000..a4bed6147 --- /dev/null +++ b/board/sx1/flash.c @@ -0,0 +1,436 @@ +/* + * (C) Copyright 2001 + * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net + * + * (C) Copyright 2004 + * Wolfgang Denk, DENX Software Engineering, wd@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> +#include <linux/byteorder/swab.h> + +#define PHYS_FLASH_SECT_SIZE	0x00020000	/* 256 KB sectors (x2) */ +flash_info_t flash_info[CFG_MAX_FLASH_BANKS];	/* info for FLASH chips	   */ + +/* Board support for 1 or 2 flash devices */ +#undef FLASH_PORT_WIDTH32 +#define FLASH_PORT_WIDTH16 + +#ifdef FLASH_PORT_WIDTH16 +#define FLASH_PORT_WIDTH	ushort +#define FLASH_PORT_WIDTHV	vu_short +#define SWAP(x)			__swab16(x) +#else +#define FLASH_PORT_WIDTH	ulong +#define FLASH_PORT_WIDTHV	vu_long +#define SWAP(x)			__swab32(x) +#endif + +#define FPW	FLASH_PORT_WIDTH +#define FPWV	FLASH_PORT_WIDTHV + +#define mb() __asm__ __volatile__ ("" : : : "memory") + +/*----------------------------------------------------------------------- + * Functions + */ +static ulong flash_get_size (FPW * addr, flash_info_t * info); +static int write_data (flash_info_t * info, ulong dest, FPW data); +static void flash_get_offsets (ulong base, flash_info_t * info); +void inline spin_wheel (void); + +/*----------------------------------------------------------------------- + */ + +unsigned long flash_init (void) +{ +	int i; +	ulong size = 0; + +	for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) { +		switch (i) { +		case 0: +			flash_get_size ((FPW *) PHYS_FLASH_1, &flash_info[i]); +			flash_get_offsets (PHYS_FLASH_1, &flash_info[i]); +			break; +		case 1: +			flash_get_size ((FPW *) PHYS_FLASH_2, &flash_info[i]); +			flash_get_offsets (PHYS_FLASH_2, &flash_info[i]); +			break; +		default: +			panic ("configured too many flash banks!\n"); +			break; +		} +		size += flash_info[i].size; +	} + +	/* Protect monitor and environment sectors +	 */ +	flash_protect ( FLAG_PROTECT_SET, +			CFG_FLASH_BASE, +			CFG_FLASH_BASE + monitor_flash_len - 1, +			&flash_info[0]); + +	flash_protect ( FLAG_PROTECT_SET, +			CFG_ENV_ADDR, +			CFG_ENV_ADDR + CFG_ENV_SIZE - 1, +			&flash_info[0]); + +	return size; +} + +/*----------------------------------------------------------------------- + */ +static void flash_get_offsets (ulong base, flash_info_t * info) +{ +	int i; + +	if (info->flash_id == FLASH_UNKNOWN) { +		return; +	} + +	if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) { +		for (i = 0; i < info->sector_count; i++) { +			info->start[i] = base + (i * PHYS_FLASH_SECT_SIZE); +			info->protect[i] = 0; +		} +	} +} + +/*----------------------------------------------------------------------- + */ +void flash_print_info (flash_info_t * info) +{ +	int i; + +	if (info->flash_id == FLASH_UNKNOWN) { +		printf ("missing or unknown FLASH type\n"); +		return; +	} + +	switch (info->flash_id & FLASH_VENDMASK) { +	case FLASH_MAN_INTEL: +		printf ("INTEL "); +		break; +	default: +		printf ("Unknown Vendor "); +		break; +	} + +	switch (info->flash_id & FLASH_TYPEMASK) { +	case FLASH_28F128J3A: +		printf ("28F128J3A\n"); +		break; +	case FLASH_28F640J3A: +		printf ("28F640J3A\n"); +		break; +	default: +		printf ("Unknown Chip Type\n"); +		break; +	} + +	printf ("  Size: %ld MB in %d Sectors\n", +		info->size >> 20, info->sector_count); + +	printf ("  Sector Start Addresses:"); +	for (i = 0; i < info->sector_count; ++i) { +		if ((i % 5) == 0) +			printf ("\n   "); +		printf (" %08lX%s", +			info->start[i], +			info->protect[i] ? " (RO)" : "	   "); +	} +	printf ("\n"); +	return; +} + +/* + * The following code cannot be run from FLASH! + */ +static ulong flash_get_size (FPW * addr, flash_info_t * info) +{ +	volatile FPW value; + +	/* Write auto select command: read Manufacturer ID */ +	addr[0x5555] = (FPW) 0x00AA00AA; +	addr[0x2AAA] = (FPW) 0x00550055; +	addr[0x5555] = (FPW) 0x00900090; + +	mb (); +	value = addr[0]; + +	switch (value) { +	case (FPW) INTEL_MANUFACT: +		info->flash_id = FLASH_MAN_INTEL; +		break; +	default: +		info->flash_id = FLASH_UNKNOWN; +		info->sector_count = 0; +		info->size = 0; +		addr[0] = (FPW) 0x00FF00FF;	/* restore read mode */ +		return (0);			/* no or unknown flash	*/ +	} + +	mb (); +	value = addr[1];			/* device ID	    */ +	switch (value) { +	case (FPW) INTEL_ID_28F128J3A: +		info->flash_id += FLASH_28F128J3A; +		info->sector_count = 128; +		info->size = 0x01000000; +		break;				/* => 16 MB	*/ +	case (FPW) INTEL_ID_28F640J3A: +		info->flash_id += FLASH_28F640J3A; +		info->sector_count = 64; +		info->size = 0x00800000; +		break;				/* => 8 MB     */ +	default: +		info->flash_id = FLASH_UNKNOWN; +		break; +	} + +	if (info->sector_count > CFG_MAX_FLASH_SECT) { +		printf ("** ERROR: sector count %d > max (%d) **\n", +			info->sector_count, CFG_MAX_FLASH_SECT); +		info->sector_count = CFG_MAX_FLASH_SECT; +	} + +	addr[0] = (FPW) 0x00FF00FF;	/* restore read mode */ + +	return (info->size); +} + + +/*----------------------------------------------------------------------- + */ + +int flash_erase (flash_info_t * info, int s_first, int s_last) +{ +	int flag, prot, sect; +	ulong type, start, last; +	int rcode = 0; + +	if ((s_first < 0) || (s_first > s_last)) { +		if (info->flash_id == FLASH_UNKNOWN) { +			printf ("- missing\n"); +		} else { +			printf ("- no sectors to erase\n"); +		} +		return 1; +	} + +	type = (info->flash_id & FLASH_VENDMASK); +	if ((type != FLASH_MAN_INTEL)) { +		printf ("Can't erase unknown flash type %08lx - aborted\n", +			info->flash_id); +		return 1; +	} + +	prot = 0; +	for (sect = s_first; sect <= s_last; ++sect) { +		if (info->protect[sect]) { +			prot++; +		} +	} + +	if (prot) { +		printf ("- Warning: %d protected sectors will not be erased!\n", +			prot); +	} else { +		printf ("\n"); +	} + +	/*start = get_timer (0); */ +	last = start; + +	/* Disable interrupts which might cause a timeout here */ +	flag = disable_interrupts (); + +	/* Start erase on unprotected sectors */ +	for (sect = s_first; sect <= s_last; sect++) { +		if (info->protect[sect] == 0) { /* not protected */ +			FPWV *addr = (FPWV *) (info->start[sect]); +			FPW status; + +			printf ("Erasing sector %2d ... ", sect); + +			/* arm simple, non interrupt dependent timer */ +			reset_timer_masked (); + +			*addr = (FPW) 0x00500050;	/* clear status register */ +			*addr = (FPW) 0x00200020;	/* erase setup */ +			*addr = (FPW) 0x00D000D0;	/* erase confirm */ + +			while (((status = *addr) & (FPW) 0x00800080) != (FPW) 0x00800080) { +				if (get_timer_masked () > CFG_FLASH_ERASE_TOUT) { +					printf ("Timeout\n"); +					*addr = (FPW) 0x00B000B0;	/* suspend erase     */ +					*addr = (FPW) 0x00FF00FF;	/* reset to read mode */ +					rcode = 1; +					break; +				} +			} + +			*addr = (FPW) 0x00500050;	/* clear status register cmd.	*/ +			*addr = (FPW) 0x00FF00FF;	/* resest to read mode		*/ + +			printf (" done\n"); +		} +	} +	return rcode; +} + +/*----------------------------------------------------------------------- + * Copy memory to flash, returns: + * 0 - OK + * 1 - write timeout + * 2 - Flash not erased + * 4 - Flash not identified + */ + +int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) +{ +	ulong cp, wp; +	FPW data; +	int count, i, l, rc, port_width; + +	if (info->flash_id == FLASH_UNKNOWN) { +		return 4; +	} +/* get lower word aligned address */ +#ifdef FLASH_PORT_WIDTH16 +	wp = (addr & ~1); +	port_width = 2; +#else +	wp = (addr & ~3); +	port_width = 4; +#endif + +	/* +	 * handle unaligned start bytes +	 */ +	if ((l = addr - wp) != 0) { +		data = 0; +		for (i = 0, cp = wp; i < l; ++i, ++cp) { +			data = (data << 8) | (*(uchar *) cp); +		} +		for (; i < port_width && cnt > 0; ++i) { +			data = (data << 8) | *src++; +			--cnt; +			++cp; +		} +		for (; cnt == 0 && i < port_width; ++i, ++cp) { +			data = (data << 8) | (*(uchar *) cp); +		} + +		if ((rc = write_data (info, wp, SWAP (data))) != 0) { +			return (rc); +		} +		wp += port_width; +	} + +	/* +	 * handle word aligned part +	 */ +	count = 0; +	while (cnt >= port_width) { +		data = 0; +		for (i = 0; i < port_width; ++i) { +			data = (data << 8) | *src++; +		} +		if ((rc = write_data (info, wp, SWAP (data))) != 0) { +			return (rc); +		} +		wp += port_width; +		cnt -= port_width; +		if (count++ > 0x800) { +			spin_wheel (); +			count = 0; +		} +	} + +	if (cnt == 0) { +		return (0); +	} + +	/* +	 * handle unaligned tail bytes +	 */ +	data = 0; +	for (i = 0, cp = wp; i < port_width && cnt > 0; ++i, ++cp) { +		data = (data << 8) | *src++; +		--cnt; +	} +	for (; i < port_width; ++i, ++cp) { +		data = (data << 8) | (*(uchar *) cp); +	} + +	return (write_data (info, wp, SWAP (data))); +} + +/*----------------------------------------------------------------------- + * Write a word or halfword to Flash, returns: + * 0 - OK + * 1 - write timeout + * 2 - Flash not erased + */ +static int write_data (flash_info_t * info, ulong dest, FPW data) +{ +	FPWV *addr = (FPWV *) dest; +	ulong status; +	int flag; + +	/* Check if Flash is (sufficiently) erased */ +	if ((*addr & data) != data) { +		printf ("not erased at %08lx (%x)\n", (ulong) addr, *addr); +		return (2); +	} +	/* Disable interrupts which might cause a timeout here */ +	flag = disable_interrupts (); + +	*addr = (FPW) 0x00400040;	/* write setup */ +	*addr = data; + +	/* arm simple, non interrupt dependent timer */ +	reset_timer_masked (); + +	/* wait while polling the status register */ +	while (((status = *addr) & (FPW) 0x00800080) != (FPW) 0x00800080) { + +		if (get_timer_masked () > CFG_FLASH_WRITE_TOUT) { +			*addr = (FPW) 0x00FF00FF;	/* restore read mode */ +			return (1); +		} +	} + +	*addr = (FPW) 0x00FF00FF;	/* restore read mode */ + +	return (0); +} + +void inline spin_wheel (void) +{ +	static int p = 0; +	static char w[] = "\\/-"; + +	printf ("\010%c", w[p]); +	(++p == 3) ? (p = 0) : 0; +} diff --git a/board/sx1/platform.S b/board/sx1/platform.S new file mode 100644 index 000000000..304812805 --- /dev/null +++ b/board/sx1/platform.S @@ -0,0 +1,406 @@ +/* + * Board specific setup info + * + * (C) Copyright 2003 + * Texas Instruments, <www.ti.com> + * + * -- Some bits of code used from rrload's head_OMAP1510.s -- + * Copyright (C) 2002 RidgeRun, Inc. + * + * 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 <config.h> +#include <version.h> + +#if defined(CONFIG_OMAP1510) +#include <./configs/omap1510.h> +#endif + +#define OMAP1510_CLKS ((1<<EN_XORPCK)|(1<<EN_PERCK)|(1<<EN_TIMCK)|(1<<EN_GPIOCK)) + + +_TEXT_BASE: +	.word	TEXT_BASE	 /* sdram load addr from config.mk */ + +.globl platformsetup +platformsetup: + +	/* +	 * Configure 1510 pins functions to match our board. +	 */ +	ldr	r0, REG_PULL_DWN_CTRL_0 +	ldr	r1, VAL_PULL_DWN_CTRL_0 +	str	r1, [r0] +	ldr	r0, REG_PULL_DWN_CTRL_1 +	ldr	r1, VAL_PULL_DWN_CTRL_1 +	str	r1, [r0] +	ldr	r0, REG_PULL_DWN_CTRL_2 +	ldr	r1, VAL_PULL_DWN_CTRL_2 +	str	r1, [r0] +	ldr	r0, REG_PULL_DWN_CTRL_3 +	ldr	r1, VAL_PULL_DWN_CTRL_3 +	str	r1, [r0] +	ldr	r0, REG_FUNC_MUX_CTRL_4 +	ldr	r1, VAL_FUNC_MUX_CTRL_4 +	str	r1, [r0] +	ldr	r0, REG_FUNC_MUX_CTRL_5 +	ldr	r1, VAL_FUNC_MUX_CTRL_5 +	str	r1, [r0] +	ldr	r0, REG_FUNC_MUX_CTRL_6 +	ldr	r1, VAL_FUNC_MUX_CTRL_6 +	str	r1, [r0] +	ldr	r0, REG_FUNC_MUX_CTRL_7 +	ldr	r1, VAL_FUNC_MUX_CTRL_7 +	str	r1, [r0] +	ldr	r0, REG_FUNC_MUX_CTRL_8 +	ldr	r1, VAL_FUNC_MUX_CTRL_8 +	str	r1, [r0] +	ldr	r0, REG_FUNC_MUX_CTRL_9 +	ldr	r1, VAL_FUNC_MUX_CTRL_9 +	str	r1, [r0] +	ldr	r0, REG_FUNC_MUX_CTRL_A +	ldr	r1, VAL_FUNC_MUX_CTRL_A +	str	r1, [r0] +	ldr	r0, REG_FUNC_MUX_CTRL_B +	ldr	r1, VAL_FUNC_MUX_CTRL_B +	str	r1, [r0] +	ldr	r0, REG_FUNC_MUX_CTRL_C +	ldr	r1, VAL_FUNC_MUX_CTRL_C +	str	r1, [r0] +	ldr	r0, REG_FUNC_MUX_CTRL_D +	ldr	r1, VAL_FUNC_MUX_CTRL_D +	str	r1, [r0] +	ldr	r0, REG_VOLTAGE_CTRL_0 +	ldr	r1, VAL_VOLTAGE_CTRL_0 +	str	r1, [r0] +	ldr	r0, REG_TEST_DBG_CTRL_0 +	ldr	r1, VAL_TEST_DBG_CTRL_0 +	str	r1, [r0] +	ldr	r0, REG_MOD_CONF_CTRL_0 +	ldr	r1, VAL_MOD_CONF_CTRL_0 +	str	r1, [r0] + +	/* Move to 1510 mode */ +	ldr	r0, REG_COMP_MODE_CTRL_0 +	ldr	r1, VAL_COMP_MODE_CTRL_0 +	str	r1, [r0] + +	/* Set up Traffic Ctlr*/ +	ldr r0, REG_TC_IMIF_PRIO +	mov r1, #0x0 +	str r1, [r0] +	ldr r0, REG_TC_EMIFS_PRIO +	str r1, [r0] +	ldr r0, REG_TC_EMIFF_PRIO +	str r1, [r0] + +	ldr r0, REG_TC_EMIFS_CONFIG +	ldr r1, [r0] +	bic r1, r1, #0x08   /* clear the global power-down enable PDE bit */ +	bic r1, r1, #0x01   /* write protect flash by clearing the WP bit */ +	str r1, [r0]	    /* EMIFS GlB Configuration. (value 0x12 most likely) */ + +	ldr r0, _GPIO_PIN_CONTROL_REG +	ldrh r1,[r0] +	orr r1, r1, #0x0001 /* M_PCM_SYNC */ +	orr r1, r1, #0x4000 /* IPC_ACTIVE */ +	orr r1, r1, #0x0002 /* A_IRDA_OFF */ +	orr r1, r1, #0x0800 /* A_SWITCH	  */ +	orr r1, r1, #0x8000 /* A_USB_ON	  */ +	strh r1,[r0] + +	ldr r0, _GPIO_DIR_CONTROL_REG +	ldrh r1,[r0] +	bic r1, r1, #0x0001 /* M_PCM_SYNC */ +	bic r1, r1, #0x4000 /* IPC_ACTIVE */ +	bic r1, r1, #0x0002 /* A_IRDA_OFF */ +	bic r1, r1, #0x0800 /* A_SWITCH	  */ +	bic r1, r1, #0x8000 /* A_USB_ON	  */ +	strh r1,[r0] + +	ldr r0, _GPIO_DATA_OUTPUT_REG +	ldrh r1,[r0] +	bic r1, r1, #0x0001 /* M_PCM_SYNC */ +	orr r1, r1, #0x4000 /* IPC_ACTIVE */ +	orr r1, r1, #0x0002 /* A_IRDA_OFF */ +	bic r1, r1, #0x0800 /* A_SWITCH	  */ +	bic r1, r1, #0x8000 /* A_USB_ON	  */ +	strh r1,[r0] + +	/* Setup some clock domains */ +	ldr r1, =OMAP1510_CLKS +	ldr r0, REG_ARM_IDLECT2 +	strh r1, [r0]  /* CLKM, Clock domain control. */ + +	mov r1, #0x01  /* PER_EN bit */ +	ldr r0, REG_ARM_RSTCT2 +	strh r1, [r0]  /* CLKM; Peripheral reset. */ + +	/* Set CLKM to Sync-Scalable  */ +	/* I supposidly need to enable the dsp clock before switching */ +	mov r1, #0x1000 +	ldr r0, REG_ARM_SYSST +	strh r1, [r0] +	mov r0, #0x400 +1: +	subs r0, r0, #0x1   /* wait for any bubbles to finish */ +	bne 1b + +	ldr r1, VAL_ARM_CKCTL  /* use 12Mhz ref, PER must be <= 50Mhz so /2 */ +	ldr r0, REG_ARM_CKCTL +	strh r1, [r0] + +	/* setup DPLL 1 */ +	ldr r1, VAL_DPLL1_CTL +	ldr r0, REG_DPLL1_CTL +	strh r1, [r0] +	ands r1, r1, #0x10  /* Check if PLL is enabled. */ +	beq lock_end	    /* Do not look for lock if BYPASS selected */ +2: +	ldrh r1, [r0] +	ands r1, r1, #0x01  /* Check the LOCK bit. */ +	beq 2b		    /* ...loop until bit goes hi. */ +lock_end: + +	/* Set memory timings corresponding to the new clock speed */ + +	/* Check execution location to determine current execution location +	 * and branch to appropriate initialization code. +	 */ +	mov r0, #0x10000000		    /* Load physical SDRAM base. */ +	mov r1, pc			    /* Get current execution location. */ +	cmp r1, r0			    /* Compare. */ +	bge skip_sdram			    /* Skip over EMIF-fast initialization if running from SDRAM. */ + +	/* +	 * Delay for SDRAM initialization. +	 */ +	mov r3, #0x1800			       /* value should be checked */ +3: +	subs r3, r3, #0x1		      /* Decrement count */ +	bne 3b + +	/* +	 * Set SDRAM control values. Disable refresh before MRS command. +	 */ +	ldr r0, VAL_TC_EMIFF_SDRAM_CONFIG   /* get good value */ +	bic r3, r0, #0xC		    /* (BIT3|BIT2) ulConfig with auto-refresh disabled. */ +	orr r3, r3, #0x8000000		    /* (BIT27) Disable CLK when Power down or Self-Refresh */ +	orr r3, r3, #0x4000000		    /* BIT26 Power Down Enable */ +	ldr r2, REG_TC_EMIFF_SDRAM_CONFIG   /* Point to configuration register. */ +	str r3, [r2]			    /* Store the passed value with AR disabled. */ + +	ldr r1, VAL_TC_EMIFF_MRS	    /* get MRS value */ +	ldr r2, REG_TC_EMIFF_MRS	    /* Point to MRS register. */ +	str r1, [r2]			    /* Store the passed value.*/ + +	ldr r2, REG_TC_EMIFF_SDRAM_CONFIG   /* Point to configuration register. */ +	str r0, [r2]			    /* Store the passed value. */ + +	/* +	 * Delay for SDRAM initialization. +	 */ +	mov r3, #0x1800 +4: +	subs r3, r3, #1			    /* Decrement count. */ +	bne 4b + +skip_sdram: + +	/* slow interface */ +	ldr r1, VAL_TC_EMIFS_CS0_CONFIG +	ldr r0, REG_TC_EMIFS_CS0_CONFIG +	str r1, [r0] /* Chip Select 0 */ +	ldr r1, VAL_TC_EMIFS_CS1_CONFIG +	ldr r0, REG_TC_EMIFS_CS1_CONFIG +	str r1, [r0] /* Chip Select 1 */ +	ldr r1, VAL_TC_EMIFS_CS2_CONFIG +	ldr r0, REG_TC_EMIFS_CS2_CONFIG +	str r1, [r0] /* Chip Select 2 */ +	ldr r1, VAL_TC_EMIFS_CS3_CONFIG +	ldr r0, REG_TC_EMIFS_CS3_CONFIG +	str r1, [r0] /* Chip Select 3 */ + +	/* back to arch calling code */ +	mov	pc, lr + +/* the literal pools origin */ +	.ltorg + +/* OMAP configuration registers */ +REG_FUNC_MUX_CTRL_0:		/* 32 bits */ +	.word 0xfffe1000 +REG_FUNC_MUX_CTRL_1:		/* 32 bits */ +	.word 0xfffe1004 +REG_FUNC_MUX_CTRL_2:		/* 32 bits */ +	.word 0xfffe1008 +REG_COMP_MODE_CTRL_0:		/* 32 bits */ +	.word 0xfffe100c +REG_FUNC_MUX_CTRL_3:		/* 32 bits */ +	.word 0xfffe1010 +REG_FUNC_MUX_CTRL_4:		/* 32 bits */ +	.word 0xfffe1014 +REG_FUNC_MUX_CTRL_5:		/* 32 bits */ +	.word 0xfffe1018 +REG_FUNC_MUX_CTRL_6:		/* 32 bits */ +	.word 0xfffe101c +REG_FUNC_MUX_CTRL_7:		/* 32 bits */ +	.word 0xfffe1020 +REG_FUNC_MUX_CTRL_8:		/* 32 bits */ +	.word 0xfffe1024 +REG_FUNC_MUX_CTRL_9:		/* 32 bits */ +	.word 0xfffe1028 +REG_FUNC_MUX_CTRL_A:		/* 32 bits */ +	.word 0xfffe102C +REG_FUNC_MUX_CTRL_B:		/* 32 bits */ +	.word 0xfffe1030 +REG_FUNC_MUX_CTRL_C:		/* 32 bits */ +	.word 0xfffe1034 +REG_FUNC_MUX_CTRL_D:		/* 32 bits */ +	.word 0xfffe1038 +REG_PULL_DWN_CTRL_0:		/* 32 bits */ +	.word 0xfffe1040 +REG_PULL_DWN_CTRL_1:		/* 32 bits */ +	.word 0xfffe1044 +REG_PULL_DWN_CTRL_2:		/* 32 bits */ +	.word 0xfffe1048 +REG_PULL_DWN_CTRL_3:		/* 32 bits */ +	.word 0xfffe104c +REG_VOLTAGE_CTRL_0:		/* 32 bits */ +	.word 0xfffe1060 +REG_TEST_DBG_CTRL_0:		/* 32 bits */ +	.word 0xfffe1070 +REG_MOD_CONF_CTRL_0:		/* 32 bits */ +	.word 0xfffe1080 +REG_TC_IMIF_PRIO:		/* 32 bits */ +	.word 0xfffecc00 +REG_TC_EMIFS_PRIO:		/* 32 bits */ +	.word 0xfffecc04 +REG_TC_EMIFF_PRIO:		/* 32 bits */ +	.word 0xfffecc08 +REG_TC_EMIFS_CONFIG:		/* 32 bits */ +	.word 0xfffecc0c +REG_TC_EMIFS_CS0_CONFIG:	/* 32 bits */ +	.word 0xfffecc10 +REG_TC_EMIFS_CS1_CONFIG:	/* 32 bits */ +	.word 0xfffecc14 +REG_TC_EMIFS_CS2_CONFIG:	/* 32 bits */ +	.word 0xfffecc18 +REG_TC_EMIFS_CS3_CONFIG:	/* 32 bits */ +	.word 0xfffecc1c +REG_TC_EMIFF_SDRAM_CONFIG:	/* 32 bits */ +	.word 0xfffecc20 +REG_TC_EMIFF_MRS:		/* 32 bits */ +	.word 0xfffecc24 +/* MPU clock/reset/power mode control registers */ +REG_ARM_CKCTL:			/* 16 bits */ +	.word 0xfffece00 +REG_ARM_IDLECT2:		/* 16 bits */ +	.word 0xfffece08 +REG_ARM_RSTCT2:			/* 16 bits */ +	.word 0xfffece14 +REG_ARM_SYSST:			/* 16 bits */ +	.word 0xfffece18 +/* DPLL control registers */ +REG_DPLL1_CTL:			/* 16 bits */ +	.word 0xfffecf00 +/* identification code register */ +REG_IDCODE:			/* 32 bits */ +	.word 0xfffed404 + +/* SX1 specific */ +_GPIO_PIN_CONTROL_REG: +	.word GPIO_PIN_CONTROL_REG +_GPIO_DIR_CONTROL_REG: +	.word GPIO_DIR_CONTROL_REG +_GPIO_DATA_OUTPUT_REG: +	.word GPIO_DATA_OUTPUT_REG + +VAL_COMP_MODE_CTRL_0: +	.word 0x0000eaef +VAL_FUNC_MUX_CTRL_4: +	.word 0x00000000 +VAL_FUNC_MUX_CTRL_5: +	.word 0x00000000 +VAL_FUNC_MUX_CTRL_6: +	.word 0x00000001 +VAL_FUNC_MUX_CTRL_7: +	.word 0x00001000 +VAL_FUNC_MUX_CTRL_8: +	.word 0x00001240       /*[Knoller]  Value of Symbian Image Wing B2*/ +VAL_FUNC_MUX_CTRL_9: +	.word 0x00201008 +VAL_FUNC_MUX_CTRL_A: +	.word 0x00001000 +VAL_FUNC_MUX_CTRL_B: +	.word 0x00000000 +VAL_FUNC_MUX_CTRL_C: +	.word 0x09008001       /*[Knoller]  Value of Symbian Image Wing B2*/ +VAL_FUNC_MUX_CTRL_D: +	.word 0x00000000 +VAL_PULL_DWN_CTRL_0: +	.word 0xfffeffff +VAL_PULL_DWN_CTRL_1: +	.word 0xd1ffffec +VAL_PULL_DWN_CTRL_2: +	.word 0xffa80c5b +VAL_PULL_DWN_CTRL_3: +	.word 0xffffc0fe +VAL_VOLTAGE_CTRL_0: +	.word 0x00000007 +VAL_TEST_DBG_CTRL_0: +	/* The OMAP5910 TRM says this register must be 0, but HelenConfRegs +	 * says to write a 7.  Don't know what the right thing is to do, so +	 * I'm leaving it at 7 since that's what was already here. +	 */ +	.word 0x00000007 +VAL_MOD_CONF_CTRL_0: +	.word 0x0da20000       /*[Knoller]  Value of Symbian Image Wing B2*/ + +VAL_ARM_CKCTL: +	.word 0x010D + +VAL_DPLL1_CTL: +	.word 0x3A33   /*[Hertle] Value of Symbian Image*/ + +VAL_TC_EMIFS_CS1_CONFIG_PRELIM: +	.word 0x00001149 + +VAL_TC_EMIFS_CS2_CONFIG_PRELIM: +	.word 0x00004158 + +VAL_TC_EMIFS_CS0_CONFIG: +	.word 0x00213090       /*[Knoller]  Value of Symbian Image Wing B2*/ + +VAL_TC_EMIFS_CS1_CONFIG: +	.word 0x00215070       /*[Knoller]  Value of Symbian Image Wing B2*/ + +VAL_TC_EMIFS_CS2_CONFIG: +	.word 0x00001139       /*[Knoller]  Value of Symbian Image Wing B2*/ + +VAL_TC_EMIFS_CS3_CONFIG: +	.word 0x00001139       /*[Knoller]  Value of Symbian Image Wing B2*/ + +VAL_TC_EMIFF_SDRAM_CONFIG: +	.word 0x0105f0b4       /*[Knoller]  Value of Symbian Image Wing B2*/ + + +VAL_TC_EMIFF_MRS: +	.word 0x00000027       /*[Knoller]  Value of Symbian Image Wing B2*/ diff --git a/board/sx1/sx1.c b/board/sx1/sx1.c new file mode 100644 index 000000000..c14a385b1 --- /dev/null +++ b/board/sx1/sx1.c @@ -0,0 +1,125 @@ +/* + * (C) Copyright 2004 + * Wolfgang Denk, DENX Software Engineering, <wd@denx.de> + * + * (C) Copyright 2003 + * Texas Instruments, <www.ti.com> + * Kshitij Gupta <Kshitij@ti.com> + * + * 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> + +static void flash__init (void); +static void ether__init (void); + +static inline void delay (unsigned long loops) +{ +	__asm__ volatile ("1:\n" +			  "subs %0, %1, #1\n" +			  "bne 1b":"=r" (loops):"0" (loops)); +} + +/* + * Miscellaneous platform dependent initialisations + */ + +int board_init (void) +{ +	DECLARE_GLOBAL_DATA_PTR; + +	/* arch number of SX1 Board */ +	gd->bd->bi_arch_number = 241; + +	/* adress of boot parameters */ +	gd->bd->bi_boot_params = 0x10000100; + +/* kk - this speeds up your boot a quite a bit.	 However to make it + *  work, you need make sure your kernel startup flush bug is fixed. + *  ... rkw ... + */ +	icache_enable (); + +	flash__init (); +	ether__init (); +	return 0; +} + + +int misc_init_r (void) +{ +	/* volatile ushort *gdir = (ushort *) (GPIO_DIR_CONTROL_REG); */ +	/* volatile ushort *mdir = (ushort *) (MPUIO_DIR_CONTROL_REG); */ + +	/* setup gpio direction to match board (no floats!) */ +	/**gdir = 0xCFF9; */ +	/**mdir = 0x103F; */ + +	return (0); +} + +/****************************** + Routine: + Description: +******************************/ +static void flash__init (void) +{ +#define CS0_CHIP_SELECT_REG 0xfffecc10 +#define CS3_CHIP_SELECT_REG 0xfffecc1c +#define EMIFS_GlB_Config_REG 0xfffecc0c + +	unsigned int regval; + +	regval = *((volatile unsigned int *) EMIFS_GlB_Config_REG); +	regval = regval | 0x0001;	/* Turn off write protection for flash devices. */ +	if (regval & 0x0002) { +		regval = regval & 0xfffd;	/* Swap CS0 and CS3 so that flash is visible at 0x0 and eeprom at 0x0c000000. */ +		/* If, instead, you want to reference flash at 0x0c000000, then it seemed the following were necessary. */ +		/* *((volatile unsigned int *)CS0_CHIP_SELECT_REG) = 0x202090; / * Overrides head.S setting of 0x212090 */ +		/* *((volatile unsigned int *)CS3_CHIP_SELECT_REG) = 0x202090; / * Let's flash chips be fully functional. */ +	} +	*((volatile unsigned int *) EMIFS_GlB_Config_REG) = regval; +} + + +/****************************** + Routine: + Description: +******************************/ +static void ether__init (void) +{ +#define ETH_CONTROL_REG 0x0800000b +	/* take the Ethernet controller out of reset and wait +	 * for the EEPROM load to complete. +	 */ +	*((volatile unsigned char *) ETH_CONTROL_REG) &= ~0x01; +	udelay (3); +} + + +int dram_init (void) +{ +	DECLARE_GLOBAL_DATA_PTR; + +	gd->bd->bi_dram[0].start = PHYS_SDRAM_1; +	gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE; + +	return 0; +} diff --git a/board/sx1/u-boot.lds b/board/sx1/u-boot.lds new file mode 100644 index 000000000..670f4db7b --- /dev/null +++ b/board/sx1/u-boot.lds @@ -0,0 +1,56 @@ +/* + * (C) Copyright 2004 + * Wolfgang Denk, DENX Software Engineering, <wg@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 + */ + +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/ +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ +	. = 0x00000000; + +	. = ALIGN(4); +	.text	   : +	{ +	  cpu/arm925t/start.o	(.text) +	  *(.text) +	} + +	. = ALIGN(4); +	.rodata : { *(.rodata) } + +	. = ALIGN(4); +	.data : { *(.data) } + +	. = ALIGN(4); +	.got : { *(.got) } + +	__u_boot_cmd_start = .; +	.u_boot_cmd : { *(.u_boot_cmd) } +	__u_boot_cmd_end = .; + +	. = ALIGN(4); +	__bss_start = .; +	.bss : { *(.bss) } +	_end = .; +} diff --git a/common/Makefile b/common/Makefile index eccb4e46f..4c94fc03a 100644 --- a/common/Makefile +++ b/common/Makefile @@ -1,5 +1,5 @@  # -# (C) Copyright 2000, 2001 +# (C) Copyright 2004  # Wolfgang Denk, DENX Software Engineering, wd@denx.de.  #  # See file CREDITS for list of people who contributed to this @@ -12,7 +12,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 @@ -47,7 +47,7 @@ COBJS	= main.o ACEX1K.o altera.o bedbug.o \  	  hush.o kgdb.o lists.o lynxkdi.o memsize.o miiphybb.o miiphyutil.o \  	  s_record.o soft_i2c.o soft_spi.o spartan2.o \  	  usb.o usb_kbd.o usb_storage.o \ -	  virtex2.o xilinx.o +	  virtex2.o xilinx.o circbuf.o  OBJS	= $(AOBJS) $(COBJS) @@ -55,7 +55,7 @@ CPPFLAGS += -I..  all:	$(LIB) $(AOBJS) -$(LIB):	.depend $(OBJS) +$(LIB): .depend $(OBJS)  	$(AR) crv $@ $(OBJS)  environment.o: environment.c ../tools/envcrc diff --git a/common/circbuf.c b/common/circbuf.c new file mode 100644 index 000000000..2332c6371 --- /dev/null +++ b/common/circbuf.c @@ -0,0 +1,110 @@ +/* + * (C) Copyright 2003 + * Gerry Hamel, geh@ti.com, Texas Instruments + * + * 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> +#include <malloc.h> + +#include <circbuf.h> + + +int buf_init (circbuf_t * buf, unsigned int size) +{ +	assert (buf != NULL); + +	buf->size = 0; +	buf->totalsize = size; +	buf->data = (char *) malloc (sizeof (char) * size); +	assert (buf->data != NULL); + +	buf->top = buf->data; +	buf->tail = buf->data; +	buf->end = &(buf->data[size]); + +	return 1; +} + +int buf_free (circbuf_t * buf) +{ +	assert (buf != NULL); +	assert (buf->data != NULL); + +	free (buf->data); +	memset (buf, 0, sizeof (circbuf_t)); + +	return 1; +} + +int buf_pop (circbuf_t * buf, char *dest, unsigned int len) +{ +	unsigned int i; +	char *p = buf->top; + +	assert (buf != NULL); +	assert (dest != NULL); + +	/* Cap to number of bytes in buffer */ +	if (len > buf->size) +		len = buf->size; + +	for (i = 0; i < len; i++) { +		dest[i] = *p++; +		/* Bounds check. */ +		if (p == buf->end) { +			p = buf->data; +		} +	} + +	/* Update 'top' pointer */ +	buf->top = p; +	buf->size -= len; + +	return len; +} + +int buf_push (circbuf_t * buf, const char *src, unsigned int len) +{ +	/* NOTE:  this function allows push to overwrite old data. */ +	unsigned int i; +	char *p = buf->tail; + +	assert (buf != NULL); +	assert (src != NULL); + +	for (i = 0; i < len; i++) { +		*p++ = src[i]; +		if (p == buf->end) { +			p = buf->data; +		} +		/* Make sure pushing too much data just replaces old data */ +		if (buf->size < buf->totalsize) { +			buf->size++; +		} else { +			buf->top++; +			if (buf->top == buf->end) { +				buf->top = buf->data; +			} +		} +	} + +	/* Update 'tail' pointer */ +	buf->tail = p; + +	return len; +} diff --git a/common/cmd_load.c b/common/cmd_load.c index 702cab6dc..b85db69e1 100644 --- a/common/cmd_load.c +++ b/common/cmd_load.c @@ -1,5 +1,5 @@  /* - * (C) Copyright 2000-2003 + * (C) Copyright 2000-2004   * Wolfgang Denk, DENX Software Engineering, wd@denx.de.   *   * See file CREDITS for list of people who contributed to this @@ -104,8 +104,8 @@ int do_load_serial (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])  	 * box some time (100 * 1 ms)  	 */  	for (i=0; i<100; ++i) { -		if (serial_tstc()) { -			(void) serial_getc(); +		if (tstc()) { +			(void) getc();  		}  		udelay(1000);  	} @@ -220,9 +220,9 @@ read_record (char *buf, ulong len)  	--len;	/* always leave room for terminating '\0' byte */  	for (p=buf; p < buf+len; ++p) { -		c = serial_getc();		/* read character		*/ +		c = getc();		/* read character		*/  		if (do_echo) -			serial_putc (c);	/* ... and echo it		*/ +			putc (c);	/* ... and echo it		*/  		switch (c) {  		case '\r': @@ -237,7 +237,7 @@ read_record (char *buf, ulong len)  		}  	    /* Check for the console hangup (if any different from serial) */ -	    if (gd->jt[XF_getc] != serial_getc) { +	    if (gd->jt[XF_getc] != getc) {  		if (ctrlc()) {  		    return (-1);  		} @@ -387,7 +387,7 @@ write_record (char *buf)  	char c;  	while((c = *buf++)) -		serial_putc(c); +		putc(c);  	/* Check for the console hangup (if any different from serial) */ @@ -531,8 +531,8 @@ static ulong load_serial_bin (ulong offset)  	 * box some time (100 * 1 ms)  	 */  	for (i=0; i<100; ++i) { -		if (serial_tstc()) { -			(void) serial_getc(); +		if (tstc()) { +			(void) getc();  		}  		udelay(1000);  	} @@ -551,7 +551,7 @@ void send_pad (void)  	int count = his_pad_count;  	while (count-- > 0) -		serial_putc (his_pad_char); +		putc (his_pad_char);  }  /* converts escaped kermit char to binary char */ @@ -579,7 +579,7 @@ void s1_sendpacket (char *packet)  {  	send_pad ();  	while (*packet) { -		serial_putc (*packet++); +		putc (*packet++);  	}  } @@ -841,7 +841,7 @@ static int k_recv (void)  		/* get a packet */  		/* wait for the starting character or ^C */  		for (;;) { -			switch (serial_getc ()) { +			switch (getc ()) {  			case START_CHAR:	/* start packet */  				goto START;  			case ETX_CHAR:		/* ^C waiting for packet */ @@ -853,13 +853,13 @@ static int k_recv (void)  START:  		/* get length of packet */  		sum = 0; -		new_char = serial_getc (); +		new_char = getc ();  		if ((new_char & 0xE0) == 0)  			goto packet_error;  		sum += new_char & 0xff;  		length = untochar (new_char);  		/* get sequence number */ -		new_char = serial_getc (); +		new_char = getc ();  		if ((new_char & 0xE0) == 0)  			goto packet_error;  		sum += new_char & 0xff; @@ -886,7 +886,7 @@ START:  		/* END NEW CODE */  		/* get packet type */ -		new_char = serial_getc (); +		new_char = getc ();  		if ((new_char & 0xE0) == 0)  			goto packet_error;  		sum += new_char & 0xff; @@ -896,19 +896,19 @@ START:  		if (length == -2) {  			/* (length byte was 0, decremented twice) */  			/* get the two length bytes */ -			new_char = serial_getc (); +			new_char = getc ();  			if ((new_char & 0xE0) == 0)  				goto packet_error;  			sum += new_char & 0xff;  			len_hi = untochar (new_char); -			new_char = serial_getc (); +			new_char = getc ();  			if ((new_char & 0xE0) == 0)  				goto packet_error;  			sum += new_char & 0xff;  			len_lo = untochar (new_char);  			length = len_hi * 95 + len_lo;  			/* check header checksum */ -			new_char = serial_getc (); +			new_char = getc ();  			if ((new_char & 0xE0) == 0)  				goto packet_error;  			if (new_char != tochar ((sum + ((sum >> 6) & 0x03)) & 0x3f)) @@ -918,7 +918,7 @@ START:  		}  		/* bring in rest of packet */  		while (length > 1) { -			new_char = serial_getc (); +			new_char = getc ();  			if ((new_char & 0xE0) == 0)  				goto packet_error;  			sum += new_char & 0xff; @@ -935,13 +935,13 @@ START:  			}  		}  		/* get and validate checksum character */ -		new_char = serial_getc (); +		new_char = getc ();  		if ((new_char & 0xE0) == 0)  			goto packet_error;  		if (new_char != tochar ((sum + ((sum >> 6) & 0x03)) & 0x3f))  			goto packet_error;  		/* get END_CHAR */ -		new_char = serial_getc (); +		new_char = getc ();  		if (new_char != END_CHAR) {  		  packet_error:  			/* restore state machines */ diff --git a/common/devices.c b/common/devices.c index bf7486ac4..aa055339e 100644 --- a/common/devices.c +++ b/common/devices.c @@ -194,6 +194,9 @@ int devices_init (void)  	drv_logbuff_init ();  #endif  	drv_system_init (); +#ifdef CONFIG_USB_TTY +	drv_usbtty_init (); +#endif  	return (0);  } diff --git a/cpu/arm925t/interrupts.c b/cpu/arm925t/interrupts.c index 00e8c18e1..d77c4e6f6 100644 --- a/cpu/arm925t/interrupts.c +++ b/cpu/arm925t/interrupts.c @@ -23,7 +23,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 @@ -107,15 +107,15 @@ void show_regs (struct pt_regs *regs)  	flags = condition_codes (regs); -	printf ("pc : [<%08lx>]    lr : [<%08lx>]\n" -		"sp : %08lx  ip : %08lx  fp : %08lx\n", +	printf ("pc : [<%08lx>]	   lr : [<%08lx>]\n" +		"sp : %08lx  ip : %08lx	 fp : %08lx\n",  		instruction_pointer (regs),  		regs->ARM_lr, regs->ARM_sp, regs->ARM_ip, regs->ARM_fp); -	printf ("r10: %08lx  r9 : %08lx  r8 : %08lx\n", +	printf ("r10: %08lx  r9 : %08lx	 r8 : %08lx\n",  		regs->ARM_r10, regs->ARM_r9, regs->ARM_r8); -	printf ("r7 : %08lx  r6 : %08lx  r5 : %08lx  r4 : %08lx\n", +	printf ("r7 : %08lx  r6 : %08lx	 r5 : %08lx  r4 : %08lx\n",  		regs->ARM_r7, regs->ARM_r6, regs->ARM_r5, regs->ARM_r4); -	printf ("r3 : %08lx  r2 : %08lx  r1 : %08lx  r0 : %08lx\n", +	printf ("r3 : %08lx  r2 : %08lx	 r1 : %08lx  r0 : %08lx\n",  		regs->ARM_r3, regs->ARM_r2, regs->ARM_r1, regs->ARM_r0);  	printf ("Flags: %c%c%c%c",  		flags & CC_N_BIT ? 'N' : 'n', @@ -227,17 +227,17 @@ void udelay (unsigned long usec)  #else  	ulong tmo, tmp; -	if(usec >= 1000){               /* if "big" number, spread normalization to seconds */ -		tmo = usec / 1000;      /* start to normalize for usec to ticks per sec */ -		tmo *= CFG_HZ;          /* find number of "ticks" to wait to achieve target */ -		tmo /= 1000;            /* finish normalize. */ -	}else{                          /* else small number, don't kill it prior to HZ multiply */ +	if(usec >= 1000){		/* if "big" number, spread normalization to seconds */ +		tmo = usec / 1000;	/* start to normalize for usec to ticks per sec */ +		tmo *= CFG_HZ;		/* find number of "ticks" to wait to achieve target */ +		tmo /= 1000;		/* finish normalize. */ +	}else{				/* else small number, don't kill it prior to HZ multiply */  		tmo = usec * CFG_HZ;  		tmo /= (1000*1000);  	}  	tmp = get_timer (0);		/* get current timestamp */ -	if( (tmo + tmp + 1) < tmp ) 	/* if setting this fordward will roll time stamp */ +	if( (tmo + tmp + 1) < tmp )	/* if setting this fordward will roll time stamp */  		reset_timer_masked ();	/* reset "advancing" timestamp to 0, set lastdec value */  	else  		tmo += tmp;		/* else, set advancing stamp wake up time */ @@ -251,7 +251,7 @@ void reset_timer_masked (void)  {  	/* reset time */  	lastdec = READ_TIMER;  /* capure current decrementer value time */ -	timestamp = 0;         /* start "advancing" time stamp from 0 */ +	timestamp = 0;	       /* start "advancing" time stamp from 0 */  }  ulong get_timer_masked (void) @@ -283,13 +283,13 @@ void udelay_masked (unsigned long usec)      for (i=time_remaining; i>0; i--) { }  #else -	ulong tmo, tmp; +	ulong tmo; -	if(usec >= 1000){               /* if "big" number, spread normalization to seconds */ -		tmo = usec / 1000;      /* start to normalize for usec to ticks per sec */ -		tmo *= CFG_HZ;          /* find number of "ticks" to wait to achieve target */ -		tmo /= 1000;            /* finish normalize. */ -	}else{                          /* else small number, don't kill it prior to HZ multiply */ +	if(usec >= 1000){		/* if "big" number, spread normalization to seconds */ +		tmo = usec / 1000;	/* start to normalize for usec to ticks per sec */ +		tmo *= CFG_HZ;		/* find number of "ticks" to wait to achieve target */ +		tmo /= 1000;		/* finish normalize. */ +	}else{				/* else small number, don't kill it prior to HZ multiply */  		tmo = usec * CFG_HZ;  		tmo /= (1000*1000);  	} diff --git a/drivers/Makefile b/drivers/Makefile index b333aed67..32a6a0607 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -1,5 +1,5 @@  # -# (C) Copyright 2000 +# (C) Copyright 2000-2004  # Wolfgang Denk, DENX Software Engineering, wd@denx.de.  #  # See file CREDITS for list of people who contributed to this @@ -12,7 +12,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 @@ -29,7 +29,7 @@ LIB	= libdrivers.a  OBJS	= 3c589.o 5701rls.o ali512x.o \  	  bcm570x.o bcm570x_autoneg.o cfb_console.o cfi_flash.o \ -	  cs8900.o ct69000.o dataflash.o dc2114x.o          \ +	  cs8900.o ct69000.o dataflash.o dc2114x.o	    \  	  e1000.o eepro100.o \  	  i8042.o i82365.o inca-ip_sw.o \  	  lan91c96.o natsemi.o netarm_eth.o \ @@ -40,11 +40,12 @@ OBJS	= 3c589.o 5701rls.o ali512x.o \  	  rtl8019.o rtl8139.o \  	  s3c24x0_i2c.o sed13806.o serial.o serial_max3100.o \  	  smc91111.o smiLynxEM.o status_led.o sym53c8xx.o \ -	  ti_pci1410a.o tigon3.o w83c553f.o +	  ti_pci1410a.o tigon3.o w83c553f.o omap1510_i2c.o \ +	  usbdcore.o usbdcore_ep0.o usbdcore_omap1510.o usbtty.o  all:	$(LIB) -$(LIB):	$(OBJS) +$(LIB): $(OBJS)  	$(AR) crv $@ $(OBJS)  ######################################################################### diff --git a/drivers/ns16550.c b/drivers/ns16550.c index a7aa40ff3..05862ee6e 100644 --- a/drivers/ns16550.c +++ b/drivers/ns16550.c @@ -18,7 +18,7 @@ void NS16550_init (NS16550_t com_port, int baud_divisor)  {  	com_port->ier = 0x00;  #ifdef CONFIG_OMAP1510 -	com_port->mdr1 = 0x7;   /* mode select reset TL16C750*/ +	com_port->mdr1 = 0x7;	/* mode select reset TL16C750*/  #endif  	com_port->lcr = LCR_BKSE | LCRVAL;  	com_port->dll = baud_divisor & 0xff; @@ -50,7 +50,12 @@ void NS16550_putc (NS16550_t com_port, char c)  char NS16550_getc (NS16550_t com_port)  { -	while ((com_port->lsr & LSR_DR) == 0); +	while ((com_port->lsr & LSR_DR) == 0) { +#ifdef CONFIG_USB_TTY +		extern void usbtty_poll(void); +		usbtty_poll(); +#endif +	}  	return (com_port->rbr);  } diff --git a/drivers/omap1510_i2c.c b/drivers/omap1510_i2c.c new file mode 100644 index 000000000..04400fbcd --- /dev/null +++ b/drivers/omap1510_i2c.c @@ -0,0 +1,281 @@ +/* + * Basic I2C functions + * + * Copyright (c) 2003 Texas Instruments + * + * This package is free software;  you can redistribute it and/or + * modify it under the terms of the license found in the file + * named COPYING that should have accompanied this file. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Author: Jian Zhang jzhang@ti.com, Texas Instruments + * + * Copyright (c) 2003 Wolfgang Denk, wd@denx.de + * Rewritten to fit into the current U-Boot framework + * + */ + +#include <common.h> + +#ifdef CONFIG_DRIVER_OMAP1510_I2C + +static void wait_for_bb (void); +static u16 wait_for_pin (void); + +void i2c_init (int speed, int slaveadd) +{ +	u16 scl; + +	if (inw (I2C_CON) & I2C_CON_EN) { +		outw (0, I2C_CON); +		udelay (5000); +	} + +	/* 12Mhz I2C module clock */ +	outw (0, I2C_PSC); +	outw (I2C_CON_EN, I2C_CON); +	outw (0, I2C_SYSTEST); +	/* have to enable intrrupts or OMAP i2c module doesn't work */ +	outw (I2C_IE_XRDY_IE | I2C_IE_RRDY_IE | I2C_IE_ARDY_IE | +	      I2C_IE_NACK_IE | I2C_IE_AL_IE, I2C_IE); +	scl = (12000000 / 2) / speed - 6; +	outw (scl, I2C_SCLL); +	outw (scl, I2C_SCLH); +	/* own address */ +	outw (slaveadd, I2C_OA); +	outw (0, I2C_CNT); +	udelay (1000); +} + +static int i2c_read_byte (u8 devaddr, u8 regoffset, u8 * value) +{ +	int i2c_error = 0; +	u16 status; + +	/* wait until bus not busy */ +	wait_for_bb (); + +	/* one byte only */ +	outw (1, I2C_CNT); +	/* set slave address */ +	outw (devaddr, I2C_SA); +	/* no stop bit needed here */ +	outw (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX, I2C_CON); + +	status = wait_for_pin (); + +	if (status & I2C_STAT_XRDY) { +		/* Important: have to use byte access */ +		*(volatile u8 *) (I2C_DATA) = regoffset; +		udelay (20000); +		if (inw (I2C_STAT) & I2C_STAT_NACK) { +			i2c_error = 1; +		} +	} else { +		i2c_error = 1; +	} + +	if (!i2c_error) { +		/* free bus, otherwise we can't use a combined transction */ +		outw (0, I2C_CON); +		while (inw (I2C_STAT) || (inw (I2C_CON) & I2C_CON_MST)) { +			udelay (10000); +			/* Have to clear pending interrupt to clear I2C_STAT */ +			inw (I2C_IV); +		} + +		wait_for_bb (); +		/* set slave address */ +		outw (devaddr, I2C_SA); +		/* read one byte from slave */ +		outw (1, I2C_CNT); +		/* need stop bit here */ +		outw (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP, +		      I2C_CON); + +		status = wait_for_pin (); +		if (status & I2C_STAT_RRDY) { +			*value = inw (I2C_DATA); +			udelay (20000); +		} else { +			i2c_error = 1; +		} + +		if (!i2c_error) { +			outw (I2C_CON_EN, I2C_CON); +			while (inw (I2C_STAT) +			       || (inw (I2C_CON) & I2C_CON_MST)) { +				udelay (10000); +				inw (I2C_IV); +			} +		} +	} + +	return i2c_error; +} + +static int i2c_write_byte (u8 devaddr, u8 regoffset, u8 value) +{ +	int i2c_error = 0; +	u16 status; + +	/* wait until bus not busy */ +	wait_for_bb (); + +	/* two bytes */ +	outw (2, I2C_CNT); +	/* set slave address */ +	outw (devaddr, I2C_SA); +	/* stop bit needed here */ +	outw (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX | +	      I2C_CON_STP, I2C_CON); + +	/* wait until state change */ +	status = wait_for_pin (); + +	if (status & I2C_STAT_XRDY) { +		/* send out two bytes */ +		outw ((value << 8) + regoffset, I2C_DATA); +		/* must have enough delay to allow BB bit to go low */ +		udelay (30000); +		if (inw (I2C_STAT) & I2C_STAT_NACK) { +			i2c_error = 1; +		} +	} else { +		i2c_error = 1; +	} + +	if (!i2c_error) { +		outw (I2C_CON_EN, I2C_CON); +		while (inw (I2C_STAT) || (inw (I2C_CON) & I2C_CON_MST)) { +			udelay (1000); +			/* have to read to clear intrrupt */ +			inw (I2C_IV); +		} +	} + +	return i2c_error; +} + +int i2c_probe (uchar chip) +{ +	int res = 1; + +	if (chip == inw (I2C_OA)) { +		return res; +	} + +	/* wait until bus not busy */ +	wait_for_bb (); + +	/* try to read one byte */ +	outw (1, I2C_CNT); +	/* set slave address */ +	outw (chip, I2C_SA); +	/* stop bit needed here */ +	outw (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP, I2C_CON); +	/* enough delay for the NACK bit set */ +	udelay (2000); +	if (!(inw (I2C_STAT) & I2C_STAT_NACK)) { +		res = 0; +	} else { +		outw (inw (I2C_CON) | I2C_CON_STP, I2C_CON); +		udelay (20); +		wait_for_bb (); +	} + +	return res; +} + +int i2c_read (uchar chip, uint addr, int alen, uchar * buffer, int len) +{ +	int i; + +	if (alen > 1) { +		printf ("I2C read: addr len %d not supported\n", alen); +		return 1; +	} + +	if (addr + len > 256) { +		printf ("I2C read: address out of range\n"); +		return 1; +	} + +	for (i = 0; i < len; i++) { +		if (i2c_read_byte (chip, addr + i, &buffer[i])) { +			printf ("I2C read: I/O error\n"); +			i2c_init (CFG_I2C_SPEED, CFG_I2C_SLAVE); +			return 1; +		} +	} + +	return 0; +} + +int i2c_write (uchar chip, uint addr, int alen, uchar * buffer, int len) +{ +	int i; + +	if (alen > 1) { +		printf ("I2C read: addr len %d not supported\n", alen); +		return 1; +	} + +	if (addr + len > 256) { +		printf ("I2C read: address out of range\n"); +		return 1; +	} + +	for (i = 0; i < len; i++) { +		if (i2c_write_byte (chip, addr + i, buffer[i])) { +			printf ("I2C read: I/O error\n"); +			i2c_init (CFG_I2C_SPEED, CFG_I2C_SLAVE); +			return 1; +		} +	} + +	return 0; +} + +static void wait_for_bb (void) +{ +	int timeout = 10; + +	while ((inw (I2C_STAT) & I2C_STAT_BB) && timeout--) { +		inw (I2C_IV); +		udelay (1000); +	} + +	if (timeout <= 0) { +		printf ("timed out in wait_for_bb: I2C_STAT=%x\n", +			inw (I2C_STAT)); +	} +} + +static u16 wait_for_pin (void) +{ +	u16 status, iv; +	int timeout = 10; + +	do { +		udelay (1000); +		status = inw (I2C_STAT); +		iv = inw (I2C_IV); +	} while (!iv && +		 !(status & +		   (I2C_STAT_ROVR | I2C_STAT_XUDF | I2C_STAT_XRDY | +		    I2C_STAT_RRDY | I2C_STAT_ARDY | I2C_STAT_NACK | +		    I2C_STAT_AL)) && timeout--); + +	if (timeout <= 0) { +		printf ("timed out in wait_for_pin: I2C_STAT=%x\n", +			inw (I2C_STAT)); +	} + +	return status; +} + +#endif /* CONFIG_DRIVER_OMAP1510_I2C */ diff --git a/drivers/usbdcore.c b/drivers/usbdcore.c new file mode 100644 index 000000000..308c7cecc --- /dev/null +++ b/drivers/usbdcore.c @@ -0,0 +1,684 @@ +/* + * (C) Copyright 2003 + * Gerry Hamel, geh@ti.com, Texas Instruments + * + * Based on + * linux/drivers/usbd/usbd.c.c - USB Device Core Layer + * + * Copyright (c) 2000, 2001, 2002 Lineo + * Copyright (c) 2001 Hewlett Packard + * + * By: + *	Stuart Lynne <sl@lineo.com>, + *	Tom Rushworth <tbr@lineo.com>, + *	Bruce Balden <balden@lineo.com> + * + * 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. + * + */ + +#include <malloc.h> +#include "usbdcore.h" + +#define MAX_INTERFACES 2 + + +int maxstrings = 20; + +/* Global variables ************************************************************************** */ + +struct usb_string_descriptor **usb_strings; + +int usb_devices; + +extern struct usb_function_driver ep0_driver; + +int registered_functions; +int registered_devices; + +char *usbd_device_events[] = { +	"DEVICE_UNKNOWN", +	"DEVICE_INIT", +	"DEVICE_CREATE", +	"DEVICE_HUB_CONFIGURED", +	"DEVICE_RESET", +	"DEVICE_ADDRESS_ASSIGNED", +	"DEVICE_CONFIGURED", +	"DEVICE_SET_INTERFACE", +	"DEVICE_SET_FEATURE", +	"DEVICE_CLEAR_FEATURE", +	"DEVICE_DE_CONFIGURED", +	"DEVICE_BUS_INACTIVE", +	"DEVICE_BUS_ACTIVITY", +	"DEVICE_POWER_INTERRUPTION", +	"DEVICE_HUB_RESET", +	"DEVICE_DESTROY", +	"DEVICE_FUNCTION_PRIVATE", +}; + +char *usbd_device_states[] = { +	"STATE_INIT", +	"STATE_CREATED", +	"STATE_ATTACHED", +	"STATE_POWERED", +	"STATE_DEFAULT", +	"STATE_ADDRESSED", +	"STATE_CONFIGURED", +	"STATE_UNKNOWN", +}; + +char *usbd_device_requests[] = { +	"GET STATUS",		/* 0 */ +	"CLEAR FEATURE",	/* 1 */ +	"RESERVED",		/* 2 */ +	"SET FEATURE",		/* 3 */ +	"RESERVED",		/* 4 */ +	"SET ADDRESS",		/* 5 */ +	"GET DESCRIPTOR",	/* 6 */ +	"SET DESCRIPTOR",	/* 7 */ +	"GET CONFIGURATION",	/* 8 */ +	"SET CONFIGURATION",	/* 9 */ +	"GET INTERFACE",	/* 10 */ +	"SET INTERFACE",	/* 11 */ +	"SYNC FRAME",		/* 12 */ +}; + +char *usbd_device_descriptors[] = { +	"UNKNOWN",		/* 0 */ +	"DEVICE",		/* 1 */ +	"CONFIG",		/* 2 */ +	"STRING",		/* 3 */ +	"INTERFACE",		/* 4 */ +	"ENDPOINT",		/* 5 */ +	"DEVICE QUALIFIER",	/* 6 */ +	"OTHER SPEED",		/* 7 */ +	"INTERFACE POWER",	/* 8 */ +}; + +char *usbd_device_status[] = { +	"USBD_OPENING", +	"USBD_OK", +	"USBD_SUSPENDED", +	"USBD_CLOSING", +}; + + +/* Descriptor support functions ************************************************************** */ + + +/** + * usbd_get_string - find and return a string descriptor + * @index: string index to return + * + * Find an indexed string and return a pointer to a it. + */ +struct usb_string_descriptor *usbd_get_string (__u8 index) +{ +	if (index >= maxstrings) { +		return NULL; +	} +	return usb_strings[index]; +} + + +/* Access to device descriptor functions ***************************************************** */ + + +/* * + * usbd_device_configuration_instance - find a configuration instance for this device + * @device: + * @configuration: index to configuration, 0 - N-1 + * + * Get specifed device configuration. Index should be bConfigurationValue-1. + */ +static struct usb_configuration_instance *usbd_device_configuration_instance (struct usb_device_instance *device, +		unsigned int port, unsigned int configuration) +{ +	/* XXX */ +	configuration = configuration ? configuration - 1 : 0; + +	if (configuration >= device->configurations) { +		return NULL; +	} +	return device->configuration_instance_array + configuration; +} + + +/* * + * usbd_device_interface_instance + * @device: + * @configuration: index to configuration, 0 - N-1 + * @interface: index to interface + * + * Return the specified interface descriptor for the specified device. + */ +struct usb_interface_instance *usbd_device_interface_instance (struct usb_device_instance *device, int port, int configuration, int interface) +{ +	struct usb_configuration_instance *configuration_instance; + +	if ((configuration_instance = usbd_device_configuration_instance (device, port, configuration)) == NULL) { +		return NULL; +	} +	if (interface >= configuration_instance->interfaces) { +		return NULL; +	} +	return configuration_instance->interface_instance_array + interface; +} + +/* * + * usbd_device_alternate_descriptor_list + * @device: + * @configuration: index to configuration, 0 - N-1 + * @interface: index to interface + * @alternate: alternate setting + * + * Return the specified alternate descriptor for the specified device. + */ +struct usb_alternate_instance *usbd_device_alternate_instance (struct usb_device_instance *device, int port, int configuration, int interface, int alternate) +{ +	struct usb_interface_instance *interface_instance; + +	if ((interface_instance = usbd_device_interface_instance (device, port, configuration, interface)) == NULL) { +		return NULL; +	} + +	if (alternate >= interface_instance->alternates) { +		return NULL; +	} + +	return interface_instance->alternates_instance_array + alternate; +} + + +/* * + * usbd_device_device_descriptor + * @device: which device + * @configuration: index to configuration, 0 - N-1 + * @port: which port + * + * Return the specified configuration descriptor for the specified device. + */ +struct usb_device_descriptor *usbd_device_device_descriptor (struct usb_device_instance *device, int port) +{ +	return (device->device_descriptor); +} + + +/** + * usbd_device_configuration_descriptor + * @device: which device + * @port: which port + * @configuration: index to configuration, 0 - N-1 + * + * Return the specified configuration descriptor for the specified device. + */ +struct usb_configuration_descriptor *usbd_device_configuration_descriptor (struct +									   usb_device_instance +									   *device, int port, int configuration) +{ +	struct usb_configuration_instance *configuration_instance; +	if (!(configuration_instance = usbd_device_configuration_instance (device, port, configuration))) { +		return NULL; +	} +	return (configuration_instance->configuration_descriptor); +} + + +/** + * usbd_device_interface_descriptor + * @device: which device + * @port: which port + * @configuration: index to configuration, 0 - N-1 + * @interface: index to interface + * @alternate: alternate setting + * + * Return the specified interface descriptor for the specified device. + */ +struct usb_interface_descriptor *usbd_device_interface_descriptor (struct usb_device_instance +								   *device, int port, int configuration, int interface, int alternate) +{ +	struct usb_interface_instance *interface_instance; +	if (!(interface_instance = usbd_device_interface_instance (device, port, configuration, interface))) { +		return NULL; +	} +	if ((alternate < 0) || (alternate >= interface_instance->alternates)) { +		return NULL; +	} +	return (interface_instance->alternates_instance_array[alternate].interface_descriptor); +} + +/** + * usbd_device_endpoint_descriptor_index + * @device: which device + * @port: which port + * @configuration: index to configuration, 0 - N-1 + * @interface: index to interface + * @alternate: index setting + * @index: which index + * + * Return the specified endpoint descriptor for the specified device. + */ +struct usb_endpoint_descriptor *usbd_device_endpoint_descriptor_index (struct usb_device_instance +								       *device, int port, int configuration, int interface, int alternate, int index) +{ +	struct usb_alternate_instance *alternate_instance; + +	if (!(alternate_instance = usbd_device_alternate_instance (device, port, configuration, interface, alternate))) { +		return NULL; +	} +	if (index >= alternate_instance->endpoints) { +		return NULL; +	} +	return *(alternate_instance->endpoints_descriptor_array + index); +} + + +/** + * usbd_device_endpoint_transfersize + * @device: which device + * @port: which port + * @configuration: index to configuration, 0 - N-1 + * @interface: index to interface + * @index: which index + * + * Return the specified endpoint transfer size; + */ +int usbd_device_endpoint_transfersize (struct usb_device_instance *device, int port, int configuration, int interface, int alternate, int index) +{ +	struct usb_alternate_instance *alternate_instance; + +	if (!(alternate_instance = usbd_device_alternate_instance (device, port, configuration, interface, alternate))) { +		return 0; +	} +	if (index >= alternate_instance->endpoints) { +		return 0; +	} +	return *(alternate_instance->endpoint_transfersize_array + index); +} + + +/** + * usbd_device_endpoint_descriptor + * @device: which device + * @port: which port + * @configuration: index to configuration, 0 - N-1 + * @interface: index to interface + * @alternate: alternate setting + * @endpoint: which endpoint + * + * Return the specified endpoint descriptor for the specified device. + */ +struct usb_endpoint_descriptor *usbd_device_endpoint_descriptor (struct usb_device_instance *device, int port, int configuration, int interface, int alternate, int endpoint) +{ +	struct usb_endpoint_descriptor *endpoint_descriptor; +	int i; + +	for (i = 0; !(endpoint_descriptor = usbd_device_endpoint_descriptor_index (device, port, configuration, interface, alternate, i)); i++) { +		if (endpoint_descriptor->bEndpointAddress == endpoint) { +			return endpoint_descriptor; +		} +	} +	return NULL; +} + +/** + * usbd_endpoint_halted + * @device: point to struct usb_device_instance + * @endpoint: endpoint to check + * + * Return non-zero if endpoint is halted. + */ +int usbd_endpoint_halted (struct usb_device_instance *device, int endpoint) +{ +	return (device->status == USB_STATUS_HALT); +} + + +/** + * usbd_rcv_complete - complete a receive + * @endpoint: + * @len: + * @urb_bad: + * + * Called from rcv interrupt to complete. + */ +void usbd_rcv_complete(struct usb_endpoint_instance *endpoint, int len, int urb_bad) +{ +	if (endpoint) { +		struct urb *rcv_urb; + +		/*usbdbg("len: %d urb: %p\n", len, endpoint->rcv_urb); */ + +		/* if we had an urb then update actual_length, dispatch if neccessary */ +		if ((rcv_urb = endpoint->rcv_urb)) { + +			/*usbdbg("actual: %d buffer: %d\n", */ +			/*rcv_urb->actual_length, rcv_urb->buffer_length); */ + +			/* check the urb is ok, are we adding data less than the packetsize */ +			if (!urb_bad && (len <= endpoint->rcv_packetSize)) { +			  /*usbdbg("updating actual_length by %d\n",len); */ + +				/* increment the received data size */ +				rcv_urb->actual_length += len; + +			} else { +				usberr(" RECV_ERROR actual: %d buffer: %d urb_bad: %d\n", +				       rcv_urb->actual_length, rcv_urb->buffer_length, urb_bad); + +				rcv_urb->actual_length = 0; +				rcv_urb->status = RECV_ERROR; +			} +		} else { +			usberr("no rcv_urb!"); +		} +	} else { +		usberr("no endpoint!"); +	} + +} + +/** + * usbd_tx_complete - complete a transmit + * @endpoint: + * @resetart: + * + * Called from tx interrupt to complete. + */ +void usbd_tx_complete (struct usb_endpoint_instance *endpoint) +{ +	if (endpoint) { +		struct urb *tx_urb; + +		/* if we have a tx_urb advance or reset, finish if complete */ +		if ((tx_urb = endpoint->tx_urb)) { +			int sent = endpoint->last; +			endpoint->sent += sent; +			endpoint->last -= sent; + +			if( (endpoint->tx_urb->actual_length - endpoint->sent) <= 0 ) { +				tx_urb->actual_length = 0; +				endpoint->sent = 0; +				endpoint->last = 0; + +				/* Remove from active, save for re-use */ +				urb_detach(tx_urb); +				urb_append(&endpoint->done, tx_urb); +				/*usbdbg("done->next %p, tx_urb %p, done %p", */ +				/*	 endpoint->done.next, tx_urb, &endpoint->done); */ + +				endpoint->tx_urb = first_urb_detached(&endpoint->tx); +				if( endpoint->tx_urb ) { +					endpoint->tx_queue--; +					usbdbg("got urb from tx list"); +				} +				if( !endpoint->tx_urb ) { +					/*usbdbg("taking urb from done list"); */ +					endpoint->tx_urb = first_urb_detached(&endpoint->done); +				} +				if( !endpoint->tx_urb ) { +					usbdbg("allocating new urb for tx_urb"); +					endpoint->tx_urb = usbd_alloc_urb(tx_urb->device, endpoint); +				} +			} +		} +	} +} + +/* URB linked list functions ***************************************************** */ + +/* + * Initialize an urb_link to be a single element list. + * If the urb_link is being used as a distinguished list head + * the list is empty when the head is the only link in the list. + */ +void urb_link_init (urb_link * ul) +{ +	if (ul) { +		ul->prev = ul->next = ul; +	} +} + +/* + * Detach an urb_link from a list, and set it + * up as a single element list, so no dangling + * pointers can be followed, and so it can be + * joined to another list if so desired. + */ +void urb_detach (struct urb *urb) +{ +	if (urb) { +		urb_link *ul = &urb->link; +		ul->next->prev = ul->prev; +		ul->prev->next = ul->next; +		urb_link_init (ul); +	} +} + +/* + * Return the first urb_link in a list with a distinguished + * head "hd", or NULL if the list is empty.  This will also + * work as a predicate, returning NULL if empty, and non-NULL + * otherwise. + */ +urb_link *first_urb_link (urb_link * hd) +{ +	urb_link *nx; +	if (NULL != hd && NULL != (nx = hd->next) && nx != hd) { +		/* There is at least one element in the list */ +		/* (besides the distinguished head). */ +		return (nx); +	} +	/* The list is empty */ +	return (NULL); +} + +/* + * Return the first urb in a list with a distinguished + * head "hd", or NULL if the list is empty. + */ +struct urb *first_urb (urb_link * hd) +{ +	urb_link *nx; +	if (NULL == (nx = first_urb_link (hd))) { +		/* The list is empty */ +		return (NULL); +	} +	return (p2surround (struct urb, link, nx)); +} + +/* + * Detach and return the first urb in a list with a distinguished + * head "hd", or NULL if the list is empty. + * + */ +struct urb *first_urb_detached (urb_link * hd) +{ +	struct urb *urb; +	if ((urb = first_urb (hd))) { +		urb_detach (urb); +	} +	return urb; +} + + +/* + * Append an urb_link (or a whole list of + * urb_links) to the tail of another list + * of urb_links. + */ +void urb_append (urb_link * hd, struct urb *urb) +{ +	if (hd && urb) { +		urb_link *new = &urb->link; + +		/* This allows the new urb to be a list of urbs, */ +		/* with new pointing at the first, but the link */ +		/* must be initialized. */ +		/* Order is important here... */ +		urb_link *pul = hd->prev; +		new->prev->next = hd; +		hd->prev = new->prev; +		new->prev = pul; +		pul->next = new; +	} +} + +/* URB create/destroy functions ***************************************************** */ + +/** + * usbd_alloc_urb - allocate an URB appropriate for specified endpoint + * @device: device instance + * @endpoint: endpoint + * + * Allocate an urb structure. The usb device urb structure is used to + * contain all data associated with a transfer, including a setup packet for + * control transfers. + * + * NOTE: endpoint_address MUST contain a direction flag. + */ +struct urb *usbd_alloc_urb (struct usb_device_instance *device, struct usb_endpoint_instance *endpoint) +{ +	struct urb *urb; + +	if( !(urb = (struct urb*)malloc(sizeof(struct urb))) ) { +	  usberr(" F A T A L:  malloc(%u) FAILED!!!!", sizeof(struct urb)); +	  return NULL; +	} + +	/* Fill in known fields */ +	memset(urb, 0, sizeof(struct urb)); +	urb->endpoint = endpoint; +	urb->device = device; +	urb->buffer = (u8*)urb->buffer_data; +	urb->buffer_length = sizeof(urb->buffer_data); + +	urb_link_init (&urb->link); + +	return urb; +} + +/** + * usbd_dealloc_urb - deallocate an URB and associated buffer + * @urb: pointer to an urb structure + * + * Deallocate an urb structure and associated data. + */ +void usbd_dealloc_urb (struct urb *urb) +{ +	if (urb) { +		free (urb); +	} +} + +/* Event signaling functions ***************************************************** */ + +/** + * usbd_device_event - called to respond to various usb events + * @device: pointer to struct device + * @event: event to respond to + * + * Used by a Bus driver to indicate an event. + */ +void usbd_device_event_irq (struct usb_device_instance *device, usb_device_event_t event, int data) +{ +	usb_device_state_t state; + +	if (!device || !device->bus) { +		usberr("(%p,%d) NULL device or device->bus", device, event); +		return; +	} + +	state = device->device_state; + +	usbinfo("%s", usbd_device_events[event]); + +	switch (event) { +	case DEVICE_UNKNOWN: +		break; +	case DEVICE_INIT: +		device->device_state = STATE_INIT; +		break; + +	case DEVICE_CREATE: +		device->device_state = STATE_ATTACHED; +		break; + +	case DEVICE_HUB_CONFIGURED: +		device->device_state = STATE_POWERED; +		break; + +	case DEVICE_RESET: +		device->device_state = STATE_DEFAULT; +		device->address = 0; +		break; + +	case DEVICE_ADDRESS_ASSIGNED: +		device->device_state = STATE_ADDRESSED; +		break; + +	case DEVICE_CONFIGURED: +		device->device_state = STATE_CONFIGURED; +		break; + +	case DEVICE_DE_CONFIGURED: +		device->device_state = STATE_ADDRESSED; +		break; + +	case DEVICE_BUS_INACTIVE: +		if (device->status != USBD_CLOSING) { +			device->status = USBD_SUSPENDED; +		} +		break; +	case DEVICE_BUS_ACTIVITY: +		if (device->status != USBD_CLOSING) { +			device->status = USBD_OK; +		} +		break; + +	case DEVICE_SET_INTERFACE: +		break; +	case DEVICE_SET_FEATURE: +		break; +	case DEVICE_CLEAR_FEATURE: +		break; + +	case DEVICE_POWER_INTERRUPTION: +		device->device_state = STATE_POWERED; +		break; +	case DEVICE_HUB_RESET: +		device->device_state = STATE_ATTACHED; +		break; +	case DEVICE_DESTROY: +		device->device_state = STATE_UNKNOWN; +		break; + +	case DEVICE_FUNCTION_PRIVATE: +		break; + +	default: +		usbdbg("event %d - not handled",event); +		break; +	} +	/*usbdbg("%s event: %d oldstate: %d newstate: %d status: %d address: %d", +		device->name, event, state, +		device->device_state, device->status, device->address); */ + +	/* tell the bus interface driver */ +	if( device->event ) { +		/* usbdbg("calling device->event"); */ +		device->event(device, event, data); +	} +} diff --git a/drivers/usbdcore_ep0.c b/drivers/usbdcore_ep0.c new file mode 100644 index 000000000..260befe97 --- /dev/null +++ b/drivers/usbdcore_ep0.c @@ -0,0 +1,686 @@ +/* + * (C) Copyright 2003 + * Gerry Hamel, geh@ti.com, Texas Instruments + * + * Based on + * linux/drivers/usbd/ep0.c + * + * Copyright (c) 2000, 2001, 2002 Lineo + * Copyright (c) 2001 Hewlett Packard + * + * By: + *	Stuart Lynne <sl@lineo.com>, + *	Tom Rushworth <tbr@lineo.com>, + *	Bruce Balden <balden@lineo.com> + * + * 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. + * + */ + +/* + * This is the builtin ep0 control function. It implements all required functionality + * for responding to control requests (SETUP packets). + * + * XXX + * + * Currently we do not pass any SETUP packets (or other) to the configured + * function driver. This may need to change. + * + * XXX + */ + +#include <common.h> + +#if defined(CONFIG_OMAP1510) && defined(CONFIG_USB_DEVICE) +#include "usbdcore.h" + +#if 0 +#define dbg_ep0(lvl,fmt,args...) serial_printf("[%s] %s:%d: "fmt"\n",__FILE__,__FUNCTION__,__LINE__,##args) +#else +#define dbg_ep0(lvl,fmt,args...) +#endif + +/* EP0 Configuration Set ********************************************************************* */ + + +/** + * ep0_get_status - fill in URB data with appropriate status + * @device: + * @urb: + * @index: + * @requesttype: + * + */ +static int ep0_get_status (struct usb_device_instance *device, +			   struct urb *urb, int index, int requesttype) +{ +	char *cp; + +	urb->actual_length = 2; +	cp = urb->buffer; +	cp[0] = cp[1] = 0; + +	switch (requesttype) { +	case USB_REQ_RECIPIENT_DEVICE: +		cp[0] = USB_STATUS_SELFPOWERED; +		break; +	case USB_REQ_RECIPIENT_INTERFACE: +		break; +	case USB_REQ_RECIPIENT_ENDPOINT: +		cp[0] = usbd_endpoint_halted (device, index); +		break; +	case USB_REQ_RECIPIENT_OTHER: +		urb->actual_length = 0; +	default: +		break; +	} +	dbg_ep0 (2, "%02x %02x", cp[0], cp[1]); +	return 0; +} + +/** + * ep0_get_one + * @device: + * @urb: + * @result: + * + * Set a single byte value in the urb send buffer. Return non-zero to signal + * a request error. + */ +static int ep0_get_one (struct usb_device_instance *device, struct urb *urb, +			__u8 result) +{ +	urb->actual_length = 1;	/* XXX 2? */ +	((char *) urb->buffer)[0] = result; +	return 0; +} + +/** + * copy_config + * @urb: pointer to urb + * @data: pointer to configuration data + * @length: length of data + * + * 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, +			 int max_buf) +{ +	int available; +	int length; + +	/*dbg_ep0(3, "-> actual: %d buf: %d max_buf: %d max_length: %d data: %p", */ +	/*        urb->actual_length, urb->buffer_length, max_buf, max_length, data); */ + +	if (!data) { +		dbg_ep0 (1, "data is NULL"); +		return; +	} +	if (!(length = *(unsigned char *) data)) { +		dbg_ep0 (1, "length is zero"); +		return; +	} + +	if (length > max_length) { +		dbg_ep0 (1, "length: %d >= max_length: %d", length, +			 max_length); +		return; +	} +	/*dbg_ep0(1, "   actual: %d buf: %d max_buf: %d max_length: %d length: %d", */ +	/*        urb->actual_length, urb->buffer_length, max_buf, max_length, length); */ + +	if ((available = +	     /*urb->buffer_length */ max_buf - urb->actual_length) <= 0) { +		return; +	} +	/*dbg_ep0(1, "actual: %d buf: %d max_buf: %d length: %d available: %d", */ +	/*        urb->actual_length, urb->buffer_length, max_buf, length, available); */ + +	if (length > available) { +		length = available; +	} +	/*dbg_ep0(1, "actual: %d buf: %d max_buf: %d length: %d available: %d", */ +	/*        urb->actual_length, urb->buffer_length, max_buf, length, available); */ + +	memcpy (urb->buffer + urb->actual_length, data, length); +	urb->actual_length += length; + +	dbg_ep0 (3, +		 "copy_config: <- actual: %d buf: %d max_buf: %d max_length: %d available: %d", +		 urb->actual_length, urb->buffer_length, max_buf, max_length, +		 available); +} + +/** + * ep0_get_descriptor + * @device: + * @urb: + * @max: + * @descriptor_type: + * @index: + * + * Called by ep0_rx_process for a get descriptor device command. Determine what + * descriptor is being requested, copy to send buffer. Return zero if ok to send, + * return non-zero to signal a request error. + */ +static int ep0_get_descriptor (struct usb_device_instance *device, +			       struct urb *urb, int max, int descriptor_type, +			       int index) +{ +	int port = 0;		/* XXX compound device */ +	char *cp; + +	/*dbg_ep0(3, "max: %x type: %x index: %x", max, descriptor_type, index); */ + +	if (!urb || !urb->buffer || !urb->buffer_length +	    || (urb->buffer_length < 255)) { +		dbg_ep0 (2, "invalid urb %p", urb); +		return -1L; +	} + +	/* setup tx urb */ +	urb->actual_length = 0; +	cp = urb->buffer; + +	dbg_ep0 (2, "%s", USBD_DEVICE_DESCRIPTORS (descriptor_type)); + +	switch (descriptor_type) { +	case USB_DESCRIPTOR_TYPE_DEVICE: +		{ +			struct usb_device_descriptor *device_descriptor; + +			if (! +			    (device_descriptor = +			     usbd_device_device_descriptor (device, port))) { +				return -1; +			} +			/* copy descriptor for this device */ +			copy_config (urb, device_descriptor, +				     sizeof (struct usb_device_descriptor), +				     max); + +			/* 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); */ +		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))) { +				return -1; +			} +			/*dbg_ep0(2, "%d %d", index, device_descriptor->bNumConfigurations); */ +			if (index > device_descriptor->bNumConfigurations) { +				dbg_ep0 (0, "index too large: %d > %d", index, +					 device_descriptor-> +					 bNumConfigurations); +				return -1; +			} + +			if (! +			    (configuration_descriptor = +			     usbd_device_configuration_descriptor (device, +								   port, +								   index))) { +				dbg_ep0 (0, +					 "usbd_device_configuration_descriptor failed: %d", +					 index); +				return -1; +			} +			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); +		} +		break; + +	case USB_DESCRIPTOR_TYPE_STRING: +		{ +			struct usb_string_descriptor *string_descriptor; + +			if (!(string_descriptor = usbd_get_string (index))) { +				return -1; +			} +			/*dbg_ep0(3, "string_descriptor: %p", string_descriptor); */ +			copy_config (urb, string_descriptor, string_descriptor->bLength, max); +		} +		break; +	case USB_DESCRIPTOR_TYPE_INTERFACE: +		return -1; +	case USB_DESCRIPTOR_TYPE_ENDPOINT: +		return -1; +	case USB_DESCRIPTOR_TYPE_HID: +		{ +			return -1;	/* unsupported at this time */ +#if 0 +			int bNumInterface = +				le16_to_cpu (urb->device_request.wIndex); +			int bAlternateSetting = 0; +			int class = 0; +			struct usb_class_descriptor *class_descriptor; + +			if (!(class_descriptor = +			      usbd_device_class_descriptor_index (device, +								  port, 0, +								  bNumInterface, +								  bAlternateSetting, +								  class)) +			    || class_descriptor->descriptor.hid.bDescriptorType != USB_DT_HID) { +				dbg_ep0 (3, "[%d] interface is not HID", +					 bNumInterface); +				return -1; +			} +			/* copy descriptor for this class */ +			copy_config (urb, class_descriptor, +				     class_descriptor->descriptor.hid.bLength, +				     max); +#endif +		} +		break; +	case USB_DESCRIPTOR_TYPE_REPORT: +		{ +			return -1;	/* unsupported at this time */ +#if 0 +			int bNumInterface = +				le16_to_cpu (urb->device_request.wIndex); +			int bAlternateSetting = 0; +			int class = 0; +			struct usb_class_report_descriptor *report_descriptor; + +			if (!(report_descriptor = +			      usbd_device_class_report_descriptor_index +			      (device, port, 0, bNumInterface, +			       bAlternateSetting, class)) +			    || report_descriptor->bDescriptorType != +			    USB_DT_REPORT) { +				dbg_ep0 (3, "[%d] descriptor is not REPORT", +					 bNumInterface); +				return -1; +			} +			/* copy report descriptor for this class */ +			/*copy_config(urb, &report_descriptor->bData[0], report_descriptor->wLength, max); */ +			if (max - urb->actual_length > 0) { +				int length = +					MIN (report_descriptor->wLength, +					     max - urb->actual_length); +				memcpy (urb->buffer + urb->actual_length, +					&report_descriptor->bData[0], length); +				urb->actual_length += length; +			} +#endif +		} +		break; +	default: +		return -1; +	} + + +	dbg_ep0 (1, "urb: buffer: %p buffer_length: %2d actual_length: %2d packet size: %2d", +		 urb->buffer, urb->buffer_length, urb->actual_length, +		 device->bus->endpoint_array[0].tx_packetSize); +/* +    if ((urb->actual_length < max) && !(urb->actual_length % device->bus->endpoint_array[0].tx_packetSize)) { +	dbg_ep0(0, "adding null byte"); +	urb->buffer[urb->actual_length++] = 0; +	dbg_ep0(0, "urb: buffer_length: %2d actual_length: %2d packet size: %2d", +		urb->buffer_length, urb->actual_length device->bus->endpoint_array[0].tx_packetSize); +    } +*/ +	return 0; + +} + +/** + * ep0_recv_setup - called to indicate URB has been received + * @urb: pointer to struct urb + * + * Check if this is a setup packet, process the device request, put results + * back into the urb and return zero or non-zero to indicate success (DATA) + * or failure (STALL). + * + */ +int ep0_recv_setup (struct urb *urb) +{ +	/*struct usb_device_request *request = urb->buffer; */ +	/*struct usb_device_instance *device = urb->device; */ + +	struct usb_device_request *request; +	struct usb_device_instance *device; +	int address; + +	dbg_ep0 (0, "entering ep0_recv_setup()"); +	if (!urb || !urb->device) { +		dbg_ep0 (3, "invalid URB %p", urb); +		return -1; +	} + +	request = &urb->device_request; +	device = urb->device; + +	dbg_ep0 (3, "urb: %p device: %p", urb, urb->device); + + +	/*dbg_ep0(2, "-       -       -       -       -       -       -       -       -       -"); */ + +	dbg_ep0 (2, +		 "bmRequestType:%02x bRequest:%02x wValue:%04x wIndex:%04x wLength:%04x %s", +		 request->bmRequestType, request->bRequest, +		 le16_to_cpu (request->wValue), le16_to_cpu (request->wIndex), +		 le16_to_cpu (request->wLength), +		 USBD_DEVICE_REQUESTS (request->bRequest)); + +	/* handle USB Standard Request (c.f. USB Spec table 9-2) */ +	if ((request->bmRequestType & USB_REQ_TYPE_MASK) != 0) { +		dbg_ep0 (1, "non standard request: %x", +			 request->bmRequestType & USB_REQ_TYPE_MASK); +		return -1;	/* Stall here */ +	} + +	switch (device->device_state) { +	case STATE_CREATED: +	case STATE_ATTACHED: +	case STATE_POWERED: +		/* It actually is important to allow requests in these states, +		 * Windows will request descriptors before assigning an +		 * address to the client. +		 */ + +		/*dbg_ep0 (1, "request %s not allowed in this state: %s", */ +		/*                USBD_DEVICE_REQUESTS(request->bRequest), */ +		/*                usbd_device_states[device->device_state]); */ +		/*return -1; */ +		break; + +	case STATE_INIT: +	case STATE_DEFAULT: +		switch (request->bRequest) { +		case USB_REQ_GET_STATUS: +		case USB_REQ_GET_INTERFACE: +		case USB_REQ_SYNCH_FRAME:	/* XXX should never see this (?) */ +		case USB_REQ_CLEAR_FEATURE: +		case USB_REQ_SET_FEATURE: +		case USB_REQ_SET_DESCRIPTOR: +			/* case USB_REQ_SET_CONFIGURATION: */ +		case USB_REQ_SET_INTERFACE: +			dbg_ep0 (1, +				 "request %s not allowed in DEFAULT state: %s", +				 USBD_DEVICE_REQUESTS (request->bRequest), +				 usbd_device_states[device->device_state]); +			return -1; + +		case USB_REQ_SET_CONFIGURATION: +		case USB_REQ_SET_ADDRESS: +		case USB_REQ_GET_DESCRIPTOR: +		case USB_REQ_GET_CONFIGURATION: +			break; +		} +	case STATE_ADDRESSED: +	case STATE_CONFIGURED: +		break; +	case STATE_UNKNOWN: +		dbg_ep0 (1, "request %s not allowed in UNKNOWN state: %s", +			 USBD_DEVICE_REQUESTS (request->bRequest), +			 usbd_device_states[device->device_state]); +		return -1; +	} + +	/* handle all requests that return data (direction bit set on bm RequestType) */ +	if ((request->bmRequestType & USB_REQ_DIRECTION_MASK)) { + +		dbg_ep0 (3, "Device-to-Host"); + +		switch (request->bRequest) { + +		case USB_REQ_GET_STATUS: +			return ep0_get_status (device, urb, request->wIndex, +					       request->bmRequestType & +					       USB_REQ_RECIPIENT_MASK); + +		case USB_REQ_GET_DESCRIPTOR: +			return ep0_get_descriptor (device, urb, +						   le16_to_cpu (request->wLength), +						   le16_to_cpu (request->wValue) >> 8, +						   le16_to_cpu (request->wValue) & 0xff); + +		case USB_REQ_GET_CONFIGURATION: +			return ep0_get_one (device, urb, +					    device->configuration); + +		case USB_REQ_GET_INTERFACE: +			return ep0_get_one (device, urb, device->alternate); + +		case USB_REQ_SYNCH_FRAME:	/* XXX should never see this (?) */ +			return -1; + +		case USB_REQ_CLEAR_FEATURE: +		case USB_REQ_SET_FEATURE: +		case USB_REQ_SET_ADDRESS: +		case USB_REQ_SET_DESCRIPTOR: +		case USB_REQ_SET_CONFIGURATION: +		case USB_REQ_SET_INTERFACE: +			return -1; +		} +	} +	/* handle the requests that do not return data */ +	else { + + +		/*dbg_ep0(3, "Host-to-Device"); */ +		switch (request->bRequest) { + +		case USB_REQ_CLEAR_FEATURE: +		case USB_REQ_SET_FEATURE: +			dbg_ep0 (0, "Host-to-Device"); +			switch (request-> +				bmRequestType & USB_REQ_RECIPIENT_MASK) { +			case USB_REQ_RECIPIENT_DEVICE: +				/* XXX DEVICE_REMOTE_WAKEUP or TEST_MODE would be added here */ +				/* XXX fall through for now as we do not support either */ +			case USB_REQ_RECIPIENT_INTERFACE: +			case USB_REQ_RECIPIENT_OTHER: +				dbg_ep0 (0, "request %s not", +					 USBD_DEVICE_REQUESTS (request->bRequest)); +			default: +				return -1; + +			case USB_REQ_RECIPIENT_ENDPOINT: +				dbg_ep0 (0, "ENDPOINT: %x", le16_to_cpu (request->wValue)); +				if (le16_to_cpu (request->wValue) == USB_ENDPOINT_HALT) { +					/*return usbd_device_feature (device, le16_to_cpu (request->wIndex), */ +					/*                    request->bRequest == USB_REQ_SET_FEATURE); */ +					/* NEED TO IMPLEMENT THIS!!! */ +					return -1; +				} else { +					dbg_ep0 (1, "request %s bad wValue: %04x", +						 USBD_DEVICE_REQUESTS +						 (request->bRequest), +						 le16_to_cpu (request->wValue)); +					return -1; +				} +			} + +		case USB_REQ_SET_ADDRESS: +			/* check if this is a re-address, reset first if it is (this shouldn't be possible) */ +			if (device->device_state != STATE_DEFAULT) { +				dbg_ep0 (1, "set_address: %02x state: %s", +					 le16_to_cpu (request->wValue), +					 usbd_device_states[device->device_state]); +				return -1; +			} +			address = le16_to_cpu (request->wValue); +			if ((address & 0x7f) != address) { +				dbg_ep0 (1, "invalid address %04x %04x", +					 address, address & 0x7f); +				return -1; +			} +			device->address = address; + +			/*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? */ +			dbg_ep0 (0, "set descriptor: NOT SUPPORTED"); +			return -1; + +		case USB_REQ_SET_CONFIGURATION: +			/* c.f. 9.4.7 - the top half of wValue is reserved */ +			/* */ +			if ((device->configuration = +			     le16_to_cpu (request->wValue) & 0x7f) != 0) { +				/* c.f. 9.4.7 - zero is the default or addressed state, in our case this */ +				/* is the same is configuration zero */ +				device->configuration = 0;	/* TBR - ?????? */ +			} +			/* reset interface and alternate settings */ +			device->interface = device->alternate = 0; + +			/*dbg_ep0(2, "set configuration: %d", device->configuration); */ +			/*serial_printf("DEVICE_CONFIGURED.. event?\n"); */ +			return 0; + +		case USB_REQ_SET_INTERFACE: +			device->interface = le16_to_cpu (request->wIndex); +			device->alternate = le16_to_cpu (request->wValue); +			/*dbg_ep0(2, "set interface: %d alternate: %d", device->interface, device->alternate); */ +			serial_printf ("DEVICE_SET_INTERFACE.. event?\n"); +			return 0; + +		case USB_REQ_GET_STATUS: +		case USB_REQ_GET_DESCRIPTOR: +		case USB_REQ_GET_CONFIGURATION: +		case USB_REQ_GET_INTERFACE: +		case USB_REQ_SYNCH_FRAME:	/* XXX should never see this (?) */ +			return -1; +		} +	} +	return -1; +} + +#endif diff --git a/drivers/usbdcore_omap1510.c b/drivers/usbdcore_omap1510.c new file mode 100644 index 000000000..042f319ac --- /dev/null +++ b/drivers/usbdcore_omap1510.c @@ -0,0 +1,1494 @@ +/* + * (C) Copyright 2003 + * Gerry Hamel, geh@ti.com, Texas Instruments + * + * Based on + * linux/drivers/usb/device/bi/omap.c + * TI OMAP1510 USB bus interface driver + * + * Author: MontaVista Software, Inc. + *	   source@mvista.com + *	   (C) Copyright 2002 + * + * 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_OMAP1510) && defined(CONFIG_USB_DEVICE) + +#include <asm/io.h> +#include <i2c.h> + +#include "usbdcore.h" +#include "usbdcore_omap1510.h" +#include "usbdcore_ep0.h" + + +#define UDC_MAX_ENDPOINTS	     31 /* Number of endpoints on this UDC */ + +/* Some kind of debugging output... */ +#if 1 +#define UDCDBG(str) +#define UDCDBGA(fmt,args...) +#else  /* The bugs still exists... */ +#define UDCDBG(str) serial_printf("[%s] %s:%d: " str "\n", __FILE__,__FUNCTION__,__LINE__) +#define UDCDBGA(fmt,args...) serial_printf("[%s] %s:%d: " fmt "\n", __FILE__,__FUNCTION__,__LINE__, ##args) +#endif + +#if 1 +#define UDCREG(name) +#define UDCREGL(name) +#else  /* The bugs still exists... */ +#define UDCREG(name)	 serial_printf("%s():%d: %s[%08x]=%.4x\n",__FUNCTION__,__LINE__, (#name), name, inw(name))	/* For 16-bit regs */ +#define UDCREGL(name)	 serial_printf("%s():%d: %s[%08x]=%.8x\n",__FUNCTION__,__LINE__, (#name), name, inl(name))	/* For 32-bit regs */ +#endif + + +static struct urb *ep0_urb = NULL; + +static struct usb_device_instance *udc_device;	/* Used in interrupt handler */ +static u16 udc_devstat = 0;	/* UDC status (DEVSTAT) */ +static u32 udc_interrupts = 0; + +static void udc_stall_ep (unsigned int ep_addr); + + +static struct usb_endpoint_instance *omap1510_find_ep (int ep) +{ +	int i; + +	for (i = 0; i < udc_device->bus->max_endpoints; i++) { +		if (udc_device->bus->endpoint_array[i].endpoint_address == ep) +			return &udc_device->bus->endpoint_array[i]; +	} +	return NULL; +} + +/* ************************************************************************** */ +/* IO + */ + +/* + * omap1510_prepare_endpoint_for_rx + * + * This function implements TRM Figure 14-11. + * + * The endpoint to prepare for transfer is specified as a physical endpoint + * number.  For OUT (rx) endpoints 1 through 15, the corresponding endpoint + * configuration register is checked to see if the endpoint is ISO or not. + * If the OUT endpoint is valid and is non-ISO then its FIFO is enabled. + * No action is taken for endpoint 0 or for IN (tx) endpoints 16 through 30. + */ +static void omap1510_prepare_endpoint_for_rx (int ep_addr) +{ +	int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK; + +	UDCDBGA ("omap1510_prepare_endpoint %x", ep_addr); +	if (((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)) { +		if ((inw (UDC_EP_RX (ep_num)) & +		     (UDC_EPn_RX_Valid | UDC_EPn_RX_Iso)) == +		    UDC_EPn_RX_Valid) { +			/* rx endpoint is valid, non-ISO, so enable its FIFO */ +			outw (UDC_EP_Sel | ep_num, UDC_EP_NUM); +			outw (UDC_Set_FIFO_En, UDC_CTRL); +			outw (0, UDC_EP_NUM); +		} +	} +} + +/* omap1510_configure_endpoints + * + * This function implements TRM Figure 14-10. + */ +static void omap1510_configure_endpoints (struct usb_device_instance *device) +{ +	int ep; +	struct usb_bus_instance *bus; +	struct usb_endpoint_instance *endpoint; +	unsigned short ep_ptr; +	unsigned short ep_size; +	unsigned short ep_isoc; +	unsigned short ep_doublebuffer; +	int ep_addr; +	int packet_size; +	int buffer_size; +	int attributes; + +	bus = device->bus; + +	/* There is a dedicated 2048 byte buffer for USB packets that may be +	 * arbitrarily partitioned among the endpoints on 8-byte boundaries. +	 * The first 8 bytes are reserved for receiving setup packets on +	 * endpoint 0. +	 */ +	ep_ptr = 8;		/* reserve the first 8 bytes for the setup fifo */ + +	for (ep = 0; ep < bus->max_endpoints; ep++) { +		endpoint = bus->endpoint_array + ep; +		ep_addr = endpoint->endpoint_address; +		if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { +			/* IN endpoint */ +			packet_size = endpoint->tx_packetSize; +			attributes = endpoint->tx_attributes; +		} else { +			/* OUT endpoint */ +			packet_size = endpoint->rcv_packetSize; +			attributes = endpoint->rcv_attributes; +		} + +		switch (packet_size) { +		case 0: +			ep_size = 0; +			break; +		case 8: +			ep_size = 0; +			break; +		case 16: +			ep_size = 1; +			break; +		case 32: +			ep_size = 2; +			break; +		case 64: +			ep_size = 3; +			break; +		case 128: +			ep_size = 4; +			break; +		case 256: +			ep_size = 5; +			break; +		case 512: +			ep_size = 6; +			break; +		default: +			UDCDBGA ("ep 0x%02x has bad packet size %d", +				 ep_addr, packet_size); +			packet_size = 0; +			ep_size = 0; +			break; +		} + +		switch (attributes & USB_ENDPOINT_XFERTYPE_MASK) { +		case USB_ENDPOINT_XFER_CONTROL: +		case USB_ENDPOINT_XFER_BULK: +		case USB_ENDPOINT_XFER_INT: +		default: +			/* A non-isochronous endpoint may optionally be +			 * double-buffered. For now we disable +			 * double-buffering. +			 */ +			ep_doublebuffer = 0; +			ep_isoc = 0; +			if (packet_size > 64) +				packet_size = 0; +			if (!ep || !ep_doublebuffer) +				buffer_size = packet_size; +			else +				buffer_size = packet_size * 2; +			break; +		case USB_ENDPOINT_XFER_ISOC: +			/* Isochronous endpoints are always double- +			 * buffered, but the double-buffering bit +			 * in the endpoint configuration register +			 * becomes the msb of the endpoint size so we +			 * set the double-buffering flag to zero. +			 */ +			ep_doublebuffer = 0; +			ep_isoc = 1; +			buffer_size = packet_size * 2; +			break; +		} + +		/* check to see if our packet buffer RAM is exhausted */ +		if ((ep_ptr + buffer_size) > 2048) { +			UDCDBGA ("out of packet RAM for ep 0x%02x buf size %d", ep_addr, buffer_size); +			buffer_size = packet_size = 0; +		} + +		/* force a default configuration for endpoint 0 since it is +		 * always enabled +		 */ +		if (!ep && ((packet_size < 8) || (packet_size > 64))) { +			buffer_size = packet_size = 64; +			ep_size = 3; +		} + +		if (!ep) { +			/* configure endpoint 0 */ +			outw ((ep_size << 12) | (ep_ptr >> 3), UDC_EP0); +			/*UDCDBGA("ep 0 buffer offset 0x%03x packet size 0x%03x", */ +			/*	ep_ptr, packet_size); */ +		} else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { +			/* IN endpoint */ +			if (packet_size) { +				outw ((1 << 15) | (ep_doublebuffer << 14) | +				      (ep_size << 12) | (ep_isoc << 11) | +				      (ep_ptr >> 3), +				      UDC_EP_TX (ep_addr & +						 USB_ENDPOINT_NUMBER_MASK)); +				UDCDBGA ("IN ep %d buffer offset 0x%03x" +					 " packet size 0x%03x", +					 ep_addr & USB_ENDPOINT_NUMBER_MASK, +					 ep_ptr, packet_size); +			} else { +				outw (0, +				      UDC_EP_TX (ep_addr & +						 USB_ENDPOINT_NUMBER_MASK)); +			} +		} else { +			/* OUT endpoint */ +			if (packet_size) { +				outw ((1 << 15) | (ep_doublebuffer << 14) | +				      (ep_size << 12) | (ep_isoc << 11) | +				      (ep_ptr >> 3), +				      UDC_EP_RX (ep_addr & +						 USB_ENDPOINT_NUMBER_MASK)); +				UDCDBGA ("OUT ep %d buffer offset 0x%03x" +					 " packet size 0x%03x", +					 ep_addr & USB_ENDPOINT_NUMBER_MASK, +					 ep_ptr, packet_size); +			} else { +				outw (0, +				      UDC_EP_RX (ep_addr & +						 USB_ENDPOINT_NUMBER_MASK)); +			} +		} +		ep_ptr += buffer_size; +	} +} + +/* omap1510_deconfigure_device + * + * This function balances omap1510_configure_device. + */ +static void omap1510_deconfigure_device (void) +{ +	int epnum; + +	UDCDBG ("clear Cfg_Lock"); +	outw (inw (UDC_SYSCON1) & ~UDC_Cfg_Lock, UDC_SYSCON1); +	UDCREG (UDC_SYSCON1); + +	/* deconfigure all endpoints */ +	for (epnum = 1; epnum <= 15; epnum++) { +		outw (0, UDC_EP_RX (epnum)); +		outw (0, UDC_EP_TX (epnum)); +	} +} + +/* omap1510_configure_device + * + * This function implements TRM Figure 14-9. + */ +static void omap1510_configure_device (struct usb_device_instance *device) +{ +	omap1510_configure_endpoints (device); + + +	/* Figure 14-9 indicates we should enable interrupts here, but we have +	 * other routines (udc_all_interrupts, udc_suspended_interrupts) to +	 * do that. +	 */ + +	UDCDBG ("set Cfg_Lock"); +	outw (inw (UDC_SYSCON1) | UDC_Cfg_Lock, UDC_SYSCON1); +	UDCREG (UDC_SYSCON1); +} + +/* omap1510_write_noniso_tx_fifo + * + * This function implements TRM Figure 14-30. + * + * If the endpoint has an active tx_urb, then the next packet of data from the + * URB is written to the tx FIFO.  The total amount of data in the urb is given + * by urb->actual_length.  The maximum amount of data that can be sent in any + * one packet is given by endpoint->tx_packetSize.  The number of data bytes + * from this URB that have already been transmitted is given by endpoint->sent. + * endpoint->last is updated by this routine with the number of data bytes + * transmitted in this packet. + * + * In accordance with Figure 14-30, the EP_NUM register must already have been + * written with the value to select the appropriate tx FIFO before this routine + * is called. + */ +static void omap1510_write_noniso_tx_fifo (struct usb_endpoint_instance +					   *endpoint) +{ +	struct urb *urb = endpoint->tx_urb; + +	if (urb) { +		unsigned int last, i; + +		UDCDBGA ("urb->buffer %p, buffer_length %d, actual_length %d", +			 urb->buffer, urb->buffer_length, urb->actual_length); +		if ((last = +		     MIN (urb->actual_length - endpoint->sent, +			  endpoint->tx_packetSize))) { +			u8 *cp = urb->buffer + endpoint->sent; + +			UDCDBGA ("endpoint->sent %d, tx_packetSize %d, last %d", endpoint->sent, endpoint->tx_packetSize, last); + +			if (((u32) cp & 1) == 0) {	/* word aligned? */ +				outsw (UDC_DATA, cp, last >> 1); +			} else {	/* byte aligned. */ +				for (i = 0; i < (last >> 1); i++) { +					u16 w = ((u16) cp[2 * i + 1] << 8) | +						(u16) cp[2 * i]; +					outw (w, UDC_DATA); +				} +			} +			if (last & 1) { +				outb (*(cp + last - 1), UDC_DATA); +			} +		} +		endpoint->last = last; +	} +} + +/* omap1510_read_noniso_rx_fifo + * + * This function implements TRM Figure 14-28. + * + * If the endpoint has an active rcv_urb, then the next packet of data is read + * from the rcv FIFO and written to rcv_urb->buffer at offset + * rcv_urb->actual_length to append the packet data to the data from any + * previous packets for this transfer.	We assume that there is sufficient room + * left in the buffer to hold an entire packet of data. + * + * The return value is the number of bytes read from the FIFO for this packet. + * + * In accordance with Figure 14-28, the EP_NUM register must already have been + * written with the value to select the appropriate rcv FIFO before this routine + * is called. + */ +static int omap1510_read_noniso_rx_fifo (struct usb_endpoint_instance +					 *endpoint) +{ +	struct urb *urb = endpoint->rcv_urb; +	int len = 0; + +	if (urb) { +		len = inw (UDC_RXFSTAT); + +		if (len) { +			unsigned char *cp = urb->buffer + urb->actual_length; + +			insw (UDC_DATA, cp, len >> 1); +			if (len & 1) +				*(cp + len - 1) = inb (UDC_DATA); +		} +	} +	return len; +} + +/* omap1510_prepare_for_control_write_status + * + * This function implements TRM Figure 14-17. + * + * We have to deal here with non-autodecoded control writes that haven't already + * been dealt with by ep0_recv_setup.  The non-autodecoded standard control + * write requests are:	set/clear endpoint feature, set configuration, set + * interface, and set descriptor.  ep0_recv_setup handles set/clear requests for + * ENDPOINT_HALT by halting the endpoint for a set request and resetting the + * endpoint for a clear request.  ep0_recv_setup returns an error for + * SET_DESCRIPTOR requests which causes them to be terminated with a stall by + * the setup handler.  A SET_INTERFACE request is handled by ep0_recv_setup by + * generating a DEVICE_SET_INTERFACE event.  This leaves only the + * SET_CONFIGURATION event for us to deal with here. + * + */ +static void omap1510_prepare_for_control_write_status (struct urb *urb) +{ +	struct usb_device_request *request = &urb->device_request;; + +	/* check for a SET_CONFIGURATION request */ +	if (request->bRequest == USB_REQ_SET_CONFIGURATION) { +		int configuration = le16_to_cpu (request->wValue) & 0xff; +		unsigned short devstat = inw (UDC_DEVSTAT); + +		if ((devstat & (UDC_ADD | UDC_CFG)) == UDC_ADD) { +			/* device is currently in ADDRESSED state */ +			if (configuration) { +				/* Assume the specified non-zero configuration +				 * value is valid and switch to the CONFIGURED +				 * state. +				 */ +				outw (UDC_Dev_Cfg, UDC_SYSCON2); +			} +		} else if ((devstat & UDC_CFG) == UDC_CFG) { +			/* device is currently in CONFIGURED state */ +			if (!configuration) { +				/* Switch to ADDRESSED state. */ +				outw (UDC_Clr_Cfg, UDC_SYSCON2); +			} +		} +	} + +	/* select EP0 tx FIFO */ +	outw (UDC_EP_Dir | UDC_EP_Sel, UDC_EP_NUM); +	/* clear endpoint (no data bytes in status stage) */ +	outw (UDC_Clr_EP, UDC_CTRL); +	/* enable the EP0 tx FIFO */ +	outw (UDC_Set_FIFO_En, UDC_CTRL); +	/* deselect the endpoint */ +	outw (UDC_EP_Dir, UDC_EP_NUM); +} + +/* 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. + * + * These functions must only be called with interrupts disabled. + */ +static void 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 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; +		} +	} +} + +/* Handle all device state changes. + * This function implements TRM Figure 14-21. + */ +static void omap1510_udc_state_changed (void) +{ +	u16 bits; +	u16 devstat = inw (UDC_DEVSTAT); + +	UDCDBGA ("state changed, devstat %x, old %x", devstat, udc_devstat); + +	bits = devstat ^ udc_devstat; +	if (bits) { +		if (bits & UDC_ATT) { +			if (devstat & UDC_ATT) { +				UDCDBG ("device attached and powered"); +				udc_state_transition_up (udc_device->device_state, STATE_POWERED); +			} else { +				UDCDBG ("device detached or unpowered"); +				udc_state_transition_down (udc_device->device_state, STATE_ATTACHED); +			} +		} +		if (bits & UDC_USB_Reset) { +			if (devstat & UDC_USB_Reset) { +				UDCDBG ("device reset in progess"); +				udc_state_transition_down (udc_device->device_state, STATE_POWERED); +			} else { +				UDCDBG ("device reset completed"); +			} +		} +		if (bits & UDC_DEF) { +			if (devstat & UDC_DEF) { +				UDCDBG ("device entering default state"); +				udc_state_transition_up (udc_device->device_state, STATE_DEFAULT); +			} else { +				UDCDBG ("device leaving default state"); +				udc_state_transition_down (udc_device->device_state, STATE_POWERED); +			} +		} +		if (bits & UDC_SUS) { +			if (devstat & UDC_SUS) { +				UDCDBG ("entering suspended state"); +				usbd_device_event_irq (udc_device, DEVICE_BUS_INACTIVE, 0); +			} else { +				UDCDBG ("leaving suspended state"); +				usbd_device_event_irq (udc_device, DEVICE_BUS_ACTIVITY, 0); +			} +		} +		if (bits & UDC_R_WK_OK) { +			UDCDBGA ("remote wakeup %s", (devstat & UDC_R_WK_OK) +				 ? "enabled" : "disabled"); +		} +		if (bits & UDC_ADD) { +			if (devstat & UDC_ADD) { +				UDCDBG ("default -> addressed"); +				udc_state_transition_up (udc_device->device_state, STATE_ADDRESSED); +			} else { +				UDCDBG ("addressed -> default"); +				udc_state_transition_down (udc_device->device_state, STATE_DEFAULT); +			} +		} +		if (bits & UDC_CFG) { +			if (devstat & UDC_CFG) { +				UDCDBG ("device configured"); +				/* The ep0_recv_setup function generates the +				 * DEVICE_CONFIGURED event when a +				 * USB_REQ_SET_CONFIGURATION setup packet is +				 * received, so we should already be in the +				 * state STATE_CONFIGURED. +				 */ +				udc_state_transition_up (udc_device->device_state, STATE_CONFIGURED); +			} else { +				UDCDBG ("device deconfigured"); +				udc_state_transition_down (udc_device->device_state, STATE_ADDRESSED); +			} +		} +	} + +	/* Clear interrupt source */ +	outw (UDC_DS_Chg, UDC_IRQ_SRC); + +	/* Save current DEVSTAT */ +	udc_devstat = devstat; +} + +/* Handle SETUP USB interrupt. + * This function implements TRM Figure 14-14. + */ +static void omap1510_udc_setup (struct usb_endpoint_instance *endpoint) +{ +	UDCDBG ("-> Entering device setup"); + +	do { +		const int setup_pktsize = 8; +		unsigned char *datap = +			(unsigned char *) &ep0_urb->device_request; + +		/* Gain access to EP 0 setup FIFO */ +		outw (UDC_Setup_Sel, UDC_EP_NUM); + +		/* Read control request data */ +		insb (UDC_DATA, datap, setup_pktsize); + +		UDCDBGA ("EP0 setup read [%x %x %x %x %x %x %x %x]", +			 *(datap + 0), *(datap + 1), *(datap + 2), +			 *(datap + 3), *(datap + 4), *(datap + 5), +			 *(datap + 6), *(datap + 7)); + +		/* Reset EP0 setup FIFO */ +		outw (0, UDC_EP_NUM); +	} while (inw (UDC_IRQ_SRC) & UDC_Setup); + +	/* Try to process setup packet */ +	if (ep0_recv_setup (ep0_urb)) { +		/* Not a setup packet, stall next EP0 transaction */ +		udc_stall_ep (0); +		UDCDBG ("can't parse setup packet, still waiting for setup"); +		return; +	} + +	/* Check direction */ +	if ((ep0_urb->device_request.bmRequestType & USB_REQ_DIRECTION_MASK) +	    == USB_REQ_HOST2DEVICE) { +		UDCDBG ("control write on EP0"); +		if (le16_to_cpu (ep0_urb->device_request.wLength)) { +			/* We don't support control write data stages. +			 * The only standard control write request with a data +			 * stage is SET_DESCRIPTOR, and ep0_recv_setup doesn't +			 * support that so we just stall those requests.  A +			 * function driver might support a non-standard +			 * write request with a data stage, but it isn't +			 * obvious what we would do with the data if we read it +			 * so we'll just stall it.  It seems like the API isn't +			 * quite right here. +			 */ +#if 0 +			/* Here is what we would do if we did support control +			 * write data stages. +			 */ +			ep0_urb->actual_length = 0; +			outw (0, UDC_EP_NUM); +			/* enable the EP0 rx FIFO */ +			outw (UDC_Set_FIFO_En, UDC_CTRL); +#else +			/* Stall this request */ +			UDCDBG ("Stalling unsupported EP0 control write data " +				"stage."); +			udc_stall_ep (0); +#endif +		} else { +			omap1510_prepare_for_control_write_status (ep0_urb); +		} +	} else { +		UDCDBG ("control read on EP0"); +		/* The ep0_recv_setup function has already placed our response +		 * packet data in ep0_urb->buffer and the packet length in +		 * ep0_urb->actual_length. +		 */ +		endpoint->tx_urb = ep0_urb; +		endpoint->sent = 0; +		/* select the EP0 tx FIFO */ +		outw (UDC_EP_Dir | UDC_EP_Sel, UDC_EP_NUM); +		/* Write packet data to the FIFO.  omap1510_write_noniso_tx_fifo +		 * will update endpoint->last with the number of bytes written +		 * to the FIFO. +		 */ +		omap1510_write_noniso_tx_fifo (endpoint); +		/* enable the FIFO to start the packet transmission */ +		outw (UDC_Set_FIFO_En, UDC_CTRL); +		/* deselect the EP0 tx FIFO */ +		outw (UDC_EP_Dir, UDC_EP_NUM); +	} + +	UDCDBG ("<- Leaving device setup"); +} + +/* Handle endpoint 0 RX interrupt + * This routine implements TRM Figure 14-16. + */ +static void omap1510_udc_ep0_rx (struct usb_endpoint_instance *endpoint) +{ +	unsigned short status; + +	UDCDBG ("RX on EP0"); +	/* select EP0 rx FIFO */ +	outw (UDC_EP_Sel, UDC_EP_NUM); + +	status = inw (UDC_STAT_FLG); + +	if (status & UDC_ACK) { +		/* Check direction */ +		if ((ep0_urb->device_request.bmRequestType +		     & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) { +			/* This rx interrupt must be for a control write data +			 * stage packet. +			 * +			 * We don't support control write data stages. +			 * We should never end up here. +			 */ + +			/* clear the EP0 rx FIFO */ +			outw (UDC_Clr_EP, UDC_CTRL); + +			/* deselect the EP0 rx FIFO */ +			outw (0, UDC_EP_NUM); + +			UDCDBG ("Stalling unexpected EP0 control write " +				"data stage packet"); +			udc_stall_ep (0); +		} else { +			/* This rx interrupt must be for a control read status +			 * stage packet. +			 */ +			UDCDBG ("ACK on EP0 control read status stage packet"); +			/* deselect EP0 rx FIFO */ +			outw (0, UDC_EP_NUM); +		} +	} else if (status & UDC_STALL) { +		UDCDBG ("EP0 stall during RX"); +		/* deselect EP0 rx FIFO */ +		outw (0, UDC_EP_NUM); +	} else { +		/* deselect EP0 rx FIFO */ +		outw (0, UDC_EP_NUM); +	} +} + +/* Handle endpoint 0 TX interrupt + * This routine implements TRM Figure 14-18. + */ +static void omap1510_udc_ep0_tx (struct usb_endpoint_instance *endpoint) +{ +	unsigned short status; +	struct usb_device_request *request = &ep0_urb->device_request; + +	UDCDBG ("TX on EP0"); +	/* select EP0 TX FIFO */ +	outw (UDC_EP_Dir | UDC_EP_Sel, UDC_EP_NUM); + +	status = inw (UDC_STAT_FLG); +	if (status & UDC_ACK) { +		/* Check direction */ +		if ((request->bmRequestType & USB_REQ_DIRECTION_MASK) == +		    USB_REQ_HOST2DEVICE) { +			/* This tx interrupt must be for a control write status +			 * stage packet. +			 */ +			UDCDBG ("ACK on EP0 control write status stage packet"); +			/* deselect EP0 TX FIFO */ +			outw (UDC_EP_Dir, UDC_EP_NUM); +		} else { +			/* This tx interrupt must be for a control read data +			 * stage packet. +			 */ +			int wLength = le16_to_cpu (request->wLength); + +			/* Update our count of bytes sent so far in this +			 * transfer. +			 */ +			endpoint->sent += endpoint->last; + +			/* We are finished with this transfer if we have sent +			 * all of the bytes in our tx urb (urb->actual_length) +			 * unless we need a zero-length terminating packet.  We +			 * need a zero-length terminating packet if we returned +			 * fewer bytes than were requested (wLength) by the host, +			 * and the number of bytes we returned is an exact +			 * multiple of the packet size endpoint->tx_packetSize. +			 */ +			if ((endpoint->sent == ep0_urb->actual_length) +			    && ((ep0_urb->actual_length == wLength) +				|| (endpoint->last != +				    endpoint->tx_packetSize))) { +				/* Done with control read data stage. */ +				UDCDBG ("control read data stage complete"); +				/* deselect EP0 TX FIFO */ +				outw (UDC_EP_Dir, UDC_EP_NUM); +				/* select EP0 RX FIFO to prepare for control +				 * read status stage. +				 */ +				outw (UDC_EP_Sel, UDC_EP_NUM); +				/* clear the EP0 RX FIFO */ +				outw (UDC_Clr_EP, UDC_CTRL); +				/* enable the EP0 RX FIFO */ +				outw (UDC_Set_FIFO_En, UDC_CTRL); +				/* deselect the EP0 RX FIFO */ +				outw (0, UDC_EP_NUM); +			} else { +				/* We still have another packet of data to send +				 * in this control read data stage or else we +				 * need a zero-length terminating packet. +				 */ +				UDCDBG ("ACK control read data stage packet"); +				omap1510_write_noniso_tx_fifo (endpoint); +				/* enable the EP0 tx FIFO to start transmission */ +				outw (UDC_Set_FIFO_En, UDC_CTRL); +				/* deselect EP0 TX FIFO */ +				outw (UDC_EP_Dir, UDC_EP_NUM); +			} +		} +	} else if (status & UDC_STALL) { +		UDCDBG ("EP0 stall during TX"); +		/* deselect EP0 TX FIFO */ +		outw (UDC_EP_Dir, UDC_EP_NUM); +	} else { +		/* deselect EP0 TX FIFO */ +		outw (UDC_EP_Dir, UDC_EP_NUM); +	} +} + +/* Handle RX transaction on non-ISO endpoint. + * This function implements TRM Figure 14-27. + * The ep argument is a physical endpoint number for a non-ISO OUT endpoint + * in the range 1 to 15. + */ +static void omap1510_udc_epn_rx (int ep) +{ +	unsigned short status; + +	/* Check endpoint status */ +	status = inw (UDC_STAT_FLG); + +	if (status & UDC_ACK) { +		int nbytes; +		struct usb_endpoint_instance *endpoint = +			omap1510_find_ep (ep); + +		nbytes = omap1510_read_noniso_rx_fifo (endpoint); +		usbd_rcv_complete (endpoint, nbytes, 0); + +		/* enable rx FIFO to prepare for next packet */ +		outw (UDC_Set_FIFO_En, UDC_CTRL); +	} else if (status & UDC_STALL) { +		UDCDBGA ("STALL on RX endpoint %d", ep); +	} else if (status & UDC_NAK) { +		UDCDBGA ("NAK on RX ep %d", ep); +	} else { +		serial_printf ("omap-bi: RX on ep %d with status %x", ep, +			       status); +	} +} + +/* Handle TX transaction on non-ISO endpoint. + * This function implements TRM Figure 14-29. + * The ep argument is a physical endpoint number for a non-ISO IN endpoint + * in the range 16 to 30. + */ +static void omap1510_udc_epn_tx (int ep) +{ +	unsigned short status; + +	/*serial_printf("omap1510_udc_epn_tx( %x )\n",ep); */ + +	/* Check endpoint status */ +	status = inw (UDC_STAT_FLG); + +	if (status & UDC_ACK) { +		struct usb_endpoint_instance *endpoint = +			omap1510_find_ep (ep); + +		/* We need to transmit a terminating zero-length packet now if +		 * we have sent all of the data in this URB and the transfer +		 * size was an exact multiple of the packet size. +		 */ +		if (endpoint->tx_urb +		    && (endpoint->last == endpoint->tx_packetSize) +		    && (endpoint->tx_urb->actual_length - endpoint->sent - +			endpoint->last == 0)) { +			/* Prepare to transmit a zero-length packet. */ +			endpoint->sent += endpoint->last; +			/* write 0 bytes of data to FIFO */ +			omap1510_write_noniso_tx_fifo (endpoint); +			/* enable tx FIFO to start transmission */ +			outw (UDC_Set_FIFO_En, UDC_CTRL); +		} else if (endpoint->tx_urb +			   && endpoint->tx_urb->actual_length) { +			/* retire the data that was just sent */ +			usbd_tx_complete (endpoint); +			/* Check to see if we have more data ready to transmit +			 * now. +			 */ +			if (endpoint->tx_urb +			    && endpoint->tx_urb->actual_length) { +				/* write data to FIFO */ +				omap1510_write_noniso_tx_fifo (endpoint); +				/* enable tx FIFO to start transmission */ +				outw (UDC_Set_FIFO_En, UDC_CTRL); +			} +		} +	} else if (status & UDC_STALL) { +		UDCDBGA ("STALL on TX endpoint %d", ep); +	} else if (status & UDC_NAK) { +		UDCDBGA ("NAK on TX endpoint %d", ep); +	} else { +		/*serial_printf("omap-bi: TX on ep %d with status %x\n", ep, status); */ +	} +} + + +/* +------------------------------------------------------------------------------- +*/ + +/* Handle general USB interrupts and dispatch according to type. + * This function implements TRM Figure 14-13. + */ +void omap1510_udc_irq (void) +{ +	u16 irq_src = inw (UDC_IRQ_SRC); +	int valid_irq = 0; + +	if (!(irq_src & ~UDC_SOF_Flg))	/* ignore SOF interrupts ) */ +		return; + +	UDCDBGA ("< IRQ #%d start >- %x", udc_interrupts, irq_src); +	/*serial_printf("< IRQ #%d start >- %x\n", udc_interrupts, irq_src); */ + +	if (irq_src & UDC_DS_Chg) { +		/* Device status changed */ +		omap1510_udc_state_changed (); +		valid_irq++; +	} +	if (irq_src & UDC_EP0_RX) { +		/* Endpoint 0 receive */ +		outw (UDC_EP0_RX, UDC_IRQ_SRC); /* ack interrupt */ +		omap1510_udc_ep0_rx (udc_device->bus->endpoint_array + 0); +		valid_irq++; +	} +	if (irq_src & UDC_EP0_TX) { +		/* Endpoint 0 transmit */ +		outw (UDC_EP0_TX, UDC_IRQ_SRC); /* ack interrupt */ +		omap1510_udc_ep0_tx (udc_device->bus->endpoint_array + 0); +		valid_irq++; +	} +	if (irq_src & UDC_Setup) { +		/* Device setup */ +		omap1510_udc_setup (udc_device->bus->endpoint_array + 0); +		valid_irq++; +	} +	/*if (!valid_irq) */ +	/*	serial_printf("unknown interrupt, IRQ_SRC %.4x\n", irq_src); */ +	UDCDBGA ("< IRQ #%d end >", udc_interrupts); +	udc_interrupts++; +} + +/* This function implements TRM Figure 14-26. */ +void omap1510_udc_noniso_irq (void) +{ +	unsigned short epnum; +	unsigned short irq_src = inw (UDC_IRQ_SRC); +	int valid_irq = 0; + +	if (!(irq_src & (UDC_EPn_RX | UDC_EPn_TX))) +		return; + +	UDCDBGA ("non-ISO IRQ, IRQ_SRC %x", inw (UDC_IRQ_SRC)); + +	if (irq_src & UDC_EPn_RX) {	/* Endpoint N OUT transaction */ +		/* Determine the endpoint number for this interrupt */ +		epnum = (inw (UDC_EPN_STAT) & 0x0f00) >> 8; +		UDCDBGA ("RX on ep %x", epnum); + +		/* acknowledge interrupt */ +		outw (UDC_EPn_RX, UDC_IRQ_SRC); + +		if (epnum) { +			/* select the endpoint FIFO */ +			outw (UDC_EP_Sel | epnum, UDC_EP_NUM); + +			omap1510_udc_epn_rx (epnum); + +			/* deselect the endpoint FIFO */ +			outw (epnum, UDC_EP_NUM); +		} +		valid_irq++; +	} +	if (irq_src & UDC_EPn_TX) {	/* Endpoint N IN transaction */ +		/* Determine the endpoint number for this interrupt */ +		epnum = (inw (UDC_EPN_STAT) & 0x000f) | USB_DIR_IN; +		UDCDBGA ("TX on ep %x", epnum); + +		/* acknowledge interrupt */ +		outw (UDC_EPn_TX, UDC_IRQ_SRC); + +		if (epnum) { +			/* select the endpoint FIFO */ +			outw (UDC_EP_Sel | UDC_EP_Dir | epnum, UDC_EP_NUM); + +			omap1510_udc_epn_tx (epnum); + +			/* deselect the endpoint FIFO */ +			outw (UDC_EP_Dir | epnum, UDC_EP_NUM); +		} +		valid_irq++; +	} +	if (!valid_irq) +		serial_printf (": unknown non-ISO interrupt, IRQ_SRC %.4x\n", +			       irq_src); +} + +/* +------------------------------------------------------------------------------- +*/ + + +/* + * Start of public functions. + */ + +/* Called to start packet transmission. */ +void udc_endpoint_write (struct usb_endpoint_instance *endpoint) +{ +	unsigned short epnum = +		endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK; + +	UDCDBGA ("Starting transmit on ep %x", epnum); + +	if (endpoint->tx_urb) { +		/* select the endpoint FIFO */ +		outw (UDC_EP_Sel | UDC_EP_Dir | epnum, UDC_EP_NUM); +		/* write data to FIFO */ +		omap1510_write_noniso_tx_fifo (endpoint); +		/* enable tx FIFO to start transmission */ +		outw (UDC_Set_FIFO_En, UDC_CTRL); +		/* deselect the endpoint FIFO */ +		outw (UDC_EP_Dir | epnum, UDC_EP_NUM); +	} +} + +/* Start to initialize h/w stuff */ +int udc_init (void) +{ +	u16 udc_rev; +	uchar wert; + +	udc_device = NULL; + +	UDCDBG ("starting"); + +	/* Check peripheral reset. Must be 1 to make sure +	   MPU TIPB peripheral reset is inactive */ +	UDCREG (ARM_RSTCT2); + +	/* Set and check clock control. +	 * We might ought to be using the clock control API to do +	 * this instead of fiddling with the clock registers directly +	 * here. +	 */ +	outw ((1 << 4) | (1 << 5), CLOCK_CTRL); +	UDCREG (CLOCK_CTRL); +	/* Set and check APLL */ +	outw (0x0008, APLL_CTRL); +	UDCREG (APLL_CTRL); +	/* Set and check DPLL */ +	outw (0x2210, DPLL_CTRL); +	UDCREG (DPLL_CTRL); +	/* Set and check SOFT */ +	outw ((1 << 4) | (1 << 3) | 1, SOFT_REQ); +	/* Short delay to wait for DPLL */ +	udelay (1000); + +	/* Print banner with device revision */ +	udc_rev = inw (UDC_REV) & 0xff; +	printf ("USB:   TI OMAP1510 USB function module rev %d.%d\n", +		udc_rev >> 4, udc_rev & 0xf); + +	/* Configure some Sofia Unit registers +	 */ +	i2c_read (0x32, 0x04, 1, &wert, 1);	/* SOF_Control_CONT */ +	wert |= 0x04;		/* SOF_ContCONT_dis_usb_det */ +	i2c_write (0x32, 0x04, 1, &wert, 1); + +	i2c_read (0x32, 0x03, 1, &wert, 1);	/* SOF_Control */ +	wert |= 0x01;		/* SOF_Cont_usb_en */ +	i2c_write (0x32, 0x03, 1, &wert, 1); + +	/* The VBUS_MODE bit selects whether VBUS detection is done via +	 * software (1) or hardware (0).  When software detection is +	 * selected, VBUS_CTRL selects whether USB is not connected (0) +	 * or connected (1). +	 */ +	outl (inl (FUNC_MUX_CTRL_0) | UDC_VBUS_MODE, FUNC_MUX_CTRL_0); +	outl (inl (FUNC_MUX_CTRL_0) & ~UDC_VBUS_CTRL, FUNC_MUX_CTRL_0); +	UDCREGL (FUNC_MUX_CTRL_0); + +	/* +	 * At this point, device is ready for configuration... +	 */ + +	UDCDBG ("disable USB interrupts"); +	outw (0, UDC_IRQ_EN); +	UDCREG (UDC_IRQ_EN); + +	UDCDBG ("disable USB DMA"); +	outw (0, UDC_DMA_IRQ_EN); +	UDCREG (UDC_DMA_IRQ_EN); + +	UDCDBG ("initialize SYSCON1"); +	outw (UDC_Self_Pwr | UDC_Pullup_En, UDC_SYSCON1); +	UDCREG (UDC_SYSCON1); + +	return 0; +} + +/* Stall endpoint */ +static void udc_stall_ep (unsigned int ep_addr) +{ +	/*int ep_addr = PHYS_EP_TO_EP_ADDR(ep); */ +	int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK; + +	UDCDBGA ("stall ep_addr %d", ep_addr); + +	/* REVISIT? +	 * The OMAP TRM section 14.2.4.2 says we must check that the FIFO +	 * is empty before halting the endpoint.  The current implementation +	 * doesn't check that the FIFO is empty. +	 */ + +	if (!ep_num) { +		outw (UDC_Stall_Cmd, UDC_SYSCON2); +	} else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) { +		if (inw (UDC_EP_RX (ep_num)) & UDC_EPn_RX_Valid) { +			/* we have a valid rx endpoint, so halt it */ +			outw (UDC_EP_Sel | ep_num, UDC_EP_NUM); +			outw (UDC_Set_Halt, UDC_CTRL); +			outw (ep_num, UDC_EP_NUM); +		} +	} else { +		if (inw (UDC_EP_TX (ep_num)) & UDC_EPn_TX_Valid) { +			/* we have a valid tx endpoint, so halt it */ +			outw (UDC_EP_Sel | UDC_EP_Dir | ep_num, UDC_EP_NUM); +			outw (UDC_Set_Halt, UDC_CTRL); +			outw (ep_num, UDC_EP_NUM); +		} +	} +} + +/* Reset endpoint */ +#if 0 +static void udc_reset_ep (unsigned int ep_addr) +{ +	/*int ep_addr = PHYS_EP_TO_EP_ADDR(ep); */ +	int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK; + +	UDCDBGA ("reset ep_addr %d", ep_addr); + +	if (!ep_num) { +		/* control endpoint 0 can't be reset */ +	} else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) { +		UDCDBGA ("UDC_EP_RX(%d) = 0x%04x", ep_num, +			 inw (UDC_EP_RX (ep_num))); +		if (inw (UDC_EP_RX (ep_num)) & UDC_EPn_RX_Valid) { +			/* we have a valid rx endpoint, so reset it */ +			outw (ep_num | UDC_EP_Sel, UDC_EP_NUM); +			outw (UDC_Reset_EP, UDC_CTRL); +			outw (ep_num, UDC_EP_NUM); +			UDCDBGA ("OUT endpoint %d reset", ep_num); +		} +	} else { +		UDCDBGA ("UDC_EP_TX(%d) = 0x%04x", ep_num, +			 inw (UDC_EP_TX (ep_num))); +		/* Resetting of tx endpoints seems to be causing the USB function +		 * module to fail, which causes problems when the driver is +		 * uninstalled.	 We'll skip resetting tx endpoints for now until +		 * we figure out what the problem is. +		 */ +#if 0 +		if (inw (UDC_EP_TX (ep_num)) & UDC_EPn_TX_Valid) { +			/* we have a valid tx endpoint, so reset it */ +			outw (ep_num | UDC_EP_Dir | UDC_EP_Sel, UDC_EP_NUM); +			outw (UDC_Reset_EP, UDC_CTRL); +			outw (ep_num | UDC_EP_Dir, UDC_EP_NUM); +			UDCDBGA ("IN endpoint %d reset", ep_num); +		} +#endif +	} +} +#endif + +/* ************************************************************************** */ + +/** + * udc_check_ep - check logical endpoint +  * + * Return physical endpoint number to use for this logical endpoint or zero if not valid. + */ +#if 0 +int udc_check_ep (int logical_endpoint, int packetsize) +{ +	if ((logical_endpoint == 0x80) || +	    ((logical_endpoint & 0x8f) != logical_endpoint)) { +		return 0; +	} + +	switch (packetsize) { +	case 8: +	case 16: +	case 32: +	case 64: +	case 128: +	case 256: +	case 512: +		break; +	default: +		return 0; +	} + +	return EP_ADDR_TO_PHYS_EP (logical_endpoint); +} +#endif + +/* + * udc_setup_ep - setup endpoint + * + * Associate a physical endpoint with endpoint_instance + */ +void udc_setup_ep (struct usb_device_instance *device, +		   unsigned int ep, struct usb_endpoint_instance *endpoint) +{ +	UDCDBGA ("setting up endpoint addr %x", endpoint->endpoint_address); + +	/* This routine gets called by bi_modinit for endpoint 0 and from +	 * bi_config for all of the other endpoints.  bi_config gets called +	 * during the DEVICE_CREATE, DEVICE_CONFIGURED, and +	 * DEVICE_SET_INTERFACE events.	 We need to reconfigure the OMAP packet +	 * RAM after bi_config scans the selected device configuration and +	 * initializes the endpoint structures, but before this routine enables +	 * the OUT endpoint FIFOs.  Since bi_config calls this routine in a +	 * loop for endpoints 1 through UDC_MAX_ENDPOINTS, we reconfigure our +	 * packet RAM here when ep==1. +	 * I really hate to do this here, but it seems like the API exported +	 * by the USB bus interface controller driver to the usbd-bi module +	 * isn't quite right so there is no good place to do this. +	 */ +	if (ep == 1) { +		omap1510_deconfigure_device (); +		omap1510_configure_device (device); +	} + +	if (endpoint && (ep < UDC_MAX_ENDPOINTS)) { +		int ep_addr = endpoint->endpoint_address; + +		if (!ep_addr) { +			/* nothing to do for endpoint 0 */ +		} else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { +			/* nothing to do for IN (tx) endpoints */ +		} else {	/* OUT (rx) endpoint */ +			if (endpoint->rcv_packetSize) { +				/*struct urb* urb = &(urb_out_array[ep&0xFF]); */ +				/*urb->endpoint = endpoint; */ +				/*urb->device = device; */ +				/*urb->buffer_length = sizeof(urb->buffer); */ + +				/*endpoint->rcv_urb = urb; */ +				omap1510_prepare_endpoint_for_rx (ep_addr); +			} +		} +	} +} + +/** + * udc_disable_ep - disable endpoint + * @ep: + * + * Disable specified endpoint + */ +#if 0 +void udc_disable_ep (unsigned int ep_addr) +{ +	/*int ep_addr = PHYS_EP_TO_EP_ADDR(ep); */ +	int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK; +	struct usb_endpoint_instance *endpoint = omap1510_find_ep (ep_addr);	/*udc_device->bus->endpoint_array + ep; */ + +	UDCDBGA ("disable ep_addr %d", ep_addr); + +	if (!ep_num) { +		/* nothing to do for endpoint 0 */ ; +	} else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { +		if (endpoint->tx_packetSize) { +			/* we have a valid tx endpoint */ +			/*usbd_flush_tx(endpoint); */ +			endpoint->tx_urb = NULL; +		} +	} else { +		if (endpoint->rcv_packetSize) { +			/* we have a valid rx endpoint */ +			/*usbd_flush_rcv(endpoint); */ +			endpoint->rcv_urb = NULL; +		} +	} +} +#endif + +/* ************************************************************************** */ + +/** + * udc_connected - is the USB cable connected + * + * Return non-zero if cable is connected. + */ +#if 0 +int udc_connected (void) +{ +	return ((inw (UDC_DEVSTAT) & UDC_ATT) == UDC_ATT); +} +#endif + +/* Turn on the USB connection by enabling the pullup resistor */ +void udc_connect (void) +{ +	UDCDBG ("connect, enable Pullup"); +	outl (0x00000018, FUNC_MUX_CTRL_D); +} + +/* Turn off the USB connection by disabling the pullup resistor */ +void udc_disconnect (void) +{ +	UDCDBG ("disconnect, disable Pullup"); +	outl (0x00000000, FUNC_MUX_CTRL_D); +} + +/* ************************************************************************** */ + + +/* + * udc_disable_interrupts - disable interrupts + * switch off interrupts + */ +#if 0 +void udc_disable_interrupts (struct usb_device_instance *device) +{ +	UDCDBG ("disabling all interrupts"); +	outw (0, UDC_IRQ_EN); +} +#endif + +/* ************************************************************************** */ + +/** + * udc_ep0_packetsize - return ep0 packetsize + */ +#if 0 +int udc_ep0_packetsize (void) +{ +	return EP0_PACKETSIZE; +} +#endif + +/* Switch on the UDC */ +void udc_enable (struct usb_device_instance *device) +{ +	UDCDBGA ("enable device %p, status %d", device, device->status); + +	/* initialize driver state variables */ +	udc_devstat = 0; + +	/* Save the device structure pointer */ +	udc_device = device; + +	/* Setup ep0 urb */ +	if (!ep0_urb) { +		ep0_urb = +			usbd_alloc_urb (udc_device, +					udc_device->bus->endpoint_array); +	} else { +		serial_printf ("udc_enable: ep0_urb already allocated %p\n", +			       ep0_urb); +	} + +	UDCDBG ("Check clock status"); +	UDCREG (STATUS_REQ); + +	/* The VBUS_MODE bit selects whether VBUS detection is done via +	 * software (1) or hardware (0).  When software detection is +	 * selected, VBUS_CTRL selects whether USB is not connected (0) +	 * or connected (1). +	 */ +	outl (inl (FUNC_MUX_CTRL_0) | UDC_VBUS_CTRL | UDC_VBUS_MODE, +	      FUNC_MUX_CTRL_0); +	UDCREGL (FUNC_MUX_CTRL_0); + +	omap1510_configure_device (device); +} + +/* Switch off the UDC */ +void udc_disable (void) +{ +	UDCDBG ("disable UDC"); + +	omap1510_deconfigure_device (); + +	/* The VBUS_MODE bit selects whether VBUS detection is done via +	 * software (1) or hardware (0).  When software detection is +	 * selected, VBUS_CTRL selects whether USB is not connected (0) +	 * or connected (1). +	 */ +	outl (inl (FUNC_MUX_CTRL_0) | UDC_VBUS_MODE, FUNC_MUX_CTRL_0); +	outl (inl (FUNC_MUX_CTRL_0) & ~UDC_VBUS_CTRL, FUNC_MUX_CTRL_0); +	UDCREGL (FUNC_MUX_CTRL_0); + +	/* Free ep0 URB */ +	if (ep0_urb) { +		/*usbd_dealloc_urb(ep0_urb); */ +		ep0_urb = NULL; +	} + +	/* Reset device pointer. +	 * We ought to do this here to balance the initialization of udc_device +	 * in udc_enable, but some of our other exported functions get called +	 * by the bus interface driver after udc_disable, so we have to hang on +	 * to the device pointer to avoid a null pointer dereference. */ +	/* udc_device = NULL; */ +} + +/** + * udc_startup - allow udc code to do any additional startup + */ +void udc_startup_events (struct usb_device_instance *device) +{ +	/* The DEVICE_INIT event puts the USB device in the state STATE_INIT. */ +	usbd_device_event_irq (device, DEVICE_INIT, 0); + +	/* The DEVICE_CREATE event puts the USB device in the state +	 * STATE_ATTACHED. +	 */ +	usbd_device_event_irq (device, DEVICE_CREATE, 0); + +	/* Some USB controller driver implementations signal +	 * DEVICE_HUB_CONFIGURED and DEVICE_RESET events here. +	 * DEVICE_HUB_CONFIGURED causes a transition to the state STATE_POWERED, +	 * and DEVICE_RESET causes a transition to the state STATE_DEFAULT. +	 * The OMAP USB client controller has the capability to detect when the +	 * USB cable is connected to a powered USB bus via the ATT bit in the +	 * DEVSTAT register, so we will defer the DEVICE_HUB_CONFIGURED and +	 * DEVICE_RESET events until later. +	 */ + +	udc_enable (device); +} + +#endif diff --git a/drivers/usbtty.c b/drivers/usbtty.c new file mode 100644 index 000000000..2f89e2b74 --- /dev/null +++ b/drivers/usbtty.c @@ -0,0 +1,647 @@ +/* + * (C) Copyright 2003 + * Gerry Hamel, geh@ti.com, Texas Instruments + * + * 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> + +#ifdef CONFIG_USB_TTY + +#include <circbuf.h> +#include <devices.h> +#include "usbtty.h" + +#if 0 +#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) +#else +#define TTYERR(fmt,args...) do{}while(0) +#endif + +/* + * Buffers to hold input and output data + */ +#define USBTTY_BUFFER_SIZE 256 +static circbuf_t usbtty_input; +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_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 + +/* + * Global flag + */ +int usbtty_configured_flag = 0; + + +/* + * Descriptors + */ +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(CONFIG_USBD_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 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 +  }, +}; +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 struct usb_endpoint_descriptor *ep_descriptor_ptrs[NUM_ENDPOINTS] = { +  &(ep_descriptors[0]), +  &(ep_descriptors[1]), +  &(ep_descriptors[2]), +}; + +/* 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]; +} + +/* + * Prototypes + */ +static void usbtty_init_strings (void); +static void usbtty_init_instances (void); +static void usbtty_init_endpoints (void); + +static void usbtty_event_handler (struct usb_device_instance *device, +				  usb_device_event_t event, int data); +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); + + +/* + * Test whether a character is in the RX buffer + */ +int usbtty_tstc (void) +{ +	usbtty_poll (); +	return (usbtty_input.size > 0); +} + +/* + * Read a single byte from the usb client port. Returns 1 on success, 0 + * otherwise. When the function is succesfull, the character read is + * written into its argument c. + */ +int usbtty_getc (void) +{ +	char c; + +	while (usbtty_input.size <= 0) { +		usbtty_poll (); +	} + +	buf_pop (&usbtty_input, &c, 1); +	return c; +} + +/* + * Output a single byte to the usb client port. + */ +void usbtty_putc (const char c) +{ +	buf_push (&usbtty_output, &c, 1); +	/* If \n, also do \r */ +	if (c == '\n') +		buf_push (&usbtty_output, "\r", 1); + +	/* Poll at end to handle new data... */ +	if ((usbtty_output.size + 2) >= usbtty_output.totalsize) { +		usbtty_poll (); +	} +} + + +/* usbtty_puts() helper function for finding the next '\n' in a string */ +static int next_nl_pos (const char *s) +{ +	int i; + +	for (i = 0; s[i] != '\0'; i++) { +		if (s[i] == '\n') +			return i; +	} +	return i; +} + +/* + * Output a string to the usb client port. + */ +static void __usbtty_puts (const char *str, int len) +{ +	int maxlen = usbtty_output.totalsize; +	int space, n; + +	/* break str into chunks < buffer size, if needed */ +	while (len > 0) { +		space = maxlen - usbtty_output.size; + +		/* Empty buffer here, if needed, to ensure space... */ +		if (space <= 0) { +			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); + +		str += n; +		len -= n; +	} +} + +void usbtty_puts (const char *str) +{ +	int n; +	int len = strlen (str); + +	/* add '\r' for each '\n' */ +	while (len > 0) { +		n = next_nl_pos (str); + +		if (str[n] == '\n') { +			__usbtty_puts (str, n + 1); +			__usbtty_puts ("\r", 1); +			str += (n + 1); +			len -= (n + 1); +		} else { +			/* No \n found.	 All done. */ +			__usbtty_puts (str, n); +			break; +		} +	} + +	/* Poll at end to handle new data... */ +	usbtty_poll (); +} + +/* + * Initialize the usb client port. + * + */ +int drv_usbtty_init (void) +{ +	int rc; + + +	/* prepare buffers... */ +	buf_init (&usbtty_input, USBTTY_BUFFER_SIZE); +	buf_init (&usbtty_output, USBTTY_BUFFER_SIZE); + +	/* Now, set up USB controller and infrastructure */ +	udc_init ();		/* Basic USB initialization */ + +	usbtty_init_strings (); +	usbtty_init_instances (); + +	udc_startup_events (device_instance);	/* Enable our device, initialize udc pointers */ +	udc_connect ();		/* Enable pullup for host detection */ + +	usbtty_init_endpoints (); + +	/* Device initialization */ +	memset (&usbttydev, 0, sizeof (usbttydev)); + +	strcpy (usbttydev.name, "usbtty"); +	usbttydev.ext = 0;	/* No extensions */ +	usbttydev.flags = DEV_FLAGS_INPUT | DEV_FLAGS_OUTPUT; +	usbttydev.tstc = usbtty_tstc;	/* 'tstc' function */ +	usbttydev.getc = usbtty_getc;	/* 'getc' function */ +	usbttydev.putc = usbtty_putc;	/* 'putc' function */ +	usbttydev.puts = usbtty_puts;	/* 'puts' function */ + +	rc = device_register (&usbttydev); + +	return (rc == 0) ? 1 : rc; +} + +static void usbtty_init_strings (void) +{ +	struct usb_string_descriptor *string; + +	string = (struct usb_string_descriptor *) wstrManufacturer; +	string->bLength = sizeof (wstrManufacturer); +	string->bDescriptorType = USB_DT_STRING; +	str2wide (CONFIG_USBD_MANUFACTURER, string->wData); + +	string = (struct usb_string_descriptor *) wstrProduct; +	string->bLength = sizeof (wstrProduct); +	string->bDescriptorType = USB_DT_STRING; +	str2wide (CONFIG_USBD_PRODUCT_NAME, string->wData); + +	string = (struct usb_string_descriptor *) wstrSerial; +	string->bLength = sizeof (wstrSerial); +	string->bDescriptorType = USB_DT_STRING; +	str2wide (CONFIG_USBD_SERIAL_NUMBER, string->wData); + +	string = (struct usb_string_descriptor *) wstrConfiguration; +	string->bLength = sizeof (wstrConfiguration); +	string->bDescriptorType = USB_DT_STRING; +	str2wide (CONFIG_USBD_CONFIGURATION_STR, string->wData); + +	string = (struct usb_string_descriptor *) wstrInterface; +	string->bLength = sizeof (wstrInterface); +	string->bDescriptorType = USB_DT_STRING; +	str2wide (CONFIG_USBD_INTERFACE_STR, string->wData); + +	/* Now, initialize the string table for ep0 handling */ +	usb_strings = usbtty_string_table; +} + +static void usbtty_init_instances (void) +{ +	int i; + +	/* initialize device instance */ +	memset (device_instance, 0, sizeof (struct usb_device_instance)); +	device_instance->device_state = STATE_INIT; +	device_instance->device_descriptor = &device_descriptor; +	device_instance->event = usbtty_event_handler; +	device_instance->bus = bus_instance; +	device_instance->configurations = NUM_CONFIGS; +	device_instance->configuration_instance_array = config_instance; + +	/* initialize bus instance */ +	memset (bus_instance, 0, sizeof (struct usb_bus_instance)); +	bus_instance->device = device_instance; +	bus_instance->endpoint_array = endpoint_instance; +	bus_instance->max_endpoints = 1; +	bus_instance->maxpacketsize = 64; +	bus_instance->serial_number_str = CONFIG_USBD_SERIAL_NUMBER; + +	/* configuration instance */ +	memset (config_instance, 0, +		sizeof (struct usb_configuration_instance)); +	config_instance->interfaces = NUM_INTERFACES; +	config_instance->configuration_descriptor = config_descriptors; +	config_instance->interface_instance_array = interface_instance; + +	/* interface instance */ +	memset (interface_instance, 0, +		sizeof (struct usb_interface_instance)); +	interface_instance->alternates = 1; +	interface_instance->alternates_instance_array = alternate_instance; + +	/* alternates instance */ +	memset (alternate_instance, 0, +		sizeof (struct usb_alternate_instance)); +	alternate_instance->interface_descriptor = interface_descriptors; +	alternate_instance->endpoints = NUM_ENDPOINTS; +	alternate_instance->endpoints_descriptor_array = ep_descriptor_ptrs; + +	/* endpoint instances */ +	memset (&endpoint_instance[0], 0, +		sizeof (struct usb_endpoint_instance)); +	endpoint_instance[0].endpoint_address = 0; +	endpoint_instance[0].rcv_packetSize = EP0_MAX_PACKET_SIZE; +	endpoint_instance[0].rcv_attributes = USB_ENDPOINT_XFER_CONTROL; +	endpoint_instance[0].tx_packetSize = EP0_MAX_PACKET_SIZE; +	endpoint_instance[0].tx_attributes = USB_ENDPOINT_XFER_CONTROL; +	udc_setup_ep (device_instance, 0, &endpoint_instance[0]); + +	for (i = 1; i <= NUM_ENDPOINTS; i++) { +		memset (&endpoint_instance[i], 0, +			sizeof (struct usb_endpoint_instance)); + +		endpoint_instance[i].endpoint_address = +			ep_descriptors[i - 1].bEndpointAddress; + +		endpoint_instance[i].rcv_packetSize = +			ep_descriptors[i - 1].wMaxPacketSize; +		endpoint_instance[i].rcv_attributes = +			ep_descriptors[i - 1].bmAttributes; + +		endpoint_instance[i].tx_packetSize = +			ep_descriptors[i - 1].wMaxPacketSize; +		endpoint_instance[i].tx_attributes = +			ep_descriptors[i - 1].bmAttributes; + +		urb_link_init (&endpoint_instance[i].rcv); +		urb_link_init (&endpoint_instance[i].rdy); +		urb_link_init (&endpoint_instance[i].tx); +		urb_link_init (&endpoint_instance[i].done); + +		if (endpoint_instance[i].endpoint_address & USB_DIR_IN) +			endpoint_instance[i].tx_urb = +				usbd_alloc_urb (device_instance, +						&endpoint_instance[i]); +		else +			endpoint_instance[i].rcv_urb = +				usbd_alloc_urb (device_instance, +						&endpoint_instance[i]); +	} +} + +static void usbtty_init_endpoints (void) +{ +	int i; + +	bus_instance->max_endpoints = NUM_ENDPOINTS + 1; +	for (i = 0; i <= NUM_ENDPOINTS; i++) { +		udc_setup_ep (device_instance, i, &endpoint_instance[i]); +	} +} + + +/*********************************************************************************/ + +static struct urb *next_urb (struct usb_device_instance *device, +			     struct usb_endpoint_instance *endpoint) +{ +	struct urb *current_urb = NULL; +	int space; + +	/* If there's a queue, then we should add to the last urb */ +	if (!endpoint->tx_queue) { +		current_urb = endpoint->tx_urb; +	} else { +		/* Last urb from tx chain */ +		current_urb = +			p2surround (struct urb, link, endpoint->tx.prev); +	} + +	/* Make sure this one has enough room */ +	space = current_urb->buffer_length - current_urb->actual_length; +	if (space > 0) { +		return current_urb; +	} else {		/* No space here */ +		/* First look at done list */ +		current_urb = first_urb_detached (&endpoint->done); +		if (!current_urb) { +			current_urb = usbd_alloc_urb (device, endpoint); +		} + +		urb_append (&endpoint->tx, current_urb); +		endpoint->tx_queue++; +	} +	return current_urb; +} + +static int write_buffer (circbuf_t * buf) +{ +	if (!usbtty_configured ()) { +		return 0; +	} + +	if (buf->size) { + +		struct usb_endpoint_instance *endpoint = +			&endpoint_instance[TX_ENDPOINT]; +		struct urb *current_urb = NULL; +		char *dest; + +		int space_avail; +		int popnum, popped; +		int total = 0; + +		/* 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 + +				current_urb->actual_length; + +			space_avail = +				current_urb->buffer_length - +				current_urb->actual_length; +			popnum = MIN (space_avail, buf->size); +			if (popnum == 0) +				break; + +			popped = buf_pop (buf, dest, popnum); +			if (popped == 0) +				break; +			current_urb->actual_length += popped; +			total += popped; + +			/* If endpoint->last == 0, then transfers have not started on this endpoint */ +			if (endpoint->last == 0) { +				udc_endpoint_write (endpoint); +			} + +		}		/* end while */ +		return total; +	}			/* end if tx_urb */ + +	return 0; +} + +static int fill_buffer (circbuf_t * buf) +{ +	struct usb_endpoint_instance *endpoint = +		&endpoint_instance[RECV_ENDPOINT]; + +	if (endpoint->rcv_urb && endpoint->rcv_urb->actual_length) { +		unsigned int nb = endpoint->rcv_urb->actual_length; +		char *src = (char *) endpoint->rcv_urb->buffer; + +		buf_push (buf, src, nb); +		endpoint->rcv_urb->actual_length = 0; + +		return nb; +	} + +	return 0; +} + +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) +{ +	switch (event) { +	case DEVICE_RESET: +	case DEVICE_BUS_INACTIVE: +		usbtty_configured_flag = 0; +		break; +	case DEVICE_CONFIGURED: +		usbtty_configured_flag = 1; +		break; + +	case DEVICE_ADDRESS_ASSIGNED: +		usbtty_init_endpoints (); + +	default: +		break; +	} +} + +/*********************************************************************************/ + + +/* + * Since interrupt handling has not yet been implemented, we use this function + * to handle polling.  This is called by the tstc,getc,putc,puts routines to + * update the USB state. + */ +void usbtty_poll (void) +{ +	/* New interrupts? */ +	pretend_interrupts (); + +	/* 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 (); + +	/* 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 (); +} + +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 new file mode 100644 index 000000000..79c2fe57d --- /dev/null +++ b/drivers/usbtty.h @@ -0,0 +1,64 @@ +/* + * (C) Copyright 2003 + * Gerry Hamel, geh@ti.com, Texas Instruments + * + * 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 __USB_TTY_H__ +#define __USB_TTY_H__ + + +#include "usbdcore.h" +#include "usbdcore_omap1510.h" + + +#define NUM_CONFIGS    1 +#define NUM_INTERFACES 1 +#define NUM_ENDPOINTS  3 + +#define EP0_MAX_PACKET_SIZE 64 + +#define CONFIG_USBD_CONFIGURATION_STR "TTY via USB" +#define CONFIG_USBD_INTERFACE_STR     "Simple Serial Data Interface - Bulk Mode" + + +#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 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 STR_MANUFACTURER 1 +#define STR_PRODUCT	 2 +#define STR_SERIAL	 3 +#define STR_CONFIG	 4 +#define STR_INTERFACE	 5 + +#endif diff --git a/include/circbuf.h b/include/circbuf.h new file mode 100644 index 000000000..e10ed9571 --- /dev/null +++ b/include/circbuf.h @@ -0,0 +1,40 @@ +/* + * (C) Copyright 2003 + * Gerry Hamel, geh@ti.com, Texas Instruments + * + * 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 __CIRCBUF_H__ +#define __CIRCBUF_H__ + +typedef struct circbuf { +	unsigned int size;	/* current number of bytes held */ +	unsigned int totalsize; /* number of bytes allocated */ + +	char *top;		/* pointer to current buffer start */ +	char *tail;		/* pointer to space for next element */ + +	char *data;		/* all data */ +	char *end;		/* end of data buffer */ +} circbuf_t; + +int buf_init (circbuf_t * buf, unsigned int size); +int buf_free (circbuf_t * buf); +int buf_pop (circbuf_t * buf, char *dest, unsigned int len); +int buf_push (circbuf_t * buf, const char *src, unsigned int len); + +#endif diff --git a/include/configs/SX1.h b/include/configs/SX1.h new file mode 100644 index 000000000..ca536c5d3 --- /dev/null +++ b/include/configs/SX1.h @@ -0,0 +1,177 @@ +/* + * (C) Copyright 2004 + * Wolfgang Denk, DENX Software Engineering, wd@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 + */ +#ifndef __CONFIG_H +#define __CONFIG_H + +/* + * If we are developing, we might want to start armboot from ram + * so we MUST NOT initialize critical regs like mem-timing ... + */ +#define CONFIG_INIT_CRITICAL		/* undef for developing */ + +/* + * High Level Configuration Options + * (easy to change) + */ +#define CONFIG_ARM925T	1		/* This is an arm925t CPU	*/ +#define CONFIG_OMAP	1		/* in a TI OMAP core	*/ +#define CONFIG_OMAP1510 1		/* which is in a 1510 (helen) */ +#define CONFIG_OMAP_SX1 1		/*	a SX1 Board  */ + +/* input clock of PLL */ +#define CONFIG_SYS_CLK_FREQ	12000000	/* the SX1 has 12MHz input clock */ + +#undef CONFIG_USE_IRQ			/* we don't need IRQ/FIQ stuff */ + +#define CONFIG_MISC_INIT_R + +#define CONFIG_CMDLINE_TAG	 1	/* enable passing of ATAGs	*/ +#define CONFIG_SETUP_MEMORY_TAGS 1 +#define CONFIG_INITRD_TAG	 1 + +/* + * Size of malloc() pool + */ +#define CFG_MALLOC_LEN		(CFG_ENV_SIZE + 128*1024) +#define CFG_GBL_DATA_SIZE	128	/* size in bytes reserved for initial data */ + +/* + * Hardware drivers + */ + +/* + * NS16550 Configuration + */ +#define CFG_NS16550 +#define CFG_NS16550_SERIAL +#define CFG_NS16550_REG_SIZE	(-4) +#define CFG_NS16550_CLK		(CONFIG_SYS_CLK_FREQ)	/* can be 12M/32Khz or 48Mhz  */ +#define CFG_NS16550_COM1	0xfffb0000		/* uart1, bluetooth uart on helen */ + +/* + * select serial console configuration + */ +#define CONFIG_SERIAL1		1	/* we use SERIAL 1 on SX1 */ + +/* + * USB device configuration + */ +#define CONFIG_USB_DEVICE	1 +#define CONFIG_USB_TTY		1 + +#define CONFIG_USBD_VENDORID		0x1234 +#define CONFIG_USBD_PRODUCTID		0x5678 +#define CONFIG_USBD_MANUFACTURER	"Siemens" +#define CONFIG_USBD_PRODUCT_NAME	"SX1" +#define CONFIG_USBD_SERIAL_NUMBER	"000000000001" + + +/* + * I2C configuration + */ +#define CONFIG_HARD_I2C +#define CFG_I2C_SPEED		100000 +#define CFG_I2C_SLAVE		1 +#define CONFIG_DRIVER_OMAP1510_I2C + +#define CONFIG_ENV_OVERWRITE + +#define CONFIG_ENV_OVERWRITE +#define CONFIG_CONS_INDEX	1 +#define CONFIG_BAUDRATE		115200 +#define CFG_BAUDRATE_TABLE	{ 9600, 19200, 38400, 57600, 115200 } + +#define CONFIG_COMMANDS		(( CONFIG_CMD_DFL | \ +				   CFG_CMD_I2C ) & \ +				  ~CFG_CMD_NET) + +/* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */ +#include <cmd_confdefs.h> +#include <configs/omap1510.h> + +#define CONFIG_BOOTDELAY	3 +#define CONFIG_BOOTARGS		"mem=16M console=ttyS0,115200n8 root=/dev/mtdblock3 rw" + +/* + * Miscellaneous configurable options + */ +#define CFG_LONGHELP				/* undef to save memory		*/ +#define CFG_PROMPT		"SX1# " /* Monitor Command Prompt	*/ +#define CFG_CBSIZE		256		/* Console I/O Buffer Size	*/ +#define CFG_PBSIZE (CFG_CBSIZE+sizeof(CFG_PROMPT)+16) /* Print Buffer Size */ +#define CFG_MAXARGS		16		/* max number of command args	*/ +#define CFG_BARGSIZE		CFG_CBSIZE	/* Boot Argument Buffer Size	*/ + +#define CFG_MEMTEST_START	0x10000000	/* memtest works on	*/ +#define CFG_MEMTEST_END		0x12000000	/* 32 MB in DRAM	*/ + +#undef	CFG_CLKS_IN_HZ		/* everything, incl board info, in Hz */ + +#define CFG_LOAD_ADDR		0x10000000	/* default load address */ + +/* The 1510 has 3 timers, they can be driven by the RefClk (12Mhz) or by DPLL1. + * This time is further subdivided by a local divisor. + */ +#define CFG_TIMERBASE	0xFFFEC500	    /* use timer 1 */ +#define CFG_PVT		7		    /* 2^(pvt+1), divide by 256 */ +#define CFG_HZ			((CONFIG_SYS_CLK_FREQ)/(2 << CFG_PVT)) + +/*----------------------------------------------------------------------- + * Stack sizes + * + * The stack sizes are set up in start.S using the settings below + */ +#define CONFIG_STACKSIZE	(128*1024)	/* regular stack */ +#ifdef CONFIG_USE_IRQ +#define CONFIG_STACKSIZE_IRQ	(4*1024)	/* IRQ stack */ +#define CONFIG_STACKSIZE_FIQ	(4*1024)	/* FIQ stack */ +#endif + +/*----------------------------------------------------------------------- + * Physical Memory Map + */ +#define CONFIG_NR_DRAM_BANKS	1	   /* we have 1 bank of DRAM */ +#define PHYS_SDRAM_1		0x10000000 /* SDRAM Bank #1 */ +#define PHYS_SDRAM_1_SIZE	0x02000000 /* 32 MB */ + +#define PHYS_FLASH_1		0x00000000 /* Flash Bank #1 */ +#define PHYS_FLASH_2		0x04000000 /* Flash Bank #2 */ + +#define CFG_FLASH_BASE		PHYS_FLASH_1 + +/*----------------------------------------------------------------------- + * FLASH and environment organization + */ +#define CFG_MAX_FLASH_BANKS	2	/* max number of memory banks */ +#define CFG_MAX_FLASH_SECT	(128)	/* max number of sectors on one chip */ +#define CFG_ENV_ADDR		(CFG_FLASH_BASE + 0x020000) /* addr of environment */ + +/* timeout values are in ticks */ +#define CFG_FLASH_ERASE_TOUT	(20*CFG_HZ) /* Timeout for Flash Erase */ +#define CFG_FLASH_WRITE_TOUT	(20*CFG_HZ) /* Timeout for Flash Write */ + +#define CFG_ENV_IS_IN_FLASH	1 +#define CFG_ENV_SIZE		0x20000 /* Total Size of Environment Sector */ +#define CFG_ENV_OFFSET		0x20000 /* environment starts here  */ + +#endif	/* __CONFIG_H */ diff --git a/include/configs/omap1510.h b/include/configs/omap1510.h index 2658135e9..6787b1928 100644 --- a/include/configs/omap1510.h +++ b/include/configs/omap1510.h @@ -179,7 +179,7 @@  #define USB_OTG_CTRL			0xFFFB040C  #define USB_TRANSCEIVER_CTRL	0xFFFE1064 -#define PULL_DWN_CTRL_4	0xFFFE10AC +#define PULL_DWN_CTRL_4 0xFFFE10AC  #define PU_PD_SEL_0		0xFFFE10B4  #define PU_PD_SEL_1		0xFFFE10B8  #define PU_PD_SEL_2		0xFFFE10BC @@ -221,6 +221,89 @@  #define OMAP_LCD_CONTROL	TI925_LCD_CONTROL +/* I2C Registers */ + +#define I2C_BASE		0xfffb3800 + +#define I2C_REV			(I2C_BASE + 0x00) +#define I2C_IE			(I2C_BASE + 0x04) +#define I2C_STAT		(I2C_BASE + 0x08) +#define I2C_IV			(I2C_BASE + 0x0c) +#define I2C_BUF			(I2C_BASE + 0x14) +#define I2C_CNT			(I2C_BASE + 0x18) +#define I2C_DATA		(I2C_BASE + 0x1c) +#define I2C_CON			(I2C_BASE + 0x24) +#define I2C_OA			(I2C_BASE + 0x28) +#define I2C_SA			(I2C_BASE + 0x2c) +#define I2C_PSC			(I2C_BASE + 0x30) +#define I2C_SCLL		(I2C_BASE + 0x34) +#define I2C_SCLH		(I2C_BASE + 0x38) +#define I2C_SYSTEST		(I2C_BASE + 0x3c) + +/* I2C masks */ + +/* I2C Interrupt Enable Register (I2C_IE): */ + +#define I2C_IE_XRDY_IE	(1 << 4)	/* Transmit data ready interrupt enable */ +#define I2C_IE_RRDY_IE	(1 << 3)	/* Receive data ready interrupt enable */ +#define I2C_IE_ARDY_IE	(1 << 2)	/* Register access ready interrupt enable */ +#define I2C_IE_NACK_IE	(1 << 1)	/* No acknowledgment interrupt enable */ +#define I2C_IE_AL_IE	(1 << 0)	/* Arbitration lost interrupt enable */ + +/* I2C Status Register (I2C_STAT): */ + +#define I2C_STAT_SBD	(1 << 15)	/* Single byte data */ +#define I2C_STAT_BB	(1 << 12)	/* Bus busy */ +#define I2C_STAT_ROVR	(1 << 11)	/* Receive overrun */ +#define I2C_STAT_XUDF	(1 << 10)	/* Transmit underflow */ +#define I2C_STAT_AAS	(1 << 9)	/* Address as slave */ +#define I2C_STAT_AD0	(1 << 8)	/* Address zero */ +#define I2C_STAT_XRDY	(1 << 4)	/* Transmit data ready */ +#define I2C_STAT_RRDY	(1 << 3)	/* Receive data ready */ +#define I2C_STAT_ARDY	(1 << 2)	/* Register access ready */ +#define I2C_STAT_NACK	(1 << 1)	/* No acknowledgment interrupt enable */ +#define I2C_STAT_AL	(1 << 0)	/* Arbitration lost interrupt enable */ + +/* I2C Interrupt Vector Register (I2C_IV): */ + +/* I2C Interrupt Code Register (I2C_INTCODE): */ + +#define I2C_INTCODE_MASK	7 +#define I2C_INTCODE_NONE	0 +#define I2C_INTCODE_AL		1	/* Arbitration lost */ +#define I2C_INTCODE_NAK		2	/* No acknowledgement/general call */ +#define I2C_INTCODE_ARDY	3	/* Register access ready */ +#define I2C_INTCODE_RRDY	4	/* Rcv data ready */ +#define I2C_INTCODE_XRDY	5	/* Xmit data ready */ + +/* I2C Buffer Configuration Register (I2C_BUF): */ + +#define I2C_BUF_RDMA_EN		(1 << 15)	/* Receive DMA channel enable */ +#define I2C_BUF_XDMA_EN		(1 << 7)	/* Transmit DMA channel enable */ + +/* I2C Configuration Register (I2C_CON): */ + +#define I2C_CON_EN	(1 << 15)	/* I2C module enable */ +#define I2C_CON_BE	(1 << 14)	/* Big endian mode */ +#define I2C_CON_STB	(1 << 11)	/* Start byte mode (master mode only) */ +#define I2C_CON_MST	(1 << 10)	/* Master/slave mode */ +#define I2C_CON_TRX	(1 << 9)	/* Transmitter/receiver mode (master mode only) */ +#define I2C_CON_XA	(1 << 8)	/* Expand address */ +#define I2C_CON_RM	(1 << 2)	/* Repeat mode (master mode only) */ +#define I2C_CON_STP	(1 << 1)	/* Stop condition (master mode only) */ +#define I2C_CON_STT	(1 << 0)	/* Start condition (master mode only) */ + +/* I2C System Test Register (I2C_SYSTEST): */ + +#define I2C_SYSTEST_ST_EN	(1 << 15)	/* System test enable */ +#define I2C_SYSTEST_FREE	(1 << 14)	/* Free running mode (on breakpoint) */ +#define I2C_SYSTEST_TMODE_MASK	(3 << 12)	/* Test mode select */ +#define I2C_SYSTEST_TMODE_SHIFT (12)		/* Test mode select */ +#define I2C_SYSTEST_SCL_I	(1 << 3)	/* SCL line sense input value */ +#define I2C_SYSTEST_SCL_O	(1 << 2)	/* SCL line drive output value */ +#define I2C_SYSTEST_SDA_I	(1 << 1)	/* SDA line sense input value */ +#define I2C_SYSTEST_SDA_O	(1 << 0)	/* SDA line drive output value */ +  /*   * MMC/SD Host Controller Registers   */ @@ -696,3 +779,12 @@ int cpu_type(void);  #define IRQ_LEVEL_INT		1  #define IRQ_EDGE_INT		0 + +/* Macros to access registers */ +#define outb(v,p) *(volatile u8 *) (p) = v +#define outw(v,p) *(volatile u16 *) (p) = v +#define outl(v,p) *(volatile u32 *) (p) = v + +#define inb(p)	*(volatile u8 *) (p) +#define inw(p)	*(volatile u16 *) (p) +#define inl(p)	*(volatile u32 *) (p) diff --git a/include/devices.h b/include/devices.h index a27c4e83f..9f2a0c34a 100644 --- a/include/devices.h +++ b/include/devices.h @@ -105,5 +105,8 @@ int	drv_video_init (void);  #ifdef CONFIG_KEYBOARD  int	drv_keyboard_init (void);  #endif +#ifdef CONFIG_USB_TTY +int	drv_usbtty_init (void); +#endif  #endif	/* _DEVICES_H_ */ diff --git a/include/usbdcore.h b/include/usbdcore.h new file mode 100644 index 000000000..6e92df13b --- /dev/null +++ b/include/usbdcore.h @@ -0,0 +1,671 @@ +/* + * (C) Copyright 2003 + * Gerry Hamel, geh@ti.com, Texas Instruments + * + * Based on linux/drivers/usbd/usbd.h + * + * Copyright (c) 2000, 2001, 2002 Lineo + * Copyright (c) 2001 Hewlett Packard + * + * By: + *	Stuart Lynne <sl@lineo.com>, + *	Tom Rushworth <tbr@lineo.com>, + *	Bruce Balden <balden@lineo.com> + * + * 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. + * + */ + +#ifndef __USBDCORE_H__ +#define __USBDCORE_H__ + +#include <common.h> +#include "usbdescriptors.h" + + +#define MAX_URBS_QUEUED 5 + + +#if 1 +#define usberr(fmt,args...) serial_printf("ERROR: %s(), %d: "fmt"\n",__FUNCTION__,__LINE__,##args) +#else +#define usberr(fmt,args...) do{}while(0) +#endif + +#if 0 +#define usbdbg(fmt,args...) serial_printf("debug: %s(), %d: "fmt"\n",__FUNCTION__,__LINE__,##args) +#else +#define usbdbg(fmt,args...) do{}while(0) +#endif + +#if 0 +#define usbinfo(fmt,args...) serial_printf("info: %s(), %d: "fmt"\n",__FUNCTION__,__LINE__,##args) +#else +#define usbinfo(fmt,args...) do{}while(0) +#endif + +#ifndef le16_to_cpu +#define le16_to_cpu(x)	(x) +#endif + +#ifndef inb +#define inb(p)	     (*(volatile u8*)(p)) +#endif + +#ifndef outb +#define outb(val,p)  (*(volatile u8*)(p) = (val)) +#endif + +#ifndef inw +#define inw(p)	     (*(volatile u16*)(p)) +#endif + +#ifndef outw +#define outw(val,p)  (*(volatile u16*)(p) = (val)) +#endif + +#ifndef inl +#define inl(p)	     (*(volatile u32*)(p)) +#endif + +#ifndef outl +#define outl(val,p)  (*(volatile u32*)(p) = (val)) +#endif + +#ifndef insw +#define insw(p,to,len)	   mmio_insw(p,to,len) +#endif + +#ifndef outsw +#define outsw(p,from,len)  mmio_outsw(p,from,len) +#endif + +#ifndef insb +#define insb(p,to,len)	   mmio_insb(p,to,len) +#endif + +#ifndef mmio_insw +#define mmio_insw(r,b,l)	({	int __i ;  \ +					u16 *__b2;  \ +					__b2 = (u16 *) b;  \ +					for (__i = 0; __i < l; __i++) {	 \ +					  *(__b2 + __i) = inw(r);  \ +					};  \ +				}) +#endif + +#ifndef mmio_outsw +#define mmio_outsw(r,b,l)	({	int __i; \ +					u16 *__b2; \ +					__b2 = (u16 *) b; \ +					for (__i = 0; __i < l; __i++) { \ +					    outw( *(__b2 + __i), r); \ +					} \ +				}) +#endif + +#ifndef mmio_insb +#define mmio_insb(r,b,l)	({	int __i ;  \ +					u8 *__b2;  \ +					__b2 = (u8 *) b;  \ +					for (__i = 0; __i < l; __i++) {	 \ +					  *(__b2 + __i) = inb(r);  \ +					};  \ +				}) +#endif + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif +#ifndef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif + + +/* + * Structure member address manipulation macros. + * These are used by client code (code using the urb_link routines), since + * the urb_link structure is embedded in the client data structures. + * + * Note: a macro offsetof equivalent to member_offset is defined in stddef.h + *	 but this is kept here for the sake of portability. + * + * p2surround returns a pointer to the surrounding structure given + * type of the surrounding structure, the name memb of the structure + * member pointed at by ptr.  For example, if you have: + * + *	struct foo { + *	    int x; + *	    float y; + *	    char z; + *	} thingy; + * + *	char *cp = &thingy.z; + * + * then + * + *	&thingy == p2surround(struct foo, z, cp) + * + * Clear? + */ +#define _cv_(ptr)		  ((char*)(void*)(ptr)) +#define member_offset(type,memb)  (_cv_(&(((type*)0)->memb))-(char*)0) +#define p2surround(type,memb,ptr) ((type*)(void*)(_cv_(ptr)-member_offset(type,memb))) + +struct urb; + +struct usb_endpoint_instance; +struct usb_interface_instance; +struct usb_configuration_instance; +struct usb_device_instance; +struct usb_bus_instance; + +/* + * Device and/or Interface Class codes + */ +#define USB_CLASS_PER_INTERFACE		0	/* for DeviceClass */ +#define USB_CLASS_AUDIO			1 +#define USB_CLASS_COMM			2 +#define USB_CLASS_HID			3 +#define USB_CLASS_PHYSICAL		5 +#define USB_CLASS_PRINTER		7 +#define USB_CLASS_MASS_STORAGE		8 +#define USB_CLASS_HUB			9 +#define USB_CLASS_DATA			10 +#define USB_CLASS_APP_SPEC		0xfe +#define USB_CLASS_VENDOR_SPEC		0xff + +/* + * USB types + */ +#define USB_TYPE_STANDARD		(0x00 << 5) +#define USB_TYPE_CLASS			(0x01 << 5) +#define USB_TYPE_VENDOR			(0x02 << 5) +#define USB_TYPE_RESERVED		(0x03 << 5) + +/* + * USB recipients + */ +#define USB_RECIP_DEVICE		0x00 +#define USB_RECIP_INTERFACE		0x01 +#define USB_RECIP_ENDPOINT		0x02 +#define USB_RECIP_OTHER			0x03 + +/* + * USB directions + */ +#define USB_DIR_OUT			0 +#define USB_DIR_IN			0x80 + +/* + * Descriptor types + */ +#define USB_DT_DEVICE			0x01 +#define USB_DT_CONFIG			0x02 +#define USB_DT_STRING			0x03 +#define USB_DT_INTERFACE		0x04 +#define USB_DT_ENDPOINT			0x05 + +#define USB_DT_HID			(USB_TYPE_CLASS | 0x01) +#define USB_DT_REPORT			(USB_TYPE_CLASS | 0x02) +#define USB_DT_PHYSICAL			(USB_TYPE_CLASS | 0x03) +#define USB_DT_HUB			(USB_TYPE_CLASS | 0x09) + +/* + * Descriptor sizes per descriptor type + */ +#define USB_DT_DEVICE_SIZE		18 +#define USB_DT_CONFIG_SIZE		9 +#define USB_DT_INTERFACE_SIZE		9 +#define USB_DT_ENDPOINT_SIZE		7 +#define USB_DT_ENDPOINT_AUDIO_SIZE	9	/* Audio extension */ +#define USB_DT_HUB_NONVAR_SIZE		7 +#define USB_DT_HID_SIZE			9 + +/* + * Endpoints + */ +#define USB_ENDPOINT_NUMBER_MASK	0x0f	/* in bEndpointAddress */ +#define USB_ENDPOINT_DIR_MASK		0x80 + +#define USB_ENDPOINT_XFERTYPE_MASK	0x03	/* in bmAttributes */ +#define USB_ENDPOINT_XFER_CONTROL	0 +#define USB_ENDPOINT_XFER_ISOC		1 +#define USB_ENDPOINT_XFER_BULK		2 +#define USB_ENDPOINT_XFER_INT		3 + +/* + * USB Packet IDs (PIDs) + */ +#define USB_PID_UNDEF_0			       0xf0 +#define USB_PID_OUT			       0xe1 +#define USB_PID_ACK			       0xd2 +#define USB_PID_DATA0			       0xc3 +#define USB_PID_PING			       0xb4	/* USB 2.0 */ +#define USB_PID_SOF			       0xa5 +#define USB_PID_NYET			       0x96	/* USB 2.0 */ +#define USB_PID_DATA2			       0x87	/* USB 2.0 */ +#define USB_PID_SPLIT			       0x78	/* USB 2.0 */ +#define USB_PID_IN			       0x69 +#define USB_PID_NAK			       0x5a +#define USB_PID_DATA1			       0x4b +#define USB_PID_PREAMBLE		       0x3c	/* Token mode */ +#define USB_PID_ERR			       0x3c	/* USB 2.0: handshake mode */ +#define USB_PID_SETUP			       0x2d +#define USB_PID_STALL			       0x1e +#define USB_PID_MDATA			       0x0f	/* USB 2.0 */ + +/* + * Standard requests + */ +#define USB_REQ_GET_STATUS		0x00 +#define USB_REQ_CLEAR_FEATURE		0x01 +#define USB_REQ_SET_FEATURE		0x03 +#define USB_REQ_SET_ADDRESS		0x05 +#define USB_REQ_GET_DESCRIPTOR		0x06 +#define USB_REQ_SET_DESCRIPTOR		0x07 +#define USB_REQ_GET_CONFIGURATION	0x08 +#define USB_REQ_SET_CONFIGURATION	0x09 +#define USB_REQ_GET_INTERFACE		0x0A +#define USB_REQ_SET_INTERFACE		0x0B +#define USB_REQ_SYNCH_FRAME		0x0C + +#define USBD_DEVICE_REQUESTS(x) (((unsigned int)x <= USB_REQ_SYNCH_FRAME) ? usbd_device_requests[x] : "UNKNOWN") + +/* + * HID requests + */ +#define USB_REQ_GET_REPORT		0x01 +#define USB_REQ_GET_IDLE		0x02 +#define USB_REQ_GET_PROTOCOL		0x03 +#define USB_REQ_SET_REPORT		0x09 +#define USB_REQ_SET_IDLE		0x0A +#define USB_REQ_SET_PROTOCOL		0x0B + + +/* + * USB Spec Release number + */ + +#define USB_BCD_VERSION			0x0110 + + +/* + * Device Requests	(c.f Table 9-2) + */ + +#define USB_REQ_DIRECTION_MASK		0x80 +#define USB_REQ_TYPE_MASK		0x60 +#define USB_REQ_RECIPIENT_MASK		0x1f + +#define USB_REQ_DEVICE2HOST		0x80 +#define USB_REQ_HOST2DEVICE		0x00 + +#define USB_REQ_TYPE_STANDARD		0x00 +#define USB_REQ_TYPE_CLASS		0x20 +#define USB_REQ_TYPE_VENDOR		0x40 + +#define USB_REQ_RECIPIENT_DEVICE	0x00 +#define USB_REQ_RECIPIENT_INTERFACE	0x01 +#define USB_REQ_RECIPIENT_ENDPOINT	0x02 +#define USB_REQ_RECIPIENT_OTHER		0x03 + +/* + * get status bits + */ + +#define USB_STATUS_SELFPOWERED		0x01 +#define USB_STATUS_REMOTEWAKEUP		0x02 + +#define USB_STATUS_HALT			0x01 + +/* + * descriptor types + */ + +#define USB_DESCRIPTOR_TYPE_DEVICE			0x01 +#define USB_DESCRIPTOR_TYPE_CONFIGURATION		0x02 +#define USB_DESCRIPTOR_TYPE_STRING			0x03 +#define USB_DESCRIPTOR_TYPE_INTERFACE			0x04 +#define USB_DESCRIPTOR_TYPE_ENDPOINT			0x05 +#define USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER		0x06 +#define USB_DESCRIPTOR_TYPE_OTHER_SPEED_CONFIGURATION	0x07 +#define USB_DESCRIPTOR_TYPE_INTERFACE_POWER		0x08 +#define USB_DESCRIPTOR_TYPE_HID				0x21 +#define USB_DESCRIPTOR_TYPE_REPORT			0x22 + +#define USBD_DEVICE_DESCRIPTORS(x) (((unsigned int)x <= USB_DESCRIPTOR_TYPE_INTERFACE_POWER) ? \ +		usbd_device_descriptors[x] : "UNKNOWN") + +/* + * standard feature selectors + */ +#define USB_ENDPOINT_HALT		0x00 +#define USB_DEVICE_REMOTE_WAKEUP	0x01 +#define USB_TEST_MODE			0x02 + + +/* USB Requests + * + */ + +struct usb_device_request { +	u8 bmRequestType; +	u8 bRequest; +	u16 wValue; +	u16 wIndex; +	u16 wLength; +} __attribute__ ((packed)); + + +/* USB Status + * + */ +typedef enum urb_send_status { +	SEND_IN_PROGRESS, +	SEND_FINISHED_OK, +	SEND_FINISHED_ERROR, +	RECV_READY, +	RECV_OK, +	RECV_ERROR +} urb_send_status_t; + +/* + * Device State (c.f USB Spec 2.0 Figure 9-1) + * + * What state the usb device is in. + * + * Note the state does not change if the device is suspended, we simply set a + * flag to show that it is suspended. + * + */ +typedef enum usb_device_state { +	STATE_INIT,		/* just initialized */ +	STATE_CREATED,		/* just created */ +	STATE_ATTACHED,		/* we are attached */ +	STATE_POWERED,		/* we have seen power indication (electrical bus signal) */ +	STATE_DEFAULT,		/* we been reset */ +	STATE_ADDRESSED,	/* we have been addressed (in default configuration) */ +	STATE_CONFIGURED,	/* we have seen a set configuration device command */ +	STATE_UNKNOWN,		/* destroyed */ +} usb_device_state_t; + +#define USBD_DEVICE_STATE(x) (((unsigned int)x <= STATE_UNKNOWN) ? usbd_device_states[x] : "UNKNOWN") + +/* + * Device status + * + * Overall state + */ +typedef enum usb_device_status { +	USBD_OPENING,		/* we are currently opening */ +	USBD_OK,		/* ok to use */ +	USBD_SUSPENDED,		/* we are currently suspended */ +	USBD_CLOSING,		/* we are currently closing */ +} usb_device_status_t; + +#define USBD_DEVICE_STATUS(x) (((unsigned int)x <= USBD_CLOSING) ? usbd_device_status[x] : "UNKNOWN") + +/* + * Device Events + * + * These are defined in the USB Spec (c.f USB Spec 2.0 Figure 9-1). + * + * There are additional events defined to handle some extra actions we need + * to have handled. + * + */ +typedef enum usb_device_event { + +	DEVICE_UNKNOWN,		/* bi - unknown event */ +	DEVICE_INIT,		/* bi  - initialize */ +	DEVICE_CREATE,		/* bi  - */ +	DEVICE_HUB_CONFIGURED,	/* bi  - bus has been plugged int */ +	DEVICE_RESET,		/* bi  - hub has powered our port */ + +	DEVICE_ADDRESS_ASSIGNED,	/* ep0 - set address setup received */ +	DEVICE_CONFIGURED,	/* ep0 - set configure setup received */ +	DEVICE_SET_INTERFACE,	/* ep0 - set interface setup received */ + +	DEVICE_SET_FEATURE,	/* ep0 - set feature setup received */ +	DEVICE_CLEAR_FEATURE,	/* ep0 - clear feature setup received */ + +	DEVICE_DE_CONFIGURED,	/* ep0 - set configure setup received for ?? */ + +	DEVICE_BUS_INACTIVE,	/* bi  - bus in inactive (no SOF packets) */ +	DEVICE_BUS_ACTIVITY,	/* bi  - bus is active again */ + +	DEVICE_POWER_INTERRUPTION,	/* bi  - hub has depowered our port */ +	DEVICE_HUB_RESET,	/* bi  - bus has been unplugged */ +	DEVICE_DESTROY,		/* bi  - device instance should be destroyed */ + +	DEVICE_HOTPLUG,		/* bi  - a hotplug event has occured */ + +	DEVICE_FUNCTION_PRIVATE,	/* function - private */ + +} usb_device_event_t; + + +typedef struct urb_link { +	struct urb_link *next; +	struct urb_link *prev; +} urb_link; + +/* USB Data structure - for passing data around. + * + * This is used for both sending and receiving data. + * + * The callback function is used to let the function driver know when + * transmitted data has been sent. + * + * The callback function is set by the alloc_recv function when an urb is + * allocated for receiving data for an endpoint and used to call the + * function driver to inform it that data has arrived. + */ + +#define URB_BUF_SIZE 128 /* in linux we'd malloc this, but in u-boot we prefer static data */ +struct urb { + +	struct usb_endpoint_instance *endpoint; +	struct usb_device_instance *device; + +	struct usb_device_request device_request;	/* contents of received SETUP packet */ + +	struct urb_link link;	/* embedded struct for circular doubly linked list of urbs */ + +	u8* buffer; +	unsigned int buffer_length; +	unsigned int actual_length; + +	urb_send_status_t status; +	int data; + +	u16 buffer_data[URB_BUF_SIZE];	/* data received (OUT) or being sent (IN) */ +}; + +/* Endpoint configuration + * + * Per endpoint configuration data. Used to track which function driver owns + * an endpoint. + * + */ +struct usb_endpoint_instance { +	int endpoint_address;	/* logical endpoint address */ + +	/* control */ +	int status;		/* halted */ +	int state;		/* available for use by bus interface driver */ + +	/* receive side */ +	struct urb_link rcv;	/* received urbs */ +	struct urb_link rdy;	/* empty urbs ready to receive */ +	struct urb *rcv_urb;	/* active urb */ +	int rcv_attributes;	/* copy of bmAttributes from endpoint descriptor */ +	int rcv_packetSize;	/* maximum packet size from endpoint descriptor */ +	int rcv_transferSize;	/* maximum transfer size from function driver */ +	int rcv_queue; + +	/* transmit side */ +	struct urb_link tx;	/* urbs ready to transmit */ +	struct urb_link done;	/* transmitted urbs */ +	struct urb *tx_urb;	/* active urb */ +	int tx_attributes;	/* copy of bmAttributes from endpoint descriptor */ +	int tx_packetSize;	/* maximum packet size from endpoint descriptor */ +	int tx_transferSize;	/* maximum transfer size from function driver */ +	int tx_queue; + +	int sent;		/* data already sent */ +	int last;		/* data sent in last packet XXX do we need this */ +}; + +struct usb_alternate_instance { +	struct usb_interface_descriptor *interface_descriptor; + +	int endpoints; +	int *endpoint_transfersize_array; +	struct usb_endpoint_descriptor **endpoints_descriptor_array; +}; + +struct usb_interface_instance { +	int alternates; +	struct usb_alternate_instance *alternates_instance_array; +}; + +struct usb_configuration_instance { +	int interfaces; +	struct usb_configuration_descriptor *configuration_descriptor; +	struct usb_interface_instance *interface_instance_array; +}; + + +/* USB Device Instance + * + * For each physical bus interface we create a logical device structure. This + * tracks all of the required state to track the USB HOST's view of the device. + * + * Keep track of the device configuration for a real physical bus interface, + * this includes the bus interface, multiple function drivers, the current + * configuration and the current state. + * + * This will show: + *	the specific bus interface driver + *	the default endpoint 0 driver + *	the configured function driver + *	device state + *	device status + *	endpoint list + */ + +struct usb_device_instance { + +	/* generic */ +	char *name; +	struct usb_device_descriptor *device_descriptor;	/* per device descriptor */ + +	void (*event) (struct usb_device_instance *device, usb_device_event_t event, int data); + +	/* bus interface */ +	struct usb_bus_instance *bus;	/* which bus interface driver */ + +	/* configuration descriptors */ +	int configurations; +	struct usb_configuration_instance *configuration_instance_array; + +	/* device state */ +	usb_device_state_t device_state;	/* current USB Device state */ +	usb_device_state_t device_previous_state;	/* current USB Device state */ + +	u8 address;		/* current address (zero is default) */ +	u8 configuration;	/* current show configuration (zero is default) */ +	u8 interface;		/* current interface (zero is default) */ +	u8 alternate;		/* alternate flag */ + +	usb_device_status_t status;	/* device status */ + +	int urbs_queued;	/* number of submitted urbs */ + +	/* Shouldn't need to make this atomic, all we need is a change indicator */ +	unsigned long usbd_rxtx_timestamp; +	unsigned long usbd_last_rxtx_timestamp; + +}; + +/* Bus Interface configuration structure + * + * This is allocated for each configured instance of a bus interface driver. + * + * The privdata pointer may be used by the bus interface driver to store private + * per instance state information. + */ +struct usb_bus_instance { + +	struct usb_device_instance *device; +	struct usb_endpoint_instance *endpoint_array;	/* array of available configured endpoints */ + +	int max_endpoints;	/* maximimum number of rx enpoints */ +	unsigned char			maxpacketsize; + +	unsigned int serial_number; +	char *serial_number_str; +	void *privdata;		/* private data for the bus interface */ + +}; + +extern char *usbd_device_events[]; +extern char *usbd_device_states[]; +extern char *usbd_device_status[]; +extern char *usbd_device_requests[]; +extern char *usbd_device_descriptors[]; + +void urb_link_init (urb_link * ul); +void urb_detach (struct urb *urb); +urb_link *first_urb_link (urb_link * hd); +struct urb *first_urb (urb_link * hd); +struct urb *first_urb_detached (urb_link * hd); +void urb_append (urb_link * hd, struct urb *urb); + +struct urb *usbd_alloc_urb (struct usb_device_instance *device, struct usb_endpoint_instance *endpoint); +void	    usbd_dealloc_urb (struct urb *urb); + +/* + * usbd_device_event is used by bus interface drivers to tell the higher layers that + * certain events have taken place. + */ +void usbd_device_event_irq (struct usb_device_instance *conf, usb_device_event_t, int); +void usbd_device_event (struct usb_device_instance *conf, usb_device_event_t, int); + +/* descriptors + * + * Various ways of finding descriptors based on the current device and any + * possible configuration / interface / endpoint for it. + */ +struct usb_configuration_descriptor *usbd_device_configuration_descriptor (struct usb_device_instance *, int, int); +struct usb_function_instance *usbd_device_function_instance (struct usb_device_instance *, unsigned int); +struct usb_interface_instance *usbd_device_interface_instance (struct usb_device_instance *, int, int, int); +struct usb_alternate_instance *usbd_device_alternate_instance (struct usb_device_instance *, int, int, int, int); +struct usb_interface_descriptor *usbd_device_interface_descriptor (struct usb_device_instance *, int, int, int, int); +struct usb_endpoint_descriptor *usbd_device_endpoint_descriptor_index (struct usb_device_instance *, int, int, int, int, int); +struct usb_class_descriptor *usbd_device_class_descriptor_index (struct usb_device_instance *, int, int, int, int, int); +struct usb_class_report_descriptor *usbd_device_class_report_descriptor_index( struct usb_device_instance *, int , int , int , int , int ); +struct usb_endpoint_descriptor *usbd_device_endpoint_descriptor (struct usb_device_instance *, int, int, int, int, int); +int				usbd_device_endpoint_transfersize (struct usb_device_instance *, int, int, int, int, int); +struct usb_string_descriptor *usbd_get_string (u8); +struct usb_device_descriptor *usbd_device_device_descriptor (struct usb_device_instance *, int); + +int usbd_endpoint_halted (struct usb_device_instance *device, int endpoint); +void usbd_rcv_complete(struct usb_endpoint_instance *endpoint, int len, int urb_bad); +void usbd_tx_complete (struct usb_endpoint_instance *endpoint); + +#endif diff --git a/include/usbdcore_ep0.h b/include/usbdcore_ep0.h new file mode 100644 index 000000000..3bec106a4 --- /dev/null +++ b/include/usbdcore_ep0.h @@ -0,0 +1,39 @@ +/* + * (C) Copyright 2003 + * Gerry Hamel, geh@ti.com, Texas Instruments + * + * Based on + * linux/drivers/usbd/ep0.c + * + * Copyright (c) 2000, 2001, 2002 Lineo + * Copyright (c) 2001 Hewlett Packard + * + * By: + *	Stuart Lynne <sl@lineo.com>, + *	Tom Rushworth <tbr@lineo.com>, + *	Bruce Balden <balden@lineo.com> + * + * 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. + * + */ + +#ifndef __USBDCORE_EP0_H__ +#define __USBDCORE_EP0_H__ + + +int ep0_recv_setup (struct urb *urb); + + +#endif diff --git a/include/usbdcore_omap1510.h b/include/usbdcore_omap1510.h new file mode 100644 index 000000000..6ea333122 --- /dev/null +++ b/include/usbdcore_omap1510.h @@ -0,0 +1,183 @@ +/* + * (C) Copyright 2003 + * Gerry Hamel, geh@ti.com, Texas Instruments + * + * Based on + * linux/drivers/usb/device/bi/omap.h + * Register definitions for TI OMAP1510 USB bus interface driver + * + * Author: MontaVista Software, Inc. + *	   source@mvista.com + * + * 2003 (c) MontaVista Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#ifndef __USBDCORE_OMAP1510_H__ +#define __USBDCORE_OMAP1510_H__ + + +/* + * 13.2 MPU Register Map + */ + +/* Table 13-1. USB Function Module Registers (endpoint) */ +#define UDC_BASE		     0xFFFB4000 +#define UDC_OFFSET(offset)	     (UDC_BASE + (offset)) +#define UDC_REV			     UDC_OFFSET(0x0)	/* Revision */ +#define UDC_EP_NUM		     UDC_OFFSET(0x4)	/* Endpoint selection */ +#define UDC_DATA		     UDC_OFFSET(0x08)	/* Data */ +#define UDC_CTRL		     UDC_OFFSET(0x0C)	/* Control */ +#define UDC_STAT_FLG		     UDC_OFFSET(0x10)	/* Status flag */ +#define UDC_RXFSTAT		     UDC_OFFSET(0x14)	/* Receive FIFO status */ +#define UDC_SYSCON1		     UDC_OFFSET(0x18)	/* System configuration 1 */ +#define UDC_SYSCON2		     UDC_OFFSET(0x1C)	/* System configuration 2 */ +#define UDC_DEVSTAT		     UDC_OFFSET(0x20)	/* Device status */ +#define UDC_SOF			     UDC_OFFSET(0x24)	/* Start of frame */ +#define UDC_IRQ_EN		     UDC_OFFSET(0x28)	/* Interrupt enable */ +#define UDC_DMA_IRQ_EN		     UDC_OFFSET(0x2C)	/* DMA interrupt enable */ +#define UDC_IRQ_SRC		     UDC_OFFSET(0x30)	/* Interrupt source */ +#define UDC_EPN_STAT		     UDC_OFFSET(0x34)	/* Endpoint interrupt status */ +#define UDC_DMAN_STAT		     UDC_OFFSET(0x3C)	/* DMA endpoint interrupt status */ + +/* IRQ_EN register fields */ +#define UDC_Sof_IE		     (1 << 7)	/* Start-of-frame interrupt enabled */ +#define UDC_EPn_RX_IE		     (1 << 5)	/* Receive endpoint interrupt enabled */ +#define UDC_EPn_TX_IE		     (1 << 4)	/* Transmit endpoint interrupt enabled */ +#define UDC_DS_Chg_IE		     (1 << 3)	/* Device state changed interrupt enabled */ +#define UDC_EP0_IE		     (1 << 0)	/* EP0 transaction interrupt enabled */ + +/* IRQ_SRC register fields */ +#define UDC_TXn_Done		     (1 << 10)	/* Transmit DMA channel n done */ +#define UDC_RXn_Cnt		     (1 << 9)	/* Receive DMA channel n transactions count */ +#define UDC_RXn_EOT		     (1 << 8)	/* Receive DMA channel n end of transfer */ +#define UDC_SOF_Flg		     (1 << 7)	/* Start-of-frame interrupt flag */ +#define UDC_EPn_RX		     (1 << 5)	/* Endpoint n OUT transaction */ +#define UDC_EPn_TX		     (1 << 4)	/* Endpoint n IN transaction */ +#define UDC_DS_Chg		     (1 << 3)	/* Device state changed */ +#define UDC_Setup		     (1 << 2)	/* Setup transaction */ +#define UDC_EP0_RX		     (1 << 1)	/* EP0 OUT transaction */ +#define UDC_EP0_TX		     (1 << 0)	/* EP0 IN transaction */ + +/* DEVSTAT register fields, 14.2.9 */ +#define UDC_R_WK_OK		     (1 << 6)	/* Remote wakeup granted */ +#define UDC_USB_Reset		     (1 << 5)	/* USB reset signalling is active */ +#define UDC_SUS			     (1 << 4)	/* Suspended state */ +#define UDC_CFG			     (1 << 3)	/* Configured state */ +#define UDC_ADD			     (1 << 2)	/* Addressed state */ +#define UDC_DEF			     (1 << 1)	/* Default state */ +#define UDC_ATT			     (1 << 0)	/* Attached state */ + +/* SYSCON1 register fields */ +#define UDC_Cfg_Lock		     (1 << 8)	/* Device configuration locked */ +#define UDC_Nak_En		     (1 << 4)	/* NAK enable */ +#define UDC_Self_Pwr		     (1 << 2)	/* Device is self-powered */ +#define UDC_Soff_Dis		     (1 << 1)	/* Shutoff disabled */ +#define UDC_Pullup_En		     (1 << 0)	/* External pullup enabled */ + +/* SYSCON2 register fields */ +#define UDC_Rmt_Wkp		     (1 << 6)	/* Remote wakeup */ +#define UDC_Stall_Cmd		     (1 << 5)	/* Stall endpoint */ +#define UDC_Dev_Cfg		     (1 << 3)	/* Device configured */ +#define UDC_Clr_Cfg		     (1 << 2)	/* Clear configured */ + +/* + * Select and enable endpoints + */ + +/* Table 13-1. USB Function Module Registers (endpoint configuration) */ +#define UDC_EPBASE		     UDC_OFFSET(0x80)	/* Endpoints base address */ +#define UDC_EP0			     UDC_EPBASE /* Control endpoint configuration */ +#define UDC_EP_RX_BASE		     UDC_OFFSET(0x84)	/* Receive endpoints base address */ +#define UDC_EP_RX(endpoint)	     (UDC_EP_RX_BASE + ((endpoint) - 1) * 4) +#define UDC_EP_TX_BASE		     UDC_OFFSET(0xC4)	/* Transmit endpoints base address */ +#define UDC_EP_TX(endpoint)	     (UDC_EP_TX_BASE + ((endpoint) - 1) * 4) + +/* EP_NUM register fields */ +#define UDC_Setup_Sel		     (1 << 6)	/* Setup FIFO select */ +#define UDC_EP_Sel		     (1 << 5)	/* TX/RX FIFO select */ +#define UDC_EP_Dir		     (1 << 4)	/* Endpoint direction */ + +/* CTRL register fields */ +#define UDC_Clr_Halt		     (1 << 7)	/* Clear halt endpoint */ +#define UDC_Set_Halt		     (1 << 6)	/* Set halt endpoint */ +#define UDC_Set_FIFO_En		     (1 << 2)	/* Set FIFO enable */ +#define UDC_Clr_EP		     (1 << 1)	/* Clear endpoint */ +#define UDC_Reset_EP		     (1 << 0)	/* Reset endpoint */ + +/* STAT_FLG register fields */ +#define UDC_Miss_In		     (1 << 14) +#define UDC_Data_Flush		     (1 << 13) +#define UDC_ISO_Err		     (1 << 12) +#define UDC_ISO_FIFO_Empty	     (1 << 9) +#define UDC_ISO_FIFO_Full	     (1 << 8) +#define UDC_EP_Halted		     (1 << 6) +#define UDC_STALL		     (1 << 5) +#define UDC_NAK			     (1 << 4) +#define UDC_ACK			     (1 << 3) +#define UDC_FIFO_En		     (1 << 2) +#define UDC_Non_ISO_FIFO_Empty	     (1 << 1) +#define UDC_Non_ISO_FIFO_Full	     (1 << 0) + +/* EPn_RX register fields */ +#define UDC_EPn_RX_Valid	     (1 << 15)	/* valid */ +#define UDC_EPn_RX_Db		     (1 << 14)	/* double-buffer */ +#define UDC_EPn_RX_Iso		     (1 << 11)	/* isochronous */ + +/* EPn_TX register fields */ +#define UDC_EPn_TX_Valid	     (1 << 15)	/* valid */ +#define UDC_EPn_TX_Db		     (1 << 14)	/* double-buffer */ +#define UDC_EPn_TX_Iso		     (1 << 11)	/* isochronous */ + +#define EP0_PACKETSIZE		     0x40 + +/* physical to logical endpoint mapping + * Physical endpoints are an index into device->bus->endpoint_array. + * Logical endpoints are endpoints 0 to 15 IN and OUT as defined in + * the USB specification. + * + *	physical ep	logical ep	direction	endpoint_address + *	0		0		IN and OUT	0x00 + *	1 to 15		1 to 15		OUT		0x01 to 0x0f + *	16 to 30	1 to 15		IN		0x81 to 0x8f + */ +#define PHYS_EP_TO_EP_ADDR(ep) (((ep) < 16) ? (ep) : (((ep) - 15) | 0x80)) +#define EP_ADDR_TO_PHYS_EP(a) (((a) & 0x80) ? (((a) & ~0x80) + 15) : (a)) + +/* MOD_CONF_CTRL_0 bits (FIXME: move to board hardware.h ?) */ +#define CONF_MOD_USB_W2FC_VBUS_MODE_R (1 << 17) + +/* Other registers (may be) related to USB */ + +#define CLOCK_CTRL	    (0xFFFE0830) +#define APLL_CTRL	    (0xFFFE084C) +#define DPLL_CTRL	    (0xFFFE083C) +#define SOFT_REQ	    (0xFFFE0834) +#define STATUS_REQ	    (0xFFFE0840) + +/* FUNC_MUX_CTRL_0 bits related to USB */ +#define UDC_VBUS_CTRL	    (1 << 19) +#define UDC_VBUS_MODE	    (1 << 18) + + +void omap1510_udc_irq(void); +void omap1510_udc_noniso_irq(void); + + +/* Higher level functions for abstracting away from specific device */ +void udc_endpoint_write(struct usb_endpoint_instance *endpoint); + +int  udc_init (void); + +void udc_enable(struct usb_device_instance *device); +void udc_disable(void); + +void udc_connect(void); +void udc_disconnect(void); + +void udc_startup_events(struct usb_device_instance *device); +void udc_setup_ep(struct usb_device_instance *device, unsigned int ep, struct usb_endpoint_instance *endpoint); + +#endif diff --git a/include/usbdescriptors.h b/include/usbdescriptors.h new file mode 100644 index 000000000..2d9f73934 --- /dev/null +++ b/include/usbdescriptors.h @@ -0,0 +1,497 @@ +/* + * (C) Copyright 2003 + * Gerry Hamel, geh@ti.com, Texas Instruments + * + * Based on + * linux/drivers/usbd/usb-function.h - USB Function + * + * Copyright (c) 2000, 2001, 2002 Lineo + * Copyright (c) 2001 Hewlett Packard + * + * By: + *	Stuart Lynne <sl@lineo.com>, + *	Tom Rushworth <tbr@lineo.com>, + *	Bruce Balden <balden@lineo.com> + * + * 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. + * + */ + +/* USB Descriptors - Create a complete description of all of the + * function driver capabilities. These map directly to the USB descriptors. + * + * This heirarchy is created by the functions drivers and is passed to the + * usb-device driver when the function driver is registered. + * + *  device + *	configuration + *	     interface + *		alternate + *		     class + *		     class + *		alternate + *		     endpoint + *		     endpoint + *	     interface + *		alternate + *		     endpoint + *		     endpoint + *	configuration + *	     interface + *		alternate + *		     endpoint + *		     endpoint + * + * + * The configuration structures refer to the USB Configurations that will be + * made available to a USB HOST during the enumeration process. + * + * The USB HOST will select a configuration and optionally an interface with + * the usb set configuration and set interface commands. + * + * The selected interface (or the default interface if not specifically + * selected) will define the list of endpoints that will be used. + * + * The configuration and interfaces are stored in an array that is indexed + * by the specified configuratin or interface number minus one. + * + * A configuration number of zero is used to specify a return to the unconfigured + * state. + * + */ + + +#ifndef __USBDESCRIPTORS_H__ +#define __USBDESCRIPTORS_H__ + +#include <asm/types.h> + +/* + * communications class types + * + * c.f. CDC  USB Class Definitions for Communications Devices + * c.f. WMCD USB CDC Subclass Specification for Wireless Mobile Communications Devices + * + */ + +#define CLASS_BCD_VERSION		0x0110 + +/* c.f. CDC 4.1 Table 14 */ +#define COMMUNICATIONS_DEVICE_CLASS	0x02 + +/* c.f. CDC 4.2 Table 15 */ +#define COMMUNICATIONS_INTERFACE_CLASS	0x02 + +/* c.f. CDC 4.3 Table 16 */ +#define COMMUNICATIONS_NO_SUBCLASS	0x00 +#define COMMUNICATIONS_DLCM_SUBCLASS	0x01 +#define COMMUNICATIONS_ACM_SUBCLASS	0x02 +#define COMMUNICATIONS_TCM_SUBCLASS	0x03 +#define COMMUNICATIONS_MCCM_SUBCLASS	0x04 +#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_MDLM_SUBCLASS	0x0a +#define COMMUNICATIONS_OBEX_SUBCLASS	0x0b + +/* c.f. CDC 4.6 Table 18 */ +#define DATA_INTERFACE_CLASS		0x0a + +/* c.f. CDC 4.7 Table 19 */ +#define COMMUNICATIONS_NO_PROTOCOL	0x00 + + +/* c.f. CDC 5.2.3 Table 24 */ +#define CS_INTERFACE			0x24 +#define CS_ENDPOINT			0x25 + +/* + * bDescriptorSubtypes + * + * c.f. CDC 5.2.3 Table 25 + * c.f. WMCD 5.3 Table 5.3 + */ + +#define USB_ST_HEADER			0x00 +#define USB_ST_CMF			0x01 +#define USB_ST_ACMF			0x02 +#define USB_ST_DLMF			0x03 +#define USB_ST_TRF			0x04 +#define USB_ST_TCLF			0x05 +#define USB_ST_UF			0x06 +#define USB_ST_CSF			0x07 +#define USB_ST_TOMF			0x08 +#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_WHCM			0x11 +#define USB_ST_MDLM			0x12 +#define USB_ST_MDLMD			0x13 +#define USB_ST_DMM			0x14 +#define USB_ST_OBEX			0x15 +#define USB_ST_CS			0x16 +#define USB_ST_CSD			0x17 +#define USB_ST_TCM			0x18 + +/* endpoint modifiers + * static struct usb_endpoint_description function_default_A_1[] = { + * + *     {this_endpoint: 0, attributes: CONTROL,	 max_size: 8,  polling_interval: 0 }, + *     {this_endpoint: 1, attributes: BULK,	 max_size: 64, polling_interval: 0, direction: IN}, + *     {this_endpoint: 2, attributes: BULK,	 max_size: 64, polling_interval: 0, direction: OUT}, + *     {this_endpoint: 3, attributes: INTERRUPT, max_size: 8,  polling_interval: 0}, + * + * + */ +#define OUT		0x00 +#define IN		0x80 + +#define CONTROL		0x00 +#define ISOCHRONOUS	0x01 +#define BULK		0x02 +#define INTERRUPT	0x03 + + +/* configuration modifiers + */ +#define BMATTRIBUTE_RESERVED		0x80 +#define BMATTRIBUTE_SELF_POWERED	0x40 + +/* + * standard usb descriptor structures + */ + +struct usb_endpoint_descriptor { +	u8 bLength; +	u8 bDescriptorType;	/* 0x5 */ +	u8 bEndpointAddress; +	u8 bmAttributes; +	u16 wMaxPacketSize; +	u8 bInterval; +} __attribute__ ((packed)); + +struct usb_interface_descriptor { +	u8 bLength; +	u8 bDescriptorType;	/* 0x04 */ +	u8 bInterfaceNumber; +	u8 bAlternateSetting; +	u8 bNumEndpoints; +	u8 bInterfaceClass; +	u8 bInterfaceSubClass; +	u8 bInterfaceProtocol; +	u8 iInterface; +} __attribute__ ((packed)); + +struct usb_configuration_descriptor { +	u8 bLength; +	u8 bDescriptorType;	/* 0x2 */ +	u16 wTotalLength; +	u8 bNumInterfaces; +	u8 bConfigurationValue; +	u8 iConfiguration; +	u8 bmAttributes; +	u8 bMaxPower; +} __attribute__ ((packed)); + +struct usb_device_descriptor { +	u8 bLength; +	u8 bDescriptorType;	/* 0x01 */ +	u16 bcdUSB; +	u8 bDeviceClass; +	u8 bDeviceSubClass; +	u8 bDeviceProtocol; +	u8 bMaxPacketSize0; +	u16 idVendor; +	u16 idProduct; +	u16 bcdDevice; +	u8 iManufacturer; +	u8 iProduct; +	u8 iSerialNumber; +	u8 bNumConfigurations; +} __attribute__ ((packed)); + +struct usb_string_descriptor { +	u8 bLength; +	u8 bDescriptorType;	/* 0x03 */ +	u16 wData[0]; +} __attribute__ ((packed)); + +struct usb_generic_descriptor { +	u8 bLength; +	u8 bDescriptorType; +	u8 bDescriptorSubtype; +} __attribute__ ((packed)); + + +/* + * communications class descriptor structures + * + * c.f. CDC 5.2 Table 25c + */ + +struct usb_class_function_descriptor { +	u8 bFunctionLength; +	u8 bDescriptorType; +	u8 bDescriptorSubtype; +} __attribute__ ((packed)); + +struct usb_class_function_descriptor_generic { +	u8 bFunctionLength; +	u8 bDescriptorType; +	u8 bDescriptorSubtype; +	u8 bmCapabilities; +} __attribute__ ((packed)); + +struct usb_class_header_function_descriptor { +	u8 bFunctionLength; +	u8 bDescriptorType; +	u8 bDescriptorSubtype;	/* 0x00 */ +	u16 bcdCDC; +} __attribute__ ((packed)); + +struct usb_class_call_management_descriptor { +	u8 bFunctionLength; +	u8 bDescriptorType; +	u8 bDescriptorSubtype;	/* 0x01 */ +	u8 bmCapabilities; +	u8 bDataInterface; +} __attribute__ ((packed)); + +struct usb_class_abstract_control_descriptor { +	u8 bFunctionLength; +	u8 bDescriptorType; +	u8 bDescriptorSubtype;	/* 0x02 */ +	u8 bmCapabilities; +} __attribute__ ((packed)); + +struct usb_class_direct_line_descriptor { +	u8 bFunctionLength; +	u8 bDescriptorType; +	u8 bDescriptorSubtype;	/* 0x03 */ +} __attribute__ ((packed)); + +struct usb_class_telephone_ringer_descriptor { +	u8 bFunctionLength; +	u8 bDescriptorType; +	u8 bDescriptorSubtype;	/* 0x04 */ +	u8 bRingerVolSeps; +	u8 bNumRingerPatterns; +} __attribute__ ((packed)); + +struct usb_class_telephone_call_descriptor { +	u8 bFunctionLength; +	u8 bDescriptorType; +	u8 bDescriptorSubtype;	/* 0x05 */ +	u8 bmCapabilities; +} __attribute__ ((packed)); + +struct usb_class_union_function_descriptor { +	u8 bFunctionLength; +	u8 bDescriptorType; +	u8 bDescriptorSubtype;	/* 0x06 */ +	u8 bMasterInterface; +	u8 bSlaveInterface0[0]; +} __attribute__ ((packed)); + +struct usb_class_country_selection_descriptor { +	u8 bFunctionLength; +	u8 bDescriptorType; +	u8 bDescriptorSubtype;	/* 0x07 */ +	u8 iCountryCodeRelDate; +	u16 wCountryCode0[0]; +} __attribute__ ((packed)); + + +struct usb_class_telephone_operational_descriptor { +	u8 bFunctionLength; +	u8 bDescriptorType; +	u8 bDescriptorSubtype;	/* 0x08 */ +	u8 bmCapabilities; +} __attribute__ ((packed)); + + +struct usb_class_usb_terminal_descriptor { +	u8 bFunctionLength; +	u8 bDescriptorType; +	u8 bDescriptorSubtype;	/* 0x09 */ +	u8 bEntityId; +	u8 bInterfaceNo; +	u8 bOutInterfaceNo; +	u8 bmOptions; +	u8 bChild0[0]; +} __attribute__ ((packed)); + +struct usb_class_network_channel_descriptor { +	u8 bFunctionLength; +	u8 bDescriptorType; +	u8 bDescriptorSubtype;	/* 0x0a */ +	u8 bEntityId; +	u8 iName; +	u8 bChannelIndex; +	u8 bPhysicalInterface; +} __attribute__ ((packed)); + +struct usb_class_protocol_unit_function_descriptor { +	u8 bFunctionLength; +	u8 bDescriptorType; +	u8 bDescriptorSubtype;	/* 0x0b */ +	u8 bEntityId; +	u8 bProtocol; +	u8 bChild0[0]; +} __attribute__ ((packed)); + +struct usb_class_extension_unit_descriptor { +	u8 bFunctionLength; +	u8 bDescriptorType; +	u8 bDescriptorSubtype;	/* 0x0c */ +	u8 bEntityId; +	u8 bExtensionCode; +	u8 iName; +	u8 bChild0[0]; +} __attribute__ ((packed)); + +struct usb_class_multi_channel_descriptor { +	u8 bFunctionLength; +	u8 bDescriptorType; +	u8 bDescriptorSubtype;	/* 0x0d */ +	u8 bmCapabilities; +} __attribute__ ((packed)); + +struct usb_class_capi_control_descriptor { +	u8 bFunctionLength; +	u8 bDescriptorType; +	u8 bDescriptorSubtype;	/* 0x0e */ +	u8 bmCapabilities; +} __attribute__ ((packed)); + +struct usb_class_ethernet_networking_descriptor { +	u8 bFunctionLength; +	u8 bDescriptorType; +	u8 bDescriptorSubtype;	/* 0x0f */ +	u8 iMACAddress; +	u32 bmEthernetStatistics; +	u16 wMaxSegmentSize; +	u16 wNumberMCFilters; +	u8 bNumberPowerFilters; +} __attribute__ ((packed)); + +struct usb_class_atm_networking_descriptor { +	u8 bFunctionLength; +	u8 bDescriptorType; +	u8 bDescriptorSubtype;	/* 0x10 */ +	u8 iEndSystermIdentifier; +	u8 bmDataCapabilities; +	u8 bmATMDeviceStatistics; +	u16 wType2MaxSegmentSize; +	u16 wType3MaxSegmentSize; +	u16 wMaxVC; +} __attribute__ ((packed)); + + +struct usb_class_mdlm_descriptor { +	u8 bFunctionLength; +	u8 bDescriptorType; +	u8 bDescriptorSubtype;	/* 0x12 */ +	u16 bcdVersion; +	u8 bGUID[16]; +} __attribute__ ((packed)); + +struct usb_class_mdlmd_descriptor { +	u8 bFunctionLength; +	u8 bDescriptorType; +	u8 bDescriptorSubtype;	/* 0x13 */ +	u8 bGuidDescriptorType; +	u8 bDetailData[0]; + +} __attribute__ ((packed)); + +/* + * HID class descriptor structures + * + * c.f. HID 6.2.1 + */ + +struct usb_class_hid_descriptor { +    u8	      bLength; +    u8	      bDescriptorType; +    u16	      bcdCDC; +    u8	      bCountryCode; +    u8	      bNumDescriptors;	/* 0x01 */ +    u8	      bDescriptorType0; +    u16	      wDescriptorLength0; +    /* optional descriptors are not supported. */ +} __attribute__((packed)); + +struct usb_class_report_descriptor { +    u8	      bLength;	/* dummy */ +    u8	      bDescriptorType; +    u16	      wLength; +    u8		bData[0]; +} __attribute__((packed)); + +/* + * descriptor union structures + */ + +struct usb_descriptor { +	union { +		struct usb_generic_descriptor generic; +		struct usb_endpoint_descriptor endpoint; +		struct usb_interface_descriptor interface; +		struct usb_configuration_descriptor configuration; +		struct usb_device_descriptor device; +		struct usb_string_descriptor string; +	} descriptor; + +} __attribute__ ((packed)); + +struct usb_class_descriptor { +	union { +		struct usb_class_function_descriptor function; +		struct usb_class_function_descriptor_generic generic; +		struct usb_class_header_function_descriptor header_function; +		struct usb_class_call_management_descriptor call_management; +		struct usb_class_abstract_control_descriptor abstract_control; +		struct usb_class_direct_line_descriptor direct_line; +		struct usb_class_telephone_ringer_descriptor telephone_ringer; +		struct usb_class_telephone_operational_descriptor telephone_operational; +		struct usb_class_telephone_call_descriptor telephone_call; +		struct usb_class_union_function_descriptor union_function; +		struct usb_class_country_selection_descriptor country_selection; +		struct usb_class_usb_terminal_descriptor usb_terminal; +		struct usb_class_network_channel_descriptor network_channel; +		struct usb_class_extension_unit_descriptor extension_unit; +		struct usb_class_multi_channel_descriptor multi_channel; +		struct usb_class_capi_control_descriptor capi_control; +		struct usb_class_ethernet_networking_descriptor ethernet_networking; +		struct usb_class_atm_networking_descriptor atm_networking; +		struct usb_class_mdlm_descriptor mobile_direct; +		struct usb_class_mdlmd_descriptor mobile_direct_detail; +		struct usb_class_hid_descriptor hid; +	} descriptor; + +} __attribute__ ((packed)); + +#endif diff --git a/lib_arm/armlinux.c b/lib_arm/armlinux.c index 8ba9f0c79..8ace06275 100644 --- a/lib_arm/armlinux.c +++ b/lib_arm/armlinux.c @@ -12,12 +12,12 @@   *   * 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   * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307	 USA   *   */ @@ -256,6 +256,13 @@ void do_bootm_linux (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],  	/* we assume that the kernel is in place */  	printf ("\nStarting kernel ...\n\n"); +#ifdef CONFIG_USB_DEVICE +	{ +		extern void udc_disconnect (void); +		udc_disconnect (); +	} +#endif +  	cleanup_before_linux ();  	theKernel (0, bd->bi_arch_number, bd->bi_boot_params); diff --git a/net/bootp.c b/net/bootp.c index e02372cb2..f5adce4f5 100644 --- a/net/bootp.c +++ b/net/bootp.c @@ -5,12 +5,12 @@   *	(See License)   *	Copyright 2000 Roland Borde   *	Copyright 2000 Paolo Scaffardi - *	Copyright 2000-2002 Wolfgang Denk, wd@denx.de + *	Copyright 2000-2004 Wolfgang Denk, wd@denx.de   */  #if 0 -#define	DEBUG		1	/* general debug */ -#define DEBUG_BOOTP_EXT	1	/* Debug received vendor fields	*/ +#define DEBUG		1	/* general debug */ +#define DEBUG_BOOTP_EXT 1	/* Debug received vendor fields */  #endif  #ifdef DEBUG_BOOTP_EXT @@ -24,26 +24,27 @@  #include <net.h>  #include "bootp.h"  #include "tftp.h" +#include "nfs.h"  #ifdef CONFIG_STATUS_LED  #include <status_led.h>  #endif -#define	BOOTP_VENDOR_MAGIC	0x63825363 	/* RFC1048 Magic Cookie 	*/ +#define BOOTP_VENDOR_MAGIC	0x63825363	/* RFC1048 Magic Cookie		*/  #if (CONFIG_COMMANDS & CFG_CMD_NET)  #define TIMEOUT		5		/* Seconds before trying BOOTP again	*/ -#ifndef	CONFIG_NET_RETRY_COUNT +#ifndef CONFIG_NET_RETRY_COUNT  # define TIMEOUT_COUNT	5		/* # of timeouts before giving up  */  #else -# define TIMEOUT_COUNT  (CONFIG_NET_RETRY_COUNT) +# define TIMEOUT_COUNT	(CONFIG_NET_RETRY_COUNT)  #endif  #define PORT_BOOTPS	67		/* BOOTP server UDP port		*/  #define PORT_BOOTPC	68		/* BOOTP client UDP port		*/  #ifndef CONFIG_DHCP_MIN_EXT_LEN		/* minimal length of extension list	*/ -#define	CONFIG_DHCP_MIN_EXT_LEN	64 +#define CONFIG_DHCP_MIN_EXT_LEN 64  #endif  ulong		BootpID; @@ -63,13 +64,13 @@ static void DhcpHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len);  static char *dhcpmsg2str(int type)  {  	switch (type) { -	case 1:  return "DHCPDISCOVER";	break; -	case 2:  return "DHCPOFFER";	break; -	case 3:  return "DHCPREQUEST";	break; -	case 4:  return "DHCPDECLINE";	break; -	case 5:  return "DHCPACK";	break; -	case 6:  return "DHCPNACK";	break; -	case 7:  return "DHCPRELEASE";	break; +	case 1:	 return "DHCPDISCOVER"; break; +	case 2:	 return "DHCPOFFER";	break; +	case 3:	 return "DHCPREQUEST";	break; +	case 4:	 return "DHCPDECLINE";	break; +	case 5:	 return "DHCPACK";	break; +	case 6:	 return "DHCPNACK";	break; +	case 7:	 return "DHCPRELEASE";	break;  	default: return "UNKNOWN/INVALID MSG TYPE"; break;  	}  } @@ -144,159 +145,158 @@ static int truncate_sz (const char *name, int maxlen, int curlen)  #if !(CONFIG_COMMANDS & CFG_CMD_DHCP) -static void BootpVendorFieldProcess(u8 *ext) +static void BootpVendorFieldProcess (u8 * ext)  { -    int size = *(ext+1) ; +	int size = *(ext + 1); -    debug_ext ("[BOOTP] Processing extension %d... (%d bytes)\n", *ext, *(ext+1)); +	debug_ext ("[BOOTP] Processing extension %d... (%d bytes)\n", *ext, +		   *(ext + 1)); -    NetBootFileSize = 0; +	NetBootFileSize = 0; -    switch (*ext) { -    /* Fixed length fields */ -	case 1:		/* Subnet mask					*/ +	switch (*ext) { +		/* Fixed length fields */ +	case 1:			/* Subnet mask                                  */  		if (NetOurSubnetMask == 0) -			NetCopyIP(&NetOurSubnetMask, (IPaddr_t*)(ext+2)); +			NetCopyIP (&NetOurSubnetMask, (IPaddr_t *) (ext + 2));  		break; -	case 2:		/* Time offset - Not yet supported		*/ +	case 2:			/* Time offset - Not yet supported              */  		break; -    /* Variable length fields */ -	case 3:		/* Gateways list				*/ +		/* Variable length fields */ +	case 3:			/* Gateways list                                */  		if (NetOurGatewayIP == 0) { -			NetCopyIP(&NetOurGatewayIP, (IPaddr_t*)(ext+2)); +			NetCopyIP (&NetOurGatewayIP, (IPaddr_t *) (ext + 2));  		}  		break; -	case 4:		/* Time server - Not yet supported		*/ +	case 4:			/* Time server - Not yet supported              */  		break; -	case 5:		/* IEN-116 name server - Not yet supported	*/ +	case 5:			/* IEN-116 name server - Not yet supported      */  		break;  	case 6:  		if (NetOurDNSIP == 0) { -			NetCopyIP(&NetOurDNSIP, (IPaddr_t*)(ext+2)); +			NetCopyIP (&NetOurDNSIP, (IPaddr_t *) (ext + 2));  		}  #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_DNS2)  		if ((NetOurDNS2IP == 0) && (size > 4)) { -			NetCopyIP(&NetOurDNS2IP, (IPaddr_t*)(ext+2+4)); +			NetCopyIP (&NetOurDNS2IP, (IPaddr_t *) (ext + 2 + 4));  		}  #endif  		break; -	case 7:		/* Log server - Not yet supported		*/ +	case 7:			/* Log server - Not yet supported               */  		break; -	case 8:		/* Cookie/Quote server - Not yet supported	*/ +	case 8:			/* Cookie/Quote server - Not yet supported      */  		break; -	case 9:		/* LPR server - Not yet supported		*/ +	case 9:			/* LPR server - Not yet supported               */  		break; -	case 10:	/* Impress server - Not yet supported		*/ +	case 10:		/* Impress server - Not yet supported           */  		break; -	case 11:	/* RPL server - Not yet supported		*/ +	case 11:		/* RPL server - Not yet supported               */  		break; -	case 12:	/* Host name					*/ +	case 12:		/* Host name                                    */  		if (NetOurHostName[0] == 0) { -		    size = truncate_sz("Host Name", sizeof(NetOurHostName), size); -		    memcpy(&NetOurHostName, ext+2, size); -		    NetOurHostName[size] = 0 ; +			size = truncate_sz ("Host Name", sizeof (NetOurHostName), size); +			memcpy (&NetOurHostName, ext + 2, size); +			NetOurHostName[size] = 0;  		}  		break; -	case 13:	/* Boot file size				*/ +	case 13:		/* Boot file size                               */  		if (size == 2) -			NetBootFileSize = ntohs(*(ushort*)(ext+2)); +			NetBootFileSize = ntohs (*(ushort *) (ext + 2));  		else if (size == 4) -			NetBootFileSize = ntohl(*(ulong*)(ext+2)); +			NetBootFileSize = ntohl (*(ulong *) (ext + 2));  		break; -	case 14:	/* Merit dump file - Not yet supported		*/ +	case 14:		/* Merit dump file - Not yet supported          */  		break; -	case 15:	/* Domain name - Not yet supported		*/ +	case 15:		/* Domain name - Not yet supported              */  		break; -	case 16:	/* Swap server - Not yet supported		*/ +	case 16:		/* Swap server - Not yet supported              */  		break; -	case 17:	/* Root path					*/ +	case 17:		/* Root path                                    */  		if (NetOurRootPath[0] == 0) { -		    size = truncate_sz("Root Path", sizeof(NetOurRootPath), size); -		    memcpy(&NetOurRootPath, ext+2, size); -		    NetOurRootPath[size] = 0 ; +			size = truncate_sz ("Root Path", sizeof (NetOurRootPath), size); +			memcpy (&NetOurRootPath, ext + 2, size); +			NetOurRootPath[size] = 0;  		}  		break; -	case 18:	/* Extension path - Not yet supported		*/ +	case 18:		/* Extension path - Not yet supported           */  		/*  		 * This can be used to send the information of the  		 * vendor area in another file that the client can  		 * access via TFTP.  		 */  		break; -    /* IP host layer fields */ -	case 40:	/* NIS Domain name				*/ +		/* IP host layer fields */ +	case 40:		/* NIS Domain name                              */  		if (NetOurNISDomain[0] == 0) { -		    size = truncate_sz ("NIS Domain Name", -					sizeof(NetOurNISDomain), -					size); -		    memcpy(&NetOurNISDomain, ext+2, size); -		    NetOurNISDomain[size] = 0 ; +			size = truncate_sz ("NIS Domain Name", sizeof (NetOurNISDomain), size); +			memcpy (&NetOurNISDomain, ext + 2, size); +			NetOurNISDomain[size] = 0;  		}  		break; -    /* Application layer fields */ -	case 43:	/* Vendor specific info - Not yet supported	*/ +		/* Application layer fields */ +	case 43:		/* Vendor specific info - Not yet supported     */  		/*  		 * Binary information to exchange specific  		 * product information.  		 */  		break; -    /* Reserved (custom) fields (128..254) */ -    } +		/* Reserved (custom) fields (128..254) */ +	}  } -static void BootpVendorProcess(u8 *ext, int size) +static void BootpVendorProcess (u8 * ext, int size)  { -    u8 *end = ext + size ; +	u8 *end = ext + size; -    debug_ext ("[BOOTP] Checking extension (%d bytes)...\n", size); +	debug_ext ("[BOOTP] Checking extension (%d bytes)...\n", size); -    while ((ext < end) && (*ext != 0xff)) { -	if (*ext == 0) { -	    ext ++ ; -	} else { -		u8 *opt = ext ; -		ext += ext[1] + 2 ; -		if (ext <= end) -		    BootpVendorFieldProcess (opt) ; +	while ((ext < end) && (*ext != 0xff)) { +		if (*ext == 0) { +			ext++; +		} else { +			u8 *opt = ext; + +			ext += ext[1] + 2; +			if (ext <= end) +				BootpVendorFieldProcess (opt); +		}  	} -    }  #ifdef DEBUG_BOOTP_EXT -    printf("[BOOTP] Received fields: \n"); -    if (NetOurSubnetMask) { -	puts ("NetOurSubnetMask	: "); -	print_IPaddr (NetOurSubnetMask); -	putc('\n'); -    } +	printf ("[BOOTP] Received fields: \n"); +	if (NetOurSubnetMask) { +		puts ("NetOurSubnetMask : "); +		print_IPaddr (NetOurSubnetMask); +		putc ('\n'); +	} -    if (NetOurGatewayIP) { -	puts ("NetOurGatewayIP	: "); -	print_IPaddr (NetOurGatewayIP); -	putc('\n'); -    } +	if (NetOurGatewayIP) { +		puts ("NetOurGatewayIP	: "); +		print_IPaddr (NetOurGatewayIP); +		putc ('\n'); +	} -    if (NetBootFileSize) { -	printf("NetBootFileSize : %d\n", NetBootFileSize); -    } +	if (NetBootFileSize) { +		printf ("NetBootFileSize : %d\n", NetBootFileSize); +	} -    if (NetOurHostName[0]) { -	printf("NetOurHostName  : %s\n", NetOurHostName); -    } +	if (NetOurHostName[0]) { +		printf ("NetOurHostName  : %s\n", NetOurHostName); +	} -    if (NetOurRootPath[0]) { -	printf("NetOurRootPath  : %s\n", NetOurRootPath); -    } +	if (NetOurRootPath[0]) { +		printf ("NetOurRootPath  : %s\n", NetOurRootPath); +	} -    if (NetOurNISDomain[0]) { -	printf("NetOurNISDomain : %s\n", NetOurNISDomain); -    } +	if (NetOurNISDomain[0]) { +		printf ("NetOurNISDomain : %s\n", NetOurNISDomain); +	} -    if (NetBootFileSize) { -	printf("NetBootFileSize: %d\n", NetBootFileSize); -    } -#endif	/* DEBUG_BOOTP_EXT */ +	if (NetBootFileSize) { +		printf ("NetBootFileSize: %d\n", NetBootFileSize); +	} +#endif /* DEBUG_BOOTP_EXT */  } -  /*   *	Handle a BOOTP received packet.   */ @@ -311,11 +311,11 @@ BootpHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len)  	bp = (Bootp_t *)pkt; -	if (BootpCheckPkt(pkt, dest, src, len))	/* Filter out pkts we don't want */ +	if (BootpCheckPkt(pkt, dest, src, len)) /* Filter out pkts we don't want */  		return;  	/* -	 *	Got a good BOOTP reply.  Copy the data into our variables. +	 *	Got a good BOOTP reply.	 Copy the data into our variables.  	 */  #ifdef CONFIG_STATUS_LED  	status_led_set (STATUS_LED_BOOT, STATUS_LED_OFF); @@ -371,179 +371,180 @@ BootpTimeout(void)   *	Initialize BOOTP extension fields in the request.   */  #if (CONFIG_COMMANDS & CFG_CMD_DHCP) -static int DhcpExtended(u8 *e, int message_type, IPaddr_t ServerID, IPaddr_t RequestedIP) +static int DhcpExtended (u8 * e, int message_type, IPaddr_t ServerID, IPaddr_t RequestedIP)  { -    u8 *start = e ; -    u8 *cnt; +	u8 *start = e; +	u8 *cnt; +  #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_VENDOREX) -    u8 *x; +	u8 *x;  #endif  #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_SEND_HOSTNAME) -    uchar *hostname; +	uchar *hostname;  #endif -    *e++ =  99;		/* RFC1048 Magic Cookie */ -    *e++ = 130; -    *e++ =  83; -    *e++ =  99; +	*e++ = 99;		/* RFC1048 Magic Cookie */ +	*e++ = 130; +	*e++ = 83; +	*e++ = 99; -    *e++ = 53;		/* DHCP Message Type */ -    *e++ = 1; -    *e++ = message_type; +	*e++ = 53;		/* DHCP Message Type */ +	*e++ = 1; +	*e++ = message_type; -    *e++ = 57;		/* Maximum DHCP Message Size */ -    *e++ = 2; -    *e++ = (576-312+OPT_SIZE) >> 8; -    *e++ = (576-312+OPT_SIZE) & 0xff; +	*e++ = 57;		/* Maximum DHCP Message Size */ +	*e++ = 2; +	*e++ = (576 - 312 + OPT_SIZE) >> 8; +	*e++ = (576 - 312 + OPT_SIZE) & 0xff; -    if ( ServerID ) { -	    int tmp = ntohl(ServerID); +	if (ServerID) { +		int tmp = ntohl (ServerID); -	    *e++ = 54;	/* ServerID */ -	    *e++ = 4; -	    *e++ = tmp >> 24; -	    *e++ = tmp >> 16; -	    *e++ = tmp >> 8; -	    *e++ = tmp & 0xff; -    } - -    if ( RequestedIP ) { -	    int tmp = ntohl(RequestedIP); +		*e++ = 54;	/* ServerID */ +		*e++ = 4; +		*e++ = tmp >> 24; +		*e++ = tmp >> 16; +		*e++ = tmp >> 8; +		*e++ = tmp & 0xff; +	} -	    *e++ = 50;	/* Requested IP */ -	    *e++ = 4; -	    *e++ = tmp >> 24; -	    *e++ = tmp >> 16; -	    *e++ = tmp >> 8; -	    *e++ = tmp & 0xff; -    } +	if (RequestedIP) { +		int tmp = ntohl (RequestedIP); +		*e++ = 50;	/* Requested IP */ +		*e++ = 4; +		*e++ = tmp >> 24; +		*e++ = tmp >> 16; +		*e++ = tmp >> 8; +		*e++ = tmp & 0xff; +	}  #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_SEND_HOSTNAME) -    if ( (hostname = getenv("hostname")) ) { -	    int hostnamelen = strlen(hostname); -	    *e++ = 12;        /* Hostname */ -	    *e++ = hostnamelen; -	    memcpy(e,hostname,hostnamelen); -	    e += hostnamelen; -    } +	if ((hostname = getenv ("hostname"))) { +		int hostnamelen = strlen (hostname); + +		*e++ = 12;	/* Hostname */ +		*e++ = hostnamelen; +		memcpy (e, hostname, hostnamelen); +		e += hostnamelen; +	}  #endif  #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_VENDOREX) -    if ((x = dhcp_vendorex_prep (e))) -	return x - start ; +	if ((x = dhcp_vendorex_prep (e))) +		return x - start;  #endif -    *e++ = 55;		/* Parameter Request List */ -    cnt  = e++;		/* Pointer to count of requested items */ -    *cnt = 0; +	*e++ = 55;		/* Parameter Request List */ +	 cnt = e++;		/* Pointer to count of requested items */ +	*cnt = 0;  #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_SUBNETMASK) -    *e++ = 1;		/* Subnet Mask */ -    *cnt += 1; +	*e++  = 1;		/* Subnet Mask */ +	*cnt += 1;  #endif  #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_GATEWAY) -    *e++ = 3;		/* Router Option */ -    *cnt += 1; +	*e++  = 3;		/* Router Option */ +	*cnt += 1;  #endif  #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_DNS) -    *e++ = 6;		/* DNS Server(s) */ -    *cnt += 1; +	*e++  = 6;		/* DNS Server(s) */ +	*cnt += 1;  #endif  #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_HOSTNAME) -    *e++ = 12;		/* Hostname */ -    *cnt += 1; +	*e++  = 12;		/* Hostname */ +	*cnt += 1;  #endif  #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_BOOTFILESIZE) -    *e++ = 13;		/* Boot File Size */ -    *cnt += 1; +	*e++  = 13;		/* Boot File Size */ +	*cnt += 1;  #endif  #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_BOOTPATH) -    *e++ = 17;		/* Boot path */ -    *cnt += 1; +	*e++  = 17;		/* Boot path */ +	*cnt += 1;  #endif  #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_NISDOMAIN) -    *e++ = 40;		/* NIS Domain name request */ -    *cnt += 1; +	*e++  = 40;		/* NIS Domain name request */ +	*cnt += 1;  #endif -    *e++ = 255;		/* End of the list */ +	*e++  = 255;		/* End of the list */ -    /* Pad to minimal length */ +	/* Pad to minimal length */  #ifdef	CONFIG_DHCP_MIN_EXT_LEN -    while ((e - start) <= CONFIG_DHCP_MIN_EXT_LEN) -	*e++ = 0; +	while ((e - start) <= CONFIG_DHCP_MIN_EXT_LEN) +		*e++ = 0;  #endif -    return e - start ; +	return e - start;  }  #else	/* CFG_CMD_DHCP */  /*   *	Warning: no field size check - change CONFIG_BOOTP_MASK at your own risk!   */ -static int BootpExtended (u8 *e) +static int BootpExtended (u8 * e)  { -    u8 *start = e ; +	u8 *start = e; -    *e++ =  99;		/* RFC1048 Magic Cookie */ -    *e++ = 130; -    *e++ =  83; -    *e++ =  99; +	*e++ = 99;		/* RFC1048 Magic Cookie */ +	*e++ = 130; +	*e++ = 83; +	*e++ = 99;  #if (CONFIG_COMMANDS & CFG_CMD_DHCP) -    *e++ = 53;		/* DHCP Message Type */ -    *e++ = 1; -    *e++ = DHCP_DISCOVER; +	*e++ = 53;		/* DHCP Message Type */ +	*e++ = 1; +	*e++ = DHCP_DISCOVER; -    *e++ = 57;		/* Maximum DHCP Message Size */ -    *e++ = 2; -    *e++ = (576-312+OPT_SIZE) >> 16; -    *e++ = (576-312+OPT_SIZE) & 0xff; -#endif	/* CFG_CMD_DHCP */ +	*e++ = 57;		/* Maximum DHCP Message Size */ +	*e++ = 2; +	*e++ = (576 - 312 + OPT_SIZE) >> 16; +	*e++ = (576 - 312 + OPT_SIZE) & 0xff; +#endif /* CFG_CMD_DHCP */  #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_SUBNETMASK) -    *e++ =  1;		/* Subnet mask request */ -    *e++ =  4; -     e  +=  4; +	*e++ = 1;		/* Subnet mask request */ +	*e++ = 4; +	e   += 4;  #endif  #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_GATEWAY) -    *e++ =  3;		/* Default gateway request */ -    *e++ =  4; -     e  +=  4; +	*e++ = 3;		/* Default gateway request */ +	*e++ = 4; +	e   += 4;  #endif  #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_DNS) -    *e++ =  6;		/* Domain Name Server */ -    *e++ =  4; -     e  +=  4; +	*e++ = 6;		/* Domain Name Server */ +	*e++ = 4; +	e   += 4;  #endif  #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_HOSTNAME) -    *e++ = 12;		/* Host name request */ -    *e++ = 32; -     e  += 32; +	*e++ = 12;		/* Host name request */ +	*e++ = 32; +	e   += 32;  #endif  #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_BOOTFILESIZE) -    *e++ = 13;		/* Boot file size */ -    *e++ =  2; -     e  +=  2; +	*e++ = 13;		/* Boot file size */ +	*e++ = 2; +	e   += 2;  #endif  #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_BOOTPATH) -    *e++ = 17;		/* Boot path */ -    *e++ = 32; -     e  += 32; +	*e++ = 17;		/* Boot path */ +	*e++ = 32; +	e   += 32;  #endif  #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_NISDOMAIN) -    *e++ = 40;		/* NIS Domain name request */ -    *e++ = 32; -     e  += 32; +	*e++ = 40;		/* NIS Domain name request */ +	*e++ = 32; +	e   += 32;  #endif -    *e++ = 255;		/* End of the list */ +	*e++ = 255;		/* End of the list */ -    return e - start ; +	return e - start;  }  #endif	/* CFG_CMD_DHCP */ @@ -678,7 +679,7 @@ BootpRequest (void)  		| ((ulong)NetOurEther[4] << 8)  		| (ulong)NetOurEther[5];  	BootpID += get_timer(0); -	BootpID  = htonl(BootpID); +	BootpID	 = htonl(BootpID);  	NetCopyLong(&bp->bp_id, &BootpID);  	/* @@ -700,64 +701,59 @@ BootpRequest (void)  }  #if (CONFIG_COMMANDS & CFG_CMD_DHCP) -static void DhcpOptionsProcess(uchar *popt) +static void DhcpOptionsProcess (uchar * popt)  {  	uchar *end = popt + BOOTP_HDR_SIZE;  	int oplen, size; -	while ( popt < end && *popt != 0xff ) { +	while (popt < end && *popt != 0xff) {  		oplen = *(popt + 1); -		switch(*popt) { -			case  1: -				NetCopyIP(&NetOurSubnetMask, (popt+2)); -				break; -			case  3: -				NetCopyIP(&NetOurGatewayIP, (popt+2)); -				break; -			case  6: -				NetCopyIP(&NetOurDNSIP, (popt+2)); +		switch (*popt) { +		case 1: +			NetCopyIP (&NetOurSubnetMask, (popt + 2)); +			break; +		case 3: +			NetCopyIP (&NetOurGatewayIP, (popt + 2)); +			break; +		case 6: +			NetCopyIP (&NetOurDNSIP, (popt + 2));  #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_DNS2) -				if ( *(popt+1) > 4 ) { -					NetCopyIP(&NetOurDNS2IP, (popt+2+4)); -				} +			if (*(popt + 1) > 4) { +				NetCopyIP (&NetOurDNS2IP, (popt + 2 + 4)); +			}  #endif -				break; -			case 12: -				size = truncate_sz ("Host Name", -						    sizeof(NetOurHostName), -						    oplen); -				memcpy(&NetOurHostName, popt+2, size); -				NetOurHostName[size] = 0 ; -				break; -			case 15:		/* Ignore Domain Name Option */ -				break; -			case 17: -				size = truncate_sz ("Root Path", -						    sizeof(NetOurRootPath), -						    oplen); -				memcpy(&NetOurRootPath, popt+2, size); -				NetOurRootPath[size] = 0 ; -				break; -			case 51: -				NetCopyLong (&dhcp_leasetime, (ulong *)(popt + 2)); -				break; -			case 53:		/* Ignore Message Type Option */ -				break; -			case 54: -				NetCopyIP(&NetDHCPServerIP, (popt+2)); -				break; -			case 58:		/* Ignore Renewal Time Option */ -				break; -			case 59:		/* Ignore Rebinding Time Option */ -				break; -			default: +			break; +		case 12: +			size = truncate_sz ("Host Name", sizeof (NetOurHostName), oplen); +			memcpy (&NetOurHostName, popt + 2, size); +			NetOurHostName[size] = 0; +			break; +		case 15:	/* Ignore Domain Name Option */ +			break; +		case 17: +			size = truncate_sz ("Root Path", sizeof (NetOurRootPath), oplen); +			memcpy (&NetOurRootPath, popt + 2, size); +			NetOurRootPath[size] = 0; +			break; +		case 51: +			NetCopyLong (&dhcp_leasetime, (ulong *) (popt + 2)); +			break; +		case 53:	/* Ignore Message Type Option */ +			break; +		case 54: +			NetCopyIP (&NetDHCPServerIP, (popt + 2)); +			break; +		case 58:	/* Ignore Renewal Time Option */ +			break; +		case 59:	/* Ignore Rebinding Time Option */ +			break; +		default:  #if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_VENDOREX) -			    if (dhcp_vendorex_proc(popt)) +			if (dhcp_vendorex_proc (popt))  				break;  #endif -				printf("*** Unhandled DHCP Option in OFFER/ACK: %d\n", -					*popt); -				break; +			printf ("*** Unhandled DHCP Option in OFFER/ACK: %d\n", *popt); +			break;  		}  		popt += oplen + 2;	/* Process next option */  	} @@ -837,7 +833,7 @@ DhcpHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len)  	debug ("DHCPHandler: got packet: (src=%d, dst=%d, len=%d) state: %d\n",  		src, dest, len, dhcp_state); -	if (BootpCheckPkt(pkt, dest, src, len))	/* Filter out pkts we don't want */ +	if (BootpCheckPkt(pkt, dest, src, len)) /* Filter out pkts we don't want */  		return;  	debug ("DHCPHandler: got DHCP packet: (src=%d, dst=%d, len=%d) state: %d\n", @@ -864,7 +860,7 @@ DhcpHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len)  			if (NetReadLong((ulong*)&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC))  				DhcpOptionsProcess(&bp->bp_vend[4]); -			BootpCopyNetParams(bp);	/* Store net params from reply */ +			BootpCopyNetParams(bp); /* Store net params from reply */  			NetSetTimeout(TIMEOUT * CFG_HZ, BootpTimeout);  			DhcpSendRequestPkt(bp); @@ -882,7 +878,7 @@ DhcpHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len)  			if (NetReadLong((ulong*)&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC))  				DhcpOptionsProcess(&bp->bp_vend[4]); -			BootpCopyNetParams(bp);	/* Store net params from reply */ +			BootpCopyNetParams(bp); /* Store net params from reply */  			dhcp_state = BOUND;  			printf("DHCP client bound to address ");  			print_IPaddr(NetOurIP); |