uvc摄像头代码解析之描述符

1.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实体

static struct 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)分配内存空间


  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值