| /* Copyright (c) 2011-2012, Code Aurora Forum. 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 |
| * only version 2 as published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| */ |
| |
| #include <linux/workqueue.h> |
| #include <linux/delay.h> |
| #include <linux/types.h> |
| #include <linux/list.h> |
| #include <linux/ioctl.h> |
| #include <linux/spinlock.h> |
| #include <linux/videodev2.h> |
| #include <linux/proc_fs.h> |
| #include <linux/vmalloc.h> |
| |
| #include <media/v4l2-dev.h> |
| #include <media/v4l2-ioctl.h> |
| #include <media/v4l2-device.h> |
| |
| #include <linux/android_pmem.h> |
| |
| #include "msm.h" |
| #include "msm_vpe.h" |
| |
| #ifdef CONFIG_MSM_CAMERA_DEBUG |
| #define D(fmt, args...) pr_debug("msm_mctl: " fmt, ##args) |
| #else |
| #define D(fmt, args...) do {} while (0) |
| #endif |
| |
| static int msm_mctl_pp_buf_divert( |
| struct msm_cam_media_controller *pmctl, |
| struct msm_cam_v4l2_dev_inst *pcam_inst, |
| struct msm_cam_evt_divert_frame *div) |
| { |
| struct v4l2_event v4l2_evt; |
| struct msm_isp_event_ctrl *isp_event; |
| isp_event = kzalloc(sizeof(struct msm_isp_event_ctrl), |
| GFP_ATOMIC); |
| if (!isp_event) { |
| pr_err("%s Insufficient memory. return", __func__); |
| return -ENOMEM; |
| } |
| D("%s: msm_cam_evt_divert_frame=%d", |
| __func__, sizeof(struct msm_cam_evt_divert_frame)); |
| memset(&v4l2_evt, 0, sizeof(v4l2_evt)); |
| v4l2_evt.id = 0; |
| v4l2_evt.type = V4L2_EVENT_PRIVATE_START + |
| MSM_CAM_RESP_DIV_FRAME_EVT_MSG; |
| *((uint32_t *)v4l2_evt.u.data) = (uint32_t)isp_event; |
| /* Copy the divert frame struct into event ctrl struct. */ |
| isp_event->isp_data.div_frame = *div; |
| |
| D("%s inst=%p, img_mode=%d, frame_id=%d\n", __func__, |
| pcam_inst, pcam_inst->image_mode, div->frame.frame_id); |
| v4l2_event_queue( |
| pmctl->config_device->config_stat_event_queue.pvdev, |
| &v4l2_evt); |
| return 0; |
| } |
| |
| int msm_mctl_check_pp(struct msm_cam_media_controller *p_mctl, |
| int image_mode, int *pp_divert_type, int *pp_type) |
| { |
| int rc = 0; |
| unsigned long flags; |
| uint32_t pp_key = 0; |
| |
| *pp_type = 0; |
| *pp_divert_type = 0; |
| spin_lock_irqsave(&p_mctl->pp_info.lock, flags); |
| switch (image_mode) { |
| case MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW: |
| pp_key = PP_PREV; |
| if (p_mctl->pp_info.pp_key & pp_key) |
| *pp_divert_type = OUTPUT_TYPE_P; |
| if (p_mctl->pp_info.pp_ctrl.pp_msg_type & OUTPUT_TYPE_P) |
| *pp_type = OUTPUT_TYPE_P; |
| break; |
| case MSM_V4L2_EXT_CAPTURE_MODE_MAIN: |
| pp_key = PP_SNAP; |
| if (p_mctl->pp_info.pp_key & pp_key) |
| *pp_divert_type = OUTPUT_TYPE_S; |
| if (p_mctl->pp_info.pp_ctrl.pp_msg_type & OUTPUT_TYPE_S) |
| *pp_type = OUTPUT_TYPE_P; |
| break; |
| case MSM_V4L2_EXT_CAPTURE_MODE_VIDEO: |
| if (p_mctl->pp_info.pp_ctrl.pp_msg_type == OUTPUT_TYPE_V) |
| *pp_type = OUTPUT_TYPE_V; |
| break; |
| case MSM_V4L2_EXT_CAPTURE_MODE_THUMBNAIL: |
| pp_key = PP_THUMB; |
| if (p_mctl->pp_info.pp_key & pp_key) |
| *pp_divert_type = OUTPUT_TYPE_T; |
| if (p_mctl->pp_info.pp_ctrl.pp_msg_type == OUTPUT_TYPE_T) |
| *pp_type = OUTPUT_TYPE_T; |
| break; |
| case MSM_V4L2_EXT_CAPTURE_MODE_RDI: |
| if (p_mctl->pp_info.pp_ctrl.pp_msg_type & OUTPUT_TYPE_R) |
| *pp_type = OUTPUT_TYPE_R; |
| break; |
| default: |
| break; |
| } |
| if (p_mctl->vfe_output_mode != VFE_OUTPUTS_MAIN_AND_THUMB && |
| p_mctl->vfe_output_mode != VFE_OUTPUTS_THUMB_AND_MAIN) { |
| if (p_mctl->pp_info.div_frame[image_mode].ch_paddr[0]) |
| *pp_divert_type = 0; |
| } |
| spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags); |
| D("%s: pp_type=%d, pp_divert_type = %d", |
| __func__, *pp_type, *pp_divert_type); |
| return rc; |
| } |
| |
| static int is_buf_in_queue(struct msm_cam_v4l2_device *pcam, |
| struct msm_free_buf *fbuf, int image_mode) |
| { |
| struct msm_frame_buffer *buf = NULL, *tmp; |
| struct msm_cam_v4l2_dev_inst *pcam_inst = NULL; |
| unsigned long flags = 0; |
| struct videobuf2_contig_pmem *mem; |
| uint32_t buf_idx, offset = 0; |
| uint32_t buf_phyaddr = 0; |
| int idx; |
| idx = pcam->mctl_node.dev_inst_map[image_mode]->my_index; |
| pcam_inst = pcam->mctl_node.dev_inst[idx]; |
| spin_lock_irqsave(&pcam_inst->vq_irqlock, flags); |
| list_for_each_entry_safe(buf, tmp, |
| &pcam_inst->free_vq, list) { |
| buf_idx = buf->vidbuf.v4l2_buf.index; |
| mem = vb2_plane_cookie(&buf->vidbuf, 0); |
| if (mem->buffer_type == VIDEOBUF2_MULTIPLE_PLANES) |
| offset = mem->offset.data_offset + |
| pcam_inst->buf_offset[buf_idx][0].data_offset; |
| else |
| offset = mem->offset.sp_off.y_off; |
| buf_phyaddr = (unsigned long) |
| videobuf2_to_pmem_contig(&buf->vidbuf, 0) + |
| offset; |
| D("%s vb_idx=%d,vb_paddr=0x%x ch0=0x%x\n", |
| __func__, buf->vidbuf.v4l2_buf.index, |
| buf_phyaddr, fbuf->ch_paddr[0]); |
| if (fbuf->ch_paddr[0] == buf_phyaddr) { |
| spin_unlock_irqrestore(&pcam_inst->vq_irqlock, flags); |
| return 1; |
| } |
| } |
| spin_unlock_irqrestore(&pcam_inst->vq_irqlock, flags); |
| return 0; |
| } |
| |
| static struct msm_cam_v4l2_dev_inst *msm_mctl_get_pcam_inst_for_divert( |
| struct msm_cam_media_controller *pmctl, |
| struct msm_cam_buf_handle *buf_handle, |
| struct msm_free_buf *fbuf, int *node_type) |
| { |
| struct msm_cam_v4l2_dev_inst *pcam_inst = NULL; |
| struct msm_cam_v4l2_device *pcam = pmctl->pcam_ptr; |
| int idx; |
| uint32_t img_mode; |
| |
| if (buf_handle->buf_lookup_type == BUF_LOOKUP_BY_INST_HANDLE) { |
| idx = GET_MCTLPP_INST_IDX(buf_handle->inst_handle); |
| if (idx > MSM_DEV_INST_MAX) { |
| idx = GET_VIDEO_INST_IDX(buf_handle->inst_handle); |
| BUG_ON(idx > MSM_DEV_INST_MAX); |
| pcam_inst = pcam->dev_inst[idx]; |
| *node_type = VIDEO_NODE; |
| } else { |
| pcam_inst = pcam->mctl_node.dev_inst[idx]; |
| *node_type = MCTL_NODE; |
| } |
| } else if (buf_handle->buf_lookup_type == BUF_LOOKUP_BY_IMG_MODE) { |
| img_mode = buf_handle->image_mode; |
| if (img_mode >= 0 && img_mode < MSM_V4L2_EXT_CAPTURE_MODE_MAX) { |
| /* Valid image mode. Search the mctl node first. |
| * If mctl node doesnt have the instance, then |
| * search in the user's video node */ |
| if (pcam->mctl_node.dev_inst_map[img_mode] |
| && is_buf_in_queue(pcam, fbuf, img_mode)) { |
| idx = pcam->mctl_node. |
| dev_inst_map[img_mode]->my_index; |
| pcam_inst = pcam->mctl_node.dev_inst[idx]; |
| *node_type = MCTL_NODE; |
| D("%s Found instance %p in mctl node device\n", |
| __func__, pcam_inst); |
| } else if (pcam->dev_inst_map[img_mode]) { |
| idx = pcam->dev_inst_map[img_mode]->my_index; |
| pcam_inst = pcam->dev_inst[idx]; |
| *node_type = VIDEO_NODE; |
| D("%s Found instance %p in video device", |
| __func__, pcam_inst); |
| } else { |
| pr_err("%s Cannot find instance for %d.\n", |
| __func__, img_mode); |
| } |
| } else { |
| pr_err("%s Invalid image mode %d. Return NULL\n", |
| __func__, buf_handle->image_mode); |
| } |
| } else { |
| pr_err("%s Invalid buffer lookup type ", __func__); |
| } |
| return pcam_inst; |
| } |
| |
| int msm_mctl_do_pp_divert( |
| struct msm_cam_media_controller *p_mctl, |
| struct msm_cam_buf_handle *buf_handle, |
| struct msm_free_buf *fbuf, |
| uint32_t frame_id, int pp_type) |
| { |
| struct msm_cam_v4l2_dev_inst *pcam_inst; |
| int rc = 0, i, buf_idx, node; |
| int del_buf = 0; /* delete from free queue */ |
| struct msm_cam_evt_divert_frame div; |
| struct msm_frame_buffer *vb = NULL; |
| struct videobuf2_contig_pmem *mem; |
| uint32_t image_mode; |
| |
| if (buf_handle->buf_lookup_type == BUF_LOOKUP_BY_IMG_MODE) { |
| image_mode = buf_handle->image_mode; |
| div.frame.inst_handle = 0; |
| } else if (buf_handle->buf_lookup_type == BUF_LOOKUP_BY_INST_HANDLE) { |
| image_mode = GET_IMG_MODE(buf_handle->inst_handle); |
| div.frame.inst_handle = buf_handle->inst_handle; |
| } else { |
| pr_err("%s Invalid buffer lookup type %d ", __func__, |
| buf_handle->buf_lookup_type); |
| return -EINVAL; |
| } |
| |
| pcam_inst = msm_mctl_get_pcam_inst_for_divert(p_mctl, |
| buf_handle, fbuf, &node); |
| if (!pcam_inst) { |
| pr_err("%s Invalid instance. Cannot divert frame.\n", |
| __func__); |
| return -EINVAL; |
| } |
| vb = msm_mctl_buf_find(p_mctl, pcam_inst, del_buf, fbuf); |
| if (!vb) |
| return -EINVAL; |
| |
| vb->vidbuf.v4l2_buf.sequence = frame_id; |
| buf_idx = vb->vidbuf.v4l2_buf.index; |
| D("%s Diverting frame %d %x Image mode %d\n", __func__, buf_idx, |
| (uint32_t)vb, pcam_inst->image_mode); |
| div.image_mode = pcam_inst->image_mode; |
| div.op_mode = pcam_inst->pcam->op_mode; |
| div.inst_idx = pcam_inst->my_index; |
| div.node_idx = pcam_inst->pcam->vnode_id; |
| p_mctl->pp_info.cur_frame_id[pcam_inst->image_mode] = frame_id; |
| div.frame.frame_id = |
| p_mctl->pp_info.cur_frame_id[pcam_inst->image_mode]; |
| div.frame.buf_idx = buf_idx; |
| div.frame.handle = (uint32_t)vb; |
| msm_mctl_gettimeofday(&div.frame.timestamp); |
| vb->vidbuf.v4l2_buf.timestamp = div.frame.timestamp; |
| div.do_pp = pp_type; |
| D("%s Diverting frame %x id %d to userspace ", __func__, |
| (int)div.frame.handle, div.frame.frame_id); |
| /* Get the cookie for 1st plane and store the path. |
| * Also use this to check the number of planes in |
| * this buffer.*/ |
| mem = vb2_plane_cookie(&vb->vidbuf, 0); |
| div.frame.path = mem->path; |
| div.frame.node_type = node; |
| if (mem->buffer_type == VIDEOBUF2_SINGLE_PLANE) { |
| /* This buffer contains only 1 plane. Use the |
| * single planar structure to store the info.*/ |
| div.frame.num_planes = 1; |
| div.frame.sp.phy_addr = |
| videobuf2_to_pmem_contig(&vb->vidbuf, 0); |
| div.frame.sp.addr_offset = mem->addr_offset; |
| div.frame.sp.y_off = 0; |
| div.frame.sp.cbcr_off = mem->offset.sp_off.cbcr_off; |
| div.frame.sp.fd = (int)mem->vaddr; |
| div.frame.sp.length = mem->size; |
| if (!pp_type) |
| p_mctl->pp_info.div_frame[pcam_inst->image_mode]. |
| ch_paddr[0] = div.frame.sp.phy_addr; |
| } else { |
| /* This buffer contains multiple planes. Use the mutliplanar |
| * structure to store the info. */ |
| div.frame.num_planes = pcam_inst->plane_info.num_planes; |
| /* Now traverse through all the planes of the buffer to |
| * fill out the plane info. */ |
| for (i = 0; i < div.frame.num_planes; i++) { |
| mem = vb2_plane_cookie(&vb->vidbuf, i); |
| div.frame.mp[i].phy_addr = |
| videobuf2_to_pmem_contig(&vb->vidbuf, i); |
| if (!pcam_inst->buf_offset) |
| div.frame.mp[i].data_offset = 0; |
| else |
| div.frame.mp[i].data_offset = |
| pcam_inst->buf_offset[buf_idx][i].data_offset; |
| div.frame.mp[i].addr_offset = |
| mem->addr_offset; |
| div.frame.mp[i].fd = (int)mem->vaddr; |
| div.frame.mp[i].length = mem->size; |
| } |
| if (!pp_type) |
| p_mctl->pp_info.div_frame[pcam_inst->image_mode]. |
| ch_paddr[0] = div.frame.mp[0].phy_addr + |
| div.frame.mp[0].data_offset; |
| } |
| rc = msm_mctl_pp_buf_divert(p_mctl, pcam_inst, &div); |
| return rc; |
| } |
| |
| static int msm_mctl_pp_get_phy_addr( |
| struct msm_cam_v4l2_dev_inst *pcam_inst, |
| uint32_t frame_handle, |
| struct msm_pp_frame *pp_frame) |
| { |
| struct msm_frame_buffer *vb = NULL; |
| struct videobuf2_contig_pmem *mem; |
| int i, buf_idx = 0; |
| |
| vb = (struct msm_frame_buffer *)frame_handle; |
| buf_idx = vb->vidbuf.v4l2_buf.index; |
| memset(pp_frame, 0, sizeof(struct msm_pp_frame)); |
| pp_frame->handle = (uint32_t)vb; |
| pp_frame->frame_id = vb->vidbuf.v4l2_buf.sequence; |
| pp_frame->timestamp = vb->vidbuf.v4l2_buf.timestamp; |
| pp_frame->buf_idx = buf_idx; |
| pp_frame->inst_handle = pcam_inst->inst_handle; |
| /* Get the cookie for 1st plane and store the path. |
| * Also use this to check the number of planes in |
| * this buffer.*/ |
| mem = vb2_plane_cookie(&vb->vidbuf, 0); |
| pp_frame->image_type = (unsigned short)mem->path; |
| if (mem->buffer_type == VIDEOBUF2_SINGLE_PLANE) { |
| pp_frame->num_planes = 1; |
| pp_frame->sp.addr_offset = mem->addr_offset; |
| pp_frame->sp.phy_addr = |
| videobuf2_to_pmem_contig(&vb->vidbuf, 0); |
| pp_frame->sp.y_off = 0; |
| pp_frame->sp.cbcr_off = mem->offset.sp_off.cbcr_off; |
| pp_frame->sp.length = mem->size; |
| pp_frame->sp.fd = (int)mem->vaddr; |
| } else { |
| pp_frame->num_planes = pcam_inst->plane_info.num_planes; |
| for (i = 0; i < pp_frame->num_planes; i++) { |
| mem = vb2_plane_cookie(&vb->vidbuf, i); |
| pp_frame->mp[i].addr_offset = mem->addr_offset; |
| pp_frame->mp[i].phy_addr = |
| videobuf2_to_pmem_contig(&vb->vidbuf, i); |
| pp_frame->mp[i].data_offset = |
| pcam_inst->buf_offset[buf_idx][i].data_offset; |
| pp_frame->mp[i].fd = (int)mem->vaddr; |
| pp_frame->mp[i].length = mem->size; |
| D("%s frame id %d buffer %d plane %d phy addr 0x%x" |
| " fd %d length %d\n", __func__, |
| pp_frame->frame_id, buf_idx, i, |
| (uint32_t)pp_frame->mp[i].phy_addr, |
| pp_frame->mp[i].fd, pp_frame->mp[i].length); |
| } |
| } |
| return 0; |
| } |
| |
| static int msm_mctl_pp_path_to_img_mode(int path) |
| { |
| switch (path) { |
| case OUTPUT_TYPE_P: |
| return MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW; |
| case OUTPUT_TYPE_V: |
| return MSM_V4L2_EXT_CAPTURE_MODE_VIDEO; |
| case OUTPUT_TYPE_S: |
| return MSM_V4L2_EXT_CAPTURE_MODE_MAIN; |
| case OUTPUT_TYPE_T: |
| return MSM_V4L2_EXT_CAPTURE_MODE_THUMBNAIL; |
| case OUTPUT_TYPE_SAEC: |
| return MSM_V4L2_EXT_CAPTURE_MODE_AEC; |
| case OUTPUT_TYPE_SAWB: |
| return MSM_V4L2_EXT_CAPTURE_MODE_AWB; |
| case OUTPUT_TYPE_SAFC: |
| return MSM_V4L2_EXT_CAPTURE_MODE_AF; |
| case OUTPUT_TYPE_IHST: |
| return MSM_V4L2_EXT_CAPTURE_MODE_IHIST; |
| case OUTPUT_TYPE_CSTA: |
| return MSM_V4L2_EXT_CAPTURE_MODE_CSTA; |
| default: |
| return -EINVAL; |
| } |
| } |
| |
| int msm_mctl_pp_proc_cmd(struct msm_cam_media_controller *p_mctl, |
| struct msm_mctl_pp_cmd *pp_cmd) |
| { |
| int rc = 0; |
| unsigned long flags; |
| |
| switch (pp_cmd->id) { |
| case MCTL_CMD_DIVERT_FRAME_PP_PATH: { |
| struct msm_mctl_pp_divert_pp divert_pp; |
| if (copy_from_user(&divert_pp, pp_cmd->value, |
| sizeof(divert_pp))) { |
| ERR_COPY_FROM_USER(); |
| return -EFAULT; |
| } |
| D("%s: Divert Image mode =%d Enable %d", |
| __func__, divert_pp.path, divert_pp.enable); |
| spin_lock_irqsave(&p_mctl->pp_info.lock, flags); |
| if (divert_pp.enable) |
| p_mctl->pp_info.pp_ctrl.pp_msg_type |= divert_pp.path; |
| else |
| p_mctl->pp_info.pp_ctrl.pp_msg_type &= ~divert_pp.path; |
| spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags); |
| D("%s: pp path = 0x%x", __func__, |
| p_mctl->pp_info.pp_ctrl.pp_msg_type); |
| break; |
| } |
| default: |
| rc = -EPERM; |
| break; |
| } |
| return rc; |
| } |
| |
| |
| int msm_mctl_pp_ioctl(struct msm_cam_media_controller *p_mctl, |
| unsigned int cmd, unsigned long arg) |
| { |
| int rc = -EINVAL; |
| struct msm_mctl_post_proc_cmd pp_cmd; |
| void __user *argp = (void __user *)arg; |
| |
| if (copy_from_user(&pp_cmd, argp, sizeof(pp_cmd))) |
| return -EFAULT; |
| |
| switch (pp_cmd.type) { |
| case MSM_PP_CMD_TYPE_MCTL: |
| rc = msm_mctl_pp_proc_cmd(p_mctl, &pp_cmd.cmd); |
| break; |
| default: |
| rc = -EPERM; |
| break; |
| } |
| if (!rc) { |
| /* deep copy back the return value */ |
| if (copy_to_user((void *)arg, |
| &pp_cmd, |
| sizeof(struct msm_mctl_post_proc_cmd))) { |
| ERR_COPY_TO_USER(); |
| rc = -EFAULT; |
| } |
| } |
| return rc; |
| } |
| |
| int msm_mctl_pp_reserve_free_frame( |
| struct msm_cam_media_controller *p_mctl, |
| void __user *arg) |
| { |
| struct msm_cam_evt_divert_frame div_frame; |
| int image_mode, rc = 0; |
| struct msm_free_buf free_buf; |
| struct msm_cam_v4l2_dev_inst *pcam_inst; |
| struct msm_cam_buf_handle buf_handle; |
| |
| memset(&free_buf, 0, sizeof(struct msm_free_buf)); |
| if (copy_from_user(&div_frame, arg, |
| sizeof(struct msm_cam_evt_divert_frame))) { |
| ERR_COPY_FROM_USER(); |
| return -EFAULT; |
| } |
| |
| image_mode = div_frame.image_mode; |
| if (image_mode <= 0) { |
| pr_err("%s Invalid image mode %d", __func__, image_mode); |
| return -EINVAL; |
| } |
| /* Always reserve the buffer from user's video node */ |
| pcam_inst = p_mctl->pcam_ptr->dev_inst_map[image_mode]; |
| if (!pcam_inst) { |
| pr_err("%s Instance already closed ", __func__); |
| return -EINVAL; |
| } |
| D("%s Reserving free frame using %p inst handle %x ", __func__, |
| pcam_inst, div_frame.frame.inst_handle); |
| if (div_frame.frame.inst_handle) { |
| buf_handle.buf_lookup_type = BUF_LOOKUP_BY_INST_HANDLE; |
| buf_handle.inst_handle = div_frame.frame.inst_handle; |
| } else { |
| buf_handle.buf_lookup_type = BUF_LOOKUP_BY_IMG_MODE; |
| buf_handle.image_mode = image_mode; |
| } |
| rc = msm_mctl_reserve_free_buf(p_mctl, pcam_inst, |
| &buf_handle, &free_buf); |
| if (rc == 0) { |
| msm_mctl_pp_get_phy_addr(pcam_inst, |
| free_buf.vb, &div_frame.frame); |
| if (copy_to_user((void *)arg, &div_frame, sizeof(div_frame))) { |
| ERR_COPY_TO_USER(); |
| rc = -EFAULT; |
| } |
| } |
| D("%s: Got buffer %d from Inst %p rc = %d, phy = 0x%x", |
| __func__, div_frame.frame.buf_idx, |
| pcam_inst, rc, free_buf.ch_paddr[0]); |
| return rc; |
| } |
| |
| int msm_mctl_pp_release_free_frame( |
| struct msm_cam_media_controller *p_mctl, |
| void __user *arg) |
| { |
| struct msm_cam_evt_divert_frame div_frame; |
| struct msm_cam_v4l2_dev_inst *pcam_inst; |
| struct msm_pp_frame *frame; |
| int image_mode, rc = 0; |
| struct msm_free_buf free_buf; |
| struct msm_cam_buf_handle buf_handle; |
| |
| if (copy_from_user(&div_frame, arg, |
| sizeof(struct msm_cam_evt_divert_frame))) { |
| ERR_COPY_FROM_USER(); |
| return -EFAULT; |
| } |
| |
| image_mode = div_frame.image_mode; |
| if (image_mode < 0) { |
| pr_err("%s Invalid image mode %d\n", __func__, image_mode); |
| return -EINVAL; |
| } |
| frame = &div_frame.frame; |
| if (frame->num_planes > 1) |
| free_buf.ch_paddr[0] = frame->mp[0].phy_addr; |
| else |
| free_buf.ch_paddr[0] = frame->sp.phy_addr; |
| |
| if (div_frame.frame.inst_handle) { |
| buf_handle.buf_lookup_type = BUF_LOOKUP_BY_INST_HANDLE; |
| buf_handle.inst_handle = div_frame.frame.inst_handle; |
| } else { |
| buf_handle.buf_lookup_type = BUF_LOOKUP_BY_IMG_MODE; |
| buf_handle.image_mode = image_mode; |
| } |
| pcam_inst = msm_mctl_get_pcam_inst(p_mctl, &buf_handle); |
| if (!pcam_inst) { |
| pr_err("%s Invalid instance. Cannot release frame.\n", |
| __func__); |
| return -EINVAL; |
| } |
| |
| rc = msm_mctl_release_free_buf(p_mctl, pcam_inst, &free_buf); |
| D("%s: release free buf, rc = %d, phy = 0x%x", |
| __func__, rc, free_buf.ch_paddr[0]); |
| |
| return rc; |
| } |
| |
| int msm_mctl_set_pp_key(struct msm_cam_media_controller *p_mctl, |
| void __user *arg) |
| { |
| int rc = 0; |
| unsigned long flags; |
| spin_lock_irqsave(&p_mctl->pp_info.lock, flags); |
| if (copy_from_user(&p_mctl->pp_info.pp_key, |
| arg, sizeof(p_mctl->pp_info.pp_key))) { |
| ERR_COPY_FROM_USER(); |
| rc = -EFAULT; |
| } else { |
| D("%s: mctl=0x%p, pp_key_setting=0x%x", |
| __func__, p_mctl, p_mctl->pp_info.pp_key); |
| } |
| spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags); |
| return rc; |
| } |
| |
| int msm_mctl_pp_done( |
| struct msm_cam_media_controller *p_mctl, |
| void __user *arg) |
| { |
| struct msm_pp_frame frame; |
| int image_mode, rc = 0; |
| int dirty = 0; |
| struct msm_free_buf buf; |
| unsigned long flags; |
| struct msm_cam_buf_handle buf_handle; |
| struct msm_cam_return_frame_info ret_frame; |
| |
| if (copy_from_user(&frame, arg, sizeof(frame))) { |
| ERR_COPY_FROM_USER(); |
| return -EFAULT; |
| } |
| |
| spin_lock_irqsave(&p_mctl->pp_info.lock, flags); |
| if (frame.inst_handle) { |
| buf_handle.buf_lookup_type = BUF_LOOKUP_BY_INST_HANDLE; |
| buf_handle.inst_handle = frame.inst_handle; |
| image_mode = GET_IMG_MODE(frame.inst_handle); |
| } else { |
| buf_handle.buf_lookup_type = BUF_LOOKUP_BY_IMG_MODE; |
| buf_handle.image_mode = |
| msm_mctl_pp_path_to_img_mode(frame.path); |
| image_mode = buf_handle.image_mode; |
| } |
| if (image_mode < 0) { |
| pr_err("%s Invalid image mode\n", __func__); |
| return image_mode; |
| } |
| D("%s Returning frame %x id %d to kernel ", __func__, |
| (int)frame.handle, frame.frame_id); |
| if (p_mctl->pp_info.div_frame[image_mode].ch_paddr[0]) { |
| memcpy(&buf, |
| &p_mctl->pp_info.div_frame[image_mode], |
| sizeof(buf)); |
| memset(&p_mctl->pp_info.div_frame[image_mode], |
| 0, sizeof(buf)); |
| if (p_mctl->pp_info.cur_frame_id[image_mode] != |
| frame.frame_id) { |
| /* dirty frame. should not pass to app */ |
| dirty = 1; |
| } |
| } else { |
| if (frame.num_planes > 1) |
| buf.ch_paddr[0] = frame.mp[0].phy_addr + |
| frame.mp[0].data_offset; |
| else |
| buf.ch_paddr[0] = frame.sp.phy_addr + frame.sp.y_off; |
| } |
| spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags); |
| |
| ret_frame.dirty = dirty; |
| ret_frame.node_type = 0; |
| ret_frame.timestamp = frame.timestamp; |
| ret_frame.frame_id = frame.frame_id; |
| D("%s frame_id: %d buffer idx %d\n", __func__, |
| frame.frame_id, frame.buf_idx); |
| rc = msm_mctl_buf_done_pp(p_mctl, &buf_handle, &buf, &ret_frame); |
| return rc; |
| } |
| |
| int msm_mctl_pp_divert_done( |
| struct msm_cam_media_controller *p_mctl, |
| void __user *arg) |
| { |
| struct msm_pp_frame frame; |
| int rc = 0; |
| struct msm_free_buf buf; |
| unsigned long flags; |
| struct msm_cam_buf_handle buf_handle; |
| struct msm_cam_return_frame_info ret_frame; |
| |
| D("%s enter\n", __func__); |
| |
| if (copy_from_user(&frame, arg, sizeof(frame))) { |
| ERR_COPY_FROM_USER(); |
| return -EFAULT; |
| } |
| |
| spin_lock_irqsave(&p_mctl->pp_info.lock, flags); |
| if (frame.inst_handle) { |
| buf_handle.buf_lookup_type = BUF_LOOKUP_BY_INST_HANDLE; |
| buf_handle.inst_handle = frame.inst_handle; |
| } else { |
| buf_handle.buf_lookup_type = BUF_LOOKUP_BY_IMG_MODE; |
| buf_handle.image_mode = frame.image_type; |
| } |
| |
| if (frame.num_planes > 1) |
| buf.ch_paddr[0] = frame.mp[0].phy_addr + |
| frame.mp[0].data_offset; |
| else |
| buf.ch_paddr[0] = frame.sp.phy_addr + frame.sp.y_off; |
| |
| spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags); |
| |
| ret_frame.dirty = 0; |
| ret_frame.node_type = frame.node_type; |
| ret_frame.timestamp = frame.timestamp; |
| D("%s Frame done id: %d\n", __func__, frame.frame_id); |
| rc = msm_mctl_buf_done_pp(p_mctl, &buf_handle, &buf, &ret_frame); |
| return rc; |
| } |
| |
| int msm_mctl_pp_mctl_divert_done( |
| struct msm_cam_media_controller *p_mctl, |
| void __user *arg) |
| { |
| struct msm_cam_evt_divert_frame div_frame; |
| struct msm_frame_buffer *buf; |
| int image_mode, rc = 0; |
| |
| if (copy_from_user(&div_frame, arg, |
| sizeof(struct msm_cam_evt_divert_frame))) { |
| pr_err("%s copy from user failed ", __func__); |
| return -EFAULT; |
| } |
| |
| if (!div_frame.frame.handle) { |
| pr_err("%s Invalid buffer handle ", __func__); |
| return -EINVAL; |
| } |
| image_mode = div_frame.image_mode; |
| buf = (struct msm_frame_buffer *)div_frame.frame.handle; |
| D("%s Returning buffer %x Image mode %d ", __func__, |
| (int)buf, image_mode); |
| rc = msm_mctl_buf_return_buf(p_mctl, image_mode, buf); |
| if (rc < 0) |
| pr_err("%s Error returning mctl buffer ", __func__); |
| |
| return rc; |
| } |