回顾:
怎么写分层驱动:
1、分配某结构体
2、设置
3、注册
4、硬件相关操作
一. V4L2框架: video for linux version 2
大致猜测:
至少分为两层:
第一层:核心层: v4l2_dev.c
1、编写file_operations结构体
2、注册
然后:
cdev_alloc
cdev->ops = v4l2_fops
cdev_add
第二层:硬件相关层:
1、分配video_device
2、设置
3、注册vido_register_device
uvc_driver.c
v4l2_device_register 这个其实并不重要
video_device_alloc
video_register_device 这个重要
虚拟视频驱动vivi.c分析:
1.分配 video_device
2.设置
3.注册:video_register_device
ViVi分析:
vivi_init
vivi_create_instance
v4l2_device_register // 不是主要, 只是用于初始化一些东西,比如自旋锁、引用计数 、并没有注册什么东西
video_device_alloc //分配vido_device设备,分配好后进行设置
// 设置
1. vfd:
.fops = &vivi_fops, // 这个fops 指的是 :v4l2_file_oprations结构体
.ioctl_ops = &vivi_ioctl_ops,
.release = video_device_release,
2.
vfd->v4l2_dev = &dev->v4l2_dev; // dev->v4l2_dev这个结构体,实际上就是前面v4l2_device_register函数得到的结构体!
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); //亮度 0:亮度Min,255:亮度Max,127:默认
dev->contrast = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
V4L2_CID_CONTRAST, 0, 255, 1, 16);
Garmen:进行好上面的分配之后,然后进行注册!
video_register_device(video_device, type:VFL_TYPE_GRABBER, nr) // 根据这个类型type:VFL_TYPE_GRABBER,创建不同的设备节点;不同类型,次设备号不同
__video_register_device
vdev->cdev = cdev_alloc(); // 从这里我们可以看到,不管驱动框架多么复杂,最后还是有cdev_alloc();和cdev_add;
vdev->cdev->ops = &v4l2_fops; //猜测:v4l2_fops 可能就是上面第1点里面的.fops
cdev_add
video_device[vdev->minor] = vdev; // 以次设备号为下标,将vdev结构体存入video_device,当我们调用open函数的时候就反方向操作
// 对应了问1里面的问题;
if (vdev->ctrl_handler == NULL)
vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler;
附上vivi.c 中vivi_init里的vivi_create_instance函数(这是主要函数)
static int __init vivi_create_instance(int inst)
{
struct vivi_dev *dev;
struct video_device *vfd;