blob: 74dfe37cd3e492f23ba8498d4cb7dfb3754e06fa [file] [log] [blame]
Duy Truong790f06d2013-02-13 16:38:12 -08001/* Copyright (c) 2008-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 * Device access library (DAL) implementation.
15 */
16
17#include <linux/kernel.h>
18#include <linux/completion.h>
19#include <linux/list.h>
20#include <linux/module.h>
21#include <linux/slab.h>
22#include <linux/workqueue.h>
23#include <linux/wait.h>
24#include <linux/sched.h>
25#include <linux/semaphore.h>
26
27#include <mach/dal.h>
28#include <mach/msm_smd.h>
29
30#define DALRPC_PROTOCOL_VERSION 0x11
31#define DALRPC_SUCCESS 0
32#define DALRPC_MAX_PORTNAME_LEN 64
33#define DALRPC_MAX_ATTACH_PARAM_LEN 64
34#define DALRPC_MAX_SERVICE_NAME_LEN 32
35#define DALRPC_MAX_PARAMS 128
36#define DALRPC_MAX_PARAMS_SIZE (DALRPC_MAX_PARAMS * 4)
37#define DALRPC_MAX_MSG_SIZE (sizeof(struct dalrpc_msg_hdr) + \
38 DALRPC_MAX_PARAMS_SIZE)
39#define DALRPC_MSGID_DDI 0x0
40#define DALRPC_MSGID_DDI_REPLY 0x80
41#define DALRPC_MSGID_ATTACH_REPLY 0x81
42#define DALRPC_MSGID_DETACH_REPLY 0x82
43#define DALRPC_MSGID_ASYNCH 0xC0
44#define ROUND_BUFLEN(x) (((x + 3) & ~0x3))
45
46struct dalrpc_msg_hdr {
47 uint32_t len:16;
48 uint32_t proto_ver:8;
49 uint32_t prio:7;
50 uint32_t async:1;
51 uint32_t ddi_idx:16;
52 uint32_t proto_id:8;
53 uint32_t msgid:8;
54 void *from;
55 void *to;
56};
57
58struct dalrpc_msg {
59 struct dalrpc_msg_hdr hdr;
60 uint32_t param[DALRPC_MAX_PARAMS];
61};
62
63struct dalrpc_event_handle {
64 struct list_head list;
65
66 int flag;
67 spinlock_t lock;
68};
69
70struct dalrpc_cb_handle {
71 struct list_head list;
72
73 void (*fn)(void *, uint32_t, void *, uint32_t);
74 void *context;
75};
76
77struct daldevice_handle {;
78 struct list_head list;
79
80 void *remote_handle;
81 struct completion read_completion;
82 struct dalrpc_port *port;
83 struct dalrpc_msg msg;
84 struct mutex client_lock;
85};
86
87struct dalrpc_port {
88 struct list_head list;
89
90 char port[DALRPC_MAX_PORTNAME_LEN+1];
91 int refcount;
92
93 struct workqueue_struct *wq;
94 struct work_struct port_work;
95 struct mutex write_lock;
96
97 smd_channel_t *ch;
98
99 struct dalrpc_msg msg_in;
100 struct daldevice_handle *msg_owner;
101 unsigned msg_bytes_read;
102
103 struct list_head event_list;
104 struct mutex event_list_lock;
105
106 struct list_head cb_list;
107 struct mutex cb_list_lock;
108};
109
110static LIST_HEAD(port_list);
111static LIST_HEAD(client_list);
112static DEFINE_MUTEX(pc_lists_lock);
113
114static DECLARE_WAIT_QUEUE_HEAD(event_wq);
115
116static int client_exists(void *handle)
117{
118 struct daldevice_handle *h;
119
120 if (!handle)
121 return 0;
122
123 mutex_lock(&pc_lists_lock);
124
125 list_for_each_entry(h, &client_list, list)
126 if (h == handle) {
127 mutex_unlock(&pc_lists_lock);
128 return 1;
129 }
130
131 mutex_unlock(&pc_lists_lock);
132
133 return 0;
134}
135
136static int client_exists_locked(void *handle)
137{
138 struct daldevice_handle *h;
139
140 /* this function must be called with pc_lists_lock acquired */
141
142 if (!handle)
143 return 0;
144
145 list_for_each_entry(h, &client_list, list)
146 if (h == handle)
147 return 1;
148
149 return 0;
150}
151
152static int port_exists(struct dalrpc_port *p)
153{
154 struct dalrpc_port *p_iter;
155
156 /* this function must be called with pc_lists_lock acquired */
157
158 if (!p)
159 return 0;
160
161 list_for_each_entry(p_iter, &port_list, list)
162 if (p_iter == p)
163 return 1;
164
165 return 0;
166}
167
168static struct dalrpc_port *port_name_exists(char *port)
169{
170 struct dalrpc_port *p;
171
172 /* this function must be called with pc_lists_lock acquired */
173
174 list_for_each_entry(p, &port_list, list)
175 if (!strcmp(p->port, port))
176 return p;
177
178 return NULL;
179}
180
181static void port_close(struct dalrpc_port *p)
182{
183 mutex_lock(&pc_lists_lock);
184
185 p->refcount--;
186 if (p->refcount == 0)
187 list_del(&p->list);
188
189 mutex_unlock(&pc_lists_lock);
190
191 if (p->refcount == 0) {
192 destroy_workqueue(p->wq);
193 smd_close(p->ch);
194 kfree(p);
195 }
196}
197
198static int event_exists(struct dalrpc_port *p,
199 struct dalrpc_event_handle *ev)
200{
201 struct dalrpc_event_handle *ev_iter;
202
203 /* this function must be called with event_list_lock acquired */
204
205 list_for_each_entry(ev_iter, &p->event_list, list)
206 if (ev_iter == ev)
207 return 1;
208
209 return 0;
210}
211
212static int cb_exists(struct dalrpc_port *p,
213 struct dalrpc_cb_handle *cb)
214{
215 struct dalrpc_cb_handle *cb_iter;
216
217 /* this function must be called with the cb_list_lock acquired */
218
219 list_for_each_entry(cb_iter, &p->cb_list, list)
220 if (cb_iter == cb)
221 return 1;
222
223 return 0;
224}
225
226static int check_version(struct dalrpc_msg_hdr *msg_hdr)
227{
228 static int version_msg = 1;
229
230 /* disabled because asynch events currently have no version */
231 return 0;
232
233 if (msg_hdr->proto_ver != DALRPC_PROTOCOL_VERSION) {
234 if (version_msg) {
235 printk(KERN_ERR "dalrpc: incompatible verison\n");
236 version_msg = 0;
237 }
238 return -1;
239 }
240 return 0;
241}
242
243static void process_asynch(struct dalrpc_port *p)
244{
245 struct dalrpc_event_handle *ev;
246 struct dalrpc_cb_handle *cb;
247
248 ev = (struct dalrpc_event_handle *)p->msg_in.param[0];
249 cb = (struct dalrpc_cb_handle *)p->msg_in.param[0];
250
251 mutex_lock(&p->event_list_lock);
252 if (event_exists(p, ev)) {
253 spin_lock(&ev->lock);
254 ev->flag = 1;
255 spin_unlock(&ev->lock);
256 smp_mb();
257 wake_up_all(&event_wq);
258 mutex_unlock(&p->event_list_lock);
259 return;
260 }
261 mutex_unlock(&p->event_list_lock);
262
263 mutex_lock(&p->cb_list_lock);
264 if (cb_exists(p, cb)) {
265 cb->fn(cb->context, p->msg_in.param[1],
266 &p->msg_in.param[3], p->msg_in.param[2]);
267 mutex_unlock(&p->cb_list_lock);
268 return;
269 }
270 mutex_unlock(&p->cb_list_lock);
271}
272
273static void process_msg(struct dalrpc_port *p)
274{
275 switch (p->msg_in.hdr.msgid) {
276
277 case DALRPC_MSGID_DDI_REPLY:
278 case DALRPC_MSGID_ATTACH_REPLY:
279 case DALRPC_MSGID_DETACH_REPLY:
280 complete(&p->msg_owner->read_completion);
281 break;
282
283 case DALRPC_MSGID_ASYNCH:
284 process_asynch(p);
285 break;
286
287 default:
288 printk(KERN_ERR "process_msg: bad msgid %#x\n",
289 p->msg_in.hdr.msgid);
290 }
291}
292
293static void flush_msg(struct dalrpc_port *p)
294{
295 int bytes_read, len;
296
297 len = p->msg_in.hdr.len - sizeof(struct dalrpc_msg_hdr);
298 while (len > 0) {
299 bytes_read = smd_read(p->ch, NULL, len);
300 if (bytes_read <= 0)
301 break;
302 len -= bytes_read;
303 }
304 p->msg_bytes_read = 0;
305}
306
307static int check_header(struct dalrpc_port *p)
308{
309 if (check_version(&p->msg_in.hdr) ||
310 p->msg_in.hdr.len > DALRPC_MAX_MSG_SIZE ||
311 (p->msg_in.hdr.msgid != DALRPC_MSGID_ASYNCH &&
312 !client_exists_locked(p->msg_in.hdr.to))) {
313 printk(KERN_ERR "dalrpc_read_msg: bad msg\n");
314 flush_msg(p);
315 return 1;
316 }
317 p->msg_owner = (struct daldevice_handle *)p->msg_in.hdr.to;
318
319 if (p->msg_in.hdr.msgid != DALRPC_MSGID_ASYNCH)
320 memcpy(&p->msg_owner->msg.hdr, &p->msg_in.hdr,
321 sizeof(p->msg_in.hdr));
322
323 return 0;
324}
325
326static int dalrpc_read_msg(struct dalrpc_port *p)
327{
328 uint8_t *read_ptr;
329 int bytes_read;
330
331 /* read msg header */
332 while (p->msg_bytes_read < sizeof(p->msg_in.hdr)) {
333 read_ptr = (uint8_t *)&p->msg_in.hdr + p->msg_bytes_read;
334
335 bytes_read = smd_read(p->ch, read_ptr,
336 sizeof(p->msg_in.hdr) -
337 p->msg_bytes_read);
338 if (bytes_read <= 0)
339 return 0;
340 p->msg_bytes_read += bytes_read;
341
342 if (p->msg_bytes_read == sizeof(p->msg_in.hdr) &&
343 check_header(p))
344 return 1;
345 }
346
347 /* read remainder of msg */
348 if (p->msg_in.hdr.msgid != DALRPC_MSGID_ASYNCH)
349 read_ptr = (uint8_t *)&p->msg_owner->msg;
350 else
351 read_ptr = (uint8_t *)&p->msg_in;
352 read_ptr += p->msg_bytes_read;
353
354 while (p->msg_bytes_read < p->msg_in.hdr.len) {
355 bytes_read = smd_read(p->ch, read_ptr,
356 p->msg_in.hdr.len - p->msg_bytes_read);
357 if (bytes_read <= 0)
358 return 0;
359 p->msg_bytes_read += bytes_read;
360 read_ptr += bytes_read;
361 }
362
363 process_msg(p);
364 p->msg_bytes_read = 0;
365 p->msg_owner = NULL;
366
367 return 1;
368}
369
370static void dalrpc_work(struct work_struct *work)
371{
372 struct dalrpc_port *p = container_of(work,
373 struct dalrpc_port,
374 port_work);
375
376 /* must lock port/client lists to ensure port doesn't disappear
377 under an asynch event */
378 mutex_lock(&pc_lists_lock);
379 if (port_exists(p))
380 while (dalrpc_read_msg(p))
381 ;
382 mutex_unlock(&pc_lists_lock);
383}
384
385static void dalrpc_smd_cb(void *priv, unsigned smd_flags)
386{
387 struct dalrpc_port *p = priv;
388
389 if (smd_flags != SMD_EVENT_DATA)
390 return;
391
392 queue_work(p->wq, &p->port_work);
393}
394
395static struct dalrpc_port *dalrpc_port_open(char *port, int cpu)
396{
397 struct dalrpc_port *p;
398 char wq_name[32];
399
400 p = port_name_exists(port);
401 if (p) {
402 p->refcount++;
403 return p;
404 }
405
406 p = kzalloc(sizeof(struct dalrpc_port), GFP_KERNEL);
407 if (!p)
408 return NULL;
409
Swaminathan Sathappanec6906d2011-10-26 13:36:00 -0700410 strlcpy(p->port, port, sizeof(p->port));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700411 p->refcount = 1;
412
413 snprintf(wq_name, sizeof(wq_name), "dalrpc_rcv_%s", port);
414 p->wq = create_singlethread_workqueue(wq_name);
415 if (!p->wq) {
416 printk(KERN_ERR "dalrpc_init: unable to create workqueue\n");
417 goto no_wq;
418 }
419 INIT_WORK(&p->port_work, dalrpc_work);
420
421 mutex_init(&p->write_lock);
422 mutex_init(&p->event_list_lock);
423 mutex_init(&p->cb_list_lock);
424
425 INIT_LIST_HEAD(&p->event_list);
426 INIT_LIST_HEAD(&p->cb_list);
427
428 p->msg_owner = NULL;
429 p->msg_bytes_read = 0;
430
431 if (smd_named_open_on_edge(port, cpu, &p->ch, p,
432 dalrpc_smd_cb)) {
433 printk(KERN_ERR "dalrpc_port_init() failed to open port\n");
434 goto no_smd;
435 }
436
437 list_add(&p->list, &port_list);
438
439 return p;
440
441no_smd:
442 destroy_workqueue(p->wq);
443no_wq:
444 kfree(p);
445 return NULL;
446}
447
448static void dalrpc_sendwait(struct daldevice_handle *h)
449{
450 u8 *buf = (u8 *)&h->msg;
451 int len = h->msg.hdr.len;
452 int written;
453
454 mutex_lock(&h->port->write_lock);
455 do {
456 written = smd_write(h->port->ch, buf + (h->msg.hdr.len - len),
457 len);
458 if (written < 0)
459 break;
460 len -= written;
461 } while (len);
462 mutex_unlock(&h->port->write_lock);
463
464 if (!h->msg.hdr.async)
465 wait_for_completion(&h->read_completion);
466}
467
468int daldevice_attach(uint32_t device_id, char *port, int cpu,
469 void **handle_ptr)
470{
471 struct daldevice_handle *h;
472 char dyn_port[DALRPC_MAX_PORTNAME_LEN + 1] = "DAL00";
473 int ret;
474 int tries = 0;
475
476 if (!port)
477 port = dyn_port;
478
479 if (strlen(port) > DALRPC_MAX_PORTNAME_LEN)
480 return -EINVAL;
481
482 h = kzalloc(sizeof(struct daldevice_handle), GFP_KERNEL);
483 if (!h) {
484 *handle_ptr = NULL;
485 return -ENOMEM;
486 }
487
488 init_completion(&h->read_completion);
489 mutex_init(&h->client_lock);
490
491 mutex_lock(&pc_lists_lock);
492 list_add(&h->list, &client_list);
493 mutex_unlock(&pc_lists_lock);
494
495 /* 3 attempts, enough for one each on the user specified port, the
496 * dynamic discovery port, and the port recommended by the dynamic
497 * discovery port */
498 while (tries < 3) {
499 tries++;
500
501 mutex_lock(&pc_lists_lock);
502 h->port = dalrpc_port_open(port, cpu);
503 if (!h->port) {
504 list_del(&h->list);
505 mutex_unlock(&pc_lists_lock);
506 printk(KERN_ERR "daldevice_attach: could not "
507 "open port\n");
508 kfree(h);
509 *handle_ptr = NULL;
510 return -EIO;
511 }
512 mutex_unlock(&pc_lists_lock);
513
514 h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 4 +
515 DALRPC_MAX_ATTACH_PARAM_LEN +
516 DALRPC_MAX_SERVICE_NAME_LEN;
517 h->msg.hdr.proto_ver = DALRPC_PROTOCOL_VERSION;
518 h->msg.hdr.ddi_idx = 0;
519 h->msg.hdr.msgid = 0x1;
520 h->msg.hdr.prio = 0;
521 h->msg.hdr.async = 0;
522 h->msg.hdr.from = h;
523 h->msg.hdr.to = 0;
524 h->msg.param[0] = device_id;
525
526 memset(&h->msg.param[1], 0,
527 DALRPC_MAX_ATTACH_PARAM_LEN +
528 DALRPC_MAX_SERVICE_NAME_LEN);
529
530 dalrpc_sendwait(h);
531 ret = h->msg.param[0];
532
533 if (ret == DALRPC_SUCCESS) {
534 h->remote_handle = h->msg.hdr.from;
535 *handle_ptr = h;
536 break;
537 } else if (strnlen((char *)&h->msg.param[1],
538 DALRPC_MAX_PORTNAME_LEN)) {
539 /* another port was recommended in the response. */
Swaminathan Sathappanec6906d2011-10-26 13:36:00 -0700540 strlcpy(dyn_port, (char *)&h->msg.param[1],
541 sizeof(dyn_port));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700542 dyn_port[DALRPC_MAX_PORTNAME_LEN] = 0;
543 port = dyn_port;
544 } else if (port == dyn_port) {
545 /* the dynamic discovery port (or port that
546 * was recommended by it) did not recognize
547 * the device id, give up */
548 daldevice_detach(h);
549 break;
550 } else
551 /* the user specified port did not work, try
552 * the dynamic discovery port */
553 port = dyn_port;
554
555 port_close(h->port);
556 }
557
558 return ret;
559}
560EXPORT_SYMBOL(daldevice_attach);
561
562static void dalrpc_ddi_prologue(uint32_t ddi_idx, struct daldevice_handle *h,
563 uint32_t idx_async)
564{
565 h->msg.hdr.proto_ver = DALRPC_PROTOCOL_VERSION;
566 h->msg.hdr.prio = 0;
567 h->msg.hdr.async = idx_async;
568 h->msg.hdr.msgid = DALRPC_MSGID_DDI;
569 h->msg.hdr.from = h;
570 h->msg.hdr.to = h->remote_handle;
571 h->msg.hdr.ddi_idx = ddi_idx;
572}
573
574int daldevice_detach(void *handle)
575{
576 struct daldevice_handle *h = handle;
577
578 if (!client_exists(h))
579 return -EINVAL;
580
581 dalrpc_ddi_prologue(0, h, 0);
582
583 if (!h->remote_handle)
584 goto norpc;
585
586 h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 4;
587 h->msg.hdr.msgid = 0x2;
588 h->msg.param[0] = 0;
589
590 dalrpc_sendwait(h);
591
592norpc:
593 mutex_lock(&pc_lists_lock);
594 list_del(&h->list);
595 mutex_unlock(&pc_lists_lock);
596
597 port_close(h->port);
598
599 kfree(h);
600
601 return 0;
602}
603EXPORT_SYMBOL(daldevice_detach);
604
605uint32_t dalrpc_fcn_0(uint32_t ddi_idx, void *handle, uint32_t s1)
606{
607 struct daldevice_handle *h = handle;
608 uint32_t ret;
609
610 if (!client_exists(h))
611 return -EINVAL;
612
613 mutex_lock(&h->client_lock);
614
615 dalrpc_ddi_prologue(ddi_idx, h, 0);
616
617 h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 4;
618 h->msg.hdr.proto_id = 0;
619 h->msg.param[0] = s1;
620
621 dalrpc_sendwait(h);
622
623 ret = h->msg.param[0];
624 mutex_unlock(&h->client_lock);
625 return ret;
626}
627EXPORT_SYMBOL(dalrpc_fcn_0);
628
629uint32_t dalrpc_fcn_1(uint32_t ddi_idx, void *handle, uint32_t s1,
630 uint32_t s2)
631{
632 struct daldevice_handle *h = handle;
633 uint32_t ret;
634
635 if (!client_exists(h))
636 return -EINVAL;
637
638 mutex_lock(&h->client_lock);
639
640 dalrpc_ddi_prologue(ddi_idx, h, 0);
641
642 h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 8;
643 h->msg.hdr.proto_id = 1;
644 h->msg.param[0] = s1;
645 h->msg.param[1] = s2;
646
647 dalrpc_sendwait(h);
648
649 ret = h->msg.param[0];
650 mutex_unlock(&h->client_lock);
651 return ret;
652}
653EXPORT_SYMBOL(dalrpc_fcn_1);
654
655uint32_t dalrpc_fcn_2(uint32_t ddi_idx, void *handle, uint32_t s1,
656 uint32_t *p_s2)
657{
658 struct daldevice_handle *h = handle;
659 uint32_t ret;
660
661 if (!client_exists(h))
662 return -EINVAL;
663
664 mutex_lock(&h->client_lock);
665
666 dalrpc_ddi_prologue(ddi_idx, h, 0);
667
668 h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 4;
669 h->msg.hdr.proto_id = 2;
670 h->msg.param[0] = s1;
671
672 dalrpc_sendwait(h);
673
674 if (h->msg.param[0] == DALRPC_SUCCESS)
675 *p_s2 = h->msg.param[1];
676
677 ret = h->msg.param[0];
678 mutex_unlock(&h->client_lock);
679 return ret;
680}
681EXPORT_SYMBOL(dalrpc_fcn_2);
682
683uint32_t dalrpc_fcn_3(uint32_t ddi_idx, void *handle, uint32_t s1,
684 uint32_t s2, uint32_t s3)
685{
686 struct daldevice_handle *h = handle;
687 uint32_t ret;
688
689 if (!client_exists(h))
690 return -EINVAL;
691
692 mutex_lock(&h->client_lock);
693
694 dalrpc_ddi_prologue(ddi_idx, h, 0);
695
696 h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 12;
697 h->msg.hdr.proto_id = 3;
698 h->msg.param[0] = s1;
699 h->msg.param[1] = s2;
700 h->msg.param[2] = s3;
701
702 dalrpc_sendwait(h);
703
704 ret = h->msg.param[0];
705 mutex_unlock(&h->client_lock);
706 return ret;
707}
708EXPORT_SYMBOL(dalrpc_fcn_3);
709
710uint32_t dalrpc_fcn_4(uint32_t ddi_idx, void *handle, uint32_t s1,
711 uint32_t s2, uint32_t *p_s3)
712{
713 struct daldevice_handle *h = handle;
714 uint32_t ret;
715
716 if (!client_exists(h))
717 return -EINVAL;
718
719 mutex_lock(&h->client_lock);
720
721 dalrpc_ddi_prologue(ddi_idx, h, 0);
722
723 h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 8;
724 h->msg.hdr.proto_id = 4;
725 h->msg.param[0] = s1;
726 h->msg.param[1] = s2;
727
728 dalrpc_sendwait(h);
729
730 if (h->msg.param[0] == DALRPC_SUCCESS)
731 *p_s3 = h->msg.param[1];
732
733 ret = h->msg.param[0];
734 mutex_unlock(&h->client_lock);
735 return ret;
736}
737EXPORT_SYMBOL(dalrpc_fcn_4);
738
739uint32_t dalrpc_fcn_5(uint32_t ddi_idx, void *handle, const void *ibuf,
740 uint32_t ilen)
741{
742 struct daldevice_handle *h = handle;
743 uint32_t ret, idx_async;
744
745 if ((ilen + 4) > DALRPC_MAX_PARAMS_SIZE)
746 return -EINVAL;
747
748 if (!client_exists(h))
749 return -EINVAL;
750
751 idx_async = (ddi_idx & 0x80000000) >> 31;
752
753 mutex_lock(&h->client_lock);
754
755 dalrpc_ddi_prologue(ddi_idx, h, idx_async);
756
757 h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 4 +
758 ROUND_BUFLEN(ilen);
759 h->msg.hdr.proto_id = 5;
760 h->msg.param[0] = ilen;
761 memcpy(&h->msg.param[1], ibuf, ilen);
762
763 dalrpc_sendwait(h);
764
765 if (h->msg.hdr.async)
766 ret = DALRPC_SUCCESS;
767 else
768 ret = h->msg.param[0];
769 mutex_unlock(&h->client_lock);
770 return ret;
771}
772EXPORT_SYMBOL(dalrpc_fcn_5);
773
774uint32_t dalrpc_fcn_6(uint32_t ddi_idx, void *handle, uint32_t s1,
775 const void *ibuf, uint32_t ilen)
776{
777 struct daldevice_handle *h = handle;
778 uint32_t ret;
779
780 if ((ilen + 8) > DALRPC_MAX_PARAMS_SIZE)
781 return -EINVAL;
782
783 if (!client_exists(h))
784 return -EINVAL;
785
786 mutex_lock(&h->client_lock);
787
788 dalrpc_ddi_prologue(ddi_idx, h, 0);
789
790 h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 8 +
791 ROUND_BUFLEN(ilen);
792 h->msg.hdr.proto_id = 6;
793 h->msg.param[0] = s1;
794 h->msg.param[1] = ilen;
795 memcpy(&h->msg.param[2], ibuf, ilen);
796
797 dalrpc_sendwait(h);
798
799 ret = h->msg.param[0];
800 mutex_unlock(&h->client_lock);
801 return ret;
802}
803EXPORT_SYMBOL(dalrpc_fcn_6);
804
805uint32_t dalrpc_fcn_7(uint32_t ddi_idx, void *handle, const void *ibuf,
806 uint32_t ilen, void *obuf, uint32_t olen,
807 uint32_t *oalen)
808{
809 struct daldevice_handle *h = handle;
810 uint32_t ret;
811 int param_idx;
812
813 if ((ilen + 8) > DALRPC_MAX_PARAMS_SIZE ||
814 (olen + 4) > DALRPC_MAX_PARAMS_SIZE)
815 return -EINVAL;
816
817
818 if (!client_exists(h))
819 return -EINVAL;
820
821 mutex_lock(&h->client_lock);
822
823 dalrpc_ddi_prologue(ddi_idx, h, 0);
824
825 h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 8 +
826 ROUND_BUFLEN(ilen);
827 h->msg.hdr.proto_id = 7;
828 h->msg.param[0] = ilen;
829 memcpy(&h->msg.param[1], ibuf, ilen);
830 param_idx = (ROUND_BUFLEN(ilen) / 4) + 1;
831 h->msg.param[param_idx] = olen;
832
833 dalrpc_sendwait(h);
834
835 if (h->msg.param[0] == DALRPC_SUCCESS) {
836 if (h->msg.param[1] > olen) {
837 mutex_unlock(&h->client_lock);
838 return -EIO;
839 }
840 *oalen = h->msg.param[1];
841 memcpy(obuf, &h->msg.param[2], h->msg.param[1]);
842 }
843
844 ret = h->msg.param[0];
845 mutex_unlock(&h->client_lock);
846 return ret;
847}
848EXPORT_SYMBOL(dalrpc_fcn_7);
849
850uint32_t dalrpc_fcn_8(uint32_t ddi_idx, void *handle, const void *ibuf,
851 uint32_t ilen, void *obuf, uint32_t olen)
852{
853 struct daldevice_handle *h = handle;
854 uint32_t ret;
855 int param_idx;
856
857 if ((ilen + 8) > DALRPC_MAX_PARAMS_SIZE ||
858 (olen + 4) > DALRPC_MAX_PARAMS_SIZE)
859 return -EINVAL;
860
861 if (!client_exists(h))
862 return -EINVAL;
863
864 mutex_lock(&h->client_lock);
865
866 dalrpc_ddi_prologue(ddi_idx, h, 0);
867
868 h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 8 +
869 ROUND_BUFLEN(ilen);
870 h->msg.hdr.proto_id = 8;
871 h->msg.param[0] = ilen;
872 memcpy(&h->msg.param[1], ibuf, ilen);
873 param_idx = (ROUND_BUFLEN(ilen) / 4) + 1;
874 h->msg.param[param_idx] = olen;
875
876 dalrpc_sendwait(h);
877
878 if (h->msg.param[0] == DALRPC_SUCCESS) {
879 if (h->msg.param[1] > olen) {
880 mutex_unlock(&h->client_lock);
881 return -EIO;
882 }
883 memcpy(obuf, &h->msg.param[2], h->msg.param[1]);
884 }
885
886 ret = h->msg.param[0];
887 mutex_unlock(&h->client_lock);
888 return ret;
889}
890EXPORT_SYMBOL(dalrpc_fcn_8);
891
892uint32_t dalrpc_fcn_9(uint32_t ddi_idx, void *handle, void *obuf,
893 uint32_t olen)
894{
895 struct daldevice_handle *h = handle;
896 uint32_t ret;
897
898 if ((olen + 4) > DALRPC_MAX_PARAMS_SIZE)
899 return -EINVAL;
900
901 if (!client_exists(h))
902 return -EINVAL;
903
904 mutex_lock(&h->client_lock);
905
906 dalrpc_ddi_prologue(ddi_idx, h, 0);
907
908 h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 4;
909 h->msg.hdr.proto_id = 9;
910 h->msg.param[0] = olen;
911
912 dalrpc_sendwait(h);
913
914 if (h->msg.param[0] == DALRPC_SUCCESS) {
915 if (h->msg.param[1] > olen) {
916 mutex_unlock(&h->client_lock);
917 return -EIO;
918 }
919 memcpy(obuf, &h->msg.param[2], h->msg.param[1]);
920 }
921
922 ret = h->msg.param[0];
923 mutex_unlock(&h->client_lock);
924 return ret;
925}
926EXPORT_SYMBOL(dalrpc_fcn_9);
927
928uint32_t dalrpc_fcn_10(uint32_t ddi_idx, void *handle, uint32_t s1,
929 const void *ibuf, uint32_t ilen, void *obuf,
930 uint32_t olen, uint32_t *oalen)
931{
932 struct daldevice_handle *h = handle;
933 uint32_t ret;
934 int param_idx;
935
936 if ((ilen + 12) > DALRPC_MAX_PARAMS_SIZE ||
937 (olen + 4) > DALRPC_MAX_PARAMS_SIZE)
938 return -EINVAL;
939
940 if (!client_exists(h))
941 return -EINVAL;
942
943 mutex_lock(&h->client_lock);
944
945 dalrpc_ddi_prologue(ddi_idx, h, 0);
946
947 h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 12 +
948 ROUND_BUFLEN(ilen);
949 h->msg.hdr.proto_id = 10;
950 h->msg.param[0] = s1;
951 h->msg.param[1] = ilen;
952 memcpy(&h->msg.param[2], ibuf, ilen);
953 param_idx = (ROUND_BUFLEN(ilen) / 4) + 2;
954 h->msg.param[param_idx] = olen;
955
956 dalrpc_sendwait(h);
957
958 if (h->msg.param[0] == DALRPC_SUCCESS) {
959 if (h->msg.param[1] > olen) {
960 mutex_unlock(&h->client_lock);
961 return -EIO;
962 }
963 *oalen = h->msg.param[1];
964 memcpy(obuf, &h->msg.param[2], h->msg.param[1]);
965 }
966
967 ret = h->msg.param[0];
968 mutex_unlock(&h->client_lock);
969 return ret;
970}
971EXPORT_SYMBOL(dalrpc_fcn_10);
972
973uint32_t dalrpc_fcn_11(uint32_t ddi_idx, void *handle, uint32_t s1,
974 void *obuf, uint32_t olen)
975{
976 struct daldevice_handle *h = handle;
977 uint32_t ret;
978
979 if ((olen + 4) > DALRPC_MAX_PARAMS_SIZE)
980 return -EINVAL;
981
982 if (!client_exists(h))
983 return -EINVAL;
984
985 mutex_lock(&h->client_lock);
986
987 dalrpc_ddi_prologue(ddi_idx, h, 0);
988
989 h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 8;
990 h->msg.hdr.proto_id = 11;
991 h->msg.param[0] = s1;
992 h->msg.param[1] = olen;
993
994 dalrpc_sendwait(h);
995
996 if (h->msg.param[0] == DALRPC_SUCCESS) {
997 if (h->msg.param[1] > olen) {
998 mutex_unlock(&h->client_lock);
999 return -EIO;
1000 }
1001 memcpy(obuf, &h->msg.param[2], h->msg.param[1]);
1002 }
1003
1004 ret = h->msg.param[0];
1005 mutex_unlock(&h->client_lock);
1006 return ret;
1007}
1008EXPORT_SYMBOL(dalrpc_fcn_11);
1009
1010uint32_t dalrpc_fcn_12(uint32_t ddi_idx, void *handle, uint32_t s1,
1011 void *obuf, uint32_t olen, uint32_t *oalen)
1012{
1013 struct daldevice_handle *h = handle;
1014 uint32_t ret;
1015
1016 if ((olen + 4) > DALRPC_MAX_PARAMS_SIZE)
1017 return -EINVAL;
1018
1019 if (!client_exists(h))
1020 return -EINVAL;
1021
1022 mutex_lock(&h->client_lock);
1023
1024 dalrpc_ddi_prologue(ddi_idx, h, 0);
1025
1026 h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 8;
1027 h->msg.hdr.proto_id = 12;
1028 h->msg.param[0] = s1;
1029 h->msg.param[1] = olen;
1030
1031 dalrpc_sendwait(h);
1032
1033 if (h->msg.param[0] == DALRPC_SUCCESS) {
1034 if (h->msg.param[1] > olen) {
1035 mutex_unlock(&h->client_lock);
1036 return -EIO;
1037 }
1038 *oalen = h->msg.param[1];
1039 memcpy(obuf, &h->msg.param[2], h->msg.param[1]);
1040 }
1041
1042 ret = h->msg.param[0];
1043 mutex_unlock(&h->client_lock);
1044 return ret;
1045}
1046EXPORT_SYMBOL(dalrpc_fcn_12);
1047
1048uint32_t dalrpc_fcn_13(uint32_t ddi_idx, void *handle, const void *ibuf,
1049 uint32_t ilen, const void *ibuf2, uint32_t ilen2,
1050 void *obuf, uint32_t olen)
1051{
1052 struct daldevice_handle *h = handle;
1053 uint32_t ret;
1054 int param_idx;
1055
1056 if ((ilen + ilen2 + 12) > DALRPC_MAX_PARAMS_SIZE ||
1057 (olen + 4) > DALRPC_MAX_PARAMS_SIZE)
1058 return -EINVAL;
1059
1060 if (!client_exists(h))
1061 return -EINVAL;
1062
1063 mutex_lock(&h->client_lock);
1064
1065 dalrpc_ddi_prologue(ddi_idx, h, 0);
1066
1067 h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 12 +
1068 ROUND_BUFLEN(ilen) + ROUND_BUFLEN(ilen2);
1069 h->msg.hdr.proto_id = 13;
1070 h->msg.param[0] = ilen;
1071 memcpy(&h->msg.param[1], ibuf, ilen);
1072 param_idx = (ROUND_BUFLEN(ilen) / 4) + 1;
1073 h->msg.param[param_idx++] = ilen2;
1074 memcpy(&h->msg.param[param_idx], ibuf2, ilen2);
1075 param_idx += (ROUND_BUFLEN(ilen2) / 4);
1076 h->msg.param[param_idx] = olen;
1077
1078 dalrpc_sendwait(h);
1079
1080 if (h->msg.param[0] == DALRPC_SUCCESS) {
1081 if (h->msg.param[1] > olen) {
1082 mutex_unlock(&h->client_lock);
1083 return -EIO;
1084 }
1085 memcpy(obuf, &h->msg.param[2], h->msg.param[1]);
1086 }
1087
1088 ret = h->msg.param[0];
1089 mutex_unlock(&h->client_lock);
1090 return ret;
1091}
1092EXPORT_SYMBOL(dalrpc_fcn_13);
1093
1094uint32_t dalrpc_fcn_14(uint32_t ddi_idx, void *handle, const void *ibuf,
1095 uint32_t ilen, void *obuf, uint32_t olen,
1096 void *obuf2, uint32_t olen2, uint32_t *oalen2)
1097{
1098 struct daldevice_handle *h = handle;
1099 uint32_t ret;
1100 int param_idx;
1101
1102 if ((ilen + 12) > DALRPC_MAX_PARAMS_SIZE ||
1103 (olen + olen2 + 8) > DALRPC_MAX_PARAMS_SIZE)
1104 return -EINVAL;
1105
1106 if (!client_exists(h))
1107 return -EINVAL;
1108
1109 mutex_lock(&h->client_lock);
1110
1111 dalrpc_ddi_prologue(ddi_idx, h, 0);
1112
1113 h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 12 +
1114 ROUND_BUFLEN(ilen);
1115 h->msg.hdr.proto_id = 14;
1116 h->msg.param[0] = ilen;
1117 memcpy(&h->msg.param[1], ibuf, ilen);
1118 param_idx = (ROUND_BUFLEN(ilen) / 4) + 1;
1119 h->msg.param[param_idx++] = olen;
1120 h->msg.param[param_idx] = olen2;
1121
1122 dalrpc_sendwait(h);
1123
1124 if (h->msg.param[0] == DALRPC_SUCCESS) {
1125 if (h->msg.param[1] > olen) {
1126 mutex_unlock(&h->client_lock);
1127 return -EIO;
1128 }
1129 param_idx = (ROUND_BUFLEN(h->msg.param[1]) / 4) + 2;
1130 if (h->msg.param[param_idx] > olen2) {
1131 mutex_unlock(&h->client_lock);
1132 return -EIO;
1133 }
1134 memcpy(obuf, &h->msg.param[2], h->msg.param[1]);
1135 memcpy(obuf2, &h->msg.param[param_idx + 1],
1136 h->msg.param[param_idx]);
1137 *oalen2 = h->msg.param[param_idx];
1138 }
1139
1140 ret = h->msg.param[0];
1141 mutex_unlock(&h->client_lock);
1142 return ret;
1143}
1144EXPORT_SYMBOL(dalrpc_fcn_14);
1145
1146uint32_t dalrpc_fcn_15(uint32_t ddi_idx, void *handle, const void *ibuf,
1147 uint32_t ilen, const void *ibuf2, uint32_t ilen2,
1148 void *obuf, uint32_t olen, uint32_t *oalen,
1149 void *obuf2, uint32_t olen2)
1150{
1151 struct daldevice_handle *h = handle;
1152 uint32_t ret;
1153 int param_idx;
1154
1155 if ((ilen + ilen2 + 16) > DALRPC_MAX_PARAMS_SIZE ||
1156 (olen + olen2 + 8) > DALRPC_MAX_PARAMS_SIZE)
1157 return -EINVAL;
1158
1159 if (!client_exists(h))
1160 return -EINVAL;
1161
1162 mutex_lock(&h->client_lock);
1163
1164 dalrpc_ddi_prologue(ddi_idx, h, 0);
1165
1166 h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 16 +
1167 ROUND_BUFLEN(ilen) + ROUND_BUFLEN(ilen2);
1168 h->msg.hdr.proto_id = 15;
1169 h->msg.param[0] = ilen;
1170 memcpy(&h->msg.param[1], ibuf, ilen);
1171 param_idx = (ROUND_BUFLEN(ilen) / 4) + 1;
1172 h->msg.param[param_idx++] = ilen2;
1173 memcpy(&h->msg.param[param_idx], ibuf2, ilen2);
1174 param_idx += (ROUND_BUFLEN(ilen2) / 4);
1175 h->msg.param[param_idx++] = olen;
1176 h->msg.param[param_idx] = olen2;
1177
1178 dalrpc_sendwait(h);
1179
1180 if (h->msg.param[0] == DALRPC_SUCCESS) {
1181 if (h->msg.param[1] > olen) {
1182 mutex_unlock(&h->client_lock);
1183 return -EIO;
1184 }
1185 param_idx = (ROUND_BUFLEN(h->msg.param[1]) / 4) + 2;
1186 if (h->msg.param[param_idx] > olen2) {
1187 mutex_unlock(&h->client_lock);
1188 return -EIO;
1189 }
1190 memcpy(obuf, &h->msg.param[2], h->msg.param[1]);
1191 memcpy(obuf2, &h->msg.param[param_idx + 1],
1192 h->msg.param[param_idx]);
1193 *oalen = h->msg.param[1];
1194 }
1195
1196 ret = h->msg.param[0];
1197 mutex_unlock(&h->client_lock);
1198 return ret;
1199}
1200EXPORT_SYMBOL(dalrpc_fcn_15);
1201
1202void *dalrpc_alloc_event(void *handle)
1203{
1204 struct daldevice_handle *h;
1205 struct dalrpc_event_handle *ev;
1206
1207 h = (struct daldevice_handle *)handle;
1208
1209 if (!client_exists(h))
1210 return NULL;
1211
1212 ev = kmalloc(sizeof(struct dalrpc_event_handle), GFP_KERNEL);
1213 if (!ev)
1214 return NULL;
1215
1216 ev->flag = 0;
1217 spin_lock_init(&ev->lock);
1218
1219 mutex_lock(&h->port->event_list_lock);
1220 list_add(&ev->list, &h->port->event_list);
1221 mutex_unlock(&h->port->event_list_lock);
1222
1223 return ev;
1224}
1225EXPORT_SYMBOL(dalrpc_alloc_event);
1226
1227void *dalrpc_alloc_cb(void *handle,
1228 void (*fn)(void *, uint32_t, void *, uint32_t),
1229 void *context)
1230{
1231 struct daldevice_handle *h;
1232 struct dalrpc_cb_handle *cb;
1233
1234 h = (struct daldevice_handle *)handle;
1235
1236 if (!client_exists(h))
1237 return NULL;
1238
1239 cb = kmalloc(sizeof(struct dalrpc_cb_handle), GFP_KERNEL);
1240 if (!cb)
1241 return NULL;
1242
1243 cb->fn = fn;
1244 cb->context = context;
1245
1246 mutex_lock(&h->port->cb_list_lock);
1247 list_add(&cb->list, &h->port->cb_list);
1248 mutex_unlock(&h->port->cb_list_lock);
1249
1250 return cb;
1251}
1252EXPORT_SYMBOL(dalrpc_alloc_cb);
1253
1254void dalrpc_dealloc_event(void *handle,
1255 void *ev_h)
1256{
1257 struct daldevice_handle *h;
1258 struct dalrpc_event_handle *ev;
1259
1260 h = (struct daldevice_handle *)handle;
1261 ev = (struct dalrpc_event_handle *)ev_h;
1262
1263 mutex_lock(&h->port->event_list_lock);
1264 list_del(&ev->list);
1265 mutex_unlock(&h->port->event_list_lock);
1266 kfree(ev);
1267}
1268EXPORT_SYMBOL(dalrpc_dealloc_event);
1269
1270void dalrpc_dealloc_cb(void *handle,
1271 void *cb_h)
1272{
1273 struct daldevice_handle *h;
1274 struct dalrpc_cb_handle *cb;
1275
1276 h = (struct daldevice_handle *)handle;
1277 cb = (struct dalrpc_cb_handle *)cb_h;
1278
1279 mutex_lock(&h->port->cb_list_lock);
1280 list_del(&cb->list);
1281 mutex_unlock(&h->port->cb_list_lock);
1282 kfree(cb);
1283}
1284EXPORT_SYMBOL(dalrpc_dealloc_cb);
1285
1286static int event_occurred(int num_events, struct dalrpc_event_handle **events,
1287 int *occurred)
1288{
1289 int i;
1290
1291 for (i = 0; i < num_events; i++) {
1292 spin_lock(&events[i]->lock);
1293 if (events[i]->flag) {
1294 events[i]->flag = 0;
1295 spin_unlock(&events[i]->lock);
1296 *occurred = i;
1297 return 1;
1298 }
1299 spin_unlock(&events[i]->lock);
1300 }
1301
1302 return 0;
1303}
1304
1305int dalrpc_event_wait_multiple(int num, void **ev_h, int timeout)
1306{
1307 struct dalrpc_event_handle **events;
1308 int ret, occurred;
1309
1310 events = (struct dalrpc_event_handle **)ev_h;
1311
1312 if (timeout == DALRPC_TIMEOUT_INFINITE) {
1313 wait_event(event_wq,
1314 event_occurred(num, events, &occurred));
1315 return occurred;
1316 }
1317
1318 ret = wait_event_timeout(event_wq,
1319 event_occurred(num, events, &occurred),
1320 timeout);
1321 if (ret > 0)
1322 return occurred;
1323 else
1324 return -ETIMEDOUT;
1325}
1326EXPORT_SYMBOL(dalrpc_event_wait_multiple);