X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=protocol%2Flufa%2Flufa.c;h=16a602df13f76d7bd4485ac273af01fbc90dd50a;hb=8f5f25fcd50d93da0f6ad53d0b622a258387c6a1;hp=f485e24bf0228586b4dd82d0d18f0520ac042168;hpb=f2ebac101d367ee091f54b8d43b39a4d74f3b90e;p=tmk_firmware.git diff --git a/protocol/lufa/lufa.c b/protocol/lufa/lufa.c index f485e24..16a602d 100644 --- a/protocol/lufa/lufa.c +++ b/protocol/lufa/lufa.c @@ -40,19 +40,24 @@ #include "host.h" #include "host_driver.h" #include "keyboard.h" +#include "action.h" +#include "led.h" #include "sendchar.h" #include "debug.h" +#ifdef SLEEP_LED_ENABLE +#include "sleep_led.h" +#endif +#include "suspend.h" #include "descriptor.h" #include "lufa.h" +uint8_t keyboard_idle = 0; +uint8_t keyboard_protocol = 1; static uint8_t keyboard_led_stats = 0; -// TODO: impl Control Request GET_REPORT static report_keyboard_t keyboard_report_sent; -#ifdef MOUSE_ENABLE -static report_mouse_t mouse_report_sent; -#endif + /* Host driver */ static uint8_t keyboard_leds(void); @@ -60,7 +65,7 @@ static void send_keyboard(report_keyboard_t *report); static void send_mouse(report_mouse_t *report); static void send_system(uint16_t data); static void send_consumer(uint16_t data); -static host_driver_t lufa_driver = { +host_driver_t lufa_driver = { keyboard_leds, send_keyboard, send_mouse, @@ -69,99 +74,113 @@ static host_driver_t lufa_driver = { }; -static void SetupHardware(void); -static void Console_HID_Task(void); - -int main(void) +/******************************************************************************* + * Console + ******************************************************************************/ +#ifdef CONSOLE_ENABLE +static void Console_Task(void) { - SetupHardware(); - sei(); + /* Device must be connected and configured for the task to run */ + if (USB_DeviceState != DEVICE_STATE_Configured) + return; - print_enable = true; - debug_enable = true; - debug_matrix = true; - debug_keyboard = true; - debug_mouse = true; - -/* TODO: can't print here - _delay_ms(5000); - USB_USBTask(); - print("abcdefg\n"); - USB_USBTask(); -*/ + uint8_t ep = Endpoint_GetCurrentEndpoint(); - keyboard_init(); - host_set_driver(&lufa_driver); - while (1) { - keyboard_proc(); +#if 0 + // TODO: impl receivechar()/recvchar() + Endpoint_SelectEndpoint(CONSOLE_OUT_EPNUM); - Console_HID_Task(); - USB_USBTask(); + /* Check to see if a packet has been sent from the host */ + if (Endpoint_IsOUTReceived()) + { + /* Check to see if the packet contains data */ + if (Endpoint_IsReadWriteAllowed()) + { + /* Create a temporary buffer to hold the read in report from the host */ + uint8_t ConsoleData[CONSOLE_EPSIZE]; + + /* Read Console Report Data */ + Endpoint_Read_Stream_LE(&ConsoleData, sizeof(ConsoleData), NULL); + + /* Process Console Report Data */ + //ProcessConsoleHIDReport(ConsoleData); + } + + /* Finalize the stream transfer to send the last packet */ + Endpoint_ClearOUT(); } -} +#endif -void SetupHardware(void) -{ - /* Disable watchdog if enabled by bootloader/fuses */ - MCUSR &= ~(1 << WDRF); - wdt_disable(); + /* IN packet */ + Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM); + if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) { + Endpoint_SelectEndpoint(ep); + return; + } - /* Disable clock division */ - clock_prescale_set(clock_div_1); + // fill empty bank + while (Endpoint_IsReadWriteAllowed()) + Endpoint_Write_8(0); - USB_Init(); -} + // flash senchar packet + if (Endpoint_IsINReady()) { + Endpoint_ClearIN(); + } -static void Console_HID_Task(void) + Endpoint_SelectEndpoint(ep); +} +#else +static void Console_Task(void) { - /* Device must be connected and configured for the task to run */ - if (USB_DeviceState != DEVICE_STATE_Configured) - return; - - // TODO: impl receivechar()/recvchar() - Endpoint_SelectEndpoint(CONSOLE_OUT_EPNUM); - - /* Check to see if a packet has been sent from the host */ - if (Endpoint_IsOUTReceived()) - { - /* Check to see if the packet contains data */ - if (Endpoint_IsReadWriteAllowed()) - { - /* Create a temporary buffer to hold the read in report from the host */ - uint8_t ConsoleData[CONSOLE_EPSIZE]; - - /* Read Console Report Data */ - Endpoint_Read_Stream_LE(&ConsoleData, sizeof(ConsoleData), NULL); - - /* Process Console Report Data */ - //ProcessConsoleHIDReport(ConsoleData); - } - - /* Finalize the stream transfer to send the last packet */ - Endpoint_ClearOUT(); - } - - /* IN packet */ - Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM); - // send IN packet - if (Endpoint_IsINReady()) - Endpoint_ClearIN(); } +#endif /******************************************************************************* * USB Events ******************************************************************************/ -/** Event handler for the USB_Connect event. */ +/* + * Event Order of Plug in: + * 0) EVENT_USB_Device_Connect + * 1) EVENT_USB_Device_Suspend + * 2) EVENT_USB_Device_Reset + * 3) EVENT_USB_Device_Wake +*/ void EVENT_USB_Device_Connect(void) { } -/** Event handler for the USB_Disconnect event. */ void EVENT_USB_Device_Disconnect(void) { } +void EVENT_USB_Device_Reset(void) +{ +} + +void EVENT_USB_Device_Suspend() +{ +#ifdef SLEEP_LED_ENABLE + sleep_led_enable(); +#endif +} + +void EVENT_USB_Device_WakeUp() +{ + suspend_wakeup_init(); + +#ifdef SLEEP_LED_ENABLE + sleep_led_disable(); + // NOTE: converters may not accept this + led_set(host_keyboard_leds()); +#endif +} + +void EVENT_USB_Device_StartOfFrame(void) +{ + Console_Task(); +} + /** Event handler for the USB_ConfigurationChanged event. * This is fired when the host sets the current configuration of the USB device after enumeration. */ @@ -170,26 +189,36 @@ void EVENT_USB_Device_ConfigurationChanged(void) bool ConfigSuccess = true; /* Setup Keyboard HID Report Endpoints */ - ConfigSuccess &= Endpoint_ConfigureEndpoint(KEYBOARD_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN, - KEYBOARD_EPSIZE, ENDPOINT_BANK_SINGLE); + ConfigSuccess &= ENDPOINT_CONFIG(KEYBOARD_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN, + KEYBOARD_EPSIZE, ENDPOINT_BANK_SINGLE); #ifdef MOUSE_ENABLE /* Setup Mouse HID Report Endpoint */ - ConfigSuccess &= Endpoint_ConfigureEndpoint(MOUSE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN, - MOUSE_EPSIZE, ENDPOINT_BANK_SINGLE); + ConfigSuccess &= ENDPOINT_CONFIG(MOUSE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN, + MOUSE_EPSIZE, ENDPOINT_BANK_SINGLE); #endif #ifdef EXTRAKEY_ENABLE /* Setup Extra HID Report Endpoint */ - ConfigSuccess &= Endpoint_ConfigureEndpoint(EXTRA_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN, - EXTRA_EPSIZE, ENDPOINT_BANK_SINGLE); + ConfigSuccess &= ENDPOINT_CONFIG(EXTRAKEY_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN, + EXTRAKEY_EPSIZE, ENDPOINT_BANK_SINGLE); #endif +#ifdef CONSOLE_ENABLE /* Setup Console HID Report Endpoints */ - ConfigSuccess &= Endpoint_ConfigureEndpoint(CONSOLE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN, - CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE); - ConfigSuccess &= Endpoint_ConfigureEndpoint(CONSOLE_OUT_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_OUT, - CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE); + ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN, + CONSOLE_EPSIZE, ENDPOINT_BANK_DOUBLE); +#if 0 + ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_OUT_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_OUT, + CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE); +#endif +#endif + +#ifdef NKRO_ENABLE + /* Setup NKRO HID Report Endpoints */ + ConfigSuccess &= ENDPOINT_CONFIG(NKRO_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN, + NKRO_EPSIZE, ENDPOINT_BANK_SINGLE); +#endif } /* @@ -228,19 +257,6 @@ void EVENT_USB_Device_ControlRequest(void) ReportData = (uint8_t*)&keyboard_report_sent; ReportSize = sizeof(keyboard_report_sent); break; -#ifdef MOUSE_ENABLE - case MOUSE_INTERFACE: - // TODO: test/check - ReportData = (uint8_t*)&mouse_report_sent; - ReportSize = sizeof(mouse_report_sent); - break; -#endif -#ifdef EXTRAKEY_ENABLE - case EXTRA_INTERFACE: - break; -#endif - case CONSOLE_INTERFACE: - break; } /* Write the report data to the control endpoint */ @@ -252,35 +268,76 @@ void EVENT_USB_Device_ControlRequest(void) case HID_REQ_SetReport: if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) { - Endpoint_ClearSETUP(); - - /* Wait until the LED report has been sent by the host */ - while (!(Endpoint_IsOUTReceived())) - { - if (USB_DeviceState == DEVICE_STATE_Unattached) - return; - } // Interface switch (USB_ControlRequest.wIndex) { case KEYBOARD_INTERFACE: - // TODO: test/check - /* Read in the LED report from the host */ - keyboard_led_stats = Endpoint_Read_8(); - break; -#ifdef MOUSE_ENABLE - case MOUSE_INTERFACE: - break; +#ifdef NKRO_ENABLE + case NKRO_INTERFACE: #endif -#ifdef EXTRAKEY_ENABLE - case EXTRA_INTERFACE: + Endpoint_ClearSETUP(); + + while (!(Endpoint_IsOUTReceived())) { + if (USB_DeviceState == DEVICE_STATE_Unattached) + return; + } + keyboard_led_stats = Endpoint_Read_8(); + + Endpoint_ClearOUT(); + Endpoint_ClearStatusStage(); break; + } + + } + + break; + + case HID_REQ_GetProtocol: + if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) + { + if (USB_ControlRequest.wIndex == KEYBOARD_INTERFACE) { + Endpoint_ClearSETUP(); + while (!(Endpoint_IsINReady())); + Endpoint_Write_8(keyboard_protocol); + Endpoint_ClearIN(); + Endpoint_ClearStatusStage(); + } + } + + break; + case HID_REQ_SetProtocol: + if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) + { + if (USB_ControlRequest.wIndex == KEYBOARD_INTERFACE) { + Endpoint_ClearSETUP(); + Endpoint_ClearStatusStage(); + + keyboard_protocol = ((USB_ControlRequest.wValue & 0xFF) != 0x00); +#ifdef NKRO_ENABLE + keyboard_nkro = !!keyboard_protocol; #endif - case CONSOLE_INTERFACE: - break; + clear_keyboard(); } + } - Endpoint_ClearOUT(); + break; + case HID_REQ_SetIdle: + if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) + { + Endpoint_ClearSETUP(); + Endpoint_ClearStatusStage(); + + keyboard_idle = ((USB_ControlRequest.wValue & 0xFF00) >> 8); + } + + break; + case HID_REQ_GetIdle: + if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) + { + Endpoint_ClearSETUP(); + while (!(Endpoint_IsINReady())); + Endpoint_Write_8(keyboard_idle); + Endpoint_ClearIN(); Endpoint_ClearStatusStage(); } @@ -298,105 +355,235 @@ static uint8_t keyboard_leds(void) static void send_keyboard(report_keyboard_t *report) { - // TODO: handle NKRO report + uint8_t timeout = 255; + + if (USB_DeviceState != DEVICE_STATE_Configured) + return; + /* Select the Keyboard Report Endpoint */ - Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM); +#ifdef NKRO_ENABLE + if (keyboard_nkro) { + /* Report protocol - NKRO */ + Endpoint_SelectEndpoint(NKRO_IN_EPNUM); + + /* Check if write ready for a polling interval around 1ms */ + while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(4); + if (!Endpoint_IsReadWriteAllowed()) return; - /* Check if Keyboard Endpoint Ready for Read/Write */ - if (Endpoint_IsReadWriteAllowed()) - { /* Write Keyboard Report Data */ - Endpoint_Write_Stream_LE(report, sizeof(report_keyboard_t), NULL); + Endpoint_Write_Stream_LE(report, NKRO_EPSIZE, NULL); + } + else +#endif + { + /* Boot protocol */ + Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM); - /* Finalize the stream transfer to send the last packet */ - Endpoint_ClearIN(); + /* Check if write ready for a polling interval around 10ms */ + while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40); + if (!Endpoint_IsReadWriteAllowed()) return; + + /* Write Keyboard Report Data */ + Endpoint_Write_Stream_LE(report, KEYBOARD_EPSIZE, NULL); } + + /* Finalize the stream transfer to send the last packet */ + Endpoint_ClearIN(); + keyboard_report_sent = *report; } static void send_mouse(report_mouse_t *report) { #ifdef MOUSE_ENABLE + uint8_t timeout = 255; + + if (USB_DeviceState != DEVICE_STATE_Configured) + return; + /* Select the Mouse Report Endpoint */ Endpoint_SelectEndpoint(MOUSE_IN_EPNUM); - /* Check if Mouse Endpoint Ready for Read/Write */ - if (Endpoint_IsReadWriteAllowed()) - { - /* Write Mouse Report Data */ - Endpoint_Write_Stream_LE(report, sizeof(report_mouse_t), NULL); + /* Check if write ready for a polling interval around 10ms */ + while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40); + if (!Endpoint_IsReadWriteAllowed()) return; - /* Finalize the stream transfer to send the last packet */ - Endpoint_ClearIN(); - } - mouse_report_sent = *report; + /* Write Mouse Report Data */ + Endpoint_Write_Stream_LE(report, sizeof(report_mouse_t), NULL); + + /* Finalize the stream transfer to send the last packet */ + Endpoint_ClearIN(); #endif } -typedef struct { - uint8_t report_id; - uint16_t usage; -} __attribute__ ((packed)) report_extra_t; - static void send_system(uint16_t data) { - Endpoint_SelectEndpoint(EXTRA_IN_EPNUM); - if (Endpoint_IsReadWriteAllowed()) { - report_extra_t r = { - .report_id = REPORT_ID_SYSTEM, - .usage = data - }; - Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL); - Endpoint_ClearIN(); - } + uint8_t timeout = 255; + + if (USB_DeviceState != DEVICE_STATE_Configured) + return; + + report_extra_t r = { + .report_id = REPORT_ID_SYSTEM, + .usage = data + }; + Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM); + + /* Check if write ready for a polling interval around 10ms */ + while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40); + if (!Endpoint_IsReadWriteAllowed()) return; + + Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL); + Endpoint_ClearIN(); } static void send_consumer(uint16_t data) { - Endpoint_SelectEndpoint(EXTRA_IN_EPNUM); - if (Endpoint_IsReadWriteAllowed()) { - report_extra_t r = { - .report_id = REPORT_ID_CONSUMER, - .usage = data - }; - Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL); - Endpoint_ClearIN(); - } + uint8_t timeout = 255; + + if (USB_DeviceState != DEVICE_STATE_Configured) + return; + + report_extra_t r = { + .report_id = REPORT_ID_CONSUMER, + .usage = data + }; + Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM); + + /* Check if write ready for a polling interval around 10ms */ + while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40); + if (!Endpoint_IsReadWriteAllowed()) return; + + Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL); + Endpoint_ClearIN(); } /******************************************************************************* * sendchar ******************************************************************************/ +#ifdef CONSOLE_ENABLE +#define SEND_TIMEOUT 5 int8_t sendchar(uint8_t c) { + // Not wait once timeouted. + // Because sendchar() is called so many times, waiting each call causes big lag. + static bool timeouted = false; + if (USB_DeviceState != DEVICE_STATE_Configured) - return -1; + return -1; + uint8_t ep = Endpoint_GetCurrentEndpoint(); Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM); + if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) { + Endpoint_SelectEndpoint(ep); + return -1; + } - uint8_t timeout = 10; + if (timeouted && !Endpoint_IsReadWriteAllowed()) { + Endpoint_SelectEndpoint(ep); + return - 1; + } + + timeouted = false; + + uint8_t timeout = SEND_TIMEOUT; uint16_t prevFN = USB_Device_GetFrameNumber(); - while (!Endpoint_IsINReady()) { + while (!Endpoint_IsReadWriteAllowed()) { switch (USB_DeviceState) { case DEVICE_STATE_Unattached: case DEVICE_STATE_Suspended: return -1; } - if (Endpoint_IsStalled()) + if (Endpoint_IsStalled()) { + Endpoint_SelectEndpoint(ep); return -1; + } if (prevFN != USB_Device_GetFrameNumber()) { - if (!(timeout--)) + if (!(timeout--)) { + timeouted = true; + Endpoint_SelectEndpoint(ep); return -1; + } prevFN = USB_Device_GetFrameNumber(); } } Endpoint_Write_8(c); - // send when packet is full + // send when bank is full if (!Endpoint_IsReadWriteAllowed()) Endpoint_ClearIN(); + Endpoint_SelectEndpoint(ep); + return 0; +} +#else +int8_t sendchar(uint8_t c) +{ return 0; } +#endif + + +/******************************************************************************* + * main + ******************************************************************************/ +static void SetupHardware(void) +{ + /* Disable watchdog if enabled by bootloader/fuses */ + MCUSR &= ~(1 << WDRF); + wdt_disable(); + + /* Disable clock division */ + clock_prescale_set(clock_div_1); + + // Leonardo needs. Without this USB device is not recognized. + USB_Disable(); + + USB_Init(); + + // for Console_Task + USB_Device_EnableSOFEvents(); + print_set_sendchar(sendchar); +} + +int main(void) __attribute__ ((weak)); +int main(void) +{ + SetupHardware(); + sei(); + + /* wait for USB startup & debug output */ + while (USB_DeviceState != DEVICE_STATE_Configured) { +#if defined(INTERRUPT_CONTROL_ENDPOINT) + ; +#else + USB_USBTask(); +#endif + } + print("USB configured.\n"); + + /* init modules */ + keyboard_init(); + host_set_driver(&lufa_driver); +#ifdef SLEEP_LED_ENABLE + sleep_led_init(); +#endif + + print("Keyboard start.\n"); + while (1) { + while (USB_DeviceState == DEVICE_STATE_Suspended) { + suspend_power_down(); + if (USB_Device_RemoteWakeupEnabled && suspend_wakeup_condition()) { + USB_Device_SendRemoteWakeup(); + } + } + + keyboard_task(); + +#if !defined(INTERRUPT_CONTROL_ENDPOINT) + USB_USBTask(); +#endif + } +}