changeset 23:845934a4e7fe

Add code to talk to a Phillips PDIUSBB12.
author darius
date Mon, 12 Dec 2005 23:32:59 +1030
parents bd792ebf813d
children 2b0ed085b95b
files usb.c usb.h
diffstat 2 files changed, 1041 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usb.c	Mon Dec 12 23:32:59 2005 +1030
@@ -0,0 +1,852 @@
+#include <stdlib.h>
+#include <avr/io.h>
+#include <avr/pgmspace.h>
+#include <avr/interrupt.h>
+#include <avr/eeprom.h>
+#include <util/delay.h>
+
+#include "usb.h"
+
+#define EP0_SIZE 16
+
+#define D12_MODE_0	0x14	/* Endpoint config = 0, SoftConnect = 1, IRQ Mode = 1,
+				 * Clock running = 0, No Lazy Clock = 0 
+				 */
+#define D12_MODE_1	0x02	/* SOF mode = 0, Set-to-one = 0, Clock div = 2 (16Mhz) */
+/* Debugging stuff */
+void		uart_putsP(const char *addr);
+void		uart_puts(const char *addr);
+int		uart_putc(char c);
+void		uart_puts_dec(uint8_t a, uint8_t l);
+void		uart_puts_hex(uint8_t a);
+
+/* USB administrivia */
+uint8_t deviceaddress;
+uint8_t deviceconfigured;
+
+/* End point buffer points and such */
+const uint8_t *pSendBuffer;
+uint8_t BytesToSend;
+static uint8_t send_Bytes;
+static uint8_t exact_Bytes;
+
+static const uint8_t *pSendBuffer2;
+static uint8_t BytesToSend2;
+
+/* Data packet buffer */
+static uint8_t send_packet2;
+static uint8_t packet2[270];
+static uint16_t packetlen2;
+
+/* XXX: Not actually used */
+void (*bootloader)(void) = (void*)0xe000;
+
+/* Device/endpoint/etc descriptions */
+const USB_DEVICE_DESCRIPTOR DeviceDescriptor = {
+    sizeof(USB_DEVICE_DESCRIPTOR),	/* bLength */
+    TYPE_DEVICE_DESCRIPTOR,		/* bDescriptorType */
+    0x0110,				/* bcdUSB USB Version 1.1 */
+    0,					/* bDeviceClass */
+    0,					/* bDeviceSubclass */
+    0,					/* bDeviceProtocol */
+    EP0_SIZE,				/* bMaxPacketSize in Bytes */
+    0x4753,				/* idVendor (inofficial GS) */
+    0x0001,				/* idProduct */
+    0x0100,				/* bcdDevice */
+    1,					/* iManufacturer String Index */
+    2,					/* iProduct String Index */
+    3,					/* iSerialNumber String Index */
+    1					/* bNumberConfigurations */
+};
+
+const USB_CONFIG_DATA ConfigurationDescriptor = {
+    {	/* configuration descriptor */
+	sizeof(USB_CONFIGURATION_DESCRIPTOR),	/* bLength */
+	TYPE_CONFIGURATION_DESCRIPTOR,		/* bDescriptorType */
+	sizeof(USB_CONFIG_DATA),		/* wTotalLength */
+	2,					/* bNumInterfaces */
+	1,					/* bConfigurationValue */
+	0,					/* iConfiguration String Index */
+	0x80,					/* bmAttributes Bus Powered, No Remote Wakeup */
+	100/2					/* bMaxPower in mA */
+    },
+    {	/* interface descriptor */
+	sizeof(USB_INTERFACE_DESCRIPTOR),	/* bLength */
+	TYPE_INTERFACE_DESCRIPTOR,		/* bDescriptorType */
+	0,					/* bInterface Number */
+	0,					/* bAlternateSetting */
+	2,					/* bNumEndpoints */
+	0xFF,					/* bInterfaceClass (Vendor specific) */
+	0x02,					/* bInterfaceSubClass */
+	0x00,					/* bInterfaceProtocol */
+	0					/* iInterface String Index */
+    },
+    {	/* endpoint descriptor */
+	sizeof(USB_ENDPOINT_DESCRIPTOR),	/* bLength */
+	TYPE_ENDPOINT_DESCRIPTOR,		/* bDescriptorType */
+	0x02,					/* bEndpoint Address EP2 OUT */
+	0x02,					/* bmAttributes - Bulk */
+	0x0040,					/* wMaxPacketSize */
+	0x00					/* bInterval */
+    },
+    {	/* endpoint descriptor */
+	sizeof(USB_ENDPOINT_DESCRIPTOR),	/* bLength */
+	TYPE_ENDPOINT_DESCRIPTOR,		/* bDescriptorType */
+	0x82,					/* bEndpoint Address EP2 IN */
+	0x02,					/* bmAttributes - Bulk */
+	0x0040,					/* wMaxPacketSize */
+	0x00					/* bInterval */
+    },
+    {	/* interface descriptor */
+	sizeof(USB_INTERFACE_DESCRIPTOR),	/* bLength */
+	TYPE_INTERFACE_DESCRIPTOR,		/* bDescriptorType */
+	1,					/* bInterface Number */
+	0,					/* bAlternateSetting */
+	2,					/* bNumEndpoints */
+	0xFF,					/* bInterfaceClass (Vendor specific) */
+	0x02,					/* bInterfaceSubClass */
+	0x00,					/* bInterfaceProtocol */
+	0					/* iInterface String Index */
+    },
+    {	/* endpoint descriptor */
+	sizeof(USB_ENDPOINT_DESCRIPTOR),	/* bLength */
+	TYPE_ENDPOINT_DESCRIPTOR,		/* bDescriptorType */
+	0x01,					/* bEndpoint Address EP1 OUT */
+	0x02,					/* bmAttributes - Bulk */
+	0x0010,					/* wMaxPacketSize */
+	0x00					/* bInterval */
+    },
+    {	/* endpoint descriptor */
+	sizeof(USB_ENDPOINT_DESCRIPTOR),	/* bLength */
+	TYPE_ENDPOINT_DESCRIPTOR,		/* bDescriptorType */
+	0x81,					/* bEndpoint Address EP1 IN */
+	0x02,					/* bmAttributes - Bulk */
+	0x0010,					/* wMaxPacketSize */
+	0x00					/* bInterval */
+    }
+};
+const LANGID_DESCRIPTOR LANGID_Descriptor = {	/* LANGID String Descriptor
+						 * Zero */
+	sizeof(LANGID_DESCRIPTOR),		/* bLength - must match string below */
+	TYPE_STRING_DESCRIPTOR,			/* bDescriptorType */
+	0x0409					/* LANGID US English */
+};
+
+/* These are really STRING_DESCRIPTOR's but we can't statically
+ * declare them as that and have the compiler generate the right size
+ * structure */
+typedef struct {
+	uint8_t bLenght;
+      	uint8_t bDescriptorType;
+      	char     bString[32];
+} MANUFACTURER_DESCRIPTOR, *PMANUFACTURER_DESCRIPTOR;
+
+const MANUFACTURER_DESCRIPTOR Manufacturer_Descriptor = {	/* ManufacturerString 1 */
+    sizeof(MANUFACTURER_DESCRIPTOR),				/* bLength */
+    TYPE_STRING_DESCRIPTOR,					/* bDescriptorType */
+    "G\0e\0n\0e\0s\0i\0s\0 \0S\0o\0f\0t\0w\0a\0r\0e\0" 		/* ManufacturerString in
+								 * UNICODE */
+};
+
+typedef struct {
+	uint8_t bLenght;
+      	uint8_t bDescriptorType;
+      	char     bString[48];
+} PRODUCT_DESCRIPTOR, *PPRODUCT_DESCRIPTOR;
+
+const PRODUCT_DESCRIPTOR Product_Descriptor = {	/* ProductString 2 */
+    sizeof(PRODUCT_DESCRIPTOR),			/* bLength */
+    TYPE_STRING_DESCRIPTOR,			/* bDescriptorType */
+    /* ProductString in
+     * UNICODE */
+    "R\0S\0""-\0""4\0""8\0""5\0"" \0M\0u\0l\0t\0i\0d\0r\0o\0p\0 \0A\0d\0a\0p\0t\0e\0r\0"
+    /* XXX: dunno why I need the double quote magic above.. */
+};
+
+typedef struct {
+	uint8_t bLenght;
+      	uint8_t bDescriptorType;
+      	char     bString[20];
+} SERIAL_DESCRIPTOR, *PSERIAL_DESCRIPTOR;
+
+const SERIAL_DESCRIPTOR EE_Serial_Descriptor __attribute__ ((section (".eeprom"))) = { /* SerialString 3 */
+    sizeof(SERIAL_DESCRIPTOR),		/* bLength - must match string below */
+    TYPE_STRING_DESCRIPTOR,		/* bDescriptorType */
+    "1\02\03\0"
+};
+
+SERIAL_DESCRIPTOR Serial_Descriptor;
+
+/*
+ * The PDIUSBD12 is wired up like so
+ *
+ *  PDI		     AVR	
+ * ======================
+ * D7:0     <=>     PA7:0	   
+ * INT_N     =>     PB0
+ * RD_N     <=      PB1
+ * WR_N     <=      PB2
+ * A0       <=      PB3 (0 = data, 1 = cmd)
+ * SUSPEND  <=>     PB4
+ */
+uint8_t
+d12_get_data(void) {
+    uint8_t data;
+#if 0
+    _delay_us(1);
+#endif
+    PORTB &= ~_BV(PB3);	/* Data phase */
+    DDRA = 0x00;	/* Set to input */
+    PORTB &= ~_BV(PB1);	/* Pull RD_N low */
+    PORTB &= ~_BV(PB1);	/* Delay 40ns */
+    PORTB &= ~_BV(PB1);
+    PORTB &= ~_BV(PB1);
+    data = PINA;	/* Read the data */
+    PORTB |= _BV(PB1);	/* Pull RD_N high */
+    return(data);
+}
+
+void
+set_d12_data(uint8_t data) {
+#if 0
+    _delay_us(1);
+#endif
+    PORTB &= ~_BV(PB3);	/* Data phase */
+    DDRA = 0xff;	/* Set to output */
+    PORTA = data;	/* Put the data on the bus */
+    PORTB &= ~_BV(PB2);	/* Pull WR_N low */
+    PORTB &= ~_BV(PB2);	/* Delay 40ns */
+    PORTB &= ~_BV(PB2);
+    PORTB &= ~_BV(PB2);
+    PORTB |= _BV(PB2);	/* Pull WR_N high */
+    PORTB |= _BV(PB2);	/* Delay 40 ns */
+    PORTB |= _BV(PB2);	 
+    PORTB |= _BV(PB2);	 
+    DDRA = 0x00;	/* Back to input */
+}
+
+void
+set_d12_cmd(uint8_t cmd) {
+#if 0
+    _delay_us(1);
+#endif
+    PORTB |= _BV(PB3);	/* Command phase */
+    DDRA = 0xff;	/* Set to output */
+    PORTA = cmd;	/* Put the data on the bus */
+    PORTB &= ~_BV(PB2);	/* Pull WR_N low */
+    PORTB &= ~_BV(PB2);	/* Delay 40ns */
+    PORTB &= ~_BV(PB2);
+    PORTB &= ~_BV(PB2);
+    PORTB |= _BV(PB2);	/* Pull WR_N high */
+    PORTB |= _BV(PB2);	/* Delay 40ns */
+    PORTB |= _BV(PB2);
+    PORTB |= _BV(PB2);
+    DDRA = 0x00;	/* Back to input */
+}
+
+void 
+d12_write_cmd(uint8_t command, const uint8_t *buffer, uint8_t count) {
+    uint8_t i;
+
+    set_d12_cmd(command);
+#if 0
+    _delay_us(1);
+#endif
+    if (count) {
+	for (i = 0; i < count; i++) {
+	    set_d12_data(buffer[i]);
+	}
+    }
+}
+
+void 
+d12_read_cmd(uint8_t command, uint8_t *buffer, uint8_t count) {
+    uint8_t i;
+
+    set_d12_cmd(command);
+    if (count) {
+	for (i = 0; i < count; i++) {
+	    buffer[i] = d12_get_data();
+	}
+    }
+}
+
+/* Set up the PDIUSBD12 */
+void
+usb_init(void) {
+    uint8_t	buffer[2];
+    
+    /* pull EE_Serial_Descriptor into RAM */
+    eeprom_read_block(&Serial_Descriptor, &EE_Serial_Descriptor, sizeof(Serial_Descriptor));
+
+    /* Set Address to zero (default) and enable function */
+    buffer[0] = 0x80;
+    d12_write_cmd(D12_SET_ADDRESS_ENABLE, buffer, 1);
+
+    /* Enable function generic endpoints */
+    buffer[0] = 0x01;
+    d12_write_cmd(D12_SET_ENDPOINT_ENABLE, buffer, 1);
+ 
+    /* Configure the device (soft connect off) */
+    buffer[0] = D12_MODE_0 & 0xef;
+    buffer[1] = D12_MODE_1;
+    d12_write_cmd(D12_SET_MODE, buffer, 2);
+    
+    /* Delay long enough for the PC to notice the disconnect */
+    _delay_us(1000);
+    
+    buffer[0] |= 0x10; /* Soft connect on */
+    d12_write_cmd(D12_SET_MODE, buffer, 2);
+
+    /* Endpoint 2 IN/OUT IRQ enable */
+    buffer[0] = 0xc0;
+    d12_write_cmd(D12_SET_DMA, buffer, 1);
+}
+
+/* Process an interrupt */
+void
+usb_intr(void) {
+    uint8_t	irq[2];
+    uint8_t	buffer[8];
+    
+    d12_read_cmd(D12_READ_INTERRUPT_REGISTER, (uint8_t *)&irq, 2);
+
+    /* Why do we get interrupts when this is 0? */
+    if (irq[0] == 0)
+	return;
+    
+    if (irq[0] & D12_INT_BUS_RESET) {
+	uart_putsP(PSTR("Bus reset\n\r"));
+	usb_init();
+	return;
+    }
+    
+    if (irq[0] & D12_INT_SUSPEND) {
+	uart_putsP(PSTR("Suspend change\n\r"));
+    }
+	
+    if (irq[0] & D12_INT_EP0_IN) {
+	d12_read_cmd(D12_READ_LAST_TRANSACTION + D12_ENDPOINT_EP0_IN, buffer, 1);
+
+	/* Handle any outgoing data for EP0 */
+	d12_write_buffer_ep0();
+    }
+    
+    /* Handle configuration and misc stuff */
+    if (irq[0] & D12_INT_EP0_OUT) {
+	d12_ep0_irq();
+    }
+    
+    /* EPx_IN is when the host has had a packet of data and is expecting more */
+    if (irq[0] & D12_INT_EP1_IN) {
+	/* XXX: Not yet implemented */
+    }
+    
+    /* EPx_OUT is when we have gotten a packet from the host */
+    if (irq[0] & D12_INT_EP1_OUT) {
+	/* XXX: Not yet implemented */
+    }
+
+    if (irq[0] & D12_INT_EP2_IN) {
+	d12_read_cmd(D12_READ_LAST_TRANSACTION + D12_ENDPOINT_EP2_IN, buffer, 1);
+	d12_send_data_ep2();
+    }
+    
+    if (irq[0] & D12_INT_EP2_OUT) {
+	d12_read_cmd(D12_READ_LAST_TRANSACTION + D12_ENDPOINT_EP2_OUT, buffer, 1);
+	d12_receive_data_ep2();
+    }
+}
+
+void
+usb_gendata(void) {
+    packet2[0] = 'a';
+    packet2[1] = 'b';
+    packet2[2] = 'c';
+    packet2[3] = '\n';
+    packet2[4] = '\r';
+    BytesToSend2 = 5;
+    pSendBuffer2 = (uint8_t *)&packet2[0];
+    send_packet2 = 1;
+
+    /* Kick off the data transfer */
+    d12_send_data_ep2();
+}
+
+void
+d12_ep0_irq(void) {
+    uint8_t		buffer[2];
+    USB_SETUP_REQUEST	setuppkt;
+
+    d12_read_cmd(D12_READ_LAST_TRANSACTION + D12_ENDPOINT_EP0_OUT, buffer, 1);
+
+    if (buffer[0] & D12_LAST_TRAN_SETUP) {
+	/* Read the setup packet */
+	d12_read_endpt(D12_ENDPOINT_EP0_OUT, (uint8_t *)&setuppkt);
+	
+	/* Ack the packet to EP0_OUT */
+	d12_write_cmd(D12_ENDPOINT_EP0_OUT, NULL, 0);
+	d12_write_cmd(D12_ACK_SETUP, NULL, 0);
+	d12_write_cmd(D12_CLEAR_BUFFER, NULL, 0);
+	
+	/* Ack the packet to EP0_IN */
+	d12_write_cmd(D12_ENDPOINT_EP0_IN, NULL, 0);
+	d12_write_cmd(D12_ACK_SETUP, NULL, 0);
+	
+	/* It's a new xfer, so forget about any old one */
+	send_Bytes = 0;
+	
+	/* Parse request type */
+	switch (setuppkt.bmRequestType & 0x7f) {
+	    case STANDARD_DEVICE_REQUEST:
+		switch (setuppkt.bRequest) {
+		    case GET_STATUS:
+			/* Get status request should return remote
+			 * wakeup and self powered status
+			 */
+			buffer[0] = 0x01;
+			buffer[1] = 0x00;
+			d12_write_endpt(D12_ENDPOINT_EP0_IN, buffer, 2);
+			break;
+		    case CLEAR_FEATURE:
+		    case SET_FEATURE:
+			/* We don't support DEVICE_REMOTE_WAKEUP or
+			 * TEST_MODE
+			 */
+			d12_stallctrlendpt();
+			break;
+			
+		    case SET_ADDRESS:
+			deviceaddress = setuppkt.wValue | 0x80;
+			d12_write_cmd(D12_SET_ADDRESS_ENABLE, &deviceaddress, 1);
+			d12_write_endpt(D12_ENDPOINT_EP0_IN, NULL, 0);
+			break;
+
+		    case GET_DESCRIPTOR:	
+			d12_getdescriptor(&setuppkt);
+			break;
+			
+		    case GET_CONFIGURATION:
+			d12_write_endpt(D12_ENDPOINT_EP0_IN, &deviceconfigured, 1);
+			break;
+			
+		    case SET_CONFIGURATION:
+			deviceconfigured = setuppkt.wValue & 0xff;
+			d12_write_endpt(D12_ENDPOINT_EP0_IN, NULL, 0);
+			break;
+			
+
+		    case SET_DESCRIPTOR:
+		    default:
+			/* Unsupported, stall */
+			d12_stallctrlendpt();
+			break;
+		}
+		break;
+		
+	    case STANDARD_INTERFACE_REQUEST:
+		switch (setuppkt.bRequest) {
+		    case GET_STATUS:
+			/* Should return 0, 0 (reserved) */
+			buffer[0] = 0x00;
+			buffer[1] = 0x00;
+			d12_write_endpt(D12_ENDPOINT_EP0_IN, buffer, 2);
+			break;
+			
+		    case SET_INTERFACE:
+			if (setuppkt.wIndex == 0 && setuppkt.wValue == 0)
+			    d12_write_endpt(D12_ENDPOINT_EP0_IN, NULL, 0);
+			else
+			    d12_stallctrlendpt();
+			break;
+
+		    case GET_INTERFACE:
+			/* Can only handle interface 0 ... */
+			if (setuppkt.wIndex == 0) {
+			    buffer[0] = 0;
+			    d12_write_endpt(D12_ENDPOINT_EP0_IN, buffer, 1);
+			    break;
+			}
+			/* .. otherwise fall through to error */
+
+		    case CLEAR_FEATURE:
+		    case SET_FEATURE:
+		    default:
+			d12_stallctrlendpt();
+			break;
+		}
+		break;
+		
+	    case STANDARD_ENDPOINT_REQUEST:
+		switch (setuppkt.bRequest) {
+		    case CLEAR_FEATURE:
+		    case SET_FEATURE:
+			/* Halt(stall) is required to be implemented on
+			 * interrupt and bulk endpoints.
+			 */
+			if (setuppkt.wValue == ENDPOINT_HALT) {
+			    if (setuppkt.bRequest == CLEAR_FEATURE)
+				buffer[0] = 0x00;
+			    else
+				buffer[0] = 0x01;
+			    switch (setuppkt.wIndex & 0xFF) {
+				case 0x01:
+				    d12_write_cmd(D12_SET_ENDPOINT_STATUS + \
+						  D12_ENDPOINT_EP1_OUT, buffer, 1);
+				    break;
+				case 0x81:
+				    d12_write_cmd(D12_SET_ENDPOINT_STATUS + \
+						  D12_ENDPOINT_EP1_IN, buffer, 1);
+				    break;
+				case 0x02:
+				    d12_write_cmd(D12_SET_ENDPOINT_STATUS + \
+						  D12_ENDPOINT_EP2_OUT, buffer, 1);
+				    break;
+				case 0x82:
+				    d12_write_cmd(D12_SET_ENDPOINT_STATUS + \
+						  D12_ENDPOINT_EP2_IN, buffer, 1);
+				    break;
+				default:	/* Invalid Endpoint -
+						 * RequestError */
+				    d12_stallctrlendpt();
+				    break;
+			    }
+			    d12_write_endpt(D12_ENDPOINT_EP0_IN, NULL, 0);
+			} else {
+			    /*
+			     * No other Features for Endpoint -
+			     * Request Error
+			     */
+			    d12_stallctrlendpt();
+			}
+			break;
+
+		    case GET_STATUS:
+			/*
+			 * Get Status Request to Endpoint should
+			 * return Halt Status in D0 for Interrupt and Bulk
+			 */
+			switch (setuppkt.wIndex & 0xFF) {
+			    case 0x01:
+				d12_read_cmd(D12_READ_ENDPOINT_STATUS + \
+					       D12_ENDPOINT_EP1_OUT, buffer, 1);
+				break;
+			    case 0x81:
+				d12_read_cmd(D12_READ_ENDPOINT_STATUS + \
+					       D12_ENDPOINT_EP1_IN, buffer, 1);
+				break;
+			    case 0x02:
+				d12_read_cmd(D12_READ_ENDPOINT_STATUS + \
+					       D12_ENDPOINT_EP2_OUT, buffer, 1);
+				break;
+			    case 0x82:
+				d12_read_cmd(D12_READ_ENDPOINT_STATUS + \
+					       D12_ENDPOINT_EP2_IN, buffer, 1);
+				break;
+			    default:	/* Invalid Endpoint -
+					 * RequestError */
+				d12_stallctrlendpt();
+				break;
+			}
+			if (buffer[0] & 0x08)
+			    buffer[0] = 0x01;
+			else
+			    buffer[0] = 0x00;
+			buffer[1] = 0x00;
+			d12_write_endpt(D12_ENDPOINT_EP0_IN, buffer, 2);
+			break;
+
+		    default:
+			/* Unsupported - Request Error - Stall */
+			d12_stallctrlendpt();
+			break;
+		}
+		break;
+	    case VENDOR_DEVICE_REQUEST:
+	    case VENDOR_ENDPOINT_REQUEST:
+		switch (setuppkt.bRequest) {
+		    case VENDOR_RESET:
+			d12_write_endpt(D12_ENDPOINT_EP0_IN, NULL, 0);
+			_delay_us(1000);
+			/* disconnect from USB */
+			buffer[0] = D12_MODE_0 & 0xef;
+			buffer[1] = D12_MODE_1;
+			d12_write_cmd(D12_SET_MODE, buffer, 2);
+			_delay_us(1000);
+			cli();
+			reset();
+			/* NOT REACHED */
+			break;
+		    case VENDOR_UPDATE:
+			d12_write_endpt(D12_ENDPOINT_EP0_IN, NULL, 0);
+			_delay_us(1000);
+			/* disconnect from USB */
+			buffer[0] = D12_MODE_0 & 0xef;
+			buffer[1] = D12_MODE_1;
+			d12_write_cmd(D12_SET_MODE, buffer, 2);
+			_delay_us(1000);
+			cli();
+			bootloader();
+			/* NOT REACHED */
+			break;
+		    default:
+			d12_stallctrlendpt();
+			break;
+		}
+		break;
+	    case VENDOR_INTERFACE_REQUEST:
+		switch (setuppkt.bRequest) {
+		    default:
+			d12_stallctrlendpt();
+			break;
+		}
+		break;
+	    default:
+		d12_stallctrlendpt();
+		break;
+	}
+    } else {
+	/* This is a Data Packet */
+    }
+		
+}
+
+/* Reset the micro
+static void
+reset(void) {
+    MCUCR = _BV(IVCE);
+    MCUCR = 0;
+    WDTCR = _BV(WDE);
+    for (;;)
+	;
+}
+
+void 
+d12_getdescriptor(USB_SETUP_REQUEST *setuppkt) {
+    switch ((setuppkt->wValue & 0xff00) >> 8) {
+	case TYPE_DEVICE_DESCRIPTOR:
+	    pSendBuffer = (const uint8_t *)&DeviceDescriptor;
+	    BytesToSend = DeviceDescriptor.bLength;
+	    send_Bytes = 1;
+	    if (BytesToSend >= setuppkt->wLength) {
+		BytesToSend = setuppkt->wLength;
+		exact_Bytes = 1;
+	    } else {
+		exact_Bytes = 0;
+	    }
+	    d12_write_buffer_ep0();
+	    break;
+
+	case TYPE_CONFIGURATION_DESCRIPTOR:
+	    pSendBuffer = (const uint8_t *)&ConfigurationDescriptor;
+	    BytesToSend = sizeof(ConfigurationDescriptor);
+	    send_Bytes = 1;
+	    if (BytesToSend >= setuppkt->wLength) {
+		BytesToSend = setuppkt->wLength;
+		exact_Bytes = 1;
+	    } else {
+		exact_Bytes = 0;
+	    }
+	    d12_write_buffer_ep0();
+	    break;
+
+	case TYPE_STRING_DESCRIPTOR:
+	    switch (setuppkt->wValue & 0xFF) {
+
+		case 0:
+		    pSendBuffer = (const uint8_t *)&LANGID_Descriptor;
+		    BytesToSend = sizeof(LANGID_Descriptor);
+		    break;
+
+		case 1:
+		    pSendBuffer = (const uint8_t *)&Manufacturer_Descriptor;
+		    BytesToSend = sizeof(Manufacturer_Descriptor);
+		    break;
+
+		case 2:
+		    pSendBuffer = (const uint8_t *)&Product_Descriptor;
+		    BytesToSend = sizeof(Product_Descriptor);
+		    break;
+
+		case 3:
+		    pSendBuffer = (const uint8_t *)&Serial_Descriptor;
+		    BytesToSend = sizeof(Serial_Descriptor);
+		    break;
+
+		default:
+		    pSendBuffer = NULL;
+		    BytesToSend = 0;
+	    }
+	    send_Bytes = 1;
+	    if (BytesToSend >= setuppkt->wLength) {
+		BytesToSend = setuppkt->wLength;
+		exact_Bytes = 1;
+	    } else {
+		exact_Bytes = 0;
+	    }
+	    d12_write_buffer_ep0();
+	    break;
+	default:
+	    d12_stallctrlendpt();
+	    break;
+    }
+}
+
+
+void 
+d12_stallctrlendpt(void) {
+    uint8_t   Buffer[] = {0x01};
+    /*
+     * 9.2.7 RequestError - return STALL PID in response to next DATA
+     * Stage Transaction
+     */
+    d12_write_cmd(D12_SET_ENDPOINT_STATUS + D12_ENDPOINT_EP0_IN, Buffer, 1);
+    /* or in the status stage of the message. */
+    d12_write_cmd(D12_SET_ENDPOINT_STATUS + D12_ENDPOINT_EP0_OUT, Buffer, 1);
+}
+    
+uint8_t
+d12_read_endpt(uint8_t endpt, uint8_t *buffer) {
+    uint8_t d12header[2];
+    uint8_t status = 0;
+    uint8_t i;
+
+    /* Select Endpoint */
+    d12_read_cmd(endpt, &status, 1);
+
+    /* Check if Buffer is Full */
+    if (status & 0x01) {
+	set_d12_cmd(D12_READ_BUFFER);
+	d12header[0] = d12_get_data();
+	d12header[1] = d12_get_data();
+	if (d12header[1]) {
+	    for (i = 0; i < d12header[1]; i++)
+		buffer[i] = d12_get_data();
+	}
+	/* Allow new packets to be accepted */
+	d12_write_cmd(D12_CLEAR_BUFFER, NULL, 0);
+	
+    }
+    return d12header[1];
+}
+
+void 
+d12_write_endpt(uint8_t endpt, const uint8_t *buffer, uint8_t bytes) {
+    uint8_t status = 0;
+    uint8_t i;
+
+    /* Select Endpoint */
+    d12_read_cmd(endpt, &status, 1);
+    /* Write Header */
+    set_d12_cmd(D12_WRITE_BUFFER);
+    set_d12_data(0x00);
+    set_d12_data(bytes);
+    /* Write Packet */
+    if (bytes) {
+	for (i = 0; i < bytes; i++) {
+	    set_d12_data(buffer[i]);
+	}
+    }
+    /* Validate Buffer */
+    d12_write_cmd(D12_VALIDATE_BUFFER, NULL, 0);
+}
+
+void 
+d12_write_buffer_ep0(void) {
+    uint8_t BufferStatus = 1;
+    
+    if (send_Bytes == 0) {
+	return;
+    }
+	
+    /* Read Buffer Full Status */
+    d12_read_cmd(D12_ENDPOINT_EP0_IN, &BufferStatus, 1);
+    if (BufferStatus != 0) {/* Buffer Full */
+	return;
+    }
+    
+    if (BytesToSend == 0) {
+	/*
+	 * If BytesToSend is Zero and we get called again, assume
+	 * buffer is smaller
+	 * than Setup Request Size and indicate end by sending Zero
+	 * Lenght packet
+	 */
+	d12_write_endpt(D12_ENDPOINT_EP0_IN, NULL, 0);
+	send_Bytes = 0;
+    } else if (BytesToSend >= EP0_SIZE) {	
+	/* Write another EP0_SIZE Bytes to buffer and send */
+	d12_write_endpt(D12_ENDPOINT_EP0_IN, pSendBuffer, EP0_SIZE);
+	pSendBuffer += EP0_SIZE;
+	BytesToSend -= EP0_SIZE;
+	if (BytesToSend == 0 && exact_Bytes) {
+	    send_Bytes = 0;
+	}
+    } else {
+	/* Buffer must have less than EP0_SIZE bytes left */	
+	d12_write_endpt(D12_ENDPOINT_EP0_IN, pSendBuffer, BytesToSend);
+	
+	BytesToSend = 0;
+	send_Bytes = 0;
+    }
+}
+
+void
+d12_send_data_ep2(void) {
+    uint8_t BufferStatus = 1;
+
+    /* Read Buffer Full Status */
+    d12_read_cmd(D12_ENDPOINT_EP2_IN, &BufferStatus, 1);
+    if (BufferStatus == 0) {   /* Buffer Empty */
+	if (BytesToSend2 == 0) {
+	    /* Nothing to do */
+	    send_packet2 = 0;
+	} else if (BytesToSend2 >= 64) {
+	    /* Write another 64 Bytes to buffer and send */
+	    d12_write_endpt(D12_ENDPOINT_EP2_IN, pSendBuffer2, 64);
+	    pSendBuffer2 += 64;
+	    BytesToSend2 -= 64;
+	} else {
+	    /* Buffer must have less than 64 bytes left */
+	    d12_write_endpt(D12_ENDPOINT_EP2_IN, pSendBuffer2, BytesToSend2);
+	    BytesToSend2 = 0;
+	    send_packet2 = 0;
+	}
+    }
+}
+
+void
+d12_receive_data_ep2(void) {
+    uint8_t D12Header[2];
+    uint8_t bytes;
+    uint8_t BufferStatus = 0;
+    uint8_t i;
+
+    /* Select Endpoint */
+    d12_read_cmd(D12_ENDPOINT_EP2_OUT, &BufferStatus, 1);
+    /* Check if Buffer is Full */
+    if (BufferStatus & 0x01) {
+	/* Read header */
+	set_d12_cmd(D12_READ_BUFFER);
+	D12Header[0] = d12_get_data();
+	D12Header[1] = d12_get_data();
+	bytes = D12Header[1];
+	/* TODO check if the packet is not too long */
+	uart_putsP(PSTR("Got data\n\r"));
+	for (i = 0; i < bytes; i++) {
+	    packet2[packetlen2 + i] = d12_get_data();
+	    uart_puts_hex(packet2[packetlen2 + i]);
+	    uart_putsP(PSTR(" "));
+	}
+	uart_putsP(PSTR("\n\r"));
+	packetlen2 += bytes;
+	/* Allow new packets to be accepted */
+	d12_write_cmd(D12_CLEAR_BUFFER, NULL, 0);
+	if (bytes == 0 || bytes < 64) { /* request complete */
+	    pSendBuffer2 = packet2;
+	    send_packet2 = 1;
+	    packetlen2 = 0;
+	    d12_send_data_ep2();
+	}
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usb.h	Mon Dec 12 23:32:59 2005 +1030
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2003 Bernd Walter
+ * All rights reserved.
+ */
+
+/*  Example Source Code for USB Enumeration using a PDIUSBD11 connected to a PIC16F87x
+ *  Copyright 2001 Craig Peacock, Craig.Peacock@beyondlogic.org
+ *  31th December 2001 http://www.beyondlogic.org            				      
+ */
+
+typedef struct {
+    uint8_t bmRequestType;
+    uint8_t bRequest;
+    uint16_t wValue;
+    uint16_t wIndex;
+    uint16_t wLength;
+} USB_SETUP_REQUEST;
+
+typedef struct {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint16_t bcdUSB;
+    uint8_t bDeviceClass;
+    uint8_t bDeviceSubClass;
+    uint8_t bDeviceProtocol;
+    uint8_t bMaxPacketSize0;
+    uint16_t idVendor;
+    uint16_t idProduct;
+    uint16_t bcdDevice;
+    uint8_t iManufacturer;
+    uint8_t iProduct;
+    uint8_t iSerialNumber;
+    uint8_t bNumConfigurations;
+} USB_DEVICE_DESCRIPTOR;
+
+typedef struct {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bEndpointAddress;
+    uint8_t bmAttributes;
+    uint16_t wMaxPacketSize;
+    uint8_t bInterval;
+} USB_ENDPOINT_DESCRIPTOR;
+
+typedef struct {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint16_t wTotalLength;
+    uint8_t bNumInterfaces;
+    uint8_t bConfigurationValue;
+    uint8_t iConfiguration;
+    uint8_t bmAttributes;
+    uint8_t MaxPower;
+} USB_CONFIGURATION_DESCRIPTOR;
+
+typedef struct {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bInterfaceNumber;
+    uint8_t bAlternateSetting;
+    uint8_t bNumEndpoints;
+    uint8_t bInterfaceClass;
+    uint8_t bInterfaceSubClass;
+    uint8_t bInterfaceProtocol;
+    uint8_t iInterface;
+} USB_INTERFACE_DESCRIPTOR;
+
+typedef struct {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint16_t wHIDClassSpecComp;
+    uint8_t bCountry;
+    uint8_t bNumDescriptors;
+    uint8_t b1stDescType;
+    uint16_t w1stDescLength;
+} USB_HID_DESCRIPTOR;
+
+typedef struct {
+    USB_CONFIGURATION_DESCRIPTOR ConfigDescriptor;
+    USB_INTERFACE_DESCRIPTOR InterfaceDescriptor0;
+    USB_ENDPOINT_DESCRIPTOR EndpointDescriptor00;
+    USB_ENDPOINT_DESCRIPTOR EndpointDescriptor01;
+    USB_INTERFACE_DESCRIPTOR InterfaceDescriptor1;
+    USB_ENDPOINT_DESCRIPTOR EndpointDescriptor10;
+    USB_ENDPOINT_DESCRIPTOR EndpointDescriptor11;
+} USB_CONFIG_DATA;
+
+typedef struct {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    char     bString[];
+} STRING_DESCRIPTOR;
+
+typedef struct {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint16_t wLANGID0;
+} LANGID_DESCRIPTOR;
+
+#define D12_SET_ADDRESS_ENABLE		0xD0
+#define D12_SET_ENDPOINT_ENABLE  	0xD8
+#define D12_SET_MODE			0xF3
+#define D12_SET_DMA			0xFB
+#define D12_READ_INTERRUPT_REGISTER 	0xF4
+#define D12_READ_BUFFER			0xF0
+#define D12_WRITE_BUFFER		0xF0
+#define D12_ACK_SETUP			0xF1
+#define D12_CLEAR_BUFFER		0xF2
+#define D12_VALIDATE_BUFFER		0xFA
+#define D12_READ_LAST_TRANSACTION	0x40
+#define D12_SET_ENDPOINT_STATUS		0x40
+#define D12_READ_ENDPOINT_STATUS	0x80
+
+#define D12_ENDPOINT_EP0_OUT 		0x00
+#define D12_ENDPOINT_EP0_IN 		0x01
+#define D12_ENDPOINT_EP1_OUT 		0x02
+#define D12_ENDPOINT_EP1_IN 		0x03
+#define D12_ENDPOINT_EP2_OUT 		0x04
+#define D12_ENDPOINT_EP2_IN 		0x05
+
+#define D12_INT_EP0_OUT			0x01
+#define D12_INT_EP0_IN			0x02
+#define D12_INT_EP1_OUT			0x04
+#define D12_INT_EP1_IN			0x08
+#define D12_INT_EP2_OUT			0x10
+#define D12_INT_EP2_IN			0x20
+#define D12_INT_BUS_RESET		0x40
+#define D12_INT_SUSPEND			0x80
+
+#define D12_LAST_TRAN_SETUP		0x20
+
+#define STANDARD_DEVICE_REQUEST		0x00
+#define STANDARD_INTERFACE_REQUEST	0x01
+#define STANDARD_ENDPOINT_REQUEST	0x02
+#define VENDOR_DEVICE_REQUEST		0x40
+#define VENDOR_INTERFACE_REQUEST	0x41
+#define VENDOR_ENDPOINT_REQUEST		0x42
+
+#define GET_STATUS  			0
+#define CLEAR_FEATURE     		1
+#define SET_FEATURE                 	3
+#define SET_ADDRESS                 	5
+#define GET_DESCRIPTOR              	6
+#define SET_DESCRIPTOR              	7
+#define GET_CONFIGURATION           	8
+#define SET_CONFIGURATION           	9
+#define GET_INTERFACE               	10
+#define SET_INTERFACE               	11
+#define SYNCH_FRAME                 	12
+
+#define VENDOR_UPDATE			126
+#define VENDOR_RESET			127
+
+#define	ENDPOINT_HALT			0
+
+#define TYPE_DEVICE_DESCRIPTOR          1
+#define TYPE_CONFIGURATION_DESCRIPTOR   2
+#define TYPE_STRING_DESCRIPTOR          3
+#define TYPE_INTERFACE_DESCRIPTOR       4
+#define TYPE_ENDPOINT_DESCRIPTOR        5
+#define TYPE_HID_DESCRIPTOR		0x21
+
+#define USB_ENDPOINT_TYPE_CONTROL	0x00
+#define USB_ENDPOINT_TYPE_ISOCHRONOUS	0x01
+#define USB_ENDPOINT_TYPE_BULK		0x02
+#define USB_ENDPOINT_TYPE_INTERRUPT	0x03
+
+/* Function prototypes */
+uint8_t		d12_get_data(void);
+void		d12_set_data(uint8_t data);
+void		d12_set_cmd(uint8_t cmd);
+void		d12_write_cmd(uint8_t command, const uint8_t *buffer, uint8_t count);
+void		d12_read_cmd(uint8_t command, uint8_t *buffer, uint8_t count);
+uint8_t		d12_read_endpt(uint8_t endpt, uint8_t *buffer);
+
+void		d12_ep0_irq(void);
+void		d12_getdescriptor(USB_SETUP_REQUEST *SetupPacket);
+void		d12_stallctrlendpt(void);
+uint8_t		d12_read_endpt(uint8_t endpt, uint8_t *buffer);
+void		d12_write_endpt(uint8_t endpt, const uint8_t *buffer, uint8_t bytes);
+void		d12_write_buffer_ep0(void);
+void		d12_send_data_ep2(void);
+void		d12_receive_data_ep2(void);
+
+static void	reset(void);
+
+void		usb_init(void);
+void		usb_intr(void);
+void		usb_gendata(void);