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 fasterblockKey
/* 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 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
* of this software and associated documentation files (the "Software"), to deal | * of this software and associated documentation files (the "Software"), to deal | ||||
// With an op of 1, the max number of characters is 6 + 1 for null | // With an op of 1, the max number of characters is 6 + 1 for null | ||||
// e.g. "0xFFFF\0" | // e.g. "0xFFFF\0" | ||||
// op 2 and 4 require fewer characters (2+1 and 4+1 respectively) | // op 2 and 4 require fewer characters (2+1 and 4+1 respectively) | ||||
char tmpStr[7]; | |||||
char tmpStr[11]; | |||||
// Convert number | // Convert number | ||||
hex32ToStr_op( in, tmpStr, op ); | hex32ToStr_op( in, tmpStr, op ); | ||||
break; | break; | ||||
case 2: // 8-bit padding | case 2: // 8-bit padding | ||||
case 4: // 16-bit padding | case 4: // 16-bit padding | ||||
case 8: // 32-bit padding | |||||
while ( pos < op ) | while ( pos < op ) | ||||
out[pos++] = '0'; | out[pos++] = '0'; | ||||
break; | break; |
# Convenience script for loading firmware onto a dfu type device | # Convenience script for loading firmware onto a dfu type device | ||||
# By default, initiates dfu-util | # 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) | PROG_NAME=$(basename $0) | ||||
# Parse all the command line arguments | # Parse all the command line arguments | ||||
SERIAL_PORT="$2" | SERIAL_PORT="$2" | ||||
shift | shift | ||||
;; | ;; | ||||
-n|--noscreen) | |||||
NOSCREEN=1 | |||||
shift | |||||
;; | |||||
-h|--help) | -h|--help) | ||||
echo "Usage: $PROG_NAME [options...]" | echo "Usage: $PROG_NAME [options...]" | ||||
echo "" | echo "" | ||||
if [[ "$SERIAL_PORT" != "" ]] && [[ -e "$SERIAL_PORT" ]]; then | 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" | echo "NOTE: This may fail if the uC is in a bad state or does not support remote flashing" | ||||
printf "reload\r" > $SERIAL_PORT | printf "reload\r" > $SERIAL_PORT | ||||
sleep 2 | |||||
fi | fi | ||||
# Load via dfu-util | # Load via dfu-util | ||||
# Used for McHCK based uCs | # Used for McHCK based uCs | ||||
if type dfu-util &>/dev/null; then | 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@ | dfu-util -D @TARGET_BIN@ | ||||
EXIT_STATUS=$? | EXIT_STATUS=$? | ||||
else | else | ||||
fi | fi | ||||
# Load Screen Session if specified | # 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 | 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 | screen $AUTO_SCREEN_SESSION | ||||
else | else | ||||
echo "screen is not installed" | echo "screen is not installed" |
// the meaning and format of the data. | // the meaning and format of the data. | ||||
// Keyboard Protocol 1, HID 1.11 spec, Appendix B, page 59-60 | // Keyboard Protocol 1, HID 1.11 spec, Appendix B, page 59-60 | ||||
#if enableKeyboard_define == 1 | |||||
static uint8_t keyboard_report_desc[] = { | static uint8_t keyboard_report_desc[] = { | ||||
// Keyboard Collection | // Keyboard Collection | ||||
0x05, 0x01, // Usage Page (Generic Desktop), | 0x05, 0x01, // Usage Page (Generic Desktop), | ||||
0x81, 0x00, // Input (Data, Array), | 0x81, 0x00, // Input (Data, Array), | ||||
0xc0, // End Collection - Consumer Control | 0xc0, // End Collection - Consumer Control | ||||
}; | }; | ||||
#endif | |||||
// Mouse Protocol 1, HID 1.11 spec, Appendix B, page 59-60, with wheel extension | // 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[] = { | static uint8_t mouse_report_desc[] = { | ||||
0x05, 0x01, // Usage Page (Generic Desktop) | 0x05, 0x01, // Usage Page (Generic Desktop) | ||||
0x09, 0x02, // Usage (Mouse) | 0x09, 0x02, // Usage (Mouse) | ||||
0xc0, // End Collection - Mouse Logical | 0xc0, // End Collection - Mouse Logical | ||||
0xc0 // End Collection - Mouse Application | 0xc0 // End Collection - Mouse Application | ||||
}; | }; | ||||
#endif | |||||
// Joystick Protocol, HID 1.11 spec, Apendix D, page 64-65 | // Joystick Protocol, HID 1.11 spec, Apendix D, page 64-65 | ||||
#if enableJoystick_define == 1 | |||||
static uint8_t joystick_report_desc[] = { | 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 ----- | // ----- 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 | // USB Configuration Descriptor. This huge descriptor tells all | ||||
// of the devices capbilities. | // of the devices capbilities. | ||||
static uint8_t config_descriptor[CONFIG_DESC_SIZE] = { | |||||
static uint8_t config_descriptor[] = { | |||||
// --- Configuration --- | // --- Configuration --- | ||||
// - 9 bytes - | // - 9 bytes - | ||||
// configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10 | // configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10 | ||||
9, // bLength; | 9, // bLength; | ||||
2, // bDescriptorType; | 2, // bDescriptorType; | ||||
LSB(CONFIG_DESC_SIZE), // wTotalLength | |||||
MSB(CONFIG_DESC_SIZE), | |||||
0xFF, // wTotalLength - XXX Set in usb_init (simplifies defines) | |||||
0xFF, | |||||
NUM_INTERFACE, // bNumInterfaces | NUM_INTERFACE, // bNumInterfaces | ||||
1, // bConfigurationValue | 1, // bConfigurationValue | ||||
0, // iConfiguration | 0, // iConfiguration | ||||
0xA0, // bmAttributes | 0xA0, // bmAttributes | ||||
250, // bMaxPower - Entry Index 8 | 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 | // --- Keyboard HID --- Boot Mode Keyboard Interface | ||||
// - 9 bytes - | // - 9 bytes - | ||||
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 | // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 | ||||
NKRO_KEYBOARD_SIZE, 0, // wMaxPacketSize | NKRO_KEYBOARD_SIZE, 0, // wMaxPacketSize | ||||
NKRO_KEYBOARD_INTERVAL, // bInterval | 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 | // --- Serial CDC --- CDC IAD Descriptor | ||||
// - 8 bytes - | // - 8 bytes - | ||||
// interface association descriptor, USB ECN, Table 9-Z | // interface association descriptor, USB ECN, Table 9-Z | ||||
0x02, // bFunctionClass | 0x02, // bFunctionClass | ||||
0x02, // bFunctionSubClass | 0x02, // bFunctionSubClass | ||||
0x01, // bFunctionProtocol | 0x01, // bFunctionProtocol | ||||
CDC_STATUS_INTERFACE + 4, // iFunction | |||||
0, // iFunction (XXX No interface index, don't give string -HaaTa) | |||||
// --- Serial CDC --- CDC Data Interface | // --- Serial CDC --- CDC Data Interface | ||||
// - 9 bytes - | // - 9 bytes - | ||||
0x02, // bmAttributes (0x02=bulk) | 0x02, // bmAttributes (0x02=bulk) | ||||
CDC_TX_SIZE, 0, // wMaxPacketSize | CDC_TX_SIZE, 0, // wMaxPacketSize | ||||
0, // bInterval | 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 --- | // --- Mouse Interface --- | ||||
// - 9 bytes - | // - 9 bytes - | ||||
0x03, // bmAttributes (0x03=intr) | 0x03, // bmAttributes (0x03=intr) | ||||
MOUSE_SIZE, 0, // wMaxPacketSize | MOUSE_SIZE, 0, // wMaxPacketSize | ||||
MOUSE_INTERVAL, // bInterval | 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 --- | // --- Joystick Interface --- | ||||
// - 9 bytes - | // - 9 bytes - | ||||
0x03, // bmAttributes (0x03=intr) | 0x03, // bmAttributes (0x03=intr) | ||||
JOYSTICK_SIZE, 0, // wMaxPacketSize | JOYSTICK_SIZE, 0, // wMaxPacketSize | ||||
JOYSTICK_INTERVAL, // bInterval | 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]; | uint8_t *usb_bMaxPower = &config_descriptor[8]; | ||||
usb_string_descriptor( usb_string_manufacturer_name_default, STR_MANUFACTURER ); | 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_product_name_default, STR_PRODUCT ); | ||||
usb_string_descriptor( usb_string_serial_number_default, STR_SERIAL ); | 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_keyboard_name, KEYBOARD_NAME ); | ||||
usb_string_descriptor( usb_string_nkro_keyboard_name, NKRO_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_status_name, CDC_STATUS_NAME ); | ||||
usb_string_descriptor( usb_string_cdc_data_name, CDC_DATA_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 ); | 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_joystick_name, JOYSTICK_NAME ); | ||||
usb_string_descriptor( usb_string_sys_ctrl_name, SYS_CTRL_NAME ); | |||||
#endif | |||||
// ----- Descriptors List ----- | // ----- 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. | // This table provides access to all the descriptor data above. | ||||
const usb_descriptor_list_t usb_descriptor_list[] = { | const usb_descriptor_list_t usb_descriptor_list[] = { | ||||
{0x0600, 0x0000, device_qualifier_descriptor, sizeof(device_qualifier_descriptor)}, | {0x0600, 0x0000, device_qualifier_descriptor, sizeof(device_qualifier_descriptor)}, | ||||
{0x0A00, 0x0000, usb_debug_descriptor, sizeof(usb_debug_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)}, | {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)}, | {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)}, | {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( KEYBOARD_INTERFACE, usb_string_keyboard_name ), | ||||
iInterfaceString( NKRO_KEYBOARD_INTERFACE, usb_string_nkro_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_STATUS_INTERFACE, usb_string_cdc_status_name ), | ||||
iInterfaceString( CDC_DATA_INTERFACE, usb_string_cdc_data_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 ), | 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( JOYSTICK_INTERFACE, usb_string_joystick_name ), | ||||
iInterfaceString( SYS_CTRL_INTERFACE, usb_string_sys_ctrl_name ), | |||||
#endif | |||||
{0, 0, NULL, 0} | {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 ----- | // ----- Endpoint Configuration ----- |
#define DEVICE_SUBCLASS 0x00 | #define DEVICE_SUBCLASS 0x00 | ||||
#define DEVICE_PROTOCOL 0x00 | #define DEVICE_PROTOCOL 0x00 | ||||
#define EP0_SIZE 64 | #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_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_INTERFACE 0 // Keyboard | ||||
#define KEYBOARD_ENDPOINT 1 | #define KEYBOARD_ENDPOINT 1 | ||||
#define NKRO_KEYBOARD_INTERVAL 1 | #define NKRO_KEYBOARD_INTERVAL 1 | ||||
#define NKRO_KEYBOARD_NAME L"NKRO Keyboard" | #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_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_ACM_SIZE 16 | ||||
#define CDC_RX_SIZE 64 | #define CDC_RX_SIZE 64 | ||||
#define CDC_TX_SIZE 64 | #define CDC_TX_SIZE 64 | ||||
#define CDC_STATUS_NAME L"Virtual Serial Port - Status" | #define CDC_STATUS_NAME L"Virtual Serial Port - Status" | ||||
#define CDC_DATA_NAME L"Virtual Serial Port - Data" | #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_SIZE 8 | ||||
#define MOUSE_INTERVAL 1 | #define MOUSE_INTERVAL 1 | ||||
#define MOUSE_NAME L"Mouse" | #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_SIZE 16 | ||||
#define JOYSTICK_INTERVAL 1 | #define JOYSTICK_INTERVAL 1 | ||||
#define JOYSTICK_NAME L"Joystick" | #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 ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY | ||||
#define ENDPOINT2_CONFIG ENDPOINT_TRANSIMIT_ONLY | #define ENDPOINT2_CONFIG ENDPOINT_TRANSIMIT_ONLY | ||||
#define ENDPOINT3_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 ENDPOINT6_CONFIG ENDPOINT_TRANSIMIT_ONLY | ||||
#define ENDPOINT7_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 | |||||
extern uint8_t *usb_bMaxPower; | extern uint8_t *usb_bMaxPower; | ||||
// ----- Functions ----- | |||||
void usb_set_config_descriptor_size(); | |||||
#include "usb_dev.h" | #include "usb_dev.h" | ||||
#include "usb_mem.h" | #include "usb_mem.h" | ||||
#if enableVirtualSerialPort_define == 1 | |||||
#include "usb_serial.h" | |||||
#endif | |||||
// ----- Defines ----- | // ----- Defines ----- | ||||
static void endpoint0_stall() | static void endpoint0_stall() | ||||
{ | { | ||||
#ifdef UART_DEBUG_UNKNOWN | #ifdef UART_DEBUG_UNKNOWN | ||||
print("STALL" NL ); | |||||
print("STALL : "); | |||||
printInt32( systick_millis_count - USBInit_TimeStart ); | |||||
print(" ms"); | |||||
print(NL); | |||||
#endif | #endif | ||||
USB0_ENDPT0 = USB_ENDPT_EPSTALL | USB_ENDPT_EPRXEN | USB_ENDPT_EPTXEN | USB_ENDPT_EPHSHK; | USB0_ENDPT0 = USB_ENDPT_EPSTALL | USB_ENDPT_EPRXEN | USB_ENDPT_EPTXEN | USB_ENDPT_EPHSHK; | ||||
} | } | ||||
void usb_reinit() | void usb_reinit() | ||||
{ | { | ||||
power_neg_delay = 0; | |||||
usb_configuration = 0; // Clear USB configuration if we have one | usb_configuration = 0; // Clear USB configuration if we have one | ||||
USB0_CONTROL = 0; // Disable D+ Pullup to simulate disconnect | USB0_CONTROL = 0; // Disable D+ Pullup to simulate disconnect | ||||
delay(10); // Delay is necessary to simulate disconnect | delay(10); // Delay is necessary to simulate disconnect | ||||
// Check if 100 ms has elapsed | // Check if 100 ms has elapsed | ||||
if ( systick_millis_count - power_neg_time > 100 ) | 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 | // Update bMaxPower | ||||
// The value set is in increments of 2 mA | // The value set is in increments of 2 mA | ||||
// So 50 * 2 mA = 100 mA | // So 50 * 2 mA = 100 mA | ||||
// Re-initialize USB | // Re-initialize USB | ||||
usb_reinit(); | usb_reinit(); | ||||
#else | |||||
warn_msg("USB Low Power Negotation Disabled, condition detected."); | |||||
#endif | |||||
} | } | ||||
} | } | ||||
} | } | ||||
const uint8_t *cfg; | const uint8_t *cfg; | ||||
int i; | int i; | ||||
// Reset USB Init timer | |||||
USBInit_TimeEnd = systick_millis_count; | |||||
USBInit_Ticks++; | |||||
// If another request is made, disable the power negotiation check | // If another request is made, disable the power negotiation check | ||||
// See GET_DESCRIPTOR - Configuration | // See GET_DESCRIPTOR - Configuration | ||||
if ( power_neg_delay ) | if ( power_neg_delay ) | ||||
endpoint0_stall(); | endpoint0_stall(); | ||||
return; | return; | ||||
#if enableVirtualSerialPort_define == 1 | |||||
case 0x2221: // CDC_SET_CONTROL_LINE_STATE | case 0x2221: // CDC_SET_CONTROL_LINE_STATE | ||||
usb_cdc_line_rtsdtr = setup.wValue; | usb_cdc_line_rtsdtr = setup.wValue; | ||||
//serial_print("set control line state\n"); | |||||
//info_print("set control line state"); | |||||
goto send; | goto send; | ||||
case 0x21A1: // CDC_GET_LINE_CODING | 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 ); | datalen = sizeof( usb_cdc_line_coding ); | ||||
goto send; | goto send; | ||||
case 0x2021: // CDC_SET_LINE_CODING | 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 | 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 | // Interface | ||||
switch ( setup.wIndex & 0xFF ) | switch ( setup.wIndex & 0xFF ) | ||||
{ | { | ||||
printHex( setup.wIndex ); | printHex( setup.wIndex ); | ||||
print( NL ); | print( NL ); | ||||
endpoint0_stall(); | endpoint0_stall(); | ||||
break; | |||||
return; | |||||
} | } | ||||
goto send; | goto send; | ||||
datalen = list->length; | datalen = list->length; | ||||
goto send; | goto send; | ||||
} | } | ||||
} | |||||
endpoint0_stall(); | |||||
return; | |||||
} | |||||
endpoint0_stall(); | |||||
return; | |||||
case 0x0A21: // HID SET_IDLE | case 0x0A21: // HID SET_IDLE | ||||
#ifdef UART_DEBUG | #ifdef UART_DEBUG | ||||
print(NL); | print(NL); | ||||
#endif | #endif | ||||
reply_buffer[0] = USBKeys_Idle_Config; | reply_buffer[0] = USBKeys_Idle_Config; | ||||
data = reply_buffer; | |||||
datalen = 1; | datalen = 1; | ||||
goto send; | goto send; | ||||
print(NL); | print(NL); | ||||
#endif | #endif | ||||
reply_buffer[0] = USBKeys_Protocol; | reply_buffer[0] = USBKeys_Protocol; | ||||
data = reply_buffer; | |||||
datalen = 1; | datalen = 1; | ||||
goto send; | goto send; | ||||
// case 0xC940: | // case 0xC940: | ||||
default: | default: | ||||
#ifdef UART_DEBUG_UNKNOWN | #ifdef UART_DEBUG_UNKNOWN | ||||
print("UNKNOWN"); | |||||
print("UNKNOWN: "); | |||||
printInt32( systick_millis_count - USBInit_TimeStart ); | |||||
print(" ms"); | |||||
print(NL); | print(NL); | ||||
#endif | #endif | ||||
endpoint0_stall(); | endpoint0_stall(); | ||||
if ( size > EP0_SIZE ) | if ( size > EP0_SIZE ) | ||||
size = EP0_SIZE; | size = EP0_SIZE; | ||||
endpoint0_transmit(data, size); | |||||
endpoint0_transmit( data, size ); | |||||
data += size; | data += size; | ||||
datalen -= size; | datalen -= size; | ||||
size = datalen; | size = datalen; | ||||
if ( size > EP0_SIZE ) | if ( size > EP0_SIZE ) | ||||
size = EP0_SIZE; | size = EP0_SIZE; | ||||
endpoint0_transmit(data, size); | |||||
endpoint0_transmit( data, size ); | |||||
data += size; | data += size; | ||||
datalen -= size; | datalen -= size; | ||||
//to be set to their default values. This includes setting the data toggle of | //to be set to their default values. This includes setting the data toggle of | ||||
//any endpoint using data toggles to the value DATA0. | //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 ) | static void usb_control( uint32_t stat ) | ||||
{ | { | ||||
print(" - "); | print(" - "); | ||||
#endif | #endif | ||||
switch (pid) | |||||
switch ( pid ) | |||||
{ | { | ||||
case 0x0D: // Setup received from host | case 0x0D: // Setup received from host | ||||
//serial_print("PID=Setup\n"); | |||||
//if (count != 8) ; // panic? | |||||
// grab the 8 byte setup info | // grab the 8 byte setup info | ||||
setup.word1 = *(uint32_t *)(buf); | setup.word1 = *(uint32_t *)(buf); | ||||
setup.word2 = *(uint32_t *)(buf + 4); | setup.word2 = *(uint32_t *)(buf + 4); | ||||
//} | //} | ||||
table[index(0, TX, EVEN)].desc = 0; | table[index(0, TX, EVEN)].desc = 0; | ||||
table[index(0, TX, ODD)].desc = 0; | table[index(0, TX, ODD)].desc = 0; | ||||
// first IN after Setup is always DATA1 | // first IN after Setup is always DATA1 | ||||
ep0_tx_data_toggle = 1; | ep0_tx_data_toggle = 1; | ||||
#ifdef UART_DEBUG_UNKNOWN | #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:"); | print(", wValue:"); | ||||
printHex(setup.wValue); | printHex(setup.wValue); | ||||
print(", wIndex:"); | print(", wIndex:"); | ||||
printHex32(setup.word1); | printHex32(setup.word1); | ||||
print(" "); | print(" "); | ||||
printHex32(setup.word2); | printHex32(setup.word2); | ||||
print(": "); | |||||
printInt32( systick_millis_count - USBInit_TimeStart ); | |||||
print(" ms"); | |||||
print(NL); | print(NL); | ||||
#endif | #endif | ||||
// actually "do" the setup request | // actually "do" the setup request | ||||
usb_setup(); | usb_setup(); | ||||
// unfreeze the USB, now that we're ready | // unfreeze the USB, now that we're ready | ||||
case 0x01: // OUT transaction received from host | case 0x01: // OUT transaction received from host | ||||
case 0x02: | case 0x02: | ||||
#ifdef UART_DEBUG_UNKNOWN | #ifdef UART_DEBUG_UNKNOWN | ||||
print("PID=OUT wRequestAndType:"); | |||||
printHex( stat ); | |||||
print(" PID=OUT wRequestAndType:"); | |||||
printHex(setup.wRequestAndType); | printHex(setup.wRequestAndType); | ||||
print(", wValue:"); | print(", wValue:"); | ||||
printHex(setup.wValue); | printHex(setup.wValue); | ||||
printHex32(setup.word1); | printHex32(setup.word1); | ||||
print(" "); | print(" "); | ||||
printHex32(setup.word2); | printHex32(setup.word2); | ||||
print(": "); | |||||
printInt32( systick_millis_count - USBInit_TimeStart ); | |||||
print(" ms"); | |||||
print(NL); | print(NL); | ||||
#endif | #endif | ||||
// CDC Interface | // 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 | // Interface | ||||
switch ( setup.wIndex & 0xFF ) | switch ( setup.wIndex & 0xFF ) | ||||
{ | { | ||||
// Keyboard Interface | // Keyboard Interface | ||||
case KEYBOARD_INTERFACE: | case KEYBOARD_INTERFACE: | ||||
USBKeys_LEDs = buf[0]; | USBKeys_LEDs = buf[0]; | ||||
endpoint0_transmit( NULL, 0 ); | |||||
break; | break; | ||||
// NKRO Keyboard Interface | // NKRO Keyboard Interface | ||||
case NKRO_KEYBOARD_INTERFACE: | case NKRO_KEYBOARD_INTERFACE: | ||||
// Already set with the control sequence | |||||
// Only use 2nd byte, first byte is the report id | // Only use 2nd byte, first byte is the report id | ||||
USBKeys_LEDs = buf[1]; | USBKeys_LEDs = buf[1]; | ||||
endpoint0_transmit( NULL, 0 ); | |||||
break; | break; | ||||
default: | default: | ||||
warn_msg("Unknown interface - "); | warn_msg("Unknown interface - "); | ||||
break; | 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 | // give the buffer back | ||||
b->desc = BDT_DESC( EP0_SIZE, DATA1 ); | b->desc = BDT_DESC( EP0_SIZE, DATA1 ); | ||||
break; | break; | ||||
case 0x09: // IN transaction completed to host | 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); | print(NL); | ||||
#endif | #endif | ||||
// send remaining data, if any... | // send remaining data, if any... | ||||
data = ep0_tx_ptr; | |||||
if ( data ) | if ( data ) | ||||
{ | { | ||||
size = ep0_tx_len; | 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; | data += size; | ||||
ep0_tx_len -= size; | ep0_tx_len -= size; | ||||
ep0_tx_ptr = (ep0_tx_len > 0 || size == EP0_SIZE) ? data : NULL; | ep0_tx_ptr = (ep0_tx_len > 0 || size == EP0_SIZE) ? data : NULL; | ||||
USB0_ADDR = setup.wValue; | 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; | break; | ||||
default: | default: | ||||
#ifdef UART_DEBUG | |||||
print("PID=unknown:"); | |||||
#ifdef UART_DEBUG_UNKNOWN | |||||
print("PID=unknown: "); | |||||
printHex(pid); | printHex(pid); | ||||
print(": "); | |||||
printInt32( systick_millis_count - USBInit_TimeStart ); | |||||
print(" ms"); | |||||
print(NL); | print(NL); | ||||
#endif | #endif | ||||
break; | break; | ||||
//print("USB RX"); | //print("USB RX"); | ||||
usb_packet_t *ret; | usb_packet_t *ret; | ||||
endpoint--; | endpoint--; | ||||
// Make sure this is a valid endpoint | |||||
if ( endpoint >= NUM_ENDPOINTS ) | if ( endpoint >= NUM_ENDPOINTS ) | ||||
{ | |||||
return NULL; | return NULL; | ||||
} | |||||
__disable_irq(); | __disable_irq(); | ||||
// Receive packet, check pointer | |||||
ret = rx_first[endpoint]; | ret = rx_first[endpoint]; | ||||
if ( ret ) | if ( ret ) | ||||
{ | |||||
rx_first[ endpoint ] = ret->next; | rx_first[ endpoint ] = ret->next; | ||||
usb_rx_byte_count_data[ endpoint ] -= ret->len; | |||||
usb_rx_byte_count_data[ endpoint ] -= ret->len; | |||||
} | |||||
__enable_irq(); | __enable_irq(); | ||||
//serial_print("rx, epidx="); | //serial_print("rx, epidx="); | ||||
//serial_phex(endpoint); | //serial_phex(endpoint); | ||||
//serial_print(", packet="); | //serial_print(", packet="); | ||||
return; | 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 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 | // 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 | // 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; | USB0_CTL |= USB_CTL_RESUME; | ||||
USB0_CTL &= ~(USB_CTL_RESUME); | USB0_CTL &= ~(USB_CTL_RESUME); | ||||
delay(50); // Wait for at least 50 ms to make sure the bus is clear | 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 | 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 | // Since we are transmitting data, USB will be brought out of sleep/suspend | ||||
// if it's in that state | // if it's in that state | ||||
// Use the currently set descriptor value | // Use the currently set descriptor value | ||||
{ | { | ||||
uint8_t status, stat, t; | uint8_t status, stat, t; | ||||
//serial_print("isr"); | |||||
//status = USB0_ISTAT; | |||||
//serial_phex(status); | |||||
//serial_print("\n"); | |||||
restart: | restart: | ||||
status = USB0_ISTAT; | status = USB0_ISTAT; | ||||
/* | /* | ||||
print("USB ISR STATUS: "); | |||||
print(" ISR("); | |||||
printHex( status ); | printHex( status ); | ||||
print( NL ); | |||||
print(") "); | |||||
*/ | */ | ||||
if ( (status & USB_INTEN_SOFTOKEN /* 04 */ ) ) | if ( (status & USB_INTEN_SOFTOKEN /* 04 */ ) ) | ||||
} | } | ||||
// CDC Interface | // CDC Interface | ||||
#if enableVirtualSerialPort_define == 1 | |||||
t = usb_cdc_transmit_flush_timer; | t = usb_cdc_transmit_flush_timer; | ||||
if ( t ) | if ( t ) | ||||
{ | { | ||||
if ( t == 0 ) | if ( t == 0 ) | ||||
usb_serial_flush_callback(); | usb_serial_flush_callback(); | ||||
} | } | ||||
#endif | |||||
} | } | ||||
USB0_ISTAT = USB_INTEN_SOFTOKEN; | USB0_ISTAT = USB_INTEN_SOFTOKEN; | ||||
// The USB Module triggers this interrupt when it detects the bus has been idle for 3 ms | // The USB Module triggers this interrupt when it detects the bus has been idle for 3 ms | ||||
if ( (status & USB_ISTAT_SLEEP /* 10 */ ) ) | 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 | Output_update_usb_current( 100 ); // Set to 100 mA | ||||
usb_dev_sleep = 1; | usb_dev_sleep = 1; | ||||
#else | |||||
info_print("USB Suspend Detected - Firmware USB Suspend Disabled"); | |||||
#endif | |||||
USB0_ISTAT |= USB_ISTAT_SLEEP; | USB0_ISTAT |= USB_ISTAT_SLEEP; | ||||
} | } | ||||
// On USB Resume, unset the usb_dev_sleep so we don't keep sending resume signals | // On USB Resume, unset the usb_dev_sleep so we don't keep sending resume signals | ||||
if ( (status & USB_ISTAT_RESUME /* 20 */ ) ) | 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 ); | Output_update_usb_current( *usb_bMaxPower * 2 ); | ||||
usb_dev_sleep = 0; | usb_dev_sleep = 0; | ||||
USB0_ISTAT |= USB_ISTAT_RESUME; | USB0_ISTAT |= USB_ISTAT_RESUME; | ||||
print("USB INIT"NL); | print("USB INIT"NL); | ||||
#endif | #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 | // Clear out endpoints table | ||||
for ( int i = 0; i <= NUM_ENDPOINTS * 4; i++ ) | for ( int i = 0; i <= NUM_ENDPOINTS * 4; i++ ) | ||||
{ | { |
extern uint16_t usb_rx_byte_count_data[NUM_ENDPOINTS]; | 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 ----- | // ----- Functions ----- | ||||
void usb_tx( uint32_t endpoint, usb_packet_t *packet ); | void usb_tx( uint32_t endpoint, usb_packet_t *packet ); | ||||
void usb_tx_isr( 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_byte_count( uint32_t endpoint ); | ||||
uint32_t usb_tx_packet_count( uint32_t endpoint ); | uint32_t usb_tx_packet_count( uint32_t endpoint ); | ||||
/* Teensyduino Core Library | /* Teensyduino Core Library | ||||
* http://www.pjrc.com/teensy/ | * http://www.pjrc.com/teensy/ | ||||
* Copyright (c) 2013 PJRC.COM, LLC. | * 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 | * Permission is hereby granted, free of charge, to any person obtaining | ||||
* a copy of this software and associated documentation files (the | * a copy of this software and associated documentation files (the | ||||
* SOFTWARE. | * SOFTWARE. | ||||
*/ | */ | ||||
#if enableJoystick_define == 1 | |||||
// ----- Includes ----- | // ----- Includes ----- | ||||
// Compiler Includes | // Compiler Includes | ||||
return 0; | return 0; | ||||
} | } | ||||
#endif | |||||
/* Teensyduino Core Library | /* Teensyduino Core Library | ||||
* http://www.pjrc.com/teensy/ | * http://www.pjrc.com/teensy/ | ||||
* Copyright (c) 2013 PJRC.COM, LLC. | * 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 | * Permission is hereby granted, free of charge, to any person obtaining | ||||
* a copy of this software and associated documentation files (the | * a copy of this software and associated documentation files (the | ||||
* SOFTWARE. | * SOFTWARE. | ||||
*/ | */ | ||||
#include <kll_defs.h> | |||||
#if enableKeyboard_define == 1 | |||||
// ----- Includes ----- | // ----- Includes ----- | ||||
// Compiler Includes | // Compiler Includes | ||||
} | } | ||||
} | } | ||||
// USB Timeout, drop the packet, and potentially try something more drastic to re-enable the bus | |||||
if ( ++wait_count > TX_TIMEOUT || transmit_previous_timeout ) | if ( ++wait_count > TX_TIMEOUT || transmit_previous_timeout ) | ||||
{ | { | ||||
transmit_previous_timeout = 1; | transmit_previous_timeout = 1; | ||||
warn_print("USB Transmit Timeout...restarting device"); | |||||
USBKeys_Changed = USBKeyChangeState_None; // Indicate packet lost | USBKeys_Changed = USBKeyChangeState_None; // Indicate packet lost | ||||
#if enableDeviceRestartOnUSBTimeout == 1 | |||||
warn_print("USB Transmit Timeout...restarting device"); | |||||
usb_device_software_reset(); | usb_device_software_reset(); | ||||
#else | |||||
warn_print("USB Transmit Timeout...auto-restart disabled"); | |||||
#endif | |||||
// Try to wakeup | |||||
return; | 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(); | yield(); | ||||
} | } | ||||
return; | return; | ||||
} | } | ||||
#endif | |||||
* SOFTWARE. | * SOFTWARE. | ||||
*/ | */ | ||||
#include <kll_defs.h> | |||||
#if enableMouse_define == 1 | |||||
// ----- Includes ----- | // ----- Includes ----- | ||||
// Compiler Includes | // Compiler Includes | ||||
} | } | ||||
} | } | ||||
#endif | |||||
/* 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 | |||||
/* 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 ); | |||||
/* Teensyduino Core Library | /* Teensyduino Core Library | ||||
* http://www.pjrc.com/teensy/ | * http://www.pjrc.com/teensy/ | ||||
* Copyright (c) 2013 PJRC.COM, LLC. | * 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 | * Permission is hereby granted, free of charge, to any person obtaining | ||||
* a copy of this software and associated documentation files (the | * a copy of this software and associated documentation files (the | ||||
* SOFTWARE. | * SOFTWARE. | ||||
*/ | */ | ||||
#include <kll_defs.h> | |||||
#if enableVirtualSerialPort_define == 1 | |||||
// ----- Includes ----- | // ----- Includes ----- | ||||
// Compiler Includes | // Compiler Includes | ||||
// ----- Variables ----- | // ----- 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_line_rtsdtr = 0; | ||||
volatile uint8_t usb_cdc_transmit_flush_timer = 0; | volatile uint8_t usb_cdc_transmit_flush_timer = 0; | ||||
} | } | ||||
} | } | ||||
#endif | |||||
/* Teensyduino Core Library | /* Teensyduino Core Library | ||||
* http://www.pjrc.com/teensy/ | * http://www.pjrc.com/teensy/ | ||||
* Copyright (c) 2013 PJRC.COM, LLC. | * 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 | * Permission is hereby granted, free of charge, to any person obtaining | ||||
* a copy of this software and associated documentation files (the | * 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 ----- | // ----- 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_line_rtsdtr; | ||||
extern volatile uint8_t usb_cdc_transmit_flush_timer; | extern volatile uint8_t usb_cdc_transmit_flush_timer; |
KLL = 0.3d; | KLL = 0.3d; | ||||
# Modified Date | # Modified Date | ||||
Date = 2016-03-21; | |||||
Date = 2016-05-31; | |||||
# Output capabilities | # Output capabilities | ||||
flashMode => Output_flashMode_capability(); | 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; | |||||
void cliFunc_sendKeys ( char* args ); | void cliFunc_sendKeys ( char* args ); | ||||
void cliFunc_setKeys ( char* args ); | void cliFunc_setKeys ( char* args ); | ||||
void cliFunc_setMod ( char* args ); | void cliFunc_setMod ( char* args ); | ||||
void cliFunc_usbInitTime( char* args ); | |||||
CLIDict_Entry( sendKeys, "Send the prepared list of USB codes and modifier byte." ); | 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( 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( 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_Def( outputCLIDict, "USB Module Commands" ) = { | ||||
CLIDict_Item( kbdProtocol ), | CLIDict_Item( kbdProtocol ), | ||||
CLIDict_Item( sendKeys ), | CLIDict_Item( sendKeys ), | ||||
CLIDict_Item( setKeys ), | CLIDict_Item( setKeys ), | ||||
CLIDict_Item( setMod ), | CLIDict_Item( setMod ), | ||||
CLIDict_Item( usbInitTime ), | |||||
{ 0, 0, 0 } // Null entry for dictionary end | { 0, 0, 0 } // Null entry for dictionary end | ||||
}; | }; | ||||
// Initially 100 mA, but may be negotiated higher (e.g. 500 mA) | // Initially 100 mA, but may be negotiated higher (e.g. 500 mA) | ||||
uint16_t Output_USBCurrent_Available = 0; | 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 ----- | // ----- Capabilities ----- | ||||
// Set Boot Keyboard Protocol | // Set Boot Keyboard Protocol | ||||
void Output_kbdProtocolBoot_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | void Output_kbdProtocolBoot_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | ||||
{ | { | ||||
#if enableKeyboard_define == 1 | |||||
// Display capability name | // Display capability name | ||||
if ( stateType == 0xFF && state == 0xFF ) | if ( stateType == 0xFF && state == 0xFF ) | ||||
{ | { | ||||
// Set the keyboard protocol to Boot Mode | // Set the keyboard protocol to Boot Mode | ||||
USBKeys_Protocol = 0; | USBKeys_Protocol = 0; | ||||
#endif | |||||
} | } | ||||
// Set NKRO Keyboard Protocol | // Set NKRO Keyboard Protocol | ||||
void Output_kbdProtocolNKRO_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | void Output_kbdProtocolNKRO_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | ||||
{ | { | ||||
#if enableKeyboard_define == 1 | |||||
// Display capability name | // Display capability name | ||||
if ( stateType == 0xFF && state == 0xFF ) | if ( stateType == 0xFF && state == 0xFF ) | ||||
{ | { | ||||
// Set the keyboard protocol to NKRO Mode | // Set the keyboard protocol to NKRO Mode | ||||
USBKeys_Protocol = 1; | USBKeys_Protocol = 1; | ||||
#endif | |||||
} | } | ||||
// Toggle Keyboard Protocol | // Toggle Keyboard Protocol | ||||
void Output_toggleKbdProtocol_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | void Output_toggleKbdProtocol_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | ||||
{ | { | ||||
#if enableKeyboard_define == 1 | |||||
// Display capability name | // Display capability name | ||||
if ( stateType == 0xFF && state == 0xFF ) | if ( stateType == 0xFF && state == 0xFF ) | ||||
{ | { | ||||
// Toggle the keyboard protocol Mode | // Toggle the keyboard protocol Mode | ||||
USBKeys_Protocol = !USBKeys_Protocol; | USBKeys_Protocol = !USBKeys_Protocol; | ||||
} | } | ||||
#endif | |||||
} | } | ||||
// Sends a Consumer Control code to the USB Output buffer | // Sends a Consumer Control code to the USB Output buffer | ||||
void Output_consCtrlSend_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | void Output_consCtrlSend_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | ||||
{ | { | ||||
#if enableKeyboard_define == 1 | |||||
// Display capability name | // Display capability name | ||||
if ( stateType == 0xFF && state == 0xFF ) | if ( stateType == 0xFF && state == 0xFF ) | ||||
{ | { | ||||
// Set consumer control code | // Set consumer control code | ||||
USBKeys_ConsCtrl = *(uint16_t*)(&args[0]); | USBKeys_ConsCtrl = *(uint16_t*)(&args[0]); | ||||
#endif | |||||
} | } | ||||
// Sends a System Control code to the USB Output buffer | // Sends a System Control code to the USB Output buffer | ||||
void Output_sysCtrlSend_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | void Output_sysCtrlSend_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | ||||
{ | { | ||||
#if enableKeyboard_define == 1 | |||||
// Display capability name | // Display capability name | ||||
if ( stateType == 0xFF && state == 0xFF ) | if ( stateType == 0xFF && state == 0xFF ) | ||||
{ | { | ||||
// Set system control code | // Set system control code | ||||
USBKeys_SysCtrl = args[0]; | USBKeys_SysCtrl = args[0]; | ||||
#endif | |||||
} | } | ||||
// Argument #1: USB Code | // Argument #1: USB Code | ||||
void Output_usbCodeSend_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | void Output_usbCodeSend_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | ||||
{ | { | ||||
#if enableKeyboard_define == 1 | |||||
// Display capability name | // Display capability name | ||||
if ( stateType == 0xFF && state == 0xFF ) | if ( stateType == 0xFF && state == 0xFF ) | ||||
{ | { | ||||
break; | break; | ||||
} | } | ||||
#endif | |||||
} | } | ||||
void Output_flashMode_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | void Output_flashMode_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | ||||
Output_firmwareReload(); | Output_firmwareReload(); | ||||
} | } | ||||
#if enableMouse_define == 1 | |||||
// Sends a mouse command over the USB Output buffer | // Sends a mouse command over the USB Output buffer | ||||
// XXX This function *will* be changing in the future | // 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) | // If you use it, be prepared that your .kll files will break in the future (post KLL 0.5) | ||||
if ( mouse_x || mouse_y ) | if ( mouse_x || mouse_y ) | ||||
USBMouse_Changed |= USBMouseChangeState_Relative; | USBMouse_Changed |= USBMouseChangeState_Relative; | ||||
} | } | ||||
#endif | |||||
// Non-standard USB state manipulation, usually does nothing | // Non-standard USB state manipulation, usually does nothing | ||||
usb_device_check(); | 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 | // 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 | // Check if idle count has been exceed, this forces usb_keyboard_send and usb_mouse_send to update | ||||
} | } | ||||
*/ | */ | ||||
#if enableMouse_define == 1 | |||||
// Process mouse actions | // Process mouse actions | ||||
while ( USBMouse_Changed ) | while ( USBMouse_Changed ) | ||||
usb_mouse_send(); | 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 | // Send keypresses while there are pending changes | ||||
while ( USBKeys_Changed ) | while ( USBKeys_Changed ) | ||||
Scan_finishedWithOutput( USBKeys_Sent ); | Scan_finishedWithOutput( USBKeys_Sent ); | ||||
break; | break; | ||||
} | } | ||||
#endif | |||||
} | } | ||||
// USB Input buffer available | // USB Input buffer available | ||||
inline unsigned int Output_availablechar() | inline unsigned int Output_availablechar() | ||||
{ | { | ||||
#if enableVirtualSerialPort_define == 1 | |||||
return usb_serial_available(); | return usb_serial_available(); | ||||
#else | |||||
return 0; | |||||
#endif | |||||
} | } | ||||
// USB Get Character from input buffer | // USB Get Character from input buffer | ||||
inline int Output_getchar() | 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) | // XXX Make sure to check output_availablechar() first! Information is lost with the cast (error codes) (AVR) | ||||
return (int)usb_serial_getchar(); | return (int)usb_serial_getchar(); | ||||
#else | |||||
return 0; | |||||
#endif | |||||
} | } | ||||
// USB Send Character to output buffer | // USB Send Character to output buffer | ||||
inline int Output_putchar( char c ) | inline int Output_putchar( char c ) | ||||
{ | { | ||||
#if enableVirtualSerialPort_define == 1 | |||||
return usb_serial_putchar( c ); | return usb_serial_putchar( c ); | ||||
#else | |||||
return 0; | |||||
#endif | |||||
} | } | ||||
// USB Send String to output buffer, null terminated | // USB Send String to output buffer, null terminated | ||||
inline int Output_putstr( char* str ) | inline int Output_putstr( char* str ) | ||||
{ | { | ||||
#if enableVirtualSerialPort_define == 1 | |||||
#if defined(_at90usb162_) || defined(_atmega32u4_) || defined(_at90usb646_) || defined(_at90usb1286_) // AVR | #if defined(_at90usb162_) || defined(_atmega32u4_) || defined(_at90usb646_) || defined(_at90usb1286_) // AVR | ||||
uint16_t count = 0; | uint16_t count = 0; | ||||
#elif defined(_mk20dx128_) || defined(_mk20dx128vlf5_) || defined(_mk20dx256_) || defined(_mk20dx256vlh7_) // ARM | #elif defined(_mk20dx128_) || defined(_mk20dx128vlf5_) || defined(_mk20dx256_) || defined(_mk20dx256vlh7_) // ARM | ||||
count++; | count++; | ||||
return usb_serial_write( str, count ); | return usb_serial_write( str, count ); | ||||
#else | |||||
return 0; | |||||
#endif | |||||
} | } | ||||
} | } | ||||
// 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) | // Update USB current (mA) | ||||
// Triggers power change event | // Triggers power change event | ||||
void Output_update_usb_current( unsigned int current ) | void Output_update_usb_current( unsigned int current ) | ||||
USBKeys_ModifiersCLI = numToInt( arg1Ptr ); | 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"); | |||||
} | |||||
extern uint16_t Output_ExtCurrent_Available; // mA - Set by outside module if not using USB (i.e. Interconnect) | 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 ----- | // ----- Functions ----- |
###| CMake Kiibohd Controller USB Module |### | ###| 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 | # Released into the Public Domain | ||||
# | # | ||||
arm/usb_keyboard.c | arm/usb_keyboard.c | ||||
arm/usb_mem.c | arm/usb_mem.c | ||||
arm/usb_mouse.c | arm/usb_mouse.c | ||||
arm/usb_rawio.c | |||||
arm/usb_serial.c | arm/usb_serial.c | ||||
) | ) | ||||
// ----- Macros ----- | // ----- Macros ----- | ||||
// Used to build a bitmap lookup table from a byte addressable array | // 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 | |||||
void cliFunc_sendUART ( char* args ); | void cliFunc_sendUART ( char* args ); | ||||
void cliFunc_setKeys ( char* args ); | void cliFunc_setKeys ( char* args ); | ||||
void cliFunc_setMod ( char* args ); | void cliFunc_setMod ( char* args ); | ||||
void cliFunc_usbInitTime( char* args ); | |||||
CLIDict_Entry( sendUART, "Send characters over UART0." ); | 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( 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( 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_Def( outputCLIDict, "USB Module Commands" ) = { | ||||
CLIDict_Item( kbdProtocol ), | CLIDict_Item( kbdProtocol ), | ||||
CLIDict_Item( sendUART ), | CLIDict_Item( sendUART ), | ||||
CLIDict_Item( setKeys ), | CLIDict_Item( setKeys ), | ||||
CLIDict_Item( setMod ), | CLIDict_Item( setMod ), | ||||
CLIDict_Item( usbInitTime ), | |||||
{ 0, 0, 0 } // Null entry for dictionary end | { 0, 0, 0 } // Null entry for dictionary end | ||||
}; | }; | ||||
// Initially 100 mA, but may be negotiated higher (e.g. 500 mA) | // Initially 100 mA, but may be negotiated higher (e.g. 500 mA) | ||||
uint16_t Output_USBCurrent_Available = 0; | 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 ----- | // ----- Capabilities ----- | ||||
// Set Boot Keyboard Protocol | // Set Boot Keyboard Protocol | ||||
void Output_kbdProtocolBoot_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | void Output_kbdProtocolBoot_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | ||||
{ | { | ||||
#if enableKeyboard_define == 1 | |||||
// Display capability name | // Display capability name | ||||
if ( stateType == 0xFF && state == 0xFF ) | if ( stateType == 0xFF && state == 0xFF ) | ||||
{ | { | ||||
// Set the keyboard protocol to Boot Mode | // Set the keyboard protocol to Boot Mode | ||||
USBKeys_Protocol = 0; | USBKeys_Protocol = 0; | ||||
#endif | |||||
} | } | ||||
// Set NKRO Keyboard Protocol | // Set NKRO Keyboard Protocol | ||||
void Output_kbdProtocolNKRO_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | void Output_kbdProtocolNKRO_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | ||||
{ | { | ||||
#if enableKeyboard_define == 1 | |||||
// Display capability name | // Display capability name | ||||
if ( stateType == 0xFF && state == 0xFF ) | if ( stateType == 0xFF && state == 0xFF ) | ||||
{ | { | ||||
// Set the keyboard protocol to NKRO Mode | // Set the keyboard protocol to NKRO Mode | ||||
USBKeys_Protocol = 1; | USBKeys_Protocol = 1; | ||||
#endif | |||||
} | } | ||||
// Toggle Keyboard Protocol | // Toggle Keyboard Protocol | ||||
void Output_toggleKbdProtocol_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | void Output_toggleKbdProtocol_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | ||||
{ | { | ||||
#if enableKeyboard_define == 1 | |||||
// Display capability name | // Display capability name | ||||
if ( stateType == 0xFF && state == 0xFF ) | if ( stateType == 0xFF && state == 0xFF ) | ||||
{ | { | ||||
// Toggle the keyboard protocol Mode | // Toggle the keyboard protocol Mode | ||||
USBKeys_Protocol = !USBKeys_Protocol; | USBKeys_Protocol = !USBKeys_Protocol; | ||||
} | } | ||||
#endif | |||||
} | } | ||||
// Sends a Consumer Control code to the USB Output buffer | // Sends a Consumer Control code to the USB Output buffer | ||||
void Output_consCtrlSend_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | void Output_consCtrlSend_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | ||||
{ | { | ||||
#if enableKeyboard_define == 1 | |||||
// Display capability name | // Display capability name | ||||
if ( stateType == 0xFF && state == 0xFF ) | if ( stateType == 0xFF && state == 0xFF ) | ||||
{ | { | ||||
// Set consumer control code | // Set consumer control code | ||||
USBKeys_ConsCtrl = *(uint16_t*)(&args[0]); | USBKeys_ConsCtrl = *(uint16_t*)(&args[0]); | ||||
#endif | |||||
} | } | ||||
// Sends a System Control code to the USB Output buffer | // Sends a System Control code to the USB Output buffer | ||||
void Output_sysCtrlSend_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | void Output_sysCtrlSend_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | ||||
{ | { | ||||
#if enableKeyboard_define == 1 | |||||
// Display capability name | // Display capability name | ||||
if ( stateType == 0xFF && state == 0xFF ) | if ( stateType == 0xFF && state == 0xFF ) | ||||
{ | { | ||||
// Set system control code | // Set system control code | ||||
USBKeys_SysCtrl = args[0]; | USBKeys_SysCtrl = args[0]; | ||||
#endif | |||||
} | } | ||||
// Argument #1: USB Code | // Argument #1: USB Code | ||||
void Output_usbCodeSend_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | void Output_usbCodeSend_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | ||||
{ | { | ||||
#if enableKeyboard_define == 1 | |||||
// Display capability name | // Display capability name | ||||
if ( stateType == 0xFF && state == 0xFF ) | if ( stateType == 0xFF && state == 0xFF ) | ||||
{ | { | ||||
break; | break; | ||||
} | } | ||||
#endif | |||||
} | } | ||||
void Output_flashMode_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | void Output_flashMode_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | ||||
// Argument #3: USB Y Axis (16 bit) relative | // Argument #3: USB Y Axis (16 bit) relative | ||||
void Output_usbMouse_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | void Output_usbMouse_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | ||||
{ | { | ||||
#if enableMouse_define == 1 | |||||
// Display capability name | // Display capability name | ||||
if ( stateType == 0xFF && state == 0xFF ) | if ( stateType == 0xFF && state == 0xFF ) | ||||
{ | { | ||||
if ( mouse_x || mouse_y ) | if ( mouse_x || mouse_y ) | ||||
USBMouse_Changed |= USBMouseChangeState_Relative; | USBMouse_Changed |= USBMouseChangeState_Relative; | ||||
#endif | |||||
} | } | ||||
usb_device_check(); | usb_device_check(); | ||||
// Boot Mode Only, unset stale keys | // 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 | // 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 | // Check if idle count has been exceed, this forces usb_keyboard_send and usb_mouse_send to update | ||||
} | } | ||||
*/ | */ | ||||
#if enableMouse_define == 1 | |||||
// Process mouse actions | // Process mouse actions | ||||
while ( USBMouse_Changed ) | while ( USBMouse_Changed ) | ||||
usb_mouse_send(); | 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 | // Send keypresses while there are pending changes | ||||
while ( USBKeys_Changed ) | while ( USBKeys_Changed ) | ||||
Scan_finishedWithOutput( USBKeys_Sent ); | Scan_finishedWithOutput( USBKeys_Sent ); | ||||
break; | break; | ||||
} | } | ||||
#endif | |||||
} | } | ||||
// USB Input buffer available | // USB Input buffer available | ||||
inline unsigned int Output_availablechar() | inline unsigned int Output_availablechar() | ||||
{ | { | ||||
#if enableVirtualSerialPort_define == 1 | |||||
return usb_serial_available() + uart_serial_available(); | return usb_serial_available() + uart_serial_available(); | ||||
#else | |||||
return uart_serial_available(); | |||||
#endif | |||||
} | } | ||||
// USB Get Character from input buffer | // USB Get Character from input buffer | ||||
inline int Output_getchar() | 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) | // XXX Make sure to check output_availablechar() first! Information is lost with the cast (error codes) (AVR) | ||||
if ( usb_serial_available() > 0 ) | if ( usb_serial_available() > 0 ) | ||||
{ | { | ||||
return (int)usb_serial_getchar(); | return (int)usb_serial_getchar(); | ||||
} | } | ||||
#endif | |||||
if ( uart_serial_available() > 0 ) | if ( uart_serial_available() > 0 ) | ||||
{ | { | ||||
// USB Send Character to output buffer | // USB Send Character to output buffer | ||||
inline int Output_putchar( char c ) | inline int Output_putchar( char c ) | ||||
{ | { | ||||
#if enableVirtualSerialPort_define == 1 | |||||
// First send to UART | // First send to UART | ||||
uart_serial_putchar( c ); | uart_serial_putchar( c ); | ||||
// Then send to USB | // Then send to USB | ||||
return usb_serial_putchar( c ); | return usb_serial_putchar( c ); | ||||
#else | |||||
return uart_serial_putchar( c ); | |||||
#endif | |||||
} | } | ||||
while ( str[count] != '\0' ) | while ( str[count] != '\0' ) | ||||
count++; | count++; | ||||
#if enableVirtualSerialPort_define == 1 | |||||
// First send to UART | // First send to UART | ||||
uart_serial_write( str, count ); | uart_serial_write( str, count ); | ||||
// Then send to USB | // Then send to USB | ||||
return usb_serial_write( str, count ); | return usb_serial_write( str, count ); | ||||
#else | |||||
return uart_serial_write( str, count ); | |||||
#endif | |||||
} | } | ||||
USBKeys_ModifiersCLI = numToInt( arg1Ptr ); | 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"); | |||||
} | |||||