/** * @file rmservices.c * * @brief * This is the Resource Manager services source. * * \par * ============================================================================ * @n (C) Copyright 2012, Texas Instruments, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * Neither the name of Texas Instruments Incorporated nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * \par */ /* RM Types */ #include /* RM external API includes */ #include /* RM internal API includes */ #include /* RM OSAL layer */ #include /********************************************************************** ********************** Internal Functions **************************** **********************************************************************/ void Rm_serviceHandler (void *rmHandle, Rm_ServiceReqInfo *serviceRequest, Rm_ServiceRespInfo *serviceResponse) { Rm_Inst *rmInst = (Rm_Inst *)rmHandle; uint32_t transactionId = 0; Rm_Transaction *transaction; Rm_TransactionReceipt receipt; void *key; /* Prevent another component using the same instance from wiping out the current * service request */ key = Rm_osalLocalCsEnter(); /* Make sure serviceType is valid and that a callback function has been provided */ if ((serviceRequest->serviceType < Rm_service_FIRST) || (serviceRequest->serviceType > Rm_service_LAST)) { serviceResponse->serviceResult = RM_SERVICE_ERROR_INVALID_SERVICE_TYPE; Rm_osalLocalCsExit(key); return; } else if (serviceRequest->serviceCallback == NULL) { /* The RM Client and Client Delegate use blocking transports to consult with a * high-level RM agent prior to providing a response to the component. It is * assumed the component's cannot block. Therefore, all responses must go * through the callback function provided by the component. Return an error * if the component does not provide a callback function. */ serviceResponse->serviceResult = RM_SERVICE_ERROR_CALLBACK_NOT_PROVIDED; Rm_osalLocalCsExit(key); return; } /* Create an ID for this transaction. The ID will be used for two purposes: * 1) Matching responses from higher level RM agents to requests * 2) Provided to the entity that requested the service so that it can match its * request with the response it receives via its callback function it provided */ transactionId = ...; /* NEED SCHEME FOR CREATING A MUTUALLY EXCLUSIVE PKT ID. CAN'T * CONFLICT WITH PCKT IDS CREATED ON OTHER RM INSTANCES */ /* Create a new transaction */ transaction = Rm_transactionQueueAdd(rmInst, transactionId); if (transaction == NULL) { /* Failed to create a new transaction */ serviceResponse->serviceResult = RM_SERVICE_ERROR_TRANSACTION_FAILED_TO_ALLOCATE; } else { /* Clear the receipt */ memset((void *) &receipt, 0, sizeof(Rm_TransactionReceipt)); /* Transfer request information into the transaction */ transaction->type = serviceRequest->serviceType; strcpy((transaction->sourceInstName, rmInst->name); transaction->callback = serviceRequest->serviceCallback; transaction->state = Rm_transactionState_PROCESSING; transaction->details = RM_SERVICE_PROCESSING; strcpy(&(transaction->resourceInfo.name)[0], serviceRequest->resourceName); transaction->resourceInfo.base = serviceRequest->resourceBase; transaction->resourceInfo.range = serviceRequest->resourceRange; transaction->resourceInfo.alignment = serviceRequest->resourceAlignment; strcpy(&(transaction->resourceInfo.nsName)[0], serviceRequest->resourceNsName); /* Pass the new transaction to the transaction processor */ Rm_transactionProcessor (rmInst, transaction, &receipt); /* Copy transaction receipt information into the response info fields for the * component based on the result of the transaction. Denied service requests * will have only a valid serviceResult field */ serviceResponse->serviceResult = receipt->serviceResult; /* Service was approved and service was an allocate request the resource * data is passed back to the component */ if ((serviceResponse->serviceResult == RM_SERVICE_APPROVED) && ((transaction->type == Rm_service_RESOURCE_ALLOCATE) || (transaction->type == Rm_service_RESOURCE_BLOCK_ALLOCATE) || (transaction->type == Rm_service_RESOURCE_ALLOCATE_BY_NAME))) { serviceResponse->resourceBase = receipt.resourceBase; serviceResponse->resourceRange = receipt.resourceRange; /* Delete the transaction since a response was received immediately */ Rm_transactionQueueDelete(rmInst, transaction->id); } else if (serviceResponse->serviceResult == RM_SERVICE_PROCESSING) { /* The service is still being processed. Provide the transaction ID * back to the component so that it can sort service responses received * via the provided callback function */ serviceResponse->requestId = receipt.serviceId; } else if (serviceResponse->serviceResult <= RM_SERVICE_ERROR_BASE) { /* Delete the transaction since there was an error processing it. */ Rm_transactionQueueDelete(rmInst, transaction->id); } } Rm_osalLocalCsExit(key); return; } /* This function is executed when a RM instance receives a response to one of its requests * and the information in the request must be provided to the original requesting component */ void Rm_serviceResponder (Rm_Inst *rmInst, Rm_Transaction *responseTransaction, Rm_Transaction *requestTransaction, Rm_TransactionReceipt *receipt) { Rm_ServiceRespInfo serviceResponse; /* Populate the service response with the transaction response details * for the component */ serviceResponse.serviceResult = responseTransaction->details; /* Pass back the ID that was provided to the component when it requested * the service */ serviceResponse.requestId = responseTransaction->id; /* Service was approved and service was an allocate request. The resource * data is passed back to the component */ if ((serviceResponse->serviceResult == RM_SERVICE_APPROVED) && ((responseTransaction.type == Rm_service_RESOURCE_ALLOCATE) || (responseTransaction.type == Rm_service_RESOURCE_BLOCK_ALLOCATE) || (responseTransaction.type == Rm_service_RESOURCE_ALLOCATE_BY_NAME))) { serviceResponse->resourceBase = receipt.resourceBase; serviceResponse->resourceRange = receipt.resourceRange; } /* Issue the callback to the requesting component with the response information */ if (requestTransaction != NULL) { /* The requestTransaction will be NULL if the request transaction is handled * by the same RM instance it was created on. Typically this applies to RM * Client Delegate and RM Server instances. In these cases the response * transaction will be a copy of the request transaction, meaning it will contain * the proper callback information */ requestTransaction->callback(&serviceResponse); } else { responseTransaction->callback(&serviceResponse); } /* Delete both transactions from the transaction queue */ Rm_transactionQueueDelete(rmInst,responseTransaction->id); if (requestTransaction != NULL) { Rm_transactionQueueDelete(rmInst,requestTransaction->id); } /* Response to component completed */ receipt.serviceResult = RM_SERVICE_ACTION_OKAY; return; } /********************************************************************** ********************** Application visible APIs ********************** **********************************************************************/ void Rm_preMainAllocService(Rm_PreMainAllocInfo *preMainAllocInfo, Rm_ServiceRespInfo *serviceResponse) { } Rm_ServicesPort *Rm_getServicePort(Rm_Handle rmHandle) { Rm_Inst *rmInst = (Rm_Inst *) rmHandle; Rm_ServicesPort *newServicePort = NULL; /* Create a new service handle for the specified RM instance */ /* Get memory for a new service port from local memory */ newServicePort = Rm_osalMalloc (sizeof(Rm_ServicesPort), false); /* Return NULL immediately if malloc returned NULL */ if (newServicePort == NULL) { return (newServicePort); } newServicePort->rmHandle = rmHandle; newServicePort->rmService = Rm_serviceHandler; return (newServicePort); } /** @} */