#include "usb_dev.h"
#include "usb_mem.h"
+#if enableVirtualSerialPort_define == 1
+#include "usb_serial.h"
+#endif
+
// ----- Defines -----
static void endpoint0_stall()
{
#ifdef UART_DEBUG_UNKNOWN
- print("STALL" NL );
+ print("STALL : ");
+ printInt32( systick_millis_count - USBInit_TimeStart );
+ print(" ms");
+ print(NL);
#endif
USB0_ENDPT0 = USB_ENDPT_EPSTALL | USB_ENDPT_EPRXEN | USB_ENDPT_EPTXEN | USB_ENDPT_EPHSHK;
}
void usb_reinit()
{
- power_neg_delay = 0;
usb_configuration = 0; // Clear USB configuration if we have one
USB0_CONTROL = 0; // Disable D+ Pullup to simulate disconnect
delay(10); // Delay is necessary to simulate disconnect
// Check if 100 ms has elapsed
if ( systick_millis_count - power_neg_time > 100 )
{
+ power_neg_delay = 0;
+
+ // USB Low Power Negotiation
+#if enableUSBLowPowerNegotiation_define == 1
+ // Check to see if bMaxPower has already be lowered
+ // This generally points to a USB bug (host or device?)
+ if ( *usb_bMaxPower == 50 )
+ {
+ warn_msg("Power negotiation delay detected again, likely a system/device USB bug");
+ return;
+ }
+
// Update bMaxPower
// The value set is in increments of 2 mA
// So 50 * 2 mA = 100 mA
// Re-initialize USB
usb_reinit();
+#else
+ warn_msg("USB Low Power Negotation Disabled, condition detected.");
+#endif
}
}
}
const uint8_t *cfg;
int i;
+ // Reset USB Init timer
+ USBInit_TimeEnd = systick_millis_count;
+ USBInit_Ticks++;
+
// If another request is made, disable the power negotiation check
// See GET_DESCRIPTOR - Configuration
if ( power_neg_delay )
endpoint0_stall();
return;
+#if enableVirtualSerialPort_define == 1
case 0x2221: // CDC_SET_CONTROL_LINE_STATE
usb_cdc_line_rtsdtr = setup.wValue;
- //serial_print("set control line state\n");
+ //info_print("set control line state");
goto send;
case 0x21A1: // CDC_GET_LINE_CODING
- data = (uint8_t*)usb_cdc_line_coding;
+ data = (uint8_t*)&usb_cdc_line_coding;
datalen = sizeof( usb_cdc_line_coding );
goto send;
case 0x2021: // CDC_SET_LINE_CODING
- // XXX Needed?
- //serial_print("set coding, waiting...\n");
- return;
+ // ZLP Reply
+ // Settings are applied in PID=OUT
+ goto send;
+#endif
case 0x0921: // HID SET_REPORT
+ // ZLP Reply
+ // Settings are applied in PID=OUT
+
+ #ifdef UART_DEBUG
+ print("report_type(");
+ printHex( setup.wValue >> 8 );
+ print(")report_id(");
+ printHex( setup.wValue & 0xFF );
+ print(")interface(");
+ printHex( setup.wIndex );
+ print(")len(");
+ printHex( setup.wLength );
+ print(")");
+ print( NL );
+ #endif
+
// Interface
switch ( setup.wIndex & 0xFF )
{
printHex( setup.wIndex );
print( NL );
endpoint0_stall();
- break;
+ return;
}
goto send;
datalen = list->length;
goto send;
}
- }
- endpoint0_stall();
- return;
+ }
+ endpoint0_stall();
+ return;
case 0x0A21: // HID SET_IDLE
#ifdef UART_DEBUG
print(NL);
#endif
reply_buffer[0] = USBKeys_Idle_Config;
+ data = reply_buffer;
datalen = 1;
goto send;
print(NL);
#endif
reply_buffer[0] = USBKeys_Protocol;
+ data = reply_buffer;
datalen = 1;
goto send;
// case 0xC940:
default:
#ifdef UART_DEBUG_UNKNOWN
- print("UNKNOWN");
+ print("UNKNOWN: ");
+ printInt32( systick_millis_count - USBInit_TimeStart );
+ print(" ms");
print(NL);
#endif
endpoint0_stall();
if ( size > EP0_SIZE )
size = EP0_SIZE;
- endpoint0_transmit(data, size);
+ endpoint0_transmit( data, size );
data += size;
datalen -= size;
size = datalen;
if ( size > EP0_SIZE )
size = EP0_SIZE;
- endpoint0_transmit(data, size);
+ endpoint0_transmit( data, size );
data += size;
datalen -= size;
//to be set to their default values. This includes setting the data toggle of
//any endpoint using data toggles to the value DATA0.
-//For endpoints using data toggle, regardless of whether an endpoint has the
-//Halt feature set, a ClearFeature(ENDPOINT_HALT) request always results in the
-//data toggle being reinitialized to DATA0.
+// For endpoints using data toggle, regardless of whether an endpoint has the
+// Halt feature set, a ClearFeature(ENDPOINT_HALT) request always results in the
+// data toggle being reinitialized to DATA0.
static void usb_control( uint32_t stat )
{
print(" - ");
#endif
- switch (pid)
+ switch ( pid )
{
case 0x0D: // Setup received from host
- //serial_print("PID=Setup\n");
- //if (count != 8) ; // panic?
// grab the 8 byte setup info
setup.word1 = *(uint32_t *)(buf);
setup.word2 = *(uint32_t *)(buf + 4);
//}
table[index(0, TX, EVEN)].desc = 0;
table[index(0, TX, ODD)].desc = 0;
+
// first IN after Setup is always DATA1
ep0_tx_data_toggle = 1;
#ifdef UART_DEBUG_UNKNOWN
- print("bmRequestType:");
- printHex(setup.bmRequestType);
- print(", bRequest:");
- printHex(setup.bRequest);
+ printHex( stat );
+ print(" PID=SETUP wRequestAndType:");
+ printHex(setup.wRequestAndType);
print(", wValue:");
printHex(setup.wValue);
print(", wIndex:");
printHex32(setup.word1);
print(" ");
printHex32(setup.word2);
+ print(": ");
+ printInt32( systick_millis_count - USBInit_TimeStart );
+ print(" ms");
print(NL);
#endif
+
// actually "do" the setup request
usb_setup();
// unfreeze the USB, now that we're ready
case 0x01: // OUT transaction received from host
case 0x02:
#ifdef UART_DEBUG_UNKNOWN
- print("PID=OUT wRequestAndType:");
+ printHex( stat );
+ print(" PID=OUT wRequestAndType:");
printHex(setup.wRequestAndType);
print(", wValue:");
printHex(setup.wValue);
printHex32(setup.word1);
print(" ");
printHex32(setup.word2);
+ print(": ");
+ printInt32( systick_millis_count - USBInit_TimeStart );
+ print(" ms");
print(NL);
#endif
// CDC Interface
- if ( setup.wRequestAndType == 0x2021 /*CDC_SET_LINE_CODING*/ )
+ #if enableVirtualSerialPort_define == 1
+ // CDC_SET_LINE_CODING - PID=OUT
+ // XXX - Getting lots of NAKs in Linux
+ if ( setup.wRequestAndType == 0x2021 )
{
- int i;
- uint8_t *dst = (uint8_t *)usb_cdc_line_coding;
- //serial_print("set line coding ");
- for ( i = 0; i < 7; i++ )
- {
- //serial_phex(*buf);
- *dst++ = *buf++;
- }
- //serial_phex32(usb_cdc_line_coding[0]);
- //serial_print("\n");
- if ( usb_cdc_line_coding[0] == 134 )
- usb_reboot_timer = 15;
- endpoint0_transmit( NULL, 0 );
+ // Copy over new line coding
+ memcpy( (void*)&usb_cdc_line_coding, buf, 7 );
+
+ #ifdef UART_DEBUG
+ // - Unused, but for the readers info -
+ print("dwDTERate(");
+ printInt32( usb_cdc_line_coding.dwDTERate );
+ print(")bCharFormat(");
+ printHex( usb_cdc_line_coding.bCharFormat );
+ print(")bParityType(");
+ printHex( usb_cdc_line_coding.bParityType );
+ print(")bDataBits(");
+ printHex( usb_cdc_line_coding.bDataBits );
+ print(")");
+ print( NL );
+ #endif
+
+ // XXX ZLP causes timeout/delay, why? -HaaTa
+ //endpoint0_transmit( NULL, 0 );
}
+ #endif
- // Keyboard SET_REPORT
- if ( setup.wRequestAndType == 0x921 && setup.wValue & 0x200 )
+ // Keyboard HID SET_REPORT - PID=OUT
+ #if enableKeyboard_define == 1
+ // XXX - Getting lots of NAKs in Linux
+ if ( setup.wRequestAndType == 0x0921 && setup.wValue & 0x200 )
{
+ #ifdef UART_DEBUG
+ print("report_type(");
+ printHex( setup.wValue >> 8 );
+ print(")report_id(");
+ printHex( setup.wValue & 0xFF );
+ print(")interface(");
+ printHex( setup.wIndex );
+ print(")len(");
+ printHex( setup.wLength );
+ print(")[");
+
+ for ( size_t len = 0; len < setup.wLength; len++ )
+ {
+ printHex( buf[ len ] );
+ print(" ");
+ }
+ print("]");
+ print( NL );
+ #endif
+
// Interface
switch ( setup.wIndex & 0xFF )
{
// Keyboard Interface
case KEYBOARD_INTERFACE:
USBKeys_LEDs = buf[0];
- endpoint0_transmit( NULL, 0 );
break;
// NKRO Keyboard Interface
case NKRO_KEYBOARD_INTERFACE:
+ // Already set with the control sequence
// Only use 2nd byte, first byte is the report id
USBKeys_LEDs = buf[1];
- endpoint0_transmit( NULL, 0 );
break;
default:
warn_msg("Unknown interface - ");
break;
}
- #ifdef UART_DEBUG
- for ( size_t len = 0; len < setup.wLength; len++ )
- {
- printHex( buf[ len ] );
- print(" ");
- }
- print( NL );
- #endif
+ // XXX ZLP causes timeout/delay, why? -HaaTa
+ //endpoint0_transmit( NULL, 0 );
}
+ #endif
// give the buffer back
b->desc = BDT_DESC( EP0_SIZE, DATA1 );
break;
case 0x09: // IN transaction completed to host
- #ifdef UART_DEBUG
- print("PID=IN:");
- printHex(stat);
+ data = ep0_tx_ptr;
+
+ #ifdef UART_DEBUG_UNKNOWN
+ printHex( stat );
+ print(" PID=IN wRequestAndType:");
+ printHex(setup.wRequestAndType);
+ print(", wValue:");
+ printHex(setup.wValue);
+ print(", wIndex:");
+ printHex(setup.wIndex);
+ print(", len:");
+ printHex(setup.wLength);
+ print(" -- ");
+ printHex32(setup.word1);
+ print(" ");
+ printHex32(setup.word2);
+ print(": ");
+ printInt32( systick_millis_count - USBInit_TimeStart );
+ print(" ms");
+ if ( data ) print(" DATA ");
print(NL);
#endif
// send remaining data, if any...
- data = ep0_tx_ptr;
if ( data )
{
size = ep0_tx_len;
- if (size > EP0_SIZE) size = EP0_SIZE;
- endpoint0_transmit(data, size);
+ if (size > EP0_SIZE)
+ {
+ size = EP0_SIZE;
+ }
+ endpoint0_transmit( data, size );
data += size;
ep0_tx_len -= size;
ep0_tx_ptr = (ep0_tx_len > 0 || size == EP0_SIZE) ? data : NULL;
USB0_ADDR = setup.wValue;
}
+ // CDC_SET_LINE_CODING - PID=IN
+ #if enableVirtualSerialPort_define == 1
+ if ( setup.wRequestAndType == 0x2021 )
+ {
+ // XXX ZLP causes timeout/delay, why? -HaaTa
+ //endpoint0_transmit( NULL, 0 );
+ }
+ #endif
+
+ // Keyboard HID SET_REPORT - PID=IN
+ #if enableKeyboard_define == 1
+ // XXX - Getting lots of NAKs in Linux
+ if ( setup.wRequestAndType == 0x0921 && setup.wValue & 0x200 )
+ {
+ // XXX ZLP causes timeout/delay, why? -HaaTa
+ //endpoint0_transmit( NULL, 0 );
+ }
+ #endif
+
break;
default:
- #ifdef UART_DEBUG
- print("PID=unknown:");
+ #ifdef UART_DEBUG_UNKNOWN
+ print("PID=unknown: ");
printHex(pid);
+ print(": ");
+ printInt32( systick_millis_count - USBInit_TimeStart );
+ print(" ms");
print(NL);
#endif
break;
//print("USB RX");
usb_packet_t *ret;
endpoint--;
+
+ // Make sure this is a valid endpoint
if ( endpoint >= NUM_ENDPOINTS )
+ {
return NULL;
+ }
+
__disable_irq();
+
+ // Receive packet, check pointer
ret = rx_first[endpoint];
if ( ret )
+ {
rx_first[ endpoint ] = ret->next;
- usb_rx_byte_count_data[ endpoint ] -= ret->len;
+ usb_rx_byte_count_data[ endpoint ] -= ret->len;
+ }
+
__enable_irq();
+
//serial_print("rx, epidx=");
//serial_phex(endpoint);
//serial_print(", packet=");
return;
}
-//#define index(endpoint, tx, odd) (((endpoint) << 2) | ((tx) << 1) | (odd))
-//#define stat2bufferdescriptor(stat) (table + ((stat) >> 2))
-
-void usb_tx( uint32_t endpoint, usb_packet_t *packet )
+// Call whenever there's an action that may wake the host device
+void usb_resume()
{
- // Update expiry counter
- USBKeys_Idle_Expiry = systick_millis_count;
-
// If we have been sleeping, try to wake up host
- if ( usb_dev_sleep )
+ if ( usb_dev_sleep && usb_configured() )
{
+ #if enableUSBResume_define == 1
+ #if enableVirtualSerialPort_define != 1
+ info_print("Attempting to resume the host");
+ #endif
// Force wake-up for 10 ms
// According to the USB Spec a device must hold resume for at least 1 ms but no more than 15 ms
USB0_CTL |= USB_CTL_RESUME;
USB0_CTL &= ~(USB_CTL_RESUME);
delay(50); // Wait for at least 50 ms to make sure the bus is clear
usb_dev_sleep = 0; // Make sure we don't call this again, may crash system
+ #else
+ warn_print("Host Resume Disabled");
+ #endif
}
+}
+
+void usb_tx( uint32_t endpoint, usb_packet_t *packet )
+{
+ // Update expiry counter
+ USBKeys_Idle_Expiry = systick_millis_count;
+
// Since we are transmitting data, USB will be brought out of sleep/suspend
// if it's in that state
// Use the currently set descriptor value
{
uint8_t status, stat, t;
- //serial_print("isr");
- //status = USB0_ISTAT;
- //serial_phex(status);
- //serial_print("\n");
restart:
status = USB0_ISTAT;
/*
- print("USB ISR STATUS: ");
+ print(" ISR(");
printHex( status );
- print( NL );
+ print(") ");
*/
if ( (status & USB_INTEN_SOFTOKEN /* 04 */ ) )
}
// CDC Interface
+ #if enableVirtualSerialPort_define == 1
t = usb_cdc_transmit_flush_timer;
if ( t )
{
if ( t == 0 )
usb_serial_flush_callback();
}
+ #endif
}
USB0_ISTAT = USB_INTEN_SOFTOKEN;
// The USB Module triggers this interrupt when it detects the bus has been idle for 3 ms
if ( (status & USB_ISTAT_SLEEP /* 10 */ ) )
{
- //info_print("Host has requested USB sleep/suspend state");
+#if enableUSBSuspend_define == 1
+ // Can cause issues with the virtual serial port
+ #if enableVirtualSerialPort_define != 1
+ info_print("Host has requested USB sleep/suspend state");
+ #endif
Output_update_usb_current( 100 ); // Set to 100 mA
usb_dev_sleep = 1;
+#else
+ info_print("USB Suspend Detected - Firmware USB Suspend Disabled");
+#endif
USB0_ISTAT |= USB_ISTAT_SLEEP;
}
// On USB Resume, unset the usb_dev_sleep so we don't keep sending resume signals
if ( (status & USB_ISTAT_RESUME /* 20 */ ) )
{
- //info_print("Host has woken-up/resumed from sleep/suspend state");
+ // Can cause issues with the virtual serial port
+ #if enableVirtualSerialPort_define != 1
+ info_print("Host has woken-up/resumed from sleep/suspend state");
+ #endif
Output_update_usb_current( *usb_bMaxPower * 2 );
usb_dev_sleep = 0;
USB0_ISTAT |= USB_ISTAT_RESUME;
print("USB INIT"NL);
#endif
+ USBInit_TimeStart = systick_millis_count;
+ USBInit_Ticks = 0;
+
+ // XXX Set wTotalLength here instead of using defines
+ // Simplifies defines considerably
+ usb_set_config_descriptor_size();
+
// Clear out endpoints table
for ( int i = 0; i <= NUM_ENDPOINTS * 4; i++ )
{