From 5ba44ffd3e0e280ef61b9dbc38b7e5f2ce3ff4c2 Mon Sep 17 00:00:00 2001 From: Johann Fischer Date: Thu, 5 Jun 2025 15:35:38 +0200 Subject: [PATCH] usb: host: allow status stage to be omitted For testing purposes, allow the status stage to be omitted. Signed-off-by: Johann Fischer --- drivers/usb/uhc/uhc_virtual.c | 10 +++++++--- include/zephyr/drivers/usb/uhc.h | 5 +++++ subsys/usb/host/usbh_ch9.c | 10 ++++++++++ subsys/usb/host/usbh_ch9.h | 6 ++++++ 4 files changed, 28 insertions(+), 3 deletions(-) diff --git a/drivers/usb/uhc/uhc_virtual.c b/drivers/usb/uhc/uhc_virtual.c index c582cfe1e7a..9210e240112 100644 --- a/drivers/usb/uhc/uhc_virtual.c +++ b/drivers/usb/uhc/uhc_virtual.c @@ -295,7 +295,11 @@ static void vrt_hrslt_success(const struct device *dev, if (xfer->buf != NULL) { xfer->stage = UHC_CONTROL_STAGE_DATA; } else { - xfer->stage = UHC_CONTROL_STAGE_STATUS; + if (xfer->no_status) { + finished = true; + } else { + xfer->stage = UHC_CONTROL_STAGE_STATUS; + } } break; @@ -311,7 +315,7 @@ static void vrt_hrslt_success(const struct device *dev, net_buf_pull(buf, length); LOG_DBG("OUT chunk %zu out of %u", length, buf->len); if (buf->len == 0) { - if (pkt->ep == USB_CONTROL_EP_OUT) { + if (pkt->ep == USB_CONTROL_EP_OUT && !xfer->no_status) { xfer->stage = UHC_CONTROL_STAGE_STATUS; } else { finished = true; @@ -327,7 +331,7 @@ static void vrt_hrslt_success(const struct device *dev, LOG_DBG("IN chunk %zu out of %zu", length, net_buf_tailroom(buf)); if (pkt->length < xfer->mps || !net_buf_tailroom(buf)) { - if (pkt->ep == USB_CONTROL_EP_IN) { + if (pkt->ep == USB_CONTROL_EP_IN && !xfer->no_status) { xfer->stage = UHC_CONTROL_STAGE_STATUS; } else { finished = true; diff --git a/include/zephyr/drivers/usb/uhc.h b/include/zephyr/drivers/usb/uhc.h index f7e357854e8..b15afbf845e 100644 --- a/include/zephyr/drivers/usb/uhc.h +++ b/include/zephyr/drivers/usb/uhc.h @@ -130,6 +130,11 @@ struct uhc_transfer { unsigned int queued : 1; /** Control stage status, up to the driver to use it or not */ unsigned int stage : 2; + /** + * The status stage of the control transfer will be omitted. + * This flag is optional and is mainly used for testing. + */ + unsigned int no_status : 1; /** Pointer to USB device */ struct usb_device *udev; /** Pointer to transfer completion callback (opaque for the UHC) */ diff --git a/subsys/usb/host/usbh_ch9.c b/subsys/usb/host/usbh_ch9.c index 29b01ea1624..d22f8f5d082 100644 --- a/subsys/usb/host/usbh_ch9.c +++ b/subsys/usb/host/usbh_ch9.c @@ -25,6 +25,7 @@ LOG_MODULE_REGISTER(usbh_ch9, CONFIG_USBH_LOG_LEVEL); #define SETUP_REQ_TIMEOUT 5000U K_SEM_DEFINE(ch9_req_sync, 0, 1); +static bool ctrl_req_no_status; static int ch9_req_cb(struct usb_device *const udev, struct uhc_transfer *const xfer) { @@ -41,6 +42,11 @@ static int ch9_req_cb(struct usb_device *const udev, struct uhc_transfer *const return 0; } +void usbh_req_omit_status(const bool omit) +{ + ctrl_req_no_status = omit; +} + int usbh_req_setup(struct usb_device *const udev, const uint8_t bmRequestType, const uint8_t bRequest, @@ -76,6 +82,10 @@ int usbh_req_setup(struct usb_device *const udev, } } + if (IS_ENABLED(CONFIG_ZTEST) && ctrl_req_no_status) { + xfer->no_status = true; + } + ret = usbh_xfer_enqueue(udev, xfer); if (ret) { goto buf_alloc_err; diff --git a/subsys/usb/host/usbh_ch9.h b/subsys/usb/host/usbh_ch9.h index 9e585c8dab6..19879dae6e2 100644 --- a/subsys/usb/host/usbh_ch9.h +++ b/subsys/usb/host/usbh_ch9.h @@ -12,6 +12,12 @@ #include "usbh_device.h" +/* + * Mainly used for testing, and driver support is optional. Use it to + * enable or disable omitting the status stage for all requests. + */ +void usbh_req_omit_status(const bool omit); + int usbh_req_setup(struct usb_device *const udev, const uint8_t bmRequestType, const uint8_t bRequest,