linux V4L2驱动中新旧版本下video buffer alloc与mmap的处理区别

  1. 首先需要说明目前在比较新的内核中已经采用了

vb2_queue与vb2_buffer来替代旧版本内核中经常使用到的

videobuf_queue与videobuf_buffer。

两者主要用于对用户层申请VIDIOC_REQBUF时的使用。

从用户层Request的Memory的类型区分,典型的两种是:

V4L2_MEMORY_USERPTR以及V4L2_MEMORY_MMAP,前者的内存主动权位于用户层,即驱动中的视频输出内存地址由用户层来提供,后者MMAP操作的内存缓存类型一般需要由驱动自己来实现内存的分配。

在旧版本内核中,假设需要实现两种Video设备操作接口,分别对应两种Memory_type, 则一般需要提供的ops接口如下:

V4L2_MEMORY_USERPTR:

static const struct v4l2_file_operations xxx_video0_fops= {

.owner = THIS_MODULE,

.open = xxx,

.release = xxx,

.poll = xxx,

.unlocked_ioctl = xxx,

};

V4L2_MEMORY_MMAP:

static const struct v4l2_file_operations xxxx_video1_fops = {

.owner = THIS_MODULE,

.open = xxx,

.release = xxx,

.poll = xxx,

.unlocked_ioctl = xxx,

.mmap = xxx,

};

两者的区别就是多了一个mmap操作的接口。

此外,对于旧版内核而言mmap的操作可以由内核提供的mmap方式来实现,一般的处理方式如下:

void videobuf_queue_dma_contig_init(struct videobuf_queue *q,

const struct videobuf_queue_ops *ops,

struct device *dev,

spinlock_t *irqlock,

enum v4l2_buf_type type,

enum v4l2_field field,

unsigned int msize,

void *priv,

struct mutex *ext_lock)

{

videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,

priv, &qops, ext_lock);

}

这里通过内核提供的一个qops来完成对每一个videobuf_buffer的alloc_vb操作,该过程主要是申请一个videobuf_buffer但并不会直接申请存储视频图像数据的内存块,所以一般在Request_buffer的过程就是主要完成alloc_vb的操作,重点是记录下申请的每个videobuf_buffer所在的index值,该过程对V4L2_MEMORY_USERPTR 和V4L2_MEMORY_MMAP 是一致的。

static struct videobuf_qtype_ops qops = {

.magic        = MAGIC_QTYPE_OPS,

.alloc_vb     = __videobuf_alloc_vb,

.iolock       = __videobuf_iolock,

.mmap_mapper  = __videobuf_mmap_mapper,

.vaddr        = __videobuf_to_vaddr,

};

而对V4L2_MEMORY_MMAP的缓存区域而言,他需要内核完成buffer真正存储数据的内存块的申请,一般就是通过用户层的mmap来完成的,而且是在这个mmap的过程中采取完成buffer区域的alloc操作,在低版本内核中通过__videobuf_mmap_mapper来实现:

mem->size = PAGE_ALIGN(buf->bsize);

mem->vaddr = dma_alloc_coherent(q->dev, mem->size,

&mem->dma_handle, GFP_KERNEL);

在完成实际物理存储区域的申请后,才会再去执行一次mmap

  1. 对比旧版本中mmap的处理机制,在新版内核中需要注意的时,可不再使用上述的模式,对于V4L2_MEMORY_MMAP类型的vb2_buffer来而言直接在Request_buffer的过程中就需要完成对实际内存区域块的申请vb2_reqbufs->__vb2_buf_mem_alloc(),而这个申请的接口在新的内核中通过实现vb2_mem_ops接口来完成,主要用于处理V4L2_MEMORY_MMAP :

struct vb2_mem_ops {

void        *(*alloc)(void *alloc_ctx, unsigned long size);

void        (*put)(void *buf_priv);

void        *(*get_userptr)(void *alloc_ctx, unsigned long vaddr,

unsigned long size, int write);

void        (*put_userptr)(void *buf_priv);

void        *(*vaddr)(void *buf_priv);

void        *(*cookie)(void *buf_priv);

unsigned int    (*num_users)(void *buf_priv);

int        (*mmap)(void *buf_priv, struct vm_area_struct *vma);

};

该接口需要在驱动中进行实现,alloc一般完成实际物理内存区域块的申请,而mmap是用于对用户空间的mmap操作的接口响应。当然在新版本的内核中依旧还是支持上述1小节所描述的处理过程的,依旧可以采用这种方式来实现video相关的驱动。同理对于方式二这种处理方式也可以在旧内核中来实现,其根本是对vb2_queue的 videobuf_qtype_op的实现。

仔细阅读源码后,可以发现本质上1和2小节描述的处理过程的根本区别在于旧版本架构中mmap过程完成实际buffer物理内存的申请以及内存映射的操作,新版本是将alloc过程放在Requestbuffer的过程中,而将mmap映射放在实际的mmap操作中实现,。

总的来说,对于新旧版本之所以这样处理的原因是,原因在于现在更多的采用V4L2_MEMORY_USERPTR类型的缓存数申请(主要是现在全新的Android系统中video申请缓存主要是来自GPU、共享内存/dev/ION等等区域块,一般再由内存申请的话会增加驱动的复杂度),故根本不需要再去实现mmap的操作,故一般不需要再实现vb2_mem_ops接口。而如果还是采用旧版的处理方式那么就需要videobuf_queue_dma_contig_init来提供一个videobuf_qtype_ops,因为alloc_vb是旧版中无论是V4L2_MEMORY_MMAP还是V4L2_MEMORY_USERPTR 均要实现videobuf_qtype_ops 。

对比而言对于V4L2_MEMORY_USERPTR来说新版本可以减少一定的编码量,无需vb2_mem_ops。

当然,架构的实现方式可以由多种多样,本质的目的是在同样的V4L2框架的基础下让Video设备可以正常工作即可。

时间: 2024-08-01 22:37:28

linux V4L2驱动中新旧版本下video buffer alloc与mmap的处理区别的相关文章

第二章-第二题(每人自己建立一个HelloWorld项目,练习使用git的add/commit/push/pull/fetch/clone等基本命令。比较项目的新旧版本的差别。)--by侯伟婷

第二题:每人自己建立一个HelloWorld项目,练习使用git的add/commit/push/pull/fetch/clone等基本命令.比较项目的新旧版本的差别. 下面我将自己的练习结果和个人感受记录如下: 第一步:安装Git,设置自己的账号和邮箱,参见Git教程-廖雪峰的官方网站,网址如下参考资料1所示. 第二步:在Git中新建repository,名叫HelloWorld,并进行初始化,如图所示. 第三步:在HelloWorld版本库中新建了helloWorld.txt文件,用以练习G

20150518 Linux设备驱动中的并发控制

20150518 Linux设备驱动中的并发控制 2015-05-18 Lover雪儿 总结一下并发控制的相关知识: 本文参考:华清远见<Linux 设备驱动开发详解>—第7章 Linux 设备驱动中的并发控制,更多详细内容请看原书 一.并发与竞态 并发(concurrency)指的是多个执行单元同时.并行被执行,而并发的执行单元对共享资源(硬件资源和软件上的全局变量.静态变量等)的访问则很容易导致竞态(race conditions). 在 Linux 内核中,主要的竞态发生于如下几种情况:

Hasen的linux设备驱动开发学习之旅--linux设备驱动中的并发与竞态

/** * Author:hasen * 参考 :<linux设备驱动开发详解> * 简介:android小菜鸟的linux * 设备驱动开发学习之旅 * 主题:linux设备驱动中的并发与竞态 * Date:2014-11-04 */ 1.并发与竞态 并发(concurrency)指的是多个执行单元同时.并行被执行,而并发的执行单元对共享资源(软件上的全 局变量,静态变量等)的访问则很容易导致竞态(race conditions). 主要的竞态发生在以下几种情况: (1)对称多处理(SMP)

Linux设备驱动中的阻塞和非阻塞I/O

[基本概念] 1.阻塞 阻塞操作是指在执行设备操作时,托不能获得资源,则挂起进程直到满足操作所需的条件后再进行操作.被挂起的进程进入休眠状态(不占用cpu资源),从调度器的运行队列转移到等待队列,直到条件满足. 2.非阻塞 非阻塞操作是指在进行设备操作是,若操作条件不满足并不会挂起,而是直接返回或重新查询(一直占用CPU资源)直到操作条件满足为止. 当用户空间的应用程序调用read(),write()等方法时,若设备的资源不能被获取,而用户又希望以阻塞的方式来访问设备,驱动程序应当在设备驱动层的

MySQL新旧版本ORDER BY 处理方法

MySQL 的order by 涉及到三个参数:A. sort_buffer_size 排序缓存.B. read_rnd_buffer_size 第二次排序缓存.C. max_length_for_sort_data 带普通列的最大排序约束. 我来简单说下MySQL的排序规则.假设查询语句select * from tb1 where 1 order by  a ; 字段a没有建立索引:以上三个参数都足够大.MySQL内部有两种排序规则:第一种,是普通的排序.这种排序的特点是节省内存,但是最终会

移动端测试:优化原有功能,改动接口需要兼容新旧版本

在测试线下培训V1.0.1(月亮天使V4.8.0)时,因为在这个版本中改动了课程状态变更的逻辑,由原来的由教师点击上下课来更新课程状态,到根据排课时间,使用定时器来更新课程状态,在逻辑上有了很大的变化. 而且界面上,我的授课由原来的三个页签减少为两个,以及对应的角标数量统计等等多种情况.最初没有考虑到兼容旧版本的功能,导致修改后的接口对应不上,导致旧版的部分功能调用修改后的接口,返回参数异常等错误. 本次更新也不是强制更新的,所以后面修改接口或新增接口,兼容旧版本,以保证旧版本的正常运作,但是我

Android技巧小结之新旧版本Notification

最近开发用到了通知功能,但有几个地方老是提示deprecated,然后就找了篇文章学习了下新旧版本的不同. Notification即通知,用于在通知栏显示提示信息. 在较新的版本中(API level  > 11),Notification类中的一些方法被Android声明deprecated(弃用),其实基本上相当于全部弃用了,因为这个类本身方法就少得可怜. Android官方声明弃用,一定有它的理由,虽然我也不知道是什么.奈何本人轻度强迫症患者,人家都建议你不要用了,那就不要老是恪守着N年

[转帖]InfluxDB 1.2.0安装及新旧版本的注意事项

InfluxDB 1.2.0安装及新旧版本的注意事项 http://haibing.org/245?zwlqby=npztq3 挺好的文章 很好的解决了 上一个文档里面 关于 web admin 的问题 更多好文章见作者电子书集<Linux运维入门指南:生产运维需要掌握的技能> 随着大数据的爆发,系统数量也是直线上升,监控系统,收集系统运行状态成了保障业务正常运行中的重要一个环节. 针对这种产生频率快.带时间标签.测点多.信息量大的数据,时序数据库(Time Series Database,简

浅谈 angular新旧版本问题

一直在学习angularJs,之前用的版本比较老,前些天更新了一下angularJs的版本,然后发现了一些问题,希望和大家分享一下. 在老的版本里控制器直接用函数定义就可以 比如: 在angularJs1.3.0中controller 直接写成函数就可以  但是在新版本里写控制器需要这样: 新版本里 我用的 1.3.9版本,必须定义angular.module,直接写成函数的形式angularJs不识别了. 然后今天我用angular-1.3.9写了一个route,一直在报错.我就想是不是版本的