blob: 231a28cdde84485fc6e31413460a2c3578374c54 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* arch/arm/mach-msm/qdsp5/audmgr.c
2 *
3 * interface to "audmgr" service on the baseband cpu
4 *
5 * Copyright (C) 2008 Google, Inc.
6 * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
7 *
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 */
18
19#include <linux/module.h>
20#include <linux/fs.h>
21#include <linux/uaccess.h>
22#include <linux/kthread.h>
23#include <linux/wait.h>
24#include <linux/slab.h>
25
26#include <asm/atomic.h>
27#include <mach/msm_rpcrouter.h>
28
29#include "audmgr.h"
30#include <mach/debug_mm.h>
31
32#define STATE_CLOSED 0
33#define STATE_DISABLED 1
34#define STATE_ENABLING 2
35#define STATE_ENABLED 3
36#define STATE_DISABLING 4
37#define STATE_ERROR 5
38
39/* store information used across complete audmgr sessions */
40struct audmgr_global {
41 struct mutex *lock;
42 struct msm_rpc_endpoint *ept;
43 struct task_struct *task;
44 uint32_t rpc_version;
45};
46static DEFINE_MUTEX(audmgr_lock);
47
48static struct audmgr_global the_audmgr_state = {
49 .lock = &audmgr_lock,
50};
51
52static void rpc_ack(struct msm_rpc_endpoint *ept, uint32_t xid)
53{
54 uint32_t rep[6];
55
56 rep[0] = cpu_to_be32(xid);
57 rep[1] = cpu_to_be32(1);
58 rep[2] = cpu_to_be32(RPCMSG_REPLYSTAT_ACCEPTED);
59 rep[3] = cpu_to_be32(RPC_ACCEPTSTAT_SUCCESS);
60 rep[4] = 0;
61 rep[5] = 0;
62
63 msm_rpc_write(ept, rep, sizeof(rep));
64}
65
66static void process_audmgr_callback(struct audmgr_global *amg,
67 struct rpc_audmgr_cb_func_ptr *args,
68 int len)
69{
70 struct audmgr *am;
71
72 /* Allow only if complete arguments recevied */
73 if (len < (sizeof(struct rpc_audmgr_cb_func_ptr)))
74 return;
75
76 /* Allow only if valid argument */
77 if (be32_to_cpu(args->set_to_one) != 1)
78 return;
79
80 am = (struct audmgr *) be32_to_cpu(args->client_data);
81
82 if (!am)
83 return;
84
85 switch (be32_to_cpu(args->status)) {
86 case RPC_AUDMGR_STATUS_READY:
87 am->handle = be32_to_cpu(args->u.handle);
88 MM_INFO("rpc READY handle=0x%08x\n", am->handle);
89 break;
90 case RPC_AUDMGR_STATUS_CODEC_CONFIG: {
91 uint32_t volume;
92 volume = be32_to_cpu(args->u.volume);
93 MM_INFO("rpc CODEC_CONFIG volume=0x%08x\n", volume);
94 am->state = STATE_ENABLED;
95 wake_up(&am->wait);
96 break;
97 }
98 case RPC_AUDMGR_STATUS_PENDING:
99 MM_ERR("PENDING?\n");
100 break;
101 case RPC_AUDMGR_STATUS_SUSPEND:
102 MM_ERR("SUSPEND?\n");
103 break;
104 case RPC_AUDMGR_STATUS_FAILURE:
105 MM_ERR("FAILURE\n");
106 break;
107 case RPC_AUDMGR_STATUS_VOLUME_CHANGE:
108 MM_ERR("VOLUME_CHANGE?\n");
109 break;
110 case RPC_AUDMGR_STATUS_DISABLED:
111 MM_ERR("DISABLED\n");
112 am->state = STATE_DISABLED;
113 wake_up(&am->wait);
114 break;
115 case RPC_AUDMGR_STATUS_ERROR:
116 MM_ERR("ERROR?\n");
117 am->state = STATE_ERROR;
118 wake_up(&am->wait);
119 break;
120 default:
121 break;
122 }
123}
124
125static void process_rpc_request(uint32_t proc, uint32_t xid,
126 void *data, int len, void *private)
127{
128 struct audmgr_global *amg = private;
129
130 if (proc == AUDMGR_CB_FUNC_PTR)
131 process_audmgr_callback(amg, data, len);
132 else
133 MM_ERR("unknown rpc proc %d\n", proc);
134 rpc_ack(amg->ept, xid);
135}
136
137#define RPC_TYPE_REQUEST 0
138#define RPC_TYPE_REPLY 1
139
140#define RPC_VERSION 2
141
142#define RPC_COMMON_HDR_SZ (sizeof(uint32_t) * 2)
143#define RPC_REQUEST_HDR_SZ (sizeof(struct rpc_request_hdr))
144#define RPC_REPLY_HDR_SZ (sizeof(uint32_t) * 3)
145#define RPC_REPLY_SZ (sizeof(uint32_t) * 6)
146
147static int audmgr_rpc_thread(void *data)
148{
149 struct audmgr_global *amg = data;
150 struct rpc_request_hdr *hdr = NULL;
151 uint32_t type;
152 int len;
153
154 MM_INFO("start\n");
155
156 while (!kthread_should_stop()) {
157 if (hdr) {
158 kfree(hdr);
159 hdr = NULL;
160 }
161 len = msm_rpc_read(amg->ept, (void **) &hdr, -1, -1);
162 if (len < 0) {
163 MM_ERR("rpc read failed (%d)\n", len);
164 break;
165 }
166 if (len < RPC_COMMON_HDR_SZ)
167 continue;
168
169 type = be32_to_cpu(hdr->type);
170 if (type == RPC_TYPE_REPLY) {
171 struct rpc_reply_hdr *rep = (void *) hdr;
172 uint32_t status;
173 if (len < RPC_REPLY_HDR_SZ)
174 continue;
175 status = be32_to_cpu(rep->reply_stat);
176 if (status == RPCMSG_REPLYSTAT_ACCEPTED) {
177 status = be32_to_cpu(rep->data.acc_hdr.accept_stat);
178 MM_INFO("rpc_reply status %d\n", status);
179 } else {
180 MM_INFO("rpc_reply denied!\n");
181 }
182 /* process reply */
183 continue;
184 }
185
186 if (len < RPC_REQUEST_HDR_SZ)
187 continue;
188
189 process_rpc_request(be32_to_cpu(hdr->procedure),
190 be32_to_cpu(hdr->xid),
191 (void *) (hdr + 1),
192 len - sizeof(*hdr),
193 data);
194 }
195 MM_INFO("exit\n");
196 if (hdr) {
197 kfree(hdr);
198 hdr = NULL;
199 }
200 amg->task = NULL;
201 return 0;
202}
203
204struct audmgr_enable_msg {
205 struct rpc_request_hdr hdr;
206 struct rpc_audmgr_enable_client_args args;
207};
208
209struct audmgr_disable_msg {
210 struct rpc_request_hdr hdr;
211 uint32_t handle;
212};
213
214int audmgr_open(struct audmgr *am)
215{
216 struct audmgr_global *amg = &the_audmgr_state;
217 int rc;
218
219 if (am->state != STATE_CLOSED)
220 return 0;
221
222 mutex_lock(amg->lock);
223
224 /* connect to audmgr end point and polling thread only once */
225 if (amg->ept == NULL) {
226 amg->ept = msm_rpc_connect_compatible(AUDMGR_PROG,
227 AUDMGR_VERS_COMP_VER3,
228 MSM_RPC_UNINTERRUPTIBLE);
229 if (IS_ERR(amg->ept)) {
230 MM_ERR("connect failed with current VERS \
231 = %x, trying again with another API\n",
232 AUDMGR_VERS_COMP_VER3);
233 amg->ept = msm_rpc_connect_compatible(AUDMGR_PROG,
234 AUDMGR_VERS_COMP_VER2,
235 MSM_RPC_UNINTERRUPTIBLE);
236 if (IS_ERR(amg->ept)) {
237 MM_ERR("connect failed with current VERS \
238 = %x, trying again with another API\n",
239 AUDMGR_VERS_COMP_VER2);
240 amg->ept = msm_rpc_connect_compatible(
241 AUDMGR_PROG,
242 AUDMGR_VERS_COMP,
243 MSM_RPC_UNINTERRUPTIBLE);
244 if (IS_ERR(amg->ept)) {
245 MM_ERR("connect failed with current \
246 VERS=%x, trying again with another \
247 API\n", AUDMGR_VERS_COMP);
248 amg->ept = msm_rpc_connect(AUDMGR_PROG,
249 AUDMGR_VERS,
250 MSM_RPC_UNINTERRUPTIBLE);
251 amg->rpc_version = AUDMGR_VERS;
252 } else
253 amg->rpc_version = AUDMGR_VERS_COMP;
254 } else
255 amg->rpc_version = AUDMGR_VERS_COMP_VER2;
256 } else
257 amg->rpc_version = AUDMGR_VERS_COMP_VER3;
258
259 if (IS_ERR(amg->ept)) {
260 rc = PTR_ERR(amg->ept);
261 amg->ept = NULL;
262 MM_ERR("failed to connect to audmgr svc\n");
263 goto done;
264 }
265
266 amg->task = kthread_run(audmgr_rpc_thread, amg, "audmgr_rpc");
267 if (IS_ERR(amg->task)) {
268 rc = PTR_ERR(amg->task);
269 amg->task = NULL;
270 msm_rpc_close(amg->ept);
271 amg->ept = NULL;
272 goto done;
273 }
274 }
275
276 /* Initialize session parameters */
277 init_waitqueue_head(&am->wait);
278 am->state = STATE_DISABLED;
279 rc = 0;
280done:
281 mutex_unlock(amg->lock);
282 return rc;
283}
284EXPORT_SYMBOL(audmgr_open);
285
286int audmgr_close(struct audmgr *am)
287{
288 return -EBUSY;
289}
290EXPORT_SYMBOL(audmgr_close);
291
292int audmgr_enable(struct audmgr *am, struct audmgr_config *cfg)
293{
294 struct audmgr_global *amg = &the_audmgr_state;
295 struct audmgr_enable_msg msg;
296 int rc;
297
298 if (am->state == STATE_ENABLED)
299 return 0;
300
301 if (am->state == STATE_DISABLING)
302 MM_ERR("state is DISABLING in enable?\n");
303 am->state = STATE_ENABLING;
304
305 MM_INFO("session 0x%08x\n", (int) am);
306 msg.args.set_to_one = cpu_to_be32(1);
307 msg.args.tx_sample_rate = cpu_to_be32(cfg->tx_rate);
308 msg.args.rx_sample_rate = cpu_to_be32(cfg->rx_rate);
309 msg.args.def_method = cpu_to_be32(cfg->def_method);
310 msg.args.codec_type = cpu_to_be32(cfg->codec);
311 msg.args.snd_method = cpu_to_be32(cfg->snd_method);
312 msg.args.cb_func = cpu_to_be32(0x11111111);
313 msg.args.client_data = cpu_to_be32((int)am);
314
315 msm_rpc_setup_req(&msg.hdr, AUDMGR_PROG, amg->rpc_version,
316 AUDMGR_ENABLE_CLIENT);
317
318 rc = msm_rpc_write(amg->ept, &msg, sizeof(msg));
319 if (rc < 0)
320 return rc;
321
322 rc = wait_event_timeout(am->wait, am->state != STATE_ENABLING, 15 * HZ);
323 if (rc == 0) {
324 MM_ERR("ARM9 did not reply to RPC am->state = %d\n", am->state);
325 }
326 if (am->state == STATE_ENABLED)
327 return 0;
328
329 MM_ERR("unexpected state %d while enabling?!\n", am->state);
330 return -ENODEV;
331}
332EXPORT_SYMBOL(audmgr_enable);
333
334int audmgr_disable(struct audmgr *am)
335{
336 struct audmgr_global *amg = &the_audmgr_state;
337 struct audmgr_disable_msg msg;
338 int rc;
339
340 if (am->state == STATE_DISABLED)
341 return 0;
342
343 MM_INFO("session 0x%08x\n", (int) am);
344 msg.handle = cpu_to_be32(am->handle);
345 msm_rpc_setup_req(&msg.hdr, AUDMGR_PROG, amg->rpc_version,
346 AUDMGR_DISABLE_CLIENT);
347
348 am->state = STATE_DISABLING;
349
350 rc = msm_rpc_write(amg->ept, &msg, sizeof(msg));
351 if (rc < 0)
352 return rc;
353
354 rc = wait_event_timeout(am->wait, am->state != STATE_DISABLING, 15 * HZ);
355 if (rc == 0) {
356 MM_ERR("ARM9 did not reply to RPC am->state = %d\n", am->state);
357 }
358
359 if (am->state == STATE_DISABLED)
360 return 0;
361
362 MM_ERR("unexpected state %d while disabling?!\n", am->state);
363 return -ENODEV;
364}
365EXPORT_SYMBOL(audmgr_disable);