blob: 97fc758dd59ca5660f1c2357ef8a6cecffcc7a1b [file] [log] [blame]
/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/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/android_pmem.h>
#include <linux/clk.h>
#include "vidc_type.h"
#include "vcd_api.h"
#include "venc_internal.h"
#include "vidc_init.h"
#include "vcd_res_tracker_api.h"
#define VID_ENC_NAME "msm_vidc_enc"
#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 int stop_cmd;
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;
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 INPUT_DON message to client = %p\n",
client_ctx);
break;
case VCD_EVT_RESP_OUTPUT_FLUSHED:
DBG("Send INPUT_FLUSHED message to client = %p\n",
client_ctx);
break;
default:
ERR("QVD: 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;
/* 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;
}
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;
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:
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 (!stop_cmd) {
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--;
stop_cmd = 0;
mutex_unlock(&vid_enc_device_p->lock);
return true;
}
static int vid_enc_open(struct inode *inode, struct file *file)
{
s32 client_index;
struct video_client_ctx *client_ctx;
u32 vcd_status = VCD_ERR_FAIL;
u8 client_count = 0;
INFO("\n msm_vidc_enc: Inside %s()", __func__);
mutex_lock(&vid_enc_device_p->lock);
stop_cmd = 0;
client_count = vcd_get_num_of_clients();
if (client_count == VIDC_MAX_NUM_CLIENTS ||
res_trk_check_for_sec_session()) {
ERR("ERROR : vid_enc_open() max number of clients"
"limit reached or secure session is open\n");
mutex_unlock(&vid_enc_device_p->lock);
return -ENODEV;
}
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())
return -ENODEV;
}
client_index = vid_enc_get_empty_client_index();
if (client_index == -1) {
ERR("%s() : No free clients client_index == -1\n",
__func__);
return -ENODEV;
}
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");
return -EFAULT;
}
}
vcd_status = vcd_open(vid_enc_device_p->device_handle, false,
vid_enc_vcd_cb, client_ctx);
client_ctx->stop_msg = 0;
if (!vcd_status) {
wait_for_completion(&client_ctx->event);
if (client_ctx->event_status) {
ERR("callback for vcd_open returned error: %u",
client_ctx->event_status);
mutex_unlock(&vid_enc_device_p->lock);
return -EFAULT;
}
} else {
ERR("vcd_open returned error: %u", vcd_status);
mutex_unlock(&vid_enc_device_p->lock);
return -EFAULT;
}
file->private_data = client_ctx;
mutex_unlock(&vid_enc_device_p->lock);
return 0;
}
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 const struct file_operations vid_enc_fops = {
.owner = THIS_MODULE,
.open = vid_enc_open,
.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;
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, 1, 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;
}
class_devp = device_create(vid_enc_class, NULL,
vid_enc_dev_num, NULL, VID_ENC_NAME);
if (IS_ERR(class_devp)) {
rc = PTR_ERR(class_devp);
ERR("%s: class device_create failed %d\n",
__func__, rc);
goto error_vid_enc_class_device_create;
}
vid_enc_device_p->device = class_devp;
cdev_init(&vid_enc_device_p->cdev, &vid_enc_fops);
vid_enc_device_p->cdev.owner = THIS_MODULE;
rc = cdev_add(&(vid_enc_device_p->cdev), vid_enc_dev_num, 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:
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)
{
INFO("\n msm_vidc_enc: Inside %s()", __func__);
cdev_del(&(vid_enc_device_p->cdev));
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;
DBG("VEN_IOCTL_CMD_ENCODE_FRAME"
"/VEN_IOCTL_CMD_FILL_OUTPUT_BUFFER\n");
if (copy_from_user(&enc_buffer, venc_msg.in,
sizeof(enc_buffer)))
return -EFAULT;
if (cmd == VEN_IOCTL_CMD_ENCODE_FRAME)
result = vid_enc_encode_frame(client_ctx,
&enc_buffer);
else
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;
DBG("VEN_IOCTL_SET_INPUT_BUFFER_REQ"
"/VEN_IOCTL_SET_OUTPUT_BUFFER_REQ\n");
if (copy_from_user(&allocatorproperty, venc_msg.in,
sizeof(allocatorproperty)))
return -EFAULT;
if (cmd == VEN_IOCTL_SET_OUTPUT_BUFFER_REQ)
result = vid_enc_set_buffer_req(client_ctx,
&allocatorproperty, false);
else
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;
DBG("VEN_IOCTL_GET_INPUT_BUFFER_REQ/"
"VEN_IOCTL_GET_OUTPUT_BUFFER_REQ\n");
if (cmd == VEN_IOCTL_GET_OUTPUT_BUFFER_REQ)
result = vid_enc_get_buffer_req(client_ctx,
&allocatorproperty, false);
else
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;
}
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;
}
stop_cmd = 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, seq_header_user;
if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
return -EFAULT;
DBG("VEN_IOCTL_GET_SEQUENCE_HDR\n");
if (copy_from_user(&seq_header_user, venc_msg.in,
sizeof(seq_header_user)))
return -EFAULT;
seq_header.hdrbufptr = NULL;
result = vid_enc_get_sequence_header(client_ctx,
&seq_header);
if (result && ((copy_to_user(seq_header_user.hdrbufptr,
seq_header.hdrbufptr, seq_header.hdrlen)) ||
(copy_to_user(&seq_header_user.hdrlen,
&seq_header.hdrlen,
sizeof(seq_header.hdrlen)))))
result = false;
kfree(seq_header.hdrbufptr);
if (!result)
return -EIO;
break;
}
case VEN_IOCTL_CMD_REQUEST_IFRAME:
{
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;
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_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);