]> git.donarmstrong.com Git - qmk_firmware.git/commitdiff
Use a single endpoint for HID reports (#3951)
authorJames Laird-Wah <james@laird-wah.net>
Fri, 16 Nov 2018 06:22:05 +0000 (17:22 +1100)
committerDrashna Jaelre <drashna@live.com>
Fri, 16 Nov 2018 06:22:05 +0000 (22:22 -0800)
* Unify multiple HID interfaces into one

This reduces the number of USB endpoints required, which frees them up
for other things.

NKRO and EXTRAKEY always use the shared endpoint.

By default, MOUSEKEY also uses it. This means it won't work as a Boot
Procotol mouse in some BIOSes, etc. If you really think your
keyboard needs to work as a mouse in your BIOS, set
MOUSE_SHARED_EP = no in your rules.mk.

By default, the core keyboard does not use the shared endpoint, as not
all BIOSes are standards compliant and that's one place you don't want
to find out your keyboard doesn't work.. If you are really confident,
you can set KEYBOARD_SHARED_EP = yes to use the shared endpoint here
too.

* unify endpoints: ChibiOS protocol implementation

* fixup: missing #ifdef EXTRAKEY_ENABLEs

broke build on AVR with EXTRAKEY disabled

* endpoints: restore error when too many endpoints required

* lufa: wait up to 10ms to send keyboard input

This avoids packets being dropped when two reports are sent in quick
succession (eg. releasing a dual role key).

* endpoints: fix compile on ARM_ATSAM

* endpoint: ARM_ATSAM fixes

No longer use wrong or unexpected endpoint IDs

* endpoints: accommodate VUSB protocol

V-USB has its own, understandably simple ideas about the report formats.
It already blasts the mouse and extrakeys through one endpoint with
report IDs. We just stay out of its way.

* endpoints: document new endpoint configuration options

* endpoints: respect keyboard_report->mods in NKRO

The caller(s) of host_keyboard_send expect to be able to just drop
modifiers in the mods field and not worry about whether NKRO is in use.
This is a good thing. So we just shift it over if needs be.

* endpoints: report.c: update for new keyboard_report format

docs/config_options.md
tmk_core/common.mk
tmk_core/common/host.c
tmk_core/common/report.c
tmk_core/common/report.h
tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.c
tmk_core/protocol/chibios/usb_main.c
tmk_core/protocol/chibios/usb_main.h
tmk_core/protocol/lufa/lufa.c
tmk_core/protocol/usb_descriptor.c
tmk_core/protocol/usb_descriptor.h

index c4921c21d7621501f0f36bfd827bc695175250e5..b811fa877dc0582d0a9da1c3b725483a2a5bcc42 100644 (file)
@@ -261,3 +261,32 @@ Use these to enable or disable building certain features. The more you have enab
   * Forces the keyboard to wait for a USB connection to be established before it starts up
 * `NO_USB_STARTUP_CHECK`
   * Disables usb suspend check after keyboard startup. Usually the keyboard waits for the host to wake it up before any tasks are performed. This is useful for split keyboards as one half will not get a wakeup call but must send commands to the master.
+
+## USB Endpoint Limitations
+
+In order to provide services over USB, QMK has to use USB endpoints.
+These are a finite resource: each microcontroller has only a certain number.
+This limits what features can be enabled together.
+If the available endpoints are exceeded, a build error is thrown.
+
+The following features can require separate endpoints:
+
+* `MOUSEKEY_ENABLE`
+* `EXTRAKEY_ENABLE`
+* `CONSOLE_ENABLE`
+* `NKRO_ENABLE`
+* `MIDI_ENABLE`
+* `RAW_ENABLE`
+* `VIRTSER_ENABLE`
+
+In order to improve utilisation of the endpoints, the HID features can be combined to use a single endpoint.
+By default, `MOUSEKEY`, `EXTRAKEY`, and `NKRO` are combined into a single endpoint.
+
+The base keyboard functionality can also be combined into the endpoint,
+by setting `KEYBOARD_SHARED_EP = yes`.
+This frees up one more endpoint,
+but it can prevent the keyboard working in some BIOSes,
+as they do not implement Boot Keyboard protocol switching.
+
+Combining the mouse also breaks Boot Mouse compatibility.
+The mouse can be uncombined by setting `MOUSE_SHARED_EP = no` if this functionality is required.
index 8eac1734f413247b09175e14e6888b08f3f1cfef..063115acb1ab803bcb4deabc228eeb0124a13839 100644 (file)
@@ -82,15 +82,31 @@ else
     TMK_COMMON_SRC += $(COMMON_DIR)/magic.c
 endif
 
+SHARED_EP_ENABLE = no
+MOUSE_SHARED_EP ?= yes
+ifeq ($(strip $(KEYBOARD_SHARED_EP)), yes)
+    TMK_COMMON_DEFS += -DKEYBOARD_SHARED_EP
+    SHARED_EP_ENABLE = yes
+    # With the current usb_descriptor.c code,
+    # you can't share kbd without sharing mouse;
+    # that would be a very unexpected use case anyway
+    MOUSE_SHARED_EP = yes
+endif
 
 ifeq ($(strip $(MOUSEKEY_ENABLE)), yes)
     TMK_COMMON_SRC += $(COMMON_DIR)/mousekey.c
     TMK_COMMON_DEFS += -DMOUSEKEY_ENABLE
     TMK_COMMON_DEFS += -DMOUSE_ENABLE
+
+    ifeq ($(strip $(MOUSE_SHARED_EP)), yes)
+        TMK_COMMON_DEFS += -DMOUSE_SHARED_EP
+        SHARED_EP_ENABLE = yes
+    endif
 endif
 
 ifeq ($(strip $(EXTRAKEY_ENABLE)), yes)
     TMK_COMMON_DEFS += -DEXTRAKEY_ENABLE
+    SHARED_EP_ENABLE = yes
 endif
 
 ifeq ($(strip $(RAW_ENABLE)), yes)
@@ -111,6 +127,7 @@ endif
 
 ifeq ($(strip $(NKRO_ENABLE)), yes)
     TMK_COMMON_DEFS += -DNKRO_ENABLE
+    SHARED_EP_ENABLE = yes
 endif
 
 ifeq ($(strip $(USB_6KRO_ENABLE)), yes)
@@ -182,6 +199,10 @@ ifeq ($(strip $(KEYMAP_SECTION_ENABLE)), yes)
     endif
 endif
 
+ifeq ($(strip $(SHARED_EP_ENABLE)), yes)
+    TMK_COMMON_DEFS += -DSHARED_EP_ENABLE
+endif
+
 # Bootloader address
 ifdef STM32_BOOTLOADER_ADDRESS
     TMK_COMMON_DEFS += -DSTM32_BOOTLOADER_ADDRESS=$(STM32_BOOTLOADER_ADDRESS)
index e12b6221656f53173e13e3a4f2a14465b863470b..f5d0416996b10b23959f8dcc862011a95d6ec31c 100644 (file)
@@ -22,6 +22,11 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #include "util.h"
 #include "debug.h"
 
+#ifdef NKRO_ENABLE
+  #include "keycode_config.h"
+  extern keymap_config_t keymap_config;
+#endif
+
 static host_driver_t *driver;
 static uint16_t last_system_report = 0;
 static uint16_t last_consumer_report = 0;
@@ -46,6 +51,20 @@ uint8_t host_keyboard_leds(void)
 void host_keyboard_send(report_keyboard_t *report)
 {
     if (!driver) return;
+#if defined(NKRO_ENABLE) && defined(NKRO_SHARED_EP)
+    if (keyboard_protocol && keymap_config.nkro) {
+        /* The callers of this function assume that report->mods is where mods go in.
+         * But report->nkro.mods can be at a different offset if core keyboard does not have a report ID.
+         */
+        report->nkro.mods = report->mods;
+        report->nkro.report_id = REPORT_ID_NKRO;
+    } else
+#endif
+    {
+#ifdef KEYBOARD_SHARED_EP
+        report->report_id = REPORT_ID_KEYBOARD;
+#endif
+    }
     (*driver->send_keyboard)(report);
 
     if (debug_keyboard) {
@@ -60,6 +79,9 @@ void host_keyboard_send(report_keyboard_t *report)
 void host_mouse_send(report_mouse_t *report)
 {
     if (!driver) return;
+#ifdef MOUSE_SHARED_EP
+    report->report_id = REPORT_ID_MOUSE;
+#endif
     (*driver->send_mouse)(report);
 }
 
index eb3b44312ffd55a0ad225f20401017ef9ca93c1a..6a06b70c60afc8fd89b64cea48dbf1c3a73bcf0c 100644 (file)
@@ -19,6 +19,7 @@
 #include "keycode_config.h"
 #include "debug.h"
 #include "util.h"
+#include <string.h>
 
 /** \brief has_anykey
  *
 uint8_t has_anykey(report_keyboard_t* keyboard_report)
 {
     uint8_t cnt = 0;
-    for (uint8_t i = 1; i < KEYBOARD_REPORT_SIZE; i++) {
-        if (keyboard_report->raw[i])
+    uint8_t *p = keyboard_report->keys;
+    uint8_t lp = sizeof(keyboard_report->keys);
+#ifdef NKRO_ENABLE
+    if (keyboard_protocol && keymap_config.nkro) {
+        p = keyboard_report->nkro.bits;
+        lp = sizeof(keyboard_report->nkro.bits);
+    }
+#endif
+    while (lp--) {
+        if (*p++)
             cnt++;
     }
     return cnt;
@@ -237,7 +246,11 @@ void del_key_from_report(report_keyboard_t* keyboard_report, uint8_t key)
 void clear_keys_from_report(report_keyboard_t* keyboard_report)
 {
     // not clear mods
-    for (int8_t i = 1; i < KEYBOARD_REPORT_SIZE; i++) {
-        keyboard_report->raw[i] = 0;
+#ifdef NKRO_ENABLE
+    if (keyboard_protocol && keymap_config.nkro) {
+        memset(keyboard_report->nkro.bits, 0, sizeof(keyboard_report->nkro.bits));
+        return;
     }
+#endif
+    memset(keyboard_report->keys, 0, sizeof(keyboard_report->keys));
 }
index 167f382751e9dadf5724bbc0293dc3b67f783fff..5a1a6b19c7b4e412cba13ecc176a5592b02a9830 100644 (file)
@@ -23,9 +23,11 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 
 /* report id */
-#define REPORT_ID_MOUSE     1
-#define REPORT_ID_SYSTEM    2
-#define REPORT_ID_CONSUMER  3
+#define REPORT_ID_KEYBOARD  1
+#define REPORT_ID_MOUSE     2
+#define REPORT_ID_SYSTEM    3
+#define REPORT_ID_CONSUMER  4
+#define REPORT_ID_NKRO      5
 
 /* mouse buttons */
 #define MOUSE_BTN1 (1<<0)
@@ -72,32 +74,35 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #define SYSTEM_WAKE_UP          0x0083
 
 
+#define NKRO_SHARED_EP
 /* key report size(NKRO or boot mode) */
 #if defined(NKRO_ENABLE)
-  #if defined(PROTOCOL_PJRC)
-    #include "usb.h"
-    #define KEYBOARD_REPORT_SIZE KBD2_SIZE
-    #define KEYBOARD_REPORT_KEYS (KBD2_SIZE - 2)
-    #define KEYBOARD_REPORT_BITS (KBD2_SIZE - 1)
-  #elif defined(PROTOCOL_LUFA) || defined(PROTOCOL_CHIBIOS)
+  #if defined(PROTOCOL_LUFA) || defined(PROTOCOL_CHIBIOS)
     #include "protocol/usb_descriptor.h"
-    #define KEYBOARD_REPORT_SIZE NKRO_EPSIZE
-    #define KEYBOARD_REPORT_KEYS (NKRO_EPSIZE - 2)
-    #define KEYBOARD_REPORT_BITS (NKRO_EPSIZE - 1)
+    #define KEYBOARD_REPORT_BITS (SHARED_EPSIZE - 2)
   #elif defined(PROTOCOL_ARM_ATSAM)
     #include "protocol/arm_atsam/usb/udi_device_epsize.h"
-    #define KEYBOARD_REPORT_SIZE NKRO_EPSIZE
-    #define KEYBOARD_REPORT_KEYS (NKRO_EPSIZE - 2)
     #define KEYBOARD_REPORT_BITS (NKRO_EPSIZE - 1)
+    #undef NKRO_SHARED_EP
+    #undef MOUSE_SHARED_EP
   #else
     #error "NKRO not supported with this protocol"
+  #endif
 #endif
 
+#ifdef KEYBOARD_SHARED_EP
+#   define KEYBOARD_REPORT_SIZE 9
 #else
 #   define KEYBOARD_REPORT_SIZE 8
-#   define KEYBOARD_REPORT_KEYS 6
 #endif
 
+#define KEYBOARD_REPORT_KEYS 6
+
+/* VUSB hardcodes keyboard and mouse+extrakey only */
+#if defined(PROTOCOL_VUSB)
+  #undef KEYBOARD_SHARED_EP
+  #undef MOUSE_SHARED_EP
+#endif
 
 #ifdef __cplusplus
 extern "C" {
@@ -126,12 +131,18 @@ extern "C" {
 typedef union {
     uint8_t raw[KEYBOARD_REPORT_SIZE];
     struct {
+#ifdef KEYBOARD_SHARED_EP
+        uint8_t report_id;
+#endif
         uint8_t mods;
         uint8_t reserved;
         uint8_t keys[KEYBOARD_REPORT_KEYS];
     };
 #ifdef NKRO_ENABLE
-    struct {
+    struct nkro_report {
+#ifdef NKRO_SHARED_EP
+        uint8_t report_id;
+#endif
         uint8_t mods;
         uint8_t bits[KEYBOARD_REPORT_BITS];
     } nkro;
@@ -139,6 +150,9 @@ typedef union {
 } __attribute__ ((packed)) report_keyboard_t;
 
 typedef struct {
+#ifdef MOUSE_SHARED_EP
+    uint8_t report_id;
+#endif
     uint8_t buttons;
     int8_t x;
     int8_t y;
index 18f9784ae68f23c2f0ab1a685583ca98f501b3c6..c263ac4aa1d9da18306d535d3a7a8d24a42edd7b 100644 (file)
@@ -54,6 +54,7 @@
 #include "udi_hid.h"
 #include "udi_hid_kbd.h"
 #include <string.h>
+#include "report.h"
 
 //***************************************************************************
 // KBD
@@ -430,7 +431,7 @@ UDC_DESC_STORAGE udi_hid_exk_report_desc_t udi_hid_exk_report_desc = {
         0x05, 0x01,         // Usage Page (Generic Desktop),
         0x09, 0x80,         // Usage (System Control),
         0xA1, 0x01,         // Collection (Application),
-        0x85, 0x02,         //   Report ID (2) (System),
+        0x85, REPORT_ID_SYSTEM,         //   Report ID (2) (System),
         0x16, 0x01, 0x00,   //   Logical Minimum (1),
         0x26, 0x03, 0x00,   //   Logical Maximum (3),
         0x1A, 0x81, 0x00,   //   Usage Minimum (81) (System Power Down),
@@ -445,7 +446,7 @@ UDC_DESC_STORAGE udi_hid_exk_report_desc_t udi_hid_exk_report_desc = {
         0x05, 0x0C,         // Usage Page (Consumer),
         0x09, 0x01,         // Usage (Consumer Control),
         0xA1, 0x01,         // Collection (Application),
-        0x85, 0x03,         //   Report ID (3) (Consumer),
+        0x85, REPORT_ID_CONSUMER,         //   Report ID (3) (Consumer),
         0x16, 0x01, 0x00,   //   Logical Minimum (1),
         0x26, 0x9C, 0x02,   //   Logical Maximum (668),
         0x1A, 0x01, 0x00,   //   Usage Minimum (1),
index 71892c4f496f9c0e12f5d059e3ca184cdc2711d2..3028e7ea2adf0e2fd7b153746f09ae00cefd9ee1 100644 (file)
@@ -95,6 +95,7 @@ static const USBDescriptor *usb_get_descriptor_cb(USBDriver *usbp, uint8_t dtype
     return &desc;
 }
 
+#ifndef KEYBOARD_SHARED_EP
 /* keyboard endpoint state structure */
 static USBInEndpointState kbd_ep_state;
 /* keyboard endpoint initialization structure (IN) */
@@ -110,8 +111,9 @@ static const USBEndpointConfig kbd_ep_config = {
   2,                            /* IN multiplier */
   NULL                          /* SETUP buffer (not a SETUP endpoint) */
 };
+#endif
 
-#ifdef MOUSE_ENABLE
+#if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP)
 /* mouse endpoint state structure */
 static USBInEndpointState mouse_ep_state;
 
@@ -128,45 +130,26 @@ static const USBEndpointConfig mouse_ep_config = {
   2,                            /* IN multiplier */
   NULL                          /* SETUP buffer (not a SETUP endpoint) */
 };
-#endif /* MOUSE_ENABLE */
-
-#ifdef EXTRAKEY_ENABLE
-/* extrakey endpoint state structure */
-static USBInEndpointState extra_ep_state;
-
-/* extrakey endpoint initialization structure (IN) */
-static const USBEndpointConfig extra_ep_config = {
-  USB_EP_MODE_TYPE_INTR,        /* Interrupt EP */
-  NULL,                         /* SETUP packet notification callback */
-  extra_in_cb,                  /* IN notification callback */
-  NULL,                         /* OUT notification callback */
-  EXTRAKEY_EPSIZE,              /* IN maximum packet size */
-  0,                            /* OUT maximum packet size */
-  &extra_ep_state,              /* IN Endpoint state */
-  NULL,                         /* OUT endpoint state */
-  2,                            /* IN multiplier */
-  NULL                          /* SETUP buffer (not a SETUP endpoint) */
-};
-#endif /* EXTRAKEY_ENABLE */
+#endif
 
-#ifdef NKRO_ENABLE
-/* nkro endpoint state structure */
-static USBInEndpointState nkro_ep_state;
+#ifdef SHARED_EP_ENABLE
+/* shared endpoint state structure */
+static USBInEndpointState shared_ep_state;
 
-/* nkro endpoint initialization structure (IN) */
-static const USBEndpointConfig nkro_ep_config = {
+/* shared endpoint initialization structure (IN) */
+static const USBEndpointConfig shared_ep_config = {
   USB_EP_MODE_TYPE_INTR,        /* Interrupt EP */
   NULL,                         /* SETUP packet notification callback */
-  nkro_in_cb,                   /* IN notification callback */
+  shared_in_cb,                 /* IN notification callback */
   NULL,                         /* OUT notification callback */
-  NKRO_EPSIZE,                  /* IN maximum packet size */
+  SHARED_EPSIZE,                /* IN maximum packet size */
   0,                            /* OUT maximum packet size */
-  &nkro_ep_state,               /* IN Endpoint state */
+  &shared_ep_state,             /* IN Endpoint state */
   NULL,                         /* OUT endpoint state */
   2,                            /* IN multiplier */
   NULL                          /* SETUP buffer (not a SETUP endpoint) */
 };
-#endif /* NKRO_ENABLE */
+#endif
 
 typedef struct {
   size_t queue_capacity_in;
@@ -309,16 +292,15 @@ static void usb_event_cb(USBDriver *usbp, usbevent_t event) {
   case USB_EVENT_CONFIGURED:
     osalSysLockFromISR();
     /* Enable the endpoints specified into the configuration. */
+#ifndef KEYBOARD_SHARED_EP
     usbInitEndpointI(usbp, KEYBOARD_IN_EPNUM, &kbd_ep_config);
-#ifdef MOUSE_ENABLE
+#endif
+#if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP)
     usbInitEndpointI(usbp, MOUSE_IN_EPNUM, &mouse_ep_config);
-#endif /* MOUSE_ENABLE */
-#ifdef EXTRAKEY_ENABLE
-    usbInitEndpointI(usbp, EXTRAKEY_IN_EPNUM, &extra_ep_config);
-#endif /* EXTRAKEY_ENABLE */
-#ifdef NKRO_ENABLE
-    usbInitEndpointI(usbp, NKRO_IN_EPNUM, &nkro_ep_config);
-#endif /* NKRO_ENABLE */
+#endif
+#ifdef SHARED_EP_ENABLE
+    usbInitEndpointI(usbp, SHARED_IN_EPNUM, &shared_ep_config);
+#endif
     for (int i=0;i<NUM_USB_DRIVERS;i++) {
       usbInitEndpointI(usbp, drivers.array[i].config.bulk_in, &drivers.array[i].in_ep_config);
       usbInitEndpointI(usbp, drivers.array[i].config.bulk_out, &drivers.array[i].out_ep_config);
@@ -389,9 +371,20 @@ static uint16_t get_hword(uint8_t *p) {
  * Other Device    Required    Optional    Optional    Optional    Optional    Optional
  */
 
+#ifdef SHARED_EP_ENABLE
+static uint8_t set_report_buf[2] __attribute__((aligned(2)));
+static void set_led_transfer_cb(USBDriver *usbp) {
+  if ((set_report_buf[0] == REPORT_ID_KEYBOARD) ||
+      (set_report_buf[0] == REPORT_ID_NKRO)) {
+    keyboard_led_stats = set_report_buf[1];
+  }
+}
+#endif
+
 /* Callback for SETUP request on the endpoint 0 (control) */
 static bool usb_request_hook_cb(USBDriver *usbp) {
   const USBDescriptor *dp;
+  int has_report_id;
 
   /* usbp->setup fields:
    *  0:   bmRequestType (bitmask)
@@ -409,42 +402,16 @@ static bool usb_request_hook_cb(USBDriver *usbp) {
       case HID_GET_REPORT:
         switch(usbp->setup[4]) {     /* LSB(wIndex) (check MSB==0?) */
         case KEYBOARD_INTERFACE:
-#ifdef NKRO_ENABLE
-        case NKRO_INTERFACE:
-#endif /* NKRO_ENABLE */
           usbSetupTransfer(usbp, (uint8_t *)&keyboard_report_sent, sizeof(keyboard_report_sent), NULL);
           return TRUE;
           break;
 
-#ifdef MOUSE_ENABLE
+#if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP)
         case MOUSE_INTERFACE:
           usbSetupTransfer(usbp, (uint8_t *)&mouse_report_blank, sizeof(mouse_report_blank), NULL);
           return TRUE;
           break;
-#endif /* MOUSE_ENABLE */
-
-#ifdef EXTRAKEY_ENABLE
-        case EXTRAKEY_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 */
+#endif
 
         default:
           usbSetupTransfer(usbp, NULL, 0, NULL);
@@ -472,12 +439,25 @@ static bool usb_request_hook_cb(USBDriver *usbp) {
       case HID_SET_REPORT:
         switch(usbp->setup[4]) {       /* LSB(wIndex) (check MSB==0 and wLength==1?) */
         case KEYBOARD_INTERFACE:
-#ifdef NKRO_ENABLE
-        case NKRO_INTERFACE:
-#endif  /* NKRO_ENABLE */
+#if defined(SHARED_EP_ENABLE) && !defined(KEYBOARD_SHARED_EP)
+        case SHARED_INTERFACE:
+#endif
         /* keyboard_led_stats = <read byte from next OUT report>
          * keyboard_led_stats needs be word (or dword), otherwise we get an exception on F0 */
-          usbSetupTransfer(usbp, (uint8_t *)&keyboard_led_stats, 1, NULL);
+          has_report_id = 0;
+#if defined(SHARED_EP_ENABLE)
+          if (usbp->setup[4] == SHARED_INTERFACE) {
+            has_report_id = 1;
+          }
+#endif
+          if (usbp->setup[4] == KEYBOARD_INTERFACE && !keyboard_protocol) {
+            has_report_id = 0;
+          }
+          if (has_report_id) {
+            usbSetupTransfer(usbp, set_report_buf, sizeof(set_report_buf), set_led_transfer_cb);
+          } else {
+            usbSetupTransfer(usbp, (uint8_t *)&keyboard_led_stats, 1, NULL);
+          }
           return TRUE;
           break;
         }
@@ -591,20 +571,13 @@ void init_usb_driver(USBDriver *usbp) {
  * ---------------------------------------------------------
  */
 /* keyboard IN callback hander (a kbd report has made it IN) */
+#ifndef KEYBOARD_SHARED_EP
 void kbd_in_cb(USBDriver *usbp, usbep_t ep) {
   /* STUB */
   (void)usbp;
   (void)ep;
 }
-
-#ifdef NKRO_ENABLE
-/* nkro IN callback hander (a nkro report has made it IN) */
-void nkro_in_cb(USBDriver *usbp, usbep_t ep) {
-  /* STUB */
-  (void)usbp;
-  (void)ep;
-}
-#endif /* NKRO_ENABLE */
+#endif
 
 /* start-of-frame handler
  * TODO: i guess it would be better to re-implement using timers,
@@ -628,9 +601,9 @@ static void keyboard_idle_timer_cb(void *arg) {
   }
 
 #ifdef NKRO_ENABLE
-  if(!keymap_config.nkro && keyboard_idle) {
+  if(!keymap_config.nkro && keyboard_idle && keyboard_protocol) {
 #else /* NKRO_ENABLE */
-  if(keyboard_idle) {
+  if(keyboard_idle && keyboard_protocol) {
 #endif /* NKRO_ENABLE */
     /* TODO: are we sure we want the KBD_ENDPOINT? */
     if(!usbGetTransmitStatusI(usbp, KEYBOARD_IN_EPNUM)) {
@@ -661,25 +634,25 @@ void send_keyboard(report_keyboard_t *report) {
   osalSysUnlock();
 
 #ifdef NKRO_ENABLE
-  if(keymap_config.nkro) {  /* NKRO protocol */
+  if(keymap_config.nkro && keyboard_protocol) {  /* NKRO protocol */
     /* need to wait until the previous packet has made it through */
     /* can rewrite this using the synchronous API, then would wait
      * until *after* the packet has been transmitted. I think
      * this is more efficient */
     /* busy wait, should be short and not very common */
     osalSysLock();
-    if(usbGetTransmitStatusI(&USB_DRIVER, NKRO_IN_EPNUM)) {
+    if(usbGetTransmitStatusI(&USB_DRIVER, SHARED_IN_EPNUM)) {
       /* Need to either suspend, or loop and call unlock/lock during
        * every iteration - otherwise the system will remain locked,
        * no interrupts served, so USB not going through as well.
        * Note: for suspend, need USB_USE_WAIT == TRUE in halconf.h */
-      osalThreadSuspendS(&(&USB_DRIVER)->epc[NKRO_IN_EPNUM]->in_state->thread);
+      osalThreadSuspendS(&(&USB_DRIVER)->epc[SHARED_IN_EPNUM]->in_state->thread);
     }
-    usbStartTransmitI(&USB_DRIVER, NKRO_IN_EPNUM, (uint8_t *)report, sizeof(report_keyboard_t));
+    usbStartTransmitI(&USB_DRIVER, SHARED_IN_EPNUM, (uint8_t *)report, sizeof(struct nkro_report));
     osalSysUnlock();
   } else
 #endif /* NKRO_ENABLE */
-  { /* boot protocol */
+  { /* regular protocol */
     /* need to wait until the previous packet has made it through */
     /* busy wait, should be short and not very common */
     osalSysLock();
@@ -690,7 +663,15 @@ void send_keyboard(report_keyboard_t *report) {
        * Note: for suspend, need USB_USE_WAIT == TRUE in halconf.h */
       osalThreadSuspendS(&(&USB_DRIVER)->epc[KEYBOARD_IN_EPNUM]->in_state->thread);
     }
-    usbStartTransmitI(&USB_DRIVER, KEYBOARD_IN_EPNUM, (uint8_t *)report, KEYBOARD_EPSIZE);
+    uint8_t *data, size;
+    if (keyboard_protocol) {
+      data = (uint8_t*)report;
+      size = KEYBOARD_REPORT_SIZE;
+    } else {    /* boot protocol */
+      data = &report->mods;
+      size = 8;
+    }
+    usbStartTransmitI(&USB_DRIVER, KEYBOARD_IN_EPNUM, data, size);
     osalSysUnlock();
   }
   keyboard_report_sent = *report;
@@ -703,11 +684,13 @@ void send_keyboard(report_keyboard_t *report) {
 
 #ifdef MOUSE_ENABLE
 
+#ifndef MOUSE_SHARED_EP
 /* mouse IN callback hander (a mouse report has made it IN) */
 void mouse_in_cb(USBDriver *usbp, usbep_t ep) {
   (void)usbp;
   (void)ep;
 }
+#endif
 
 void send_mouse(report_mouse_t *report) {
   osalSysLock();
@@ -737,19 +720,24 @@ void send_mouse(report_mouse_t *report) {
 #endif /* MOUSE_ENABLE */
 
 /* ---------------------------------------------------------
- *                   Extrakey functions
+ *                   Shared EP functions
  * ---------------------------------------------------------
  */
-
-#ifdef EXTRAKEY_ENABLE
-
-/* extrakey IN callback hander */
-void extra_in_cb(USBDriver *usbp, usbep_t ep) {
+#ifdef SHARED_EP_ENABLE
+/* shared IN callback hander */
+void shared_in_cb(USBDriver *usbp, usbep_t ep) {
   /* STUB */
   (void)usbp;
   (void)ep;
 }
+#endif
+
+/* ---------------------------------------------------------
+ *                   Extrakey functions
+ * ---------------------------------------------------------
+ */
 
+#ifdef EXTRAKEY_ENABLE
 static void send_extra_report(uint8_t report_id, uint16_t data) {
   osalSysLock();
   if(usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) {
@@ -762,7 +750,7 @@ static void send_extra_report(uint8_t report_id, uint16_t data) {
     .usage = data
   };
 
-  usbStartTransmitI(&USB_DRIVER, EXTRAKEY_IN_EPNUM, (uint8_t *)&report, sizeof(report_extra_t));
+  usbStartTransmitI(&USB_DRIVER, SHARED_IN_EPNUM, (uint8_t *)&report, sizeof(report_extra_t));
   osalSysUnlock();
 }
 
index 1f7eb12f8db5c5e0e2a7c84d29eea8c0e351479f..55e8882cc4bf46ce7709ff69effcf585197928ef 100644 (file)
@@ -65,6 +65,14 @@ void nkro_in_cb(USBDriver *usbp, usbep_t ep);
 void mouse_in_cb(USBDriver *usbp, usbep_t ep);
 #endif /* MOUSE_ENABLE */
 
+/* ---------------
+ * Shared EP header
+ * ---------------
+ */
+
+/* shared IN request callback handler */
+void shared_in_cb(USBDriver *usbp, usbep_t ep);
+
 /* ---------------
  * Extrakey header
  * ---------------
@@ -72,9 +80,6 @@ void mouse_in_cb(USBDriver *usbp, usbep_t ep);
 
 #ifdef EXTRAKEY_ENABLE
 
-/* extrakey IN request callback handler */
-void extra_in_cb(USBDriver *usbp, usbep_t ep);
-
 /* extra report structure */
 typedef struct {
   uint8_t report_id;
index 95e0b95b2fa9c1dfc23804d8b525a6c985589f1c..e88e6f34aac4d21fcdaca9fc565a0b0f8d70feb8 100644 (file)
@@ -409,19 +409,21 @@ void EVENT_USB_Device_ConfigurationChanged(void)
     bool ConfigSuccess = true;
 
     /* Setup Keyboard HID Report Endpoints */
+#ifndef KEYBOARD_SHARED_EP
     ConfigSuccess &= ENDPOINT_CONFIG(KEYBOARD_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
                                      KEYBOARD_EPSIZE, ENDPOINT_BANK_SINGLE);
+#endif
 
-#ifdef MOUSE_ENABLE
+#if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP)
     /* Setup Mouse HID Report Endpoint */
     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_CONFIG(EXTRAKEY_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
-                                     EXTRAKEY_EPSIZE, ENDPOINT_BANK_SINGLE);
+#ifdef SHARED_EP_ENABLE
+    /* Setup Shared HID Report Endpoint */
+    ConfigSuccess &= ENDPOINT_CONFIG(SHARED_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
+                                     SHARED_EPSIZE, ENDPOINT_BANK_SINGLE);
 #endif
 
 #ifdef RAW_ENABLE
@@ -442,12 +444,6 @@ void EVENT_USB_Device_ConfigurationChanged(void)
 #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
-
 #ifdef MIDI_ENABLE
     ConfigSuccess &= Endpoint_ConfigureEndpoint(MIDI_STREAM_IN_EPADDR, EP_TYPE_BULK, MIDI_STREAM_EPSIZE, ENDPOINT_BANK_SINGLE);
     ConfigSuccess &= Endpoint_ConfigureEndpoint(MIDI_STREAM_OUT_EPADDR, EP_TYPE_BULK, MIDI_STREAM_EPSIZE, ENDPOINT_BANK_SINGLE);
@@ -512,8 +508,8 @@ void EVENT_USB_Device_ControlRequest(void)
                 // Interface
                 switch (USB_ControlRequest.wIndex) {
                 case KEYBOARD_INTERFACE:
-#ifdef NKRO_ENABLE
-                case NKRO_INTERFACE:
+#if defined(SHARED_EP_ENABLE) && !defined(KEYBOARD_SHARED_EP)
+                case SHARED_INTERFACE:
 #endif
                     Endpoint_ClearSETUP();
 
@@ -521,7 +517,17 @@ void EVENT_USB_Device_ControlRequest(void)
                         if (USB_DeviceState == DEVICE_STATE_Unattached)
                           return;
                     }
+#if defined(SHARED_EP_ENABLE)
+                    uint8_t report_id = REPORT_ID_KEYBOARD;
+                    if (keyboard_protocol) {
+                       report_id = Endpoint_Read_8();
+                    }
+                    if (report_id == REPORT_ID_KEYBOARD || report_id == REPORT_ID_NKRO) {
+                        keyboard_led_stats = Endpoint_Read_8();
+                    }
+#else
                     keyboard_led_stats = Endpoint_Read_8();
+#endif
 
                     Endpoint_ClearOUT();
                     Endpoint_ClearStatusStage();
@@ -612,16 +618,20 @@ static void send_keyboard(report_keyboard_t *report)
     #ifdef MODULE_ADAFRUIT_BLE
       adafruit_ble_send_keys(report->mods, report->keys, sizeof(report->keys));
     #elif MODULE_RN42
-       bluefruit_serial_send(0xFD);
-       bluefruit_serial_send(0x09);
-       bluefruit_serial_send(0x01);
-       for (uint8_t i = 0; i < KEYBOARD_EPSIZE; i++) {
-         bluefruit_serial_send(report->raw[i]);
-       }
+      bluefruit_serial_send(0xFD);
+      bluefruit_serial_send(0x09);
+      bluefruit_serial_send(0x01);
+      bluefruit_serial_send(report->mods);
+      bluefruit_serial_send(report->reserved);
+      for (uint8_t i = 0; i < KEYBOARD_REPORT_KEYS; i++) {
+        bluefruit_serial_send(report->keys[i]);
+      }
     #else
       bluefruit_serial_send(0xFD);
-      for (uint8_t i = 0; i < KEYBOARD_EPSIZE; i++) {
-        bluefruit_serial_send(report->raw[i]);
+      bluefruit_serial_send(report->mods);
+      bluefruit_serial_send(report->reserved);
+      for (uint8_t i = 0; i < KEYBOARD_REPORT_KEYS; i++) {
+        bluefruit_serial_send(report->keys[i]);
       }
     #endif
   }
@@ -632,30 +642,24 @@ static void send_keyboard(report_keyboard_t *report)
     }
 
     /* Select the Keyboard Report Endpoint */
+    uint8_t ep = KEYBOARD_IN_EPNUM;
+    uint8_t size = KEYBOARD_REPORT_SIZE;
 #ifdef NKRO_ENABLE
     if (keyboard_protocol && keymap_config.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;
-
-        /* Write Keyboard Report Data */
-        Endpoint_Write_Stream_LE(report, NKRO_EPSIZE, NULL);
+        ep = SHARED_IN_EPNUM;
+        size = sizeof(struct nkro_report);
     }
-    else
 #endif
-    {
-        /* Boot protocol */
-        Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM);
-
-        /* Check if write ready for a polling interval around 10ms */
-        while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
-        if (!Endpoint_IsReadWriteAllowed()) return;
+    Endpoint_SelectEndpoint(ep);
+    /* 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);
+    /* If we're in Boot Protocol, don't send any report ID or other funky fields */
+    if (!keyboard_protocol) {
+        Endpoint_Write_Stream_LE(&report->mods, 8, NULL);
+    } else {
+        Endpoint_Write_Stream_LE(report, size, NULL);
     }
 
     /* Finalize the stream transfer to send the last packet */
@@ -718,6 +722,7 @@ static void send_mouse(report_mouse_t *report)
  */
 static void send_system(uint16_t data)
 {
+#ifdef EXTRAKEY_ENABLE
     uint8_t timeout = 255;
 
     if (USB_DeviceState != DEVICE_STATE_Configured)
@@ -727,7 +732,7 @@ static void send_system(uint16_t data)
         .report_id = REPORT_ID_SYSTEM,
         .usage = data - SYSTEM_POWER_DOWN + 1
     };
-    Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
+    Endpoint_SelectEndpoint(SHARED_IN_EPNUM);
 
     /* Check if write ready for a polling interval around 10ms */
     while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
@@ -735,6 +740,7 @@ static void send_system(uint16_t data)
 
     Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
     Endpoint_ClearIN();
+#endif
 }
 
 /** \brief Send Consumer
@@ -743,6 +749,7 @@ static void send_system(uint16_t data)
  */
 static void send_consumer(uint16_t data)
 {
+#ifdef EXTRAKEY_ENABLE
     uint8_t timeout = 255;
     uint8_t where = where_to_send();
 
@@ -786,7 +793,7 @@ static void send_consumer(uint16_t data)
         .report_id = REPORT_ID_CONSUMER,
         .usage = data
     };
-    Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
+    Endpoint_SelectEndpoint(SHARED_IN_EPNUM);
 
     /* Check if write ready for a polling interval around 10ms */
     while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
@@ -794,6 +801,7 @@ static void send_consumer(uint16_t data)
 
     Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
     Endpoint_ClearIN();
+#endif
 }
 
 
index cab344675245de8d1954409155ca975f60c02d6b..589ad23cdd51a1c30606aa903e9c82dd563de9c4 100644 (file)
 /*******************************************************************************
  * HID Report Descriptors
  ******************************************************************************/
-const USB_Descriptor_HIDReport_Datatype_t PROGMEM KeyboardReport[] =
-{
+#ifdef KEYBOARD_SHARED_EP
+const USB_Descriptor_HIDReport_Datatype_t PROGMEM SharedReport[] = {
+#define SHARED_REPORT_STARTED
+#else
+const USB_Descriptor_HIDReport_Datatype_t PROGMEM KeyboardReport[] = {
+#endif
     HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */
     HID_RI_USAGE(8, 0x06), /* Keyboard */
     HID_RI_COLLECTION(8, 0x01), /* Application */
+#   ifdef KEYBOARD_SHARED_EP
+        HID_RI_REPORT_ID(8, REPORT_ID_KEYBOARD),
+#   endif
         HID_RI_USAGE_PAGE(8, 0x07), /* Key Codes */
         HID_RI_USAGE_MINIMUM(8, 0xE0), /* Keyboard Left Control */
         HID_RI_USAGE_MAXIMUM(8, 0xE7), /* Keyboard Right GUI */
@@ -84,14 +91,25 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM KeyboardReport[] =
         HID_RI_REPORT_SIZE(8, 0x08),
         HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_ARRAY | HID_IOF_ABSOLUTE),
     HID_RI_END_COLLECTION(0),
+
+#ifndef KEYBOARD_SHARED_EP
 };
+#endif
 
-#ifdef MOUSE_ENABLE
-const USB_Descriptor_HIDReport_Datatype_t PROGMEM MouseReport[] =
-{
+#if defined(MOUSE_ENABLE)
+
+#   if !defined(MOUSE_SHARED_EP)
+const USB_Descriptor_HIDReport_Datatype_t PROGMEM MouseReport[] = {
+#   elif !defined(SHARED_REPORT_STARTED)
+const USB_Descriptor_HIDReport_Datatype_t PROGMEM SharedReport[] = {
+#define SHARED_REPORT_STARTED
+#   endif
     HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */
     HID_RI_USAGE(8, 0x02), /* Mouse */
     HID_RI_COLLECTION(8, 0x01), /* Application */
+#   ifdef MOUSE_SHARED_EP
+        HID_RI_REPORT_ID(8, REPORT_ID_MOUSE),
+#   endif
         HID_RI_USAGE(8, 0x01), /* Pointer */
         HID_RI_COLLECTION(8, 0x00), /* Physical */
 
@@ -133,12 +151,15 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM MouseReport[] =
 
         HID_RI_END_COLLECTION(0),
     HID_RI_END_COLLECTION(0),
+#   ifndef MOUSE_SHARED_EP
 };
+#   endif
 #endif
 
-#ifdef EXTRAKEY_ENABLE
-const USB_Descriptor_HIDReport_Datatype_t PROGMEM ExtrakeyReport[] =
-{
+#if defined(SHARED_EP_ENABLE) && !defined(SHARED_REPORT_STARTED)
+const USB_Descriptor_HIDReport_Datatype_t PROGMEM SharedReport[] = {
+#endif
+#   ifdef EXTRAKEY_ENABLE
     HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */
     HID_RI_USAGE(8, 0x80), /* System Control */
     HID_RI_COLLECTION(8, 0x01), /* Application */
@@ -164,6 +185,43 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM ExtrakeyReport[] =
         HID_RI_REPORT_COUNT(8, 1),
         HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_ARRAY | HID_IOF_ABSOLUTE),
     HID_RI_END_COLLECTION(0),
+#   endif
+
+#   ifdef NKRO_ENABLE
+    HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */
+    HID_RI_USAGE(8, 0x06), /* Keyboard */
+    HID_RI_COLLECTION(8, 0x01), /* Application */
+        HID_RI_REPORT_ID(8, REPORT_ID_NKRO),
+        HID_RI_USAGE_PAGE(8, 0x07), /* Key Codes */
+        HID_RI_USAGE_MINIMUM(8, 0xE0), /* Keyboard Left Control */
+        HID_RI_USAGE_MAXIMUM(8, 0xE7), /* Keyboard Right GUI */
+        HID_RI_LOGICAL_MINIMUM(8, 0x00),
+        HID_RI_LOGICAL_MAXIMUM(8, 0x01),
+        HID_RI_REPORT_COUNT(8, 0x08),
+        HID_RI_REPORT_SIZE(8, 0x01),
+        HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
+
+        HID_RI_USAGE_PAGE(8, 0x08), /* LEDs */
+        HID_RI_USAGE_MINIMUM(8, 0x01), /* Num Lock */
+        HID_RI_USAGE_MAXIMUM(8, 0x05), /* Kana */
+        HID_RI_REPORT_COUNT(8, 0x05),
+        HID_RI_REPORT_SIZE(8, 0x01),
+        HID_RI_OUTPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NON_VOLATILE),
+        HID_RI_REPORT_COUNT(8, 0x01),
+        HID_RI_REPORT_SIZE(8, 0x03),
+        HID_RI_OUTPUT(8, HID_IOF_CONSTANT),
+
+        HID_RI_USAGE_PAGE(8, 0x07), /* Key Codes */
+        HID_RI_USAGE_MINIMUM(8, 0x00), /* Keyboard 0 */
+        HID_RI_USAGE_MAXIMUM(8, KEYBOARD_REPORT_BITS*8-1),
+        HID_RI_LOGICAL_MINIMUM(8, 0x00),
+        HID_RI_LOGICAL_MAXIMUM(8, 0x01),
+        HID_RI_REPORT_COUNT(8, KEYBOARD_REPORT_BITS*8),
+        HID_RI_REPORT_SIZE(8, 0x01),
+        HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
+    HID_RI_END_COLLECTION(0),
+#   endif
+#ifdef SHARED_EP_ENABLE
 };
 #endif
 
@@ -211,42 +269,6 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM ConsoleReport[] =
 };
 #endif
 
-#ifdef NKRO_ENABLE
-const USB_Descriptor_HIDReport_Datatype_t PROGMEM NKROReport[] =
-{
-    HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */
-    HID_RI_USAGE(8, 0x06), /* Keyboard */
-    HID_RI_COLLECTION(8, 0x01), /* Application */
-        HID_RI_USAGE_PAGE(8, 0x07), /* Key Codes */
-        HID_RI_USAGE_MINIMUM(8, 0xE0), /* Keyboard Left Control */
-        HID_RI_USAGE_MAXIMUM(8, 0xE7), /* Keyboard Right GUI */
-        HID_RI_LOGICAL_MINIMUM(8, 0x00),
-        HID_RI_LOGICAL_MAXIMUM(8, 0x01),
-        HID_RI_REPORT_COUNT(8, 0x08),
-        HID_RI_REPORT_SIZE(8, 0x01),
-        HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
-
-        HID_RI_USAGE_PAGE(8, 0x08), /* LEDs */
-        HID_RI_USAGE_MINIMUM(8, 0x01), /* Num Lock */
-        HID_RI_USAGE_MAXIMUM(8, 0x05), /* Kana */
-        HID_RI_REPORT_COUNT(8, 0x05),
-        HID_RI_REPORT_SIZE(8, 0x01),
-        HID_RI_OUTPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NON_VOLATILE),
-        HID_RI_REPORT_COUNT(8, 0x01),
-        HID_RI_REPORT_SIZE(8, 0x03),
-        HID_RI_OUTPUT(8, HID_IOF_CONSTANT),
-
-        HID_RI_USAGE_PAGE(8, 0x07), /* Key Codes */
-        HID_RI_USAGE_MINIMUM(8, 0x00), /* Keyboard 0 */
-        HID_RI_USAGE_MAXIMUM(8, (NKRO_EPSIZE-1)*8-1), /* Keyboard Right GUI */
-        HID_RI_LOGICAL_MINIMUM(8, 0x00),
-        HID_RI_LOGICAL_MAXIMUM(8, 0x01),
-        HID_RI_REPORT_COUNT(8, (NKRO_EPSIZE-1)*8),
-        HID_RI_REPORT_SIZE(8, 0x01),
-        HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
-    HID_RI_END_COLLECTION(0),
-};
-#endif
 
 /*******************************************************************************
  * Device Descriptors
@@ -303,6 +325,7 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
     /*
      * Keyboard
      */
+#ifndef KEYBOARD_SHARED_EP
     .Keyboard_Interface =
         {
             .Header                 = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},
@@ -339,11 +362,12 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
             .EndpointSize           = KEYBOARD_EPSIZE,
             .PollingIntervalMS      = 0x0A
         },
+#endif
 
     /*
      * Mouse
      */
-#ifdef MOUSE_ENABLE
+#if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP)
     .Mouse_Interface =
         {
             .Header                 = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},
@@ -383,26 +407,31 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
 #endif
 
     /*
-     * Extra
+     * Shared
      */
-#ifdef EXTRAKEY_ENABLE
-    .Extrakey_Interface =
+#ifdef SHARED_EP_ENABLE
+    .Shared_Interface =
         {
             .Header                 = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},
 
-            .InterfaceNumber        = EXTRAKEY_INTERFACE,
+            .InterfaceNumber        = SHARED_INTERFACE,
             .AlternateSetting       = 0x00,
 
             .TotalEndpoints         = 1,
 
             .Class                  = HID_CSCP_HIDClass,
+#   ifdef KEYBOARD_SHARED_EP
+            .SubClass               = HID_CSCP_BootSubclass,
+            .Protocol               = HID_CSCP_KeyboardBootProtocol,
+#   else
             .SubClass               = HID_CSCP_NonBootSubclass,
             .Protocol               = HID_CSCP_NonBootProtocol,
+#endif
 
             .InterfaceStrIndex      = NO_DESCRIPTOR
         },
 
-    .Extrakey_HID =
+    .Shared_HID =
         {
             .Header                 = {.Size = sizeof(USB_HID_Descriptor_HID_t), .Type = HID_DTYPE_HID},
 
@@ -410,16 +439,16 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
             .CountryCode            = 0x00,
             .TotalReportDescriptors = 1,
             .HIDReportType          = HID_DTYPE_Report,
-            .HIDReportLength        = sizeof(ExtrakeyReport)
+            .HIDReportLength        = sizeof(SharedReport)
         },
 
-    .Extrakey_INEndpoint =
+    .Shared_INEndpoint =
         {
             .Header                 = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},
 
-            .EndpointAddress        = (ENDPOINT_DIR_IN | EXTRAKEY_IN_EPNUM),
+            .EndpointAddress        = (ENDPOINT_DIR_IN | SHARED_IN_EPNUM),
             .Attributes             = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
-            .EndpointSize           = EXTRAKEY_EPSIZE,
+            .EndpointSize           = SHARED_EPSIZE,
             .PollingIntervalMS      = 0x0A
         },
 #endif
@@ -528,48 +557,6 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
         },
 #endif
 
-    /*
-     * NKRO
-     */
-#ifdef NKRO_ENABLE
-    .NKRO_Interface =
-        {
-            .Header                 = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},
-
-            .InterfaceNumber        = NKRO_INTERFACE,
-            .AlternateSetting       = 0x00,
-
-            .TotalEndpoints         = 1,
-
-            .Class                  = HID_CSCP_HIDClass,
-            .SubClass               = HID_CSCP_NonBootSubclass,
-            .Protocol               = HID_CSCP_NonBootProtocol,
-
-            .InterfaceStrIndex      = NO_DESCRIPTOR
-        },
-
-    .NKRO_HID =
-        {
-            .Header                 = {.Size = sizeof(USB_HID_Descriptor_HID_t), .Type = HID_DTYPE_HID},
-
-            .HIDSpec                = VERSION_BCD(1,1,1),
-            .CountryCode            = 0x00,
-            .TotalReportDescriptors = 1,
-            .HIDReportType          = HID_DTYPE_Report,
-            .HIDReportLength        = sizeof(NKROReport)
-        },
-
-    .NKRO_INEndpoint =
-        {
-            .Header                 = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},
-
-            .EndpointAddress        = (ENDPOINT_DIR_IN | NKRO_IN_EPNUM),
-            .Attributes             = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
-            .EndpointSize           = NKRO_EPSIZE,
-            .PollingIntervalMS      = 0x01
-        },
-#endif
-
 #ifdef MIDI_ENABLE
     .Audio_Interface_Association =
         {
@@ -936,19 +923,21 @@ uint16_t get_usb_descriptor(const uint16_t wValue,
             break;
         case HID_DTYPE_HID:
             switch (wIndex) {
+#ifndef KEYBOARD_SHARED_EP
             case KEYBOARD_INTERFACE:
                 Address = &ConfigurationDescriptor.Keyboard_HID;
                 Size    = sizeof(USB_HID_Descriptor_HID_t);
                 break;
-#ifdef MOUSE_ENABLE
+#endif
+#if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP)
             case MOUSE_INTERFACE:
                 Address = &ConfigurationDescriptor.Mouse_HID;
                 Size    = sizeof(USB_HID_Descriptor_HID_t);
                 break;
 #endif
-#ifdef EXTRAKEY_ENABLE
-            case EXTRAKEY_INTERFACE:
-                Address = &ConfigurationDescriptor.Extrakey_HID;
+#ifdef SHARED_EP_ENABLE
+            case SHARED_INTERFACE:
+                Address = &ConfigurationDescriptor.Shared_HID;
                 Size    = sizeof(USB_HID_Descriptor_HID_t);
                 break;
 #endif
@@ -963,31 +952,27 @@ uint16_t get_usb_descriptor(const uint16_t wValue,
                 Address = &ConfigurationDescriptor.Console_HID;
                 Size    = sizeof(USB_HID_Descriptor_HID_t);
                 break;
-#endif
-#ifdef NKRO_ENABLE
-            case NKRO_INTERFACE:
-                Address = &ConfigurationDescriptor.NKRO_HID;
-                Size    = sizeof(USB_HID_Descriptor_HID_t);
-                break;
 #endif
             }
             break;
         case HID_DTYPE_Report:
             switch (wIndex) {
+#ifndef KEYBOARD_SHARED_EP
             case KEYBOARD_INTERFACE:
                 Address = &KeyboardReport;
                 Size    = sizeof(KeyboardReport);
                 break;
-#ifdef MOUSE_ENABLE
+#endif
+#if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP)
             case MOUSE_INTERFACE:
                 Address = &MouseReport;
                 Size    = sizeof(MouseReport);
                 break;
 #endif
-#ifdef EXTRAKEY_ENABLE
-            case EXTRAKEY_INTERFACE:
-                Address = &ExtrakeyReport;
-                Size    = sizeof(ExtrakeyReport);
+#ifdef SHARED_EP_ENABLE
+            case SHARED_INTERFACE:
+                Address = &SharedReport;
+                Size    = sizeof(SharedReport);
                 break;
 #endif
 #ifdef RAW_ENABLE
@@ -1001,12 +986,6 @@ uint16_t get_usb_descriptor(const uint16_t wValue,
                 Address = &ConsoleReport;
                 Size    = sizeof(ConsoleReport);
                 break;
-#endif
-#ifdef NKRO_ENABLE
-            case NKRO_INTERFACE:
-                Address = &NKROReport;
-                Size    = sizeof(NKROReport);
-                break;
 #endif
             }
             break;
index 586d07df627ccc555e726dafd487a45f6ef4715e..3ca0c00b34f2f0f2581e88a007f9098e7f364732 100644 (file)
@@ -53,26 +53,27 @@ typedef struct
 {
     USB_Descriptor_Configuration_Header_t Config;
 
+#ifndef KEYBOARD_SHARED_EP
     // Keyboard HID Interface
     USB_Descriptor_Interface_t            Keyboard_Interface;
     USB_HID_Descriptor_HID_t              Keyboard_HID;
     USB_Descriptor_Endpoint_t             Keyboard_INEndpoint;
+#endif
 
-#ifdef MOUSE_ENABLE
+#if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP)
     // Mouse HID Interface
     USB_Descriptor_Interface_t            Mouse_Interface;
     USB_HID_Descriptor_HID_t              Mouse_HID;
     USB_Descriptor_Endpoint_t             Mouse_INEndpoint;
 #endif
 
-#ifdef EXTRAKEY_ENABLE
-    // Extrakey HID Interface
-    USB_Descriptor_Interface_t            Extrakey_Interface;
-    USB_HID_Descriptor_HID_t              Extrakey_HID;
-    USB_Descriptor_Endpoint_t             Extrakey_INEndpoint;
+#if defined(SHARED_EP_ENABLE)
+    USB_Descriptor_Interface_t            Shared_Interface;
+    USB_HID_Descriptor_HID_t              Shared_HID;
+    USB_Descriptor_Endpoint_t             Shared_INEndpoint;
 #endif
 
-#ifdef RAW_ENABLE
+#if defined(RAW_ENABLE)
     // Raw HID Interface
     USB_Descriptor_Interface_t            Raw_Interface;
     USB_HID_Descriptor_HID_t              Raw_HID;
@@ -88,13 +89,6 @@ typedef struct
     USB_Descriptor_Endpoint_t             Console_OUTEndpoint;
 #endif
 
-#ifdef NKRO_ENABLE
-    // NKRO HID Interface
-    USB_Descriptor_Interface_t            NKRO_Interface;
-    USB_HID_Descriptor_HID_t              NKRO_HID;
-    USB_Descriptor_Endpoint_t             NKRO_INEndpoint;
-#endif
-
 #ifdef MIDI_ENABLE
     USB_Descriptor_Interface_Association_t    Audio_Interface_Association;
     // MIDI Audio Control Interface
@@ -133,133 +127,105 @@ typedef struct
 
 
 /* index of interface */
-#define KEYBOARD_INTERFACE          0
-
+enum usb_interfaces {
+#if !defined(KEYBOARD_SHARED_EP)
+    KEYBOARD_INTERFACE,
+#else
+#   define KEYBOARD_INTERFACE SHARED_INTERFACE
+#endif
 // It is important that the Raw HID interface is at a constant
 // interface number, to support Linux/OSX platforms and chrome.hid
 // If Raw HID is enabled, let it be always 1.
-#ifdef RAW_ENABLE
-#   define RAW_INTERFACE          (KEYBOARD_INTERFACE + 1)
-#else
-#   define RAW_INTERFACE          KEYBOARD_INTERFACE
+#if defined(RAW_ENABLE)
+    RAW_INTERFACE,
 #endif
-
-#ifdef MOUSE_ENABLE
-#   define MOUSE_INTERFACE          (RAW_INTERFACE + 1)
-#else
-#   define MOUSE_INTERFACE          RAW_INTERFACE
+#if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP)
+    MOUSE_INTERFACE,
 #endif
-
-#ifdef EXTRAKEY_ENABLE
-#   define EXTRAKEY_INTERFACE       (MOUSE_INTERFACE + 1)
-#else
-#   define EXTRAKEY_INTERFACE       MOUSE_INTERFACE
+#if defined(SHARED_EP_ENABLE)
+    SHARED_INTERFACE,
 #endif
-
-#ifdef CONSOLE_ENABLE
-#   define CONSOLE_INTERFACE        (EXTRAKEY_INTERFACE + 1)
-#else
-#   define CONSOLE_INTERFACE        EXTRAKEY_INTERFACE
-#endif
-
-#ifdef NKRO_ENABLE
-#   define NKRO_INTERFACE           (CONSOLE_INTERFACE + 1)
-#else
-#   define NKRO_INTERFACE           CONSOLE_INTERFACE
+#if defined(CONSOLE_ENABLE)
+    CONSOLE_INTERFACE,
 #endif
-
-#ifdef MIDI_ENABLE
-#   define AC_INTERFACE           (NKRO_INTERFACE + 1)
-#   define AS_INTERFACE           (NKRO_INTERFACE + 2)
-#else
-#   define AS_INTERFACE           NKRO_INTERFACE
+#if defined(MIDI_ENABLE)
+    AC_INTERFACE,
+    AS_INTERFACE,
 #endif
-
-#ifdef VIRTSER_ENABLE
-#   define CCI_INTERFACE         (AS_INTERFACE + 1)
-#   define CDI_INTERFACE         (AS_INTERFACE + 2)
-#else
-#   define CDI_INTERFACE         AS_INTERFACE
+#if defined(VIRTSER_ENABLE)
+    CCI_INTERFACE,
+    CDI_INTERFACE,
 #endif
+    TOTAL_INTERFACES
+};
 
-/* nubmer of interfaces */
-#define TOTAL_INTERFACES            (CDI_INTERFACE + 1)
-
+#define NEXT_EPNUM __COUNTER__
 
-// Endopoint number and size
-#define KEYBOARD_IN_EPNUM           1
-
-#ifdef MOUSE_ENABLE
-#   define MOUSE_IN_EPNUM           (KEYBOARD_IN_EPNUM + 1)
+enum usb_endpoints {
+    __unused_epnum__ = NEXT_EPNUM,   /* EP numbering starts at 1 */
+#if !defined(KEYBOARD_SHARED_EP)
+    KEYBOARD_IN_EPNUM = NEXT_EPNUM,
 #else
-#   define MOUSE_IN_EPNUM           KEYBOARD_IN_EPNUM
+#   define KEYBOARD_IN_EPNUM    SHARED_IN_EPNUM
 #endif
-
-#ifdef EXTRAKEY_ENABLE
-#   define EXTRAKEY_IN_EPNUM        (MOUSE_IN_EPNUM + 1)
+#if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP)
+    MOUSE_IN_EPNUM = NEXT_EPNUM,
 #else
-#   define EXTRAKEY_IN_EPNUM        MOUSE_IN_EPNUM
+#   define MOUSE_IN_EPNUM   SHARED_IN_EPNUM
 #endif
-
-#ifdef RAW_ENABLE
-#   define RAW_IN_EPNUM         (EXTRAKEY_IN_EPNUM + 1)
-#   define RAW_OUT_EPNUM        (EXTRAKEY_IN_EPNUM + 2)
-#else
-#   define RAW_OUT_EPNUM        EXTRAKEY_IN_EPNUM
+#if defined(RAW_ENABLE)
+    RAW_IN_EPNUM = NEXT_EPNUM,
+    RAW_OUT_EPNUM = NEXT_EPNUM,
 #endif
-
-#ifdef CONSOLE_ENABLE
-#   define CONSOLE_IN_EPNUM         (RAW_OUT_EPNUM + 1)
+#if defined(SHARED_EP_ENABLE)
+    SHARED_IN_EPNUM = NEXT_EPNUM,
+#endif
+#if defined(CONSOLE_ENABLE)
+    CONSOLE_IN_EPNUM = NEXT_EPNUM,
 #ifdef PROTOCOL_CHIBIOS
 // ChibiOS has enough memory and descriptor to actually enable the endpoint
 // It could use the same endpoint numbers, as that's supported by ChibiOS
 // But the QMK code currently assumes that the endpoint numbers are different
-#   define CONSOLE_OUT_EPNUM        (RAW_OUT_EPNUM + 2)
+    CONSOLE_OUT_EPNUM = NEXT_EPNUM,
 #else
-#   define CONSOLE_OUT_EPNUM        (RAW_OUT_EPNUM + 1)
+#define CONSOLE_OUT_EPNUM CONSOLE_IN_EPNUM
 #endif
-#else
-#   define CONSOLE_OUT_EPNUM        RAW_OUT_EPNUM
 #endif
-
-#ifdef NKRO_ENABLE
-#   define NKRO_IN_EPNUM            (CONSOLE_OUT_EPNUM + 1)
-#else
-#   define NKRO_IN_EPNUM            CONSOLE_OUT_EPNUM
-#endif
-
 #ifdef MIDI_ENABLE
-#   define MIDI_STREAM_IN_EPNUM     (NKRO_IN_EPNUM + 1)
-// #   define MIDI_STREAM_OUT_EPNUM    (NKRO_IN_EPNUM + 1)
-#   define MIDI_STREAM_OUT_EPNUM    (NKRO_IN_EPNUM + 2)
+    MIDI_STREAM_IN_EPNUM = NEXT_EPNUM,
+    MIDI_STREAM_OUT_EPNUM = NEXT_EPNUM,
 #   define MIDI_STREAM_IN_EPADDR    (ENDPOINT_DIR_IN | MIDI_STREAM_IN_EPNUM)
 #   define MIDI_STREAM_OUT_EPADDR   (ENDPOINT_DIR_OUT | MIDI_STREAM_OUT_EPNUM)
-#else
-#   define MIDI_STREAM_OUT_EPNUM     NKRO_IN_EPNUM
 #endif
-
 #ifdef VIRTSER_ENABLE
-#   define CDC_NOTIFICATION_EPNUM   (MIDI_STREAM_OUT_EPNUM + 1)
-#   define CDC_IN_EPNUM       (MIDI_STREAM_OUT_EPNUM + 2)
-#   define CDC_OUT_EPNUM        (MIDI_STREAM_OUT_EPNUM + 3)
+    CDC_NOTIFICATION_EPNUM = NEXT_EPNUM,
+    CDC_IN_EPNUM = NEXT_EPNUM,
+    CDC_OUT_EPNUM = NEXT_EPNUM,
 #   define CDC_NOTIFICATION_EPADDR        (ENDPOINT_DIR_IN | CDC_NOTIFICATION_EPNUM)
 #   define CDC_IN_EPADDR                  (ENDPOINT_DIR_IN | CDC_IN_EPNUM)
 #   define CDC_OUT_EPADDR                  (ENDPOINT_DIR_OUT | CDC_OUT_EPNUM)
-#else
-#   define CDC_OUT_EPNUM  MIDI_STREAM_OUT_EPNUM
 #endif
+};
+
+#if defined(PROTOCOL_LUFA)
+/* LUFA tells us total endpoints including control */
+#define MAX_ENDPOINTS (ENDPOINT_TOTAL_ENDPOINTS - 1)
+#elif defined(PROTOCOL_CHIBIOS)
+/* ChibiOS gives us number of available user endpoints, not control */
+#define MAX_ENDPOINTS USB_MAX_ENDPOINTS
+#endif
+/* TODO - ARM_ATSAM */
+
 
-#if (defined(PROTOCOL_LUFA) && CDC_OUT_EPNUM > (ENDPOINT_TOTAL_ENDPOINTS - 1)) || \
-  (defined(PROTOCOL_CHIBIOS) && CDC_OUT_EPNUM > USB_MAX_ENDPOINTS)
-# error "There are not enough available endpoints to support all functions. Remove some in the rules.mk file.(MOUSEKEY, EXTRAKEY, CONSOLE, NKRO, MIDI, SERIAL, STENO)"
+#if (NEXT_EPNUM - 1) > MAX_ENDPOINTS
+# error There are not enough available endpoints to support all functions. Remove some in the rules.mk file. (MOUSEKEY, EXTRAKEY, CONSOLE, NKRO, MIDI, SERIAL, STENO)
 #endif
 
 #define KEYBOARD_EPSIZE             8
+#define SHARED_EPSIZE               32
 #define MOUSE_EPSIZE                8
-#define EXTRAKEY_EPSIZE             8
 #define RAW_EPSIZE                  32
 #define CONSOLE_EPSIZE              32
-#define NKRO_EPSIZE                 32
 #define MIDI_STREAM_EPSIZE          64
 #define CDC_NOTIFICATION_EPSIZE     8
 #define CDC_EPSIZE                  16