sound: soc: msm: msm8k-android-dsp: ?
[htc-msm-2-6-32:leviathan-incoming.git] / sound / soc / msm / msm8k-android-dsp.c
1 /* arch/arm/mach-msm/qdsp6/pcm_out.c
2  *
3  * Copyright (C) 2009 Google, Inc.
4  * Author: Brian Swetland <swetland@google.com>
5  *
6  * This software is licensed under the terms of the GNU General Public
7  * License version 2, as published by the Free Software Foundation, and
8  * may be copied, distributed, and modified under those terms.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  */
16
17 #include <linux/fs.h>
18 #include <linux/module.h>
19 #include <linux/miscdevice.h>
20 #include <linux/mutex.h>
21 #include <linux/sched.h>
22 #include <linux/slab.h>
23 #include <linux/wait.h>
24 #include <linux/uaccess.h>
25 #include <sound/pcm.h>
26
27 #include <linux/msm_audio.h>
28 #include <mach/msm_qdsp6_audio.h>
29 #include "msm8k-android-pcm.h"
30
31 /* /\* routing*\/ */
32 /* #define ADSP_AUDIO_DEVICE_ID_HEADSET_SPKR_STEREO                0x107ac8a */
33 #define ACDB_ID_SPKR_PLAYBACK 5
34 /* #define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO                    0x1081513 */
35
36 struct pcm {
37         struct mutex lock;
38         struct audio_client *ac;
39         uint32_t sample_rate;
40         uint32_t channel_count;
41         size_t buffer_size;
42 };
43
44
45 int alsa_init(struct snd_pcm_substream *substream){
46         struct snd_pcm_runtime *runtime = substream->runtime;
47
48         runtime->channels = 2;
49         runtime->rate = 44100;
50         runtime->buffer_size = BUFSZ;
51
52 }
53 EXPORT_SYMBOL(alsa_init);
54
55 int alsa_audio_configure(struct snd_pcm_substream *substream)
56 {
57         struct snd_pcm_runtime *runtime = substream->runtime;
58         struct audio_client *ac;
59         struct pcm *pcm;
60
61
62
63         pr_info("pcm_out: open\n");
64         pcm = kzalloc(sizeof(struct pcm), GFP_KERNEL);
65
66         if (!pcm)
67                 return -ENOMEM;
68
69 //      mutex_init(&pcm->lock);
70         pcm->channel_count = 2;  //runtime->channels; //was 2
71         pcm->sample_rate = 44100;  //runtime->rate; //was 44100
72         pcm->buffer_size = BUFSZ;  //runtime->buffer_size; //was BUFSZ
73         runtime->private_data = pcm;
74
75
76         printk("msm8k-android-dsp|1|channels:%d|sample_rate:%d|buffer_size:%lu\n",
77                runtime->channels,runtime->rate,runtime->buffer_size);
78
79
80
81
82         printk("msm8k-android-dsp|2|channels:%d|sample_rate:%d|buffer_size:%lu\n",
83                runtime->channels,runtime->rate,runtime->buffer_size);
84         if (pcm->ac){
85                 printk("busy\n");
86                 return -EBUSY;
87         }
88         else{
89                 //      do_rx_routing(ADSP_AUDIO_DEVICE_ID_HEADSET_SPKR_STEREO,607);
90                 pcm->ac = q6audio_open_pcm(pcm->buffer_size,
91                                            pcm->sample_rate,
92                                            pcm->channel_count
93                                            ,AUDIO_FLAG_WRITE,ACDB_ID_SPKR_PLAYBACK);
94                         if (!pcm->ac)
95                                 return -ENOMEM;
96         }
97         ac = pcm->ac;
98         return 0;
99 }
100 EXPORT_SYMBOL(alsa_audio_configure);
101
102
103 ssize_t alsa_send_buffer(struct snd_pcm_substream *substream, const char __user *buf,
104                            size_t count, size_t *pos)
105 {
106
107         struct snd_pcm_runtime *runtime = substream->runtime;
108         struct pcm *pcm = runtime->private_data;
109
110         struct audio_client *ac;
111         struct audio_buffer *ab;
112         const char __user *start = buf;
113         int xfer;
114
115         ac = pcm->ac;
116
117
118
119         while (count > 0) {
120                 printk("count1 %u\n",count);
121                 ab = ac->buf + ac->cpu_buf;
122
123                 if (ab->used)
124                         if (!wait_event_timeout(ac->wait, (ab->used == 0), 5*HZ)) {
125                                 audio_client_dump(ac);
126                                 pr_err("pcm_write: timeout. dsp dead?\n");
127                                 q6audio_dsp_not_responding();
128                         }
129                 xfer = count;
130                 *pos += xfer;
131                 if (xfer > ab->size)
132                         xfer = ab->size;
133                 if (copy_from_user(ab->data, buf, xfer)) 
134                         return -EFAULT;
135
136                 buf += xfer;
137                 /* pos = buf - start; */
138                 count -= xfer;
139                 printk("count2 %u\n",count);
140
141
142                 ab->used = xfer;
143                 q6audio_write(ac, ab);
144                 ac->cpu_buf ^= 1;
145
146         }
147         /* pos = buf - start; */
148         return buf - start;
149 }
150 EXPORT_SYMBOL(alsa_send_buffer);
151
152 int alsa_audio_disable(struct snd_pcm_substream *substream)
153 {
154         struct snd_pcm_runtime *runtime = substream->runtime;
155
156         struct pcm *pcm = runtime->private_data;
157         if (pcm->ac)
158                 q6audio_close(pcm->ac);
159         kfree(pcm);
160         pr_info("pcm_out: release\n");
161         return 0;
162 }
163 EXPORT_SYMBOL(alsa_audio_disable);