blob: 654f547fe1056b86e60b4147e1d352a7164b990a [file] [log] [blame]
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301/* Copyright (C) 2008 Google, Inc.
2 * Copyright (C) 2008 HTC Corporation
Devendra Patel8c556a12013-01-24 23:09:45 -08003 * Copyright (c) 2009-2013, The Linux Foundation. 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"
Sidipotu Ashokbf84d4d2012-11-06 17:13:28 +053028#ifdef CONFIG_USE_DEV_CTRL_VOLUME
29#include <mach/qdsp6v2/audio_dev_ctl.h>
30#endif /*CONFIG_USE_DEV_CTRL_VOLUME*/
Deepa Madiregama55cbf782011-09-10 05:44:39 +053031
32#ifdef CONFIG_DEBUG_FS
33ssize_t audio_aio_debug_open(struct inode *inode, struct file *file)
34{
35 file->private_data = inode->i_private;
36 return 0;
37}
38
Harmandeep Singheaf59b42012-06-05 21:46:02 -070039ssize_t audio_aio_debug_read(struct file *file, char __user *buf,
Deepa Madiregama55cbf782011-09-10 05:44:39 +053040 size_t count, loff_t *ppos)
41{
42 const int debug_bufmax = 4096;
43 static char buffer[4096];
44 int n = 0;
45 struct q6audio_aio *audio = file->private_data;
46
47 mutex_lock(&audio->lock);
48 n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
49 n += scnprintf(buffer + n, debug_bufmax - n,
50 "enabled %d\n", audio->enabled);
51 n += scnprintf(buffer + n, debug_bufmax - n,
52 "stopped %d\n", audio->stopped);
53 n += scnprintf(buffer + n, debug_bufmax - n,
54 "feedback %d\n", audio->feedback);
55 mutex_unlock(&audio->lock);
56 /* Following variables are only useful for debugging when
57 * when playback halts unexpectedly. Thus, no mutual exclusion
58 * enforced
59 */
60 n += scnprintf(buffer + n, debug_bufmax - n,
61 "wflush %d\n", audio->wflush);
62 n += scnprintf(buffer + n, debug_bufmax - n,
63 "rflush %d\n", audio->rflush);
64 n += scnprintf(buffer + n, debug_bufmax - n,
65 "inqueue empty %d\n", list_empty(&audio->in_queue));
66 n += scnprintf(buffer + n, debug_bufmax - n,
67 "outqueue empty %d\n", list_empty(&audio->out_queue));
68 buffer[n] = 0;
69 return simple_read_from_buffer(buf, count, ppos, buffer, n);
70}
71#endif
72
Harmandeep Singheaf59b42012-06-05 21:46:02 -070073int insert_eos_buf(struct q6audio_aio *audio,
Deepa Madiregama55cbf782011-09-10 05:44:39 +053074 struct audio_aio_buffer_node *buf_node)
75{
76 struct dec_meta_out *eos_buf = buf_node->kvaddr;
77 pr_debug("%s[%p]:insert_eos_buf\n", __func__, audio);
78 eos_buf->num_of_frames = 0xFFFFFFFF;
79 eos_buf->meta_out_dsp[0].offset_to_frame = 0x0;
80 eos_buf->meta_out_dsp[0].nflags = AUDIO_DEC_EOS_SET;
81 return sizeof(struct dec_meta_out) +
82 sizeof(eos_buf->meta_out_dsp[0]);
83}
84
85/* Routine which updates read buffers of driver/dsp,
86 for flush operation as DSP output might not have proper
87 value set */
88static int insert_meta_data_flush(struct q6audio_aio *audio,
89 struct audio_aio_buffer_node *buf_node)
90{
91 struct dec_meta_out *meta_data = buf_node->kvaddr;
92 meta_data->num_of_frames = 0x0;
93 meta_data->meta_out_dsp[0].offset_to_frame = 0x0;
94 meta_data->meta_out_dsp[0].nflags = 0x0;
95 return sizeof(struct dec_meta_out) +
96 sizeof(meta_data->meta_out_dsp[0]);
97}
98
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +053099static int audio_aio_ion_lookup_vaddr(struct q6audio_aio *audio, void *addr,
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530100 unsigned long len,
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530101 struct audio_aio_ion_region **region)
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530102{
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530103 struct audio_aio_ion_region *region_elt;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530104
105 int match_count = 0;
106
107 *region = NULL;
108
109 /* returns physical address or zero */
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530110 list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530111 if (addr >= region_elt->vaddr &&
112 addr < region_elt->vaddr + region_elt->len &&
113 addr + len <= region_elt->vaddr + region_elt->len) {
114 /* offset since we could pass vaddr inside a registerd
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530115 * ion buffer
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530116 */
117
118 match_count++;
119 if (!*region)
120 *region = region_elt;
121 }
122 }
123
124 if (match_count > 1) {
125 pr_err("%s[%p]:multiple hits for vaddr %p, len %ld\n",
126 __func__, audio, addr, len);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530127 list_for_each_entry(region_elt, &audio->ion_region_queue,
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530128 list) {
129 if (addr >= region_elt->vaddr &&
130 addr < region_elt->vaddr + region_elt->len &&
131 addr + len <= region_elt->vaddr + region_elt->len)
132 pr_err("\t%s[%p]:%p, %ld --> %p\n",
133 __func__, audio,
134 region_elt->vaddr,
135 region_elt->len,
136 (void *)region_elt->paddr);
137 }
138 }
139
140 return *region ? 0 : -1;
141}
142
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530143static unsigned long audio_aio_ion_fixup(struct q6audio_aio *audio, void *addr,
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530144 unsigned long len, int ref_up, void **kvaddr)
145{
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530146 struct audio_aio_ion_region *region;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530147 unsigned long paddr;
148 int ret;
149
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530150 ret = audio_aio_ion_lookup_vaddr(audio, addr, len, &region);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530151 if (ret) {
152 pr_err("%s[%p]:lookup (%p, %ld) failed\n",
153 __func__, audio, addr, len);
154 return 0;
155 }
156 if (ref_up)
157 region->ref_cnt++;
158 else
159 region->ref_cnt--;
160 pr_debug("%s[%p]:found region %p ref_cnt %d\n",
161 __func__, audio, region, region->ref_cnt);
162 paddr = region->paddr + (addr - region->vaddr);
163 /* provide kernel virtual address for accessing meta information */
164 if (kvaddr)
165 *kvaddr = (void *) (region->kvaddr + (addr - region->vaddr));
166 return paddr;
167}
168
169static int audio_aio_pause(struct q6audio_aio *audio)
170{
Laxminath Kasam92ad28c2012-09-03 13:47:33 +0530171 int rc = -EINVAL;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530172
173 pr_debug("%s[%p], enabled = %d\n", __func__, audio,
174 audio->enabled);
175 if (audio->enabled) {
176 rc = q6asm_cmd(audio->ac, CMD_PAUSE);
177 if (rc < 0)
178 pr_err("%s[%p]: pause cmd failed rc=%d\n",
179 __func__, audio, rc);
180
181 } else
182 pr_err("%s[%p]: Driver not enabled\n", __func__, audio);
183 return rc;
184}
185
186static int audio_aio_flush(struct q6audio_aio *audio)
187{
188 int rc;
189
190 if (audio->enabled) {
191 /* Implicitly issue a pause to the decoder before flushing if
192 it is not in pause state */
193 if (!(audio->drv_status & ADRV_STATUS_PAUSE)) {
194 rc = audio_aio_pause(audio);
195 if (rc < 0)
196 pr_err("%s[%p}: pause cmd failed rc=%d\n",
197 __func__, audio,
198 rc);
199 else
200 audio->drv_status |= ADRV_STATUS_PAUSE;
201 }
202 rc = q6asm_cmd(audio->ac, CMD_FLUSH);
203 if (rc < 0)
204 pr_err("%s[%p]: flush cmd failed rc=%d\n",
205 __func__, audio, rc);
206 /* Not in stop state, reenable the stream */
207 if (audio->stopped == 0) {
208 rc = audio_aio_enable(audio);
209 if (rc)
210 pr_err("%s[%p]:audio re-enable failed\n",
211 __func__, audio);
212 else {
213 audio->enabled = 1;
214 if (audio->drv_status & ADRV_STATUS_PAUSE)
215 audio->drv_status &= ~ADRV_STATUS_PAUSE;
216 }
217 }
218 }
219 pr_debug("%s[%p]:in_bytes %d\n",
220 __func__, audio, atomic_read(&audio->in_bytes));
221 pr_debug("%s[%p]:in_samples %d\n",
222 __func__, audio, atomic_read(&audio->in_samples));
223 atomic_set(&audio->in_bytes, 0);
224 atomic_set(&audio->in_samples, 0);
225 return 0;
226}
227
228static int audio_aio_outport_flush(struct q6audio_aio *audio)
229{
230 int rc;
231
232 rc = q6asm_cmd(audio->ac, CMD_OUT_FLUSH);
233 if (rc < 0)
234 pr_err("%s[%p}: output port flush cmd failed rc=%d\n",
235 __func__, audio, rc);
236 return rc;
237}
238
239/* Write buffer to DSP / Handle Ack from DSP */
240void audio_aio_async_write_ack(struct q6audio_aio *audio, uint32_t token,
241 uint32_t *payload)
242{
243 unsigned long flags;
244 union msm_audio_event_payload event_payload;
245 struct audio_aio_buffer_node *used_buf;
246
247 /* No active flush in progress */
248 if (audio->wflush)
249 return;
250
251 spin_lock_irqsave(&audio->dsp_lock, flags);
252 BUG_ON(list_empty(&audio->out_queue));
253 used_buf = list_first_entry(&audio->out_queue,
254 struct audio_aio_buffer_node, list);
255 if (token == used_buf->token) {
256 list_del(&used_buf->list);
257 spin_unlock_irqrestore(&audio->dsp_lock, flags);
258 pr_debug("%s[%p]:consumed buffer\n", __func__, audio);
259 event_payload.aio_buf = used_buf->buf;
260 audio_aio_post_event(audio, AUDIO_EVENT_WRITE_DONE,
261 event_payload);
262 kfree(used_buf);
263 if (list_empty(&audio->out_queue) &&
264 (audio->drv_status & ADRV_STATUS_FSYNC)) {
Harmandeep Singheaf59b42012-06-05 21:46:02 -0700265 pr_debug("%s[%p]: list is empty, reached EOS in Tunnel\n",
266 __func__, audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530267 wake_up(&audio->write_wait);
268 }
269 } else {
270 pr_err("%s[%p]:expected=%lx ret=%x\n",
271 __func__, audio, used_buf->token, token);
272 spin_unlock_irqrestore(&audio->dsp_lock, flags);
273 }
274}
275
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530276/* ------------------- device --------------------- */
277void audio_aio_async_out_flush(struct q6audio_aio *audio)
278{
279 struct audio_aio_buffer_node *buf_node;
280 struct list_head *ptr, *next;
281 union msm_audio_event_payload payload;
282 unsigned long flags;
283
284 pr_debug("%s[%p}\n", __func__, audio);
285 /* EOS followed by flush, EOS response not guranteed, free EOS i/p
286 buffer */
287 spin_lock_irqsave(&audio->dsp_lock, flags);
288
289 if (audio->eos_flag && (audio->eos_write_payload.aio_buf.buf_addr)) {
290 pr_debug("%s[%p]: EOS followed by flush received,acknowledge"\
291 " eos i/p buffer immediately\n", __func__, audio);
292 audio_aio_post_event(audio, AUDIO_EVENT_WRITE_DONE,
293 audio->eos_write_payload);
294 memset(&audio->eos_write_payload , 0,
295 sizeof(union msm_audio_event_payload));
296 }
297 spin_unlock_irqrestore(&audio->dsp_lock, flags);
298 list_for_each_safe(ptr, next, &audio->out_queue) {
299 buf_node = list_entry(ptr, struct audio_aio_buffer_node, list);
300 list_del(&buf_node->list);
301 payload.aio_buf = buf_node->buf;
302 audio_aio_post_event(audio, AUDIO_EVENT_WRITE_DONE, payload);
303 kfree(buf_node);
304 pr_debug("%s[%p]: Propagate WRITE_DONE during flush\n",
305 __func__, audio);
306 }
307}
308
309void audio_aio_async_in_flush(struct q6audio_aio *audio)
310{
311 struct audio_aio_buffer_node *buf_node;
312 struct list_head *ptr, *next;
313 union msm_audio_event_payload payload;
314
315 pr_debug("%s[%p]\n", __func__, audio);
316 list_for_each_safe(ptr, next, &audio->in_queue) {
317 buf_node = list_entry(ptr, struct audio_aio_buffer_node, list);
318 list_del(&buf_node->list);
319 /* Forcefull send o/p eos buffer after flush, if no eos response
320 * received by dsp even after sending eos command */
321 if ((audio->eos_rsp != 1) && audio->eos_flag) {
Harmandeep Singheaf59b42012-06-05 21:46:02 -0700322 pr_debug("%s[%p]: send eos on o/p buffer during flush\n",
323 __func__, audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530324 payload.aio_buf = buf_node->buf;
325 payload.aio_buf.data_len =
326 insert_eos_buf(audio, buf_node);
327 audio->eos_flag = 0;
328 } else {
329 payload.aio_buf = buf_node->buf;
330 payload.aio_buf.data_len =
331 insert_meta_data_flush(audio, buf_node);
332 }
333 audio_aio_post_event(audio, AUDIO_EVENT_READ_DONE, payload);
334 kfree(buf_node);
335 pr_debug("%s[%p]: Propagate READ_DONE during flush\n",
336 __func__, audio);
337 }
338}
339
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530340int audio_aio_enable(struct q6audio_aio *audio)
341{
342 /* 2nd arg: 0 -> run immediately
343 3rd arg: 0 -> msw_ts, 4th arg: 0 ->lsw_ts */
344 return q6asm_run(audio->ac, 0x00, 0x00, 0x00);
345}
346
347int audio_aio_disable(struct q6audio_aio *audio)
348{
349 int rc = 0;
350 if (audio->opened) {
351 audio->enabled = 0;
352 audio->opened = 0;
353 pr_debug("%s[%p]: inbytes[%d] insamples[%d]\n", __func__,
354 audio, atomic_read(&audio->in_bytes),
355 atomic_read(&audio->in_samples));
356 /* Close the session */
357 rc = q6asm_cmd(audio->ac, CMD_CLOSE);
358 if (rc < 0)
359 pr_err("%s[%p]:Failed to close the session rc=%d\n",
360 __func__, audio, rc);
361 audio->stopped = 1;
362 wake_up(&audio->write_wait);
363 wake_up(&audio->cmd_wait);
364 }
365 pr_debug("%s[%p]:enabled[%d]\n", __func__, audio, audio->enabled);
366 return rc;
367}
368
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530369void audio_aio_reset_ion_region(struct q6audio_aio *audio)
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530370{
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530371 struct audio_aio_ion_region *region;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530372 struct list_head *ptr, *next;
373
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530374 list_for_each_safe(ptr, next, &audio->ion_region_queue) {
375 region = list_entry(ptr, struct audio_aio_ion_region, list);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530376 list_del(&region->list);
Deepa Madiregamaa4795072012-06-15 22:35:52 +0530377 ion_unmap_kernel(audio->client, region->handle);
378 ion_free(audio->client, region->handle);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530379 kfree(region);
380 }
381
382 return;
383}
384
385void audio_aio_reset_event_queue(struct q6audio_aio *audio)
386{
387 unsigned long flags;
388 struct audio_aio_event *drv_evt;
389 struct list_head *ptr, *next;
390
391 spin_lock_irqsave(&audio->event_queue_lock, flags);
392 list_for_each_safe(ptr, next, &audio->event_queue) {
393 drv_evt = list_first_entry(&audio->event_queue,
394 struct audio_aio_event, list);
395 list_del(&drv_evt->list);
396 kfree(drv_evt);
397 }
398 list_for_each_safe(ptr, next, &audio->free_event_queue) {
399 drv_evt = list_first_entry(&audio->free_event_queue,
400 struct audio_aio_event, list);
401 list_del(&drv_evt->list);
402 kfree(drv_evt);
403 }
404 spin_unlock_irqrestore(&audio->event_queue_lock, flags);
405
406 return;
407}
408
Deepa Madiregamaa64fae92012-10-03 16:19:41 +0530409static void audio_aio_unmap_ion_region(struct q6audio_aio *audio)
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530410{
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530411 struct audio_aio_ion_region *region;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530412 struct list_head *ptr, *next;
413 int rc = -EINVAL;
414
415 pr_debug("%s[%p]:\n", __func__, audio);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530416 list_for_each_safe(ptr, next, &audio->ion_region_queue) {
417 region = list_entry(ptr, struct audio_aio_ion_region, list);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530418 pr_debug("%s[%p]: phy_address = 0x%lx\n",
419 __func__, audio, region->paddr);
420 if (region != NULL) {
421 rc = q6asm_memory_unmap(audio->ac,
422 (uint32_t)region->paddr, IN);
423 if (rc < 0)
424 pr_err("%s[%p]: memory unmap failed\n",
425 __func__, audio);
426 }
427 }
428}
429
Sidipotu Ashokbf84d4d2012-11-06 17:13:28 +0530430#ifdef CONFIG_USE_DEV_CTRL_VOLUME
431
432static void audio_aio_listner(u32 evt_id, union auddev_evt_data *evt_payload,
433 void *private_data)
434{
435 struct q6audio_aio *audio = (struct q6audio_aio *) private_data;
436 int rc = 0;
437
438 switch (evt_id) {
439 case AUDDEV_EVT_STREAM_VOL_CHG:
440 audio->volume = evt_payload->session_vol;
441 pr_debug("%s[%p]: AUDDEV_EVT_STREAM_VOL_CHG, stream vol %d, enabled = %d\n",
442 __func__, audio, audio->volume, audio->enabled);
443 if (audio->enabled == 1) {
444 if (audio->ac) {
445 rc = q6asm_set_volume(audio->ac, audio->volume);
446 if (rc < 0) {
447 pr_err("%s[%p]: Send Volume command failed rc=%d\n",
448 __func__, audio, rc);
449 }
450 }
451 }
452 break;
453 default:
454 pr_err("%s[%p]:ERROR:wrong event\n", __func__, audio);
455 break;
456 }
457}
458
459int register_volume_listener(struct q6audio_aio *audio)
460{
461 int rc = 0;
462 audio->device_events = AUDDEV_EVT_STREAM_VOL_CHG;
463 audio->drv_status &= ~ADRV_STATUS_PAUSE;
464
465 rc = auddev_register_evt_listner(audio->device_events,
466 AUDDEV_CLNT_DEC,
467 audio->ac->session,
468 audio_aio_listner,
469 (void *)audio);
470 if (rc < 0) {
471 pr_err("%s[%p]: Event listener failed\n", __func__, audio);
472 rc = -EACCES;
473 }
474 return rc;
475}
476void unregister_volume_listener(struct q6audio_aio *audio)
477{
478 auddev_unregister_evt_listner(AUDDEV_CLNT_DEC, audio->ac->session);
479}
Deepa Madiregamacb6ab2c2012-11-28 12:41:19 +0530480
481int enable_volume_ramp(struct q6audio_aio *audio)
482{
483 int rc = 0;
484 struct asm_softpause_params softpause;
485 struct asm_softvolume_params softvol;
486
487 if (audio->ac == NULL)
488 return -EINVAL;
489 pr_debug("%s[%p]\n", __func__, audio);
490 softpause.enable = SOFT_PAUSE_ENABLE;
491 softpause.period = SOFT_PAUSE_PERIOD;
492 softpause.step = SOFT_PAUSE_STEP;
493 softpause.rampingcurve = SOFT_PAUSE_CURVE_LINEAR;
494
495 softvol.period = SOFT_VOLUME_PERIOD;
496 softvol.step = SOFT_VOLUME_STEP;
497 softvol.rampingcurve = SOFT_VOLUME_CURVE_LINEAR;
498
499 if (softpause.rampingcurve == SOFT_PAUSE_CURVE_LINEAR)
500 softpause.step = SOFT_PAUSE_STEP_LINEAR;
501 if (softvol.rampingcurve == SOFT_VOLUME_CURVE_LINEAR)
502 softvol.step = SOFT_VOLUME_STEP_LINEAR;
503 rc = q6asm_set_volume(audio->ac, audio->volume);
504 if (rc < 0) {
505 pr_err("%s: Send Volume command failed rc=%d\n",
506 __func__, rc);
507 return rc;
508 }
509 rc = q6asm_set_softpause(audio->ac, &softpause);
510 if (rc < 0) {
511 pr_err("%s: Send SoftPause Param failed rc=%d\n",
512 __func__, rc);
513 return rc;
514 }
515 rc = q6asm_set_softvolume(audio->ac, &softvol);
516 if (rc < 0) {
517 pr_err("%s: Send SoftVolume Param failed rc=%d\n",
518 __func__, rc);
519 return rc;
520 }
521 /* disable mute by default */
522 rc = q6asm_set_mute(audio->ac, 0);
523 if (rc < 0) {
524 pr_err("%s: Send mute command failed rc=%d\n",
525 __func__, rc);
526 return rc;
527 }
528 return rc;
529}
530
Sidipotu Ashokbf84d4d2012-11-06 17:13:28 +0530531#else /*CONFIG_USE_DEV_CTRL_VOLUME*/
532int register_volume_listener(struct q6audio_aio *audio)
533{
534 return 0;/* do nothing */
535}
536void unregister_volume_listener(struct q6audio_aio *audio)
537{
538 return;/* do nothing */
539}
Deepa Madiregamacb6ab2c2012-11-28 12:41:19 +0530540int enable_volume_ramp(struct q6audio_aio *audio)
541{
542 return 0; /* do nothing */
543}
Sidipotu Ashokbf84d4d2012-11-06 17:13:28 +0530544#endif /*CONFIG_USE_DEV_CTRL_VOLUME*/
545
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530546int audio_aio_release(struct inode *inode, struct file *file)
547{
548 struct q6audio_aio *audio = file->private_data;
549 pr_debug("%s[%p]\n", __func__, audio);
550 mutex_lock(&audio->lock);
551 audio->wflush = 1;
552 if (audio->enabled)
553 audio_aio_flush(audio);
554 audio->wflush = 0;
555 audio->drv_ops.out_flush(audio);
556 audio->drv_ops.in_flush(audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530557 audio_aio_disable(audio);
Deepa Madiregamaa64fae92012-10-03 16:19:41 +0530558 audio_aio_unmap_ion_region(audio);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530559 audio_aio_reset_ion_region(audio);
Deepa Madiregamaa4795072012-06-15 22:35:52 +0530560 ion_client_destroy(audio->client);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530561 audio->event_abort = 1;
562 wake_up(&audio->event_wait);
563 audio_aio_reset_event_queue(audio);
564 q6asm_audio_client_free(audio->ac);
565 mutex_unlock(&audio->lock);
566 mutex_destroy(&audio->lock);
567 mutex_destroy(&audio->read_lock);
568 mutex_destroy(&audio->write_lock);
569 mutex_destroy(&audio->get_event_lock);
Sidipotu Ashokbf84d4d2012-11-06 17:13:28 +0530570 unregister_volume_listener(audio);
571
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530572#ifdef CONFIG_DEBUG_FS
573 if (audio->dentry)
574 debugfs_remove(audio->dentry);
575#endif
576 kfree(audio->codec_cfg);
577 kfree(audio);
578 return 0;
579}
580
Steve Mucklef132c6c2012-06-06 18:30:57 -0700581int audio_aio_fsync(struct file *file, loff_t start, loff_t end, int datasync)
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530582{
583 int rc = 0;
584 struct q6audio_aio *audio = file->private_data;
585
586 if (!audio->enabled || audio->feedback)
587 return -EINVAL;
588
589 /* Blocking client sends more data */
590 mutex_lock(&audio->lock);
591 audio->drv_status |= ADRV_STATUS_FSYNC;
592 mutex_unlock(&audio->lock);
593
594 pr_debug("%s[%p]:\n", __func__, audio);
595
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530596 audio->eos_rsp = 0;
597
Sidipotu Ashokfe014152012-09-16 18:24:18 +0530598 pr_debug("%s[%p]Wait for write done from DSP\n", __func__, audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530599 rc = wait_event_interruptible(audio->write_wait,
600 (list_empty(&audio->out_queue)) ||
601 audio->wflush || audio->stopped);
602
Sidipotu Ashokfe014152012-09-16 18:24:18 +0530603 if (audio->stopped || audio->wflush) {
604 pr_debug("%s[%p]: Audio Flushed or Stopped,this is not EOS\n"
605 , __func__, audio);
606 audio->wflush = 0;
607 rc = -EBUSY;
608 }
609
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530610 if (rc < 0) {
611 pr_err("%s[%p]: wait event for list_empty failed, rc = %d\n",
612 __func__, audio, rc);
613 goto done;
614 }
615
616 rc = q6asm_cmd(audio->ac, CMD_EOS);
Sidipotu Ashokfe014152012-09-16 18:24:18 +0530617 pr_debug("%s[%p]: EOS cmd sent to DSP\n", __func__, audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530618
619 if (rc < 0)
620 pr_err("%s[%p]: q6asm_cmd failed, rc = %d",
621 __func__, audio, rc);
622
Sidipotu Ashokfe014152012-09-16 18:24:18 +0530623 pr_debug("%s[%p]: wait for RENDERED_EOS from DSP\n"
624 , __func__, audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530625 rc = wait_event_interruptible(audio->write_wait,
626 (audio->eos_rsp || audio->wflush ||
627 audio->stopped));
628
629 if (rc < 0) {
630 pr_err("%s[%p]: wait event for eos_rsp failed, rc = %d\n",
631 __func__, audio, rc);
632 goto done;
633 }
634
Sidipotu Ashokfe014152012-09-16 18:24:18 +0530635 if (audio->stopped || audio->wflush) {
636 audio->wflush = 0;
637 pr_debug("%s[%p]: Audio Flushed or Stopped,this is not EOS\n"
638 , __func__, audio);
639 rc = -EBUSY;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530640 }
641
Sidipotu Ashokfe014152012-09-16 18:24:18 +0530642 if (audio->eos_rsp == 1)
643 pr_debug("%s[%p]: EOS\n", __func__, audio);
644
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530645
646done:
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530647 mutex_lock(&audio->lock);
648 audio->drv_status &= ~ADRV_STATUS_FSYNC;
649 mutex_unlock(&audio->lock);
650
651 return rc;
652}
653
654static int audio_aio_events_pending(struct q6audio_aio *audio)
655{
656 unsigned long flags;
657 int empty;
658
659 spin_lock_irqsave(&audio->event_queue_lock, flags);
660 empty = !list_empty(&audio->event_queue);
661 spin_unlock_irqrestore(&audio->event_queue_lock, flags);
662 return empty || audio->event_abort;
663}
664
665static long audio_aio_process_event_req(struct q6audio_aio *audio,
666 void __user *arg)
667{
668 long rc;
669 struct msm_audio_event usr_evt;
670 struct audio_aio_event *drv_evt = NULL;
671 int timeout;
672 unsigned long flags;
673
674 if (copy_from_user(&usr_evt, arg, sizeof(struct msm_audio_event)))
675 return -EFAULT;
676
677 timeout = (int)usr_evt.timeout_ms;
678
679 if (timeout > 0) {
680 rc = wait_event_interruptible_timeout(audio->event_wait,
681 audio_aio_events_pending
682 (audio),
683 msecs_to_jiffies
684 (timeout));
685 if (rc == 0)
686 return -ETIMEDOUT;
687 } else {
688 rc = wait_event_interruptible(audio->event_wait,
689 audio_aio_events_pending(audio));
690 }
691 if (rc < 0)
692 return rc;
693
694 if (audio->event_abort) {
695 audio->event_abort = 0;
696 return -ENODEV;
697 }
698
699 rc = 0;
700
701 spin_lock_irqsave(&audio->event_queue_lock, flags);
702 if (!list_empty(&audio->event_queue)) {
703 drv_evt = list_first_entry(&audio->event_queue,
704 struct audio_aio_event, list);
705 list_del(&drv_evt->list);
706 }
707 if (drv_evt) {
708 usr_evt.event_type = drv_evt->event_type;
709 usr_evt.event_payload = drv_evt->payload;
710 list_add_tail(&drv_evt->list, &audio->free_event_queue);
711 } else {
712 pr_err("%s[%p]:Unexpected path\n", __func__, audio);
713 spin_unlock_irqrestore(&audio->event_queue_lock, flags);
714 return -EPERM;
715 }
716 spin_unlock_irqrestore(&audio->event_queue_lock, flags);
717
718 if (drv_evt->event_type == AUDIO_EVENT_WRITE_DONE) {
719 pr_debug("%s[%p]:posted AUDIO_EVENT_WRITE_DONE to user\n",
720 __func__, audio);
721 mutex_lock(&audio->write_lock);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530722 audio_aio_ion_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530723 drv_evt->payload.aio_buf.buf_len, 0, 0);
724 mutex_unlock(&audio->write_lock);
725 } else if (drv_evt->event_type == AUDIO_EVENT_READ_DONE) {
726 pr_debug("%s[%p]:posted AUDIO_EVENT_READ_DONE to user\n",
727 __func__, audio);
728 mutex_lock(&audio->read_lock);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530729 audio_aio_ion_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530730 drv_evt->payload.aio_buf.buf_len, 0, 0);
731 mutex_unlock(&audio->read_lock);
732 }
733
734 /* Some read buffer might be held up in DSP,release all
735 * Once EOS indicated
736 */
737 if (audio->eos_rsp && !list_empty(&audio->in_queue)) {
738 pr_debug("%s[%p]:Send flush command to release read buffers"\
739 " held up in DSP\n", __func__, audio);
740 audio_aio_flush(audio);
741 }
742
743 if (copy_to_user(arg, &usr_evt, sizeof(usr_evt)))
744 rc = -EFAULT;
745
746 return rc;
747}
748
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530749static int audio_aio_ion_check(struct q6audio_aio *audio,
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530750 void *vaddr, unsigned long len)
751{
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530752 struct audio_aio_ion_region *region_elt;
753 struct audio_aio_ion_region t = {.vaddr = vaddr, .len = len };
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530754
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530755 list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530756 if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
757 OVERLAPS(region_elt, &t)) {
Harmandeep Singheaf59b42012-06-05 21:46:02 -0700758 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 +0530759 __func__, audio, vaddr, len,
760 region_elt->vaddr,
761 (void *)region_elt->paddr, region_elt->len);
762 return -EINVAL;
763 }
764 }
765
766 return 0;
767}
768
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530769static int audio_aio_ion_add(struct q6audio_aio *audio,
770 struct msm_audio_ion_info *info)
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530771{
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530772 ion_phys_addr_t paddr;
773 size_t len;
774 unsigned long kvaddr;
775 struct audio_aio_ion_region *region;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530776 int rc = -EINVAL;
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530777 struct ion_handle *handle;
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530778 unsigned long ionflag;
779 void *temp_ptr;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530780
781 pr_debug("%s[%p]:\n", __func__, audio);
782 region = kmalloc(sizeof(*region), GFP_KERNEL);
783
784 if (!region) {
785 rc = -ENOMEM;
786 goto end;
787 }
788
Deepa Madiregamaa4795072012-06-15 22:35:52 +0530789 handle = ion_import_dma_buf(audio->client, info->fd);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530790 if (IS_ERR_OR_NULL(handle)) {
791 pr_err("%s: could not get handle of the given fd\n", __func__);
792 goto import_error;
793 }
794
Deepa Madiregamaa4795072012-06-15 22:35:52 +0530795 rc = ion_handle_get_flags(audio->client, handle, &ionflag);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530796 if (rc) {
797 pr_err("%s: could not get flags for the handle\n", __func__);
798 goto flag_error;
799 }
800
Mitchel Humpherys911b4b72012-09-12 14:42:50 -0700801 temp_ptr = ion_map_kernel(audio->client, handle);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530802 if (IS_ERR_OR_NULL(temp_ptr)) {
803 pr_err("%s: could not get virtual address\n", __func__);
804 goto map_error;
805 }
806 kvaddr = (unsigned long)temp_ptr;
807
Deepa Madiregamaa4795072012-06-15 22:35:52 +0530808 rc = ion_phys(audio->client, handle, &paddr, &len);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530809 if (rc) {
810 pr_err("%s: could not get physical address\n", __func__);
811 goto ion_error;
812 }
813
814 rc = audio_aio_ion_check(audio, info->vaddr, len);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530815 if (rc < 0) {
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530816 pr_err("%s: audio_aio_ion_check failed\n", __func__);
817 goto ion_error;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530818 }
819
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530820 region->handle = handle;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530821 region->vaddr = info->vaddr;
822 region->fd = info->fd;
823 region->paddr = paddr;
824 region->kvaddr = kvaddr;
825 region->len = len;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530826 region->ref_cnt = 0;
827 pr_debug("%s[%p]:add region paddr %lx vaddr %p, len %lu kvaddr %lx\n",
828 __func__, audio,
829 region->paddr, region->vaddr, region->len, region->kvaddr);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530830 list_add_tail(&region->list, &audio->ion_region_queue);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530831 rc = q6asm_memory_map(audio->ac, (uint32_t) paddr, IN, (uint32_t) len,
832 1);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530833 if (rc < 0) {
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530834 pr_err("%s[%p]: memory map failed\n", __func__, audio);
Phani Kumar Uppalapatia08ae342013-01-30 14:01:30 -0800835 goto mmap_error;
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530836 } else {
837 goto end;
838 }
Phani Kumar Uppalapatia08ae342013-01-30 14:01:30 -0800839mmap_error:
840 list_del(&region->list);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530841ion_error:
Deepa Madiregamaa4795072012-06-15 22:35:52 +0530842 ion_unmap_kernel(audio->client, handle);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530843map_error:
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530844flag_error:
Deepa Madiregamaa4795072012-06-15 22:35:52 +0530845 ion_free(audio->client, handle);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530846import_error:
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530847 kfree(region);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530848end:
849 return rc;
850}
851
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530852static int audio_aio_ion_remove(struct q6audio_aio *audio,
853 struct msm_audio_ion_info *info)
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530854{
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530855 struct audio_aio_ion_region *region;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530856 struct list_head *ptr, *next;
857 int rc = -EINVAL;
858
859 pr_debug("%s[%p]:info fd %d vaddr %p\n",
860 __func__, audio, info->fd, info->vaddr);
861
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530862 list_for_each_safe(ptr, next, &audio->ion_region_queue) {
863 region = list_entry(ptr, struct audio_aio_ion_region, list);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530864
865 if ((region->fd == info->fd) &&
866 (region->vaddr == info->vaddr)) {
867 if (region->ref_cnt) {
868 pr_debug("%s[%p]:region %p in use ref_cnt %d\n",
869 __func__, audio, region,
870 region->ref_cnt);
871 break;
872 }
873 pr_debug("%s[%p]:remove region fd %d vaddr %p\n",
874 __func__, audio, info->fd, info->vaddr);
875 rc = q6asm_memory_unmap(audio->ac,
876 (uint32_t) region->paddr, IN);
877 if (rc < 0)
878 pr_err("%s[%p]: memory unmap failed\n",
879 __func__, audio);
880
881 list_del(&region->list);
Deepa Madiregamaa4795072012-06-15 22:35:52 +0530882 ion_unmap_kernel(audio->client, region->handle);
883 ion_free(audio->client, region->handle);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530884 kfree(region);
885 rc = 0;
886 break;
887 }
888 }
889
890 return rc;
891}
892
893static void audio_aio_async_write(struct q6audio_aio *audio,
894 struct audio_aio_buffer_node *buf_node)
895{
896 int rc;
897 struct audio_client *ac;
898 struct audio_aio_write_param param;
899
Harmandeep Singheaf59b42012-06-05 21:46:02 -0700900 pr_debug("%s[%p]: Send write buff %p phy %lx len %d meta_enable = %d\n",
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530901 __func__, audio, buf_node, buf_node->paddr,
902 buf_node->buf.data_len,
903 audio->buf_cfg.meta_info_enable);
Swaminathan Sathappan08508ac2012-10-11 19:51:25 -0700904 pr_debug("%s[%p]: flags = 0x%x\n", __func__, audio,
905 buf_node->meta_info.meta_in.nflags);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530906
907 ac = audio->ac;
908 /* Offset with appropriate meta */
Karthik Reddy Katta6f09ac92012-04-23 15:04:38 +0530909 if (audio->feedback) {
910 /* Non Tunnel mode */
911 param.paddr = buf_node->paddr + sizeof(struct dec_meta_in);
912 param.len = buf_node->buf.data_len - sizeof(struct dec_meta_in);
913 } else {
914 /* Tunnel mode */
915 param.paddr = buf_node->paddr;
916 param.len = buf_node->buf.data_len;
917 }
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530918 param.msw_ts = buf_node->meta_info.meta_in.ntimestamp.highpart;
919 param.lsw_ts = buf_node->meta_info.meta_in.ntimestamp.lowpart;
Preetam Singh Ranawat5bd5fd32013-01-03 14:42:53 +0530920 param.flags = buf_node->meta_info.meta_in.nflags;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530921 /* If no meta_info enaled, indicate no time stamp valid */
Preetam Singh Ranawat5bd5fd32013-01-03 14:42:53 +0530922 if (!audio->buf_cfg.meta_info_enable)
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530923 param.flags = 0xFF00;
Swaminathan Sathappan08508ac2012-10-11 19:51:25 -0700924
925 if ((buf_node != NULL) &&
926 (buf_node->meta_info.meta_in.nflags & AUDIO_DEC_EOF_SET))
927 param.flags |= AUDIO_DEC_EOF_SET;
928
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530929 param.uid = param.paddr;
930 /* Read command will populate paddr as token */
931 buf_node->token = param.paddr;
932 rc = q6asm_async_write(ac, &param);
933 if (rc < 0)
934 pr_err("%s[%p]:failed\n", __func__, audio);
935}
936
937void audio_aio_post_event(struct q6audio_aio *audio, int type,
938 union msm_audio_event_payload payload)
939{
940 struct audio_aio_event *e_node = NULL;
941 unsigned long flags;
942
943 spin_lock_irqsave(&audio->event_queue_lock, flags);
944
945 if (!list_empty(&audio->free_event_queue)) {
946 e_node = list_first_entry(&audio->free_event_queue,
947 struct audio_aio_event, list);
948 list_del(&e_node->list);
949 } else {
950 e_node = kmalloc(sizeof(struct audio_aio_event), GFP_ATOMIC);
951 if (!e_node) {
952 pr_err("%s[%p]:No mem to post event %d\n",
953 __func__, audio, type);
954 spin_unlock_irqrestore(&audio->event_queue_lock, flags);
955 return;
956 }
957 }
958
959 e_node->event_type = type;
960 e_node->payload = payload;
961
962 list_add_tail(&e_node->list, &audio->event_queue);
963 spin_unlock_irqrestore(&audio->event_queue_lock, flags);
964 wake_up(&audio->event_wait);
965}
966
967static void audio_aio_async_read(struct q6audio_aio *audio,
968 struct audio_aio_buffer_node *buf_node)
969{
970 struct audio_client *ac;
971 struct audio_aio_read_param param;
972 int rc;
973
974 pr_debug("%s[%p]: Send read buff %p phy %lx len %d\n",
975 __func__, audio, buf_node,
976 buf_node->paddr, buf_node->buf.buf_len);
977 ac = audio->ac;
978 /* Provide address so driver can append nr frames information */
979 param.paddr = buf_node->paddr +
980 sizeof(struct dec_meta_out);
981 param.len = buf_node->buf.buf_len -
982 sizeof(struct dec_meta_out);
983 param.uid = param.paddr;
984 /* Write command will populate paddr as token */
985 buf_node->token = param.paddr;
986 rc = q6asm_async_read(ac, &param);
987 if (rc < 0)
988 pr_err("%s[%p]:failed\n", __func__, audio);
989}
990
991static int audio_aio_buf_add(struct q6audio_aio *audio, unsigned dir,
992 void __user *arg)
993{
994 unsigned long flags;
995 struct audio_aio_buffer_node *buf_node;
996
997
998 buf_node = kzalloc(sizeof(*buf_node), GFP_KERNEL);
999
1000 if (!buf_node)
1001 return -ENOMEM;
1002
1003 if (copy_from_user(&buf_node->buf, arg, sizeof(buf_node->buf))) {
1004 kfree(buf_node);
1005 return -EFAULT;
1006 }
1007
Harmandeep Singheaf59b42012-06-05 21:46:02 -07001008 pr_debug("%s[%p]:node %p dir %x buf_addr %p buf_len %d data_len %d\n",
1009 __func__, audio, buf_node, dir, buf_node->buf.buf_addr,
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301010 buf_node->buf.buf_len, buf_node->buf.data_len);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +05301011 buf_node->paddr = audio_aio_ion_fixup(audio, buf_node->buf.buf_addr,
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301012 buf_node->buf.buf_len, 1,
1013 &buf_node->kvaddr);
1014 if (dir) {
1015 /* write */
1016 if (!buf_node->paddr ||
1017 (buf_node->paddr & 0x1) ||
1018 (!audio->feedback && !buf_node->buf.data_len)) {
1019 kfree(buf_node);
1020 return -EINVAL;
1021 }
1022 extract_meta_out_info(audio, buf_node, 1);
1023 /* Not a EOS buffer */
1024 if (!(buf_node->meta_info.meta_in.nflags & AUDIO_DEC_EOS_SET)) {
1025 spin_lock_irqsave(&audio->dsp_lock, flags);
1026 audio_aio_async_write(audio, buf_node);
1027 /* EOS buffer handled in driver */
1028 list_add_tail(&buf_node->list, &audio->out_queue);
1029 spin_unlock_irqrestore(&audio->dsp_lock, flags);
Preetam Singh Ranawat6aae2412011-11-04 18:16:27 +05301030 } else if (buf_node->meta_info.meta_in.nflags
1031 & AUDIO_DEC_EOS_SET) {
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301032 if (!audio->wflush) {
1033 pr_debug("%s[%p]:Send EOS cmd at i/p\n",
1034 __func__, audio);
1035 /* Driver will forcefully post writedone event
1036 * once eos ack recived from DSP
1037 */
1038 audio->eos_write_payload.aio_buf =\
1039 buf_node->buf;
1040 audio->eos_flag = 1;
1041 audio->eos_rsp = 0;
1042 q6asm_cmd(audio->ac, CMD_EOS);
1043 kfree(buf_node);
1044 } else { /* Flush in progress, send back i/p
1045 * EOS buffer as is
1046 */
1047 union msm_audio_event_payload event_payload;
1048 event_payload.aio_buf = buf_node->buf;
1049 audio_aio_post_event(audio,
1050 AUDIO_EVENT_WRITE_DONE,
1051 event_payload);
1052 kfree(buf_node);
1053 }
1054 }
1055 } else {
1056 /* read */
1057 if (!buf_node->paddr ||
1058 (buf_node->paddr & 0x1) ||
1059 (buf_node->buf.buf_len < PCM_BUFSZ_MIN)) {
1060 kfree(buf_node);
1061 return -EINVAL;
1062 }
1063 /* No EOS reached */
1064 if (!audio->eos_rsp) {
1065 spin_lock_irqsave(&audio->dsp_lock, flags);
1066 audio_aio_async_read(audio, buf_node);
1067 /* EOS buffer handled in driver */
1068 list_add_tail(&buf_node->list, &audio->in_queue);
1069 spin_unlock_irqrestore(&audio->dsp_lock, flags);
1070 }
1071 /* EOS reached at input side fake all upcoming read buffer to
1072 * indicate the same
1073 */
1074 else {
1075 union msm_audio_event_payload event_payload;
1076 event_payload.aio_buf = buf_node->buf;
1077 event_payload.aio_buf.data_len =
1078 insert_eos_buf(audio, buf_node);
1079 pr_debug("%s[%p]: propagate READ_DONE as EOS done\n",\
1080 __func__, audio);
1081 audio_aio_post_event(audio, AUDIO_EVENT_READ_DONE,
1082 event_payload);
1083 kfree(buf_node);
1084 }
1085 }
1086 return 0;
1087}
1088
Deepa Madiregama75d0b932012-11-28 14:57:43 +05301089void audio_aio_ioport_reset(struct q6audio_aio *audio)
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301090{
1091 if (audio->drv_status & ADRV_STATUS_AIO_INTF) {
1092 /* If fsync is in progress, make sure
1093 * return value of fsync indicates
1094 * abort due to flush
1095 */
1096 if (audio->drv_status & ADRV_STATUS_FSYNC) {
1097 pr_debug("%s[%p]:fsync in progress\n", __func__, audio);
1098 audio->drv_ops.out_flush(audio);
1099 } else
1100 audio->drv_ops.out_flush(audio);
Sidipotu Ashokfe014152012-09-16 18:24:18 +05301101 if (audio->feedback == NON_TUNNEL_MODE)
1102 audio->drv_ops.in_flush(audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301103 }
1104}
1105
1106int audio_aio_open(struct q6audio_aio *audio, struct file *file)
1107{
1108 int rc = 0;
1109 int i;
1110 struct audio_aio_event *e_node = NULL;
1111
1112 /* Settings will be re-config at AUDIO_SET_CONFIG,
1113 * but at least we need to have initial config
1114 */
1115 audio->str_cfg.buffer_size = FRAME_SIZE;
1116 audio->str_cfg.buffer_count = FRAME_NUM;
1117 audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
1118 audio->pcm_cfg.sample_rate = 48000;
1119 audio->pcm_cfg.channel_count = 2;
1120
1121 /* Only AIO interface */
1122 if (file->f_flags & O_NONBLOCK) {
1123 pr_debug("%s[%p]:set to aio interface\n", __func__, audio);
1124 audio->drv_status |= ADRV_STATUS_AIO_INTF;
1125 audio->drv_ops.out_flush = audio_aio_async_out_flush;
1126 audio->drv_ops.in_flush = audio_aio_async_in_flush;
1127 q6asm_set_io_mode(audio->ac, ASYNC_IO_MODE);
1128 } else {
1129 pr_err("%s[%p]:SIO interface not supported\n",
1130 __func__, audio);
1131 rc = -EACCES;
1132 goto fail;
1133 }
1134
1135 /* Initialize all locks of audio instance */
1136 mutex_init(&audio->lock);
1137 mutex_init(&audio->read_lock);
1138 mutex_init(&audio->write_lock);
1139 mutex_init(&audio->get_event_lock);
1140 spin_lock_init(&audio->dsp_lock);
1141 spin_lock_init(&audio->event_queue_lock);
1142 init_waitqueue_head(&audio->cmd_wait);
1143 init_waitqueue_head(&audio->write_wait);
1144 init_waitqueue_head(&audio->event_wait);
1145 INIT_LIST_HEAD(&audio->out_queue);
1146 INIT_LIST_HEAD(&audio->in_queue);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +05301147 INIT_LIST_HEAD(&audio->ion_region_queue);
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301148 INIT_LIST_HEAD(&audio->free_event_queue);
1149 INIT_LIST_HEAD(&audio->event_queue);
1150
1151 audio->drv_ops.out_flush(audio);
1152 audio->opened = 1;
1153 file->private_data = audio;
1154 audio->codec_ioctl = audio_aio_ioctl;
1155
Mingming Yinc09967e2012-04-27 15:09:43 -07001156 for (i = 0; i < AUDIO_EVENT_NUM; i++) {
1157 e_node = kmalloc(sizeof(struct audio_aio_event), GFP_KERNEL);
1158 if (e_node)
1159 list_add_tail(&e_node->list, &audio->free_event_queue);
1160 else {
1161 pr_err("%s[%p]:event pkt alloc failed\n",
1162 __func__, audio);
1163 break;
1164 }
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301165 }
Deepa Madiregamaa4795072012-06-15 22:35:52 +05301166 audio->client = msm_ion_client_create(UINT_MAX, "Audio_Dec_Client");
1167 if (IS_ERR_OR_NULL(audio->client)) {
1168 pr_err("Unable to create ION client\n");
1169 rc = -EACCES;
1170 goto fail;
1171 }
1172 pr_debug("Ion client create in audio_aio_open %p", audio->client);
Sidipotu Ashokbf84d4d2012-11-06 17:13:28 +05301173
1174 rc = register_volume_listener(audio);
1175 if (rc < 0)
1176 goto fail;
1177
Mingming Yinc09967e2012-04-27 15:09:43 -07001178 return 0;
Sidipotu Ashokbf84d4d2012-11-06 17:13:28 +05301179
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301180fail:
Mingming Yinc09967e2012-04-27 15:09:43 -07001181 q6asm_audio_client_free(audio->ac);
1182 kfree(audio->codec_cfg);
1183 kfree(audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301184 return rc;
1185}
1186
1187long audio_aio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
1188{
1189 struct q6audio_aio *audio = file->private_data;
1190 int rc = 0;
1191
1192 switch (cmd) {
1193 case AUDIO_GET_STATS: {
1194 struct msm_audio_stats stats;
Sidipotu Ashok388cdc52012-09-16 16:59:16 +05301195 uint64_t timestamp;
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301196 stats.byte_count = atomic_read(&audio->in_bytes);
1197 stats.sample_count = atomic_read(&audio->in_samples);
Patrick Laifc8f2242013-01-06 00:52:34 -08001198 rc = q6asm_get_session_time(audio->ac, &timestamp);
1199 if (rc >= 0)
Sidipotu Ashok388cdc52012-09-16 16:59:16 +05301200 memcpy(&stats.unused[0], &timestamp, sizeof(timestamp));
1201 else
1202 pr_debug("Error while getting timestamp\n");
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301203 if (copy_to_user((void *)arg, &stats, sizeof(stats)))
1204 rc = -EFAULT;
1205 break;
1206 }
1207 case AUDIO_GET_EVENT: {
1208 pr_debug("%s[%p]:AUDIO_GET_EVENT\n", __func__, audio);
1209 if (mutex_trylock(&audio->get_event_lock)) {
1210 rc = audio_aio_process_event_req(audio,
1211 (void __user *)arg);
1212 mutex_unlock(&audio->get_event_lock);
1213 } else
1214 rc = -EBUSY;
1215 break;
1216 }
1217 case AUDIO_ABORT_GET_EVENT: {
1218 audio->event_abort = 1;
1219 wake_up(&audio->event_wait);
1220 break;
1221 }
1222 case AUDIO_ASYNC_WRITE: {
1223 mutex_lock(&audio->write_lock);
1224 if (audio->drv_status & ADRV_STATUS_FSYNC)
1225 rc = -EBUSY;
1226 else {
1227 if (audio->enabled)
1228 rc = audio_aio_buf_add(audio, 1,
1229 (void __user *)arg);
1230 else
1231 rc = -EPERM;
1232 }
1233 mutex_unlock(&audio->write_lock);
1234 break;
1235 }
1236 case AUDIO_ASYNC_READ: {
1237 mutex_lock(&audio->read_lock);
1238 if ((audio->feedback) && (audio->enabled))
1239 rc = audio_aio_buf_add(audio, 0,
1240 (void __user *)arg);
1241 else
1242 rc = -EPERM;
1243 mutex_unlock(&audio->read_lock);
1244 break;
1245 }
1246 case AUDIO_OUTPORT_FLUSH: {
1247 pr_debug("%s[%p]:AUDIO_OUTPORT_FLUSH\n", __func__, audio);
1248 mutex_lock(&audio->read_lock);
1249 rc = audio_aio_outport_flush(audio);
1250 if (rc < 0) {
1251 pr_err("%s[%p]: AUDIO_OUTPORT_FLUSH failed\n",
1252 __func__, audio);
1253 rc = -EINTR;
1254 }
1255 mutex_unlock(&audio->read_lock);
1256 break;
1257 }
1258 case AUDIO_STOP: {
1259 pr_debug("%s[%p]: AUDIO_STOP session_id[%d]\n", __func__,
1260 audio, audio->ac->session);
1261 mutex_lock(&audio->lock);
1262 audio->stopped = 1;
Deepa Madiregama75d0b932012-11-28 14:57:43 +05301263 rc = audio_aio_flush(audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301264 if (rc < 0) {
1265 pr_err("%s[%p]:Audio Stop procedure failed rc=%d\n",
1266 __func__, audio, rc);
1267 mutex_unlock(&audio->lock);
1268 break;
1269 }
Deepa Madiregama75d0b932012-11-28 14:57:43 +05301270 audio->enabled = 0;
1271 audio->drv_status &= ~ADRV_STATUS_PAUSE;
Deepa Madiregama900d3572012-11-28 15:48:48 +05301272 if (audio->drv_status & ADRV_STATUS_FSYNC) {
1273 pr_debug("%s[%p] Waking up the audio_aio_fsync\n",
1274 __func__, audio);
1275 wake_up(&audio->write_wait);
1276 }
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301277 mutex_unlock(&audio->lock);
1278 break;
1279 }
1280 case AUDIO_PAUSE: {
1281 pr_debug("%s[%p]:AUDIO_PAUSE %ld\n", __func__, audio, arg);
1282 mutex_lock(&audio->lock);
1283 if (arg == 1) {
1284 rc = audio_aio_pause(audio);
Laxminath Kasam92ad28c2012-09-03 13:47:33 +05301285 if (rc < 0) {
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301286 pr_err("%s[%p]: pause FAILED rc=%d\n",
1287 __func__, audio, rc);
Laxminath Kasam92ad28c2012-09-03 13:47:33 +05301288 mutex_unlock(&audio->lock);
1289 break;
1290 }
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301291 audio->drv_status |= ADRV_STATUS_PAUSE;
1292 } else if (arg == 0) {
1293 if (audio->drv_status & ADRV_STATUS_PAUSE) {
1294 rc = audio_aio_enable(audio);
1295 if (rc)
1296 pr_err("%s[%p]: audio enable failed\n",
1297 __func__, audio);
1298 else {
1299 audio->drv_status &= ~ADRV_STATUS_PAUSE;
1300 audio->enabled = 1;
1301 }
1302 }
1303 }
1304 mutex_unlock(&audio->lock);
1305 break;
1306 }
1307 case AUDIO_FLUSH: {
1308 pr_debug("%s[%p]: AUDIO_FLUSH sessionid[%d]\n", __func__,
1309 audio, audio->ac->session);
1310 mutex_lock(&audio->lock);
1311 audio->rflush = 1;
1312 audio->wflush = 1;
Deepa Madiregama900d3572012-11-28 15:48:48 +05301313 if (audio->drv_status & ADRV_STATUS_FSYNC) {
1314 pr_debug("%s[%p] Waking up the audio_aio_fsync\n",
1315 __func__, audio);
1316 wake_up(&audio->write_wait);
1317 }
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301318 /* Flush DSP */
1319 rc = audio_aio_flush(audio);
Amal Paul765cb102013-02-16 15:44:31 -08001320 /* Flush input / Output buffer in software*/
1321 audio_aio_ioport_reset(audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301322 if (rc < 0) {
1323 pr_err("%s[%p]:AUDIO_FLUSH interrupted\n",
1324 __func__, audio);
1325 rc = -EINTR;
1326 } else {
1327 audio->rflush = 0;
Sidipotu Ashokfe014152012-09-16 18:24:18 +05301328 if (audio->drv_status & ADRV_STATUS_FSYNC)
1329 wake_up(&audio->write_wait);
1330 else
1331 audio->wflush = 0;
1332
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301333 }
1334 audio->eos_flag = 0;
1335 audio->eos_rsp = 0;
1336 mutex_unlock(&audio->lock);
1337 break;
1338 }
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +05301339 case AUDIO_REGISTER_ION: {
1340 struct msm_audio_ion_info info;
1341 pr_debug("%s[%p]:AUDIO_REGISTER_ION\n", __func__, audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301342 mutex_lock(&audio->lock);
1343 if (copy_from_user(&info, (void *)arg, sizeof(info)))
1344 rc = -EFAULT;
1345 else
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +05301346 rc = audio_aio_ion_add(audio, &info);
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301347 mutex_unlock(&audio->lock);
1348 break;
1349 }
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +05301350 case AUDIO_DEREGISTER_ION: {
1351 struct msm_audio_ion_info info;
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301352 mutex_lock(&audio->lock);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +05301353 pr_debug("%s[%p]:AUDIO_DEREGISTER_ION\n", __func__, audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301354 if (copy_from_user(&info, (void *)arg, sizeof(info)))
1355 rc = -EFAULT;
1356 else
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +05301357 rc = audio_aio_ion_remove(audio, &info);
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301358 mutex_unlock(&audio->lock);
1359 break;
1360 }
1361 case AUDIO_GET_STREAM_CONFIG: {
1362 struct msm_audio_stream_config cfg;
1363 mutex_lock(&audio->lock);
1364 memset(&cfg, 0, sizeof(cfg));
1365 cfg.buffer_size = audio->str_cfg.buffer_size;
1366 cfg.buffer_count = audio->str_cfg.buffer_count;
1367 pr_debug("%s[%p]:GET STREAM CFG %d %d\n",
1368 __func__, audio, cfg.buffer_size, cfg.buffer_count);
1369 if (copy_to_user((void *)arg, &cfg, sizeof(cfg)))
1370 rc = -EFAULT;
1371 mutex_unlock(&audio->lock);
1372 break;
1373 }
1374 case AUDIO_SET_STREAM_CONFIG: {
1375 struct msm_audio_stream_config cfg;
1376 pr_debug("%s[%p]:SET STREAM CONFIG\n", __func__, audio);
1377 mutex_lock(&audio->lock);
1378 if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
1379 rc = -EFAULT;
1380 mutex_unlock(&audio->lock);
1381 break;
1382 }
1383 audio->str_cfg.buffer_size = FRAME_SIZE;
1384 audio->str_cfg.buffer_count = FRAME_NUM;
1385 rc = 0;
1386 mutex_unlock(&audio->lock);
1387 break;
1388 }
1389 case AUDIO_GET_CONFIG: {
1390 struct msm_audio_config cfg;
1391 mutex_lock(&audio->lock);
1392 if (copy_to_user((void *)arg, &audio->pcm_cfg, sizeof(cfg)))
1393 rc = -EFAULT;
1394 mutex_unlock(&audio->lock);
1395 break;
1396 }
1397 case AUDIO_SET_CONFIG: {
1398 struct msm_audio_config config;
1399 pr_err("%s[%p]:AUDIO_SET_CONFIG\n", __func__, audio);
1400 mutex_lock(&audio->lock);
1401 if (copy_from_user(&config, (void *)arg, sizeof(config))) {
1402 rc = -EFAULT;
1403 mutex_unlock(&audio->lock);
1404 break;
1405 }
1406 if (audio->feedback != NON_TUNNEL_MODE) {
Harmandeep Singheaf59b42012-06-05 21:46:02 -07001407 pr_err("%s[%p]:Not sufficient permission to change the playback mode\n",
1408 __func__, audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301409 rc = -EACCES;
1410 mutex_unlock(&audio->lock);
1411 break;
1412 }
1413 if ((config.buffer_count > PCM_BUF_COUNT) ||
1414 (config.buffer_count == 1))
1415 config.buffer_count = PCM_BUF_COUNT;
1416
1417 if (config.buffer_size < PCM_BUFSZ_MIN)
1418 config.buffer_size = PCM_BUFSZ_MIN;
1419
1420 audio->pcm_cfg.buffer_count = config.buffer_count;
1421 audio->pcm_cfg.buffer_size = config.buffer_size;
1422 audio->pcm_cfg.channel_count = config.channel_count;
1423 audio->pcm_cfg.sample_rate = config.sample_rate;
1424 rc = 0;
1425 mutex_unlock(&audio->lock);
1426 break;
1427 }
1428 case AUDIO_SET_BUF_CFG: {
1429 struct msm_audio_buf_cfg cfg;
1430 mutex_lock(&audio->lock);
1431 if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
1432 rc = -EFAULT;
1433 mutex_unlock(&audio->lock);
1434 break;
1435 }
1436 if ((audio->feedback == NON_TUNNEL_MODE) &&
1437 !cfg.meta_info_enable) {
1438 rc = -EFAULT;
1439 mutex_unlock(&audio->lock);
1440 break;
1441 }
1442
1443 audio->buf_cfg.meta_info_enable = cfg.meta_info_enable;
1444 pr_debug("%s[%p]:session id %d: Set-buf-cfg: meta[%d]",
1445 __func__, audio,
1446 audio->ac->session, cfg.meta_info_enable);
1447 mutex_unlock(&audio->lock);
1448 break;
1449 }
1450 case AUDIO_GET_BUF_CFG: {
Harmandeep Singheaf59b42012-06-05 21:46:02 -07001451 pr_debug("%s[%p]:session id %d: Get-buf-cfg: meta[%d] framesperbuf[%d]\n",
1452 __func__, audio,
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301453 audio->ac->session, audio->buf_cfg.meta_info_enable,
1454 audio->buf_cfg.frames_per_buf);
1455
1456 mutex_lock(&audio->lock);
1457 if (copy_to_user((void *)arg, &audio->buf_cfg,
1458 sizeof(struct msm_audio_buf_cfg)))
1459 rc = -EFAULT;
1460 mutex_unlock(&audio->lock);
1461 break;
1462 }
1463 case AUDIO_GET_SESSION_ID: {
1464 mutex_lock(&audio->lock);
1465 if (copy_to_user((void *)arg, &audio->ac->session,
1466 sizeof(unsigned short))) {
1467 rc = -EFAULT;
1468 }
1469 mutex_unlock(&audio->lock);
1470 break;
1471 }
1472 default:
1473 rc = -EINVAL;
1474 }
1475 return rc;
1476}