blob: ce9dc45c1d9651629d3328be5e2b1b43e4999229 [file] [log] [blame]
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301/*
2 * Copyright (c) 2011-2012, 2014, 2016-2017 The Linux Foundation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/dma-mapping.h>
15#include <linux/fs.h>
16#include <linux/module.h>
17#include <linux/miscdevice.h>
18#include <linux/msm_audio_amrwb.h>
19#include <linux/sched.h>
20#include <linux/slab.h>
21#include <linux/uaccess.h>
22#include <linux/wait.h>
23#include <linux/compat.h>
24#include <linux/atomic.h>
25#include <asm/ioctls.h>
26#include "audio_utils.h"
27
28/* Buffer with meta*/
29#define PCM_BUF_SIZE (4096 + sizeof(struct meta_in))
30
31/* Maximum 10 frames in buffer with meta */
32#define FRAME_SIZE (1 + ((61+sizeof(struct meta_out_dsp)) * 10))
33
34static long amrwb_in_ioctl_shared(struct file *file,
35 unsigned int cmd, void *arg)
36{
37 struct q6audio_in *audio = file->private_data;
38 int rc = 0;
39 int cnt = 0;
40
41 switch (cmd) {
42 case AUDIO_START: {
43 struct msm_audio_amrwb_enc_config *enc_cfg;
44
45 enc_cfg = audio->enc_cfg;
46 pr_debug("%s:session id %d: default buf alloc[%d]\n", __func__,
47 audio->ac->session, audio->buf_alloc);
48 if (audio->enabled == 1) {
49 pr_info("%s:AUDIO_START already over\n", __func__);
50 rc = 0;
51 break;
52 }
53 rc = audio_in_buf_alloc(audio);
54 if (rc < 0) {
55 pr_err("%s:session id %d: buffer allocation failed\n",
56 __func__, audio->ac->session);
57 break;
58 }
59
60 rc = q6asm_enc_cfg_blk_amrwb(audio->ac,
61 audio->buf_cfg.frames_per_buf,
62 enc_cfg->band_mode,
63 enc_cfg->dtx_enable);
64
65 if (rc < 0) {
66 pr_err("%s:session id %d: cmd amrwb media format block failed\n",
67 __func__, audio->ac->session);
68 break;
69 }
70 if (audio->feedback == NON_TUNNEL_MODE) {
71 rc = q6asm_media_format_block_pcm(audio->ac,
72 audio->pcm_cfg.sample_rate,
73 audio->pcm_cfg.channel_count);
74
75 if (rc < 0) {
76 pr_err("%s:session id %d: media format block failed\n",
77 __func__, audio->ac->session);
78 break;
79 }
80 }
81 pr_debug("%s:session id %d: AUDIO_START enable[%d]\n",
82 __func__, audio->ac->session,
83 audio->enabled);
84 rc = audio_in_enable(audio);
85 if (!rc) {
86 audio->enabled = 1;
87 } else {
88 audio->enabled = 0;
89 pr_err("%s:session id %d: Audio Start procedure failed rc=%d\n",
90 __func__, audio->ac->session, rc);
91 break;
92 }
93 while (cnt++ < audio->str_cfg.buffer_count)
94 q6asm_read(audio->ac); /* Push buffer to DSP */
95 rc = 0;
96 pr_debug("%s:session id %d: AUDIO_START success enable[%d]\n",
97 __func__, audio->ac->session, audio->enabled);
98 break;
99 }
100 case AUDIO_STOP: {
101 pr_debug("%s:AUDIO_STOP\n", __func__);
102 rc = audio_in_disable(audio);
103 if (rc < 0) {
104 pr_err("%s:session id %d: Audio Stop procedure failed rc=%d\n",
105 __func__, audio->ac->session, rc);
106 break;
107 }
108 break;
109 }
110 case AUDIO_SET_AMRWB_ENC_CONFIG: {
111 struct msm_audio_amrwb_enc_config *cfg;
112 struct msm_audio_amrwb_enc_config *enc_cfg;
113
114 enc_cfg = audio->enc_cfg;
115 cfg = (struct msm_audio_amrwb_enc_config *)arg;
116 if (cfg == NULL) {
117 pr_err("%s: NULL config pointer for %s\n",
118 __func__, "AUDIO_SET_AMRWB_ENC_CONFIG");
119 rc = -EINVAL;
120 break;
121 }
122
123 if (cfg->band_mode > 8) {
124 pr_err("%s:session id %d: invalid band mode\n",
125 __func__, audio->ac->session);
126 rc = -EINVAL;
127 break;
128 }
129 /* ToDo: AMR WB encoder accepts values between 0-8
130 * while openmax provides value between 9-17
131 * as per spec
132 */
133 enc_cfg->band_mode = cfg->band_mode;
134 enc_cfg->dtx_enable = (cfg->dtx_enable ? 1 : 0);
135 /* Currently DSP does not support different frameformat */
136 enc_cfg->frame_format = 0;
137 pr_debug("%s:session id %d: band_mode = 0x%x dtx_enable=0x%x\n",
138 __func__, audio->ac->session,
139 enc_cfg->band_mode, enc_cfg->dtx_enable);
140 break;
141 }
142 default:
143 pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
144 rc = -EINVAL;
145 }
146 return rc;
147}
148
149static long amrwb_in_ioctl(struct file *file,
150 unsigned int cmd, unsigned long arg)
151{
152 struct q6audio_in *audio = file->private_data;
153 int rc = 0;
154
155 switch (cmd) {
156 case AUDIO_START:
157 case AUDIO_STOP: {
158 rc = amrwb_in_ioctl_shared(file, cmd, NULL);
159 break;
160 }
161 case AUDIO_GET_AMRWB_ENC_CONFIG: {
162 if (copy_to_user((void *)arg, audio->enc_cfg,
163 sizeof(struct msm_audio_amrwb_enc_config)))
164 pr_err("%s: copy_to_user for AUDIO_GET_AMRWB_ENC_CONFIG failed\n",
165 __func__);
166 rc = -EFAULT;
167 break;
168 }
169 case AUDIO_SET_AMRWB_ENC_CONFIG: {
170 struct msm_audio_amrwb_enc_config cfg;
171
172 if (copy_from_user(&cfg, (void *) arg,
173 sizeof(cfg))) {
174 pr_err("%s: copy_from_user for AUDIO_SET_AMRWB_ENC_CONFIG failed\n",
175 __func__);
176 rc = -EFAULT;
177 break;
178 }
179 rc = amrwb_in_ioctl_shared(file, cmd, &cfg);
180 if (rc)
181 pr_err("%s:AUDIO_SET_AAC_ENC_CONFIG failed. rc=%d\n",
182 __func__, rc);
183 break;
184 }
185 default:
186 pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
187 rc = -EINVAL;
188 }
189 return rc;
190}
191
192#ifdef CONFIG_COMPAT
193struct msm_audio_amrwb_enc_config_32 {
194 u32 band_mode;
195 u32 dtx_enable;
196 u32 frame_format;
197};
198
199enum {
200 AUDIO_GET_AMRWB_ENC_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC,
201 (AUDIO_MAX_COMMON_IOCTL_NUM+0),
202 struct msm_audio_amrwb_enc_config_32),
203 AUDIO_SET_AMRWB_ENC_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC,
204 (AUDIO_MAX_COMMON_IOCTL_NUM+1),
205 struct msm_audio_amrwb_enc_config_32)
206};
207
208static long amrwb_in_compat_ioctl(struct file *file,
209 unsigned int cmd, unsigned long arg)
210{
211 struct q6audio_in *audio = file->private_data;
212 int rc = 0;
213
214 switch (cmd) {
215 case AUDIO_START:
216 case AUDIO_STOP: {
217 rc = amrwb_in_ioctl_shared(file, cmd, NULL);
218 break;
219 }
220 case AUDIO_GET_AMRWB_ENC_CONFIG_32: {
221 struct msm_audio_amrwb_enc_config *amrwb_config;
222 struct msm_audio_amrwb_enc_config_32 amrwb_config_32;
223
224 memset(&amrwb_config_32, 0, sizeof(amrwb_config_32));
225
226 amrwb_config =
227 (struct msm_audio_amrwb_enc_config *)audio->enc_cfg;
228 amrwb_config_32.band_mode = amrwb_config->band_mode;
229 amrwb_config_32.dtx_enable = amrwb_config->dtx_enable;
230 amrwb_config_32.frame_format = amrwb_config->frame_format;
231
232 if (copy_to_user((void *)arg, &amrwb_config_32,
233 sizeof(struct msm_audio_amrwb_enc_config_32))) {
234 pr_err("%s: copy_to_user for AUDIO_GET_AMRWB_ENC_CONFIG_32 failed\n",
235 __func__);
236 rc = -EFAULT;
237 }
238 break;
239 }
240 case AUDIO_SET_AMRWB_ENC_CONFIG_32: {
241 struct msm_audio_amrwb_enc_config cfg_32;
242
243 if (copy_from_user(&cfg_32, (void *) arg,
244 sizeof(cfg_32))) {
245 pr_err("%s: copy_from_user for AUDIO_SET_AMRWB_ENC_CONFIG_32 failed\n",
246 __func__);
247 rc = -EFAULT;
248 break;
249 }
250 cmd = AUDIO_SET_AMRWB_ENC_CONFIG;
251 rc = amrwb_in_ioctl_shared(file, cmd, &cfg_32);
252 if (rc)
253 pr_err("%s:AUDIO_SET_AAC_ENC_CONFIG failed. rc=%d\n",
254 __func__, rc);
255 break;
256 }
257 default:
258 pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
259 rc = -EINVAL;
260 }
261 return rc;
262}
263#else
264#define amrwb_in_compat_ioctl NULL
265#endif
266
267static int amrwb_in_open(struct inode *inode, struct file *file)
268{
269 struct q6audio_in *audio = NULL;
270 struct msm_audio_amrwb_enc_config *enc_cfg;
271 int rc = 0;
272
273 audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL);
274
275 if (audio == NULL)
276 return -ENOMEM;
277
278 /* Allocate memory for encoder config param */
279 audio->enc_cfg = kzalloc(sizeof(struct msm_audio_amrwb_enc_config),
280 GFP_KERNEL);
281 if (audio->enc_cfg == NULL) {
282 kfree(audio);
283 return -ENOMEM;
284 }
285 enc_cfg = audio->enc_cfg;
286
287 mutex_init(&audio->lock);
288 mutex_init(&audio->read_lock);
289 mutex_init(&audio->write_lock);
290 spin_lock_init(&audio->dsp_lock);
291 init_waitqueue_head(&audio->read_wait);
292 init_waitqueue_head(&audio->write_wait);
293
294 /* Settings will be re-config at AUDIO_SET_CONFIG,
295 * but at least we need to have initial config
296 */
297 audio->str_cfg.buffer_size = FRAME_SIZE;
298 audio->str_cfg.buffer_count = FRAME_NUM;
299 audio->min_frame_size = 32;
300 audio->max_frames_per_buf = 10;
301 audio->pcm_cfg.buffer_size = PCM_BUF_SIZE;
302 audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
303 enc_cfg->band_mode = 8;
304 enc_cfg->dtx_enable = 0;
305 audio->pcm_cfg.channel_count = 1;
306 audio->pcm_cfg.sample_rate = 16000;
307 audio->buf_cfg.meta_info_enable = 0x01;
308 audio->buf_cfg.frames_per_buf = 0x01;
309
310 audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_in_cb,
311 (void *)audio);
312
313 if (!audio->ac) {
314 pr_err("%s:audio[%pK]: Could not allocate memory for audio client\n",
315 __func__, audio);
316 kfree(audio->enc_cfg);
317 kfree(audio);
318 return -ENOMEM;
319 }
320
321 /* open amrwb encoder in T/NT mode */
322 if ((file->f_mode & FMODE_WRITE) &&
323 (file->f_mode & FMODE_READ)) {
324 audio->feedback = NON_TUNNEL_MODE;
325 rc = q6asm_open_read_write(audio->ac, FORMAT_AMRWB,
326 FORMAT_LINEAR_PCM);
327 if (rc < 0) {
328 pr_err("%s:session id %d: NT mode Open failed rc=%d\n",
329 __func__, audio->ac->session, rc);
330 rc = -ENODEV;
331 goto fail;
332 }
333 pr_info("%s:session id %d: NT mode encoder success\n",
334 __func__, audio->ac->session);
335 } else if (!(file->f_mode & FMODE_WRITE) &&
336 (file->f_mode & FMODE_READ)) {
337 audio->feedback = TUNNEL_MODE;
338 rc = q6asm_open_read(audio->ac, FORMAT_AMRWB);
339 if (rc < 0) {
340 pr_err("%s:session id %d: T mode Open failed rc=%d\n",
341 __func__, audio->ac->session, rc);
342 rc = -ENODEV;
343 goto fail;
344 }
345 /* register for tx overflow (valid for tunnel mode only) */
346 rc = q6asm_reg_tx_overflow(audio->ac, 0x01);
347 if (rc < 0) {
348 pr_err("%s:session id %d: TX Overflow registration failed rc=%d\n",
349 __func__, audio->ac->session,
350 rc);
351 rc = -ENODEV;
352 goto fail;
353 }
354 pr_info("%s:session id %d: T mode encoder success\n",
355 __func__, audio->ac->session);
356 } else {
357 pr_err("%s:session id %d: Unexpected mode\n", __func__,
358 audio->ac->session);
359 rc = -EACCES;
360 goto fail;
361 }
362
363 audio->opened = 1;
364 atomic_set(&audio->in_count, PCM_BUF_COUNT);
365 atomic_set(&audio->out_count, 0x00);
366 audio->enc_compat_ioctl = amrwb_in_compat_ioctl;
367 audio->enc_ioctl = amrwb_in_ioctl;
368 file->private_data = audio;
369
370 pr_info("%s:session id %d: success\n", __func__, audio->ac->session);
371 return 0;
372fail:
373 q6asm_audio_client_free(audio->ac);
374 kfree(audio->enc_cfg);
375 kfree(audio);
376 return rc;
377}
378
379static const struct file_operations audio_in_fops = {
380 .owner = THIS_MODULE,
381 .open = amrwb_in_open,
382 .release = audio_in_release,
383 .read = audio_in_read,
384 .write = audio_in_write,
385 .unlocked_ioctl = audio_in_ioctl,
386 .compat_ioctl = audio_in_compat_ioctl
387};
388
389struct miscdevice audio_amrwb_in_misc = {
390 .minor = MISC_DYNAMIC_MINOR,
391 .name = "msm_amrwb_in",
392 .fops = &audio_in_fops,
393};
394
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530395int __init amrwb_in_init(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530396{
397 return misc_register(&audio_amrwb_in_misc);
398}
399
Asish Bhattacharya5faacb32017-12-04 17:23:15 +0530400void amrwb_in_exit(void)
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530401{
402 misc_deregister(&audio_amrwb_in_misc);
403}