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
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写操作
上一篇: 盘点野菜八宝菜的种类作用跟吃法