V4L2学习(三)框架分析
整个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学习(三)框架分析的更多相关文章
- 初识V4L2(三)-------分析vivi.c 虚拟视频驱动
1.分配video_device结构体 2.设置 3.注册 video_register_device 分析vivi.c: vivi_init( )//入口函数 vivi_create_instan ...
- Python学习---抽屉框架分析[点赞功能/文件上传分析]0317
点赞功能分析 前台传递过来新闻id[new_id]和session[session内有用户ID和用户之间的信息]到后台 后台News数据库内用户和新闻是多对多的关系,查看第三张表中的内容,判读用户Id ...
- spring学习 三 框架的搭建
1 导入jar包 spring启来最少要5个包,四个核心包和一个依赖的日志包 2 创建配置文件 在dynamic web project下的src目录下,创建一个spring的xml配置文件,名称可以 ...
- Python学习---抽屉框架分析[小评论分析]0315
注: 此处的小评论涉及数据库操作 初级小评论代码 settings.py INSTALLED_APPS = [ ... 'app01', # 注册app ] STATICFILES_DIRS = (o ...
- Python学习---抽屉框架分析[ORM操作]180314
Django ORM操作 1. 字段操作 class User(model.Model); u=字段 用处: 1 . ...
- Python学习---抽屉框架分析[数据库设计分析]180313
基本的: models.py ####################################以下都是抽屉的代码#################################### fro ...
- Python学习---抽屉框架分析[点赞功能分析]
实际上就是多了一个隐藏的span标签,内容是+1,配合setInterval实现的动态效果 settings.py INSTALLED_APPS = [ ... 'app01', # 注册app ] ...
- v4l2框架分析
参考:https://www.cnblogs.com/fengong/p/4424823.html http://www.cnblogs.com/fengong/p/4424895.html 一 ...
- 摄像头驱动——V4L2框架分析
一.概述 Video for Linux 2,简称V4l2,是Linux内核中关于视频设备的内核驱动框架,为上层的访问底层的视频设备提供了统一的接口. 摄像头驱动是属于字符设备驱动程序.(分析linu ...
- 【原创】Linux v4l2框架分析
背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...
随机推荐
- SpringBoot | 第二十六章:邮件发送
前言 讲解了日志相关的知识点后.今天来点相对简单的,一般上,我们在开发一些注册功能.发送验证码或者订单服务时,都会通过短信或者邮件的方式通知消费者,注册或者订单的相关信息.而且基本上邮件的内容都是模版 ...
- python起源,变量,用户交互,流程语句
1.Python的起源 Python是一门解释型弱类型编程语言. 特点:简单.明确.优雅 2.Python解释器 CPython官方提供的, 内部使用C语言来实现 PyPy,一次性把我们的代码解释成字 ...
- #include stdio.h(2)
#include <stdio.h> //mian函数是程序的入口 int main() { /* //函数:是按一定的格式对一段代码的封装 //专门用来实现一功能的代码合集,可以重复使用 ...
- css钻石旋转实现
css钻石旋转实现: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> &l ...
- Openfire+spark在linux上搭建内部聊天系统
一. 实验环境 Ubuntu server14.04 openfire:http://www.igniterealtime.org/downloads/index.jsp spark:http: ...
- python 学习之FAQ:文档内容写入报错
2017.3.29 FAQ 1. 文档内容写入报错 使用with open() as file: 写入文档时,出现'\xa9'特殊字符写入报错,通过print('\xa9')打印输出“©”. > ...
- C++,C++编程,Windows编程,MFC
编程 我们日常生活中接触到的电子类产品中的应用都是由编程而来 为什么编程,偷懒 我们通过编程驱使(指挥,命令)的是电信号 为什么上面说编程是偷懒,电的发现,给人们带来了便利,人们在各个方面驱使(换成“ ...
- IOS NSNotificationCenter(通知 的使用)监听文本框的文字改变
监听文本框的文字改变 * 一个文本输入框的文字发生改变时,文本输入框会发出一个UITextFieldTextDidChangeNotification通知 * 因此通过监听通知来监听文本输入框的文字改 ...
- Codeforces Round #324 (Div. 2) A B C D E
A,水题不多说. #include<bits/stdc++.h> using namespace std; //#define LOCAL int main() { #ifdef LOCA ...
- python基础一 day16 内置函数
# 数据类型 :int bool ...# 数据结构 : dict list tuple set str reversed()l = [1,2,3,4,5]l.reverse()print(l)l = ...