blob: a1463bc9b88f45af38bb302dd29a8b5d32d055f6 [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>
Fred Ohde9438a2013-04-04 11:29:12 -070027#include <linux/msm_audio_ion.h>
Deepa Madiregama55cbf782011-09-10 05:44:39 +053028#include "audio_utils_aio.h"
Sidipotu Ashokbf84d4d2012-11-06 17:13:28 +053029#ifdef CONFIG_USE_DEV_CTRL_VOLUME
30#include <mach/qdsp6v2/audio_dev_ctl.h>
31#endif /*CONFIG_USE_DEV_CTRL_VOLUME*/
Deepa Madiregama55cbf782011-09-10 05:44:39 +053032
33#ifdef CONFIG_DEBUG_FS
34ssize_t audio_aio_debug_open(struct inode *inode, struct file *file)
35{
36 file->private_data = inode->i_private;
37 return 0;
38}
39
Harmandeep Singheaf59b42012-06-05 21:46:02 -070040ssize_t audio_aio_debug_read(struct file *file, char __user *buf,
Deepa Madiregama55cbf782011-09-10 05:44:39 +053041 size_t count, loff_t *ppos)
42{
43 const int debug_bufmax = 4096;
44 static char buffer[4096];
45 int n = 0;
46 struct q6audio_aio *audio = file->private_data;
47
48 mutex_lock(&audio->lock);
49 n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
50 n += scnprintf(buffer + n, debug_bufmax - n,
51 "enabled %d\n", audio->enabled);
52 n += scnprintf(buffer + n, debug_bufmax - n,
53 "stopped %d\n", audio->stopped);
54 n += scnprintf(buffer + n, debug_bufmax - n,
55 "feedback %d\n", audio->feedback);
56 mutex_unlock(&audio->lock);
57 /* Following variables are only useful for debugging when
58 * when playback halts unexpectedly. Thus, no mutual exclusion
59 * enforced
60 */
61 n += scnprintf(buffer + n, debug_bufmax - n,
62 "wflush %d\n", audio->wflush);
63 n += scnprintf(buffer + n, debug_bufmax - n,
64 "rflush %d\n", audio->rflush);
65 n += scnprintf(buffer + n, debug_bufmax - n,
66 "inqueue empty %d\n", list_empty(&audio->in_queue));
67 n += scnprintf(buffer + n, debug_bufmax - n,
68 "outqueue empty %d\n", list_empty(&audio->out_queue));
69 buffer[n] = 0;
70 return simple_read_from_buffer(buf, count, ppos, buffer, n);
71}
72#endif
73
Harmandeep Singheaf59b42012-06-05 21:46:02 -070074int insert_eos_buf(struct q6audio_aio *audio,
Deepa Madiregama55cbf782011-09-10 05:44:39 +053075 struct audio_aio_buffer_node *buf_node)
76{
77 struct dec_meta_out *eos_buf = buf_node->kvaddr;
78 pr_debug("%s[%p]:insert_eos_buf\n", __func__, audio);
79 eos_buf->num_of_frames = 0xFFFFFFFF;
80 eos_buf->meta_out_dsp[0].offset_to_frame = 0x0;
81 eos_buf->meta_out_dsp[0].nflags = AUDIO_DEC_EOS_SET;
82 return sizeof(struct dec_meta_out) +
83 sizeof(eos_buf->meta_out_dsp[0]);
84}
85
86/* Routine which updates read buffers of driver/dsp,
87 for flush operation as DSP output might not have proper
88 value set */
89static int insert_meta_data_flush(struct q6audio_aio *audio,
90 struct audio_aio_buffer_node *buf_node)
91{
92 struct dec_meta_out *meta_data = buf_node->kvaddr;
93 meta_data->num_of_frames = 0x0;
94 meta_data->meta_out_dsp[0].offset_to_frame = 0x0;
95 meta_data->meta_out_dsp[0].nflags = 0x0;
96 return sizeof(struct dec_meta_out) +
97 sizeof(meta_data->meta_out_dsp[0]);
98}
99
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530100static int audio_aio_ion_lookup_vaddr(struct q6audio_aio *audio, void *addr,
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530101 unsigned long len,
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530102 struct audio_aio_ion_region **region)
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530103{
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530104 struct audio_aio_ion_region *region_elt;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530105
106 int match_count = 0;
107
108 *region = NULL;
109
110 /* returns physical address or zero */
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530111 list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530112 if (addr >= region_elt->vaddr &&
113 addr < region_elt->vaddr + region_elt->len &&
114 addr + len <= region_elt->vaddr + region_elt->len) {
115 /* offset since we could pass vaddr inside a registerd
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530116 * ion buffer
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530117 */
118
119 match_count++;
120 if (!*region)
121 *region = region_elt;
122 }
123 }
124
125 if (match_count > 1) {
126 pr_err("%s[%p]:multiple hits for vaddr %p, len %ld\n",
127 __func__, audio, addr, len);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530128 list_for_each_entry(region_elt, &audio->ion_region_queue,
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530129 list) {
130 if (addr >= region_elt->vaddr &&
131 addr < region_elt->vaddr + region_elt->len &&
132 addr + len <= region_elt->vaddr + region_elt->len)
133 pr_err("\t%s[%p]:%p, %ld --> %p\n",
134 __func__, audio,
135 region_elt->vaddr,
136 region_elt->len,
137 (void *)region_elt->paddr);
138 }
139 }
140
141 return *region ? 0 : -1;
142}
143
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530144static unsigned long audio_aio_ion_fixup(struct q6audio_aio *audio, void *addr,
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530145 unsigned long len, int ref_up, void **kvaddr)
146{
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530147 struct audio_aio_ion_region *region;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530148 unsigned long paddr;
149 int ret;
150
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530151 ret = audio_aio_ion_lookup_vaddr(audio, addr, len, &region);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530152 if (ret) {
153 pr_err("%s[%p]:lookup (%p, %ld) failed\n",
154 __func__, audio, addr, len);
155 return 0;
156 }
157 if (ref_up)
158 region->ref_cnt++;
159 else
160 region->ref_cnt--;
161 pr_debug("%s[%p]:found region %p ref_cnt %d\n",
162 __func__, audio, region, region->ref_cnt);
163 paddr = region->paddr + (addr - region->vaddr);
164 /* provide kernel virtual address for accessing meta information */
165 if (kvaddr)
166 *kvaddr = (void *) (region->kvaddr + (addr - region->vaddr));
167 return paddr;
168}
169
170static int audio_aio_pause(struct q6audio_aio *audio)
171{
Laxminath Kasam92ad28c2012-09-03 13:47:33 +0530172 int rc = -EINVAL;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530173
174 pr_debug("%s[%p], enabled = %d\n", __func__, audio,
175 audio->enabled);
176 if (audio->enabled) {
177 rc = q6asm_cmd(audio->ac, CMD_PAUSE);
178 if (rc < 0)
179 pr_err("%s[%p]: pause cmd failed rc=%d\n",
180 __func__, audio, rc);
181
182 } else
183 pr_err("%s[%p]: Driver not enabled\n", __func__, audio);
184 return rc;
185}
186
187static int audio_aio_flush(struct q6audio_aio *audio)
188{
189 int rc;
190
191 if (audio->enabled) {
192 /* Implicitly issue a pause to the decoder before flushing if
193 it is not in pause state */
194 if (!(audio->drv_status & ADRV_STATUS_PAUSE)) {
195 rc = audio_aio_pause(audio);
196 if (rc < 0)
197 pr_err("%s[%p}: pause cmd failed rc=%d\n",
198 __func__, audio,
199 rc);
200 else
201 audio->drv_status |= ADRV_STATUS_PAUSE;
202 }
203 rc = q6asm_cmd(audio->ac, CMD_FLUSH);
204 if (rc < 0)
205 pr_err("%s[%p]: flush cmd failed rc=%d\n",
206 __func__, audio, rc);
207 /* Not in stop state, reenable the stream */
208 if (audio->stopped == 0) {
209 rc = audio_aio_enable(audio);
210 if (rc)
211 pr_err("%s[%p]:audio re-enable failed\n",
212 __func__, audio);
213 else {
214 audio->enabled = 1;
215 if (audio->drv_status & ADRV_STATUS_PAUSE)
216 audio->drv_status &= ~ADRV_STATUS_PAUSE;
217 }
218 }
219 }
220 pr_debug("%s[%p]:in_bytes %d\n",
221 __func__, audio, atomic_read(&audio->in_bytes));
222 pr_debug("%s[%p]:in_samples %d\n",
223 __func__, audio, atomic_read(&audio->in_samples));
224 atomic_set(&audio->in_bytes, 0);
225 atomic_set(&audio->in_samples, 0);
226 return 0;
227}
228
229static int audio_aio_outport_flush(struct q6audio_aio *audio)
230{
231 int rc;
232
233 rc = q6asm_cmd(audio->ac, CMD_OUT_FLUSH);
234 if (rc < 0)
235 pr_err("%s[%p}: output port flush cmd failed rc=%d\n",
236 __func__, audio, rc);
237 return rc;
238}
239
240/* Write buffer to DSP / Handle Ack from DSP */
241void audio_aio_async_write_ack(struct q6audio_aio *audio, uint32_t token,
242 uint32_t *payload)
243{
244 unsigned long flags;
245 union msm_audio_event_payload event_payload;
246 struct audio_aio_buffer_node *used_buf;
247
248 /* No active flush in progress */
249 if (audio->wflush)
250 return;
251
252 spin_lock_irqsave(&audio->dsp_lock, flags);
Gopikrishnaiah Anandanec9ba3e2013-07-15 20:07:50 -0400253 if (list_empty(&audio->out_queue)) {
254 pr_warning("%s: ingore unexpected event from dsp\n", __func__);
255 spin_unlock_irqrestore(&audio->dsp_lock, flags);
256 return;
257 }
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530258 used_buf = list_first_entry(&audio->out_queue,
259 struct audio_aio_buffer_node, list);
260 if (token == used_buf->token) {
261 list_del(&used_buf->list);
262 spin_unlock_irqrestore(&audio->dsp_lock, flags);
263 pr_debug("%s[%p]:consumed buffer\n", __func__, audio);
264 event_payload.aio_buf = used_buf->buf;
265 audio_aio_post_event(audio, AUDIO_EVENT_WRITE_DONE,
266 event_payload);
267 kfree(used_buf);
268 if (list_empty(&audio->out_queue) &&
269 (audio->drv_status & ADRV_STATUS_FSYNC)) {
Harmandeep Singheaf59b42012-06-05 21:46:02 -0700270 pr_debug("%s[%p]: list is empty, reached EOS in Tunnel\n",
271 __func__, audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530272 wake_up(&audio->write_wait);
273 }
274 } else {
275 pr_err("%s[%p]:expected=%lx ret=%x\n",
276 __func__, audio, used_buf->token, token);
277 spin_unlock_irqrestore(&audio->dsp_lock, flags);
278 }
279}
280
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530281/* ------------------- device --------------------- */
282void audio_aio_async_out_flush(struct q6audio_aio *audio)
283{
284 struct audio_aio_buffer_node *buf_node;
285 struct list_head *ptr, *next;
286 union msm_audio_event_payload payload;
287 unsigned long flags;
288
289 pr_debug("%s[%p}\n", __func__, audio);
290 /* EOS followed by flush, EOS response not guranteed, free EOS i/p
291 buffer */
292 spin_lock_irqsave(&audio->dsp_lock, flags);
293
294 if (audio->eos_flag && (audio->eos_write_payload.aio_buf.buf_addr)) {
295 pr_debug("%s[%p]: EOS followed by flush received,acknowledge"\
296 " eos i/p buffer immediately\n", __func__, audio);
297 audio_aio_post_event(audio, AUDIO_EVENT_WRITE_DONE,
298 audio->eos_write_payload);
299 memset(&audio->eos_write_payload , 0,
300 sizeof(union msm_audio_event_payload));
301 }
302 spin_unlock_irqrestore(&audio->dsp_lock, flags);
303 list_for_each_safe(ptr, next, &audio->out_queue) {
304 buf_node = list_entry(ptr, struct audio_aio_buffer_node, list);
305 list_del(&buf_node->list);
306 payload.aio_buf = buf_node->buf;
307 audio_aio_post_event(audio, AUDIO_EVENT_WRITE_DONE, payload);
308 kfree(buf_node);
309 pr_debug("%s[%p]: Propagate WRITE_DONE during flush\n",
310 __func__, audio);
311 }
312}
313
314void audio_aio_async_in_flush(struct q6audio_aio *audio)
315{
316 struct audio_aio_buffer_node *buf_node;
317 struct list_head *ptr, *next;
318 union msm_audio_event_payload payload;
319
320 pr_debug("%s[%p]\n", __func__, audio);
321 list_for_each_safe(ptr, next, &audio->in_queue) {
322 buf_node = list_entry(ptr, struct audio_aio_buffer_node, list);
323 list_del(&buf_node->list);
324 /* Forcefull send o/p eos buffer after flush, if no eos response
325 * received by dsp even after sending eos command */
326 if ((audio->eos_rsp != 1) && audio->eos_flag) {
Harmandeep Singheaf59b42012-06-05 21:46:02 -0700327 pr_debug("%s[%p]: send eos on o/p buffer during flush\n",
328 __func__, audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530329 payload.aio_buf = buf_node->buf;
330 payload.aio_buf.data_len =
331 insert_eos_buf(audio, buf_node);
332 audio->eos_flag = 0;
333 } else {
334 payload.aio_buf = buf_node->buf;
335 payload.aio_buf.data_len =
336 insert_meta_data_flush(audio, buf_node);
337 }
338 audio_aio_post_event(audio, AUDIO_EVENT_READ_DONE, payload);
339 kfree(buf_node);
340 pr_debug("%s[%p]: Propagate READ_DONE during flush\n",
341 __func__, audio);
342 }
343}
344
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530345int audio_aio_enable(struct q6audio_aio *audio)
346{
347 /* 2nd arg: 0 -> run immediately
348 3rd arg: 0 -> msw_ts, 4th arg: 0 ->lsw_ts */
349 return q6asm_run(audio->ac, 0x00, 0x00, 0x00);
350}
351
352int audio_aio_disable(struct q6audio_aio *audio)
353{
354 int rc = 0;
355 if (audio->opened) {
356 audio->enabled = 0;
357 audio->opened = 0;
358 pr_debug("%s[%p]: inbytes[%d] insamples[%d]\n", __func__,
359 audio, atomic_read(&audio->in_bytes),
360 atomic_read(&audio->in_samples));
361 /* Close the session */
362 rc = q6asm_cmd(audio->ac, CMD_CLOSE);
363 if (rc < 0)
364 pr_err("%s[%p]:Failed to close the session rc=%d\n",
365 __func__, audio, rc);
366 audio->stopped = 1;
367 wake_up(&audio->write_wait);
368 wake_up(&audio->cmd_wait);
369 }
370 pr_debug("%s[%p]:enabled[%d]\n", __func__, audio, audio->enabled);
371 return rc;
372}
373
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530374void audio_aio_reset_ion_region(struct q6audio_aio *audio)
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530375{
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530376 struct audio_aio_ion_region *region;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530377 struct list_head *ptr, *next;
378
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530379 list_for_each_safe(ptr, next, &audio->ion_region_queue) {
380 region = list_entry(ptr, struct audio_aio_ion_region, list);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530381 list_del(&region->list);
Fred Ohde9438a2013-04-04 11:29:12 -0700382 msm_audio_ion_free_legacy(audio->client, region->handle);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530383 kfree(region);
384 }
385
386 return;
387}
388
389void audio_aio_reset_event_queue(struct q6audio_aio *audio)
390{
391 unsigned long flags;
392 struct audio_aio_event *drv_evt;
393 struct list_head *ptr, *next;
394
395 spin_lock_irqsave(&audio->event_queue_lock, flags);
396 list_for_each_safe(ptr, next, &audio->event_queue) {
397 drv_evt = list_first_entry(&audio->event_queue,
398 struct audio_aio_event, list);
399 list_del(&drv_evt->list);
400 kfree(drv_evt);
401 }
402 list_for_each_safe(ptr, next, &audio->free_event_queue) {
403 drv_evt = list_first_entry(&audio->free_event_queue,
404 struct audio_aio_event, list);
405 list_del(&drv_evt->list);
406 kfree(drv_evt);
407 }
408 spin_unlock_irqrestore(&audio->event_queue_lock, flags);
409
410 return;
411}
412
Deepa Madiregamaa64fae92012-10-03 16:19:41 +0530413static void audio_aio_unmap_ion_region(struct q6audio_aio *audio)
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530414{
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530415 struct audio_aio_ion_region *region;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530416 struct list_head *ptr, *next;
417 int rc = -EINVAL;
418
419 pr_debug("%s[%p]:\n", __func__, audio);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530420 list_for_each_safe(ptr, next, &audio->ion_region_queue) {
421 region = list_entry(ptr, struct audio_aio_ion_region, list);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530422 pr_debug("%s[%p]: phy_address = 0x%lx\n",
423 __func__, audio, region->paddr);
424 if (region != NULL) {
425 rc = q6asm_memory_unmap(audio->ac,
426 (uint32_t)region->paddr, IN);
427 if (rc < 0)
428 pr_err("%s[%p]: memory unmap failed\n",
429 __func__, audio);
430 }
431 }
432}
433
Sidipotu Ashokbf84d4d2012-11-06 17:13:28 +0530434#ifdef CONFIG_USE_DEV_CTRL_VOLUME
435
436static void audio_aio_listner(u32 evt_id, union auddev_evt_data *evt_payload,
437 void *private_data)
438{
439 struct q6audio_aio *audio = (struct q6audio_aio *) private_data;
440 int rc = 0;
441
442 switch (evt_id) {
443 case AUDDEV_EVT_STREAM_VOL_CHG:
444 audio->volume = evt_payload->session_vol;
445 pr_debug("%s[%p]: AUDDEV_EVT_STREAM_VOL_CHG, stream vol %d, enabled = %d\n",
446 __func__, audio, audio->volume, audio->enabled);
447 if (audio->enabled == 1) {
448 if (audio->ac) {
449 rc = q6asm_set_volume(audio->ac, audio->volume);
450 if (rc < 0) {
451 pr_err("%s[%p]: Send Volume command failed rc=%d\n",
452 __func__, audio, rc);
453 }
454 }
455 }
456 break;
457 default:
458 pr_err("%s[%p]:ERROR:wrong event\n", __func__, audio);
459 break;
460 }
461}
462
463int register_volume_listener(struct q6audio_aio *audio)
464{
465 int rc = 0;
466 audio->device_events = AUDDEV_EVT_STREAM_VOL_CHG;
467 audio->drv_status &= ~ADRV_STATUS_PAUSE;
468
469 rc = auddev_register_evt_listner(audio->device_events,
470 AUDDEV_CLNT_DEC,
471 audio->ac->session,
472 audio_aio_listner,
473 (void *)audio);
474 if (rc < 0) {
475 pr_err("%s[%p]: Event listener failed\n", __func__, audio);
476 rc = -EACCES;
477 }
478 return rc;
479}
480void unregister_volume_listener(struct q6audio_aio *audio)
481{
482 auddev_unregister_evt_listner(AUDDEV_CLNT_DEC, audio->ac->session);
483}
Deepa Madiregamacb6ab2c2012-11-28 12:41:19 +0530484
485int enable_volume_ramp(struct q6audio_aio *audio)
486{
487 int rc = 0;
488 struct asm_softpause_params softpause;
489 struct asm_softvolume_params softvol;
490
491 if (audio->ac == NULL)
492 return -EINVAL;
493 pr_debug("%s[%p]\n", __func__, audio);
494 softpause.enable = SOFT_PAUSE_ENABLE;
495 softpause.period = SOFT_PAUSE_PERIOD;
496 softpause.step = SOFT_PAUSE_STEP;
497 softpause.rampingcurve = SOFT_PAUSE_CURVE_LINEAR;
498
499 softvol.period = SOFT_VOLUME_PERIOD;
500 softvol.step = SOFT_VOLUME_STEP;
501 softvol.rampingcurve = SOFT_VOLUME_CURVE_LINEAR;
502
503 if (softpause.rampingcurve == SOFT_PAUSE_CURVE_LINEAR)
504 softpause.step = SOFT_PAUSE_STEP_LINEAR;
505 if (softvol.rampingcurve == SOFT_VOLUME_CURVE_LINEAR)
506 softvol.step = SOFT_VOLUME_STEP_LINEAR;
507 rc = q6asm_set_volume(audio->ac, audio->volume);
508 if (rc < 0) {
509 pr_err("%s: Send Volume command failed rc=%d\n",
510 __func__, rc);
511 return rc;
512 }
513 rc = q6asm_set_softpause(audio->ac, &softpause);
514 if (rc < 0) {
515 pr_err("%s: Send SoftPause Param failed rc=%d\n",
516 __func__, rc);
517 return rc;
518 }
519 rc = q6asm_set_softvolume(audio->ac, &softvol);
520 if (rc < 0) {
521 pr_err("%s: Send SoftVolume Param failed rc=%d\n",
522 __func__, rc);
523 return rc;
524 }
525 /* disable mute by default */
526 rc = q6asm_set_mute(audio->ac, 0);
527 if (rc < 0) {
528 pr_err("%s: Send mute command failed rc=%d\n",
529 __func__, rc);
530 return rc;
531 }
532 return rc;
533}
534
Sidipotu Ashokbf84d4d2012-11-06 17:13:28 +0530535#else /*CONFIG_USE_DEV_CTRL_VOLUME*/
536int register_volume_listener(struct q6audio_aio *audio)
537{
538 return 0;/* do nothing */
539}
540void unregister_volume_listener(struct q6audio_aio *audio)
541{
542 return;/* do nothing */
543}
Deepa Madiregamacb6ab2c2012-11-28 12:41:19 +0530544int enable_volume_ramp(struct q6audio_aio *audio)
545{
546 return 0; /* do nothing */
547}
Sidipotu Ashokbf84d4d2012-11-06 17:13:28 +0530548#endif /*CONFIG_USE_DEV_CTRL_VOLUME*/
549
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530550int audio_aio_release(struct inode *inode, struct file *file)
551{
552 struct q6audio_aio *audio = file->private_data;
553 pr_debug("%s[%p]\n", __func__, audio);
554 mutex_lock(&audio->lock);
555 audio->wflush = 1;
556 if (audio->enabled)
557 audio_aio_flush(audio);
558 audio->wflush = 0;
559 audio->drv_ops.out_flush(audio);
560 audio->drv_ops.in_flush(audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530561 audio_aio_disable(audio);
Deepa Madiregamaa64fae92012-10-03 16:19:41 +0530562 audio_aio_unmap_ion_region(audio);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530563 audio_aio_reset_ion_region(audio);
Fred Ohde9438a2013-04-04 11:29:12 -0700564 msm_audio_ion_client_destroy(audio->client);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530565 audio->event_abort = 1;
566 wake_up(&audio->event_wait);
567 audio_aio_reset_event_queue(audio);
568 q6asm_audio_client_free(audio->ac);
569 mutex_unlock(&audio->lock);
570 mutex_destroy(&audio->lock);
571 mutex_destroy(&audio->read_lock);
572 mutex_destroy(&audio->write_lock);
573 mutex_destroy(&audio->get_event_lock);
Sidipotu Ashokbf84d4d2012-11-06 17:13:28 +0530574 unregister_volume_listener(audio);
575
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530576#ifdef CONFIG_DEBUG_FS
577 if (audio->dentry)
578 debugfs_remove(audio->dentry);
579#endif
580 kfree(audio->codec_cfg);
581 kfree(audio);
582 return 0;
583}
584
Steve Mucklef132c6c2012-06-06 18:30:57 -0700585int audio_aio_fsync(struct file *file, loff_t start, loff_t end, int datasync)
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530586{
587 int rc = 0;
588 struct q6audio_aio *audio = file->private_data;
589
590 if (!audio->enabled || audio->feedback)
591 return -EINVAL;
592
593 /* Blocking client sends more data */
594 mutex_lock(&audio->lock);
595 audio->drv_status |= ADRV_STATUS_FSYNC;
596 mutex_unlock(&audio->lock);
597
598 pr_debug("%s[%p]:\n", __func__, audio);
599
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530600 audio->eos_rsp = 0;
601
Sidipotu Ashokfe014152012-09-16 18:24:18 +0530602 pr_debug("%s[%p]Wait for write done from DSP\n", __func__, audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530603 rc = wait_event_interruptible(audio->write_wait,
604 (list_empty(&audio->out_queue)) ||
605 audio->wflush || audio->stopped);
606
Sidipotu Ashokfe014152012-09-16 18:24:18 +0530607 if (audio->stopped || audio->wflush) {
608 pr_debug("%s[%p]: Audio Flushed or Stopped,this is not EOS\n"
609 , __func__, audio);
610 audio->wflush = 0;
611 rc = -EBUSY;
612 }
613
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530614 if (rc < 0) {
615 pr_err("%s[%p]: wait event for list_empty failed, rc = %d\n",
616 __func__, audio, rc);
617 goto done;
618 }
619
620 rc = q6asm_cmd(audio->ac, CMD_EOS);
Sidipotu Ashokfe014152012-09-16 18:24:18 +0530621 pr_debug("%s[%p]: EOS cmd sent to DSP\n", __func__, audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530622
623 if (rc < 0)
624 pr_err("%s[%p]: q6asm_cmd failed, rc = %d",
625 __func__, audio, rc);
626
Sidipotu Ashokfe014152012-09-16 18:24:18 +0530627 pr_debug("%s[%p]: wait for RENDERED_EOS from DSP\n"
628 , __func__, audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530629 rc = wait_event_interruptible(audio->write_wait,
630 (audio->eos_rsp || audio->wflush ||
631 audio->stopped));
632
633 if (rc < 0) {
634 pr_err("%s[%p]: wait event for eos_rsp failed, rc = %d\n",
635 __func__, audio, rc);
636 goto done;
637 }
638
Sidipotu Ashokfe014152012-09-16 18:24:18 +0530639 if (audio->stopped || audio->wflush) {
640 audio->wflush = 0;
641 pr_debug("%s[%p]: Audio Flushed or Stopped,this is not EOS\n"
642 , __func__, audio);
643 rc = -EBUSY;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530644 }
645
Sidipotu Ashokfe014152012-09-16 18:24:18 +0530646 if (audio->eos_rsp == 1)
647 pr_debug("%s[%p]: EOS\n", __func__, audio);
648
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530649
650done:
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530651 mutex_lock(&audio->lock);
652 audio->drv_status &= ~ADRV_STATUS_FSYNC;
653 mutex_unlock(&audio->lock);
654
655 return rc;
656}
657
658static int audio_aio_events_pending(struct q6audio_aio *audio)
659{
660 unsigned long flags;
661 int empty;
662
663 spin_lock_irqsave(&audio->event_queue_lock, flags);
664 empty = !list_empty(&audio->event_queue);
665 spin_unlock_irqrestore(&audio->event_queue_lock, flags);
666 return empty || audio->event_abort;
667}
668
669static long audio_aio_process_event_req(struct q6audio_aio *audio,
670 void __user *arg)
671{
672 long rc;
673 struct msm_audio_event usr_evt;
674 struct audio_aio_event *drv_evt = NULL;
675 int timeout;
676 unsigned long flags;
677
678 if (copy_from_user(&usr_evt, arg, sizeof(struct msm_audio_event)))
679 return -EFAULT;
680
681 timeout = (int)usr_evt.timeout_ms;
682
683 if (timeout > 0) {
684 rc = wait_event_interruptible_timeout(audio->event_wait,
685 audio_aio_events_pending
686 (audio),
687 msecs_to_jiffies
688 (timeout));
689 if (rc == 0)
690 return -ETIMEDOUT;
691 } else {
692 rc = wait_event_interruptible(audio->event_wait,
693 audio_aio_events_pending(audio));
694 }
695 if (rc < 0)
696 return rc;
697
698 if (audio->event_abort) {
699 audio->event_abort = 0;
700 return -ENODEV;
701 }
702
703 rc = 0;
704
705 spin_lock_irqsave(&audio->event_queue_lock, flags);
706 if (!list_empty(&audio->event_queue)) {
707 drv_evt = list_first_entry(&audio->event_queue,
708 struct audio_aio_event, list);
709 list_del(&drv_evt->list);
710 }
711 if (drv_evt) {
712 usr_evt.event_type = drv_evt->event_type;
713 usr_evt.event_payload = drv_evt->payload;
714 list_add_tail(&drv_evt->list, &audio->free_event_queue);
715 } else {
716 pr_err("%s[%p]:Unexpected path\n", __func__, audio);
717 spin_unlock_irqrestore(&audio->event_queue_lock, flags);
718 return -EPERM;
719 }
720 spin_unlock_irqrestore(&audio->event_queue_lock, flags);
721
722 if (drv_evt->event_type == AUDIO_EVENT_WRITE_DONE) {
723 pr_debug("%s[%p]:posted AUDIO_EVENT_WRITE_DONE to user\n",
724 __func__, audio);
725 mutex_lock(&audio->write_lock);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530726 audio_aio_ion_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530727 drv_evt->payload.aio_buf.buf_len, 0, 0);
728 mutex_unlock(&audio->write_lock);
729 } else if (drv_evt->event_type == AUDIO_EVENT_READ_DONE) {
730 pr_debug("%s[%p]:posted AUDIO_EVENT_READ_DONE to user\n",
731 __func__, audio);
732 mutex_lock(&audio->read_lock);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530733 audio_aio_ion_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530734 drv_evt->payload.aio_buf.buf_len, 0, 0);
735 mutex_unlock(&audio->read_lock);
736 }
737
738 /* Some read buffer might be held up in DSP,release all
739 * Once EOS indicated
740 */
741 if (audio->eos_rsp && !list_empty(&audio->in_queue)) {
742 pr_debug("%s[%p]:Send flush command to release read buffers"\
743 " held up in DSP\n", __func__, audio);
744 audio_aio_flush(audio);
745 }
746
747 if (copy_to_user(arg, &usr_evt, sizeof(usr_evt)))
748 rc = -EFAULT;
749
750 return rc;
751}
752
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530753static int audio_aio_ion_check(struct q6audio_aio *audio,
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530754 void *vaddr, unsigned long len)
755{
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530756 struct audio_aio_ion_region *region_elt;
757 struct audio_aio_ion_region t = {.vaddr = vaddr, .len = len };
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530758
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530759 list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530760 if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
761 OVERLAPS(region_elt, &t)) {
Harmandeep Singheaf59b42012-06-05 21:46:02 -0700762 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 +0530763 __func__, audio, vaddr, len,
764 region_elt->vaddr,
765 (void *)region_elt->paddr, region_elt->len);
766 return -EINVAL;
767 }
768 }
769
770 return 0;
771}
772
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530773static int audio_aio_ion_add(struct q6audio_aio *audio,
774 struct msm_audio_ion_info *info)
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530775{
Fred Oh312f30d2013-04-08 10:57:17 -0700776 ion_phys_addr_t paddr = 0;
777 size_t len = 0;
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530778 struct audio_aio_ion_region *region;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530779 int rc = -EINVAL;
Fred Oh312f30d2013-04-08 10:57:17 -0700780 struct ion_handle *handle = NULL;
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530781 unsigned long ionflag;
Fred Oh312f30d2013-04-08 10:57:17 -0700782 void *kvaddr = NULL;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530783
784 pr_debug("%s[%p]:\n", __func__, audio);
785 region = kmalloc(sizeof(*region), GFP_KERNEL);
786
787 if (!region) {
788 rc = -ENOMEM;
789 goto end;
790 }
791
Fred Ohde9438a2013-04-04 11:29:12 -0700792 rc = msm_audio_ion_import_legacy("Audio_Dec_Client", audio->client,
793 &handle, info->fd, &ionflag,
794 0, &paddr, &len, &kvaddr);
795 if (rc) {
796 pr_err("%s: msm audio ion alloc failed\n", __func__);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530797 goto import_error;
798 }
799
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530800 rc = audio_aio_ion_check(audio, info->vaddr, len);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530801 if (rc < 0) {
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530802 pr_err("%s: audio_aio_ion_check failed\n", __func__);
803 goto ion_error;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530804 }
805
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530806 region->handle = handle;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530807 region->vaddr = info->vaddr;
808 region->fd = info->fd;
809 region->paddr = paddr;
Fred Ohde9438a2013-04-04 11:29:12 -0700810 region->kvaddr = (unsigned long)kvaddr;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530811 region->len = len;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530812 region->ref_cnt = 0;
813 pr_debug("%s[%p]:add region paddr %lx vaddr %p, len %lu kvaddr %lx\n",
814 __func__, audio,
815 region->paddr, region->vaddr, region->len, region->kvaddr);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530816 list_add_tail(&region->list, &audio->ion_region_queue);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530817 rc = q6asm_memory_map(audio->ac, (uint32_t) paddr, IN, (uint32_t) len,
818 1);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530819 if (rc < 0) {
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530820 pr_err("%s[%p]: memory map failed\n", __func__, audio);
Phani Kumar Uppalapatia08ae342013-01-30 14:01:30 -0800821 goto mmap_error;
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530822 } else {
823 goto end;
824 }
Phani Kumar Uppalapatia08ae342013-01-30 14:01:30 -0800825mmap_error:
826 list_del(&region->list);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530827ion_error:
Fred Ohde9438a2013-04-04 11:29:12 -0700828 msm_audio_ion_free_legacy(audio->client, handle);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530829import_error:
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530830 kfree(region);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530831end:
832 return rc;
833}
834
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530835static int audio_aio_ion_remove(struct q6audio_aio *audio,
836 struct msm_audio_ion_info *info)
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530837{
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530838 struct audio_aio_ion_region *region;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530839 struct list_head *ptr, *next;
840 int rc = -EINVAL;
841
842 pr_debug("%s[%p]:info fd %d vaddr %p\n",
843 __func__, audio, info->fd, info->vaddr);
844
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530845 list_for_each_safe(ptr, next, &audio->ion_region_queue) {
846 region = list_entry(ptr, struct audio_aio_ion_region, list);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530847
848 if ((region->fd == info->fd) &&
849 (region->vaddr == info->vaddr)) {
850 if (region->ref_cnt) {
851 pr_debug("%s[%p]:region %p in use ref_cnt %d\n",
852 __func__, audio, region,
853 region->ref_cnt);
854 break;
855 }
856 pr_debug("%s[%p]:remove region fd %d vaddr %p\n",
857 __func__, audio, info->fd, info->vaddr);
858 rc = q6asm_memory_unmap(audio->ac,
859 (uint32_t) region->paddr, IN);
860 if (rc < 0)
861 pr_err("%s[%p]: memory unmap failed\n",
862 __func__, audio);
863
864 list_del(&region->list);
Fred Ohde9438a2013-04-04 11:29:12 -0700865 msm_audio_ion_free_legacy(audio->client,
866 region->handle);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530867 kfree(region);
868 rc = 0;
869 break;
870 }
871 }
872
873 return rc;
874}
875
876static void audio_aio_async_write(struct q6audio_aio *audio,
877 struct audio_aio_buffer_node *buf_node)
878{
879 int rc;
880 struct audio_client *ac;
881 struct audio_aio_write_param param;
882
Fred Oh21963aa2013-02-21 11:43:56 -0800883 if (!audio || !buf_node) {
884 pr_err("%s NULL pointer audio=[0x%p], buf_node=[0x%p]\n",
885 __func__, audio, buf_node);
886 return;
887 }
Harmandeep Singheaf59b42012-06-05 21:46:02 -0700888 pr_debug("%s[%p]: Send write buff %p phy %lx len %d meta_enable = %d\n",
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530889 __func__, audio, buf_node, buf_node->paddr,
890 buf_node->buf.data_len,
891 audio->buf_cfg.meta_info_enable);
Swaminathan Sathappan08508ac2012-10-11 19:51:25 -0700892 pr_debug("%s[%p]: flags = 0x%x\n", __func__, audio,
893 buf_node->meta_info.meta_in.nflags);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530894
895 ac = audio->ac;
896 /* Offset with appropriate meta */
Karthik Reddy Katta6f09ac92012-04-23 15:04:38 +0530897 if (audio->feedback) {
898 /* Non Tunnel mode */
899 param.paddr = buf_node->paddr + sizeof(struct dec_meta_in);
900 param.len = buf_node->buf.data_len - sizeof(struct dec_meta_in);
901 } else {
902 /* Tunnel mode */
903 param.paddr = buf_node->paddr;
904 param.len = buf_node->buf.data_len;
905 }
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530906 param.msw_ts = buf_node->meta_info.meta_in.ntimestamp.highpart;
907 param.lsw_ts = buf_node->meta_info.meta_in.ntimestamp.lowpart;
Preetam Singh Ranawat5bd5fd32013-01-03 14:42:53 +0530908 param.flags = buf_node->meta_info.meta_in.nflags;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530909 /* If no meta_info enaled, indicate no time stamp valid */
Preetam Singh Ranawat5bd5fd32013-01-03 14:42:53 +0530910 if (!audio->buf_cfg.meta_info_enable)
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530911 param.flags = 0xFF00;
Swaminathan Sathappan08508ac2012-10-11 19:51:25 -0700912
Fred Oh21963aa2013-02-21 11:43:56 -0800913 if (buf_node->meta_info.meta_in.nflags & AUDIO_DEC_EOF_SET)
Swaminathan Sathappan08508ac2012-10-11 19:51:25 -0700914 param.flags |= AUDIO_DEC_EOF_SET;
915
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530916 param.uid = param.paddr;
917 /* Read command will populate paddr as token */
918 buf_node->token = param.paddr;
919 rc = q6asm_async_write(ac, &param);
920 if (rc < 0)
921 pr_err("%s[%p]:failed\n", __func__, audio);
922}
923
924void audio_aio_post_event(struct q6audio_aio *audio, int type,
925 union msm_audio_event_payload payload)
926{
927 struct audio_aio_event *e_node = NULL;
928 unsigned long flags;
929
930 spin_lock_irqsave(&audio->event_queue_lock, flags);
931
932 if (!list_empty(&audio->free_event_queue)) {
933 e_node = list_first_entry(&audio->free_event_queue,
934 struct audio_aio_event, list);
935 list_del(&e_node->list);
936 } else {
937 e_node = kmalloc(sizeof(struct audio_aio_event), GFP_ATOMIC);
938 if (!e_node) {
939 pr_err("%s[%p]:No mem to post event %d\n",
940 __func__, audio, type);
941 spin_unlock_irqrestore(&audio->event_queue_lock, flags);
942 return;
943 }
944 }
945
946 e_node->event_type = type;
947 e_node->payload = payload;
948
949 list_add_tail(&e_node->list, &audio->event_queue);
950 spin_unlock_irqrestore(&audio->event_queue_lock, flags);
951 wake_up(&audio->event_wait);
952}
953
954static void audio_aio_async_read(struct q6audio_aio *audio,
955 struct audio_aio_buffer_node *buf_node)
956{
957 struct audio_client *ac;
958 struct audio_aio_read_param param;
959 int rc;
960
961 pr_debug("%s[%p]: Send read buff %p phy %lx len %d\n",
962 __func__, audio, buf_node,
963 buf_node->paddr, buf_node->buf.buf_len);
964 ac = audio->ac;
965 /* Provide address so driver can append nr frames information */
966 param.paddr = buf_node->paddr +
967 sizeof(struct dec_meta_out);
968 param.len = buf_node->buf.buf_len -
969 sizeof(struct dec_meta_out);
970 param.uid = param.paddr;
971 /* Write command will populate paddr as token */
972 buf_node->token = param.paddr;
973 rc = q6asm_async_read(ac, &param);
974 if (rc < 0)
975 pr_err("%s[%p]:failed\n", __func__, audio);
976}
977
978static int audio_aio_buf_add(struct q6audio_aio *audio, unsigned dir,
979 void __user *arg)
980{
981 unsigned long flags;
982 struct audio_aio_buffer_node *buf_node;
983
984
985 buf_node = kzalloc(sizeof(*buf_node), GFP_KERNEL);
986
987 if (!buf_node)
988 return -ENOMEM;
989
990 if (copy_from_user(&buf_node->buf, arg, sizeof(buf_node->buf))) {
991 kfree(buf_node);
992 return -EFAULT;
993 }
994
Harmandeep Singheaf59b42012-06-05 21:46:02 -0700995 pr_debug("%s[%p]:node %p dir %x buf_addr %p buf_len %d data_len %d\n",
996 __func__, audio, buf_node, dir, buf_node->buf.buf_addr,
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530997 buf_node->buf.buf_len, buf_node->buf.data_len);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530998 buf_node->paddr = audio_aio_ion_fixup(audio, buf_node->buf.buf_addr,
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530999 buf_node->buf.buf_len, 1,
1000 &buf_node->kvaddr);
1001 if (dir) {
1002 /* write */
1003 if (!buf_node->paddr ||
1004 (buf_node->paddr & 0x1) ||
1005 (!audio->feedback && !buf_node->buf.data_len)) {
1006 kfree(buf_node);
1007 return -EINVAL;
1008 }
1009 extract_meta_out_info(audio, buf_node, 1);
1010 /* Not a EOS buffer */
1011 if (!(buf_node->meta_info.meta_in.nflags & AUDIO_DEC_EOS_SET)) {
1012 spin_lock_irqsave(&audio->dsp_lock, flags);
1013 audio_aio_async_write(audio, buf_node);
1014 /* EOS buffer handled in driver */
1015 list_add_tail(&buf_node->list, &audio->out_queue);
1016 spin_unlock_irqrestore(&audio->dsp_lock, flags);
Preetam Singh Ranawat6aae2412011-11-04 18:16:27 +05301017 } else if (buf_node->meta_info.meta_in.nflags
1018 & AUDIO_DEC_EOS_SET) {
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301019 if (!audio->wflush) {
1020 pr_debug("%s[%p]:Send EOS cmd at i/p\n",
1021 __func__, audio);
1022 /* Driver will forcefully post writedone event
1023 * once eos ack recived from DSP
1024 */
1025 audio->eos_write_payload.aio_buf =\
1026 buf_node->buf;
1027 audio->eos_flag = 1;
1028 audio->eos_rsp = 0;
1029 q6asm_cmd(audio->ac, CMD_EOS);
1030 kfree(buf_node);
1031 } else { /* Flush in progress, send back i/p
1032 * EOS buffer as is
1033 */
1034 union msm_audio_event_payload event_payload;
1035 event_payload.aio_buf = buf_node->buf;
1036 audio_aio_post_event(audio,
1037 AUDIO_EVENT_WRITE_DONE,
1038 event_payload);
1039 kfree(buf_node);
1040 }
1041 }
1042 } else {
1043 /* read */
1044 if (!buf_node->paddr ||
1045 (buf_node->paddr & 0x1) ||
1046 (buf_node->buf.buf_len < PCM_BUFSZ_MIN)) {
1047 kfree(buf_node);
1048 return -EINVAL;
1049 }
1050 /* No EOS reached */
1051 if (!audio->eos_rsp) {
1052 spin_lock_irqsave(&audio->dsp_lock, flags);
1053 audio_aio_async_read(audio, buf_node);
1054 /* EOS buffer handled in driver */
1055 list_add_tail(&buf_node->list, &audio->in_queue);
1056 spin_unlock_irqrestore(&audio->dsp_lock, flags);
1057 }
1058 /* EOS reached at input side fake all upcoming read buffer to
1059 * indicate the same
1060 */
1061 else {
1062 union msm_audio_event_payload event_payload;
1063 event_payload.aio_buf = buf_node->buf;
1064 event_payload.aio_buf.data_len =
1065 insert_eos_buf(audio, buf_node);
1066 pr_debug("%s[%p]: propagate READ_DONE as EOS done\n",\
1067 __func__, audio);
1068 audio_aio_post_event(audio, AUDIO_EVENT_READ_DONE,
1069 event_payload);
1070 kfree(buf_node);
1071 }
1072 }
1073 return 0;
1074}
1075
Deepa Madiregama75d0b932012-11-28 14:57:43 +05301076void audio_aio_ioport_reset(struct q6audio_aio *audio)
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301077{
1078 if (audio->drv_status & ADRV_STATUS_AIO_INTF) {
1079 /* If fsync is in progress, make sure
1080 * return value of fsync indicates
1081 * abort due to flush
1082 */
1083 if (audio->drv_status & ADRV_STATUS_FSYNC) {
1084 pr_debug("%s[%p]:fsync in progress\n", __func__, audio);
1085 audio->drv_ops.out_flush(audio);
1086 } else
1087 audio->drv_ops.out_flush(audio);
Sidipotu Ashokfe014152012-09-16 18:24:18 +05301088 if (audio->feedback == NON_TUNNEL_MODE)
1089 audio->drv_ops.in_flush(audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301090 }
1091}
1092
1093int audio_aio_open(struct q6audio_aio *audio, struct file *file)
1094{
1095 int rc = 0;
1096 int i;
1097 struct audio_aio_event *e_node = NULL;
Kuirong Wang86d5e7a2013-02-12 18:45:49 -08001098 struct list_head *ptr, *next;
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301099
1100 /* Settings will be re-config at AUDIO_SET_CONFIG,
1101 * but at least we need to have initial config
1102 */
1103 audio->str_cfg.buffer_size = FRAME_SIZE;
1104 audio->str_cfg.buffer_count = FRAME_NUM;
1105 audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
1106 audio->pcm_cfg.sample_rate = 48000;
1107 audio->pcm_cfg.channel_count = 2;
1108
1109 /* Only AIO interface */
1110 if (file->f_flags & O_NONBLOCK) {
1111 pr_debug("%s[%p]:set to aio interface\n", __func__, audio);
1112 audio->drv_status |= ADRV_STATUS_AIO_INTF;
1113 audio->drv_ops.out_flush = audio_aio_async_out_flush;
1114 audio->drv_ops.in_flush = audio_aio_async_in_flush;
1115 q6asm_set_io_mode(audio->ac, ASYNC_IO_MODE);
1116 } else {
1117 pr_err("%s[%p]:SIO interface not supported\n",
1118 __func__, audio);
1119 rc = -EACCES;
1120 goto fail;
1121 }
1122
1123 /* Initialize all locks of audio instance */
1124 mutex_init(&audio->lock);
1125 mutex_init(&audio->read_lock);
1126 mutex_init(&audio->write_lock);
1127 mutex_init(&audio->get_event_lock);
1128 spin_lock_init(&audio->dsp_lock);
1129 spin_lock_init(&audio->event_queue_lock);
1130 init_waitqueue_head(&audio->cmd_wait);
1131 init_waitqueue_head(&audio->write_wait);
1132 init_waitqueue_head(&audio->event_wait);
1133 INIT_LIST_HEAD(&audio->out_queue);
1134 INIT_LIST_HEAD(&audio->in_queue);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +05301135 INIT_LIST_HEAD(&audio->ion_region_queue);
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301136 INIT_LIST_HEAD(&audio->free_event_queue);
1137 INIT_LIST_HEAD(&audio->event_queue);
1138
1139 audio->drv_ops.out_flush(audio);
1140 audio->opened = 1;
1141 file->private_data = audio;
1142 audio->codec_ioctl = audio_aio_ioctl;
1143
Mingming Yinc09967e2012-04-27 15:09:43 -07001144 for (i = 0; i < AUDIO_EVENT_NUM; i++) {
1145 e_node = kmalloc(sizeof(struct audio_aio_event), GFP_KERNEL);
1146 if (e_node)
1147 list_add_tail(&e_node->list, &audio->free_event_queue);
1148 else {
1149 pr_err("%s[%p]:event pkt alloc failed\n",
1150 __func__, audio);
Kuirong Wang86d5e7a2013-02-12 18:45:49 -08001151 rc = -ENOMEM;
1152 goto cleanup;
Mingming Yinc09967e2012-04-27 15:09:43 -07001153 }
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301154 }
Fred Ohde9438a2013-04-04 11:29:12 -07001155 audio->client = msm_audio_ion_client_create(UINT_MAX,
1156 "Audio_Dec_Client");
Deepa Madiregamaa4795072012-06-15 22:35:52 +05301157 if (IS_ERR_OR_NULL(audio->client)) {
1158 pr_err("Unable to create ION client\n");
Kuirong Wang86d5e7a2013-02-12 18:45:49 -08001159 rc = -ENOMEM;
1160 goto cleanup;
Deepa Madiregamaa4795072012-06-15 22:35:52 +05301161 }
1162 pr_debug("Ion client create in audio_aio_open %p", audio->client);
Sidipotu Ashokbf84d4d2012-11-06 17:13:28 +05301163
1164 rc = register_volume_listener(audio);
1165 if (rc < 0)
Kuirong Wang86d5e7a2013-02-12 18:45:49 -08001166 goto ion_cleanup;
Sidipotu Ashokbf84d4d2012-11-06 17:13:28 +05301167
Mingming Yinc09967e2012-04-27 15:09:43 -07001168 return 0;
Kuirong Wang86d5e7a2013-02-12 18:45:49 -08001169ion_cleanup:
1170 msm_audio_ion_client_destroy(audio->client);
1171 audio->client = NULL;
1172cleanup:
1173 list_for_each_safe(ptr, next, &audio->free_event_queue) {
1174 e_node = list_first_entry(&audio->free_event_queue,
1175 struct audio_aio_event, list);
1176 list_del(&e_node->list);
1177 kfree(e_node);
1178 }
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301179fail:
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301180 return rc;
1181}
1182
1183long audio_aio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
1184{
1185 struct q6audio_aio *audio = file->private_data;
1186 int rc = 0;
1187
1188 switch (cmd) {
1189 case AUDIO_GET_STATS: {
1190 struct msm_audio_stats stats;
Sidipotu Ashok388cdc52012-09-16 16:59:16 +05301191 uint64_t timestamp;
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301192 stats.byte_count = atomic_read(&audio->in_bytes);
1193 stats.sample_count = atomic_read(&audio->in_samples);
Patrick Laifc8f2242013-01-06 00:52:34 -08001194 rc = q6asm_get_session_time(audio->ac, &timestamp);
1195 if (rc >= 0)
Sidipotu Ashok388cdc52012-09-16 16:59:16 +05301196 memcpy(&stats.unused[0], &timestamp, sizeof(timestamp));
1197 else
1198 pr_debug("Error while getting timestamp\n");
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301199 if (copy_to_user((void *)arg, &stats, sizeof(stats)))
1200 rc = -EFAULT;
1201 break;
1202 }
1203 case AUDIO_GET_EVENT: {
1204 pr_debug("%s[%p]:AUDIO_GET_EVENT\n", __func__, audio);
1205 if (mutex_trylock(&audio->get_event_lock)) {
1206 rc = audio_aio_process_event_req(audio,
1207 (void __user *)arg);
1208 mutex_unlock(&audio->get_event_lock);
1209 } else
1210 rc = -EBUSY;
1211 break;
1212 }
1213 case AUDIO_ABORT_GET_EVENT: {
1214 audio->event_abort = 1;
1215 wake_up(&audio->event_wait);
1216 break;
1217 }
1218 case AUDIO_ASYNC_WRITE: {
1219 mutex_lock(&audio->write_lock);
1220 if (audio->drv_status & ADRV_STATUS_FSYNC)
1221 rc = -EBUSY;
1222 else {
1223 if (audio->enabled)
1224 rc = audio_aio_buf_add(audio, 1,
1225 (void __user *)arg);
1226 else
1227 rc = -EPERM;
1228 }
1229 mutex_unlock(&audio->write_lock);
1230 break;
1231 }
1232 case AUDIO_ASYNC_READ: {
1233 mutex_lock(&audio->read_lock);
1234 if ((audio->feedback) && (audio->enabled))
1235 rc = audio_aio_buf_add(audio, 0,
1236 (void __user *)arg);
1237 else
1238 rc = -EPERM;
1239 mutex_unlock(&audio->read_lock);
1240 break;
1241 }
1242 case AUDIO_OUTPORT_FLUSH: {
1243 pr_debug("%s[%p]:AUDIO_OUTPORT_FLUSH\n", __func__, audio);
1244 mutex_lock(&audio->read_lock);
1245 rc = audio_aio_outport_flush(audio);
1246 if (rc < 0) {
1247 pr_err("%s[%p]: AUDIO_OUTPORT_FLUSH failed\n",
1248 __func__, audio);
1249 rc = -EINTR;
1250 }
1251 mutex_unlock(&audio->read_lock);
1252 break;
1253 }
1254 case AUDIO_STOP: {
1255 pr_debug("%s[%p]: AUDIO_STOP session_id[%d]\n", __func__,
1256 audio, audio->ac->session);
1257 mutex_lock(&audio->lock);
1258 audio->stopped = 1;
Deepa Madiregama75d0b932012-11-28 14:57:43 +05301259 rc = audio_aio_flush(audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301260 if (rc < 0) {
1261 pr_err("%s[%p]:Audio Stop procedure failed rc=%d\n",
1262 __func__, audio, rc);
1263 mutex_unlock(&audio->lock);
1264 break;
1265 }
Deepa Madiregama75d0b932012-11-28 14:57:43 +05301266 audio->enabled = 0;
1267 audio->drv_status &= ~ADRV_STATUS_PAUSE;
Deepa Madiregama900d3572012-11-28 15:48:48 +05301268 if (audio->drv_status & ADRV_STATUS_FSYNC) {
1269 pr_debug("%s[%p] Waking up the audio_aio_fsync\n",
1270 __func__, audio);
1271 wake_up(&audio->write_wait);
1272 }
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301273 mutex_unlock(&audio->lock);
1274 break;
1275 }
1276 case AUDIO_PAUSE: {
1277 pr_debug("%s[%p]:AUDIO_PAUSE %ld\n", __func__, audio, arg);
1278 mutex_lock(&audio->lock);
1279 if (arg == 1) {
1280 rc = audio_aio_pause(audio);
Laxminath Kasam92ad28c2012-09-03 13:47:33 +05301281 if (rc < 0) {
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301282 pr_err("%s[%p]: pause FAILED rc=%d\n",
1283 __func__, audio, rc);
Laxminath Kasam92ad28c2012-09-03 13:47:33 +05301284 mutex_unlock(&audio->lock);
1285 break;
1286 }
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301287 audio->drv_status |= ADRV_STATUS_PAUSE;
1288 } else if (arg == 0) {
1289 if (audio->drv_status & ADRV_STATUS_PAUSE) {
1290 rc = audio_aio_enable(audio);
1291 if (rc)
1292 pr_err("%s[%p]: audio enable failed\n",
1293 __func__, audio);
1294 else {
1295 audio->drv_status &= ~ADRV_STATUS_PAUSE;
1296 audio->enabled = 1;
1297 }
1298 }
1299 }
1300 mutex_unlock(&audio->lock);
1301 break;
1302 }
1303 case AUDIO_FLUSH: {
1304 pr_debug("%s[%p]: AUDIO_FLUSH sessionid[%d]\n", __func__,
1305 audio, audio->ac->session);
1306 mutex_lock(&audio->lock);
1307 audio->rflush = 1;
1308 audio->wflush = 1;
Deepa Madiregama900d3572012-11-28 15:48:48 +05301309 if (audio->drv_status & ADRV_STATUS_FSYNC) {
1310 pr_debug("%s[%p] Waking up the audio_aio_fsync\n",
1311 __func__, audio);
1312 wake_up(&audio->write_wait);
1313 }
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301314 /* Flush DSP */
1315 rc = audio_aio_flush(audio);
Amal Paul765cb102013-02-16 15:44:31 -08001316 /* Flush input / Output buffer in software*/
1317 audio_aio_ioport_reset(audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301318 if (rc < 0) {
1319 pr_err("%s[%p]:AUDIO_FLUSH interrupted\n",
1320 __func__, audio);
1321 rc = -EINTR;
1322 } else {
1323 audio->rflush = 0;
Sidipotu Ashokfe014152012-09-16 18:24:18 +05301324 if (audio->drv_status & ADRV_STATUS_FSYNC)
1325 wake_up(&audio->write_wait);
1326 else
1327 audio->wflush = 0;
1328
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301329 }
1330 audio->eos_flag = 0;
1331 audio->eos_rsp = 0;
1332 mutex_unlock(&audio->lock);
1333 break;
1334 }
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +05301335 case AUDIO_REGISTER_ION: {
1336 struct msm_audio_ion_info info;
1337 pr_debug("%s[%p]:AUDIO_REGISTER_ION\n", __func__, audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301338 mutex_lock(&audio->lock);
1339 if (copy_from_user(&info, (void *)arg, sizeof(info)))
1340 rc = -EFAULT;
1341 else
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +05301342 rc = audio_aio_ion_add(audio, &info);
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301343 mutex_unlock(&audio->lock);
1344 break;
1345 }
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +05301346 case AUDIO_DEREGISTER_ION: {
1347 struct msm_audio_ion_info info;
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301348 mutex_lock(&audio->lock);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +05301349 pr_debug("%s[%p]:AUDIO_DEREGISTER_ION\n", __func__, audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301350 if (copy_from_user(&info, (void *)arg, sizeof(info)))
1351 rc = -EFAULT;
1352 else
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +05301353 rc = audio_aio_ion_remove(audio, &info);
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301354 mutex_unlock(&audio->lock);
1355 break;
1356 }
1357 case AUDIO_GET_STREAM_CONFIG: {
1358 struct msm_audio_stream_config cfg;
1359 mutex_lock(&audio->lock);
1360 memset(&cfg, 0, sizeof(cfg));
1361 cfg.buffer_size = audio->str_cfg.buffer_size;
1362 cfg.buffer_count = audio->str_cfg.buffer_count;
1363 pr_debug("%s[%p]:GET STREAM CFG %d %d\n",
1364 __func__, audio, cfg.buffer_size, cfg.buffer_count);
1365 if (copy_to_user((void *)arg, &cfg, sizeof(cfg)))
1366 rc = -EFAULT;
1367 mutex_unlock(&audio->lock);
1368 break;
1369 }
1370 case AUDIO_SET_STREAM_CONFIG: {
1371 struct msm_audio_stream_config cfg;
1372 pr_debug("%s[%p]:SET STREAM CONFIG\n", __func__, audio);
1373 mutex_lock(&audio->lock);
1374 if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
1375 rc = -EFAULT;
1376 mutex_unlock(&audio->lock);
1377 break;
1378 }
1379 audio->str_cfg.buffer_size = FRAME_SIZE;
1380 audio->str_cfg.buffer_count = FRAME_NUM;
1381 rc = 0;
1382 mutex_unlock(&audio->lock);
1383 break;
1384 }
1385 case AUDIO_GET_CONFIG: {
1386 struct msm_audio_config cfg;
1387 mutex_lock(&audio->lock);
1388 if (copy_to_user((void *)arg, &audio->pcm_cfg, sizeof(cfg)))
1389 rc = -EFAULT;
1390 mutex_unlock(&audio->lock);
1391 break;
1392 }
1393 case AUDIO_SET_CONFIG: {
1394 struct msm_audio_config config;
1395 pr_err("%s[%p]:AUDIO_SET_CONFIG\n", __func__, audio);
1396 mutex_lock(&audio->lock);
1397 if (copy_from_user(&config, (void *)arg, sizeof(config))) {
1398 rc = -EFAULT;
1399 mutex_unlock(&audio->lock);
1400 break;
1401 }
1402 if (audio->feedback != NON_TUNNEL_MODE) {
Harmandeep Singheaf59b42012-06-05 21:46:02 -07001403 pr_err("%s[%p]:Not sufficient permission to change the playback mode\n",
1404 __func__, audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301405 rc = -EACCES;
1406 mutex_unlock(&audio->lock);
1407 break;
1408 }
1409 if ((config.buffer_count > PCM_BUF_COUNT) ||
1410 (config.buffer_count == 1))
1411 config.buffer_count = PCM_BUF_COUNT;
1412
1413 if (config.buffer_size < PCM_BUFSZ_MIN)
1414 config.buffer_size = PCM_BUFSZ_MIN;
1415
1416 audio->pcm_cfg.buffer_count = config.buffer_count;
1417 audio->pcm_cfg.buffer_size = config.buffer_size;
1418 audio->pcm_cfg.channel_count = config.channel_count;
1419 audio->pcm_cfg.sample_rate = config.sample_rate;
1420 rc = 0;
1421 mutex_unlock(&audio->lock);
1422 break;
1423 }
1424 case AUDIO_SET_BUF_CFG: {
1425 struct msm_audio_buf_cfg cfg;
1426 mutex_lock(&audio->lock);
1427 if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
1428 rc = -EFAULT;
1429 mutex_unlock(&audio->lock);
1430 break;
1431 }
1432 if ((audio->feedback == NON_TUNNEL_MODE) &&
1433 !cfg.meta_info_enable) {
1434 rc = -EFAULT;
1435 mutex_unlock(&audio->lock);
1436 break;
1437 }
1438
1439 audio->buf_cfg.meta_info_enable = cfg.meta_info_enable;
1440 pr_debug("%s[%p]:session id %d: Set-buf-cfg: meta[%d]",
1441 __func__, audio,
1442 audio->ac->session, cfg.meta_info_enable);
1443 mutex_unlock(&audio->lock);
1444 break;
1445 }
1446 case AUDIO_GET_BUF_CFG: {
Harmandeep Singheaf59b42012-06-05 21:46:02 -07001447 pr_debug("%s[%p]:session id %d: Get-buf-cfg: meta[%d] framesperbuf[%d]\n",
1448 __func__, audio,
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301449 audio->ac->session, audio->buf_cfg.meta_info_enable,
1450 audio->buf_cfg.frames_per_buf);
1451
1452 mutex_lock(&audio->lock);
1453 if (copy_to_user((void *)arg, &audio->buf_cfg,
1454 sizeof(struct msm_audio_buf_cfg)))
1455 rc = -EFAULT;
1456 mutex_unlock(&audio->lock);
1457 break;
1458 }
1459 case AUDIO_GET_SESSION_ID: {
1460 mutex_lock(&audio->lock);
1461 if (copy_to_user((void *)arg, &audio->ac->session,
1462 sizeof(unsigned short))) {
1463 rc = -EFAULT;
1464 }
1465 mutex_unlock(&audio->lock);
1466 break;
1467 }
1468 default:
1469 rc = -EINVAL;
1470 }
1471 return rc;
1472}