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