diff --git a/Output/pjrcUSB/arm/usb_desc.c b/Output/pjrcUSB/arm/usb_desc.c index 0deaa82..7ac7547 100644 --- a/Output/pjrcUSB/arm/usb_desc.c +++ b/Output/pjrcUSB/arm/usb_desc.c @@ -29,56 +29,31 @@ * SOFTWARE. */ +// ----- Includes ----- + +// Local Includes #include "usb_desc.h" -// USB Descriptors are binary data which the USB host reads to -// automatically detect a USB device's capabilities. The format -// and meaning of every field is documented in numerous USB -// standards. When working with USB descriptors, despite the -// complexity of the standards and poor writing quality in many -// of those documents, remember descriptors are nothing more -// than constant binary data that tells the USB host what the -// device can do. Computers will load drivers based on this data. -// Those drivers then communicate on the endpoints specified by -// the descriptors. -// To configure a new combination of interfaces or make minor -// changes to existing configuration (eg, change the name or ID -// numbers), usually you would edit "usb_desc.h". This file -// is meant to be configured by the header, so generally it is -// only edited to add completely new USB interfaces or features. - - - -// ************************************************************** -// USB Device -// ************************************************************** +// ----- Macros ----- #define LSB(n) ((n) & 255) #define MSB(n) (((n) >> 8) & 255) + + +// ----- USB Device Descriptor ----- + // USB Device Descriptor. The USB host reads this first, to learn // what type of device is connected. static uint8_t device_descriptor[] = { 18, // bLength 1, // bDescriptorType 0x00, 0x02, // bcdUSB -#ifdef DEVICE_CLASS DEVICE_CLASS, // bDeviceClass -#else - 0, -#endif -#ifdef DEVICE_SUBCLASS DEVICE_SUBCLASS, // bDeviceSubClass -#else - 0, -#endif -#ifdef DEVICE_PROTOCOL DEVICE_PROTOCOL, // bDeviceProtocol -#else - 0, -#endif EP0_SIZE, // bMaxPacketSize0 LSB(VENDOR_ID), MSB(VENDOR_ID), // idVendor LSB(PRODUCT_ID), MSB(PRODUCT_ID), // idProduct @@ -89,69 +64,202 @@ static uint8_t device_descriptor[] = { 1 // bNumConfigurations }; +// USB Device Qualifier Descriptor +static uint8_t device_qualifier_descriptor[] = { + 0 // Indicate only single speed + /* Device qualifier example (used for specifying multiple USB speeds) + 10, // bLength + 6, // bDescriptorType + 0x00, 0x02, // bcdUSB + DEVICE_CLASS, // bDeviceClass + DEVICE_SUBCLASS, // bDeviceSubClass + DEVICE_PROTOCOL, // bDeviceProtocol + EP0_SIZE, // bMaxPacketSize0 + 1, // bNumOtherSpeedConfigurations + 0 // bReserved + */ +}; + +// USB Debug Descriptor +// XXX Not sure of exact use, lsusb requests it +static uint8_t usb_debug_descriptor[] = { + 0 +}; + +// XXX // These descriptors must NOT be "const", because the USB DMA // has trouble accessing flash memory with enough bandwidth // while the processor is executing from flash. +// XXX -// ************************************************************** -// HID Report Descriptors -// ************************************************************** +// ----- USB HID Report Descriptsors ----- // Each HID interface needs a special report descriptor that tells // the meaning and format of the data. -#ifdef KEYBOARD_INTERFACE // Keyboard Protocol 1, HID 1.11 spec, Appendix B, page 59-60 static uint8_t keyboard_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 -}; -#endif + // Keyboard Collection + 0x05, 0x01, // Usage Page (Generic Desktop), + 0x09, 0x06, // Usage (Keyboard), + 0xA1, 0x01, // Collection (Application) - Keyboard, -#ifdef MOUSE_INTERFACE + // Modifier Byte + 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), + + // Reserved Byte + 0x75, 0x08, // Report Size (8), + 0x95, 0x01, // Report Count (1), + 0x81, 0x03, // Output (Constant), + + // LED Report + 0x75, 0x01, // Report Size (1), + 0x95, 0x05, // Report Count (5), + 0x05, 0x08, // Usage Page (LEDs), + 0x19, 0x01, // Usage Minimum (1), + 0x29, 0x05, // Usage Maximum (5), + 0x91, 0x02, // Output (Data, Variable, Absolute), + + // LED Report Padding + 0x75, 0x03, // Report Size (3), + 0x95, 0x01, // Report Count (1), + 0x91, 0x03, // Output (Constant), + + // Normal Keys + 0x75, 0x08, // Report Size (8), + 0x95, 0x06, // Report Count (6), + 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), + 0xc0, // End Collection - Keyboard +}; + +// Keyboard Protocol 1, HID 1.11 spec, Appendix B, page 59-60 +static uint8_t nkro_keyboard_report_desc[] = { + // Keyboard Collection + 0x05, 0x01, // Usage Page (Generic Desktop), + 0x09, 0x06, // Usage (Keyboard), + 0xA1, 0x01, // Collection (Application) - Keyboard, + + // Modifier Byte + 0x85, 0x01, // Report ID (1), + 0x75, 0x01, // Report Size (1), + 0x95, 0x08, // Report Count (8), + 0x15, 0x00, // Logical Minimum (0), + 0x25, 0x01, // Logical Maximum (1), + 0x05, 0x07, // Usage Page (Key Codes), + 0x19, 0xE0, // Usage Minimum (224), + 0x29, 0xE7, // Usage Maximum (231), + 0x81, 0x02, // Input (Data, Variable, Absolute), + + // LED Report + 0x85, 0x02, // Report ID (2), + 0x75, 0x01, // Report Size (1), + 0x95, 0x05, // Report Count (5), + 0x05, 0x08, // Usage Page (LEDs), + 0x19, 0x01, // Usage Minimum (1), + 0x29, 0x05, // Usage Maximum (5), + 0x91, 0x02, // Output (Data, Variable, Absolute), + + // LED Report Padding + 0x75, 0x03, // Report Size (3), + 0x95, 0x01, // Report Count (1), + 0x91, 0x03, // Output (Constant), + + // Normal Keys - Using an NKRO Bitmap + // + // NOTES: + // Supports all keys defined by the spec, except 1-3 which define error events + // and 0 which is "no keys pressed" + // See http://www.usb.org/developers/hidpage/Hut1_12v2.pdf Chapter 10 + // Or Macros/PartialMap/usb_hid.h + // + // 165-175 are reserved/unused as well as 222-223 and 232-65535 + // 224-231 are used for modifiers (see above) + // + // Packing of bitmaps are as follows: + // 4-164 : 20 bytes + 1 Report ID byte (0x04-0xA4) + // 176-221 : 6 bytes + 1 Report ID byte (0xB0-0xDD) (45 bits + 3 padding bits for 6 bytes total) + // + // 4-164 (20 bytes/160 bits) + 0x85, 0x03, // Report ID (3), + 0x75, 0x01, // Report Size (1), + 0x95, 0xA0, // Report Count (160), + 0x15, 0x00, // Logical Minimum (0), + 0x25, 0x01, // Logical Maximum (1), + 0x05, 0x07, // Usage Page (Key Codes), + 0x19, 0x04, // Usage Minimum (4), + 0x29, 0xA4, // Usage Maximum (164), + 0x81, 0x02, // Input (Data, Variable, Absolute, Bitfield), + + // 176-221 (45 bits) + 0x85, 0x04, // Report ID (4), + 0x75, 0x01, // Report Size (1), + 0x95, 0x2D, // Report Count (45), + 0x15, 0x00, // Logical Minimum (0), + 0x25, 0x01, // Logical Maximum (1), + 0x05, 0x07, // Usage Page (Key Codes), + 0x19, 0xB0, // Usage Minimum (176), + 0x29, 0xDD, // Usage Maximum (221), + 0x81, 0x02, // Input (Data, Variable, Absolute, Bitfield), + + // 176-221 Padding (3 bits) + 0x75, 0x03, // Report Size (3), + 0x95, 0x01, // Report Count (1), + 0x81, 0x03, // Input (Constant), + 0xc0, // End Collection - Keyboard + + // System Control Collection + // + // NOTES: + // Not bothering with NKRO for this table. If there's need, I can implement it. -HaaTa + // Using a 1KRO scheme + 0x05, 0x01, // Usage Page (Generic Desktop), + 0x09, 0x80, // Usage (System Control), + 0xA1, 0x01, // Collection (Application), + 0x85, 0x05, // Report ID (5), + 0x75, 0x08, // Report Size (8), + 0x95, 0x01, // Report Count (1), + 0x16, 0x81, 0x00, // Logical Minimum (129), + 0x26, 0xB7, 0x00, // Logical Maximum (183), + 0x19, 0x81, // Usage Minimum (129), + 0x29, 0xB7, // Usage Maximum (183), + 0x81, 0x00, // Input (Data, Array), + 0xc0, // End Collection - System Control + + // Consumer Control Collection - Media Keys + // + // NOTES: + // Not bothering with NKRO for this table. If there's a need, I can implement it. -HaaTa + // Using a 1KRO scheme + 0x05, 0x0c, // Usage Page (Consumer), + 0x09, 0x01, // Usage (Consumer Control), + 0xA1, 0x01, // Collection (Application), + 0x85, 0x06, // Report ID (6), + 0x75, 0x10, // Report Size (16), + 0x95, 0x01, // Report Count (1), + 0x16, 0x20, 0x00, // Logical Minimum (32), + 0x26, 0x9C, 0x02, // Logical Maximum (668), + 0x05, 0x0C, // Usage Page (Consumer), + 0x19, 0x20, // Usage Minimum (32), + 0x2A, 0x9C, 0x02, // Usage Maximum (668), + 0x81, 0x00, // Input (Data, Array), + 0xc0, // End Collection - Consumer Control +}; + +/* MOUSE // Mouse Protocol 1, HID 1.11 spec, Appendix B, page 59-60, with wheel extension static uint8_t mouse_report_desc[] = { 0x05, 0x01, // Usage Page (Generic Desktop) @@ -184,29 +292,92 @@ static uint8_t mouse_report_desc[] = { 0x81, 0x06, // Input (Data, Variable, Relative) 0xC0 // End Collection }; -#endif +*/ -// ************************************************************** -// USB Configuration -// ************************************************************** +// ----- USB Configuration ----- // USB Configuration Descriptor. This huge descriptor tells all // of the devices capbilities. static uint8_t config_descriptor[CONFIG_DESC_SIZE] = { +// --- Configuration --- +// - 9 bytes - // configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10 9, // bLength; 2, // bDescriptorType; - LSB(CONFIG_DESC_SIZE), // wTotalLength + LSB(CONFIG_DESC_SIZE), // wTotalLength MSB(CONFIG_DESC_SIZE), NUM_INTERFACE, // bNumInterfaces 1, // bConfigurationValue 0, // iConfiguration 0xC0, // bmAttributes - 50, // bMaxPower + 250, // bMaxPower -#ifdef CDC_IAD_DESCRIPTOR +// --- Keyboard HID --- Boot Mode Keyboard Interface +// - 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 (0x00 = Non-Boot, 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_report_desc)), // wDescriptorLength + MSB(sizeof(keyboard_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 + +// --- NKRO Keyboard HID --- OS Mode Keyboard Interface +// - 9 bytes - + // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 + 9, // bLength + 4, // bDescriptorType + NKRO_KEYBOARD_INTERFACE, // bInterfaceNumber + 0, // bAlternateSetting + 1, // bNumEndpoints + 0x03, // bInterfaceClass (0x03 = HID) + 0x00, // bInterfaceSubClass (0x00 = Non-Boot, 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(nkro_keyboard_report_desc)), // wDescriptorLength + MSB(sizeof(nkro_keyboard_report_desc)), +// - 7 bytes - + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + 7, // bLength + 5, // bDescriptorType + NKRO_KEYBOARD_ENDPOINT | 0x80, // bEndpointAddress + 0x03, // bmAttributes (0x03=intr) + NKRO_KEYBOARD_SIZE, 0, // wMaxPacketSize + NKRO_KEYBOARD_INTERVAL, // bInterval + +// --- Serial CDC --- CDC IAD Descriptor +// - 8 bytes - // interface association descriptor, USB ECN, Table 9-Z 8, // bLength 11, // bDescriptorType @@ -216,9 +387,9 @@ static uint8_t config_descriptor[CONFIG_DESC_SIZE] = { 0x02, // bFunctionSubClass 0x01, // bFunctionProtocol 4, // iFunction -#endif -#ifdef CDC_DATA_INTERFACE +// --- Serial CDC --- CDC Data Interface +// - 9 bytes - // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 9, // bLength 4, // bDescriptorType @@ -229,28 +400,33 @@ static uint8_t config_descriptor[CONFIG_DESC_SIZE] = { 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 @@ -258,6 +434,7 @@ static uint8_t config_descriptor[CONFIG_DESC_SIZE] = { 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 @@ -268,6 +445,7 @@ static uint8_t config_descriptor[CONFIG_DESC_SIZE] = { 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 @@ -275,6 +453,7 @@ static uint8_t config_descriptor[CONFIG_DESC_SIZE] = { 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 @@ -282,38 +461,10 @@ static uint8_t config_descriptor[CONFIG_DESC_SIZE] = { 0x02, // bmAttributes (0x02=bulk) CDC_TX_SIZE, 0, // wMaxPacketSize 0, // bInterval -#endif // CDC_DATA_INTERFACE -#ifdef KEYBOARD_INTERFACE - // 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 - // 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_report_desc)), // wDescriptorLength - MSB(sizeof(keyboard_report_desc)), - // 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 -#endif // KEYBOARD_INTERFACE - -#ifdef MOUSE_INTERFACE +/* +// Mouse Interface +// - 9 bytes - // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 9, // bLength 4, // bDescriptorType @@ -324,6 +475,7 @@ static uint8_t config_descriptor[CONFIG_DESC_SIZE] = { 0x00, // bInterfaceSubClass (0x01 = Boot) 0x00, // bInterfaceProtocol (0x02 = Mouse) 0, // iInterface +// - 9 bytes - // HID interface descriptor, HID 1.11 spec, section 6.2.1 9, // bLength 0x21, // bDescriptorType @@ -333,6 +485,7 @@ static uint8_t config_descriptor[CONFIG_DESC_SIZE] = { 0x22, // bDescriptorType LSB(sizeof(mouse_report_desc)), // wDescriptorLength MSB(sizeof(mouse_report_desc)), +// - 7 bytes - // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 7, // bLength 5, // bDescriptorType @@ -341,13 +494,12 @@ static uint8_t config_descriptor[CONFIG_DESC_SIZE] = { MOUSE_SIZE, 0, // wMaxPacketSize MOUSE_INTERVAL, // bInterval #endif // MOUSE_INTERFACE +*/ }; -// ************************************************************** -// String Descriptors -// ************************************************************** +// ----- String Descriptors ----- // The descriptors above can provide human readable strings, // referenced by index numbers. These descriptors are the @@ -389,9 +541,8 @@ struct usb_string_descriptor_struct usb_string_serial_number_default = { }; -// ************************************************************** -// Descriptors List -// ************************************************************** + +// ----- Descriptors List ----- // This table provides access to all the descriptor data above. @@ -399,14 +550,16 @@ const usb_descriptor_list_t usb_descriptor_list[] = { //wValue, wIndex, address, length {0x0100, 0x0000, device_descriptor, sizeof(device_descriptor)}, {0x0200, 0x0000, config_descriptor, sizeof(config_descriptor)}, -#ifdef KEYBOARD_INTERFACE + {0x0600, 0x0000, device_qualifier_descriptor, sizeof(device_qualifier_descriptor)}, + {0x0A00, 0x0000, usb_debug_descriptor, sizeof(usb_debug_descriptor)}, {0x2200, KEYBOARD_INTERFACE, keyboard_report_desc, sizeof(keyboard_report_desc)}, - {0x2100, KEYBOARD_INTERFACE, config_descriptor+KEYBOARD_DESC_OFFSET, 9}, -#endif -#ifdef MOUSE_INTERFACE + {0x2100, KEYBOARD_INTERFACE, config_descriptor + KEYBOARD_DESC_OFFSET, 9}, + {0x2200, NKRO_KEYBOARD_INTERFACE, nkro_keyboard_report_desc, sizeof(nkro_keyboard_report_desc)}, + {0x2100, NKRO_KEYBOARD_INTERFACE, config_descriptor + NKRO_KEYBOARD_DESC_OFFSET, 9}, +/* MOUSE {0x2200, MOUSE_INTERFACE, mouse_report_desc, sizeof(mouse_report_desc)}, {0x2100, MOUSE_INTERFACE, config_descriptor+MOUSE_DESC_OFFSET, 9}, -#endif +*/ {0x0300, 0x0000, (const uint8_t *)&string0, 0}, {0x0301, 0x0409, (const uint8_t *)&usb_string_manufacturer_name, 0}, {0x0302, 0x0409, (const uint8_t *)&usb_string_product_name, 0}, @@ -415,24 +568,15 @@ const usb_descriptor_list_t usb_descriptor_list[] = { }; -// ************************************************************** -// Endpoint Configuration -// ************************************************************** -#if 0 +// ----- Endpoint Configuration ----- + +// See usb_desc.h for Endpoint configuration // 0x00 = not used // 0x19 = Recieve only // 0x15 = Transmit only // 0x1D = Transmit & Recieve // -const uint8_t usb_endpoint_config_table[NUM_ENDPOINTS] = -{ - 0x00, 0x15, 0x19, 0x15, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; -#endif - - const uint8_t usb_endpoint_config_table[NUM_ENDPOINTS] = { #if (defined(ENDPOINT1_CONFIG) && NUM_ENDPOINTS >= 1) diff --git a/Output/pjrcUSB/arm/usb_desc.h b/Output/pjrcUSB/arm/usb_desc.h index 06ce7ff..259bc30 100644 --- a/Output/pjrcUSB/arm/usb_desc.h +++ b/Output/pjrcUSB/arm/usb_desc.h @@ -32,105 +32,83 @@ #ifndef _usb_desc_h_ #define _usb_desc_h_ -// This header is NOT meant to be included when compiling -// user sketches in Arduino. The low-level functions -// provided by usb_dev.c are meant to be called only by -// code which provides higher-level interfaces to the user. +// ----- Includes ----- +// Compiler Includes #include #include -#include "output_com.h" + +// Local Includes +#include + + + +// ----- Defines ----- #define ENDPOINT_UNUSED 0x00 #define ENDPOINT_TRANSIMIT_ONLY 0x15 #define ENDPOINT_RECEIVE_ONLY 0x19 #define ENDPOINT_TRANSMIT_AND_RECEIVE 0x1D -/* -To modify a USB Type to have different interfaces, start in this -file. Delete the XYZ_INTERFACE lines for any interfaces you -wish to remove, and copy them from another USB Type for any you -want to add. -Give each interface a unique number, and edit NUM_INTERFACE to -reflect the number of interfaces. - -Within each interface, make sure it uses a unique set of endpoints. -Edit NUM_ENDPOINTS to be at least the largest endpoint number used. -Then edit the ENDPOINT*_CONFIG lines so each endpoint is configured -the proper way (transmit, receive, or both). - -The CONFIG_DESC_SIZE and any XYZ_DESC_OFFSET numbers must be -edited to the correct sizes. See usb_desc.c for the giant array -of bytes. Someday these may be done automatically..... (but how?) - -If you are using existing interfaces, the code in each file should -automatically adapt to the changes you specify. If you need to -create a new type of interface, you'll need to write the code which -sends and receives packets, and presents an API to the user. - -Finally, edit usb_inst.cpp, which creats instances of the C++ -objects for each combination. - -Some operating systems, especially Windows, may cache USB device -info. Changes to the device name may not update on the same -computer unless the vendor or product ID numbers change, or the -"bcdDevice" revision code is increased. - -If these instructions are missing steps or could be improved, please -let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports -*/ - - - -#define DEVICE_CLASS 0xEF -#define DEVICE_SUBCLASS 0x02 -#define DEVICE_PROTOCOL 0x01 +#define DEVICE_CLASS 0x03 // 0x03 = HID Class +#define DEVICE_SUBCLASS 0x00 +#define DEVICE_PROTOCOL 0x00 #define EP0_SIZE 64 -#define NUM_ENDPOINTS 6 +#define NUM_ENDPOINTS 5 #define NUM_USB_BUFFERS 30 #define NUM_INTERFACE 4 -#define CDC_IAD_DESCRIPTOR 1 -#define CDC_STATUS_INTERFACE 0 -#define CDC_DATA_INTERFACE 1 // Serial -#define CDC_ACM_ENDPOINT 2 -#define CDC_RX_ENDPOINT 3 -#define CDC_TX_ENDPOINT 4 -#define CDC_ACM_SIZE 16 -#define CDC_RX_SIZE 64 -#define CDC_TX_SIZE 64 - -#define KEYBOARD_INTERFACE 2 // Keyboard +#define KEYBOARD_INTERFACE 0 // Keyboard #define KEYBOARD_ENDPOINT 1 #define KEYBOARD_SIZE 8 #define KEYBOARD_INTERVAL 1 -#define MOUSE_INTERFACE 3 // Mouse -#define MOUSE_ENDPOINT 5 +#define NKRO_KEYBOARD_INTERFACE 1 // NKRO Keyboard +#define NKRO_KEYBOARD_ENDPOINT 2 +#define NKRO_KEYBOARD_SIZE 128 +#define NKRO_KEYBOARD_INTERVAL 1 + +#define CDC_IAD_DESCRIPTOR 1 +#define CDC_STATUS_INTERFACE 2 +#define CDC_DATA_INTERFACE 3 // Serial +#define CDC_ACM_ENDPOINT 3 +#define CDC_RX_ENDPOINT 4 +#define CDC_TX_ENDPOINT 5 +#define CDC_ACM_SIZE 16 +#define CDC_RX_SIZE 64 +#define CDC_TX_SIZE 64 + +#define MOUSE_INTERFACE 4 // Mouse +#define MOUSE_ENDPOINT 6 #define MOUSE_SIZE 8 #define MOUSE_INTERVAL 2 -#define JOYSTICK_INTERFACE 4 // Joystick -#define JOYSTICK_ENDPOINT 6 +#define JOYSTICK_INTERFACE 5 // Joystick +#define JOYSTICK_ENDPOINT 7 #define JOYSTICK_SIZE 16 #define JOYSTICK_INTERVAL 1 -#define KEYBOARD_DESC_OFFSET (9+8 + 9+5+5+4+5+7+9+7+7 + 9) -#define MOUSE_DESC_OFFSET (9+8 + 9+5+5+4+5+7+9+7+7 + 9+9+7 + 9) -#define JOYSTICK_DESC_OFFSET (9+8 + 9+5+5+4+5+7+9+7+7 + 9+9+7 + 9+9+7 + 9) -#define CONFIG_DESC_SIZE (9+8 + 9+5+5+4+5+7+9+7+7 + 9+9+7 + 9+9+7 + 9+9+7) +#define KEYBOARD_DESC_OFFSET (9 + 9) +#define NKRO_KEYBOARD_DESC_OFFSET (9 + 9+9+7 + 9) +#define SERIAL_CDC_DESC_OFFSET (9 + 9+9+7 + 9+9+7 + 8) +#define CONFIG_DESC_SIZE (9 + 9+9+7 + 9+9+7 + 8+9+5+5+4+5+7+9+7+7) + +// XXX Unused +#define MOUSE_DESC_OFFSET (9 + 9+9+7 + 9+9+7 + 8+9+5+5+4+5+7+9+7+7 + 9) +#define JOYSTICK_DESC_OFFSET (9 + 9+9+7 + 9+9+7 + 8+9+5+5+4+5+7+9+7+7 + 9+9+7 + 9) #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY #define ENDPOINT2_CONFIG ENDPOINT_TRANSIMIT_ONLY -#define ENDPOINT3_CONFIG ENDPOINT_RECEIVE_ONLY -#define ENDPOINT4_CONFIG ENDPOINT_TRANSIMIT_ONLY +#define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY +#define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY #define ENDPOINT5_CONFIG ENDPOINT_TRANSIMIT_ONLY #define ENDPOINT6_CONFIG ENDPOINT_TRANSIMIT_ONLY +#define ENDPOINT7_CONFIG ENDPOINT_TRANSIMIT_ONLY -// NUM_ENDPOINTS = number of non-zero endpoints (0 to 15) -extern const uint8_t usb_endpoint_config_table[NUM_ENDPOINTS]; + +// ----- Enumerations ----- typedef struct { uint16_t wValue; @@ -139,6 +117,13 @@ typedef struct { uint16_t length; } usb_descriptor_list_t; + + +// ----- Variables ----- + +// NUM_ENDPOINTS = number of non-zero endpoints (0 to 15) +extern const uint8_t usb_endpoint_config_table[NUM_ENDPOINTS]; + extern const usb_descriptor_list_t usb_descriptor_list[]; diff --git a/Output/pjrcUSB/arm/usb_dev.c b/Output/pjrcUSB/arm/usb_dev.c index 0ea7e9f..e41a4e3 100644 --- a/Output/pjrcUSB/arm/usb_dev.c +++ b/Output/pjrcUSB/arm/usb_dev.c @@ -1,7 +1,7 @@ /* Teensyduino Core Library * http://www.pjrc.com/teensy/ * Copyright (c) 2013 PJRC.COM, LLC. - * Modified by Jacob Alexander 2013-2014 + * Modifications by Jacob Alexander (2013-2014) * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -29,6 +29,8 @@ * SOFTWARE. */ +// ----- Includes ----- + // Project Includes #include #include @@ -37,23 +39,18 @@ #include "usb_dev.h" #include "usb_mem.h" -// buffer descriptor table -typedef struct { - uint32_t desc; - void * addr; -} bdt_t; -__attribute__ ((section(".usbdescriptortable"), used)) -static bdt_t table[(NUM_ENDPOINTS+1)*4]; +// ----- Defines ----- + +// DEBUG Mode +// XXX - Only use when using usbMuxUart Module +// Delay causes issues initializing more than 1 hid device (i.e. NKRO keyboard) +//#define UART_DEBUG 1 +// Debug Unknown USB requests, usually what you want to debug USB issues +//#define UART_DEBUG_UNKNOWN 1 -static usb_packet_t *rx_first[NUM_ENDPOINTS]; -static usb_packet_t *rx_last[NUM_ENDPOINTS]; -static usb_packet_t *tx_first[NUM_ENDPOINTS]; -static usb_packet_t *tx_last[NUM_ENDPOINTS]; -uint16_t usb_rx_byte_count_data[NUM_ENDPOINTS]; -static uint8_t tx_state[NUM_ENDPOINTS]; #define TX_STATE_BOTH_FREE_EVEN_FIRST 0 #define TX_STATE_BOTH_FREE_ODD_FIRST 1 #define TX_STATE_EVEN_FREE 2 @@ -66,40 +63,13 @@ static uint8_t tx_state[NUM_ENDPOINTS]; #define BDT_DATA0 0x00 #define BDT_DTS 0x08 #define BDT_STALL 0x04 -#define BDT_PID(n) (((n) >> 2) & 15) -#define BDT_DESC(count, data) (BDT_OWN | BDT_DTS \ - | ((data) ? BDT_DATA1 : BDT_DATA0) \ - | ((count) << 16)) - -#define TX 1 -#define RX 0 -#define ODD 1 -#define EVEN 0 +#define TX 1 +#define RX 0 +#define ODD 1 +#define EVEN 0 #define DATA0 0 #define DATA1 1 -#define index(endpoint, tx, odd) (((endpoint) << 2) | ((tx) << 1) | (odd)) -#define stat2bufferdescriptor(stat) (table + ((stat) >> 2)) - - -static union { - struct { - union { - struct { - uint8_t bmRequestType; - uint8_t bRequest; - }; - uint16_t wRequestAndType; - }; - uint16_t wValue; - uint16_t wIndex; - uint16_t wLength; - }; - struct { - uint32_t word1; - uint32_t word2; - }; -} setup; #define GET_STATUS 0 @@ -114,6 +84,72 @@ static union { #define SET_INTERFACE 11 #define SYNCH_FRAME 12 +#define TX_STATE_BOTH_FREE_EVEN_FIRST 0 +#define TX_STATE_BOTH_FREE_ODD_FIRST 1 +#define TX_STATE_EVEN_FREE 2 +#define TX_STATE_ODD_FREE 3 +#define TX_STATE_NONE_FREE 4 + + + + + +// ----- Macros ----- + +#define BDT_PID(n) (((n) >> 2) & 15) + +#define BDT_DESC(count, data) (BDT_OWN | BDT_DTS \ + | ((data) ? BDT_DATA1 : BDT_DATA0) \ + | ((count) << 16)) + +#define index(endpoint, tx, odd) (((endpoint) << 2) | ((tx) << 1) | (odd)) +#define stat2bufferdescriptor(stat) (table + ((stat) >> 2)) + + + +// ----- Structs ----- + +// buffer descriptor table + +typedef struct { + uint32_t desc; + void * addr; +} bdt_t; + +static union { + struct { + union { + struct { + uint8_t bmRequestType; + uint8_t bRequest; + }; + uint16_t wRequestAndType; + }; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; + }; + struct { + uint32_t word1; + uint32_t word2; + }; +} setup; + + + +// ----- Variables ----- + +__attribute__ ((section(".usbdescriptortable"), used)) +static bdt_t table[ (NUM_ENDPOINTS + 1) * 4 ]; + +static usb_packet_t *rx_first [ NUM_ENDPOINTS ]; +static usb_packet_t *rx_last [ NUM_ENDPOINTS ]; +static usb_packet_t *tx_first [ NUM_ENDPOINTS ]; +static usb_packet_t *tx_last [ NUM_ENDPOINTS ]; +uint16_t usb_rx_byte_count_data[ NUM_ENDPOINTS ]; + +static uint8_t tx_state[NUM_ENDPOINTS]; + // SETUP always uses a DATA0 PID for the data field of the SETUP transaction. // transactions in the data phase start with DATA1 and toggle (figure 8-12, USB1.1) // Status stage uses a DATA1 PID. @@ -129,36 +165,27 @@ uint8_t usb_rx_memory_needed = 0; volatile uint8_t usb_configuration = 0; volatile uint8_t usb_reboot_timer = 0; +static uint8_t reply_buffer[8]; + + + +// ----- Functions ----- static void endpoint0_stall() { - //print("STALL"); USB0_ENDPT0 = USB_ENDPT_EPSTALL | USB_ENDPT_EPRXEN | USB_ENDPT_EPTXEN | USB_ENDPT_EPHSHK; } - -static void endpoint0_transmit(const void *data, uint32_t len) +static void endpoint0_transmit( const void *data, uint32_t len ) { - //print("TRANSMIT"); -#if 0 - serial_print("tx0:"); - serial_phex32((uint32_t)data); - serial_print(","); - serial_phex16(len); - serial_print(ep0_tx_bdt_bank ? ", odd" : ", even"); - serial_print(ep0_tx_data_toggle ? ", d1\n" : ", d0\n"); -#endif table[index(0, TX, ep0_tx_bdt_bank)].addr = (void *)data; table[index(0, TX, ep0_tx_bdt_bank)].desc = BDT_DESC(len, ep0_tx_data_toggle); ep0_tx_data_toggle ^= 1; ep0_tx_bdt_bank ^= 1; } -static uint8_t reply_buffer[8]; - static void usb_setup() { - //print("SETUP"); const uint8_t *data = NULL; uint32_t datalen = 0; const usb_descriptor_list_t *list; @@ -168,25 +195,32 @@ static void usb_setup() const uint8_t *cfg; int i; - switch (setup.wRequestAndType) { - case 0x0500: // SET_ADDRESS + switch ( setup.wRequestAndType ) + { + case 0x0500: // SET_ADDRESS break; - case 0x0900: // SET_CONFIGURATION - //serial_print("configure\n"); + case 0x0900: // SET_CONFIGURATION + #ifdef UART_DEBUG + print("CONFIGURE - "); + #endif usb_configuration = setup.wValue; reg = &USB0_ENDPT1; cfg = usb_endpoint_config_table; // clear all BDT entries, free any allocated memory... - for (i=4; i < (NUM_ENDPOINTS+1)*4; i++) { - if (table[i].desc & BDT_OWN) { - usb_free((usb_packet_t *)((uint8_t *)(table[i].addr) - 8)); + for ( i = 4; i < ( NUM_ENDPOINTS + 1) * 4; i++ ) + { + if ( table[i].desc & BDT_OWN ) + { + usb_free( (usb_packet_t *)((uint8_t *)(table[ i ].addr) - 8) ); } } // free all queued packets - for (i=0; i < NUM_ENDPOINTS; i++) { + for ( i = 0; i < NUM_ENDPOINTS; i++ ) + { usb_packet_t *p, *n; p = rx_first[i]; - while (p) { + while ( p ) + { n = p->next; usb_free(p); p = n; @@ -194,7 +228,8 @@ static void usb_setup() rx_first[i] = NULL; rx_last[i] = NULL; p = tx_first[i]; - while (p) { + while (p) + { n = p->next; usb_free(p); p = n; @@ -202,39 +237,48 @@ static void usb_setup() tx_first[i] = NULL; tx_last[i] = NULL; usb_rx_byte_count_data[i] = 0; + switch (tx_state[i]) { - case TX_STATE_EVEN_FREE: - case TX_STATE_NONE_FREE_EVEN_FIRST: + case TX_STATE_EVEN_FREE: + case TX_STATE_NONE_FREE_EVEN_FIRST: tx_state[i] = TX_STATE_BOTH_FREE_EVEN_FIRST; break; - case TX_STATE_ODD_FREE: - case TX_STATE_NONE_FREE_ODD_FIRST: + case TX_STATE_ODD_FREE: + case TX_STATE_NONE_FREE_ODD_FIRST: tx_state[i] = TX_STATE_BOTH_FREE_ODD_FIRST; break; - default: + default: break; } } usb_rx_memory_needed = 0; - for (i=1; i <= NUM_ENDPOINTS; i++) { + for ( i = 1; i <= NUM_ENDPOINTS; i++ ) + { epconf = *cfg++; *reg = epconf; reg += 4; - if (epconf & USB_ENDPT_EPRXEN) { + if ( epconf & USB_ENDPT_EPRXEN ) + { usb_packet_t *p; p = usb_malloc(); - if (p) { + if ( p ) + { table[index(i, RX, EVEN)].addr = p->buf; table[index(i, RX, EVEN)].desc = BDT_DESC(64, 0); - } else { + } + else + { table[index(i, RX, EVEN)].desc = 0; usb_rx_memory_needed++; } p = usb_malloc(); - if (p) { + if ( p ) + { table[index(i, RX, ODD)].addr = p->buf; table[index(i, RX, ODD)].desc = BDT_DESC(64, 1); - } else { + } + else + { table[index(i, RX, ODD)].desc = 0; usb_rx_memory_needed++; } @@ -243,32 +287,35 @@ static void usb_setup() table[index(i, TX, ODD)].desc = 0; } break; - case 0x0880: // GET_CONFIGURATION + case 0x0880: // GET_CONFIGURATION reply_buffer[0] = usb_configuration; datalen = 1; data = reply_buffer; break; - case 0x0080: // GET_STATUS (device) + case 0x0080: // GET_STATUS (device) reply_buffer[0] = 0; reply_buffer[1] = 0; datalen = 2; data = reply_buffer; break; - case 0x0082: // GET_STATUS (endpoint) - if (setup.wIndex > NUM_ENDPOINTS) { + case 0x0082: // GET_STATUS (endpoint) + if (setup.wIndex > NUM_ENDPOINTS) + { // TODO: do we need to handle IN vs OUT here? endpoint0_stall(); return; } reply_buffer[0] = 0; reply_buffer[1] = 0; - if (*(uint8_t *)(&USB0_ENDPT0 + setup.wIndex * 4) & 0x02) reply_buffer[0] = 1; + if ( *(uint8_t *)(&USB0_ENDPT0 + setup.wIndex * 4) & 0x02 ) + reply_buffer[0] = 1; data = reply_buffer; datalen = 2; break; - case 0x0102: // CLEAR_FEATURE (endpoint) + case 0x0102: // CLEAR_FEATURE (endpoint) i = setup.wIndex & 0x7F; - if (i > NUM_ENDPOINTS || setup.wValue != 0) { + if ( i > NUM_ENDPOINTS || setup.wValue != 0 ) + { // TODO: do we need to handle IN vs OUT here? endpoint0_stall(); return; @@ -276,9 +323,10 @@ static void usb_setup() (*(uint8_t *)(&USB0_ENDPT0 + setup.wIndex * 4)) &= ~0x02; // TODO: do we need to clear the data toggle here? break; - case 0x0302: // SET_FEATURE (endpoint) + case 0x0302: // SET_FEATURE (endpoint) i = setup.wIndex & 0x7F; - if (i > NUM_ENDPOINTS || setup.wValue != 0) { + if ( i > NUM_ENDPOINTS || setup.wValue != 0 ) + { // TODO: do we need to handle IN vs OUT here? endpoint0_stall(); return; @@ -286,96 +334,167 @@ static void usb_setup() (*(uint8_t *)(&USB0_ENDPT0 + setup.wIndex * 4)) |= 0x02; // TODO: do we need to clear the data toggle here? break; - case 0x0680: // GET_DESCRIPTOR - case 0x0681: - //serial_print("desc:"); - //serial_phex16(setup.wValue); - //serial_print("\n"); - for (list = usb_descriptor_list; 1; list++) { - if (list->addr == NULL) break; - //if (setup.wValue == list->wValue && + case 0x0680: // GET_DESCRIPTOR + case 0x0681: + #ifdef UART_DEBUG + print("desc:"); + printHex(setup.wValue); + print(NL); + #endif + for ( list = usb_descriptor_list; 1; list++ ) + { + if ( list->addr == NULL ) + break; + //if (setup.wValue == list->wValue && //(setup.wIndex == list->wIndex) || ((setup.wValue >> 8) == 3)) { - if (setup.wValue == list->wValue && setup.wIndex == list->wIndex) { + if ( setup.wValue == list->wValue && setup.wIndex == list->wIndex ) + { data = list->addr; - if ((setup.wValue >> 8) == 3) { + if ( (setup.wValue >> 8) == 3 ) + { // for string descriptors, use the descriptor's // length field, allowing runtime configured // length. datalen = *(list->addr); - } else { + } + else + { datalen = list->length; } -#if 0 - serial_print("Desc found, "); - serial_phex32((uint32_t)data); - serial_print(","); - serial_phex16(datalen); - serial_print(","); - serial_phex(data[0]); - serial_phex(data[1]); - serial_phex(data[2]); - serial_phex(data[3]); - serial_phex(data[4]); - serial_phex(data[5]); - serial_print("\n"); -#endif + #if UART_DEBUG + print("Desc found, "); + printHex32((uint32_t)data); + print(","); + printHex(datalen); + print(","); + printHex_op(data[0], 2); + printHex_op(data[1], 2); + printHex_op(data[2], 2); + printHex_op(data[3], 2); + printHex_op(data[4], 2); + printHex_op(data[5], 2); + print(NL); + #endif goto send; } } - //serial_print("desc: not found\n"); + #ifdef UART_DEBUG + print("desc: not found"NL); + #endif endpoint0_stall(); return; -#if defined(CDC_STATUS_INTERFACE) - case 0x2221: // CDC_SET_CONTROL_LINE_STATE + + case 0x2221: // CDC_SET_CONTROL_LINE_STATE usb_cdc_line_rtsdtr = setup.wValue; //serial_print("set control line state\n"); - break; - case 0x2021: // CDC_SET_LINE_CODING - //serial_print("set coding, waiting...\n"); + endpoint0_stall(); return; -#endif -// TODO: this does not work... why? -#if defined(SEREMU_INTERFACE) || defined(KEYBOARD_INTERFACE) - case 0x0921: // HID SET_REPORT - //serial_print(":)\n"); + case 0x21A1: // CDC_GET_LINE_CODING + data = (uint8_t*)usb_cdc_line_coding; + datalen = sizeof( usb_cdc_line_coding ); + goto send; + + case 0x2021: // CDC_SET_LINE_CODING + // XXX Needed? + //serial_print("set coding, waiting...\n"); + return; // Cannot stall here (causes issues) + + case 0x0921: // HID SET_REPORT + #ifdef UART_DEBUG + print("SET_REPORT - "); + printHex( setup.wValue ); + print(" - "); + printHex( setup.wValue & 0xFF ); + print(NL); + #endif + USBKeys_LEDs = setup.wValue & 0xFF; + endpoint0_stall(); return; - case 0x0A21: // HID SET_IDLE - break; - // case 0xC940: -#endif - default: + + case 0x01A1: // HID GET_REPORT + #ifdef UART_DEBUG + print("GET_REPORT - "); + printHex( USBKeys_LEDs ); + print(NL); + #endif + data = (uint8_t*)&USBKeys_LEDs; + datalen = 1; + goto send; + + case 0x0A21: // HID SET_IDLE + #ifdef UART_DEBUG + print("SET_IDLE - "); + printHex( setup.wValue ); + print(NL); + #endif + USBKeys_Idle_Config = (setup.wValue >> 8); + USBKeys_Idle_Count = 0; + endpoint0_stall(); + return; + + case 0x0B21: // HID SET_PROTOCOL + #ifdef UART_DEBUG + print("SET_PROTOCOL - "); + printHex( setup.wValue ); + print(" - "); + printHex( setup.wValue & 0xFF ); + print(NL); + #endif + USBKeys_Protocol = setup.wValue & 0xFF; // 0 - Boot Mode, 1 - NKRO Mode + endpoint0_stall(); + return; + + // case 0xC940: + default: + #ifdef UART_DEBUG_UNKNOWN + print("UNKNOWN"); + #endif endpoint0_stall(); return; } - send: - //serial_print("setup send "); - //serial_phex32(data); - //serial_print(","); - //serial_phex16(datalen); - //serial_print("\n"); - if (datalen > setup.wLength) datalen = setup.wLength; +send: + #ifdef UART_DEBUG + print("setup send "); + printHex32((uint32_t)data); + print(","); + printHex(datalen); + print(NL); + #endif + + if ( datalen > setup.wLength ) + datalen = setup.wLength; + size = datalen; - if (size > EP0_SIZE) size = EP0_SIZE; + if ( size > EP0_SIZE ) + size = EP0_SIZE; + endpoint0_transmit(data, size); data += size; datalen -= size; - if (datalen == 0 && size < EP0_SIZE) return; + + // See if transmit has finished + if ( datalen == 0 && size < EP0_SIZE ) + return; size = datalen; - if (size > EP0_SIZE) size = EP0_SIZE; + if ( size > EP0_SIZE ) + size = EP0_SIZE; endpoint0_transmit(data, size); data += size; datalen -= size; - if (datalen == 0 && size < EP0_SIZE) return; + // See if transmit has finished + if ( datalen == 0 && size < EP0_SIZE ) + return; + + // Save rest of transfer for later? XXX ep0_tx_ptr = data; ep0_tx_len = datalen; } - //A bulk endpoint's toggle sequence is initialized to DATA0 when the endpoint //experiences any configuration event (configuration events are explained in //Sections 9.1.1.5 and 9.4.5). @@ -389,29 +508,29 @@ static void usb_setup() //Halt feature set, a ClearFeature(ENDPOINT_HALT) request always results in the //data toggle being reinitialized to DATA0. - - -// #define stat2bufferdescriptor(stat) (table + ((stat) >> 2)) - -static void usb_control(uint32_t stat) +static void usb_control( uint32_t stat ) { - //print("CONTROL"); + #ifdef UART_DEBUG + print("CONTROL - "); + #endif bdt_t *b; uint32_t pid, size; uint8_t *buf; const uint8_t *data; - b = stat2bufferdescriptor(stat); - pid = BDT_PID(b->desc); - //count = b->desc >> 16; + b = stat2bufferdescriptor( stat ); + pid = BDT_PID( b->desc ); buf = b->addr; - //serial_print("pid:"); - //serial_phex(pid); - //serial_print(", count:"); - //serial_phex(count); - //serial_print("\n"); + #ifdef UART_DEBUG + print("pid:"); + printHex(pid); + print(", count:"); + printHex32(b->desc); + print(" - "); + #endif - switch (pid) { + switch (pid) + { case 0x0D: // Setup received from host //serial_print("PID=Setup\n"); //if (count != 8) ; // panic? @@ -420,13 +539,14 @@ static void usb_control(uint32_t stat) setup.word2 = *(uint32_t *)(buf + 4); // give the buffer back - b->desc = BDT_DESC(EP0_SIZE, DATA1); + b->desc = BDT_DESC( EP0_SIZE, DATA1 ); //table[index(0, RX, EVEN)].desc = BDT_DESC(EP0_SIZE, 1); //table[index(0, RX, ODD)].desc = BDT_DESC(EP0_SIZE, 1); // clear any leftover pending IN transactions ep0_tx_ptr = NULL; - if (ep0_tx_data_toggle) { + if ( ep0_tx_data_toggle ) + { } //if (table[index(0, TX, EVEN)].desc & 0x80) { //serial_print("leftover tx even\n"); @@ -439,19 +559,19 @@ static void usb_control(uint32_t stat) // first IN after Setup is always DATA1 ep0_tx_data_toggle = 1; -#if 0 - serial_print("bmRequestType:"); - serial_phex(setup.bmRequestType); - serial_print(", bRequest:"); - serial_phex(setup.bRequest); - serial_print(", wValue:"); - serial_phex16(setup.wValue); - serial_print(", wIndex:"); - serial_phex16(setup.wIndex); - serial_print(", len:"); - serial_phex16(setup.wLength); - serial_print("\n"); -#endif + #ifdef UART_DEBUG_UNKNOWN + print("bmRequestType:"); + printHex(setup.bmRequestType); + print(", bRequest:"); + printHex(setup.bRequest); + print(", wValue:"); + printHex(setup.wValue); + print(", wIndex:"); + printHex(setup.wIndex); + print(", len:"); + printHex(setup.wLength); + print(NL); + #endif // actually "do" the setup request usb_setup(); // unfreeze the USB, now that we're ready @@ -459,40 +579,55 @@ static void usb_control(uint32_t stat) break; case 0x01: // OUT transaction received from host case 0x02: - //serial_print("PID=OUT\n"); -#ifdef CDC_STATUS_INTERFACE - if (setup.wRequestAndType == 0x2021 /*CDC_SET_LINE_CODING*/) { + #ifdef UART_DEBUG + print("PID=OUT"NL); + #endif + // CDC Interface + if ( setup.wRequestAndType == 0x2021 /*CDC_SET_LINE_CODING*/ ) + { int i; uint8_t *dst = (uint8_t *)usb_cdc_line_coding; //serial_print("set line coding "); - for (i=0; i<7; i++) { + for ( i = 0; i < 7; i++ ) + { //serial_phex(*buf); *dst++ = *buf++; } //serial_phex32(usb_cdc_line_coding[0]); //serial_print("\n"); - if (usb_cdc_line_coding[0] == 134) usb_reboot_timer = 15; - endpoint0_transmit(NULL, 0); + if ( usb_cdc_line_coding[0] == 134 ) + usb_reboot_timer = 15; + endpoint0_transmit( NULL, 0 ); } -#endif -#ifdef KEYBOARD_INTERFACE - if (setup.word1 == 0x02000921 && setup.word2 == ((1<<16)|KEYBOARD_INTERFACE)) { + + // Keyboard Interface + if ( setup.word1 == 0x02000921 && setup.word2 == ( (1<<16) | KEYBOARD_INTERFACE ) ) + { USBKeys_LEDs = buf[0]; - endpoint0_transmit(NULL, 0); + endpoint0_transmit( NULL, 0 ); } -#endif + // NKRO Keyboard Interface + if ( setup.word1 == 0x02000921 && setup.word2 == ( (1<<16) | NKRO_KEYBOARD_INTERFACE ) ) + { + USBKeys_LEDs = buf[0]; + endpoint0_transmit( NULL, 0 ); + } + // give the buffer back - b->desc = BDT_DESC(EP0_SIZE, DATA1); + b->desc = BDT_DESC( EP0_SIZE, DATA1 ); break; case 0x09: // IN transaction completed to host - //serial_print("PID=IN:"); - //serial_phex(stat); - //serial_print("\n"); + #ifdef UART_DEBUG + print("PID=IN:"); + printHex(stat); + print(NL); + #endif // send remaining data, if any... data = ep0_tx_ptr; - if (data) { + if ( data ) + { size = ep0_tx_len; if (size > EP0_SIZE) size = EP0_SIZE; endpoint0_transmit(data, size); @@ -501,49 +636,41 @@ static void usb_control(uint32_t stat) ep0_tx_ptr = (ep0_tx_len > 0 || size == EP0_SIZE) ? data : NULL; } - if (setup.bRequest == 5 && setup.bmRequestType == 0) { + if ( setup.bRequest == 5 && setup.bmRequestType == 0 ) + { setup.bRequest = 0; - //serial_print("set address: "); - //serial_phex16(setup.wValue); - //serial_print("\n"); + #ifdef UART_DEBUG + print("set address: "); + printHex(setup.wValue); + print(NL); + #endif USB0_ADDR = setup.wValue; } break; - //default: - //serial_print("PID=unknown:"); - //serial_phex(pid); - //serial_print("\n"); + default: + #ifdef UART_DEBUG + print("PID=unknown:"); + printHex(pid); + print(NL); + #endif + break; } USB0_CTL = USB_CTL_USBENSOFEN; // clear TXSUSPENDTOKENBUSY bit } - - -static usb_packet_t *rx_first[NUM_ENDPOINTS]; -static usb_packet_t *rx_last[NUM_ENDPOINTS]; -static usb_packet_t *tx_first[NUM_ENDPOINTS]; -static usb_packet_t *tx_last[NUM_ENDPOINTS]; - -static uint8_t tx_state[NUM_ENDPOINTS]; -#define TX_STATE_BOTH_FREE_EVEN_FIRST 0 -#define TX_STATE_BOTH_FREE_ODD_FIRST 1 -#define TX_STATE_EVEN_FREE 2 -#define TX_STATE_ODD_FREE 3 -#define TX_STATE_NONE_FREE 4 - - - -usb_packet_t *usb_rx(uint32_t endpoint) +usb_packet_t *usb_rx( uint32_t endpoint ) { //print("USB RX"); usb_packet_t *ret; endpoint--; - if (endpoint >= NUM_ENDPOINTS) return NULL; + if ( endpoint >= NUM_ENDPOINTS ) + return NULL; __disable_irq(); ret = rx_first[endpoint]; - if (ret) rx_first[endpoint] = ret->next; - usb_rx_byte_count_data[endpoint] -= ret->len; + if ( ret ) + rx_first[ endpoint ] = ret->next; + usb_rx_byte_count_data[ endpoint ] -= ret->len; __enable_irq(); //serial_print("rx, epidx="); //serial_phex(endpoint); @@ -553,34 +680,38 @@ usb_packet_t *usb_rx(uint32_t endpoint) return ret; } -static uint32_t usb_queue_byte_count(const usb_packet_t *p) +static uint32_t usb_queue_byte_count( const usb_packet_t *p ) { uint32_t count=0; __disable_irq(); - for ( ; p; p = p->next) { + for ( ; p; p = p->next ) + { count += p->len; } __enable_irq(); return count; } -uint32_t usb_tx_byte_count(uint32_t endpoint) +uint32_t usb_tx_byte_count( uint32_t endpoint ) { endpoint--; - if (endpoint >= NUM_ENDPOINTS) return 0; - return usb_queue_byte_count(tx_first[endpoint]); + if ( endpoint >= NUM_ENDPOINTS ) + return 0; + return usb_queue_byte_count( tx_first[ endpoint ] ); } -uint32_t usb_tx_packet_count(uint32_t endpoint) +uint32_t usb_tx_packet_count( uint32_t endpoint ) { const usb_packet_t *p; uint32_t count=0; endpoint--; - if (endpoint >= NUM_ENDPOINTS) return 0; + if ( endpoint >= NUM_ENDPOINTS ) + return 0; __disable_irq(); - for (p = tx_first[endpoint]; p; p = p->next) count++; + for ( p = tx_first[ endpoint ]; p; p = p->next ) + count++; __enable_irq(); return count; } @@ -594,7 +725,7 @@ uint32_t usb_tx_packet_count(uint32_t endpoint) // without this prioritization. The packet buffer (input) is assigned to the // first endpoint needing memory. // -void usb_rx_memory(usb_packet_t *packet) +void usb_rx_memory( usb_packet_t *packet ) { //print("USB RX MEMORY"); unsigned int i; @@ -605,18 +736,20 @@ void usb_rx_memory(usb_packet_t *packet) __disable_irq(); for (i=1; i <= NUM_ENDPOINTS; i++) { if (*cfg++ & USB_ENDPT_EPRXEN) { - if (table[index(i, RX, EVEN)].desc == 0) { + if ( table[ index( i, RX, EVEN ) ].desc == 0 ) + { table[index(i, RX, EVEN)].addr = packet->buf; - table[index(i, RX, EVEN)].desc = BDT_DESC(64, 0); + table[index(i, RX, EVEN)].desc = BDT_DESC( 64, 0 ); usb_rx_memory_needed--; __enable_irq(); //serial_phex(i); //serial_print(",even\n"); return; } - if (table[index(i, RX, ODD)].desc == 0) { - table[index(i, RX, ODD)].addr = packet->buf; - table[index(i, RX, ODD)].desc = BDT_DESC(64, 1); + if ( table[ index( i, RX, ODD ) ].desc == 0 ) + { + table[ index( i, RX, ODD ) ].addr = packet->buf; + table[ index( i, RX, ODD ) ].desc = BDT_DESC( 64, 1 ); usb_rx_memory_needed--; __enable_irq(); //serial_phex(i); @@ -630,52 +763,58 @@ void usb_rx_memory(usb_packet_t *packet) // usb_rx_memory_needed was set greater than zero, but no memory // was actually needed. usb_rx_memory_needed = 0; - usb_free(packet); + usb_free( packet ); return; } //#define index(endpoint, tx, odd) (((endpoint) << 2) | ((tx) << 1) | (odd)) //#define stat2bufferdescriptor(stat) (table + ((stat) >> 2)) -void usb_tx(uint32_t endpoint, usb_packet_t *packet) +void usb_tx( uint32_t endpoint, usb_packet_t *packet ) { - bdt_t *b = &table[index(endpoint, TX, EVEN)]; + bdt_t *b = &table[ index( endpoint, TX, EVEN ) ]; uint8_t next; endpoint--; - if (endpoint >= NUM_ENDPOINTS) return; + if ( endpoint >= NUM_ENDPOINTS ) + return; __disable_irq(); //serial_print("txstate="); - //serial_phex(tx_state[endpoint]); + //serial_phex(tx_state[ endpoint ]); //serial_print("\n"); - switch (tx_state[endpoint]) { - case TX_STATE_BOTH_FREE_EVEN_FIRST: + switch ( tx_state[ endpoint ] ) + { + case TX_STATE_BOTH_FREE_EVEN_FIRST: next = TX_STATE_ODD_FREE; break; - case TX_STATE_BOTH_FREE_ODD_FIRST: + case TX_STATE_BOTH_FREE_ODD_FIRST: b++; next = TX_STATE_EVEN_FREE; break; - case TX_STATE_EVEN_FREE: + case TX_STATE_EVEN_FREE: next = TX_STATE_NONE_FREE_ODD_FIRST; break; - case TX_STATE_ODD_FREE: + case TX_STATE_ODD_FREE: b++; next = TX_STATE_NONE_FREE_EVEN_FIRST; break; - default: - if (tx_first[endpoint] == NULL) { - tx_first[endpoint] = packet; - } else { - tx_last[endpoint]->next = packet; + default: + if (tx_first[ endpoint ] == NULL) + { + tx_first[ endpoint ] = packet; } - tx_last[endpoint] = packet; + else + { + tx_last[ endpoint ]->next = packet; + } + tx_last[ endpoint ] = packet; __enable_irq(); return; } - tx_state[endpoint] = next; + + tx_state[ endpoint ] = next; b->addr = packet->buf; - b->desc = BDT_DESC(packet->len, ((uint32_t)b & 8) ? DATA1 : DATA0); + b->desc = BDT_DESC( packet->len, ((uint32_t)b & 8) ? DATA1 : DATA0 ); __enable_irq(); } @@ -701,7 +840,8 @@ void usb_device_reload() else { // Copies variable into the VBAT register, must be identical to the variable in the bootloader to jump to the bootloader flash mode - for ( int pos = 0; pos < sizeof(sys_reset_to_loader_magic); pos++ )(&VBAT)[pos] = sys_reset_to_loader_magic[ pos ]; + for ( int pos = 0; pos < sizeof(sys_reset_to_loader_magic); pos++ ) + (&VBAT)[ pos ] = sys_reset_to_loader_magic[ pos ]; SOFTWARE_RESET(); } @@ -728,25 +868,33 @@ void usb_isr() print( NL ); */ - if ((status & USB_INTEN_SOFTOKEN /* 04 */ )) { - if (usb_configuration) { + if ( (status & USB_INTEN_SOFTOKEN /* 04 */ ) ) + { + if ( usb_configuration ) + { t = usb_reboot_timer; - if (t) { + if ( t ) + { usb_reboot_timer = --t; - if (!t) usb_device_reload(); + if ( !t ) + usb_device_reload(); } -#ifdef CDC_DATA_INTERFACE + + // CDC Interface t = usb_cdc_transmit_flush_timer; - if (t) { + if ( t ) + { usb_cdc_transmit_flush_timer = --t; - if (t == 0) usb_serial_flush_callback(); + if ( t == 0 ) + usb_serial_flush_callback(); } -#endif + } USB0_ISTAT = USB_INTEN_SOFTOKEN; } - if ((status & USB_ISTAT_TOKDNE /* 08 */ )) { + if ( (status & USB_ISTAT_TOKDNE /* 08 */ ) ) + { uint8_t endpoint; stat = USB0_STAT; //serial_print("token: ep="); @@ -754,9 +902,12 @@ void usb_isr() //serial_print(stat & 0x08 ? ",tx" : ",rx"); //serial_print(stat & 0x04 ? ",odd\n" : ",even\n"); endpoint = stat >> 4; - if (endpoint == 0) { - usb_control(stat); - } else { + if ( endpoint == 0 ) + { + usb_control( stat ); + } + else + { bdt_t *b = stat2bufferdescriptor(stat); usb_packet_t *packet = (usb_packet_t *)((uint8_t *)(b->addr) - 8); #if 0 @@ -771,61 +922,71 @@ void usb_isr() #endif endpoint--; // endpoint is index to zero-based arrays - if (stat & 0x08) { // transmit - usb_free(packet); + if ( stat & 0x08 ) + { // transmit + usb_free( packet ); packet = tx_first[endpoint]; - if (packet) { + if ( packet ) + { //serial_print("tx packet\n"); tx_first[endpoint] = packet->next; b->addr = packet->buf; - switch (tx_state[endpoint]) { - case TX_STATE_BOTH_FREE_EVEN_FIRST: + switch ( tx_state[ endpoint ] ) + { + case TX_STATE_BOTH_FREE_EVEN_FIRST: tx_state[endpoint] = TX_STATE_ODD_FREE; break; - case TX_STATE_BOTH_FREE_ODD_FIRST: + case TX_STATE_BOTH_FREE_ODD_FIRST: tx_state[endpoint] = TX_STATE_EVEN_FREE; break; - case TX_STATE_EVEN_FREE: + case TX_STATE_EVEN_FREE: tx_state[endpoint] = TX_STATE_NONE_FREE_ODD_FIRST; break; - case TX_STATE_ODD_FREE: + case TX_STATE_ODD_FREE: tx_state[endpoint] = TX_STATE_NONE_FREE_EVEN_FIRST; break; - default: + default: break; } b->desc = BDT_DESC(packet->len, ((uint32_t)b & 8) ? DATA1 : DATA0); } else { //serial_print("tx no packet\n"); - switch (tx_state[endpoint]) { - case TX_STATE_BOTH_FREE_EVEN_FIRST: - case TX_STATE_BOTH_FREE_ODD_FIRST: + switch ( tx_state[ endpoint ] ) + { + case TX_STATE_BOTH_FREE_EVEN_FIRST: + case TX_STATE_BOTH_FREE_ODD_FIRST: break; - case TX_STATE_EVEN_FREE: + case TX_STATE_EVEN_FREE: tx_state[endpoint] = TX_STATE_BOTH_FREE_EVEN_FIRST; break; - case TX_STATE_ODD_FREE: + case TX_STATE_ODD_FREE: tx_state[endpoint] = TX_STATE_BOTH_FREE_ODD_FIRST; break; - default: - tx_state[endpoint] = ((uint32_t)b & 8) ? - TX_STATE_ODD_FREE : TX_STATE_EVEN_FREE; + default: + tx_state[endpoint] = ((uint32_t)b & 8) + ? TX_STATE_ODD_FREE + : TX_STATE_EVEN_FREE; break; } } - } else { // receive + } + else + { // receive packet->len = b->desc >> 16; if (packet->len > 0) { packet->index = 0; packet->next = NULL; - if (rx_first[endpoint] == NULL) { + if (rx_first[endpoint] == NULL) + { //serial_print("rx 1st, epidx="); //serial_phex(endpoint); //serial_print(", packet="); //serial_phex32((uint32_t)packet); //serial_print("\n"); rx_first[endpoint] = packet; - } else { + } + else + { //serial_print("rx Nth, epidx="); //serial_phex(endpoint); //serial_print(", packet="); @@ -839,17 +1000,22 @@ void usb_isr() // so a flood of incoming data on 1 endpoint doesn't starve // the others if the user isn't reading it regularly packet = usb_malloc(); - if (packet) { + if ( packet ) + { b->addr = packet->buf; b->desc = BDT_DESC(64, ((uint32_t)b & 8) ? DATA1 : DATA0); - } else { + } + else + { //serial_print("starving "); //serial_phex(endpoint + 1); //serial_print(((uint32_t)b & 8) ? ",odd\n" : ",even\n"); b->desc = 0; usb_rx_memory_needed++; } - } else { + } + else + { b->desc = BDT_DESC(64, ((uint32_t)b & 8) ? DATA1 : DATA0); } } @@ -863,8 +1029,8 @@ void usb_isr() } - - if (status & USB_ISTAT_USBRST /* 01 */ ) { + if ( status & USB_ISTAT_USBRST /* 01 */ ) + { //serial_print("reset\n"); // initialize BDT toggle bits @@ -904,12 +1070,14 @@ void usb_isr() } - if ((status & USB_ISTAT_STALL /* 80 */ )) { + if ( (status & USB_ISTAT_STALL /* 80 */ ) ) + { //serial_print("stall:\n"); USB0_ENDPT0 = USB_ENDPT_EPRXEN | USB_ENDPT_EPTXEN | USB_ENDPT_EPHSHK; USB0_ISTAT = USB_ISTAT_STALL; } - if ((status & USB_ISTAT_ERROR /* 02 */ )) { + if ( (status & USB_ISTAT_ERROR /* 02 */ ) ) + { uint8_t err = USB0_ERRSTAT; USB0_ERRSTAT = err; //serial_print("err:"); @@ -918,7 +1086,8 @@ void usb_isr() USB0_ISTAT = USB_ISTAT_ERROR; } - if ((status & USB_ISTAT_SLEEP /* 10 */ )) { + if ( (status & USB_ISTAT_SLEEP /* 10 */ ) ) + { //serial_print("sleep\n"); USB0_ISTAT = USB_ISTAT_SLEEP; } @@ -929,7 +1098,9 @@ void usb_isr() void usb_init() { - //print("USB INIT"); + #ifdef UART_DEBUG + print("USB INIT"NL); + #endif // Clear out endpoints table for ( int i = 0; i <= NUM_ENDPOINTS * 4; i++ ) diff --git a/Output/pjrcUSB/arm/usb_dev.h b/Output/pjrcUSB/arm/usb_dev.h index 4e8af8b..01f98cb 100644 --- a/Output/pjrcUSB/arm/usb_dev.h +++ b/Output/pjrcUSB/arm/usb_dev.h @@ -11,10 +11,10 @@ * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * - * 1. The above copyright notice and this permission notice shall be + * 1. The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * - * 2. If the Software is incorporated into a build system that allows + * 2. If the Software is incorporated into a build system that allows * selection among a list of target devices, then similar target * devices manufactured by PJRC.COM must be included in the list of * target devices and selectable in the same manner. @@ -32,16 +32,34 @@ #ifndef _usb_dev_h_ #define _usb_dev_h_ -// This header is NOT meant to be included when compiling -// user sketches in Arduino. The low-level functions -// provided by usb_dev.c are meant to be called only by -// code which provides higher-level interfaces to the user. +// ----- Includes ----- +// Local Includes #include "usb_mem.h" #include "usb_desc.h" + + +// ----- Defines ----- + #define usb_device_software_reset() SOFTWARE_RESET() + + +// ----- Variables ----- + +extern volatile uint8_t usb_configuration; + +extern uint16_t usb_rx_byte_count_data[NUM_ENDPOINTS]; + +extern volatile uint8_t usb_cdc_line_coding[7]; +extern volatile uint8_t usb_cdc_line_rtsdtr; +extern volatile uint8_t usb_cdc_transmit_flush_timer; + + + +// ----- Functions ----- + uint8_t usb_configured(); // is the USB port configured void usb_init(); @@ -54,35 +72,19 @@ uint32_t usb_tx_packet_count( uint32_t endpoint ); usb_packet_t *usb_rx( uint32_t endpoint ); -void usb_device_reload(); - -extern volatile uint8_t usb_configuration; - -extern uint16_t usb_rx_byte_count_data[NUM_ENDPOINTS]; static inline uint32_t usb_rx_byte_count(uint32_t endpoint) __attribute__((always_inline)); static inline uint32_t usb_rx_byte_count(uint32_t endpoint) { endpoint--; - if (endpoint >= NUM_ENDPOINTS) return 0; - return usb_rx_byte_count_data[endpoint]; + if ( endpoint >= NUM_ENDPOINTS ) + return 0; + return usb_rx_byte_count_data[ endpoint ]; } -#ifdef CDC_DATA_INTERFACE -extern uint32_t usb_cdc_line_coding[2]; -extern volatile uint8_t usb_cdc_line_rtsdtr; -extern volatile uint8_t usb_cdc_transmit_flush_timer; -extern void usb_serial_flush_callback(void); -#endif +void usb_device_reload(); +extern void usb_serial_flush_callback(); -#ifdef KEYBOARD_INTERFACE -extern uint8_t keyboard_modifier_keys; -extern uint8_t keyboard_keys[6]; -extern uint8_t keyboard_protocol; -extern uint8_t keyboard_idle_config; -extern uint8_t keyboard_idle_count; -extern volatile uint8_t keyboard_leds; -#endif #endif diff --git a/Output/pjrcUSB/arm/usb_mem.c b/Output/pjrcUSB/arm/usb_mem.c index 8a909cf..a26b184 100644 --- a/Output/pjrcUSB/arm/usb_mem.c +++ b/Output/pjrcUSB/arm/usb_mem.c @@ -1,6 +1,7 @@ /* Teensyduino Core Library * http://www.pjrc.com/teensy/ * Copyright (c) 2013 PJRC.COM, LLC. + * Modifications by Jacob Alexander (2013-2014) * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -10,10 +11,10 @@ * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * - * 1. The above copyright notice and this permission notice shall be + * 1. The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * - * 2. If the Software is incorporated into a build system that allows + * 2. If the Software is incorporated into a build system that allows * selection among a list of target devices, then similar target * devices manufactured by PJRC.COM must be included in the list of * target devices and selectable in the same manner. @@ -28,68 +29,78 @@ * SOFTWARE. */ +// ----- Includes ----- + +// Project Includes #include + +// Local Includes #include "usb_dev.h" #include "usb_mem.h" + + +// ----- Variables ----- + __attribute__ ((section(".usbbuffers"), used)) -unsigned char usb_buffer_memory[NUM_USB_BUFFERS * sizeof(usb_packet_t)]; +unsigned char usb_buffer_memory[ NUM_USB_BUFFERS * sizeof(usb_packet_t) ]; static uint32_t usb_buffer_available = 0xFFFFFFFF; + + +// ----- Externs ----- + +extern void usb_rx_memory( usb_packet_t *packet ); + +// for the receive endpoints to request memory +extern uint8_t usb_rx_memory_needed; + + + +// ----- Functions ----- + // use bitmask and CLZ instruction to implement fast free list // http://www.archivum.info/gnu.gcc.help/2006-08/00148/Re-GCC-Inline-Assembly.html // http://gcc.gnu.org/ml/gcc/2012-06/msg00015.html // __builtin_clz() -usb_packet_t * usb_malloc(void) +usb_packet_t *usb_malloc() { unsigned int n, avail; uint8_t *p; __disable_irq(); avail = usb_buffer_available; - n = __builtin_clz(avail); // clz = count leading zeros - if (n >= NUM_USB_BUFFERS) { + n = __builtin_clz( avail ); // clz = count leading zeros + if ( n >= NUM_USB_BUFFERS ) + { __enable_irq(); return NULL; } - //serial_print("malloc:"); - //serial_phex(n); - //serial_print("\n"); usb_buffer_available = avail & ~(0x80000000 >> n); __enable_irq(); - p = usb_buffer_memory + (n * sizeof(usb_packet_t)); - //serial_print("malloc:"); - //serial_phex32((int)p); - //serial_print("\n"); + p = usb_buffer_memory + ( n * sizeof(usb_packet_t) ); *(uint32_t *)p = 0; *(uint32_t *)(p + 4) = 0; return (usb_packet_t *)p; } -// for the receive endpoints to request memory -extern uint8_t usb_rx_memory_needed; -extern void usb_rx_memory(usb_packet_t *packet); -void usb_free(usb_packet_t *p) +void usb_free( usb_packet_t *p ) { unsigned int n, mask; - //serial_print("free:"); - n = ((uint8_t *)p - usb_buffer_memory) / sizeof(usb_packet_t); - if (n >= NUM_USB_BUFFERS) return; - //serial_phex(n); - //serial_print("\n"); + n = ( (uint8_t *)p - usb_buffer_memory ) / sizeof(usb_packet_t); + if ( n >= NUM_USB_BUFFERS ) + return; // if any endpoints are starving for memory to receive // packets, give this memory to them immediately! - if (usb_rx_memory_needed && usb_configuration) { - //serial_print("give to rx:"); - //serial_phex32((int)p); - //serial_print("\n"); - usb_rx_memory(p); + if ( usb_rx_memory_needed && usb_configuration ) + { + usb_rx_memory( p ); return; } @@ -97,9 +108,5 @@ void usb_free(usb_packet_t *p) __disable_irq(); usb_buffer_available |= mask; __enable_irq(); - - //serial_print("free:"); - //serial_phex32((int)p); - //serial_print("\n"); } diff --git a/Output/pjrcUSB/arm/usb_mem.h b/Output/pjrcUSB/arm/usb_mem.h index 6cec9ac..9beb63e 100644 --- a/Output/pjrcUSB/arm/usb_mem.h +++ b/Output/pjrcUSB/arm/usb_mem.h @@ -1,6 +1,7 @@ /* Teensyduino Core Library * http://www.pjrc.com/teensy/ * Copyright (c) 2013 PJRC.COM, LLC. + * Modifications by Jacob Alexander (2013-2014) * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -31,8 +32,15 @@ #ifndef _usb_mem_h_ #define _usb_mem_h_ +// ----- Includes ----- + +// Compiler Includes #include + + +// ----- Structs ----- + typedef struct usb_packet_struct { uint16_t len; uint16_t index; @@ -40,8 +48,14 @@ typedef struct usb_packet_struct { uint8_t buf[64]; } usb_packet_t; -usb_packet_t * usb_malloc(void); -void usb_free(usb_packet_t *p); + + +// ----- Functions ----- + +usb_packet_t *usb_malloc(); +void usb_free( usb_packet_t *p ); + + #endif diff --git a/Output/pjrcUSB/arm/usb_serial.c b/Output/pjrcUSB/arm/usb_serial.c index f9ec66f..2f7a6c2 100644 --- a/Output/pjrcUSB/arm/usb_serial.c +++ b/Output/pjrcUSB/arm/usb_serial.c @@ -29,116 +29,24 @@ * SOFTWARE. */ -#include "usb_dev.h" -#include "usb_serial.h" -#include +// ----- Includes ----- + +// Compiler Includes #include // For memcpy -// defined by usb_dev.h -> usb_desc.h -#if defined(CDC_STATUS_INTERFACE) && defined(CDC_DATA_INTERFACE) +// Project Includes +#include -uint32_t usb_cdc_line_coding[2]; -volatile uint8_t usb_cdc_line_rtsdtr=0; -volatile uint8_t usb_cdc_transmit_flush_timer=0; +// Local Includes +#include "usb_dev.h" +#include "usb_serial.h" -static usb_packet_t *rx_packet=NULL; -static usb_packet_t *tx_packet=NULL; -static volatile uint8_t tx_noautoflush=0; + + +// ----- Defines ----- #define TRANSMIT_FLUSH_TIMEOUT 5 /* in milliseconds */ -// get the next character, or -1 if nothing received -int usb_serial_getchar(void) -{ - unsigned int i; - int c; - - if (!rx_packet) { - if (!usb_configuration) return -1; - rx_packet = usb_rx(CDC_RX_ENDPOINT); - if (!rx_packet) return -1; - } - i = rx_packet->index; - c = rx_packet->buf[i++]; - if (i >= rx_packet->len) { - usb_free(rx_packet); - rx_packet = NULL; - } else { - rx_packet->index = i; - } - return c; -} - -// peek at the next character, or -1 if nothing received -int usb_serial_peekchar(void) -{ - if (!rx_packet) { - if (!usb_configuration) return -1; - rx_packet = usb_rx(CDC_RX_ENDPOINT); - if (!rx_packet) return -1; - } - if (!rx_packet) return -1; - return rx_packet->buf[rx_packet->index]; -} - -// number of bytes available in the receive buffer -int usb_serial_available(void) -{ - int count; - count = usb_rx_byte_count(CDC_RX_ENDPOINT); - if (rx_packet) count += rx_packet->len - rx_packet->index; - return count; -} - -// read a block of bytes to a buffer -int usb_serial_read(void *buffer, uint32_t size) -{ - uint8_t *p = (uint8_t *)buffer; - uint32_t qty, count=0; - - while (size) { - if (!usb_configuration) break; - if (!rx_packet) { - rx: - rx_packet = usb_rx(CDC_RX_ENDPOINT); - if (!rx_packet) break; - if (rx_packet->len == 0) { - usb_free(rx_packet); - goto rx; - } - } - qty = rx_packet->len - rx_packet->index; - if (qty > size) qty = size; - memcpy(p, rx_packet->buf + rx_packet->index, qty); - p += qty; - count += qty; - size -= qty; - rx_packet->index += qty; - if (rx_packet->index >= rx_packet->len) { - usb_free(rx_packet); - rx_packet = NULL; - } - } - return count; -} - -// discard any buffered input -void usb_serial_flush_input(void) -{ - usb_packet_t *rx; - - if (!usb_configuration) return; - if (rx_packet) { - usb_free(rx_packet); - rx_packet = NULL; - } - while (1) { - rx = usb_rx(CDC_RX_ENDPOINT); - if (!rx) break; - usb_free(rx); - } -} - // Maximum number of transmit packets to queue so we don't starve other endpoints for memory #define TX_PACKET_LIMIT 8 @@ -155,21 +63,150 @@ void usb_serial_flush_input(void) #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 262) #endif + + +// ----- Variables ----- + +// serial port settings (baud rate, control signals, etc) set +// by the PC. These are ignored, but kept in RAM. +volatile uint8_t usb_cdc_line_coding[7] = { 0x00, 0xE1, 0x00, 0x00, 0x00, 0x00, 0x08 }; +volatile uint8_t usb_cdc_line_rtsdtr = 0; +volatile uint8_t usb_cdc_transmit_flush_timer = 0; + +static usb_packet_t *rx_packet = NULL; +static usb_packet_t *tx_packet = NULL; +static volatile uint8_t tx_noautoflush = 0; + // When we've suffered the transmit timeout, don't wait again until the computer // begins accepting data. If no software is running to receive, we'll just discard // data as rapidly as Serial.print() can generate it, until there's something to // actually receive it. -static uint8_t transmit_previous_timeout=0; +static uint8_t transmit_previous_timeout = 0; -// transmit a character. 0 returned on success, -1 on error -int usb_serial_putchar(uint8_t c) + +// ----- Functions ----- + +// get the next character, or -1 if nothing received +int usb_serial_getchar() { - return usb_serial_write(&c, 1); + unsigned int i; + int c; + + if ( !rx_packet ) + { + if ( !usb_configuration ) + return -1; + rx_packet = usb_rx( CDC_RX_ENDPOINT ); + if ( !rx_packet ) + return -1; + } + i = rx_packet->index; + c = rx_packet->buf[i++]; + if ( i >= rx_packet->len ) + { + usb_free( rx_packet ); + rx_packet = NULL; + } + else + { + rx_packet->index = i; + } + return c; } +// peek at the next character, or -1 if nothing received +int usb_serial_peekchar() +{ + if ( !rx_packet ) + { + if ( !usb_configuration ) + return -1; + rx_packet = usb_rx( CDC_RX_ENDPOINT ); + if ( !rx_packet ) + return -1; + } + if ( !rx_packet ) + return -1; + return rx_packet->buf[ rx_packet->index ]; +} -int usb_serial_write(const void *buffer, uint32_t size) +// number of bytes available in the receive buffer +int usb_serial_available() +{ + int count = usb_rx_byte_count( CDC_RX_ENDPOINT ); + if ( rx_packet ) + count += rx_packet->len - rx_packet->index; + return count; +} + +// read a block of bytes to a buffer +int usb_serial_read( void *buffer, uint32_t size ) +{ + uint8_t *p = (uint8_t *)buffer; + uint32_t qty, count=0; + + while ( size ) + { + if ( !usb_configuration ) + break; + if ( !rx_packet ) + { + rx: + rx_packet = usb_rx(CDC_RX_ENDPOINT); + if ( !rx_packet ) + break; + if ( rx_packet->len == 0 ) + { + usb_free(rx_packet); + goto rx; + } + } + qty = rx_packet->len - rx_packet->index; + if ( qty > size ) + qty = size; + memcpy( p, rx_packet->buf + rx_packet->index, qty ); + p += qty; + count += qty; + size -= qty; + rx_packet->index += qty; + if ( rx_packet->index >= rx_packet->len ) + { + usb_free( rx_packet ); + rx_packet = NULL; + } + } + return count; +} + +// discard any buffered input +void usb_serial_flush_input() +{ + usb_packet_t *rx; + + if ( !usb_configuration ) + return; + if ( rx_packet ) + { + usb_free( rx_packet ); + rx_packet = NULL; + } + while (1) + { + rx = usb_rx( CDC_RX_ENDPOINT ); + if ( !rx ) + break; + usb_free( rx ); + } +} + +// transmit a character. 0 returned on success, -1 on error +int usb_serial_putchar( uint8_t c ) +{ + return usb_serial_write( &c, 1 ); +} + +int usb_serial_write( const void *buffer, uint32_t size ) { uint32_t len; uint32_t wait_count; @@ -177,21 +214,28 @@ int usb_serial_write(const void *buffer, uint32_t size) uint8_t *dest; tx_noautoflush = 1; - while (size > 0) { - if (!tx_packet) { + while ( size > 0 ) + { + if ( !tx_packet ) + { wait_count = 0; - while (1) { - if (!usb_configuration) { + while ( 1 ) + { + if ( !usb_configuration ) + { tx_noautoflush = 0; return -1; } - if (usb_tx_packet_count(CDC_TX_ENDPOINT) < TX_PACKET_LIMIT) { + if ( usb_tx_packet_count( CDC_TX_ENDPOINT ) < TX_PACKET_LIMIT ) + { tx_noautoflush = 1; tx_packet = usb_malloc(); - if (tx_packet) break; + if ( tx_packet ) + break; tx_noautoflush = 0; } - if (++wait_count > TX_TIMEOUT || transmit_previous_timeout) { + if ( ++wait_count > TX_TIMEOUT || transmit_previous_timeout ) + { transmit_previous_timeout = 1; return -1; } @@ -200,14 +244,17 @@ int usb_serial_write(const void *buffer, uint32_t size) } transmit_previous_timeout = 0; len = CDC_TX_SIZE - tx_packet->index; - if (len > size) len = size; + if ( len > size ) + len = size; dest = tx_packet->buf + tx_packet->index; tx_packet->index += len; size -= len; - while (len-- > 0) *dest++ = *src++; - if (tx_packet->index >= CDC_TX_SIZE) { + while ( len-- > 0 ) + *dest++ = *src++; + if ( tx_packet->index >= CDC_TX_SIZE ) + { tx_packet->len = CDC_TX_SIZE; - usb_tx(CDC_TX_ENDPOINT, tx_packet); + usb_tx( CDC_TX_ENDPOINT, tx_packet ); tx_packet = NULL; } usb_cdc_transmit_flush_timer = TRANSMIT_FLUSH_TIMEOUT; @@ -216,43 +263,53 @@ int usb_serial_write(const void *buffer, uint32_t size) return 0; } -void usb_serial_flush_output(void) +void usb_serial_flush_output() { - if (!usb_configuration) return; + if ( !usb_configuration ) + return; tx_noautoflush = 1; - if (tx_packet) { + if ( tx_packet ) + { usb_cdc_transmit_flush_timer = 0; tx_packet->len = tx_packet->index; - usb_tx(CDC_TX_ENDPOINT, tx_packet); + usb_tx( CDC_TX_ENDPOINT, tx_packet ); tx_packet = NULL; - } else { + } + else + { usb_packet_t *tx = usb_malloc(); - if (tx) { + if ( tx ) + { usb_cdc_transmit_flush_timer = 0; - usb_tx(CDC_TX_ENDPOINT, tx); - } else { + usb_tx( CDC_TX_ENDPOINT, tx ); + } + else + { usb_cdc_transmit_flush_timer = 1; } } tx_noautoflush = 0; } -void usb_serial_flush_callback(void) +void usb_serial_flush_callback() { - if (tx_noautoflush) return; - if (tx_packet) { + if ( tx_noautoflush ) + return; + if ( tx_packet ) + { tx_packet->len = tx_packet->index; - usb_tx(CDC_TX_ENDPOINT, tx_packet); + usb_tx( CDC_TX_ENDPOINT, tx_packet ); tx_packet = NULL; } else { usb_packet_t *tx = usb_malloc(); - if (tx) { - usb_tx(CDC_TX_ENDPOINT, tx); - } else { + if ( tx ) + { + usb_tx( CDC_TX_ENDPOINT, tx ); + } + else + { usb_cdc_transmit_flush_timer = 1; } } } -#endif // CDC_STATUS_INTERFACE && CDC_DATA_INTERFACE - diff --git a/Output/pjrcUSB/arm/usb_serial.h b/Output/pjrcUSB/arm/usb_serial.h index d64396b..487ef98 100644 --- a/Output/pjrcUSB/arm/usb_serial.h +++ b/Output/pjrcUSB/arm/usb_serial.h @@ -1,6 +1,7 @@ /* Teensyduino Core Library * http://www.pjrc.com/teensy/ * Copyright (c) 2013 PJRC.COM, LLC. + * Modifications by Jacob Alexander (2013-2014) * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -31,29 +32,48 @@ #ifndef USBserial_h_ #define USBserial_h_ +// ----- Includes ----- + +// Compiler Includes #include + + +// ----- Defines ----- + // Compatibility defines from AVR #define PROGMEM #define PGM_P const char * #define PSTR(str) (str) +#define USB_SERIAL_DTR 0x01 +#define USB_SERIAL_RTS 0x02 + + + +// ----- Variables ----- + +extern volatile uint8_t usb_cdc_line_coding[7]; -int usb_serial_getchar(void); -int usb_serial_peekchar(void); -int usb_serial_available(void); -int usb_serial_read(void *buffer, uint32_t size); -void usb_serial_flush_input(void); -int usb_serial_putchar(uint8_t c); -int usb_serial_write(const void *buffer, uint32_t size); -void usb_serial_flush_output(void); -extern uint32_t usb_cdc_line_coding[2]; extern volatile uint8_t usb_cdc_line_rtsdtr; extern volatile uint8_t usb_cdc_transmit_flush_timer; extern volatile uint8_t usb_configuration; -#define USB_SERIAL_DTR 0x01 -#define USB_SERIAL_RTS 0x02 + + +// ----- Functions ----- + +int usb_serial_available(); +int usb_serial_getchar(); +int usb_serial_peekchar(); +int usb_serial_putchar( uint8_t c ); +int usb_serial_read( void *buffer, uint32_t size ); +int usb_serial_write( const void *buffer, uint32_t size ); + +void usb_serial_flush_input(); +void usb_serial_flush_output(); + + #endif // USBserial_h_