From 358d480ea9862106f851cbb68c1d68da7369ddd5 Mon Sep 17 00:00:00 2001 From: Jacob Alexander Date: Tue, 31 May 2016 00:19:45 -0700 Subject: [PATCH] Major USB update, fixes most (if not all) known issues USB - General - Refactored descriptors - Enabled/Disable USB endpoints - Added debug flags for special features - Code cleanup - Interface count calculation based off of enabled endpoints - Delayed wTotalLength calculation to simplify descriptor offsets - Re-ordered endpoints and interfaces - Added more debug output - Added usbInitTime to show how long keyboard initialization took (Useful when debugging bad init sequences) - Added function for usb_resume() which takes care of the resume sequence * Resume is now only called if packets are starting to timeout USB - Special Options - Added enableDeviceRestartOnUSBTimeout * A last resort hammer for bad USB Chipsets/OSs, don't use if you can help it * Disabled - Added enableUSBResume * Enables host resume wake-up signalling, required to wake a computer from sleep * Enabled - Added enableUSBLowPowerNegotiation * Enables power negotiation hack * Required to use firmware with an IPad and other hard-limit low-power USB hosts * Hasn't been tested with the recent changes * Disabled - Added enableUSBSuspend * Enables power down events on host USB bus suspend * Enabled USB - Keyboard - Attempted to cleanup HID SET_REPORT * Works much better * Still has an issue under Linux which generates *a lot* of NAKs (initializes quickly regardless) + Not present on other keyboards + SETUP -> OUT -> IN : This sequence is the problem + Specifically during the OUT phase - Enabled USB - CDC Virtual Serial Port - Code cleanup - Added convenience struct USBCDCLineCoding for easier debugging - Attempted to cleanup CDC_SET_LING_CODING * Works much better * Still has an issue under Linux which generates *a lot* of NAKs (initializes quickly regardless) + SETUP -> OUT -> IN : This sequence is the problem + Specifically during the OUT phase + Likely the same issues as HID SET_REPORT - Enabled USB - Mouse - Enabled USB - Joystick - Disabled USB - RawIO - Initial code, API not used yet - Disabled DFU - Updated load script, now faster --- Debug/print/print.c | 5 +- LoadFile/load.dfu | 25 ++- Output/pjrcUSB/arm/usb_desc.c | 353 ++++++++++++++++++++++-------- Output/pjrcUSB/arm/usb_desc.h | 111 +++++++--- Output/pjrcUSB/arm/usb_dev.c | 351 ++++++++++++++++++++--------- Output/pjrcUSB/arm/usb_dev.h | 6 +- Output/pjrcUSB/arm/usb_joystick.c | 6 +- Output/pjrcUSB/arm/usb_keyboard.c | 20 +- Output/pjrcUSB/arm/usb_mouse.c | 5 + Output/pjrcUSB/arm/usb_rawio.c | 141 ++++++++++++ Output/pjrcUSB/arm/usb_rawio.h | 35 +++ Output/pjrcUSB/arm/usb_serial.c | 19 +- Output/pjrcUSB/arm/usb_serial.h | 31 ++- Output/pjrcUSB/capabilities.kll | 63 +++++- Output/pjrcUSB/output_com.c | 101 ++++++++- Output/pjrcUSB/output_com.h | 4 + Output/pjrcUSB/setup.cmake | 3 +- Output/usbMuxUart/output_com.c | 77 ++++++- 18 files changed, 1097 insertions(+), 259 deletions(-) create mode 100644 Output/pjrcUSB/arm/usb_rawio.c create mode 100644 Output/pjrcUSB/arm/usb_rawio.h diff --git a/Debug/print/print.c b/Debug/print/print.c index c93ec50..4d4aa40 100644 --- a/Debug/print/print.c +++ b/Debug/print/print.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2011-2014 by Jacob Alexander +/* Copyright (C) 2011-2016 by Jacob Alexander * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -127,7 +127,7 @@ void printHex32_op( uint32_t in, uint8_t op ) // With an op of 1, the max number of characters is 6 + 1 for null // e.g. "0xFFFF\0" // op 2 and 4 require fewer characters (2+1 and 4+1 respectively) - char tmpStr[7]; + char tmpStr[11]; // Convert number hex32ToStr_op( in, tmpStr, op ); @@ -259,6 +259,7 @@ void hex32ToStr_op( uint32_t in, char* out, uint8_t op ) break; case 2: // 8-bit padding case 4: // 16-bit padding + case 8: // 32-bit padding while ( pos < op ) out[pos++] = '0'; break; diff --git a/LoadFile/load.dfu b/LoadFile/load.dfu index 5c7719c..8f2c7e3 100755 --- a/LoadFile/load.dfu +++ b/LoadFile/load.dfu @@ -2,8 +2,9 @@ # Convenience script for loading firmware onto a dfu type device # By default, initiates dfu-util -SERIAL_PORT="" -AUTO_SCREEN_SESSION="" +SERIAL_PORT="/dev/kiibohd" +AUTO_SCREEN_SESSION="/dev/kiibohd" +NOSCREEN=0 PROG_NAME=$(basename $0) # Parse all the command line arguments @@ -19,6 +20,10 @@ while (( "$#" >= "1" )); do SERIAL_PORT="$2" shift ;; + -n|--noscreen) + NOSCREEN=1 + shift + ;; -h|--help) echo "Usage: $PROG_NAME [options...]" echo "" @@ -49,12 +54,19 @@ done if [[ "$SERIAL_PORT" != "" ]] && [[ -e "$SERIAL_PORT" ]]; then echo "NOTE: This may fail if the uC is in a bad state or does not support remote flashing" printf "reload\r" > $SERIAL_PORT - sleep 2 fi # Load via dfu-util # Used for McHCK based uCs if type dfu-util &>/dev/null; then + # Wait for device to appear + while true; do + dfu-util -l | grep -q "Kiibohd DFU" + if [ $? -eq 0 ]; then + break + fi + sleep 0.1 + done dfu-util -D @TARGET_BIN@ EXIT_STATUS=$? else @@ -63,9 +75,12 @@ else fi # Load Screen Session if specified -if (( "$EXIT_STATUS" == "0" )) && [[ "$AUTO_SCREEN_SESSION" != "" ]]; then +if (( "$EXIT_STATUS" == "0" )) && [[ "$AUTO_SCREEN_SESSION" != "" ]] && [[ $NOSCREEN -ne 1 ]]; then if type screen &>/dev/null; then - sleep 0.1 + # Wait for interface + while [ ! -e $AUTO_SCREEN_SESSION ]; do + sleep 0.1 + done screen $AUTO_SCREEN_SESSION else echo "screen is not installed" diff --git a/Output/pjrcUSB/arm/usb_desc.c b/Output/pjrcUSB/arm/usb_desc.c index b0be2a0..56fd482 100644 --- a/Output/pjrcUSB/arm/usb_desc.c +++ b/Output/pjrcUSB/arm/usb_desc.c @@ -103,6 +103,7 @@ static uint8_t usb_debug_descriptor[] = { // the meaning and format of the data. // Keyboard Protocol 1, HID 1.11 spec, Appendix B, page 59-60 +#if enableKeyboard_define == 1 static uint8_t keyboard_report_desc[] = { // Keyboard Collection 0x05, 0x01, // Usage Page (Generic Desktop), @@ -304,8 +305,11 @@ static uint8_t sys_ctrl_report_desc[] = { 0x81, 0x00, // Input (Data, Array), 0xc0, // End Collection - Consumer Control }; +#endif + // Mouse Protocol 1, HID 1.11 spec, Appendix B, page 59-60, with wheel extension +#if enableMouse_define == 1 static uint8_t mouse_report_desc[] = { 0x05, 0x01, // Usage Page (Generic Desktop) 0x09, 0x02, // Usage (Mouse) @@ -383,73 +387,117 @@ static uint8_t mouse_report_desc[] = { 0xc0, // End Collection - Mouse Logical 0xc0 // End Collection - Mouse Application }; +#endif + // Joystick Protocol, HID 1.11 spec, Apendix D, page 64-65 +#if enableJoystick_define == 1 static uint8_t joystick_report_desc[] = { - 0x05, 0x01, // Usage Page (Generic Desktop) - 0x09, 0x04, // Usage (Joystick) - 0xA1, 0x01, // Collection (Application) - 0x15, 0x00, // Logical Minimum (0) - 0x25, 0x01, // Logical Maximum (1) - 0x75, 0x01, // Report Size (1) - 0x95, 0x20, // Report Count (32) - 0x05, 0x09, // Usage Page (Button) - 0x19, 0x01, // Usage Minimum (Button #1) - 0x29, 0x20, // Usage Maximum (Button #32) - 0x81, 0x02, // Input (variable,absolute) - 0x15, 0x00, // Logical Minimum (0) - 0x25, 0x07, // Logical Maximum (7) - 0x35, 0x00, // Physical Minimum (0) - 0x46, 0x3B, 0x01, // Physical Maximum (315) - 0x75, 0x04, // Report Size (4) - 0x95, 0x01, // Report Count (1) - 0x65, 0x14, // Unit (20) - 0x05, 0x01, // Usage Page (Generic Desktop) - 0x09, 0x39, // Usage (Hat switch) - 0x81, 0x42, // Input (variable,absolute,null_state) - 0x05, 0x01, // Usage Page (Generic Desktop) - 0x09, 0x01, // Usage (Pointer) - 0xA1, 0x00, // Collection () - 0x15, 0x00, // Logical Minimum (0) - 0x26, 0xFF, 0x03, // Logical Maximum (1023) - 0x75, 0x0A, // Report Size (10) - 0x95, 0x04, // Report Count (4) - 0x09, 0x30, // Usage (X) - 0x09, 0x31, // Usage (Y) - 0x09, 0x32, // Usage (Z) - 0x09, 0x35, // Usage (Rz) - 0x81, 0x02, // Input (variable,absolute) - 0xC0, // End Collection - 0x15, 0x00, // Logical Minimum (0) - 0x26, 0xFF, 0x03, // Logical Maximum (1023) - 0x75, 0x0A, // Report Size (10) - 0x95, 0x02, // Report Count (2) - 0x09, 0x36, // Usage (Slider) - 0x09, 0x36, // Usage (Slider) - 0x81, 0x02, // Input (variable,absolute) - 0xC0 // End Collection + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x04, // Usage (Joystick) + 0xA1, 0x01, // Collection (Application) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x75, 0x01, // Report Size (1) + 0x95, 0x20, // Report Count (32) + 0x05, 0x09, // Usage Page (Button) + 0x19, 0x01, // Usage Minimum (Button #1) + 0x29, 0x20, // Usage Maximum (Button #32) + 0x81, 0x02, // Input (variable,absolute) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x07, // Logical Maximum (7) + 0x35, 0x00, // Physical Minimum (0) + 0x46, 0x3B, 0x01, // Physical Maximum (315) + 0x75, 0x04, // Report Size (4) + 0x95, 0x01, // Report Count (1) + 0x65, 0x14, // Unit (20) + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x39, // Usage (Hat switch) + 0x81, 0x42, // Input (variable,absolute,null_state) + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x01, // Usage (Pointer) + 0xA1, 0x00, // Collection () + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x03, // Logical Maximum (1023) + 0x75, 0x0A, // Report Size (10) + 0x95, 0x04, // Report Count (4) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x09, 0x32, // Usage (Z) + 0x09, 0x35, // Usage (Rz) + 0x81, 0x02, // Input (variable,absolute) + 0xC0, // End Collection + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x03, // Logical Maximum (1023) + 0x75, 0x0A, // Report Size (10) + 0x95, 0x02, // Report Count (2) + 0x09, 0x36, // Usage (Slider) + 0x09, 0x36, // Usage (Slider) + 0x81, 0x02, // Input (variable,absolute) + 0xC0 // End Collection }; +#endif // ----- USB Configuration ----- +// Check for non-selected USB descriptors to update the total interface count +// XXX This must be correct or some OSs/Init sequences will not initialize the keyboard/device +#if enableKeyboard_define != 1 +#undef KEYBOARD_INTERFACES +#define KEYBOARD_INTERFACES 0 +#endif + +#if enableMouse_define != 1 +#undef MOUSE_INTERFACES +#define MOUSE_INTERFACES 0 +#endif + +#if enableJoystick_define != 1 +#undef JOYSTICK_INTERFACES +#define JOYSTICK_INTERFACES 0 +#endif + +#if enableVirtualSerialPort_define != 1 +#undef CDC_INTERFACES +#define CDC_INTERFACES 0 +#endif + +#if enableRawIO_define != 1 +#undef RAWIO_INTERFACES +#define RAWIO_INTERFACES 0 +#endif + +// Determine number of interfaces +#define NUM_INTERFACE (KEYBOARD_INTERFACES + CDC_INTERFACES + MOUSE_INTERFACES + JOYSTICK_INTERFACES + RAWIO_INTERFACES) + + // USB Configuration Descriptor. This huge descriptor tells all // of the devices capbilities. -static uint8_t config_descriptor[CONFIG_DESC_SIZE] = { +static uint8_t config_descriptor[] = { // --- 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 - MSB(CONFIG_DESC_SIZE), + 0xFF, // wTotalLength - XXX Set in usb_init (simplifies defines) + 0xFF, NUM_INTERFACE, // bNumInterfaces 1, // bConfigurationValue 0, // iConfiguration 0xA0, // bmAttributes 250, // bMaxPower - Entry Index 8 + +// +// --- Keyboard Endpoint Descriptors --- +// +#if enableKeyboard_define == 1 +#define KEYBOARD_DESC_TOTAL_OFFSET (KEYBOARD_DESC_SIZE + NKRO_KEYBOARD_DESC_SIZE + SYS_CTRL_DESC_SIZE) +#define NKRO_KEYBOARD_DESC_BASE_OFFSET (KEYBOARD_DESC_BASE_OFFSET + KEYBOARD_DESC_SIZE) +#define SYS_CTRL_DESC_BASE_OFFSET (KEYBOARD_DESC_BASE_OFFSET + KEYBOARD_DESC_SIZE + NKRO_KEYBOARD_DESC_SIZE) + // --- Keyboard HID --- Boot Mode Keyboard Interface // - 9 bytes - // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 @@ -512,6 +560,47 @@ static uint8_t config_descriptor[CONFIG_DESC_SIZE] = { NKRO_KEYBOARD_SIZE, 0, // wMaxPacketSize NKRO_KEYBOARD_INTERVAL, // bInterval +// --- System/Consumer Control --- +// - 9 bytes - + // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 + 9, // bLength + 4, // bDescriptorType + SYS_CTRL_INTERFACE, // bInterfaceNumber + 0, // bAlternateSetting + 1, // bNumEndpoints + 0x03, // bInterfaceClass (0x03 = HID) + 0x01, // bInterfaceSubClass (0x00 = Non-Boot, 0x01 = Boot) + 0x00, // bInterfaceProtocol (0x00 = None) + SYS_CTRL_INTERFACE + 4, // iInterface +// - 9 bytes - + // HID interface descriptor, HID 1.11 spec, section 6.2.1 + 9, // bLength + 0x21, // bDescriptorType + 0x11, 0x01, // bcdHID + KeyboardLocale_define, // bCountryCode + 1, // bNumDescriptors + 0x22, // bDescriptorType + LSB(sizeof(sys_ctrl_report_desc)), // wDescriptorLength + MSB(sizeof(sys_ctrl_report_desc)), +// - 7 bytes - + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + 7, // bLength + 5, // bDescriptorType + SYS_CTRL_ENDPOINT | 0x80, // bEndpointAddress + 0x03, // bmAttributes (0x03=intr) + SYS_CTRL_SIZE, 0, // wMaxPacketSize + SYS_CTRL_INTERVAL, // bInterval +#else +#define KEYBOARD_DESC_TOTAL_OFFSET (0) +#endif + + +// +// --- CDC / Serial Port Endpoint Descriptors --- +// +#if enableVirtualSerialPort_define == 1 +#define SERIAL_CDC_DESC_TOTAL_OFFSET (SERIAL_CDC_DESC_SIZE) + // --- Serial CDC --- CDC IAD Descriptor // - 8 bytes - // interface association descriptor, USB ECN, Table 9-Z @@ -522,7 +611,7 @@ static uint8_t config_descriptor[CONFIG_DESC_SIZE] = { 0x02, // bFunctionClass 0x02, // bFunctionSubClass 0x01, // bFunctionProtocol - CDC_STATUS_INTERFACE + 4, // iFunction + 0, // iFunction (XXX No interface index, don't give string -HaaTa) // --- Serial CDC --- CDC Data Interface // - 9 bytes - @@ -597,6 +686,57 @@ static uint8_t config_descriptor[CONFIG_DESC_SIZE] = { 0x02, // bmAttributes (0x02=bulk) CDC_TX_SIZE, 0, // wMaxPacketSize 0, // bInterval +#else +#define SERIAL_CDC_DESC_TOTAL_OFFSET (0) +#endif + + +// +// --- Raw IO Endpoint Descriptors --- +// +#if enableRawIO_define == 1 +#define RAWIO_DESC_TOTAL_OFFSET (RAWIO_DESC_SIZE) + +// --- Vendor Specific / RAW I/O --- +// - 9 bytes - + // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 + 9, // bLength + 4, // bDescriptorType + RAWIO_INTERFACE, // bInterfaceNumber + 0, // bAlternateSetting + 2, // bNumEndpoints + 0xFF, // bInterfaceClass (0xFF) + 0xFF, // bInterfaceSubClass + 0xFF, // bInterfaceProtocol + RAWIO_INTERFACE + 4, // iInterface + +// - 7 bytes - + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + 7, // bLength + 5, // bDescriptorType + RAWIO_TX_ENDPOINT | 0x80, // bEndpointAddress + 0x02, // bmAttributes (0x02=bulk) + RAWIO_TX_SIZE, 0, // wMaxPacketSize + RAWIO_TX_INTERVAL, // bInterval + +// - 7 bytes - + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + 7, // bLength + 5, // bDescriptorType + RAWIO_RX_ENDPOINT, // bEndpointAddress + 0x02, // bmAttributes (0x02=bulk) + RAWIO_RX_SIZE, 0, // wMaxPacketSize + RAWIO_RX_INTERVAL, // bInterval +#else +#define RAWIO_DESC_TOTAL_OFFSET (0) +#endif + + +// +// --- Mouse Endpoint Descriptors --- +// +#if enableMouse_define == 1 +#define MOUSE_DESC_TOTAL_OFFSET (MOUSE_DESC_SIZE) // --- Mouse Interface --- // - 9 bytes - @@ -628,6 +768,16 @@ static uint8_t config_descriptor[CONFIG_DESC_SIZE] = { 0x03, // bmAttributes (0x03=intr) MOUSE_SIZE, 0, // wMaxPacketSize MOUSE_INTERVAL, // bInterval +#else +#define MOUSE_DESC_TOTAL_OFFSET (0) +#endif + + +// +// --- Joystick Endpoint Descriptors --- +// +#if enableJoystick_define == 1 +#define JOYSTICK_DESC_TOTAL_OFFSET (JOYSTICK_DESC_SIZE) // --- Joystick Interface --- // - 9 bytes - @@ -659,37 +809,10 @@ static uint8_t config_descriptor[CONFIG_DESC_SIZE] = { 0x03, // bmAttributes (0x03=intr) JOYSTICK_SIZE, 0, // wMaxPacketSize JOYSTICK_INTERVAL, // bInterval +#else +#define JOYSTICK_DESC_TOTAL_OFFSET (0) +#endif -// --- System/Consumer Control --- -// - 9 bytes - - // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 - 9, // bLength - 4, // bDescriptorType - SYS_CTRL_INTERFACE, // bInterfaceNumber - 0, // bAlternateSetting - 1, // bNumEndpoints - 0x03, // bInterfaceClass (0x03 = HID) - 0x01, // bInterfaceSubClass (0x00 = Non-Boot, 0x01 = Boot) - 0x00, // bInterfaceProtocol (0x00 = None) - SYS_CTRL_INTERFACE + 4, // iInterface -// - 9 bytes - - // HID interface descriptor, HID 1.11 spec, section 6.2.1 - 9, // bLength - 0x21, // bDescriptorType - 0x11, 0x01, // bcdHID - KeyboardLocale_define, // bCountryCode - 1, // bNumDescriptors - 0x22, // bDescriptorType - LSB(sizeof(sys_ctrl_report_desc)), // wDescriptorLength - MSB(sizeof(sys_ctrl_report_desc)), -// - 7 bytes - - // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 - 7, // bLength - 5, // bDescriptorType - SYS_CTRL_ENDPOINT | 0x80, // bEndpointAddress - 0x03, // bmAttributes (0x03=intr) - SYS_CTRL_SIZE, 0, // wMaxPacketSize - SYS_CTRL_INTERVAL, // bInterval }; uint8_t *usb_bMaxPower = &config_descriptor[8]; @@ -731,18 +854,37 @@ struct usb_string_descriptor_struct string0 = { usb_string_descriptor( usb_string_manufacturer_name_default, STR_MANUFACTURER ); usb_string_descriptor( usb_string_product_name_default, STR_PRODUCT ); usb_string_descriptor( usb_string_serial_number_default, STR_SERIAL ); + +#if enableKeyboard_define == 1 usb_string_descriptor( usb_string_keyboard_name, KEYBOARD_NAME ); usb_string_descriptor( usb_string_nkro_keyboard_name, NKRO_KEYBOARD_NAME ); +usb_string_descriptor( usb_string_sys_ctrl_name, SYS_CTRL_NAME ); +#endif + +#if enableVirtualSerialPort_define == 1 usb_string_descriptor( usb_string_cdc_status_name, CDC_STATUS_NAME ); usb_string_descriptor( usb_string_cdc_data_name, CDC_DATA_NAME ); +#endif + +#if enableRawIO_define == 1 +usb_string_descriptor( usb_string_rawio_name, RAWIO_NAME ); +#endif + +#if enableMouse_define == 1 usb_string_descriptor( usb_string_mouse_name, MOUSE_NAME ); +#endif + +#if enableJoystick_define == 1 usb_string_descriptor( usb_string_joystick_name, JOYSTICK_NAME ); -usb_string_descriptor( usb_string_sys_ctrl_name, SYS_CTRL_NAME ); +#endif // ----- Descriptors List ----- +#define iInterfaceString(num, var) \ + {0x0300 + 4 + num, 0x0409, (const uint8_t *)&var, 0 } + // This table provides access to all the descriptor data above. const usb_descriptor_list_t usb_descriptor_list[] = { @@ -752,38 +894,57 @@ const usb_descriptor_list_t usb_descriptor_list[] = { {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}, - - {0x2200, NKRO_KEYBOARD_INTERFACE, nkro_keyboard_report_desc, sizeof(nkro_keyboard_report_desc)}, - {0x2100, NKRO_KEYBOARD_INTERFACE, config_descriptor + NKRO_KEYBOARD_DESC_OFFSET, 9}, - - {0x2200, MOUSE_INTERFACE, mouse_report_desc, sizeof(mouse_report_desc)}, - {0x2100, MOUSE_INTERFACE, config_descriptor + MOUSE_DESC_OFFSET, 9}, - - {0x2200, JOYSTICK_INTERFACE, joystick_report_desc, sizeof(joystick_report_desc)}, - {0x2100, JOYSTICK_INTERFACE, config_descriptor + JOYSTICK_DESC_OFFSET, 9}, - - {0x2200, SYS_CTRL_INTERFACE, sys_ctrl_report_desc, sizeof(sys_ctrl_report_desc)}, - {0x2100, SYS_CTRL_INTERFACE, config_descriptor + SYS_CTRL_DESC_OFFSET, 9}, - -#define iInterfaceString(num, var) \ - {0x0300 + 4 + num, 0x409, (const uint8_t *)&var, 0 } - {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}, {0x0303, 0x0409, (const uint8_t *)&usb_string_serial_number, 0}, + +#if enableKeyboard_define == 1 + {0x2200, KEYBOARD_INTERFACE, keyboard_report_desc, sizeof(keyboard_report_desc)}, + {0x2100, KEYBOARD_INTERFACE, config_descriptor + KEYBOARD_DESC_BASE_OFFSET, 9}, + + {0x2200, NKRO_KEYBOARD_INTERFACE, nkro_keyboard_report_desc, sizeof(nkro_keyboard_report_desc)}, + {0x2100, NKRO_KEYBOARD_INTERFACE, config_descriptor + NKRO_KEYBOARD_DESC_BASE_OFFSET, 9}, + + {0x2200, SYS_CTRL_INTERFACE, sys_ctrl_report_desc, sizeof(sys_ctrl_report_desc)}, + {0x2100, SYS_CTRL_INTERFACE, config_descriptor + SYS_CTRL_DESC_BASE_OFFSET, 9}, + iInterfaceString( KEYBOARD_INTERFACE, usb_string_keyboard_name ), iInterfaceString( NKRO_KEYBOARD_INTERFACE, usb_string_nkro_keyboard_name ), + iInterfaceString( SYS_CTRL_INTERFACE, usb_string_sys_ctrl_name ), +#endif + +#if enableVirtualSerialPort_define == 1 iInterfaceString( CDC_STATUS_INTERFACE, usb_string_cdc_status_name ), iInterfaceString( CDC_DATA_INTERFACE, usb_string_cdc_data_name ), +#endif + +#if enableRawIO_define == 1 + iInterfaceString( RAWIO_INTERFACE, usb_string_rawio_name ), +#endif + +#if enableMouse_define == 1 + {0x2200, MOUSE_INTERFACE, mouse_report_desc, sizeof(mouse_report_desc)}, + {0x2100, MOUSE_INTERFACE, config_descriptor + MOUSE_DESC_BASE_OFFSET, 9}, iInterfaceString( MOUSE_INTERFACE, usb_string_mouse_name ), +#endif + +#if enableJoystick_define == 1 + {0x2200, JOYSTICK_INTERFACE, joystick_report_desc, sizeof(joystick_report_desc)}, + {0x2100, JOYSTICK_INTERFACE, config_descriptor + JOYSTICK_DESC_BASE_OFFSET, 9}, iInterfaceString( JOYSTICK_INTERFACE, usb_string_joystick_name ), - iInterfaceString( SYS_CTRL_INTERFACE, usb_string_sys_ctrl_name ), +#endif + {0, 0, NULL, 0} }; +// Simplifies defines for USB descriptors +void usb_set_config_descriptor_size() +{ + config_descriptor[2] = LSB( sizeof( config_descriptor ) ); + config_descriptor[3] = MSB( sizeof( config_descriptor ) ); +} + // ----- Endpoint Configuration ----- diff --git a/Output/pjrcUSB/arm/usb_desc.h b/Output/pjrcUSB/arm/usb_desc.h index 0e769a1..adbc949 100644 --- a/Output/pjrcUSB/arm/usb_desc.h +++ b/Output/pjrcUSB/arm/usb_desc.h @@ -54,9 +54,18 @@ #define DEVICE_SUBCLASS 0x00 #define DEVICE_PROTOCOL 0x00 #define EP0_SIZE 64 -#define NUM_ENDPOINTS 8 +#define NUM_ENDPOINTS 10 // XXX Can save some space if this can be calculated using KLL #define NUM_USB_BUFFERS 30 -#define NUM_INTERFACE 7 + +// XXX Remember to update total interface count, if it isn't correct some OSs will not initialize USB +// Linux warns in dmesg +// Mac OSX login screen will not initialize +#define KEYBOARD_INTERFACES 3 // Boot, NKRO, SysCtrl +#define CDC_INTERFACES 2 +#define MOUSE_INTERFACES 1 +#define JOYSTICK_INTERFACES 1 +#define RAWIO_INTERFACES 1 + #define KEYBOARD_INTERFACE 0 // Keyboard #define KEYBOARD_ENDPOINT 1 @@ -70,52 +79,97 @@ #define NKRO_KEYBOARD_INTERVAL 1 #define NKRO_KEYBOARD_NAME L"NKRO Keyboard" +#define SYS_CTRL_INTERFACE 2 // Media Keys +#define SYS_CTRL_ENDPOINT 3 +#define SYS_CTRL_SIZE 8 +#define SYS_CTRL_INTERVAL 1 +#define SYS_CTRL_NAME L"Media Keys" + #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_STATUS_INTERFACE 3 +#define CDC_DATA_INTERFACE 4 // Serial +#define CDC_ACM_ENDPOINT 4 +#define CDC_RX_ENDPOINT 5 +#define CDC_TX_ENDPOINT 6 #define CDC_ACM_SIZE 16 #define CDC_RX_SIZE 64 #define CDC_TX_SIZE 64 #define CDC_STATUS_NAME L"Virtual Serial Port - Status" #define CDC_DATA_NAME L"Virtual Serial Port - Data" -#define MOUSE_INTERFACE 4 // Mouse -#define MOUSE_ENDPOINT 6 +#define RAWIO_INTERFACE 5 // RawIO +#define RAWIO_TX_ENDPOINT 7 +#define RAWIO_TX_SIZE 64 +#define RAWIO_TX_INTERVAL 1 +#define RAWIO_RX_ENDPOINT 8 +#define RAWIO_RX_SIZE 64 +#define RAWIO_RX_INTERVAL 1 +#define RAWIO_NAME L"API Interface" + +#define MOUSE_INTERFACE 6 // Mouse +#define MOUSE_ENDPOINT 9 #define MOUSE_SIZE 8 #define MOUSE_INTERVAL 1 #define MOUSE_NAME L"Mouse" -#define JOYSTICK_INTERFACE 5 // Joystick -#define JOYSTICK_ENDPOINT 7 +#define JOYSTICK_INTERFACE 7 // Joystick +#define JOYSTICK_ENDPOINT 10 #define JOYSTICK_SIZE 16 #define JOYSTICK_INTERVAL 1 #define JOYSTICK_NAME L"Joystick" -#define SYS_CTRL_INTERFACE 6 // Media Keys -#define SYS_CTRL_ENDPOINT 8 -#define SYS_CTRL_SIZE 8 -#define SYS_CTRL_INTERVAL 1 -#define SYS_CTRL_NAME L"Media Keys" -#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 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 SYS_CTRL_DESC_OFFSET (9 + 9+9+7 + 9+9+7 + 8+9+5+5+4+5+7+9+7+7 + 9+9+7 + 9+9+7 + 9) -#define CONFIG_DESC_SIZE (9 + 9+9+7 + 9+9+7 + 8+9+5+5+4+5+7+9+7+7 + 9+9+7 + 9+9+7 + 9+9+7) +// Descriptor sizes +#define BASE_DESC_SIZE (9) +#define KEYBOARD_DESC_SIZE (9+9+7) +#define NKRO_KEYBOARD_DESC_SIZE (9+9+7) +#define SYS_CTRL_DESC_SIZE (9+9+7) +#define SERIAL_CDC_DESC_SIZE (8+9+5+5+4+5+7+9+7+7) +#define RAWIO_DESC_SIZE (9+7+7) +#define MOUSE_DESC_SIZE (9+9+7) +#define JOYSTICK_DESC_SIZE (9+9+7) + +// Descriptor offsets +#define KEYBOARD_DESC_BASE_OFFSET ( \ + BASE_DESC_SIZE + \ + 9 \ +) +#define SERIAL_CDC_DESC_BASE_OFFSET ( \ + BASE_DESC_SIZE + \ + KEYBOARD_DESC_TOTAL_OFFSET + \ + 8 \ +) +#define RAWIO_DESC_BASE_OFFSET ( \ + BASE_DESC_SIZE + \ + KEYBOARD_DESC_TOTAL_OFFSET + \ + SERIAL_CDC_DESC_TOTAL_OFFSET + \ + 9 \ +) +#define MOUSE_DESC_BASE_OFFSET ( \ + BASE_DESC_SIZE + \ + KEYBOARD_DESC_TOTAL_OFFSET + \ + SERIAL_CDC_DESC_TOTAL_OFFSET + \ + 9 \ +) +#define JOYSTICK_DESC_BASE_OFFSET ( \ + BASE_DESC_SIZE + \ + KEYBOARD_DESC_TOTAL_OFFSET + \ + SERIAL_CDC_DESC_TOTAL_OFFSET + \ + MOUSE_DESC_TOTAL_OFFSET + \ + 9 \ +) + #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY #define ENDPOINT2_CONFIG ENDPOINT_TRANSIMIT_ONLY #define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY -#define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY -#define ENDPOINT5_CONFIG ENDPOINT_TRANSIMIT_ONLY +#define ENDPOINT4_CONFIG ENDPOINT_TRANSIMIT_ONLY +#define ENDPOINT5_CONFIG ENDPOINT_RECEIVE_ONLY #define ENDPOINT6_CONFIG ENDPOINT_TRANSIMIT_ONLY #define ENDPOINT7_CONFIG ENDPOINT_TRANSIMIT_ONLY -#define ENDPOINT8_CONFIG ENDPOINT_TRANSIMIT_ONLY +#define ENDPOINT8_CONFIG ENDPOINT_RECEIVE_ONLY +#define ENDPOINT9_CONFIG ENDPOINT_TRANSIMIT_ONLY +#define ENDPOINT10_CONFIG ENDPOINT_TRANSIMIT_ONLY @@ -139,3 +193,8 @@ extern const usb_descriptor_list_t usb_descriptor_list[]; extern uint8_t *usb_bMaxPower; + +// ----- Functions ----- + +void usb_set_config_descriptor_size(); + diff --git a/Output/pjrcUSB/arm/usb_dev.c b/Output/pjrcUSB/arm/usb_dev.c index f46f10b..42b545e 100644 --- a/Output/pjrcUSB/arm/usb_dev.c +++ b/Output/pjrcUSB/arm/usb_dev.c @@ -40,6 +40,10 @@ #include "usb_dev.h" #include "usb_mem.h" +#if enableVirtualSerialPort_define == 1 +#include "usb_serial.h" +#endif + // ----- Defines ----- @@ -180,7 +184,10 @@ static uint8_t usb_dev_sleep = 0; static void endpoint0_stall() { #ifdef UART_DEBUG_UNKNOWN - print("STALL" NL ); + print("STALL : "); + printInt32( systick_millis_count - USBInit_TimeStart ); + print(" ms"); + print(NL); #endif USB0_ENDPT0 = USB_ENDPT_EPSTALL | USB_ENDPT_EPRXEN | USB_ENDPT_EPTXEN | USB_ENDPT_EPHSHK; } @@ -195,7 +202,6 @@ static void endpoint0_transmit( const void *data, uint32_t len ) void usb_reinit() { - power_neg_delay = 0; usb_configuration = 0; // Clear USB configuration if we have one USB0_CONTROL = 0; // Disable D+ Pullup to simulate disconnect delay(10); // Delay is necessary to simulate disconnect @@ -213,6 +219,18 @@ void usb_device_check() // Check if 100 ms has elapsed if ( systick_millis_count - power_neg_time > 100 ) { + power_neg_delay = 0; + + // USB Low Power Negotiation +#if enableUSBLowPowerNegotiation_define == 1 + // Check to see if bMaxPower has already be lowered + // This generally points to a USB bug (host or device?) + if ( *usb_bMaxPower == 50 ) + { + warn_msg("Power negotiation delay detected again, likely a system/device USB bug"); + return; + } + // Update bMaxPower // The value set is in increments of 2 mA // So 50 * 2 mA = 100 mA @@ -222,6 +240,9 @@ void usb_device_check() // Re-initialize USB usb_reinit(); +#else + warn_msg("USB Low Power Negotation Disabled, condition detected."); +#endif } } } @@ -237,6 +258,10 @@ static void usb_setup() const uint8_t *cfg; int i; + // Reset USB Init timer + USBInit_TimeEnd = systick_millis_count; + USBInit_Ticks++; + // If another request is made, disable the power negotiation check // See GET_DESCRIPTOR - Configuration if ( power_neg_delay ) @@ -517,22 +542,40 @@ static void usb_setup() endpoint0_stall(); return; +#if enableVirtualSerialPort_define == 1 case 0x2221: // CDC_SET_CONTROL_LINE_STATE usb_cdc_line_rtsdtr = setup.wValue; - //serial_print("set control line state\n"); + //info_print("set control line state"); goto send; case 0x21A1: // CDC_GET_LINE_CODING - data = (uint8_t*)usb_cdc_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; + // ZLP Reply + // Settings are applied in PID=OUT + goto send; +#endif case 0x0921: // HID SET_REPORT + // ZLP Reply + // Settings are applied in PID=OUT + + #ifdef UART_DEBUG + print("report_type("); + printHex( setup.wValue >> 8 ); + print(")report_id("); + printHex( setup.wValue & 0xFF ); + print(")interface("); + printHex( setup.wIndex ); + print(")len("); + printHex( setup.wLength ); + print(")"); + print( NL ); + #endif + // Interface switch ( setup.wIndex & 0xFF ) { @@ -547,7 +590,7 @@ static void usb_setup() printHex( setup.wIndex ); print( NL ); endpoint0_stall(); - break; + return; } goto send; @@ -571,9 +614,9 @@ static void usb_setup() datalen = list->length; goto send; } - } - endpoint0_stall(); - return; + } + endpoint0_stall(); + return; case 0x0A21: // HID SET_IDLE #ifdef UART_DEBUG @@ -596,6 +639,7 @@ static void usb_setup() print(NL); #endif reply_buffer[0] = USBKeys_Idle_Config; + data = reply_buffer; datalen = 1; goto send; @@ -620,13 +664,16 @@ static void usb_setup() print(NL); #endif reply_buffer[0] = USBKeys_Protocol; + data = reply_buffer; datalen = 1; goto send; // case 0xC940: default: #ifdef UART_DEBUG_UNKNOWN - print("UNKNOWN"); + print("UNKNOWN: "); + printInt32( systick_millis_count - USBInit_TimeStart ); + print(" ms"); print(NL); #endif endpoint0_stall(); @@ -655,7 +702,7 @@ send: if ( size > EP0_SIZE ) size = EP0_SIZE; - endpoint0_transmit(data, size); + endpoint0_transmit( data, size ); data += size; datalen -= size; @@ -666,7 +713,7 @@ send: size = datalen; if ( size > EP0_SIZE ) size = EP0_SIZE; - endpoint0_transmit(data, size); + endpoint0_transmit( data, size ); data += size; datalen -= size; @@ -689,9 +736,9 @@ send: //to be set to their default values. This includes setting the data toggle of //any endpoint using data toggles to the value DATA0. -//For endpoints using data toggle, regardless of whether an endpoint has the -//Halt feature set, a ClearFeature(ENDPOINT_HALT) request always results in the -//data toggle being reinitialized to DATA0. +// For endpoints using data toggle, regardless of whether an endpoint has the +// Halt feature set, a ClearFeature(ENDPOINT_HALT) request always results in the +// data toggle being reinitialized to DATA0. static void usb_control( uint32_t stat ) { @@ -714,11 +761,9 @@ static void usb_control( uint32_t stat ) print(" - "); #endif - switch (pid) + switch ( pid ) { case 0x0D: // Setup received from host - //serial_print("PID=Setup\n"); - //if (count != 8) ; // panic? // grab the 8 byte setup info setup.word1 = *(uint32_t *)(buf); setup.word2 = *(uint32_t *)(buf + 4); @@ -741,36 +786,13 @@ static void usb_control( uint32_t stat ) //} table[index(0, TX, EVEN)].desc = 0; table[index(0, TX, ODD)].desc = 0; + // first IN after Setup is always DATA1 ep0_tx_data_toggle = 1; #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(" -- "); - printHex32(setup.word1); - print(" "); - printHex32(setup.word2); - print(NL); - #endif - // actually "do" the setup request - usb_setup(); - // unfreeze the USB, now that we're ready - USB0_CTL = USB_CTL_USBENSOFEN; // clear TXSUSPENDTOKENBUSY bit - break; - - case 0x01: // OUT transaction received from host - case 0x02: - #ifdef UART_DEBUG_UNKNOWN - print("PID=OUT wRequestAndType:"); + printHex( stat ); + print(" PID=SETUP wRequestAndType:"); printHex(setup.wRequestAndType); print(", wValue:"); printHex(setup.wValue); @@ -782,43 +804,105 @@ static void usb_control( uint32_t stat ) printHex32(setup.word1); print(" "); printHex32(setup.word2); + print(": "); + printInt32( systick_millis_count - USBInit_TimeStart ); + print(" ms"); + print(NL); + #endif + + // actually "do" the setup request + usb_setup(); + // unfreeze the USB, now that we're ready + USB0_CTL = USB_CTL_USBENSOFEN; // clear TXSUSPENDTOKENBUSY bit + break; + + case 0x01: // OUT transaction received from host + case 0x02: + #ifdef UART_DEBUG_UNKNOWN + printHex( stat ); + print(" PID=OUT wRequestAndType:"); + printHex(setup.wRequestAndType); + print(", wValue:"); + printHex(setup.wValue); + print(", wIndex:"); + printHex(setup.wIndex); + print(", len:"); + printHex(setup.wLength); + print(" -- "); + printHex32(setup.word1); + print(" "); + printHex32(setup.word2); + print(": "); + printInt32( systick_millis_count - USBInit_TimeStart ); + print(" ms"); print(NL); #endif // CDC Interface - if ( setup.wRequestAndType == 0x2021 /*CDC_SET_LINE_CODING*/ ) + #if enableVirtualSerialPort_define == 1 + // CDC_SET_LINE_CODING - PID=OUT + // XXX - Getting lots of NAKs in Linux + if ( setup.wRequestAndType == 0x2021 ) { - int i; - uint8_t *dst = (uint8_t *)usb_cdc_line_coding; - //serial_print("set line coding "); - 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 ); - } + // Copy over new line coding + memcpy( (void*)&usb_cdc_line_coding, buf, 7 ); - // Keyboard SET_REPORT - if ( setup.wRequestAndType == 0x921 && setup.wValue & 0x200 ) + #ifdef UART_DEBUG + // - Unused, but for the readers info - + print("dwDTERate("); + printInt32( usb_cdc_line_coding.dwDTERate ); + print(")bCharFormat("); + printHex( usb_cdc_line_coding.bCharFormat ); + print(")bParityType("); + printHex( usb_cdc_line_coding.bParityType ); + print(")bDataBits("); + printHex( usb_cdc_line_coding.bDataBits ); + print(")"); + print( NL ); + #endif + + // XXX ZLP causes timeout/delay, why? -HaaTa + //endpoint0_transmit( NULL, 0 ); + } + #endif + + // Keyboard HID SET_REPORT - PID=OUT + #if enableKeyboard_define == 1 + // XXX - Getting lots of NAKs in Linux + if ( setup.wRequestAndType == 0x0921 && setup.wValue & 0x200 ) { + #ifdef UART_DEBUG + print("report_type("); + printHex( setup.wValue >> 8 ); + print(")report_id("); + printHex( setup.wValue & 0xFF ); + print(")interface("); + printHex( setup.wIndex ); + print(")len("); + printHex( setup.wLength ); + print(")["); + + for ( size_t len = 0; len < setup.wLength; len++ ) + { + printHex( buf[ len ] ); + print(" "); + } + print("]"); + print( NL ); + #endif + // Interface switch ( setup.wIndex & 0xFF ) { // Keyboard Interface case KEYBOARD_INTERFACE: USBKeys_LEDs = buf[0]; - endpoint0_transmit( NULL, 0 ); break; // NKRO Keyboard Interface case NKRO_KEYBOARD_INTERFACE: + // Already set with the control sequence // Only use 2nd byte, first byte is the report id USBKeys_LEDs = buf[1]; - endpoint0_transmit( NULL, 0 ); break; default: warn_msg("Unknown interface - "); @@ -827,34 +911,48 @@ static void usb_control( uint32_t stat ) break; } - #ifdef UART_DEBUG - for ( size_t len = 0; len < setup.wLength; len++ ) - { - printHex( buf[ len ] ); - print(" "); - } - print( NL ); - #endif + // XXX ZLP causes timeout/delay, why? -HaaTa + //endpoint0_transmit( NULL, 0 ); } + #endif // give the buffer back b->desc = BDT_DESC( EP0_SIZE, DATA1 ); break; case 0x09: // IN transaction completed to host - #ifdef UART_DEBUG - print("PID=IN:"); - printHex(stat); + data = ep0_tx_ptr; + + #ifdef UART_DEBUG_UNKNOWN + printHex( stat ); + print(" PID=IN wRequestAndType:"); + printHex(setup.wRequestAndType); + print(", wValue:"); + printHex(setup.wValue); + print(", wIndex:"); + printHex(setup.wIndex); + print(", len:"); + printHex(setup.wLength); + print(" -- "); + printHex32(setup.word1); + print(" "); + printHex32(setup.word2); + print(": "); + printInt32( systick_millis_count - USBInit_TimeStart ); + print(" ms"); + if ( data ) print(" DATA "); print(NL); #endif // send remaining data, if any... - data = ep0_tx_ptr; if ( data ) { size = ep0_tx_len; - if (size > EP0_SIZE) size = EP0_SIZE; - endpoint0_transmit(data, size); + if (size > EP0_SIZE) + { + size = EP0_SIZE; + } + endpoint0_transmit( data, size ); data += size; ep0_tx_len -= size; ep0_tx_ptr = (ep0_tx_len > 0 || size == EP0_SIZE) ? data : NULL; @@ -871,12 +969,34 @@ static void usb_control( uint32_t stat ) USB0_ADDR = setup.wValue; } + // CDC_SET_LINE_CODING - PID=IN + #if enableVirtualSerialPort_define == 1 + if ( setup.wRequestAndType == 0x2021 ) + { + // XXX ZLP causes timeout/delay, why? -HaaTa + //endpoint0_transmit( NULL, 0 ); + } + #endif + + // Keyboard HID SET_REPORT - PID=IN + #if enableKeyboard_define == 1 + // XXX - Getting lots of NAKs in Linux + if ( setup.wRequestAndType == 0x0921 && setup.wValue & 0x200 ) + { + // XXX ZLP causes timeout/delay, why? -HaaTa + //endpoint0_transmit( NULL, 0 ); + } + #endif + break; default: - #ifdef UART_DEBUG - print("PID=unknown:"); + #ifdef UART_DEBUG_UNKNOWN + print("PID=unknown: "); printHex(pid); + print(": "); + printInt32( systick_millis_count - USBInit_TimeStart ); + print(" ms"); print(NL); #endif break; @@ -889,14 +1009,25 @@ usb_packet_t *usb_rx( uint32_t endpoint ) //print("USB RX"); usb_packet_t *ret; endpoint--; + + // Make sure this is a valid endpoint if ( endpoint >= NUM_ENDPOINTS ) + { return NULL; + } + __disable_irq(); + + // Receive packet, check pointer ret = rx_first[endpoint]; if ( ret ) + { rx_first[ endpoint ] = ret->next; - usb_rx_byte_count_data[ endpoint ] -= ret->len; + usb_rx_byte_count_data[ endpoint ] -= ret->len; + } + __enable_irq(); + //serial_print("rx, epidx="); //serial_phex(endpoint); //serial_print(", packet="); @@ -994,17 +1125,16 @@ void usb_rx_memory( usb_packet_t *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 ) +// Call whenever there's an action that may wake the host device +void usb_resume() { - // Update expiry counter - USBKeys_Idle_Expiry = systick_millis_count; - // If we have been sleeping, try to wake up host - if ( usb_dev_sleep ) + if ( usb_dev_sleep && usb_configured() ) { + #if enableUSBResume_define == 1 + #if enableVirtualSerialPort_define != 1 + info_print("Attempting to resume the host"); + #endif // Force wake-up for 10 ms // According to the USB Spec a device must hold resume for at least 1 ms but no more than 15 ms USB0_CTL |= USB_CTL_RESUME; @@ -1012,8 +1142,18 @@ void usb_tx( uint32_t endpoint, usb_packet_t *packet ) USB0_CTL &= ~(USB_CTL_RESUME); delay(50); // Wait for at least 50 ms to make sure the bus is clear usb_dev_sleep = 0; // Make sure we don't call this again, may crash system + #else + warn_print("Host Resume Disabled"); + #endif } +} + +void usb_tx( uint32_t endpoint, usb_packet_t *packet ) +{ + // Update expiry counter + USBKeys_Idle_Expiry = systick_millis_count; + // Since we are transmitting data, USB will be brought out of sleep/suspend // if it's in that state // Use the currently set descriptor value @@ -1087,16 +1227,12 @@ void usb_isr() { uint8_t status, stat, t; - //serial_print("isr"); - //status = USB0_ISTAT; - //serial_phex(status); - //serial_print("\n"); restart: status = USB0_ISTAT; /* - print("USB ISR STATUS: "); + print(" ISR("); printHex( status ); - print( NL ); + print(") "); */ if ( (status & USB_INTEN_SOFTOKEN /* 04 */ ) ) @@ -1112,6 +1248,7 @@ restart: } // CDC Interface + #if enableVirtualSerialPort_define == 1 t = usb_cdc_transmit_flush_timer; if ( t ) { @@ -1119,6 +1256,7 @@ restart: if ( t == 0 ) usb_serial_flush_callback(); } + #endif } USB0_ISTAT = USB_INTEN_SOFTOKEN; @@ -1323,16 +1461,26 @@ restart: // The USB Module triggers this interrupt when it detects the bus has been idle for 3 ms if ( (status & USB_ISTAT_SLEEP /* 10 */ ) ) { - //info_print("Host has requested USB sleep/suspend state"); +#if enableUSBSuspend_define == 1 + // Can cause issues with the virtual serial port + #if enableVirtualSerialPort_define != 1 + info_print("Host has requested USB sleep/suspend state"); + #endif Output_update_usb_current( 100 ); // Set to 100 mA usb_dev_sleep = 1; +#else + info_print("USB Suspend Detected - Firmware USB Suspend Disabled"); +#endif USB0_ISTAT |= USB_ISTAT_SLEEP; } // On USB Resume, unset the usb_dev_sleep so we don't keep sending resume signals if ( (status & USB_ISTAT_RESUME /* 20 */ ) ) { - //info_print("Host has woken-up/resumed from sleep/suspend state"); + // Can cause issues with the virtual serial port + #if enableVirtualSerialPort_define != 1 + info_print("Host has woken-up/resumed from sleep/suspend state"); + #endif Output_update_usb_current( *usb_bMaxPower * 2 ); usb_dev_sleep = 0; USB0_ISTAT |= USB_ISTAT_RESUME; @@ -1347,6 +1495,13 @@ uint8_t usb_init() print("USB INIT"NL); #endif + USBInit_TimeStart = systick_millis_count; + USBInit_Ticks = 0; + + // XXX Set wTotalLength here instead of using defines + // Simplifies defines considerably + usb_set_config_descriptor_size(); + // 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 4593396..586340f 100644 --- a/Output/pjrcUSB/arm/usb_dev.h +++ b/Output/pjrcUSB/arm/usb_dev.h @@ -51,10 +51,6 @@ 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 ----- @@ -67,6 +63,8 @@ void usb_isr(); void usb_tx( uint32_t endpoint, usb_packet_t *packet ); void usb_tx_isr( uint32_t endpoint, usb_packet_t *packet ); +void usb_resume(); + uint32_t usb_tx_byte_count( uint32_t endpoint ); uint32_t usb_tx_packet_count( uint32_t endpoint ); diff --git a/Output/pjrcUSB/arm/usb_joystick.c b/Output/pjrcUSB/arm/usb_joystick.c index 2b5ea79..9edcccb 100644 --- a/Output/pjrcUSB/arm/usb_joystick.c +++ b/Output/pjrcUSB/arm/usb_joystick.c @@ -1,7 +1,7 @@ /* Teensyduino Core Library * http://www.pjrc.com/teensy/ * Copyright (c) 2013 PJRC.COM, LLC. - * Modified by Jacob Alexander (2015) + * Modified by Jacob Alexander (2015-2016) * * 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. */ +#if enableJoystick_define == 1 + // ----- Includes ----- // Compiler Includes @@ -112,3 +114,5 @@ int usb_joystick_send() return 0; } +#endif + diff --git a/Output/pjrcUSB/arm/usb_keyboard.c b/Output/pjrcUSB/arm/usb_keyboard.c index ec4aae6..233cc31 100644 --- a/Output/pjrcUSB/arm/usb_keyboard.c +++ b/Output/pjrcUSB/arm/usb_keyboard.c @@ -1,7 +1,7 @@ /* Teensyduino Core Library * http://www.pjrc.com/teensy/ * Copyright (c) 2013 PJRC.COM, LLC. - * Modifications by Jacob Alexander 2013-2015 + * Modifications by Jacob Alexander 2013-2016 * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -29,6 +29,9 @@ * SOFTWARE. */ +#include +#if enableKeyboard_define == 1 + // ----- Includes ----- // Compiler Includes @@ -123,14 +126,25 @@ void usb_keyboard_send() } } + // USB Timeout, drop the packet, and potentially try something more drastic to re-enable the bus if ( ++wait_count > TX_TIMEOUT || transmit_previous_timeout ) { transmit_previous_timeout = 1; - warn_print("USB Transmit Timeout...restarting device"); USBKeys_Changed = USBKeyChangeState_None; // Indicate packet lost + #if enableDeviceRestartOnUSBTimeout == 1 + warn_print("USB Transmit Timeout...restarting device"); usb_device_software_reset(); + #else + warn_print("USB Transmit Timeout...auto-restart disabled"); + #endif + // Try to wakeup return; } + + // Try to wake up the device if we can't allocate a packet for some reason + // XXX This is a bit aggressive, but seems to work well. Unfortunately, not as quick as I'd like it -HaaTa + usb_resume(); + yield(); } @@ -277,3 +291,5 @@ void usb_keyboard_send() return; } +#endif + diff --git a/Output/pjrcUSB/arm/usb_mouse.c b/Output/pjrcUSB/arm/usb_mouse.c index c72eed5..d1f9a1b 100644 --- a/Output/pjrcUSB/arm/usb_mouse.c +++ b/Output/pjrcUSB/arm/usb_mouse.c @@ -29,6 +29,9 @@ * SOFTWARE. */ +#include +#if enableMouse_define == 1 + // ----- Includes ----- // Compiler Includes @@ -300,3 +303,5 @@ void usb_mouse_screen_size(uint16_t width, uint16_t height, uint8_t mac) } } +#endif + diff --git a/Output/pjrcUSB/arm/usb_rawio.c b/Output/pjrcUSB/arm/usb_rawio.c new file mode 100644 index 0000000..bb9a183 --- /dev/null +++ b/Output/pjrcUSB/arm/usb_rawio.c @@ -0,0 +1,141 @@ +/* Copyright (C) 2016 by Jacob Alexander + * + * 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. + */ + +#include +#if enableRawIO_define == 1 + +// ----- Includes ----- + +// Compiler Includes +#include // For memcpy + +// Project Includes +#include +#include + +// Local Includes +#include "usb_dev.h" +#include "usb_rawio.h" + + + +// ----- Defines ----- + +// Maximum number of transmit packets to queue so we don't starve other endpoints for memory +#define TX_PACKET_LIMIT 5 + + + +// ----- Functions ----- + +// Check for packets available from host +uint32_t usb_rawio_available() +{ + // Error if USB isn't configured + if ( !usb_configuration ) + return 0; + + // Query number of bytes available from the endpoint + return usb_rx_byte_count( RAWIO_RX_ENDPOINT ); +} + +// Retrieve packets from host +// Always returns RAWIO_RX_SIZE +int32_t usb_rawio_rx( void *buf, uint32_t timeout ) +{ + usb_packet_t *rx_packet; + uint32_t begin = millis(); + + // Read + while ( 1 ) + { + // Error if USB isn't configured + if ( !usb_configuration ) + return -1; + + // Retrieve packet + rx_packet = usb_rx( RAWIO_RX_ENDPOINT ); + if ( rx_packet ) + break; + + // Check for timeout + if ( millis() - begin > timeout || !timeout ) + { + warn_msg("RAWIO Rx - Timeout, dropping packet."); + return 0; + } + + yield(); + } + + // Transfer packet from USB buffer to given buffer + memcpy( buf, rx_packet->buf, RAWIO_RX_SIZE ); + usb_free( rx_packet ); + + // Data sent in full packet chunks + return RAWIO_RX_SIZE; +} + +// Send packet to host +// XXX Only transfers RAWIO_TX_SIZE on each call (likely 64 bytes) +// Always returns RAWIO_TX_SIZE +int32_t usb_rawio_tx( const void *buf, uint32_t timeout ) +{ + usb_packet_t *tx_packet; + uint32_t begin = millis(); + + while ( 1 ) + { + // Error if USB isn't configured + if ( !usb_configuration ) + return -1; + + // Make sure we haven't exceeded the outgoing packet limit + if ( usb_tx_packet_count( RAWIO_TX_ENDPOINT ) < TX_PACKET_LIMIT ) + { + // Allocate a packet buffer + tx_packet = usb_malloc(); + if ( tx_packet ) + break; + } + + // Check for timeout + if ( millis() - begin > timeout ) + { + warn_msg("RAWIO Tx - Timeout, dropping packet."); + return 0; + } + + yield(); + } + + // Copy input buffer to usb packet buffer and assign length + memcpy( tx_packet->buf, buf, RAWIO_TX_SIZE ); + tx_packet->len = RAWIO_TX_SIZE; + + // Send USB packet + usb_tx( RAWIO_TX_ENDPOINT, tx_packet ); + + return RAWIO_TX_SIZE; +} + +#endif + diff --git a/Output/pjrcUSB/arm/usb_rawio.h b/Output/pjrcUSB/arm/usb_rawio.h new file mode 100644 index 0000000..c63ac87 --- /dev/null +++ b/Output/pjrcUSB/arm/usb_rawio.h @@ -0,0 +1,35 @@ +/* Copyright (C) 2016 by Jacob Alexander + * + * 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. + */ + +#pragma once + +// ----- Includes ----- + +#include "usb_desc.h" + + + +// ----- Functions ----- + +uint32_t usb_rawio_available(); +int32_t usb_rawio_rx( void *buf, uint32_t timeout ); +int32_t usb_rawio_tx( const void *buf, uint32_t timeout ); + diff --git a/Output/pjrcUSB/arm/usb_serial.c b/Output/pjrcUSB/arm/usb_serial.c index 4510d40..cf20797 100644 --- a/Output/pjrcUSB/arm/usb_serial.c +++ b/Output/pjrcUSB/arm/usb_serial.c @@ -1,7 +1,7 @@ /* Teensyduino Core Library * http://www.pjrc.com/teensy/ * Copyright (c) 2013 PJRC.COM, LLC. - * Modified by Jacob Alexander 2013-2015 + * Modified by Jacob Alexander 2013-2016 * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -29,6 +29,9 @@ * SOFTWARE. */ +#include +#if enableVirtualSerialPort_define == 1 + // ----- Includes ----- // Compiler Includes @@ -69,9 +72,15 @@ // ----- 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 }; +// Serial port settings (baud rate, control signals, etc) set by the host +// These are *ignored*, except to return back to the host if requested +volatile USBCDCLineCoding usb_cdc_line_coding = { + 115200, + 0, + 0, + 8, +}; + volatile uint8_t usb_cdc_line_rtsdtr = 0; volatile uint8_t usb_cdc_transmit_flush_timer = 0; @@ -315,3 +324,5 @@ void usb_serial_flush_callback() } } +#endif + diff --git a/Output/pjrcUSB/arm/usb_serial.h b/Output/pjrcUSB/arm/usb_serial.h index 09980d3..9d223da 100644 --- a/Output/pjrcUSB/arm/usb_serial.h +++ b/Output/pjrcUSB/arm/usb_serial.h @@ -1,7 +1,7 @@ /* Teensyduino Core Library * http://www.pjrc.com/teensy/ * Copyright (c) 2013 PJRC.COM, LLC. - * Modifications by Jacob Alexander (2013-2015) + * Modifications by Jacob Alexander (2013-2016) * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -50,9 +50,36 @@ +// ----- Structs ----- + +// See: Universal Serial Bus Class Definitions for Communication Devices 1.11 Table 50 +// dwDTERate - Baud Rate : 4 bytes +// bCharFormat - Stop Bits : 1 byte +// 0: 1 stop bit +// 1: 1.5 stop bits +// 2: 2 stop bits +// bParityType - Parity : 1 byte +// 0: None +// 1: Odd +// 2: Even +// 3: Mark +// 4: Space +// bDataBits - Data Bits : 1 byte +// (5,6,7,8 or 16) +// +// Struct is 7 bytes wide +typedef struct USBCDCLineCoding { + uint32_t dwDTERate; // Baud Rate + uint8_t bCharFormat; // Stop Bits + uint8_t bParityType; // Parity + uint8_t bDataBits; // Data Bits +} USBCDCLineCoding; + + + // ----- Variables ----- -extern volatile uint8_t usb_cdc_line_coding[7]; +extern volatile USBCDCLineCoding usb_cdc_line_coding; extern volatile uint8_t usb_cdc_line_rtsdtr; extern volatile uint8_t usb_cdc_transmit_flush_timer; diff --git a/Output/pjrcUSB/capabilities.kll b/Output/pjrcUSB/capabilities.kll index 94a6c20..ce3504d 100644 --- a/Output/pjrcUSB/capabilities.kll +++ b/Output/pjrcUSB/capabilities.kll @@ -4,7 +4,7 @@ Author = "HaaTa (Jacob Alexander) 2014-2016"; KLL = 0.3d; # Modified Date -Date = 2016-03-21; +Date = 2016-05-31; # Output capabilities @@ -38,3 +38,64 @@ flashModeEnabled = 0; flashMode => Output_flashMode_capability(); + +## USB Compatibility Flags ## +# Some OSs and USB Chipsets have issues with USB features +# These flags are available to provide ways to debug them + +# Enable USB Suspend/Low Power mode +# After a period of inactivity, the USB host may request that the device go into low power mode +# This is different than system sleep, though it may occur around the same time +enableUSBSuspend => enableUSBSuspend_define; +enableUSBSuspend = 1; + +# Enable Low-power Negotiation +# In order to support low-powered USB hosts, such as an Apple IPad, a low power auto-negotiation scheme has been implemented +# Unfortunately, badly behaved USB Chipsets and OSs may not work correctly with this support enabled +# Typical symptoms: +# * USB constantly re-initializing when first plugging in +enableUSBLowPowerNegotiation => enableUSBLowPowerNegotiation_define; +enableUSBLowPowerNegotiation = 0; + +# Enable Device Restart on USB Timeout +# *USE AS LAST RETORT* +# To work around some USB OS, Chipset and Firwmare bugs, an auto-restart mechanism has been implemented +# Depending on the situation, this can be rather aggressive. +# This behaves differently than the Low-power negotiation restart and have very different triggering schemes. +enableDeviceRestartOnUSBTimeout => enableDeviceRestartOnUSBTimeout_define; +enableDeviceRestartOnUSBTimeout = 0; + +# Enable Host-Resume (wake-from-sleep) +# On specific actions (such as USB key actions), will trigger the host device to wake if USB is suspended +enableUSBResume => enableUSBResume_define; +enableUSBResume = 1; + +## USB Endpoint Configuration ## +# 1 - Enable endpoint +# 0 - Disable endpoint +# Any/all endpoints can be disabled +# But you'll lose functionality for that feature +# Disabling endpoints will save RAM and Flash on the target MCU + +# Joystick Endpoint +# *Currently Unused* +enableJoystick => enableJoystick_define; +enableJoystick = 0; + +# Mouse Endpoint +enableMouse => enableMouse_define; +enableMouse = 1; + +# Keyboard Endpoint +enableKeyboard => enableKeyboard_define; +enableKeyboard = 1; + +# CDC / Serial Port Endpoint +enableVirtualSerialPort => enableVirtualSerialPort_define; +enableVirtualSerialPort = 1; + +# Raw I/O Endpoint +# *Currently Unused* +enableRawIO => enableRawIO_define; +enableRawIO = 0; + diff --git a/Output/pjrcUSB/output_com.c b/Output/pjrcUSB/output_com.c index b156e1f..e7ba5eb 100644 --- a/Output/pjrcUSB/output_com.c +++ b/Output/pjrcUSB/output_com.c @@ -71,6 +71,7 @@ void cliFunc_readLEDs ( char* args ); void cliFunc_sendKeys ( char* args ); void cliFunc_setKeys ( char* args ); void cliFunc_setMod ( char* args ); +void cliFunc_usbInitTime( char* args ); @@ -83,6 +84,7 @@ CLIDict_Entry( readLEDs, "Read LED byte:" NL "\t\t1 NumLck, 2 CapsLck, 4 Scrl CLIDict_Entry( sendKeys, "Send the prepared list of USB codes and modifier byte." ); CLIDict_Entry( setKeys, "Prepare a space separated list of USB codes (decimal). Waits until \033[35msendKeys\033[0m." ); CLIDict_Entry( setMod, "Set the modfier byte:" NL "\t\t1 LCtrl, 2 LShft, 4 LAlt, 8 LGUI, 16 RCtrl, 32 RShft, 64 RAlt, 128 RGUI" ); +CLIDict_Entry( usbInitTime, "Displays the time in ms from usb_init() till the last setup call." ); CLIDict_Def( outputCLIDict, "USB Module Commands" ) = { CLIDict_Item( kbdProtocol ), @@ -91,6 +93,7 @@ CLIDict_Def( outputCLIDict, "USB Module Commands" ) = { CLIDict_Item( sendKeys ), CLIDict_Item( setKeys ), CLIDict_Item( setMod ), + CLIDict_Item( usbInitTime ), { 0, 0, 0 } // Null entry for dictionary end }; @@ -162,6 +165,11 @@ uint16_t Output_ExtCurrent_Available = 0; // Initially 100 mA, but may be negotiated higher (e.g. 500 mA) uint16_t Output_USBCurrent_Available = 0; +// USB Init Time (ms) - usb_init() +volatile uint32_t USBInit_TimeStart; +volatile uint32_t USBInit_TimeEnd; +volatile uint16_t USBInit_Ticks; + // ----- Capabilities ----- @@ -169,6 +177,7 @@ uint16_t Output_USBCurrent_Available = 0; // Set Boot Keyboard Protocol void Output_kbdProtocolBoot_capability( uint8_t state, uint8_t stateType, uint8_t *args ) { +#if enableKeyboard_define == 1 // Display capability name if ( stateType == 0xFF && state == 0xFF ) { @@ -190,12 +199,14 @@ void Output_kbdProtocolBoot_capability( uint8_t state, uint8_t stateType, uint8_ // Set the keyboard protocol to Boot Mode USBKeys_Protocol = 0; +#endif } // Set NKRO Keyboard Protocol void Output_kbdProtocolNKRO_capability( uint8_t state, uint8_t stateType, uint8_t *args ) { +#if enableKeyboard_define == 1 // Display capability name if ( stateType == 0xFF && state == 0xFF ) { @@ -217,12 +228,14 @@ void Output_kbdProtocolNKRO_capability( uint8_t state, uint8_t stateType, uint8_ // Set the keyboard protocol to NKRO Mode USBKeys_Protocol = 1; +#endif } // Toggle Keyboard Protocol void Output_toggleKbdProtocol_capability( uint8_t state, uint8_t stateType, uint8_t *args ) { +#if enableKeyboard_define == 1 // Display capability name if ( stateType == 0xFF && state == 0xFF ) { @@ -239,12 +252,14 @@ void Output_toggleKbdProtocol_capability( uint8_t state, uint8_t stateType, uint // Toggle the keyboard protocol Mode USBKeys_Protocol = !USBKeys_Protocol; } +#endif } // Sends a Consumer Control code to the USB Output buffer void Output_consCtrlSend_capability( uint8_t state, uint8_t stateType, uint8_t *args ) { +#if enableKeyboard_define == 1 // Display capability name if ( stateType == 0xFF && state == 0xFF ) { @@ -273,6 +288,7 @@ void Output_consCtrlSend_capability( uint8_t state, uint8_t stateType, uint8_t * // Set consumer control code USBKeys_ConsCtrl = *(uint16_t*)(&args[0]); +#endif } @@ -294,6 +310,7 @@ void Output_noneSend_capability( uint8_t state, uint8_t stateType, uint8_t *args // Sends a System Control code to the USB Output buffer void Output_sysCtrlSend_capability( uint8_t state, uint8_t stateType, uint8_t *args ) { +#if enableKeyboard_define == 1 // Display capability name if ( stateType == 0xFF && state == 0xFF ) { @@ -322,6 +339,7 @@ void Output_sysCtrlSend_capability( uint8_t state, uint8_t stateType, uint8_t *a // Set system control code USBKeys_SysCtrl = args[0]; +#endif } @@ -329,6 +347,7 @@ void Output_sysCtrlSend_capability( uint8_t state, uint8_t stateType, uint8_t *a // Argument #1: USB Code void Output_usbCodeSend_capability( uint8_t state, uint8_t stateType, uint8_t *args ) { +#if enableKeyboard_define == 1 // Display capability name if ( stateType == 0xFF && state == 0xFF ) { @@ -529,6 +548,7 @@ void Output_usbCodeSend_capability( uint8_t state, uint8_t stateType, uint8_t *a break; } +#endif } void Output_flashMode_capability( uint8_t state, uint8_t stateType, uint8_t *args ) @@ -544,6 +564,7 @@ void Output_flashMode_capability( uint8_t state, uint8_t stateType, uint8_t *arg Output_firmwareReload(); } +#if enableMouse_define == 1 // Sends a mouse command over the USB Output buffer // XXX This function *will* be changing in the future // If you use it, be prepared that your .kll files will break in the future (post KLL 0.5) @@ -600,6 +621,7 @@ void Output_usbMouse_capability( uint8_t state, uint8_t stateType, uint8_t *args if ( mouse_x || mouse_y ) USBMouse_Changed |= USBMouseChangeState_Relative; } +#endif @@ -643,11 +665,6 @@ inline void Output_send() // Non-standard USB state manipulation, usually does nothing usb_device_check(); - // Boot Mode Only, unset stale keys - if ( USBKeys_Protocol == 0 ) - for ( uint8_t c = USBKeys_Sent; c < USB_BOOT_MAX_KEYS; c++ ) - USBKeys_Keys[c] = 0; - // XXX - Behaves oddly on Mac OSX, might help with corrupted packets specific to OSX? -HaaTa /* // Check if idle count has been exceed, this forces usb_keyboard_send and usb_mouse_send to update @@ -661,9 +678,17 @@ inline void Output_send() } */ +#if enableMouse_define == 1 // Process mouse actions while ( USBMouse_Changed ) usb_mouse_send(); +#endif + +#if enableKeyboard_define == 1 + // Boot Mode Only, unset stale keys + if ( USBKeys_Protocol == 0 ) + for ( uint8_t c = USBKeys_Sent; c < USB_BOOT_MAX_KEYS; c++ ) + USBKeys_Keys[c] = 0; // Send keypresses while there are pending changes while ( USBKeys_Changed ) @@ -684,6 +709,7 @@ inline void Output_send() Scan_finishedWithOutput( USBKeys_Sent ); break; } +#endif } @@ -697,28 +723,41 @@ inline void Output_firmwareReload() // USB Input buffer available inline unsigned int Output_availablechar() { +#if enableVirtualSerialPort_define == 1 return usb_serial_available(); +#else + return 0; +#endif } // USB Get Character from input buffer inline int Output_getchar() { +#if enableVirtualSerialPort_define == 1 // XXX Make sure to check output_availablechar() first! Information is lost with the cast (error codes) (AVR) return (int)usb_serial_getchar(); +#else + return 0; +#endif } // USB Send Character to output buffer inline int Output_putchar( char c ) { +#if enableVirtualSerialPort_define == 1 return usb_serial_putchar( c ); +#else + return 0; +#endif } // USB Send String to output buffer, null terminated inline int Output_putstr( char* str ) { +#if enableVirtualSerialPort_define == 1 #if defined(_at90usb162_) || defined(_atmega32u4_) || defined(_at90usb646_) || defined(_at90usb1286_) // AVR uint16_t count = 0; #elif defined(_mk20dx128_) || defined(_mk20dx128vlf5_) || defined(_mk20dx256_) || defined(_mk20dx256vlh7_) // ARM @@ -729,6 +768,9 @@ inline int Output_putstr( char* str ) count++; return usb_serial_write( str, count ); +#else + return 0; +#endif } @@ -739,6 +781,43 @@ inline void Output_softReset() } +// USB RawIO buffer available +inline unsigned int Output_rawio_availablechar() +{ +#if enableRawIO_define == 1 + return usb_rawio_available(); +#else + return 0; +#endif +} + + +// USB RawIO get buffer +// XXX Must be a 64 byte buffer +inline int Output_rawio_getbuffer( char* buffer ) +{ +#if enableRawIO_define == 1 + // No timeout, fail immediately + return usb_rawio_rx( (void*)buffer, 0 ); +#else + return 0; +#endif +} + + +// USB RawIO send buffer +// XXX Must be a 64 byte buffer +inline int Output_rawio_sendbuffer( char* buffer ) +{ +#if enableRawIO_define == 1 + // No timeout, fail immediately + return usb_rawio_tx( (void*)buffer, 0 ); +#else + return 0; +#endif +} + + // Update USB current (mA) // Triggers power change event void Output_update_usb_current( unsigned int current ) @@ -892,3 +971,15 @@ void cliFunc_setMod( char* args ) USBKeys_ModifiersCLI = numToInt( arg1Ptr ); } +void cliFunc_usbInitTime( char* args ) +{ + // Calculate overall USB initialization time + // XXX A protocol analyzer will be more accurate, however, this is built-in and easier to collect data + print(NL); + info_msg("USB Init Time: "); + printInt32( USBInit_TimeEnd - USBInit_TimeStart ); + print(" ms - "); + printInt16( USBInit_Ticks ); + print(" ticks"); +} + diff --git a/Output/pjrcUSB/output_com.h b/Output/pjrcUSB/output_com.h index 7008943..1dc0ac2 100644 --- a/Output/pjrcUSB/output_com.h +++ b/Output/pjrcUSB/output_com.h @@ -99,6 +99,10 @@ extern uint8_t Output_DebugMode; // 0 - Debug disabled, 1 - Debug enab extern uint16_t Output_ExtCurrent_Available; // mA - Set by outside module if not using USB (i.e. Interconnect) +extern volatile uint32_t USBInit_TimeStart; // Timetamp when usb_init was triggered +extern volatile uint32_t USBInit_TimeEnd; // Timetamp since last call to the Configuration endpoint +extern volatile uint16_t USBInit_Ticks; // Number of times the end time has been updated + // ----- Functions ----- diff --git a/Output/pjrcUSB/setup.cmake b/Output/pjrcUSB/setup.cmake index 7e7a874..ded1c3f 100644 --- a/Output/pjrcUSB/setup.cmake +++ b/Output/pjrcUSB/setup.cmake @@ -1,6 +1,6 @@ ###| CMake Kiibohd Controller USB Module |### # -# Written by Jacob Alexander in 2011-2015 for the Kiibohd Controller +# Written by Jacob Alexander in 2011-2016 for the Kiibohd Controller # # Released into the Public Domain # @@ -30,6 +30,7 @@ elseif ( ${COMPILER_FAMILY} MATCHES "arm" ) arm/usb_keyboard.c arm/usb_mem.c arm/usb_mouse.c + arm/usb_rawio.c arm/usb_serial.c ) diff --git a/Output/usbMuxUart/output_com.c b/Output/usbMuxUart/output_com.c index 9de4212..a4243f8 100644 --- a/Output/usbMuxUart/output_com.c +++ b/Output/usbMuxUart/output_com.c @@ -51,14 +51,15 @@ // ----- Macros ----- // Used to build a bitmap lookup table from a byte addressable array -#define byteLookup( byte ) case (( byte ) * ( 8 )): bytePosition = byte; byteShift = 0; break; \ - case (( byte ) * ( 8 ) + ( 1 )): bytePosition = byte; byteShift = 1; break; \ - case (( byte ) * ( 8 ) + ( 2 )): bytePosition = byte; byteShift = 2; break; \ - case (( byte ) * ( 8 ) + ( 3 )): bytePosition = byte; byteShift = 3; break; \ - case (( byte ) * ( 8 ) + ( 4 )): bytePosition = byte; byteShift = 4; break; \ - case (( byte ) * ( 8 ) + ( 5 )): bytePosition = byte; byteShift = 5; break; \ - case (( byte ) * ( 8 ) + ( 6 )): bytePosition = byte; byteShift = 6; break; \ - case (( byte ) * ( 8 ) + ( 7 )): bytePosition = byte; byteShift = 7; break +#define byteLookup( byte ) \ + case (( byte ) * ( 8 )): bytePosition = byte; byteShift = 0; break; \ + case (( byte ) * ( 8 ) + ( 1 )): bytePosition = byte; byteShift = 1; break; \ + case (( byte ) * ( 8 ) + ( 2 )): bytePosition = byte; byteShift = 2; break; \ + case (( byte ) * ( 8 ) + ( 3 )): bytePosition = byte; byteShift = 3; break; \ + case (( byte ) * ( 8 ) + ( 4 )): bytePosition = byte; byteShift = 4; break; \ + case (( byte ) * ( 8 ) + ( 5 )): bytePosition = byte; byteShift = 5; break; \ + case (( byte ) * ( 8 ) + ( 6 )): bytePosition = byte; byteShift = 6; break; \ + case (( byte ) * ( 8 ) + ( 7 )): bytePosition = byte; byteShift = 7; break @@ -72,6 +73,7 @@ void cliFunc_sendKeys ( char* args ); void cliFunc_sendUART ( char* args ); void cliFunc_setKeys ( char* args ); void cliFunc_setMod ( char* args ); +void cliFunc_usbInitTime( char* args ); @@ -86,6 +88,7 @@ CLIDict_Entry( sendKeys, "Send the prepared list of USB codes and modifier by CLIDict_Entry( sendUART, "Send characters over UART0." ); CLIDict_Entry( setKeys, "Prepare a space separated list of USB codes (decimal). Waits until \033[35msendKeys\033[0m." ); CLIDict_Entry( setMod, "Set the modfier byte:" NL "\t\t1 LCtrl, 2 LShft, 4 LAlt, 8 LGUI, 16 RCtrl, 32 RShft, 64 RAlt, 128 RGUI" ); +CLIDict_Entry( usbInitTime, "Displays the time in ms from usb_init() till the last setup call." ); CLIDict_Def( outputCLIDict, "USB Module Commands" ) = { CLIDict_Item( kbdProtocol ), @@ -96,6 +99,7 @@ CLIDict_Def( outputCLIDict, "USB Module Commands" ) = { CLIDict_Item( sendUART ), CLIDict_Item( setKeys ), CLIDict_Item( setMod ), + CLIDict_Item( usbInitTime ), { 0, 0, 0 } // Null entry for dictionary end }; @@ -167,6 +171,11 @@ uint16_t Output_ExtCurrent_Available = 0; // Initially 100 mA, but may be negotiated higher (e.g. 500 mA) uint16_t Output_USBCurrent_Available = 0; +// USB Init Time (ms) +volatile uint32_t USBInit_TimeStart; +volatile uint32_t USBInit_TimeEnd; +volatile uint16_t USBInit_Ticks; + // ----- Capabilities ----- @@ -174,6 +183,7 @@ uint16_t Output_USBCurrent_Available = 0; // Set Boot Keyboard Protocol void Output_kbdProtocolBoot_capability( uint8_t state, uint8_t stateType, uint8_t *args ) { +#if enableKeyboard_define == 1 // Display capability name if ( stateType == 0xFF && state == 0xFF ) { @@ -195,12 +205,14 @@ void Output_kbdProtocolBoot_capability( uint8_t state, uint8_t stateType, uint8_ // Set the keyboard protocol to Boot Mode USBKeys_Protocol = 0; +#endif } // Set NKRO Keyboard Protocol void Output_kbdProtocolNKRO_capability( uint8_t state, uint8_t stateType, uint8_t *args ) { +#if enableKeyboard_define == 1 // Display capability name if ( stateType == 0xFF && state == 0xFF ) { @@ -222,12 +234,14 @@ void Output_kbdProtocolNKRO_capability( uint8_t state, uint8_t stateType, uint8_ // Set the keyboard protocol to NKRO Mode USBKeys_Protocol = 1; +#endif } // Toggle Keyboard Protocol void Output_toggleKbdProtocol_capability( uint8_t state, uint8_t stateType, uint8_t *args ) { +#if enableKeyboard_define == 1 // Display capability name if ( stateType == 0xFF && state == 0xFF ) { @@ -244,12 +258,14 @@ void Output_toggleKbdProtocol_capability( uint8_t state, uint8_t stateType, uint // Toggle the keyboard protocol Mode USBKeys_Protocol = !USBKeys_Protocol; } +#endif } // Sends a Consumer Control code to the USB Output buffer void Output_consCtrlSend_capability( uint8_t state, uint8_t stateType, uint8_t *args ) { +#if enableKeyboard_define == 1 // Display capability name if ( stateType == 0xFF && state == 0xFF ) { @@ -278,6 +294,7 @@ void Output_consCtrlSend_capability( uint8_t state, uint8_t stateType, uint8_t * // Set consumer control code USBKeys_ConsCtrl = *(uint16_t*)(&args[0]); +#endif } @@ -299,6 +316,7 @@ void Output_noneSend_capability( uint8_t state, uint8_t stateType, uint8_t *args // Sends a System Control code to the USB Output buffer void Output_sysCtrlSend_capability( uint8_t state, uint8_t stateType, uint8_t *args ) { +#if enableKeyboard_define == 1 // Display capability name if ( stateType == 0xFF && state == 0xFF ) { @@ -327,6 +345,7 @@ void Output_sysCtrlSend_capability( uint8_t state, uint8_t stateType, uint8_t *a // Set system control code USBKeys_SysCtrl = args[0]; +#endif } @@ -334,6 +353,7 @@ void Output_sysCtrlSend_capability( uint8_t state, uint8_t stateType, uint8_t *a // Argument #1: USB Code void Output_usbCodeSend_capability( uint8_t state, uint8_t stateType, uint8_t *args ) { +#if enableKeyboard_define == 1 // Display capability name if ( stateType == 0xFF && state == 0xFF ) { @@ -534,6 +554,7 @@ void Output_usbCodeSend_capability( uint8_t state, uint8_t stateType, uint8_t *a break; } +#endif } void Output_flashMode_capability( uint8_t state, uint8_t stateType, uint8_t *args ) @@ -557,6 +578,7 @@ void Output_flashMode_capability( uint8_t state, uint8_t stateType, uint8_t *arg // Argument #3: USB Y Axis (16 bit) relative void Output_usbMouse_capability( uint8_t state, uint8_t stateType, uint8_t *args ) { +#if enableMouse_define == 1 // Display capability name if ( stateType == 0xFF && state == 0xFF ) { @@ -604,6 +626,7 @@ void Output_usbMouse_capability( uint8_t state, uint8_t stateType, uint8_t *args if ( mouse_x || mouse_y ) USBMouse_Changed |= USBMouseChangeState_Relative; +#endif } @@ -652,10 +675,6 @@ inline void Output_send() usb_device_check(); // Boot Mode Only, unset stale keys - if ( USBKeys_Protocol == 0 ) - for ( uint8_t c = USBKeys_Sent; c < USB_BOOT_MAX_KEYS; c++ ) - USBKeys_Keys[c] = 0; - // XXX - Behaves oddly on Mac OSX, might help with corrupted packets specific to OSX? -HaaTa /* // Check if idle count has been exceed, this forces usb_keyboard_send and usb_mouse_send to update @@ -669,9 +688,16 @@ inline void Output_send() } */ +#if enableMouse_define == 1 // Process mouse actions while ( USBMouse_Changed ) usb_mouse_send(); +#endif + +#if enableKeyboard_define == 1 + if ( USBKeys_Protocol == 0 ) + for ( uint8_t c = USBKeys_Sent; c < USB_BOOT_MAX_KEYS; c++ ) + USBKeys_Keys[c] = 0; // Send keypresses while there are pending changes while ( USBKeys_Changed ) @@ -692,6 +718,7 @@ inline void Output_send() Scan_finishedWithOutput( USBKeys_Sent ); break; } +#endif } @@ -705,18 +732,24 @@ void Output_firmwareReload() // USB Input buffer available inline unsigned int Output_availablechar() { +#if enableVirtualSerialPort_define == 1 return usb_serial_available() + uart_serial_available(); +#else + return uart_serial_available(); +#endif } // USB Get Character from input buffer inline int Output_getchar() { +#if enableVirtualSerialPort_define == 1 // XXX Make sure to check output_availablechar() first! Information is lost with the cast (error codes) (AVR) if ( usb_serial_available() > 0 ) { return (int)usb_serial_getchar(); } +#endif if ( uart_serial_available() > 0 ) { @@ -730,11 +763,15 @@ inline int Output_getchar() // USB Send Character to output buffer inline int Output_putchar( char c ) { +#if enableVirtualSerialPort_define == 1 // First send to UART uart_serial_putchar( c ); // Then send to USB return usb_serial_putchar( c ); +#else + return uart_serial_putchar( c ); +#endif } @@ -750,11 +787,15 @@ inline int Output_putstr( char* str ) while ( str[count] != '\0' ) count++; +#if enableVirtualSerialPort_define == 1 // First send to UART uart_serial_write( str, count ); // Then send to USB return usb_serial_write( str, count ); +#else + return uart_serial_write( str, count ); +#endif } @@ -938,3 +979,15 @@ void cliFunc_setMod( char* args ) USBKeys_ModifiersCLI = numToInt( arg1Ptr ); } +void cliFunc_usbInitTime( char* args ) +{ + // Calculate overall USB initialization time + // XXX A protocol analyzer will be more accurate, however, this is built-in and easier to collect data + print(NL); + info_msg("USB Init Time: "); + printInt32( USBInit_TimeEnd - USBInit_TimeStart ); + print(" ms - "); + printInt16( USBInit_Ticks ); + print(" ticks"); +} +