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