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