blob: 653784614fddc9a82385c1e0076fd2053994175c [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 RPCROUTER CLIENTS module.
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/kthread.h>
22#include <linux/delay.h>
Steve Mucklef132c6c2012-06-06 18:30:57 -070023#include <linux/module.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070024
25#include <mach/msm_rpcrouter.h>
26#include "smd_rpcrouter.h"
27
28struct msm_rpc_client_cb_item {
29 struct list_head list;
30
31 void *buf;
32 int size;
33};
34
35struct msm_rpc_cb_table_item {
36 struct list_head list;
37
38 uint32_t cb_id;
39 void *cb_func;
40};
41
42static int rpc_clients_cb_thread(void *data)
43{
44 struct msm_rpc_client_cb_item *cb_item;
45 struct msm_rpc_client *client;
46 struct rpc_request_hdr req;
47 int ret;
48
49 client = data;
50 for (;;) {
51 wait_event(client->cb_wait, client->cb_avail);
52 if (client->exit_flag)
53 break;
54
55 client->cb_avail = 0;
56 mutex_lock(&client->cb_item_list_lock);
57 while (!list_empty(&client->cb_item_list)) {
58 cb_item = list_first_entry(
59 &client->cb_item_list,
60 struct msm_rpc_client_cb_item,
61 list);
62 list_del(&cb_item->list);
63 mutex_unlock(&client->cb_item_list_lock);
64 xdr_init_input(&client->cb_xdr, cb_item->buf,
65 cb_item->size);
66 ret = xdr_recv_req(&client->cb_xdr, &req);
67 if (ret)
68 goto bad_rpc;
69
70 if (req.type != 0)
71 goto bad_rpc;
72 if (req.rpc_vers != 2)
73 goto bad_rpc;
74 if (req.prog !=
75 (client->prog | 0x01000000))
76 goto bad_rpc;
77
78 if (client->version == 2)
79 client->cb_func2(client, &req, &client->cb_xdr);
80 else
81 client->cb_func(client, client->cb_xdr.in_buf,
82 client->cb_xdr.in_size);
83 bad_rpc:
84 xdr_clean_input(&client->cb_xdr);
85 kfree(cb_item);
86 mutex_lock(&client->cb_item_list_lock);
87 }
88 mutex_unlock(&client->cb_item_list_lock);
89 }
90 complete_and_exit(&client->cb_complete, 0);
91}
92
93static int rpc_clients_thread(void *data)
94{
95 void *buffer;
96 uint32_t type;
97 struct msm_rpc_client *client;
98 int rc = 0;
99 struct msm_rpc_client_cb_item *cb_item;
100 struct rpc_request_hdr req;
101
102 client = data;
103 for (;;) {
104 buffer = NULL;
105 rc = msm_rpc_read(client->ept, &buffer, -1, -1);
106
107 if (client->exit_flag) {
108 kfree(buffer);
109 break;
110 }
111
112 if (rc < 0) {
113 /* wakeup any pending requests */
114 wake_up(&client->reply_wait);
115 kfree(buffer);
116 continue;
117 }
118
119 if (rc < ((int)(sizeof(uint32_t) * 2))) {
120 kfree(buffer);
121 continue;
122 }
123
124 type = be32_to_cpu(*((uint32_t *)buffer + 1));
125 if (type == 1) {
126 xdr_init_input(&client->xdr, buffer, rc);
127 wake_up(&client->reply_wait);
128 } else if (type == 0) {
129 if (client->cb_thread == NULL) {
130 xdr_init_input(&client->cb_xdr, buffer, rc);
131 xdr_recv_req(&client->cb_xdr, &req);
132
133 if ((req.rpc_vers == 2) &&
134 (req.prog == (client->prog | 0x01000000))) {
135 if (client->version == 2)
136 client->cb_func2(client, &req,
137 &client->cb_xdr);
138 else
139 client->cb_func(client,
140 client->cb_xdr.in_buf, rc);
141 }
142 xdr_clean_input(&client->cb_xdr);
143 } else {
144 cb_item = kmalloc(sizeof(*cb_item), GFP_KERNEL);
145 if (!cb_item) {
146 pr_err("%s: no memory for cb item\n",
147 __func__);
148 continue;
149 }
150
151 INIT_LIST_HEAD(&cb_item->list);
152 cb_item->buf = buffer;
153 cb_item->size = rc;
154 mutex_lock(&client->cb_item_list_lock);
155 list_add_tail(&cb_item->list,
156 &client->cb_item_list);
157 mutex_unlock(&client->cb_item_list_lock);
158 client->cb_avail = 1;
159 wake_up(&client->cb_wait);
160 }
161 }
162 }
163 complete_and_exit(&client->complete, 0);
164}
165
166static struct msm_rpc_client *msm_rpc_create_client(void)
167{
168 struct msm_rpc_client *client;
169 void *buf;
170
171 client = kmalloc(sizeof(struct msm_rpc_client), GFP_KERNEL);
172 if (!client)
173 return ERR_PTR(-ENOMEM);
174
175 xdr_init(&client->xdr);
176 xdr_init(&client->cb_xdr);
177
178 buf = kmalloc(MSM_RPC_MSGSIZE_MAX, GFP_KERNEL);
179 if (!buf) {
180 kfree(client);
181 return ERR_PTR(-ENOMEM);
182 }
183 xdr_init_output(&client->xdr, buf, MSM_RPC_MSGSIZE_MAX);
184
185 buf = kmalloc(MSM_RPC_MSGSIZE_MAX, GFP_KERNEL);
186 if (!buf) {
187 xdr_clean_output(&client->xdr);
188 kfree(client);
189 return ERR_PTR(-ENOMEM);
190 }
191 xdr_init_output(&client->cb_xdr, buf, MSM_RPC_MSGSIZE_MAX);
192
193 init_waitqueue_head(&client->reply_wait);
194 mutex_init(&client->req_lock);
195 client->buf = NULL;
196 client->cb_buf = NULL;
197 client->cb_size = 0;
198 client->exit_flag = 0;
199 client->cb_restart_teardown = NULL;
200 client->cb_restart_setup = NULL;
201 client->in_reset = 0;
202
203 init_completion(&client->complete);
204 init_completion(&client->cb_complete);
205 INIT_LIST_HEAD(&client->cb_item_list);
206 mutex_init(&client->cb_item_list_lock);
207 client->cb_avail = 0;
208 init_waitqueue_head(&client->cb_wait);
209 INIT_LIST_HEAD(&client->cb_list);
Karthikeyan Ramasubramanianf23a2312011-08-23 10:27:32 -0600210 spin_lock_init(&client->cb_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700211 atomic_set(&client->next_cb_id, 1);
212
213 return client;
214}
215
216static void msm_rpc_destroy_client(struct msm_rpc_client *client)
217{
218 xdr_clean_output(&client->xdr);
219 xdr_clean_output(&client->cb_xdr);
220
221 kfree(client);
222}
223
224void msm_rpc_remove_all_cb_func(struct msm_rpc_client *client)
225{
226 struct msm_rpc_cb_table_item *cb_item, *tmp_cb_item;
Karthikeyan Ramasubramanianf23a2312011-08-23 10:27:32 -0600227 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700228
Karthikeyan Ramasubramanianf23a2312011-08-23 10:27:32 -0600229 spin_lock_irqsave(&client->cb_list_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700230 list_for_each_entry_safe(cb_item, tmp_cb_item,
231 &client->cb_list, list) {
232 list_del(&cb_item->list);
233 kfree(cb_item);
234 }
Karthikeyan Ramasubramanianf23a2312011-08-23 10:27:32 -0600235 spin_unlock_irqrestore(&client->cb_list_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700236}
237
238static void cb_restart_teardown(void *client_data)
239{
240 struct msm_rpc_client *client;
241
242 client = (struct msm_rpc_client *)client_data;
243 if (client) {
244 client->in_reset = 1;
245 msm_rpc_remove_all_cb_func(client);
246 client->xdr.out_index = 0;
247
248 if (client->cb_restart_teardown)
249 client->cb_restart_teardown(client);
250 }
251}
252
253static void cb_restart_setup(void *client_data)
254{
255 struct msm_rpc_client *client;
256
257 client = (struct msm_rpc_client *)client_data;
258
259 if (client) {
260 client->in_reset = 0;
261 if (client->cb_restart_setup)
262 client->cb_restart_setup(client);
263 }
264}
265
266/* Returns the reset state of the client.
267 *
268 * Return Value:
269 * 0 if client isn't in reset, >0 otherwise.
270 */
271int msm_rpc_client_in_reset(struct msm_rpc_client *client)
272{
273 int ret = 1;
274
275 if (client)
276 ret = client->in_reset;
277
278 return ret;
279}
280EXPORT_SYMBOL(msm_rpc_client_in_reset);
281
282/*
283 * Interface to be used to register the client.
284 *
285 * name: string representing the client
286 *
287 * prog: program number of the client
288 *
289 * ver: version number of the client
290 *
291 * create_cb_thread: if set calls the callback function from a seprate thread
292 * which helps the client requests to be processed without
293 * getting loaded by callback handling.
294 *
295 * cb_func: function to be called if callback request is received.
296 * unmarshaling should be handled by the user in callback function
297 *
298 * Return Value:
299 * Pointer to initialized client data sturcture
300 * Or, the error code if registration fails.
301 *
302 */
303struct msm_rpc_client *msm_rpc_register_client(
304 const char *name,
305 uint32_t prog, uint32_t ver,
306 uint32_t create_cb_thread,
307 int (*cb_func)(struct msm_rpc_client *, void *, int))
308{
309 struct msm_rpc_client *client;
310 struct msm_rpc_endpoint *ept;
311 int rc;
312
313 client = msm_rpc_create_client();
314 if (IS_ERR(client))
315 return client;
316
317 ept = msm_rpc_connect_compatible(prog, ver, MSM_RPC_UNINTERRUPTIBLE);
318 if (IS_ERR(ept)) {
319 msm_rpc_destroy_client(client);
320 return (struct msm_rpc_client *)ept;
321 }
322
323 ept->client_data = client;
324 ept->cb_restart_teardown = cb_restart_teardown;
325 ept->cb_restart_setup = cb_restart_setup;
326
327 client->prog = prog;
328 client->ver = ver;
329 client->ept = client->xdr.ept = client->cb_xdr.ept = ept;
330 client->cb_func = cb_func;
331 client->version = 1;
332
333 /* start the read thread */
334 client->read_thread = kthread_run(rpc_clients_thread, client,
335 "k%sclntd", name);
336 if (IS_ERR(client->read_thread)) {
337 rc = PTR_ERR(client->read_thread);
338 msm_rpc_close(client->ept);
339 msm_rpc_destroy_client(client);
340 return ERR_PTR(rc);
341 }
342
343 if (!create_cb_thread || (cb_func == NULL)) {
344 client->cb_thread = NULL;
345 return client;
346 }
347
348 /* start the callback thread */
349 client->cb_thread = kthread_run(rpc_clients_cb_thread, client,
350 "k%sclntcbd", name);
351 if (IS_ERR(client->cb_thread)) {
352 rc = PTR_ERR(client->cb_thread);
353 client->exit_flag = 1;
354 msm_rpc_read_wakeup(client->ept);
355 wait_for_completion(&client->complete);
356 msm_rpc_close(client->ept);
357 msm_rpc_destroy_client(client);
358 return ERR_PTR(rc);
359 }
360
361 return client;
362}
363EXPORT_SYMBOL(msm_rpc_register_client);
364
365/*
366 * Interface to be used to register the client.
367 *
368 * name: string representing the client
369 *
370 * prog: program number of the client
371 *
372 * ver: version number of the client
373 *
374 * create_cb_thread: if set calls the callback function from a seprate thread
375 * which helps the client requests to be processed without
376 * getting loaded by callback handling.
377 *
378 * cb_func: function to be called if callback request is received.
379 * unmarshaling should be handled by the user in callback function
380 *
381 * Return Value:
382 * Pointer to initialized client data sturcture
383 * Or, the error code if registration fails.
384 *
385 */
386struct msm_rpc_client *msm_rpc_register_client2(
387 const char *name,
388 uint32_t prog, uint32_t ver,
389 uint32_t create_cb_thread,
390 int (*cb_func)(struct msm_rpc_client *,
391 struct rpc_request_hdr *req, struct msm_rpc_xdr *))
392{
393 struct msm_rpc_client *client;
394 struct msm_rpc_endpoint *ept;
395 int rc;
396
397 client = msm_rpc_create_client();
398 if (IS_ERR(client))
399 return client;
400
401 ept = msm_rpc_connect_compatible(prog, ver, MSM_RPC_UNINTERRUPTIBLE);
402 if (IS_ERR(ept)) {
403 msm_rpc_destroy_client(client);
404 return (struct msm_rpc_client *)ept;
405 }
406
407 client->prog = prog;
408 client->ver = ver;
409 client->ept = client->xdr.ept = client->cb_xdr.ept = ept;
410 client->cb_func2 = cb_func;
411 client->version = 2;
412
413 ept->client_data = client;
414 ept->cb_restart_teardown = cb_restart_teardown;
415 ept->cb_restart_setup = cb_restart_setup;
416
417 /* start the read thread */
418 client->read_thread = kthread_run(rpc_clients_thread, client,
419 "k%sclntd", name);
420 if (IS_ERR(client->read_thread)) {
421 rc = PTR_ERR(client->read_thread);
422 msm_rpc_close(client->ept);
423 msm_rpc_destroy_client(client);
424 return ERR_PTR(rc);
425 }
426
427 if (!create_cb_thread || (cb_func == NULL)) {
428 client->cb_thread = NULL;
429 return client;
430 }
431
432 /* start the callback thread */
433 client->cb_thread = kthread_run(rpc_clients_cb_thread, client,
434 "k%sclntcbd", name);
435 if (IS_ERR(client->cb_thread)) {
436 rc = PTR_ERR(client->cb_thread);
437 client->exit_flag = 1;
438 msm_rpc_read_wakeup(client->ept);
439 wait_for_completion(&client->complete);
440 msm_rpc_close(client->ept);
441 msm_rpc_destroy_client(client);
442 return ERR_PTR(rc);
443 }
444
445 return client;
446}
447EXPORT_SYMBOL(msm_rpc_register_client2);
448
449/*
450 * Register callbacks for modem state changes.
451 *
452 * Teardown is called when the modem is going into reset.
453 * Setup is called after the modem has come out of reset (but may not
454 * be available, yet).
455 *
456 * client: pointer to client data structure.
457 *
458 * Return Value:
459 * 0 (success)
460 * 1 (client pointer invalid)
461 */
462int msm_rpc_register_reset_callbacks(
463 struct msm_rpc_client *client,
464 void (*teardown)(struct msm_rpc_client *client),
465 void (*setup)(struct msm_rpc_client *client)
466 )
467{
468 int rc = 1;
469
470 if (client) {
471 client->cb_restart_teardown = teardown;
472 client->cb_restart_setup = setup;
473 rc = 0;
474 }
475
476 return rc;
477}
478EXPORT_SYMBOL(msm_rpc_register_reset_callbacks);
479
480/*
481 * Interface to be used to unregister the client
482 * No client operations should be done once the unregister function
483 * is called.
484 *
485 * client: pointer to client data structure.
486 *
487 * Return Value:
488 * Always returns 0 (success).
489 */
490int msm_rpc_unregister_client(struct msm_rpc_client *client)
491{
492 pr_info("%s: stopping client...\n", __func__);
493 client->exit_flag = 1;
494 if (client->cb_thread) {
495 client->cb_avail = 1;
496 wake_up(&client->cb_wait);
497 wait_for_completion(&client->cb_complete);
498 }
499
500 msm_rpc_read_wakeup(client->ept);
501 wait_for_completion(&client->complete);
502
503 msm_rpc_close(client->ept);
504 msm_rpc_remove_all_cb_func(client);
505 xdr_clean_output(&client->xdr);
506 xdr_clean_output(&client->cb_xdr);
507 kfree(client);
508 return 0;
509}
510EXPORT_SYMBOL(msm_rpc_unregister_client);
511
512/*
513 * Interface to be used to send a client request.
514 * If the request takes any arguments or expects any return, the user
515 * should handle it in 'arg_func' and 'ret_func' respectively.
516 * Marshaling and Unmarshaling should be handled by the user in argument
517 * and return functions.
518 *
519 * client: pointer to client data sturcture
520 *
521 * proc: procedure being requested
522 *
523 * arg_func: argument function pointer. 'buf' is where arguments needs to
524 * be filled. 'data' is arg_data.
525 *
526 * ret_func: return function pointer. 'buf' is where returned data should
527 * be read from. 'data' is ret_data.
528 *
529 * arg_data: passed as an input parameter to argument function.
530 *
531 * ret_data: passed as an input parameter to return function.
532 *
533 * timeout: timeout for reply wait in jiffies. If negative timeout is
534 * specified a default timeout of 10s is used.
535 *
536 * Return Value:
537 * 0 on success, otherwise an error code is returned.
538 */
539int msm_rpc_client_req(struct msm_rpc_client *client, uint32_t proc,
540 int (*arg_func)(struct msm_rpc_client *client,
541 void *buf, void *data),
542 void *arg_data,
543 int (*ret_func)(struct msm_rpc_client *client,
544 void *buf, void *data),
545 void *ret_data, long timeout)
546{
547 struct rpc_reply_hdr *rpc_rsp;
548 int rc = 0;
549 uint32_t req_xid;
550
551 mutex_lock(&client->req_lock);
552
553 msm_rpc_setup_req((struct rpc_request_hdr *)client->xdr.out_buf,
554 client->prog, client->ver, proc);
555 client->xdr.out_index = sizeof(struct rpc_request_hdr);
556 req_xid = *(uint32_t *)client->xdr.out_buf;
557 if (arg_func) {
558 rc = arg_func(client,
559 (void *)((struct rpc_request_hdr *)
560 client->xdr.out_buf + 1),
561 arg_data);
562 if (rc < 0)
563 goto release_locks;
564 else
565 client->xdr.out_index += rc;
566 }
567
568 rc = msm_rpc_write(client->ept, client->xdr.out_buf,
569 client->xdr.out_index);
570 if (rc < 0) {
571 pr_err("%s: couldn't send RPC request:%d\n", __func__, rc);
572 goto release_locks;
573 } else
574 rc = 0;
575
576 if (timeout < 0)
577 timeout = msecs_to_jiffies(10000);
578
579 do {
580 rc = wait_event_timeout(client->reply_wait,
581 xdr_read_avail(&client->xdr) || client->in_reset,
582 timeout);
583
584 if (client->in_reset) {
585 rc = -ENETRESET;
586 goto release_locks;
587 }
588
589 if (rc == 0) {
590 pr_err("%s: request timeout\n", __func__);
591 rc = -ETIMEDOUT;
592 goto release_locks;
593 }
594
595 rpc_rsp = (struct rpc_reply_hdr *)client->xdr.in_buf;
596 if (req_xid != rpc_rsp->xid) {
597 pr_info("%s: xid mismatch, req %d reply %d\n",
598 __func__, be32_to_cpu(req_xid),
599 be32_to_cpu(rpc_rsp->xid));
600 timeout = rc;
601 xdr_clean_input(&client->xdr);
602 } else
603 rc = 0;
604 } while (rc);
605
606 if (be32_to_cpu(rpc_rsp->reply_stat) != RPCMSG_REPLYSTAT_ACCEPTED) {
607 pr_err("%s: RPC call was denied! %d\n", __func__,
608 be32_to_cpu(rpc_rsp->reply_stat));
609 rc = -EPERM;
610 goto free_and_release;
611 }
612
613 if (be32_to_cpu(rpc_rsp->data.acc_hdr.accept_stat) !=
614 RPC_ACCEPTSTAT_SUCCESS) {
615 pr_err("%s: RPC call was not successful (%d)\n", __func__,
616 be32_to_cpu(rpc_rsp->data.acc_hdr.accept_stat));
617 rc = -EINVAL;
618 goto free_and_release;
619 }
620
621 if (ret_func)
622 rc = ret_func(client, (void *)(rpc_rsp + 1), ret_data);
623
624 free_and_release:
625 xdr_clean_input(&client->xdr);
626 client->xdr.out_index = 0;
627 release_locks:
628 mutex_unlock(&client->req_lock);
629 return rc;
630}
631EXPORT_SYMBOL(msm_rpc_client_req);
632
633/*
634 * Interface to be used to send a client request.
635 * If the request takes any arguments or expects any return, the user
636 * should handle it in 'arg_func' and 'ret_func' respectively.
637 * Marshaling and Unmarshaling should be handled by the user in argument
638 * and return functions.
639 *
640 * client: pointer to client data sturcture
641 *
642 * proc: procedure being requested
643 *
644 * arg_func: argument function pointer. 'xdr' is the xdr being used.
645 * 'data' is arg_data.
646 *
647 * ret_func: return function pointer. 'xdr' is the xdr being used.
648 * 'data' is ret_data.
649 *
650 * arg_data: passed as an input parameter to argument function.
651 *
652 * ret_data: passed as an input parameter to return function.
653 *
654 * timeout: timeout for reply wait in jiffies. If negative timeout is
655 * specified a default timeout of 10s is used.
656 *
657 * Return Value:
658 * 0 on success, otherwise an error code is returned.
659 */
660int msm_rpc_client_req2(struct msm_rpc_client *client, uint32_t proc,
661 int (*arg_func)(struct msm_rpc_client *client,
662 struct msm_rpc_xdr *xdr, void *data),
663 void *arg_data,
664 int (*ret_func)(struct msm_rpc_client *client,
665 struct msm_rpc_xdr *xdr, void *data),
666 void *ret_data, long timeout)
667{
668 struct rpc_reply_hdr rpc_rsp;
669 int rc = 0;
670 uint32_t req_xid;
671
672 mutex_lock(&client->req_lock);
673
674 if (client->in_reset) {
675 rc = -ENETRESET;
676 goto release_locks;
677 }
678
679 xdr_start_request(&client->xdr, client->prog, client->ver, proc);
680 req_xid = be32_to_cpu(*(uint32_t *)client->xdr.out_buf);
681 if (arg_func) {
682 rc = arg_func(client, &client->xdr, arg_data);
683 if (rc < 0) {
684 mutex_unlock(&client->xdr.out_lock);
685 goto release_locks;
686 }
687 }
688
689 rc = xdr_send_msg(&client->xdr);
690 if (rc < 0) {
691 pr_err("%s: couldn't send RPC request:%d\n", __func__, rc);
692 goto release_locks;
693 } else
694 rc = 0;
695
696 if (timeout < 0)
697 timeout = msecs_to_jiffies(10000);
698
699 do {
700 rc = wait_event_timeout(client->reply_wait,
701 xdr_read_avail(&client->xdr) || client->in_reset,
702 timeout);
703
704 if (client->in_reset) {
705 rc = -ENETRESET;
706 goto release_locks;
707 }
708
709 if (rc == 0) {
710 pr_err("%s: request timeout\n", __func__);
711 rc = -ETIMEDOUT;
712 goto release_locks;
713 }
714
715 xdr_recv_reply(&client->xdr, &rpc_rsp);
716 /* TODO: may be this check should be a xdr function */
717 if (req_xid != rpc_rsp.xid) {
718 pr_info("%s: xid mismatch, req %d reply %d\n",
719 __func__, req_xid, rpc_rsp.xid);
720 timeout = rc;
721 xdr_clean_input(&client->xdr);
722 } else
723 rc = 0;
724 } while (rc);
725
726 if (rpc_rsp.reply_stat != RPCMSG_REPLYSTAT_ACCEPTED) {
727 pr_err("%s: RPC call was denied! %d\n",
728 __func__, rpc_rsp.reply_stat);
729 rc = -EPERM;
730 goto free_and_release;
731 }
732
733 if (rpc_rsp.data.acc_hdr.accept_stat != RPC_ACCEPTSTAT_SUCCESS) {
734 pr_err("%s: RPC call was not successful (%d)\n", __func__,
735 rpc_rsp.data.acc_hdr.accept_stat);
736 rc = -EINVAL;
737 goto free_and_release;
738 }
739
740 if (ret_func)
741 rc = ret_func(client, &client->xdr, ret_data);
742
743 free_and_release:
744 xdr_clean_input(&client->xdr);
745 /* TODO: put it in xdr_reset_output */
746 client->xdr.out_index = 0;
747 release_locks:
748 mutex_unlock(&client->req_lock);
749 return rc;
750}
751EXPORT_SYMBOL(msm_rpc_client_req2);
752
753/*
754 * Interface to be used to start accepted reply message required in
755 * callback handling. Returns the buffer pointer to attach any
756 * payload. Should call msm_rpc_send_accepted_reply to complete
757 * sending reply. Marshaling should be handled by user for the payload.
758 *
759 * client: pointer to client data structure
760 *
761 * xid: transaction id. Has to be same as the one in callback request.
762 *
763 * accept_status: acceptance status
764 *
765 * Return Value:
766 * pointer to buffer to attach the payload.
767 */
768void *msm_rpc_start_accepted_reply(struct msm_rpc_client *client,
769 uint32_t xid, uint32_t accept_status)
770{
771 struct rpc_reply_hdr *reply;
772
773 mutex_lock(&client->cb_xdr.out_lock);
774
775 reply = (struct rpc_reply_hdr *)client->cb_xdr.out_buf;
776
777 reply->xid = cpu_to_be32(xid);
778 reply->type = cpu_to_be32(1); /* reply */
779 reply->reply_stat = cpu_to_be32(RPCMSG_REPLYSTAT_ACCEPTED);
780
781 reply->data.acc_hdr.accept_stat = cpu_to_be32(accept_status);
782 reply->data.acc_hdr.verf_flavor = 0;
783 reply->data.acc_hdr.verf_length = 0;
784
785 client->cb_xdr.out_index = sizeof(*reply);
786 return reply + 1;
787}
788EXPORT_SYMBOL(msm_rpc_start_accepted_reply);
789
790/*
791 * Interface to be used to send accepted reply required in callback handling.
792 * msm_rpc_start_accepted_reply should have been called before.
793 * Marshaling should be handled by user for the payload.
794 *
795 * client: pointer to client data structure
796 *
797 * size: additional payload size
798 *
799 * Return Value:
800 * 0 on success, otherwise returns an error code.
801 */
802int msm_rpc_send_accepted_reply(struct msm_rpc_client *client, uint32_t size)
803{
804 int rc = 0;
805
806 client->cb_xdr.out_index += size;
807 rc = msm_rpc_write(client->ept, client->cb_xdr.out_buf,
808 client->cb_xdr.out_index);
809 if (rc > 0)
810 rc = 0;
811
812 mutex_unlock(&client->cb_xdr.out_lock);
813 return rc;
814}
815EXPORT_SYMBOL(msm_rpc_send_accepted_reply);
816
817/*
818 * Interface to be used to add a callback function.
819 * If the call back function is already in client's 'cb_id - cb_func'
820 * table, then that cb_id is returned. otherwise, new entry
821 * is added to the above table and corresponding cb_id is returned.
822 *
823 * client: pointer to client data structure
824 *
825 * cb_func: callback function
826 *
827 * Return Value:
828 * callback ID on success, otherwise returns an error code.
829 * If cb_func is NULL, the callback Id returned is 0xffffffff.
830 * This tells the other processor that no callback is reqested.
831 */
832int msm_rpc_add_cb_func(struct msm_rpc_client *client, void *cb_func)
833{
834 struct msm_rpc_cb_table_item *cb_item;
Karthikeyan Ramasubramanianf23a2312011-08-23 10:27:32 -0600835 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700836
837 if (cb_func == NULL)
838 return MSM_RPC_CLIENT_NULL_CB_ID;
839
Karthikeyan Ramasubramanianf23a2312011-08-23 10:27:32 -0600840 spin_lock_irqsave(&client->cb_list_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700841 list_for_each_entry(cb_item, &client->cb_list, list) {
842 if (cb_item->cb_func == cb_func) {
Karthikeyan Ramasubramanianf23a2312011-08-23 10:27:32 -0600843 spin_unlock_irqrestore(&client->cb_list_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700844 return cb_item->cb_id;
845 }
846 }
Karthikeyan Ramasubramanianf23a2312011-08-23 10:27:32 -0600847 spin_unlock_irqrestore(&client->cb_list_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700848
849 cb_item = kmalloc(sizeof(struct msm_rpc_cb_table_item), GFP_KERNEL);
850 if (!cb_item)
851 return -ENOMEM;
852
853 INIT_LIST_HEAD(&cb_item->list);
854 cb_item->cb_id = atomic_add_return(1, &client->next_cb_id);
855 cb_item->cb_func = cb_func;
856
Karthikeyan Ramasubramanianf23a2312011-08-23 10:27:32 -0600857 spin_lock_irqsave(&client->cb_list_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700858 list_add_tail(&cb_item->list, &client->cb_list);
Karthikeyan Ramasubramanianf23a2312011-08-23 10:27:32 -0600859 spin_unlock_irqrestore(&client->cb_list_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700860
861 return cb_item->cb_id;
862}
863EXPORT_SYMBOL(msm_rpc_add_cb_func);
864
865/*
866 * Interface to be used to get a callback function from a callback ID.
867 * If no entry is found, NULL is returned.
868 *
869 * client: pointer to client data structure
870 *
871 * cb_id: callback ID
872 *
873 * Return Value:
874 * callback function pointer if entry with given cb_id is found,
875 * otherwise returns NULL.
876 */
877void *msm_rpc_get_cb_func(struct msm_rpc_client *client, uint32_t cb_id)
878{
879 struct msm_rpc_cb_table_item *cb_item;
Karthikeyan Ramasubramanianf23a2312011-08-23 10:27:32 -0600880 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700881
Karthikeyan Ramasubramanianf23a2312011-08-23 10:27:32 -0600882 spin_lock_irqsave(&client->cb_list_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700883 list_for_each_entry(cb_item, &client->cb_list, list) {
884 if (cb_item->cb_id == cb_id) {
Karthikeyan Ramasubramanianf23a2312011-08-23 10:27:32 -0600885 spin_unlock_irqrestore(&client->cb_list_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700886 return cb_item->cb_func;
887 }
888 }
Karthikeyan Ramasubramanianf23a2312011-08-23 10:27:32 -0600889 spin_unlock_irqrestore(&client->cb_list_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700890 return NULL;
891}
892EXPORT_SYMBOL(msm_rpc_get_cb_func);
893
894/*
895 * Interface to be used to remove a callback function.
896 *
897 * client: pointer to client data structure
898 *
899 * cb_func: callback function
900 *
901 */
902void msm_rpc_remove_cb_func(struct msm_rpc_client *client, void *cb_func)
903{
904 struct msm_rpc_cb_table_item *cb_item, *tmp_cb_item;
Karthikeyan Ramasubramanianf23a2312011-08-23 10:27:32 -0600905 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700906
907 if (cb_func == NULL)
908 return;
909
Karthikeyan Ramasubramanianf23a2312011-08-23 10:27:32 -0600910 spin_lock_irqsave(&client->cb_list_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700911 list_for_each_entry_safe(cb_item, tmp_cb_item,
912 &client->cb_list, list) {
913 if (cb_item->cb_func == cb_func) {
914 list_del(&cb_item->list);
915 kfree(cb_item);
Karthikeyan Ramasubramanianf23a2312011-08-23 10:27:32 -0600916 spin_unlock_irqrestore(&client->cb_list_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700917 return;
918 }
919 }
Karthikeyan Ramasubramanianf23a2312011-08-23 10:27:32 -0600920 spin_unlock_irqrestore(&client->cb_list_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700921}
922EXPORT_SYMBOL(msm_rpc_remove_cb_func);