Notify: Add NULL check for robustness
[ipc/ipcdev.git] / packages / ti / sdo / ipc / Notify.c
1 /*
2  * Copyright (c) 2012-2019, Texas Instruments Incorporated
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * *  Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * *  Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * *  Neither the name of Texas Instruments Incorporated nor the names of
17  *    its contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 /*
33  *  ======== Notify.c ========
34  */
36 #include <xdc/std.h>
38 #include <xdc/runtime/Assert.h>
39 #include <xdc/runtime/Gate.h>
40 #include <xdc/runtime/Memory.h>
41 #include <xdc/runtime/Startup.h>
42 #include <xdc/runtime/Error.h>
44 #include <ti/sdo/ipc/interfaces/INotifyDriver.h>
46 #include <ti/sdo/ipc/_Notify.h>
47 #include <ti/sdo/utils/_MultiProc.h>
48 #include <ti/sdo/utils/List.h>
50 #include <ti/sysbios/hal/Hwi.h>
52 #include "package/internal/Notify.xdc.h"
54 #define ISRESERVED(eventId) (((eventId) & 0xFFFF) >= ti_sdo_ipc_Notify_reservedEvents || \
55                                 (((eventId) >> 16) == Notify_SYSTEMKEY))
57 /* Bit mask operations */
58 #define SET_BIT(num,pos)            ((num) |= (1u << (pos)))
59 #define CLEAR_BIT(num,pos)          ((num) &= ~(1u << (pos)))
60 #define TEST_BIT(num,pos)           ((num) & (1u << (pos)))
62 #ifdef __ti__
63     #pragma FUNC_EXT_CALLED(Notify_attach);
64     #pragma FUNC_EXT_CALLED(Notify_disable);
65     #pragma FUNC_EXT_CALLED(Notify_disableEvent);
66     #pragma FUNC_EXT_CALLED(Notify_enableEvent);
67     #pragma FUNC_EXT_CALLED(Notify_eventAvailable);
68     #pragma FUNC_EXT_CALLED(Notify_intLineRegistered);
69     #pragma FUNC_EXT_CALLED(Notify_numIntLines);
70     #pragma FUNC_EXT_CALLED(Notify_registerEvent);
71     #pragma FUNC_EXT_CALLED(Notify_registerEventSingle);
72     #pragma FUNC_EXT_CALLED(Notify_restore);
73     #pragma FUNC_EXT_CALLED(Notify_sendEvent);
74     #pragma FUNC_EXT_CALLED(Notify_sharedMemReq);
75     #pragma FUNC_EXT_CALLED(Notify_unregisterEvent);
76     #pragma FUNC_EXT_CALLED(Notify_unregisterEventSingle);
77 #endif
79 /*
80  *************************************************************************
81  *                       Common Header Functions
82  *************************************************************************
83  */
85 /*
86  *  A Note about interrupt latency:
87  *
88  *  Some of the functions below modify the registration of callback functions
89  *  (registerEventSingle, unregisterEventSingle, registerEvent, unregisterEvent)
90  *  Because the state of event registration is modified in these functions and
91  *  the Notify_exec function (run within an ISR context) reads this state, we
92  *  have to consider the possibility and outcome of these functions being
93  *  interrupted by the Notify_exec function.  In order to ensure the integrity
94  *  of the callback registration state during any call to Notify_exec, we
95  *  eliminate the possiblity of preemption altogether by adhering to the
96  *  following rules:
97  *
98  *  - If registering a single (or many) callback functions, modify state in the
99  *    following order:
100  *
101  *    1.  Add to the event list (if registerEvent)
102  *    2.  Add the callback function (if registerEventSingle for the first time
103  *        or if doing a single register)
104  *    3.  Finally enable the event in the notify driver, thus opening the gate
105  *        for incoming interrupts.
106  *
107  *    Performing step 3) last during a register is crucial as it ensures that
108  *    the remote processor never sends an interrupt that disrupts the operations
109  *    performed in/between 1) and 2).
110  *
111  *  - If unregistering a single (or many) callback functions, perform the
112  *    above steps in reverse order.  Doing so ensures that possibility of
113  *    getting incoming interrupts is eliminated before local callback
114  *    registration state is modified.
115  *
116  */
118 /*
119  *  ======== Notify_attach ========
120  *  Called within Ipc module or directly by the user
121  */
122 Int Notify_attach(UInt16 remoteProcId, Ptr sharedAddr)
124     Int status;
126     /* validate remote processor ID */
127     if ((remoteProcId >= ti_sdo_utils_MultiProc_numProcessors)
128             || (remoteProcId == MultiProc_self())) {
130         return (Notify_E_INVALIDARG);
131     }
133     /* use the NotifySetup proxy to setup drivers */
134     status = ti_sdo_ipc_Notify_SetupProxy_attach(remoteProcId, sharedAddr);
136     return (status);
140 /*
141  *  ======== Notify_disable ========
142  */
143 UInt Notify_disable(UInt16 procId, UInt16 lineId)
145     UInt key;
146     UInt modKey;
147     UInt16 clusterId = ti_sdo_utils_MultiProc_getClusterId(procId);
148     ti_sdo_ipc_Notify_Object *obj;
150     Assert_isTrue(procId < ti_sdo_utils_MultiProc_numProcessors &&
151             lineId < ti_sdo_ipc_Notify_numLines,
152             ti_sdo_ipc_Notify_A_invArgument);
154     obj = (ti_sdo_ipc_Notify_Object *)
155         Notify_module->notifyHandles[clusterId][lineId];
157     Assert_isTrue(obj != NULL, ti_sdo_ipc_Notify_A_notRegistered);
159     /* Nesting value and enable state have to be in sync */
160     modKey = Gate_enterModule();
162     obj->nesting++;
163     if (obj->nesting == 1) {
164         /* Disable receiving all events */
165         if (procId != MultiProc_self()) {
166             INotifyDriver_disable(obj->driverHandle);
167         }
168     }
170     key = obj->nesting;
172     Gate_leaveModule(modKey);
174     return (key);
177 /*
178  *  ======== Notify_disableEvent ========
179  */
180 Void Notify_disableEvent(UInt16 procId, UInt16 lineId, UInt32 eventId)
182     UInt32 strippedEventId = (eventId & 0xFFFF);
183     UInt16 clusterId = ti_sdo_utils_MultiProc_getClusterId(procId);
184     ti_sdo_ipc_Notify_Object *obj;
185     UInt sysKey;
187     Assert_isTrue(procId < ti_sdo_utils_MultiProc_numProcessors && lineId <
188             ti_sdo_ipc_Notify_numLines, ti_sdo_ipc_Notify_A_invArgument);
189     Assert_isTrue(strippedEventId < ti_sdo_ipc_Notify_numEvents,
190             ti_sdo_ipc_Notify_A_invArgument);
191     Assert_isTrue(ISRESERVED(eventId), ti_sdo_ipc_Notify_A_reservedEvent);
193     obj = (ti_sdo_ipc_Notify_Object *)
194             Notify_module->notifyHandles[clusterId][lineId];
196     Assert_isTrue(obj != NULL, ti_sdo_ipc_Notify_A_notRegistered);
198     if (procId != MultiProc_self()) {
199         /* disable the remote event */
200         INotifyDriver_disableEvent(obj->driverHandle, strippedEventId);
201     }
202     else {
203         /* disable the local event */
204         sysKey = Hwi_disable();
205         CLEAR_BIT(Notify_module->localEnableMask, strippedEventId);
206         Hwi_restore(sysKey);
207     }
210 /*
211  *  ======== Notify_enableEvent ========
212  */
213 Void Notify_enableEvent(UInt16 procId, UInt16 lineId, UInt32 eventId)
215     UInt32 strippedEventId = (eventId & 0xFFFF);
216     UInt16 clusterId = ti_sdo_utils_MultiProc_getClusterId(procId);
217     ti_sdo_ipc_Notify_Object *obj;
218     UInt sysKey;
220     Assert_isTrue(procId < ti_sdo_utils_MultiProc_numProcessors && lineId <
221             ti_sdo_ipc_Notify_numLines, ti_sdo_ipc_Notify_A_invArgument);
222     Assert_isTrue(strippedEventId < ti_sdo_ipc_Notify_numEvents,
223             ti_sdo_ipc_Notify_A_invArgument);
224     Assert_isTrue(ISRESERVED(eventId), ti_sdo_ipc_Notify_A_reservedEvent);
226     obj = (ti_sdo_ipc_Notify_Object *)
227             Notify_module->notifyHandles[clusterId][lineId];
229     Assert_isTrue(obj != NULL, ti_sdo_ipc_Notify_A_notRegistered);
231     if (procId != MultiProc_self()) {
232         /* enable the remote event */
233         INotifyDriver_enableEvent(obj->driverHandle, strippedEventId);
234     }
235     else {
236         /* enable the local event */
237         sysKey = Hwi_disable();
238         SET_BIT(Notify_module->localEnableMask, strippedEventId);
239         Hwi_restore(sysKey);
240     }
243 /*
244  *  ======== Notify_eventAvailable ========
245  */
246 Bool Notify_eventAvailable(UInt16 procId, UInt16 lineId, UInt32 eventId)
248     UInt32 strippedEventId = (eventId & 0xFFFF);
249     UInt16 clusterId = ti_sdo_utils_MultiProc_getClusterId(procId);
250     Bool available;
251     ti_sdo_ipc_Notify_Object *obj;
253     Assert_isTrue(procId < ti_sdo_utils_MultiProc_numProcessors && lineId <
254             ti_sdo_ipc_Notify_numLines, ti_sdo_ipc_Notify_A_invArgument);
255     Assert_isTrue(strippedEventId < ti_sdo_ipc_Notify_numEvents,
256             ti_sdo_ipc_Notify_A_invArgument);
258     obj = (ti_sdo_ipc_Notify_Object *)
259             Notify_module->notifyHandles[clusterId][lineId];
260     if (obj == NULL) {
261         /* Driver not registered */
262         return (FALSE);
263     }
265     if (!ISRESERVED(eventId)) {
266         /* Event is reserved and the caller isn't using Notify_SYSTEMKEY */
267         return (FALSE);
268     }
270     available = (obj->callbacks[strippedEventId].fnNotifyCbck == NULL);
272     return (available);
275 /*
276  *  ======== Notify_intLineRegistered ========
277  */
278 Bool Notify_intLineRegistered(UInt16 procId, UInt16 lineId)
280     Bool registered;
281     UInt16 clusterId = ti_sdo_utils_MultiProc_getClusterId(procId);
283     Assert_isTrue(procId < ti_sdo_utils_MultiProc_numProcessors && lineId <
284             ti_sdo_ipc_Notify_numLines, ti_sdo_ipc_Notify_A_invArgument);
286     registered = (Notify_module->notifyHandles[clusterId][lineId] != NULL);
288     return (registered);
291 /*
292  *  ======== Notify_numIntLines ========
293  */
294 UInt16 Notify_numIntLines(UInt16 procId)
296     UInt16 numIntLines;
298     if (MultiProc_self() == procId) {
299         /* There is always a single interrupt line to the loopback instance */
300         numIntLines = 1;
301     }
302     else {
303         /* Query the NotifySetup module for the device */
304         numIntLines = ti_sdo_ipc_Notify_SetupProxy_numIntLines(procId);
305     }
307     return (numIntLines);
310 /*
311  *  ======== Notify_registerEvent ========
312  */
313 Int Notify_registerEvent(UInt16                 procId,
314                          UInt16                 lineId,
315                          UInt32                 eventId,
316                          Notify_FnNotifyCbck    fnNotifyCbck,
317                          UArg                   cbckArg)
319     UInt32               strippedEventId = (eventId & 0xFFFF);
320     UInt16 clusterId =   ti_sdo_utils_MultiProc_getClusterId(procId);
321     Int                  status;
322     ti_sdo_ipc_Notify_Object        *obj;
323     UInt                 modKey;
324     List_Handle          eventList;
325     ti_sdo_ipc_Notify_EventListener *listener;
326     Bool                 listWasEmpty;
327     Error_Block          eb;
329     Assert_isTrue(procId < ti_sdo_utils_MultiProc_numProcessors &&
330             lineId < ti_sdo_ipc_Notify_numLines, ti_sdo_ipc_Notify_A_invArgument);
331     Assert_isTrue(strippedEventId < ti_sdo_ipc_Notify_numEvents,
332             ti_sdo_ipc_Notify_A_invArgument);
333     Assert_isTrue(ISRESERVED(eventId), ti_sdo_ipc_Notify_A_reservedEvent);
335     Error_init(&eb);
337     modKey = Gate_enterModule();
339     obj = (ti_sdo_ipc_Notify_Object *)
340             Notify_module->notifyHandles[clusterId][lineId];
342     Assert_isTrue(obj != NULL, ti_sdo_ipc_Notify_A_notRegistered);
344     /* Allocate a new EventListener */
345     listener = Memory_alloc(ti_sdo_ipc_Notify_Object_heap(),
346             sizeof(ti_sdo_ipc_Notify_EventListener), 0, &eb);
347     if (listener == NULL) {
348         /* Listener memory allocation failed.  Leave module gate & return */
349         Gate_leaveModule(modKey);
351         return (Notify_E_MEMORY);
352     }
354     listener->callback.fnNotifyCbck = (Fxn)fnNotifyCbck;
355     listener->callback.cbckArg = cbckArg;
357     eventList = List_Object_get(obj->eventList, strippedEventId);
358     if (eventList == NULL) {
359         Gate_leaveModule(modKey);
361         return (Notify_E_RESOURCE);
362     }
364     /*
365      *  Store whether the list was empty so we know whether to register the
366      *  callback
367      */
368     listWasEmpty = List_empty(eventList);
370     /*
371      *  Need to atomically add to the list using the system gate because
372      *  Notify_exec might preempt List_remove.  List_put is atomic.
373      */
374     List_put(eventList, (List_Elem *)listener);
376     if (listWasEmpty) {
377         /*
378          *  Registering this event for the first time.  Need to register the
379          *  callback function.
380          */
381         status = Notify_registerEventSingle(procId, lineId, eventId,
382             Notify_execMany, (UArg)obj);
384         /* Notify_registerEventSingle should always succeed */
385         Assert_isTrue(status == Notify_S_SUCCESS,
386                 ti_sdo_ipc_Notify_A_internal);
387     }
389     status = Notify_S_SUCCESS;
391     Gate_leaveModule(modKey);
393     return (status);
396 /*
397  *  ======== Notify_registerEventSingle ========
398  */
399 Int Notify_registerEventSingle(UInt16                 procId,
400                                UInt16                 lineId,
401                                UInt32                 eventId,
402                                Notify_FnNotifyCbck    fnNotifyCbck,
403                                UArg                   cbckArg)
405     UInt32        strippedEventId = (eventId & 0xFFFF);
406     UInt16 clusterId = ti_sdo_utils_MultiProc_getClusterId(procId);
407     UInt          modKey;
408     Int           status;
409     ti_sdo_ipc_Notify_Object *obj;
411     Assert_isTrue(procId < ti_sdo_utils_MultiProc_numProcessors &&
412             lineId < ti_sdo_ipc_Notify_numLines, ti_sdo_ipc_Notify_A_invArgument);
413     Assert_isTrue(strippedEventId < ti_sdo_ipc_Notify_numEvents,
414             ti_sdo_ipc_Notify_A_invArgument);
415     Assert_isTrue(ISRESERVED(eventId), ti_sdo_ipc_Notify_A_reservedEvent);
417     modKey = Gate_enterModule();
419     obj = (ti_sdo_ipc_Notify_Object *)
420             Notify_module->notifyHandles[clusterId][lineId];
422     Assert_isTrue(obj != NULL, ti_sdo_ipc_Notify_A_notRegistered);
424     if (obj->callbacks[strippedEventId].fnNotifyCbck) {
425         /* A callback is already registered. Fail. */
426         status = Notify_E_ALREADYEXISTS;
427     }
428     else {
429         /*
430          *  No callback is registered. Register it. There is no need to protect
431          *  these modifications because the event isn't registered yet.
432          */
433         obj->callbacks[strippedEventId].fnNotifyCbck = (Fxn)fnNotifyCbck;
434         obj->callbacks[strippedEventId].cbckArg = cbckArg;
436         if (procId != MultiProc_self()) {
437             /* Tell the remote notify driver that the event is now registered */
438             INotifyDriver_registerEvent(obj->driverHandle, strippedEventId);
439         }
441         status = Notify_S_SUCCESS;
442     }
444     Gate_leaveModule(modKey);
446     return (status);
449 /*
450  *  ======== Notify_restore ========
451  */
452 Void Notify_restore(UInt16 procId, UInt16 lineId, UInt key)
454     UInt modKey;
455     UInt16 clusterId = ti_sdo_utils_MultiProc_getClusterId(procId);
456     ti_sdo_ipc_Notify_Object *obj;
458     Assert_isTrue(procId < ti_sdo_utils_MultiProc_numProcessors &&
459             lineId < ti_sdo_ipc_Notify_numLines, ti_sdo_ipc_Notify_A_invArgument);
461     obj = (ti_sdo_ipc_Notify_Object *)
462             Notify_module->notifyHandles[clusterId][lineId];
464     Assert_isTrue(obj != NULL, ti_sdo_ipc_Notify_A_notRegistered);
465     Assert_isTrue(key == obj->nesting, ti_sdo_ipc_Notify_A_outOfOrderNesting);
467     /* Nesting value and enable state have to be in sync */
468     modKey = Gate_enterModule();
470     obj->nesting--;
471     if (obj->nesting == 0) {
472         /* Enable receiving events */
473         if (procId != MultiProc_self()) {
474             INotifyDriver_enable(obj->driverHandle);
475         }
476     }
478     Gate_leaveModule(modKey);
481 /*
482  *  ======== Notify_sendEvent ========
483  */
484 Int Notify_sendEvent(UInt16   procId,
485                      UInt16   lineId,
486                      UInt32   eventId,
487                      UInt32   payload,
488                      Bool     waitClear)
490     UInt32        strippedEventId = (eventId & 0xFFFF);
491     UInt16        clusterId = ti_sdo_utils_MultiProc_getClusterId(procId);
492     Int           status;
493     ti_sdo_ipc_Notify_Object *obj;
494     UInt          sysKey;
496     Assert_isTrue(procId < ti_sdo_utils_MultiProc_numProcessors &&
497             lineId < ti_sdo_ipc_Notify_numLines, ti_sdo_ipc_Notify_A_invArgument);
498     Assert_isTrue(strippedEventId < ti_sdo_ipc_Notify_numEvents,
499             ti_sdo_ipc_Notify_A_invArgument);
500     Assert_isTrue(ISRESERVED(eventId), ti_sdo_ipc_Notify_A_reservedEvent);
502     obj = (ti_sdo_ipc_Notify_Object *)
503             Notify_module->notifyHandles[clusterId][lineId];
505     Assert_isTrue(obj != NULL, ti_sdo_ipc_Notify_A_notRegistered);
507     if (procId != MultiProc_self()) {
508         /* Send a remote event */
509         status = INotifyDriver_sendEvent(obj->driverHandle,
510                                          strippedEventId,
511                                          payload, waitClear);
512     }
513     else {
514         /*
515          *  The check agaist non-NULL fnNotifyCbCk must be atomic with
516          *  Notify_exec so Notify_exec doesn't encounter a null callback.
517          */
518         sysKey = Hwi_disable();
520         /*
521          *  If nesting == 0 (the driver is enabled) and the event is enabled,
522          *  send the event
523          */
524         if (obj->callbacks[strippedEventId].fnNotifyCbck == NULL) {
525             /* No callbacks are registered locally for the event. */
526             status = Notify_E_EVTNOTREGISTERED;
527         }
528         else if (obj->nesting != 0) {
529             /* Driver is disabled */
530             status = Notify_E_FAIL;
531         }
532         else if (!TEST_BIT (Notify_module->localEnableMask, strippedEventId)){
533             /* Event is disabled */
534             status = Notify_E_EVTDISABLED;
535         }
536         else {
537             /* Execute the callback function registered to the event */
538             ti_sdo_ipc_Notify_exec(obj, strippedEventId, payload);
540             status = Notify_S_SUCCESS;
541         }
543         Hwi_restore(sysKey);
544     }
546     return (status);
549 /*
550  *  ======== Notify_sharedMemReq ========
551  */
552 SizeT Notify_sharedMemReq(UInt16 procId, Ptr sharedAddr)
554     SizeT memReq;
556     if (procId == MultiProc_self()) {
557         return (0);
558     }
560     /* Determine device-specific shared memory requirements */
561     memReq = ti_sdo_ipc_Notify_SetupProxy_sharedMemReq(procId, sharedAddr);
563     return (memReq);
566 /*
567  *  ======== Notify_unregisterEventSingle ========
568  */
569 Int Notify_unregisterEventSingle(UInt16 procId, UInt16 lineId, UInt32 eventId)
571     UInt32  strippedEventId = (eventId & 0xFFFF);
572     UInt16  clusterId = ti_sdo_utils_MultiProc_getClusterId(procId);
573     Int     status;
574     ti_sdo_ipc_Notify_Object *obj;
575     UInt    modKey;
577     Assert_isTrue(procId < ti_sdo_utils_MultiProc_numProcessors &&
578             lineId < ti_sdo_ipc_Notify_numLines, ti_sdo_ipc_Notify_A_invArgument);
579     Assert_isTrue(strippedEventId < ti_sdo_ipc_Notify_numEvents,
580             ti_sdo_ipc_Notify_A_invArgument);
581     Assert_isTrue(ISRESERVED(eventId), ti_sdo_ipc_Notify_A_reservedEvent);
583     modKey = Gate_enterModule();
585     obj = (ti_sdo_ipc_Notify_Object *)
586             Notify_module->notifyHandles[clusterId][lineId];
588     Assert_isTrue(obj != NULL, ti_sdo_ipc_Notify_A_notRegistered);
590     if (obj->callbacks[strippedEventId].fnNotifyCbck) {
591         if (procId != MultiProc_self()) {
592             /*
593              *  First, Tell the remote notify driver that the event is now
594              *  unregistered
595              */
596             INotifyDriver_unregisterEvent(obj->driverHandle,
597                                           strippedEventId);
598         }
600         /*
601          *  No need to protect these modifications with the system gate because
602          *  we shouldn't get preempted by Notify_exec after INotifyDriver_
603          *  unregisterEvent.
604          */
605         obj->callbacks[strippedEventId].fnNotifyCbck = NULL;
606         obj->callbacks[strippedEventId].cbckArg = 0;
608         status = Notify_S_SUCCESS;
609     }
610     else {
611         /* No callback is registered. Fail. */
612         status = Notify_E_FAIL;
613     }
615     Gate_leaveModule(modKey);
617     return (status);
620 /*
621  *  ======== Notify_unregisterEvent ========
622  */
623 Int Notify_unregisterEvent(UInt16                 procId,
624                            UInt16                 lineId,
625                            UInt32                 eventId,
626                            Notify_FnNotifyCbck    fnNotifyCbck,
627                            UArg                   cbckArg)
629     UInt32  strippedEventId = (eventId & 0xFFFF);
630     UInt16  clusterId = ti_sdo_utils_MultiProc_getClusterId(procId);
631     Int     status;
632     UInt    sysKey, modKey;
633     ti_sdo_ipc_Notify_Object *obj;
634     List_Handle eventList;
635     ti_sdo_ipc_Notify_EventListener *listener;
636     UInt    count = 0;
638     Assert_isTrue(procId < ti_sdo_utils_MultiProc_numProcessors && lineId <
639             ti_sdo_ipc_Notify_numLines, ti_sdo_ipc_Notify_A_invArgument);
640     Assert_isTrue(strippedEventId < ti_sdo_ipc_Notify_numEvents,
641             ti_sdo_ipc_Notify_A_invArgument);
642     Assert_isTrue(ISRESERVED(eventId), ti_sdo_ipc_Notify_A_reservedEvent);
644     modKey = Gate_enterModule();
646     obj = (ti_sdo_ipc_Notify_Object *)
647             Notify_module->notifyHandles[clusterId][lineId];
649     Assert_isTrue(obj != NULL, ti_sdo_ipc_Notify_A_notRegistered);
651     eventList = List_Object_get(obj->eventList, strippedEventId);
653     if ( eventList == NULL) {
654         return (Notify_E_NOTFOUND);
655     }
657     if (List_empty(eventList)) {
658         return (Notify_E_NOTFOUND);
659     }
661     /* Get the first listener on the list */
662     listener = (ti_sdo_ipc_Notify_EventListener *)List_next(eventList, NULL);
664     while (listener != NULL) {
665         count++;
666         if (listener->callback.fnNotifyCbck == (Fxn)fnNotifyCbck &&
667                 listener->callback.cbckArg == cbckArg ) {
668             break;      /* found a match! */
669         }
670         listener = (ti_sdo_ipc_Notify_EventListener *)
671             List_next(eventList, (List_Elem *)listener);
672     }
674     if (listener == NULL) {
675         /* Event listener not found */
676         status = Notify_E_NOTFOUND;
677     }
678     else {
679         if (count == 1 && List_next(eventList, (List_Elem *)listener) == NULL) {
680             /*
681              *  If only one element counted so far and the List_next returns
682              *  NULL, the list will be empty after unregistering.  Therefore,
683              *  unregister the callback function.
684              */
685             status = Notify_unregisterEventSingle(procId, lineId, eventId);
686             /* unregisterEvent should always suceed */
687             Assert_isTrue(status == Notify_S_SUCCESS,
688                     ti_sdo_ipc_Notify_A_internal);
690             /*  No need to protect the list removal: the event's unregistered */
691             List_remove(eventList, (List_Elem *)listener);
692         }
693         else {
694             /*
695              *  Need to atomically remove from the list using the system gate
696              *  because Notify_exec might preempt List_remove (the event is
697              *  still registered)
698              */
699             sysKey = Hwi_disable();
700             List_remove(eventList, (List_Elem *)listener);
701             Hwi_restore(sysKey);
702         }
704         /* Free the memory alloc'ed for the event listener */
705         Memory_free(ti_sdo_ipc_Notify_Object_heap(), listener,
706             sizeof(ti_sdo_ipc_Notify_EventListener));
708         status = Notify_S_SUCCESS;
709     }
711     Gate_leaveModule(modKey);
713     return (status);
716 /*
717  *************************************************************************
718  *                      Module functions
719  *************************************************************************
720  */
722 /*
723  *  ======== ti_sdo_ipc_Notify_Module_startup ========
724  */
725 Int ti_sdo_ipc_Notify_Module_startup(Int phase)
727     UInt16 procId = MultiProc_self();
729     /*
730      *  Wait for Startup to be done (if MultiProc id not yet set) because a
731      *  user fxn may set it
732      */
733     if (!Startup_Module_startupDone() && procId == MultiProc_INVALIDID) {
734         return (Startup_NOTDONE);
735     }
737     /* Ensure that the MultiProc ID has been configured */
738     Assert_isTrue(procId != MultiProc_INVALIDID,
739             ti_sdo_utils_MultiProc_A_invalidMultiProcId);
741     /* Create a local instance */
742     ti_sdo_ipc_Notify_create(NULL, procId, 0, NULL, NULL);
744     return (Startup_DONE);
747 /*
748  *************************************************************************
749  *                      Instance functions
750  *************************************************************************
751  */
753 /*
754  *  ======== ti_sdo_ipc_Notify_Instance_init ========
755  */
756 Int ti_sdo_ipc_Notify_Instance_init(
757         ti_sdo_ipc_Notify_Object *obj,
758         INotifyDriver_Handle driverHandle,
759         UInt16 remoteProcId, UInt16 lineId,
760         const ti_sdo_ipc_Notify_Params *params,
761         Error_Block *eb)
763     UInt        i;
764     UInt16      clusterId = ti_sdo_utils_MultiProc_getClusterId(remoteProcId);
765     List_Handle eventList;
767     Assert_isTrue(remoteProcId < ti_sdo_utils_MultiProc_numProcessors &&
768                   lineId < ti_sdo_ipc_Notify_numLines, ti_sdo_ipc_Notify_A_invArgument);
769     Assert_isTrue(Notify_module->notifyHandles[clusterId][lineId] == NULL,
770                   ti_sdo_ipc_Notify_A_alreadyRegistered);
772     obj->remoteProcId = remoteProcId;
773     obj->lineId = lineId;
774     obj->nesting = 0;
776     /* Allocate and initialize (to 0 with calloc()) the callbacks array. */
777     obj->callbacks = Memory_calloc(ti_sdo_ipc_Notify_Object_heap(),
778             (sizeof(ti_sdo_ipc_Notify_EventCallback) *
779             ti_sdo_ipc_Notify_numEvents), 0, eb);
780     if (obj->callbacks == NULL) {
781         return (2);
782     }
784     obj->eventList = Memory_alloc(ti_sdo_ipc_Notify_Object_heap(),
785         sizeof(List_Struct) * ti_sdo_ipc_Notify_numEvents, 0, eb);
786     if (obj->eventList == NULL) {
787         return (1);
788     }
790     for (i = 0; i < ti_sdo_ipc_Notify_numEvents; i++) {
791         eventList = List_Object_get(obj->eventList, i);
793         /* Pass in NULL for eb since construct should never fail */
794         List_construct(List_struct(eventList), NULL);
795     }
797     /* Used solely for remote driver (NULL if remoteProcId == self) */
798     obj->driverHandle = driverHandle;
800     if (driverHandle != NULL) {
801         /* Send this handle to the INotifyDriver */
802         INotifyDriver_setNotifyHandle(driverHandle, obj);
803     }
805     Notify_module->notifyHandles[clusterId][lineId] = obj;
807     return (0);
810 /*
811  *  ======== ti_sdo_ipc_Notify_Instance_finalize ========
812  */
813 Void ti_sdo_ipc_Notify_Instance_finalize(ti_sdo_ipc_Notify_Object *obj,
814         Int status)
816     UInt    i;
817     UInt16  clusterId = ti_sdo_utils_MultiProc_getClusterId(obj->remoteProcId);
819     switch (status) {
820         case 0:
821             /* Unregister the notify instance from the Notify module */
822             Notify_module->notifyHandles[clusterId][obj->lineId] = NULL;
824             /* Destruct the event lists */
825             for (i = 0; i < ti_sdo_ipc_Notify_numEvents; i++) {
826                 List_destruct(List_struct(List_Object_get(obj->eventList, i)));
827             }
829             /* Free memory used for the List.Objects */
830             Memory_free(ti_sdo_ipc_Notify_Object_heap(), obj->eventList,
831                     sizeof(List_Struct) * ti_sdo_ipc_Notify_numEvents);
833             /* OK to fall through */
835         case 1:
836             /* Free memory used for callbacks array */
837             Memory_free(ti_sdo_ipc_Notify_Object_heap(), obj->callbacks,
838                     sizeof(ti_sdo_ipc_Notify_EventCallback) *
839                     ti_sdo_ipc_Notify_numEvents);
840     }
843 /*
844  *  ======== ti_sdo_ipc_Notify_detach ========
845  *  Called within Ipc module
846  */
847 Int ti_sdo_ipc_Notify_detach(UInt16 remoteProcId)
849     ti_sdo_ipc_Notify_Object *obj;
850     UInt16 clusterId = ti_sdo_utils_MultiProc_getClusterId(remoteProcId);
851     INotifyDriver_Handle driverHandle;
852     UInt i;
854     for (i = 0; i < ti_sdo_ipc_Notify_numLines; i++) {
855         obj = (ti_sdo_ipc_Notify_Object *)
856                 Notify_module->notifyHandles[clusterId][i];
858         /* Ensure that notify is actually registered for the procId + lineId */
859         if (obj != NULL) {
860             driverHandle = obj->driverHandle;
862             /* First, unregister the driver since it was registered last */
863             ti_sdo_ipc_Notify_delete(&obj);
865             /* Second, delete the driver itself */
866             INotifyDriver_delete(&driverHandle);
867         }
869     }
871     /* Notify_detech never fails on RTOS */
872     return (Notify_S_SUCCESS);
876 /*
877  *  ======== ti_sdo_ipc_Notify_exec ========
878  */
879 Void ti_sdo_ipc_Notify_exec(ti_sdo_ipc_Notify_Object *obj, UInt32 eventId,
880         UInt32 payload)
882     ti_sdo_ipc_Notify_EventCallback *callback;
884     callback = &(obj->callbacks[eventId]);
886     /* Make sure the callback function is not null */
887     Assert_isTrue(callback->fnNotifyCbck != NULL,
888             ti_sdo_ipc_Notify_A_internal);
890     /* Execute the callback function with its argument and the payload */
891     callback->fnNotifyCbck(obj->remoteProcId, obj->lineId, eventId,
892         callback->cbckArg, payload);
896 /*
897  *************************************************************************
898  *                       Internal functions
899  *************************************************************************
900  */
902 /*
903  *  ======== ti_sdo_ipc_Notify_execMany ========
904  */
905 Void ti_sdo_ipc_Notify_execMany(UInt16 procId, UInt16 lineId, UInt32 eventId,
906         UArg arg, UInt32 payload)
908     ti_sdo_ipc_Notify_Object *obj = (ti_sdo_ipc_Notify_Object *)arg;
909     List_Handle eventList;
910     ti_sdo_ipc_Notify_EventListener *listener;
912     /* Both loopback and the the event itself are enabled */
913     eventList = List_Object_get(obj->eventList, eventId);
915     /* Check eventList Non Null */
916     Assert_isTrue(eventList != NULL, ti_sdo_ipc_Notify_A_internal);
917     /* Additional check to handle case when Assert is disabled */
918     if(eventList == NULL) {
919         return;
920     }
922     /* Use "NULL" to get the first EventListener on the list */
923     listener = (ti_sdo_ipc_Notify_EventListener *)List_next(eventList, NULL);
924     while (listener != NULL) {
925         /* Execute the callback function */
926         listener->callback.fnNotifyCbck(procId, lineId,
927             eventId, listener->callback.cbckArg, payload);
929         listener = (ti_sdo_ipc_Notify_EventListener *)List_next(eventList,
930              (List_Elem *)listener);
931     }
934 /*
935  *                      Added procId/lineId Asserts to [un]registerEvent[Single]
936  *! 24-Mar-2010 skp     Fix SDOCM00068331 (sendEvent shouldn't enter mod gate)
937  *! 04-Mar-2010 skp     Fix SDOCM00067532 (added Notify_eventAvailable)
938  *! 19-Feb-2010 skp     Added FUNC_EXT_CALLED #pragma's
939  *! 21-Jan-2010 skp     Fix SDOCM00066064 (misc notify bugs)
940  *! 01-Dec-2009 skp     Loopback instance created in Module_startup
941  *! 19-Nov-2009 skp     fixed high interrupt latency issues
942  */