blob: d34499dff6a6a12ae9269f60d0ea0a9691eeb705 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/*
2 * qcelp audio input device
3 *
4 * Copyright (C) 2008 Google, Inc.
5 * Copyright (C) 2008 HTC Corporation
6 * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
7 *
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_qcp.h>
30#include <linux/android_pmem.h>
Santosh Mardifdc227a2011-07-11 17:20:34 +053031#include <linux/memory_alloc.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070032
33#include <mach/msm_adsp.h>
Santosh Mardifdc227a2011-07-11 17:20:34 +053034#include <mach/iommu.h>
35#include <mach/iommu_domains.h>
36#include <mach/msm_subsystem_map.h>
Kalyani polepeddy7413d2b2011-10-14 15:42:15 +053037#include <mach/socinfo.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070038#include <mach/qdsp5v2/qdsp5audreccmdi.h>
39#include <mach/qdsp5v2/qdsp5audrecmsg.h>
40#include <mach/qdsp5v2/audpreproc.h>
41#include <mach/qdsp5v2/audio_dev_ctl.h>
42#include <mach/debug_mm.h>
Santosh Mardifdc227a2011-07-11 17:20:34 +053043#include <mach/msm_memtypes.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070044
45#define META_OUT_SIZE 24
46/* FRAME_NUM must be a power of two */
47#define FRAME_NUM 8
48#define QCELP_FRAME_SIZE 36 /* 36 bytes data */
49#define FRAME_SIZE (22 * 2) /* 36 bytes data */
50 /* 36 bytes data + 24 meta field*/
51#define NT_FRAME_SIZE (QCELP_FRAME_SIZE + META_OUT_SIZE)
52#define DMASZ (NT_FRAME_SIZE * FRAME_NUM)
53#define OUT_FRAME_NUM (2)
54#define OUT_BUFFER_SIZE (4 * 1024 + META_OUT_SIZE)
55#define BUFFER_SIZE (OUT_BUFFER_SIZE * OUT_FRAME_NUM)
56
57
58#define AUDPREPROC_QCELP_EOS_FLG_OFFSET 0x0A
59#define AUDPREPROC_QCELP_EOS_FLG_MASK 0x01
60#define AUDPREPROC_QCELP_EOS_NONE 0x0 /* No EOS detected */
61#define AUDPREPROC_QCELP_EOS_SET 0x1 /* EOS set in meta field */
62
63struct buffer {
64 void *data;
65 uint32_t size;
66 uint32_t read;
67 uint32_t addr;
68 uint32_t used;
69 uint32_t mfield_sz;
70};
71
72struct audio_in {
73 struct buffer in[FRAME_NUM];
74
75 spinlock_t dsp_lock;
76
77 atomic_t in_bytes;
78 atomic_t in_samples;
79
80 struct mutex lock;
81 struct mutex read_lock;
82 wait_queue_head_t wait;
83 wait_queue_head_t wait_enable;
84 /*write section*/
85 struct buffer out[OUT_FRAME_NUM];
86
87 uint8_t out_head;
88 uint8_t out_tail;
89 uint8_t out_needed; /* number of buffers the dsp is waiting for */
90 uint32_t out_count;
91
92 struct mutex write_lock;
93 wait_queue_head_t write_wait;
94 int32_t out_phys; /* physical address of write buffer */
95 char *out_data;
96 int mfield; /* meta field embedded in data */
97 int wflush; /*write flush */
98 int rflush; /*read flush*/
99 int out_frame_cnt;
100
101 struct msm_adsp_module *audrec;
102
103 struct audrec_session_info session_info; /*audrec session info*/
104
105 /* configuration to use on next enable */
106 uint32_t buffer_size; /* Frame size (36 bytes) */
107 uint32_t samp_rate;
108 uint32_t channel_mode;
109 uint32_t enc_type;
110
111 struct msm_audio_qcelp_enc_config cfg;
112 uint32_t rec_mode;
113
114 uint32_t dsp_cnt;
115 uint32_t in_head; /* next buffer dsp will write */
116 uint32_t in_tail; /* next buffer read() will read */
117 uint32_t in_count; /* number of buffers available to read() */
118 uint32_t mode;
119 uint32_t eos_ack;
120 uint32_t flush_ack;
121
122 const char *module_name;
123 unsigned queue_ids;
124 uint16_t enc_id;
125
126 uint16_t source; /* Encoding source bit mask */
127 uint32_t device_events;
128 uint32_t in_call;
129 uint32_t dev_cnt;
130 int voice_state;
131 spinlock_t dev_lock;
132
133 /* data allocated for various buffers */
134 char *data;
135 dma_addr_t phys;
Santosh Mardifdc227a2011-07-11 17:20:34 +0530136 struct msm_mapped_buffer *map_v_read;
137 struct msm_mapped_buffer *map_v_write;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700138
139 int opened;
140 int enabled;
141 int running;
142 int stopped; /* set when stopped, cleared on flush */
Kalyani polepeddy7413d2b2011-10-14 15:42:15 +0530143 char *build_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700144};
145
146struct audio_frame {
147 uint16_t frame_count_lsw;
148 uint16_t frame_count_msw;
149 uint16_t frame_length;
150 uint16_t erased_pcm;
151 unsigned char raw_bitstream[]; /* samples */
152} __attribute__((packed));
153
154struct audio_frame_nt {
155 uint16_t metadata_len;
156 uint16_t frame_count_lsw;
157 uint16_t frame_count_msw;
158 uint16_t frame_length;
159 uint16_t erased_pcm;
160 uint16_t reserved;
161 uint16_t time_stamp_dword_lsw;
162 uint16_t time_stamp_dword_msw;
163 uint16_t time_stamp_lsw;
164 uint16_t time_stamp_msw;
165 uint16_t nflag_lsw;
166 uint16_t nflag_msw;
167 unsigned char raw_bitstream[]; /* samples */
168} __attribute__((packed));
169
170struct qcelp_encoded_meta_out {
171 uint16_t metadata_len;
172 uint16_t time_stamp_dword_lsw;
173 uint16_t time_stamp_dword_msw;
174 uint16_t time_stamp_lsw;
175 uint16_t time_stamp_msw;
176 uint16_t nflag_lsw;
177 uint16_t nflag_msw;
178};
179
180/* Audrec Queue command sent macro's */
181#define audrec_send_bitstreamqueue(audio, cmd, len) \
182 msm_adsp_write(audio->audrec, ((audio->queue_ids & 0xFFFF0000) >> 16),\
183 cmd, len)
184
185#define audrec_send_audrecqueue(audio, cmd, len) \
186 msm_adsp_write(audio->audrec, (audio->queue_ids & 0x0000FFFF),\
187 cmd, len)
188
189/* DSP command send functions */
190static int audqcelp_in_enc_config(struct audio_in *audio, int enable);
191static int audqcelp_in_param_config(struct audio_in *audio);
192static int audqcelp_in_mem_config(struct audio_in *audio);
193static int audqcelp_in_record_config(struct audio_in *audio, int enable);
194static int audqcelp_dsp_read_buffer(struct audio_in *audio, uint32_t read_cnt);
195
196static void audqcelp_in_get_dsp_frames(struct audio_in *audio);
197static int audpcm_config(struct audio_in *audio);
198static void audqcelp_out_flush(struct audio_in *audio);
199static int audpreproc_cmd_cfg_routing_mode(struct audio_in *audio);
200static void audpreproc_pcm_send_data(struct audio_in *audio, unsigned needed);
201static void audqcelp_nt_in_get_dsp_frames(struct audio_in *audio);
202
203static void audqcelp_in_flush(struct audio_in *audio);
204
205static void qcelp_in_listener(u32 evt_id, union auddev_evt_data *evt_payload,
206 void *private_data)
207{
208 struct audio_in *audio = (struct audio_in *) private_data;
209 unsigned long flags;
210
211 MM_DBG("evt_id = 0x%8x\n", evt_id);
212 switch (evt_id) {
213 case AUDDEV_EVT_DEV_RDY: {
214 MM_DBG("AUDDEV_EVT_DEV_RDY\n");
215 spin_lock_irqsave(&audio->dev_lock, flags);
216 audio->dev_cnt++;
217 if (!audio->in_call)
218 audio->source |= (0x1 << evt_payload->routing_id);
219 spin_unlock_irqrestore(&audio->dev_lock, flags);
220
221 if ((audio->running == 1) && (audio->enabled == 1) &&
222 (audio->mode == MSM_AUD_ENC_MODE_TUNNEL))
223 audqcelp_in_record_config(audio, 1);
224 }
225 break;
226 case AUDDEV_EVT_DEV_RLS: {
227 MM_DBG("AUDDEV_EVT_DEV_RLS\n");
228 spin_lock_irqsave(&audio->dev_lock, flags);
229 audio->dev_cnt--;
230 if (!audio->in_call)
231 audio->source &= ~(0x1 << evt_payload->routing_id);
232 spin_unlock_irqrestore(&audio->dev_lock, flags);
233
234 if ((!audio->running) || (!audio->enabled))
235 break;
236
237 if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
238 /* Turn of as per source */
239 if (audio->source)
240 audqcelp_in_record_config(audio, 1);
241 else
242 /* Turn off all */
243 audqcelp_in_record_config(audio, 0);
244 }
245 }
246 break;
247 case AUDDEV_EVT_VOICE_STATE_CHG: {
248 MM_DBG("AUDDEV_EVT_VOICE_STATE_CHG, state = %d\n",
249 evt_payload->voice_state);
250 audio->voice_state = evt_payload->voice_state;
251 if (audio->in_call && audio->running &&
252 (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)) {
253 if (audio->voice_state == VOICE_STATE_INCALL)
254 audqcelp_in_record_config(audio, 1);
255 else if (audio->voice_state == VOICE_STATE_OFFCALL) {
256 audqcelp_in_record_config(audio, 0);
257 wake_up(&audio->wait);
258 }
259 }
260
261 break;
262 }
263 default:
264 MM_ERR("wrong event %d\n", evt_id);
265 break;
266 }
267}
268
269/* ------------------- dsp preproc event handler--------------------- */
270static void audpreproc_dsp_event(void *data, unsigned id, void *msg)
271{
272 struct audio_in *audio = data;
273
274 switch (id) {
275 case AUDPREPROC_ERROR_MSG: {
276 struct audpreproc_err_msg *err_msg = msg;
277
278 MM_ERR("ERROR_MSG: stream id %d err idx %d\n",
279 err_msg->stream_id, err_msg->aud_preproc_err_idx);
280 /* Error case */
281 wake_up(&audio->wait_enable);
282 break;
283 }
284 case AUDPREPROC_CMD_CFG_DONE_MSG: {
285 MM_DBG("CMD_CFG_DONE_MSG \n");
286 break;
287 }
288 case AUDPREPROC_CMD_ENC_CFG_DONE_MSG: {
289 struct audpreproc_cmd_enc_cfg_done_msg *enc_cfg_msg = msg;
290
291 MM_DBG("CMD_ENC_CFG_DONE_MSG: stream id %d enc type \
292 0x%8x\n", enc_cfg_msg->stream_id,
293 enc_cfg_msg->rec_enc_type);
294 /* Encoder enable success */
295 if (enc_cfg_msg->rec_enc_type & ENCODE_ENABLE) {
296 if(audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) {
297 MM_DBG("routing command\n");
298 audpreproc_cmd_cfg_routing_mode(audio);
299 } else {
300 audqcelp_in_param_config(audio);
301 }
302 } else { /* Encoder disable success */
303 audio->running = 0;
304 if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
305 audqcelp_in_record_config(audio, 0);
306 else
307 wake_up(&audio->wait_enable);
308 }
309 break;
310 }
311 case AUDPREPROC_CMD_ENC_PARAM_CFG_DONE_MSG: {
312 MM_DBG("CMD_ENC_PARAM_CFG_DONE_MSG\n");
313 if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
314 audqcelp_in_mem_config(audio);
315 else
316 audpcm_config(audio);
317 break;
318 }
319 case AUDPREPROC_CMD_ROUTING_MODE_DONE_MSG: {
320 struct audpreproc_cmd_routing_mode_done\
321 *routing_cfg_done_msg = msg;
322 if (routing_cfg_done_msg->configuration == 0) {
323 MM_INFO("routing configuration failed\n");
324 audio->running = 0;
325 } else
326 audqcelp_in_param_config(audio);
327 break;
328 }
329 case AUDPREPROC_AFE_CMD_AUDIO_RECORD_CFG_DONE_MSG: {
330 MM_DBG("AFE_CMD_AUDIO_RECORD_CFG_DONE_MSG \n");
331 wake_up(&audio->wait_enable);
332 break;
333 }
334 default:
335 MM_ERR("Unknown Event id %d\n", id);
336 }
337}
338
339/* ------------------- dsp audrec event handler--------------------- */
340static void audrec_dsp_event(void *data, unsigned id, size_t len,
341 void (*getevent)(void *ptr, size_t len))
342{
343 struct audio_in *audio = data;
344
345 switch (id) {
346 case AUDREC_CMD_MEM_CFG_DONE_MSG: {
347 MM_DBG("CMD_MEM_CFG_DONE MSG DONE\n");
348 audio->running = 1;
349 if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
350 if ((!audio->in_call && (audio->dev_cnt > 0)) ||
351 (audio->in_call &&
352 (audio->voice_state \
353 == VOICE_STATE_INCALL)))
354 audqcelp_in_record_config(audio, 1);
355 } else {
356 audpreproc_pcm_send_data(audio, 1);
357 wake_up(&audio->wait_enable);
358 }
359 break;
360 }
361 case AUDREC_FATAL_ERR_MSG: {
362 struct audrec_fatal_err_msg fatal_err_msg;
363
364 getevent(&fatal_err_msg, AUDREC_FATAL_ERR_MSG_LEN);
365 MM_ERR("FATAL_ERR_MSG: err id %d\n",
366 fatal_err_msg.audrec_err_id);
367 /* Error stop the encoder */
368 audio->stopped = 1;
369 wake_up(&audio->wait);
370 if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL)
371 wake_up(&audio->write_wait);
372 break;
373 }
374 case AUDREC_UP_PACKET_READY_MSG: {
375 struct audrec_up_pkt_ready_msg pkt_ready_msg;
376
377 getevent(&pkt_ready_msg, AUDREC_UP_PACKET_READY_MSG_LEN);
378 MM_DBG("UP_PACKET_READY_MSG: write cnt lsw %d \
379 write cnt msw %d read cnt lsw %d read cnt msw %d \n",\
380 pkt_ready_msg.audrec_packet_write_cnt_lsw, \
381 pkt_ready_msg.audrec_packet_write_cnt_msw, \
382 pkt_ready_msg.audrec_up_prev_read_cnt_lsw, \
383 pkt_ready_msg.audrec_up_prev_read_cnt_msw);
384
385 audqcelp_in_get_dsp_frames(audio);
386 break;
387 }
388 case AUDREC_CMD_PCM_BUFFER_PTR_UPDATE_ARM_TO_ENC_MSG: {
389 MM_DBG("ptr_update recieved from DSP\n");
390 audpreproc_pcm_send_data(audio, 1);
391 break;
392 }
393 case AUDREC_CMD_PCM_CFG_ARM_TO_ENC_DONE_MSG: {
394 MM_ERR("AUDREC_CMD_PCM_CFG_ARM_TO_ENC_DONE_MSG");
395 audqcelp_in_mem_config(audio);
396 break;
397 }
398 case AUDREC_UP_NT_PACKET_READY_MSG: {
399 struct audrec_up_nt_packet_ready_msg pkt_ready_msg;
400
401 getevent(&pkt_ready_msg, AUDREC_UP_NT_PACKET_READY_MSG_LEN);
402 MM_DBG("UP_NT_PACKET_READY_MSG: write cnt lsw %d \
403 write cnt msw %d read cnt lsw %d read cnt msw %d \n",\
404 pkt_ready_msg.audrec_packetwrite_cnt_lsw, \
405 pkt_ready_msg.audrec_packetwrite_cnt_msw, \
406 pkt_ready_msg.audrec_upprev_readcount_lsw, \
407 pkt_ready_msg.audrec_upprev_readcount_msw);
408
409 audqcelp_nt_in_get_dsp_frames(audio);
410 break;
411 }
412 case AUDREC_CMD_EOS_ACK_MSG: {
413 MM_DBG("eos ack recieved\n");
414 break;
415 }
416 case AUDREC_CMD_FLUSH_DONE_MSG: {
417 audio->wflush = 0;
418 audio->rflush = 0;
419 audio->flush_ack = 1;
420 wake_up(&audio->write_wait);
421 MM_DBG("flush ack recieved\n");
422 break;
423 }
424 case ADSP_MESSAGE_ID: {
425 MM_DBG("Received ADSP event:module audrectask\n");
426 break;
427 }
428 default:
429 MM_ERR("Unknown Event id %d\n", id);
430 }
431}
432
433static void audqcelp_in_get_dsp_frames(struct audio_in *audio)
434{
435 struct audio_frame *frame;
436 uint32_t index;
437 unsigned long flags;
438
439 MM_DBG("head = %d\n", audio->in_head);
440 index = audio->in_head;
441
442 frame = (void *) (((char *)audio->in[index].data) - \
443 sizeof(*frame));
444
445 spin_lock_irqsave(&audio->dsp_lock, flags);
446 audio->in[index].size = frame->frame_length;
447
448 /* statistics of read */
449 atomic_add(audio->in[index].size, &audio->in_bytes);
450 atomic_add(1, &audio->in_samples);
451
452 audio->in_head = (audio->in_head + 1) & (FRAME_NUM - 1);
453
454 /* If overflow, move the tail index foward. */
455 if (audio->in_head == audio->in_tail) {
456 MM_ERR("Error! not able to keep up the read\n");
457 audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1);
458 MM_ERR("in_count = %d\n", audio->in_count);
459 } else
460 audio->in_count++;
461
462 audqcelp_dsp_read_buffer(audio, audio->dsp_cnt++);
463 spin_unlock_irqrestore(&audio->dsp_lock, flags);
464
465 wake_up(&audio->wait);
466}
467
468static void audqcelp_nt_in_get_dsp_frames(struct audio_in *audio)
469{
470 struct audio_frame_nt *nt_frame;
471 uint32_t index;
472 unsigned long flags;
473 MM_DBG("head = %d\n", audio->in_head);
474 index = audio->in_head;
475 nt_frame = (void *) (((char *)audio->in[index].data) - \
476 sizeof(struct audio_frame_nt));
477 spin_lock_irqsave(&audio->dsp_lock, flags);
478 audio->in[index].size = nt_frame->frame_length;
479 /* statistics of read */
480 atomic_add(audio->in[index].size, &audio->in_bytes);
481 atomic_add(1, &audio->in_samples);
482
483 audio->in_head = (audio->in_head + 1) & (FRAME_NUM - 1);
484
485 /* If overflow, move the tail index foward. */
486 if (audio->in_head == audio->in_tail)
487 MM_DBG("Error! not able to keep up the read\n");
488 else
489 audio->in_count++;
490
491 spin_unlock_irqrestore(&audio->dsp_lock, flags);
492 wake_up(&audio->wait);
493}
494
495
496struct msm_adsp_ops audrec_qcelp_adsp_ops = {
497 .event = audrec_dsp_event,
498};
499
500static int audpreproc_pcm_buffer_ptr_refresh(struct audio_in *audio,
501 unsigned idx, unsigned len)
502{
503 struct audrec_cmd_pcm_buffer_ptr_refresh_arm_enc cmd;
504
505 if (len == META_OUT_SIZE)
506 len = len / 2;
507 else
508 len = (len + META_OUT_SIZE) / 2;
509 MM_DBG("len = %d\n", len);
510 memset(&cmd, 0, sizeof(cmd));
511 cmd.cmd_id = AUDREC_CMD_PCM_BUFFER_PTR_REFRESH_ARM_TO_ENC;
512 cmd.num_buffers = 1;
513 if (cmd.num_buffers == 1) {
514 cmd.buf_address_length[0] = (audio->out[idx].addr &
515 0xffff0000) >> 16;
516 cmd.buf_address_length[1] = (audio->out[idx].addr &
517 0x0000ffff);
518 cmd.buf_address_length[2] = (len & 0xffff0000) >> 16;
519 cmd.buf_address_length[3] = (len & 0x0000ffff);
520 }
521 audio->out_frame_cnt++;
522 return audrec_send_audrecqueue(audio, (void *)&cmd,
523 (unsigned int)sizeof(cmd));
524}
525
526
527static int audpcm_config(struct audio_in *audio)
528{
529 struct audrec_cmd_pcm_cfg_arm_to_enc cmd;
530 MM_DBG("\n");
531 memset(&cmd, 0, sizeof(cmd));
532 cmd.cmd_id = AUDREC_CMD_PCM_CFG_ARM_TO_ENC;
533 cmd.config_update_flag = AUDREC_PCM_CONFIG_UPDATE_FLAG_ENABLE;
534 cmd.enable_flag = AUDREC_ENABLE_FLAG_VALUE;
535 cmd.sampling_freq = audio->samp_rate;
536 if (!audio->channel_mode)
537 cmd.channels = 1;
538 else
539 cmd.channels = 2;
540 cmd.frequency_of_intimation = 1;
541 cmd.max_number_of_buffers = OUT_FRAME_NUM;
542 return audrec_send_audrecqueue(audio, (void *)&cmd,
543 (unsigned int)sizeof(cmd));
544}
545
546
547static int audpreproc_cmd_cfg_routing_mode(struct audio_in *audio)
548{
549 struct audpreproc_audrec_cmd_routing_mode cmd;
550
551 MM_DBG("\n");
552 memset(&cmd, 0, sizeof(cmd));
553 cmd.cmd_id = AUDPREPROC_AUDREC_CMD_ROUTING_MODE;
554 cmd.stream_id = audio->enc_id;
555 if (audio->mode == MSM_ADSP_ENC_MODE_NON_TUNNEL)
556 cmd.routing_mode = 1;
557 return audpreproc_send_audreccmdqueue(&cmd, sizeof(cmd));
558}
559
560
561
562static int audqcelp_in_enc_config(struct audio_in *audio, int enable)
563{
564 struct audpreproc_audrec_cmd_enc_cfg cmd;
565
566 memset(&cmd, 0, sizeof(cmd));
Kalyani polepeddy7413d2b2011-10-14 15:42:15 +0530567 if (audio->build_id[17] == '1') {
568 cmd.cmd_id = AUDPREPROC_AUDREC_CMD_ENC_CFG_2;
569 MM_ERR("sending AUDPREPROC_AUDREC_CMD_ENC_CFG_2 command");
570 } else {
571 cmd.cmd_id = AUDPREPROC_AUDREC_CMD_ENC_CFG;
572 MM_ERR("sending AUDPREPROC_AUDREC_CMD_ENC_CFG command");
573 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700574 cmd.stream_id = audio->enc_id;
575
576 if (enable)
577 cmd.audrec_enc_type = audio->enc_type | ENCODE_ENABLE;
578 else
579 cmd.audrec_enc_type &= ~(ENCODE_ENABLE);
580
581 return audpreproc_send_audreccmdqueue(&cmd, sizeof(cmd));
582}
583
584static int audqcelp_in_param_config(struct audio_in *audio)
585{
586 struct audpreproc_audrec_cmd_parm_cfg_qcelp13k cmd;
587
588 memset(&cmd, 0, sizeof(cmd));
589 cmd.common.cmd_id = AUDPREPROC_AUDREC_CMD_PARAM_CFG;
590 cmd.common.stream_id = audio->enc_id;
591
592 cmd.enc_min_rate = audio->cfg.min_bit_rate;
593 cmd.enc_max_rate = audio->cfg.max_bit_rate;
594 cmd.rate_modulation_cmd = 0; /* Default set to 0 */
595 cmd.reduced_rate_level = 0; /* Default set to 0 */
596
597 return audpreproc_send_audreccmdqueue(&cmd, sizeof(cmd));
598}
599
600/* To Do: msm_snddev_route_enc(audio->enc_id); */
601static int audqcelp_in_record_config(struct audio_in *audio, int enable)
602{
603 struct audpreproc_afe_cmd_audio_record_cfg cmd;
604 memset(&cmd, 0, sizeof(cmd));
605 cmd.cmd_id = AUDPREPROC_AFE_CMD_AUDIO_RECORD_CFG;
606 cmd.stream_id = audio->enc_id;
607 if (enable)
608 cmd.destination_activity = AUDIO_RECORDING_TURN_ON;
609 else
610 cmd.destination_activity = AUDIO_RECORDING_TURN_OFF;
611
612 cmd.source_mix_mask = audio->source;
613 if (audio->enc_id == 2) {
614 if ((cmd.source_mix_mask &
615 INTERNAL_CODEC_TX_SOURCE_MIX_MASK) ||
616 (cmd.source_mix_mask & AUX_CODEC_TX_SOURCE_MIX_MASK) ||
617 (cmd.source_mix_mask & VOICE_UL_SOURCE_MIX_MASK) ||
618 (cmd.source_mix_mask & VOICE_DL_SOURCE_MIX_MASK)) {
619 cmd.pipe_id = SOURCE_PIPE_1;
620 }
621 if (cmd.source_mix_mask &
622 AUDPP_A2DP_PIPE_SOURCE_MIX_MASK)
623 cmd.pipe_id |= SOURCE_PIPE_0;
624 }
625 MM_DBG("stream_id %x destination_activity %x \
626 source_mix_mask %x pipe_id %x",\
627 cmd.stream_id, cmd.destination_activity,
628 cmd.source_mix_mask, cmd.pipe_id);
629 return audpreproc_send_audreccmdqueue(&cmd, sizeof(cmd));
630}
631
632static int audqcelp_in_mem_config(struct audio_in *audio)
633{
634 struct audrec_cmd_arecmem_cfg cmd;
635 uint16_t *data = (void *) audio->data;
636 int n;
637
638 memset(&cmd, 0, sizeof(cmd));
639 cmd.cmd_id = AUDREC_CMD_MEM_CFG_CMD;
640 cmd.audrec_up_pkt_intm_count = 1;
641 cmd.audrec_ext_pkt_start_addr_msw = audio->phys >> 16;
642 cmd.audrec_ext_pkt_start_addr_lsw = audio->phys;
643 cmd.audrec_ext_pkt_buf_number = FRAME_NUM;
644 MM_DBG("audio->phys = %x\n", audio->phys);
645 /* prepare buffer pointers:
646 * T:36 bytes qcelp ppacket + 4 halfword header
647 * NT:36 bytes qcelp packet + 12 halfword header
648 */
649 for (n = 0; n < FRAME_NUM; n++) {
650 if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
651 audio->in[n].data = data + 4;
652 data += (FRAME_SIZE/2);
653 MM_DBG("0x%8x\n", (int)(audio->in[n].data - 8));
654 } else {
655 audio->in[n].data = data + 12;
656 data += ((QCELP_FRAME_SIZE) / 2) + 12;
657 MM_DBG("0x%8x\n", (int)(audio->in[n].data - 24));
658 }
659 }
660 return audrec_send_audrecqueue(audio, &cmd, sizeof(cmd));
661}
662
663static int audqcelp_dsp_read_buffer(struct audio_in *audio, uint32_t read_cnt)
664{
665 struct up_audrec_packet_ext_ptr cmd;
666
667 memset(&cmd, 0, sizeof(cmd));
668 cmd.cmd_id = UP_AUDREC_PACKET_EXT_PTR;
669 cmd.audrec_up_curr_read_count_msw = read_cnt >> 16;
670 cmd.audrec_up_curr_read_count_lsw = read_cnt;
671
672 return audrec_send_bitstreamqueue(audio, &cmd, sizeof(cmd));
673}
674static int audqcelp_flush_command(struct audio_in *audio)
675{
676 struct audrec_cmd_flush cmd;
677 MM_DBG("\n");
678 memset(&cmd, 0, sizeof(cmd));
679 cmd.cmd_id = AUDREC_CMD_FLUSH;
680 return audrec_send_audrecqueue(audio, &cmd, sizeof(cmd));
681}
682
683/* must be called with audio->lock held */
684static int audqcelp_in_enable(struct audio_in *audio)
685{
686 if (audio->enabled)
687 return 0;
688
689 if (audpreproc_enable(audio->enc_id, &audpreproc_dsp_event, audio)) {
690 MM_ERR("msm_adsp_enable(audpreproc) failed\n");
691 return -ENODEV;
692 }
693
694 if (msm_adsp_enable(audio->audrec)) {
695 MM_ERR("msm_adsp_enable(audrec) failed\n");
696 audpreproc_disable(audio->enc_id, audio);
697 return -ENODEV;
698 }
699 audio->enabled = 1;
700 audqcelp_in_enc_config(audio, 1);
701
702 return 0;
703}
704
705/* must be called with audio->lock held */
706static int audqcelp_in_disable(struct audio_in *audio)
707{
708 if (audio->enabled) {
709 audio->enabled = 0;
710 audqcelp_in_enc_config(audio, 0);
711 wake_up(&audio->wait);
712 wait_event_interruptible_timeout(audio->wait_enable,
713 audio->running == 0, 1*HZ);
714 msm_adsp_disable(audio->audrec);
715 audpreproc_disable(audio->enc_id, audio);
716 }
717 return 0;
718}
719
720static void audqcelp_ioport_reset(struct audio_in *audio)
721{
722 /* Make sure read/write thread are free from
723 * sleep and knowing that system is not able
724 * to process io request at the moment
725 */
726 wake_up(&audio->write_wait);
727 mutex_lock(&audio->write_lock);
728 audqcelp_in_flush(audio);
729 mutex_unlock(&audio->write_lock);
730 wake_up(&audio->wait);
731 mutex_lock(&audio->read_lock);
732 audqcelp_out_flush(audio);
733 mutex_unlock(&audio->read_lock);
734}
735
736static void audqcelp_in_flush(struct audio_in *audio)
737{
738 int i;
739
740 audio->dsp_cnt = 0;
741 audio->in_head = 0;
742 audio->in_tail = 0;
743 audio->in_count = 0;
744 audio->eos_ack = 0;
745 for (i = 0; i < FRAME_NUM; i++) {
746 audio->in[i].size = 0;
747 audio->in[i].read = 0;
748 }
749 MM_DBG("in_bytes %d\n", atomic_read(&audio->in_bytes));
750 MM_DBG("in_samples %d\n", atomic_read(&audio->in_samples));
751 atomic_set(&audio->in_bytes, 0);
752 atomic_set(&audio->in_samples, 0);
753}
754
755static void audqcelp_out_flush(struct audio_in *audio)
756{
757 int i;
758
759 audio->out_head = 0;
760 audio->out_tail = 0;
761 audio->out_count = 0;
762 for (i = 0; i < OUT_FRAME_NUM; i++) {
763 audio->out[i].size = 0;
764 audio->out[i].read = 0;
765 audio->out[i].used = 0;
766 }
767}
768
769/* ------------------- device --------------------- */
770static long audqcelp_in_ioctl(struct file *file,
771 unsigned int cmd, unsigned long arg)
772{
773 struct audio_in *audio = file->private_data;
774 int rc = 0;
775
776 MM_DBG("\n");
777 if (cmd == AUDIO_GET_STATS) {
778 struct msm_audio_stats stats;
779 stats.byte_count = atomic_read(&audio->in_bytes);
780 stats.sample_count = atomic_read(&audio->in_samples);
781 if (copy_to_user((void *) arg, &stats, sizeof(stats)))
782 return -EFAULT;
783 return rc;
784 }
785
786 mutex_lock(&audio->lock);
787 switch (cmd) {
788 case AUDIO_START: {
789 uint32_t freq;
790 freq = 48000;
791 MM_DBG("AUDIO_START\n");
792 if (audio->in_call && (audio->voice_state !=
793 VOICE_STATE_INCALL)) {
794 rc = -EPERM;
795 break;
796 }
797 rc = msm_snddev_request_freq(&freq, audio->enc_id,
798 SNDDEV_CAP_TX, AUDDEV_CLNT_ENC);
799 MM_DBG("sample rate configured %d\n", freq);
800 if (rc < 0) {
801 MM_DBG(" Sample rate can not be set, return code %d\n",
802 rc);
803 msm_snddev_withdraw_freq(audio->enc_id,
804 SNDDEV_CAP_TX, AUDDEV_CLNT_ENC);
805 MM_DBG("msm_snddev_withdraw_freq\n");
806 break;
807 }
808 /*update aurec session info in audpreproc layer*/
809 audio->session_info.session_id = audio->enc_id;
810 audio->session_info.sampling_freq = audio->samp_rate;
811 audpreproc_update_audrec_info(&audio->session_info);
812 rc = audqcelp_in_enable(audio);
813 if (!rc) {
814 rc =
815 wait_event_interruptible_timeout(audio->wait_enable,
816 audio->running != 0, 1*HZ);
817 MM_DBG("state %d rc = %d\n", audio->running, rc);
818
819 if (audio->running == 0)
820 rc = -ENODEV;
821 else
822 rc = 0;
823 }
824 audio->stopped = 0;
825 break;
826 }
827 case AUDIO_STOP: {
828 /*reset the sampling frequency information at audpreproc layer*/
829 audio->session_info.sampling_freq = 0;
830 audpreproc_update_audrec_info(&audio->session_info);
831 rc = audqcelp_in_disable(audio);
832 rc = msm_snddev_withdraw_freq(audio->enc_id,
833 SNDDEV_CAP_TX, AUDDEV_CLNT_ENC);
834 MM_DBG("msm_snddev_withdraw_freq\n");
835 audio->stopped = 1;
836 break;
837 }
838 case AUDIO_FLUSH: {
839 MM_DBG("AUDIO_FLUSH\n");
840 audio->rflush = 1;
841 audio->wflush = 1;
842 audqcelp_ioport_reset(audio);
843 if (audio->running) {
844 audqcelp_flush_command(audio);
845 rc = wait_event_interruptible(audio->write_wait,
846 !audio->wflush);
847 if (rc < 0) {
848 MM_ERR("AUDIO_FLUSH interrupted\n");
849 rc = -EINTR;
850 }
851 } else {
852 audio->rflush = 0;
853 audio->wflush = 0;
854 }
855 break;
856 }
857 case AUDIO_SET_STREAM_CONFIG: {
858 struct msm_audio_stream_config cfg;
859 if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) {
860 rc = -EFAULT;
861 break;
862 }
863 /* Allow only single frame */
864 if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
865 if (cfg.buffer_size != (FRAME_SIZE - 8)) {
866 rc = -EINVAL;
867 break;
868 }
869 } else {
870 if (cfg.buffer_size != (QCELP_FRAME_SIZE + 14)) {
871 rc = -EINVAL;
872 break;
873 }
874 }
875 audio->buffer_size = cfg.buffer_size;
876 break;
877 }
878 case AUDIO_GET_STREAM_CONFIG: {
879 struct msm_audio_stream_config cfg;
880 memset(&cfg, 0, sizeof(cfg));
881 cfg.buffer_size = audio->buffer_size;
882 cfg.buffer_count = FRAME_NUM;
883 if (copy_to_user((void *) arg, &cfg, sizeof(cfg)))
884 rc = -EFAULT;
885 break;
886 }
887 case AUDIO_GET_QCELP_ENC_CONFIG: {
888 if (copy_to_user((void *) arg, &audio->cfg, sizeof(audio->cfg)))
889 rc = -EFAULT;
890 break;
891 }
892 case AUDIO_SET_QCELP_ENC_CONFIG: {
893 struct msm_audio_qcelp_enc_config cfg;
894 if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) {
895 rc = -EFAULT;
896 break;
897 }
898 MM_DBG("0X%8x, 0x%8x, 0x%8x\n", cfg.min_bit_rate, \
899 cfg.max_bit_rate, cfg.cdma_rate);
900 if (cfg.min_bit_rate > CDMA_RATE_FULL || \
901 cfg.min_bit_rate < CDMA_RATE_EIGHTH) {
902 MM_ERR("invalid min bitrate\n");
903 rc = -EFAULT;
904 break;
905 }
906 if (cfg.max_bit_rate > CDMA_RATE_FULL || \
907 cfg.max_bit_rate < CDMA_RATE_EIGHTH) {
908 MM_ERR("invalid max bitrate\n");
909 rc = -EFAULT;
910 break;
911 }
912 /* Recording Does not support Erase and Blank */
913 if (cfg.cdma_rate > CDMA_RATE_FULL ||
914 cfg.cdma_rate < CDMA_RATE_EIGHTH) {
915 MM_ERR("invalid qcelp cdma rate\n");
916 rc = -EFAULT;
917 break;
918 }
919 memcpy(&audio->cfg, &cfg, sizeof(cfg));
920 break;
921 }
922 case AUDIO_GET_CONFIG: {
923 struct msm_audio_config cfg;
924 memset(&cfg, 0, sizeof(cfg));
925 cfg.buffer_size = OUT_BUFFER_SIZE;
926 cfg.buffer_count = OUT_FRAME_NUM;
927 cfg.sample_rate = audio->samp_rate;
928 cfg.channel_count = audio->channel_mode;
929 if (copy_to_user((void *)arg, &cfg, sizeof(cfg)))
930 rc = -EFAULT;
931 break;
932 }
933 case AUDIO_SET_INCALL: {
934 struct msm_voicerec_mode cfg;
935 unsigned long flags;
936 if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
937 if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) {
938 rc = -EFAULT;
939 break;
940 }
941 if (cfg.rec_mode != VOC_REC_BOTH &&
942 cfg.rec_mode != VOC_REC_UPLINK &&
943 cfg.rec_mode != VOC_REC_DOWNLINK) {
944 MM_ERR("invalid rec_mode\n");
945 rc = -EINVAL;
946 break;
947 } else {
948 spin_lock_irqsave(&audio->dev_lock, flags);
949 if (cfg.rec_mode == VOC_REC_UPLINK)
950 audio->source = \
951 VOICE_UL_SOURCE_MIX_MASK;
952 else if (cfg.rec_mode == VOC_REC_DOWNLINK)
953 audio->source = \
954 VOICE_DL_SOURCE_MIX_MASK;
955 else
956 audio->source = \
957 VOICE_DL_SOURCE_MIX_MASK |
958 VOICE_UL_SOURCE_MIX_MASK ;
959 audio->in_call = 1;
960 spin_unlock_irqrestore(&audio->dev_lock, flags);
961 }
962 }
963 break;
964 }
965 case AUDIO_GET_SESSION_ID: {
966 if (copy_to_user((void *) arg, &audio->enc_id,
967 sizeof(unsigned short))) {
968 rc = -EFAULT;
969 }
970 break;
971 }
972 default:
973 rc = -EINVAL;
974 }
975 mutex_unlock(&audio->lock);
976 return rc;
977}
978
979static ssize_t audqcelp_in_read(struct file *file,
980 char __user *buf,
981 size_t count, loff_t *pos)
982{
983 struct audio_in *audio = file->private_data;
984 unsigned long flags;
985 const char __user *start = buf;
986 void *data;
987 uint32_t index;
988 uint32_t size;
989 int rc = 0;
990 struct qcelp_encoded_meta_out meta_field;
991 struct audio_frame_nt *nt_frame;
992 MM_DBG(" count = %d\n", count);
993 mutex_lock(&audio->read_lock);
994 while (count > 0) {
995 rc = wait_event_interruptible(
996 audio->wait, (audio->in_count > 0) || audio->stopped ||
997 audio->rflush ||
998 ((audio->mode == MSM_AUD_ENC_MODE_TUNNEL) &&
999 audio->in_call && audio->running &&
1000 (audio->voice_state == VOICE_STATE_OFFCALL)));
1001 if (rc < 0)
1002 break;
1003
1004 if (audio->rflush) {
1005 rc = -EBUSY;
1006 break;
1007 }
1008 if (audio->stopped && !audio->in_count) {
1009 MM_DBG("Driver in stop state, No more buffer to read");
1010 rc = 0;/* End of File */
1011 break;
1012 } else if ((audio->mode == MSM_AUD_ENC_MODE_TUNNEL) &&
1013 audio->in_call && audio->running &&
1014 (audio->voice_state \
1015 == VOICE_STATE_OFFCALL)) {
1016 MM_DBG("Not Permitted Voice Terminated\n");
1017 rc = -EPERM; /* Voice Call stopped */
1018 break;
1019 }
1020
1021 index = audio->in_tail;
1022 data = (uint8_t *) audio->in[index].data;
1023 size = audio->in[index].size;
1024
1025 if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) {
1026 nt_frame = (struct audio_frame_nt *)(data -
1027 sizeof(struct audio_frame_nt));
1028 memcpy((char *)&meta_field.time_stamp_dword_lsw,
1029 (char *)&nt_frame->time_stamp_dword_lsw,
1030 (sizeof(struct qcelp_encoded_meta_out) - \
1031 sizeof(uint16_t)));
1032 meta_field.metadata_len =
1033 sizeof(struct qcelp_encoded_meta_out);
1034 if (copy_to_user((char *)start,
1035 (char *)&meta_field,
1036 sizeof(struct qcelp_encoded_meta_out))) {
1037 rc = -EFAULT;
1038 break;
1039 }
1040 if (nt_frame->nflag_lsw & 0x0001) {
1041 MM_ERR("recieved EOS in read call\n");
1042 audio->eos_ack = 1;
1043 }
1044 buf += sizeof(struct qcelp_encoded_meta_out);
1045 count -= sizeof(struct qcelp_encoded_meta_out);
1046 }
1047 if (count >= size) {
1048 if (copy_to_user(buf, data, size)) {
1049 rc = -EFAULT;
1050 break;
1051 }
1052 spin_lock_irqsave(&audio->dsp_lock, flags);
1053 if (index != audio->in_tail) {
1054 /* overrun -- data is
1055 * invalid and we need to retry */
1056 spin_unlock_irqrestore(&audio->dsp_lock, flags);
1057 continue;
1058 }
1059 audio->in[index].size = 0;
1060 audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1);
1061 audio->in_count--;
1062 spin_unlock_irqrestore(&audio->dsp_lock, flags);
1063 count -= size;
1064 buf += size;
1065 if ((audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL)) {
1066 if (!audio->eos_ack) {
1067 MM_DBG("sending read ptr command\
1068 %d %d\n",
1069 audio->dsp_cnt,
1070 audio->in_tail);
1071 audqcelp_dsp_read_buffer(audio,
1072 audio->dsp_cnt++);
1073 }
1074 }
1075 } else {
1076 MM_ERR("short read\n");
1077 break;
1078 }
1079 break;
1080 }
1081 mutex_unlock(&audio->read_lock);
1082
1083 if (buf > start)
1084 return buf - start;
1085
1086 return rc;
1087}
1088
1089static void audpreproc_pcm_send_data(struct audio_in *audio, unsigned needed)
1090{
1091 struct buffer *frame;
1092 unsigned long flags;
1093 MM_DBG("\n");
1094 spin_lock_irqsave(&audio->dsp_lock, flags);
1095 if (!audio->running)
1096 goto done;
1097
1098 if (needed && !audio->wflush) {
1099 /* We were called from the callback because the DSP
1100 * requested more data. Note that the DSP does want
1101 * more data, and if a buffer was in-flight, mark it
1102 * as available (since the DSP must now be done with
1103 * it).
1104 */
1105 audio->out_needed = 1;
1106 frame = audio->out + audio->out_tail;
1107 if (frame->used == 0xffffffff) {
1108 MM_DBG("frame %d free\n", audio->out_tail);
1109 frame->used = 0;
1110 audio->out_tail ^= 1;
1111 wake_up(&audio->write_wait);
1112 }
1113 }
1114
1115 if (audio->out_needed) {
1116 /* If the DSP currently wants data and we have a
1117 * buffer available, we will send it and reset
1118 * the needed flag. We'll mark the buffer as in-flight
1119 * so that it won't be recycled until the next buffer
1120 * is requested
1121 */
1122
1123 frame = audio->out + audio->out_tail;
1124 if (frame->used) {
1125 BUG_ON(frame->used == 0xffffffff);
1126 audpreproc_pcm_buffer_ptr_refresh(audio,
1127 audio->out_tail,
1128 frame->used);
1129 frame->used = 0xffffffff;
1130 audio->out_needed = 0;
1131 }
1132 }
1133 done:
1134 spin_unlock_irqrestore(&audio->dsp_lock, flags);
1135}
1136
1137
1138static int audqcelp_in_fsync(struct file *file, int datasync)
1139
1140{
1141 struct audio_in *audio = file->private_data;
1142 int rc = 0;
1143
1144 MM_DBG("\n"); /* Macro prints the file name and function */
1145 if (!audio->running || (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)) {
1146 rc = -EINVAL;
1147 goto done_nolock;
1148 }
1149
1150 mutex_lock(&audio->write_lock);
1151
1152 rc = wait_event_interruptible(audio->write_wait,
1153 audio->wflush);
1154 MM_DBG("waked on by some event audio->wflush = %d\n", audio->wflush);
1155
1156 if (rc < 0)
1157 goto done;
1158 else if (audio->wflush) {
1159 rc = -EBUSY;
1160 goto done;
1161 }
1162done:
1163 mutex_unlock(&audio->write_lock);
1164done_nolock:
1165 return rc;
1166
1167}
1168
1169 int audpreproc_qcelp_process_eos(struct audio_in *audio,
1170 const char __user *buf_start, unsigned short mfield_size)
1171{
1172 struct buffer *frame;
1173 int rc = 0;
1174
1175 frame = audio->out + audio->out_head;
1176
1177 rc = wait_event_interruptible(audio->write_wait,
1178 (audio->out_needed &&
1179 audio->out[0].used == 0 &&
1180 audio->out[1].used == 0)
1181 || (audio->stopped)
1182 || (audio->wflush));
1183
1184 if (rc < 0)
1185 goto done;
1186 if (audio->stopped || audio->wflush) {
1187 rc = -EBUSY;
1188 goto done;
1189 }
1190 if (copy_from_user(frame->data, buf_start, mfield_size)) {
1191 rc = -EFAULT;
1192 goto done;
1193 }
1194
1195 frame->mfield_sz = mfield_size;
1196 audio->out_head ^= 1;
1197 frame->used = mfield_size;
1198 MM_DBG("copying meta_out frame->used = %d\n", frame->used);
1199 audpreproc_pcm_send_data(audio, 0);
1200done:
1201 return rc;
1202}
1203
1204static ssize_t audqcelp_in_write(struct file *file,
1205 const char __user *buf,
1206 size_t count, loff_t *pos)
1207{
1208 struct audio_in *audio = file->private_data;
1209 const char __user *start = buf;
1210 struct buffer *frame;
1211 char *cpy_ptr;
1212 int rc = 0, eos_condition = AUDPREPROC_QCELP_EOS_NONE;
1213 unsigned short mfield_size = 0;
1214 int write_count = 0;
1215
1216 MM_DBG("cnt=%d\n", count);
1217 if (count & 1)
1218 return -EINVAL;
1219
1220 if (audio->mode != MSM_AUD_ENC_MODE_NONTUNNEL)
1221 return -EINVAL;
1222
1223 mutex_lock(&audio->write_lock);
1224 frame = audio->out + audio->out_head;
1225 /* if supplied count is more than driver buffer size
1226 * then only copy driver buffer size
1227 */
1228 if (count > frame->size)
1229 count = frame->size;
1230
1231 write_count = count;
1232 cpy_ptr = frame->data;
1233 rc = wait_event_interruptible(audio->write_wait,
1234 (frame->used == 0)
1235 || (audio->stopped)
1236 || (audio->wflush));
1237 if (rc < 0)
1238 goto error;
1239
1240 if (audio->stopped || audio->wflush) {
1241 rc = -EBUSY;
1242 goto error;
1243 }
1244 if (audio->mfield) {
1245 if (buf == start) {
1246 /* Processing beginning of user buffer */
1247 if (__get_user(mfield_size,
1248 (unsigned short __user *) buf)) {
1249 rc = -EFAULT;
1250 goto error;
1251 } else if (mfield_size > count) {
1252 rc = -EINVAL;
1253 goto error;
1254 }
1255 MM_DBG("mf offset_val %x\n", mfield_size);
1256 if (copy_from_user(cpy_ptr, buf, mfield_size)) {
1257 rc = -EFAULT;
1258 goto error;
1259 }
1260 /* Check if EOS flag is set and buffer has
1261 * contains just meta field
1262 */
1263 if (cpy_ptr[AUDPREPROC_QCELP_EOS_FLG_OFFSET] &
1264 AUDPREPROC_QCELP_EOS_FLG_MASK) {
1265 eos_condition = AUDPREPROC_QCELP_EOS_SET;
1266 MM_DBG("EOS SET\n");
1267 if (mfield_size == count) {
1268 buf += mfield_size;
1269 eos_condition = 0;
1270 goto exit;
1271 } else
1272 cpy_ptr[AUDPREPROC_QCELP_EOS_FLG_OFFSET] &=
1273 ~AUDPREPROC_QCELP_EOS_FLG_MASK;
1274 }
1275 cpy_ptr += mfield_size;
1276 count -= mfield_size;
1277 buf += mfield_size;
1278 } else {
1279 mfield_size = 0;
1280 MM_DBG("continuous buffer\n");
1281 }
1282 frame->mfield_sz = mfield_size;
1283 }
1284 MM_DBG("copying the stream count = %d\n", count);
1285 if (copy_from_user(cpy_ptr, buf, count)) {
1286 rc = -EFAULT;
1287 goto error;
1288 }
1289exit:
1290 frame->used = count;
1291 audio->out_head ^= 1;
1292 if (!audio->flush_ack)
1293 audpreproc_pcm_send_data(audio, 0);
1294 else {
1295 audpreproc_pcm_send_data(audio, 1);
1296 audio->flush_ack = 0;
1297 }
1298 if (eos_condition == AUDPREPROC_QCELP_EOS_SET)
1299 rc = audpreproc_qcelp_process_eos(audio, start, mfield_size);
1300 mutex_unlock(&audio->write_lock);
1301 return write_count;
1302error:
1303 mutex_unlock(&audio->write_lock);
1304 return rc;
1305}
1306
1307static int audqcelp_in_release(struct inode *inode, struct file *file)
1308{
1309 struct audio_in *audio = file->private_data;
1310
1311 mutex_lock(&audio->lock);
1312 audio->in_call = 0;
1313 /* with draw frequency for session
1314 incase not stopped the driver */
1315 msm_snddev_withdraw_freq(audio->enc_id, SNDDEV_CAP_TX,
1316 AUDDEV_CLNT_ENC);
1317 auddev_unregister_evt_listner(AUDDEV_CLNT_ENC, audio->enc_id);
1318 /*reset the sampling frequency information at audpreproc layer*/
1319 audio->session_info.sampling_freq = 0;
1320 audpreproc_update_audrec_info(&audio->session_info);
1321 audqcelp_in_disable(audio);
1322 audqcelp_in_flush(audio);
1323 msm_adsp_put(audio->audrec);
1324 audpreproc_aenc_free(audio->enc_id);
1325 audio->audrec = NULL;
1326 audio->opened = 0;
1327 if (audio->data) {
Santosh Mardifdc227a2011-07-11 17:20:34 +05301328 msm_subsystem_unmap_buffer(audio->map_v_read);
1329 free_contiguous_memory_by_paddr(audio->phys);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001330 audio->data = NULL;
1331 }
1332 if (audio->out_data) {
Santosh Mardifdc227a2011-07-11 17:20:34 +05301333 msm_subsystem_unmap_buffer(audio->map_v_write);
1334 free_contiguous_memory_by_paddr(audio->out_phys);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001335 audio->out_data = NULL;
1336 }
1337 mutex_unlock(&audio->lock);
1338 return 0;
1339}
1340
1341struct audio_in the_audio_qcelp_in;
1342static int audqcelp_in_open(struct inode *inode, struct file *file)
1343{
1344 struct audio_in *audio = &the_audio_qcelp_in;
1345 int rc;
1346 int encid;
1347
1348 mutex_lock(&audio->lock);
1349 if (audio->opened) {
1350 rc = -EBUSY;
1351 goto done;
1352 }
Santosh Mardifdc227a2011-07-11 17:20:34 +05301353 audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
1354 if (audio->phys) {
1355 audio->map_v_read = msm_subsystem_map_buffer(
1356 audio->phys, DMASZ,
1357 MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
1358 if (IS_ERR(audio->map_v_read)) {
1359 MM_ERR("could not map DMA buffers\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001360 rc = -ENOMEM;
Santosh Mardifdc227a2011-07-11 17:20:34 +05301361 free_contiguous_memory_by_paddr(audio->phys);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001362 goto done;
1363 }
Santosh Mardifdc227a2011-07-11 17:20:34 +05301364 audio->data = audio->map_v_read->vaddr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001365 } else {
1366 MM_ERR("could not allocate DMA buffers\n");
1367 rc = -ENOMEM;
1368 goto done;
1369 }
1370 MM_DBG("Memory addr = 0x%8x phy addr = 0x%8x\n",\
1371 (int) audio->data, (int) audio->phys);
1372 if ((file->f_mode & FMODE_WRITE) &&
1373 (file->f_mode & FMODE_READ)) {
1374 audio->mode = MSM_AUD_ENC_MODE_NONTUNNEL;
1375 MM_DBG("Opened for non tunnel mode encoding\n");
1376 } else if (!(file->f_mode & FMODE_WRITE) &&
1377 (file->f_mode & FMODE_READ)) {
1378 audio->mode = MSM_AUD_ENC_MODE_TUNNEL;
1379 MM_DBG("Opened for tunnel mode encoding\n");
1380 } else {
1381 MM_ERR("Invalid mode\n");
1382 rc = -EACCES;
1383 goto done;
1384 }
1385
1386 /* Settings will be re-config at AUDIO_SET_CONFIG,
1387 * but at least we need to have initial config
1388 */
1389 if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL)
1390 audio->buffer_size = (QCELP_FRAME_SIZE + 14);
1391 else
1392 audio->buffer_size = (FRAME_SIZE - 8);
1393 audio->enc_type = ENC_TYPE_V13K | audio->mode;
1394 audio->samp_rate = 8000;
1395 audio->channel_mode = AUDREC_CMD_MODE_MONO;
1396 audio->cfg.cdma_rate = CDMA_RATE_FULL;
1397 audio->cfg.min_bit_rate = CDMA_RATE_FULL;
1398 audio->cfg.max_bit_rate = CDMA_RATE_FULL;
1399 audio->source = INTERNAL_CODEC_TX_SOURCE_MIX_MASK;
1400 audio->rec_mode = VOC_REC_UPLINK;
1401
1402 encid = audpreproc_aenc_alloc(audio->enc_type, &audio->module_name,
1403 &audio->queue_ids);
1404 if (encid < 0) {
1405 MM_ERR("No free encoder available\n");
1406 rc = -ENODEV;
1407 goto done;
1408 }
1409 audio->enc_id = encid;
1410
1411 rc = msm_adsp_get(audio->module_name, &audio->audrec,
1412 &audrec_qcelp_adsp_ops, audio);
1413
1414 if (rc) {
1415 audpreproc_aenc_free(audio->enc_id);
1416 goto done;
1417 }
1418
1419 audio->stopped = 0;
1420 audio->source = 0;
1421 audio->wflush = 0;
1422 audio->rflush = 0;
1423 audio->flush_ack = 0;
1424
1425 audqcelp_in_flush(audio);
1426 audqcelp_out_flush(audio);
1427
Santosh Mardifdc227a2011-07-11 17:20:34 +05301428 audio->out_phys = allocate_contiguous_ebi_nomap(BUFFER_SIZE, SZ_4K);
1429 if (!audio->out_phys) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001430 MM_ERR("could not allocate write buffers\n");
1431 rc = -ENOMEM;
1432 goto evt_error;
1433 } else {
Santosh Mardifdc227a2011-07-11 17:20:34 +05301434 audio->map_v_write = msm_subsystem_map_buffer(
1435 audio->out_phys, BUFFER_SIZE,
1436 MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
1437 if (IS_ERR(audio->map_v_write)) {
1438 MM_ERR("could not map write buffers\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001439 rc = -ENOMEM;
Santosh Mardifdc227a2011-07-11 17:20:34 +05301440 free_contiguous_memory_by_paddr(audio->out_phys);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001441 goto evt_error;
1442 }
Santosh Mardifdc227a2011-07-11 17:20:34 +05301443 audio->out_data = audio->map_v_write->vaddr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001444 MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
1445 audio->out_phys, (int)audio->out_data);
1446 }
1447
1448 /* Initialize buffer */
1449 audio->out[0].data = audio->out_data + 0;
1450 audio->out[0].addr = audio->out_phys + 0;
1451 audio->out[0].size = OUT_BUFFER_SIZE;
1452
1453 audio->out[1].data = audio->out_data + OUT_BUFFER_SIZE;
1454 audio->out[1].addr = audio->out_phys + OUT_BUFFER_SIZE;
1455 audio->out[1].size = OUT_BUFFER_SIZE;
1456
1457 MM_DBG("audio->out[0].data = %d audio->out[1].data = %d",
1458 (unsigned int)audio->out[0].data,
1459 (unsigned int)audio->out[1].data);
1460 audio->device_events = AUDDEV_EVT_DEV_RDY | AUDDEV_EVT_DEV_RLS |
1461 AUDDEV_EVT_VOICE_STATE_CHG;
1462
1463 audio->voice_state = msm_get_voice_state();
1464 rc = auddev_register_evt_listner(audio->device_events,
1465 AUDDEV_CLNT_ENC, audio->enc_id,
1466 qcelp_in_listener, (void *) audio);
1467 if (rc) {
1468 MM_ERR("failed to register device event listener\n");
Santosh Mardifdc227a2011-07-11 17:20:34 +05301469 msm_subsystem_unmap_buffer(audio->map_v_write);
1470 free_contiguous_memory_by_paddr(audio->out_phys);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001471 goto evt_error;
1472 }
1473 audio->mfield = META_OUT_SIZE;
1474 file->private_data = audio;
1475 audio->opened = 1;
1476 audio->out_frame_cnt++;
Kalyani polepeddy7413d2b2011-10-14 15:42:15 +05301477 audio->build_id = socinfo_get_build_id();
Vinay Vaka4ff52a62011-12-13 15:38:35 +05301478 MM_DBG("Modem build id = %s\n", audio->build_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001479done:
1480 mutex_unlock(&audio->lock);
1481 return rc;
1482evt_error:
1483 msm_adsp_put(audio->audrec);
1484 audpreproc_aenc_free(audio->enc_id);
1485 mutex_unlock(&audio->lock);
1486 return rc;
1487}
1488
1489static const struct file_operations audio_in_fops = {
1490 .owner = THIS_MODULE,
1491 .open = audqcelp_in_open,
1492 .release = audqcelp_in_release,
1493 .read = audqcelp_in_read,
1494 .write = audqcelp_in_write,
1495 .fsync = audqcelp_in_fsync,
1496 .unlocked_ioctl = audqcelp_in_ioctl,
1497};
1498
1499struct miscdevice audio_qcelp_in_misc = {
1500 .minor = MISC_DYNAMIC_MINOR,
1501 .name = "msm_qcelp_in",
1502 .fops = &audio_in_fops,
1503};
1504
1505static int __init audqcelp_in_init(void)
1506{
1507 mutex_init(&the_audio_qcelp_in.lock);
1508 mutex_init(&the_audio_qcelp_in.read_lock);
1509 spin_lock_init(&the_audio_qcelp_in.dsp_lock);
1510 spin_lock_init(&the_audio_qcelp_in.dev_lock);
1511 init_waitqueue_head(&the_audio_qcelp_in.wait);
1512 init_waitqueue_head(&the_audio_qcelp_in.wait_enable);
1513 mutex_init(&the_audio_qcelp_in.write_lock);
1514 init_waitqueue_head(&the_audio_qcelp_in.write_wait);
1515 return misc_register(&audio_qcelp_in_misc);
1516}
1517
1518device_initcall(audqcelp_in_init);