mirror of
https://github.com/qmk/qmk_firmware
synced 2024-12-22 08:26:21 +00:00
[Core] Refactor ChibiOS USB endpoints to be fully async (#21656)
This commit is contained in:
parent
b43f6cb7ef
commit
0e02b0c41e
@ -192,15 +192,18 @@ void protocol_pre_task(void) {
|
||||
/* Remote wakeup */
|
||||
if ((USB_DRIVER.status & USB_GETSTATUS_REMOTE_WAKEUP_ENABLED) && suspend_wakeup_condition()) {
|
||||
usbWakeupHost(&USB_DRIVER);
|
||||
restart_usb_driver(&USB_DRIVER);
|
||||
# if USB_SUSPEND_WAKEUP_DELAY > 0
|
||||
// Some hubs, kvm switches, and monitors do
|
||||
// weird things, with USB device state bouncing
|
||||
// around wildly on wakeup, yielding race
|
||||
// conditions that can corrupt the keyboard state.
|
||||
//
|
||||
// Pause for a while to let things settle...
|
||||
wait_ms(USB_SUSPEND_WAKEUP_DELAY);
|
||||
# endif
|
||||
}
|
||||
}
|
||||
/* Woken up */
|
||||
// variables has been already cleared by the wakeup hook
|
||||
send_keyboard_report();
|
||||
# ifdef MOUSEKEY_ENABLE
|
||||
mousekey_send();
|
||||
# endif /* MOUSEKEY_ENABLE */
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -218,4 +221,5 @@ void protocol_post_task(void) {
|
||||
#ifdef RAW_ENABLE
|
||||
raw_hid_task();
|
||||
#endif
|
||||
usb_idle_task();
|
||||
}
|
||||
|
@ -6,6 +6,8 @@ SRC += $(CHIBIOS_DIR)/usb_main.c
|
||||
SRC += $(CHIBIOS_DIR)/chibios.c
|
||||
SRC += usb_descriptor.c
|
||||
SRC += $(CHIBIOS_DIR)/usb_driver.c
|
||||
SRC += $(CHIBIOS_DIR)/usb_endpoints.c
|
||||
SRC += $(CHIBIOS_DIR)/usb_report_handling.c
|
||||
SRC += $(CHIBIOS_DIR)/usb_util.c
|
||||
SRC += $(LIBSRC)
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
152
tmk_core/protocol/chibios/usb_endpoints.c
Normal file
152
tmk_core/protocol/chibios/usb_endpoints.c
Normal file
@ -0,0 +1,152 @@
|
||||
// Copyright 2023 Stefan Kerkmann (@KarlK90)
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include <ch.h>
|
||||
#include <hal.h>
|
||||
|
||||
#include "usb_main.h"
|
||||
#include "usb_driver.h"
|
||||
#include "usb_endpoints.h"
|
||||
#include "report.h"
|
||||
|
||||
usb_endpoint_in_t usb_endpoints_in[USB_ENDPOINT_IN_COUNT] = {
|
||||
// clang-format off
|
||||
#if defined(SHARED_EP_ENABLE)
|
||||
[USB_ENDPOINT_IN_SHARED] = QMK_USB_ENDPOINT_IN(USB_EP_MODE_TYPE_INTR, SHARED_EPSIZE, SHARED_IN_EPNUM, SHARED_IN_CAPACITY, NULL,
|
||||
QMK_USB_REPORT_STORAGE(
|
||||
&usb_shared_get_report,
|
||||
&usb_shared_set_report,
|
||||
&usb_shared_reset_report,
|
||||
&usb_shared_get_idle_rate,
|
||||
&usb_shared_set_idle_rate,
|
||||
&usb_shared_idle_timer_elapsed,
|
||||
(REPORT_ID_COUNT + 1),
|
||||
#if defined(KEYBOARD_SHARED_EP)
|
||||
QMK_USB_REPORT_STROAGE_ENTRY(REPORT_ID_KEYBOARD, sizeof(report_keyboard_t)),
|
||||
#endif
|
||||
#if defined(MOUSE_SHARED_EP)
|
||||
QMK_USB_REPORT_STROAGE_ENTRY(REPORT_ID_MOUSE, sizeof(report_mouse_t)),
|
||||
#endif
|
||||
#if defined(EXTRAKEY_ENABLE)
|
||||
QMK_USB_REPORT_STROAGE_ENTRY(REPORT_ID_SYSTEM, sizeof(report_extra_t)),
|
||||
QMK_USB_REPORT_STROAGE_ENTRY(REPORT_ID_CONSUMER, sizeof(report_extra_t)),
|
||||
#endif
|
||||
#if defined(PROGRAMMABLE_BUTTON_ENABLE)
|
||||
QMK_USB_REPORT_STROAGE_ENTRY(REPORT_ID_PROGRAMMABLE_BUTTON, sizeof(report_programmable_button_t)),
|
||||
#endif
|
||||
#if defined(NKRO_ENABLE)
|
||||
QMK_USB_REPORT_STROAGE_ENTRY(REPORT_ID_NKRO, sizeof(report_nkro_t)),
|
||||
#endif
|
||||
#if defined(JOYSTICK_SHARED_EP)
|
||||
QMK_USB_REPORT_STROAGE_ENTRY(REPORT_ID_JOYSTICK, sizeof(report_joystick_t)),
|
||||
#endif
|
||||
#if defined(DIGITIZER_SHARED_EP)
|
||||
QMK_USB_REPORT_STROAGE_ENTRY(REPORT_ID_DIGITIZER, sizeof(report_digitizer_t)),
|
||||
#endif
|
||||
)
|
||||
),
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
#if !defined(KEYBOARD_SHARED_EP)
|
||||
[USB_ENDPOINT_IN_KEYBOARD] = QMK_USB_ENDPOINT_IN(USB_EP_MODE_TYPE_INTR, KEYBOARD_EPSIZE, KEYBOARD_IN_EPNUM, KEYBOARD_IN_CAPACITY, NULL, QMK_USB_REPORT_STORAGE_DEFAULT(sizeof(report_keyboard_t))),
|
||||
#endif
|
||||
|
||||
#if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP)
|
||||
[USB_ENDPOINT_IN_MOUSE] = QMK_USB_ENDPOINT_IN(USB_EP_MODE_TYPE_INTR, MOUSE_EPSIZE, MOUSE_IN_EPNUM, MOUSE_IN_CAPACITY, NULL, QMK_USB_REPORT_STORAGE_DEFAULT(sizeof(report_mouse_t))),
|
||||
#endif
|
||||
|
||||
#if defined(JOYSTICK_ENABLE) && !defined(JOYSTICK_SHARED_EP)
|
||||
[USB_ENDPOINT_IN_JOYSTICK] = QMK_USB_ENDPOINT_IN(USB_EP_MODE_TYPE_INTR, JOYSTICK_EPSIZE, JOYSTICK_IN_EPNUM, JOYSTICK_IN_CAPACITY, QMK_USB_REPORT_STORAGE_DEFAULT(sizeof(report_joystick_t))),
|
||||
#endif
|
||||
|
||||
#if defined(DIGITIZER_ENABLE) && !defined(DIGITIZER_SHARED_EP)
|
||||
[USB_ENDPOINT_IN_JOYSTICK] = QMK_USB_ENDPOINT_IN(USB_EP_MODE_TYPE_INTR, DIGITIZER_EPSIZE, DIGITIZER_IN_EPNUM, DIGITIZER_IN_CAPACITY, QMK_USB_REPORT_STORAGE_DEFAULT(sizeof(report_digitizer_t))),
|
||||
#endif
|
||||
|
||||
#if defined(CONSOLE_ENABLE)
|
||||
# if defined(USB_ENDPOINTS_ARE_REORDERABLE)
|
||||
[USB_ENDPOINT_IN_CONSOLE] = QMK_USB_ENDPOINT_IN_SHARED(USB_EP_MODE_TYPE_INTR, CONSOLE_EPSIZE, CONSOLE_IN_EPNUM, CONSOLE_IN_CAPACITY, NULL, QMK_USB_REPORT_STORAGE_DEFAULT(CONSOLE_EPSIZE)),
|
||||
# else
|
||||
[USB_ENDPOINT_IN_CONSOLE] = QMK_USB_ENDPOINT_IN(USB_EP_MODE_TYPE_INTR, CONSOLE_EPSIZE, CONSOLE_IN_EPNUM, CONSOLE_IN_CAPACITY, NULL, QMK_USB_REPORT_STORAGE_DEFAULT(CONSOLE_EPSIZE)),
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(RAW_ENABLE)
|
||||
# if defined(USB_ENDPOINTS_ARE_REORDERABLE)
|
||||
[USB_ENDPOINT_IN_RAW] = QMK_USB_ENDPOINT_IN_SHARED(USB_EP_MODE_TYPE_INTR, RAW_EPSIZE, RAW_IN_EPNUM, RAW_IN_CAPACITY, NULL, QMK_USB_REPORT_STORAGE_DEFAULT(RAW_EPSIZE)),
|
||||
# else
|
||||
[USB_ENDPOINT_IN_RAW] = QMK_USB_ENDPOINT_IN(USB_EP_MODE_TYPE_INTR, RAW_EPSIZE, RAW_IN_EPNUM, RAW_IN_CAPACITY, NULL, QMK_USB_REPORT_STORAGE_DEFAULT(RAW_EPSIZE)),
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(MIDI_ENABLE)
|
||||
# if defined(USB_ENDPOINTS_ARE_REORDERABLE)
|
||||
[USB_ENDPOINT_IN_MIDI] = QMK_USB_ENDPOINT_IN_SHARED(USB_EP_MODE_TYPE_BULK, MIDI_STREAM_EPSIZE, MIDI_STREAM_IN_EPNUM, MIDI_STREAM_IN_CAPACITY, NULL, NULL),
|
||||
# else
|
||||
[USB_ENDPOINT_IN_MIDI] = QMK_USB_ENDPOINT_IN(USB_EP_MODE_TYPE_BULK, MIDI_STREAM_EPSIZE, MIDI_STREAM_IN_EPNUM, MIDI_STREAM_IN_CAPACITY, NULL, NULL),
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(VIRTSER_ENABLE)
|
||||
# if defined(USB_ENDPOINTS_ARE_REORDERABLE)
|
||||
[USB_ENDPOINT_IN_CDC_DATA] = QMK_USB_ENDPOINT_IN_SHARED(USB_EP_MODE_TYPE_BULK, CDC_EPSIZE, CDC_IN_EPNUM, CDC_IN_CAPACITY, virtser_usb_request_cb, NULL),
|
||||
# else
|
||||
[USB_ENDPOINT_IN_CDC_DATA] = QMK_USB_ENDPOINT_IN(USB_EP_MODE_TYPE_BULK, CDC_EPSIZE, CDC_IN_EPNUM, CDC_IN_CAPACITY, virtser_usb_request_cb, NULL),
|
||||
# endif
|
||||
[USB_ENDPOINT_IN_CDC_SIGNALING] = QMK_USB_ENDPOINT_IN(USB_EP_MODE_TYPE_INTR, CDC_NOTIFICATION_EPSIZE, CDC_NOTIFICATION_EPNUM, CDC_SIGNALING_DUMMY_CAPACITY, NULL, NULL),
|
||||
#endif
|
||||
};
|
||||
|
||||
usb_endpoint_in_lut_t usb_endpoint_interface_lut[TOTAL_INTERFACES] = {
|
||||
#if !defined(KEYBOARD_SHARED_EP)
|
||||
[KEYBOARD_INTERFACE] = USB_ENDPOINT_IN_KEYBOARD,
|
||||
#endif
|
||||
|
||||
#if defined(RAW_ENABLE)
|
||||
[RAW_INTERFACE] = USB_ENDPOINT_IN_RAW,
|
||||
#endif
|
||||
|
||||
#if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP)
|
||||
[MOUSE_INTERFACE] = USB_ENDPOINT_IN_MOUSE,
|
||||
#endif
|
||||
|
||||
#if defined(SHARED_EP_ENABLE)
|
||||
[SHARED_INTERFACE] = USB_ENDPOINT_IN_SHARED,
|
||||
#endif
|
||||
|
||||
#if defined(CONSOLE_ENABLE)
|
||||
[CONSOLE_INTERFACE] = USB_ENDPOINT_IN_CONSOLE,
|
||||
#endif
|
||||
|
||||
#if defined(MIDI_ENABLE)
|
||||
[AS_INTERFACE] = USB_ENDPOINT_IN_MIDI,
|
||||
#endif
|
||||
|
||||
#if defined(VIRTSER_ENABLE)
|
||||
[CCI_INTERFACE] = USB_ENDPOINT_IN_CDC_SIGNALING,
|
||||
[CDI_INTERFACE] = USB_ENDPOINT_IN_CDC_DATA,
|
||||
#endif
|
||||
|
||||
#if defined(JOYSTICK_ENABLE) && !defined(JOYSTICK_SHARED_EP)
|
||||
[JOYSTICK_INTERFACE] = USB_ENDPOINT_IN_JOYSTICK,
|
||||
#endif
|
||||
|
||||
#if defined(DIGITIZER_ENABLE) && !defined(DIGITIZER_SHARED_EP)
|
||||
[DIGITIZER_INTERFACE] = USB_ENDPOINT_IN_DIGITIZER,
|
||||
#endif
|
||||
};
|
||||
|
||||
usb_endpoint_out_t usb_endpoints_out[USB_ENDPOINT_OUT_COUNT] = {
|
||||
#if defined(RAW_ENABLE)
|
||||
[USB_ENDPOINT_OUT_RAW] = QMK_USB_ENDPOINT_OUT(USB_EP_MODE_TYPE_INTR, RAW_EPSIZE, RAW_OUT_EPNUM, RAW_OUT_CAPACITY),
|
||||
#endif
|
||||
|
||||
#if defined(MIDI_ENABLE)
|
||||
[USB_ENDPOINT_OUT_MIDI] = QMK_USB_ENDPOINT_OUT(USB_EP_MODE_TYPE_BULK, MIDI_STREAM_EPSIZE, MIDI_STREAM_OUT_EPNUM, MIDI_STREAM_OUT_CAPACITY),
|
||||
#endif
|
||||
|
||||
#if defined(VIRTSER_ENABLE)
|
||||
[USB_ENDPOINT_OUT_CDC_DATA] = QMK_USB_ENDPOINT_OUT(USB_EP_MODE_TYPE_BULK, CDC_EPSIZE, CDC_OUT_EPNUM, CDC_OUT_CAPACITY),
|
||||
#endif
|
||||
};
|
137
tmk_core/protocol/chibios/usb_endpoints.h
Normal file
137
tmk_core/protocol/chibios/usb_endpoints.h
Normal file
@ -0,0 +1,137 @@
|
||||
// Copyright 2023 Stefan Kerkmann (@KarlK90)
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "usb_descriptor.h"
|
||||
|
||||
#if !defined(USB_DEFAULT_BUFFER_CAPACITY)
|
||||
# define USB_DEFAULT_BUFFER_CAPACITY 4
|
||||
#endif
|
||||
|
||||
#if !defined(KEYBOARD_IN_CAPACITY)
|
||||
# define KEYBOARD_IN_CAPACITY USB_DEFAULT_BUFFER_CAPACITY
|
||||
#endif
|
||||
#if !defined(SHARED_IN_CAPACITY)
|
||||
# define SHARED_IN_CAPACITY USB_DEFAULT_BUFFER_CAPACITY
|
||||
#endif
|
||||
#if !defined(MOUSE_IN_CAPACITY)
|
||||
# define MOUSE_IN_CAPACITY USB_DEFAULT_BUFFER_CAPACITY
|
||||
#endif
|
||||
|
||||
#if !defined(JOYSTICK_IN_CAPACITY)
|
||||
# define JOYSTICK_IN_CAPACITY USB_DEFAULT_BUFFER_CAPACITY
|
||||
#endif
|
||||
|
||||
#if !defined(DIGITIZER_IN_CAPACITY)
|
||||
# define DIGITIZER_IN_CAPACITY USB_DEFAULT_BUFFER_CAPACITY
|
||||
#endif
|
||||
|
||||
#if !defined(CONSOLE_IN_CAPACITY)
|
||||
# define CONSOLE_IN_CAPACITY USB_DEFAULT_BUFFER_CAPACITY
|
||||
#endif
|
||||
|
||||
#if !defined(CONSOLE_OUT_CAPACITY)
|
||||
# define CONSOLE_OUT_CAPACITY USB_DEFAULT_BUFFER_CAPACITY
|
||||
#endif
|
||||
|
||||
#if !defined(RAW_IN_CAPACITY)
|
||||
# define RAW_IN_CAPACITY USB_DEFAULT_BUFFER_CAPACITY
|
||||
#endif
|
||||
|
||||
#if !defined(RAW_OUT_CAPACITY)
|
||||
# define RAW_OUT_CAPACITY USB_DEFAULT_BUFFER_CAPACITY
|
||||
#endif
|
||||
|
||||
#if !defined(MIDI_STREAM_IN_CAPACITY)
|
||||
# define MIDI_STREAM_IN_CAPACITY USB_DEFAULT_BUFFER_CAPACITY
|
||||
#endif
|
||||
|
||||
#if !defined(MIDI_STREAM_OUT_CAPACITY)
|
||||
# define MIDI_STREAM_OUT_CAPACITY USB_DEFAULT_BUFFER_CAPACITY
|
||||
#endif
|
||||
|
||||
#if !defined(CDC_IN_CAPACITY)
|
||||
# define CDC_IN_CAPACITY USB_DEFAULT_BUFFER_CAPACITY
|
||||
#endif
|
||||
|
||||
#if !defined(CDC_OUT_CAPACITY)
|
||||
# define CDC_OUT_CAPACITY USB_DEFAULT_BUFFER_CAPACITY
|
||||
#endif
|
||||
|
||||
#define CDC_SIGNALING_DUMMY_CAPACITY 1
|
||||
|
||||
typedef enum {
|
||||
#if defined(SHARED_EP_ENABLE)
|
||||
USB_ENDPOINT_IN_SHARED,
|
||||
#endif
|
||||
|
||||
#if !defined(KEYBOARD_SHARED_EP)
|
||||
USB_ENDPOINT_IN_KEYBOARD,
|
||||
#endif
|
||||
|
||||
#if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP)
|
||||
USB_ENDPOINT_IN_MOUSE,
|
||||
#endif
|
||||
|
||||
#if defined(JOYSTICK_ENABLE) && !defined(JOYSTICK_SHARED_EP)
|
||||
USB_ENDPOINT_IN_JOYSTICK,
|
||||
#endif
|
||||
|
||||
#if defined(DIGITIZER_ENABLE) && !defined(DIGITIZER_SHARED_EP)
|
||||
USB_ENDPOINT_IN_DIGITIZER,
|
||||
#endif
|
||||
|
||||
#if defined(CONSOLE_ENABLE)
|
||||
USB_ENDPOINT_IN_CONSOLE,
|
||||
#endif
|
||||
|
||||
#if defined(RAW_ENABLE)
|
||||
USB_ENDPOINT_IN_RAW,
|
||||
#endif
|
||||
|
||||
#if defined(MIDI_ENABLE)
|
||||
USB_ENDPOINT_IN_MIDI,
|
||||
#endif
|
||||
|
||||
#if defined(VIRTSER_ENABLE)
|
||||
USB_ENDPOINT_IN_CDC_DATA,
|
||||
USB_ENDPOINT_IN_CDC_SIGNALING,
|
||||
#endif
|
||||
USB_ENDPOINT_IN_COUNT,
|
||||
/* All non shared endpoints have to be consequtive numbers starting from 0, so
|
||||
* that they can be used as array indices. The shared endpoints all point to
|
||||
* the same endpoint so they have to be defined last to not reset the enum
|
||||
* counter. */
|
||||
#if defined(SHARED_EP_ENABLE)
|
||||
# if defined(KEYBOARD_SHARED_EP)
|
||||
USB_ENDPOINT_IN_KEYBOARD = USB_ENDPOINT_IN_SHARED,
|
||||
# endif
|
||||
# if defined(MOUSE_SHARED_EP)
|
||||
USB_ENDPOINT_IN_MOUSE = USB_ENDPOINT_IN_SHARED,
|
||||
# endif
|
||||
# if defined(JOYSTICK_SHARED_EP)
|
||||
USB_ENDPOINT_IN_JOYSTICK = USB_ENDPOINT_IN_SHARED,
|
||||
# endif
|
||||
# if defined(DIGITIZER_SHARED_EP)
|
||||
USB_ENDPOINT_IN_DIGITIZER = USB_ENDPOINT_IN_SHARED,
|
||||
# endif
|
||||
#endif
|
||||
} usb_endpoint_in_lut_t;
|
||||
|
||||
#define IS_VALID_USB_ENDPOINT_IN_LUT(i) ((i) >= 0 && (i) < USB_ENDPOINT_IN_COUNT)
|
||||
|
||||
usb_endpoint_in_lut_t usb_endpoint_interface_lut[TOTAL_INTERFACES];
|
||||
|
||||
typedef enum {
|
||||
#if defined(RAW_ENABLE)
|
||||
USB_ENDPOINT_OUT_RAW,
|
||||
#endif
|
||||
#if defined(MIDI_ENABLE)
|
||||
USB_ENDPOINT_OUT_MIDI,
|
||||
#endif
|
||||
#if defined(VIRTSER_ENABLE)
|
||||
USB_ENDPOINT_OUT_CDC_DATA,
|
||||
#endif
|
||||
USB_ENDPOINT_OUT_COUNT,
|
||||
} usb_endpoint_out_lut_t;
|
File diff suppressed because it is too large
Load Diff
@ -1,25 +1,21 @@
|
||||
/*
|
||||
* (c) 2015 flabberast <s3+flabbergast@sdfeu.org>
|
||||
*
|
||||
* Based on the following work:
|
||||
* - Guillaume Duc's raw hid example (MIT License)
|
||||
* https://github.com/guiduc/usb-hid-chibios-example
|
||||
* - PJRC Teensy examples (MIT License)
|
||||
* https://www.pjrc.com/teensy/usb_keyboard.html
|
||||
* - hasu's TMK keyboard code (GPL v2 and some code Modified BSD)
|
||||
* https://github.com/tmk/tmk_keyboard/
|
||||
* - ChibiOS demo code (Apache 2.0 License)
|
||||
* http://www.chibios.org
|
||||
*
|
||||
* Since some GPL'd code is used, this work is licensed under
|
||||
* GPL v2 or later.
|
||||
*/
|
||||
// Copyright 2023 Stefan Kerkmann (@KarlK90)
|
||||
// Copyright 2020 Ryan (@fauxpark)
|
||||
// Copyright 2020 Joel Challis (@zvecr)
|
||||
// Copyright 2018 James Laird-Wah
|
||||
// Copyright 2016 Fredizzimo
|
||||
// Copyright 2016 Giovanni Di Sirio
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later OR Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ch.h>
|
||||
#include <hal.h>
|
||||
|
||||
#include "usb_device_state.h"
|
||||
#include "usb_descriptor.h"
|
||||
#include "usb_driver.h"
|
||||
#include "usb_endpoints.h"
|
||||
|
||||
/* -------------------------
|
||||
* General USB driver header
|
||||
* -------------------------
|
||||
@ -36,6 +32,8 @@ void init_usb_driver(USBDriver *usbp);
|
||||
/* Restart the USB driver and bus */
|
||||
void restart_usb_driver(USBDriver *usbp);
|
||||
|
||||
bool send_report(usb_endpoint_in_lut_t endpoint, void *report, size_t size);
|
||||
|
||||
/* ---------------
|
||||
* USB Event queue
|
||||
* ---------------
|
||||
@ -58,3 +56,14 @@ void usb_event_queue_task(void);
|
||||
int8_t sendchar(uint8_t c);
|
||||
|
||||
#endif /* CONSOLE_ENABLE */
|
||||
|
||||
/* --------------
|
||||
* Virtser header
|
||||
* --------------
|
||||
*/
|
||||
|
||||
#if defined(VIRTSER_ENABLE)
|
||||
|
||||
bool virtser_usb_request_cb(USBDriver *usbp);
|
||||
|
||||
#endif
|
||||
|
296
tmk_core/protocol/chibios/usb_report_handling.c
Normal file
296
tmk_core/protocol/chibios/usb_report_handling.c
Normal file
@ -0,0 +1,296 @@
|
||||
// Copyright 2023 Stefan Kerkmann (@KarlK90)
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "usb_report_handling.h"
|
||||
#include "usb_endpoints.h"
|
||||
#include "usb_main.h"
|
||||
#include "usb_types.h"
|
||||
#include "usb_driver.h"
|
||||
#include "report.h"
|
||||
|
||||
extern usb_endpoint_in_t usb_endpoints_in[USB_ENDPOINT_IN_COUNT];
|
||||
extern usb_endpoint_in_lut_t usb_endpoint_interface_lut[TOTAL_INTERFACES];
|
||||
|
||||
void usb_set_report(usb_fs_report_t **reports, const uint8_t *data, size_t length) {
|
||||
if (*reports == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
(*reports)->last_report = chVTGetSystemTimeX();
|
||||
(*reports)->length = length;
|
||||
memcpy(&(*reports)->data, data, length);
|
||||
}
|
||||
|
||||
void usb_get_report(usb_fs_report_t **reports, uint8_t report_id, usb_fs_report_t *report) {
|
||||
(void)report_id;
|
||||
if (*reports == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
report->length = (*reports)->length;
|
||||
memcpy(&report->data, &(*reports)->data, report->length);
|
||||
}
|
||||
|
||||
void usb_reset_report(usb_fs_report_t **reports) {
|
||||
if (*reports == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&(*reports)->data, 0, (*reports)->length);
|
||||
(*reports)->idle_rate = 0;
|
||||
(*reports)->last_report = 0;
|
||||
}
|
||||
|
||||
void usb_shared_set_report(usb_fs_report_t **reports, const uint8_t *data, size_t length) {
|
||||
uint8_t report_id = data[0];
|
||||
|
||||
if (report_id > REPORT_ID_COUNT || reports[report_id] == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
reports[report_id]->last_report = chVTGetSystemTimeX();
|
||||
reports[report_id]->length = length;
|
||||
memcpy(&reports[report_id]->data, data, length);
|
||||
}
|
||||
|
||||
void usb_shared_get_report(usb_fs_report_t **reports, uint8_t report_id, usb_fs_report_t *report) {
|
||||
if (report_id > REPORT_ID_COUNT || reports[report_id] == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
report->length = reports[report_id]->length;
|
||||
memcpy(&report->data, &reports[report_id]->data, report->length);
|
||||
}
|
||||
|
||||
void usb_shared_reset_report(usb_fs_report_t **reports) {
|
||||
for (int i = 0; i <= REPORT_ID_COUNT; i++) {
|
||||
if (reports[i] == NULL) {
|
||||
continue;
|
||||
}
|
||||
memset(&reports[i]->data, 0, reports[i]->length);
|
||||
reports[i]->idle_rate = 0;
|
||||
reports[i]->last_report = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool usb_get_report_cb(USBDriver *driver) {
|
||||
usb_control_request_t *setup = (usb_control_request_t *)driver->setup;
|
||||
uint8_t interface = setup->wIndex;
|
||||
uint8_t report_id = setup->wValue.lbyte;
|
||||
|
||||
static usb_fs_report_t report;
|
||||
|
||||
if (!IS_VALID_INTERFACE(interface) || !IS_VALID_REPORT_ID(report_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
usb_endpoint_in_lut_t ep = usb_endpoint_interface_lut[interface];
|
||||
|
||||
if (!IS_VALID_USB_ENDPOINT_IN_LUT(ep)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
usb_report_storage_t *report_storage = usb_endpoints_in[ep].report_storage;
|
||||
|
||||
if (report_storage == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
report_storage->get_report(report_storage->reports, report_id, &report);
|
||||
|
||||
usbSetupTransfer(driver, (uint8_t *)report.data, report.length, NULL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool run_idle_task = false;
|
||||
|
||||
void usb_set_idle_rate(usb_fs_report_t **reports, uint8_t report_id, uint8_t idle_rate) {
|
||||
(void)report_id;
|
||||
|
||||
if (*reports == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
(*reports)->idle_rate = idle_rate * 4;
|
||||
|
||||
run_idle_task |= idle_rate != 0;
|
||||
}
|
||||
|
||||
uint8_t usb_get_idle_rate(usb_fs_report_t **reports, uint8_t report_id) {
|
||||
(void)report_id;
|
||||
|
||||
if (*reports == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (*reports)->idle_rate / 4;
|
||||
}
|
||||
|
||||
bool usb_idle_timer_elapsed(usb_fs_report_t **reports, uint8_t report_id) {
|
||||
(void)report_id;
|
||||
|
||||
if (*reports == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
osalSysLock();
|
||||
time_msecs_t idle_rate = (*reports)->idle_rate;
|
||||
systime_t last_report = (*reports)->last_report;
|
||||
osalSysUnlock();
|
||||
|
||||
if (idle_rate == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return chTimeI2MS(chVTTimeElapsedSinceX(last_report)) >= idle_rate;
|
||||
}
|
||||
|
||||
void usb_shared_set_idle_rate(usb_fs_report_t **reports, uint8_t report_id, uint8_t idle_rate) {
|
||||
// USB spec demands that a report_id of 0 would set the idle rate for all
|
||||
// reports of that endpoint, but this can easily lead to resource
|
||||
// exhaustion, therefore we deliberalty break the spec at this point.
|
||||
if (report_id == 0 || report_id > REPORT_ID_COUNT || reports[report_id] == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
reports[report_id]->idle_rate = idle_rate * 4;
|
||||
|
||||
run_idle_task |= idle_rate != 0;
|
||||
}
|
||||
|
||||
uint8_t usb_shared_get_idle_rate(usb_fs_report_t **reports, uint8_t report_id) {
|
||||
if (report_id > REPORT_ID_COUNT || reports[report_id] == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return reports[report_id]->idle_rate / 4;
|
||||
}
|
||||
|
||||
bool usb_shared_idle_timer_elapsed(usb_fs_report_t **reports, uint8_t report_id) {
|
||||
if (report_id > REPORT_ID_COUNT || reports[report_id] == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
osalSysLock();
|
||||
time_msecs_t idle_rate = reports[report_id]->idle_rate;
|
||||
systime_t last_report = reports[report_id]->last_report;
|
||||
osalSysUnlock();
|
||||
|
||||
if (idle_rate == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return chTimeI2MS(chVTTimeElapsedSinceX(last_report)) >= idle_rate;
|
||||
}
|
||||
|
||||
void usb_idle_task(void) {
|
||||
if (!run_idle_task) {
|
||||
return;
|
||||
}
|
||||
|
||||
static usb_fs_report_t report;
|
||||
bool non_zero_idle_rate_found = false;
|
||||
|
||||
for (int ep = 0; ep < USB_ENDPOINT_IN_COUNT; ep++) {
|
||||
usb_report_storage_t *report_storage = usb_endpoints_in[ep].report_storage;
|
||||
|
||||
if (report_storage == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
#if defined(SHARED_EP_ENABLE)
|
||||
if (ep == USB_ENDPOINT_IN_SHARED) {
|
||||
for (int report_id = 1; report_id <= REPORT_ID_COUNT; report_id++) {
|
||||
osalSysLock();
|
||||
non_zero_idle_rate_found |= report_storage->get_idle(report_storage->reports, report_id) != 0;
|
||||
osalSysUnlock();
|
||||
|
||||
if (usb_endpoint_in_is_inactive(&usb_endpoints_in[ep]) && report_storage->idle_timer_elasped(report_storage->reports, report_id)) {
|
||||
osalSysLock();
|
||||
report_storage->get_report(report_storage->reports, report_id, &report);
|
||||
osalSysUnlock();
|
||||
send_report(ep, &report.data, report.length);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
osalSysLock();
|
||||
non_zero_idle_rate_found |= report_storage->get_idle(report_storage->reports, 0) != 0;
|
||||
osalSysUnlock();
|
||||
|
||||
if (usb_endpoint_in_is_inactive(&usb_endpoints_in[ep]) && report_storage->idle_timer_elasped(report_storage->reports, 0)) {
|
||||
osalSysLock();
|
||||
report_storage->get_report(report_storage->reports, 0, &report);
|
||||
osalSysUnlock();
|
||||
send_report(ep, &report.data, report.length);
|
||||
}
|
||||
}
|
||||
|
||||
run_idle_task = non_zero_idle_rate_found;
|
||||
}
|
||||
|
||||
bool usb_get_idle_cb(USBDriver *driver) {
|
||||
usb_control_request_t *setup = (usb_control_request_t *)driver->setup;
|
||||
uint8_t interface = setup->wIndex;
|
||||
uint8_t report_id = setup->wValue.lbyte;
|
||||
|
||||
static uint8_t _Alignas(4) idle_rate;
|
||||
|
||||
if (!IS_VALID_INTERFACE(interface) || !IS_VALID_REPORT_ID(report_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
usb_endpoint_in_lut_t ep = usb_endpoint_interface_lut[interface];
|
||||
|
||||
if (!IS_VALID_USB_ENDPOINT_IN_LUT(ep)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
usb_report_storage_t *report_storage = usb_endpoints_in[ep].report_storage;
|
||||
|
||||
if (report_storage == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
idle_rate = report_storage->get_idle(report_storage->reports, report_id);
|
||||
|
||||
usbSetupTransfer(driver, &idle_rate, 1, NULL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool usb_set_idle_cb(USBDriver *driver) {
|
||||
usb_control_request_t *setup = (usb_control_request_t *)driver->setup;
|
||||
uint8_t interface = setup->wIndex;
|
||||
uint8_t report_id = setup->wValue.lbyte;
|
||||
uint8_t idle_rate = setup->wValue.hbyte;
|
||||
|
||||
if (!IS_VALID_INTERFACE(interface) || !IS_VALID_REPORT_ID(report_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
usb_endpoint_in_lut_t ep = usb_endpoint_interface_lut[interface];
|
||||
|
||||
if (!IS_VALID_USB_ENDPOINT_IN_LUT(ep)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
usb_report_storage_t *report_storage = usb_endpoints_in[ep].report_storage;
|
||||
|
||||
if (report_storage == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
report_storage->set_idle(report_storage->reports, report_id, idle_rate);
|
||||
|
||||
usbSetupTransfer(driver, NULL, 0, NULL);
|
||||
|
||||
return true;
|
||||
}
|
77
tmk_core/protocol/chibios/usb_report_handling.h
Normal file
77
tmk_core/protocol/chibios/usb_report_handling.h
Normal file
@ -0,0 +1,77 @@
|
||||
// Copyright 2023 Stefan Kerkmann (@KarlK90)
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ch.h>
|
||||
#include <hal.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "timer.h"
|
||||
|
||||
typedef struct {
|
||||
time_msecs_t idle_rate;
|
||||
systime_t last_report;
|
||||
uint8_t data[64];
|
||||
size_t length;
|
||||
} usb_fs_report_t;
|
||||
|
||||
typedef struct {
|
||||
usb_fs_report_t **reports;
|
||||
const void (*get_report)(usb_fs_report_t **, uint8_t, usb_fs_report_t *);
|
||||
const void (*set_report)(usb_fs_report_t **, const uint8_t *, size_t);
|
||||
const void (*reset_report)(usb_fs_report_t **);
|
||||
const void (*set_idle)(usb_fs_report_t **, uint8_t, uint8_t);
|
||||
const uint8_t (*get_idle)(usb_fs_report_t **, uint8_t);
|
||||
const bool (*idle_timer_elasped)(usb_fs_report_t **, uint8_t);
|
||||
} usb_report_storage_t;
|
||||
|
||||
#define QMK_USB_REPORT_STROAGE_ENTRY(_report_id, _report_size) [_report_id] = &((usb_fs_report_t){.data = {[0] = _report_id}, .length = _report_size})
|
||||
|
||||
#define QMK_USB_REPORT_STORAGE(_get_report, _set_report, _reset_report, _get_idle, _set_idle, _idle_timer_elasped, _report_count, _reports...) \
|
||||
&((usb_report_storage_t){ \
|
||||
.reports = (_Alignas(4) usb_fs_report_t *[_report_count]){_reports}, \
|
||||
.get_report = _get_report, \
|
||||
.set_report = _set_report, \
|
||||
.reset_report = _reset_report, \
|
||||
.get_idle = _get_idle, \
|
||||
.set_idle = _set_idle, \
|
||||
.idle_timer_elasped = _idle_timer_elasped, \
|
||||
})
|
||||
|
||||
#define QMK_USB_REPORT_STORAGE_DEFAULT(_report_length) \
|
||||
QMK_USB_REPORT_STORAGE(&usb_get_report, /* _get_report */ \
|
||||
&usb_set_report, /* _set_report */ \
|
||||
&usb_reset_report, /* _reset_report */ \
|
||||
&usb_get_idle_rate, /* _get_idle */ \
|
||||
&usb_set_idle_rate, /* _set_idle */ \
|
||||
&usb_idle_timer_elapsed, /* _idle_timer_elasped */ \
|
||||
1, /* _report_count */ \
|
||||
QMK_USB_REPORT_STROAGE_ENTRY(0, _report_length))
|
||||
|
||||
// USB HID SET_REPORT and GET_REPORT handling functions
|
||||
void usb_set_report(usb_fs_report_t **reports, const uint8_t *data, size_t length);
|
||||
void usb_shared_set_report(usb_fs_report_t **reports, const uint8_t *data, size_t length);
|
||||
|
||||
void usb_get_report(usb_fs_report_t **reports, uint8_t report_id, usb_fs_report_t *report);
|
||||
void usb_shared_get_report(usb_fs_report_t **reports, uint8_t report_id, usb_fs_report_t *report);
|
||||
|
||||
void usb_reset_report(usb_fs_report_t **reports);
|
||||
void usb_shared_reset_report(usb_fs_report_t **reports);
|
||||
|
||||
bool usb_get_report_cb(USBDriver *driver);
|
||||
|
||||
// USB HID SET_IDLE and GET_IDLE handling functions
|
||||
void usb_idle_task(void);
|
||||
|
||||
void usb_set_idle_rate(usb_fs_report_t **timers, uint8_t report_id, uint8_t idle_rate);
|
||||
void usb_shared_set_idle_rate(usb_fs_report_t **timers, uint8_t report_id, uint8_t idle_rate);
|
||||
|
||||
uint8_t usb_get_idle_rate(usb_fs_report_t **timers, uint8_t report_id);
|
||||
uint8_t usb_shared_get_idle_rate(usb_fs_report_t **timers, uint8_t report_id);
|
||||
|
||||
bool usb_idle_timer_elapsed(usb_fs_report_t **timers, uint8_t report_id);
|
||||
bool usb_shared_idle_timer_elapsed(usb_fs_report_t **timers, uint8_t report_id);
|
||||
|
||||
bool usb_get_idle_cb(USBDriver *driver);
|
||||
bool usb_set_idle_cb(USBDriver *driver);
|
@ -29,7 +29,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
// clang-format off
|
||||
|
||||
/* HID report IDs */
|
||||
enum hid_report_ids {
|
||||
enum hid_report_ids {
|
||||
REPORT_ID_ALL = 0,
|
||||
REPORT_ID_KEYBOARD = 1,
|
||||
REPORT_ID_MOUSE,
|
||||
REPORT_ID_SYSTEM,
|
||||
@ -37,9 +38,12 @@ enum hid_report_ids {
|
||||
REPORT_ID_PROGRAMMABLE_BUTTON,
|
||||
REPORT_ID_NKRO,
|
||||
REPORT_ID_JOYSTICK,
|
||||
REPORT_ID_DIGITIZER
|
||||
REPORT_ID_DIGITIZER,
|
||||
REPORT_ID_COUNT = REPORT_ID_DIGITIZER
|
||||
};
|
||||
|
||||
#define IS_VALID_REPORT_ID(id) ((id) >= REPORT_ID_ALL && (id) <= REPORT_ID_COUNT)
|
||||
|
||||
/* Mouse buttons */
|
||||
#define MOUSE_BTN_MASK(n) (1 << (n))
|
||||
enum mouse_buttons {
|
||||
|
@ -196,6 +196,8 @@ enum usb_interfaces {
|
||||
TOTAL_INTERFACES
|
||||
};
|
||||
|
||||
#define IS_VALID_INTERFACE(i) ((i) >= 0 && (i) < TOTAL_INTERFACES)
|
||||
|
||||
#define NEXT_EPNUM __COUNTER__
|
||||
|
||||
/*
|
||||
|
Loading…
x
Reference in New Issue
Block a user