blob: 4044836cb4a612b235bb8124a17c1b0c7f22e3a9 [file] [log] [blame]
Duy Truong790f06d2013-02-13 16:38:12 -08001/* Copyright (c) 2009-2011, 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 * SMD RPC PING MODEM Driver
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/kfifo.h>
Steve Mucklef132c6c2012-06-06 18:30:57 -070027#include <linux/export.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070028#include <mach/msm_rpcrouter.h>
29
30#define PING_TEST_BASE 0x31
31
32#define PTIOC_NULL_TEST _IO(PING_TEST_BASE, 1)
33#define PTIOC_REG_TEST _IO(PING_TEST_BASE, 2)
34#define PTIOC_DATA_REG_TEST _IO(PING_TEST_BASE, 3)
35#define PTIOC_DATA_CB_REG_TEST _IO(PING_TEST_BASE, 4)
36
37#define PING_MDM_PROG 0x30000081
38#define PING_MDM_VERS 0x00010001
39#define PING_MDM_CB_PROG 0x31000081
40#define PING_MDM_CB_VERS 0x00010001
41
42#define PING_MDM_NULL_PROC 0
43#define PING_MDM_RPC_GLUE_CODE_INFO_REMOTE_PROC 1
44#define PING_MDM_REGISTER_PROC 2
45#define PING_MDM_UNREGISTER_PROC 3
46#define PING_MDM_REGISTER_DATA_PROC 4
47#define PING_MDM_UNREGISTER_DATA_CB_PROC 5
48#define PING_MDM_REGISTER_DATA_CB_PROC 6
49
50#define PING_MDM_DATA_CB_PROC 1
51#define PING_MDM_CB_PROC 2
52
53#define PING_MAX_RETRY 5
54
55static struct msm_rpc_client *rpc_client;
56static uint32_t open_count;
57static DEFINE_MUTEX(ping_mdm_lock);
58
59struct ping_mdm_register_cb_arg {
60 uint32_t cb_id;
61 int val;
62};
63
64struct ping_mdm_register_data_cb_cb_arg {
65 uint32_t cb_id;
66 uint32_t *data;
67 uint32_t size;
68 uint32_t sum;
69};
70
71struct ping_mdm_register_data_cb_cb_ret {
72 uint32_t result;
73};
74
75static struct dentry *dent;
76static uint32_t test_res;
77static int reg_cb_num, reg_cb_num_req;
78static int data_cb_num, data_cb_num_req;
79static int reg_done_flag, data_cb_done_flag;
80static DECLARE_WAIT_QUEUE_HEAD(reg_test_wait);
81static DECLARE_WAIT_QUEUE_HEAD(data_cb_test_wait);
82
83enum {
84 PING_MODEM_NOT_IN_RESET = 0,
85 PING_MODEM_IN_RESET,
86 PING_LEAVING_RESET,
87 PING_MODEM_REGISTER_CB
88};
89static int fifo_event;
90static DEFINE_MUTEX(event_fifo_lock);
91static DEFINE_KFIFO(event_fifo, int, sizeof(int)*16);
92
93static int ping_mdm_register_cb(struct msm_rpc_client *client,
94 struct msm_rpc_xdr *xdr)
95{
96 int rc;
97 uint32_t accept_status;
98 struct ping_mdm_register_cb_arg arg;
99 void *cb_func;
100
101 xdr_recv_uint32(xdr, &arg.cb_id); /* cb_id */
102 xdr_recv_int32(xdr, &arg.val); /* val */
103
104 cb_func = msm_rpc_get_cb_func(client, arg.cb_id);
105 if (cb_func) {
106 rc = ((int (*)(struct ping_mdm_register_cb_arg *, void *))
107 cb_func)(&arg, NULL);
108 if (rc)
109 accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR;
110 else
111 accept_status = RPC_ACCEPTSTAT_SUCCESS;
112 } else
113 accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR;
114
115 xdr_start_accepted_reply(xdr, accept_status);
116 rc = xdr_send_msg(xdr);
117 if (rc)
118 pr_err("%s: send accepted reply failed: %d\n", __func__, rc);
119
120 return rc;
121}
122
123static int ping_mdm_data_cb(struct msm_rpc_client *client,
124 struct msm_rpc_xdr *xdr)
125{
126 int rc;
127 void *cb_func;
128 uint32_t size, accept_status;
129 struct ping_mdm_register_data_cb_cb_arg arg;
130 struct ping_mdm_register_data_cb_cb_ret ret;
131
132 xdr_recv_uint32(xdr, &arg.cb_id); /* cb_id */
133
134 /* data */
135 xdr_recv_array(xdr, (void **)(&(arg.data)), &size, 64,
136 sizeof(uint32_t), (void *)xdr_recv_uint32);
137
138 xdr_recv_uint32(xdr, &arg.size); /* size */
139 xdr_recv_uint32(xdr, &arg.sum); /* sum */
140
141 cb_func = msm_rpc_get_cb_func(client, arg.cb_id);
142 if (cb_func) {
143 rc = ((int (*)
144 (struct ping_mdm_register_data_cb_cb_arg *,
145 struct ping_mdm_register_data_cb_cb_ret *))
146 cb_func)(&arg, &ret);
147 if (rc)
148 accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR;
149 else
150 accept_status = RPC_ACCEPTSTAT_SUCCESS;
151 } else
152 accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR;
153
154 xdr_start_accepted_reply(xdr, accept_status);
155
156 if (accept_status == RPC_ACCEPTSTAT_SUCCESS)
157 xdr_send_uint32(xdr, &ret.result); /* result */
158
159 rc = xdr_send_msg(xdr);
160 if (rc)
161 pr_err("%s: send accepted reply failed: %d\n", __func__, rc);
162
163 kfree(arg.data);
164 return rc;
165}
166
167static int ping_mdm_cb_func(struct msm_rpc_client *client,
168 struct rpc_request_hdr *req,
169 struct msm_rpc_xdr *xdr)
170{
171 int rc = 0;
172
173 switch (req->procedure) {
174 case PING_MDM_CB_PROC:
175 rc = ping_mdm_register_cb(client, xdr);
176 break;
177 case PING_MDM_DATA_CB_PROC:
178 rc = ping_mdm_data_cb(client, xdr);
179 break;
180 default:
181 pr_err("%s: procedure not supported %d\n",
182 __func__, req->procedure);
183 xdr_start_accepted_reply(xdr, RPC_ACCEPTSTAT_PROC_UNAVAIL);
184 rc = xdr_send_msg(xdr);
185 if (rc)
186 pr_err("%s: sending reply failed: %d\n", __func__, rc);
187 break;
188 }
189 return rc;
190}
191
192struct ping_mdm_unregister_data_cb_arg {
193 int (*cb_func)(
194 struct ping_mdm_register_data_cb_cb_arg *arg,
195 struct ping_mdm_register_data_cb_cb_ret *ret);
196};
197
198struct ping_mdm_register_data_cb_arg {
199 int (*cb_func)(
200 struct ping_mdm_register_data_cb_cb_arg *arg,
201 struct ping_mdm_register_data_cb_cb_ret *ret);
202 uint32_t num;
203 uint32_t size;
204 uint32_t interval_ms;
205 uint32_t num_tasks;
206};
207
208struct ping_mdm_register_data_cb_ret {
209 uint32_t result;
210};
211
212struct ping_mdm_unregister_data_cb_ret {
213 uint32_t result;
214};
215
216static int ping_mdm_data_cb_register_arg(struct msm_rpc_client *client,
217 struct msm_rpc_xdr *xdr, void *data)
218{
219 struct ping_mdm_register_data_cb_arg *arg = data;
220 int cb_id;
221
222 cb_id = msm_rpc_add_cb_func(client, (void *)arg->cb_func);
223 if ((cb_id < 0) && (cb_id != MSM_RPC_CLIENT_NULL_CB_ID))
224 return cb_id;
225
226 xdr_send_uint32(xdr, &cb_id); /* cb_id */
227 xdr_send_uint32(xdr, &arg->num); /* num */
228 xdr_send_uint32(xdr, &arg->size); /* size */
229 xdr_send_uint32(xdr, &arg->interval_ms); /* interval_ms */
230 xdr_send_uint32(xdr, &arg->num_tasks); /* num_tasks */
231
232 return 0;
233}
234
235static int ping_mdm_data_cb_unregister_arg(struct msm_rpc_client *client,
236 struct msm_rpc_xdr *xdr, void *data)
237{
238 struct ping_mdm_unregister_data_cb_arg *arg = data;
239 int cb_id;
240
241 cb_id = msm_rpc_add_cb_func(client, (void *)arg->cb_func);
242 if ((cb_id < 0) && (cb_id != MSM_RPC_CLIENT_NULL_CB_ID))
243 return cb_id;
244
245 xdr_send_uint32(xdr, &cb_id); /* cb_id */
246
247 return 0;
248}
249
250static int ping_mdm_data_cb_register_ret(struct msm_rpc_client *client,
251 struct msm_rpc_xdr *xdr, void *data)
252{
253 struct ping_mdm_register_data_cb_ret *ret = data;
254
255 xdr_recv_uint32(xdr, &ret->result); /* result */
256
257 return 0;
258}
259
260static int ping_mdm_register_data_cb(
261 struct msm_rpc_client *client,
262 struct ping_mdm_register_data_cb_arg *arg,
263 struct ping_mdm_register_data_cb_ret *ret)
264{
265 return msm_rpc_client_req2(client,
266 PING_MDM_REGISTER_DATA_CB_PROC,
267 ping_mdm_data_cb_register_arg, arg,
268 ping_mdm_data_cb_register_ret, ret, -1);
269}
270
271static int ping_mdm_unregister_data_cb(
272 struct msm_rpc_client *client,
273 struct ping_mdm_unregister_data_cb_arg *arg,
274 struct ping_mdm_unregister_data_cb_ret *ret)
275{
276 return msm_rpc_client_req2(client,
277 PING_MDM_UNREGISTER_DATA_CB_PROC,
278 ping_mdm_data_cb_unregister_arg, arg,
279 ping_mdm_data_cb_register_ret, ret, -1);
280}
281
282struct ping_mdm_data_arg {
283 uint32_t *data;
284 uint32_t size;
285};
286
287struct ping_mdm_data_ret {
288 uint32_t result;
289};
290
291static int ping_mdm_data_register_arg(struct msm_rpc_client *client,
292 struct msm_rpc_xdr *xdr, void *data)
293{
294 struct ping_mdm_data_arg *arg = data;
295
296 /* data */
297 xdr_send_array(xdr, (void **)&arg->data, &arg->size, 64,
298 sizeof(uint32_t), (void *)xdr_send_uint32);
299
300 xdr_send_uint32(xdr, &arg->size); /* size */
301
302 return 0;
303}
304
305static int ping_mdm_data_register_ret(struct msm_rpc_client *client,
306 struct msm_rpc_xdr *xdr, void *data)
307{
308 struct ping_mdm_data_ret *ret = data;
309
310 xdr_recv_uint32(xdr, &ret->result); /* result */
311
312 return 0;
313}
314
315static int ping_mdm_data_register(
316 struct msm_rpc_client *client,
317 struct ping_mdm_data_arg *arg,
318 struct ping_mdm_data_ret *ret)
319{
320 return msm_rpc_client_req2(client,
321 PING_MDM_REGISTER_DATA_PROC,
322 ping_mdm_data_register_arg, arg,
323 ping_mdm_data_register_ret, ret, -1);
324}
325
326struct ping_mdm_register_arg {
327 int (*cb_func)(struct ping_mdm_register_cb_arg *, void *);
328 int num;
329};
330
331struct ping_mdm_unregister_arg {
332 int (*cb_func)(struct ping_mdm_register_cb_arg *, void *);
333};
334
335struct ping_mdm_register_ret {
336 uint32_t result;
337};
338
339struct ping_mdm_unregister_ret {
340 uint32_t result;
341};
342
343static int ping_mdm_register_arg(struct msm_rpc_client *client,
344 struct msm_rpc_xdr *xdr, void *data)
345{
346 struct ping_mdm_register_arg *arg = data;
347 int cb_id;
348
349 cb_id = msm_rpc_add_cb_func(client, (void *)arg->cb_func);
350 if ((cb_id < 0) && (cb_id != MSM_RPC_CLIENT_NULL_CB_ID))
351 return cb_id;
352
353 xdr_send_uint32(xdr, &cb_id); /* cb_id */
354 xdr_send_uint32(xdr, &arg->num); /* num */
355
356 return 0;
357}
358
359static int ping_mdm_unregister_arg(struct msm_rpc_client *client,
360 struct msm_rpc_xdr *xdr, void *data)
361{
362 struct ping_mdm_unregister_arg *arg = data;
363 int cb_id;
364
365 cb_id = msm_rpc_add_cb_func(client, (void *)arg->cb_func);
366 if ((cb_id < 0) && (cb_id != MSM_RPC_CLIENT_NULL_CB_ID))
367 return cb_id;
368
369 xdr_send_uint32(xdr, &cb_id); /* cb_id */
370
371 return 0;
372}
373
374static int ping_mdm_register_ret(struct msm_rpc_client *client,
375 struct msm_rpc_xdr *xdr, void *data)
376{
377 struct ping_mdm_register_ret *ret = data;
378
379 xdr_recv_uint32(xdr, &ret->result); /* result */
380
381 return 0;
382}
383
384static int ping_mdm_register(
385 struct msm_rpc_client *client,
386 struct ping_mdm_register_arg *arg,
387 struct ping_mdm_register_ret *ret)
388{
389 return msm_rpc_client_req2(client,
390 PING_MDM_REGISTER_PROC,
391 ping_mdm_register_arg, arg,
392 ping_mdm_register_ret, ret, -1);
393}
394
395static int ping_mdm_unregister(
396 struct msm_rpc_client *client,
397 struct ping_mdm_unregister_arg *arg,
398 struct ping_mdm_unregister_ret *ret)
399{
400 return msm_rpc_client_req2(client,
401 PING_MDM_UNREGISTER_PROC,
402 ping_mdm_unregister_arg, arg,
403 ping_mdm_register_ret, ret, -1);
404}
405
406static int ping_mdm_null(struct msm_rpc_client *client,
407 void *arg, void *ret)
408{
409 return msm_rpc_client_req2(client, PING_MDM_NULL_PROC,
410 NULL, NULL, NULL, NULL, -1);
411}
412
413static int ping_mdm_close(void)
414{
415 mutex_lock(&ping_mdm_lock);
416 if (--open_count == 0) {
417 msm_rpc_unregister_client(rpc_client);
418 pr_info("%s: disconnected from remote ping server\n",
419 __func__);
420 }
421 mutex_unlock(&ping_mdm_lock);
422 return 0;
423}
424
425static void handle_restart_teardown(struct msm_rpc_client *client)
426{
427 int event = PING_MODEM_IN_RESET;
428
429 pr_info("%s: modem in reset\n", __func__);
430
431 mutex_lock(&event_fifo_lock);
432 kfifo_in(&event_fifo, &event, sizeof(event));
433 fifo_event = 1;
434 mutex_unlock(&event_fifo_lock);
435
436 wake_up(&data_cb_test_wait);
437}
438
439static void handle_restart_setup(struct msm_rpc_client *client)
440{
441 int event = PING_LEAVING_RESET;
442
443 pr_info("%s: modem leaving reset\n", __func__);
444
445 mutex_lock(&event_fifo_lock);
446 kfifo_in(&event_fifo, &event, sizeof(event));
447 fifo_event = 1;
448 mutex_unlock(&event_fifo_lock);
449
450 wake_up(&data_cb_test_wait);
451}
452
453static struct msm_rpc_client *ping_mdm_init(void)
454{
455 mutex_lock(&ping_mdm_lock);
456 if (open_count == 0) {
457 rpc_client = msm_rpc_register_client2("pingdef",
458 PING_MDM_PROG,
459 PING_MDM_VERS, 1,
460 ping_mdm_cb_func);
461 if (!IS_ERR(rpc_client)) {
462 open_count++;
463 msm_rpc_register_reset_callbacks(rpc_client,
464 handle_restart_teardown,
465 handle_restart_setup);
466 }
467 }
468 mutex_unlock(&ping_mdm_lock);
469 return rpc_client;
470}
471
472static int ping_mdm_data_register_test(void)
473{
474 int i, rc = 0;
475 uint32_t my_data[64];
476 uint32_t my_sum = 0;
477 struct ping_mdm_data_arg data_arg;
478 struct ping_mdm_data_ret data_ret;
479
480 for (i = 0; i < 64; i++) {
481 my_data[i] = (42 + i);
482 my_sum ^= (42 + i);
483 }
484
485 data_arg.data = my_data;
486 data_arg.size = 64;
487
488 rc = ping_mdm_data_register(rpc_client, &data_arg, &data_ret);
489 if (rc)
490 return rc;
491
492 if (my_sum != data_ret.result) {
493 pr_err("%s: sum mismatch %d %d\n",
494 __func__, my_sum, data_ret.result);
495 rc = -1;
496 }
497
498 return rc;
499}
500
501static int ping_mdm_test_register_data_cb(
502 struct ping_mdm_register_data_cb_cb_arg *arg,
503 struct ping_mdm_register_data_cb_cb_ret *ret)
504{
505 uint32_t i, sum = 0;
506
507 data_cb_num++;
508
509 pr_info("%s: received cb_id %d, size = %d, sum = %u, num = %u of %u\n",
510 __func__, arg->cb_id, arg->size, arg->sum, data_cb_num,
511 data_cb_num_req);
512
513 if (arg->data)
514 for (i = 0; i < arg->size; i++)
515 sum ^= arg->data[i];
516
517 if (sum != arg->sum)
518 pr_err("%s: sum mismatch %u %u\n", __func__, sum, arg->sum);
519
520 if (data_cb_num == data_cb_num_req) {
521 data_cb_done_flag = 1;
522 wake_up(&data_cb_test_wait);
523 }
524
525 ret->result = 1;
526 return 0;
527}
528
529static int ping_mdm_data_cb_register(
530 struct ping_mdm_register_data_cb_ret *reg_ret)
531{
532 int rc;
533 struct ping_mdm_register_data_cb_arg reg_arg;
534
535 reg_arg.cb_func = ping_mdm_test_register_data_cb;
536 reg_arg.num = data_cb_num_req - data_cb_num;
537 reg_arg.size = 64;
538 reg_arg.interval_ms = 10;
539 reg_arg.num_tasks = 1;
540
541 pr_info("%s: registering callback\n", __func__);
542 rc = ping_mdm_register_data_cb(rpc_client, &reg_arg, reg_ret);
543 if (rc)
544 pr_err("%s: failed to register callback %d\n", __func__, rc);
545
546 return rc;
547}
548
549
550static void retry_timer_cb(unsigned long data)
551{
552 int event = (int)data;
553
554 pr_info("%s: retry timer triggered\n", __func__);
555
556 mutex_lock(&event_fifo_lock);
557 kfifo_in(&event_fifo, &event, sizeof(event));
558 fifo_event = 1;
559 mutex_unlock(&event_fifo_lock);
560
561 wake_up(&data_cb_test_wait);
562}
563
564static int ping_mdm_data_cb_register_test(void)
565{
566 int rc;
567 int event;
568 int retry_count = 0;
569 struct ping_mdm_register_data_cb_ret reg_ret;
570 struct ping_mdm_unregister_data_cb_arg unreg_arg;
571 struct ping_mdm_unregister_data_cb_ret unreg_ret;
572 struct timer_list retry_timer;
573
574 mutex_init(&event_fifo_lock);
575 init_timer(&retry_timer);
576
577 data_cb_done_flag = 0;
578 data_cb_num = 0;
579 if (!data_cb_num_req)
580 data_cb_num_req = 10;
581
582 rc = ping_mdm_data_cb_register(&reg_ret);
583 if (rc)
584 return rc;
585
586 pr_info("%s: data_cb_register result: 0x%x\n",
587 __func__, reg_ret.result);
588
589 while (!data_cb_done_flag) {
590 wait_event(data_cb_test_wait, data_cb_done_flag || fifo_event);
591 fifo_event = 0;
592
593 for (;;) {
594 mutex_lock(&event_fifo_lock);
595
596 if (kfifo_is_empty(&event_fifo)) {
597 mutex_unlock(&event_fifo_lock);
598 break;
599 }
600 rc = kfifo_out(&event_fifo, &event, sizeof(event));
601 mutex_unlock(&event_fifo_lock);
602 BUG_ON(rc != sizeof(event));
603
604 pr_info("%s: processing event data_cb_done_flag=%d,event=%d\n",
605 __func__, data_cb_done_flag, event);
606
607 if (event == PING_MODEM_IN_RESET) {
608 pr_info("%s: modem entering reset\n", __func__);
609 retry_count = 0;
610 } else if (event == PING_LEAVING_RESET) {
611 pr_info("%s: modem exiting reset - "
612 "re-registering cb\n", __func__);
613
614 rc = ping_mdm_data_cb_register(&reg_ret);
615 if (rc) {
616 retry_count++;
617 if (retry_count < PING_MAX_RETRY) {
618 pr_info("%s: retry %d failed\n",
619 __func__, retry_count);
620
621 retry_timer.expires = jiffies +
622 msecs_to_jiffies(1000);
623 retry_timer.data =
624 PING_LEAVING_RESET;
625 retry_timer.function =
626 retry_timer_cb;
627 add_timer(&retry_timer);
628 } else {
629 pr_err("%s: max retries exceeded, aborting\n",
630 __func__);
631 return -ENETRESET;
632 }
633 } else
634 pr_info("%s: data_cb_register result: 0x%x\n",
635 __func__, reg_ret.result);
636 }
637 }
638 }
639
640 while (del_timer(&retry_timer))
641 ;
642
643 unreg_arg.cb_func = ping_mdm_test_register_data_cb;
644 rc = ping_mdm_unregister_data_cb(rpc_client, &unreg_arg, &unreg_ret);
645 if (rc)
646 return rc;
647
648 pr_info("%s: data_cb_unregister result: 0x%x\n",
649 __func__, unreg_ret.result);
650
651 pr_info("%s: Test completed\n", __func__);
652
653 return 0;
654}
655
656static int ping_mdm_test_register_cb(
657 struct ping_mdm_register_cb_arg *arg, void *ret)
658{
659 pr_info("%s: received cb_id %d, val = %d\n",
660 __func__, arg->cb_id, arg->val);
661
662 reg_cb_num++;
663 if (reg_cb_num == reg_cb_num_req) {
664 reg_done_flag = 1;
665 wake_up(&reg_test_wait);
666 }
667 return 0;
668}
669
670static int ping_mdm_register_test(void)
671{
672 int rc = 0;
673 struct ping_mdm_register_arg reg_arg;
674 struct ping_mdm_unregister_arg unreg_arg;
675 struct ping_mdm_register_ret reg_ret;
676 struct ping_mdm_unregister_ret unreg_ret;
677
678 reg_cb_num = 0;
679 reg_cb_num_req = 10;
680 reg_done_flag = 0;
681
682 reg_arg.num = 10;
683 reg_arg.cb_func = ping_mdm_test_register_cb;
684
685 rc = ping_mdm_register(rpc_client, &reg_arg, &reg_ret);
686 if (rc)
687 return rc;
688
689 pr_info("%s: register result: 0x%x\n",
690 __func__, reg_ret.result);
691
692 wait_event(reg_test_wait, reg_done_flag);
693
694 unreg_arg.cb_func = ping_mdm_test_register_cb;
695 rc = ping_mdm_unregister(rpc_client, &unreg_arg, &unreg_ret);
696 if (rc)
697 return rc;
698
699 pr_info("%s: unregister result: 0x%x\n",
700 __func__, unreg_ret.result);
701
702 return 0;
703}
704
705static int ping_mdm_null_test(void)
706{
707 return ping_mdm_null(rpc_client, NULL, NULL);
708}
709
710static int ping_test_release(struct inode *ip, struct file *fp)
711{
712 return ping_mdm_close();
713}
714
715static int ping_test_open(struct inode *ip, struct file *fp)
716{
717 struct msm_rpc_client *client;
718
719 client = ping_mdm_init();
720 if (IS_ERR(client)) {
721 pr_err("%s: couldn't open ping client\n", __func__);
722 return PTR_ERR(client);
723 } else
724 pr_info("%s: connected to remote ping server\n",
725 __func__);
726
727 return 0;
728}
729
730static ssize_t ping_test_read(struct file *fp, char __user *buf,
731 size_t count, loff_t *pos)
732{
733 char _buf[16];
734
735 snprintf(_buf, sizeof(_buf), "%i\n", test_res);
736
737 return simple_read_from_buffer(buf, count, pos, _buf, strlen(_buf));
738}
739
740static ssize_t ping_test_write(struct file *fp, const char __user *buf,
741 size_t count, loff_t *pos)
742{
743 unsigned char cmd[64];
744 int len;
745
746 if (count < 1)
747 return 0;
748
749 len = count > 63 ? 63 : count;
750
751 if (copy_from_user(cmd, buf, len))
752 return -EFAULT;
753
754 cmd[len] = 0;
755
756 /* lazy */
757 if (cmd[len-1] == '\n') {
758 cmd[len-1] = 0;
759 len--;
760 }
761
762 if (!strncmp(cmd, "null_test", 64))
763 test_res = ping_mdm_null_test();
764 else if (!strncmp(cmd, "reg_test", 64))
765 test_res = ping_mdm_register_test();
766 else if (!strncmp(cmd, "data_reg_test", 64))
767 test_res = ping_mdm_data_register_test();
768 else if (!strncmp(cmd, "data_cb_reg_test", 64))
769 test_res = ping_mdm_data_cb_register_test();
770 else if (!strncmp(cmd, "count=", 6)) {
771 long tmp;
772
773 if (strict_strtol(cmd + 6, 0, &tmp) == 0) {
774 data_cb_num_req = tmp;
775 pr_info("Set repetition count to %d\n",
776 data_cb_num_req);
777 } else {
778 data_cb_num_req = 10;
779 pr_err("invalid number %s, defaulting to %d\n",
780 cmd + 6, data_cb_num_req);
781 }
782 }
783 else
784 test_res = -EINVAL;
785
786 return count;
787}
788
789static const struct file_operations debug_ops = {
790 .owner = THIS_MODULE,
791 .open = ping_test_open,
792 .read = ping_test_read,
793 .write = ping_test_write,
794 .release = ping_test_release,
795};
796
797static void __exit ping_test_exit(void)
798{
799 debugfs_remove(dent);
800}
801
802static int __init ping_test_init(void)
803{
804 dent = debugfs_create_file("ping_mdm", 0444, 0, NULL, &debug_ops);
805 test_res = 0;
806 open_count = 0;
807 return 0;
808}
809
810module_init(ping_test_init);
811module_exit(ping_test_exit);
812
813MODULE_DESCRIPTION("PING TEST Driver");
814MODULE_LICENSE("GPL v2");