Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use a single endpoint for HID reports #3951

Merged
merged 12 commits into from
Nov 16, 2018
29 changes: 29 additions & 0 deletions docs/config_options.md
Original file line number Diff line number Diff line change
Expand Up @@ -260,3 +260,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.
21 changes: 21 additions & 0 deletions tmk_core/common.mk
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,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)
Expand All @@ -109,6 +125,7 @@ endif

ifeq ($(strip $(NKRO_ENABLE)), yes)
TMK_COMMON_DEFS += -DNKRO_ENABLE
SHARED_EP_ENABLE = yes
endif

ifeq ($(strip $(USB_6KRO_ENABLE)), yes)
Expand Down Expand Up @@ -180,6 +197,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)
Expand Down
22 changes: 22 additions & 0 deletions tmk_core/common/host.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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) {
Expand All @@ -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);
}

Expand Down
21 changes: 17 additions & 4 deletions tmk_core/common/report.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "keycode_config.h"
#include "debug.h"
#include "util.h"
#include <string.h>

/** \brief has_anykey
*
Expand All @@ -27,8 +28,16 @@
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;
Expand Down Expand Up @@ -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));
}
46 changes: 30 additions & 16 deletions tmk_core/common/report.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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" {
Expand Down Expand Up @@ -126,19 +131,28 @@ 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;
#endif
} __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;
Expand Down
5 changes: 3 additions & 2 deletions tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
#include "udi_hid.h"
#include "udi_hid_kbd.h"
#include <string.h>
#include "report.h"

//***************************************************************************
// KBD
Expand Down Expand Up @@ -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),
Expand All @@ -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),
Expand Down
Loading