blob: 1937aafc4c4b118a5537c4243c59da5913b64f7c [file] [log] [blame]
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301/* Copyright (C) 2008 Google, Inc.
2 * Copyright (C) 2008 HTC Corporation
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +05303 * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
Deepa Madiregama55cbf782011-09-10 05:44:39 +05304 *
5 * This software is licensed under the terms of the GNU General Public
6 * License version 2, as published by the Free Software Foundation, and
7 * may be copied, distributed, and modified under those terms.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 */
15
16#include <linux/module.h>
17#include <linux/fs.h>
18#include <linux/miscdevice.h>
19#include <linux/uaccess.h>
20#include <linux/sched.h>
21#include <linux/wait.h>
22#include <linux/dma-mapping.h>
23#include <linux/slab.h>
24#include <asm/atomic.h>
25#include <asm/ioctls.h>
Deepa Madiregama55cbf782011-09-10 05:44:39 +053026#include <linux/debugfs.h>
27#include "audio_utils_aio.h"
28
29#ifdef CONFIG_DEBUG_FS
30ssize_t audio_aio_debug_open(struct inode *inode, struct file *file)
31{
32 file->private_data = inode->i_private;
33 return 0;
34}
35
Harmandeep Singheaf59b42012-06-05 21:46:02 -070036ssize_t audio_aio_debug_read(struct file *file, char __user *buf,
Deepa Madiregama55cbf782011-09-10 05:44:39 +053037 size_t count, loff_t *ppos)
38{
39 const int debug_bufmax = 4096;
40 static char buffer[4096];
41 int n = 0;
42 struct q6audio_aio *audio = file->private_data;
43
44 mutex_lock(&audio->lock);
45 n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
46 n += scnprintf(buffer + n, debug_bufmax - n,
47 "enabled %d\n", audio->enabled);
48 n += scnprintf(buffer + n, debug_bufmax - n,
49 "stopped %d\n", audio->stopped);
50 n += scnprintf(buffer + n, debug_bufmax - n,
51 "feedback %d\n", audio->feedback);
52 mutex_unlock(&audio->lock);
53 /* Following variables are only useful for debugging when
54 * when playback halts unexpectedly. Thus, no mutual exclusion
55 * enforced
56 */
57 n += scnprintf(buffer + n, debug_bufmax - n,
58 "wflush %d\n", audio->wflush);
59 n += scnprintf(buffer + n, debug_bufmax - n,
60 "rflush %d\n", audio->rflush);
61 n += scnprintf(buffer + n, debug_bufmax - n,
62 "inqueue empty %d\n", list_empty(&audio->in_queue));
63 n += scnprintf(buffer + n, debug_bufmax - n,
64 "outqueue empty %d\n", list_empty(&audio->out_queue));
65 buffer[n] = 0;
66 return simple_read_from_buffer(buf, count, ppos, buffer, n);
67}
68#endif
69
Harmandeep Singheaf59b42012-06-05 21:46:02 -070070int insert_eos_buf(struct q6audio_aio *audio,
Deepa Madiregama55cbf782011-09-10 05:44:39 +053071 struct audio_aio_buffer_node *buf_node)
72{
73 struct dec_meta_out *eos_buf = buf_node->kvaddr;
74 pr_debug("%s[%p]:insert_eos_buf\n", __func__, audio);
75 eos_buf->num_of_frames = 0xFFFFFFFF;
76 eos_buf->meta_out_dsp[0].offset_to_frame = 0x0;
77 eos_buf->meta_out_dsp[0].nflags = AUDIO_DEC_EOS_SET;
78 return sizeof(struct dec_meta_out) +
79 sizeof(eos_buf->meta_out_dsp[0]);
80}
81
82/* Routine which updates read buffers of driver/dsp,
83 for flush operation as DSP output might not have proper
84 value set */
85static int insert_meta_data_flush(struct q6audio_aio *audio,
86 struct audio_aio_buffer_node *buf_node)
87{
88 struct dec_meta_out *meta_data = buf_node->kvaddr;
89 meta_data->num_of_frames = 0x0;
90 meta_data->meta_out_dsp[0].offset_to_frame = 0x0;
91 meta_data->meta_out_dsp[0].nflags = 0x0;
92 return sizeof(struct dec_meta_out) +
93 sizeof(meta_data->meta_out_dsp[0]);
94}
95
Harmandeep Singheaf59b42012-06-05 21:46:02 -070096void extract_meta_out_info(struct q6audio_aio *audio,
Deepa Madiregama55cbf782011-09-10 05:44:39 +053097 struct audio_aio_buffer_node *buf_node, int dir)
98{
99 struct dec_meta_out *meta_data = buf_node->kvaddr;
100 if (dir) { /* input buffer - Write */
101 if (audio->buf_cfg.meta_info_enable)
102 memcpy(&buf_node->meta_info.meta_in,
103 (char *)buf_node->kvaddr, sizeof(struct dec_meta_in));
104 else
105 memset(&buf_node->meta_info.meta_in,
106 0, sizeof(struct dec_meta_in));
107 pr_debug("%s[%p]:i/p: msw_ts 0x%lx lsw_ts 0x%lx nflags 0x%8x\n",
108 __func__, audio,
109 buf_node->meta_info.meta_in.ntimestamp.highpart,
110 buf_node->meta_info.meta_in.ntimestamp.lowpart,
111 buf_node->meta_info.meta_in.nflags);
112 } else { /* output buffer - Read */
113 memcpy((char *)buf_node->kvaddr,
114 &buf_node->meta_info.meta_out,
115 sizeof(struct dec_meta_out));
116 meta_data->meta_out_dsp[0].nflags = 0x00000000;
Harmandeep Singheaf59b42012-06-05 21:46:02 -0700117 pr_debug("%s[%p]:o/p: msw_ts 0x%8x lsw_ts 0x%8x nflags 0x%8x, num_frames = %d\n",
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530118 __func__, audio,
119 ((struct dec_meta_out *)buf_node->kvaddr)->\
120 meta_out_dsp[0].msw_ts,
121 ((struct dec_meta_out *)buf_node->kvaddr)->\
122 meta_out_dsp[0].lsw_ts,
123 ((struct dec_meta_out *)buf_node->kvaddr)->\
124 meta_out_dsp[0].nflags,
125 ((struct dec_meta_out *)buf_node->kvaddr)->num_of_frames);
126 }
127}
128
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530129static int audio_aio_ion_lookup_vaddr(struct q6audio_aio *audio, void *addr,
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530130 unsigned long len,
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530131 struct audio_aio_ion_region **region)
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530132{
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530133 struct audio_aio_ion_region *region_elt;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530134
135 int match_count = 0;
136
137 *region = NULL;
138
139 /* returns physical address or zero */
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530140 list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530141 if (addr >= region_elt->vaddr &&
142 addr < region_elt->vaddr + region_elt->len &&
143 addr + len <= region_elt->vaddr + region_elt->len) {
144 /* offset since we could pass vaddr inside a registerd
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530145 * ion buffer
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530146 */
147
148 match_count++;
149 if (!*region)
150 *region = region_elt;
151 }
152 }
153
154 if (match_count > 1) {
155 pr_err("%s[%p]:multiple hits for vaddr %p, len %ld\n",
156 __func__, audio, addr, len);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530157 list_for_each_entry(region_elt, &audio->ion_region_queue,
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530158 list) {
159 if (addr >= region_elt->vaddr &&
160 addr < region_elt->vaddr + region_elt->len &&
161 addr + len <= region_elt->vaddr + region_elt->len)
162 pr_err("\t%s[%p]:%p, %ld --> %p\n",
163 __func__, audio,
164 region_elt->vaddr,
165 region_elt->len,
166 (void *)region_elt->paddr);
167 }
168 }
169
170 return *region ? 0 : -1;
171}
172
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530173static unsigned long audio_aio_ion_fixup(struct q6audio_aio *audio, void *addr,
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530174 unsigned long len, int ref_up, void **kvaddr)
175{
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530176 struct audio_aio_ion_region *region;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530177 unsigned long paddr;
178 int ret;
179
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530180 ret = audio_aio_ion_lookup_vaddr(audio, addr, len, &region);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530181 if (ret) {
182 pr_err("%s[%p]:lookup (%p, %ld) failed\n",
183 __func__, audio, addr, len);
184 return 0;
185 }
186 if (ref_up)
187 region->ref_cnt++;
188 else
189 region->ref_cnt--;
190 pr_debug("%s[%p]:found region %p ref_cnt %d\n",
191 __func__, audio, region, region->ref_cnt);
192 paddr = region->paddr + (addr - region->vaddr);
193 /* provide kernel virtual address for accessing meta information */
194 if (kvaddr)
195 *kvaddr = (void *) (region->kvaddr + (addr - region->vaddr));
196 return paddr;
197}
198
199static int audio_aio_pause(struct q6audio_aio *audio)
200{
201 int rc = 0;
202
203 pr_debug("%s[%p], enabled = %d\n", __func__, audio,
204 audio->enabled);
205 if (audio->enabled) {
206 rc = q6asm_cmd(audio->ac, CMD_PAUSE);
207 if (rc < 0)
208 pr_err("%s[%p]: pause cmd failed rc=%d\n",
209 __func__, audio, rc);
210
211 } else
212 pr_err("%s[%p]: Driver not enabled\n", __func__, audio);
213 return rc;
214}
215
216static int audio_aio_flush(struct q6audio_aio *audio)
217{
218 int rc;
219
220 if (audio->enabled) {
221 /* Implicitly issue a pause to the decoder before flushing if
222 it is not in pause state */
223 if (!(audio->drv_status & ADRV_STATUS_PAUSE)) {
224 rc = audio_aio_pause(audio);
225 if (rc < 0)
226 pr_err("%s[%p}: pause cmd failed rc=%d\n",
227 __func__, audio,
228 rc);
229 else
230 audio->drv_status |= ADRV_STATUS_PAUSE;
231 }
232 rc = q6asm_cmd(audio->ac, CMD_FLUSH);
233 if (rc < 0)
234 pr_err("%s[%p]: flush cmd failed rc=%d\n",
235 __func__, audio, rc);
236 /* Not in stop state, reenable the stream */
237 if (audio->stopped == 0) {
238 rc = audio_aio_enable(audio);
239 if (rc)
240 pr_err("%s[%p]:audio re-enable failed\n",
241 __func__, audio);
242 else {
243 audio->enabled = 1;
244 if (audio->drv_status & ADRV_STATUS_PAUSE)
245 audio->drv_status &= ~ADRV_STATUS_PAUSE;
246 }
247 }
248 }
249 pr_debug("%s[%p]:in_bytes %d\n",
250 __func__, audio, atomic_read(&audio->in_bytes));
251 pr_debug("%s[%p]:in_samples %d\n",
252 __func__, audio, atomic_read(&audio->in_samples));
253 atomic_set(&audio->in_bytes, 0);
254 atomic_set(&audio->in_samples, 0);
255 return 0;
256}
257
258static int audio_aio_outport_flush(struct q6audio_aio *audio)
259{
260 int rc;
261
262 rc = q6asm_cmd(audio->ac, CMD_OUT_FLUSH);
263 if (rc < 0)
264 pr_err("%s[%p}: output port flush cmd failed rc=%d\n",
265 __func__, audio, rc);
266 return rc;
267}
268
269/* Write buffer to DSP / Handle Ack from DSP */
270void audio_aio_async_write_ack(struct q6audio_aio *audio, uint32_t token,
271 uint32_t *payload)
272{
273 unsigned long flags;
274 union msm_audio_event_payload event_payload;
275 struct audio_aio_buffer_node *used_buf;
276
277 /* No active flush in progress */
278 if (audio->wflush)
279 return;
280
281 spin_lock_irqsave(&audio->dsp_lock, flags);
282 BUG_ON(list_empty(&audio->out_queue));
283 used_buf = list_first_entry(&audio->out_queue,
284 struct audio_aio_buffer_node, list);
285 if (token == used_buf->token) {
286 list_del(&used_buf->list);
287 spin_unlock_irqrestore(&audio->dsp_lock, flags);
288 pr_debug("%s[%p]:consumed buffer\n", __func__, audio);
289 event_payload.aio_buf = used_buf->buf;
290 audio_aio_post_event(audio, AUDIO_EVENT_WRITE_DONE,
291 event_payload);
292 kfree(used_buf);
293 if (list_empty(&audio->out_queue) &&
294 (audio->drv_status & ADRV_STATUS_FSYNC)) {
Harmandeep Singheaf59b42012-06-05 21:46:02 -0700295 pr_debug("%s[%p]: list is empty, reached EOS in Tunnel\n",
296 __func__, audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530297 wake_up(&audio->write_wait);
298 }
299 } else {
300 pr_err("%s[%p]:expected=%lx ret=%x\n",
301 __func__, audio, used_buf->token, token);
302 spin_unlock_irqrestore(&audio->dsp_lock, flags);
303 }
304}
305
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530306/* ------------------- device --------------------- */
307void audio_aio_async_out_flush(struct q6audio_aio *audio)
308{
309 struct audio_aio_buffer_node *buf_node;
310 struct list_head *ptr, *next;
311 union msm_audio_event_payload payload;
312 unsigned long flags;
313
314 pr_debug("%s[%p}\n", __func__, audio);
315 /* EOS followed by flush, EOS response not guranteed, free EOS i/p
316 buffer */
317 spin_lock_irqsave(&audio->dsp_lock, flags);
318
319 if (audio->eos_flag && (audio->eos_write_payload.aio_buf.buf_addr)) {
320 pr_debug("%s[%p]: EOS followed by flush received,acknowledge"\
321 " eos i/p buffer immediately\n", __func__, audio);
322 audio_aio_post_event(audio, AUDIO_EVENT_WRITE_DONE,
323 audio->eos_write_payload);
324 memset(&audio->eos_write_payload , 0,
325 sizeof(union msm_audio_event_payload));
326 }
327 spin_unlock_irqrestore(&audio->dsp_lock, flags);
328 list_for_each_safe(ptr, next, &audio->out_queue) {
329 buf_node = list_entry(ptr, struct audio_aio_buffer_node, list);
330 list_del(&buf_node->list);
331 payload.aio_buf = buf_node->buf;
332 audio_aio_post_event(audio, AUDIO_EVENT_WRITE_DONE, payload);
333 kfree(buf_node);
334 pr_debug("%s[%p]: Propagate WRITE_DONE during flush\n",
335 __func__, audio);
336 }
337}
338
339void audio_aio_async_in_flush(struct q6audio_aio *audio)
340{
341 struct audio_aio_buffer_node *buf_node;
342 struct list_head *ptr, *next;
343 union msm_audio_event_payload payload;
344
345 pr_debug("%s[%p]\n", __func__, audio);
346 list_for_each_safe(ptr, next, &audio->in_queue) {
347 buf_node = list_entry(ptr, struct audio_aio_buffer_node, list);
348 list_del(&buf_node->list);
349 /* Forcefull send o/p eos buffer after flush, if no eos response
350 * received by dsp even after sending eos command */
351 if ((audio->eos_rsp != 1) && audio->eos_flag) {
Harmandeep Singheaf59b42012-06-05 21:46:02 -0700352 pr_debug("%s[%p]: send eos on o/p buffer during flush\n",
353 __func__, audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530354 payload.aio_buf = buf_node->buf;
355 payload.aio_buf.data_len =
356 insert_eos_buf(audio, buf_node);
357 audio->eos_flag = 0;
358 } else {
359 payload.aio_buf = buf_node->buf;
360 payload.aio_buf.data_len =
361 insert_meta_data_flush(audio, buf_node);
362 }
363 audio_aio_post_event(audio, AUDIO_EVENT_READ_DONE, payload);
364 kfree(buf_node);
365 pr_debug("%s[%p]: Propagate READ_DONE during flush\n",
366 __func__, audio);
367 }
368}
369
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530370int audio_aio_enable(struct q6audio_aio *audio)
371{
372 /* 2nd arg: 0 -> run immediately
373 3rd arg: 0 -> msw_ts, 4th arg: 0 ->lsw_ts */
374 return q6asm_run(audio->ac, 0x00, 0x00, 0x00);
375}
376
377int audio_aio_disable(struct q6audio_aio *audio)
378{
379 int rc = 0;
380 if (audio->opened) {
381 audio->enabled = 0;
382 audio->opened = 0;
383 pr_debug("%s[%p]: inbytes[%d] insamples[%d]\n", __func__,
384 audio, atomic_read(&audio->in_bytes),
385 atomic_read(&audio->in_samples));
386 /* Close the session */
387 rc = q6asm_cmd(audio->ac, CMD_CLOSE);
388 if (rc < 0)
389 pr_err("%s[%p]:Failed to close the session rc=%d\n",
390 __func__, audio, rc);
391 audio->stopped = 1;
392 wake_up(&audio->write_wait);
393 wake_up(&audio->cmd_wait);
394 }
395 pr_debug("%s[%p]:enabled[%d]\n", __func__, audio, audio->enabled);
396 return rc;
397}
398
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530399void audio_aio_reset_ion_region(struct q6audio_aio *audio)
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530400{
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530401 struct audio_aio_ion_region *region;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530402 struct list_head *ptr, *next;
403
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530404 list_for_each_safe(ptr, next, &audio->ion_region_queue) {
405 region = list_entry(ptr, struct audio_aio_ion_region, list);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530406 list_del(&region->list);
Deepa Madiregamaa4795072012-06-15 22:35:52 +0530407 ion_unmap_kernel(audio->client, region->handle);
408 ion_free(audio->client, region->handle);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530409 kfree(region);
410 }
411
412 return;
413}
414
415void audio_aio_reset_event_queue(struct q6audio_aio *audio)
416{
417 unsigned long flags;
418 struct audio_aio_event *drv_evt;
419 struct list_head *ptr, *next;
420
421 spin_lock_irqsave(&audio->event_queue_lock, flags);
422 list_for_each_safe(ptr, next, &audio->event_queue) {
423 drv_evt = list_first_entry(&audio->event_queue,
424 struct audio_aio_event, list);
425 list_del(&drv_evt->list);
426 kfree(drv_evt);
427 }
428 list_for_each_safe(ptr, next, &audio->free_event_queue) {
429 drv_evt = list_first_entry(&audio->free_event_queue,
430 struct audio_aio_event, list);
431 list_del(&drv_evt->list);
432 kfree(drv_evt);
433 }
434 spin_unlock_irqrestore(&audio->event_queue_lock, flags);
435
436 return;
437}
438
Deepa Madiregama14e9e762012-08-29 12:27:41 +0530439void audio_aio_unmap_ion_region(struct q6audio_aio *audio)
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530440{
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530441 struct audio_aio_ion_region *region;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530442 struct list_head *ptr, *next;
443 int rc = -EINVAL;
444
445 pr_debug("%s[%p]:\n", __func__, audio);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530446 list_for_each_safe(ptr, next, &audio->ion_region_queue) {
447 region = list_entry(ptr, struct audio_aio_ion_region, list);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530448 pr_debug("%s[%p]: phy_address = 0x%lx\n",
449 __func__, audio, region->paddr);
450 if (region != NULL) {
451 rc = q6asm_memory_unmap(audio->ac,
452 (uint32_t)region->paddr, IN);
453 if (rc < 0)
454 pr_err("%s[%p]: memory unmap failed\n",
455 __func__, audio);
456 }
457 }
458}
459
460int audio_aio_release(struct inode *inode, struct file *file)
461{
462 struct q6audio_aio *audio = file->private_data;
463 pr_debug("%s[%p]\n", __func__, audio);
464 mutex_lock(&audio->lock);
465 audio->wflush = 1;
466 if (audio->enabled)
467 audio_aio_flush(audio);
468 audio->wflush = 0;
469 audio->drv_ops.out_flush(audio);
470 audio->drv_ops.in_flush(audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530471 audio_aio_disable(audio);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530472 audio_aio_reset_ion_region(audio);
Deepa Madiregamaa4795072012-06-15 22:35:52 +0530473 ion_client_destroy(audio->client);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530474 audio->event_abort = 1;
475 wake_up(&audio->event_wait);
476 audio_aio_reset_event_queue(audio);
477 q6asm_audio_client_free(audio->ac);
478 mutex_unlock(&audio->lock);
479 mutex_destroy(&audio->lock);
480 mutex_destroy(&audio->read_lock);
481 mutex_destroy(&audio->write_lock);
482 mutex_destroy(&audio->get_event_lock);
483#ifdef CONFIG_DEBUG_FS
484 if (audio->dentry)
485 debugfs_remove(audio->dentry);
486#endif
487 kfree(audio->codec_cfg);
488 kfree(audio);
489 return 0;
490}
491
Steve Mucklef132c6c2012-06-06 18:30:57 -0700492int audio_aio_fsync(struct file *file, loff_t start, loff_t end, int datasync)
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530493{
494 int rc = 0;
495 struct q6audio_aio *audio = file->private_data;
496
497 if (!audio->enabled || audio->feedback)
498 return -EINVAL;
499
500 /* Blocking client sends more data */
501 mutex_lock(&audio->lock);
502 audio->drv_status |= ADRV_STATUS_FSYNC;
503 mutex_unlock(&audio->lock);
504
505 pr_debug("%s[%p]:\n", __func__, audio);
506
507 mutex_lock(&audio->write_lock);
508 audio->eos_rsp = 0;
509
510 rc = wait_event_interruptible(audio->write_wait,
511 (list_empty(&audio->out_queue)) ||
512 audio->wflush || audio->stopped);
513
514 if (rc < 0) {
515 pr_err("%s[%p]: wait event for list_empty failed, rc = %d\n",
516 __func__, audio, rc);
517 goto done;
518 }
519
520 rc = q6asm_cmd(audio->ac, CMD_EOS);
521
522 if (rc < 0)
523 pr_err("%s[%p]: q6asm_cmd failed, rc = %d",
524 __func__, audio, rc);
525
526 rc = wait_event_interruptible(audio->write_wait,
527 (audio->eos_rsp || audio->wflush ||
528 audio->stopped));
529
530 if (rc < 0) {
531 pr_err("%s[%p]: wait event for eos_rsp failed, rc = %d\n",
532 __func__, audio, rc);
533 goto done;
534 }
535
536 if (audio->eos_rsp == 1) {
537 rc = audio_aio_enable(audio);
538 if (rc)
539 pr_err("%s[%p]: audio enable failed\n",
540 __func__, audio);
541 else {
542 audio->drv_status &= ~ADRV_STATUS_PAUSE;
543 audio->enabled = 1;
544 }
545 }
546
547 if (audio->stopped || audio->wflush)
548 rc = -EBUSY;
549
550done:
551 mutex_unlock(&audio->write_lock);
552 mutex_lock(&audio->lock);
553 audio->drv_status &= ~ADRV_STATUS_FSYNC;
554 mutex_unlock(&audio->lock);
555
556 return rc;
557}
558
559static int audio_aio_events_pending(struct q6audio_aio *audio)
560{
561 unsigned long flags;
562 int empty;
563
564 spin_lock_irqsave(&audio->event_queue_lock, flags);
565 empty = !list_empty(&audio->event_queue);
566 spin_unlock_irqrestore(&audio->event_queue_lock, flags);
567 return empty || audio->event_abort;
568}
569
570static long audio_aio_process_event_req(struct q6audio_aio *audio,
571 void __user *arg)
572{
573 long rc;
574 struct msm_audio_event usr_evt;
575 struct audio_aio_event *drv_evt = NULL;
576 int timeout;
577 unsigned long flags;
578
579 if (copy_from_user(&usr_evt, arg, sizeof(struct msm_audio_event)))
580 return -EFAULT;
581
582 timeout = (int)usr_evt.timeout_ms;
583
584 if (timeout > 0) {
585 rc = wait_event_interruptible_timeout(audio->event_wait,
586 audio_aio_events_pending
587 (audio),
588 msecs_to_jiffies
589 (timeout));
590 if (rc == 0)
591 return -ETIMEDOUT;
592 } else {
593 rc = wait_event_interruptible(audio->event_wait,
594 audio_aio_events_pending(audio));
595 }
596 if (rc < 0)
597 return rc;
598
599 if (audio->event_abort) {
600 audio->event_abort = 0;
601 return -ENODEV;
602 }
603
604 rc = 0;
605
606 spin_lock_irqsave(&audio->event_queue_lock, flags);
607 if (!list_empty(&audio->event_queue)) {
608 drv_evt = list_first_entry(&audio->event_queue,
609 struct audio_aio_event, list);
610 list_del(&drv_evt->list);
611 }
612 if (drv_evt) {
613 usr_evt.event_type = drv_evt->event_type;
614 usr_evt.event_payload = drv_evt->payload;
615 list_add_tail(&drv_evt->list, &audio->free_event_queue);
616 } else {
617 pr_err("%s[%p]:Unexpected path\n", __func__, audio);
618 spin_unlock_irqrestore(&audio->event_queue_lock, flags);
619 return -EPERM;
620 }
621 spin_unlock_irqrestore(&audio->event_queue_lock, flags);
622
623 if (drv_evt->event_type == AUDIO_EVENT_WRITE_DONE) {
624 pr_debug("%s[%p]:posted AUDIO_EVENT_WRITE_DONE to user\n",
625 __func__, audio);
626 mutex_lock(&audio->write_lock);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530627 audio_aio_ion_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530628 drv_evt->payload.aio_buf.buf_len, 0, 0);
629 mutex_unlock(&audio->write_lock);
630 } else if (drv_evt->event_type == AUDIO_EVENT_READ_DONE) {
631 pr_debug("%s[%p]:posted AUDIO_EVENT_READ_DONE to user\n",
632 __func__, audio);
633 mutex_lock(&audio->read_lock);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530634 audio_aio_ion_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530635 drv_evt->payload.aio_buf.buf_len, 0, 0);
636 mutex_unlock(&audio->read_lock);
637 }
638
639 /* Some read buffer might be held up in DSP,release all
640 * Once EOS indicated
641 */
642 if (audio->eos_rsp && !list_empty(&audio->in_queue)) {
643 pr_debug("%s[%p]:Send flush command to release read buffers"\
644 " held up in DSP\n", __func__, audio);
645 audio_aio_flush(audio);
646 }
647
648 if (copy_to_user(arg, &usr_evt, sizeof(usr_evt)))
649 rc = -EFAULT;
650
651 return rc;
652}
653
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530654static int audio_aio_ion_check(struct q6audio_aio *audio,
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530655 void *vaddr, unsigned long len)
656{
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530657 struct audio_aio_ion_region *region_elt;
658 struct audio_aio_ion_region t = {.vaddr = vaddr, .len = len };
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530659
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530660 list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530661 if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
662 OVERLAPS(region_elt, &t)) {
Harmandeep Singheaf59b42012-06-05 21:46:02 -0700663 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 +0530664 __func__, audio, vaddr, len,
665 region_elt->vaddr,
666 (void *)region_elt->paddr, region_elt->len);
667 return -EINVAL;
668 }
669 }
670
671 return 0;
672}
673
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530674static int audio_aio_ion_add(struct q6audio_aio *audio,
675 struct msm_audio_ion_info *info)
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530676{
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530677 ion_phys_addr_t paddr;
678 size_t len;
679 unsigned long kvaddr;
680 struct audio_aio_ion_region *region;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530681 int rc = -EINVAL;
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530682 struct ion_handle *handle;
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530683 unsigned long ionflag;
684 void *temp_ptr;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530685
686 pr_debug("%s[%p]:\n", __func__, audio);
687 region = kmalloc(sizeof(*region), GFP_KERNEL);
688
689 if (!region) {
690 rc = -ENOMEM;
691 goto end;
692 }
693
Deepa Madiregamaa4795072012-06-15 22:35:52 +0530694 handle = ion_import_dma_buf(audio->client, info->fd);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530695 if (IS_ERR_OR_NULL(handle)) {
696 pr_err("%s: could not get handle of the given fd\n", __func__);
697 goto import_error;
698 }
699
Deepa Madiregamaa4795072012-06-15 22:35:52 +0530700 rc = ion_handle_get_flags(audio->client, handle, &ionflag);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530701 if (rc) {
702 pr_err("%s: could not get flags for the handle\n", __func__);
703 goto flag_error;
704 }
705
Deepa Madiregamaa4795072012-06-15 22:35:52 +0530706 temp_ptr = ion_map_kernel(audio->client, handle, ionflag);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530707 if (IS_ERR_OR_NULL(temp_ptr)) {
708 pr_err("%s: could not get virtual address\n", __func__);
709 goto map_error;
710 }
711 kvaddr = (unsigned long)temp_ptr;
712
Deepa Madiregamaa4795072012-06-15 22:35:52 +0530713 rc = ion_phys(audio->client, handle, &paddr, &len);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530714 if (rc) {
715 pr_err("%s: could not get physical address\n", __func__);
716 goto ion_error;
717 }
718
719 rc = audio_aio_ion_check(audio, info->vaddr, len);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530720 if (rc < 0) {
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530721 pr_err("%s: audio_aio_ion_check failed\n", __func__);
722 goto ion_error;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530723 }
724
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530725 region->handle = handle;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530726 region->vaddr = info->vaddr;
727 region->fd = info->fd;
728 region->paddr = paddr;
729 region->kvaddr = kvaddr;
730 region->len = len;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530731 region->ref_cnt = 0;
732 pr_debug("%s[%p]:add region paddr %lx vaddr %p, len %lu kvaddr %lx\n",
733 __func__, audio,
734 region->paddr, region->vaddr, region->len, region->kvaddr);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530735 list_add_tail(&region->list, &audio->ion_region_queue);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530736 rc = q6asm_memory_map(audio->ac, (uint32_t) paddr, IN, (uint32_t) len,
737 1);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530738 if (rc < 0) {
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530739 pr_err("%s[%p]: memory map failed\n", __func__, audio);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530740 goto ion_error;
741 } else {
742 goto end;
743 }
744
745ion_error:
Deepa Madiregamaa4795072012-06-15 22:35:52 +0530746 ion_unmap_kernel(audio->client, handle);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530747map_error:
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530748flag_error:
Deepa Madiregamaa4795072012-06-15 22:35:52 +0530749 ion_free(audio->client, handle);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530750import_error:
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530751 kfree(region);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530752end:
753 return rc;
754}
755
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530756static int audio_aio_ion_remove(struct q6audio_aio *audio,
757 struct msm_audio_ion_info *info)
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530758{
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530759 struct audio_aio_ion_region *region;
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530760 struct list_head *ptr, *next;
761 int rc = -EINVAL;
762
763 pr_debug("%s[%p]:info fd %d vaddr %p\n",
764 __func__, audio, info->fd, info->vaddr);
765
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530766 list_for_each_safe(ptr, next, &audio->ion_region_queue) {
767 region = list_entry(ptr, struct audio_aio_ion_region, list);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530768
769 if ((region->fd == info->fd) &&
770 (region->vaddr == info->vaddr)) {
771 if (region->ref_cnt) {
772 pr_debug("%s[%p]:region %p in use ref_cnt %d\n",
773 __func__, audio, region,
774 region->ref_cnt);
775 break;
776 }
777 pr_debug("%s[%p]:remove region fd %d vaddr %p\n",
778 __func__, audio, info->fd, info->vaddr);
779 rc = q6asm_memory_unmap(audio->ac,
780 (uint32_t) region->paddr, IN);
781 if (rc < 0)
782 pr_err("%s[%p]: memory unmap failed\n",
783 __func__, audio);
784
785 list_del(&region->list);
Deepa Madiregamaa4795072012-06-15 22:35:52 +0530786 ion_unmap_kernel(audio->client, region->handle);
787 ion_free(audio->client, region->handle);
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530788 kfree(region);
789 rc = 0;
790 break;
791 }
792 }
793
794 return rc;
795}
796
797static void audio_aio_async_write(struct q6audio_aio *audio,
798 struct audio_aio_buffer_node *buf_node)
799{
800 int rc;
801 struct audio_client *ac;
802 struct audio_aio_write_param param;
803
Harmandeep Singheaf59b42012-06-05 21:46:02 -0700804 pr_debug("%s[%p]: Send write buff %p phy %lx len %d meta_enable = %d\n",
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530805 __func__, audio, buf_node, buf_node->paddr,
806 buf_node->buf.data_len,
807 audio->buf_cfg.meta_info_enable);
808
809 ac = audio->ac;
810 /* Offset with appropriate meta */
Karthik Reddy Katta6f09ac92012-04-23 15:04:38 +0530811 if (audio->feedback) {
812 /* Non Tunnel mode */
813 param.paddr = buf_node->paddr + sizeof(struct dec_meta_in);
814 param.len = buf_node->buf.data_len - sizeof(struct dec_meta_in);
815 } else {
816 /* Tunnel mode */
817 param.paddr = buf_node->paddr;
818 param.len = buf_node->buf.data_len;
819 }
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530820 param.msw_ts = buf_node->meta_info.meta_in.ntimestamp.highpart;
821 param.lsw_ts = buf_node->meta_info.meta_in.ntimestamp.lowpart;
822 /* If no meta_info enaled, indicate no time stamp valid */
823 if (audio->buf_cfg.meta_info_enable)
824 param.flags = 0;
825 else
826 param.flags = 0xFF00;
827 param.uid = param.paddr;
828 /* Read command will populate paddr as token */
829 buf_node->token = param.paddr;
830 rc = q6asm_async_write(ac, &param);
831 if (rc < 0)
832 pr_err("%s[%p]:failed\n", __func__, audio);
833}
834
835void audio_aio_post_event(struct q6audio_aio *audio, int type,
836 union msm_audio_event_payload payload)
837{
838 struct audio_aio_event *e_node = NULL;
839 unsigned long flags;
840
841 spin_lock_irqsave(&audio->event_queue_lock, flags);
842
843 if (!list_empty(&audio->free_event_queue)) {
844 e_node = list_first_entry(&audio->free_event_queue,
845 struct audio_aio_event, list);
846 list_del(&e_node->list);
847 } else {
848 e_node = kmalloc(sizeof(struct audio_aio_event), GFP_ATOMIC);
849 if (!e_node) {
850 pr_err("%s[%p]:No mem to post event %d\n",
851 __func__, audio, type);
852 spin_unlock_irqrestore(&audio->event_queue_lock, flags);
853 return;
854 }
855 }
856
857 e_node->event_type = type;
858 e_node->payload = payload;
859
860 list_add_tail(&e_node->list, &audio->event_queue);
861 spin_unlock_irqrestore(&audio->event_queue_lock, flags);
862 wake_up(&audio->event_wait);
863}
864
865static void audio_aio_async_read(struct q6audio_aio *audio,
866 struct audio_aio_buffer_node *buf_node)
867{
868 struct audio_client *ac;
869 struct audio_aio_read_param param;
870 int rc;
871
872 pr_debug("%s[%p]: Send read buff %p phy %lx len %d\n",
873 __func__, audio, buf_node,
874 buf_node->paddr, buf_node->buf.buf_len);
875 ac = audio->ac;
876 /* Provide address so driver can append nr frames information */
877 param.paddr = buf_node->paddr +
878 sizeof(struct dec_meta_out);
879 param.len = buf_node->buf.buf_len -
880 sizeof(struct dec_meta_out);
881 param.uid = param.paddr;
882 /* Write command will populate paddr as token */
883 buf_node->token = param.paddr;
884 rc = q6asm_async_read(ac, &param);
885 if (rc < 0)
886 pr_err("%s[%p]:failed\n", __func__, audio);
887}
888
889static int audio_aio_buf_add(struct q6audio_aio *audio, unsigned dir,
890 void __user *arg)
891{
892 unsigned long flags;
893 struct audio_aio_buffer_node *buf_node;
894
895
896 buf_node = kzalloc(sizeof(*buf_node), GFP_KERNEL);
897
898 if (!buf_node)
899 return -ENOMEM;
900
901 if (copy_from_user(&buf_node->buf, arg, sizeof(buf_node->buf))) {
902 kfree(buf_node);
903 return -EFAULT;
904 }
905
Harmandeep Singheaf59b42012-06-05 21:46:02 -0700906 pr_debug("%s[%p]:node %p dir %x buf_addr %p buf_len %d data_len %d\n",
907 __func__, audio, buf_node, dir, buf_node->buf.buf_addr,
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530908 buf_node->buf.buf_len, buf_node->buf.data_len);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +0530909 buf_node->paddr = audio_aio_ion_fixup(audio, buf_node->buf.buf_addr,
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530910 buf_node->buf.buf_len, 1,
911 &buf_node->kvaddr);
912 if (dir) {
913 /* write */
914 if (!buf_node->paddr ||
915 (buf_node->paddr & 0x1) ||
916 (!audio->feedback && !buf_node->buf.data_len)) {
917 kfree(buf_node);
918 return -EINVAL;
919 }
920 extract_meta_out_info(audio, buf_node, 1);
921 /* Not a EOS buffer */
922 if (!(buf_node->meta_info.meta_in.nflags & AUDIO_DEC_EOS_SET)) {
923 spin_lock_irqsave(&audio->dsp_lock, flags);
924 audio_aio_async_write(audio, buf_node);
925 /* EOS buffer handled in driver */
926 list_add_tail(&buf_node->list, &audio->out_queue);
927 spin_unlock_irqrestore(&audio->dsp_lock, flags);
Preetam Singh Ranawat6aae2412011-11-04 18:16:27 +0530928 } else if (buf_node->meta_info.meta_in.nflags
929 & AUDIO_DEC_EOS_SET) {
Deepa Madiregama55cbf782011-09-10 05:44:39 +0530930 if (!audio->wflush) {
931 pr_debug("%s[%p]:Send EOS cmd at i/p\n",
932 __func__, audio);
933 /* Driver will forcefully post writedone event
934 * once eos ack recived from DSP
935 */
936 audio->eos_write_payload.aio_buf =\
937 buf_node->buf;
938 audio->eos_flag = 1;
939 audio->eos_rsp = 0;
940 q6asm_cmd(audio->ac, CMD_EOS);
941 kfree(buf_node);
942 } else { /* Flush in progress, send back i/p
943 * EOS buffer as is
944 */
945 union msm_audio_event_payload event_payload;
946 event_payload.aio_buf = buf_node->buf;
947 audio_aio_post_event(audio,
948 AUDIO_EVENT_WRITE_DONE,
949 event_payload);
950 kfree(buf_node);
951 }
952 }
953 } else {
954 /* read */
955 if (!buf_node->paddr ||
956 (buf_node->paddr & 0x1) ||
957 (buf_node->buf.buf_len < PCM_BUFSZ_MIN)) {
958 kfree(buf_node);
959 return -EINVAL;
960 }
961 /* No EOS reached */
962 if (!audio->eos_rsp) {
963 spin_lock_irqsave(&audio->dsp_lock, flags);
964 audio_aio_async_read(audio, buf_node);
965 /* EOS buffer handled in driver */
966 list_add_tail(&buf_node->list, &audio->in_queue);
967 spin_unlock_irqrestore(&audio->dsp_lock, flags);
968 }
969 /* EOS reached at input side fake all upcoming read buffer to
970 * indicate the same
971 */
972 else {
973 union msm_audio_event_payload event_payload;
974 event_payload.aio_buf = buf_node->buf;
975 event_payload.aio_buf.data_len =
976 insert_eos_buf(audio, buf_node);
977 pr_debug("%s[%p]: propagate READ_DONE as EOS done\n",\
978 __func__, audio);
979 audio_aio_post_event(audio, AUDIO_EVENT_READ_DONE,
980 event_payload);
981 kfree(buf_node);
982 }
983 }
984 return 0;
985}
986
987static void audio_aio_ioport_reset(struct q6audio_aio *audio)
988{
989 if (audio->drv_status & ADRV_STATUS_AIO_INTF) {
990 /* If fsync is in progress, make sure
991 * return value of fsync indicates
992 * abort due to flush
993 */
994 if (audio->drv_status & ADRV_STATUS_FSYNC) {
995 pr_debug("%s[%p]:fsync in progress\n", __func__, audio);
996 audio->drv_ops.out_flush(audio);
997 } else
998 audio->drv_ops.out_flush(audio);
999 audio->drv_ops.in_flush(audio);
1000 }
1001}
1002
1003int audio_aio_open(struct q6audio_aio *audio, struct file *file)
1004{
1005 int rc = 0;
1006 int i;
1007 struct audio_aio_event *e_node = NULL;
1008
1009 /* Settings will be re-config at AUDIO_SET_CONFIG,
1010 * but at least we need to have initial config
1011 */
1012 audio->str_cfg.buffer_size = FRAME_SIZE;
1013 audio->str_cfg.buffer_count = FRAME_NUM;
1014 audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
1015 audio->pcm_cfg.sample_rate = 48000;
1016 audio->pcm_cfg.channel_count = 2;
1017
1018 /* Only AIO interface */
1019 if (file->f_flags & O_NONBLOCK) {
1020 pr_debug("%s[%p]:set to aio interface\n", __func__, audio);
1021 audio->drv_status |= ADRV_STATUS_AIO_INTF;
1022 audio->drv_ops.out_flush = audio_aio_async_out_flush;
1023 audio->drv_ops.in_flush = audio_aio_async_in_flush;
1024 q6asm_set_io_mode(audio->ac, ASYNC_IO_MODE);
1025 } else {
1026 pr_err("%s[%p]:SIO interface not supported\n",
1027 __func__, audio);
1028 rc = -EACCES;
1029 goto fail;
1030 }
1031
1032 /* Initialize all locks of audio instance */
1033 mutex_init(&audio->lock);
1034 mutex_init(&audio->read_lock);
1035 mutex_init(&audio->write_lock);
1036 mutex_init(&audio->get_event_lock);
1037 spin_lock_init(&audio->dsp_lock);
1038 spin_lock_init(&audio->event_queue_lock);
1039 init_waitqueue_head(&audio->cmd_wait);
1040 init_waitqueue_head(&audio->write_wait);
1041 init_waitqueue_head(&audio->event_wait);
1042 INIT_LIST_HEAD(&audio->out_queue);
1043 INIT_LIST_HEAD(&audio->in_queue);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +05301044 INIT_LIST_HEAD(&audio->ion_region_queue);
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301045 INIT_LIST_HEAD(&audio->free_event_queue);
1046 INIT_LIST_HEAD(&audio->event_queue);
1047
1048 audio->drv_ops.out_flush(audio);
1049 audio->opened = 1;
1050 file->private_data = audio;
1051 audio->codec_ioctl = audio_aio_ioctl;
1052
Mingming Yinc09967e2012-04-27 15:09:43 -07001053 for (i = 0; i < AUDIO_EVENT_NUM; i++) {
1054 e_node = kmalloc(sizeof(struct audio_aio_event), GFP_KERNEL);
1055 if (e_node)
1056 list_add_tail(&e_node->list, &audio->free_event_queue);
1057 else {
1058 pr_err("%s[%p]:event pkt alloc failed\n",
1059 __func__, audio);
1060 break;
1061 }
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301062 }
Deepa Madiregamaa4795072012-06-15 22:35:52 +05301063 audio->client = msm_ion_client_create(UINT_MAX, "Audio_Dec_Client");
1064 if (IS_ERR_OR_NULL(audio->client)) {
1065 pr_err("Unable to create ION client\n");
1066 rc = -EACCES;
1067 goto fail;
1068 }
1069 pr_debug("Ion client create in audio_aio_open %p", audio->client);
Mingming Yinc09967e2012-04-27 15:09:43 -07001070 return 0;
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301071fail:
Mingming Yinc09967e2012-04-27 15:09:43 -07001072 q6asm_audio_client_free(audio->ac);
1073 kfree(audio->codec_cfg);
1074 kfree(audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301075 return rc;
1076}
1077
1078long audio_aio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
1079{
1080 struct q6audio_aio *audio = file->private_data;
1081 int rc = 0;
1082
1083 switch (cmd) {
1084 case AUDIO_GET_STATS: {
1085 struct msm_audio_stats stats;
1086 stats.byte_count = atomic_read(&audio->in_bytes);
1087 stats.sample_count = atomic_read(&audio->in_samples);
1088 if (copy_to_user((void *)arg, &stats, sizeof(stats)))
1089 rc = -EFAULT;
1090 break;
1091 }
1092 case AUDIO_GET_EVENT: {
1093 pr_debug("%s[%p]:AUDIO_GET_EVENT\n", __func__, audio);
1094 if (mutex_trylock(&audio->get_event_lock)) {
1095 rc = audio_aio_process_event_req(audio,
1096 (void __user *)arg);
1097 mutex_unlock(&audio->get_event_lock);
1098 } else
1099 rc = -EBUSY;
1100 break;
1101 }
1102 case AUDIO_ABORT_GET_EVENT: {
1103 audio->event_abort = 1;
1104 wake_up(&audio->event_wait);
1105 break;
1106 }
1107 case AUDIO_ASYNC_WRITE: {
1108 mutex_lock(&audio->write_lock);
1109 if (audio->drv_status & ADRV_STATUS_FSYNC)
1110 rc = -EBUSY;
1111 else {
1112 if (audio->enabled)
1113 rc = audio_aio_buf_add(audio, 1,
1114 (void __user *)arg);
1115 else
1116 rc = -EPERM;
1117 }
1118 mutex_unlock(&audio->write_lock);
1119 break;
1120 }
1121 case AUDIO_ASYNC_READ: {
1122 mutex_lock(&audio->read_lock);
1123 if ((audio->feedback) && (audio->enabled))
1124 rc = audio_aio_buf_add(audio, 0,
1125 (void __user *)arg);
1126 else
1127 rc = -EPERM;
1128 mutex_unlock(&audio->read_lock);
1129 break;
1130 }
1131 case AUDIO_OUTPORT_FLUSH: {
1132 pr_debug("%s[%p]:AUDIO_OUTPORT_FLUSH\n", __func__, audio);
1133 mutex_lock(&audio->read_lock);
1134 rc = audio_aio_outport_flush(audio);
1135 if (rc < 0) {
1136 pr_err("%s[%p]: AUDIO_OUTPORT_FLUSH failed\n",
1137 __func__, audio);
1138 rc = -EINTR;
1139 }
1140 mutex_unlock(&audio->read_lock);
1141 break;
1142 }
1143 case AUDIO_STOP: {
1144 pr_debug("%s[%p]: AUDIO_STOP session_id[%d]\n", __func__,
1145 audio, audio->ac->session);
1146 mutex_lock(&audio->lock);
1147 audio->stopped = 1;
1148 audio_aio_flush(audio);
1149 audio->enabled = 0;
1150 audio->drv_status &= ~ADRV_STATUS_PAUSE;
1151 if (rc < 0) {
1152 pr_err("%s[%p]:Audio Stop procedure failed rc=%d\n",
1153 __func__, audio, rc);
1154 mutex_unlock(&audio->lock);
1155 break;
1156 }
1157 mutex_unlock(&audio->lock);
1158 break;
1159 }
1160 case AUDIO_PAUSE: {
1161 pr_debug("%s[%p]:AUDIO_PAUSE %ld\n", __func__, audio, arg);
1162 mutex_lock(&audio->lock);
1163 if (arg == 1) {
1164 rc = audio_aio_pause(audio);
1165 if (rc < 0)
1166 pr_err("%s[%p]: pause FAILED rc=%d\n",
1167 __func__, audio, rc);
1168 audio->drv_status |= ADRV_STATUS_PAUSE;
1169 } else if (arg == 0) {
1170 if (audio->drv_status & ADRV_STATUS_PAUSE) {
1171 rc = audio_aio_enable(audio);
1172 if (rc)
1173 pr_err("%s[%p]: audio enable failed\n",
1174 __func__, audio);
1175 else {
1176 audio->drv_status &= ~ADRV_STATUS_PAUSE;
1177 audio->enabled = 1;
1178 }
1179 }
1180 }
1181 mutex_unlock(&audio->lock);
1182 break;
1183 }
1184 case AUDIO_FLUSH: {
1185 pr_debug("%s[%p]: AUDIO_FLUSH sessionid[%d]\n", __func__,
1186 audio, audio->ac->session);
1187 mutex_lock(&audio->lock);
1188 audio->rflush = 1;
1189 audio->wflush = 1;
1190 /* Flush DSP */
1191 rc = audio_aio_flush(audio);
1192 /* Flush input / Output buffer in software*/
1193 audio_aio_ioport_reset(audio);
1194 if (rc < 0) {
1195 pr_err("%s[%p]:AUDIO_FLUSH interrupted\n",
1196 __func__, audio);
1197 rc = -EINTR;
1198 } else {
1199 audio->rflush = 0;
1200 audio->wflush = 0;
1201 }
1202 audio->eos_flag = 0;
1203 audio->eos_rsp = 0;
1204 mutex_unlock(&audio->lock);
1205 break;
1206 }
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +05301207 case AUDIO_REGISTER_ION: {
1208 struct msm_audio_ion_info info;
1209 pr_debug("%s[%p]:AUDIO_REGISTER_ION\n", __func__, audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301210 mutex_lock(&audio->lock);
1211 if (copy_from_user(&info, (void *)arg, sizeof(info)))
1212 rc = -EFAULT;
1213 else
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +05301214 rc = audio_aio_ion_add(audio, &info);
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301215 mutex_unlock(&audio->lock);
1216 break;
1217 }
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +05301218 case AUDIO_DEREGISTER_ION: {
1219 struct msm_audio_ion_info info;
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301220 mutex_lock(&audio->lock);
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +05301221 pr_debug("%s[%p]:AUDIO_DEREGISTER_ION\n", __func__, audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301222 if (copy_from_user(&info, (void *)arg, sizeof(info)))
1223 rc = -EFAULT;
1224 else
Chaithanya Krishna Bacharajubbc2e702012-02-16 14:46:55 +05301225 rc = audio_aio_ion_remove(audio, &info);
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301226 mutex_unlock(&audio->lock);
1227 break;
1228 }
1229 case AUDIO_GET_STREAM_CONFIG: {
1230 struct msm_audio_stream_config cfg;
1231 mutex_lock(&audio->lock);
1232 memset(&cfg, 0, sizeof(cfg));
1233 cfg.buffer_size = audio->str_cfg.buffer_size;
1234 cfg.buffer_count = audio->str_cfg.buffer_count;
1235 pr_debug("%s[%p]:GET STREAM CFG %d %d\n",
1236 __func__, audio, cfg.buffer_size, cfg.buffer_count);
1237 if (copy_to_user((void *)arg, &cfg, sizeof(cfg)))
1238 rc = -EFAULT;
1239 mutex_unlock(&audio->lock);
1240 break;
1241 }
1242 case AUDIO_SET_STREAM_CONFIG: {
1243 struct msm_audio_stream_config cfg;
1244 pr_debug("%s[%p]:SET STREAM CONFIG\n", __func__, audio);
1245 mutex_lock(&audio->lock);
1246 if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
1247 rc = -EFAULT;
1248 mutex_unlock(&audio->lock);
1249 break;
1250 }
1251 audio->str_cfg.buffer_size = FRAME_SIZE;
1252 audio->str_cfg.buffer_count = FRAME_NUM;
1253 rc = 0;
1254 mutex_unlock(&audio->lock);
1255 break;
1256 }
1257 case AUDIO_GET_CONFIG: {
1258 struct msm_audio_config cfg;
1259 mutex_lock(&audio->lock);
1260 if (copy_to_user((void *)arg, &audio->pcm_cfg, sizeof(cfg)))
1261 rc = -EFAULT;
1262 mutex_unlock(&audio->lock);
1263 break;
1264 }
1265 case AUDIO_SET_CONFIG: {
1266 struct msm_audio_config config;
1267 pr_err("%s[%p]:AUDIO_SET_CONFIG\n", __func__, audio);
1268 mutex_lock(&audio->lock);
1269 if (copy_from_user(&config, (void *)arg, sizeof(config))) {
1270 rc = -EFAULT;
1271 mutex_unlock(&audio->lock);
1272 break;
1273 }
1274 if (audio->feedback != NON_TUNNEL_MODE) {
Harmandeep Singheaf59b42012-06-05 21:46:02 -07001275 pr_err("%s[%p]:Not sufficient permission to change the playback mode\n",
1276 __func__, audio);
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301277 rc = -EACCES;
1278 mutex_unlock(&audio->lock);
1279 break;
1280 }
1281 if ((config.buffer_count > PCM_BUF_COUNT) ||
1282 (config.buffer_count == 1))
1283 config.buffer_count = PCM_BUF_COUNT;
1284
1285 if (config.buffer_size < PCM_BUFSZ_MIN)
1286 config.buffer_size = PCM_BUFSZ_MIN;
1287
1288 audio->pcm_cfg.buffer_count = config.buffer_count;
1289 audio->pcm_cfg.buffer_size = config.buffer_size;
1290 audio->pcm_cfg.channel_count = config.channel_count;
1291 audio->pcm_cfg.sample_rate = config.sample_rate;
1292 rc = 0;
1293 mutex_unlock(&audio->lock);
1294 break;
1295 }
1296 case AUDIO_SET_BUF_CFG: {
1297 struct msm_audio_buf_cfg cfg;
1298 mutex_lock(&audio->lock);
1299 if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
1300 rc = -EFAULT;
1301 mutex_unlock(&audio->lock);
1302 break;
1303 }
1304 if ((audio->feedback == NON_TUNNEL_MODE) &&
1305 !cfg.meta_info_enable) {
1306 rc = -EFAULT;
1307 mutex_unlock(&audio->lock);
1308 break;
1309 }
1310
1311 audio->buf_cfg.meta_info_enable = cfg.meta_info_enable;
1312 pr_debug("%s[%p]:session id %d: Set-buf-cfg: meta[%d]",
1313 __func__, audio,
1314 audio->ac->session, cfg.meta_info_enable);
1315 mutex_unlock(&audio->lock);
1316 break;
1317 }
1318 case AUDIO_GET_BUF_CFG: {
Harmandeep Singheaf59b42012-06-05 21:46:02 -07001319 pr_debug("%s[%p]:session id %d: Get-buf-cfg: meta[%d] framesperbuf[%d]\n",
1320 __func__, audio,
Deepa Madiregama55cbf782011-09-10 05:44:39 +05301321 audio->ac->session, audio->buf_cfg.meta_info_enable,
1322 audio->buf_cfg.frames_per_buf);
1323
1324 mutex_lock(&audio->lock);
1325 if (copy_to_user((void *)arg, &audio->buf_cfg,
1326 sizeof(struct msm_audio_buf_cfg)))
1327 rc = -EFAULT;
1328 mutex_unlock(&audio->lock);
1329 break;
1330 }
1331 case AUDIO_GET_SESSION_ID: {
1332 mutex_lock(&audio->lock);
1333 if (copy_to_user((void *)arg, &audio->ac->session,
1334 sizeof(unsigned short))) {
1335 rc = -EFAULT;
1336 }
1337 mutex_unlock(&audio->lock);
1338 break;
1339 }
1340 default:
1341 rc = -EINVAL;
1342 }
1343 return rc;
1344}