blob: 24d2117a8f9ce8d708bda8f6e944531babf668aa [file] [log] [blame]
Duy Truong790f06d2013-02-13 16:38:12 -08001/* Copyright (c) 2008-2010, The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
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 */
13
14/*
15#define DEBUG_TRACE_VDEC
16#define DEBUG
17*/
18
19#include <linux/slab.h>
20#include <linux/cdev.h>
21#include <linux/delay.h>
22#include <linux/file.h>
23#include <linux/fs.h>
24#include <linux/list.h>
25#include <linux/miscdevice.h>
26#include <linux/module.h>
27#include <linux/mutex.h>
28#include <linux/platform_device.h>
29#include <linux/sched.h>
30#include <linux/spinlock.h>
31#include <linux/uaccess.h>
32#include <linux/wakelock.h>
Stephen Boyd2fcabf92012-05-30 10:41:11 -070033#include <linux/pm_qos.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070034
35#include <linux/android_pmem.h>
36#include <linux/msm_q6vdec.h>
37
Stephen Boyd2fcabf92012-05-30 10:41:11 -070038#include <mach/cpuidle.h>
39
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070040#include "dal.h"
41
42#define DALDEVICEID_VDEC_DEVICE 0x02000026
43#define DALDEVICEID_VDEC_PORTNAME "DAL_AQ_VID"
44
45#define VDEC_INTERFACE_VERSION 0x00020000
46
47#define MAJOR_MASK 0xFFFF0000
48#define MINOR_MASK 0x0000FFFF
49
50#define VDEC_GET_MAJOR_VERSION(version) (((version)&MAJOR_MASK)>>16)
51
52#define VDEC_GET_MINOR_VERSION(version) ((version)&MINOR_MASK)
53
54#ifdef DEBUG_TRACE_VDEC
55#define TRACE(fmt,x...) \
56 do { pr_debug("%s:%d " fmt, __func__, __LINE__, ##x); } while (0)
57#else
58#define TRACE(fmt,x...) do { } while (0)
59#endif
60
61#define YAMATO_COLOR_FORMAT 0x02
62#define MAX_Q6_LOAD ((720*1280)/256) /* 720p */
63#define MAX_Q6_LOAD_YAMATO ((736*1280)/256)
64#define MAX_Q6_LOAD_VP6 ((800*480)/256)
65
66#define VDEC_MAX_PORTS 4
67
68/*
69 *why magic number 300?
70
71 *the Maximum size of the DAL payload is 512 bytes according to DAL protocol
72 *Initialize call to QDSP6 from scorpion need to send sequence header as part of
73 *the DAL payload. DAL payload to initialize contains the following
74
75 *1) configuration data- 52 bytes 2) length field of config data - 4 bytes
76 *3) sequence header data ( that is from the bit stream)
77 *4) length field for sequence header - 4 bytes
78 *5) length field for output structure - 4 bytes
79
80 *that left with 512 - 68 = 448 bytes. It is unusual that we get a sequence
81 *header with such a big length unless the bit stream has multiple sequence
82 *headers.We estimated 300 is good enough which gives enough room for rest
83 *of the payload and even reserves some space for future payload.
84 */
85
86#define VDEC_MAX_SEQ_HEADER_SIZE 300
87
88char *Q6Portnames[] = {
89"DAL_AQ_VID_0",
90"DAL_AQ_VID_1",
91"DAL_AQ_VID_2",
92"DAL_AQ_VID_3"
93};
94
95
96
97#define DALDEVICEID_VDEC_DEVICE_0 0x020000D2
98#define DALDEVICEID_VDEC_DEVICE_1 0x020000D3
99#define DALDEVICEID_VDEC_DEVICE_2 0x020000D4
100#define DALDEVICEID_VDEC_DEVICE_3 0x020000D5
101#define DALDEVICEID_VDEC_DEVICE_4 0x020000D6
102#define DALDEVICEID_VDEC_DEVICE_5 0x020000D7
103#define DALDEVICEID_VDEC_DEVICE_6 0x020000D8
104#define DALDEVICEID_VDEC_DEVICE_7 0x020000D9
105#define DALDEVICEID_VDEC_DEVICE_8 0x020000DA
106#define DALDEVICEID_VDEC_DEVICE_9 0x020000DB
107#define DALDEVICEID_VDEC_DEVICE_10 0x020000DC
108#define DALDEVICEID_VDEC_DEVICE_11 0x020000DD
109#define DALDEVICEID_VDEC_DEVICE_12 0x020000DE
110#define DALDEVICEID_VDEC_DEVICE_13 0x020000DF
111#define DALDEVICEID_VDEC_DEVICE_14 0x020000E0
112#define DALDEVICEID_VDEC_DEVICE_15 0x020000E1
113#define DALDEVICEID_VDEC_DEVICE_16 0x020000E2
114#define DALDEVICEID_VDEC_DEVICE_17 0x020000E3
115#define DALDEVICEID_VDEC_DEVICE_18 0x020000E4
116#define DALDEVICEID_VDEC_DEVICE_19 0x020000E5
117#define DALDEVICEID_VDEC_DEVICE_20 0x020000E6
118#define DALDEVICEID_VDEC_DEVICE_21 0x020000E7
119#define DALDEVICEID_VDEC_DEVICE_22 0x020000E8
120#define DALDEVICEID_VDEC_DEVICE_23 0x020000E9
121#define DALDEVICEID_VDEC_DEVICE_24 0x020000EA
122#define DALDEVICEID_VDEC_DEVICE_25 0x020000EB
123#define DALDEVICEID_VDEC_DEVICE_26 0x020000EC
124#define DALDEVICEID_VDEC_DEVICE_27 0x020000ED
125#define DALDEVICEID_VDEC_DEVICE_28 0x020000EE
126#define DALDEVICEID_VDEC_DEVICE_29 0x020000EF
127#define DALDEVICEID_VDEC_DEVICE_30 0x020000F0
128#define DALDEVICEID_VDEC_DEVICE_31 0x020000F1
129
130#define DALVDEC_MAX_DEVICE_IDS 32
131
132
133static int numOfPorts;
134
135
136static char loadOnPorts[VDEC_MAX_PORTS];
137
138static char deviceIdRegistry[DALVDEC_MAX_DEVICE_IDS];
139
140
141#define VDEC_DEVID_FREE 0
142#define VDEC_DEVID_OCCUPIED 1
143
144#define MAX_SUPPORTED_INSTANCES 6
145
146#define MAKEFOURCC(ch0, ch1, ch2, ch3) ((unsigned int)(unsigned char)(ch0) | \
147 ((unsigned int)(unsigned char)(ch1) << 8) | \
148 ((unsigned int)(unsigned char)(ch2) << 16) | \
149 ((unsigned int)(unsigned char)(ch3) << 24))
150
151#define FOURCC_MPEG4 MAKEFOURCC('m', 'p', '4', 'v')
152#define FOURCC_H263 MAKEFOURCC('h', '2', '6', '3')
153#define FOURCC_H264 MAKEFOURCC('h', '2', '6', '4')
154#define FOURCC_VC1 MAKEFOURCC('w', 'm', 'v', '3')
155#define FOURCC_DIVX MAKEFOURCC('D', 'I', 'V', 'X')
156#define FOURCC_SPARK MAKEFOURCC('F', 'L', 'V', '1')
157#define FOURCC_VP6 MAKEFOURCC('V', 'P', '6', '0')
158
159/* static struct vdec_data *multiInstances[MAX_SUPPORTED_INSTANCES];*/
160
161static int totalPlaybackQ6load;
162static int totalTnailQ6load;
163
164#define FLAG_THUMBNAIL_MODE 0x8
165#define MAX_TNAILS 3
166
167#define TRUE 1
168#define FALSE 0
169
170enum {
171 VDEC_DALRPC_INITIALIZE = DAL_OP_FIRST_DEVICE_API,
172 VDEC_DALRPC_SETBUFFERS,
173 VDEC_DALRPC_FREEBUFFERS,
174 VDEC_DALRPC_QUEUE,
175 VDEC_DALRPC_SIGEOFSTREAM,
176 VDEC_DALRPC_FLUSH,
177 VDEC_DALRPC_REUSEFRAMEBUFFER,
178 VDEC_DALRPC_GETDECATTRIBUTES,
179 VDEC_DALRPC_SUSPEND,
180 VDEC_DALRPC_RESUME,
181 VDEC_DALRPC_INITIALIZE_00,
182 VDEC_DALRPC_GETINTERNALBUFFERREQ,
183 VDEC_DALRPC_SETBUFFERS_00,
184 VDEC_DALRPC_FREEBUFFERS_00,
185 VDEC_DALRPC_GETPROPERTY,
186 VDEC_DALRPC_SETPROPERTY,
187 VDEC_DALRPC_GETDECATTRIBUTES_00,
188 VDEC_DALRPC_PERFORMANCE_CHANGE_REQUEST
189};
190
191enum {
192 VDEC_ASYNCMSG_DECODE_DONE = 0xdec0de00,
193 VDEC_ASYNCMSG_REUSE_FRAME,
194};
195
196struct vdec_init_cfg {
197 u32 decode_done_evt;
198 u32 reuse_frame_evt;
199 struct vdec_config cfg;
200};
201
202struct vdec_buffer_status {
203 u32 data;
204 u32 status;
205};
206
207#define VDEC_MSG_MAX 128
208
209struct vdec_msg_list {
210 struct list_head list;
211 struct vdec_msg vdec_msg;
212};
213
214struct vdec_mem_info {
215 u32 buf_type;
216 u32 id;
217 unsigned long phys_addr;
218 unsigned long len;
219 struct file *file;
220};
221
222struct vdec_mem_list {
223 struct list_head list;
224 struct vdec_mem_info mem;
225};
226
227struct videoStreamDetails{
228 int height;
229 int width;
230 unsigned int fourcc;
231 int Q6usage;
232 bool isThisTnail;
233 bool isTnailGranted;
234};
235
236struct vdec_data {
237 struct dal_client *vdec_handle;
238 unsigned int Q6deviceId;
239 struct videoStreamDetails streamDetails;
240 struct list_head vdec_msg_list_head;
241 struct list_head vdec_msg_list_free;
242 wait_queue_head_t vdec_msg_evt;
243 spinlock_t vdec_list_lock;
244 struct list_head vdec_mem_list_head;
245 spinlock_t vdec_mem_list_lock;
246 int mem_initialized;
247 int running;
248 int close_decode;
249};
250
251static struct class *driver_class;
252static dev_t vdec_device_no;
253static struct cdev vdec_cdev;
254static int ref_cnt;
255static DEFINE_MUTEX(vdec_ref_lock);
256
257static DEFINE_MUTEX(idlecount_lock);
258
259static DEFINE_MUTEX(vdec_rm_lock);
260
261static int idlecount;
262static struct wake_lock wakelock;
Stephen Boyd2fcabf92012-05-30 10:41:11 -0700263static struct pm_qos_request pm_qos_req;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700264
265static void prevent_sleep(void)
266{
267 mutex_lock(&idlecount_lock);
268 if (++idlecount == 1) {
Stephen Boyd2fcabf92012-05-30 10:41:11 -0700269 pm_qos_update_request(&pm_qos_req,
270 msm_cpuidle_get_deep_idle_latency());
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700271 wake_lock(&wakelock);
272 }
273 mutex_unlock(&idlecount_lock);
274}
275
276static void allow_sleep(void)
277{
278 mutex_lock(&idlecount_lock);
279 if (--idlecount == 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700280 wake_unlock(&wakelock);
Stephen Boyd2fcabf92012-05-30 10:41:11 -0700281 pm_qos_update_request(&pm_qos_req, PM_QOS_DEFAULT_VALUE);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700282 }
283 mutex_unlock(&idlecount_lock);
284}
285
286static inline int vdec_check_version(u32 client, u32 server)
287{
288 int ret = -EINVAL;
289 if ((VDEC_GET_MAJOR_VERSION(client) == VDEC_GET_MAJOR_VERSION(server))
290 && (VDEC_GET_MINOR_VERSION(client) <=
291 VDEC_GET_MINOR_VERSION(server)))
292 ret = 0;
293 return ret;
294}
295
296static int vdec_get_msg(struct vdec_data *vd, void *msg)
297{
298 struct vdec_msg_list *l;
299 unsigned long flags;
300 int ret = 0;
301
302 if (!vd->running)
303 return -EPERM;
304
305 spin_lock_irqsave(&vd->vdec_list_lock, flags);
306 list_for_each_entry_reverse(l, &vd->vdec_msg_list_head, list) {
307 if (copy_to_user(msg, &l->vdec_msg, sizeof(struct vdec_msg)))
308 pr_err("vdec_get_msg failed to copy_to_user!\n");
309 if (l->vdec_msg.id == VDEC_MSG_REUSEINPUTBUFFER)
310 TRACE("reuse_input_buffer %d\n", l->vdec_msg.buf_id);
311 else if (l->vdec_msg.id == VDEC_MSG_FRAMEDONE)
312 TRACE("frame_done (stat=%d)\n",
313 l->vdec_msg.vfr_info.status);
314 else
315 TRACE("unknown msg (msgid=%d)\n", l->vdec_msg.id);
316 list_del(&l->list);
317 list_add(&l->list, &vd->vdec_msg_list_free);
318 ret = 1;
319 break;
320 }
321 spin_unlock_irqrestore(&vd->vdec_list_lock, flags);
322
323 if (vd->close_decode)
324 ret = 1;
325
326 return ret;
327}
328
329static void vdec_put_msg(struct vdec_data *vd, struct vdec_msg *msg)
330{
331 struct vdec_msg_list *l;
332 unsigned long flags;
333 int found = 0;
334
335 spin_lock_irqsave(&vd->vdec_list_lock, flags);
336 list_for_each_entry(l, &vd->vdec_msg_list_free, list) {
337 memcpy(&l->vdec_msg, msg, sizeof(struct vdec_msg));
338 list_del(&l->list);
339 list_add(&l->list, &vd->vdec_msg_list_head);
340 found = 1;
341 break;
342 }
343 spin_unlock_irqrestore(&vd->vdec_list_lock, flags);
344
345 if (found)
346 wake_up(&vd->vdec_msg_evt);
347 else
348 pr_err("vdec_put_msg can't find free list!\n");
349}
350
351static struct vdec_mem_list *vdec_get_mem_from_list(struct vdec_data *vd,
352 u32 pmem_id, u32 buf_type)
353{
354 struct vdec_mem_list *l;
355 unsigned long flags;
356 int found = 0;
357
358 spin_lock_irqsave(&vd->vdec_mem_list_lock, flags);
359 list_for_each_entry(l, &vd->vdec_mem_list_head, list) {
360 if (l->mem.buf_type == buf_type && l->mem.id == pmem_id) {
361 found = 1;
362 break;
363 }
364 }
365 spin_unlock_irqrestore(&vd->vdec_mem_list_lock, flags);
366
367 if (found)
368 return l;
369 else
370 return NULL;
371
372}
373static int vdec_setproperty(struct vdec_data *vd, void *argp)
374{
375 struct vdec_property_info property;
376 int res;
377
378 if (copy_from_user(&property, argp, sizeof(struct vdec_property_info)))
379 return -1;
380
381 res = dal_call_f6(vd->vdec_handle, VDEC_DALRPC_SETPROPERTY,
382 property.id, &(property.property), sizeof(union vdec_property));
383 if (res)
384 TRACE("Set Property failed");
385 else
386 TRACE("Set Property succeeded");
387 return res;
388}
389static int vdec_getproperty(struct vdec_data *vd, void *argp)
390{
391 int res;
392 union vdec_property property = {0};
393
394 res = dal_call_f11(vd->vdec_handle, VDEC_DALRPC_GETPROPERTY,
395 ((struct vdec_property_info *)argp)->id, &property,
396 sizeof(union vdec_property));
397
398 if (res)
399 TRACE("get Property failed");
400 else
401 TRACE("get Property succeeded");
402
403 res = copy_to_user(
404 (&((struct vdec_property_info *)argp)->property),
405 &property, sizeof(property));
406
407 return res;
408}
409static int vdec_performance_change_request(struct vdec_data *vd, void* argp)
410{
411 u32 request_type;
412 int ret;
413
414 ret = copy_from_user(&request_type, argp, sizeof(request_type));
415 if (ret) {
416 pr_err("%s: copy_from_user failed\n", __func__);
417 return ret;
418 }
419 ret = dal_call_f0(vd->vdec_handle,
420 VDEC_DALRPC_PERFORMANCE_CHANGE_REQUEST,
421 request_type);
422 if (ret) {
423 pr_err("%s: remote function failed (%d)\n", __func__, ret);
424 return ret;
425 }
426 return ret;
427}
428
429#ifdef TRACE_PORTS
430static void printportsanddeviceids(void)
431{
432 int i;
433
434 pr_err("\n\n%s:loadOnPorts", __func__);
435 for (i = 0; i < numOfPorts; i++)
436 pr_err("\t%d", loadOnPorts[i]);
437
438 pr_err("\n\n");
439
440 pr_err("\n\n%s:Devids", __func__);
441 for (i = 0; i < DALVDEC_MAX_DEVICE_IDS; i++)
442 pr_err("Devid[%d]:%d\n", i, deviceIdRegistry[i]);
443
444
445 pr_err("\n\n");
446}
447#endif /*TRACE_PORTS*/
448
449
450/*
451 *
452 * This method is used to get the number of ports supported on the Q6
453 *
454 */
455static int vdec_get_numberofq6ports(void)
456{
457 struct dal_client *vdec_handle = NULL;
458 int retval = 0;
459 union vdec_property property = {0};
460
461 vdec_handle = dal_attach(DALDEVICEID_VDEC_DEVICE,
462 DALDEVICEID_VDEC_PORTNAME, 1, NULL, NULL);
463 if (!vdec_handle) {
464 pr_err("%s: failed to attach\n", __func__);
465 return 1;/* default setting */
466 }
467
468 retval = dal_call_f6(vdec_handle, VDEC_DALRPC_GETPROPERTY,
469 VDEC_NUM_DAL_PORTS, (void *)&property, sizeof(union vdec_property));
470 if (retval) {
471 pr_err("%s: Q6get prperty failed\n", __func__);
472 return 1;/* default setting */
473 }
474
475 dal_detach(vdec_handle);
476 return property.num_dal_ports ;
477}
478
479
480/**
481 * This method is used to get the find the least loaded port and a corresponding
482 * free device id in that port.
483 *
484 * Prerequisite: vdec_open should have been called.
485 *
486 * @param[in] deviceid
487 * device id will be populated here.
488 *
489 * @param[in] portname
490 * portname will be populated here.
491 */
492static void vdec_get_next_portanddevid(int *deviceid, char **portname)
493{
494
495 int i = 0;
496 int leastLoad = 0;
497 int leastLoadedIndex = 0;
498
499 if (0 == numOfPorts) {
500 numOfPorts = vdec_get_numberofq6ports();
501 pr_err("%s: Q6get numOfPorts %d\n", __func__, numOfPorts);
502 numOfPorts = 4;
503 /*fix: me currently hard coded to 4 as
504 *the Q6 getproperty is failing
505 */
506 }
507
508 if ((NULL == deviceid) || (NULL == portname))
509 return;
510 else
511 *deviceid = 0; /* init value */
512
513 if (numOfPorts > 1) {
514 /* multi ports mode*/
515
516 /* find the least loaded port*/
517 for (i = 1, leastLoad = loadOnPorts[0], leastLoadedIndex = 0;
518 i < numOfPorts; i++) {
519 if (leastLoad > loadOnPorts[i]) {
520 leastLoadedIndex = i;
521 leastLoad = loadOnPorts[i];
522 }
523 }
524
525 /* register the load */
526 loadOnPorts[leastLoadedIndex]++;
527 *portname = Q6Portnames[leastLoadedIndex];
528
529 /* find a free device id corresponding to the port*/
530 for (i = leastLoadedIndex; i < DALVDEC_MAX_DEVICE_IDS;
531 i += numOfPorts) {
532 if (VDEC_DEVID_FREE == deviceIdRegistry[i]) {
533 deviceIdRegistry[i] = VDEC_DEVID_OCCUPIED;
534 *deviceid = DALDEVICEID_VDEC_DEVICE_0 + i;
535 break;
536 }
537 }
538
539#ifdef TRACE_PORTS
540 printportsanddeviceids();
541#endif /*TRACE_PORTS*/
542 } else if (1 == numOfPorts) {
543 /* single port mode */
544 *deviceid = DALDEVICEID_VDEC_DEVICE;
545 *portname = DALDEVICEID_VDEC_PORTNAME;
546 } else if (numOfPorts <= 0) {
547 pr_err("%s: FATAL error numOfPorts cannot be \
548 less than or equal to zero\n", __func__);
549 }
550
551
552}
553
554
555/**
556 * This method frees up the used dev id and decrements the port load.
557 *
558 */
559
560static void vdec_freeup_portanddevid(int deviceid)
561{
562
563 if (numOfPorts > 1) {
564 /* multi ports mode*/
565 if (VDEC_DEVID_FREE ==
566 deviceIdRegistry[deviceid - DALDEVICEID_VDEC_DEVICE_0])
567 pr_err("device id cannot be already free\n");
568 deviceIdRegistry[deviceid - DALDEVICEID_VDEC_DEVICE_0] =
569 VDEC_DEVID_FREE;
570
571 loadOnPorts[(deviceid - DALDEVICEID_VDEC_DEVICE_0)
572 % numOfPorts]--;
573
574 if (loadOnPorts[(deviceid - DALDEVICEID_VDEC_DEVICE_0)
575 % numOfPorts] < 0)
576 pr_err("Warning:load cannot be negative\n");
577
578 pr_err("dettaching on deviceid %x portname %s\n", deviceid,
579 Q6Portnames[(deviceid - DALDEVICEID_VDEC_DEVICE_0)
580 % numOfPorts]);
581
582#ifdef TRACE_PORTS
583 printportsanddeviceids();
584#endif /*TRACE_PORTS*/
585 } else {
586 /*single port mode, nothing to be done here*/
587 }
588
589}
590
591
592/**
593 * This method validates whether a new instance can be houred or not.
594 *
595 */
596static int vdec_rm_checkWithRm(struct vdec_data *vdecInstance,
597 unsigned int color_format)
598{
599
600 unsigned int maxQ6load = 0;/* in the units of macro blocks per second */
601 unsigned int currentq6load = 0;
602 struct videoStreamDetails *streamDetails = &vdecInstance->streamDetails;
603
604
605
606 if (streamDetails->isThisTnail) {
607 if (totalTnailQ6load < MAX_TNAILS) {
608
609 totalTnailQ6load++;
610 streamDetails->isTnailGranted = TRUE;
611 pr_info("%s: thumbnail granted %d\n", __func__,
612 totalTnailQ6load);
613 return 0;
614
615 } else {
616
617 pr_err("%s: thumbnails load max this instance cannot \
618 be supported\n", __func__);
619 streamDetails->isTnailGranted = FALSE;
620 return -ENOSPC;
621
622 }
623 }
624
625 /* calculate the Q6 percentage instance would need */
626 if ((streamDetails->fourcc == FOURCC_MPEG4) ||
627 (streamDetails->fourcc == FOURCC_H264) ||
628 (streamDetails->fourcc == FOURCC_DIVX) ||
629 (streamDetails->fourcc == FOURCC_VC1) ||
630 (streamDetails->fourcc == FOURCC_SPARK) ||
631 (streamDetails->fourcc == FOURCC_H263)
632 ){
633
634 /* is yamato color format,
635 Rounds the H & W --> mutiple of 32 */
636 if (color_format == YAMATO_COLOR_FORMAT)
637 maxQ6load = MAX_Q6_LOAD_YAMATO;
638 else
639 maxQ6load = MAX_Q6_LOAD; /* 720p */
640
641 } else if (streamDetails->fourcc == FOURCC_VP6) {
642
643 maxQ6load = MAX_Q6_LOAD_VP6; /* FWVGA */
644
645 } else {
646
647 pr_err("%s: unknown fourcc %d maxQ6load %u\n", __func__,
648 streamDetails->fourcc, maxQ6load);
649 return -EINVAL;
650
651 }
652
653 currentq6load = ((streamDetails->height)*(streamDetails->width) / 256);
654 currentq6load = ((currentq6load * 100)/maxQ6load);
655 if ((currentq6load+totalPlaybackQ6load) > 100) {
656 /* reject this instance */
657 pr_err("%s: too much Q6load [cur+tot] = [%d + %d] = %d",
658 __func__, currentq6load, totalPlaybackQ6load,
659 (currentq6load+totalPlaybackQ6load));
660 pr_err("rejecting the instance,[WxH] = [%d x %d],color_fmt=0x%x\n",
661 streamDetails->width, streamDetails->height, color_format);
662 pr_err("VDEC_fmt=%s\n", (char *)(&streamDetails->fourcc));
663 streamDetails->Q6usage = 0;
664 return -ENOSPC;
665 }
666
667 totalPlaybackQ6load += currentq6load;
668 streamDetails->Q6usage = currentq6load;
669
670 pr_info("%s: adding a load [%d%%] bringing total Q6load to [%d%%]\n",
671 __func__, currentq6load, totalPlaybackQ6load);
672
673 return 0;
674}
675
676
677static int vdec_initialize(struct vdec_data *vd, void *argp)
678{
679 struct vdec_config_sps vdec_cfg_sps;
680 struct vdec_init_cfg vi_cfg;
681 struct vdec_buf_req vdec_buf_req;
682 struct u8 *header;
683 int ret = 0;
684
685 ret = copy_from_user(&vdec_cfg_sps,
686 &((struct vdec_init *)argp)->sps_cfg,
687 sizeof(vdec_cfg_sps));
688
689 if (ret) {
690 pr_err("%s: copy_from_user failed\n", __func__);
691 return ret;
692 }
693
694 vi_cfg.decode_done_evt = VDEC_ASYNCMSG_DECODE_DONE;
695 vi_cfg.reuse_frame_evt = VDEC_ASYNCMSG_REUSE_FRAME;
696 memcpy(&vi_cfg.cfg, &vdec_cfg_sps.cfg, sizeof(struct vdec_config));
697
698 /*
699 * restricting the max value of the seq header
700 */
701 if (vdec_cfg_sps.seq.len > VDEC_MAX_SEQ_HEADER_SIZE)
702 vdec_cfg_sps.seq.len = VDEC_MAX_SEQ_HEADER_SIZE;
703
704 header = kmalloc(vdec_cfg_sps.seq.len, GFP_KERNEL);
705 if (!header) {
706 pr_err("%s: kmalloc failed\n", __func__);
707 return -ENOMEM;
708 }
709
710 ret = copy_from_user(header,
711 ((struct vdec_init *)argp)->sps_cfg.seq.header,
712 vdec_cfg_sps.seq.len);
713
714 if (ret) {
715 pr_err("%s: copy_from_user failed\n", __func__);
716 kfree(header);
717 return ret;
718 }
719
720 TRACE("vi_cfg: handle=%p fourcc=0x%x w=%d h=%d order=%d notify_en=%d "
721 "vc1_rb=%d h264_sd=%d h264_nls=%d pp_flag=%d fruc_en=%d\n",
722 vd->vdec_handle, vi_cfg.cfg.fourcc, vi_cfg.cfg.width,
723 vi_cfg.cfg.height, vi_cfg.cfg.order, vi_cfg.cfg.notify_enable,
724 vi_cfg.cfg.vc1_rowbase, vi_cfg.cfg.h264_startcode_detect,
725 vi_cfg.cfg.h264_nal_len_size, vi_cfg.cfg.postproc_flag,
726 vi_cfg.cfg.fruc_enable);
727
728 vd->streamDetails.height = vi_cfg.cfg.height;
729 vd->streamDetails.width = vi_cfg.cfg.width;
730 vd->streamDetails.fourcc = vi_cfg.cfg.fourcc;
731 if (FLAG_THUMBNAIL_MODE == vi_cfg.cfg.postproc_flag)
732 vd->streamDetails.isThisTnail = TRUE;
733 else
734 vd->streamDetails.isThisTnail = FALSE;
735
736 mutex_lock(&vdec_rm_lock);
737 ret = vdec_rm_checkWithRm(vd, vi_cfg.cfg.color_format);
738 mutex_unlock(&vdec_rm_lock);
739 if (ret)
740 return ret;
741
742 ret = dal_call_f13(vd->vdec_handle, VDEC_DALRPC_INITIALIZE,
743 &vi_cfg, sizeof(vi_cfg),
744 header, vdec_cfg_sps.seq.len,
745 &vdec_buf_req, sizeof(vdec_buf_req));
746
747 kfree(header);
748
749 if (ret)
750 pr_err("%s: remote function failed (%d)\n", __func__, ret);
751 else
752 ret = copy_to_user(((struct vdec_init *)argp)->buf_req,
753 &vdec_buf_req, sizeof(vdec_buf_req));
754
755 vd->close_decode = 0;
756 return ret;
757}
758
759static void vdec_rm_freeupResources(struct vdec_data *vdecInstance)
760{
761 struct videoStreamDetails *streamDetails = &vdecInstance->streamDetails;
762
763
764
765 if ((streamDetails->isThisTnail) &&
766 (streamDetails->isTnailGranted)) {
767
768 totalTnailQ6load--;
769 pr_info("%s: Thumbnail released %d\n", __func__,
770 totalTnailQ6load);
771
772 } else if (streamDetails->Q6usage > 0) {
773
774 totalPlaybackQ6load -= streamDetails->Q6usage;
775 if (totalPlaybackQ6load < 0)
776 pr_err("Warning:Q6load cannot be negative\n");
777
778 pr_info("%s:Releasing [%d%%] of Q6load from a total of [%d%%]\n"
779 , __func__, streamDetails->Q6usage,
780 (streamDetails->Q6usage+totalPlaybackQ6load));
781 }
782
783}
784
785static int vdec_setbuffers(struct vdec_data *vd, void *argp)
786{
787 struct vdec_buffer vmem;
788 struct vdec_mem_list *l;
789 unsigned long vstart;
790 unsigned long flags;
791 struct {
792 uint32_t size;
793 struct vdec_buf_info buf;
794 } rpc;
795 uint32_t res;
796
797 int ret = 0;
798
799 vd->mem_initialized = 0;
800
801 ret = copy_from_user(&vmem, argp, sizeof(vmem));
802 if (ret) {
803 pr_err("%s: copy_from_user failed\n", __func__);
804 return ret;
805 }
806
807 l = kzalloc(sizeof(struct vdec_mem_list), GFP_KERNEL);
808 if (!l) {
809 pr_err("%s: kzalloc failed!\n", __func__);
810 return -ENOMEM;
811 }
812
813 l->mem.id = vmem.pmem_id;
814 l->mem.buf_type = vmem.buf.buf_type;
815
816 ret = get_pmem_file(l->mem.id, &l->mem.phys_addr, &vstart,
817 &l->mem.len, &l->mem.file);
818 if (ret) {
819 pr_err("%s: get_pmem_fd failed\n", __func__);
820 goto err_get_pmem_file;
821 }
822
823 TRACE("pmem_id=%d (phys=0x%08lx len=0x%lx) buftype=%d num_buf=%d "
824 "islast=%d src_id=%d offset=0x%08x size=0x%x\n",
825 vmem.pmem_id, l->mem.phys_addr, l->mem.len,
826 vmem.buf.buf_type, vmem.buf.num_buf, vmem.buf.islast,
827 vmem.buf.region.src_id, vmem.buf.region.offset,
828 vmem.buf.region.size);
829
830 /* input buffers */
831 if ((vmem.buf.region.offset + vmem.buf.region.size) > l->mem.len) {
832 pr_err("%s: invalid input buffer offset!\n", __func__);
833 ret = -EINVAL;
834 goto err_bad_offset;
835
836 }
837 vmem.buf.region.offset += l->mem.phys_addr;
838
839 rpc.size = sizeof(vmem.buf);
840 memcpy(&rpc.buf, &vmem.buf, sizeof(struct vdec_buf_info));
841
842
843 ret = dal_call(vd->vdec_handle, VDEC_DALRPC_SETBUFFERS, 5,
844 &rpc, sizeof(rpc), &res, sizeof(res));
845
846 if (ret < 4) {
847 pr_err("%s: remote function failed (%d)\n", __func__, ret);
848 ret = -EIO;
849 goto err_dal_call;
850 }
851
852 spin_lock_irqsave(&vd->vdec_mem_list_lock, flags);
853 list_add(&l->list, &vd->vdec_mem_list_head);
854 spin_unlock_irqrestore(&vd->vdec_mem_list_lock, flags);
855
856 vd->mem_initialized = 1;
857 return ret;
858
859err_dal_call:
860err_bad_offset:
861 put_pmem_file(l->mem.file);
862err_get_pmem_file:
863 kfree(l);
864 return ret;
865}
866
867static int vdec_queue(struct vdec_data *vd, void *argp)
868{
869 struct {
870 uint32_t size;
871 struct vdec_input_buf_info buf_info;
872 uint32_t osize;
873 } rpc;
874 struct vdec_mem_list *l;
875 struct {
876 uint32_t result;
877 uint32_t size;
878 struct vdec_queue_status status;
879 } rpc_res;
880
881 u32 pmem_id;
882 int ret = 0;
883
884 if (!vd->mem_initialized) {
885 pr_err("%s: memory is not being initialized!\n", __func__);
886 return -EPERM;
887 }
888
889 ret = copy_from_user(&rpc.buf_info,
890 &((struct vdec_input_buf *)argp)->buffer,
891 sizeof(rpc.buf_info));
892 if (ret) {
893 pr_err("%s: copy_from_user failed\n", __func__);
894 return ret;
895 }
896
897 ret = copy_from_user(&pmem_id,
898 &((struct vdec_input_buf *)argp)->pmem_id,
899 sizeof(u32));
900 if (ret) {
901 pr_err("%s: copy_from_user failed\n", __func__);
902 return ret;
903 }
904
905 l = vdec_get_mem_from_list(vd, pmem_id, VDEC_BUFFER_TYPE_INPUT);
906
907 if (NULL == l) {
908 pr_err("%s: not able to find the buffer from list\n", __func__);
909 return -EPERM;
910 }
911
912 if ((rpc.buf_info.size + rpc.buf_info.offset) >= l->mem.len) {
913 pr_err("%s: invalid queue buffer offset!\n", __func__);
914 return -EINVAL;
915 }
916
917 rpc.buf_info.offset += l->mem.phys_addr;
918 rpc.size = sizeof(struct vdec_input_buf_info);
919 rpc.osize = sizeof(struct vdec_queue_status);
920
921 /* complete the writes to the buffer */
922 wmb();
923 ret = dal_call(vd->vdec_handle, VDEC_DALRPC_QUEUE, 8,
924 &rpc, sizeof(rpc), &rpc_res, sizeof(rpc_res));
925 if (ret < 4) {
926 pr_err("%s: remote function failed (%d)\n", __func__, ret);
927 ret = -EIO;
928 }
929 return ret;
930}
931
932static int vdec_reuse_framebuffer(struct vdec_data *vd, void *argp)
933{
934 u32 buf_id;
935 int ret = 0;
936
937 ret = copy_from_user(&buf_id, argp, sizeof(buf_id));
938 if (ret) {
939 pr_err("%s: copy_from_user failed\n", __func__);
940 return ret;
941 }
942
943 ret = dal_call_f0(vd->vdec_handle, VDEC_DALRPC_REUSEFRAMEBUFFER,
944 buf_id);
945 if (ret)
946 pr_err("%s: remote function failed (%d)\n", __func__, ret);
947
948 return ret;
949}
950
951static int vdec_flush(struct vdec_data *vd, void *argp)
952{
953 u32 flush_type;
954 int ret = 0;
955
956 if (!vd->mem_initialized) {
957 pr_err("%s: memory is not being initialized!\n", __func__);
958 return -EPERM;
959 }
960
961 ret = copy_from_user(&flush_type, argp, sizeof(flush_type));
962 if (ret) {
963 pr_err("%s: copy_from_user failed\n", __func__);
964 return ret;
965 }
966
967 TRACE("flush_type=%d\n", flush_type);
968 ret = dal_call_f0(vd->vdec_handle, VDEC_DALRPC_FLUSH, flush_type);
969 if (ret) {
970 pr_err("%s: remote function failed (%d)\n", __func__, ret);
971 return ret;
972 }
973
974 return ret;
975}
976
977static int vdec_close(struct vdec_data *vd, void *argp)
978{
979 struct vdec_mem_list *l;
980 int ret = 0;
981
982 pr_info("q6vdec_close()\n");
983 vd->close_decode = 1;
984 wake_up(&vd->vdec_msg_evt);
985
986 ret = dal_call_f0(vd->vdec_handle, DAL_OP_CLOSE, 0);
987 if (ret)
988 pr_err("%s: failed to close daldevice (%d)\n", __func__, ret);
989
990 if (vd->mem_initialized) {
991 list_for_each_entry(l, &vd->vdec_mem_list_head, list)
992 put_pmem_file(l->mem.file);
993 }
994
995 return ret;
996}
997static int vdec_getdecattributes(struct vdec_data *vd, void *argp)
998{
999 struct {
1000 uint32_t status;
1001 uint32_t size;
1002 struct vdec_dec_attributes dec_attr;
1003 } rpc;
1004 uint32_t inp;
1005 int ret = 0;
1006 inp = sizeof(struct vdec_dec_attributes);
1007
1008 ret = dal_call(vd->vdec_handle, VDEC_DALRPC_GETDECATTRIBUTES, 9,
1009 &inp, sizeof(inp), &rpc, sizeof(rpc));
1010 if (ret < 4 || rpc.size != sizeof(struct vdec_dec_attributes)) {
1011 pr_err("%s: remote function failed (%d)\n", __func__, ret);
1012 ret = -EIO;
1013 } else
1014 ret =
1015 copy_to_user(((struct vdec_dec_attributes *)argp),
1016 &rpc.dec_attr, sizeof(rpc.dec_attr));
1017 return ret;
1018}
1019
1020static int vdec_freebuffers(struct vdec_data *vd, void *argp)
1021{
1022 struct vdec_buffer vmem;
1023 struct vdec_mem_list *l;
1024 struct {
1025 uint32_t size;
1026 struct vdec_buf_info buf;
1027 } rpc;
1028 uint32_t res;
1029
1030 int ret = 0;
1031
1032 if (!vd->mem_initialized) {
1033 pr_err("%s: memory is not being initialized!\n", __func__);
1034 return -EPERM;
1035 }
1036
1037 ret = copy_from_user(&vmem, argp, sizeof(vmem));
1038 if (ret) {
1039 pr_err("%s: copy_from_user failed\n", __func__);
1040 return ret;
1041 }
1042
1043 l = vdec_get_mem_from_list(vd, vmem.pmem_id, vmem.buf.buf_type);
1044
1045 if (NULL == l) {
1046 pr_err("%s: not able to find the buffer from list\n", __func__);
1047 return -EPERM;
1048 }
1049
1050 /* input buffers */
1051 if ((vmem.buf.region.offset + vmem.buf.region.size) > l->mem.len) {
1052 pr_err("%s: invalid input buffer offset!\n", __func__);
1053 return -EINVAL;
1054
1055 }
1056 vmem.buf.region.offset += l->mem.phys_addr;
1057
1058 rpc.size = sizeof(vmem.buf);
1059 memcpy(&rpc.buf, &vmem.buf, sizeof(struct vdec_buf_info));
1060
1061 ret = dal_call(vd->vdec_handle, VDEC_DALRPC_FREEBUFFERS, 5,
1062 &rpc, sizeof(rpc), &res, sizeof(res));
1063 if (ret < 4) {
1064 pr_err("%s: remote function failed (%d)\n", __func__, ret);
1065 }
1066
1067 return ret;
1068}
1069
1070static int vdec_getversion(struct vdec_data *vd, void *argp)
1071{
1072 struct vdec_version ver_info;
1073 int ret = 0;
1074
1075 ver_info.major = VDEC_GET_MAJOR_VERSION(VDEC_INTERFACE_VERSION);
1076 ver_info.minor = VDEC_GET_MINOR_VERSION(VDEC_INTERFACE_VERSION);
1077
1078 ret = copy_to_user(((struct vdec_version *)argp),
1079 &ver_info, sizeof(ver_info));
1080
1081 return ret;
1082
1083}
1084
1085static long vdec_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
1086{
1087 struct vdec_data *vd = file->private_data;
1088 void __user *argp = (void __user *)arg;
1089 int ret = 0;
1090
1091 if (!vd->running)
1092 return -EPERM;
1093
1094 switch (cmd) {
1095 case VDEC_IOCTL_INITIALIZE:
1096 ret = vdec_initialize(vd, argp);
1097 break;
1098
1099 case VDEC_IOCTL_SETBUFFERS:
1100 ret = vdec_setbuffers(vd, argp);
1101 break;
1102
1103 case VDEC_IOCTL_QUEUE:
1104 TRACE("VDEC_IOCTL_QUEUE (pid=%d tid=%d)\n",
1105 current->group_leader->pid, current->pid);
1106 ret = vdec_queue(vd, argp);
1107 break;
1108
1109 case VDEC_IOCTL_REUSEFRAMEBUFFER:
1110 TRACE("VDEC_IOCTL_REUSEFRAMEBUFFER (pid=%d tid=%d)\n",
1111 current->group_leader->pid, current->pid);
1112 ret = vdec_reuse_framebuffer(vd, argp);
1113 break;
1114
1115 case VDEC_IOCTL_FLUSH:
1116 TRACE("IOCTL flush\n");
1117 ret = vdec_flush(vd, argp);
1118 break;
1119
1120 case VDEC_IOCTL_EOS:
1121 TRACE("VDEC_IOCTL_EOS (pid=%d tid=%d)\n",
1122 current->group_leader->pid, current->pid);
1123 ret = dal_call_f0(vd->vdec_handle, VDEC_DALRPC_SIGEOFSTREAM, 0);
1124 if (ret)
1125 pr_err("%s: remote function failed (%d)\n",
1126 __func__, ret);
1127 break;
1128
1129 case VDEC_IOCTL_GETMSG:
1130 TRACE("VDEC_IOCTL_GETMSG (pid=%d tid=%d)\n",
1131 current->group_leader->pid, current->pid);
1132 wait_event_interruptible(vd->vdec_msg_evt,
1133 vdec_get_msg(vd, argp));
1134
1135 if (vd->close_decode)
1136 ret = -EINTR;
1137 else
1138 /* order the reads from the buffer */
1139 rmb();
1140 break;
1141
1142 case VDEC_IOCTL_CLOSE:
1143 ret = vdec_close(vd, argp);
1144 break;
1145
1146 case VDEC_IOCTL_GETDECATTRIBUTES:
1147 TRACE("VDEC_IOCTL_GETDECATTRIBUTES (pid=%d tid=%d)\n",
1148 current->group_leader->pid, current->pid);
1149 ret = vdec_getdecattributes(vd, argp);
1150
1151 if (ret)
1152 pr_err("%s: remote function failed (%d)\n",
1153 __func__, ret);
1154 break;
1155
1156 case VDEC_IOCTL_FREEBUFFERS:
1157 TRACE("VDEC_IOCTL_FREEBUFFERS (pid=%d tid=%d)\n",
1158 current->group_leader->pid, current->pid);
1159 ret = vdec_freebuffers(vd, argp);
1160
1161 if (ret)
1162 pr_err("%s: remote function failed (%d)\n",
1163 __func__, ret);
1164 break;
1165 case VDEC_IOCTL_GETVERSION:
1166 TRACE("VDEC_IOCTL_GETVERSION (pid=%d tid=%d)\n",
1167 current->group_leader->pid, current->pid);
1168 ret = vdec_getversion(vd, argp);
1169
1170 if (ret)
1171 pr_err("%s: remote function failed (%d)\n",
1172 __func__, ret);
1173 break;
1174 case VDEC_IOCTL_GETPROPERTY:
1175 TRACE("VDEC_IOCTL_GETPROPERTY (pid=%d tid=%d)\n",
1176 current->group_leader->pid, current->pid);
1177 ret = vdec_getproperty(vd, argp);
1178 break;
1179 case VDEC_IOCTL_SETPROPERTY:
1180 TRACE("VDEC_IOCTL_SETPROPERTY (pid=%d tid=%d)\n",
1181 current->group_leader->pid, current->pid);
1182 ret = vdec_setproperty(vd, argp);
1183 break;
1184 case VDEC_IOCTL_PERFORMANCE_CHANGE_REQ:
1185 ret = vdec_performance_change_request(vd, argp);
1186 break;
1187 default:
1188 pr_err("%s: invalid ioctl!\n", __func__);
1189 ret = -EINVAL;
1190 break;
1191 }
1192
1193 TRACE("ioctl done (pid=%d tid=%d)\n",
1194 current->group_leader->pid, current->pid);
1195
1196 return ret;
1197}
1198
1199static void vdec_dcdone_handler(struct vdec_data *vd, void *frame,
1200 uint32_t frame_size)
1201{
1202 struct vdec_msg msg;
1203 struct vdec_mem_list *l;
1204 unsigned long flags;
1205 int found = 0;
1206
1207 if (frame_size < sizeof(struct vdec_frame_info)) {
1208 pr_warning("%s: msg size mismatch %d != %d\n", __func__,
1209 frame_size, sizeof(struct vdec_frame_info));
1210 return;
1211 }
1212
1213 memcpy(&msg.vfr_info, (struct vdec_frame_info *)frame,
1214 sizeof(struct vdec_frame_info));
1215
1216 if (msg.vfr_info.status == VDEC_FRAME_DECODE_OK) {
1217 spin_lock_irqsave(&vd->vdec_mem_list_lock, flags);
1218 list_for_each_entry(l, &vd->vdec_mem_list_head, list) {
1219 if ((l->mem.buf_type == VDEC_BUFFER_TYPE_OUTPUT) &&
1220 (msg.vfr_info.offset >= l->mem.phys_addr) &&
1221 (msg.vfr_info.offset <
1222 (l->mem.phys_addr + l->mem.len))) {
1223 found = 1;
1224 msg.vfr_info.offset -= l->mem.phys_addr;
1225 msg.vfr_info.data2 = l->mem.id;
1226 break;
1227 }
1228 }
1229 spin_unlock_irqrestore(&vd->vdec_mem_list_lock, flags);
1230 }
1231
1232 if (found || (msg.vfr_info.status != VDEC_FRAME_DECODE_OK)) {
1233 msg.id = VDEC_MSG_FRAMEDONE;
1234 vdec_put_msg(vd, &msg);
1235 } else {
1236 pr_err("%s: invalid phys addr = 0x%x\n",
1237 __func__, msg.vfr_info.offset);
1238 }
1239
1240}
1241
1242static void vdec_reuseibuf_handler(struct vdec_data *vd, void *bufstat,
1243 uint32_t bufstat_size)
1244{
1245 struct vdec_buffer_status *vdec_bufstat;
1246 struct vdec_msg msg;
1247
1248 /* TODO: how do we signal the client? If they are waiting on a
1249 * message in an ioctl, they may block forever */
1250 if (bufstat_size != sizeof(struct vdec_buffer_status)) {
1251 pr_warning("%s: msg size mismatch %d != %d\n", __func__,
1252 bufstat_size, sizeof(struct vdec_buffer_status));
1253 return;
1254 }
1255 vdec_bufstat = (struct vdec_buffer_status *)bufstat;
1256 msg.id = VDEC_MSG_REUSEINPUTBUFFER;
1257 msg.buf_id = vdec_bufstat->data;
1258 vdec_put_msg(vd, &msg);
1259}
1260
1261static void callback(void *data, int len, void *cookie)
1262{
1263 struct vdec_data *vd = (struct vdec_data *)cookie;
1264 uint32_t *tmp = (uint32_t *) data;
1265
1266 if (!vd->mem_initialized) {
1267 pr_err("%s:memory not initialize but callback called!\n",
1268 __func__);
1269 return;
1270 }
1271
1272 TRACE("vdec_async: tmp=0x%08x 0x%08x 0x%08x\n", tmp[0], tmp[1], tmp[2]);
1273 switch (tmp[0]) {
1274 case VDEC_ASYNCMSG_DECODE_DONE:
1275 vdec_dcdone_handler(vd, &tmp[3], tmp[2]);
1276 break;
1277 case VDEC_ASYNCMSG_REUSE_FRAME:
1278 vdec_reuseibuf_handler(vd, &tmp[3], tmp[2]);
1279 break;
1280 default:
1281 pr_err("%s: Unknown async message from DSP id=0x%08x sz=%u\n",
1282 __func__, tmp[0], tmp[2]);
1283 }
1284}
1285
1286static int vdec_open(struct inode *inode, struct file *file)
1287{
1288 int ret;
1289 int i;
1290 struct vdec_msg_list *l;
1291 struct vdec_data *vd;
1292 struct dal_info version_info;
1293 char *portname = NULL;
1294
1295 pr_info("q6vdec_open()\n");
1296 mutex_lock(&vdec_ref_lock);
1297 if (ref_cnt >= MAX_SUPPORTED_INSTANCES) {
1298 pr_err("%s: Max allowed instances exceeded \n", __func__);
1299 mutex_unlock(&vdec_ref_lock);
1300 return -EBUSY;
1301 }
1302 ref_cnt++;
1303 mutex_unlock(&vdec_ref_lock);
1304
1305 vd = kmalloc(sizeof(struct vdec_data), GFP_KERNEL);
1306 if (!vd) {
1307 pr_err("%s: kmalloc failed\n", __func__);
1308 ret = -ENOMEM;
1309 goto vdec_open_err_handle_vd;
1310 }
1311 file->private_data = vd;
1312
1313 vd->mem_initialized = 0;
1314 INIT_LIST_HEAD(&vd->vdec_msg_list_head);
1315 INIT_LIST_HEAD(&vd->vdec_msg_list_free);
1316 INIT_LIST_HEAD(&vd->vdec_mem_list_head);
1317 init_waitqueue_head(&vd->vdec_msg_evt);
1318
1319 spin_lock_init(&vd->vdec_list_lock);
1320 spin_lock_init(&vd->vdec_mem_list_lock);
1321 for (i = 0; i < VDEC_MSG_MAX; i++) {
1322 l = kzalloc(sizeof(struct vdec_msg_list), GFP_KERNEL);
1323 if (!l) {
1324 pr_err("%s: kzalloc failed!\n", __func__);
1325 ret = -ENOMEM;
1326 goto vdec_open_err_handle_list;
1327 }
1328 list_add(&l->list, &vd->vdec_msg_list_free);
1329 }
1330
1331 memset(&vd->streamDetails, 0, sizeof(struct videoStreamDetails));
1332
1333 mutex_lock(&vdec_ref_lock);
1334 vdec_get_next_portanddevid(&vd->Q6deviceId, &portname);
1335 mutex_unlock(&vdec_ref_lock);
1336
1337 if ((0 == vd->Q6deviceId) || (NULL == portname)) {
1338 pr_err("%s: FATAL error portname %s or deviceId %d not picked properly\n",
1339 __func__, portname, vd->Q6deviceId);
1340 ret = -EIO;
1341 goto vdec_open_err_handle_list;
1342 } else {
1343 pr_err("attaching on deviceid %x portname %s\n",
1344 vd->Q6deviceId, portname);
1345 vd->vdec_handle = dal_attach(vd->Q6deviceId,
1346 portname, 1, callback, vd);
1347 }
1348
1349 if (!vd->vdec_handle) {
1350 pr_err("%s: failed to attach\n", __func__);
1351 ret = -EIO;
1352 goto vdec_open_err_handle_list;
1353 }
1354 ret = dal_call_f9(vd->vdec_handle, DAL_OP_INFO,
1355 &version_info, sizeof(struct dal_info));
1356
1357 if (ret) {
1358 pr_err("%s: failed to get version \n", __func__);
1359 goto vdec_open_err_handle_version;
1360 }
1361
1362 TRACE("q6vdec_open() interface version 0x%x\n", version_info.version);
1363 if (vdec_check_version(VDEC_INTERFACE_VERSION,
1364 version_info.version)) {
1365 pr_err("%s: driver version mismatch !\n", __func__);
1366 goto vdec_open_err_handle_version;
1367 }
1368
1369 vd->running = 1;
1370 prevent_sleep();
1371
1372 return 0;
1373vdec_open_err_handle_version:
1374 dal_detach(vd->vdec_handle);
1375vdec_open_err_handle_list:
1376 {
1377 struct vdec_msg_list *l, *n;
1378 list_for_each_entry_safe(l, n, &vd->vdec_msg_list_free, list) {
1379 list_del(&l->list);
1380 kfree(l);
1381 }
1382 }
1383vdec_open_err_handle_vd:
1384 mutex_lock(&vdec_ref_lock);
1385 vdec_freeup_portanddevid(vd->Q6deviceId);
1386 ref_cnt--;
1387 mutex_unlock(&vdec_ref_lock);
1388 kfree(vd);
1389 return ret;
1390}
1391
1392static int vdec_release(struct inode *inode, struct file *file)
1393{
1394 int ret;
1395 struct vdec_msg_list *l, *n;
1396 struct vdec_mem_list *m, *k;
1397 struct vdec_data *vd = file->private_data;
1398
1399 vd->running = 0;
1400 wake_up_all(&vd->vdec_msg_evt);
1401
1402 if (!vd->close_decode)
1403 vdec_close(vd, NULL);
1404
1405 ret = dal_detach(vd->vdec_handle);
1406 if (ret)
1407 printk(KERN_INFO "%s: failed to detach (%d)\n", __func__, ret);
1408
1409 list_for_each_entry_safe(l, n, &vd->vdec_msg_list_free, list) {
1410 list_del(&l->list);
1411 kfree(l);
1412 }
1413
1414 list_for_each_entry_safe(l, n, &vd->vdec_msg_list_head, list) {
1415 list_del(&l->list);
1416 kfree(l);
1417 }
1418
1419 list_for_each_entry_safe(m, k, &vd->vdec_mem_list_head, list) {
1420 list_del(&m->list);
1421 kfree(m);
1422 }
1423 mutex_lock(&vdec_ref_lock);
1424 BUG_ON(ref_cnt <= 0);
1425 ref_cnt--;
1426 vdec_freeup_portanddevid(vd->Q6deviceId);
1427 mutex_unlock(&vdec_ref_lock);
1428
1429 mutex_lock(&vdec_rm_lock);
1430 vdec_rm_freeupResources(vd);
1431 mutex_unlock(&vdec_rm_lock);
1432
1433
1434 kfree(vd);
1435 allow_sleep();
1436 return 0;
1437}
1438
1439static const struct file_operations vdec_fops = {
1440 .owner = THIS_MODULE,
1441 .open = vdec_open,
1442 .release = vdec_release,
1443 .unlocked_ioctl = vdec_ioctl,
1444};
1445
1446static int __init vdec_init(void)
1447{
1448 struct device *class_dev;
1449 int rc = 0;
1450
Stephen Boyd2fcabf92012-05-30 10:41:11 -07001451 pm_qos_add_request(&pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
1452 PM_QOS_DEFAULT_VALUE);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001453 wake_lock_init(&wakelock, WAKE_LOCK_SUSPEND, "vdec_suspend");
1454
1455 rc = alloc_chrdev_region(&vdec_device_no, 0, 1, "vdec");
1456 if (rc < 0) {
1457 pr_err("%s: alloc_chrdev_region failed %d\n", __func__, rc);
1458 return rc;
1459 }
1460
1461 driver_class = class_create(THIS_MODULE, "vdec");
1462 if (IS_ERR(driver_class)) {
1463 rc = -ENOMEM;
1464 pr_err("%s: class_create failed %d\n", __func__, rc);
1465 goto vdec_init_err_unregister_chrdev_region;
1466 }
1467 class_dev = device_create(driver_class, NULL,
1468 vdec_device_no, NULL, "vdec");
1469 if (!class_dev) {
1470 pr_err("%s: class_device_create failed %d\n", __func__, rc);
1471 rc = -ENOMEM;
1472 goto vdec_init_err_class_destroy;
1473 }
1474
1475 cdev_init(&vdec_cdev, &vdec_fops);
1476 vdec_cdev.owner = THIS_MODULE;
1477 rc = cdev_add(&vdec_cdev, MKDEV(MAJOR(vdec_device_no), 0), 1);
1478
1479 if (rc < 0) {
1480 pr_err("%s: cdev_add failed %d\n", __func__, rc);
1481 goto vdec_init_err_class_device_destroy;
1482 }
1483
1484 memset(&deviceIdRegistry, 0, sizeof(deviceIdRegistry));
1485 memset(&loadOnPorts, 0, sizeof(loadOnPorts));
1486 numOfPorts = 0;
1487
1488 return 0;
1489
1490vdec_init_err_class_device_destroy:
1491 device_destroy(driver_class, vdec_device_no);
1492vdec_init_err_class_destroy:
1493 class_destroy(driver_class);
1494vdec_init_err_unregister_chrdev_region:
1495 unregister_chrdev_region(vdec_device_no, 1);
1496 return rc;
1497}
1498
1499static void __exit vdec_exit(void)
1500{
1501 device_destroy(driver_class, vdec_device_no);
1502 class_destroy(driver_class);
1503 unregister_chrdev_region(vdec_device_no, 1);
1504}
1505
1506MODULE_DESCRIPTION("video decoder driver for QSD platform");
1507MODULE_VERSION("2.00");
1508
1509module_init(vdec_init);
1510module_exit(vdec_exit);