david vor 15 Jahren
Ursprung
Commit
920913d9e1

+ 1 - 1
poc/lpc2148_efsl/conf/config.h

@@ -15,7 +15,7 @@
 */
 
 	/*#define HW_ENDPOINT_LINUX*/
-	/*#define HW_ENDPOINT_ATMEGA128_SD*/
+	/*#define HW_ENDPOINT_ATMEGA128_SD*/
 
 
 	#define HW_ENDPOINT_LPC2000_SD

+ 1 - 1
poc/lpc2148_efsl/inc/fs.h

@@ -166,7 +166,7 @@ struct FileRecord{
 	euint32 FileSize;
 };
 #else
-#warning "mt ATTR_PACKED active"
+//#warning "mt ATTR_PACKED active"
 struct FileRecord{
 	euint8 FileName[11];
 	euint8 Attribute;

+ 56 - 14
poc/lpc2148_efsl/test/main.c

@@ -18,6 +18,8 @@
 #include "efs.h"
 #include "ls.h"
 #include "mkfs.h"
+#include "types.h"
+#include "debug.h"
 #include "interfaces/efsl_dbg_printf_arm.h"
 
 #define rprintf efsl_debug_printf_arm
@@ -31,7 +33,7 @@
 #define LEDDIR      IODIR0
 #define LEDSET      IOSET0
 #define LEDCLR      IOCLR0
-static char LogFileName[] = "dummy.log";
+static char rom_filename[] = "SPRITE.SMC";
 
 static void gpioInit(void)
 {
@@ -53,6 +55,17 @@ DirList list;
 unsigned short e;
 unsigned char buf[513];
 
+void cleanup_name(filename,sfn){
+	
+	while(*filename != '\0'){
+		if(*filename=='.' && !dot){
+			dot=1;
+			c=8;
+		}else{
+	
+	
+}
+
 void list_roms(){
 	uint8_t cnt = 0;	
     rprintf("Directory of 'root':\n");
@@ -78,13 +91,41 @@ uint8_t * get_filename(uint8_t idx){
 	return NULL;	
 }
 
+void dump_packet(uint32_t addr,uint32_t len,uint8_t *packet){
+	uint16_t i,j;
+	uint16_t sum =0;
+	for (i=0;i<len;i+=16) {
+		sum = 0;
+		for (j=0;j<16;j++) {
+			sum +=packet[i+j];
+		}
+		if (!sum)
+			continue;
+		DBG((TXT("%08x:"), addr + i));
+		for (j=0;j<16;j++) {
+			DBG((TXT(" %02x"), packet[i+j]));
+		}
+		DBG((TXT(" |")));
+		for (j=0;j<16;j++) {
+			if (packet[i+j]>=33 && packet[i+j]<=126 )
+				DBG((TXT("%c"), packet[i+j]));
+			else
+				DBG((TXT(".")));
+		}
+		DBG((TXT("|\n")));
+		
+	}
+}
+
 void dump_filename(uint8_t * filename){
+	uint32_t cnt = 0;
     if (file_fopen(&filer, &efs.myFs, filename, 'r') == 0) {
         rprintf("File %s open. Content:\n", filename);
         while ((e = file_read(&filer, 512, buf)) != 0) {
-            buf[e] = '\0';
-            uart0Puts((char *) buf);
+			dump_packet(cnt,e,buf);
+			cnt+=e;
         } 
+		DBG((TXT("Len %08x(%li)\n"), cnt,cnt));
 		rprintf("\n");
         file_fclose(&filer);
 	} else {
@@ -100,6 +141,7 @@ int main(void)
     int ch;
     int8_t res;
     uint8_t * filename;
+    uint8_t fatfilename[12];
 
     Initialize();
     gpioInit();
@@ -120,21 +162,21 @@ int main(void)
             uart0Puts("You pressed : ");
             uart0Putch(ch);
             uart0Puts("\r\n");
-            if (ch == 'r') {
-                if (file_fopen(&filer, &efs.myFs, LogFileName, 'r') == 0) {
-                    rprintf("File %s open. Content:\n", LogFileName);
-                    while ((e = file_read(&filer, 512, buf)) != 0) {
-                        buf[e] = '\0';
-                        uart0Puts((char *) buf);
-                    } rprintf("\n");
-                    file_fclose(&filer);
-                }
-            }
 			if (ch >='1' && ch <='9'){
 				
 				filename = get_filename(ch - 48);
-				rprintf("Dump: %s\n",filename);
+				file_normalToFatName(filename,fatfilename);
+				rprintf("Filename: '%s'\n",filename);
 				dump_filename(filename);
+				rprintf("Fatfilename: '%s'\n",fatfilename);
+				dump_filename(fatfilename);
+				file_normalToFatName("sprite.smc",fatfilename);
+				rprintf("Fatfilename: '%s'\n",fatfilename);
+				dump_filename(fatfilename);
+				file_normalToFatName("sprite .smc",fatfilename);
+				rprintf("Fatfilename: '%s'\n",fatfilename);
+				dump_filename(fatfilename);
+				//dump_filename(rom_filename);
 			}
 			  
             ledToggle();

+ 19 - 0
poc/lpc2148_usb/client/Makefile

@@ -0,0 +1,19 @@
+# app defs
+EXE = custom_client
+ifndef LIBUSB
+		LIBUSB = "/opt/local/"
+endif
+
+# tool defs
+CFLAGS = -W -Wall -g -I$(LIBUSB)/include
+LIBS =  -L$(LIBUSB)/lib -lusb
+
+all: $(EXE)
+
+$(EXE): main.o
+	$(CC) -o $(EXE) $< $(LIBS)
+
+clean:
+	$(RM) $(EXE) main.o 
+	
+	

+ 193 - 0
poc/lpc2148_usb/client/main.c

@@ -0,0 +1,193 @@
+/*
+	LPCUSB, an USB device driver for LPC microcontrollers	
+	Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library 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
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the Free Software
+	Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+/*
+	Simple benchmarking application.
+	
+	It talks with the 'custom' device application on the LPC214x through
+	libusb.
+
+*/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/timeb.h>
+
+#include "usb.h"
+
+// types
+#ifndef MIN
+#define MIN(a,b)	((a)<(b)?(a):(b))
+#endif
+typedef unsigned int U32;
+typedef unsigned char U8;
+
+#define MAX_TIME 3000
+
+static unsigned char abData[16384];
+
+// USB device specific definitions
+#define VENDOR_ID	0xFFFF
+#define PRODUCT_ID	0x0004
+
+#define	BM_REQUEST_TYPE		(2<<5)
+#define BULK_IN_EP			0x82
+#define BULK_OUT_EP			0x05
+
+// this structure should match with the expectations of the 'custom' device!
+typedef struct {
+	U32		dwAddress;
+	U32		dwLength;
+} TMemoryCmd;
+
+
+static struct usb_device * find_device(int iVendor, int iProduct)
+{
+	struct usb_bus	*usb_bus;
+	struct usb_device *dev;	
+	
+	for (usb_bus = usb_get_busses(); usb_bus; usb_bus = usb_bus->next) {
+		for (dev = usb_bus->devices; dev; dev = dev->next) {
+			if ((dev->descriptor.idVendor == iVendor) && 
+				(dev->descriptor.idProduct == iProduct)) {
+				return dev;
+			}
+		}
+	}
+	return NULL;
+}
+
+
+static struct timeb start;
+
+static void starttimer(void)
+{
+	ftime(&start);
+}
+
+static int stoptimer(void)
+{
+	struct timeb now;
+	
+	ftime(&now);
+	return 1000 * (now.time - start.time) + now.millitm - start.millitm;
+}
+
+
+int main(int argc, char *argv[])
+{
+	struct usb_device *dev;	
+	struct usb_dev_handle *hdl;
+	int i, j;
+	U32 dwBlockSize, dwChunk, dwBytes;
+	TMemoryCmd MemCmd;
+	int iTimer;
+
+	usb_init();
+	usb_find_busses();
+	usb_find_devices();
+	
+	dev = find_device(VENDOR_ID, PRODUCT_ID);
+	if (dev == NULL) {
+		fprintf(stderr, "device not found\n");
+		return -1;
+	}
+	
+	hdl = usb_open(dev);
+	
+	i = usb_set_configuration(hdl, 1);
+	if (i < 0) {
+		fprintf(stderr, "usb_set_configuration failed\n");
+	}
+	
+	i = usb_claim_interface(hdl, 0);
+	if (i < 0) {
+		fprintf(stderr, "usb_claim_interface failed %d\n", i);
+		return -1;
+	}
+
+
+	// read some data
+	for (j = 6; j < 15; j++) {
+		dwBlockSize = (1 << j);
+		fprintf(stderr, "Testing blocksize %5d\n", dwBlockSize);
+
+		fprintf(stderr, "* read :");
+		// send a vendor request for a read
+		MemCmd.dwAddress = 0;
+		MemCmd.dwLength = 1024 * 1024;
+		i = usb_control_msg(hdl, BM_REQUEST_TYPE, 0x01, 0, 0, (char *)&MemCmd, sizeof(MemCmd), 1000);
+		if (i < 0) {
+			fprintf(stderr, "usb_control_msg failed %d\n", i);
+		}
+		dwBytes = 0;
+		starttimer();
+		while (MemCmd.dwLength > 0) {
+			dwChunk = MIN(dwBlockSize, MemCmd.dwLength);
+			i = usb_bulk_read(hdl, 0x82, (char *)abData, dwBlockSize, 2000);
+			if (i < 0) {
+				fprintf(stderr, "usb_bulk_read failed %d\n", i);
+				break;
+			}
+			MemCmd.dwLength -= dwChunk;
+			dwBytes += dwBlockSize;
+			if (stoptimer() > MAX_TIME) {
+				break;
+			}
+		}
+		iTimer = stoptimer();
+		fprintf(stderr, " %7d bytes in %d ms = %d kB/s\n", dwBytes, iTimer, dwBytes / iTimer);
+		// stdout
+		printf("%d,%d,%d,", dwBlockSize, dwBytes, iTimer);
+
+		fprintf(stderr, "* write:");
+		// send a vendor request for a write
+		MemCmd.dwAddress = 0;
+		MemCmd.dwLength = 1024 * 1024;
+		i = usb_control_msg(hdl, BM_REQUEST_TYPE, 0x02, 0, 0, (char *)&MemCmd, sizeof(MemCmd), 1000);
+		if (i < 0) {
+			fprintf(stderr, "usb_control_msg failed %d\n", i);
+		}
+		dwBytes = 0;
+		starttimer();
+		while (MemCmd.dwLength > 0) {
+			dwChunk = MIN(dwBlockSize, MemCmd.dwLength);
+			i = usb_bulk_write(hdl, 0x05, (char *)abData, dwBlockSize, 2000);
+			if (i < 0) {
+				fprintf(stderr, "usb_bulk_read failed %d\n", i);
+				break;
+			}
+			MemCmd.dwLength -= dwChunk;
+			dwBytes += dwBlockSize;
+			if (stoptimer() > MAX_TIME) {
+				break;
+			}
+		}
+		fprintf(stderr, " %7d bytes in %d ms = %d kB/s\n", dwBytes, iTimer, dwBytes / iTimer);
+		// stdout
+		printf("%d,%d,%d\n", dwBlockSize, dwBytes, iTimer);
+	}
+
+
+	usb_release_interface(hdl, 0);
+	usb_close(hdl);
+
+	return 0;
+}
+

+ 52 - 0
poc/lpc2148_usb/target/Makefile

@@ -0,0 +1,52 @@
+LIBNAME	= usbstack
+
+# Package definitions
+PKG_NAME	= target
+DATE		= $$(date +%Y%m%d)
+
+# Tool definitions
+CC      = arm-elf-gcc
+LD      = arm-elf-ld -v
+AR      = arm-elf-ar
+AS      = arm-elf-as
+CP      = arm-elf-objcopy
+OD		= arm-elf-objdump
+RM		= rm
+TAR		= tar
+
+CFLAGS  = -I./ -I../ -c -W -Wall -Os -g -DDEBUG -mcpu=arm7tdmi
+ARFLAGS = -rcs
+
+LIBSRCS = usbhw_lpc.c usbcontrol.c usbstdreq.c usbinit.c
+LIBOBJS = $(LIBSRCS:.c=.o)
+
+all: depend lib examples
+
+clean:
+	$(RM) -f $(LIBNAME).a $(LIBOBJS) .depend
+	make -C custom clean
+
+custom:
+	make -C custom
+
+# build lib
+lib: $(LIBNAME).a
+
+$(LIBNAME).a: $(LIBOBJS)
+	$(AR) $(ARFLAGS) $@ $^
+
+# Builds release tar file
+dist: clean
+	cd .. && $(TAR) --exclude={CVS,cvs} -cvzf $(PKG_NAME)-$(DATE).tar.gz $(PKG_NAME)
+
+# recompile if the Makefile changes
+$(LIBOBJS): Makefile
+
+# dependency checking
+depend: $(LIBSRCS)
+	$(CC) $(CFLAGS) -MM $^ > .depend || rm -f .depend
+
+# phony targets
+.PHONY: all clean examples depend
+
+-include .depend

+ 55 - 0
poc/lpc2148_usb/target/custom/Makefile

@@ -0,0 +1,55 @@
+LIBNAME	= ../usbstack
+APPNAME = main
+
+# Tool definitions
+CC      = arm-elf-gcc
+LD      = arm-elf-ld -v
+AR      = arm-elf-ar
+AS      = arm-elf-as
+CP      = arm-elf-objcopy
+OD		= arm-elf-objdump
+RM		= rm
+
+# Tool flags
+CFLAGS  = -I./ -I../ -c -W -Wall -Os -g -DDEBUG -mcpu=arm7tdmi
+ASFLAGS = -ahls -mapcs-32 -o crt.o
+LFLAGS  =  -nostartfiles --warn-common
+CPFLAGS = -O ihex
+ODFLAGS	= -x --syms
+
+LINKFILE	= lpc2148-rom.ld
+
+CSRCS	= startup.c printf.c console.c
+OBJS 	= crt.o $(CSRCS:.c=.o)
+
+EXAMPLES =  custom
+
+all: depend $(EXAMPLES)
+
+custom:	$(OBJS) main_custom.o $(LIBNAME).a
+
+$(EXAMPLES):
+	@ echo "Building $@ example..."
+	$(CC) -T $(LINKFILE) $(LFLAGS) $^ -o $@.elf -Wl,-Map,$@.map
+	$(CP) $(CPFLAGS) $@.elf $@.hex
+	$(CP) -O binary  $@.elf $@.bin
+	$(OD) $(ODFLAGS) $@.elf > $@.dmp
+crt.o: crt.s
+	@ echo ".assembling"
+	$(CC) -c $(AFLAGS) -Wa,-ahlms=crt.lst crt.s -o crt.o
+	
+clean:
+	rm -f *.hex *.elf *.o *.lst *.dmp *.map .depend
+
+# recompile if the Makefile changes
+$(OBJS): Makefile
+
+# dependency checking
+depend: $(CSRCS)
+	$(CC) $(CFLAGS) -MM $^ > .depend || rm -f .depend
+
+# phony targets
+.PHONY: clean
+
+-include .depend
+

+ 65 - 0
poc/lpc2148_usb/target/custom/console.c

@@ -0,0 +1,65 @@
+/*
+	Simple console input/output, over serial port #0
+
+	Partially copied from Jim Lynch's tutorial
+*/
+
+#include "console.h"
+
+#define PINSEL0		*(volatile unsigned int *)0xE002C000
+
+#define U0THR		*(volatile unsigned int *)0xE000C000
+#define U0RBR		*(volatile unsigned int *)0xE000C000
+#define U0DLL		*(volatile unsigned int *)0xE000C000
+#define U0DLM		*(volatile unsigned int *)0xE000C004
+#define U0FCR		*(volatile unsigned int *)0xE000C008
+#define U0LCR		*(volatile unsigned int *)0xE000C00C
+#define U0LSR		*(volatile unsigned int *)0xE000C014
+
+
+/* Initialize Serial Interface       */
+void ConsoleInit(int iDivider)  
+{               
+	PINSEL0 = (PINSEL0 & ~0x0000000F) | 0x00000005;	/* Enable RxD0 and TxD0              */
+	U0LCR = 0x83;                          			/* 8 bits, no Parity, 1 Stop bit     */
+	U0DLL = iDivider & 0xFF;						/* set divider / baud rate */
+	U0DLM = iDivider >> 8;
+	U0LCR = 0x03;                          			/* DLAB = 0                          */
+	
+	// enable FIFO
+	U0FCR = 1;
+}
+
+
+/* Write character to Serial Port    */
+int putchar(int ch)  
+{             
+	if (ch == '\n') {
+		while (!(U0LSR & 0x20));
+		U0THR = '\r';
+	}
+	while (!(U0LSR & 0x20));
+	U0THR = ch;
+	
+	return ch;
+}
+
+
+int getchar (void)  {                    /* Read character from Serial Port   */
+
+  while (!(U0LSR & 0x01));
+
+  return (U0RBR);
+}
+
+
+int puts(char *s)
+{
+	while (*s) {
+		putchar(*s++);
+	}
+	putchar('\n');
+	return 1;
+}
+
+

+ 5 - 0
poc/lpc2148_usb/target/custom/console.h

@@ -0,0 +1,5 @@
+void ConsoleInit(int iDivider);
+int putchar(int c);
+int puts(char *s);
+
+

+ 110 - 0
poc/lpc2148_usb/target/custom/crt.s

@@ -0,0 +1,110 @@
+/* ***************************************************************************************************************
+
+	crt.s						STARTUP  ASSEMBLY  CODE 
+								-----------------------
+
+
+	Module includes the interrupt vectors and start-up code.
+
+  *************************************************************************************************************** */
+
+/* Stack Sizes */
+.set  UND_STACK_SIZE, 0x00000040		/* stack for "undefined instruction" interrupts is 4 bytes  */
+.set  ABT_STACK_SIZE, 0x00000040		/* stack for "abort" interrupts is 4 bytes                  */
+.set  FIQ_STACK_SIZE, 0x00000040		/* stack for "FIQ" interrupts  is 4 bytes         			*/
+.set  IRQ_STACK_SIZE, 0X00000040		/* stack for "IRQ" normal interrupts is 4 bytes    			*/
+.set  SVC_STACK_SIZE, 0x00000400		/* stack for "SVC" supervisor mode is 4 bytes  				*/
+
+
+
+/* Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs (program status registers) */
+.set  MODE_USR, 0x10            		/* Normal User Mode 										*/
+.set  MODE_FIQ, 0x11            		/* FIQ Processing Fast Interrupts Mode 						*/
+.set  MODE_IRQ, 0x12            		/* IRQ Processing Standard Interrupts Mode 					*/
+.set  MODE_SVC, 0x13            		/* Supervisor Processing Software Interrupts Mode 			*/
+.set  MODE_ABT, 0x17            		/* Abort Processing memory Faults Mode 						*/
+.set  MODE_UND, 0x1B            		/* Undefined Processing Undefined Instructions Mode 		*/
+.set  MODE_SYS, 0x1F            		/* System Running Priviledged Operating System Tasks  Mode	*/
+
+.set  I_BIT, 0x80               		/* when I bit is set, IRQ is disabled (program status registers) */
+.set  F_BIT, 0x40               		/* when F bit is set, FIQ is disabled (program status registers) */
+
+
+.text
+.arm
+
+.global	Reset_Handler
+.global _startup
+.func   _startup
+
+_startup:
+
+# Exception Vectors
+
+_vectors:       ldr     PC, Reset_Addr         
+                ldr     PC, Undef_Addr
+                ldr     PC, SWI_Addr
+                ldr     PC, PAbt_Addr
+                ldr     PC, DAbt_Addr
+                nop							/* Reserved Vector (holds Philips ISP checksum) */
+                ldr     PC, [PC,#-0xFF0]	/* see page 71 of "Insiders Guide to the Philips ARM7-Based Microcontrollers" by Trevor Martin  */
+                ldr     PC, FIQ_Addr
+
+Reset_Addr:     .word   Reset_Handler		/* defined in this module below  */
+Undef_Addr:     .word   UNDEF_Routine		/* defined in main.c  */
+SWI_Addr:       .word   SWI_Routine			/* defined in main.c  */
+PAbt_Addr:      .word   UNDEF_Routine		/* defined in main.c  */
+DAbt_Addr:      .word   UNDEF_Routine		/* defined in main.c  */
+IRQ_Addr:       .word   IRQ_Routine			/* defined in main.c  */
+FIQ_Addr:       .word   FIQ_Routine			/* defined in main.c  */
+                .word   0					/* rounds the vectors and ISR addresses to 64 bytes total  */
+
+
+# Reset Handler
+
+Reset_Handler:  
+
+				/* Setup a stack for each mode - note that this only sets up a usable stack
+				for User mode.   Also each mode is setup with interrupts initially disabled. */
+    			  
+    			ldr   r0, =_stack_end
+    			msr   CPSR_c, #MODE_UND|I_BIT|F_BIT 	/* Undefined Instruction Mode  */
+    			mov   sp, r0
+    			sub   r0, r0, #UND_STACK_SIZE
+    			msr   CPSR_c, #MODE_ABT|I_BIT|F_BIT 	/* Abort Mode */
+    			mov   sp, r0
+    			sub   r0, r0, #ABT_STACK_SIZE
+    			msr   CPSR_c, #MODE_FIQ|I_BIT|F_BIT 	/* FIQ Mode */
+    			mov   sp, r0	
+   				sub   r0, r0, #FIQ_STACK_SIZE
+    			msr   CPSR_c, #MODE_IRQ|I_BIT|F_BIT 	/* IRQ Mode */
+    			mov   sp, r0
+    			sub   r0, r0, #IRQ_STACK_SIZE
+    			msr   CPSR_c, #MODE_SVC|I_BIT|F_BIT 	/* Supervisor Mode */
+    			mov   sp, r0
+    			sub   r0, r0, #SVC_STACK_SIZE
+    			msr   CPSR_c, #MODE_SYS|I_BIT|F_BIT 	/* User Mode */
+    			mov   sp, r0
+
+				/* copy .data section (Copy from ROM to RAM) */
+                ldr     R1, =_etext
+                ldr     R2, =_data
+                ldr     R3, =_edata
+1:        		cmp     R2, R3
+                ldrlo   R0, [R1], #4
+                strlo   R0, [R2], #4
+                blo     1b
+
+				/* Clear .bss section (Zero init)  */
+                mov     R0, #0
+                ldr     R1, =_bss_start
+                ldr     R2, =_bss_end
+2:				cmp     R1, R2
+                strlo   R0, [R1], #4
+                blo     2b
+
+				/* Enter the C code  */
+                b       main
+
+.endfunc
+.end

+ 7 - 0
poc/lpc2148_usb/target/custom/flash.ocd

@@ -0,0 +1,7 @@
+halt 
+wait_halt 
+sleep 10 
+poll 
+flash erase_sector 0 0 14 
+flash write_bank  0 /Users/david/Devel/arch/arm/code/lpcusb/examples/custom.bin 0
+reset run

+ 197 - 0
poc/lpc2148_usb/target/custom/lpc2148-ram.ld

@@ -0,0 +1,197 @@
+/* ****************************************************************************************************** */
+/*   demo2148_blink_flash.cmd				LINKER  SCRIPT                                                */
+/*                                                                                                        */
+/*                                                                                                        */
+/*   The Linker Script defines how the code and data emitted by the GNU C compiler and assembler are  	  */
+/*   to be loaded into memory (code goes into FLASH, variables go into RAM).                 			  */
+/*                                                                                                        */
+/*   Any symbols defined in the Linker Script are automatically global and available to the rest of the   */
+/*   program.                                                                                             */
+/*                                                                                                        */
+/*   To force the linker to use this LINKER SCRIPT, just add the -T demo2148_blink_flash.cmd directive    */
+/*   to the linker flags in the makefile.                                                                 */
+/*                                                                                                        */
+/*   			LFLAGS  =  -Map main.map -nostartfiles -T demo2148_blink_flash.cmd                        */
+/*                                                                                                        */
+/*                                                                                                        */
+/*   The Philips boot loader supports the ISP (In System Programming) via the serial port and the IAP     */
+/*   (In Application Programming) for flash programming from within your application.                     */
+/*                                                                                                        */
+/*   The boot loader uses RAM memory and we MUST NOT load variables or code in these areas.               */
+/*                                                                                                        */
+/*   RAM used by boot loader:  0x40000120 - 0x400001FF  (223 bytes) for ISP variables                     */
+/*                             0x40007FE0 - 0x4000FFFF  (32 bytes)  for ISP and IAP variables             */
+/*                             0x40007EE0 - 0x40007FE0  (256 bytes) stack for ISP and IAP                 */
+/*                                                                                                        */
+/*                                                                                                        */
+/*                              MEMORY MAP                                                                */
+/*                      |                                 |0x40008000                                     */
+/*            .-------->|---------------------------------|                                               */
+/*            .         |     variables and stack         |0x40007FFF                                     */
+/*         ram_isp_high |     for Philips boot loader     |                                               */
+/*            .         |     32 + 256 = 288 bytes        |                                               */
+/*            .         |                                 |                                     		  */
+/*            .         |   Do not put anything here      |0x40007EE0                                     */
+/*            .-------->|---------------------------------|                                               */
+/*                      |    UDF Stack  4 bytes           |0x40007EDC  <---------- _stack_end             */
+/*            .-------->|---------------------------------|                                               */
+/*                      |    ABT Stack  4 bytes           |0x40007ED8                                     */
+/*            .-------->|---------------------------------|                                               */
+/*                      |    FIQ Stack  4 bytes           |0x40007ED4                                     */
+/*            .-------->|---------------------------------|                                               */
+/*                      |    IRQ Stack  4 bytes           |0x40007ED0                                     */
+/*            .-------->|---------------------------------|                                               */
+/*                      |    SVC Stack  4 bytes           |0x40007ECC                                     */
+/*            .-------->|---------------------------------|                                               */
+/*            .         |                                 |0x40007EC8 			                          */
+/*            .         |     stack area for user program |                                               */
+/*            .         |               |                 |                                               */
+/*            .         |               |                 |                                               */
+/*            .         |               |                 |                                               */
+/*            .         |               V                 |                                               */
+/*            .         |                                 |                                               */
+/*            .         |                                 |                                               */
+/*            .         |                                 |                                               */
+/*            .         |          free ram               |                                               */
+/*           ram        |                                 |                                               */
+/*            .         |                                 |                                               */
+/*            .         |                                 |                                               */
+/*            .         |.................................|0x40000234 <---------- _bss_end                */
+/*            .         |                                 |                                               */
+/*            .         |  .bss   uninitialized variables |                                               */
+/*            .         |.................................|0x40000218 <---------- _bss_start, _edata      */
+/*            .         |                                 |                                               */
+/*            .         |  .data  initialized variables   |                                               */
+/*            .         |                                 |0x40000200 <---------- _data                   */
+/*            .-------->|---------------------------------|                                               */
+/*            .         |     variables used by           |0x400001FF                                     */
+/*         ram_isp_low  |     Philips boot loader         |                                               */
+/*            .         |           223 bytes             |0x40000120                                     */
+/*            .-------->|---------------------------------|                                               */
+/*            .         |                                 |0x4000011F                                     */
+/*         ram_vectors  |          free ram               |                                               */
+/*            .         |---------------------------------|0x40000040                                     */
+/*            .         |                                 |0x4000003F                                     */
+/*            .         |  Interrupt Vectors (re-mapped)  |                                               */
+/*            .         |          64 bytes               |0x40000000                                     */
+/*            .-------->|---------------------------------|                                               */
+/*                      |                                 |                                               */
+/*                                                                                                        */
+/*                                                                                                        */
+/*                                                                                                        */
+/*                      |                                 |                                               */
+/*           .--------> |---------------------------------|                                               */
+/*           .          |                                 |0x0001FFFF                                     */
+/*           .          |                                 |                                               */
+/*           .          |                                 |                                               */
+/*           .          |                                 |                                               */
+/*           .          |                                 |                                               */
+/*           .          |                                 |                                               */
+/*           .          |       unused flash eprom        |                                               */
+/*           .          |                                 |                                               */
+/*           .          |.................................|0x0000032c                                     */
+/*           .          |                                 |                                               */
+/*           .          |      copy of .data area         |                                               */
+/*         flash        |                                 |                                               */
+/*           .          |---------------------------------|0x00000314 <----------- _etext                 */
+/*           .          |                                 |                                               */
+/*           .          |                                 |0x00000180  main                               */
+/*           .          |                                 |0x00000278  feed                               */
+/*           .          |         main()                  |0x000002c4  FIQ_Routine                        */
+/*           .          |                                 |0x000002d8  SWI_Routine                        */
+/*           .          |                                 |0x000002ec  UNDEF_Routine	                  */
+/*           .          |                                 |0x000002b0  IRQ_routine                        */
+/*           .          |---------------------------------|0x000001cc  initialize                         */
+/*           .          |                                 |0x000000D4                                     */
+/*           .          |         Startup Code            |                                               */
+/*           .          |         (assembler)             |                                               */
+/*           .          |                                 |                                               */
+/*           .          |---------------------------------|0x00000040 Reset_Handler                       */
+/*           .          |                                 |0x0000003F                                     */
+/*           .          | Interrupt Vector Table (unused) |                                               */
+/*           .          |          64 bytes               |                                               */
+/*           .--------->|---------------------------------|0x00000000 _startup                            *
+/*                                                                                                        */
+/*                                                                                                        */
+/*    The easy way to prevent the linker from loading anything into a memory area is to define            */
+/*    a MEMORY region for it and then avoid assigning any .text, .data or .bss sections into it.          */
+/*                                                                                                        */
+/*                                                                                                        */
+/*             MEMORY                                                                                     */
+/*             {                                                                                          */
+/*                ram_isp_low(A)  : ORIGIN = 0x40000120, LENGTH = 223                                     */
+/*                                                                                                        */
+/*             }                                                                                          */
+/*                                                                                                        */
+/*                                                                                                        */
+/*  Author:  James P. Lynch                                                                               */
+/*                                                                                                        */
+/* ****************************************************************************************************** */
+
+
+/* identify the Entry Point  */
+
+ENTRY(_startup)
+
+
+
+/* specify the LPC2148 memory areas  */
+
+MEMORY 
+{
+	flash     			: ORIGIN = 0,          LENGTH = 512K	/* FLASH ROM                            	*/	
+	ram_isp_low(A)		: ORIGIN = 0x40000120, LENGTH = 223		/* variables used by Philips ISP bootloader	*/		 
+	ram   				: ORIGIN = 0x40000200, LENGTH = 32513   /* free RAM area							*/
+	ram_isp_high(A)		: ORIGIN = 0x40007FE0, LENGTH = 32		/* variables used by Philips ISP bootloader	*/
+	ram_usb_dma			: ORIGIN = 0x7FD00000, LENGTH = 8192    /* on-chip USB DMA RAM area (not used)      */
+}
+
+
+
+/* define a global symbol _stack_end  */
+
+_stack_end = 0x40007EDC;
+
+
+
+/* now define the output sections  */
+
+SECTIONS 
+{
+	. = 0;								/* set location counter to address zero  */
+	
+	startup : { *(.startup)} >ram		/* the startup code goes into FLASH */
+	
+	
+
+	.text :								/* collect all sections that should go into FLASH after startup  */ 
+	{
+		*(.text)						/* all .text sections (code)  */
+		*(.rodata)						/* all .rodata sections (constants, strings, etc.)  */
+		*(.rodata*)						/* all .rodata* sections (constants, strings, etc.)  */
+		*(.glue_7)						/* all .glue_7 sections  (no idea what these are) */
+		*(.glue_7t)						/* all .glue_7t sections (no idea what these are) */
+		_etext = .;						/* define a global symbol _etext just after the last code byte */
+	} >ram								/* put all the above into FLASH */
+	
+
+	
+
+	.data :								/* collect all initialized .data sections that go into RAM  */ 
+	{
+		_data = .;						/* create a global symbol marking the start of the .data section  */
+		*(.data)						/* all .data sections  */
+		_edata = .;						/* define a global symbol marking the end of the .data section  */
+	} >ram AT >ram						/* put all the above into RAM (but load the LMA copy into FLASH) */
+
+	.bss :								/* collect all uninitialized .bss sections that go into RAM  */
+	{
+		_bss_start = .;					/* define a global symbol marking the start of the .bss section */
+		*(.bss)							/* all .bss sections  */
+	} >ram								/* put all the above in RAM (it will be cleared in the startup code */
+
+	. = ALIGN(4);						/* advance location counter to the next 32-bit boundary */
+	_bss_end = . ;						/* define a global symbol marking the end of the .bss section */
+}
+	_end = .;							/* define a global symbol marking the end of application RAM */
+	

+ 197 - 0
poc/lpc2148_usb/target/custom/lpc2148-rom.ld

@@ -0,0 +1,197 @@
+/* ****************************************************************************************************** */
+/*   demo2148_blink_flash.cmd				LINKER  SCRIPT                                                */
+/*                                                                                                        */
+/*                                                                                                        */
+/*   The Linker Script defines how the code and data emitted by the GNU C compiler and assembler are  	  */
+/*   to be loaded into memory (code goes into FLASH, variables go into RAM).                 			  */
+/*                                                                                                        */
+/*   Any symbols defined in the Linker Script are automatically global and available to the rest of the   */
+/*   program.                                                                                             */
+/*                                                                                                        */
+/*   To force the linker to use this LINKER SCRIPT, just add the -T demo2148_blink_flash.cmd directive    */
+/*   to the linker flags in the makefile.                                                                 */
+/*                                                                                                        */
+/*   			LFLAGS  =  -Map main.map -nostartfiles -T demo2148_blink_flash.cmd                        */
+/*                                                                                                        */
+/*                                                                                                        */
+/*   The Philips boot loader supports the ISP (In System Programming) via the serial port and the IAP     */
+/*   (In Application Programming) for flash programming from within your application.                     */
+/*                                                                                                        */
+/*   The boot loader uses RAM memory and we MUST NOT load variables or code in these areas.               */
+/*                                                                                                        */
+/*   RAM used by boot loader:  0x40000120 - 0x400001FF  (223 bytes) for ISP variables                     */
+/*                             0x40007FE0 - 0x4000FFFF  (32 bytes)  for ISP and IAP variables             */
+/*                             0x40007EE0 - 0x40007FE0  (256 bytes) stack for ISP and IAP                 */
+/*                                                                                                        */
+/*                                                                                                        */
+/*                              MEMORY MAP                                                                */
+/*                      |                                 |0x40008000                                     */
+/*            .-------->|---------------------------------|                                               */
+/*            .         |     variables and stack         |0x40007FFF                                     */
+/*         ram_isp_high |     for Philips boot loader     |                                               */
+/*            .         |     32 + 256 = 288 bytes        |                                               */
+/*            .         |                                 |                                     		  */
+/*            .         |   Do not put anything here      |0x40007EE0                                     */
+/*            .-------->|---------------------------------|                                               */
+/*                      |    UDF Stack  4 bytes           |0x40007EDC  <---------- _stack_end             */
+/*            .-------->|---------------------------------|                                               */
+/*                      |    ABT Stack  4 bytes           |0x40007ED8                                     */
+/*            .-------->|---------------------------------|                                               */
+/*                      |    FIQ Stack  4 bytes           |0x40007ED4                                     */
+/*            .-------->|---------------------------------|                                               */
+/*                      |    IRQ Stack  4 bytes           |0x40007ED0                                     */
+/*            .-------->|---------------------------------|                                               */
+/*                      |    SVC Stack  4 bytes           |0x40007ECC                                     */
+/*            .-------->|---------------------------------|                                               */
+/*            .         |                                 |0x40007EC8 			                          */
+/*            .         |     stack area for user program |                                               */
+/*            .         |               |                 |                                               */
+/*            .         |               |                 |                                               */
+/*            .         |               |                 |                                               */
+/*            .         |               V                 |                                               */
+/*            .         |                                 |                                               */
+/*            .         |                                 |                                               */
+/*            .         |                                 |                                               */
+/*            .         |          free ram               |                                               */
+/*           ram        |                                 |                                               */
+/*            .         |                                 |                                               */
+/*            .         |                                 |                                               */
+/*            .         |.................................|0x40000234 <---------- _bss_end                */
+/*            .         |                                 |                                               */
+/*            .         |  .bss   uninitialized variables |                                               */
+/*            .         |.................................|0x40000218 <---------- _bss_start, _edata      */
+/*            .         |                                 |                                               */
+/*            .         |  .data  initialized variables   |                                               */
+/*            .         |                                 |0x40000200 <---------- _data                   */
+/*            .-------->|---------------------------------|                                               */
+/*            .         |     variables used by           |0x400001FF                                     */
+/*         ram_isp_low  |     Philips boot loader         |                                               */
+/*            .         |           223 bytes             |0x40000120                                     */
+/*            .-------->|---------------------------------|                                               */
+/*            .         |                                 |0x4000011F                                     */
+/*         ram_vectors  |          free ram               |                                               */
+/*            .         |---------------------------------|0x40000040                                     */
+/*            .         |                                 |0x4000003F                                     */
+/*            .         |  Interrupt Vectors (re-mapped)  |                                               */
+/*            .         |          64 bytes               |0x40000000                                     */
+/*            .-------->|---------------------------------|                                               */
+/*                      |                                 |                                               */
+/*                                                                                                        */
+/*                                                                                                        */
+/*                                                                                                        */
+/*                      |                                 |                                               */
+/*           .--------> |---------------------------------|                                               */
+/*           .          |                                 |0x0001FFFF                                     */
+/*           .          |                                 |                                               */
+/*           .          |                                 |                                               */
+/*           .          |                                 |                                               */
+/*           .          |                                 |                                               */
+/*           .          |                                 |                                               */
+/*           .          |       unused flash eprom        |                                               */
+/*           .          |                                 |                                               */
+/*           .          |.................................|0x0000032c                                     */
+/*           .          |                                 |                                               */
+/*           .          |      copy of .data area         |                                               */
+/*         flash        |                                 |                                               */
+/*           .          |---------------------------------|0x00000314 <----------- _etext                 */
+/*           .          |                                 |                                               */
+/*           .          |                                 |0x00000180  main                               */
+/*           .          |                                 |0x00000278  feed                               */
+/*           .          |         main()                  |0x000002c4  FIQ_Routine                        */
+/*           .          |                                 |0x000002d8  SWI_Routine                        */
+/*           .          |                                 |0x000002ec  UNDEF_Routine	                  */
+/*           .          |                                 |0x000002b0  IRQ_routine                        */
+/*           .          |---------------------------------|0x000001cc  initialize                         */
+/*           .          |                                 |0x000000D4                                     */
+/*           .          |         Startup Code            |                                               */
+/*           .          |         (assembler)             |                                               */
+/*           .          |                                 |                                               */
+/*           .          |---------------------------------|0x00000040 Reset_Handler                       */
+/*           .          |                                 |0x0000003F                                     */
+/*           .          | Interrupt Vector Table (unused) |                                               */
+/*           .          |          64 bytes               |                                               */
+/*           .--------->|---------------------------------|0x00000000 _startup                            *
+/*                                                                                                        */
+/*                                                                                                        */
+/*    The easy way to prevent the linker from loading anything into a memory area is to define            */
+/*    a MEMORY region for it and then avoid assigning any .text, .data or .bss sections into it.          */
+/*                                                                                                        */
+/*                                                                                                        */
+/*             MEMORY                                                                                     */
+/*             {                                                                                          */
+/*                ram_isp_low(A)  : ORIGIN = 0x40000120, LENGTH = 223                                     */
+/*                                                                                                        */
+/*             }                                                                                          */
+/*                                                                                                        */
+/*                                                                                                        */
+/*  Author:  James P. Lynch                                                                               */
+/*                                                                                                        */
+/* ****************************************************************************************************** */
+
+
+/* identify the Entry Point  */
+
+ENTRY(_startup)
+
+
+
+/* specify the LPC2148 memory areas  */
+
+MEMORY 
+{
+	flash     			: ORIGIN = 0,          LENGTH = 512K	/* FLASH ROM                            	*/	
+	ram_isp_low(A)		: ORIGIN = 0x40000120, LENGTH = 223		/* variables used by Philips ISP bootloader	*/		 
+	ram   				: ORIGIN = 0x40000200, LENGTH = 32513   /* free RAM area							*/
+	ram_isp_high(A)		: ORIGIN = 0x40007FE0, LENGTH = 32		/* variables used by Philips ISP bootloader	*/
+	ram_usb_dma			: ORIGIN = 0x7FD00000, LENGTH = 8192    /* on-chip USB DMA RAM area (not used)      */
+}
+
+
+
+/* define a global symbol _stack_end  */
+
+_stack_end = 0x40007EDC;
+
+
+
+/* now define the output sections  */
+
+SECTIONS 
+{
+	. = 0;								/* set location counter to address zero  */
+	
+	startup : { *(.startup)} >flash		/* the startup code goes into FLASH */
+	
+	
+
+	.text :								/* collect all sections that should go into FLASH after startup  */ 
+	{
+		*(.text)						/* all .text sections (code)  */
+		*(.rodata)						/* all .rodata sections (constants, strings, etc.)  */
+		*(.rodata*)						/* all .rodata* sections (constants, strings, etc.)  */
+		*(.glue_7)						/* all .glue_7 sections  (no idea what these are) */
+		*(.glue_7t)						/* all .glue_7t sections (no idea what these are) */
+		_etext = .;						/* define a global symbol _etext just after the last code byte */
+	} >flash							/* put all the above into FLASH */
+	
+
+	
+
+	.data :								/* collect all initialized .data sections that go into RAM  */ 
+	{
+		_data = .;						/* create a global symbol marking the start of the .data section  */
+		*(.data)						/* all .data sections  */
+		_edata = .;						/* define a global symbol marking the end of the .data section  */
+	} >ram AT >flash					/* put all the above into RAM (but load the LMA copy into FLASH) */
+
+	.bss :								/* collect all uninitialized .bss sections that go into RAM  */
+	{
+		_bss_start = .;					/* define a global symbol marking the start of the .bss section */
+		*(.bss)							/* all .bss sections  */
+	} >ram								/* put all the above in RAM (it will be cleared in the startup code */
+
+	. = ALIGN(4);						/* advance location counter to the next 32-bit boundary */
+	_bss_end = . ;						/* define a global symbol marking the end of the .bss section */
+}
+	_end = .;							/* define a global symbol marking the end of application RAM */
+	

+ 265 - 0
poc/lpc2148_usb/target/custom/main_custom.c

@@ -0,0 +1,265 @@
+/*
+	LPCUSB, an USB device driver for LPC microcontrollers	
+	Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library 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
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the Free Software
+	Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+/*
+	This is a very simple custom device (not belonging to a specific USB
+	class). It implements primitive read and write in the ARM memory space.
+	
+	Each transfer is initiated by a control transfer to inform the device
+	about the address and size of the following data transfer.
+	The data transfer takes place over a bulk endpoint (BULK_IN_EP for
+	reads and BULK_OUT_EP for writes).
+
+	This example can be used to measure USB transfer speed.
+*/
+
+#include "type.h"
+#include "usbdebug.h"
+
+#include "console.h"
+#include "usbapi.h"
+#include "startup.h"
+
+
+#define BULK_IN_EP		0x82
+#define BULK_OUT_EP		0x05
+
+#define MAX_PACKET_SIZE	64
+
+#define LE_WORD(x)		((x)&0xFF),((x)>>8)
+
+
+static const U8 abDescriptors[] = {
+
+/* Device descriptor */
+	0x12,              		
+	DESC_DEVICE,       		
+	LE_WORD(0x0200),		// bcdUSB	
+	0xFF,              		// bDeviceClass
+	0x00,              		// bDeviceSubClass
+	0x00,              		// bDeviceProtocol
+	MAX_PACKET_SIZE0,  		// bMaxPacketSize
+	LE_WORD(0xFFFF),		// idVendor
+	LE_WORD(0x0004),		// idProduct
+	LE_WORD(0x0100),		// bcdDevice
+	0x01,              		// iManufacturer
+	0x02,              		// iProduct
+	0x03,              		// iSerialNumber
+	0x01,              		// bNumConfigurations
+
+// configuration
+	0x09,
+	DESC_CONFIGURATION,
+	LE_WORD(0x20),  		// wTotalLength
+	0x01,  					// bNumInterfaces
+	0x01,  					// bConfigurationValue
+	0x00,  					// iConfiguration
+	0x80,  					// bmAttributes
+	0x32,  					// bMaxPower
+
+// interface
+	0x09,   				
+	DESC_INTERFACE, 
+	0x00,  		 			// bInterfaceNumber
+	0x00,   				// bAlternateSetting
+	0x02,   				// bNumEndPoints
+	0xFF,   				// bInterfaceClass
+	0x00,   				// bInterfaceSubClass
+	0x00,   				// bInterfaceProtocol
+	0x00,   				// iInterface
+
+// bulk in
+	0x07,   		
+	DESC_ENDPOINT,   		
+	BULK_IN_EP,				// bEndpointAddress
+	0x02,   				// bmAttributes = BULK
+	LE_WORD(MAX_PACKET_SIZE),// wMaxPacketSize
+	0,						// bInterval   		
+
+// bulk out
+	0x07,   		
+	DESC_ENDPOINT,   		
+	BULK_OUT_EP,			// bEndpointAddress
+	0x02,   				// bmAttributes = BULK
+	LE_WORD(MAX_PACKET_SIZE),// wMaxPacketSize
+	0,						// bInterval   		
+
+// string descriptors
+	0x04,
+	DESC_STRING,
+	LE_WORD(0x0409),
+
+	// manufacturer string
+	0x0E,
+	DESC_STRING,
+	'L', 0, 'P', 0, 'C', 0, 'U', 0, 'S', 0, 'B', 0,
+
+	// product string
+	0x1A,
+	DESC_STRING,
+	'M', 0, 'e', 0, 'm', 0, 'o', 0, 'r', 0, 'y', 0, 'A', 0, 'c', 0, 'c', 0, 'e', 0, 's', 0, 's', 0,
+
+	// serial number string
+	0x12,
+	DESC_STRING,
+	'D', 0, 'E', 0, 'A', 0, 'D', 0, 'C', 0, '0', 0, 'D', 0, 'E', 0,
+	
+	// terminator
+	0
+};
+
+
+typedef struct {
+	U32		dwAddress;
+	U32		dwLength;
+} TMemoryCmd;
+
+
+static TMemoryCmd	MemoryCmd;
+static U8			abVendorReqData[sizeof(TMemoryCmd)];
+
+
+static void _HandleBulkIn(U8 bEP, U8 bEPStatus)
+{
+	int iChunk;
+	
+	iChunk = MIN(MAX_PACKET_SIZE, MemoryCmd.dwLength);
+	if (iChunk == 0) {
+		DBG("_HandleBulkIn  done\n");
+		return;
+	}
+	
+	// send next part
+	USBHwEPWrite(bEP, (U8 *)MemoryCmd.dwAddress, iChunk);
+	
+	MemoryCmd.dwAddress += iChunk;
+	MemoryCmd.dwLength -= iChunk;
+
+	// limit address range to prevent abort
+	MemoryCmd.dwAddress &= ~(-512 * 1024);
+}
+
+
+static void _HandleBulkOut(U8 bEP, U8 bEPStatus)
+{
+	int iChunk;
+	
+	// get next part
+	iChunk = USBHwEPRead(bEP, NULL, 0);
+	
+	MemoryCmd.dwAddress += iChunk;
+	MemoryCmd.dwLength -= iChunk;	
+
+	if (MemoryCmd.dwLength == 0) {
+		DBG("_HandleBulkOut done\n");
+	}
+}
+
+
+/*************************************************************************
+	HandleVendorRequest
+	===================
+		Handles vendor specific requests
+		
+	Control transfer fields:
+	* request:	0x01 = prepare memory read
+				0x02 = prepare memory write
+	* index:	ignored
+	* value:	ignored
+	* data:		U32 dwAddress
+				U32 dwLength
+		
+**************************************************************************/
+static BOOL HandleVendorRequest(TSetupPacket *pSetup, int *piLen, U8 **ppbData)
+{
+	TMemoryCmd	*pCmd;
+	
+	pCmd = (TMemoryCmd *)*ppbData;
+
+	switch (pSetup->bRequest) {
+	
+	// prepare read
+	case 0x01:
+		MemoryCmd = *pCmd;
+		DBG("READ: addr=%X, len=%d\n", MemoryCmd.dwAddress, MemoryCmd.dwLength);
+		// send initial packet
+		_HandleBulkIn(BULK_IN_EP, 0);
+		*piLen = 0;
+		break;
+		
+	// prepare write
+	case 0x02:
+		MemoryCmd = *pCmd;
+		DBG("WRITE: addr=%X, len=%d\n", MemoryCmd.dwAddress, MemoryCmd.dwLength);
+		*piLen = 0;
+		break;
+
+	default:
+		DBG("Unhandled class %X\n", pSetup->bRequest);
+		return FALSE;
+	}
+	return TRUE;
+}
+
+
+
+
+#define BAUD_RATE 57600
+
+
+/*************************************************************************
+	main
+	====
+**************************************************************************/
+int main(void)
+{
+	// PLL and MAM
+	Initialize();
+
+	// init DBG
+	ConsoleInit(60000000 / (16 * BAUD_RATE));
+
+	DBG("Initialising USB stack\n");
+	
+	// initialise stack
+	USBInit();
+	
+	// register device descriptors
+	USBRegisterDescriptors(abDescriptors);
+
+	// override standard request handler
+	USBRegisterRequestHandler(REQTYPE_TYPE_VENDOR, HandleVendorRequest, abVendorReqData);
+
+	// register endpoints
+	USBHwRegisterEPIntHandler(BULK_IN_EP, _HandleBulkIn);
+	USBHwRegisterEPIntHandler(BULK_OUT_EP, _HandleBulkOut);
+
+	DBG("Starting USB communication\n");
+
+	// connect to bus
+	USBHwConnect(TRUE);
+
+	// call USB interrupt handler continuously
+	while (1) {
+		USBHwISR();
+	}
+	
+	return 0;
+}
+

+ 268 - 0
poc/lpc2148_usb/target/custom/printf.c

@@ -0,0 +1,268 @@
+/*
+	Copyright 2001, 2002 Georges Menie (www.menie.org)
+	stdarg version contributed by Christian Ettinger
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser 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
+*/
+
+/*
+	putchar is the only external dependency for this file,
+	if you have a working putchar, leave it commented out.
+	If not, uncomment the define below and
+	replace outbyte(c) by your own function call.
+
+#define putchar(c) outbyte(c)
+*/
+
+#include <stdarg.h>
+#include "console.h"
+
+
+static void printchar(char **str, int c)
+{
+	if (str) {
+		**str = c;
+		++(*str);
+	}
+	else {
+		putchar(c);
+	}
+}
+
+#define PAD_RIGHT 1
+#define PAD_ZERO 2
+
+static int prints(char **out, const char *string, int width, int pad)
+{
+	register int pc = 0, padchar = ' ';
+
+	if (width > 0) {
+		register int len = 0;
+		register const char *ptr;
+		for (ptr = string; *ptr; ++ptr) ++len;
+		if (len >= width) width = 0;
+		else width -= len;
+		if (pad & PAD_ZERO) padchar = '0';
+	}
+	if (!(pad & PAD_RIGHT)) {
+		for ( ; width > 0; --width) {
+			printchar (out, padchar);
+			++pc;
+		}
+	}
+	for ( ; *string ; ++string) {
+		printchar (out, *string);
+		++pc;
+	}
+	for ( ; width > 0; --width) {
+		printchar (out, padchar);
+		++pc;
+	}
+
+	return pc;
+}
+
+/* the following should be enough for 32 bit int */
+#define PRINT_BUF_LEN 12
+
+static int printi(char **out, int i, int b, int sg, int width, int pad, int letbase)
+{
+	char print_buf[PRINT_BUF_LEN];
+	register char *s;
+	register int t, neg = 0, pc = 0;
+	register unsigned int u = i;
+
+	if (i == 0) {
+		print_buf[0] = '0';
+		print_buf[1] = '\0';
+		return prints (out, print_buf, width, pad);
+	}
+
+	if (sg && b == 10 && i < 0) {
+		neg = 1;
+		u = -i;
+	}
+
+	s = print_buf + PRINT_BUF_LEN-1;
+	*s = '\0';
+
+	while (u) {
+		t = u % b;
+		if( t >= 10 )
+			t += letbase - '0' - 10;
+		*--s = t + '0';
+		u /= b;
+	}
+
+	if (neg) {
+		if( width && (pad & PAD_ZERO) ) {
+			printchar (out, '-');
+			++pc;
+			--width;
+		}
+		else {
+			*--s = '-';
+		}
+	}
+
+	return pc + prints (out, s, width, pad);
+}
+
+static int print(char **out, const char *format, va_list args )
+{
+	register int width, pad;
+	register int pc = 0;
+	char scr[2];
+
+	for (; *format != 0; ++format) {
+		if (*format == '%') {
+			++format;
+			width = pad = 0;
+			if (*format == '\0') break;
+			if (*format == '%') goto out;
+			if (*format == '-') {
+				++format;
+				pad = PAD_RIGHT;
+			}
+			while (*format == '0') {
+				++format;
+				pad |= PAD_ZERO;
+			}
+			for ( ; *format >= '0' && *format <= '9'; ++format) {
+				width *= 10;
+				width += *format - '0';
+			}
+			if( *format == 's' ) {
+				register char *s = (char *)va_arg( args, int );
+				pc += prints (out, s?s:"(null)", width, pad);
+				continue;
+			}
+			if( *format == 'd' ) {
+				pc += printi (out, va_arg( args, int ), 10, 1, width, pad, 'a');
+				continue;
+			}
+			if( *format == 'x' ) {
+				pc += printi (out, va_arg( args, int ), 16, 0, width, pad, 'a');
+				continue;
+			}
+			if( *format == 'X' ) {
+				pc += printi (out, va_arg( args, int ), 16, 0, width, pad, 'A');
+				continue;
+			}
+			if( *format == 'u' ) {
+				pc += printi (out, va_arg( args, int ), 10, 0, width, pad, 'a');
+				continue;
+			}
+			if( *format == 'c' ) {
+				/* char are converted to int then pushed on the stack */
+				scr[0] = (char)va_arg( args, int );
+				scr[1] = '\0';
+				pc += prints (out, scr, width, pad);
+				continue;
+			}
+		}
+		else {
+		out:
+			printchar (out, *format);
+			++pc;
+		}
+	}
+	if (out) **out = '\0';
+	va_end( args );
+	return pc;
+}
+
+int printf(const char *format, ...)
+{
+        va_list args;
+        
+        va_start( args, format );
+        return print( 0, format, args );
+}
+
+int sprintf(char *out, const char *format, ...)
+{
+        va_list args;
+        
+        va_start( args, format );
+        return print( &out, format, args );
+}
+
+#ifdef TEST_PRINTF
+int main(void)
+{
+	char *ptr = "Hello world!";
+	char *np = 0;
+	int i = 5;
+	unsigned int bs = sizeof(int)*8;
+	int mi;
+	char buf[80];
+
+	mi = (1 << (bs-1)) + 1;
+	printf("%s\n", ptr);
+	printf("printf test\n");
+	printf("%s is null pointer\n", np);
+	printf("%d = 5\n", i);
+	printf("%d = - max int\n", mi);
+	printf("char %c = 'a'\n", 'a');
+	printf("hex %x = ff\n", 0xff);
+	printf("hex %02x = 00\n", 0);
+	printf("signed %d = unsigned %u = hex %x\n", -3, -3, -3);
+	printf("%d %s(s)%", 0, "message");
+	printf("\n");
+	printf("%d %s(s) with %%\n", 0, "message");
+	sprintf(buf, "justif: \"%-10s\"\n", "left"); printf("%s", buf);
+	sprintf(buf, "justif: \"%10s\"\n", "right"); printf("%s", buf);
+	sprintf(buf, " 3: %04d zero padded\n", 3); printf("%s", buf);
+	sprintf(buf, " 3: %-4d left justif.\n", 3); printf("%s", buf);
+	sprintf(buf, " 3: %4d right justif.\n", 3); printf("%s", buf);
+	sprintf(buf, "-3: %04d zero padded\n", -3); printf("%s", buf);
+	sprintf(buf, "-3: %-4d left justif.\n", -3); printf("%s", buf);
+	sprintf(buf, "-3: %4d right justif.\n", -3); printf("%s", buf);
+
+	return 0;
+}
+
+/*
+ * if you compile this file with
+ *   gcc -Wall $(YOUR_C_OPTIONS) -DTEST_PRINTF -c printf.c
+ * you will get a normal warning:
+ *   printf.c:214: warning: spurious trailing `%' in format
+ * this line is testing an invalid % at the end of the format string.
+ *
+ * this should display (on 32bit int machine) :
+ *
+ * Hello world!
+ * printf test
+ * (null) is null pointer
+ * 5 = 5
+ * -2147483647 = - max int
+ * char a = 'a'
+ * hex ff = ff
+ * hex 00 = 00
+ * signed -3 = unsigned 4294967293 = hex fffffffd
+ * 0 message(s)
+ * 0 message(s) with %
+ * justif: "left      "
+ * justif: "     right"
+ *  3: 0003 zero padded
+ *  3: 3    left justif.
+ *  3:    3 right justif.
+ * -3: -003 zero padded
+ * -3: -3   left justif.
+ * -3:   -3 right justif.
+ */
+
+#endif

+ 126 - 0
poc/lpc2148_usb/target/custom/startup.c

@@ -0,0 +1,126 @@
+/*
+	Initialisation functions for exception handlers, PLL and MAM
+	
+	Partially copied from Jim Lynch's tutorial
+*/
+
+/**********************************************************
+                  Header files
+ **********************************************************/
+
+#include "startup.h"
+
+
+#define MAMCR		*(volatile unsigned int *)0xE01FC000
+#define MAMTIM		*(volatile unsigned int *)0xE01FC004
+
+#define PLLCON		*(volatile unsigned int *)0xE01FC080
+#define PLLCFG		*(volatile unsigned int *)0xE01FC084
+#define PLLSTAT		*(volatile unsigned int *)0xE01FC088
+#define PLLFEED		*(volatile unsigned int *)0xE01FC08C
+
+#define VPBDIV		*(volatile unsigned int *)0xE01FC100
+
+void IRQ_Routine (void)   __attribute__ ((interrupt("IRQ")));
+void FIQ_Routine (void)   __attribute__ ((interrupt("FIQ")));
+void SWI_Routine (void)   __attribute__ ((interrupt("SWI")));
+void UNDEF_Routine (void) __attribute__ ((interrupt("UNDEF")));
+
+
+/*  Stubs for various interrupts (may be replaced later)  */
+/*  ----------------------------------------------------  */
+
+void IRQ_Routine (void) {
+	while (1) ;	
+}
+
+void FIQ_Routine (void)  {
+	while (1) ;	
+}
+
+
+void SWI_Routine (void)  {
+	while (1) ;	
+}
+
+
+void UNDEF_Routine (void) {
+	while (1) ;	
+}
+
+
+/**********************************************************
+                      Initialize
+**********************************************************/
+
+#define PLOCK 0x400
+
+static void feed(void)
+{
+	PLLFEED = 0xAA;
+	PLLFEED = 0x55;
+}
+
+
+void Initialize(void)  
+{
+	
+ 
+	// 				Setting the Phased Lock Loop (PLL)
+	//               ----------------------------------
+	//
+	// Olimex LPC-P2148 has a 12.0000 mhz crystal
+	//
+	// We'd like the LPC2148 to run at 60 mhz (has to be an even multiple of crystal)
+	// 
+	// According to the Philips LPC2148 manual:   M = cclk / Fosc	where:	M    = PLL multiplier (bits 0-4 of PLLCFG)
+	//																		cclk = 60000000 hz
+	//																		Fosc = 12000000 hz
+	//
+	// Solving:	M = 60000000 / 12000000 = 5           
+	//
+	//			Note: M - 1 must be entered into bits 0-4 of PLLCFG (assign 4 to these bits)
+	//
+	//
+	// The Current Controlled Oscilator (CCO) must operate in the range 156 mhz to 320 mhz
+	//
+	// According to the Philips LPC2148 manual:	Fcco = cclk * 2 * P    where:	Fcco = CCO frequency 
+	//																			cclk = 60000000 hz
+	//																			P = PLL divisor (bits 5-6 of PLLCFG)
+	//
+	// Solving:	Fcco = 60000000 * 2 * P
+	//			P = 2  (trial value)
+	//			Fcco = 60000000 * 2 * 2
+	//			Fcc0 = 240000000 hz    (good choice for P since it's within the 156 mhz to 320 mhz range)
+	//
+	// From Table 22 (page 34) of Philips LPC2148 manual    P = 2, PLLCFG bits 5-6 = 1  (assign 1 to these bits)
+	//
+	// Finally:      PLLCFG = 0  01  00100  =  0x24
+	//
+	// Final note: to load PLLCFG register, we must use the 0xAA followed 0x55 write sequence to the PLLFEED register
+	//             this is done in the short function feed() below
+	//
+   
+	// Setting Multiplier and Divider values
+  	PLLCFG = 0x24;
+  	feed();
+  
+	// Enabling the PLL */	
+	PLLCON = 0x1;
+	feed();
+  
+	// Wait for the PLL to lock to set frequency
+	while(!(PLLSTAT & PLOCK)) ;
+  
+	// Connect the PLL as the clock source
+	PLLCON = 0x3;
+	feed();
+  
+	// Enabling MAM and setting number of clocks used for Flash memory fetch
+	MAMTIM = 0x3;
+	MAMCR = 0x2;
+  
+	// Setting peripheral Clock (pclk) to System Clock (cclk)
+	VPBDIV = 0x1;
+}
+

+ 2 - 0
poc/lpc2148_usb/target/custom/startup.h

@@ -0,0 +1,2 @@
+void Initialize(void);
+

+ 31 - 0
poc/lpc2148_usb/target/lpcusb.tmproj

@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>documents</key>
+	<array>
+		<dict>
+			<key>name</key>
+			<string>lpcusb</string>
+			<key>regexFolderFilter</key>
+			<string>!.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$</string>
+			<key>selected</key>
+			<true/>
+			<key>sourceDirectory</key>
+			<string></string>
+		</dict>
+	</array>
+	<key>fileHierarchyDrawerWidth</key>
+	<integer>200</integer>
+	<key>metaData</key>
+	<dict/>
+	<key>showFileHierarchyDrawer</key>
+	<false/>
+	<key>showFileHierarchyPanel</key>
+	<true/>
+	<key>treeState</key>
+	<dict/>
+	<key>windowFrame</key>
+	<string>{{0, 58}, {721, 820}}</string>
+</dict>
+</plist>

+ 31 - 0
poc/lpc2148_usb/target/type.h

@@ -0,0 +1,31 @@
+/**
+	@file
+	primitive types used in the USB stack
+	
+	(c) 2006, Bertrik Sikken, bertrik@sikken.nl
+ */
+
+
+#ifndef _TYPE_H_
+#define _TYPE_H_
+
+typedef unsigned char		U8;		/**< unsigned 8-bit */
+typedef unsigned short int	U16;	/**< unsigned 16-bit */
+typedef unsigned int		U32;	/**< unsigned 32-bit */
+
+typedef int					BOOL;	/**< #TRUE or #FALSE */
+
+#define	TRUE	1					/**< TRUE */
+#define FALSE	0					/**< FALSE */
+
+#ifndef NULL
+#define NULL	((void*)0)			/**< NULL pointer */
+#endif
+
+/* some other useful macros */
+#define MIN(x,y)	((x)<(y)?(x):(y))	/**< MIN */
+#define MAX(x,y)	((x)>(y)?(x):(y))	/**< MAX */
+
+
+#endif /* _TYPE_H_ */
+

+ 95 - 0
poc/lpc2148_usb/target/usbapi.h

@@ -0,0 +1,95 @@
+/**
+	(c) 2006, Bertrik Sikken, bertrik@sikken.nl
+	
+	@file
+*/
+
+
+#include "type.h"
+#include "usbstruct.h"		// for TSetupPacket
+
+/*************************************************************************
+	USB configuration
+**************************************************************************/
+
+#define MAX_PACKET_SIZE0	64		/**< maximum packet size for EP 0 */
+
+/*************************************************************************
+	USB hardware interface
+**************************************************************************/
+
+// endpoint status sent through callback
+#define EP_STATUS_DATA		(1<<0)		/**< EP has data */
+#define EP_STATUS_STALLED	(1<<1)		/**< EP is stalled */
+#define EP_STATUS_SETUP		(1<<2)		/**< EP received setup packet */
+#define EP_STATUS_NACKED	(1<<3)		/**< EP sent NAK */
+#define EP_STATUS_ERROR		(1<<4)		/**< EP data was overwritten by setup packet */
+
+// device status sent through callback
+#define DEV_STATUS_CONNECT		(1<<0)	/**< device just got connected */
+#define DEV_STATUS_SUSPEND		(1<<2)	/**< device entered suspend state */
+#define DEV_STATUS_RESET		(1<<4)	/**< device just got reset */
+
+// interrupt bits for NACK events in USBHwNakIntEnable
+// (these bits conveniently coincide with the LPC214x USB controller bit)
+#define INACK_CI		(1<<1)			/**< interrupt on NACK for control in */
+#define INACK_CO		(1<<2)			/**< interrupt on NACK for control out */
+#define INACK_II		(1<<3)			/**< interrupt on NACK for interrupt in */
+#define INACK_IO		(1<<4)			/**< interrupt on NACK for interrupt out */
+#define INACK_BI		(1<<5)			/**< interrupt on NACK for bulk in */
+#define INACK_BO		(1<<6)			/**< interrupt on NACK for bulk out */
+
+BOOL USBHwInit			(void);
+void USBHwISR			(void);
+
+void USBHwNakIntEnable	(U8 bIntBits);
+
+void USBHwConnect		(BOOL fConnect);
+
+void USBHwSetAddress	(U8 bAddr);
+void USBHwConfigDevice	(BOOL fConfigured);
+
+// endpoint operations
+void USBHwEPConfig		(U8 bEP, U16 wMaxPacketSize);
+int  USBHwEPRead		(U8 bEP, U8 *pbBuf, int iMaxLen);
+int	 USBHwEPWrite		(U8 bEP, U8 *pbBuf, int iLen);
+void USBHwEPStall		(U8 bEP, BOOL fStall);
+BOOL USBHwEPIsStalled	(U8 bEP);
+
+/** Endpoint interrupt handler callback */
+typedef void (TFnEPIntHandler)	(U8 bEP, U8 bEPStatus);
+void USBHwRegisterEPIntHandler	(U8 bEP, TFnEPIntHandler *pfnHandler);
+
+/** Device status handler callback */
+typedef void (TFnDevIntHandler)	(U8 bDevStatus);
+void USBHwRegisterDevIntHandler	(TFnDevIntHandler *pfnHandler);
+
+/** Frame event handler callback */
+typedef void (TFnFrameHandler)(U16 wFrame);
+void USBHwRegisterFrameHandler(TFnFrameHandler *pfnHandler);
+
+
+/*************************************************************************
+	USB application interface
+**************************************************************************/
+
+// initialise the complete stack, including HW
+BOOL USBInit(void);
+
+/** Request handler callback (standard, vendor, class) */
+typedef BOOL (TFnHandleRequest)(TSetupPacket *pSetup, int *piLen, U8 **ppbData);
+void USBRegisterRequestHandler(int iType, TFnHandleRequest *pfnHandler, U8 *pbDataStore);
+void USBRegisterCustomReqHandler(TFnHandleRequest *pfnHandler);
+
+/** Descriptor handler callback */
+typedef BOOL (TFnGetDescriptor)(U16 wTypeIndex, U16 wLangID, int *piLen, U8 **ppbData);
+
+/** Default standard request handler */
+BOOL USBHandleStandardRequest(TSetupPacket *pSetup, int *piLen, U8 **ppbData);
+
+/** Default EP0 handler */
+void USBHandleControlTransfer(U8 bEP, U8 bEPStat);
+
+/** Descriptor handling */
+void USBRegisterDescriptors(const U8 *pabDescriptors);
+BOOL USBGetDescriptor(U16 wTypeIndex, U16 wLangID, int *piLen, U8 **ppbData);

+ 222 - 0
poc/lpc2148_usb/target/usbcontrol.c

@@ -0,0 +1,222 @@
+/*
+	LPCUSB, an USB device driver for LPC microcontrollers	
+	Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library 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
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the Free Software
+	Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+/** @file
+	Control transfer handler.
+
+	In case of a control-write (host-to-device), this module collects the full
+	control message in a local buffer, then sends it off to an installed
+	request handler.
+
+	In case of a control-read (device-to-host), an installed request handler
+	is asked to handle the request and provide return data. The handler can
+	either put the data in the control data buffer through the supplied pointer,
+	or it can supply a new data pointer. In both cases, the handler is required
+	to update the data length in *piLen;
+
+
+	Currently, control transfers are handled in a very simple way, keeping
+	almost no state about the control transfer progress (setup stage, data
+	stage, status stage). We simply follow the host: if it sends data, we store
+	it in the control data buffer and if it asks for data, we just send the next
+	block.
+	
+*/
+
+#include "type.h"
+#include "usbdebug.h"
+
+#include "usbstruct.h"
+#include "usbapi.h"
+
+
+
+#define	MAX_CONTROL_SIZE	128	/**< maximum total size of control transfer data */
+#define	MAX_REQ_HANDLERS	4	/**< standard, class, vendor, reserved */
+
+static TSetupPacket		Setup;	/**< setup packet */
+
+static U8				*pbData;	/**< pointer to data buffer */
+static int				iResidue;	/**< remaining bytes in buffer */
+static int				iLen;		/**< total length of control transfer */
+
+/** Array of installed request handler callbacks */
+static TFnHandleRequest *apfnReqHandlers[4] = {NULL, NULL, NULL, NULL};
+/** Array of installed request data pointers */
+static U8				*apbDataStore[4] = {NULL, NULL, NULL, NULL};
+
+/**
+	Local function to handle a request by calling one of the installed
+	request handlers.
+		
+	In case of data going from host to device, the data is at *ppbData.
+	In case of data going from device to host, the handler can either
+	choose to write its data at *ppbData or update the data pointer.
+		
+	@param [in]		pSetup		The setup packet
+	@param [in,out]	*piLen		Pointer to data length
+	@param [in,out]	ppbData		Data buffer.
+
+	@return TRUE if the request was handles successfully
+ */
+static BOOL _HandleRequest(TSetupPacket *pSetup, int *piLen, U8 **ppbData)
+{
+	TFnHandleRequest *pfnHandler;
+	int iType;
+	
+	iType = REQTYPE_GET_TYPE(pSetup->bmRequestType);
+	pfnHandler = apfnReqHandlers[iType];
+	if (pfnHandler == NULL) {
+		DBG("No handler for reqtype %d\n", iType);
+		return FALSE;
+	}
+
+	return pfnHandler(pSetup, piLen, ppbData);
+}
+
+
+/**
+	Local function to stall the control endpoint
+	
+	@param [in]	bEPStat	Endpoint status
+ */
+static void StallControlPipe(U8 bEPStat)
+{
+	U8	*pb;
+	int	i;
+
+	USBHwEPStall(0x80, TRUE);
+
+// dump setup packet
+	DBG("STALL on [");
+	pb = (U8 *)&Setup;
+	for (i = 0; i < 8; i++) {
+		DBG(" %02x", *pb++);
+	}
+	DBG("] stat=%x\n", bEPStat);
+}
+
+
+/**
+	Sends next chunk of data (possibly 0 bytes) to host
+ */
+static void DataIn(void)
+{
+	int iChunk;
+
+	iChunk = MIN(MAX_PACKET_SIZE0, iResidue);
+	USBHwEPWrite(0x80, pbData, iChunk);
+	pbData += iChunk;
+	iResidue -= iChunk;
+}
+
+
+/**
+ *	Handles IN/OUT transfers on EP0
+ *
+ *	@param [in]	bEP		Endpoint address
+ *	@param [in]	bEPStat	Endpoint status
+ */
+void USBHandleControlTransfer(U8 bEP, U8 bEPStat)
+{
+	int iChunk, iType;
+
+	if (bEP == 0x00) {
+		// OUT transfer
+		if (bEPStat & EP_STATUS_SETUP) {
+			// setup packet, reset request message state machine
+			USBHwEPRead(0x00, (U8 *)&Setup, sizeof(Setup));
+			DBG("S%x", Setup.bRequest);
+
+			// defaults for data pointer and residue
+			iType = REQTYPE_GET_TYPE(Setup.bmRequestType);
+			pbData = apbDataStore[iType];
+			iResidue = Setup.wLength;
+			iLen = Setup.wLength;
+
+			if ((Setup.wLength == 0) ||
+				(REQTYPE_GET_DIR(Setup.bmRequestType) == REQTYPE_DIR_TO_HOST)) {
+				// ask installed handler to process request
+				if (!_HandleRequest(&Setup, &iLen, &pbData)) {
+					DBG("_HandleRequest1 failed\n");
+					StallControlPipe(bEPStat);
+					return;
+				}
+				// send smallest of requested and offered length
+				iResidue = MIN(iLen, Setup.wLength);
+				// send first part (possibly a zero-length status message)
+				DataIn();
+			}
+		}
+		else {		
+			if (iResidue > 0) {
+				// store data
+				iChunk = USBHwEPRead(0x00, pbData, iResidue);
+				if (iChunk < 0) {
+					StallControlPipe(bEPStat);
+					return;
+				}
+				pbData += iChunk;
+				iResidue -= iChunk;
+				if (iResidue == 0) {
+					// received all, send data to handler
+					iType = REQTYPE_GET_TYPE(Setup.bmRequestType);
+					pbData = apbDataStore[iType];
+					if (!_HandleRequest(&Setup, &iLen, &pbData)) {
+						DBG("_HandleRequest2 failed\n");
+						StallControlPipe(bEPStat);
+						return;
+					}
+					// send status to host
+					DataIn();
+				}
+			}
+			else {
+				// absorb zero-length status message
+				iChunk = USBHwEPRead(0x00, NULL, 0);
+				DBG(iChunk > 0 ? "?" : "");
+			}
+		}
+	}
+	else if (bEP == 0x80) {
+		// IN transfer
+		// send more data if available (possibly a 0-length packet)
+		DataIn();
+	}
+	else {
+		ASSERT(FALSE);
+	}
+}
+
+
+/**
+	Registers a callback for handling requests
+		
+	@param [in]	iType			Type of request, e.g. REQTYPE_TYPE_STANDARD
+	@param [in]	*pfnHandler		Callback function pointer
+	@param [in]	*pbDataStore	Data storage area for this type of request
+ */
+void USBRegisterRequestHandler(int iType, TFnHandleRequest *pfnHandler, U8 *pbDataStore)
+{
+	ASSERT(iType >= 0);
+	ASSERT(iType < 4);
+	apfnReqHandlers[iType] = pfnHandler;
+	apbDataStore[iType] = pbDataStore;
+}
+

+ 12 - 0
poc/lpc2148_usb/target/usbdebug.h

@@ -0,0 +1,12 @@
+
+
+int printf(const char *format, ...);
+
+#ifdef DEBUG
+#define DBG	printf
+#define ASSERT(x)	if(!(x)){DBG("\nAssertion '%s' failed in %s:%s#%d!\n",#x,__FILE__,__FUNCTION__,__LINE__);while(1);}
+#else
+#define DBG(x ...)
+#define ASSERT(x)
+#endif
+

+ 541 - 0
poc/lpc2148_usb/target/usbhw_lpc.c

@@ -0,0 +1,541 @@
+/*
+	LPCUSB, an USB device driver for LPC microcontrollers	
+	Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library 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
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the Free Software
+	Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+/** @file
+	USB hardware layer
+ */
+
+#include "type.h"
+#include "usbdebug.h"
+#include "usbhw_lpc.h"
+#include "usbapi.h"
+
+
+#ifdef DEBUG
+// comment out the following line if you don't want to use debug LEDs
+#define DEBUG_LED
+#endif
+
+#ifdef DEBUG_LED
+#define DEBUG_LED_ON(x)		IOCLR0 = (1 << x);
+#define DEBUG_LED_OFF(x)	IOSET0 = (1 << x);
+#define DEBUG_LED_INIT(x)	PINSEL0 &= ~(0x3 << (2*x)); IODIR0 |= (1 << x); DEBUG_LED_OFF(x);
+#else
+#define DEBUG_LED_INIT(x)	/**< LED initialisation macro */
+#define DEBUG_LED_ON(x)		/**< turn LED on */
+#define DEBUG_LED_OFF(x)	/**< turn LED off */
+#endif
+
+/** Installed device interrupt handler */
+static TFnDevIntHandler *_pfnDevIntHandler = NULL;
+/** Installed endpoint interrupt handlers */
+static TFnEPIntHandler	*_apfnEPIntHandlers[16];
+/** Installed frame interrupt handlers */
+static TFnFrameHandler	*_pfnFrameHandler = NULL;
+
+/** convert from endpoint address to endpoint index */
+#define EP2IDX(bEP)	((((bEP)&0xF)<<1)|(((bEP)&0x80)>>7))
+/** convert from endpoint index to endpoint address */
+#define IDX2EP(idx)	((((idx)<<7)&0x80)|(((idx)>>1)&0xF))
+
+
+
+/**
+	Local function to wait for a device interrupt (and clear it)
+		
+	@param [in]	dwIntr		Interrupts to wait for	
+ */
+static void Wait4DevInt(U32 dwIntr)
+{
+	while ((USBDevIntSt & dwIntr) != dwIntr);
+	USBDevIntClr = dwIntr;
+}
+
+
+/**
+	Local function to send a command to the USB protocol engine
+		
+	@param [in]	bCmd		Command to send
+ */
+static void USBHwCmd(U8 bCmd)
+{
+	// clear CDFULL/CCEMTY
+	USBDevIntClr = CDFULL | CCEMTY;
+	// write command code
+	USBCmdCode = 0x00000500 | (bCmd << 16);
+	Wait4DevInt(CCEMTY);
+}
+
+
+/**
+	Local function to send a command + data to the USB protocol engine
+		
+	@param [in]	bCmd		Command to send
+	@param [in]	bData		Data to send
+ */
+static void USBHwCmdWrite(U8 bCmd, U16 bData)
+{
+	// write command code
+	USBHwCmd(bCmd);
+
+	// write command data
+	USBCmdCode = 0x00000100 | (bData << 16);
+	Wait4DevInt(CCEMTY);
+}
+
+
+/**
+	Local function to send a command to the USB protocol engine and read data
+		
+	@param [in]	bCmd		Command to send
+
+	@return the data
+ */
+static U8 USBHwCmdRead(U8 bCmd)
+{
+	// write command code
+	USBHwCmd(bCmd);
+	
+	// get data
+	USBCmdCode = 0x00000200 | (bCmd << 16);
+	Wait4DevInt(CDFULL);
+	return USBCmdData;
+}
+
+
+/**
+	'Realizes' an endpoint, meaning that buffer space is reserved for
+	it. An endpoint needs to be realised before it can be used.
+		
+	From experiments, it appears that a USB reset causes USBReEP to
+	re-initialise to 3 (= just the control endpoints).
+	However, a USB bus reset does not disturb the USBMaxPSize settings.
+		
+	@param [in]	idx			Endpoint index
+	@param [in] wMaxPSize	Maximum packet size for this endpoint
+ */
+static void USBHwEPRealize(int idx, U16 wMaxPSize)
+{
+	USBReEP |= (1 << idx);
+	USBEpInd = idx;
+	USBMaxPSize = wMaxPSize;
+	Wait4DevInt(EP_RLZED);
+}
+
+
+/**
+	Enables or disables an endpoint
+		
+	@param [in]	idx		Endpoint index
+	@param [in]	fEnable	TRUE to enable, FALSE to disable
+ */
+static void USBHwEPEnable(int idx, BOOL fEnable)
+{
+	USBHwCmdWrite(CMD_EP_SET_STATUS | idx, fEnable ? 0 : EP_DA);
+}
+
+
+/**
+	Configures an endpoint and enables it
+		
+	@param [in]	bEP				Endpoint number
+	@param [in]	wMaxPacketSize	Maximum packet size for this EP
+ */
+void USBHwEPConfig(U8 bEP, U16 wMaxPacketSize)
+{
+	int idx;
+	
+	idx = EP2IDX(bEP);
+	
+	// realise EP
+	USBHwEPRealize(idx, wMaxPacketSize);
+
+	// enable EP
+	USBHwEPEnable(idx, TRUE);
+}
+
+
+/**
+	Registers an endpoint event callback
+		
+	@param [in]	bEP				Endpoint number
+	@param [in]	pfnHandler		Callback function
+ */
+void USBHwRegisterEPIntHandler(U8 bEP, TFnEPIntHandler *pfnHandler)
+{
+	int idx;
+	
+	idx = EP2IDX(bEP);
+
+	ASSERT(idx<32);
+
+	/* add handler to list of EP handlers */
+	_apfnEPIntHandlers[idx / 2] = pfnHandler;
+	
+	/* enable EP interrupt */
+	USBEpIntEn |= (1 << idx);
+	USBDevIntEn |= EP_SLOW;
+	
+	DBG("Registered handler for EP 0x%x\n", bEP);
+}
+
+
+/**
+	Registers an device status callback
+		
+	@param [in]	pfnHandler	Callback function
+ */
+void USBHwRegisterDevIntHandler(TFnDevIntHandler *pfnHandler)
+{
+	_pfnDevIntHandler = pfnHandler;
+	
+	// enable device interrupt
+	USBDevIntEn |= DEV_STAT;
+
+	DBG("Registered handler for device status\n");
+}
+
+
+/**
+	Registers the frame callback
+		
+	@param [in]	pfnHandler	Callback function
+ */
+void USBHwRegisterFrameHandler(TFnFrameHandler *pfnHandler)
+{
+	_pfnFrameHandler = pfnHandler;
+	
+	// enable device interrupt
+	USBDevIntEn |= FRAME;
+
+	DBG("Registered handler for frame\n");
+}
+
+
+/**
+	Sets the USB address.
+		
+	@param [in]	bAddr		Device address to set
+ */
+void USBHwSetAddress(U8 bAddr)
+{
+	USBHwCmdWrite(CMD_DEV_SET_ADDRESS, DEV_EN | bAddr);
+}
+
+
+/**
+	Connects or disconnects from the USB bus
+		
+	@param [in]	fConnect	If TRUE, connect, otherwise disconnect
+ */
+void USBHwConnect(BOOL fConnect)
+{
+	USBHwCmdWrite(CMD_DEV_STATUS, fConnect ? CON : 0);
+}
+
+
+/**
+	Enables interrupt on NAK condition
+		
+	For IN endpoints a NAK is generated when the host wants to read data
+	from the device, but none is available in the endpoint buffer.
+	For OUT endpoints a NAK is generated when the host wants to write data
+	to the device, but the endpoint buffer is still full.
+	
+	The endpoint interrupt handlers can distinguish regular (ACK) interrupts
+	from NAK interrupt by checking the bits in their bEPStatus argument.
+	
+	@param [in]	bIntBits	Bitmap indicating which NAK interrupts to enable
+ */
+void USBHwNakIntEnable(U8 bIntBits)
+{
+	USBHwCmdWrite(CMD_DEV_SET_MODE, bIntBits);
+}
+
+
+/**
+	Gets the stalled property of an endpoint
+		
+	@param [in]	bEP		Endpoint number
+			
+	@return TRUE if stalled, FALSE if not stalled
+ */
+BOOL USBHwEPIsStalled(U8 bEP)
+{
+   	int idx = EP2IDX(bEP);
+
+	return (USBHwCmdRead(CMD_EP_SELECT | idx) & 2);
+}
+
+
+/**
+	Sets the stalled property of an endpoint
+		
+	@param [in]	bEP		Endpoint number
+	@param [in]	fStall	TRUE to stall, FALSE to unstall
+ */
+void USBHwEPStall(U8 bEP, BOOL fStall)
+{
+	int idx = EP2IDX(bEP);
+
+	USBHwCmdWrite(CMD_EP_SET_STATUS | idx, fStall ? EP_ST : 0);
+}
+
+
+/**
+	Writes data to an endpoint buffer
+		
+	@param [in]	bEP		Endpoint number
+	@param [in]	pbBuf	Endpoint data
+	@param [in]	iLen	Number of bytes to write
+			
+	@return TRUE if the data was successfully written or <0 in case of error.
+*/
+int USBHwEPWrite(U8 bEP, U8 *pbBuf, int iLen)
+{
+	int idx;
+	
+	idx = EP2IDX(bEP);
+	
+//	DBG("<%d", iLen);
+//	DBG("<");
+
+	// set write enable for specific endpoint
+	USBCtrl = WR_EN | ((bEP & 0xF) << 2);
+	
+	// set packet length
+	USBTxPLen = iLen;
+	
+	// write data
+	while (USBCtrl & WR_EN) {
+		USBTxData = (pbBuf[3] << 24) | (pbBuf[2] << 16) | (pbBuf[1] << 8) | pbBuf[0];
+		pbBuf += 4;
+	}
+
+	// select endpoint and validate buffer
+	USBHwCmd(CMD_EP_SELECT | idx);
+	USBHwCmd(CMD_EP_VALIDATE_BUFFER);
+	
+	return iLen;
+}
+
+
+/**
+	Reads data from an endpoint buffer
+		
+	@param [in]	bEP		Endpoint number
+	@param [in]	pbBuf	Endpoint data
+	@param [in]	iMaxLen	Maximum number of bytes to read
+			
+	@return the number of bytes available in the EP (possibly more than iMaxLen),
+	or <0 in case of error.
+ */
+int USBHwEPRead(U8 bEP, U8 *pbBuf, int iMaxLen)
+{
+	int i, idx;
+	U32	dwData, dwLen;
+	
+	idx = EP2IDX(bEP);
+	
+	// set read enable bit for specific endpoint
+	USBCtrl = RD_EN | ((bEP & 0xF) << 2);
+	
+	// wait for PKT_RDY
+	do {
+		dwLen = USBRxPLen;
+	} while ((dwLen & PKT_RDY) == 0);
+	
+	// packet valid?
+	if ((dwLen & DV) == 0) {
+		return -1;
+	}
+	
+	// get length
+	dwLen &= PKT_LNGTH_MASK;
+	
+	// get data
+	while (USBCtrl & RD_EN) {
+		dwData = USBRxData;
+		if (pbBuf != NULL) {
+			for (i = 0; i < 4; i++) {
+				if (iMaxLen-- != 0) {
+					*pbBuf++ = dwData & 0xFF;
+				}
+				dwData >>= 8;
+			}
+		}
+	}
+
+	// select endpoint and clear buffer
+	USBHwCmd(CMD_EP_SELECT | idx);
+	USBHwCmd(CMD_EP_CLEAR_BUFFER);
+	
+//	DBG(">%d", dwLen);
+//	DBG(">");
+
+	return dwLen;
+}
+
+
+/**
+	Sets the 'configured' state.
+		
+	All registered endpoints are 'realised' and enabled, and the
+	'configured' bit is set in the device status register.
+		
+	@param [in]	fConfigured	If TRUE, configure device, else unconfigure
+ */
+void USBHwConfigDevice(BOOL fConfigured)
+{
+	// set configured bit
+	USBHwCmdWrite(CMD_DEV_CONFIG, fConfigured ? CONF_DEVICE : 0);
+}
+
+
+/**
+	USB interrupt handler
+		
+	Endpoint interrupts are mapped to the slow interrupt
+ */
+void USBHwISR(void)
+{
+	U32	dwStatus, dwEPIntStat;
+	U32 dwIntBit;
+	U8	bEPStat, bDevStat, bStat;
+	int i;
+	
+	dwStatus = USBDevIntSt;
+
+	// handle device dwStatus interrupts
+	if (dwStatus & DEV_STAT) {
+DEBUG_LED_ON(8);		
+		bDevStat = USBHwCmdRead(CMD_DEV_STATUS);
+		if (bDevStat & (CON_CH | SUS_CH | RST)) {
+			// convert device status into something HW independent
+			bStat = ((bDevStat & CON) ? DEV_STATUS_CONNECT : 0) |
+					((bDevStat & SUS) ? DEV_STATUS_SUSPEND : 0) |
+					((bDevStat & RST) ? DEV_STATUS_RESET : 0);
+			// call handler
+			if (_pfnDevIntHandler != NULL) {
+				_pfnDevIntHandler(bStat);
+			}
+		}
+		// clear DEV_STAT;
+		USBDevIntClr = DEV_STAT;
+DEBUG_LED_OFF(8);		
+	}
+	
+	// check endpoint interrupts
+	if (dwStatus & EP_SLOW) {
+DEBUG_LED_ON(9);		
+		dwEPIntStat = USBEpIntSt;
+		for (i = 0; i < 32; i++) {
+			dwIntBit = (1 << i);
+			if (dwEPIntStat & dwIntBit) {
+				// clear int (and retrieve status)
+				USBEpIntClr = dwIntBit;
+				Wait4DevInt(CDFULL);
+				bEPStat = USBCmdData;
+				// convert EP pipe stat into something HW independent
+				bStat = ((bEPStat & EPSTAT_FE) ? EP_STATUS_DATA : 0) |
+						((bEPStat & EPSTAT_ST) ? EP_STATUS_STALLED : 0) |
+						((bEPStat & EPSTAT_STP) ? EP_STATUS_SETUP : 0) |
+						((bEPStat & EPSTAT_EPN) ? EP_STATUS_NACKED : 0) |
+						((bEPStat & EPSTAT_PO) ? EP_STATUS_ERROR : 0);
+				// call handler
+				if (_apfnEPIntHandlers[i / 2] != NULL) {
+					_apfnEPIntHandlers[i / 2](IDX2EP(i), bStat);
+				}
+			}
+		}
+		// clear EP_SLOW
+		USBDevIntClr = EP_SLOW;
+DEBUG_LED_OFF(9);
+	}
+	
+	// handle frame interrupt
+	if (dwStatus & FRAME) {
+DEBUG_LED_ON(10);
+		if (_pfnFrameHandler != NULL) {
+			_pfnFrameHandler(0);	// implement counter later
+		}
+		// clear int
+		USBDevIntClr = FRAME;
+DEBUG_LED_OFF(10);
+	}
+}
+
+
+
+/**
+	Initialises the USB hardware
+		
+	This function assumes that the hardware is connected as shown in
+	section 10.1 of the LPC2148 data sheet:
+	* P0.31 controls a switch to connect a 1.5k pull-up to D+ if low.
+	* P0.23 is connected to USB VCC.
+	
+	Embedded artists board: make sure to disconnect P0.23 LED as it
+	acts as a pull-up and so prevents detection of USB disconnect.
+		
+	@return TRUE if the hardware was successfully initialised
+ */
+BOOL USBHwInit(void)
+{
+	// configure P0.23 for Vbus sense
+	PINSEL1 = (PINSEL1 & ~(3 << 14)) | (1 << 14);	// P0.23
+	IODIR0 &= ~(1 << 23);
+	// configure P0.31 for CONNECT
+	PINSEL1 = (PINSEL1 & ~(3 << 30)) | (2 << 30);	// P0.31
+
+	// enable PUSB
+	PCONP |= (1 << 31);		
+	
+	// initialise PLL
+	PLL1CON = 1;			// enable PLL
+	PLL1CFG = (1 << 5) | 3; // P = 2, M = 4
+	PLL1FEED = 0xAA;
+	PLL1FEED = 0x55;
+	while ((PLL1STAT & (1 << 10)) == 0);
+
+	PLL1CON = 3;			// enable and connect
+	PLL1FEED = 0xAA;
+	PLL1FEED = 0x55;
+	
+	// disable/clear all interrupts for now
+	USBDevIntEn = 0;
+	USBEpIntEn = 0;
+	USBDevIntClr = 0xFFFFFFFF;
+	USBEpIntClr = 0xFFFFFFFF;
+
+	// setup control endpoints
+	USBHwEPConfig(0x00, MAX_PACKET_SIZE0);
+	USBHwEPConfig(0x80, MAX_PACKET_SIZE0);
+	
+	// by default, only ACKs generate interrupts
+	USBHwNakIntEnable(0);
+	
+	// init debug leds
+	DEBUG_LED_INIT(8);
+	DEBUG_LED_INIT(9);
+	DEBUG_LED_INIT(10);
+
+	return TRUE;
+}
+

+ 156 - 0
poc/lpc2148_usb/target/usbhw_lpc.h

@@ -0,0 +1,156 @@
+/**
+	(c) 2006, Bertrik Sikken, bertrik@sikken.nl
+
+	Hardware definitions for the LPC214x USB controller
+
+	These are private to the usbhw module
+*/
+
+
+/* Common LPC2148 definitions, related to USB */
+#define	PCONP			*(volatile unsigned int *)0xE01FC0C4
+#define	PLL1CON			*(volatile unsigned int *)0xE01FC0A0
+#define	PLL1CFG			*(volatile unsigned int *)0xE01FC0A4
+#define	PLL1STAT		*(volatile unsigned int *)0xE01FC0A8
+#define	PLL1FEED		*(volatile unsigned int *)0xE01FC0AC
+
+#define PINSEL0			*(volatile unsigned int *)0xE002C000
+#define PINSEL1			*(volatile unsigned int *)0xE002C004
+#define IOPIN0			*(volatile unsigned int *)0xE0028000
+#define IOSET0			*(volatile unsigned int *)0xE0028004
+#define IODIR0			*(volatile unsigned int *)0xE0028008
+#define IOCLR0			*(volatile unsigned int *)0xE002800C
+
+/* USB register definitions */
+#define USBIntSt		*(volatile unsigned int *)0xE01FC1C0
+
+#define USBDevIntSt		*(volatile unsigned int *)0xE0090000
+#define USBDevIntEn		*(volatile unsigned int *)0xE0090004
+#define USBDevIntClr	*(volatile unsigned int *)0xE0090008
+#define USBDevIntSet	*(volatile unsigned int *)0xE009000C
+#define USBDevIntPri	*(volatile unsigned int *)0xE009002C
+
+#define USBEpIntSt		*(volatile unsigned int *)0xE0090030
+#define USBEpIntEn		*(volatile unsigned int *)0xE0090034
+#define USBEpIntClr		*(volatile unsigned int *)0xE0090038
+#define USBEpIntSet		*(volatile unsigned int *)0xE009003C
+#define USBEpIntPri		*(volatile unsigned int *)0xE0090040
+
+#define USBReEP			*(volatile unsigned int *)0xE0090044
+#define USBEpInd		*(volatile unsigned int *)0xE0090048
+#define USBMaxPSize		*(volatile unsigned int *)0xE009004C
+
+#define USBRxData		*(volatile unsigned int *)0xE0090018
+#define USBRxPLen		*(volatile unsigned int *)0xE0090020
+#define USBTxData		*(volatile unsigned int *)0xE009001C
+#define USBTxPLen		*(volatile unsigned int *)0xE0090024
+#define USBCtrl			*(volatile unsigned int *)0xE0090028
+
+#define USBCmdCode		*(volatile unsigned int *)0xE0090010
+#define USBCmdData		*(volatile unsigned int *)0xE0090014
+
+/* USBIntSt bits */
+#define USB_INT_REQ_LP				(1<<0)
+#define USB_INT_REQ_HP				(1<<1)
+#define USB_INT_REQ_DMA				(1<<2)
+#define USB_need_clock				(1<<8)
+#define EN_USB_BITS					(1<<31)
+
+/* USBDevInt... bits */
+#define FRAME						(1<<0)
+#define EP_FAST						(1<<1)
+#define EP_SLOW						(1<<2)
+#define DEV_STAT					(1<<3)
+#define CCEMTY						(1<<4)
+#define CDFULL						(1<<5)
+#define RxENDPKT					(1<<6)
+#define TxENDPKT					(1<<7)
+#define EP_RLZED					(1<<8)
+#define ERR_INT						(1<<9)
+
+/* USBRxPLen bits */
+#define PKT_LNGTH					(1<<0)
+#define PKT_LNGTH_MASK				0x3FF
+#define DV							(1<<10)
+#define PKT_RDY						(1<<11)
+
+/* USBCtrl bits */
+#define RD_EN						(1<<0)
+#define WR_EN						(1<<1)
+#define LOG_ENDPOINT				(1<<2)
+
+/* protocol engine command codes */
+	/* device commands */
+#define CMD_DEV_SET_ADDRESS			0xD0
+#define CMD_DEV_CONFIG				0xD8
+#define CMD_DEV_SET_MODE			0xF3
+#define CMD_DEV_READ_CUR_FRAME_NR	0xF5
+#define CMD_DEV_READ_TEST_REG		0xFD
+#define CMD_DEV_STATUS				0xFE		/* read/write */
+#define CMD_DEV_GET_ERROR_CODE		0xFF
+#define CMD_DEV_READ_ERROR_STATUS	0xFB
+	/* endpoint commands */
+#define CMD_EP_SELECT				0x00
+#define CMD_EP_SELECT_CLEAR			0x40
+#define CMD_EP_SET_STATUS			0x40
+#define CMD_EP_CLEAR_BUFFER			0xF2
+#define CMD_EP_VALIDATE_BUFFER		0xFA
+
+/* set address command */
+#define DEV_ADDR					(1<<0)
+#define DEV_EN						(1<<7)
+
+/* configure device command */
+#define CONF_DEVICE					(1<<0)
+
+/* set mode command */
+#define AP_CLK						(1<<0)
+#define INAK_CI						(1<<1)
+#define INAK_CO						(1<<2)
+#define INAK_II						(1<<3)
+#define INAK_IO						(1<<4)
+#define INAK_BI						(1<<5)
+#define INAK_BO						(1<<6)
+
+/* set get device status command */
+#define CON							(1<<0)
+#define CON_CH						(1<<1)
+#define SUS							(1<<2)
+#define SUS_CH						(1<<3)
+#define RST							(1<<4)
+
+/* get error code command */
+// ...
+
+/* Select Endpoint command read bits */
+#define EPSTAT_FE					(1<<0)
+#define EPSTAT_ST					(1<<1)
+#define EPSTAT_STP					(1<<2)
+#define EPSTAT_PO					(1<<3)
+#define EPSTAT_EPN					(1<<4)
+#define EPSTAT_B1FULL				(1<<5)
+#define EPSTAT_B2FULL				(1<<6)
+
+/* CMD_EP_SET_STATUS command */
+#define EP_ST						(1<<0)
+#define EP_DA						(1<<5)
+#define EP_RF_MO					(1<<6)
+#define EP_CND_ST					(1<<7)
+
+/* read error status command */
+#define PID_ERR						(1<<0)
+#define UEPKT						(1<<1)
+#define DCRC						(1<<2)
+#define TIMEOUT						(1<<3)
+#define EOP							(1<<4)
+#define B_OVRN						(1<<5)
+#define BTSTF						(1<<6)
+#define TGL_ERR						(1<<7)
+
+
+
+
+
+
+
+

+ 69 - 0
poc/lpc2148_usb/target/usbinit.c

@@ -0,0 +1,69 @@
+/*
+	LPCUSB, an USB device driver for LPC microcontrollers	
+	Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library 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
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the Free Software
+	Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+/** @file
+	USB stack initialisation
+ */
+
+#include "type.h"
+#include "usbdebug.h"
+#include "usbapi.h"
+
+
+/** data storage area for standard requests */
+static U8	abStdReqData[8];
+
+
+/**
+	USB reset handler
+	
+	@param [in] bDevStatus	Device status
+ */
+static void HandleUsbReset(U8 bDevStatus)
+{
+	if (bDevStatus & DEV_STATUS_RESET) {
+		DBG("\n!");
+	}
+}
+
+
+/**
+	Initialises the USB hardware and sets up the USB stack by
+	installing default callbacks.
+	
+	@return TRUE if initialisation was successful
+ */
+BOOL USBInit(void)
+{
+	// init hardware
+	USBHwInit();
+	
+	// register bus reset handler
+	USBHwRegisterDevIntHandler(HandleUsbReset);
+	
+	// register control transfer handler on EP0
+	USBHwRegisterEPIntHandler(0x00, USBHandleControlTransfer);
+	USBHwRegisterEPIntHandler(0x80, USBHandleControlTransfer);
+	
+	// register standard request handler
+	USBRegisterRequestHandler(REQTYPE_TYPE_STANDARD, USBHandleStandardRequest, abStdReqData);
+
+	return TRUE;
+}
+

+ 415 - 0
poc/lpc2148_usb/target/usbstdreq.c

@@ -0,0 +1,415 @@
+/*
+	LPCUSB, an USB device driver for LPC microcontrollers	
+	Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library 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
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the Free Software
+	Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+/** @file
+	Standard request handler.
+	
+	This modules handles the 'chapter 9' processing, specifically the
+	standard device requests in table 9-3 from the universal serial bus
+	specification revision 2.0
+	
+	Specific types of devices may specify additional requests (for example
+	HID devices add a GET_DESCRIPTOR request for interfaces), but they
+	will not be part of this module.
+
+	@todo some requests have to return a request error if device not configured:
+	@todo GET_INTERFACE, GET_STATUS, SET_INTERFACE, SYNCH_FRAME
+	@todo this applies to the following if endpoint != 0:
+	@todo SET_FEATURE, GET_FEATURE 
+*/
+
+#include "type.h"
+#include "usbdebug.h"
+#include "usbstruct.h"
+#include "usbapi.h"
+
+#define MAX_DESC_HANDLERS	4		/**< device, interface, endpoint, other */
+
+
+/* general descriptor field offsets */
+#define DESC_bLength					0	/**< length offset */
+#define DESC_bDescriptorType			1	/**< descriptor type offset */	
+
+/* config descriptor field offsets */
+#define CONF_DESC_wTotalLength			2	/**< total length offset */
+#define CONF_DESC_bConfigurationValue	5	/**< configuration value offset */	
+
+/* interface descriptor field offsets */
+#define INTF_DESC_bAlternateSetting		3	/**< alternate setting offset */
+
+/* endpoint descriptor field offsets */
+#define ENDP_DESC_bEndpointAddress		2	/**< endpoint address offset */
+#define ENDP_DESC_wMaxPacketSize		4	/**< maximum packet size offset */
+
+
+/** Currently selected configuration */
+static U8				bConfiguration = 0;
+/** Installed custom request handler */
+static TFnHandleRequest	*pfnHandleCustomReq = NULL;
+/** Pointer to registered descriptors */
+static const U8			*pabDescrip = NULL;
+
+
+/**
+	Registers a pointer to a descriptor block containing all descriptors
+	for the device.
+
+	@param [in]	pabDescriptors	The descriptor byte array
+ */
+void USBRegisterDescriptors(const U8 *pabDescriptors)
+{
+	pabDescrip = pabDescriptors;
+}
+
+
+/**
+	Parses the list of installed USB descriptors and attempts to find
+	the specified USB descriptor.
+		
+	@param [in]		wTypeIndex	Type and index of the descriptor
+	@param [in]		wLangID		Language ID of the descriptor (currently unused)
+	@param [out]	*piLen		Descriptor length
+	@param [out]	*ppbData	Descriptor data
+	
+	@return TRUE if the descriptor was found, FALSE otherwise
+ */
+BOOL USBGetDescriptor(U16 wTypeIndex, U16 wLangID, int *piLen, U8 **ppbData)
+{
+	U8	bType, bIndex;
+	U8	*pab;
+	int iCurIndex;
+	
+	ASSERT(pabDescrip != NULL);
+
+	bType = GET_DESC_TYPE(wTypeIndex);
+	bIndex = GET_DESC_INDEX(wTypeIndex);
+	
+	pab = (U8 *)pabDescrip;
+	iCurIndex = 0;
+	
+	while (pab[DESC_bLength] != 0) {
+		if (pab[DESC_bDescriptorType] == bType) {
+			if (iCurIndex == bIndex) {
+				// set data pointer
+				*ppbData = pab;
+				// get length from structure
+				if (bType == DESC_CONFIGURATION) {
+					// configuration descriptor is an exception, length is at offset 2 and 3
+					*piLen =	(pab[CONF_DESC_wTotalLength]) |
+								(pab[CONF_DESC_wTotalLength + 1] << 8);
+				}
+				else {
+					// normally length is at offset 0
+					*piLen = pab[0];
+				}
+				return TRUE;
+			}
+			iCurIndex++;
+		}
+		// skip to next descriptor
+		pab += pab[DESC_bLength];
+	}
+	// nothing found
+	DBG("Desc %x not found!\n", wTypeIndex);
+	return FALSE;
+}
+
+
+/**
+	Configures the device according to the specified configuration index and
+	alternate setting by parsing the installed USB descriptor list.
+	A configuration index of 0 unconfigures the device.
+		
+	@param [in]		bConfigIndex	Configuration index
+	@param [in]		bAltSetting		Alternate setting number
+	
+	@todo function always returns TRUE, add stricter checking?
+	
+	@return TRUE if successfully configured, FALSE otherwise
+ */
+static BOOL USBSetConfiguration(U8 bConfigIndex, U8 bAltSetting)
+{
+	U8	*pab;
+	U8	bCurConfig, bCurAltSetting;
+	U8	bEP;
+	U16	wMaxPktSize;
+	
+	ASSERT(pabDescrip != NULL);
+
+	// parse installed USB descriptors to configure endpoints
+	pab = (U8 *)pabDescrip;
+	bCurConfig = 0xFF;
+	bCurAltSetting = 0xFF;
+
+	while (pab[DESC_bLength] != 0) {
+		
+		switch (pab[DESC_bDescriptorType]) {
+			
+		case DESC_CONFIGURATION:
+			// remember current configuration index
+			bCurConfig = pab[CONF_DESC_bConfigurationValue];
+			break;
+			
+		case DESC_INTERFACE:
+			// remember current alternate setting
+			bCurAltSetting = pab[INTF_DESC_bAlternateSetting];
+			break;
+			
+		case DESC_ENDPOINT:
+			if ((bCurConfig == bConfigIndex) &&
+				(bCurAltSetting == bAltSetting)) {
+				// endpoint found for desired config and alternate setting
+				bEP = pab[ENDP_DESC_bEndpointAddress];
+				wMaxPktSize = 	(pab[ENDP_DESC_wMaxPacketSize]) |
+								(pab[ENDP_DESC_wMaxPacketSize + 1] << 8);
+				// configure it
+				USBHwEPConfig(bEP, wMaxPktSize);
+			}
+			break;
+			
+		default:
+			break;
+		}
+		// skip to next descriptor
+		pab += pab[DESC_bLength];
+	}
+
+	// configure device
+	USBHwConfigDevice(bConfigIndex != 0);
+	
+	return TRUE;
+}
+
+
+/**
+	Local function to handle a standard device request
+		
+	@param [in]		pSetup		The setup packet
+	@param [in,out]	*piLen		Pointer to data length
+	@param [in,out]	ppbData		Data buffer.
+
+	@return TRUE if the request was handled successfully
+ */
+static BOOL HandleStdDeviceReq(TSetupPacket *pSetup, int *piLen, U8 **ppbData)
+{
+	U8	*pbData = *ppbData;
+
+	switch (pSetup->bRequest) {
+	
+	case REQ_GET_STATUS:
+		// bit 0: self-powered
+		// bit 1: remote wakeup
+		pbData[0] = 0; 	// TODO use bmAttributes according to configuration
+		pbData[1] = 0;
+		*piLen = 2;
+		break;
+		
+	case REQ_SET_ADDRESS:
+		USBHwSetAddress(pSetup->wValue);
+		break;
+
+	case REQ_GET_DESCRIPTOR:
+		DBG("D%x", pSetup->wValue);
+		return USBGetDescriptor(pSetup->wValue, pSetup->wIndex, piLen, ppbData);
+
+	case REQ_GET_CONFIGURATION:
+		// indicate if we are configured
+		pbData[0] = bConfiguration;
+		*piLen = 1;
+		break;
+
+	case REQ_SET_CONFIGURATION:
+		if (!USBSetConfiguration(pSetup->wValue & 0xFF, 0)) {
+			DBG("USBSetConfiguration failed!\n");
+			return FALSE;
+		}
+		// configuration successful, update current configuration
+		bConfiguration = pSetup->wValue & 0xFF;	
+		break;
+
+	case REQ_CLEAR_FEATURE:
+	case REQ_SET_FEATURE:
+		if (pSetup->wValue == FEA_REMOTE_WAKEUP) {
+			// put DEVICE_REMOTE_WAKEUP code here
+		}
+		if (pSetup->wValue == FEA_TEST_MODE) {
+			// put TEST_MODE code here
+		}
+		return FALSE;
+
+	case REQ_SET_DESCRIPTOR:
+		DBG("Device req %d not implemented\n", pSetup->bRequest);
+		return FALSE;
+
+	default:
+		DBG("Illegal device req %d\n", pSetup->bRequest);
+		return FALSE;
+	}
+	
+	return TRUE;
+}
+
+
+/**
+	Local function to handle a standard interface request
+		
+	@param [in]		pSetup		The setup packet
+	@param [in,out]	*piLen		Pointer to data length
+	@param [in]		ppbData		Data buffer.
+
+	@return TRUE if the request was handled successfully
+ */
+static BOOL HandleStdInterfaceReq(TSetupPacket	*pSetup, int *piLen, U8 **ppbData)
+{
+	U8	*pbData = *ppbData;
+
+	switch (pSetup->bRequest) {
+
+	case REQ_GET_STATUS:
+		// no bits specified
+		pbData[0] = 0;
+		pbData[1] = 0;
+		*piLen = 2;
+		break;
+
+	case REQ_CLEAR_FEATURE:
+	case REQ_SET_FEATURE:
+		// not defined for interface
+		return FALSE;
+	
+	case REQ_GET_INTERFACE:	// TODO use bNumInterfaces
+        // there is only one interface, return n-1 (= 0)
+		pbData[0] = 0;
+		*piLen = 1;
+		break;
+	
+	case REQ_SET_INTERFACE:	// TODO use bNumInterfaces
+		// there is only one interface (= 0)
+		if (pSetup->wValue != 0) {
+			return FALSE;
+		}
+		*piLen = 0;
+		break;
+
+	default:
+		DBG("Illegal interface req %d\n", pSetup->bRequest);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+
+/**
+	Local function to handle a standard endpoint request
+		
+	@param [in]		pSetup		The setup packet
+	@param [in,out]	*piLen		Pointer to data length
+	@param [in]		ppbData		Data buffer.
+
+	@return TRUE if the request was handled successfully
+ */
+static BOOL HandleStdEndPointReq(TSetupPacket	*pSetup, int *piLen, U8 **ppbData)
+{
+	U8	*pbData = *ppbData;
+
+	switch (pSetup->bRequest) {
+	case REQ_GET_STATUS:
+		// bit 0 = endpointed halted or not
+		pbData[0] = USBHwEPIsStalled(pSetup->wIndex) ? 1 : 0;
+		pbData[1] = 0;
+		*piLen = 2;
+		break;
+		
+	case REQ_CLEAR_FEATURE:
+		if (pSetup->wValue == FEA_ENDPOINT_HALT) {
+			// clear HALT by unstalling
+			USBHwEPStall(pSetup->wIndex, FALSE);
+			break;
+		}
+		// only ENDPOINT_HALT defined for endpoints
+		return FALSE;
+	
+	case REQ_SET_FEATURE:
+		if (pSetup->wValue == FEA_ENDPOINT_HALT) {
+			// set HALT by stalling
+			USBHwEPStall(pSetup->wIndex, TRUE);
+			break;
+		}
+		// only ENDPOINT_HALT defined for endpoints
+		return FALSE;
+
+	case REQ_SYNCH_FRAME:
+		DBG("EP req %d not implemented\n", pSetup->bRequest);
+		return FALSE;
+
+	default:
+		DBG("Illegal EP req %d\n", pSetup->bRequest);
+		return FALSE;
+	}
+	
+	return TRUE;
+}
+
+
+/**
+	Default handler for standard ('chapter 9') requests
+	
+	If a custom request handler was installed, this handler is called first.
+		
+	@param [in]		pSetup		The setup packet
+	@param [in,out]	*piLen		Pointer to data length
+	@param [in]		ppbData		Data buffer.
+
+	@return TRUE if the request was handled successfully
+ */
+BOOL USBHandleStandardRequest(TSetupPacket	*pSetup, int *piLen, U8 **ppbData)
+{
+	// try the custom request handler first
+	if ((pfnHandleCustomReq != NULL) && pfnHandleCustomReq(pSetup, piLen, ppbData)) {
+		return TRUE;
+	}
+	
+	switch (REQTYPE_GET_RECIP(pSetup->bmRequestType)) {
+	case REQTYPE_RECIP_DEVICE:		return HandleStdDeviceReq(pSetup, piLen, ppbData);
+	case REQTYPE_RECIP_INTERFACE:	return HandleStdInterfaceReq(pSetup, piLen, ppbData);
+	case REQTYPE_RECIP_ENDPOINT: 	return HandleStdEndPointReq(pSetup, piLen, ppbData);
+	default: 						return FALSE;
+	}
+}
+
+
+/**
+	Registers a callback for custom device requests
+	
+	In USBHandleStandardRequest, the custom request handler gets a first
+	chance at handling the request before it is handed over to the 'chapter 9'
+	request handler.
+	
+	This can be used for example in HID devices, where a REQ_GET_DESCRIPTOR
+	request is sent to an interface, which is not covered by the 'chapter 9'
+	specification.
+		
+	@param [in]	pfnHandler	Callback function pointer
+ */
+void USBRegisterCustomReqHandler(TFnHandleRequest *pfnHandler)
+{
+	pfnHandleCustomReq = pfnHandler;
+}
+

+ 94 - 0
poc/lpc2148_usb/target/usbstruct.h

@@ -0,0 +1,94 @@
+/**
+	(c) 2006, Bertrik Sikken, bertrik@sikken.nl
+
+	definitions of structure of standard USB packets
+*/
+
+#ifndef _USBSTRUCT_H_
+#define _USBSTRUCT_H_
+
+
+#include "type.h"
+
+
+/** setup packet definitions */
+typedef struct {
+	U8	bmRequestType;			/**< characteristics of the specific request */
+	U8	bRequest;				/**< specific request */
+	U16	wValue;					/**< request specific parameter */
+	U16	wIndex;					/**< request specific parameter */
+	U16	wLength;				/**< length of data transfered in data phase */
+} TSetupPacket;
+
+
+#define REQTYPE_GET_DIR(x)		(((x)>>7)&0x01)
+#define REQTYPE_GET_TYPE(x)		(((x)>>5)&0x03)
+#define REQTYPE_GET_RECIP(x)	((x)&0x1F)
+
+#define REQTYPE_DIR_TO_DEVICE	0
+#define REQTYPE_DIR_TO_HOST		1
+
+#define REQTYPE_TYPE_STANDARD	0
+#define REQTYPE_TYPE_CLASS		1
+#define REQTYPE_TYPE_VENDOR		2
+#define REQTYPE_TYPE_RESERVED	3
+
+#define REQTYPE_RECIP_DEVICE	0
+#define REQTYPE_RECIP_INTERFACE	1
+#define REQTYPE_RECIP_ENDPOINT	2
+#define REQTYPE_RECIP_OTHER		3
+
+/* standard requests */
+#define	REQ_GET_STATUS			0x00
+#define REQ_CLEAR_FEATURE		0x01
+#define REQ_SET_FEATURE			0x03
+#define REQ_SET_ADDRESS			0x05
+#define REQ_GET_DESCRIPTOR		0x06
+#define REQ_SET_DESCRIPTOR		0x07
+#define REQ_GET_CONFIGURATION	0x08
+#define REQ_SET_CONFIGURATION	0x09
+#define REQ_GET_INTERFACE		0x0A
+#define REQ_SET_INTERFACE		0x0B
+#define REQ_SYNCH_FRAME			0x0C
+
+/* class requests HID */
+#define HID_GET_REPORT			0x01
+#define HID_GET_IDLE			0x02
+#define HID_GET_PROTOCOL	 	0x03
+#define HID_SET_REPORT			0x09
+#define HID_SET_IDLE			0x0A
+#define HID_SET_PROTOCOL		0x0B
+
+/* feature selectors */
+#define FEA_ENDPOINT_HALT		0x00
+#define FEA_REMOTE_WAKEUP		0x01
+#define FEA_TEST_MODE			0x02
+
+/*
+	USB descriptors
+*/
+
+/** USB descriptor header */
+typedef struct {
+	U8	bLength;			/**< descriptor length */
+	U8	bDescriptorType;	/**< descriptor type */
+} TUSBDescHeader;
+
+#define DESC_DEVICE				1
+#define DESC_CONFIGURATION		2
+#define DESC_STRING				3
+#define DESC_INTERFACE			4
+#define DESC_ENDPOINT			5
+#define DESC_DEVICE_QUALIFIER	6
+#define DESC_OTHER_SPEED		7
+#define DESC_INTERFACE_POWER	8
+
+#define DESC_HID_HID			0x21
+#define DESC_HID_REPORT			0x22
+#define DESC_HID_PHYSICAL		0x23
+
+#define GET_DESC_TYPE(x)		(((x)>>8)&0xFF)
+#define GET_DESC_INDEX(x)		((x)&0xFF)
+
+#endif /* _USBSTRUCT_H_ */
+