2a4da2d5073e2da24573661073ddf5e943f303d1
[ipc/ipcdev.git] / qnx / src / ipc3x_dev / ti / syslink / ti-ipc / ti-ipc.c
1 /*
2  *  @file       ti-ipc.c
3  *
4  *  @brief      fileops handler for ti-ipc component.
5  *
6  *
7  *  @ver
8  *
9  *  ============================================================================
10  *
11  *  Copyright (c) 2013, Texas Instruments Incorporated
12  *
13  *  Redistribution and use in source and binary forms, with or without
14  *  modification, are permitted provided that the following conditions
15  *  are met:
16  *
17  *  *  Redistributions of source code must retain the above copyright
18  *     notice, this list of conditions and the following disclaimer.
19  *
20  *  *  Redistributions in binary form must reproduce the above copyright
21  *     notice, this list of conditions and the following disclaimer in the
22  *     documentation and/or other materials provided with the distribution.
23  *
24  *  *  Neither the name of Texas Instruments Incorporated nor the names of
25  *     its contributors may be used to endorse or promote products derived
26  *     from this software without specific prior written permission.
27  *
28  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
29  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
30  *  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31  *  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
32  *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
33  *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
34  *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
35  *  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
36  *  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
37  *  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
38  *  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39  *  Contact information for paper mail:
40  *  Texas Instruments
41  *  Post Office Box 655303
42  *  Dallas, Texas 75265
43  *  Contact information:
44  *  http://www-k.ext.ti.com/sc/technical-support/product-information-centers.htm?
45  *  DCMP=TIHomeTracking&HQS=Other+OT+home_d_contact
46  *  ============================================================================
47  *
48  */
51 /* Standard headers */
52 #include <ti/syslink/Std.h>
54 /* OSAL & Utils headers */
55 #include <ti/syslink/utils/List.h>
56 #include <ti/syslink/utils/String.h>
57 #include <ti/syslink/utils/Trace.h>
58 #include <ti/syslink/utils/Memory.h>
59 #include <ti/syslink/utils/IGateProvider.h>
60 #include <ti/syslink/utils/GateSpinlock.h>
61 #include <_MultiProc.h>
63 /*QNX specific header include */
64 #include <errno.h>
65 #include <unistd.h>
66 #include <sys/iofunc.h>
67 #include <sys/dispatch.h>
68 #include <sys/netmgr.h>
69 #include <devctl.h>
71 /* Module headers */
72 #include <ti/ipc/ti_ipc.h>
73 #include <ti/ipc/MessageQCopy.h>
74 #include <_MessageQCopy.h>
75 #include <_MessageQCopyDefs.h>
76 #include "OsalSemaphore.h"
77 #include "std_qnx.h"
78 #include <pthread.h>
80 #include "ti-ipc.h"
82 #define PRIORITY_REALTIME_LOW 29
84 #define TIIPC_DEVICE_NAME "/dev/tiipc"
86 #define MESSAGEQ_RPMSG_PORT       61
87 #define RPMSG_RESERVED_ADDRESSES  1024
89 /* structure to hold rpmsg-rpc device information */
90 typedef struct named_device {
91     iofunc_mount_t      mattr;
92     iofunc_attr_t       cattr;
93     int                 resmgr_id;
94     iofunc_funcs_t      mfuncs;
95     resmgr_connect_funcs_t  cfuncs;
96     resmgr_io_funcs_t   iofuncs;
97 } named_device_t;
99 /* ti-ipc device structure */
100 typedef struct ti_ipc_dev {
101     dispatch_t       * dpp;
102     thread_pool_t    * tpool;
103     named_device_t     ti_ipc;
104 } ti_ipc_dev_t;
106 /*!
107  *  @brief  ti ipc instance object
108  */
109 typedef struct ti_ipc_object_tag {
110     MessageQCopy_Handle     mq;
111     UInt32                  addr;
112     UInt32                  remoteAddr;
113     UInt16                  procId;
114     pid_t                   pid;
115     bool                    isValid;
116     iofunc_notify_t         notify[3];
117 } ti_ipc_object;
119 /*!
120  *  @brief  Keeps the information related to Event.
121  */
122 typedef struct ipc_EventState_tag {
123     List_Handle            bufList;
124     /*!< Head of received event list. */
125     ti_ipc_object         *ipc;
126     /*!< ipc instacne. */
127     UInt32                 refCount;
128     /*!< Reference count, used when multiple Notify_registerEvent are called
129          from same process space (multi threads/processes). */
130     WaitingReaders_t *     head;
131     /*!< Waiting readers head. */
132     WaitingReaders_t *     tail;
133     /*!< Waiting readers tail. */
134 } ipc_EventState;
136 /*!
137  *  @brief  Per-connection information
138  */
139 typedef struct ti_ipc_ocb {
140     iofunc_ocb_t      hdr;
141     pid_t             pid;
142     ti_ipc_object *   ipc;
143 } ti_ipc_ocb_t;
145 /*!
146  *  @brief  ti_ipc Module state object
147  */
148 typedef struct ti_ipc_ModuleObject_tag {
149     Bool                 isSetup;
150     /*!< Indicates whether the module has been already setup */
151     IGateProvider_Handle gateHandle;
152     /*!< Handle of gate to be used for local thread safety */
153     ipc_EventState eventState [MAX_PROCESSES];
154     /*!< List for all user processes registered. */
155     pthread_t nt;
156     /*!< notifier thread */
157     pthread_mutex_t lock;
158     /*!< protection between notifier and event */
159     pthread_cond_t  cond;
160     /*!< protection between notifier and event */
161     MsgList_t *head;
162     /*!< list head */
163     MsgList_t *tail;
164     /*!< list tail */
165     int run;
166     /*!< notifier thread must keep running */
167     ti_ipc_dev_t *dev;
168     /*!< device for this module */
169 } ti_ipc_ModuleObject;
171 /*!
172  *  @brief  Structure of Event Packet read from notify kernel-side.
173  */
174 typedef struct ipc_EventPacket_tag {
175     List_Elem          element;
176     /*!< List element header */
177     UInt32             pid;
178     /* Processor identifier */
179     ti_ipc_object *    obj;
180     /*!< Pointer to the channel associated with this callback */
181     UInt32             len;
182     /*!< Length of the data associated with event. */
183     UInt8              data[MessageQCopy_BUFSIZE];
184     /*!< Data associated with event. */
185     UInt32             src;
186     /*!< Src endpoint associated with event. */
187     struct ipc_EventPacket * next;
188     struct ipc_EventPacket * prev;
189 } ipc_EventPacket ;
192 /** ============================================================================
193  *  Globals
194  *  ============================================================================
195  */
196 /*!
197  *  @var    ti_ipc_state
198  *
199  *  @brief  ti-ipc state object variable
200  */
201 static ti_ipc_ModuleObject ti_ipc_state =
203     .gateHandle = NULL,
204     .isSetup = FALSE,
205     .nt = 0,
206     .lock = PTHREAD_MUTEX_INITIALIZER,
207     .cond = PTHREAD_COND_INITIALIZER,
208     .head = NULL,
209     .tail = NULL,
210     .run  = 0,
211     .dev  = NULL
212 };
214 static MsgList_t *nl_cache;
215 static int num_nl = 0;
216 static WaitingReaders_t *wr_cache;
217 static int num_wr = 0;
219 extern dispatch_t * syslink_dpp;
222 /** ============================================================================
223  *  Internal functions
224  *  ============================================================================
225  */
227 /*
228  * Instead of constantly allocating and freeing the uBuf structures
229  * we just cache a few of them, and recycle them instead.
230  * The cache count is set with CACHE_NUM in rpmsg-omxdrv.h.
231  */
232 static ipc_EventPacket *uBuf_cache;
233 static int num_uBuf = 0;
235 static void flush_uBuf()
237     ipc_EventPacket *uBuf = NULL;
239     while(uBuf_cache) {
240         num_uBuf--;
241         uBuf = uBuf_cache;
242         uBuf_cache = (ipc_EventPacket *)uBuf_cache->next;
243         Memory_free(NULL, uBuf, sizeof(*uBuf));
244     }
247 static ipc_EventPacket *get_uBuf()
249     ipc_EventPacket *uBuf;
250     uBuf = uBuf_cache;
251     if (uBuf != NULL) {
252         uBuf_cache = (ipc_EventPacket *)uBuf_cache->next;
253         num_uBuf--;
254     } else {
255         uBuf = Memory_alloc(NULL, sizeof(ipc_EventPacket), 0, NULL);
256     }
257     return(uBuf);
260 static void put_uBuf(ipc_EventPacket * uBuf)
262     if (num_uBuf >= CACHE_NUM) {
263         Memory_free(NULL, uBuf, sizeof(*uBuf));
264     } else {
265         uBuf->next = (struct ipc_EventPacket *)uBuf_cache;
266         uBuf_cache = uBuf;
267         num_uBuf++;
268     }
269     return;
272 /*
273  * Instead of constantly allocating and freeing the notifier structures
274  * we just cache a few of them, and recycle them instead.
275  * The cache count is set with CACHE_NUM in ti-ipc.h.
276  */
278 static MsgList_t *get_nl()
280     MsgList_t *item;
281     item = nl_cache;
282     if (item != NULL) {
283         nl_cache = nl_cache->next;
284         num_nl--;
285     } else {
286         item = Memory_alloc(NULL, sizeof(MsgList_t), 0, NULL);
287     }
288     return(item);
291 static void put_nl(MsgList_t *item)
293     if (num_nl >= CACHE_NUM) {
294         Memory_free(NULL, item, sizeof(*item));
295     } else {
296         item->next = nl_cache;
297         nl_cache = item;
298         num_nl++;
299     }
300     return;
303 static WaitingReaders_t *get_wr()
305     WaitingReaders_t *item;
306     item = wr_cache;
307     if (item != NULL) {
308         wr_cache = wr_cache->next;
309         num_wr--;
310     } else {
311         item = Memory_alloc(NULL, sizeof(WaitingReaders_t), 0, NULL);
312     }
313     return(item);
316 static void put_wr(WaitingReaders_t *item)
318     if (num_wr >= CACHE_NUM) {
319         Memory_free(NULL, item, sizeof(*item));
320     } else {
321         item->next = wr_cache;
322         wr_cache = item;
323         num_wr++;
324     }
325     return;
327 /* The following functions are used for list/waiting reader management */
328 static MsgList_t *find_nl(int index)
330     MsgList_t *item=NULL;
331     item = ti_ipc_state.head;
332     while (item) {
333         if (item->index == index)
334             return(item);
335         item = item->next;
336     }
337     return(item);
340 /* we have the right locks when calling this function */
341 /*!
342  *  @brief      Function to enqueue a notify list item.
343  *
344  *  @param      index    Index of the client process associated with the item.
345  *
346  *  @sa         find_nl
347  *              get_nl
348  */
349 static int enqueue_notify_list(int index)
351     MsgList_t *item;
352     item = find_nl(index);
353     if (item == NULL) {
354         item = get_nl();
355         if (item == NULL) {
356             return(-1);
357         }
358         item->next = NULL;
359         item->index = index;
360         item->num_events=1;
361         if (ti_ipc_state.head == NULL) {
362             ti_ipc_state.head = item;
363             ti_ipc_state.tail = item;
364             item->prev = NULL;
365         }
366         else {
367             item->prev = ti_ipc_state.tail;
368             ti_ipc_state.tail->next = item;
369             ti_ipc_state.tail = item;
370         }
371     }
372     else {
373         item->num_events++;
374     }
375     return(0);
378 /* we have the right locks when calling this function */
379 /*!
380  *  @brief      Function to dequeue a notify list item.
381  *
382  *  @param      item     The item to remove.
383  *
384  *  @sa         put_nl
385  */
386 static inline int dequeue_notify_list_item(MsgList_t *item)
388     int index;
389     if (item == NULL) {
390         return(-1);
391     }
392     index = item->index;
393     item->num_events--;
394     if (item->num_events > 0) {
395         return(index);
396     }
397     if (ti_ipc_state.head == item) {
398         // removing head
399         ti_ipc_state.head = item->next;
400         if (ti_ipc_state.head != NULL) {
401             ti_ipc_state.head->prev = NULL;
402         }
403         else {
404             // removing head and tail
405             ti_ipc_state.tail = NULL;
406         }
407     }
408     else {
409         item->prev->next = item->next;
410         if (item->next != NULL) {
411             item->next->prev = item->prev;
412         }
413         else {
414             // removing tail
415             ti_ipc_state.tail = item->prev;
416         }
417     }
418     put_nl(item);
419     return(index);
422 /* we have the right locks when calling this function */
423 /*!
424  *  @brief      Function to add a waiting reader to the list.
425  *
426  *  @param      index    Index of the client process waiting reader to add.
427  *  @param      rcvid    Receive ID of the client process that was passed
428  *                       when the client called read().
429  *
430  *  @sa         None
431  */
432 static int enqueue_waiting_reader(int index, int rcvid)
434     WaitingReaders_t *item;
435     item = get_wr();
436     if (item == NULL) {
437         return(-1);
438     }
439     item->rcvid = rcvid;
440     item->next = NULL;
441     if (ti_ipc_state.eventState [index].head == NULL) {
442         ti_ipc_state.eventState [index].head = item;
443         ti_ipc_state.eventState [index].tail = item;
444     }
445     else {
446         ti_ipc_state.eventState [index].tail->next = item;
447         ti_ipc_state.eventState [index].tail = item;
448     }
449     return(EOK);
452 /* we have the right locks when calling this function */
453 /* caller frees item */
454 /*!
455  *  @brief      Function to remove a waiting reader from the list.
456  *
457  *  @param      index    Index of the client process waiting reader to dequeue.
458  *
459  *  @sa         None
460  */
461 static WaitingReaders_t *dequeue_waiting_reader(int index)
463     WaitingReaders_t *item = NULL;
464     if (ti_ipc_state.eventState [index].head) {
465         item = ti_ipc_state.eventState [index].head;
466         ti_ipc_state.eventState [index].head =
467                                      ti_ipc_state.eventState [index].head->next;
468         if (ti_ipc_state.eventState [index].head == NULL) {
469             ti_ipc_state.eventState [index].tail = NULL;
470         }
471     }
472     return(item);
475 /*!
476  *  @brief      Function find a specified waiting reader.
477  *
478  *  @param      index    Index of the client process waiting for the message.
479  *  @param      rcvid    Receive ID of the client process that was passed
480  *                       when the client called read().
481  *
482  *  @sa         None
483  */
485 static WaitingReaders_t *find_waiting_reader(int index, int rcvid)
487     WaitingReaders_t *item = NULL;
488     WaitingReaders_t *prev = NULL;
489     if (ti_ipc_state.eventState [index].head) {
490         item = ti_ipc_state.eventState [index].head;
491         while (item) {
492             if (item->rcvid == rcvid) {
493                 /* remove item from list */
494                 if (prev)
495                     prev->next = item->next;
496                 if (item == ti_ipc_state.eventState [index].head)
497                     ti_ipc_state.eventState [index].head = item->next;
498                 break;
499             }
500             else {
501                 prev = item;
502                 item = item->next;
503             }
504         }
505     }
506     return item;
509 /*!
510  *  @brief      Function used to check if there is a waiting reader with an
511  *              event (message) ready to be delivered.
512  *
513  *  @param      index    Index of the client process waiting for the message.
514  *  @param      item     Pointer to the waiting reader.
515  *
516  *  @sa         dequeue_notify_list_item
517  *              dequeue_waiting_reader
518  */
520 static int find_available_reader_and_event(int *index, WaitingReaders_t **item)
522     MsgList_t *temp;
523     if (ti_ipc_state.head == NULL) {
524         return(0);
525     }
526     temp = ti_ipc_state.head;
527     while (temp) {
528         if (ti_ipc_state.eventState [temp->index].head) {
529             // event and reader found
530             if (dequeue_notify_list_item(temp) >= 0) {
531                 *index = temp->index;
532                 *item = dequeue_waiting_reader(temp->index);
533             }
534             else {
535                 /* error occurred, return 0 as item has not been set */
536                 return(0);
537             }
538             return(1);
539         }
540         temp = temp->next;
541     }
542     return(0);
545 /*!
546  *  @brief      Function used to deliver the notification to the client that
547  *              it has received a message.
548  *
549  *  @param      index    Index of the client process receiving hte message.
550  *  @param      rcvid    Receive ID of the client process that was passed
551  *                       when the client called read().
552  *
553  *  @sa         put_uBuf
554  */
556 static void deliver_notification(int index, int rcvid)
558     int err = EOK;
559     ipc_EventPacket * uBuf     = NULL;
561     uBuf = (ipc_EventPacket *) List_get (ti_ipc_state.eventState [index].bufList);
563     /*  Let the check remain at run-time. */
564     if (uBuf != NULL) {
565         err = MsgReply(rcvid, uBuf->len, uBuf->data, uBuf->len);
566         if (err == -1)
567             perror("deliver_notification: MsgReply");
568         /* Free the processed event callback packet. */
569         put_uBuf(uBuf);
570     }
571     else {
572         MsgReply(rcvid, EOK, NULL, 0);
573     }
574     return;
577 /*!
578  *  @brief      Thread used for notifying waiting readers of messages.
579  *
580  *  @param      arg    Thread-specific private arg.
581  *
582  *  @sa         find_available_reader_and_event
583  *              deliver_notification
584  *              put_wr
585  */
586 static void *notifier_thread(void *arg)
588     int status;
589     int index;
590     WaitingReaders_t *item = NULL;
591     pthread_mutex_lock(&ti_ipc_state.lock);
592     while (ti_ipc_state.run) {
593         status = find_available_reader_and_event(&index, &item);
594         if ( (status == 0) || (item == NULL) ) {
595             status = pthread_cond_wait(&ti_ipc_state.cond, &ti_ipc_state.lock);
596             if ((status != EOK) && (status != EINTR)) {
597                 // false wakeup
598                 break;
599             }
600             status = find_available_reader_and_event(&index, &item);
601             if ( (status == 0) || (item == NULL) ) {
602                 continue;
603             }
604         }
605         pthread_mutex_unlock(&ti_ipc_state.lock);
606         // we have unlocked, and now we have an event to deliver
607         // we deliver one event at a time, relock, check and continue
608         deliver_notification(index, item->rcvid);
609         pthread_mutex_lock(&ti_ipc_state.lock);
610         put_wr(item);
611     }
612     pthread_mutex_unlock(&ti_ipc_state.lock);
613     return(NULL);
617 /*!
618  *  @brief      Attach a process to ti-ipc user support framework.
619  *
620  *  @param      obj    TI IPC instance
621  *
622  *  @sa         _ti_ipc_detach
623  */
624 static
625 Int
626 _ti_ipc_attach (ti_ipc_object * obj)
628     Int32                status   = EOK;
629     Bool                 flag     = FALSE;
630     Bool                 isInit   = FALSE;
631     List_Object *        bufList  = NULL;
632     IArg                 key      = 0;
633     List_Params          listparams;
634     UInt32               i;
636     GT_1trace (curTrace, GT_ENTER, "_ti_ipc_attach", obj);
638     key = IGateProvider_enter (ti_ipc_state.gateHandle);
639     for (i = 0 ; (i < MAX_PROCESSES) ; i++) {
640         if (ti_ipc_state.eventState [i].ipc == obj) {
641             ti_ipc_state.eventState [i].refCount++;
642             isInit = TRUE;
643             status = EOK;
644             break;
645         }
646     }
648     if (isInit == FALSE) {
649         List_Params_init (&listparams);
650         bufList = List_create (&listparams) ;
651         /* Search for an available slot for user process. */
652         for (i = 0 ; i < MAX_PROCESSES ; i++) {
653             if (ti_ipc_state.eventState [i].ipc == NULL) {
654                 ti_ipc_state.eventState [i].ipc = obj;
655                 ti_ipc_state.eventState [i].refCount = 1;
656                 ti_ipc_state.eventState [i].bufList = bufList;
657                 flag = TRUE;
658                 break;
659             }
660         }
662         /* No free slots found. Let this check remain at run-time,
663          * since it is dependent on user environment.
664          */
665         if (flag != TRUE) {
666             /*! @retval Notify_E_RESOURCE Maximum number of
667              supported user clients have already been registered. */
668             status = -ENOMEM;
669             GT_setFailureReason (curTrace,
670                               GT_4CLASS,
671                               "_ti_ipc_attach",
672                               status,
673                               "Maximum number of supported user"
674                                   " clients have already been "
675                                   "registered.");
676             if (bufList != NULL) {
677                 List_delete (&bufList);
678             }
679         }
680     }
681     IGateProvider_leave (ti_ipc_state.gateHandle, key);
683     GT_1trace (curTrace, GT_LEAVE, "_ti_ipc_attach", status);
685     /*! @retval Notify_S_SUCCESS Operation successfully completed. */
686     return status ;
690  /*!
691  *  @brief      This function adds a data to a registered process.
692  *
693  *  @param      obj       Instance object associated with the client
694  *  @param      src       Source address (endpoint) sending the data
695  *  @param      pid       Process ID associated with the client
696  *  @param      data      Data to be added
697  *  @param      len       Length of data to be added
698  *
699  *  @sa
700  */
701 Int
702 _ti_ipc_addBufByPid (ti_ipc_object *  obj,
703                      UInt32           src,
704                      UInt32           pid,
705                      void *           data,
706                      UInt32           len)
708     Int32                   status = EOK;
709     Bool                    flag   = FALSE;
710     ipc_EventPacket *  uBuf   = NULL;
711     IArg                    key;
712     UInt32                  i;
713     WaitingReaders_t *item;
714     MsgList_t *msgItem;
716     GT_assert (curTrace, (ti_ipc_state.isSetup == TRUE));
718     key = IGateProvider_enter (ti_ipc_state.gateHandle);
719     /* Find the registration for this callback */
720     for (i = 0 ; i < MAX_PROCESSES ; i++) {
721         if (ti_ipc_state.eventState [i].ipc == obj) {
722             flag = TRUE;
723             break;
724         }
725     }
726     IGateProvider_leave (ti_ipc_state.gateHandle, key);
728 #if !defined(SYSLINK_BUILD_OPTIMIZE)
729     if (flag != TRUE) {
730         /*! @retval ENOMEM Could not find a registered handler
731                                       for this process. */
732         status = -ENOMEM;
733         GT_setFailureReason (curTrace,
734                              GT_4CLASS,
735                              "_ti_ipc_addBufByPid",
736                              status,
737                              "Could not find a registered handler "
738                              "for this process.!");
739     }
740     else {
741 #endif /* if !defined(SYSLINK_BUILD_OPTIMIZE) */
742         /* Allocate memory for the buf */
743         pthread_mutex_lock(&ti_ipc_state.lock);
744         uBuf = get_uBuf();
745         pthread_mutex_unlock(&ti_ipc_state.lock);
747 #if !defined(SYSLINK_BUILD_OPTIMIZE)
748         if (uBuf == NULL) {
749             /*! @retval Notify_E_MEMORY Failed to allocate memory for event
750                                 packet for received callback. */
751             status = -ENOMEM;
752             GT_setFailureReason (curTrace,
753                                  GT_4CLASS,
754                                  "_ti_ipc_addBufByPid",
755                                  status,
756                                  "Failed to allocate memory for event"
757                                  " packet for received callback.!");
758         }
759         else {
760 #endif /* if !defined(SYSLINK_BUILD_OPTIMIZE) */
761             List_elemClear (&(uBuf->element));
762             GT_assert (curTrace,
763                        (ti_ipc_state.eventState [i].bufList != NULL));
765             if (data) {
766                 Memory_copy(uBuf->data, data, len);
767             }
768             uBuf->len = len;
770             List_put (ti_ipc_state.eventState [i].bufList,
771                       &(uBuf->element));
772             pthread_mutex_lock(&ti_ipc_state.lock);
773             item = dequeue_waiting_reader(i);
774             if (item) {
775                 // there is a waiting reader
776                 deliver_notification(i, item->rcvid);
777                 put_wr(item);
778                 pthread_mutex_unlock(&ti_ipc_state.lock);
779                 status = EOK;
780             }
781             else {
782                 if (enqueue_notify_list(i) < 0) {
783                     pthread_mutex_unlock(&ti_ipc_state.lock);
784                     status = -ENOMEM;
785                     GT_setFailureReason (curTrace,
786                                   GT_4CLASS,
787                                   "_ti_ipc_addBufByPid",
788                                   status,
789                                   "Failed to allocate memory for notifier");
790                 }
791                 else {
792                     msgItem = find_nl(i);
793                     /* TODO: obj could be NULL in some cases  */
794                     if (obj && msgItem) {
795                         if (IOFUNC_NOTIFY_INPUT_CHECK(obj->notify,
796                                                       msgItem->num_events, 0)) {
797                             iofunc_notify_trigger(obj->notify,
798                                                   msgItem->num_events,
799                                                   IOFUNC_NOTIFY_INPUT);
800                         }
801                     }
802                     status = EOK;
803                     pthread_cond_signal(&ti_ipc_state.cond);
804                     pthread_mutex_unlock(&ti_ipc_state.lock);
805                 }
806             }
807 #if !defined(SYSLINK_BUILD_OPTIMIZE)
808         }
809     }
810 #endif /* if !defined(SYSLINK_BUILD_OPTIMIZE) */
812     GT_1trace (curTrace, GT_LEAVE, "_ti_ipc_addBufByPid", status);
814     return status;
818 /*!
819  *  @brief      This function implements the callback registered with
820  *              MessageQCopy_create for each client.  This function
821  *              adds the message from the remote proc to a list
822  *              where it is routed to the appropriate waiting reader.
823  *
824  *  @param      handle    Destinatino MessageQCopy_Handle instance for the msg
825  *  @param      data      Message buffer
826  *  @param      len       Length of the message data
827  *  @param      priv      Private information given when callback was registered
828  *  @param      src       Source address of the message
829  *  @param      srcProc   Source proc of the message
830  *
831  *  @sa
832  */
833 Void
834 _ti_ipc_cb (MessageQCopy_Handle handle, void * data, int len, void * priv,
835             UInt32 src, UInt16 srcProc)
837 #if !defined(SYSLINK_BUILD_OPTIMIZE)
838     Int32                   status = 0;
839 #endif /* if !defined(SYSLINK_BUILD_OPTIMIZE) */
840     ti_ipc_object * obj = NULL;
842     obj = (ti_ipc_object *) priv;
844 #if !defined(SYSLINK_BUILD_OPTIMIZE)
845     status =
846 #endif /* if !defined(SYSLINK_BUILD_OPTIMIZE) */
847              _ti_ipc_addBufByPid (obj,
848                                   src,
849                                   obj->pid,
850                                   data,
851                                   len);
852 #if !defined(SYSLINK_BUILD_OPTIMIZE)
853     if (status < 0) {
854         GT_setFailureReason (curTrace,
855                              GT_4CLASS,
856                              "_ti_ipc_cb",
857                              status,
858                              "Failed to add callback packet for pid");
859     }
860 #endif /* if !defined(SYSLINK_BUILD_OPTIMIZE) */
863  /**
864   * Handler for ocb_calloc() requests.
865   *
866   * Special handler for ocb_calloc() requests that we export for control.  An
867   * open request from the client will result in a call to our special ocb_calloc
868   * handler.  This function allocates client-specific information.
869   *
870   * \param ctp       Thread's associated context information.
871   * \param device    Device attributes structure.
872   *
873   * \return Pointer to an iofunc_ocb_t OCB structure.
874   */
876 IOFUNC_OCB_T *
877 ti_ipc_ocb_calloc (resmgr_context_t * ctp, IOFUNC_ATTR_T * device)
879     ti_ipc_ocb_t * ocb = NULL;
880     ti_ipc_object * obj = NULL;
882     /* Allocate the OCB */
883     ocb = (ti_ipc_ocb_t *) calloc (1, sizeof (ti_ipc_ocb_t));
884     if (ocb == NULL){
885         errno = ENOMEM;
886         return (NULL);
887     }
889     ocb->pid = ctp->info.pid;
891     /* Allocate memory for the rpmsg object. */
892     obj = Memory_calloc (NULL, sizeof (ti_ipc_object), 0u, NULL);
893     if (obj == NULL) {
894         errno = ENOMEM;
895         free(ocb);
896         return (NULL);
897     }
898     else if (_ti_ipc_attach(obj) < 0) {
899         errno = ENOMEM;
900         free(ocb);
901         return (NULL);
902     }
903     else {
904         ocb->ipc = obj;
905         IOFUNC_NOTIFY_INIT(obj->notify);
906         obj->addr = MessageQCopy_ADDRANY;
907         obj->remoteAddr = MessageQCopy_ADDRANY;
908         obj->procId = MultiProc_INVALIDID;
909         obj->mq = NULL;
910         obj->isValid = TRUE;
911     }
913     return (IOFUNC_OCB_T *)(ocb);
917 /*!
918  *  @brief      Detach a process from ti-ipc user support framework.
919  *
920  *  @param      obj    TI IPC instance
921  *  @param      force  Tells if detach should be forced even if conditions
922  *                     are not met.
923  *
924  *  @sa         _ti_ipc_attach
925  */
926 static
927 Int
928 _ti_ipc_detach (ti_ipc_object * obj, Bool force)
930     Int32                status    = EOK;
931     Int32                tmpStatus = EOK;
932     Bool                 flag      = FALSE;
933     List_Object *        bufList   = NULL;
934     UInt32               i;
935     IArg                 key;
936     MsgList_t          * item;
937     WaitingReaders_t   * wr        = NULL;
938     struct _msg_info     info;
940     GT_1trace (curTrace, GT_ENTER, "_ti_ipc_detach", obj);
942     key = IGateProvider_enter (ti_ipc_state.gateHandle);
944     for (i = 0 ; i < MAX_PROCESSES ; i++) {
945         if (ti_ipc_state.eventState [i].ipc == obj) {
946             if (ti_ipc_state.eventState [i].refCount == 1) {
947                 ti_ipc_state.eventState [i].refCount = 0;
949                 flag = TRUE;
950                 break;
951             }
952             else {
953                 ti_ipc_state.eventState [i].refCount--;
954                 status = EOK;
955                 break;
956             }
957         }
958     }
959     IGateProvider_leave (ti_ipc_state.gateHandle, key);
961     if (flag == TRUE) {
962         key = IGateProvider_enter (ti_ipc_state.gateHandle);
963         /* Last client being unregistered for this process. */
964         ti_ipc_state.eventState [i].ipc = NULL;
966         /* Store in local variable to delete outside lock. */
967         bufList = ti_ipc_state.eventState [i].bufList;
969         ti_ipc_state.eventState [i].bufList = NULL;
971         IGateProvider_leave (ti_ipc_state.gateHandle, key);
972     }
974     if (flag != TRUE) {
975 #if !defined(SYSLINK_BUILD_OPTIMIZE)
976         if (i == MAX_PROCESSES) {
977             /*! @retval Notify_E_NOTFOUND The specified user process was
978                      not found registered with Notify Driver module. */
979             status = -ENOMEM;
980             GT_setFailureReason (curTrace,
981                               GT_4CLASS,
982                               "_ti_ipc_detach",
983                               status,
984                               "The specified user process was not found"
985                               " registered with rpmsg Driver module.");
986         }
987 #endif /* if !defined(SYSLINK_BUILD_OPTIMIZE) */
988     }
989     else {
990         if (bufList != NULL) {
991             /* Dequeue waiting readers and reply to them */
992             pthread_mutex_lock(&ti_ipc_state.lock);
993             while ((wr = dequeue_waiting_reader(i)) != NULL) {
994                 /* Check if rcvid is still valid */
995                 if (MsgInfo(wr->rcvid, &info) != -1) {
996                     put_wr(wr);
997                     pthread_mutex_unlock(&ti_ipc_state.lock);
998                     MsgError(wr->rcvid, EINTR);
999                     pthread_mutex_lock(&ti_ipc_state.lock);
1000                 }
1001             }
1002             /* Check for pending ionotify/select calls */
1003             if (obj) {
1004                 if (IOFUNC_NOTIFY_INPUT_CHECK(obj->notify, 1, 0)) {
1005                     iofunc_notify_trigger(obj->notify, 1, IOFUNC_NOTIFY_INPUT);
1006                 }
1007             }
1009             /* Free event packets for any received but unprocessed events. */
1010             while ((item = find_nl(i)) != NULL) {
1011                 if (dequeue_notify_list_item(item) >= 0) {
1012                     ipc_EventPacket * uBuf = NULL;
1014                     uBuf = (ipc_EventPacket *) List_get (bufList);
1016                     /*  Let the check remain at run-time. */
1017                     if (uBuf != NULL) {
1018                         put_uBuf(uBuf);
1019                     }
1020                 }
1021             }
1022             pthread_mutex_unlock(&ti_ipc_state.lock);
1024             /* Last client being unregistered with Notify module. */
1025             List_delete (&bufList);
1026         }
1028 #if !defined(SYSLINK_BUILD_OPTIMIZE)
1029         if ((tmpStatus < 0) && (status >= 0)) {
1030             status =  tmpStatus;
1031             GT_setFailureReason (curTrace,
1032                              GT_4CLASS,
1033                              "_ti_ipc_detach",
1034                              status,
1035                              "Failed to delete termination semaphore!");
1036         }
1037 #endif /* if !defined(SYSLINK_BUILD_OPTIMIZE) */
1038     }
1040     GT_1trace (curTrace, GT_LEAVE, "_ti_ipc_detach", status);
1042     /*! @retval Notify_S_SUCCESS Operation successfully completed */
1043     return status;
1046  /**
1047   * Handler for ocb_free() requests.
1048   *
1049   * Special handler for ocb_free() requests that we export for control.  A
1050   * close request from the client will result in a call to our special ocb_free
1051   * handler.  This function frees any client-specific information that was
1052   * allocated.
1053   *
1054   * \param i_ocb     OCB associated with client's session.
1055   *
1056   * \return POSIX errno value.
1057   *
1058   * \retval None.
1059   */
1061 void
1062 ti_ipc_ocb_free (IOFUNC_OCB_T * i_ocb)
1064     ti_ipc_ocb_t * ocb = (ti_ipc_ocb_t *)i_ocb;
1065     ti_ipc_object * obj;
1067     if (ocb) {
1068         if (ocb->ipc) {
1069             obj = ocb->ipc;
1070             /* TBD: Notification to remote core of endpoint closure? */
1071             if (obj->mq) {
1072                 MessageQCopy_delete (&obj->mq);
1073                 obj->mq = NULL;
1074             }
1075             _ti_ipc_detach(ocb->ipc, FALSE);
1076             free (obj);
1077         }
1078         free (ocb);
1079     }
1082  /**
1083   * Handler for close_ocb() requests.
1084   *
1085   * This function removes the notification entries associated with the current
1086   * client.
1087   *
1088   * \param ctp       Thread's associated context information.
1089   * \param reserved  This argument must be NULL.
1090   * \param ocb       OCB associated with client's session.
1091   *
1092   * \return POSIX errno value.
1093   *
1094   * \retval EOK      Success.
1095   */
1097 Int
1098 ti_ipc_close_ocb (resmgr_context_t *ctp, void *reserved, RESMGR_OCB_T *ocb)
1100     ti_ipc_ocb_t * ipc_ocb = (ti_ipc_ocb_t *)ocb;
1101     iofunc_notify_remove(ctp, ipc_ocb->ipc->notify);
1102     return (iofunc_close_ocb_default(ctp, reserved, ocb));
1105  /**
1106   * Handler for read() requests.
1107   *
1108   * Handles special read() requests that we export for control.  A read
1109   * request will get a message from the remote processor that is associated
1110   * with the client that is calling read().
1111   *
1112   * \param ctp     Thread's associated context information.
1113   * \param msg     The actual read() message.
1114   * \param ocb     OCB associated with client's session.
1115   *
1116   * \return POSIX errno value.
1117   *
1118   * \retval EOK      Success.
1119   * \retval EAGAIN   Call is non-blocking and no messages available.
1120   * \retval ENOMEM   Not enough memory to preform the read.
1121   */
1123 int
1124 ti_ipc_read(resmgr_context_t *ctp, io_read_t *msg, RESMGR_OCB_T *i_ocb)
1126     Int status;
1127     Bool                    flag     = FALSE;
1128     Int                  retVal   = EOK;
1129     UInt32                  i;
1130     MsgList_t          * item;
1131     Int                  nonblock;
1132     ti_ipc_ocb_t * ocb = (ti_ipc_ocb_t *)i_ocb;
1133     ti_ipc_object * obj = ocb->ipc;
1135     if ((status = iofunc_read_verify(ctp, msg, i_ocb, &nonblock)) != EOK)
1136         return (status);
1138     if (!obj->isValid) {
1139         return EIO;
1140     }
1142     if (obj->addr == MessageQCopy_ADDRANY) {
1143         return ENOTCONN;
1144     }
1146     for (i = 0 ; i < MAX_PROCESSES ; i++) {
1147         if (ti_ipc_state.eventState [i].ipc == obj) {
1148             flag = TRUE;
1149             break;
1150         }
1151     }
1153     /* Let the check remain at run-time. */
1154     if (flag == TRUE) {
1155         /* Let the check remain at run-time for handling any run-time
1156         * race conditions.
1157         */
1158         if (ti_ipc_state.eventState [i].bufList != NULL) {
1159             pthread_mutex_lock(&ti_ipc_state.lock);
1160             item = find_nl(i);
1161             if (dequeue_notify_list_item(item) < 0) {
1162                 if (nonblock) {
1163                     pthread_mutex_unlock(&ti_ipc_state.lock);
1164                     return EAGAIN;
1165                 }
1166                 else {
1167                     retVal = enqueue_waiting_reader(i, ctp->rcvid);
1168                     if (retVal == EOK) {
1169                         pthread_cond_signal(&ti_ipc_state.cond);
1170                         pthread_mutex_unlock(&ti_ipc_state.lock);
1171                         return(_RESMGR_NOREPLY);
1172                     }
1173                     retVal = ENOMEM;
1174                     pthread_mutex_unlock(&ti_ipc_state.lock);
1175                 }
1176             }
1177             else {
1178                 deliver_notification(i, ctp->rcvid);
1179                 pthread_mutex_unlock(&ti_ipc_state.lock);
1180                 return(_RESMGR_NOREPLY);
1181             }
1182         }
1183     }
1185     /*! @retval Number-of-bytes-read Number of bytes read. */
1186     return retVal;
1189  /**
1190   * Handler for write() requests.
1191   *
1192   * Handles special write() requests that we export for control.  A write()
1193   * request will send a message to the remote processor which is associated with
1194   * the client.
1195   *
1196   * \param ctp     Thread's associated context information.
1197   * \param msg     The actual write() message.
1198   * \param io_ocb  OCB associated with client's session.
1199   *
1200   * \return POSIX errno value.
1201   *
1202   * \retval EOK      Success.
1203   * \retval ENOTCONN Remote address has not been set.
1204   * \retval ENOMEM   Not enough memory to perform the write.
1205   * \retval EIO      MessageQCopy_send failed.
1206   * \retval EINVAL   msg->i.bytes is negative.
1207   */
1209 int
1210 ti_ipc_write(resmgr_context_t *ctp, io_write_t *msg, RESMGR_OCB_T *io_ocb)
1212     int status;
1213     char buf[MessageQCopy_BUFSIZE];
1214     int bytes;
1215     ti_ipc_ocb_t * ocb = (ti_ipc_ocb_t *)io_ocb;
1216     ti_ipc_object * obj = ocb->ipc;
1218     if ((status = iofunc_write_verify(ctp, msg, io_ocb, NULL)) != EOK) {
1219         return (status);
1220     }
1222     if (!obj->isValid) {
1223         return EIO;
1224     }
1226     if (obj->remoteAddr == MessageQCopy_ADDRANY) {
1227         return ENOTCONN;
1228     }
1230     bytes = ((int64_t) msg->i.nbytes) > MessageQCopy_BUFSIZE ?
1231             MessageQCopy_BUFSIZE : msg->i.nbytes;
1232     if (bytes < 0) {
1233         return EINVAL;
1234     }
1235     _IO_SET_WRITE_NBYTES (ctp, bytes);
1237     status = resmgr_msgread(ctp, buf, bytes, sizeof(msg->i));
1238     if (status != bytes) {
1239         return (errno);
1240     }
1242     /* TODO: Need to make generic instead of hardcoding the address */
1243     if (obj->remoteAddr == MESSAGEQ_RPMSG_PORT){
1244         status = MessageQCopy_send(obj->procId, MultiProc_self(), obj->remoteAddr,
1245                                    RPMSG_RESERVED_ADDRESSES, buf, bytes, TRUE);
1246     }
1247     else {
1248         status = MessageQCopy_send(obj->procId, MultiProc_self(), obj->remoteAddr,
1249                                    obj->addr, buf, bytes, TRUE);
1250     }
1251     if (status < 0) {
1252         return (EIO);
1253     }
1255     return(EOK);
1258  /**
1259   * Handler for TIIPC_IOCSETLOCAL requests.
1260   *
1261   * Handles TIIPC_IOCSETLOCAL requests to set the local endpoint address.
1262   *
1263   * \param ctp     Thread's associated context information.
1264   * \param msg     The actual devctl() message.
1265   * \param io_ocb  OCB associated with client's session.
1266   *
1267   * \return POSIX errno value.
1268   *
1269   * \retval EOK      Success.
1270   * \retval EISCONN  Local address is already set.
1271   * \retval ENOMEM   Not enough memory to create the endpoint.
1272   * \retval EINVAL   ctp->info.msglen or ctp->info.dstmsglen is not big enough.
1273   */
1274 static
1275 Int
1276 _ti_ipc_set_local(resmgr_context_t *ctp, io_devctl_t *msg, ti_ipc_ocb_t *ocb)
1278     Int status = EOK;
1279     tiipc_local_params * cargs = (tiipc_local_params *)(_DEVCTL_DATA (msg->i));
1280     tiipc_local_params * out = (tiipc_local_params *)(_DEVCTL_DATA (msg->o));
1281     ti_ipc_object * obj = ocb->ipc;
1283     if ((ctp->info.msglen - sizeof(msg->i) < sizeof(tiipc_local_params)) ||
1284         (ctp->info.dstmsglen - sizeof(msg->o) < sizeof (tiipc_local_params))) {
1285         status = (EINVAL);
1286     }
1287     else if (obj->mq) {
1288         /* already a local endpoint associated with this instance */
1289         status = (EISCONN);
1290     }
1291     else {
1292         if (cargs->local_addr == TIIPC_ADDRANY) {
1293             cargs->local_addr = MessageQCopy_ADDRANY;
1294         }
1295         /* Create the local endpoint based on the request */
1296         obj->mq = MessageQCopy_create (cargs->local_addr, NULL, _ti_ipc_cb,
1297                                        obj, &obj->addr);
1298         if (obj->mq == NULL) {
1299             status = (ENOMEM);
1300         }
1301         else {
1302             out->local_addr = obj->addr;
1303             msg->o.ret_val = EOK;
1304             status = (_RESMGR_PTR(ctp, &msg->o, sizeof(msg->o) +\
1305                                   sizeof(tiipc_local_params)));
1306         }
1307     }
1309     return status;
1312  /**
1313   * Handler for TIIPC_IOCGETLOCAL requests.
1314   *
1315   * Handles TIIPC_IOCGETLOCAL requests to get the local endpoint address info.
1316   *
1317   * \param ctp     Thread's associated context information.
1318   * \param msg     The actual devctl() message.
1319   * \param io_ocb  OCB associated with client's session.
1320   *
1321   * \return POSIX errno value.
1322   *
1323   * \retval EOK      Success.
1324   * \retval EINVAL   ctp->info.dstmsglen is not big enough.
1325   */
1326 static
1327 Int
1328 _ti_ipc_get_local(resmgr_context_t *ctp, io_devctl_t *msg, ti_ipc_ocb_t *ocb)
1330     Int status = EOK;
1331     tiipc_local_params * out = (tiipc_local_params *)(_DEVCTL_DATA (msg->o));
1332     ti_ipc_object * obj = ocb->ipc;
1334     if (ctp->info.dstmsglen - sizeof(msg->o) < sizeof (tiipc_local_params)) {
1335         status = (EINVAL);
1336     }
1337     else {
1338         if (obj->addr == MessageQCopy_ADDRANY)
1339             out->local_addr = TIIPC_ADDRANY;
1340         else
1341             out->local_addr = obj->addr;
1342         msg->o.ret_val = EOK;
1343         status = (_RESMGR_PTR(ctp, &msg->o, sizeof(msg->o) +\
1344                               sizeof(tiipc_local_params)));
1345     }
1347     return status;
1350  /**
1351   * Handler for TIIPC_IOCSETREMOTE requests.
1352   *
1353   * Handles TIIPC_IOCSETREMOTE requests to set the remote endpoint address and
1354   * proc ID used for write() commands.
1355   *
1356   * \param ctp     Thread's associated context information.
1357   * \param msg     The actual devctl() message.
1358   * \param io_ocb  OCB associated with client's session.
1359   *
1360   * \return POSIX errno value.
1361   *
1362   * \retval EOK      Success.
1363   * \retval EISCONN  Remote address is already set.
1364   * \retval ENOMEM   Not enough memory to create the endpoint.
1365   * \retval EINVAL   ctp->info.msglen or ctp->info.dstmsglen is not big enough
1366   *                  or the specified remote proc ID is invalid.
1367   */
1368 static
1369 Int
1370 _ti_ipc_set_remote(resmgr_context_t *ctp, io_devctl_t *msg, ti_ipc_ocb_t *ocb)
1372     Int status = EOK;
1373     tiipc_remote_params * cargs =
1374                                  (tiipc_remote_params *)(_DEVCTL_DATA (msg->i));
1375     ti_ipc_object *obj = ocb->ipc;
1377     if ((ctp->info.msglen - sizeof(msg->i) < sizeof (tiipc_remote_params)) ||
1378         (ctp->info.dstmsglen - sizeof(msg->o) < sizeof (tiipc_remote_params))) {
1379         status = (EINVAL);
1380     }
1381     else if (obj->remoteAddr != MessageQCopy_ADDRANY) {
1382         /* already a remote endpoint associated with this instance */
1383         status = (EISCONN);
1384     }
1385     else if (cargs->remote_proc == MultiProc_self() ||
1386              cargs->remote_proc >= MultiProc_getNumProcessors()) {
1387         /* Don't support sending to self and remote proc ID must be valid */
1388         status = (EINVAL);
1389     }
1390     else {
1391         obj->remoteAddr = cargs->remote_addr;
1392         obj->procId = cargs->remote_proc;
1393         msg->o.ret_val = EOK;
1394         status = (_RESMGR_PTR(ctp, &msg->o, sizeof(msg->o) +\
1395                               sizeof(tiipc_remote_params)));
1396     }
1398     return status;
1401  /**
1402   * Handler for TIIPC_IOCGETREMOTE requests.
1403   *
1404   * Handles TIIPC_IOCGETREMOTE requests to get the remote endpoint address info.
1405   *
1406   * \param ctp     Thread's associated context information.
1407   * \param msg     The actual devctl() message.
1408   * \param io_ocb  OCB associated with client's session.
1409   *
1410   * \return POSIX errno value.
1411   *
1412   * \retval EOK      Success.
1413   * \retval EINVAL   ctp->info.dstmsglen is not big enough.
1414   */
1415 static
1416 Int
1417 _ti_ipc_get_remote(resmgr_context_t *ctp, io_devctl_t *msg, ti_ipc_ocb_t *ocb)
1419     Int status = EOK;
1420     tiipc_remote_params * out = (tiipc_remote_params *)(_DEVCTL_DATA (msg->o));
1421     ti_ipc_object * obj = ocb->ipc;
1423     if (ctp->info.dstmsglen - sizeof(msg->i) < sizeof (tiipc_remote_params)) {
1424         status = (EINVAL);
1425     }
1426     else {
1427         if (obj->remoteAddr == MessageQCopy_ADDRANY)
1428             out->remote_addr = TIIPC_ADDRANY;
1429         else
1430             out->remote_addr = obj->remoteAddr;
1431         out->remote_proc = obj->procId;
1432         msg->o.ret_val = EOK;
1433         status = (_RESMGR_PTR(ctp, &msg->o, sizeof(msg->o) +\
1434                               sizeof(tiipc_remote_params)));
1435     }
1437     return status;
1440  /**
1441   * Handler for devctl() requests.
1442   *
1443   * Handles special devctl() requests that we export for control.  A devctl()
1444   * request will perform different functions depending on the dcmd.
1445   *
1446   * \param ctp     Thread's associated context information.
1447   * \param msg     The actual devctl() message.
1448   * \param i_ocb   OCB associated with client's session.
1449   *
1450   * \return POSIX errno value.
1451   *
1452   * \retval EOK      Success.
1453   * \retval other    Fail.
1454   */
1455 static
1456 Int
1457 ti_ipc_devctl(resmgr_context_t *ctp, io_devctl_t *msg, IOFUNC_OCB_T *i_ocb)
1459     Int status = 0;
1460     ti_ipc_ocb_t *ocb = (ti_ipc_ocb_t *)i_ocb;
1462     if ((status = iofunc_devctl_default(ctp, msg, &ocb->hdr)) != _RESMGR_DEFAULT)
1463         return(_RESMGR_ERRNO(status));
1464     status = 0;
1466     if (!ocb->ipc->isValid) {
1467         return EIO;
1468     }
1470     switch (msg->i.dcmd)
1471     {
1472         case TIIPC_IOCSETLOCAL:
1473             /* Must be called before receiving messages */
1474             status = _ti_ipc_set_local (ctp, msg, ocb);
1475             break;
1476         case TIIPC_IOCGETLOCAL:
1477             status = _ti_ipc_get_local (ctp, msg, ocb);
1478             break;
1479         case TIIPC_IOCSETREMOTE:
1480             /* Must be called before sending messages */
1481             status = _ti_ipc_set_remote (ctp, msg, ocb);
1482             break;
1483         case TIIPC_IOCGETREMOTE:
1484             status = _ti_ipc_get_remote (ctp, msg, ocb);
1485             break;
1486         default:
1487             status = (ENOSYS);
1488             break;
1489     }
1491     return status;
1493  /**
1494   * Unblock read calls
1495   *
1496   * This function checks if the client is blocked on a read call and if so,
1497   * unblocks the client.
1498   *
1499   * \param ctp     Thread's associated context information.
1500   * \param msg     The pulse message.
1501   * \param ocb     OCB associated with client's session.
1502   *
1503   * \return POSIX errno value.
1504   *
1505   * \retval EINTR    The client has been unblocked.
1506   * \retval other    The client has not been unblocked or the client was not
1507   *                  blocked.
1508   */
1510 int
1511 ti_ipc_read_unblock(resmgr_context_t *ctp, io_pulse_t *msg, iofunc_ocb_t *i_ocb)
1513     UInt32                  i;
1514     Bool                    flag     = FALSE;
1515     WaitingReaders_t      * wr;
1516     ti_ipc_ocb_t * ocb = (ti_ipc_ocb_t *)i_ocb;
1517     ti_ipc_object * obj = ocb->ipc;
1519     for (i = 0 ; i < MAX_PROCESSES ; i++) {
1520         if (ti_ipc_state.eventState [i].ipc == obj) {
1521             flag = TRUE;
1522             break;
1523         }
1524     }
1526     /*  Let the check remain at run-time. */
1527     if (flag == TRUE) {
1528         /* Let the check remain at run-time for handling any run-time
1529          * race conditions.
1530          */
1531         if (ti_ipc_state.eventState [i].bufList != NULL) {
1532             pthread_mutex_lock(&ti_ipc_state.lock);
1533             wr = find_waiting_reader(i, ctp->rcvid);
1534             if (wr) {
1535                 put_wr(wr);
1536                 pthread_mutex_unlock(&ti_ipc_state.lock);
1537                 return (EINTR);
1538             }
1539             pthread_mutex_unlock(&ti_ipc_state.lock);
1540         }
1541     }
1543     return _RESMGR_NOREPLY;
1546  /**
1547   * Handler for unblock() requests.
1548   *
1549   * Handles unblock request for the client which is requesting to no longer be
1550   * blocked on the ti-ipc driver.
1551   *
1552   * \param ctp     Thread's associated context information.
1553   * \param msg     The pulse message.
1554   * \param ocb     OCB associated with client's session.
1555   *
1556   * \return POSIX errno value.
1557   *
1558   * \retval EINTR    The rcvid has been unblocked.
1559   */
1561 int
1562 ti_ipc_unblock(resmgr_context_t *ctp, io_pulse_t *msg, RESMGR_OCB_T *ocb)
1564     int status = _RESMGR_NOREPLY;
1565     struct _msg_info info;
1567     /*
1568      * Try to run the default unblock for this message.
1569      */
1570     if ((status = iofunc_unblock_default(ctp,msg, ocb)) != _RESMGR_DEFAULT) {
1571         return status;
1572     }
1574     /*
1575      * Check if rcvid is still valid and still has an unblock
1576      * request pending.
1577      */
1578     if (MsgInfo(ctp->rcvid, &info) == -1 ||
1579         !(info.flags & _NTO_MI_UNBLOCK_REQ)) {
1580         return _RESMGR_NOREPLY;
1581     }
1583     if (ti_ipc_read_unblock(ctp, msg, ocb) != _RESMGR_NOREPLY) {
1584            return _RESMGR_ERRNO(EINTR);
1585     }
1587     return _RESMGR_ERRNO(EINTR);
1590  /**
1591   * Handler for notify() requests.
1592   *
1593   * Handles special notify() requests that we export for control.  A notify
1594   * request results from the client calling select().
1595   *
1596   * \param ctp     Thread's associated context information.
1597   * \param msg     The actual notify() message.
1598   * \param ocb     OCB associated with client's session.
1599   *
1600   * \return POSIX errno value.
1601   */
1603 Int
1604 ti_ipc_notify( resmgr_context_t *ctp, io_notify_t *msg, RESMGR_OCB_T *ocb)
1606     ti_ipc_ocb_t * ipc_ocb = (ti_ipc_ocb_t *)ocb;
1607     int trig;
1608     int i = 0;
1609     Bool flag = FALSE;
1610     MsgList_t * item = NULL;
1611     int status = EOK;
1612     ti_ipc_object * obj = ipc_ocb->ipc;
1614     trig = _NOTIFY_COND_OUTPUT; /* clients can give us data */
1616     for (i = 0 ; i < MAX_PROCESSES ; i++) {
1617         if (ti_ipc_state.eventState [i].ipc == obj) {
1618             flag = TRUE;
1619             break;
1620         }
1621     }
1623     pthread_mutex_lock(&ti_ipc_state.lock);
1624     /* Let the check remain at run-time. */
1625     if (flag == TRUE) {
1626         /* Let the check remain at run-time for handling any run-time
1627         * race conditions.
1628         */
1629         if (ti_ipc_state.eventState [i].bufList != NULL) {
1630             item = find_nl(i);
1631             if (item && item->num_events > 0) {
1632                 trig |= _NOTIFY_COND_INPUT;
1633             }
1634         }
1635     }
1636     status = iofunc_notify(ctp, msg, ipc_ocb->ipc->notify, trig, NULL, NULL);
1637     pthread_mutex_unlock(&ti_ipc_state.lock);
1638     return status;
1641  /**
1642   * Initializes and attaches ti-ipc resource manager functions to an
1643   * ti-ipc device name.
1644   *
1645   * \param num     The number to append to the end of the device name.
1646   *
1647   * \return Pointer to the created ti_ipc_dev_t device.
1648   */
1650 static
1651 ti_ipc_dev_t *
1652 _init_device ()
1654     iofunc_attr_t  * attr;
1655     resmgr_attr_t    resmgr_attr;
1656     ti_ipc_dev_t *   dev = NULL;
1658     dev = malloc(sizeof(*dev));
1659     if (dev == NULL) {
1660         return NULL;
1661     }
1663     memset(&resmgr_attr, 0, sizeof resmgr_attr);
1664     resmgr_attr.nparts_max = 10;
1665     resmgr_attr.msg_max_size = 2048;
1666     memset(&dev->ti_ipc.mattr, 0, sizeof(iofunc_mount_t));
1667     dev->ti_ipc.mattr.flags = ST_NOSUID | ST_NOEXEC;
1668     dev->ti_ipc.mattr.conf = IOFUNC_PC_CHOWN_RESTRICTED |
1669                               IOFUNC_PC_NO_TRUNC |
1670                               IOFUNC_PC_SYNC_IO;
1671     dev->ti_ipc.mattr.funcs = &dev->ti_ipc.mfuncs;
1672     memset(&dev->ti_ipc.mfuncs, 0, sizeof(iofunc_funcs_t));
1673     dev->ti_ipc.mfuncs.nfuncs = _IOFUNC_NFUNCS;
1674     dev->ti_ipc.mfuncs.ocb_calloc = ti_ipc_ocb_calloc;
1675     dev->ti_ipc.mfuncs.ocb_free = ti_ipc_ocb_free;
1676     iofunc_func_init(_RESMGR_CONNECT_NFUNCS, &dev->ti_ipc.cfuncs,
1677                      _RESMGR_IO_NFUNCS, &dev->ti_ipc.iofuncs);
1678     iofunc_attr_init(attr = &dev->ti_ipc.cattr, S_IFCHR | 0777, NULL, NULL);
1679     dev->ti_ipc.iofuncs.unblock = ti_ipc_unblock;
1680     dev->ti_ipc.iofuncs.devctl = ti_ipc_devctl;
1681     dev->ti_ipc.iofuncs.notify = ti_ipc_notify;
1682     dev->ti_ipc.iofuncs.close_ocb = ti_ipc_close_ocb;
1683     dev->ti_ipc.iofuncs.read = ti_ipc_read;
1684     dev->ti_ipc.iofuncs.write = ti_ipc_write;
1685     attr->mount = &dev->ti_ipc.mattr;
1686     iofunc_time_update(attr);
1688     if (-1 == (dev->ti_ipc.resmgr_id =
1689         resmgr_attach(syslink_dpp, &resmgr_attr,
1690                       TIIPC_DEVICE_NAME, _FTYPE_ANY, 0,
1691                       &dev->ti_ipc.cfuncs,
1692                       &dev->ti_ipc.iofuncs, attr))) {
1693         free(dev);
1694         return(NULL);
1695     }
1697     return(dev);
1700  /**
1701   * Detaches an ti-ipc resource manager device name.
1702   *
1703   * \param dev     The device to detach.
1704   *
1705   * \return POSIX errno value.
1706   */
1708 static
1709 Void
1710 _deinit_device (ti_ipc_dev_t * dev)
1712     resmgr_detach(syslink_dpp, dev->ti_ipc.resmgr_id, 0);
1714     free (dev);
1716     return;
1719 /*!
1720  *  @brief  Module setup function.
1721  *
1722  *  @sa     ti_ipc_destroy
1723  */
1724 Int
1725 ti_ipc_setup (Void)
1727     UInt16 i;
1728     List_Params  listparams;
1729     Int status = 0;
1730     Error_Block eb;
1731     pthread_attr_t thread_attr;
1732     struct sched_param sched_param;
1734     GT_0trace (curTrace, GT_ENTER, "ti_ipc_setup");
1736     Error_init(&eb);
1738     List_Params_init (&listparams);
1739     ti_ipc_state.gateHandle = (IGateProvider_Handle)
1740                      GateSpinlock_create ((GateSpinlock_Handle) NULL, &eb);
1741 #if !defined(SYSLINK_BUILD_OPTIMIZE)
1742     if (ti_ipc_state.gateHandle == NULL) {
1743         status = -ENOMEM;
1744         GT_setFailureReason (curTrace,
1745                              GT_4CLASS,
1746                              "_ti_ipc_setup",
1747                              status,
1748                              "Failed to create spinlock gate!");
1749     }
1750     else {
1751 #endif /* if !defined(SYSLINK_BUILD_OPTIMIZE) */
1752         for (i = 0 ; i < MAX_PROCESSES ; i++) {
1753             ti_ipc_state.eventState [i].bufList = NULL;
1754             ti_ipc_state.eventState [i].ipc = NULL;
1755             ti_ipc_state.eventState [i].refCount = 0;
1756             ti_ipc_state.eventState [i].head = NULL;
1757             ti_ipc_state.eventState [i].tail = NULL;
1758         }
1760         pthread_attr_init(&thread_attr );
1761         sched_param.sched_priority = PRIORITY_REALTIME_LOW;
1762         pthread_attr_setinheritsched(&thread_attr, PTHREAD_EXPLICIT_SCHED);
1763         pthread_attr_setschedpolicy(&thread_attr, SCHED_RR);
1764         pthread_attr_setschedparam(&thread_attr, &sched_param);
1766         ti_ipc_state.run = TRUE;
1767         if (pthread_create(&ti_ipc_state.nt,
1768                            &thread_attr, notifier_thread, NULL) == EOK) {
1769             pthread_setname_np(ti_ipc_state.nt, "tiipc-notifier");
1770             /* create a /dev/tiipc instance for users to open */
1771             if (!ti_ipc_state.dev)
1772                 ti_ipc_state.dev = _init_device();
1773             if (ti_ipc_state.dev == NULL) {
1774                 Osal_printf("Failed to create tiipc");
1775                 ti_ipc_state.run = FALSE;
1776             }
1777             else {
1778                 ti_ipc_state.isSetup = TRUE;
1779             }
1780         }
1781         else {
1782             ti_ipc_state.run = FALSE;
1783         }
1784         pthread_attr_destroy(&thread_attr);
1785 #if !defined(SYSLINK_BUILD_OPTIMIZE)
1786     }
1787 #endif /* if !defined(SYSLINK_BUILD_OPTIMIZE) */
1789     GT_0trace (curTrace, GT_LEAVE, "ti_ipc_setup");
1790     return status;
1794 /*!
1795  *  @brief  Module destroy function.
1796  *
1797  *  @sa     ti_ipc_setup
1798  */
1799 Void
1800 ti_ipc_destroy (bool recover)
1802     ipc_EventPacket * packet;
1803     UInt32                  i;
1804     List_Handle             bufList;
1805     ti_ipc_object      * obj = NULL;
1806     WaitingReaders_t      * wr = NULL;
1807     struct _msg_info        info;
1809     GT_0trace (curTrace, GT_ENTER, "_ti_ipc_destroy");
1811     if (!recover)
1812         _deinit_device(ti_ipc_state.dev);
1814     for (i = 0 ; i < MAX_PROCESSES ; i++) {
1815         obj = NULL;
1816         if (ti_ipc_state.eventState [i].ipc != NULL) {
1817             /* This is recovery.  Need to mark mq structures as invalid */
1818             obj = ti_ipc_state.eventState[i].ipc;
1819             MessageQCopy_delete(&obj->mq);
1820             obj->mq = NULL;
1821             obj->isValid = FALSE;
1822         }
1823         bufList = ti_ipc_state.eventState [i].bufList;
1825         ti_ipc_state.eventState [i].bufList = NULL;
1826         ti_ipc_state.eventState [i].ipc = NULL;
1827         ti_ipc_state.eventState [i].refCount = 0;
1828         if (bufList != NULL) {
1829             /* Dequeue waiting readers and reply to them */
1830             pthread_mutex_lock(&ti_ipc_state.lock);
1831             while ((wr = dequeue_waiting_reader(i)) != NULL) {
1832                 /* Check if rcvid is still valid */
1833                 if (MsgInfo(wr->rcvid, &info) != -1) {
1834                     put_wr(wr);
1835                     pthread_mutex_unlock(&ti_ipc_state.lock);
1836                     MsgError(wr->rcvid, EINTR);
1837                     pthread_mutex_lock(&ti_ipc_state.lock);
1838                 }
1839             }
1840             /* Check for pending ionotify/select calls */
1841             if (obj) {
1842                 if (IOFUNC_NOTIFY_INPUT_CHECK(obj->notify, 1, 0)) {
1843                     iofunc_notify_trigger(obj->notify, 1, IOFUNC_NOTIFY_INPUT);
1844                 }
1845             }
1846             pthread_mutex_unlock(&ti_ipc_state.lock);
1848             /* Free event packets for any received but unprocessed events. */
1849             while (List_empty (bufList) != TRUE){
1850                 packet = (ipc_EventPacket *)
1851                               List_get (bufList);
1852                 if (packet != NULL){
1853                     Memory_free (NULL, packet, sizeof(*packet));
1854                 }
1855             }
1856             List_delete (&(bufList));
1857         }
1858     }
1860     /* Free the cached list */
1861     pthread_mutex_lock(&ti_ipc_state.lock);
1862     flush_uBuf();
1863     pthread_mutex_unlock(&ti_ipc_state.lock);
1865     if (ti_ipc_state.gateHandle != NULL) {
1866         GateSpinlock_delete ((GateSpinlock_Handle *)
1867                                        &(ti_ipc_state.gateHandle));
1868     }
1870     ti_ipc_state.isSetup = FALSE ;
1871     ti_ipc_state.run = FALSE;
1872     // run through and destroy the thread, and all outstanding
1873     // notify structures
1874     pthread_mutex_lock(&ti_ipc_state.lock);
1875     pthread_cond_signal(&ti_ipc_state.cond);
1876     pthread_mutex_unlock(&ti_ipc_state.lock);
1877     pthread_join(ti_ipc_state.nt, NULL);
1878     pthread_mutex_lock(&ti_ipc_state.lock);
1879     while (ti_ipc_state.head != NULL) {
1880         int index;
1881         WaitingReaders_t *item;
1882         index = dequeue_notify_list_item(ti_ipc_state.head);
1883         if (index < 0)
1884             break;
1885         item = dequeue_waiting_reader(index);
1886         while (item) {
1887             put_wr(item);
1888             item = dequeue_waiting_reader(index);
1889         }
1890     }
1891     ti_ipc_state.head = NULL ;
1892     ti_ipc_state.tail = NULL ;
1893     pthread_mutex_unlock(&ti_ipc_state.lock);
1895     GT_0trace (curTrace, GT_LEAVE, "_ti_ipc_destroy");