/****************************************************************************** * * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA * * ******************************************************************************/ #define _MAILBOX_C_ #include "mailbox.h" /****************************************************************************** * Function Prototype Declaration ******************************************************************************/ static PRTL_MAILBOX RtlMBoxIdToHdl(IN u8 MBoxId); PRTL_MAILBOX RtlMailboxCreate(IN u8 MboxID, IN u32 MboxSize, IN _Sema *pWakeSema); VOID RtlMailboxDel(IN PRTL_MAILBOX MboxHdl); u8 RtlMailboxSendToBack( IN u8 MboxID, IN MSG_BLK *pMsg, IN u32 MSToWait, IN u8 IsFromISR ); u8 RtlMailboxSendToFront( IN u8 MboxID, IN MSG_BLK *pMsg, IN u32 MSToWait, IN u8 IsFromISR ); u8 RtlMailboxReceive( IN u8 MboxID, OUT MSG_BLK *pMsg, IN u32 MSToWait, IN u8 IsFromISR ); u8 RtlMailboxPeek( IN u8 MboxID, OUT MSG_BLK *pMsg, IN u32 MSToWait, IN u8 IsFromISR ); u32 RtlMailboxMsgWaiting( IN u8 MboxID, IN u8 IsFromISR ); /****************************************************************************** * Global Variable Declaration ******************************************************************************/ static RTL_MBOX_ROOT MBox_Entry; /****************************************************************************** * External Function & Variable Declaration ******************************************************************************/ /****************************************************************************** * Function: RtlMBoxIdToHdl * Desc: Map a mailbox ID to the mailbox pointer. * Para: * MBoxId: The Mailbox ID * Return: The pointer of the mailbox. If didn't found match mailbox, * return NULL. * ******************************************************************************/ static PRTL_MAILBOX RtlMBoxIdToHdl( IN u8 MBoxId ) { RTL_MAILBOX *pMbox=NULL; RTL_MAILBOX *pTmpMbox; _LIST *pHead; _LIST *pList; // if the Mailbox root entry initialed ? if not, initial it if (!MBox_Entry.isInitialed) { RtlMutexInit(&MBox_Entry.Mutex); // Init the Mutex for the mailbox add/delete procedure protection RtlInitListhead(&MBox_Entry.mbox_list); // Init the link list head to chain all created mailbox MBox_Entry.isInitialed = 1; MSG_MBOX_INFO("MBox Entry Initial...\n"); } pHead = &MBox_Entry.mbox_list; RtlDownMutex(&MBox_Entry.Mutex); pList = RtlListGetNext(&MBox_Entry.mbox_list); while (pList != pHead) { pTmpMbox = CONTAINER_OF(pList, RTL_MAILBOX, mbox_list); if (MBoxId == pTmpMbox->mbox_id) { pMbox = pTmpMbox; break; } pList = RtlListGetNext(pList); } RtlUpMutex(&MBox_Entry.Mutex); return pMbox; } /****************************************************************************** * Function: RtlMailboxCreate * Desc: To create a mailbox with a given mailbox ID and size * Para: * MboxID: A number to identify this created mailbox. A message block can * be send to a mailbox by a given MboxID. The MboxID must be unique * in the whole system. If this MboxID is conflict with a created * mailbox, the mailbox creation will fail and return NULL. * MboxSize: The size of this mailbox to be created. It means maximum number * of message blocks can be stored in this mailbox. * pWakeSema: The semaphore to wake up the receiving task to receive the new * message. If the receiving task doesn't need a semaphore to wakeup * it, then just let this pointer is NULL. * Return: The created mailbox pointer. If it failed, return NULL. ******************************************************************************/ PRTL_MAILBOX RtlMailboxCreate( IN u8 MboxID, IN u32 MboxSize, IN _Sema *pWakeSema ) { PRTL_MAILBOX pMBox=NULL; // if the Mailbox root entry initialed ? if not, initial it if (!MBox_Entry.isInitialed) { RtlMutexInit(&MBox_Entry.Mutex); // Init the Mutex for the mailbox add/delete procedure protection RtlInitListhead(&MBox_Entry.mbox_list); // Init the link list head to chain all created mailbox MBox_Entry.isInitialed = 1; MSG_MBOX_INFO("MBox Entry Initial...\n"); } // check if this mailbox ID is ocupied ? pMBox = RtlMBoxIdToHdl(MboxID); if (NULL != pMBox) { MSG_MBOX_ERR("RtlMailboxCreate: The Mailbox ID %d is used by someone!!\n", MboxID); return NULL; } pMBox = (RTL_MAILBOX *)RtlZmalloc(sizeof(RTL_MAILBOX)); if (NULL==pMBox) { MSG_MBOX_ERR("RtlMailboxCreate: MAlloc Failed\n"); return NULL; } RtlInitListhead(&pMBox->mbox_list); // Init the link list to be chained into the created mailbox list pMBox->mbox_id = MboxID; pMBox->pWakeSema = pWakeSema; #ifdef PLATFORM_FREERTOS pMBox->mbox_hdl = xQueueCreate(MboxSize, sizeof(MSG_BLK)); if (NULL == pMBox->mbox_hdl) { MSG_MBOX_ERR("RtlMailboxCreate: xQueueCreate Failed\n"); RtlMfree((void *)pMBox, sizeof(RTL_MAILBOX)); return NULL; } #endif #ifdef PLATFORM_ECOS // TODO: Create mailbox #endif // Add this mailbox to the link list of created mailbox RtlDownMutex(&MBox_Entry.Mutex); RtlListInsertTail(&pMBox->mbox_list, &MBox_Entry.mbox_list); RtlUpMutex(&MBox_Entry.Mutex); MSG_MBOX_INFO("A Mailbox Created: Size=%d\n", MboxSize); return pMBox; } /****************************************************************************** * Function: RtlMailboxDel * Desc: To delete a mailbox by a given mailbox handle. * Para: * MboxHdl: The handle of the mailbox to be deleted. * Return: None. ******************************************************************************/ VOID RtlMailboxDel( IN PRTL_MAILBOX MboxHdl ) { if (NULL == MboxHdl) { MSG_MBOX_ERR("RtlMailboxDel: Try to delete a NULL mailbox\n"); return; } // Remove this mailbox from the link list of created mailbox RtlDownMutex(&MBox_Entry.Mutex); RtlListDelete(&MboxHdl->mbox_list); RtlUpMutex(&MBox_Entry.Mutex); // delete the Queue/Mailbox #ifdef PLATFORM_FREERTOS vQueueDelete((xQueueHandle)(MboxHdl->mbox_hdl)); #endif #ifdef PLATFORM_ECOS // TODO: Delete mailbox #endif RtlMfree((void *)MboxHdl, sizeof(RTL_MAILBOX)); } /****************************************************************************** * Function: RtlMailboxSendToBack * Desc: To put a message block to the tail of a given mailbox. * Para: * MboxID: The identifier of the target mailbox. * pMsg: The pointer of the message block to be put into the mailbox. * MSToWait: If the mailbox is full, this value gives a time to wait to put * this message. The time unit is millisecond. * The special values are: * 0: no waiting; * 0xffffffff: wait without timeout. * If the waiting is timeout, the message sending is failed and * return _FAIL. * IsFromISR: Is this function is called from an ISR ? * Return: _SUCCESS or _FAIL. ******************************************************************************/ u8 RtlMailboxSendToBack( IN u8 MboxID, IN MSG_BLK *pMsg, IN u32 MSToWait, IN u8 IsFromISR ) { RTL_MAILBOX *pMbox=NULL; u32 wait_ticks; #ifdef PLATFORM_FREERTOS portBASE_TYPE ret; #endif pMbox = RtlMBoxIdToHdl(MboxID); if (NULL == pMbox) { MSG_MBOX_ERR("RtlMailboxSendToBack: Didn't find matched MBoxID=%d\n", MboxID); return _FAIL; } #ifdef PLATFORM_FREERTOS if (MBOX_WAIT_NO_TIMEOUT == MSToWait) { wait_ticks = portMAX_DELAY; } else if (MBOX_WAIT_NONE == MSToWait) { wait_ticks = 0; } else { wait_ticks = ((MSToWait/portTICK_RATE_MS)>0)?(MSToWait/portTICK_RATE_MS):(1); } if (IsFromISR) { ret = xQueueSendToBackFromISR(pMbox->mbox_hdl, (void *)pMsg, NULL);//(portTickType) wait_ticks); } else { ret = xQueueSendToBack(pMbox->mbox_hdl, (void *)pMsg, (portTickType) wait_ticks); } if(ret != pdPASS ) { // send message to the queue failed MSG_MBOX_ERR("RtlMailboxSendToBack: Put Msg to Queue Failed, MBoxID=%d\n", MboxID); ret = _FAIL; } else { // try to give a semaphore to wake up the receiving task if (pMbox->pWakeSema) { RtlUpSema(pMbox->pWakeSema); } ret = _SUCCESS; } return ret; #endif #ifdef PLATFORM_ECOS // TODO: Put the message to a mailbox #endif } /****************************************************************************** * Function: RtlMailboxSendToFront * Desc: To put a message block to the head of a mailbox. * Para: * MboxID: The identifier of the target mailbox. * pMsg: The pointer of the message block to be put into the mailbox. * MSToWait: If the mailbox is full, this value gives a time to wait to put * this message. The time unit is millisecond. * The special values are: * 0: no waiting; * 0xffffffff: wait without timeout. * If the waiting is timeout, the message sending is failed and * return _FAIL. * IsFromISR: Is this function is called from an ISR ? * Return: _SUCCESS or _FAIL. ******************************************************************************/ u8 RtlMailboxSendToFront( IN u8 MboxID, IN MSG_BLK *pMsg, IN u32 MSToWait, IN u8 IsFromISR ) { RTL_MAILBOX *pMbox=NULL; u32 wait_ticks; #ifdef PLATFORM_FREERTOS portBASE_TYPE ret; #endif pMbox = RtlMBoxIdToHdl(MboxID); if (NULL == pMbox) { MSG_MBOX_ERR("RtlMailboxSendToBack: Didn't find matched MBoxID=%d\n", MboxID); return _FAIL; } #ifdef PLATFORM_FREERTOS if (MBOX_WAIT_NO_TIMEOUT == MSToWait) { wait_ticks = portMAX_DELAY; } else if (MBOX_WAIT_NONE == MSToWait) { wait_ticks = 0; } else { wait_ticks = ((MSToWait/portTICK_RATE_MS)>0)?(MSToWait/portTICK_RATE_MS):(1); } if (IsFromISR) { ret = xQueueSendToFrontFromISR(pMbox->mbox_hdl, (void *)pMsg, NULL);//(portTickType) wait_ticks); } else { ret = xQueueSendToFront(pMbox->mbox_hdl, (void *)pMsg, (portTickType) wait_ticks); } if(ret != pdPASS ) { // send message to the queue failed MSG_MBOX_ERR("RtlMailboxSendToBack: Put Msg to Queue Failed, MBoxID=%d\n", MboxID); ret = _FAIL; } else { // try to give a semaphore to wake up the receiving task if (pMbox->pWakeSema) { RtlUpSema(pMbox->pWakeSema); } ret = _SUCCESS; } return ret; #endif #ifdef PLATFORM_ECOS // TODO: eCos has no API to put message to the head of a mailbox #endif } /****************************************************************************** * Function: RtlMailboxSendToFront * Desc: To get a message block from a given mailbox. * Para: * MboxID: The identifier of the target mailbox. * pMsg: The message block to store the gotten message. * MSToWait: If the mailbox is full, this value gives a time to wait to put * this message. The time unit is millisecond. * The special values are: * 0: no waiting; * 0xffffffff: wait without timeout. * If the waiting is timeout, the message sending is failed and * return _FAIL. * IsFromISR: Is this function is called from an ISR ? * Return: _SUCCESS or _FAIL. ******************************************************************************/ u8 RtlMailboxReceive( IN u8 MboxID, OUT MSG_BLK *pMsg, IN u32 MSToWait, IN u8 IsFromISR ) { RTL_MAILBOX *pMbox=NULL; u32 wait_ticks; #ifdef PLATFORM_FREERTOS portBASE_TYPE ret; #endif pMbox = RtlMBoxIdToHdl(MboxID); if (NULL == pMbox) { MSG_MBOX_ERR("RtlMailboxReceive: Didn't find the MBox with ID=%d\n", MboxID); return _FAIL; } #ifdef PLATFORM_FREERTOS if (MBOX_WAIT_NONE == MSToWait) { wait_ticks = 0; } else if (MBOX_WAIT_NO_TIMEOUT == MSToWait) { wait_ticks = portMAX_DELAY; } else { wait_ticks = ((MSToWait/portTICK_RATE_MS)>0)?(MSToWait/portTICK_RATE_MS):(1); } if (IsFromISR) { ret = xQueueReceiveFromISR(pMbox->mbox_hdl, (void *)pMsg, NULL);//( portTickType ) wait_ticks); } else { ret = xQueueReceive(pMbox->mbox_hdl, (void *)pMsg, ( portTickType ) wait_ticks); } if(ret != pdTRUE ) { // receive message failed if (0 != MSToWait) { MSG_MBOX_ERR("RtlMailboxReceive: Receive Msg Failed, MBoxID=%d\n", MboxID); } ret = _FAIL; } else { ret = _SUCCESS; } return ret; #endif #ifdef PLATFORM_ECOS // TODO: Get a message from the mailbox #endif } /****************************************************************************** * Function: RtlMailboxPeek * Desc: To copy the head message from a given mailbox without move this * message block out from the mailbox. * Para: * MboxID: The identifier of the target mailbox. * pMsg: The message block to store the gotten message. * MSToWait: If the mailbox is full, this value gives a time to wait to put * this message. The time unit is millisecond. * The special values are: * 0: no waiting; * 0xffffffff: wait without timeout. * If the waiting is timeout, the message sending is failed and * return _FAIL. * IsFromISR: Is this function is called from an ISR ? * Return: _SUCCESS or _FAIL. ******************************************************************************/ u8 RtlMailboxPeek( IN u8 MboxID, OUT MSG_BLK *pMsg, IN u32 MSToWait, IN u8 IsFromISR ) { RTL_MAILBOX *pMbox=NULL; u32 wait_ticks; #ifdef PLATFORM_FREERTOS portBASE_TYPE ret; #endif pMbox = RtlMBoxIdToHdl(MboxID); if (NULL == pMbox) { MSG_MBOX_ERR("RtlMailboxPeek: Didn't find the MBox with ID=%d\n", MboxID); return _FAIL; } #ifdef PLATFORM_FREERTOS if (MBOX_WAIT_NONE == MSToWait) { wait_ticks = 0; } else if (MBOX_WAIT_NO_TIMEOUT == MSToWait) { wait_ticks = portMAX_DELAY; } else { wait_ticks = ((MSToWait/portTICK_RATE_MS)>0)?(MSToWait/portTICK_RATE_MS):(1); } if (IsFromISR) { // ret = xQueuePeekFromISR(pMbox->mbox_hdl, (void *)pMsg, ( portTickType ) wait_ticks); // TODO: check why we have no "xQueuePeekFromISR" MSG_MBOX_ERR("RtlMailboxPeek: Current version has no 'xQueuePeekFromISR'\n"); ret = pdFALSE; } else { ret = xQueuePeek(pMbox->mbox_hdl, (void *)pMsg, ( portTickType ) wait_ticks); } if(ret != pdTRUE ) { // receive message failed MSG_MBOX_ERR("RtlMailboxReceive: Receive Msg Failed, MBoxID=%d\n", MboxID); ret = _FAIL; } else { ret = _SUCCESS; } return ret; #endif #ifdef PLATFORM_ECOS // TODO: Get a message from the mailbox #endif } /****************************************************************************** * Function: RtlMailboxMsgWaiting * Desc: To get the number of message blocks are storing in a given mailbox. * Para: * MboxID: The identifier of the target mailbox. * IsFromISR: Is this function is called from an ISR ? * Return: The number of message blocks are storing in this mailbox. ******************************************************************************/ u32 RtlMailboxMsgWaiting( IN u8 MboxID, IN u8 IsFromISR ) { RTL_MAILBOX *pMbox=NULL; u32 msg_num=0; pMbox = RtlMBoxIdToHdl(MboxID); if (NULL == pMbox) { MSG_MBOX_ERR("RtlMailboxMsgWaiting: Didn't find the MBox with ID=%d\n", MboxID); return 0; } #ifdef PLATFORM_FREERTOS if (IsFromISR) { msg_num = uxQueueMessagesWaitingFromISR(pMbox->mbox_hdl); } else { msg_num = uxQueueMessagesWaiting(pMbox->mbox_hdl); } #endif #ifdef PLATFORM_ECOS // TODO: call eCos API to implement this function #endif return msg_num; }