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