mirror of
https://github.com/apache/nuttx.git
synced 2026-10-03 12:18:06 +00:00
Add USB Video Class 1.1 gadget driver supporting Bulk transport with uncompressed YUY2 video streaming. Resolution and frame interval are negotiated dynamically via PROBE/COMMIT control. - uvc.h: protocol constants, streaming control struct, public API - uvc.c: class driver with PROBE/COMMIT, bulk EP, /dev/uvc0 chardev - Kconfig/Make.defs: USBUVC config and build rules - boardctl.c: BOARDIOC_USBDEV_UVC standalone init path Hardened against host disconnect: - Removed nxmutex_lock from USB interrupt context paths - Added 30s semaphore timeout in uvc_write with EP_CANCEL fallback - Drain stale wrsem counts in VS_COMMIT before new stream - Guard uvc_streaming_stop() against double EP_CANCEL race - Handle EP_SUBMIT returning -ESHUTDOWN gracefully Signed-off-by: wangjianyu3 <wangjianyu3@xiaomi.com>
127 lines
4.1 KiB
ReStructuredText
127 lines
4.1 KiB
ReStructuredText
======================================
|
||
USB Video Class (UVC) Gadget Driver
|
||
======================================
|
||
|
||
Overview
|
||
========
|
||
|
||
The UVC gadget driver (``drivers/usbdev/uvc.c``) implements a USB Video Class
|
||
1.1 device that makes NuttX appear as a USB webcam to the host. The driver
|
||
exposes a character device (``/dev/uvc0``) that applications write video frames
|
||
to. It handles all UVC class-specific control requests (PROBE / COMMIT)
|
||
internally and uses bulk transfers for video data.
|
||
|
||
The driver supports two modes:
|
||
|
||
- **Standalone** – the UVC function is the only USB class on the bus.
|
||
- **Composite** – the UVC function is combined with other USB class drivers
|
||
(e.g. CDC/ACM) via the NuttX composite device framework.
|
||
|
||
Features
|
||
========
|
||
|
||
- UVC 1.1 compliant (uncompressed YUY2 format)
|
||
- Bulk transfer mode for video data
|
||
- Automatic PROBE / COMMIT negotiation with the host
|
||
- ``poll()`` support – applications can wait for the host to start streaming
|
||
(``POLLOUT``) and detect disconnection (``POLLHUP``)
|
||
- Runtime video parameters – resolution and frame rate are passed at
|
||
initialization time, so USB descriptors always match the actual sensor
|
||
- ``boardctl()`` integration for easy application-level bring-up
|
||
|
||
Configuration
|
||
=============
|
||
|
||
The driver is enabled through the following Kconfig options:
|
||
|
||
.. code-block:: kconfig
|
||
|
||
CONFIG_USBUVC=y # Enable UVC gadget support
|
||
CONFIG_USBUVC_COMPOSITE=n # Set y for composite device mode
|
||
CONFIG_USBUVC_EPBULKIN=1 # Bulk IN endpoint number (standalone)
|
||
CONFIG_USBUVC_EP0MAXPACKET=64 # EP0 max packet size (standalone)
|
||
CONFIG_USBUVC_EPBULKIN_FSSIZE=64 # Bulk IN full-speed max packet size
|
||
CONFIG_USBUVC_NWRREQS=4 # Number of pre-allocated write requests
|
||
CONFIG_USBUVC_NPOLLWAITERS=2 # Number of poll waiters
|
||
|
||
Header Files
|
||
============
|
||
|
||
- ``include/nuttx/usb/uvc.h`` – Public API, UVC descriptor constants, and
|
||
data structures.
|
||
|
||
Data Structures
|
||
===============
|
||
|
||
``struct uvc_params_s``
|
||
-----------------------
|
||
|
||
Passed to the initialization function so that USB descriptors reflect the
|
||
actual sensor capabilities::
|
||
|
||
struct uvc_params_s
|
||
{
|
||
uint16_t width; /* Frame width in pixels */
|
||
uint16_t height; /* Frame height in pixels */
|
||
uint8_t fps; /* Frames per second */
|
||
};
|
||
|
||
Public Interfaces
|
||
=================
|
||
|
||
Standalone Mode
|
||
---------------
|
||
|
||
``usbdev_uvc_initialize()``
|
||
Initialize the UVC gadget and register ``/dev/uvc0``. *params* may be
|
||
``NULL`` to use defaults (320 × 240 @ 5 fps). Returns a handle for later
|
||
``usbdev_uvc_uninitialize()``.
|
||
|
||
``usbdev_uvc_uninitialize()``
|
||
Tear down the UVC gadget and unregister the character device.
|
||
|
||
Composite Mode
|
||
--------------
|
||
|
||
``usbdev_uvc_classobject()``
|
||
Create a UVC class driver instance for use inside a composite device.
|
||
|
||
``usbdev_uvc_classuninitialize()``
|
||
Destroy a class driver instance created by ``usbdev_uvc_classobject()``.
|
||
|
||
``usbdev_uvc_get_composite_devdesc()``
|
||
Fill a ``composite_devdesc_s`` for the composite framework.
|
||
|
||
boardctl Integration
|
||
--------------------
|
||
|
||
Applications can manage the UVC gadget through ``boardctl()``::
|
||
|
||
struct boardioc_usbdev_ctrl_s ctrl;
|
||
struct uvc_params_s params = { .width = 320, .height = 240, .fps = 15 };
|
||
FAR void *handle = (FAR void *)¶ms;
|
||
|
||
ctrl.usbdev = BOARDIOC_USBDEV_UVC;
|
||
ctrl.action = BOARDIOC_USBDEV_CONNECT;
|
||
ctrl.instance = 0;
|
||
ctrl.config = 0;
|
||
ctrl.handle = &handle;
|
||
|
||
boardctl(BOARDIOC_USBDEV_CONTROL, (uintptr_t)&ctrl);
|
||
|
||
/* ... use /dev/uvc0 ... */
|
||
|
||
ctrl.action = BOARDIOC_USBDEV_DISCONNECT;
|
||
boardctl(BOARDIOC_USBDEV_CONTROL, (uintptr_t)&ctrl);
|
||
|
||
Device Operation
|
||
================
|
||
|
||
1. The application opens ``/dev/uvc0`` for writing.
|
||
2. Use ``poll()`` with ``POLLOUT`` to wait for the USB host to start streaming
|
||
(i.e. the host sends a VS_COMMIT_CONTROL SET_CUR request).
|
||
3. Write complete video frames via ``write()``. The driver prepends a 2-byte
|
||
UVC payload header (with FID / EOF bits) automatically.
|
||
4. When the host stops streaming, ``write()`` returns ``-EAGAIN``. The
|
||
application can ``poll()`` again to wait for the host to restart.
|
||
5. ``POLLHUP`` is reported when the host explicitly stops streaming.
|