]> bbs.cooldavid.org Git - net-next-2.6.git/blame - drivers/staging/dream/qdsp5/audmgr.c
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel...
[net-next-2.6.git] / drivers / staging / dream / qdsp5 / audmgr.c
CommitLineData
caff4cae
IM
1/* 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 *
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/module.h>
19#include <linux/fs.h>
20#include <linux/uaccess.h>
5a0e3ad6 21#include <linux/slab.h>
caff4cae
IM
22#include <linux/kthread.h>
23#include <linux/wait.h>
24
25#include <asm/atomic.h>
26#include <mach/msm_rpcrouter.h>
27
28#include "audmgr.h"
29
30#define STATE_CLOSED 0
31#define STATE_DISABLED 1
32#define STATE_ENABLING 2
33#define STATE_ENABLED 3
34#define STATE_DISABLING 4
35#define STATE_ERROR 5
36
37static void rpc_ack(struct msm_rpc_endpoint *ept, uint32_t xid)
38{
39 uint32_t rep[6];
40
41 rep[0] = cpu_to_be32(xid);
42 rep[1] = cpu_to_be32(1);
43 rep[2] = cpu_to_be32(RPCMSG_REPLYSTAT_ACCEPTED);
44 rep[3] = cpu_to_be32(RPC_ACCEPTSTAT_SUCCESS);
45 rep[4] = 0;
46 rep[5] = 0;
47
48 msm_rpc_write(ept, rep, sizeof(rep));
49}
50
51static void process_audmgr_callback(struct audmgr *am,
52 struct rpc_audmgr_cb_func_ptr *args,
53 int len)
54{
55 if (len < (sizeof(uint32_t) * 3))
56 return;
57 if (be32_to_cpu(args->set_to_one) != 1)
58 return;
59
60 switch (be32_to_cpu(args->status)) {
61 case RPC_AUDMGR_STATUS_READY:
62 if (len < sizeof(uint32_t) * 4)
63 break;
64 am->handle = be32_to_cpu(args->u.handle);
65 pr_info("audmgr: rpc READY handle=0x%08x\n", am->handle);
66 break;
67 case RPC_AUDMGR_STATUS_CODEC_CONFIG: {
68 uint32_t volume;
69 if (len < sizeof(uint32_t) * 4)
70 break;
71 volume = be32_to_cpu(args->u.volume);
72 pr_info("audmgr: rpc CODEC_CONFIG volume=0x%08x\n", volume);
73 am->state = STATE_ENABLED;
74 wake_up(&am->wait);
75 break;
76 }
77 case RPC_AUDMGR_STATUS_PENDING:
78 pr_err("audmgr: PENDING?\n");
79 break;
80 case RPC_AUDMGR_STATUS_SUSPEND:
81 pr_err("audmgr: SUSPEND?\n");
82 break;
83 case RPC_AUDMGR_STATUS_FAILURE:
84 pr_err("audmgr: FAILURE\n");
85 break;
86 case RPC_AUDMGR_STATUS_VOLUME_CHANGE:
87 pr_err("audmgr: VOLUME_CHANGE?\n");
88 break;
89 case RPC_AUDMGR_STATUS_DISABLED:
90 pr_err("audmgr: DISABLED\n");
91 am->state = STATE_DISABLED;
92 wake_up(&am->wait);
93 break;
94 case RPC_AUDMGR_STATUS_ERROR:
95 pr_err("audmgr: ERROR?\n");
96 am->state = STATE_ERROR;
97 wake_up(&am->wait);
98 break;
99 default:
100 break;
101 }
102}
103
104static void process_rpc_request(uint32_t proc, uint32_t xid,
105 void *data, int len, void *private)
106{
107 struct audmgr *am = private;
108 uint32_t *x = data;
109
110 if (0) {
111 int n = len / 4;
112 pr_info("rpc_call proc %d:", proc);
113 while (n--)
114 printk(" %08x", be32_to_cpu(*x++));
115 printk("\n");
116 }
117
118 if (proc == AUDMGR_CB_FUNC_PTR)
119 process_audmgr_callback(am, data, len);
120 else
121 pr_err("audmgr: unknown rpc proc %d\n", proc);
122 rpc_ack(am->ept, xid);
123}
124
125#define RPC_TYPE_REQUEST 0
126#define RPC_TYPE_REPLY 1
127
128#define RPC_VERSION 2
129
130#define RPC_COMMON_HDR_SZ (sizeof(uint32_t) * 2)
131#define RPC_REQUEST_HDR_SZ (sizeof(struct rpc_request_hdr))
132#define RPC_REPLY_HDR_SZ (sizeof(uint32_t) * 3)
133#define RPC_REPLY_SZ (sizeof(uint32_t) * 6)
134
135static int audmgr_rpc_thread(void *data)
136{
137 struct audmgr *am = data;
138 struct rpc_request_hdr *hdr = NULL;
139 uint32_t type;
140 int len;
141
142 pr_info("audmgr_rpc_thread() start\n");
143
144 while (!kthread_should_stop()) {
145 if (hdr) {
146 kfree(hdr);
147 hdr = NULL;
148 }
149 len = msm_rpc_read(am->ept, (void **) &hdr, -1, -1);
150 if (len < 0) {
151 pr_err("audmgr: rpc read failed (%d)\n", len);
152 break;
153 }
154 if (len < RPC_COMMON_HDR_SZ)
155 continue;
156
157 type = be32_to_cpu(hdr->type);
158 if (type == RPC_TYPE_REPLY) {
159 struct rpc_reply_hdr *rep = (void *) hdr;
160 uint32_t status;
161 if (len < RPC_REPLY_HDR_SZ)
162 continue;
163 status = be32_to_cpu(rep->reply_stat);
164 if (status == RPCMSG_REPLYSTAT_ACCEPTED) {
165 status = be32_to_cpu(rep->data.acc_hdr.accept_stat);
166 pr_info("audmgr: rpc_reply status %d\n", status);
167 } else {
168 pr_info("audmgr: rpc_reply denied!\n");
169 }
170 /* process reply */
171 continue;
172 }
173
174 if (len < RPC_REQUEST_HDR_SZ)
175 continue;
176
177 process_rpc_request(be32_to_cpu(hdr->procedure),
178 be32_to_cpu(hdr->xid),
179 (void *) (hdr + 1),
180 len - sizeof(*hdr),
181 data);
182 }
183 pr_info("audmgr_rpc_thread() exit\n");
184 if (hdr) {
185 kfree(hdr);
186 hdr = NULL;
187 }
188 am->task = NULL;
189 wake_up(&am->wait);
190 return 0;
191}
192
193struct audmgr_enable_msg {
194 struct rpc_request_hdr hdr;
195 struct rpc_audmgr_enable_client_args args;
196};
197
198struct audmgr_disable_msg {
199 struct rpc_request_hdr hdr;
200 uint32_t handle;
201};
202
203int audmgr_open(struct audmgr *am)
204{
205 int rc;
206
207 if (am->state != STATE_CLOSED)
208 return 0;
209
210 am->ept = msm_rpc_connect(AUDMGR_PROG,
211 AUDMGR_VERS,
212 MSM_RPC_UNINTERRUPTIBLE);
213
214 init_waitqueue_head(&am->wait);
215
216 if (IS_ERR(am->ept)) {
217 rc = PTR_ERR(am->ept);
218 am->ept = NULL;
219 pr_err("audmgr: failed to connect to audmgr svc\n");
220 return rc;
221 }
222
223 am->task = kthread_run(audmgr_rpc_thread, am, "audmgr_rpc");
224 if (IS_ERR(am->task)) {
225 rc = PTR_ERR(am->task);
226 am->task = NULL;
227 msm_rpc_close(am->ept);
228 am->ept = NULL;
229 return rc;
230 }
231
232 am->state = STATE_DISABLED;
233 return 0;
234}
235EXPORT_SYMBOL(audmgr_open);
236
237int audmgr_close(struct audmgr *am)
238{
239 return -EBUSY;
240}
241EXPORT_SYMBOL(audmgr_close);
242
243int audmgr_enable(struct audmgr *am, struct audmgr_config *cfg)
244{
245 struct audmgr_enable_msg msg;
246 int rc;
247
248 if (am->state == STATE_ENABLED)
249 return 0;
250
251 if (am->state == STATE_DISABLING)
252 pr_err("audmgr: state is DISABLING in enable?\n");
253 am->state = STATE_ENABLING;
254
255 msg.args.set_to_one = cpu_to_be32(1);
256 msg.args.tx_sample_rate = cpu_to_be32(cfg->tx_rate);
257 msg.args.rx_sample_rate = cpu_to_be32(cfg->rx_rate);
258 msg.args.def_method = cpu_to_be32(cfg->def_method);
259 msg.args.codec_type = cpu_to_be32(cfg->codec);
260 msg.args.snd_method = cpu_to_be32(cfg->snd_method);
261 msg.args.cb_func = cpu_to_be32(0x11111111);
262 msg.args.client_data = cpu_to_be32(0x11223344);
263
264 msm_rpc_setup_req(&msg.hdr, AUDMGR_PROG, msm_rpc_get_vers(am->ept),
265 AUDMGR_ENABLE_CLIENT);
266
267 rc = msm_rpc_write(am->ept, &msg, sizeof(msg));
268 if (rc < 0)
269 return rc;
270
271 rc = wait_event_timeout(am->wait, am->state != STATE_ENABLING, 15 * HZ);
272 if (rc == 0) {
273 pr_err("audmgr_enable: ARM9 did not reply to RPC am->state = %d\n", am->state);
274 BUG();
275 }
276 if (am->state == STATE_ENABLED)
277 return 0;
278
279 pr_err("audmgr: unexpected state %d while enabling?!\n", am->state);
280 return -ENODEV;
281}
282EXPORT_SYMBOL(audmgr_enable);
283
284int audmgr_disable(struct audmgr *am)
285{
286 struct audmgr_disable_msg msg;
287 int rc;
288
289 if (am->state == STATE_DISABLED)
290 return 0;
291
292 msm_rpc_setup_req(&msg.hdr, AUDMGR_PROG, msm_rpc_get_vers(am->ept),
293 AUDMGR_DISABLE_CLIENT);
294 msg.handle = cpu_to_be32(am->handle);
295
296 am->state = STATE_DISABLING;
297
298 rc = msm_rpc_write(am->ept, &msg, sizeof(msg));
299 if (rc < 0)
300 return rc;
301
302 rc = wait_event_timeout(am->wait, am->state != STATE_DISABLING, 15 * HZ);
303 if (rc == 0) {
304 pr_err("audmgr_disable: ARM9 did not reply to RPC am->state = %d\n", am->state);
305 BUG();
306 }
307
308 if (am->state == STATE_DISABLED)
309 return 0;
310
311 pr_err("audmgr: unexpected state %d while disabling?!\n", am->state);
312 return -ENODEV;
313}
314EXPORT_SYMBOL(audmgr_disable);