]> git.donarmstrong.com Git - tmk_firmware.git/blobdiff - protocol/lufa/lufa.c
Revert lufa/lufa.c
[tmk_firmware.git] / protocol / lufa / lufa.c
index 10511ba67b27339177740065f280a403a38cceba..16a602df13f76d7bd4485ac273af01fbc90dd50a 100644 (file)
 #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"
 
-static uint8_t idle_duration = 0;
-static uint8_t protocol_report = 1;
+uint8_t keyboard_idle = 0;
+uint8_t keyboard_protocol = 1;
 static uint8_t keyboard_led_stats = 0;
 
 static report_keyboard_t keyboard_report_sent;
@@ -59,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,
@@ -68,54 +74,15 @@ static host_driver_t lufa_driver = {
 };
 
 
-static void SetupHardware(void);
-static void Console_Task(void);
-
-int main(void)
-{
-    SetupHardware();
-    sei();
-
-    print_enable = true;
-    debug_enable = true;
-    debug_matrix = true;
-    debug_keyboard = true;
-    debug_mouse = true;
-
-    // TODO: can't print here
-    debug("LUFA init\n");
-
-    keyboard_init();
-    host_set_driver(&lufa_driver);
-    while (1) {
-        keyboard_proc();
-
-#if !defined(INTERRUPT_CONTROL_ENDPOINT)
-        USB_USBTask();
-#endif
-    }
-}
-
-void SetupHardware(void)
-{
-    /* Disable watchdog if enabled by bootloader/fuses */
-    MCUSR &= ~(1 << WDRF);
-    wdt_disable();
-
-    /* Disable clock division */
-    clock_prescale_set(clock_div_1);
-
-    USB_Init();
-
-    // for Console_Task
-    USB_Device_EnableSOFEvents();
-}
-
+/*******************************************************************************
+ * Console
+ ******************************************************************************/
+#ifdef CONSOLE_ENABLE
 static void Console_Task(void)
 {
     /* Device must be connected and configured for the task to run */
     if (USB_DeviceState != DEVICE_STATE_Configured)
-      return;
+        return;
 
     uint8_t ep = Endpoint_GetCurrentEndpoint();
 
@@ -146,6 +113,15 @@ static void Console_Task(void)
 
     /* IN packet */
     Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
+    if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
+        Endpoint_SelectEndpoint(ep);
+        return;
+    }
+
+    // fill empty bank
+    while (Endpoint_IsReadWriteAllowed())
+        Endpoint_Write_8(0);
+
     // flash senchar packet
     if (Endpoint_IsINReady()) {
         Endpoint_ClearIN();
@@ -153,29 +129,56 @@ static void Console_Task(void)
 
     Endpoint_SelectEndpoint(ep);
 }
+#else
+static void Console_Task(void)
+{
+}
+#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)
 {
 }
 
-#define CONSOLE_TASK_INTERVAL 50
+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)
 {
-    static uint8_t interval;
-    if (++interval == CONSOLE_TASK_INTERVAL) {
-        Console_Task();
-        interval = 0;
-    }
+    Console_Task();
 }
 
 /** Event handler for the USB_ConfigurationChanged event.
@@ -186,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_DOUBLE);
-    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
 }
 
 /*
@@ -259,6 +272,9 @@ void EVENT_USB_Device_ControlRequest(void)
                 // Interface
                 switch (USB_ControlRequest.wIndex) {
                 case KEYBOARD_INTERFACE:
+#ifdef NKRO_ENABLE
+                case NKRO_INTERFACE:
+#endif
                     Endpoint_ClearSETUP();
 
                     while (!(Endpoint_IsOUTReceived())) {
@@ -279,21 +295,29 @@ void EVENT_USB_Device_ControlRequest(void)
         case HID_REQ_GetProtocol:
             if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
             {
-                Endpoint_ClearSETUP();
-                while (!(Endpoint_IsINReady()));
-                Endpoint_Write_8(protocol_report);
-                Endpoint_ClearIN();
-                Endpoint_ClearStatusStage();
+                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))
             {
-                Endpoint_ClearSETUP();
-                Endpoint_ClearStatusStage();
+                if (USB_ControlRequest.wIndex == KEYBOARD_INTERFACE) {
+                    Endpoint_ClearSETUP();
+                    Endpoint_ClearStatusStage();
 
-                protocol_report = ((USB_ControlRequest.wValue & 0xFF) != 0x00);
+                    keyboard_protocol = ((USB_ControlRequest.wValue & 0xFF) != 0x00);
+#ifdef NKRO_ENABLE
+                    keyboard_nkro = !!keyboard_protocol;
+#endif
+                    clear_keyboard();
+                }
             }
 
             break;
@@ -303,7 +327,7 @@ void EVENT_USB_Device_ControlRequest(void)
                 Endpoint_ClearSETUP();
                 Endpoint_ClearStatusStage();
 
-                idle_duration = ((USB_ControlRequest.wValue & 0xFF00) >> 8);
+                keyboard_idle = ((USB_ControlRequest.wValue & 0xFF00) >> 8);
             }
 
             break;
@@ -312,7 +336,7 @@ void EVENT_USB_Device_ControlRequest(void)
             {
                 Endpoint_ClearSETUP();
                 while (!(Endpoint_IsINReady()));
-                Endpoint_Write_8(idle_duration);
+                Endpoint_Write_8(keyboard_idle);
                 Endpoint_ClearIN();
                 Endpoint_ClearStatusStage();
             }
@@ -331,77 +355,137 @@ 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();
-    }
+    /* 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
 }
 
 static void send_system(uint16_t data)
 {
+    uint8_t timeout = 255;
+
+    if (USB_DeviceState != DEVICE_STATE_Configured)
+        return;
+
     report_extra_t r = {
         .report_id = REPORT_ID_SYSTEM,
         .usage = data
     };
-    Endpoint_SelectEndpoint(EXTRA_IN_EPNUM);
-    if (Endpoint_IsReadWriteAllowed()) {
-        Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
-        Endpoint_ClearIN();
-    }
+    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)
 {
+    uint8_t timeout = 255;
+
+    if (USB_DeviceState != DEVICE_STATE_Configured)
+        return;
+
     report_extra_t r = {
         .report_id = REPORT_ID_CONSUMER,
         .usage = data
     };
-    Endpoint_SelectEndpoint(EXTRA_IN_EPNUM);
-    if (Endpoint_IsReadWriteAllowed()) {
-        Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
-        Endpoint_ClearIN();
-    }
+    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
  ******************************************************************************/
-#define SEND_TIMEOUT 10
+#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;
+    }
+
+    if (timeouted && !Endpoint_IsReadWriteAllowed()) {
+        Endpoint_SelectEndpoint(ep);
+        return - 1;
+    }
+
+    timeouted = false;
 
     uint8_t timeout = SEND_TIMEOUT;
     uint16_t prevFN = USB_Device_GetFrameNumber();
@@ -411,11 +495,16 @@ int8_t sendchar(uint8_t c)
         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();
         }
     }
@@ -426,5 +515,75 @@ int8_t sendchar(uint8_t c)
     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
+    }
+}