view usb.c @ 45:efd44dc40934

Add macros for number system used for temperatures. Add error strings and improve comments for ROM programming.
author darius@Inchoate
date Mon, 20 Oct 2008 22:11:18 +1030
parents 5898fba6593c
children
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\r\n"));
	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\r\n"));
    
    if (irq[0] & D12_INT_BUS_RESET) {
	uart_putsP(PSTR("Bus reset\r\n"));
	usb_init();
	return;
    }
    
    if (irq[0] & D12_INT_SUSPEND) {
	uart_putsP(PSTR("Suspend change\r\n"));
    }
	
    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("\r\n"));
	}

	/* 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("\r\n"));
	}

	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("\r\n"));
	}
	    
	/* Select endpoint */
	d12_read_cmd(D12_ENDPOINT_EP1_IN, buffer, 1);

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

	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("\r\n"));
	}

	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("\r\n"));
	}

	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("\r\n"));
	}
	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!\r\n"));
    _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..\r\n"));
	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\r\n"));
	
    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\r\n"));
	
    /* 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()\r\n"));
	    buffer[0] = OWTouchReset();
	    d12_write_endpt(ep, buffer, 1);
	    break;
		
	case 0x01:
	    uart_putsP(PSTR("OWFirst()\r\n"));
	    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("\r\n"));
	    d12_write_endpt(ep, buffer, 9);
	    break;

	case 0x02:
	    uart_putsP(PSTR("OWNext()\r\n"));
	    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("\r\n"));
	    d12_write_endpt(ep, buffer, 9);
		
	    break;
		
	default:
	    uart_putsP(PSTR("Unknown command on endpoint 1\r\n"));
	    break;
    }
}