1039 lines
26 KiB
C
1039 lines
26 KiB
C
|
|
||
|
/* arch/arm/mach-msm/qdsp5/audpp.c
|
||
|
*
|
||
|
* common code to deal with the AUDPP dsp task (audio postproc)
|
||
|
*
|
||
|
* Copyright (C) 2008 Google, Inc.
|
||
|
* Copyright (c) 2009-2010, 2012-2013 The Linux Foundation. All rights reserved.
|
||
|
*
|
||
|
* This software is licensed under the terms of the GNU General Public
|
||
|
* License version 2, as published by the Free Software Foundation, and
|
||
|
* may be copied, distributed, and modified under those terms.
|
||
|
*
|
||
|
* This program is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU General Public License for more details.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#include <linux/kernel.h>
|
||
|
#include <linux/module.h>
|
||
|
#include <linux/wait.h>
|
||
|
#include <linux/delay.h>
|
||
|
#include <linux/sched.h>
|
||
|
#include <linux/platform_device.h>
|
||
|
#include <linux/dma-mapping.h>
|
||
|
|
||
|
#include <asm/atomic.h>
|
||
|
#include <asm/ioctls.h>
|
||
|
#include <mach/board.h>
|
||
|
#include <mach/msm_adsp.h>
|
||
|
|
||
|
#include "audmgr.h"
|
||
|
|
||
|
#include <mach/qdsp5/qdsp5audppcmdi.h>
|
||
|
#include <mach/qdsp5/qdsp5audppmsg.h>
|
||
|
#include <mach/qdsp5/qdsp5audpp.h>
|
||
|
#include <mach/qdsp5v2/audio_acdbi.h>
|
||
|
#include <mach/debug_mm.h>
|
||
|
|
||
|
#include "evlog.h"
|
||
|
|
||
|
enum {
|
||
|
EV_NULL,
|
||
|
EV_ENABLE,
|
||
|
EV_DISABLE,
|
||
|
EV_EVENT,
|
||
|
EV_DATA,
|
||
|
};
|
||
|
|
||
|
static const char *dsp_log_strings[] = {
|
||
|
"NULL",
|
||
|
"ENABLE",
|
||
|
"DISABLE",
|
||
|
"EVENT",
|
||
|
"DATA",
|
||
|
};
|
||
|
|
||
|
DECLARE_LOG(dsp_log, 64, dsp_log_strings);
|
||
|
|
||
|
static int __init _dsp_log_init(void)
|
||
|
{
|
||
|
return ev_log_init(&dsp_log);
|
||
|
}
|
||
|
|
||
|
module_init(_dsp_log_init);
|
||
|
#define LOG(id,arg) ev_log_write(&dsp_log, id, arg)
|
||
|
|
||
|
static DEFINE_MUTEX(audpp_lock);
|
||
|
static DEFINE_MUTEX(audpp_dec_lock);
|
||
|
|
||
|
#define CH_COUNT 5
|
||
|
#define AUDPP_CLNT_MAX_COUNT 6
|
||
|
#define AUDPP_AVSYNC_INFO_SIZE 7
|
||
|
|
||
|
#define AUDPP_SRS_PARAMS 2
|
||
|
#define AUDPP_SRS_PARAMS_G 0
|
||
|
#define AUDPP_SRS_PARAMS_W 1
|
||
|
#define AUDPP_SRS_PARAMS_C 2
|
||
|
#define AUDPP_SRS_PARAMS_H 3
|
||
|
#define AUDPP_SRS_PARAMS_P 4
|
||
|
#define AUDPP_SRS_PARAMS_L 5
|
||
|
|
||
|
#define AUDPP_CMD_CFG_OBJ_UPDATE 0x8000
|
||
|
#define AUDPP_CMD_EQ_FLAG_DIS 0x0000
|
||
|
#define AUDPP_CMD_EQ_FLAG_ENA -1
|
||
|
#define AUDPP_CMD_IIR_FLAG_DIS 0x0000
|
||
|
#define AUDPP_CMD_IIR_FLAG_ENA -1
|
||
|
|
||
|
#define MAX_EVENT_CALLBACK_CLIENTS 2
|
||
|
|
||
|
#define AUDPP_CONCURRENCY_DEFAULT 6 /* All non tunnel mode */
|
||
|
#define AUDPP_MAX_DECODER_CNT 5
|
||
|
#define AUDPP_CODEC_MASK 0x000000FF
|
||
|
#define AUDPP_MODE_MASK 0x00000F00
|
||
|
#define AUDPP_OP_MASK 0xF0000000
|
||
|
|
||
|
struct audpp_decoder_info {
|
||
|
unsigned int codec;
|
||
|
pid_t pid;
|
||
|
};
|
||
|
|
||
|
struct audpp_state {
|
||
|
struct msm_adsp_module *mod;
|
||
|
audpp_event_func func[AUDPP_CLNT_MAX_COUNT];
|
||
|
void *private[AUDPP_CLNT_MAX_COUNT];
|
||
|
struct mutex *lock;
|
||
|
unsigned open_count;
|
||
|
unsigned enabled;
|
||
|
|
||
|
/* Related to decoder allocation */
|
||
|
struct mutex *lock_dec;
|
||
|
struct msm_adspdec_database *dec_database;
|
||
|
struct audpp_decoder_info dec_info_table[AUDPP_MAX_DECODER_CNT];
|
||
|
unsigned dec_inuse;
|
||
|
unsigned long concurrency;
|
||
|
|
||
|
/* which channels are actually enabled */
|
||
|
unsigned avsync_mask;
|
||
|
|
||
|
/* flags, 48 bits sample/bytes counter per channel */
|
||
|
uint16_t avsync[CH_COUNT * AUDPP_CLNT_MAX_COUNT + 1];
|
||
|
struct audpp_event_callback *cb_tbl[MAX_EVENT_CALLBACK_CLIENTS];
|
||
|
|
||
|
spinlock_t avsync_lock;
|
||
|
|
||
|
wait_queue_head_t event_wait;
|
||
|
};
|
||
|
|
||
|
struct audpp_state the_audpp_state = {
|
||
|
.lock = &audpp_lock,
|
||
|
.lock_dec = &audpp_dec_lock,
|
||
|
};
|
||
|
|
||
|
int audpp_send_queue1(void *cmd, unsigned len)
|
||
|
{
|
||
|
return msm_adsp_write(the_audpp_state.mod,
|
||
|
QDSP_uPAudPPCmd1Queue, cmd, len);
|
||
|
}
|
||
|
EXPORT_SYMBOL(audpp_send_queue1);
|
||
|
|
||
|
int audpp_send_queue2(void *cmd, unsigned len)
|
||
|
{
|
||
|
return msm_adsp_write(the_audpp_state.mod,
|
||
|
QDSP_uPAudPPCmd2Queue, cmd, len);
|
||
|
}
|
||
|
EXPORT_SYMBOL(audpp_send_queue2);
|
||
|
|
||
|
int audpp_send_queue3(void *cmd, unsigned len)
|
||
|
{
|
||
|
return msm_adsp_write(the_audpp_state.mod,
|
||
|
QDSP_uPAudPPCmd3Queue, cmd, len);
|
||
|
}
|
||
|
EXPORT_SYMBOL(audpp_send_queue3);
|
||
|
|
||
|
static int audpp_dsp_config(int enable)
|
||
|
{
|
||
|
audpp_cmd_cfg cmd;
|
||
|
|
||
|
cmd.cmd_id = AUDPP_CMD_CFG;
|
||
|
cmd.cfg = enable ? AUDPP_CMD_CFG_ENABLE : AUDPP_CMD_CFG_SLEEP;
|
||
|
|
||
|
return audpp_send_queue1(&cmd, sizeof(cmd));
|
||
|
}
|
||
|
|
||
|
int is_audpp_enable(void)
|
||
|
{
|
||
|
struct audpp_state *audpp = &the_audpp_state;
|
||
|
|
||
|
return audpp->enabled;
|
||
|
}
|
||
|
EXPORT_SYMBOL(is_audpp_enable);
|
||
|
|
||
|
int audpp_register_event_callback(struct audpp_event_callback *ecb)
|
||
|
{
|
||
|
struct audpp_state *audpp = &the_audpp_state;
|
||
|
int i;
|
||
|
|
||
|
mutex_lock(audpp->lock);
|
||
|
for (i = 0; i < MAX_EVENT_CALLBACK_CLIENTS; ++i) {
|
||
|
if (NULL == audpp->cb_tbl[i]) {
|
||
|
audpp->cb_tbl[i] = ecb;
|
||
|
mutex_unlock(audpp->lock);
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
mutex_unlock(audpp->lock);
|
||
|
return -1;
|
||
|
}
|
||
|
EXPORT_SYMBOL(audpp_register_event_callback);
|
||
|
|
||
|
int audpp_unregister_event_callback(struct audpp_event_callback *ecb)
|
||
|
{
|
||
|
struct audpp_state *audpp = &the_audpp_state;
|
||
|
int i;
|
||
|
|
||
|
mutex_lock(audpp->lock);
|
||
|
for (i = 0; i < MAX_EVENT_CALLBACK_CLIENTS; ++i) {
|
||
|
if (ecb == audpp->cb_tbl[i]) {
|
||
|
audpp->cb_tbl[i] = NULL;
|
||
|
mutex_unlock(audpp->lock);
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
mutex_unlock(audpp->lock);
|
||
|
return -1;
|
||
|
}
|
||
|
EXPORT_SYMBOL(audpp_unregister_event_callback);
|
||
|
|
||
|
static void audpp_broadcast(struct audpp_state *audpp, unsigned id,
|
||
|
uint16_t *msg)
|
||
|
{
|
||
|
unsigned n;
|
||
|
|
||
|
if ((id != AUDPP_MSG_PP_DISABLE_FEEDBACK) &&
|
||
|
(id != AUDPP_MSG_PP_FEATS_RE_ENABLE)) {
|
||
|
for (n = 0; n < AUDPP_CLNT_MAX_COUNT; n++) {
|
||
|
if (audpp->func[n])
|
||
|
audpp->func[n] (audpp->private[n], id, msg);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (n = 0; n < MAX_EVENT_CALLBACK_CLIENTS; ++n)
|
||
|
if (audpp->cb_tbl[n] && audpp->cb_tbl[n]->fn)
|
||
|
audpp->cb_tbl[n]->fn(audpp->cb_tbl[n]->private, id,
|
||
|
msg);
|
||
|
}
|
||
|
|
||
|
static void audpp_notify_clnt(struct audpp_state *audpp, unsigned clnt_id,
|
||
|
unsigned id, uint16_t *msg)
|
||
|
{
|
||
|
if (clnt_id < AUDPP_CLNT_MAX_COUNT && audpp->func[clnt_id])
|
||
|
audpp->func[clnt_id] (audpp->private[clnt_id], id, msg);
|
||
|
}
|
||
|
|
||
|
static void audpp_handle_pcmdmamiss(struct audpp_state *audpp,
|
||
|
uint16_t bit_mask)
|
||
|
{
|
||
|
uint8_t b_index;
|
||
|
|
||
|
for (b_index = 0; b_index < AUDPP_CLNT_MAX_COUNT; b_index++) {
|
||
|
if (bit_mask & (0x1 << b_index))
|
||
|
if (audpp->func[b_index])
|
||
|
audpp->func[b_index] (audpp->private[b_index],
|
||
|
AUDPP_MSG_PCMDMAMISSED,
|
||
|
&bit_mask);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void audpp_fake_event(struct audpp_state *audpp, int id,
|
||
|
unsigned event, unsigned arg)
|
||
|
{
|
||
|
uint16_t msg[1];
|
||
|
msg[0] = arg;
|
||
|
audpp->func[id] (audpp->private[id], event, msg);
|
||
|
}
|
||
|
|
||
|
static void audpp_dsp_event(void *data, unsigned id, size_t len,
|
||
|
void (*getevent) (void *ptr, size_t len))
|
||
|
{
|
||
|
struct audpp_state *audpp = data;
|
||
|
unsigned long flags;
|
||
|
uint16_t msg[8];
|
||
|
int cid = 0;
|
||
|
|
||
|
if (id == AUDPP_MSG_AVSYNC_MSG) {
|
||
|
spin_lock_irqsave(&audpp->avsync_lock, flags);
|
||
|
getevent(audpp->avsync, sizeof(audpp->avsync));
|
||
|
|
||
|
/* mask off any channels we're not watching to avoid
|
||
|
* cases where we might get one last update after
|
||
|
* disabling avsync and end up in an odd state when
|
||
|
* we next read...
|
||
|
*/
|
||
|
audpp->avsync[0] &= audpp->avsync_mask;
|
||
|
spin_unlock_irqrestore(&audpp->avsync_lock, flags);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
getevent(msg, sizeof(msg));
|
||
|
|
||
|
LOG(EV_EVENT, (id << 16) | msg[0]);
|
||
|
LOG(EV_DATA, (msg[1] << 16) | msg[2]);
|
||
|
|
||
|
switch (id) {
|
||
|
case AUDPP_MSG_STATUS_MSG:{
|
||
|
unsigned cid = msg[0];
|
||
|
MM_DBG("status %d %d %d\n", cid, msg[1], msg[2]);
|
||
|
if ((cid < 5) && audpp->func[cid])
|
||
|
audpp->func[cid] (audpp->private[cid], id, msg);
|
||
|
break;
|
||
|
}
|
||
|
case AUDPP_MSG_HOST_PCM_INTF_MSG:
|
||
|
if (audpp->func[5])
|
||
|
audpp->func[5] (audpp->private[5], id, msg);
|
||
|
break;
|
||
|
case AUDPP_MSG_PCMDMAMISSED:
|
||
|
audpp_handle_pcmdmamiss(audpp, msg[0]);
|
||
|
break;
|
||
|
case AUDPP_MSG_CFG_MSG:
|
||
|
if (msg[0] == AUDPP_MSG_ENA_ENA) {
|
||
|
MM_INFO("ENABLE\n");
|
||
|
if (!audpp->enabled) {
|
||
|
audpp->enabled = 1;
|
||
|
wake_up(&audpp->event_wait);
|
||
|
audpp_broadcast(audpp, id, msg);
|
||
|
} else {
|
||
|
cid = msg[1];
|
||
|
audpp_fake_event(audpp, cid,
|
||
|
id, AUDPP_MSG_ENA_ENA);
|
||
|
}
|
||
|
|
||
|
} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
|
||
|
if (audpp->open_count == 0) {
|
||
|
MM_INFO("DISABLE\n");
|
||
|
audpp->enabled = 0;
|
||
|
wake_up(&audpp->event_wait);
|
||
|
audpp_broadcast(audpp, id, msg);
|
||
|
} else {
|
||
|
cid = msg[1];
|
||
|
audpp_fake_event(audpp, cid,
|
||
|
id, AUDPP_MSG_ENA_DIS);
|
||
|
audpp->func[cid] = NULL;
|
||
|
audpp->private[cid] = NULL;
|
||
|
}
|
||
|
} else {
|
||
|
MM_ERR("invalid config msg %d\n", msg[0]);
|
||
|
}
|
||
|
break;
|
||
|
case AUDPP_MSG_ROUTING_ACK:
|
||
|
audpp_notify_clnt(audpp, msg[0], id, msg);
|
||
|
break;
|
||
|
case AUDPP_MSG_FLUSH_ACK:
|
||
|
audpp_notify_clnt(audpp, msg[0], id, msg);
|
||
|
break;
|
||
|
case ADSP_MESSAGE_ID:
|
||
|
MM_DBG("Received ADSP event: module enable/disable(audpptask)");
|
||
|
break;
|
||
|
case AUDPP_MSG_FEAT_QUERY_DM_DONE:
|
||
|
MM_INFO(" RTC ACK --> %x %x %x\n", msg[0],\
|
||
|
msg[1], msg[2]);
|
||
|
acdb_rtc_set_err(msg[2]);
|
||
|
break;
|
||
|
case AUDPP_MSG_PP_DISABLE_FEEDBACK:
|
||
|
MM_DBG("PP Disable feedback due to mips limitation");
|
||
|
audpp_broadcast(audpp, id, msg);
|
||
|
break;
|
||
|
case AUDPP_MSG_PP_FEATS_RE_ENABLE:
|
||
|
MM_DBG("Re-enable the disabled PP features");
|
||
|
audpp_broadcast(audpp, id, msg);
|
||
|
break;
|
||
|
default:
|
||
|
MM_ERR("unhandled msg id %x\n", id);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static struct msm_adsp_ops adsp_ops = {
|
||
|
.event = audpp_dsp_event,
|
||
|
};
|
||
|
|
||
|
int audpp_enable(int id, audpp_event_func func, void *private)
|
||
|
{
|
||
|
struct audpp_state *audpp = &the_audpp_state;
|
||
|
uint16_t msg[8];
|
||
|
int res = 0;
|
||
|
int rc;
|
||
|
|
||
|
if (id < -1 || id > 4)
|
||
|
return -EINVAL;
|
||
|
|
||
|
if (id == -1)
|
||
|
id = 5;
|
||
|
|
||
|
mutex_lock(audpp->lock);
|
||
|
if (audpp->func[id]) {
|
||
|
res = -EBUSY;
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
audpp->func[id] = func;
|
||
|
audpp->private[id] = private;
|
||
|
|
||
|
LOG(EV_ENABLE, 1);
|
||
|
if (audpp->open_count++ == 0) {
|
||
|
MM_DBG("enable\n");
|
||
|
res = msm_adsp_get("AUDPPTASK", &audpp->mod, &adsp_ops, audpp);
|
||
|
if (res < 0) {
|
||
|
MM_ERR("cannot open AUDPPTASK\n");
|
||
|
audpp->open_count = 0;
|
||
|
audpp->func[id] = NULL;
|
||
|
audpp->private[id] = NULL;
|
||
|
goto out;
|
||
|
}
|
||
|
LOG(EV_ENABLE, 2);
|
||
|
msm_adsp_enable(audpp->mod);
|
||
|
audpp_dsp_config(1);
|
||
|
rc = wait_event_timeout(audpp->event_wait,
|
||
|
(audpp->enabled == 1),
|
||
|
3 * HZ);
|
||
|
if (rc == 0)
|
||
|
msm_adsp_dump(audpp->mod);
|
||
|
} else {
|
||
|
if (audpp->enabled) {
|
||
|
msg[0] = AUDPP_MSG_ENA_ENA;
|
||
|
msg[1] = id;
|
||
|
res = msm_adsp_generate_event(audpp, audpp->mod,
|
||
|
AUDPP_MSG_CFG_MSG, sizeof(msg),
|
||
|
sizeof(uint16_t), (void *)msg);
|
||
|
if (res < 0)
|
||
|
goto out;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
res = 0;
|
||
|
out:
|
||
|
mutex_unlock(audpp->lock);
|
||
|
return res;
|
||
|
}
|
||
|
EXPORT_SYMBOL(audpp_enable);
|
||
|
|
||
|
void audpp_disable(int id, void *private)
|
||
|
{
|
||
|
struct audpp_state *audpp = &the_audpp_state;
|
||
|
uint16_t msg[8];
|
||
|
int rc;
|
||
|
|
||
|
if (id < -1 || id > 4)
|
||
|
return;
|
||
|
|
||
|
if (id == -1)
|
||
|
id = 5;
|
||
|
|
||
|
mutex_lock(audpp->lock);
|
||
|
LOG(EV_DISABLE, 1);
|
||
|
if (!audpp->func[id])
|
||
|
goto out;
|
||
|
if (audpp->private[id] != private)
|
||
|
goto out;
|
||
|
|
||
|
msg[0] = AUDPP_MSG_ENA_DIS;
|
||
|
msg[1] = id;
|
||
|
rc = msm_adsp_generate_event(audpp, audpp->mod,
|
||
|
AUDPP_MSG_CFG_MSG, sizeof(msg),
|
||
|
sizeof(uint16_t), (void *)msg);
|
||
|
if (rc < 0)
|
||
|
goto out;
|
||
|
|
||
|
if (--audpp->open_count == 0) {
|
||
|
MM_DBG("disable\n");
|
||
|
LOG(EV_DISABLE, 2);
|
||
|
audpp_dsp_config(0);
|
||
|
rc = wait_event_timeout(audpp->event_wait,
|
||
|
(audpp->enabled == 0),
|
||
|
3 * HZ);
|
||
|
if (audpp->enabled == 0)
|
||
|
MM_INFO("Received CFG_MSG_DISABLE from ADSP\n");
|
||
|
else {
|
||
|
MM_ERR("Didn't receive CFG_MSG DISABLE \
|
||
|
message from ADSP\n");
|
||
|
if (rc == 0)
|
||
|
msm_adsp_dump(audpp->mod);
|
||
|
}
|
||
|
msm_adsp_disable(audpp->mod);
|
||
|
msm_adsp_put(audpp->mod);
|
||
|
audpp->mod = NULL;
|
||
|
}
|
||
|
out:
|
||
|
mutex_unlock(audpp->lock);
|
||
|
}
|
||
|
EXPORT_SYMBOL(audpp_disable);
|
||
|
|
||
|
#define BAD_ID(id) ((id < 0) || (id >= CH_COUNT))
|
||
|
|
||
|
void audpp_avsync(int id, unsigned rate)
|
||
|
{
|
||
|
unsigned long flags;
|
||
|
audpp_cmd_avsync cmd;
|
||
|
|
||
|
if (BAD_ID(id))
|
||
|
return;
|
||
|
|
||
|
spin_lock_irqsave(&the_audpp_state.avsync_lock, flags);
|
||
|
if (rate)
|
||
|
the_audpp_state.avsync_mask |= (1 << id);
|
||
|
else
|
||
|
the_audpp_state.avsync_mask &= (~(1 << id));
|
||
|
the_audpp_state.avsync[0] &= the_audpp_state.avsync_mask;
|
||
|
spin_unlock_irqrestore(&the_audpp_state.avsync_lock, flags);
|
||
|
|
||
|
cmd.cmd_id = AUDPP_CMD_AVSYNC;
|
||
|
cmd.object_number = id;
|
||
|
cmd.interrupt_interval_lsw = rate;
|
||
|
cmd.interrupt_interval_msw = rate >> 16;
|
||
|
audpp_send_queue1(&cmd, sizeof(cmd));
|
||
|
}
|
||
|
EXPORT_SYMBOL(audpp_avsync);
|
||
|
|
||
|
unsigned audpp_avsync_sample_count(int id)
|
||
|
{
|
||
|
struct audpp_state *audpp = &the_audpp_state;
|
||
|
uint16_t *avsync = audpp->avsync;
|
||
|
unsigned val;
|
||
|
unsigned long flags;
|
||
|
unsigned mask;
|
||
|
|
||
|
if (BAD_ID(id))
|
||
|
return 0;
|
||
|
|
||
|
mask = 1 << id;
|
||
|
id = id * AUDPP_AVSYNC_INFO_SIZE + 2;
|
||
|
spin_lock_irqsave(&audpp->avsync_lock, flags);
|
||
|
if (avsync[0] & mask)
|
||
|
val = (avsync[id] << 16) | avsync[id + 1];
|
||
|
else
|
||
|
val = 0;
|
||
|
spin_unlock_irqrestore(&audpp->avsync_lock, flags);
|
||
|
|
||
|
return val;
|
||
|
}
|
||
|
EXPORT_SYMBOL(audpp_avsync_sample_count);
|
||
|
|
||
|
unsigned audpp_avsync_byte_count(int id)
|
||
|
{
|
||
|
struct audpp_state *audpp = &the_audpp_state;
|
||
|
uint16_t *avsync = audpp->avsync;
|
||
|
unsigned val;
|
||
|
unsigned long flags;
|
||
|
unsigned mask;
|
||
|
|
||
|
if (BAD_ID(id))
|
||
|
return 0;
|
||
|
|
||
|
mask = 1 << id;
|
||
|
id = id * AUDPP_AVSYNC_INFO_SIZE + 5;
|
||
|
spin_lock_irqsave(&audpp->avsync_lock, flags);
|
||
|
if (avsync[0] & mask)
|
||
|
val = (avsync[id] << 16) | avsync[id + 1];
|
||
|
else
|
||
|
val = 0;
|
||
|
spin_unlock_irqrestore(&audpp->avsync_lock, flags);
|
||
|
|
||
|
return val;
|
||
|
}
|
||
|
EXPORT_SYMBOL(audpp_avsync_byte_count);
|
||
|
|
||
|
int audpp_set_volume_and_pan(unsigned id, unsigned volume, int pan)
|
||
|
{
|
||
|
/* cmd, obj_cfg[7], cmd_type, volume, pan */
|
||
|
uint16_t cmd[11];
|
||
|
|
||
|
if (id > 6)
|
||
|
return -EINVAL;
|
||
|
|
||
|
memset(cmd, 0, sizeof(cmd));
|
||
|
cmd[0] = AUDPP_CMD_CFG_OBJECT_PARAMS;
|
||
|
cmd[1 + id] = AUDPP_CMD_CFG_OBJ_UPDATE;
|
||
|
cmd[8] = AUDPP_CMD_VOLUME_PAN;
|
||
|
cmd[9] = volume;
|
||
|
cmd[10] = pan;
|
||
|
|
||
|
return audpp_send_queue3(cmd, sizeof(cmd));
|
||
|
}
|
||
|
EXPORT_SYMBOL(audpp_set_volume_and_pan);
|
||
|
|
||
|
/* Implementation of COPP features */
|
||
|
int audpp_dsp_set_mbadrc(unsigned id, unsigned enable,
|
||
|
audpp_cmd_cfg_object_params_mbadrc *mbadrc)
|
||
|
{
|
||
|
audpp_cmd_cfg_object_params_mbadrc cmd;
|
||
|
|
||
|
if (id != 6)
|
||
|
return -EINVAL;
|
||
|
|
||
|
memset(&cmd, 0, sizeof(cmd));
|
||
|
cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
|
||
|
cmd.common.command_type = AUDPP_CMD_MBADRC;
|
||
|
|
||
|
if (enable) {
|
||
|
memcpy(&cmd.num_bands, &mbadrc->num_bands,
|
||
|
sizeof(*mbadrc) -
|
||
|
(AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2));
|
||
|
cmd.enable = AUDPP_CMD_ADRC_FLAG_ENA;
|
||
|
} else
|
||
|
cmd.enable = AUDPP_CMD_ADRC_FLAG_DIS;
|
||
|
|
||
|
/*order the writes to mbadrc */
|
||
|
dma_coherent_pre_ops();
|
||
|
return audpp_send_queue3(&cmd, sizeof(cmd));
|
||
|
}
|
||
|
EXPORT_SYMBOL(audpp_dsp_set_mbadrc);
|
||
|
|
||
|
int audpp_dsp_set_qconcert_plus(unsigned id, unsigned enable,
|
||
|
audpp_cmd_cfg_object_params_qconcert *
|
||
|
qconcert_plus)
|
||
|
{
|
||
|
audpp_cmd_cfg_object_params_qconcert cmd;
|
||
|
if (id != 6)
|
||
|
return -EINVAL;
|
||
|
|
||
|
memset(&cmd, 0, sizeof(cmd));
|
||
|
cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
|
||
|
cmd.common.command_type = AUDPP_CMD_QCONCERT;
|
||
|
|
||
|
if (enable) {
|
||
|
memcpy(&cmd.op_mode, &qconcert_plus->op_mode,
|
||
|
sizeof(audpp_cmd_cfg_object_params_qconcert) -
|
||
|
(AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2));
|
||
|
cmd.enable_flag = AUDPP_CMD_ADRC_FLAG_ENA;
|
||
|
} else
|
||
|
cmd.enable_flag = AUDPP_CMD_ADRC_FLAG_DIS;
|
||
|
|
||
|
return audpp_send_queue3(&cmd, sizeof(cmd));
|
||
|
}
|
||
|
|
||
|
int audpp_dsp_set_rx_iir(unsigned id, unsigned enable,
|
||
|
audpp_cmd_cfg_object_params_pcm *iir)
|
||
|
{
|
||
|
audpp_cmd_cfg_object_params_pcm cmd;
|
||
|
|
||
|
if (id != 6)
|
||
|
return -EINVAL;
|
||
|
|
||
|
memset(&cmd, 0, sizeof(cmd));
|
||
|
cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
|
||
|
cmd.common.command_type = AUDPP_CMD_IIR_TUNING_FILTER;
|
||
|
|
||
|
if (enable) {
|
||
|
cmd.active_flag = AUDPP_CMD_IIR_FLAG_ENA;
|
||
|
cmd.num_bands = iir->num_bands;
|
||
|
memcpy(&cmd.params_filter, &iir->params_filter,
|
||
|
sizeof(iir->params_filter));
|
||
|
} else
|
||
|
cmd.active_flag = AUDPP_CMD_IIR_FLAG_DIS;
|
||
|
|
||
|
return audpp_send_queue3(&cmd, sizeof(cmd));
|
||
|
}
|
||
|
EXPORT_SYMBOL(audpp_dsp_set_rx_iir);
|
||
|
|
||
|
int audpp_dsp_set_rx_srs_trumedia_g(
|
||
|
struct audpp_cmd_cfg_object_params_srstm_g *srstm)
|
||
|
{
|
||
|
struct audpp_cmd_cfg_object_params_srstm_g cmd;
|
||
|
|
||
|
MM_DBG("%s\n", __func__);
|
||
|
memset(&cmd, 0, sizeof(cmd));
|
||
|
cmd.common.cmd_id = AUDPP_SRS_PARAMS;
|
||
|
cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
|
||
|
cmd.common.command_type = AUDPP_SRS_PARAMS_G;
|
||
|
|
||
|
memcpy(cmd.v, srstm->v, sizeof(srstm->v));
|
||
|
|
||
|
return audpp_send_queue3(&cmd, sizeof(cmd));
|
||
|
}
|
||
|
EXPORT_SYMBOL(audpp_dsp_set_rx_srs_trumedia_g);
|
||
|
|
||
|
int audpp_dsp_set_rx_srs_trumedia_w(
|
||
|
struct audpp_cmd_cfg_object_params_srstm_w *srstm)
|
||
|
{
|
||
|
struct audpp_cmd_cfg_object_params_srstm_w cmd;
|
||
|
|
||
|
MM_DBG("%s\n", __func__);
|
||
|
memset(&cmd, 0, sizeof(cmd));
|
||
|
cmd.common.cmd_id = AUDPP_SRS_PARAMS;
|
||
|
cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
|
||
|
cmd.common.command_type = AUDPP_SRS_PARAMS_W;
|
||
|
|
||
|
memcpy(cmd.v, srstm->v, sizeof(srstm->v));
|
||
|
|
||
|
return audpp_send_queue3(&cmd, sizeof(cmd));
|
||
|
}
|
||
|
EXPORT_SYMBOL(audpp_dsp_set_rx_srs_trumedia_w);
|
||
|
|
||
|
int audpp_dsp_set_rx_srs_trumedia_c(
|
||
|
struct audpp_cmd_cfg_object_params_srstm_c *srstm)
|
||
|
{
|
||
|
struct audpp_cmd_cfg_object_params_srstm_c cmd;
|
||
|
|
||
|
MM_DBG("%s\n", __func__);
|
||
|
memset(&cmd, 0, sizeof(cmd));
|
||
|
cmd.common.cmd_id = AUDPP_SRS_PARAMS;
|
||
|
cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
|
||
|
cmd.common.command_type = AUDPP_SRS_PARAMS_C;
|
||
|
|
||
|
memcpy(cmd.v, srstm->v, sizeof(srstm->v));
|
||
|
|
||
|
return audpp_send_queue3(&cmd, sizeof(cmd));
|
||
|
}
|
||
|
EXPORT_SYMBOL(audpp_dsp_set_rx_srs_trumedia_c);
|
||
|
|
||
|
int audpp_dsp_set_rx_srs_trumedia_h(
|
||
|
struct audpp_cmd_cfg_object_params_srstm_h *srstm)
|
||
|
{
|
||
|
struct audpp_cmd_cfg_object_params_srstm_h cmd;
|
||
|
|
||
|
MM_DBG("%s\n", __func__);
|
||
|
memset(&cmd, 0, sizeof(cmd));
|
||
|
cmd.common.cmd_id = AUDPP_SRS_PARAMS;
|
||
|
cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
|
||
|
cmd.common.command_type = AUDPP_SRS_PARAMS_H;
|
||
|
|
||
|
memcpy(cmd.v, srstm->v, sizeof(srstm->v));
|
||
|
|
||
|
return audpp_send_queue3(&cmd, sizeof(cmd));
|
||
|
}
|
||
|
EXPORT_SYMBOL(audpp_dsp_set_rx_srs_trumedia_h);
|
||
|
|
||
|
int audpp_dsp_set_rx_srs_trumedia_p(
|
||
|
struct audpp_cmd_cfg_object_params_srstm_p *srstm)
|
||
|
{
|
||
|
struct audpp_cmd_cfg_object_params_srstm_p cmd;
|
||
|
|
||
|
MM_DBG("%s\n", __func__);
|
||
|
memset(&cmd, 0, sizeof(cmd));
|
||
|
cmd.common.cmd_id = AUDPP_SRS_PARAMS;
|
||
|
cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
|
||
|
cmd.common.command_type = AUDPP_SRS_PARAMS_P;
|
||
|
|
||
|
memcpy(cmd.v, srstm->v, sizeof(srstm->v));
|
||
|
|
||
|
return audpp_send_queue3(&cmd, sizeof(cmd));
|
||
|
}
|
||
|
EXPORT_SYMBOL(audpp_dsp_set_rx_srs_trumedia_p);
|
||
|
|
||
|
int audpp_dsp_set_rx_srs_trumedia_l(
|
||
|
struct audpp_cmd_cfg_object_params_srstm_l *srstm)
|
||
|
{
|
||
|
struct audpp_cmd_cfg_object_params_srstm_l cmd;
|
||
|
|
||
|
MM_DBG("%s\n", __func__);
|
||
|
memset(&cmd, 0, sizeof(cmd));
|
||
|
cmd.common.cmd_id = AUDPP_SRS_PARAMS;
|
||
|
cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
|
||
|
cmd.common.command_type = AUDPP_SRS_PARAMS_L;
|
||
|
|
||
|
memcpy(cmd.v, srstm->v, sizeof(srstm->v));
|
||
|
|
||
|
return audpp_send_queue3(&cmd, sizeof(cmd));
|
||
|
}
|
||
|
EXPORT_SYMBOL(audpp_dsp_set_rx_srs_trumedia_l);
|
||
|
|
||
|
/* Implementation Of COPP + POPP */
|
||
|
int audpp_dsp_set_eq(unsigned id, unsigned enable,
|
||
|
audpp_cmd_cfg_object_params_eqalizer *eq)
|
||
|
{
|
||
|
audpp_cmd_cfg_object_params_eqalizer cmd;
|
||
|
unsigned short *id_ptr = (unsigned short *)&cmd;
|
||
|
|
||
|
if (id > 6 || id == 5)
|
||
|
return -EINVAL;
|
||
|
|
||
|
memset(&cmd, 0, sizeof(cmd));
|
||
|
id_ptr[1 + id] = AUDPP_CMD_CFG_OBJ_UPDATE;
|
||
|
cmd.common.command_type = AUDPP_CMD_EQUALIZER;
|
||
|
|
||
|
if (enable) {
|
||
|
cmd.eq_flag = AUDPP_CMD_EQ_FLAG_ENA;
|
||
|
cmd.num_bands = eq->num_bands;
|
||
|
memcpy(&cmd.eq_coeff, &eq->eq_coeff, sizeof(eq->eq_coeff));
|
||
|
} else
|
||
|
cmd.eq_flag = AUDPP_CMD_EQ_FLAG_DIS;
|
||
|
|
||
|
return audpp_send_queue3(&cmd, sizeof(cmd));
|
||
|
}
|
||
|
EXPORT_SYMBOL(audpp_dsp_set_eq);
|
||
|
|
||
|
int audpp_dsp_set_vol_pan(unsigned id,
|
||
|
audpp_cmd_cfg_object_params_volume *vol_pan)
|
||
|
{
|
||
|
audpp_cmd_cfg_object_params_volume cmd;
|
||
|
unsigned short *id_ptr = (unsigned short *)&cmd;
|
||
|
|
||
|
if (id > 6)
|
||
|
return -EINVAL;
|
||
|
|
||
|
memset(&cmd, 0, sizeof(cmd));
|
||
|
id_ptr[1 + id] = AUDPP_CMD_CFG_OBJ_UPDATE;
|
||
|
cmd.common.command_type = AUDPP_CMD_VOLUME_PAN;
|
||
|
|
||
|
cmd.volume = vol_pan->volume;
|
||
|
cmd.pan = vol_pan->pan;
|
||
|
|
||
|
return audpp_send_queue3(&cmd, sizeof(cmd));
|
||
|
}
|
||
|
EXPORT_SYMBOL(audpp_dsp_set_vol_pan);
|
||
|
|
||
|
int audpp_pause(unsigned id, int pause)
|
||
|
{
|
||
|
/* pause 1 = pause 0 = resume */
|
||
|
u16 pause_cmd[AUDPP_CMD_DEC_CTRL_LEN / sizeof(unsigned short)];
|
||
|
|
||
|
if (id >= CH_COUNT)
|
||
|
return -EINVAL;
|
||
|
|
||
|
memset(pause_cmd, 0, sizeof(pause_cmd));
|
||
|
|
||
|
pause_cmd[0] = AUDPP_CMD_DEC_CTRL;
|
||
|
if (pause == 1)
|
||
|
pause_cmd[1 + id] = AUDPP_CMD_UPDATE_V | AUDPP_CMD_PAUSE_V;
|
||
|
else if (pause == 0)
|
||
|
pause_cmd[1 + id] = AUDPP_CMD_UPDATE_V | AUDPP_CMD_RESUME_V;
|
||
|
else
|
||
|
return -EINVAL;
|
||
|
|
||
|
return audpp_send_queue1(pause_cmd, sizeof(pause_cmd));
|
||
|
}
|
||
|
EXPORT_SYMBOL(audpp_pause);
|
||
|
|
||
|
int audpp_flush(unsigned id)
|
||
|
{
|
||
|
u16 flush_cmd[AUDPP_CMD_DEC_CTRL_LEN / sizeof(unsigned short)];
|
||
|
|
||
|
if (id >= CH_COUNT)
|
||
|
return -EINVAL;
|
||
|
|
||
|
memset(flush_cmd, 0, sizeof(flush_cmd));
|
||
|
|
||
|
flush_cmd[0] = AUDPP_CMD_DEC_CTRL;
|
||
|
flush_cmd[1 + id] = AUDPP_CMD_UPDATE_V | AUDPP_CMD_FLUSH_V;
|
||
|
|
||
|
return audpp_send_queue1(flush_cmd, sizeof(flush_cmd));
|
||
|
}
|
||
|
EXPORT_SYMBOL(audpp_flush);
|
||
|
|
||
|
/* dec_attrb = 7:0, 0 - No Decoder, else supported decoder *
|
||
|
* like mp3, aac, wma etc ... *
|
||
|
* = 15:8, bit[8] = 1 - Tunnel, bit[9] = 1 - NonTunnel *
|
||
|
* = 31:16, reserved */
|
||
|
int audpp_adec_alloc(unsigned dec_attrb, const char **module_name,
|
||
|
unsigned *queueid)
|
||
|
{
|
||
|
struct audpp_state *audpp = &the_audpp_state;
|
||
|
int decid = -1, idx, lidx, mode, codec;
|
||
|
int codecs_supported, min_codecs_supported;
|
||
|
unsigned int *concurrency_entry;
|
||
|
mutex_lock(audpp->lock_dec);
|
||
|
/* Represents in bit mask */
|
||
|
mode = ((dec_attrb & AUDPP_MODE_MASK) << 16);
|
||
|
codec = (1 << (dec_attrb & AUDPP_CODEC_MASK));
|
||
|
/* Point to Last entry of the row */
|
||
|
concurrency_entry = ((audpp->dec_database->dec_concurrency_table +
|
||
|
((audpp->concurrency + 1) *
|
||
|
(audpp->dec_database->num_dec))) - 1);
|
||
|
|
||
|
lidx = audpp->dec_database->num_dec;
|
||
|
min_codecs_supported = sizeof(unsigned int) * 8;
|
||
|
|
||
|
MM_DBG("mode = 0x%08x codec = 0x%08x\n", mode, codec);
|
||
|
|
||
|
for (idx = lidx; idx > 0; idx--, concurrency_entry--) {
|
||
|
if (!(audpp->dec_inuse & (1 << (idx - 1)))) {
|
||
|
if ((mode & *concurrency_entry) &&
|
||
|
(codec & *concurrency_entry)) {
|
||
|
/* Check supports minimum number codecs */
|
||
|
codecs_supported =
|
||
|
audpp->dec_database->dec_info_list[idx -
|
||
|
1].
|
||
|
nr_codec_support;
|
||
|
if (codecs_supported < min_codecs_supported) {
|
||
|
lidx = idx - 1;
|
||
|
min_codecs_supported = codecs_supported;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (lidx < audpp->dec_database->num_dec) {
|
||
|
audpp->dec_inuse |= (1 << lidx);
|
||
|
*module_name =
|
||
|
audpp->dec_database->dec_info_list[lidx].module_name;
|
||
|
*queueid =
|
||
|
audpp->dec_database->dec_info_list[lidx].module_queueid;
|
||
|
decid = audpp->dec_database->dec_info_list[lidx].module_decid;
|
||
|
audpp->dec_info_table[lidx].codec =
|
||
|
(dec_attrb & AUDPP_CODEC_MASK);
|
||
|
audpp->dec_info_table[lidx].pid = current->pid;
|
||
|
/* point to row to get supported operation */
|
||
|
concurrency_entry =
|
||
|
((audpp->dec_database->dec_concurrency_table +
|
||
|
((audpp->concurrency) * (audpp->dec_database->num_dec))) +
|
||
|
lidx);
|
||
|
decid |= ((*concurrency_entry & AUDPP_OP_MASK) >> 12);
|
||
|
MM_INFO("decid =0x%08x module_name=%s, queueid=%d \n",
|
||
|
decid, *module_name, *queueid);
|
||
|
}
|
||
|
mutex_unlock(audpp->lock_dec);
|
||
|
return decid;
|
||
|
|
||
|
}
|
||
|
EXPORT_SYMBOL(audpp_adec_alloc);
|
||
|
|
||
|
void audpp_adec_free(int decid)
|
||
|
{
|
||
|
struct audpp_state *audpp = &the_audpp_state;
|
||
|
int idx;
|
||
|
mutex_lock(audpp->lock_dec);
|
||
|
for (idx = audpp->dec_database->num_dec; idx > 0; idx--) {
|
||
|
if (audpp->dec_database->dec_info_list[idx - 1].module_decid ==
|
||
|
decid) {
|
||
|
audpp->dec_inuse &= ~(1 << (idx - 1));
|
||
|
audpp->dec_info_table[idx - 1].codec = -1;
|
||
|
audpp->dec_info_table[idx - 1].pid = 0;
|
||
|
MM_INFO("free decid =%d \n", decid);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
mutex_unlock(audpp->lock_dec);
|
||
|
return;
|
||
|
|
||
|
}
|
||
|
EXPORT_SYMBOL(audpp_adec_free);
|
||
|
|
||
|
static ssize_t concurrency_show(struct device *dev,
|
||
|
struct device_attribute *attr, char *buf)
|
||
|
{
|
||
|
struct audpp_state *audpp = &the_audpp_state;
|
||
|
int rc;
|
||
|
mutex_lock(audpp->lock_dec);
|
||
|
rc = sprintf(buf, "%ld\n", audpp->concurrency);
|
||
|
mutex_unlock(audpp->lock_dec);
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
static ssize_t concurrency_store(struct device *dev,
|
||
|
struct device_attribute *attr,
|
||
|
const char *buf, size_t count)
|
||
|
{
|
||
|
struct audpp_state *audpp = &the_audpp_state;
|
||
|
unsigned long concurrency;
|
||
|
int rc = -1;
|
||
|
mutex_lock(audpp->lock_dec);
|
||
|
if (audpp->dec_inuse) {
|
||
|
MM_ERR("Can not change profile, while playback in progress\n");
|
||
|
goto done;
|
||
|
}
|
||
|
rc = strict_strtoul(buf, 10, &concurrency);
|
||
|
if (!rc &&
|
||
|
(concurrency < audpp->dec_database->num_concurrency_support)) {
|
||
|
audpp->concurrency = concurrency;
|
||
|
MM_DBG("Concurrency case %ld\n", audpp->concurrency);
|
||
|
rc = count;
|
||
|
} else {
|
||
|
MM_ERR("Not a valid Concurrency case\n");
|
||
|
rc = -EINVAL;
|
||
|
}
|
||
|
done:
|
||
|
mutex_unlock(audpp->lock_dec);
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
static ssize_t decoder_info_show(struct device *dev,
|
||
|
struct device_attribute *attr, char *buf);
|
||
|
static struct device_attribute dev_attr_decoder[AUDPP_MAX_DECODER_CNT] = {
|
||
|
__ATTR(decoder0, S_IRUGO, decoder_info_show, NULL),
|
||
|
__ATTR(decoder1, S_IRUGO, decoder_info_show, NULL),
|
||
|
__ATTR(decoder2, S_IRUGO, decoder_info_show, NULL),
|
||
|
__ATTR(decoder3, S_IRUGO, decoder_info_show, NULL),
|
||
|
__ATTR(decoder4, S_IRUGO, decoder_info_show, NULL),
|
||
|
};
|
||
|
|
||
|
static ssize_t decoder_info_show(struct device *dev,
|
||
|
struct device_attribute *attr, char *buf)
|
||
|
{
|
||
|
int cpy_sz = 0;
|
||
|
struct audpp_state *audpp = &the_audpp_state;
|
||
|
const ptrdiff_t off = attr - dev_attr_decoder; /* decoder number */
|
||
|
mutex_lock(audpp->lock_dec);
|
||
|
cpy_sz += scnprintf(buf + cpy_sz, PAGE_SIZE - cpy_sz, "%d:",
|
||
|
audpp->dec_info_table[off].codec);
|
||
|
cpy_sz += scnprintf(buf + cpy_sz, PAGE_SIZE - cpy_sz, "%d\n",
|
||
|
audpp->dec_info_table[off].pid);
|
||
|
mutex_unlock(audpp->lock_dec);
|
||
|
return cpy_sz;
|
||
|
}
|
||
|
|
||
|
static DEVICE_ATTR(concurrency, S_IWUSR | S_IRUGO, concurrency_show,
|
||
|
concurrency_store);
|
||
|
static int audpp_probe(struct platform_device *pdev)
|
||
|
{
|
||
|
int rc, idx;
|
||
|
struct audpp_state *audpp = &the_audpp_state;
|
||
|
audpp->concurrency = AUDPP_CONCURRENCY_DEFAULT;
|
||
|
audpp->dec_database =
|
||
|
(struct msm_adspdec_database *)pdev->dev.platform_data;
|
||
|
|
||
|
MM_INFO("Number of decoder supported %d\n",
|
||
|
audpp->dec_database->num_dec);
|
||
|
MM_INFO("Number of concurrency supported %d\n",
|
||
|
audpp->dec_database->num_concurrency_support);
|
||
|
|
||
|
init_waitqueue_head(&audpp->event_wait);
|
||
|
|
||
|
spin_lock_init(&audpp->avsync_lock);
|
||
|
|
||
|
for (idx = 0; idx < audpp->dec_database->num_dec; idx++) {
|
||
|
audpp->dec_info_table[idx].codec = -1;
|
||
|
audpp->dec_info_table[idx].pid = 0;
|
||
|
MM_INFO("module_name:%s\n",
|
||
|
audpp->dec_database->dec_info_list[idx].module_name);
|
||
|
MM_INFO("queueid:%d\n",
|
||
|
audpp->dec_database->dec_info_list[idx].module_queueid);
|
||
|
MM_INFO("decid:%d\n",
|
||
|
audpp->dec_database->dec_info_list[idx].module_decid);
|
||
|
MM_INFO("nr_codec_support:%d\n",
|
||
|
audpp->dec_database->dec_info_list[idx].
|
||
|
nr_codec_support);
|
||
|
}
|
||
|
|
||
|
for (idx = 0; idx < audpp->dec_database->num_dec; idx++) {
|
||
|
rc = device_create_file(&pdev->dev, &dev_attr_decoder[idx]);
|
||
|
if (rc)
|
||
|
goto err;
|
||
|
}
|
||
|
rc = device_create_file(&pdev->dev, &dev_attr_concurrency);
|
||
|
if (rc)
|
||
|
goto err;
|
||
|
else
|
||
|
goto done;
|
||
|
err:
|
||
|
while (idx--)
|
||
|
device_remove_file(&pdev->dev, &dev_attr_decoder[idx]);
|
||
|
done:
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
static struct platform_driver audpp_plat_driver = {
|
||
|
.probe = audpp_probe,
|
||
|
.driver = {
|
||
|
.name = "msm_adspdec",
|
||
|
.owner = THIS_MODULE,
|
||
|
},
|
||
|
};
|
||
|
|
||
|
static int __init audpp_init(void)
|
||
|
{
|
||
|
return platform_driver_register(&audpp_plat_driver);
|
||
|
}
|
||
|
|
||
|
device_initcall(audpp_init);
|