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
This commit is contained in:
mojyack 2025-12-19 21:09:03 +09:00 committed by Solomon Peachy
parent fad99773e3
commit 6d387e2e7f
4 changed files with 29 additions and 7 deletions

View file

@ -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);

View file

@ -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;
}
}
}

View file

@ -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");
}

View file

@ -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);