X-Git-Url: https://git.donarmstrong.com/?p=kiibohd-controller.git;a=blobdiff_plain;f=Output%2FpjrcUSB%2Farm%2Fusb_dev.c;h=37541e488f6856c2a82c17bde0e41fac10024bde;hp=52c886becbf602b82dc55ff6e696567e32b433b9;hb=9c52fb32fa476249c35279ef4fff1be59e3e7eac;hpb=25304734af9f8870d5ee73c44c63b33d200016a6 diff --git a/Output/pjrcUSB/arm/usb_dev.c b/Output/pjrcUSB/arm/usb_dev.c index 52c886b..37541e4 100644 --- a/Output/pjrcUSB/arm/usb_dev.c +++ b/Output/pjrcUSB/arm/usb_dev.c @@ -1,6 +1,7 @@ /* Teensyduino Core Library * http://www.pjrc.com/teensy/ * Copyright (c) 2013 PJRC.COM, LLC. + * Modifications by Jacob Alexander (2013-2015) * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -10,10 +11,10 @@ * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * - * 1. The above copyright notice and this permission notice shall be + * 1. The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * - * 2. If the Software is incorporated into a build system that allows + * 2. If the Software is incorporated into a build system that allows * selection among a list of target devices, then similar target * devices manufactured by PJRC.COM must be included in the list of * target devices and selectable in the same manner. @@ -28,86 +29,127 @@ * SOFTWARE. */ -#include +// ----- Includes ----- + +// Project Includes +#include +#include +#include + +// Local Includes #include "usb_dev.h" #include "usb_mem.h" -// buffer descriptor table -typedef struct { - uint32_t desc; - void * addr; -} bdt_t; -__attribute__ ((section(".usbdescriptortable"), used)) -static bdt_t table[(NUM_ENDPOINTS+1)*4]; +// ----- Defines ----- -static usb_packet_t *rx_first[NUM_ENDPOINTS]; -static usb_packet_t *rx_last[NUM_ENDPOINTS]; -static usb_packet_t *tx_first[NUM_ENDPOINTS]; -static usb_packet_t *tx_last[NUM_ENDPOINTS]; -uint16_t usb_rx_byte_count_data[NUM_ENDPOINTS]; +// DEBUG Mode +// XXX - Only use when using usbMuxUart Module +// Delay causes issues initializing more than 1 hid device (i.e. NKRO keyboard) +//#define UART_DEBUG 1 +// Debug Unknown USB requests, usually what you want to debug USB issues +//#define UART_DEBUG_UNKNOWN 1 -static uint8_t tx_state[NUM_ENDPOINTS]; -#define TX_STATE_BOTH_FREE_EVEN_FIRST 0 -#define TX_STATE_BOTH_FREE_ODD_FIRST 1 -#define TX_STATE_EVEN_FREE 2 -#define TX_STATE_ODD_FREE 3 -#define TX_STATE_NONE_FREE_EVEN_FIRST 4 -#define TX_STATE_NONE_FREE_ODD_FIRST 5 - -#define BDT_OWN 0x80 -#define BDT_DATA1 0x40 -#define BDT_DATA0 0x00 -#define BDT_DTS 0x08 -#define BDT_STALL 0x04 -#define BDT_PID(n) (((n) >> 2) & 15) - -#define BDT_DESC(count, data) (BDT_OWN | BDT_DTS \ - | ((data) ? BDT_DATA1 : BDT_DATA0) \ - | ((count) << 16)) -#define TX 1 -#define RX 0 -#define ODD 1 -#define EVEN 0 +#define TX_STATE_BOTH_FREE_EVEN_FIRST 0 +#define TX_STATE_BOTH_FREE_ODD_FIRST 1 +#define TX_STATE_EVEN_FREE 2 +#define TX_STATE_ODD_FREE 3 +#define TX_STATE_NONE_FREE_EVEN_FIRST 4 +#define TX_STATE_NONE_FREE_ODD_FIRST 5 + +#define BDT_OWN 0x80 +#define BDT_DATA1 0x40 +#define BDT_DATA0 0x00 +#define BDT_DTS 0x08 +#define BDT_STALL 0x04 + +#define TX 1 +#define RX 0 +#define ODD 1 +#define EVEN 0 #define DATA0 0 #define DATA1 1 + + +#define GET_STATUS 0 +#define CLEAR_FEATURE 1 +#define SET_FEATURE 3 +#define SET_ADDRESS 5 +#define GET_DESCRIPTOR 6 +#define SET_DESCRIPTOR 7 +#define GET_CONFIGURATION 8 +#define SET_CONFIGURATION 9 +#define GET_INTERFACE 10 +#define SET_INTERFACE 11 +#define SYNCH_FRAME 12 + +#define TX_STATE_BOTH_FREE_EVEN_FIRST 0 +#define TX_STATE_BOTH_FREE_ODD_FIRST 1 +#define TX_STATE_EVEN_FREE 2 +#define TX_STATE_ODD_FREE 3 +#define TX_STATE_NONE_FREE 4 + + + + + +// ----- Macros ----- + +#define BDT_PID(n) (((n) >> 2) & 15) + +#define BDT_DESC(count, data) (BDT_OWN | BDT_DTS \ + | ((data) ? BDT_DATA1 : BDT_DATA0) \ + | ((count) << 16)) + #define index(endpoint, tx, odd) (((endpoint) << 2) | ((tx) << 1) | (odd)) #define stat2bufferdescriptor(stat) (table + ((stat) >> 2)) + +// ----- Structs ----- + +// buffer descriptor table + +typedef struct { + uint32_t desc; + void * addr; +} bdt_t; + static union { - struct { - union { - struct { - uint8_t bmRequestType; - uint8_t bRequest; - }; - uint16_t wRequestAndType; - }; - uint16_t wValue; - uint16_t wIndex; - uint16_t wLength; - }; - struct { - uint32_t word1; - uint32_t word2; - }; + struct { + union { + struct { + uint8_t bmRequestType; + uint8_t bRequest; + }; + uint16_t wRequestAndType; + }; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; + }; + struct { + uint32_t word1; + uint32_t word2; + }; } setup; -#define GET_STATUS 0 -#define CLEAR_FEATURE 1 -#define SET_FEATURE 3 -#define SET_ADDRESS 5 -#define GET_DESCRIPTOR 6 -#define SET_DESCRIPTOR 7 -#define GET_CONFIGURATION 8 -#define SET_CONFIGURATION 9 -#define GET_INTERFACE 10 -#define SET_INTERFACE 11 -#define SYNCH_FRAME 12 + +// ----- Variables ----- + +__attribute__ ((section(".usbdescriptortable"), used)) +static bdt_t table[ (NUM_ENDPOINTS + 1) * 4 ]; + +static usb_packet_t *rx_first [ NUM_ENDPOINTS ]; +static usb_packet_t *rx_last [ NUM_ENDPOINTS ]; +static usb_packet_t *tx_first [ NUM_ENDPOINTS ]; +static usb_packet_t *tx_last [ NUM_ENDPOINTS ]; +uint16_t usb_rx_byte_count_data[ NUM_ENDPOINTS ]; + +static uint8_t tx_state[NUM_ENDPOINTS]; // SETUP always uses a DATA0 PID for the data field of the SETUP transaction. // transactions in the data phase start with DATA1 and toggle (figure 8-12, USB1.1) @@ -124,32 +166,29 @@ uint8_t usb_rx_memory_needed = 0; volatile uint8_t usb_configuration = 0; volatile uint8_t usb_reboot_timer = 0; +static uint8_t reply_buffer[8]; + + + +// ----- Functions ----- -static void endpoint0_stall(void) +static void endpoint0_stall() { + #ifdef UART_DEBUG_UNKNOWN + print("STALL" NL ); + #endif USB0_ENDPT0 = USB_ENDPT_EPSTALL | USB_ENDPT_EPRXEN | USB_ENDPT_EPTXEN | USB_ENDPT_EPHSHK; } - -static void endpoint0_transmit(const void *data, uint32_t len) +static void endpoint0_transmit( const void *data, uint32_t len ) { -#if 0 - serial_print("tx0:"); - serial_phex32((uint32_t)data); - serial_print(","); - serial_phex16(len); - serial_print(ep0_tx_bdt_bank ? ", odd" : ", even"); - serial_print(ep0_tx_data_toggle ? ", d1\n" : ", d0\n"); -#endif table[index(0, TX, ep0_tx_bdt_bank)].addr = (void *)data; table[index(0, TX, ep0_tx_bdt_bank)].desc = BDT_DESC(len, ep0_tx_data_toggle); ep0_tx_data_toggle ^= 1; ep0_tx_bdt_bank ^= 1; } -static uint8_t reply_buffer[8]; - -static void usb_setup(void) +static void usb_setup() { const uint8_t *data = NULL; uint32_t datalen = 0; @@ -160,214 +199,350 @@ static void usb_setup(void) const uint8_t *cfg; int i; - switch (setup.wRequestAndType) { - case 0x0500: // SET_ADDRESS - break; - case 0x0900: // SET_CONFIGURATION - //serial_print("configure\n"); + switch ( setup.wRequestAndType ) + { + case 0x0500: // SET_ADDRESS + goto send; + + case 0x0900: // SET_CONFIGURATION + #ifdef UART_DEBUG + print("CONFIGURE - "); + #endif usb_configuration = setup.wValue; + Output_Available = usb_configuration; reg = &USB0_ENDPT1; cfg = usb_endpoint_config_table; // clear all BDT entries, free any allocated memory... - for (i=4; i < (NUM_ENDPOINTS+1)*4; i++) { - if (table[i].desc & BDT_OWN) { - usb_free((usb_packet_t *)((uint8_t *)(table[i].addr) - 8)); + for ( i = 4; i < ( NUM_ENDPOINTS + 1) * 4; i++ ) + { + if ( table[i].desc & BDT_OWN ) + { + usb_free( (usb_packet_t *)((uint8_t *)(table[ i ].addr) - 8) ); } } // free all queued packets - for (i=0; i < NUM_ENDPOINTS; i++) { + for ( i = 0; i < NUM_ENDPOINTS; i++ ) + { usb_packet_t *p, *n; p = rx_first[i]; - while (p) { + while ( p ) + { n = p->next; usb_free(p); p = n; } - rx_first[i] = NULL; - rx_last[i] = NULL; + rx_first[ i ] = NULL; + rx_last[ i ] = NULL; p = tx_first[i]; - while (p) { + while (p) + { n = p->next; usb_free(p); p = n; } - tx_first[i] = NULL; - tx_last[i] = NULL; + tx_first[ i ] = NULL; + tx_last[ i ] = NULL; usb_rx_byte_count_data[i] = 0; - switch (tx_state[i]) { - case TX_STATE_EVEN_FREE: - case TX_STATE_NONE_FREE_EVEN_FIRST: - tx_state[i] = TX_STATE_BOTH_FREE_EVEN_FIRST; + + switch ( tx_state[ i ] ) + { + case TX_STATE_EVEN_FREE: + case TX_STATE_NONE_FREE_EVEN_FIRST: + tx_state[ i ] = TX_STATE_BOTH_FREE_EVEN_FIRST; break; - case TX_STATE_ODD_FREE: - case TX_STATE_NONE_FREE_ODD_FIRST: - tx_state[i] = TX_STATE_BOTH_FREE_ODD_FIRST; + case TX_STATE_ODD_FREE: + case TX_STATE_NONE_FREE_ODD_FIRST: + tx_state[ i ] = TX_STATE_BOTH_FREE_ODD_FIRST; break; - default: + default: break; } } usb_rx_memory_needed = 0; - for (i=1; i <= NUM_ENDPOINTS; i++) { + for ( i = 1; i <= NUM_ENDPOINTS; i++ ) + { epconf = *cfg++; *reg = epconf; reg += 4; - if (epconf & USB_ENDPT_EPRXEN) { + if ( epconf & USB_ENDPT_EPRXEN ) + { usb_packet_t *p; p = usb_malloc(); - if (p) { - table[index(i, RX, EVEN)].addr = p->buf; - table[index(i, RX, EVEN)].desc = BDT_DESC(64, 0); - } else { - table[index(i, RX, EVEN)].desc = 0; + if ( p ) + { + table[ index( i, RX, EVEN ) ].addr = p->buf; + table[ index( i, RX, EVEN ) ].desc = BDT_DESC( 64, 0 ); + } + else + { + table[ index( i, RX, EVEN ) ].desc = 0; usb_rx_memory_needed++; } p = usb_malloc(); - if (p) { - table[index(i, RX, ODD)].addr = p->buf; - table[index(i, RX, ODD)].desc = BDT_DESC(64, 1); - } else { - table[index(i, RX, ODD)].desc = 0; + if ( p ) + { + table[ index( i, RX, ODD ) ].addr = p->buf; + table[ index( i, RX, ODD ) ].desc = BDT_DESC( 64, 1 ); + } + else + { + table[ index( i, RX, ODD ) ].desc = 0; usb_rx_memory_needed++; } } - table[index(i, TX, EVEN)].desc = 0; - table[index(i, TX, ODD)].desc = 0; + table[ index( i, TX, EVEN ) ].desc = 0; + table[ index( i, TX, ODD ) ].desc = 0; } - break; - case 0x0880: // GET_CONFIGURATION + goto send; + + case 0x0880: // GET_CONFIGURATION reply_buffer[0] = usb_configuration; datalen = 1; data = reply_buffer; - break; - case 0x0080: // GET_STATUS (device) + goto send; + + case 0x0080: // GET_STATUS (device) reply_buffer[0] = 0; reply_buffer[1] = 0; datalen = 2; data = reply_buffer; - break; - case 0x0082: // GET_STATUS (endpoint) - if (setup.wIndex > NUM_ENDPOINTS) { + goto send; + + case 0x0082: // GET_STATUS (endpoint) + if ( setup.wIndex > NUM_ENDPOINTS ) + { // TODO: do we need to handle IN vs OUT here? endpoint0_stall(); return; } reply_buffer[0] = 0; reply_buffer[1] = 0; - if (*(uint8_t *)(&USB0_ENDPT0 + setup.wIndex * 4) & 0x02) reply_buffer[0] = 1; + if ( *(uint8_t *)(&USB0_ENDPT0 + setup.wIndex * 4) & 0x02 ) + reply_buffer[0] = 1; data = reply_buffer; datalen = 2; - break; - case 0x0102: // CLEAR_FEATURE (endpoint) + goto send; + + case 0x0100: // CLEAR_FEATURE (device) + case 0x0101: // CLEAR_FEATURE (interface) + // TODO: Currently ignoring, perhaps useful? -HaaTa + warn_print("CLEAR_FEATURE - Device/Interface"); + endpoint0_stall(); + return; + + case 0x0102: // CLEAR_FEATURE (interface) i = setup.wIndex & 0x7F; - if (i > NUM_ENDPOINTS || setup.wValue != 0) { - // TODO: do we need to handle IN vs OUT here? + if ( i > NUM_ENDPOINTS || setup.wValue != 0 ) + { endpoint0_stall(); return; } - (*(uint8_t *)(&USB0_ENDPT0 + setup.wIndex * 4)) &= ~0x02; + warn_print("CLEAR_FEATURE - Interface"); + //(*(uint8_t *)(&USB0_ENDPT0 + setup.wIndex * 4)) &= ~0x02; // TODO: do we need to clear the data toggle here? - break; - case 0x0302: // SET_FEATURE (endpoint) + //break; + + // FIXME: Clearing causes keyboard to freeze, likely an invalid clear + // XXX: Ignoring seems to work, though this may not be the ideal behaviour -HaaTa + endpoint0_stall(); + return; + + case 0x0300: // SET_FEATURE (device) + case 0x0301: // SET_FEATURE (interface) + // TODO: Currently ignoring, perhaps useful? -HaaTa + warn_print("SET_FEATURE"); + endpoint0_stall(); + return; + + case 0x0302: // SET_FEATURE (endpoint) i = setup.wIndex & 0x7F; - if (i > NUM_ENDPOINTS || setup.wValue != 0) { + if ( i > NUM_ENDPOINTS || setup.wValue != 0 ) + { // TODO: do we need to handle IN vs OUT here? endpoint0_stall(); return; } (*(uint8_t *)(&USB0_ENDPT0 + setup.wIndex * 4)) |= 0x02; // TODO: do we need to clear the data toggle here? - break; - case 0x0680: // GET_DESCRIPTOR - case 0x0681: - //serial_print("desc:"); - //serial_phex16(setup.wValue); - //serial_print("\n"); - for (list = usb_descriptor_list; 1; list++) { - if (list->addr == NULL) break; - //if (setup.wValue == list->wValue && - //(setup.wIndex == list->wIndex) || ((setup.wValue >> 8) == 3)) { - if (setup.wValue == list->wValue && setup.wIndex == list->wIndex) { + goto send; + + case 0x0680: // GET_DESCRIPTOR + case 0x0681: + #ifdef UART_DEBUG + print("desc:"); + printHex( setup.wValue ); + print( NL ); + #endif + for ( list = usb_descriptor_list; 1; list++ ) + { + if ( list->addr == NULL ) + break; + if ( setup.wValue == list->wValue && setup.wIndex == list->wIndex ) + { data = list->addr; - if ((setup.wValue >> 8) == 3) { + if ( (setup.wValue >> 8) == 3 ) + { // for string descriptors, use the descriptor's // length field, allowing runtime configured // length. datalen = *(list->addr); - } else { + } + else + { datalen = list->length; } -#if 0 - serial_print("Desc found, "); - serial_phex32((uint32_t)data); - serial_print(","); - serial_phex16(datalen); - serial_print(","); - serial_phex(data[0]); - serial_phex(data[1]); - serial_phex(data[2]); - serial_phex(data[3]); - serial_phex(data[4]); - serial_phex(data[5]); - serial_print("\n"); -#endif + #if UART_DEBUG + print("Desc found, "); + printHex32( (uint32_t)data ); + print(","); + printHex( datalen ); + print(","); + printHex_op( data[0], 2 ); + printHex_op( data[1], 2 ); + printHex_op( data[2], 2 ); + printHex_op( data[3], 2 ); + printHex_op( data[4], 2 ); + printHex_op( data[5], 2 ); + print( NL ); + #endif goto send; } } - //serial_print("desc: not found\n"); + #ifdef UART_DEBUG + print( "desc: not found" NL ); + #endif endpoint0_stall(); return; -#if defined(CDC_STATUS_INTERFACE) - case 0x2221: // CDC_SET_CONTROL_LINE_STATE + + case 0x2221: // CDC_SET_CONTROL_LINE_STATE usb_cdc_line_rtsdtr = setup.wValue; //serial_print("set control line state\n"); - break; - case 0x2021: // CDC_SET_LINE_CODING + goto send; + + case 0x21A1: // CDC_GET_LINE_CODING + data = (uint8_t*)usb_cdc_line_coding; + datalen = sizeof( usb_cdc_line_coding ); + goto send; + + case 0x2021: // CDC_SET_LINE_CODING + // XXX Needed? //serial_print("set coding, waiting...\n"); return; -#endif -// TODO: this does not work... why? -#if defined(SEREMU_INTERFACE) || defined(KEYBOARD_INTERFACE) - case 0x0921: // HID SET_REPORT - //serial_print(":)\n"); + case 0x0921: // HID SET_REPORT + #ifdef UART_DEBUG + warn_msg("SET_REPORT - "); + printHex( setup.wValue ); + print(" - "); + printHex( setup.wValue & 0xFF ); + print( NL ); + #endif + USBKeys_LEDs = setup.wValue & 0xFF; + + // Must be stall for some reason... -HaaTa + endpoint0_stall(); return; - case 0x0A21: // HID SET_IDLE - break; - // case 0xC940: -#endif - default: + + case 0x01A1: // HID GET_REPORT + #ifdef UART_DEBUG + print("GET_REPORT - "); + printHex( setup.wIndex ); + print(NL); + #endif + // Search through descriptors returning necessary info + for ( list = usb_descriptor_list; 1; list++ ) + { + if ( list->addr == NULL ) + break; + if ( list->wValue != 0x2200 ) + continue; + if ( setup.wIndex == list->wIndex ) + { + data = list->addr; + datalen = list->length; + goto send; + } + } + endpoint0_stall(); + return; + + case 0x0A21: // HID SET_IDLE + #ifdef UART_DEBUG + print("SET_IDLE - "); + printHex( setup.wValue ); + print(NL); + #endif + USBKeys_Idle_Config = (setup.wValue >> 8); + USBKeys_Idle_Count = 0; + goto send; + + case 0x0B21: // HID SET_PROTOCOL + #ifdef UART_DEBUG + print("SET_PROTOCOL - "); + printHex( setup.wValue ); + print(" - "); + printHex( setup.wValue & 0xFF ); + print(NL); + #endif + USBKeys_Protocol = setup.wValue & 0xFF; // 0 - Boot Mode, 1 - NKRO Mode + goto send; + + // case 0xC940: + default: + #ifdef UART_DEBUG_UNKNOWN + print("UNKNOWN"); + #endif endpoint0_stall(); return; } - send: - //serial_print("setup send "); - //serial_phex32(data); - //serial_print(","); - //serial_phex16(datalen); - //serial_print("\n"); - if (datalen > setup.wLength) datalen = setup.wLength; +send: + #ifdef UART_DEBUG + print("setup send "); + printHex32( (uint32_t)data ); + print(","); + for ( uint8_t c = 0; c < datalen; c++ ) + { + printHex( data[c] ); + print(" "); + } + print(","); + printHex( datalen ); + print( NL ); + #endif + + if ( datalen > setup.wLength ) + datalen = setup.wLength; + size = datalen; - if (size > EP0_SIZE) size = EP0_SIZE; + if ( size > EP0_SIZE ) + size = EP0_SIZE; + endpoint0_transmit(data, size); data += size; datalen -= size; - if (datalen == 0 && size < EP0_SIZE) return; + + // See if transmit has finished + if ( datalen == 0 && size < EP0_SIZE ) + return; size = datalen; - if (size > EP0_SIZE) size = EP0_SIZE; + if ( size > EP0_SIZE ) + size = EP0_SIZE; endpoint0_transmit(data, size); data += size; datalen -= size; - if (datalen == 0 && size < EP0_SIZE) return; + // See if transmit has finished + if ( datalen == 0 && size < EP0_SIZE ) + return; + + // Save rest of transfer for later? XXX ep0_tx_ptr = data; ep0_tx_len = datalen; } - //A bulk endpoint's toggle sequence is initialized to DATA0 when the endpoint //experiences any configuration event (configuration events are explained in //Sections 9.1.1.5 and 9.4.5). @@ -381,28 +556,29 @@ static void usb_setup(void) //Halt feature set, a ClearFeature(ENDPOINT_HALT) request always results in the //data toggle being reinitialized to DATA0. - - -// #define stat2bufferdescriptor(stat) (table + ((stat) >> 2)) - -static void usb_control(uint32_t stat) +static void usb_control( uint32_t stat ) { + #ifdef UART_DEBUG + print("CONTROL - "); + #endif bdt_t *b; uint32_t pid, size; uint8_t *buf; const uint8_t *data; - b = stat2bufferdescriptor(stat); - pid = BDT_PID(b->desc); - //count = b->desc >> 16; + b = stat2bufferdescriptor( stat ); + pid = BDT_PID( b->desc ); buf = b->addr; - //serial_print("pid:"); - //serial_phex(pid); - //serial_print(", count:"); - //serial_phex(count); - //serial_print("\n"); - - switch (pid) { + #ifdef UART_DEBUG + print("pid:"); + printHex(pid); + print(", count:"); + printHex32(b->desc); + print(" - "); + #endif + + switch (pid) + { case 0x0D: // Setup received from host //serial_print("PID=Setup\n"); //if (count != 8) ; // panic? @@ -411,13 +587,14 @@ static void usb_control(uint32_t stat) setup.word2 = *(uint32_t *)(buf + 4); // give the buffer back - b->desc = BDT_DESC(EP0_SIZE, DATA1); + b->desc = BDT_DESC( EP0_SIZE, DATA1 ); //table[index(0, RX, EVEN)].desc = BDT_DESC(EP0_SIZE, 1); //table[index(0, RX, ODD)].desc = BDT_DESC(EP0_SIZE, 1); // clear any leftover pending IN transactions ep0_tx_ptr = NULL; - if (ep0_tx_data_toggle) { + if ( ep0_tx_data_toggle ) + { } //if (table[index(0, TX, EVEN)].desc & 0x80) { //serial_print("leftover tx even\n"); @@ -430,60 +607,76 @@ static void usb_control(uint32_t stat) // first IN after Setup is always DATA1 ep0_tx_data_toggle = 1; -#if 0 - serial_print("bmRequestType:"); - serial_phex(setup.bmRequestType); - serial_print(", bRequest:"); - serial_phex(setup.bRequest); - serial_print(", wValue:"); - serial_phex16(setup.wValue); - serial_print(", wIndex:"); - serial_phex16(setup.wIndex); - serial_print(", len:"); - serial_phex16(setup.wLength); - serial_print("\n"); -#endif + #ifdef UART_DEBUG_UNKNOWN + print("bmRequestType:"); + printHex(setup.bmRequestType); + print(", bRequest:"); + printHex(setup.bRequest); + print(", wValue:"); + printHex(setup.wValue); + print(", wIndex:"); + printHex(setup.wIndex); + print(", len:"); + printHex(setup.wLength); + print(NL); + #endif // actually "do" the setup request usb_setup(); // unfreeze the USB, now that we're ready USB0_CTL = USB_CTL_USBENSOFEN; // clear TXSUSPENDTOKENBUSY bit break; + case 0x01: // OUT transaction received from host case 0x02: - //serial_print("PID=OUT\n"); -#ifdef CDC_STATUS_INTERFACE - if (setup.wRequestAndType == 0x2021 /*CDC_SET_LINE_CODING*/) { + #ifdef UART_DEBUG + print("PID=OUT"NL); + #endif + // CDC Interface + if ( setup.wRequestAndType == 0x2021 /*CDC_SET_LINE_CODING*/ ) + { int i; uint8_t *dst = (uint8_t *)usb_cdc_line_coding; //serial_print("set line coding "); - for (i=0; i<7; i++) { + for ( i = 0; i < 7; i++ ) + { //serial_phex(*buf); *dst++ = *buf++; } //serial_phex32(usb_cdc_line_coding[0]); //serial_print("\n"); - if (usb_cdc_line_coding[0] == 134) usb_reboot_timer = 15; - endpoint0_transmit(NULL, 0); + if ( usb_cdc_line_coding[0] == 134 ) + usb_reboot_timer = 15; + endpoint0_transmit( NULL, 0 ); } -#endif -#ifdef KEYBOARD_INTERFACE - if (setup.word1 == 0x02000921 && setup.word2 == ((1<<16)|KEYBOARD_INTERFACE)) { + + // Keyboard Interface + if ( setup.word1 == 0x02000921 && setup.word2 == ( (1<<16) | KEYBOARD_INTERFACE ) ) + { USBKeys_LEDs = buf[0]; - endpoint0_transmit(NULL, 0); + endpoint0_transmit( NULL, 0 ); } -#endif + // NKRO Keyboard Interface + if ( setup.word1 == 0x02000921 && setup.word2 == ( (1<<16) | NKRO_KEYBOARD_INTERFACE ) ) + { + USBKeys_LEDs = buf[0]; + endpoint0_transmit( NULL, 0 ); + } + // give the buffer back - b->desc = BDT_DESC(EP0_SIZE, DATA1); + b->desc = BDT_DESC( EP0_SIZE, DATA1 ); break; case 0x09: // IN transaction completed to host - //serial_print("PID=IN:"); - //serial_phex(stat); - //serial_print("\n"); + #ifdef UART_DEBUG + print("PID=IN:"); + printHex(stat); + print(NL); + #endif // send remaining data, if any... data = ep0_tx_ptr; - if (data) { + if ( data ) + { size = ep0_tx_len; if (size > EP0_SIZE) size = EP0_SIZE; endpoint0_transmit(data, size); @@ -492,48 +685,42 @@ static void usb_control(uint32_t stat) ep0_tx_ptr = (ep0_tx_len > 0 || size == EP0_SIZE) ? data : NULL; } - if (setup.bRequest == 5 && setup.bmRequestType == 0) { + if ( setup.bRequest == 5 && setup.bmRequestType == 0 ) + { setup.bRequest = 0; - //serial_print("set address: "); - //serial_phex16(setup.wValue); - //serial_print("\n"); + #ifdef UART_DEBUG + print("set address: "); + printHex(setup.wValue); + print(NL); + #endif USB0_ADDR = setup.wValue; } break; - //default: - //serial_print("PID=unknown:"); - //serial_phex(pid); - //serial_print("\n"); + + default: + #ifdef UART_DEBUG + print("PID=unknown:"); + printHex(pid); + print(NL); + #endif + break; } USB0_CTL = USB_CTL_USBENSOFEN; // clear TXSUSPENDTOKENBUSY bit } - - -static usb_packet_t *rx_first[NUM_ENDPOINTS]; -static usb_packet_t *rx_last[NUM_ENDPOINTS]; -static usb_packet_t *tx_first[NUM_ENDPOINTS]; -static usb_packet_t *tx_last[NUM_ENDPOINTS]; - -static uint8_t tx_state[NUM_ENDPOINTS]; -#define TX_STATE_BOTH_FREE_EVEN_FIRST 0 -#define TX_STATE_BOTH_FREE_ODD_FIRST 1 -#define TX_STATE_EVEN_FREE 2 -#define TX_STATE_ODD_FREE 3 -#define TX_STATE_NONE_FREE 4 - - - -usb_packet_t *usb_rx(uint32_t endpoint) +usb_packet_t *usb_rx( uint32_t endpoint ) { + //print("USB RX"); usb_packet_t *ret; endpoint--; - if (endpoint >= NUM_ENDPOINTS) return NULL; + if ( endpoint >= NUM_ENDPOINTS ) + return NULL; __disable_irq(); ret = rx_first[endpoint]; - if (ret) rx_first[endpoint] = ret->next; - usb_rx_byte_count_data[endpoint] -= ret->len; + if ( ret ) + rx_first[ endpoint ] = ret->next; + usb_rx_byte_count_data[ endpoint ] -= ret->len; __enable_irq(); //serial_print("rx, epidx="); //serial_phex(endpoint); @@ -543,34 +730,38 @@ usb_packet_t *usb_rx(uint32_t endpoint) return ret; } -static uint32_t usb_queue_byte_count(const usb_packet_t *p) +static uint32_t usb_queue_byte_count( const usb_packet_t *p ) { uint32_t count=0; __disable_irq(); - for ( ; p; p = p->next) { + for ( ; p; p = p->next ) + { count += p->len; } __enable_irq(); return count; } -uint32_t usb_tx_byte_count(uint32_t endpoint) +uint32_t usb_tx_byte_count( uint32_t endpoint ) { endpoint--; - if (endpoint >= NUM_ENDPOINTS) return 0; - return usb_queue_byte_count(tx_first[endpoint]); + if ( endpoint >= NUM_ENDPOINTS ) + return 0; + return usb_queue_byte_count( tx_first[ endpoint ] ); } -uint32_t usb_tx_packet_count(uint32_t endpoint) +uint32_t usb_tx_packet_count( uint32_t endpoint ) { const usb_packet_t *p; uint32_t count=0; endpoint--; - if (endpoint >= NUM_ENDPOINTS) return 0; + if ( endpoint >= NUM_ENDPOINTS ) + return 0; __disable_irq(); - for (p = tx_first[endpoint]; p; p = p->next) count++; + for ( p = tx_first[ endpoint ]; p; p = p->next ) + count++; __enable_irq(); return count; } @@ -584,28 +775,33 @@ uint32_t usb_tx_packet_count(uint32_t endpoint) // without this prioritization. The packet buffer (input) is assigned to the // first endpoint needing memory. // -void usb_rx_memory(usb_packet_t *packet) +void usb_rx_memory( usb_packet_t *packet ) { + //print("USB RX MEMORY"); unsigned int i; const uint8_t *cfg; cfg = usb_endpoint_config_table; //serial_print("rx_mem:"); __disable_irq(); - for (i=1; i <= NUM_ENDPOINTS; i++) { - if (*cfg++ & USB_ENDPT_EPRXEN) { - if (table[index(i, RX, EVEN)].desc == 0) { - table[index(i, RX, EVEN)].addr = packet->buf; - table[index(i, RX, EVEN)].desc = BDT_DESC(64, 0); + for ( i = 1; i <= NUM_ENDPOINTS; i++ ) + { + if ( *cfg++ & USB_ENDPT_EPRXEN ) + { + if ( table[ index( i, RX, EVEN ) ].desc == 0 ) + { + table[ index( i, RX, EVEN ) ].addr = packet->buf; + table[ index( i, RX, EVEN ) ].desc = BDT_DESC( 64, 0 ); usb_rx_memory_needed--; __enable_irq(); //serial_phex(i); //serial_print(",even\n"); return; } - if (table[index(i, RX, ODD)].desc == 0) { - table[index(i, RX, ODD)].addr = packet->buf; - table[index(i, RX, ODD)].desc = BDT_DESC(64, 1); + if ( table[ index( i, RX, ODD ) ].desc == 0 ) + { + table[ index( i, RX, ODD ) ].addr = packet->buf; + table[ index( i, RX, ODD ) ].desc = BDT_DESC( 64, 1 ); usb_rx_memory_needed--; __enable_irq(); //serial_phex(i); @@ -617,74 +813,113 @@ void usb_rx_memory(usb_packet_t *packet) __enable_irq(); // we should never reach this point. If we get here, it means // usb_rx_memory_needed was set greater than zero, but no memory - // was actually needed. + // was actually needed. usb_rx_memory_needed = 0; - usb_free(packet); + usb_free( packet ); return; } //#define index(endpoint, tx, odd) (((endpoint) << 2) | ((tx) << 1) | (odd)) //#define stat2bufferdescriptor(stat) (table + ((stat) >> 2)) -void usb_tx(uint32_t endpoint, usb_packet_t *packet) +void usb_tx( uint32_t endpoint, usb_packet_t *packet ) { - bdt_t *b = &table[index(endpoint, TX, EVEN)]; + bdt_t *b = &table[ index( endpoint, TX, EVEN ) ]; uint8_t next; endpoint--; - if (endpoint >= NUM_ENDPOINTS) return; + if ( endpoint >= NUM_ENDPOINTS ) + return; __disable_irq(); //serial_print("txstate="); - //serial_phex(tx_state[endpoint]); + //serial_phex(tx_state[ endpoint ]); //serial_print("\n"); - switch (tx_state[endpoint]) { - case TX_STATE_BOTH_FREE_EVEN_FIRST: + switch ( tx_state[ endpoint ] ) + { + case TX_STATE_BOTH_FREE_EVEN_FIRST: next = TX_STATE_ODD_FREE; break; - case TX_STATE_BOTH_FREE_ODD_FIRST: + case TX_STATE_BOTH_FREE_ODD_FIRST: b++; next = TX_STATE_EVEN_FREE; break; - case TX_STATE_EVEN_FREE: + case TX_STATE_EVEN_FREE: next = TX_STATE_NONE_FREE_ODD_FIRST; break; - case TX_STATE_ODD_FREE: + case TX_STATE_ODD_FREE: b++; next = TX_STATE_NONE_FREE_EVEN_FIRST; break; - default: - if (tx_first[endpoint] == NULL) { - tx_first[endpoint] = packet; - } else { - tx_last[endpoint]->next = packet; + default: + if (tx_first[ endpoint ] == NULL) + { + tx_first[ endpoint ] = packet; + } + else + { + tx_last[ endpoint ]->next = packet; } - tx_last[endpoint] = packet; + tx_last[ endpoint ] = packet; __enable_irq(); return; } - tx_state[endpoint] = next; + + tx_state[ endpoint ] = next; b->addr = packet->buf; - b->desc = BDT_DESC(packet->len, ((uint32_t)b & 8) ? DATA1 : DATA0); + b->desc = BDT_DESC( packet->len, ((uint32_t)b & 8) ? DATA1 : DATA0 ); __enable_irq(); } - void usb_device_reload() { - asm volatile("bkpt"); -} + if ( flashModeEnabled_define == 0 ) + { + print( NL ); + warn_print("flashModeEnabled not set, cancelling firmware reload..."); + info_msg("Set flashModeEnabled to 1 in your kll configuration."); + return; + } + +// MCHCK +#if defined(_mk20dx128vlf5_) + + // MCHCK Kiibohd Variant + // Check to see if PTA3 (has a pull-up) is connected to GND (usually via jumper) + // Only allow reload if the jumper is present (security) + GPIOA_PDDR &= ~(1<<3); // Input + PORTA_PCR3 = PORT_PCR_PFE | PORT_PCR_MUX(1); // Internal pull-up + + // Check for jumper + if ( GPIOA_PDIR & (1<<3) && flashModeEnabled_define != 0 ) + { + print( NL ); + warn_print("Security jumper not present, cancelling firmware reload..."); + info_msg("Replace jumper on middle 2 pins, or manually press the firmware reload button."); + } + else + { + // Copies variable into the VBAT register, must be identical to the variable in the bootloader to jump to the bootloader flash mode + for ( int pos = 0; pos < sizeof(sys_reset_to_loader_magic); pos++ ) + (&VBAT)[ pos ] = sys_reset_to_loader_magic[ pos ]; + SOFTWARE_RESET(); + } +// Kiibohd mk20dx256vlh7 +#elif defined(_mk20dx256vlh7_) + // Copies variable into the VBAT register, must be identical to the variable in the bootloader to jump to the bootloader flash mode + for ( int pos = 0; pos < sizeof(sys_reset_to_loader_magic); pos++ ) + (&VBAT)[ pos ] = sys_reset_to_loader_magic[ pos ]; + SOFTWARE_RESET(); -void _reboot_Teensyduino_(void) -{ - // TODO: initialize R0 with a code.... +// Teensy 3.0 and 3.1 +#else asm volatile("bkpt"); +#endif } - -void usb_isr(void) +void usb_isr() { uint8_t status, stat, t; @@ -692,28 +927,41 @@ void usb_isr(void) //status = USB0_ISTAT; //serial_phex(status); //serial_print("\n"); - restart: +restart: status = USB0_ISTAT; - - if ((status & USB_INTEN_SOFTOKEN /* 04 */ )) { - if (usb_configuration) { + /* + print("USB ISR STATUS: "); + printHex( status ); + print( NL ); + */ + + if ( (status & USB_INTEN_SOFTOKEN /* 04 */ ) ) + { + if ( usb_configuration ) + { t = usb_reboot_timer; - if (t) { + if ( t ) + { usb_reboot_timer = --t; - if (!t) _reboot_Teensyduino_(); + if ( !t ) + usb_device_reload(); } -#ifdef CDC_DATA_INTERFACE + + // CDC Interface t = usb_cdc_transmit_flush_timer; - if (t) { + if ( t ) + { usb_cdc_transmit_flush_timer = --t; - if (t == 0) usb_serial_flush_callback(); + if ( t == 0 ) + usb_serial_flush_callback(); } -#endif + } USB0_ISTAT = USB_INTEN_SOFTOKEN; } - if ((status & USB_ISTAT_TOKDNE /* 08 */ )) { + if ( (status & USB_ISTAT_TOKDNE /* 08 */ ) ) + { uint8_t endpoint; stat = USB0_STAT; //serial_print("token: ep="); @@ -721,9 +969,12 @@ void usb_isr(void) //serial_print(stat & 0x08 ? ",tx" : ",rx"); //serial_print(stat & 0x04 ? ",odd\n" : ",even\n"); endpoint = stat >> 4; - if (endpoint == 0) { - usb_control(stat); - } else { + if ( endpoint == 0 ) + { + usb_control( stat ); + } + else + { bdt_t *b = stat2bufferdescriptor(stat); usb_packet_t *packet = (usb_packet_t *)((uint8_t *)(b->addr) - 8); #if 0 @@ -736,88 +987,104 @@ void usb_isr(void) serial_phex(b->desc >> 16); serial_print("\n"); #endif - endpoint--; // endpoint is index to zero-based arrays - - if (stat & 0x08) { // transmit - usb_free(packet); - packet = tx_first[endpoint]; - if (packet) { + endpoint--; // endpoint is index to zero-based arrays + + if ( stat & 0x08 ) + { // transmit + usb_free( packet ); + packet = tx_first[ endpoint ]; + if ( packet ) + { //serial_print("tx packet\n"); tx_first[endpoint] = packet->next; b->addr = packet->buf; - switch (tx_state[endpoint]) { - case TX_STATE_BOTH_FREE_EVEN_FIRST: - tx_state[endpoint] = TX_STATE_ODD_FREE; + switch ( tx_state[ endpoint ] ) + { + case TX_STATE_BOTH_FREE_EVEN_FIRST: + tx_state[ endpoint ] = TX_STATE_ODD_FREE; break; - case TX_STATE_BOTH_FREE_ODD_FIRST: - tx_state[endpoint] = TX_STATE_EVEN_FREE; + case TX_STATE_BOTH_FREE_ODD_FIRST: + tx_state[ endpoint ] = TX_STATE_EVEN_FREE; break; - case TX_STATE_EVEN_FREE: - tx_state[endpoint] = TX_STATE_NONE_FREE_ODD_FIRST; + case TX_STATE_EVEN_FREE: + tx_state[ endpoint ] = TX_STATE_NONE_FREE_ODD_FIRST; break; - case TX_STATE_ODD_FREE: - tx_state[endpoint] = TX_STATE_NONE_FREE_EVEN_FIRST; + case TX_STATE_ODD_FREE: + tx_state[ endpoint ] = TX_STATE_NONE_FREE_EVEN_FIRST; break; - default: + default: break; } - b->desc = BDT_DESC(packet->len, ((uint32_t)b & 8) ? DATA1 : DATA0); + b->desc = BDT_DESC( packet->len, ((uint32_t)b & 8) ? DATA1 : DATA0 ); } else { //serial_print("tx no packet\n"); - switch (tx_state[endpoint]) { - case TX_STATE_BOTH_FREE_EVEN_FIRST: - case TX_STATE_BOTH_FREE_ODD_FIRST: + switch ( tx_state[ endpoint ] ) + { + case TX_STATE_BOTH_FREE_EVEN_FIRST: + case TX_STATE_BOTH_FREE_ODD_FIRST: break; - case TX_STATE_EVEN_FREE: - tx_state[endpoint] = TX_STATE_BOTH_FREE_EVEN_FIRST; + case TX_STATE_EVEN_FREE: + tx_state[ endpoint ] = TX_STATE_BOTH_FREE_EVEN_FIRST; break; - case TX_STATE_ODD_FREE: - tx_state[endpoint] = TX_STATE_BOTH_FREE_ODD_FIRST; + case TX_STATE_ODD_FREE: + tx_state[ endpoint ] = TX_STATE_BOTH_FREE_ODD_FIRST; break; - default: - tx_state[endpoint] = ((uint32_t)b & 8) ? - TX_STATE_ODD_FREE : TX_STATE_EVEN_FREE; + default: + tx_state[ endpoint ] = ((uint32_t)b & 8) + ? TX_STATE_ODD_FREE + : TX_STATE_EVEN_FREE; break; } } - } else { // receive + } + else + { // receive packet->len = b->desc >> 16; - if (packet->len > 0) { + if ( packet->len > 0 ) + { packet->index = 0; packet->next = NULL; - if (rx_first[endpoint] == NULL) { + if ( rx_first[ endpoint ] == NULL ) + { //serial_print("rx 1st, epidx="); //serial_phex(endpoint); //serial_print(", packet="); //serial_phex32((uint32_t)packet); //serial_print("\n"); - rx_first[endpoint] = packet; - } else { + rx_first[ endpoint ] = packet; + } + else + { //serial_print("rx Nth, epidx="); //serial_phex(endpoint); //serial_print(", packet="); //serial_phex32((uint32_t)packet); //serial_print("\n"); - rx_last[endpoint]->next = packet; + rx_last[ endpoint ]->next = packet; } - rx_last[endpoint] = packet; - usb_rx_byte_count_data[endpoint] += packet->len; + rx_last[ endpoint ] = packet; + usb_rx_byte_count_data[ endpoint ] += packet->len; // TODO: implement a per-endpoint maximum # of allocated packets // so a flood of incoming data on 1 endpoint doesn't starve // the others if the user isn't reading it regularly packet = usb_malloc(); - if (packet) { + if ( packet ) + { b->addr = packet->buf; - b->desc = BDT_DESC(64, ((uint32_t)b & 8) ? DATA1 : DATA0); - } else { + b->desc = BDT_DESC( 64, ((uint32_t)b & 8) ? DATA1 : DATA0 ); + } + else + { //serial_print("starving "); //serial_phex(endpoint + 1); //serial_print(((uint32_t)b & 8) ? ",odd\n" : ",even\n"); b->desc = 0; usb_rx_memory_needed++; } - } else { - b->desc = BDT_DESC(64, ((uint32_t)b & 8) ? DATA1 : DATA0); + } + else + { + b->desc = BDT_DESC( 64, ((uint32_t)b & 8) ? DATA1 : DATA0 ); } } @@ -830,8 +1097,8 @@ void usb_isr(void) } - - if (status & USB_ISTAT_USBRST /* 01 */ ) { + if ( status & USB_ISTAT_USBRST /* 01 */ ) + { //serial_print("reset\n"); // initialize BDT toggle bits @@ -839,13 +1106,13 @@ void usb_isr(void) ep0_tx_bdt_bank = 0; // set up buffers to receive Setup and OUT packets - table[index(0, RX, EVEN)].desc = BDT_DESC(EP0_SIZE, 0); - table[index(0, RX, EVEN)].addr = ep0_rx0_buf; - table[index(0, RX, ODD)].desc = BDT_DESC(EP0_SIZE, 0); - table[index(0, RX, ODD)].addr = ep0_rx1_buf; - table[index(0, TX, EVEN)].desc = 0; - table[index(0, TX, ODD)].desc = 0; - + table[index( 0, RX, EVEN ) ].desc = BDT_DESC( EP0_SIZE, 0 ); + table[index( 0, RX, EVEN ) ].addr = ep0_rx0_buf; + table[index( 0, RX, ODD ) ].desc = BDT_DESC( EP0_SIZE, 0 ); + table[index( 0, RX, ODD ) ].addr = ep0_rx1_buf; + table[index( 0, TX, EVEN ) ].desc = 0; + table[index( 0, TX, ODD ) ].desc = 0; + // activate endpoint 0 USB0_ENDPT0 = USB_ENDPT_EPRXEN | USB_ENDPT_EPTXEN | USB_ENDPT_EPHSHK; @@ -871,12 +1138,14 @@ void usb_isr(void) } - if ((status & USB_ISTAT_STALL /* 80 */ )) { + if ( (status & USB_ISTAT_STALL /* 80 */ ) ) + { //serial_print("stall:\n"); USB0_ENDPT0 = USB_ENDPT_EPRXEN | USB_ENDPT_EPTXEN | USB_ENDPT_EPHSHK; USB0_ISTAT = USB_ISTAT_STALL; } - if ((status & USB_ISTAT_ERROR /* 02 */ )) { + if ( (status & USB_ISTAT_ERROR /* 02 */ ) ) + { uint8_t err = USB0_ERRSTAT; USB0_ERRSTAT = err; //serial_print("err:"); @@ -885,25 +1154,24 @@ void usb_isr(void) USB0_ISTAT = USB_ISTAT_ERROR; } - if ((status & USB_ISTAT_SLEEP /* 10 */ )) { + if ( (status & USB_ISTAT_SLEEP /* 10 */ ) ) + { //serial_print("sleep\n"); USB0_ISTAT = USB_ISTAT_SLEEP; } - } -void usb_init(void) +uint8_t usb_init() { - int i; - - //serial_begin(BAUD2DIV(115200)); - //serial_print("usb_init\n"); + #ifdef UART_DEBUG + print("USB INIT"NL); + #endif - //usb_init_serialnumber(); - - for (i=0; i <= NUM_ENDPOINTS*4; i++) { + // Clear out endpoints table + for ( int i = 0; i <= NUM_ENDPOINTS * 4; i++ ) + { table[i].desc = 0; table[i].addr = 0; } @@ -917,7 +1185,7 @@ void usb_init(void) // reset USB module USB0_USBTRC0 = USB_USBTRC_USBRESET; - while ((USB0_USBTRC0 & USB_USBTRC_USBRESET) != 0) ; // wait for reset to end + while ( (USB0_USBTRC0 & USB_USBTRC_USBRESET) != 0 ); // wait for reset to end // set desc table base addr USB0_BDTPAGE1 = ((uint32_t)table) >> 8; @@ -939,16 +1207,18 @@ void usb_init(void) USB0_INTEN = USB_INTEN_USBRSTEN; // enable interrupt in NVIC... - NVIC_SET_PRIORITY(IRQ_USBOTG, 112); - NVIC_ENABLE_IRQ(IRQ_USBOTG); + NVIC_SET_PRIORITY( IRQ_USBOTG, 112 ); + NVIC_ENABLE_IRQ( IRQ_USBOTG ); // enable d+ pullup USB0_CONTROL = USB_CONTROL_DPPULLUPNONOTG; + + return 1; } // return 0 if the USB is not configured, or the configuration // number selected by the HOST -uint8_t usb_configured(void) +uint8_t usb_configured() { return usb_configuration; }