blob: cb3c3ea86e2c2d0cdee77acf1cd94cf2b1701e1b [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/*
2 * amrnb audio input device
3 *
4 * Copyright (C) 2008 Google, Inc.
5 * Copyright (C) 2008 HTC Corporation
Asish Bhattacharya4a064192013-10-01 17:15:05 +05306 * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007 *
8 * This software is licensed under the terms of the GNU General Public
9 * License version 2, as published by the Free Software Foundation, and
10 * may be copied, distributed, and modified under those terms.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 */
18
Santosh Mardifdc227a2011-07-11 17:20:34 +053019#include <asm/atomic.h>
20#include <asm/ioctls.h>
21
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070022#include <linux/module.h>
23#include <linux/fs.h>
24#include <linux/miscdevice.h>
25#include <linux/uaccess.h>
26#include <linux/sched.h>
27#include <linux/wait.h>
28#include <linux/dma-mapping.h>
29#include <linux/msm_audio_amrnb.h>
Sidipotu Ashok1e4d3472012-09-05 15:36:11 +053030#include <linux/msm_ion.h>
Santosh Mardifdc227a2011-07-11 17:20:34 +053031#include <linux/memory_alloc.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070032
Santosh Mardifdc227a2011-07-11 17:20:34 +053033#include <mach/iommu.h>
34#include <mach/iommu_domains.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070035#include <mach/msm_adsp.h>
Kalyani polepeddy7413d2b2011-10-14 15:42:15 +053036#include <mach/socinfo.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070037#include <mach/qdsp5v2/qdsp5audreccmdi.h>
38#include <mach/qdsp5v2/qdsp5audrecmsg.h>
39#include <mach/qdsp5v2/audpreproc.h>
40#include <mach/qdsp5v2/audio_dev_ctl.h>
41#include <mach/debug_mm.h>
Santosh Mardifdc227a2011-07-11 17:20:34 +053042#include <mach/msm_memtypes.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070043
44/* FRAME_NUM must be a power of two */
45#define FRAME_NUM (8)
46#define FRAME_SIZE (22 * 2) /* 36 bytes data */
47#define DMASZ (FRAME_SIZE * FRAME_NUM)
48
49struct buffer {
50 void *data;
51 uint32_t size;
52 uint32_t read;
53 uint32_t addr;
54};
55
56struct audio_in {
57 struct buffer in[FRAME_NUM];
58
59 spinlock_t dsp_lock;
60
61 atomic_t in_bytes;
62 atomic_t in_samples;
63
64 struct mutex lock;
65 struct mutex read_lock;
66 wait_queue_head_t wait;
67 wait_queue_head_t wait_enable;
68
69 struct msm_adsp_module *audrec;
70 struct audrec_session_info session_info; /*audrec session info*/
71
72 /* configuration to use on next enable */
73 uint32_t buffer_size; /* Frame size (36 bytes) */
74 uint32_t enc_type;
75
76 int dtx_mode;
77 uint32_t frame_format;
78 uint32_t used_mode;
79 uint32_t rec_mode;
80
81 uint32_t dsp_cnt;
82 uint32_t in_head; /* next buffer dsp will write */
83 uint32_t in_tail; /* next buffer read() will read */
84 uint32_t in_count; /* number of buffers available to read() */
85 uint32_t mode;
86
87 const char *module_name;
88 unsigned queue_ids;
89 uint16_t enc_id;
90
91 uint16_t source; /* Encoding source bit mask */
92 uint32_t device_events;
93 uint32_t in_call;
94 uint32_t dev_cnt;
95 int voice_state;
96 spinlock_t dev_lock;
97
98 /* data allocated for various buffers */
99 char *data;
100 dma_addr_t phys;
Laura Abbott61399692012-04-30 14:25:46 -0700101 void *map_v_read;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700102
103 int opened;
104 int enabled;
105 int running;
106 int stopped; /* set when stopped, cleared on flush */
Kalyani polepeddy7413d2b2011-10-14 15:42:15 +0530107 char *build_id;
Sidipotu Ashok1e4d3472012-09-05 15:36:11 +0530108 struct ion_client *client;
109 struct ion_handle *buff_handle;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700110};
111
112struct audio_frame {
113 uint16_t frame_count_lsw;
114 uint16_t frame_count_msw;
115 uint16_t frame_length;
116 uint16_t erased_pcm;
117 unsigned char raw_bitstream[]; /* samples */
118} __attribute__((packed));
119
120/* Audrec Queue command sent macro's */
121#define audrec_send_bitstreamqueue(audio, cmd, len) \
122 msm_adsp_write(audio->audrec, ((audio->queue_ids & 0xFFFF0000) >> 16),\
123 cmd, len)
124
125#define audrec_send_audrecqueue(audio, cmd, len) \
126 msm_adsp_write(audio->audrec, (audio->queue_ids & 0x0000FFFF),\
127 cmd, len)
128
129struct audio_in the_audio_amrnb_in;
130
131/* DSP command send functions */
132static int audamrnb_in_enc_config(struct audio_in *audio, int enable);
133static int audamrnb_in_param_config(struct audio_in *audio);
134static int audamrnb_in_mem_config(struct audio_in *audio);
135static int audamrnb_in_record_config(struct audio_in *audio, int enable);
136static int audamrnb_dsp_read_buffer(struct audio_in *audio, uint32_t read_cnt);
137
138static void audamrnb_in_get_dsp_frames(struct audio_in *audio);
139
140static void audamrnb_in_flush(struct audio_in *audio);
141
142static void amrnb_in_listener(u32 evt_id, union auddev_evt_data *evt_payload,
143 void *private_data)
144{
145 struct audio_in *audio = (struct audio_in *) private_data;
146 unsigned long flags;
147
148 MM_DBG("evt_id = 0x%8x\n", evt_id);
149 switch (evt_id) {
150 case AUDDEV_EVT_DEV_RDY: {
151 MM_DBG("AUDDEV_EVT_DEV_RDY\n");
152 spin_lock_irqsave(&audio->dev_lock, flags);
153 audio->dev_cnt++;
154 if (!audio->in_call)
155 audio->source |= (0x1 << evt_payload->routing_id);
156 spin_unlock_irqrestore(&audio->dev_lock, flags);
157
158 if ((audio->running == 1) && (audio->enabled == 1))
159 audamrnb_in_record_config(audio, 1);
160
161 break;
162 }
163 case AUDDEV_EVT_DEV_RLS: {
164 MM_DBG("AUDDEV_EVT_DEV_RLS\n");
165 spin_lock_irqsave(&audio->dev_lock, flags);
166 audio->dev_cnt--;
167 if (!audio->in_call)
168 audio->source &= ~(0x1 << evt_payload->routing_id);
169 spin_unlock_irqrestore(&audio->dev_lock, flags);
170
171 if ((!audio->running) || (!audio->enabled))
172 break;
173
174 /* Turn of as per source */
175 if (audio->source)
176 audamrnb_in_record_config(audio, 1);
177 else
178 /* Turn off all */
179 audamrnb_in_record_config(audio, 0);
180
181 break;
182 }
183 case AUDDEV_EVT_VOICE_STATE_CHG: {
184 MM_DBG("AUDDEV_EVT_VOICE_STATE_CHG, state = %d\n",
185 evt_payload->voice_state);
186 audio->voice_state = evt_payload->voice_state;
187 if (audio->in_call && audio->running) {
188 if (audio->voice_state == VOICE_STATE_INCALL)
189 audamrnb_in_record_config(audio, 1);
190 else if (audio->voice_state == VOICE_STATE_OFFCALL) {
191 audamrnb_in_record_config(audio, 0);
192 wake_up(&audio->wait);
193 }
194 }
195
196 break;
197 }
198 default:
199 MM_ERR("wrong event %d\n", evt_id);
200 break;
201 }
202}
203
204/* ------------------- dsp preproc event handler--------------------- */
205static void audpreproc_dsp_event(void *data, unsigned id, void *msg)
206{
207 struct audio_in *audio = data;
208
209 switch (id) {
210 case AUDPREPROC_ERROR_MSG: {
211 struct audpreproc_err_msg *err_msg = msg;
212
213 MM_ERR("ERROR_MSG: stream id %d err idx %d\n",
214 err_msg->stream_id, err_msg->aud_preproc_err_idx);
215 /* Error case */
216 wake_up(&audio->wait_enable);
217 break;
218 }
219 case AUDPREPROC_CMD_CFG_DONE_MSG: {
220 MM_DBG("CMD_CFG_DONE_MSG \n");
221 break;
222 }
223 case AUDPREPROC_CMD_ENC_CFG_DONE_MSG: {
224 struct audpreproc_cmd_enc_cfg_done_msg *enc_cfg_msg = msg;
225
226 MM_DBG("CMD_ENC_CFG_DONE_MSG: stream id %d enc type \
227 0x%8x\n", enc_cfg_msg->stream_id,
228 enc_cfg_msg->rec_enc_type);
229 /* Encoder enable success */
230 if (enc_cfg_msg->rec_enc_type & ENCODE_ENABLE)
231 audamrnb_in_param_config(audio);
232 else { /* Encoder disable success */
233 audio->running = 0;
234 audamrnb_in_record_config(audio, 0);
235 }
236 break;
237 }
238 case AUDPREPROC_CMD_ENC_PARAM_CFG_DONE_MSG: {
239 MM_DBG("CMD_ENC_PARAM_CFG_DONE_MSG \n");
240 audamrnb_in_mem_config(audio);
241 break;
242 }
243 case AUDPREPROC_AFE_CMD_AUDIO_RECORD_CFG_DONE_MSG: {
244 MM_DBG("AFE_CMD_AUDIO_RECORD_CFG_DONE_MSG \n");
245 wake_up(&audio->wait_enable);
246 break;
247 }
248 default:
249 MM_ERR("Unknown Event id %d\n", id);
250 }
251}
252
253/* ------------------- dsp audrec event handler--------------------- */
254static void audrec_dsp_event(void *data, unsigned id, size_t len,
255 void (*getevent)(void *ptr, size_t len))
256{
257 struct audio_in *audio = data;
258
259 switch (id) {
260 case AUDREC_CMD_MEM_CFG_DONE_MSG: {
261 MM_DBG("CMD_MEM_CFG_DONE MSG DONE\n");
262 audio->running = 1;
263 if ((!audio->in_call && (audio->dev_cnt > 0)) ||
264 (audio->in_call &&
265 (audio->voice_state == VOICE_STATE_INCALL)))
266 audamrnb_in_record_config(audio, 1);
267 break;
268 }
269 case AUDREC_FATAL_ERR_MSG: {
270 struct audrec_fatal_err_msg fatal_err_msg;
271
272 getevent(&fatal_err_msg, AUDREC_FATAL_ERR_MSG_LEN);
273 MM_ERR("FATAL_ERR_MSG: err id %d\n",
274 fatal_err_msg.audrec_err_id);
275 /* Error stop the encoder */
276 audio->stopped = 1;
277 wake_up(&audio->wait);
278 break;
279 }
280 case AUDREC_UP_PACKET_READY_MSG: {
281 struct audrec_up_pkt_ready_msg pkt_ready_msg;
282
283 getevent(&pkt_ready_msg, AUDREC_UP_PACKET_READY_MSG_LEN);
284 MM_DBG("UP_PACKET_READY_MSG: write cnt lsw %d \
285 write cnt msw %d read cnt lsw %d read cnt msw %d \n",\
286 pkt_ready_msg.audrec_packet_write_cnt_lsw, \
287 pkt_ready_msg.audrec_packet_write_cnt_msw, \
288 pkt_ready_msg.audrec_up_prev_read_cnt_lsw, \
289 pkt_ready_msg.audrec_up_prev_read_cnt_msw);
290
291 audamrnb_in_get_dsp_frames(audio);
292 break;
293 }
294 case ADSP_MESSAGE_ID: {
295 MM_DBG("Received ADSP event:module audrectask\n");
296 break;
297 }
298 default:
299 MM_ERR("Unknown Event id %d\n", id);
300 }
301}
302
303static void audamrnb_in_get_dsp_frames(struct audio_in *audio)
304{
305 struct audio_frame *frame;
306 uint32_t index;
307 unsigned long flags;
308
309 index = audio->in_head;
310
311 frame = (void *) (((char *)audio->in[index].data) - \
312 sizeof(*frame));
313
314 spin_lock_irqsave(&audio->dsp_lock, flags);
315 audio->in[index].size = frame->frame_length;
316
317 /* statistics of read */
318 atomic_add(audio->in[index].size, &audio->in_bytes);
319 atomic_add(1, &audio->in_samples);
320
321 audio->in_head = (audio->in_head + 1) & (FRAME_NUM - 1);
322
323 /* If overflow, move the tail index foward. */
324 if (audio->in_head == audio->in_tail)
325 audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1);
326 else
327 audio->in_count++;
328
329 audamrnb_dsp_read_buffer(audio, audio->dsp_cnt++);
330 spin_unlock_irqrestore(&audio->dsp_lock, flags);
331
332 wake_up(&audio->wait);
333}
334struct msm_adsp_ops audrec_amrnb_adsp_ops = {
335 .event = audrec_dsp_event,
336};
337
338static int audamrnb_in_enc_config(struct audio_in *audio, int enable)
339{
340 struct audpreproc_audrec_cmd_enc_cfg cmd;
341
342 memset(&cmd, 0, sizeof(cmd));
Kalyani polepeddy7413d2b2011-10-14 15:42:15 +0530343 if (audio->build_id[17] == '1') {
344 cmd.cmd_id = AUDPREPROC_AUDREC_CMD_ENC_CFG_2;
345 MM_ERR("sending AUDPREPROC_AUDREC_CMD_ENC_CFG_2 command");
346 } else {
347 cmd.cmd_id = AUDPREPROC_AUDREC_CMD_ENC_CFG;
348 MM_ERR("sending AUDPREPROC_AUDREC_CMD_ENC_CFG command");
349 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700350 cmd.stream_id = audio->enc_id;
351
352 if (enable)
353 cmd.audrec_enc_type = audio->enc_type | ENCODE_ENABLE;
354 else
355 cmd.audrec_enc_type &= ~(ENCODE_ENABLE);
356
357 return audpreproc_send_audreccmdqueue(&cmd, sizeof(cmd));
358}
359
360static int audamrnb_in_param_config(struct audio_in *audio)
361{
362 struct audpreproc_audrec_cmd_parm_cfg_amrnb cmd;
363
364 memset(&cmd, 0, sizeof(cmd));
365 cmd.common.cmd_id = AUDPREPROC_AUDREC_CMD_PARAM_CFG;
366 cmd.common.stream_id = audio->enc_id;
367
368 cmd.dtx_mode = audio->dtx_mode;
369 cmd.test_mode = -1; /* Default set to -1 */
370 cmd.used_mode = audio->used_mode;
371
372 return audpreproc_send_audreccmdqueue(&cmd, sizeof(cmd));
373}
374
375/* To Do: msm_snddev_route_enc(audio->enc_id); */
376static int audamrnb_in_record_config(struct audio_in *audio, int enable)
377{
378 struct audpreproc_afe_cmd_audio_record_cfg cmd;
379
380 memset(&cmd, 0, sizeof(cmd));
381 cmd.cmd_id = AUDPREPROC_AFE_CMD_AUDIO_RECORD_CFG;
382 cmd.stream_id = audio->enc_id;
383 if (enable)
384 cmd.destination_activity = AUDIO_RECORDING_TURN_ON;
385 else
386 cmd.destination_activity = AUDIO_RECORDING_TURN_OFF;
387
388 cmd.source_mix_mask = audio->source;
389 if (audio->enc_id == 2) {
390 if ((cmd.source_mix_mask &
391 INTERNAL_CODEC_TX_SOURCE_MIX_MASK) ||
392 (cmd.source_mix_mask & AUX_CODEC_TX_SOURCE_MIX_MASK) ||
393 (cmd.source_mix_mask & VOICE_UL_SOURCE_MIX_MASK) ||
394 (cmd.source_mix_mask & VOICE_DL_SOURCE_MIX_MASK)) {
395 cmd.pipe_id = SOURCE_PIPE_1;
396 }
397 if (cmd.source_mix_mask &
398 AUDPP_A2DP_PIPE_SOURCE_MIX_MASK)
399 cmd.pipe_id |= SOURCE_PIPE_0;
400 }
401
402 return audpreproc_send_audreccmdqueue(&cmd, sizeof(cmd));
403}
404
405static int audamrnb_in_mem_config(struct audio_in *audio)
406{
407 struct audrec_cmd_arecmem_cfg cmd;
408 uint16_t *data = (void *) audio->data;
409 int n;
410
411 memset(&cmd, 0, sizeof(cmd));
412 cmd.cmd_id = AUDREC_CMD_MEM_CFG_CMD;
413 cmd.audrec_up_pkt_intm_count = 1;
414 cmd.audrec_ext_pkt_start_addr_msw = audio->phys >> 16;
415 cmd.audrec_ext_pkt_start_addr_lsw = audio->phys;
416 cmd.audrec_ext_pkt_buf_number = FRAME_NUM;
417
418 /* prepare buffer pointers:
419 * 36 bytes amrnb packet + 4 halfword header
420 */
421 for (n = 0; n < FRAME_NUM; n++) {
422 audio->in[n].data = data + 4;
423 data += (FRAME_SIZE/2); /* word increment */
424 MM_DBG("0x%8x\n", (int)(audio->in[n].data - 8));
425 }
426
427 return audrec_send_audrecqueue(audio, &cmd, sizeof(cmd));
428}
429
430static int audamrnb_dsp_read_buffer(struct audio_in *audio, uint32_t read_cnt)
431{
432 struct up_audrec_packet_ext_ptr cmd;
433
434 memset(&cmd, 0, sizeof(cmd));
435 cmd.cmd_id = UP_AUDREC_PACKET_EXT_PTR;
436 cmd.audrec_up_curr_read_count_msw = read_cnt >> 16;
437 cmd.audrec_up_curr_read_count_lsw = read_cnt;
438
439 return audrec_send_bitstreamqueue(audio, &cmd, sizeof(cmd));
440}
441
442/* must be called with audio->lock held */
443static int audamrnb_in_enable(struct audio_in *audio)
444{
445 if (audio->enabled)
446 return 0;
447
448 if (audpreproc_enable(audio->enc_id, &audpreproc_dsp_event, audio)) {
449 MM_ERR("msm_adsp_enable(audpreproc) failed\n");
450 return -ENODEV;
451 }
452
453 if (msm_adsp_enable(audio->audrec)) {
454 MM_ERR("msm_adsp_enable(audrec) failed\n");
455 audpreproc_disable(audio->enc_id, audio);
456 return -ENODEV;
457 }
458 audio->enabled = 1;
459 audamrnb_in_enc_config(audio, 1);
460
461 return 0;
462}
463
464/* must be called with audio->lock held */
465static int audamrnb_in_disable(struct audio_in *audio)
466{
467 if (audio->enabled) {
468 audio->enabled = 0;
469 audamrnb_in_enc_config(audio, 0);
470 wake_up(&audio->wait);
471 wait_event_interruptible_timeout(audio->wait_enable,
472 audio->running == 0, 1*HZ);
473 msm_adsp_disable(audio->audrec);
474 audpreproc_disable(audio->enc_id, audio);
475 }
476 return 0;
477}
478
479static void audamrnb_in_flush(struct audio_in *audio)
480{
481 int i;
482
483 audio->dsp_cnt = 0;
484 audio->in_head = 0;
485 audio->in_tail = 0;
486 audio->in_count = 0;
487 for (i = 0; i < FRAME_NUM; i++) {
488 audio->in[i].size = 0;
489 audio->in[i].read = 0;
490 }
491 MM_DBG("in_bytes %d\n", atomic_read(&audio->in_bytes));
492 MM_DBG("in_samples %d\n", atomic_read(&audio->in_samples));
493 atomic_set(&audio->in_bytes, 0);
494 atomic_set(&audio->in_samples, 0);
495}
496
497/* ------------------- device --------------------- */
498static long audamrnb_in_ioctl(struct file *file,
499 unsigned int cmd, unsigned long arg)
500{
501 struct audio_in *audio = file->private_data;
502 int rc = 0;
503
504 if (cmd == AUDIO_GET_STATS) {
505 struct msm_audio_stats stats;
Asish Bhattacharya4a064192013-10-01 17:15:05 +0530506 memset(&stats, 0, sizeof(stats));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700507 stats.byte_count = atomic_read(&audio->in_bytes);
508 stats.sample_count = atomic_read(&audio->in_samples);
509 if (copy_to_user((void *) arg, &stats, sizeof(stats)))
510 return -EFAULT;
511 return rc;
512 }
513
514 mutex_lock(&audio->lock);
515 switch (cmd) {
516 case AUDIO_START: {
517 uint32_t freq;
518 freq = 48000;
519 MM_DBG("AUDIO_START\n");
520 if (audio->in_call && (audio->voice_state !=
521 VOICE_STATE_INCALL)) {
522 rc = -EPERM;
523 break;
524 }
525 rc = msm_snddev_request_freq(&freq, audio->enc_id,
526 SNDDEV_CAP_TX, AUDDEV_CLNT_ENC);
527 MM_DBG("sample rate configured %d\n", freq);
528 if (rc < 0) {
529 MM_DBG(" Sample rate can not be set, return code %d\n",
530 rc);
531 msm_snddev_withdraw_freq(audio->enc_id,
532 SNDDEV_CAP_TX, AUDDEV_CLNT_ENC);
533 MM_DBG("msm_snddev_withdraw_freq\n");
534 break;
535 }
536 /*update aurec session info in audpreproc layer*/
537 audio->session_info.session_id = audio->enc_id;
538 /*amrnb works only on 8KHz*/
539 audio->session_info.sampling_freq = 8000;
540 audpreproc_update_audrec_info(&audio->session_info);
541 rc = audamrnb_in_enable(audio);
542 if (!rc) {
543 rc =
544 wait_event_interruptible_timeout(audio->wait_enable,
545 audio->running != 0, 1*HZ);
546 MM_DBG("state %d rc = %d\n", audio->running, rc);
547
548 if (audio->running == 0)
549 rc = -ENODEV;
550 else
551 rc = 0;
552 }
553 audio->stopped = 0;
554 break;
555 }
556 case AUDIO_STOP: {
557 /*reset the sampling frequency information at audpreproc layer*/
558 audio->session_info.sampling_freq = 0;
559 audpreproc_update_audrec_info(&audio->session_info);
560 rc = audamrnb_in_disable(audio);
561 rc = msm_snddev_withdraw_freq(audio->enc_id,
562 SNDDEV_CAP_TX, AUDDEV_CLNT_ENC);
563 MM_DBG("msm_snddev_withdraw_freq\n");
564 audio->stopped = 1;
565 break;
566 }
567 case AUDIO_FLUSH: {
568 if (audio->stopped) {
569 /* Make sure we're stopped and we wake any threads
570 * that might be blocked holding the read_lock.
571 * While audio->stopped read threads will always
572 * exit immediately.
573 */
574 wake_up(&audio->wait);
575 mutex_lock(&audio->read_lock);
576 audamrnb_in_flush(audio);
577 mutex_unlock(&audio->read_lock);
578 }
579 break;
580 }
581 case AUDIO_SET_STREAM_CONFIG: {
582 struct msm_audio_stream_config cfg;
583 if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) {
584 rc = -EFAULT;
585 break;
586 }
587 /* Allow only single frame */
588 if (cfg.buffer_size != (FRAME_SIZE - 8))
589 rc = -EINVAL;
590 else
591 audio->buffer_size = cfg.buffer_size;
592 break;
593 }
594 case AUDIO_GET_STREAM_CONFIG: {
595 struct msm_audio_stream_config cfg;
596 memset(&cfg, 0, sizeof(cfg));
597 cfg.buffer_size = audio->buffer_size;
598 cfg.buffer_count = FRAME_NUM;
599 if (copy_to_user((void *) arg, &cfg, sizeof(cfg)))
600 rc = -EFAULT;
601 break;
602 }
603 case AUDIO_GET_AMRNB_ENC_CONFIG_V2: {
604 struct msm_audio_amrnb_enc_config_v2 cfg;
605 memset(&cfg, 0, sizeof(cfg));
606 cfg.dtx_enable = ((audio->dtx_mode == -1) ? 1 : 0);
607 cfg.band_mode = audio->used_mode;
608 cfg.frame_format = audio->frame_format;
609 if (copy_to_user((void *) arg, &cfg, sizeof(cfg)))
610 rc = -EFAULT;
611 break;
612 }
613 case AUDIO_SET_AMRNB_ENC_CONFIG_V2: {
614 struct msm_audio_amrnb_enc_config_v2 cfg;
615 if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) {
616 rc = -EFAULT;
617 break;
618 }
619 /* DSP does not support any other than default format */
620 if (audio->frame_format != cfg.frame_format) {
621 rc = -EINVAL;
622 break;
623 }
624 if (cfg.dtx_enable == 0)
625 audio->dtx_mode = 0;
626 else if (cfg.dtx_enable == 1)
627 audio->dtx_mode = -1;
628 else {
629 rc = -EINVAL;
630 break;
631 }
632 audio->used_mode = cfg.band_mode;
633 break;
634 }
635 case AUDIO_SET_INCALL: {
636 struct msm_voicerec_mode cfg;
637 unsigned long flags;
638 if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) {
639 rc = -EFAULT;
640 break;
641 }
642 if (cfg.rec_mode != VOC_REC_BOTH &&
643 cfg.rec_mode != VOC_REC_UPLINK &&
644 cfg.rec_mode != VOC_REC_DOWNLINK) {
645 MM_ERR("invalid rec_mode\n");
646 rc = -EINVAL;
647 break;
648 } else {
649 spin_lock_irqsave(&audio->dev_lock, flags);
650 if (cfg.rec_mode == VOC_REC_UPLINK)
651 audio->source = VOICE_UL_SOURCE_MIX_MASK;
652 else if (cfg.rec_mode == VOC_REC_DOWNLINK)
653 audio->source = VOICE_DL_SOURCE_MIX_MASK;
654 else
655 audio->source = VOICE_DL_SOURCE_MIX_MASK |
656 VOICE_UL_SOURCE_MIX_MASK ;
657 audio->in_call = 1;
658 spin_unlock_irqrestore(&audio->dev_lock, flags);
659 }
660 break;
661 }
662 case AUDIO_GET_SESSION_ID: {
663 if (copy_to_user((void *) arg, &audio->enc_id,
664 sizeof(unsigned short))) {
665 rc = -EFAULT;
666 }
667 break;
668 }
669 default:
670 rc = -EINVAL;
671 }
672 mutex_unlock(&audio->lock);
673 return rc;
674}
675
676static ssize_t audamrnb_in_read(struct file *file,
677 char __user *buf,
678 size_t count, loff_t *pos)
679{
680 struct audio_in *audio = file->private_data;
681 unsigned long flags;
682 const char __user *start = buf;
683 void *data;
684 uint32_t index;
685 uint32_t size;
686 int rc = 0;
687
688 mutex_lock(&audio->read_lock);
689 while (count > 0) {
690 rc = wait_event_interruptible(
691 audio->wait, (audio->in_count > 0) || audio->stopped
692 || (audio->in_call && audio->running &&
693 (audio->voice_state == VOICE_STATE_OFFCALL)));
694 if (rc < 0)
695 break;
696
697 if (!audio->in_count) {
698 if (audio->stopped) {
699 rc = 0;/* End of File */
700 break;
701 } else if (audio->in_call && audio->running &&
702 (audio->voice_state == VOICE_STATE_OFFCALL)) {
703 MM_DBG("Not Permitted Voice Terminated\n");
704 rc = -EPERM; /* Voice Call stopped */
705 break;
706 }
707 }
708
709 index = audio->in_tail;
710 data = (uint8_t *) audio->in[index].data;
711 size = audio->in[index].size;
712 if (count >= size) {
713 if (copy_to_user(buf, data, size)) {
714 rc = -EFAULT;
715 break;
716 }
717 spin_lock_irqsave(&audio->dsp_lock, flags);
718 if (index != audio->in_tail) {
719 /* overrun -- data is
720 * invalid and we need to retry */
721 spin_unlock_irqrestore(&audio->dsp_lock, flags);
722 continue;
723 }
724 audio->in[index].size = 0;
725 audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1);
726 audio->in_count--;
727 spin_unlock_irqrestore(&audio->dsp_lock, flags);
728 count -= size;
729 buf += size;
730 } else {
731 MM_ERR("short read\n");
732 break;
733 }
734 }
735 mutex_unlock(&audio->read_lock);
736
737 if (buf > start)
738 return buf - start;
739
740 return rc;
741}
742
743static ssize_t audamrnb_in_write(struct file *file,
744 const char __user *buf,
745 size_t count, loff_t *pos)
746{
747 return -EINVAL;
748}
749
750static int audamrnb_in_release(struct inode *inode, struct file *file)
751{
752 struct audio_in *audio = file->private_data;
753
754 MM_DBG("\n");
755 mutex_lock(&audio->lock);
756 audio->in_call = 0;
757 /* with draw frequency for session
758 incase not stopped the driver */
759 msm_snddev_withdraw_freq(audio->enc_id, SNDDEV_CAP_TX,
760 AUDDEV_CLNT_ENC);
761 auddev_unregister_evt_listner(AUDDEV_CLNT_ENC, audio->enc_id);
762 /*reset the sampling frequency information at audpreproc layer*/
763 audio->session_info.sampling_freq = 0;
764 audpreproc_update_audrec_info(&audio->session_info);
765 audamrnb_in_disable(audio);
766 audamrnb_in_flush(audio);
767 msm_adsp_put(audio->audrec);
768 audpreproc_aenc_free(audio->enc_id);
769 audio->audrec = NULL;
770 audio->opened = 0;
771 if (audio->data) {
Sidipotu Ashok1e4d3472012-09-05 15:36:11 +0530772 ion_unmap_kernel(audio->client, audio->buff_handle);
773 ion_free(audio->client, audio->buff_handle);
774 ion_client_destroy(audio->client);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700775 audio->data = NULL;
776 }
777 mutex_unlock(&audio->lock);
778 return 0;
779}
780
781static int audamrnb_in_open(struct inode *inode, struct file *file)
782{
783 struct audio_in *audio = &the_audio_amrnb_in;
784 int rc;
785 int encid;
Sidipotu Ashok1e4d3472012-09-05 15:36:11 +0530786 int len = 0;
787 unsigned long ionflag = 0;
788 ion_phys_addr_t addr = 0;
789 struct ion_handle *handle = NULL;
790 struct ion_client *client = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700791
792 mutex_lock(&audio->lock);
793 if (audio->opened) {
794 rc = -EBUSY;
795 goto done;
796 }
Sidipotu Ashok1e4d3472012-09-05 15:36:11 +0530797
798 client = msm_ion_client_create(UINT_MAX, "Audio_AMR_In_Client");
799 if (IS_ERR_OR_NULL(client)) {
800 MM_ERR("Unable to create ION client\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700801 rc = -ENOMEM;
Sidipotu Ashok1e4d3472012-09-05 15:36:11 +0530802 goto client_create_error;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700803 }
Sidipotu Ashok1e4d3472012-09-05 15:36:11 +0530804 audio->client = client;
805
806 handle = ion_alloc(client, DMASZ, SZ_4K,
Hanumant Singh7d72bad2012-08-29 18:39:44 -0700807 ION_HEAP(ION_AUDIO_HEAP_ID), 0);
Sidipotu Ashok1e4d3472012-09-05 15:36:11 +0530808 if (IS_ERR_OR_NULL(handle)) {
809 MM_ERR("Unable to create allocate O/P buffers\n");
810 rc = -ENOMEM;
811 goto buff_alloc_error;
812 }
813 audio->buff_handle = handle;
814
815 rc = ion_phys(client, handle, &addr, &len);
816 if (rc) {
817 MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
818 (unsigned int) addr, (unsigned int) len);
819 goto buff_get_phys_error;
820 } else {
821 MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
822 (unsigned int) addr, (unsigned int) len);
823 }
824 audio->phys = (int32_t)addr;
825
826 rc = ion_handle_get_flags(client, handle, &ionflag);
827 if (rc) {
828 MM_ERR("could not get flags for the handle\n");
829 goto buff_get_flags_error;
830 }
831
Mitchel Humpherys911b4b72012-09-12 14:42:50 -0700832 audio->map_v_read = ion_map_kernel(client, handle);
Sidipotu Ashok1e4d3472012-09-05 15:36:11 +0530833 if (IS_ERR(audio->map_v_read)) {
834 MM_ERR("could not map write buffers\n");
835 rc = -ENOMEM;
836 goto buff_map_error;
837 }
838 audio->data = audio->map_v_read;
839 MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
840 audio->phys, (int)audio->data);
841
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700842 MM_DBG("Memory addr = 0x%8x phy addr = 0x%8x\n",\
843 (int) audio->data, (int) audio->phys);
844 if ((file->f_mode & FMODE_WRITE) &&
845 (file->f_mode & FMODE_READ)) {
846 rc = -EACCES;
847 MM_ERR("Non tunnel encoding is not supported\n");
848 goto done;
849 } else if (!(file->f_mode & FMODE_WRITE) &&
850 (file->f_mode & FMODE_READ)) {
851 audio->mode = MSM_AUD_ENC_MODE_TUNNEL;
852 MM_DBG("Opened for tunnel mode encoding\n");
853 } else {
854 rc = -EACCES;
855 goto done;
856 }
857
858
859 /* Settings will be re-config at AUDIO_SET_CONFIG,
860 * but at least we need to have initial config
861 */
862 audio->buffer_size = (FRAME_SIZE - 8);
863 audio->enc_type = ENC_TYPE_AMRNB | audio->mode;
864 audio->dtx_mode = -1;
865 audio->frame_format = 0;
866 audio->used_mode = 7; /* Bit Rate 12.2 kbps MR122 */
867
868 encid = audpreproc_aenc_alloc(audio->enc_type, &audio->module_name,
869 &audio->queue_ids);
870 if (encid < 0) {
871 MM_ERR("No free encoder available\n");
872 rc = -ENODEV;
873 goto done;
874 }
875 audio->enc_id = encid;
876
877 rc = msm_adsp_get(audio->module_name, &audio->audrec,
878 &audrec_amrnb_adsp_ops, audio);
879
880 if (rc) {
881 audpreproc_aenc_free(audio->enc_id);
882 goto done;
883 }
884
885 audio->stopped = 0;
886 audio->source = 0;
887
888 audamrnb_in_flush(audio);
889
890 audio->device_events = AUDDEV_EVT_DEV_RDY | AUDDEV_EVT_DEV_RLS |
891 AUDDEV_EVT_VOICE_STATE_CHG;
892
893 audio->voice_state = msm_get_voice_state();
894 rc = auddev_register_evt_listner(audio->device_events,
895 AUDDEV_CLNT_ENC, audio->enc_id,
896 amrnb_in_listener, (void *) audio);
897 if (rc) {
898 MM_ERR("failed to register device event listener\n");
899 goto evt_error;
900 }
Kalyani polepeddy7413d2b2011-10-14 15:42:15 +0530901 audio->build_id = socinfo_get_build_id();
Vinay Vaka4ff52a62011-12-13 15:38:35 +0530902 MM_DBG("Modem build id = %s\n", audio->build_id);
Kalyani polepeddy7413d2b2011-10-14 15:42:15 +0530903
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700904 file->private_data = audio;
905 audio->opened = 1;
906done:
907 mutex_unlock(&audio->lock);
908 return rc;
909evt_error:
910 msm_adsp_put(audio->audrec);
911 audpreproc_aenc_free(audio->enc_id);
912 mutex_unlock(&audio->lock);
Sidipotu Ashok1e4d3472012-09-05 15:36:11 +0530913 ion_unmap_kernel(client, audio->buff_handle);
914buff_map_error:
915buff_get_phys_error:
916buff_get_flags_error:
917 ion_free(client, audio->buff_handle);
918buff_alloc_error:
919 ion_client_destroy(client);
920client_create_error:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700921 return rc;
922}
923
924static const struct file_operations audio_in_fops = {
925 .owner = THIS_MODULE,
926 .open = audamrnb_in_open,
927 .release = audamrnb_in_release,
928 .read = audamrnb_in_read,
929 .write = audamrnb_in_write,
930 .unlocked_ioctl = audamrnb_in_ioctl,
931};
932
933struct miscdevice audio_amrnb_in_misc = {
934 .minor = MISC_DYNAMIC_MINOR,
935 .name = "msm_amrnb_in",
936 .fops = &audio_in_fops,
937};
938
939static int __init audamrnb_in_init(void)
940{
941 mutex_init(&the_audio_amrnb_in.lock);
942 mutex_init(&the_audio_amrnb_in.read_lock);
943 spin_lock_init(&the_audio_amrnb_in.dsp_lock);
944 spin_lock_init(&the_audio_amrnb_in.dev_lock);
945 init_waitqueue_head(&the_audio_amrnb_in.wait);
946 init_waitqueue_head(&the_audio_amrnb_in.wait_enable);
947 return misc_register(&audio_amrnb_in_misc);
948}
949
950device_initcall(audamrnb_in_init);