uvc攝像頭程式碼解析之描述符
module_init(uvc_init); //1.模組入口
2.初始化函式
static int __init uvc_init(void) // 2.初始化函式
{
int result;
result = usb_register(&uvc_driver.driver); // 3.註冊usb裝置驅動(usb攝像頭裝置)
if (result == 0) //註冊失敗
printk(KERN_INFO DRIVER_DESC " (" DRIVER_VERSION ")\n");
return result;
}
3.註冊usb裝置驅動(usb攝像頭裝置)
3.1 usb攝像頭驅動
struct uvc_driver uvc_driver = { // 3.1 usb攝像頭裝置 .driver = { .name = "uvcvideo", .probe = uvc_probe, // 4. probe方法 .disconnect = uvc_disconnect, .suspend = uvc_suspend, .resume = uvc_resume, .reset_resume = uvc_reset_resume, .id_table = uvc_ids, //3.2 支援的裝置id列表 .supports_autosuspend = 1, }, };
3.2 支援的裝置id列表uvc_ids
static struct usb_device_id uvc_ids[] = { /* Genius eFace 2025 */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, .idVendor = 0x0458, .idProduct = 0x706e, .bInterfaceClass = USB_CLASS_VIDEO, //uvc介面類 0x0e .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_PROBE_MINMAX }, ... ... ... /* SiGma Micro USB Web Camera */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, .idVendor = 0x1c4f, .idProduct = 0x3000, .bInterfaceClass = USB_CLASS_VIDEO, .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_PROBE_MINMAX | UVC_QUIRK_IGNORE_SELECTOR_UNIT }, /* Generic USB Video Class */ //通用usb視訊類 { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) }, //匹配方法:uvc類 {} };
4.probe方法
static int uvc_probe(struct usb_interface *intf,const struct usb_device_id *id)
{
struct usb_device *udev = interface_to_usbdev(intf); //通過usb介面獲取usb裝置
struct uvc_device *dev; //宣告uvc裝置
int ret;
if (id->idVendor && id->idProduct) //有廠商id和商品id(知名裝置)
uvc_trace(UVC_TRACE_PROBE, "Probing known UVC device %s (%04x:%04x)\n", udev->devpath, id->idVendor,id->idProduct);
else //通用uvc裝置
uvc_trace(UVC_TRACE_PROBE, "Probing generic UVC device %s\n",udev->devpath);
/* Allocate memory for the device and initialize it. */
if ((dev = kzalloc(sizeof *dev, GFP_KERNEL)) == NULL) //分配uvc裝置記憶體
return -ENOMEM;
INIT_LIST_HEAD(&dev->entities); //初始化entities(實體)連結串列 Terminal或Unit
INIT_LIST_HEAD(&dev->chains); //初始化chains(鏈)連結串列
INIT_LIST_HEAD(&dev->streams); //初始化streams(視訊流)連結串列
atomic_set(&dev->nstreams, 0);
atomic_set(&dev->users, 0);
atomic_set(&dev->nmappings, 0);
dev->udev = usb_get_dev(udev); //捆綁usb裝置,並增加其引用計數
dev->intf = usb_get_intf(intf); //捆綁usb介面,並增加其引用計數
dev->intfnum = intf->cur_altsetting->desc.bInterfaceNumber; //獲取usb介面描述符介面數
dev->quirks = (uvc_quirks_param == -1) ? id->driver_info : uvc_quirks_param;
if (udev->product != NULL) //存在產品名
strlcpy(dev->name, udev->product, sizeof dev->name); //設定uvc裝置名字為其產品名
else //通用的uvc裝置名
snprintf(dev->name, sizeof dev->name,"UVC Camera (%04x:%04x)",le16_to_cpu(udev->descriptor.idVendor),le16_to_cpu(udev->descriptor.idProduct));
/* Parse the Video Class control descriptor. */
if (uvc_parse_control(dev) < 0) { //-->5 uvc解析usb視訊類控制描述符
uvc_trace(UVC_TRACE_PROBE, "Unable to parse UVC descriptors.\n");
goto error;
}
uvc_printk(KERN_INFO, "Found UVC %u.%02x device %s (%04x:%04x)\n",dev->uvc_version >> 8, dev->uvc_version & 0xff,
udev->product ? udev->product : "<unnamed>",le16_to_cpu(udev->descriptor.idVendor),le16_to_cpu(udev->descriptor.idProduct));
if (dev->quirks != id->driver_info) {
uvc_printk(KERN_INFO, "Forcing device quirks to 0x%x by module parameter for testing purpose.\n", dev->quirks);
uvc_printk(KERN_INFO, "Please report required quirks to the linux-uvc-devel mailing list.\n");
}
/* Initialize controls. */
if (uvc_ctrl_init_device(dev) < 0) //8.uvc初始化控制
goto error;
/* Scan the device for video chains. */
if (uvc_scan_device(dev) < 0) //10.uvc掃描視訊鏈
goto error;
/* Register video devices. */
if (uvc_register_chains(dev) < 0) //11.uvc註冊視訊裝置
goto error;
/* Save our data pointer in the interface data. */
usb_set_intfdata(intf, dev); //設定uvc裝置為usb介面的資料
/* Initialize the interrupt URB. */
if ((ret = uvc_status_init(dev)) < 0) { //12 uvc裝置狀態初始化
uvc_printk(KERN_INFO, "Unable to initialize the status endpoint (%d), status interrupt will not be supported.\n", ret);
}
uvc_trace(UVC_TRACE_PROBE, "UVC device initialized.\n");
usb_enable_autosuspend(udev); //使能自動掛起
return 0;
error:
uvc_unregister_video(dev);
return -ENODEV;
}
4.1 uvc裝置結構體
struct uvc_device {
struct usb_device *udev; //usb裝置指標
struct usb_interface *intf; //usb介面指標
unsigned long warnings;
__u32 quirks;
int intfnum; //介面數
char name[32]; //裝置名
enum uvc_device_state state; //uvc裝置狀態
atomic_t users;
atomic_t nmappings;
/* Video control interface */
__u16 uvc_version; //UVC協議版本
__u32 clock_frequency; //時鐘頻率
struct list_head entities; //uvc實體連結串列頭(掛著uvc裝置的Terminal和Unit)
struct list_head chains; //uvc視訊鏈連結串列頭
/* Video Streaming interfaces */
struct list_head streams; //uvc視訊流連結串列頭
atomic_t nstreams;//uvc視訊流個數
/* Status Interrupt Endpoint */
struct usb_host_endpoint *int_ep; //usb_host_endpoint物件
struct urb *int_urb; //中斷urb
__u8 *status; //uvc裝置狀態標誌
struct input_dev *input; //輸入裝置
char input_phys[64]; //輸入裝置裝置節點路徑
};
4.2 uvc協議標準上的描述符佈局
-->(Interface Association Descript)IDA介面描述符
-->標準VC介面描述符 --------------------------------VC(video control)
-->uvc類視訊介面描述符(header)-->輸入Terminal介面描述符-->處理Unit介面描述符-->編碼Unit介面描述符-->輸出Terminal介面描述符
-->標準中斷端點描述符
-->uvc類中斷端點描述符
-->標準VS介面描述符 --------------------------------VS(video streaming) Alt.Setting 0
-->uvc類視訊介面描述符(header)-->format負荷格式描述符-->若干frame-->靜態影象幀格式描述符
-->uvc類視訊介面描述符(header)-->format負荷格式描述符-->若干frame-->靜態影象幀格式描述符->顏色匹配描述符
...(1...n)
-->Bulk-in 靜態影象資料端點描述符
-->標準VS介面描述符 --------------------------------VS(video streaming) Alt.Setting 1
-->標準同步輸入視訊端點描述符
-->Bulk-in 靜態影象資料端點描述符
...(1...n)
-->標準VS介面描述符 --------------------------------VS(video streaming) Alt.Setting n
-->標準同步輸入視訊端點描述符
-->Bulk-in 靜態影象資料端點描述符
這些佈局是可變的 但大體佈局是這樣,下面兩張圖也是典型的佈局
具體分析的時候可以利用lsubs工具列印所有描述符來分析
usb描述符的框架圖
輸入命令lsusb -d 0c45:62f1 -v
Bus 001 Device 002: ID 0c45:62f1 Microdia //匯流排 裝置ID
Device Descriptor: //裝置描述符
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 239 Miscellaneous Device
bDeviceSubClass 2 ?
bDeviceProtocol 1 Interface Association
bMaxPacketSize0 64
idVendor 0x0c45 Microdia
idProduct 0x62f1
bcdDevice 1.00
iManufacturer 2 Sonix Technology Co., Ltd.
iProduct 1 USB 2.0 Camera
iSerial 0
bNumConfigurations 1
Configuration Descriptor: //配置描述符
bLength 9
bDescriptorType 2
wTotalLength 697
bNumInterfaces 4
bConfigurationValue 1
iConfiguration 0
bmAttributes 0x80
(Bus Powered)
MaxPower 500mA
Interface Association: //3.6 Interface Association Descriptor
bLength 8
bDescriptorType 11
bFirstInterface 0
bInterfaceCount 2
bFunctionClass 14 Video
bFunctionSubClass 3 Video Interface Collection
bFunctionProtocol 0
iFunction 5 USB Camera
Interface Descriptor: //Table 3-2 Standard VC Interface Descriptor
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 14 Video
bInterfaceSubClass 1 Video Control
bInterfaceProtocol 0
iInterface 5 USB Camera
VideoControl Interface Descriptor: //Table 3-3 Class-specific VC Interface Header Descriptor
bLength 13
bDescriptorType 36
bDescriptorSubtype 1 (HEADER)
bcdUVC 1.00
wTotalLength 103
dwClockFrequency 15.000000MHz
bInCollection 1
baInterfaceNr( 0) 1
VideoControl Interface Descriptor: //Table 3-5 Output Terminal Descriptor
bLength 9
bDescriptorType 36
bDescriptorSubtype 3 (OUTPUT_TERMINAL)
bTerminalID 2
wTerminalType 0x0101 USB Streaming
bAssocTerminal 0
bSourceID 5
iTerminal 0
VideoControl Interface Descriptor: //Table 3-10 Extension Unit Descriptor
bLength 26
bDescriptorType 36
bDescriptorSubtype 6 (EXTENSION_UNIT)
bUnitID 4
guidExtensionCode {7033f028-1163-2e4a-ba2c-6890eb334016}
bNumControl 8
bNrPins 1
baSourceID( 0) 3
bControlSize 1
bmControls( 0) 0x0f
iExtension 0
VideoControl Interface Descriptor: //Table 3-10 Extension Unit Descriptor
bLength 26
bDescriptorType 36
bDescriptorSubtype 6 (EXTENSION_UNIT)
bUnitID 5
guidExtensionCode {3fae1228-d7bc-114e-a357-6f1edef7d61d}
bNumControl 8
bNrPins 1
baSourceID( 0) 4
bControlSize 1
bmControls( 0) 0xff
iExtension 0
VideoControl Interface Descriptor: //Table 3-6 Camera Terminal Descriptor
bLength 18
bDescriptorType 36
bDescriptorSubtype 2 (INPUT_TERMINAL)
bTerminalID 1
wTerminalType 0x0201 Camera Sensor
bAssocTerminal 0
iTerminal 0
wObjectiveFocalLengthMin 0
wObjectiveFocalLengthMax 0
wOcularFocalLength 0
bControlSize 3
bmControls 0x00000000
VideoControl Interface Descriptor: //Table 3-8 Processing Unit Descriptor
bLength 11
bDescriptorType 36
bDescriptorSubtype 5 (PROCESSING_UNIT)
Warning: Descriptor too short
bUnitID 3
bSourceID 1
wMaxMultiplier 0
bControlSize 2
bmControls 0x0000053f
Brightness
Contrast
Hue
Saturation
Sharpness
Gamma
Backlight Compensation
Power Line Frequency
iProcessing 0
bmVideoStandards 0x 0
Endpoint Descriptor: //Table 3-11 Standard VC Interrupt Endpoint Descriptor
bLength 7
bDescriptorType 5
bEndpointAddress 0x83 EP 3 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0010 1x 16 bytes
bInterval 6
Interface Descriptor: //Table 3-13 Standard VS Interface Descriptor
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 0
bNumEndpoints 0
bInterfaceClass 14 Video
bInterfaceSubClass 2 Video Streaming
bInterfaceProtocol 0
iInterface 0
VideoStreaming Interface Descriptor: //Table 3-14 Class-specific VS Interface Input Header Descriptor
bLength 14
bDescriptorType 36
bDescriptorSubtype 1 (INPUT_HEADER)
bNumFormats 1
wTotalLength 323
bEndPointAddress 129
bmInfo 0
bTerminalLink 2
bStillCaptureMethod 2
bTriggerSupport 1
bTriggerUsage 1
bControlSize 1
bmaControls( 0) 27
VideoStreaming Interface Descriptor: //Table 3-1 Uncompressed Video Format Descriptor
bLength 27
bDescriptorType 36
bDescriptorSubtype 4 (FORMAT_UNCOMPRESSED)
bFormatIndex 1
bNumFrameDescriptors 5
guidFormat {59555932-0000-1000-8000-00aa00389b71}
bBitsPerPixel 16
bDefaultFrameIndex 1
bAspectRatioX 0
bAspectRatioY 0
bmInterlaceFlags 0x00
Interlaced stream or variable: No
Fields per frame: 1 fields
Field 1 first: No
Field pattern: Field 1 only
bCopyProtect 0
VideoStreaming Interface Descriptor: //Table 3-2 Uncompressed Video Frame Descriptors
bLength 50
bDescriptorType 36
bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
bFrameIndex 1
bmCapabilities 0x00
Still image unsupported
wWidth 640
wHeight 480
dwMinBitRate 24576000
dwMaxBitRate 147456000
dwMaxVideoFrameBufferSize 614400
dwDefaultFrameInterval 333333
bFrameIntervalType 6
dwFrameInterval( 0) 333333
dwFrameInterval( 1) 400000
dwFrameInterval( 2) 500000
dwFrameInterval( 3) 666666
dwFrameInterval( 4) 1000000
dwFrameInterval( 5) 2000000
VideoStreaming Interface Descriptor: //Table 3-2 Uncompressed Video Frame Descriptors
bLength 50
bDescriptorType 36
bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
bFrameIndex 2
bmCapabilities 0x00
Still image unsupported
wWidth 352
wHeight 288
dwMinBitRate 8110080
dwMaxBitRate 48660480
dwMaxVideoFrameBufferSize 202752
dwDefaultFrameInterval 333333
bFrameIntervalType 6
dwFrameInterval( 0) 333333
dwFrameInterval( 1) 400000
dwFrameInterval( 2) 500000
dwFrameInterval( 3) 666666
dwFrameInterval( 4) 1000000
dwFrameInterval( 5) 2000000
VideoStreaming Interface Descriptor: //Table 3-2 Uncompressed Video Frame Descriptors
bLength 50
bDescriptorType 36
bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
bFrameIndex 3
bmCapabilities 0x00
Still image unsupported
wWidth 320
wHeight 240
dwMinBitRate 6144000
dwMaxBitRate 36864000
dwMaxVideoFrameBufferSize 153600
dwDefaultFrameInterval 333333
bFrameIntervalType 6
dwFrameInterval( 0) 333333
dwFrameInterval( 1) 400000
dwFrameInterval( 2) 500000
dwFrameInterval( 3) 666666
dwFrameInterval( 4) 1000000
dwFrameInterval( 5) 2000000
VideoStreaming Interface Descriptor: //Table 3-2 Uncompressed Video Frame Descriptors
bLength 50
bDescriptorType 36
bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
bFrameIndex 4
bmCapabilities 0x00
Still image unsupported
wWidth 176
wHeight 144
dwMinBitRate 2027520
dwMaxBitRate 12165120
dwMaxVideoFrameBufferSize 50688
dwDefaultFrameInterval 333333
bFrameIntervalType 6
dwFrameInterval( 0) 333333
dwFrameInterval( 1) 400000
dwFrameInterval( 2) 500000
dwFrameInterval( 3) 666666
dwFrameInterval( 4) 1000000
dwFrameInterval( 5) 2000000
VideoStreaming Interface Descriptor: //Table 3-2 Uncompressed Video Frame Descriptors
bLength 50
bDescriptorType 36
bDescriptorSubtype 5 (FRAME_UNCOMPRESSED)
bFrameIndex 5
bmCapabilities 0x00
Still image unsupported
wWidth 160
wHeight 120
dwMinBitRate 1536000
dwMaxBitRate 9216000
dwMaxVideoFrameBufferSize 38400
dwDefaultFrameInterval 333333
bFrameIntervalType 6
dwFrameInterval( 0) 333333
dwFrameInterval( 1) 400000
dwFrameInterval( 2) 500000
dwFrameInterval( 3) 666666
dwFrameInterval( 4) 1000000
dwFrameInterval( 5) 2000000
VideoStreaming Interface Descriptor: //Table 3-18 Still Image Frame Descriptor
bLength 26
bDescriptorType 36
bDescriptorSubtype 3 (STILL_IMAGE_FRAME)
bEndpointAddress 0
bNumImageSizePatterns 5
wWidth( 0) 640
wHeight( 0) 480
wWidth( 1) 352
wHeight( 1) 288
wWidth( 2) 320
wHeight( 2) 240
wWidth( 3) 176
wHeight( 3) 144
wWidth( 4) 160
wHeight( 4) 120
bNumCompressionPatterns 5
VideoStreaming Interface Descriptor: //Table 3-19 Color Matching Descriptor
bLength 6
bDescriptorType 36
bDescriptorSubtype 13 (COLORFORMAT)
bColorPrimaries 1 (BT.709,sRGB)
bTransferCharacteristics 1 (BT.709)
bMatrixCoefficients 4 (SMPTE 170M (BT.601))
Interface Descriptor: //Table 3-13 Standard VS Interface Descriptor
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 1
bNumEndpoints 1
bInterfaceClass 14 Video
bInterfaceSubClass 2 Video Streaming
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 5
Transfer Type Isochronous
Synch Type Asynchronous
Usage Type Data
wMaxPacketSize 0x0080 1x 128 bytes
bInterval 1
Interface Descriptor: //Table 3-13 Standard VS Interface Descriptor
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 2
bNumEndpoints 1
bInterfaceClass 14 Video
bInterfaceSubClass 2 Video Streaming
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 5
Transfer Type Isochronous
Synch Type Asynchronous
Usage Type Data
wMaxPacketSize 0x0100 1x 256 bytes
bInterval 1
Interface Descriptor: //Table 3-13 Standard VS Interface Descriptor
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 3
bNumEndpoints 1
bInterfaceClass 14 Video
bInterfaceSubClass 2 Video Streaming
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor: //Table 3-20 Standard VS Isochronous Video Data Endpoint Descriptor
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 5
Transfer Type Isochronous
Synch Type Asynchronous
Usage Type Data
wMaxPacketSize 0x0320 1x 800 bytes
bInterval 1
Interface Descriptor: //Table 3-13 Standard VS Interface Descriptor
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 4
bNumEndpoints 1
bInterfaceClass 14 Video
bInterfaceSubClass 2 Video Streaming
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor: //Table 3-20 Standard VS Isochronous Video Data Endpoint Descriptor
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 5
Transfer Type Isochronous
Synch Type Asynchronous
Usage Type Data
wMaxPacketSize 0x0b20 2x 800 bytes
bInterval 1
Interface Descriptor: //Table 3-13 Standard VS Interface Descriptor
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 5
bNumEndpoints 1
bInterfaceClass 14 Video
bInterfaceSubClass 2 Video Streaming
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor: //Table 3-20 Standard VS Isochronous Video Data Endpoint Descriptor
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 5
Transfer Type Isochronous
Synch Type Asynchronous
Usage Type Data
wMaxPacketSize 0x1320 3x 800 bytes
bInterval 1
Interface Descriptor: //Table 3-13 Standard VS Interface Descriptor
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 6
bNumEndpoints 1
bInterfaceClass 14 Video
bInterfaceSubClass 2 Video Streaming
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor: //Table 3-20 Standard VS Isochronous Video Data Endpoint Descriptor
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 5
Transfer Type Isochronous
Synch Type Asynchronous
Usage Type Data
wMaxPacketSize 0x1400 3x 1024 bytes
bInterval 1
////////////////////////////////////////////////////////////////////////////音訊部分
Interface Association:
bLength 8
bDescriptorType 11
bFirstInterface 2
bInterfaceCount 2
bFunctionClass 1 Audio
bFunctionSubClass 0
bFunctionProtocol 0
iFunction 4 USB Microphone
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 2
bAlternateSetting 0
bNumEndpoints 0
bInterfaceClass 1 Audio
bInterfaceSubClass 1 Control Device
bInterfaceProtocol 0
iInterface 4 USB Microphone
AudioControl Interface Descriptor:
bLength 9
bDescriptorType 36
bDescriptorSubtype 1 (HEADER)
bcdADC 1.00
wTotalLength 41
bInCollection 1
baInterfaceNr( 0) 3
AudioControl Interface Descriptor:
bLength 12
bDescriptorType 36
bDescriptorSubtype 2 (INPUT_TERMINAL)
bTerminalID 1
wTerminalType 0x0201 Microphone
bAssocTerminal 0
bNrChannels 1
wChannelConfig 0x0000
iChannelNames 0
iTerminal 0
AudioControl Interface Descriptor:
bLength 11
bDescriptorType 36
bDescriptorSubtype 6 (FEATURE_UNIT)
bUnitID 2
bSourceID 1
bControlSize 2
bmaControls( 0) 0x01
bmaControls( 0) 0x00
Mute
bmaControls( 1) 0x02
bmaControls( 1) 0x00
Volume
iFeature 0
AudioControl Interface Descriptor:
bLength 9
bDescriptorType 36
bDescriptorSubtype 3 (OUTPUT_TERMINAL)
bTerminalID 3
wTerminalType 0x0101 USB Streaming
bAssocTerminal 0
bSourceID 2
iTerminal 0
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 3
bAlternateSetting 0
bNumEndpoints 0
bInterfaceClass 1 Audio
bInterfaceSubClass 2 Streaming
bInterfaceProtocol 0
iInterface 0
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 3
bAlternateSetting 1
bNumEndpoints 1
bInterfaceClass 1 Audio
bInterfaceSubClass 2 Streaming
bInterfaceProtocol 0
iInterface 0
AudioStreaming Interface Descriptor:
bLength 7
bDescriptorType 36
bDescriptorSubtype 1 (AS_GENERAL)
bTerminalLink 3
bDelay 1 frames
wFormatTag 1 PCM
AudioStreaming Interface Descriptor:
bLength 29
bDescriptorType 36
bDescriptorSubtype 2 (FORMAT_TYPE)
bFormatType 1 (FORMAT_TYPE_I)
bNrChannels 1
bSubframeSize 2
bBitResolution 16
bSamFreqType 7 Discrete
tSamFreq[ 0] 8000
tSamFreq[ 1] 11025
tSamFreq[ 2] 16000
tSamFreq[ 3] 22050
tSamFreq[ 4] 24000
tSamFreq[ 5] 44100
tSamFreq[ 6] 48000
Endpoint Descriptor:
bLength 9
bDescriptorType 5
bEndpointAddress 0x84 EP 4 IN
bmAttributes 5
Transfer Type Isochronous
Synch Type Asynchronous
Usage Type Data
wMaxPacketSize 0x0190 1x 400 bytes
bInterval 4
bRefresh 0
bSynchAddress 0
AudioControl Endpoint Descriptor:
bLength 7
bDescriptorType 37
bDescriptorSubtype 1 (EP_GENERAL)
bmAttributes 0x01
Sampling Frequency
bLockDelayUnits 0 Undefined
wLockDelay 0 Undefined
/////////////////////////////////////////////////////////////////
Device Qualifier (for other device speed): //裝置限定符
bLength 10
bDescriptorType 6
bcdUSB 2.00
bDeviceClass 239 Miscellaneous Device
bDeviceSubClass 2 ?
bDeviceProtocol 1 Interface Association
bMaxPacketSize0 64
bNumConfigurations 1
Device Status: 0x0002
(Bus Powered)
Remote Wakeup Enabled
可以通過描述符佈局,分析出攝像頭框架
第一步找出Terminal和Unit的(bTerminalID/bUnitID)
IT(1)
OT(2)
XU(4)
XU(5)
PU(3)
第二步從OT輸出Terminal開始分析
OT(2)的bSourceID=5
所以XU(5)->OT(2)
XU(5)的bNrPins=1所以只有一個輸入baSourceID( 0)=4
所以XU(4)->XU(5)->OT(2)
XU(4)的bNrPins=1所以只有一個輸入baSourceID( 0)=3
所以PU(3)->XU(4)->XU(5)->OT(2)
PU(3)的bSourceID=1
所以IT(1)->PU(3)->XU(4)->XU(5)->OT(2)
4.3 probe方法初始化uvc裝置結構體物件
5 uvc解析usb視訊類控制描述符
static int uvc_parse_control(struct uvc_device *dev)
{
struct usb_host_interface *alts = dev->intf->cur_altsetting; //獲取當前usb_host_interface
unsigned char *buffer = alts->extra; //額外描述符
int buflen = alts->extralen; //額外描述符長度
int ret;
/* 解析預設的交替設定,正如UVC標準協議定義的單個交替設定,預設是交替設定0(Alt.Setting 0)*/
while (buflen > 2) {
if (uvc_parse_vendor_control(dev, buffer, buflen) || buffer[1] != USB_DT_CS_INTERFACE) //5.1解析廠商特殊控制
goto next_descriptor; //特殊廠商處理則直接跳過標準處理
}
if ((ret = uvc_parse_standard_control(dev, buffer, buflen)) < 0) //5.2.解析uvc標準控制
return ret;
next_descriptor: //buffer[0]是bLength描述符長度
buflen -= buffer[0]; //調整buflen長度
buffer += buffer[0]; //調整buffer指標
}
//判斷描述符是否有1個端點
if (alts->desc.bNumEndpoints == 1 && !(dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT)) {
struct usb_host_endpoint *ep = &alts->endpoint[0]; //獲取usb_host_endpoint
struct usb_endpoint_descriptor *desc = &ep->desc; //獲取端點描述符
//判斷是否中斷輸入端點
if (usb_endpoint_is_int_in(desc) && le16_to_cpu(desc->wMaxPacketSize) >= 8 && desc->bInterval != 0) {
uvc_trace(UVC_TRACE_DESCR, "Found a Status endpoint (addr %02x).\n", desc->bEndpointAddress);
dev->int_ep = ep;
}
}
return 0;
}
5.1 解析廠商特殊控制 (特殊廠商處理返回1,不是返回0)
static int uvc_parse_vendor_control(struct uvc_device *dev,const unsigned char *buffer, int buflen)
{
struct usb_device *udev = dev->udev;
struct usb_host_interface *alts = dev->intf->cur_altsetting; //獲取usb_host_interface
struct uvc_entity *unit;
unsigned int n, p;
int handled = 0; //返回值 預設為0
switch (le16_to_cpu(dev->udev->descriptor.idVendor)) {
case 0x046d: /* Logitech 羅技*/
...
handled = 1; //特殊廠商處理則返回1
break;
}
return handled;
}
5.1.1 uvc實體結構體
struct uvc_entity { //uvc實體
struct list_head list; //實體連結串列頭
struct list_head chain; //視訊鏈連結串列頭
__u8 id; //實體id
__u16 type; //實體型別
char name[64]; //實體名
union {
struct {
__u16 wObjectiveFocalLengthMin;
__u16 wObjectiveFocalLengthMax;
__u16 wOcularFocalLength;
__u8 bControlSize; //控制位域大小
__u8 *bmControls; //控制點陣圖指標
} camera; //輸入Terminal UVC_ITT_CAMERA
struct {
__u8 bControlSize; //控制位域大小
__u8 *bmControls; //控制點陣圖指標
__u8 bTransportModeSize;
__u8 *bmTransportModes;
} media; //輸入Terminal UVC_ITT_MEDIA_TRANSPORT_INPUT
struct {
} output; //輸出Terminal
//處理Unit
struct {
__u16 wMaxMultiplier;
__u8 bControlSize; //控制位域大小
__u8 *bmControls; //控制點陣圖指標
__u8 bmVideoStandards;
} processing; //處理Unit
//選擇器Unit
struct {
} selector; //選擇器Unit
//擴充套件Unit
struct {
__u8 guidExtensionCode[16];
__u8 bNumControls;
__u8 bControlSize; //控制位域大小
__u8 *bmControls; //控制點陣圖指標
__u8 *bmControlsType;
} extension; //擴充套件Unit
};
__u8 bNrInPins; //輸入引腳數
__u8 *baSourceID; //第一個輸入引腳ID(Terminal/Unit ID)
unsigned int ncontrols; //uvc控制個數
struct uvc_control *controls; //ucv控制陣列指標
};
5.2 解析uvc標準控制
static int uvc_parse_standard_control(struct uvc_device *dev,const unsigned char *buffer, int buflen)
{
struct usb_device *udev = dev->udev; //獲取usb裝置
struct uvc_entity *unit, *term; //uvc實體Unit或Terminal
struct usb_interface *intf; //usb介面
struct usb_host_interface *alts = dev->intf->cur_altsetting; //獲取當前usb介面配置描述符
unsigned int i, n, p, len;
__u16 type;
switch (buffer[2]) { //buffer[2]存放bDescriptorSubType
case UVC_VC_HEADER: //vc 介面頭部描述符
n = buflen >= 12 ? buffer[11] : 0; //bInCollection 視訊流介面數
if (buflen < 12 || buflen < 12 + n) {
uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol interface %d HEADER error\n", udev->devnum,alts->desc.bInterfaceNumber);
return -EINVAL;
}
dev->uvc_version = get_unaligned_le16(&buffer[3]); //bcdUVC
dev->clock_frequency = get_unaligned_le32(&buffer[7]); //獲取時鐘頻率
/* Parse all USB Video Streaming interfaces. 解析所有USB視訊介面*/
for (i = 0; i < n; ++i) { //遍歷視訊流介面
intf = usb_ifnum_to_if(udev, buffer[12+i]); //baInterfaceNr(n) 獲取視訊流對應的usb介面
if (intf == NULL) {
uvc_trace(UVC_TRACE_DESCR, "device %d interface %d doesn't exists\n",udev->devnum, i);
continue;
}
uvc_parse_streaming(dev, intf); //6.uvc解析uvc視訊流
}
break;
case UVC_VC_INPUT_TERMINAL: //UVC輸入Terminal
if (buflen < 8) { //檢驗buflen長度
uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol interface %d INPUT_TERMINAL error\n",udev->devnum, alts->desc.bInterfaceNumber);
return -EINVAL;
}
/* Make sure the terminal type MSB is not null, otherwise it could be confused with a unit.*/
type = get_unaligned_le16(&buffer[4]); //獲取Terminal型別(ITT_ VENDOR_SPECIFIC/ITT_CAMERA/ITT_MEDIA_TRANSPORT_INPUT)
if ((type & 0xff00) == 0) { //錯誤型別
uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol interface %d INPUT_TERMINAL %d has invalid type 0x%04x, skipping\n", udev->devnum,alts->desc.bInterfaceNumber,buffer[3], type);
return 0;
}
n = 0;
p = 0;
len = 8; //標準長度(0~7)
if (type == UVC_ITT_CAMERA) { //攝像頭感測器 (speciafication.pdf P67)
n = buflen >= 15 ? buffer[14] : 0; //bControlSize 控制位域大小
len = 15;
}
else if (type == UVC_ITT_MEDIA_TRANSPORT_INPUT) { //連續的媒體 (USB_Video_Transport_1.5.pdf P11)
n = buflen >= 9 ? buffer[8] : 0; //bControlSize 控制位域大小
p = buflen >= 10 + n ? buffer[9+n] : 0; //bmTransportModesSize 傳輸模式位域大小
len = 10;
}
if (buflen < len + n + p) { //檢驗buflen長度是否合適
uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol interface %d INPUT_TERMINAL error\n",udev->devnum, alts->desc.bInterfaceNumber);
return -EINVAL;
}
term = uvc_alloc_entity(type | UVC_TERM_INPUT, buffer[3],1, n + p); //分配uvc實體 buffer[3]是實體ID
if (term == NULL)
return -ENOMEM;
if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA) { //攝像頭感測器
term->camera.bControlSize = n; //bControlSize 控制位域大小
term->camera.bmControls = (__u8 *)term + sizeof *term; //bmControls 控制點陣圖指標
term->camera.wObjectiveFocalLengthMin = get_unaligned_le16(&buffer[8]); // wObjectiveFocalLengthMin 焦點長度最小值
term->camera.wObjectiveFocalLengthMax = get_unaligned_le16(&buffer[10]); //wObjectiveFocalLengthMax 焦點長度最大值
term->camera.wOcularFocalLength = get_unaligned_le16(&buffer[12]); //wOcularFocalLength Ocular焦距
memcpy(term->camera.bmControls, &buffer[15], n); //初始化控制點陣圖
}
else if (UVC_ENTITY_TYPE(term) == UVC_ITT_MEDIA_TRANSPORT_INPUT) { //連續的媒體
term->media.bControlSize = n; //bControlSize 控制位域大小
term->media.bmControls = (__u8 *)term + sizeof *term; //bmControls控制點陣圖指標
term->media.bTransportModeSize = p; //bTransportModeSize 傳輸模式位域大小
term->media.bmTransportModes = (__u8 *)term + sizeof *term + n; //bmTransportModes傳輸模式點陣圖指標
memcpy(term->media.bmControls, &buffer[9], n); //初始化控制點陣圖
memcpy(term->media.bmTransportModes, &buffer[10+n], p); //初始化傳輸模式點陣圖
}
if (buffer[7] != 0) //設定實體名
usb_string(udev, buffer[7], term->name,sizeof term->name);
else if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA) //設定Camera Terminal實體名
sprintf(term->name, "Camera %u", buffer[3]);
else if (UVC_ENTITY_TYPE(term) == UVC_ITT_MEDIA_TRANSPORT_INPUT) //設定Media Terminal實體名
sprintf(term->name, "Media %u", buffer[3]);
else
sprintf(term->name, "Input %u", buffer[3]);
list_add_tail(&term->list, &dev->entities); //新增uvc實體到uvc實體連結串列中
break;
case UVC_VC_OUTPUT_TERMINAL: //UVC輸出Terminal
if (buflen < 9) { //檢驗buflen長度
uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol interface %d OUTPUT_TERMINAL error\n",udev->devnum, alts->desc.bInterfaceNumber);
return -EINVAL;
}
/* Make sure the terminal type MSB is not null, otherwise it could be confused with a unit.*/
type = get_unaligned_le16(&buffer[4]); //wTerminalType 輸出Terminal型別
if ((type & 0xff00) == 0) {
uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol interface %d OUTPUT_TERMINAL %d has invalid type 0x%04x, skipping\n", udev->devnum,
alts->desc.bInterfaceNumber, buffer[3], type);
return 0;
}
term = uvc_alloc_entity(type | UVC_TERM_OUTPUT, buffer[3],1, 0); //分配uvc實體 buffer[3]是實體ID
if (term == NULL)
return -ENOMEM;
memcpy(term->baSourceID, &buffer[7], 1); //複製Terminal ID到baSourceID
if (buffer[8] != 0) //設定Terminal實體名
usb_string(udev, buffer[8], term->name,sizeof term->name);
else //設定output Terminal實體名
sprintf(term->name, "Output %u", buffer[3]);
list_add_tail(&term->list, &dev->entities); //新增uvc實體到uvc實體連結串列中
break;
case UVC_VC_SELECTOR_UNIT: //UVC選擇器Unit
p = buflen >= 5 ? buffer[4] : 0; //Unit輸入引腳數
if (buflen < 5 || buflen < 6 + p) { //檢驗buflen是否符合
uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol interface %d SELECTOR_UNIT error\n",udev->devnum, alts->desc.bInterfaceNumber);
return -EINVAL;
}
unit = uvc_alloc_entity(buffer[2], buffer[3], p + 1, 0); //分配uvc實體 buffer[3]是實體ID
if (unit == NULL)
return -ENOMEM;
memcpy(unit->baSourceID, &buffer[5], p); //複製Unit ID到bSourceID
if (buffer[5+p] != 0) //設定selector Unit名
usb_string(udev, buffer[5+p], unit->name,sizeof unit->name);
else
sprintf(unit->name, "Selector %u", buffer[3]);
list_add_tail(&unit->list, &dev->entities); //新增uvc實體到uvc實體連結串列中
break;
case UVC_VC_PROCESSING_UNIT: //UVC處理Unit
n = buflen >= 8 ? buffer[7] : 0; //bControlSize控制位域大小
p = dev->uvc_version >= 0x0110 ? 10 : 9; //uvc類協議版本
if (buflen < p + n) { //檢驗buflen長度是否符合
uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol interface %d PROCESSING_UNIT error\n",udev->devnum, alts->desc.bInterfaceNumber);
return -EINVAL;
}
unit = uvc_alloc_entity(buffer[2], buffer[3], 2, n); //分配uvc實體 buffer[3]是實體ID
if (unit == NULL)
return -ENOMEM;
memcpy(unit->baSourceID, &buffer[4], 1); //複製Unit ID到bSourceID
unit->processing.wMaxMultiplier = get_unaligned_le16(&buffer[5]); //最大數字放大率
unit->processing.bControlSize = buffer[7]; //bControlSize 控制位域大小
unit->processing.bmControls = (__u8 *)unit + sizeof *unit; //bmControls控制點陣圖指標
memcpy(unit->processing.bmControls, &buffer[8], n); //初始化控制點陣圖
if (dev->uvc_version >= 0x0110) //版本大於1.1
unit->processing.bmVideoStandards = buffer[9+n]; //設定視訊標準支援點陣圖
if (buffer[8+n] != 0) //設定處理Unit名
usb_string(udev, buffer[8+n], unit->name,sizeof unit->name);
else
sprintf(unit->name, "Processing %u", buffer[3]);
list_add_tail(&unit->list, &dev->entities); //新增uvc實體到uvc實體連結串列中
break;
case UVC_VC_EXTENSION_UNIT: //UVC擴充套件Unit
p = buflen >= 22 ? buffer[21] : 0; //Unit輸入引腳數
n = buflen >= 24 + p ? buffer[22+p] : 0; //bControlSize控制位域長度
if (buflen < 24 + p + n) { //判斷buflen長度是否符合
uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol interface %d EXTENSION_UNIT error\n",udev->devnum, alts->desc.bInterfaceNumber);
return -EINVAL;
}
unit = uvc_alloc_entity(buffer[2], buffer[3], p + 1, n); //分配uvc實體 buffer[3]是實體ID
if (unit == NULL)
return -ENOMEM;
memcpy(unit->extension.guidExtensionCode, &buffer[4], 16); //guidExtensionCode 廠商特殊<span class="wp_keywordlink" style="margin: 0px; padding: 0px; border: 0px; background: transparent;"><a target=_blank href="http://www.xuebuyuan.com/" title="程式碼" target="_blank" style="text-decoration: none; color: rgb(1, 150, 227);">程式碼</a></span>id
unit->extension.bNumControls = buffer[20]; //Unit的控制元件數
memcpy(unit->baSourceID, &buffer[22], p); //複製Unit ID到baSourceID
unit->extension.bControlSize = buffer[22+p]; //bControlSize 控制位域大小
unit->extension.bmControls = (__u8 *)unit + sizeof *unit; //bmControls控制點陣圖指標
memcpy(unit->extension.bmControls, &buffer[23+p], n); //初始化控制點陣圖
if (buffer[23+p+n] != 0) //設定擴充套件Unit實體名
usb_string(udev, buffer[23+p+n], unit->name,sizeof unit->name);
else
sprintf(unit->name, "Extension %u", buffer[3]);
list_add_tail(&unit->list, &dev->entities); //新增uvc實體到uvc實體連結串列中
break;
default:
uvc_trace(UVC_TRACE_DESCR, "Found an unknown CS_INTERFACE descriptor (%u)\n", buffer[2]);
break;
}
return 0;
}
5.2.1 新增uvc實體到uvc裝置的實體連結串列下
list_add_tail(&term->list, &dev->entities);
5.2.2 分配uvc實體
staticstruct uvc_entity *uvc_alloc_entity(u16 type, u8 id,unsigned int num_pads, unsigned int extra_size)
case VC_INPUT_TERMINAL(n=bControlSize控制位域長度,p=bmTransportModesSize 傳輸模式位域大小)
term = uvc_alloc_entity(type | UVC_TERM_INPUT, buffer[3],1, n + p); //輸入Terminal只有一個pad
case VC_OUTPUT_TERMINAL
term = uvc_alloc_entity(type | UVC_TERM_OUTPUT, buffer[3],1, 0); //輸出Terminal只有一個pad
case VC_SELECTOR_UNIT:(p=Unit輸入引腳數)
unit = uvc_alloc_entity(buffer[2], buffer[3], p + 1, 0); //選擇Unit有p個輸入pad,1個輸出pad
case VC_PROCESSING_UNIT(n=bControlSize控制位域長度)
unit = uvc_alloc_entity(buffer[2], buffer[3], 2, n); //處理Unit只有1個輸入pad,1個輸出pad
case VC_EXTENSION_UNIT(n=bControlSize控制位域長度,p=Unit輸入引腳數)
unit = uvc_alloc_entity(buffer[2], buffer[3], p + 1, n); //擴充套件Unit有p個輸入pad,1個輸出pad
這裡的pad可以理解為規範書上說的pin,畫了個圈圈那個叫做"pad"
static struct uvc_entity *uvc_alloc_entity(u16 type, u8 id,unsigned int num_pads, unsigned int extra_size)
{
struct uvc_entity *entity;
unsigned int num_inputs;
unsigned int size;
num_inputs = (type & UVC_TERM_OUTPUT) ? num_pads : num_pads - 1; //輸入Terminal個數=pad個數-1個輸出Terminal
size = sizeof(*entity) + extra_size + num_inputs; //uvc實體大小+額外尺寸+輸入Ternimal個數
entity = kzalloc(size, GFP_KERNEL); //分配uvc實體記憶體
if (entity == NULL)
return NULL;
entity->id = id; //設定uvc實體id
entity->type = type; //設定uvc實體型別
entity->bNrInPins = num_inputs; //設定uvc實體輸入Terminal個數
entity->baSourceID = ((__u8 *)entity) + sizeof(*entity) + extra_size; //Ternimal ID指標
return entity;
}
這裡extra_size是給uvc實體的聯合體中的*指標變數(*bmControls、*bmTransportModes;)分配記憶體空間,而num_inputs是給*baSourceID(指向輸入Terminal ID)分配記憶體空間