git: c6203b6c00ca - stable/13 - usb(4): Call optional endpoint_uninit() when changing configuration or alternate setting.
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sun, 30 Apr 2023 06:57:49 UTC
The branch stable/13 has been updated by hselasky: URL: https://cgit.FreeBSD.org/src/commit/?id=c6203b6c00ca87a182a8a81d372ade0dc3e1f5f5 commit c6203b6c00ca87a182a8a81d372ade0dc3e1f5f5 Author: Hans Petter Selasky <hselasky@FreeBSD.org> AuthorDate: 2022-12-15 22:32:47 +0000 Commit: Hans Petter Selasky <hselasky@FreeBSD.org> CommitDate: 2023-04-30 06:56:16 +0000 usb(4): Call optional endpoint_uninit() when changing configuration or alternate setting. Sponsored by: NVIDIA Networking (cherry picked from commit e4611d26265fb9e3bd2a345cf4776863f49a2587) --- sys/dev/usb/usb_device.c | 55 ++++++++++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/sys/dev/usb/usb_device.c b/sys/dev/usb/usb_device.c index b5e51cbdc7a7..392d969587c0 100644 --- a/sys/dev/usb/usb_device.c +++ b/sys/dev/usb/usb_device.c @@ -841,38 +841,53 @@ usb_config_parse(struct usb_device *udev, uint8_t iface_index, uint8_t cmd) DPRINTFN(5, "iface_index=%d cmd=%d\n", iface_index, cmd); - if (cmd == USB_CFG_FREE) - goto cleanup; - - if (cmd == USB_CFG_INIT) { + if (cmd == USB_CFG_INIT || cmd == USB_CFG_FREE) { sx_assert(&udev->enum_sx, SA_LOCKED); /* check for in-use endpoints */ + if (cmd == USB_CFG_INIT) { + ep = udev->endpoints; + ep_max = udev->endpoints_max; + while (ep_max--) { + /* look for matching endpoints */ + if (iface_index == USB_IFACE_INDEX_ANY || + iface_index == ep->iface_index) { + if (ep->refcount_alloc != 0) + return (USB_ERR_IN_USE); + } + } + } + ep = udev->endpoints; ep_max = udev->endpoints_max; while (ep_max--) { /* look for matching endpoints */ - if ((iface_index == USB_IFACE_INDEX_ANY) || - (iface_index == ep->iface_index)) { - if (ep->refcount_alloc != 0) { - /* - * This typically indicates a - * more serious error. - */ - err = USB_ERR_IN_USE; - } else { - /* reset endpoint */ - memset(ep, 0, sizeof(*ep)); - /* make sure we don't zero the endpoint again */ - ep->iface_index = USB_IFACE_INDEX_ANY; - } + if (iface_index == USB_IFACE_INDEX_ANY || + iface_index == ep->iface_index) { + /* + * Check if hardware needs a callback + * to unconfigure the endpoint. This + * may happen multiple times, + * because the requested alternate + * setting may fail. The callback + * implementation should be aware of + * and handle that. + */ + if (ep->edesc != NULL && + udev->bus->methods->endpoint_uninit != NULL) + udev->bus->methods->endpoint_uninit(udev, ep); + + /* reset endpoint */ + memset(ep, 0, sizeof(*ep)); + /* make sure we don't zero the endpoint again */ + ep->iface_index = USB_IFACE_INDEX_ANY; } ep++; } - if (err) - return (err); + if (cmd == USB_CFG_FREE) + goto cleanup; } memset(&ips, 0, sizeof(ips));