LINUX&UVC驱动的uvc_probe函数主体分析
UVC驱动的prob函数原型如下:
static int uvc_probe(struct usb_interface *intf,
const struct usb_device_id *id);
这是由USBCore回调并提供相关的USB逻辑设备相关的参数,这我们在上一节已经分析过了。
对于UVC设备,和其它类驱动一样,也会创建自己的设备对象来代表自己是驱动中的一层,所以这里UVC驱动定义的设备结构体就是uvc_device。
其结构体如下:
struct uvc_device {
struct usb_device *udev;
struct usb_interface *intf;
unsigned long warnings;
u32 quirks;
int intfnum;
char name[32];
const struct uvc_device_info *info;
struct mutex lock; /* Protects users */
unsigned int users;
atomic_t nmappings;
/* Video control interface */
#ifdef CONFIG_MEDIA_CONTROLLER
struct media_device mdev;
#endif
struct v4l2_device vdev;
u16 uvc_version;
u32 clock_frequency;
struct list_head entities;
struct list_head chains;
/* Video Streaming interfaces */
struct list_head streams;
struct kref ref;
/* Status Interrupt Endpoint */
struct usb_host_endpoint *int_ep;
struct urb *int_urb;
u8 *status;
struct input_dev *input;
char input_phys[64];
struct uvc_ctrl_work {
struct work_struct work;
struct urb *urb;
struct uvc_video_chain *chain;
struct uvc_control *ctrl;
const void *data;
} async_ctrl;
};
可以看到,这里不仅包括了USB设备对象本身相关的信息,也有UVC类设备特有的东西,如视频控制接口,视频流接口等。
1.在uvc_probe中,进行必要的信息验证后,就应该和Windows驱动调用IoCreateDevice创建本层的设备对象一样,UVC驱动申请本层设备驱动的设备对象结构体。
struct uvc_device *dev;
...
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
2.对申请的结构体对象进行初始化,并保存该逻辑USB设备对象的相关信息。
INIT_LIST_HEAD(&dev->entities);
INIT_LIST_HEAD(&dev->chains);
INIT_LIST_HEAD(&dev->streams);
kref_init(&dev->ref);
atomic_set(&dev->nmappings, 0);
mutex_init(&dev->lock);
dev->udev = usb_get_dev(udev);
dev->intf = usb_get_intf(intf);
dev->intfnum = intf->cur_altsetting->desc.bInterfaceNumber;
...
3.UVC规范定义的UVC设备,至少有一个视频控制接口和0个或者多个视频流接口(实际一般只有一个视频接口)
/* Parse the Video Class control descriptor. */
if (uvc_parse_control(dev) < 0) {
uvc_trace(UVC_TRACE_PROBE, "Unable to parse UVC "
"descriptors.\n");
goto error;
}
使用uvc_parse_control解析该UVC设备的配置描述符,解析出需要的信息。
4.与V4L2扯上关系,使用v4l2_device_register函数。
第一个参数intf->dev是LINUX系统层的设备struct device *dev
。
第二个是V4L2设备,由v4l2_device_register初始化,但其位于struct uvc_device结构体中。
/* Register the V4L2 device. */
if (v4l2_device_register(&intf->dev, &dev->vdev) < 0)
goto error;
4.初始化UVC控制接口中的各种Unit或者Terminal,比如UVC扩展单元,UVC相机终端单元,UVC处理单元等,这些支持的UVC特定类请求。
/* Initialize controls. */
if (uvc_ctrl_init_device(dev) < 0)
goto error;
5.这一块没看,估计与视频流接口中UVC设备的格式,分辨率等相关。
/* Scan the device for video chains. */
if (uvc_scan_device(dev) < 0)
goto error;
/* Register video device nodes. */
if (uvc_register_chains(dev) < 0)
goto error;
6.将UVC对象保留在USBCore对象给的私有数据成员中。
/* Save our data pointer in the interface data. */
usb_set_intfdata(intf, dev);
详见:存储驱动私有数据 https://www.usbzh.com/article/detail-1318.html
7.初始化中断状态。这应与UVC控制接口某些设备中有一些中断端点,用于向主机上报其错误状态。当然如这个中断端点是可选的。
/* Initialize the interrupt URB. */
if ((ret = uvc_status_init(dev)) < 0) {
uvc_printk(KERN_INFO, "Unable to initialize the status "
"endpoint (%d), status interrupt will not be "
"supported.\n", ret);
}
8.设备就绪-自动挂起
usb_enable_autosuspend(udev);
奇怪的问题
int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
{
...
if (!dev_get_drvdata(dev))
dev_set_drvdata(dev, v4l2_dev);
return 0;
}
static inline void usb_set_intfdata(struct usb_interface *intf, void *data)
{
dev_set_drvdata(&intf->dev, data);
}
UVC驱动中的prob函数中,会调用如下2行代码
v4l2_device_register(&intf->dev, &dev->vdev) < 0);
usb_set_intfdata(intf, dev);
但从结果上来看,最终都是设置的是intf->dev的私有数据,
那么前面调用的v4l2_device_register是不是就没有意义了,因为会被usb_set_intfdata又被覆盖了.
这是为啥?
其实在disconnect函数中可以解释,确实是覆盖了。
struct uvc_driver uvc_driver = {
.driver = {
...
.disconnect = uvc_disconnect,
...
},
};
函数实现如下:
static void uvc_disconnect(struct usb_interface *intf)
{
struct uvc_device *dev = usb_get_intfdata(intf);
/* Set the USB interface data to NULL. This can be done outside the
* lock, as there's no other reader.
*/
usb_set_intfdata(intf, NULL);
if (intf->cur_altsetting->desc.bInterfaceSubClass ==
UVC_SC_VIDEOSTREAMING)
return;
uvc_unregister_video(dev);
kref_put(&dev->ref, uvc_delete);
}
其通过usb_get_intfdata获取的接口设备的私有数据为uvc_device,其正好对应的是
usb_set_intfdata(intf, dev);
最后就是反注册uvc设备,使用uvc_unregister_video,最后删除申请的内存数据。