blob: 8e66939f22f849203603fdc644f63c50d68b15cf [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
Duy Truong790f06d2013-02-13 16:38:12 -08006 * Copyright (c) 2009-2012, 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;
506 stats.byte_count = atomic_read(&audio->in_bytes);
507 stats.sample_count = atomic_read(&audio->in_samples);
508 if (copy_to_user((void *) arg, &stats, sizeof(stats)))
509 return -EFAULT;
510 return rc;
511 }
512
513 mutex_lock(&audio->lock);
514 switch (cmd) {
515 case AUDIO_START: {
516 uint32_t freq;
517 freq = 48000;
518 MM_DBG("AUDIO_START\n");
519 if (audio->in_call && (audio->voice_state !=
520 VOICE_STATE_INCALL)) {
521 rc = -EPERM;
522 break;
523 }
524 rc = msm_snddev_request_freq(&freq, audio->enc_id,
525 SNDDEV_CAP_TX, AUDDEV_CLNT_ENC);
526 MM_DBG("sample rate configured %d\n", freq);
527 if (rc < 0) {
528 MM_DBG(" Sample rate can not be set, return code %d\n",
529 rc);
530 msm_snddev_withdraw_freq(audio->enc_id,
531 SNDDEV_CAP_TX, AUDDEV_CLNT_ENC);
532 MM_DBG("msm_snddev_withdraw_freq\n");
533 break;
534 }
535 /*update aurec session info in audpreproc layer*/
536 audio->session_info.session_id = audio->enc_id;
537 /*amrnb works only on 8KHz*/
538 audio->session_info.sampling_freq = 8000;
539 audpreproc_update_audrec_info(&audio->session_info);
540 rc = audamrnb_in_enable(audio);
541 if (!rc) {
542 rc =
543 wait_event_interruptible_timeout(audio->wait_enable,
544 audio->running != 0, 1*HZ);
545 MM_DBG("state %d rc = %d\n", audio->running, rc);
546
547 if (audio->running == 0)
548 rc = -ENODEV;
549 else
550 rc = 0;
551 }
552 audio->stopped = 0;
553 break;
554 }
555 case AUDIO_STOP: {
556 /*reset the sampling frequency information at audpreproc layer*/
557 audio->session_info.sampling_freq = 0;
558 audpreproc_update_audrec_info(&audio->session_info);
559 rc = audamrnb_in_disable(audio);
560 rc = msm_snddev_withdraw_freq(audio->enc_id,
561 SNDDEV_CAP_TX, AUDDEV_CLNT_ENC);
562 MM_DBG("msm_snddev_withdraw_freq\n");
563 audio->stopped = 1;
564 break;
565 }
566 case AUDIO_FLUSH: {
567 if (audio->stopped) {
568 /* Make sure we're stopped and we wake any threads
569 * that might be blocked holding the read_lock.
570 * While audio->stopped read threads will always
571 * exit immediately.
572 */
573 wake_up(&audio->wait);
574 mutex_lock(&audio->read_lock);
575 audamrnb_in_flush(audio);
576 mutex_unlock(&audio->read_lock);
577 }
578 break;
579 }
580 case AUDIO_SET_STREAM_CONFIG: {
581 struct msm_audio_stream_config cfg;
582 if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) {
583 rc = -EFAULT;
584 break;
585 }
586 /* Allow only single frame */
587 if (cfg.buffer_size != (FRAME_SIZE - 8))
588 rc = -EINVAL;
589 else
590 audio->buffer_size = cfg.buffer_size;
591 break;
592 }
593 case AUDIO_GET_STREAM_CONFIG: {
594 struct msm_audio_stream_config cfg;
595 memset(&cfg, 0, sizeof(cfg));
596 cfg.buffer_size = audio->buffer_size;
597 cfg.buffer_count = FRAME_NUM;
598 if (copy_to_user((void *) arg, &cfg, sizeof(cfg)))
599 rc = -EFAULT;
600 break;
601 }
602 case AUDIO_GET_AMRNB_ENC_CONFIG_V2: {
603 struct msm_audio_amrnb_enc_config_v2 cfg;
604 memset(&cfg, 0, sizeof(cfg));
605 cfg.dtx_enable = ((audio->dtx_mode == -1) ? 1 : 0);
606 cfg.band_mode = audio->used_mode;
607 cfg.frame_format = audio->frame_format;
608 if (copy_to_user((void *) arg, &cfg, sizeof(cfg)))
609 rc = -EFAULT;
610 break;
611 }
612 case AUDIO_SET_AMRNB_ENC_CONFIG_V2: {
613 struct msm_audio_amrnb_enc_config_v2 cfg;
614 if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) {
615 rc = -EFAULT;
616 break;
617 }
618 /* DSP does not support any other than default format */
619 if (audio->frame_format != cfg.frame_format) {
620 rc = -EINVAL;
621 break;
622 }
623 if (cfg.dtx_enable == 0)
624 audio->dtx_mode = 0;
625 else if (cfg.dtx_enable == 1)
626 audio->dtx_mode = -1;
627 else {
628 rc = -EINVAL;
629 break;
630 }
631 audio->used_mode = cfg.band_mode;
632 break;
633 }
634 case AUDIO_SET_INCALL: {
635 struct msm_voicerec_mode cfg;
636 unsigned long flags;
637 if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) {
638 rc = -EFAULT;
639 break;
640 }
641 if (cfg.rec_mode != VOC_REC_BOTH &&
642 cfg.rec_mode != VOC_REC_UPLINK &&
643 cfg.rec_mode != VOC_REC_DOWNLINK) {
644 MM_ERR("invalid rec_mode\n");
645 rc = -EINVAL;
646 break;
647 } else {
648 spin_lock_irqsave(&audio->dev_lock, flags);
649 if (cfg.rec_mode == VOC_REC_UPLINK)
650 audio->source = VOICE_UL_SOURCE_MIX_MASK;
651 else if (cfg.rec_mode == VOC_REC_DOWNLINK)
652 audio->source = VOICE_DL_SOURCE_MIX_MASK;
653 else
654 audio->source = VOICE_DL_SOURCE_MIX_MASK |
655 VOICE_UL_SOURCE_MIX_MASK ;
656 audio->in_call = 1;
657 spin_unlock_irqrestore(&audio->dev_lock, flags);
658 }
659 break;
660 }
661 case AUDIO_GET_SESSION_ID: {
662 if (copy_to_user((void *) arg, &audio->enc_id,
663 sizeof(unsigned short))) {
664 rc = -EFAULT;
665 }
666 break;
667 }
668 default:
669 rc = -EINVAL;
670 }
671 mutex_unlock(&audio->lock);
672 return rc;
673}
674
675static ssize_t audamrnb_in_read(struct file *file,
676 char __user *buf,
677 size_t count, loff_t *pos)
678{
679 struct audio_in *audio = file->private_data;
680 unsigned long flags;
681 const char __user *start = buf;
682 void *data;
683 uint32_t index;
684 uint32_t size;
685 int rc = 0;
686
687 mutex_lock(&audio->read_lock);
688 while (count > 0) {
689 rc = wait_event_interruptible(
690 audio->wait, (audio->in_count > 0) || audio->stopped
691 || (audio->in_call && audio->running &&
692 (audio->voice_state == VOICE_STATE_OFFCALL)));
693 if (rc < 0)
694 break;
695
696 if (!audio->in_count) {
697 if (audio->stopped) {
698 rc = 0;/* End of File */
699 break;
700 } else if (audio->in_call && audio->running &&
701 (audio->voice_state == VOICE_STATE_OFFCALL)) {
702 MM_DBG("Not Permitted Voice Terminated\n");
703 rc = -EPERM; /* Voice Call stopped */
704 break;
705 }
706 }
707
708 index = audio->in_tail;
709 data = (uint8_t *) audio->in[index].data;
710 size = audio->in[index].size;
711 if (count >= size) {
712 if (copy_to_user(buf, data, size)) {
713 rc = -EFAULT;
714 break;
715 }
716 spin_lock_irqsave(&audio->dsp_lock, flags);
717 if (index != audio->in_tail) {
718 /* overrun -- data is
719 * invalid and we need to retry */
720 spin_unlock_irqrestore(&audio->dsp_lock, flags);
721 continue;
722 }
723 audio->in[index].size = 0;
724 audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1);
725 audio->in_count--;
726 spin_unlock_irqrestore(&audio->dsp_lock, flags);
727 count -= size;
728 buf += size;
729 } else {
730 MM_ERR("short read\n");
731 break;
732 }
733 }
734 mutex_unlock(&audio->read_lock);
735
736 if (buf > start)
737 return buf - start;
738
739 return rc;
740}
741
742static ssize_t audamrnb_in_write(struct file *file,
743 const char __user *buf,
744 size_t count, loff_t *pos)
745{
746 return -EINVAL;
747}
748
749static int audamrnb_in_release(struct inode *inode, struct file *file)
750{
751 struct audio_in *audio = file->private_data;
752
753 MM_DBG("\n");
754 mutex_lock(&audio->lock);
755 audio->in_call = 0;
756 /* with draw frequency for session
757 incase not stopped the driver */
758 msm_snddev_withdraw_freq(audio->enc_id, SNDDEV_CAP_TX,
759 AUDDEV_CLNT_ENC);
760 auddev_unregister_evt_listner(AUDDEV_CLNT_ENC, audio->enc_id);
761 /*reset the sampling frequency information at audpreproc layer*/
762 audio->session_info.sampling_freq = 0;
763 audpreproc_update_audrec_info(&audio->session_info);
764 audamrnb_in_disable(audio);
765 audamrnb_in_flush(audio);
766 msm_adsp_put(audio->audrec);
767 audpreproc_aenc_free(audio->enc_id);
768 audio->audrec = NULL;
769 audio->opened = 0;
770 if (audio->data) {
Sidipotu Ashok1e4d3472012-09-05 15:36:11 +0530771 ion_unmap_kernel(audio->client, audio->buff_handle);
772 ion_free(audio->client, audio->buff_handle);
773 ion_client_destroy(audio->client);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700774 audio->data = NULL;
775 }
776 mutex_unlock(&audio->lock);
777 return 0;
778}
779
780static int audamrnb_in_open(struct inode *inode, struct file *file)
781{
782 struct audio_in *audio = &the_audio_amrnb_in;
783 int rc;
784 int encid;
Sidipotu Ashok1e4d3472012-09-05 15:36:11 +0530785 int len = 0;
786 unsigned long ionflag = 0;
787 ion_phys_addr_t addr = 0;
788 struct ion_handle *handle = NULL;
789 struct ion_client *client = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700790
791 mutex_lock(&audio->lock);
792 if (audio->opened) {
793 rc = -EBUSY;
794 goto done;
795 }
Sidipotu Ashok1e4d3472012-09-05 15:36:11 +0530796
797 client = msm_ion_client_create(UINT_MAX, "Audio_AMR_In_Client");
798 if (IS_ERR_OR_NULL(client)) {
799 MM_ERR("Unable to create ION client\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700800 rc = -ENOMEM;
Sidipotu Ashok1e4d3472012-09-05 15:36:11 +0530801 goto client_create_error;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700802 }
Sidipotu Ashok1e4d3472012-09-05 15:36:11 +0530803 audio->client = client;
804
805 handle = ion_alloc(client, DMASZ, SZ_4K,
Hanumant Singh7d72bad2012-08-29 18:39:44 -0700806 ION_HEAP(ION_AUDIO_HEAP_ID), 0);
Sidipotu Ashok1e4d3472012-09-05 15:36:11 +0530807 if (IS_ERR_OR_NULL(handle)) {
808 MM_ERR("Unable to create allocate O/P buffers\n");
809 rc = -ENOMEM;
810 goto buff_alloc_error;
811 }
812 audio->buff_handle = handle;
813
814 rc = ion_phys(client, handle, &addr, &len);
815 if (rc) {
816 MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
817 (unsigned int) addr, (unsigned int) len);
818 goto buff_get_phys_error;
819 } else {
820 MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
821 (unsigned int) addr, (unsigned int) len);
822 }
823 audio->phys = (int32_t)addr;
824
825 rc = ion_handle_get_flags(client, handle, &ionflag);
826 if (rc) {
827 MM_ERR("could not get flags for the handle\n");
828 goto buff_get_flags_error;
829 }
830
Mitchel Humpherys911b4b72012-09-12 14:42:50 -0700831 audio->map_v_read = ion_map_kernel(client, handle);
Sidipotu Ashok1e4d3472012-09-05 15:36:11 +0530832 if (IS_ERR(audio->map_v_read)) {
833 MM_ERR("could not map write buffers\n");
834 rc = -ENOMEM;
835 goto buff_map_error;
836 }
837 audio->data = audio->map_v_read;
838 MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
839 audio->phys, (int)audio->data);
840
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700841 MM_DBG("Memory addr = 0x%8x phy addr = 0x%8x\n",\
842 (int) audio->data, (int) audio->phys);
843 if ((file->f_mode & FMODE_WRITE) &&
844 (file->f_mode & FMODE_READ)) {
845 rc = -EACCES;
846 MM_ERR("Non tunnel encoding is not supported\n");
847 goto done;
848 } else if (!(file->f_mode & FMODE_WRITE) &&
849 (file->f_mode & FMODE_READ)) {
850 audio->mode = MSM_AUD_ENC_MODE_TUNNEL;
851 MM_DBG("Opened for tunnel mode encoding\n");
852 } else {
853 rc = -EACCES;
854 goto done;
855 }
856
857
858 /* Settings will be re-config at AUDIO_SET_CONFIG,
859 * but at least we need to have initial config
860 */
861 audio->buffer_size = (FRAME_SIZE - 8);
862 audio->enc_type = ENC_TYPE_AMRNB | audio->mode;
863 audio->dtx_mode = -1;
864 audio->frame_format = 0;
865 audio->used_mode = 7; /* Bit Rate 12.2 kbps MR122 */
866
867 encid = audpreproc_aenc_alloc(audio->enc_type, &audio->module_name,
868 &audio->queue_ids);
869 if (encid < 0) {
870 MM_ERR("No free encoder available\n");
871 rc = -ENODEV;
872 goto done;
873 }
874 audio->enc_id = encid;
875
876 rc = msm_adsp_get(audio->module_name, &audio->audrec,
877 &audrec_amrnb_adsp_ops, audio);
878
879 if (rc) {
880 audpreproc_aenc_free(audio->enc_id);
881 goto done;
882 }
883
884 audio->stopped = 0;
885 audio->source = 0;
886
887 audamrnb_in_flush(audio);
888
889 audio->device_events = AUDDEV_EVT_DEV_RDY | AUDDEV_EVT_DEV_RLS |
890 AUDDEV_EVT_VOICE_STATE_CHG;
891
892 audio->voice_state = msm_get_voice_state();
893 rc = auddev_register_evt_listner(audio->device_events,
894 AUDDEV_CLNT_ENC, audio->enc_id,
895 amrnb_in_listener, (void *) audio);
896 if (rc) {
897 MM_ERR("failed to register device event listener\n");
898 goto evt_error;
899 }
Kalyani polepeddy7413d2b2011-10-14 15:42:15 +0530900 audio->build_id = socinfo_get_build_id();
Vinay Vaka4ff52a62011-12-13 15:38:35 +0530901 MM_DBG("Modem build id = %s\n", audio->build_id);
Kalyani polepeddy7413d2b2011-10-14 15:42:15 +0530902
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700903 file->private_data = audio;
904 audio->opened = 1;
905done:
906 mutex_unlock(&audio->lock);
907 return rc;
908evt_error:
909 msm_adsp_put(audio->audrec);
910 audpreproc_aenc_free(audio->enc_id);
911 mutex_unlock(&audio->lock);
Sidipotu Ashok1e4d3472012-09-05 15:36:11 +0530912 ion_unmap_kernel(client, audio->buff_handle);
913buff_map_error:
914buff_get_phys_error:
915buff_get_flags_error:
916 ion_free(client, audio->buff_handle);
917buff_alloc_error:
918 ion_client_destroy(client);
919client_create_error:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700920 return rc;
921}
922
923static const struct file_operations audio_in_fops = {
924 .owner = THIS_MODULE,
925 .open = audamrnb_in_open,
926 .release = audamrnb_in_release,
927 .read = audamrnb_in_read,
928 .write = audamrnb_in_write,
929 .unlocked_ioctl = audamrnb_in_ioctl,
930};
931
932struct miscdevice audio_amrnb_in_misc = {
933 .minor = MISC_DYNAMIC_MINOR,
934 .name = "msm_amrnb_in",
935 .fops = &audio_in_fops,
936};
937
938static int __init audamrnb_in_init(void)
939{
940 mutex_init(&the_audio_amrnb_in.lock);
941 mutex_init(&the_audio_amrnb_in.read_lock);
942 spin_lock_init(&the_audio_amrnb_in.dsp_lock);
943 spin_lock_init(&the_audio_amrnb_in.dev_lock);
944 init_waitqueue_head(&the_audio_amrnb_in.wait);
945 init_waitqueue_head(&the_audio_amrnb_in.wait_enable);
946 return misc_register(&audio_amrnb_in_misc);
947}
948
949device_initcall(audamrnb_in_init);