From 13b4f8de2cb2354e6a3a5cddf4c88885c272d5a1 Mon Sep 17 00:00:00 2001 From: Koen Zandberg Date: Sun, 31 Oct 2021 21:16:52 +0100 Subject: [PATCH] usbus: Implement endpoint halt condition. Instead of directly stalling an endpoint, handlers should enable the halt condition on an usbus endpoint to signal error condition. This can then be cleared via a CLEAR FEATURE request from the host. --- sys/include/usb/usbus.h | 17 +++++++++++++++++ sys/usb/usbus/usbus.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/sys/include/usb/usbus.h b/sys/include/usb/usbus.h index 3a46575012..ad0bb06b81 100644 --- a/sys/include/usb/usbus.h +++ b/sys/include/usb/usbus.h @@ -327,6 +327,7 @@ typedef struct usbus_endpoint { uint8_t interval; /**< Poll interval for interrupt endpoints */ bool active; /**< If the endpoint should be activated after reset */ + bool halted; /**< Endpoint is halted */ } usbus_endpoint_t; /** @@ -676,6 +677,22 @@ void usbus_urb_submit(usbus_t *usbus, usbus_endpoint_t *endpoint, usbus_urb_t *u */ int usbus_urb_cancel(usbus_t *usbus, usbus_endpoint_t *endpoint, usbus_urb_t *urb); +/** + * @brief Set the halt condition on an endpoint. + * + * The endpoint will respond with stall to all packets and must explicitly be + * cleared by the host by clearing the halt condition or switching interfaces + */ +void usbus_endpoint_halt(usbus_endpoint_t *ep); + +/** + * @brief Clear the halt condition on an endpoint + * + * @note Must only be used when the endpoint is halted and when the host issues + * a SetInterface request on the interface containing the endpoint + */ +void usbus_endpoint_clear_halt(usbus_endpoint_t *ep); + /** * @brief Enable an endpoint * diff --git a/sys/usb/usbus/usbus.c b/sys/usb/usbus/usbus.c index abba08e809..77bdf906c3 100644 --- a/sys/usb/usbus/usbus.c +++ b/sys/usb/usbus/usbus.c @@ -470,6 +470,34 @@ static void *_usbus_thread(void *args) return NULL; } +void usbus_endpoint_halt(usbus_endpoint_t *ep) +{ + assert(ep->ep->num != 0); /* Not valid for endpoint 0 */ + DEBUG("Endpoint %u halted\n", ep->ep->num); + ep->halted = 1; + usbdev_ep_stall(ep->ep, true); +} + +void usbus_endpoint_clear_halt(usbus_endpoint_t *ep) +{ + assert(ep->ep->num != 0); /* Not valid for endpoint 0 */ + DEBUG("Endpoint %u unhalted\n", ep->ep->num); + ep->halted = 0; + usbdev_ep_stall(ep->ep, false); +} + +/** + * @brief Reset the halted status on USB reset condition + */ +static void _usbus_endpoint_reset_halt(usbus_t *usbus) +{ + /* Clear halted state. No need to notify usbdev, USB reset already resets those */ + for (size_t i = 0; i < USBDEV_NUM_ENDPOINTS; i++) { + usbus->ep_out[i].halted = 0; + usbus->ep_in[i].halted = 0; + } +} + /* USB event callback */ static void _event_cb(usbdev_t *usbdev, usbdev_event_t event) { @@ -487,6 +515,7 @@ static void _event_cb(usbdev_t *usbdev, usbdev_event_t event) usbus->addr = 0; usbdev_set(usbus->dev, USBOPT_ADDRESS, &usbus->addr, sizeof(uint8_t)); + _usbus_endpoint_reset_halt(usbus); flag = USBUS_HANDLER_FLAG_RESET; msg = USBUS_EVENT_USB_RESET; DEBUG("usbus: USB reset detected\n");