这段时间开始搞安卓camera底层驱动了,把以前的的Linux视频驱动回顾一下,本篇主要概述一下vfl2(video for linux 2).
一. V4L2框架: video for linux version 2
虚拟视频驱动vivi.c分析:
1.分配video_device
2.设置
3.注册:video_register_device
vivi_init
vivi_create_instance
v4l2_device_register // 不是主要, 只是用于初始化一些东西,比如自旋锁、引用计数
video_device_alloc
// 设置
1. vfd:
.fops = &vivi_fops,
.ioctl_ops = &vivi_ioctl_ops,
.release = video_device_release,
2.
vfd->v4l2_dev = &dev->v4l2_dev;
3. 设置"ctrl属性"(用于APP的ioctl):
v4l2_ctrl_handler_init(hdl, 11);
dev->volume = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
V4L2_CID_AUDIO_VOLUME, 0, 255, 1, 200);
dev->brightness = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
V4L2_CID_BRIGHTNESS, 0, 255, 1, 127);
dev->contrast = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
V4L2_CID_CONTRAST, 0, 255, 1, 16);
video_register_device(video_device, type:VFL_TYPE_GRABBER, nr)
__video_register_device
vdev->cdev = cdev_alloc();
vdev->cdev->ops = &v4l2_fops;
cdev_add
video_device[vdev->minor] = vdev;
if (vdev->ctrl_handler == NULL)
vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler;
分析vivi.c的open,read,write,ioctl过程
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
2. read
app: read ....
---------------------------------------------------
drv: v4l2_fops.v4l2_read
struct video_device *vdev = video_devdata(filp);
ret = vdev->fops->read(filp, buf, sz, off);
3. ioctl
app: ioctl
----------------------------------------------------
drv: v4l2_fops.unlocked_ioctl
v4l2_ioctl
struct video_device *vdev = video_devdata(filp);
ret = vdev->fops->unlocked_ioctl(filp, cmd, arg);
video_ioctl2
video_usercopy(file, cmd, arg, __video_do_ioctl);
__video_do_ioctl
struct video_device *vfd = video_devdata(file);
根据APP传入的cmd来获得、设置"某些属性"v4l2_ctrl_handler的使用过程:
__video_do_ioctl
struct video_device *vfd = video_devdata(file); case VIDIOC_QUERYCTRL:
{
struct v4l2_queryctrl *p = arg;
if (vfh && vfh->ctrl_handler)
ret = v4l2_queryctrl(vfh->ctrl_handler, p);
else if (vfd->ctrl_handler) // 在哪设置?在video_register_device
ret = v4l2_queryctrl(vfd->ctrl_handler, p);
// 根据ID在ctrl_handler里找到v4l2_ctrl,返回它的值...}
[18721.327983] usb 2-1: USB disconnect, address 4
[18724.929301] usb 2-1: new full speed USB device using uhci_hcd and address 5
[18725.196200] usb 2-1: configuration #1 chosen from 1 choice
[18725.204999] uvcvideo: Found UVC 1.00 device <unnamed> (1b3b:2977)
[18725.222065] input: UVC Camera (1b3b:2977) as /devices/pci0000:00/0000:00:07.2/usb2/2-1/2-1:1.0/input/input7
[25252.578719] usb 2-1: USB disconnect, address 5
由以上usb摄像头插入的dmesg打印信息,搜索UVC关键字得到相关代码:uvc.driver.c ->uvc_driver结构体->video_register_device方法。
二、如何写v4l2驱动:
①构造、设置、注册: v4l2_device : v4l2_device_register, v4l2_device
②分配:video_device, video_device_alloc
③设置: a. vfd->v4l2_dev
b. vfd: .fops = ***.open/read/write <-上层app调用
.ioctl_ops <-驱动程序 v4l2_fops {open,read,write,"ioctl"}
c.APP通过ioctl来设置,获得亮度 等信息。
驱动程序: v4l2_ctrl : 属性。
v4l2_ctrl_handler : 管理 ===>(1)初始化:v4l2_ctrl_handler_init
(2)设置:v4l2_ctrl_new_std , v4l2_ctrl_new_custom ,设置创建v4l2_ctrl并加入链表。
(3)跟vdev关联: v4l2_dev.ctrl_handler = hdl
video_dev -> v4l2_dev.
具体驱动代码的编写将在下篇继续....