From 094f391013ba9cc77b4b1ae1617f0a832e598d67 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Wed, 8 Mar 2023 16:52:13 +0000 Subject: docs: usb: Add documentation for the UVC Gadget The UVC Gadget function has become quite complex, but documentation for it is fairly sparse. Add some more detailed documentation to improve the situation. Signed-off-by: Daniel Scally Link: https://lore.kernel.org/r/20230308165213.139315-1-dan.scally@ideasonboard.com Signed-off-by: Greg Kroah-Hartman --- Documentation/usb/gadget_uvc.rst | 352 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 352 insertions(+) create mode 100644 Documentation/usb/gadget_uvc.rst (limited to 'Documentation/usb/gadget_uvc.rst') diff --git a/Documentation/usb/gadget_uvc.rst b/Documentation/usb/gadget_uvc.rst new file mode 100644 index 000000000000..6d22faceb1a0 --- /dev/null +++ b/Documentation/usb/gadget_uvc.rst @@ -0,0 +1,352 @@ +======================= +Linux UVC Gadget Driver +======================= + +Overview +-------- +The UVC Gadget driver is a driver for hardware on the *device* side of a USB +connection. It is intended to run on a Linux system that has USB device-side +hardware such as boards with an OTG port. + +On the device system, once the driver is bound it appears as a V4L2 device with +the output capability. + +On the host side (once connected via USB cable), a device running the UVC Gadget +driver *and controlled by an appropriate userspace program* should appear as a UVC +specification compliant camera, and function appropriately with any program +designed to handle them. The userspace program running on the device system can +queue image buffers from a variety of sources to be transmitted via the USB +connection. Typically this would mean forwarding the buffers from a camera sensor +peripheral, but the source of the buffer is entirely dependent on the userspace +companion program. + +Configuring the device kernel +----------------------------- +The Kconfig options USB_CONFIGFS, USB_LIBCOMPOSITE, USB_CONFIGFS_F_UVC and +USB_F_UVC must be selected to enable support for the UVC gadget. + +Configuring the gadget through configfs +--------------------------------------- +The UVC Gadget expects to be configured through configfs using the UVC function. +This allows a significant degree of flexibility, as many of a UVC device's +settings can be controlled this way. + +Not all of the available attributes are described here. For a complete enumeration +see Documentation/ABI/testing/configfs-usb-gadget-uvc + +Assumptions +~~~~~~~~~~~ +This section assumes that you have mounted configfs at `/sys/kernel/config` and +created a gadget as `/sys/kernel/config/usb_gadget/g1`. + +The UVC Function +~~~~~~~~~~~~~~~~ + +The first step is to create the UVC function: + +.. code-block:: bash + + # These variables will be assumed throughout the rest of the document + CONFIGFS="/sys/kernel/config" + GADGET="$CONFIGFS/usb_gadget/g1" + FUNCTION="$GADGET/functions/uvc.0" + + mkdir -p $FUNCTION + +Formats and Frames +~~~~~~~~~~~~~~~~~~ + +You must configure the gadget by telling it which formats you support, as well +as the frame sizes and frame intervals that are supported for each format. In +the current implementation there is no way for the gadget to refuse to set a +format that the host instructs it to set, so it is important that this step is +completed *accurately* to ensure that the host never asks for a format that +can't be provided. + +Formats are created under the streaming/uncompressed and streaming/mjpeg configfs +groups, with the framesizes created under the formats in the following +structure: + +:: + + uvc.0 + + | + + streaming + + | + + mjpeg + + | | + | + mjpeg + + | | + | + 720p + | | + | + 1080p + | + + uncompressed + + | + + yuyv + + | + + 720p + | + + 1080p + +Each frame can then be configured with a width and height, plus the maximum +buffer size required to store a single frame, and finally with the supported +frame intervals for that format and framesize. Width and height are enumerated in +units of pixels, frame interval in units of 100ns. To create the structure +above with 2, 15 and 100 fps frameintervals for each framesize for example you +might do: + +.. code-block:: bash + + create_frame() { + # Example usage: + # create_frame + + WIDTH=$1 + HEIGHT=$2 + FORMAT=$3 + NAME=$4 + + wdir=$FUNCTION/streaming/$FORMAT/$NAME/${HEIGHT}p + + mkdir -p $wdir + echo $WIDTH > $wdir/wWidth + echo $HEIGHT > $wdir/wHeight + echo $(( $WIDTH * $HEIGHT * 2 )) > $wdir/dwMaxVideoFrameBufferSize + cat < $wdir/dwFrameInterval + 666666 + 100000 + 5000000 + EOF + } + + create_frame 1280 720 mjpeg mjpeg + create_frame 1920 1080 mjpeg mjpeg + create_frame 1280 720 uncompressed yuyv + create_frame 1920 1080 uncompressed yuyv + +The only uncompressed format currently supported is YUYV, which is detailed at +Documentation/userspace-api/media/v4l/pixfmt-packed.yuv.rst. + +Color Matching Descriptors +~~~~~~~~~~~~~~~~~~~~~~~~~~ +It's possible to specify some colometry information for each format you create. +This step is optional, and default information will be included if this step is +skipped; those default values follow those defined in the Color Matching Descriptor +section of the UVC specification. + +To create a Color Matching Descriptor, create a configfs item and set its three +attributes to your desired settings and then link to it from the format you wish +it to be associated with: + +.. code-block:: bash + + # Create a new Color Matching Descriptor + + mkdir $FUNCTION/streaming/color_matching/yuyv + pushd $FUNCTION/streaming/color_matching/yuyv + + echo 1 > bColorPrimaries + echo 1 > bTransferCharacteristics + echo 4 > bMatrixCoefficients + + popd + + # Create a symlink to the Color Matching Descriptor from the format's config item + ln -s $FUNCTION/streaming/color_matching/yuyv $FUNCTION/streaming/uncompressed/yuyv + +For details about the valid values, consult the UVC specification. Note that a +default color matching descriptor exists and is used by any format which does +not have a link to a different Color Matching Descriptor. It's possible to +change the attribute settings for the default descriptor, so bear in mind that if +you do that you are altering the defaults for any format that does not link to +a different one. + + +Header linking +~~~~~~~~~~~~~~ + +The UVC specification requires that Format and Frame descriptors be preceded by +Headers detailing things such as the number and cumulative size of the different +Format descriptors that follow. This and similar operations are acheived in +configfs by linking between the configfs item representing the header and the +config items representing those other descriptors, in this manner: + +.. code-block:: bash + + mkdir $FUNCTION/streaming/header/h + + # This section links the format descriptors and their associated frames + # to the header + cd $FUNCTION/streaming/header/h + ln -s ../../uncompressed/yuyv + ln -s ../../mjpeg/mjpeg + + # This section ensures that the header will be transmitted for each + # speed's set of descriptors. If support for a particular speed is not + # needed then it can be skipped here. + cd ../../class/fs + ln -s ../../header/h + cd ../../class/hs + ln -s ../../header/h + cd ../../class/ss + ln -s ../../header/h + cd ../../../control + mkdir header/h + ln -s header/h class/fs + ln -s header/h class/ss + + +Extension Unit Support +~~~~~~~~~~~~~~~~~~~~~~ + +A UVC Extension Unit (XU) basically provides a distinct unit to which control set +and get requests can be addressed. The meaning of those control requests is +entirely implementation dependent, but may be used to control settings outside +of the UVC specification (for example enabling or disabling video effects). An +XU can be inserted into the UVC unit chain or left free-hanging. + +Configuring an extension unit involves creating an entry in the appropriate +directory and setting its attributes appropriately, like so: + +.. code-block:: bash + + mkdir $FUNCTION/control/extensions/xu.0 + pushd $FUNCTION/control/extensions/xu.0 + + # Set the bUnitID of the Processing Unit as the source for this + # Extension Unit + echo 2 > baSourceID + + # Set this XU as the source of the default output terminal. This inserts + # the XU into the UVC chain between the PU and OT such that the final + # chain is IT > PU > XU.0 > OT + cat bUnitID > ../../terminal/output/default/baSourceID + + # Flag some controls as being available for use. The bmControl field is + # a bitmap with each bit denoting the availability of a particular + # control. For example to flag the 0th, 2nd and 3rd controls available: + echo 0x0d > bmControls + + # Set the GUID; this is a vendor-specific code identifying the XU. + echo -e -n "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10" > guidExtensionCode + + popd + +The bmControls attribute and the baSourceID attribute are multi-value attributes. +This means that you may write multiple newline separated values to them. For +example to flag the 1st, 2nd, 9th and 10th controls as being available you would +need to write two values to bmControls, like so: + +.. code-block:: bash + + cat << EOF > bmControls + 0x03 + 0x03 + EOF + +The multi-value nature of the baSourceID attribute belies the fact that XUs can +be multiple-input, though note that this currently has no significant effect. + +The bControlSize attribute reflects the size of the bmControls attribute, and +similarly bNrInPins reflects the size of the baSourceID attributes. Both +attributes are automatically increased / decreased as you set bmControls and +baSourceID. It is also possible to manually increase or decrease bControlSize +which has the effect of truncating entries to the new size, or padding entries +out with 0x00, for example: + +:: + + $ cat bmControls + 0x03 + 0x05 + + $ cat bControlSize + 2 + + $ echo 1 > bControlSize + $ cat bmControls + 0x03 + + $ echo 2 > bControlSize + $ cat bmControls + 0x03 + 0x00 + +bNrInPins and baSourceID function in the same way. + +Custom Strings Support +~~~~~~~~~~~~~~~~~~~~~~ + +String descriptors that provide a textual description for various parts of a +USB device can be defined in the usual place within USB configfs, and may then +be linked to from the UVC function root or from Extension Unit directories to +assign those strings as descriptors: + +.. code-block:: bash + + # Create a string descriptor in us-EN and link to it from the function + # root. The name of the link is significant here, as it declares this + # descriptor to be intended for the Interface Association Descriptor. + # Other significant link names at function root are vs0_desc and vs1_desc + # For the VideoStreaming Interface 0/1 Descriptors. + + mkdir -p $GADGET/strings/0x409/iad_desc + echo -n "Interface Associaton Descriptor" > $GADGET/strings/0x409/iad_desc/s + ln -s $GADGET/strings/0x409/iad_desc $FUNCTION/iad_desc + + # Because the link to a String Descriptor from an Extension Unit clearly + # associates the two, the name of this link is not significant and may + # be set freely. + + mkdir -p $GADGET/strings/0x409/xu.0 + echo -n "A Very Useful Extension Unit" > $GADGET/strings/0x409/xu.0/s + ln -s $GADGET/strings/0x409/xu.0 $FUNCTION/control/extensions/xu.0 + +The interrupt endpoint +~~~~~~~~~~~~~~~~~~~~~~ + +The VideoControl interface has an optional interrupt endpoint which is by default +disabled. This is intended to support delayed response control set requests for +UVC (which should respond through the interrupt endpoint rather than tying up +endpoint 0). At present support for sending data through this endpoint is missing +and so it is left disabled to avoid confusion. If you wish to enable it you can +do so through the configfs attribute: + +.. code-block:: bash + + echo 1 > $FUNCTION/control/enable_interrupt_ep + +Bandwidth configuration +~~~~~~~~~~~~~~~~~~~~~~~ + +There are three attributes which control the bandwidth of the USB connection. +These live in the function root and can be set within limits: + +.. code-block:: bash + + # streaming_interval sets bInterval. Values range from 1..255 + echo 1 > $FUNCTION/streaming_interval + + # streaming_maxpacket sets wMaxPacketSize. Valid values are 1024/2048/3072 + echo 3072 > $FUNCTION/streaming_maxpacket + + # streaming_maxburst sets bMaxBurst. Valid values are 1..15 + echo 1 > $FUNCTION/streaming_maxburst + + +The values passed here will be clamped to valid values according to the UVC +specification (which depend on the speed of the USB connection). To understand +how the settings influence bandwidth you should consult the UVC specifications, +but a rule of thumb is that increasing the streaming_maxpacket setting will +improve bandwidth (and thus the maximum possible framerate), whilst the same is +true for streaming_maxburst provided the USB connection is running at SuperSpeed. +Increasing streaming_interval will reduce bandwidth and framerate. + +The userspace application +------------------------- +By itself, the UVC Gadget driver cannot do anything particularly interesting. It +must be paired with a userspace program that responds to UVC control requests and +fills buffers to be queued to the V4L2 device that the driver creates. How those +things are achieved is implementation dependent and beyond the scope of this +document, but a reference application can be found at https://gitlab.freedesktop.org/camera/uvc-gadget -- cgit v1.2.3