Initial Contribution
msm-2.6.38: tag AU_LINUX_ANDROID_GINGERBREAD.02.03.04.00.142
Signed-off-by: Bryan Huntsman <bryanh@codeaurora.org>
diff --git a/arch/arm/mach-msm/qdsp5/audrec.c b/arch/arm/mach-msm/qdsp5/audrec.c
new file mode 100644
index 0000000..d5cb168
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audrec.c
@@ -0,0 +1,272 @@
+/* arch/arm/mach-msm/qdsp5/audrec.c
+ *
+ * common code to deal with the AUDREC dsp task (audio recording)
+ *
+ * Copyright (c) 2009, Code Aurora Forum. 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 "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);
+