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