blob: 644df2d0b5888fd83c997c7c561928a87c9c2e18 [file] [log] [blame]
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301/* Copyright (C) 2008 Google, Inc.
2 * Copyright (C) 2008 HTC Corporation
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +05303 * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
Deepa Madiregama55cbf782011-09-10 05:44:39 +05304 *
5 * This software is licensed under the terms of the GNU General Public
6 * License version 2, as published by the Free Software Foundation, and
7 * may be copied, distributed, and modified under those terms.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 */
15
16#include <linux/module.h>
17#include <linux/fs.h>
18#include <linux/miscdevice.h>
19#include <linux/uaccess.h>
20#include <linux/sched.h>
21#include <linux/wait.h>
22#include <linux/dma-mapping.h>
23#include <linux/slab.h>
24#include <asm/atomic.h>
25#include <asm/ioctls.h>
26#include <sound/q6asm.h>
27#include <sound/apr_audio.h>
28#include <linux/debugfs.h>
29#include "audio_utils_aio.h"
30
31#ifdef CONFIG_DEBUG_FS
32ssize_t audio_aio_debug_open(struct inode *inode, struct file *file)
33{
34 file->private_data = inode->i_private;
35 return 0;
36}
37
38ssize_t audio_aio_debug_read(struct file *file, char __user * buf,
39 size_t count, loff_t *ppos)
40{
41 const int debug_bufmax = 4096;
42 static char buffer[4096];
43 int n = 0;
44 struct q6audio_aio *audio = file->private_data;
45
46 mutex_lock(&audio->lock);
47 n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
48 n += scnprintf(buffer + n, debug_bufmax - n,
49 "enabled %d\n", audio->enabled);
50 n += scnprintf(buffer + n, debug_bufmax - n,
51 "stopped %d\n", audio->stopped);
52 n += scnprintf(buffer + n, debug_bufmax - n,
53 "feedback %d\n", audio->feedback);
54 mutex_unlock(&audio->lock);
55 /* Following variables are only useful for debugging when
56 * when playback halts unexpectedly. Thus, no mutual exclusion
57 * enforced
58 */
59 n += scnprintf(buffer + n, debug_bufmax - n,
60 "wflush %d\n", audio->wflush);
61 n += scnprintf(buffer + n, debug_bufmax - n,
62 "rflush %d\n", audio->rflush);
63 n += scnprintf(buffer + n, debug_bufmax - n,
64 "inqueue empty %d\n", list_empty(&audio->in_queue));
65 n += scnprintf(buffer + n, debug_bufmax - n,
66 "outqueue empty %d\n", list_empty(&audio->out_queue));
67 buffer[n] = 0;
68 return simple_read_from_buffer(buf, count, ppos, buffer, n);
69}
70#endif
71
72static int insert_eos_buf(struct q6audio_aio *audio,
73 struct audio_aio_buffer_node *buf_node)
74{
75 struct dec_meta_out *eos_buf = buf_node->kvaddr;
76 pr_debug("%s[%p]:insert_eos_buf\n", __func__, audio);
77 eos_buf->num_of_frames = 0xFFFFFFFF;
78 eos_buf->meta_out_dsp[0].offset_to_frame = 0x0;
79 eos_buf->meta_out_dsp[0].nflags = AUDIO_DEC_EOS_SET;
80 return sizeof(struct dec_meta_out) +
81 sizeof(eos_buf->meta_out_dsp[0]);
82}
83
84/* Routine which updates read buffers of driver/dsp,
85 for flush operation as DSP output might not have proper
86 value set */
87static int insert_meta_data_flush(struct q6audio_aio *audio,
88 struct audio_aio_buffer_node *buf_node)
89{
90 struct dec_meta_out *meta_data = buf_node->kvaddr;
91 meta_data->num_of_frames = 0x0;
92 meta_data->meta_out_dsp[0].offset_to_frame = 0x0;
93 meta_data->meta_out_dsp[0].nflags = 0x0;
94 return sizeof(struct dec_meta_out) +
95 sizeof(meta_data->meta_out_dsp[0]);
96}
97
98static void extract_meta_out_info(struct q6audio_aio *audio,
99 struct audio_aio_buffer_node *buf_node, int dir)
100{
101 struct dec_meta_out *meta_data = buf_node->kvaddr;
102 if (dir) { /* input buffer - Write */
103 if (audio->buf_cfg.meta_info_enable)
104 memcpy(&buf_node->meta_info.meta_in,
105 (char *)buf_node->kvaddr, sizeof(struct dec_meta_in));
106 else
107 memset(&buf_node->meta_info.meta_in,
108 0, sizeof(struct dec_meta_in));
109 pr_debug("%s[%p]:i/p: msw_ts 0x%lx lsw_ts 0x%lx nflags 0x%8x\n",
110 __func__, audio,
111 buf_node->meta_info.meta_in.ntimestamp.highpart,
112 buf_node->meta_info.meta_in.ntimestamp.lowpart,
113 buf_node->meta_info.meta_in.nflags);
114 } else { /* output buffer - Read */
115 memcpy((char *)buf_node->kvaddr,
116 &buf_node->meta_info.meta_out,
117 sizeof(struct dec_meta_out));
118 meta_data->meta_out_dsp[0].nflags = 0x00000000;
119 pr_debug("%s[%p]:o/p: msw_ts 0x%8x lsw_ts 0x%8x nflags 0x%8x,"
120 "num_frames = %d\n",
121 __func__, audio,
122 ((struct dec_meta_out *)buf_node->kvaddr)->\
123 meta_out_dsp[0].msw_ts,
124 ((struct dec_meta_out *)buf_node->kvaddr)->\
125 meta_out_dsp[0].lsw_ts,
126 ((struct dec_meta_out *)buf_node->kvaddr)->\
127 meta_out_dsp[0].nflags,
128 ((struct dec_meta_out *)buf_node->kvaddr)->num_of_frames);
129 }
130}
131
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530132static int audio_aio_ion_lookup_vaddr(struct q6audio_aio *audio, void *addr,
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530133 unsigned long len,
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530134 struct audio_aio_ion_region **region)
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530135{
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530136 struct audio_aio_ion_region *region_elt;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530137
138 int match_count = 0;
139
140 *region = NULL;
141
142 /* returns physical address or zero */
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530143 list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530144 if (addr >= region_elt->vaddr &&
145 addr < region_elt->vaddr + region_elt->len &&
146 addr + len <= region_elt->vaddr + region_elt->len) {
147 /* offset since we could pass vaddr inside a registerd
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530148 * ion buffer
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530149 */
150
151 match_count++;
152 if (!*region)
153 *region = region_elt;
154 }
155 }
156
157 if (match_count > 1) {
158 pr_err("%s[%p]:multiple hits for vaddr %p, len %ld\n",
159 __func__, audio, addr, len);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530160 list_for_each_entry(region_elt, &audio->ion_region_queue,
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530161 list) {
162 if (addr >= region_elt->vaddr &&
163 addr < region_elt->vaddr + region_elt->len &&
164 addr + len <= region_elt->vaddr + region_elt->len)
165 pr_err("\t%s[%p]:%p, %ld --> %p\n",
166 __func__, audio,
167 region_elt->vaddr,
168 region_elt->len,
169 (void *)region_elt->paddr);
170 }
171 }
172
173 return *region ? 0 : -1;
174}
175
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530176static unsigned long audio_aio_ion_fixup(struct q6audio_aio *audio, void *addr,
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530177 unsigned long len, int ref_up, void **kvaddr)
178{
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530179 struct audio_aio_ion_region *region;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530180 unsigned long paddr;
181 int ret;
182
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530183 ret = audio_aio_ion_lookup_vaddr(audio, addr, len, &region);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530184 if (ret) {
185 pr_err("%s[%p]:lookup (%p, %ld) failed\n",
186 __func__, audio, addr, len);
187 return 0;
188 }
189 if (ref_up)
190 region->ref_cnt++;
191 else
192 region->ref_cnt--;
193 pr_debug("%s[%p]:found region %p ref_cnt %d\n",
194 __func__, audio, region, region->ref_cnt);
195 paddr = region->paddr + (addr - region->vaddr);
196 /* provide kernel virtual address for accessing meta information */
197 if (kvaddr)
198 *kvaddr = (void *) (region->kvaddr + (addr - region->vaddr));
199 return paddr;
200}
201
202static int audio_aio_pause(struct q6audio_aio *audio)
203{
204 int rc = 0;
205
206 pr_debug("%s[%p], enabled = %d\n", __func__, audio,
207 audio->enabled);
208 if (audio->enabled) {
209 rc = q6asm_cmd(audio->ac, CMD_PAUSE);
210 if (rc < 0)
211 pr_err("%s[%p]: pause cmd failed rc=%d\n",
212 __func__, audio, rc);
213
214 } else
215 pr_err("%s[%p]: Driver not enabled\n", __func__, audio);
216 return rc;
217}
218
219static int audio_aio_flush(struct q6audio_aio *audio)
220{
221 int rc;
222
223 if (audio->enabled) {
224 /* Implicitly issue a pause to the decoder before flushing if
225 it is not in pause state */
226 if (!(audio->drv_status & ADRV_STATUS_PAUSE)) {
227 rc = audio_aio_pause(audio);
228 if (rc < 0)
229 pr_err("%s[%p}: pause cmd failed rc=%d\n",
230 __func__, audio,
231 rc);
232 else
233 audio->drv_status |= ADRV_STATUS_PAUSE;
234 }
235 rc = q6asm_cmd(audio->ac, CMD_FLUSH);
236 if (rc < 0)
237 pr_err("%s[%p]: flush cmd failed rc=%d\n",
238 __func__, audio, rc);
239 /* Not in stop state, reenable the stream */
240 if (audio->stopped == 0) {
241 rc = audio_aio_enable(audio);
242 if (rc)
243 pr_err("%s[%p]:audio re-enable failed\n",
244 __func__, audio);
245 else {
246 audio->enabled = 1;
247 if (audio->drv_status & ADRV_STATUS_PAUSE)
248 audio->drv_status &= ~ADRV_STATUS_PAUSE;
249 }
250 }
251 }
252 pr_debug("%s[%p]:in_bytes %d\n",
253 __func__, audio, atomic_read(&audio->in_bytes));
254 pr_debug("%s[%p]:in_samples %d\n",
255 __func__, audio, atomic_read(&audio->in_samples));
256 atomic_set(&audio->in_bytes, 0);
257 atomic_set(&audio->in_samples, 0);
258 return 0;
259}
260
261static int audio_aio_outport_flush(struct q6audio_aio *audio)
262{
263 int rc;
264
265 rc = q6asm_cmd(audio->ac, CMD_OUT_FLUSH);
266 if (rc < 0)
267 pr_err("%s[%p}: output port flush cmd failed rc=%d\n",
268 __func__, audio, rc);
269 return rc;
270}
271
272/* Write buffer to DSP / Handle Ack from DSP */
273void audio_aio_async_write_ack(struct q6audio_aio *audio, uint32_t token,
274 uint32_t *payload)
275{
276 unsigned long flags;
277 union msm_audio_event_payload event_payload;
278 struct audio_aio_buffer_node *used_buf;
279
280 /* No active flush in progress */
281 if (audio->wflush)
282 return;
283
284 spin_lock_irqsave(&audio->dsp_lock, flags);
285 BUG_ON(list_empty(&audio->out_queue));
286 used_buf = list_first_entry(&audio->out_queue,
287 struct audio_aio_buffer_node, list);
288 if (token == used_buf->token) {
289 list_del(&used_buf->list);
290 spin_unlock_irqrestore(&audio->dsp_lock, flags);
291 pr_debug("%s[%p]:consumed buffer\n", __func__, audio);
292 event_payload.aio_buf = used_buf->buf;
293 audio_aio_post_event(audio, AUDIO_EVENT_WRITE_DONE,
294 event_payload);
295 kfree(used_buf);
296 if (list_empty(&audio->out_queue) &&
297 (audio->drv_status & ADRV_STATUS_FSYNC)) {
298 pr_debug("%s[%p]: list is empty, reached EOS in\
299 Tunnel\n", __func__, audio);
300 wake_up(&audio->write_wait);
301 }
302 } else {
303 pr_err("%s[%p]:expected=%lx ret=%x\n",
304 __func__, audio, used_buf->token, token);
305 spin_unlock_irqrestore(&audio->dsp_lock, flags);
306 }
307}
308
309/* Read buffer from DSP / Handle Ack from DSP */
310void audio_aio_async_read_ack(struct q6audio_aio *audio, uint32_t token,
311 uint32_t *payload)
312{
313 unsigned long flags;
314 union msm_audio_event_payload event_payload;
315 struct audio_aio_buffer_node *filled_buf;
316
317 /* No active flush in progress */
318 if (audio->rflush)
319 return;
320
321 /* Statistics of read */
322 atomic_add(payload[2], &audio->in_bytes);
323 atomic_add(payload[7], &audio->in_samples);
324
325 spin_lock_irqsave(&audio->dsp_lock, flags);
326 BUG_ON(list_empty(&audio->in_queue));
327 filled_buf = list_first_entry(&audio->in_queue,
328 struct audio_aio_buffer_node, list);
329 if (token == (filled_buf->token)) {
330 list_del(&filled_buf->list);
331 spin_unlock_irqrestore(&audio->dsp_lock, flags);
332 event_payload.aio_buf = filled_buf->buf;
333 /* Read done Buffer due to flush/normal condition
334 after EOS event, so append EOS buffer */
335 if (audio->eos_rsp == 0x1) {
336 event_payload.aio_buf.data_len =
337 insert_eos_buf(audio, filled_buf);
338 /* Reset flag back to indicate eos intimated */
339 audio->eos_rsp = 0;
340 } else {
341 filled_buf->meta_info.meta_out.num_of_frames =
342 payload[7];
343 event_payload.aio_buf.data_len = payload[2] + \
344 payload[3] + \
345 sizeof(struct dec_meta_out);
346 pr_debug("%s[%p]:nr of frames 0x%8x len=%d\n",
347 __func__, audio,
348 filled_buf->meta_info.meta_out.num_of_frames,
349 event_payload.aio_buf.data_len);
350 extract_meta_out_info(audio, filled_buf, 0);
351 audio->eos_rsp = 0;
352 }
353 audio_aio_post_event(audio, AUDIO_EVENT_READ_DONE,
354 event_payload);
355 kfree(filled_buf);
356 } else {
357 pr_err("%s[%p]:expected=%lx ret=%x\n",
358 __func__, audio, filled_buf->token, token);
359 spin_unlock_irqrestore(&audio->dsp_lock, flags);
360 }
361}
362
363/* ------------------- device --------------------- */
364void audio_aio_async_out_flush(struct q6audio_aio *audio)
365{
366 struct audio_aio_buffer_node *buf_node;
367 struct list_head *ptr, *next;
368 union msm_audio_event_payload payload;
369 unsigned long flags;
370
371 pr_debug("%s[%p}\n", __func__, audio);
372 /* EOS followed by flush, EOS response not guranteed, free EOS i/p
373 buffer */
374 spin_lock_irqsave(&audio->dsp_lock, flags);
375
376 if (audio->eos_flag && (audio->eos_write_payload.aio_buf.buf_addr)) {
377 pr_debug("%s[%p]: EOS followed by flush received,acknowledge"\
378 " eos i/p buffer immediately\n", __func__, audio);
379 audio_aio_post_event(audio, AUDIO_EVENT_WRITE_DONE,
380 audio->eos_write_payload);
381 memset(&audio->eos_write_payload , 0,
382 sizeof(union msm_audio_event_payload));
383 }
384 spin_unlock_irqrestore(&audio->dsp_lock, flags);
385 list_for_each_safe(ptr, next, &audio->out_queue) {
386 buf_node = list_entry(ptr, struct audio_aio_buffer_node, list);
387 list_del(&buf_node->list);
388 payload.aio_buf = buf_node->buf;
389 audio_aio_post_event(audio, AUDIO_EVENT_WRITE_DONE, payload);
390 kfree(buf_node);
391 pr_debug("%s[%p]: Propagate WRITE_DONE during flush\n",
392 __func__, audio);
393 }
394}
395
396void audio_aio_async_in_flush(struct q6audio_aio *audio)
397{
398 struct audio_aio_buffer_node *buf_node;
399 struct list_head *ptr, *next;
400 union msm_audio_event_payload payload;
401
402 pr_debug("%s[%p]\n", __func__, audio);
403 list_for_each_safe(ptr, next, &audio->in_queue) {
404 buf_node = list_entry(ptr, struct audio_aio_buffer_node, list);
405 list_del(&buf_node->list);
406 /* Forcefull send o/p eos buffer after flush, if no eos response
407 * received by dsp even after sending eos command */
408 if ((audio->eos_rsp != 1) && audio->eos_flag) {
409 pr_debug("%s[%p]: send eos on o/p buffer during"
410 "flush\n", __func__, audio);
411 payload.aio_buf = buf_node->buf;
412 payload.aio_buf.data_len =
413 insert_eos_buf(audio, buf_node);
414 audio->eos_flag = 0;
415 } else {
416 payload.aio_buf = buf_node->buf;
417 payload.aio_buf.data_len =
418 insert_meta_data_flush(audio, buf_node);
419 }
420 audio_aio_post_event(audio, AUDIO_EVENT_READ_DONE, payload);
421 kfree(buf_node);
422 pr_debug("%s[%p]: Propagate READ_DONE during flush\n",
423 __func__, audio);
424 }
425}
426
427void audio_aio_cb(uint32_t opcode, uint32_t token,
428 uint32_t *payload, struct q6audio_aio *audio)
429{
430 union msm_audio_event_payload e_payload;
431
432 switch (opcode) {
433 case ASM_DATA_EVENT_WRITE_DONE:
434 pr_debug("%s[%p]:ASM_DATA_EVENT_WRITE_DONE token = 0x%x\n",
435 __func__, audio, token);
436 audio_aio_async_write_ack(audio, token, payload);
437 break;
438 case ASM_DATA_EVENT_READ_DONE:
439 pr_debug("%s[%p]:ASM_DATA_EVENT_READ_DONE token = 0x%x\n",
440 __func__, audio, token);
441 audio_aio_async_read_ack(audio, token, payload);
442 break;
443 case ASM_DATA_CMDRSP_EOS:
444 /* EOS Handle */
445 pr_debug("%s[%p]:ASM_DATA_CMDRSP_EOS\n", __func__, audio);
446 if (audio->feedback) { /* Non-Tunnel mode */
447 audio->eos_rsp = 1;
448 /* propagate input EOS i/p buffer,
449 after receiving DSP acknowledgement */
450 if (audio->eos_flag &&
451 (audio->eos_write_payload.aio_buf.buf_addr)) {
452 audio_aio_post_event(audio,
453 AUDIO_EVENT_WRITE_DONE,
454 audio->eos_write_payload);
455 memset(&audio->eos_write_payload , 0,
456 sizeof(union msm_audio_event_payload));
457 audio->eos_flag = 0;
458 }
459 } else { /* Tunnel mode */
460 audio->eos_rsp = 1;
461 wake_up(&audio->write_wait);
462 wake_up(&audio->cmd_wait);
463 }
464 break;
465 case ASM_DATA_CMD_MEDIA_FORMAT_UPDATE:
466 case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
467 pr_debug("%s[%p]:payload0[%x] payloa1d[%x]opcode= 0x%x\n",
468 __func__, audio, payload[0], payload[1], opcode);
469 break;
470 case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
471 case ASM_DATA_EVENT_ENC_SR_CM_NOTIFY:
472 pr_debug("%s[%p]: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, "
473
474 "payload[0]-sr = %d, payload[1]-chl = %d, "
475 "payload[2] = %d, payload[3] = %d\n", __func__,
476 audio, payload[0], payload[1], payload[2],
477 payload[3]);
478 pr_debug("%s[%p]: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, "
479 "sr(prev) = %d, chl(prev) = %d,",
480 __func__, audio, audio->pcm_cfg.sample_rate,
481 audio->pcm_cfg.channel_count);
482 audio->pcm_cfg.sample_rate = payload[0];
483 audio->pcm_cfg.channel_count = payload[1] & 0xFFFF;
484 e_payload.stream_info.chan_info = audio->pcm_cfg.channel_count;
485 e_payload.stream_info.sample_rate = audio->pcm_cfg.sample_rate;
486 audio_aio_post_event(audio, AUDIO_EVENT_STREAM_INFO, e_payload);
487 break;
488 default:
489 break;
490 }
491}
492
493int audio_aio_enable(struct q6audio_aio *audio)
494{
495 /* 2nd arg: 0 -> run immediately
496 3rd arg: 0 -> msw_ts, 4th arg: 0 ->lsw_ts */
497 return q6asm_run(audio->ac, 0x00, 0x00, 0x00);
498}
499
500int audio_aio_disable(struct q6audio_aio *audio)
501{
502 int rc = 0;
503 if (audio->opened) {
504 audio->enabled = 0;
505 audio->opened = 0;
506 pr_debug("%s[%p]: inbytes[%d] insamples[%d]\n", __func__,
507 audio, atomic_read(&audio->in_bytes),
508 atomic_read(&audio->in_samples));
509 /* Close the session */
510 rc = q6asm_cmd(audio->ac, CMD_CLOSE);
511 if (rc < 0)
512 pr_err("%s[%p]:Failed to close the session rc=%d\n",
513 __func__, audio, rc);
514 audio->stopped = 1;
515 wake_up(&audio->write_wait);
516 wake_up(&audio->cmd_wait);
517 }
518 pr_debug("%s[%p]:enabled[%d]\n", __func__, audio, audio->enabled);
519 return rc;
520}
521
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530522void audio_aio_reset_ion_region(struct q6audio_aio *audio)
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530523{
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530524 struct audio_aio_ion_region *region;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530525 struct list_head *ptr, *next;
526
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530527 list_for_each_safe(ptr, next, &audio->ion_region_queue) {
528 region = list_entry(ptr, struct audio_aio_ion_region, list);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530529 list_del(&region->list);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530530 ion_unmap_kernel(region->client, region->handle);
531 ion_free(region->client, region->handle);
532 ion_client_destroy(region->client);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530533 kfree(region);
534 }
535
536 return;
537}
538
539void audio_aio_reset_event_queue(struct q6audio_aio *audio)
540{
541 unsigned long flags;
542 struct audio_aio_event *drv_evt;
543 struct list_head *ptr, *next;
544
545 spin_lock_irqsave(&audio->event_queue_lock, flags);
546 list_for_each_safe(ptr, next, &audio->event_queue) {
547 drv_evt = list_first_entry(&audio->event_queue,
548 struct audio_aio_event, list);
549 list_del(&drv_evt->list);
550 kfree(drv_evt);
551 }
552 list_for_each_safe(ptr, next, &audio->free_event_queue) {
553 drv_evt = list_first_entry(&audio->free_event_queue,
554 struct audio_aio_event, list);
555 list_del(&drv_evt->list);
556 kfree(drv_evt);
557 }
558 spin_unlock_irqrestore(&audio->event_queue_lock, flags);
559
560 return;
561}
562
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530563static void audio_aio_unmap_ion_region(struct q6audio_aio *audio)
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530564{
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530565 struct audio_aio_ion_region *region;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530566 struct list_head *ptr, *next;
567 int rc = -EINVAL;
568
569 pr_debug("%s[%p]:\n", __func__, audio);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530570 list_for_each_safe(ptr, next, &audio->ion_region_queue) {
571 region = list_entry(ptr, struct audio_aio_ion_region, list);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530572 pr_debug("%s[%p]: phy_address = 0x%lx\n",
573 __func__, audio, region->paddr);
574 if (region != NULL) {
575 rc = q6asm_memory_unmap(audio->ac,
576 (uint32_t)region->paddr, IN);
577 if (rc < 0)
578 pr_err("%s[%p]: memory unmap failed\n",
579 __func__, audio);
580 }
581 }
582}
583
584int audio_aio_release(struct inode *inode, struct file *file)
585{
586 struct q6audio_aio *audio = file->private_data;
587 pr_debug("%s[%p]\n", __func__, audio);
588 mutex_lock(&audio->lock);
589 audio->wflush = 1;
590 if (audio->enabled)
591 audio_aio_flush(audio);
592 audio->wflush = 0;
593 audio->drv_ops.out_flush(audio);
594 audio->drv_ops.in_flush(audio);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530595 audio_aio_unmap_ion_region(audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530596 audio_aio_disable(audio);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530597 audio_aio_reset_ion_region(audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530598 audio->event_abort = 1;
599 wake_up(&audio->event_wait);
600 audio_aio_reset_event_queue(audio);
601 q6asm_audio_client_free(audio->ac);
602 mutex_unlock(&audio->lock);
603 mutex_destroy(&audio->lock);
604 mutex_destroy(&audio->read_lock);
605 mutex_destroy(&audio->write_lock);
606 mutex_destroy(&audio->get_event_lock);
607#ifdef CONFIG_DEBUG_FS
608 if (audio->dentry)
609 debugfs_remove(audio->dentry);
610#endif
611 kfree(audio->codec_cfg);
612 kfree(audio);
613 return 0;
614}
615
616int audio_aio_fsync(struct file *file, int datasync)
617{
618 int rc = 0;
619 struct q6audio_aio *audio = file->private_data;
620
621 if (!audio->enabled || audio->feedback)
622 return -EINVAL;
623
624 /* Blocking client sends more data */
625 mutex_lock(&audio->lock);
626 audio->drv_status |= ADRV_STATUS_FSYNC;
627 mutex_unlock(&audio->lock);
628
629 pr_debug("%s[%p]:\n", __func__, audio);
630
631 mutex_lock(&audio->write_lock);
632 audio->eos_rsp = 0;
633
634 rc = wait_event_interruptible(audio->write_wait,
635 (list_empty(&audio->out_queue)) ||
636 audio->wflush || audio->stopped);
637
638 if (rc < 0) {
639 pr_err("%s[%p]: wait event for list_empty failed, rc = %d\n",
640 __func__, audio, rc);
641 goto done;
642 }
643
644 rc = q6asm_cmd(audio->ac, CMD_EOS);
645
646 if (rc < 0)
647 pr_err("%s[%p]: q6asm_cmd failed, rc = %d",
648 __func__, audio, rc);
649
650 rc = wait_event_interruptible(audio->write_wait,
651 (audio->eos_rsp || audio->wflush ||
652 audio->stopped));
653
654 if (rc < 0) {
655 pr_err("%s[%p]: wait event for eos_rsp failed, rc = %d\n",
656 __func__, audio, rc);
657 goto done;
658 }
659
660 if (audio->eos_rsp == 1) {
661 rc = audio_aio_enable(audio);
662 if (rc)
663 pr_err("%s[%p]: audio enable failed\n",
664 __func__, audio);
665 else {
666 audio->drv_status &= ~ADRV_STATUS_PAUSE;
667 audio->enabled = 1;
668 }
669 }
670
671 if (audio->stopped || audio->wflush)
672 rc = -EBUSY;
673
674done:
675 mutex_unlock(&audio->write_lock);
676 mutex_lock(&audio->lock);
677 audio->drv_status &= ~ADRV_STATUS_FSYNC;
678 mutex_unlock(&audio->lock);
679
680 return rc;
681}
682
683static int audio_aio_events_pending(struct q6audio_aio *audio)
684{
685 unsigned long flags;
686 int empty;
687
688 spin_lock_irqsave(&audio->event_queue_lock, flags);
689 empty = !list_empty(&audio->event_queue);
690 spin_unlock_irqrestore(&audio->event_queue_lock, flags);
691 return empty || audio->event_abort;
692}
693
694static long audio_aio_process_event_req(struct q6audio_aio *audio,
695 void __user *arg)
696{
697 long rc;
698 struct msm_audio_event usr_evt;
699 struct audio_aio_event *drv_evt = NULL;
700 int timeout;
701 unsigned long flags;
702
703 if (copy_from_user(&usr_evt, arg, sizeof(struct msm_audio_event)))
704 return -EFAULT;
705
706 timeout = (int)usr_evt.timeout_ms;
707
708 if (timeout > 0) {
709 rc = wait_event_interruptible_timeout(audio->event_wait,
710 audio_aio_events_pending
711 (audio),
712 msecs_to_jiffies
713 (timeout));
714 if (rc == 0)
715 return -ETIMEDOUT;
716 } else {
717 rc = wait_event_interruptible(audio->event_wait,
718 audio_aio_events_pending(audio));
719 }
720 if (rc < 0)
721 return rc;
722
723 if (audio->event_abort) {
724 audio->event_abort = 0;
725 return -ENODEV;
726 }
727
728 rc = 0;
729
730 spin_lock_irqsave(&audio->event_queue_lock, flags);
731 if (!list_empty(&audio->event_queue)) {
732 drv_evt = list_first_entry(&audio->event_queue,
733 struct audio_aio_event, list);
734 list_del(&drv_evt->list);
735 }
736 if (drv_evt) {
737 usr_evt.event_type = drv_evt->event_type;
738 usr_evt.event_payload = drv_evt->payload;
739 list_add_tail(&drv_evt->list, &audio->free_event_queue);
740 } else {
741 pr_err("%s[%p]:Unexpected path\n", __func__, audio);
742 spin_unlock_irqrestore(&audio->event_queue_lock, flags);
743 return -EPERM;
744 }
745 spin_unlock_irqrestore(&audio->event_queue_lock, flags);
746
747 if (drv_evt->event_type == AUDIO_EVENT_WRITE_DONE) {
748 pr_debug("%s[%p]:posted AUDIO_EVENT_WRITE_DONE to user\n",
749 __func__, audio);
750 mutex_lock(&audio->write_lock);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530751 audio_aio_ion_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530752 drv_evt->payload.aio_buf.buf_len, 0, 0);
753 mutex_unlock(&audio->write_lock);
754 } else if (drv_evt->event_type == AUDIO_EVENT_READ_DONE) {
755 pr_debug("%s[%p]:posted AUDIO_EVENT_READ_DONE to user\n",
756 __func__, audio);
757 mutex_lock(&audio->read_lock);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530758 audio_aio_ion_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530759 drv_evt->payload.aio_buf.buf_len, 0, 0);
760 mutex_unlock(&audio->read_lock);
761 }
762
763 /* Some read buffer might be held up in DSP,release all
764 * Once EOS indicated
765 */
766 if (audio->eos_rsp && !list_empty(&audio->in_queue)) {
767 pr_debug("%s[%p]:Send flush command to release read buffers"\
768 " held up in DSP\n", __func__, audio);
769 audio_aio_flush(audio);
770 }
771
772 if (copy_to_user(arg, &usr_evt, sizeof(usr_evt)))
773 rc = -EFAULT;
774
775 return rc;
776}
777
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530778static int audio_aio_ion_check(struct q6audio_aio *audio,
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530779 void *vaddr, unsigned long len)
780{
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530781 struct audio_aio_ion_region *region_elt;
782 struct audio_aio_ion_region t = {.vaddr = vaddr, .len = len };
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530783
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530784 list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530785 if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
786 OVERLAPS(region_elt, &t)) {
787 pr_err("%s[%p]:region (vaddr %p len %ld)"
788 " clashes with registered region"
789 " (vaddr %p paddr %p len %ld)\n",
790 __func__, audio, vaddr, len,
791 region_elt->vaddr,
792 (void *)region_elt->paddr, region_elt->len);
793 return -EINVAL;
794 }
795 }
796
797 return 0;
798}
799
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530800static int audio_aio_ion_add(struct q6audio_aio *audio,
801 struct msm_audio_ion_info *info)
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530802{
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530803 ion_phys_addr_t paddr;
804 size_t len;
805 unsigned long kvaddr;
806 struct audio_aio_ion_region *region;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530807 int rc = -EINVAL;
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530808 struct ion_handle *handle;
809 struct ion_client *client;
810 unsigned long ionflag;
811 void *temp_ptr;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530812
813 pr_debug("%s[%p]:\n", __func__, audio);
814 region = kmalloc(sizeof(*region), GFP_KERNEL);
815
816 if (!region) {
817 rc = -ENOMEM;
818 goto end;
819 }
820
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530821 client = msm_ion_client_create(UINT_MAX, "Audio_Dec_Client");
822 if (IS_ERR_OR_NULL(client)) {
823 pr_err("Unable to create ION client\n");
824 goto client_error;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530825 }
826
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530827 handle = ion_import_fd(client, info->fd);
828 if (IS_ERR_OR_NULL(handle)) {
829 pr_err("%s: could not get handle of the given fd\n", __func__);
830 goto import_error;
831 }
832
833 rc = ion_handle_get_flags(client, handle, &ionflag);
834 if (rc) {
835 pr_err("%s: could not get flags for the handle\n", __func__);
836 goto flag_error;
837 }
838
839 temp_ptr = ion_map_kernel(client, handle, ionflag);
840 if (IS_ERR_OR_NULL(temp_ptr)) {
841 pr_err("%s: could not get virtual address\n", __func__);
842 goto map_error;
843 }
844 kvaddr = (unsigned long)temp_ptr;
845
846 rc = ion_phys(client, handle, &paddr, &len);
847 if (rc) {
848 pr_err("%s: could not get physical address\n", __func__);
849 goto ion_error;
850 }
851
852 rc = audio_aio_ion_check(audio, info->vaddr, len);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530853 if (rc < 0) {
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530854 pr_err("%s: audio_aio_ion_check failed\n", __func__);
855 goto ion_error;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530856 }
857
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530858 region->client = client;
859 region->handle = handle;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530860 region->vaddr = info->vaddr;
861 region->fd = info->fd;
862 region->paddr = paddr;
863 region->kvaddr = kvaddr;
864 region->len = len;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530865 region->ref_cnt = 0;
866 pr_debug("%s[%p]:add region paddr %lx vaddr %p, len %lu kvaddr %lx\n",
867 __func__, audio,
868 region->paddr, region->vaddr, region->len, region->kvaddr);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530869 list_add_tail(&region->list, &audio->ion_region_queue);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530870 rc = q6asm_memory_map(audio->ac, (uint32_t) paddr, IN, (uint32_t) len,
871 1);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530872 if (rc < 0) {
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530873 pr_err("%s[%p]: memory map failed\n", __func__, audio);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530874 goto ion_error;
875 } else {
876 goto end;
877 }
878
879ion_error:
880 ion_unmap_kernel(client, handle);
881map_error:
882 ion_free(client, handle);
883flag_error:
884import_error:
885 ion_client_destroy(client);
886client_error:
887 kfree(region);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530888end:
889 return rc;
890}
891
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530892static int audio_aio_ion_remove(struct q6audio_aio *audio,
893 struct msm_audio_ion_info *info)
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530894{
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530895 struct audio_aio_ion_region *region;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530896 struct list_head *ptr, *next;
897 int rc = -EINVAL;
898
899 pr_debug("%s[%p]:info fd %d vaddr %p\n",
900 __func__, audio, info->fd, info->vaddr);
901
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530902 list_for_each_safe(ptr, next, &audio->ion_region_queue) {
903 region = list_entry(ptr, struct audio_aio_ion_region, list);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530904
905 if ((region->fd == info->fd) &&
906 (region->vaddr == info->vaddr)) {
907 if (region->ref_cnt) {
908 pr_debug("%s[%p]:region %p in use ref_cnt %d\n",
909 __func__, audio, region,
910 region->ref_cnt);
911 break;
912 }
913 pr_debug("%s[%p]:remove region fd %d vaddr %p\n",
914 __func__, audio, info->fd, info->vaddr);
915 rc = q6asm_memory_unmap(audio->ac,
916 (uint32_t) region->paddr, IN);
917 if (rc < 0)
918 pr_err("%s[%p]: memory unmap failed\n",
919 __func__, audio);
920
921 list_del(&region->list);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530922 ion_unmap_kernel(region->client, region->handle);
923 ion_free(region->client, region->handle);
924 ion_client_destroy(region->client);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530925 kfree(region);
926 rc = 0;
927 break;
928 }
929 }
930
931 return rc;
932}
933
934static void audio_aio_async_write(struct q6audio_aio *audio,
935 struct audio_aio_buffer_node *buf_node)
936{
937 int rc;
938 struct audio_client *ac;
939 struct audio_aio_write_param param;
940
941 pr_debug("%s[%p]: Send write buff %p phy %lx len %d"
942 "meta_enable = %d\n",
943 __func__, audio, buf_node, buf_node->paddr,
944 buf_node->buf.data_len,
945 audio->buf_cfg.meta_info_enable);
946
947 ac = audio->ac;
948 /* Offset with appropriate meta */
Karthik Reddy Katta6f09ac92012-04-23 15:04:38 +0530949 if (audio->feedback) {
950 /* Non Tunnel mode */
951 param.paddr = buf_node->paddr + sizeof(struct dec_meta_in);
952 param.len = buf_node->buf.data_len - sizeof(struct dec_meta_in);
953 } else {
954 /* Tunnel mode */
955 param.paddr = buf_node->paddr;
956 param.len = buf_node->buf.data_len;
957 }
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530958 param.msw_ts = buf_node->meta_info.meta_in.ntimestamp.highpart;
959 param.lsw_ts = buf_node->meta_info.meta_in.ntimestamp.lowpart;
960 /* If no meta_info enaled, indicate no time stamp valid */
961 if (audio->buf_cfg.meta_info_enable)
962 param.flags = 0;
963 else
964 param.flags = 0xFF00;
965 param.uid = param.paddr;
966 /* Read command will populate paddr as token */
967 buf_node->token = param.paddr;
968 rc = q6asm_async_write(ac, &param);
969 if (rc < 0)
970 pr_err("%s[%p]:failed\n", __func__, audio);
971}
972
973void audio_aio_post_event(struct q6audio_aio *audio, int type,
974 union msm_audio_event_payload payload)
975{
976 struct audio_aio_event *e_node = NULL;
977 unsigned long flags;
978
979 spin_lock_irqsave(&audio->event_queue_lock, flags);
980
981 if (!list_empty(&audio->free_event_queue)) {
982 e_node = list_first_entry(&audio->free_event_queue,
983 struct audio_aio_event, list);
984 list_del(&e_node->list);
985 } else {
986 e_node = kmalloc(sizeof(struct audio_aio_event), GFP_ATOMIC);
987 if (!e_node) {
988 pr_err("%s[%p]:No mem to post event %d\n",
989 __func__, audio, type);
990 spin_unlock_irqrestore(&audio->event_queue_lock, flags);
991 return;
992 }
993 }
994
995 e_node->event_type = type;
996 e_node->payload = payload;
997
998 list_add_tail(&e_node->list, &audio->event_queue);
999 spin_unlock_irqrestore(&audio->event_queue_lock, flags);
1000 wake_up(&audio->event_wait);
1001}
1002
1003static void audio_aio_async_read(struct q6audio_aio *audio,
1004 struct audio_aio_buffer_node *buf_node)
1005{
1006 struct audio_client *ac;
1007 struct audio_aio_read_param param;
1008 int rc;
1009
1010 pr_debug("%s[%p]: Send read buff %p phy %lx len %d\n",
1011 __func__, audio, buf_node,
1012 buf_node->paddr, buf_node->buf.buf_len);
1013 ac = audio->ac;
1014 /* Provide address so driver can append nr frames information */
1015 param.paddr = buf_node->paddr +
1016 sizeof(struct dec_meta_out);
1017 param.len = buf_node->buf.buf_len -
1018 sizeof(struct dec_meta_out);
1019 param.uid = param.paddr;
1020 /* Write command will populate paddr as token */
1021 buf_node->token = param.paddr;
1022 rc = q6asm_async_read(ac, &param);
1023 if (rc < 0)
1024 pr_err("%s[%p]:failed\n", __func__, audio);
1025}
1026
1027static int audio_aio_buf_add(struct q6audio_aio *audio, unsigned dir,
1028 void __user *arg)
1029{
1030 unsigned long flags;
1031 struct audio_aio_buffer_node *buf_node;
1032
1033
1034 buf_node = kzalloc(sizeof(*buf_node), GFP_KERNEL);
1035
1036 if (!buf_node)
1037 return -ENOMEM;
1038
1039 if (copy_from_user(&buf_node->buf, arg, sizeof(buf_node->buf))) {
1040 kfree(buf_node);
1041 return -EFAULT;
1042 }
1043
1044 pr_debug("%s[%p]:node %p dir %x buf_addr %p buf_len %d data_len \
1045 %d\n", __func__, audio, buf_node, dir, buf_node->buf.buf_addr,
1046 buf_node->buf.buf_len, buf_node->buf.data_len);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +05301047 buf_node->paddr = audio_aio_ion_fixup(audio, buf_node->buf.buf_addr,
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301048 buf_node->buf.buf_len, 1,
1049 &buf_node->kvaddr);
1050 if (dir) {
1051 /* write */
1052 if (!buf_node->paddr ||
1053 (buf_node->paddr & 0x1) ||
1054 (!audio->feedback && !buf_node->buf.data_len)) {
1055 kfree(buf_node);
1056 return -EINVAL;
1057 }
1058 extract_meta_out_info(audio, buf_node, 1);
1059 /* Not a EOS buffer */
1060 if (!(buf_node->meta_info.meta_in.nflags & AUDIO_DEC_EOS_SET)) {
1061 spin_lock_irqsave(&audio->dsp_lock, flags);
1062 audio_aio_async_write(audio, buf_node);
1063 /* EOS buffer handled in driver */
1064 list_add_tail(&buf_node->list, &audio->out_queue);
1065 spin_unlock_irqrestore(&audio->dsp_lock, flags);
Preetam Singh Ranawat6aae2412011-11-04 18:16:27 +05301066 } else if (buf_node->meta_info.meta_in.nflags
1067 & AUDIO_DEC_EOS_SET) {
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301068 if (!audio->wflush) {
1069 pr_debug("%s[%p]:Send EOS cmd at i/p\n",
1070 __func__, audio);
1071 /* Driver will forcefully post writedone event
1072 * once eos ack recived from DSP
1073 */
1074 audio->eos_write_payload.aio_buf =\
1075 buf_node->buf;
1076 audio->eos_flag = 1;
1077 audio->eos_rsp = 0;
1078 q6asm_cmd(audio->ac, CMD_EOS);
1079 kfree(buf_node);
1080 } else { /* Flush in progress, send back i/p
1081 * EOS buffer as is
1082 */
1083 union msm_audio_event_payload event_payload;
1084 event_payload.aio_buf = buf_node->buf;
1085 audio_aio_post_event(audio,
1086 AUDIO_EVENT_WRITE_DONE,
1087 event_payload);
1088 kfree(buf_node);
1089 }
1090 }
1091 } else {
1092 /* read */
1093 if (!buf_node->paddr ||
1094 (buf_node->paddr & 0x1) ||
1095 (buf_node->buf.buf_len < PCM_BUFSZ_MIN)) {
1096 kfree(buf_node);
1097 return -EINVAL;
1098 }
1099 /* No EOS reached */
1100 if (!audio->eos_rsp) {
1101 spin_lock_irqsave(&audio->dsp_lock, flags);
1102 audio_aio_async_read(audio, buf_node);
1103 /* EOS buffer handled in driver */
1104 list_add_tail(&buf_node->list, &audio->in_queue);
1105 spin_unlock_irqrestore(&audio->dsp_lock, flags);
1106 }
1107 /* EOS reached at input side fake all upcoming read buffer to
1108 * indicate the same
1109 */
1110 else {
1111 union msm_audio_event_payload event_payload;
1112 event_payload.aio_buf = buf_node->buf;
1113 event_payload.aio_buf.data_len =
1114 insert_eos_buf(audio, buf_node);
1115 pr_debug("%s[%p]: propagate READ_DONE as EOS done\n",\
1116 __func__, audio);
1117 audio_aio_post_event(audio, AUDIO_EVENT_READ_DONE,
1118 event_payload);
1119 kfree(buf_node);
1120 }
1121 }
1122 return 0;
1123}
1124
1125static void audio_aio_ioport_reset(struct q6audio_aio *audio)
1126{
1127 if (audio->drv_status & ADRV_STATUS_AIO_INTF) {
1128 /* If fsync is in progress, make sure
1129 * return value of fsync indicates
1130 * abort due to flush
1131 */
1132 if (audio->drv_status & ADRV_STATUS_FSYNC) {
1133 pr_debug("%s[%p]:fsync in progress\n", __func__, audio);
1134 audio->drv_ops.out_flush(audio);
1135 } else
1136 audio->drv_ops.out_flush(audio);
1137 audio->drv_ops.in_flush(audio);
1138 }
1139}
1140
1141int audio_aio_open(struct q6audio_aio *audio, struct file *file)
1142{
1143 int rc = 0;
1144 int i;
1145 struct audio_aio_event *e_node = NULL;
1146
1147 /* Settings will be re-config at AUDIO_SET_CONFIG,
1148 * but at least we need to have initial config
1149 */
1150 audio->str_cfg.buffer_size = FRAME_SIZE;
1151 audio->str_cfg.buffer_count = FRAME_NUM;
1152 audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
1153 audio->pcm_cfg.sample_rate = 48000;
1154 audio->pcm_cfg.channel_count = 2;
1155
1156 /* Only AIO interface */
1157 if (file->f_flags & O_NONBLOCK) {
1158 pr_debug("%s[%p]:set to aio interface\n", __func__, audio);
1159 audio->drv_status |= ADRV_STATUS_AIO_INTF;
1160 audio->drv_ops.out_flush = audio_aio_async_out_flush;
1161 audio->drv_ops.in_flush = audio_aio_async_in_flush;
1162 q6asm_set_io_mode(audio->ac, ASYNC_IO_MODE);
1163 } else {
1164 pr_err("%s[%p]:SIO interface not supported\n",
1165 __func__, audio);
1166 rc = -EACCES;
1167 goto fail;
1168 }
1169
1170 /* Initialize all locks of audio instance */
1171 mutex_init(&audio->lock);
1172 mutex_init(&audio->read_lock);
1173 mutex_init(&audio->write_lock);
1174 mutex_init(&audio->get_event_lock);
1175 spin_lock_init(&audio->dsp_lock);
1176 spin_lock_init(&audio->event_queue_lock);
1177 init_waitqueue_head(&audio->cmd_wait);
1178 init_waitqueue_head(&audio->write_wait);
1179 init_waitqueue_head(&audio->event_wait);
1180 INIT_LIST_HEAD(&audio->out_queue);
1181 INIT_LIST_HEAD(&audio->in_queue);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +05301182 INIT_LIST_HEAD(&audio->ion_region_queue);
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301183 INIT_LIST_HEAD(&audio->free_event_queue);
1184 INIT_LIST_HEAD(&audio->event_queue);
1185
1186 audio->drv_ops.out_flush(audio);
1187 audio->opened = 1;
1188 file->private_data = audio;
1189 audio->codec_ioctl = audio_aio_ioctl;
1190
Mingming Yinc09967e2012-04-27 15:09:43 -07001191 for (i = 0; i < AUDIO_EVENT_NUM; i++) {
1192 e_node = kmalloc(sizeof(struct audio_aio_event), GFP_KERNEL);
1193 if (e_node)
1194 list_add_tail(&e_node->list, &audio->free_event_queue);
1195 else {
1196 pr_err("%s[%p]:event pkt alloc failed\n",
1197 __func__, audio);
1198 break;
1199 }
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301200 }
Mingming Yinc09967e2012-04-27 15:09:43 -07001201 return 0;
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301202fail:
Mingming Yinc09967e2012-04-27 15:09:43 -07001203 q6asm_audio_client_free(audio->ac);
1204 kfree(audio->codec_cfg);
1205 kfree(audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301206 return rc;
1207}
1208
1209long audio_aio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
1210{
1211 struct q6audio_aio *audio = file->private_data;
1212 int rc = 0;
1213
1214 switch (cmd) {
1215 case AUDIO_GET_STATS: {
1216 struct msm_audio_stats stats;
1217 stats.byte_count = atomic_read(&audio->in_bytes);
1218 stats.sample_count = atomic_read(&audio->in_samples);
1219 if (copy_to_user((void *)arg, &stats, sizeof(stats)))
1220 rc = -EFAULT;
1221 break;
1222 }
1223 case AUDIO_GET_EVENT: {
1224 pr_debug("%s[%p]:AUDIO_GET_EVENT\n", __func__, audio);
1225 if (mutex_trylock(&audio->get_event_lock)) {
1226 rc = audio_aio_process_event_req(audio,
1227 (void __user *)arg);
1228 mutex_unlock(&audio->get_event_lock);
1229 } else
1230 rc = -EBUSY;
1231 break;
1232 }
1233 case AUDIO_ABORT_GET_EVENT: {
1234 audio->event_abort = 1;
1235 wake_up(&audio->event_wait);
1236 break;
1237 }
1238 case AUDIO_ASYNC_WRITE: {
1239 mutex_lock(&audio->write_lock);
1240 if (audio->drv_status & ADRV_STATUS_FSYNC)
1241 rc = -EBUSY;
1242 else {
1243 if (audio->enabled)
1244 rc = audio_aio_buf_add(audio, 1,
1245 (void __user *)arg);
1246 else
1247 rc = -EPERM;
1248 }
1249 mutex_unlock(&audio->write_lock);
1250 break;
1251 }
1252 case AUDIO_ASYNC_READ: {
1253 mutex_lock(&audio->read_lock);
1254 if ((audio->feedback) && (audio->enabled))
1255 rc = audio_aio_buf_add(audio, 0,
1256 (void __user *)arg);
1257 else
1258 rc = -EPERM;
1259 mutex_unlock(&audio->read_lock);
1260 break;
1261 }
1262 case AUDIO_OUTPORT_FLUSH: {
1263 pr_debug("%s[%p]:AUDIO_OUTPORT_FLUSH\n", __func__, audio);
1264 mutex_lock(&audio->read_lock);
1265 rc = audio_aio_outport_flush(audio);
1266 if (rc < 0) {
1267 pr_err("%s[%p]: AUDIO_OUTPORT_FLUSH failed\n",
1268 __func__, audio);
1269 rc = -EINTR;
1270 }
1271 mutex_unlock(&audio->read_lock);
1272 break;
1273 }
1274 case AUDIO_STOP: {
1275 pr_debug("%s[%p]: AUDIO_STOP session_id[%d]\n", __func__,
1276 audio, audio->ac->session);
1277 mutex_lock(&audio->lock);
1278 audio->stopped = 1;
1279 audio_aio_flush(audio);
1280 audio->enabled = 0;
1281 audio->drv_status &= ~ADRV_STATUS_PAUSE;
1282 if (rc < 0) {
1283 pr_err("%s[%p]:Audio Stop procedure failed rc=%d\n",
1284 __func__, audio, rc);
1285 mutex_unlock(&audio->lock);
1286 break;
1287 }
1288 mutex_unlock(&audio->lock);
1289 break;
1290 }
1291 case AUDIO_PAUSE: {
1292 pr_debug("%s[%p]:AUDIO_PAUSE %ld\n", __func__, audio, arg);
1293 mutex_lock(&audio->lock);
1294 if (arg == 1) {
1295 rc = audio_aio_pause(audio);
1296 if (rc < 0)
1297 pr_err("%s[%p]: pause FAILED rc=%d\n",
1298 __func__, audio, rc);
1299 audio->drv_status |= ADRV_STATUS_PAUSE;
1300 } else if (arg == 0) {
1301 if (audio->drv_status & ADRV_STATUS_PAUSE) {
1302 rc = audio_aio_enable(audio);
1303 if (rc)
1304 pr_err("%s[%p]: audio enable failed\n",
1305 __func__, audio);
1306 else {
1307 audio->drv_status &= ~ADRV_STATUS_PAUSE;
1308 audio->enabled = 1;
1309 }
1310 }
1311 }
1312 mutex_unlock(&audio->lock);
1313 break;
1314 }
1315 case AUDIO_FLUSH: {
1316 pr_debug("%s[%p]: AUDIO_FLUSH sessionid[%d]\n", __func__,
1317 audio, audio->ac->session);
1318 mutex_lock(&audio->lock);
1319 audio->rflush = 1;
1320 audio->wflush = 1;
1321 /* Flush DSP */
1322 rc = audio_aio_flush(audio);
1323 /* Flush input / Output buffer in software*/
1324 audio_aio_ioport_reset(audio);
1325 if (rc < 0) {
1326 pr_err("%s[%p]:AUDIO_FLUSH interrupted\n",
1327 __func__, audio);
1328 rc = -EINTR;
1329 } else {
1330 audio->rflush = 0;
1331 audio->wflush = 0;
1332 }
1333 audio->eos_flag = 0;
1334 audio->eos_rsp = 0;
1335 mutex_unlock(&audio->lock);
1336 break;
1337 }
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +05301338 case AUDIO_REGISTER_ION: {
1339 struct msm_audio_ion_info info;
1340 pr_debug("%s[%p]:AUDIO_REGISTER_ION\n", __func__, audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301341 mutex_lock(&audio->lock);
1342 if (copy_from_user(&info, (void *)arg, sizeof(info)))
1343 rc = -EFAULT;
1344 else
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +05301345 rc = audio_aio_ion_add(audio, &info);
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301346 mutex_unlock(&audio->lock);
1347 break;
1348 }
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +05301349 case AUDIO_DEREGISTER_ION: {
1350 struct msm_audio_ion_info info;
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301351 mutex_lock(&audio->lock);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +05301352 pr_debug("%s[%p]:AUDIO_DEREGISTER_ION\n", __func__, audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301353 if (copy_from_user(&info, (void *)arg, sizeof(info)))
1354 rc = -EFAULT;
1355 else
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +05301356 rc = audio_aio_ion_remove(audio, &info);
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301357 mutex_unlock(&audio->lock);
1358 break;
1359 }
1360 case AUDIO_GET_STREAM_CONFIG: {
1361 struct msm_audio_stream_config cfg;
1362 mutex_lock(&audio->lock);
1363 memset(&cfg, 0, sizeof(cfg));
1364 cfg.buffer_size = audio->str_cfg.buffer_size;
1365 cfg.buffer_count = audio->str_cfg.buffer_count;
1366 pr_debug("%s[%p]:GET STREAM CFG %d %d\n",
1367 __func__, audio, cfg.buffer_size, cfg.buffer_count);
1368 if (copy_to_user((void *)arg, &cfg, sizeof(cfg)))
1369 rc = -EFAULT;
1370 mutex_unlock(&audio->lock);
1371 break;
1372 }
1373 case AUDIO_SET_STREAM_CONFIG: {
1374 struct msm_audio_stream_config cfg;
1375 pr_debug("%s[%p]:SET STREAM CONFIG\n", __func__, audio);
1376 mutex_lock(&audio->lock);
1377 if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
1378 rc = -EFAULT;
1379 mutex_unlock(&audio->lock);
1380 break;
1381 }
1382 audio->str_cfg.buffer_size = FRAME_SIZE;
1383 audio->str_cfg.buffer_count = FRAME_NUM;
1384 rc = 0;
1385 mutex_unlock(&audio->lock);
1386 break;
1387 }
1388 case AUDIO_GET_CONFIG: {
1389 struct msm_audio_config cfg;
1390 mutex_lock(&audio->lock);
1391 if (copy_to_user((void *)arg, &audio->pcm_cfg, sizeof(cfg)))
1392 rc = -EFAULT;
1393 mutex_unlock(&audio->lock);
1394 break;
1395 }
1396 case AUDIO_SET_CONFIG: {
1397 struct msm_audio_config config;
1398 pr_err("%s[%p]:AUDIO_SET_CONFIG\n", __func__, audio);
1399 mutex_lock(&audio->lock);
1400 if (copy_from_user(&config, (void *)arg, sizeof(config))) {
1401 rc = -EFAULT;
1402 mutex_unlock(&audio->lock);
1403 break;
1404 }
1405 if (audio->feedback != NON_TUNNEL_MODE) {
1406 pr_err("%s[%p]:Not sufficient permission to"
1407 "change the playback mode\n", __func__, audio);
1408 rc = -EACCES;
1409 mutex_unlock(&audio->lock);
1410 break;
1411 }
1412 if ((config.buffer_count > PCM_BUF_COUNT) ||
1413 (config.buffer_count == 1))
1414 config.buffer_count = PCM_BUF_COUNT;
1415
1416 if (config.buffer_size < PCM_BUFSZ_MIN)
1417 config.buffer_size = PCM_BUFSZ_MIN;
1418
1419 audio->pcm_cfg.buffer_count = config.buffer_count;
1420 audio->pcm_cfg.buffer_size = config.buffer_size;
1421 audio->pcm_cfg.channel_count = config.channel_count;
1422 audio->pcm_cfg.sample_rate = config.sample_rate;
1423 rc = 0;
1424 mutex_unlock(&audio->lock);
1425 break;
1426 }
1427 case AUDIO_SET_BUF_CFG: {
1428 struct msm_audio_buf_cfg cfg;
1429 mutex_lock(&audio->lock);
1430 if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
1431 rc = -EFAULT;
1432 mutex_unlock(&audio->lock);
1433 break;
1434 }
1435 if ((audio->feedback == NON_TUNNEL_MODE) &&
1436 !cfg.meta_info_enable) {
1437 rc = -EFAULT;
1438 mutex_unlock(&audio->lock);
1439 break;
1440 }
1441
1442 audio->buf_cfg.meta_info_enable = cfg.meta_info_enable;
1443 pr_debug("%s[%p]:session id %d: Set-buf-cfg: meta[%d]",
1444 __func__, audio,
1445 audio->ac->session, cfg.meta_info_enable);
1446 mutex_unlock(&audio->lock);
1447 break;
1448 }
1449 case AUDIO_GET_BUF_CFG: {
1450 pr_debug("%s[%p]:session id %d: Get-buf-cfg: meta[%d]\
1451 framesperbuf[%d]\n", __func__, audio,
1452 audio->ac->session, audio->buf_cfg.meta_info_enable,
1453 audio->buf_cfg.frames_per_buf);
1454
1455 mutex_lock(&audio->lock);
1456 if (copy_to_user((void *)arg, &audio->buf_cfg,
1457 sizeof(struct msm_audio_buf_cfg)))
1458 rc = -EFAULT;
1459 mutex_unlock(&audio->lock);
1460 break;
1461 }
1462 case AUDIO_GET_SESSION_ID: {
1463 mutex_lock(&audio->lock);
1464 if (copy_to_user((void *)arg, &audio->ac->session,
1465 sizeof(unsigned short))) {
1466 rc = -EFAULT;
1467 }
1468 mutex_unlock(&audio->lock);
1469 break;
1470 }
1471 default:
1472 rc = -EINVAL;
1473 }
1474 return rc;
1475}