From f01b05bf5eef2c6cdcdd12899c9cb25e0b0e892a Mon Sep 17 00:00:00 2001 From: Taylor Yu Date: Fri, 11 Nov 2022 20:00:05 -0600 Subject: [PATCH] send at least ZLP on successful control read The KeyboardioHID library implicitly relied on underdocumented behavior of the AVR USB core to always send at least a zero-length packet for successful control read transfers. GD32 was timing out these transfers instead. Signed-off-by: Taylor Yu --- cores/arduino/USBCore.cpp | 11 +++++++++++ cores/arduino/USBCore.h | 2 ++ 2 files changed, 13 insertions(+) diff --git a/cores/arduino/USBCore.cpp b/cores/arduino/USBCore.cpp index 948c01c3..de4452a0 100644 --- a/cores/arduino/USBCore.cpp +++ b/cores/arduino/USBCore.cpp @@ -563,6 +563,10 @@ int USBCore_::sendControl(uint8_t flags, const void* data, int len) this->flush(0); } + if (wrote != 0) { + this->controlWritten = true; + } + // Return ‘len’, rather than ‘wrote’, because PluggableUSB // calculates descriptor sizes by first having them write to an // empty buffer (setting ‘this->maxWrite’ to 0). To accomodate @@ -734,6 +738,7 @@ usb_dev& USBCore_::usbDev() void USBCore_::transcSetup(usb_dev* usbd, uint8_t ep) { (void)ep; + this->controlWritten = false; usb_reqsta reqstat = REQ_NOTSUPP; @@ -764,6 +769,9 @@ void USBCore_::transcSetup(usb_dev* usbd, uint8_t ep) if (reqstat == REQ_SUPP) { if ((usbd->control.req.bmRequestType & USB_TRX_IN) != USB_TRX_IN) { this->sendZLP(usbd, 0); + } else if (!this->controlWritten) { + // Send at least a ZLP if nothing was written, to avoid timeouts + this->sendZLP(usbd, 0); } } else { usbd_ep_stall(usbd, 0); @@ -784,6 +792,9 @@ void USBCore_::transcSetup(usb_dev* usbd, uint8_t ep) if (reqstat == REQ_SUPP) { if ((usbd->control.req.bmRequestType & USB_TRX_IN) != USB_TRX_IN) { this->sendZLP(usbd, 0); + } else if (!this->controlWritten) { + // Send at least a ZLP if nothing was written, to avoid timeouts + this->sendZLP(usbd, 0); } } else { usbd_ep_stall(usbd, 0); diff --git a/cores/arduino/USBCore.h b/cores/arduino/USBCore.h index 1d7b1747..cccb2931 100644 --- a/cores/arduino/USBCore.h +++ b/cores/arduino/USBCore.h @@ -183,6 +183,8 @@ class USBCore_ // TODO: verify that this only applies to the control endpoint’s use of wLength // I think this is only on the setup packet, so it should be fine. uint16_t maxWrite = 0; + // Whether a control write has occurred during a control transaction + bool controlWritten; /* * Pointers to the transaction routines specified by ‘usbd_init’.