diff options
author | James Laird-Wah <james@laird-wah.net> | 2018-11-16 17:22:05 +1100 |
---|---|---|
committer | Drashna Jaelre <drashna@live.com> | 2018-11-15 22:22:05 -0800 |
commit | 39bd760faf2666e91d6dc5b199f02fa3206c6acd (patch) | |
tree | 12db265881a0d358bb0e186689a7b20a81c37bc6 /tmk_core/protocol/chibios | |
parent | 46cf8cc9b33a3c8bdbb0ce7df7f48f28e4d979a5 (diff) |
Use a single endpoint for HID reports (#3951)
* 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
Diffstat (limited to 'tmk_core/protocol/chibios')
-rw-r--r-- | tmk_core/protocol/chibios/usb_main.c | 176 | ||||
-rw-r--r-- | tmk_core/protocol/chibios/usb_main.h | 11 |
2 files changed, 90 insertions, 97 deletions
diff --git a/tmk_core/protocol/chibios/usb_main.c b/tmk_core/protocol/chibios/usb_main.c index 71892c4f49..3028e7ea2a 100644 --- a/tmk_core/protocol/chibios/usb_main.c +++ b/tmk_core/protocol/chibios/usb_main.c @@ -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(); } diff --git a/tmk_core/protocol/chibios/usb_main.h b/tmk_core/protocol/chibios/usb_main.h index 1f7eb12f8d..55e8882cc4 100644 --- a/tmk_core/protocol/chibios/usb_main.h +++ b/tmk_core/protocol/chibios/usb_main.h @@ -66,15 +66,20 @@ 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 * --------------- */ #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; |