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