整个v4l2的框架分为三层:

在应用层,我们可以在 /dev 目录发现 video0 类似的设备节点,上层的摄像头程序打开设备节点进行数据捕获,显示视频画面。设备节点的名字很统一,video0 video1 video2...这些设备节点在是核心层注册。

核心层 v4l2-dev.c,承上启下,对于每一个硬件相关层注册进来的设备,设置一个统一的接口 v4l2_fops ,既然是统一的接口必然不是具体的视频设备的操作函数,应用层调用 v4l2_fops 中的函数最终将调用到硬件相关层的 video_device 的 fops 。

硬件相关层,与具体的视频硬件打交道,分配、设置、注册 video_device 结构体。

static int __init videodev_init(void)
{
/* 申请设备号,留给 video 设备使用 */
dev_t dev = MKDEV(VIDEO_MAJOR, );
ret = register_chrdev_region(dev, VIDEO_NUM_DEVICES, VIDEO_NAME);
/* 创建 video 类 */
ret = class_register(&video_class);
return ;
}
struct video_device
{
/* device ops */
const struct v4l2_file_operations *fops; /* sysfs */
struct device dev; /* v4l device */
struct cdev *cdev; /* character device */ /* Set either parent or v4l2_dev if your driver uses v4l2_device */
struct device *parent; /* device parent */
struct v4l2_device *v4l2_dev; /* v4l2_device parent */ /* Control handler associated with this device node. May be NULL. */
struct v4l2_ctrl_handler *ctrl_handler; /* Priority state. If NULL, then v4l2_dev->prio will be used. */
struct v4l2_prio_state *prio; /* device info */
char name[];
int vfl_type;
/* 'minor' is set to -1 if the registration failed */
int minor;
u16 num;
/* use bitops to set/clear/test flags */
unsigned long flags;
/* attribute to differentiate multiple indices on one physical device */
int index; /* V4L2 file handles */
spinlock_t fh_lock; /* Lock for all v4l2_fhs */
struct list_head fh_list; /* List of struct v4l2_fh */ int debug; /* Activates debug level*/ /* Video standard vars */
v4l2_std_id tvnorms; /* Supported tv norms */
v4l2_std_id current_norm; /* Current tvnorm */ /* callbacks */
void (*release)(struct video_device *vdev); /* ioctl callbacks */
const struct v4l2_ioctl_ops *ioctl_ops;
DECLARE_BITMAP(valid_ioctls, BASE_VIDIOC_PRIVATE); /* serialization lock */
DECLARE_BITMAP(disable_locking, BASE_VIDIOC_PRIVATE);
struct mutex *lock;
};
struct v4l2_device {
struct device *dev;
/* used to keep track of the registered subdevs */
struct list_head subdevs;
spinlock_t lock;
char name[V4L2_DEVICE_NAME_SIZE];
void (*notify)(struct v4l2_subdev *sd, unsigned int notification, void *arg);
struct v4l2_ctrl_handler *ctrl_handler;
struct v4l2_prio_state prio;
struct mutex ioctl_lock;
struct kref ref;
void (*release)(struct v4l2_device *v4l2_dev);
};
static inline int __must_check video_register_device(struct video_device *vdev,
int type, int nr)
{
return __video_register_device(vdev, type, nr, , vdev->fops->owner);
} int __video_register_device(struct video_device *vdev, int type, int nr,
int warn_if_nr_in_use, struct module *owner)
{
int i = ;
int ret;
int minor_offset = ;
int minor_cnt = VIDEO_NUM_DEVICES;
const char *name_base; /* A minor value of -1 marks this video device as never having been registered */
vdev->minor = -; /* 视频设备的设备节点一般为 video0 ..video 就是由此而来 */
switch (type) {
case VFL_TYPE_GRABBER:
name_base = "video";
break;
case VFL_TYPE_VBI:
name_base = "vbi";
break;
...
} vdev->vfl_type = type;
vdev->cdev = NULL; /* Part 2: find a free minor, device node number and device index. */
#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
switch (type) {
case VFL_TYPE_GRABBER:
minor_offset = ;
minor_cnt = ;
break;
...
#endif /* 寻找一个空的项,这个好像并不重要 */
mutex_lock(&videodev_lock);
nr = devnode_find(vdev, nr == - ? : nr, minor_cnt);
if (nr == minor_cnt)
nr = devnode_find(vdev, , minor_cnt);
if (nr == minor_cnt) {
printk(KERN_ERR "could not get a free device node number\n");
mutex_unlock(&videodev_lock);
return -ENFILE;
}
#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
/* 1-on-1 mapping of device node number to minor number */
i = nr;
#else
/* 在全局 video_deivce 数组中寻找一个空的项,下标+minor_offset作为设备的次设备号 */
for (i = ; i < VIDEO_NUM_DEVICES; i++)
if (video_device[i] == NULL)
break;
if (i == VIDEO_NUM_DEVICES) {
mutex_unlock(&videodev_lock);
printk(KERN_ERR "could not get a free minor\n");
return -ENFILE;
}
#endif
vdev->minor = i + minor_offset;
vdev->num = nr;
devnode_set(vdev); if (vdev->ioctl_ops)
determine_valid_ioctls(vdev); /* 注册字符设备 */
vdev->cdev = cdev_alloc();
vdev->cdev->ops = &v4l2_fops;
vdev->cdev->owner = owner;
ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), ); /* 得把device注册进内核,mdev才能自动创建设备节点,/dev 目录下的video0 等就是来自这里 */
vdev->dev.class = &video_class;
vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor);
if (vdev->parent)
vdev->dev.parent = vdev->parent;
dev_set_name(&vdev->dev, "%s%d", name_base, vdev->num);
ret = device_register(&vdev->dev); vdev->dev.release = v4l2_device_release; /* Part 6: Activate this minor. The char device can now be used. */
set_bit(V4L2_FL_REGISTERED, &vdev->flags);
mutex_lock(&videodev_lock);
video_device[vdev->minor] = vdev;
mutex_unlock(&videodev_lock); return ; }
EXPORT_SYMBOL(__video_register_device);
static const struct file_operations v4l2_fops = {
.owner = THIS_MODULE,
.read = v4l2_read,
.write = v4l2_write,
.open = v4l2_open,
.get_unmapped_area = v4l2_get_unmapped_area,
.mmap = v4l2_mmap,
.unlocked_ioctl = v4l2_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = v4l2_compat_ioctl32,
#endif
.release = v4l2_release,
.poll = v4l2_poll,
.llseek = no_llseek,
};
static int v4l2_open(struct inode *inode, struct file *filp)
{
struct video_device *vdev = video_devdata(filp);
if (vdev->fops->open) { if (video_is_registered(vdev))
ret = vdev->fops->open(filp);
}
}
static ssize_t v4l2_read(struct file *filp, char __user *buf,
size_t sz, loff_t *off)
{
struct video_device *vdev = video_devdata(filp);
if (!vdev->fops->read)
return -EINVAL;
if (video_is_registered(vdev))
ret = vdev->fops->read(filp, buf, sz, off);
}
static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm)
{
struct video_device *vdev = video_devdata(filp);
if (!vdev->fops->mmap)
return ret;
ret = vdev->fops->mmap(filp, vm);
} static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct video_device *vdev = video_devdata(filp);
if (vdev->fops->unlocked_ioctl) {
if (video_is_registered(vdev))
ret = vdev->fops->unlocked_ioctl(filp, cmd, arg);
} else if (vdev->fops->ioctl) {
if (video_is_registered(vdev))
ret = vdev->fops->ioctl(filp, cmd, arg);
}
}

V4L2学习(三)框架分析的更多相关文章

  1. 初识V4L2(三)-------分析vivi.c 虚拟视频驱动

    1.分配video_device结构体 2.设置 3.注册  video_register_device 分析vivi.c: vivi_init( )//入口函数 vivi_create_instan ...

  2. Python学习---抽屉框架分析[点赞功能/文件上传分析]0317

    点赞功能分析 前台传递过来新闻id[new_id]和session[session内有用户ID和用户之间的信息]到后台 后台News数据库内用户和新闻是多对多的关系,查看第三张表中的内容,判读用户Id ...

  3. spring学习 三 框架的搭建

    1 导入jar包 spring启来最少要5个包,四个核心包和一个依赖的日志包 2 创建配置文件 在dynamic web project下的src目录下,创建一个spring的xml配置文件,名称可以 ...

  4. Python学习---抽屉框架分析[小评论分析]0315

    注: 此处的小评论涉及数据库操作 初级小评论代码 settings.py INSTALLED_APPS = [ ... 'app01', # 注册app ] STATICFILES_DIRS = (o ...

  5. Python学习---抽屉框架分析[ORM操作]180314

    Django ORM操作     1. 字段操作         class User(model.Model);             u=字段        用处:            1 . ...

  6. Python学习---抽屉框架分析[数据库设计分析]180313

    基本的: models.py ####################################以下都是抽屉的代码#################################### fro ...

  7. Python学习---抽屉框架分析[点赞功能分析]

    实际上就是多了一个隐藏的span标签,内容是+1,配合setInterval实现的动态效果 settings.py INSTALLED_APPS = [ ... 'app01', # 注册app ] ...

  8. v4l2框架分析

    参考:https://www.cnblogs.com/fengong/p/4424823.html    http://www.cnblogs.com/fengong/p/4424895.html 一 ...

  9. 摄像头驱动——V4L2框架分析

    一.概述 Video for Linux 2,简称V4l2,是Linux内核中关于视频设备的内核驱动框架,为上层的访问底层的视频设备提供了统一的接口. 摄像头驱动是属于字符设备驱动程序.(分析linu ...

  10. 【原创】Linux v4l2框架分析

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...

随机推荐

  1. HDU 5465——Clarke and puzzle——————【树状数组BIT维护前缀和+Nim博弈】

    Clarke and puzzle Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others ...

  2. 19.CentOS7下PostgreSQL安装过程

    CentOS7下PostgreSQL安装过程 装包 sudo yum install postgresql-server postgresql-contrib 说明: 这种方式直接明了,其他方法也可以 ...

  3. ios下表单disabled样式重置

    在做最近的一个活动项目时,需要用到表单的disabled状态,但是在IOS下那颜色不是一般的浅,就跟没有一样,一开始通过如下样式重置: input:disabled, input[disabled]{ ...

  4. ngnix反向代理

    https://blog.csdn.net/sherry_chan/article/details/79055211

  5. JavaScript 创建对象的七种方式

    转自:xxxgitone.github.io/2017/06/10/JavaScript创建对象的七种方式/ JavaScript创建对象的方式有很多,通过Object构造函数或对象字面量的方式也可以 ...

  6. [QualityCenter]设置工作流脚本-根据某字段是否包含指定字符串来判断其他字段的选值

    需求:当在创建或更改值时,自动判断A字段是否包含B值,然后自动填写相应的内容. 如以下例子: 在脚本编辑器新建一个函数TestPlan_Test_New,然后编写脚本如下: '通过主题判断项目内容   ...

  7. centos7 初体验

    centos7 https://linux.cn/tag-RHCSA%7CRHCSA.html #/etc/sysconfig/network NETWORKING=yes GATEWAY=192.1 ...

  8. vue-初识

    一:vue基础1.1.Vue是一套构建用户界面的渐进式框架1.2.引入vue:<script src="https://unpkg.com/vue/dist/vue.js"& ...

  9. 【BZOJ3106】[CQOI2013] 棋盘游戏(对抗搜索)

    点此看题面 大致题意: 在一张\(n*n\)的棋盘上有一枚黑棋子和一枚白棋子.白棋子先移动,然后是黑棋子.白棋子每次可以向上下左右四个方向中任一方向移动一步,黑棋子每次则可以向上下左右四个方向中任一方 ...

  10. Java代码工具箱之链接Oracle

    1. 需要oracle的 odbc  jar包 2. 代码 3. 注意:ps对象和statement对象最好用完立即释放,尤其是读写数据库代码出现在 for 循环语句中时. 否则会出现游标不够的情况, ...