Fix ChibiOS control OUT buffer sizing. (#26570)

* Fix ChibiOS control OUT buffer sizing.

Some ChibiOS low level drivers (STM32 USBv1, WB32, Kinetis) write a whole control packet into the EP0 OUT buffer rather than only the requested length, so the buffer must hold a full packet. SET_REPORT and SET_LINE_CODING now share one packet-sized buffer, and line coding is copied out on transfer completion so a short data stage cannot leave it partly overwritten.

* Use exact size.

* Recover some RAM on failing builds.
This commit is contained in:
Nick Brassel
2026-11-12 12:28:13 +11:00
committed by GitHub
parent d194c077ed
commit ec8a1b6549
3 changed files with 14 additions and 10 deletions
-2
View File
@@ -53,8 +53,6 @@
"pixel_fractal": true,
"pixel_flow": true,
"pixel_rain": true,
"typing_heatmap": true,
"digital_rain": true,
"solid_reactive_simple": true,
"solid_reactive": true,
"solid_reactive_wide": true,
+1 -2
View File
@@ -38,8 +38,7 @@
"christmas": true,
"static_gradient": true,
"rgb_test": true,
"alternating": true,
"twinkle": true
"alternating": true
}
},
"processor": "STM32F042",
+13 -6
View File
@@ -231,18 +231,18 @@ static void usb_event_cb(USBDriver *usbp, usbevent_t event) {
* Other Device Required Optional Optional Optional Optional Optional
*/
static uint8_t _Alignas(4) set_report_buf[2];
static uint8_t _Alignas(4) control_out_buf[FIXED_CONTROL_ENDPOINT_SIZE]; // Some low level drivers copy a whole control packet regardless of the requested transfer size. Shared by all EP0 OUT handlers; ChibiOS runs one control transfer at a time.
static void set_led_transfer_cb(USBDriver *usbp) {
usb_control_request_t *setup = (usb_control_request_t *)usbp->setup;
if (setup->wLength == 2) {
uint8_t report_id = set_report_buf[0];
uint8_t report_id = control_out_buf[0];
if ((report_id == REPORT_ID_KEYBOARD) || (report_id == REPORT_ID_NKRO)) {
usb_device_state_set_leds(set_report_buf[1]);
usb_device_state_set_leds(control_out_buf[1]);
}
} else {
usb_device_state_set_leds(set_report_buf[0]);
usb_device_state_set_leds(control_out_buf[0]);
}
}
@@ -277,7 +277,7 @@ static bool usb_requests_hook_cb(USBDriver *usbp) {
#if defined(SHARED_EP_ENABLE) && !defined(KEYBOARD_SHARED_EP)
case SHARED_INTERFACE:
#endif
usbSetupTransfer(usbp, set_report_buf, sizeof(set_report_buf), set_led_transfer_cb);
usbSetupTransfer(usbp, control_out_buf, 2, set_led_transfer_cb);
return true;
}
break;
@@ -549,6 +549,13 @@ bool recv_midi_packet(MIDI_EventPacket_t *const event) {
*/
static cdc_linecoding_t linecoding = {{0x00, 0x96, 0x00, 0x00}, LC_STOP_1, LC_PARITY_NONE, 8};
static void set_line_coding_transfer_cb(USBDriver *usbp) {
if (usbGetReceiveTransactionSizeX(usbp, 0) != sizeof(linecoding)) {
return;
}
memcpy(&linecoding, control_out_buf, sizeof(linecoding));
}
bool virtser_usb_request_cb(USBDriver *usbp) {
if ((usbp->setup[0] & USB_RTYPE_TYPE_MASK) == USB_RTYPE_TYPE_CLASS) { /* bmRequestType */
if (usbp->setup[4] == CCI_INTERFACE) { /* wIndex (LSB) */
@@ -557,7 +564,7 @@ bool virtser_usb_request_cb(USBDriver *usbp) {
usbSetupTransfer(usbp, (uint8_t *)&linecoding, sizeof(linecoding), NULL);
return true;
case CDC_SET_LINE_CODING:
usbSetupTransfer(usbp, (uint8_t *)&linecoding, sizeof(linecoding), NULL);
usbSetupTransfer(usbp, control_out_buf, sizeof(linecoding), set_line_coding_transfer_cb);
return true;
case CDC_SET_CONTROL_LINE_STATE:
/* Nothing to do, there are no control lines.*/