blob: f2b93cefc334e15244d030cd089fc45448bb81bb [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14/*
15 * OEM RAPI CLIENT Driver source file
16 */
17
18#include <linux/slab.h>
19#include <linux/kernel.h>
20#include <linux/err.h>
21#include <linux/fs.h>
22#include <linux/sched.h>
23#include <linux/debugfs.h>
24#include <linux/uaccess.h>
25#include <linux/delay.h>
26#include <mach/msm_rpcrouter.h>
27#include <mach/oem_rapi_client.h>
28
29#define OEM_RAPI_PROG 0x3000006B
30#define OEM_RAPI_VERS 0x00010001
31
32#define OEM_RAPI_NULL_PROC 0
33#define OEM_RAPI_RPC_GLUE_CODE_INFO_REMOTE_PROC 1
34#define OEM_RAPI_STREAMING_FUNCTION_PROC 2
35
36#define OEM_RAPI_CLIENT_MAX_OUT_BUFF_SIZE 128
37
38static struct msm_rpc_client *rpc_client;
39static uint32_t open_count;
40static DEFINE_MUTEX(oem_rapi_client_lock);
41
42/* TODO: check where to allocate memory for return */
43static int oem_rapi_client_cb(struct msm_rpc_client *client,
44 struct rpc_request_hdr *req,
45 struct msm_rpc_xdr *xdr)
46{
47 uint32_t cb_id, accept_status;
48 int rc;
49 void *cb_func;
50 uint32_t temp;
51
52 struct oem_rapi_client_streaming_func_cb_arg arg;
53 struct oem_rapi_client_streaming_func_cb_ret ret;
54
55 arg.input = NULL;
56 ret.out_len = NULL;
57 ret.output = NULL;
58
59 xdr_recv_uint32(xdr, &cb_id); /* cb_id */
60 xdr_recv_uint32(xdr, &arg.event); /* enum */
61 xdr_recv_uint32(xdr, (uint32_t *)(&arg.handle)); /* handle */
62 xdr_recv_uint32(xdr, &arg.in_len); /* in_len */
63 xdr_recv_bytes(xdr, (void **)&arg.input, &temp); /* input */
64 xdr_recv_uint32(xdr, &arg.out_len_valid); /* out_len */
65 if (arg.out_len_valid) {
66 ret.out_len = kmalloc(sizeof(*ret.out_len), GFP_KERNEL);
67 if (!ret.out_len) {
68 accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR;
69 goto oem_rapi_send_ack;
70 }
71 }
72
73 xdr_recv_uint32(xdr, &arg.output_valid); /* out */
74 if (arg.output_valid) {
75 xdr_recv_uint32(xdr, &arg.output_size); /* ouput_size */
76
77 ret.output = kmalloc(arg.output_size, GFP_KERNEL);
78 if (!ret.output) {
79 accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR;
80 goto oem_rapi_send_ack;
81 }
82 }
83
84 cb_func = msm_rpc_get_cb_func(client, cb_id);
85 if (cb_func) {
86 rc = ((int (*)(struct oem_rapi_client_streaming_func_cb_arg *,
87 struct oem_rapi_client_streaming_func_cb_ret *))
88 cb_func)(&arg, &ret);
89 if (rc)
90 accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR;
91 else
92 accept_status = RPC_ACCEPTSTAT_SUCCESS;
93 } else
94 accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR;
95
96 oem_rapi_send_ack:
97 xdr_start_accepted_reply(xdr, accept_status);
98
99 if (accept_status == RPC_ACCEPTSTAT_SUCCESS) {
100 uint32_t temp = sizeof(uint32_t);
101 xdr_send_pointer(xdr, (void **)&(ret.out_len), temp,
102 xdr_send_uint32);
103
104 /* output */
105 if (ret.output && ret.out_len)
106 xdr_send_bytes(xdr, (const void **)&ret.output,
107 ret.out_len);
108 else {
109 temp = 0;
110 xdr_send_uint32(xdr, &temp);
111 }
112 }
113 rc = xdr_send_msg(xdr);
114 if (rc)
115 pr_err("%s: sending reply failed: %d\n", __func__, rc);
116
117 kfree(arg.input);
118 kfree(ret.out_len);
119 kfree(ret.output);
120
121 return 0;
122}
123
124static int oem_rapi_client_streaming_function_arg(struct msm_rpc_client *client,
125 struct msm_rpc_xdr *xdr,
126 void *data)
127{
128 int cb_id;
129 struct oem_rapi_client_streaming_func_arg *arg = data;
130
131 cb_id = msm_rpc_add_cb_func(client, (void *)arg->cb_func);
132 if ((cb_id < 0) && (cb_id != MSM_RPC_CLIENT_NULL_CB_ID))
133 return cb_id;
134
135 xdr_send_uint32(xdr, &arg->event); /* enum */
136 xdr_send_uint32(xdr, &cb_id); /* cb_id */
137 xdr_send_uint32(xdr, (uint32_t *)(&arg->handle)); /* handle */
138 xdr_send_uint32(xdr, &arg->in_len); /* in_len */
139 xdr_send_bytes(xdr, (const void **)&arg->input,
140 &arg->in_len); /* input */
141 xdr_send_uint32(xdr, &arg->out_len_valid); /* out_len */
142 xdr_send_uint32(xdr, &arg->output_valid); /* output */
143
144 /* output_size */
145 if (arg->output_valid)
146 xdr_send_uint32(xdr, &arg->output_size);
147
148 return 0;
149}
150
151static int oem_rapi_client_streaming_function_ret(struct msm_rpc_client *client,
152 struct msm_rpc_xdr *xdr,
153 void *data)
154{
155 struct oem_rapi_client_streaming_func_ret *ret = data;
156 uint32_t temp;
157
158 /* out_len */
159 xdr_recv_pointer(xdr, (void **)&(ret->out_len), sizeof(uint32_t),
160 xdr_recv_uint32);
161
162 /* output */
163 if (ret->out_len && *ret->out_len)
164 xdr_recv_bytes(xdr, (void **)&ret->output, &temp);
165
166 return 0;
167}
168
169int oem_rapi_client_streaming_function(
170 struct msm_rpc_client *client,
171 struct oem_rapi_client_streaming_func_arg *arg,
172 struct oem_rapi_client_streaming_func_ret *ret)
173{
174 return msm_rpc_client_req2(client,
175 OEM_RAPI_STREAMING_FUNCTION_PROC,
176 oem_rapi_client_streaming_function_arg, arg,
177 oem_rapi_client_streaming_function_ret,
178 ret, -1);
179}
180EXPORT_SYMBOL(oem_rapi_client_streaming_function);
181
182int oem_rapi_client_close(void)
183{
184 mutex_lock(&oem_rapi_client_lock);
185 if (--open_count == 0) {
186 msm_rpc_unregister_client(rpc_client);
187 pr_info("%s: disconnected from remote oem rapi server\n",
188 __func__);
189 }
190 mutex_unlock(&oem_rapi_client_lock);
191 return 0;
192}
193EXPORT_SYMBOL(oem_rapi_client_close);
194
195struct msm_rpc_client *oem_rapi_client_init(void)
196{
197 mutex_lock(&oem_rapi_client_lock);
198 if (open_count == 0) {
199 rpc_client = msm_rpc_register_client2("oemrapiclient",
200 OEM_RAPI_PROG,
201 OEM_RAPI_VERS, 0,
202 oem_rapi_client_cb);
203 if (!IS_ERR(rpc_client))
204 open_count++;
205 }
206 mutex_unlock(&oem_rapi_client_lock);
207 return rpc_client;
208}
209EXPORT_SYMBOL(oem_rapi_client_init);
210
211#if defined(CONFIG_DEBUG_FS)
212
213static struct dentry *dent;
214static int oem_rapi_client_test_res;
215
216static int oem_rapi_client_null(struct msm_rpc_client *client,
217 void *arg, void *ret)
218{
219 return msm_rpc_client_req2(client, OEM_RAPI_NULL_PROC,
220 NULL, NULL, NULL, NULL, -1);
221}
222
223static int oem_rapi_client_test_streaming_cb_func(
224 struct oem_rapi_client_streaming_func_cb_arg *arg,
225 struct oem_rapi_client_streaming_func_cb_ret *ret)
226{
227 uint32_t size;
228
229 size = (arg->in_len < OEM_RAPI_CLIENT_MAX_OUT_BUFF_SIZE) ?
230 arg->in_len : OEM_RAPI_CLIENT_MAX_OUT_BUFF_SIZE;
231
232 if (ret->out_len != 0)
233 *ret->out_len = size;
234
235 if (ret->output != 0)
236 memcpy(ret->output, arg->input, size);
237
238 return 0;
239}
240
241static ssize_t debug_read(struct file *fp, char __user *buf,
242 size_t count, loff_t *pos)
243{
244 char _buf[16];
245
246 snprintf(_buf, sizeof(_buf), "%i\n", oem_rapi_client_test_res);
247
248 return simple_read_from_buffer(buf, count, pos, _buf, strlen(_buf));
249}
250
251static ssize_t debug_write(struct file *fp, const char __user *buf,
252 size_t count, loff_t *pos)
253{
254 char input[OEM_RAPI_CLIENT_MAX_OUT_BUFF_SIZE];
255 struct oem_rapi_client_streaming_func_arg arg;
256 struct oem_rapi_client_streaming_func_ret ret;
257
258 unsigned char cmd[64];
259 int len;
260
261 if (count < 1)
262 return 0;
263
264 len = count > 63 ? 63 : count;
265
266 if (copy_from_user(cmd, buf, len))
267 return -EFAULT;
268
269 cmd[len] = 0;
270
271 if (cmd[len-1] == '\n') {
272 cmd[len-1] = 0;
273 len--;
274 }
275
276 if (!strncmp(cmd, "null", 64)) {
277 oem_rapi_client_test_res = oem_rapi_client_null(rpc_client,
278 NULL, NULL);
279 } else if (!strncmp(cmd, "streaming_func", 64)) {
280 memset(input, 5, 16);
281 arg.event = 0;
282 arg.cb_func = oem_rapi_client_test_streaming_cb_func;
283 arg.handle = (void *)20;
284 arg.in_len = 16;
285 arg.input = input;
286 arg.out_len_valid = 1;
287 arg.output_valid = 1;
288 arg.output_size = OEM_RAPI_CLIENT_MAX_OUT_BUFF_SIZE;
289 ret.out_len = NULL;
290 ret.output = NULL;
291
292 oem_rapi_client_test_res = oem_rapi_client_streaming_function(
293 rpc_client, &arg, &ret);
294
295 kfree(ret.out_len);
296 kfree(ret.output);
297
298 } else
299 oem_rapi_client_test_res = -EINVAL;
300
301 if (oem_rapi_client_test_res)
302 pr_err("oem rapi client test fail %d\n",
303 oem_rapi_client_test_res);
304 else
305 pr_info("oem rapi client test passed\n");
306
307 return count;
308}
309
310static int debug_release(struct inode *ip, struct file *fp)
311{
312 return oem_rapi_client_close();
313}
314
315static int debug_open(struct inode *ip, struct file *fp)
316{
317 struct msm_rpc_client *client;
318 client = oem_rapi_client_init();
319 if (IS_ERR(client)) {
320 pr_err("%s: couldn't open oem rapi client\n", __func__);
321 return PTR_ERR(client);
322 } else
323 pr_info("%s: connected to remote oem rapi server\n", __func__);
324
325 return 0;
326}
327
328static const struct file_operations debug_ops = {
329 .owner = THIS_MODULE,
330 .open = debug_open,
331 .release = debug_release,
332 .read = debug_read,
333 .write = debug_write,
334};
335
336static void __exit oem_rapi_client_mod_exit(void)
337{
338 debugfs_remove(dent);
339}
340
341static int __init oem_rapi_client_mod_init(void)
342{
343 dent = debugfs_create_file("oem_rapi", 0444, 0, NULL, &debug_ops);
344 open_count = 0;
345 oem_rapi_client_test_res = -1;
346 return 0;
347}
348
349module_init(oem_rapi_client_mod_init);
350module_exit(oem_rapi_client_mod_exit);
351
352#endif
353
354MODULE_DESCRIPTION("OEM RAPI CLIENT Driver");
355MODULE_LICENSE("GPL v2");