blob: 4195454776c243b84bb2bbd9445beb55a5b9a229 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* arch/arm/mach-msm/qdsp6/auxpcm_lb_in.c
2 *
3 * Copyright (C) 2009 Google, Inc.
4 * Copyright (C) 2009 HTC Corporation
5 * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
6 *
7 * This software is licensed under the terms of the GNU General Public
8 * License version 2, as published by the Free Software Foundation, and
9 * may be copied, distributed, and modified under those terms.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 */
17
18#include <linux/slab.h>
19#include <linux/fs.h>
20#include <linux/module.h>
21#include <linux/miscdevice.h>
22#include <linux/mutex.h>
23#include <linux/sched.h>
24#include <linux/wait.h>
25#include <linux/uaccess.h>
26
27#include <linux/msm_audio.h>
28
29#include <mach/msm_qdsp6_audio.h>
30#include <mach/debug_mm.h>
31
32struct auxpcm {
33 struct mutex lock;
34 struct audio_client *ac;
35 uint32_t sample_rate;
36 uint32_t channel_count;
37 int opened;;
38};
39
40static long auxpcmin_ioctl(struct file *file, unsigned int cmd,
41 unsigned long arg)
42{
43 struct auxpcm *auxpcmin = file->private_data;
44 int rc = 0;
45
46 mutex_lock(&auxpcmin->lock);
47 switch (cmd) {
48 case AUDIO_START: {
49 uint32_t acdb_id;
50 pr_debug("[%s:%s] AUDIO_START\n", __MM_FILE__, __func__);
51 if (arg == 0) {
52 acdb_id = 0;
53 } else if (copy_from_user(&acdb_id, (void *) arg,
54 sizeof(acdb_id))) {
55 pr_info("[%s:%s] copy acdb_id from user failed\n",
56 __MM_FILE__, __func__);
57 rc = -EFAULT;
58 break;
59 }
60 if (auxpcmin->ac) {
61 pr_err("[%s:%s] active session already existing\n",
62 __MM_FILE__, __func__);
63 rc = -EBUSY;
64 } else {
65 auxpcmin->ac =
66 q6audio_open_auxpcm(auxpcmin->sample_rate,
67 auxpcmin->channel_count,
68 AUDIO_FLAG_READ, acdb_id);
69 if (!auxpcmin->ac) {
70 pr_err("[%s:%s] auxpcm open session failed\n",
71 __MM_FILE__, __func__);
72 rc = -ENOMEM;
73 }
74 }
75 break;
76 }
77 case AUDIO_STOP:
78 pr_debug("[%s:%s] AUDIO_STOP\n", __MM_FILE__, __func__);
79 break;
80 case AUDIO_FLUSH:
81 break;
82 case AUDIO_SET_CONFIG: {
83 struct msm_audio_config config;
84 if (auxpcmin->ac) {
85 rc = -EBUSY;
86 pr_err("[%s:%s] active session already existing\n",
87 __MM_FILE__, __func__);
88 break;
89 }
90 if (copy_from_user(&config, (void *) arg, sizeof(config))) {
91 rc = -EFAULT;
92 break;
93 }
94 pr_debug("[%s:%s] SET_CONFIG: samplerate = %d, channels = %d\n",
95 __MM_FILE__, __func__, config.sample_rate,
96 config.channel_count);
97 if (config.channel_count != 1) {
98 rc = -EINVAL;
99 pr_err("[%s:%s] invalid channelcount %d\n",
100 __MM_FILE__, __func__, config.channel_count);
101 break;
102 }
103 if (config.sample_rate != 8000) {
104 rc = -EINVAL;
105 pr_err("[%s:%s] invalid samplerate %d\n", __MM_FILE__,
106 __func__, config.sample_rate);
107 break;
108 }
109 auxpcmin->sample_rate = config.sample_rate;
110 auxpcmin->channel_count = config.channel_count;
111 break;
112 }
113 case AUDIO_GET_CONFIG: {
114 struct msm_audio_config config;
115 config.buffer_size = 0;
116 config.buffer_count = 0;
117 config.sample_rate = auxpcmin->sample_rate;
118 config.channel_count = auxpcmin->channel_count;
119 config.unused[0] = 0;
120 config.unused[1] = 0;
121 config.unused[2] = 0;
122 if (copy_to_user((void *) arg, &config, sizeof(config)))
123 rc = -EFAULT;
124 pr_debug("[%s:%s] GET_CONFIG: samplerate = %d, channels = %d\n",
125 __MM_FILE__, __func__, config.sample_rate,
126 config.channel_count);
127 break;
128 }
129 default:
130 rc = -EINVAL;
131 }
132 mutex_unlock(&auxpcmin->lock);
133 pr_debug("[%s:%s] rc = %d\n", __MM_FILE__, __func__, rc);
134 return rc;
135}
136
137static struct auxpcm the_auxpcmin;
138
139static int auxpcmin_open(struct inode *inode, struct file *file)
140{
141 struct auxpcm *auxpcmin = &the_auxpcmin;
142
143 pr_info("[%s:%s] open\n", __MM_FILE__, __func__);
144 mutex_lock(&auxpcmin->lock);
145 if (auxpcmin->opened) {
146 pr_err("aux pcm loopback tx already open!\n");
147 mutex_unlock(&auxpcmin->lock);
148 return -EBUSY;
149 }
150 auxpcmin->channel_count = 1;
151 auxpcmin->sample_rate = 8000;
152 auxpcmin->opened = 1;
153 file->private_data = auxpcmin;
154 mutex_unlock(&auxpcmin->lock);
155 return 0;
156}
157
158static int auxpcmin_release(struct inode *inode, struct file *file)
159{
160 struct auxpcm *auxpcmin = file->private_data;
161 mutex_lock(&auxpcmin->lock);
162 if (auxpcmin->ac)
163 q6audio_auxpcm_close(auxpcmin->ac);
164 auxpcmin->ac = NULL;
165 auxpcmin->opened = 0;
166 mutex_unlock(&auxpcmin->lock);
167 pr_info("[%s:%s] release\n", __MM_FILE__, __func__);
168 return 0;
169}
170
171static const struct file_operations auxpcmin_fops = {
172 .owner = THIS_MODULE,
173 .open = auxpcmin_open,
174 .release = auxpcmin_release,
175 .unlocked_ioctl = auxpcmin_ioctl,
176};
177
178struct miscdevice auxpcmin_misc = {
179 .minor = MISC_DYNAMIC_MINOR,
180 .name = "msm_aux_pcm_lb_in",
181 .fops = &auxpcmin_fops,
182};
183
184static int __init auxpcmin_init(void)
185{
186 mutex_init(&the_auxpcmin.lock);
187 return misc_register(&auxpcmin_misc);
188}
189
190device_initcall(auxpcmin_init);