aboutsummaryrefslogtreecommitdiff
path: root/tmk_core/protocol/vusb
diff options
context:
space:
mode:
authorNick Brassel <[email protected]>2023-11-28 16:39:48 +1100
committerNick Brassel <[email protected]>2023-11-28 16:40:47 +1100
commit0115951de12bd4c798a43a380651c34552552e85 (patch)
tree62999011ae782d93aa6dc9c889615db2a840cafc /tmk_core/protocol/vusb
parent0379d1f59e58cefa18cdb72ba1b77507d1108ae6 (diff)
parent4d99e0a23cff02f4c6e55e093b5de08a9be0df7c (diff)
downloadqmk_firmware-0.23.0.tar.gz
qmk_firmware-0.23.0.zip
`develop` -> `master`, 2023q4 edition0.23.0
Diffstat (limited to 'tmk_core/protocol/vusb')
-rw-r--r--tmk_core/protocol/vusb/protocol.c1
-rw-r--r--tmk_core/protocol/vusb/vusb.c276
-rw-r--r--tmk_core/protocol/vusb/vusb.h1
3 files changed, 148 insertions, 130 deletions
diff --git a/tmk_core/protocol/vusb/protocol.c b/tmk_core/protocol/vusb/protocol.c
index ae99680ce4..1f64561274 100644
--- a/tmk_core/protocol/vusb/protocol.c
+++ b/tmk_core/protocol/vusb/protocol.c
@@ -153,7 +153,6 @@ void protocol_task(void) {
if (usbConfiguration && usbInterruptIsReady()) {
keyboard_task();
}
- vusb_transfer_keyboard();
#ifdef RAW_ENABLE
usbPoll();
diff --git a/tmk_core/protocol/vusb/vusb.c b/tmk_core/protocol/vusb/vusb.c
index d74f375f66..d09b2f19b7 100644
--- a/tmk_core/protocol/vusb/vusb.c
+++ b/tmk_core/protocol/vusb/vusb.c
@@ -48,16 +48,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
# include "os_detection.h"
#endif
-#define NEXT_INTERFACE __COUNTER__
-
/*
* Interface indexes
*/
enum usb_interfaces {
#ifndef KEYBOARD_SHARED_EP
- KEYBOARD_INTERFACE = NEXT_INTERFACE,
+ KEYBOARD_INTERFACE,
#else
- SHARED_INTERFACE = NEXT_INTERFACE,
+ SHARED_INTERFACE,
# define KEYBOARD_INTERFACE SHARED_INTERFACE
#endif
@@ -65,67 +63,77 @@ enum usb_interfaces {
// interface number, to support Linux/OSX platforms and chrome.hid
// If Raw HID is enabled, let it be always 1.
#ifdef RAW_ENABLE
- RAW_INTERFACE = NEXT_INTERFACE,
+ RAW_INTERFACE,
#endif
#if defined(SHARED_EP_ENABLE) && !defined(KEYBOARD_SHARED_EP)
- SHARED_INTERFACE = NEXT_INTERFACE,
+ SHARED_INTERFACE,
#endif
#ifdef CONSOLE_ENABLE
- CONSOLE_INTERFACE = NEXT_INTERFACE,
+ CONSOLE_INTERFACE,
#endif
- TOTAL_INTERFACES = NEXT_INTERFACE
+ TOTAL_INTERFACES
};
#define MAX_INTERFACES 3
-#if (NEXT_INTERFACE - 1) > MAX_INTERFACES
-# error There are not enough available interfaces to support all functions. Please disable one or more of the following: Mouse Keys, Extra Keys, Raw HID, Console
-#endif
+_Static_assert(TOTAL_INTERFACES <= MAX_INTERFACES, "There are not enough available interfaces to support all functions. Please disable one or more of the following: Mouse Keys, Extra Keys, Raw HID, Console.");
#if (defined(MOUSE_ENABLE) || defined(EXTRAKEY_ENABLE)) && CONSOLE_ENABLE
# error Mouse/Extra Keys share an endpoint with Console. Please disable one of the two.
#endif
static uint8_t keyboard_led_state = 0;
-static uint8_t vusb_idle_rate = 0;
-
-/* Keyboard report send buffer */
-#define KBUF_SIZE 16
-static report_keyboard_t kbuf[KBUF_SIZE];
-static uint8_t kbuf_head = 0;
-static uint8_t kbuf_tail = 0;
+uint8_t keyboard_idle = 0;
+uint8_t keyboard_protocol = 1;
static report_keyboard_t keyboard_report_sent;
-#define VUSB_TRANSFER_KEYBOARD_MAX_TRIES 10
-
-/* transfer keyboard report from buffer */
-void vusb_transfer_keyboard(void) {
- for (int i = 0; i < VUSB_TRANSFER_KEYBOARD_MAX_TRIES; i++) {
- if (usbInterruptIsReady()) {
- if (kbuf_head != kbuf_tail) {
-#ifndef KEYBOARD_SHARED_EP
- usbSetInterrupt((void *)&kbuf[kbuf_tail], sizeof(report_keyboard_t));
-#else
- // Ugly hack! :(
- usbSetInterrupt((void *)&kbuf[kbuf_tail], sizeof(report_keyboard_t) - 1);
- while (!usbInterruptIsReady()) {
- usbPoll();
+static void send_report_fragment(uint8_t endpoint, void *data, size_t size) {
+ for (uint8_t retries = 5; retries > 0; retries--) {
+ switch (endpoint) {
+ case 1:
+ if (usbInterruptIsReady()) {
+ usbSetInterrupt(data, size);
+ return;
}
- usbSetInterrupt((void *)(&(kbuf[kbuf_tail].keys[5])), 1);
-#endif
- kbuf_tail = (kbuf_tail + 1) % KBUF_SIZE;
- if (debug_keyboard) {
- dprintf("V-USB: kbuf[%d->%d](%02X)\n", kbuf_tail, kbuf_head, (kbuf_head < kbuf_tail) ? (KBUF_SIZE - kbuf_tail + kbuf_head) : (kbuf_head - kbuf_tail));
+ break;
+ case USB_CFG_EP3_NUMBER:
+ if (usbInterruptIsReady3()) {
+ usbSetInterrupt3(data, size);
+ return;
}
- }
- break;
+ break;
+ case USB_CFG_EP4_NUMBER:
+ if (usbInterruptIsReady4()) {
+ usbSetInterrupt4(data, size);
+ return;
+ }
+ break;
+ default:
+ return;
}
+
usbPoll();
- wait_ms(1);
+ wait_ms(5);
+ }
+}
+
+static void send_report(uint8_t endpoint, void *report, size_t size) {
+ uint8_t *temp = (uint8_t *)report;
+
+ // Send as many full packets as possible
+ for (uint8_t i = 0; i < size / 8; i++) {
+ send_report_fragment(endpoint, temp, 8);
+ temp += 8;
+ }
+
+ // Send any data left over
+ uint8_t remainder = size % 8;
+ if (remainder) {
+ send_report_fragment(endpoint, temp, remainder);
}
}
@@ -144,18 +152,7 @@ void raw_hid_send(uint8_t *data, uint8_t length) {
return;
}
- uint8_t *temp = data;
- for (uint8_t i = 0; i < 4; i++) {
- while (!usbInterruptIsReady4()) {
- usbPoll();
- }
- usbSetInterrupt4(temp, 8);
- temp += 8;
- }
- while (!usbInterruptIsReady4()) {
- usbPoll();
- }
- usbSetInterrupt4(0, 0);
+ send_report(4, data, 32);
}
__attribute__((weak)) void raw_hid_receive(uint8_t *data, uint8_t length) {
@@ -184,19 +181,6 @@ int8_t sendchar(uint8_t c) {
return 0;
}
-static inline bool usbSendData3(char *data, uint8_t len) {
- uint8_t retries = 5;
- while (!usbInterruptIsReady3()) {
- if (!(retries--)) {
- return false;
- }
- usbPoll();
- }
-
- usbSetInterrupt3((unsigned char *)data, len);
- return true;
-}
-
void console_task(void) {
if (!usbConfiguration) {
return;
@@ -213,16 +197,7 @@ void console_task(void) {
send_buf[send_buf_count++] = rbuf_dequeue();
}
- char *temp = send_buf;
- for (uint8_t i = 0; i < 4; i++) {
- if (!usbSendData3(temp, 8)) {
- break;
- }
- temp += 8;
- }
-
- usbSendData3(0, 0);
- usbPoll();
+ send_report(3, send_buf, CONSOLE_BUFFER_SIZE);
}
#endif
@@ -231,10 +206,11 @@ void console_task(void) {
*------------------------------------------------------------------*/
static uint8_t keyboard_leds(void);
static void send_keyboard(report_keyboard_t *report);
+static void send_nkro(report_nkro_t *report);
static void send_mouse(report_mouse_t *report);
static void send_extra(report_extra_t *report);
-static host_driver_t driver = {keyboard_leds, send_keyboard, send_mouse, send_extra};
+static host_driver_t driver = {keyboard_leds, send_keyboard, send_nkro, send_mouse, send_extra};
host_driver_t *vusb_driver(void) {
return &driver;
@@ -245,65 +221,56 @@ static uint8_t keyboard_leds(void) {
}
static void send_keyboard(report_keyboard_t *report) {
- uint8_t next = (kbuf_head + 1) % KBUF_SIZE;
- if (next != kbuf_tail) {
- kbuf[kbuf_head] = *report;
- kbuf_head = next;
+ if (!keyboard_protocol) {
+ send_report(1, &report->mods, 8);
} else {
- dprint("kbuf: full\n");
+ send_report(1, report, sizeof(report_keyboard_t));
}
- // NOTE: send key strokes of Macro
- usbPoll();
- vusb_transfer_keyboard();
keyboard_report_sent = *report;
}
#ifndef KEYBOARD_SHARED_EP
-# define usbInterruptIsReadyShared usbInterruptIsReady3
-# define usbSetInterruptShared usbSetInterrupt3
+# define MOUSE_IN_EPNUM 3
+# define SHARED_IN_EPNUM 3
#else
-# define usbInterruptIsReadyShared usbInterruptIsReady
-# define usbSetInterruptShared usbSetInterrupt
+# define MOUSE_IN_EPNUM 1
+# define SHARED_IN_EPNUM 1
+#endif
+
+static void send_nkro(report_nkro_t *report) {
+#ifdef NKRO_ENABLE
+ send_report(3, report, sizeof(report_nkro_t));
#endif
+}
static void send_mouse(report_mouse_t *report) {
#ifdef MOUSE_ENABLE
- if (usbInterruptIsReadyShared()) {
- usbSetInterruptShared((void *)report, sizeof(report_mouse_t));
- }
+ send_report(MOUSE_IN_EPNUM, report, sizeof(report_mouse_t));
#endif
}
static void send_extra(report_extra_t *report) {
#ifdef EXTRAKEY_ENABLE
- if (usbInterruptIsReadyShared()) {
- usbSetInterruptShared((void *)report, sizeof(report_extra_t));
- }
+ send_report(SHARED_IN_EPNUM, report, sizeof(report_extra_t));
#endif
}
void send_joystick(report_joystick_t *report) {
#ifdef JOYSTICK_ENABLE
- if (usbInterruptIsReadyShared()) {
- usbSetInterruptShared((void *)report, sizeof(report_joystick_t));
- }
+ send_report(SHARED_IN_EPNUM, report, sizeof(report_joystick_t));
#endif
}
void send_digitizer(report_digitizer_t *report) {
#ifdef DIGITIZER_ENABLE
- if (usbInterruptIsReadyShared()) {
- usbSetInterruptShared((void *)report, sizeof(report_digitizer_t));
- }
+ send_report(SHARED_IN_EPNUM, report, sizeof(report_digitizer_t));
#endif
}
void send_programmable_button(report_programmable_button_t *report) {
#ifdef PROGRAMMABLE_BUTTON_ENABLE
- if (usbInterruptIsReadyShared()) {
- usbSetInterruptShared((void *)report, sizeof(report_programmable_button_t));
- }
+ send_report(SHARED_IN_EPNUM, report, sizeof(report_programmable_button_t));
#endif
}
@@ -319,30 +286,44 @@ usbMsgLen_t usbFunctionSetup(uchar data[8]) {
usbRequest_t *rq = (void *)data;
if ((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS) { /* class request type */
- if (rq->bRequest == USBRQ_HID_GET_REPORT) {
- dprint("GET_REPORT:");
- if (rq->wIndex.word == KEYBOARD_INTERFACE) {
- usbMsgPtr = (usbMsgPtr_t)&keyboard_report_sent;
- return sizeof(keyboard_report_sent);
- }
- } else if (rq->bRequest == USBRQ_HID_GET_IDLE) {
- dprint("GET_IDLE:");
- usbMsgPtr = (usbMsgPtr_t)&vusb_idle_rate;
- return 1;
- } else if (rq->bRequest == USBRQ_HID_SET_IDLE) {
- vusb_idle_rate = rq->wValue.bytes[1];
- dprintf("SET_IDLE: %02X", vusb_idle_rate);
- } else if (rq->bRequest == USBRQ_HID_SET_REPORT) {
- dprint("SET_REPORT:");
- // Report Type: 0x02(Out)/ReportID: 0x00(none) && Interface: 0(keyboard)
- if (rq->wValue.word == 0x0200 && rq->wIndex.word == KEYBOARD_INTERFACE) {
- dprint("SET_LED:");
- last_req.kind = SET_LED;
- last_req.len = rq->wLength.word;
- }
- return USB_NO_MSG; // to get data in usbFunctionWrite
- } else {
- dprint("UNKNOWN:");
+ switch (rq->bRequest) {
+ case USBRQ_HID_GET_REPORT:
+ dprint("GET_REPORT:");
+ if (rq->wIndex.word == KEYBOARD_INTERFACE) {
+ usbMsgPtr = (usbMsgPtr_t)&keyboard_report_sent;
+ return sizeof(keyboard_report_sent);
+ }
+ break;
+ case USBRQ_HID_GET_IDLE:
+ dprint("GET_IDLE:");
+ usbMsgPtr = (usbMsgPtr_t)&keyboard_idle;
+ return 1;
+ case USBRQ_HID_GET_PROTOCOL:
+ dprint("GET_PROTOCOL:");
+ usbMsgPtr = (usbMsgPtr_t)&keyboard_protocol;
+ return 1;
+ case USBRQ_HID_SET_REPORT:
+ dprint("SET_REPORT:");
+ // Report Type: 0x02(Out)/ReportID: 0x00(none) && Interface: 0(keyboard)
+ if (rq->wValue.word == 0x0200 && rq->wIndex.word == KEYBOARD_INTERFACE) {
+ dprint("SET_LED:");
+ last_req.kind = SET_LED;
+ last_req.len = rq->wLength.word;
+ }
+ return USB_NO_MSG; // to get data in usbFunctionWrite
+ case USBRQ_HID_SET_IDLE:
+ keyboard_idle = (rq->wValue.word & 0xFF00) >> 8;
+ dprintf("SET_IDLE: %02X", keyboard_idle);
+ break;
+ case USBRQ_HID_SET_PROTOCOL:
+ if (rq->wIndex.word == KEYBOARD_INTERFACE) {
+ keyboard_protocol = rq->wValue.word & 0xFF;
+ dprintf("SET_PROTOCOL: %02X", keyboard_protocol);
+ }
+ break;
+ default:
+ dprint("UNKNOWN:");
+ break;
}
} else {
dprint("VENDOR:");
@@ -454,6 +435,45 @@ const PROGMEM uchar shared_hid_report[] = {
# define SHARED_REPORT_STARTED
#endif
+#ifdef NKRO_ENABLE
+ // NKRO report descriptor
+ 0x05, 0x01, // Usage Page (Generic Desktop)
+ 0x09, 0x06, // Usage (Keyboard)
+ 0xA1, 0x01, // Collection (Application)
+ 0x85, REPORT_ID_NKRO, // Report ID
+ // Modifiers (8 bits)
+ 0x05, 0x07, // Usage Page (Keyboard/Keypad)
+ 0x19, 0xE0, // Usage Minimum (Keyboard Left Control)
+ 0x29, 0xE7, // Usage Maximum (Keyboard Right GUI)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x25, 0x01, // Logical Maximum (1)
+ 0x95, 0x08, // Report Count (8)
+ 0x75, 0x01, // Report Size (1)
+ 0x81, 0x02, // Input (Data, Variable, Absolute)
+ // Keycodes
+ 0x05, 0x07, // Usage Page (Keyboard/Keypad)
+ 0x19, 0x00, // Usage Minimum (0)
+ 0x29, NKRO_REPORT_BITS * 8 - 1, // Usage Maximum
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x25, 0x01, // Logical Maximum (1)
+ 0x95, NKRO_REPORT_BITS * 8, // Report Count
+ 0x75, 0x01, // Report Size (1)
+ 0x81, 0x02, // Input (Data, Variable, Absolute)
+
+ // Status LEDs (5 bits)
+ 0x05, 0x08, // Usage Page (LED)
+ 0x19, 0x01, // Usage Minimum (Num Lock)
+ 0x29, 0x05, // Usage Maximum (Kana)
+ 0x95, 0x05, // Report Count (5)
+ 0x75, 0x01, // Report Size (1)
+ 0x91, 0x02, // Output (Data, Variable, Absolute)
+ // LED padding (3 bits)
+ 0x95, 0x01, // Report Count (1)
+ 0x75, 0x03, // Report Size (3)
+ 0x91, 0x03, // Output (Constant)
+ 0xC0, // End Collection
+#endif
+
#ifdef MOUSE_ENABLE
// Mouse report descriptor
0x05, 0x01, // Usage Page (Generic Desktop)
@@ -1024,7 +1044,7 @@ USB_PUBLIC usbMsgLen_t usbFunctionDescriptor(struct usbRequest *rq) {
#endif
break;
case USBDESCR_HID:
- switch (rq->wValue.bytes[0]) {
+ switch (rq->wIndex.word) {
#ifndef KEYBOARD_SHARED_EP
case KEYBOARD_INTERFACE:
usbMsgPtr = (usbMsgPtr_t)&usbConfigurationDescriptor.keyboardHID;
diff --git a/tmk_core/protocol/vusb/vusb.h b/tmk_core/protocol/vusb/vusb.h
index c5cb27ded6..ae17e5e014 100644
--- a/tmk_core/protocol/vusb/vusb.h
+++ b/tmk_core/protocol/vusb/vusb.h
@@ -121,4 +121,3 @@ typedef struct usbConfigurationDescriptor {
extern bool vusb_suspended;
host_driver_t *vusb_driver(void);
-void vusb_transfer_keyboard(void);