Mercurial > ~darius > hgwebdir.cgi > avr
view usb.c @ 36:e40e919721b0
Conditionalise USB support, use DWARF debugging as AVR studio groks
it.
author | darius |
---|---|
date | Tue, 23 Oct 2007 10:55:51 +0930 |
parents | fed32b382de2 |
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; } }