blob: d5cb168b98ed30ec4668f1a0f41b72f31fae51c1 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* arch/arm/mach-msm/qdsp5/audrec.c
2 *
3 * common code to deal with the AUDREC dsp task (audio recording)
4 *
5 * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
6 *
7 * Based on the audpp layer in arch/arm/mach-msm/qdsp5/audpp.c
8 *
9 * Copyright (C) 2008 Google, Inc.
10 * Copyright (C) 2008 HTC Corporation
11 *
12 * This software is licensed under the terms of the GNU General Public
13 * License version 2, as published by the Free Software Foundation, and
14 * may be copied, distributed, and modified under those terms.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 *
20 * See the GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, you can find it at http://www.fsf.org.
23 *
24 */
25
26#include <linux/kernel.h>
27#include <linux/module.h>
28#include <linux/wait.h>
29#include <linux/delay.h>
30
31#include <asm/atomic.h>
32#include <asm/ioctls.h>
33#include <mach/msm_adsp.h>
34
35#include <mach/qdsp5/qdsp5audreccmdi.h>
36#include <mach/qdsp5/qdsp5audrecmsg.h>
37
38#include "audmgr.h"
39#include <mach/debug_mm.h>
40
41static DEFINE_MUTEX(audrec_lock);
42
43#define MAX_ENC_COUNT 8 /* Max encoder supported */
44
45#define ENC_SESSION_FREE 0
46#define ENC_SESSION_ACTIVE 1
47
48struct enc_session {
49 unsigned enc_type; /* Param to identify type of encoder */
50 unsigned audrec_obj_idx; /* Param to identify REC_OBJ or Session ID */
51 audrec_event_func event_func; /* Event Call back
52 routine for the encoder */
53 void *private; /* private data element passed as
54 part of Event Call back routine */
55 unsigned state; /* Current state of the encoder session ,
56 free, active*/
57};
58
59struct audrec_state {
60 struct msm_adsp_module *audrec_mod;
61 struct enc_session enc_session[MAX_ENC_COUNT];
62 struct mutex *lock;
63 unsigned enc_count;
64};
65
66struct audrec_state the_audrec_state = {
67 .lock = &audrec_lock,
68};
69
70int audrectask_send_cmdqueue(void *cmd, unsigned len)
71{
72 return msm_adsp_write(the_audrec_state.audrec_mod,
73 QDSP_uPAudRecCmdQueue, cmd, len);
74}
75EXPORT_SYMBOL(audrectask_send_cmdqueue);
76
77int audrectask_send_bitstreamqueue(void *cmd, unsigned len)
78{
79 return msm_adsp_write(the_audrec_state.audrec_mod,
80 QDSP_uPAudRecBitStreamQueue, cmd, len);
81}
82EXPORT_SYMBOL(audrectask_send_bitstreamqueue);
83
84static void audrectask_dsp_event(void *data, unsigned id, size_t len,
85 void (*getevent)(void *ptr, size_t len))
86{
87 struct audrec_state *audrec = data;
88 int cnt;
89 uint16_t msg[5]; /* Max size of message */
90 getevent(msg, len);
91
92 switch (id) {
93 case AUDREC_MSG_CMD_CFG_DONE_MSG: {
94 MM_DBG("CMD CFG DONE %x\n", msg[1]);
95 if (msg[0] & AUDREC_MSG_CFG_DONE_ENC_ENA) {
96 for (cnt = 0; cnt < MAX_ENC_COUNT ; cnt++) {
97 if (audrec->enc_session[cnt].enc_type ==
98 (msg[0] & AUDREC_CMD_ENC_TYPE_MASK)) {
99 audrec->enc_session[cnt].audrec_obj_idx
100 = msg[1];
101 audrec->enc_session[cnt].event_func(
102 audrec->enc_session[cnt].private, id,
103 msg);
104 break;
105 }
106 }
107 } else {
108 for (cnt = 0; cnt < MAX_ENC_COUNT ; cnt++) {
109 if (audrec->enc_session[cnt].enc_type ==
110 (msg[0] & AUDREC_CMD_ENC_TYPE_MASK)) {
111 audrec->enc_session[cnt].event_func(
112 audrec->enc_session[cnt].private, id,
113 msg);
114 audrec->enc_session[cnt].audrec_obj_idx
115 = 0xFFFFFFFF;
116 audrec->enc_session[cnt].state
117 = ENC_SESSION_FREE;
118 audrec->enc_session[cnt].enc_type
119 = 0xFFFFFFFF;
120 audrec->enc_session[cnt].event_func
121 = NULL;
122 audrec->enc_session[cnt].private
123 = NULL;
124 break;
125 }
126 }
127 }
128 break;
129 }
130 case AUDREC_MSG_CMD_AREC_MEM_CFG_DONE_MSG: {
131 MM_DBG("CMD AREC MEM CFG DONE %x\n", msg[0]);
132 for (cnt = 0; cnt < MAX_ENC_COUNT ; cnt++) {
133 if (audrec->enc_session[cnt].audrec_obj_idx ==
134 msg[0]) {
135 audrec->enc_session[cnt].event_func(
136 audrec->enc_session[cnt].private, id, msg);
137 break;
138 }
139 }
140 break;
141 }
142 case AUDREC_MSG_CMD_AREC_PARAM_CFG_DONE_MSG: {
143 MM_DBG("CMD AREC PARAM CFG DONE %x\n", msg[0]);
144 for (cnt = 0; cnt < MAX_ENC_COUNT ; cnt++) {
145 if (audrec->enc_session[cnt].audrec_obj_idx ==
146 msg[0]) {
147 audrec->enc_session[cnt].event_func(
148 audrec->enc_session[cnt].private, id, msg);
149 break;
150 }
151 }
152 break;
153 }
154 case AUDREC_MSG_PACKET_READY_MSG: {
155 MM_DBG("PCK READY %x\n", msg[0]);
156 for (cnt = 0; cnt < MAX_ENC_COUNT ; cnt++) {
157 if (audrec->enc_session[cnt].audrec_obj_idx ==
158 msg[0]) {
159 audrec->enc_session[cnt].event_func(
160 audrec->enc_session[cnt].private, id, msg);
161 break;
162 }
163 }
164 break;
165 }
166 case AUDREC_MSG_FATAL_ERR_MSG: {
167 MM_ERR("ERROR %x\n", msg[0]);
168 if (msg[1] & AUDREC_MSG_FATAL_ERR_TYPE_0) {
169 for (cnt = 0; cnt < MAX_ENC_COUNT ; cnt++) {
170 if (audrec->enc_session[cnt].audrec_obj_idx ==
171 msg[0]) {
172 audrec->enc_session[cnt].event_func(
173 audrec->enc_session[cnt].private, id,
174 msg);
175 break;
176 }
177 }
178 } else if (msg[1] & AUDREC_MSG_FATAL_ERR_TYPE_1) {
179 cnt = audrec->enc_count-1;
180 if (audrec->enc_session[cnt].event_func)
181 audrec->enc_session[cnt].event_func(
182 audrec->enc_session[cnt].private, id,
183 msg);
184 }
185 break;
186 }
187 case ADSP_MESSAGE_ID:
188 MM_DBG("Received ADSP event: module \
189 enable/disable(audrectask)\n");
190 break;
191 default:
192 MM_ERR("unknown event %d\n", id);
193 }
194}
195
196static struct msm_adsp_ops adsp_ops = {
197 .event = audrectask_dsp_event,
198};
199
200int audrectask_enable(unsigned enc_type, audrec_event_func func, void *private)
201{
202 struct audrec_state *audrec = &the_audrec_state;
203 int cnt, rc = 0;
204
205 mutex_lock(audrec->lock);
206
207 if (audrec->enc_count++ == 0) {
208 MM_DBG("enable\n");
209 for (cnt = 0; cnt < MAX_ENC_COUNT ; cnt++) {
210 if (audrec->enc_session[cnt].state ==
211 ENC_SESSION_FREE) {
212 audrec->enc_session[cnt].state =
213 ENC_SESSION_ACTIVE;
214 audrec->enc_session[cnt].enc_type = enc_type;
215 audrec->enc_session[cnt].event_func = func;
216 audrec->enc_session[cnt].private = private;
217 break;
218 }
219 }
220 rc = msm_adsp_get("AUDRECTASK", &audrec->audrec_mod, &adsp_ops,
221 audrec);
222 if (rc < 0) {
223 MM_ERR("cannot open AUDRECTASK\n");
224 audrec->enc_count = 0;
225 audrec->enc_session[cnt].state = ENC_SESSION_FREE;
226 audrec->enc_session[cnt].enc_type = 0xFFFFFFFF;
227 audrec->enc_session[cnt].event_func = NULL;
228 audrec->enc_session[cnt].private = NULL;
229 goto out;
230 }
231 msm_adsp_enable(audrec->audrec_mod);
232 } else {
233 for (cnt = 0; cnt < MAX_ENC_COUNT ; cnt++) {
234 if (audrec->enc_session[cnt].state ==
235 ENC_SESSION_FREE) {
236 audrec->enc_session[cnt].state =
237 ENC_SESSION_ACTIVE;
238 audrec->enc_session[cnt].enc_type = enc_type;
239 audrec->enc_session[cnt].event_func = func;
240 audrec->enc_session[cnt].private = private;
241 break;
242 }
243 }
244 }
245 if (cnt == MAX_ENC_COUNT)
246 rc = -EBUSY;
247 else
248 rc = 0;
249
250out:
251 mutex_unlock(audrec->lock);
252 return rc;
253}
254EXPORT_SYMBOL(audrectask_enable);
255
256void audrectask_disable(unsigned enc_type, void *private)
257{
258 struct audrec_state *audrec = &the_audrec_state;
259
260 mutex_lock(audrec->lock);
261
262 if (--audrec->enc_count == 0) {
263 MM_DBG("\n"); /* Macro prints the file name and function */
264 msm_adsp_disable(audrec->audrec_mod);
265 msm_adsp_put(audrec->audrec_mod);
266 audrec->audrec_mod = NULL;
267 }
268
269 mutex_unlock(audrec->lock);
270}
271EXPORT_SYMBOL(audrectask_disable);
272