X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=Output%2FpjrcUSB%2Farm%2Fusb_dev.c;h=e913006e615d06970ed8e5408f0ced007a2b7af9;hb=f4da2560c43f8182aa0fd8270fe175148d084b66;hp=0ea7e9f53d5bf43a31483d1c86ba4540bc3bd389;hpb=eabb1c546a15111221a4f45f50265729ae5197be;p=kiibohd-controller.git diff --git a/Output/pjrcUSB/arm/usb_dev.c b/Output/pjrcUSB/arm/usb_dev.c index 0ea7e9f..e913006 100644 --- a/Output/pjrcUSB/arm/usb_dev.c +++ b/Output/pjrcUSB/arm/usb_dev.c @@ -1,7 +1,7 @@ /* Teensyduino Core Library * http://www.pjrc.com/teensy/ * Copyright (c) 2013 PJRC.COM, LLC. - * Modified by Jacob Alexander 2013-2014 + * Modifications by Jacob Alexander (2013-2015) * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -29,90 +29,127 @@ * SOFTWARE. */ +// ----- 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) @@ -129,36 +166,30 @@ uint8_t usb_rx_memory_needed = 0; volatile uint8_t usb_configuration = 0; volatile uint8_t usb_reboot_timer = 0; +static uint8_t reply_buffer[8]; + + + +// ----- Functions ----- static void endpoint0_stall() { - //print("STALL"); + #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 ) { - //print("TRANSMIT"); -#if 0 - serial_print("tx0:"); - serial_phex32((uint32_t)data); - serial_print(","); - serial_phex16(len); - serial_print(ep0_tx_bdt_bank ? ", odd" : ", even"); - serial_print(ep0_tx_data_toggle ? ", d1\n" : ", d0\n"); -#endif table[index(0, TX, ep0_tx_bdt_bank)].addr = (void *)data; table[index(0, TX, ep0_tx_bdt_bank)].desc = BDT_DESC(len, ep0_tx_data_toggle); ep0_tx_data_toggle ^= 1; ep0_tx_bdt_bank ^= 1; } -static uint8_t reply_buffer[8]; - static void usb_setup() { - //print("SETUP"); const uint8_t *data = NULL; uint32_t datalen = 0; const usb_descriptor_list_t *list; @@ -168,214 +199,350 @@ static void usb_setup() 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 (endpoint) 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; // TODO: do we need to clear the data toggle here? - break; - case 0x0302: // SET_FEATURE (endpoint) + goto send; + + case 0x0300: // SET_FEATURE (device) + case 0x0301: // SET_FEATURE (interface) + // TODO: Currently ignoring, perhaps useful? -HaaTa + warn_print("SET_FEATURE - Device/Interface"); + 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 + // Interface + switch ( setup.wIndex & 0xFF ) + { + // Keyboard Interface + case KEYBOARD_INTERFACE: + break; + // NKRO Keyboard Interface + case NKRO_KEYBOARD_INTERFACE: + break; + default: + warn_msg("Unknown interface - "); + printHex( setup.wIndex ); + print( NL ); + endpoint0_stall(); + break; + } + 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). @@ -389,29 +556,29 @@ static void usb_setup() //Halt feature set, a ClearFeature(ENDPOINT_HALT) request always results in the //data toggle being reinitialized to DATA0. - - -// #define stat2bufferdescriptor(stat) (table + ((stat) >> 2)) - -static void usb_control(uint32_t stat) +static void usb_control( uint32_t stat ) { - //print("CONTROL"); + #ifdef UART_DEBUG + print("CONTROL - "); + #endif bdt_t *b; uint32_t pid, size; uint8_t *buf; const uint8_t *data; - b = stat2bufferdescriptor(stat); - pid = BDT_PID(b->desc); - //count = b->desc >> 16; + b = stat2bufferdescriptor( stat ); + pid = BDT_PID( b->desc ); buf = b->addr; - //serial_print("pid:"); - //serial_phex(pid); - //serial_print(", count:"); - //serial_phex(count); - //serial_print("\n"); - - 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? @@ -420,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"); @@ -439,60 +607,114 @@ 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(" -- "); + printHex32(setup.word1); + print(" "); + printHex32(setup.word2); + print(NL); + #endif // actually "do" the setup request usb_setup(); // unfreeze the USB, now that we're ready USB0_CTL = USB_CTL_USBENSOFEN; // clear TXSUSPENDTOKENBUSY bit break; + case 0x01: // OUT transaction received from host case 0x02: - //serial_print("PID=OUT\n"); -#ifdef CDC_STATUS_INTERFACE - if (setup.wRequestAndType == 0x2021 /*CDC_SET_LINE_CODING*/) { + #ifdef UART_DEBUG_UNKNOWN + print("PID=OUT wRequestAndType:"); + printHex(setup.wRequestAndType); + print(", wValue:"); + printHex(setup.wValue); + print(", wIndex:"); + printHex(setup.wIndex); + print(", len:"); + printHex(setup.wLength); + print(" -- "); + printHex32(setup.word1); + print(" "); + printHex32(setup.word2); + print(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)) { - USBKeys_LEDs = buf[0]; - endpoint0_transmit(NULL, 0); + + // Keyboard SET_REPORT + if ( setup.wRequestAndType == 0x921 && setup.wValue & 0x200 ) + { + // Interface + switch ( setup.wIndex & 0xFF ) + { + // Keyboard Interface + case KEYBOARD_INTERFACE: + USBKeys_LEDs = buf[0]; + endpoint0_transmit( NULL, 0 ); + break; + // NKRO Keyboard Interface + case NKRO_KEYBOARD_INTERFACE: + // Only use 2nd byte, first byte is the report id + USBKeys_LEDs = buf[1]; + endpoint0_transmit( NULL, 0 ); + break; + default: + warn_msg("Unknown interface - "); + printHex( setup.wIndex ); + print( NL ); + break; + } + + #ifdef UART_DEBUG + for ( size_t len = 0; len < setup.wLength; len++ ) + { + printHex( buf[ len ] ); + print(" "); + } + print( NL ); + #endif } -#endif + // give the buffer back - b->desc = BDT_DESC(EP0_SIZE, DATA1); + b->desc = BDT_DESC( EP0_SIZE, DATA1 ); break; case 0x09: // IN transaction completed to host - //serial_print("PID=IN:"); - //serial_phex(stat); - //serial_print("\n"); + #ifdef UART_DEBUG + print("PID=IN:"); + printHex(stat); + print(NL); + #endif // send remaining data, if any... data = ep0_tx_ptr; - if (data) { + if ( data ) + { size = ep0_tx_len; if (size > EP0_SIZE) size = EP0_SIZE; endpoint0_transmit(data, size); @@ -501,49 +723,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); @@ -553,34 +768,38 @@ usb_packet_t *usb_rx(uint32_t endpoint) return ret; } -static uint32_t usb_queue_byte_count(const usb_packet_t *p) +static uint32_t usb_queue_byte_count( const usb_packet_t *p ) { uint32_t count=0; __disable_irq(); - for ( ; p; p = p->next) { + for ( ; p; p = p->next ) + { count += p->len; } __enable_irq(); return count; } -uint32_t usb_tx_byte_count(uint32_t endpoint) +uint32_t usb_tx_byte_count( uint32_t endpoint ) { endpoint--; - if (endpoint >= NUM_ENDPOINTS) return 0; - return usb_queue_byte_count(tx_first[endpoint]); + if ( endpoint >= NUM_ENDPOINTS ) + return 0; + return usb_queue_byte_count( tx_first[ endpoint ] ); } -uint32_t usb_tx_packet_count(uint32_t endpoint) +uint32_t usb_tx_packet_count( uint32_t endpoint ) { const usb_packet_t *p; uint32_t count=0; endpoint--; - if (endpoint >= NUM_ENDPOINTS) return 0; + if ( endpoint >= NUM_ENDPOINTS ) + return 0; __disable_irq(); - for (p = tx_first[endpoint]; p; p = p->next) count++; + for ( p = tx_first[ endpoint ]; p; p = p->next ) + count++; __enable_irq(); return count; } @@ -594,7 +813,7 @@ uint32_t usb_tx_packet_count(uint32_t endpoint) // without this prioritization. The packet buffer (input) is assigned to the // first endpoint needing memory. // -void usb_rx_memory(usb_packet_t *packet) +void usb_rx_memory( usb_packet_t *packet ) { //print("USB RX MEMORY"); unsigned int i; @@ -603,20 +822,24 @@ void usb_rx_memory(usb_packet_t *packet) 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); @@ -630,58 +853,72 @@ void usb_rx_memory(usb_packet_t *packet) // usb_rx_memory_needed was set greater than zero, but no memory // was actually needed. usb_rx_memory_needed = 0; - usb_free(packet); + usb_free( packet ); return; } //#define index(endpoint, tx, odd) (((endpoint) << 2) | ((tx) << 1) | (odd)) //#define stat2bufferdescriptor(stat) (table + ((stat) >> 2)) -void usb_tx(uint32_t endpoint, usb_packet_t *packet) +void usb_tx( uint32_t endpoint, usb_packet_t *packet ) { - bdt_t *b = &table[index(endpoint, TX, EVEN)]; + bdt_t *b = &table[ index( endpoint, TX, EVEN ) ]; uint8_t next; endpoint--; - if (endpoint >= NUM_ENDPOINTS) return; + if ( endpoint >= NUM_ENDPOINTS ) + return; __disable_irq(); //serial_print("txstate="); - //serial_phex(tx_state[endpoint]); + //serial_phex(tx_state[ endpoint ]); //serial_print("\n"); - switch (tx_state[endpoint]) { - case TX_STATE_BOTH_FREE_EVEN_FIRST: + switch ( tx_state[ endpoint ] ) + { + case TX_STATE_BOTH_FREE_EVEN_FIRST: next = TX_STATE_ODD_FREE; break; - case TX_STATE_BOTH_FREE_ODD_FIRST: + case TX_STATE_BOTH_FREE_ODD_FIRST: b++; next = TX_STATE_EVEN_FREE; break; - case TX_STATE_EVEN_FREE: + case TX_STATE_EVEN_FREE: next = TX_STATE_NONE_FREE_ODD_FIRST; break; - case TX_STATE_ODD_FREE: + case TX_STATE_ODD_FREE: b++; next = TX_STATE_NONE_FREE_EVEN_FIRST; break; - default: - if (tx_first[endpoint] == NULL) { - tx_first[endpoint] = packet; - } else { - tx_last[endpoint]->next = packet; + default: + if (tx_first[ endpoint ] == NULL) + { + tx_first[ endpoint ] = packet; } - tx_last[endpoint] = packet; + else + { + tx_last[ endpoint ]->next = packet; + } + tx_last[ endpoint ] = packet; __enable_irq(); return; } - tx_state[endpoint] = next; + + tx_state[ endpoint ] = next; b->addr = packet->buf; - b->desc = BDT_DESC(packet->len, ((uint32_t)b & 8) ? DATA1 : DATA0); + b->desc = BDT_DESC( packet->len, ((uint32_t)b & 8) ? DATA1 : DATA0 ); __enable_irq(); } void usb_device_reload() { + 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_) @@ -692,7 +929,7 @@ void usb_device_reload() PORTA_PCR3 = PORT_PCR_PFE | PORT_PCR_MUX(1); // Internal pull-up // Check for jumper - if ( GPIOA_PDIR & (1<<3) ) + if ( GPIOA_PDIR & (1<<3) && flashModeEnabled_define != 0 ) { print( NL ); warn_print("Security jumper not present, cancelling firmware reload..."); @@ -701,10 +938,18 @@ void usb_device_reload() else { // Copies variable into the VBAT register, must be identical to the variable in the bootloader to jump to the bootloader flash mode - for ( int pos = 0; pos < sizeof(sys_reset_to_loader_magic); pos++ )(&VBAT)[pos] = sys_reset_to_loader_magic[ pos ]; + for ( int pos = 0; pos < sizeof(sys_reset_to_loader_magic); pos++ ) + (&VBAT)[ pos ] = sys_reset_to_loader_magic[ pos ]; SOFTWARE_RESET(); } +// 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(); + // Teensy 3.0 and 3.1 #else asm volatile("bkpt"); @@ -720,7 +965,7 @@ void usb_isr() //status = USB0_ISTAT; //serial_phex(status); //serial_print("\n"); - restart: +restart: status = USB0_ISTAT; /* print("USB ISR STATUS: "); @@ -728,25 +973,33 @@ void usb_isr() print( NL ); */ - if ((status & USB_INTEN_SOFTOKEN /* 04 */ )) { - if (usb_configuration) { + if ( (status & USB_INTEN_SOFTOKEN /* 04 */ ) ) + { + if ( usb_configuration ) + { t = usb_reboot_timer; - if (t) { + if ( t ) + { usb_reboot_timer = --t; - if (!t) usb_device_reload(); + if ( !t ) + usb_device_reload(); } -#ifdef CDC_DATA_INTERFACE + + // CDC Interface t = usb_cdc_transmit_flush_timer; - if (t) { + if ( t ) + { usb_cdc_transmit_flush_timer = --t; - if (t == 0) usb_serial_flush_callback(); + if ( t == 0 ) + usb_serial_flush_callback(); } -#endif + } USB0_ISTAT = USB_INTEN_SOFTOKEN; } - if ((status & USB_ISTAT_TOKDNE /* 08 */ )) { + if ( (status & USB_ISTAT_TOKDNE /* 08 */ ) ) + { uint8_t endpoint; stat = USB0_STAT; //serial_print("token: ep="); @@ -754,9 +1007,12 @@ void usb_isr() //serial_print(stat & 0x08 ? ",tx" : ",rx"); //serial_print(stat & 0x04 ? ",odd\n" : ",even\n"); endpoint = stat >> 4; - if (endpoint == 0) { - usb_control(stat); - } else { + if ( endpoint == 0 ) + { + usb_control( stat ); + } + else + { bdt_t *b = stat2bufferdescriptor(stat); usb_packet_t *packet = (usb_packet_t *)((uint8_t *)(b->addr) - 8); #if 0 @@ -769,88 +1025,104 @@ void usb_isr() 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 ); } } @@ -863,8 +1135,8 @@ void usb_isr() } - - if (status & USB_ISTAT_USBRST /* 01 */ ) { + if ( status & USB_ISTAT_USBRST /* 01 */ ) + { //serial_print("reset\n"); // initialize BDT toggle bits @@ -872,12 +1144,12 @@ void usb_isr() 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; @@ -904,12 +1176,14 @@ void usb_isr() } - if ((status & USB_ISTAT_STALL /* 80 */ )) { + if ( (status & USB_ISTAT_STALL /* 80 */ ) ) + { //serial_print("stall:\n"); USB0_ENDPT0 = USB_ENDPT_EPRXEN | USB_ENDPT_EPTXEN | USB_ENDPT_EPHSHK; USB0_ISTAT = USB_ISTAT_STALL; } - if ((status & USB_ISTAT_ERROR /* 02 */ )) { + if ( (status & USB_ISTAT_ERROR /* 02 */ ) ) + { uint8_t err = USB0_ERRSTAT; USB0_ERRSTAT = err; //serial_print("err:"); @@ -918,18 +1192,20 @@ void usb_isr() USB0_ISTAT = USB_ISTAT_ERROR; } - if ((status & USB_ISTAT_SLEEP /* 10 */ )) { + if ( (status & USB_ISTAT_SLEEP /* 10 */ ) ) + { //serial_print("sleep\n"); USB0_ISTAT = USB_ISTAT_SLEEP; } - } -void usb_init() +uint8_t usb_init() { - //print("USB INIT"); + #ifdef UART_DEBUG + print("USB INIT"NL); + #endif // Clear out endpoints table for ( int i = 0; i <= NUM_ENDPOINTS * 4; i++ ) @@ -974,6 +1250,8 @@ void usb_init() // enable d+ pullup USB0_CONTROL = USB_CONTROL_DPPULLUPNONOTG; + + return 1; } // return 0 if the USB is not configured, or the configuration