blob: 28bf5c6bb5279e27ff7331d7e38977917c5039da [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>
Phani Kumar Uppalapati784ff992012-08-29 14:26:18 -070024#include <linux/atomic.h>
Deepa Madiregama55cbf782011-09-10 05:44:39 +053025#include <asm/ioctls.h>
Deepa Madiregama55cbf782011-09-10 05:44:39 +053026#include <linux/debugfs.h>
27#include "audio_utils_aio.h"
28
29#ifdef CONFIG_DEBUG_FS
30ssize_t audio_aio_debug_open(struct inode *inode, struct file *file)
31{
32 file->private_data = inode->i_private;
33 return 0;
34}
35
Harmandeep Singheaf59b42012-06-05 21:46:02 -070036ssize_t audio_aio_debug_read(struct file *file, char __user *buf,
Deepa Madiregama55cbf782011-09-10 05:44:39 +053037 size_t count, loff_t *ppos)
38{
39 const int debug_bufmax = 4096;
40 static char buffer[4096];
41 int n = 0;
42 struct q6audio_aio *audio = file->private_data;
43
44 mutex_lock(&audio->lock);
45 n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
46 n += scnprintf(buffer + n, debug_bufmax - n,
47 "enabled %d\n", audio->enabled);
48 n += scnprintf(buffer + n, debug_bufmax - n,
49 "stopped %d\n", audio->stopped);
50 n += scnprintf(buffer + n, debug_bufmax - n,
51 "feedback %d\n", audio->feedback);
52 mutex_unlock(&audio->lock);
53 /* Following variables are only useful for debugging when
54 * when playback halts unexpectedly. Thus, no mutual exclusion
55 * enforced
56 */
57 n += scnprintf(buffer + n, debug_bufmax - n,
58 "wflush %d\n", audio->wflush);
59 n += scnprintf(buffer + n, debug_bufmax - n,
60 "rflush %d\n", audio->rflush);
61 n += scnprintf(buffer + n, debug_bufmax - n,
62 "inqueue empty %d\n", list_empty(&audio->in_queue));
63 n += scnprintf(buffer + n, debug_bufmax - n,
64 "outqueue empty %d\n", list_empty(&audio->out_queue));
65 buffer[n] = 0;
66 return simple_read_from_buffer(buf, count, ppos, buffer, n);
67}
68#endif
69
Harmandeep Singheaf59b42012-06-05 21:46:02 -070070int insert_eos_buf(struct q6audio_aio *audio,
Deepa Madiregama55cbf782011-09-10 05:44:39 +053071 struct audio_aio_buffer_node *buf_node)
72{
73 struct dec_meta_out *eos_buf = buf_node->kvaddr;
74 pr_debug("%s[%p]:insert_eos_buf\n", __func__, audio);
75 eos_buf->num_of_frames = 0xFFFFFFFF;
76 eos_buf->meta_out_dsp[0].offset_to_frame = 0x0;
77 eos_buf->meta_out_dsp[0].nflags = AUDIO_DEC_EOS_SET;
78 return sizeof(struct dec_meta_out) +
79 sizeof(eos_buf->meta_out_dsp[0]);
80}
81
82/* Routine which updates read buffers of driver/dsp,
83 for flush operation as DSP output might not have proper
84 value set */
85static int insert_meta_data_flush(struct q6audio_aio *audio,
86 struct audio_aio_buffer_node *buf_node)
87{
88 struct dec_meta_out *meta_data = buf_node->kvaddr;
89 meta_data->num_of_frames = 0x0;
90 meta_data->meta_out_dsp[0].offset_to_frame = 0x0;
91 meta_data->meta_out_dsp[0].nflags = 0x0;
92 return sizeof(struct dec_meta_out) +
93 sizeof(meta_data->meta_out_dsp[0]);
94}
95
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +053096static int audio_aio_ion_lookup_vaddr(struct q6audio_aio *audio, void *addr,
Deepa Madiregama55cbf782011-09-10 05:44:39 +053097 unsigned long len,
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +053098 struct audio_aio_ion_region **region)
Deepa Madiregama55cbf782011-09-10 05:44:39 +053099{
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530100 struct audio_aio_ion_region *region_elt;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530101
102 int match_count = 0;
103
104 *region = NULL;
105
106 /* returns physical address or zero */
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530107 list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530108 if (addr >= region_elt->vaddr &&
109 addr < region_elt->vaddr + region_elt->len &&
110 addr + len <= region_elt->vaddr + region_elt->len) {
111 /* offset since we could pass vaddr inside a registerd
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530112 * ion buffer
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530113 */
114
115 match_count++;
116 if (!*region)
117 *region = region_elt;
118 }
119 }
120
121 if (match_count > 1) {
122 pr_err("%s[%p]:multiple hits for vaddr %p, len %ld\n",
123 __func__, audio, addr, len);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530124 list_for_each_entry(region_elt, &audio->ion_region_queue,
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530125 list) {
126 if (addr >= region_elt->vaddr &&
127 addr < region_elt->vaddr + region_elt->len &&
128 addr + len <= region_elt->vaddr + region_elt->len)
129 pr_err("\t%s[%p]:%p, %ld --> %p\n",
130 __func__, audio,
131 region_elt->vaddr,
132 region_elt->len,
133 (void *)region_elt->paddr);
134 }
135 }
136
137 return *region ? 0 : -1;
138}
139
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530140static unsigned long audio_aio_ion_fixup(struct q6audio_aio *audio, void *addr,
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530141 unsigned long len, int ref_up, void **kvaddr)
142{
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530143 struct audio_aio_ion_region *region;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530144 unsigned long paddr;
145 int ret;
146
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530147 ret = audio_aio_ion_lookup_vaddr(audio, addr, len, &region);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530148 if (ret) {
149 pr_err("%s[%p]:lookup (%p, %ld) failed\n",
150 __func__, audio, addr, len);
151 return 0;
152 }
153 if (ref_up)
154 region->ref_cnt++;
155 else
156 region->ref_cnt--;
157 pr_debug("%s[%p]:found region %p ref_cnt %d\n",
158 __func__, audio, region, region->ref_cnt);
159 paddr = region->paddr + (addr - region->vaddr);
160 /* provide kernel virtual address for accessing meta information */
161 if (kvaddr)
162 *kvaddr = (void *) (region->kvaddr + (addr - region->vaddr));
163 return paddr;
164}
165
166static int audio_aio_pause(struct q6audio_aio *audio)
167{
Laxminath Kasam92ad28c2012-09-03 13:47:33 +0530168 int rc = -EINVAL;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530169
170 pr_debug("%s[%p], enabled = %d\n", __func__, audio,
171 audio->enabled);
172 if (audio->enabled) {
173 rc = q6asm_cmd(audio->ac, CMD_PAUSE);
174 if (rc < 0)
175 pr_err("%s[%p]: pause cmd failed rc=%d\n",
176 __func__, audio, rc);
177
178 } else
179 pr_err("%s[%p]: Driver not enabled\n", __func__, audio);
180 return rc;
181}
182
183static int audio_aio_flush(struct q6audio_aio *audio)
184{
185 int rc;
186
187 if (audio->enabled) {
188 /* Implicitly issue a pause to the decoder before flushing if
189 it is not in pause state */
190 if (!(audio->drv_status & ADRV_STATUS_PAUSE)) {
191 rc = audio_aio_pause(audio);
192 if (rc < 0)
193 pr_err("%s[%p}: pause cmd failed rc=%d\n",
194 __func__, audio,
195 rc);
196 else
197 audio->drv_status |= ADRV_STATUS_PAUSE;
198 }
199 rc = q6asm_cmd(audio->ac, CMD_FLUSH);
200 if (rc < 0)
201 pr_err("%s[%p]: flush cmd failed rc=%d\n",
202 __func__, audio, rc);
203 /* Not in stop state, reenable the stream */
204 if (audio->stopped == 0) {
205 rc = audio_aio_enable(audio);
206 if (rc)
207 pr_err("%s[%p]:audio re-enable failed\n",
208 __func__, audio);
209 else {
210 audio->enabled = 1;
211 if (audio->drv_status & ADRV_STATUS_PAUSE)
212 audio->drv_status &= ~ADRV_STATUS_PAUSE;
213 }
214 }
215 }
216 pr_debug("%s[%p]:in_bytes %d\n",
217 __func__, audio, atomic_read(&audio->in_bytes));
218 pr_debug("%s[%p]:in_samples %d\n",
219 __func__, audio, atomic_read(&audio->in_samples));
220 atomic_set(&audio->in_bytes, 0);
221 atomic_set(&audio->in_samples, 0);
222 return 0;
223}
224
225static int audio_aio_outport_flush(struct q6audio_aio *audio)
226{
227 int rc;
228
229 rc = q6asm_cmd(audio->ac, CMD_OUT_FLUSH);
230 if (rc < 0)
231 pr_err("%s[%p}: output port flush cmd failed rc=%d\n",
232 __func__, audio, rc);
233 return rc;
234}
235
236/* Write buffer to DSP / Handle Ack from DSP */
237void audio_aio_async_write_ack(struct q6audio_aio *audio, uint32_t token,
238 uint32_t *payload)
239{
240 unsigned long flags;
241 union msm_audio_event_payload event_payload;
242 struct audio_aio_buffer_node *used_buf;
243
244 /* No active flush in progress */
245 if (audio->wflush)
246 return;
247
248 spin_lock_irqsave(&audio->dsp_lock, flags);
249 BUG_ON(list_empty(&audio->out_queue));
250 used_buf = list_first_entry(&audio->out_queue,
251 struct audio_aio_buffer_node, list);
252 if (token == used_buf->token) {
253 list_del(&used_buf->list);
254 spin_unlock_irqrestore(&audio->dsp_lock, flags);
255 pr_debug("%s[%p]:consumed buffer\n", __func__, audio);
256 event_payload.aio_buf = used_buf->buf;
257 audio_aio_post_event(audio, AUDIO_EVENT_WRITE_DONE,
258 event_payload);
259 kfree(used_buf);
260 if (list_empty(&audio->out_queue) &&
261 (audio->drv_status & ADRV_STATUS_FSYNC)) {
Harmandeep Singheaf59b42012-06-05 21:46:02 -0700262 pr_debug("%s[%p]: list is empty, reached EOS in Tunnel\n",
263 __func__, audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530264 wake_up(&audio->write_wait);
265 }
266 } else {
267 pr_err("%s[%p]:expected=%lx ret=%x\n",
268 __func__, audio, used_buf->token, token);
269 spin_unlock_irqrestore(&audio->dsp_lock, flags);
270 }
271}
272
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530273/* ------------------- device --------------------- */
274void audio_aio_async_out_flush(struct q6audio_aio *audio)
275{
276 struct audio_aio_buffer_node *buf_node;
277 struct list_head *ptr, *next;
278 union msm_audio_event_payload payload;
279 unsigned long flags;
280
281 pr_debug("%s[%p}\n", __func__, audio);
282 /* EOS followed by flush, EOS response not guranteed, free EOS i/p
283 buffer */
284 spin_lock_irqsave(&audio->dsp_lock, flags);
285
286 if (audio->eos_flag && (audio->eos_write_payload.aio_buf.buf_addr)) {
287 pr_debug("%s[%p]: EOS followed by flush received,acknowledge"\
288 " eos i/p buffer immediately\n", __func__, audio);
289 audio_aio_post_event(audio, AUDIO_EVENT_WRITE_DONE,
290 audio->eos_write_payload);
291 memset(&audio->eos_write_payload , 0,
292 sizeof(union msm_audio_event_payload));
293 }
294 spin_unlock_irqrestore(&audio->dsp_lock, flags);
295 list_for_each_safe(ptr, next, &audio->out_queue) {
296 buf_node = list_entry(ptr, struct audio_aio_buffer_node, list);
297 list_del(&buf_node->list);
298 payload.aio_buf = buf_node->buf;
299 audio_aio_post_event(audio, AUDIO_EVENT_WRITE_DONE, payload);
300 kfree(buf_node);
301 pr_debug("%s[%p]: Propagate WRITE_DONE during flush\n",
302 __func__, audio);
303 }
304}
305
306void audio_aio_async_in_flush(struct q6audio_aio *audio)
307{
308 struct audio_aio_buffer_node *buf_node;
309 struct list_head *ptr, *next;
310 union msm_audio_event_payload payload;
311
312 pr_debug("%s[%p]\n", __func__, audio);
313 list_for_each_safe(ptr, next, &audio->in_queue) {
314 buf_node = list_entry(ptr, struct audio_aio_buffer_node, list);
315 list_del(&buf_node->list);
316 /* Forcefull send o/p eos buffer after flush, if no eos response
317 * received by dsp even after sending eos command */
318 if ((audio->eos_rsp != 1) && audio->eos_flag) {
Harmandeep Singheaf59b42012-06-05 21:46:02 -0700319 pr_debug("%s[%p]: send eos on o/p buffer during flush\n",
320 __func__, audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530321 payload.aio_buf = buf_node->buf;
322 payload.aio_buf.data_len =
323 insert_eos_buf(audio, buf_node);
324 audio->eos_flag = 0;
325 } else {
326 payload.aio_buf = buf_node->buf;
327 payload.aio_buf.data_len =
328 insert_meta_data_flush(audio, buf_node);
329 }
330 audio_aio_post_event(audio, AUDIO_EVENT_READ_DONE, payload);
331 kfree(buf_node);
332 pr_debug("%s[%p]: Propagate READ_DONE during flush\n",
333 __func__, audio);
334 }
335}
336
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530337int audio_aio_enable(struct q6audio_aio *audio)
338{
339 /* 2nd arg: 0 -> run immediately
340 3rd arg: 0 -> msw_ts, 4th arg: 0 ->lsw_ts */
341 return q6asm_run(audio->ac, 0x00, 0x00, 0x00);
342}
343
344int audio_aio_disable(struct q6audio_aio *audio)
345{
346 int rc = 0;
347 if (audio->opened) {
348 audio->enabled = 0;
349 audio->opened = 0;
350 pr_debug("%s[%p]: inbytes[%d] insamples[%d]\n", __func__,
351 audio, atomic_read(&audio->in_bytes),
352 atomic_read(&audio->in_samples));
353 /* Close the session */
354 rc = q6asm_cmd(audio->ac, CMD_CLOSE);
355 if (rc < 0)
356 pr_err("%s[%p]:Failed to close the session rc=%d\n",
357 __func__, audio, rc);
358 audio->stopped = 1;
359 wake_up(&audio->write_wait);
360 wake_up(&audio->cmd_wait);
361 }
362 pr_debug("%s[%p]:enabled[%d]\n", __func__, audio, audio->enabled);
363 return rc;
364}
365
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530366void audio_aio_reset_ion_region(struct q6audio_aio *audio)
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530367{
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530368 struct audio_aio_ion_region *region;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530369 struct list_head *ptr, *next;
370
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530371 list_for_each_safe(ptr, next, &audio->ion_region_queue) {
372 region = list_entry(ptr, struct audio_aio_ion_region, list);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530373 list_del(&region->list);
Deepa Madiregamaa4795072012-06-15 22:35:52 +0530374 ion_unmap_kernel(audio->client, region->handle);
375 ion_free(audio->client, region->handle);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530376 kfree(region);
377 }
378
379 return;
380}
381
382void audio_aio_reset_event_queue(struct q6audio_aio *audio)
383{
384 unsigned long flags;
385 struct audio_aio_event *drv_evt;
386 struct list_head *ptr, *next;
387
388 spin_lock_irqsave(&audio->event_queue_lock, flags);
389 list_for_each_safe(ptr, next, &audio->event_queue) {
390 drv_evt = list_first_entry(&audio->event_queue,
391 struct audio_aio_event, list);
392 list_del(&drv_evt->list);
393 kfree(drv_evt);
394 }
395 list_for_each_safe(ptr, next, &audio->free_event_queue) {
396 drv_evt = list_first_entry(&audio->free_event_queue,
397 struct audio_aio_event, list);
398 list_del(&drv_evt->list);
399 kfree(drv_evt);
400 }
401 spin_unlock_irqrestore(&audio->event_queue_lock, flags);
402
403 return;
404}
405
Deepa Madiregama14e9e762012-08-29 12:27:41 +0530406void audio_aio_unmap_ion_region(struct q6audio_aio *audio)
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530407{
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530408 struct audio_aio_ion_region *region;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530409 struct list_head *ptr, *next;
410 int rc = -EINVAL;
411
412 pr_debug("%s[%p]:\n", __func__, audio);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530413 list_for_each_safe(ptr, next, &audio->ion_region_queue) {
414 region = list_entry(ptr, struct audio_aio_ion_region, list);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530415 pr_debug("%s[%p]: phy_address = 0x%lx\n",
416 __func__, audio, region->paddr);
417 if (region != NULL) {
418 rc = q6asm_memory_unmap(audio->ac,
419 (uint32_t)region->paddr, IN);
420 if (rc < 0)
421 pr_err("%s[%p]: memory unmap failed\n",
422 __func__, audio);
423 }
424 }
425}
426
427int audio_aio_release(struct inode *inode, struct file *file)
428{
429 struct q6audio_aio *audio = file->private_data;
430 pr_debug("%s[%p]\n", __func__, audio);
431 mutex_lock(&audio->lock);
432 audio->wflush = 1;
433 if (audio->enabled)
434 audio_aio_flush(audio);
435 audio->wflush = 0;
436 audio->drv_ops.out_flush(audio);
437 audio->drv_ops.in_flush(audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530438 audio_aio_disable(audio);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530439 audio_aio_reset_ion_region(audio);
Deepa Madiregamaa4795072012-06-15 22:35:52 +0530440 ion_client_destroy(audio->client);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530441 audio->event_abort = 1;
442 wake_up(&audio->event_wait);
443 audio_aio_reset_event_queue(audio);
444 q6asm_audio_client_free(audio->ac);
445 mutex_unlock(&audio->lock);
446 mutex_destroy(&audio->lock);
447 mutex_destroy(&audio->read_lock);
448 mutex_destroy(&audio->write_lock);
449 mutex_destroy(&audio->get_event_lock);
450#ifdef CONFIG_DEBUG_FS
451 if (audio->dentry)
452 debugfs_remove(audio->dentry);
453#endif
454 kfree(audio->codec_cfg);
455 kfree(audio);
456 return 0;
457}
458
Steve Mucklef132c6c2012-06-06 18:30:57 -0700459int audio_aio_fsync(struct file *file, loff_t start, loff_t end, int datasync)
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530460{
461 int rc = 0;
462 struct q6audio_aio *audio = file->private_data;
463
464 if (!audio->enabled || audio->feedback)
465 return -EINVAL;
466
467 /* Blocking client sends more data */
468 mutex_lock(&audio->lock);
469 audio->drv_status |= ADRV_STATUS_FSYNC;
470 mutex_unlock(&audio->lock);
471
472 pr_debug("%s[%p]:\n", __func__, audio);
473
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530474 audio->eos_rsp = 0;
475
Sidipotu Ashokfe014152012-09-16 18:24:18 +0530476 pr_debug("%s[%p]Wait for write done from DSP\n", __func__, audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530477 rc = wait_event_interruptible(audio->write_wait,
478 (list_empty(&audio->out_queue)) ||
479 audio->wflush || audio->stopped);
480
Sidipotu Ashokfe014152012-09-16 18:24:18 +0530481 if (audio->stopped || audio->wflush) {
482 pr_debug("%s[%p]: Audio Flushed or Stopped,this is not EOS\n"
483 , __func__, audio);
484 audio->wflush = 0;
485 rc = -EBUSY;
486 }
487
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530488 if (rc < 0) {
489 pr_err("%s[%p]: wait event for list_empty failed, rc = %d\n",
490 __func__, audio, rc);
491 goto done;
492 }
493
494 rc = q6asm_cmd(audio->ac, CMD_EOS);
Sidipotu Ashokfe014152012-09-16 18:24:18 +0530495 pr_debug("%s[%p]: EOS cmd sent to DSP\n", __func__, audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530496
497 if (rc < 0)
498 pr_err("%s[%p]: q6asm_cmd failed, rc = %d",
499 __func__, audio, rc);
500
Sidipotu Ashokfe014152012-09-16 18:24:18 +0530501 pr_debug("%s[%p]: wait for RENDERED_EOS from DSP\n"
502 , __func__, audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530503 rc = wait_event_interruptible(audio->write_wait,
504 (audio->eos_rsp || audio->wflush ||
505 audio->stopped));
506
507 if (rc < 0) {
508 pr_err("%s[%p]: wait event for eos_rsp failed, rc = %d\n",
509 __func__, audio, rc);
510 goto done;
511 }
512
Sidipotu Ashokfe014152012-09-16 18:24:18 +0530513 if (audio->stopped || audio->wflush) {
514 audio->wflush = 0;
515 pr_debug("%s[%p]: Audio Flushed or Stopped,this is not EOS\n"
516 , __func__, audio);
517 rc = -EBUSY;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530518 }
519
Sidipotu Ashokfe014152012-09-16 18:24:18 +0530520 if (audio->eos_rsp == 1)
521 pr_debug("%s[%p]: EOS\n", __func__, audio);
522
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530523
524done:
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530525 mutex_lock(&audio->lock);
526 audio->drv_status &= ~ADRV_STATUS_FSYNC;
527 mutex_unlock(&audio->lock);
528
529 return rc;
530}
531
532static int audio_aio_events_pending(struct q6audio_aio *audio)
533{
534 unsigned long flags;
535 int empty;
536
537 spin_lock_irqsave(&audio->event_queue_lock, flags);
538 empty = !list_empty(&audio->event_queue);
539 spin_unlock_irqrestore(&audio->event_queue_lock, flags);
540 return empty || audio->event_abort;
541}
542
543static long audio_aio_process_event_req(struct q6audio_aio *audio,
544 void __user *arg)
545{
546 long rc;
547 struct msm_audio_event usr_evt;
548 struct audio_aio_event *drv_evt = NULL;
549 int timeout;
550 unsigned long flags;
551
552 if (copy_from_user(&usr_evt, arg, sizeof(struct msm_audio_event)))
553 return -EFAULT;
554
555 timeout = (int)usr_evt.timeout_ms;
556
557 if (timeout > 0) {
558 rc = wait_event_interruptible_timeout(audio->event_wait,
559 audio_aio_events_pending
560 (audio),
561 msecs_to_jiffies
562 (timeout));
563 if (rc == 0)
564 return -ETIMEDOUT;
565 } else {
566 rc = wait_event_interruptible(audio->event_wait,
567 audio_aio_events_pending(audio));
568 }
569 if (rc < 0)
570 return rc;
571
572 if (audio->event_abort) {
573 audio->event_abort = 0;
574 return -ENODEV;
575 }
576
577 rc = 0;
578
579 spin_lock_irqsave(&audio->event_queue_lock, flags);
580 if (!list_empty(&audio->event_queue)) {
581 drv_evt = list_first_entry(&audio->event_queue,
582 struct audio_aio_event, list);
583 list_del(&drv_evt->list);
584 }
585 if (drv_evt) {
586 usr_evt.event_type = drv_evt->event_type;
587 usr_evt.event_payload = drv_evt->payload;
588 list_add_tail(&drv_evt->list, &audio->free_event_queue);
589 } else {
590 pr_err("%s[%p]:Unexpected path\n", __func__, audio);
591 spin_unlock_irqrestore(&audio->event_queue_lock, flags);
592 return -EPERM;
593 }
594 spin_unlock_irqrestore(&audio->event_queue_lock, flags);
595
596 if (drv_evt->event_type == AUDIO_EVENT_WRITE_DONE) {
597 pr_debug("%s[%p]:posted AUDIO_EVENT_WRITE_DONE to user\n",
598 __func__, audio);
599 mutex_lock(&audio->write_lock);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530600 audio_aio_ion_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530601 drv_evt->payload.aio_buf.buf_len, 0, 0);
602 mutex_unlock(&audio->write_lock);
603 } else if (drv_evt->event_type == AUDIO_EVENT_READ_DONE) {
604 pr_debug("%s[%p]:posted AUDIO_EVENT_READ_DONE to user\n",
605 __func__, audio);
606 mutex_lock(&audio->read_lock);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530607 audio_aio_ion_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530608 drv_evt->payload.aio_buf.buf_len, 0, 0);
609 mutex_unlock(&audio->read_lock);
610 }
611
612 /* Some read buffer might be held up in DSP,release all
613 * Once EOS indicated
614 */
615 if (audio->eos_rsp && !list_empty(&audio->in_queue)) {
616 pr_debug("%s[%p]:Send flush command to release read buffers"\
617 " held up in DSP\n", __func__, audio);
618 audio_aio_flush(audio);
619 }
620
621 if (copy_to_user(arg, &usr_evt, sizeof(usr_evt)))
622 rc = -EFAULT;
623
624 return rc;
625}
626
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530627static int audio_aio_ion_check(struct q6audio_aio *audio,
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530628 void *vaddr, unsigned long len)
629{
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530630 struct audio_aio_ion_region *region_elt;
631 struct audio_aio_ion_region t = {.vaddr = vaddr, .len = len };
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530632
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530633 list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530634 if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
635 OVERLAPS(region_elt, &t)) {
Harmandeep Singheaf59b42012-06-05 21:46:02 -0700636 pr_err("%s[%p]:region (vaddr %p len %ld) clashes with registered region (vaddr %p paddr %p len %ld)\n",
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530637 __func__, audio, vaddr, len,
638 region_elt->vaddr,
639 (void *)region_elt->paddr, region_elt->len);
640 return -EINVAL;
641 }
642 }
643
644 return 0;
645}
646
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530647static int audio_aio_ion_add(struct q6audio_aio *audio,
648 struct msm_audio_ion_info *info)
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530649{
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530650 ion_phys_addr_t paddr;
651 size_t len;
652 unsigned long kvaddr;
653 struct audio_aio_ion_region *region;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530654 int rc = -EINVAL;
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530655 struct ion_handle *handle;
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530656 unsigned long ionflag;
657 void *temp_ptr;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530658
659 pr_debug("%s[%p]:\n", __func__, audio);
660 region = kmalloc(sizeof(*region), GFP_KERNEL);
661
662 if (!region) {
663 rc = -ENOMEM;
664 goto end;
665 }
666
Deepa Madiregamaa4795072012-06-15 22:35:52 +0530667 handle = ion_import_dma_buf(audio->client, info->fd);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530668 if (IS_ERR_OR_NULL(handle)) {
669 pr_err("%s: could not get handle of the given fd\n", __func__);
670 goto import_error;
671 }
672
Deepa Madiregamaa4795072012-06-15 22:35:52 +0530673 rc = ion_handle_get_flags(audio->client, handle, &ionflag);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530674 if (rc) {
675 pr_err("%s: could not get flags for the handle\n", __func__);
676 goto flag_error;
677 }
678
Mitchel Humpherys911b4b72012-09-12 14:42:50 -0700679 temp_ptr = ion_map_kernel(audio->client, handle);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530680 if (IS_ERR_OR_NULL(temp_ptr)) {
681 pr_err("%s: could not get virtual address\n", __func__);
682 goto map_error;
683 }
684 kvaddr = (unsigned long)temp_ptr;
685
Deepa Madiregamaa4795072012-06-15 22:35:52 +0530686 rc = ion_phys(audio->client, handle, &paddr, &len);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530687 if (rc) {
688 pr_err("%s: could not get physical address\n", __func__);
689 goto ion_error;
690 }
691
692 rc = audio_aio_ion_check(audio, info->vaddr, len);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530693 if (rc < 0) {
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530694 pr_err("%s: audio_aio_ion_check failed\n", __func__);
695 goto ion_error;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530696 }
697
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530698 region->handle = handle;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530699 region->vaddr = info->vaddr;
700 region->fd = info->fd;
701 region->paddr = paddr;
702 region->kvaddr = kvaddr;
703 region->len = len;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530704 region->ref_cnt = 0;
705 pr_debug("%s[%p]:add region paddr %lx vaddr %p, len %lu kvaddr %lx\n",
706 __func__, audio,
707 region->paddr, region->vaddr, region->len, region->kvaddr);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530708 list_add_tail(&region->list, &audio->ion_region_queue);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530709 rc = q6asm_memory_map(audio->ac, (uint32_t) paddr, IN, (uint32_t) len,
710 1);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530711 if (rc < 0) {
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530712 pr_err("%s[%p]: memory map failed\n", __func__, audio);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530713 goto ion_error;
714 } else {
715 goto end;
716 }
717
718ion_error:
Deepa Madiregamaa4795072012-06-15 22:35:52 +0530719 ion_unmap_kernel(audio->client, handle);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530720map_error:
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530721flag_error:
Deepa Madiregamaa4795072012-06-15 22:35:52 +0530722 ion_free(audio->client, handle);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530723import_error:
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530724 kfree(region);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530725end:
726 return rc;
727}
728
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530729static int audio_aio_ion_remove(struct q6audio_aio *audio,
730 struct msm_audio_ion_info *info)
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530731{
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530732 struct audio_aio_ion_region *region;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530733 struct list_head *ptr, *next;
734 int rc = -EINVAL;
735
736 pr_debug("%s[%p]:info fd %d vaddr %p\n",
737 __func__, audio, info->fd, info->vaddr);
738
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530739 list_for_each_safe(ptr, next, &audio->ion_region_queue) {
740 region = list_entry(ptr, struct audio_aio_ion_region, list);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530741
742 if ((region->fd == info->fd) &&
743 (region->vaddr == info->vaddr)) {
744 if (region->ref_cnt) {
745 pr_debug("%s[%p]:region %p in use ref_cnt %d\n",
746 __func__, audio, region,
747 region->ref_cnt);
748 break;
749 }
750 pr_debug("%s[%p]:remove region fd %d vaddr %p\n",
751 __func__, audio, info->fd, info->vaddr);
752 rc = q6asm_memory_unmap(audio->ac,
753 (uint32_t) region->paddr, IN);
754 if (rc < 0)
755 pr_err("%s[%p]: memory unmap failed\n",
756 __func__, audio);
757
758 list_del(&region->list);
Deepa Madiregamaa4795072012-06-15 22:35:52 +0530759 ion_unmap_kernel(audio->client, region->handle);
760 ion_free(audio->client, region->handle);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530761 kfree(region);
762 rc = 0;
763 break;
764 }
765 }
766
767 return rc;
768}
769
770static void audio_aio_async_write(struct q6audio_aio *audio,
771 struct audio_aio_buffer_node *buf_node)
772{
773 int rc;
774 struct audio_client *ac;
775 struct audio_aio_write_param param;
776
Harmandeep Singheaf59b42012-06-05 21:46:02 -0700777 pr_debug("%s[%p]: Send write buff %p phy %lx len %d meta_enable = %d\n",
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530778 __func__, audio, buf_node, buf_node->paddr,
779 buf_node->buf.data_len,
780 audio->buf_cfg.meta_info_enable);
781
782 ac = audio->ac;
783 /* Offset with appropriate meta */
Karthik Reddy Katta6f09ac92012-04-23 15:04:38 +0530784 if (audio->feedback) {
785 /* Non Tunnel mode */
786 param.paddr = buf_node->paddr + sizeof(struct dec_meta_in);
787 param.len = buf_node->buf.data_len - sizeof(struct dec_meta_in);
788 } else {
789 /* Tunnel mode */
790 param.paddr = buf_node->paddr;
791 param.len = buf_node->buf.data_len;
792 }
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530793 param.msw_ts = buf_node->meta_info.meta_in.ntimestamp.highpart;
794 param.lsw_ts = buf_node->meta_info.meta_in.ntimestamp.lowpart;
795 /* If no meta_info enaled, indicate no time stamp valid */
796 if (audio->buf_cfg.meta_info_enable)
797 param.flags = 0;
798 else
799 param.flags = 0xFF00;
800 param.uid = param.paddr;
801 /* Read command will populate paddr as token */
802 buf_node->token = param.paddr;
803 rc = q6asm_async_write(ac, &param);
804 if (rc < 0)
805 pr_err("%s[%p]:failed\n", __func__, audio);
806}
807
808void audio_aio_post_event(struct q6audio_aio *audio, int type,
809 union msm_audio_event_payload payload)
810{
811 struct audio_aio_event *e_node = NULL;
812 unsigned long flags;
813
814 spin_lock_irqsave(&audio->event_queue_lock, flags);
815
816 if (!list_empty(&audio->free_event_queue)) {
817 e_node = list_first_entry(&audio->free_event_queue,
818 struct audio_aio_event, list);
819 list_del(&e_node->list);
820 } else {
821 e_node = kmalloc(sizeof(struct audio_aio_event), GFP_ATOMIC);
822 if (!e_node) {
823 pr_err("%s[%p]:No mem to post event %d\n",
824 __func__, audio, type);
825 spin_unlock_irqrestore(&audio->event_queue_lock, flags);
826 return;
827 }
828 }
829
830 e_node->event_type = type;
831 e_node->payload = payload;
832
833 list_add_tail(&e_node->list, &audio->event_queue);
834 spin_unlock_irqrestore(&audio->event_queue_lock, flags);
835 wake_up(&audio->event_wait);
836}
837
838static void audio_aio_async_read(struct q6audio_aio *audio,
839 struct audio_aio_buffer_node *buf_node)
840{
841 struct audio_client *ac;
842 struct audio_aio_read_param param;
843 int rc;
844
845 pr_debug("%s[%p]: Send read buff %p phy %lx len %d\n",
846 __func__, audio, buf_node,
847 buf_node->paddr, buf_node->buf.buf_len);
848 ac = audio->ac;
849 /* Provide address so driver can append nr frames information */
850 param.paddr = buf_node->paddr +
851 sizeof(struct dec_meta_out);
852 param.len = buf_node->buf.buf_len -
853 sizeof(struct dec_meta_out);
854 param.uid = param.paddr;
855 /* Write command will populate paddr as token */
856 buf_node->token = param.paddr;
857 rc = q6asm_async_read(ac, &param);
858 if (rc < 0)
859 pr_err("%s[%p]:failed\n", __func__, audio);
860}
861
862static int audio_aio_buf_add(struct q6audio_aio *audio, unsigned dir,
863 void __user *arg)
864{
865 unsigned long flags;
866 struct audio_aio_buffer_node *buf_node;
867
868
869 buf_node = kzalloc(sizeof(*buf_node), GFP_KERNEL);
870
871 if (!buf_node)
872 return -ENOMEM;
873
874 if (copy_from_user(&buf_node->buf, arg, sizeof(buf_node->buf))) {
875 kfree(buf_node);
876 return -EFAULT;
877 }
878
Harmandeep Singheaf59b42012-06-05 21:46:02 -0700879 pr_debug("%s[%p]:node %p dir %x buf_addr %p buf_len %d data_len %d\n",
880 __func__, audio, buf_node, dir, buf_node->buf.buf_addr,
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530881 buf_node->buf.buf_len, buf_node->buf.data_len);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530882 buf_node->paddr = audio_aio_ion_fixup(audio, buf_node->buf.buf_addr,
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530883 buf_node->buf.buf_len, 1,
884 &buf_node->kvaddr);
885 if (dir) {
886 /* write */
887 if (!buf_node->paddr ||
888 (buf_node->paddr & 0x1) ||
889 (!audio->feedback && !buf_node->buf.data_len)) {
890 kfree(buf_node);
891 return -EINVAL;
892 }
893 extract_meta_out_info(audio, buf_node, 1);
894 /* Not a EOS buffer */
895 if (!(buf_node->meta_info.meta_in.nflags & AUDIO_DEC_EOS_SET)) {
896 spin_lock_irqsave(&audio->dsp_lock, flags);
897 audio_aio_async_write(audio, buf_node);
898 /* EOS buffer handled in driver */
899 list_add_tail(&buf_node->list, &audio->out_queue);
900 spin_unlock_irqrestore(&audio->dsp_lock, flags);
Preetam Singh Ranawat6aae2412011-11-04 18:16:27 +0530901 } else if (buf_node->meta_info.meta_in.nflags
902 & AUDIO_DEC_EOS_SET) {
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530903 if (!audio->wflush) {
904 pr_debug("%s[%p]:Send EOS cmd at i/p\n",
905 __func__, audio);
906 /* Driver will forcefully post writedone event
907 * once eos ack recived from DSP
908 */
909 audio->eos_write_payload.aio_buf =\
910 buf_node->buf;
911 audio->eos_flag = 1;
912 audio->eos_rsp = 0;
913 q6asm_cmd(audio->ac, CMD_EOS);
914 kfree(buf_node);
915 } else { /* Flush in progress, send back i/p
916 * EOS buffer as is
917 */
918 union msm_audio_event_payload event_payload;
919 event_payload.aio_buf = buf_node->buf;
920 audio_aio_post_event(audio,
921 AUDIO_EVENT_WRITE_DONE,
922 event_payload);
923 kfree(buf_node);
924 }
925 }
926 } else {
927 /* read */
928 if (!buf_node->paddr ||
929 (buf_node->paddr & 0x1) ||
930 (buf_node->buf.buf_len < PCM_BUFSZ_MIN)) {
931 kfree(buf_node);
932 return -EINVAL;
933 }
934 /* No EOS reached */
935 if (!audio->eos_rsp) {
936 spin_lock_irqsave(&audio->dsp_lock, flags);
937 audio_aio_async_read(audio, buf_node);
938 /* EOS buffer handled in driver */
939 list_add_tail(&buf_node->list, &audio->in_queue);
940 spin_unlock_irqrestore(&audio->dsp_lock, flags);
941 }
942 /* EOS reached at input side fake all upcoming read buffer to
943 * indicate the same
944 */
945 else {
946 union msm_audio_event_payload event_payload;
947 event_payload.aio_buf = buf_node->buf;
948 event_payload.aio_buf.data_len =
949 insert_eos_buf(audio, buf_node);
950 pr_debug("%s[%p]: propagate READ_DONE as EOS done\n",\
951 __func__, audio);
952 audio_aio_post_event(audio, AUDIO_EVENT_READ_DONE,
953 event_payload);
954 kfree(buf_node);
955 }
956 }
957 return 0;
958}
959
960static void audio_aio_ioport_reset(struct q6audio_aio *audio)
961{
962 if (audio->drv_status & ADRV_STATUS_AIO_INTF) {
963 /* If fsync is in progress, make sure
964 * return value of fsync indicates
965 * abort due to flush
966 */
967 if (audio->drv_status & ADRV_STATUS_FSYNC) {
968 pr_debug("%s[%p]:fsync in progress\n", __func__, audio);
969 audio->drv_ops.out_flush(audio);
970 } else
971 audio->drv_ops.out_flush(audio);
Sidipotu Ashokfe014152012-09-16 18:24:18 +0530972 if (audio->feedback == NON_TUNNEL_MODE)
973 audio->drv_ops.in_flush(audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530974 }
975}
976
977int audio_aio_open(struct q6audio_aio *audio, struct file *file)
978{
979 int rc = 0;
980 int i;
981 struct audio_aio_event *e_node = NULL;
982
983 /* Settings will be re-config at AUDIO_SET_CONFIG,
984 * but at least we need to have initial config
985 */
986 audio->str_cfg.buffer_size = FRAME_SIZE;
987 audio->str_cfg.buffer_count = FRAME_NUM;
988 audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
989 audio->pcm_cfg.sample_rate = 48000;
990 audio->pcm_cfg.channel_count = 2;
991
992 /* Only AIO interface */
993 if (file->f_flags & O_NONBLOCK) {
994 pr_debug("%s[%p]:set to aio interface\n", __func__, audio);
995 audio->drv_status |= ADRV_STATUS_AIO_INTF;
996 audio->drv_ops.out_flush = audio_aio_async_out_flush;
997 audio->drv_ops.in_flush = audio_aio_async_in_flush;
998 q6asm_set_io_mode(audio->ac, ASYNC_IO_MODE);
999 } else {
1000 pr_err("%s[%p]:SIO interface not supported\n",
1001 __func__, audio);
1002 rc = -EACCES;
1003 goto fail;
1004 }
1005
1006 /* Initialize all locks of audio instance */
1007 mutex_init(&audio->lock);
1008 mutex_init(&audio->read_lock);
1009 mutex_init(&audio->write_lock);
1010 mutex_init(&audio->get_event_lock);
1011 spin_lock_init(&audio->dsp_lock);
1012 spin_lock_init(&audio->event_queue_lock);
1013 init_waitqueue_head(&audio->cmd_wait);
1014 init_waitqueue_head(&audio->write_wait);
1015 init_waitqueue_head(&audio->event_wait);
1016 INIT_LIST_HEAD(&audio->out_queue);
1017 INIT_LIST_HEAD(&audio->in_queue);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +05301018 INIT_LIST_HEAD(&audio->ion_region_queue);
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301019 INIT_LIST_HEAD(&audio->free_event_queue);
1020 INIT_LIST_HEAD(&audio->event_queue);
1021
1022 audio->drv_ops.out_flush(audio);
1023 audio->opened = 1;
1024 file->private_data = audio;
1025 audio->codec_ioctl = audio_aio_ioctl;
1026
Mingming Yinc09967e2012-04-27 15:09:43 -07001027 for (i = 0; i < AUDIO_EVENT_NUM; i++) {
1028 e_node = kmalloc(sizeof(struct audio_aio_event), GFP_KERNEL);
1029 if (e_node)
1030 list_add_tail(&e_node->list, &audio->free_event_queue);
1031 else {
1032 pr_err("%s[%p]:event pkt alloc failed\n",
1033 __func__, audio);
1034 break;
1035 }
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301036 }
Deepa Madiregamaa4795072012-06-15 22:35:52 +05301037 audio->client = msm_ion_client_create(UINT_MAX, "Audio_Dec_Client");
1038 if (IS_ERR_OR_NULL(audio->client)) {
1039 pr_err("Unable to create ION client\n");
1040 rc = -EACCES;
1041 goto fail;
1042 }
1043 pr_debug("Ion client create in audio_aio_open %p", audio->client);
Mingming Yinc09967e2012-04-27 15:09:43 -07001044 return 0;
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301045fail:
Mingming Yinc09967e2012-04-27 15:09:43 -07001046 q6asm_audio_client_free(audio->ac);
1047 kfree(audio->codec_cfg);
1048 kfree(audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301049 return rc;
1050}
1051
1052long audio_aio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
1053{
1054 struct q6audio_aio *audio = file->private_data;
1055 int rc = 0;
1056
1057 switch (cmd) {
1058 case AUDIO_GET_STATS: {
1059 struct msm_audio_stats stats;
Sidipotu Ashok388cdc52012-09-16 16:59:16 +05301060 uint64_t timestamp;
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301061 stats.byte_count = atomic_read(&audio->in_bytes);
1062 stats.sample_count = atomic_read(&audio->in_samples);
Sidipotu Ashok388cdc52012-09-16 16:59:16 +05301063 timestamp = q6asm_get_session_time(audio->ac);
1064 if (timestamp >= 0)
1065 memcpy(&stats.unused[0], &timestamp, sizeof(timestamp));
1066 else
1067 pr_debug("Error while getting timestamp\n");
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301068 if (copy_to_user((void *)arg, &stats, sizeof(stats)))
1069 rc = -EFAULT;
1070 break;
1071 }
1072 case AUDIO_GET_EVENT: {
1073 pr_debug("%s[%p]:AUDIO_GET_EVENT\n", __func__, audio);
1074 if (mutex_trylock(&audio->get_event_lock)) {
1075 rc = audio_aio_process_event_req(audio,
1076 (void __user *)arg);
1077 mutex_unlock(&audio->get_event_lock);
1078 } else
1079 rc = -EBUSY;
1080 break;
1081 }
1082 case AUDIO_ABORT_GET_EVENT: {
1083 audio->event_abort = 1;
1084 wake_up(&audio->event_wait);
1085 break;
1086 }
1087 case AUDIO_ASYNC_WRITE: {
1088 mutex_lock(&audio->write_lock);
1089 if (audio->drv_status & ADRV_STATUS_FSYNC)
1090 rc = -EBUSY;
1091 else {
1092 if (audio->enabled)
1093 rc = audio_aio_buf_add(audio, 1,
1094 (void __user *)arg);
1095 else
1096 rc = -EPERM;
1097 }
1098 mutex_unlock(&audio->write_lock);
1099 break;
1100 }
1101 case AUDIO_ASYNC_READ: {
1102 mutex_lock(&audio->read_lock);
1103 if ((audio->feedback) && (audio->enabled))
1104 rc = audio_aio_buf_add(audio, 0,
1105 (void __user *)arg);
1106 else
1107 rc = -EPERM;
1108 mutex_unlock(&audio->read_lock);
1109 break;
1110 }
1111 case AUDIO_OUTPORT_FLUSH: {
1112 pr_debug("%s[%p]:AUDIO_OUTPORT_FLUSH\n", __func__, audio);
1113 mutex_lock(&audio->read_lock);
1114 rc = audio_aio_outport_flush(audio);
1115 if (rc < 0) {
1116 pr_err("%s[%p]: AUDIO_OUTPORT_FLUSH failed\n",
1117 __func__, audio);
1118 rc = -EINTR;
1119 }
1120 mutex_unlock(&audio->read_lock);
1121 break;
1122 }
1123 case AUDIO_STOP: {
1124 pr_debug("%s[%p]: AUDIO_STOP session_id[%d]\n", __func__,
1125 audio, audio->ac->session);
1126 mutex_lock(&audio->lock);
1127 audio->stopped = 1;
1128 audio_aio_flush(audio);
1129 audio->enabled = 0;
1130 audio->drv_status &= ~ADRV_STATUS_PAUSE;
1131 if (rc < 0) {
1132 pr_err("%s[%p]:Audio Stop procedure failed rc=%d\n",
1133 __func__, audio, rc);
1134 mutex_unlock(&audio->lock);
1135 break;
1136 }
1137 mutex_unlock(&audio->lock);
1138 break;
1139 }
1140 case AUDIO_PAUSE: {
1141 pr_debug("%s[%p]:AUDIO_PAUSE %ld\n", __func__, audio, arg);
1142 mutex_lock(&audio->lock);
1143 if (arg == 1) {
1144 rc = audio_aio_pause(audio);
Laxminath Kasam92ad28c2012-09-03 13:47:33 +05301145 if (rc < 0) {
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301146 pr_err("%s[%p]: pause FAILED rc=%d\n",
1147 __func__, audio, rc);
Laxminath Kasam92ad28c2012-09-03 13:47:33 +05301148 mutex_unlock(&audio->lock);
1149 break;
1150 }
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301151 audio->drv_status |= ADRV_STATUS_PAUSE;
1152 } else if (arg == 0) {
1153 if (audio->drv_status & ADRV_STATUS_PAUSE) {
1154 rc = audio_aio_enable(audio);
1155 if (rc)
1156 pr_err("%s[%p]: audio enable failed\n",
1157 __func__, audio);
1158 else {
1159 audio->drv_status &= ~ADRV_STATUS_PAUSE;
1160 audio->enabled = 1;
1161 }
1162 }
1163 }
1164 mutex_unlock(&audio->lock);
1165 break;
1166 }
1167 case AUDIO_FLUSH: {
1168 pr_debug("%s[%p]: AUDIO_FLUSH sessionid[%d]\n", __func__,
1169 audio, audio->ac->session);
1170 mutex_lock(&audio->lock);
1171 audio->rflush = 1;
1172 audio->wflush = 1;
1173 /* Flush DSP */
1174 rc = audio_aio_flush(audio);
1175 /* Flush input / Output buffer in software*/
1176 audio_aio_ioport_reset(audio);
1177 if (rc < 0) {
1178 pr_err("%s[%p]:AUDIO_FLUSH interrupted\n",
1179 __func__, audio);
1180 rc = -EINTR;
1181 } else {
1182 audio->rflush = 0;
Sidipotu Ashokfe014152012-09-16 18:24:18 +05301183 if (audio->drv_status & ADRV_STATUS_FSYNC)
1184 wake_up(&audio->write_wait);
1185 else
1186 audio->wflush = 0;
1187
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301188 }
1189 audio->eos_flag = 0;
1190 audio->eos_rsp = 0;
1191 mutex_unlock(&audio->lock);
1192 break;
1193 }
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +05301194 case AUDIO_REGISTER_ION: {
1195 struct msm_audio_ion_info info;
1196 pr_debug("%s[%p]:AUDIO_REGISTER_ION\n", __func__, audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301197 mutex_lock(&audio->lock);
1198 if (copy_from_user(&info, (void *)arg, sizeof(info)))
1199 rc = -EFAULT;
1200 else
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +05301201 rc = audio_aio_ion_add(audio, &info);
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301202 mutex_unlock(&audio->lock);
1203 break;
1204 }
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +05301205 case AUDIO_DEREGISTER_ION: {
1206 struct msm_audio_ion_info info;
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301207 mutex_lock(&audio->lock);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +05301208 pr_debug("%s[%p]:AUDIO_DEREGISTER_ION\n", __func__, audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301209 if (copy_from_user(&info, (void *)arg, sizeof(info)))
1210 rc = -EFAULT;
1211 else
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +05301212 rc = audio_aio_ion_remove(audio, &info);
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301213 mutex_unlock(&audio->lock);
1214 break;
1215 }
1216 case AUDIO_GET_STREAM_CONFIG: {
1217 struct msm_audio_stream_config cfg;
1218 mutex_lock(&audio->lock);
1219 memset(&cfg, 0, sizeof(cfg));
1220 cfg.buffer_size = audio->str_cfg.buffer_size;
1221 cfg.buffer_count = audio->str_cfg.buffer_count;
1222 pr_debug("%s[%p]:GET STREAM CFG %d %d\n",
1223 __func__, audio, cfg.buffer_size, cfg.buffer_count);
1224 if (copy_to_user((void *)arg, &cfg, sizeof(cfg)))
1225 rc = -EFAULT;
1226 mutex_unlock(&audio->lock);
1227 break;
1228 }
1229 case AUDIO_SET_STREAM_CONFIG: {
1230 struct msm_audio_stream_config cfg;
1231 pr_debug("%s[%p]:SET STREAM CONFIG\n", __func__, audio);
1232 mutex_lock(&audio->lock);
1233 if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
1234 rc = -EFAULT;
1235 mutex_unlock(&audio->lock);
1236 break;
1237 }
1238 audio->str_cfg.buffer_size = FRAME_SIZE;
1239 audio->str_cfg.buffer_count = FRAME_NUM;
1240 rc = 0;
1241 mutex_unlock(&audio->lock);
1242 break;
1243 }
1244 case AUDIO_GET_CONFIG: {
1245 struct msm_audio_config cfg;
1246 mutex_lock(&audio->lock);
1247 if (copy_to_user((void *)arg, &audio->pcm_cfg, sizeof(cfg)))
1248 rc = -EFAULT;
1249 mutex_unlock(&audio->lock);
1250 break;
1251 }
1252 case AUDIO_SET_CONFIG: {
1253 struct msm_audio_config config;
1254 pr_err("%s[%p]:AUDIO_SET_CONFIG\n", __func__, audio);
1255 mutex_lock(&audio->lock);
1256 if (copy_from_user(&config, (void *)arg, sizeof(config))) {
1257 rc = -EFAULT;
1258 mutex_unlock(&audio->lock);
1259 break;
1260 }
1261 if (audio->feedback != NON_TUNNEL_MODE) {
Harmandeep Singheaf59b42012-06-05 21:46:02 -07001262 pr_err("%s[%p]:Not sufficient permission to change the playback mode\n",
1263 __func__, audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301264 rc = -EACCES;
1265 mutex_unlock(&audio->lock);
1266 break;
1267 }
1268 if ((config.buffer_count > PCM_BUF_COUNT) ||
1269 (config.buffer_count == 1))
1270 config.buffer_count = PCM_BUF_COUNT;
1271
1272 if (config.buffer_size < PCM_BUFSZ_MIN)
1273 config.buffer_size = PCM_BUFSZ_MIN;
1274
1275 audio->pcm_cfg.buffer_count = config.buffer_count;
1276 audio->pcm_cfg.buffer_size = config.buffer_size;
1277 audio->pcm_cfg.channel_count = config.channel_count;
1278 audio->pcm_cfg.sample_rate = config.sample_rate;
1279 rc = 0;
1280 mutex_unlock(&audio->lock);
1281 break;
1282 }
1283 case AUDIO_SET_BUF_CFG: {
1284 struct msm_audio_buf_cfg cfg;
1285 mutex_lock(&audio->lock);
1286 if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
1287 rc = -EFAULT;
1288 mutex_unlock(&audio->lock);
1289 break;
1290 }
1291 if ((audio->feedback == NON_TUNNEL_MODE) &&
1292 !cfg.meta_info_enable) {
1293 rc = -EFAULT;
1294 mutex_unlock(&audio->lock);
1295 break;
1296 }
1297
1298 audio->buf_cfg.meta_info_enable = cfg.meta_info_enable;
1299 pr_debug("%s[%p]:session id %d: Set-buf-cfg: meta[%d]",
1300 __func__, audio,
1301 audio->ac->session, cfg.meta_info_enable);
1302 mutex_unlock(&audio->lock);
1303 break;
1304 }
1305 case AUDIO_GET_BUF_CFG: {
Harmandeep Singheaf59b42012-06-05 21:46:02 -07001306 pr_debug("%s[%p]:session id %d: Get-buf-cfg: meta[%d] framesperbuf[%d]\n",
1307 __func__, audio,
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301308 audio->ac->session, audio->buf_cfg.meta_info_enable,
1309 audio->buf_cfg.frames_per_buf);
1310
1311 mutex_lock(&audio->lock);
1312 if (copy_to_user((void *)arg, &audio->buf_cfg,
1313 sizeof(struct msm_audio_buf_cfg)))
1314 rc = -EFAULT;
1315 mutex_unlock(&audio->lock);
1316 break;
1317 }
1318 case AUDIO_GET_SESSION_ID: {
1319 mutex_lock(&audio->lock);
1320 if (copy_to_user((void *)arg, &audio->ac->session,
1321 sizeof(unsigned short))) {
1322 rc = -EFAULT;
1323 }
1324 mutex_unlock(&audio->lock);
1325 break;
1326 }
1327 default:
1328 rc = -EINVAL;
1329 }
1330 return rc;
1331}