/* USB Keyboard and CDC Serial Device for Teensy USB Development Board * Copyright (c) 2009 PJRC.COM, LLC * Modifications by Jacob Alexander (2011-2014) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // Local Includes #include "usb_keyboard_serial.h" // ----- Functions ----- // Set the avr into firmware reload mode void usb_debug_reload() { cli(); // Disable watchdog, if enabled // Disable all peripherals UDCON = 1; USBCON = (1 << FRZCLK); // Disable USB UCSR1B = 0; _delay_ms( 5 ); #if defined(__AVR_AT90USB162__) // Teensy 1.0 EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; TIMSK0 = 0; TIMSK1 = 0; UCSR1B = 0; DDRB = 0; DDRC = 0; DDRD = 0; PORTB = 0; PORTC = 0; PORTD = 0; asm volatile("jmp 0x3E00"); #elif defined(__AVR_ATmega32U4__) // Teensy 2.0 EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0; TIMSK0 = 0; TIMSK1 = 0; TIMSK3 = 0; TIMSK4 = 0; UCSR1B = 0; TWCR = 0; DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0; TWCR = 0; PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0; asm volatile("jmp 0x7E00"); #elif defined(__AVR_AT90USB646__) // Teensy++ 1.0 EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0; TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0; TIMSK3 = 0; UCSR1B = 0; TWCR = 0; DDRA = 0; DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0; PORTA = 0; PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0; asm volatile("jmp 0xFC00"); #elif defined(__AVR_AT90USB1286__) // Teensy++ 2.0 EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0; TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0; TIMSK3 = 0; UCSR1B = 0; TWCR = 0; DDRA = 0; DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0; PORTA = 0; PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0; asm volatile("jmp 0x1FC00"); #endif } // WDT Setup for software reset the chip void wdt_init(void) { MCUSR = 0; wdt_disable(); } /************************************************************************** * * Configurable Options * **************************************************************************/ // When you write data, it goes into a USB endpoint buffer, which // is transmitted to the PC when it becomes full, or after a timeout // with no more writes. Even if you write in exactly packet-size // increments, this timeout is used to send a "zero length packet" // that tells the PC no more data is expected and it should pass // any buffered data to the application that may be waiting. If // you want data sent immediately, call usb_serial_flush_output(). #define TRANSMIT_FLUSH_TIMEOUT 5 /* in milliseconds */ // If the PC is connected but not "listening", this is the length // of time before usb_serial_getchar() returns with an error. This // is roughly equivilant to a real UART simply transmitting the // bits on a wire where nobody is listening, except you get an error // code which you can ignore for serial-like discard of data, or // use to know your data wasn't sent. #define TRANSMIT_TIMEOUT 25 /* in milliseconds */ // USB devices are supposed to implment a halt feature, which is // rarely (if ever) used. If you comment this line out, the halt // code will be removed, saving 116 bytes of space (gcc 4.3.0). // This is not strictly USB compliant, but works with all major // operating systems. #define SUPPORT_ENDPOINT_HALT /************************************************************************** * * Descriptor Data * **************************************************************************/ // Descriptors are the data that your computer reads when it auto-detects // this USB device (called "enumeration" in USB lingo). The most commonly // changed items are editable at the top of this file. Changing things // in here should only be done by those who've read chapter 9 of the USB // spec and relevant portions of any USB class specifications! static const uint8_t PROGMEM device_descriptor[] = { 18, // bLength 1, // bDescriptorType 0x00, 0x02, // bcdUSB 0, // bDeviceClass 0, // bDeviceSubClass 0, // bDeviceProtocol ENDPOINT0_SIZE, // bMaxPacketSize0 LSB(VENDOR_ID), MSB(VENDOR_ID), // idVendor LSB(PRODUCT_ID), MSB(PRODUCT_ID), // idProduct 0x00, 0x01, // bcdDevice 1, // iManufacturer 2, // iProduct 3, // iSerialNumber 1 // bNumConfigurations }; // Keyboard Protocol 1, HID 1.11 spec, Appendix B, page 59-60 static const uint8_t PROGMEM keyboard_hid_report_desc[] = { 0x05, 0x01, // Usage Page (Generic Desktop), 0x09, 0x06, // Usage (Keyboard), 0xA1, 0x01, // Collection (Application), 0x75, 0x01, // Report Size (1), 0x95, 0x08, // Report Count (8), 0x05, 0x07, // Usage Page (Key Codes), 0x19, 0xE0, // Usage Minimum (224), 0x29, 0xE7, // Usage Maximum (231), 0x15, 0x00, // Logical Minimum (0), 0x25, 0x01, // Logical Maximum (1), 0x81, 0x02, // Input (Data, Variable, Absolute), ;Modifier byte 0x95, 0x08, // Report Count (8), 0x75, 0x01, // Report Size (1), 0x15, 0x00, // Logical Minimum (0), 0x25, 0x01, // Logical Maximum (1), 0x05, 0x0C, // Usage Page (Consumer), 0x09, 0xE9, // Usage (Volume Increment), 0x09, 0xEA, // Usage (Volume Decrement), 0x09, 0xE2, // Usage (Mute), 0x09, 0xCD, // Usage (Play/Pause), 0x09, 0xB5, // Usage (Scan Next Track), 0x09, 0xB6, // Usage (Scan Previous Track), 0x09, 0xB7, // Usage (Stop), 0x09, 0xB8, // Usage (Eject), 0x81, 0x02, // Input (Data, Variable, Absolute), ;Media keys 0x95, 0x05, // Report Count (5), 0x75, 0x01, // Report Size (1), 0x05, 0x08, // Usage Page (LEDs), 0x19, 0x01, // Usage Minimum (1), 0x29, 0x05, // Usage Maximum (5), 0x91, 0x02, // Output (Data, Variable, Absolute), ;LED report 0x95, 0x01, // Report Count (1), 0x75, 0x03, // Report Size (3), 0x91, 0x03, // Output (Constant), ;LED report padding 0x95, 0x06, // Report Count (6), 0x75, 0x08, // Report Size (8), 0x15, 0x00, // Logical Minimum (0), 0x25, 0x7F, // Logical Maximum(104), 0x05, 0x07, // Usage Page (Key Codes), 0x19, 0x00, // Usage Minimum (0), 0x29, 0x7F, // Usage Maximum (104), 0x81, 0x00, // Input (Data, Array), ;Normal keys 0xc0 // End Collection }; // + + #define CONFIG1_DESC_SIZE (9 + 9+9+7 + 8+9+5+5+4+5+7+9+7+7) #define KEYBOARD_HID_DESC_OFFSET (9 + 9) #define SERIAL_CDC_DESC_OFFSET (9 + 9+9+7) static const uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = { // --- Configuration --- // - 9 bytes - // configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10 9, // bLength; 2, // bDescriptorType; LSB(CONFIG1_DESC_SIZE), // wTotalLength MSB(CONFIG1_DESC_SIZE), 3, // bNumInterfaces 1, // bConfigurationValue 0, // iConfiguration 0xC0, // bmAttributes 50, // bMaxPower // --- Keyboard HID --- // - 9 bytes - // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 9, // bLength 4, // bDescriptorType KEYBOARD_INTERFACE, // bInterfaceNumber 0, // bAlternateSetting 1, // bNumEndpoints 0x03, // bInterfaceClass (0x03 = HID) 0x01, // bInterfaceSubClass (0x01 = Boot) 0x01, // bInterfaceProtocol (0x01 = Keyboard) 0, // iInterface // - 9 bytes - // HID interface descriptor, HID 1.11 spec, section 6.2.1 9, // bLength 0x21, // bDescriptorType 0x11, 0x01, // bcdHID 0, // bCountryCode 1, // bNumDescriptors 0x22, // bDescriptorType LSB(sizeof(keyboard_hid_report_desc)), // wDescriptorLength MSB(sizeof(keyboard_hid_report_desc)), // - 7 bytes - // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 7, // bLength 5, // bDescriptorType KEYBOARD_ENDPOINT | 0x80, // bEndpointAddress 0x03, // bmAttributes (0x03=intr) KEYBOARD_SIZE, 0, // wMaxPacketSize KEYBOARD_INTERVAL, // bInterval // --- Serial CDC --- // - 8 bytes - // interface association descriptor, USB ECN, Table 9-Z 8, // bLength 11, // bDescriptorType CDC_STATUS_INTERFACE, // bFirstInterface 2, // bInterfaceCount 0x02, // bFunctionClass 0x02, // bFunctionSubClass 0x01, // bFunctionProtocol 4, // iFunction // - 9 bytes - // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 9, // bLength 4, // bDescriptorType CDC_STATUS_INTERFACE, // bInterfaceNumber 0, // bAlternateSetting 1, // bNumEndpoints 0x02, // bInterfaceClass 0x02, // bInterfaceSubClass 0x01, // bInterfaceProtocol 0, // iInterface // - 5 bytes - // CDC Header Functional Descriptor, CDC Spec 5.2.3.1, Table 26 5, // bFunctionLength 0x24, // bDescriptorType 0x00, // bDescriptorSubtype 0x10, 0x01, // bcdCDC // - 5 bytes - // Call Management Functional Descriptor, CDC Spec 5.2.3.2, Table 27 5, // bFunctionLength 0x24, // bDescriptorType 0x01, // bDescriptorSubtype 0x01, // bmCapabilities 1, // bDataInterface // - 4 bytes - // Abstract Control Management Functional Descriptor, CDC Spec 5.2.3.3, Table 28 4, // bFunctionLength 0x24, // bDescriptorType 0x02, // bDescriptorSubtype 0x06, // bmCapabilities // - 5 bytes - // Union Functional Descriptor, CDC Spec 5.2.3.8, Table 33 5, // bFunctionLength 0x24, // bDescriptorType 0x06, // bDescriptorSubtype CDC_STATUS_INTERFACE, // bMasterInterface CDC_DATA_INTERFACE, // bSlaveInterface0 // - 7 bytes - // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 7, // bLength 5, // bDescriptorType CDC_ACM_ENDPOINT | 0x80, // bEndpointAddress 0x03, // bmAttributes (0x03=intr) CDC_ACM_SIZE, 0, // wMaxPacketSize 64, // bInterval // - 9 bytes - // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 9, // bLength 4, // bDescriptorType CDC_DATA_INTERFACE, // bInterfaceNumber 0, // bAlternateSetting 2, // bNumEndpoints 0x0A, // bInterfaceClass 0x00, // bInterfaceSubClass 0x00, // bInterfaceProtocol 0, // iInterface // - 7 bytes - // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 7, // bLength 5, // bDescriptorType CDC_RX_ENDPOINT, // bEndpointAddress 0x02, // bmAttributes (0x02=bulk) CDC_RX_SIZE, 0, // wMaxPacketSize 0, // bInterval // - 7 bytes - // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 7, // bLength 5, // bDescriptorType CDC_TX_ENDPOINT | 0x80, // bEndpointAddress 0x02, // bmAttributes (0x02=bulk) CDC_TX_SIZE, 0, // wMaxPacketSize 0, // bInterval }; // If you're desperate for a little extra code memory, these strings // can be completely removed if iManufacturer, iProduct, iSerialNumber // in the device desciptor are changed to zeros. struct usb_string_descriptor_struct { uint8_t bLength; uint8_t bDescriptorType; int16_t wString[]; }; static const struct usb_string_descriptor_struct PROGMEM string0 = { 4, 3, {0x0409} }; static const struct usb_string_descriptor_struct PROGMEM string1 = { sizeof(STR_MANUFACTURER), 3, STR_MANUFACTURER }; static const struct usb_string_descriptor_struct PROGMEM string2 = { sizeof(STR_PRODUCT), 3, STR_PRODUCT }; static const struct usb_string_descriptor_struct PROGMEM string3 = { sizeof(STR_SERIAL), 3, STR_SERIAL }; // This table defines which descriptor data is sent for each specific // request from the host (in wValue and wIndex). static const struct descriptor_list_struct { uint16_t wValue; uint16_t wIndex; const uint8_t *addr; uint8_t length; } PROGMEM descriptor_list[] = { {0x0100, 0x0000, device_descriptor, sizeof(device_descriptor)}, {0x0200, 0x0000, config1_descriptor, sizeof(config1_descriptor)}, {0x2200, KEYBOARD_INTERFACE, keyboard_hid_report_desc, sizeof(keyboard_hid_report_desc)}, {0x2100, KEYBOARD_INTERFACE, config1_descriptor+KEYBOARD_HID_DESC_OFFSET, 9}, {0x0300, 0x0000, (const uint8_t *)&string0, 4}, {0x0301, 0x0409, (const uint8_t *)&string1, sizeof(STR_MANUFACTURER)}, {0x0302, 0x0409, (const uint8_t *)&string2, sizeof(STR_PRODUCT)}, {0x0303, 0x0409, (const uint8_t *)&string3, sizeof(STR_SERIAL)} }; #define NUM_DESC_LIST (sizeof(descriptor_list)/sizeof(struct descriptor_list_struct)) /************************************************************************** * * Variables - these are the only non-stack RAM usage * **************************************************************************/ // zero when we are not configured, non-zero when enumerated static volatile uint8_t usb_configuration=0; // the time remaining before we transmit any partially full // packet, or send a zero length packet. static volatile uint8_t transmit_flush_timer=0; static uint8_t transmit_previous_timeout=0; // serial port settings (baud rate, control signals, etc) set // by the PC. These are ignored, but kept in RAM. static uint8_t cdc_line_coding[7]={0x00, 0xE1, 0x00, 0x00, 0x00, 0x00, 0x08}; static uint8_t cdc_line_rtsdtr=0; /************************************************************************** * * Public Functions - these are the API intended for the user * **************************************************************************/ // initialize USB void usb_init(void) { HW_CONFIG(); USB_FREEZE(); // enable USB PLL_CONFIG(); // config PLL while (!(PLLCSR & (1< size) write_size = size; size -= write_size; // write the packet switch (write_size) { #if (CDC_TX_SIZE == 64) case 64: UEDATX = *buffer++; case 63: UEDATX = *buffer++; case 62: UEDATX = *buffer++; case 61: UEDATX = *buffer++; case 60: UEDATX = *buffer++; case 59: UEDATX = *buffer++; case 58: UEDATX = *buffer++; case 57: UEDATX = *buffer++; case 56: UEDATX = *buffer++; case 55: UEDATX = *buffer++; case 54: UEDATX = *buffer++; case 53: UEDATX = *buffer++; case 52: UEDATX = *buffer++; case 51: UEDATX = *buffer++; case 50: UEDATX = *buffer++; case 49: UEDATX = *buffer++; case 48: UEDATX = *buffer++; case 47: UEDATX = *buffer++; case 46: UEDATX = *buffer++; case 45: UEDATX = *buffer++; case 44: UEDATX = *buffer++; case 43: UEDATX = *buffer++; case 42: UEDATX = *buffer++; case 41: UEDATX = *buffer++; case 40: UEDATX = *buffer++; case 39: UEDATX = *buffer++; case 38: UEDATX = *buffer++; case 37: UEDATX = *buffer++; case 36: UEDATX = *buffer++; case 35: UEDATX = *buffer++; case 34: UEDATX = *buffer++; case 33: UEDATX = *buffer++; #endif #if (CDC_TX_SIZE >= 32) case 32: UEDATX = *buffer++; case 31: UEDATX = *buffer++; case 30: UEDATX = *buffer++; case 29: UEDATX = *buffer++; case 28: UEDATX = *buffer++; case 27: UEDATX = *buffer++; case 26: UEDATX = *buffer++; case 25: UEDATX = *buffer++; case 24: UEDATX = *buffer++; case 23: UEDATX = *buffer++; case 22: UEDATX = *buffer++; case 21: UEDATX = *buffer++; case 20: UEDATX = *buffer++; case 19: UEDATX = *buffer++; case 18: UEDATX = *buffer++; case 17: UEDATX = *buffer++; #endif #if (CDC_TX_SIZE >= 16) case 16: UEDATX = *buffer++; case 15: UEDATX = *buffer++; case 14: UEDATX = *buffer++; case 13: UEDATX = *buffer++; case 12: UEDATX = *buffer++; case 11: UEDATX = *buffer++; case 10: UEDATX = *buffer++; case 9: UEDATX = *buffer++; #endif case 8: UEDATX = *buffer++; case 7: UEDATX = *buffer++; case 6: UEDATX = *buffer++; case 5: UEDATX = *buffer++; case 4: UEDATX = *buffer++; case 3: UEDATX = *buffer++; case 2: UEDATX = *buffer++; default: case 1: UEDATX = *buffer++; case 0: break; } // if this completed a packet, transmit it now! if (!(UEINTX & (1<= NUM_DESC_LIST) { UECONX = (1< desc_length) len = desc_length; do { // wait for host ready for IN packet do { i = UEINTX; } while (!(i & ((1<= 1 && i <= MAX_ENDPOINT) { usb_send_in(); UENUM = i; if (bRequest == SET_FEATURE) { UECONX = (1<> 8); USBKeys_Idle_Count = 0; //usb_wait_in_ready(); usb_send_in(); return; } if (bRequest == HID_SET_PROTOCOL) { USBKeys_Protocol = wValue; //usb_wait_in_ready(); usb_send_in(); return; } } } } UECONX = (1<