blob: cf2748807bea17d7bdcf956a87076740cc23d0ff [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
2 *
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
14#include <linux/slab.h>
15#include <linux/fs.h>
16#include <linux/module.h>
17#include <linux/miscdevice.h>
18#include <linux/mutex.h>
19#include <linux/sched.h>
20#include <linux/wait.h>
21#include <linux/uaccess.h>
22
23#include <linux/msm_audio.h>
24
25#include <mach/msm_qdsp6_audio.h>
26#include <mach/debug_mm.h>
27
28struct dtmf {
29 struct mutex lock;
30 struct audio_client *ac;
31 struct msm_dtmf_config cfg;
32};
33
34static long dtmf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
35{
36 struct dtmf *dtmf = file->private_data;
37 int rc = 0;
38
39 mutex_lock(&dtmf->lock);
40 switch (cmd) {
41
42 case AUDIO_START: {
43 pr_debug("[%s:%s] AUDIO_START\n", __MM_FILE__, __func__);
44 if (dtmf->ac) {
45 pr_err("[%s:%s] active session already existing\n",
46 __MM_FILE__, __func__);
47 rc = -EBUSY;
48 } else {
49 dtmf->ac = q6audio_open_dtmf(48000, 2, 0);
50 if (!dtmf->ac)
51 rc = -ENOMEM;
52 }
53 break;
54 }
55 case AUDIO_PLAY_DTMF: {
56 rc = copy_from_user((void *)&dtmf->cfg, (void *)arg,
57 sizeof(struct msm_dtmf_config));
58
59 pr_debug("[%s:%s] PLAY_DTMF: high = %d, low = %d\n",
60 __MM_FILE__, __func__, dtmf->cfg.dtmf_hi,
61 dtmf->cfg.dtmf_low);
62 rc = q6audio_play_dtmf(dtmf->ac, dtmf->cfg.dtmf_hi,
63 dtmf->cfg.dtmf_low, dtmf->cfg.duration,
64 dtmf->cfg.rx_gain);
65 if (rc) {
66 pr_err("[%s:%s] DTMF_START failed\n", __MM_FILE__,
67 __func__);
68 break;
69 }
70 break;
71 }
72 default:
73 rc = -EINVAL;
74 }
75 mutex_unlock(&dtmf->lock);
76
77 pr_debug("[%s:%s] rc = %d\n", __MM_FILE__, __func__, rc) ;
78 return rc;
79}
80
81static int dtmf_open(struct inode *inode, struct file *file)
82{
83 int rc = 0;
84
85 struct dtmf *dtmf;
86 pr_info("[%s:%s] open\n", __MM_FILE__, __func__);
87 dtmf = kzalloc(sizeof(struct dtmf), GFP_KERNEL);
88
89 if (!dtmf)
90 return -ENOMEM;
91
92 mutex_init(&dtmf->lock);
93
94 file->private_data = dtmf;
95 return rc;
96}
97
98static int dtmf_release(struct inode *inode, struct file *file)
99{
100 struct dtmf *dtmf = file->private_data;
101 if (dtmf->ac)
102 q6audio_close(dtmf->ac);
103 kfree(dtmf);
104 pr_info("[%s:%s] release\n", __MM_FILE__, __func__);
105 return 0;
106}
107
108static const struct file_operations dtmf_fops = {
109 .owner = THIS_MODULE,
110 .open = dtmf_open,
111 .release = dtmf_release,
112 .unlocked_ioctl = dtmf_ioctl,
113};
114
115struct miscdevice dtmf_misc = {
116 .minor = MISC_DYNAMIC_MINOR,
117 .name = "msm_dtmf",
118 .fops = &dtmf_fops,
119};
120
121static int __init dtmf_init(void)
122{
123 return misc_register(&dtmf_misc);
124}
125
126device_initcall(dtmf_init);