Merge branch 'bkl/procfs' of git://git.kernel.org/pub/scm/linux/kernel/git/frederic...
[pandora-kernel.git] / drivers / staging / dream / qdsp5 / audmgr.c
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>
21 #include <linux/slab.h>
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
37 static 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
51 static 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
104 static 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
135 static 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
193 struct audmgr_enable_msg {
194         struct rpc_request_hdr hdr;
195         struct rpc_audmgr_enable_client_args args;
196 };
197
198 struct audmgr_disable_msg {
199         struct rpc_request_hdr hdr;
200         uint32_t handle;
201 };
202
203 int 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 }
235 EXPORT_SYMBOL(audmgr_open);
236
237 int audmgr_close(struct audmgr *am)
238 {
239         return -EBUSY;
240 }
241 EXPORT_SYMBOL(audmgr_close);
242
243 int 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 }
282 EXPORT_SYMBOL(audmgr_enable);
283
284 int 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 }
314 EXPORT_SYMBOL(audmgr_disable);