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);
111 }
113 Rm_TransactionQueueEntry *Rm_transactionQueueFind(void *rmHandle, uint32_t transactionId)
114 {
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 }
139 Rm_osalLocalCsExit(key);
140 return (entry);
141 }
143 uint32_t Rm_transactionQueueDelete(void *rmHandle, uint32_t transactionId)
144 {
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 */
203 }
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)
209 {
211 }
213 void Rm_transactionForwarder (void *rmHandle, Rm_Transaction *transInfo,
214 Rm_TransactionReceipt *transReceipt)
215 {
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 }
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));
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;
328 }
330 void Rm_transactionProcessor (void *rmHandle, Rm_Transaction *transaction,
331 Rm_TransactionReceipt *transactionReceipt)
332 {
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 }
360 }
362 void Rm_serviceHandler (void *rmHandle, Rm_ServiceReqInfo *requestInfo,
363 Rm_ServiceRespInfo *responseInfo)
364 {
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);
427 return;
428 }
430 /**********************************************************************
431 *********************** Application visible APIs ***************************
432 **********************************************************************/
434 Rm_Handle Rm_init(Rm_InitCfg *initCfg)
435 {
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 }
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);
486 }
488 Rm_Result Rm_preMainAllocResource(Rm_PreMainAllocInfo
489 *preMainAllocInfo)
490 {
492 }
494 Rm_ServiceHandle Rm_getServiceHandle(Rm_Handle rmHandle)
495 {
496 Rm_Inst *rmInst = (Rm_Inst *) rmHandle;
497 Rm_ServicesPort *newServicePort;
499 /* Create a new service handle for the specified RM instance */
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);
508 }
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)
513 {
514 Rm_serviceHandler(rmHandle, requestInfo, responseInfo);
515 }
517 Rm_TransportHandle Rm_registerTransport (Rm_Handle rmHandle, Rm_TransCfg *transCfg)
518 {
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 */
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);
581 }
583 Rm_Result Rm_unregisterTransport (Rm_Handle rmHandle, Rm_TransportHandle transHandle)
584 {
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 }
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);
639 }
642 Rm_TransVerifyResult Rm_verifyTransport (Rm_Handle, uint32_t timeout,
643 Rm_TransFailData *failData)
644 {
646 }
648 uint32_t Rm_getVersion (void)
649 {
650 return RM_VERSION_ID;
651 }
654 const char* Rm_getVersionStr (void)
655 {
656 return rmVersionStr;
657 }
659 /**
660 @}
661 */