blob: ece44fdc5daffdf4a69206ad5f87d724fa5ef832 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12*/
13
14#include <linux/module.h>
15#include <linux/fs.h>
16#include <linux/miscdevice.h>
17#include <linux/uaccess.h>
18#include <linux/sched.h>
19#include <linux/slab.h>
20#include <linux/wait.h>
21#include <linux/dma-mapping.h>
22#include <linux/msm_audio_amrnb.h>
23#include <asm/atomic.h>
24#include <asm/ioctls.h>
25#include <sound/q6asm.h>
26#include <sound/apr_audio.h>
27#include "audio_utils.h"
28
29/* Buffer with meta*/
30#define PCM_BUF_SIZE (4096 + sizeof(struct meta_in))
31
32/* Maximum 10 frames in buffer with meta */
33#define FRAME_SIZE (1 + ((32+sizeof(struct meta_out_dsp)) * 10))
34
35void q6asm_amrnb_in_cb(uint32_t opcode, uint32_t token,
36 uint32_t *payload, void *priv)
37{
38 struct q6audio_in * audio = (struct q6audio_in *)priv;
39 unsigned long flags;
40
41 pr_debug("%s:session id %d: opcode - %d\n", __func__,
42 audio->ac->session, opcode);
43
44 spin_lock_irqsave(&audio->dsp_lock, flags);
45 switch (opcode) {
46 case ASM_DATA_EVENT_READ_DONE:
47 audio_in_get_dsp_frames(audio, token, payload);
48 break;
49 case ASM_DATA_EVENT_WRITE_DONE:
50 atomic_inc(&audio->in_count);
51 wake_up(&audio->write_wait);
52 break;
53 case ASM_DATA_CMDRSP_EOS:
54 audio->eos_rsp = 1;
55 wake_up(&audio->read_wait);
56 break;
57 case ASM_STREAM_CMDRSP_GET_ENCDEC_PARAM:
58 break;
59 case ASM_STREAM_CMDRSP_GET_PP_PARAMS:
60 break;
61 case ASM_SESSION_EVENT_TX_OVERFLOW:
62 pr_err("%s:session id %d: ASM_SESSION_EVENT_TX_OVERFLOW\n",
63 __func__, audio->ac->session);
64 break;
65 default:
66 pr_err("%s:session id %d: Ignore opcode[0x%x]\n", __func__,
67 audio->ac->session, opcode);
68 break;
69 }
70 spin_unlock_irqrestore(&audio->dsp_lock, flags);
71}
72
73/* ------------------- device --------------------- */
74static long amrnb_in_ioctl(struct file *file,
75 unsigned int cmd, unsigned long arg)
76{
77 struct q6audio_in *audio = file->private_data;
78 int rc = 0;
79 int cnt = 0;
80
81 switch (cmd) {
82 case AUDIO_START: {
83 struct msm_audio_amrnb_enc_config_v2 *enc_cfg;
84 enc_cfg = audio->enc_cfg;
85 pr_debug("%s:session id %d: default buf alloc[%d]\n", __func__,
86 audio->ac->session, audio->buf_alloc);
87 if (audio->enabled == 1) {
88 pr_info("%s:AUDIO_START already over\n", __func__);
89 rc = 0;
90 break;
91 }
92 rc = audio_in_buf_alloc(audio);
93 if (rc < 0) {
94 pr_err("%s:session id %d: buffer allocation failed\n",
95 __func__, audio->ac->session);
96 break;
97 }
98
99 rc = q6asm_enc_cfg_blk_amrnb(audio->ac,
100 audio->buf_cfg.frames_per_buf,
101 enc_cfg->band_mode,
102 enc_cfg->dtx_enable);
103
104 if (rc < 0) {
105 pr_err("%s:session id %d: cmd amrnb media format block\
106 failed\n", __func__, audio->ac->session);
107 break;
108 }
109 if (audio->feedback == NON_TUNNEL_MODE) {
110 rc = q6asm_media_format_block_pcm(audio->ac,
111 audio->pcm_cfg.sample_rate,
112 audio->pcm_cfg.channel_count);
113
114 if (rc < 0) {
115 pr_err("%s:session id %d: media format block\
116 failed\n", __func__, audio->ac->session);
117 break;
118 }
119 }
120 pr_debug("%s:session id %d: AUDIO_START enable[%d]\n",
121 __func__, audio->ac->session,
122 audio->enabled);
123 rc = audio_in_enable(audio);
124 if (!rc) {
125 audio->enabled = 1;
126 } else {
127 audio->enabled = 0;
128 pr_err("%s:session id %d: Audio Start procedure failed\
129 rc=%d\n", __func__,
130 audio->ac->session, rc);
131 break;
132 }
133 while (cnt++ < audio->str_cfg.buffer_count)
134 q6asm_read(audio->ac); /* Push buffer to DSP */
135 rc = 0;
136 pr_debug("%s:session id %d: AUDIO_START success enable[%d]\n",
137 __func__, audio->ac->session, audio->enabled);
138 break;
139 }
140 case AUDIO_STOP: {
141 pr_debug("%s:AUDIO_STOP\n", __func__);
142 rc = audio_in_disable(audio);
143 if (rc < 0) {
144 pr_err("%s:session id %d: Audio Stop procedure failed\
145 rc=%d\n", __func__,
146 audio->ac->session, rc);
147 break;
148 }
149 break;
150 }
151 case AUDIO_GET_AMRNB_ENC_CONFIG_V2: {
152 if (copy_to_user((void *)arg, audio->enc_cfg,
153 sizeof(struct msm_audio_amrnb_enc_config_v2)))
154 rc = -EFAULT;
155 break;
156 }
157 case AUDIO_SET_AMRNB_ENC_CONFIG_V2: {
158 struct msm_audio_amrnb_enc_config_v2 cfg;
159 struct msm_audio_amrnb_enc_config_v2 *enc_cfg;
160 enc_cfg = audio->enc_cfg;
161 if (copy_from_user(&cfg, (void *) arg,
162 sizeof(struct msm_audio_amrnb_enc_config_v2))) {
163 rc = -EFAULT;
164 break;
165 }
166 if (cfg.band_mode > 8 ||
167 cfg.band_mode < 1) {
168 pr_err("%s:session id %d: invalid band mode\n",
169 __func__, audio->ac->session);
170 rc = -EINVAL;
171 break;
172 }
173 /* AMR NB encoder accepts values between 0-7
174 while openmax provides value between 1-8
175 as per spec */
176 enc_cfg->band_mode = (cfg.band_mode - 1);
177 enc_cfg->dtx_enable = (cfg.dtx_enable ? 1 : 0);
178 enc_cfg->frame_format = 0;
179 pr_debug("%s:session id %d: band_mode = 0x%x dtx_enable=0x%x\n",
180 __func__, audio->ac->session,
181 enc_cfg->band_mode, enc_cfg->dtx_enable);
182 break;
183 }
184 default:
185 rc = -EINVAL;
186 }
187 return rc;
188}
189
190static int amrnb_in_open(struct inode *inode, struct file *file)
191{
192 struct q6audio_in *audio = NULL;
193 struct msm_audio_amrnb_enc_config_v2 *enc_cfg;
194 int rc = 0;
195
196 audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL);
197
198 if (audio == NULL) {
199 pr_err("%s:session id %d: Could not allocate memory for amrnb\
200 driver\n", __func__, audio->ac->session);
201 return -ENOMEM;
202 }
203 /* Allocate memory for encoder config param */
204 audio->enc_cfg = kzalloc(sizeof(struct msm_audio_amrnb_enc_config_v2),
205 GFP_KERNEL);
206 if (audio->enc_cfg == NULL) {
207 pr_err("%s:session id %d: Could not allocate memory for aac\
208 config param\n", __func__, audio->ac->session);
209 kfree(audio);
210 return -ENOMEM;
211 }
212 enc_cfg = audio->enc_cfg;
213
214 mutex_init(&audio->lock);
215 mutex_init(&audio->read_lock);
216 mutex_init(&audio->write_lock);
217 spin_lock_init(&audio->dsp_lock);
218 init_waitqueue_head(&audio->read_wait);
219 init_waitqueue_head(&audio->write_wait);
220
221 /* Settings will be re-config at AUDIO_SET_CONFIG,
222 * but at least we need to have initial config
223 */
224 audio->str_cfg.buffer_size = FRAME_SIZE;
225 audio->str_cfg.buffer_count = FRAME_NUM;
226 audio->min_frame_size = 32;
227 audio->max_frames_per_buf = 10;
228 audio->pcm_cfg.buffer_size = PCM_BUF_SIZE;
229 audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
230 enc_cfg->band_mode = 7;
231 enc_cfg->dtx_enable = 0;
232 audio->pcm_cfg.channel_count = 1;
233 audio->pcm_cfg.sample_rate = 8000;
234 audio->buf_cfg.meta_info_enable = 0x01;
235 audio->buf_cfg.frames_per_buf = 0x01;
236
237 audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_amrnb_in_cb,
238 (void *)audio);
239
240 if (!audio->ac) {
241 pr_err("%s:session id %d: Could not allocate memory for audio\
242 client\n", __func__, audio->ac->session);
243 kfree(audio->enc_cfg);
244 kfree(audio);
245 return -ENOMEM;
246 }
247
248 /* open amrnb encoder in T/NT mode */
249 if ((file->f_mode & FMODE_WRITE) &&
250 (file->f_mode & FMODE_READ)) {
251 audio->feedback = NON_TUNNEL_MODE;
252 rc = q6asm_open_read_write(audio->ac, FORMAT_AMRNB,
253 FORMAT_LINEAR_PCM);
254 if (rc < 0) {
255 pr_err("%s:session id %d: NT mode Open failed rc=%d\n",
256 __func__, audio->ac->session, rc);
257 rc = -ENODEV;
258 goto fail;
259 }
260 pr_info("%s:session id %d: NT mode encoder success\n",
261 __func__, audio->ac->session);
262 } else if (!(file->f_mode & FMODE_WRITE) &&
263 (file->f_mode & FMODE_READ)) {
264 audio->feedback = TUNNEL_MODE;
265 rc = q6asm_open_read(audio->ac, FORMAT_AMRNB);
266 if (rc < 0) {
267 pr_err("%s:session id %d: T mode Open failed rc=%d\n",
268 __func__, audio->ac->session, rc);
269 rc = -ENODEV;
270 goto fail;
271 }
272 /* register for tx overflow (valid for tunnel mode only) */
273 rc = q6asm_reg_tx_overflow(audio->ac, 0x01);
274 if (rc < 0) {
275 pr_err("%s:session id %d: TX Overflow registration\
276 failed rc=%d\n", __func__, audio->ac->session,
277 rc);
278 rc = -ENODEV;
279 goto fail;
280 }
281 pr_info("%s:session id %d: T mode encoder success\n",
282 __func__, audio->ac->session);
283 } else {
284 pr_err("%s:session id %d: Unexpected mode\n", __func__,
285 audio->ac->session);
286 rc = -EACCES;
287 goto fail;
288 }
289
290 audio->opened = 1;
291 atomic_set(&audio->in_count, PCM_BUF_COUNT);
292 atomic_set(&audio->out_count, 0x00);
293 audio->enc_ioctl = amrnb_in_ioctl;
294 file->private_data = audio;
295
296 pr_info("%s:session id %d: success\n", __func__, audio->ac->session);
297 return 0;
298fail:
299 q6asm_audio_client_free(audio->ac);
300 kfree(audio->enc_cfg);
301 kfree(audio);
302 return rc;
303}
304
305static const struct file_operations audio_in_fops = {
306 .owner = THIS_MODULE,
307 .open = amrnb_in_open,
308 .release = audio_in_release,
309 .read = audio_in_read,
310 .write = audio_in_write,
311 .unlocked_ioctl = audio_in_ioctl,
312};
313
314struct miscdevice audio_amrnb_in_misc = {
315 .minor = MISC_DYNAMIC_MINOR,
316 .name = "msm_amrnb_in",
317 .fops = &audio_in_fops,
318};
319
320static int __init amrnb_in_init(void)
321{
322 return misc_register(&audio_amrnb_in_misc);
323}
324
325device_initcall(amrnb_in_init);