274 lines
7.2 KiB
C
274 lines
7.2 KiB
C
|
/* arch/arm/mach-msm/qdsp5/audrec.c
|
||
|
*
|
||
|
* common code to deal with the AUDREC dsp task (audio recording)
|
||
|
*
|
||
|
* Copyright (c) 2009,2012 The Linux Foundation. All rights reserved.
|
||
|
*
|
||
|
* Based on the audpp layer in arch/arm/mach-msm/qdsp5/audpp.c
|
||
|
*
|
||
|
* Copyright (C) 2008 Google, Inc.
|
||
|
* Copyright (C) 2008 HTC Corporation
|
||
|
*
|
||
|
* 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.
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with this program; if not, you can find it at http://www.fsf.org.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#include <linux/kernel.h>
|
||
|
#include <linux/module.h>
|
||
|
#include <linux/wait.h>
|
||
|
#include <linux/delay.h>
|
||
|
|
||
|
#include <asm/atomic.h>
|
||
|
#include <asm/ioctls.h>
|
||
|
#include <mach/msm_adsp.h>
|
||
|
|
||
|
#include <mach/qdsp5/qdsp5audreccmdi.h>
|
||
|
#include <mach/qdsp5/qdsp5audrecmsg.h>
|
||
|
#include <mach/qdsp5/qdsp5audpreproc.h>
|
||
|
|
||
|
#include "audmgr.h"
|
||
|
#include <mach/debug_mm.h>
|
||
|
|
||
|
static DEFINE_MUTEX(audrec_lock);
|
||
|
|
||
|
#define MAX_ENC_COUNT 8 /* Max encoder supported */
|
||
|
|
||
|
#define ENC_SESSION_FREE 0
|
||
|
#define ENC_SESSION_ACTIVE 1
|
||
|
|
||
|
struct enc_session {
|
||
|
unsigned enc_type; /* Param to identify type of encoder */
|
||
|
unsigned audrec_obj_idx; /* Param to identify REC_OBJ or Session ID */
|
||
|
audrec_event_func event_func; /* Event Call back
|
||
|
routine for the encoder */
|
||
|
void *private; /* private data element passed as
|
||
|
part of Event Call back routine */
|
||
|
unsigned state; /* Current state of the encoder session ,
|
||
|
free, active*/
|
||
|
};
|
||
|
|
||
|
struct audrec_state {
|
||
|
struct msm_adsp_module *audrec_mod;
|
||
|
struct enc_session enc_session[MAX_ENC_COUNT];
|
||
|
struct mutex *lock;
|
||
|
unsigned enc_count;
|
||
|
};
|
||
|
|
||
|
struct audrec_state the_audrec_state = {
|
||
|
.lock = &audrec_lock,
|
||
|
};
|
||
|
|
||
|
int audrectask_send_cmdqueue(void *cmd, unsigned len)
|
||
|
{
|
||
|
return msm_adsp_write(the_audrec_state.audrec_mod,
|
||
|
QDSP_uPAudRecCmdQueue, cmd, len);
|
||
|
}
|
||
|
EXPORT_SYMBOL(audrectask_send_cmdqueue);
|
||
|
|
||
|
int audrectask_send_bitstreamqueue(void *cmd, unsigned len)
|
||
|
{
|
||
|
return msm_adsp_write(the_audrec_state.audrec_mod,
|
||
|
QDSP_uPAudRecBitStreamQueue, cmd, len);
|
||
|
}
|
||
|
EXPORT_SYMBOL(audrectask_send_bitstreamqueue);
|
||
|
|
||
|
static void audrectask_dsp_event(void *data, unsigned id, size_t len,
|
||
|
void (*getevent)(void *ptr, size_t len))
|
||
|
{
|
||
|
struct audrec_state *audrec = data;
|
||
|
int cnt;
|
||
|
uint16_t msg[5]; /* Max size of message */
|
||
|
getevent(msg, len);
|
||
|
|
||
|
switch (id) {
|
||
|
case AUDREC_MSG_CMD_CFG_DONE_MSG: {
|
||
|
MM_DBG("CMD CFG DONE %x\n", msg[1]);
|
||
|
if (msg[0] & AUDREC_MSG_CFG_DONE_ENC_ENA) {
|
||
|
for (cnt = 0; cnt < MAX_ENC_COUNT ; cnt++) {
|
||
|
if (audrec->enc_session[cnt].enc_type ==
|
||
|
(msg[0] & AUDREC_CMD_ENC_TYPE_MASK)) {
|
||
|
audrec->enc_session[cnt].audrec_obj_idx
|
||
|
= msg[1];
|
||
|
audrec->enc_session[cnt].event_func(
|
||
|
audrec->enc_session[cnt].private, id,
|
||
|
msg);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
for (cnt = 0; cnt < MAX_ENC_COUNT ; cnt++) {
|
||
|
if (audrec->enc_session[cnt].enc_type ==
|
||
|
(msg[0] & AUDREC_CMD_ENC_TYPE_MASK)) {
|
||
|
audrec->enc_session[cnt].event_func(
|
||
|
audrec->enc_session[cnt].private, id,
|
||
|
msg);
|
||
|
audrec->enc_session[cnt].audrec_obj_idx
|
||
|
= 0xFFFFFFFF;
|
||
|
audrec->enc_session[cnt].state
|
||
|
= ENC_SESSION_FREE;
|
||
|
audrec->enc_session[cnt].enc_type
|
||
|
= 0xFFFFFFFF;
|
||
|
audrec->enc_session[cnt].event_func
|
||
|
= NULL;
|
||
|
audrec->enc_session[cnt].private
|
||
|
= NULL;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case AUDREC_MSG_CMD_AREC_MEM_CFG_DONE_MSG: {
|
||
|
MM_DBG("CMD AREC MEM CFG DONE %x\n", msg[0]);
|
||
|
for (cnt = 0; cnt < MAX_ENC_COUNT ; cnt++) {
|
||
|
if (audrec->enc_session[cnt].audrec_obj_idx ==
|
||
|
msg[0]) {
|
||
|
audrec->enc_session[cnt].event_func(
|
||
|
audrec->enc_session[cnt].private, id, msg);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case AUDREC_MSG_CMD_AREC_PARAM_CFG_DONE_MSG: {
|
||
|
MM_DBG("CMD AREC PARAM CFG DONE %x\n", msg[0]);
|
||
|
for (cnt = 0; cnt < MAX_ENC_COUNT ; cnt++) {
|
||
|
if (audrec->enc_session[cnt].audrec_obj_idx ==
|
||
|
msg[0]) {
|
||
|
audrec->enc_session[cnt].event_func(
|
||
|
audrec->enc_session[cnt].private, id, msg);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case AUDREC_MSG_PACKET_READY_MSG: {
|
||
|
MM_DBG("PCK READY %x\n", msg[0]);
|
||
|
for (cnt = 0; cnt < MAX_ENC_COUNT ; cnt++) {
|
||
|
if (audrec->enc_session[cnt].audrec_obj_idx ==
|
||
|
msg[0]) {
|
||
|
audrec->enc_session[cnt].event_func(
|
||
|
audrec->enc_session[cnt].private, id, msg);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case AUDREC_MSG_FATAL_ERR_MSG: {
|
||
|
MM_ERR("ERROR %x\n", msg[0]);
|
||
|
if (msg[1] & AUDREC_MSG_FATAL_ERR_TYPE_0) {
|
||
|
for (cnt = 0; cnt < MAX_ENC_COUNT ; cnt++) {
|
||
|
if (audrec->enc_session[cnt].audrec_obj_idx ==
|
||
|
msg[0]) {
|
||
|
audrec->enc_session[cnt].event_func(
|
||
|
audrec->enc_session[cnt].private, id,
|
||
|
msg);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
} else if (msg[1] & AUDREC_MSG_FATAL_ERR_TYPE_1) {
|
||
|
cnt = audrec->enc_count-1;
|
||
|
if (audrec->enc_session[cnt].event_func)
|
||
|
audrec->enc_session[cnt].event_func(
|
||
|
audrec->enc_session[cnt].private, id,
|
||
|
msg);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case ADSP_MESSAGE_ID:
|
||
|
MM_DBG("Received ADSP event: module \
|
||
|
enable/disable(audrectask)\n");
|
||
|
break;
|
||
|
default:
|
||
|
MM_ERR("unknown event %d\n", id);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static struct msm_adsp_ops adsp_ops = {
|
||
|
.event = audrectask_dsp_event,
|
||
|
};
|
||
|
|
||
|
int audrectask_enable(unsigned enc_type, audrec_event_func func, void *private)
|
||
|
{
|
||
|
struct audrec_state *audrec = &the_audrec_state;
|
||
|
int cnt, rc = 0;
|
||
|
|
||
|
mutex_lock(audrec->lock);
|
||
|
|
||
|
if (audrec->enc_count++ == 0) {
|
||
|
MM_DBG("enable\n");
|
||
|
for (cnt = 0; cnt < MAX_ENC_COUNT ; cnt++) {
|
||
|
if (audrec->enc_session[cnt].state ==
|
||
|
ENC_SESSION_FREE) {
|
||
|
audrec->enc_session[cnt].state =
|
||
|
ENC_SESSION_ACTIVE;
|
||
|
audrec->enc_session[cnt].enc_type = enc_type;
|
||
|
audrec->enc_session[cnt].event_func = func;
|
||
|
audrec->enc_session[cnt].private = private;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
rc = msm_adsp_get("AUDRECTASK", &audrec->audrec_mod, &adsp_ops,
|
||
|
audrec);
|
||
|
if (rc < 0) {
|
||
|
MM_ERR("cannot open AUDRECTASK\n");
|
||
|
audrec->enc_count = 0;
|
||
|
audrec->enc_session[cnt].state = ENC_SESSION_FREE;
|
||
|
audrec->enc_session[cnt].enc_type = 0xFFFFFFFF;
|
||
|
audrec->enc_session[cnt].event_func = NULL;
|
||
|
audrec->enc_session[cnt].private = NULL;
|
||
|
goto out;
|
||
|
}
|
||
|
msm_adsp_enable(audrec->audrec_mod);
|
||
|
} else {
|
||
|
for (cnt = 0; cnt < MAX_ENC_COUNT ; cnt++) {
|
||
|
if (audrec->enc_session[cnt].state ==
|
||
|
ENC_SESSION_FREE) {
|
||
|
audrec->enc_session[cnt].state =
|
||
|
ENC_SESSION_ACTIVE;
|
||
|
audrec->enc_session[cnt].enc_type = enc_type;
|
||
|
audrec->enc_session[cnt].event_func = func;
|
||
|
audrec->enc_session[cnt].private = private;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (cnt == MAX_ENC_COUNT)
|
||
|
rc = -EBUSY;
|
||
|
else
|
||
|
rc = 0;
|
||
|
|
||
|
out:
|
||
|
mutex_unlock(audrec->lock);
|
||
|
return rc;
|
||
|
}
|
||
|
EXPORT_SYMBOL(audrectask_enable);
|
||
|
|
||
|
void audrectask_disable(unsigned enc_type, void *private)
|
||
|
{
|
||
|
struct audrec_state *audrec = &the_audrec_state;
|
||
|
|
||
|
mutex_lock(audrec->lock);
|
||
|
|
||
|
if (--audrec->enc_count == 0) {
|
||
|
MM_DBG("\n"); /* Macro prints the file name and function */
|
||
|
msm_adsp_disable(audrec->audrec_mod);
|
||
|
msm_adsp_put(audrec->audrec_mod);
|
||
|
audrec->audrec_mod = NULL;
|
||
|
}
|
||
|
|
||
|
mutex_unlock(audrec->lock);
|
||
|
}
|
||
|
EXPORT_SYMBOL(audrectask_disable);
|
||
|
|