blob: e5c59babeaed93321c722b6427d5c712fe7c7b3d [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/*
2 * pcm audio output device
3 *
4 * Copyright (C) 2008 Google, Inc.
5 * Copyright (C) 2008 HTC Corporation
Sidipotu Ashok6ba18202012-09-27 17:02:52 +05306 * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007 *
8 * This software is licensed under the terms of the GNU General Public
9 * License version 2, as published by the Free Software Foundation, and
10 * may be copied, distributed, and modified under those terms.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 */
Santosh Mardifdc227a2011-07-11 17:20:34 +053018#include <asm/atomic.h>
19#include <asm/ioctls.h>
20
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070021#include <linux/module.h>
22#include <linux/fs.h>
23#include <linux/miscdevice.h>
24#include <linux/uaccess.h>
25#include <linux/kthread.h>
26#include <linux/wait.h>
27#include <linux/dma-mapping.h>
28#include <linux/debugfs.h>
29#include <linux/delay.h>
30#include <linux/wakelock.h>
Santosh Mardifdc227a2011-07-11 17:20:34 +053031#include <linux/memory_alloc.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070032#include <linux/msm_audio.h>
33#include <linux/android_pmem.h>
Stephen Boyd2fcabf92012-05-30 10:41:11 -070034#include <linux/pm_qos.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070035
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070036#include <mach/msm_adsp.h>
Santosh Mardifdc227a2011-07-11 17:20:34 +053037#include <mach/iommu.h>
38#include <mach/iommu_domains.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070039#include <mach/qdsp5v2/qdsp5audppcmdi.h>
40#include <mach/qdsp5v2/qdsp5audppmsg.h>
41#include <mach/qdsp5v2/audio_dev_ctl.h>
42#include <mach/qdsp5v2/audpp.h>
43#include <mach/qdsp5v2/audio_dev_ctl.h>
Santosh Mardifdc227a2011-07-11 17:20:34 +053044#include <mach/msm_memtypes.h>
Stephen Boyd2fcabf92012-05-30 10:41:11 -070045#include <mach/cpuidle.h>
Sidipotu Ashok6ba18202012-09-27 17:02:52 +053046#include <linux/msm_ion.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070047#include <mach/htc_pwrsink.h>
48#include <mach/debug_mm.h>
49
50#define BUFSZ (960 * 5)
51#define DMASZ (BUFSZ * 2)
52
53#define HOSTPCM_STREAM_ID 5
54
55struct buffer {
56 void *data;
57 unsigned size;
58 unsigned used;
59 unsigned addr;
60};
61
62struct audio {
63 struct buffer out[2];
64
65 spinlock_t dsp_lock;
66
67 uint8_t out_head;
68 uint8_t out_tail;
69 uint8_t out_needed; /* number of buffers the dsp is waiting for */
70
71 atomic_t out_bytes;
72
73 struct mutex lock;
74 struct mutex write_lock;
75 wait_queue_head_t wait;
76
77 /* configuration to use on next enable */
78 uint32_t out_sample_rate;
79 uint32_t out_channel_mode;
80 uint32_t out_weight;
81 uint32_t out_buffer_size;
82 uint32_t device_events;
83 int16_t source;
84
85 /* data allocated for various buffers */
86 char *data;
87 dma_addr_t phys;
Laura Abbott61399692012-04-30 14:25:46 -070088 void *map_v_write;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070089 int teos; /* valid only if tunnel mode & no data left for decoder */
90 int opened;
91 int enabled;
92 int running;
93 int stopped; /* set when stopped, cleared on flush */
94 uint16_t dec_id;
95 int voice_state;
96
97 struct wake_lock wakelock;
Stephen Boyd2fcabf92012-05-30 10:41:11 -070098 struct pm_qos_request pm_qos_req;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070099
100 struct audpp_cmd_cfg_object_params_volume vol_pan;
Sidipotu Ashok6ba18202012-09-27 17:02:52 +0530101 struct ion_client *client;
102 struct ion_handle *buff_handle;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700103};
104
105static void audio_out_listener(u32 evt_id, union auddev_evt_data *evt_payload,
106 void *private_data)
107{
108 struct audio *audio = private_data;
109 switch (evt_id) {
110 case AUDDEV_EVT_DEV_RDY:
111 MM_DBG(":AUDDEV_EVT_DEV_RDY\n");
112 audio->source |= (0x1 << evt_payload->routing_id);
113 if (audio->running == 1 && audio->enabled == 1)
114 audpp_route_stream(audio->dec_id, audio->source);
115 break;
116 case AUDDEV_EVT_DEV_RLS:
117 MM_DBG(":AUDDEV_EVT_DEV_RLS\n");
118 audio->source &= ~(0x1 << evt_payload->routing_id);
119 if (audio->running == 1 && audio->enabled == 1)
120 audpp_route_stream(audio->dec_id, audio->source);
121 break;
122 case AUDDEV_EVT_STREAM_VOL_CHG:
123 audio->vol_pan.volume = evt_payload->session_vol;
124 MM_DBG(":AUDDEV_EVT_STREAM_VOL_CHG, stream vol %d\n",
125 audio->vol_pan.volume);
126 if (audio->running)
127 audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
128 POPP);
129 break;
130 case AUDDEV_EVT_VOICE_STATE_CHG:
131 MM_DBG("AUDDEV_EVT_VOICE_STATE_CHG, state = %d\n",
132 evt_payload->voice_state);
133 audio->voice_state = evt_payload->voice_state;
134 /* Voice uplink Rx case */
135 if (audio->running &&
136 (audio->source & AUDPP_MIXER_UPLINK_RX) &&
137 (audio->voice_state == VOICE_STATE_OFFCALL)) {
138 MM_DBG("Voice is terminated, Wake up write: %x %x\n",
139 audio->voice_state, audio->source);
140 wake_up(&audio->wait);
141 }
142 break;
143 default:
144 MM_ERR("ERROR:wrong event\n");
145 break;
146 }
147}
148
149static void audio_prevent_sleep(struct audio *audio)
150{
151 MM_DBG("\n"); /* Macro prints the file name and function */
152 wake_lock(&audio->wakelock);
Stephen Boyd2fcabf92012-05-30 10:41:11 -0700153 pm_qos_update_request(&audio->pm_qos_req,
154 msm_cpuidle_get_deep_idle_latency());
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700155}
156
157static void audio_allow_sleep(struct audio *audio)
158{
Stephen Boyd2fcabf92012-05-30 10:41:11 -0700159 pm_qos_update_request(&audio->pm_qos_req, PM_QOS_DEFAULT_VALUE);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700160 wake_unlock(&audio->wakelock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700161 MM_DBG("\n"); /* Macro prints the file name and function */
162}
163
164static int audio_dsp_out_enable(struct audio *audio, int yes);
165static int audio_dsp_send_buffer(struct audio *audio, unsigned id,
166 unsigned len);
167
168static void audio_dsp_event(void *private, unsigned id, uint16_t *msg);
169
170/* must be called with audio->lock held */
171static int audio_enable(struct audio *audio)
172{
173 MM_DBG("\n"); /* Macro prints the file name and function */
174
175 if (audio->enabled)
176 return 0;
177
178 /* refuse to start if we're not ready */
179 if (!audio->out[0].used || !audio->out[1].used)
180 return -EIO;
181
182 /* we start buffers 0 and 1, so buffer 0 will be the
183 * next one the dsp will want
184 */
185 audio->out_tail = 0;
186 audio->out_needed = 0;
187
188 audio_prevent_sleep(audio);
189
190 if (audpp_enable(-1, audio_dsp_event, audio)) {
191 MM_ERR("audpp_enable() failed\n");
192 audio_allow_sleep(audio);
193 return -ENODEV;
194 }
195
196 audio->enabled = 1;
197 htc_pwrsink_set(PWRSINK_AUDIO, 100);
198 return 0;
199}
200
201/* must be called with audio->lock held */
202static int audio_disable(struct audio *audio)
203{
204 MM_DBG("\n"); /* Macro prints the file name and function */
205 if (audio->enabled) {
206 audio->enabled = 0;
207 audio_dsp_out_enable(audio, 0);
208
209 audpp_disable(-1, audio);
210
211 wake_up(&audio->wait);
212 audio->out_needed = 0;
213 audio_allow_sleep(audio);
214 }
215 return 0;
216}
217
218/* ------------------- dsp --------------------- */
219static void audio_dsp_event(void *private, unsigned id, uint16_t *msg)
220{
221 struct audio *audio = private;
222 struct buffer *frame;
223 unsigned long flags;
224 static unsigned long pcmdmamsd_time;
225
226 switch (id) {
227 case AUDPP_MSG_HOST_PCM_INTF_MSG: {
228 unsigned id = msg[3];
229 unsigned idx = msg[4] - 1;
230
231 MM_DBG("HOST_PCM id %d idx %d\n", id, idx);
232 if (id != AUDPP_MSG_HOSTPCM_ID_ARM_RX) {
233 MM_ERR("bogus id\n");
234 break;
235 }
236 if (idx > 1) {
237 MM_ERR("bogus buffer idx\n");
238 break;
239 }
240 spin_lock_irqsave(&audio->dsp_lock, flags);
241 if (audio->running) {
242 atomic_add(audio->out[idx].used, &audio->out_bytes);
243 audio->out[idx].used = 0;
244 frame = audio->out + audio->out_tail;
245 if (frame->used) {
246 /* Reset teos flag to avoid stale
247 * PCMDMAMISS been considered
248 */
249 audio->teos = 0;
250 audio_dsp_send_buffer(
251 audio, audio->out_tail, frame->used);
252 audio->out_tail ^= 1;
253 } else {
254 audio->out_needed++;
255 }
256 wake_up(&audio->wait);
257 }
258 spin_unlock_irqrestore(&audio->dsp_lock, flags);
259 break;
260 }
261 case AUDPP_MSG_PCMDMAMISSED:
262 /* prints only if 1 second is elapsed since the last time
263 * this message has been printed */
264 if (printk_timed_ratelimit(&pcmdmamsd_time, 1000))
265 printk(KERN_INFO "[%s:%s] PCMDMAMISSED %d\n",
266 __MM_FILE__, __func__, msg[0]);
267 audio->teos++;
268 MM_DBG("PCMDMAMISSED Count per Buffer %d\n", audio->teos);
269 wake_up(&audio->wait);
270 break;
271 case AUDPP_MSG_CFG_MSG:
272 if (msg[0] == AUDPP_MSG_ENA_ENA) {
273 MM_DBG("CFG_MSG ENABLE\n");
274 audio->out_needed = 0;
275 audio->running = 1;
276 audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
277 POPP);
278 audpp_route_stream(audio->dec_id, audio->source);
279 audio_dsp_out_enable(audio, 1);
280 } else if (msg[0] == AUDPP_MSG_ENA_DIS) {
281 MM_DBG("CFG_MSG DISABLE\n");
282 audio->running = 0;
283 } else {
284 MM_ERR("CFG_MSG %d?\n", msg[0]);
285 }
286 break;
287 default:
288 MM_ERR("UNKNOWN (%d)\n", id);
289 }
290}
291
292static int audio_dsp_out_enable(struct audio *audio, int yes)
293{
294 struct audpp_cmd_pcm_intf cmd;
295
296 memset(&cmd, 0, sizeof(cmd));
297 cmd.cmd_id = AUDPP_CMD_PCM_INTF;
298 cmd.stream = AUDPP_CMD_POPP_STREAM;
299 cmd.stream_id = audio->dec_id;
300 cmd.config = AUDPP_CMD_PCM_INTF_CONFIG_CMD_V;
301 cmd.intf_type = AUDPP_CMD_PCM_INTF_RX_ENA_ARMTODSP_V;
302
303 if (yes) {
304 cmd.write_buf1LSW = audio->out[0].addr;
305 cmd.write_buf1MSW = audio->out[0].addr >> 16;
306 if (audio->out[0].used)
307 cmd.write_buf1_len = audio->out[0].used;
308 else
309 cmd.write_buf1_len = audio->out[0].size;
310 cmd.write_buf2LSW = audio->out[1].addr;
311 cmd.write_buf2MSW = audio->out[1].addr >> 16;
312 if (audio->out[1].used)
313 cmd.write_buf2_len = audio->out[1].used;
314 else
315 cmd.write_buf2_len = audio->out[1].size;
316 cmd.arm_to_rx_flag = AUDPP_CMD_PCM_INTF_ENA_V;
317 cmd.weight_decoder_to_rx = audio->out_weight;
318 cmd.weight_arm_to_rx = 1;
319 cmd.partition_number_arm_to_dsp = 0;
320 cmd.sample_rate = audio->out_sample_rate;
321 cmd.channel_mode = audio->out_channel_mode;
322 }
323
324 return audpp_send_queue2(&cmd, sizeof(cmd));
325}
326
327static int audio_dsp_send_buffer(struct audio *audio, unsigned idx,
328 unsigned len)
329{
330 struct audpp_cmd_pcm_intf_send_buffer cmd;
331
332 cmd.cmd_id = AUDPP_CMD_PCM_INTF;
333 cmd.stream = AUDPP_CMD_POPP_STREAM;
334 cmd.stream_id = audio->dec_id;
335 cmd.config = AUDPP_CMD_PCM_INTF_BUFFER_CMD_V;
336 cmd.intf_type = AUDPP_CMD_PCM_INTF_RX_ENA_ARMTODSP_V;
337 cmd.dsp_to_arm_buf_id = 0;
338 cmd.arm_to_dsp_buf_id = idx + 1;
339 cmd.arm_to_dsp_buf_len = len;
340
341 return audpp_send_queue2(&cmd, sizeof(cmd));
342}
343
344/* ------------------- device --------------------- */
345static void audio_flush(struct audio *audio)
346{
347 audio->out[0].used = 0;
348 audio->out[1].used = 0;
349 audio->out_head = 0;
350 audio->out_tail = 0;
351 audio->stopped = 0;
352}
353
354static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
355{
356 struct audio *audio = file->private_data;
357 int rc = -EINVAL;
358 unsigned long flags = 0;
359
360 if (cmd == AUDIO_GET_STATS) {
361 struct msm_audio_stats stats;
362 stats.byte_count = atomic_read(&audio->out_bytes);
363 if (copy_to_user((void *) arg, &stats, sizeof(stats)))
364 return -EFAULT;
365 return 0;
366 }
367
368 switch (cmd) {
369 case AUDIO_SET_VOLUME:
370 spin_lock_irqsave(&audio->dsp_lock, flags);
371 audio->vol_pan.volume = arg;
372 if (audio->running)
373 audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
374 POPP);
375 spin_unlock_irqrestore(&audio->dsp_lock, flags);
376 return 0;
377
378 case AUDIO_SET_PAN:
379 spin_lock_irqsave(&audio->dsp_lock, flags);
380 audio->vol_pan.pan = arg;
381 if (audio->running)
382 audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
383 POPP);
384 spin_unlock_irqrestore(&audio->dsp_lock, flags);
385 return 0;
386 }
387
388 mutex_lock(&audio->lock);
389 switch (cmd) {
390 case AUDIO_START:
391 if ((audio->voice_state != VOICE_STATE_INCALL)
392 && (audio->source & AUDPP_MIXER_UPLINK_RX)) {
393 MM_ERR("Unable to Start : state %d source %d\n",
394 audio->voice_state, audio->source);
395 rc = -EPERM;
396 break;
397 }
398 rc = audio_enable(audio);
399 break;
400 case AUDIO_STOP:
401 rc = audio_disable(audio);
402 audio->stopped = 1;
403 break;
404 case AUDIO_FLUSH:
405 if (audio->stopped) {
406 /* Make sure we're stopped and we wake any threads
407 * that might be blocked holding the write_lock.
408 * While audio->stopped write threads will always
409 * exit immediately.
410 */
411 wake_up(&audio->wait);
412 mutex_lock(&audio->write_lock);
413 audio_flush(audio);
414 mutex_unlock(&audio->write_lock);
415 }
416 case AUDIO_SET_CONFIG: {
417 struct msm_audio_config config;
418 if (copy_from_user(&config, (void *) arg, sizeof(config))) {
419 rc = -EFAULT;
420 break;
421 }
422 if (config.channel_count == 1)
423 config.channel_count = AUDPP_CMD_PCM_INTF_MONO_V;
424 else if (config.channel_count == 2)
425 config.channel_count = AUDPP_CMD_PCM_INTF_STEREO_V;
426 else {
427 rc = -EINVAL;
428 break;
429 }
430 audio->out_sample_rate = config.sample_rate;
431 audio->out_channel_mode = config.channel_count;
432 rc = 0;
433 break;
434 }
435 case AUDIO_GET_CONFIG: {
436 struct msm_audio_config config;
437 config.buffer_size = BUFSZ;
438 config.buffer_count = 2;
439 config.sample_rate = audio->out_sample_rate;
440 if (audio->out_channel_mode == AUDPP_CMD_PCM_INTF_MONO_V)
441 config.channel_count = 1;
442 else
443 config.channel_count = 2;
444
445 config.unused[0] = 0;
446 config.unused[1] = 0;
447 config.unused[2] = 0;
448 if (copy_to_user((void *) arg, &config, sizeof(config)))
449 rc = -EFAULT;
450 else
451 rc = 0;
452 break;
453 }
454 case AUDIO_GET_SESSION_ID: {
455 if (copy_to_user((void *) arg, &audio->dec_id,
456 sizeof(unsigned short)))
457 return -EFAULT;
458 rc = 0;
459 break;
460 }
461 default:
462 rc = -EINVAL;
463 }
464 mutex_unlock(&audio->lock);
465 return rc;
466}
467
468/* Only useful in tunnel-mode */
Steve Mucklef132c6c2012-06-06 18:30:57 -0700469static int audio_fsync(struct file *file, loff_t ppos1, loff_t ppos2, int datasync)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700470{
471 struct audio *audio = file->private_data;
472 int rc = 0;
473
474 if (!audio->running)
475 return -EINVAL;
476
477 mutex_lock(&audio->write_lock);
478
479 /* PCM DMAMISS message is sent only once in
480 * hpcm interface. So, wait for buffer complete
481 * and teos flag.
482 */
483 rc = wait_event_interruptible(audio->wait,
484 (!audio->out[0].used &&
485 !audio->out[1].used));
486
487 if (rc < 0)
488 goto done;
489
490 rc = wait_event_interruptible(audio->wait,
491 audio->teos);
492done:
493 mutex_unlock(&audio->write_lock);
494 return rc;
495}
496
497static ssize_t audio_read(struct file *file, char __user *buf,
498 size_t count, loff_t *pos)
499{
500 return -EINVAL;
501}
502
503static inline int rt_policy(int policy)
504{
505 if (unlikely(policy == SCHED_FIFO) || unlikely(policy == SCHED_RR))
506 return 1;
507 return 0;
508}
509
510static inline int task_has_rt_policy(struct task_struct *p)
511{
512 return rt_policy(p->policy);
513}
514
515static ssize_t audio_write(struct file *file, const char __user *buf,
516 size_t count, loff_t *pos)
517{
518 struct sched_param s = { .sched_priority = 1 };
519 struct audio *audio = file->private_data;
520 unsigned long flags;
521 const char __user *start = buf;
522 struct buffer *frame;
523 size_t xfer;
524 int old_prio = current->rt_priority;
525 int old_policy = current->policy;
526 int cap_nice = cap_raised(current_cap(), CAP_SYS_NICE);
527 int rc = 0;
528
529
530 if ((audio->voice_state == VOICE_STATE_OFFCALL)
531 && (audio->source & AUDPP_MIXER_UPLINK_RX) &&
532 audio->running) {
533 MM_ERR("Not Permitted Voice Terminated: state %d source %x \
534 running %d\n",
535 audio->voice_state, audio->source, audio->running);
536 return -EPERM;
537 }
538 /* just for this write, set us real-time */
539 if (!task_has_rt_policy(current)) {
540 struct cred *new = prepare_creds();
541 cap_raise(new->cap_effective, CAP_SYS_NICE);
542 commit_creds(new);
543 if ((sched_setscheduler(current, SCHED_RR, &s)) < 0)
544 MM_ERR("sched_setscheduler failed\n");
545 }
546
547 mutex_lock(&audio->write_lock);
548 while (count > 0) {
549 frame = audio->out + audio->out_head;
550
551 rc = wait_event_interruptible(audio->wait,
552 (frame->used == 0) || (audio->stopped) ||
553 ((audio->voice_state == VOICE_STATE_OFFCALL) &&
554 (audio->source & AUDPP_MIXER_UPLINK_RX)));
555
556 if (rc < 0)
557 break;
558 if (audio->stopped) {
559 rc = -EBUSY;
560 break;
561 } else if ((audio->voice_state == VOICE_STATE_OFFCALL) &&
562 (audio->source & AUDPP_MIXER_UPLINK_RX)) {
563 MM_ERR("Not Permitted Voice Terminated: %d\n",
564 audio->voice_state);
565 rc = -EPERM;
566 break;
567 }
568
569 xfer = count > frame->size ? frame->size : count;
570 if (copy_from_user(frame->data, buf, xfer)) {
571 rc = -EFAULT;
572 break;
573 }
574 frame->used = xfer;
575 audio->out_head ^= 1;
576 count -= xfer;
577 buf += xfer;
578
579 spin_lock_irqsave(&audio->dsp_lock, flags);
580 frame = audio->out + audio->out_tail;
581 if (frame->used && audio->out_needed) {
582 /* Reset teos flag to avoid stale
583 * PCMDMAMISS been considered
584 */
585 audio->teos = 0;
586 audio_dsp_send_buffer(audio, audio->out_tail,
587 frame->used);
588 audio->out_tail ^= 1;
589 audio->out_needed--;
590 }
591 spin_unlock_irqrestore(&audio->dsp_lock, flags);
592 }
593
594 mutex_unlock(&audio->write_lock);
595
596 /* restore scheduling policy and priority */
597 if (!rt_policy(old_policy)) {
598 struct sched_param v = { .sched_priority = old_prio };
599 if ((sched_setscheduler(current, old_policy, &v)) < 0)
600 MM_ERR("sched_setscheduler failed\n");
601 if (likely(!cap_nice)) {
602 struct cred *new = prepare_creds();
603 cap_lower(new->cap_effective, CAP_SYS_NICE);
604 commit_creds(new);
605 }
606 }
607
608 if (buf > start)
609 return buf - start;
610 return rc;
611}
612
613static int audio_release(struct inode *inode, struct file *file)
614{
615 struct audio *audio = file->private_data;
616
617 mutex_lock(&audio->lock);
618 auddev_unregister_evt_listner(AUDDEV_CLNT_DEC, audio->dec_id);
619 audio_disable(audio);
620 audio_flush(audio);
621 audio->opened = 0;
622 mutex_unlock(&audio->lock);
623 htc_pwrsink_set(PWRSINK_AUDIO, 0);
624 return 0;
625}
626
627static struct audio the_audio;
628
629static int audio_open(struct inode *inode, struct file *file)
630{
631 struct audio *audio = &the_audio;
632 int rc;
633
634 mutex_lock(&audio->lock);
635
636 if (audio->opened) {
637 MM_ERR("busy\n");
638 rc = -EBUSY;
639 goto done;
640 }
641
642
643 audio->dec_id = HOSTPCM_STREAM_ID;
644
645 audio->out_buffer_size = BUFSZ;
646 audio->out_sample_rate = 44100;
647 audio->out_channel_mode = AUDPP_CMD_PCM_INTF_STEREO_V;
648 audio->out_weight = 100;
649
650 audio->out[0].data = audio->data + 0;
651 audio->out[0].addr = audio->phys + 0;
652 audio->out[0].size = BUFSZ;
653
654 audio->out[1].data = audio->data + BUFSZ;
655 audio->out[1].addr = audio->phys + BUFSZ;
656 audio->out[1].size = BUFSZ;
657
658 audio->vol_pan.volume = 0x2000;
659 audio->vol_pan.pan = 0x0;
660 audio->source = 0x0;
661
662 audio_flush(audio);
663 audio->voice_state = msm_get_voice_state();
664 MM_DBG("voice_state = %x\n", audio->voice_state);
665 audio->device_events = AUDDEV_EVT_DEV_RDY
666 |AUDDEV_EVT_DEV_RLS|
667 AUDDEV_EVT_STREAM_VOL_CHG|
668 AUDDEV_EVT_VOICE_STATE_CHG;
669
670 MM_DBG("register for event callback pdata %p\n", audio);
671 rc = auddev_register_evt_listner(audio->device_events,
672 AUDDEV_CLNT_DEC,
673 audio->dec_id,
674 audio_out_listener,
675 (void *)audio);
676 if (rc) {
677 MM_ERR("%s: failed to register listener\n", __func__);
678 goto done;
679 }
680
681 file->private_data = audio;
682 audio->opened = 1;
683 rc = 0;
684done:
685 mutex_unlock(&audio->lock);
686 return rc;
687}
688
689static const struct file_operations audio_fops = {
690 .owner = THIS_MODULE,
691 .open = audio_open,
692 .release = audio_release,
693 .read = audio_read,
694 .write = audio_write,
695 .unlocked_ioctl = audio_ioctl,
696 .fsync = audio_fsync,
697};
698
699struct miscdevice audio_misc = {
700 .minor = MISC_DYNAMIC_MINOR,
701 .name = "msm_pcm_out",
702 .fops = &audio_fops,
703};
704
705static int __init audio_init(void)
706{
Sidipotu Ashok6ba18202012-09-27 17:02:52 +0530707 unsigned long ionflag = 0;
708 ion_phys_addr_t addr = 0;
709 int rc;
710 int len = 0;
711 struct ion_handle *handle = NULL;
712 struct ion_client *client = NULL;
713
714 client = msm_ion_client_create(UINT_MAX, "HostPCM");
715 if (IS_ERR_OR_NULL(client)) {
716 MM_ERR("Unable to create ION client\n");
717 rc = -ENOMEM;
718 goto client_create_error;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700719 }
Sidipotu Ashok6ba18202012-09-27 17:02:52 +0530720 the_audio.client = client;
721
722 handle = ion_alloc(client, DMASZ, SZ_4K,
723 ION_HEAP(ION_AUDIO_HEAP_ID), 0);
724 if (IS_ERR_OR_NULL(handle)) {
725 MM_ERR("Unable to create allocate O/P buffers\n");
726 rc = -ENOMEM;
727 goto buff_alloc_error;
728 }
729 the_audio.buff_handle = handle;
730
731 rc = ion_phys(client, handle, &addr, &len);
732 if (rc) {
733 MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
734 (unsigned int) addr, (unsigned int) len);
735 goto buff_get_phys_error;
736 } else
737 MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
738 (unsigned int) addr, (unsigned int) len);
739 the_audio.phys = (int32_t)addr;
740
741 rc = ion_handle_get_flags(client, handle, &ionflag);
742 if (rc) {
743 MM_ERR("could not get flags for the handle\n");
744 goto buff_get_flags_error;
745 }
746
747 the_audio.map_v_write = ion_map_kernel(client, handle);
748 if (IS_ERR(the_audio.map_v_write)) {
749 MM_ERR("could not map write buffers\n");
750 rc = -ENOMEM;
751 goto buff_map_error;
752 }
753 the_audio.data = (char *)the_audio.map_v_write;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700754 MM_DBG("Memory addr = 0x%8x phy addr = 0x%8x\n",\
755 (int) the_audio.data, (int) the_audio.phys);
756 mutex_init(&the_audio.lock);
757 mutex_init(&the_audio.write_lock);
758 spin_lock_init(&the_audio.dsp_lock);
759 init_waitqueue_head(&the_audio.wait);
760 wake_lock_init(&the_audio.wakelock, WAKE_LOCK_SUSPEND, "audio_pcm");
Stephen Boyd2fcabf92012-05-30 10:41:11 -0700761 pm_qos_add_request(&the_audio.pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
762 PM_QOS_DEFAULT_VALUE);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700763 return misc_register(&audio_misc);
Sidipotu Ashok6ba18202012-09-27 17:02:52 +0530764buff_map_error:
765buff_get_phys_error:
766buff_get_flags_error:
767 ion_free(client, the_audio.buff_handle);
768buff_alloc_error:
769 ion_client_destroy(client);
770client_create_error:
771 return rc;
772
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700773}
774
775late_initcall(audio_init);