1930 lines
49 KiB
C
1930 lines
49 KiB
C
/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 and
|
|
* 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 <media/msm/vidc_type.h>
|
|
#include <media/msm/vcd_api.h>
|
|
#include <media/msm/vidc_init.h>
|
|
|
|
#include "venc_internal.h"
|
|
#include "vcd_res_tracker_api.h"
|
|
|
|
#define VID_ENC_NAME "msm_vidc_enc"
|
|
static char *node_name[2] = {"", "_sec"};
|
|
|
|
#if DEBUG
|
|
#define DBG(x...) printk(KERN_DEBUG x)
|
|
#else
|
|
#define DBG(x...)
|
|
#endif
|
|
|
|
#define INFO(x...) printk(KERN_INFO x)
|
|
#define ERR(x...) printk(KERN_ERR x)
|
|
|
|
static struct vid_enc_dev *vid_enc_device_p;
|
|
static dev_t vid_enc_dev_num;
|
|
static struct class *vid_enc_class;
|
|
static long vid_enc_ioctl(struct file *file,
|
|
unsigned cmd, unsigned long arg);
|
|
|
|
static s32 vid_enc_get_empty_client_index(void)
|
|
{
|
|
u32 i;
|
|
u32 found = false;
|
|
|
|
for (i = 0; i < VIDC_MAX_NUM_CLIENTS; i++) {
|
|
if (!vid_enc_device_p->venc_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_enc_get_status(u32 status)
|
|
{
|
|
u32 venc_status;
|
|
|
|
switch (status) {
|
|
case VCD_S_SUCCESS:
|
|
venc_status = VEN_S_SUCCESS;
|
|
break;
|
|
case VCD_ERR_FAIL:
|
|
venc_status = VEN_S_EFAIL;
|
|
break;
|
|
case VCD_ERR_ALLOC_FAIL:
|
|
venc_status = VEN_S_ENOSWRES;
|
|
break;
|
|
case VCD_ERR_ILLEGAL_OP:
|
|
venc_status = VEN_S_EINVALCMD;
|
|
break;
|
|
case VCD_ERR_ILLEGAL_PARM:
|
|
venc_status = VEN_S_EBADPARAM;
|
|
break;
|
|
case VCD_ERR_BAD_POINTER:
|
|
case VCD_ERR_BAD_HANDLE:
|
|
venc_status = VEN_S_EFATAL;
|
|
break;
|
|
case VCD_ERR_NOT_SUPPORTED:
|
|
venc_status = VEN_S_ENOTSUPP;
|
|
break;
|
|
case VCD_ERR_BAD_STATE:
|
|
venc_status = VEN_S_EINVALSTATE;
|
|
break;
|
|
case VCD_ERR_MAX_CLIENT:
|
|
venc_status = VEN_S_ENOHWRES;
|
|
break;
|
|
default:
|
|
venc_status = VEN_S_EFAIL;
|
|
break;
|
|
}
|
|
return venc_status;
|
|
}
|
|
|
|
static void vid_enc_notify_client(struct video_client_ctx *client_ctx)
|
|
{
|
|
if (client_ctx)
|
|
complete(&client_ctx->event);
|
|
}
|
|
|
|
void vid_enc_vcd_open_done(struct video_client_ctx *client_ctx,
|
|
struct vcd_handle_container *handle_container)
|
|
{
|
|
DBG("vid_enc_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_enc_notify_client(client_ctx);
|
|
} else
|
|
ERR("%s(): ERROR. client_ctx is NULL\n",
|
|
__func__);
|
|
}
|
|
|
|
static void vid_enc_input_frame_done(struct video_client_ctx *client_ctx,
|
|
u32 event, u32 status,
|
|
struct vcd_frame_data *vcd_frame_data)
|
|
{
|
|
struct vid_enc_msg *venc_msg;
|
|
|
|
if (!client_ctx || !vcd_frame_data) {
|
|
ERR("vid_enc_input_frame_done() NULL pointer\n");
|
|
return;
|
|
}
|
|
|
|
venc_msg = kzalloc(sizeof(struct vid_enc_msg),
|
|
GFP_KERNEL);
|
|
if (!venc_msg) {
|
|
ERR("vid_enc_input_frame_done(): cannot allocate vid_enc_msg "
|
|
" buffer\n");
|
|
return;
|
|
}
|
|
|
|
venc_msg->venc_msg_info.statuscode = vid_enc_get_status(status);
|
|
|
|
venc_msg->venc_msg_info.msgcode = VEN_MSG_INPUT_BUFFER_DONE;
|
|
|
|
switch (event) {
|
|
case VCD_EVT_RESP_INPUT_DONE:
|
|
DBG("Send INPUT_DON message to client = %p\n",
|
|
client_ctx);
|
|
break;
|
|
case VCD_EVT_RESP_INPUT_FLUSHED:
|
|
DBG("Send INPUT_FLUSHED message to client = %p\n",
|
|
client_ctx);
|
|
break;
|
|
default:
|
|
ERR("vid_enc_input_frame_done(): invalid event type: "
|
|
"%d\n", event);
|
|
venc_msg->venc_msg_info.statuscode = VEN_S_EFATAL;
|
|
break;
|
|
}
|
|
|
|
venc_msg->venc_msg_info.buf.clientdata =
|
|
(void *)vcd_frame_data->frm_clnt_data;
|
|
venc_msg->venc_msg_info.msgdata_size =
|
|
sizeof(struct vid_enc_msg);
|
|
|
|
mutex_lock(&client_ctx->msg_queue_lock);
|
|
list_add_tail(&venc_msg->list, &client_ctx->msg_queue);
|
|
mutex_unlock(&client_ctx->msg_queue_lock);
|
|
wake_up(&client_ctx->msg_wait);
|
|
}
|
|
|
|
static void vid_enc_output_frame_done(struct video_client_ctx *client_ctx,
|
|
u32 event, u32 status,
|
|
struct vcd_frame_data *vcd_frame_data)
|
|
{
|
|
struct vid_enc_msg *venc_msg;
|
|
unsigned long kernel_vaddr, phy_addr, user_vaddr;
|
|
int pmem_fd;
|
|
struct file *file;
|
|
s32 buffer_index = -1;
|
|
u32 ion_flag = 0;
|
|
struct ion_handle *buff_handle = NULL;
|
|
|
|
if (!client_ctx || !vcd_frame_data) {
|
|
ERR("vid_enc_input_frame_done() NULL pointer\n");
|
|
return;
|
|
}
|
|
|
|
venc_msg = kzalloc(sizeof(struct vid_enc_msg),
|
|
GFP_KERNEL);
|
|
if (!venc_msg) {
|
|
ERR("vid_enc_input_frame_done(): cannot allocate vid_enc_msg "
|
|
" buffer\n");
|
|
return;
|
|
}
|
|
|
|
venc_msg->venc_msg_info.statuscode = vid_enc_get_status(status);
|
|
venc_msg->venc_msg_info.msgcode = VEN_MSG_OUTPUT_BUFFER_DONE;
|
|
|
|
switch (event) {
|
|
case VCD_EVT_RESP_OUTPUT_DONE:
|
|
DBG("Send OUTPUT_DON message to client = %p\n",
|
|
client_ctx);
|
|
break;
|
|
case VCD_EVT_RESP_OUTPUT_FLUSHED:
|
|
DBG("Send OUTPUT_FLUSHED message to client = %p\n",
|
|
client_ctx);
|
|
break;
|
|
default:
|
|
ERR("vid_enc_output_frame_done: invalid cmd type: %d\n", event);
|
|
venc_msg->venc_msg_info.statuscode = VEN_S_EFATAL;
|
|
break;
|
|
}
|
|
|
|
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)) {
|
|
|
|
/* Buffer address in user space */
|
|
venc_msg->venc_msg_info.buf.ptrbuffer = (u8 *) user_vaddr;
|
|
/* Buffer address in user space */
|
|
venc_msg->venc_msg_info.buf.clientdata = (void *)
|
|
vcd_frame_data->frm_clnt_data;
|
|
/* Data length */
|
|
venc_msg->venc_msg_info.buf.len =
|
|
vcd_frame_data->data_len;
|
|
venc_msg->venc_msg_info.buf.flags =
|
|
vcd_frame_data->flags;
|
|
/* Timestamp pass-through from input frame */
|
|
venc_msg->venc_msg_info.buf.timestamp =
|
|
vcd_frame_data->time_stamp;
|
|
venc_msg->venc_msg_info.buf.sz =
|
|
vcd_frame_data->alloc_len;
|
|
|
|
/* Decoded picture width and height */
|
|
venc_msg->venc_msg_info.msgdata_size =
|
|
sizeof(struct venc_buffer);
|
|
} else {
|
|
ERR("vid_enc_output_frame_done UVA can not be found\n");
|
|
venc_msg->venc_msg_info.statuscode =
|
|
VEN_S_EFATAL;
|
|
}
|
|
if (venc_msg->venc_msg_info.buf.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) {
|
|
msm_ion_do_cache_op(client_ctx->user_ion_client,
|
|
buff_handle,
|
|
(unsigned long *) kernel_vaddr,
|
|
(unsigned long)venc_msg->venc_msg_info.buf.sz,
|
|
ION_IOC_CLEAN_INV_CACHES);
|
|
}
|
|
}
|
|
mutex_lock(&client_ctx->msg_queue_lock);
|
|
list_add_tail(&venc_msg->list, &client_ctx->msg_queue);
|
|
mutex_unlock(&client_ctx->msg_queue_lock);
|
|
wake_up(&client_ctx->msg_wait);
|
|
}
|
|
|
|
static void vid_enc_lean_event(struct video_client_ctx *client_ctx,
|
|
u32 event, u32 status)
|
|
{
|
|
struct vid_enc_msg *venc_msg;
|
|
if (!client_ctx) {
|
|
ERR("%s(): !client_ctx pointer\n",
|
|
__func__);
|
|
return;
|
|
}
|
|
|
|
venc_msg = kzalloc(sizeof(struct vid_enc_msg),
|
|
GFP_KERNEL);
|
|
if (!venc_msg) {
|
|
ERR("%s(): cannot allocate vid_enc_msg buffer\n",
|
|
__func__);
|
|
return;
|
|
}
|
|
|
|
venc_msg->venc_msg_info.statuscode =
|
|
vid_enc_get_status(status);
|
|
|
|
switch (event) {
|
|
case VCD_EVT_RESP_FLUSH_INPUT_DONE:
|
|
INFO("\n msm_vidc_enc: Sending VCD_EVT_RESP_FLUSH_INPUT_DONE"
|
|
" to client");
|
|
venc_msg->venc_msg_info.msgcode =
|
|
VEN_MSG_FLUSH_INPUT_DONE;
|
|
break;
|
|
case VCD_EVT_RESP_FLUSH_OUTPUT_DONE:
|
|
INFO("\n msm_vidc_enc: Sending VCD_EVT_RESP_FLUSH_OUTPUT_DONE"
|
|
" to client");
|
|
venc_msg->venc_msg_info.msgcode =
|
|
VEN_MSG_FLUSH_OUPUT_DONE;
|
|
break;
|
|
|
|
case VCD_EVT_RESP_START:
|
|
INFO("\n msm_vidc_enc: Sending VCD_EVT_RESP_START"
|
|
" to client");
|
|
venc_msg->venc_msg_info.msgcode =
|
|
VEN_MSG_START;
|
|
break;
|
|
|
|
case VCD_EVT_RESP_STOP:
|
|
INFO("\n msm_vidc_enc: Sending VCD_EVT_RESP_STOP"
|
|
" to client");
|
|
venc_msg->venc_msg_info.msgcode =
|
|
VEN_MSG_STOP;
|
|
break;
|
|
|
|
case VCD_EVT_RESP_PAUSE:
|
|
INFO("\n msm_vidc_enc: Sending VCD_EVT_RESP_PAUSE"
|
|
" to client");
|
|
venc_msg->venc_msg_info.msgcode =
|
|
VEN_MSG_PAUSE;
|
|
break;
|
|
case VCD_EVT_IND_INFO_LTRUSE_FAILED:
|
|
INFO("\n msm_vidc_enc: Sending VEN_MSG_LTRUSE_FAILED"\
|
|
" to client");
|
|
venc_msg->venc_msg_info.msgcode =
|
|
VEN_MSG_LTRUSE_FAILED;
|
|
break;
|
|
|
|
default:
|
|
ERR("%s() : unknown event type %u\n",
|
|
__func__, event);
|
|
break;
|
|
}
|
|
|
|
venc_msg->venc_msg_info.msgdata_size = 0;
|
|
|
|
mutex_lock(&client_ctx->msg_queue_lock);
|
|
list_add_tail(&venc_msg->list, &client_ctx->msg_queue);
|
|
mutex_unlock(&client_ctx->msg_queue_lock);
|
|
wake_up(&client_ctx->msg_wait);
|
|
}
|
|
|
|
|
|
void vid_enc_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_enc_vcd_open_done(client_ctx,
|
|
(struct vcd_handle_container *)info);
|
|
break;
|
|
|
|
case VCD_EVT_RESP_INPUT_DONE:
|
|
case VCD_EVT_RESP_INPUT_FLUSHED:
|
|
vid_enc_input_frame_done(client_ctx, event,
|
|
status, (struct vcd_frame_data *)info);
|
|
break;
|
|
|
|
case VCD_EVT_RESP_OUTPUT_DONE:
|
|
case VCD_EVT_RESP_OUTPUT_FLUSHED:
|
|
vid_enc_output_frame_done(client_ctx, event, status,
|
|
(struct vcd_frame_data *)info);
|
|
break;
|
|
|
|
case VCD_EVT_RESP_PAUSE:
|
|
case VCD_EVT_RESP_START:
|
|
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_LTRUSE_FAILED:
|
|
vid_enc_lean_event(client_ctx, event, status);
|
|
break;
|
|
|
|
default:
|
|
ERR("%s() : Error - Invalid event type =%u\n",
|
|
__func__, event);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static u32 vid_enc_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_enc 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_enc msg queue Not empty\n",
|
|
__func__);
|
|
|
|
return !islist_empty;
|
|
}
|
|
|
|
static int vid_enc_get_next_msg(struct video_client_ctx *client_ctx,
|
|
struct venc_msg *venc_msg_info)
|
|
{
|
|
int rc;
|
|
struct vid_enc_msg *vid_enc_msg = NULL;
|
|
|
|
if (!client_ctx)
|
|
return -EIO;
|
|
|
|
rc = wait_event_interruptible(client_ctx->msg_wait,
|
|
vid_enc_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("stopped stop_msg = %u\n", 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_enc_msg = list_first_entry(&client_ctx->msg_queue,
|
|
struct vid_enc_msg, list);
|
|
list_del(&vid_enc_msg->list);
|
|
memcpy(venc_msg_info, &vid_enc_msg->venc_msg_info,
|
|
sizeof(struct venc_msg));
|
|
kfree(vid_enc_msg);
|
|
}
|
|
mutex_unlock(&client_ctx->msg_queue_lock);
|
|
return 0;
|
|
}
|
|
|
|
static u32 vid_enc_close_client(struct video_client_ctx *client_ctx)
|
|
{
|
|
struct vid_enc_msg *vid_enc_msg = NULL;
|
|
u32 vcd_status;
|
|
int rc;
|
|
|
|
INFO("\n msm_vidc_enc: Inside %s()", __func__);
|
|
if (!client_ctx || (!client_ctx->vcd_handle)) {
|
|
ERR("\n %s(): Invalid client_ctx", __func__);
|
|
return false;
|
|
}
|
|
|
|
mutex_lock(&vid_enc_device_p->lock);
|
|
|
|
if (!client_ctx->stop_called) {
|
|
vcd_status = vcd_stop(client_ctx->vcd_handle);
|
|
DBG("Waiting for VCD_STOP: Before Timeout\n");
|
|
if (!vcd_status) {
|
|
rc = wait_for_completion_timeout(&client_ctx->event,
|
|
5 * HZ);
|
|
if (!rc) {
|
|
ERR("%s:ERROR vcd_stop time out"
|
|
"rc = %d\n", __func__, rc);
|
|
}
|
|
|
|
if (client_ctx->event_status) {
|
|
ERR("%s:ERROR "
|
|
"vcd_stop Not successs\n", __func__);
|
|
}
|
|
}
|
|
}
|
|
DBG("VCD_STOPPED: After Timeout, calling VCD_CLOSE\n");
|
|
mutex_lock(&client_ctx->msg_queue_lock);
|
|
while (!list_empty(&client_ctx->msg_queue)) {
|
|
DBG("%s(): Delete remaining entries\n", __func__);
|
|
vid_enc_msg = list_first_entry(&client_ctx->msg_queue,
|
|
struct vid_enc_msg, list);
|
|
list_del(&vid_enc_msg->list);
|
|
kfree(vid_enc_msg);
|
|
}
|
|
mutex_unlock(&client_ctx->msg_queue_lock);
|
|
vcd_status = vcd_close(client_ctx->vcd_handle);
|
|
|
|
if (vcd_status) {
|
|
mutex_unlock(&vid_enc_device_p->lock);
|
|
return false;
|
|
}
|
|
memset((void *)client_ctx, 0,
|
|
sizeof(struct video_client_ctx));
|
|
|
|
vid_enc_device_p->num_clients--;
|
|
client_ctx->stop_called = 0;
|
|
mutex_unlock(&vid_enc_device_p->lock);
|
|
return true;
|
|
}
|
|
|
|
static int vid_enc_open_client(struct video_client_ctx **vid_clnt_ctx,
|
|
int flags)
|
|
{
|
|
s32 client_index;
|
|
struct video_client_ctx *client_ctx;
|
|
int rc = 0;
|
|
u8 client_count = 0;
|
|
|
|
INFO("\n msm_vidc_enc: Inside %s()", __func__);
|
|
if (!vid_clnt_ctx) {
|
|
ERR("Invalid input\n");
|
|
rc = -EINVAL;
|
|
goto client_failure;
|
|
}
|
|
*vid_clnt_ctx = NULL;
|
|
client_count = vcd_get_num_of_clients();
|
|
if (client_count == VIDC_MAX_NUM_CLIENTS) {
|
|
ERR("ERROR : vid_enc_open() max number of clients\n");
|
|
rc = -ENODEV;
|
|
goto client_failure;
|
|
}
|
|
|
|
DBG(" Virtual Address of ioremap is %p\n", vid_enc_device_p->virt_base);
|
|
if (!vid_enc_device_p->num_clients) {
|
|
if (!vidc_load_firmware()) {
|
|
rc = -ENODEV;
|
|
goto client_failure;
|
|
}
|
|
}
|
|
|
|
client_index = vid_enc_get_empty_client_index();
|
|
|
|
if (client_index < 0) {
|
|
ERR("%s() : No free clients client_index == -1\n",
|
|
__func__);
|
|
rc = -ENODEV;
|
|
goto client_failure;
|
|
}
|
|
|
|
client_ctx =
|
|
&vid_enc_device_p->venc_clients[client_index];
|
|
vid_enc_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);
|
|
if (vcd_get_ion_status()) {
|
|
client_ctx->user_ion_client = vcd_get_ion_client();
|
|
if (!client_ctx->user_ion_client) {
|
|
ERR("vcd_open ion get client failed");
|
|
rc = -EFAULT;
|
|
goto client_failure;
|
|
}
|
|
}
|
|
rc = vcd_open(vid_enc_device_p->device_handle, false,
|
|
vid_enc_vcd_cb, client_ctx, flags);
|
|
client_ctx->stop_msg = 0;
|
|
client_ctx->stop_called = 1;
|
|
|
|
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 = -EFAULT;
|
|
goto client_failure;
|
|
}
|
|
} else {
|
|
ERR("vcd_open returned error: %u", rc);
|
|
goto client_failure;
|
|
}
|
|
*vid_clnt_ctx = client_ctx;
|
|
client_failure:
|
|
return rc;
|
|
}
|
|
static int vid_enc_open(struct inode *inode, struct file *file)
|
|
{
|
|
int rc = 0;
|
|
struct video_client_ctx *client_ctx = NULL;
|
|
INFO("msm_vidc_venc: Inside %s()", __func__);
|
|
mutex_lock(&vid_enc_device_p->lock);
|
|
rc = vid_enc_open_client(&client_ctx, 0);
|
|
if (rc)
|
|
pr_err("%s() open failed rc=%d\n", __func__, rc);
|
|
else if (!client_ctx) {
|
|
pr_err("%s() client_ctx is NULL\n", __func__);
|
|
rc = -ENOMEM;
|
|
}
|
|
if (!rc)
|
|
file->private_data = client_ctx;
|
|
mutex_unlock(&vid_enc_device_p->lock);
|
|
return rc;
|
|
}
|
|
|
|
static int vid_enc_release(struct inode *inode, struct file *file)
|
|
{
|
|
struct video_client_ctx *client_ctx = file->private_data;
|
|
INFO("\n msm_vidc_enc: Inside %s()", __func__);
|
|
vid_enc_close_client(client_ctx);
|
|
vidc_release_firmware();
|
|
#ifndef USE_RES_TRACKER
|
|
vidc_disable_clk();
|
|
#endif
|
|
INFO("\n msm_vidc_enc: Return from %s()", __func__);
|
|
return 0;
|
|
}
|
|
static int vid_enc_open_secure(struct inode *inode, struct file *file)
|
|
{
|
|
int rc = 0, vcd_status = 0;
|
|
struct video_client_ctx *client_ctx = NULL;
|
|
struct vcd_property_hdr vcd_property_hdr;
|
|
struct vcd_property_sps_pps_for_idr_enable idr_enable;
|
|
|
|
INFO("msm_vidc_enc: Inside %s()", __func__);
|
|
mutex_lock(&vid_enc_device_p->lock);
|
|
rc = vid_enc_open_client(&client_ctx, VCD_CP_SESSION);
|
|
if (rc || !client_ctx) {
|
|
pr_err("%s() open failed rc=%d\n", __func__, rc);
|
|
if (!client_ctx)
|
|
rc = -ENOMEM;
|
|
goto error;
|
|
}
|
|
file->private_data = client_ctx;
|
|
vcd_property_hdr.prop_id = VCD_I_ENABLE_SPS_PPS_FOR_IDR;
|
|
vcd_property_hdr.sz =
|
|
sizeof(struct vcd_property_sps_pps_for_idr_enable);
|
|
idr_enable.sps_pps_for_idr_enable_flag = 1;
|
|
vcd_status = vcd_set_property(client_ctx->vcd_handle,
|
|
&vcd_property_hdr, &idr_enable);
|
|
if (vcd_status) {
|
|
ERR("Setting SPS with IDR failed\n");
|
|
rc = -EACCES;
|
|
goto close_client;
|
|
}
|
|
|
|
if (res_trk_open_secure_session()) {
|
|
rc = -EACCES;
|
|
goto close_client;
|
|
}
|
|
mutex_unlock(&vid_enc_device_p->lock);
|
|
return rc;
|
|
|
|
close_client:
|
|
vid_enc_close_client(client_ctx);
|
|
ERR("Secure session operation failure\n");
|
|
error:
|
|
mutex_unlock(&vid_enc_device_p->lock);
|
|
return rc;
|
|
}
|
|
static const struct file_operations vid_enc_fops[NUM_OF_DRIVER_NODES] = {
|
|
{
|
|
.owner = THIS_MODULE,
|
|
.open = vid_enc_open,
|
|
.release = vid_enc_release,
|
|
.unlocked_ioctl = vid_enc_ioctl,
|
|
},
|
|
{
|
|
.owner = THIS_MODULE,
|
|
.open = vid_enc_open_secure,
|
|
.release = vid_enc_release,
|
|
.unlocked_ioctl = vid_enc_ioctl,
|
|
},
|
|
};
|
|
|
|
void vid_enc_interrupt_deregister(void)
|
|
{
|
|
}
|
|
|
|
void vid_enc_interrupt_register(void *device_name)
|
|
{
|
|
}
|
|
|
|
void vid_enc_interrupt_clear(void)
|
|
{
|
|
}
|
|
|
|
void *vid_enc_map_dev_base_addr(void *device_name)
|
|
{
|
|
return vid_enc_device_p->virt_base;
|
|
}
|
|
|
|
static int vid_enc_vcd_init(void)
|
|
{
|
|
int rc;
|
|
struct vcd_init_config vcd_init_config;
|
|
u32 i;
|
|
|
|
INFO("\n msm_vidc_enc: Inside %s()", __func__);
|
|
vid_enc_device_p->num_clients = 0;
|
|
|
|
for (i = 0; i < VIDC_MAX_NUM_CLIENTS; i++) {
|
|
memset((void *)&vid_enc_device_p->venc_clients[i], 0,
|
|
sizeof(vid_enc_device_p->venc_clients[i]));
|
|
}
|
|
|
|
mutex_init(&vid_enc_device_p->lock);
|
|
vid_enc_device_p->virt_base = vidc_get_ioaddr();
|
|
|
|
if (!vid_enc_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_enc_map_dev_base_addr;
|
|
vcd_init_config.interrupt_clr =
|
|
vid_enc_interrupt_clear;
|
|
vcd_init_config.register_isr =
|
|
vid_enc_interrupt_register;
|
|
vcd_init_config.deregister_isr =
|
|
vid_enc_interrupt_deregister;
|
|
|
|
rc = vcd_init(&vcd_init_config,
|
|
&vid_enc_device_p->device_handle);
|
|
|
|
if (rc) {
|
|
ERR("%s() : vcd_init failed\n",
|
|
__func__);
|
|
return -ENODEV;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int __init vid_enc_init(void)
|
|
{
|
|
int rc = 0, i = 0, j = 0;
|
|
struct device *class_devp;
|
|
|
|
INFO("\n msm_vidc_enc: Inside %s()", __func__);
|
|
vid_enc_device_p = kzalloc(sizeof(struct vid_enc_dev),
|
|
GFP_KERNEL);
|
|
if (!vid_enc_device_p) {
|
|
ERR("%s Unable to allocate memory for vid_enc_dev\n",
|
|
__func__);
|
|
return -ENOMEM;
|
|
}
|
|
rc = alloc_chrdev_region(&vid_enc_dev_num, 0, NUM_OF_DRIVER_NODES,
|
|
VID_ENC_NAME);
|
|
if (rc < 0) {
|
|
ERR("%s: alloc_chrdev_region Failed rc = %d\n",
|
|
__func__, rc);
|
|
goto error_vid_enc_alloc_chrdev_region;
|
|
}
|
|
vid_enc_class = class_create(THIS_MODULE, VID_ENC_NAME);
|
|
if (IS_ERR(vid_enc_class)) {
|
|
rc = PTR_ERR(vid_enc_class);
|
|
ERR("%s: couldn't create vid_enc_class rc = %d\n",
|
|
__func__, rc);
|
|
goto error_vid_enc_class_create;
|
|
}
|
|
for (i = 0; i < NUM_OF_DRIVER_NODES; i++) {
|
|
class_devp = device_create(vid_enc_class, NULL,
|
|
(vid_enc_dev_num + i), NULL,
|
|
VID_ENC_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_enc_class_device_create;
|
|
else
|
|
goto error_vid_enc_cdev_add;
|
|
}
|
|
|
|
vid_enc_device_p->device[i] = class_devp;
|
|
|
|
cdev_init(&vid_enc_device_p->cdev[i], &vid_enc_fops[i]);
|
|
vid_enc_device_p->cdev[i].owner = THIS_MODULE;
|
|
rc = cdev_add(&(vid_enc_device_p->cdev[i]),
|
|
(vid_enc_dev_num + i), 1);
|
|
|
|
if (rc < 0) {
|
|
ERR("%s: cdev_add failed %d\n",
|
|
__func__, rc);
|
|
goto error_vid_enc_cdev_add;
|
|
}
|
|
}
|
|
vid_enc_vcd_init();
|
|
return 0;
|
|
|
|
error_vid_enc_cdev_add:
|
|
for (j = i-1; j >= 0; j--)
|
|
cdev_del(&(vid_enc_device_p->cdev[j]));
|
|
device_destroy(vid_enc_class, vid_enc_dev_num);
|
|
error_vid_enc_class_device_create:
|
|
class_destroy(vid_enc_class);
|
|
error_vid_enc_class_create:
|
|
unregister_chrdev_region(vid_enc_dev_num, 1);
|
|
error_vid_enc_alloc_chrdev_region:
|
|
kfree(vid_enc_device_p);
|
|
|
|
return rc;
|
|
}
|
|
|
|
static void __exit vid_enc_exit(void)
|
|
{
|
|
int i = 0;
|
|
INFO("\n msm_vidc_enc: Inside %s()", __func__);
|
|
for (i = 0; i < NUM_OF_DRIVER_NODES; i++)
|
|
cdev_del(&(vid_enc_device_p->cdev[i]));
|
|
device_destroy(vid_enc_class, vid_enc_dev_num);
|
|
class_destroy(vid_enc_class);
|
|
unregister_chrdev_region(vid_enc_dev_num, 1);
|
|
kfree(vid_enc_device_p);
|
|
INFO("\n msm_vidc_enc: Return from %s()", __func__);
|
|
}
|
|
static long vid_enc_ioctl(struct file *file,
|
|
unsigned cmd, unsigned long u_arg)
|
|
{
|
|
struct video_client_ctx *client_ctx = NULL;
|
|
struct venc_ioctl_msg venc_msg;
|
|
void __user *arg = (void __user *)u_arg;
|
|
u32 result = true;
|
|
int result_read = -1;
|
|
|
|
DBG("%s\n", __func__);
|
|
|
|
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 VEN_IOCTL_CMD_READ_NEXT_MSG:
|
|
{
|
|
struct venc_msg cb_msg;
|
|
if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
|
|
return -EFAULT;
|
|
DBG("VEN_IOCTL_CMD_READ_NEXT_MSG\n");
|
|
result_read = vid_enc_get_next_msg(client_ctx, &cb_msg);
|
|
if (result_read < 0)
|
|
return result_read;
|
|
if (copy_to_user(venc_msg.out, &cb_msg, sizeof(cb_msg)))
|
|
return -EFAULT;
|
|
break;
|
|
}
|
|
case VEN_IOCTL_CMD_STOP_READ_MSG:
|
|
{
|
|
DBG("VEN_IOCTL_CMD_STOP_READ_MSG\n");
|
|
client_ctx->stop_msg = 1;
|
|
wake_up(&client_ctx->msg_wait);
|
|
break;
|
|
}
|
|
case VEN_IOCTL_CMD_ENCODE_FRAME:
|
|
case VEN_IOCTL_CMD_FILL_OUTPUT_BUFFER:
|
|
{
|
|
struct venc_buffer enc_buffer;
|
|
if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
|
|
return -EFAULT;
|
|
if (copy_from_user(&enc_buffer, venc_msg.in,
|
|
sizeof(enc_buffer)))
|
|
return -EFAULT;
|
|
if (cmd == VEN_IOCTL_CMD_ENCODE_FRAME) {
|
|
DBG("VEN_IOCTL_CMD_ENCODE_FRAME\n");
|
|
result = vid_enc_encode_frame(client_ctx,
|
|
&enc_buffer);
|
|
} else {
|
|
DBG("VEN_IOCTL_CMD_FILL_OUTPUT_BUFFER\n");
|
|
result = vid_enc_fill_output_buffer(client_ctx,
|
|
&enc_buffer);
|
|
}
|
|
if (!result) {
|
|
DBG("\n VEN_IOCTL_CMD_ENCODE_FRAME/"
|
|
"VEN_IOCTL_CMD_FILL_OUTPUT_BUFFER failed");
|
|
return -EIO;
|
|
}
|
|
break;
|
|
}
|
|
case VEN_IOCTL_SET_INPUT_BUFFER:
|
|
case VEN_IOCTL_SET_OUTPUT_BUFFER:
|
|
{
|
|
enum venc_buffer_dir buffer_dir;
|
|
struct venc_bufferpayload buffer_info;
|
|
if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
|
|
return -EFAULT;
|
|
DBG("VEN_IOCTL_SET_INPUT_BUFFER/VEN_IOCTL_SET_OUTPUT_BUFFER\n");
|
|
if (copy_from_user(&buffer_info, venc_msg.in,
|
|
sizeof(buffer_info)))
|
|
return -EFAULT;
|
|
buffer_dir = VEN_BUFFER_TYPE_INPUT;
|
|
if (cmd == VEN_IOCTL_SET_OUTPUT_BUFFER)
|
|
buffer_dir = VEN_BUFFER_TYPE_OUTPUT;
|
|
result = vid_enc_set_buffer(client_ctx, &buffer_info,
|
|
buffer_dir);
|
|
if (!result) {
|
|
DBG("\n VEN_IOCTL_SET_INPUT_BUFFER"
|
|
"/VEN_IOCTL_SET_OUTPUT_BUFFER failed");
|
|
return -EIO;
|
|
}
|
|
break;
|
|
}
|
|
case VEN_IOCTL_CMD_FREE_INPUT_BUFFER:
|
|
case VEN_IOCTL_CMD_FREE_OUTPUT_BUFFER:
|
|
{
|
|
enum venc_buffer_dir buffer_dir;
|
|
struct venc_bufferpayload buffer_info;
|
|
if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
|
|
return -EFAULT;
|
|
|
|
DBG("VEN_IOCTL_CMD_FREE_INPUT_BUFFER/"
|
|
"VEN_IOCTL_CMD_FREE_OUTPUT_BUFFER\n");
|
|
|
|
if (copy_from_user(&buffer_info, venc_msg.in,
|
|
sizeof(buffer_info)))
|
|
return -EFAULT;
|
|
|
|
buffer_dir = VEN_BUFFER_TYPE_INPUT;
|
|
if (cmd == VEN_IOCTL_CMD_FREE_OUTPUT_BUFFER)
|
|
buffer_dir = VEN_BUFFER_TYPE_OUTPUT;
|
|
|
|
result = vid_enc_free_buffer(client_ctx, &buffer_info,
|
|
buffer_dir);
|
|
if (!result) {
|
|
DBG("\n VEN_IOCTL_CMD_FREE_OUTPUT_BUFFER"
|
|
"/VEN_IOCTL_CMD_FREE_OUTPUT_BUFFER failed");
|
|
return -EIO;
|
|
}
|
|
break;
|
|
}
|
|
case VEN_IOCTL_SET_INPUT_BUFFER_REQ:
|
|
case VEN_IOCTL_SET_OUTPUT_BUFFER_REQ:
|
|
{
|
|
struct venc_allocatorproperty allocatorproperty;
|
|
if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
|
|
return -EFAULT;
|
|
|
|
if (copy_from_user(&allocatorproperty, venc_msg.in,
|
|
sizeof(allocatorproperty)))
|
|
return -EFAULT;
|
|
|
|
if (cmd == VEN_IOCTL_SET_OUTPUT_BUFFER_REQ) {
|
|
DBG("VEN_IOCTL_SET_OUTPUT_BUFFER_REQ\n");
|
|
result = vid_enc_set_buffer_req(client_ctx,
|
|
&allocatorproperty, false);
|
|
} else {
|
|
DBG("VEN_IOCTL_SET_INPUT_BUFFER_REQ\n");
|
|
result = vid_enc_set_buffer_req(client_ctx,
|
|
&allocatorproperty, true);
|
|
}
|
|
if (!result) {
|
|
DBG("setting VEN_IOCTL_SET_OUTPUT_BUFFER_REQ/"
|
|
"VEN_IOCTL_SET_INPUT_BUFFER_REQ failed\n");
|
|
return -EIO;
|
|
}
|
|
break;
|
|
}
|
|
case VEN_IOCTL_GET_INPUT_BUFFER_REQ:
|
|
case VEN_IOCTL_GET_OUTPUT_BUFFER_REQ:
|
|
{
|
|
struct venc_allocatorproperty allocatorproperty;
|
|
if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
|
|
return -EFAULT;
|
|
|
|
if (cmd == VEN_IOCTL_GET_OUTPUT_BUFFER_REQ) {
|
|
DBG("VEN_IOCTL_GET_OUTPUT_BUFFER_REQ\n");
|
|
result = vid_enc_get_buffer_req(client_ctx,
|
|
&allocatorproperty, false);
|
|
} else {
|
|
DBG("VEN_IOCTL_GET_INPUT_BUFFER_REQ\n");
|
|
result = vid_enc_get_buffer_req(client_ctx,
|
|
&allocatorproperty, true);
|
|
}
|
|
if (!result)
|
|
return -EIO;
|
|
if (copy_to_user(venc_msg.out, &allocatorproperty,
|
|
sizeof(allocatorproperty)))
|
|
return -EFAULT;
|
|
break;
|
|
}
|
|
case VEN_IOCTL_CMD_FLUSH:
|
|
{
|
|
struct venc_bufferflush bufferflush;
|
|
if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
|
|
return -EFAULT;
|
|
|
|
DBG("VEN_IOCTL_CMD_FLUSH\n");
|
|
if (copy_from_user(&bufferflush, venc_msg.in,
|
|
sizeof(bufferflush)))
|
|
return -EFAULT;
|
|
INFO("\n %s(): Calling vid_enc_flush with mode = %lu",
|
|
__func__, bufferflush.flush_mode);
|
|
result = vid_enc_flush(client_ctx, &bufferflush);
|
|
|
|
if (!result) {
|
|
ERR("setting VEN_IOCTL_CMD_FLUSH failed\n");
|
|
return -EIO;
|
|
}
|
|
break;
|
|
}
|
|
case VEN_IOCTL_CMD_START:
|
|
{
|
|
INFO("\n %s(): Executing VEN_IOCTL_CMD_START", __func__);
|
|
result = vid_enc_start_stop(client_ctx, true);
|
|
if (!result) {
|
|
ERR("setting VEN_IOCTL_CMD_START failed\n");
|
|
return -EIO;
|
|
} else
|
|
client_ctx->stop_called = 0;
|
|
break;
|
|
}
|
|
case VEN_IOCTL_CMD_STOP:
|
|
{
|
|
INFO("\n %s(): Executing VEN_IOCTL_CMD_STOP", __func__);
|
|
result = vid_enc_start_stop(client_ctx, false);
|
|
if (!result) {
|
|
ERR("setting VEN_IOCTL_CMD_STOP failed\n");
|
|
return -EIO;
|
|
}
|
|
client_ctx->stop_called = 1;
|
|
break;
|
|
}
|
|
case VEN_IOCTL_CMD_PAUSE:
|
|
{
|
|
INFO("\n %s(): Executing VEN_IOCTL_CMD_PAUSE", __func__);
|
|
result = vid_enc_pause_resume(client_ctx, true);
|
|
if (!result) {
|
|
ERR("setting VEN_IOCTL_CMD_PAUSE failed\n");
|
|
return -EIO;
|
|
}
|
|
break;
|
|
}
|
|
case VEN_IOCTL_CMD_RESUME:
|
|
{
|
|
INFO("\n %s(): Executing VEN_IOCTL_CMD_RESUME", __func__);
|
|
result = vid_enc_pause_resume(client_ctx, false);
|
|
if (!result) {
|
|
ERR("setting VEN_IOCTL_CMD_RESUME failed\n");
|
|
return -EIO;
|
|
}
|
|
break;
|
|
}
|
|
case VEN_IOCTL_SET_RECON_BUFFER:
|
|
{
|
|
struct venc_recon_addr venc_recon;
|
|
if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
|
|
return -EFAULT;
|
|
DBG("VEN_IOCTL_SET_RECON_BUFFER\n");
|
|
if (copy_from_user(&venc_recon, venc_msg.in,
|
|
sizeof(venc_recon)))
|
|
return -EFAULT;
|
|
result = vid_enc_set_recon_buffers(client_ctx,
|
|
&venc_recon);
|
|
if (!result) {
|
|
ERR("setting VEN_IOCTL_SET_RECON_BUFFER failed\n");
|
|
return -EIO;
|
|
}
|
|
break;
|
|
}
|
|
case VEN_IOCTL_FREE_RECON_BUFFER:
|
|
{
|
|
struct venc_recon_addr venc_recon;
|
|
DBG("VEN_IOCTL_FREE_RECON_BUFFER\n");
|
|
if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
|
|
return -EFAULT;
|
|
if (copy_from_user(&venc_recon, venc_msg.in,
|
|
sizeof(venc_recon)))
|
|
return -EFAULT;
|
|
result = vid_enc_free_recon_buffers(client_ctx,
|
|
&venc_recon);
|
|
if (!result) {
|
|
ERR("VEN_IOCTL_FREE_RECON_BUFFER failed\n");
|
|
return -EIO;
|
|
}
|
|
break;
|
|
}
|
|
case VEN_IOCTL_GET_RECON_BUFFER_SIZE:
|
|
{
|
|
struct venc_recon_buff_size venc_recon_size;
|
|
if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
|
|
return -EFAULT;
|
|
DBG("VEN_IOCTL_GET_RECON_BUFFER_SIZE\n");
|
|
if (copy_from_user(&venc_recon_size, venc_msg.out,
|
|
sizeof(venc_recon_size)))
|
|
return -EFAULT;
|
|
result = vid_enc_get_recon_buffer_size(client_ctx,
|
|
&venc_recon_size);
|
|
if (result) {
|
|
if (copy_to_user(venc_msg.out, &venc_recon_size,
|
|
sizeof(venc_recon_size)))
|
|
return -EFAULT;
|
|
} else {
|
|
ERR("setting VEN_IOCTL_GET_RECON_BUFFER_SIZE"
|
|
"failed\n");
|
|
return -EIO;
|
|
}
|
|
break;
|
|
}
|
|
case VEN_IOCTL_SET_QP_RANGE:
|
|
case VEN_IOCTL_GET_QP_RANGE:
|
|
{
|
|
struct venc_qprange qprange;
|
|
if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
|
|
return -EFAULT;
|
|
DBG("VEN_IOCTL_G(S)ET_QP_RANGE\n");
|
|
if (cmd == VEN_IOCTL_SET_QP_RANGE) {
|
|
if (copy_from_user(&qprange, venc_msg.in,
|
|
sizeof(qprange)))
|
|
return -EFAULT;
|
|
result = vid_enc_set_get_qprange(client_ctx,
|
|
&qprange, true);
|
|
} else {
|
|
result = vid_enc_set_get_qprange(client_ctx,
|
|
&qprange, false);
|
|
if (result) {
|
|
if (copy_to_user(venc_msg.out, &qprange,
|
|
sizeof(qprange)))
|
|
return -EFAULT;
|
|
}
|
|
}
|
|
if (!result) {
|
|
ERR("setting VEN_IOCTL_G(S)ET_QP_RANGE failed\n");
|
|
return -EIO;
|
|
}
|
|
break;
|
|
}
|
|
case VEN_IOCTL_SET_HEC:
|
|
case VEN_IOCTL_GET_HEC:
|
|
{
|
|
struct venc_headerextension headerextension;
|
|
if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
|
|
return -EFAULT;
|
|
DBG("VEN_IOCTL_(G)SET_HEC\n");
|
|
if (cmd == VEN_IOCTL_SET_HEC) {
|
|
if (copy_from_user(&headerextension, venc_msg.in,
|
|
sizeof(headerextension)))
|
|
return -EFAULT;
|
|
|
|
result = vid_enc_set_get_headerextension(client_ctx,
|
|
&headerextension, true);
|
|
} else {
|
|
result = vid_enc_set_get_headerextension(client_ctx,
|
|
&headerextension, false);
|
|
if (result) {
|
|
if (copy_to_user(venc_msg.out, &headerextension,
|
|
sizeof(headerextension)))
|
|
return -EFAULT;
|
|
}
|
|
}
|
|
|
|
if (!result) {
|
|
ERR("setting VEN_IOCTL_(G)SET_HEC failed\n");
|
|
return -EIO;
|
|
}
|
|
break;
|
|
}
|
|
case VEN_IOCTL_SET_TARGET_BITRATE:
|
|
case VEN_IOCTL_GET_TARGET_BITRATE:
|
|
{
|
|
struct venc_targetbitrate targetbitrate;
|
|
if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
|
|
return -EFAULT;
|
|
DBG("VEN_IOCTL_(G)SET_TARGET_BITRATE\n");
|
|
if (cmd == VEN_IOCTL_SET_TARGET_BITRATE) {
|
|
if (copy_from_user(&targetbitrate, venc_msg.in,
|
|
sizeof(targetbitrate)))
|
|
return -EFAULT;
|
|
|
|
result = vid_enc_set_get_bitrate(client_ctx,
|
|
&targetbitrate, true);
|
|
} else {
|
|
result = vid_enc_set_get_bitrate(client_ctx,
|
|
&targetbitrate, false);
|
|
if (result) {
|
|
if (copy_to_user(venc_msg.out, &targetbitrate,
|
|
sizeof(targetbitrate)))
|
|
return -EFAULT;
|
|
}
|
|
}
|
|
if (!result) {
|
|
ERR("setting VEN_IOCTL_(G)SET_TARGET_BITRATE failed\n");
|
|
return -EIO;
|
|
}
|
|
break;
|
|
}
|
|
case VEN_IOCTL_SET_FRAME_RATE:
|
|
case VEN_IOCTL_GET_FRAME_RATE:
|
|
{
|
|
struct venc_framerate framerate;
|
|
if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
|
|
return -EFAULT;
|
|
DBG("VEN_IOCTL_(G)SET_FRAME_RATE\n");
|
|
if (cmd == VEN_IOCTL_SET_FRAME_RATE) {
|
|
if (copy_from_user(&framerate, venc_msg.in,
|
|
sizeof(framerate)))
|
|
return -EFAULT;
|
|
result = vid_enc_set_get_framerate(client_ctx,
|
|
&framerate, true);
|
|
} else {
|
|
result = vid_enc_set_get_framerate(client_ctx,
|
|
&framerate, false);
|
|
if (result) {
|
|
if (copy_to_user(venc_msg.out, &framerate,
|
|
sizeof(framerate)))
|
|
return -EFAULT;
|
|
}
|
|
}
|
|
|
|
if (!result) {
|
|
ERR("VEN_IOCTL_(G)SET_FRAME_RATE failed\n");
|
|
return -EIO;
|
|
}
|
|
break;
|
|
}
|
|
case VEN_IOCTL_SET_VOP_TIMING_CFG:
|
|
case VEN_IOCTL_GET_VOP_TIMING_CFG:
|
|
{
|
|
struct venc_voptimingcfg voptimingcfg;
|
|
if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
|
|
return -EFAULT;
|
|
|
|
DBG("VEN_IOCTL_(G)SET_VOP_TIMING_CFG\n");
|
|
if (cmd == VEN_IOCTL_SET_VOP_TIMING_CFG) {
|
|
if (copy_from_user(&voptimingcfg, venc_msg.in,
|
|
sizeof(voptimingcfg)))
|
|
return -EFAULT;
|
|
result = vid_enc_set_get_voptimingcfg(client_ctx,
|
|
&voptimingcfg, true);
|
|
} else {
|
|
result = vid_enc_set_get_voptimingcfg(client_ctx,
|
|
&voptimingcfg, false);
|
|
if (result) {
|
|
if (copy_to_user(venc_msg.out, &voptimingcfg,
|
|
sizeof(voptimingcfg)))
|
|
return -EFAULT;
|
|
}
|
|
}
|
|
if (!result) {
|
|
ERR("VEN_IOCTL_(G)SET_VOP_TIMING_CFG failed\n");
|
|
return -EIO;
|
|
}
|
|
break;
|
|
}
|
|
case VEN_IOCTL_SET_RATE_CTRL_CFG:
|
|
case VEN_IOCTL_GET_RATE_CTRL_CFG:
|
|
{
|
|
struct venc_ratectrlcfg ratectrlcfg;
|
|
if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
|
|
return -EFAULT;
|
|
DBG("VEN_IOCTL_(G)SET_RATE_CTRL_CFG\n");
|
|
if (cmd == VEN_IOCTL_SET_RATE_CTRL_CFG) {
|
|
if (copy_from_user(&ratectrlcfg, venc_msg.in,
|
|
sizeof(ratectrlcfg)))
|
|
return -EFAULT;
|
|
|
|
result = vid_enc_set_get_ratectrlcfg(client_ctx,
|
|
&ratectrlcfg, true);
|
|
} else {
|
|
result = vid_enc_set_get_ratectrlcfg(client_ctx,
|
|
&ratectrlcfg, false);
|
|
if (result) {
|
|
if (copy_to_user(venc_msg.out, &ratectrlcfg,
|
|
sizeof(ratectrlcfg)))
|
|
return -EFAULT;
|
|
}
|
|
}
|
|
if (!result) {
|
|
ERR("setting VEN_IOCTL_(G)SET_RATE_CTRL_CFG failed\n");
|
|
return -EIO;
|
|
}
|
|
break;
|
|
}
|
|
case VEN_IOCTL_SET_MULTI_SLICE_CFG:
|
|
case VEN_IOCTL_GET_MULTI_SLICE_CFG:
|
|
{
|
|
struct venc_multiclicecfg multiclicecfg;
|
|
if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
|
|
return -EFAULT;
|
|
DBG("VEN_IOCTL_(G)SET_MULTI_SLICE_CFG\n");
|
|
if (cmd == VEN_IOCTL_SET_MULTI_SLICE_CFG) {
|
|
if (copy_from_user(&multiclicecfg, venc_msg.in,
|
|
sizeof(multiclicecfg)))
|
|
return -EFAULT;
|
|
|
|
result = vid_enc_set_get_multiclicecfg(client_ctx,
|
|
&multiclicecfg, true);
|
|
} else {
|
|
result = vid_enc_set_get_multiclicecfg(client_ctx,
|
|
&multiclicecfg, false);
|
|
if (result) {
|
|
if (copy_to_user(venc_msg.out, &multiclicecfg,
|
|
sizeof(multiclicecfg)))
|
|
return -EFAULT;
|
|
}
|
|
}
|
|
if (!result) {
|
|
ERR("VEN_IOCTL_(G)SET_MULTI_SLICE_CFG failed\n");
|
|
return -EIO;
|
|
}
|
|
break;
|
|
}
|
|
case VEN_IOCTL_SET_INTRA_REFRESH:
|
|
case VEN_IOCTL_GET_INTRA_REFRESH:
|
|
{
|
|
struct venc_intrarefresh intrarefresh;
|
|
if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
|
|
return -EFAULT;
|
|
DBG("VEN_IOCTL_(G)SET_INTRA_REFRESH\n");
|
|
if (cmd == VEN_IOCTL_SET_INTRA_REFRESH) {
|
|
if (copy_from_user(&intrarefresh, venc_msg.in,
|
|
sizeof(intrarefresh)))
|
|
return -EFAULT;
|
|
result = vid_enc_set_get_intrarefresh(client_ctx,
|
|
&intrarefresh, true);
|
|
} else {
|
|
result = vid_enc_set_get_intrarefresh(client_ctx,
|
|
&intrarefresh, false);
|
|
if (result) {
|
|
if (copy_to_user(venc_msg.out, &intrarefresh,
|
|
sizeof(intrarefresh)))
|
|
return -EFAULT;
|
|
}
|
|
}
|
|
if (!result) {
|
|
ERR("setting VEN_IOCTL_SET_INTRA_REFRESH failed\n");
|
|
return -EIO;
|
|
}
|
|
break;
|
|
}
|
|
case VEN_IOCTL_SET_DEBLOCKING_CFG:
|
|
case VEN_IOCTL_GET_DEBLOCKING_CFG:
|
|
{
|
|
struct venc_dbcfg dbcfg;
|
|
if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
|
|
return -EFAULT;
|
|
|
|
DBG("VEN_IOCTL_(G)SET_DEBLOCKING_CFG\n");
|
|
if (cmd == VEN_IOCTL_SET_DEBLOCKING_CFG) {
|
|
if (copy_from_user(&dbcfg, venc_msg.in,
|
|
sizeof(dbcfg)))
|
|
return -EFAULT;
|
|
result = vid_enc_set_get_dbcfg(client_ctx,
|
|
&dbcfg, true);
|
|
} else {
|
|
result = vid_enc_set_get_dbcfg(client_ctx,
|
|
&dbcfg, false);
|
|
if (result) {
|
|
if (copy_to_user(venc_msg.out, &dbcfg,
|
|
sizeof(dbcfg)))
|
|
return -EFAULT;
|
|
}
|
|
}
|
|
if (!result) {
|
|
ERR("setting VEN_IOCTL_SET_DEBLOCKING_CFG failed\n");
|
|
return -EIO;
|
|
}
|
|
break;
|
|
}
|
|
case VEN_IOCTL_SET_ENTROPY_CFG:
|
|
case VEN_IOCTL_GET_ENTROPY_CFG:
|
|
{
|
|
struct venc_entropycfg entropy_cfg;
|
|
if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
|
|
return -EFAULT;
|
|
DBG("VEN_IOCTL_(G)SET_ENTROPY_CFG\n");
|
|
if (cmd == VEN_IOCTL_SET_ENTROPY_CFG) {
|
|
if (copy_from_user(&entropy_cfg, venc_msg.in,
|
|
sizeof(entropy_cfg)))
|
|
return -EFAULT;
|
|
result = vid_enc_set_get_entropy_cfg(client_ctx,
|
|
&entropy_cfg, true);
|
|
} else {
|
|
result = vid_enc_set_get_entropy_cfg(client_ctx,
|
|
&entropy_cfg, false);
|
|
if (result) {
|
|
if (copy_to_user(venc_msg.out, &entropy_cfg,
|
|
sizeof(entropy_cfg)))
|
|
return -EFAULT;
|
|
}
|
|
}
|
|
if (!result) {
|
|
ERR("setting VEN_IOCTL_(G)SET_ENTROPY_CFG failed\n");
|
|
return -EIO;
|
|
}
|
|
break;
|
|
}
|
|
case VEN_IOCTL_GET_SEQUENCE_HDR:
|
|
{
|
|
struct venc_seqheader seq_header;
|
|
if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
|
|
return -EFAULT;
|
|
|
|
if (copy_from_user(&seq_header, venc_msg.in,
|
|
sizeof(seq_header)))
|
|
return -EFAULT;
|
|
|
|
DBG("VEN_IOCTL_GET_SEQUENCE_HDR\n");
|
|
result = vid_enc_get_sequence_header(client_ctx,
|
|
&seq_header);
|
|
if (!result) {
|
|
ERR("get sequence header failed\n");
|
|
return -EIO;
|
|
}
|
|
DBG("seq_header: buf=%x, sz=%d, hdrlen=%d\n",
|
|
(int)seq_header.hdrbufptr,
|
|
(int)seq_header.bufsize,
|
|
(int)seq_header.hdrlen);
|
|
if (copy_to_user(venc_msg.out, &seq_header,
|
|
sizeof(seq_header)))
|
|
return -EFAULT;
|
|
break;
|
|
}
|
|
case VEN_IOCTL_CMD_REQUEST_IFRAME:
|
|
{
|
|
DBG("VEN_IOCTL_CMD_REQUEST_IFRAME\n");
|
|
result = vid_enc_request_iframe(client_ctx);
|
|
if (!result) {
|
|
ERR("setting VEN_IOCTL_CMD_REQUEST_IFRAME failed\n");
|
|
return -EIO;
|
|
}
|
|
break;
|
|
}
|
|
case VEN_IOCTL_SET_INTRA_PERIOD:
|
|
case VEN_IOCTL_GET_INTRA_PERIOD:
|
|
{
|
|
struct venc_intraperiod intraperiod;
|
|
if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
|
|
return -EFAULT;
|
|
DBG("VEN_IOCTL_(G)SET_INTRA_PERIOD\n");
|
|
if (cmd == VEN_IOCTL_SET_INTRA_PERIOD) {
|
|
if (copy_from_user(&intraperiod, venc_msg.in,
|
|
sizeof(intraperiod)))
|
|
return -EFAULT;
|
|
result = vid_enc_set_get_intraperiod(client_ctx,
|
|
&intraperiod, true);
|
|
} else {
|
|
result = vid_enc_set_get_intraperiod(client_ctx,
|
|
&intraperiod, false);
|
|
if (result) {
|
|
if (copy_to_user(venc_msg.out, &intraperiod,
|
|
sizeof(intraperiod)))
|
|
return -EFAULT;
|
|
}
|
|
}
|
|
if (!result) {
|
|
ERR("setting VEN_IOCTL_(G)SET_INTRA_PERIOD failed\n");
|
|
return -EIO;
|
|
}
|
|
break;
|
|
}
|
|
case VEN_IOCTL_SET_SESSION_QP:
|
|
case VEN_IOCTL_GET_SESSION_QP:
|
|
{
|
|
struct venc_sessionqp session_qp;
|
|
if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
|
|
return -EFAULT;
|
|
DBG("VEN_IOCTL_(G)SET_SESSION_QP\n");
|
|
if (cmd == VEN_IOCTL_SET_SESSION_QP) {
|
|
if (copy_from_user(&session_qp, venc_msg.in,
|
|
sizeof(session_qp)))
|
|
return -EFAULT;
|
|
result = vid_enc_set_get_session_qp(client_ctx,
|
|
&session_qp, true);
|
|
} else {
|
|
result = vid_enc_set_get_session_qp(client_ctx,
|
|
&session_qp, false);
|
|
if (result) {
|
|
if (copy_to_user(venc_msg.out, &session_qp,
|
|
sizeof(session_qp)))
|
|
return -EFAULT;
|
|
}
|
|
}
|
|
if (!result) {
|
|
ERR("setting VEN_IOCTL_(G)SET_SESSION_QP failed\n");
|
|
return -EIO;
|
|
}
|
|
break;
|
|
}
|
|
case VEN_IOCTL_SET_PROFILE_LEVEL:
|
|
case VEN_IOCTL_GET_PROFILE_LEVEL:
|
|
{
|
|
struct ven_profilelevel profile_level;
|
|
if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
|
|
return -EFAULT;
|
|
|
|
DBG("VEN_IOCTL_(G)SET_PROFILE_LEVEL\n");
|
|
if (cmd == VEN_IOCTL_SET_PROFILE_LEVEL) {
|
|
if (copy_from_user(&profile_level, venc_msg.in,
|
|
sizeof(profile_level)))
|
|
return -EFAULT;
|
|
result = vid_enc_set_get_profile_level(client_ctx,
|
|
&profile_level, true);
|
|
} else {
|
|
result = vid_enc_set_get_profile_level(client_ctx,
|
|
&profile_level, false);
|
|
if (result) {
|
|
if (copy_to_user(venc_msg.out,
|
|
&profile_level, sizeof(profile_level)))
|
|
return -EFAULT;
|
|
}
|
|
}
|
|
if (!result) {
|
|
ERR("setting VEN_IOCTL_SET_PROFILE_LEVEL failed\n");
|
|
return -EIO;
|
|
}
|
|
break;
|
|
}
|
|
case VEN_IOCTL_SET_CODEC_PROFILE:
|
|
case VEN_IOCTL_GET_CODEC_PROFILE:
|
|
{
|
|
struct venc_profile profile;
|
|
if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
|
|
return -EFAULT;
|
|
|
|
DBG("VEN_IOCTL_(G)SET_CODEC_PROFILE\n");
|
|
if (cmd == VEN_IOCTL_SET_CODEC_PROFILE) {
|
|
if (copy_from_user(&profile, venc_msg.in,
|
|
sizeof(profile)))
|
|
return -EFAULT;
|
|
result = vid_enc_set_get_profile(client_ctx,
|
|
&profile, true);
|
|
} else {
|
|
result = vid_enc_set_get_profile(client_ctx,
|
|
&profile, false);
|
|
if (result) {
|
|
if (copy_to_user(venc_msg.out, &profile,
|
|
sizeof(profile)))
|
|
return -EFAULT;
|
|
}
|
|
}
|
|
if (!result) {
|
|
ERR("setting VEN_IOCTL_SET_CODEC_PROFILE failed\n");
|
|
return -EIO;
|
|
}
|
|
break;
|
|
}
|
|
case VEN_IOCTL_SET_SHORT_HDR:
|
|
case VEN_IOCTL_GET_SHORT_HDR:
|
|
{
|
|
struct venc_switch encoder_switch;
|
|
if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
|
|
return -EFAULT;
|
|
DBG("Getting VEN_IOCTL_(G)SET_SHORT_HDR\n");
|
|
if (cmd == VEN_IOCTL_SET_SHORT_HDR) {
|
|
if (copy_from_user(&encoder_switch, venc_msg.in,
|
|
sizeof(encoder_switch)))
|
|
return -EFAULT;
|
|
|
|
result = vid_enc_set_get_short_header(client_ctx,
|
|
&encoder_switch, true);
|
|
} else {
|
|
result = vid_enc_set_get_short_header(client_ctx,
|
|
&encoder_switch, false);
|
|
if (result) {
|
|
if (copy_to_user(venc_msg.out, &encoder_switch,
|
|
sizeof(encoder_switch)))
|
|
return -EFAULT;
|
|
}
|
|
}
|
|
if (!result) {
|
|
ERR("setting VEN_IOCTL_(G)SET_SHORT_HDR failed\n");
|
|
return -EIO;
|
|
}
|
|
break;
|
|
}
|
|
case VEN_IOCTL_SET_BASE_CFG:
|
|
case VEN_IOCTL_GET_BASE_CFG:
|
|
{
|
|
struct venc_basecfg base_config;
|
|
DBG("VEN_IOCTL_SET_BASE_CFG\n");
|
|
if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
|
|
return -EFAULT;
|
|
if (cmd == VEN_IOCTL_SET_BASE_CFG) {
|
|
if (copy_from_user(&base_config, venc_msg.in,
|
|
sizeof(base_config)))
|
|
return -EFAULT;
|
|
result = vid_enc_set_get_base_cfg(client_ctx,
|
|
&base_config, true);
|
|
} else {
|
|
result = vid_enc_set_get_base_cfg(client_ctx,
|
|
&base_config, false);
|
|
if (result) {
|
|
if (copy_to_user(venc_msg.out, &base_config,
|
|
sizeof(base_config)))
|
|
return -EFAULT;
|
|
}
|
|
}
|
|
if (!result) {
|
|
ERR("setting VEN_IOCTL_SET_BASE_CFG failed\n");
|
|
return -EIO;
|
|
}
|
|
break;
|
|
}
|
|
case VEN_IOCTL_SET_LIVE_MODE:
|
|
case VEN_IOCTL_GET_LIVE_MODE:
|
|
{
|
|
struct venc_switch encoder_switch;
|
|
if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
|
|
return -EFAULT;
|
|
|
|
DBG("Getting VEN_IOCTL_(G)SET_LIVE_MODE\n");
|
|
if (cmd == VEN_IOCTL_SET_LIVE_MODE) {
|
|
if (copy_from_user(&encoder_switch, venc_msg.in,
|
|
sizeof(encoder_switch)))
|
|
return -EFAULT;
|
|
result = vid_enc_set_get_live_mode(client_ctx,
|
|
&encoder_switch, true);
|
|
} else {
|
|
result = vid_enc_set_get_live_mode(client_ctx,
|
|
&encoder_switch, false);
|
|
if (result) {
|
|
if (copy_to_user(venc_msg.out, &encoder_switch,
|
|
sizeof(encoder_switch)))
|
|
return -EFAULT;
|
|
}
|
|
}
|
|
if (!result) {
|
|
ERR("setting VEN_IOCTL_(G)SET_LIVE_MODE failed\n");
|
|
return -EIO;
|
|
}
|
|
break;
|
|
}
|
|
case VEN_IOCTL_GET_NUMBER_INSTANCES:
|
|
{
|
|
DBG("VEN_IOCTL_GET_NUMBER_INSTANCES\n");
|
|
if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
|
|
return -EFAULT;
|
|
if (copy_to_user(venc_msg.out,
|
|
&vid_enc_device_p->num_clients, sizeof(u32)))
|
|
return -EFAULT;
|
|
break;
|
|
}
|
|
case VEN_IOCTL_SET_METABUFFER_MODE:
|
|
{
|
|
u32 metabuffer_mode, vcd_status;
|
|
struct vcd_property_hdr vcd_property_hdr;
|
|
struct vcd_property_live live_mode;
|
|
|
|
DBG("VEN_IOCTL_SET_METABUFFER_MODE\n");
|
|
if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
|
|
return -EFAULT;
|
|
if (copy_from_user(&metabuffer_mode, venc_msg.in,
|
|
sizeof(metabuffer_mode)))
|
|
return -EFAULT;
|
|
vcd_property_hdr.prop_id = VCD_I_META_BUFFER_MODE;
|
|
vcd_property_hdr.sz =
|
|
sizeof(struct vcd_property_live);
|
|
live_mode.live = metabuffer_mode;
|
|
vcd_status = vcd_set_property(client_ctx->vcd_handle,
|
|
&vcd_property_hdr, &live_mode);
|
|
if (vcd_status) {
|
|
pr_err(" Setting metabuffer mode failed");
|
|
return -EIO;
|
|
}
|
|
break;
|
|
}
|
|
case VEN_IOCTL_SET_EXTRADATA:
|
|
case VEN_IOCTL_GET_EXTRADATA:
|
|
{
|
|
u32 extradata_flag;
|
|
DBG("VEN_IOCTL_(G)SET_EXTRADATA\n");
|
|
if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
|
|
return -EFAULT;
|
|
if (cmd == VEN_IOCTL_SET_EXTRADATA) {
|
|
if (copy_from_user(&extradata_flag, venc_msg.in,
|
|
sizeof(u32)))
|
|
return -EFAULT;
|
|
result = vid_enc_set_get_extradata(client_ctx,
|
|
&extradata_flag, true);
|
|
} else {
|
|
result = vid_enc_set_get_extradata(client_ctx,
|
|
&extradata_flag, false);
|
|
if (result) {
|
|
if (copy_to_user(venc_msg.out, &extradata_flag,
|
|
sizeof(u32)))
|
|
return -EFAULT;
|
|
}
|
|
}
|
|
if (!result) {
|
|
ERR("setting VEN_IOCTL_(G)SET_LIVE_MODE failed\n");
|
|
}
|
|
break;
|
|
}
|
|
case VEN_IOCTL_SET_SLICE_DELIVERY_MODE:
|
|
{
|
|
struct vcd_property_hdr vcd_property_hdr;
|
|
u32 vcd_status = VCD_ERR_FAIL;
|
|
u32 enable = true;
|
|
DBG("VEN_IOCTL_SET_SLICE_DELIVERY_MODE\n");
|
|
vcd_property_hdr.prop_id = VCD_I_SLICE_DELIVERY_MODE;
|
|
vcd_property_hdr.sz = sizeof(u32);
|
|
vcd_status = vcd_set_property(client_ctx->vcd_handle,
|
|
&vcd_property_hdr, &enable);
|
|
if (vcd_status) {
|
|
pr_err(" Setting slice delivery mode failed");
|
|
return -EIO;
|
|
}
|
|
break;
|
|
}
|
|
case VEN_IOCTL_SET_H263_PLUSPTYPE:
|
|
{
|
|
struct vcd_property_hdr vcd_property_hdr;
|
|
struct venc_plusptype plusptype;
|
|
u32 enable;
|
|
u32 vcd_status = VCD_ERR_FAIL;
|
|
if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
|
|
return -EFAULT;
|
|
if (copy_from_user(&plusptype, venc_msg.in,
|
|
sizeof(plusptype)))
|
|
return -EFAULT;
|
|
vcd_property_hdr.prop_id = VCD_I_H263_PLUSPTYPE;
|
|
vcd_property_hdr.sz = sizeof(u32);
|
|
enable = plusptype.plusptype_enable;
|
|
DBG("VEN_IOCTL_SET PLUSPTYPE = %d\n", enable);
|
|
vcd_status = vcd_set_property(client_ctx->vcd_handle,
|
|
&vcd_property_hdr, &enable);
|
|
if (vcd_status) {
|
|
pr_err(" Setting plusptype failed");
|
|
return -EIO;
|
|
}
|
|
break;
|
|
}
|
|
case VEN_IOCTL_SET_LTRMODE:
|
|
case VEN_IOCTL_GET_LTRMODE:
|
|
{
|
|
struct venc_ltrmode encoder_ltrmode;
|
|
if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
|
|
return -EFAULT;
|
|
if (cmd == VEN_IOCTL_SET_LTRMODE) {
|
|
DBG("VEN_IOCTL_SET_LTRMODE\n");
|
|
if (copy_from_user(&encoder_ltrmode, venc_msg.in,
|
|
sizeof(encoder_ltrmode)))
|
|
return -EFAULT;
|
|
result = vid_enc_set_get_ltrmode(client_ctx,
|
|
&encoder_ltrmode, true);
|
|
} else {
|
|
DBG("VEN_IOCTL_GET_LTRMODE\n");
|
|
result = vid_enc_set_get_ltrmode(client_ctx,
|
|
&encoder_ltrmode, false);
|
|
if (result) {
|
|
if (copy_to_user(venc_msg.out, &encoder_ltrmode,
|
|
sizeof(encoder_ltrmode)))
|
|
return -EFAULT;
|
|
}
|
|
}
|
|
if (!result) {
|
|
ERR("VEN_IOCTL_(G)SET_LTRMODE failed\n");
|
|
return -EIO;
|
|
}
|
|
break;
|
|
}
|
|
case VEN_IOCTL_SET_LTRCOUNT:
|
|
case VEN_IOCTL_GET_LTRCOUNT:
|
|
{
|
|
struct venc_ltrcount encoder_ltrcount;
|
|
if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
|
|
return -EFAULT;
|
|
if (cmd == VEN_IOCTL_SET_LTRCOUNT) {
|
|
DBG("VEN_IOCTL_SET_LTRCOUNT\n");
|
|
if (copy_from_user(&encoder_ltrcount, venc_msg.in,
|
|
sizeof(encoder_ltrcount)))
|
|
return -EFAULT;
|
|
result = vid_enc_set_get_ltrcount(client_ctx,
|
|
&encoder_ltrcount, true);
|
|
} else {
|
|
DBG("VEN_IOCTL_GET_LTRCOUNT\n");
|
|
result = vid_enc_set_get_ltrcount(client_ctx,
|
|
&encoder_ltrcount, false);
|
|
if (result) {
|
|
if (copy_to_user(venc_msg.out,
|
|
&encoder_ltrcount,
|
|
sizeof(encoder_ltrcount)))
|
|
return -EFAULT;
|
|
}
|
|
}
|
|
if (!result) {
|
|
ERR("VEN_IOCTL_(G)SET_LTRCOUNT failed\n");
|
|
return -EIO;
|
|
}
|
|
break;
|
|
}
|
|
case VEN_IOCTL_SET_LTRPERIOD:
|
|
case VEN_IOCTL_GET_LTRPERIOD:
|
|
{
|
|
struct venc_ltrperiod encoder_ltrperiod;
|
|
if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
|
|
return -EFAULT;
|
|
if (cmd == VEN_IOCTL_SET_LTRPERIOD) {
|
|
DBG("VEN_IOCTL_SET_LTRPERIOD\n");
|
|
if (copy_from_user(&encoder_ltrperiod, venc_msg.in,
|
|
sizeof(encoder_ltrperiod)))
|
|
return -EFAULT;
|
|
result = vid_enc_set_get_ltrperiod(client_ctx,
|
|
&encoder_ltrperiod, true);
|
|
} else {
|
|
DBG("VEN_IOCTL_GET_LTRPERIOD\n");
|
|
result = vid_enc_set_get_ltrperiod(client_ctx,
|
|
&encoder_ltrperiod, false);
|
|
if (result) {
|
|
if (copy_to_user(venc_msg.out,
|
|
&encoder_ltrperiod,
|
|
sizeof(encoder_ltrperiod)))
|
|
return -EFAULT;
|
|
}
|
|
}
|
|
if (!result) {
|
|
ERR("VEN_IOCTL_(G)SET_LTRPERIOD failed\n");
|
|
return -EIO;
|
|
}
|
|
break;
|
|
}
|
|
case VEN_IOCTL_GET_CAPABILITY_LTRCOUNT:
|
|
{
|
|
struct venc_range venc_capltrcount;
|
|
if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
|
|
return -EFAULT;
|
|
DBG("VEN_IOCTL_GET_CAPABILITY_LTRCOUNT\n");
|
|
result = vid_enc_get_capability_ltrcount(client_ctx,
|
|
&venc_capltrcount);
|
|
if (result) {
|
|
if (copy_to_user(venc_msg.out, &venc_capltrcount,
|
|
sizeof(venc_capltrcount)))
|
|
return -EFAULT;
|
|
} else {
|
|
ERR("VEN_IOCTL_GET_CAPABILITY_LTRCOUNT failed\n");
|
|
return -EIO;
|
|
}
|
|
break;
|
|
}
|
|
case VEN_IOCTL_SET_LTRUSE:
|
|
case VEN_IOCTL_GET_LTRUSE:
|
|
{
|
|
struct venc_ltruse encoder_ltruse;
|
|
if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
|
|
return -EFAULT;
|
|
if (cmd == VEN_IOCTL_SET_LTRUSE) {
|
|
DBG("VEN_IOCTL_SET_LTRUSE\n");
|
|
if (copy_from_user(&encoder_ltruse, venc_msg.in,
|
|
sizeof(encoder_ltruse)))
|
|
return -EFAULT;
|
|
result = vid_enc_set_get_ltruse(client_ctx,
|
|
&encoder_ltruse, true);
|
|
} else {
|
|
DBG("VEN_IOCTL_GET_LTRUSE\n");
|
|
result = vid_enc_set_get_ltruse(client_ctx,
|
|
&encoder_ltruse, false);
|
|
if (result) {
|
|
if (copy_to_user(venc_msg.out,
|
|
&encoder_ltruse,
|
|
sizeof(encoder_ltruse)))
|
|
return -EFAULT;
|
|
}
|
|
}
|
|
if (!result) {
|
|
ERR("VEN_IOCTL_(G)SET_LTRUSE failed\n");
|
|
return -EIO;
|
|
}
|
|
break;
|
|
}
|
|
case VEN_IOCTL_SET_SPS_PPS_FOR_IDR:
|
|
{
|
|
struct vcd_property_hdr vcd_property_hdr;
|
|
struct vcd_property_sps_pps_for_idr_enable idr_enable;
|
|
u32 vcd_status = VCD_ERR_FAIL;
|
|
u32 enabled = 1;
|
|
|
|
if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
|
|
return -EFAULT;
|
|
|
|
vcd_property_hdr.prop_id = VCD_I_ENABLE_SPS_PPS_FOR_IDR;
|
|
vcd_property_hdr.sz = sizeof(idr_enable);
|
|
|
|
if (copy_from_user(&enabled, venc_msg.in, sizeof(u32)))
|
|
return -EFAULT;
|
|
|
|
idr_enable.sps_pps_for_idr_enable_flag = enabled;
|
|
vcd_status = vcd_set_property(client_ctx->vcd_handle,
|
|
&vcd_property_hdr, &idr_enable);
|
|
if (vcd_status) {
|
|
pr_err("Setting sps/pps per IDR failed");
|
|
return -EIO;
|
|
}
|
|
break;
|
|
}
|
|
case VEN_IOCTL_SET_AC_PREDICTION:
|
|
case VEN_IOCTL_GET_AC_PREDICTION:
|
|
case VEN_IOCTL_SET_RVLC:
|
|
case VEN_IOCTL_GET_RVLC:
|
|
case VEN_IOCTL_SET_ROTATION:
|
|
case VEN_IOCTL_GET_ROTATION:
|
|
case VEN_IOCTL_SET_DATA_PARTITION:
|
|
case VEN_IOCTL_GET_DATA_PARTITION:
|
|
case VEN_IOCTL_GET_CAPABILITY:
|
|
default:
|
|
ERR("%s(): Unsupported ioctl %d\n", __func__, cmd);
|
|
return -ENOTTY;
|
|
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
MODULE_LICENSE("GPL v2");
|
|
MODULE_DESCRIPTION("Video encoder driver");
|
|
MODULE_VERSION("1.0");
|
|
|
|
module_init(vid_enc_init);
|
|
module_exit(vid_enc_exit);
|