view usb.c @ 35:fed32b382de2

Tidy up, hide details behind macros to make it more obvious what we talk to do do things. Convert constants to my preferred format.
author darius
date Tue, 23 Oct 2007 10:54:01 +0930
parents 4e417d84365e
children 5898fba6593c
line wrap: on
line source

#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"
#include "1wire.h"

/* Maximum FIFO sizes for each endpoint */
#define EP0_FIFO_SZ 16
#define EP1_FIFO_SZ 16
#define EP2_FIFO_SZ 64

/* PDIUSBD12 mode */
#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);

void		parsebuf(uint8_t *buffer, uint8_t ep);

/* USB administrivia */
uint8_t deviceaddress;
uint8_t deviceconfigured;

/* Endpoint buffers and such */
/* EP0 in */
static const uint8_t *sendbuffer0;
static uint8_t sendbytes0;

/* EP0 out */
/* This is unbuffered as we don't handle packets > EP0_FIFO_SZ */

/* EP1 */
/* Unbuffered as yet */
static uint8_t packet1[270];
static uint16_t packetlen1;

/* EP2 in */
static const uint8_t *sendbuffer2;
static uint8_t sendbytes2;

/* EP2 out */
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_FIFO_SZ,			/* bMaxPacketSize in Bytes */
    0x4753,				/* idVendor (unofficial 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 */
};

STRING_DESCRIPTOR Manufacturer_Descriptor = {
    sizeof(STRING_DESCRIPTOR) + 32,			/* 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 */
};

STRING_DESCRIPTOR Product_Descriptor = {
    sizeof(STRING_DESCRIPTOR) + 48,		/* 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.. */
};   

STRING_DESCRIPTOR Serial_Descriptor;
STRING_DESCRIPTOR EE_Serial_Descriptor  __attribute__ ((section (".eeprom"))) = { /* SerialString 3 */
    sizeof(STRING_DESCRIPTOR) + 20,	/* bLength - must match string below */
    TYPE_STRING_DESCRIPTOR,		/* bDescriptorType */
    "1\02\03\0"
};

/*******************************************************************************
** d12_get_data
**
** Read a data byte
*/
uint8_t
d12_get_data(void) {
    uint8_t data;

    _delay_us(1);
    PDICTL &= ~_BV(PDIA0);	/* Data phase */
    PDIDDR = 0x00;		/* Set to input */
    PDICTL &= ~_BV(PDIRD);	/* Pull RD_N low */
    PDICTL &= ~_BV(PDIRD);	/* Delay 40ns */
    PDICTL &= ~_BV(PDIRD);
    PDICTL &= ~_BV(PDIRD);
    data = PINA;		/* Read the data */
    PDICTL |= _BV(PDIRD);	/* Pull RD_N high */

    return(data);
}

/*******************************************************************************
** d12_set_data
**
** Write a data byte
*/
void
d12_set_data(uint8_t data) {
    _delay_us(1);
    PDICTL &= ~_BV(PDIA0);	/* Data phase */
    PDIDDR = 0xff;		/* Set to output */
    PDIPORT = data;		/* Put the data on the bus */
    PDICTL &= ~_BV(PDIWR);	/* Pull WR_N low */
    PDICTL &= ~_BV(PDIWR);	/* Delay 40ns */
    PDICTL &= ~_BV(PDIWR);
    PDICTL &= ~_BV(PDIWR);
    PDICTL |= _BV(PDIWR);	/* Pull WR_N high */
    PDICTL |= _BV(PDIWR);	/* Delay 40 ns */
    PDICTL |= _BV(PDIWR);	 
    PDICTL |= _BV(PDIWR);	 
    PDIDDR = 0x00;		/* Back to input */
}

/*******************************************************************************
** d12_set_cmd
**
** Start a command
*/
void
d12_set_cmd(uint8_t cmd) {
    _delay_us(1);
    PDICTL |= _BV(PDIA0);	/* Command phase */
    PDIDDR = 0xff;		/* Set to output */
    PDIPORT = cmd;		/* Put the data on the bus */
    PDICTL &= ~_BV(PDIWR);	/* Pull WR_N low */
    PDICTL &= ~_BV(PDIWR);	/* Delay 40ns */
    PDICTL &= ~_BV(PDIWR);
    PDICTL &= ~_BV(PDIWR);
    PDICTL |= _BV(PDIWR);	/* Pull WR_N high */
    PDICTL |= _BV(PDIWR);	/* Delay 40ns */
    PDICTL |= _BV(PDIWR);
    PDICTL |= _BV(PDIWR);
    PDIDDR = 0x00;		/* Back to input */
}

/*******************************************************************************
** d12_write_cmd
**
** Issue a command with associated data
*/
void 
d12_write_cmd(uint8_t command, const uint8_t *buffer, uint8_t count) {
    uint8_t i;

    d12_set_cmd(command);
    if (count) {
	for (i = 0; i < count; i++) {
	    d12_set_data(buffer[i]);
	}
    }
}

/*******************************************************************************
** d12_read_cmd
**
** Issue a command and read back the data
*/
void 
d12_read_cmd(uint8_t command, uint8_t *buffer, uint8_t count) {
    uint8_t i;

    d12_set_cmd(command);
    if (count) {
	for (i = 0; i < count; i++) {
	    buffer[i] = d12_get_data();
	}
    }
}

/*******************************************************************************
** usb_init
**
** Configure the PDIUSBD12
*/
void
usb_init(void) {
    uint8_t	buffer[2];
    
    /* Check the device is present */
    d12_read_cmd(D12_READ_CHIP_ID, buffer, 2);
    if (buffer[0] != 0x12 || buffer[1] != 0x10) {
	uart_putsP(PSTR("PDIUSBD12 does not appear to be present/working, chip ID = 0x"));
	uart_puts_hex(buffer[0]);
	uart_puts_hex(buffer[1]);
	uart_putsP(PSTR(", expected 0x1210\n\r"));
	return;
    }
    
    /* pull EE_Serial_Descriptor into RAM */
    eeprom_read_block(&Serial_Descriptor, &EE_Serial_Descriptor, EE_Serial_Descriptor.bLength);

    /* 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);

}

/*******************************************************************************
** usb_intr
**
** Process any pending interrupts
*/
void
usb_intr(void) {
    uint8_t	irq[2];
    uint8_t	buffer[8];
    
    d12_read_cmd(D12_READ_INTERRUPT_REGISTER, irq, 2);

    /* Why do we get interrupts when this is 0? */
    if (irq[0] == 0)
	return;

    uart_putsP(PSTR("usb_intr() called\n\r"));
    
    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);
	if ((buffer[0] & D12_LAST_TRAN_ERRMSK) != 0) {
	    uart_putsP(PSTR("EP0_IN error "));
	    uart_puts_hex((buffer[0] & D12_LAST_TRAN_ERRMSK) >> 1);
	    uart_putsP(PSTR("\n\r"));
	}

	/* Handle any outgoing data for EP0 */
	d12_send_data_ep0();
    }
    
    /* Handle configuration and misc stuff */
    if (irq[0] & D12_INT_EP0_OUT) {
	d12_read_cmd(D12_READ_LAST_TRANSACTION + D12_ENDPOINT_EP0_OUT, buffer, 1);
	if ((buffer[0] & D12_LAST_TRAN_ERRMSK) != 0) {
	    uart_putsP(PSTR("EP0_OUT error "));
	    uart_puts_hex((buffer[0] & D12_LAST_TRAN_ERRMSK) >> 1);
	    uart_putsP(PSTR("\n\r"));
	}

	if (buffer[0] & D12_LAST_TRAN_SETUP)
	    d12_handle_setup();
	else {
	    /* Data packet */
	}
    }
    
    /* EPx_IN is when the host has had a packet of data and is expecting more */
    if (irq[0] & D12_INT_EP1_IN) {
	d12_read_cmd(D12_READ_LAST_TRANSACTION + D12_ENDPOINT_EP1_IN, buffer, 1);
	if ((buffer[0] & D12_LAST_TRAN_ERRMSK) != 0) {
	    uart_putsP(PSTR("EP1_IN error "));
	    uart_puts_hex((buffer[0] & D12_LAST_TRAN_ERRMSK) >> 1);
	    uart_putsP(PSTR("\n\r"));
	}
	    
	/* Select endpoint */
	d12_read_cmd(D12_ENDPOINT_EP1_IN, buffer, 1);

	if (buffer[0] & 0x01)
	    uart_putsP(PSTR("EP1_IN is full\n\r"));
	
	if (buffer[0] & 0x02)
	    uart_putsP(PSTR("EP1_IN is stalled\n\r"));

	d12_write_endpt(D12_ENDPOINT_EP1_IN, NULL, 0);
    }
    
    /* EPx_OUT is when we have gotten a packet from the host */
    if (irq[0] & D12_INT_EP1_OUT) {
	d12_read_cmd(D12_READ_LAST_TRANSACTION + D12_ENDPOINT_EP1_OUT, buffer, 1);
	if ((buffer[0] & D12_LAST_TRAN_ERRMSK) != 0) {
	    uart_putsP(PSTR("EP1_OUT error "));
	    uart_puts_hex((buffer[0] & D12_LAST_TRAN_ERRMSK) >> 1);
	    uart_putsP(PSTR("\n\r"));
	}

	d12_receive_data_ep1();
    }

    if (irq[0] & D12_INT_EP2_IN) {	
	d12_read_cmd(D12_READ_LAST_TRANSACTION + D12_ENDPOINT_EP2_IN, buffer, 1);
	if ((buffer[0] & D12_LAST_TRAN_ERRMSK) != 0) {
	    uart_putsP(PSTR("EP2_IN error "));
	    uart_puts_hex((buffer[0] & D12_LAST_TRAN_ERRMSK) >> 1);
	    uart_putsP(PSTR("\n\r"));
	}

	d12_send_data_ep2();
    }
    
    if (irq[0] & D12_INT_EP2_OUT) {
	d12_read_cmd(D12_READ_LAST_TRANSACTION + D12_ENDPOINT_EP2_OUT, buffer, 1);
	if ((buffer[0] & D12_LAST_TRAN_ERRMSK) != 0) {
	    uart_putsP(PSTR("EP2_OUT error "));
	    uart_puts_hex((buffer[0] & D12_LAST_TRAN_ERRMSK) >> 1);
	    uart_putsP(PSTR("\n\r"));
	}
	d12_receive_data_ep2();
    }
}

/*******************************************************************************
** usb_gendata
**
** Fake up some data for testing purposes
*/
void
usb_gendata(void) {
    packet2[0] = 'a';
    packet2[1] = 'b';
    packet2[2] = 'c';
    packet2[3] = '\n';
    packet2[4] = '\r';
    sendbytes2 = 5;
    sendbuffer2 = (uint8_t *)&packet2[0];

    /* Kick off the data transfer */
    d12_send_data_ep2();
}

/*******************************************************************************
** d12_handle_setup
**
** Handle setup packet stuff for endpoint 0
*/
void
d12_handle_setup(void) {
    uint8_t		buffer[2];
    USB_SETUP_REQUEST	setuppkt;

    /* 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);
	
    /* 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_stallendpt(D12_ENDPOINT_EP0_IN);
		    d12_stallendpt(D12_ENDPOINT_EP0_OUT);
		    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_stallendpt(D12_ENDPOINT_EP0_IN);
		    d12_stallendpt(D12_ENDPOINT_EP0_OUT);
		    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_stallendpt(D12_ENDPOINT_EP0_IN);
			d12_stallendpt(D12_ENDPOINT_EP0_OUT);
		    }
			
		    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_stallendpt(D12_ENDPOINT_EP0_IN);
		    d12_stallendpt(D12_ENDPOINT_EP0_OUT);
		    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_stallendpt(D12_ENDPOINT_EP0_IN);
				d12_stallendpt(D12_ENDPOINT_EP0_OUT);
				break;
			}
			d12_write_endpt(D12_ENDPOINT_EP0_IN, NULL, 0);
		    } else {
			/*
			 * No other Features for Endpoint -
			 * Request Error
			 */
			d12_stallendpt(D12_ENDPOINT_EP0_IN);
			d12_stallendpt(D12_ENDPOINT_EP0_OUT);
		    }
		    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_stallendpt(D12_ENDPOINT_EP0_IN);
			    d12_stallendpt(D12_ENDPOINT_EP0_OUT);
			    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_stallendpt(D12_ENDPOINT_EP0_IN);
		    d12_stallendpt(D12_ENDPOINT_EP0_OUT);
		    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_stallendpt(D12_ENDPOINT_EP0_IN);
		    d12_stallendpt(D12_ENDPOINT_EP0_OUT);
		    break;
	    }
	    break;
	case VENDOR_INTERFACE_REQUEST:
	    switch (setuppkt.bRequest) {
		default:
		    d12_stallendpt(D12_ENDPOINT_EP0_IN);
		    d12_stallendpt(D12_ENDPOINT_EP0_OUT);
		    break;
	    }
	    break;
	default:
	    d12_stallendpt(D12_ENDPOINT_EP0_IN);
	    d12_stallendpt(D12_ENDPOINT_EP0_OUT);
	    break;
    }
}


/*******************************************************************************
** reset
**
** Reset the micro by triggering the watchdog timer.
**
*/
void
reset(void) {
    uart_putsP(PSTR("Resetting!\n\r"));
    _delay_us(1000);
    
    /* Disable the interrupts */
    MCUCR = _BV(IVCE);
    MCUCR = 0;

    /* Enable watchdog, smallest prescaler */
    WDTCR = _BV(WDE);

    /* Wait for oblivion! */
    for (;;)
	;
}

/*******************************************************************************
** d12_getdescriptor
**
** Handle returning the various descriptor to the host
**
** Note: that we need to truncate the request because the host first
** requests the first 2 bytes to find out then size, then requests the
** rest.
*/
void 
d12_getdescriptor(USB_SETUP_REQUEST *setuppkt) {
    switch ((setuppkt->wValue & 0xff00) >> 8) {
	case TYPE_DEVICE_DESCRIPTOR:
	    sendbuffer0 = (const uint8_t *)&DeviceDescriptor;
	    sendbytes0 = DeviceDescriptor.bLength;
	    if (sendbytes0 >= setuppkt->wLength)
		sendbytes0 = setuppkt->wLength;

	    d12_send_data_ep0();
	    break;

	case TYPE_CONFIGURATION_DESCRIPTOR:
	    sendbuffer0 = (const uint8_t *)&ConfigurationDescriptor;
	    sendbytes0 = sizeof(ConfigurationDescriptor);
	    if (sendbytes0 >= setuppkt->wLength)
		sendbytes0 = setuppkt->wLength;

	    d12_send_data_ep0();
	    break;

	case TYPE_STRING_DESCRIPTOR:
	    switch (setuppkt->wValue & 0xFF) {
		case 0:
		    sendbuffer0 = (const uint8_t *)&LANGID_Descriptor;
		    sendbytes0 = LANGID_Descriptor.bLength;
		    break;

		case 1:
		    sendbuffer0 = (const uint8_t *)&Manufacturer_Descriptor;
		    sendbytes0 = Manufacturer_Descriptor.bLength;
		    break;

		case 2:
		    sendbuffer0 = (const uint8_t *)&Product_Descriptor;
		    sendbytes0 = Product_Descriptor.bLength;
		    break;

		case 3:
		    sendbuffer0 = (const uint8_t *)&Serial_Descriptor;
		    sendbytes0 = Serial_Descriptor.bLength;
		    break;

		default:
		    sendbuffer0 = NULL;
		    sendbytes0 = 0;
	    }
	    if (sendbytes0 >= setuppkt->wLength)
		sendbytes0 = setuppkt->wLength;

	    d12_send_data_ep0();
	    break;

	default:
	    d12_stallendpt(D12_ENDPOINT_EP0_IN);
	    d12_stallendpt(D12_ENDPOINT_EP0_OUT);
	    break;
    }
}

/*******************************************************************************
** d12_stallendpt
**
** Stall the nominated endpoint.
**
*/
void 
d12_stallendpt(uint8_t ep) {
    uint8_t   buffer[] = {0x01};

    d12_write_cmd(D12_SET_ENDPOINT_STATUS + ep, buffer, 1);
}
    
/*******************************************************************************
** d12_read_cmd
**
** Read data from the nominated endpoint if it's full.
**
*/
uint8_t
d12_read_endpt(uint8_t endpt, uint8_t *buffer) {
    uint8_t d12header[2], status, i;

    d12header[1] = 0;
    
    /* Select Endpoint */
    d12_read_cmd(endpt, &status, 1);

    /* Check if buffer is Full */
    if (status & 0x01) {
	d12_set_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];
}

/*******************************************************************************
** d12_read_cmd
**
** Write data to the nominated endpoint.
**
*/
void 
d12_write_endpt(uint8_t endpt, const uint8_t *buffer, uint8_t bytes) {
    uint8_t status, i;

    /* Select Endpoint */
    d12_read_cmd(endpt, &status, 1);
    if ((status & 0x01) != 0) {
	uart_putsP(PSTR("Endpoint "));
	uart_puts_dec(endpt / 2, 0);
	uart_putsP(PSTR(" IN is full..\n\r"));
	return;
    }
    
    /* Write Header */
    d12_set_cmd(D12_WRITE_BUFFER);
    d12_set_data(0x00);
    d12_set_data(bytes);
    /* Write Packet */
    if (bytes) {
	for (i = 0; i < bytes; i++)
	    d12_set_data(buffer[i]);
    }
    /* Validate buffer */
    d12_write_cmd(D12_VALIDATE_BUFFER, NULL, 0);
}

/*******************************************************************************
** d12_send_data_ep0
**
** Send the next FIFOs worth of data to the endpoint and update the
** pointer and counters.
**
** d12_send_data_epX should be collapsed together but it's more
** complex than it looks.
**
*/
void 
d12_send_data_ep0(void) {
    uint8_t status;

    /* Select endpoint */
    d12_read_cmd(D12_ENDPOINT_EP0_IN, &status, 1);

    if (status & 0x01)	/* Bail if the buffer is full */
	return;
    
    if (sendbytes0 == 0) {
	/* Nothing to do */
    } else if (sendbytes0 >= EP0_FIFO_SZ) {
	/* Write another EP0_FIFO_SZ Bytes to buffer and send */
	d12_write_endpt(D12_ENDPOINT_EP0_IN, sendbuffer0, EP0_FIFO_SZ);
	sendbuffer0 += EP0_FIFO_SZ;
	sendbytes0 -= EP0_FIFO_SZ;
    } else {
	/* Buffer must have less than EP0_FIFO_SZ bytes left */
	d12_write_endpt(D12_ENDPOINT_EP0_IN, sendbuffer0, sendbytes0);
	sendbytes0 = 0;
    }
}

/*******************************************************************************
** d12_send_data_ep2
**
** Send the next FIFOs worth of data to the endpoint and update the
** pointer and counters.
**
*/
void
d12_send_data_ep2(void) {
    uint8_t status;

    /* Select endpoint */
    d12_read_cmd(D12_ENDPOINT_EP2_IN, &status, 1);

    if (status & 0x01)   /* Bail if the buffer is full */
	return;

    if (sendbytes2 == 0) {
	/* Nothing to do */
    } else if (sendbytes2 >= EP2_FIFO_SZ) {
	/* Write another EP2_FIFO_SZ Bytes to buffer and send */
	d12_write_endpt(D12_ENDPOINT_EP2_IN, sendbuffer2, EP2_FIFO_SZ);
	sendbuffer2 += EP2_FIFO_SZ;
	sendbytes2 -= EP2_FIFO_SZ;
    } else {
	/* Buffer must have less than EP2_FIFO_SZ bytes left */
	d12_write_endpt(D12_ENDPOINT_EP2_IN, sendbuffer2, sendbytes2);
	sendbytes2 = 0;
    }
}

/*******************************************************************************
** d12_receive_data_ep2
**
** Get the next FIFOs worth of data from the endpoint
**
*/
void
d12_receive_data_ep2(void) {
    uint8_t d12header[2], bytes, i, status;
    
    /* Select Endpoint */
    d12_read_cmd(D12_ENDPOINT_EP2_OUT, &status, 1);

    if (!(status & 0x01))	/* Bail if the buffer is empty */
	return;
    
    /* Read header */
    d12_set_cmd(D12_READ_BUFFER);
    d12header[0] = d12_get_data();
    d12header[1] = d12_get_data();
    bytes = d12header[1];

    packetlen2 = 0;
    
    for (i = 0; i < bytes; i++)
	packet2[i] = d12_get_data();

    packetlen2 += bytes;

    /* Allow new packets to be accepted */
    d12_write_cmd(D12_CLEAR_BUFFER, NULL, 0);

    uart_putsP(PSTR("Got "));
    uart_puts_dec(bytes, 0);
    uart_putsP(PSTR(" bytes from the host\n\r"));
	
    parsebuf(packet2, D12_ENDPOINT_EP2_IN);
    
}

/*******************************************************************************
** d12_receive_data_ep1
**
** Get the next FIFOs worth of data from the endpoint
**
*/
void
d12_receive_data_ep1(void) {
    uint8_t d12header[2], bytes, i, status;
    
    /* Select Endpoint */
    d12_read_cmd(D12_ENDPOINT_EP1_OUT, &status, 1);

    /* Check if Buffer is Full */
    if (!(status & 0x01))
	return;
    
    /* Read header */
    d12_set_cmd(D12_READ_BUFFER);
    d12header[0] = d12_get_data();
    d12header[1] = d12_get_data();
    bytes = d12header[1];

    packetlen1 = 0;
    
    for (i = 0; i < bytes; i++)
	packet1[i] = d12_get_data();

    packetlen1 += bytes;

    uart_putsP(PSTR("Got "));
    uart_puts_dec(bytes, 0);
    uart_putsP(PSTR(" bytes from the host\n\r"));
	
    /* Allow new packets to be accepted */
    d12_write_cmd(D12_CLEAR_BUFFER, NULL, 0);

    parsebuf(packet1, D12_ENDPOINT_EP1_IN);
}

void
parsebuf(uint8_t *buffer, uint8_t ep) {
    int		i;

    switch (buffer[0]) {
	case 0x00:
	    uart_putsP(PSTR("OWTouchReset()\n\r"));
	    buffer[0] = OWTouchReset();
	    d12_write_endpt(ep, buffer, 1);
	    break;
		
	case 0x01:
	    uart_putsP(PSTR("OWFirst()\n\r"));
	    buffer[0] = OWFirst(&buffer[1], 1, 0);
	    for (i = 0; i < 9; i++) {
		uart_puts_hex(buffer[i + 1]);
		uart_putsP(PSTR(" "));
	    }
	    uart_putsP(PSTR("\n\r"));
	    d12_write_endpt(ep, buffer, 9);
	    break;

	case 0x02:
	    uart_putsP(PSTR("OWNext()\n\r"));
	    buffer[0] = OWNext(&buffer[1], 1, 0);
	    d12_write_endpt(ep, buffer, 9);
	    break;

	case 0x03:
	    uart_putsP(PSTR(" bytes, asked to do temperature conversion for "));
	    for (i = 0; i < 8; i++) {
		uart_puts_hex(buffer[i + 1]);
		if (i != 7)
		    uart_putsP(PSTR(":"));
	    }

	    uart_putsP(PSTR("\n\r"));
	    d12_write_endpt(ep, buffer, 9);
		
	    break;
		
	default:
	    uart_putsP(PSTR("Unknown command on endpoint 1\n\r"));
	    break;
    }
}