blob: 3e834d86f19e124bfa43d0b2d27c1b93760677cf [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001
2/* arch/arm/mach-msm/qdsp5/audpp.c
3 *
4 * common code to deal with the AUDPP dsp task (audio postproc)
5 *
6 * Copyright (C) 2008 Google, Inc.
7 * Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
8 *
9 * This software is licensed under the terms of the GNU General Public
10 * License version 2, as published by the Free Software Foundation, and
11 * may be copied, distributed, and modified under those terms.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 */
19
20#include <linux/kernel.h>
21#include <linux/module.h>
22#include <linux/wait.h>
23#include <linux/delay.h>
24#include <linux/sched.h>
25#include <linux/platform_device.h>
26#include <linux/dma-mapping.h>
27
28#include <asm/atomic.h>
29#include <asm/ioctls.h>
30#include <mach/board.h>
31#include <mach/msm_adsp.h>
32
33#include "audmgr.h"
34
35#include <mach/qdsp5/qdsp5audppcmdi.h>
36#include <mach/qdsp5/qdsp5audppmsg.h>
37#include <mach/debug_mm.h>
38
39#include "evlog.h"
40
41enum {
42 EV_NULL,
43 EV_ENABLE,
44 EV_DISABLE,
45 EV_EVENT,
46 EV_DATA,
47};
48
49static const char *dsp_log_strings[] = {
50 "NULL",
51 "ENABLE",
52 "DISABLE",
53 "EVENT",
54 "DATA",
55};
56
57DECLARE_LOG(dsp_log, 64, dsp_log_strings);
58
59static int __init _dsp_log_init(void)
60{
61 return ev_log_init(&dsp_log);
62}
63
64module_init(_dsp_log_init);
65#define LOG(id,arg) ev_log_write(&dsp_log, id, arg)
66
67static DEFINE_MUTEX(audpp_lock);
68static DEFINE_MUTEX(audpp_dec_lock);
69
70#define CH_COUNT 5
71#define AUDPP_CLNT_MAX_COUNT 6
72#define AUDPP_AVSYNC_INFO_SIZE 7
73
74#define AUDPP_CMD_CFG_OBJ_UPDATE 0x8000
75#define AUDPP_CMD_EQ_FLAG_DIS 0x0000
76#define AUDPP_CMD_EQ_FLAG_ENA -1
77#define AUDPP_CMD_IIR_FLAG_DIS 0x0000
78#define AUDPP_CMD_IIR_FLAG_ENA -1
79
80#define AUDPP_CMD_VOLUME_PAN 0
81#define AUDPP_CMD_IIR_TUNING_FILTER 1
82#define AUDPP_CMD_EQUALIZER 2
83#define AUDPP_CMD_ADRC 3
84#define AUDPP_CMD_SPECTROGRAM 4
85#define AUDPP_CMD_QCONCERT 5
86#define AUDPP_CMD_SIDECHAIN_TUNING_FILTER 6
87#define AUDPP_CMD_SAMPLING_FREQUENCY 7
88#define AUDPP_CMD_QAFX 8
89#define AUDPP_CMD_QRUMBLE 9
90#define AUDPP_CMD_MBADRC 10
91
92#define MAX_EVENT_CALLBACK_CLIENTS 1
93
94#define AUDPP_CONCURRENCY_DEFAULT 6 /* All non tunnel mode */
95#define AUDPP_MAX_DECODER_CNT 5
96#define AUDPP_CODEC_MASK 0x000000FF
97#define AUDPP_MODE_MASK 0x00000F00
98#define AUDPP_OP_MASK 0xF0000000
99
100struct audpp_decoder_info {
101 unsigned int codec;
102 pid_t pid;
103};
104
105struct audpp_state {
106 struct msm_adsp_module *mod;
107 audpp_event_func func[AUDPP_CLNT_MAX_COUNT];
108 void *private[AUDPP_CLNT_MAX_COUNT];
109 struct mutex *lock;
110 unsigned open_count;
111 unsigned enabled;
112
113 /* Related to decoder allocation */
114 struct mutex *lock_dec;
115 struct msm_adspdec_database *dec_database;
116 struct audpp_decoder_info dec_info_table[AUDPP_MAX_DECODER_CNT];
117 unsigned dec_inuse;
118 unsigned long concurrency;
119
120 /* which channels are actually enabled */
121 unsigned avsync_mask;
122
123 /* flags, 48 bits sample/bytes counter per channel */
124 uint16_t avsync[CH_COUNT * AUDPP_CLNT_MAX_COUNT + 1];
125 struct audpp_event_callback *cb_tbl[MAX_EVENT_CALLBACK_CLIENTS];
126
127 wait_queue_head_t event_wait;
128};
129
130struct audpp_state the_audpp_state = {
131 .lock = &audpp_lock,
132 .lock_dec = &audpp_dec_lock,
133};
134
135int audpp_send_queue1(void *cmd, unsigned len)
136{
137 return msm_adsp_write(the_audpp_state.mod,
138 QDSP_uPAudPPCmd1Queue, cmd, len);
139}
140EXPORT_SYMBOL(audpp_send_queue1);
141
142int audpp_send_queue2(void *cmd, unsigned len)
143{
144 return msm_adsp_write(the_audpp_state.mod,
145 QDSP_uPAudPPCmd2Queue, cmd, len);
146}
147EXPORT_SYMBOL(audpp_send_queue2);
148
149int audpp_send_queue3(void *cmd, unsigned len)
150{
151 return msm_adsp_write(the_audpp_state.mod,
152 QDSP_uPAudPPCmd3Queue, cmd, len);
153}
154EXPORT_SYMBOL(audpp_send_queue3);
155
156static int audpp_dsp_config(int enable)
157{
158 audpp_cmd_cfg cmd;
159
160 cmd.cmd_id = AUDPP_CMD_CFG;
161 cmd.cfg = enable ? AUDPP_CMD_CFG_ENABLE : AUDPP_CMD_CFG_SLEEP;
162
163 return audpp_send_queue1(&cmd, sizeof(cmd));
164}
165
166int is_audpp_enable(void)
167{
168 struct audpp_state *audpp = &the_audpp_state;
169
170 return audpp->enabled;
171}
172EXPORT_SYMBOL(is_audpp_enable);
173
174int audpp_register_event_callback(struct audpp_event_callback *ecb)
175{
176 struct audpp_state *audpp = &the_audpp_state;
177 int i;
178
179 for (i = 0; i < MAX_EVENT_CALLBACK_CLIENTS; ++i) {
180 if (NULL == audpp->cb_tbl[i]) {
181 audpp->cb_tbl[i] = ecb;
182 return 0;
183 }
184 }
185 return -1;
186}
187EXPORT_SYMBOL(audpp_register_event_callback);
188
189int audpp_unregister_event_callback(struct audpp_event_callback *ecb)
190{
191 struct audpp_state *audpp = &the_audpp_state;
192 int i;
193
194 for (i = 0; i < MAX_EVENT_CALLBACK_CLIENTS; ++i) {
195 if (ecb == audpp->cb_tbl[i]) {
196 audpp->cb_tbl[i] = NULL;
197 return 0;
198 }
199 }
200 return -1;
201}
202EXPORT_SYMBOL(audpp_unregister_event_callback);
203
204static void audpp_broadcast(struct audpp_state *audpp, unsigned id,
205 uint16_t *msg)
206{
207 unsigned n;
208 for (n = 0; n < AUDPP_CLNT_MAX_COUNT; n++) {
209 if (audpp->func[n])
210 audpp->func[n] (audpp->private[n], id, msg);
211 }
212
213 for (n = 0; n < MAX_EVENT_CALLBACK_CLIENTS; ++n)
214 if (audpp->cb_tbl[n] && audpp->cb_tbl[n]->fn)
215 audpp->cb_tbl[n]->fn(audpp->cb_tbl[n]->private, id,
216 msg);
217}
218
219static void audpp_notify_clnt(struct audpp_state *audpp, unsigned clnt_id,
220 unsigned id, uint16_t *msg)
221{
222 if (clnt_id < AUDPP_CLNT_MAX_COUNT && audpp->func[clnt_id])
223 audpp->func[clnt_id] (audpp->private[clnt_id], id, msg);
224}
225
226static void audpp_handle_pcmdmamiss(struct audpp_state *audpp,
227 uint16_t bit_mask)
228{
229 uint8_t b_index;
230
231 for (b_index = 0; b_index < AUDPP_CLNT_MAX_COUNT; b_index++) {
232 if (bit_mask & (0x1 << b_index))
233 if (audpp->func[b_index])
234 audpp->func[b_index] (audpp->private[b_index],
235 AUDPP_MSG_PCMDMAMISSED,
236 &bit_mask);
237 }
238}
239
240static void audpp_dsp_event(void *data, unsigned id, size_t len,
241 void (*getevent) (void *ptr, size_t len))
242{
243 struct audpp_state *audpp = data;
244 uint16_t msg[8];
245
246 if (id == AUDPP_MSG_AVSYNC_MSG) {
247 getevent(audpp->avsync, sizeof(audpp->avsync));
248
249 /* mask off any channels we're not watching to avoid
250 * cases where we might get one last update after
251 * disabling avsync and end up in an odd state when
252 * we next read...
253 */
254 audpp->avsync[0] &= audpp->avsync_mask;
255 return;
256 }
257
258 getevent(msg, sizeof(msg));
259
260 LOG(EV_EVENT, (id << 16) | msg[0]);
261 LOG(EV_DATA, (msg[1] << 16) | msg[2]);
262
263 switch (id) {
264 case AUDPP_MSG_STATUS_MSG:{
265 unsigned cid = msg[0];
266 MM_DBG("status %d %d %d\n", cid, msg[1], msg[2]);
267 if ((cid < 5) && audpp->func[cid])
268 audpp->func[cid] (audpp->private[cid], id, msg);
269 break;
270 }
271 case AUDPP_MSG_HOST_PCM_INTF_MSG:
272 if (audpp->func[5])
273 audpp->func[5] (audpp->private[5], id, msg);
274 break;
275 case AUDPP_MSG_PCMDMAMISSED:
276 audpp_handle_pcmdmamiss(audpp, msg[0]);
277 break;
278 case AUDPP_MSG_CFG_MSG:
279 if (msg[0] == AUDPP_MSG_ENA_ENA) {
280 MM_INFO("ENABLE\n");
281 audpp->enabled = 1;
282 audpp_broadcast(audpp, id, msg);
283 } else if (msg[0] == AUDPP_MSG_ENA_DIS) {
284 MM_INFO("DISABLE\n");
285 audpp->enabled = 0;
286 wake_up(&audpp->event_wait);
287 audpp_broadcast(audpp, id, msg);
288 } else {
289 MM_ERR("invalid config msg %d\n", msg[0]);
290 }
291 break;
292 case AUDPP_MSG_ROUTING_ACK:
293 audpp_notify_clnt(audpp, msg[0], id, msg);
294 break;
295 case AUDPP_MSG_FLUSH_ACK:
296 audpp_notify_clnt(audpp, msg[0], id, msg);
297 break;
298 case ADSP_MESSAGE_ID:
299 MM_DBG("Received ADSP event: module enable/disable(audpptask)");
300 break;
301 default:
302 MM_ERR("unhandled msg id %x\n", id);
303 }
304}
305
306static struct msm_adsp_ops adsp_ops = {
307 .event = audpp_dsp_event,
308};
309
310static void audpp_fake_event(struct audpp_state *audpp, int id,
311 unsigned event, unsigned arg)
312{
313 uint16_t msg[1];
314 msg[0] = arg;
315 audpp->func[id] (audpp->private[id], event, msg);
316}
317
318int audpp_enable(int id, audpp_event_func func, void *private)
319{
320 struct audpp_state *audpp = &the_audpp_state;
321 int res = 0;
322
323 if (id < -1 || id > 4)
324 return -EINVAL;
325
326 if (id == -1)
327 id = 5;
328
329 mutex_lock(audpp->lock);
330 if (audpp->func[id]) {
331 res = -EBUSY;
332 goto out;
333 }
334
335 audpp->func[id] = func;
336 audpp->private[id] = private;
337
338 LOG(EV_ENABLE, 1);
339 if (audpp->open_count++ == 0) {
340 MM_DBG("enable\n");
341 res = msm_adsp_get("AUDPPTASK", &audpp->mod, &adsp_ops, audpp);
342 if (res < 0) {
343 MM_ERR("cannot open AUDPPTASK\n");
344 audpp->open_count = 0;
345 audpp->func[id] = NULL;
346 audpp->private[id] = NULL;
347 goto out;
348 }
349 LOG(EV_ENABLE, 2);
350 msm_adsp_enable(audpp->mod);
351 audpp_dsp_config(1);
352 } else {
353 unsigned long flags;
354 local_irq_save(flags);
355 if (audpp->enabled)
356 audpp_fake_event(audpp, id,
357 AUDPP_MSG_CFG_MSG, AUDPP_MSG_ENA_ENA);
358 local_irq_restore(flags);
359 }
360
361 res = 0;
362out:
363 mutex_unlock(audpp->lock);
364 return res;
365}
366EXPORT_SYMBOL(audpp_enable);
367
368void audpp_disable(int id, void *private)
369{
370 struct audpp_state *audpp = &the_audpp_state;
371 unsigned long flags;
372 int rc;
373
374 if (id < -1 || id > 4)
375 return;
376
377 if (id == -1)
378 id = 5;
379
380 mutex_lock(audpp->lock);
381 LOG(EV_DISABLE, 1);
382 if (!audpp->func[id])
383 goto out;
384 if (audpp->private[id] != private)
385 goto out;
386
387 local_irq_save(flags);
388 audpp_fake_event(audpp, id, AUDPP_MSG_CFG_MSG, AUDPP_MSG_ENA_DIS);
389 audpp->func[id] = NULL;
390 audpp->private[id] = NULL;
391 local_irq_restore(flags);
392
393 if (--audpp->open_count == 0) {
394 MM_DBG("disable\n");
395 LOG(EV_DISABLE, 2);
396 audpp_dsp_config(0);
397 rc = wait_event_interruptible(audpp->event_wait,
398 (audpp->enabled == 0));
399 if (audpp->enabled == 0)
400 MM_INFO("Received CFG_MSG_DISABLE from ADSP\n");
401 else
402 MM_ERR("Didn't receive CFG_MSG DISABLE \
403 message from ADSP\n");
404 msm_adsp_disable(audpp->mod);
405 msm_adsp_put(audpp->mod);
406 audpp->mod = NULL;
407 }
408out:
409 mutex_unlock(audpp->lock);
410}
411EXPORT_SYMBOL(audpp_disable);
412
413#define BAD_ID(id) ((id < 0) || (id >= CH_COUNT))
414
415void audpp_avsync(int id, unsigned rate)
416{
417 unsigned long flags;
418 audpp_cmd_avsync cmd;
419
420 if (BAD_ID(id))
421 return;
422
423 local_irq_save(flags);
424 if (rate)
425 the_audpp_state.avsync_mask |= (1 << id);
426 else
427 the_audpp_state.avsync_mask &= (~(1 << id));
428 the_audpp_state.avsync[0] &= the_audpp_state.avsync_mask;
429 local_irq_restore(flags);
430
431 cmd.cmd_id = AUDPP_CMD_AVSYNC;
432 cmd.object_number = id;
433 cmd.interrupt_interval_lsw = rate;
434 cmd.interrupt_interval_msw = rate >> 16;
435 audpp_send_queue1(&cmd, sizeof(cmd));
436}
437EXPORT_SYMBOL(audpp_avsync);
438
439unsigned audpp_avsync_sample_count(int id)
440{
441 uint16_t *avsync = the_audpp_state.avsync;
442 unsigned val;
443 unsigned long flags;
444 unsigned mask;
445
446 if (BAD_ID(id))
447 return 0;
448
449 mask = 1 << id;
450 id = id * AUDPP_AVSYNC_INFO_SIZE + 2;
451 local_irq_save(flags);
452 if (avsync[0] & mask)
453 val = (avsync[id] << 16) | avsync[id + 1];
454 else
455 val = 0;
456 local_irq_restore(flags);
457
458 return val;
459}
460EXPORT_SYMBOL(audpp_avsync_sample_count);
461
462unsigned audpp_avsync_byte_count(int id)
463{
464 uint16_t *avsync = the_audpp_state.avsync;
465 unsigned val;
466 unsigned long flags;
467 unsigned mask;
468
469 if (BAD_ID(id))
470 return 0;
471
472 mask = 1 << id;
473 id = id * AUDPP_AVSYNC_INFO_SIZE + 5;
474 local_irq_save(flags);
475 if (avsync[0] & mask)
476 val = (avsync[id] << 16) | avsync[id + 1];
477 else
478 val = 0;
479 local_irq_restore(flags);
480
481 return val;
482}
483EXPORT_SYMBOL(audpp_avsync_byte_count);
484
485int audpp_set_volume_and_pan(unsigned id, unsigned volume, int pan)
486{
487 /* cmd, obj_cfg[7], cmd_type, volume, pan */
488 uint16_t cmd[11];
489
490 if (id > 6)
491 return -EINVAL;
492
493 memset(cmd, 0, sizeof(cmd));
494 cmd[0] = AUDPP_CMD_CFG_OBJECT_PARAMS;
495 cmd[1 + id] = AUDPP_CMD_CFG_OBJ_UPDATE;
496 cmd[8] = AUDPP_CMD_VOLUME_PAN;
497 cmd[9] = volume;
498 cmd[10] = pan;
499
500 return audpp_send_queue3(cmd, sizeof(cmd));
501}
502EXPORT_SYMBOL(audpp_set_volume_and_pan);
503
504/* Implementation of COPP features */
505int audpp_dsp_set_mbadrc(unsigned id, unsigned enable,
506 audpp_cmd_cfg_object_params_mbadrc *mbadrc)
507{
508 audpp_cmd_cfg_object_params_mbadrc cmd;
509
510 if (id != 6)
511 return -EINVAL;
512
513 memset(&cmd, 0, sizeof(cmd));
514 cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
515 cmd.common.command_type = AUDPP_CMD_MBADRC;
516
517 if (enable) {
518 memcpy(&cmd.num_bands, &mbadrc->num_bands,
519 sizeof(*mbadrc) -
520 (AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2));
521 cmd.enable = AUDPP_CMD_ADRC_FLAG_ENA;
522 } else
523 cmd.enable = AUDPP_CMD_ADRC_FLAG_DIS;
524
525 /*order the writes to mbadrc */
526 dma_coherent_pre_ops();
527 return audpp_send_queue3(&cmd, sizeof(cmd));
528}
529EXPORT_SYMBOL(audpp_dsp_set_mbadrc);
530
531int audpp_dsp_set_qconcert_plus(unsigned id, unsigned enable,
532 audpp_cmd_cfg_object_params_qconcert *
533 qconcert_plus)
534{
535 audpp_cmd_cfg_object_params_qconcert cmd;
536 if (id != 6)
537 return -EINVAL;
538
539 memset(&cmd, 0, sizeof(cmd));
540 cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
541 cmd.common.command_type = AUDPP_CMD_QCONCERT;
542
543 if (enable) {
544 memcpy(&cmd.op_mode, &qconcert_plus->op_mode,
545 sizeof(audpp_cmd_cfg_object_params_qconcert) -
546 (AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2));
547 cmd.enable_flag = AUDPP_CMD_ADRC_FLAG_ENA;
548 } else
549 cmd.enable_flag = AUDPP_CMD_ADRC_FLAG_DIS;
550
551 return audpp_send_queue3(&cmd, sizeof(cmd));
552}
553
554int audpp_dsp_set_rx_iir(unsigned id, unsigned enable,
555 audpp_cmd_cfg_object_params_pcm *iir)
556{
557 audpp_cmd_cfg_object_params_pcm cmd;
558
559 if (id != 6)
560 return -EINVAL;
561
562 memset(&cmd, 0, sizeof(cmd));
563 cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
564 cmd.common.command_type = AUDPP_CMD_IIR_TUNING_FILTER;
565
566 if (enable) {
567 cmd.active_flag = AUDPP_CMD_IIR_FLAG_ENA;
568 cmd.num_bands = iir->num_bands;
569 memcpy(&cmd.params_filter, &iir->params_filter,
570 sizeof(iir->params_filter));
571 } else
572 cmd.active_flag = AUDPP_CMD_IIR_FLAG_DIS;
573
574 return audpp_send_queue3(&cmd, sizeof(cmd));
575}
576EXPORT_SYMBOL(audpp_dsp_set_rx_iir);
577
578/* Implementation Of COPP + POPP */
579int audpp_dsp_set_eq(unsigned id, unsigned enable,
580 audpp_cmd_cfg_object_params_eqalizer *eq)
581{
582 audpp_cmd_cfg_object_params_eqalizer cmd;
583 unsigned short *id_ptr = (unsigned short *)&cmd;
584
585 if (id > 6 || id == 5)
586 return -EINVAL;
587
588 memset(&cmd, 0, sizeof(cmd));
589 id_ptr[1 + id] = AUDPP_CMD_CFG_OBJ_UPDATE;
590 cmd.common.command_type = AUDPP_CMD_EQUALIZER;
591
592 if (enable) {
593 cmd.eq_flag = AUDPP_CMD_EQ_FLAG_ENA;
594 cmd.num_bands = eq->num_bands;
595 memcpy(&cmd.eq_coeff, &eq->eq_coeff, sizeof(eq->eq_coeff));
596 } else
597 cmd.eq_flag = AUDPP_CMD_EQ_FLAG_DIS;
598
599 return audpp_send_queue3(&cmd, sizeof(cmd));
600}
601EXPORT_SYMBOL(audpp_dsp_set_eq);
602
603int audpp_dsp_set_vol_pan(unsigned id,
604 audpp_cmd_cfg_object_params_volume *vol_pan)
605{
606 audpp_cmd_cfg_object_params_volume cmd;
607 unsigned short *id_ptr = (unsigned short *)&cmd;
608
609 if (id > 6)
610 return -EINVAL;
611
612 memset(&cmd, 0, sizeof(cmd));
613 id_ptr[1 + id] = AUDPP_CMD_CFG_OBJ_UPDATE;
614 cmd.common.command_type = AUDPP_CMD_VOLUME_PAN;
615
616 cmd.volume = vol_pan->volume;
617 cmd.pan = vol_pan->pan;
618
619 return audpp_send_queue3(&cmd, sizeof(cmd));
620}
621EXPORT_SYMBOL(audpp_dsp_set_vol_pan);
622
623int audpp_pause(unsigned id, int pause)
624{
625 /* pause 1 = pause 0 = resume */
626 u16 pause_cmd[AUDPP_CMD_DEC_CTRL_LEN / sizeof(unsigned short)];
627
628 if (id >= CH_COUNT)
629 return -EINVAL;
630
631 memset(pause_cmd, 0, sizeof(pause_cmd));
632
633 pause_cmd[0] = AUDPP_CMD_DEC_CTRL;
634 if (pause == 1)
635 pause_cmd[1 + id] = AUDPP_CMD_UPDATE_V | AUDPP_CMD_PAUSE_V;
636 else if (pause == 0)
637 pause_cmd[1 + id] = AUDPP_CMD_UPDATE_V | AUDPP_CMD_RESUME_V;
638 else
639 return -EINVAL;
640
641 return audpp_send_queue1(pause_cmd, sizeof(pause_cmd));
642}
643EXPORT_SYMBOL(audpp_pause);
644
645int audpp_flush(unsigned id)
646{
647 u16 flush_cmd[AUDPP_CMD_DEC_CTRL_LEN / sizeof(unsigned short)];
648
649 if (id >= CH_COUNT)
650 return -EINVAL;
651
652 memset(flush_cmd, 0, sizeof(flush_cmd));
653
654 flush_cmd[0] = AUDPP_CMD_DEC_CTRL;
655 flush_cmd[1 + id] = AUDPP_CMD_UPDATE_V | AUDPP_CMD_FLUSH_V;
656
657 return audpp_send_queue1(flush_cmd, sizeof(flush_cmd));
658}
659EXPORT_SYMBOL(audpp_flush);
660
661/* dec_attrb = 7:0, 0 - No Decoder, else supported decoder *
662 * like mp3, aac, wma etc ... *
663 * = 15:8, bit[8] = 1 - Tunnel, bit[9] = 1 - NonTunnel *
664 * = 31:16, reserved */
665int audpp_adec_alloc(unsigned dec_attrb, const char **module_name,
666 unsigned *queueid)
667{
668 struct audpp_state *audpp = &the_audpp_state;
669 int decid = -1, idx, lidx, mode, codec;
670 int codecs_supported, min_codecs_supported;
671 unsigned int *concurrency_entry;
672 mutex_lock(audpp->lock_dec);
673 /* Represents in bit mask */
674 mode = ((dec_attrb & AUDPP_MODE_MASK) << 16);
675 codec = (1 << (dec_attrb & AUDPP_CODEC_MASK));
676 /* Point to Last entry of the row */
677 concurrency_entry = ((audpp->dec_database->dec_concurrency_table +
678 ((audpp->concurrency + 1) *
679 (audpp->dec_database->num_dec))) - 1);
680
681 lidx = audpp->dec_database->num_dec;
682 min_codecs_supported = sizeof(unsigned int) * 8;
683
684 MM_DBG("mode = 0x%08x codec = 0x%08x\n", mode, codec);
685
686 for (idx = lidx; idx > 0; idx--, concurrency_entry--) {
687 if (!(audpp->dec_inuse & (1 << (idx - 1)))) {
688 if ((mode & *concurrency_entry) &&
689 (codec & *concurrency_entry)) {
690 /* Check supports minimum number codecs */
691 codecs_supported =
692 audpp->dec_database->dec_info_list[idx -
693 1].
694 nr_codec_support;
695 if (codecs_supported < min_codecs_supported) {
696 lidx = idx - 1;
697 min_codecs_supported = codecs_supported;
698 }
699 }
700 }
701 }
702
703 if (lidx < audpp->dec_database->num_dec) {
704 audpp->dec_inuse |= (1 << lidx);
705 *module_name =
706 audpp->dec_database->dec_info_list[lidx].module_name;
707 *queueid =
708 audpp->dec_database->dec_info_list[lidx].module_queueid;
709 decid = audpp->dec_database->dec_info_list[lidx].module_decid;
710 audpp->dec_info_table[lidx].codec =
711 (dec_attrb & AUDPP_CODEC_MASK);
712 audpp->dec_info_table[lidx].pid = current->pid;
713 /* point to row to get supported operation */
714 concurrency_entry =
715 ((audpp->dec_database->dec_concurrency_table +
716 ((audpp->concurrency) * (audpp->dec_database->num_dec))) +
717 lidx);
718 decid |= ((*concurrency_entry & AUDPP_OP_MASK) >> 12);
719 MM_INFO("decid =0x%08x module_name=%s, queueid=%d \n",
720 decid, *module_name, *queueid);
721 }
722 mutex_unlock(audpp->lock_dec);
723 return decid;
724
725}
726EXPORT_SYMBOL(audpp_adec_alloc);
727
728void audpp_adec_free(int decid)
729{
730 struct audpp_state *audpp = &the_audpp_state;
731 int idx;
732 mutex_lock(audpp->lock_dec);
733 for (idx = audpp->dec_database->num_dec; idx > 0; idx--) {
734 if (audpp->dec_database->dec_info_list[idx - 1].module_decid ==
735 decid) {
736 audpp->dec_inuse &= ~(1 << (idx - 1));
737 audpp->dec_info_table[idx - 1].codec = -1;
738 audpp->dec_info_table[idx - 1].pid = 0;
739 MM_INFO("free decid =%d \n", decid);
740 break;
741 }
742 }
743 mutex_unlock(audpp->lock_dec);
744 return;
745
746}
747EXPORT_SYMBOL(audpp_adec_free);
748
749static ssize_t concurrency_show(struct device *dev,
750 struct device_attribute *attr, char *buf)
751{
752 struct audpp_state *audpp = &the_audpp_state;
753 int rc;
754 mutex_lock(audpp->lock_dec);
755 rc = sprintf(buf, "%ld\n", audpp->concurrency);
756 mutex_unlock(audpp->lock_dec);
757 return rc;
758}
759
760static ssize_t concurrency_store(struct device *dev,
761 struct device_attribute *attr,
762 const char *buf, size_t count)
763{
764 struct audpp_state *audpp = &the_audpp_state;
765 unsigned long concurrency;
766 int rc = -1;
767 mutex_lock(audpp->lock_dec);
768 if (audpp->dec_inuse) {
769 MM_ERR("Can not change profile, while playback in progress\n");
770 goto done;
771 }
772 rc = strict_strtoul(buf, 10, &concurrency);
773 if (!rc &&
774 (concurrency < audpp->dec_database->num_concurrency_support)) {
775 audpp->concurrency = concurrency;
776 MM_DBG("Concurrency case %ld\n", audpp->concurrency);
777 rc = count;
778 } else {
779 MM_ERR("Not a valid Concurrency case\n");
780 rc = -EINVAL;
781 }
782done:
783 mutex_unlock(audpp->lock_dec);
784 return rc;
785}
786
787static ssize_t decoder_info_show(struct device *dev,
788 struct device_attribute *attr, char *buf);
789static struct device_attribute dev_attr_decoder[AUDPP_MAX_DECODER_CNT] = {
790 __ATTR(decoder0, S_IRUGO, decoder_info_show, NULL),
791 __ATTR(decoder1, S_IRUGO, decoder_info_show, NULL),
792 __ATTR(decoder2, S_IRUGO, decoder_info_show, NULL),
793 __ATTR(decoder3, S_IRUGO, decoder_info_show, NULL),
794 __ATTR(decoder4, S_IRUGO, decoder_info_show, NULL),
795};
796
797static ssize_t decoder_info_show(struct device *dev,
798 struct device_attribute *attr, char *buf)
799{
800 int cpy_sz = 0;
801 struct audpp_state *audpp = &the_audpp_state;
802 const ptrdiff_t off = attr - dev_attr_decoder; /* decoder number */
803 mutex_lock(audpp->lock_dec);
804 cpy_sz += scnprintf(buf + cpy_sz, PAGE_SIZE - cpy_sz, "%d:",
805 audpp->dec_info_table[off].codec);
806 cpy_sz += scnprintf(buf + cpy_sz, PAGE_SIZE - cpy_sz, "%d\n",
807 audpp->dec_info_table[off].pid);
808 mutex_unlock(audpp->lock_dec);
809 return cpy_sz;
810}
811
812static DEVICE_ATTR(concurrency, S_IWUSR | S_IRUGO, concurrency_show,
813 concurrency_store);
814static int audpp_probe(struct platform_device *pdev)
815{
816 int rc, idx;
817 struct audpp_state *audpp = &the_audpp_state;
818 audpp->concurrency = AUDPP_CONCURRENCY_DEFAULT;
819 audpp->dec_database =
820 (struct msm_adspdec_database *)pdev->dev.platform_data;
821
822 MM_INFO("Number of decoder supported %d\n",
823 audpp->dec_database->num_dec);
824 MM_INFO("Number of concurrency supported %d\n",
825 audpp->dec_database->num_concurrency_support);
826
827 init_waitqueue_head(&audpp->event_wait);
828
829 for (idx = 0; idx < audpp->dec_database->num_dec; idx++) {
830 audpp->dec_info_table[idx].codec = -1;
831 audpp->dec_info_table[idx].pid = 0;
832 MM_INFO("module_name:%s\n",
833 audpp->dec_database->dec_info_list[idx].module_name);
834 MM_INFO("queueid:%d\n",
835 audpp->dec_database->dec_info_list[idx].module_queueid);
836 MM_INFO("decid:%d\n",
837 audpp->dec_database->dec_info_list[idx].module_decid);
838 MM_INFO("nr_codec_support:%d\n",
839 audpp->dec_database->dec_info_list[idx].
840 nr_codec_support);
841 }
842
843 for (idx = 0; idx < audpp->dec_database->num_dec; idx++) {
844 rc = device_create_file(&pdev->dev, &dev_attr_decoder[idx]);
845 if (rc)
846 goto err;
847 }
848 rc = device_create_file(&pdev->dev, &dev_attr_concurrency);
849 if (rc)
850 goto err;
851 else
852 goto done;
853err:
854 while (idx--)
855 device_remove_file(&pdev->dev, &dev_attr_decoder[idx]);
856done:
857 return rc;
858}
859
860static struct platform_driver audpp_plat_driver = {
861 .probe = audpp_probe,
862 .driver = {
863 .name = "msm_adspdec",
864 .owner = THIS_MODULE,
865 },
866};
867
868static int __init audpp_init(void)
869{
870 return platform_driver_register(&audpp_plat_driver);
871}
872
873device_initcall(audpp_init);