blob: b1446e82cc48a2f749b4c2bdb82b0f340acc0c2f [file] [log] [blame]
Duy Truong790f06d2013-02-13 16:38:12 -08001/* Copyright (c) 2009-2011, The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13#include <linux/module.h>
14#include <linux/fs.h>
15#include <linux/miscdevice.h>
16#include <linux/msm_audio.h>
17#include <asm/uaccess.h>
18#include <asm/atomic.h>
19#include <mach/qdsp5v2/audio_dev_ctl.h>
20#include <linux/wait.h>
21#include <linux/sched.h>
22#include <mach/debug_mm.h>
23#include <mach/qdsp5v2/qdsp5audppmsg.h>
24#include <mach/qdsp5v2/audpp.h>
25#include <linux/slab.h>
26#include <linux/debugfs.h>
27
28#ifndef MAX
29#define MAX(x, y) (((x) > (y)) ? (x) : (y))
30#endif
31
32
33static DEFINE_MUTEX(session_lock);
34
35struct audio_dev_ctrl_state {
36 struct msm_snddev_info *devs[AUDIO_DEV_CTL_MAX_DEV];
37 u32 num_dev;
38 atomic_t opened;
39 struct msm_snddev_info *voice_rx_dev;
40 struct msm_snddev_info *voice_tx_dev;
41 wait_queue_head_t wait;
42};
43
44static struct audio_dev_ctrl_state audio_dev_ctrl;
45struct event_listner event;
46#define MAX_DEC_SESSIONS 7
47#define MAX_ENC_SESSIONS 3
48
49struct session_freq {
50 int freq;
51 int evt;
52};
53
54
55struct audio_routing_info {
56 unsigned short mixer_mask[MAX_DEC_SESSIONS];
57 unsigned short audrec_mixer_mask[MAX_ENC_SESSIONS];
58 struct session_freq dec_freq[MAX_DEC_SESSIONS];
59 struct session_freq enc_freq[MAX_ENC_SESSIONS];
60 int dual_mic_setting[MAX_ENC_SESSIONS];
61 int voice_tx_dev_id;
62 int voice_rx_dev_id;
63 int voice_tx_sample_rate;
64 int voice_rx_sample_rate;
65 signed int voice_tx_vol;
66 signed int voice_rx_vol;
67 int tx_mute;
68 int rx_mute;
69 int voice_state;
70};
71
72static struct audio_routing_info routing_info;
73
74#ifdef CONFIG_DEBUG_FS
75
76static struct dentry *dentry;
77static int rtc_getdevice_dbg_open(struct inode *inode, struct file *file)
78{
79 file->private_data = inode->i_private;
80 MM_INFO("debug intf %s\n", (char *) file->private_data);
81 return 0;
82}
83bool is_dev_opened(u32 adb_id)
84{
85
86 int dev_id = 0;
87 struct msm_snddev_info *dev_info = NULL;
88
89 for (dev_id = 0; dev_id < audio_dev_ctrl.num_dev; dev_id++) {
90 dev_info = audio_dev_ctrl_find_dev(dev_id);
91 if (IS_ERR(dev_info)) {
92 MM_ERR("pass invalid dev_id %d\n", dev_id);
93 return false;
94 }
95 if (dev_info->opened && (dev_info->acdb_id == adb_id))
96 return true;
97 }
98
99 return false;
100}
101static ssize_t rtc_getdevice_dbg_read(struct file *file, char __user *buf,
102 size_t count, loff_t *ppos)
103{
104 static char buffer[1024];
105 static char swap_buf[1024];
106 const int debug_bufmax = sizeof(buffer);
107 int n = 0;
108 int swap_count = 0;
109 int rc = 0;
110 int dev_count = 0;
111 int dev_id = 0;
112 struct msm_snddev_info *dev_info = NULL;
113
114
115 if (audio_dev_ctrl.num_dev <= 0) {
116 MM_ERR("Invalid no Device present\n");
117 dev_count = 0;
118 n = scnprintf(buffer, debug_bufmax, "DEV_NO:0x%x\n", dev_count);
119 } else {
120 for (dev_id = 0; dev_id < audio_dev_ctrl.num_dev; dev_id++) {
121 dev_info = audio_dev_ctrl_find_dev(dev_id);
122 if (IS_ERR(dev_info)) {
123 MM_ERR("pass invalid dev_id %d\n", dev_id);
124 rc = PTR_ERR(dev_info);
125 return rc;
126 }
127 if (dev_info->opened) {
128 n += scnprintf(swap_buf + n, debug_bufmax - n,
129 "ACDB_ID:0x%x;CAPB:0x%x\n",
130 dev_info->acdb_id,
131 dev_info->capability);
132 dev_count++;
133 MM_DBG("RTC Get Device %x COPP %x Session Mask \
134 %x Capb %x Dev Count %x\n",
135 dev_id , dev_info->copp_id, dev_info->sessions,
136 dev_info->capability, dev_count);
137
138 }
139 }
140
141 swap_count = scnprintf(buffer, debug_bufmax, \
142 "DEV_NO:0x%x\n", dev_count);
143
144 memcpy(buffer+swap_count, swap_buf, n*sizeof(char));
145 n = n+swap_count;
146
147 buffer[n] = 0;
148 }
149 return simple_read_from_buffer(buf, count, ppos, buffer, n);
150}
151
152static const struct file_operations rtc_acdb_debug_fops = {
153 .open = rtc_getdevice_dbg_open,
154 .read = rtc_getdevice_dbg_read
155};
156#endif
157int msm_reset_all_device(void)
158{
159 int rc = 0;
160 int dev_id = 0;
161 struct msm_snddev_info *dev_info = NULL;
162
163 for (dev_id = 0; dev_id < audio_dev_ctrl.num_dev; dev_id++) {
164 dev_info = audio_dev_ctrl_find_dev(dev_id);
165 if (IS_ERR(dev_info)) {
166 MM_ERR("pass invalid dev_id %d\n", dev_id);
167 rc = PTR_ERR(dev_info);
168 return rc;
169 }
170 if (!dev_info->opened)
171 continue;
172 MM_DBG("Resetting device %d active on COPP %d"
173 "with 0x%08x as routing\n",
174 dev_id, dev_info->copp_id, dev_info->sessions);
175 broadcast_event(AUDDEV_EVT_REL_PENDING,
176 dev_id,
177 SESSION_IGNORE);
178 rc = dev_info->dev_ops.close(dev_info);
179 if (rc < 0) {
180 MM_ERR("Snd device %d failed close!\n", dev_id);
181 return rc;
182 } else {
183 dev_info->opened = 0;
184 broadcast_event(AUDDEV_EVT_DEV_RLS,
185 dev_id,
186 SESSION_IGNORE);
187 }
188 dev_info->sessions = 0;
189 }
190 return 0;
191}
192EXPORT_SYMBOL(msm_reset_all_device);
193
194int msm_set_dual_mic_config(int enc_session_id, int config)
195{
196 int i;
197 if (enc_session_id >= MAX_ENC_SESSIONS)
198 return -EINVAL;
199 /*config is set(1) dual mic recording is selected */
200 /*config is reset (0) dual mic recording is not selected*/
201 routing_info.dual_mic_setting[enc_session_id] = config;
202 for (i = 0; i < MAX_ENC_SESSIONS; i++)
203 MM_DBG("dual_mic_setting[%d] = %d\n",
204 i, routing_info.dual_mic_setting[i]);
205 return 0;
206}
207EXPORT_SYMBOL(msm_set_dual_mic_config);
208
209int msm_get_dual_mic_config(int enc_session_id)
210{
211 if (enc_session_id >= MAX_ENC_SESSIONS)
212 return -EINVAL;
213 return routing_info.dual_mic_setting[enc_session_id];
214}
215EXPORT_SYMBOL(msm_get_dual_mic_config);
216
217int msm_get_voice_state(void)
218{
219 MM_DBG("voice state %d\n", routing_info.voice_state);
220 return routing_info.voice_state;
221}
222EXPORT_SYMBOL(msm_get_voice_state);
223
224int msm_set_voice_mute(int dir, int mute)
225{
226 MM_DBG("dir %x mute %x\n", dir, mute);
227 if (!audio_dev_ctrl.voice_rx_dev
228 || !audio_dev_ctrl.voice_tx_dev)
229 return -EPERM;
230 if (dir == DIR_TX) {
231 routing_info.tx_mute = mute;
232 broadcast_event(AUDDEV_EVT_DEVICE_VOL_MUTE_CHG,
233 routing_info.voice_tx_dev_id, SESSION_IGNORE);
234 } else
235 return -EPERM;
236 return 0;
237}
238EXPORT_SYMBOL(msm_set_voice_mute);
239
240int msm_set_voice_vol(int dir, s32 volume)
241{
242 if (!audio_dev_ctrl.voice_rx_dev
243 || !audio_dev_ctrl.voice_tx_dev)
244 return -EPERM;
245 if (dir == DIR_TX) {
246 routing_info.voice_tx_vol = volume;
247 broadcast_event(AUDDEV_EVT_DEVICE_VOL_MUTE_CHG,
248 routing_info.voice_tx_dev_id,
249 SESSION_IGNORE);
250 } else if (dir == DIR_RX) {
251 routing_info.voice_rx_vol = volume;
252 broadcast_event(AUDDEV_EVT_DEVICE_VOL_MUTE_CHG,
253 routing_info.voice_rx_dev_id,
254 SESSION_IGNORE);
255 } else
256 return -EINVAL;
257 return 0;
258}
259EXPORT_SYMBOL(msm_set_voice_vol);
260
261void msm_snddev_register(struct msm_snddev_info *dev_info)
262{
263 mutex_lock(&session_lock);
264 if (audio_dev_ctrl.num_dev < AUDIO_DEV_CTL_MAX_DEV) {
265 audio_dev_ctrl.devs[audio_dev_ctrl.num_dev] = dev_info;
266 dev_info->dev_volume = 50; /* 50% */
267 dev_info->sessions = 0x0;
268 dev_info->usage_count = 0;
269 dev_info->set_sample_rate = 0;
270 audio_dev_ctrl.num_dev++;
271 } else
272 MM_ERR("%s: device registry max out\n", __func__);
273 mutex_unlock(&session_lock);
274}
275EXPORT_SYMBOL(msm_snddev_register);
276
277int msm_snddev_devcount(void)
278{
279 return audio_dev_ctrl.num_dev;
280}
281EXPORT_SYMBOL(msm_snddev_devcount);
282
283int msm_snddev_query(int dev_id)
284{
285 if (dev_id <= audio_dev_ctrl.num_dev)
286 return 0;
287 return -ENODEV;
288}
289EXPORT_SYMBOL(msm_snddev_query);
290
291int msm_snddev_is_set(int popp_id, int copp_id)
292{
293 return routing_info.mixer_mask[popp_id] & (0x1 << copp_id);
294}
295EXPORT_SYMBOL(msm_snddev_is_set);
296
297unsigned short msm_snddev_route_enc(int enc_id)
298{
299 if (enc_id >= MAX_ENC_SESSIONS)
300 return -EINVAL;
301 return routing_info.audrec_mixer_mask[enc_id];
302}
303EXPORT_SYMBOL(msm_snddev_route_enc);
304
305unsigned short msm_snddev_route_dec(int popp_id)
306{
307 if (popp_id >= MAX_DEC_SESSIONS)
308 return -EINVAL;
309 return routing_info.mixer_mask[popp_id];
310}
311EXPORT_SYMBOL(msm_snddev_route_dec);
312
313int msm_snddev_set_dec(int popp_id, int copp_id, int set)
314{
315 if (set)
316 routing_info.mixer_mask[popp_id] |= (0x1 << copp_id);
317 else
318 routing_info.mixer_mask[popp_id] &= ~(0x1 << copp_id);
319
320 return 0;
321}
322EXPORT_SYMBOL(msm_snddev_set_dec);
323
324int msm_snddev_set_enc(int popp_id, int copp_id, int set)
325{
326 if (set)
327 routing_info.audrec_mixer_mask[popp_id] |= (0x1 << copp_id);
328 else
329 routing_info.audrec_mixer_mask[popp_id] &= ~(0x1 << copp_id);
330 return 0;
331}
332EXPORT_SYMBOL(msm_snddev_set_enc);
333
334int msm_device_is_voice(int dev_id)
335{
336 if ((dev_id == routing_info.voice_rx_dev_id)
337 || (dev_id == routing_info.voice_tx_dev_id))
338 return 0;
339 else
340 return -EINVAL;
341}
342EXPORT_SYMBOL(msm_device_is_voice);
343
344int msm_set_voc_route(struct msm_snddev_info *dev_info,
345 int stream_type, int dev_id)
346{
347 int rc = 0;
348 u32 session_mask = 0;
349
350 mutex_lock(&session_lock);
351 switch (stream_type) {
352 case AUDIO_ROUTE_STREAM_VOICE_RX:
353 if (audio_dev_ctrl.voice_rx_dev)
354 audio_dev_ctrl.voice_rx_dev->sessions &= ~0xFF;
355
356 if (!(dev_info->capability & SNDDEV_CAP_RX) |
357 !(dev_info->capability & SNDDEV_CAP_VOICE)) {
358 rc = -EINVAL;
359 break;
360 }
361 audio_dev_ctrl.voice_rx_dev = dev_info;
362 if (audio_dev_ctrl.voice_rx_dev) {
363 session_mask =
364 0x1 << (8 * ((int)AUDDEV_CLNT_VOC-1));
365 audio_dev_ctrl.voice_rx_dev->sessions |=
366 session_mask;
367 }
368 routing_info.voice_rx_dev_id = dev_id;
369 break;
370 case AUDIO_ROUTE_STREAM_VOICE_TX:
371 if (audio_dev_ctrl.voice_tx_dev)
372 audio_dev_ctrl.voice_tx_dev->sessions &= ~0xFF;
373
374 if (!(dev_info->capability & SNDDEV_CAP_TX) |
375 !(dev_info->capability & SNDDEV_CAP_VOICE)) {
376 rc = -EINVAL;
377 break;
378 }
379
380 audio_dev_ctrl.voice_tx_dev = dev_info;
381 if (audio_dev_ctrl.voice_rx_dev) {
382 session_mask =
383 0x1 << (8 * ((int)AUDDEV_CLNT_VOC-1));
384 audio_dev_ctrl.voice_tx_dev->sessions |=
385 session_mask;
386 }
387 routing_info.voice_tx_dev_id = dev_id;
388 break;
389 default:
390 rc = -EINVAL;
391 }
392 mutex_unlock(&session_lock);
393 return rc;
394}
395EXPORT_SYMBOL(msm_set_voc_route);
396
397void msm_release_voc_thread(void)
398{
399 wake_up(&audio_dev_ctrl.wait);
400}
401EXPORT_SYMBOL(msm_release_voc_thread);
402
403int msm_snddev_get_enc_freq(session_id)
404{
405 return routing_info.enc_freq[session_id].freq;
406}
407EXPORT_SYMBOL(msm_snddev_get_enc_freq);
408
409int msm_get_voc_freq(int *tx_freq, int *rx_freq)
410{
411 *tx_freq = routing_info.voice_tx_sample_rate;
412 *rx_freq = routing_info.voice_rx_sample_rate;
413 return 0;
414}
415EXPORT_SYMBOL(msm_get_voc_freq);
416
417int msm_get_voc_route(u32 *rx_id, u32 *tx_id)
418{
419 int rc = 0;
420
421 if (!rx_id || !tx_id)
422 return -EINVAL;
423
424 mutex_lock(&session_lock);
425 if (!audio_dev_ctrl.voice_rx_dev || !audio_dev_ctrl.voice_tx_dev) {
426 rc = -ENODEV;
427 mutex_unlock(&session_lock);
428 return rc;
429 }
430
431 *rx_id = audio_dev_ctrl.voice_rx_dev->acdb_id;
432 *tx_id = audio_dev_ctrl.voice_tx_dev->acdb_id;
433
434 mutex_unlock(&session_lock);
435
436 return rc;
437}
438EXPORT_SYMBOL(msm_get_voc_route);
439
440struct msm_snddev_info *audio_dev_ctrl_find_dev(u32 dev_id)
441{
442 struct msm_snddev_info *info;
443
444 if ((audio_dev_ctrl.num_dev - 1) < dev_id) {
445 info = ERR_PTR(-ENODEV);
446 goto error;
447 }
448
449 info = audio_dev_ctrl.devs[dev_id];
450error:
451 return info;
452
453}
454EXPORT_SYMBOL(audio_dev_ctrl_find_dev);
455
456int snddev_voice_set_volume(int vol, int path)
457{
458 if (audio_dev_ctrl.voice_rx_dev
459 && audio_dev_ctrl.voice_tx_dev) {
460 if (path)
461 audio_dev_ctrl.voice_tx_dev->dev_volume = vol;
462 else
463 audio_dev_ctrl.voice_rx_dev->dev_volume = vol;
464 } else
465 return -ENODEV;
466 return 0;
467}
468EXPORT_SYMBOL(snddev_voice_set_volume);
469
470static int audio_dev_ctrl_get_devices(struct audio_dev_ctrl_state *dev_ctrl,
471 void __user *arg)
472{
473 int rc = 0;
474 u32 index;
475 struct msm_snd_device_list work_list;
476 struct msm_snd_device_info *work_tbl;
477
478 if (copy_from_user(&work_list, arg, sizeof(work_list))) {
479 rc = -EFAULT;
480 goto error;
481 }
482
483 if (work_list.num_dev > dev_ctrl->num_dev) {
484 rc = -EINVAL;
485 goto error;
486 }
487
488 work_tbl = kmalloc(work_list.num_dev *
489 sizeof(struct msm_snd_device_info), GFP_KERNEL);
490 if (!work_tbl) {
491 rc = -ENOMEM;
492 goto error;
493 }
494
495 for (index = 0; index < dev_ctrl->num_dev; index++) {
496 work_tbl[index].dev_id = index;
497 work_tbl[index].dev_cap = dev_ctrl->devs[index]->capability;
498 strlcpy(work_tbl[index].dev_name, dev_ctrl->devs[index]->name,
499 64);
500 }
501
502 if (copy_to_user((void *) (work_list.list), work_tbl,
503 work_list.num_dev * sizeof(struct msm_snd_device_info)))
504 rc = -EFAULT;
505 kfree(work_tbl);
506error:
507 return rc;
508}
509
510
511int auddev_register_evt_listner(u32 evt_id, u32 clnt_type, u32 clnt_id,
512 void (*listner)(u32 evt_id,
513 union auddev_evt_data *evt_payload,
514 void *private_data),
515 void *private_data)
516{
517 int rc;
518 struct msm_snd_evt_listner *callback = NULL;
519 struct msm_snd_evt_listner *new_cb;
520
521 new_cb = kzalloc(sizeof(struct msm_snd_evt_listner), GFP_KERNEL);
522 if (!new_cb) {
523 MM_ERR("No memory to add new listener node\n");
524 return -ENOMEM;
525 }
526
527 mutex_lock(&session_lock);
528 new_cb->cb_next = NULL;
529 new_cb->auddev_evt_listener = listner;
530 new_cb->evt_id = evt_id;
531 new_cb->clnt_type = clnt_type;
532 new_cb->clnt_id = clnt_id;
533 new_cb->private_data = private_data;
534 if (event.cb == NULL) {
535 event.cb = new_cb;
536 new_cb->cb_prev = NULL;
537 } else {
538 callback = event.cb;
539 for (; ;) {
540 if (callback->cb_next == NULL)
541 break;
542 else {
543 callback = callback->cb_next;
544 continue;
545 }
546 }
547 callback->cb_next = new_cb;
548 new_cb->cb_prev = callback;
549 }
550 event.num_listner++;
551 mutex_unlock(&session_lock);
552 rc = 0;
553 return rc;
554}
555EXPORT_SYMBOL(auddev_register_evt_listner);
556
557int auddev_unregister_evt_listner(u32 clnt_type, u32 clnt_id)
558{
559 struct msm_snd_evt_listner *callback = event.cb;
560 struct msm_snddev_info *info;
561 u32 session_mask = 0;
562 int i = 0;
563
564 mutex_lock(&session_lock);
565 while (callback != NULL) {
566 if ((callback->clnt_type == clnt_type)
567 && (callback->clnt_id == clnt_id))
568 break;
569 callback = callback->cb_next;
570 }
571 if (callback == NULL) {
572 mutex_unlock(&session_lock);
573 return -EINVAL;
574 }
575
576 if ((callback->cb_next == NULL) && (callback->cb_prev == NULL))
577 event.cb = NULL;
578 else if (callback->cb_next == NULL)
579 callback->cb_prev->cb_next = NULL;
580 else if (callback->cb_prev == NULL) {
581 callback->cb_next->cb_prev = NULL;
582 event.cb = callback->cb_next;
583 } else {
584 callback->cb_prev->cb_next = callback->cb_next;
585 callback->cb_next->cb_prev = callback->cb_prev;
586 }
587 kfree(callback);
588
589 session_mask = (0x1 << (clnt_id)) << (8 * ((int)clnt_type-1));
590 for (i = 0; i < audio_dev_ctrl.num_dev; i++) {
591 info = audio_dev_ctrl.devs[i];
592 info->sessions &= ~session_mask;
593 }
594 if (clnt_type == AUDDEV_CLNT_ENC)
595 msm_set_dual_mic_config(clnt_id, 0);
596 mutex_unlock(&session_lock);
597 return 0;
598}
599EXPORT_SYMBOL(auddev_unregister_evt_listner);
600
601int msm_snddev_withdraw_freq(u32 session_id, u32 capability, u32 clnt_type)
602{
603 int i = 0;
604 struct msm_snddev_info *info;
605 u32 session_mask = 0;
606
607 if ((clnt_type == AUDDEV_CLNT_VOC) && (session_id != 0))
608 return -EINVAL;
609 if ((clnt_type == AUDDEV_CLNT_DEC)
610 && (session_id >= MAX_DEC_SESSIONS))
611 return -EINVAL;
612 if ((clnt_type == AUDDEV_CLNT_ENC)
613 && (session_id >= MAX_ENC_SESSIONS))
614 return -EINVAL;
615
616 session_mask = (0x1 << (session_id)) << (8 * ((int)clnt_type-1));
617
618 for (i = 0; i < audio_dev_ctrl.num_dev; i++) {
619 info = audio_dev_ctrl.devs[i];
620 if ((info->sessions & session_mask)
621 && (info->capability & capability)) {
622 if (!(info->sessions & ~(session_mask)))
623 info->set_sample_rate = 0;
624 }
625 }
626 if (clnt_type == AUDDEV_CLNT_DEC)
627 routing_info.dec_freq[session_id].freq
628 = 0;
629 else if (clnt_type == AUDDEV_CLNT_ENC)
630 routing_info.enc_freq[session_id].freq
631 = 0;
632 else if (capability == SNDDEV_CAP_TX)
633 routing_info.voice_tx_sample_rate = 0;
634 else
635 routing_info.voice_rx_sample_rate = 48000;
636 return 0;
637}
638
639int msm_snddev_request_freq(int *freq, u32 session_id,
640 u32 capability, u32 clnt_type)
641{
642 int i = 0;
643 int rc = 0;
644 struct msm_snddev_info *info;
645 u32 set_freq;
646 u32 session_mask = 0;
647 u32 clnt_type_mask = 0;
648
649 MM_DBG(": clnt_type 0x%08x\n", clnt_type);
650
651 if ((clnt_type == AUDDEV_CLNT_VOC) && (session_id != 0))
652 return -EINVAL;
653 if ((clnt_type == AUDDEV_CLNT_DEC)
654 && (session_id >= MAX_DEC_SESSIONS))
655 return -EINVAL;
656 if ((clnt_type == AUDDEV_CLNT_ENC)
657 && (session_id >= MAX_ENC_SESSIONS))
658 return -EINVAL;
659 session_mask = ((0x1 << session_id)) << (8 * (clnt_type-1));
660 clnt_type_mask = (0xFF << (8 * (clnt_type-1)));
661 if (!(*freq == 8000) && !(*freq == 11025) &&
662 !(*freq == 12000) && !(*freq == 16000) &&
663 !(*freq == 22050) && !(*freq == 24000) &&
664 !(*freq == 32000) && !(*freq == 44100) &&
665 !(*freq == 48000))
666 return -EINVAL;
667
668 for (i = 0; i < audio_dev_ctrl.num_dev; i++) {
669 info = audio_dev_ctrl.devs[i];
670 if ((info->sessions & session_mask)
671 && (info->capability & capability)) {
672 rc = 0;
673 if ((info->sessions & ~clnt_type_mask)
674 && ((*freq != 8000) && (*freq != 16000)
675 && (*freq != 48000))) {
676 if (clnt_type == AUDDEV_CLNT_ENC) {
677 routing_info.enc_freq[session_id].freq
678 = 0;
679 return -EPERM;
680 } else if (clnt_type == AUDDEV_CLNT_DEC) {
681 routing_info.dec_freq[session_id].freq
682 = 0;
683 return -EPERM;
684 }
685 }
686 if (*freq == info->set_sample_rate) {
687 rc = info->set_sample_rate;
688 continue;
689 }
690 set_freq = MAX(*freq, info->set_sample_rate);
691
692
693 if (clnt_type == AUDDEV_CLNT_DEC)
694 routing_info.dec_freq[session_id].freq
695 = set_freq;
696 else if (clnt_type == AUDDEV_CLNT_ENC)
697 routing_info.enc_freq[session_id].freq
698 = set_freq;
699 else if (capability == SNDDEV_CAP_TX)
700 routing_info.voice_tx_sample_rate = set_freq;
701
702 rc = set_freq;
703 *freq = set_freq;
704 /* There is difference in device sample rate to
705 * requested sample rate. So update device sample rate
706 * and propagate sample rate change event to active
707 * sessions of the device.
708 */
709 if (info->set_sample_rate != set_freq) {
710 info->set_sample_rate = set_freq;
711 if (info->opened) {
712 /* Ignore propagating sample rate
713 * change event to requested client
714 * session
715 */
716 if (clnt_type == AUDDEV_CLNT_DEC)
717 routing_info.\
718 dec_freq[session_id].evt = 1;
719 else if (clnt_type == AUDDEV_CLNT_ENC)
720 routing_info.\
721 enc_freq[session_id].evt = 1;
722 broadcast_event(AUDDEV_EVT_FREQ_CHG, i,
723 SESSION_IGNORE);
724 set_freq = info->dev_ops.set_freq(info,
725 set_freq);
726 broadcast_event(AUDDEV_EVT_DEV_RDY, i,
727 SESSION_IGNORE);
728 }
729 }
730 }
731 MM_DBG("info->set_sample_rate = %d\n", info->set_sample_rate);
732 MM_DBG("routing_info.enc_freq.freq = %d\n",
733 routing_info.enc_freq[session_id].freq);
734 }
735 return rc;
736}
737EXPORT_SYMBOL(msm_snddev_request_freq);
738
739int msm_snddev_enable_sidetone(u32 dev_id, u32 enable)
740{
741 int rc;
742 struct msm_snddev_info *dev_info;
743
744 MM_DBG("dev_id %d enable %d\n", dev_id, enable);
745
746 dev_info = audio_dev_ctrl_find_dev(dev_id);
747
748 if (IS_ERR(dev_info)) {
749 MM_ERR("bad dev_id %d\n", dev_id);
750 rc = -EINVAL;
751 } else if (!dev_info->dev_ops.enable_sidetone) {
752 MM_DBG("dev %d no sidetone support\n", dev_id);
753 rc = -EPERM;
754 } else
755 rc = dev_info->dev_ops.enable_sidetone(dev_info, enable);
756
757 return rc;
758}
759EXPORT_SYMBOL(msm_snddev_enable_sidetone);
760
761static long audio_dev_ctrl_ioctl(struct file *file,
762 unsigned int cmd, unsigned long arg)
763{
764 int rc = 0;
765 struct audio_dev_ctrl_state *dev_ctrl = file->private_data;
766
767 mutex_lock(&session_lock);
768 switch (cmd) {
769 case AUDIO_GET_NUM_SND_DEVICE:
770 rc = put_user(dev_ctrl->num_dev, (uint32_t __user *) arg);
771 break;
772 case AUDIO_GET_SND_DEVICES:
773 rc = audio_dev_ctrl_get_devices(dev_ctrl, (void __user *) arg);
774 break;
775 case AUDIO_ENABLE_SND_DEVICE: {
776 struct msm_snddev_info *dev_info;
777 u32 dev_id;
778
779 if (get_user(dev_id, (u32 __user *) arg)) {
780 rc = -EFAULT;
781 break;
782 }
783 dev_info = audio_dev_ctrl_find_dev(dev_id);
784 if (IS_ERR(dev_info))
785 rc = PTR_ERR(dev_info);
786 else {
787 rc = dev_info->dev_ops.open(dev_info);
788 if (!rc)
789 dev_info->opened = 1;
790 wake_up(&audio_dev_ctrl.wait);
791 }
792 break;
793
794 }
795
796 case AUDIO_DISABLE_SND_DEVICE: {
797 struct msm_snddev_info *dev_info;
798 u32 dev_id;
799
800 if (get_user(dev_id, (u32 __user *) arg)) {
801 rc = -EFAULT;
802 break;
803 }
804 dev_info = audio_dev_ctrl_find_dev(dev_id);
805 if (IS_ERR(dev_info))
806 rc = PTR_ERR(dev_info);
807 else {
808 rc = dev_info->dev_ops.close(dev_info);
809 dev_info->opened = 0;
810 }
811 break;
812 }
813
814 case AUDIO_ROUTE_STREAM: {
815 struct msm_audio_route_config route_cfg;
816 struct msm_snddev_info *dev_info;
817
818 if (copy_from_user(&route_cfg, (void __user *) arg,
819 sizeof(struct msm_audio_route_config))) {
820 rc = -EFAULT;
821 break;
822 }
823 MM_DBG("%s: route cfg %d %d type\n", __func__,
824 route_cfg.dev_id, route_cfg.stream_type);
825 dev_info = audio_dev_ctrl_find_dev(route_cfg.dev_id);
826 if (IS_ERR(dev_info)) {
827 MM_ERR("%s: pass invalid dev_id\n", __func__);
828 rc = PTR_ERR(dev_info);
829 break;
830 }
831
832 switch (route_cfg.stream_type) {
833
834 case AUDIO_ROUTE_STREAM_VOICE_RX:
835 if (!(dev_info->capability & SNDDEV_CAP_RX) |
836 !(dev_info->capability & SNDDEV_CAP_VOICE)) {
837 rc = -EINVAL;
838 break;
839 }
840 dev_ctrl->voice_rx_dev = dev_info;
841 break;
842 case AUDIO_ROUTE_STREAM_VOICE_TX:
843 if (!(dev_info->capability & SNDDEV_CAP_TX) |
844 !(dev_info->capability & SNDDEV_CAP_VOICE)) {
845 rc = -EINVAL;
846 break;
847 }
848 dev_ctrl->voice_tx_dev = dev_info;
849 break;
850 }
851 break;
852 }
853
854 default:
855 rc = -EINVAL;
856 }
857 mutex_unlock(&session_lock);
858 return rc;
859}
860
861static int audio_dev_ctrl_open(struct inode *inode, struct file *file)
862{
863 MM_DBG("open audio_dev_ctrl\n");
864 atomic_inc(&audio_dev_ctrl.opened);
865 file->private_data = &audio_dev_ctrl;
866 return 0;
867}
868
869static int audio_dev_ctrl_release(struct inode *inode, struct file *file)
870{
871 MM_DBG("release audio_dev_ctrl\n");
872 atomic_dec(&audio_dev_ctrl.opened);
873 return 0;
874}
875
876static const struct file_operations audio_dev_ctrl_fops = {
877 .owner = THIS_MODULE,
878 .open = audio_dev_ctrl_open,
879 .release = audio_dev_ctrl_release,
880 .unlocked_ioctl = audio_dev_ctrl_ioctl,
881};
882
883
884struct miscdevice audio_dev_ctrl_misc = {
885 .minor = MISC_DYNAMIC_MINOR,
886 .name = "msm_audio_dev_ctrl",
887 .fops = &audio_dev_ctrl_fops,
888};
889
890/* session id is 32 bit routing mask per device
891 * 0-7 for voice clients
892 * 8-15 for Decoder clients
893 * 16-23 for Encoder clients
894 * 24-31 Do not care
895 */
896void broadcast_event(u32 evt_id, u32 dev_id, u32 session_id)
897{
898 int clnt_id = 0, i;
899 union auddev_evt_data *evt_payload;
900 struct msm_snd_evt_listner *callback;
901 struct msm_snddev_info *dev_info = NULL;
902 u32 session_mask = 0;
903 static int pending_sent;
904
905 MM_DBG(": evt_id = %d\n", evt_id);
906
907 if ((evt_id != AUDDEV_EVT_START_VOICE)
908 && (evt_id != AUDDEV_EVT_END_VOICE)
909 && (evt_id != AUDDEV_EVT_STREAM_VOL_CHG)
910 && (evt_id != AUDDEV_EVT_VOICE_STATE_CHG)) {
911 dev_info = audio_dev_ctrl_find_dev(dev_id);
912 if (IS_ERR(dev_info)) {
913 MM_ERR("pass invalid dev_id\n");
914 return;
915 }
916 }
917
918 if (event.cb != NULL)
919 callback = event.cb;
920 else
921 return;
922
923 evt_payload = kzalloc(sizeof(union auddev_evt_data),
924 GFP_KERNEL);
925 if (evt_payload == NULL) {
926 MM_ERR("Memory allocation for event payload failed\n");
927 return;
928 }
929
930 mutex_lock(&session_lock);
931
932 if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
933 routing_info.voice_state = dev_id;
934
935 for (; ;) {
936 if (!(evt_id & callback->evt_id)) {
937 if (callback->cb_next == NULL)
938 break;
939 else {
940 callback = callback->cb_next;
941 continue;
942 }
943 }
944 clnt_id = callback->clnt_id;
945 memset(evt_payload, 0, sizeof(union auddev_evt_data));
946
947 if ((evt_id == AUDDEV_EVT_START_VOICE)
948 || (evt_id == AUDDEV_EVT_END_VOICE))
949 goto skip_check;
950 if (callback->clnt_type == AUDDEV_CLNT_AUDIOCAL)
951 goto aud_cal;
952
953 session_mask = (0x1 << (clnt_id))
954 << (8 * ((int)callback->clnt_type-1));
955
956 if ((evt_id == AUDDEV_EVT_STREAM_VOL_CHG) || \
957 (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)) {
958 MM_DBG("AUDDEV_EVT_STREAM_VOL_CHG or\
959 AUDDEV_EVT_VOICE_STATE_CHG\n");
960 goto volume_strm;
961 }
962
963 MM_DBG("dev_info->sessions = %08x\n", dev_info->sessions);
964
965 if ((!session_id && !(dev_info->sessions & session_mask)) ||
966 (session_id && ((dev_info->sessions & session_mask) !=
967 session_id))) {
968 if (callback->cb_next == NULL)
969 break;
970 else {
971 callback = callback->cb_next;
972 continue;
973 }
974 }
975 if (evt_id == AUDDEV_EVT_DEV_CHG_VOICE)
976 goto voc_events;
977
978volume_strm:
979 if (callback->clnt_type == AUDDEV_CLNT_DEC) {
980 MM_DBG("AUDDEV_CLNT_DEC\n");
981 if (evt_id == AUDDEV_EVT_STREAM_VOL_CHG) {
982 MM_DBG("clnt_id = %d, session_id = 0x%8x\n",
983 clnt_id, session_id);
984 if (session_mask != session_id)
985 goto sent_dec;
986 else
987 evt_payload->session_vol =
988 msm_vol_ctl.volume;
989 } else if (evt_id == AUDDEV_EVT_FREQ_CHG) {
990 if (routing_info.dec_freq[clnt_id].evt) {
991 routing_info.dec_freq[clnt_id].evt
992 = 0;
993 goto sent_dec;
994 } else if (routing_info.dec_freq[clnt_id].freq
995 == dev_info->set_sample_rate)
996 goto sent_dec;
997 else {
998 evt_payload->freq_info.sample_rate
999 = dev_info->set_sample_rate;
1000 evt_payload->freq_info.dev_type
1001 = dev_info->capability;
1002 evt_payload->freq_info.acdb_dev_id
1003 = dev_info->acdb_id;
1004 }
1005 /* Propogate device information to client */
1006 } else if (evt_id == AUDDEV_EVT_DEVICE_INFO) {
1007 evt_payload->devinfo.dev_id
1008 = dev_info->copp_id;
1009 evt_payload->devinfo.acdb_id
1010 = dev_info->acdb_id;
1011 evt_payload->devinfo.dev_type =
1012 (dev_info->capability & SNDDEV_CAP_TX) ?
1013 SNDDEV_CAP_TX : SNDDEV_CAP_RX;
1014 evt_payload->devinfo.sample_rate
1015 = dev_info->sample_rate;
1016 if (session_id == SESSION_IGNORE)
1017 evt_payload->devinfo.sessions
1018 = dev_info->sessions;
1019 else
1020 evt_payload->devinfo.sessions
1021 = session_id;
1022 evt_payload->devinfo.sessions =
1023 (evt_payload->devinfo.sessions >>
1024 ((AUDDEV_CLNT_DEC-1) * 8));
1025 } else if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
1026 evt_payload->voice_state =
1027 routing_info.voice_state;
1028 else
1029 evt_payload->routing_id = dev_info->copp_id;
1030 callback->auddev_evt_listener(
1031 evt_id,
1032 evt_payload,
1033 callback->private_data);
1034sent_dec:
1035 if ((evt_id != AUDDEV_EVT_STREAM_VOL_CHG) &&
1036 (evt_id != AUDDEV_EVT_VOICE_STATE_CHG))
1037 routing_info.dec_freq[clnt_id].freq
1038 = dev_info->set_sample_rate;
1039
1040 if (callback->cb_next == NULL)
1041 break;
1042 else {
1043 callback = callback->cb_next;
1044 continue;
1045 }
1046 }
1047 if (callback->clnt_type == AUDDEV_CLNT_ENC) {
1048
1049 MM_DBG("AUDDEV_CLNT_ENC\n");
1050 if (evt_id == AUDDEV_EVT_FREQ_CHG) {
1051 if (routing_info.enc_freq[clnt_id].evt) {
1052 routing_info.enc_freq[clnt_id].evt
1053 = 0;
1054 goto sent_enc;
1055 } else {
1056 evt_payload->freq_info.sample_rate
1057 = dev_info->set_sample_rate;
1058 evt_payload->freq_info.dev_type
1059 = dev_info->capability;
1060 evt_payload->freq_info.acdb_dev_id
1061 = dev_info->acdb_id;
1062 }
1063 /* Propogate device information to client */
1064 } else if (evt_id == AUDDEV_EVT_DEVICE_INFO) {
1065 evt_payload->devinfo.dev_id
1066 = dev_info->copp_id;
1067 evt_payload->devinfo.acdb_id
1068 = dev_info->acdb_id;
1069 evt_payload->devinfo.dev_type =
1070 (dev_info->capability & SNDDEV_CAP_TX) ?
1071 SNDDEV_CAP_TX : SNDDEV_CAP_RX;
1072 evt_payload->devinfo.sample_rate
1073 = dev_info->sample_rate;
1074 if (session_id == SESSION_IGNORE)
1075 evt_payload->devinfo.sessions
1076 = dev_info->sessions;
1077 else
1078 evt_payload->devinfo.sessions
1079 = session_id;
1080 evt_payload->devinfo.sessions =
1081 (evt_payload->devinfo.sessions >>
1082 ((AUDDEV_CLNT_ENC-1) * 8));
1083 } else if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
1084 evt_payload->voice_state =
1085 routing_info.voice_state;
1086 else
1087 evt_payload->routing_id = dev_info->copp_id;
1088 callback->auddev_evt_listener(
1089 evt_id,
1090 evt_payload,
1091 callback->private_data);
1092sent_enc:
1093 if (callback->cb_next == NULL)
1094 break;
1095 else {
1096 callback = callback->cb_next;
1097 continue;
1098 }
1099 }
1100aud_cal:
1101 if (callback->clnt_type == AUDDEV_CLNT_AUDIOCAL) {
1102 int temp_sessions;
1103 MM_DBG("AUDDEV_CLNT_AUDIOCAL\n");
1104 if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
1105 evt_payload->voice_state =
1106 routing_info.voice_state;
1107 else if (!dev_info->sessions)
1108 goto sent_aud_cal;
1109 else {
1110 evt_payload->audcal_info.dev_id =
1111 dev_info->copp_id;
1112 evt_payload->audcal_info.acdb_id =
1113 dev_info->acdb_id;
1114 evt_payload->audcal_info.dev_type =
1115 (dev_info->capability & SNDDEV_CAP_TX) ?
1116 SNDDEV_CAP_TX : SNDDEV_CAP_RX;
1117 evt_payload->audcal_info.sample_rate =
1118 dev_info->set_sample_rate ?
1119 dev_info->set_sample_rate :
1120 dev_info->sample_rate;
1121 }
1122 if (evt_payload->audcal_info.dev_type ==
1123 SNDDEV_CAP_TX) {
1124 if (session_id == SESSION_IGNORE)
1125 temp_sessions = dev_info->sessions;
1126 else
1127 temp_sessions = session_id;
1128 evt_payload->audcal_info.sessions =
1129 (temp_sessions >>
1130 ((AUDDEV_CLNT_ENC-1) * 8));
1131 } else {
1132 if (session_id == SESSION_IGNORE)
1133 temp_sessions = dev_info->sessions;
1134 else
1135 temp_sessions = session_id;
1136 evt_payload->audcal_info.sessions =
1137 (temp_sessions >>
1138 ((AUDDEV_CLNT_DEC-1) * 8));
1139 }
1140 callback->auddev_evt_listener(
1141 evt_id,
1142 evt_payload,
1143 callback->private_data);
1144
1145sent_aud_cal:
1146 if (callback->cb_next == NULL)
1147 break;
1148 else {
1149 callback = callback->cb_next;
1150 continue;
1151 }
1152 }
1153skip_check:
1154voc_events:
1155 if (callback->clnt_type == AUDDEV_CLNT_VOC) {
1156 MM_DBG("AUDDEV_CLNT_VOC\n");
1157 if (evt_id == AUDDEV_EVT_DEV_RLS) {
1158 if (!pending_sent)
1159 goto sent_voc;
1160 else
1161 pending_sent = 0;
1162 }
1163 if (evt_id == AUDDEV_EVT_REL_PENDING)
1164 pending_sent = 1;
1165
1166 if (evt_id == AUDDEV_EVT_DEVICE_VOL_MUTE_CHG) {
1167 if (dev_info->capability & SNDDEV_CAP_TX) {
1168 evt_payload->voc_vm_info.dev_type =
1169 SNDDEV_CAP_TX;
1170 evt_payload->voc_vm_info.acdb_dev_id =
1171 dev_info->acdb_id;
1172 evt_payload->
1173 voc_vm_info.dev_vm_val.mute =
1174 routing_info.tx_mute;
1175 } else {
1176 evt_payload->voc_vm_info.dev_type =
1177 SNDDEV_CAP_RX;
1178 evt_payload->voc_vm_info.acdb_dev_id =
1179 dev_info->acdb_id;
1180 evt_payload->
1181 voc_vm_info.dev_vm_val.vol =
1182 routing_info.voice_rx_vol;
1183 }
1184 } else if ((evt_id == AUDDEV_EVT_START_VOICE)
1185 || (evt_id == AUDDEV_EVT_END_VOICE))
1186 memset(evt_payload, 0,
1187 sizeof(union auddev_evt_data));
1188 else if (evt_id == AUDDEV_EVT_FREQ_CHG) {
1189 if (routing_info.voice_tx_sample_rate
1190 != dev_info->set_sample_rate) {
1191 routing_info.voice_tx_sample_rate
1192 = dev_info->set_sample_rate;
1193 evt_payload->freq_info.sample_rate
1194 = dev_info->set_sample_rate;
1195 evt_payload->freq_info.dev_type
1196 = dev_info->capability;
1197 evt_payload->freq_info.acdb_dev_id
1198 = dev_info->acdb_id;
1199 } else
1200 goto sent_voc;
1201 } else if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
1202 evt_payload->voice_state =
1203 routing_info.voice_state;
1204 else {
1205 evt_payload->voc_devinfo.dev_type =
1206 (dev_info->capability & SNDDEV_CAP_TX) ?
1207 SNDDEV_CAP_TX : SNDDEV_CAP_RX;
1208 evt_payload->voc_devinfo.acdb_dev_id =
1209 dev_info->acdb_id;
1210 evt_payload->voc_devinfo.dev_sample =
1211 dev_info->set_sample_rate ?
1212 dev_info->set_sample_rate :
1213 dev_info->sample_rate;
1214 evt_payload->voc_devinfo.dev_id = dev_id;
1215 if (dev_info->capability & SNDDEV_CAP_RX) {
1216 for (i = 0; i < VOC_RX_VOL_ARRAY_NUM;
1217 i++) {
1218 evt_payload->
1219 voc_devinfo.max_rx_vol[i] =
1220 dev_info->max_voc_rx_vol[i];
1221 evt_payload
1222 ->voc_devinfo.min_rx_vol[i] =
1223 dev_info->min_voc_rx_vol[i];
1224 }
1225 }
1226 }
1227 callback->auddev_evt_listener(
1228 evt_id,
1229 evt_payload,
1230 callback->private_data);
1231 if (evt_id == AUDDEV_EVT_DEV_RLS)
1232 dev_info->sessions &= ~(0xFF);
1233sent_voc:
1234 if (callback->cb_next == NULL)
1235 break;
1236 else {
1237 callback = callback->cb_next;
1238 continue;
1239 }
1240 }
1241 }
1242 kfree(evt_payload);
1243 mutex_unlock(&session_lock);
1244}
1245EXPORT_SYMBOL(broadcast_event);
1246
1247
1248void mixer_post_event(u32 evt_id, u32 id)
1249{
1250
1251 MM_DBG("evt_id = %d\n", evt_id);
1252 switch (evt_id) {
1253 case AUDDEV_EVT_DEV_CHG_VOICE: /* Called from Voice_route */
1254 broadcast_event(AUDDEV_EVT_DEV_CHG_VOICE, id, SESSION_IGNORE);
1255 break;
1256 case AUDDEV_EVT_DEV_RDY:
1257 broadcast_event(AUDDEV_EVT_DEV_RDY, id, SESSION_IGNORE);
1258 break;
1259 case AUDDEV_EVT_DEV_RLS:
1260 broadcast_event(AUDDEV_EVT_DEV_RLS, id, SESSION_IGNORE);
1261 break;
1262 case AUDDEV_EVT_REL_PENDING:
1263 broadcast_event(AUDDEV_EVT_REL_PENDING, id, SESSION_IGNORE);
1264 break;
1265 case AUDDEV_EVT_DEVICE_VOL_MUTE_CHG:
1266 broadcast_event(AUDDEV_EVT_DEVICE_VOL_MUTE_CHG, id,
1267 SESSION_IGNORE);
1268 break;
1269 case AUDDEV_EVT_STREAM_VOL_CHG:
1270 broadcast_event(AUDDEV_EVT_STREAM_VOL_CHG, id,
1271 SESSION_IGNORE);
1272 break;
1273 case AUDDEV_EVT_START_VOICE:
1274 broadcast_event(AUDDEV_EVT_START_VOICE,
1275 id, SESSION_IGNORE);
1276 break;
1277 case AUDDEV_EVT_END_VOICE:
1278 broadcast_event(AUDDEV_EVT_END_VOICE,
1279 id, SESSION_IGNORE);
1280 break;
1281 case AUDDEV_EVT_FREQ_CHG:
1282 broadcast_event(AUDDEV_EVT_FREQ_CHG, id, SESSION_IGNORE);
1283 break;
1284 default:
1285 break;
1286 }
1287}
1288EXPORT_SYMBOL(mixer_post_event);
1289
1290static int __init audio_dev_ctrl_init(void)
1291{
1292#ifdef CONFIG_DEBUG_FS
1293 char name[sizeof "rtc_get_device"+1];
1294#endif
1295
1296 init_waitqueue_head(&audio_dev_ctrl.wait);
1297
1298 event.cb = NULL;
1299
1300 atomic_set(&audio_dev_ctrl.opened, 0);
1301 audio_dev_ctrl.num_dev = 0;
1302 audio_dev_ctrl.voice_tx_dev = NULL;
1303 audio_dev_ctrl.voice_rx_dev = NULL;
1304 routing_info.voice_state = VOICE_STATE_INVALID;
1305#ifdef CONFIG_DEBUG_FS
1306 snprintf(name, sizeof name, "rtc_get_device");
1307 dentry = debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUGO,
1308 NULL, NULL, &rtc_acdb_debug_fops);
1309 if (IS_ERR(dentry))
1310 MM_DBG("debugfs_create_file failed\n");
1311#endif
1312
1313 return misc_register(&audio_dev_ctrl_misc);
1314}
1315
1316static void __exit audio_dev_ctrl_exit(void)
1317{
1318#ifdef CONFIG_DEBUG_FS
1319 if (dentry)
1320 debugfs_remove(dentry);
1321#endif
1322
1323}
1324module_init(audio_dev_ctrl_init);
1325module_exit(audio_dev_ctrl_exit);
1326
1327MODULE_DESCRIPTION("MSM 7K Audio Device Control driver");
1328MODULE_LICENSE("GPL v2");