528 lines
15 KiB
C
528 lines
15 KiB
C
/*
|
|
* Common code to deal with the AUDPREPROC dsp task (audio preprocessing)
|
|
*
|
|
* Copyright (c) 2009-2011, The Linux Foundation. All rights reserved.
|
|
*
|
|
* Based on the audpp layer in arch/arm/mach-msm/qdsp5/audpp.c
|
|
*
|
|
* Copyright (C) 2008 Google, Inc.
|
|
*
|
|
* 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.
|
|
*
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/module.h>
|
|
#include <linux/wakelock.h>
|
|
#include <linux/pm_qos.h>
|
|
|
|
#include <mach/msm_adsp.h>
|
|
#include <mach/qdsp5v2/audio_acdbi.h>
|
|
#include <mach/qdsp5v2/audpreproc.h>
|
|
#include <mach/debug_mm.h>
|
|
#include <mach/qdsp5v2/qdsp5audpreprocmsg.h>
|
|
#include <mach/cpuidle.h>
|
|
|
|
static DEFINE_MUTEX(audpreproc_lock);
|
|
static struct wake_lock audpre_wake_lock;
|
|
static struct pm_qos_request audpre_pm_qos_req;
|
|
|
|
struct msm_adspenc_info {
|
|
const char *module_name;
|
|
unsigned module_queueids;
|
|
int module_encid; /* streamid */
|
|
int enc_formats; /* supported formats */
|
|
int nr_codec_support; /* number of codec suported */
|
|
};
|
|
|
|
#define ENC_MODULE_INFO(name, queueids, encid, formats, nr_codec) \
|
|
{.module_name = name, .module_queueids = queueids, \
|
|
.module_encid = encid, .enc_formats = formats, \
|
|
.nr_codec_support = nr_codec }
|
|
|
|
#define MAX_EVENT_CALLBACK_CLIENTS 1
|
|
|
|
#define ENC0_FORMAT ((1<<MSM_ADSP_ENC_CODEC_WAV)| \
|
|
(1<<MSM_ADSP_ENC_CODEC_SBC) | (1<<MSM_ADSP_ENC_CODEC_EXT_WAV))
|
|
|
|
#define ENC1_FORMAT ((1<<MSM_ADSP_ENC_CODEC_WAV)| \
|
|
(1<<MSM_ADSP_ENC_CODEC_AAC) | (1<<MSM_ADSP_ENC_CODEC_AMRNB) | \
|
|
(1<<MSM_ADSP_ENC_CODEC_EVRC) | (1<<MSM_ADSP_ENC_CODEC_QCELP) | \
|
|
(1<<MSM_ADSP_ENC_CODEC_EXT_WAV))
|
|
|
|
#define ENC2_FORMAT ((1<<MSM_ADSP_ENC_CODEC_WAV) | \
|
|
(1<<MSM_ADSP_ENC_CODEC_EXT_WAV))
|
|
|
|
struct msm_adspenc_database {
|
|
unsigned num_enc;
|
|
struct msm_adspenc_info *enc_info_list;
|
|
};
|
|
|
|
static struct msm_adspenc_info enc_info_list[] = {
|
|
ENC_MODULE_INFO("AUDREC0TASK", \
|
|
((QDSP_uPAudRec0BitStreamQueue << 16)| \
|
|
QDSP_uPAudRec0CmdQueue), 0, \
|
|
(ENC0_FORMAT | (1 << MSM_ADSP_ENC_MODE_TUNNEL)), 3),
|
|
|
|
ENC_MODULE_INFO("AUDREC1TASK", \
|
|
((QDSP_uPAudRec1BitStreamQueue << 16)| \
|
|
QDSP_uPAudRec1CmdQueue), 1, \
|
|
(ENC1_FORMAT | (1 << MSM_ADSP_ENC_MODE_TUNNEL) | \
|
|
(1 << MSM_ADSP_ENC_MODE_NON_TUNNEL)), 6),
|
|
|
|
ENC_MODULE_INFO("AUDREC2TASK", \
|
|
((QDSP_uPAudRec2BitStreamQueue << 16)| \
|
|
QDSP_uPAudRec2CmdQueue), 2, \
|
|
(ENC2_FORMAT | (1 << MSM_ADSP_ENC_MODE_TUNNEL)), 2),
|
|
|
|
};
|
|
|
|
static struct msm_adspenc_database msm_enc_database = {
|
|
.num_enc = ARRAY_SIZE(enc_info_list),
|
|
.enc_info_list = enc_info_list,
|
|
};
|
|
|
|
|
|
static struct audrec_session_info
|
|
session_info[MAX_ENC_COUNT] = { {0, 0}, {0, 0}, {0, 0} };
|
|
|
|
struct audpreproc_state {
|
|
struct msm_adsp_module *mod;
|
|
audpreproc_event_func func[MAX_ENC_COUNT];
|
|
void *private[MAX_ENC_COUNT];
|
|
struct mutex *lock;
|
|
unsigned open_count;
|
|
unsigned enc_inuse;
|
|
struct audpreproc_event_callback *cb_tbl[MAX_EVENT_CALLBACK_CLIENTS];
|
|
};
|
|
|
|
static struct audpreproc_state the_audpreproc_state = {
|
|
.lock = &audpreproc_lock,
|
|
};
|
|
|
|
static inline void prevent_suspend(void)
|
|
{
|
|
wake_lock(&audpre_wake_lock);
|
|
pm_qos_update_request(&audpre_pm_qos_req,
|
|
msm_cpuidle_get_deep_idle_latency());
|
|
}
|
|
static inline void allow_suspend(void)
|
|
{
|
|
pm_qos_update_request(&audpre_pm_qos_req, PM_QOS_DEFAULT_VALUE);
|
|
wake_unlock(&audpre_wake_lock);
|
|
}
|
|
|
|
/* DSP preproc event handler */
|
|
static void audpreproc_dsp_event(void *data, unsigned id, size_t len,
|
|
void (*getevent)(void *ptr, size_t len))
|
|
{
|
|
struct audpreproc_state *audpreproc = data;
|
|
int n = 0;
|
|
|
|
switch (id) {
|
|
case AUDPREPROC_CMD_CFG_DONE_MSG: {
|
|
struct audpreproc_cmd_cfg_done_msg cfg_done_msg;
|
|
|
|
getevent(&cfg_done_msg, AUDPREPROC_CMD_CFG_DONE_MSG_LEN);
|
|
MM_DBG("AUDPREPROC_CMD_CFG_DONE_MSG: stream id %d preproc \
|
|
type %x\n", cfg_done_msg.stream_id, \
|
|
cfg_done_msg.aud_preproc_type);
|
|
if ((cfg_done_msg.stream_id < MAX_ENC_COUNT) &&
|
|
audpreproc->func[cfg_done_msg.stream_id])
|
|
audpreproc->func[cfg_done_msg.stream_id](
|
|
audpreproc->private[cfg_done_msg.stream_id], id,
|
|
&cfg_done_msg);
|
|
break;
|
|
}
|
|
case AUDPREPROC_ERROR_MSG: {
|
|
struct audpreproc_err_msg err_msg;
|
|
|
|
getevent(&err_msg, AUDPREPROC_ERROR_MSG_LEN);
|
|
MM_DBG("AUDPREPROC_ERROR_MSG: stream id %d err idx %d\n",
|
|
err_msg.stream_id, err_msg.aud_preproc_err_idx);
|
|
if ((err_msg.stream_id < MAX_ENC_COUNT) &&
|
|
audpreproc->func[err_msg.stream_id])
|
|
audpreproc->func[err_msg.stream_id](
|
|
audpreproc->private[err_msg.stream_id], id,
|
|
&err_msg);
|
|
break;
|
|
}
|
|
case AUDPREPROC_CMD_ENC_CFG_DONE_MSG: {
|
|
struct audpreproc_cmd_enc_cfg_done_msg enc_cfg_msg;
|
|
|
|
getevent(&enc_cfg_msg, AUDPREPROC_CMD_ENC_CFG_DONE_MSG_LEN);
|
|
MM_DBG("AUDPREPROC_CMD_ENC_CFG_DONE_MSG: stream id %d enc type \
|
|
%d\n", enc_cfg_msg.stream_id, enc_cfg_msg.rec_enc_type);
|
|
if ((enc_cfg_msg.stream_id < MAX_ENC_COUNT) &&
|
|
audpreproc->func[enc_cfg_msg.stream_id])
|
|
audpreproc->func[enc_cfg_msg.stream_id](
|
|
audpreproc->private[enc_cfg_msg.stream_id], id,
|
|
&enc_cfg_msg);
|
|
for (n = 0; n < MAX_EVENT_CALLBACK_CLIENTS; ++n) {
|
|
if (audpreproc->cb_tbl[n] &&
|
|
audpreproc->cb_tbl[n]->fn) {
|
|
audpreproc->cb_tbl[n]->fn( \
|
|
audpreproc->cb_tbl[n]->private, \
|
|
id, (void *) &enc_cfg_msg);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case AUDPREPROC_CMD_ENC_PARAM_CFG_DONE_MSG: {
|
|
struct audpreproc_cmd_enc_param_cfg_done_msg enc_param_msg;
|
|
|
|
getevent(&enc_param_msg,
|
|
AUDPREPROC_CMD_ENC_PARAM_CFG_DONE_MSG_LEN);
|
|
MM_DBG("AUDPREPROC_CMD_ENC_PARAM_CFG_DONE_MSG: stream id %d\n",
|
|
enc_param_msg.stream_id);
|
|
if ((enc_param_msg.stream_id < MAX_ENC_COUNT) &&
|
|
audpreproc->func[enc_param_msg.stream_id])
|
|
audpreproc->func[enc_param_msg.stream_id](
|
|
audpreproc->private[enc_param_msg.stream_id], id,
|
|
&enc_param_msg);
|
|
break;
|
|
}
|
|
case AUDPREPROC_AFE_CMD_AUDIO_RECORD_CFG_DONE_MSG: {
|
|
struct audpreproc_afe_cmd_audio_record_cfg_done
|
|
record_cfg_done;
|
|
getevent(&record_cfg_done,
|
|
AUDPREPROC_AFE_CMD_AUDIO_RECORD_CFG_DONE_MSG_LEN);
|
|
MM_DBG("AUDPREPROC_AFE_CMD_AUDIO_RECORD_CFG_DONE_MSG: \
|
|
stream id %d\n", record_cfg_done.stream_id);
|
|
if ((record_cfg_done.stream_id < MAX_ENC_COUNT) &&
|
|
audpreproc->func[record_cfg_done.stream_id])
|
|
audpreproc->func[record_cfg_done.stream_id](
|
|
audpreproc->private[record_cfg_done.stream_id], id,
|
|
&record_cfg_done);
|
|
break;
|
|
}
|
|
case AUDPREPROC_CMD_ROUTING_MODE_DONE_MSG: {
|
|
struct audpreproc_cmd_routing_mode_done routing_mode_done;
|
|
|
|
getevent(&routing_mode_done,
|
|
AUDPREPROC_CMD_ROUTING_MODE_DONE_MSG_LEN);
|
|
MM_DBG("AUDPREPROC_CMD_ROUTING_MODE_DONE_MSG: \
|
|
stream id %d\n", routing_mode_done.stream_id);
|
|
if ((routing_mode_done.stream_id < MAX_ENC_COUNT) &&
|
|
audpreproc->func[routing_mode_done.stream_id])
|
|
audpreproc->func[routing_mode_done.stream_id](
|
|
audpreproc->private[routing_mode_done.stream_id], id,
|
|
&routing_mode_done);
|
|
break;
|
|
}
|
|
#ifdef CONFIG_DEBUG_FS
|
|
case AUDPREPROC_MSG_FEAT_QUERY_DM_DONE:
|
|
{
|
|
uint16_t msg[3];
|
|
getevent(msg, sizeof(msg));
|
|
MM_INFO("RTC ACK --> %x %x %x\n", msg[0], msg[1], msg[2]);
|
|
acdb_rtc_set_err(msg[2]);
|
|
}
|
|
break;
|
|
#endif
|
|
case ADSP_MESSAGE_ID: {
|
|
MM_DBG("Received ADSP event:module audpreproctask\n");
|
|
break;
|
|
}
|
|
default:
|
|
MM_ERR("Unknown Event %d\n", id);
|
|
}
|
|
return;
|
|
}
|
|
|
|
static struct msm_adsp_ops adsp_ops = {
|
|
.event = audpreproc_dsp_event,
|
|
};
|
|
|
|
/* EXPORTED API's */
|
|
int audpreproc_enable(int enc_id, audpreproc_event_func func, void *private)
|
|
{
|
|
struct audpreproc_state *audpreproc = &the_audpreproc_state;
|
|
int res = 0;
|
|
|
|
if (enc_id < 0 || enc_id > (MAX_ENC_COUNT - 1))
|
|
return -EINVAL;
|
|
|
|
mutex_lock(audpreproc->lock);
|
|
if (audpreproc->func[enc_id]) {
|
|
res = -EBUSY;
|
|
goto out;
|
|
}
|
|
|
|
audpreproc->func[enc_id] = func;
|
|
audpreproc->private[enc_id] = private;
|
|
|
|
/* First client to enable preproc task */
|
|
if (audpreproc->open_count++ == 0) {
|
|
MM_DBG("Get AUDPREPROCTASK\n");
|
|
res = msm_adsp_get("AUDPREPROCTASK", &audpreproc->mod,
|
|
&adsp_ops, audpreproc);
|
|
if (res < 0) {
|
|
MM_ERR("Can not get AUDPREPROCTASK\n");
|
|
audpreproc->open_count = 0;
|
|
audpreproc->func[enc_id] = NULL;
|
|
audpreproc->private[enc_id] = NULL;
|
|
goto out;
|
|
}
|
|
prevent_suspend();
|
|
if (msm_adsp_enable(audpreproc->mod)) {
|
|
MM_ERR("Can not enable AUDPREPROCTASK\n");
|
|
audpreproc->open_count = 0;
|
|
audpreproc->func[enc_id] = NULL;
|
|
audpreproc->private[enc_id] = NULL;
|
|
msm_adsp_put(audpreproc->mod);
|
|
audpreproc->mod = NULL;
|
|
res = -ENODEV;
|
|
allow_suspend();
|
|
goto out;
|
|
}
|
|
}
|
|
res = 0;
|
|
out:
|
|
mutex_unlock(audpreproc->lock);
|
|
return res;
|
|
}
|
|
EXPORT_SYMBOL(audpreproc_enable);
|
|
|
|
int audpreproc_update_audrec_info(
|
|
struct audrec_session_info *audrec_session_info)
|
|
{
|
|
if (!audrec_session_info) {
|
|
MM_ERR("error in audrec session info address\n");
|
|
return -EINVAL;
|
|
}
|
|
if (audrec_session_info->session_id < MAX_ENC_COUNT) {
|
|
memcpy(&session_info[audrec_session_info->session_id],
|
|
audrec_session_info,
|
|
sizeof(struct audrec_session_info));
|
|
return 0;
|
|
}
|
|
return -EINVAL;
|
|
}
|
|
EXPORT_SYMBOL(audpreproc_update_audrec_info);
|
|
|
|
void audpreproc_disable(int enc_id, void *private)
|
|
{
|
|
struct audpreproc_state *audpreproc = &the_audpreproc_state;
|
|
|
|
if (enc_id < 0 || enc_id > (MAX_ENC_COUNT - 1))
|
|
return;
|
|
|
|
mutex_lock(audpreproc->lock);
|
|
if (!audpreproc->func[enc_id])
|
|
goto out;
|
|
if (audpreproc->private[enc_id] != private)
|
|
goto out;
|
|
|
|
audpreproc->func[enc_id] = NULL;
|
|
audpreproc->private[enc_id] = NULL;
|
|
|
|
/* Last client then disable preproc task */
|
|
if (--audpreproc->open_count == 0) {
|
|
msm_adsp_disable(audpreproc->mod);
|
|
MM_DBG("Put AUDPREPROCTASK\n");
|
|
msm_adsp_put(audpreproc->mod);
|
|
audpreproc->mod = NULL;
|
|
allow_suspend();
|
|
}
|
|
out:
|
|
mutex_unlock(audpreproc->lock);
|
|
return;
|
|
}
|
|
EXPORT_SYMBOL(audpreproc_disable);
|
|
|
|
|
|
int audpreproc_register_event_callback(struct audpreproc_event_callback *ecb)
|
|
{
|
|
struct audpreproc_state *audpreproc = &the_audpreproc_state;
|
|
int i;
|
|
|
|
for (i = 0; i < MAX_EVENT_CALLBACK_CLIENTS; ++i) {
|
|
if (NULL == audpreproc->cb_tbl[i]) {
|
|
audpreproc->cb_tbl[i] = ecb;
|
|
return 0;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
EXPORT_SYMBOL(audpreproc_register_event_callback);
|
|
|
|
int audpreproc_unregister_event_callback(struct audpreproc_event_callback *ecb)
|
|
{
|
|
struct audpreproc_state *audpreproc = &the_audpreproc_state;
|
|
int i;
|
|
|
|
for (i = 0; i < MAX_EVENT_CALLBACK_CLIENTS; ++i) {
|
|
if (ecb == audpreproc->cb_tbl[i]) {
|
|
audpreproc->cb_tbl[i] = NULL;
|
|
return 0;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
EXPORT_SYMBOL(audpreproc_unregister_event_callback);
|
|
|
|
|
|
/* enc_type = supported encode format *
|
|
* like pcm, aac, sbc, evrc, qcelp, amrnb etc ... *
|
|
*/
|
|
int audpreproc_aenc_alloc(unsigned enc_type, const char **module_name,
|
|
unsigned *queue_ids)
|
|
{
|
|
struct audpreproc_state *audpreproc = &the_audpreproc_state;
|
|
int encid = -1, idx, lidx, mode, codec;
|
|
int codecs_supported, min_codecs_supported;
|
|
static int wakelock_init;
|
|
|
|
mutex_lock(audpreproc->lock);
|
|
/* Represents in bit mask */
|
|
mode = ((enc_type & AUDPREPROC_MODE_MASK) << 16);
|
|
codec = (1 << (enc_type & AUDPREPROC_CODEC_MASK));
|
|
|
|
lidx = msm_enc_database.num_enc;
|
|
min_codecs_supported = sizeof(unsigned int) * 8;
|
|
MM_DBG("mode = 0x%08x codec = 0x%08x\n", mode, codec);
|
|
|
|
for (idx = lidx-1; idx >= 0; idx--) {
|
|
/* encoder free and supports the format */
|
|
if (!(audpreproc->enc_inuse & (1 << (idx))) &&
|
|
((mode & msm_enc_database.enc_info_list[idx].enc_formats)
|
|
== mode) && ((codec &
|
|
msm_enc_database.enc_info_list[idx].enc_formats)
|
|
== codec)){
|
|
/* Check supports minimum number codecs */
|
|
codecs_supported =
|
|
msm_enc_database.enc_info_list[idx].nr_codec_support;
|
|
if (codecs_supported < min_codecs_supported) {
|
|
lidx = idx;
|
|
min_codecs_supported = codecs_supported;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (lidx < msm_enc_database.num_enc) {
|
|
audpreproc->enc_inuse |= (1 << lidx);
|
|
*module_name =
|
|
msm_enc_database.enc_info_list[lidx].module_name;
|
|
*queue_ids =
|
|
msm_enc_database.enc_info_list[lidx].module_queueids;
|
|
encid = msm_enc_database.enc_info_list[lidx].module_encid;
|
|
}
|
|
|
|
if (!wakelock_init) {
|
|
wake_lock_init(&audpre_wake_lock, WAKE_LOCK_SUSPEND, "audpre");
|
|
pm_qos_add_request(&audpre_pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
|
|
PM_QOS_DEFAULT_VALUE);
|
|
wakelock_init = 1;
|
|
}
|
|
|
|
mutex_unlock(audpreproc->lock);
|
|
return encid;
|
|
}
|
|
EXPORT_SYMBOL(audpreproc_aenc_alloc);
|
|
|
|
void audpreproc_aenc_free(int enc_id)
|
|
{
|
|
struct audpreproc_state *audpreproc = &the_audpreproc_state;
|
|
int idx;
|
|
|
|
mutex_lock(audpreproc->lock);
|
|
for (idx = 0; idx < msm_enc_database.num_enc; idx++) {
|
|
if (msm_enc_database.enc_info_list[idx].module_encid ==
|
|
enc_id) {
|
|
audpreproc->enc_inuse &= ~(1 << idx);
|
|
break;
|
|
}
|
|
}
|
|
mutex_unlock(audpreproc->lock);
|
|
return;
|
|
|
|
}
|
|
EXPORT_SYMBOL(audpreproc_aenc_free);
|
|
|
|
int audpreproc_send_preproccmdqueue(void *cmd, unsigned len)
|
|
{
|
|
return msm_adsp_write(the_audpreproc_state.mod,
|
|
QDSP_uPAudPreProcCmdQueue, cmd, len);
|
|
}
|
|
EXPORT_SYMBOL(audpreproc_send_preproccmdqueue);
|
|
|
|
int audpreproc_send_audreccmdqueue(void *cmd, unsigned len)
|
|
{
|
|
return msm_adsp_write(the_audpreproc_state.mod,
|
|
QDSP_uPAudPreProcAudRecCmdQueue, cmd, len);
|
|
}
|
|
EXPORT_SYMBOL(audpreproc_send_audreccmdqueue);
|
|
|
|
int audpreproc_send_audrec2cmdqueue(void *cmd, unsigned len)
|
|
{
|
|
return msm_adsp_write(the_audpreproc_state.mod,
|
|
QDSP_uPAudRec2CmdQueue, cmd, len);
|
|
}
|
|
EXPORT_SYMBOL(audpreproc_send_audrec2cmdqueue);
|
|
|
|
int audpreproc_dsp_set_agc(struct audpreproc_cmd_cfg_agc_params *agc,
|
|
unsigned len)
|
|
{
|
|
return msm_adsp_write(the_audpreproc_state.mod,
|
|
QDSP_uPAudPreProcCmdQueue, agc, len);
|
|
}
|
|
EXPORT_SYMBOL(audpreproc_dsp_set_agc);
|
|
|
|
int audpreproc_dsp_set_agc2(struct audpreproc_cmd_cfg_agc_params_2 *agc2,
|
|
unsigned len)
|
|
{
|
|
return msm_adsp_write(the_audpreproc_state.mod,
|
|
QDSP_uPAudPreProcCmdQueue, agc2, len);
|
|
}
|
|
EXPORT_SYMBOL(audpreproc_dsp_set_agc2);
|
|
|
|
int audpreproc_dsp_set_ns(struct audpreproc_cmd_cfg_ns_params *ns,
|
|
unsigned len)
|
|
{
|
|
return msm_adsp_write(the_audpreproc_state.mod,
|
|
QDSP_uPAudPreProcCmdQueue, ns, len);
|
|
}
|
|
EXPORT_SYMBOL(audpreproc_dsp_set_ns);
|
|
|
|
int audpreproc_dsp_set_iir(
|
|
struct audpreproc_cmd_cfg_iir_tuning_filter_params *iir, unsigned len)
|
|
{
|
|
return msm_adsp_write(the_audpreproc_state.mod,
|
|
QDSP_uPAudPreProcCmdQueue, iir, len);
|
|
}
|
|
EXPORT_SYMBOL(audpreproc_dsp_set_iir);
|
|
|
|
int audpreproc_dsp_set_gain_tx(
|
|
struct audpreproc_cmd_cfg_cal_gain *calib_gain_tx, unsigned len)
|
|
{
|
|
return msm_adsp_write(the_audpreproc_state.mod,
|
|
QDSP_uPAudPreProcCmdQueue, calib_gain_tx, len);
|
|
}
|
|
EXPORT_SYMBOL(audpreproc_dsp_set_gain_tx);
|
|
|
|
void get_audrec_session_info(int id, struct audrec_session_info *info)
|
|
{
|
|
if (id >= MAX_ENC_COUNT) {
|
|
MM_ERR("invalid session id = %d\n", id);
|
|
return;
|
|
}
|
|
memcpy(info, &session_info[id], sizeof(struct audrec_session_info));
|
|
}
|
|
EXPORT_SYMBOL(get_audrec_session_info);
|
|
|
|
int audpreproc_dsp_set_lvnv(
|
|
struct audpreproc_cmd_cfg_lvnv_param *preproc_lvnv, unsigned len)
|
|
{
|
|
return msm_adsp_write(the_audpreproc_state.mod,
|
|
QDSP_uPAudPreProcCmdQueue, preproc_lvnv, len);
|
|
}
|
|
EXPORT_SYMBOL(audpreproc_dsp_set_lvnv);
|
|
|