git: e4611d26265f - main - usb(4): Call optional endpoint_uninit() when changing configuration or alternate setting.
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 13 Jan 2023 10:19:30 UTC
The branch main has been updated by hselasky:
URL: https://cgit.FreeBSD.org/src/commit/?id=e4611d26265fb9e3bd2a345cf4776863f49a2587
commit e4611d26265fb9e3bd2a345cf4776863f49a2587
Author: Hans Petter Selasky <hselasky@FreeBSD.org>
AuthorDate: 2022-12-15 22:32:47 +0000
Commit: Hans Petter Selasky <hselasky@FreeBSD.org>
CommitDate: 2023-01-13 10:18:19 +0000
usb(4): Call optional endpoint_uninit() when changing configuration or alternate setting.
MFC after: 1 week
Sponsored by: NVIDIA Networking
---
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));