Support in QNX MmRpc/MmServiceMgr to identify deleted instance during cleanup
[ipc/ipcdev.git] / qnx / src / ipc3x_dev / ti / syslink / rpmsg-rpc / rpmsg-rpc.c
1 /*
2  *  Copyright (c) 2013-2014, Texas Instruments Incorporated
3  *
4  *  Redistribution and use in source and binary forms, with or without
5  *  modification, are permitted provided that the following conditions
6  *  are met:
7  *
8  *  *  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  *
11  *  *  Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  *
15  *  *  Neither the name of Texas Instruments Incorporated nor the names of
16  *     its contributors may be used to endorse or promote products derived
17  *     from this software without specific prior written permission.
18  *
19  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21  *  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  *  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23  *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26  *  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27  *  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28  *  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
29  *  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
33 /* Standard headers */
34 #include <ti/syslink/Std.h>
36 /* OSAL & Utils headers */
37 #include <ti/syslink/utils/List.h>
38 #include <ti/syslink/utils/String.h>
39 #include <ti/syslink/utils/Trace.h>
40 #include <ti/syslink/utils/Memory.h>
41 #include <ti/syslink/utils/IGateProvider.h>
42 #include <ti/syslink/utils/GateSpinlock.h>
43 #include <_MultiProc.h>
45 /*QNX specific header include */
46 #include <errno.h>
47 #include <unistd.h>
48 #include <sys/iofunc.h>
49 #include <sys/dispatch.h>
50 #include <sys/netmgr.h>
51 #include <sys/mman.h>
52 #include <devctl.h>
54 /* Module headers */
55 #include <ti/syslink/ProcMgr.h>
56 #include <ti/ipc/rpmsg_rpc.h>
57 #include <ti/ipc/MessageQCopy.h>
58 #include <_MessageQCopy.h>
59 #include <_MessageQCopyDefs.h>
60 #include "OsalSemaphore.h"
61 #include "std_qnx.h"
62 #include <pthread.h>
64 #include "rpmsg-rpc.h"
65 #include <rpmsg.h>
67 #define PRIORITY_REALTIME_LOW 29
69 extern int mem_offset64_peer(pid_t pid, const uintptr_t addr, size_t len,
70                              off64_t *offset, size_t *contig_len);
72 static MsgList_t *nl_cache;
73 static int num_nl = 0;
74 static WaitingReaders_t *wr_cache;
75 static int num_wr = 0;
77 /*
78  * Instead of constantly allocating and freeing the notifier structures
79  * we just cache a few of them, and recycle them instead.
80  * The cache count is set with CACHE_NUM in rpmsg-rpc.h.
81  */
83 static MsgList_t *get_nl()
84 {
85     MsgList_t *item;
86     item = nl_cache;
87     if (item != NULL) {
88         nl_cache = nl_cache->next;
89         num_nl--;
90     } else {
91         item = Memory_alloc(NULL, sizeof(MsgList_t), 0, NULL);
92     }
93     return(item);
94 }
96 static void put_nl(MsgList_t *item)
97 {
98     if (num_nl >= CACHE_NUM) {
99         Memory_free(NULL, item, sizeof(*item));
100     } else {
101         item->next = nl_cache;
102         nl_cache = item;
103         num_nl++;
104     }
105     return;
108 static WaitingReaders_t *get_wr()
110     WaitingReaders_t *item;
111     item = wr_cache;
112     if (item != NULL) {
113         wr_cache = wr_cache->next;
114         num_wr--;
115     } else {
116         item = Memory_alloc(NULL, sizeof(WaitingReaders_t), 0, NULL);
117     }
118     return(item);
121 static void put_wr(WaitingReaders_t *item)
123     if (num_wr >= CACHE_NUM) {
124         Memory_free(NULL, item, sizeof(*item));
125     } else {
126         item->next = wr_cache;
127         wr_cache = item;
128         num_wr++;
129     }
130     return;
133 /* structure to hold rpmsg-rpc device information */
134 typedef struct named_device {
135     iofunc_mount_t      mattr;
136     iofunc_attr_t       cattr;
137     int                 resmgr_id;
138     pthread_mutex_t     mutex;
139     iofunc_funcs_t      mfuncs;
140     resmgr_connect_funcs_t  cfuncs;
141     resmgr_io_funcs_t   iofuncs;
142     char device_name[_POSIX_PATH_MAX];
143 } named_device_t;
145 /* rpmsg-rpc device structure */
146 typedef struct rpmsg_rpc_dev {
147     dispatch_t       * dpp;
148     thread_pool_t    * tpool;
149     named_device_t     rpmsg_rpc;
150 } rpmsg_rpc_dev_t;
152 /*!
153  *  @brief  Remote connection object
154  */
155 typedef struct rpmsg_rpc_conn_object {
156     rpmsg_rpc_dev_t *   dev;
157     MessageQCopy_Handle mq;
158     UInt32              addr;
159     UInt16              procId;
160     ProcMgr_Handle      procH;
161     UInt32              numFuncs;
162     Bool                destroy;
163 } rpmsg_rpc_conn_object;
165 /*!
166  *  @brief  rpc instance object
167  */
168 typedef struct rpmsg_rpc_object_tag {
169     MessageQCopy_Handle     mq;
170     rpmsg_rpc_conn_object * conn;
171     UInt32                  addr;
172     UInt32                  remoteAddr;
173     UInt16                  procId;
174     pid_t                   pid;
175     Bool                    created;
176     iofunc_notify_t         notify[3];
177 } rpmsg_rpc_object;
179 /*!
180  *  @brief  Structure of Event callback argument passed to register fucntion.
181  */
182 typedef struct rpmsg_rpc_EventCbck_tag {
183     List_Elem          element;
184     /*!< List element header */
185     rpmsg_rpc_object * rpc;
186     /*!< User rpc info pointer. Passed back to user callback function */
187     UInt32             pid;
188     /*!< Process Identifier for user process. */
189 } rpmsg_rpc_EventCbck ;
191 /*!
192  *  @brief  Structure of Fxn Info for reverse translations.
193  */
194 typedef struct rpmsg_rpc_FxnInfo_tag {
195     List_Elem              element;
196     /*!< List element header */
197     UInt16                 msgId;
198     /*!< Unique msgId of the rpc fxn call */
199     struct rppc_function   func;
200     /*!< rpc function information. */
201 } rpmsg_rpc_FxnInfo ;
203 /*!
204  *  @brief  Keeps the information related to Event.
205  */
206 typedef struct rpmsg_rpc_EventState_tag {
207     List_Handle            bufList;
208     /*!< Head of received event list. */
209     List_Handle            fxnList;
210     /*!< Head of received msg list. */
211     UInt32                 pid;
212     /*!< User process ID. */
213     rpmsg_rpc_object *     rpc;
214     /*!< User rpc comp. */
215     UInt32                 refCount;
216     /*!< Reference count, used when multiple Notify_registerEvent are called
217          from same process space (multi threads/processes). */
218     WaitingReaders_t *     head;
219     /*!< Waiting readers head. */
220     WaitingReaders_t *     tail;
221     /*!< Waiting readers tail. */
222 } rpmsg_rpc_EventState;
224 /*!
225  *  @brief  Per-connection information
226  */
227 typedef struct rpmsg_rpc_ocb {
228     iofunc_ocb_t        hdr;
229     pid_t               pid;
230     rpmsg_rpc_object *  rpc;
231 } rpmsg_rpc_ocb_t;
233 typedef struct rpmsg_rpc_name {
234     char name[RPMSG_NAME_SIZE];
235 }rpmsg_rpc_name_t;
237 static struct rpmsg_rpc_name rpmsg_rpc_names[] = {
238         {.name = "rpmsg-rpc"},
239 };
241 #define NUM_RPMSG_RPC_QUEUES sizeof(rpmsg_rpc_names)/sizeof(*rpmsg_rpc_names)
243 /*!
244  *  @brief  rpmsg-rpc Module state object
245  */
246 typedef struct rpmsg_rpc_ModuleObject_tag {
247     Bool                 isSetup;
248     /*!< Indicates whether the module has been already setup */
249     Bool                 openRefCount;
250     /*!< Open reference count. */
251     IGateProvider_Handle gateHandle;
252     /*!< Handle of gate to be used for local thread safety */
253     rpmsg_rpc_EventState eventState [MAX_PROCESSES];
254     /*!< List for all user processes registered. */
255     rpmsg_rpc_conn_object * objects [MAX_CONNS];
256     /*!< List of all remote connections. */
257     MessageQCopy_Handle mqHandle[NUM_RPMSG_RPC_QUEUES];
258     /*!< Local mq handle associated with this module */
259     UInt32 endpoint[NUM_RPMSG_RPC_QUEUES];
260     /*!< Local endpoint associated with the mq handle */
261     OsalSemaphore_Handle sem;
262     /*!< Handle to semaphore used for rpc instance connection notifications */
263     pthread_t nt;
264     /*!< notifier thread */
265     pthread_mutex_t lock;
266     /*!< protection between notifier and event */
267     pthread_cond_t  cond;
268     /*!< protection between notifier and event */
269     MsgList_t *head;
270     /*!< list head */
271     MsgList_t *tail;
272     /*!< list tail */
273     int run;
274     /*!< notifier thread must keep running */
275 } rpmsg_rpc_ModuleObject;
277 /*!
278  *  @brief  Structure of Event Packet read from notify kernel-side.
279  */
280 typedef struct rpmsg_rpc_EventPacket_tag {
281     List_Elem          element;
282     /*!< List element header */
283     UInt32             pid;
284     /* Processor identifier */
285     rpmsg_rpc_object * obj;
286     /*!< Pointer to the channel associated with this callback */
287     UInt8              data[MessageQCopy_BUFSIZE];
288     /*!< Data associated with event. */
289     UInt32             len;
290     /*!< Length of the data associated with event. */
291     UInt32             src;
292     /*!< Src endpoint associated with event. */
293     struct rpmsg_rpc_EventPacket * next;
294     struct rpmsg_rpc_EventPacket * prev;
295 } rpmsg_rpc_EventPacket ;
298 /*
299  * Instead of constantly allocating and freeing the uBuf structures
300  * we just cache a few of them, and recycle them instead.
301  * The cache count is set with CACHE_NUM in rpmsg-rpc.h.
302  */
303 static rpmsg_rpc_EventPacket *uBuf_cache;
304 static int num_uBuf = 0;
306 static void flush_uBuf()
308     rpmsg_rpc_EventPacket *uBuf = NULL;
310     while(uBuf_cache) {
311         num_uBuf--;
312         uBuf = uBuf_cache;
313         uBuf_cache = (rpmsg_rpc_EventPacket *)uBuf_cache->next;
314         Memory_free(NULL, uBuf, sizeof(*uBuf));
315     }
318 static rpmsg_rpc_EventPacket *get_uBuf()
320     rpmsg_rpc_EventPacket *uBuf;
321     uBuf = uBuf_cache;
322     if (uBuf != NULL) {
323         uBuf_cache = (rpmsg_rpc_EventPacket *)uBuf_cache->next;
324         num_uBuf--;
325     } else {
326         uBuf = Memory_alloc(NULL, sizeof(rpmsg_rpc_EventPacket), 0, NULL);
327     }
328     return(uBuf);
331 static void put_uBuf(rpmsg_rpc_EventPacket * uBuf)
333     if (num_uBuf >= CACHE_NUM) {
334         Memory_free(NULL, uBuf, sizeof(*uBuf));
335     } else {
336         uBuf->next = (struct rpmsg_rpc_EventPacket *)uBuf_cache;
337         uBuf_cache = uBuf;
338         num_uBuf++;
339     }
340     return;
343 /** ============================================================================
344  *  Function Prototypes
345  *  ============================================================================
346  */
347 int
348 _rpmsg_rpc_translate (ProcMgr_Handle handle, char *data, pid_t pid,
349                       bool reverse);
351 /** ============================================================================
352  *  Globals
353  *  ============================================================================
354  */
355 /*!
356  *  @var    rpmsg_rpc_state
357  *
358  *  @brief  rpmsg-rpc state object variable
359  */
360 static rpmsg_rpc_ModuleObject rpmsg_rpc_state =
362     .gateHandle = NULL,
363     .isSetup = FALSE,
364     .openRefCount = 0,
365     .nt = 0,
366     .lock = PTHREAD_MUTEX_INITIALIZER,
367     .cond = PTHREAD_COND_INITIALIZER,
368     .head = NULL,
369     .tail = NULL,
370     .run  = 0
371 };
373 static uint16_t msg_id = 0xFFFF;
375 extern dispatch_t * syslink_dpp;
378 static MsgList_t *find_nl(int index)
380     MsgList_t *item=NULL;
381     item = rpmsg_rpc_state.head;
382     while (item) {
383         if (item->index == index)
384             return(item);
385         item = item->next;
386     }
387     return(item);
390 /* we have the right locks when calling this function */
391 /*!
392  *  @brief      Function to enqueue a notify list item.
393  *
394  *  @param      index    Index of the client process associated with the item.
395  *
396  *  @sa         find_nl
397  *              get_nl
398  */
399 static int enqueue_notify_list(int index)
401     MsgList_t *item;
402     item = find_nl(index);
403     if (item == NULL) {
404         item = get_nl();
405         if (item == NULL) {
406             return(-1);
407         }
408         item->next = NULL;
409         item->index = index;
410         item->num_events=1;
411         if (rpmsg_rpc_state.head == NULL) {
412             rpmsg_rpc_state.head = item;
413             rpmsg_rpc_state.tail = item;
414             item->prev = NULL;
415         }
416         else {
417             item->prev = rpmsg_rpc_state.tail;
418             rpmsg_rpc_state.tail->next = item;
419             rpmsg_rpc_state.tail = item;
420         }
421     }
422     else {
423         item->num_events++;
424     }
425     return(0);
428 /* we have the right locks when calling this function */
429 /*!
430  *  @brief      Function to dequeue a notify list item.
431  *
432  *  @param      item     The item to remove.
433  *
434  *  @sa         put_nl
435  */
436 static inline int dequeue_notify_list_item(MsgList_t *item)
438     int index;
439     if (item == NULL) {
440         return(-1);
441     }
442     index = item->index;
443     item->num_events--;
444     if (item->num_events > 0) {
445         return(index);
446     }
447     if (rpmsg_rpc_state.head == item) {
448         // removing head
449         rpmsg_rpc_state.head = item->next;
450         if (rpmsg_rpc_state.head != NULL) {
451             rpmsg_rpc_state.head->prev = NULL;
452         }
453         else {
454             // removing head and tail
455             rpmsg_rpc_state.tail = NULL;
456         }
457     }
458     else {
459         item->prev->next = item->next;
460         if (item->next != NULL) {
461             item->next->prev = item->prev;
462         }
463         else {
464             // removing tail
465             rpmsg_rpc_state.tail = item->prev;
466         }
467     }
468     put_nl(item);
469     return(index);
472 /* we have the right locks when calling this function */
473 /*!
474  *  @brief      Function to add a waiting reader to the list.
475  *
476  *  @param      index    Index of the client process waiting reader to add.
477  *  @param      rcvid    Receive ID of the client process that was passed
478  *                       when the client called read().
479  *
480  *  @sa         None
481  */
482 static int enqueue_waiting_reader(int index, int rcvid)
484     WaitingReaders_t *item;
485     item = get_wr();
486     if (item == NULL) {
487         return(-1);
488     }
489     item->rcvid = rcvid;
490     item->next = NULL;
491     if (rpmsg_rpc_state.eventState [index].head == NULL) {
492         rpmsg_rpc_state.eventState [index].head = item;
493         rpmsg_rpc_state.eventState [index].tail = item;
494     }
495     else {
496         rpmsg_rpc_state.eventState [index].tail->next = item;
497         rpmsg_rpc_state.eventState [index].tail = item;
498     }
499     return(EOK);
502 /* we have the right locks when calling this function */
503 /* caller frees item */
504 /*!
505  *  @brief      Function to remove a waiting reader from the list.
506  *
507  *  @param      index    Index of the client process waiting reader to dequeue.
508  *
509  *  @sa         None
510  */
511 static WaitingReaders_t *dequeue_waiting_reader(int index)
513     WaitingReaders_t *item = NULL;
514     if (rpmsg_rpc_state.eventState [index].head) {
515         item = rpmsg_rpc_state.eventState [index].head;
516         rpmsg_rpc_state.eventState [index].head = rpmsg_rpc_state.eventState [index].head->next;
517         if (rpmsg_rpc_state.eventState [index].head == NULL) {
518             rpmsg_rpc_state.eventState [index].tail = NULL;
519         }
520     }
521     return(item);
524 /*!
525  *  @brief      Function find a specified waiting reader.
526  *
527  *  @param      index    Index of the client process waiting for the message.
528  *  @param      rcvid    Receive ID of the client process that was passed
529  *                       when the client called read().
530  *
531  *  @sa         None
532  */
534 static WaitingReaders_t *find_waiting_reader(int index, int rcvid)
536     WaitingReaders_t *item = NULL;
537     WaitingReaders_t *prev = NULL;
538     if (rpmsg_rpc_state.eventState [index].head) {
539         item = rpmsg_rpc_state.eventState [index].head;
540         while (item) {
541             if (item->rcvid == rcvid) {
542                 /* remove item from list */
543                 if (prev)
544                     prev->next = item->next;
545                 if (item == rpmsg_rpc_state.eventState [index].head)
546                     rpmsg_rpc_state.eventState [index].head = item->next;
547                 break;
548             }
549             else {
550                 prev = item;
551                 item = item->next;
552             }
553         }
554     }
555     return item;
558 /*!
559  *  @brief      Function used to check if there is a waiting reader with an
560  *              event (message) ready to be delivered.
561  *
562  *  @param      index    Index of the client process waiting for the message.
563  *  @param      item     Pointer to the waiting reader.
564  *
565  *  @sa         dequeue_notify_list_item
566  *              dequeue_waiting_reader
567  */
569 static int find_available_reader_and_event(int *index, WaitingReaders_t **item)
571     MsgList_t *temp;
572     if (rpmsg_rpc_state.head == NULL) {
573         return(0);
574     }
575     temp = rpmsg_rpc_state.head;
576     while (temp) {
577         if (rpmsg_rpc_state.eventState [temp->index].head) {
578             // event and reader found
579             if (dequeue_notify_list_item(temp) >= 0) {
580                 *index = temp->index;
581                 *item = dequeue_waiting_reader(temp->index);
582             }
583             else {
584                 /* error occurred, return 0 as item has not been set */
585                 return(0);
586             }
587             return(1);
588         }
589         temp = temp->next;
590     }
591     return(0);
594 /*!
595  *  @brief      Function used to deliver the notification to the client that
596  *              it has received a message.
597  *
598  *  @param      index    Index of the client process receiving hte message.
599  *  @param      rcvid    Receive ID of the client process that was passed
600  *                       when the client called read().
601  *
602  *  @sa         put_uBuf
603  */
605 static void deliver_notification(int index, int rcvid)
607     int err = EOK;
608     rpmsg_rpc_EventPacket * uBuf     = NULL;
610     uBuf = (rpmsg_rpc_EventPacket *) List_get (rpmsg_rpc_state.eventState [index].bufList);
612     /*  Let the check remain at run-time. */
613     if (uBuf != NULL) {
614         err = MsgReply(rcvid, uBuf->len, uBuf->data, uBuf->len);
615         if (err == -1)
616             perror("deliver_notification: MsgReply");
617         /* Free the processed event callback packet. */
618         put_uBuf(uBuf);
619     }
620     else {
621         MsgReply(rcvid, EOK, NULL, 0);
622     }
623     return;
626 /*!
627  *  @brief      Thread used for notifying waiting readers of messages.
628  *
629  *  @param      arg    Thread-specific private arg.
630  *
631  *  @sa         find_available_reader_and_event
632  *              deliver_notification
633  *              put_wr
634  */
635 static void *notifier_thread(void *arg)
637     int status;
638     int index;
639     WaitingReaders_t *item = NULL;
640     pthread_mutex_lock(&rpmsg_rpc_state.lock);
641     while (rpmsg_rpc_state.run) {
642         status = find_available_reader_and_event(&index, &item);
643         if ( (status == 0) || (item == NULL) ) {
644             status = pthread_cond_wait(&rpmsg_rpc_state.cond, &rpmsg_rpc_state.lock);
645             if ((status != EOK) && (status != EINTR)) {
646                 // false wakeup
647                 break;
648             }
649             status = find_available_reader_and_event(&index, &item);
650             if ( (status == 0) || (item == NULL) ) {
651                 continue;
652             }
653         }
654         pthread_mutex_unlock(&rpmsg_rpc_state.lock);
655         // we have unlocked, and now we have an event to deliver
656         // we deliver one event at a time, relock, check and continue
657         deliver_notification(index, item->rcvid);
658         pthread_mutex_lock(&rpmsg_rpc_state.lock);
659         put_wr(item);
660     }
661     pthread_mutex_unlock(&rpmsg_rpc_state.lock);
662     return(NULL);
666 static
667 Int
668 _rpmsg_rpc_create(resmgr_context_t *ctp, io_devctl_t *msg, rpmsg_rpc_ocb_t *ocb)
670     Int status = EOK;
671     struct rppc_create_instance * cargs =
672         (struct rppc_create_instance *)(_DEVCTL_DATA (msg->i));
673     struct rppc_create_instance * out =
674         (struct rppc_create_instance *) (_DEVCTL_DATA (msg->o));
675     struct rppc_msg_header * msg_hdr = NULL;
676     rpmsg_rpc_object * rpc = ocb->rpc;
677     Char * msg_data = NULL;
678     UInt8 buf[sizeof(struct rppc_create_instance) + sizeof(struct rppc_msg_header)];
680     if (rpc->created == TRUE) {
681         GT_0trace(curTrace, GT_4CLASS, "Already created.");
682         status = (EINVAL);
683     }
684     else if ((ctp->info.msglen - sizeof(msg->i)) <
685              sizeof (struct rppc_create_instance)) {
686         status = (EINVAL);
687     }
688     else if (String_nlen(cargs->name, 47) == -1) {
689         status = (EINVAL);
690     }
691     else {
692         msg_hdr = (struct rppc_msg_header *)buf;
693         msg_hdr->msg_type = RPPC_MSG_CREATE_INSTANCE;
694         msg_hdr->msg_len = sizeof(struct rppc_create_instance);
695         msg_data = (Char *)((UInt32)msg_hdr + sizeof(struct rppc_msg_header));
696         Memory_copy(msg_data, cargs, sizeof(struct rppc_create_instance));
698         status = MessageQCopy_send (rpc->conn->procId, // remote procid
699                                     MultiProc_self(), // local procid
700                                     rpc->conn->addr, // remote server
701                                     rpc->addr, // local address
702                                     buf, // connect msg
703                                     sizeof(buf), // msg size
704                                     TRUE); // wait for available bufs
705         if (status != MessageQCopy_S_SUCCESS) {
706             GT_0trace(curTrace, GT_4CLASS, "Failed to send create message.");
707             status = (EIO);
708         }
709         else {
710             status = OsalSemaphore_pend(rpmsg_rpc_state.sem, 5000);
711             if (rpc->created == TRUE) {
712                 msg->o.ret_val = EOK;
713                 /* Use the remote endpoint address to identify this instance */
714                 out->id = rpc->remoteAddr;
715                 status = (_RESMGR_PTR(ctp, &msg->o, sizeof(msg->o) +
716                     sizeof(struct rppc_create_instance)));
717             }
718             else if (status < 0) {
719                 GT_0trace(curTrace, GT_4CLASS, "Semaphore pend failed.");
720                 status = (EIO);
721             }
722             else {
723                 status = (ETIMEDOUT);
724             }
725         }
726     }
728     return status;
732 static
733 Int
734 _rpmsg_rpc_destroy(resmgr_context_t *ctp, io_devctl_t *msg,
735                    rpmsg_rpc_ocb_t *ocb)
737     Int status = EOK;
738     struct rppc_msg_header * hdr = NULL;
739     rpmsg_rpc_object * rpc = ocb->rpc;
740     UInt8 buf[sizeof(struct rppc_instance_handle) + sizeof(struct rppc_msg_header)];
741     struct rppc_instance_handle * instance = NULL;
743     if (rpc->created != TRUE) {
744         GT_0trace(curTrace, GT_4CLASS, "Already destroyed.");
745         status = (EINVAL);
746     }
747     else if (!rpc->conn->destroy) {
748         hdr = (struct rppc_msg_header *)buf;
749         hdr->msg_type = RPPC_MSG_DESTROY_INSTANCE;
750         hdr->msg_len = sizeof(struct rppc_instance_handle);
751         instance = (struct rppc_instance_handle *)((UInt32)hdr + sizeof(struct rppc_msg_header));
752         instance->endpoint_address = rpc->remoteAddr;
753         instance->status = 0;
755         status = MessageQCopy_send (rpc->conn->procId, // remote procid
756                                     MultiProc_self(), // local procid
757                                     rpc->conn->addr, // remote server
758                                     rpc->addr, // local address
759                                     buf, // connect msg
760                                     sizeof(buf), // msg size
761                                     TRUE); // wait for available bufs
762         if (status != MessageQCopy_S_SUCCESS) {
763             GT_0trace(curTrace, GT_4CLASS, "Failed to send disconnect message.");
764             status = (EIO);
765         }
766         else {
767             status = OsalSemaphore_pend(rpmsg_rpc_state.sem, 5000);
768             if (rpc->created != FALSE || status < 0) {
769                 GT_0trace(curTrace, GT_4CLASS, "Semaphore pend failed.");
770                 status = (EIO);
771             }
772             else {
773                 status = (ETIMEDOUT);
774             }
775         }
776     }
777     else {
778         /* This is the shutdown, remote proc has already been stopped,
779          * so just set created to false. */
780         rpc->created = FALSE;
781     }
783     return status;
787 Int
788 rpmsg_rpc_devctl(resmgr_context_t *ctp, io_devctl_t *msg, IOFUNC_OCB_T *i_ocb)
790     Int status = 0;
791     rpmsg_rpc_ocb_t *ocb = (rpmsg_rpc_ocb_t *)i_ocb;
793     if ((status = iofunc_devctl_default(ctp, msg, &ocb->hdr)) != _RESMGR_DEFAULT)
794         return(_RESMGR_ERRNO(status));
795     status = 0;
797     switch (msg->i.dcmd)
798     {
799         case RPPC_IOC_CREATE:
800             status = _rpmsg_rpc_create (ctp, msg, ocb);
801             break;
802 #if 0
803         case RPPC_IOC_DESTROY:
804             status = _rpmsg_rpc_destroy (ctp, msg, ocb);
805             break;
806 #endif
807         default:
808             status = (ENOSYS);
809             break;
810     }
812     return status;
816 /*!
817  *  @brief      Attach a process to rpmsg-rpc user support framework.
818  *
819  *  @param      pid    Process identifier
820  *
821  *  @sa         _rpmsg_rpc_detach
822  */
823 static
824 Int
825 _rpmsg_rpc_attach (rpmsg_rpc_object * rpc)
827     Int32                status   = EOK;
828     Bool                 flag     = FALSE;
829     Bool                 isInit   = FALSE;
830     List_Object *        bufList  = NULL;
831     List_Object *        fxnList  = NULL;
832     IArg                 key      = 0;
833     List_Params          listparams;
834     UInt32               i;
836     GT_1trace (curTrace, GT_ENTER, "_rpmsg_rpc_attach", rpc);
838     key = IGateProvider_enter (rpmsg_rpc_state.gateHandle);
839     for (i = 0 ; (i < MAX_PROCESSES) ; i++) {
840         if (rpmsg_rpc_state.eventState [i].rpc == rpc) {
841             rpmsg_rpc_state.eventState [i].refCount++;
842             isInit = TRUE;
843             status = EOK;
844             break;
845         }
846     }
848     if (isInit == FALSE) {
849         List_Params_init (&listparams);
850         bufList = List_create (&listparams) ;
851         fxnList = List_create (&listparams) ;
852         /* Search for an available slot for user process. */
853         for (i = 0 ; i < MAX_PROCESSES ; i++) {
854             if (rpmsg_rpc_state.eventState [i].rpc == NULL) {
855                 rpmsg_rpc_state.eventState [i].rpc = rpc;
856                 rpmsg_rpc_state.eventState [i].refCount = 1;
857                 rpmsg_rpc_state.eventState [i].bufList = bufList;
858                 rpmsg_rpc_state.eventState [i].fxnList = fxnList;
859                 flag = TRUE;
860                 break;
861             }
862         }
864         /* No free slots found. Let this check remain at run-time,
865          * since it is dependent on user environment.
866          */
867         if (flag != TRUE) {
868             /*! @retval Notify_E_RESOURCE Maximum number of
869              supported user clients have already been registered. */
870             status = -ENOMEM;
871             GT_setFailureReason (curTrace,
872                               GT_4CLASS,
873                               "rpmsgDrv_attach",
874                               status,
875                               "Maximum number of supported user"
876                                   " clients have already been "
877                                   "registered.");
878             if (bufList != NULL) {
879                 List_delete (&bufList);
880             }
881             if (fxnList != NULL) {
882                 List_delete (&fxnList);
883             }
884         }
885     }
886     IGateProvider_leave (rpmsg_rpc_state.gateHandle, key);
888     GT_1trace (curTrace, GT_LEAVE, "_rpmsg_rpc_attach", status);
890     /*! @retval Notify_S_SUCCESS Operation successfully completed. */
891     return status ;
895  /*!
896  *  @brief      This function adds a data to a registered process.
897  *
898  *  @param      dce       RPC object associated with the client
899  *  @param      src       Source address (endpoint) sending the data
900  *  @param      pid       Process ID associated with the client
901  *  @param      data      Data to be added
902  *  @param      len       Length of data to be added
903  *
904  *  @sa
905  */
906 Int
907 _rpmsg_rpc_addBufByPid (rpmsg_rpc_object *rpc,
908                         UInt32             src,
909                         UInt32             pid,
910                         UInt16             msgId,
911                         void *             data,
912                         UInt32             len)
914     Int32                   status = EOK;
915     Bool                    flag   = FALSE;
916     rpmsg_rpc_EventPacket * uBuf   = NULL;
917     IArg                    key;
918     UInt32                  i;
919     WaitingReaders_t *item;
920     MsgList_t *msgItem;
921     List_Elem * elem = NULL;
922     List_Elem * temp = NULL;
924     GT_5trace (curTrace,
925                GT_ENTER,
926                "_rpmsg_rpc_addBufByPid",
927                rpc,
928                src,
929                pid,
930                data,
931                len);
933     GT_assert (curTrace, (rpmsg_rpc_state.isSetup == TRUE));
935     key = IGateProvider_enter (rpmsg_rpc_state.gateHandle);
936     /* Find the registration for this callback */
937     for (i = 0 ; i < MAX_PROCESSES ; i++) {
938         if (rpmsg_rpc_state.eventState [i].rpc == rpc) {
939             flag = TRUE;
940             break;
941         }
942     }
943     IGateProvider_leave (rpmsg_rpc_state.gateHandle, key);
945 #if !defined(SYSLINK_BUILD_OPTIMIZE)
946     if (flag != TRUE) {
947         /*! @retval ENOMEM Could not find a registered handler
948                                       for this process. */
949         status = -ENOMEM;
950         GT_setFailureReason (curTrace,
951                              GT_4CLASS,
952                              "_rpmsgDrv_addBufByPid",
953                              status,
954                              "Could not find a registered handler "
955                              "for this process.!");
956     }
957     else {
958 #endif /* if !defined(SYSLINK_BUILD_OPTIMIZE) */
959         /* Allocate memory for the buf */
960         pthread_mutex_lock(&rpmsg_rpc_state.lock);
961         uBuf = get_uBuf();
962         pthread_mutex_unlock(&rpmsg_rpc_state.lock);
964 #if !defined(SYSLINK_BUILD_OPTIMIZE)
965         if (uBuf == NULL) {
966             /*! @retval Notify_E_MEMORY Failed to allocate memory for event
967                                 packet for received callback. */
968             status = -ENOMEM;
969             GT_setFailureReason (curTrace,
970                                  GT_4CLASS,
971                                  "_rpmsgDrv_addBufByPid",
972                                  status,
973                                  "Failed to allocate memory for event"
974                                  " packet for received callback.!");
975         }
976         else {
977 #endif /* if !defined(SYSLINK_BUILD_OPTIMIZE) */
978             key = IGateProvider_enter (rpmsg_rpc_state.gateHandle);
979             List_traverse_safe(elem, temp, rpmsg_rpc_state.eventState [i].fxnList) {
980                 if (((rpmsg_rpc_FxnInfo *)elem)->msgId == msgId) {
981                     List_remove(rpmsg_rpc_state.eventState [i].fxnList, elem);
982                     break;
983                 }
984             }
985             IGateProvider_leave (rpmsg_rpc_state.gateHandle, key);
987             if (elem != (List_Elem *)rpmsg_rpc_state.eventState [i].fxnList) {
988                 struct rppc_function * function;
989                 function = &(((rpmsg_rpc_FxnInfo *)elem)->func);
990                 _rpmsg_rpc_translate(NULL, (char *)function, pid, true);
991                 Memory_free(NULL, elem, sizeof(rpmsg_rpc_FxnInfo) +\
992                             RPPC_TRANS_SIZE(function->num_translations));
993             }
995             List_elemClear (&(uBuf->element));
996             GT_assert (curTrace,
997                        (rpmsg_rpc_state.eventState [i].bufList != NULL));
999             if (data) {
1000                 Memory_copy(uBuf->data, data, len);
1001             }
1002             uBuf->len = len;
1004             List_put (rpmsg_rpc_state.eventState [i].bufList,
1005                       &(uBuf->element));
1006             pthread_mutex_lock(&rpmsg_rpc_state.lock);
1007             item = dequeue_waiting_reader(i);
1008             if (item) {
1009                 // there is a waiting reader
1010                 deliver_notification(i, item->rcvid);
1011                 put_wr(item);
1012                 pthread_mutex_unlock(&rpmsg_rpc_state.lock);
1013                 status = EOK;
1014             }
1015             else {
1016                 if (enqueue_notify_list(i) < 0) {
1017                     pthread_mutex_unlock(&rpmsg_rpc_state.lock);
1018                     status = -ENOMEM;
1019                     GT_setFailureReason (curTrace,
1020                                   GT_4CLASS,
1021                                   "_rpmsgDrv_addBufByPid",
1022                                   status,
1023                                   "Failed to allocate memory for notifier");
1024                 }
1025                 else {
1026                     msgItem = find_nl(i);
1027                     /* TODO: rpc could be NULL in some cases  */
1028                     if (rpc && msgItem) {
1029                         if (IOFUNC_NOTIFY_INPUT_CHECK(rpc->notify, msgItem->num_events, 0)) {
1030                             iofunc_notify_trigger(rpc->notify, msgItem->num_events, IOFUNC_NOTIFY_INPUT);
1031                         }
1032                     }
1033                     status = EOK;
1034                     pthread_cond_signal(&rpmsg_rpc_state.cond);
1035                     pthread_mutex_unlock(&rpmsg_rpc_state.lock);
1036                 }
1037             }
1038 #if !defined(SYSLINK_BUILD_OPTIMIZE)
1039         }
1040     }
1041 #endif /* if !defined(SYSLINK_BUILD_OPTIMIZE) */
1043     GT_1trace (curTrace, GT_LEAVE, "_rpmsgDrv_addBufByPid", status);
1045     return status;
1049 /*!
1050  *  @brief      This function implements the callback registered with
1051  *              MessageQCopy_create for each client.  This function
1052  *              adds the message from the remote proc to a list
1053  *              where it is routed to the appropriate waiting reader.
1054  *
1055  *  @param      procId    processor Id from which interrupt is received
1056  *  @param      lineId    Interrupt line ID to be used
1057  *  @param      eventId   eventId registered
1058  *  @param      arg       argument to call back
1059  *  @param      payload   payload received
1060  *
1061  *  @sa
1062  */
1063 Void
1064 _rpmsg_rpc_cb (MessageQCopy_Handle handle, void * data, int len, void * priv,
1065                UInt32 src, UInt16 srcProc)
1067 #if !defined(SYSLINK_BUILD_OPTIMIZE)
1068     Int32                   status = 0;
1069 #endif /* if !defined(SYSLINK_BUILD_OPTIMIZE) */
1070     rpmsg_rpc_object * rpc = NULL;
1071     struct rppc_msg_header * msg_hdr = NULL;
1072     struct rppc_instance_handle * instance;
1073     struct rppc_packet * packet = NULL;
1075     GT_6trace (curTrace,
1076                GT_ENTER,
1077                "_rpmsg_rpc_cb",
1078                handle,
1079                data,
1080                len,
1081                priv,
1082                src,
1083                srcProc);
1085     if (len < sizeof(struct rppc_msg_header)) {
1086         status = EINVAL;
1087         GT_setFailureReason(curTrace, GT_4CLASS, "_rpmsg_rpc_cb", status,
1088                             "len is smaller than sizeof rppc_msg_header");
1089         return;
1090     }
1092     rpc = (rpmsg_rpc_object *) priv;
1093     msg_hdr = (struct rppc_msg_header *)data;
1095     switch (msg_hdr->msg_type) {
1096         case RPPC_MSG_INSTANCE_CREATED:
1097             if (msg_hdr->msg_len != sizeof(struct rppc_instance_handle)) {
1098                 status = EINVAL;
1099                 rpc->created = FALSE;
1100                 GT_setFailureReason(curTrace, GT_4CLASS, "_rpmsg_rpc_cb",
1101                                     status, "msg_len is invalid");
1102             }
1103             else {
1104                 instance = (struct rppc_instance_handle *)
1105                           ((UInt32)msg_hdr + sizeof(struct rppc_msg_header));
1106                 rpc->remoteAddr = instance->endpoint_address;
1107                 if (instance->status != 0) {
1108                     rpc->created = FALSE;
1109                 }
1110                 else {
1111                     rpc->created = TRUE;
1112                 }
1113             }
1114             /* post the semaphore to have the ioctl reply */
1115             OsalSemaphore_post(rpmsg_rpc_state.sem);
1116             break;
1117         case RPPC_MSG_INSTANCE_DESTROYED:
1118             if (msg_hdr->msg_len != sizeof(struct rppc_instance_handle)) {
1119                 status = EINVAL;
1120                 rpc->created = FALSE;
1121                 GT_setFailureReason(curTrace, GT_4CLASS, "_rpmsg_rpc_cb",
1122                                     status, "msg_len is invalid");
1123             }
1124             else {
1125                 instance = (struct rppc_instance_handle *)
1126                           ((UInt32)msg_hdr + sizeof(struct rppc_msg_header));
1127                 rpc->remoteAddr = instance->endpoint_address;
1128                 if (instance->status != 0) {
1129                     rpc->created = TRUE;
1130                 }
1131                 else {
1132                     rpc->created = FALSE;
1133                 }
1134             }
1135             /* post the semaphore to have the ioctl reply */
1136             OsalSemaphore_post(rpmsg_rpc_state.sem);
1137             break;
1139         case RPPC_MSG_CALL_FUNCTION:
1140             if ((len != sizeof(struct rppc_msg_header) + msg_hdr->msg_len) ||
1141                 (msg_hdr->msg_len < sizeof(struct rppc_packet))) {
1142                 status = EINVAL;
1143                 GT_setFailureReason(curTrace, GT_4CLASS, "_rpmsg_rpc_cb",
1144                                     status, "msg_len is invalid");
1145             }
1146             packet = (struct rppc_packet *)((UInt32)msg_hdr + sizeof(struct rppc_msg_header));
1147             if (len != sizeof(struct rppc_msg_header) + sizeof(struct rppc_packet) + packet->data_size) {
1148                 status = EINVAL;
1149                 GT_setFailureReason(curTrace, GT_4CLASS, "_rpmsg_rpc_cb",
1150                                     status, "msg_len is invalid");
1151             }
1152 #if !defined(SYSLINK_BUILD_OPTIMIZE)
1153             status =
1154 #endif /* if !defined(SYSLINK_BUILD_OPTIMIZE) */
1155             _rpmsg_rpc_addBufByPid (rpc,
1156                                     src,
1157                                     rpc->pid,
1158                                     packet->msg_id,
1159                                     &packet->fxn_id,
1160                                     sizeof(packet->fxn_id) + sizeof(packet->result));
1161 #if !defined(SYSLINK_BUILD_OPTIMIZE)
1162             if (status < 0) {
1163                 GT_setFailureReason (curTrace,
1164                                      GT_4CLASS,
1165                                      "_rpmsg_rpc_cb",
1166                                      status,
1167                                      "Failed to add callback packet for pid");
1168             }
1169 #endif /* if !defined(SYSLINK_BUILD_OPTIMIZE) */
1170             break;
1171         default:
1172             break;
1173     }
1175     GT_0trace (curTrace, GT_LEAVE, "_rpmsg_rpc_cb");
1178  /**
1179   * Handler for ocb_calloc() requests.
1180   *
1181   * Special handler for ocb_calloc() requests that we export for control.  An
1182   * open request from the client will result in a call to our special ocb_calloc
1183   * handler.  This function attaches the client's pid using _rpmsg_dce_attach
1184   * and allocates client-specific information.  This function creates an
1185   * endpoint for the client to communicate with the dCE server on the
1186   * remote core also.
1187   *
1188   * \param ctp       Thread's associated context information.
1189   * \param device    Device attributes structure.
1190   *
1191   * \return Pointer to an iofunc_ocb_t OCB structure.
1192   */
1194 IOFUNC_OCB_T *
1195 rpmsg_rpc_ocb_calloc (resmgr_context_t * ctp, IOFUNC_ATTR_T * device)
1197     rpmsg_rpc_ocb_t *ocb = NULL;
1198     rpmsg_rpc_object *obj = NULL;
1199     struct _msg_info cl_info;
1200     rpmsg_rpc_dev_t * dev = NULL;
1201     int i = 0;
1202     Bool found = FALSE;
1203     char path1[20];
1204     char path2[20];
1206     GT_2trace (curTrace, GT_ENTER, "rpmsg_rpc_ocb_calloc",
1207                ctp, device);
1209     /* Allocate the OCB */
1210     ocb = (rpmsg_rpc_ocb_t *) calloc (1, sizeof (rpmsg_rpc_ocb_t));
1211     if (ocb == NULL){
1212         errno = ENOMEM;
1213         return (NULL);
1214     }
1216     ocb->pid = ctp->info.pid;
1218     /* Allocate memory for the rpmsg object. */
1219     obj = Memory_calloc (NULL, sizeof (rpmsg_rpc_object), 0u, NULL);
1220     if (obj == NULL) {
1221         errno = ENOMEM;
1222         free(ocb);
1223         return (NULL);
1224     }
1225     else {
1226         ocb->rpc = obj;
1227         IOFUNC_NOTIFY_INIT(obj->notify);
1228         obj->created = FALSE;
1229         /* determine conn and procId for communication based on which device
1230          * was opened */
1231         MsgInfo(ctp->rcvid, &cl_info);
1232         resmgr_pathname(ctp->id, 0, path1, sizeof(path1));
1233         for (i = 0; i < MAX_CONNS; i++) {
1234             if (rpmsg_rpc_state.objects[i] != NULL) {
1235                 dev = rpmsg_rpc_state.objects[i]->dev;
1236                 resmgr_pathname(dev->rpmsg_rpc.resmgr_id, 0, path2,
1237                                 sizeof(path2));
1238                 if (!strcmp(path1, path2)) {
1239                     found = TRUE;
1240                     break;
1241                 }
1242             }
1243         }
1244         if (found) {
1245             obj->conn = rpmsg_rpc_state.objects[i];
1246             obj->procId = obj->conn->procId;
1247             obj->pid = ctp->info.pid;
1248             obj->mq = MessageQCopy_create (MessageQCopy_ADDRANY, NULL,
1249                                            _rpmsg_rpc_cb, obj, &obj->addr);
1250             if (obj->mq == NULL) {
1251                 errno = ENOMEM;
1252                 free(obj);
1253                 free(ocb);
1254                 return (NULL);
1255             }
1256             else {
1257                 if (_rpmsg_rpc_attach (ocb->rpc) < 0) {
1258                     errno = ENOMEM;
1259                     MessageQCopy_delete (&obj->mq);
1260                     free(obj);
1261                     free(ocb);
1262                     return (NULL);
1263                 }
1264             }
1265         }
1266     }
1268     GT_1trace (curTrace, GT_LEAVE, "rpmsg_rpc_ocb_calloc", ocb);
1270     return (IOFUNC_OCB_T *)(ocb);
1274 /*!
1275  *  @brief      Detach a process from rpmsg-rpc user support framework.
1276  *
1277  *  @param      pid    Process identifier
1278  *
1279  *  @sa         _rpmsg_rpc_attach
1280  */
1281 static
1282 Int
1283 _rpmsg_rpc_detach (rpmsg_rpc_object * rpc)
1285     Int32                status    = EOK;
1286     Int32                tmpStatus = EOK;
1287     Bool                 flag      = FALSE;
1288     List_Object *        bufList   = NULL;
1289     List_Object *        fxnList   = NULL;
1290     UInt32               i;
1291     IArg                 key;
1292     MsgList_t          * item;
1293     WaitingReaders_t   * wr        = NULL;
1294     struct _msg_info     info;
1296     GT_1trace (curTrace, GT_ENTER, "rpmsg_rpc_detach", rpc);
1298     key = IGateProvider_enter (rpmsg_rpc_state.gateHandle);
1300     for (i = 0 ; i < MAX_PROCESSES ; i++) {
1301         if (rpmsg_rpc_state.eventState [i].rpc == rpc) {
1302             if (rpmsg_rpc_state.eventState [i].refCount == 1) {
1303                 rpmsg_rpc_state.eventState [i].refCount = 0;
1305                 flag = TRUE;
1306                 break;
1307             }
1308             else {
1309                 rpmsg_rpc_state.eventState [i].refCount--;
1310                 status = EOK;
1311                 break;
1312             }
1313         }
1314     }
1315     IGateProvider_leave (rpmsg_rpc_state.gateHandle, key);
1317     if (flag == TRUE) {
1318         key = IGateProvider_enter (rpmsg_rpc_state.gateHandle);
1319         /* Last client being unregistered for this process. */
1320         rpmsg_rpc_state.eventState [i].rpc = NULL;
1322         /* Store in local variable to delete outside lock. */
1323         bufList = rpmsg_rpc_state.eventState [i].bufList;
1325         rpmsg_rpc_state.eventState [i].bufList = NULL;
1327         /* Store in local variable to delete outside lock. */
1328         fxnList = rpmsg_rpc_state.eventState [i].fxnList;
1330         rpmsg_rpc_state.eventState [i].fxnList = NULL;
1332         IGateProvider_leave (rpmsg_rpc_state.gateHandle, key);
1333     }
1335     if (flag != TRUE) {
1336 #if !defined(SYSLINK_BUILD_OPTIMIZE)
1337         if (i == MAX_PROCESSES) {
1338             /*! @retval Notify_E_NOTFOUND The specified user process was
1339                      not found registered with Notify Driver module. */
1340             status = -ENOMEM;
1341             GT_setFailureReason (curTrace,
1342                               GT_4CLASS,
1343                               "rpmsg_rpc_detach",
1344                               status,
1345                               "The specified user process was not found"
1346                               " registered with rpmsg Driver module.");
1347         }
1348 #endif /* if !defined(SYSLINK_BUILD_OPTIMIZE) */
1349     }
1350     else {
1351         if (bufList != NULL) {
1352             /* Dequeue waiting readers and reply to them */
1353             pthread_mutex_lock(&rpmsg_rpc_state.lock);
1354             while ((wr = dequeue_waiting_reader(i)) != NULL) {
1355                 /* Check if rcvid is still valid */
1356                 if (MsgInfo(wr->rcvid, &info) != -1) {
1357                     put_wr(wr);
1358                     pthread_mutex_unlock(&rpmsg_rpc_state.lock);
1359                     MsgError(wr->rcvid, EINTR);
1360                     pthread_mutex_lock(&rpmsg_rpc_state.lock);
1361                 }
1362             }
1363             /* Check for pending ionotify/select calls */
1364             if (rpc) {
1365                 if (IOFUNC_NOTIFY_INPUT_CHECK(rpc->notify, 1, 0)) {
1366                     iofunc_notify_trigger(rpc->notify, 1, IOFUNC_NOTIFY_INPUT);
1367                 }
1368             }
1370             /* Free event packets for any received but unprocessed events. */
1371             while ((item = find_nl(i)) != NULL) {
1372                 if (dequeue_notify_list_item(item) >= 0) {
1373                     rpmsg_rpc_EventPacket * uBuf = NULL;
1375                     uBuf = (rpmsg_rpc_EventPacket *) List_get (bufList);
1377                     /*  Let the check remain at run-time. */
1378                     if (uBuf != NULL) {
1379                         put_uBuf(uBuf);
1380                     }
1381                 }
1382             }
1383             pthread_mutex_unlock(&rpmsg_rpc_state.lock);
1385             /* Last client being unregistered with Notify module. */
1386             List_delete (&bufList);
1387         }
1388         if (fxnList != NULL) {
1389             key = IGateProvider_enter (rpmsg_rpc_state.gateHandle);
1390             rpmsg_rpc_FxnInfo * fxnInfo = NULL;
1391             while ((fxnInfo = (rpmsg_rpc_FxnInfo *)List_dequeue (fxnList))) {
1392                 Memory_free (NULL, fxnInfo, sizeof(rpmsg_rpc_FxnInfo) +\
1393                              RPPC_TRANS_SIZE(fxnInfo->func.num_translations));
1394             }
1395             IGateProvider_leave (rpmsg_rpc_state.gateHandle, key);
1396             List_delete (&fxnList);
1397         }
1399 #if !defined(SYSLINK_BUILD_OPTIMIZE)
1400         if ((tmpStatus < 0) && (status >= 0)) {
1401             status =  tmpStatus;
1402             GT_setFailureReason (curTrace,
1403                              GT_4CLASS,
1404                              "rpmsg_rpc_detach",
1405                              status,
1406                              "Failed to delete termination semaphore!");
1407         }
1408 #endif /* if !defined(SYSLINK_BUILD_OPTIMIZE) */
1409     }
1411     GT_1trace (curTrace, GT_LEAVE, "rpmsg_rpc_detach", status);
1413     /*! @retval Notify_S_SUCCESS Operation successfully completed */
1414     return status;
1417  /**
1418   * Handler for ocb_free() requests.
1419   *
1420   * Special handler for ocb_free() requests that we export for control.  A
1421   * close request from the client will result in a call to our special ocb_free
1422   * handler.  This function detaches the client's pid using _rpmsg_dce_detach
1423   * and frees any client-specific information that was allocated.
1424   *
1425   * \param i_ocb     OCB associated with client's session.
1426   *
1427   * \return POSIX errno value.
1428   *
1429   * \retval None.
1430   */
1432 void
1433 rpmsg_rpc_ocb_free (IOFUNC_OCB_T * i_ocb)
1435     rpmsg_rpc_ocb_t * ocb = (rpmsg_rpc_ocb_t *)i_ocb;
1436     rpmsg_rpc_object *obj;
1438     if (ocb && ocb->rpc) {
1439         obj = ocb->rpc;
1440         if (obj->created == TRUE) {
1441             /* Need to disconnect this device */
1442             _rpmsg_rpc_destroy(NULL, NULL, ocb);
1443         }
1444         _rpmsg_rpc_detach(ocb->rpc);
1445         if (obj->mq) {
1446             MessageQCopy_delete (&obj->mq);
1447             obj->mq = NULL;
1448         }
1449         free (obj);
1450         free (ocb);
1451     }
1454  /**
1455   * Handler for close_ocb() requests.
1456   *
1457   * This function removes the notification entries associated with the current
1458   * client.
1459   *
1460   * \param ctp       Thread's associated context information.
1461   * \param reserved  This argument must be NULL.
1462   * \param ocb       OCB associated with client's session.
1463   *
1464   * \return POSIX errno value.
1465   *
1466   * \retval EOK      Success.
1467   */
1469 Int
1470 rpmsg_rpc_close_ocb (resmgr_context_t *ctp, void *reserved, RESMGR_OCB_T *ocb)
1472     rpmsg_rpc_ocb_t * rpc_ocb = (rpmsg_rpc_ocb_t *)ocb;
1473     iofunc_notify_remove(ctp, rpc_ocb->rpc->notify);
1474     return (iofunc_close_ocb_default(ctp, reserved, ocb));
1477  /**
1478   * Handler for read() requests.
1479   *
1480   * Handles special read() requests that we export for control.  A read
1481   * request will get a message from the remote processor that is associated
1482   * with the client that is calling read().
1483   *
1484   * \param ctp     Thread's associated context information.
1485   * \param msg     The actual read() message.
1486   * \param ocb     OCB associated with client's session.
1487   *
1488   * \return POSIX errno value.
1489   *
1490   * \retval EOK      Success.
1491   * \retval EAGAIN   Call is non-blocking and no messages available.
1492   * \retval ENOMEM   Not enough memory to preform the read.
1493   */
1495 int rpmsg_rpc_read(resmgr_context_t *ctp, io_read_t *msg, RESMGR_OCB_T *ocb)
1497     Int status;
1498     rpmsg_rpc_ocb_t * rpc_ocb = (rpmsg_rpc_ocb_t *)ocb;
1499     rpmsg_rpc_object * rpc = rpc_ocb->rpc;
1500     Bool                    flag     = FALSE;
1501     Int                  retVal   = EOK;
1502     UInt32                  i;
1503     MsgList_t          * item;
1504     Int                  nonblock;
1506     if ((status = iofunc_read_verify(ctp, msg, ocb, &nonblock)) != EOK)
1507         return (status);
1509     if (rpc->created != TRUE) {
1510         return (ENOTCONN);
1511     }
1513     for (i = 0 ; i < MAX_PROCESSES ; i++) {
1514         if (rpmsg_rpc_state.eventState [i].rpc == rpc) {
1515             flag = TRUE;
1516             break;
1517         }
1518     }
1520     /* Let the check remain at run-time. */
1521     if (flag == TRUE) {
1522         /* Let the check remain at run-time for handling any run-time
1523         * race conditions.
1524         */
1525         if (rpmsg_rpc_state.eventState [i].bufList != NULL) {
1526             pthread_mutex_lock(&rpmsg_rpc_state.lock);
1527             item = find_nl(i);
1528             if (dequeue_notify_list_item(item) < 0) {
1529                 if (nonblock) {
1530                     pthread_mutex_unlock(&rpmsg_rpc_state.lock);
1531                     return EAGAIN;
1532                 }
1533                 else {
1534                     retVal = enqueue_waiting_reader(i, ctp->rcvid);
1535                     if (retVal == EOK) {
1536                         pthread_cond_signal(&rpmsg_rpc_state.cond);
1537                         pthread_mutex_unlock(&rpmsg_rpc_state.lock);
1538                         return(_RESMGR_NOREPLY);
1539                     }
1540                     retVal = ENOMEM;
1541                     pthread_mutex_unlock(&rpmsg_rpc_state.lock);
1542                 }
1543             }
1544             else {
1545                 deliver_notification(i, ctp->rcvid);
1546                 pthread_mutex_unlock(&rpmsg_rpc_state.lock);
1547                 return(_RESMGR_NOREPLY);
1548             }
1549         }
1550     }
1552     /*! @retval Number-of-bytes-read Number of bytes read. */
1553     return retVal;
1556  /**
1557   * Unblock read calls
1558   *
1559   * This function checks if the client is blocked on a read call and if so,
1560   * unblocks the client.
1561   *
1562   * \param ctp     Thread's associated context information.
1563   * \param msg     The pulse message.
1564   * \param ocb     OCB associated with client's session.
1565   *
1566   * \return POSIX errno value.
1567   *
1568   * \retval EINTR    The client has been unblocked.
1569   * \retval other    The client has not been unblocked or the client was not
1570   *                  blocked.
1571   */
1573 int rpmsg_rpc_read_unblock(resmgr_context_t *ctp, io_pulse_t *msg, iofunc_ocb_t *ocb)
1575     UInt32                  i;
1576     Bool                    flag     = FALSE;
1577     WaitingReaders_t      * wr;
1578     rpmsg_rpc_ocb_t * rpc_ocb = (rpmsg_rpc_ocb_t *)ocb;
1579     rpmsg_rpc_object * rpc = rpc_ocb->rpc;
1581     for (i = 0 ; i < MAX_PROCESSES ; i++) {
1582         if (rpmsg_rpc_state.eventState [i].rpc == rpc) {
1583             flag = TRUE;
1584             break;
1585         }
1586     }
1588     /*  Let the check remain at run-time. */
1589     if (flag == TRUE) {
1590         /* Let the check remain at run-time for handling any run-time
1591          * race conditions.
1592          */
1593         if (rpmsg_rpc_state.eventState [i].bufList != NULL) {
1594             pthread_mutex_lock(&rpmsg_rpc_state.lock);
1595             wr = find_waiting_reader(i, ctp->rcvid);
1596             if (wr) {
1597                 put_wr(wr);
1598                 pthread_mutex_unlock(&rpmsg_rpc_state.lock);
1599                 return (EINTR);
1600             }
1601             pthread_mutex_unlock(&rpmsg_rpc_state.lock);
1602         }
1603     }
1605     return _RESMGR_NOREPLY;
1608 /**
1609   * Handler for unblock() requests.
1610   *
1611   * Handles unblock request for the client which is requesting to no longer be
1612   * blocked on the rpmsg-rpc driver.
1613   *
1614   * \param ctp     Thread's associated context information.
1615   * \param msg     The pulse message.
1616   * \param ocb     OCB associated with client's session.
1617   *
1618   * \return POSIX errno value.
1619   *
1620   * \retval EINTR    The rcvid has been unblocked.
1621   */
1623 int rpmsg_rpc_unblock(resmgr_context_t *ctp, io_pulse_t *msg, RESMGR_OCB_T *ocb)
1625     int status = _RESMGR_NOREPLY;
1626     struct _msg_info        info;
1628     /*
1629      * Try to run the default unblock for this message.
1630      */
1631     if ((status = iofunc_unblock_default(ctp,msg,ocb)) != _RESMGR_DEFAULT) {
1632         return status;
1633     }
1635     /*
1636      * Check if rcvid is still valid and still has an unblock
1637      * request pending.
1638      */
1639     if (MsgInfo(ctp->rcvid, &info) == -1 ||
1640         !(info.flags & _NTO_MI_UNBLOCK_REQ)) {
1641         return _RESMGR_NOREPLY;
1642     }
1644     if (rpmsg_rpc_read_unblock(ctp, msg, ocb) != _RESMGR_NOREPLY) {
1645            return _RESMGR_ERRNO(EINTR);
1646     }
1648     return _RESMGR_ERRNO(EINTR);
1652 uint32_t
1653 _rpmsg_rpc_pa2da(ProcMgr_Handle handle, uint32_t pa)
1655     Int status = 0;
1656     uint32_t da;
1658     status = ProcMgr_translateAddr(handle, (Ptr *)&da,
1659                                    ProcMgr_AddrType_SlaveVirt,
1660                                    (Ptr)pa, ProcMgr_AddrType_MasterPhys);
1661     if (status >= 0) {
1662         return da;
1663     }
1664     else {
1665         return 0;
1666     }
1669 int
1670 _rpmsg_rpc_translate(ProcMgr_Handle handle, char *data, pid_t pid, bool reverse)
1672     int status = EOK;
1673     struct rppc_function * function = NULL;
1674     struct rppc_param_translation * translation = NULL;
1675     int i = 0;
1676     off64_t phys_addr;
1677     off64_t paddr[RPPC_MAX_PARAMETERS];
1678     uint32_t ipu_addr;
1679     size_t phys_len = 0;
1680     uintptr_t ptr;
1681     void * vptr[RPPC_MAX_PARAMETERS];
1682     uint32_t idx = 0;
1684     function = (struct rppc_function *)data;
1685     memset(vptr, 0, sizeof(void *) * RPPC_MAX_PARAMETERS);
1686     memset(paddr, 0, sizeof(off64_t) * RPPC_MAX_PARAMETERS);
1688     translation = (struct rppc_param_translation *)function->translations;
1689     for (i = 0; i < function->num_translations; i++) {
1690         idx = translation[i].index;
1691         if (idx >= function->num_params) {
1692             status = -EINVAL;
1693             break;
1694         }
1695         if (translation[i].offset + sizeof(uint32_t) > function->params[idx].size) {
1696             status = -EINVAL;
1697             break;
1698         }
1699         if (!vptr[idx]) {
1700             /* get the physical address of ptr */
1701             status = mem_offset64_peer(pid,
1702                                        reverse ? function->params[idx].base : function->params[idx].data,
1703                                        function->params[idx].size,
1704                                        &paddr[idx], &phys_len);
1705             if (status >= 0 && phys_len == function->params[idx].size) {
1706                 /* map into my process space */
1707                 vptr[idx] = mmap64(NULL, function->params[idx].size,
1708                                    PROT_NOCACHE | PROT_READ | PROT_WRITE,
1709                                    MAP_PHYS, NOFD, paddr[idx]);
1710                 if (vptr[idx] == MAP_FAILED) {
1711                     vptr[idx] = 0;
1712                     status = -ENOMEM;
1713                     break;
1714                 }
1715             }
1716             else {
1717                 status = -EINVAL;
1718                 break;
1719             }
1720         }
1721         /* Get physical address of the contents */
1722         ptr = (uint32_t)vptr[idx] + translation[i].offset;
1723         if (reverse) {
1724             *(uint32_t *)ptr = translation[i].base;
1725         }
1726         else {
1727             translation[i].base = *(uint32_t *)ptr;
1728             status = mem_offset64_peer(pid, *(uint32_t *)ptr, sizeof(uint32_t),
1729                                        &phys_addr, &phys_len);
1730             if (status >= 0 && phys_len == sizeof(uint32_t)) {
1731                 /* translate pa2da */
1732                 if ((ipu_addr =
1733                         _rpmsg_rpc_pa2da(handle, (uint32_t)phys_addr)) != 0)
1734                     /* update vptr contents */
1735                     *(uint32_t *)ptr = ipu_addr;
1736                 else {
1737                     status = -EINVAL;
1738                     break;
1739                 }
1740             }
1741             else {
1742                 status = -EINVAL;
1743                 break;
1744             }
1745         }
1746     }
1748     /* No need to do this for reverse translations */
1749     for (i = 0; i < function->num_params && status >= 0 && !reverse; i++) {
1750         if (function->params[i].type == RPPC_PARAM_TYPE_PTR) {
1751             if (paddr[i]) {
1752                 phys_addr = paddr[i];
1753             }
1754             else {
1755                 /* translate the param pointer */
1756                 status = mem_offset64_peer(pid,
1757                                            (uintptr_t)(function->params[i].data),
1758                                            function->params[i].size, &phys_addr,
1759                                            &phys_len);
1760             }
1761             if (status >= 0) {
1762                 if ((ipu_addr =
1763                             _rpmsg_rpc_pa2da(handle, (uint32_t)phys_addr)) != 0) {
1764                     function->params[i].base = function->params[i].data;
1765                     function->params[i].data = ipu_addr;
1766                 }
1767                 else {
1768                     status = -EINVAL;
1769                     break;
1770                 }
1771             }
1772             else {
1773                 status = -EINVAL;
1774                 break;
1775             }
1776         }
1777     }
1779     for (i = 0; i < function->num_params; i++) {
1780         if (vptr[i])
1781             munmap(vptr[i], function->params[i].size);
1782     }
1784     return status;
1787  /**
1788   * Handler for write() requests.
1789   *
1790   * Handles special write() requests that we export for control.  A write()
1791   * request will send a message to the remote processor which is associated with
1792   * the client.
1793   *
1794   * \param ctp     Thread's associated context information.
1795   * \param msg     The actual write() message.
1796   * \param io_ocb  OCB associated with client's session.
1797   *
1798   * \return POSIX errno value.
1799   *
1800   * \retval EOK      Success.
1801   * \retval ENOMEM   Not enough memory to preform the write.
1802   * \retval EIO      MessageQCopy_send failed.
1803   * \retval EINVAL   msg->i.bytes is negative.
1804   */
1806 int
1807 rpmsg_rpc_write(resmgr_context_t *ctp, io_write_t *msg, RESMGR_OCB_T *io_ocb)
1809     int status;
1810     char buf[MessageQCopy_BUFSIZE];
1811     int bytes;
1812     rpmsg_rpc_ocb_t * ocb = (rpmsg_rpc_ocb_t *)io_ocb;
1813     rpmsg_rpc_object * rpc = ocb->rpc;
1814     struct rppc_msg_header * msg_hdr = NULL;
1815     struct rppc_packet *packet = NULL;
1816     struct rppc_function *function = NULL;
1817     char usr_msg[MessageQCopy_BUFSIZE];
1818     int i = 0;
1819     rpmsg_rpc_EventState * event_state = NULL;
1820     rpmsg_rpc_FxnInfo * fxn_info = NULL;
1821     IArg key = 0;
1823     if ((status = iofunc_write_verify(ctp, msg, io_ocb, NULL)) != EOK) {
1824         return (status);
1825     }
1827     bytes = ((int64_t) msg->i.nbytes) + sizeof(struct rppc_msg_header) > MessageQCopy_BUFSIZE ?
1828             MessageQCopy_BUFSIZE - sizeof(struct rppc_msg_header) : msg->i.nbytes;
1829     if (bytes < 0) {
1830         return EINVAL;
1831     }
1832     _IO_SET_WRITE_NBYTES (ctp, bytes);
1834     for (i = 0 ; i < MAX_PROCESSES ; i++) {
1835         if (rpmsg_rpc_state.eventState [i].rpc == rpc) {
1836             break;
1837         }
1838     }
1839     if (i == MAX_PROCESSES) {
1840         return EINVAL;
1841     }
1842     event_state = &rpmsg_rpc_state.eventState[i];
1844     msg_hdr = (struct rppc_msg_header *)buf;
1845     packet = (struct rppc_packet *)((UInt32)msg_hdr + sizeof(struct rppc_msg_header));
1847     status = resmgr_msgread(ctp, usr_msg, bytes, sizeof(msg->i));
1848     if (status != bytes) {
1849         return (errno);
1850     }
1851     else if (bytes < sizeof(struct rppc_function)) {
1852         return (EINVAL);
1853     }
1854     function = (struct rppc_function *)usr_msg;
1856     if (bytes < RPPC_PARAM_SIZE(function->num_translations)) {
1857          return (EINVAL);
1858     }
1860     /* check that we're in the correct state */
1861     if (rpc->created != TRUE) {
1862         return (EINVAL);
1863     }
1865     /* store the fxn info for use with reverse translation */
1866     fxn_info = Memory_alloc (NULL, sizeof(rpmsg_rpc_FxnInfo) +\
1867                              RPPC_TRANS_SIZE(function->num_translations),
1868                              0, NULL);
1869     List_elemClear(&(fxn_info->element));
1870     Memory_copy (&(fxn_info->func), function,
1871                  RPPC_PARAM_SIZE(function->num_translations));
1873     status = _rpmsg_rpc_translate(rpc->conn->procH, (char *)&(fxn_info->func),
1874                                   ctp->info.pid, false);
1875     if (status < 0) {
1876         Memory_free(NULL, fxn_info, sizeof(rpmsg_rpc_FxnInfo) +\
1877                     RPPC_TRANS_SIZE(function->num_translations));
1878         return -status;
1879     }
1881     msg_hdr->msg_type = RPPC_MSG_CALL_FUNCTION;
1882     msg_hdr->msg_len = sizeof(struct rppc_packet);
1884     /* initialize the packet structure */
1885     packet->desc = RPPC_DESC_EXEC_SYNC;
1886     packet->msg_id = msg_id == 0xFFFF ? msg_id = 1 : ++(msg_id);
1887     packet->flags = (0x8000);//OMAPRPC_POOLID_DEFAULT;
1888     packet->fxn_id = RPPC_SET_FXN_IDX(function->fxn_id);
1889     packet->result = 0;
1890     packet->data_size = 0;
1892     for (i = 0; i < function->num_params; i++) {
1893         ((UInt32 *)(packet->data))[i*2] = function->params[i].size;
1894         ((UInt32 *)(packet->data))[(i*2)+1] = fxn_info->func.params[i].data;
1895         packet->data_size += (sizeof(UInt32) * 2);
1896     }
1897     msg_hdr->msg_len += packet->data_size;
1899     fxn_info->msgId = packet->msg_id;
1900     key = IGateProvider_enter (rpmsg_rpc_state.gateHandle);
1901     List_enqueue(event_state->fxnList, &(fxn_info->element));
1902     IGateProvider_leave (rpmsg_rpc_state.gateHandle, key);
1904     status = MessageQCopy_send(rpc->conn->procId, MultiProc_self(),
1905                               rpc->remoteAddr, rpc->addr, buf,
1906                               msg_hdr->msg_len + sizeof(struct rppc_msg_header),
1907                               TRUE);
1908     if (status < 0) {
1909         key = IGateProvider_enter (rpmsg_rpc_state.gateHandle);
1910         List_remove(event_state->fxnList, &(fxn_info->element));
1911         IGateProvider_leave (rpmsg_rpc_state.gateHandle, key);
1912         Memory_free(NULL, fxn_info, sizeof(rpmsg_rpc_FxnInfo) +\
1913                     RPPC_TRANS_SIZE(function->num_translations));
1914         return (EIO);
1915     }
1917     return(EOK);
1922  /**
1923   * Handler for notify() requests.
1924   *
1925   * Handles special notify() requests that we export for control.  A notify
1926   * request results from the client calling select().
1927   *
1928   * \param ctp     Thread's associated context information.
1929   * \param msg     The actual notify() message.
1930   * \param ocb     OCB associated with client's session.
1931   *
1932   * \return POSIX errno value.
1933   */
1935 Int rpmsg_rpc_notify( resmgr_context_t *ctp, io_notify_t *msg, RESMGR_OCB_T *ocb)
1937     rpmsg_rpc_ocb_t * rpc_ocb = (rpmsg_rpc_ocb_t *)ocb;
1938     rpmsg_rpc_object * rpc = rpc_ocb->rpc;
1939     int trig;
1940     int i = 0;
1941     Bool flag = FALSE;
1942     MsgList_t * item = NULL;
1943     int status = EOK;
1945     trig = _NOTIFY_COND_OUTPUT; /* clients can give us data */
1947     for (i = 0 ; i < MAX_PROCESSES ; i++) {
1948         if (rpmsg_rpc_state.eventState [i].rpc == rpc) {
1949             flag = TRUE;
1950             break;
1951         }
1952     }
1954     pthread_mutex_lock(&rpmsg_rpc_state.lock);
1955     /* Let the check remain at run-time. */
1956     if (flag == TRUE) {
1957         /* Let the check remain at run-time for handling any run-time
1958         * race conditions.
1959         */
1960         if (rpmsg_rpc_state.eventState [i].bufList != NULL) {
1961             item = find_nl(i);
1962             if (item && item->num_events > 0) {
1963                 trig |= _NOTIFY_COND_INPUT;
1964             }
1965         }
1966     }
1967     status = iofunc_notify(ctp, msg, rpc_ocb->rpc->notify, trig, NULL, NULL);
1968     pthread_mutex_unlock(&rpmsg_rpc_state.lock);
1969     return status;
1972  /**
1973   * Detaches an rpmsg-dce resource manager device name.
1974   *
1975   * \param dev     The device to detach.
1976   *
1977   * \return POSIX errno value.
1978   */
1980 static
1981 Void
1982 _deinit_rpmsg_rpc_device (rpmsg_rpc_dev_t * dev)
1984     resmgr_detach(syslink_dpp, dev->rpmsg_rpc.resmgr_id, _RESMGR_DETACH_CLOSE);
1986     pthread_mutex_destroy(&dev->rpmsg_rpc.mutex);
1988     free (dev);
1990     return;
1993  /**
1994   * Initializes and attaches rpmsg-dce resource manager functions to an
1995   * rpmsg-dce device name.
1996   *
1997   * \param num     The number to append to the end of the device name.
1998   *
1999   * \return Pointer to the created rpmsg_dce_dev_t device.
2000   */
2002 static
2003 rpmsg_rpc_dev_t *
2004 _init_rpmsg_rpc_device (char * name)
2006     iofunc_attr_t  * attr;
2007     resmgr_attr_t    resmgr_attr;
2008     rpmsg_rpc_dev_t * dev = NULL;
2010     dev = malloc(sizeof(*dev));
2011     if (dev == NULL) {
2012         return NULL;
2013     }
2015     memset(&resmgr_attr, 0, sizeof resmgr_attr);
2016     resmgr_attr.nparts_max = 10;
2017     resmgr_attr.msg_max_size = 2048;
2018     memset(&dev->rpmsg_rpc.mattr, 0, sizeof(iofunc_mount_t));
2019     dev->rpmsg_rpc.mattr.flags = ST_NOSUID | ST_NOEXEC;
2020     dev->rpmsg_rpc.mattr.conf = IOFUNC_PC_CHOWN_RESTRICTED |
2021                               IOFUNC_PC_NO_TRUNC |
2022                               IOFUNC_PC_SYNC_IO;
2023     dev->rpmsg_rpc.mattr.funcs = &dev->rpmsg_rpc.mfuncs;
2024     memset(&dev->rpmsg_rpc.mfuncs, 0, sizeof(iofunc_funcs_t));
2025     dev->rpmsg_rpc.mfuncs.nfuncs = _IOFUNC_NFUNCS;
2026     dev->rpmsg_rpc.mfuncs.ocb_calloc = rpmsg_rpc_ocb_calloc;
2027     dev->rpmsg_rpc.mfuncs.ocb_free = rpmsg_rpc_ocb_free;
2028     iofunc_func_init(_RESMGR_CONNECT_NFUNCS, &dev->rpmsg_rpc.cfuncs,
2029                      _RESMGR_IO_NFUNCS, &dev->rpmsg_rpc.iofuncs);
2030     iofunc_attr_init(attr = &dev->rpmsg_rpc.cattr, S_IFCHR | 0777, NULL, NULL);
2031     dev->rpmsg_rpc.iofuncs.devctl = rpmsg_rpc_devctl;
2032     dev->rpmsg_rpc.iofuncs.notify = rpmsg_rpc_notify;
2033     dev->rpmsg_rpc.iofuncs.close_ocb = rpmsg_rpc_close_ocb;
2034     dev->rpmsg_rpc.iofuncs.read = rpmsg_rpc_read;
2035     dev->rpmsg_rpc.iofuncs.write = rpmsg_rpc_write;
2036     dev->rpmsg_rpc.iofuncs.unblock = rpmsg_rpc_read_unblock;
2037     attr->mount = &dev->rpmsg_rpc.mattr;
2038     iofunc_time_update(attr);
2039     pthread_mutex_init(&dev->rpmsg_rpc.mutex, NULL);
2041     snprintf (dev->rpmsg_rpc.device_name, _POSIX_PATH_MAX, "/dev/%s", name);
2042     if (-1 == (dev->rpmsg_rpc.resmgr_id =
2043         resmgr_attach(syslink_dpp, &resmgr_attr,
2044                       dev->rpmsg_rpc.device_name, _FTYPE_ANY, 0,
2045                       &dev->rpmsg_rpc.cfuncs,
2046                       &dev->rpmsg_rpc.iofuncs, attr))) {
2047         pthread_mutex_destroy(&dev->rpmsg_rpc.mutex);
2048         free(dev);
2049         return(NULL);
2050     }
2052     return(dev);
2055 /**
2056  * Callback passed to MessageQCopy_registerNotify.
2057  *
2058  * This callback is called when a remote processor creates a MessageQCopy
2059  * handle with the same name as the local MessageQCopy handle and then
2060  * calls NameMap_register to notify the HOST of the handle.
2061  *
2062  * \param handle    The remote handle.
2063  * \param procId    The remote proc ID of the remote handle.
2064  * \param endpoint  The endpoint address of the remote handle.
2065  *
2066  * \return None.
2067  */
2069 static
2070 Void
2071 _rpmsg_rpc_notify_cb (MessageQCopy_Handle handle, UInt16 procId,
2072                       UInt32 endpoint, Char * desc, Bool create)
2074     Int status = 0, i = 0, j = 0;
2075     Bool found = FALSE;
2076     rpmsg_rpc_conn_object * obj = NULL;
2077     char msg[512];
2078     struct rppc_msg_header * msg_hdr = (struct rppc_msg_header *)msg;
2080     for (i = 0; i < MAX_CONNS; i++) {
2081         if (rpmsg_rpc_state.objects[i] == NULL) {
2082             found = TRUE;
2083             break;
2084         }
2085     }
2087     for (j = 0; j < NUM_RPMSG_RPC_QUEUES; j++) {
2088         if (rpmsg_rpc_state.mqHandle[j] == handle) {
2089             break;
2090         }
2091     }
2093     if (found && j < NUM_RPMSG_RPC_QUEUES) {
2094         /* found a space to save this mq handle, allocate memory */
2095         obj = Memory_calloc (NULL, sizeof (rpmsg_rpc_conn_object), 0x0, NULL);
2096         if (obj) {
2097             /* store the object in the module info */
2098             rpmsg_rpc_state.objects[i] = obj;
2100             /* store the mq info in the object */
2101             obj->mq = handle;
2102             obj->procId = procId;
2103             status = ProcMgr_open(&obj->procH, obj->procId);
2104             if (status < 0) {
2105                 Osal_printf("Failed to open handle to proc %d", procId);
2106                 Memory_free(NULL, obj, sizeof(rpmsg_rpc_object));
2107             }
2108             else {
2109                 obj->addr = endpoint;
2111                 /* create a /dev/rpmsg-rpc instance for users to open */
2112                 obj->dev = _init_rpmsg_rpc_device(desc);
2113                 if (obj->dev == NULL) {
2114                     Osal_printf("Failed to create %s", desc);
2115                     ProcMgr_close(&obj->procH);
2116                     Memory_free(NULL, obj, sizeof(rpmsg_rpc_object));
2117                 }
2118             }
2119         }
2121         /* Send a message to query the chan info. Handle creating of the conn
2122          * in the callback */
2123         msg_hdr->msg_type = RPPC_MSG_QUERY_CHAN_INFO;
2124         msg_hdr->msg_len = 0;
2125         status = MessageQCopy_send(procId, MultiProc_self(), endpoint,
2126                                    rpmsg_rpc_state.endpoint[j],
2127                                    msg, sizeof(struct rppc_msg_header),
2128                                    TRUE);
2129     }
2132  /**
2133   * Callback passed to MessageQCopy_create for the module.
2134   *
2135   * This callback is called when a message is received for the rpmsg-dce
2136   * module.  This callback will never be called, since each client connection
2137   * gets it's own endpoint for message passing.
2138   *
2139   * \param handle    The local MessageQCopy handle.
2140   * \param data      Data message
2141   * \param len       Length of data message
2142   * \param priv      Private information for the endpoint
2143   * \param src       Remote endpoint sending this message
2144   * \param srcProc   Remote proc ID sending this message
2145   *
2146   * \return None.
2147   */
2149 static
2150 Void
2151 _rpmsg_rpc_module_cb (MessageQCopy_Handle handle, void * data, int len,
2152                       void * priv, UInt32 src, UInt16 srcProc)
2154     Int status = 0, i = 0, j = 0;
2155     rpmsg_rpc_conn_object * obj = NULL;
2156     struct rppc_msg_header * msg_hdr = (struct rppc_msg_header *)data;
2158     Osal_printf ("_rpmsg_rpc_module_cb callback");
2160     for (i = 0; i < MAX_CONNS; i++) {
2161         if (rpmsg_rpc_state.objects[i] != NULL &&
2162             rpmsg_rpc_state.objects[i]->addr == src) {
2163             obj = rpmsg_rpc_state.objects[i];
2164             break;
2165         }
2166     }
2168     for (j = 0; j < NUM_RPMSG_RPC_QUEUES; j++) {
2169         if (rpmsg_rpc_state.mqHandle[j] == handle) {
2170             break;
2171         }
2172     }
2174     if (obj && j < NUM_RPMSG_RPC_QUEUES) {
2175         switch (msg_hdr->msg_type) {
2176             case RPPC_MSG_CHAN_INFO:
2177             {
2178                 struct rppc_channel_info * chan_info =
2179                                       (struct rppc_channel_info *)(msg_hdr + 1);
2180                 obj->numFuncs = chan_info->num_funcs;
2181                 /* TODO: Query the info about each function */
2182                 break;
2183             }
2184             default:
2185                 status = EINVAL;
2186                 GT_setFailureReason(curTrace, GT_4CLASS, "_rpmsg_rpc_module_cb",
2187                                     status, "invalid msg_type received");
2188                 break;
2189         }
2190     }
2194 /*!
2195  *  @brief  Module setup function.
2196  *
2197  *  @sa     rpmsg_rpc_destroy
2198  */
2199 Int
2200 rpmsg_rpc_setup (Void)
2202     UInt16 i;
2203     List_Params  listparams;
2204     Int status = 0;
2205     Error_Block eb;
2206     pthread_attr_t thread_attr;
2207     struct sched_param sched_param;
2209     GT_0trace (curTrace, GT_ENTER, "rpmsg_rpc_setup");
2211     Error_init(&eb);
2213     List_Params_init (&listparams);
2214     rpmsg_rpc_state.gateHandle = (IGateProvider_Handle)
2215                      GateSpinlock_create ((GateSpinlock_Handle) NULL, &eb);
2216 #if !defined(SYSLINK_BUILD_OPTIMIZE)
2217     if (rpmsg_rpc_state.gateHandle == NULL) {
2218         status = -ENOMEM;
2219         GT_setFailureReason (curTrace,
2220                              GT_4CLASS,
2221                              "_rpmsg_rpc_setup",
2222                              status,
2223                              "Failed to create spinlock gate!");
2224     }
2225     else {
2226 #endif /* if !defined(SYSLINK_BUILD_OPTIMIZE) */
2227         for (i = 0 ; i < MAX_PROCESSES ; i++) {
2228             rpmsg_rpc_state.eventState [i].bufList = NULL;
2229             rpmsg_rpc_state.eventState [i].rpc = NULL;
2230             rpmsg_rpc_state.eventState [i].refCount = 0;
2231             rpmsg_rpc_state.eventState [i].head = NULL;
2232             rpmsg_rpc_state.eventState [i].tail = NULL;
2233         }
2235         pthread_attr_init(&thread_attr);
2236         sched_param.sched_priority = PRIORITY_REALTIME_LOW;
2237         pthread_attr_setinheritsched(&thread_attr, PTHREAD_EXPLICIT_SCHED);
2238         pthread_attr_setschedpolicy(&thread_attr, SCHED_RR);
2239         pthread_attr_setschedparam(&thread_attr, &sched_param);
2241         rpmsg_rpc_state.run = TRUE;
2242         if (pthread_create(&rpmsg_rpc_state.nt, &thread_attr, notifier_thread, NULL) == EOK) {
2243             pthread_setname_np(rpmsg_rpc_state.nt, "rpmsg-rpc-notifier");
2244             /* Initialize the driver mapping array. */
2245             Memory_set (&rpmsg_rpc_state.objects,
2246                         0,
2247                         (sizeof (rpmsg_rpc_conn_object *)
2248                          *  MAX_CONNS));
2249             for (i = 0; i < NUM_RPMSG_RPC_QUEUES; i++) {
2250                 /* create a local handle and register for notifications with MessageQCopy */
2251                 rpmsg_rpc_state.mqHandle[i] = MessageQCopy_create (
2252                                                    MessageQCopy_ADDRANY,
2253                                                    rpmsg_rpc_names[i].name,
2254                                                    _rpmsg_rpc_module_cb,
2255                                                    NULL,
2256                                                    &rpmsg_rpc_state.endpoint[i]);
2257                 if (rpmsg_rpc_state.mqHandle[i] == NULL) {
2258                     /*! @retval RPC_FAIL Failed to create MessageQCopy handle! */
2259                     status = -ENOMEM;
2260                     GT_setFailureReason (curTrace,
2261                                          GT_4CLASS,
2262                                          "rpmsg_rpc_setup",
2263                                          status,
2264                                          "Failed to create MessageQCopy handle!");
2265                     break;
2266                 }
2267                 else {
2268                     /* TBD: This could be replaced with a messageqcopy_open type call, one for
2269                      * each core */
2270                     status = MessageQCopy_registerNotify (rpmsg_rpc_state.mqHandle[i],
2271                                                         _rpmsg_rpc_notify_cb);
2272                     if (status < 0) {
2273                         MessageQCopy_delete (&rpmsg_rpc_state.mqHandle[i]);
2274                         /*! @retval RPC_FAIL Failed to register MQCopy handle! */
2275                         status = -ENOMEM;
2276                         GT_setFailureReason (curTrace,
2277                                              GT_4CLASS,
2278                                              "rpmsg_rpc_setup",
2279                                              status,
2280                                              "Failed to register MQCopy handle!");
2281                         break;
2282                     }
2283                 }
2284             }
2285             if (status >= 0){
2286                 rpmsg_rpc_state.sem = OsalSemaphore_create(OsalSemaphore_Type_Binary);
2287                 if (rpmsg_rpc_state.sem == NULL) {
2288                     //MessageQCopy_unregisterNotify();
2289                     /*! @retval RPC_FAIL Failed to register MQCopy handle! */
2290                     status = -ENOMEM;
2291                     GT_setFailureReason (curTrace,
2292                                          GT_4CLASS,
2293                                          "rpmsg_rpc_setup",
2294                                          status,
2295                                          "Failed to register MQCopy handle!");
2296                 }
2297             }
2298             if (status >= 0) {
2299                 rpmsg_rpc_state.isSetup = TRUE;
2300             }
2301             else {
2302                 for (; i > 0; --i) {
2303                     MessageQCopy_delete (&rpmsg_rpc_state.mqHandle[i]);
2304                 }
2305                 rpmsg_rpc_state.run = FALSE;
2306             }
2307         }
2308         else {
2309             rpmsg_rpc_state.run = FALSE;
2310         }
2311         pthread_attr_destroy(&thread_attr);
2312 #if !defined(SYSLINK_BUILD_OPTIMIZE)
2313     }
2314 #endif /* if !defined(SYSLINK_BUILD_OPTIMIZE) */
2316     GT_0trace (curTrace, GT_LEAVE, "rpmsg_rpc_setup");
2317     return status;
2321 /*!
2322  *  @brief  Module destroy function.
2323  *
2324  *  @sa     rpmsg_rpc_setup
2325  */
2326 Void
2327 rpmsg_rpc_destroy (Void)
2329     rpmsg_rpc_EventPacket * packet;
2330     UInt32                  i;
2331     List_Handle             bufList;
2332     rpmsg_rpc_object      * rpc = NULL;
2333     WaitingReaders_t      * wr = NULL;
2334     struct _msg_info        info;
2336     GT_0trace (curTrace, GT_ENTER, "rpmsg_rpc_destroy");
2338     for (i = 0; i < MAX_CONNS; i++) {
2339         if (rpmsg_rpc_state.objects[i]) {
2340             rpmsg_rpc_conn_object * obj = rpmsg_rpc_state.objects[i];
2341             obj->destroy = TRUE;
2342             _deinit_rpmsg_rpc_device(obj->dev);
2343             ProcMgr_close(&obj->procH);
2344             Memory_free(NULL, obj, sizeof(rpmsg_rpc_conn_object));
2345             rpmsg_rpc_state.objects[i] = NULL;
2346         }
2347     }
2349     for (i = 0 ; i < MAX_PROCESSES ; i++) {
2350         rpc = NULL;
2351         if (rpmsg_rpc_state.eventState [i].rpc != NULL) {
2352             /* This is recovery.  Need to mark rpc structures as invalid */
2353             rpc = rpmsg_rpc_state.eventState[i].rpc;
2354             MessageQCopy_delete(&rpc->mq);
2355             rpc->mq = NULL;
2356         }
2357         bufList = rpmsg_rpc_state.eventState [i].bufList;
2359         rpmsg_rpc_state.eventState [i].bufList = NULL;
2360         rpmsg_rpc_state.eventState [i].rpc = NULL;
2361         rpmsg_rpc_state.eventState [i].refCount = 0;
2362         if (bufList != NULL) {
2363             /* Dequeue waiting readers and reply to them */
2364             pthread_mutex_lock(&rpmsg_rpc_state.lock);
2365             while ((wr = dequeue_waiting_reader(i)) != NULL) {
2366                 /* Check if rcvid is still valid */
2367                 if (MsgInfo(wr->rcvid, &info) != -1) {
2368                     put_wr(wr);
2369                     pthread_mutex_unlock(&rpmsg_rpc_state.lock);
2370                     MsgError(wr->rcvid, EINTR);
2371                     pthread_mutex_lock(&rpmsg_rpc_state.lock);
2372                 }
2373             }
2374             /* Check for pending ionotify/select calls */
2375             if (rpc) {
2376                 if (IOFUNC_NOTIFY_INPUT_CHECK(rpc->notify, 1, 0)) {
2377                     iofunc_notify_trigger(rpc->notify, 1, IOFUNC_NOTIFY_INPUT);
2378                 }
2379             }
2380             pthread_mutex_unlock(&rpmsg_rpc_state.lock);
2382             /* Free event packets for any received but unprocessed events. */
2383             while (List_empty (bufList) != TRUE){
2384                 packet = (rpmsg_rpc_EventPacket *)
2385                               List_get (bufList);
2386                 if (packet != NULL){
2387                     Memory_free (NULL, packet, sizeof(*packet));
2388                 }
2389             }
2390             List_delete (&(bufList));
2391         }
2392     }
2394     /* Free the cached list */
2395     flush_uBuf();
2397     if (rpmsg_rpc_state.sem) {
2398         OsalSemaphore_delete(&rpmsg_rpc_state.sem);
2399     }
2401     for (i = 0; i < NUM_RPMSG_RPC_QUEUES; i++) {
2402         if (rpmsg_rpc_state.mqHandle[i]) {
2403             //MessageQCopy_unregisterNotify();
2404             MessageQCopy_delete(&rpmsg_rpc_state.mqHandle[i]);
2405         }
2406     }
2408     if (rpmsg_rpc_state.gateHandle != NULL) {
2409         GateSpinlock_delete ((GateSpinlock_Handle *)
2410                                        &(rpmsg_rpc_state.gateHandle));
2411     }
2413     rpmsg_rpc_state.isSetup = FALSE ;
2414     rpmsg_rpc_state.run = FALSE;
2415     // run through and destroy the thread, and all outstanding
2416     // rpc structures
2417     pthread_mutex_lock(&rpmsg_rpc_state.lock);
2418     pthread_cond_signal(&rpmsg_rpc_state.cond);
2419     pthread_mutex_unlock(&rpmsg_rpc_state.lock);
2420     pthread_join(rpmsg_rpc_state.nt, NULL);
2421     pthread_mutex_lock(&rpmsg_rpc_state.lock);
2422     while (rpmsg_rpc_state.head != NULL) {
2423         int index;
2424         WaitingReaders_t *item;
2425         index = dequeue_notify_list_item(rpmsg_rpc_state.head);
2426         if (index < 0)
2427             break;
2428         item = dequeue_waiting_reader(index);
2429         while (item) {
2430             put_wr(item);
2431             item = dequeue_waiting_reader(index);
2432         }
2433     }
2434     rpmsg_rpc_state.head = NULL ;
2435     rpmsg_rpc_state.tail = NULL ;
2436     pthread_mutex_unlock(&rpmsg_rpc_state.lock);
2438     GT_0trace (curTrace, GT_LEAVE, "_rpmsgDrv_destroy");