欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

qcom v4l2 实现分析

程序员文章站 2022-07-01 20:24:29
...

1.queue buf 过程
Qcom HAL code

int32_t mm_stream_qbuf(mm_stream_t *my_obj, mm_camera_buf_def_t *buf)
{
    int32_t rc = 0;
    uint32_t length = 0;
    struct v4l2_buffer buffer;
    struct v4l2_plane planes[VIDEO_MAX_PLANES];
    LOGD("E, my_handle = 0x%x, fd = %d, state = %d, stream type = %d",
          my_obj->my_hdl, my_obj->fd, my_obj->state,
         my_obj->stream_info->stream_type);
    if (buf->buf_type == CAM_STREAM_BUF_TYPE_USERPTR) {
        LOGD("USERPTR num_buf = %d, idx = %d",
                buf->user_buf.bufs_used, buf->buf_idx);
        memset(&planes, 0, sizeof(planes));
        planes[0].length = my_obj->stream_info->user_buf_info.size;
        planes[0].m.userptr = buf->fd;
        length = 1;
    } else {
        memcpy(planes, buf->planes_buf.planes, sizeof(planes));
        length = buf->planes_buf.num_planes;
    }
    memset(&buffer, 0, sizeof(buffer));
    buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
    buffer.memory = V4L2_MEMORY_USERPTR;
    buffer.index = (__u32)buf->buf_idx;
    buffer.m.planes = &planes[0];
    buffer.length = (__u32)length;
    rc = mm_stream_handle_cache_ops(my_obj, buf, FALSE);
    if (rc != 0) {
        LOGE("Error cleaning/invalidating the buffer");
    }
    pthread_mutex_lock(&my_obj->buf_lock);
    my_obj->queued_buffer_count++;

    pthread_mutex_unlock(&my_obj->buf_lock);
    rc = ioctl(my_obj->fd, VIDIOC_QBUF, &buffer);
    pthread_mutex_unlock(&my_obj->buf_lock);
    return rc;
}

上面关键部分是

        planes[0].length = my_obj->stream_info->user_buf_info.size;//buffer 的大小
        planes[0].m.userptr = buf->fd;// ion fd ,申请的实际buffer

kernel code

static void msm_isp_copy_planes_from_v4l2_buffer(
	struct msm_isp_qbuf_buffer *qbuf_buf,
	const struct v4l2_buffer *v4l2_buf)
{
	int i;
	qbuf_buf->num_planes = v4l2_buf->length;
	for (i = 0; i < qbuf_buf->num_planes; i++) {
		qbuf_buf->planes[i].addr = v4l2_buf->m.planes[i].m.userptr;
		qbuf_buf->planes[i].offset = v4l2_buf->m.planes[i].data_offset;
		qbuf_buf->planes[i].length = v4l2_buf->m.planes[i].length;
	}
}

这里的 planes[0].m.userptr 对应的就是 ion buffer fd,

static int msm_isp_prepare_isp_buf(struct msm_isp_buf_mgr *buf_mgr,
	struct msm_isp_buffer *buf_info,
	struct msm_isp_qbuf_buffer *qbuf_buf)
{
	int i, rc = -1;
	struct msm_isp_buffer_mapped_info *mapped_info;
	struct buffer_cmd *buf_pending = NULL;
	int domain_num;
	uint32_t accu_length = 0;
	unsigned long flags;
	if (buf_mgr->secure_enable == NON_SECURE_MODE)
		domain_num = buf_mgr->iommu_domain_num;
	else
		domain_num = buf_mgr->iommu_domain_num_secure;
	for (i = 0; i < qbuf_buf->num_planes; i++) {
		mapped_info = &buf_info->mapped_info[i];
		mapped_info->handle =
		ion_import_dma_buf(buf_mgr->client,
			qbuf_buf->planes[i].addr);
		if (IS_ERR_OR_NULL(mapped_info->handle)) {
			pr_err_ratelimited("%s: null/error ION handle %p\n",
				__func__, mapped_info->handle);
			goto ion_map_error;
		}
		if (ion_map_iommu(buf_mgr->client, mapped_info->handle,
				domain_num, 0, SZ_4K,
				0, &(mapped_info->paddr),
				&(mapped_info->len), 0, 0) < 0) {
			rc = -EINVAL;
			pr_err("%s: cannot map address", __func__);
			ion_free(buf_mgr->client, mapped_info->handle);
			goto ion_map_error;
		}
		mapped_info->paddr += accu_length;
		accu_length += qbuf_buf->planes[i].length;
		CDBG("%s: plane: %d addr:%lu\n",
			__func__, i, (unsigned long)mapped_info->paddr);
		buf_pending = kzalloc(sizeof(struct buffer_cmd), GFP_ATOMIC);
		if (!buf_pending) {
			pr_err("No free memory for buf_pending\n");
			return rc;
		}
		buf_pending->mapped_info = mapped_info;
		spin_lock_irqsave(&buf_mgr->bufq_list_lock, flags);
		list_add_tail(&buf_pending->list, &buf_mgr->buffer_q);
		spin_unlock_irqrestore(&buf_mgr->bufq_list_lock, flags);
	}
	buf_info->num_planes = qbuf_buf->num_planes;
	return 0;
ion_map_error:
	for (--i; i >= 0; i--) {
		mapped_info = &buf_info->mapped_info[i];
		ion_unmap_iommu(buf_mgr->client, mapped_info->handle,
		buf_mgr->iommu_domain_num, 0);
		ion_free(buf_mgr->client, mapped_info->handle);
	}
	return rc;
}

关键部分

mapped_info->handle =
		ion_import_dma_buf(buf_mgr->client,
			qbuf_buf->planes[i].addr);

通过ion fd 经过 dma buffer相关操作经过iommu翻译就可以得到真实的物理地址对应的虚拟地址送给硬件去DMA写操作