blob: bea528fe9ac3838302caf9f55627bc15cb87ea3b [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* sound/soc/msm/msm-pcm.c
2 *
3 * Copyright (C) 2008 Google, Inc.
4 * Copyright (C) 2008 HTC Corporation
5 * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
6 *
7 * This software is licensed under the terms of the GNU General Public
8 * License version 2, as published by the Free Software Foundation, and
9 * may be copied, distributed, and modified under those terms.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 *
15 * See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you can find it at http://www.fsf.org.
18 */
19
20
21#include <linux/init.h>
22#include <linux/err.h>
23#include <linux/module.h>
24#include <linux/moduleparam.h>
25#include <linux/time.h>
26#include <linux/wait.h>
27#include <linux/platform_device.h>
28#include <sound/core.h>
29#include <sound/soc.h>
30#include <sound/pcm.h>
31#include <sound/initval.h>
32#include <asm/dma.h>
33#include <linux/dma-mapping.h>
34
35#include "msm-pcm.h"
36
37#define MAX_DATA_SIZE 496
38#define AUDPP_ALSA_DECODER (-1)
39
40#define DB_TABLE_INDEX (50)
41
42#define audio_send_queue_recbs(prtd, cmd, len) \
43 msm_adsp_write(prtd->audrec, QDSP_uPAudRecBitStreamQueue, cmd, len)
44#define audio_send_queue_rec(prtd, cmd, len) \
45 msm_adsp_write(prtd->audrec, QDSP_uPAudRecCmdQueue, cmd, len)
46
47int intcnt;
48static int audio_dsp_send_buffer(struct msm_audio *prtd,
49 unsigned idx, unsigned len);
50
51struct audio_frame {
52 uint16_t count_low;
53 uint16_t count_high;
54 uint16_t bytes;
55 uint16_t unknown;
56 unsigned char samples[];
57} __attribute__ ((packed));
58
59/* Table contains dB to raw value mapping */
60static const unsigned decoder_db_table[] = {
61
62 31 , /* -50 dB */
63 35 , 39 , 44 , 50 , 56 ,
64 63 , 70 , 79 , 89 , 99 ,
65 112 , 125 , 141 , 158 , 177 ,
66 199 , 223 , 251 , 281 , 316 ,
67 354 , 398 , 446 , 501 , 562 ,
68 630 , 707 , 794 , 891 , 999 ,
69 1122 , 1258 , 1412 , 1584 , 1778 ,
70 1995 , 2238 , 2511 , 2818 , 3162 ,
71 3548 , 3981 , 4466 , 5011 , 5623 ,
72 6309 , 7079 , 7943 , 8912 , 10000 ,
73 11220 , 12589 , 14125 , 15848 , 17782 ,
74 19952 , 22387 , 25118 , 28183 , 31622 ,
75 35481 , 39810 , 44668 , 50118 , 56234 ,
76 63095 , 70794 , 79432 , 89125 , 100000 ,
77 112201 , 125892 , 141253 , 158489 , 177827 ,
78 199526 , 223872 , 251188 , 281838 , 316227 ,
79 354813 , 398107 , 446683 , 501187 , 562341 ,
80 630957 , 707945 , 794328 , 891250 , 1000000 ,
81 1122018 , 1258925 , 1412537 , 1584893 , 1778279 ,
82 1995262 , 2238721 , 2511886 , 2818382 , 3162277 ,
83 3548133 /* 51 dB */
84
85};
86
87static unsigned compute_db_raw(int db)
88{
89 unsigned reg_val = 0; /* Computed result for correspondent db */
90 /* Check if the given db is out of range */
91 if (db <= MIN_DB)
92 return 0;
93 else if (db > MAX_DB)
94 db = MAX_DB; /* If db is too high then set to max */
95 reg_val = decoder_db_table[DB_TABLE_INDEX+db];
96 return reg_val;
97}
98
99int msm_audio_volume_update(unsigned id,
100 int volume, int pan)
101{
102 unsigned vol_raw;
103
104 vol_raw = compute_db_raw(volume);
105 printk(KERN_INFO "volume: %8x vol_raw: %8x \n", volume, vol_raw);
106 return audpp_set_volume_and_pan(id, vol_raw, pan);
107}
108EXPORT_SYMBOL(msm_audio_volume_update);
109
110void alsa_dsp_event(void *data, unsigned id, uint16_t *msg)
111{
112 struct msm_audio *prtd = data;
113 struct buffer *frame;
114 unsigned long flag;
115
116 switch (id) {
117 case AUDPP_MSG_STATUS_MSG:
118 break;
119 case AUDPP_MSG_SPA_BANDS:
120 break;
121 case AUDPP_MSG_HOST_PCM_INTF_MSG:{
122 unsigned id = msg[2];
123 unsigned idx = msg[3] - 1;
124 if (id != AUDPP_MSG_HOSTPCM_ID_ARM_RX) {
125 printk(KERN_ERR "bogus id\n");
126 break;
127 }
128 if (idx > 1) {
129 printk(KERN_ERR "bogus buffer idx\n");
130 break;
131 }
132 /* Update with actual sent buffer size */
133 if (prtd->out[idx].used != BUF_INVALID_LEN)
134 prtd->pcm_irq_pos += prtd->out[idx].used;
135
136 if (prtd->pcm_irq_pos > prtd->pcm_size)
137 prtd->pcm_irq_pos = prtd->pcm_count;
138
139 if (prtd->ops->playback)
140 prtd->ops->playback(prtd);
141
142 spin_lock_irqsave(&the_locks.write_dsp_lock, flag);
143 if (prtd->running) {
144 prtd->out[idx].used = 0;
145 frame = prtd->out + prtd->out_tail;
146 if (frame->used) {
147 audio_dsp_send_buffer(prtd,
148 prtd->out_tail,
149 frame->used);
150 prtd->out_tail ^= 1;
151 } else {
152 prtd->out_needed++;
153 }
154 wake_up(&the_locks.write_wait);
155 }
156 spin_unlock_irqrestore(&the_locks.write_dsp_lock, flag);
157 break;
158 }
159 case AUDPP_MSG_PCMDMAMISSED:
160 pr_info("alsa_dsp_event: PCMDMAMISSED %d\n", msg[0]);
161 prtd->eos_ack = 1;
162 wake_up(&the_locks.eos_wait);
163 break;
164 case AUDPP_MSG_CFG_MSG:
165 if (msg[0] == AUDPP_MSG_ENA_ENA) {
166 prtd->out_needed = 0;
167 prtd->running = 1;
168 audio_dsp_out_enable(prtd, 1);
169 } else if (msg[0] == AUDPP_MSG_ENA_DIS) {
170 prtd->running = 0;
171 } else {
172 printk(KERN_ERR "alsa_dsp_event:CFG_MSG=%d\n", msg[0]);
173 }
174 break;
175 case EVENT_MSG_ID:
176 printk(KERN_INFO"alsa_dsp_event: arm9 event\n");
177 break;
178 default:
179 printk(KERN_ERR "alsa_dsp_event: UNKNOWN (%d)\n", id);
180 }
181}
182
183void alsa_audpre_dsp_event(void *data, unsigned id, size_t len,
184 void (*getevent) (void *ptr, size_t len))
185{
186 uint16_t msg[MAX_DATA_SIZE/2];
187
188 if (len > MAX_DATA_SIZE) {
189 printk(KERN_ERR"audpre: event too large(%d bytes)\n", len);
190 return;
191 }
192 getevent(msg, len);
193
194 switch (id) {
195 case AUDPREPROC_MSG_CMD_CFG_DONE_MSG:
196 break;
197 case AUDPREPROC_MSG_ERROR_MSG_ID:
198 printk(KERN_ERR "audpre: err_index %d\n", msg[0]);
199 break;
200 case EVENT_MSG_ID:
201 printk(KERN_INFO"audpre: arm9 event\n");
202 break;
203 default:
204 printk(KERN_ERR "audpre: unknown event %d\n", id);
205 }
206}
207
208void audrec_dsp_event(void *data, unsigned id, size_t len,
209 void (*getevent) (void *ptr, size_t len))
210{
211 struct msm_audio *prtd = data;
212 unsigned long flag;
213 uint16_t msg[MAX_DATA_SIZE/2];
214
215 if (len > MAX_DATA_SIZE) {
216 printk(KERN_ERR"audrec: event/msg too large(%d bytes)\n", len);
217 return;
218 }
219 getevent(msg, len);
220
221 switch (id) {
222 case AUDREC_MSG_CMD_CFG_DONE_MSG:
223 if (msg[0] & AUDREC_MSG_CFG_DONE_TYPE_0_UPDATE) {
224 if (msg[0] & AUDREC_MSG_CFG_DONE_TYPE_0_ENA)
225 audrec_encoder_config(prtd);
226 else
227 prtd->running = 0;
228 }
229 break;
230 case AUDREC_MSG_CMD_AREC_PARAM_CFG_DONE_MSG:{
231 prtd->running = 1;
232 break;
233 }
234 case AUDREC_MSG_FATAL_ERR_MSG:
235 printk(KERN_ERR "audrec: ERROR %x\n", msg[0]);
236 break;
237 case AUDREC_MSG_PACKET_READY_MSG:
238 alsa_get_dsp_frames(prtd);
239 ++intcnt;
240 if (prtd->channel_mode == 1) {
241 spin_lock_irqsave(&the_locks.read_dsp_lock, flag);
242 prtd->pcm_irq_pos += prtd->pcm_count;
243 if (prtd->pcm_irq_pos >= prtd->pcm_size)
244 prtd->pcm_irq_pos = 0;
245 spin_unlock_irqrestore(&the_locks.read_dsp_lock, flag);
246
247 if (prtd->ops->capture)
248 prtd->ops->capture(prtd);
249 } else if ((prtd->channel_mode == 0) && (intcnt % 2 == 0)) {
250 spin_lock_irqsave(&the_locks.read_dsp_lock, flag);
251 prtd->pcm_irq_pos += prtd->pcm_count;
252 if (prtd->pcm_irq_pos >= prtd->pcm_size)
253 prtd->pcm_irq_pos = 0;
254 spin_unlock_irqrestore(&the_locks.read_dsp_lock, flag);
255 if (prtd->ops->capture)
256 prtd->ops->capture(prtd);
257 }
258 break;
259 case EVENT_MSG_ID:
260 printk(KERN_INFO"audrec: arm9 event\n");
261 break;
262 default:
263 printk(KERN_ERR "audrec: unknown event %d\n", id);
264 }
265}
266
267struct msm_adsp_ops aud_pre_adsp_ops = {
268 .event = alsa_audpre_dsp_event,
269};
270
271struct msm_adsp_ops aud_rec_adsp_ops = {
272 .event = audrec_dsp_event,
273};
274
275int alsa_adsp_configure(struct msm_audio *prtd)
276{
277 int ret, i;
278
279 if (prtd->dir == SNDRV_PCM_STREAM_PLAYBACK) {
280 prtd->data = prtd->playback_substream->dma_buffer.area;
281 prtd->phys = prtd->playback_substream->dma_buffer.addr;
282 }
283 if (prtd->dir == SNDRV_PCM_STREAM_CAPTURE) {
284 prtd->data = prtd->capture_substream->dma_buffer.area;
285 prtd->phys = prtd->capture_substream->dma_buffer.addr;
286 }
287 if (!prtd->data) {
288 ret = -ENOMEM;
289 goto err1;
290 }
291
292 ret = audmgr_open(&prtd->audmgr);
293 if (ret)
294 goto err2;
295 if (prtd->dir == SNDRV_PCM_STREAM_PLAYBACK) {
296 prtd->out_buffer_size = PLAYBACK_DMASZ;
297 prtd->out_sample_rate = 44100;
298 prtd->out_channel_mode = AUDPP_CMD_PCM_INTF_STEREO_V;
299 prtd->out_weight = 100;
300
301 prtd->out[0].data = prtd->data + 0;
302 prtd->out[0].addr = prtd->phys + 0;
303 prtd->out[0].size = BUFSZ;
304 prtd->out[1].data = prtd->data + BUFSZ;
305 prtd->out[1].addr = prtd->phys + BUFSZ;
306 prtd->out[1].size = BUFSZ;
307 }
308 if (prtd->dir == SNDRV_PCM_STREAM_CAPTURE) {
309 prtd->samp_rate = RPC_AUD_DEF_SAMPLE_RATE_44100;
310 prtd->samp_rate_index = AUDREC_CMD_SAMP_RATE_INDX_44100;
311 prtd->channel_mode = AUDREC_CMD_STEREO_MODE_STEREO;
312 prtd->buffer_size = STEREO_DATA_SIZE;
313 prtd->type = AUDREC_CMD_TYPE_0_INDEX_WAV;
314 prtd->tx_agc_cfg.cmd_id = AUDPREPROC_CMD_CFG_AGC_PARAMS;
315 prtd->ns_cfg.cmd_id = AUDPREPROC_CMD_CFG_NS_PARAMS;
316 prtd->iir_cfg.cmd_id =
317 AUDPREPROC_CMD_CFG_IIR_TUNING_FILTER_PARAMS;
318
319 ret = msm_adsp_get("AUDPREPROCTASK",
320 &prtd->audpre, &aud_pre_adsp_ops, prtd);
321 if (ret)
322 goto err3;
323 ret = msm_adsp_get("AUDRECTASK",
324 &prtd->audrec, &aud_rec_adsp_ops, prtd);
325 if (ret) {
326 msm_adsp_put(prtd->audpre);
327 goto err3;
328 }
329 prtd->dsp_cnt = 0;
330 prtd->in_head = 0;
331 prtd->in_tail = 0;
332 prtd->in_count = 0;
333 for (i = 0; i < FRAME_NUM; i++) {
334 prtd->in[i].size = 0;
335 prtd->in[i].read = 0;
336 }
337 }
338
339 return 0;
340
341err3:
342 audmgr_close(&prtd->audmgr);
343
344err2:
345 prtd->data = NULL;
346err1:
347 return ret;
348}
349EXPORT_SYMBOL(alsa_adsp_configure);
350
351int alsa_audio_configure(struct msm_audio *prtd)
352{
353 struct audmgr_config cfg;
354 int rc;
355
356 if (prtd->enabled)
357 return 0;
358
359 /* refuse to start if we're not ready with first buffer */
360 if (!prtd->out[0].used)
361 return -EIO;
362
363 cfg.tx_rate = 0;
364 cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_48000;
365 cfg.def_method = RPC_AUD_DEF_METHOD_HOST_PCM;
366 cfg.codec = RPC_AUD_DEF_CODEC_PCM;
367 cfg.snd_method = RPC_SND_METHOD_MIDI;
368 rc = audmgr_enable(&prtd->audmgr, &cfg);
369 if (rc < 0)
370 return rc;
371
372 if (audpp_enable(AUDPP_ALSA_DECODER, alsa_dsp_event, prtd)) {
373 printk(KERN_ERR "audio: audpp_enable() failed\n");
374 audmgr_disable(&prtd->audmgr);
375 return -ENODEV;
376 }
377
378 prtd->enabled = 1;
379 return 0;
380}
381EXPORT_SYMBOL(alsa_audio_configure);
382
383ssize_t alsa_send_buffer(struct msm_audio *prtd, const char __user *buf,
384 size_t count, loff_t *pos)
385{
386 unsigned long flag;
387 const char __user *start = buf;
388 struct buffer *frame;
389 size_t xfer;
390 int rc = 0;
391
392 mutex_lock(&the_locks.write_lock);
393 while (count > 0) {
394 frame = prtd->out + prtd->out_head;
395 rc = wait_event_interruptible(the_locks.write_wait,
396 (frame->used == 0)
397 || (prtd->stopped));
398 if (rc < 0)
399 break;
400 if (prtd->stopped) {
401 rc = -EBUSY;
402 break;
403 }
404 xfer = count > frame->size ? frame->size : count;
405 if (copy_from_user(frame->data, buf, xfer)) {
406 rc = -EFAULT;
407 break;
408 }
409 frame->used = xfer;
410 prtd->out_head ^= 1;
411 count -= xfer;
412 buf += xfer;
413
414 spin_lock_irqsave(&the_locks.write_dsp_lock, flag);
415 frame = prtd->out + prtd->out_tail;
416 if (frame->used && prtd->out_needed) {
417 audio_dsp_send_buffer(prtd, prtd->out_tail,
418 frame->used);
419 prtd->out_tail ^= 1;
420 prtd->out_needed--;
421 }
422 spin_unlock_irqrestore(&the_locks.write_dsp_lock, flag);
423 }
424 mutex_unlock(&the_locks.write_lock);
425 if (buf > start)
426 return buf - start;
427 return rc;
428}
429EXPORT_SYMBOL(alsa_send_buffer);
430
431int alsa_audio_disable(struct msm_audio *prtd)
432{
433 if (prtd->enabled) {
434 mutex_lock(&the_locks.lock);
435 prtd->enabled = 0;
436 audio_dsp_out_enable(prtd, 0);
437 wake_up(&the_locks.write_wait);
438 audpp_disable(AUDPP_ALSA_DECODER, prtd);
439 audmgr_disable(&prtd->audmgr);
440 prtd->out_needed = 0;
441 mutex_unlock(&the_locks.lock);
442 }
443 return 0;
444}
445EXPORT_SYMBOL(alsa_audio_disable);
446
447int alsa_audrec_disable(struct msm_audio *prtd)
448{
449 if (prtd->enabled) {
450 mutex_lock(&the_locks.lock);
451 prtd->enabled = 0;
452 alsa_rec_dsp_enable(prtd, 0);
453 wake_up(&the_locks.read_wait);
454 msm_adsp_disable(prtd->audpre);
455 msm_adsp_disable(prtd->audrec);
456 audmgr_disable(&prtd->audmgr);
457 prtd->out_needed = 0;
458 prtd->opened = 0;
459 mutex_unlock(&the_locks.lock);
460 }
461 return 0;
462}
463EXPORT_SYMBOL(alsa_audrec_disable);
464
465static int audio_dsp_read_buffer(struct msm_audio *prtd, uint32_t read_cnt)
466{
467 audrec_cmd_packet_ext_ptr cmd;
468
469 memset(&cmd, 0, sizeof(cmd));
470 cmd.cmd_id = AUDREC_CMD_PACKET_EXT_PTR;
471 /* Both WAV and AAC use AUDREC_CMD_TYPE_0 */
472 cmd.type = AUDREC_CMD_TYPE_0;
473 cmd.curr_rec_count_msw = read_cnt >> 16;
474 cmd.curr_rec_count_lsw = read_cnt;
475
476 return audio_send_queue_recbs(prtd, &cmd, sizeof(cmd));
477}
478
479int audrec_encoder_config(struct msm_audio *prtd)
480{
481 audrec_cmd_arec0param_cfg cmd;
482 uint16_t *data = (void *)prtd->data;
483 unsigned n;
484
485 memset(&cmd, 0, sizeof(cmd));
486 cmd.cmd_id = AUDREC_CMD_AREC0PARAM_CFG;
487 cmd.ptr_to_extpkt_buffer_msw = prtd->phys >> 16;
488 cmd.ptr_to_extpkt_buffer_lsw = prtd->phys;
489 cmd.buf_len = FRAME_NUM; /* Both WAV and AAC use 8 frames */
490 cmd.samp_rate_index = prtd->samp_rate_index;
491 /* 0 for mono, 1 for stereo */
492 cmd.stereo_mode = prtd->channel_mode;
493 cmd.rec_quality = 0x1C00;
494
495 /* prepare buffer pointers:
496 * Mono: 1024 samples + 4 halfword header
497 * Stereo: 2048 samples + 4 halfword header
498 */
499
500 for (n = 0; n < FRAME_NUM; n++) {
501 prtd->in[n].data = data + 4;
502 data += (4 + (prtd->channel_mode ? 2048 : 1024));
503 }
504
505 return audio_send_queue_rec(prtd, &cmd, sizeof(cmd));
506}
507
508int audio_dsp_out_enable(struct msm_audio *prtd, int yes)
509{
510 audpp_cmd_pcm_intf cmd;
511 memset(&cmd, 0, sizeof(cmd));
512 cmd.cmd_id = AUDPP_CMD_PCM_INTF_2;
513 cmd.object_num = AUDPP_CMD_PCM_INTF_OBJECT_NUM;
514 cmd.config = AUDPP_CMD_PCM_INTF_CONFIG_CMD_V;
515 cmd.intf_type = AUDPP_CMD_PCM_INTF_RX_ENA_ARMTODSP_V;
516
517 if (yes) {
518 cmd.write_buf1LSW = prtd->out[0].addr;
519 cmd.write_buf1MSW = prtd->out[0].addr >> 16;
520 cmd.write_buf1_len = 0;
521 cmd.write_buf2LSW = prtd->out[1].addr;
522 cmd.write_buf2MSW = prtd->out[1].addr >> 16;
523 cmd.write_buf2_len = prtd->out[1].used;
524 cmd.arm_to_rx_flag = AUDPP_CMD_PCM_INTF_ENA_V;
525 cmd.weight_decoder_to_rx = prtd->out_weight;
526 cmd.weight_arm_to_rx = 1;
527 cmd.partition_number_arm_to_dsp = 0;
528 cmd.sample_rate = prtd->out_sample_rate;
529 cmd.channel_mode = prtd->out_channel_mode;
530 }
531 return audpp_send_queue2(&cmd, sizeof(cmd));
532}
533
534int alsa_buffer_read(struct msm_audio *prtd, void __user *buf,
535 size_t count, loff_t *pos)
536{
537 unsigned long flag;
538 void *data;
539 uint32_t index;
540 uint32_t size;
541 int rc = 0;
542
543 mutex_lock(&the_locks.read_lock);
544 while (count > 0) {
545 rc = wait_event_interruptible(the_locks.read_wait,
546 (prtd->in_count > 0)
547 || prtd->stopped);
548 if (rc < 0)
549 break;
550
551 if (prtd->stopped) {
552 rc = -EBUSY;
553 break;
554 }
555
556 index = prtd->in_tail;
557 data = (uint8_t *) prtd->in[index].data;
558 size = prtd->in[index].size;
559 if (count >= size) {
560 if (copy_to_user(buf, data, size)) {
561 rc = -EFAULT;
562 break;
563 }
564 spin_lock_irqsave(&the_locks.read_dsp_lock, flag);
565 if (index != prtd->in_tail) {
566 /* overrun: data is invalid, we need to retry */
567 spin_unlock_irqrestore(&the_locks.read_dsp_lock,
568 flag);
569 continue;
570 }
571 prtd->in[index].size = 0;
572 prtd->in_tail = (prtd->in_tail + 1) & (FRAME_NUM - 1);
573 prtd->in_count--;
574 spin_unlock_irqrestore(&the_locks.read_dsp_lock, flag);
575 count -= size;
576 buf += size;
577 } else {
578 break;
579 }
580 }
581 mutex_unlock(&the_locks.read_lock);
582 return rc;
583}
584EXPORT_SYMBOL(alsa_buffer_read);
585
586static int audio_dsp_send_buffer(struct msm_audio *prtd,
587 unsigned idx, unsigned len)
588{
589 audpp_cmd_pcm_intf_send_buffer cmd;
590 cmd.cmd_id = AUDPP_CMD_PCM_INTF_2;
591 cmd.host_pcm_object = AUDPP_CMD_PCM_INTF_OBJECT_NUM;
592 cmd.config = AUDPP_CMD_PCM_INTF_BUFFER_CMD_V;
593 cmd.intf_type = AUDPP_CMD_PCM_INTF_RX_ENA_ARMTODSP_V;
594 cmd.dsp_to_arm_buf_id = 0;
595 cmd.arm_to_dsp_buf_id = idx + 1;
596 cmd.arm_to_dsp_buf_len = len;
597 return audpp_send_queue2(&cmd, sizeof(cmd));
598}
599
600int alsa_rec_dsp_enable(struct msm_audio *prtd, int enable)
601{
602 audrec_cmd_cfg cmd;
603
604 memset(&cmd, 0, sizeof(cmd));
605 cmd.cmd_id = AUDREC_CMD_CFG;
606 cmd.type_0 = enable ? AUDREC_CMD_TYPE_0_ENA : AUDREC_CMD_TYPE_0_DIS;
607 cmd.type_0 |= (AUDREC_CMD_TYPE_0_UPDATE | prtd->type);
608 cmd.type_1 = 0;
609
610 return audio_send_queue_rec(prtd, &cmd, sizeof(cmd));
611}
612EXPORT_SYMBOL(alsa_rec_dsp_enable);
613
614void alsa_get_dsp_frames(struct msm_audio *prtd)
615{
616 struct audio_frame *frame;
617 uint32_t index = 0;
618 unsigned long flag;
619
620 if (prtd->type == AUDREC_CMD_TYPE_0_INDEX_WAV) {
621 index = prtd->in_head;
622
623 frame =
624 (void *)(((char *)prtd->in[index].data) - sizeof(*frame));
625
626 spin_lock_irqsave(&the_locks.read_dsp_lock, flag);
627 prtd->in[index].size = frame->bytes;
628
629 prtd->in_head = (prtd->in_head + 1) & (FRAME_NUM - 1);
630
631 /* If overflow, move the tail index foward. */
632 if (prtd->in_head == prtd->in_tail)
633 prtd->in_tail = (prtd->in_tail + 1) & (FRAME_NUM - 1);
634 else
635 prtd->in_count++;
636
637 audio_dsp_read_buffer(prtd, prtd->dsp_cnt++);
638 spin_unlock_irqrestore(&the_locks.read_dsp_lock, flag);
639
640 wake_up(&the_locks.read_wait);
641 } else {
642 /* TODO AAC not supported yet. */
643 }
644}
645EXPORT_SYMBOL(alsa_get_dsp_frames);