2597bbbc6f5e9da65fd14fa579320cc94b6a8566
[linux-flexiantxendom0-3.2.10.git] / drivers / staging / dream / smd / smd_rpcrouter_servers.c
1 /* arch/arm/mach-msm/rpc_servers.c
2  *
3  * Copyright (C) 2007 Google, Inc.
4  * Author: Iliyan Malchev <ibm@android.com>
5  *
6  * This software is licensed under the terms of the GNU General Public
7  * License version 2, as published by the Free Software Foundation, and
8  * may be copied, distributed, and modified under those terms.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  */
16
17 #include <linux/module.h>
18 #include <linux/kernel.h>
19 #include <linux/string.h>
20 #include <linux/errno.h>
21 #include <linux/cdev.h>
22 #include <linux/init.h>
23 #include <linux/device.h>
24 #include <linux/types.h>
25 #include <linux/fs.h>
26 #include <linux/kthread.h>
27 #include <linux/delay.h>
28 #include <linux/platform_device.h>
29 #include <linux/wakelock.h>
30
31 #include <linux/msm_rpcrouter.h>
32 #include <linux/uaccess.h>
33
34 #include <mach/msm_rpcrouter.h>
35 #include "smd_rpcrouter.h"
36
37 static struct msm_rpc_endpoint *endpoint;
38
39 #define FLAG_REGISTERED 0x0001
40
41 static LIST_HEAD(rpc_server_list);
42 static DEFINE_MUTEX(rpc_server_list_lock);
43 static int rpc_servers_active;
44 static struct wake_lock rpc_servers_wake_lock;
45
46 static void rpc_server_register(struct msm_rpc_server *server)
47 {
48         int rc;
49         rc = msm_rpc_register_server(endpoint, server->prog, server->vers);
50         if (rc < 0)
51                 printk(KERN_ERR "[rpcserver] error registering %p @ %08x:%d\n",
52                        server, server->prog, server->vers);
53 }
54
55 static struct msm_rpc_server *rpc_server_find(uint32_t prog, uint32_t vers)
56 {
57         struct msm_rpc_server *server;
58
59         mutex_lock(&rpc_server_list_lock);
60         list_for_each_entry(server, &rpc_server_list, list) {
61                 if ((server->prog == prog) &&
62 #if CONFIG_MSM_AMSS_VERSION >= 6350
63                     msm_rpc_is_compatible_version(server->vers, vers)) {
64 #else
65                     server->vers == vers) {
66 #endif
67                         mutex_unlock(&rpc_server_list_lock);
68                         return server;
69                 }
70         }
71         mutex_unlock(&rpc_server_list_lock);
72         return NULL;
73 }
74
75 static void rpc_server_register_all(void)
76 {
77         struct msm_rpc_server *server;
78
79         mutex_lock(&rpc_server_list_lock);
80         list_for_each_entry(server, &rpc_server_list, list) {
81                 if (!(server->flags & FLAG_REGISTERED)) {
82                         rpc_server_register(server);
83                         server->flags |= FLAG_REGISTERED;
84                 }
85         }
86         mutex_unlock(&rpc_server_list_lock);
87 }
88
89 int msm_rpc_create_server(struct msm_rpc_server *server)
90 {
91         /* make sure we're in a sane state first */
92         server->flags = 0;
93         INIT_LIST_HEAD(&server->list);
94
95         mutex_lock(&rpc_server_list_lock);
96         list_add(&server->list, &rpc_server_list);
97         if (rpc_servers_active) {
98                 rpc_server_register(server);
99                 server->flags |= FLAG_REGISTERED;
100         }
101         mutex_unlock(&rpc_server_list_lock);
102
103         return 0;
104 }
105
106 static int rpc_send_accepted_void_reply(struct msm_rpc_endpoint *client,
107                                         uint32_t xid, uint32_t accept_status)
108 {
109         int rc = 0;
110         uint8_t reply_buf[sizeof(struct rpc_reply_hdr)];
111         struct rpc_reply_hdr *reply = (struct rpc_reply_hdr *)reply_buf;
112
113         reply->xid = cpu_to_be32(xid);
114         reply->type = cpu_to_be32(1); /* reply */
115         reply->reply_stat = cpu_to_be32(RPCMSG_REPLYSTAT_ACCEPTED);
116
117         reply->data.acc_hdr.accept_stat = cpu_to_be32(accept_status);
118         reply->data.acc_hdr.verf_flavor = 0;
119         reply->data.acc_hdr.verf_length = 0;
120
121         rc = msm_rpc_write(client, reply_buf, sizeof(reply_buf));
122         if (rc < 0)
123                 printk(KERN_ERR
124                        "%s: could not write response: %d\n",
125                        __FUNCTION__, rc);
126
127         return rc;
128 }
129
130 static int rpc_servers_thread(void *data)
131 {
132         void *buffer;
133         struct rpc_request_hdr *req;
134         struct msm_rpc_server *server;
135         int rc;
136
137         for (;;) {
138                 wake_unlock(&rpc_servers_wake_lock);
139                 rc = wait_event_interruptible(endpoint->wait_q,
140                                                 !list_empty(&endpoint->read_q));
141                 wake_lock(&rpc_servers_wake_lock);
142                 rc = msm_rpc_read(endpoint, &buffer, -1, -1);
143                 if (rc < 0) {
144                         printk(KERN_ERR "%s: could not read: %d\n",
145                                __FUNCTION__, rc);
146                         break;
147                 }
148                 req = (struct rpc_request_hdr *)buffer;
149
150                 req->type = be32_to_cpu(req->type);
151                 req->xid = be32_to_cpu(req->xid);
152                 req->rpc_vers = be32_to_cpu(req->rpc_vers);
153                 req->prog = be32_to_cpu(req->prog);
154                 req->vers = be32_to_cpu(req->vers);
155                 req->procedure = be32_to_cpu(req->procedure);
156
157                 server = rpc_server_find(req->prog, req->vers);
158
159                 if (req->rpc_vers != 2)
160                         continue;
161                 if (req->type != 0)
162                         continue;
163                 if (!server) {
164                         rpc_send_accepted_void_reply(
165                                 endpoint, req->xid,
166                                 RPC_ACCEPTSTAT_PROG_UNAVAIL);
167                         continue;
168                 }
169
170                 rc = server->rpc_call(server, req, rc);
171
172                 switch (rc) {
173                 case 0:
174                         rpc_send_accepted_void_reply(
175                                 endpoint, req->xid,
176                                 RPC_ACCEPTSTAT_SUCCESS);
177                         break;
178                 default:
179                         rpc_send_accepted_void_reply(
180                                 endpoint, req->xid,
181                                 RPC_ACCEPTSTAT_PROG_UNAVAIL);
182                         break;
183                 }
184
185                 kfree(buffer);
186         }
187
188         do_exit(0);
189 }
190
191 static int rpcservers_probe(struct platform_device *pdev)
192 {
193         struct task_struct *server_thread;
194
195         endpoint = msm_rpc_open();
196         if (IS_ERR(endpoint))
197                 return PTR_ERR(endpoint);
198
199         /* we're online -- register any servers installed beforehand */
200         rpc_servers_active = 1;
201         rpc_server_register_all();
202
203         /* start the kernel thread */
204         server_thread = kthread_run(rpc_servers_thread, NULL, "krpcserversd");
205         if (IS_ERR(server_thread))
206                 return PTR_ERR(server_thread);
207
208         return 0;
209 }
210
211 static struct platform_driver rpcservers_driver = {
212         .probe  = rpcservers_probe,
213         .driver = {
214                 .name   = "oncrpc_router",
215                 .owner  = THIS_MODULE,
216         },
217 };
218
219 static int __init rpc_servers_init(void)
220 {
221         wake_lock_init(&rpc_servers_wake_lock, WAKE_LOCK_SUSPEND, "rpc_server");
222         return platform_driver_register(&rpcservers_driver);
223 }
224
225 module_init(rpc_servers_init);
226
227 MODULE_DESCRIPTION("MSM RPC Servers");
228 MODULE_AUTHOR("Iliyan Malchev <ibm@android.com>");
229 MODULE_LICENSE("GPL");