Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
16b61db
usb: host: add host status to the host context
Aug 8, 2025
010638b
usb: host: add copyright notice to linker script
Oct 23, 2025
9c27337
usb: host: class: implement more of the class/data struct fields
Aug 14, 2025
a071c98
usb: host: introduce wrappers to access the class function pointers
Aug 15, 2025
4617ffc
usb: host: introduce usbh_class with init/remove functions
Aug 15, 2025
474238e
usb: uvc: move the header definition to include/
Jul 25, 2025
c960560
tests: usb: host: test basic API functionality
Sep 11, 2025
5bd97c9
usb: host: use SPDX-FileCopyrightText prefix
Dec 8, 2025
f5e898b
tests: usb: host: test basic API functionality
Sep 11, 2025
d814fbe
usb: uvc: move the header definition to include/
Jul 25, 2025
cfd72a3
uvc: device: move helper functions to a common directory
Aug 17, 2025
e51fbbf
usb: uvc: common: correct the size for UVC_PU_CONTRAST_CONTROL
Nov 27, 2025
d334d1d
usb: host: uvc: placeholder implementation
Jul 26, 2025
9bb8b64
tests: usb: uvc: connect USB device and host via UVB
Jul 24, 2025
f545687
usb: device_next: uvc: fix public API include
Oct 29, 2025
ca1514b
usb: host: device: Read descriptor after setting device address
santhosh-c-c Nov 13, 2025
4139fff
subsys: usb: host: support multiple devices under hub
AidenHu Nov 18, 2025
fd1abd7
subsys: usb: host: remove root member for usbh_context
AidenHu Nov 19, 2025
16538fd
drivers: uhc: use correct endpoint type and interval
AidenHu Nov 18, 2025
ef9d0cf
drivers: uhc: correct interval usage for usb xfer
AidenHu Nov 18, 2025
2f940be
drivers: uhc: set right value for pipe by xfer's mps
AidenHu Nov 19, 2025
399578c
subsys: usb: host: refine connect/disconnect handling
AidenHu Nov 26, 2025
16a20c6
subsys: usb: host: add config support for hub class
AidenHu Dec 2, 2025
6b42426
subsys: usb: host: new usb host hub class implementation
AidenHu Nov 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions drivers/usb/uhc/uhc_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ struct uhc_transfer *uhc_xfer_alloc(const struct device *dev,
const struct uhc_api *api = dev->api;
struct uhc_transfer *xfer = NULL;
uint16_t mps;
uint16_t interval;
uint8_t type;

api->lock(dev);

Expand All @@ -109,6 +111,8 @@ struct uhc_transfer *uhc_xfer_alloc(const struct device *dev,
}

if (ep_idx == 0) {
interval = 0;
type = USB_EP_TYPE_CONTROL;
mps = udev->dev_desc.bMaxPacketSize0;
} else {
struct usb_ep_descriptor *ep_desc;
Expand All @@ -125,6 +129,8 @@ struct uhc_transfer *uhc_xfer_alloc(const struct device *dev,
}

mps = ep_desc->wMaxPacketSize;
interval = ep_desc->bInterval;
type = ep_desc->bmAttributes & USB_EP_TRANSFER_TYPE_MASK;
}

LOG_DBG("Allocate xfer, ep 0x%02x mps %u cb %p", ep, mps, cb);
Expand All @@ -137,6 +143,8 @@ struct uhc_transfer *uhc_xfer_alloc(const struct device *dev,
memset(xfer, 0, sizeof(struct uhc_transfer));
xfer->ep = ep;
xfer->mps = mps;
xfer->interval = interval;
xfer->type = type;
xfer->udev = udev;
xfer->cb = cb;
xfer->priv = cb_priv;
Expand Down
18 changes: 7 additions & 11 deletions drivers/usb/uhc/uhc_mcux_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -243,10 +243,9 @@ static usb_host_pipe_handle uhc_mcux_check_hal_ep(const struct device *dev,
}
}

/* TODO: need to check endpoint type too */
if (mcux_ep != NULL &&
if (mcux_ep != NULL && mcux_ep->pipeType == xfer->type &&
(mcux_ep->maxPacketSize != xfer->mps ||
mcux_ep->interval != xfer->interval)) {
priv->mcux_eps_interval[i] != xfer->interval)) {
/* re-initialize the ep */
status = priv->mcux_if->controllerClosePipe(priv->mcux_host.controllerHandle,
mcux_ep);
Expand All @@ -256,6 +255,7 @@ static usb_host_pipe_handle uhc_mcux_check_hal_ep(const struct device *dev,

uhc_mcux_lock(dev);
priv->mcux_eps[i] = NULL;
priv->mcux_eps_interval[i] = 0;
uhc_mcux_unlock(dev);
mcux_ep = NULL;
}
Expand All @@ -280,21 +280,16 @@ usb_host_pipe_t *uhc_mcux_init_hal_ep(const struct device *dev, struct uhc_trans
/* USB_HostHelperGetPeripheralInformation uses this value as first parameter */
pipe_init.devInstance = xfer->udev;
pipe_init.nakCount = USB_HOST_CONFIG_MAX_NAK;
pipe_init.maxPacketSize = xfer->mps;
pipe_init.maxPacketSize = USB_MPS_EP_SIZE(xfer->mps);
pipe_init.endpointAddress = USB_EP_GET_IDX(xfer->ep);
pipe_init.direction = USB_EP_GET_IDX(xfer->ep) == 0 ? USB_OUT :
USB_EP_GET_DIR(xfer->ep) ? USB_IN : USB_OUT;
/* Current Zephyr Host stack is experimental, the endpoint's interval,
* 'number per uframe' and the endpoint type cannot be got yet.
*/
pipe_init.numberPerUframe = 0; /* TODO: need right way to implement it. */
pipe_init.numberPerUframe = USB_MPS_ADDITIONAL_TRANSACTIONS(xfer->mps);
pipe_init.interval = xfer->interval;
/* TODO: need right way to implement it. */
if (pipe_init.endpointAddress == 0) {
pipe_init.pipeType = USB_ENDPOINT_CONTROL;
} else {
pipe_init.pipeType = USB_ENDPOINT_BULK;
}
pipe_init.pipeType = xfer->type;

status = priv->mcux_if->controllerOpenPipe(priv->mcux_host.controllerHandle,
(usb_host_pipe_handle *)&mcux_ep, &pipe_init);
Expand All @@ -314,6 +309,7 @@ usb_host_pipe_t *uhc_mcux_init_hal_ep(const struct device *dev, struct uhc_trans
for (i = 0; i < USB_HOST_CONFIG_MAX_PIPES; i++) {
if (priv->mcux_eps[i] == NULL) {
priv->mcux_eps[i] = mcux_ep;
priv->mcux_eps_interval[i] = xfer->interval;
break;
}
}
Expand Down
1 change: 1 addition & 0 deletions drivers/usb/uhc/uhc_mcux_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ struct uhc_mcux_data {
const usb_host_controller_interface_t *mcux_if;
/* TODO: Maybe make it to link with udev->ep_in and udev->ep_out */
usb_host_pipe_t *mcux_eps[USB_HOST_CONFIG_MAX_PIPES];
uint16_t mcux_eps_interval[USB_HOST_CONFIG_MAX_PIPES];
usb_host_instance_t mcux_host;
struct k_thread drv_stack_data;
uint8_t controller_id; /* MCUX hal controller id, 0xFF is invalid value */
Expand Down
15 changes: 15 additions & 0 deletions dts/bindings/usb/zephyr,uvc-host.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# SPDX-FileCopyrightText: Copyright Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0

description: |
USB Video Class (UVC) host instance.

Each UVC instance added to the USB Host Controller (UHC) node will be visible
as a new camera from Zephyr point of view.

as soon as a camera is connected to USB this device will be usable by the application as a
video device, following the video API.

compatible: "zephyr,uvc-host"

include: base.yaml
2 changes: 2 additions & 0 deletions include/zephyr/drivers/usb/uhc.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ struct uhc_transfer {
struct net_buf *buf;
/** Endpoint to which request is associated */
uint8_t ep;
/** Endpoint type */
uint8_t type;
/** Maximum packet size */
uint16_t mps;
/** Interval, used for periodic transfers only */
Expand Down
1 change: 1 addition & 0 deletions include/zephyr/usb/class/usbd_uvc.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#define ZEPHYR_INCLUDE_USB_CLASS_USBD_UVC_H

#include <zephyr/device.h>
#include <zephyr/drivers/video.h>

/**
* @brief USB Video Class (UVC) device API
Expand Down
140 changes: 110 additions & 30 deletions include/zephyr/usb/usbh.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2022 Nordic Semiconductor ASA
*
* SPDX-FileCopyrightText: Copyright Nordic Semiconductor ASA
* SPDX-FileCopyrightText: Copyright 2025 NXP
* SPDX-License-Identifier: Apache-2.0
*/

Expand All @@ -17,6 +17,7 @@
#include <stdint.h>
#include <zephyr/device.h>
#include <zephyr/net_buf.h>
#include <zephyr/sys/util.h>
#include <zephyr/sys/dlist.h>
#include <zephyr/sys/bitarray.h>
#include <zephyr/drivers/usb/uhc.h>
Expand All @@ -33,6 +34,16 @@ extern "C" {
* @{
*/

/**
* USB host support status
*/
struct usbh_status {
/** USB host support is initialized */
unsigned int initialized : 1;
/** USB host support is enabled */
unsigned int enabled : 1;
};

/**
* USB host support runtime context
*/
Expand All @@ -43,10 +54,10 @@ struct usbh_context {
struct k_mutex mutex;
/** Pointer to UHC device struct */
const struct device *dev;
/** Status of the USB host support */
struct usbh_status status;
/** USB device list */
sys_dlist_t udevs;
/** USB root device */
struct usb_device *root;
/** Allocated device addresses bit array */
struct sys_bitarray *addr_ba;
};
Expand All @@ -60,47 +71,116 @@ struct usbh_context {
.addr_ba = &ba_##device_name, \
}

struct usbh_class_data;

/**
* @brief USB Class Code triple
* @brief Information about a device, which is relevant for matching a particular class.
*/
struct usbh_code_triple {
/** Device Class Code */
uint8_t dclass;
/** Class Subclass Code */
struct usbh_class_filter {
/** Vendor ID */
uint16_t vid;
/** Product ID */
uint16_t pid;
/** Class Code */
uint8_t class;
/** Subclass Code */
uint8_t sub;
/** Class Protocol Code */
/** Protocol Code */
uint8_t proto;
/** Flags that tell which field to match */
uint8_t flags;
};

/**
* @brief USB host class data and class instance API
* @brief USB host class instance API
*/
struct usbh_class_api {
/** Host init handler, before any device is connected */
int (*init)(struct usbh_class_data *const c_data,
struct usbh_context *const uhs_ctx);
/** Request completion event handler */
int (*completion_cb)(struct usbh_class_data *const c_data,
struct uhc_transfer *const xfer);
/** Device connection handler */
int (*probe)(struct usbh_class_data *const c_data,
struct usb_device *const udev,
const uint8_t iface);
/** Device removal handler */
int (*removed)(struct usbh_class_data *const c_data);
};

/**
* @brief USB host class instance data
*/
struct usbh_class_data {
/** Class code supported by this instance */
struct usbh_code_triple code;
/** Name of the USB host class instance */
const char *name;
/** Pointer to USB host stack context structure */
struct usbh_context *uhs_ctx;
/** Pointer to USB device this class is used for */
struct usb_device *udev;
/** Interface number for which this class matched */
uint8_t iface;
/** Pointer to host support class API */
struct usbh_class_api *api;
/** Pointer to private data */
void *priv;
};

/** Initialization of the class implementation */
/* int (*init)(struct usbh_context *const uhs_ctx); */
/** Request completion event handler */
int (*request)(struct usbh_context *const uhs_ctx,
struct uhc_transfer *const xfer, int err);
/** Device connected handler */
int (*connected)(struct usbh_context *const uhs_ctx);
/** Device removed handler */
int (*removed)(struct usbh_context *const uhs_ctx);
/** Bus remote wakeup handler */
int (*rwup)(struct usbh_context *const uhs_ctx);
/** Bus suspended handler */
int (*suspended)(struct usbh_context *const uhs_ctx);
/** Bus resumed handler */
int (*resumed)(struct usbh_context *const uhs_ctx);
/**
* @cond INTERNAL_HIDDEN
*
* Internal state of an USB class. Not corresponding to an USB protocol state,
* but instead software life cycle.
*/
enum usbh_class_state {
/** The class is available to be associated to an USB device function. */
USBH_CLASS_STATE_IDLE,
/** The class got bound to an USB function of a particular device on the bus. */
USBH_CLASS_STATE_BOUND,
/** The class failed to initialize and cannot be used. */
USBH_CLASS_STATE_ERROR,
};
/* @endcond */

/**
* @cond INTERNAL_HIDDEN
*
* Variables used by the USB host stack but not exposed to the class
* through the class API.
*/
#define USBH_DEFINE_CLASS(name) \
static STRUCT_SECTION_ITERABLE(usbh_class_data, name)
struct usbh_class_node {
/** Class information exposed to host class implementations (drivers). */
struct usbh_class_data *const c_data;
/** Filter rules to match this USB host class instance against a device class **/
struct usbh_class_filter *filters;
/** State of the USB class instance */
enum usbh_class_state state;
};
/* @endcond */

/**
* @brief Define USB host support class data
*
* Macro defines class (function) data, as well as corresponding node
* structures used internally by the stack.
*
* @param[in] class_name Class name
* @param[in] class_api Pointer to struct usbh_class_api
* @param[in] class_priv Class private data
* @param[in] filt Array of @ref usbh_class_filter to match this class or NULL to match everything.
* When non-NULL, the it has to be terminated by an entry with @c flags set to 0.
*/
#define USBH_DEFINE_CLASS(class_name, class_api, class_priv, filt) \
static struct usbh_class_data UTIL_CAT(class_data_, class_name) = { \
.name = STRINGIFY(class_name), \
.api = class_api, \
.priv = class_priv, \
}; \
static STRUCT_SECTION_ITERABLE(usbh_class_node, class_name) = { \
.c_data = &UTIL_CAT(class_data_, class_name), \
.filters = filt, \
};

/**
* @brief Initialize the USB host support;
Expand Down
3 changes: 2 additions & 1 deletion subsys/usb/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# Copyright (c) 2022 Nordic Semiconductor
# SPDX-FileCopyrightText: Copyright Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0

add_subdirectory_ifdef(CONFIG_USB_DEVICE_STACK device)
add_subdirectory_ifdef(CONFIG_USB_DEVICE_STACK_NEXT device_next)
add_subdirectory_ifdef(CONFIG_USB_HOST_STACK host)
add_subdirectory_ifdef(CONFIG_USBC_STACK usb_c)
add_subdirectory(common)
7 changes: 7 additions & 0 deletions subsys/usb/common/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Copyright (c) 2025 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0

if(CONFIG_USBD_VIDEO_CLASS OR CONFIG_USBH_VIDEO_CLASS)
zephyr_include_directories(include)
zephyr_sources(usb_common_uvc.c)
endif()
Loading
Loading