]> git.friedersdorff.com Git - max/tmk_keyboard.git/blobdiff - tmk_core/protocol/chibios/usb_main.c
Merge remote-tracking branch 'upstream/master' into chibios
[max/tmk_keyboard.git] / tmk_core / protocol / chibios / usb_main.c
index f5f2dad76f944fa62c57120d70a73c7f2d007c51..ee2788e5247711b04242ff31e865081f8f53bd7c 100644 (file)
@@ -22,6 +22,7 @@
 
 #include "host.h"
 #include "debug.h"
+#include "suspend.h"
 #ifdef SLEEP_LED_ENABLE
 #include "sleep_led.h"
 #include "led.h"
@@ -43,6 +44,12 @@ extern bool keyboard_nkro;
 #endif /* NKRO_ENABLE */
 
 report_keyboard_t keyboard_report_sent = {{0}};
+#ifdef MOUSE_ENABLE
+report_mouse_t mouse_report_blank = {0};
+#endif /* MOUSE_ENABLE */
+#ifdef EXTRAKEY_ENABLE
+uint8_t extra_report_blank[3] = {0};
+#endif /* EXTRAKEY_ENABLE */
 
 #ifdef CONSOLE_ENABLE
 /* The emission queue */
@@ -350,8 +357,8 @@ static const uint8_t hid_configuration_descriptor_data[] = {
                          NUM_INTERFACES,    // bNumInterfaces
                          1,    // bConfigurationValue
                          0,    // iConfiguration
-                         0xA0, // bmAttributes
-                         50),  // bMaxPower (100mA)
+                         0xA0, // bmAttributes (RESERVED|REMOTEWAKEUP)
+                         50),  // bMaxPower (50mA)
 
   /* Interface Descriptor (9 bytes) USB spec 9.6.5, page 267-269, Table 9-12 */
   USB_DESC_INTERFACE(KBD_INTERFACE,        // bInterfaceNumber
@@ -787,7 +794,6 @@ static void usb_event_cb(USBDriver *usbp, usbevent_t event) {
 
   case USB_EVENT_SUSPEND:
     //TODO: from ISR! print("[S]");
-    //TODO: signal suspend?
 #ifdef SLEEP_LED_ENABLE
     sleep_led_enable();
 #endif /* SLEEP_LED_ENABLE */
@@ -795,7 +801,7 @@ static void usb_event_cb(USBDriver *usbp, usbevent_t event) {
 
   case USB_EVENT_WAKEUP:
     //TODO: from ISR! print("[W]");
-    //TODO: suspend_wakeup_init();
+    suspend_wakeup_init();
 #ifdef SLEEP_LED_ENABLE
     sleep_led_disable();
     // NOTE: converters may not accept this
@@ -858,6 +864,43 @@ static bool usb_request_hook_cb(USBDriver *usbp) {
           return TRUE;
           break;
 
+#ifdef MOUSE_ENABLE
+        case MOUSE_INTERFACE:
+          usbSetupTransfer(usbp, (uint8_t *)&mouse_report_blank, sizeof(mouse_report_blank), NULL);
+          return TRUE;
+          break;
+#endif /* MOUSE_ENABLE */
+
+#ifdef CONSOLE_ENABLE
+        case CONSOLE_INTERFACE:
+          usbSetupTransfer(usbp, console_queue_buffer, CONSOLE_EPSIZE, NULL);
+          return TRUE;
+          break;
+#endif /* CONSOLE_ENABLE */
+
+#ifdef EXTRAKEY_ENABLE
+        case EXTRA_INTERFACE:
+          if(usbp->setup[3] == 1) { /* MSB(wValue) [Report Type] == 1 [Input Report] */
+            switch(usbp->setup[2]) { /* LSB(wValue) [Report ID] */
+              case REPORT_ID_SYSTEM:
+                extra_report_blank[0] = REPORT_ID_SYSTEM;
+                usbSetupTransfer(usbp, (uint8_t *)extra_report_blank, sizeof(extra_report_blank), NULL);
+                return TRUE;
+                break;
+              case REPORT_ID_CONSUMER:
+                extra_report_blank[0] = REPORT_ID_CONSUMER;
+                usbSetupTransfer(usbp, (uint8_t *)extra_report_blank, sizeof(extra_report_blank), NULL);
+                return TRUE;
+                break;
+              default:
+                return FALSE;
+            }
+          } else {
+            return FALSE;
+          }
+          break;
+#endif /* EXTRAKEY_ENABLE */
+
         default:
           usbSetupTransfer(usbp, NULL, 0, NULL);
           return TRUE;
@@ -981,6 +1024,27 @@ void init_usb_driver(USBDriver *usbp) {
 #endif
 }
 
+/*
+ * Send remote wakeup packet
+ * Note: should not be called from ISR
+ */
+void send_remote_wakeup(USBDriver *usbp) {
+  (void)usbp;
+#if defined(K20x) || defined(KL2x)
+#if KINETIS_USB_USE_USB0
+  USB0->CTL |= USBx_CTL_RESUME;
+  chThdSleepMilliseconds(15);
+  USB0->CTL &= ~USBx_CTL_RESUME;
+#endif /* KINETIS_USB_USE_USB0 */
+#elif defined(STM32F0XX) || defined(STM32F1XX) /* K20x || KL2x */
+  STM32_USB->CNTR |= CNTR_RESUME;
+  chThdSleepMilliseconds(15);
+  STM32_USB->CNTR &= ~CNTR_RESUME;
+#else /* STM32F0XX || STM32F1XX */
+#warning Sending remote wakeup packet not implemented for your platform.
+#endif /* K20x || KL2x */
+}
+
 /* ---------------------------------------------------------
  *                  Keyboard functions
  * ---------------------------------------------------------
@@ -1057,19 +1121,26 @@ void send_keyboard(report_keyboard_t *report) {
   }
   osalSysUnlock();
 
+  bool ep_not_ready;
 #ifdef NKRO_ENABLE
   if(keyboard_nkro) {  /* NKRO protocol */
     usbPrepareTransmit(&USB_DRIVER, NKRO_ENDPOINT, (uint8_t *)report, sizeof(report_keyboard_t));
-    osalSysLock();
-    usbStartTransmitI(&USB_DRIVER, NKRO_ENDPOINT);
-    osalSysUnlock();
+    /* need to wait until the previous packet has made it through */
+    do {
+        osalSysLock();
+        ep_not_ready = usbStartTransmitI(&USB_DRIVER, NKRO_ENDPOINT);
+        osalSysUnlock();
+    } while (ep_not_ready);
   } else
 #endif /* NKRO_ENABLE */
   { /* boot protocol */
-    usbPrepareTransmit(&USB_DRIVER, KBD_ENDPOINT, (uint8_t *)report, sizeof(report_keyboard_t));
-    osalSysLock();
-    usbStartTransmitI(&USB_DRIVER, KBD_ENDPOINT);
-    osalSysUnlock();
+    usbPrepareTransmit(&USB_DRIVER, KBD_ENDPOINT, (uint8_t *)report, KBD_EPSIZE);
+    /* need to wait until the previous packet has made it through */
+    do {
+        osalSysLock();
+        ep_not_ready = usbStartTransmitI(&USB_DRIVER, KBD_ENDPOINT);
+        osalSysUnlock();
+    } while (ep_not_ready);
   }
   keyboard_report_sent = *report;
 }
@@ -1252,10 +1323,13 @@ int8_t sendchar(uint8_t c) {
     return 0;
   }
   osalSysUnlock();
-  /* should get suspended and wait if the queue is full
-   * but it's not blocking even if noone is listening,
-   *  because the USB packets are sent anyway */
-  return(chOQPut(&console_queue, c));
+  /* Timeout after 5us if the queue is full.
+   * Increase this timeout if too much stuff is getting
+   * dropped (i.e. the buffer is getting full too fast
+   * for USB/HIDRAW to dequeue). Another possibility
+   * for fixing this kind of thing is to increase
+   * CONSOLE_QUEUE_CAPACITY. */
+  return(chOQPutTimeout(&console_queue, c, US2ST(5)));
 }
 
 #else /* CONSOLE_ENABLE */