blob: 105426e3c3922f132ca6b516f45c60803c868262 [file] [log] [blame]
/* 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;
}