Loading drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c +317 −38 Original line number Diff line number Diff line /* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. /* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading @@ -9,6 +9,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #define pr_fmt(fmt) "CAM-BUFMGR %s:%d " fmt, __func__, __LINE__ #include "msm_generic_buf_mgr.h" static struct msm_buf_mngr_device *msm_buf_mngr_dev; Loading @@ -18,10 +20,12 @@ struct v4l2_subdev *msm_buf_mngr_get_subdev(void) return &msm_buf_mngr_dev->subdev.sd; } static int32_t msm_buf_mngr_get_buf(struct msm_buf_mngr_device *buf_mngr_dev, static int32_t msm_buf_mngr_get_buf(struct msm_buf_mngr_device *dev, void __user *argp) { unsigned long flags; struct msm_buf_mngr_user_buf_cont_info *cbuf, *cont_save; unsigned int i; struct msm_buf_mngr_info *buf_info = (struct msm_buf_mngr_info *)argp; struct msm_get_bufs *new_entry = Loading @@ -32,7 +36,7 @@ static int32_t msm_buf_mngr_get_buf(struct msm_buf_mngr_device *buf_mngr_dev, return -ENOMEM; } INIT_LIST_HEAD(&new_entry->entry); new_entry->vb2_buf = buf_mngr_dev->vb2_ops.get_buf(buf_info->session_id, new_entry->vb2_buf = dev->vb2_ops.get_buf(buf_info->session_id, buf_info->stream_id); if (!new_entry->vb2_buf) { pr_debug("%s:Get buf is null\n", __func__); Loading @@ -41,10 +45,48 @@ static int32_t msm_buf_mngr_get_buf(struct msm_buf_mngr_device *buf_mngr_dev, } new_entry->session_id = buf_info->session_id; new_entry->stream_id = buf_info->stream_id; spin_lock_irqsave(&buf_mngr_dev->buf_q_spinlock, flags); list_add_tail(&new_entry->entry, &buf_mngr_dev->buf_qhead); spin_unlock_irqrestore(&buf_mngr_dev->buf_q_spinlock, flags); spin_lock_irqsave(&dev->buf_q_spinlock, flags); list_add_tail(&new_entry->entry, &dev->buf_qhead); spin_unlock_irqrestore(&dev->buf_q_spinlock, flags); buf_info->index = new_entry->vb2_buf->v4l2_buf.index; if (buf_info->type == MSM_CAMERA_BUF_MNGR_BUF_USER) { mutex_lock(&dev->cont_mutex); if (!list_empty(&dev->cont_qhead)) { list_for_each_entry_safe(cbuf, cont_save, &dev->cont_qhead, entry) { if ((cbuf->sessid == buf_info->session_id) && (cbuf->index == buf_info->index) && (cbuf->strid == buf_info->stream_id)) { buf_info->user_buf.buf_cnt = cbuf->paddr->buf_cnt; if (buf_info->user_buf.buf_cnt > MSM_CAMERA_MAX_USER_BUFF_CNT) { pr_err("Invalid cnt%d,%d,%d\n", cbuf->paddr->buf_cnt, buf_info->session_id, buf_info->stream_id); mutex_unlock(&dev->cont_mutex); return -EINVAL; } for (i = 0 ; i < buf_info->user_buf.buf_cnt; i++) { buf_info->user_buf.buf_idx[i] = cbuf->paddr->buf_idx[i]; } break; } } } else { pr_err("Nothing mapped in user buf for %d,%d\n", buf_info->session_id, buf_info->stream_id); mutex_unlock(&dev->cont_mutex); return -EINVAL; } mutex_unlock(&dev->cont_mutex); } return 0; } Loading Loading @@ -100,19 +142,36 @@ static int32_t msm_buf_mngr_put_buf(struct msm_buf_mngr_device *buf_mngr_dev, return ret; } static void msm_buf_mngr_sd_shutdown(struct msm_buf_mngr_device *buf_mngr_dev, static int32_t msm_buf_mngr_find_cont_stream(struct msm_buf_mngr_device *dev, uint32_t *cnt, uint32_t *tstream, struct msm_sd_close_ioctl *session) { struct msm_buf_mngr_user_buf_cont_info *cont_bufs, *cont_save; int32_t ret = -1; list_for_each_entry_safe(cont_bufs, cont_save, &dev->cont_qhead, entry) { if (cont_bufs->sessid == session->session) { *cnt = cont_bufs->cnt; *tstream = cont_bufs->strid; return 0; } } return ret; } static void msm_buf_mngr_sd_shutdown(struct msm_buf_mngr_device *dev, struct msm_sd_close_ioctl *session) { unsigned long flags; struct msm_get_bufs *bufs, *save; BUG_ON(!buf_mngr_dev); BUG_ON(!dev); BUG_ON(!session); spin_lock_irqsave(&buf_mngr_dev->buf_q_spinlock, flags); if (!list_empty(&buf_mngr_dev->buf_qhead)) { spin_lock_irqsave(&dev->buf_q_spinlock, flags); if (!list_empty(&dev->buf_qhead)) { list_for_each_entry_safe(bufs, save, &buf_mngr_dev->buf_qhead, entry) { save, &dev->buf_qhead, entry) { pr_info("%s: Delete invalid bufs =%lx, session_id=%u, bufs->ses_id=%d, str_id=%d, idx=%d\n", __func__, (unsigned long)bufs, session->session, bufs->session_id, bufs->stream_id, Loading @@ -123,7 +182,187 @@ static void msm_buf_mngr_sd_shutdown(struct msm_buf_mngr_device *buf_mngr_dev, } } } spin_unlock_irqrestore(&buf_mngr_dev->buf_q_spinlock, flags); spin_unlock_irqrestore(&dev->buf_q_spinlock, flags); mutex_lock(&dev->cont_mutex); if (!list_empty(&dev->cont_qhead)) { uint32_t cnt = 0, tstream = -1; int32_t found = -1; struct msm_buf_mngr_user_buf_cont_info *cont_bufs, *cont_save; do { found = msm_buf_mngr_find_cont_stream(dev, &cnt, &tstream, session); if (found == -1) break; list_for_each_entry_safe(cont_bufs, cont_save, &dev->cont_qhead, entry) { if ((cont_bufs->sessid == session->session) && (cont_bufs->strid == tstream)) { if (cnt == 1) { ion_unmap_kernel( dev->ion_client, cont_bufs->ion_handle); ion_free(dev->ion_client, cont_bufs->ion_handle); } list_del_init(&cont_bufs->entry); kfree(cont_bufs); cnt--; } } if (cnt != 0) pr_err("Buffers pending cnt = %d\n", cnt); } while (found == 0); } mutex_unlock(&dev->cont_mutex); } static int msm_buf_mngr_handle_cont_cmd(struct msm_buf_mngr_device *dev, struct msm_buf_mngr_main_cont_info *cont_cmd) { int rc = 0, i = 0; struct ion_handle *ion_handle = NULL; struct msm_camera_user_buf_cont_t *iaddr, *temp_addr; struct msm_buf_mngr_user_buf_cont_info *new_entry, *bufs, *save; unsigned long size; if ((cont_cmd->cmd >= MSM_CAMERA_BUF_MNGR_CONT_MAX) || (cont_cmd->cmd < 0) || (cont_cmd->cnt > VIDEO_MAX_FRAME) || (cont_cmd->cont_fd < 0)) { pr_debug("Invalid arg passed Cmd:%d, cnt:%d, fd:%d\n", cont_cmd->cmd, cont_cmd->cnt, cont_cmd->cont_fd); return -EINVAL; } mutex_lock(&dev->cont_mutex); if (cont_cmd->cmd == MSM_CAMERA_BUF_MNGR_CONT_MAP) { if (!list_empty(&dev->cont_qhead)) { list_for_each_entry_safe(bufs, save, &dev->cont_qhead, entry) { if ((bufs->sessid == cont_cmd->session_id) && (bufs->strid == cont_cmd->stream_id)) { pr_err("Map exist %d,%d unmap first\n", cont_cmd->session_id, cont_cmd->stream_id); rc = -EINVAL; goto end; } } } ion_handle = ion_import_dma_buf(dev->ion_client, cont_cmd->cont_fd); if (IS_ERR_OR_NULL(ion_handle)) { pr_err("Failed to create ion handle for fd %d\n", cont_cmd->cont_fd); rc = -EINVAL; goto end; } if (ion_handle_get_size(dev->ion_client, ion_handle, &size) < 0) { pr_err("Get ion size failed\n"); rc = -EINVAL; goto free_ion_handle; } if ((size == 0) || (size < (sizeof(struct msm_camera_user_buf_cont_t) * cont_cmd->cnt))) { pr_err("Invalid or zero size ION buffer %lu\n", size); rc = -EINVAL; goto free_ion_handle; } iaddr = ion_map_kernel(dev->ion_client, ion_handle); if (IS_ERR_OR_NULL(iaddr)) { pr_err("Mapping cont buff failed\n"); rc = -EINVAL; goto free_ion_handle; } for (i = 0; i < cont_cmd->cnt; i++) { temp_addr = iaddr + i; if (temp_addr->buf_cnt > MSM_CAMERA_MAX_USER_BUFF_CNT) { pr_err("%s:Invalid buf_cnt:%d for cont:%d\n", __func__, temp_addr->buf_cnt, i); rc = -EINVAL; goto free_list; } new_entry = kzalloc(sizeof( struct msm_buf_mngr_user_buf_cont_info), GFP_KERNEL); if (!new_entry) { pr_err("%s:No mem\n", __func__); rc = -ENOMEM; goto free_list; } INIT_LIST_HEAD(&new_entry->entry); new_entry->sessid = cont_cmd->session_id; new_entry->strid = cont_cmd->stream_id; new_entry->index = i; new_entry->main_fd = cont_cmd->cont_fd; new_entry->ion_handle = ion_handle; new_entry->cnt = cont_cmd->cnt; new_entry->paddr = temp_addr; list_add_tail(&new_entry->entry, &dev->cont_qhead); } goto end; } else if (cont_cmd->cmd == MSM_CAMERA_BUF_MNGR_CONT_UNMAP) { int cnt = cont_cmd->cnt; if (!list_empty(&dev->cont_qhead)) { list_for_each_entry_safe(bufs, save, &dev->cont_qhead, entry) { if ((bufs->sessid == cont_cmd->session_id) && (bufs->main_fd == cont_cmd->cont_fd) && (bufs->cnt == cont_cmd->cnt) && (bufs->strid == cont_cmd->stream_id)) { if (cnt == 1) { ion_unmap_kernel( dev->ion_client, bufs->ion_handle); ion_free(dev->ion_client, bufs->ion_handle); } list_del_init(&bufs->entry); kfree(bufs); cnt--; } } } else { pr_err("Nothing mapped for %d,%d\n", cont_cmd->session_id, cont_cmd->stream_id); rc = -EINVAL; } goto end; } free_list: if (i != 0) { if (!list_empty(&dev->cont_qhead)) { list_for_each_entry_safe(bufs, save, &dev->cont_qhead, entry) { if ((bufs->sessid == cont_cmd->session_id) && (bufs->main_fd == cont_cmd->cont_fd) && (bufs->cnt == cont_cmd->cnt) && (bufs->strid == cont_cmd->stream_id)) { list_del_init(&bufs->entry); kfree(bufs); i--; if (i == 0) break; } } } } ion_unmap_kernel(dev->ion_client, ion_handle); free_ion_handle: ion_free(dev->ion_client, ion_handle); end: mutex_unlock(&dev->cont_mutex); return rc; } static int msm_generic_buf_mngr_open(struct v4l2_subdev *sd, Loading Loading @@ -184,6 +423,9 @@ static long msm_buf_mngr_subdev_ioctl(struct v4l2_subdev *sd, case MSM_SD_SHUTDOWN: msm_buf_mngr_sd_shutdown(buf_mngr_dev, argp); break; case VIDIOC_MSM_BUF_MNGR_CONT_CMD: rc = msm_buf_mngr_handle_cont_cmd(buf_mngr_dev, argp); break; default: return -ENOIOCTLCMD; } Loading @@ -200,21 +442,6 @@ static long msm_bmgr_subdev_fops_compat_ioctl(struct file *file, void __user *up = (void __user *)arg; struct msm_buf_mngr_info32_t buf_info32; struct msm_buf_mngr_info buf_info; if (copy_from_user(&buf_info32, (void __user *)up, sizeof(struct msm_buf_mngr_info32_t))) return -EFAULT; buf_info.session_id = buf_info32.session_id; buf_info.stream_id = buf_info32.stream_id; buf_info.frame_id = buf_info32.frame_id; buf_info.index = buf_info32.index; buf_info.timestamp.tv_sec = (long) buf_info32.timestamp.tv_sec; buf_info.timestamp.tv_usec = (long) buf_info32.timestamp.tv_usec; buf_info.reserved = buf_info32.reserved; /* Convert 32 bit IOCTL ID's to 64 bit IOCTL ID's * except VIDIOC_MSM_CPP_CFG32, which needs special * processing Loading @@ -229,6 +456,9 @@ static long msm_bmgr_subdev_fops_compat_ioctl(struct file *file, case VIDIOC_MSM_BUF_MNGR_PUT_BUF32: cmd = VIDIOC_MSM_BUF_MNGR_PUT_BUF; break; case VIDIOC_MSM_BUF_MNGR_CONT_CMD: cmd = VIDIOC_MSM_BUF_MNGR_CONT_CMD; break; default: pr_debug("%s : unsupported compat type", __func__); return -ENOIOCTLCMD; Loading @@ -237,29 +467,67 @@ static long msm_bmgr_subdev_fops_compat_ioctl(struct file *file, switch (cmd) { case VIDIOC_MSM_BUF_MNGR_GET_BUF: case VIDIOC_MSM_BUF_MNGR_BUF_DONE: case VIDIOC_MSM_BUF_MNGR_PUT_BUF: case VIDIOC_MSM_BUF_MNGR_PUT_BUF: { struct msm_buf_mngr_info32_t buf_info32; struct msm_buf_mngr_info buf_info; if (copy_from_user(&buf_info32, (void __user *)up, sizeof(struct msm_buf_mngr_info32_t))) return -EFAULT; buf_info.session_id = buf_info32.session_id; buf_info.stream_id = buf_info32.stream_id; buf_info.frame_id = buf_info32.frame_id; buf_info.index = buf_info32.index; buf_info.timestamp.tv_sec = (long) buf_info32.timestamp.tv_sec; buf_info.timestamp.tv_usec = (long) buf_info32. timestamp.tv_usec; buf_info.reserved = buf_info32.reserved; buf_info.type = buf_info32.type; rc = v4l2_subdev_call(sd, core, ioctl, cmd, &buf_info); if (rc < 0) { pr_debug("%s : Subdev cmd %d fail", __func__, cmd); return rc; } break; default: pr_debug("%s : unsupported compat type", __func__); return -ENOIOCTLCMD; break; } buf_info32.session_id = buf_info.session_id; buf_info32.stream_id = buf_info.stream_id; buf_info32.index = buf_info.index; buf_info32.timestamp.tv_sec = (int32_t) buf_info.timestamp.tv_sec; buf_info32.timestamp.tv_usec = (int32_t) buf_info.timestamp.tv_usec; buf_info32.timestamp.tv_sec = (int32_t) buf_info. timestamp.tv_sec; buf_info32.timestamp.tv_usec = (int32_t) buf_info.timestamp. tv_usec; buf_info32.reserved = buf_info.reserved; buf_info32.type = buf_info.type; buf_info32.user_buf.buf_cnt = buf_info.user_buf.buf_cnt; memcpy(&buf_info32.user_buf.buf_idx, &buf_info.user_buf.buf_idx, sizeof(buf_info.user_buf.buf_idx)); if (copy_to_user((void __user *)up, &buf_info32, sizeof(struct msm_buf_mngr_info32_t))) return -EFAULT; } break; case VIDIOC_MSM_BUF_MNGR_CONT_CMD: { struct msm_buf_mngr_main_cont_info cont_cmd; if (copy_from_user(&cont_cmd, (void __user *)up, sizeof(struct msm_buf_mngr_main_cont_info))) return -EFAULT; rc = v4l2_subdev_call(sd, core, ioctl, cmd, &cont_cmd); if (rc < 0) { pr_debug("%s : Subdev cmd %d fail", __func__, cmd); return rc; } } break; default: pr_debug("%s : unsupported compat type", __func__); return -ENOIOCTLCMD; break; } return 0; } Loading Loading @@ -350,12 +618,24 @@ static int32_t __init msm_buf_mngr_init(void) INIT_LIST_HEAD(&msm_buf_mngr_dev->buf_qhead); spin_lock_init(&msm_buf_mngr_dev->buf_q_spinlock); mutex_init(&msm_buf_mngr_dev->cont_mutex); INIT_LIST_HEAD(&msm_buf_mngr_dev->cont_qhead); msm_buf_mngr_dev->ion_client = msm_ion_client_create("msm_cam_generic_buf_mgr"); if (!msm_buf_mngr_dev->ion_client) { pr_err("%s: Failed to create ion client\n", __func__); rc = -EBADFD; } end: return rc; } static void __exit msm_buf_mngr_exit(void) { msm_sd_unregister(&msm_buf_mngr_dev->subdev); mutex_destroy(&msm_buf_mngr_dev->cont_mutex); kfree(msm_buf_mngr_dev); } Loading @@ -363,4 +643,3 @@ module_init(msm_buf_mngr_init); module_exit(msm_buf_mngr_exit); MODULE_DESCRIPTION("MSM Buffer Manager"); MODULE_LICENSE("GPL v2"); drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.h +15 −1 Original line number Diff line number Diff line /* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. /* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -34,7 +34,21 @@ struct msm_get_bufs { struct msm_buf_mngr_device { struct list_head buf_qhead; spinlock_t buf_q_spinlock; struct ion_client *ion_client; struct msm_sd_subdev subdev; struct msm_sd_req_vb2_q vb2_ops; struct list_head cont_qhead; struct mutex cont_mutex; }; struct msm_buf_mngr_user_buf_cont_info { struct list_head entry; uint32_t sessid; uint32_t strid; uint32_t index; int32_t main_fd; struct msm_camera_user_buf_cont_t *paddr; uint32_t cnt; struct ion_handle *ion_handle; }; #endif include/media/msmb_camera.h +8 −0 Original line number Diff line number Diff line Loading @@ -66,6 +66,9 @@ * configured in future*/ #define MSM_CAMERA_MAX_STREAM_BUF 72 /* Max batch size of processing */ #define MSM_CAMERA_MAX_USER_BUFF_CNT 16 /* featur base */ #define MSM_CAMERA_FEATURE_BASE 0x00010000 #define MSM_CAMERA_FEATURE_SHUTDOWN (MSM_CAMERA_FEATURE_BASE + 1) Loading Loading @@ -197,4 +200,9 @@ struct msm_camera_smmu_attach_type { enum smmu_attach_mode attach; }; struct msm_camera_user_buf_cont_t { unsigned int buf_cnt; unsigned int buf_idx[MSM_CAMERA_MAX_USER_BUFF_CNT]; }; #endif /* __LINUX_MSMB_CAMERA_H */ include/uapi/media/msmb_generic_buf_mgr.h +33 −2 Original line number Diff line number Diff line #ifndef __UAPI_MEDIA_MSMB_BUF_MNGR_H__ #define __UAPI_MEDIA_MSMB_BUF_MNGR_H__ #include <media/msmb_camera.h> enum msm_camera_buf_mngr_cmd { MSM_CAMERA_BUF_MNGR_CONT_MAP, MSM_CAMERA_BUF_MNGR_CONT_UNMAP, MSM_CAMERA_BUF_MNGR_CONT_MAX, }; enum msm_camera_buf_mngr_buf_type { MSM_CAMERA_BUF_MNGR_BUF_PLANAR, MSM_CAMERA_BUF_MNGR_BUF_USER, MSM_CAMERA_BUF_MNGR_BUF_INVALID, }; struct msm_buf_mngr_info { uint32_t session_id; uint32_t stream_id; Loading @@ -8,6 +22,16 @@ struct msm_buf_mngr_info { struct timeval timestamp; uint32_t index; uint32_t reserved; enum msm_camera_buf_mngr_buf_type type; struct msm_camera_user_buf_cont_t user_buf; }; struct msm_buf_mngr_main_cont_info { uint32_t session_id; uint32_t stream_id; enum msm_camera_buf_mngr_cmd cmd; uint32_t cnt; int32_t cont_fd; }; struct v4l2_subdev *msm_buf_mngr_get_subdev(void); Loading @@ -21,11 +45,15 @@ struct v4l2_subdev *msm_buf_mngr_get_subdev(void); #define VIDIOC_MSM_BUF_MNGR_BUF_DONE \ _IOWR('V', BASE_VIDIOC_PRIVATE + 35, struct msm_buf_mngr_info) #define VIDIOC_MSM_BUF_MNGR_CONT_CMD \ _IOWR('V', BASE_VIDIOC_PRIVATE + 36, struct msm_buf_mngr_main_cont_info) #define VIDIOC_MSM_BUF_MNGR_INIT \ _IOWR('V', BASE_VIDIOC_PRIVATE + 36, struct msm_buf_mngr_info) _IOWR('V', BASE_VIDIOC_PRIVATE + 37, struct msm_buf_mngr_info) #define VIDIOC_MSM_BUF_MNGR_DEINIT \ _IOWR('V', BASE_VIDIOC_PRIVATE + 37, struct msm_buf_mngr_info) _IOWR('V', BASE_VIDIOC_PRIVATE + 38, struct msm_buf_mngr_info) #ifdef CONFIG_COMPAT struct msm_buf_mngr_info32_t { Loading @@ -35,6 +63,8 @@ struct msm_buf_mngr_info32_t { struct compat_timeval timestamp; uint32_t index; uint32_t reserved; enum msm_camera_buf_mngr_buf_type type; struct msm_camera_user_buf_cont_t user_buf; }; #define VIDIOC_MSM_BUF_MNGR_GET_BUF32 \ Loading @@ -45,6 +75,7 @@ struct msm_buf_mngr_info32_t { #define VIDIOC_MSM_BUF_MNGR_BUF_DONE32 \ _IOWR('V', BASE_VIDIOC_PRIVATE + 35, struct msm_buf_mngr_info32_t) #endif #endif Loading
drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c +317 −38 Original line number Diff line number Diff line /* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. /* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading @@ -9,6 +9,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #define pr_fmt(fmt) "CAM-BUFMGR %s:%d " fmt, __func__, __LINE__ #include "msm_generic_buf_mgr.h" static struct msm_buf_mngr_device *msm_buf_mngr_dev; Loading @@ -18,10 +20,12 @@ struct v4l2_subdev *msm_buf_mngr_get_subdev(void) return &msm_buf_mngr_dev->subdev.sd; } static int32_t msm_buf_mngr_get_buf(struct msm_buf_mngr_device *buf_mngr_dev, static int32_t msm_buf_mngr_get_buf(struct msm_buf_mngr_device *dev, void __user *argp) { unsigned long flags; struct msm_buf_mngr_user_buf_cont_info *cbuf, *cont_save; unsigned int i; struct msm_buf_mngr_info *buf_info = (struct msm_buf_mngr_info *)argp; struct msm_get_bufs *new_entry = Loading @@ -32,7 +36,7 @@ static int32_t msm_buf_mngr_get_buf(struct msm_buf_mngr_device *buf_mngr_dev, return -ENOMEM; } INIT_LIST_HEAD(&new_entry->entry); new_entry->vb2_buf = buf_mngr_dev->vb2_ops.get_buf(buf_info->session_id, new_entry->vb2_buf = dev->vb2_ops.get_buf(buf_info->session_id, buf_info->stream_id); if (!new_entry->vb2_buf) { pr_debug("%s:Get buf is null\n", __func__); Loading @@ -41,10 +45,48 @@ static int32_t msm_buf_mngr_get_buf(struct msm_buf_mngr_device *buf_mngr_dev, } new_entry->session_id = buf_info->session_id; new_entry->stream_id = buf_info->stream_id; spin_lock_irqsave(&buf_mngr_dev->buf_q_spinlock, flags); list_add_tail(&new_entry->entry, &buf_mngr_dev->buf_qhead); spin_unlock_irqrestore(&buf_mngr_dev->buf_q_spinlock, flags); spin_lock_irqsave(&dev->buf_q_spinlock, flags); list_add_tail(&new_entry->entry, &dev->buf_qhead); spin_unlock_irqrestore(&dev->buf_q_spinlock, flags); buf_info->index = new_entry->vb2_buf->v4l2_buf.index; if (buf_info->type == MSM_CAMERA_BUF_MNGR_BUF_USER) { mutex_lock(&dev->cont_mutex); if (!list_empty(&dev->cont_qhead)) { list_for_each_entry_safe(cbuf, cont_save, &dev->cont_qhead, entry) { if ((cbuf->sessid == buf_info->session_id) && (cbuf->index == buf_info->index) && (cbuf->strid == buf_info->stream_id)) { buf_info->user_buf.buf_cnt = cbuf->paddr->buf_cnt; if (buf_info->user_buf.buf_cnt > MSM_CAMERA_MAX_USER_BUFF_CNT) { pr_err("Invalid cnt%d,%d,%d\n", cbuf->paddr->buf_cnt, buf_info->session_id, buf_info->stream_id); mutex_unlock(&dev->cont_mutex); return -EINVAL; } for (i = 0 ; i < buf_info->user_buf.buf_cnt; i++) { buf_info->user_buf.buf_idx[i] = cbuf->paddr->buf_idx[i]; } break; } } } else { pr_err("Nothing mapped in user buf for %d,%d\n", buf_info->session_id, buf_info->stream_id); mutex_unlock(&dev->cont_mutex); return -EINVAL; } mutex_unlock(&dev->cont_mutex); } return 0; } Loading Loading @@ -100,19 +142,36 @@ static int32_t msm_buf_mngr_put_buf(struct msm_buf_mngr_device *buf_mngr_dev, return ret; } static void msm_buf_mngr_sd_shutdown(struct msm_buf_mngr_device *buf_mngr_dev, static int32_t msm_buf_mngr_find_cont_stream(struct msm_buf_mngr_device *dev, uint32_t *cnt, uint32_t *tstream, struct msm_sd_close_ioctl *session) { struct msm_buf_mngr_user_buf_cont_info *cont_bufs, *cont_save; int32_t ret = -1; list_for_each_entry_safe(cont_bufs, cont_save, &dev->cont_qhead, entry) { if (cont_bufs->sessid == session->session) { *cnt = cont_bufs->cnt; *tstream = cont_bufs->strid; return 0; } } return ret; } static void msm_buf_mngr_sd_shutdown(struct msm_buf_mngr_device *dev, struct msm_sd_close_ioctl *session) { unsigned long flags; struct msm_get_bufs *bufs, *save; BUG_ON(!buf_mngr_dev); BUG_ON(!dev); BUG_ON(!session); spin_lock_irqsave(&buf_mngr_dev->buf_q_spinlock, flags); if (!list_empty(&buf_mngr_dev->buf_qhead)) { spin_lock_irqsave(&dev->buf_q_spinlock, flags); if (!list_empty(&dev->buf_qhead)) { list_for_each_entry_safe(bufs, save, &buf_mngr_dev->buf_qhead, entry) { save, &dev->buf_qhead, entry) { pr_info("%s: Delete invalid bufs =%lx, session_id=%u, bufs->ses_id=%d, str_id=%d, idx=%d\n", __func__, (unsigned long)bufs, session->session, bufs->session_id, bufs->stream_id, Loading @@ -123,7 +182,187 @@ static void msm_buf_mngr_sd_shutdown(struct msm_buf_mngr_device *buf_mngr_dev, } } } spin_unlock_irqrestore(&buf_mngr_dev->buf_q_spinlock, flags); spin_unlock_irqrestore(&dev->buf_q_spinlock, flags); mutex_lock(&dev->cont_mutex); if (!list_empty(&dev->cont_qhead)) { uint32_t cnt = 0, tstream = -1; int32_t found = -1; struct msm_buf_mngr_user_buf_cont_info *cont_bufs, *cont_save; do { found = msm_buf_mngr_find_cont_stream(dev, &cnt, &tstream, session); if (found == -1) break; list_for_each_entry_safe(cont_bufs, cont_save, &dev->cont_qhead, entry) { if ((cont_bufs->sessid == session->session) && (cont_bufs->strid == tstream)) { if (cnt == 1) { ion_unmap_kernel( dev->ion_client, cont_bufs->ion_handle); ion_free(dev->ion_client, cont_bufs->ion_handle); } list_del_init(&cont_bufs->entry); kfree(cont_bufs); cnt--; } } if (cnt != 0) pr_err("Buffers pending cnt = %d\n", cnt); } while (found == 0); } mutex_unlock(&dev->cont_mutex); } static int msm_buf_mngr_handle_cont_cmd(struct msm_buf_mngr_device *dev, struct msm_buf_mngr_main_cont_info *cont_cmd) { int rc = 0, i = 0; struct ion_handle *ion_handle = NULL; struct msm_camera_user_buf_cont_t *iaddr, *temp_addr; struct msm_buf_mngr_user_buf_cont_info *new_entry, *bufs, *save; unsigned long size; if ((cont_cmd->cmd >= MSM_CAMERA_BUF_MNGR_CONT_MAX) || (cont_cmd->cmd < 0) || (cont_cmd->cnt > VIDEO_MAX_FRAME) || (cont_cmd->cont_fd < 0)) { pr_debug("Invalid arg passed Cmd:%d, cnt:%d, fd:%d\n", cont_cmd->cmd, cont_cmd->cnt, cont_cmd->cont_fd); return -EINVAL; } mutex_lock(&dev->cont_mutex); if (cont_cmd->cmd == MSM_CAMERA_BUF_MNGR_CONT_MAP) { if (!list_empty(&dev->cont_qhead)) { list_for_each_entry_safe(bufs, save, &dev->cont_qhead, entry) { if ((bufs->sessid == cont_cmd->session_id) && (bufs->strid == cont_cmd->stream_id)) { pr_err("Map exist %d,%d unmap first\n", cont_cmd->session_id, cont_cmd->stream_id); rc = -EINVAL; goto end; } } } ion_handle = ion_import_dma_buf(dev->ion_client, cont_cmd->cont_fd); if (IS_ERR_OR_NULL(ion_handle)) { pr_err("Failed to create ion handle for fd %d\n", cont_cmd->cont_fd); rc = -EINVAL; goto end; } if (ion_handle_get_size(dev->ion_client, ion_handle, &size) < 0) { pr_err("Get ion size failed\n"); rc = -EINVAL; goto free_ion_handle; } if ((size == 0) || (size < (sizeof(struct msm_camera_user_buf_cont_t) * cont_cmd->cnt))) { pr_err("Invalid or zero size ION buffer %lu\n", size); rc = -EINVAL; goto free_ion_handle; } iaddr = ion_map_kernel(dev->ion_client, ion_handle); if (IS_ERR_OR_NULL(iaddr)) { pr_err("Mapping cont buff failed\n"); rc = -EINVAL; goto free_ion_handle; } for (i = 0; i < cont_cmd->cnt; i++) { temp_addr = iaddr + i; if (temp_addr->buf_cnt > MSM_CAMERA_MAX_USER_BUFF_CNT) { pr_err("%s:Invalid buf_cnt:%d for cont:%d\n", __func__, temp_addr->buf_cnt, i); rc = -EINVAL; goto free_list; } new_entry = kzalloc(sizeof( struct msm_buf_mngr_user_buf_cont_info), GFP_KERNEL); if (!new_entry) { pr_err("%s:No mem\n", __func__); rc = -ENOMEM; goto free_list; } INIT_LIST_HEAD(&new_entry->entry); new_entry->sessid = cont_cmd->session_id; new_entry->strid = cont_cmd->stream_id; new_entry->index = i; new_entry->main_fd = cont_cmd->cont_fd; new_entry->ion_handle = ion_handle; new_entry->cnt = cont_cmd->cnt; new_entry->paddr = temp_addr; list_add_tail(&new_entry->entry, &dev->cont_qhead); } goto end; } else if (cont_cmd->cmd == MSM_CAMERA_BUF_MNGR_CONT_UNMAP) { int cnt = cont_cmd->cnt; if (!list_empty(&dev->cont_qhead)) { list_for_each_entry_safe(bufs, save, &dev->cont_qhead, entry) { if ((bufs->sessid == cont_cmd->session_id) && (bufs->main_fd == cont_cmd->cont_fd) && (bufs->cnt == cont_cmd->cnt) && (bufs->strid == cont_cmd->stream_id)) { if (cnt == 1) { ion_unmap_kernel( dev->ion_client, bufs->ion_handle); ion_free(dev->ion_client, bufs->ion_handle); } list_del_init(&bufs->entry); kfree(bufs); cnt--; } } } else { pr_err("Nothing mapped for %d,%d\n", cont_cmd->session_id, cont_cmd->stream_id); rc = -EINVAL; } goto end; } free_list: if (i != 0) { if (!list_empty(&dev->cont_qhead)) { list_for_each_entry_safe(bufs, save, &dev->cont_qhead, entry) { if ((bufs->sessid == cont_cmd->session_id) && (bufs->main_fd == cont_cmd->cont_fd) && (bufs->cnt == cont_cmd->cnt) && (bufs->strid == cont_cmd->stream_id)) { list_del_init(&bufs->entry); kfree(bufs); i--; if (i == 0) break; } } } } ion_unmap_kernel(dev->ion_client, ion_handle); free_ion_handle: ion_free(dev->ion_client, ion_handle); end: mutex_unlock(&dev->cont_mutex); return rc; } static int msm_generic_buf_mngr_open(struct v4l2_subdev *sd, Loading Loading @@ -184,6 +423,9 @@ static long msm_buf_mngr_subdev_ioctl(struct v4l2_subdev *sd, case MSM_SD_SHUTDOWN: msm_buf_mngr_sd_shutdown(buf_mngr_dev, argp); break; case VIDIOC_MSM_BUF_MNGR_CONT_CMD: rc = msm_buf_mngr_handle_cont_cmd(buf_mngr_dev, argp); break; default: return -ENOIOCTLCMD; } Loading @@ -200,21 +442,6 @@ static long msm_bmgr_subdev_fops_compat_ioctl(struct file *file, void __user *up = (void __user *)arg; struct msm_buf_mngr_info32_t buf_info32; struct msm_buf_mngr_info buf_info; if (copy_from_user(&buf_info32, (void __user *)up, sizeof(struct msm_buf_mngr_info32_t))) return -EFAULT; buf_info.session_id = buf_info32.session_id; buf_info.stream_id = buf_info32.stream_id; buf_info.frame_id = buf_info32.frame_id; buf_info.index = buf_info32.index; buf_info.timestamp.tv_sec = (long) buf_info32.timestamp.tv_sec; buf_info.timestamp.tv_usec = (long) buf_info32.timestamp.tv_usec; buf_info.reserved = buf_info32.reserved; /* Convert 32 bit IOCTL ID's to 64 bit IOCTL ID's * except VIDIOC_MSM_CPP_CFG32, which needs special * processing Loading @@ -229,6 +456,9 @@ static long msm_bmgr_subdev_fops_compat_ioctl(struct file *file, case VIDIOC_MSM_BUF_MNGR_PUT_BUF32: cmd = VIDIOC_MSM_BUF_MNGR_PUT_BUF; break; case VIDIOC_MSM_BUF_MNGR_CONT_CMD: cmd = VIDIOC_MSM_BUF_MNGR_CONT_CMD; break; default: pr_debug("%s : unsupported compat type", __func__); return -ENOIOCTLCMD; Loading @@ -237,29 +467,67 @@ static long msm_bmgr_subdev_fops_compat_ioctl(struct file *file, switch (cmd) { case VIDIOC_MSM_BUF_MNGR_GET_BUF: case VIDIOC_MSM_BUF_MNGR_BUF_DONE: case VIDIOC_MSM_BUF_MNGR_PUT_BUF: case VIDIOC_MSM_BUF_MNGR_PUT_BUF: { struct msm_buf_mngr_info32_t buf_info32; struct msm_buf_mngr_info buf_info; if (copy_from_user(&buf_info32, (void __user *)up, sizeof(struct msm_buf_mngr_info32_t))) return -EFAULT; buf_info.session_id = buf_info32.session_id; buf_info.stream_id = buf_info32.stream_id; buf_info.frame_id = buf_info32.frame_id; buf_info.index = buf_info32.index; buf_info.timestamp.tv_sec = (long) buf_info32.timestamp.tv_sec; buf_info.timestamp.tv_usec = (long) buf_info32. timestamp.tv_usec; buf_info.reserved = buf_info32.reserved; buf_info.type = buf_info32.type; rc = v4l2_subdev_call(sd, core, ioctl, cmd, &buf_info); if (rc < 0) { pr_debug("%s : Subdev cmd %d fail", __func__, cmd); return rc; } break; default: pr_debug("%s : unsupported compat type", __func__); return -ENOIOCTLCMD; break; } buf_info32.session_id = buf_info.session_id; buf_info32.stream_id = buf_info.stream_id; buf_info32.index = buf_info.index; buf_info32.timestamp.tv_sec = (int32_t) buf_info.timestamp.tv_sec; buf_info32.timestamp.tv_usec = (int32_t) buf_info.timestamp.tv_usec; buf_info32.timestamp.tv_sec = (int32_t) buf_info. timestamp.tv_sec; buf_info32.timestamp.tv_usec = (int32_t) buf_info.timestamp. tv_usec; buf_info32.reserved = buf_info.reserved; buf_info32.type = buf_info.type; buf_info32.user_buf.buf_cnt = buf_info.user_buf.buf_cnt; memcpy(&buf_info32.user_buf.buf_idx, &buf_info.user_buf.buf_idx, sizeof(buf_info.user_buf.buf_idx)); if (copy_to_user((void __user *)up, &buf_info32, sizeof(struct msm_buf_mngr_info32_t))) return -EFAULT; } break; case VIDIOC_MSM_BUF_MNGR_CONT_CMD: { struct msm_buf_mngr_main_cont_info cont_cmd; if (copy_from_user(&cont_cmd, (void __user *)up, sizeof(struct msm_buf_mngr_main_cont_info))) return -EFAULT; rc = v4l2_subdev_call(sd, core, ioctl, cmd, &cont_cmd); if (rc < 0) { pr_debug("%s : Subdev cmd %d fail", __func__, cmd); return rc; } } break; default: pr_debug("%s : unsupported compat type", __func__); return -ENOIOCTLCMD; break; } return 0; } Loading Loading @@ -350,12 +618,24 @@ static int32_t __init msm_buf_mngr_init(void) INIT_LIST_HEAD(&msm_buf_mngr_dev->buf_qhead); spin_lock_init(&msm_buf_mngr_dev->buf_q_spinlock); mutex_init(&msm_buf_mngr_dev->cont_mutex); INIT_LIST_HEAD(&msm_buf_mngr_dev->cont_qhead); msm_buf_mngr_dev->ion_client = msm_ion_client_create("msm_cam_generic_buf_mgr"); if (!msm_buf_mngr_dev->ion_client) { pr_err("%s: Failed to create ion client\n", __func__); rc = -EBADFD; } end: return rc; } static void __exit msm_buf_mngr_exit(void) { msm_sd_unregister(&msm_buf_mngr_dev->subdev); mutex_destroy(&msm_buf_mngr_dev->cont_mutex); kfree(msm_buf_mngr_dev); } Loading @@ -363,4 +643,3 @@ module_init(msm_buf_mngr_init); module_exit(msm_buf_mngr_exit); MODULE_DESCRIPTION("MSM Buffer Manager"); MODULE_LICENSE("GPL v2");
drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.h +15 −1 Original line number Diff line number Diff line /* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. /* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -34,7 +34,21 @@ struct msm_get_bufs { struct msm_buf_mngr_device { struct list_head buf_qhead; spinlock_t buf_q_spinlock; struct ion_client *ion_client; struct msm_sd_subdev subdev; struct msm_sd_req_vb2_q vb2_ops; struct list_head cont_qhead; struct mutex cont_mutex; }; struct msm_buf_mngr_user_buf_cont_info { struct list_head entry; uint32_t sessid; uint32_t strid; uint32_t index; int32_t main_fd; struct msm_camera_user_buf_cont_t *paddr; uint32_t cnt; struct ion_handle *ion_handle; }; #endif
include/media/msmb_camera.h +8 −0 Original line number Diff line number Diff line Loading @@ -66,6 +66,9 @@ * configured in future*/ #define MSM_CAMERA_MAX_STREAM_BUF 72 /* Max batch size of processing */ #define MSM_CAMERA_MAX_USER_BUFF_CNT 16 /* featur base */ #define MSM_CAMERA_FEATURE_BASE 0x00010000 #define MSM_CAMERA_FEATURE_SHUTDOWN (MSM_CAMERA_FEATURE_BASE + 1) Loading Loading @@ -197,4 +200,9 @@ struct msm_camera_smmu_attach_type { enum smmu_attach_mode attach; }; struct msm_camera_user_buf_cont_t { unsigned int buf_cnt; unsigned int buf_idx[MSM_CAMERA_MAX_USER_BUFF_CNT]; }; #endif /* __LINUX_MSMB_CAMERA_H */
include/uapi/media/msmb_generic_buf_mgr.h +33 −2 Original line number Diff line number Diff line #ifndef __UAPI_MEDIA_MSMB_BUF_MNGR_H__ #define __UAPI_MEDIA_MSMB_BUF_MNGR_H__ #include <media/msmb_camera.h> enum msm_camera_buf_mngr_cmd { MSM_CAMERA_BUF_MNGR_CONT_MAP, MSM_CAMERA_BUF_MNGR_CONT_UNMAP, MSM_CAMERA_BUF_MNGR_CONT_MAX, }; enum msm_camera_buf_mngr_buf_type { MSM_CAMERA_BUF_MNGR_BUF_PLANAR, MSM_CAMERA_BUF_MNGR_BUF_USER, MSM_CAMERA_BUF_MNGR_BUF_INVALID, }; struct msm_buf_mngr_info { uint32_t session_id; uint32_t stream_id; Loading @@ -8,6 +22,16 @@ struct msm_buf_mngr_info { struct timeval timestamp; uint32_t index; uint32_t reserved; enum msm_camera_buf_mngr_buf_type type; struct msm_camera_user_buf_cont_t user_buf; }; struct msm_buf_mngr_main_cont_info { uint32_t session_id; uint32_t stream_id; enum msm_camera_buf_mngr_cmd cmd; uint32_t cnt; int32_t cont_fd; }; struct v4l2_subdev *msm_buf_mngr_get_subdev(void); Loading @@ -21,11 +45,15 @@ struct v4l2_subdev *msm_buf_mngr_get_subdev(void); #define VIDIOC_MSM_BUF_MNGR_BUF_DONE \ _IOWR('V', BASE_VIDIOC_PRIVATE + 35, struct msm_buf_mngr_info) #define VIDIOC_MSM_BUF_MNGR_CONT_CMD \ _IOWR('V', BASE_VIDIOC_PRIVATE + 36, struct msm_buf_mngr_main_cont_info) #define VIDIOC_MSM_BUF_MNGR_INIT \ _IOWR('V', BASE_VIDIOC_PRIVATE + 36, struct msm_buf_mngr_info) _IOWR('V', BASE_VIDIOC_PRIVATE + 37, struct msm_buf_mngr_info) #define VIDIOC_MSM_BUF_MNGR_DEINIT \ _IOWR('V', BASE_VIDIOC_PRIVATE + 37, struct msm_buf_mngr_info) _IOWR('V', BASE_VIDIOC_PRIVATE + 38, struct msm_buf_mngr_info) #ifdef CONFIG_COMPAT struct msm_buf_mngr_info32_t { Loading @@ -35,6 +63,8 @@ struct msm_buf_mngr_info32_t { struct compat_timeval timestamp; uint32_t index; uint32_t reserved; enum msm_camera_buf_mngr_buf_type type; struct msm_camera_user_buf_cont_t user_buf; }; #define VIDIOC_MSM_BUF_MNGR_GET_BUF32 \ Loading @@ -45,6 +75,7 @@ struct msm_buf_mngr_info32_t { #define VIDIOC_MSM_BUF_MNGR_BUF_DONE32 \ _IOWR('V', BASE_VIDIOC_PRIVATE + 35, struct msm_buf_mngr_info32_t) #endif #endif