Loading drivers/media/platform/msm/vidc/msm_vidc.c +350 −89 Original line number Diff line number Diff line Loading @@ -199,21 +199,31 @@ int msm_vidc_reqbufs(void *instance, struct v4l2_requestbuffers *b) return -EINVAL; } struct buffer_info *get_registered_buf(struct list_head *list, int fd, u32 buff_off, u32 size, int *plane) struct buffer_info *get_registered_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b, int idx, int *plane) { struct buffer_info *temp; struct buffer_info *ret = NULL; int i; struct list_head *list = &inst->registered_bufs; int fd = b->m.planes[idx].reserved[0]; u32 buff_off = b->m.planes[idx].reserved[1]; u32 size = b->m.planes[idx].length; u32 device_addr = b->m.planes[idx].m.userptr; if (!list || fd < 0 || !plane) { dprintk(VIDC_ERR, "Invalid input\n"); goto err_invalid_input; } *plane = 0; mutex_lock(&inst->lock); list_for_each_entry(temp, list, list) { for (i = 0; (i < temp->num_planes) && (i < VIDEO_MAX_PLANES); i++) { if (temp && temp->fd[i] == fd && if (temp && ((fd == temp->fd[i]) || (device_addr == temp->device_addr[i])) && (CONTAINS(temp->buff_off[i], temp->size[i], buff_off) || CONTAINS(buff_off, Loading @@ -231,25 +241,30 @@ struct buffer_info *get_registered_buf(struct list_head *list, if (ret) break; } mutex_unlock(&inst->lock); err_invalid_input: return ret; } struct buffer_info *get_same_fd_buffer(struct list_head *list, int fd, int *plane) struct buffer_info *get_same_fd_buffer(struct msm_vidc_inst *inst, struct list_head *list, int fd, int *plane) { struct buffer_info *temp; struct buffer_info *ret = NULL; int i; if (fd == 0) return NULL; if (!list || fd < 0 || !plane) { dprintk(VIDC_ERR, "Invalid input\n"); goto err_invalid_input; } *plane = 0; mutex_lock(&inst->lock); list_for_each_entry(temp, list, list) { for (i = 0; (i < temp->num_planes) && (i < VIDEO_MAX_PLANES); i++) { if (temp && temp->fd[i] == fd) { temp->same_fd_ref[i]++; dprintk(VIDC_INFO, "Found same fd buffer\n"); ret = temp; Loading @@ -260,26 +275,28 @@ struct buffer_info *get_same_fd_buffer(struct list_head *list, if (ret) break; } mutex_unlock(&inst->lock); err_invalid_input: return ret; } struct buffer_info *device_to_uvaddr( struct buffer_info *device_to_uvaddr(struct msm_vidc_inst *inst, struct list_head *list, u32 device_addr) { struct buffer_info *temp = NULL; struct buffer_info *dummy = NULL; int found = 0; int i; if (!list || !device_addr) { dprintk(VIDC_ERR, "Invalid input\n"); goto err_invalid_input; } list_for_each_entry(temp, list, list) { mutex_lock(&inst->lock); list_for_each_entry_safe(temp, dummy, list, list) { for (i = 0; (i < temp->num_planes) && (i < VIDEO_MAX_PLANES); i++) { if (temp && temp->device_addr[i] == device_addr) { if (temp && !temp->inactive && temp->device_addr[i] == device_addr) { dprintk(VIDC_INFO, "Found same fd buffer\n"); found = 1; Loading @@ -289,6 +306,7 @@ struct buffer_info *device_to_uvaddr( if (found) break; } mutex_unlock(&inst->lock); err_invalid_input: return temp; } Loading @@ -301,8 +319,31 @@ static inline void populate_buf_info(struct buffer_info *binfo, binfo->buff_off[i] = b->m.planes[i].reserved[1]; binfo->size[i] = b->m.planes[i].length; binfo->uvaddr[i] = b->m.planes[i].m.userptr; binfo->device_addr[i] = 0; binfo->handle[i] = NULL; binfo->num_planes = b->length; binfo->memory = b->memory; binfo->v4l2_index = b->index; binfo->dequeued = false; dprintk(VIDC_DBG, "%s: fd[%d] = %d b->index = %d", __func__, i, binfo->fd[0], b->index); } static inline void repopulate_v4l2_buffer(struct v4l2_buffer *b, struct buffer_info *binfo) { int i = 0; b->type = binfo->type; b->length = binfo->num_planes; b->memory = binfo->memory; b->index = binfo->v4l2_index; for (i = 0; i < binfo->num_planes; ++i) { b->m.planes[i].reserved[0] = binfo->fd[i]; b->m.planes[i].reserved[1] = binfo->buff_off[i]; b->m.planes[i].length = binfo->size[i]; b->m.planes[i].m.userptr = binfo->device_addr[i]; dprintk(VIDC_DBG, "%s %d %d %d %u\n", __func__, binfo->fd[i], binfo->buff_off[i], binfo->size[i], binfo->device_addr[i]); } } static struct msm_smem *map_buffer(struct msm_vidc_inst *inst, Loading Loading @@ -347,22 +388,47 @@ static inline enum hal_buffer get_hal_buffer_type( return -EINVAL; } static inline bool is_dynamic_output_buffer_mode(struct v4l2_buffer *b, struct msm_vidc_inst *inst) { return ((b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) && (inst->buffer_mode_set[CAPTURE_PORT] == HAL_BUFFER_MODE_DYNAMIC)); } static inline void save_v4l2_buffer(struct v4l2_buffer *b, struct buffer_info *binfo) { int i = 0; for (i = 0; i < b->length; ++i) { if (EXTRADATA_IDX(b->length) && (i == EXTRADATA_IDX(b->length)) && !b->m.planes[i].length) { continue; } populate_buf_info(binfo, b, i); } } int map_and_register_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b) { struct buffer_info *binfo = NULL; struct buffer_info *temp = NULL; int plane = 0; int i, rc = 0; int i = 0, rc = 0; if (!b || !inst) { dprintk(VIDC_ERR, "%s: invalid input\n", __func__); return -EINVAL; } /* For kernel clients, we do not need to map the buffer again.*/ if (!b->m.planes[0].reserved[0]) return 0; binfo = kzalloc(sizeof(*binfo), GFP_KERNEL); if (!binfo) { dprintk(VIDC_ERR, "Out of memory\n"); rc = -ENOMEM; goto exit; } if (b->length > VIDEO_MAX_PLANES) { dprintk(VIDC_ERR, "Num planes exceeds max: %d, %d\n", b->length, VIDEO_MAX_PLANES); Loading @@ -370,12 +436,8 @@ int map_and_register_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b) goto exit; } binfo = kzalloc(sizeof(*binfo), GFP_KERNEL); if (!binfo) { dprintk(VIDC_ERR, "Out of memory\n"); rc = -ENOMEM; goto exit; } dprintk(VIDC_DBG, "[MAP] Create binfo = %p fd = %d type = %d\n", binfo, b->m.planes[0].reserved[0], b->type); for (i = 0; i < b->length; ++i) { if (EXTRADATA_IDX(b->length) && Loading @@ -383,27 +445,44 @@ int map_and_register_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b) !b->m.planes[i].length) { continue; } temp = get_registered_buf(&inst->registered_bufs, b->m.planes[i].reserved[0], b->m.planes[i].reserved[1], b->m.planes[i].length, &plane); if (temp) { temp = get_registered_buf(inst, b, i, &plane); if (temp && !is_dynamic_output_buffer_mode(b, inst)) { dprintk(VIDC_DBG, "This memory region has already been prepared\n"); rc = -EINVAL; goto exit; } temp = get_same_fd_buffer(&inst->registered_bufs, if (temp && is_dynamic_output_buffer_mode(b, inst) && (i == 0)) { /* * Buffer is already present in registered list * increment ref_count, populate new values of v4l2 * buffer in existing buffer_info struct. * * We will use the saved buffer info and queue it when * we receive RELEASE_BUFFER_REFERENCE EVENT from f/w. */ dprintk(VIDC_DBG, "[MAP] Buffer already prepared\n"); rc = buf_ref_get(inst, temp); if (rc < 0) return rc; save_v4l2_buffer(b, temp); rc = -EEXIST; goto exit; } temp = get_same_fd_buffer(inst, &inst->registered_bufs, b->m.planes[i].reserved[0], &plane); if (temp) { populate_buf_info(binfo, b, i); if (temp) { binfo->device_addr[i] = temp->handle[plane]->device_addr + binfo->buff_off[i]; b->m.planes[i].m.userptr = binfo->device_addr[i]; binfo->mapped[i] = false; } else { populate_buf_info(binfo, b, i); if (inst->map_output_buffer) { binfo->handle[i] = map_buffer(inst, &b->m.planes[i], get_hal_buffer_type(inst, b)); Loading @@ -411,24 +490,180 @@ int map_and_register_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b) rc = -EINVAL; goto exit; } dprintk(VIDC_DBG, "[MAP] - mapped handle[%d] = %p fd[%d] = %d", i, binfo->handle[i], i, binfo->fd[i]); binfo->mapped[i] = true; binfo->device_addr[i] = binfo->handle[i]->device_addr + binfo->buff_off[i]; b->m.planes[i].m.userptr = binfo->device_addr[i]; } else { binfo->device_addr[i] = b->m.planes[i].m.userptr; } dprintk(VIDC_DBG, "Registering buffer: %d, %d, %d\n", b->m.planes[i].reserved[0], b->m.planes[i].reserved[1], b->m.planes[i].length); } /* We maintain one ref count for all planes*/ if ((i == 0) && is_dynamic_output_buffer_mode(b, inst)) { rc = buf_ref_get(inst, binfo); if (rc < 0) return rc; } binfo->num_planes = b->length; } dprintk(VIDC_DBG, "[MAP] Adding binfo = %p to list\n", binfo); mutex_lock(&inst->lock); list_add_tail(&binfo->list, &inst->registered_bufs); mutex_unlock(&inst->lock); return 0; exit: kfree(binfo); return rc; } int unmap_and_deregister_buf(struct msm_vidc_inst *inst, struct buffer_info *binfo) { int i = 0; struct buffer_info *temp = NULL; struct buffer_info *dummy = NULL; struct list_head *list; bool found = false, keep_node = false; if (!inst || !binfo) { dprintk(VIDC_ERR, "%s invalid param: %p %p\n", __func__, inst, binfo); return -EINVAL; } mutex_lock(&inst->lock); list = &inst->registered_bufs; /* * Make sure the buffer to be unmapped and deleted * from the registered list is present in the list. */ list_for_each_entry_safe(temp, dummy, list, list) { if (temp == binfo) { found = true; break; } } /* * Free the buffer info only if * - buffer info has not been deleted from registered list * - vidc client has called dqbuf on the buffer * - no references are held on the buffer */ if (!found || !temp || !temp->pending_deletion || !temp->dequeued) goto exit; for (i = 0; i < temp->num_planes; i++) { /* * Unmap the handle only if the buffer has been mapped and no * other buffer has a reference to this buffer. * In case of buffers with same fd, we will map the buffer only * once and subsequent buffers will refer to the mapped buffer's * device address. * For buffers which share the same fd, do not unmap and keep * the buffer info in registered list. */ if (temp->handle[i] && temp->mapped[i] && !temp->same_fd_ref[i]) { dprintk(VIDC_DBG, "[UNMAP] - handle[%d] = %p fd[%d] = %d", i, temp->handle[i], i, temp->fd[i]); msm_smem_free(inst->mem_client, temp->handle[i]); } if (temp->same_fd_ref[i]) keep_node = true; else { temp->fd[i] = 0; temp->handle[i] = 0; temp->device_addr[i] = 0; temp->uvaddr[i] = 0; } } if (!keep_node) { dprintk(VIDC_DBG, "[UNMAP] AND-FREED binfo: %p\n", temp); list_del(&temp->list); kfree(temp); } else { temp->inactive = true; dprintk(VIDC_DBG, "[UNMAP] NOT-FREED binfo: %p\n", temp); } exit: mutex_unlock(&inst->lock); return 0; } int qbuf_dynamic_buf(struct msm_vidc_inst *inst, struct buffer_info *binfo) { struct v4l2_buffer b = {0}; struct v4l2_plane plane[VIDEO_MAX_PLANES] = { {0} }; if (!binfo) { dprintk(VIDC_ERR, "%s invalid param: %p\n", __func__, binfo); return -EINVAL; } dprintk(VIDC_DBG, "%s fd[0] = %d\n", __func__, binfo->fd[0]); b.m.planes = plane; repopulate_v4l2_buffer(&b, binfo); if (inst->session_type == MSM_VIDC_DECODER) return msm_vdec_qbuf(inst, &b); if (inst->session_type == MSM_VIDC_ENCODER) return msm_venc_qbuf(inst, &b); return -EINVAL; } int output_buffer_cache_invalidate(struct msm_vidc_inst *inst, struct buffer_info *binfo) { int i = 0; int rc = 0; if (!inst) { dprintk(VIDC_ERR, "%s: invalid inst: %p\n", __func__, inst); return -EINVAL; } if (!inst->map_output_buffer) return 0; if (!binfo) { dprintk(VIDC_ERR, "%s: invalid buffer info: %p\n", __func__, inst); return -EINVAL; } if (binfo->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) return 0; for (i = 0; i < binfo->num_planes; i++) { if (binfo->handle[i]) { rc = msm_smem_cache_operations(inst->mem_client, binfo->handle[i], SMEM_CACHE_INVALIDATE); if (rc) { dprintk(VIDC_ERR, "%s: Failed to clean caches: %d\n", __func__, rc); return -EINVAL; } } } return 0; } int msm_vidc_prepare_buf(void *instance, struct v4l2_buffer *b) { Loading @@ -437,8 +672,18 @@ int msm_vidc_prepare_buf(void *instance, struct v4l2_buffer *b) if (!inst || !b) return -EINVAL; if (is_dynamic_output_buffer_mode(b, inst)) { dprintk(VIDC_ERR, "%s: not supported in dynamic buffer mode\n", __func__); return -EINVAL; } /* Map the buffer only for non-kernel clients*/ if (b->m.planes[0].reserved[0]) { inst->map_output_buffer = true; if (map_and_register_buf(inst, b)) return -EINVAL; } if (inst->session_type == MSM_VIDC_DECODER) return msm_vdec_prepare_buf(instance, b); Loading Loading @@ -533,8 +778,20 @@ int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b) b->length); return -EINVAL; } if (is_dynamic_output_buffer_mode(b, inst)) { if (b->m.planes[0].reserved[0]) inst->map_output_buffer = true; rc = map_and_register_buf(inst, b); if (rc == -EEXIST) return 0; if (rc) return rc; } for (i = 0; i < b->length; ++i) { if (!b->m.planes[i].reserved[0]) if (!inst->map_output_buffer) continue; if (EXTRADATA_IDX(b->length) && (i == EXTRADATA_IDX(b->length)) && Loading @@ -542,10 +799,8 @@ int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b) b->m.planes[i].m.userptr = 0; continue; } binfo = get_registered_buf(&inst->registered_bufs, b->m.planes[i].reserved[0], b->m.planes[i].reserved[1], b->m.planes[i].length, &plane); binfo = get_registered_buf(inst, b, i, &plane); if (!binfo) { dprintk(VIDC_ERR, "This buffer is not registered: %d, %d, %d\n", Loading Loading @@ -594,9 +849,8 @@ err_invalid_buff: int msm_vidc_dqbuf(void *instance, struct v4l2_buffer *b) { struct msm_vidc_inst *inst = instance; struct buffer_info *buffer_info; struct buffer_info *buffer_info = NULL; int i = 0, rc = 0; bool skip_invalidate = false; if (!inst || !b) return -EINVAL; Loading @@ -606,48 +860,54 @@ int msm_vidc_dqbuf(void *instance, struct v4l2_buffer *b) b->length); return -EINVAL; } if (!b->m.planes[0].reserved[0]) skip_invalidate = true; if (inst->session_type == MSM_VIDC_DECODER) rc = msm_vdec_dqbuf(instance, b); if (inst->session_type == MSM_VIDC_ENCODER) rc = msm_venc_dqbuf(instance, b); if (rc) goto fail_dq_buf; return rc; for (i = 0; i < b->length; i++) { if ((EXTRADATA_IDX(b->length) && if (!inst->map_output_buffer) continue; if (EXTRADATA_IDX(b->length) && (i == EXTRADATA_IDX(b->length)) && !b->m.planes[i].m.userptr) || skip_invalidate) { !b->m.planes[i].m.userptr) { continue; } buffer_info = device_to_uvaddr( buffer_info = device_to_uvaddr(inst, &inst->registered_bufs, b->m.planes[i].m.userptr); b->m.planes[i].m.userptr = buffer_info->uvaddr[i]; if (!b->m.planes[i].m.userptr) { if (!buffer_info) { dprintk(VIDC_ERR, "Failed to find user virtual address, 0x%lx, %d, %d\n", b->m.planes[i].m.userptr, b->type, i); goto fail_dq_buf; "%s no buffer info registered for buffer addr: 0x%lx\n", __func__, b->m.planes[i].m.userptr); return -EINVAL; } if (buffer_info->handle[i] && (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) { rc = msm_smem_cache_operations(inst->mem_client, buffer_info->handle[i], SMEM_CACHE_INVALIDATE); if (rc) { b->m.planes[i].m.userptr = buffer_info->uvaddr[i]; if (!b->m.planes[i].m.userptr) { dprintk(VIDC_ERR, "Failed to clean caches: %d\n", rc); goto fail_dq_buf; } "%s: Failed to find user virtual address, 0x%lx, %d, %d\n", __func__, b->m.planes[i].m.userptr, b->type, i); return -EINVAL; } } if (is_dynamic_output_buffer_mode(b, inst)) { mutex_lock(&inst->lock); buffer_info->dequeued = true; mutex_unlock(&inst->lock); dprintk(VIDC_DBG, "[DEQUEUED]: fd[0] = %d\n", buffer_info->fd[0]); rc = unmap_and_deregister_buf(inst, buffer_info); } else rc = output_buffer_cache_invalidate(inst, buffer_info); return rc; fail_dq_buf: dprintk(VIDC_DBG, "Failed to dqbuf, capability: %d\n", b->type); return -EINVAL; } int msm_vidc_streamon(void *instance, enum v4l2_buf_type i) Loading Loading @@ -836,6 +1096,7 @@ void *msm_vidc_open(int core_id, int session_type) init_waitqueue_head(&inst->kernel_event_queue); inst->state = MSM_VIDC_CORE_UNINIT_DONE; inst->core = core; inst->map_output_buffer = false; for (i = SESSION_MSG_INDEX(SESSION_MSG_START); i <= SESSION_MSG_INDEX(SESSION_MSG_END); i++) { Loading drivers/media/platform/msm/vidc/msm_vidc_common.c +105 −0 Original line number Diff line number Diff line Loading @@ -819,6 +819,107 @@ static void handle_ebd(enum command_response cmd, void *data) } } int buf_ref_get(struct msm_vidc_inst *inst, struct buffer_info *binfo) { int cnt = 0; if (!inst || !binfo) return -EINVAL; mutex_lock(&inst->lock); atomic_inc(&binfo->ref_count); cnt = atomic_read(&binfo->ref_count); if (cnt > 2) { dprintk(VIDC_ERR, "%s: invalid ref_cnt: %d\n", __func__, cnt); cnt = -EINVAL; } dprintk(VIDC_DBG, "REF_GET[%d] fd[0] = %d\n", cnt, binfo->fd[0]); mutex_unlock(&inst->lock); return cnt; } int buf_ref_put(struct msm_vidc_inst *inst, struct buffer_info *binfo) { int rc = 0; int cnt; bool release_buf = false; bool qbuf_again = false; if (!inst || !binfo) return -EINVAL; mutex_lock(&inst->lock); atomic_dec(&binfo->ref_count); cnt = atomic_read(&binfo->ref_count); dprintk(VIDC_DBG, "REF_PUT[%d] fd[0] = %d\n", cnt, binfo->fd[0]); if (cnt == 0) release_buf = true; else if (cnt == 1) qbuf_again = true; else { dprintk(VIDC_ERR, "%s: invalid ref_cnt: %d\n", __func__, cnt); cnt = -EINVAL; } mutex_unlock(&inst->lock); if (cnt < 0) return cnt; rc = output_buffer_cache_invalidate(inst, binfo); if (rc) return rc; if (release_buf) { /* * We can not delete binfo here as we need to set the user * virtual address saved in binfo->uvaddr to the dequeued v4l2 * buffer. * * We will set the pending_deletion flag to true here and delete * binfo from registered list in dqbuf after setting the uvaddr. */ dprintk(VIDC_DBG, "fd[0] = %d -> pending_deletion = true\n", binfo->fd[0]); binfo->pending_deletion = true; } else if (qbuf_again) { rc = qbuf_dynamic_buf(inst, binfo); if (!rc) return rc; } return cnt; } static void handle_dynamic_buffer(struct msm_vidc_inst *inst, u32 device_addr, u32 flags) { struct buffer_info *binfo = NULL; /* * Update reference count and release OR queue back the buffer, * only when firmware is not holding a reference. */ if (inst->buffer_mode_set[CAPTURE_PORT] == HAL_BUFFER_MODE_DYNAMIC) { binfo = device_to_uvaddr(inst, &inst->registered_bufs, device_addr); if (!binfo) { dprintk(VIDC_ERR, "%s buffer not found in registered list\n", __func__); return; } if (flags & HAL_BUFFERFLAG_READONLY) { dprintk(VIDC_DBG, "_F_B_D_ fd[0] = %d -> Reference with f/w", binfo->fd[0]); } else { dprintk(VIDC_DBG, "_F_B_D_ fd[0] = %d -> FBD_ref_released\n", binfo->fd[0]); buf_ref_put(inst, binfo); } } } static void handle_fbd(enum command_response cmd, void *data) { struct msm_vidc_cb_data_done *response = data; Loading Loading @@ -862,6 +963,10 @@ static void handle_fbd(enum command_response cmd, void *data) } vb->v4l2_buf.flags = 0; handle_dynamic_buffer(inst, (u32)fill_buf_done->packet_buffer1, fill_buf_done->flags1); if (fill_buf_done->flags1 & HAL_BUFFERFLAG_READONLY) vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_READONLY; if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOS) vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_EOS; if (fill_buf_done->flags1 & HAL_BUFFERFLAG_CODECCONFIG) Loading drivers/media/platform/msm/vidc/msm_vidc_internal.h +17 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ #ifndef _MSM_VIDC_INTERNAL_H_ #define _MSM_VIDC_INTERNAL_H_ #include <linux/atomic.h> #include <linux/list.h> #include <linux/types.h> #include <linux/completion.h> Loading Loading @@ -231,6 +232,7 @@ struct msm_vidc_inst { struct msm_vidc_core_capability capability; enum buffer_mode_type buffer_mode_set[MAX_PORT_NUM]; struct list_head registered_bufs; bool map_output_buffer; }; extern struct msm_vidc_drv *vidc_driver; Loading Loading @@ -271,6 +273,21 @@ struct buffer_info { u32 uvaddr[VIDEO_MAX_PLANES]; u32 device_addr[VIDEO_MAX_PLANES]; struct msm_smem *handle[VIDEO_MAX_PLANES]; enum v4l2_memory memory; u32 v4l2_index; bool pending_deletion; atomic_t ref_count; bool dequeued; bool inactive; bool mapped[VIDEO_MAX_PLANES]; int same_fd_ref[VIDEO_MAX_PLANES]; }; struct buffer_info *device_to_uvaddr(struct msm_vidc_inst *inst, struct list_head *list, u32 device_addr); int buf_ref_get(struct msm_vidc_inst *inst, struct buffer_info *binfo); int output_buffer_cache_invalidate(struct msm_vidc_inst *inst, struct buffer_info *binfo); int qbuf_dynamic_buf(struct msm_vidc_inst *inst, struct buffer_info *binfo); #endif include/uapi/linux/videodev2.h +1 −0 Original line number Diff line number Diff line Loading @@ -712,6 +712,7 @@ struct v4l2_buffer { #define V4L2_QCOM_BUF_FLAG_EOS 0x1000000 #define V4L2_QCOM_BUF_TS_DISCONTINUITY 0x2000000 #define V4L2_QCOM_BUF_TS_ERROR 0x4000000 #define V4L2_QCOM_BUF_FLAG_READONLY 0x8000000 /** * struct v4l2_exportbuffer - export of video buffer as DMABUF file descriptor Loading Loading
drivers/media/platform/msm/vidc/msm_vidc.c +350 −89 Original line number Diff line number Diff line Loading @@ -199,21 +199,31 @@ int msm_vidc_reqbufs(void *instance, struct v4l2_requestbuffers *b) return -EINVAL; } struct buffer_info *get_registered_buf(struct list_head *list, int fd, u32 buff_off, u32 size, int *plane) struct buffer_info *get_registered_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b, int idx, int *plane) { struct buffer_info *temp; struct buffer_info *ret = NULL; int i; struct list_head *list = &inst->registered_bufs; int fd = b->m.planes[idx].reserved[0]; u32 buff_off = b->m.planes[idx].reserved[1]; u32 size = b->m.planes[idx].length; u32 device_addr = b->m.planes[idx].m.userptr; if (!list || fd < 0 || !plane) { dprintk(VIDC_ERR, "Invalid input\n"); goto err_invalid_input; } *plane = 0; mutex_lock(&inst->lock); list_for_each_entry(temp, list, list) { for (i = 0; (i < temp->num_planes) && (i < VIDEO_MAX_PLANES); i++) { if (temp && temp->fd[i] == fd && if (temp && ((fd == temp->fd[i]) || (device_addr == temp->device_addr[i])) && (CONTAINS(temp->buff_off[i], temp->size[i], buff_off) || CONTAINS(buff_off, Loading @@ -231,25 +241,30 @@ struct buffer_info *get_registered_buf(struct list_head *list, if (ret) break; } mutex_unlock(&inst->lock); err_invalid_input: return ret; } struct buffer_info *get_same_fd_buffer(struct list_head *list, int fd, int *plane) struct buffer_info *get_same_fd_buffer(struct msm_vidc_inst *inst, struct list_head *list, int fd, int *plane) { struct buffer_info *temp; struct buffer_info *ret = NULL; int i; if (fd == 0) return NULL; if (!list || fd < 0 || !plane) { dprintk(VIDC_ERR, "Invalid input\n"); goto err_invalid_input; } *plane = 0; mutex_lock(&inst->lock); list_for_each_entry(temp, list, list) { for (i = 0; (i < temp->num_planes) && (i < VIDEO_MAX_PLANES); i++) { if (temp && temp->fd[i] == fd) { temp->same_fd_ref[i]++; dprintk(VIDC_INFO, "Found same fd buffer\n"); ret = temp; Loading @@ -260,26 +275,28 @@ struct buffer_info *get_same_fd_buffer(struct list_head *list, if (ret) break; } mutex_unlock(&inst->lock); err_invalid_input: return ret; } struct buffer_info *device_to_uvaddr( struct buffer_info *device_to_uvaddr(struct msm_vidc_inst *inst, struct list_head *list, u32 device_addr) { struct buffer_info *temp = NULL; struct buffer_info *dummy = NULL; int found = 0; int i; if (!list || !device_addr) { dprintk(VIDC_ERR, "Invalid input\n"); goto err_invalid_input; } list_for_each_entry(temp, list, list) { mutex_lock(&inst->lock); list_for_each_entry_safe(temp, dummy, list, list) { for (i = 0; (i < temp->num_planes) && (i < VIDEO_MAX_PLANES); i++) { if (temp && temp->device_addr[i] == device_addr) { if (temp && !temp->inactive && temp->device_addr[i] == device_addr) { dprintk(VIDC_INFO, "Found same fd buffer\n"); found = 1; Loading @@ -289,6 +306,7 @@ struct buffer_info *device_to_uvaddr( if (found) break; } mutex_unlock(&inst->lock); err_invalid_input: return temp; } Loading @@ -301,8 +319,31 @@ static inline void populate_buf_info(struct buffer_info *binfo, binfo->buff_off[i] = b->m.planes[i].reserved[1]; binfo->size[i] = b->m.planes[i].length; binfo->uvaddr[i] = b->m.planes[i].m.userptr; binfo->device_addr[i] = 0; binfo->handle[i] = NULL; binfo->num_planes = b->length; binfo->memory = b->memory; binfo->v4l2_index = b->index; binfo->dequeued = false; dprintk(VIDC_DBG, "%s: fd[%d] = %d b->index = %d", __func__, i, binfo->fd[0], b->index); } static inline void repopulate_v4l2_buffer(struct v4l2_buffer *b, struct buffer_info *binfo) { int i = 0; b->type = binfo->type; b->length = binfo->num_planes; b->memory = binfo->memory; b->index = binfo->v4l2_index; for (i = 0; i < binfo->num_planes; ++i) { b->m.planes[i].reserved[0] = binfo->fd[i]; b->m.planes[i].reserved[1] = binfo->buff_off[i]; b->m.planes[i].length = binfo->size[i]; b->m.planes[i].m.userptr = binfo->device_addr[i]; dprintk(VIDC_DBG, "%s %d %d %d %u\n", __func__, binfo->fd[i], binfo->buff_off[i], binfo->size[i], binfo->device_addr[i]); } } static struct msm_smem *map_buffer(struct msm_vidc_inst *inst, Loading Loading @@ -347,22 +388,47 @@ static inline enum hal_buffer get_hal_buffer_type( return -EINVAL; } static inline bool is_dynamic_output_buffer_mode(struct v4l2_buffer *b, struct msm_vidc_inst *inst) { return ((b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) && (inst->buffer_mode_set[CAPTURE_PORT] == HAL_BUFFER_MODE_DYNAMIC)); } static inline void save_v4l2_buffer(struct v4l2_buffer *b, struct buffer_info *binfo) { int i = 0; for (i = 0; i < b->length; ++i) { if (EXTRADATA_IDX(b->length) && (i == EXTRADATA_IDX(b->length)) && !b->m.planes[i].length) { continue; } populate_buf_info(binfo, b, i); } } int map_and_register_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b) { struct buffer_info *binfo = NULL; struct buffer_info *temp = NULL; int plane = 0; int i, rc = 0; int i = 0, rc = 0; if (!b || !inst) { dprintk(VIDC_ERR, "%s: invalid input\n", __func__); return -EINVAL; } /* For kernel clients, we do not need to map the buffer again.*/ if (!b->m.planes[0].reserved[0]) return 0; binfo = kzalloc(sizeof(*binfo), GFP_KERNEL); if (!binfo) { dprintk(VIDC_ERR, "Out of memory\n"); rc = -ENOMEM; goto exit; } if (b->length > VIDEO_MAX_PLANES) { dprintk(VIDC_ERR, "Num planes exceeds max: %d, %d\n", b->length, VIDEO_MAX_PLANES); Loading @@ -370,12 +436,8 @@ int map_and_register_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b) goto exit; } binfo = kzalloc(sizeof(*binfo), GFP_KERNEL); if (!binfo) { dprintk(VIDC_ERR, "Out of memory\n"); rc = -ENOMEM; goto exit; } dprintk(VIDC_DBG, "[MAP] Create binfo = %p fd = %d type = %d\n", binfo, b->m.planes[0].reserved[0], b->type); for (i = 0; i < b->length; ++i) { if (EXTRADATA_IDX(b->length) && Loading @@ -383,27 +445,44 @@ int map_and_register_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b) !b->m.planes[i].length) { continue; } temp = get_registered_buf(&inst->registered_bufs, b->m.planes[i].reserved[0], b->m.planes[i].reserved[1], b->m.planes[i].length, &plane); if (temp) { temp = get_registered_buf(inst, b, i, &plane); if (temp && !is_dynamic_output_buffer_mode(b, inst)) { dprintk(VIDC_DBG, "This memory region has already been prepared\n"); rc = -EINVAL; goto exit; } temp = get_same_fd_buffer(&inst->registered_bufs, if (temp && is_dynamic_output_buffer_mode(b, inst) && (i == 0)) { /* * Buffer is already present in registered list * increment ref_count, populate new values of v4l2 * buffer in existing buffer_info struct. * * We will use the saved buffer info and queue it when * we receive RELEASE_BUFFER_REFERENCE EVENT from f/w. */ dprintk(VIDC_DBG, "[MAP] Buffer already prepared\n"); rc = buf_ref_get(inst, temp); if (rc < 0) return rc; save_v4l2_buffer(b, temp); rc = -EEXIST; goto exit; } temp = get_same_fd_buffer(inst, &inst->registered_bufs, b->m.planes[i].reserved[0], &plane); if (temp) { populate_buf_info(binfo, b, i); if (temp) { binfo->device_addr[i] = temp->handle[plane]->device_addr + binfo->buff_off[i]; b->m.planes[i].m.userptr = binfo->device_addr[i]; binfo->mapped[i] = false; } else { populate_buf_info(binfo, b, i); if (inst->map_output_buffer) { binfo->handle[i] = map_buffer(inst, &b->m.planes[i], get_hal_buffer_type(inst, b)); Loading @@ -411,24 +490,180 @@ int map_and_register_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b) rc = -EINVAL; goto exit; } dprintk(VIDC_DBG, "[MAP] - mapped handle[%d] = %p fd[%d] = %d", i, binfo->handle[i], i, binfo->fd[i]); binfo->mapped[i] = true; binfo->device_addr[i] = binfo->handle[i]->device_addr + binfo->buff_off[i]; b->m.planes[i].m.userptr = binfo->device_addr[i]; } else { binfo->device_addr[i] = b->m.planes[i].m.userptr; } dprintk(VIDC_DBG, "Registering buffer: %d, %d, %d\n", b->m.planes[i].reserved[0], b->m.planes[i].reserved[1], b->m.planes[i].length); } /* We maintain one ref count for all planes*/ if ((i == 0) && is_dynamic_output_buffer_mode(b, inst)) { rc = buf_ref_get(inst, binfo); if (rc < 0) return rc; } binfo->num_planes = b->length; } dprintk(VIDC_DBG, "[MAP] Adding binfo = %p to list\n", binfo); mutex_lock(&inst->lock); list_add_tail(&binfo->list, &inst->registered_bufs); mutex_unlock(&inst->lock); return 0; exit: kfree(binfo); return rc; } int unmap_and_deregister_buf(struct msm_vidc_inst *inst, struct buffer_info *binfo) { int i = 0; struct buffer_info *temp = NULL; struct buffer_info *dummy = NULL; struct list_head *list; bool found = false, keep_node = false; if (!inst || !binfo) { dprintk(VIDC_ERR, "%s invalid param: %p %p\n", __func__, inst, binfo); return -EINVAL; } mutex_lock(&inst->lock); list = &inst->registered_bufs; /* * Make sure the buffer to be unmapped and deleted * from the registered list is present in the list. */ list_for_each_entry_safe(temp, dummy, list, list) { if (temp == binfo) { found = true; break; } } /* * Free the buffer info only if * - buffer info has not been deleted from registered list * - vidc client has called dqbuf on the buffer * - no references are held on the buffer */ if (!found || !temp || !temp->pending_deletion || !temp->dequeued) goto exit; for (i = 0; i < temp->num_planes; i++) { /* * Unmap the handle only if the buffer has been mapped and no * other buffer has a reference to this buffer. * In case of buffers with same fd, we will map the buffer only * once and subsequent buffers will refer to the mapped buffer's * device address. * For buffers which share the same fd, do not unmap and keep * the buffer info in registered list. */ if (temp->handle[i] && temp->mapped[i] && !temp->same_fd_ref[i]) { dprintk(VIDC_DBG, "[UNMAP] - handle[%d] = %p fd[%d] = %d", i, temp->handle[i], i, temp->fd[i]); msm_smem_free(inst->mem_client, temp->handle[i]); } if (temp->same_fd_ref[i]) keep_node = true; else { temp->fd[i] = 0; temp->handle[i] = 0; temp->device_addr[i] = 0; temp->uvaddr[i] = 0; } } if (!keep_node) { dprintk(VIDC_DBG, "[UNMAP] AND-FREED binfo: %p\n", temp); list_del(&temp->list); kfree(temp); } else { temp->inactive = true; dprintk(VIDC_DBG, "[UNMAP] NOT-FREED binfo: %p\n", temp); } exit: mutex_unlock(&inst->lock); return 0; } int qbuf_dynamic_buf(struct msm_vidc_inst *inst, struct buffer_info *binfo) { struct v4l2_buffer b = {0}; struct v4l2_plane plane[VIDEO_MAX_PLANES] = { {0} }; if (!binfo) { dprintk(VIDC_ERR, "%s invalid param: %p\n", __func__, binfo); return -EINVAL; } dprintk(VIDC_DBG, "%s fd[0] = %d\n", __func__, binfo->fd[0]); b.m.planes = plane; repopulate_v4l2_buffer(&b, binfo); if (inst->session_type == MSM_VIDC_DECODER) return msm_vdec_qbuf(inst, &b); if (inst->session_type == MSM_VIDC_ENCODER) return msm_venc_qbuf(inst, &b); return -EINVAL; } int output_buffer_cache_invalidate(struct msm_vidc_inst *inst, struct buffer_info *binfo) { int i = 0; int rc = 0; if (!inst) { dprintk(VIDC_ERR, "%s: invalid inst: %p\n", __func__, inst); return -EINVAL; } if (!inst->map_output_buffer) return 0; if (!binfo) { dprintk(VIDC_ERR, "%s: invalid buffer info: %p\n", __func__, inst); return -EINVAL; } if (binfo->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) return 0; for (i = 0; i < binfo->num_planes; i++) { if (binfo->handle[i]) { rc = msm_smem_cache_operations(inst->mem_client, binfo->handle[i], SMEM_CACHE_INVALIDATE); if (rc) { dprintk(VIDC_ERR, "%s: Failed to clean caches: %d\n", __func__, rc); return -EINVAL; } } } return 0; } int msm_vidc_prepare_buf(void *instance, struct v4l2_buffer *b) { Loading @@ -437,8 +672,18 @@ int msm_vidc_prepare_buf(void *instance, struct v4l2_buffer *b) if (!inst || !b) return -EINVAL; if (is_dynamic_output_buffer_mode(b, inst)) { dprintk(VIDC_ERR, "%s: not supported in dynamic buffer mode\n", __func__); return -EINVAL; } /* Map the buffer only for non-kernel clients*/ if (b->m.planes[0].reserved[0]) { inst->map_output_buffer = true; if (map_and_register_buf(inst, b)) return -EINVAL; } if (inst->session_type == MSM_VIDC_DECODER) return msm_vdec_prepare_buf(instance, b); Loading Loading @@ -533,8 +778,20 @@ int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b) b->length); return -EINVAL; } if (is_dynamic_output_buffer_mode(b, inst)) { if (b->m.planes[0].reserved[0]) inst->map_output_buffer = true; rc = map_and_register_buf(inst, b); if (rc == -EEXIST) return 0; if (rc) return rc; } for (i = 0; i < b->length; ++i) { if (!b->m.planes[i].reserved[0]) if (!inst->map_output_buffer) continue; if (EXTRADATA_IDX(b->length) && (i == EXTRADATA_IDX(b->length)) && Loading @@ -542,10 +799,8 @@ int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b) b->m.planes[i].m.userptr = 0; continue; } binfo = get_registered_buf(&inst->registered_bufs, b->m.planes[i].reserved[0], b->m.planes[i].reserved[1], b->m.planes[i].length, &plane); binfo = get_registered_buf(inst, b, i, &plane); if (!binfo) { dprintk(VIDC_ERR, "This buffer is not registered: %d, %d, %d\n", Loading Loading @@ -594,9 +849,8 @@ err_invalid_buff: int msm_vidc_dqbuf(void *instance, struct v4l2_buffer *b) { struct msm_vidc_inst *inst = instance; struct buffer_info *buffer_info; struct buffer_info *buffer_info = NULL; int i = 0, rc = 0; bool skip_invalidate = false; if (!inst || !b) return -EINVAL; Loading @@ -606,48 +860,54 @@ int msm_vidc_dqbuf(void *instance, struct v4l2_buffer *b) b->length); return -EINVAL; } if (!b->m.planes[0].reserved[0]) skip_invalidate = true; if (inst->session_type == MSM_VIDC_DECODER) rc = msm_vdec_dqbuf(instance, b); if (inst->session_type == MSM_VIDC_ENCODER) rc = msm_venc_dqbuf(instance, b); if (rc) goto fail_dq_buf; return rc; for (i = 0; i < b->length; i++) { if ((EXTRADATA_IDX(b->length) && if (!inst->map_output_buffer) continue; if (EXTRADATA_IDX(b->length) && (i == EXTRADATA_IDX(b->length)) && !b->m.planes[i].m.userptr) || skip_invalidate) { !b->m.planes[i].m.userptr) { continue; } buffer_info = device_to_uvaddr( buffer_info = device_to_uvaddr(inst, &inst->registered_bufs, b->m.planes[i].m.userptr); b->m.planes[i].m.userptr = buffer_info->uvaddr[i]; if (!b->m.planes[i].m.userptr) { if (!buffer_info) { dprintk(VIDC_ERR, "Failed to find user virtual address, 0x%lx, %d, %d\n", b->m.planes[i].m.userptr, b->type, i); goto fail_dq_buf; "%s no buffer info registered for buffer addr: 0x%lx\n", __func__, b->m.planes[i].m.userptr); return -EINVAL; } if (buffer_info->handle[i] && (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) { rc = msm_smem_cache_operations(inst->mem_client, buffer_info->handle[i], SMEM_CACHE_INVALIDATE); if (rc) { b->m.planes[i].m.userptr = buffer_info->uvaddr[i]; if (!b->m.planes[i].m.userptr) { dprintk(VIDC_ERR, "Failed to clean caches: %d\n", rc); goto fail_dq_buf; } "%s: Failed to find user virtual address, 0x%lx, %d, %d\n", __func__, b->m.planes[i].m.userptr, b->type, i); return -EINVAL; } } if (is_dynamic_output_buffer_mode(b, inst)) { mutex_lock(&inst->lock); buffer_info->dequeued = true; mutex_unlock(&inst->lock); dprintk(VIDC_DBG, "[DEQUEUED]: fd[0] = %d\n", buffer_info->fd[0]); rc = unmap_and_deregister_buf(inst, buffer_info); } else rc = output_buffer_cache_invalidate(inst, buffer_info); return rc; fail_dq_buf: dprintk(VIDC_DBG, "Failed to dqbuf, capability: %d\n", b->type); return -EINVAL; } int msm_vidc_streamon(void *instance, enum v4l2_buf_type i) Loading Loading @@ -836,6 +1096,7 @@ void *msm_vidc_open(int core_id, int session_type) init_waitqueue_head(&inst->kernel_event_queue); inst->state = MSM_VIDC_CORE_UNINIT_DONE; inst->core = core; inst->map_output_buffer = false; for (i = SESSION_MSG_INDEX(SESSION_MSG_START); i <= SESSION_MSG_INDEX(SESSION_MSG_END); i++) { Loading
drivers/media/platform/msm/vidc/msm_vidc_common.c +105 −0 Original line number Diff line number Diff line Loading @@ -819,6 +819,107 @@ static void handle_ebd(enum command_response cmd, void *data) } } int buf_ref_get(struct msm_vidc_inst *inst, struct buffer_info *binfo) { int cnt = 0; if (!inst || !binfo) return -EINVAL; mutex_lock(&inst->lock); atomic_inc(&binfo->ref_count); cnt = atomic_read(&binfo->ref_count); if (cnt > 2) { dprintk(VIDC_ERR, "%s: invalid ref_cnt: %d\n", __func__, cnt); cnt = -EINVAL; } dprintk(VIDC_DBG, "REF_GET[%d] fd[0] = %d\n", cnt, binfo->fd[0]); mutex_unlock(&inst->lock); return cnt; } int buf_ref_put(struct msm_vidc_inst *inst, struct buffer_info *binfo) { int rc = 0; int cnt; bool release_buf = false; bool qbuf_again = false; if (!inst || !binfo) return -EINVAL; mutex_lock(&inst->lock); atomic_dec(&binfo->ref_count); cnt = atomic_read(&binfo->ref_count); dprintk(VIDC_DBG, "REF_PUT[%d] fd[0] = %d\n", cnt, binfo->fd[0]); if (cnt == 0) release_buf = true; else if (cnt == 1) qbuf_again = true; else { dprintk(VIDC_ERR, "%s: invalid ref_cnt: %d\n", __func__, cnt); cnt = -EINVAL; } mutex_unlock(&inst->lock); if (cnt < 0) return cnt; rc = output_buffer_cache_invalidate(inst, binfo); if (rc) return rc; if (release_buf) { /* * We can not delete binfo here as we need to set the user * virtual address saved in binfo->uvaddr to the dequeued v4l2 * buffer. * * We will set the pending_deletion flag to true here and delete * binfo from registered list in dqbuf after setting the uvaddr. */ dprintk(VIDC_DBG, "fd[0] = %d -> pending_deletion = true\n", binfo->fd[0]); binfo->pending_deletion = true; } else if (qbuf_again) { rc = qbuf_dynamic_buf(inst, binfo); if (!rc) return rc; } return cnt; } static void handle_dynamic_buffer(struct msm_vidc_inst *inst, u32 device_addr, u32 flags) { struct buffer_info *binfo = NULL; /* * Update reference count and release OR queue back the buffer, * only when firmware is not holding a reference. */ if (inst->buffer_mode_set[CAPTURE_PORT] == HAL_BUFFER_MODE_DYNAMIC) { binfo = device_to_uvaddr(inst, &inst->registered_bufs, device_addr); if (!binfo) { dprintk(VIDC_ERR, "%s buffer not found in registered list\n", __func__); return; } if (flags & HAL_BUFFERFLAG_READONLY) { dprintk(VIDC_DBG, "_F_B_D_ fd[0] = %d -> Reference with f/w", binfo->fd[0]); } else { dprintk(VIDC_DBG, "_F_B_D_ fd[0] = %d -> FBD_ref_released\n", binfo->fd[0]); buf_ref_put(inst, binfo); } } } static void handle_fbd(enum command_response cmd, void *data) { struct msm_vidc_cb_data_done *response = data; Loading Loading @@ -862,6 +963,10 @@ static void handle_fbd(enum command_response cmd, void *data) } vb->v4l2_buf.flags = 0; handle_dynamic_buffer(inst, (u32)fill_buf_done->packet_buffer1, fill_buf_done->flags1); if (fill_buf_done->flags1 & HAL_BUFFERFLAG_READONLY) vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_READONLY; if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOS) vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_EOS; if (fill_buf_done->flags1 & HAL_BUFFERFLAG_CODECCONFIG) Loading
drivers/media/platform/msm/vidc/msm_vidc_internal.h +17 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ #ifndef _MSM_VIDC_INTERNAL_H_ #define _MSM_VIDC_INTERNAL_H_ #include <linux/atomic.h> #include <linux/list.h> #include <linux/types.h> #include <linux/completion.h> Loading Loading @@ -231,6 +232,7 @@ struct msm_vidc_inst { struct msm_vidc_core_capability capability; enum buffer_mode_type buffer_mode_set[MAX_PORT_NUM]; struct list_head registered_bufs; bool map_output_buffer; }; extern struct msm_vidc_drv *vidc_driver; Loading Loading @@ -271,6 +273,21 @@ struct buffer_info { u32 uvaddr[VIDEO_MAX_PLANES]; u32 device_addr[VIDEO_MAX_PLANES]; struct msm_smem *handle[VIDEO_MAX_PLANES]; enum v4l2_memory memory; u32 v4l2_index; bool pending_deletion; atomic_t ref_count; bool dequeued; bool inactive; bool mapped[VIDEO_MAX_PLANES]; int same_fd_ref[VIDEO_MAX_PLANES]; }; struct buffer_info *device_to_uvaddr(struct msm_vidc_inst *inst, struct list_head *list, u32 device_addr); int buf_ref_get(struct msm_vidc_inst *inst, struct buffer_info *binfo); int output_buffer_cache_invalidate(struct msm_vidc_inst *inst, struct buffer_info *binfo); int qbuf_dynamic_buf(struct msm_vidc_inst *inst, struct buffer_info *binfo); #endif
include/uapi/linux/videodev2.h +1 −0 Original line number Diff line number Diff line Loading @@ -712,6 +712,7 @@ struct v4l2_buffer { #define V4L2_QCOM_BUF_FLAG_EOS 0x1000000 #define V4L2_QCOM_BUF_TS_DISCONTINUITY 0x2000000 #define V4L2_QCOM_BUF_TS_ERROR 0x4000000 #define V4L2_QCOM_BUF_FLAG_READONLY 0x8000000 /** * struct v4l2_exportbuffer - export of video buffer as DMABUF file descriptor Loading