Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 10 additions & 0 deletions include/zephyr/usb/usb_ch9.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,16 @@ struct usb_desc_header {
uint8_t bDescriptorType;
} __packed;

/** Header of an USB class-specific descriptor */
struct usb_cs_desc_header {
/** Length of the descriptor in bytes */
uint8_t bLength;
/** Type of the descriptor */
uint8_t bDescriptorType;
/** Class-specific type of the descriptor */
uint8_t bDescriptorSubtype;
} __packed;

/** USB Standard Device Descriptor defined in spec. Table 9-8 */
struct usb_device_descriptor {
uint8_t bLength;
Expand Down
2 changes: 1 addition & 1 deletion subsys/usb/common/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# SPDX-FileCopyrightText: Copyright Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0

if(CONFIG_USBD_VIDEO_CLASS)
if(CONFIG_USBD_VIDEO_CLASS OR CONFIG_USBH_VIDEO_CLASS)
zephyr_include_directories(.)
zephyr_sources(uvc.c)
endif()
37 changes: 35 additions & 2 deletions subsys/usb/common/uvc.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,19 @@

/* Video Class-Specific Request Codes */
#define UVC_SET_CUR 0x01
#define UVC_SET_CUR_ALL 0x11
#define UVC_GET_CUR 0x81
#define UVC_GET_MIN 0x82
#define UVC_GET_MAX 0x83
#define UVC_GET_RES 0x84
#define UVC_GET_LEN 0x85
#define UVC_GET_INFO 0x86
#define UVC_GET_DEF 0x87
#define UVC_GET_CUR_ALL 0x91
#define UVC_GET_MIN_ALL 0x92
#define UVC_GET_MAX_ALL 0x93
#define UVC_GET_RES_ALL 0x94
#define UVC_GET_DEF_ALL 0x97

/* Flags announcing which controls are supported */
#define UVC_INFO_SUPPORTS_GET BIT(0)
Expand Down Expand Up @@ -209,6 +215,23 @@
/* Base GUID string present at the end of most GUID formats, preceded by the FourCC code */
#define UVC_FORMAT_GUID(fourcc) fourcc "\x00\x00\x10\x00\x80\x00\x00\xaa\x00\x38\x9b\x71"

/* Handle cases where device mode is not enabled */
#if CONFIG_USBD_VIDEO_MAX_FRMIVAL
#define USBD_VIDEO_MAX_FRMIVAL CONFIG_USBD_VIDEO_MAX_FRMIVAL
#else
#define USBD_VIDEO_MAX_FRMIVAL 0
#endif

/* Handle cases where host mode is not enabled */
#if CONFIG_USBH_VIDEO_MAX_FRMIVAL
#define USBH_VIDEO_MAX_FRMIVAL CONFIG_USBH_VIDEO_MAX_FRMIVAL
#else
#define USBH_VIDEO_MAX_FRMIVAL 0
#endif

/* Maximum number of frame interval supported by either USB device or host */
#define USB_VIDEO_MAX_FRMIVAL MAX(USBH_VIDEO_MAX_FRMIVAL, USBD_VIDEO_MAX_FRMIVAL)

struct uvc_if_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
Expand All @@ -233,6 +256,16 @@ struct uvc_unit_descriptor {
uint8_t bUnitID;
};

struct uvc_input_terminal_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bDescriptorSubtype;
uint8_t bTerminalID;
uint16_t wTerminalType;
uint8_t bAssocTerminal;
uint8_t iTerminal;
} __packed;

struct uvc_output_terminal_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
Expand Down Expand Up @@ -436,7 +469,7 @@ struct uvc_frame_discrete_descriptor {
uint32_t dwMaxVideoFrameBufferSize;
uint32_t dwDefaultFrameInterval;
uint8_t bFrameIntervalType;
uint32_t dwFrameInterval[CONFIG_USBD_VIDEO_MAX_FRMIVAL];
uint32_t dwFrameInterval[USB_VIDEO_MAX_FRMIVAL];
} __packed;

struct uvc_frame_based_continuous_descriptor {
Expand Down Expand Up @@ -468,7 +501,7 @@ struct uvc_frame_based_discrete_descriptor {
uint32_t dwMaxBitRate;
uint32_t dwDefaultFrameInterval;
uint8_t bFrameIntervalType;
Comment thread
josuah marked this conversation as resolved.
uint32_t dwFrameInterval[CONFIG_USBD_VIDEO_MAX_FRMIVAL];
uint32_t dwFrameInterval[USB_VIDEO_MAX_FRMIVAL];
} __packed;

struct uvc_color_descriptor {
Expand Down
8 changes: 4 additions & 4 deletions subsys/usb/device_next/class/usbd_uvc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1288,9 +1288,9 @@ static int uvc_add_vs_frame_interval(struct uvc_frame_descriptor *const desc,
desc->bDescriptorSubtype == UVC_VS_FRAME_MJPEG) {
struct uvc_frame_discrete_descriptor *frame_desc = (void *)desc;

if (frame_desc->bFrameIntervalType >= CONFIG_USBD_VIDEO_MAX_FRMIVAL) {
if (frame_desc->bFrameIntervalType >= USB_VIDEO_MAX_FRMIVAL) {
LOG_WRN("Out of descriptors, raise CONFIG_USBD_VIDEO_MAX_FRMIVAL above %u",
CONFIG_USBD_VIDEO_MAX_FRMIVAL);
USB_VIDEO_MAX_FRMIVAL);
return -ENOMEM;
}

Expand All @@ -1301,7 +1301,7 @@ static int uvc_add_vs_frame_interval(struct uvc_frame_descriptor *const desc,
} else if (desc->bDescriptorSubtype == UVC_VS_FRAME_FRAME_BASED) {
struct uvc_frame_based_discrete_descriptor *frame_desc = (void *)desc;

if (frame_desc->bFrameIntervalType >= CONFIG_USBD_VIDEO_MAX_FRMIVAL) {
if (frame_desc->bFrameIntervalType >= USB_VIDEO_MAX_FRMIVAL) {
LOG_WRN("Out of descriptors, raise CONFIG_USBD_VIDEO_MAX_FRMIVAL above %u",
CONFIG_USBD_VIDEO_MAX_FRMIVAL);
return -ENOMEM;
Expand Down Expand Up @@ -1343,7 +1343,7 @@ static int uvc_add_vs_frame_desc(const struct device *dev,
}

desc->bLength = sizeof(struct uvc_frame_discrete_descriptor) -
CONFIG_USBD_VIDEO_MAX_FRMIVAL * sizeof(uint32_t);
USB_VIDEO_MAX_FRMIVAL * sizeof(uint32_t);
desc->bDescriptorType = USB_DESC_CS_INTERFACE;
desc->bFrameIndex = format_desc->bNumFrameDescriptors + 1;
desc->wWidth = sys_cpu_to_le16(fmt->width);
Expand Down
5 changes: 5 additions & 0 deletions subsys/usb/host/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ zephyr_library_sources_ifdef(
usbh_shell.c
)

zephyr_library_sources_ifdef(
CONFIG_USBH_VIDEO_CLASS
class/usbh_uvc.c
)

zephyr_library_sources_ifdef(
CONFIG_USBIP
usbip.c
Expand Down
1 change: 1 addition & 0 deletions subsys/usb/host/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,6 @@ config USBH_MAX_UHC_MSG
Maximum number of USB host controller events that can be queued.

rsource "Kconfig.usbip"
rsource "class/Kconfig"

endif # USB_HOST_STACK
4 changes: 4 additions & 0 deletions subsys/usb/host/class/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# SPDX-FileCopyrightText: Copyright Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0

rsource "Kconfig.uvc"
26 changes: 26 additions & 0 deletions subsys/usb/host/class/Kconfig.uvc
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# SPDX-FileCopyrightText: Copyright Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0

config USBH_VIDEO_CLASS
bool "USB host Video Class support [EXPERIMENTAL]"
select EXPERIMENTAL
help
USB Host Video Class (UVC) implementation.

if USBH_VIDEO_CLASS

config USBH_VIDEO_MAX_FRMIVAL
int "Max number of video frame interval per descriptor supported"
range 1 255
default 16
help
Max number of Frame Interval listed on a frame descriptor. The
default value is selected arbitrarily to fit most situations.

module = USBH_UVC
module-str = usbh uvc
default-count = 1
source "subsys/logging/Kconfig.template.log_config"
source "subsys/usb/device_next/class/Kconfig.template.instances_count"

endif # USBH_VIDEO_CLASS
142 changes: 142 additions & 0 deletions subsys/usb/host/class/usbh_uvc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/*
* SPDX-FileCopyrightText: Copyright Nordic Semiconductor ASA
* SPDX-License-Identifier: Apache-2.0
*/

#include <stdlib.h>

#include <zephyr/init.h>
#include <zephyr/device.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/sys/atomic.h>
#include <zephyr/usb/usbh.h>
#include <zephyr/usb/usb_ch9.h>
#include <zephyr/drivers/usb/udc.h>
#include <zephyr/drivers/video.h>
#include <zephyr/drivers/video-controls.h>
#include <zephyr/logging/log.h>

#include <zephyr/sys/util.h>
#include <zephyr/usb/usb_ch9.h>

#include "usbh_ch9.h"
#include "usbh_class.h"
#include "usbh_desc.h"
#include "usbh_device.h"

#include "uvc.h"
#include "../../../drivers/video/video_ctrls.h"
#include "../../../drivers/video/video_device.h"

LOG_MODULE_REGISTER(usbh_uvc, CONFIG_USBH_UVC_LOG_LEVEL);

struct usbh_uvc_data {
const char *name;
};

/*
* Descriptor parsing utilities
* Validate and parse the video streaming and video control descriptors.
*/

static int usbh_uvc_probe(struct usbh_class_data *const c_data,
struct usb_device *const udev, const uint8_t iface)
{
return 0;
}

static int usbh_uvc_removed(struct usbh_class_data *const c_data)
{
return 0;
}

static int usbh_uvc_init(struct usbh_class_data *const c_data,
struct usbh_context *const uhs_ctx)
{
return 0;
}

static int usbh_uvc_completion_cb(struct usbh_class_data *const c_data,
struct uhc_transfer *const xfer)
{
return 0;
}

static int usbh_uvc_preinit(const struct device *dev)
{
return 0;
}

static struct usbh_class_api uvc_class_api = {
.init = usbh_uvc_init,
.completion_cb = usbh_uvc_completion_cb,
.probe = usbh_uvc_probe,
.removed = usbh_uvc_removed,
};

static int usbh_uvc_get_caps(const struct device *const dev, struct video_caps *const caps)
{
return 0;
}

static int usbh_uvc_get_format(const struct device *const dev, struct video_format *const fmt)
{
return 0;
}

static int usbh_uvc_set_stream(const struct device *const dev, const bool enable,
const enum video_buf_type type)
{
return 0;
}

static int usbh_uvc_enqueue(const struct device *const dev, struct video_buffer *const vbuf)
{
return 0;
}

static int usbh_uvc_dequeue(const struct device *const dev, struct video_buffer **const vbuf,
k_timeout_t timeout)
{
return 0;
}

static DEVICE_API(video, uvc_video_api) = {
.get_caps = usbh_uvc_get_caps,
.get_format = usbh_uvc_get_format,
.set_stream = usbh_uvc_set_stream,
.enqueue = usbh_uvc_enqueue,
.dequeue = usbh_uvc_dequeue,
};

static struct usbh_class_filter usbh_uvc_filters[] = {
{
.flags = USBH_CLASS_MATCH_CODE_TRIPLE,
.class = USB_BCC_VIDEO,
.sub = UVC_SC_VIDEO_INTERFACE_COLLECTION,
.proto = 0,
},
{0},
};


#define USBH_VIDEO_DEVICE_DEFINE(n, _) \
\
static struct usbh_uvc_data uvc_data_##n = { \
.name = "uvc_"#n, \
}; \
\
DEVICE_DEFINE(usbh_uvc_##n, "usbh_uvc_"#n, \
usbh_uvc_preinit, NULL, \
&uvc_data_##n, NULL, \
POST_KERNEL, CONFIG_VIDEO_INIT_PRIORITY, \
&uvc_video_api); \
\
USBH_DEFINE_CLASS(uvc_c_data_##n, &uvc_class_api, \
(void *)DEVICE_GET(usbh_uvc_##n), \
usbh_uvc_filters); \
\
VIDEO_DEVICE_DEFINE(uvc_host_##n, DEVICE_GET(usbh_uvc_##n), NULL);

LISTIFY(CONFIG_USBH_UVC_INSTANCES_COUNT, USBH_VIDEO_DEVICE_DEFINE, ())
11 changes: 11 additions & 0 deletions tests/subsys/usb/uvc/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# SPDX-License-Identifier: Apache-2.0

cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(uvc_uvb)

include(${ZEPHYR_BASE}/samples/subsys/usb/common/common.cmake)

FILE(GLOB app_sources src/*.c)
target_sources(app PRIVATE ${app_sources})
zephyr_include_directories(${ZEPHYR_BASE}/subsys/usb/host)
12 changes: 12 additions & 0 deletions tests/subsys/usb/uvc/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# SPDX-FileCopyrightText: Copyright The Zephyr Project Contributors
# SPDX-License-Identifier: Apache-2.0

config SYS_CLOCK_TICKS_PER_SEC
default 1000000 if BOARD_NATIVE_SIM

# Source common USB sample options used to initialize new experimental USB
# device stack. The scope of these options is limited to USB samples in project
# tree, you cannot use them in your own application.
source "samples/subsys/usb/common/Kconfig.sample_usbd"

source "Kconfig.zephyr"
22 changes: 22 additions & 0 deletions tests/subsys/usb/uvc/boards/native_sim.overlay
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* SPDX-FileCopyrightText: Copyright Nordic Semiconductor ASA
* SPDX-License-Identifier: Apache-2.0
*/

/delete-node/ &zephyr_udc0;

/ {
zephyr_uhc0: uhc_vrt0 {
compatible = "zephyr,uhc-virtual";

zephyr_udc0: udc_vrt0 {
compatible = "zephyr,udc-virtual";
num-bidir-endpoints = <8>;
maximum-speed = "high-speed";
};
};

uvc_device: uvcd {
compatible = "zephyr,uvc-device";
};
};
6 changes: 6 additions & 0 deletions tests/subsys/usb/uvc/boards/native_sim_64.overlay
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/*
* SPDX-FileCopyrightText: Copyright Nordic Semiconductor ASA
* SPDX-License-Identifier: Apache-2.0
*/

#include "native_sim.overlay"
Loading