学习V4L2(V4L2:vidio for linux version 2)摄像头驱动框架,需要分析vivi.c(虚拟视频硬件相关)驱动源码程序,
vivi.c(虚拟视频驱动程序的分析)
通过分析vivi.c结构如下
vivi_init
-->vivi_create_instance
-->v4l2_device_register // 不是主要, 只是用于初始化一些东西,比如自旋锁、引用计数
vfd = video_device_alloc(); //分配video_device结构体
1. *vfd = vivi_template; // 设置
.fops = &vivi_fops,
.ioctl_ops = &vivi_ioctl_ops,
.release = video_device_release,
2. vfd->v4l2_dev = &dev->v4l2_dev;
3. 设置"ctrl属性"(用于APP的ioctl):(设置ctrl的属性让ioctl调用或者使用例如亮度等在驱动程序中抽象出来一个结构体 v4l2_ctrl,每个Ctrl对应其中的一项(音量、亮度等等)v4l2_ctrl_handler来管理他们)
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);
4. video_register_device(vfd, VFL_TYPE_GRABBER, video_nr); //注册
--> __video_register_device(vdev, type, nr, 1, vdev->fops->owner);
-->vdev->cdev = cdev_alloc(); (v4l2.dev.c程序中)
vdev->cdev->ops = &v4l2_fops;
cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);
vivi.c的open,read,write,ioctl过程
1)open
app: open("/dev/video0",....)向下层调用
-------------------------------------------------------------------
drv: v4l2_fops.v4l2_open
vdev = video_devdata(filp); // 根据次设备号从数组中得到video_device
return video_device[iminor(file->f_path.dentry->d_inode)];
if (vdev->fops->open) //如果有open函数
if (video_is_registered(vdev))
ret = vdev->fops->open(filp);//调用open 函数
调用vivi.c 里的v4l2_fh_open函数
2)read
app: read("/dev/video0",....)向下层调用
-------------------------------------------------------------------
drv: v4l2_fops.v4l2_read
struct video_device *vdev = video_devdata(filp);
if (video_is_registered(vdev))
ret = vdev->fops->read(filp, buf, sz, off);
调用vivi.c 里的vivi_read
3)ioctl
app: ioctl
----------------------------------------------------
drv: v4l2_fops.unlocked_ioctl => v4l2_ioctl
struct video_device *vdev = video_devdata(filp);
if (video_is_registered(vdev))
ret = vdev->fops->unlocked_ioctl(filp, cmd, arg);
调用vivi.c 里的video_ioctl2
video_usercopy(file, cmd, arg, __video_do_ioctl); //从用户空间把用户的命令cmd复制进来,调用__video_do_ioctl
__video_do_ioctl
struct video_device *vfd = video_devdata(file); //根据次设备号从数组中得到video_device
switch (cmd) { ..... // 根据APP传入的cmd来获得、设置"某些属性"
V4L2驱动架构(通过上面的分析)
通过V4L2驱动框架知道如何编写V4L2驱动
1. 分配、设置、注册:v4l2_device --》 v4l2_device_register()(辅助作用,提供自旋锁、引用计数等功能)
2. 分配一个video_device:video_device_alloc()
3. 设置
1)vfd->v4l2_dev
2) .fops 设置vfd的fops 里的open、read、write 被上层调用
.ioctl_ops 设置属性被上层调用
3)注册:video_register_device()
4. 接下来,应用层App可以通过ioctl来设置(获得)亮度等某些属性,在驱动程序里,谁来接收、存储、设置到硬件(提供这些信息)?
在驱动程序中抽象出来一个结构体v4l2_ctrl,每个Ctrl对应其中的一项(音量、亮度等等);
v4l2_ctrl_handler来管理他们,在vivi.c的vivi_create_instance函数中:
1.初始化
v4l2_ctrl_handler_init
2.设置
v4l2_ctrl_new_std
v4l2_ctrl_new_custom
这些函数就是创建各个属性,并且放入v4l2_ctrl_handler的链表
3.跟vdev关联
dev->v4l2_dev.ctrl_handler = hdl;