blob: cfda4b93e54c4362e9e8ac841e498c9834b66434 [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 *
Asish Bhattacharya4a064192013-10-01 17:15:05 +05305 * Copyright (c) 2011-2013, 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;
Asish Bhattacharya4a064192013-10-01 17:15:05 +0530735 memset(&stats, 0, sizeof(stats));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700736 stats.byte_count = atomic_read(&audio->in_bytes);
737 stats.sample_count = atomic_read(&audio->in_samples);
738 if (copy_to_user((void *) arg, &stats, sizeof(stats)))
739 return -EFAULT;
740 return rc;
741 }
742
743 mutex_lock(&audio->lock);
744 switch (cmd) {
745 case AUDIO_START: {
746 rc = audqcelp_in_enable(audio);
747 if (!rc) {
748 rc =
749 wait_event_interruptible_timeout(audio->wait_enable,
750 audio->running != 0, 1*HZ);
751 MM_DBG("state %d rc = %d\n", audio->running, rc);
752
753 if (audio->running == 0)
754 rc = -ENODEV;
755 else
756 rc = 0;
757 }
758 audio->stopped = 0;
759 break;
760 }
761 case AUDIO_STOP: {
762 rc = audqcelp_in_disable(audio);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700763 break;
764 }
765 case AUDIO_FLUSH: {
766 MM_DBG("AUDIO_FLUSH\n");
767 audio->rflush = 1;
768 audio->wflush = 1;
769 audqcelp_ioport_reset(audio);
770 if (audio->running) {
771 audqcelp_flush_command(audio);
772 rc = wait_event_interruptible(audio->write_wait,
773 !audio->wflush);
774 if (rc < 0) {
775 MM_ERR("AUDIO_FLUSH interrupted\n");
776 rc = -EINTR;
777 }
778 } else {
779 audio->rflush = 0;
780 audio->wflush = 0;
781 }
782 break;
783 }
784 case AUDIO_GET_CONFIG: {
785 struct msm_audio_config cfg;
786 memset(&cfg, 0, sizeof(cfg));
787 cfg.buffer_size = OUT_BUFFER_SIZE;
788 cfg.buffer_count = OUT_FRAME_NUM;
789 cfg.sample_rate = convert_samp_index(audio->samp_rate);
790 cfg.channel_count = 1;
791 cfg.type = 0;
792 cfg.unused[0] = 0;
793 cfg.unused[1] = 0;
794 cfg.unused[2] = 0;
795 if (copy_to_user((void *) arg, &cfg, sizeof(cfg)))
796 rc = -EFAULT;
797 else
798 rc = 0;
799 break;
800 }
801 case AUDIO_GET_STREAM_CONFIG: {
802 struct msm_audio_stream_config cfg;
803 memset(&cfg, 0, sizeof(cfg));
804 cfg.buffer_size = audio->buffer_size;
805 cfg.buffer_count = FRAME_NUM;
806 if (copy_to_user((void *)arg, &cfg, sizeof(cfg)))
807 rc = -EFAULT;
808 else
809 rc = 0;
810 break;
811 }
812 case AUDIO_SET_STREAM_CONFIG: {
813 struct msm_audio_stream_config cfg;
814 if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) {
815 rc = -EFAULT;
816 break;
817 }
818 /* Allow only single frame */
819 if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
Phani Kumar Alladaee940eb2012-05-10 11:13:04 +0530820 if (cfg.buffer_size != (FRAME_SIZE - 8)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700821 rc = -EINVAL;
822 break;
Phani Kumar Alladaee940eb2012-05-10 11:13:04 +0530823 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700824 } else {
Phani Kumar Alladaee940eb2012-05-10 11:13:04 +0530825 if (cfg.buffer_size != (QCELP_FRAME_SIZE + 14)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700826 rc = -EINVAL;
827 break;
Phani Kumar Alladaee940eb2012-05-10 11:13:04 +0530828 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700829 }
830 audio->buffer_size = cfg.buffer_size;
831 break;
832 }
833 case AUDIO_GET_QCELP_ENC_CONFIG: {
834 if (copy_to_user((void *) arg, &audio->cfg, sizeof(audio->cfg)))
835 rc = -EFAULT;
836 break;
837 }
838 case AUDIO_SET_QCELP_ENC_CONFIG: {
839 struct msm_audio_qcelp_enc_config cfg;
840 if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) {
841 rc = -EFAULT;
842 break;
843 }
844 MM_DBG("0X%8x, 0x%8x, 0x%8x\n", cfg.min_bit_rate,
845 cfg.max_bit_rate, cfg.cdma_rate);
846 if (cfg.min_bit_rate > CDMA_RATE_FULL || \
847 cfg.min_bit_rate < CDMA_RATE_EIGHTH) {
848 MM_ERR("invalid min bitrate\n");
849 rc = -EFAULT;
850 break;
851 }
852 if (cfg.max_bit_rate > CDMA_RATE_FULL || \
853 cfg.max_bit_rate < CDMA_RATE_EIGHTH) {
854 MM_ERR("invalid max bitrate\n");
855 rc = -EFAULT;
856 break;
857 }
858 /* Recording Does not support Erase and Blank */
859 if (cfg.cdma_rate > CDMA_RATE_FULL ||
860 cfg.cdma_rate < CDMA_RATE_EIGHTH) {
861 MM_ERR("invalid qcelp cdma rate\n");
862 rc = -EFAULT;
863 break;
864 }
865 memcpy(&audio->cfg, &cfg, sizeof(cfg));
866 break;
867 }
868 default:
869 rc = -EINVAL;
870 }
871 mutex_unlock(&audio->lock);
872 return rc;
873}
874
875static ssize_t audqcelp_in_read(struct file *file,
876 char __user *buf,
877 size_t count, loff_t *pos)
878{
879 struct audio_qcelp_in *audio = file->private_data;
880 unsigned long flags;
881 const char __user *start = buf;
882 void *data;
883 uint32_t index;
884 uint32_t size;
885 int rc = 0;
886 struct qcelp_encoded_meta_out meta_field;
887 struct audio_frame_nt *nt_frame;
888 MM_DBG("count = %d\n", count);
889 mutex_lock(&audio->read_lock);
890 while (count > 0) {
891 rc = wait_event_interruptible(
892 audio->wait, (audio->in_count > 0) || audio->stopped ||
893 audio->rflush);
894 if (rc < 0)
895 break;
896
897 if (audio->rflush) {
898 rc = -EBUSY;
899 break;
900 }
901 if (audio->stopped && !audio->in_count) {
902 MM_DBG("Driver in stop state, No more buffer to read");
903 rc = 0;/* End of File */
904 break;
905 }
906
907 index = audio->in_tail;
908 data = (uint8_t *) audio->in[index].data;
909 size = audio->in[index].size;
910
911 if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) {
912 nt_frame = (struct audio_frame_nt *)(data -
913 sizeof(struct audio_frame_nt));
914 memcpy((char *)&meta_field.time_stamp_dword_lsw,
915 (char *)&nt_frame->time_stamp_dword_lsw,
916 (sizeof(struct qcelp_encoded_meta_out) - \
917 sizeof(uint16_t)));
918 meta_field.metadata_len =
919 sizeof(struct qcelp_encoded_meta_out);
920 if (copy_to_user((char *)start, (char *)&meta_field,
921 sizeof(struct qcelp_encoded_meta_out))) {
922 rc = -EFAULT;
923 break;
924 }
925 if (nt_frame->nflag_lsw & 0x0001) {
926 MM_ERR("recieved EOS in read call\n");
927 audio->eos_ack = 1;
928 }
929 buf += sizeof(struct qcelp_encoded_meta_out);
930 count -= sizeof(struct qcelp_encoded_meta_out);
931 }
932 if (count >= size) {
933 /* order the reads on the buffer */
934 dma_coherent_post_ops();
935 if (copy_to_user(buf, data, size)) {
936 rc = -EFAULT;
937 break;
938 }
939 spin_lock_irqsave(&audio->dsp_lock, flags);
940 if (index != audio->in_tail) {
941 /* overrun -- data is
942 * invalid and we need to retry */
943 spin_unlock_irqrestore(&audio->dsp_lock, flags);
944 continue;
945 }
946 audio->in[index].size = 0;
947 audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1);
948 audio->in_count--;
949 spin_unlock_irqrestore(&audio->dsp_lock, flags);
950 count -= size;
951 buf += size;
952 if ((audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL)) {
953 if (!audio->eos_ack) {
954 MM_DBG("sending read ptr command \
955 %d %d\n",
956 audio->dsp_cnt,
957 audio->in_tail);
958 audqcelp_in_dsp_read_buffer(audio,
959 audio->dsp_cnt++);
960 }
961 }
962 } else {
963 MM_ERR("short read\n");
964 break;
965 }
966 break;
967 }
968 mutex_unlock(&audio->read_lock);
969
970 if (buf > start)
971 return buf - start;
972
973 return rc;
974}
975
976static void audrec_pcm_send_data(struct audio_qcelp_in *audio, unsigned needed)
977{
978 struct buffer *frame;
979 unsigned long flags;
980 MM_DBG("\n");
981 spin_lock_irqsave(&audio->dsp_lock, flags);
982 if (!audio->running)
983 goto done;
984
985 if (needed && !audio->wflush) {
986 /* We were called from the callback because the DSP
987 * requested more data. Note that the DSP does want
988 * more data, and if a buffer was in-flight, mark it
989 * as available (since the DSP must now be done with
990 * it).
991 */
992 audio->out_needed = 1;
993 frame = audio->out + audio->out_tail;
994 if (frame->used == 0xffffffff) {
995 MM_DBG("frame %d free\n", audio->out_tail);
996 frame->used = 0;
997 audio->out_tail ^= 1;
998 wake_up(&audio->write_wait);
999 }
1000 }
1001
1002 if (audio->out_needed) {
1003 /* If the DSP currently wants data and we have a
1004 * buffer available, we will send it and reset
1005 * the needed flag. We'll mark the buffer as in-flight
1006 * so that it won't be recycled until the next buffer
1007 * is requested
1008 */
1009
1010 frame = audio->out + audio->out_tail;
1011 if (frame->used) {
1012 BUG_ON(frame->used == 0xffffffff);
1013 audrec_pcm_buffer_ptr_refresh(audio,
1014 audio->out_tail,
1015 frame->used);
1016 frame->used = 0xffffffff;
1017 audio->out_needed = 0;
1018 }
1019 }
1020 done:
1021 spin_unlock_irqrestore(&audio->dsp_lock, flags);
1022}
1023
Sidipotu Ashok172c98b2012-06-26 17:58:29 +05301024static int audqcelp_in_fsync(struct file *file, loff_t a, loff_t b,
1025 int datasync)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001026
1027{
1028 struct audio_qcelp_in *audio = file->private_data;
1029 int rc = 0;
1030
1031 MM_DBG("\n"); /* Macro prints the file name and function */
1032 if (!audio->running || (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)) {
1033 rc = -EINVAL;
1034 goto done_nolock;
1035 }
1036
1037 mutex_lock(&audio->write_lock);
1038
1039 rc = wait_event_interruptible(audio->write_wait,
1040 audio->wflush);
1041 MM_DBG("waked on by some event audio->wflush = %d\n", audio->wflush);
1042
1043 if (rc < 0)
1044 goto done;
1045 else if (audio->wflush) {
1046 rc = -EBUSY;
1047 goto done;
1048 }
1049done:
1050 mutex_unlock(&audio->write_lock);
1051done_nolock:
1052 return rc;
1053
1054}
1055
1056int audrec_qcelp_process_eos(struct audio_qcelp_in *audio,
1057 const char __user *buf_start, unsigned short mfield_size)
1058{
1059 struct buffer *frame;
1060 int rc = 0;
1061
1062 frame = audio->out + audio->out_head;
1063
1064 rc = wait_event_interruptible(audio->write_wait,
1065 (audio->out_needed &&
1066 audio->out[0].used == 0 &&
1067 audio->out[1].used == 0)
1068 || (audio->stopped)
1069 || (audio->wflush));
1070
1071 if (rc < 0)
1072 goto done;
1073 if (audio->stopped || audio->wflush) {
1074 rc = -EBUSY;
1075 goto done;
1076 }
1077 if (copy_from_user(frame->data, buf_start, mfield_size)) {
1078 rc = -EFAULT;
1079 goto done;
1080 }
1081
1082 frame->mfield_sz = mfield_size;
1083 audio->out_head ^= 1;
1084 frame->used = mfield_size;
1085 MM_DBG("copying meta_out frame->used = %d\n", frame->used);
1086 audrec_pcm_send_data(audio, 0);
1087done:
1088 return rc;
1089}
1090
1091static ssize_t audqcelp_in_write(struct file *file,
1092 const char __user *buf,
1093 size_t count, loff_t *pos)
1094{
1095 struct audio_qcelp_in *audio = file->private_data;
1096 const char __user *start = buf;
1097 struct buffer *frame;
1098 char *cpy_ptr;
1099 int rc = 0, eos_condition = AUDPREPROC_QCELP_EOS_NONE;
1100 unsigned short mfield_size = 0;
1101 int write_count = 0;
1102 MM_DBG("cnt=%d\n", count);
1103
1104 if (count & 1)
1105 return -EINVAL;
1106
1107 if (audio->mode != MSM_AUD_ENC_MODE_NONTUNNEL)
1108 return -EINVAL;
1109
1110 mutex_lock(&audio->write_lock);
1111 frame = audio->out + audio->out_head;
1112 /* if supplied count is more than driver buffer size
1113 * then only copy driver buffer size
1114 */
1115 if (count > frame->size)
1116 count = frame->size;
1117
1118 write_count = count;
1119 cpy_ptr = frame->data;
1120 rc = wait_event_interruptible(audio->write_wait,
1121 (frame->used == 0)
1122 || (audio->stopped)
1123 || (audio->wflush));
1124 if (rc < 0)
1125 goto error;
1126
1127 if (audio->stopped || audio->wflush) {
1128 rc = -EBUSY;
1129 goto error;
1130 }
1131 if (audio->mfield) {
1132 if (buf == start) {
1133 /* Processing beginning of user buffer */
1134 if (__get_user(mfield_size,
1135 (unsigned short __user *) buf)) {
1136 rc = -EFAULT;
1137 goto error;
1138 } else if (mfield_size > count) {
1139 rc = -EINVAL;
1140 goto error;
1141 }
1142 MM_DBG("mf offset_val %x\n", mfield_size);
1143 if (copy_from_user(cpy_ptr, buf, mfield_size)) {
1144 rc = -EFAULT;
1145 goto error;
1146 }
1147 /* Check if EOS flag is set and buffer has
1148 * contains just meta field
1149 */
1150 if (cpy_ptr[AUDPREPROC_QCELP_EOS_FLG_OFFSET] &
1151 AUDPREPROC_QCELP_EOS_FLG_MASK) {
1152 eos_condition = AUDPREPROC_QCELP_EOS_SET;
1153 MM_DBG("EOS SET\n");
1154 if (mfield_size == count) {
1155 buf += mfield_size;
1156 eos_condition = 0;
1157 goto exit;
1158 } else
1159 cpy_ptr[AUDPREPROC_QCELP_EOS_FLG_OFFSET] &=
1160 ~AUDPREPROC_QCELP_EOS_FLG_MASK;
1161 }
1162 cpy_ptr += mfield_size;
1163 count -= mfield_size;
1164 buf += mfield_size;
1165 } else {
1166 mfield_size = 0;
1167 MM_DBG("continuous buffer\n");
1168 }
1169 frame->mfield_sz = mfield_size;
1170 }
1171 MM_DBG("copying the stream count = %d\n", count);
1172 if (copy_from_user(cpy_ptr, buf, count)) {
1173 rc = -EFAULT;
1174 goto error;
1175 }
1176exit:
1177 frame->used = count;
1178 audio->out_head ^= 1;
1179 if (!audio->flush_ack)
1180 audrec_pcm_send_data(audio, 0);
1181 else {
1182 audrec_pcm_send_data(audio, 1);
1183 audio->flush_ack = 0;
1184 }
1185 if (eos_condition == AUDPREPROC_QCELP_EOS_SET)
1186 rc = audrec_qcelp_process_eos(audio, start, mfield_size);
1187 mutex_unlock(&audio->write_lock);
1188 return write_count;
1189error:
1190 mutex_unlock(&audio->write_lock);
1191 return rc;
1192}
1193
1194static int audqcelp_in_release(struct inode *inode, struct file *file)
1195{
1196 struct audio_qcelp_in *audio = file->private_data;
1197
1198 mutex_lock(&audio->lock);
1199 audqcelp_in_disable(audio);
1200 audqcelp_in_flush(audio);
1201 msm_adsp_put(audio->audrec);
1202
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001203 audpreproc_aenc_free(audio->enc_id);
1204 audio->audrec = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001205 audio->opened = 0;
1206
1207 if ((audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) && \
1208 (audio->out_data)) {
Sidipotu Ashok172c98b2012-06-26 17:58:29 +05301209 ion_unmap_kernel(audio->client, audio->input_buff_handle);
1210 ion_free(audio->client, audio->input_buff_handle);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001211 audio->out_data = NULL;
1212 }
1213
1214 if (audio->data) {
Sidipotu Ashok172c98b2012-06-26 17:58:29 +05301215 ion_unmap_kernel(audio->client, audio->output_buff_handle);
1216 ion_free(audio->client, audio->output_buff_handle);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001217 audio->data = NULL;
1218 }
Sidipotu Ashok172c98b2012-06-26 17:58:29 +05301219 ion_client_destroy(audio->client);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001220 mutex_unlock(&audio->lock);
1221 return 0;
1222}
1223
1224static struct audio_qcelp_in the_audio_qcelp_in;
1225
1226static int audqcelp_in_open(struct inode *inode, struct file *file)
1227{
1228 struct audio_qcelp_in *audio = &the_audio_qcelp_in;
1229 int rc;
1230 int encid;
1231 int dma_size = 0;
Sidipotu Ashok172c98b2012-06-26 17:58:29 +05301232 int len = 0;
1233 unsigned long ionflag = 0;
1234 ion_phys_addr_t addr = 0;
1235 struct ion_handle *handle = NULL;
1236 struct ion_client *client = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001237
1238 mutex_lock(&audio->lock);
1239 if (audio->opened) {
1240 rc = -EBUSY;
1241 goto done;
1242 }
1243 if ((file->f_mode & FMODE_WRITE) &&
1244 (file->f_mode & FMODE_READ)) {
1245 audio->mode = MSM_AUD_ENC_MODE_NONTUNNEL;
1246 dma_size = NT_DMASZ;
1247 MM_DBG("Opened for non tunnel mode encoding\n");
1248 } else if (!(file->f_mode & FMODE_WRITE) &&
1249 (file->f_mode & FMODE_READ)) {
1250 audio->mode = MSM_AUD_ENC_MODE_TUNNEL;
1251 dma_size = DMASZ;
1252 MM_DBG("Opened for tunnel mode encoding\n");
1253 } else {
1254 MM_ERR("Invalid mode\n");
1255 rc = -EACCES;
1256 goto done;
1257 }
1258
1259 /* Settings will be re-config at AUDIO_SET_CONFIG,
1260 * but at least we need to have initial config
1261 */
1262 audio->samp_rate = RPC_AUD_DEF_SAMPLE_RATE_8000,
1263 audio->samp_rate_index = AUDREC_CMD_SAMP_RATE_INDX_8000;
1264 audio->channel_mode = AUDREC_CMD_STEREO_MODE_MONO;
1265 if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL)
1266 audio->buffer_size = (QCELP_FRAME_SIZE + 14);
1267 else
1268 audio->buffer_size = QCELP_FRAME_SIZE;
1269 audio->enc_type = AUDREC_CMD_TYPE_0_INDEX_QCELP | audio->mode;
1270
1271 audio->cfg.cdma_rate = CDMA_RATE_FULL;
1272 audio->cfg.min_bit_rate = CDMA_RATE_FULL;
1273 audio->cfg.max_bit_rate = CDMA_RATE_FULL;
1274
1275 if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
1276 rc = audmgr_open(&audio->audmgr);
1277 if (rc)
1278 goto done;
1279 }
1280
1281 encid = audpreproc_aenc_alloc(audio->enc_type, &audio->module_name,
1282 &audio->queue_ids);
1283 if (encid < 0) {
1284 MM_ERR("No free encoder available\n");
1285 rc = -ENODEV;
1286 goto done;
1287 }
1288 audio->enc_id = encid;
1289
1290 rc = msm_adsp_get(audio->module_name, &audio->audrec,
1291 &audrec_qcelp_adsp_ops, audio);
1292 if (rc) {
1293 audpreproc_aenc_free(audio->enc_id);
1294 goto done;
1295 }
1296
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001297 audio->dsp_cnt = 0;
1298 audio->stopped = 0;
1299 audio->wflush = 0;
1300 audio->rflush = 0;
1301 audio->flush_ack = 0;
1302
1303 audqcelp_in_flush(audio);
1304 audqcelp_out_flush(audio);
1305
Sidipotu Ashok172c98b2012-06-26 17:58:29 +05301306 client = msm_ion_client_create(UINT_MAX, "Audio_QCELP_in_client");
1307 if (IS_ERR_OR_NULL(client)) {
1308 MM_ERR("Unable to create ION client\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001309 rc = -ENOMEM;
Sidipotu Ashok172c98b2012-06-26 17:58:29 +05301310 goto client_create_error;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001311 }
Sidipotu Ashok172c98b2012-06-26 17:58:29 +05301312 audio->client = client;
1313
1314 MM_DBG("allocating mem sz = %d\n", dma_size);
1315 handle = ion_alloc(client, dma_size, SZ_4K,
Hanumant Singh7d72bad2012-08-29 18:39:44 -07001316 ION_HEAP(ION_AUDIO_HEAP_ID), 0);
Sidipotu Ashok172c98b2012-06-26 17:58:29 +05301317 if (IS_ERR_OR_NULL(handle)) {
1318 MM_ERR("Unable to create allocate O/P buffers\n");
1319 rc = -ENOMEM;
1320 goto output_buff_alloc_error;
1321 }
1322
1323 audio->output_buff_handle = handle;
1324
1325 rc = ion_phys(client , handle, &addr, &len);
1326 if (rc) {
1327 MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
1328 (unsigned int) addr, (unsigned int) len);
1329 rc = -ENOMEM;
1330 goto output_buff_get_phys_error;
1331 } else {
1332 MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
1333 (unsigned int) addr, (unsigned int) len);
1334 }
1335 audio->phys = (int32_t)addr;
1336
1337 rc = ion_handle_get_flags(client, handle, &ionflag);
1338 if (rc) {
1339 MM_ERR("could not get flags for the handle\n");
1340 rc = -ENOMEM;
1341 goto output_buff_get_flags_error;
1342 }
1343
Mitchel Humpherys911b4b72012-09-12 14:42:50 -07001344 audio->map_v_read = ion_map_kernel(client, handle);
Sidipotu Ashok172c98b2012-06-26 17:58:29 +05301345 if (IS_ERR(audio->map_v_read)) {
1346 MM_ERR("could not map read buffers,freeing instance 0x%08x\n",
1347 (int)audio);
1348 rc = -ENOMEM;
1349 goto output_buff_map_error;
1350 }
1351 audio->data = audio->map_v_read;
1352 MM_DBG("read buf: phy addr 0x%08x kernel addr 0x%08x\n",
1353 audio->phys, (int)audio->data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001354
1355 audio->out_data = NULL;
1356 if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) {
Sidipotu Ashok172c98b2012-06-26 17:58:29 +05301357 MM_DBG("allocating BUFFER_SIZE %d\n", BUFFER_SIZE);
1358 handle = ion_alloc(client, BUFFER_SIZE,
Hanumant Singh7d72bad2012-08-29 18:39:44 -07001359 SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0);
Sidipotu Ashok172c98b2012-06-26 17:58:29 +05301360 if (IS_ERR_OR_NULL(handle)) {
1361 MM_ERR("Unable to create allocate I/P buffers\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001362 rc = -ENOMEM;
Sidipotu Ashok172c98b2012-06-26 17:58:29 +05301363 goto input_buff_alloc_error;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001364 }
1365
Sidipotu Ashok172c98b2012-06-26 17:58:29 +05301366 audio->input_buff_handle = handle;
1367
1368 rc = ion_phys(client , handle, &addr, &len);
1369 if (rc) {
1370 MM_ERR("I/P buffers:Invalid phy: %x sz: %x\n",
1371 (unsigned int) addr, (unsigned int) len);
1372 rc = -ENOMEM;
1373 goto input_buff_get_phys_error;
1374 } else {
1375 MM_INFO("Got valid phy: %x sz: %x\n",
1376 (unsigned int) addr,
1377 (unsigned int) len);
1378 }
1379 audio->out_phys = (int32_t)addr;
1380
1381 rc = ion_handle_get_flags(client,
1382 handle, &ionflag);
1383 if (rc) {
1384 MM_ERR("could not get flags for the handle\n");
1385 rc = -ENOMEM;
1386 goto input_buff_get_flags_error;
1387 }
1388
Mitchel Humpherys911b4b72012-09-12 14:42:50 -07001389 audio->map_v_write = ion_map_kernel(client, handle);
Sidipotu Ashok172c98b2012-06-26 17:58:29 +05301390 if (IS_ERR(audio->map_v_write)) {
1391 MM_ERR("could not map write buffers\n");
1392 rc = -ENOMEM;
1393 goto input_buff_map_error;
1394 }
1395 audio->out_data = audio->map_v_write;
1396 MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
1397 (unsigned int)addr,
1398 (unsigned int)audio->out_data);
1399
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001400 /* Initialize buffer */
1401 audio->out[0].data = audio->out_data + 0;
1402 audio->out[0].addr = audio->out_phys + 0;
1403 audio->out[0].size = OUT_BUFFER_SIZE;
1404
1405 audio->out[1].data = audio->out_data + OUT_BUFFER_SIZE;
1406 audio->out[1].addr = audio->out_phys + OUT_BUFFER_SIZE;
1407 audio->out[1].size = OUT_BUFFER_SIZE;
1408
1409 MM_DBG("audio->out[0].data = %d audio->out[1].data = %d",
1410 (unsigned int)audio->out[0].data,
1411 (unsigned int)audio->out[1].data);
1412 audio->mfield = NT_FRAME_HEADER_SIZE;
1413 audio->out_frame_cnt++;
1414 }
1415 file->private_data = audio;
1416 audio->opened = 1;
1417
1418done:
1419 mutex_unlock(&audio->lock);
1420 return rc;
Sidipotu Ashok172c98b2012-06-26 17:58:29 +05301421input_buff_map_error:
1422input_buff_get_flags_error:
1423input_buff_get_phys_error:
1424 ion_free(client, audio->input_buff_handle);
1425input_buff_alloc_error:
1426 ion_unmap_kernel(client, audio->output_buff_handle);
1427output_buff_map_error:
1428output_buff_get_phys_error:
1429output_buff_get_flags_error:
1430 ion_free(client, audio->output_buff_handle);
1431output_buff_alloc_error:
1432 ion_client_destroy(client);
1433client_create_error:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001434 msm_adsp_put(audio->audrec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001435
1436 audpreproc_aenc_free(audio->enc_id);
1437 mutex_unlock(&audio->lock);
1438 return rc;
1439}
1440
1441static const struct file_operations audio_qcelp_in_fops = {
1442 .owner = THIS_MODULE,
1443 .open = audqcelp_in_open,
1444 .release = audqcelp_in_release,
1445 .read = audqcelp_in_read,
1446 .write = audqcelp_in_write,
1447 .fsync = audqcelp_in_fsync,
1448 .unlocked_ioctl = audqcelp_in_ioctl,
1449};
1450
1451static struct miscdevice audqcelp_in_misc = {
1452 .minor = MISC_DYNAMIC_MINOR,
1453 .name = "msm_qcelp_in",
1454 .fops = &audio_qcelp_in_fops,
1455};
1456
1457static int __init audqcelp_in_init(void)
1458{
1459 mutex_init(&the_audio_qcelp_in.lock);
1460 mutex_init(&the_audio_qcelp_in.read_lock);
1461 spin_lock_init(&the_audio_qcelp_in.dsp_lock);
1462 init_waitqueue_head(&the_audio_qcelp_in.wait);
1463 init_waitqueue_head(&the_audio_qcelp_in.wait_enable);
1464 mutex_init(&the_audio_qcelp_in.write_lock);
1465 init_waitqueue_head(&the_audio_qcelp_in.write_wait);
1466 return misc_register(&audqcelp_in_misc);
1467}
1468device_initcall(audqcelp_in_init);