2692 lines
73 KiB
C
2692 lines
73 KiB
C
/* Copyright (c) 2010-2013, 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
|
|
* 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/cdev.h>
|
|
#include <linux/device.h>
|
|
#include <linux/firmware.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/init.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/io.h>
|
|
#include <linux/list.h>
|
|
#include <linux/module.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/uaccess.h>
|
|
#include <linux/wait.h>
|
|
#include <linux/workqueue.h>
|
|
|
|
#include <linux/clk.h>
|
|
#include <linux/timer.h>
|
|
#include <media/msm/vidc_type.h>
|
|
#include <media/msm/vcd_api.h>
|
|
#include <media/msm/vidc_init.h>
|
|
#include <mach/iommu_domains.h>
|
|
#include "vcd_res_tracker_api.h"
|
|
#include "vdec_internal.h"
|
|
|
|
|
|
|
|
#define DBG(x...) pr_debug(x)
|
|
#define INFO(x...) pr_info(x)
|
|
#define ERR(x...) pr_err(x)
|
|
|
|
#define VID_DEC_NAME "msm_vidc_dec"
|
|
|
|
static char *node_name[2] = {"", "_sec"};
|
|
static struct vid_dec_dev *vid_dec_device_p;
|
|
static dev_t vid_dec_dev_num;
|
|
static struct class *vid_dec_class;
|
|
|
|
static s32 vid_dec_get_empty_client_index(void)
|
|
{
|
|
u32 i, found = false;
|
|
|
|
for (i = 0; i < VIDC_MAX_NUM_CLIENTS; i++) {
|
|
if (!vid_dec_device_p->vdec_clients[i].vcd_handle) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!found) {
|
|
ERR("%s():ERROR No space for new client\n", __func__);
|
|
return -ENOMEM;
|
|
} else {
|
|
DBG("%s(): available client index = %u\n", __func__, i);
|
|
return i;
|
|
}
|
|
}
|
|
|
|
u32 vid_dec_get_status(u32 status)
|
|
{
|
|
u32 vdec_status;
|
|
|
|
switch (status) {
|
|
case VCD_ERR_SEQHDR_PARSE_FAIL:
|
|
case VCD_ERR_BITSTREAM_ERR:
|
|
vdec_status = VDEC_S_INPUT_BITSTREAM_ERR;
|
|
break;
|
|
case VCD_S_SUCCESS:
|
|
vdec_status = VDEC_S_SUCCESS;
|
|
break;
|
|
case VCD_ERR_FAIL:
|
|
vdec_status = VDEC_S_EFAIL;
|
|
break;
|
|
case VCD_ERR_ALLOC_FAIL:
|
|
vdec_status = VDEC_S_ENOSWRES;
|
|
break;
|
|
case VCD_ERR_ILLEGAL_OP:
|
|
vdec_status = VDEC_S_EINVALCMD;
|
|
break;
|
|
case VCD_ERR_ILLEGAL_PARM:
|
|
vdec_status = VDEC_S_EBADPARAM;
|
|
break;
|
|
case VCD_ERR_BAD_POINTER:
|
|
case VCD_ERR_BAD_HANDLE:
|
|
vdec_status = VDEC_S_EFATAL;
|
|
break;
|
|
case VCD_ERR_NOT_SUPPORTED:
|
|
vdec_status = VDEC_S_ENOTSUPP;
|
|
break;
|
|
case VCD_ERR_BAD_STATE:
|
|
vdec_status = VDEC_S_EINVALSTATE;
|
|
break;
|
|
case VCD_ERR_BUSY:
|
|
vdec_status = VDEC_S_BUSY;
|
|
break;
|
|
case VCD_ERR_MAX_CLIENT:
|
|
vdec_status = VDEC_S_ENOHWRES;
|
|
break;
|
|
default:
|
|
vdec_status = VDEC_S_EFAIL;
|
|
break;
|
|
}
|
|
|
|
return vdec_status;
|
|
}
|
|
|
|
static void vid_dec_notify_client(struct video_client_ctx *client_ctx)
|
|
{
|
|
if (client_ctx)
|
|
complete(&client_ctx->event);
|
|
}
|
|
|
|
void vid_dec_vcd_open_done(struct video_client_ctx *client_ctx,
|
|
struct vcd_handle_container *handle_container)
|
|
{
|
|
DBG("vid_dec_vcd_open_done\n");
|
|
|
|
if (client_ctx) {
|
|
if (handle_container)
|
|
client_ctx->vcd_handle = handle_container->handle;
|
|
else
|
|
ERR("%s(): ERROR. handle_container is NULL\n",
|
|
__func__);
|
|
|
|
vid_dec_notify_client(client_ctx);
|
|
} else
|
|
ERR("%s(): ERROR. client_ctx is NULL\n", __func__);
|
|
}
|
|
|
|
static void vid_dec_handle_field_drop(struct video_client_ctx *client_ctx,
|
|
u32 event, u32 status, int64_t time_stamp)
|
|
{
|
|
struct vid_dec_msg *vdec_msg;
|
|
|
|
if (!client_ctx) {
|
|
ERR("%s() NULL pointer\n", __func__);
|
|
return;
|
|
}
|
|
|
|
vdec_msg = kzalloc(sizeof(struct vid_dec_msg), GFP_KERNEL);
|
|
if (!vdec_msg) {
|
|
ERR("%s(): cannot allocate vid_dec_msg "
|
|
" buffer\n", __func__);
|
|
return;
|
|
}
|
|
vdec_msg->vdec_msg_info.status_code = vid_dec_get_status(status);
|
|
if (event == VCD_EVT_IND_INFO_FIELD_DROPPED) {
|
|
vdec_msg->vdec_msg_info.msgcode =
|
|
VDEC_MSG_EVT_INFO_FIELD_DROPPED;
|
|
vdec_msg->vdec_msg_info.msgdata.output_frame.time_stamp
|
|
= time_stamp;
|
|
DBG("Send FIELD_DROPPED message to client = %p\n", client_ctx);
|
|
} else {
|
|
ERR("vid_dec_input_frame_done(): invalid event type: "
|
|
"%d\n", event);
|
|
vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_INVALID;
|
|
}
|
|
vdec_msg->vdec_msg_info.msgdatasize =
|
|
sizeof(struct vdec_output_frameinfo);
|
|
mutex_lock(&client_ctx->msg_queue_lock);
|
|
list_add_tail(&vdec_msg->list, &client_ctx->msg_queue);
|
|
mutex_unlock(&client_ctx->msg_queue_lock);
|
|
wake_up(&client_ctx->msg_wait);
|
|
}
|
|
|
|
static void vid_dec_input_frame_done(struct video_client_ctx *client_ctx,
|
|
u32 event, u32 status,
|
|
struct vcd_frame_data *vcd_frame_data)
|
|
{
|
|
struct vid_dec_msg *vdec_msg;
|
|
|
|
if (!client_ctx || !vcd_frame_data) {
|
|
ERR("vid_dec_input_frame_done() NULL pointer\n");
|
|
return;
|
|
}
|
|
|
|
kfree(vcd_frame_data->desc_buf);
|
|
vcd_frame_data->desc_buf = NULL;
|
|
vcd_frame_data->desc_size = 0;
|
|
|
|
vdec_msg = kzalloc(sizeof(struct vid_dec_msg), GFP_KERNEL);
|
|
if (!vdec_msg) {
|
|
ERR("vid_dec_input_frame_done(): cannot allocate vid_dec_msg "
|
|
" buffer\n");
|
|
return;
|
|
}
|
|
|
|
vdec_msg->vdec_msg_info.status_code = vid_dec_get_status(status);
|
|
|
|
if (event == VCD_EVT_RESP_INPUT_DONE) {
|
|
vdec_msg->vdec_msg_info.msgcode =
|
|
VDEC_MSG_RESP_INPUT_BUFFER_DONE;
|
|
DBG("Send INPUT_DON message to client = %p\n", client_ctx);
|
|
|
|
} else if (event == VCD_EVT_RESP_INPUT_FLUSHED) {
|
|
vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_RESP_INPUT_FLUSHED;
|
|
DBG("Send INPUT_FLUSHED message to client = %p\n", client_ctx);
|
|
} else {
|
|
ERR("vid_dec_input_frame_done(): invalid event type: "
|
|
"%d\n", event);
|
|
vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_INVALID;
|
|
}
|
|
|
|
vdec_msg->vdec_msg_info.msgdata.input_frame_clientdata =
|
|
(void *)vcd_frame_data->frm_clnt_data;
|
|
vdec_msg->vdec_msg_info.msgdatasize = sizeof(void *);
|
|
|
|
mutex_lock(&client_ctx->msg_queue_lock);
|
|
list_add_tail(&vdec_msg->list, &client_ctx->msg_queue);
|
|
mutex_unlock(&client_ctx->msg_queue_lock);
|
|
wake_up(&client_ctx->msg_wait);
|
|
}
|
|
|
|
static void vid_dec_output_frame_done(struct video_client_ctx *client_ctx,
|
|
u32 event, u32 status,
|
|
struct vcd_frame_data *vcd_frame_data)
|
|
{
|
|
struct vid_dec_msg *vdec_msg;
|
|
|
|
unsigned long kernel_vaddr = 0, phy_addr = 0, user_vaddr = 0;
|
|
int pmem_fd;
|
|
struct file *file;
|
|
s32 buffer_index = -1;
|
|
enum vdec_picture pic_type;
|
|
u32 ion_flag = 0;
|
|
struct ion_handle *buff_handle = NULL;
|
|
struct vdec_output_frameinfo *output_frame;
|
|
|
|
if (!client_ctx || !vcd_frame_data) {
|
|
ERR("vid_dec_input_frame_done() NULL pointer\n");
|
|
return;
|
|
}
|
|
|
|
vdec_msg = kzalloc(sizeof(struct vid_dec_msg), GFP_KERNEL);
|
|
if (!vdec_msg) {
|
|
ERR("vid_dec_input_frame_done(): cannot allocate vid_dec_msg "
|
|
" buffer\n");
|
|
return;
|
|
}
|
|
|
|
vdec_msg->vdec_msg_info.status_code = vid_dec_get_status(status);
|
|
|
|
if (event == VCD_EVT_RESP_OUTPUT_DONE)
|
|
vdec_msg->vdec_msg_info.msgcode =
|
|
VDEC_MSG_RESP_OUTPUT_BUFFER_DONE;
|
|
else if (event == VCD_EVT_RESP_OUTPUT_FLUSHED)
|
|
vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_RESP_OUTPUT_FLUSHED;
|
|
else {
|
|
ERR("QVD: vid_dec_output_frame_done invalid cmd type: "
|
|
"%d\n", event);
|
|
vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_INVALID;
|
|
}
|
|
|
|
kernel_vaddr = (unsigned long)vcd_frame_data->virtual;
|
|
|
|
if (vidc_lookup_addr_table(client_ctx, BUFFER_TYPE_OUTPUT,
|
|
false, &user_vaddr, &kernel_vaddr,
|
|
&phy_addr, &pmem_fd, &file,
|
|
&buffer_index) ||
|
|
(vcd_frame_data->flags & VCD_FRAME_FLAG_EOS)) {
|
|
|
|
if (res_trk_check_for_sec_session() &&
|
|
event == VCD_EVT_RESP_OUTPUT_DONE) {
|
|
DBG("Buffer Index = %d", buffer_index);
|
|
if (buffer_index != -1) {
|
|
if (client_ctx->meta_addr_table[buffer_index].
|
|
kernel_vir_addr_iommu &&
|
|
client_ctx->
|
|
meta_addr_table[buffer_index].
|
|
kernel_vir_addr) {
|
|
|
|
memcpy(client_ctx->
|
|
meta_addr_table[buffer_index].
|
|
kernel_vir_addr_iommu,
|
|
client_ctx->
|
|
meta_addr_table[buffer_index].
|
|
kernel_vir_addr,
|
|
client_ctx->meta_buf_size);
|
|
DBG("Copying Meta Buffer from "\
|
|
"secure memory"
|
|
"kernel_virt_iommu = %p "
|
|
"kernel_virt = %p",
|
|
client_ctx->
|
|
meta_addr_table[buffer_index].
|
|
kernel_vir_addr_iommu,
|
|
client_ctx->
|
|
meta_addr_table[buffer_index].
|
|
kernel_vir_addr);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Buffer address in user space */
|
|
vdec_msg->vdec_msg_info.msgdata.output_frame.bufferaddr =
|
|
(u8 *) user_vaddr;
|
|
/* Data length */
|
|
vdec_msg->vdec_msg_info.msgdata.output_frame.len =
|
|
vcd_frame_data->data_len;
|
|
vdec_msg->vdec_msg_info.msgdata.output_frame.flags =
|
|
vcd_frame_data->flags;
|
|
/* Timestamp pass-through from input frame */
|
|
vdec_msg->vdec_msg_info.msgdata.output_frame.time_stamp =
|
|
vcd_frame_data->time_stamp;
|
|
/* Output frame client data */
|
|
vdec_msg->vdec_msg_info.msgdata.output_frame.client_data =
|
|
(void *)vcd_frame_data->frm_clnt_data;
|
|
/* Associated input frame client data */
|
|
vdec_msg->vdec_msg_info.msgdata.output_frame.
|
|
input_frame_clientdata =
|
|
(void *)vcd_frame_data->ip_frm_tag;
|
|
/* Decoded picture width and height */
|
|
vdec_msg->vdec_msg_info.msgdata.output_frame.framesize.
|
|
bottom =
|
|
vcd_frame_data->dec_op_prop.disp_frm.bottom;
|
|
vdec_msg->vdec_msg_info.msgdata.output_frame.framesize.left =
|
|
vcd_frame_data->dec_op_prop.disp_frm.left;
|
|
vdec_msg->vdec_msg_info.msgdata.output_frame.framesize.right =
|
|
vcd_frame_data->dec_op_prop.disp_frm.right;
|
|
vdec_msg->vdec_msg_info.msgdata.output_frame.framesize.top =
|
|
vcd_frame_data->dec_op_prop.disp_frm.top;
|
|
if (vcd_frame_data->interlaced) {
|
|
vdec_msg->vdec_msg_info.msgdata.
|
|
output_frame.interlaced_format =
|
|
VDEC_InterlaceInterleaveFrameTopFieldFirst;
|
|
} else {
|
|
vdec_msg->vdec_msg_info.msgdata.
|
|
output_frame.interlaced_format =
|
|
VDEC_InterlaceFrameProgressive;
|
|
}
|
|
/* Decoded picture type */
|
|
switch (vcd_frame_data->frame) {
|
|
case VCD_FRAME_I:
|
|
pic_type = PICTURE_TYPE_I;
|
|
break;
|
|
case VCD_FRAME_P:
|
|
pic_type = PICTURE_TYPE_P;
|
|
break;
|
|
case VCD_FRAME_B:
|
|
pic_type = PICTURE_TYPE_B;
|
|
break;
|
|
case VCD_FRAME_NOTCODED:
|
|
pic_type = PICTURE_TYPE_SKIP;
|
|
break;
|
|
case VCD_FRAME_IDR:
|
|
pic_type = PICTURE_TYPE_IDR;
|
|
break;
|
|
default:
|
|
pic_type = PICTURE_TYPE_UNKNOWN;
|
|
}
|
|
vdec_msg->vdec_msg_info.msgdata.output_frame.pic_type =
|
|
pic_type;
|
|
output_frame = &vdec_msg->vdec_msg_info.msgdata.output_frame;
|
|
output_frame->aspect_ratio_info.aspect_ratio =
|
|
vcd_frame_data->aspect_ratio_info.aspect_ratio;
|
|
output_frame->aspect_ratio_info.par_width =
|
|
vcd_frame_data->aspect_ratio_info.par_width;
|
|
output_frame->aspect_ratio_info.par_height =
|
|
vcd_frame_data->aspect_ratio_info.par_height;
|
|
vdec_msg->vdec_msg_info.msgdatasize =
|
|
sizeof(struct vdec_output_frameinfo);
|
|
} else {
|
|
ERR("vid_dec_output_frame_done UVA can not be found\n");
|
|
vdec_msg->vdec_msg_info.status_code = VDEC_S_EFATAL;
|
|
}
|
|
if (vcd_frame_data->data_len > 0) {
|
|
ion_flag = vidc_get_fd_info(client_ctx, BUFFER_TYPE_OUTPUT,
|
|
pmem_fd, kernel_vaddr, buffer_index,
|
|
&buff_handle);
|
|
if (ion_flag == ION_FLAG_CACHED && buff_handle) {
|
|
DBG("%s: Cache invalidate: vaddr (%p), "\
|
|
"size %u\n", __func__,
|
|
(void *)kernel_vaddr,
|
|
vcd_frame_data->alloc_len);
|
|
msm_ion_do_cache_op(client_ctx->user_ion_client,
|
|
buff_handle,
|
|
(unsigned long *) kernel_vaddr,
|
|
(unsigned long)vcd_frame_data->\
|
|
alloc_len,
|
|
ION_IOC_INV_CACHES);
|
|
}
|
|
}
|
|
mutex_lock(&client_ctx->msg_queue_lock);
|
|
list_add_tail(&vdec_msg->list, &client_ctx->msg_queue);
|
|
mutex_unlock(&client_ctx->msg_queue_lock);
|
|
wake_up(&client_ctx->msg_wait);
|
|
}
|
|
|
|
static void vid_dec_lean_event(struct video_client_ctx *client_ctx,
|
|
u32 event, u32 status)
|
|
{
|
|
struct vid_dec_msg *vdec_msg;
|
|
|
|
if (!client_ctx) {
|
|
ERR("%s(): !client_ctx pointer\n", __func__);
|
|
return;
|
|
}
|
|
|
|
vdec_msg = kzalloc(sizeof(struct vid_dec_msg), GFP_KERNEL);
|
|
if (!vdec_msg) {
|
|
ERR("%s(): cannot allocate vid_dec_msg buffer\n", __func__);
|
|
return;
|
|
}
|
|
|
|
vdec_msg->vdec_msg_info.status_code = vid_dec_get_status(status);
|
|
|
|
switch (event) {
|
|
case VCD_EVT_IND_OUTPUT_RECONFIG:
|
|
DBG("msm_vidc_dec: Sending VDEC_MSG_EVT_CONFIG_CHANGED"
|
|
" to client");
|
|
vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_EVT_CONFIG_CHANGED;
|
|
break;
|
|
case VCD_EVT_IND_RESOURCES_LOST:
|
|
DBG("msm_vidc_dec: Sending VDEC_EVT_RESOURCES_LOST"
|
|
" to client");
|
|
vdec_msg->vdec_msg_info.msgcode = VDEC_EVT_RESOURCES_LOST;
|
|
break;
|
|
case VCD_EVT_RESP_FLUSH_INPUT_DONE:
|
|
DBG("msm_vidc_dec: Sending VDEC_MSG_RESP_FLUSH_INPUT_DONE"
|
|
" to client");
|
|
vdec_msg->vdec_msg_info.msgcode =
|
|
VDEC_MSG_RESP_FLUSH_INPUT_DONE;
|
|
break;
|
|
case VCD_EVT_RESP_FLUSH_OUTPUT_DONE:
|
|
DBG("msm_vidc_dec: Sending VDEC_MSG_RESP_FLUSH_OUTPUT_DONE"
|
|
" to client");
|
|
vdec_msg->vdec_msg_info.msgcode =
|
|
VDEC_MSG_RESP_FLUSH_OUTPUT_DONE;
|
|
break;
|
|
case VCD_EVT_IND_HWERRFATAL:
|
|
DBG("msm_vidc_dec: Sending VDEC_MSG_EVT_HW_ERROR"
|
|
" to client");
|
|
vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_EVT_HW_ERROR;
|
|
break;
|
|
case VCD_EVT_RESP_START:
|
|
DBG("msm_vidc_dec: Sending VDEC_MSG_RESP_START_DONE"
|
|
" to client");
|
|
vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_RESP_START_DONE;
|
|
break;
|
|
case VCD_EVT_RESP_STOP:
|
|
DBG("msm_vidc_dec: Sending VDEC_MSG_RESP_STOP_DONE"
|
|
" to client");
|
|
vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_RESP_STOP_DONE;
|
|
break;
|
|
case VCD_EVT_RESP_PAUSE:
|
|
DBG("msm_vidc_dec: Sending VDEC_MSG_RESP_PAUSE_DONE"
|
|
" to client");
|
|
vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_RESP_PAUSE_DONE;
|
|
break;
|
|
case VCD_EVT_IND_INFO_OUTPUT_RECONFIG:
|
|
DBG("msm_vidc_dec: Sending VDEC_MSG_EVT_INFO_CONFIG_CHANGED"
|
|
" to client");
|
|
vdec_msg->vdec_msg_info.msgcode =
|
|
VDEC_MSG_EVT_INFO_CONFIG_CHANGED;
|
|
break;
|
|
default:
|
|
ERR("%s() : unknown event type\n", __func__);
|
|
break;
|
|
}
|
|
|
|
vdec_msg->vdec_msg_info.msgdatasize = 0;
|
|
if (client_ctx->stop_sync_cb &&
|
|
(event == VCD_EVT_RESP_STOP || event == VCD_EVT_IND_HWERRFATAL)) {
|
|
client_ctx->stop_sync_cb = false;
|
|
complete(&client_ctx->event);
|
|
kfree(vdec_msg);
|
|
return;
|
|
}
|
|
mutex_lock(&client_ctx->msg_queue_lock);
|
|
list_add_tail(&vdec_msg->list, &client_ctx->msg_queue);
|
|
mutex_unlock(&client_ctx->msg_queue_lock);
|
|
wake_up(&client_ctx->msg_wait);
|
|
}
|
|
|
|
|
|
void vid_dec_vcd_cb(u32 event, u32 status,
|
|
void *info, size_t sz, void *handle, void *const client_data)
|
|
{
|
|
struct video_client_ctx *client_ctx =
|
|
(struct video_client_ctx *)client_data;
|
|
|
|
DBG("Entering %s()\n", __func__);
|
|
|
|
if (!client_ctx) {
|
|
ERR("%s(): client_ctx is NULL\n", __func__);
|
|
return;
|
|
}
|
|
|
|
client_ctx->event_status = status;
|
|
|
|
switch (event) {
|
|
case VCD_EVT_RESP_OPEN:
|
|
vid_dec_vcd_open_done(client_ctx,
|
|
(struct vcd_handle_container *)
|
|
info);
|
|
break;
|
|
case VCD_EVT_RESP_INPUT_DONE:
|
|
case VCD_EVT_RESP_INPUT_FLUSHED:
|
|
vid_dec_input_frame_done(client_ctx, event, status,
|
|
(struct vcd_frame_data *)info);
|
|
break;
|
|
case VCD_EVT_IND_INFO_FIELD_DROPPED:
|
|
if (info)
|
|
vid_dec_handle_field_drop(client_ctx, event,
|
|
status, *((int64_t *)info));
|
|
else
|
|
pr_err("Wrong Payload for Field dropped\n");
|
|
break;
|
|
case VCD_EVT_RESP_OUTPUT_DONE:
|
|
case VCD_EVT_RESP_OUTPUT_FLUSHED:
|
|
vid_dec_output_frame_done(client_ctx, event, status,
|
|
(struct vcd_frame_data *)info);
|
|
break;
|
|
case VCD_EVT_RESP_PAUSE:
|
|
case VCD_EVT_RESP_STOP:
|
|
case VCD_EVT_RESP_FLUSH_INPUT_DONE:
|
|
case VCD_EVT_RESP_FLUSH_OUTPUT_DONE:
|
|
case VCD_EVT_IND_OUTPUT_RECONFIG:
|
|
case VCD_EVT_IND_HWERRFATAL:
|
|
case VCD_EVT_IND_RESOURCES_LOST:
|
|
case VCD_EVT_IND_INFO_OUTPUT_RECONFIG:
|
|
vid_dec_lean_event(client_ctx, event, status);
|
|
break;
|
|
case VCD_EVT_RESP_START:
|
|
if (!client_ctx->seq_header_set)
|
|
vid_dec_lean_event(client_ctx, event, status);
|
|
else
|
|
vid_dec_notify_client(client_ctx);
|
|
break;
|
|
default:
|
|
ERR("%s() : Error - Invalid event type =%u\n", __func__,
|
|
event);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static u32 vid_dec_set_codec(struct video_client_ctx *client_ctx,
|
|
enum vdec_codec *vdec_codec)
|
|
{
|
|
u32 result = true;
|
|
struct vcd_property_hdr vcd_property_hdr;
|
|
struct vcd_property_codec codec;
|
|
u32 vcd_status = VCD_ERR_FAIL;
|
|
|
|
if (!client_ctx || !vdec_codec)
|
|
return false;
|
|
|
|
vcd_property_hdr.prop_id = VCD_I_CODEC;
|
|
vcd_property_hdr.sz = sizeof(struct vcd_property_codec);
|
|
|
|
switch (*vdec_codec) {
|
|
case VDEC_CODECTYPE_MPEG4:
|
|
codec.codec = VCD_CODEC_MPEG4;
|
|
break;
|
|
case VDEC_CODECTYPE_H264:
|
|
codec.codec = VCD_CODEC_H264;
|
|
break;
|
|
case VDEC_CODECTYPE_DIVX_3:
|
|
codec.codec = VCD_CODEC_DIVX_3;
|
|
break;
|
|
case VDEC_CODECTYPE_DIVX_4:
|
|
codec.codec = VCD_CODEC_DIVX_4;
|
|
break;
|
|
case VDEC_CODECTYPE_DIVX_5:
|
|
codec.codec = VCD_CODEC_DIVX_5;
|
|
break;
|
|
case VDEC_CODECTYPE_DIVX_6:
|
|
codec.codec = VCD_CODEC_DIVX_6;
|
|
break;
|
|
case VDEC_CODECTYPE_XVID:
|
|
codec.codec = VCD_CODEC_XVID;
|
|
break;
|
|
case VDEC_CODECTYPE_H263:
|
|
codec.codec = VCD_CODEC_H263;
|
|
break;
|
|
case VDEC_CODECTYPE_MPEG2:
|
|
codec.codec = VCD_CODEC_MPEG2;
|
|
break;
|
|
case VDEC_CODECTYPE_VC1:
|
|
codec.codec = VCD_CODEC_VC1;
|
|
break;
|
|
case VDEC_CODECTYPE_VC1_RCV:
|
|
codec.codec = VCD_CODEC_VC1_RCV;
|
|
break;
|
|
default:
|
|
result = false;
|
|
break;
|
|
}
|
|
|
|
if (result) {
|
|
vcd_status = vcd_set_property(client_ctx->vcd_handle,
|
|
&vcd_property_hdr, &codec);
|
|
if (vcd_status)
|
|
result = false;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static u32 vid_dec_set_output_format(struct video_client_ctx *client_ctx,
|
|
enum vdec_output_fromat *output_format)
|
|
{
|
|
u32 result = true;
|
|
struct vcd_property_hdr vcd_property_hdr;
|
|
struct vcd_property_buffer_format vcd_prop_buffer_format;
|
|
u32 vcd_status = VCD_ERR_FAIL;
|
|
|
|
if (!client_ctx || !output_format)
|
|
return false;
|
|
|
|
vcd_property_hdr.prop_id = VCD_I_BUFFER_FORMAT;;
|
|
vcd_property_hdr.sz =
|
|
sizeof(struct vcd_property_buffer_format);
|
|
|
|
switch (*output_format) {
|
|
case VDEC_YUV_FORMAT_NV12:
|
|
vcd_prop_buffer_format.buffer_format = VCD_BUFFER_FORMAT_NV12;
|
|
break;
|
|
case VDEC_YUV_FORMAT_TILE_4x2:
|
|
vcd_prop_buffer_format.buffer_format =
|
|
VCD_BUFFER_FORMAT_TILE_4x2;
|
|
break;
|
|
default:
|
|
result = false;
|
|
break;
|
|
}
|
|
|
|
if (result)
|
|
vcd_status = vcd_set_property(client_ctx->vcd_handle,
|
|
&vcd_property_hdr,
|
|
&vcd_prop_buffer_format);
|
|
|
|
if (vcd_status)
|
|
return false;
|
|
else
|
|
return true;
|
|
}
|
|
|
|
static u32 vid_dec_set_frame_resolution(struct video_client_ctx *client_ctx,
|
|
struct vdec_picsize *video_resoultion)
|
|
{
|
|
struct vcd_property_hdr vcd_property_hdr;
|
|
struct vcd_property_frame_size frame_resolution;
|
|
u32 vcd_status = VCD_ERR_FAIL;
|
|
|
|
if (!client_ctx || !video_resoultion)
|
|
return false;
|
|
|
|
vcd_property_hdr.prop_id = VCD_I_FRAME_SIZE;
|
|
vcd_property_hdr.sz = sizeof(struct vcd_property_frame_size);
|
|
frame_resolution.width = video_resoultion->frame_width;
|
|
frame_resolution.height = video_resoultion->frame_height;
|
|
frame_resolution.stride = video_resoultion->stride;
|
|
frame_resolution.scan_lines = video_resoultion->scan_lines;
|
|
|
|
vcd_status = vcd_set_property(client_ctx->vcd_handle,
|
|
&vcd_property_hdr, &frame_resolution);
|
|
|
|
if (vcd_status)
|
|
return false;
|
|
else
|
|
return true;
|
|
}
|
|
|
|
static u32 vid_dec_set_turbo_clk(struct video_client_ctx *client_ctx)
|
|
{
|
|
struct vcd_property_hdr vcd_property_hdr;
|
|
u32 vcd_status = VCD_ERR_FAIL;
|
|
u32 dummy = 0;
|
|
|
|
if (!client_ctx)
|
|
return false;
|
|
vcd_property_hdr.prop_id = VCD_I_SET_TURBO_CLK;
|
|
vcd_property_hdr.sz = sizeof(struct vcd_property_frame_size);
|
|
|
|
vcd_status = vcd_set_property(client_ctx->vcd_handle,
|
|
&vcd_property_hdr, &dummy);
|
|
|
|
if (vcd_status)
|
|
return false;
|
|
else
|
|
return true;
|
|
}
|
|
|
|
static u32 vid_dec_get_frame_resolution(struct video_client_ctx *client_ctx,
|
|
struct vdec_picsize *video_resoultion)
|
|
{
|
|
struct vcd_property_hdr vcd_property_hdr;
|
|
struct vcd_property_frame_size frame_resolution;
|
|
u32 vcd_status = VCD_ERR_FAIL;
|
|
|
|
if (!client_ctx || !video_resoultion)
|
|
return false;
|
|
|
|
vcd_property_hdr.prop_id = VCD_I_FRAME_SIZE;
|
|
vcd_property_hdr.sz = sizeof(struct vcd_property_frame_size);
|
|
|
|
vcd_status = vcd_get_property(client_ctx->vcd_handle, &vcd_property_hdr,
|
|
&frame_resolution);
|
|
|
|
video_resoultion->frame_width = frame_resolution.width;
|
|
video_resoultion->frame_height = frame_resolution.height;
|
|
video_resoultion->scan_lines = frame_resolution.scan_lines;
|
|
video_resoultion->stride = frame_resolution.stride;
|
|
|
|
if (vcd_status)
|
|
return false;
|
|
else
|
|
return true;
|
|
}
|
|
|
|
static u32 vid_dec_get_progressive_only(struct video_client_ctx *client_ctx,
|
|
u32 *progressive_only)
|
|
{
|
|
struct vcd_property_hdr vcd_property_hdr;
|
|
if (!client_ctx || !progressive_only)
|
|
return false;
|
|
vcd_property_hdr.prop_id = VCD_I_PROGRESSIVE_ONLY;
|
|
vcd_property_hdr.sz = sizeof(u32);
|
|
if (vcd_get_property(client_ctx->vcd_handle, &vcd_property_hdr,
|
|
progressive_only))
|
|
return false;
|
|
else
|
|
return true;
|
|
}
|
|
|
|
static u32 vid_dec_get_disable_dmx_support(struct video_client_ctx *client_ctx,
|
|
u32 *disable_dmx)
|
|
{
|
|
|
|
struct vcd_property_hdr vcd_property_hdr;
|
|
if (!client_ctx || !disable_dmx)
|
|
return false;
|
|
vcd_property_hdr.prop_id = VCD_I_DISABLE_DMX_SUPPORT;
|
|
vcd_property_hdr.sz = sizeof(u32);
|
|
if (vcd_get_property(client_ctx->vcd_handle, &vcd_property_hdr,
|
|
disable_dmx))
|
|
return false;
|
|
else
|
|
return true;
|
|
}
|
|
static u32 vid_dec_get_disable_dmx(struct video_client_ctx *client_ctx,
|
|
u32 *disable_dmx)
|
|
{
|
|
|
|
struct vcd_property_hdr vcd_property_hdr;
|
|
if (!client_ctx || !disable_dmx)
|
|
return false;
|
|
vcd_property_hdr.prop_id = VCD_I_DISABLE_DMX;
|
|
vcd_property_hdr.sz = sizeof(u32);
|
|
if (vcd_get_property(client_ctx->vcd_handle, &vcd_property_hdr,
|
|
disable_dmx))
|
|
return false;
|
|
else
|
|
return true;
|
|
}
|
|
|
|
static u32 vid_dec_set_disable_dmx(struct video_client_ctx *client_ctx)
|
|
{
|
|
|
|
struct vcd_property_hdr vcd_property_hdr;
|
|
u32 vcd_disable_dmx;
|
|
if (!client_ctx)
|
|
return false;
|
|
vcd_property_hdr.prop_id = VCD_I_DISABLE_DMX;
|
|
vcd_property_hdr.sz = sizeof(u32);
|
|
vcd_disable_dmx = true;
|
|
DBG("%s() : Setting Disable DMX: %d\n",
|
|
__func__, vcd_disable_dmx);
|
|
|
|
if (vcd_set_property(client_ctx->vcd_handle, &vcd_property_hdr,
|
|
&vcd_disable_dmx))
|
|
return false;
|
|
else
|
|
return true;
|
|
}
|
|
|
|
static u32 vid_dec_set_picture_order(struct video_client_ctx *client_ctx,
|
|
u32 *picture_order)
|
|
{
|
|
struct vcd_property_hdr vcd_property_hdr;
|
|
u32 vcd_status = VCD_ERR_FAIL, vcd_picture_order, ret = true;
|
|
if (!client_ctx || !picture_order)
|
|
return false;
|
|
vcd_property_hdr.prop_id = VCD_I_OUTPUT_ORDER;
|
|
vcd_property_hdr.sz = sizeof(u32);
|
|
if (*picture_order == VDEC_ORDER_DISPLAY)
|
|
vcd_picture_order = VCD_DEC_ORDER_DISPLAY;
|
|
else if (*picture_order == VDEC_ORDER_DECODE)
|
|
vcd_picture_order = VCD_DEC_ORDER_DECODE;
|
|
else
|
|
ret = false;
|
|
if (ret) {
|
|
DBG("%s() : Setting output picture order: %d\n",
|
|
__func__, vcd_picture_order);
|
|
vcd_status = vcd_set_property(client_ctx->vcd_handle,
|
|
&vcd_property_hdr, &vcd_picture_order);
|
|
if (vcd_status != VCD_S_SUCCESS)
|
|
ret = false;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static u32 vid_dec_set_frame_rate(struct video_client_ctx *client_ctx,
|
|
struct vdec_framerate *frame_rate)
|
|
{
|
|
struct vcd_property_hdr vcd_property_hdr;
|
|
struct vcd_property_frame_rate vcd_frame_rate;
|
|
u32 vcd_status = VCD_ERR_FAIL;
|
|
|
|
if (!client_ctx || !frame_rate)
|
|
return false;
|
|
|
|
vcd_property_hdr.prop_id = VCD_I_FRAME_RATE;
|
|
vcd_property_hdr.sz = sizeof(struct vcd_property_frame_rate);
|
|
vcd_frame_rate.fps_numerator = frame_rate->fps_numerator;
|
|
vcd_frame_rate.fps_denominator = frame_rate->fps_denominator;
|
|
|
|
vcd_status = vcd_set_property(client_ctx->vcd_handle,
|
|
&vcd_property_hdr, &vcd_frame_rate);
|
|
|
|
if (vcd_status)
|
|
return false;
|
|
else
|
|
return true;
|
|
}
|
|
|
|
static u32 vid_dec_set_extradata(struct video_client_ctx *client_ctx,
|
|
u32 *extradata_flag)
|
|
{
|
|
struct vcd_property_hdr vcd_property_hdr;
|
|
struct vcd_property_meta_data_enable vcd_meta_data;
|
|
u32 vcd_status = VCD_ERR_FAIL;
|
|
if (!client_ctx || !extradata_flag)
|
|
return false;
|
|
vcd_property_hdr.prop_id = VCD_I_METADATA_ENABLE;
|
|
vcd_property_hdr.sz = sizeof(struct vcd_property_meta_data_enable);
|
|
vcd_meta_data.meta_data_enable_flag = *extradata_flag;
|
|
vcd_status = vcd_set_property(client_ctx->vcd_handle,
|
|
&vcd_property_hdr, &vcd_meta_data);
|
|
if (vcd_status)
|
|
return false;
|
|
else
|
|
return true;
|
|
}
|
|
|
|
static u32 vid_dec_set_idr_only_decoding(struct video_client_ctx *client_ctx)
|
|
{
|
|
struct vcd_property_hdr vcd_property_hdr;
|
|
u32 vcd_status = VCD_ERR_FAIL;
|
|
u32 enable = true;
|
|
if (!client_ctx)
|
|
return false;
|
|
vcd_property_hdr.prop_id = VCD_I_DEC_PICTYPE;
|
|
vcd_property_hdr.sz = sizeof(u32);
|
|
vcd_status = vcd_set_property(client_ctx->vcd_handle,
|
|
&vcd_property_hdr, &enable);
|
|
if (vcd_status)
|
|
return false;
|
|
return true;
|
|
}
|
|
static u32 vid_dec_set_meta_buffers(struct video_client_ctx *client_ctx,
|
|
struct vdec_meta_buffers *meta_buffers)
|
|
{
|
|
struct vcd_property_hdr vcd_property_hdr;
|
|
struct vcd_property_meta_buffer *vcd_meta_buffer = NULL;
|
|
u32 vcd_status = VCD_ERR_FAIL;
|
|
u32 len = 0, len_iommu = 0, buf_size = 0;
|
|
int rc = 0;
|
|
unsigned long ionflag = 0, ionflag_iommu = 0;
|
|
unsigned long buffer_size = 0, buffer_size_iommu = 0;
|
|
unsigned long iova = 0, iova_iommu = 0;
|
|
int index = -1, num_buffers = 0;
|
|
u8 *ker_vir_addr = NULL, *ker_vir_addr_iommu = NULL;
|
|
|
|
if (!client_ctx || !meta_buffers)
|
|
return false;
|
|
|
|
vcd_property_hdr.prop_id = VCD_I_SET_EXT_METABUFFER;
|
|
vcd_property_hdr.sz = sizeof(struct vcd_property_meta_buffer);
|
|
vcd_meta_buffer = &client_ctx->vcd_meta_buffer;
|
|
|
|
memset(&client_ctx->vcd_meta_buffer, 0,
|
|
sizeof(struct vcd_property_meta_buffer));
|
|
vcd_meta_buffer->size = meta_buffers->size;
|
|
vcd_meta_buffer->count = meta_buffers->count;
|
|
vcd_meta_buffer->pmem_fd = meta_buffers->pmem_fd;
|
|
vcd_meta_buffer->offset = meta_buffers->offset;
|
|
vcd_meta_buffer->pmem_fd_iommu = meta_buffers->pmem_fd_iommu;
|
|
|
|
if (!vcd_get_ion_status()) {
|
|
pr_err("PMEM Not available\n");
|
|
return false;
|
|
} else {
|
|
client_ctx->meta_buffer_ion_handle = ion_import_dma_buf(
|
|
client_ctx->user_ion_client,
|
|
vcd_meta_buffer->pmem_fd);
|
|
if (IS_ERR_OR_NULL(client_ctx->meta_buffer_ion_handle)) {
|
|
ERR("%s(): get_ION_handle failed\n", __func__);
|
|
goto import_ion_error;
|
|
}
|
|
rc = ion_handle_get_flags(client_ctx->user_ion_client,
|
|
client_ctx->meta_buffer_ion_handle,
|
|
&ionflag);
|
|
if (rc) {
|
|
ERR("%s():get_ION_flags fail\n",
|
|
__func__);
|
|
goto import_ion_error;
|
|
}
|
|
vcd_meta_buffer->kernel_virtual_addr =
|
|
(u8 *) ion_map_kernel(
|
|
client_ctx->user_ion_client,
|
|
client_ctx->meta_buffer_ion_handle);
|
|
if (!vcd_meta_buffer->kernel_virtual_addr) {
|
|
ERR("%s(): get_ION_kernel virtual addr failed\n",
|
|
__func__);
|
|
goto import_ion_error;
|
|
}
|
|
if (res_trk_check_for_sec_session() ||
|
|
(res_trk_get_core_type() == (u32)VCD_CORE_720P)) {
|
|
rc = ion_phys(client_ctx->user_ion_client,
|
|
client_ctx->meta_buffer_ion_handle,
|
|
(unsigned long *) (&(vcd_meta_buffer->
|
|
physical_addr)), &len);
|
|
if (rc) {
|
|
ERR("%s():get_ION_kernel physical addr fail\n",
|
|
__func__);
|
|
goto ion_map_error;
|
|
}
|
|
vcd_meta_buffer->client_data = NULL;
|
|
vcd_meta_buffer->dev_addr = (u8 *)
|
|
vcd_meta_buffer->physical_addr;
|
|
} else {
|
|
rc = ion_map_iommu(client_ctx->user_ion_client,
|
|
client_ctx->meta_buffer_ion_handle,
|
|
VIDEO_DOMAIN, VIDEO_MAIN_POOL,
|
|
SZ_4K, 0, (unsigned long *)&iova,
|
|
(unsigned long *)&buffer_size,
|
|
0, 0);
|
|
if (rc || !iova) {
|
|
ERR("%s():get_ION_kernel physical addr fail,"\
|
|
" rc = %d iova = 0x%lx\n",
|
|
__func__, rc, iova);
|
|
goto ion_map_error;
|
|
}
|
|
vcd_meta_buffer->physical_addr = (u8 *) iova;
|
|
vcd_meta_buffer->client_data = NULL;
|
|
vcd_meta_buffer->dev_addr = (u8 *) iova;
|
|
}
|
|
|
|
client_ctx->meta_buffer_iommu_ion_handle = ion_import_dma_buf(
|
|
client_ctx->user_ion_client,
|
|
vcd_meta_buffer->pmem_fd_iommu);
|
|
if (IS_ERR_OR_NULL(client_ctx->meta_buffer_iommu_ion_handle)) {
|
|
ERR("%s(): get_ION_handle failed\n", __func__);
|
|
goto import_ion_error;
|
|
}
|
|
rc = ion_handle_get_flags(client_ctx->user_ion_client,
|
|
client_ctx->
|
|
meta_buffer_iommu_ion_handle,
|
|
&ionflag_iommu);
|
|
if (rc) {
|
|
ERR("%s():get_ION_flags fail\n",
|
|
__func__);
|
|
goto import_ion_error;
|
|
}
|
|
vcd_meta_buffer->kernel_virt_addr_iommu =
|
|
(u8 *) ion_map_kernel(
|
|
client_ctx->user_ion_client,
|
|
client_ctx->meta_buffer_iommu_ion_handle);
|
|
if (!vcd_meta_buffer->kernel_virt_addr_iommu) {
|
|
ERR("%s(): get_ION_kernel virtual addr failed\n",
|
|
__func__);
|
|
goto import_ion_error;
|
|
}
|
|
if (res_trk_get_core_type() == (u32)VCD_CORE_720P) {
|
|
rc = ion_phys(client_ctx->user_ion_client,
|
|
client_ctx->meta_buffer_iommu_ion_handle,
|
|
(unsigned long *) (&(vcd_meta_buffer->
|
|
physical_addr_iommu)), &len_iommu);
|
|
if (rc) {
|
|
ERR("%s():get_ION_kernel physical addr fail\n",
|
|
__func__);
|
|
goto ion_map_error_iommu;
|
|
}
|
|
vcd_meta_buffer->client_data_iommu = NULL;
|
|
vcd_meta_buffer->dev_addr_iommu = (u8 *)
|
|
vcd_meta_buffer->physical_addr_iommu;
|
|
} else {
|
|
rc = ion_map_iommu(client_ctx->user_ion_client,
|
|
client_ctx->meta_buffer_iommu_ion_handle,
|
|
VIDEO_DOMAIN, VIDEO_MAIN_POOL,
|
|
SZ_4K, 0, (unsigned long *)&iova_iommu,
|
|
(unsigned long *)&buffer_size_iommu,
|
|
0, 0);
|
|
if (rc || !iova_iommu) {
|
|
ERR("%s():get_ION_kernel physical addr fail, "\
|
|
"rc = %d iova = 0x%lx\n",
|
|
__func__, rc, iova);
|
|
goto ion_map_error_iommu;
|
|
}
|
|
vcd_meta_buffer->physical_addr_iommu =
|
|
(u8 *) iova_iommu;
|
|
vcd_meta_buffer->client_data_iommu = NULL;
|
|
vcd_meta_buffer->dev_addr_iommu = (u8 *) iova_iommu;
|
|
}
|
|
}
|
|
|
|
/*fill the meta addr table*/
|
|
num_buffers = vcd_meta_buffer->count;
|
|
buf_size = vcd_meta_buffer->size/num_buffers;
|
|
ker_vir_addr = vcd_meta_buffer->kernel_virtual_addr;
|
|
ker_vir_addr_iommu = vcd_meta_buffer->kernel_virt_addr_iommu;
|
|
client_ctx->meta_buf_size = buf_size;
|
|
for (index = 0; index < num_buffers; index++) {
|
|
client_ctx->meta_addr_table[index].kernel_vir_addr =
|
|
ker_vir_addr;
|
|
client_ctx->meta_addr_table[index].kernel_vir_addr_iommu =
|
|
ker_vir_addr_iommu;
|
|
DBG("[%d] kernel_virtual = %p kernel_vir_iommu = %p",
|
|
index, ker_vir_addr, ker_vir_addr_iommu);
|
|
ker_vir_addr += buf_size;
|
|
ker_vir_addr_iommu += buf_size;
|
|
}
|
|
|
|
DBG("Meta Buffer: Virt: %p, Phys %p, fd: %d",
|
|
vcd_meta_buffer->kernel_virtual_addr,
|
|
vcd_meta_buffer->physical_addr,
|
|
vcd_meta_buffer->pmem_fd);
|
|
DBG("IOMMU Meta Buffer: Virt: %p, Phys %p, fd: %d",
|
|
vcd_meta_buffer->kernel_virt_addr_iommu,
|
|
vcd_meta_buffer->physical_addr_iommu,
|
|
vcd_meta_buffer->pmem_fd_iommu);
|
|
DBG("Meta_buffer: Dev addr %p", vcd_meta_buffer->dev_addr);
|
|
DBG("IOMMU Meta_buffer: Dev addr %p",
|
|
vcd_meta_buffer->dev_addr_iommu);
|
|
vcd_status = vcd_set_property(client_ctx->vcd_handle,
|
|
&vcd_property_hdr,
|
|
vcd_meta_buffer);
|
|
|
|
if (vcd_status)
|
|
return false;
|
|
else
|
|
return true;
|
|
ion_map_error_iommu:
|
|
if (vcd_meta_buffer->kernel_virt_addr_iommu) {
|
|
ion_unmap_kernel(client_ctx->user_ion_client,
|
|
client_ctx->meta_buffer_iommu_ion_handle);
|
|
vcd_meta_buffer->kernel_virt_addr_iommu = NULL;
|
|
}
|
|
if (!IS_ERR_OR_NULL(client_ctx->meta_buffer_iommu_ion_handle)) {
|
|
ion_free(client_ctx->user_ion_client,
|
|
client_ctx->meta_buffer_iommu_ion_handle);
|
|
client_ctx->meta_buffer_iommu_ion_handle = NULL;
|
|
}
|
|
ion_map_error:
|
|
if (vcd_meta_buffer->kernel_virtual_addr) {
|
|
ion_unmap_kernel(client_ctx->user_ion_client,
|
|
client_ctx->meta_buffer_ion_handle);
|
|
vcd_meta_buffer->kernel_virtual_addr = NULL;
|
|
}
|
|
if (!IS_ERR_OR_NULL(client_ctx->meta_buffer_ion_handle)) {
|
|
ion_free(client_ctx->user_ion_client,
|
|
client_ctx->meta_buffer_ion_handle);
|
|
client_ctx->meta_buffer_ion_handle = NULL;
|
|
}
|
|
import_ion_error:
|
|
return false;
|
|
}
|
|
static u32 vid_dec_set_h264_mv_buffers(struct video_client_ctx *client_ctx,
|
|
struct vdec_h264_mv *mv_data)
|
|
{
|
|
struct vcd_property_hdr vcd_property_hdr;
|
|
struct vcd_property_h264_mv_buffer *vcd_h264_mv_buffer = NULL;
|
|
u32 vcd_status = VCD_ERR_FAIL;
|
|
u32 len = 0;
|
|
int rc = 0;
|
|
unsigned long ionflag = 0;
|
|
unsigned long buffer_size = 0;
|
|
unsigned long iova = 0;
|
|
|
|
if (!client_ctx || !mv_data)
|
|
return false;
|
|
|
|
vcd_property_hdr.prop_id = VCD_I_H264_MV_BUFFER;
|
|
vcd_property_hdr.sz = sizeof(struct vcd_property_h264_mv_buffer);
|
|
vcd_h264_mv_buffer = &client_ctx->vcd_h264_mv_buffer;
|
|
|
|
memset(&client_ctx->vcd_h264_mv_buffer, 0,
|
|
sizeof(struct vcd_property_h264_mv_buffer));
|
|
vcd_h264_mv_buffer->size = mv_data->size;
|
|
vcd_h264_mv_buffer->count = mv_data->count;
|
|
vcd_h264_mv_buffer->pmem_fd = mv_data->pmem_fd;
|
|
vcd_h264_mv_buffer->offset = mv_data->offset;
|
|
|
|
if (!vcd_get_ion_status()) {
|
|
pr_err("PMEM not available\n");
|
|
return false;
|
|
} else {
|
|
client_ctx->h264_mv_ion_handle = ion_import_dma_buf(
|
|
client_ctx->user_ion_client,
|
|
vcd_h264_mv_buffer->pmem_fd);
|
|
if (IS_ERR_OR_NULL(client_ctx->h264_mv_ion_handle)) {
|
|
ERR("%s(): get_ION_handle failed\n", __func__);
|
|
goto import_ion_error;
|
|
}
|
|
rc = ion_handle_get_flags(client_ctx->user_ion_client,
|
|
client_ctx->h264_mv_ion_handle,
|
|
&ionflag);
|
|
if (rc) {
|
|
ERR("%s():get_ION_flags fail\n",
|
|
__func__);
|
|
goto import_ion_error;
|
|
}
|
|
vcd_h264_mv_buffer->kernel_virtual_addr = (u8 *) ion_map_kernel(
|
|
client_ctx->user_ion_client,
|
|
client_ctx->h264_mv_ion_handle);
|
|
if (!vcd_h264_mv_buffer->kernel_virtual_addr) {
|
|
ERR("%s(): get_ION_kernel virtual addr failed\n",
|
|
__func__);
|
|
goto import_ion_error;
|
|
}
|
|
if (res_trk_check_for_sec_session() ||
|
|
(res_trk_get_core_type() == (u32)VCD_CORE_720P)) {
|
|
rc = ion_phys(client_ctx->user_ion_client,
|
|
client_ctx->h264_mv_ion_handle,
|
|
(unsigned long *) (&(vcd_h264_mv_buffer->
|
|
physical_addr)), &len);
|
|
if (rc) {
|
|
ERR("%s():get_ION_kernel physical addr fail\n",
|
|
__func__);
|
|
goto ion_map_error;
|
|
}
|
|
vcd_h264_mv_buffer->client_data = NULL;
|
|
vcd_h264_mv_buffer->dev_addr = (u8 *)
|
|
vcd_h264_mv_buffer->physical_addr;
|
|
} else {
|
|
rc = ion_map_iommu(client_ctx->user_ion_client,
|
|
client_ctx->h264_mv_ion_handle,
|
|
VIDEO_DOMAIN, VIDEO_MAIN_POOL,
|
|
SZ_4K, 0, (unsigned long *)&iova,
|
|
(unsigned long *)&buffer_size,
|
|
0, 0);
|
|
if (rc || !iova) {
|
|
ERR(
|
|
"%s():get_ION_kernel physical addr fail, rc = %d iova = 0x%lx\n",
|
|
__func__, rc, iova);
|
|
goto ion_map_error;
|
|
}
|
|
vcd_h264_mv_buffer->physical_addr = (u8 *) iova;
|
|
vcd_h264_mv_buffer->client_data = NULL;
|
|
vcd_h264_mv_buffer->dev_addr = (u8 *) iova;
|
|
}
|
|
}
|
|
DBG("Virt: %p, Phys %p, fd: %d", vcd_h264_mv_buffer->
|
|
kernel_virtual_addr, vcd_h264_mv_buffer->physical_addr,
|
|
vcd_h264_mv_buffer->pmem_fd);
|
|
DBG("Dev addr %p", vcd_h264_mv_buffer->dev_addr);
|
|
vcd_status = vcd_set_property(client_ctx->vcd_handle,
|
|
&vcd_property_hdr, vcd_h264_mv_buffer);
|
|
|
|
if (vcd_status)
|
|
return false;
|
|
else
|
|
return true;
|
|
ion_map_error:
|
|
if (vcd_h264_mv_buffer->kernel_virtual_addr) {
|
|
ion_unmap_kernel(client_ctx->user_ion_client,
|
|
client_ctx->h264_mv_ion_handle);
|
|
vcd_h264_mv_buffer->kernel_virtual_addr = NULL;
|
|
}
|
|
if (!IS_ERR_OR_NULL(client_ctx->h264_mv_ion_handle)) {
|
|
ion_free(client_ctx->user_ion_client,
|
|
client_ctx->h264_mv_ion_handle);
|
|
client_ctx->h264_mv_ion_handle = NULL;
|
|
}
|
|
import_ion_error:
|
|
return false;
|
|
}
|
|
|
|
static u32 vid_dec_set_cont_on_reconfig(struct video_client_ctx *client_ctx)
|
|
{
|
|
struct vcd_property_hdr vcd_property_hdr;
|
|
u32 vcd_status = VCD_ERR_FAIL;
|
|
u32 enable = true;
|
|
if (!client_ctx)
|
|
return false;
|
|
vcd_property_hdr.prop_id = VCD_I_CONT_ON_RECONFIG;
|
|
vcd_property_hdr.sz = sizeof(u32);
|
|
vcd_status = vcd_set_property(client_ctx->vcd_handle,
|
|
&vcd_property_hdr, &enable);
|
|
if (vcd_status)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
static u32 vid_dec_get_h264_mv_buffer_size(struct video_client_ctx *client_ctx,
|
|
struct vdec_mv_buff_size *mv_buff)
|
|
{
|
|
struct vcd_property_hdr vcd_property_hdr;
|
|
struct vcd_property_buffer_size h264_mv_buffer_size;
|
|
u32 vcd_status = VCD_ERR_FAIL;
|
|
|
|
if (!client_ctx || !mv_buff)
|
|
return false;
|
|
|
|
vcd_property_hdr.prop_id = VCD_I_GET_H264_MV_SIZE;
|
|
vcd_property_hdr.sz = sizeof(struct vcd_property_buffer_size);
|
|
|
|
h264_mv_buffer_size.width = mv_buff->width;
|
|
h264_mv_buffer_size.height = mv_buff->height;
|
|
|
|
vcd_status = vcd_get_property(client_ctx->vcd_handle,
|
|
&vcd_property_hdr, &h264_mv_buffer_size);
|
|
|
|
mv_buff->width = h264_mv_buffer_size.width;
|
|
mv_buff->height = h264_mv_buffer_size.height;
|
|
mv_buff->size = h264_mv_buffer_size.size;
|
|
mv_buff->alignment = h264_mv_buffer_size.alignment;
|
|
|
|
if (vcd_status)
|
|
return false;
|
|
else
|
|
return true;
|
|
}
|
|
|
|
static u32 vid_dec_free_meta_buffers(struct video_client_ctx *client_ctx)
|
|
{
|
|
struct vcd_property_hdr vcd_property_hdr;
|
|
struct vcd_property_buffer_size meta_buffer_size;
|
|
u32 vcd_status = VCD_ERR_FAIL;
|
|
|
|
if (!client_ctx)
|
|
return false;
|
|
|
|
vcd_property_hdr.prop_id = VCD_I_FREE_EXT_METABUFFER;
|
|
vcd_property_hdr.sz = sizeof(struct vcd_property_buffer_size);
|
|
|
|
vcd_status = vcd_set_property(client_ctx->vcd_handle,
|
|
&vcd_property_hdr, &meta_buffer_size);
|
|
|
|
if (!IS_ERR_OR_NULL(client_ctx->meta_buffer_ion_handle)) {
|
|
ion_unmap_kernel(client_ctx->user_ion_client,
|
|
client_ctx->meta_buffer_ion_handle);
|
|
if (!res_trk_check_for_sec_session() &&
|
|
(res_trk_get_core_type() != (u32)VCD_CORE_720P)) {
|
|
ion_unmap_iommu(client_ctx->user_ion_client,
|
|
client_ctx->meta_buffer_ion_handle,
|
|
VIDEO_DOMAIN,
|
|
VIDEO_MAIN_POOL);
|
|
}
|
|
ion_free(client_ctx->user_ion_client,
|
|
client_ctx->meta_buffer_ion_handle);
|
|
client_ctx->meta_buffer_ion_handle = NULL;
|
|
}
|
|
|
|
if (!IS_ERR_OR_NULL(client_ctx->meta_buffer_iommu_ion_handle)) {
|
|
ion_unmap_kernel(client_ctx->user_ion_client,
|
|
client_ctx->meta_buffer_iommu_ion_handle);
|
|
if (res_trk_check_for_sec_session() &&
|
|
(res_trk_get_core_type() != (u32)VCD_CORE_720P)) {
|
|
ion_unmap_iommu(client_ctx->user_ion_client,
|
|
client_ctx->meta_buffer_iommu_ion_handle,
|
|
VIDEO_DOMAIN,
|
|
VIDEO_MAIN_POOL);
|
|
}
|
|
ion_free(client_ctx->user_ion_client,
|
|
client_ctx->meta_buffer_iommu_ion_handle);
|
|
client_ctx->meta_buffer_iommu_ion_handle = NULL;
|
|
}
|
|
|
|
if (vcd_status)
|
|
return false;
|
|
else
|
|
return true;
|
|
}
|
|
|
|
|
|
static u32 vid_dec_free_h264_mv_buffers(struct video_client_ctx *client_ctx)
|
|
{
|
|
struct vcd_property_hdr vcd_property_hdr;
|
|
struct vcd_property_buffer_size h264_mv_buffer_size;
|
|
u32 vcd_status = VCD_ERR_FAIL;
|
|
|
|
if (!client_ctx)
|
|
return false;
|
|
|
|
vcd_property_hdr.prop_id = VCD_I_FREE_H264_MV_BUFFER;
|
|
vcd_property_hdr.sz = sizeof(struct vcd_property_buffer_size);
|
|
|
|
vcd_status = vcd_set_property(client_ctx->vcd_handle,
|
|
&vcd_property_hdr, &h264_mv_buffer_size);
|
|
|
|
if (!IS_ERR_OR_NULL(client_ctx->h264_mv_ion_handle)) {
|
|
ion_unmap_kernel(client_ctx->user_ion_client,
|
|
client_ctx->h264_mv_ion_handle);
|
|
if (!res_trk_check_for_sec_session() &&
|
|
(res_trk_get_core_type() != (u32)VCD_CORE_720P)) {
|
|
ion_unmap_iommu(client_ctx->user_ion_client,
|
|
client_ctx->h264_mv_ion_handle,
|
|
VIDEO_DOMAIN,
|
|
VIDEO_MAIN_POOL);
|
|
}
|
|
ion_free(client_ctx->user_ion_client,
|
|
client_ctx->h264_mv_ion_handle);
|
|
client_ctx->h264_mv_ion_handle = NULL;
|
|
}
|
|
|
|
if (vcd_status)
|
|
return false;
|
|
else
|
|
return true;
|
|
}
|
|
|
|
static u32 vid_dec_get_buffer_req(struct video_client_ctx *client_ctx,
|
|
struct vdec_allocatorproperty *vdec_buf_req)
|
|
{
|
|
u32 vcd_status = VCD_ERR_FAIL;
|
|
struct vcd_buffer_requirement vcd_buf_req;
|
|
|
|
if (!client_ctx || !vdec_buf_req)
|
|
return false;
|
|
|
|
if (vdec_buf_req->buffer_type == VDEC_BUFFER_TYPE_INPUT) {
|
|
vcd_status = vcd_get_buffer_requirements(client_ctx->vcd_handle,
|
|
VCD_BUFFER_INPUT,
|
|
&vcd_buf_req);
|
|
} else {
|
|
vcd_status = vcd_get_buffer_requirements(client_ctx->vcd_handle,
|
|
VCD_BUFFER_OUTPUT,
|
|
&vcd_buf_req);
|
|
}
|
|
|
|
if (vcd_status) {
|
|
return false;
|
|
} else {
|
|
vdec_buf_req->mincount = vcd_buf_req.min_count;
|
|
vdec_buf_req->maxcount = vcd_buf_req.max_count;
|
|
vdec_buf_req->actualcount = vcd_buf_req.actual_count;
|
|
vdec_buf_req->buffer_size = vcd_buf_req.sz;
|
|
vdec_buf_req->alignment = vcd_buf_req.align;
|
|
vdec_buf_req->buf_poolid = vcd_buf_req.buf_pool_id;
|
|
vdec_buf_req->meta_buffer_size = vcd_buf_req.meta_buffer_size;
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
static u32 vid_dec_set_buffer(struct video_client_ctx *client_ctx,
|
|
struct vdec_setbuffer_cmd *buffer_info)
|
|
{
|
|
enum vcd_buffer_type buffer = VCD_BUFFER_INPUT;
|
|
enum buffer_dir dir_buffer = BUFFER_TYPE_INPUT;
|
|
u32 vcd_status = VCD_ERR_FAIL;
|
|
unsigned long kernel_vaddr, buf_adr_offset = 0, length;
|
|
|
|
if (!client_ctx || !buffer_info)
|
|
return false;
|
|
|
|
if (buffer_info->buffer_type == VDEC_BUFFER_TYPE_OUTPUT) {
|
|
dir_buffer = BUFFER_TYPE_OUTPUT;
|
|
buffer = VCD_BUFFER_OUTPUT;
|
|
buf_adr_offset = (unsigned long)buffer_info->buffer.offset;
|
|
}
|
|
length = buffer_info->buffer.buffer_len;
|
|
/*If buffer cannot be set, ignore */
|
|
if (!vidc_insert_addr_table(client_ctx, dir_buffer,
|
|
(unsigned long)buffer_info->buffer.bufferaddr,
|
|
&kernel_vaddr, buffer_info->buffer.pmem_fd,
|
|
buf_adr_offset, MAX_VIDEO_NUM_OF_BUFF, length)) {
|
|
DBG("%s() : user_virt_addr = %p cannot be set.",
|
|
__func__, buffer_info->buffer.bufferaddr);
|
|
return false;
|
|
}
|
|
vcd_status = vcd_set_buffer(client_ctx->vcd_handle,
|
|
buffer, (u8 *) kernel_vaddr,
|
|
buffer_info->buffer.buffer_len);
|
|
|
|
if (!vcd_status)
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
|
|
static u32 vid_dec_free_buffer(struct video_client_ctx *client_ctx,
|
|
struct vdec_setbuffer_cmd *buffer_info)
|
|
{
|
|
enum vcd_buffer_type buffer = VCD_BUFFER_INPUT;
|
|
enum buffer_dir dir_buffer = BUFFER_TYPE_INPUT;
|
|
u32 vcd_status = VCD_ERR_FAIL;
|
|
unsigned long kernel_vaddr;
|
|
|
|
if (!client_ctx || !buffer_info)
|
|
return false;
|
|
|
|
if (buffer_info->buffer_type == VDEC_BUFFER_TYPE_OUTPUT) {
|
|
dir_buffer = BUFFER_TYPE_OUTPUT;
|
|
buffer = VCD_BUFFER_OUTPUT;
|
|
}
|
|
|
|
/*If buffer NOT set, ignore */
|
|
if (!vidc_delete_addr_table(client_ctx, dir_buffer,
|
|
(unsigned long)buffer_info->buffer.bufferaddr,
|
|
&kernel_vaddr)) {
|
|
DBG("%s() : user_virt_addr = %p has not been set.",
|
|
__func__, buffer_info->buffer.bufferaddr);
|
|
return true;
|
|
}
|
|
vcd_status = vcd_free_buffer(client_ctx->vcd_handle, buffer,
|
|
(u8 *)kernel_vaddr);
|
|
|
|
if (!vcd_status)
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
static u32 vid_dec_pause_resume(struct video_client_ctx *client_ctx, u32 pause)
|
|
{
|
|
u32 vcd_status;
|
|
|
|
if (!client_ctx) {
|
|
ERR("\n %s(): Invalid client_ctx", __func__);
|
|
return false;
|
|
}
|
|
|
|
if (pause) {
|
|
DBG("msm_vidc_dec: PAUSE command from client = %p\n",
|
|
client_ctx);
|
|
vcd_status = vcd_pause(client_ctx->vcd_handle);
|
|
} else{
|
|
DBG("msm_vidc_dec: RESUME command from client = %p\n",
|
|
client_ctx);
|
|
vcd_status = vcd_resume(client_ctx->vcd_handle);
|
|
}
|
|
|
|
if (vcd_status)
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
static u32 vid_dec_start_stop(struct video_client_ctx *client_ctx, u32 start)
|
|
{
|
|
struct vid_dec_msg *vdec_msg = NULL;
|
|
u32 vcd_status;
|
|
|
|
DBG("msm_vidc_dec: Inside %s()", __func__);
|
|
if (!client_ctx) {
|
|
ERR("\n Invalid client_ctx");
|
|
return false;
|
|
}
|
|
|
|
if (start) {
|
|
if (client_ctx->seq_header_set) {
|
|
DBG("%s(): Seq Hdr set: Send START_DONE to client",
|
|
__func__);
|
|
vdec_msg = kzalloc(sizeof(*vdec_msg), GFP_KERNEL);
|
|
if (!vdec_msg) {
|
|
ERR("vid_dec_start_stop: cannot allocate"
|
|
"buffer\n");
|
|
return false;
|
|
}
|
|
vdec_msg->vdec_msg_info.msgcode =
|
|
VDEC_MSG_RESP_START_DONE;
|
|
vdec_msg->vdec_msg_info.status_code = VDEC_S_SUCCESS;
|
|
vdec_msg->vdec_msg_info.msgdatasize = 0;
|
|
mutex_lock(&client_ctx->msg_queue_lock);
|
|
list_add_tail(&vdec_msg->list, &client_ctx->msg_queue);
|
|
mutex_unlock(&client_ctx->msg_queue_lock);
|
|
|
|
wake_up(&client_ctx->msg_wait);
|
|
|
|
DBG("Send START_DONE message to client = %p\n",
|
|
client_ctx);
|
|
|
|
} else {
|
|
DBG("%s(): Calling decode_start()", __func__);
|
|
vcd_status =
|
|
vcd_decode_start(client_ctx->vcd_handle, NULL);
|
|
|
|
if (vcd_status) {
|
|
ERR("%s(): vcd_decode_start failed."
|
|
" vcd_status = %u\n", __func__, vcd_status);
|
|
return false;
|
|
}
|
|
}
|
|
} else {
|
|
DBG("%s(): Calling vcd_stop()", __func__);
|
|
mutex_lock(&vid_dec_device_p->lock);
|
|
vcd_status = VCD_ERR_FAIL;
|
|
if (!client_ctx->stop_called) {
|
|
client_ctx->stop_called = true;
|
|
vcd_status = vcd_stop(client_ctx->vcd_handle);
|
|
}
|
|
if (vcd_status) {
|
|
ERR("%s(): vcd_stop failed. vcd_status = %u\n",
|
|
__func__, vcd_status);
|
|
mutex_unlock(&vid_dec_device_p->lock);
|
|
return false;
|
|
}
|
|
DBG("Send STOP_DONE message to client = %p\n", client_ctx);
|
|
mutex_unlock(&vid_dec_device_p->lock);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static u32 vid_dec_decode_frame(struct video_client_ctx *client_ctx,
|
|
struct vdec_input_frameinfo *input_frame_info,
|
|
u8 *desc_buf, u32 desc_size)
|
|
{
|
|
struct vcd_frame_data vcd_input_buffer;
|
|
unsigned long kernel_vaddr, phy_addr, user_vaddr;
|
|
int pmem_fd;
|
|
struct file *file;
|
|
s32 buffer_index = -1;
|
|
u32 vcd_status = VCD_ERR_FAIL;
|
|
u32 ion_flag = 0;
|
|
struct ion_handle *buff_handle = NULL;
|
|
|
|
if (!client_ctx || !input_frame_info)
|
|
return false;
|
|
|
|
user_vaddr = (unsigned long)input_frame_info->bufferaddr;
|
|
|
|
if (vidc_lookup_addr_table(client_ctx, BUFFER_TYPE_INPUT,
|
|
true, &user_vaddr, &kernel_vaddr,
|
|
&phy_addr, &pmem_fd, &file,
|
|
&buffer_index)) {
|
|
|
|
/* kernel_vaddr is found. send the frame to VCD */
|
|
memset((void *)&vcd_input_buffer, 0,
|
|
sizeof(struct vcd_frame_data));
|
|
vcd_input_buffer.virtual =
|
|
(u8 *) (kernel_vaddr + input_frame_info->pmem_offset);
|
|
vcd_input_buffer.offset = input_frame_info->offset;
|
|
vcd_input_buffer.frm_clnt_data =
|
|
(u32) input_frame_info->client_data;
|
|
vcd_input_buffer.ip_frm_tag =
|
|
(u32) input_frame_info->client_data;
|
|
vcd_input_buffer.data_len = input_frame_info->datalen;
|
|
vcd_input_buffer.time_stamp = input_frame_info->timestamp;
|
|
/* Rely on VCD using the same flags as OMX */
|
|
vcd_input_buffer.flags = input_frame_info->flags;
|
|
vcd_input_buffer.desc_buf = desc_buf;
|
|
vcd_input_buffer.desc_size = desc_size;
|
|
if (vcd_input_buffer.data_len > 0) {
|
|
ion_flag = vidc_get_fd_info(client_ctx,
|
|
BUFFER_TYPE_INPUT,
|
|
pmem_fd,
|
|
kernel_vaddr,
|
|
buffer_index,
|
|
&buff_handle);
|
|
if (ion_flag == ION_FLAG_CACHED && buff_handle) {
|
|
msm_ion_do_cache_op(client_ctx->user_ion_client,
|
|
buff_handle,
|
|
(unsigned long *)kernel_vaddr,
|
|
(unsigned long) vcd_input_buffer.data_len,
|
|
ION_IOC_CLEAN_CACHES);
|
|
}
|
|
}
|
|
vcd_status = vcd_decode_frame(client_ctx->vcd_handle,
|
|
&vcd_input_buffer);
|
|
if (!vcd_status)
|
|
return true;
|
|
else {
|
|
ERR("%s(): vcd_decode_frame failed = %u\n", __func__,
|
|
vcd_status);
|
|
return false;
|
|
}
|
|
|
|
} else {
|
|
ERR("%s(): kernel_vaddr not found\n", __func__);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static u32 vid_dec_fill_output_buffer(struct video_client_ctx *client_ctx,
|
|
struct vdec_fillbuffer_cmd *fill_buffer_cmd)
|
|
{
|
|
unsigned long kernel_vaddr, phy_addr, user_vaddr;
|
|
int pmem_fd;
|
|
struct file *file;
|
|
s32 buffer_index = -1;
|
|
u32 vcd_status = VCD_ERR_FAIL;
|
|
struct ion_handle *buff_handle = NULL;
|
|
|
|
struct vcd_frame_data vcd_frame;
|
|
|
|
if (!client_ctx || !fill_buffer_cmd)
|
|
return false;
|
|
|
|
user_vaddr = (unsigned long)fill_buffer_cmd->buffer.bufferaddr;
|
|
|
|
if (vidc_lookup_addr_table(client_ctx, BUFFER_TYPE_OUTPUT,
|
|
true, &user_vaddr, &kernel_vaddr,
|
|
&phy_addr, &pmem_fd, &file,
|
|
&buffer_index)) {
|
|
|
|
memset((void *)&vcd_frame, 0,
|
|
sizeof(struct vcd_frame_data));
|
|
vcd_frame.virtual = (u8 *) kernel_vaddr;
|
|
vcd_frame.frm_clnt_data = (u32) fill_buffer_cmd->client_data;
|
|
vcd_frame.alloc_len = fill_buffer_cmd->buffer.buffer_len;
|
|
vcd_frame.ion_flag = vidc_get_fd_info(client_ctx,
|
|
BUFFER_TYPE_OUTPUT,
|
|
pmem_fd, kernel_vaddr,
|
|
buffer_index,
|
|
&buff_handle);
|
|
vcd_frame.buff_ion_handle = buff_handle;
|
|
vcd_status = vcd_fill_output_buffer(client_ctx->vcd_handle,
|
|
&vcd_frame);
|
|
if (!vcd_status)
|
|
return true;
|
|
else {
|
|
ERR("%s(): vcd_fill_output_buffer failed = %u\n",
|
|
__func__, vcd_status);
|
|
return false;
|
|
}
|
|
} else {
|
|
ERR("%s(): kernel_vaddr not found\n", __func__);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
static u32 vid_dec_flush(struct video_client_ctx *client_ctx,
|
|
enum vdec_bufferflush flush_dir)
|
|
{
|
|
u32 vcd_status = VCD_ERR_FAIL;
|
|
|
|
DBG("msm_vidc_dec: %s() called with dir = %u", __func__,
|
|
flush_dir);
|
|
if (!client_ctx) {
|
|
ERR("\n Invalid client_ctx");
|
|
return false;
|
|
}
|
|
|
|
switch (flush_dir) {
|
|
case VDEC_FLUSH_TYPE_INPUT:
|
|
vcd_status = vcd_flush(client_ctx->vcd_handle, VCD_FLUSH_INPUT);
|
|
break;
|
|
case VDEC_FLUSH_TYPE_OUTPUT:
|
|
vcd_status = vcd_flush(client_ctx->vcd_handle,
|
|
VCD_FLUSH_OUTPUT);
|
|
break;
|
|
case VDEC_FLUSH_TYPE_ALL:
|
|
vcd_status = vcd_flush(client_ctx->vcd_handle, VCD_FLUSH_ALL);
|
|
break;
|
|
default:
|
|
ERR("%s(): Inavlid flush cmd. flush_dir = %u\n", __func__,
|
|
flush_dir);
|
|
return false;
|
|
break;
|
|
}
|
|
|
|
if (!vcd_status)
|
|
return true;
|
|
else {
|
|
ERR("%s(): vcd_flush failed. vcd_status = %u "
|
|
" flush_dir = %u\n", __func__, vcd_status, flush_dir);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static u32 vid_dec_msg_pending(struct video_client_ctx *client_ctx)
|
|
{
|
|
u32 islist_empty = 0;
|
|
mutex_lock(&client_ctx->msg_queue_lock);
|
|
islist_empty = list_empty(&client_ctx->msg_queue);
|
|
mutex_unlock(&client_ctx->msg_queue_lock);
|
|
|
|
if (islist_empty) {
|
|
DBG("%s(): vid_dec msg queue empty\n", __func__);
|
|
if (client_ctx->stop_msg) {
|
|
DBG("%s(): List empty and Stop Msg set\n",
|
|
__func__);
|
|
return client_ctx->stop_msg;
|
|
}
|
|
} else
|
|
DBG("%s(): vid_dec msg queue Not empty\n", __func__);
|
|
|
|
return !islist_empty;
|
|
}
|
|
|
|
static int vid_dec_get_next_msg(struct video_client_ctx *client_ctx,
|
|
struct vdec_msginfo *vdec_msg_info)
|
|
{
|
|
int rc;
|
|
struct vid_dec_msg *vid_dec_msg = NULL;
|
|
|
|
if (!client_ctx)
|
|
return false;
|
|
|
|
rc = wait_event_interruptible(client_ctx->msg_wait,
|
|
vid_dec_msg_pending(client_ctx));
|
|
if (rc < 0) {
|
|
DBG("rc = %d, stop_msg = %u\n", rc, client_ctx->stop_msg);
|
|
return rc;
|
|
} else if (client_ctx->stop_msg) {
|
|
DBG("rc = %d, stop_msg = %u\n", rc, client_ctx->stop_msg);
|
|
return -EIO;
|
|
}
|
|
|
|
mutex_lock(&client_ctx->msg_queue_lock);
|
|
if (!list_empty(&client_ctx->msg_queue)) {
|
|
DBG("%s(): After Wait\n", __func__);
|
|
vid_dec_msg = list_first_entry(&client_ctx->msg_queue,
|
|
struct vid_dec_msg, list);
|
|
list_del(&vid_dec_msg->list);
|
|
memcpy(vdec_msg_info, &vid_dec_msg->vdec_msg_info,
|
|
sizeof(struct vdec_msginfo));
|
|
kfree(vid_dec_msg);
|
|
}
|
|
mutex_unlock(&client_ctx->msg_queue_lock);
|
|
return 0;
|
|
}
|
|
|
|
static long vid_dec_ioctl(struct file *file,
|
|
unsigned cmd, unsigned long u_arg)
|
|
{
|
|
struct video_client_ctx *client_ctx = NULL;
|
|
struct vdec_ioctl_msg vdec_msg;
|
|
u32 vcd_status;
|
|
unsigned long kernel_vaddr, phy_addr, len;
|
|
unsigned long ker_vaddr;
|
|
u32 result = true;
|
|
void __user *arg = (void __user *)u_arg;
|
|
int rc = 0;
|
|
size_t ion_len;
|
|
|
|
DBG("%s\n", __func__);
|
|
if (_IOC_TYPE(cmd) != VDEC_IOCTL_MAGIC)
|
|
return -ENOTTY;
|
|
|
|
client_ctx = (struct video_client_ctx *)file->private_data;
|
|
if (!client_ctx) {
|
|
ERR("!client_ctx. Cannot attach to device handle\n");
|
|
return -ENODEV;
|
|
}
|
|
|
|
switch (cmd) {
|
|
case VDEC_IOCTL_SET_CODEC:
|
|
{
|
|
enum vdec_codec vdec_codec;
|
|
DBG("VDEC_IOCTL_SET_CODEC\n");
|
|
if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
|
|
return -EFAULT;
|
|
if (copy_from_user(&vdec_codec, vdec_msg.in,
|
|
sizeof(vdec_codec)))
|
|
return -EFAULT;
|
|
DBG("setting code type = %u\n", vdec_codec);
|
|
result = vid_dec_set_codec(client_ctx, &vdec_codec);
|
|
if (!result)
|
|
return -EIO;
|
|
break;
|
|
}
|
|
case VDEC_IOCTL_SET_OUTPUT_FORMAT:
|
|
{
|
|
enum vdec_output_fromat output_format;
|
|
DBG("VDEC_IOCTL_SET_OUTPUT_FORMAT\n");
|
|
if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
|
|
return -EFAULT;
|
|
if (copy_from_user(&output_format, vdec_msg.in,
|
|
sizeof(output_format)))
|
|
return -EFAULT;
|
|
|
|
result = vid_dec_set_output_format(client_ctx, &output_format);
|
|
|
|
if (!result)
|
|
return -EIO;
|
|
break;
|
|
}
|
|
case VDEC_IOCTL_SET_PICRES:
|
|
{
|
|
struct vdec_picsize video_resoultion;
|
|
DBG("VDEC_IOCTL_SET_PICRES\n");
|
|
if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
|
|
return -EFAULT;
|
|
if (copy_from_user(&video_resoultion, vdec_msg.in,
|
|
sizeof(video_resoultion)))
|
|
return -EFAULT;
|
|
result =
|
|
vid_dec_set_frame_resolution(client_ctx, &video_resoultion);
|
|
if (!result)
|
|
return -EIO;
|
|
break;
|
|
}
|
|
case VDEC_IOCTL_GET_PICRES:
|
|
{
|
|
struct vdec_picsize video_resoultion;
|
|
DBG("VDEC_IOCTL_GET_PICRES\n");
|
|
if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
|
|
return -EFAULT;
|
|
if (copy_from_user(&video_resoultion, vdec_msg.out,
|
|
sizeof(video_resoultion)))
|
|
return -EFAULT;
|
|
|
|
result = vid_dec_get_frame_resolution(client_ctx,
|
|
&video_resoultion);
|
|
|
|
if (result) {
|
|
if (copy_to_user(vdec_msg.out, &video_resoultion,
|
|
sizeof(video_resoultion)))
|
|
return -EFAULT;
|
|
} else
|
|
return -EIO;
|
|
break;
|
|
}
|
|
case VDEC_IOCTL_SET_BUFFER_REQ:
|
|
{
|
|
struct vdec_allocatorproperty vdec_buf_req;
|
|
struct vcd_buffer_requirement buffer_req;
|
|
DBG("VDEC_IOCTL_SET_BUFFER_REQ\n");
|
|
if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
|
|
return -EFAULT;
|
|
|
|
if (copy_from_user(&vdec_buf_req, vdec_msg.in,
|
|
sizeof(vdec_buf_req)))
|
|
return -EFAULT;
|
|
|
|
buffer_req.actual_count = vdec_buf_req.actualcount;
|
|
buffer_req.align = vdec_buf_req.alignment;
|
|
buffer_req.max_count = vdec_buf_req.maxcount;
|
|
buffer_req.min_count = vdec_buf_req.mincount;
|
|
buffer_req.sz = vdec_buf_req.buffer_size;
|
|
|
|
switch (vdec_buf_req.buffer_type) {
|
|
case VDEC_BUFFER_TYPE_INPUT:
|
|
vcd_status =
|
|
vcd_set_buffer_requirements(client_ctx->vcd_handle,
|
|
VCD_BUFFER_INPUT, &buffer_req);
|
|
break;
|
|
case VDEC_BUFFER_TYPE_OUTPUT:
|
|
vcd_status =
|
|
vcd_set_buffer_requirements(client_ctx->vcd_handle,
|
|
VCD_BUFFER_OUTPUT, &buffer_req);
|
|
break;
|
|
default:
|
|
vcd_status = VCD_ERR_BAD_POINTER;
|
|
break;
|
|
}
|
|
|
|
if (vcd_status)
|
|
return -EFAULT;
|
|
break;
|
|
}
|
|
case VDEC_IOCTL_GET_BUFFER_REQ:
|
|
{
|
|
struct vdec_allocatorproperty vdec_buf_req;
|
|
DBG("VDEC_IOCTL_GET_BUFFER_REQ\n");
|
|
if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
|
|
return -EFAULT;
|
|
if (copy_from_user(&vdec_buf_req, vdec_msg.out,
|
|
sizeof(vdec_buf_req)))
|
|
return -EFAULT;
|
|
|
|
result = vid_dec_get_buffer_req(client_ctx, &vdec_buf_req);
|
|
|
|
if (result) {
|
|
if (copy_to_user(vdec_msg.out, &vdec_buf_req,
|
|
sizeof(vdec_buf_req)))
|
|
return -EFAULT;
|
|
} else
|
|
return -EIO;
|
|
break;
|
|
}
|
|
case VDEC_IOCTL_SET_BUFFER:
|
|
{
|
|
struct vdec_setbuffer_cmd setbuffer;
|
|
DBG("VDEC_IOCTL_SET_BUFFER\n");
|
|
if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
|
|
return -EFAULT;
|
|
if (copy_from_user(&setbuffer, vdec_msg.in,
|
|
sizeof(setbuffer)))
|
|
return -EFAULT;
|
|
result = vid_dec_set_buffer(client_ctx, &setbuffer);
|
|
if (!result)
|
|
return -EIO;
|
|
break;
|
|
}
|
|
case VDEC_IOCTL_FREE_BUFFER:
|
|
{
|
|
struct vdec_setbuffer_cmd setbuffer;
|
|
DBG("VDEC_IOCTL_FREE_BUFFER\n");
|
|
if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
|
|
return -EFAULT;
|
|
if (copy_from_user(&setbuffer, vdec_msg.in,
|
|
sizeof(setbuffer)))
|
|
return -EFAULT;
|
|
result = vid_dec_free_buffer(client_ctx, &setbuffer);
|
|
if (!result)
|
|
return -EIO;
|
|
break;
|
|
}
|
|
case VDEC_IOCTL_CMD_START:
|
|
{
|
|
DBG(" VDEC_IOCTL_CMD_START\n");
|
|
result = vid_dec_start_stop(client_ctx, true);
|
|
if (!result)
|
|
return -EIO;
|
|
break;
|
|
}
|
|
case VDEC_IOCTL_CMD_STOP:
|
|
{
|
|
DBG("VDEC_IOCTL_CMD_STOP\n");
|
|
result = vid_dec_start_stop(client_ctx, false);
|
|
if (!result)
|
|
return -EIO;
|
|
break;
|
|
}
|
|
case VDEC_IOCTL_CMD_PAUSE:
|
|
{
|
|
result = vid_dec_pause_resume(client_ctx, true);
|
|
if (!result)
|
|
return -EIO;
|
|
break;
|
|
}
|
|
case VDEC_IOCTL_CMD_RESUME:
|
|
{
|
|
DBG("VDEC_IOCTL_CMD_PAUSE\n");
|
|
result = vid_dec_pause_resume(client_ctx, false);
|
|
|
|
if (!result)
|
|
return -EIO;
|
|
break;
|
|
}
|
|
case VDEC_IOCTL_DECODE_FRAME:
|
|
{
|
|
struct vdec_input_frameinfo input_frame_info;
|
|
u8 *desc_buf = NULL;
|
|
u32 desc_size = 0;
|
|
DBG("VDEC_IOCTL_DECODE_FRAME\n");
|
|
if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
|
|
return -EFAULT;
|
|
if (copy_from_user(&input_frame_info, vdec_msg.in,
|
|
sizeof(input_frame_info)))
|
|
return -EFAULT;
|
|
if (client_ctx->dmx_disable) {
|
|
if (input_frame_info.desc_addr) {
|
|
desc_size = input_frame_info.desc_size;
|
|
desc_buf = kzalloc(desc_size, GFP_KERNEL);
|
|
if (desc_buf) {
|
|
if (copy_from_user(desc_buf,
|
|
input_frame_info.desc_addr,
|
|
desc_size)) {
|
|
kfree(desc_buf);
|
|
desc_buf = NULL;
|
|
return -EFAULT;
|
|
}
|
|
}
|
|
} else
|
|
return -EINVAL;
|
|
}
|
|
result = vid_dec_decode_frame(client_ctx, &input_frame_info,
|
|
desc_buf, desc_size);
|
|
|
|
if (!result) {
|
|
kfree(desc_buf);
|
|
desc_buf = NULL;
|
|
return -EIO;
|
|
}
|
|
break;
|
|
}
|
|
case VDEC_IOCTL_SET_PERF_CLK:
|
|
{
|
|
vid_dec_set_turbo_clk(client_ctx);
|
|
break;
|
|
}
|
|
case VDEC_IOCTL_FILL_OUTPUT_BUFFER:
|
|
{
|
|
struct vdec_fillbuffer_cmd fill_buffer_cmd;
|
|
DBG("VDEC_IOCTL_FILL_OUTPUT_BUFFER\n");
|
|
if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
|
|
return -EFAULT;
|
|
if (copy_from_user(&fill_buffer_cmd, vdec_msg.in,
|
|
sizeof(fill_buffer_cmd)))
|
|
return -EFAULT;
|
|
result = vid_dec_fill_output_buffer(client_ctx,
|
|
&fill_buffer_cmd);
|
|
if (!result)
|
|
return -EIO;
|
|
break;
|
|
}
|
|
case VDEC_IOCTL_CMD_FLUSH:
|
|
{
|
|
enum vdec_bufferflush flush_dir;
|
|
DBG("VDEC_IOCTL_CMD_FLUSH\n");
|
|
if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
|
|
return -EFAULT;
|
|
if (copy_from_user(&flush_dir, vdec_msg.in,
|
|
sizeof(flush_dir)))
|
|
return -EFAULT;
|
|
result = vid_dec_flush(client_ctx, flush_dir);
|
|
if (!result)
|
|
return -EIO;
|
|
break;
|
|
}
|
|
case VDEC_IOCTL_GET_NEXT_MSG:
|
|
{
|
|
struct vdec_msginfo vdec_msg_info;
|
|
DBG("VDEC_IOCTL_GET_NEXT_MSG\n");
|
|
if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
|
|
return -EFAULT;
|
|
result = vid_dec_get_next_msg(client_ctx, &vdec_msg_info);
|
|
if (result)
|
|
return result;
|
|
if (copy_to_user(vdec_msg.out, &vdec_msg_info,
|
|
sizeof(vdec_msg_info)))
|
|
return -EFAULT;
|
|
break;
|
|
}
|
|
case VDEC_IOCTL_STOP_NEXT_MSG:
|
|
{
|
|
DBG("VDEC_IOCTL_STOP_NEXT_MSG\n");
|
|
client_ctx->stop_msg = 1;
|
|
wake_up(&client_ctx->msg_wait);
|
|
break;
|
|
}
|
|
case VDEC_IOCTL_SET_SEQUENCE_HEADER:
|
|
{
|
|
struct vdec_seqheader seq_header;
|
|
struct vcd_sequence_hdr vcd_seq_hdr;
|
|
unsigned long ionflag;
|
|
DBG("VDEC_IOCTL_SET_SEQUENCE_HEADER\n");
|
|
if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg))) {
|
|
ERR("Copy from user vdec_msg failed\n");
|
|
return -EFAULT;
|
|
}
|
|
if (copy_from_user(&seq_header, vdec_msg.in,
|
|
sizeof(seq_header))) {
|
|
ERR("Copy from user seq_header failed\n");
|
|
return -EFAULT;
|
|
}
|
|
if (!seq_header.seq_header_len) {
|
|
ERR("Seq Len is Zero\n");
|
|
return -EFAULT;
|
|
}
|
|
|
|
if (!vcd_get_ion_status()) {
|
|
pr_err("PMEM Not available\n");
|
|
return -EINVAL;
|
|
} else {
|
|
client_ctx->seq_hdr_ion_handle = ion_import_dma_buf(
|
|
client_ctx->user_ion_client,
|
|
seq_header.pmem_fd);
|
|
if (!client_ctx->seq_hdr_ion_handle) {
|
|
ERR("%s(): get_ION_handle failed\n", __func__);
|
|
return false;
|
|
}
|
|
rc = ion_handle_get_flags(client_ctx->user_ion_client,
|
|
client_ctx->seq_hdr_ion_handle,
|
|
&ionflag);
|
|
if (rc) {
|
|
ERR("%s():get_ION_flags fail\n",
|
|
__func__);
|
|
ion_free(client_ctx->user_ion_client,
|
|
client_ctx->seq_hdr_ion_handle);
|
|
return false;
|
|
}
|
|
ker_vaddr = (unsigned long) ion_map_kernel(
|
|
client_ctx->user_ion_client,
|
|
client_ctx->seq_hdr_ion_handle);
|
|
if (!ker_vaddr) {
|
|
ERR("%s():get_ION_kernel virtual addr fail\n",
|
|
__func__);
|
|
ion_free(client_ctx->user_ion_client,
|
|
client_ctx->seq_hdr_ion_handle);
|
|
return false;
|
|
}
|
|
kernel_vaddr = ker_vaddr;
|
|
rc = ion_phys(client_ctx->user_ion_client,
|
|
client_ctx->seq_hdr_ion_handle,
|
|
&phy_addr, &ion_len);
|
|
if (rc) {
|
|
ERR("%s():get_ION_kernel physical addr fail\n",
|
|
__func__);
|
|
ion_unmap_kernel(client_ctx->user_ion_client,
|
|
client_ctx->seq_hdr_ion_handle);
|
|
ion_free(client_ctx->user_ion_client,
|
|
client_ctx->seq_hdr_ion_handle);
|
|
return false;
|
|
}
|
|
len = ion_len;
|
|
}
|
|
vcd_seq_hdr.sequence_header_len = seq_header.seq_header_len;
|
|
kernel_vaddr += (unsigned long)seq_header.pmem_offset;
|
|
vcd_seq_hdr.sequence_header = (u8 *)kernel_vaddr;
|
|
if (!vcd_seq_hdr.sequence_header) {
|
|
ERR("Sequence Header pointer failed\n");
|
|
return -EFAULT;
|
|
}
|
|
client_ctx->seq_header_set = true;
|
|
if (vcd_decode_start(client_ctx->vcd_handle, &vcd_seq_hdr)) {
|
|
ERR("Decode start Failed\n");
|
|
client_ctx->seq_header_set = false;
|
|
return -EFAULT;
|
|
}
|
|
DBG("Wait Client completion Sequence Header\n");
|
|
wait_for_completion(&client_ctx->event);
|
|
vcd_seq_hdr.sequence_header = NULL;
|
|
if (client_ctx->event_status) {
|
|
ERR("Set Seq Header status is failed");
|
|
return -EFAULT;
|
|
}
|
|
if (vcd_get_ion_status()) {
|
|
if (client_ctx->seq_hdr_ion_handle) {
|
|
ion_unmap_kernel(client_ctx->user_ion_client,
|
|
client_ctx->seq_hdr_ion_handle);
|
|
ion_free(client_ctx->user_ion_client,
|
|
client_ctx->seq_hdr_ion_handle);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case VDEC_IOCTL_GET_NUMBER_INSTANCES:
|
|
{
|
|
DBG("VDEC_IOCTL_GET_NUMBER_INSTANCES\n");
|
|
if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
|
|
return -EFAULT;
|
|
if (copy_to_user(vdec_msg.out,
|
|
&vid_dec_device_p->num_clients, sizeof(u32)))
|
|
return -EFAULT;
|
|
break;
|
|
}
|
|
case VDEC_IOCTL_GET_INTERLACE_FORMAT:
|
|
{
|
|
u32 progressive_only, interlace_format;
|
|
DBG("VDEC_IOCTL_GET_INTERLACE_FORMAT\n");
|
|
if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
|
|
return -EFAULT;
|
|
result = vid_dec_get_progressive_only(client_ctx,
|
|
&progressive_only);
|
|
if (result) {
|
|
interlace_format = progressive_only ?
|
|
VDEC_InterlaceFrameProgressive :
|
|
VDEC_InterlaceInterleaveFrameTopFieldFirst;
|
|
if (copy_to_user(vdec_msg.out, &interlace_format,
|
|
sizeof(u32)))
|
|
return -EFAULT;
|
|
} else
|
|
return -EIO;
|
|
break;
|
|
}
|
|
|
|
case VDEC_IOCTL_GET_DISABLE_DMX_SUPPORT:
|
|
{
|
|
u32 disable_dmx;
|
|
DBG("VDEC_IOCTL_GET_DISABLE_DMX_SUPPORT\n");
|
|
if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
|
|
return -EFAULT;
|
|
result = vid_dec_get_disable_dmx_support(client_ctx,
|
|
&disable_dmx);
|
|
if (result) {
|
|
if (copy_to_user(vdec_msg.out, &disable_dmx,
|
|
sizeof(u32)))
|
|
return -EFAULT;
|
|
} else
|
|
return -EIO;
|
|
break;
|
|
}
|
|
case VDEC_IOCTL_GET_DISABLE_DMX:
|
|
{
|
|
u32 disable_dmx;
|
|
DBG("VDEC_IOCTL_GET_DISABLE_DMX\n");
|
|
if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
|
|
return -EFAULT;
|
|
result = vid_dec_get_disable_dmx(client_ctx,
|
|
&disable_dmx);
|
|
if (result) {
|
|
if (copy_to_user(vdec_msg.out, &disable_dmx,
|
|
sizeof(u32)))
|
|
return -EFAULT;
|
|
} else
|
|
return -EIO;
|
|
break;
|
|
}
|
|
case VDEC_IOCTL_SET_DISABLE_DMX:
|
|
{
|
|
DBG("VDEC_IOCTL_SET_DISABLE_DMX\n");
|
|
result = vid_dec_set_disable_dmx(client_ctx);
|
|
if (!result)
|
|
return -EIO;
|
|
client_ctx->dmx_disable = 1;
|
|
break;
|
|
}
|
|
case VDEC_IOCTL_SET_PICTURE_ORDER:
|
|
{
|
|
u32 picture_order;
|
|
DBG("VDEC_IOCTL_SET_PICTURE_ORDER\n");
|
|
if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
|
|
return -EFAULT;
|
|
if (copy_from_user(&picture_order, vdec_msg.in,
|
|
sizeof(u32)))
|
|
return -EFAULT;
|
|
result = vid_dec_set_picture_order(client_ctx, &picture_order);
|
|
if (!result)
|
|
return -EIO;
|
|
break;
|
|
}
|
|
case VDEC_IOCTL_SET_FRAME_RATE:
|
|
{
|
|
struct vdec_framerate frame_rate;
|
|
DBG("VDEC_IOCTL_SET_FRAME_RATE\n");
|
|
if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
|
|
return -EFAULT;
|
|
if (copy_from_user(&frame_rate, vdec_msg.in,
|
|
sizeof(frame_rate)))
|
|
return -EFAULT;
|
|
result = vid_dec_set_frame_rate(client_ctx, &frame_rate);
|
|
if (!result)
|
|
return -EIO;
|
|
break;
|
|
}
|
|
case VDEC_IOCTL_SET_EXTRADATA:
|
|
{
|
|
u32 extradata_flag;
|
|
DBG("VDEC_IOCTL_SET_EXTRADATA\n");
|
|
if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
|
|
return -EFAULT;
|
|
if (copy_from_user(&extradata_flag, vdec_msg.in,
|
|
sizeof(u32)))
|
|
return -EFAULT;
|
|
result = vid_dec_set_extradata(client_ctx, &extradata_flag);
|
|
if (!result)
|
|
return -EIO;
|
|
break;
|
|
}
|
|
case VDEC_IOCTL_SET_META_BUFFERS:
|
|
{
|
|
struct vdec_meta_buffers meta_buffers;
|
|
DBG("VDEC_IOCTL_SET_META_BUFFERS\n");
|
|
if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
|
|
return -EFAULT;
|
|
if (copy_from_user(&meta_buffers, vdec_msg.in,
|
|
sizeof(meta_buffers)))
|
|
return -EFAULT;
|
|
result = vid_dec_set_meta_buffers(client_ctx, &meta_buffers);
|
|
|
|
if (!result)
|
|
return -EIO;
|
|
break;
|
|
}
|
|
case VDEC_IOCTL_FREE_META_BUFFERS:
|
|
{
|
|
DBG("VDEC_IOCTL_FREE_META_BUFFERS\n");
|
|
result = vid_dec_free_meta_buffers(client_ctx);
|
|
if (!result)
|
|
return -EIO;
|
|
break;
|
|
}
|
|
case VDEC_IOCTL_SET_H264_MV_BUFFER:
|
|
{
|
|
struct vdec_h264_mv mv_data;
|
|
DBG("VDEC_IOCTL_SET_H264_MV_BUFFER\n");
|
|
if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
|
|
return -EFAULT;
|
|
if (copy_from_user(&mv_data, vdec_msg.in,
|
|
sizeof(mv_data)))
|
|
return -EFAULT;
|
|
result = vid_dec_set_h264_mv_buffers(client_ctx, &mv_data);
|
|
|
|
if (!result)
|
|
return -EIO;
|
|
break;
|
|
}
|
|
case VDEC_IOCTL_FREE_H264_MV_BUFFER:
|
|
{
|
|
DBG("VDEC_IOCTL_FREE_H264_MV_BUFFER\n");
|
|
result = vid_dec_free_h264_mv_buffers(client_ctx);
|
|
if (!result)
|
|
return -EIO;
|
|
break;
|
|
}
|
|
case VDEC_IOCTL_GET_MV_BUFFER_SIZE:
|
|
{
|
|
struct vdec_mv_buff_size mv_buff;
|
|
DBG("VDEC_IOCTL_GET_MV_BUFFER_SIZE\n");
|
|
if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg)))
|
|
return -EFAULT;
|
|
if (copy_from_user(&mv_buff, vdec_msg.out,
|
|
sizeof(mv_buff)))
|
|
return -EFAULT;
|
|
result = vid_dec_get_h264_mv_buffer_size(client_ctx, &mv_buff);
|
|
if (result) {
|
|
DBG(" Returning W: %d, H: %d, S: %d, A: %d",
|
|
mv_buff.width, mv_buff.height,
|
|
mv_buff.size, mv_buff.alignment);
|
|
if (copy_to_user(vdec_msg.out, &mv_buff,
|
|
sizeof(mv_buff)))
|
|
return -EFAULT;
|
|
} else
|
|
return -EIO;
|
|
break;
|
|
}
|
|
case VDEC_IOCTL_SET_IDR_ONLY_DECODING:
|
|
{
|
|
result = vid_dec_set_idr_only_decoding(client_ctx);
|
|
if (!result)
|
|
return -EIO;
|
|
break;
|
|
}
|
|
case VDEC_IOCTL_SET_CONT_ON_RECONFIG:
|
|
{
|
|
result = vid_dec_set_cont_on_reconfig(client_ctx);
|
|
if (!result)
|
|
return -EIO;
|
|
break;
|
|
}
|
|
default:
|
|
ERR("%s(): Unsupported ioctl\n", __func__);
|
|
return -ENOTTY;
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static u32 vid_dec_close_client(struct video_client_ctx *client_ctx)
|
|
{
|
|
struct vid_dec_msg *vdec_msg;
|
|
u32 vcd_status;
|
|
|
|
DBG("msm_vidc_dec: Inside %s()", __func__);
|
|
if (!client_ctx || (!client_ctx->vcd_handle)) {
|
|
ERR("\n Invalid client_ctx");
|
|
return false;
|
|
}
|
|
|
|
mutex_lock(&vid_dec_device_p->lock);
|
|
if (!client_ctx->stop_called) {
|
|
client_ctx->stop_called = true;
|
|
client_ctx->stop_sync_cb = true;
|
|
vcd_status = vcd_stop(client_ctx->vcd_handle);
|
|
DBG("\n Stuck at the stop call");
|
|
if (!vcd_status)
|
|
wait_for_completion(&client_ctx->event);
|
|
DBG("\n Came out of wait event");
|
|
}
|
|
mutex_lock(&client_ctx->msg_queue_lock);
|
|
while (!list_empty(&client_ctx->msg_queue)) {
|
|
DBG("%s(): Delete remaining entries\n", __func__);
|
|
vdec_msg = list_first_entry(&client_ctx->msg_queue,
|
|
struct vid_dec_msg, list);
|
|
if (vdec_msg) {
|
|
list_del(&vdec_msg->list);
|
|
kfree(vdec_msg);
|
|
}
|
|
}
|
|
mutex_unlock(&client_ctx->msg_queue_lock);
|
|
vcd_status = vcd_close(client_ctx->vcd_handle);
|
|
|
|
client_ctx->user_ion_client = NULL;
|
|
memset((void *)client_ctx, 0, sizeof(struct video_client_ctx));
|
|
vid_dec_device_p->num_clients--;
|
|
mutex_unlock(&vid_dec_device_p->lock);
|
|
return true;
|
|
}
|
|
|
|
int vid_dec_open_client(struct video_client_ctx **vid_clnt_ctx, int flags)
|
|
{
|
|
int rc = 0;
|
|
s32 client_index;
|
|
struct video_client_ctx *client_ctx = NULL;
|
|
u8 client_count;
|
|
|
|
if (!vid_clnt_ctx) {
|
|
ERR("Invalid input\n");
|
|
return -EINVAL;
|
|
}
|
|
*vid_clnt_ctx = NULL;
|
|
client_count = vcd_get_num_of_clients();
|
|
if (client_count == VIDC_MAX_NUM_CLIENTS) {
|
|
ERR("ERROR : vid_dec_open() max number of clients"
|
|
"limit reached\n");
|
|
rc = -ENOMEM;
|
|
goto client_failure;
|
|
}
|
|
|
|
DBG(" Virtual Address of ioremap is %p\n", vid_dec_device_p->virt_base);
|
|
if (!vid_dec_device_p->num_clients) {
|
|
if (!vidc_load_firmware()) {
|
|
rc = -ENOMEM;
|
|
goto client_failure;
|
|
}
|
|
}
|
|
|
|
client_index = vid_dec_get_empty_client_index();
|
|
if (client_index < 0) {
|
|
ERR("%s() : No free clients client_index == -1\n", __func__);
|
|
rc = -ENOMEM;
|
|
goto client_failure;
|
|
}
|
|
client_ctx = &vid_dec_device_p->vdec_clients[client_index];
|
|
vid_dec_device_p->num_clients++;
|
|
init_completion(&client_ctx->event);
|
|
mutex_init(&client_ctx->msg_queue_lock);
|
|
mutex_init(&client_ctx->enrty_queue_lock);
|
|
INIT_LIST_HEAD(&client_ctx->msg_queue);
|
|
init_waitqueue_head(&client_ctx->msg_wait);
|
|
client_ctx->stop_msg = 0;
|
|
client_ctx->stop_called = false;
|
|
client_ctx->stop_sync_cb = false;
|
|
client_ctx->dmx_disable = 0;
|
|
if (vcd_get_ion_status()) {
|
|
client_ctx->user_ion_client = vcd_get_ion_client();
|
|
if (!client_ctx->user_ion_client) {
|
|
ERR("vcd_open ion client get failed");
|
|
rc = -ENOMEM;
|
|
goto client_failure;
|
|
}
|
|
}
|
|
rc = vcd_open(vid_dec_device_p->device_handle, true,
|
|
vid_dec_vcd_cb, client_ctx, flags);
|
|
if (!rc) {
|
|
wait_for_completion(&client_ctx->event);
|
|
if (client_ctx->event_status) {
|
|
ERR("callback for vcd_open returned error: %u",
|
|
client_ctx->event_status);
|
|
rc = -ENODEV;
|
|
goto client_failure;
|
|
}
|
|
} else {
|
|
ERR("vcd_open returned error: %u", rc);
|
|
goto client_failure;
|
|
}
|
|
client_ctx->seq_header_set = false;
|
|
*vid_clnt_ctx = client_ctx;
|
|
client_failure:
|
|
return rc;
|
|
}
|
|
|
|
static int vid_dec_open_secure(struct inode *inode, struct file *file)
|
|
{
|
|
int rc = 0;
|
|
struct video_client_ctx *client_ctx;
|
|
mutex_lock(&vid_dec_device_p->lock);
|
|
rc = vid_dec_open_client(&client_ctx, VCD_CP_SESSION);
|
|
if (rc)
|
|
goto error;
|
|
if (!client_ctx) {
|
|
rc = -ENOMEM;
|
|
goto error;
|
|
}
|
|
|
|
file->private_data = client_ctx;
|
|
if (res_trk_open_secure_session()) {
|
|
ERR("Secure session operation failure\n");
|
|
rc = -EACCES;
|
|
goto error;
|
|
}
|
|
mutex_unlock(&vid_dec_device_p->lock);
|
|
return 0;
|
|
error:
|
|
mutex_unlock(&vid_dec_device_p->lock);
|
|
return rc;
|
|
}
|
|
|
|
static int vid_dec_open(struct inode *inode, struct file *file)
|
|
{
|
|
int rc = 0;
|
|
struct video_client_ctx *client_ctx;
|
|
INFO("msm_vidc_dec: Inside %s()", __func__);
|
|
mutex_lock(&vid_dec_device_p->lock);
|
|
rc = vid_dec_open_client(&client_ctx, 0);
|
|
if (rc) {
|
|
mutex_unlock(&vid_dec_device_p->lock);
|
|
return rc;
|
|
}
|
|
if (!client_ctx) {
|
|
mutex_unlock(&vid_dec_device_p->lock);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
file->private_data = client_ctx;
|
|
mutex_unlock(&vid_dec_device_p->lock);
|
|
return rc;
|
|
}
|
|
|
|
static int vid_dec_release_secure(struct inode *inode, struct file *file)
|
|
{
|
|
struct video_client_ctx *client_ctx = file->private_data;
|
|
|
|
INFO("msm_vidc_dec: Inside %s()", __func__);
|
|
vidc_cleanup_addr_table(client_ctx, BUFFER_TYPE_OUTPUT);
|
|
vidc_cleanup_addr_table(client_ctx, BUFFER_TYPE_INPUT);
|
|
vid_dec_close_client(client_ctx);
|
|
vidc_release_firmware();
|
|
#ifndef USE_RES_TRACKER
|
|
vidc_disable_clk();
|
|
#endif
|
|
INFO("msm_vidc_dec: Return from %s()", __func__);
|
|
return 0;
|
|
}
|
|
|
|
static int vid_dec_release(struct inode *inode, struct file *file)
|
|
{
|
|
struct video_client_ctx *client_ctx = file->private_data;
|
|
|
|
INFO("msm_vidc_dec: Inside %s()", __func__);
|
|
vidc_cleanup_addr_table(client_ctx, BUFFER_TYPE_OUTPUT);
|
|
vidc_cleanup_addr_table(client_ctx, BUFFER_TYPE_INPUT);
|
|
vid_dec_close_client(client_ctx);
|
|
vidc_release_firmware();
|
|
#ifndef USE_RES_TRACKER
|
|
vidc_disable_clk();
|
|
#endif
|
|
INFO("msm_vidc_dec: Return from %s()", __func__);
|
|
return 0;
|
|
}
|
|
|
|
static const struct file_operations vid_dec_fops[2] = {
|
|
{
|
|
.owner = THIS_MODULE,
|
|
.open = vid_dec_open,
|
|
.release = vid_dec_release,
|
|
.unlocked_ioctl = vid_dec_ioctl,
|
|
},
|
|
{
|
|
.owner = THIS_MODULE,
|
|
.open = vid_dec_open_secure,
|
|
.release = vid_dec_release_secure,
|
|
.unlocked_ioctl = vid_dec_ioctl,
|
|
},
|
|
|
|
};
|
|
|
|
void vid_dec_interrupt_deregister(void)
|
|
{
|
|
}
|
|
|
|
void vid_dec_interrupt_register(void *device_name)
|
|
{
|
|
}
|
|
|
|
void vid_dec_interrupt_clear(void)
|
|
{
|
|
}
|
|
|
|
void *vid_dec_map_dev_base_addr(void *device_name)
|
|
{
|
|
return vid_dec_device_p->virt_base;
|
|
}
|
|
|
|
static int vid_dec_vcd_init(void)
|
|
{
|
|
int rc;
|
|
struct vcd_init_config vcd_init_config;
|
|
u32 i;
|
|
|
|
/* init_timer(&hw_timer); */
|
|
DBG("msm_vidc_dec: Inside %s()", __func__);
|
|
vid_dec_device_p->num_clients = 0;
|
|
|
|
for (i = 0; i < VIDC_MAX_NUM_CLIENTS; i++) {
|
|
memset((void *)&vid_dec_device_p->vdec_clients[i], 0,
|
|
sizeof(vid_dec_device_p->vdec_clients[i]));
|
|
}
|
|
|
|
mutex_init(&vid_dec_device_p->lock);
|
|
vid_dec_device_p->virt_base = vidc_get_ioaddr();
|
|
DBG("%s() : base address for VIDC core %u\n", __func__, \
|
|
(int)vid_dec_device_p->virt_base);
|
|
|
|
if (!vid_dec_device_p->virt_base) {
|
|
ERR("%s() : ioremap failed\n", __func__);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
vcd_init_config.device_name = "VIDC";
|
|
vcd_init_config.map_dev_base_addr = vid_dec_map_dev_base_addr;
|
|
vcd_init_config.interrupt_clr = vid_dec_interrupt_clear;
|
|
vcd_init_config.register_isr = vid_dec_interrupt_register;
|
|
vcd_init_config.deregister_isr = vid_dec_interrupt_deregister;
|
|
vcd_init_config.timer_create = vidc_timer_create;
|
|
vcd_init_config.timer_release = vidc_timer_release;
|
|
vcd_init_config.timer_start = vidc_timer_start;
|
|
vcd_init_config.timer_stop = vidc_timer_stop;
|
|
|
|
rc = vcd_init(&vcd_init_config, &vid_dec_device_p->device_handle);
|
|
|
|
if (rc) {
|
|
ERR("%s() : vcd_init failed\n", __func__);
|
|
return -ENODEV;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int __init vid_dec_init(void)
|
|
{
|
|
int rc = 0, i = 0, j = 0;
|
|
struct device *class_devp;
|
|
|
|
DBG("msm_vidc_dec: Inside %s()", __func__);
|
|
vid_dec_device_p = kzalloc(sizeof(struct vid_dec_dev), GFP_KERNEL);
|
|
if (!vid_dec_device_p) {
|
|
ERR("%s Unable to allocate memory for vid_dec_dev\n",
|
|
__func__);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
rc = alloc_chrdev_region(&vid_dec_dev_num, 0, NUM_OF_DRIVER_NODES,
|
|
VID_DEC_NAME);
|
|
if (rc < 0) {
|
|
ERR("%s: alloc_chrdev_region Failed rc = %d\n",
|
|
__func__, rc);
|
|
goto error_vid_dec_alloc_chrdev_region;
|
|
}
|
|
|
|
vid_dec_class = class_create(THIS_MODULE, VID_DEC_NAME);
|
|
if (IS_ERR(vid_dec_class)) {
|
|
rc = PTR_ERR(vid_dec_class);
|
|
ERR("%s: couldn't create vid_dec_class rc = %d\n",
|
|
__func__, rc);
|
|
|
|
goto error_vid_dec_class_create;
|
|
}
|
|
for (i = 0; i < NUM_OF_DRIVER_NODES; i++) {
|
|
class_devp = device_create(vid_dec_class, NULL,
|
|
(vid_dec_dev_num + i),
|
|
NULL, VID_DEC_NAME "%s",
|
|
node_name[i]);
|
|
|
|
if (IS_ERR(class_devp)) {
|
|
rc = PTR_ERR(class_devp);
|
|
ERR("%s: class device_create failed %d\n",
|
|
__func__, rc);
|
|
if (!i)
|
|
goto error_vid_dec_class_device_create;
|
|
else
|
|
goto error_vid_dec_cdev_add;
|
|
}
|
|
|
|
vid_dec_device_p->device[i] = class_devp;
|
|
|
|
cdev_init(&vid_dec_device_p->cdev[i], &vid_dec_fops[i]);
|
|
vid_dec_device_p->cdev[i].owner = THIS_MODULE;
|
|
rc = cdev_add(&(vid_dec_device_p->cdev[i]),
|
|
(vid_dec_dev_num+i), 1);
|
|
|
|
if (rc < 0) {
|
|
ERR("%s: cdev_add failed %d\n", __func__, rc);
|
|
goto error_vid_dec_cdev_add;
|
|
}
|
|
}
|
|
vid_dec_vcd_init();
|
|
return 0;
|
|
|
|
error_vid_dec_cdev_add:
|
|
for (j = i-1; j >= 0; j--)
|
|
cdev_del(&(vid_dec_device_p->cdev[j]));
|
|
device_destroy(vid_dec_class, vid_dec_dev_num);
|
|
error_vid_dec_class_device_create:
|
|
class_destroy(vid_dec_class);
|
|
error_vid_dec_class_create:
|
|
unregister_chrdev_region(vid_dec_dev_num, NUM_OF_DRIVER_NODES);
|
|
error_vid_dec_alloc_chrdev_region:
|
|
kfree(vid_dec_device_p);
|
|
return rc;
|
|
}
|
|
|
|
static void __exit vid_dec_exit(void)
|
|
{
|
|
int i = 0;
|
|
INFO("msm_vidc_dec: Inside %s()", __func__);
|
|
for (i = 0; i < NUM_OF_DRIVER_NODES; i++)
|
|
cdev_del(&(vid_dec_device_p->cdev[i]));
|
|
device_destroy(vid_dec_class, vid_dec_dev_num);
|
|
class_destroy(vid_dec_class);
|
|
unregister_chrdev_region(vid_dec_dev_num, NUM_OF_DRIVER_NODES);
|
|
kfree(vid_dec_device_p);
|
|
DBG("msm_vidc_dec: Return from %s()", __func__);
|
|
}
|
|
|
|
MODULE_LICENSE("GPL v2");
|
|
MODULE_DESCRIPTION("Video decoder driver");
|
|
MODULE_VERSION("1.0");
|
|
|
|
module_init(vid_dec_init);
|
|
module_exit(vid_dec_exit);
|