]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - keystone-rtos/rm-lld.git/blob - src/rm.c
commit prior to modifying transaction tracking and storing
[keystone-rtos/rm-lld.git] / src / rm.c
1 /**\r
2  *   @file  rm.c\r
3  *\r
4  *   @brief   \r
5  *      This is the Resource Manager source.\r
6  *\r
7  *  \par\r
8  *  ============================================================================\r
9  *  @n   (C) Copyright 2012, Texas Instruments, Inc.\r
10  * \r
11  *  Redistribution and use in source and binary forms, with or without \r
12  *  modification, are permitted provided that the following conditions \r
13  *  are met:\r
14  *\r
15  *    Redistributions of source code must retain the above copyright \r
16  *    notice, this list of conditions and the following disclaimer.\r
17  *\r
18  *    Redistributions in binary form must reproduce the above copyright\r
19  *    notice, this list of conditions and the following disclaimer in the \r
20  *    documentation and/or other materials provided with the   \r
21  *    distribution.\r
22  *\r
23  *    Neither the name of Texas Instruments Incorporated nor the names of\r
24  *    its contributors may be used to endorse or promote products derived\r
25  *    from this software without specific prior written permission.\r
26  *\r
27  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \r
28  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT \r
29  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\r
30  *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT \r
31  *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, \r
32  *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT \r
33  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
34  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
35  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT \r
36  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE \r
37  *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
38  *\r
39  *  \par\r
40 */\r
41 \r
42 /* RM Types */\r
43 #include <ti/drv/rm/rm_types.h>\r
44 \r
45 /* RM includes */\r
46 #include <ti/drv/rm/rm.h>\r
47 #include <ti/drv/rm/rm_services.h>\r
48 #include <ti/drv/rm/rm_transport.h>\r
49 #include <ti/drv/rm/rm_policy.h>\r
50 #include <ti/drv/rm/include/rm_pvt.h>\r
51 \r
52 /* RM OSAL layer */\r
53 #include <rm_osal.h>\r
54 \r
55 /**********************************************************************\r
56  ************************** Globals ***********************************\r
57  **********************************************************************/\r
58 \r
59 /* Place QMSS PDSP permissions array */\r
60 #pragma DATA_SECTION (rmQmssPdspFirmwarePerms, ".rm");\r
61 #pragma DATA_ALIGN (rmQmssPdspFirmwarePerms, 128)\r
62 Rm_Perms rmQmssPdspFirmwarePerms[RM_ALIGN_PERMISSIONS_ARRAY(RM_QMSS_FIRMWARE_PDSPS, Rm_Perms)];\r
63 \r
64 \r
65 /** @brief Global Variable which describes the RM Version Information */\r
66 const char   rmVersionStr[] = RM_VERSION_STR ":" __DATE__  ":" __TIME__;\r
67 \r
68 /**********************************************************************\r
69  ********************** Internal Functions ****************************\r
70  **********************************************************************/\r
71 \r
72 void Rm_transactionQueueAdd(Rm_Inst *rmInst, uint32_t transactionId, \r
73                             Rm_TransportHandle transportHandle, void *callbackFunc)\r
74 {\r
75     Rm_TransactionQueueEntry *transactionQueue = (Rm_TransactionQueueEntry *) rmInst->transactionQueue;\r
76     Rm_TransactionQueueEntry *newEntry;\r
77     void *key;\r
78 \r
79     /* Lock access to the RM instance's transaction queue */\r
80     key = Rm_osalLocalCsEnter();\r
81 \r
82     /* Get memory for a new transaction queue entry from local memory */\r
83     newEntry = Rm_osalMalloc (sizeof(Rm_TransactionQueueNode), false);\r
84 \r
85     /* Populate the new entry. */\r
86     newEntry->transactionId = transactionId;\r
87     newEntry->transportHandle = transportHandle;\r
88     newEntry->transactionCallback = callbackFunc;\r
89     newEntry->nextEntry = NULL;  /* New entry's nextEntry pointer will always be NULL */\r
90 \r
91     /* Check if there are any entries in the transaction queue */\r
92     if (transactionQueue)\r
93     {\r
94         /* At least one entry in the transaction queue.  Add the new entry to the end of the\r
95          * transaction queue */\r
96         while (transactionQueue->nextEntry != NULL)\r
97         {\r
98             /* Traverse the list until arriving at the last entry */\r
99             transactionQueue = transactionQueue->nextEntry;\r
100         }\r
101 \r
102         /* Add the new entry to the end of the queue */\r
103         transactionQueue->nextEntry = newEntry;\r
104     }\r
105     else\r
106     {\r
107         /* The transaction queue does not currently exist.  The new entry is the first entry */\r
108         rmInst->routeMap = newEntry;\r
109     }\r
110 \r
111     Rm_osalLocalCsExit(key);\r
112 }\r
113 \r
114 Rm_TransactionQueueEntry *Rm_transactionQueueFind(Rm_Inst *rmInst, uint32_t transactionId)\r
115 {\r
116     Rm_TransactionQueueEntry *entry = (Rm_TransactionQueueEntry *) rmInst->transactionQueue;\r
117     void *key;\r
118 \r
119     /* Lock access to the RM instance's transaction queue */\r
120     key = Rm_osalLocalCsEnter();\r
121 \r
122     /* Make sure there is at least one entry in the transaction queue */\r
123     if (entry != NULL)\r
124     {\r
125         /* Find the transaction ID within the specified RM instance's transaction queue.\r
126          * If the end of the transaction queue is reached without finding the entry the \r
127          * entry pointer will be NULL */\r
128         while (entry != NULL)\r
129         {\r
130             if (entry->transactionId == transactionId)\r
131             {\r
132                 /* Match: break out of loop and return the entry */\r
133                 break;             \r
134             }\r
135             entry = entry->nextEntry;\r
136         }\r
137     }\r
138     \r
139     Rm_osalLocalCsExit(key);\r
140     return (entry);\r
141 }\r
142 \r
143 uint32_t Rm_transactionQueueDelete(Rm_Inst *rmInst, uint32_t transactionId)\r
144 {\r
145     Rm_TransactionQueueEntry *currentEntry = (Rm_TransactionQueueEntry *) rmInst->transactionQueue;\r
146     Rm_TransactionQueueEntry *prevEntry = NULL;\r
147     void *key;\r
148 \r
149     /* Lock access to the RM instance's transaction queue */\r
150     key = Rm_osalLocalCsEnter();\r
151 \r
152     /* Make sure there is at least one entry in the transaction queue */\r
153     if (currentEntry == NULL)\r
154     {\r
155         Rm_osalLocalCsExit(key);\r
156         return (-1); /* TEMP ERROR RETURN */\r
157     }\r
158 \r
159     /* Find the transaction ID within the specified RM instance's transaction queue. */\r
160     while (currentEntry != NULL)\r
161     {\r
162         if (currentEntry->transactionId == transactionId)\r
163         {\r
164             /* Match: break out of loop and delete the entry */\r
165             break;             \r
166         }\r
167 \r
168         prevEntry = currentEntry;\r
169         currentEntry = currentEntry->nextEntry;\r
170     }\r
171 \r
172     /* Traversed entire queue but did not find transaction */\r
173     if (currentEntry == NULL)\r
174     {\r
175         Rm_osalLocalCsExit(key);\r
176         return (-2); /* TEMP ERROR RETURN */\r
177     }\r
178     else\r
179     {\r
180         /* Delete the transaction queue entry */\r
181         if ((prevEntry == NULL) && currentEntry->nextEntry)\r
182         {\r
183             /* Entry to be deleted exists at start of transaction queue.  Map second\r
184              * entry to be start of transaction queue as long as there are more than\r
185              * one entries */\r
186             rmInst->transactionQueue = currentEntry->nextNode;\r
187         }\r
188         else\r
189         {\r
190             /* Entry to be deleted is in the middle or at end of the queue.  Adjust adjacent\r
191              * entry pointers.  This covers the case where the entry to be removed is at the\r
192              * end of the queue. */\r
193             prevEntry->nextNode = currentEntry->nextNode;\r
194         }\r
195 \r
196         /* Delete the node, free the memory associated with the node. */\r
197         Rm_osalFree((void *) currentEntry, sizeof(Rm_TransactionQueueEntry), false);\r
198     }\r
199 \r
200     Rm_osalLocalCsExit(key);\r
201     return (0); /* RETURN OKAY - FIX MAGIC NUMBER */\r
202 }\r
203 \r
204 /* Used in Client Delegate case where it forwarded requests from Client to Server\r
205  * callback will direct to internal function that forwards response from server back\r
206  * to client */\r
207 void Rm_internalCallback (Rm_ServiceRespInfo *responseInfo)\r
208 {\r
209 \r
210 }\r
211 \r
212 /* Function used to send RM response transactions to lower level agents */\r
213 void Rm_transactionResponder (Rm_Inst *rmInst, Rm_Transaction *transaction,\r
214                               Rm_TransactionReceipt *receipt)\r
215 {\r
216     Rm_TransactionQueueEntry *transactionEntry;\r
217     Rm_Packet *rmPkt = NULL;\r
218     Rm_ProtocolPkt *rmProtPkt = NULL;\r
219 \r
220     /* Find the transaction request that matches the received response */\r
221     transactionEntry = Rm_transactionQueueFind(rmInst,transaction->pktId);\r
222 \r
223     if (transactionEntry == NULL)\r
224     {\r
225         /* No transaction request matching the transaction ID was forwarded from\r
226          * this RM instace */\r
227         receipt->transactionResult = RM_SERVICE_ERROR_TRANSACTION_DOES_NOT_EXST_FOR_THIS_RM_INSTANCE;\r
228         return;\r
229     }\r
230 \r
231     /* Create a RM packet using the transaction information */\r
232     if (rmInst->transport.rmAllocPkt)\r
233     {\r
234         rmPkt = rmInst->transport.rmAllocPkt(transactionEntry->transportHandle, sizeof(Rm_Packet));\r
235     }\r
236     else\r
237     {\r
238         /* The transport packet alloc API is not plugged */\r
239         receipt->transactionResult = RM_SERVICE_ERROR_TRANSPORT_PKT_ALLOC_API_NULL;\r
240         return;\r
241     }\r
242 \r
243     /* Make sure a buffer for the packet was allocated  */\r
244     if (rmPkt == NULL)\r
245     {\r
246         receipt->transactionResult = RM_SERVICE_ERROR_TRANSPORT_NULL_PKT_BUF;\r
247         return;\r
248     }\r
249 \r
250     /* Make sure allocated buffer is large enough to fit the protocol packet plus the \r
251      * rmPktLen field */\r
252     if (rmPkt->rmPktLen < (sizeof(Rm_ProtocolPkt) + sizeof(uint32_t))\r
253     {   \r
254         receipt->transactionResult = RM_SERVICE_ERROR_TRANSPORT_PKT_BUF_TOO_SMALL;\r
255         return;\r
256     }\r
257 \r
258 \r
259     /* Initialize the rmPkt.  Do not assume the transport code will do it */                            \r
260     memset((void *)rmPkt, 0, sizeof(Rm_Packet));\r
261 \r
262     /* Assign the rmData field to be the rmProtPkt */\r
263     rmProtPkt = &(rmPkt->rmData[0]);\r
264 \r
265     /* Populate the response packet with the transaction response details for\r
266      * the lower leverl RM instance */\r
267     rmProtPkt->rmPktId = transactionEntry->transactionId;\r
268     strcpy((void *)rmProtPkt->rmInstName,(void *)rmInst->name);\r
269     rmProtPkt->rmCmd = (uint32_t) transaction->command;\r
270     rmProtPkt->rmDetails = transaction->details;\r
271     if (transaction->command == Rm_command_POLICY_RESPONSE)\r
272     {\r
273         /* Copy the policy data if the transaction is policy based */\r
274         memcpy ((void *)rmProtPkt->u.rmPolicyData, (void *)transaction->u.policyData,\r
275                 RM_MAX_POLICY_SIZE_BYTES);\r
276     }\r
277     else\r
278     {\r
279         /* Otherwise copy the resource data */\r
280         memcpy ((void *)&(rmProtPkt->u.resInfo), (void *) &(transaction->u.resourceInfo),\r
281                 sizeof(Rm_ResourceInfo));\r
282     }\r
283 \r
284     /* Send the RM packet to the application transport */\r
285     if (rmInst->transport.rmSend)\r
286     {\r
287         if (!(rmInst->transport.rmSend(transactionEntry->transportHandle, rmPkt))\r
288         {\r
289             /* Transport returned an error */\r
290 \r
291             /* SHOULD TRANSPORT ERROR SOMEHOW BE OR'D WITH THE SERVICE ERROR ??? */\r
292             receipt->transactionResult = RM_SERVICE_ERROR_TRANPSPORT_SEND_ERROR;\r
293             return;\r
294         }\r
295     }\r
296     else\r
297     {\r
298         /* The transport packet send API is not plugged */\r
299         receipt->transactionResult = RM_SERVICE_ERROR_TRANSPORT_PKT_SEND_API_NULL;\r
300         return;\r
301     }    \r
302     \r
303     receipt->transactionResult = RM_RESPONSE_PACKET_SENT;\r
304 \r
305     /* Delete the transaction entry from the transaction queue */\r
306     Rm_transactionQueueDelete(rmInst,transaction->pktId);\r
307 \r
308     return;\r
309 }\r
310 \r
311 /* Function used to forward RM transactions to higher level agents */\r
312 void Rm_transactionForwarder (Rm_Inst *rmInst, Rm_Transaction *transaction,\r
313                               Rm_TransactionReceipt *receipt)\r
314 {\r
315     Rm_TransRouteMapNode *routeMap = (Rm_TransRouteMapNode *) rmInst->routeMap;\r
316     uint32_t transactionId;\r
317     Rm_Packet *rmPkt = NULL;\r
318     Rm_ProtocolPkt *rmProtPkt = NULL;\r
319 \r
320     /* Make sure at least one transport has been registered */\r
321     if (routeMap == NULL)\r
322     {\r
323         receipt->transactionResult = RM_SERVICE_ERROR_NO_TRANSPORT_REGISTERED;\r
324         return;\r
325     }\r
326     \r
327     /* Make sure the RM instance has a transport registered with a higher level agent */\r
328     if (!rmInst->registeredWithDelegateOrServer)\r
329     {\r
330         receipt->transactionResult = RM_SERVICE_ERROR_NOT_REGISTERED_WITH_DEL_OR_SERVER;\r
331         return;\r
332     }\r
333 \r
334     /* Parse the RM instance's routing map to find the higher level agent for forwarding */\r
335     while ((routeMap->remoteInstType != Rm_instType_CLIENT_DELEGATE) || \r
336            (routeMap->remoteInstType != Rm_instType_SERVER))\r
337     {\r
338         /* Traverse the list until arriving at the upper level agent node */\r
339         routeMap = routeMap->nextNode;\r
340     }\r
341 \r
342     /* Create a RM packet using the service information */\r
343     if (rmInst->transport.rmAllocPkt)\r
344     {\r
345         rmPkt = rmInst->transport.rmAllocPkt(routeMap->transHandle, sizeof(Rm_Packet));\r
346     }\r
347     else\r
348     {\r
349         /* The transport packet alloc API is not plugged */\r
350         receipt->transactionResult = RM_SERVICE_ERROR_TRANSPORT_PKT_ALLOC_API_NULL;\r
351         return;\r
352     }\r
353 \r
354     /* Make sure a buffer for the packet was allocated  */\r
355     if (rmPkt == NULL)\r
356     {\r
357         receipt->transactionResult = RM_SERVICE_ERROR_TRANSPORT_NULL_PKT_BUF;\r
358         return;\r
359     }\r
360 \r
361     /* Make sure allocated buffer is large enough to fit the protocol packet plus the \r
362      * rmPktLen field */\r
363     if (rmPkt->rmPktLen < (sizeof(Rm_ProtocolPkt) + sizeof(uint32_t))\r
364     {   \r
365         receipt->transactionResult = RM_SERVICE_ERROR_TRANSPORT_PKT_BUF_TOO_SMALL;\r
366         return;\r
367     }\r
368 \r
369     /* Create an ID for this transaction.  The ID will be used for two purposes:\r
370      * 1) Matching the response from the higher level RM agent to the request\r
371      * 2) Provided to the service requesting component so that it can match the\r
372      *    service request with the response it receives via its callback function */\r
373     transactionId = ...; /* NEED SCHEME FOR CREATING A MUTUALLY EXCLUSIVE PKT ID.  CAN'T\r
374                           * CONFLICT WITH PCKT IDS CREATED ON OTHER RM INSTANCES */\r
375     /* Initialize the rmPkt.  Do not assume the transport code will do it */                            \r
376     memset((void *)rmPkt, 0, sizeof(Rm_Packet));\r
377                           \r
378     /* Assign the rmData field to be the rmProtPkt */\r
379     rmProtPkt = &(rmPkt->rmData[0]);\r
380     /* Populate the RM packet using the service information */\r
381     rmProtPkt->rmPktId = transactionId;\r
382     strcpy((void *)rmProtPkt->rmInstName,(void *)rmInst->name);\r
383     rmProtPkt->rmCmd = (uint32_t) transaction->command;\r
384     if ((transaction->command == Rm_command_POLICY_REQUEST) ||\r
385         (transaction->command == Rm_command_POLICY_RESPONSE)\r
386     {\r
387         /* Copy the policy data if the transaction is policy based */\r
388         memcpy ((void *)rmProtPkt->u.rmPolicyData, (void *)transaction->u.policyData,\r
389                 RM_MAX_POLICY_SIZE_BYTES);\r
390     }\r
391     else\r
392     {\r
393         /* Otherwise copy the resource data */\r
394         memcpy ((void *)&(rmProtPkt->u.resInfo), (void *) &(transaction->u.resourceInfo),\r
395                 sizeof(Rm_ResourceInfo));\r
396     }\r
397 \r
398     /* Create an entry in the transaction queue */\r
399     Rm_transactionQueueAdd(rmInst, transactionId, transaction->callback);\r
400 \r
401     /* Send the RM packet to the application transport */\r
402     if (rmInst->transport.rmSend)\r
403     {\r
404         if (!(rmInst->transport.rmSend(routeMap->transHandle, rmPkt))\r
405         {\r
406             /* Transport returned an error */\r
407 \r
408             /* SHOULD TRANSPORT ERROR SOMEHOW BE OR'D WITH THE SERVICE ERROR ??? */\r
409             receipt->transactionResult = RM_SERVICE_ERROR_TRANPSPORT_SEND_ERROR;\r
410             return;\r
411         }\r
412     }\r
413     else\r
414     {\r
415         /* The transport packet send API is not plugged */\r
416         receipt->transactionResult = RM_SERVICE_ERROR_TRANSPORT_PKT_SEND_API_NULL;\r
417         return;\r
418     }    \r
419 \r
420     /* Inform requesting component that the service is being forwarded to a higher lever\r
421      * RM agent for processing.  The result of the service will be provided to the \r
422      * component via the specified callback function */\r
423     receipt->transactionResult = RM_SERVICE_PROCESSING;\r
424     receipt->transactionId = transactionId;\r
425     return;\r
426 }\r
427 \r
428 void Rm_transactionProcessor (Rm_Inst *rmInst, Rm_Transaction *transaction, \r
429                                  Rm_TransactionReceipt *receipt)\r
430 {\r
431     if (rmInst->instType == Rm_instType_CLIENT)\r
432     {\r
433         if (transaction->command == Rm_command_RESOURCE_RESPONSE)\r
434         {\r
435             /* Responses received by the Client must be issued back to the requesting\r
436              * component */\r
437             Rm_serviceResponder (rmInst, transaction, receipt);\r
438         }\r
439         else\r
440         {\r
441             /* All service requests on Clients are forwarded to the higher level RM agent\r
442              * either a Client Delegate or Server, based on the RM system architecture */\r
443             Rm_transactionForwarder(rmInst, transaction, receipt);\r
444         }\r
445     }\r
446     else\r
447     {\r
448         /* Execute a command processor based on the command type */\r
449         switch (transaction->transCommand)\r
450         {\r
451             case Rm_command_ALLOCATE:\r
452             case Rm_command_BLOCK_ALLOCATE:\r
453             case Rm_command_ALLOCATE_NAMED:\r
454                 Rm_allocate(rmInst, transaction, receipt);\r
455                 break;\r
456             case Rm_command_FREE:\r
457             case Rm_command_BLOCK_FREE:\r
458             case Rm_command_FREE_NAMED:\r
459                 Rm_free(rmInst, transaction, receipt);\r
460                 break;\r
461             case Rm_command_MAP_NAME:\r
462                 Rm_nsAddObject(rmInst, transaction, receipt);\r
463                 break;\r
464             case Rm_command_UNMAP_NAME:\r
465                 Rm_nsDeleteObject(rmInst, transaction, receipt);\r
466                 break;\r
467             case Rm_command_RESOURCE_STATUS:\r
468                 Rm_getResourceStatus(rmInst, transaction, receipt);\r
469                 break;\r
470             case Rm_command_RESOURCE_RESPONSE:\r
471                 \r
472                 break;\r
473             case Rm_command_POLICY_REQUEST:\r
474                 break;\r
475             case Rm_command_POLICY_RESPONSE:\r
476                 break;\r
477         }\r
478 \r
479     }\r
480 \r
481 }\r
482 \r
483 void Rm_serviceHandler (void *rmHandle, Rm_ServiceReqInfo *requestInfo,\r
484                         Rm_ServiceRespInfo *responseInfo)\r
485 {\r
486     Rm_Inst *rmInst = (Rm_Inst *) rmHandle;\r
487     Rm_Transaction transaction;\r
488     Rm_TransactionReceipt receipt;\r
489     void *key;\r
490 \r
491     /* Prevent another component using the same instance from wiping out the current\r
492      * service request */\r
493     key = Rm_osalLocalCsEnter();\r
494 \r
495     /* Make sure serviceType is valid and that a callback function has been provided */\r
496     if ((requestInfo->serviceType < Rm_service_FIRST) || \r
497         (requestInfo->serviceType > Rm_service_LAST))\r
498     {\r
499         responseInfo->serviceResult = RM_SERVICE_ERROR_INVALID_SERVICE_TYPE;\r
500         Rm_osalLocalCsExit(key);\r
501         return;\r
502     }\r
503     else if (requestInfo->serviceCallback == NULL)\r
504     {\r
505         /* RM Client's and Client Delegate's use blocking transports to consult with a \r
506          * high-level RM agent prior to providing a response to the component.  It is \r
507          * assumed the component's cannot block.  Therefore, all responses must go\r
508          * through the callback function provided by the component.  Return an error \r
509          * if the component does not provide a callback function. */\r
510         responseInfo->serviceResult = RM_SERVICE_ERROR_CALLBACK_NOT_PROVIDED;\r
511         Rm_osalLocalCsExit(key);\r
512         return;\r
513     }\r
514 \r
515     /* Clear the transaction and receipt prior to using them */\r
516     memset((void *) &transaction, 0, sizeof(Rm_Transaction));\r
517     memset((void *) &transactionReceipt, 0, sizeof(Rm_TransactionReceipt));\r
518 \r
519     /* Transfer request information into the internal transaction format */\r
520     transaction.command = (Rm_Command) requestInfo->serviceType;\r
521     transaction.callback = requestInfo->serviceCallback;\r
522     /* Policy modifications will never originate from components */\r
523     strcpy ((void *) &(transaction.u.resourceInfo.resName)[0], (void *)requestInfo->resName);\r
524     transaction.u.resourceInfo.resBase = requestInfo->resourceBase;\r
525     transaction.u.resourceInfo.resNum = requestInfo->resourceNum;\r
526     transaction.u.resourceInfo.resAlign = requestInfo->resourceAlign;\r
527     strcpy ((void *) &(transaction.u.resourceInfo.resNsName)[0], (void *)requestInfo->resNsName);\r
528 \r
529     /* Pass the new transaction to the transaction processor */\r
530     Rm_transactionProcessor (rmInst, &transaction, &receipt);\r
531 \r
532     /* Copy transaction receipt information into the response info fields for the \r
533      * component based on the result of the transaction.  Denied service requests\r
534      * will have only a valid serviceResult field */\r
535     responseInfo->serviceResult = receipt->transactionResult;\r
536     if (responseInfo->serviceResult == RM_SERVICE_APPROVED)\r
537     {\r
538         /* Service was approved.  The resource data should be passed back\r
539          * to the component */\r
540         responseInfo->resBase = receipt.resBase;\r
541         responseInfo->resNum = receipt.resNum;\r
542     }\r
543     else if (responseInfo->serviceResult == RM_SERVICE_PROCESSING)\r
544     {\r
545         /* The service is still being processed.  Provide the transaction ID\r
546          * back to the component so that it can sort service responses received\r
547          * via the provided callback function */\r
548         responseInfo->requestId = receipt.transactionId;\r
549     }\r
550 \r
551     Rm_osalLocalCsExit(key);\r
552     \r
553     return;\r
554 }\r
555 \r
556 /* This function is executed when a RM instance receives a response to one of it's requests\r
557  * and the information in the request must be provided to the original requesting component */\r
558 void Rm_serviceResponder (Rm_Inst *rmInst, Rm_Transaction *transaction, \r
559                           Rm_TransactionReceipt *receipt)\r
560 {\r
561     Rm_TransactionQueueEntry *transactionEntry;\r
562     Rm_ServiceRespInfo responseInfo;\r
563 \r
564     /* Find the transaction request that matches the received response */\r
565     transactionEntry = Rm_transactionQueueFind(rmInst,transaction->pktId);\r
566 \r
567     if (transactionEntry == NULL)\r
568     {\r
569         /* No transaction request matching the transaction ID was forwarded from\r
570          * this RM instace */\r
571         receipt->transactionResult = RM_SERVICE_ERROR_TRANSACTION_DOES_NOT_EXST_FOR_THIS_RM_INSTANCE;\r
572         return;\r
573     }\r
574 \r
575     /* Populate the service response with the transaction response details for\r
576      * the component */\r
577     responseInfo.requestId = transaction->pktId;\r
578     responseInfo.serviceResult = transaction->details;\r
579     responseInfo.resBase = transaction->u.resourceInfo.resBase;\r
580     responseInfo.resNum = transaction->u.resourceInfo.resNum;\r
581 \r
582     /* Issue the callback to the requesting component with the response information */\r
583     transactionEntry->transactionCallback(&responseInfo);\r
584 \r
585     /* Delete the transaction entry from the transaction queue */\r
586     Rm_transactionQueueDelete(rmInst,transaction->pktId);\r
587 \r
588     return;\r
589 }\r
590 \r
591 /**********************************************************************\r
592  *********************** Application visible APIs ***************************\r
593  **********************************************************************/\r
594 \r
595 Rm_Handle Rm_init(Rm_InitCfg *initCfg)\r
596 {\r
597     Rm_Inst *rmInst;\r
598 \r
599     /* Instance creation checks.  Add one to strlen calculation for null character */\r
600     if ((strlen(initCfg->instName) + 1) > RM_INSTANCE_NAME_MAX_CHARS)\r
601     {\r
602         /* Failure: Instance name is too big */\r
603         return (NULL);\r
604     }\r
605     \r
606     /* Get memory for RM instance from local memory */\r
607     rmInst = Rm_osalMalloc (sizeof(Rm_Inst), false);\r
608     /* Populate instance based on input parameters */\r
609     strcpy (&rmInst->name[0], initCfg->instName);\r
610     rmInst->instType = initCfg->instType;\r
611     rmInst->instState = RM_state_IDLE;\r
612     rmInst->registeredWithDelegateOrServer = false;\r
613     rmInst->serviceCallback = NULL;\r
614 \r
615     /* Populate the instance transport callouts */\r
616     rmInst->transport.rmAllocPkt = initCfg->rmAllocPktFuncPtr;\r
617     rmInst->transport.rmFreePkt = initCfg->rmFreePktFuncPtr;\r
618     rmInst->transport.rmSend = initCfg->rmSendFuncPtr;\r
619     rmInst->transport.rmReceive = initCfg->rmReceiveFuncPtr;\r
620     rmInst->transport.rmNumPktsReceived = initCfg->rmNumPktsReceivedFuncPtr;\r
621 \r
622     /* Initialize the transport routing map linked list pointer to NULL.  The linked list\r
623      * nodes will be created when the application registers transports */\r
624     rmInst->routeMap = NULL;\r
625 \r
626     /* Initialize the transaction queue linked list pointer to NULL.  The linked list\r
627      * nodes will be created when the transactions are forwarded to higher level RM\r
628      * agents. */\r
629     rmInst->transactionQueue= NULL;\r
630 \r
631     /* RM Server specific actions */\r
632     if (rmInst->instType == Rm_instType_SERVER)\r
633     {\r
634        /* parse DTB, etc */\r
635     }\r
636 \r
637     /* Instance startup policies are only used for Servers and Client Delegates */\r
638     if (rmInst->instType != Rm_instType_CLIENT)\r
639     {\r
640         rmInst->instPolicy = initCfg->startupPolicy;\r
641 \r
642         /* Store policy via policy APIs ... */\r
643     }\r
644 \r
645     /* Return the RM Handle */\r
646     return ((Rm_Handle) rmInst);\r
647 }\r
648 \r
649 Rm_Result Rm_preMainAllocResource(Rm_PreMainAllocInfo *preMainAllocInfo)\r
650 {\r
651 \r
652 }\r
653 \r
654 Rm_ServiceHandle Rm_getServiceHandle(Rm_Handle rmHandle)\r
655 {\r
656     Rm_Inst *rmInst = (Rm_Inst *) rmHandle;\r
657     Rm_ServicesPort *newServicePort;\r
658     \r
659     /* Create a new service handle for the specified RM instance */\r
660     \r
661     /* Get memory for a new service port from local memory */\r
662     newServicePort = Rm_osalMalloc (sizeof(Rm_ServicesPort), false);\r
663 \r
664     newServicePort->rmHandle = rmHandle;\r
665     newServicePort->rmService = rmServiceHandler;\r
666 \r
667     return ((Rm_ServiceHandle) newServicePort);\r
668 }\r
669 \r
670 Rm_TransportHandle Rm_registerTransport (Rm_Handle rmHandle, Rm_TransCfg *transCfg)\r
671 {\r
672     Rm_Inst *rmInst = (Rm_Inst *) rmHandle;\r
673     Rm_TransRouteMapNode *existingRouteMap = (Rm_TransRouteMapNode *) rmInst->routeMap;\r
674     Rm_TransRouteMapNode *newRouteMapNode;\r
675 \r
676     /* RM Servers cannot connect to other Servers */\r
677     if ((rmInst->instType == Rm_instType_SERVER) &&\r
678          (transCfg->rmRemoteInstType == Rm_instType_SERVER))\r
679     {\r
680         return (NULL); /* Error -return null */\r
681     }\r
682 \r
683     /* Verify Clients and Client Delegates are not registering with more than one \r
684      * Client Delegate or Server. Assuming a Client Delegate can register with another \r
685      * Client Delegate that can "act" as a server */\r
686     if (((rmInst->instType == Rm_instType_CLIENT) || \r
687          (rmInst->instType == Rm_instType_CLIENT_DELEGATE)) &&\r
688         ((transCfg->rmRemoteInstType == Rm_instType_CLIENT_DELEGATE) ||\r
689          (transCfg->rmRemoteInstType == Rm_instType_SERVER)) &&\r
690         rmInst->registeredWithDelegateOrServer)\r
691     {\r
692         return (NULL); /* Error -return null */\r
693     }         \r
694 \r
695     /* Error checks passed - Create a new transport handle for the specified RM instance */\r
696     \r
697     /* Get memory for a new routing map node from local memory */\r
698     newRouteMapNode = Rm_osalMalloc (sizeof(Rm_TransRouteMapNode), false);\r
699 \r
700     /* Populate the new node.  The address of the node itself is stored since this address is returned\r
701      *  to the application as the Rm_TransportHandle */\r
702     newRouteMapNode->transHandle = newRouteMapNode;\r
703     newRouteMapNode->remoteInstType = transCfg->rmRemoteInstType;\r
704     newRouteMapNode->nextNode = NULL;  /* New node will always be NULL */\r
705 \r
706     /* Check if there are any entries in the routing map */\r
707     if (existingRouteMap)\r
708     {\r
709         /* At least one entry in the routing map.  Add the new routing map node to the end of the\r
710          * routing map node list */\r
711         while (existingRouteMap->nextNode != NULL)\r
712         {\r
713             /* Traverse the list until arriving at the last node */\r
714             existingRouteMap = existingRouteMap->nextNode;\r
715         }\r
716 \r
717         /* Add the new node to the end of the list */\r
718         existingRouteMap->nextNode = newRouteMapNode;\r
719     }\r
720     else\r
721     {\r
722         /* A routing map does not currently exist.  The new node is the first entry */\r
723         rmInst->routeMap = newRouteMapNode;\r
724     }\r
725 \r
726     /* Specify RM instance has registered with a higher level agent */\r
727     if ((newRouteMapNode->remoteInstType == Rm_instType_CLIENT_DELEGATE) ||\r
728         (newRouteMapNode->remoteInstType == Rm_instType_SERVER))\r
729     {\r
730         rmInst->registeredWithDelegateOrServer = true;\r
731     }\r
732 \r
733     return ((Rm_TransportHandle) newRouteMapNode);\r
734 }\r
735 \r
736 Rm_Result Rm_unregisterTransport (Rm_Handle rmHandle, Rm_TransportHandle transHandle)\r
737 {\r
738     Rm_Inst *rmInst = (Rm_Inst *) rmHandle;\r
739     Rm_TransRouteMapNode *routeMapNode = (Rm_TransRouteMapNode *) rmInst->routeMap;\r
740     Rm_TransRouteMapNode *prevNode = NULL;\r
741 \r
742     /* Make sure a routing map exists for the RM instance */\r
743     if (routeMapNode == NULL)\r
744     {\r
745         return (-1); /* TEMP ERROR RETURN */\r
746     }\r
747 \r
748     /* Find the transport handle within the specified RM instance's routing map. */\r
749     while (1)\r
750     {\r
751         if (routeMapNode->transHandle == transHandle)\r
752         {\r
753             /* Match: break out of loop and delete the node */\r
754             break;             \r
755         }\r
756         else if (routeMapNode->nextNode == NULL)\r
757         {\r
758             return (-1); /* TEMP ERROR: transhandle does not exist for RM instance */\r
759         }\r
760 \r
761         prevNode = routeMapNode;\r
762         routeMapNode = routeMapNode->nextNode;\r
763     }\r
764     \r
765     /* Delete the routing map node */\r
766     if ((prevNode == NULL) && routeMapNode->nextNode)\r
767     {\r
768         /* Node to be deleted exists at start of route map.  Map second node to be start of\r
769          * node list as long as there are more than one routing map nodes */\r
770         rmInst->routeMap = routeMapNode->nextNode;\r
771     }\r
772     else\r
773     {\r
774         /* Node to be deleted is in the middle or at end of the list.  Adjust adjacent\r
775          * nodes pointers.  This covers the case where the node to be removed is at the\r
776          * end of the list. */\r
777         prevNode->nextNode = routeMapNode->nextNode;\r
778     }\r
779 \r
780     /* Remove specification in RM instance that it has been connected to an upper level agent\r
781      * if the node to be deleted has a remote instance type of Client Delegate or Server */\r
782     if ((routeMapNode->remoteInstType == Rm_instType_CLIENT_DELEGATE) ||\r
783         (routeMapNode->remoteInstType == Rm_instType_SERVER))\r
784     {\r
785         rmInst->registeredWithDelegateOrServer = false;\r
786     }\r
787 \r
788     /* Delete the node, free the memory associated with the node. */\r
789     Rm_osalFree((void *) routeMapNode, sizeof(Rm_TransRouteMapNode), false);\r
790 \r
791     return (RM_OK);\r
792 }\r
793 \r
794 \r
795 Rm_TransVerifyResult Rm_verifyTransport (Rm_Handle rmHandle, uint32_t timeout, \r
796                                          Rm_TransFailData *failData)\r
797 {\r
798 \r
799 }\r
800 \r
801 /* Resource requests that come directly from application go through this API */\r
802 void Rm_requestService (void *rmHandle, Rm_ServiceReqInfo *requestInfo,\r
803                         Rm_ServiceRespInfo *responseInfo)\r
804 {\r
805     Rm_serviceHandler(rmHandle, requestInfo, responseInfo);\r
806 }\r
807 \r
808 /* Used by the application to pass RM packets received from a transport to RM.\r
809  * CODE THE FUNCTION SUCH THAT IT CAN BE CALLED DIRECTLY BY APP OR BE PLUGGED\r
810  * AS PART OF AN ISR HANDLER FOR THE TRANSACTION RECEIVE */\r
811 Rm_Result Rm_receiveRmPkt(Rm_Handle rmHandle, Rm_TransportHandle transHandle, Rm_Packet *pkt)\r
812 {\r\r\r
813     Rm_Inst *rmInst = (Rm_Inst *)rmHandle;\r
814     Rm_ProtocolPkt rmProtPkt = &(pkt->rmData)[0];\r
815     Rm_Transaction transaction;\r
816     Rm_TransactionReceipt receipt;\r
817     void *key;\r
818 \r
819     /* Lock access to the RM instance's transaction queue */\r
820     key = Rm_osalLocalCsEnter();    \r
821 \r
822     /* Initialize the transaction and receipt */\r
823     memset((void *)&transaction, 0, sizeof(Rm_Transaction));\r
824     memset((void *)&receipt, 0, sizeof(Rm_TransactionReceipt));\r
825 \r
826     /* Create a new transaction based on the packet details */\r
827     transaction.pktId = rmProtPkt->rmPktId;\r
828     transaction.command = (Rm_Command) rmProtPkt->rmCmd;\r
829     transaction.details = rmProtPkt->rmDetails;\r
830     transaction.receivedTransport = transHandle;\r
831     if ((transaction->command == Rm_command_POLICY_REQUEST) ||\r
832         (transaction->command == Rm_command_POLICY_RESPONSE)\r
833     {\r
834         /* Copy the policy data if the transaction is policy based */\r
835         memcpy ((void *)transInfo->u.policyData, (void *)rmProtPkt->u.rmPolicyData,\r
836                 RM_MAX_POLICY_SIZE_BYTES);\r
837     }\r
838     else\r
839     {\r
840         /* Otherwise copy the resource data */\r
841         memcpy((void *)transaction.u.resourceInfo,(void *)rmProtPkt->u.resInfo, \r
842                sizeof(Rm_ResourceInfo));\r
843     }\r
844 \r
845     /* Process the transaction */\r
846     Rm_transactionProcessor(rmInst,&transaction,&receipt)\r
847 \r
848     /* IS RECEIPT DATA NEEDED FOR ANYTHING HERE??*/\r
849 \r
850     Rm_osalLocalCsExit(key);\r
851     return (0);    \r
852 }\r
853 \r
854 /* Application can call this API so that RM handles reception of packets based on\r
855  * the RM handle and transport handle provided */\r
856 Rm_Result Rm_getRmPkt(Rm_Handle rmHandle, Rm_TransportHandle transHandle)\r
857 {\r
858     Rm_Inst *rmInst = (Rm_Inst *)rmHandle;\r
859     Rm_TransRouteMapNode *transNode = rmInst->routeMap;\r
860     Rm_Packet *rmPkt = NULL;\r
861     Rm_Result retVal = 0;\r
862     void *key;\r
863 \r
864     /* Lock access to the RM instance's transaction queue */\r
865     key = Rm_osalLocalCsEnter();    \r
866 \r
867     /* Verify the transport handle is registered with the RM handle */\r
868     while (transNode != NULL)\r
869     {\r
870         if (transNode->transHandle == transHandle)\r
871         {\r
872            /* Break out of loop if an entry in the route map has been found */\r
873            break;\r
874         }\r
875         transNode = transNode->nextNode;\r
876     }\r
877 \r
878     if (transNode == NULL)\r
879     {\r
880         Rm_osalLocalCsExit(key);\r
881         return (-1) /* ERROR: THE TRANSPORT HANDLE IS NOT REGISTERED WITH THE RM HANDLE */\r
882     }\r
883 \r
884     /* Check to see if any RM packets are available.  Process any available packets. */\r
885     while (rmInst->transport.rmNumPktsReceived(transHandle))\r
886     {\r
887         rmInst->transport.rmReceive(transHandle, rmPkt);\r
888 \r
889         if (rmPkt == NULL)\r
890         {\r
891             retVal = -1;  /* ERROR - PACKET RECEIVED FROM TRANSPORT IS NULL */\r
892         }\r
893 \r
894         /* Pass the packet to RM */\r
895         retVal = Rm_receiveRmPkt(rmHandle, transHandle, rmPkt);\r
896         /* Delete the packet */\r
897         rmInst->transport.rmFreePkt(transHandle, rmPkt);\r
898 \r
899         if (retVal)\r
900         {\r
901             /* If retVal is not 0 (Okay) there was an error so break out of loop and return */\r
902             break;\r
903         }\r
904     }\r
905     \r
906     Rm_osalLocalCsExit(key);\r
907     return (retVal); \r
908 }\r
909 \r
910 uint32_t Rm_getVersion (void)\r
911 {\r
912     return RM_VERSION_ID;\r
913 }\r
914 \r
915 \r
916 const char* Rm_getVersionStr (void)\r
917 {\r
918     return rmVersionStr;\r
919 }\r
920 \r
921 /**\r
922 @}\r
923 */\r