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设备可以正常工作即可。


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值