赞
踩
对于一个usb摄像头,它的内核驱动源码位于/drivers/media/usb/uvc/
核心层:V4L2_dev.c文件
硬件相关层: uvc_driver.c文件
本篇记录基于对6.8.8.8内核下vivid-core.c文件(虚拟视频驱动程序)的分析,梳理Linux系统中vedio视频设备的驱动框架。
- module_init(vivid_init);
-
- vivid_init
- //注册vivid设备和驱动
- platform_device_register(&vivid_pdev);
- platform_driver_register(&vivid_pdrv);
通过入口函数将平台设备和平台驱动结构体注册到内核中,关于具体的设备和驱动注册先关内容可以看Linux--平台设备、平台驱动的注册源码分析-CSDN博客这篇。
在代码中,vivid_pdrv
平台驱动没有 of_match_table
字段,因为该驱动程序不依赖设备树进行匹配和初始化。如果是真实的硬件驱动程序需要支持设备树匹配,则需要定义 of_match_table
字段,并提供一个设备树兼容字符串数组,也就是compatible属性值。
在vivid_init()
里分别注册了vivid_pdev
和vivid_pdrv
,注册后,当他们匹配时,内核会自动则会调用该驱动程序probe()初始化该设备
。在probe()
里面主要进行初始化、注册等相关流程。
- vivid_probe
- 1) vivid_create_instance /* 创建实例 */
- dev = kzalloc(sizeof(*vivid_dev), GFP_KERNEL);/* 分配video_devicede */
- v4l2_device_register /* 初始化v4l2_device */
-
- 2) static int vivid_create_devnodes(struct platform_device *pdev,
- struct vivid_dev *dev, int inst,
- unsigned int cec_tx_bus_cnt,
- v4l2_std_id tvnorms_cap,
- v4l2_std_id tvnorms_out,
- unsigned in_type_counter[4],
- unsigned out_type_counter[4])
- {
- /* 设置video_device */
- 1.vfd->fops = &vivid_fops; /*也就是在probe里的这一步实现设备操作和驱动操作的绑定*/
- vfd->ioctl_ops = &vivid_ioctl_ops;
- vfd->release = video_device_release_empty;
- 2.vfd->v4l2_dev = &dev->v4l2_dev;
- 3.设置"ctrl属性"(用于APP的ioctl)
- v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vid_cap);
- v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vid_out);
- ...
-
- /*注册vedio_device*/ /*分配主次设备号*/
- video_register_device(video_device, type:VFL_TYPE_GRABBER, nr)
- __video_register_device
- vdev->cdev = cdev_alloc();
- vdev->cdev->ops = &v4l2_fops;
- video_devices[vdev->minor] = vdev;//将video_device放入全局数组中
- ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);
- if (vdev->ctrl_handler == NULL)
- vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler;
-

关键点:
1、分配video_device结构体内存 video_device_alloc()
或kzalloc()
;
2、设置video_device .fops
、.ioctl_ops
、dev
;、
也就是在probe里的这一步实现设备操作和驱动操作的绑定
3、注册video_device结构体 video_register_device()
;
1、open
- app: open("/dev/video0",....)
-
- ---------------------------------------------------
- drv: v4l2_fops.v4l2_open
- vdev = video_devdata(filp); // 根据次设备号从数组中得到video_device
- ret = vdev->fops->open(filp);
- vivi_ioctl_ops.open
- v4l2_fh_open
当应用层发生系统调用时,会先调用到v4l2_fops中的v4l2_open,v4l2_open会找到对应设备video_device的file opr中的open,而设备中的open是在驱动注册后调用probe函数与驱动函数定义的open绑定的,这样就实现了video设备用户空间open调用驱动open的过程。
2、ioctl
- app: read ....
-
- -----------------------------------------------
-
- drv: v4l2_fops.v4l2_read
- struct video_device *vdev = video_devdata(filp);
- ret = vdev->fops->read(filp, buf, sz, off);
核心层v4l2_ctrl_handler会找到video_device的fops 。过程如下(在上文中通过v4l2_ctrl_handler_setup设置了某些属性的ioctl处理函数)
- __video_do_ioctl
- struct video_device *vfd = video_devdata(file);
- v4l2_is_known_ioctl(cmd)
- info = &v4l2_ioctls[_IOC_NR(cmd)]; /* v4l2_ioctls数组存有全部IOCTL_INFO,含有 ioctl函数指针 */
- ret = info->func(ops, file, fh, arg); /* 调用对应的ioctl函数 */
UVC全称为USB Video Class,即:USB视频类,是一种为USB视频捕获设备定义的协议标准。是Microsoft与另外几家设备厂商联合推出的为USB视频捕获设备定义的协议标准,已成为USB org标准之一。
最新的UVC版本为UVC 1.5,由USB Implementers Forum定义包括基本协议及负载格式。
USB摄像头示例如下:
对于框架具体细节可以看这篇UVC 1.5 Class Specification 简解_uvc1.5-CSDN博客
UVC驱动的重点在于:
描述符的分析
属性的控制: 通过VideoControl Interface来设置
格式的选择:通过VideoStreaming Interface来设置
数据的获得:通过VideoStreaming Interface的URB来获得
参考文章:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。