]> git.donarmstrong.com Git - kiibohd-controller.git/commitdiff
Major USB update, fixes most (if not all) known issues
authorJacob Alexander <haata@kiibohd.com>
Tue, 31 May 2016 07:19:45 +0000 (00:19 -0700)
committerJacob Alexander <haata@kiibohd.com>
Tue, 31 May 2016 07:40:10 +0000 (00:40 -0700)
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

18 files changed:
Debug/print/print.c
LoadFile/load.dfu
Output/pjrcUSB/arm/usb_desc.c
Output/pjrcUSB/arm/usb_desc.h
Output/pjrcUSB/arm/usb_dev.c
Output/pjrcUSB/arm/usb_dev.h
Output/pjrcUSB/arm/usb_joystick.c
Output/pjrcUSB/arm/usb_keyboard.c
Output/pjrcUSB/arm/usb_mouse.c
Output/pjrcUSB/arm/usb_rawio.c [new file with mode: 0644]
Output/pjrcUSB/arm/usb_rawio.h [new file with mode: 0644]
Output/pjrcUSB/arm/usb_serial.c
Output/pjrcUSB/arm/usb_serial.h
Output/pjrcUSB/capabilities.kll
Output/pjrcUSB/output_com.c
Output/pjrcUSB/output_com.h
Output/pjrcUSB/setup.cmake
Output/usbMuxUart/output_com.c

index c93ec5082a4c9ad566d33f183d2b85862ef1e9a9..4d4aa402f917d9eb7b7fe321b8b1d78b1aed9502 100644 (file)
@@ -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;
index 5c7719c2c12c7f7c0fcd16c169229c578d3b7349..8f2c7e323ebe641aae957112c5e70a752f07b41a 100755 (executable)
@@ -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"
index b0be2a0c6aa8e5cd5fab6e1fbe773d68e52eda73..56fd4822ac925581ee7f19fbc2f0c9c192f03643 100644 (file)
@@ -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)},
 
+       {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_OFFSET, 9},
+       {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_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},
+       {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_OFFSET, 9},
-
-#define iInterfaceString(num, var) \
-       {0x0300 + 4 + num, 0x409, (const uint8_t *)&var, 0 }
+       {0x2100, SYS_CTRL_INTERFACE, config_descriptor + SYS_CTRL_DESC_BASE_OFFSET, 9},
 
-       {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},
        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 -----
index 0e769a18d32af2872bbbb00b1a1706055a758aea..adbc949bec9a72c18c12377d7df56fd7a52a5d05 100644 (file)
 #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
 #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();
+
index f46f10b2b92316f213cdec3f450f394b266378e7..42b545eff7c07ad957c275ebf2fadb77f0062237 100644 (file)
 #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,14 +786,14 @@ 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);
+               printHex( stat );
+               print(" PID=SETUP wRequestAndType:");
+               printHex(setup.wRequestAndType);
                print(", wValue:");
                printHex(setup.wValue);
                print(", wIndex:");
@@ -759,8 +804,12 @@ 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
@@ -770,7 +819,8 @@ static void usb_control( uint32_t stat )
        case 0x01:  // OUT transaction received from host
        case 0x02:
                #ifdef UART_DEBUG_UNKNOWN
-               print("PID=OUT wRequestAndType:");
+               printHex( stat );
+               print(" PID=OUT   wRequestAndType:");
                printHex(setup.wRequestAndType);
                print(", wValue:");
                printHex(setup.wValue);
@@ -782,43 +832,77 @@ 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
 
                // 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 );
+
+                       #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 SET_REPORT
-               if ( setup.wRequestAndType == 0x921 && setup.wValue & 0x200 )
+               // 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++ )
        {
index 4593396ec2c3dd65ad81521d618437c638da4042..586340f68ba55d27913ab7f75c55f82e0b866d1f 100644 (file)
@@ -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 );
 
index 2b5ea7915e1692a0fb0606f3c221b632103f1314..9edcccb87d1e1439ffce0a3279eda2d5306330a6 100644 (file)
@@ -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
+
index ec4aae6bfb88a187fac5f732b719e004a177077e..233cc317fe0d4af52583a4d8d7081f6ab1bf87e9 100644 (file)
@@ -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 <kll_defs.h>
+#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
+
index c72eed568270b15f9f4c2a881d48e3ae98b7a7ac..d1f9a1b47fd52e57c9c9d67824678021b401a0e5 100644 (file)
@@ -29,6 +29,9 @@
  * SOFTWARE.
  */
 
+#include <kll_defs.h>
+#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 (file)
index 0000000..bb9a183
--- /dev/null
@@ -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 <kll_defs.h>
+#if enableRawIO_define == 1
+
+// ----- Includes -----
+
+// Compiler Includes
+#include <string.h> // For memcpy
+
+// Project Includes
+#include <Lib/OutputLib.h>
+#include <print.h>
+
+// 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 (file)
index 0000000..c63ac87
--- /dev/null
@@ -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 );
+
index 4510d404f323bd039972166ad51665fec3e82b96..cf20797021939396c9755b0f5eda70c0af1b92e9 100644 (file)
@@ -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 <kll_defs.h>
+#if enableVirtualSerialPort_define == 1
+
 // ----- Includes -----
 
 // Compiler Includes
 
 // ----- 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
+
index 09980d33c2912d3028e9a89baa88052035451936..9d223dace4c105994a7b57b86737e212fb6f895a 100644 (file)
@@ -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
 
 
 
+// ----- 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;
index 94a6c206cb041aef99cfa4b74ffcd041deece1c1..ce3504d97bd1d1085d7208f649806b8c477f43de 100644 (file)
@@ -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;
+
index b156e1f910f8240b9a5f36d1137ab83ea6663756..e7ba5eb26a3e535788bd01e44a1c408c7a803a4d 100644 (file)
@@ -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");
+}
+
index 700894313a7b8ebef480be7ec321438c936232e0..1dc0ac20832b594f7b1020aeeaecea4c51d6d64d 100644 (file)
@@ -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 -----
index 7e7a874ab8cb2c83091fbde5848b9182bd6f7510..ded1c3f197909d8145037c0327eb19aa625d5fd7 100644 (file)
@@ -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
        )
 
index 9de42126e6420e537b57355b973514552cb42069..a4243f84565398a38de0e9cd6f1f542ea20c40d4 100644 (file)
 // ----- 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");
+}
+