PageRenderTime 60ms CodeModel.GetById 7ms app.highlight 48ms RepoModel.GetById 0ms app.codeStats 0ms

/arch/arm/mach-msm/qdsp6/msm_q6venc.c

https://bitbucket.org/sammyz/iscream_thunderc-2.6.35-rebase
C | 1200 lines | 1083 code | 100 blank | 17 comment | 136 complexity | faab94334e82e7c1205f4bf92740eb39 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
   1/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
   2 *
   3 * This program is free software; you can redistribute it and/or modify
   4 * it under the terms of the GNU General Public License version 2 and
   5 * only version 2 as published by the Free Software Foundation.
   6 *
   7 * This program is distributed in the hope that it will be useful,
   8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
   9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  10 * GNU General Public License for more details.
  11 *
  12 * You should have received a copy of the GNU General Public License
  13 * along with this program; if not, write to the Free Software
  14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  15 * 02110-1301, USA.
  16 *
  17 */
  18
  19#include <linux/slab.h>
  20#include <linux/cdev.h>
  21#include <linux/file.h>
  22#include <linux/device.h>
  23#include <linux/fs.h>
  24#include <linux/list.h>
  25#include <linux/module.h>
  26#include <linux/sched.h>
  27#include <linux/spinlock.h>
  28#include <linux/uaccess.h>
  29#include <linux/wakelock.h>
  30#include <linux/android_pmem.h>
  31#include <linux/msm_q6venc.h>
  32#include "dal.h"
  33
  34#define DALDEVICEID_VENC_DEVICE         0x0200002D
  35#define DALDEVICEID_VENC_PORTNAME       "DAL_AQ_VID"
  36
  37#define VENC_NAME		        "q6venc"
  38#define VENC_MSG_MAX                    128
  39
  40#define VENC_INTERFACE_VERSION		0x00020000
  41#define MAJOR_MASK			0xFFFF0000
  42#define MINOR_MASK			0x0000FFFF
  43#define VENC_GET_MAJOR_VERSION(version) ((version & MAJOR_MASK)>>16)
  44#define VENC_GET_MINOR_VERSION(version) (version & MINOR_MASK)
  45
  46enum {
  47	VENC_BUFFER_TYPE_INPUT,
  48	VENC_BUFFER_TYPE_OUTPUT,
  49	VENC_BUFFER_TYPE_QDSP6,
  50	VENC_BUFFER_TYPE_HDR
  51};
  52enum {
  53	VENC_DALRPC_GET_SYNTAX_HEADER = DAL_OP_FIRST_DEVICE_API,
  54	VENC_DALRPC_UPDATE_INTRA_REFRESH,
  55	VENC_DALRPC_UPDATE_FRAME_RATE,
  56	VENC_DALRPC_UPDATE_BITRATE,
  57	VENC_DALRPC_UPDATE_QP_RANGE,
  58	VENC_DALRPC_UPDATE_INTRA_PERIOD,
  59	VENC_DALRPC_REQUEST_IFRAME,
  60	VENC_DALRPC_START,
  61	VENC_DALRPC_STOP,
  62	VENC_DALRPC_SUSPEND,
  63	VENC_DALRPC_RESUME,
  64	VENC_DALRPC_FLUSH,
  65	VENC_DALRPC_QUEUE_INPUT,
  66	VENC_DALRPC_QUEUE_OUTPUT
  67};
  68struct venc_input_payload {
  69	u32 data;
  70};
  71struct venc_output_payload {
  72	u32 size;
  73	long long time_stamp;
  74	u32 flags;
  75	u32 data;
  76	u32 client_data_from_input;
  77};
  78union venc_payload {
  79	struct venc_input_payload input_payload;
  80	struct venc_output_payload output_payload;
  81};
  82struct venc_msg_type {
  83	u32 event;
  84	u32 status;
  85	union venc_payload payload;
  86};
  87struct venc_input_buf {
  88	struct venc_buf_type yuv_buf;
  89	u32 data_size;
  90	long long time_stamp;
  91	u32 flags;
  92	u32 dvs_offsetx;
  93	u32 dvs_offsety;
  94	u32 client_data;
  95	u32 op_client_data;
  96};
  97struct venc_output_buf {
  98	struct venc_buf_type bit_stream_buf;
  99	u32 client_data;
 100};
 101
 102struct venc_msg_list {
 103	struct list_head list;
 104	struct venc_msg msg_data;
 105};
 106struct venc_buf {
 107	int fd;
 108	u32 src;
 109	u32 offset;
 110	u32 size;
 111	u32 btype;
 112	unsigned long paddr;
 113	struct file *file;
 114};
 115struct venc_pmem_list {
 116	struct list_head list;
 117	struct venc_buf buf;
 118};
 119struct venc_dev {
 120	bool is_active;
 121	bool pmem_freed;
 122	enum venc_state_type state;
 123	struct list_head venc_msg_list_head;
 124	struct list_head venc_msg_list_free;
 125	spinlock_t venc_msg_list_lock;
 126	struct list_head venc_pmem_list_head;
 127	spinlock_t venc_pmem_list_lock;
 128	struct dal_client *q6_handle;
 129	wait_queue_head_t venc_msg_evt;
 130	struct device *class_devp;
 131};
 132
 133#define DEBUG_VENC 0
 134#if DEBUG_VENC
 135#define TRACE(fmt, x...)     \
 136	do { pr_debug("%s:%d " fmt, __func__, __LINE__, ##x); } while (0)
 137#else
 138#define TRACE(fmt, x...)         do { } while (0)
 139#endif
 140
 141static struct cdev cdev;
 142static dev_t venc_dev_num;
 143static struct class *venc_class;
 144static struct venc_dev *venc_device_p;
 145static int venc_ref;
 146
 147static DEFINE_MUTEX(idlecount_lock);
 148static int idlecount;
 149static struct wake_lock wakelock;
 150static struct wake_lock idlelock;
 151
 152static void prevent_sleep(void)
 153{
 154	mutex_lock(&idlecount_lock);
 155	if (++idlecount == 1) {
 156		wake_lock(&idlelock);
 157		wake_lock(&wakelock);
 158	}
 159	mutex_unlock(&idlecount_lock);
 160}
 161
 162static void allow_sleep(void)
 163{
 164	mutex_lock(&idlecount_lock);
 165	if (--idlecount == 0) {
 166		wake_unlock(&idlelock);
 167		wake_unlock(&wakelock);
 168	}
 169	mutex_unlock(&idlecount_lock);
 170}
 171
 172static inline int venc_check_version(u32 client, u32 server)
 173{
 174	int ret = -EINVAL;
 175
 176	if ((VENC_GET_MAJOR_VERSION(client) == VENC_GET_MAJOR_VERSION(server))
 177	     && (VENC_GET_MINOR_VERSION(client) <=
 178		 VENC_GET_MINOR_VERSION(server)))
 179		ret = 0;
 180
 181	return ret;
 182}
 183
 184static int venc_get_msg(struct venc_dev *dvenc, void *msg)
 185{
 186	struct venc_msg_list *l;
 187	unsigned long flags;
 188	int ret = 0;
 189	struct venc_msg qdsp_msg;
 190
 191	if (!dvenc->is_active)
 192		return -EPERM;
 193	spin_lock_irqsave(&dvenc->venc_msg_list_lock, flags);
 194	list_for_each_entry_reverse(l, &dvenc->venc_msg_list_head, list) {
 195		memcpy(&qdsp_msg, &l->msg_data, sizeof(struct venc_msg));
 196		list_del(&l->list);
 197		list_add(&l->list, &dvenc->venc_msg_list_free);
 198		ret = 1;
 199		break;
 200	}
 201	spin_unlock_irqrestore(&dvenc->venc_msg_list_lock, flags);
 202	if (copy_to_user(msg, &qdsp_msg, sizeof(struct venc_msg)))
 203		pr_err("%s failed to copy_to_user\n", __func__);
 204	return ret;
 205}
 206
 207static void venc_put_msg(struct venc_dev *dvenc, struct venc_msg *msg)
 208{
 209	struct venc_msg_list *l;
 210	unsigned long flags;
 211	int found = 0;
 212
 213	spin_lock_irqsave(&dvenc->venc_msg_list_lock, flags);
 214	list_for_each_entry(l, &dvenc->venc_msg_list_free, list) {
 215		memcpy(&l->msg_data, msg, sizeof(struct venc_msg));
 216		list_del(&l->list);
 217		list_add(&l->list, &dvenc->venc_msg_list_head);
 218		found = 1;
 219		break;
 220	}
 221	spin_unlock_irqrestore(&dvenc->venc_msg_list_lock, flags);
 222	if (found)
 223		wake_up(&dvenc->venc_msg_evt);
 224	else
 225		pr_err("%s: failed to find a free node\n", __func__);
 226
 227}
 228
 229static struct venc_pmem_list *venc_add_pmem_to_list(struct venc_dev *dvenc,
 230						      struct venc_pmem *mptr,
 231						      u32 btype)
 232{
 233	int ret = 0;
 234	unsigned long flags;
 235	unsigned long len;
 236	unsigned long vaddr;
 237	struct venc_pmem_list *plist = NULL;
 238
 239	plist = kzalloc(sizeof(struct venc_pmem_list), GFP_KERNEL);
 240	if (!plist) {
 241		pr_err("%s: kzalloc failed\n", __func__);
 242		return NULL;
 243	}
 244
 245	ret = get_pmem_file(mptr->fd, &(plist->buf.paddr),
 246		&vaddr, &len, &(plist->buf.file));
 247	if (ret) {
 248		pr_err("%s: get_pmem_file failed for fd=%d offset=%d\n",
 249			__func__, mptr->fd, mptr->offset);
 250		goto err_venc_add_pmem;
 251	} else if (mptr->offset >= len) {
 252		pr_err("%s: invalid offset (%d > %ld) for fd=%d\n",
 253		       __func__, mptr->offset, len, mptr->fd);
 254		ret = -EINVAL;
 255		goto err_venc_get_pmem;
 256	}
 257
 258	plist->buf.fd = mptr->fd;
 259	plist->buf.paddr += mptr->offset;
 260	plist->buf.size = mptr->size;
 261	plist->buf.btype = btype;
 262	plist->buf.offset = mptr->offset;
 263	plist->buf.src = mptr->src;
 264
 265	spin_lock_irqsave(&dvenc->venc_pmem_list_lock, flags);
 266	list_add(&plist->list, &dvenc->venc_pmem_list_head);
 267	spin_unlock_irqrestore(&dvenc->venc_pmem_list_lock, flags);
 268	return plist;
 269
 270err_venc_get_pmem:
 271	put_pmem_file(plist->buf.file);
 272err_venc_add_pmem:
 273	kfree(plist);
 274	return NULL;
 275}
 276
 277static struct venc_pmem_list *venc_get_pmem_from_list(
 278		struct venc_dev *dvenc, u32 pmem_fd,
 279		u32 offset, u32 btype)
 280{
 281	struct venc_pmem_list *plist;
 282	unsigned long flags;
 283	struct file *file;
 284	int found = 0;
 285
 286	file = fget(pmem_fd);
 287	if (!file) {
 288		pr_err("%s: invalid encoder buffer fd(%d)\n", __func__,
 289			pmem_fd);
 290		return NULL;
 291	}
 292	spin_lock_irqsave(&dvenc->venc_pmem_list_lock, flags);
 293	list_for_each_entry(plist, &dvenc->venc_pmem_list_head, list) {
 294		if (plist->buf.btype == btype && plist->buf.file == file &&
 295			plist->buf.offset == offset) {
 296			found = 1;
 297			break;
 298		}
 299	}
 300	spin_unlock_irqrestore(&dvenc->venc_pmem_list_lock, flags);
 301	fput(file);
 302	if (found)
 303		return plist;
 304
 305	else
 306		return NULL;
 307}
 308
 309static int venc_set_buffer(struct venc_dev *dvenc, void *argp,
 310			     u32 btype)
 311{
 312	struct venc_pmem pmem;
 313	struct venc_pmem_list *plist;
 314	int ret = 0;
 315
 316	ret = copy_from_user(&pmem, argp, sizeof(pmem));
 317	if (ret) {
 318		pr_err("%s: copy_from_user failed\n", __func__);
 319		return ret;
 320	}
 321	plist = venc_add_pmem_to_list(dvenc, &pmem, btype);
 322	if (plist == NULL) {
 323		pr_err("%s: buffer add_to_pmem_list failed\n",
 324			__func__);
 325		return -EPERM;
 326	}
 327	return ret;
 328}
 329
 330static int venc_assign_q6_buffers(struct venc_dev *dvenc,
 331				    struct venc_buffers *pbufs,
 332				    struct venc_nonio_buf_config *pcfg)
 333{
 334	int ret = 0;
 335	struct venc_pmem_list *plist;
 336
 337	plist = venc_add_pmem_to_list(dvenc, &(pbufs->recon_buf[0]),
 338				  VENC_BUFFER_TYPE_QDSP6);
 339	if (plist == NULL) {
 340		pr_err("%s: recon_buf0 failed to add_to_pmem_list\n",
 341			__func__);
 342		return -EPERM;
 343	}
 344	pcfg->recon_buf1.region = pbufs->recon_buf[0].src;
 345	pcfg->recon_buf1.phys = plist->buf.paddr;
 346	pcfg->recon_buf1.size = plist->buf.size;
 347	pcfg->recon_buf1.offset = 0;
 348
 349	plist = venc_add_pmem_to_list(dvenc, &(pbufs->recon_buf[1]),
 350				  VENC_BUFFER_TYPE_QDSP6);
 351	if (plist == NULL) {
 352		pr_err("%s: recons_buf1 failed to add_to_pmem_list\n",
 353			__func__);
 354		return -EPERM;
 355	}
 356	pcfg->recon_buf2.region = pbufs->recon_buf[1].src;
 357	pcfg->recon_buf2.phys = plist->buf.paddr;
 358	pcfg->recon_buf2.size = plist->buf.size;
 359	pcfg->recon_buf2.offset = 0;
 360
 361	plist = venc_add_pmem_to_list(dvenc, &(pbufs->wb_buf),
 362				  VENC_BUFFER_TYPE_QDSP6);
 363	if (plist == NULL) {
 364		pr_err("%s: wb_buf failed to add_to_pmem_list\n",
 365			__func__);
 366		return -EPERM;
 367	}
 368	pcfg->wb_buf.region = pbufs->wb_buf.src;
 369	pcfg->wb_buf.phys = plist->buf.paddr;
 370	pcfg->wb_buf.size = plist->buf.size;
 371	pcfg->wb_buf.offset = 0;
 372
 373	plist = venc_add_pmem_to_list(dvenc, &(pbufs->cmd_buf),
 374				  VENC_BUFFER_TYPE_QDSP6);
 375	if (plist == NULL) {
 376		pr_err("%s: cmd_buf failed to add_to_pmem_list\n",
 377			__func__);
 378		return -EPERM;
 379	}
 380	pcfg->cmd_buf.region = pbufs->cmd_buf.src;
 381	pcfg->cmd_buf.phys = plist->buf.paddr;
 382	pcfg->cmd_buf.size = plist->buf.size;
 383	pcfg->cmd_buf.offset = 0;
 384
 385	plist = venc_add_pmem_to_list(dvenc, &(pbufs->vlc_buf),
 386				  VENC_BUFFER_TYPE_QDSP6);
 387	if (plist == NULL) {
 388		pr_err("%s: vlc_buf failed to add_to_pmem_list"
 389		" failed\n", __func__);
 390		return -EPERM;
 391	}
 392	pcfg->vlc_buf.region = pbufs->vlc_buf.src;
 393	pcfg->vlc_buf.phys = plist->buf.paddr;
 394	pcfg->vlc_buf.size = plist->buf.size;
 395	pcfg->vlc_buf.offset = 0;
 396
 397	return ret;
 398}
 399
 400static int venc_start(struct venc_dev *dvenc, void *argp)
 401{
 402	int ret = 0;
 403	struct venc_q6_config q6_config;
 404	struct venc_init_config vconfig;
 405
 406	dvenc->state = VENC_STATE_START;
 407	ret = copy_from_user(&vconfig, argp, sizeof(struct venc_init_config));
 408	if (ret) {
 409		pr_err("%s: copy_from_user failed\n", __func__);
 410		return ret;
 411	}
 412	memcpy(&q6_config, &(vconfig.q6_config), sizeof(q6_config));
 413	ret = venc_assign_q6_buffers(dvenc, &(vconfig.q6_bufs),
 414		&(q6_config.buf_params));
 415	if (ret != 0) {
 416		pr_err("%s: assign_q6_buffers failed\n", __func__);
 417		return -EPERM;
 418	}
 419
 420	q6_config.callback_event = dvenc->q6_handle;
 421	TRACE("%s: parameters: handle:%p, config:%p, callback:%p \n", __func__,
 422		dvenc->q6_handle, &q6_config, q6_config.callback_event);
 423	TRACE("%s: parameters:recon1:0x%x, recon2:0x%x,"
 424		" wb_buf:0x%x, cmd:0x%x, vlc:0x%x\n", __func__,
 425		q6_config.buf_params.recon_buf1.phys,
 426		q6_config.buf_params.recon_buf2.phys,
 427		q6_config.buf_params.wb_buf.phys,
 428		q6_config.buf_params.cmd_buf.phys,
 429		q6_config.buf_params.vlc_buf.phys);
 430	TRACE("%s: size of param:%d \n", __func__, sizeof(q6_config));
 431	ret = dal_call_f5(dvenc->q6_handle, VENC_DALRPC_START, &q6_config,
 432		sizeof(q6_config));
 433	if (ret != 0) {
 434		pr_err("%s: remote function failed (%d)\n", __func__, ret);
 435		return ret;
 436	}
 437	return ret;
 438}
 439
 440static int venc_encode_frame(struct venc_dev *dvenc, void *argp)
 441{
 442	int ret = 0;
 443	struct venc_pmem buf;
 444	struct venc_input_buf q6_input;
 445	struct venc_pmem_list *plist;
 446	struct venc_buffer input;
 447
 448	ret = copy_from_user(&input, argp, sizeof(struct venc_buffer));
 449	if (ret) {
 450		pr_err("%s: copy_from_user failed\n", __func__);
 451		return ret;
 452	}
 453	ret = copy_from_user(&buf,
 454			       ((struct venc_buffer *)argp)->ptr_buffer,
 455			       sizeof(struct venc_pmem));
 456	if (ret) {
 457		pr_err("%s: copy_from_user failed\n", __func__);
 458		return ret;
 459	}
 460
 461	plist = venc_get_pmem_from_list(dvenc, buf.fd, buf.offset,
 462			VENC_BUFFER_TYPE_INPUT);
 463	if (NULL == plist) {
 464		plist = venc_add_pmem_to_list(dvenc, &buf,
 465			VENC_BUFFER_TYPE_INPUT);
 466		if (plist == NULL) {
 467			pr_err("%s: buffer add_to_pmem_list failed\n",
 468				__func__);
 469			return -EPERM;
 470		}
 471	}
 472
 473	q6_input.flags = 0;
 474	if (input.flags & VENC_FLAG_EOS)
 475		q6_input.flags |= 0x00000001;
 476	q6_input.yuv_buf.region = plist->buf.src;
 477	q6_input.yuv_buf.phys = plist->buf.paddr;
 478	q6_input.yuv_buf.size = plist->buf.size;
 479	q6_input.yuv_buf.offset = 0;
 480	q6_input.data_size = plist->buf.size;
 481	q6_input.client_data = (u32)input.client_data;
 482	q6_input.time_stamp = input.time_stamp;
 483	q6_input.dvs_offsetx = 0;
 484	q6_input.dvs_offsety = 0;
 485
 486	TRACE("Pushing down input phys=0x%x fd= %d, client_data: 0x%x,"
 487		" time_stamp:%lld \n", q6_input.yuv_buf.phys, plist->buf.fd,
 488		input.client_data, input.time_stamp);
 489	ret = dal_call_f5(dvenc->q6_handle, VENC_DALRPC_QUEUE_INPUT,
 490		&q6_input, sizeof(q6_input));
 491
 492	if (ret != 0)
 493		pr_err("%s: Q6 queue_input failed (%d)\n", __func__,
 494		(int)ret);
 495	return ret;
 496}
 497
 498static int venc_fill_output(struct venc_dev *dvenc, void *argp)
 499{
 500	int ret = 0;
 501	struct venc_pmem buf;
 502	struct venc_output_buf q6_output;
 503	struct venc_pmem_list *plist;
 504	struct venc_buffer output;
 505
 506	ret = copy_from_user(&output, argp, sizeof(struct venc_buffer));
 507	if (ret) {
 508		pr_err("%s: copy_from_user failed\n", __func__);
 509		return ret;
 510	}
 511	ret = copy_from_user(&buf,
 512			       ((struct venc_buffer *)argp)->ptr_buffer,
 513			       sizeof(struct venc_pmem));
 514	if (ret) {
 515		pr_err("%s: copy_from_user failed\n", __func__);
 516		return ret;
 517	}
 518	plist =	venc_get_pmem_from_list(dvenc, buf.fd, buf.offset,
 519			VENC_BUFFER_TYPE_OUTPUT);
 520	if (NULL == plist) {
 521		plist = venc_add_pmem_to_list(dvenc, &buf,
 522				VENC_BUFFER_TYPE_OUTPUT);
 523		if (NULL == plist) {
 524			pr_err("%s: output buffer failed to add_to_pmem_list"
 525				"\n", __func__);
 526			return -EPERM;
 527		}
 528	}
 529	q6_output.bit_stream_buf.region = plist->buf.src;
 530	q6_output.bit_stream_buf.phys = (u32)plist->buf.paddr;
 531	q6_output.bit_stream_buf.size = plist->buf.size;
 532	q6_output.bit_stream_buf.offset = 0;
 533	q6_output.client_data = (u32)output.client_data;
 534	ret =
 535	    dal_call_f5(dvenc->q6_handle, VENC_DALRPC_QUEUE_OUTPUT, &q6_output,
 536			sizeof(q6_output));
 537	if (ret != 0)
 538		pr_err("%s: remote function failed (%d)\n", __func__, ret);
 539	return ret;
 540}
 541
 542static int venc_stop(struct venc_dev *dvenc)
 543{
 544	int ret = 0;
 545	struct venc_msg msg;
 546
 547	ret = dal_call_f0(dvenc->q6_handle, VENC_DALRPC_STOP, 1);
 548	if (ret) {
 549		pr_err("%s: remote runction failed (%d)\n", __func__, ret);
 550		msg.msg_code = VENC_MSG_STOP;
 551		msg.msg_data_size = 0;
 552		msg.status_code = VENC_S_EFAIL;
 553		venc_put_msg(dvenc, &msg);
 554	}
 555	return ret;
 556}
 557
 558static int venc_pause(struct venc_dev *dvenc)
 559{
 560	int ret = 0;
 561	struct venc_msg msg;
 562
 563	ret = dal_call_f0(dvenc->q6_handle, VENC_DALRPC_SUSPEND, 1);
 564	if (ret) {
 565		pr_err("%s: remote function failed (%d)\n", __func__, ret);
 566		msg.msg_code = VENC_MSG_PAUSE;
 567		msg.status_code = VENC_S_EFAIL;
 568		msg.msg_data_size = 0;
 569		venc_put_msg(dvenc, &msg);
 570	}
 571	return ret;
 572}
 573
 574static int venc_resume(struct venc_dev *dvenc)
 575{
 576	int ret = 0;
 577	struct venc_msg msg;
 578
 579	ret = dal_call_f0(dvenc->q6_handle, VENC_DALRPC_RESUME, 1);
 580	if (ret) {
 581		pr_err("%s: remote function failed (%d)\n", __func__, ret);
 582		msg.msg_code = VENC_MSG_RESUME;
 583		msg.msg_data_size = 0;
 584		msg.status_code = VENC_S_EFAIL;
 585		venc_put_msg(dvenc, &msg);
 586	}
 587	return ret;
 588}
 589
 590static int venc_flush(struct venc_dev *dvenc, void *argp)
 591{
 592	int ret = 0;
 593	struct venc_msg msg;
 594	union venc_msg_data smsg;
 595	int status = VENC_S_SUCCESS;
 596	struct venc_buffer_flush flush;
 597
 598	if (copy_from_user(&flush, argp, sizeof(struct venc_buffer_flush)))
 599		return -EFAULT;
 600	if (flush.flush_mode == VENC_FLUSH_ALL) {
 601		ret = dal_call_f0(dvenc->q6_handle, VENC_DALRPC_FLUSH, 1);
 602		if (ret)
 603			status = VENC_S_EFAIL;
 604	} else
 605		status = VENC_S_ENOTSUPP;
 606
 607	if (status != VENC_S_SUCCESS) {
 608		if ((flush.flush_mode == VENC_FLUSH_INPUT) ||
 609		     (flush.flush_mode == VENC_FLUSH_ALL)) {
 610			smsg.flush_ret.flush_mode = VENC_FLUSH_INPUT;
 611			msg.msg_data = smsg;
 612			msg.status_code = status;
 613			msg.msg_code = VENC_MSG_FLUSH;
 614			msg.msg_data_size = sizeof(union venc_msg_data);
 615			venc_put_msg(dvenc, &msg);
 616		}
 617		if (flush.flush_mode == VENC_FLUSH_OUTPUT ||
 618		     (flush.flush_mode == VENC_FLUSH_ALL)) {
 619			smsg.flush_ret.flush_mode = VENC_FLUSH_OUTPUT;
 620			msg.msg_data = smsg;
 621			msg.status_code = status;
 622			msg.msg_code = VENC_MSG_FLUSH;
 623			msg.msg_data_size = sizeof(union venc_msg_data);
 624			venc_put_msg(dvenc, &msg);
 625		}
 626		return -EIO;
 627	}
 628	return ret;
 629}
 630
 631static int venc_get_sequence_hdr(struct venc_dev *dvenc, void *argp)
 632{
 633	pr_err("%s not supported\n", __func__);
 634	return -EIO;
 635}
 636
 637static int venc_set_qp_range(struct venc_dev *dvenc, void *argp)
 638{
 639	int ret = 0;
 640	struct venc_qp_range qp;
 641
 642	ret = copy_from_user(&qp, argp, sizeof(struct venc_qp_range));
 643	if (ret) {
 644		pr_err("%s: copy_from_user failed\n", __func__);
 645		return ret;
 646	}
 647
 648	if (dvenc->state == VENC_STATE_START ||
 649		dvenc->state == VENC_STATE_PAUSE) {
 650		ret =
 651		    dal_call_f5(dvenc->q6_handle, VENC_DALRPC_UPDATE_QP_RANGE,
 652				&qp, sizeof(struct venc_qp_range));
 653		if (ret) {
 654			pr_err("%s: remote function failed (%d) \n", __func__,
 655				ret);
 656			return ret;
 657		}
 658	}
 659	return ret;
 660}
 661
 662static int venc_set_intra_period(struct venc_dev *dvenc, void *argp)
 663{
 664	int ret = 0;
 665	u32 pnum = 0;
 666
 667	ret = copy_from_user(&pnum, argp, sizeof(int));
 668	if (ret) {
 669		pr_err("%s: copy_from_user failed\n", __func__);
 670		return ret;
 671	}
 672	if (dvenc->state == VENC_STATE_START ||
 673		dvenc->state == VENC_STATE_PAUSE) {
 674		ret = dal_call_f0(dvenc->q6_handle,
 675			VENC_DALRPC_UPDATE_INTRA_PERIOD, pnum);
 676		if (ret)
 677			pr_err("%s: remote function failed (%d)\n", __func__,
 678				ret);
 679	}
 680	return ret;
 681}
 682
 683static int venc_set_intra_refresh(struct venc_dev *dvenc, void *argp)
 684{
 685	int ret = 0;
 686	u32 mb_num = 0;
 687
 688	ret = copy_from_user(&mb_num, argp, sizeof(int));
 689	if (ret) {
 690		pr_err("%s: copy_from_user failed\n", __func__);
 691		return ret;
 692	}
 693	if (dvenc->state == VENC_STATE_START ||
 694		dvenc->state == VENC_STATE_PAUSE) {
 695		ret = dal_call_f0(dvenc->q6_handle,
 696			VENC_DALRPC_UPDATE_INTRA_REFRESH, mb_num);
 697		if (ret)
 698			pr_err("%s: remote function failed (%d)\n", __func__,
 699				ret);
 700	}
 701	return ret;
 702}
 703
 704static int venc_set_frame_rate(struct venc_dev *dvenc, void *argp)
 705{
 706	int ret = 0;
 707	struct venc_frame_rate pdata;
 708	ret = copy_from_user(&pdata, argp, sizeof(struct venc_frame_rate));
 709	if (ret) {
 710		pr_err("%s: copy_from_user failed\n", __func__);
 711		return ret;
 712	}
 713	if (dvenc->state == VENC_STATE_START ||
 714		dvenc->state == VENC_STATE_PAUSE) {
 715		ret = dal_call_f5(dvenc->q6_handle,
 716				VENC_DALRPC_UPDATE_FRAME_RATE,
 717				(void *)&(pdata),
 718				sizeof(struct venc_frame_rate));
 719		if (ret)
 720			pr_err("%s: remote function failed (%d)\n", __func__,
 721				ret);
 722	}
 723	return ret;
 724}
 725
 726static int venc_set_target_bitrate(struct venc_dev *dvenc, void *argp)
 727{
 728	int ret = 0;
 729	u32 pdata = 0;
 730
 731	ret = copy_from_user(&pdata, argp, sizeof(int));
 732	if (ret) {
 733		pr_err("%s: copy_from_user failed\n", __func__);
 734		return ret;
 735	}
 736	if (dvenc->state == VENC_STATE_START ||
 737		dvenc->state == VENC_STATE_PAUSE) {
 738		ret = dal_call_f0(dvenc->q6_handle,
 739			VENC_DALRPC_UPDATE_BITRATE, pdata);
 740		if (ret)
 741			pr_err("%s: remote function failed (%d)\n", __func__,
 742				ret);
 743	}
 744	return ret;
 745}
 746
 747static int venc_request_iframe(struct venc_dev *dvenc)
 748{
 749	int ret = 0;
 750
 751	if (dvenc->state != VENC_STATE_START)
 752		return -EINVAL;
 753
 754	ret = dal_call_f0(dvenc->q6_handle, VENC_DALRPC_REQUEST_IFRAME, 1);
 755	if (ret)
 756		pr_err("%s: remote function failed (%d)\n", __func__, ret);
 757	return ret;
 758}
 759
 760static int venc_stop_read_msg(struct venc_dev *dvenc)
 761{
 762	struct venc_msg msg;
 763	int ret = 0;
 764
 765	msg.status_code = 0;
 766	msg.msg_code = VENC_MSG_STOP_READING_MSG;
 767	msg.msg_data_size = 0;
 768	venc_put_msg(dvenc, &msg);
 769	return ret;
 770}
 771
 772static int venc_q6_stop(struct venc_dev *dvenc)
 773{
 774	int ret = 0;
 775	struct venc_pmem_list *plist;
 776	unsigned long flags;
 777
 778	wake_up(&dvenc->venc_msg_evt);
 779	spin_lock_irqsave(&dvenc->venc_pmem_list_lock, flags);
 780	if (!dvenc->pmem_freed) {
 781		list_for_each_entry(plist, &dvenc->venc_pmem_list_head, list)
 782			put_pmem_file(plist->buf.file);
 783		dvenc->pmem_freed = 1;
 784	}
 785	spin_unlock_irqrestore(&dvenc->venc_pmem_list_lock, flags);
 786
 787	dvenc->state = VENC_STATE_STOP;
 788	return ret;
 789}
 790
 791static int venc_translate_error(enum venc_status_code q6_status)
 792{
 793	int ret = 0;
 794
 795	switch (q6_status) {
 796	case VENC_STATUS_SUCCESS:
 797		ret = VENC_S_SUCCESS;
 798		break;
 799	case VENC_STATUS_ERROR:
 800		ret = VENC_S_EFAIL;
 801		break;
 802	case VENC_STATUS_INVALID_STATE:
 803		ret = VENC_S_EINVALSTATE;
 804		break;
 805	case VENC_STATUS_FLUSHING:
 806		ret = VENC_S_EFLUSHED;
 807		break;
 808	case VENC_STATUS_INVALID_PARAM:
 809		ret = VENC_S_EBADPARAM;
 810		break;
 811	case VENC_STATUS_CMD_QUEUE_FULL:
 812		ret = VENC_S_ECMDQFULL;
 813		break;
 814	case VENC_STATUS_CRITICAL:
 815		ret = VENC_S_EFATAL;
 816		break;
 817	case VENC_STATUS_INSUFFICIENT_RESOURCES:
 818		ret = VENC_S_ENOHWRES;
 819		break;
 820	case VENC_STATUS_TIMEOUT:
 821		ret = VENC_S_ETIMEOUT;
 822		break;
 823	}
 824	if (q6_status != VENC_STATUS_SUCCESS)
 825		pr_err("%s: Q6 failed (%d)", __func__, (int)q6_status);
 826	return ret;
 827}
 828
 829static void venc_q6_callback(void *data, int len, void *cookie)
 830{
 831	int status = 0;
 832	struct venc_dev *dvenc = (struct venc_dev *)cookie;
 833	struct venc_msg_type *q6_msg = NULL;
 834	struct venc_msg msg, msg1;
 835	union venc_msg_data smsg1, smsg2;
 836	unsigned long msg_code = 0;
 837	struct venc_input_payload *pload1;
 838	struct venc_output_payload *pload2;
 839	uint32_t * tmp = (uint32_t *) data;
 840
 841	if (dvenc == NULL) {
 842		pr_err("%s: empty driver parameter\n", __func__);
 843		return;
 844	}
 845	if (tmp[2] == sizeof(struct venc_msg_type)) {
 846		q6_msg = (struct venc_msg_type *)&tmp[3];
 847	} else {
 848		pr_err("%s: callback with empty message (%d, %d)\n",
 849			__func__, tmp[2], sizeof(struct venc_msg_type));
 850		return;
 851	}
 852	msg.msg_data_size = 0;
 853	status = venc_translate_error(q6_msg->status);
 854	switch ((enum venc_event_type_enum)q6_msg->event) {
 855	case VENC_EVENT_START_STATUS:
 856		dvenc->state = VENC_STATE_START;
 857		msg_code = VENC_MSG_START;
 858		break;
 859	case VENC_EVENT_STOP_STATUS:
 860		venc_q6_stop(dvenc);
 861		msg_code = VENC_MSG_STOP;
 862		break;
 863	case VENC_EVENT_SUSPEND_STATUS:
 864		dvenc->state = VENC_STATE_PAUSE;
 865		msg_code = VENC_MSG_PAUSE;
 866		break;
 867	case VENC_EVENT_RESUME_STATUS:
 868		dvenc->state = VENC_STATE_START;
 869		msg_code = VENC_MSG_RESUME;
 870		break;
 871	case VENC_EVENT_FLUSH_STATUS:
 872		smsg1.flush_ret.flush_mode = VENC_FLUSH_INPUT;
 873		msg1.status_code = status;
 874		msg1.msg_code = VENC_MSG_FLUSH;
 875		msg1.msg_data = smsg1;
 876		msg1.msg_data_size = sizeof(union venc_msg_data);
 877		venc_put_msg(dvenc, &msg1);
 878		smsg2.flush_ret.flush_mode = VENC_FLUSH_OUTPUT;
 879		msg_code = VENC_MSG_FLUSH;
 880		msg.msg_data = smsg2;
 881		msg.msg_data_size = sizeof(union venc_msg_data);
 882		break;
 883	case VENC_EVENT_RELEASE_INPUT:
 884		pload1 = &((q6_msg->payload).input_payload);
 885		TRACE("Release_input: data: 0x%x \n", pload1->data);
 886		if (pload1 != NULL) {
 887			msg.msg_data.buf.client_data = pload1->data;
 888			msg_code = VENC_MSG_INPUT_BUFFER_DONE;
 889			msg.msg_data_size = sizeof(union venc_msg_data);
 890		}
 891		break;
 892	case VENC_EVENT_DELIVER_OUTPUT:
 893		pload2 = &((q6_msg->payload).output_payload);
 894		smsg1.buf.flags = 0;
 895		if (pload2->flags & VENC_FLAG_SYNC_FRAME)
 896			smsg1.buf.flags |= VENC_FLAG_SYNC_FRAME;
 897		if (pload2->flags & VENC_FLAG_CODEC_CONFIG)
 898			smsg1.buf.flags |= VENC_FLAG_CODEC_CONFIG;
 899		if (pload2->flags & VENC_FLAG_END_OF_FRAME)
 900			smsg1.buf.flags |= VENC_FLAG_END_OF_FRAME;
 901		if (pload2->flags & VENC_FLAG_EOS)
 902			smsg1.buf.flags |= VENC_FLAG_EOS;
 903		smsg1.buf.len = pload2->size;
 904		smsg1.buf.offset = 0;
 905		smsg1.buf.time_stamp = pload2->time_stamp;
 906		smsg1.buf.client_data = pload2->data;
 907		msg_code = VENC_MSG_OUTPUT_BUFFER_DONE;
 908		msg.msg_data = smsg1;
 909		msg.msg_data_size = sizeof(union venc_msg_data);
 910		break;
 911	default:
 912		pr_err("%s: invalid response from Q6 (%d)\n", __func__,
 913			(int)q6_msg->event);
 914		return;
 915	}
 916	msg.status_code = status;
 917	msg.msg_code = msg_code;
 918	venc_put_msg(dvenc, &msg);
 919	return;
 920}
 921
 922static int venc_get_version(struct venc_dev *dvenc, void *argp)
 923{
 924	struct venc_version ver_info;
 925	int ret = 0;
 926
 927	ver_info.major = VENC_GET_MAJOR_VERSION(VENC_INTERFACE_VERSION);
 928	ver_info.minor = VENC_GET_MINOR_VERSION(VENC_INTERFACE_VERSION);
 929
 930	ret = copy_to_user(((struct venc_version *)argp),
 931				&ver_info, sizeof(ver_info));
 932	if (ret)
 933		pr_err("%s failed to copy_to_user\n", __func__);
 934
 935	return ret;
 936
 937}
 938
 939static long q6venc_ioctl(struct file *file, u32 cmd,
 940			   unsigned long arg)
 941{
 942	long ret = 0;
 943	void __user *argp = (void __user *)arg;
 944	struct venc_dev *dvenc = file->private_data;
 945
 946	if (!dvenc || !dvenc->is_active)
 947		return -EPERM;
 948
 949	switch (cmd) {
 950	case VENC_IOCTL_SET_INPUT_BUFFER:
 951		ret = venc_set_buffer(dvenc, argp, VENC_BUFFER_TYPE_INPUT);
 952		break;
 953	case VENC_IOCTL_SET_OUTPUT_BUFFER:
 954		ret = venc_set_buffer(dvenc, argp, VENC_BUFFER_TYPE_OUTPUT);
 955		break;
 956	case VENC_IOCTL_GET_SEQUENCE_HDR:
 957		ret = venc_get_sequence_hdr(dvenc, argp);
 958		break;
 959	case VENC_IOCTL_SET_QP_RANGE:
 960		ret = venc_set_qp_range(dvenc, argp);
 961		break;
 962	case VENC_IOCTL_SET_INTRA_PERIOD:
 963		ret = venc_set_intra_period(dvenc, argp);
 964		break;
 965	case VENC_IOCTL_SET_INTRA_REFRESH:
 966		ret = venc_set_intra_refresh(dvenc, argp);
 967		break;
 968	case VENC_IOCTL_SET_FRAME_RATE:
 969		ret = venc_set_frame_rate(dvenc, argp);
 970		break;
 971	case VENC_IOCTL_SET_TARGET_BITRATE:
 972		ret = venc_set_target_bitrate(dvenc, argp);
 973		break;
 974	case VENC_IOCTL_CMD_REQUEST_IFRAME:
 975		if (dvenc->state == VENC_STATE_START)
 976			ret = venc_request_iframe(dvenc);
 977		break;
 978	case VENC_IOCTL_CMD_START:
 979		ret = venc_start(dvenc, argp);
 980		break;
 981	case VENC_IOCTL_CMD_STOP:
 982		ret = venc_stop(dvenc);
 983		break;
 984	case VENC_IOCTL_CMD_PAUSE:
 985		ret = venc_pause(dvenc);
 986		break;
 987	case VENC_IOCTL_CMD_RESUME:
 988		ret = venc_resume(dvenc);
 989		break;
 990	case VENC_IOCTL_CMD_ENCODE_FRAME:
 991		ret = venc_encode_frame(dvenc, argp);
 992		break;
 993	case VENC_IOCTL_CMD_FILL_OUTPUT_BUFFER:
 994		ret = venc_fill_output(dvenc, argp);
 995		break;
 996	case VENC_IOCTL_CMD_FLUSH:
 997		ret = venc_flush(dvenc, argp);
 998		break;
 999	case VENC_IOCTL_CMD_READ_NEXT_MSG:
1000		wait_event_interruptible(dvenc->venc_msg_evt,
1001					  venc_get_msg(dvenc, argp));
1002		break;
1003	case VENC_IOCTL_CMD_STOP_READ_MSG:
1004		ret = venc_stop_read_msg(dvenc);
1005		break;
1006	case VENC_IOCTL_GET_VERSION:
1007		ret = venc_get_version(dvenc, argp);
1008		break;
1009	default:
1010		pr_err("%s: invalid ioctl code (%d)\n", __func__, cmd);
1011		ret = -ENOTTY;
1012		break;
1013	}
1014	return ret;
1015}
1016
1017static int q6venc_open(struct inode *inode, struct file *file)
1018{
1019	int i;
1020	int ret = 0;
1021	struct venc_dev *dvenc;
1022	struct venc_msg_list *plist, *tmp;
1023	struct dal_info version_info;
1024
1025	dvenc = kzalloc(sizeof(struct venc_dev), GFP_KERNEL);
1026	if (!dvenc) {
1027		pr_err("%s: unable to allocate memory for struct venc_dev\n",
1028			__func__);
1029		return -ENOMEM;
1030	}
1031	file->private_data = dvenc;
1032	INIT_LIST_HEAD(&dvenc->venc_msg_list_head);
1033	INIT_LIST_HEAD(&dvenc->venc_msg_list_free);
1034	INIT_LIST_HEAD(&dvenc->venc_pmem_list_head);
1035	init_waitqueue_head(&dvenc->venc_msg_evt);
1036	spin_lock_init(&dvenc->venc_msg_list_lock);
1037	spin_lock_init(&dvenc->venc_pmem_list_lock);
1038	venc_ref++;
1039	for (i = 0; i < VENC_MSG_MAX; i++) {
1040		plist = kzalloc(sizeof(struct venc_msg_list), GFP_KERNEL);
1041		if (!plist) {
1042			pr_err("%s: kzalloc failed\n", __func__);
1043			ret = -ENOMEM;
1044			goto err_venc_create_msg_list;
1045		}
1046		list_add(&plist->list, &dvenc->venc_msg_list_free);
1047	}
1048	dvenc->q6_handle =
1049	    dal_attach(DALDEVICEID_VENC_DEVICE, DALDEVICEID_VENC_PORTNAME, 1,
1050		       venc_q6_callback, (void *)dvenc);
1051	if (!(dvenc->q6_handle)) {
1052		pr_err("%s: daldevice_attach failed (%d)\n", __func__, ret);
1053		goto err_venc_dal_attach;
1054	}
1055	ret = dal_call_f9(dvenc->q6_handle, DAL_OP_INFO, &version_info,
1056		sizeof(struct dal_info));
1057	if (ret) {
1058		pr_err("%s: failed to get version\n", __func__);
1059		goto err_venc_dal_open;
1060	}
1061	if (venc_check_version(VENC_INTERFACE_VERSION, version_info.version)) {
1062		pr_err("%s: driver version mismatch\n", __func__);
1063		goto err_venc_dal_open;
1064	}
1065	ret = dal_call_f0(dvenc->q6_handle, DAL_OP_OPEN, 1);
1066	if (ret) {
1067		pr_err("%s: dal_call_open failed (%d)\n", __func__, ret);
1068		goto err_venc_dal_open;
1069	}
1070	dvenc->state = VENC_STATE_STOP;
1071	dvenc->is_active = 1;
1072	prevent_sleep();
1073	return ret;
1074err_venc_dal_open:
1075	dal_detach(dvenc->q6_handle);
1076err_venc_dal_attach:
1077	list_for_each_entry_safe(plist, tmp, &dvenc->venc_msg_list_free, list) {
1078		list_del(&plist->list);
1079		kfree(plist);
1080	}
1081err_venc_create_msg_list:
1082	kfree(dvenc);
1083	venc_ref--;
1084	return ret;
1085}
1086
1087static int q6venc_release(struct inode *inode, struct file *file)
1088{
1089	int ret = 0;
1090	struct venc_msg_list *l, *n;
1091	struct venc_pmem_list *plist, *m;
1092	struct venc_dev *dvenc;
1093	unsigned long flags;
1094
1095	venc_ref--;
1096	dvenc = file->private_data;
1097	dvenc->is_active = 0;
1098	wake_up_all(&dvenc->venc_msg_evt);
1099	dal_call_f0(dvenc->q6_handle, VENC_DALRPC_STOP, 1);
1100	dal_call_f0(dvenc->q6_handle, DAL_OP_CLOSE, 1);
1101	dal_detach(dvenc->q6_handle);
1102	list_for_each_entry_safe(l, n, &dvenc->venc_msg_list_free, list) {
1103		list_del(&l->list);
1104		kfree(l);
1105	}
1106	list_for_each_entry_safe(l, n, &dvenc->venc_msg_list_head, list) {
1107		list_del(&l->list);
1108		kfree(l);
1109	}
1110	spin_lock_irqsave(&dvenc->venc_pmem_list_lock, flags);
1111	if (!dvenc->pmem_freed) {
1112		list_for_each_entry(plist, &dvenc->venc_pmem_list_head, list)
1113			put_pmem_file(plist->buf.file);
1114		dvenc->pmem_freed = 1;
1115	}
1116	spin_unlock_irqrestore(&dvenc->venc_pmem_list_lock, flags);
1117
1118	list_for_each_entry_safe(plist, m, &dvenc->venc_pmem_list_head, list) {
1119		list_del(&plist->list);
1120		kfree(plist);
1121	}
1122	kfree(dvenc);
1123	allow_sleep();
1124	return ret;
1125}
1126
1127const struct file_operations q6venc_fops = {
1128	.owner = THIS_MODULE,
1129	.open = q6venc_open,
1130	.release = q6venc_release,
1131	.unlocked_ioctl = q6venc_ioctl,
1132};
1133
1134static int __init q6venc_init(void)
1135{
1136	int ret = 0;
1137
1138	wake_lock_init(&idlelock, WAKE_LOCK_IDLE, "venc_idle");
1139	wake_lock_init(&wakelock, WAKE_LOCK_SUSPEND, "venc_suspend");
1140
1141	venc_device_p = kzalloc(sizeof(struct venc_dev), GFP_KERNEL);
1142	if (!venc_device_p) {
1143		pr_err("%s: unable to allocate memory for venc_device_p\n",
1144			__func__);
1145		return -ENOMEM;
1146	}
1147	ret = alloc_chrdev_region(&venc_dev_num, 0, 1, VENC_NAME);
1148	if (ret < 0) {
1149		pr_err("%s: alloc_chrdev_region failed (%d)\n", __func__,
1150			ret);
1151		return ret;
1152	}
1153	venc_class = class_create(THIS_MODULE, VENC_NAME);
1154	if (IS_ERR(venc_class)) {
1155		ret = PTR_ERR(venc_class);
1156		pr_err("%s: failed to create venc_class (%d)\n",
1157			__func__, ret);
1158		goto err_venc_class_create;
1159	}
1160	venc_device_p->class_devp =
1161	    device_create(venc_class, NULL, venc_dev_num, NULL,
1162			  VENC_NAME);
1163	if (IS_ERR(venc_device_p->class_devp)) {
1164		ret = PTR_ERR(venc_device_p->class_devp);
1165		pr_err("%s: failed to create class_device (%d)\n", __func__,
1166			ret);
1167		goto err_venc_class_device_create;
1168	}
1169	cdev_init(&cdev, &q6venc_fops);
1170	cdev.owner = THIS_MODULE;
1171	ret = cdev_add(&cdev, venc_dev_num, 1);
1172	if (ret < 0) {
1173		pr_err("%s: cdev_add failed (%d)\n", __func__, ret);
1174		goto err_venc_cdev_add;
1175	}
1176	init_waitqueue_head(&venc_device_p->venc_msg_evt);
1177	return ret;
1178
1179err_venc_cdev_add:
1180	device_destroy(venc_class, venc_dev_num);
1181err_venc_class_device_create:
1182	class_destroy(venc_class);
1183err_venc_class_create:
1184	unregister_chrdev_region(venc_dev_num, 1);
1185	return ret;
1186}
1187
1188static void __exit q6venc_exit(void)
1189{
1190	cdev_del(&(cdev));
1191	device_destroy(venc_class, venc_dev_num);
1192	class_destroy(venc_class);
1193	unregister_chrdev_region(venc_dev_num, 1);
1194}
1195
1196MODULE_LICENSE("GPL v2");
1197MODULE_DESCRIPTION("Video encoder driver for QDSP6");
1198MODULE_VERSION("2.0");
1199module_init(q6venc_init);
1200module_exit(q6venc_exit);