1. 概述
详细讲解请参考这篇博客:【genius_platform软件平台开发】第五十一讲:Linux系统内存映射mmap原理 主要就是内核内存区域的迎神,方便用户空间操控该内存,获取数据。
2. 应用层
m_pBuffers = (StuV4l2FrameBuffer *)calloc(info.count, sizeof(StuV4l2FrameBuffer));
CHECKI(m_pBuffers);
LOGMSG("CV4l2CaptureIr::initMmap calloc m_pBuffers=[%p] size=[%u]", m_pBuffers, info.count * sizeof(StuV4l2FrameBuffer));
for (int nIdx = 0; nIdx < m_nBuffersCount; ++nIdx)
{
struct v4l2_buffer info;
MEMSET(info);
info.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
info.memory = V4L2_MEMORY_MMAP;
info.index = nIdx;
if (-1 == this->ioCtrl(m_nFd, VIDIOC_QBUF, &info))
{
LOGERROR("CV4l2CaptureIr::initMmap is error... VIDIOC_QBUF");
return ReturnCode_Error;
}
if (-1 == this->ioCtrl(m_nFd, VIDIOC_QUERYBUF, &info))
{
LOGERROR("CV4l2CaptureIr::initMmap is error... DALI_IR_SENSOR_DEV_NAME=[%s] VIDIOC_QUERYBUF", DALI_IR_SENSOR_DEV_NAME);
return ReturnCode_Error;
}
m_pBuffers[nIdx].unLength = info.length;
m_pBuffers[nIdx].pBuffer = mmap(NULL , info.length, PROT_READ | PROT_WRITE , MAP_SHARED , m_nFd, info.m.offset);
if (MAP_FAILED == m_pBuffers[nIdx].pBuffer)
{
LOGERROR("CV4l2CaptureIr::initMmap DALI_IR_SENSOR_DEV_NAME=[%s] VIDIOC_QUERYBUF", DALI_IR_SENSOR_DEV_NAME);
return ReturnCode_Error;
}
LOGMSG("CV4l2CaptureIr::initMmap nIdx=[%d] pBuffer=[%p] unLength=[%d] m_nFd=[%d] offset=[%u]", nIdx, m_pBuffers[nIdx].pBuffer, m_pBuffers[nIdx].unLength, m_nFd, info.m.offset);
}
3. 驱动层
3.1 vb2_mmap函数
int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
{
unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
struct vb2_buffer *vb;
unsigned int buffer = 0, plane = 0;
int ret;
unsigned long length;
if (q->memory != VB2_MEMORY_MMAP) {
dprintk(1, "queue is not currently set up for mmap\n");
return -EINVAL;
}
if (!(vma->vm_flags & VM_SHARED)) {
dprintk(1, "invalid vma flags, VM_SHARED needed\n");
return -EINVAL;
}
if (q->is_output) {
if (!(vma->vm_flags & VM_WRITE)) {
dprintk(1, "invalid vma flags, VM_WRITE needed\n");
return -EINVAL;
}
} else {
if (!(vma->vm_flags & VM_READ)) {
dprintk(1, "invalid vma flags, VM_READ needed\n");
return -EINVAL;
}
}
mutex_lock(&q->mmap_lock);
if (vb2_fileio_is_active(q)) {
dprintk(1, "mmap: file io in progress\n");
ret = -EBUSY;
goto unlock;
}
ret = __find_plane_by_offset(q, off, &buffer, &plane);
if (ret)
goto unlock;
vb = q->bufs[buffer];
length = PAGE_ALIGN(vb->planes[plane].length);
if (length < (vma->vm_end - vma->vm_start)) {
dprintk(1,
"MMAP invalid, as it would overflow buffer length\n");
ret = -EINVAL;
goto unlock;
}
ret = call_memop(vb, mmap, vb->planes[plane].mem_priv, vma);
unlock:
mutex_unlock(&q->mmap_lock);
if (ret)
return ret;
dprintk(3, "buffer %d, plane %d successfully mapped\n", buffer, plane);
return 0;
}
EXPORT_SYMBOL_GPL(vb2_mmap);
#define log_memop(vb, op) \
dprintk(2, "call_memop(%p, %d, %s)%s\n", \
(vb)->vb2_queue, (vb)->index, #op, \
(vb)->vb2_queue->mem_ops->op ? "" : " (nop)")
#define call_memop(vb, op, args...) \
({ \
struct vb2_queue *_q = (vb)->vb2_queue; \
int err; \
\
log_memop(vb, op); \
err = _q->mem_ops->op ? _q->mem_ops->op(args) : 0; \
if (!err) \
(vb)->cnt_mem_ ## op++; \
err; \
})
|