]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - keystone-rtos/rm-lld.git/blob - src/rm.c
Completed transaction forwarder
[keystone-rtos/rm-lld.git] / src / rm.c
1 /**
2  *   @file  rm.c
3  *
4  *   @brief   
5  *      This is the Resource Manager source.
6  *
7  *  \par
8  *  ============================================================================
9  *  @n   (C) Copyright 2012, Texas Instruments, Inc.
10  * 
11  *  Redistribution and use in source and binary forms, with or without 
12  *  modification, are permitted provided that the following conditions 
13  *  are met:
14  *
15  *    Redistributions of source code must retain the above copyright 
16  *    notice, this list of conditions and the following disclaimer.
17  *
18  *    Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the 
20  *    documentation and/or other materials provided with the   
21  *    distribution.
22  *
23  *    Neither the name of Texas Instruments Incorporated nor the names of
24  *    its contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
28  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
29  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30  *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
31  *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
32  *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
33  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
36  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
37  *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38  *
39  *  \par
40 */
42 /* RM Types */
43 #include <ti/drv/rm/rm_types.h>
45 /* RM includes */
46 #include <ti/drv/rm/rm.h>
47 #include <ti/drv/rm/rm_services.h>
48 #include <ti/drv/rm/rm_transport.h>
49 #include <ti/drv/rm/rm_policy.h>
50 #include <ti/drv/rm/include/rm_pvt.h>
52 /* RM OSAL layer */
53 #include <rm_osal.h>
55 /**********************************************************************
56  ************************** Globals ***********************************
57  **********************************************************************/
59 /* Place QMSS PDSP permissions array */
60 #pragma DATA_SECTION (rmQmssPdspFirmwarePerms, ".rm");
61 #pragma DATA_ALIGN (rmQmssPdspFirmwarePerms, 128)
62 Rm_Perms rmQmssPdspFirmwarePerms[RM_ALIGN_PERMISSIONS_ARRAY(RM_QMSS_FIRMWARE_PDSPS, Rm_Perms)];
65 /** @brief Global Variable which describes the RM Version Information */
66 const char   rmVersionStr[] = RM_VERSION_STR ":" __DATE__  ":" __TIME__;
68 /**********************************************************************
69  ********************** Internal Functions ****************************
70  **********************************************************************/
72 void Rm_transactionQueueAdd(void *rmHandle, uint32_t transactionId, void *callbackFunc)
73 {
74     Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
75     Rm_TransactionQueueEntry *transactionQueue = (Rm_TransactionQueueEntry *) rmInst->transactionQueue;
76     Rm_TransactionQueueEntry *newEntry;
77     void *key;
79     /* Lock access to the RM instance's transaction queue */
80     key = Rm_osalLocalCsEnter();
82     /* Get memory for a new transaction queue entry from local memory */
83     newEntry = Rm_osalMalloc (sizeof(Rm_TransactionQueueNode), false);
85     /* Populate the new entry. */
86     newEntry->transactionId = transactionId;
87     newEntry->transactionCallback = callbackFunc;
88     newEntry->nextEntry = NULL;  /* New entry's nextEntry pointer will always be NULL */
90     /* Check if there are any entries in the transaction queue */
91     if (transactionQueue)
92     {
93         /* At least one entry in the transaction queue.  Add the new entry to the end of the
94          * transaction queue */
95         while (transactionQueue->nextEntry != NULL)
96         {
97             /* Traverse the list until arriving at the last entry */
98             transactionQueue = transactionQueue->nextEntry;
99         }
101         /* Add the new entry to the end of the queue */
102         transactionQueue->nextEntry = newEntry;
103     }
104     else
105     {
106         /* The transaction queue does not currently exist.  The new entry is the first entry */
107         rmInst->routeMap = newEntry;
108     }
110     Rm_osalLocalCsExit(key);
113 Rm_TransactionQueueEntry *Rm_transactionQueueFind(void *rmHandle, uint32_t transactionId)
115     Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
116     Rm_TransactionQueueEntry *entry = (Rm_TransactionQueueEntry *) rmInst->transactionQueue;
117     void *key;
119     /* Lock access to the RM instance's transaction queue */
120     key = Rm_osalLocalCsEnter();
122     /* Make sure there is at least one entry in the transaction queue */
123     if (entry != NULL)
124     {
125         /* Find the transaction ID within the specified RM instance's transaction queue.
126          * If the end of the transaction queue is reached without finding the entry the 
127          * entry pointer will be NULL */
128         while (entry != NULL)
129         {
130             if (entry->transactionId == transactionId)
131             {
132                 /* Match: break out of loop and return the entry */
133                 break;             
134             }
135             entry = entry->nextEntry;
136         }
137     }
138     
139     Rm_osalLocalCsExit(key);
140     return (entry);
143 uint32_t Rm_transactionQueueDelete(void *rmHandle, uint32_t transactionId)
145     Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
146     Rm_TransactionQueueEntry *currentEntry = (Rm_TransactionQueueEntry *) rmInst->transactionQueue;
147     Rm_TransactionQueueEntry *prevEntry = NULL;
148     void *key;
150     /* Lock access to the RM instance's transaction queue */
151     key = Rm_osalLocalCsEnter();
153     /* Make sure there is at least one entry in the transaction queue */
154     if (currentEntry == NULL)
155     {
156         Rm_osalLocalCsExit(key);
157         return (-1); /* TEMP ERROR RETURN */
158     }
160     /* Find the transaction ID within the specified RM instance's transaction queue. */
161     while (currentEntry != NULL)
162     {
163         if (currentEntry->transactionId == transactionId)
164         {
165             /* Match: break out of loop and delete the entry */
166             break;             
167         }
169         prevEntry = currentEntry;
170         currentEntry = currentEntry->nextEntry;
171     }
173     /* Traversed entire queue but did not find transaction */
174     if (currentEntry == NULL)
175     {
176         Rm_osalLocalCsExit(key);
177         return (-2); /* TEMP ERROR RETURN */
178     }
179     else
180     {
181         /* Delete the transaction queue entry */
182         if ((prevEntry == NULL) && currentEntry->nextEntry)
183         {
184             /* Entry to be deleted exists at start of transaction queue.  Map second
185              * entry to be start of transaction queue as long as there are more than
186              * one entries */
187             rmInst->transactionQueue = currentEntry->nextNode;
188         }
189         else
190         {
191             /* Entry to be deleted is in the middle or at end of the queue.  Adjust adjacent
192              * entry pointers.  This covers the case where the entry to be removed is at the
193              * end of the queue. */
194             prevEntry->nextNode = currentEntry->nextNode;
195         }
197         /* Delete the node, free the memory associated with the node. */
198         Rm_osalFree((void *) currentEntry, sizeof(Rm_TransactionQueueEntry), false);
199     }
201     Rm_osalLocalCsExit(key);
202     return (0); /* RETURN OKAY - FIX MAGIC NUMBER */
205 /* Used in Client Delegate case where it forwarded requests from Client to Server
206  * callback will direct to internal function that forwards response from server back
207  * to client */
208 void Rm_internalCallback (Rm_ServiceRespInfo *responseInfo)
213 void Rm_transactionForwarder (void *rmHandle, Rm_Transaction *transInfo,
214                               Rm_TransactionReceipt *transReceipt)
216     Rm_Inst *rmInst = (Rm_Inst *) rmHandle;
217     Rm_TransRouteMapNode *routeMap = (Rm_TransRouteMapNode *) rmInst->routeMap;
218     uint32_t transactionId;
219     Rm_Packet *rmPkt = NULL;
220     Rm_ProtocolPkt *rmProtPkt = NULL;
222     /* Make sure at least one transport has been registered */
223     if (routeMap == NULL)
224     {
225         transReceipt->transactionResult = RM_SERVICE_ERROR_NO_TRANSPORT_REGISTERED;
226         return;
227     }
228     
229     /* Make sure the RM instance has a transport registered with a higher level agent */
230     if (!rmInst->registeredWithDelegateOrServer)
231     {
232         transReceipt->transactionResult = RM_SERVICE_ERROR_NOT_REGISTERED_WITH_DEL_OR_SERVER;
233         return;
234     }
236     /* Parse the RM instance's routing map to find the higher level agent for forwarding */
237     while ((routeMap->remoteInstType != Rm_instType_CLIENT_DELEGATE) || 
238            (routeMap->remoteInstType != Rm_instType_SERVER))
239     {
240         /* Traverse the list until arriving at the upper level agent node */
241         routeMap = routeMap->nextNode;
242     }
244     /* Create a RM packet using the service information */
245     if (rmInst->transport.rmAllocPkt)
246     {
247         rmPkt = rmInst->transport.rmAllocPkt(routeMap->transHandle, sizeof(Rm_Packet));
248     }
249     else
250     {
251         /* The transport packet alloc API is not plugged */
252         transReceipt->transactionResult = RM_SERVICE_ERROR_TRANSPORT_PKT_ALLOC_API_NULL;
253         return;
254     }
256     /* Make sure a buffer for the packet was allocated  */
257     if (rmPkt == NULL)
258     {
259         transReceipt->transactionResult = RM_SERVICE_ERROR_TRANSPORT_NULL_PKT_BUF;
260         return;
261     }
263     /* Make sure allocated buffer is large enough to fit the protocol packet plus the 
264      * rmPktLen field */
265     if (rmPkt->rmPktLen < (sizeof(Rm_ProtocolPkt) + sizeof(uint32_t))
266     {   
267         transReceipt->transactionResult = RM_SERVICE_ERROR_TRANSPORT_PKT_BUF_TOO_SMALL;
268         return;
269     }
271     /* Create an ID for this transaction.  The ID will be used for two purposes:
272      * 1) Matching the response from the higher level RM agent to the request
273      * 2) Provided to the service requesting component so that it can match the
274      *    service request with the response it receives via its callback function */
275     transactionId = ...; /* NEED SCHEME FOR CREATING A MUTUALLY EXCLUSIVE PKT ID.  CAN'T
276                           * CONFLICT WITH PCKT IDS CREATED ON OTHER RM INSTANCES */
277     /* Initialize the rmPkt.  Do not assume the transport code will do it */                            
278     memset((void *)rmPkt, 0, sizeof(Rm_Packet));
279                           
280     /* Assign the rmData field to be the rmProtPkt */
281     rmProtPkt = &(rmPkt->rmData[0]);
282     /* Populate the RM packet using the service information */
283     rmProtPkt->rmPktId = transactionId;
284     strcpy((void *)rmProtPkt->rmInstName,(void *)rmInst->name);
285     rmProtPkt->rmCmd = (uint32_t) transInfo->transType;
286     if ((transInfo->transCommand == Rm_command_POLICY_REQUEST) ||
287         (transInfo->transCommand == Rm_command_POLICY_RESPONSE)
288     {
289         /* Copy the policy data if the transaction is policy based */
290         memcpy ((void *)rmProtPkt->u.rmPolicyData, (void *)transInfo->u.policyData,
291                 RM_MAX_POLICY_SIZE_BYTES);
292     }
293     else
294     {
295         /* Otherwise copy the resource data */
296         memcpy ((void *)&(rmProtPkt->u.resInfo), (void *) &(transInfo->u.resourceInfo),
297                 sizeof(Rm_ResourceInfo));
298     }
300     /* Create an entry in the transaction queue */
301     Rm_transactionQueueAdd(rmHandle, transactionId, transInfo->transCallback);
303     /* Send the RM packet to the application transport */
304     if (rmInst->transport.rmSend)
305     {
306         if (!(rmInst->transport.rmSend(routeMap->transHandle, rmPkt))
307         {
308             /* Transport returned an error */
310             /* SHOULD TRANSPORT ERROR SOMEHOW BE OR'D WITH THE SERVICE ERROR ??? */
311             transReceipt->transactionResult = RM_SERVICE_ERROR_TRANPSPORT_SEND_ERROR;
312             return;
313         }
314     }
315     else
316     {
317         /* The transport packet send API is not plugged */
318         transReceipt->transactionResult = RM_SERVICE_ERROR_TRANSPORT_PKT_SEND_API_NULL;
319         return;
320     }    
322     /* Inform requesting component that the service is being forwarded to a higher lever
323      * RM agent for processing.  The result of the service will be provided to the 
324      * component via the specified callback function */
325     transReceipt->transactionResult = RM_SERVICE_PROCESSING;
326     transReceipt->transactionId = transactionId;
327     return;
330 void Rm_transactionProcessor (void *rmHandle, Rm_Transaction *transaction, 
331                                  Rm_TransactionReceipt *transactionReceipt)
333     Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
335     /* All service requests on Clients are forwarded to the higher level RM agent
336      * either a Client Delegate or Server, based on the RM system architecture */
337     if (rmInst->instType == Rm_instType_CLIENT)
338     {
339         Rm_transactionForwarder(rmHandle, transaction, transactionReceipt);
341         if (requestInfo->serviceCallback == NULL)
342         {
343             /* RM Client's always use a blocking RM transport to consult with a high-level
344              * RM agent prior to providing a response to the component.  It is assumed the 
345              * component's cannot block.  Therefore, all responses must go through the 
346              * callback function provided by the component.  Return an error if the 
347              * component does not provide a callback function */
348         }
350         /* Provide a transaction ID back to the component so that it can map service requests
351          * to the responses received via the component's callback function */
352         responseInfo->requestId = transactionReceipt.transactionId;
353     }
354     else
355     {
358     }
362 void Rm_serviceHandler (void *rmHandle, Rm_ServiceReqInfo *requestInfo,
363                         Rm_ServiceRespInfo *responseInfo)
365     Rm_Inst *rmInst = (Rm_Inst *) rmHandle;
366     Rm_Transaction transaction;
367     Rm_TransactionReceipt transactionReceipt;
368     void *key;
370     /* Prevent another component using the same instance from wiping out the current
371      * service request */
372     key = Rm_osalLocalCsEnter();
374     /* Make sure serviceType is valid and that a callback function has been provided */
375     if ((requestInfo->serviceType < Rm_service_FIRST) || 
376         (requestInfo->serviceType > Rm_service_LAST))
377     {
378         responseInfo->serviceResult = RM_SERVICE_ERROR_INVALID_SERVICE_TYPE;
379         Rm_osalLocalCsExit(key);
380         return;
381     }
382     else if (requestInfo->serviceCallback == NULL)
383     {
384         responseInfo->serviceResult = RM_SERVICE_ERROR_CALLBACK_NOT_PROVIDED;
385         Rm_osalLocalCsExit(key);
386         return;
387     }
389     /* Clear the transaction and receipt prior to using them */
390     memset((void *) &transaction, 0, sizeof(Rm_Transaction));
391     memset((void *) &transactionReceipt, 0, sizeof(Rm_TransactionReceipt));
393     /* Transfer request information into the internal transaction format */
394     transaction.transCommand = (Rm_Command) requestInfo->serviceType;
395     transaction.transCallback = requestInfo->serviceCallback;
396     /* Policy modifications will never originate from components */
397     strcpy ((void *) &(transaction.u.resourceInfo.resName)[0], (void *)requestInfo->resName);
398     transaction.u.resourceInfo.resBase = requestInfo->resourceBase;
399     transaction.u.resourceInfo.resNum = requestInfo->resourceNum;
400     transaction.u.resourceInfo.resAlign = requestInfo->resourceAlign;
401     strcpy ((void *) &(transaction.u.resourceInfo.resNsName)[0], (void *)requestInfo->resNsName);
403     /* Pass the new transaction to the transaction processor */
404     Rm_transactionProcessor (rmHandle, &transaction, &transactionReceipt);
406     /* Copy transaction receipt information into the response info fields for the 
407      * component based on the result of the transaction.  Denied service requests
408      * will have only a valid serviceResult field */
409     responseInfo->serviceResult = transactionReceipt->transactionResult;
410     if (responseInfo->serviceResult == RM_SERVICE_APPROVED)
411     {
412         /* Service was approved.  The resource data should be passed back
413          * to the component */
414         responseInfo->resBase = transactionReceipt.resBase;
415         responseInfo->resNum = transactionReceipt.resNum;
416     }
417     else if (responseInfo->serviceResult == RM_SERVICE_PROCESSING)
418     {
419         /* The service is still being processed.  Provide the transaction ID
420          * back to the component so that it can sort service responses received
421          * via the provided callback function */
422         responseInfo->requestId = transactionReceipt.transactionId;
423     }
425     Rm_osalLocalCsExit(key);
426     
427     return;
430 /**********************************************************************
431  *********************** Application visible APIs ***************************
432  **********************************************************************/
434 Rm_Handle Rm_init(Rm_InitCfg *initCfg)
436     Rm_Inst *rmInst;
438     /* Instance creation checks.  Add one to strlen calculation for null character */
439     if ((strlen(initCfg->instName) + 1) > RM_INSTANCE_NAME_MAX_CHARS)
440     {
441         /* Failure: Instance name is too big */
442         return (NULL);
443     }
444     
445     /* Get memory for RM instance from local memory */
446     rmInst = Rm_osalMalloc (sizeof(Rm_Inst), false);
447     /* Populate instance based on input parameters */
448     strcpy (&rmInst->name[0], initCfg->instName);
449     rmInst->instType = initCfg->instType;
450     rmInst->instState = RM_state_IDLE;
451     rmInst->registeredWithDelegateOrServer = false;
452     rmInst->serviceCallback = NULL;
454     /* Populate the instance transport callouts */
455     rmInst->transport.rmAllocPkt = initCfg->rmAllocPktFuncPtr;
456     rmInst->transport.rmFreePkt = initCfg->rmFreePktFuncPtr;
457     rmInst->transport.rmSend = initCfg->rmSendFuncPtr;
458     rmInst->transport.rmReceive = initCfg->rmReceiveFuncPtr;
459     rmInst->transport.rmNumPktsReceived = initCfg->rmNumPktsReceivedFuncPtr;
461     /* Initialize the transport routing map linked list pointer to NULL.  The linked list
462      * nodes will be created when the application registers transports */
463     rmInst->routeMap = NULL;
465     /* Initialize the transaction queue linked list pointer to NULL.  The linked list
466      * nodes will be created when the transactions are forwarded to higher level RM
467      * agents. */
468     rmInst->transactionQueue= NULL;
470     /* RM Server specific actions */
471     if (rmInst->instType == Rm_instType_SERVER)
472     {
473        /* parse DTB, etc */
474     }
476     /* Instance startup policies are only used for Servers and Client Delegates */
477     if (rmInst->instType != Rm_instType_CLIENT)
478     {
479         rmInst->instPolicy = initCfg->startupPolicy;
481         /* Store policy via policy APIs ... */
482     }
484     /* Return the RM Handle */
485     return ((Rm_Handle) rmInst);
488 Rm_Result Rm_preMainAllocResource(Rm_PreMainAllocInfo 
489                                                    *preMainAllocInfo)
494 Rm_ServiceHandle Rm_getServiceHandle(Rm_Handle rmHandle)
496     Rm_Inst *rmInst = (Rm_Inst *) rmHandle;
497     Rm_ServicesPort *newServicePort;
498     
499     /* Create a new service handle for the specified RM instance */
500     
501     /* Get memory for a new service port from local memory */
502     newServicePort = Rm_osalMalloc (sizeof(Rm_ServicesPort), false);
504     newServicePort->rmHandle = rmHandle;
505     newServicePort->rmService = rmServiceHandler;
507     return ((Rm_ServiceHandle) newServicePort);
510 /* Resource requests that come directly from application go through this API */
511 void Rm_requestService (void *rmHandle, Rm_ServiceReqInfo *requestInfo,
512                         Rm_ServiceRespInfo *responseInfo)
514     Rm_serviceHandler(rmHandle, requestInfo, responseInfo);
517 Rm_TransportHandle Rm_registerTransport (Rm_Handle rmHandle, Rm_TransCfg *transCfg)
519     Rm_Inst *rmInst = (Rm_Inst *) rmHandle;
520     Rm_TransRouteMapNode *existingRouteMap = (Rm_TransRouteMapNode *) rmInst->routeMap;
521     Rm_TransRouteMapNode *newRouteMapNode;
523     /* RM Servers cannot connect to other Servers */
524     if ((rmInst->instType == Rm_instType_SERVER) &&
525          (transCfg->rmRemoteInstType == Rm_instType_SERVER))
526     {
527         return (NULL); /* Error -return null */
528     }
530     /* Verify Clients and Client Delegates are not registering with more than one 
531      * Client Delegate or Server. Assuming a Client Delegate can register with another 
532      * Client Delegate that can "act" as a server */
533     if (((rmInst->instType == Rm_instType_CLIENT) || 
534          (rmInst->instType == Rm_instType_CLIENT_DELEGATE)) &&
535         ((transCfg->rmRemoteInstType == Rm_instType_CLIENT_DELEGATE) ||
536          (transCfg->rmRemoteInstType == Rm_instType_SERVER)) &&
537         rmInst->registeredWithDelegateOrServer)
538     {
539         return (NULL); /* Error -return null */
540     }         
542     /* Error checks passed - Create a new transport handle for the specified RM instance */
543     
544     /* Get memory for a new routing map node from local memory */
545     newRouteMapNode = Rm_osalMalloc (sizeof(Rm_TransRouteMapNode), false);
547     /* Populate the new node.  The address of the node itself is stored since this address is returned
548      *  to the application as the Rm_TransportHandle */
549     newRouteMapNode->transHandle = newRouteMapNode;
550     newRouteMapNode->remoteInstType = transCfg->rmRemoteInstType;
551     newRouteMapNode->nextNode = NULL;  /* New node will always be NULL */
553     /* Check if there are any entries in the routing map */
554     if (existingRouteMap)
555     {
556         /* At least one entry in the routing map.  Add the new routing map node to the end of the
557          * routing map node list */
558         while (existingRouteMap->nextNode != NULL)
559         {
560             /* Traverse the list until arriving at the last node */
561             existingRouteMap = existingRouteMap->nextNode;
562         }
564         /* Add the new node to the end of the list */
565         existingRouteMap->nextNode = newRouteMapNode;
566     }
567     else
568     {
569         /* A routing map does not currently exist.  The new node is the first entry */
570         rmInst->routeMap = newRouteMapNode;
571     }
573     /* Specify RM instance has registered with a higher level agent */
574     if ((newRouteMapNode->remoteInstType == Rm_instType_CLIENT_DELEGATE) ||
575         (newRouteMapNode->remoteInstType == Rm_instType_SERVER))
576     {
577         rmInst->registeredWithDelegateOrServer = true;
578     }
580     return ((Rm_TransportHandle) newRouteMapNode);
583 Rm_Result Rm_unregisterTransport (Rm_Handle rmHandle, Rm_TransportHandle transHandle)
585     Rm_Inst *rmInst = (Rm_Inst *) rmHandle;
586     Rm_TransRouteMapNode *routeMapNode = (Rm_TransRouteMapNode *) rmInst->routeMap;
587     Rm_TransRouteMapNode *prevNode = NULL;
589     /* Make sure a routing map exists for the RM instance */
590     if (routeMapNode == NULL)
591     {
592         return (-1); /* TEMP ERROR RETURN */
593     }
595     /* Find the transport handle within the specified RM instance's routing map. */
596     while (1)
597     {
598         if (routeMapNode->transHandle == transHandle)
599         {
600             /* Match: break out of loop and delete the node */
601             break;             
602         }
603         else if (routeMapNode->nextNode == NULL)
604         {
605             return (-1); /* TEMP ERROR: transhandle does not exist for RM instance */
606         }
608         prevNode = routeMapNode;
609         routeMapNode = routeMapNode->nextNode;
610     }
611     
612     /* Delete the routing map node */
613     if ((prevNode == NULL) && routeMapNode->nextNode)
614     {
615         /* Node to be deleted exists at start of route map.  Map second node to be start of
616          * node list as long as there are more than one routing map nodes */
617         rmInst->routeMap = routeMapNode->nextNode;
618     }
619     else
620     {
621         /* Node to be deleted is in the middle or at end of the list.  Adjust adjacent
622          * nodes pointers.  This covers the case where the node to be removed is at the
623          * end of the list. */
624         prevNode->nextNode = routeMapNode->nextNode;
625     }
627     /* Remove specification in RM instance that it has been connected to an upper level agent
628      * if the node to be deleted has a remote instance type of Client Delegate or Server */
629     if ((routeMapNode->remoteInstType == Rm_instType_CLIENT_DELEGATE) ||
630         (routeMapNode->remoteInstType == Rm_instType_SERVER))
631     {
632         rmInst->registeredWithDelegateOrServer = false;
633     }
635     /* Delete the node, free the memory associated with the node. */
636     Rm_osalFree((void *) routeMapNode, sizeof(Rm_TransRouteMapNode), false);
638     return (RM_OK);
642 Rm_TransVerifyResult Rm_verifyTransport (Rm_Handle, uint32_t timeout, 
643                                          Rm_TransFailData *failData)
648 uint32_t Rm_getVersion (void)
650     return RM_VERSION_ID;
654 const char* Rm_getVersionStr (void)
656     return rmVersionStr;
659 /**
660 @}
661 */