M7350/kernel/drivers/video/msm/vidc/common/enc/venc.c
2024-09-09 08:52:07 +00:00

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);