qcom v4l2 實現分析

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寫操作

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章