blob: 99a169dff1356669007e684ab5289826f88cf9dc [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
2 *
3 * qcelp audio input device
4 *
Manish Dewangana4f1df02012-02-08 17:06:54 +05305 * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006 *
7 * This code is based in part on arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c,
8 * Copyright (C) 2008 Google, Inc.
9 * Copyright (C) 2008 HTC Corporation
10 *
11 * This software is licensed under the terms of the GNU General Public
12 * License version 2, as published by the Free Software Foundation, and
13 * may be copied, distributed, and modified under those terms.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 */
21
22#include <linux/module.h>
23#include <linux/fs.h>
24#include <linux/miscdevice.h>
25#include <linux/uaccess.h>
26#include <linux/kthread.h>
27#include <linux/wait.h>
28#include <linux/dma-mapping.h>
29
30#include <linux/delay.h>
31
32#include <linux/msm_audio_qcp.h>
33
Santosh Mardi7faa0fa2011-09-22 15:32:23 +053034
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070035#include <linux/memory_alloc.h>
Sidipotu Ashok172c98b2012-06-26 17:58:29 +053036#include <linux/ion.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070037
38#include <asm/atomic.h>
39#include <asm/ioctls.h>
Santosh Mardi7faa0fa2011-09-22 15:32:23 +053040
41#include <mach/msm_memtypes.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070042#include <mach/msm_adsp.h>
43#include <mach/msm_rpcrouter.h>
Santosh Mardi7faa0fa2011-09-22 15:32:23 +053044#include <mach/iommu.h>
45#include <mach/iommu_domains.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070046#include "audmgr.h"
47
48#include <mach/qdsp5/qdsp5audpreproc.h>
49#include <mach/qdsp5/qdsp5audpreproccmdi.h>
50#include <mach/qdsp5/qdsp5audpreprocmsg.h>
51#include <mach/qdsp5/qdsp5audreccmdi.h>
52#include <mach/qdsp5/qdsp5audrecmsg.h>
53#include <mach/debug_mm.h>
54
55#define FRAME_HEADER_SIZE 8 /* 8 bytes frame header */
56#define NT_FRAME_HEADER_SIZE 24 /* 24 bytes frame header */
57/* FRAME_NUM must be a power of two */
58#define FRAME_NUM 8
59#define QCELP_FRAME_SIZE 36 /* 36 bytes data */
60/*Tunnel mode : 36 bytes data + 8 byte header*/
61#define FRAME_SIZE (QCELP_FRAME_SIZE + FRAME_HEADER_SIZE)
62 /* 36 bytes data + 24 meta field*/
63#define NT_FRAME_SIZE (QCELP_FRAME_SIZE + NT_FRAME_HEADER_SIZE)
64#define DMASZ (FRAME_SIZE * FRAME_NUM)
65#define NT_DMASZ (NT_FRAME_SIZE * FRAME_NUM)
66#define OUT_FRAME_NUM 2
67#define OUT_BUFFER_SIZE (4 * 1024 + NT_FRAME_HEADER_SIZE)
68#define BUFFER_SIZE (OUT_BUFFER_SIZE * OUT_FRAME_NUM)
69
70/* Offset from beginning of buffer*/
71#define AUDPREPROC_QCELP_EOS_FLG_OFFSET 0x0A
72#define AUDPREPROC_QCELP_EOS_FLG_MASK 0x01
73#define AUDPREPROC_QCELP_EOS_NONE 0x0 /* No EOS detected */
74#define AUDPREPROC_QCELP_EOS_SET 0x1 /* EOS set in meta field */
75
76struct buffer {
77 void *data;
78 uint32_t size;
79 uint32_t read;
80 uint32_t addr;
81 uint32_t used;
82 uint32_t mfield_sz;
83};
84
85struct audio_qcelp_in {
86 struct buffer in[FRAME_NUM];
87
88 spinlock_t dsp_lock;
89
90 atomic_t in_bytes;
91 atomic_t in_samples;
92
93 struct mutex lock;
94 struct mutex read_lock;
95 wait_queue_head_t wait;
96 wait_queue_head_t wait_enable;
97 /*write section*/
98 struct buffer out[OUT_FRAME_NUM];
99
100 uint8_t out_head;
101 uint8_t out_tail;
102 uint8_t out_needed; /* number of buffers the dsp is waiting for */
103 uint32_t out_count;
104
105 struct mutex write_lock;
106 wait_queue_head_t write_wait;
107 int32_t out_phys; /* physical address of write buffer */
108 char *out_data;
109 int mfield; /* meta field embedded in data */
110 int wflush; /*write flush */
111 int rflush; /*read flush*/
112 int out_frame_cnt;
113
114 struct msm_adsp_module *audrec;
115 struct msm_adsp_module *audpre;
116
117
118 /* configuration to use on next enable */
119 uint32_t samp_rate;
120 uint32_t channel_mode;
121 uint32_t buffer_size; /* Frame size (36 bytes) */
122 uint32_t enc_type; /* 11 for QCELP */
123 uint32_t mode; /* T or NT Mode*/
124
125 struct msm_audio_qcelp_enc_config cfg;
126
127 uint32_t dsp_cnt;
128 uint32_t in_head; /* next buffer dsp will write */
129 uint32_t in_tail; /* next buffer read() will read */
130 uint32_t in_count; /* number of buffers available to read() */
131
132 uint32_t eos_ack;
133 uint32_t flush_ack;
134
135 const char *module_name;
136 unsigned queue_ids;
137 uint16_t enc_id; /* Session Id */
138
139 unsigned short samp_rate_index;
140 uint32_t audrec_obj_idx ;
141
142 struct audmgr audmgr;
143
144 /* data allocated for various buffers */
145 char *data;
146 dma_addr_t phys;
147
Laura Abbott35111d32012-04-27 18:41:48 -0700148 void *map_v_read;
149 void *map_v_write;
Santosh Mardi7faa0fa2011-09-22 15:32:23 +0530150
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700151 int opened;
152 int enabled;
153 int running;
154 int stopped; /* set when stopped, cleared on flush */
Sidipotu Ashok172c98b2012-06-26 17:58:29 +0530155 struct ion_client *client;
156 struct ion_handle *input_buff_handle;
157 struct ion_handle *output_buff_handle;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700158};
159
160struct audio_frame {
161 uint16_t frame_count_lsw;
162 uint16_t frame_count_msw;
163 uint16_t frame_length;
164 uint16_t erased_pcm;
165 unsigned char raw_bitstream[];
166} __packed;
167
168struct audio_frame_nt {
169 uint16_t metadata_len;
170 uint16_t frame_count_lsw;
171 uint16_t frame_count_msw;
172 uint16_t frame_length;
173 uint16_t erased_pcm;
174 uint16_t reserved;
175 uint16_t time_stamp_dword_lsw;
176 uint16_t time_stamp_dword_msw;
177 uint16_t time_stamp_lsw;
178 uint16_t time_stamp_msw;
179 uint16_t nflag_lsw;
180 uint16_t nflag_msw;
181 unsigned char raw_bitstream[]; /* samples */
182} __packed;
183
184struct qcelp_encoded_meta_out {
185 uint16_t metadata_len;
186 uint16_t time_stamp_dword_lsw;
187 uint16_t time_stamp_dword_msw;
188 uint16_t time_stamp_lsw;
189 uint16_t time_stamp_msw;
190 uint16_t nflag_lsw;
191 uint16_t nflag_msw;
192};
193
194/* Audrec Queue command sent macro's */
195#define audio_send_queue_pre(audio, cmd, len) \
196 msm_adsp_write(audio->audpre, QDSP_uPAudPreProcCmdQueue, cmd, len)
197
198#define audio_send_queue_recbs(audio, cmd, len) \
199 msm_adsp_write(audio->audrec, ((audio->queue_ids & 0xFFFF0000) >> 16),\
200 cmd, len)
201#define audio_send_queue_rec(audio, cmd, len) \
202 msm_adsp_write(audio->audrec, (audio->queue_ids & 0x0000FFFF),\
203 cmd, len)
204
205static int audqcelp_in_dsp_enable(struct audio_qcelp_in *audio, int enable);
206static int audqcelp_in_encparam_config(struct audio_qcelp_in *audio);
207static int audqcelp_in_encmem_config(struct audio_qcelp_in *audio);
208static int audqcelp_in_dsp_read_buffer(struct audio_qcelp_in *audio,
209 uint32_t read_cnt);
210static void audqcelp_in_flush(struct audio_qcelp_in *audio);
211
212static void audqcelp_in_get_dsp_frames(struct audio_qcelp_in *audio);
213static int audpcm_config(struct audio_qcelp_in *audio);
214static void audqcelp_out_flush(struct audio_qcelp_in *audio);
215static int audqcelp_in_routing_mode_config(struct audio_qcelp_in *audio);
216static void audrec_pcm_send_data(struct audio_qcelp_in *audio, unsigned needed);
217static void audqcelp_nt_in_get_dsp_frames(struct audio_qcelp_in *audio);
218static void audqcelp_in_flush(struct audio_qcelp_in *audio);
219
220static unsigned convert_samp_index(unsigned index)
221{
222 switch (index) {
223 case RPC_AUD_DEF_SAMPLE_RATE_48000: return 48000;
224 case RPC_AUD_DEF_SAMPLE_RATE_44100: return 44100;
225 case RPC_AUD_DEF_SAMPLE_RATE_32000: return 32000;
226 case RPC_AUD_DEF_SAMPLE_RATE_24000: return 24000;
227 case RPC_AUD_DEF_SAMPLE_RATE_22050: return 22050;
228 case RPC_AUD_DEF_SAMPLE_RATE_16000: return 16000;
229 case RPC_AUD_DEF_SAMPLE_RATE_12000: return 12000;
230 case RPC_AUD_DEF_SAMPLE_RATE_11025: return 11025;
231 case RPC_AUD_DEF_SAMPLE_RATE_8000: return 8000;
232 default: return 11025;
233 }
234}
235
236/* must be called with audio->lock held */
237static int audqcelp_in_enable(struct audio_qcelp_in *audio)
238{
239 struct audmgr_config cfg;
240 int rc;
241
242 if (audio->enabled)
243 return 0;
244
245 cfg.tx_rate = audio->samp_rate;
246 cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE;
247 cfg.def_method = RPC_AUD_DEF_METHOD_RECORD;
248 cfg.codec = RPC_AUD_DEF_CODEC_13K;
249 cfg.snd_method = RPC_SND_METHOD_MIDI;
250
251 if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
252 rc = audmgr_enable(&audio->audmgr, &cfg);
253 if (rc < 0)
254 return rc;
255
256 if (msm_adsp_enable(audio->audpre)) {
257 audmgr_disable(&audio->audmgr);
258 MM_ERR("msm_adsp_enable(audpre) failed\n");
259 return -ENODEV;
260 }
261 }
262 if (msm_adsp_enable(audio->audrec)) {
263 if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
264 audmgr_disable(&audio->audmgr);
265 msm_adsp_disable(audio->audpre);
266 }
267 MM_ERR("msm_adsp_enable(audrec) failed\n");
268 return -ENODEV;
269 }
270
271 audio->enabled = 1;
272 audqcelp_in_dsp_enable(audio, 1);
273
274 return 0;
275}
276
277/* must be called with audio->lock held */
278static int audqcelp_in_disable(struct audio_qcelp_in *audio)
279{
280 if (audio->enabled) {
281 audio->enabled = 0;
282
283 audqcelp_in_dsp_enable(audio, 0);
284
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700285 wait_event_interruptible_timeout(audio->wait_enable,
286 audio->running == 0, 1*HZ);
Manish Dewangan89a9f232012-02-09 17:14:40 +0530287 audio->stopped = 1;
288 wake_up(&audio->wait);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700289 msm_adsp_disable(audio->audrec);
290 if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
291 msm_adsp_disable(audio->audpre);
292 audmgr_disable(&audio->audmgr);
293 }
294 }
295 return 0;
296}
297
298/* ------------------- dsp --------------------- */
299static void audpre_dsp_event(void *data, unsigned id, size_t len,
300 void (*getevent)(void *ptr, size_t len))
301{
302 uint16_t msg[2];
303 getevent(msg, sizeof(msg));
304
305 switch (id) {
306 case AUDPREPROC_MSG_CMD_CFG_DONE_MSG:
307 MM_DBG("type %d, status_flag %d\n", msg[0], msg[1]);
308 break;
309 case AUDPREPROC_MSG_ERROR_MSG_ID:
310 MM_ERR("err_index %d\n", msg[0]);
311 break;
312 case ADSP_MESSAGE_ID:
313 MM_DBG("Received ADSP event: module enable(audpreproctask)\n");
314 break;
315 default:
316 MM_ERR("unknown event %d\n", id);
317 }
318}
319
320static void audqcelp_in_get_dsp_frames(struct audio_qcelp_in *audio)
321{
322 struct audio_frame *frame;
323 uint32_t index;
324 unsigned long flags;
325
326 index = audio->in_head;
327
328 frame = (void *) (((char *)audio->in[index].data) -
329 sizeof(*frame));
330 spin_lock_irqsave(&audio->dsp_lock, flags);
331 audio->in[index].size = frame->frame_length;
332
333 /* statistics of read */
334 atomic_add(audio->in[index].size, &audio->in_bytes);
335 atomic_add(1, &audio->in_samples);
336
337 audio->in_head = (audio->in_head + 1) & (FRAME_NUM - 1);
338
339 /* If overflow, move the tail index foward. */
340 if (audio->in_head == audio->in_tail) {
341 MM_ERR("Error! not able to keep up the read\n");
342 audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1);
343 MM_ERR("in_count = %d\n", audio->in_count);
344 } else
345 audio->in_count++;
346
347 audqcelp_in_dsp_read_buffer(audio, audio->dsp_cnt++);
348 spin_unlock_irqrestore(&audio->dsp_lock, flags);
349
350 wake_up(&audio->wait);
351}
352
353static void audqcelp_nt_in_get_dsp_frames(struct audio_qcelp_in *audio)
354{
355 struct audio_frame_nt *nt_frame;
356 uint32_t index;
357 unsigned long flags;
358
359 index = audio->in_head;
360 nt_frame = (void *) (((char *)audio->in[index].data) - \
361 sizeof(struct audio_frame_nt));
362 spin_lock_irqsave(&audio->dsp_lock, flags);
363 audio->in[index].size = nt_frame->frame_length;
364 /* statistics of read */
365 atomic_add(audio->in[index].size, &audio->in_bytes);
366 atomic_add(1, &audio->in_samples);
367
368 audio->in_head = (audio->in_head + 1) & (FRAME_NUM - 1);
369
370 /* If overflow, move the tail index foward. */
371 if (audio->in_head == audio->in_tail)
372 MM_DBG("Error! not able to keep up the read\n");
373 else
374 audio->in_count++;
375
376 spin_unlock_irqrestore(&audio->dsp_lock, flags);
377 wake_up(&audio->wait);
378}
379
380static int audrec_pcm_buffer_ptr_refresh(struct audio_qcelp_in *audio,
381 unsigned idx, unsigned len)
382{
383 struct audrec_cmd_pcm_buffer_ptr_refresh_arm_enc cmd;
384
385 if (len == NT_FRAME_HEADER_SIZE)
386 len = len / 2;
387 else
388 len = (len + NT_FRAME_HEADER_SIZE) / 2;
389 MM_DBG("len = %d\n", len);
390 memset(&cmd, 0, sizeof(cmd));
391 cmd.cmd_id = AUDREC_CMD_PCM_BUFFER_PTR_REFRESH_ARM_TO_ENC;
392 cmd.num_buffers = 1;
393 if (cmd.num_buffers == 1) {
394 cmd.buf_address_length[0] = (audio->out[idx].addr &
395 0xffff0000) >> 16;
396 cmd.buf_address_length[1] = (audio->out[idx].addr &
397 0x0000ffff);
398 cmd.buf_address_length[2] = (len & 0xffff0000) >> 16;
399 cmd.buf_address_length[3] = (len & 0x0000ffff);
400 }
401 audio->out_frame_cnt++;
402 return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
403}
404
405static int audpcm_config(struct audio_qcelp_in *audio)
406{
407 struct audrec_cmd_pcm_cfg_arm_to_enc cmd;
408 MM_DBG("\n");
409 memset(&cmd, 0, sizeof(cmd));
410 cmd.cmd_id = AUDREC_CMD_PCM_CFG_ARM_TO_ENC;
411 cmd.config_update_flag = AUDREC_PCM_CONFIG_UPDATE_FLAG_ENABLE;
412 cmd.enable_flag = AUDREC_ENABLE_FLAG_VALUE;
413 cmd.sampling_freq = convert_samp_index(audio->samp_rate);
414 if (!audio->channel_mode)
415 cmd.channels = 1;
416 else
417 cmd.channels = 2;
418 cmd.frequency_of_intimation = 1;
419 cmd.max_number_of_buffers = OUT_FRAME_NUM;
420 return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
421}
422
423
424static int audqcelp_in_routing_mode_config(struct audio_qcelp_in *audio)
425{
426 struct audrec_cmd_routing_mode cmd;
427
428 MM_DBG("\n");
429 memset(&cmd, 0, sizeof(cmd));
430 cmd.cmd_id = AUDREC_CMD_ROUTING_MODE;
431 if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL)
432 cmd.routing_mode = 1;
433 return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
434}
435
436static void audrec_dsp_event(void *data, unsigned id, size_t len,
437 void (*getevent)(void *ptr, size_t len))
438{
439 struct audio_qcelp_in *audio = NULL;
440
441 if (data)
442 audio = data;
443 else {
444 MM_ERR("invalid data for event %x\n", id);
445 return;
446 }
447
448 switch (id) {
449 case AUDREC_MSG_CMD_CFG_DONE_MSG: {
450 struct audrec_msg_cmd_cfg_done_msg cmd_cfg_done_msg;
451 getevent(&cmd_cfg_done_msg, AUDREC_MSG_CMD_CFG_DONE_MSG_LEN);
452 if (cmd_cfg_done_msg.audrec_enc_type & \
453 AUDREC_MSG_CFG_DONE_ENC_ENA) {
454 audio->audrec_obj_idx = cmd_cfg_done_msg.audrec_obj_idx;
455 MM_DBG("CFG ENABLED\n");
456 if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) {
457 MM_DBG("routing command\n");
458 audqcelp_in_routing_mode_config(audio);
459 } else {
460 audqcelp_in_encmem_config(audio);
461 }
462 } else {
463 MM_DBG("CFG SLEEP\n");
464 audio->running = 0;
465 wake_up(&audio->wait_enable);
466 }
467 break;
468 }
469 case AUDREC_MSG_CMD_ROUTING_MODE_DONE_MSG: {
470 struct audrec_msg_cmd_routing_mode_done_msg \
471 routing_msg;
472 getevent(&routing_msg, AUDREC_MSG_CMD_ROUTING_MODE_DONE_MSG);
473 MM_DBG("AUDREC_MSG_CMD_ROUTING_MODE_DONE_MSG");
474 if (routing_msg.configuration == 0) {
475 MM_ERR("routing configuration failed\n");
476 audio->running = 0;
477 wake_up(&audio->wait_enable);
478 } else
479 audqcelp_in_encmem_config(audio);
480 break;
481 }
482 case AUDREC_MSG_CMD_AREC_MEM_CFG_DONE_MSG: {
483 MM_DBG("AREC_MEM_CFG_DONE_MSG\n");
484 if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
485 audqcelp_in_encparam_config(audio);
486 else
487 audpcm_config(audio);
488 break;
489 }
490 case AUDREC_CMD_PCM_CFG_ARM_TO_ENC_DONE_MSG: {
491 MM_DBG("AUDREC_CMD_PCM_CFG_ARM_TO_ENC_DONE_MSG");
492 audqcelp_in_encparam_config(audio);
493 break;
494 }
495 case AUDREC_MSG_CMD_AREC_PARAM_CFG_DONE_MSG: {
496 MM_DBG("AUDREC_MSG_CMD_AREC_PARAM_CFG_DONE_MSG\n");
497 audio->running = 1;
498 wake_up(&audio->wait_enable);
499 if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL)
500 audrec_pcm_send_data(audio, 1);
501 break;
502 }
503 case AUDREC_CMD_PCM_BUFFER_PTR_UPDATE_ARM_TO_ENC_MSG: {
504 MM_DBG("ptr_update recieved from DSP\n");
505 audrec_pcm_send_data(audio, 1);
506 break;
507 }
508 case AUDREC_MSG_NO_EXT_PKT_AVAILABLE_MSG: {
509 struct audrec_msg_no_ext_pkt_avail_msg err_msg;
510 getevent(&err_msg, AUDREC_MSG_NO_EXT_PKT_AVAILABLE_MSG_LEN);
511 MM_DBG("NO_EXT_PKT_AVAILABLE_MSG %x\n",\
512 err_msg.audrec_err_id);
513 break;
514 }
515 case AUDREC_MSG_PACKET_READY_MSG: {
516 struct audrec_msg_packet_ready_msg pkt_ready_msg;
517
518 getevent(&pkt_ready_msg, AUDREC_MSG_PACKET_READY_MSG_LEN);
519 MM_DBG("UP_PACKET_READY_MSG: write cnt msw %d \
520 write cnt lsw %d read cnt msw %d read cnt lsw %d \n",\
521 pkt_ready_msg.pkt_counter_msw, \
522 pkt_ready_msg.pkt_counter_lsw, \
523 pkt_ready_msg.pkt_read_cnt_msw, \
524 pkt_ready_msg.pkt_read_cnt_lsw);
525
526 audqcelp_in_get_dsp_frames(audio);
527 break;
528 }
529 case AUDREC_UP_NT_PACKET_READY_MSG: {
530 struct audrec_up_nt_packet_ready_msg pkt_ready_msg;
531
532 getevent(&pkt_ready_msg, AUDREC_UP_NT_PACKET_READY_MSG_LEN);
533 MM_DBG("UP_NT_PACKET_READY_MSG: write cnt lsw %d \
534 write cnt msw %d read cnt lsw %d read cnt msw %d \n",\
535 pkt_ready_msg.audrec_packetwrite_cnt_lsw, \
536 pkt_ready_msg.audrec_packetwrite_cnt_msw, \
537 pkt_ready_msg.audrec_upprev_readcount_lsw, \
538 pkt_ready_msg.audrec_upprev_readcount_msw);
539
540 audqcelp_nt_in_get_dsp_frames(audio);
541 break;
542 }
543 case AUDREC_CMD_FLUSH_DONE_MSG: {
544 audio->wflush = 0;
545 audio->rflush = 0;
546 audio->flush_ack = 1;
547 wake_up(&audio->write_wait);
548 MM_DBG("flush ack recieved\n");
549 break;
550 }
551 case ADSP_MESSAGE_ID:
552 MM_DBG("Received ADSP event: module \
553 enable/disable(audrectask)\n");
554 break;
555 default:
556 MM_ERR("unknown event %d\n", id);
557 }
558}
559
560static struct msm_adsp_ops audpre_qcelp_adsp_ops = {
561 .event = audpre_dsp_event,
562};
563
564static struct msm_adsp_ops audrec_qcelp_adsp_ops = {
565 .event = audrec_dsp_event,
566};
567
568static int audqcelp_in_dsp_enable(struct audio_qcelp_in *audio, int enable)
569{
570 struct audrec_cmd_enc_cfg cmd;
571
572 memset(&cmd, 0, sizeof(cmd));
573 cmd.cmd_id = AUDREC_CMD_ENC_CFG;
574 cmd.audrec_enc_type = (audio->enc_type & 0xFF) |
575 (enable ? AUDREC_CMD_ENC_ENA : AUDREC_CMD_ENC_DIS);
576 /* Don't care */
577 cmd.audrec_obj_idx = audio->audrec_obj_idx;
578
579 return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
580}
581
582static int audqcelp_in_encmem_config(struct audio_qcelp_in *audio)
583{
584 struct audrec_cmd_arecmem_cfg cmd;
585 uint16_t *data = (void *) audio->data;
586 int n;
587 int header_len = 0;
588
589 memset(&cmd, 0, sizeof(cmd));
590
591 cmd.cmd_id = AUDREC_CMD_ARECMEM_CFG;
592 cmd.audrec_obj_idx = audio->audrec_obj_idx;
593 /* Rate at which packet complete message comes */
594 cmd.audrec_up_pkt_intm_cnt = 1;
595 cmd.audrec_extpkt_buffer_msw = audio->phys >> 16;
596 cmd.audrec_extpkt_buffer_lsw = audio->phys;
597 /* Max Buffer no available for frames */
598 cmd.audrec_extpkt_buffer_num = FRAME_NUM;
599
600 /* prepare buffer pointers:
601 * T:36 bytes qcelp packet + 4 halfword header
602 * NT:36 bytes qcelp packet + 12 halfword header
603 */
604 if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
605 header_len = FRAME_HEADER_SIZE/2;
606 else
607 header_len = NT_FRAME_HEADER_SIZE/2;
608
609 for (n = 0; n < FRAME_NUM; n++) {
610 audio->in[n].data = data + header_len;
611 data += (QCELP_FRAME_SIZE/2) + header_len;
612 MM_DBG("0x%8x\n", (int)(audio->in[n].data - header_len*2));
613 }
614
615 return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
616}
617
618static int audqcelp_in_encparam_config(struct audio_qcelp_in *audio)
619{
620 struct audrec_cmd_arecparam_qcelp_cfg cmd;
621
622 memset(&cmd, 0, sizeof(cmd));
623 cmd.common.cmd_id = AUDREC_CMD_ARECPARAM_CFG;
624 cmd.common.audrec_obj_idx = audio->audrec_obj_idx;
625 cmd.enc_min_rate = audio->cfg.min_bit_rate;
626 cmd.enc_max_rate = audio->cfg.max_bit_rate;
627 cmd.rate_modulation_cmd = 0; /* Default set to 0 */
628 cmd.reduced_rate_level = 0; /* Default set to 0 */
629
630 return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
631}
632
633static int audqcelp_flush_command(struct audio_qcelp_in *audio)
634{
635 struct audrec_cmd_flush cmd;
636 MM_DBG("\n");
637 memset(&cmd, 0, sizeof(cmd));
638 cmd.cmd_id = AUDREC_CMD_FLUSH;
639 return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
640}
641
642static int audqcelp_in_dsp_read_buffer(struct audio_qcelp_in *audio,
643 uint32_t read_cnt)
644{
645 audrec_cmd_packet_ext_ptr cmd;
646
647 memset(&cmd, 0, sizeof(cmd));
648 cmd.cmd_id = AUDREC_CMD_PACKET_EXT_PTR;
649 cmd.type = audio->audrec_obj_idx;
650 cmd.curr_rec_count_msw = read_cnt >> 16;
651 cmd.curr_rec_count_lsw = read_cnt;
652
653 return audio_send_queue_recbs(audio, &cmd, sizeof(cmd));
654}
655
656/* ------------------- device --------------------- */
657
658static void audqcelp_ioport_reset(struct audio_qcelp_in *audio)
659{
660 /* Make sure read/write thread are free from
661 * sleep and knowing that system is not able
662 * to process io request at the moment
663 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700664 wake_up(&audio->wait);
665 mutex_lock(&audio->read_lock);
Manish Dewangana4f1df02012-02-08 17:06:54 +0530666 audqcelp_in_flush(audio);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700667 mutex_unlock(&audio->read_lock);
Manish Dewangana4f1df02012-02-08 17:06:54 +0530668 wake_up(&audio->write_wait);
669 mutex_lock(&audio->write_lock);
670 audqcelp_out_flush(audio);
671 mutex_unlock(&audio->write_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700672}
673
674static void audqcelp_in_flush(struct audio_qcelp_in *audio)
675{
676 int i;
Manish Dewangana4f1df02012-02-08 17:06:54 +0530677 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700678
Manish Dewangana4f1df02012-02-08 17:06:54 +0530679 audio->eos_ack = 0;
680 spin_lock_irqsave(&audio->dsp_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700681 audio->dsp_cnt = 0;
682 audio->in_head = 0;
683 audio->in_tail = 0;
684 audio->in_count = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700685 for (i = FRAME_NUM-1; i >= 0; i--) {
686 audio->in[i].size = 0;
687 audio->in[i].read = 0;
688 }
Manish Dewangana4f1df02012-02-08 17:06:54 +0530689 spin_unlock_irqrestore(&audio->dsp_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700690 MM_DBG("in_bytes %d\n", atomic_read(&audio->in_bytes));
691 MM_DBG("in_samples %d\n", atomic_read(&audio->in_samples));
692 atomic_set(&audio->in_bytes, 0);
693 atomic_set(&audio->in_samples, 0);
694}
695
696static void audqcelp_out_flush(struct audio_qcelp_in *audio)
697{
698 int i;
Manish Dewangana4f1df02012-02-08 17:06:54 +0530699 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700700
701 audio->out_head = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700702 audio->out_count = 0;
Manish Dewangana4f1df02012-02-08 17:06:54 +0530703 spin_lock_irqsave(&audio->dsp_lock, flags);
704 audio->out_tail = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700705 for (i = OUT_FRAME_NUM-1; i >= 0; i--) {
706 audio->out[i].size = 0;
707 audio->out[i].read = 0;
708 audio->out[i].used = 0;
709 }
Manish Dewangana4f1df02012-02-08 17:06:54 +0530710 spin_unlock_irqrestore(&audio->dsp_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700711}
712
713/* ------------------- device --------------------- */
714static long audqcelp_in_ioctl(struct file *file,
715 unsigned int cmd, unsigned long arg)
716{
717 struct audio_qcelp_in *audio = file->private_data;
718 int rc = 0;
719
720 MM_DBG("\n");
721 if (cmd == AUDIO_GET_STATS) {
722 struct msm_audio_stats stats;
723 stats.byte_count = atomic_read(&audio->in_bytes);
724 stats.sample_count = atomic_read(&audio->in_samples);
725 if (copy_to_user((void *) arg, &stats, sizeof(stats)))
726 return -EFAULT;
727 return rc;
728 }
729
730 mutex_lock(&audio->lock);
731 switch (cmd) {
732 case AUDIO_START: {
733 rc = audqcelp_in_enable(audio);
734 if (!rc) {
735 rc =
736 wait_event_interruptible_timeout(audio->wait_enable,
737 audio->running != 0, 1*HZ);
738 MM_DBG("state %d rc = %d\n", audio->running, rc);
739
740 if (audio->running == 0)
741 rc = -ENODEV;
742 else
743 rc = 0;
744 }
745 audio->stopped = 0;
746 break;
747 }
748 case AUDIO_STOP: {
749 rc = audqcelp_in_disable(audio);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700750 break;
751 }
752 case AUDIO_FLUSH: {
753 MM_DBG("AUDIO_FLUSH\n");
754 audio->rflush = 1;
755 audio->wflush = 1;
756 audqcelp_ioport_reset(audio);
757 if (audio->running) {
758 audqcelp_flush_command(audio);
759 rc = wait_event_interruptible(audio->write_wait,
760 !audio->wflush);
761 if (rc < 0) {
762 MM_ERR("AUDIO_FLUSH interrupted\n");
763 rc = -EINTR;
764 }
765 } else {
766 audio->rflush = 0;
767 audio->wflush = 0;
768 }
769 break;
770 }
771 case AUDIO_GET_CONFIG: {
772 struct msm_audio_config cfg;
773 memset(&cfg, 0, sizeof(cfg));
774 cfg.buffer_size = OUT_BUFFER_SIZE;
775 cfg.buffer_count = OUT_FRAME_NUM;
776 cfg.sample_rate = convert_samp_index(audio->samp_rate);
777 cfg.channel_count = 1;
778 cfg.type = 0;
779 cfg.unused[0] = 0;
780 cfg.unused[1] = 0;
781 cfg.unused[2] = 0;
782 if (copy_to_user((void *) arg, &cfg, sizeof(cfg)))
783 rc = -EFAULT;
784 else
785 rc = 0;
786 break;
787 }
788 case AUDIO_GET_STREAM_CONFIG: {
789 struct msm_audio_stream_config cfg;
790 memset(&cfg, 0, sizeof(cfg));
791 cfg.buffer_size = audio->buffer_size;
792 cfg.buffer_count = FRAME_NUM;
793 if (copy_to_user((void *)arg, &cfg, sizeof(cfg)))
794 rc = -EFAULT;
795 else
796 rc = 0;
797 break;
798 }
799 case AUDIO_SET_STREAM_CONFIG: {
800 struct msm_audio_stream_config cfg;
801 if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) {
802 rc = -EFAULT;
803 break;
804 }
805 /* Allow only single frame */
806 if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
Phani Kumar Alladaee940eb2012-05-10 11:13:04 +0530807 if (cfg.buffer_size != (FRAME_SIZE - 8)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700808 rc = -EINVAL;
809 break;
Phani Kumar Alladaee940eb2012-05-10 11:13:04 +0530810 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700811 } else {
Phani Kumar Alladaee940eb2012-05-10 11:13:04 +0530812 if (cfg.buffer_size != (QCELP_FRAME_SIZE + 14)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700813 rc = -EINVAL;
814 break;
Phani Kumar Alladaee940eb2012-05-10 11:13:04 +0530815 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700816 }
817 audio->buffer_size = cfg.buffer_size;
818 break;
819 }
820 case AUDIO_GET_QCELP_ENC_CONFIG: {
821 if (copy_to_user((void *) arg, &audio->cfg, sizeof(audio->cfg)))
822 rc = -EFAULT;
823 break;
824 }
825 case AUDIO_SET_QCELP_ENC_CONFIG: {
826 struct msm_audio_qcelp_enc_config cfg;
827 if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) {
828 rc = -EFAULT;
829 break;
830 }
831 MM_DBG("0X%8x, 0x%8x, 0x%8x\n", cfg.min_bit_rate,
832 cfg.max_bit_rate, cfg.cdma_rate);
833 if (cfg.min_bit_rate > CDMA_RATE_FULL || \
834 cfg.min_bit_rate < CDMA_RATE_EIGHTH) {
835 MM_ERR("invalid min bitrate\n");
836 rc = -EFAULT;
837 break;
838 }
839 if (cfg.max_bit_rate > CDMA_RATE_FULL || \
840 cfg.max_bit_rate < CDMA_RATE_EIGHTH) {
841 MM_ERR("invalid max bitrate\n");
842 rc = -EFAULT;
843 break;
844 }
845 /* Recording Does not support Erase and Blank */
846 if (cfg.cdma_rate > CDMA_RATE_FULL ||
847 cfg.cdma_rate < CDMA_RATE_EIGHTH) {
848 MM_ERR("invalid qcelp cdma rate\n");
849 rc = -EFAULT;
850 break;
851 }
852 memcpy(&audio->cfg, &cfg, sizeof(cfg));
853 break;
854 }
855 default:
856 rc = -EINVAL;
857 }
858 mutex_unlock(&audio->lock);
859 return rc;
860}
861
862static ssize_t audqcelp_in_read(struct file *file,
863 char __user *buf,
864 size_t count, loff_t *pos)
865{
866 struct audio_qcelp_in *audio = file->private_data;
867 unsigned long flags;
868 const char __user *start = buf;
869 void *data;
870 uint32_t index;
871 uint32_t size;
872 int rc = 0;
873 struct qcelp_encoded_meta_out meta_field;
874 struct audio_frame_nt *nt_frame;
875 MM_DBG("count = %d\n", count);
876 mutex_lock(&audio->read_lock);
877 while (count > 0) {
878 rc = wait_event_interruptible(
879 audio->wait, (audio->in_count > 0) || audio->stopped ||
880 audio->rflush);
881 if (rc < 0)
882 break;
883
884 if (audio->rflush) {
885 rc = -EBUSY;
886 break;
887 }
888 if (audio->stopped && !audio->in_count) {
889 MM_DBG("Driver in stop state, No more buffer to read");
890 rc = 0;/* End of File */
891 break;
892 }
893
894 index = audio->in_tail;
895 data = (uint8_t *) audio->in[index].data;
896 size = audio->in[index].size;
897
898 if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) {
899 nt_frame = (struct audio_frame_nt *)(data -
900 sizeof(struct audio_frame_nt));
901 memcpy((char *)&meta_field.time_stamp_dword_lsw,
902 (char *)&nt_frame->time_stamp_dword_lsw,
903 (sizeof(struct qcelp_encoded_meta_out) - \
904 sizeof(uint16_t)));
905 meta_field.metadata_len =
906 sizeof(struct qcelp_encoded_meta_out);
907 if (copy_to_user((char *)start, (char *)&meta_field,
908 sizeof(struct qcelp_encoded_meta_out))) {
909 rc = -EFAULT;
910 break;
911 }
912 if (nt_frame->nflag_lsw & 0x0001) {
913 MM_ERR("recieved EOS in read call\n");
914 audio->eos_ack = 1;
915 }
916 buf += sizeof(struct qcelp_encoded_meta_out);
917 count -= sizeof(struct qcelp_encoded_meta_out);
918 }
919 if (count >= size) {
920 /* order the reads on the buffer */
921 dma_coherent_post_ops();
922 if (copy_to_user(buf, data, size)) {
923 rc = -EFAULT;
924 break;
925 }
926 spin_lock_irqsave(&audio->dsp_lock, flags);
927 if (index != audio->in_tail) {
928 /* overrun -- data is
929 * invalid and we need to retry */
930 spin_unlock_irqrestore(&audio->dsp_lock, flags);
931 continue;
932 }
933 audio->in[index].size = 0;
934 audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1);
935 audio->in_count--;
936 spin_unlock_irqrestore(&audio->dsp_lock, flags);
937 count -= size;
938 buf += size;
939 if ((audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL)) {
940 if (!audio->eos_ack) {
941 MM_DBG("sending read ptr command \
942 %d %d\n",
943 audio->dsp_cnt,
944 audio->in_tail);
945 audqcelp_in_dsp_read_buffer(audio,
946 audio->dsp_cnt++);
947 }
948 }
949 } else {
950 MM_ERR("short read\n");
951 break;
952 }
953 break;
954 }
955 mutex_unlock(&audio->read_lock);
956
957 if (buf > start)
958 return buf - start;
959
960 return rc;
961}
962
963static void audrec_pcm_send_data(struct audio_qcelp_in *audio, unsigned needed)
964{
965 struct buffer *frame;
966 unsigned long flags;
967 MM_DBG("\n");
968 spin_lock_irqsave(&audio->dsp_lock, flags);
969 if (!audio->running)
970 goto done;
971
972 if (needed && !audio->wflush) {
973 /* We were called from the callback because the DSP
974 * requested more data. Note that the DSP does want
975 * more data, and if a buffer was in-flight, mark it
976 * as available (since the DSP must now be done with
977 * it).
978 */
979 audio->out_needed = 1;
980 frame = audio->out + audio->out_tail;
981 if (frame->used == 0xffffffff) {
982 MM_DBG("frame %d free\n", audio->out_tail);
983 frame->used = 0;
984 audio->out_tail ^= 1;
985 wake_up(&audio->write_wait);
986 }
987 }
988
989 if (audio->out_needed) {
990 /* If the DSP currently wants data and we have a
991 * buffer available, we will send it and reset
992 * the needed flag. We'll mark the buffer as in-flight
993 * so that it won't be recycled until the next buffer
994 * is requested
995 */
996
997 frame = audio->out + audio->out_tail;
998 if (frame->used) {
999 BUG_ON(frame->used == 0xffffffff);
1000 audrec_pcm_buffer_ptr_refresh(audio,
1001 audio->out_tail,
1002 frame->used);
1003 frame->used = 0xffffffff;
1004 audio->out_needed = 0;
1005 }
1006 }
1007 done:
1008 spin_unlock_irqrestore(&audio->dsp_lock, flags);
1009}
1010
Sidipotu Ashok172c98b2012-06-26 17:58:29 +05301011static int audqcelp_in_fsync(struct file *file, loff_t a, loff_t b,
1012 int datasync)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001013
1014{
1015 struct audio_qcelp_in *audio = file->private_data;
1016 int rc = 0;
1017
1018 MM_DBG("\n"); /* Macro prints the file name and function */
1019 if (!audio->running || (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)) {
1020 rc = -EINVAL;
1021 goto done_nolock;
1022 }
1023
1024 mutex_lock(&audio->write_lock);
1025
1026 rc = wait_event_interruptible(audio->write_wait,
1027 audio->wflush);
1028 MM_DBG("waked on by some event audio->wflush = %d\n", audio->wflush);
1029
1030 if (rc < 0)
1031 goto done;
1032 else if (audio->wflush) {
1033 rc = -EBUSY;
1034 goto done;
1035 }
1036done:
1037 mutex_unlock(&audio->write_lock);
1038done_nolock:
1039 return rc;
1040
1041}
1042
1043int audrec_qcelp_process_eos(struct audio_qcelp_in *audio,
1044 const char __user *buf_start, unsigned short mfield_size)
1045{
1046 struct buffer *frame;
1047 int rc = 0;
1048
1049 frame = audio->out + audio->out_head;
1050
1051 rc = wait_event_interruptible(audio->write_wait,
1052 (audio->out_needed &&
1053 audio->out[0].used == 0 &&
1054 audio->out[1].used == 0)
1055 || (audio->stopped)
1056 || (audio->wflush));
1057
1058 if (rc < 0)
1059 goto done;
1060 if (audio->stopped || audio->wflush) {
1061 rc = -EBUSY;
1062 goto done;
1063 }
1064 if (copy_from_user(frame->data, buf_start, mfield_size)) {
1065 rc = -EFAULT;
1066 goto done;
1067 }
1068
1069 frame->mfield_sz = mfield_size;
1070 audio->out_head ^= 1;
1071 frame->used = mfield_size;
1072 MM_DBG("copying meta_out frame->used = %d\n", frame->used);
1073 audrec_pcm_send_data(audio, 0);
1074done:
1075 return rc;
1076}
1077
1078static ssize_t audqcelp_in_write(struct file *file,
1079 const char __user *buf,
1080 size_t count, loff_t *pos)
1081{
1082 struct audio_qcelp_in *audio = file->private_data;
1083 const char __user *start = buf;
1084 struct buffer *frame;
1085 char *cpy_ptr;
1086 int rc = 0, eos_condition = AUDPREPROC_QCELP_EOS_NONE;
1087 unsigned short mfield_size = 0;
1088 int write_count = 0;
1089 MM_DBG("cnt=%d\n", count);
1090
1091 if (count & 1)
1092 return -EINVAL;
1093
1094 if (audio->mode != MSM_AUD_ENC_MODE_NONTUNNEL)
1095 return -EINVAL;
1096
1097 mutex_lock(&audio->write_lock);
1098 frame = audio->out + audio->out_head;
1099 /* if supplied count is more than driver buffer size
1100 * then only copy driver buffer size
1101 */
1102 if (count > frame->size)
1103 count = frame->size;
1104
1105 write_count = count;
1106 cpy_ptr = frame->data;
1107 rc = wait_event_interruptible(audio->write_wait,
1108 (frame->used == 0)
1109 || (audio->stopped)
1110 || (audio->wflush));
1111 if (rc < 0)
1112 goto error;
1113
1114 if (audio->stopped || audio->wflush) {
1115 rc = -EBUSY;
1116 goto error;
1117 }
1118 if (audio->mfield) {
1119 if (buf == start) {
1120 /* Processing beginning of user buffer */
1121 if (__get_user(mfield_size,
1122 (unsigned short __user *) buf)) {
1123 rc = -EFAULT;
1124 goto error;
1125 } else if (mfield_size > count) {
1126 rc = -EINVAL;
1127 goto error;
1128 }
1129 MM_DBG("mf offset_val %x\n", mfield_size);
1130 if (copy_from_user(cpy_ptr, buf, mfield_size)) {
1131 rc = -EFAULT;
1132 goto error;
1133 }
1134 /* Check if EOS flag is set and buffer has
1135 * contains just meta field
1136 */
1137 if (cpy_ptr[AUDPREPROC_QCELP_EOS_FLG_OFFSET] &
1138 AUDPREPROC_QCELP_EOS_FLG_MASK) {
1139 eos_condition = AUDPREPROC_QCELP_EOS_SET;
1140 MM_DBG("EOS SET\n");
1141 if (mfield_size == count) {
1142 buf += mfield_size;
1143 eos_condition = 0;
1144 goto exit;
1145 } else
1146 cpy_ptr[AUDPREPROC_QCELP_EOS_FLG_OFFSET] &=
1147 ~AUDPREPROC_QCELP_EOS_FLG_MASK;
1148 }
1149 cpy_ptr += mfield_size;
1150 count -= mfield_size;
1151 buf += mfield_size;
1152 } else {
1153 mfield_size = 0;
1154 MM_DBG("continuous buffer\n");
1155 }
1156 frame->mfield_sz = mfield_size;
1157 }
1158 MM_DBG("copying the stream count = %d\n", count);
1159 if (copy_from_user(cpy_ptr, buf, count)) {
1160 rc = -EFAULT;
1161 goto error;
1162 }
1163exit:
1164 frame->used = count;
1165 audio->out_head ^= 1;
1166 if (!audio->flush_ack)
1167 audrec_pcm_send_data(audio, 0);
1168 else {
1169 audrec_pcm_send_data(audio, 1);
1170 audio->flush_ack = 0;
1171 }
1172 if (eos_condition == AUDPREPROC_QCELP_EOS_SET)
1173 rc = audrec_qcelp_process_eos(audio, start, mfield_size);
1174 mutex_unlock(&audio->write_lock);
1175 return write_count;
1176error:
1177 mutex_unlock(&audio->write_lock);
1178 return rc;
1179}
1180
1181static int audqcelp_in_release(struct inode *inode, struct file *file)
1182{
1183 struct audio_qcelp_in *audio = file->private_data;
1184
1185 mutex_lock(&audio->lock);
1186 audqcelp_in_disable(audio);
1187 audqcelp_in_flush(audio);
1188 msm_adsp_put(audio->audrec);
1189
1190 if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
1191 msm_adsp_put(audio->audpre);
1192
1193 audpreproc_aenc_free(audio->enc_id);
1194 audio->audrec = NULL;
1195 audio->audpre = NULL;
1196 audio->opened = 0;
1197
1198 if ((audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) && \
1199 (audio->out_data)) {
Sidipotu Ashok172c98b2012-06-26 17:58:29 +05301200 ion_unmap_kernel(audio->client, audio->input_buff_handle);
1201 ion_free(audio->client, audio->input_buff_handle);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001202 audio->out_data = NULL;
1203 }
1204
1205 if (audio->data) {
Sidipotu Ashok172c98b2012-06-26 17:58:29 +05301206 ion_unmap_kernel(audio->client, audio->output_buff_handle);
1207 ion_free(audio->client, audio->output_buff_handle);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001208 audio->data = NULL;
1209 }
Sidipotu Ashok172c98b2012-06-26 17:58:29 +05301210 ion_client_destroy(audio->client);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001211 mutex_unlock(&audio->lock);
1212 return 0;
1213}
1214
1215static struct audio_qcelp_in the_audio_qcelp_in;
1216
1217static int audqcelp_in_open(struct inode *inode, struct file *file)
1218{
1219 struct audio_qcelp_in *audio = &the_audio_qcelp_in;
1220 int rc;
1221 int encid;
1222 int dma_size = 0;
Sidipotu Ashok172c98b2012-06-26 17:58:29 +05301223 int len = 0;
1224 unsigned long ionflag = 0;
1225 ion_phys_addr_t addr = 0;
1226 struct ion_handle *handle = NULL;
1227 struct ion_client *client = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001228
1229 mutex_lock(&audio->lock);
1230 if (audio->opened) {
1231 rc = -EBUSY;
1232 goto done;
1233 }
1234 if ((file->f_mode & FMODE_WRITE) &&
1235 (file->f_mode & FMODE_READ)) {
1236 audio->mode = MSM_AUD_ENC_MODE_NONTUNNEL;
1237 dma_size = NT_DMASZ;
1238 MM_DBG("Opened for non tunnel mode encoding\n");
1239 } else if (!(file->f_mode & FMODE_WRITE) &&
1240 (file->f_mode & FMODE_READ)) {
1241 audio->mode = MSM_AUD_ENC_MODE_TUNNEL;
1242 dma_size = DMASZ;
1243 MM_DBG("Opened for tunnel mode encoding\n");
1244 } else {
1245 MM_ERR("Invalid mode\n");
1246 rc = -EACCES;
1247 goto done;
1248 }
1249
1250 /* Settings will be re-config at AUDIO_SET_CONFIG,
1251 * but at least we need to have initial config
1252 */
1253 audio->samp_rate = RPC_AUD_DEF_SAMPLE_RATE_8000,
1254 audio->samp_rate_index = AUDREC_CMD_SAMP_RATE_INDX_8000;
1255 audio->channel_mode = AUDREC_CMD_STEREO_MODE_MONO;
1256 if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL)
1257 audio->buffer_size = (QCELP_FRAME_SIZE + 14);
1258 else
1259 audio->buffer_size = QCELP_FRAME_SIZE;
1260 audio->enc_type = AUDREC_CMD_TYPE_0_INDEX_QCELP | audio->mode;
1261
1262 audio->cfg.cdma_rate = CDMA_RATE_FULL;
1263 audio->cfg.min_bit_rate = CDMA_RATE_FULL;
1264 audio->cfg.max_bit_rate = CDMA_RATE_FULL;
1265
1266 if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
1267 rc = audmgr_open(&audio->audmgr);
1268 if (rc)
1269 goto done;
1270 }
1271
1272 encid = audpreproc_aenc_alloc(audio->enc_type, &audio->module_name,
1273 &audio->queue_ids);
1274 if (encid < 0) {
1275 MM_ERR("No free encoder available\n");
1276 rc = -ENODEV;
1277 goto done;
1278 }
1279 audio->enc_id = encid;
1280
1281 rc = msm_adsp_get(audio->module_name, &audio->audrec,
1282 &audrec_qcelp_adsp_ops, audio);
1283 if (rc) {
1284 audpreproc_aenc_free(audio->enc_id);
1285 goto done;
1286 }
1287
1288 if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
1289 rc = msm_adsp_get("AUDPREPROCTASK", &audio->audpre,
1290 &audpre_qcelp_adsp_ops, audio);
1291 if (rc) {
1292 msm_adsp_put(audio->audrec);
1293 audpreproc_aenc_free(audio->enc_id);
1294 goto done;
1295 }
1296 }
1297
1298 audio->dsp_cnt = 0;
1299 audio->stopped = 0;
1300 audio->wflush = 0;
1301 audio->rflush = 0;
1302 audio->flush_ack = 0;
1303
1304 audqcelp_in_flush(audio);
1305 audqcelp_out_flush(audio);
1306
Sidipotu Ashok172c98b2012-06-26 17:58:29 +05301307 client = msm_ion_client_create(UINT_MAX, "Audio_QCELP_in_client");
1308 if (IS_ERR_OR_NULL(client)) {
1309 MM_ERR("Unable to create ION client\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001310 rc = -ENOMEM;
Sidipotu Ashok172c98b2012-06-26 17:58:29 +05301311 goto client_create_error;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001312 }
Sidipotu Ashok172c98b2012-06-26 17:58:29 +05301313 audio->client = client;
1314
1315 MM_DBG("allocating mem sz = %d\n", dma_size);
1316 handle = ion_alloc(client, dma_size, SZ_4K,
1317 ION_HEAP(ION_AUDIO_HEAP_ID));
1318 if (IS_ERR_OR_NULL(handle)) {
1319 MM_ERR("Unable to create allocate O/P buffers\n");
1320 rc = -ENOMEM;
1321 goto output_buff_alloc_error;
1322 }
1323
1324 audio->output_buff_handle = handle;
1325
1326 rc = ion_phys(client , handle, &addr, &len);
1327 if (rc) {
1328 MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
1329 (unsigned int) addr, (unsigned int) len);
1330 rc = -ENOMEM;
1331 goto output_buff_get_phys_error;
1332 } else {
1333 MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
1334 (unsigned int) addr, (unsigned int) len);
1335 }
1336 audio->phys = (int32_t)addr;
1337
1338 rc = ion_handle_get_flags(client, handle, &ionflag);
1339 if (rc) {
1340 MM_ERR("could not get flags for the handle\n");
1341 rc = -ENOMEM;
1342 goto output_buff_get_flags_error;
1343 }
1344
1345 audio->map_v_read = ion_map_kernel(client, handle, ionflag);
1346 if (IS_ERR(audio->map_v_read)) {
1347 MM_ERR("could not map read buffers,freeing instance 0x%08x\n",
1348 (int)audio);
1349 rc = -ENOMEM;
1350 goto output_buff_map_error;
1351 }
1352 audio->data = audio->map_v_read;
1353 MM_DBG("read buf: phy addr 0x%08x kernel addr 0x%08x\n",
1354 audio->phys, (int)audio->data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001355
1356 audio->out_data = NULL;
1357 if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) {
Sidipotu Ashok172c98b2012-06-26 17:58:29 +05301358 MM_DBG("allocating BUFFER_SIZE %d\n", BUFFER_SIZE);
1359 handle = ion_alloc(client, BUFFER_SIZE,
1360 SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
1361 if (IS_ERR_OR_NULL(handle)) {
1362 MM_ERR("Unable to create allocate I/P buffers\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001363 rc = -ENOMEM;
Sidipotu Ashok172c98b2012-06-26 17:58:29 +05301364 goto input_buff_alloc_error;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001365 }
1366
Sidipotu Ashok172c98b2012-06-26 17:58:29 +05301367 audio->input_buff_handle = handle;
1368
1369 rc = ion_phys(client , handle, &addr, &len);
1370 if (rc) {
1371 MM_ERR("I/P buffers:Invalid phy: %x sz: %x\n",
1372 (unsigned int) addr, (unsigned int) len);
1373 rc = -ENOMEM;
1374 goto input_buff_get_phys_error;
1375 } else {
1376 MM_INFO("Got valid phy: %x sz: %x\n",
1377 (unsigned int) addr,
1378 (unsigned int) len);
1379 }
1380 audio->out_phys = (int32_t)addr;
1381
1382 rc = ion_handle_get_flags(client,
1383 handle, &ionflag);
1384 if (rc) {
1385 MM_ERR("could not get flags for the handle\n");
1386 rc = -ENOMEM;
1387 goto input_buff_get_flags_error;
1388 }
1389
1390 audio->map_v_write = ion_map_kernel(client,
1391 handle, ionflag);
1392 if (IS_ERR(audio->map_v_write)) {
1393 MM_ERR("could not map write buffers\n");
1394 rc = -ENOMEM;
1395 goto input_buff_map_error;
1396 }
1397 audio->out_data = audio->map_v_write;
1398 MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
1399 (unsigned int)addr,
1400 (unsigned int)audio->out_data);
1401
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001402 /* Initialize buffer */
1403 audio->out[0].data = audio->out_data + 0;
1404 audio->out[0].addr = audio->out_phys + 0;
1405 audio->out[0].size = OUT_BUFFER_SIZE;
1406
1407 audio->out[1].data = audio->out_data + OUT_BUFFER_SIZE;
1408 audio->out[1].addr = audio->out_phys + OUT_BUFFER_SIZE;
1409 audio->out[1].size = OUT_BUFFER_SIZE;
1410
1411 MM_DBG("audio->out[0].data = %d audio->out[1].data = %d",
1412 (unsigned int)audio->out[0].data,
1413 (unsigned int)audio->out[1].data);
1414 audio->mfield = NT_FRAME_HEADER_SIZE;
1415 audio->out_frame_cnt++;
1416 }
1417 file->private_data = audio;
1418 audio->opened = 1;
1419
1420done:
1421 mutex_unlock(&audio->lock);
1422 return rc;
Sidipotu Ashok172c98b2012-06-26 17:58:29 +05301423input_buff_map_error:
1424input_buff_get_flags_error:
1425input_buff_get_phys_error:
1426 ion_free(client, audio->input_buff_handle);
1427input_buff_alloc_error:
1428 ion_unmap_kernel(client, audio->output_buff_handle);
1429output_buff_map_error:
1430output_buff_get_phys_error:
1431output_buff_get_flags_error:
1432 ion_free(client, audio->output_buff_handle);
1433output_buff_alloc_error:
1434 ion_client_destroy(client);
1435client_create_error:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001436 msm_adsp_put(audio->audrec);
1437 if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
1438 msm_adsp_put(audio->audpre);
1439
1440 audpreproc_aenc_free(audio->enc_id);
1441 mutex_unlock(&audio->lock);
1442 return rc;
1443}
1444
1445static const struct file_operations audio_qcelp_in_fops = {
1446 .owner = THIS_MODULE,
1447 .open = audqcelp_in_open,
1448 .release = audqcelp_in_release,
1449 .read = audqcelp_in_read,
1450 .write = audqcelp_in_write,
1451 .fsync = audqcelp_in_fsync,
1452 .unlocked_ioctl = audqcelp_in_ioctl,
1453};
1454
1455static struct miscdevice audqcelp_in_misc = {
1456 .minor = MISC_DYNAMIC_MINOR,
1457 .name = "msm_qcelp_in",
1458 .fops = &audio_qcelp_in_fops,
1459};
1460
1461static int __init audqcelp_in_init(void)
1462{
1463 mutex_init(&the_audio_qcelp_in.lock);
1464 mutex_init(&the_audio_qcelp_in.read_lock);
1465 spin_lock_init(&the_audio_qcelp_in.dsp_lock);
1466 init_waitqueue_head(&the_audio_qcelp_in.wait);
1467 init_waitqueue_head(&the_audio_qcelp_in.wait_enable);
1468 mutex_init(&the_audio_qcelp_in.write_lock);
1469 init_waitqueue_head(&the_audio_qcelp_in.write_wait);
1470 return misc_register(&audqcelp_in_misc);
1471}
1472device_initcall(audqcelp_in_init);