LINUX&UVC驱动的uvc_probe函数之参数分析
当一个UVC设备被USBCore识别后,会调用UVC驱动的probe函数。这个probe函数就是Windows驱动中类似的AddDevice回调。
struct uvc_driver uvc_driver = {
.driver = {
.name = "uvcvideo",
.probe = uvc_probe,
.disconnect = uvc_disconnect,
.suspend = uvc_suspend,
.resume = uvc_resume,
.reset_resume = uvc_reset_resume,
.id_table = uvc_ids,
.supports_autosuspend = 1,
},
};
回调函数uvc_probe的原型如下:
static int uvc_probe(struct usb_interface *intf,
const struct usb_device_id *id)
其两个入参是由USBCore提供的。
第一个参数可以看到是usb_interface的指针,而不是usb_device类型的指针。这就涉及到usb规范的定义了。USB设备一个物理设备可以支持多个逻辑设备,比如一个USB设备可以包括UVC相机,UAC相机,甚至再加一个HID设备。而USB设备的这种复合通过是通过接口描述符实现的。对于占用多个接口的USB设备,其通过接口关联描述符描述该设备占用的接口范围。所以这里可以充分理解USB接口描述符其实是描述USB功能的最小单位。这个最小单位就是单一的逻辑设备。
在Windows系统中,也有一个专门的驱动usbccgp来拆解USB物理设备的逻辑功能,但在LINUX系统中,这个体力活交给了USBCore了。
USB规范通过各个描述符定义了USB设备灵活多样的特征。一个USB设备可以有多个USB配置,一个USB设备又因其复合接口描述符而实现多个逻辑设备功能。而备用接口描述符引入的又可以让USB逻辑设备根据带宽的不同,提供不同质量的数据传输。在Linux系统中,这些都有对应的对构体来描述。其分别为usb_device,usb_host_config,usb_interface。
struct usb_interface {
/* array of alternate settings for this interface,
* stored in no particular order */
struct usb_host_interface *altsetting;
struct usb_host_interface *cur_altsetting; /* the currently
* active alternate setting */
unsigned num_altsetting; /* number of alternate settings */
/* If there is an interface association descriptor then it will list
* the associated interfaces */
struct usb_interface_assoc_descriptor *intf_assoc;
int minor; /* minor number this interface is
* bound to */
enum usb_interface_condition condition; /* state of binding */
unsigned sysfs_files_created:1; /* the sysfs attributes exist */
unsigned ep_devs_created:1; /* endpoint "devices" exist */
unsigned unregistering:1; /* unregistration is in progress */
unsigned needs_remote_wakeup:1; /* driver requires remote wakeup */
unsigned needs_altsetting0:1; /* switch to altsetting 0 is pending */
unsigned needs_binding:1; /* needs delayed unbind/rebind */
unsigned resetting_device:1; /* true: bandwidth alloc after reset */
unsigned authorized:1; /* used for interface authorization */
struct device dev; /* interface specific device info */
struct device *usb_dev;
struct work_struct reset_ws; /* for resets in atomic context */
};
对于usb_interface指针,可以通过函数interface_to_usbdev获取USB设备。
struct usb_device *udev = interface_to_usbdev(intf);
更详细的可详见:https://www.usbzh.com/article/detail-1317.html
第二个参数usb_device_id指针描述了该USB逻辑设备的基本信息。这里可以通过其结构体来查看:
struct usb_device_id {
/* which fields to match against? */
__u16 match_flags;
/* Used for product specific matches; range is inclusive */
__u16 idVendor;
__u16 idProduct;
__u16 bcdDevice_lo;
__u16 bcdDevice_hi;
/* Used for device class matches */
__u8 bDeviceClass;
__u8 bDeviceSubClass;
__u8 bDeviceProtocol;
/* Used for interface class matches */
__u8 bInterfaceClass;
__u8 bInterfaceSubClass;
__u8 bInterfaceProtocol;
/* Used for vendor-specific interface matches */
__u8 bInterfaceNumber;
/* not matched against */
kernel_ulong_t driver_info
__attribute__((aligned(sizeof(kernel_ulong_t))));
};
这些是通过解析USB设备描述符,USB接口描述符而获取到的。