diff --git a/include/zephyr/usb/usbh.h b/include/zephyr/usb/usbh.h index e2e6f3074000e..748da72b19027 100644 --- a/include/zephyr/usb/usbh.h +++ b/include/zephyr/usb/usbh.h @@ -45,8 +45,6 @@ struct usbh_context { const struct device *dev; /** USB device list */ sys_dlist_t udevs; - /** USB root device */ - struct usb_device *root; /** Allocated device addresses bit array */ struct sys_bitarray *addr_ba; }; diff --git a/subsys/usb/host/usbh_core.c b/subsys/usb/host/usbh_core.c index 1b654b5041133..18d02b9ff0610 100644 --- a/subsys/usb/host/usbh_core.c +++ b/subsys/usb/host/usbh_core.c @@ -46,42 +46,49 @@ static int usbh_event_carrier(const struct device *dev, static void dev_connected_handler(struct usbh_context *const ctx, const struct uhc_event *const event) { + int err; + struct usb_device *udev; LOG_DBG("Device connected event"); - if (ctx->root != NULL) { - LOG_ERR("Device already connected"); - usbh_device_free(ctx->root); - ctx->root = NULL; - } - ctx->root = usbh_device_alloc(ctx); - if (ctx->root == NULL) { + udev = usbh_device_alloc(ctx); + if (udev == NULL) { LOG_ERR("Failed allocate new device"); return; } - ctx->root->state = USB_STATE_DEFAULT; + udev->state = USB_STATE_DEFAULT; if (event->type == UHC_EVT_DEV_CONNECTED_HS) { - ctx->root->speed = USB_SPEED_SPEED_HS; + udev->speed = USB_SPEED_SPEED_HS; } else { - ctx->root->speed = USB_SPEED_SPEED_FS; + udev->speed = USB_SPEED_SPEED_FS; } - if (usbh_device_init(ctx->root)) { + k_mutex_lock(&ctx->mutex, K_FOREVER); + sys_dlist_append(&ctx->udevs, &udev->node); + k_mutex_unlock(&ctx->mutex); + + err = usbh_device_init(udev); + if (ret != 0) { LOG_ERR("Failed to reset new USB device"); + sys_dlist_remove(&udev->node); } } static void dev_removed_handler(struct usbh_context *const ctx) { - if (ctx->root != NULL) { - usbh_device_free(ctx->root); - ctx->root = NULL; + struct usb_device *udev = NULL; + + udev = usbh_device_get_root(ctx); + + if (NULL != udev) { + usbh_device_free(udev); LOG_DBG("Device removed"); } else { LOG_DBG("Spurious device removed event"); } + /* TODO: handle remove for all of classes for the unattached device */ } static int discard_ep_request(struct usbh_context *const ctx, diff --git a/subsys/usb/host/usbh_device.c b/subsys/usb/host/usbh_device.c index 92ecf6ae7aee1..1da536a5d9e42 100644 --- a/subsys/usb/host/usbh_device.c +++ b/subsys/usb/host/usbh_device.c @@ -447,11 +447,33 @@ int usbh_device_set_configuration(struct usb_device *const udev, const uint8_t n return err; } +struct usb_device *usbh_device_get_root(struct usbh_context *const ctx) +{ + sys_dnode_t *node; + + node = sys_dlist_peek_head(&ctx->udevs); + if (node == NULL) { + /* No devices in the list */ + return NULL; + } + + /* Get the usb_device structure from the node */ + return CONTAINER_OF(node, struct usb_device, node); +} + +bool usbh_device_is_root(struct usbh_context *const ctx, + struct usb_device *const udev) +{ + return sys_dlist_peek_head(&ctx->udevs) == &udev->node; +} + int usbh_device_init(struct usb_device *const udev) { struct usbh_context *const uhs_ctx = udev->ctx; uint8_t new_addr; int err; + sys_dnode_t *node; + uint8_t device_count = 0; if (udev->state != USB_STATE_DEFAULT) { LOG_ERR("USB device is not in default state"); @@ -464,11 +486,17 @@ int usbh_device_init(struct usb_device *const udev) return err; } - /* FIXME: The port to which the device is connected should be reset. */ - err = uhc_bus_reset(uhs_ctx->dev); - if (err) { - LOG_ERR("Failed to signal bus reset"); - return err; + k_mutex_lock(&uhs_ctx->mutex, K_FOREVER); + device_count = sys_dlist_len(&uhs_ctx->udevs); + k_mutex_unlock(&uhs_ctx->mutex); + + /* Only reset bus if this is the root device. */ + if (device_count == 1U) { + err = uhc_bus_reset(uhs_ctx->dev); + if (err) { + LOG_ERR("Failed to signal bus reset"); + return err; + } } /* diff --git a/subsys/usb/host/usbh_device.h b/subsys/usb/host/usbh_device.h index 5c5637fb0bee8..d45257c58b975 100644 --- a/subsys/usb/host/usbh_device.h +++ b/subsys/usb/host/usbh_device.h @@ -36,6 +36,13 @@ int usbh_device_interface_set(struct usb_device *const udev, const uint8_t iface, const uint8_t alt, const bool dry); +/* Get root USB device */ +struct usb_device *usbh_device_get_root(struct usbh_context *const ctx); + +/* Check if USB device is root */ +bool usbh_device_is_root(struct usbh_context *const ctx, + struct usb_device *const udev); + /* Wrappers around to avoid glue UHC calls. */ static inline struct uhc_transfer *usbh_xfer_alloc(struct usb_device *udev, const uint8_t ep,