2014-02-03 00:19:58 +00:00
/* Teensyduino Core Library
* http : //www.pjrc.com/teensy/
* Copyright ( c ) 2013 PJRC . COM , LLC .
2014-09-28 23:44:57 +00:00
* Modifications by Jacob Alexander ( 2013 - 2014 )
2014-02-03 00:19:58 +00:00
*
* 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 :
*
2014-07-15 07:28:12 +00:00
* 1. The above copyright notice and this permission notice shall be
2014-02-03 00:19:58 +00:00
* included in all copies or substantial portions of the Software .
*
2014-07-15 07:28:12 +00:00
* 2. If the Software is incorporated into a build system that allows
2014-02-03 00:19:58 +00:00
* 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 .
*
* 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 .
*/
2014-09-28 23:44:57 +00:00
// ----- Includes -----
2014-07-15 07:28:12 +00:00
// Project Includes
2014-02-03 01:33:23 +00:00
# include <Lib/OutputLib.h>
2014-07-15 07:28:12 +00:00
# include <print.h>
// Local Includes
2013-01-27 06:47:52 +00:00
# include "usb_dev.h"
# include "usb_mem.h"
2014-09-28 23:44:57 +00:00
// ----- Defines -----
// 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
2014-02-03 00:19:58 +00:00
# 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
2013-01-27 06:47:52 +00:00
# define BDT_OWN 0x80
# define BDT_DATA1 0x40
# define BDT_DATA0 0x00
# define BDT_DTS 0x08
# define BDT_STALL 0x04
2014-09-28 23:44:57 +00:00
# define TX 1
# define RX 0
# define ODD 1
# define EVEN 0
2013-01-27 06:47:52 +00:00
# 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
2014-09-28 23:44:57 +00:00
# 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 ;
} ;
} setup ;
// ----- 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 ] ;
2013-01-27 06:47:52 +00:00
// 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)
// Status stage uses a DATA1 PID.
static uint8_t ep0_rx0_buf [ EP0_SIZE ] __attribute__ ( ( aligned ( 4 ) ) ) ;
static uint8_t ep0_rx1_buf [ EP0_SIZE ] __attribute__ ( ( aligned ( 4 ) ) ) ;
static const uint8_t * ep0_tx_ptr = NULL ;
static uint16_t ep0_tx_len ;
static uint8_t ep0_tx_bdt_bank = 0 ;
static uint8_t ep0_tx_data_toggle = 0 ;
uint8_t usb_rx_memory_needed = 0 ;
volatile uint8_t usb_configuration = 0 ;
volatile uint8_t usb_reboot_timer = 0 ;
2014-09-28 23:44:57 +00:00
static uint8_t reply_buffer [ 8 ] ;
// ----- Functions -----
2013-01-27 06:47:52 +00:00
2014-07-15 07:28:12 +00:00
static void endpoint0_stall ( )
2013-01-27 06:47:52 +00:00
{
USB0_ENDPT0 = USB_ENDPT_EPSTALL | USB_ENDPT_EPRXEN | USB_ENDPT_EPTXEN | USB_ENDPT_EPHSHK ;
}
2014-09-28 23:44:57 +00:00
static void endpoint0_transmit ( const void * data , uint32_t len )
2013-01-27 06:47:52 +00:00
{
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 ;
}
2014-07-15 07:28:12 +00:00
static void usb_setup ( )
2013-01-27 06:47:52 +00:00
{
const uint8_t * data = NULL ;
uint32_t datalen = 0 ;
const usb_descriptor_list_t * list ;
uint32_t size ;
volatile uint8_t * reg ;
uint8_t epconf ;
const uint8_t * cfg ;
int i ;
2014-09-28 23:44:57 +00:00
switch ( setup . wRequestAndType )
{
case 0x0500 : // SET_ADDRESS
2013-01-27 06:47:52 +00:00
break ;
2014-09-28 23:44:57 +00:00
case 0x0900 : // SET_CONFIGURATION
# ifdef UART_DEBUG
print ( " CONFIGURE - " ) ;
# endif
2013-01-27 06:47:52 +00:00
usb_configuration = setup . wValue ;
reg = & USB0_ENDPT1 ;
cfg = usb_endpoint_config_table ;
// clear all BDT entries, free any allocated memory...
2014-09-28 23:44:57 +00:00
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 ) ) ;
2014-02-03 00:19:58 +00:00
}
}
// free all queued packets
2014-09-28 23:44:57 +00:00
for ( i = 0 ; i < NUM_ENDPOINTS ; i + + )
{
2014-02-03 00:19:58 +00:00
usb_packet_t * p , * n ;
p = rx_first [ i ] ;
2014-09-28 23:44:57 +00:00
while ( p )
{
2014-02-03 00:19:58 +00:00
n = p - > next ;
usb_free ( p ) ;
p = n ;
}
2014-11-11 07:42:39 +00:00
rx_first [ i ] = NULL ;
rx_last [ i ] = NULL ;
2014-02-03 00:19:58 +00:00
p = tx_first [ i ] ;
2014-09-28 23:44:57 +00:00
while ( p )
{
2014-02-03 00:19:58 +00:00
n = p - > next ;
usb_free ( p ) ;
p = n ;
}
2014-11-11 07:42:39 +00:00
tx_first [ i ] = NULL ;
tx_last [ i ] = NULL ;
2014-02-03 00:19:58 +00:00
usb_rx_byte_count_data [ i ] = 0 ;
2014-09-28 23:44:57 +00:00
2014-11-11 07:42:39 +00:00
switch ( tx_state [ i ] )
{
2014-09-28 23:44:57 +00:00
case TX_STATE_EVEN_FREE :
case TX_STATE_NONE_FREE_EVEN_FIRST :
2014-11-11 07:42:39 +00:00
tx_state [ i ] = TX_STATE_BOTH_FREE_EVEN_FIRST ;
2014-02-03 00:19:58 +00:00
break ;
2014-09-28 23:44:57 +00:00
case TX_STATE_ODD_FREE :
case TX_STATE_NONE_FREE_ODD_FIRST :
2014-11-11 07:42:39 +00:00
tx_state [ i ] = TX_STATE_BOTH_FREE_ODD_FIRST ;
2014-02-03 00:19:58 +00:00
break ;
2014-09-28 23:44:57 +00:00
default :
2014-02-03 00:19:58 +00:00
break ;
2013-01-27 06:47:52 +00:00
}
}
usb_rx_memory_needed = 0 ;
2014-09-28 23:44:57 +00:00
for ( i = 1 ; i < = NUM_ENDPOINTS ; i + + )
{
2013-01-27 06:47:52 +00:00
epconf = * cfg + + ;
* reg = epconf ;
reg + = 4 ;
2014-09-28 23:44:57 +00:00
if ( epconf & USB_ENDPT_EPRXEN )
{
2013-01-27 06:47:52 +00:00
usb_packet_t * p ;
p = usb_malloc ( ) ;
2014-09-28 23:44:57 +00:00
if ( p )
{
2014-11-11 07:42:39 +00:00
table [ index ( i , RX , EVEN ) ] . addr = p - > buf ;
table [ index ( i , RX , EVEN ) ] . desc = BDT_DESC ( 64 , 0 ) ;
2014-09-28 23:44:57 +00:00
}
else
{
2014-11-11 07:42:39 +00:00
table [ index ( i , RX , EVEN ) ] . desc = 0 ;
2013-01-27 06:47:52 +00:00
usb_rx_memory_needed + + ;
}
p = usb_malloc ( ) ;
2014-09-28 23:44:57 +00:00
if ( p )
{
2014-11-11 07:42:39 +00:00
table [ index ( i , RX , ODD ) ] . addr = p - > buf ;
table [ index ( i , RX , ODD ) ] . desc = BDT_DESC ( 64 , 1 ) ;
2014-09-28 23:44:57 +00:00
}
else
{
2014-11-11 07:42:39 +00:00
table [ index ( i , RX , ODD ) ] . desc = 0 ;
2013-01-27 06:47:52 +00:00
usb_rx_memory_needed + + ;
}
}
2014-11-11 07:42:39 +00:00
table [ index ( i , TX , EVEN ) ] . desc = 0 ;
table [ index ( i , TX , ODD ) ] . desc = 0 ;
2013-01-27 06:47:52 +00:00
}
break ;
2014-09-28 23:44:57 +00:00
case 0x0880 : // GET_CONFIGURATION
2013-01-27 06:47:52 +00:00
reply_buffer [ 0 ] = usb_configuration ;
datalen = 1 ;
data = reply_buffer ;
break ;
2014-09-28 23:44:57 +00:00
case 0x0080 : // GET_STATUS (device)
2013-01-27 06:47:52 +00:00
reply_buffer [ 0 ] = 0 ;
reply_buffer [ 1 ] = 0 ;
datalen = 2 ;
data = reply_buffer ;
break ;
2014-09-28 23:44:57 +00:00
case 0x0082 : // GET_STATUS (endpoint)
if ( setup . wIndex > NUM_ENDPOINTS )
{
2013-01-27 06:47:52 +00:00
// TODO: do we need to handle IN vs OUT here?
endpoint0_stall ( ) ;
return ;
}
reply_buffer [ 0 ] = 0 ;
reply_buffer [ 1 ] = 0 ;
2014-09-28 23:44:57 +00:00
if ( * ( uint8_t * ) ( & USB0_ENDPT0 + setup . wIndex * 4 ) & 0x02 )
reply_buffer [ 0 ] = 1 ;
2013-01-27 06:47:52 +00:00
data = reply_buffer ;
datalen = 2 ;
break ;
2014-09-28 23:44:57 +00:00
case 0x0102 : // CLEAR_FEATURE (endpoint)
2013-01-27 06:47:52 +00:00
i = setup . wIndex & 0x7F ;
2014-09-28 23:44:57 +00:00
if ( i > NUM_ENDPOINTS | | setup . wValue ! = 0 )
{
2013-01-27 06:47:52 +00:00
// 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 ;
2014-09-28 23:44:57 +00:00
case 0x0302 : // SET_FEATURE (endpoint)
2013-01-27 06:47:52 +00:00
i = setup . wIndex & 0x7F ;
2014-09-28 23:44:57 +00:00
if ( i > NUM_ENDPOINTS | | setup . wValue ! = 0 )
{
2013-01-27 06:47:52 +00:00
// 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 ;
2014-09-28 23:44:57 +00:00
case 0x0680 : // GET_DESCRIPTOR
case 0x0681 :
# ifdef UART_DEBUG
print ( " desc: " ) ;
2014-11-11 07:42:39 +00:00
printHex ( setup . wValue ) ;
print ( NL ) ;
2014-09-28 23:44:57 +00:00
# endif
for ( list = usb_descriptor_list ; 1 ; list + + )
{
if ( list - > addr = = NULL )
break ;
if ( setup . wValue = = list - > wValue & & setup . wIndex = = list - > wIndex )
{
2013-01-27 06:47:52 +00:00
data = list - > addr ;
2014-09-28 23:44:57 +00:00
if ( ( setup . wValue > > 8 ) = = 3 )
{
2014-02-03 00:19:58 +00:00
// for string descriptors, use the descriptor's
// length field, allowing runtime configured
// length.
datalen = * ( list - > addr ) ;
2014-09-28 23:44:57 +00:00
}
else
{
2014-02-03 00:19:58 +00:00
datalen = list - > length ;
}
2014-09-28 23:44:57 +00:00
# if UART_DEBUG
print ( " Desc found, " ) ;
2014-11-11 07:42:39 +00:00
printHex32 ( ( uint32_t ) data ) ;
2014-09-28 23:44:57 +00:00
print ( " , " ) ;
2014-11-11 07:42:39 +00:00
printHex ( datalen ) ;
2014-09-28 23:44:57 +00:00
print ( " , " ) ;
2014-11-11 07:42:39 +00:00
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 ) ;
2014-09-28 23:44:57 +00:00
# endif
2013-01-27 06:47:52 +00:00
goto send ;
}
}
2014-09-28 23:44:57 +00:00
# ifdef UART_DEBUG
2014-11-11 07:42:39 +00:00
print ( " desc: not found " NL ) ;
2014-09-28 23:44:57 +00:00
# endif
2013-01-27 06:47:52 +00:00
endpoint0_stall ( ) ;
return ;
2014-09-28 23:44:57 +00:00
case 0x2221 : // CDC_SET_CONTROL_LINE_STATE
2013-01-27 06:47:52 +00:00
usb_cdc_line_rtsdtr = setup . wValue ;
//serial_print("set control line state\n");
2014-09-28 23:44:57 +00:00
endpoint0_stall ( ) ;
return ;
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?
2013-01-27 06:47:52 +00:00
//serial_print("set coding, waiting...\n");
2014-11-13 07:04:50 +00:00
endpoint0_stall ( ) ;
2014-09-28 23:44:57 +00:00
return ; // Cannot stall here (causes issues)
case 0x0921 : // HID SET_REPORT
# ifdef UART_DEBUG
print ( " SET_REPORT - " ) ;
printHex ( setup . wValue ) ;
print ( " - " ) ;
printHex ( setup . wValue & 0xFF ) ;
2014-11-11 07:42:39 +00:00
print ( NL ) ;
2014-09-28 23:44:57 +00:00
# endif
USBKeys_LEDs = setup . wValue & 0xFF ;
endpoint0_stall ( ) ;
2013-01-27 06:47:52 +00:00
return ;
2014-09-28 23:44:57 +00:00
case 0x01A1 : // HID GET_REPORT
# ifdef UART_DEBUG
print ( " GET_REPORT - " ) ;
printHex ( USBKeys_LEDs ) ;
print ( NL ) ;
# endif
data = ( uint8_t * ) & USBKeys_LEDs ;
datalen = 1 ;
goto send ;
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 ;
endpoint0_stall ( ) ;
2013-01-27 06:47:52 +00:00
return ;
2014-09-28 23:44:57 +00:00
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
endpoint0_stall ( ) ;
return ;
// case 0xC940:
default :
# ifdef UART_DEBUG_UNKNOWN
print ( " UNKNOWN " ) ;
# endif
2013-01-27 06:47:52 +00:00
endpoint0_stall ( ) ;
return ;
}
2014-09-28 23:44:57 +00:00
send :
# ifdef UART_DEBUG
print ( " setup send " ) ;
printHex32 ( ( uint32_t ) data ) ;
print ( " , " ) ;
printHex ( datalen ) ;
print ( NL ) ;
# endif
if ( datalen > setup . wLength )
datalen = setup . wLength ;
2013-01-27 06:47:52 +00:00
size = datalen ;
2014-09-28 23:44:57 +00:00
if ( size > EP0_SIZE )
size = EP0_SIZE ;
2013-01-27 06:47:52 +00:00
endpoint0_transmit ( data , size ) ;
data + = size ;
datalen - = size ;
2014-09-28 23:44:57 +00:00
// See if transmit has finished
if ( datalen = = 0 & & size < EP0_SIZE )
return ;
2013-01-27 06:47:52 +00:00
size = datalen ;
2014-09-28 23:44:57 +00:00
if ( size > EP0_SIZE )
size = EP0_SIZE ;
2013-01-27 06:47:52 +00:00
endpoint0_transmit ( data , size ) ;
data + = size ;
datalen - = size ;
2014-09-28 23:44:57 +00:00
// See if transmit has finished
if ( datalen = = 0 & & size < EP0_SIZE )
return ;
// Save rest of transfer for later? XXX
2013-01-27 06:47:52 +00:00
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).
//Configuring a device or changing an alternate setting causes all of the status
//and configuration values associated with endpoints in the affected interfaces
//to be set to their default values. This includes setting the data toggle of
//any endpoint using data toggles to the value DATA0.
//For endpoints using data toggle, regardless of whether an endpoint has the
//Halt feature set, a ClearFeature(ENDPOINT_HALT) request always results in the
//data toggle being reinitialized to DATA0.
2014-09-28 23:44:57 +00:00
static void usb_control ( uint32_t stat )
2013-01-27 06:47:52 +00:00
{
2014-09-28 23:44:57 +00:00
# ifdef UART_DEBUG
print ( " CONTROL - " ) ;
# endif
2013-01-27 06:47:52 +00:00
bdt_t * b ;
uint32_t pid , size ;
uint8_t * buf ;
const uint8_t * data ;
2014-09-28 23:44:57 +00:00
b = stat2bufferdescriptor ( stat ) ;
pid = BDT_PID ( b - > desc ) ;
2013-01-27 06:47:52 +00:00
buf = b - > addr ;
2014-09-28 23:44:57 +00:00
# ifdef UART_DEBUG
print ( " pid: " ) ;
printHex ( pid ) ;
print ( " , count: " ) ;
printHex32 ( b - > desc ) ;
print ( " - " ) ;
# endif
switch ( pid )
{
2013-01-27 06:47:52 +00:00
case 0x0D : // Setup received from host
//serial_print("PID=Setup\n");
//if (count != 8) ; // panic?
// grab the 8 byte setup info
setup . word1 = * ( uint32_t * ) ( buf ) ;
setup . word2 = * ( uint32_t * ) ( buf + 4 ) ;
// give the buffer back
2014-09-28 23:44:57 +00:00
b - > desc = BDT_DESC ( EP0_SIZE , DATA1 ) ;
2013-01-27 06:47:52 +00:00
//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 ;
2014-09-28 23:44:57 +00:00
if ( ep0_tx_data_toggle )
{
2013-01-27 06:47:52 +00:00
}
//if (table[index(0, TX, EVEN)].desc & 0x80) {
//serial_print("leftover tx even\n");
//}
//if (table[index(0, TX, ODD)].desc & 0x80) {
//serial_print("leftover tx odd\n");
//}
table [ index ( 0 , TX , EVEN ) ] . desc = 0 ;
table [ index ( 0 , TX , ODD ) ] . desc = 0 ;
// first IN after Setup is always DATA1
ep0_tx_data_toggle = 1 ;
2014-09-28 23:44:57 +00:00
# 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
2013-01-27 06:47:52 +00:00
// actually "do" the setup request
2014-02-03 00:19:58 +00:00
usb_setup ( ) ;
2013-01-27 06:47:52 +00:00
// 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 :
2014-09-28 23:44:57 +00:00
# ifdef UART_DEBUG
print ( " PID=OUT " NL ) ;
# endif
// CDC Interface
if ( setup . wRequestAndType = = 0x2021 /*CDC_SET_LINE_CODING*/ )
{
2013-01-27 06:47:52 +00:00
int i ;
2014-02-03 00:19:58 +00:00
uint8_t * dst = ( uint8_t * ) usb_cdc_line_coding ;
2013-01-27 06:47:52 +00:00
//serial_print("set line coding ");
2014-09-28 23:44:57 +00:00
for ( i = 0 ; i < 7 ; i + + )
{
2013-01-27 06:47:52 +00:00
//serial_phex(*buf);
* dst + + = * buf + + ;
}
2014-02-03 00:19:58 +00:00
//serial_phex32(usb_cdc_line_coding[0]);
2013-01-27 06:47:52 +00:00
//serial_print("\n");
2014-09-28 23:44:57 +00:00
if ( usb_cdc_line_coding [ 0 ] = = 134 )
usb_reboot_timer = 15 ;
endpoint0_transmit ( NULL , 0 ) ;
2013-01-27 06:47:52 +00:00
}
2014-09-28 23:44:57 +00:00
// Keyboard Interface
if ( setup . word1 = = 0x02000921 & & setup . word2 = = ( ( 1 < < 16 ) | KEYBOARD_INTERFACE ) )
{
2013-01-27 06:47:52 +00:00
USBKeys_LEDs = buf [ 0 ] ;
2014-09-28 23:44:57 +00:00
endpoint0_transmit ( NULL , 0 ) ;
2013-01-27 06:47:52 +00:00
}
2014-09-28 23:44:57 +00:00
// NKRO Keyboard Interface
if ( setup . word1 = = 0x02000921 & & setup . word2 = = ( ( 1 < < 16 ) | NKRO_KEYBOARD_INTERFACE ) )
{
USBKeys_LEDs = buf [ 0 ] ;
endpoint0_transmit ( NULL , 0 ) ;
}
2013-01-27 06:47:52 +00:00
// give the buffer back
2014-09-28 23:44:57 +00:00
b - > desc = BDT_DESC ( EP0_SIZE , DATA1 ) ;
2013-01-27 06:47:52 +00:00
break ;
case 0x09 : // IN transaction completed to host
2014-09-28 23:44:57 +00:00
# ifdef UART_DEBUG
print ( " PID=IN: " ) ;
printHex ( stat ) ;
print ( NL ) ;
# endif
2013-01-27 06:47:52 +00:00
// send remaining data, if any...
data = ep0_tx_ptr ;
2014-09-28 23:44:57 +00:00
if ( data )
{
2013-01-27 06:47:52 +00:00
size = ep0_tx_len ;
if ( size > EP0_SIZE ) size = EP0_SIZE ;
endpoint0_transmit ( data , size ) ;
data + = size ;
ep0_tx_len - = size ;
ep0_tx_ptr = ( ep0_tx_len > 0 | | size = = EP0_SIZE ) ? data : NULL ;
}
2014-09-28 23:44:57 +00:00
if ( setup . bRequest = = 5 & & setup . bmRequestType = = 0 )
{
2013-01-27 06:47:52 +00:00
setup . bRequest = 0 ;
2014-09-28 23:44:57 +00:00
# ifdef UART_DEBUG
print ( " set address: " ) ;
printHex ( setup . wValue ) ;
print ( NL ) ;
# endif
2013-01-27 06:47:52 +00:00
USB0_ADDR = setup . wValue ;
}
break ;
2014-09-28 23:44:57 +00:00
default :
# ifdef UART_DEBUG
print ( " PID=unknown: " ) ;
printHex ( pid ) ;
print ( NL ) ;
# endif
break ;
2013-01-27 06:47:52 +00:00
}
USB0_CTL = USB_CTL_USBENSOFEN ; // clear TXSUSPENDTOKENBUSY bit
}
2014-09-28 23:44:57 +00:00
usb_packet_t * usb_rx ( uint32_t endpoint )
2013-01-27 06:47:52 +00:00
{
2014-07-15 07:28:12 +00:00
//print("USB RX");
2013-01-27 06:47:52 +00:00
usb_packet_t * ret ;
endpoint - - ;
2014-09-28 23:44:57 +00:00
if ( endpoint > = NUM_ENDPOINTS )
return NULL ;
2013-01-27 06:47:52 +00:00
__disable_irq ( ) ;
ret = rx_first [ endpoint ] ;
2014-09-28 23:44:57 +00:00
if ( ret )
rx_first [ endpoint ] = ret - > next ;
usb_rx_byte_count_data [ endpoint ] - = ret - > len ;
2013-01-27 06:47:52 +00:00
__enable_irq ( ) ;
//serial_print("rx, epidx=");
//serial_phex(endpoint);
//serial_print(", packet=");
//serial_phex32(ret);
//serial_print("\n");
return ret ;
}
2014-09-28 23:44:57 +00:00
static uint32_t usb_queue_byte_count ( const usb_packet_t * p )
2013-01-27 06:47:52 +00:00
{
uint32_t count = 0 ;
__disable_irq ( ) ;
2014-09-28 23:44:57 +00:00
for ( ; p ; p = p - > next )
{
2013-01-27 06:47:52 +00:00
count + = p - > len ;
}
__enable_irq ( ) ;
return count ;
}
2014-09-28 23:44:57 +00:00
uint32_t usb_tx_byte_count ( uint32_t endpoint )
2013-01-27 06:47:52 +00:00
{
endpoint - - ;
2014-09-28 23:44:57 +00:00
if ( endpoint > = NUM_ENDPOINTS )
return 0 ;
return usb_queue_byte_count ( tx_first [ endpoint ] ) ;
2013-01-27 06:47:52 +00:00
}
2014-09-28 23:44:57 +00:00
uint32_t usb_tx_packet_count ( uint32_t endpoint )
2013-01-27 06:47:52 +00:00
{
const usb_packet_t * p ;
uint32_t count = 0 ;
endpoint - - ;
2014-09-28 23:44:57 +00:00
if ( endpoint > = NUM_ENDPOINTS )
return 0 ;
2013-01-27 06:47:52 +00:00
__disable_irq ( ) ;
2014-09-28 23:44:57 +00:00
for ( p = tx_first [ endpoint ] ; p ; p = p - > next )
count + + ;
2013-01-27 06:47:52 +00:00
__enable_irq ( ) ;
return count ;
}
// Called from usb_free, but only when usb_rx_memory_needed > 0, indicating
// receive endpoints are starving for memory. The intention is to give
// endpoints needing receive memory priority over the user's code, which is
// likely calling usb_malloc to obtain memory for transmitting. When the
// user is creating data very quickly, their consumption could starve reception
// without this prioritization. The packet buffer (input) is assigned to the
// first endpoint needing memory.
//
2014-09-28 23:44:57 +00:00
void usb_rx_memory ( usb_packet_t * packet )
2013-01-27 06:47:52 +00:00
{
2014-07-15 07:28:12 +00:00
//print("USB RX MEMORY");
2013-01-27 06:47:52 +00:00
unsigned int i ;
const uint8_t * cfg ;
cfg = usb_endpoint_config_table ;
//serial_print("rx_mem:");
__disable_irq ( ) ;
2014-11-11 07:42:39 +00:00
for ( i = 1 ; i < = NUM_ENDPOINTS ; i + + )
{
if ( * cfg + + & USB_ENDPT_EPRXEN )
{
2014-09-28 23:44:57 +00:00
if ( table [ index ( i , RX , EVEN ) ] . desc = = 0 )
{
2014-11-11 07:42:39 +00:00
table [ index ( i , RX , EVEN ) ] . addr = packet - > buf ;
table [ index ( i , RX , EVEN ) ] . desc = BDT_DESC ( 64 , 0 ) ;
2013-01-27 06:47:52 +00:00
usb_rx_memory_needed - - ;
__enable_irq ( ) ;
//serial_phex(i);
//serial_print(",even\n");
return ;
}
2014-09-28 23:44:57 +00:00
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 ) ;
2013-01-27 06:47:52 +00:00
usb_rx_memory_needed - - ;
__enable_irq ( ) ;
//serial_phex(i);
//serial_print(",odd\n");
return ;
}
}
}
__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
2014-07-15 07:28:12 +00:00
// was actually needed.
2013-01-27 06:47:52 +00:00
usb_rx_memory_needed = 0 ;
2014-09-28 23:44:57 +00:00
usb_free ( packet ) ;
2013-01-27 06:47:52 +00:00
return ;
}
//#define index(endpoint, tx, odd) (((endpoint) << 2) | ((tx) << 1) | (odd))
//#define stat2bufferdescriptor(stat) (table + ((stat) >> 2))
2014-09-28 23:44:57 +00:00
void usb_tx ( uint32_t endpoint , usb_packet_t * packet )
2013-01-27 06:47:52 +00:00
{
2014-09-28 23:44:57 +00:00
bdt_t * b = & table [ index ( endpoint , TX , EVEN ) ] ;
2013-01-27 06:47:52 +00:00
uint8_t next ;
endpoint - - ;
2014-09-28 23:44:57 +00:00
if ( endpoint > = NUM_ENDPOINTS )
return ;
2013-01-27 06:47:52 +00:00
__disable_irq ( ) ;
//serial_print("txstate=");
2014-09-28 23:44:57 +00:00
//serial_phex(tx_state[ endpoint ]);
2013-01-27 06:47:52 +00:00
//serial_print("\n");
2014-09-28 23:44:57 +00:00
switch ( tx_state [ endpoint ] )
{
case TX_STATE_BOTH_FREE_EVEN_FIRST :
2013-01-27 06:47:52 +00:00
next = TX_STATE_ODD_FREE ;
break ;
2014-09-28 23:44:57 +00:00
case TX_STATE_BOTH_FREE_ODD_FIRST :
2013-01-27 06:47:52 +00:00
b + + ;
next = TX_STATE_EVEN_FREE ;
break ;
2014-09-28 23:44:57 +00:00
case TX_STATE_EVEN_FREE :
2014-02-03 00:19:58 +00:00
next = TX_STATE_NONE_FREE_ODD_FIRST ;
2013-01-27 06:47:52 +00:00
break ;
2014-09-28 23:44:57 +00:00
case TX_STATE_ODD_FREE :
2013-01-27 06:47:52 +00:00
b + + ;
2014-02-03 00:19:58 +00:00
next = TX_STATE_NONE_FREE_EVEN_FIRST ;
2013-01-27 06:47:52 +00:00
break ;
2014-09-28 23:44:57 +00:00
default :
if ( tx_first [ endpoint ] = = NULL )
{
tx_first [ endpoint ] = packet ;
}
else
{
tx_last [ endpoint ] - > next = packet ;
2013-01-27 06:47:52 +00:00
}
2014-09-28 23:44:57 +00:00
tx_last [ endpoint ] = packet ;
2013-01-27 06:47:52 +00:00
__enable_irq ( ) ;
return ;
}
2014-09-28 23:44:57 +00:00
tx_state [ endpoint ] = next ;
2013-01-27 06:47:52 +00:00
b - > addr = packet - > buf ;
2014-09-28 23:44:57 +00:00
b - > desc = BDT_DESC ( packet - > len , ( ( uint32_t ) b & 8 ) ? DATA1 : DATA0 ) ;
2013-01-27 06:47:52 +00:00
__enable_irq ( ) ;
}
2014-01-23 10:01:12 +00:00
void usb_device_reload ( )
{
2014-07-19 16:21:35 +00:00
// MCHCK
# if defined(_mk20dx128vlf5_)
2014-08-01 08:26:25 +00:00
// 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 ) )
{
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
{
2014-08-15 17:42:12 +00:00
// Copies variable into the VBAT register, must be identical to the variable in the bootloader to jump to the bootloader flash mode
2014-09-28 23:44:57 +00:00
for ( int pos = 0 ; pos < sizeof ( sys_reset_to_loader_magic ) ; pos + + )
( & VBAT ) [ pos ] = sys_reset_to_loader_magic [ pos ] ;
2014-08-01 08:26:25 +00:00
SOFTWARE_RESET ( ) ;
}
2014-07-19 16:21:35 +00:00
// Teensy 3.0 and 3.1
# else
2014-01-23 10:01:12 +00:00
asm volatile ( " bkpt " ) ;
2014-07-19 16:21:35 +00:00
# endif
2014-01-23 10:01:12 +00:00
}
2013-01-27 06:47:52 +00:00
2014-07-15 07:28:12 +00:00
void usb_isr ( )
2013-01-27 06:47:52 +00:00
{
uint8_t status , stat , t ;
//serial_print("isr");
//status = USB0_ISTAT;
//serial_phex(status);
//serial_print("\n");
2014-11-11 07:42:39 +00:00
restart :
2013-01-27 06:47:52 +00:00
status = USB0_ISTAT ;
2014-07-15 07:28:12 +00:00
/*
print ( " USB ISR STATUS: " ) ;
printHex ( status ) ;
print ( NL ) ;
*/
2013-01-27 06:47:52 +00:00
2014-09-28 23:44:57 +00:00
if ( ( status & USB_INTEN_SOFTOKEN /* 04 */ ) )
{
if ( usb_configuration )
{
2013-01-27 06:47:52 +00:00
t = usb_reboot_timer ;
2014-09-28 23:44:57 +00:00
if ( t )
{
2013-01-27 06:47:52 +00:00
usb_reboot_timer = - - t ;
2014-09-28 23:44:57 +00:00
if ( ! t )
usb_device_reload ( ) ;
2013-01-27 06:47:52 +00:00
}
2014-09-28 23:44:57 +00:00
// CDC Interface
2013-01-27 06:47:52 +00:00
t = usb_cdc_transmit_flush_timer ;
2014-09-28 23:44:57 +00:00
if ( t )
{
2013-01-27 06:47:52 +00:00
usb_cdc_transmit_flush_timer = - - t ;
2014-09-28 23:44:57 +00:00
if ( t = = 0 )
usb_serial_flush_callback ( ) ;
2013-01-27 06:47:52 +00:00
}
2014-09-28 23:44:57 +00:00
2013-01-27 06:47:52 +00:00
}
USB0_ISTAT = USB_INTEN_SOFTOKEN ;
}
2014-09-28 23:44:57 +00:00
if ( ( status & USB_ISTAT_TOKDNE /* 08 */ ) )
{
2013-01-27 06:47:52 +00:00
uint8_t endpoint ;
stat = USB0_STAT ;
//serial_print("token: ep=");
//serial_phex(stat >> 4);
//serial_print(stat & 0x08 ? ",tx" : ",rx");
//serial_print(stat & 0x04 ? ",odd\n" : ",even\n");
endpoint = stat > > 4 ;
2014-09-28 23:44:57 +00:00
if ( endpoint = = 0 )
{
usb_control ( stat ) ;
}
else
{
2013-01-27 06:47:52 +00:00
bdt_t * b = stat2bufferdescriptor ( stat ) ;
usb_packet_t * packet = ( usb_packet_t * ) ( ( uint8_t * ) ( b - > addr ) - 8 ) ;
#if 0
serial_print ( " ep: " ) ;
serial_phex ( endpoint ) ;
serial_print ( " , pid: " ) ;
serial_phex ( BDT_PID ( b - > desc ) ) ;
serial_print ( ( ( uint32_t ) b & 8 ) ? " , odd " : " , even " ) ;
serial_print ( " , count: " ) ;
serial_phex ( b - > desc > > 16 ) ;
serial_print ( " \n " ) ;
# endif
endpoint - - ; // endpoint is index to zero-based arrays
2014-09-28 23:44:57 +00:00
if ( stat & 0x08 )
{ // transmit
usb_free ( packet ) ;
2014-11-11 07:42:39 +00:00
packet = tx_first [ endpoint ] ;
2014-09-28 23:44:57 +00:00
if ( packet )
{
2013-01-27 06:47:52 +00:00
//serial_print("tx packet\n");
tx_first [ endpoint ] = packet - > next ;
b - > addr = packet - > buf ;
2014-09-28 23:44:57 +00:00
switch ( tx_state [ endpoint ] )
{
case TX_STATE_BOTH_FREE_EVEN_FIRST :
2014-11-11 07:42:39 +00:00
tx_state [ endpoint ] = TX_STATE_ODD_FREE ;
2013-01-27 06:47:52 +00:00
break ;
2014-09-28 23:44:57 +00:00
case TX_STATE_BOTH_FREE_ODD_FIRST :
2014-11-11 07:42:39 +00:00
tx_state [ endpoint ] = TX_STATE_EVEN_FREE ;
2013-01-27 06:47:52 +00:00
break ;
2014-09-28 23:44:57 +00:00
case TX_STATE_EVEN_FREE :
2014-11-11 07:42:39 +00:00
tx_state [ endpoint ] = TX_STATE_NONE_FREE_ODD_FIRST ;
2014-02-03 00:19:58 +00:00
break ;
2014-09-28 23:44:57 +00:00
case TX_STATE_ODD_FREE :
2014-11-11 07:42:39 +00:00
tx_state [ endpoint ] = TX_STATE_NONE_FREE_EVEN_FIRST ;
2014-02-03 00:19:58 +00:00
break ;
2014-09-28 23:44:57 +00:00
default :
2013-01-27 06:47:52 +00:00
break ;
}
2014-11-11 07:42:39 +00:00
b - > desc = BDT_DESC ( packet - > len , ( ( uint32_t ) b & 8 ) ? DATA1 : DATA0 ) ;
2013-01-27 06:47:52 +00:00
} else {
//serial_print("tx no packet\n");
2014-09-28 23:44:57 +00:00
switch ( tx_state [ endpoint ] )
{
case TX_STATE_BOTH_FREE_EVEN_FIRST :
case TX_STATE_BOTH_FREE_ODD_FIRST :
2013-01-27 06:47:52 +00:00
break ;
2014-09-28 23:44:57 +00:00
case TX_STATE_EVEN_FREE :
2014-11-11 07:42:39 +00:00
tx_state [ endpoint ] = TX_STATE_BOTH_FREE_EVEN_FIRST ;
2013-01-27 06:47:52 +00:00
break ;
2014-09-28 23:44:57 +00:00
case TX_STATE_ODD_FREE :
2014-11-11 07:42:39 +00:00
tx_state [ endpoint ] = TX_STATE_BOTH_FREE_ODD_FIRST ;
2013-01-27 06:47:52 +00:00
break ;
2014-09-28 23:44:57 +00:00
default :
2014-11-11 07:42:39 +00:00
tx_state [ endpoint ] = ( ( uint32_t ) b & 8 )
2014-09-28 23:44:57 +00:00
? TX_STATE_ODD_FREE
: TX_STATE_EVEN_FREE ;
2013-01-27 06:47:52 +00:00
break ;
}
}
2014-09-28 23:44:57 +00:00
}
else
{ // receive
2013-01-27 06:47:52 +00:00
packet - > len = b - > desc > > 16 ;
2014-11-11 07:42:39 +00:00
if ( packet - > len > 0 )
{
2014-02-03 00:19:58 +00:00
packet - > index = 0 ;
packet - > next = NULL ;
2014-11-11 07:42:39 +00:00
if ( rx_first [ endpoint ] = = NULL )
2014-09-28 23:44:57 +00:00
{
2014-02-03 00:19:58 +00:00
//serial_print("rx 1st, epidx=");
//serial_phex(endpoint);
//serial_print(", packet=");
//serial_phex32((uint32_t)packet);
//serial_print("\n");
2014-11-11 07:42:39 +00:00
rx_first [ endpoint ] = packet ;
2014-09-28 23:44:57 +00:00
}
else
{
2014-02-03 00:19:58 +00:00
//serial_print("rx Nth, epidx=");
//serial_phex(endpoint);
//serial_print(", packet=");
//serial_phex32((uint32_t)packet);
//serial_print("\n");
2014-11-11 07:42:39 +00:00
rx_last [ endpoint ] - > next = packet ;
2014-02-03 00:19:58 +00:00
}
2014-11-11 07:42:39 +00:00
rx_last [ endpoint ] = packet ;
usb_rx_byte_count_data [ endpoint ] + = packet - > len ;
2014-02-03 00:19:58 +00:00
// 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 ( ) ;
2014-09-28 23:44:57 +00:00
if ( packet )
{
2014-02-03 00:19:58 +00:00
b - > addr = packet - > buf ;
2014-11-11 07:42:39 +00:00
b - > desc = BDT_DESC ( 64 , ( ( uint32_t ) b & 8 ) ? DATA1 : DATA0 ) ;
2014-09-28 23:44:57 +00:00
}
else
{
2014-02-03 00:19:58 +00:00
//serial_print("starving ");
//serial_phex(endpoint + 1);
//serial_print(((uint32_t)b & 8) ? ",odd\n" : ",even\n");
b - > desc = 0 ;
usb_rx_memory_needed + + ;
}
2014-09-28 23:44:57 +00:00
}
else
{
2014-11-11 07:42:39 +00:00
b - > desc = BDT_DESC ( 64 , ( ( uint32_t ) b & 8 ) ? DATA1 : DATA0 ) ;
2013-01-27 06:47:52 +00:00
}
}
}
USB0_ISTAT = USB_ISTAT_TOKDNE ;
goto restart ;
}
2014-09-28 23:44:57 +00:00
if ( status & USB_ISTAT_USBRST /* 01 */ )
{
2013-01-27 06:47:52 +00:00
//serial_print("reset\n");
// initialize BDT toggle bits
USB0_CTL = USB_CTL_ODDRST ;
ep0_tx_bdt_bank = 0 ;
// set up buffers to receive Setup and OUT packets
2014-11-11 07:42:39 +00:00
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 ;
2014-06-26 07:54:39 +00:00
2013-01-27 06:47:52 +00:00
// activate endpoint 0
USB0_ENDPT0 = USB_ENDPT_EPRXEN | USB_ENDPT_EPTXEN | USB_ENDPT_EPHSHK ;
// clear all ending interrupts
USB0_ERRSTAT = 0xFF ;
USB0_ISTAT = 0xFF ;
// set the address to zero during enumeration
USB0_ADDR = 0 ;
// enable other interrupts
USB0_ERREN = 0xFF ;
USB0_INTEN = USB_INTEN_TOKDNEEN |
USB_INTEN_SOFTOKEN |
USB_INTEN_STALLEN |
USB_INTEN_ERROREN |
USB_INTEN_USBRSTEN |
USB_INTEN_SLEEPEN ;
// is this necessary?
USB0_CTL = USB_CTL_USBENSOFEN ;
return ;
}
2014-09-28 23:44:57 +00:00
if ( ( status & USB_ISTAT_STALL /* 80 */ ) )
{
2013-01-27 06:47:52 +00:00
//serial_print("stall:\n");
USB0_ENDPT0 = USB_ENDPT_EPRXEN | USB_ENDPT_EPTXEN | USB_ENDPT_EPHSHK ;
USB0_ISTAT = USB_ISTAT_STALL ;
}
2014-09-28 23:44:57 +00:00
if ( ( status & USB_ISTAT_ERROR /* 02 */ ) )
{
2013-01-27 06:47:52 +00:00
uint8_t err = USB0_ERRSTAT ;
USB0_ERRSTAT = err ;
//serial_print("err:");
//serial_phex(err);
//serial_print("\n");
USB0_ISTAT = USB_ISTAT_ERROR ;
}
2014-09-28 23:44:57 +00:00
if ( ( status & USB_ISTAT_SLEEP /* 10 */ ) )
{
2013-01-27 06:47:52 +00:00
//serial_print("sleep\n");
USB0_ISTAT = USB_ISTAT_SLEEP ;
}
}
2015-02-09 21:21:23 +00:00
uint8_t usb_init ( )
2013-01-27 06:47:52 +00:00
{
2014-09-28 23:44:57 +00:00
# ifdef UART_DEBUG
print ( " USB INIT " NL ) ;
# endif
2014-02-03 00:19:58 +00:00
2015-02-09 21:21:23 +00:00
// If no USB cable is attached, do not initialize usb
// XXX Test -HaaTa
//if ( USB0_OTGISTAT & USB_OTGSTAT_ID )
// return 0;
2014-07-15 07:28:12 +00:00
// Clear out endpoints table
for ( int i = 0 ; i < = NUM_ENDPOINTS * 4 ; i + + )
{
2013-01-27 06:47:52 +00:00
table [ i ] . desc = 0 ;
table [ i ] . addr = 0 ;
}
// this basically follows the flowchart in the Kinetis
// Quick Reference User Guide, Rev. 1, 03/2012, page 141
// assume 48 MHz clock already running
// SIM - enable clock
SIM_SCGC4 | = SIM_SCGC4_USBOTG ;
// reset USB module
USB0_USBTRC0 = USB_USBTRC_USBRESET ;
2014-07-15 07:28:12 +00:00
while ( ( USB0_USBTRC0 & USB_USBTRC_USBRESET ) ! = 0 ) ; // wait for reset to end
2013-01-27 06:47:52 +00:00
// set desc table base addr
USB0_BDTPAGE1 = ( ( uint32_t ) table ) > > 8 ;
USB0_BDTPAGE2 = ( ( uint32_t ) table ) > > 16 ;
USB0_BDTPAGE3 = ( ( uint32_t ) table ) > > 24 ;
// clear all ISR flags
USB0_ISTAT = 0xFF ;
USB0_ERRSTAT = 0xFF ;
USB0_OTGISTAT = 0xFF ;
USB0_USBTRC0 | = 0x40 ; // undocumented bit
// enable USB
USB0_CTL = USB_CTL_USBENSOFEN ;
USB0_USBCTRL = 0 ;
// enable reset interrupt
USB0_INTEN = USB_INTEN_USBRSTEN ;
// enable interrupt in NVIC...
2014-07-15 07:28:12 +00:00
NVIC_SET_PRIORITY ( IRQ_USBOTG , 112 ) ;
NVIC_ENABLE_IRQ ( IRQ_USBOTG ) ;
2013-01-27 06:47:52 +00:00
// enable d+ pullup
USB0_CONTROL = USB_CONTROL_DPPULLUPNONOTG ;
2015-02-09 21:21:23 +00:00
return 1 ;
2013-01-27 06:47:52 +00:00
}
// return 0 if the USB is not configured, or the configuration
// number selected by the HOST
2014-07-15 07:28:12 +00:00
uint8_t usb_configured ( )
2013-01-27 06:47:52 +00:00
{
return usb_configuration ;
}