Commit | Line | Data |
---|---|---|
caff4cae IM |
1 | /* arch/arm/mach-msm/qdsp5/audio_in.c |
2 | * | |
3 | * pcm audio input device | |
4 | * | |
5 | * Copyright (C) 2008 Google, Inc. | |
6 | * Copyright (C) 2008 HTC Corporation | |
7 | * | |
8 | * This software is licensed under the terms of the GNU General Public | |
9 | * License version 2, as published by the Free Software Foundation, and | |
10 | * may be copied, distributed, and modified under those terms. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | * GNU General Public License for more details. | |
16 | * | |
17 | */ | |
18 | ||
19 | #include <linux/module.h> | |
20 | #include <linux/fs.h> | |
21 | #include <linux/miscdevice.h> | |
22 | #include <linux/uaccess.h> | |
23 | #include <linux/kthread.h> | |
24 | #include <linux/wait.h> | |
25 | #include <linux/dma-mapping.h> | |
26 | ||
27 | #include <linux/delay.h> | |
28 | ||
29 | #include <linux/msm_audio.h> | |
30 | ||
31 | #include <asm/atomic.h> | |
32 | #include <asm/ioctls.h> | |
33 | #include <mach/msm_adsp.h> | |
34 | #include <mach/msm_rpcrouter.h> | |
35 | ||
36 | #include "audmgr.h" | |
37 | ||
38 | #include <mach/qdsp5/qdsp5audpreproccmdi.h> | |
39 | #include <mach/qdsp5/qdsp5audpreprocmsg.h> | |
40 | #include <mach/qdsp5/qdsp5audreccmdi.h> | |
41 | #include <mach/qdsp5/qdsp5audrecmsg.h> | |
42 | ||
43 | /* for queue ids - should be relative to module number*/ | |
44 | #include "adsp.h" | |
45 | ||
46 | /* FRAME_NUM must be a power of two */ | |
47 | #define FRAME_NUM (8) | |
48 | #define FRAME_SIZE (2052 * 2) | |
49 | #define MONO_DATA_SIZE (2048) | |
50 | #define STEREO_DATA_SIZE (MONO_DATA_SIZE * 2) | |
51 | #define DMASZ (FRAME_SIZE * FRAME_NUM) | |
52 | ||
53 | #define AGC_PARAM_SIZE (20) | |
54 | #define NS_PARAM_SIZE (6) | |
55 | #define IIR_PARAM_SIZE (48) | |
56 | #define DEBUG (0) | |
57 | ||
58 | #define AGC_ENABLE 0x0001 | |
59 | #define NS_ENABLE 0x0002 | |
60 | #define IIR_ENABLE 0x0004 | |
61 | ||
62 | struct tx_agc_config { | |
63 | uint16_t agc_params[AGC_PARAM_SIZE]; | |
64 | }; | |
65 | ||
66 | struct ns_config { | |
67 | uint16_t ns_params[NS_PARAM_SIZE]; | |
68 | }; | |
69 | ||
70 | struct tx_iir_filter { | |
71 | uint16_t num_bands; | |
72 | uint16_t iir_params[IIR_PARAM_SIZE]; | |
73 | }; | |
74 | ||
75 | struct audpre_cmd_iir_config_type { | |
76 | uint16_t cmd_id; | |
77 | uint16_t active_flag; | |
78 | uint16_t num_bands; | |
79 | uint16_t iir_params[IIR_PARAM_SIZE]; | |
80 | }; | |
81 | ||
82 | struct buffer { | |
83 | void *data; | |
84 | uint32_t size; | |
85 | uint32_t read; | |
86 | uint32_t addr; | |
87 | }; | |
88 | ||
89 | struct audio_in { | |
90 | struct buffer in[FRAME_NUM]; | |
91 | ||
92 | spinlock_t dsp_lock; | |
93 | ||
94 | atomic_t in_bytes; | |
95 | ||
96 | struct mutex lock; | |
97 | struct mutex read_lock; | |
98 | wait_queue_head_t wait; | |
99 | ||
100 | struct msm_adsp_module *audpre; | |
101 | struct msm_adsp_module *audrec; | |
102 | ||
103 | /* configuration to use on next enable */ | |
104 | uint32_t samp_rate; | |
105 | uint32_t channel_mode; | |
106 | uint32_t buffer_size; /* 2048 for mono, 4096 for stereo */ | |
107 | uint32_t type; /* 0 for PCM ,1 for AAC */ | |
108 | uint32_t dsp_cnt; | |
109 | uint32_t in_head; /* next buffer dsp will write */ | |
110 | uint32_t in_tail; /* next buffer read() will read */ | |
111 | uint32_t in_count; /* number of buffers available to read() */ | |
112 | ||
113 | unsigned short samp_rate_index; | |
114 | ||
115 | struct audmgr audmgr; | |
116 | ||
117 | /* data allocated for various buffers */ | |
118 | char *data; | |
119 | dma_addr_t phys; | |
120 | ||
121 | int opened; | |
122 | int enabled; | |
123 | int running; | |
124 | int stopped; /* set when stopped, cleared on flush */ | |
125 | ||
126 | /* audpre settings */ | |
127 | int agc_enable; | |
128 | struct tx_agc_config agc; | |
129 | ||
130 | int ns_enable; | |
131 | struct ns_config ns; | |
132 | ||
133 | int iir_enable; | |
134 | struct tx_iir_filter iir; | |
135 | }; | |
136 | ||
137 | static int audio_in_dsp_enable(struct audio_in *audio, int enable); | |
138 | static int audio_in_encoder_config(struct audio_in *audio); | |
139 | static int audio_dsp_read_buffer(struct audio_in *audio, uint32_t read_cnt); | |
140 | static void audio_flush(struct audio_in *audio); | |
141 | static int audio_dsp_set_agc(struct audio_in *audio); | |
142 | static int audio_dsp_set_ns(struct audio_in *audio); | |
143 | static int audio_dsp_set_tx_iir(struct audio_in *audio); | |
144 | ||
145 | static unsigned convert_dsp_samp_index(unsigned index) | |
146 | { | |
147 | switch (index) { | |
148 | case 48000: return AUDREC_CMD_SAMP_RATE_INDX_48000; | |
149 | case 44100: return AUDREC_CMD_SAMP_RATE_INDX_44100; | |
150 | case 32000: return AUDREC_CMD_SAMP_RATE_INDX_32000; | |
151 | case 24000: return AUDREC_CMD_SAMP_RATE_INDX_24000; | |
152 | case 22050: return AUDREC_CMD_SAMP_RATE_INDX_22050; | |
153 | case 16000: return AUDREC_CMD_SAMP_RATE_INDX_16000; | |
154 | case 12000: return AUDREC_CMD_SAMP_RATE_INDX_12000; | |
155 | case 11025: return AUDREC_CMD_SAMP_RATE_INDX_11025; | |
156 | case 8000: return AUDREC_CMD_SAMP_RATE_INDX_8000; | |
157 | default: return AUDREC_CMD_SAMP_RATE_INDX_11025; | |
158 | } | |
159 | } | |
160 | ||
161 | static unsigned convert_samp_rate(unsigned hz) | |
162 | { | |
163 | switch (hz) { | |
164 | case 48000: return RPC_AUD_DEF_SAMPLE_RATE_48000; | |
165 | case 44100: return RPC_AUD_DEF_SAMPLE_RATE_44100; | |
166 | case 32000: return RPC_AUD_DEF_SAMPLE_RATE_32000; | |
167 | case 24000: return RPC_AUD_DEF_SAMPLE_RATE_24000; | |
168 | case 22050: return RPC_AUD_DEF_SAMPLE_RATE_22050; | |
169 | case 16000: return RPC_AUD_DEF_SAMPLE_RATE_16000; | |
170 | case 12000: return RPC_AUD_DEF_SAMPLE_RATE_12000; | |
171 | case 11025: return RPC_AUD_DEF_SAMPLE_RATE_11025; | |
172 | case 8000: return RPC_AUD_DEF_SAMPLE_RATE_8000; | |
173 | default: return RPC_AUD_DEF_SAMPLE_RATE_11025; | |
174 | } | |
175 | } | |
176 | ||
177 | static unsigned convert_samp_index(unsigned index) | |
178 | { | |
179 | switch (index) { | |
180 | case RPC_AUD_DEF_SAMPLE_RATE_48000: return 48000; | |
181 | case RPC_AUD_DEF_SAMPLE_RATE_44100: return 44100; | |
182 | case RPC_AUD_DEF_SAMPLE_RATE_32000: return 32000; | |
183 | case RPC_AUD_DEF_SAMPLE_RATE_24000: return 24000; | |
184 | case RPC_AUD_DEF_SAMPLE_RATE_22050: return 22050; | |
185 | case RPC_AUD_DEF_SAMPLE_RATE_16000: return 16000; | |
186 | case RPC_AUD_DEF_SAMPLE_RATE_12000: return 12000; | |
187 | case RPC_AUD_DEF_SAMPLE_RATE_11025: return 11025; | |
188 | case RPC_AUD_DEF_SAMPLE_RATE_8000: return 8000; | |
189 | default: return 11025; | |
190 | } | |
191 | } | |
192 | ||
193 | /* must be called with audio->lock held */ | |
194 | static int audio_in_enable(struct audio_in *audio) | |
195 | { | |
196 | struct audmgr_config cfg; | |
197 | int rc; | |
198 | ||
199 | if (audio->enabled) | |
200 | return 0; | |
201 | ||
202 | cfg.tx_rate = audio->samp_rate; | |
203 | cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE; | |
204 | cfg.def_method = RPC_AUD_DEF_METHOD_RECORD; | |
205 | if (audio->type == AUDREC_CMD_TYPE_0_INDEX_WAV) | |
206 | cfg.codec = RPC_AUD_DEF_CODEC_PCM; | |
207 | else | |
208 | cfg.codec = RPC_AUD_DEF_CODEC_AAC; | |
209 | cfg.snd_method = RPC_SND_METHOD_MIDI; | |
210 | ||
211 | rc = audmgr_enable(&audio->audmgr, &cfg); | |
212 | if (rc < 0) | |
213 | return rc; | |
214 | ||
215 | if (msm_adsp_enable(audio->audpre)) { | |
216 | pr_err("audrec: msm_adsp_enable(audpre) failed\n"); | |
217 | return -ENODEV; | |
218 | } | |
219 | if (msm_adsp_enable(audio->audrec)) { | |
220 | pr_err("audrec: msm_adsp_enable(audrec) failed\n"); | |
221 | return -ENODEV; | |
222 | } | |
223 | ||
224 | audio->enabled = 1; | |
225 | audio_in_dsp_enable(audio, 1); | |
226 | ||
227 | return 0; | |
228 | } | |
229 | ||
230 | /* must be called with audio->lock held */ | |
231 | static int audio_in_disable(struct audio_in *audio) | |
232 | { | |
233 | if (audio->enabled) { | |
234 | audio->enabled = 0; | |
235 | ||
236 | audio_in_dsp_enable(audio, 0); | |
237 | ||
238 | wake_up(&audio->wait); | |
239 | ||
240 | msm_adsp_disable(audio->audrec); | |
241 | msm_adsp_disable(audio->audpre); | |
242 | audmgr_disable(&audio->audmgr); | |
243 | } | |
244 | return 0; | |
245 | } | |
246 | ||
247 | /* ------------------- dsp --------------------- */ | |
248 | static void audpre_dsp_event(void *data, unsigned id, size_t len, | |
249 | void (*getevent)(void *ptr, size_t len)) | |
250 | { | |
251 | uint16_t msg[2]; | |
252 | getevent(msg, sizeof(msg)); | |
253 | ||
254 | switch (id) { | |
255 | case AUDPREPROC_MSG_CMD_CFG_DONE_MSG: | |
256 | pr_info("audpre: type %d, status_flag %d\n", msg[0], msg[1]); | |
257 | break; | |
258 | case AUDPREPROC_MSG_ERROR_MSG_ID: | |
259 | pr_info("audpre: err_index %d\n", msg[0]); | |
260 | break; | |
261 | default: | |
262 | pr_err("audpre: unknown event %d\n", id); | |
263 | } | |
264 | } | |
265 | ||
266 | struct audio_frame { | |
267 | uint16_t count_low; | |
268 | uint16_t count_high; | |
269 | uint16_t bytes; | |
270 | uint16_t unknown; | |
271 | unsigned char samples[]; | |
272 | } __attribute__((packed)); | |
273 | ||
274 | static void audio_in_get_dsp_frames(struct audio_in *audio) | |
275 | { | |
276 | struct audio_frame *frame; | |
277 | uint32_t index; | |
278 | unsigned long flags; | |
279 | ||
280 | index = audio->in_head; | |
281 | ||
282 | /* XXX check for bogus frame size? */ | |
283 | ||
284 | frame = (void *) (((char *)audio->in[index].data) - sizeof(*frame)); | |
285 | ||
286 | spin_lock_irqsave(&audio->dsp_lock, flags); | |
287 | audio->in[index].size = frame->bytes; | |
288 | ||
289 | audio->in_head = (audio->in_head + 1) & (FRAME_NUM - 1); | |
290 | ||
291 | /* If overflow, move the tail index foward. */ | |
292 | if (audio->in_head == audio->in_tail) | |
293 | audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1); | |
294 | else | |
295 | audio->in_count++; | |
296 | ||
297 | audio_dsp_read_buffer(audio, audio->dsp_cnt++); | |
298 | spin_unlock_irqrestore(&audio->dsp_lock, flags); | |
299 | ||
300 | wake_up(&audio->wait); | |
301 | } | |
302 | ||
303 | static void audrec_dsp_event(void *data, unsigned id, size_t len, | |
304 | void (*getevent)(void *ptr, size_t len)) | |
305 | { | |
306 | struct audio_in *audio = data; | |
307 | uint16_t msg[3]; | |
308 | getevent(msg, sizeof(msg)); | |
309 | ||
310 | switch (id) { | |
311 | case AUDREC_MSG_CMD_CFG_DONE_MSG: | |
312 | if (msg[0] & AUDREC_MSG_CFG_DONE_TYPE_0_UPDATE) { | |
313 | if (msg[0] & AUDREC_MSG_CFG_DONE_TYPE_0_ENA) { | |
314 | pr_info("audpre: CFG ENABLED\n"); | |
315 | audio_dsp_set_agc(audio); | |
316 | audio_dsp_set_ns(audio); | |
317 | audio_dsp_set_tx_iir(audio); | |
318 | audio_in_encoder_config(audio); | |
319 | } else { | |
320 | pr_info("audrec: CFG SLEEP\n"); | |
321 | audio->running = 0; | |
322 | } | |
323 | } else { | |
324 | pr_info("audrec: CMD_CFG_DONE %x\n", msg[0]); | |
325 | } | |
326 | break; | |
327 | case AUDREC_MSG_CMD_AREC_PARAM_CFG_DONE_MSG: { | |
328 | pr_info("audrec: PARAM CFG DONE\n"); | |
329 | audio->running = 1; | |
330 | break; | |
331 | } | |
332 | case AUDREC_MSG_FATAL_ERR_MSG: | |
333 | pr_err("audrec: ERROR %x\n", msg[0]); | |
334 | break; | |
335 | case AUDREC_MSG_PACKET_READY_MSG: | |
336 | /* REC_DBG("type %x, count %d", msg[0], (msg[1] | (msg[2] << 16))); */ | |
337 | audio_in_get_dsp_frames(audio); | |
338 | break; | |
339 | default: | |
340 | pr_err("audrec: unknown event %d\n", id); | |
341 | } | |
342 | } | |
343 | ||
344 | struct msm_adsp_ops audpre_adsp_ops = { | |
345 | .event = audpre_dsp_event, | |
346 | }; | |
347 | ||
348 | struct msm_adsp_ops audrec_adsp_ops = { | |
349 | .event = audrec_dsp_event, | |
350 | }; | |
351 | ||
352 | ||
353 | #define audio_send_queue_pre(audio, cmd, len) \ | |
354 | msm_adsp_write(audio->audpre, QDSP_uPAudPreProcCmdQueue, cmd, len) | |
355 | #define audio_send_queue_recbs(audio, cmd, len) \ | |
356 | msm_adsp_write(audio->audrec, QDSP_uPAudRecBitStreamQueue, cmd, len) | |
357 | #define audio_send_queue_rec(audio, cmd, len) \ | |
358 | msm_adsp_write(audio->audrec, \ | |
359 | QDSP_uPAudRecCmdQueue, cmd, len) | |
360 | ||
361 | static int audio_dsp_set_agc(struct audio_in *audio) | |
362 | { | |
363 | audpreproc_cmd_cfg_agc_params cmd; | |
364 | ||
365 | memset(&cmd, 0, sizeof(cmd)); | |
366 | cmd.cmd_id = AUDPREPROC_CMD_CFG_AGC_PARAMS; | |
367 | ||
368 | if (audio->agc_enable) { | |
369 | /* cmd.tx_agc_param_mask = 0xFE00 from sample code */ | |
370 | cmd.tx_agc_param_mask = | |
371 | (1 << AUDPREPROC_CMD_TX_AGC_PARAM_MASK_COMP_SLOPE) | | |
372 | (1 << AUDPREPROC_CMD_TX_AGC_PARAM_MASK_COMP_TH) | | |
373 | (1 << AUDPREPROC_CMD_TX_AGC_PARAM_MASK_EXP_SLOPE) | | |
374 | (1 << AUDPREPROC_CMD_TX_AGC_PARAM_MASK_EXP_TH) | | |
375 | (1 << AUDPREPROC_CMD_TX_AGC_PARAM_MASK_COMP_AIG_FLAG) | | |
376 | (1 << AUDPREPROC_CMD_TX_AGC_PARAM_MASK_COMP_STATIC_GAIN) | | |
377 | (1 << AUDPREPROC_CMD_TX_AGC_PARAM_MASK_TX_AGC_ENA_FLAG); | |
378 | cmd.tx_agc_enable_flag = | |
379 | AUDPREPROC_CMD_TX_AGC_ENA_FLAG_ENA; | |
380 | memcpy(&cmd.static_gain, &audio->agc.agc_params[0], | |
381 | sizeof(uint16_t) * 6); | |
382 | /* cmd.param_mask = 0xFFF0 from sample code */ | |
383 | cmd.param_mask = | |
384 | (1 << AUDPREPROC_CMD_PARAM_MASK_RMS_TAY) | | |
385 | (1 << AUDPREPROC_CMD_PARAM_MASK_RELEASEK) | | |
386 | (1 << AUDPREPROC_CMD_PARAM_MASK_DELAY) | | |
387 | (1 << AUDPREPROC_CMD_PARAM_MASK_ATTACKK) | | |
388 | (1 << AUDPREPROC_CMD_PARAM_MASK_LEAKRATE_SLOW) | | |
389 | (1 << AUDPREPROC_CMD_PARAM_MASK_LEAKRATE_FAST) | | |
390 | (1 << AUDPREPROC_CMD_PARAM_MASK_AIG_RELEASEK) | | |
391 | (1 << AUDPREPROC_CMD_PARAM_MASK_AIG_MIN) | | |
392 | (1 << AUDPREPROC_CMD_PARAM_MASK_AIG_MAX) | | |
393 | (1 << AUDPREPROC_CMD_PARAM_MASK_LEAK_UP) | | |
394 | (1 << AUDPREPROC_CMD_PARAM_MASK_LEAK_DOWN) | | |
395 | (1 << AUDPREPROC_CMD_PARAM_MASK_AIG_ATTACKK); | |
396 | memcpy(&cmd.aig_attackk, &audio->agc.agc_params[6], | |
397 | sizeof(uint16_t) * 14); | |
398 | ||
399 | } else { | |
400 | cmd.tx_agc_param_mask = | |
401 | (1 << AUDPREPROC_CMD_TX_AGC_PARAM_MASK_TX_AGC_ENA_FLAG); | |
402 | cmd.tx_agc_enable_flag = | |
403 | AUDPREPROC_CMD_TX_AGC_ENA_FLAG_DIS; | |
404 | } | |
405 | #if DEBUG | |
406 | pr_info("cmd_id = 0x%04x\n", cmd.cmd_id); | |
407 | pr_info("tx_agc_param_mask = 0x%04x\n", cmd.tx_agc_param_mask); | |
408 | pr_info("tx_agc_enable_flag = 0x%04x\n", cmd.tx_agc_enable_flag); | |
409 | pr_info("static_gain = 0x%04x\n", cmd.static_gain); | |
410 | pr_info("adaptive_gain_flag = 0x%04x\n", cmd.adaptive_gain_flag); | |
411 | pr_info("expander_th = 0x%04x\n", cmd.expander_th); | |
412 | pr_info("expander_slope = 0x%04x\n", cmd.expander_slope); | |
413 | pr_info("compressor_th = 0x%04x\n", cmd.compressor_th); | |
414 | pr_info("compressor_slope = 0x%04x\n", cmd.compressor_slope); | |
415 | pr_info("param_mask = 0x%04x\n", cmd.param_mask); | |
416 | pr_info("aig_attackk = 0x%04x\n", cmd.aig_attackk); | |
417 | pr_info("aig_leak_down = 0x%04x\n", cmd.aig_leak_down); | |
418 | pr_info("aig_leak_up = 0x%04x\n", cmd.aig_leak_up); | |
419 | pr_info("aig_max = 0x%04x\n", cmd.aig_max); | |
420 | pr_info("aig_min = 0x%04x\n", cmd.aig_min); | |
421 | pr_info("aig_releasek = 0x%04x\n", cmd.aig_releasek); | |
422 | pr_info("aig_leakrate_fast = 0x%04x\n", cmd.aig_leakrate_fast); | |
423 | pr_info("aig_leakrate_slow = 0x%04x\n", cmd.aig_leakrate_slow); | |
424 | pr_info("attackk_msw = 0x%04x\n", cmd.attackk_msw); | |
425 | pr_info("attackk_lsw = 0x%04x\n", cmd.attackk_lsw); | |
426 | pr_info("delay = 0x%04x\n", cmd.delay); | |
427 | pr_info("releasek_msw = 0x%04x\n", cmd.releasek_msw); | |
428 | pr_info("releasek_lsw = 0x%04x\n", cmd.releasek_lsw); | |
429 | pr_info("rms_tav = 0x%04x\n", cmd.rms_tav); | |
430 | #endif | |
431 | return audio_send_queue_pre(audio, &cmd, sizeof(cmd)); | |
432 | } | |
433 | ||
434 | static int audio_dsp_set_ns(struct audio_in *audio) | |
435 | { | |
436 | audpreproc_cmd_cfg_ns_params cmd; | |
437 | ||
438 | memset(&cmd, 0, sizeof(cmd)); | |
439 | cmd.cmd_id = AUDPREPROC_CMD_CFG_NS_PARAMS; | |
440 | ||
441 | if (audio->ns_enable) { | |
442 | /* cmd.ec_mode_new is fixed as 0x0064 when enable from sample code */ | |
443 | cmd.ec_mode_new = | |
444 | AUDPREPROC_CMD_EC_MODE_NEW_NS_ENA | | |
445 | AUDPREPROC_CMD_EC_MODE_NEW_HB_ENA | | |
446 | AUDPREPROC_CMD_EC_MODE_NEW_VA_ENA; | |
447 | memcpy(&cmd.dens_gamma_n, &audio->ns.ns_params, | |
448 | sizeof(audio->ns.ns_params)); | |
449 | } else { | |
450 | cmd.ec_mode_new = | |
451 | AUDPREPROC_CMD_EC_MODE_NEW_NLMS_DIS | | |
452 | AUDPREPROC_CMD_EC_MODE_NEW_DES_DIS | | |
453 | AUDPREPROC_CMD_EC_MODE_NEW_NS_DIS | | |
454 | AUDPREPROC_CMD_EC_MODE_NEW_CNI_DIS | | |
455 | AUDPREPROC_CMD_EC_MODE_NEW_NLES_DIS | | |
456 | AUDPREPROC_CMD_EC_MODE_NEW_HB_DIS | | |
457 | AUDPREPROC_CMD_EC_MODE_NEW_VA_DIS | | |
458 | AUDPREPROC_CMD_EC_MODE_NEW_PCD_DIS | | |
459 | AUDPREPROC_CMD_EC_MODE_NEW_FEHI_DIS | | |
460 | AUDPREPROC_CMD_EC_MODE_NEW_NEHI_DIS | | |
461 | AUDPREPROC_CMD_EC_MODE_NEW_NLPP_DIS | | |
462 | AUDPREPROC_CMD_EC_MODE_NEW_FNE_DIS | | |
463 | AUDPREPROC_CMD_EC_MODE_NEW_PRENLMS_DIS; | |
464 | } | |
465 | #if DEBUG | |
466 | pr_info("cmd_id = 0x%04x\n", cmd.cmd_id); | |
467 | pr_info("ec_mode_new = 0x%04x\n", cmd.ec_mode_new); | |
468 | pr_info("dens_gamma_n = 0x%04x\n", cmd.dens_gamma_n); | |
469 | pr_info("dens_nfe_block_size = 0x%04x\n", cmd.dens_nfe_block_size); | |
470 | pr_info("dens_limit_ns = 0x%04x\n", cmd.dens_limit_ns); | |
471 | pr_info("dens_limit_ns_d = 0x%04x\n", cmd.dens_limit_ns_d); | |
472 | pr_info("wb_gamma_e = 0x%04x\n", cmd.wb_gamma_e); | |
473 | pr_info("wb_gamma_n = 0x%04x\n", cmd.wb_gamma_n); | |
474 | #endif | |
475 | return audio_send_queue_pre(audio, &cmd, sizeof(cmd)); | |
476 | } | |
477 | ||
478 | static int audio_dsp_set_tx_iir(struct audio_in *audio) | |
479 | { | |
480 | struct audpre_cmd_iir_config_type cmd; | |
481 | ||
482 | memset(&cmd, 0, sizeof(cmd)); | |
483 | cmd.cmd_id = AUDPREPROC_CMD_CFG_IIR_TUNING_FILTER_PARAMS; | |
484 | ||
485 | if (audio->iir_enable) { | |
486 | cmd.active_flag = AUDPREPROC_CMD_IIR_ACTIVE_FLAG_ENA; | |
487 | cmd.num_bands = audio->iir.num_bands; | |
488 | memcpy(&cmd.iir_params, &audio->iir.iir_params, | |
489 | sizeof(audio->iir.iir_params)); | |
490 | } else { | |
491 | cmd.active_flag = AUDPREPROC_CMD_IIR_ACTIVE_FLAG_DIS; | |
492 | } | |
493 | #if DEBUG | |
494 | pr_info("cmd_id = 0x%04x\n", cmd.cmd_id); | |
495 | pr_info("active_flag = 0x%04x\n", cmd.active_flag); | |
496 | #endif | |
497 | return audio_send_queue_pre(audio, &cmd, sizeof(cmd)); | |
498 | } | |
499 | ||
500 | static int audio_in_dsp_enable(struct audio_in *audio, int enable) | |
501 | { | |
502 | audrec_cmd_cfg cmd; | |
503 | ||
504 | memset(&cmd, 0, sizeof(cmd)); | |
505 | cmd.cmd_id = AUDREC_CMD_CFG; | |
506 | cmd.type_0 = enable ? AUDREC_CMD_TYPE_0_ENA : AUDREC_CMD_TYPE_0_DIS; | |
507 | cmd.type_0 |= (AUDREC_CMD_TYPE_0_UPDATE | audio->type); | |
508 | cmd.type_1 = 0; | |
509 | ||
510 | return audio_send_queue_rec(audio, &cmd, sizeof(cmd)); | |
511 | } | |
512 | ||
513 | static int audio_in_encoder_config(struct audio_in *audio) | |
514 | { | |
515 | audrec_cmd_arec0param_cfg cmd; | |
516 | uint16_t *data = (void *) audio->data; | |
517 | unsigned n; | |
518 | ||
519 | memset(&cmd, 0, sizeof(cmd)); | |
520 | cmd.cmd_id = AUDREC_CMD_AREC0PARAM_CFG; | |
521 | cmd.ptr_to_extpkt_buffer_msw = audio->phys >> 16; | |
522 | cmd.ptr_to_extpkt_buffer_lsw = audio->phys; | |
523 | cmd.buf_len = FRAME_NUM; /* Both WAV and AAC use 8 frames */ | |
524 | cmd.samp_rate_index = audio->samp_rate_index; | |
525 | cmd.stereo_mode = audio->channel_mode; /* 0 for mono, 1 for stereo */ | |
526 | ||
527 | /* FIXME have no idea why cmd.rec_quality is fixed | |
528 | * as 0x1C00 from sample code | |
529 | */ | |
530 | cmd.rec_quality = 0x1C00; | |
531 | ||
532 | /* prepare buffer pointers: | |
533 | * Mono: 1024 samples + 4 halfword header | |
534 | * Stereo: 2048 samples + 4 halfword header | |
535 | * AAC | |
536 | * Mono/Stere: 768 + 4 halfword header | |
537 | */ | |
538 | for (n = 0; n < FRAME_NUM; n++) { | |
539 | audio->in[n].data = data + 4; | |
540 | if (audio->type == AUDREC_CMD_TYPE_0_INDEX_WAV) | |
541 | data += (4 + (audio->channel_mode ? 2048 : 1024)); | |
542 | else if (audio->type == AUDREC_CMD_TYPE_0_INDEX_AAC) | |
543 | data += (4 + 768); | |
544 | } | |
545 | ||
546 | return audio_send_queue_rec(audio, &cmd, sizeof(cmd)); | |
547 | } | |
548 | ||
549 | static int audio_dsp_read_buffer(struct audio_in *audio, uint32_t read_cnt) | |
550 | { | |
551 | audrec_cmd_packet_ext_ptr cmd; | |
552 | ||
553 | memset(&cmd, 0, sizeof(cmd)); | |
554 | cmd.cmd_id = AUDREC_CMD_PACKET_EXT_PTR; | |
555 | /* Both WAV and AAC use AUDREC_CMD_TYPE_0 */ | |
556 | cmd.type = AUDREC_CMD_TYPE_0; | |
557 | cmd.curr_rec_count_msw = read_cnt >> 16; | |
558 | cmd.curr_rec_count_lsw = read_cnt; | |
559 | ||
560 | return audio_send_queue_recbs(audio, &cmd, sizeof(cmd)); | |
561 | } | |
562 | ||
563 | /* ------------------- device --------------------- */ | |
564 | ||
565 | static void audio_enable_agc(struct audio_in *audio, int enable) | |
566 | { | |
567 | if (audio->agc_enable != enable) { | |
568 | audio->agc_enable = enable; | |
569 | if (audio->running) | |
570 | audio_dsp_set_agc(audio); | |
571 | } | |
572 | } | |
573 | ||
574 | static void audio_enable_ns(struct audio_in *audio, int enable) | |
575 | { | |
576 | if (audio->ns_enable != enable) { | |
577 | audio->ns_enable = enable; | |
578 | if (audio->running) | |
579 | audio_dsp_set_ns(audio); | |
580 | } | |
581 | } | |
582 | ||
583 | static void audio_enable_tx_iir(struct audio_in *audio, int enable) | |
584 | { | |
585 | if (audio->iir_enable != enable) { | |
586 | audio->iir_enable = enable; | |
587 | if (audio->running) | |
588 | audio_dsp_set_tx_iir(audio); | |
589 | } | |
590 | } | |
591 | ||
592 | static void audio_flush(struct audio_in *audio) | |
593 | { | |
594 | int i; | |
595 | ||
596 | audio->dsp_cnt = 0; | |
597 | audio->in_head = 0; | |
598 | audio->in_tail = 0; | |
599 | audio->in_count = 0; | |
600 | for (i = 0; i < FRAME_NUM; i++) { | |
601 | audio->in[i].size = 0; | |
602 | audio->in[i].read = 0; | |
603 | } | |
604 | } | |
605 | ||
606 | static long audio_in_ioctl(struct file *file, | |
607 | unsigned int cmd, unsigned long arg) | |
608 | { | |
609 | struct audio_in *audio = file->private_data; | |
610 | int rc; | |
611 | ||
612 | if (cmd == AUDIO_GET_STATS) { | |
613 | struct msm_audio_stats stats; | |
614 | stats.byte_count = atomic_read(&audio->in_bytes); | |
615 | if (copy_to_user((void *) arg, &stats, sizeof(stats))) | |
616 | return -EFAULT; | |
617 | return 0; | |
618 | } | |
619 | ||
620 | mutex_lock(&audio->lock); | |
621 | switch (cmd) { | |
622 | case AUDIO_START: | |
623 | rc = audio_in_enable(audio); | |
624 | break; | |
625 | case AUDIO_STOP: | |
626 | rc = audio_in_disable(audio); | |
627 | audio->stopped = 1; | |
628 | break; | |
629 | case AUDIO_FLUSH: | |
630 | if (audio->stopped) { | |
631 | /* Make sure we're stopped and we wake any threads | |
632 | * that might be blocked holding the read_lock. | |
633 | * While audio->stopped read threads will always | |
634 | * exit immediately. | |
635 | */ | |
636 | wake_up(&audio->wait); | |
637 | mutex_lock(&audio->read_lock); | |
638 | audio_flush(audio); | |
639 | mutex_unlock(&audio->read_lock); | |
640 | } | |
641 | case AUDIO_SET_CONFIG: { | |
642 | struct msm_audio_config cfg; | |
643 | if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) { | |
644 | rc = -EFAULT; | |
645 | break; | |
646 | } | |
647 | if (cfg.channel_count == 1) { | |
648 | cfg.channel_count = AUDREC_CMD_STEREO_MODE_MONO; | |
649 | } else if (cfg.channel_count == 2) { | |
650 | cfg.channel_count = AUDREC_CMD_STEREO_MODE_STEREO; | |
651 | } else { | |
652 | rc = -EINVAL; | |
653 | break; | |
654 | } | |
655 | ||
656 | if (cfg.type == 0) { | |
657 | cfg.type = AUDREC_CMD_TYPE_0_INDEX_WAV; | |
658 | } else if (cfg.type == 1) { | |
659 | cfg.type = AUDREC_CMD_TYPE_0_INDEX_AAC; | |
660 | } else { | |
661 | rc = -EINVAL; | |
662 | break; | |
663 | } | |
664 | audio->samp_rate = convert_samp_rate(cfg.sample_rate); | |
665 | audio->samp_rate_index = | |
666 | convert_dsp_samp_index(cfg.sample_rate); | |
667 | audio->channel_mode = cfg.channel_count; | |
668 | audio->buffer_size = | |
669 | audio->channel_mode ? STEREO_DATA_SIZE | |
670 | : MONO_DATA_SIZE; | |
671 | audio->type = cfg.type; | |
672 | rc = 0; | |
673 | break; | |
674 | } | |
675 | case AUDIO_GET_CONFIG: { | |
676 | struct msm_audio_config cfg; | |
677 | cfg.buffer_size = audio->buffer_size; | |
678 | cfg.buffer_count = FRAME_NUM; | |
679 | cfg.sample_rate = convert_samp_index(audio->samp_rate); | |
680 | if (audio->channel_mode == AUDREC_CMD_STEREO_MODE_MONO) | |
681 | cfg.channel_count = 1; | |
682 | else | |
683 | cfg.channel_count = 2; | |
684 | if (audio->type == AUDREC_CMD_TYPE_0_INDEX_WAV) | |
685 | cfg.type = 0; | |
686 | else | |
687 | cfg.type = 1; | |
688 | cfg.unused[0] = 0; | |
689 | cfg.unused[1] = 0; | |
690 | cfg.unused[2] = 0; | |
691 | if (copy_to_user((void *) arg, &cfg, sizeof(cfg))) | |
692 | rc = -EFAULT; | |
693 | else | |
694 | rc = 0; | |
695 | break; | |
696 | } | |
697 | default: | |
698 | rc = -EINVAL; | |
699 | } | |
700 | mutex_unlock(&audio->lock); | |
701 | return rc; | |
702 | } | |
703 | ||
704 | static ssize_t audio_in_read(struct file *file, | |
705 | char __user *buf, | |
706 | size_t count, loff_t *pos) | |
707 | { | |
708 | struct audio_in *audio = file->private_data; | |
709 | unsigned long flags; | |
710 | const char __user *start = buf; | |
711 | void *data; | |
712 | uint32_t index; | |
713 | uint32_t size; | |
714 | int rc = 0; | |
715 | ||
716 | mutex_lock(&audio->read_lock); | |
717 | while (count > 0) { | |
718 | rc = wait_event_interruptible( | |
719 | audio->wait, (audio->in_count > 0) || audio->stopped); | |
720 | if (rc < 0) | |
721 | break; | |
722 | ||
723 | if (audio->stopped) { | |
724 | rc = -EBUSY; | |
725 | break; | |
726 | } | |
727 | ||
728 | index = audio->in_tail; | |
729 | data = (uint8_t *) audio->in[index].data; | |
730 | size = audio->in[index].size; | |
731 | if (count >= size) { | |
732 | if (copy_to_user(buf, data, size)) { | |
733 | rc = -EFAULT; | |
734 | break; | |
735 | } | |
736 | spin_lock_irqsave(&audio->dsp_lock, flags); | |
737 | if (index != audio->in_tail) { | |
738 | /* overrun -- data is invalid and we need to retry */ | |
739 | spin_unlock_irqrestore(&audio->dsp_lock, flags); | |
740 | continue; | |
741 | } | |
742 | audio->in[index].size = 0; | |
743 | audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1); | |
744 | audio->in_count--; | |
745 | spin_unlock_irqrestore(&audio->dsp_lock, flags); | |
746 | count -= size; | |
747 | buf += size; | |
748 | if (audio->type == AUDREC_CMD_TYPE_0_INDEX_AAC) | |
749 | break; | |
750 | } else { | |
751 | pr_err("audio_in: short read\n"); | |
752 | break; | |
753 | } | |
754 | if (audio->type == AUDREC_CMD_TYPE_0_INDEX_AAC) | |
755 | break; /* AAC only read one frame */ | |
756 | } | |
757 | mutex_unlock(&audio->read_lock); | |
758 | ||
759 | if (buf > start) | |
760 | return buf - start; | |
761 | ||
762 | return rc; | |
763 | } | |
764 | ||
765 | static ssize_t audio_in_write(struct file *file, | |
766 | const char __user *buf, | |
767 | size_t count, loff_t *pos) | |
768 | { | |
769 | return -EINVAL; | |
770 | } | |
771 | ||
772 | static int audio_in_release(struct inode *inode, struct file *file) | |
773 | { | |
774 | struct audio_in *audio = file->private_data; | |
775 | ||
776 | mutex_lock(&audio->lock); | |
777 | audio_in_disable(audio); | |
778 | audio_flush(audio); | |
779 | msm_adsp_put(audio->audrec); | |
780 | msm_adsp_put(audio->audpre); | |
781 | audio->audrec = NULL; | |
782 | audio->audpre = NULL; | |
783 | audio->opened = 0; | |
784 | mutex_unlock(&audio->lock); | |
785 | return 0; | |
786 | } | |
787 | ||
788 | struct audio_in the_audio_in; | |
789 | ||
790 | static int audio_in_open(struct inode *inode, struct file *file) | |
791 | { | |
792 | struct audio_in *audio = &the_audio_in; | |
793 | int rc; | |
794 | ||
795 | mutex_lock(&audio->lock); | |
796 | if (audio->opened) { | |
797 | rc = -EBUSY; | |
798 | goto done; | |
799 | } | |
800 | ||
801 | /* Settings will be re-config at AUDIO_SET_CONFIG, | |
802 | * but at least we need to have initial config | |
803 | */ | |
804 | audio->samp_rate = RPC_AUD_DEF_SAMPLE_RATE_11025; | |
805 | audio->samp_rate_index = AUDREC_CMD_SAMP_RATE_INDX_11025; | |
806 | audio->channel_mode = AUDREC_CMD_STEREO_MODE_MONO; | |
807 | audio->buffer_size = MONO_DATA_SIZE; | |
808 | audio->type = AUDREC_CMD_TYPE_0_INDEX_WAV; | |
809 | ||
810 | rc = audmgr_open(&audio->audmgr); | |
811 | if (rc) | |
812 | goto done; | |
813 | rc = msm_adsp_get("AUDPREPROCTASK", &audio->audpre, | |
814 | &audpre_adsp_ops, audio); | |
815 | if (rc) | |
816 | goto done; | |
817 | rc = msm_adsp_get("AUDRECTASK", &audio->audrec, | |
818 | &audrec_adsp_ops, audio); | |
819 | if (rc) | |
820 | goto done; | |
821 | ||
822 | audio->dsp_cnt = 0; | |
823 | audio->stopped = 0; | |
824 | ||
825 | audio_flush(audio); | |
826 | ||
827 | file->private_data = audio; | |
828 | audio->opened = 1; | |
829 | rc = 0; | |
830 | done: | |
831 | mutex_unlock(&audio->lock); | |
832 | return rc; | |
833 | } | |
834 | ||
835 | static long audpre_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |
836 | { | |
837 | struct audio_in *audio = file->private_data; | |
838 | int rc = 0, enable; | |
839 | uint16_t enable_mask; | |
840 | #if DEBUG | |
841 | int i; | |
842 | #endif | |
843 | ||
844 | mutex_lock(&audio->lock); | |
845 | switch (cmd) { | |
846 | case AUDIO_ENABLE_AUDPRE: { | |
847 | if (copy_from_user(&enable_mask, (void *) arg, | |
848 | sizeof(enable_mask))) | |
849 | goto out_fault; | |
850 | ||
851 | enable = (enable_mask & AGC_ENABLE) ? 1 : 0; | |
852 | audio_enable_agc(audio, enable); | |
853 | enable = (enable_mask & NS_ENABLE) ? 1 : 0; | |
854 | audio_enable_ns(audio, enable); | |
855 | enable = (enable_mask & IIR_ENABLE) ? 1 : 0; | |
856 | audio_enable_tx_iir(audio, enable); | |
857 | break; | |
858 | } | |
859 | case AUDIO_SET_AGC: { | |
860 | if (copy_from_user(&audio->agc, (void *) arg, | |
861 | sizeof(audio->agc))) | |
862 | goto out_fault; | |
863 | #if DEBUG | |
864 | pr_info("set agc\n"); | |
865 | for (i = 0; i < AGC_PARAM_SIZE; i++) \ | |
866 | pr_info("agc_params[%d] = 0x%04x\n", i, | |
867 | audio->agc.agc_params[i]); | |
868 | #endif | |
869 | break; | |
870 | } | |
871 | case AUDIO_SET_NS: { | |
872 | if (copy_from_user(&audio->ns, (void *) arg, | |
873 | sizeof(audio->ns))) | |
874 | goto out_fault; | |
875 | #if DEBUG | |
876 | pr_info("set ns\n"); | |
877 | for (i = 0; i < NS_PARAM_SIZE; i++) \ | |
878 | pr_info("ns_params[%d] = 0x%04x\n", | |
879 | i, audio->ns.ns_params[i]); | |
880 | #endif | |
881 | break; | |
882 | } | |
883 | case AUDIO_SET_TX_IIR: { | |
884 | if (copy_from_user(&audio->iir, (void *) arg, | |
885 | sizeof(audio->iir))) | |
886 | goto out_fault; | |
887 | #if DEBUG | |
888 | pr_info("set iir\n"); | |
889 | pr_info("iir.num_bands = 0x%04x\n", audio->iir.num_bands); | |
890 | for (i = 0; i < IIR_PARAM_SIZE; i++) \ | |
891 | pr_info("iir_params[%d] = 0x%04x\n", | |
892 | i, audio->iir.iir_params[i]); | |
893 | #endif | |
894 | break; | |
895 | } | |
896 | default: | |
897 | rc = -EINVAL; | |
898 | } | |
899 | ||
900 | goto out; | |
901 | ||
902 | out_fault: | |
903 | rc = -EFAULT; | |
904 | out: | |
905 | mutex_unlock(&audio->lock); | |
906 | return rc; | |
907 | } | |
908 | ||
909 | static int audpre_open(struct inode *inode, struct file *file) | |
910 | { | |
911 | struct audio_in *audio = &the_audio_in; | |
912 | file->private_data = audio; | |
913 | return 0; | |
914 | } | |
915 | ||
916 | static struct file_operations audio_fops = { | |
917 | .owner = THIS_MODULE, | |
918 | .open = audio_in_open, | |
919 | .release = audio_in_release, | |
920 | .read = audio_in_read, | |
921 | .write = audio_in_write, | |
922 | .unlocked_ioctl = audio_in_ioctl, | |
923 | }; | |
924 | ||
925 | static struct file_operations audpre_fops = { | |
926 | .owner = THIS_MODULE, | |
927 | .open = audpre_open, | |
928 | .unlocked_ioctl = audpre_ioctl, | |
929 | }; | |
930 | ||
931 | struct miscdevice audio_in_misc = { | |
932 | .minor = MISC_DYNAMIC_MINOR, | |
933 | .name = "msm_pcm_in", | |
934 | .fops = &audio_fops, | |
935 | }; | |
936 | ||
937 | struct miscdevice audpre_misc = { | |
938 | .minor = MISC_DYNAMIC_MINOR, | |
939 | .name = "msm_audpre", | |
940 | .fops = &audpre_fops, | |
941 | }; | |
942 | ||
943 | static int __init audio_in_init(void) | |
944 | { | |
945 | int rc; | |
946 | the_audio_in.data = dma_alloc_coherent(NULL, DMASZ, | |
947 | &the_audio_in.phys, GFP_KERNEL); | |
948 | if (!the_audio_in.data) { | |
949 | printk(KERN_ERR "%s: Unable to allocate DMA buffer\n", | |
950 | __func__); | |
951 | return -ENOMEM; | |
952 | } | |
953 | ||
954 | mutex_init(&the_audio_in.lock); | |
955 | mutex_init(&the_audio_in.read_lock); | |
956 | spin_lock_init(&the_audio_in.dsp_lock); | |
957 | init_waitqueue_head(&the_audio_in.wait); | |
958 | rc = misc_register(&audio_in_misc); | |
959 | if (!rc) { | |
960 | rc = misc_register(&audpre_misc); | |
961 | if (rc < 0) | |
962 | misc_deregister(&audio_in_misc); | |
963 | } | |
964 | return rc; | |
965 | } | |
966 | ||
967 | device_initcall(audio_in_init); |