blob: 4499f7637ec24b60653513ffccaaa469af47eb53 [file] [log] [blame]
Duy Truong790f06d2013-02-13 16:38:12 -08001/* Copyright (c) 2010, The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
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 * PING APPS SERVER Driver
16 */
17
18#include <linux/slab.h>
19#include <linux/module.h>
20#include <linux/kernel.h>
21#include <linux/delay.h>
22#include <linux/err.h>
23#include <linux/kthread.h>
24#include <linux/workqueue.h>
25#include <mach/msm_rpcrouter.h>
26
27/* ping server definitions */
28
29#define PING_APPS_PROG 0x30000082
30#define PING_APPS_VERS 0x00010001
31
32#define PING_APPS_NULL 0
33#define PING_APPS_DATA 4
34#define PING_APPS_REG 2
35#define PING_APPS_UNREG 3
36#define PING_APPS_DATA_CB_REG 6
37#define PING_APPS_DATA_CB_UNREG 5
38
39#define PING_APPS_REG_CB 2
40#define PING_APPS_DATA_CB 1
41
42static LIST_HEAD(cb_entry_list);
43static DEFINE_MUTEX(cb_entry_list_lock);
44
45static struct task_struct *server_thread;
46
47struct ping_apps_register_arg {
48 uint32_t cb_id;
49 int32_t num;
50};
51
52struct ping_apps_unregister_arg {
53 uint32_t cb_id;
54};
55
56struct ping_apps_register_cb_arg {
57 uint32_t cb_id;
58 int32_t num;
59};
60
61struct ping_apps_register_ret {
62 uint32_t result;
63};
64
65struct ping_apps_unregister_ret {
66 uint32_t result;
67};
68
69struct ping_apps_data_cb_reg_arg {
70 uint32_t cb_id;
71 uint32_t num;
72 uint32_t size;
73 uint32_t interval_ms;
74 uint32_t num_tasks;
75};
76
77struct ping_apps_data_cb_unreg_arg {
78 uint32_t cb_id;
79};
80
81struct ping_apps_data_cb_arg {
82 uint32_t cb_id;
83 uint32_t *data;
84 uint32_t size;
85 uint32_t sum;
86};
87
88struct ping_apps_data_cb_reg_ret {
89 uint32_t result;
90};
91
92struct ping_apps_data_cb_unreg_ret {
93 uint32_t result;
94};
95
96struct ping_apps_data_cb_ret {
97 uint32_t result;
98};
99
100struct ping_apps_data_arg {
101 uint32_t *data;
102 uint32_t size;
103};
104
105struct ping_apps_data_ret {
106 uint32_t result;
107};
108
109struct ping_apps_data_cb_info {
110 void *cb_func;
111 uint32_t size;
112 uint32_t num_tasks;
113};
114
115struct ping_apps_cb_entry {
116 struct list_head list;
117
118 struct msm_rpc_client_info clnt_info;
119 void *cb_info;
120 uint32_t cb_id;
121 int32_t num;
122 uint32_t interval_ms;
123 uint32_t time_to_next_cb;
124 void (*cb_func)(struct ping_apps_cb_entry *);
125};
126
127static int handle_rpc_call(struct msm_rpc_server *server,
128 struct rpc_request_hdr *req,
129 struct msm_rpc_xdr *xdr);
130
131static int ping_apps_data_cb(struct msm_rpc_server *server,
132 struct msm_rpc_client_info *clnt_info,
133 struct ping_apps_data_cb_arg *arg,
134 struct ping_apps_data_cb_ret *ret);
135
136static int ping_apps_register_cb(struct msm_rpc_server *server,
137 struct msm_rpc_client_info *clnt_info,
138 struct ping_apps_register_cb_arg *arg,
139 void *ret);
140
141static struct msm_rpc_server rpc_server = {
142 .prog = PING_APPS_PROG,
143 .vers = PING_APPS_VERS,
144 .rpc_call2 = handle_rpc_call,
145};
146
147static void handle_ping_apps_data_cb(struct ping_apps_cb_entry *cb_entry)
148{
149 struct ping_apps_data_cb_arg arg;
150 struct ping_apps_data_cb_ret ret;
151 uint32_t my_sum = 0;
152 uint32_t *my_data;
153 int i;
154
155 if (cb_entry->num > 0) {
156 cb_entry->num--;
157 arg.cb_id = cb_entry->cb_id;
158 arg.size = ((struct ping_apps_data_cb_info *)
159 (cb_entry->cb_info))->size;
160
161 my_data = kmalloc((arg.size * sizeof(uint32_t)), GFP_KERNEL);
162 if (!my_data)
163 return;
164
165 for (i = 0; i < arg.size; i++) {
166 my_data[i] = (42 + i);
167 my_sum ^= (42 + i);
168 }
169 arg.data = my_data;
170 arg.sum = my_sum;
171
172 ((int (*)(struct msm_rpc_server *,
173 struct msm_rpc_client_info *,
174 struct ping_apps_data_cb_arg *,
175 struct ping_apps_data_cb_ret *))
176 ((struct ping_apps_data_cb_info *)
177 (cb_entry->cb_info))->cb_func)(&rpc_server,
178 &cb_entry->clnt_info,
179 &arg, &ret);
180 pr_info("%s: cb_id = %d, ret = %d\n",
181 __func__, arg.cb_id, ret.result);
182 kfree(my_data);
183 }
184}
185
186static void handle_ping_apps_register_cb(struct ping_apps_cb_entry *cb_entry)
187{
188 struct ping_apps_register_cb_arg arg;
189
190 if (cb_entry->num > 0) {
191 cb_entry->num--;
192 arg.cb_id = cb_entry->cb_id;
193 arg.num = cb_entry->num;
194
195 pr_info("%s: cb_id = %d, num = %d\n",
196 __func__, arg.cb_id, arg.num);
197 ((int (*)(struct msm_rpc_server *,
198 struct msm_rpc_client_info *,
199 struct ping_apps_register_cb_arg *,
200 void *))cb_entry->cb_info)(&rpc_server,
201 &cb_entry->clnt_info,
202 &arg, NULL);
203 }
204
205}
206
207static int ping_apps_cb_process_thread(void *data)
208{
209 struct ping_apps_cb_entry *cb_entry;
210 uint32_t sleep_time;
211 uint32_t time_slept = 0;
212
213 pr_info("%s: thread started\n", __func__);
214 for (;;) {
215 sleep_time = 1000;
216 mutex_lock(&cb_entry_list_lock);
217 list_for_each_entry(cb_entry, &cb_entry_list, list) {
218 if (cb_entry->time_to_next_cb <= time_slept) {
219 cb_entry->cb_func(cb_entry);
220 cb_entry->time_to_next_cb =
221 cb_entry->interval_ms;
222 } else
223 cb_entry->time_to_next_cb -= time_slept;
224
225 if (cb_entry->time_to_next_cb < sleep_time)
226 sleep_time = cb_entry->time_to_next_cb;
227 }
228 mutex_unlock(&cb_entry_list_lock);
229
230 msleep(sleep_time);
231 time_slept = sleep_time;
232 }
233
234 do_exit(0);
235}
236
237static int ping_apps_data_register(struct ping_apps_data_arg *arg,
238 struct ping_apps_data_ret *ret)
239{
240 int i;
241
242 ret->result = 0;
243 for (i = 0; i < arg->size; i++)
244 ret->result ^= arg->data[i];
245
246 return 0;
247}
248
249static int ping_apps_data_cb_reg(struct ping_apps_data_cb_reg_arg *arg,
250 struct ping_apps_data_cb_reg_ret *ret)
251{
252 struct ping_apps_cb_entry *cb_entry;
253 struct ping_apps_data_cb_info *cb_info;
254
255 cb_entry = kmalloc(sizeof(*cb_entry), GFP_KERNEL);
256 if (!cb_entry)
257 return -ENOMEM;
258
259 cb_entry->cb_info = kmalloc(sizeof(struct ping_apps_data_cb_info),
260 GFP_KERNEL);
261 if (!cb_entry->cb_info) {
262 kfree(cb_entry);
263 return -ENOMEM;
264 }
265 cb_info = (struct ping_apps_data_cb_info *)cb_entry->cb_info;
266
267 INIT_LIST_HEAD(&cb_entry->list);
268 cb_entry->cb_func = handle_ping_apps_data_cb;
269 cb_entry->cb_id = arg->cb_id;
270 cb_entry->num = arg->num;
271 cb_entry->interval_ms = arg->interval_ms;
272 cb_entry->time_to_next_cb = arg->interval_ms;
273 cb_info->cb_func = ping_apps_data_cb;
274 cb_info->size = arg->size;
275 cb_info->num_tasks = arg->num_tasks;
276
277 mutex_lock(&cb_entry_list_lock);
278 list_add_tail(&cb_entry->list, &cb_entry_list);
279 mutex_unlock(&cb_entry_list_lock);
280
281 msm_rpc_server_get_requesting_client(&cb_entry->clnt_info);
282
283 if (IS_ERR(server_thread))
284 server_thread = kthread_run(ping_apps_cb_process_thread,
285 NULL, "kpingrpccbprocessd");
286 if (IS_ERR(server_thread)) {
287 kfree(cb_entry);
288 return PTR_ERR(server_thread);
289 }
290
291 ret->result = 1;
292 return 0;
293}
294
295static int ping_apps_data_cb_unreg(struct ping_apps_data_cb_unreg_arg *arg,
296 struct ping_apps_data_cb_unreg_ret *ret)
297{
298 struct ping_apps_cb_entry *cb_entry, *tmp_cb_entry;
299
300 mutex_lock(&cb_entry_list_lock);
301 list_for_each_entry_safe(cb_entry, tmp_cb_entry,
302 &cb_entry_list, list) {
303 if (cb_entry->cb_id == arg->cb_id) {
304 list_del(&cb_entry->list);
305 kfree(cb_entry->cb_info);
306 kfree(cb_entry);
307 break;
308 }
309 }
310 mutex_unlock(&cb_entry_list_lock);
311
312 ret->result = 1;
313 return 0;
314}
315
316static int ping_apps_register(struct ping_apps_register_arg *arg,
317 struct ping_apps_register_ret *ret)
318{
319 struct ping_apps_cb_entry *cb_entry;
320
321 cb_entry = kmalloc(sizeof(*cb_entry), GFP_KERNEL);
322 if (!cb_entry)
323 return -ENOMEM;
324
325 INIT_LIST_HEAD(&cb_entry->list);
326 cb_entry->cb_func = handle_ping_apps_register_cb;
327 cb_entry->cb_info = ping_apps_register_cb;
328 cb_entry->cb_id = arg->cb_id;
329 cb_entry->num = arg->num;
330 cb_entry->interval_ms = 100;
331 cb_entry->time_to_next_cb = 100;
332
333 mutex_lock(&cb_entry_list_lock);
334 list_add_tail(&cb_entry->list, &cb_entry_list);
335 mutex_unlock(&cb_entry_list_lock);
336
337 msm_rpc_server_get_requesting_client(&cb_entry->clnt_info);
338
339 if (IS_ERR(server_thread))
340 server_thread = kthread_run(ping_apps_cb_process_thread,
341 NULL, "kpingrpccbprocessd");
342 if (IS_ERR(server_thread)) {
343 kfree(cb_entry);
344 return PTR_ERR(server_thread);
345 }
346
347 ret->result = 1;
348 return 0;
349}
350
351static int ping_apps_unregister(struct ping_apps_unregister_arg *arg,
352 struct ping_apps_unregister_ret *ret)
353{
354 struct ping_apps_cb_entry *cb_entry, *tmp_cb_entry;
355
356 mutex_lock(&cb_entry_list_lock);
357 list_for_each_entry_safe(cb_entry, tmp_cb_entry,
358 &cb_entry_list, list) {
359 if (cb_entry->cb_id == arg->cb_id) {
360 list_del(&cb_entry->list);
361 kfree(cb_entry);
362 break;
363 }
364 }
365 mutex_unlock(&cb_entry_list_lock);
366
367 ret->result = 1;
368 return 0;
369}
370
371static int ping_apps_data_cb_arg_func(struct msm_rpc_server *server,
372 struct msm_rpc_xdr *xdr, void *data)
373{
374 struct ping_apps_data_cb_arg *arg = data;
375
376 xdr_send_uint32(xdr, &arg->cb_id);
377 xdr_send_array(xdr, (void **)&arg->data, &arg->size, 64,
378 sizeof(uint32_t), (void *)xdr_send_uint32);
379 xdr_send_uint32(xdr, &arg->size);
380 xdr_send_uint32(xdr, &arg->sum);
381
382 return 0;
383}
384
385static int ping_apps_data_cb_ret_func(struct msm_rpc_server *server,
386 struct msm_rpc_xdr *xdr, void *data)
387{
388 struct ping_apps_data_cb_ret *ret = data;
389
390 xdr_recv_uint32(xdr, &ret->result);
391
392 return 0;
393}
394
395static int ping_apps_data_cb(struct msm_rpc_server *server,
396 struct msm_rpc_client_info *clnt_info,
397 struct ping_apps_data_cb_arg *arg,
398 struct ping_apps_data_cb_ret *ret)
399{
400 return msm_rpc_server_cb_req2(server, clnt_info,
401 PING_APPS_DATA_CB,
402 ping_apps_data_cb_arg_func, arg,
403 ping_apps_data_cb_ret_func, ret, -1);
404}
405
406static int ping_apps_register_cb_arg(struct msm_rpc_server *server,
407 struct msm_rpc_xdr *xdr, void *data)
408{
409 struct ping_apps_register_cb_arg *arg = data;
410
411 xdr_send_uint32(xdr, &arg->cb_id);
412 xdr_send_int32(xdr, &arg->num);
413
414 return 0;
415}
416
417static int ping_apps_register_cb(struct msm_rpc_server *server,
418 struct msm_rpc_client_info *clnt_info,
419 struct ping_apps_register_cb_arg *arg,
420 void *ret)
421{
422 return msm_rpc_server_cb_req2(server, clnt_info,
423 PING_APPS_REG_CB,
424 ping_apps_register_cb_arg,
425 arg, NULL, NULL, -1);
426}
427
428static int handle_ping_apps_data_register(struct msm_rpc_server *server,
429 struct rpc_request_hdr *req,
430 struct msm_rpc_xdr *xdr)
431{
432 uint32_t rc;
433 struct ping_apps_data_arg arg;
434 struct ping_apps_data_ret ret;
435
436 pr_info("%s: request received\n", __func__);
437
438 xdr_recv_array(xdr, (void **)&arg.data, &arg.size, 64,
439 sizeof(uint32_t), (void *)xdr_recv_uint32);
440 xdr_recv_uint32(xdr, &arg.size);
441
442 rc = ping_apps_data_register(&arg, &ret);
443 if (rc < 0)
444 goto free_and_return;
445
446 xdr_start_accepted_reply(xdr, RPC_ACCEPTSTAT_SUCCESS);
447 xdr_send_uint32(xdr, &ret.result);
448 rc = xdr_send_msg(xdr);
449 if (rc < 0)
450 pr_info("%s: sending reply failed\n", __func__);
451 else
452 rc = 1;
453
454 free_and_return:
455 kfree(arg.data);
456 return rc;
457}
458
459static int handle_ping_apps_data_cb_reg(struct msm_rpc_server *server,
460 struct rpc_request_hdr *req,
461 struct msm_rpc_xdr *xdr)
462{
463 uint32_t rc;
464 struct ping_apps_data_cb_reg_arg arg;
465 struct ping_apps_data_cb_reg_ret ret;
466
467 pr_info("%s: request received\n", __func__);
468
469 xdr_recv_uint32(xdr, &arg.cb_id);
470 xdr_recv_uint32(xdr, &arg.num);
471 xdr_recv_uint32(xdr, &arg.size);
472 xdr_recv_uint32(xdr, &arg.interval_ms);
473 xdr_recv_uint32(xdr, &arg.num_tasks);
474
475 rc = ping_apps_data_cb_reg(&arg, &ret);
476 if (rc < 0)
477 return rc;
478
479 xdr_start_accepted_reply(xdr, RPC_ACCEPTSTAT_SUCCESS);
480 xdr_send_uint32(xdr, &ret.result);
481 rc = xdr_send_msg(xdr);
482 if (rc < 0)
483 pr_info("%s: sending reply failed\n", __func__);
484 else
485 rc = 1;
486
487 return rc;
488}
489
490static int handle_ping_apps_data_cb_unreg(struct msm_rpc_server *server,
491 struct rpc_request_hdr *req,
492 struct msm_rpc_xdr *xdr)
493{
494 uint32_t rc;
495 struct ping_apps_data_cb_unreg_arg arg;
496 struct ping_apps_data_cb_unreg_ret ret;
497
498 pr_info("%s: request received\n", __func__);
499
500 xdr_recv_uint32(xdr, &arg.cb_id);
501
502 rc = ping_apps_data_cb_unreg(&arg, &ret);
503 if (rc < 0)
504 return rc;
505
506 xdr_start_accepted_reply(xdr, RPC_ACCEPTSTAT_SUCCESS);
507 xdr_send_uint32(xdr, &ret.result);
508 rc = xdr_send_msg(xdr);
509 if (rc < 0)
510 pr_info("%s: sending reply failed\n", __func__);
511 else
512 rc = 1;
513
514 return rc;
515}
516
517static int handle_ping_apps_register(struct msm_rpc_server *server,
518 struct rpc_request_hdr *req,
519 struct msm_rpc_xdr *xdr)
520{
521 uint32_t rc;
522 struct ping_apps_register_arg arg;
523 struct ping_apps_register_ret ret;
524
525 pr_info("%s: request received\n", __func__);
526
527 xdr_recv_uint32(xdr, &arg.cb_id);
528 xdr_recv_int32(xdr, &arg.num);
529
530 rc = ping_apps_register(&arg, &ret);
531 if (rc < 0)
532 return rc;
533
534 xdr_start_accepted_reply(xdr, RPC_ACCEPTSTAT_SUCCESS);
535 xdr_send_uint32(xdr, &ret.result);
536 rc = xdr_send_msg(xdr);
537 if (rc < 0)
538 pr_info("%s: sending reply failed\n", __func__);
539 else
540 rc = 1;
541
542 return rc;
543}
544
545static int handle_ping_apps_unregister(struct msm_rpc_server *server,
546 struct rpc_request_hdr *req,
547 struct msm_rpc_xdr *xdr)
548{
549 uint32_t rc;
550 struct ping_apps_unregister_arg arg;
551 struct ping_apps_unregister_ret ret;
552
553 pr_info("%s: request received\n", __func__);
554
555 xdr_recv_uint32(xdr, &arg.cb_id);
556
557 rc = ping_apps_unregister(&arg, &ret);
558 if (rc < 0)
559 return rc;
560
561 xdr_start_accepted_reply(xdr, RPC_ACCEPTSTAT_SUCCESS);
562 xdr_send_uint32(xdr, &ret.result);
563 rc = xdr_send_msg(xdr);
564 if (rc < 0)
565 pr_info("%s: sending reply failed\n", __func__);
566 else
567 rc = 1;
568
569 return rc;
570}
571
572static int handle_rpc_call(struct msm_rpc_server *server,
573 struct rpc_request_hdr *req,
574 struct msm_rpc_xdr *xdr)
575{
576 switch (req->procedure) {
577 case PING_APPS_NULL:
578 pr_info("%s: null procedure request received\n", __func__);
579 return 0;
580 case PING_APPS_DATA:
581 return handle_ping_apps_data_register(server, req, xdr);
582 case PING_APPS_REG:
583 return handle_ping_apps_register(server, req, xdr);
584 case PING_APPS_UNREG:
585 return handle_ping_apps_unregister(server, req, xdr);
586 case PING_APPS_DATA_CB_REG:
587 return handle_ping_apps_data_cb_reg(server, req, xdr);
588 case PING_APPS_DATA_CB_UNREG:
589 return handle_ping_apps_data_cb_unreg(server, req, xdr);
590 default:
591 return -ENODEV;
592 }
593}
594
595static int __init ping_apps_server_init(void)
596{
597 INIT_LIST_HEAD(&cb_entry_list);
598 server_thread = ERR_PTR(-1);
599 return msm_rpc_create_server2(&rpc_server);
600}
601
602module_init(ping_apps_server_init);
603
604MODULE_DESCRIPTION("PING APPS SERVER Driver");
605MODULE_LICENSE("GPL v2");