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

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

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

对比旧版本中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设备可以正常工作即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值