From 6d387e2e7f1a2021b65fe8ff44d29d72f898dec8 Mon Sep 17 00:00:00 2001 From: mojyack Date: Fri, 19 Dec 2025 21:09:03 +0900 Subject: [PATCH] usb: allow class drivers to override max packet size this is required to make hid endpoint of iap class driver work, especially on ipodvideo(arc). at least for arc, it is required to set mps as 64 instead of 512 on highspeed, or some accessories ignore incoming hid reports. Change-Id: I242060faced28a66204146a9c36ef10626d6d265 --- firmware/usbstack/usb_class_driver.h | 5 +++++ firmware/usbstack/usb_core.c | 20 +++++++++++++------- firmware/usbstack/usb_iap.c | 10 ++++++++++ firmware/usbstack/usb_iap.h | 1 + 4 files changed, 29 insertions(+), 7 deletions(-) diff --git a/firmware/usbstack/usb_class_driver.h b/firmware/usbstack/usb_class_driver.h index f26324fe20..dc19c31ad5 100644 --- a/firmware/usbstack/usb_class_driver.h +++ b/firmware/usbstack/usb_class_driver.h @@ -119,6 +119,11 @@ struct usb_class_driver { * Mandatory function if alternate interface support is needed */ int (*get_interface)(int interface); + /* Asks the driver max packet size for the endpoint. + * Drivers can returns desired value in bytes, + * or -1 to use the device controller default */ + int (*get_max_packet_size)(int ep); + /* Invoked by USB_NOTIFY_CLASS_DRIVER Optional function */ void (*notify_event)(intptr_t data); diff --git a/firmware/usbstack/usb_core.c b/firmware/usbstack/usb_core.c index 2a10c36c7e..f6b48a3185 100644 --- a/firmware/usbstack/usb_core.c +++ b/firmware/usbstack/usb_core.c @@ -333,6 +333,7 @@ static struct usb_class_driver drivers[USB_NUM_DRIVERS] = #endif .set_interface = usb_iap_set_interface, .get_interface = usb_iap_get_interface, + .get_max_packet_size = usb_iap_get_max_packet_size, .notify_event = usb_iap_notify_event, }, #endif @@ -661,21 +662,26 @@ static void init_deinit_endpoints(uint8_t conf_index, bool init) { for(int epnum = 0; epnum < USB_NUM_ENDPOINTS; epnum += 1) { for(int dir = 0; dir < 2; dir += 1) { struct ep_alloc_state* alloc = &ep_alloc_states[conf_index][epnum]; - if(alloc->owner[dir] == NULL) { + struct usb_class_driver* driver = alloc->owner[dir]; + if(driver == NULL) { continue; } int ep = epnum | (dir == DIR_OUT ? USB_DIR_OUT : USB_DIR_IN); - int ret = init ? - usb_drv_init_endpoint(ep, alloc->type[dir], -1) : - usb_drv_deinit_endpoint(ep); + int ret; + if(init) { + int ps = driver->get_max_packet_size ? driver->get_max_packet_size(ep) : -1; + ret = usb_drv_init_endpoint(ep, alloc->type[dir], ps); + } else { + ret = usb_drv_deinit_endpoint(ep); + } if(ret) { logf("usb_core: usb_drv_%s_endpoint failed ep=%d dir=%d", init ? "init" : "deinit", epnum, dir); continue; } if(init) { - ep_data[epnum].completion_handler[dir] = alloc->owner[dir]->transfer_complete; - ep_data[epnum].fast_completion_handler[dir] = alloc->owner[dir]->fast_transfer_complete; - ep_data[epnum].control_handler[dir] = alloc->owner[dir]->control_request; + ep_data[epnum].completion_handler[dir] = driver->transfer_complete; + ep_data[epnum].fast_completion_handler[dir] = driver->fast_transfer_complete; + ep_data[epnum].control_handler[dir] = driver->control_request; } } } diff --git a/firmware/usbstack/usb_iap.c b/firmware/usbstack/usb_iap.c index 3126ec6bc3..6608e12880 100644 --- a/firmware/usbstack/usb_iap.c +++ b/firmware/usbstack/usb_iap.c @@ -441,6 +441,16 @@ int usb_iap_get_interface(int intf) { return stream.alt; } +int usb_iap_get_max_packet_size(int ep) { + if(ep == AS_EP_IN) { + return 1024; + } else if(ep == HID_EP_IN) { + return 64; + } else { + panicf("unexpected endpoint number %d", ep); + } +} + void usb_iap_init(void) { LOG("init"); } diff --git a/firmware/usbstack/usb_iap.h b/firmware/usbstack/usb_iap.h index f807009830..c1990bc8d3 100644 --- a/firmware/usbstack/usb_iap.h +++ b/firmware/usbstack/usb_iap.h @@ -39,4 +39,5 @@ bool usb_iap_fast_transfer_complete(int ep, int dir, int status, int length); bool usb_iap_control_request(struct usb_ctrlrequest* req, void* reqdata, unsigned char* dest); int usb_iap_set_interface(int intf, int alt); int usb_iap_get_interface(int intf); +int usb_iap_get_max_packet_size(int ep); void usb_iap_notify_event(intptr_t data);