blob: 0eca74d5825ae480a85ffb3b8963e9a7c1113cdc [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* arch/arm/mach-msm/qdsp5/audio_amrnb_in.c
2 *
3 * amrnb encoder device
4 *
Asish Bhattacharya4a064192013-10-01 17:15:05 +05305 * Copyright (c) 2009, 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/qdsp5/audio_in.c, which is
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.
18 *
19 * See the GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, you can find it at http://www.fsf.org.
22 *
23 */
24
Manish Dewanganb9171e52011-03-15 15:18:18 +053025
26#include <asm/atomic.h>
27#include <asm/ioctls.h>
28
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070029#include <linux/module.h>
30#include <linux/fs.h>
31#include <linux/miscdevice.h>
32#include <linux/uaccess.h>
33#include <linux/kthread.h>
34#include <linux/wait.h>
35#include <linux/dma-mapping.h>
36#include <linux/debugfs.h>
37#include <linux/delay.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070038#include <linux/msm_audio_amrnb.h>
Manish Dewanganb9171e52011-03-15 15:18:18 +053039#include <linux/memory_alloc.h>
Mitchel Humpherys1da6ebe2012-09-06 10:15:56 -070040#include <linux/msm_ion.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070041
42#include "audmgr.h"
43
Manish Dewanganb9171e52011-03-15 15:18:18 +053044#include <mach/msm_rpcrouter.h>
45#include <mach/msm_memtypes.h>
46#include <mach/iommu.h>
Manish Dewanganb9171e52011-03-15 15:18:18 +053047#include <mach/iommu_domains.h>
48
49#include <mach/msm_adsp.h>
50#include <mach/qdsp5/qdsp5audpreproc.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070051#include <mach/qdsp5/qdsp5audpreproccmdi.h>
52#include <mach/qdsp5/qdsp5audpreprocmsg.h>
53#include <mach/qdsp5/qdsp5audreccmdi.h>
54#include <mach/qdsp5/qdsp5audrecmsg.h>
55#include <mach/debug_mm.h>
56
Manish Dewanganb9171e52011-03-15 15:18:18 +053057#define FRAME_HEADER_SIZE 8 /* 8 bytes frame header */
58#define NT_FRAME_HEADER_SIZE 24 /* 24 bytes frame header */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070059/* FRAME_NUM must be a power of two */
Manish Dewanganb9171e52011-03-15 15:18:18 +053060#define FRAME_NUM 8
61#define AMRNB_FRAME_SIZE 36 /* 36 bytes data */
62/*Tunnel mode : 1536 bytes data + 8 byte header*/
63#define FRAME_SIZE (AMRNB_FRAME_SIZE + FRAME_HEADER_SIZE)
64/* 1536 bytes data + 24 meta field*/
65#define NT_FRAME_SIZE (AMRNB_FRAME_SIZE + NT_FRAME_HEADER_SIZE)
66#define DMASZ (FRAME_SIZE * FRAME_NUM)
67#define NT_DMASZ (NT_FRAME_SIZE * FRAME_NUM)
68#define OUT_FRAME_NUM 2
69#define OUT_BUFFER_SIZE (4 * 1024 + NT_FRAME_HEADER_SIZE)
70#define BUFFER_SIZE (OUT_BUFFER_SIZE * OUT_FRAME_NUM)
71
72/* Offset from beginning of buffer*/
73#define AUDPREPROC_AMRNB_EOS_FLG_OFFSET 0x0A
74#define AUDPREPROC_AMRNB_EOS_FLG_MASK 0x01
75#define AUDPREPROC_AMRNB_EOS_NONE 0x0 /* No EOS detected */
76#define AUDPREPROC_AMRNB_EOS_SET 0x1 /* EOS set in meta field */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070077
78struct buffer {
79 void *data;
80 uint32_t size;
81 uint32_t read;
82 uint32_t addr;
Manish Dewanganb9171e52011-03-15 15:18:18 +053083 uint32_t used;
84 uint32_t mfield_sz;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070085};
86
87struct audio_amrnb_in {
88 struct buffer in[FRAME_NUM];
89
90 spinlock_t dsp_lock;
91
92 atomic_t in_bytes;
Manish Dewanganb9171e52011-03-15 15:18:18 +053093 atomic_t in_samples;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070094
95 struct mutex lock;
96 struct mutex read_lock;
97 wait_queue_head_t wait;
Manish Dewanganb9171e52011-03-15 15:18:18 +053098 wait_queue_head_t wait_enable;
99 /*write section*/
100 struct buffer out[OUT_FRAME_NUM];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700101
Manish Dewanganb9171e52011-03-15 15:18:18 +0530102 uint8_t out_head;
103 uint8_t out_tail;
104 uint8_t out_needed; /* number of buffers the dsp is waiting for */
105 uint32_t out_count;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700106
Manish Dewanganb9171e52011-03-15 15:18:18 +0530107 struct mutex write_lock;
108 wait_queue_head_t write_wait;
109 int32_t out_phys; /* physical address of write buffer */
110 char *out_data;
111 uint8_t mfield; /* meta field embedded in data */
112 uint8_t wflush; /*write flush */
113 uint8_t rflush; /*read flush*/
114 uint32_t out_frame_cnt;
115
116 struct msm_adsp_module *audrec;
Manish Dewanganb9171e52011-03-15 15:18:18 +0530117
118 /* configuration to use on next enable */
119 uint32_t samp_rate;
120 uint32_t channel_mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700121 uint32_t buffer_size;
122 uint32_t enc_type; /* 0 for WAV ,1 for AAC,10 for AMRNB */
Manish Dewanganb9171e52011-03-15 15:18:18 +0530123 uint32_t mode; /* T or NT Mode*/
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700124 struct msm_audio_amrnb_enc_config amrnb_enc_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
Manish Dewanganb9171e52011-03-15 15:18:18 +0530131 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
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700141 struct audmgr audmgr;
142
143 /* data allocated for various buffers */
144 char *data;
145 dma_addr_t phys;
Laura Abbott35111d32012-04-27 18:41:48 -0700146 void *map_v_write;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700147
Manish Dewanganb9171e52011-03-15 15:18:18 +0530148 uint8_t opened;
149 uint8_t enabled;
150 uint8_t running;
151 uint8_t stopped; /* set when stopped, cleared on flush */
Sidipotu Ashok172c98b2012-06-26 17:58:29 +0530152 struct ion_client *client;
153 struct ion_handle *input_buff_handle;
154
Manish Dewanganda9c07e2012-07-09 15:36:52 +0530155 struct audrec_session_info session_info; /*audrec session info*/
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700156};
157
Manish Dewanganb9171e52011-03-15 15:18:18 +0530158struct audio_frame {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700159 uint16_t frame_count_lsw;
160 uint16_t frame_count_msw;
161 uint16_t frame_length;
162 uint16_t erased_pcm;
163 unsigned char raw_bitstream[];
Manish Dewanganb9171e52011-03-15 15:18:18 +0530164} __packed;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700165
Manish Dewanganb9171e52011-03-15 15:18:18 +0530166struct audio_frame_nt {
167 uint16_t metadata_len;
168 uint16_t frame_count_lsw;
169 uint16_t frame_count_msw;
170 uint16_t frame_length;
171 uint16_t erased_pcm;
172 uint16_t reserved;
173 uint16_t time_stamp_dword_lsw;
174 uint16_t time_stamp_dword_msw;
175 uint16_t time_stamp_lsw;
176 uint16_t time_stamp_msw;
177 uint16_t nflag_lsw;
178 uint16_t nflag_msw;
179 unsigned char raw_bitstream[]; /* samples */
180} __packed;
181
182struct amrnb_encoded_meta_out {
183 uint16_t metadata_len;
184 uint16_t time_stamp_dword_lsw;
185 uint16_t time_stamp_dword_msw;
186 uint16_t time_stamp_lsw;
187 uint16_t time_stamp_msw;
188 uint16_t nflag_lsw;
189 uint16_t nflag_msw;
190};
191
192/* Audrec Queue command sent macro's */
193#define audio_send_queue_pre(audio, cmd, len) \
194 msm_adsp_write(audio->audpre, QDSP_uPAudPreProcCmdQueue, cmd, len)
195
196#define audio_send_queue_recbs(audio, cmd, len) \
197 msm_adsp_write(audio->audrec, ((audio->queue_ids & 0xFFFF0000) >> 16),\
198 cmd, len)
199#define audio_send_queue_rec(audio, cmd, len) \
200 msm_adsp_write(audio->audrec, (audio->queue_ids & 0x0000FFFF),\
201 cmd, len)
202
203static int audamrnb_in_dsp_enable(struct audio_amrnb_in *audio, int enable);
204static int audamrnb_in_encparam_config(struct audio_amrnb_in *audio);
205static int audamrnb_in_encmem_config(struct audio_amrnb_in *audio);
206static int audamrnb_in_dsp_read_buffer(struct audio_amrnb_in *audio,
207 uint32_t read_cnt);
208static void audamrnb_in_flush(struct audio_amrnb_in *audio);
209
210static void audamrnb_in_get_dsp_frames(struct audio_amrnb_in *audio);
211static int audpcm_config(struct audio_amrnb_in *audio);
212static void audamrnb_out_flush(struct audio_amrnb_in *audio);
213static int audamrnb_in_routing_mode_config(struct audio_amrnb_in *audio);
214static void audrec_pcm_send_data(struct audio_amrnb_in *audio, unsigned needed);
215static void audamrnb_nt_in_get_dsp_frames(struct audio_amrnb_in *audio);
216static void audamrnb_in_flush(struct audio_amrnb_in *audio);
217
218static unsigned convert_samp_index(unsigned index)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700219{
Manish Dewanganb9171e52011-03-15 15:18:18 +0530220 switch (index) {
221 case RPC_AUD_DEF_SAMPLE_RATE_48000: return 48000;
222 case RPC_AUD_DEF_SAMPLE_RATE_44100: return 44100;
223 case RPC_AUD_DEF_SAMPLE_RATE_32000: return 32000;
224 case RPC_AUD_DEF_SAMPLE_RATE_24000: return 24000;
225 case RPC_AUD_DEF_SAMPLE_RATE_22050: return 22050;
226 case RPC_AUD_DEF_SAMPLE_RATE_16000: return 16000;
227 case RPC_AUD_DEF_SAMPLE_RATE_12000: return 12000;
228 case RPC_AUD_DEF_SAMPLE_RATE_11025: return 11025;
229 case RPC_AUD_DEF_SAMPLE_RATE_8000: return 8000;
230 default: return 11025;
231 }
232}
233
Manish Dewanganda9c07e2012-07-09 15:36:52 +0530234/* ------------------- dsp --------------------- */
235static void audpre_dsp_event(void *data, unsigned id, void *event_data)
236{
237
238 uint16_t *msg = event_data;
239
240 if (!msg)
241 return;
242
243 switch (id) {
244 case AUDPREPROC_MSG_CMD_CFG_DONE_MSG:
245 MM_DBG("type %d, status_flag %d\n",\
246 msg[0], msg[1]);
247 break;
248 case AUDPREPROC_MSG_ERROR_MSG_ID:
249 MM_INFO("err_index %d\n", msg[0]);
250 break;
251 case ADSP_MESSAGE_ID:
252 MM_DBG("Received ADSP event: module enable(audpreproctask)\n");
253 break;
254 default:
255 MM_ERR("unknown event %d\n", id);
256 }
257}
Manish Dewanganb9171e52011-03-15 15:18:18 +0530258/* must be called with audio->lock held */
259static int audamrnb_in_enable(struct audio_amrnb_in *audio)
260{
261 struct audmgr_config cfg;
262 int32_t rc;
263
264 if (audio->enabled)
265 return 0;
266
267 cfg.tx_rate = audio->samp_rate;
268 cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE;
269 cfg.def_method = RPC_AUD_DEF_METHOD_RECORD;
270 cfg.codec = RPC_AUD_DEF_CODEC_AMR_NB;
271 cfg.snd_method = RPC_SND_METHOD_MIDI;
272
273 if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
274 rc = audmgr_enable(&audio->audmgr, &cfg);
275 if (rc < 0)
276 return rc;
277
Manish Dewanganda9c07e2012-07-09 15:36:52 +0530278 if (audpreproc_enable(audio->enc_id,
279 &audpre_dsp_event, audio)) {
280 MM_ERR("msm_adsp_enable(audpreproc) failed\n");
Manish Dewanganb9171e52011-03-15 15:18:18 +0530281 audmgr_disable(&audio->audmgr);
Manish Dewanganb9171e52011-03-15 15:18:18 +0530282 return -ENODEV;
283 }
Manish Dewanganda9c07e2012-07-09 15:36:52 +0530284 /*update aurec session info in audpreproc layer*/
285 audio->session_info.session_id = audio->enc_id;
286 audio->session_info.sampling_freq =
287 convert_samp_index(audio->samp_rate);
288 audpreproc_update_audrec_info(&audio->session_info);
Manish Dewanganb9171e52011-03-15 15:18:18 +0530289 }
Manish Dewanganda9c07e2012-07-09 15:36:52 +0530290
Manish Dewanganb9171e52011-03-15 15:18:18 +0530291 if (msm_adsp_enable(audio->audrec)) {
292 if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
Manish Dewanganda9c07e2012-07-09 15:36:52 +0530293 audpreproc_disable(audio->enc_id, audio);
Manish Dewanganb9171e52011-03-15 15:18:18 +0530294 audmgr_disable(&audio->audmgr);
Manish Dewanganb9171e52011-03-15 15:18:18 +0530295 }
296 MM_ERR("msm_adsp_enable(audrec) failed\n");
297 return -ENODEV;
298 }
299
300 audio->enabled = 1;
301 audamrnb_in_dsp_enable(audio, 1);
302
303 return 0;
304}
305
306/* must be called with audio->lock held */
307static int audamrnb_in_disable(struct audio_amrnb_in *audio)
308{
309 if (audio->enabled) {
310 audio->enabled = 0;
311
312 audamrnb_in_dsp_enable(audio, 0);
313
314 wake_up(&audio->wait);
315 wait_event_interruptible_timeout(audio->wait_enable,
316 audio->running == 0, 1*HZ);
317 msm_adsp_disable(audio->audrec);
318 if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
Manish Dewanganda9c07e2012-07-09 15:36:52 +0530319 /*reset the sampling frequency information at
320 audpreproc layer*/
321 audio->session_info.sampling_freq = 0;
322 audpreproc_update_audrec_info(&audio->session_info);
323 audpreproc_disable(audio->enc_id, audio);
Manish Dewanganb9171e52011-03-15 15:18:18 +0530324 audmgr_disable(&audio->audmgr);
325 }
326 }
327 return 0;
328}
329
Manish Dewanganb9171e52011-03-15 15:18:18 +0530330static void audamrnb_in_get_dsp_frames(struct audio_amrnb_in *audio)
331{
332 struct audio_frame *frame;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700333 uint32_t index;
334 unsigned long flags;
335 index = audio->in_head;
336
337 frame = (void *) (((char *)audio->in[index].data) -
338 sizeof(*frame));
339 spin_lock_irqsave(&audio->dsp_lock, flags);
Manish Dewanganb9171e52011-03-15 15:18:18 +0530340
341 /* Send Complete Transcoded Data, not actual frame part */
342 audio->in[index].size = FRAME_SIZE - (sizeof(*frame));
343 /* statistics of read */
344 atomic_add(audio->in[index].size, &audio->in_bytes);
345 atomic_add(1, &audio->in_samples);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700346
347 audio->in_head = (audio->in_head + 1) & (FRAME_NUM - 1);
348
349 /* If overflow, move the tail index foward. */
Manish Dewanganb9171e52011-03-15 15:18:18 +0530350 if (audio->in_head == audio->in_tail) {
351 MM_ERR("Error! not able to keep up the read\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700352 audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1);
Manish Dewanganb9171e52011-03-15 15:18:18 +0530353 MM_ERR("in_count = %d\n", audio->in_count);
354 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700355 audio->in_count++;
356
Manish Dewanganb9171e52011-03-15 15:18:18 +0530357 audamrnb_in_dsp_read_buffer(audio, audio->dsp_cnt++);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700358 spin_unlock_irqrestore(&audio->dsp_lock, flags);
359
360 wake_up(&audio->wait);
361}
362
Manish Dewanganb9171e52011-03-15 15:18:18 +0530363static void audamrnb_nt_in_get_dsp_frames(struct audio_amrnb_in *audio)
364{
365 struct audio_frame_nt *nt_frame;
366 uint32_t index;
367 unsigned long flags;
368
369 index = audio->in_head;
370 nt_frame = (void *) (((char *)audio->in[index].data) - \
371 sizeof(struct audio_frame_nt));
372 spin_lock_irqsave(&audio->dsp_lock, flags);
373 audio->in[index].size = nt_frame->frame_length;
374 /* statistics of read */
375 atomic_add(audio->in[index].size, &audio->in_bytes);
376 atomic_add(1, &audio->in_samples);
377
378 audio->in_head = (audio->in_head + 1) & (FRAME_NUM - 1);
379
380 /* If overflow, move the tail index foward. */
381 if (audio->in_head == audio->in_tail)
382 MM_DBG("Error! not able to keep up the read\n");
383 else
384 audio->in_count++;
385
386 spin_unlock_irqrestore(&audio->dsp_lock, flags);
387 wake_up(&audio->wait);
388}
389
390static int audrec_pcm_buffer_ptr_refresh(struct audio_amrnb_in *audio,
391 unsigned idx, unsigned len)
392{
393 struct audrec_cmd_pcm_buffer_ptr_refresh_arm_enc cmd;
394
395 if (len == NT_FRAME_HEADER_SIZE)
396 len = len / 2;
397 else
398 len = (len + NT_FRAME_HEADER_SIZE) / 2;
399 MM_DBG("len = %d\n", len);
400 memset(&cmd, 0, sizeof(cmd));
401 cmd.cmd_id = AUDREC_CMD_PCM_BUFFER_PTR_REFRESH_ARM_TO_ENC;
402 cmd.num_buffers = 1;
403 if (cmd.num_buffers == 1) {
404 cmd.buf_address_length[0] = (audio->out[idx].addr &
405 0xffff0000) >> 16;
406 cmd.buf_address_length[1] = (audio->out[idx].addr &
407 0x0000ffff);
408 cmd.buf_address_length[2] = (len & 0xffff0000) >> 16;
409 cmd.buf_address_length[3] = (len & 0x0000ffff);
410 }
411 audio->out_frame_cnt++;
412 return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
413}
414
415static int audpcm_config(struct audio_amrnb_in *audio)
416{
417 struct audrec_cmd_pcm_cfg_arm_to_enc cmd;
418 MM_DBG("\n");
419 memset(&cmd, 0, sizeof(cmd));
420 cmd.cmd_id = AUDREC_CMD_PCM_CFG_ARM_TO_ENC;
421 cmd.config_update_flag = AUDREC_PCM_CONFIG_UPDATE_FLAG_ENABLE;
422 cmd.enable_flag = AUDREC_ENABLE_FLAG_VALUE;
423 cmd.sampling_freq = convert_samp_index(audio->samp_rate);
424 if (!audio->channel_mode)
425 cmd.channels = 1;
426 else
427 cmd.channels = 2;
428 cmd.frequency_of_intimation = 1;
429 cmd.max_number_of_buffers = OUT_FRAME_NUM;
430 return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
431}
432
433
434static int audamrnb_in_routing_mode_config(struct audio_amrnb_in *audio)
435{
436 struct audrec_cmd_routing_mode cmd;
437
438 MM_DBG("\n");
439 memset(&cmd, 0, sizeof(cmd));
440 cmd.cmd_id = AUDREC_CMD_ROUTING_MODE;
441 if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL)
442 cmd.routing_mode = 1;
443 return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
444}
445
446static void audrec_dsp_event(void *data, unsigned id, size_t len,
447 void (*getevent)(void *ptr, size_t len))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700448{
449 struct audio_amrnb_in *audio = data;
Manish Dewanganb9171e52011-03-15 15:18:18 +0530450 if (data)
451 audio = data;
452 else {
453 MM_ERR("invalid data for event %x\n", id);
454 return;
455 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700456
457 switch (id) {
Manish Dewanganb9171e52011-03-15 15:18:18 +0530458 case AUDREC_MSG_CMD_CFG_DONE_MSG: {
459 struct audrec_msg_cmd_cfg_done_msg cmd_cfg_done_msg;
460 getevent(&cmd_cfg_done_msg, AUDREC_MSG_CMD_CFG_DONE_MSG_LEN);
461 if (cmd_cfg_done_msg.audrec_enc_type & \
462 AUDREC_MSG_CFG_DONE_ENC_ENA) {
463 audio->audrec_obj_idx = cmd_cfg_done_msg.audrec_obj_idx;
464 MM_DBG("CFG ENABLED\n");
465 if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) {
466 MM_DBG("routing command\n");
467 audamrnb_in_routing_mode_config(audio);
468 } else {
469 audamrnb_in_encmem_config(audio);
470 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700471 } else {
Manish Dewanganb9171e52011-03-15 15:18:18 +0530472 MM_DBG("CFG SLEEP\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700473 audio->running = 0;
Manish Dewanganb9171e52011-03-15 15:18:18 +0530474 wake_up(&audio->wait_enable);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700475 }
476 break;
Manish Dewanganb9171e52011-03-15 15:18:18 +0530477 }
478 case AUDREC_MSG_CMD_ROUTING_MODE_DONE_MSG: {
479 struct audrec_msg_cmd_routing_mode_done_msg \
480 routing_msg;
481 getevent(&routing_msg, AUDREC_MSG_CMD_ROUTING_MODE_DONE_MSG);
482 MM_DBG("AUDREC_MSG_CMD_ROUTING_MODE_DONE_MSG");
483 if (routing_msg.configuration == 0) {
484 MM_ERR("routing configuration failed\n");
485 audio->running = 0;
486 wake_up(&audio->wait_enable);
487 } else
488 audamrnb_in_encmem_config(audio);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700489 break;
490 }
Manish Dewanganb9171e52011-03-15 15:18:18 +0530491 case AUDREC_MSG_CMD_AREC_MEM_CFG_DONE_MSG: {
492 MM_DBG("AREC_MEM_CFG_DONE_MSG\n");
493 if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
494 audamrnb_in_encparam_config(audio);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700495 else
Manish Dewanganb9171e52011-03-15 15:18:18 +0530496 audpcm_config(audio);
497 break;
498 }
499
500 case AUDREC_CMD_PCM_CFG_ARM_TO_ENC_DONE_MSG: {
501 MM_DBG("AUDREC_CMD_PCM_CFG_ARM_TO_ENC_DONE_MSG");
502 audamrnb_in_encparam_config(audio);
503 break;
504 }
505 case AUDREC_MSG_CMD_AREC_PARAM_CFG_DONE_MSG: {
506 MM_DBG("AUDREC_MSG_CMD_AREC_PARAM_CFG_DONE_MSG\n");
507 audio->running = 1;
508 wake_up(&audio->wait_enable);
509 if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL)
510 audrec_pcm_send_data(audio, 1);
511 break;
512 }
513 case AUDREC_CMD_PCM_BUFFER_PTR_UPDATE_ARM_TO_ENC_MSG: {
514 MM_DBG("ptr_update recieved from DSP\n");
515 audrec_pcm_send_data(audio, 1);
516 break;
517 }
518 case AUDREC_MSG_NO_EXT_PKT_AVAILABLE_MSG: {
519 struct audrec_msg_no_ext_pkt_avail_msg err_msg;
520 getevent(&err_msg, AUDREC_MSG_NO_EXT_PKT_AVAILABLE_MSG_LEN);
521 MM_DBG("NO_EXT_PKT_AVAILABLE_MSG %x\n",\
522 err_msg.audrec_err_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700523 break;
524 }
525 case AUDREC_MSG_PACKET_READY_MSG: {
Manish Dewanganb9171e52011-03-15 15:18:18 +0530526 struct audrec_msg_packet_ready_msg pkt_ready_msg;
527
528 getevent(&pkt_ready_msg, AUDREC_MSG_PACKET_READY_MSG_LEN);
529 MM_DBG("UP_PACKET_READY_MSG: write cnt msw %d \
530 write cnt lsw %d read cnt msw %d read cnt lsw %d \n",\
531 pkt_ready_msg.pkt_counter_msw, \
532 pkt_ready_msg.pkt_counter_lsw, \
533 pkt_ready_msg.pkt_read_cnt_msw, \
534 pkt_ready_msg.pkt_read_cnt_lsw);
535
536 audamrnb_in_get_dsp_frames(audio);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700537 break;
538 }
Manish Dewanganb9171e52011-03-15 15:18:18 +0530539 case AUDREC_UP_NT_PACKET_READY_MSG: {
540 struct audrec_up_nt_packet_ready_msg pkt_ready_msg;
541
542 getevent(&pkt_ready_msg, AUDREC_UP_NT_PACKET_READY_MSG_LEN);
543 MM_DBG("UP_NT_PACKET_READY_MSG: write cnt lsw %d \
544 write cnt msw %d read cnt lsw %d read cnt msw %d \n",\
545 pkt_ready_msg.audrec_packetwrite_cnt_lsw, \
546 pkt_ready_msg.audrec_packetwrite_cnt_msw, \
547 pkt_ready_msg.audrec_upprev_readcount_lsw, \
548 pkt_ready_msg.audrec_upprev_readcount_msw);
549
550 audamrnb_nt_in_get_dsp_frames(audio);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700551 break;
552 }
Manish Dewanganb9171e52011-03-15 15:18:18 +0530553 case AUDREC_CMD_FLUSH_DONE_MSG: {
554 audio->wflush = 0;
555 audio->rflush = 0;
556 audio->flush_ack = 1;
557 wake_up(&audio->write_wait);
558 MM_DBG("flush ack recieved\n");
559 break;
560 }
561 case ADSP_MESSAGE_ID:
562 MM_DBG("Received ADSP event: module \
563 enable/disable(audrectask)\n");
564 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700565 default:
566 MM_ERR("unknown event %d\n", id);
567 }
568}
569
Manish Dewanganb9171e52011-03-15 15:18:18 +0530570struct msm_adsp_ops audrec_amrnb_adsp_ops = {
571 .event = audrec_dsp_event,
572};
573
574static int audamrnb_in_dsp_enable(struct audio_amrnb_in *audio, int enable)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700575{
576 struct audrec_cmd_enc_cfg cmd;
577
578 memset(&cmd, 0, sizeof(cmd));
579 cmd.cmd_id = AUDREC_CMD_ENC_CFG;
Manish Dewanganb9171e52011-03-15 15:18:18 +0530580 cmd.audrec_enc_type = (audio->enc_type & 0xFF) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700581 (enable ? AUDREC_CMD_ENC_ENA : AUDREC_CMD_ENC_DIS);
582 /* Don't care on enable, required on disable */
583 cmd.audrec_obj_idx = audio->audrec_obj_idx;
584
Manish Dewanganb9171e52011-03-15 15:18:18 +0530585 return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700586}
587
Manish Dewanganb9171e52011-03-15 15:18:18 +0530588static int audamrnb_in_encmem_config(struct audio_amrnb_in *audio)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700589{
590 struct audrec_cmd_arecmem_cfg cmd;
591 uint16_t *data = (void *) audio->data;
Manish Dewanganb9171e52011-03-15 15:18:18 +0530592 uint8_t n;
593 uint16_t header_len = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700594
595 memset(&cmd, 0, sizeof(cmd));
596
597 cmd.cmd_id = AUDREC_CMD_ARECMEM_CFG;
598 cmd.audrec_obj_idx = audio->audrec_obj_idx;
599 /* Rate at which packet complete message comes */
600 cmd.audrec_up_pkt_intm_cnt = 1;
601 cmd.audrec_extpkt_buffer_msw = audio->phys >> 16;
602 cmd.audrec_extpkt_buffer_lsw = audio->phys;
603 /* Max Buffer no available for frames */
604 cmd.audrec_extpkt_buffer_num = FRAME_NUM;
605
606 /* prepare buffer pointers:
Manish Dewanganb9171e52011-03-15 15:18:18 +0530607 * T:36 bytes amrnb packet + 4 halfword header
608 * NT:36 bytes amrnb packet + 12 halfword header
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700609 */
Manish Dewanganb9171e52011-03-15 15:18:18 +0530610 if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
611 header_len = FRAME_HEADER_SIZE/2;
612 else
613 header_len = NT_FRAME_HEADER_SIZE/2;
614
615 for (n = 0; n < FRAME_NUM; n++) {
616 audio->in[n].data = data + header_len;
617 data += (AMRNB_FRAME_SIZE/2) + header_len;
618 MM_DBG("0x%8x\n", (uint32_t)(audio->in[n].data - header_len*2));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700619 }
620
Manish Dewanganb9171e52011-03-15 15:18:18 +0530621 return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700622}
623
Manish Dewanganb9171e52011-03-15 15:18:18 +0530624static int audamrnb_in_encparam_config(struct audio_amrnb_in *audio)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700625{
626 struct audrec_cmd_arecparam_amrnb_cfg cmd;
627
628 memset(&cmd, 0, sizeof(cmd));
629
630 cmd.common.cmd_id = AUDREC_CMD_ARECPARAM_CFG;
631 cmd.common.audrec_obj_idx = audio->audrec_obj_idx;
Manish Dewanganb9171e52011-03-15 15:18:18 +0530632 cmd.samp_rate_idx = audio->samp_rate_index; /* 8k Sampling rate */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700633 cmd.voicememoencweight1 = audio->amrnb_enc_cfg.voicememoencweight1;
634 cmd.voicememoencweight2 = audio->amrnb_enc_cfg.voicememoencweight2;
635 cmd.voicememoencweight3 = audio->amrnb_enc_cfg.voicememoencweight3;
636 cmd.voicememoencweight4 = audio->amrnb_enc_cfg.voicememoencweight4;
637 cmd.update_mode = 0x8000 | 0x0000;
638 cmd.dtx_mode = audio->amrnb_enc_cfg.dtx_mode_enable;
639 cmd.test_mode = audio->amrnb_enc_cfg.test_mode_enable;
640 cmd.used_mode = audio->amrnb_enc_cfg.enc_mode;
641
642 MM_DBG("cmd.common.cmd_id = 0x%4x\n", cmd.common.cmd_id);
643 MM_DBG("cmd.common.audrec_obj_idx = 0x%4x\n",
644 cmd.common.audrec_obj_idx);
645 MM_DBG("cmd.samp_rate_idx = 0x%4x\n", cmd.samp_rate_idx);
646 MM_DBG("cmd.voicememoencweight1 = 0x%4x\n",
647 cmd.voicememoencweight1);
648 MM_DBG("cmd.voicememoencweight2 = 0x%4x\n",
649 cmd.voicememoencweight2);
650 MM_DBG("cmd.voicememoencweight3 = 0x%4x\n",
651 cmd.voicememoencweight3);
652 MM_DBG("cmd.voicememoencweight4 = 0x%4x\n",
653 cmd.voicememoencweight4);
654 MM_DBG("cmd.update_mode = 0x%4x\n", cmd.update_mode);
655 MM_DBG("cmd.dtx_mode = 0x%4x\n", cmd.dtx_mode);
656 MM_DBG("cmd.test_mode = 0x%4x\n", cmd.test_mode);
657 MM_DBG("cmd.used_mode = 0x%4x\n", cmd.used_mode);
658
Manish Dewanganb9171e52011-03-15 15:18:18 +0530659 return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700660}
661
Manish Dewanganb9171e52011-03-15 15:18:18 +0530662static int audamrnb_flush_command(struct audio_amrnb_in *audio)
663{
664 struct audrec_cmd_flush cmd;
665 MM_DBG("\n");
666 memset(&cmd, 0, sizeof(cmd));
667 cmd.cmd_id = AUDREC_CMD_FLUSH;
668 return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
669}
670static int audamrnb_in_dsp_read_buffer(struct audio_amrnb_in *audio,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700671 uint32_t read_cnt)
672{
673 audrec_cmd_packet_ext_ptr cmd;
674
675 memset(&cmd, 0, sizeof(cmd));
676 cmd.cmd_id = AUDREC_CMD_PACKET_EXT_PTR;
677 cmd.type = audio->audrec_obj_idx;
678 cmd.curr_rec_count_msw = read_cnt >> 16;
679 cmd.curr_rec_count_lsw = read_cnt;
680
Manish Dewanganb9171e52011-03-15 15:18:18 +0530681 return audio_send_queue_recbs(audio, &cmd, sizeof(cmd));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700682}
683
Manish Dewanganb9171e52011-03-15 15:18:18 +0530684/* ------------------- device --------------------- */
685
686static void audamrnb_ioport_reset(struct audio_amrnb_in *audio)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700687{
Manish Dewanganb9171e52011-03-15 15:18:18 +0530688 /* Make sure read/write thread are free from
689 * sleep and knowing that system is not able
690 * to process io request at the moment
691 */
692 wake_up(&audio->write_wait);
693 mutex_lock(&audio->write_lock);
694 audamrnb_in_flush(audio);
695 mutex_unlock(&audio->write_lock);
696 wake_up(&audio->wait);
697 mutex_lock(&audio->read_lock);
698 audamrnb_out_flush(audio);
699 mutex_unlock(&audio->read_lock);
700}
701
702static void audamrnb_in_flush(struct audio_amrnb_in *audio)
703{
704 uint8_t i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700705
706 audio->dsp_cnt = 0;
707 audio->in_head = 0;
708 audio->in_tail = 0;
709 audio->in_count = 0;
Manish Dewanganb9171e52011-03-15 15:18:18 +0530710 audio->eos_ack = 0;
711 for (i = FRAME_NUM-1; i >= 0; i--) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700712 audio->in[i].size = 0;
713 audio->in[i].read = 0;
714 }
Manish Dewanganb9171e52011-03-15 15:18:18 +0530715 MM_DBG("in_bytes %d\n", atomic_read(&audio->in_bytes));
716 MM_DBG("in_samples %d\n", atomic_read(&audio->in_samples));
717 atomic_set(&audio->in_bytes, 0);
718 atomic_set(&audio->in_samples, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700719}
720
Manish Dewanganb9171e52011-03-15 15:18:18 +0530721static void audamrnb_out_flush(struct audio_amrnb_in *audio)
722{
723 uint8_t i;
724
725 audio->out_head = 0;
726 audio->out_tail = 0;
727 audio->out_count = 0;
728 for (i = OUT_FRAME_NUM-1; i >= 0; i--) {
729 audio->out[i].size = 0;
730 audio->out[i].read = 0;
731 audio->out[i].used = 0;
732 }
733}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700734
735/* ------------------- device --------------------- */
Manish Dewanganb9171e52011-03-15 15:18:18 +0530736static long audamrnb_in_ioctl(struct file *file,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700737 unsigned int cmd, unsigned long arg)
738{
739 struct audio_amrnb_in *audio = file->private_data;
Manish Dewanganb9171e52011-03-15 15:18:18 +0530740 int32_t rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700741
Manish Dewanganb9171e52011-03-15 15:18:18 +0530742 MM_DBG("\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700743 if (cmd == AUDIO_GET_STATS) {
744 struct msm_audio_stats stats;
Asish Bhattacharya4a064192013-10-01 17:15:05 +0530745 memset(&stats, 0, sizeof(stats));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700746 stats.byte_count = atomic_read(&audio->in_bytes);
Manish Dewanganb9171e52011-03-15 15:18:18 +0530747 stats.sample_count = atomic_read(&audio->in_samples);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700748 if (copy_to_user((void *) arg, &stats, sizeof(stats)))
749 return -EFAULT;
Manish Dewanganb9171e52011-03-15 15:18:18 +0530750 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700751 }
752
753 mutex_lock(&audio->lock);
754 switch (cmd) {
Manish Dewanganb9171e52011-03-15 15:18:18 +0530755 case AUDIO_START: {
756 rc = audamrnb_in_enable(audio);
757 if (!rc) {
758 rc =
759 wait_event_interruptible_timeout(audio->wait_enable,
760 audio->running != 0, 1*HZ);
761 MM_INFO("state %d rc = %d\n", audio->running, rc);
762
763 if (audio->running == 0)
764 rc = -ENODEV;
765 else
766 rc = 0;
767 }
768 audio->stopped = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700769 break;
Manish Dewanganb9171e52011-03-15 15:18:18 +0530770 }
771 case AUDIO_STOP: {
772 rc = audamrnb_in_disable(audio);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700773 audio->stopped = 1;
774 break;
Manish Dewanganb9171e52011-03-15 15:18:18 +0530775 }
776 case AUDIO_FLUSH: {
777 MM_DBG("AUDIO_FLUSH\n");
778 audio->rflush = 1;
779 audio->wflush = 1;
780 audamrnb_ioport_reset(audio);
781 if (audio->running) {
782 audamrnb_flush_command(audio);
783 rc = wait_event_interruptible(audio->write_wait,
784 !audio->wflush);
785 if (rc < 0) {
786 MM_ERR("AUDIO_FLUSH interrupted\n");
787 rc = -EINTR;
788 }
789 } else {
790 audio->rflush = 0;
791 audio->wflush = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700792 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700793 break;
794 }
795 case AUDIO_GET_CONFIG: {
Manish Dewanganb9171e52011-03-15 15:18:18 +0530796 struct msm_audio_config cfg;
797 memset(&cfg, 0, sizeof(cfg));
798 if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) {
799 cfg.buffer_size = OUT_BUFFER_SIZE;
800 cfg.buffer_count = OUT_FRAME_NUM;
801 } else {
802 cfg.buffer_size = audio->buffer_size;
803 cfg.buffer_count = FRAME_NUM;
804 }
805 cfg.sample_rate = convert_samp_index(audio->samp_rate);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700806 cfg.channel_count = 1;
Manish Dewanganb9171e52011-03-15 15:18:18 +0530807 cfg.type = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700808 cfg.unused[0] = 0;
809 cfg.unused[1] = 0;
810 cfg.unused[2] = 0;
811 if (copy_to_user((void *) arg, &cfg, sizeof(cfg)))
812 rc = -EFAULT;
813 else
814 rc = 0;
815 break;
816 }
Manish Dewanganb9171e52011-03-15 15:18:18 +0530817 case AUDIO_GET_STREAM_CONFIG: {
818 struct msm_audio_stream_config cfg;
819 memset(&cfg, 0, sizeof(cfg));
820 cfg.buffer_size = audio->buffer_size;
821 cfg.buffer_count = FRAME_NUM;
822 if (copy_to_user((void *)arg, &cfg, sizeof(cfg)))
823 rc = -EFAULT;
824 else
825 rc = 0;
826 break;
827 }
828 case AUDIO_SET_STREAM_CONFIG: {
829 struct msm_audio_stream_config cfg;
830 if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) {
831 rc = -EFAULT;
832 break;
833 }
834 /* Allow only single frame */
835 if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
Phani Kumar Alladaee940eb2012-05-10 11:13:04 +0530836 if (cfg.buffer_size != (FRAME_SIZE - 8)) {
Manish Dewanganb9171e52011-03-15 15:18:18 +0530837 rc = -EINVAL;
838 break;
Phani Kumar Alladaee940eb2012-05-10 11:13:04 +0530839 }
Manish Dewanganb9171e52011-03-15 15:18:18 +0530840 } else {
Phani Kumar Alladaee940eb2012-05-10 11:13:04 +0530841 if (cfg.buffer_size != (AMRNB_FRAME_SIZE + 14)) {
Manish Dewanganb9171e52011-03-15 15:18:18 +0530842 rc = -EINVAL;
843 break;
Phani Kumar Alladaee940eb2012-05-10 11:13:04 +0530844 }
Manish Dewanganb9171e52011-03-15 15:18:18 +0530845 }
846 audio->buffer_size = cfg.buffer_size;
847 break;
848 }
849
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700850 case AUDIO_GET_AMRNB_ENC_CONFIG: {
851 if (copy_to_user((void *)arg, &audio->amrnb_enc_cfg,
852 sizeof(audio->amrnb_enc_cfg)))
853 rc = -EFAULT;
854 else
855 rc = 0;
856 break;
857 }
858 case AUDIO_SET_AMRNB_ENC_CONFIG: {
859 struct msm_audio_amrnb_enc_config cfg;
860 if (copy_from_user
861 (&cfg, (void *)arg, sizeof(cfg))) {
862 rc = -EFAULT;
863 } else
864 rc = 0;
865 audio->amrnb_enc_cfg.voicememoencweight1 =
866 cfg.voicememoencweight1;
867 audio->amrnb_enc_cfg.voicememoencweight2 =
868 cfg.voicememoencweight2;
869 audio->amrnb_enc_cfg.voicememoencweight3 =
870 cfg.voicememoencweight3;
871 audio->amrnb_enc_cfg.voicememoencweight4 =
872 cfg.voicememoencweight4;
873 audio->amrnb_enc_cfg.dtx_mode_enable = cfg.dtx_mode_enable;
874 audio->amrnb_enc_cfg.test_mode_enable = cfg.test_mode_enable;
875 audio->amrnb_enc_cfg.enc_mode = cfg.enc_mode;
876 /* Run time change of Param */
877 break;
878 }
879 default:
880 rc = -EINVAL;
881 }
882 mutex_unlock(&audio->lock);
883 return rc;
884}
885
Manish Dewanganb9171e52011-03-15 15:18:18 +0530886static ssize_t audamrnb_in_read(struct file *file,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700887 char __user *buf,
888 size_t count, loff_t *pos)
889{
890 struct audio_amrnb_in *audio = file->private_data;
891 unsigned long flags;
892 const char __user *start = buf;
893 void *data;
894 uint32_t index;
895 uint32_t size;
Manish Dewanganb9171e52011-03-15 15:18:18 +0530896 int32_t rc = 0;
897 struct amrnb_encoded_meta_out meta_field;
898 struct audio_frame_nt *nt_frame;
899 MM_DBG("count = %d\n", count);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700900 mutex_lock(&audio->read_lock);
901 while (count > 0) {
902 rc = wait_event_interruptible(
Manish Dewanganb9171e52011-03-15 15:18:18 +0530903 audio->wait, (audio->in_count > 0) || audio->stopped ||
904 audio->rflush);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700905 if (rc < 0)
906 break;
907
Manish Dewanganb9171e52011-03-15 15:18:18 +0530908 if (audio->rflush) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700909 rc = -EBUSY;
910 break;
911 }
Manish Dewanganb9171e52011-03-15 15:18:18 +0530912 if (audio->stopped && !audio->in_count) {
913 MM_DBG("Driver in stop state, No more buffer to read");
914 rc = 0;/* End of File */
915 break;
916 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700917
918 index = audio->in_tail;
919 data = (uint8_t *) audio->in[index].data;
920 size = audio->in[index].size;
Manish Dewanganb9171e52011-03-15 15:18:18 +0530921
922 if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) {
923 nt_frame = (struct audio_frame_nt *)(data -
924 sizeof(struct audio_frame_nt));
925 memcpy((char *)&meta_field.time_stamp_dword_lsw,
926 (char *)&nt_frame->time_stamp_dword_lsw,
927 (sizeof(struct amrnb_encoded_meta_out) - \
928 sizeof(uint16_t)));
929 meta_field.metadata_len =
930 sizeof(struct amrnb_encoded_meta_out);
931 if (copy_to_user((char *)start, (char *)&meta_field,
932 sizeof(struct amrnb_encoded_meta_out))) {
933 rc = -EFAULT;
934 break;
935 }
936 if (nt_frame->nflag_lsw & 0x0001) {
937 MM_ERR("recieved EOS in read call\n");
938 audio->eos_ack = 1;
939 }
940 buf += sizeof(struct amrnb_encoded_meta_out);
941 count -= sizeof(struct amrnb_encoded_meta_out);
942 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700943 if (count >= size) {
Manish Dewanganb9171e52011-03-15 15:18:18 +0530944 /* order the reads on the buffer */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700945 dma_coherent_post_ops();
946 if (copy_to_user(buf, data, size)) {
947 rc = -EFAULT;
948 break;
949 }
950 spin_lock_irqsave(&audio->dsp_lock, flags);
951 if (index != audio->in_tail) {
Manish Dewanganb9171e52011-03-15 15:18:18 +0530952 /* overrun -- data is
953 * invalid and we need to retry */
954 spin_unlock_irqrestore(&audio->dsp_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700955 continue;
956 }
957 audio->in[index].size = 0;
958 audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1);
959 audio->in_count--;
960 spin_unlock_irqrestore(&audio->dsp_lock, flags);
961 count -= size;
962 buf += size;
Manish Dewanganb9171e52011-03-15 15:18:18 +0530963 if ((audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL)) {
964 if (!audio->eos_ack) {
965 MM_DBG("sending read ptr command \
966 %d %d\n",
967 audio->dsp_cnt,
968 audio->in_tail);
969 audamrnb_in_dsp_read_buffer(audio,
970 audio->dsp_cnt++);
971 }
972 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700973 } else {
974 MM_ERR("short read\n");
975 break;
976 }
Manish Dewanganb9171e52011-03-15 15:18:18 +0530977
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700978 }
979 mutex_unlock(&audio->read_lock);
980
981 if (buf > start)
982 return buf - start;
983
984 return rc;
985}
986
Manish Dewanganb9171e52011-03-15 15:18:18 +0530987static void audrec_pcm_send_data(struct audio_amrnb_in *audio, unsigned needed)
988{
989 struct buffer *frame;
990 unsigned long flags;
991 MM_DBG("\n");
992 spin_lock_irqsave(&audio->dsp_lock, flags);
993 if (!audio->running)
994 goto done;
995
996 if (needed && !audio->wflush) {
997 /* We were called from the callback because the DSP
998 * requested more data. Note that the DSP does want
999 * more data, and if a buffer was in-flight, mark it
1000 * as available (since the DSP must now be done with
1001 * it).
1002 */
1003 audio->out_needed = 1;
1004 frame = audio->out + audio->out_tail;
1005 if (frame->used == 0xffffffff) {
1006 MM_DBG("frame %d free\n", audio->out_tail);
1007 frame->used = 0;
1008 audio->out_tail ^= 1;
1009 wake_up(&audio->write_wait);
1010 }
1011 }
1012
1013 if (audio->out_needed) {
1014 /* If the DSP currently wants data and we have a
1015 * buffer available, we will send it and reset
1016 * the needed flag. We'll mark the buffer as in-flight
1017 * so that it won't be recycled until the next buffer
1018 * is requested
1019 */
1020
1021 frame = audio->out + audio->out_tail;
1022 if (frame->used) {
1023 BUG_ON(frame->used == 0xffffffff);
1024 audrec_pcm_buffer_ptr_refresh(audio,
1025 audio->out_tail,
1026 frame->used);
1027 frame->used = 0xffffffff;
1028 audio->out_needed = 0;
1029 }
1030 }
1031 done:
1032 spin_unlock_irqrestore(&audio->dsp_lock, flags);
1033}
1034
Steve Mucklef132c6c2012-06-06 18:30:57 -07001035static int audamrnb_in_fsync(struct file *file, loff_t a, loff_t b, int datasync)
Manish Dewanganb9171e52011-03-15 15:18:18 +05301036
1037{
1038 struct audio_amrnb_in *audio = file->private_data;
1039 int32_t rc = 0;
1040
1041 MM_DBG("\n"); /* Macro prints the file name and function */
1042 if (!audio->running || (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)) {
1043 rc = -EINVAL;
1044 goto done_nolock;
1045 }
1046
1047 mutex_lock(&audio->write_lock);
1048
1049 rc = wait_event_interruptible(audio->write_wait,
1050 audio->wflush);
1051 MM_DBG("waked on by some event audio->wflush = %d\n", audio->wflush);
1052
1053 if (rc < 0)
1054 goto done;
1055 else if (audio->wflush) {
1056 rc = -EBUSY;
1057 goto done;
1058 }
1059done:
1060 mutex_unlock(&audio->write_lock);
1061done_nolock:
1062 return rc;
1063
1064}
1065
1066int audrec_amrnb_process_eos(struct audio_amrnb_in *audio,
1067 const char __user *buf_start, unsigned short mfield_size)
1068{
1069 struct buffer *frame;
1070 int32_t rc = 0;
1071
1072 frame = audio->out + audio->out_head;
1073
1074 rc = wait_event_interruptible(audio->write_wait,
1075 (audio->out_needed &&
1076 audio->out[0].used == 0 &&
1077 audio->out[1].used == 0)
1078 || (audio->stopped)
1079 || (audio->wflush));
1080
1081 if (rc < 0)
1082 goto done;
1083 if (audio->stopped || audio->wflush) {
1084 rc = -EBUSY;
1085 goto done;
1086 }
1087 if (copy_from_user(frame->data, buf_start, mfield_size)) {
1088 rc = -EFAULT;
1089 goto done;
1090 }
1091
1092 frame->mfield_sz = mfield_size;
1093 audio->out_head ^= 1;
1094 frame->used = mfield_size;
1095 MM_DBG("copying meta_out frame->used = %d\n", frame->used);
1096 audrec_pcm_send_data(audio, 0);
1097done:
1098 return rc;
1099}
1100
1101static ssize_t audamrnb_in_write(struct file *file,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001102 const char __user *buf,
1103 size_t count, loff_t *pos)
1104{
Manish Dewanganb9171e52011-03-15 15:18:18 +05301105 struct audio_amrnb_in *audio = file->private_data;
1106 const char __user *start = buf;
1107 struct buffer *frame;
1108 char *cpy_ptr;
1109 int32_t rc = 0, eos_condition = AUDPREPROC_AMRNB_EOS_NONE;
1110 unsigned short mfield_size = 0;
1111 int32_t write_count = 0;
1112 MM_DBG("cnt=%d\n", count);
1113
1114 if (count & 1)
1115 return -EINVAL;
1116
1117 if (audio->mode != MSM_AUD_ENC_MODE_NONTUNNEL)
1118 return -EINVAL;
1119
1120 mutex_lock(&audio->write_lock);
1121 frame = audio->out + audio->out_head;
1122 /* if supplied count is more than driver buffer size
1123 * then only copy driver buffer size
1124 */
1125 if (count > frame->size)
1126 count = frame->size;
1127
1128 write_count = count;
1129 cpy_ptr = frame->data;
1130 rc = wait_event_interruptible(audio->write_wait,
1131 (frame->used == 0)
1132 || (audio->stopped)
1133 || (audio->wflush));
1134 if (rc < 0)
1135 goto error;
1136
1137 if (audio->stopped || audio->wflush) {
1138 rc = -EBUSY;
1139 goto error;
1140 }
1141 if (audio->mfield) {
1142 if (buf == start) {
1143 /* Processing beginning of user buffer */
1144 if (__get_user(mfield_size,
1145 (unsigned short __user *) buf)) {
1146 rc = -EFAULT;
1147 goto error;
1148 } else if (mfield_size > count) {
1149 rc = -EINVAL;
1150 goto error;
1151 }
1152 MM_DBG("mf offset_val %x\n", mfield_size);
1153 if (copy_from_user(cpy_ptr, buf, mfield_size)) {
1154 rc = -EFAULT;
1155 goto error;
1156 }
1157 /* Check if EOS flag is set and buffer has
1158 * contains just meta field
1159 */
1160 if (cpy_ptr[AUDPREPROC_AMRNB_EOS_FLG_OFFSET] &
1161 AUDPREPROC_AMRNB_EOS_FLG_MASK) {
1162 eos_condition = AUDPREPROC_AMRNB_EOS_SET;
1163 MM_DBG("EOS SET\n");
1164 if (mfield_size == count) {
1165 buf += mfield_size;
1166 eos_condition = 0;
1167 goto exit;
1168 } else
1169 cpy_ptr[AUDPREPROC_AMRNB_EOS_FLG_OFFSET] &=
1170 ~AUDPREPROC_AMRNB_EOS_FLG_MASK;
1171 }
1172 cpy_ptr += mfield_size;
1173 count -= mfield_size;
1174 buf += mfield_size;
1175 } else {
1176 mfield_size = 0;
1177 MM_DBG("continuous buffer\n");
1178 }
1179 frame->mfield_sz = mfield_size;
1180 }
1181 MM_DBG("copying the stream count = %d\n", count);
1182 if (copy_from_user(cpy_ptr, buf, count)) {
1183 rc = -EFAULT;
1184 goto error;
1185 }
1186exit:
1187 frame->used = count;
1188 audio->out_head ^= 1;
1189 if (!audio->flush_ack)
1190 audrec_pcm_send_data(audio, 0);
1191 else {
1192 audrec_pcm_send_data(audio, 1);
1193 audio->flush_ack = 0;
1194 }
1195 if (eos_condition == AUDPREPROC_AMRNB_EOS_SET)
1196 rc = audrec_amrnb_process_eos(audio, start, mfield_size);
1197 mutex_unlock(&audio->write_lock);
1198 return write_count;
1199error:
1200 mutex_unlock(&audio->write_lock);
1201 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001202}
1203
Manish Dewanganb9171e52011-03-15 15:18:18 +05301204static int audamrnb_in_release(struct inode *inode, struct file *file)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001205{
1206 struct audio_amrnb_in *audio = file->private_data;
Manish Dewanganb9171e52011-03-15 15:18:18 +05301207 int32_t dma_size = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001208 mutex_lock(&audio->lock);
Manish Dewanganb9171e52011-03-15 15:18:18 +05301209 audamrnb_in_disable(audio);
1210 audamrnb_in_flush(audio);
1211 msm_adsp_put(audio->audrec);
1212
Manish Dewanganb9171e52011-03-15 15:18:18 +05301213 audpreproc_aenc_free(audio->enc_id);
1214 audio->audrec = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001215 audio->opened = 0;
Manish Dewanganb9171e52011-03-15 15:18:18 +05301216 if ((audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) && \
1217 (audio->out_data)) {
Sidipotu Ashok172c98b2012-06-26 17:58:29 +05301218 ion_unmap_kernel(audio->client, audio->input_buff_handle);
1219 ion_free(audio->client, audio->input_buff_handle);
Manish Dewanganb9171e52011-03-15 15:18:18 +05301220 audio->out_data = NULL;
1221 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001222 if (audio->data) {
Manish Dewanganb9171e52011-03-15 15:18:18 +05301223 if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
1224 dma_size = DMASZ;
1225 else
1226 dma_size = NT_DMASZ;
1227
1228 dma_free_coherent(NULL,
1229 dma_size, audio->data, audio->phys);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001230 audio->data = NULL;
1231 }
Sidipotu Ashok172c98b2012-06-26 17:58:29 +05301232 ion_client_destroy(audio->client);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001233 mutex_unlock(&audio->lock);
1234 return 0;
1235}
1236
Manish Dewanganb9171e52011-03-15 15:18:18 +05301237struct audio_amrnb_in the_audio_amrnb_in;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001238
Manish Dewanganb9171e52011-03-15 15:18:18 +05301239static int audamrnb_in_open(struct inode *inode, struct file *file)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001240{
1241 struct audio_amrnb_in *audio = &the_audio_amrnb_in;
Manish Dewanganb9171e52011-03-15 15:18:18 +05301242 int32_t rc;
1243 int encid;
1244 int32_t dma_size = 0;
Sidipotu Ashok172c98b2012-06-26 17:58:29 +05301245 int len = 0;
1246 unsigned long ionflag = 0;
1247 ion_phys_addr_t addr = 0;
1248 struct ion_handle *handle = NULL;
1249 struct ion_client *client = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001250
1251 mutex_lock(&audio->lock);
1252 if (audio->opened) {
1253 rc = -EBUSY;
1254 goto done;
1255 }
Manish Dewanganb9171e52011-03-15 15:18:18 +05301256 if ((file->f_mode & FMODE_WRITE) &&
1257 (file->f_mode & FMODE_READ)) {
1258 audio->mode = MSM_AUD_ENC_MODE_NONTUNNEL;
1259 dma_size = NT_DMASZ;
1260 MM_DBG("Opened for non tunnel mode encoding\n");
1261 } else if (!(file->f_mode & FMODE_WRITE) &&
1262 (file->f_mode & FMODE_READ)) {
1263 audio->mode = MSM_AUD_ENC_MODE_TUNNEL;
1264 dma_size = DMASZ;
1265 MM_DBG("Opened for tunnel mode encoding\n");
1266 } else {
1267 MM_ERR("Invalid mode\n");
1268 rc = -EACCES;
1269 goto done;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001270 }
1271
Manish Dewanganb9171e52011-03-15 15:18:18 +05301272 /* Settings will be re-config at AUDIO_SET_CONFIG,
1273 * but at least we need to have initial config
1274 */
1275 audio->samp_rate = RPC_AUD_DEF_SAMPLE_RATE_8000,
1276 audio->samp_rate_index = AUDREC_CMD_SAMP_RATE_INDX_8000;
1277 audio->channel_mode = AUDREC_CMD_STEREO_MODE_MONO;
1278 if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL)
1279 audio->buffer_size = (AMRNB_FRAME_SIZE + 14);
1280 else
1281 audio->buffer_size = (FRAME_SIZE - 8);
1282 audio->enc_type = AUDREC_CMD_TYPE_0_INDEX_AMRNB | audio->mode;
1283
1284 if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
1285 rc = audmgr_open(&audio->audmgr);
1286 if (rc)
1287 goto done;
1288 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001289 audio->amrnb_enc_cfg.voicememoencweight1 = 0x0000;
1290 audio->amrnb_enc_cfg.voicememoencweight2 = 0x0000;
1291 audio->amrnb_enc_cfg.voicememoencweight3 = 0x4000;
1292 audio->amrnb_enc_cfg.voicememoencweight4 = 0x0000;
1293 audio->amrnb_enc_cfg.dtx_mode_enable = 0;
1294 audio->amrnb_enc_cfg.test_mode_enable = 0;
1295 audio->amrnb_enc_cfg.enc_mode = 7;
Manish Dewanganb9171e52011-03-15 15:18:18 +05301296
1297 encid = audpreproc_aenc_alloc(audio->enc_type, &audio->module_name,
1298 &audio->queue_ids);
1299 if (encid < 0) {
1300 MM_ERR("No free encoder available\n");
1301 rc = -ENODEV;
1302 goto done;
1303 }
1304 audio->enc_id = encid;
1305 rc = msm_adsp_get(audio->module_name, &audio->audrec,
1306 &audrec_amrnb_adsp_ops, audio);
1307 if (rc) {
1308 audpreproc_aenc_free(audio->enc_id);
1309 goto done;
1310 }
1311
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001312 audio->dsp_cnt = 0;
1313 audio->stopped = 0;
Manish Dewanganb9171e52011-03-15 15:18:18 +05301314 audio->wflush = 0;
1315 audio->rflush = 0;
1316 audio->flush_ack = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001317
Manish Dewanganb9171e52011-03-15 15:18:18 +05301318 audamrnb_in_flush(audio);
1319 audamrnb_out_flush(audio);
1320 /* used dma_allco_coherent for backward compatibility with 7x27 */
1321 audio->data = dma_alloc_coherent(NULL, dma_size,
1322 &audio->phys, GFP_KERNEL);
1323 if (!audio->data) {
1324 MM_ERR("Unable to allocate DMA buffer\n");
1325 goto evt_error;
1326 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001327
Sidipotu Ashok172c98b2012-06-26 17:58:29 +05301328 client = msm_ion_client_create(UINT_MAX, "Audio_AMRNB_in_client");
1329 if (IS_ERR_OR_NULL(client)) {
1330 MM_ERR("Unable to create ION client\n");
1331 rc = -ENOMEM;
1332 goto client_create_error;
1333 }
1334 audio->client = client;
1335
Manish Dewanganb9171e52011-03-15 15:18:18 +05301336 audio->out_data = NULL;
1337 if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) {
Sidipotu Ashok172c98b2012-06-26 17:58:29 +05301338 MM_DBG("allocating BUFFER_SIZE %d\n", BUFFER_SIZE);
1339 handle = ion_alloc(client, BUFFER_SIZE,
Hanumant Singh7d72bad2012-08-29 18:39:44 -07001340 SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0);
Sidipotu Ashok172c98b2012-06-26 17:58:29 +05301341 if (IS_ERR_OR_NULL(handle)) {
1342 MM_ERR("Unable to create allocate write buffers\n");
Manish Dewanganb9171e52011-03-15 15:18:18 +05301343 rc = -ENOMEM;
Sidipotu Ashok172c98b2012-06-26 17:58:29 +05301344 goto input_buff_alloc_error;
Manish Dewanganb9171e52011-03-15 15:18:18 +05301345 }
1346
Sidipotu Ashok172c98b2012-06-26 17:58:29 +05301347 audio->input_buff_handle = handle;
1348
1349 rc = ion_phys(client , handle, &addr, &len);
1350 if (rc) {
1351 MM_ERR("I/P buffers:Invalid phy: %x sz: %x\n",
1352 (unsigned int) addr, (unsigned int) len);
1353 rc = -ENOMEM;
1354 goto input_buff_get_phys_error;
1355 } else {
1356 MM_INFO("Got valid phy: %x sz: %x\n",
1357 (unsigned int) addr,
1358 (unsigned int) len);
1359 }
1360 audio->out_phys = (int32_t)addr;
1361
1362 rc = ion_handle_get_flags(client,
1363 handle, &ionflag);
1364 if (rc) {
1365 MM_ERR("could not get flags for the handle\n");
1366 rc = -ENOMEM;
1367 goto input_buff_get_flags_error;
1368 }
1369
Mitchel Humpherys911b4b72012-09-12 14:42:50 -07001370 audio->map_v_write = ion_map_kernel(client, handle);
Sidipotu Ashok172c98b2012-06-26 17:58:29 +05301371 if (IS_ERR(audio->map_v_write)) {
1372 MM_ERR("could not map write buffers\n");
1373 rc = -ENOMEM;
1374 goto input_buff_map_error;
1375 }
1376 audio->out_data = audio->map_v_write;
1377 MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
1378 (unsigned int)addr,
1379 (unsigned int)audio->out_data);
1380
Manish Dewanganb9171e52011-03-15 15:18:18 +05301381 /* Initialize buffer */
1382 audio->out[0].data = audio->out_data + 0;
1383 audio->out[0].addr = audio->out_phys + 0;
1384 audio->out[0].size = OUT_BUFFER_SIZE;
1385
1386 audio->out[1].data = audio->out_data + OUT_BUFFER_SIZE;
1387 audio->out[1].addr = audio->out_phys + OUT_BUFFER_SIZE;
1388 audio->out[1].size = OUT_BUFFER_SIZE;
1389
1390 MM_DBG("audio->out[0].data = %d audio->out[1].data = %d",
1391 (uint32_t)audio->out[0].data,
1392 (uint32_t)audio->out[1].data);
1393 audio->mfield = NT_FRAME_HEADER_SIZE;
1394 audio->out_frame_cnt++;
1395 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001396 file->private_data = audio;
1397 audio->opened = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001398
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001399done:
1400 mutex_unlock(&audio->lock);
1401 return rc;
Sidipotu Ashok172c98b2012-06-26 17:58:29 +05301402input_buff_map_error:
1403input_buff_get_phys_error:
1404input_buff_get_flags_error:
1405 ion_free(client, audio->input_buff_handle);
1406input_buff_alloc_error:
1407 ion_client_destroy(client);
1408client_create_error:
1409 dma_free_coherent(NULL, dma_size, audio->data, audio->phys);
Manish Dewanganb9171e52011-03-15 15:18:18 +05301410evt_error:
1411 msm_adsp_put(audio->audrec);
Manish Dewanganb9171e52011-03-15 15:18:18 +05301412
1413 audpreproc_aenc_free(audio->enc_id);
1414 mutex_unlock(&audio->lock);
1415 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001416}
1417
1418static const struct file_operations audio_fops = {
1419 .owner = THIS_MODULE,
Manish Dewanganb9171e52011-03-15 15:18:18 +05301420 .open = audamrnb_in_open,
1421 .release = audamrnb_in_release,
1422 .read = audamrnb_in_read,
1423 .write = audamrnb_in_write,
1424 .fsync = audamrnb_in_fsync,
1425 .unlocked_ioctl = audamrnb_in_ioctl,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001426};
1427
Manish Dewanganb9171e52011-03-15 15:18:18 +05301428struct miscdevice audamrnb_in_misc = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001429 .minor = MISC_DYNAMIC_MINOR,
1430 .name = "msm_amrnb_in",
1431 .fops = &audio_fops,
1432};
1433
1434#ifdef CONFIG_DEBUG_FS
1435static ssize_t audamrnb_in_debug_open(struct inode *inode, struct file *file)
1436{
1437 file->private_data = inode->i_private;
1438 return 0;
1439}
1440
1441static ssize_t audamrnb_in_debug_read(struct file *file, char __user *buf,
1442 size_t count, loff_t *ppos)
1443{
Manish Dewanganb9171e52011-03-15 15:18:18 +05301444 const int32_t debug_bufmax = 1024;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001445 static char buffer[1024];
Manish Dewanganb9171e52011-03-15 15:18:18 +05301446 int32_t n = 0, i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001447 struct audio_amrnb_in *audio = file->private_data;
1448
1449 mutex_lock(&audio->lock);
1450 n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
1451 n += scnprintf(buffer + n, debug_bufmax - n,
1452 "enabled %d\n", audio->enabled);
1453 n += scnprintf(buffer + n, debug_bufmax - n,
1454 "stopped %d\n", audio->stopped);
1455 n += scnprintf(buffer + n, debug_bufmax - n,
1456 "audrec_obj_idx %d\n", audio->audrec_obj_idx);
1457 n += scnprintf(buffer + n, debug_bufmax - n,
1458 "dsp_cnt %d \n", audio->dsp_cnt);
1459 n += scnprintf(buffer + n, debug_bufmax - n,
1460 "in_count %d \n", audio->in_count);
1461 for (i = 0; i < FRAME_NUM; i++)
1462 n += scnprintf(buffer + n, debug_bufmax - n,
1463 "audio->in[%d].size %d \n", i, audio->in[i].size);
1464 mutex_unlock(&audio->lock);
1465 /* Following variables are only useful for debugging when
1466 * when record halts unexpectedly. Thus, no mutual exclusion
1467 * enforced
1468 */
1469 n += scnprintf(buffer + n, debug_bufmax - n,
1470 "running %d \n", audio->running);
1471 n += scnprintf(buffer + n, debug_bufmax - n,
1472 "buffer_size %d \n", audio->buffer_size);
1473 n += scnprintf(buffer + n, debug_bufmax - n,
1474 "in_head %d \n", audio->in_head);
1475 n += scnprintf(buffer + n, debug_bufmax - n,
1476 "in_tail %d \n", audio->in_tail);
1477 buffer[n] = 0;
1478 return simple_read_from_buffer(buf, count, ppos, buffer, n);
1479}
1480
1481static const struct file_operations audamrnb_in_debug_fops = {
1482 .read = audamrnb_in_debug_read,
1483 .open = audamrnb_in_debug_open,
1484};
1485#endif
1486
Manish Dewanganb9171e52011-03-15 15:18:18 +05301487static int __init audamrnb_in_init(void)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001488{
1489#ifdef CONFIG_DEBUG_FS
1490 struct dentry *dentry;
1491#endif
1492
1493 mutex_init(&the_audio_amrnb_in.lock);
1494 mutex_init(&the_audio_amrnb_in.read_lock);
1495 spin_lock_init(&the_audio_amrnb_in.dsp_lock);
1496 init_waitqueue_head(&the_audio_amrnb_in.wait);
Manish Dewanganb9171e52011-03-15 15:18:18 +05301497 init_waitqueue_head(&the_audio_amrnb_in.wait_enable);
1498 mutex_init(&the_audio_amrnb_in.write_lock);
1499 init_waitqueue_head(&the_audio_amrnb_in.write_wait);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001500
1501#ifdef CONFIG_DEBUG_FS
1502 dentry = debugfs_create_file("msm_amrnb_in", S_IFREG | S_IRUGO, NULL,
1503 (void *) &the_audio_amrnb_in, &audamrnb_in_debug_fops);
1504
1505 if (IS_ERR(dentry))
1506 MM_ERR("debugfs_create_file failed\n");
1507#endif
Manish Dewanganb9171e52011-03-15 15:18:18 +05301508 return misc_register(&audamrnb_in_misc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001509}
1510
Manish Dewanganb9171e52011-03-15 15:18:18 +05301511static void __exit audamrnb_in_exit(void)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001512{
Manish Dewanganb9171e52011-03-15 15:18:18 +05301513 misc_deregister(&audamrnb_in_misc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001514}
1515
Manish Dewanganb9171e52011-03-15 15:18:18 +05301516module_init(audamrnb_in_init);
1517module_exit(audamrnb_in_exit);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001518
1519MODULE_DESCRIPTION("MSM AMRNB Encoder driver");
1520MODULE_LICENSE("GPL v2");