Linux UVC Gadget 驅動

概述

UVC Gadget 驅動是用於 USB 連線裝置端的硬體的驅動程式。它旨在執行在具有 USB 裝置端硬體(例如帶有 OTG 埠的板卡)的 Linux 系統上。

在裝置系統上,一旦驅動繫結,它將表現為一個具有輸出能力的 V4L2 裝置。

在主機端(透過 USB 電纜連線後),執行 UVC Gadget 驅動並由適當的使用者空間程式控制的裝置應顯示為符合 UVC 規範的攝像頭,並能與任何設計用於處理它們的程式正常執行。在裝置系統上執行的使用者空間程式可以將來自各種來源的影像緩衝區排隊,透過 USB 連線傳輸。通常這意味著轉發來自攝像頭感測器外設的緩衝區,但緩衝區的來源完全取決於使用者空間伴隨程式。

配置裝置核心

必須選擇 Kconfig 選項 USB_CONFIGFS、USB_LIBCOMPOSITE、USB_CONFIGFS_F_UVC 和 USB_F_UVC 以啟用 UVC gadget 的支援。

透過 configfs 配置 gadget

UVC Gadget 期望透過使用 UVC 函式的 configfs 進行配置。這提供了很大的靈活性,因為 UVC 裝置的許多設定都可以透過這種方式控制。

並非所有可用屬性都在此處描述。有關完整列舉,請參閱ABI 檔案測試/configfs-usb-gadget-uvc

假設

本節假設您已將 configfs 掛載到 /sys/kernel/config 並將 gadget 建立為 /sys/kernel/config/usb_gadget/g1

UVC 函式

第一步是建立 UVC 函式

# 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

格式和幀

您必須透過告知 gadget 支援哪些格式,以及每種格式支援的幀大小和幀間隔來配置 gadget。在當前的實現中,gadget 無法拒絕設定主機指示其設定的格式,因此,準確地完成此步驟以確保主機永遠不會請求無法提供的格式非常重要。

格式在 streaming/uncompressed 和 streaming/mjpeg configfs 組下建立,幀大小在格式下建立,結構如下

uvc.0 +
      |
      + streaming +
                  |
                  + mjpeg +
                  |       |
                  |       + mjpeg +
                  |            |
                  |            + 720p
                  |            |
                  |            + 1080p
                  |
                  + uncompressed +
                                 |
                                 + yuyv +
                                        |
                                        + 720p
                                        |
                                        + 1080p

然後可以為每個幀配置寬度和高度,加上儲存單個幀所需的最大緩衝區大小,最後是該格式和幀大小支援的幀間隔。寬度和高度以畫素為單位列舉,幀間隔以 100ns 為單位。例如,要建立上述結構,併為每個幀大小設定 2、15 和 100 fps 的幀間隔,您可以這樣做

create_frame() {
        # Example usage:
        # create_frame <width> <height> <group> <format name>

        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 <<EOF > $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

目前唯一支援的未壓縮格式是 YUYV,詳情請參閱打包的 YUV 格式

顏色匹配描述符

可以為您建立的每種格式指定一些色彩資訊。此步驟是可選的,如果跳過此步驟,將包含預設資訊;這些預設值遵循 UVC 規範的顏色匹配描述符部分中定義的那些值。

要建立顏色匹配描述符,請建立一個 configfs 項並將其三個屬性設定為您想要的設定,然後從您希望與之關聯的格式連結到它

# 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

有關有效值的詳細資訊,請查閱 UVC 規範。請注意,存在一個預設的顏色匹配描述符,任何未連結到不同顏色匹配描述符的格式都將使用它。可以更改預設描述符的屬性設定,因此請記住,如果您這樣做,您將更改任何未連結到不同描述符的格式的預設值。

頭部連結

UVC 規範要求格式和幀描述符前面有頭部,詳細說明後續不同格式描述符的數量和累積大小等。此操作和類似操作透過 configfs 中代表頭部的 configfs 項與代表其他描述符的 config 項之間的連結來實現,方式如下

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

擴充套件單元支援

UVC 擴充套件單元 (XU) 基本上提供了一個獨立的單元,可以向其傳送控制設定和獲取請求。這些控制請求的含義完全取決於實現,但可用於控制 UVC 規範之外的設定(例如啟用或停用影片效果)。XU 可以插入到 UVC 單元鏈中,也可以保持自由懸掛。

配置擴充套件單元涉及在相應目錄中建立條目並適當設定其屬性,如下所示

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

bmControls 屬性和 baSourceID 屬性是多值屬性。這意味著您可以向它們寫入多個以換行符分隔的值。例如,要將第 1、2、9 和 10 個控制標記為可用,您需要向 bmControls 寫入兩個值,如下所示

cat << EOF > bmControls
0x03
0x03
EOF

baSourceID 屬性的多值特性表明 XU 可以是多輸入的,但請注意,這目前沒有顯著影響。

bControlSize 屬性反映 bmControls 屬性的大小,類似地 bNrInPins 反映 baSourceID 屬性的大小。當您設定 bmControls 和 baSourceID 時,這兩個屬性都會自動增加/減少。也可以手動增加或減少 bControlSize,這將導致條目截斷到新大小,或用 0x00 填充條目,例如

$ cat bmControls
0x03
0x05

$ cat bControlSize
2

$ echo 1 > bControlSize
$ cat bmControls
0x03

$ echo 2 > bControlSize
$ cat bmControls
0x03
0x00

bNrInPins 和 baSourceID 的功能相同。

配置攝像頭終端和處理單元支援的控制

UVC 鏈中的攝像頭終端和處理單元也有 bmControls 屬性,其功能與擴充套件單元中的相同欄位類似。然而,與 XU 不同的是,這些單元的位標誌的含義在 UVC 規範中定義;您應該查閱“攝像頭終端描述符”和“處理單元描述符”部分以獲取標誌的列舉。

# Set the Processing Unit's bmControls, flagging Brightness, Contrast
# and Hue as available controls:
echo 0x05 > $FUNCTION/control/processing/default/bmControls

# Set the Camera Terminal's bmControls, flagging Focus Absolute and
# Focus Relative as available controls:
echo 0x60 > $FUNCTION/control/terminal/camera/default/bmControls

如果您不設定這些欄位,則預設情況下,攝像頭終端的自動曝光模式控制和處理單元的亮度控制將被標記為可用;如果它們不受支援,您應將該欄位設定為 0x00。

請注意,攝像頭終端或處理單元的 bmControls 欄位的大小由 UVC 規範固定,因此 bControlSize 屬性在此處是隻讀的。

自定義字串支援

提供 USB 裝置各個部分的文字描述的字串描述符可以在 USB configfs 中的常用位置定義,然後可以從 UVC 函式根目錄或擴充套件單元目錄連結到它們,以將這些字串指定為描述符

# 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

中斷端點

VideoControl 介面有一個可選的中斷端點,預設情況下是停用的。這旨在支援 UVC 的延遲響應控制設定請求(應該透過中斷端點而不是佔用端點 0 進行響應)。目前缺少透過此端點發送資料的支援,因此為了避免混淆,它保持停用狀態。如果您希望啟用它,可以透過 configfs 屬性進行

echo 1 > $FUNCTION/control/enable_interrupt_ep

頻寬配置

有三個屬性控制 USB 連線的頻寬。它們位於功能根目錄中,可以在限制範圍內設定

# 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

此處傳遞的值將根據 UVC 規範(取決於 USB 連線的速度)鉗制到有效值。要了解這些設定如何影響頻寬,您應該查閱 UVC 規範,但一個經驗法則是,增加 streaming_maxpacket 設定將改善頻寬(從而提高最大可能幀率),而 streaming_maxburst 在 USB 連線以超高速執行時也是如此。增加 streaming_interval 將降低頻寬和幀率。

使用者空間應用程式

UVC Gadget 驅動本身無法做任何特別有趣的事情。它必須與一個使用者空間程式配對,該程式響應 UVC 控制請求並填充緩衝區以排隊到驅動程式建立的 V4L2 裝置。這些如何實現取決於具體實現,並且超出了本文件的範圍,但可以在https://gitlab.freedesktop.org/camera/uvc-gadget找到一個參考應用程式