回顾第二期驱动视频:字符 块 网卡
app层:open read write
____________________________________________
怎样写驱动:1、构造file_operation:
.open = drv_open
.read = drv_read
2、告诉内核: register_chrdev(主, file_operation,name)
3、入口函数
4、出口函数
第二种方式
1、分配 cdev
2、设置:cdev
对于复杂的字符设备驱动程序,引入分层概念,如LCD分层:
分层 fbmem.c 1 file_operation
2 regiser_chrdev
3 入口/出口函数(内核已经提供)
———————————————————————————————————
硬件相关: 1、分配fb_info
2、设置fb_infor
3、注册
1、分配某个结构体(不同的设备不同,如lcd为fb_info)
2、设置
3、注册
4、硬件相关操作
vivi.c中的头文件包含:
vivi.c包含头文件v4l2-device.h和v4l2-ioctl.h,其中v4l2-device.h中包含了v4l2-subdev.h,v4l2-subdev.h中又包含了
v4l2-common.h,v4l2-common.h中包含了v4l2-dev.h。vivi.h
在v4l2-device.h中定义了结构体v4l2_device;
struct v4l2_capability/v4l2_cropcap/v4l2_crop在/include/linux/videodev2.h定义
结构体包含关系
struct video_device
->vivi_fops (v4l2_file_operations)
->vivi_ioctl_ops (v4l2_ioctl_ops)
构思V4L2框架:
APP open write read
———————————————————————————————————
核心层 v4l2_dev.c 1、file_operation -》》 vdev->cdev = cdev_alloc()
vdev->cdev->ops = &v4l2_fops (函数)
cdev_add
2、注册
———————————————————————————————————
硬件相关 |--- uvc_register_device 不重要 1、分配 video_device
uvc_driver.c |--- video_dev_alloc 2、设置
|--- video_register_device 重要 3、注册:video_register_device
video_register_device最后调用__video_register_device (核心层的)
———————————————————————————————————
/drivers/media/video
虚拟视频驱动分析:
1、分配video_device
2、设置
3、注册:video_register_device
*************************************************************************************************
vivi_dev *dev //这个设备定义了vivi_dev摄像头驱动的结构体
程序的思路:(1)最重要的是vivi_dev这个抽象出来的设备,即*dev。它其实定义了一个vivi虚拟摄像头设备,其中有相机的照片大 小、v4l2_ctrl结构体、video_device设备等结构体成员。在vivi_init()函数中完成了height width/v4l2_ctrl的 赋值,对于video_device,定义了vfd这个变量,将vivi_template{ .fops = ;. ioctl = ;...}赋值给了vfd。
(2)video_register_device()函数中完成了对vfd这个video_device这个结构体的赋值,其中主要是对vfd->cdev的赋值
vdev->cdev = cdev_alloc();
vdev->cdev->ops = &v4l2_fops;
vdev->cdev->owner = owner;
其中:stuct file_operation v4l2_fops =
{ .owner = ;
.read = v4l2_read;
总结:vivi_dev包含了video_device重要成员,video_device中包含了cdev/dev/*ioctl_ops/*fops(v4l2_file_operateion)成员,
而cdev中又包含了ops/owner等成员。
/video_device只是一个vivi_dev摄像头设备的一个重要部分而已。
*************************************************************************************************
/drivers/media/video/vivi.c
vivi_init
vivi_create_instance /drivers/media/video/vivi.c
v4l2_device_register //不是主要的 ,只是用于初始化一些东西,比如自旋锁
video_device_alloc
kzalloc(sizeof(struct video_device),GFP_KERNEL);
//设置
*vfd = vivi_template; //将vivi_tmpplate结构体完全赋值给*vfd(video_device)
1.vfd:
vfd->v4l2_dev = &dev->v4l2_dev;
***将vivi_device中v4l2_device赋给vfd即video_device的v4l2****
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);
vfd.v4l2_file_operation
video_register_device(video_device,type:VFL_TYPE_GRABBER,nr)
__video_register_device
vdev->cdev = cdev_alloc();
vdev->cdev->ops = &v4l2_fops;
cdev_add
dev->vfd = vfd ; ****将vfd即video_device结构体赋给vivi_dev中的video_device******
video_device[vdev->minor] = vdev
分析vivi.c的open,read,write,ioctl过程:
1. open
app: open("/dev/**",);
_____________________________________________
drv: 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,返回它的值
怎样写V4L2驱动:
1、分配/设置/注册 V4L2_device 、v4l2_device_register,v4l2_device(辅助作用,提供自旋锁)
2、分配:video_device ,video_device_alloc |
3、设置:a.vfd->v4l2_dev 指向第一步v4l2_device ---------------
b.vfd .fops
.ioctl
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.handler = hd1)
( video_dev->v4l2_dev =v4l2_dev )
app层:open read write
____________________________________________
驱动:drv_open drv_read drv_write
____________________________________________怎样写驱动:1、构造file_operation:
.open = drv_open
.read = drv_read
2、告诉内核: register_chrdev(主, file_operation,name)
3、入口函数
4、出口函数
第二种方式
1、分配 cdev
2、设置:cdev
对于复杂的字符设备驱动程序,引入分层概念,如LCD分层:
分层 fbmem.c 1 file_operation
2 regiser_chrdev
3 入口/出口函数(内核已经提供)
———————————————————————————————————
硬件相关: 1、分配fb_info
2、设置fb_infor
3、注册
4、硬件相关的操作
1、分配某个结构体(不同的设备不同,如lcd为fb_info)
2、设置
3、注册
4、硬件相关操作
vivi.c中的头文件包含:
vivi.c包含头文件v4l2-device.h和v4l2-ioctl.h,其中v4l2-device.h中包含了v4l2-subdev.h,v4l2-subdev.h中又包含了
v4l2-common.h,v4l2-common.h中包含了v4l2-dev.h。vivi.h
在v4l2-dev.h中定义了结构体video_device和v4l2_file_operations;
在v4l2-ioctl.h中定义了结构体v4l2_ioctl_ops;在v4l2-device.h中定义了结构体v4l2_device;
struct v4l2_capability/v4l2_cropcap/v4l2_crop在/include/linux/videodev2.h定义
结构体包含关系
struct video_device
->vivi_fops (v4l2_file_operations)
->vivi_ioctl_ops (v4l2_ioctl_ops)
构思V4L2框架:
APP open write read
———————————————————————————————————
核心层 v4l2_dev.c 1、file_operation -》》 vdev->cdev = cdev_alloc()
vdev->cdev->ops = &v4l2_fops (函数)
cdev_add
2、注册
———————————————————————————————————
硬件相关 |--- uvc_register_device 不重要 1、分配 video_device
uvc_driver.c |--- video_dev_alloc 2、设置
|--- video_register_device 重要 3、注册:video_register_device
video_register_device最后调用__video_register_device (核心层的)
———————————————————————————————————
/drivers/media/video
虚拟视频驱动分析:
1、分配video_device
2、设置
3、注册:video_register_device
*************************************************************************************************
vivi_dev *dev //这个设备定义了vivi_dev摄像头驱动的结构体
程序的思路:(1)最重要的是vivi_dev这个抽象出来的设备,即*dev。它其实定义了一个vivi虚拟摄像头设备,其中有相机的照片大 小、v4l2_ctrl结构体、video_device设备等结构体成员。在vivi_init()函数中完成了height width/v4l2_ctrl的 赋值,对于video_device,定义了vfd这个变量,将vivi_template{ .fops = ;. ioctl = ;...}赋值给了vfd。
(2)video_register_device()函数中完成了对vfd这个video_device这个结构体的赋值,其中主要是对vfd->cdev的赋值
vdev->cdev = cdev_alloc();
vdev->cdev->ops = &v4l2_fops;
vdev->cdev->owner = owner;
其中:stuct file_operation v4l2_fops =
{ .owner = ;
.read = v4l2_read;
另外一个成员vfd->dev这个成员进行了注册device_register(&vdev->dev); video_device结构体中包含了cdev和 device dev两个成员变量。
总结:vivi_dev包含了video_device重要成员,video_device中包含了cdev/dev/*ioctl_ops/*fops(v4l2_file_operateion)成员,
而cdev中又包含了ops/owner等成员。
/video_device只是一个vivi_dev摄像头设备的一个重要部分而已。
*************************************************************************************************
/drivers/media/video/vivi.c
vivi_init
vivi_create_instance /drivers/media/video/vivi.c
v4l2_device_register //不是主要的 ,只是用于初始化一些东西,比如自旋锁
video_device_alloc
kzalloc(sizeof(struct video_device),GFP_KERNEL);
//设置
*vfd = vivi_template; //将vivi_tmpplate结构体完全赋值给*vfd(video_device)
1.vfd:
.fops = &vivi_fops,
.ioctl_ops = &vivi_ioctl_ops,
.release = video_device_release,
vfd->v4l2_dev = &dev->v4l2_dev;
***将vivi_device中v4l2_device赋给vfd即video_device的v4l2****
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);
vfd.v4l2_file_operation
video_register_device(video_device,type:VFL_TYPE_GRABBER,nr)
__video_register_device
vdev->cdev = cdev_alloc();
vdev->cdev->ops = &v4l2_fops;
cdev_add
dev->vfd = vfd ; ****将vfd即video_device结构体赋给vivi_dev中的video_device******
video_device[vdev->minor] = vdev
分析vivi.c的open,read,write,ioctl过程:
1. open
app: open("/dev/**",);
_____________________________________________
drv: 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,返回它的值
怎样写V4L2驱动:
1、分配/设置/注册 V4L2_device 、v4l2_device_register,v4l2_device(辅助作用,提供自旋锁)
2、分配:video_device ,video_device_alloc |
3、设置:a.vfd->v4l2_dev 指向第一步v4l2_device ---------------
b.vfd .fops
.ioctl
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.handler = hd1)
( video_dev->v4l2_dev =v4l2_dev )