blob: 0eff121b8291eeefaa7773eb8970d39d959880f3 [file] [log] [blame]
#include "wilc_msgqueue.h"
#include <linux/spinlock.h>
#include "linux_wlan_common.h"
#include <linux/errno.h>
#include <linux/slab.h>
/*!
* @author syounan
* @date 1 Sep 2010
* @note copied from FLO glue implementatuion
* @version 1.0
*/
int wilc_mq_create(WILC_MsgQueueHandle *pHandle)
{
spin_lock_init(&pHandle->strCriticalSection);
sema_init(&pHandle->hSem, 0);
pHandle->pstrMessageList = NULL;
pHandle->u32ReceiversCount = 0;
pHandle->bExiting = false;
return 0;
}
/*!
* @author syounan
* @date 1 Sep 2010
* @note copied from FLO glue implementatuion
* @version 1.0
*/
int wilc_mq_destroy(WILC_MsgQueueHandle *pHandle)
{
pHandle->bExiting = true;
/* Release any waiting receiver thread. */
while (pHandle->u32ReceiversCount > 0) {
up(&pHandle->hSem);
pHandle->u32ReceiversCount--;
}
while (pHandle->pstrMessageList) {
Message *pstrMessge = pHandle->pstrMessageList->pstrNext;
kfree(pHandle->pstrMessageList);
pHandle->pstrMessageList = pstrMessge;
}
return 0;
}
/*!
* @author syounan
* @date 1 Sep 2010
* @note copied from FLO glue implementatuion
* @version 1.0
*/
int wilc_mq_send(WILC_MsgQueueHandle *pHandle,
const void *pvSendBuffer, u32 u32SendBufferSize)
{
unsigned long flags;
Message *pstrMessage = NULL;
if ((!pHandle) || (u32SendBufferSize == 0) || (!pvSendBuffer)) {
PRINT_ER("pHandle or pvSendBuffer is null\n");
return -EFAULT;
}
if (pHandle->bExiting) {
PRINT_ER("pHandle fail\n");
return -EFAULT;
}
/* construct a new message */
pstrMessage = kmalloc(sizeof(Message), GFP_ATOMIC);
if (!pstrMessage)
return -ENOMEM;
pstrMessage->u32Length = u32SendBufferSize;
pstrMessage->pstrNext = NULL;
pstrMessage->pvBuffer = kmemdup(pvSendBuffer, u32SendBufferSize,
GFP_ATOMIC);
if (!pstrMessage->pvBuffer) {
kfree(pstrMessage);
return -ENOMEM;
}
spin_lock_irqsave(&pHandle->strCriticalSection, flags);
/* add it to the message queue */
if (!pHandle->pstrMessageList) {
pHandle->pstrMessageList = pstrMessage;
} else {
Message *pstrTailMsg = pHandle->pstrMessageList;
while (pstrTailMsg->pstrNext)
pstrTailMsg = pstrTailMsg->pstrNext;
pstrTailMsg->pstrNext = pstrMessage;
}
spin_unlock_irqrestore(&pHandle->strCriticalSection, flags);
up(&pHandle->hSem);
return 0;
}
/*!
* @author syounan
* @date 1 Sep 2010
* @note copied from FLO glue implementatuion
* @version 1.0
*/
int wilc_mq_recv(WILC_MsgQueueHandle *pHandle,
void *pvRecvBuffer, u32 u32RecvBufferSize,
u32 *pu32ReceivedLength)
{
Message *pstrMessage;
int result = 0;
unsigned long flags;
if ((!pHandle) || (u32RecvBufferSize == 0)
|| (!pvRecvBuffer) || (!pu32ReceivedLength)) {
PRINT_ER("pHandle or pvRecvBuffer is null\n");
return -EINVAL;
}
if (pHandle->bExiting) {
PRINT_ER("pHandle fail\n");
return -EFAULT;
}
spin_lock_irqsave(&pHandle->strCriticalSection, flags);
pHandle->u32ReceiversCount++;
spin_unlock_irqrestore(&pHandle->strCriticalSection, flags);
down(&pHandle->hSem);
/* other non-timeout scenarios */
if (result) {
PRINT_ER("Non-timeout\n");
return result;
}
if (pHandle->bExiting) {
PRINT_ER("pHandle fail\n");
return -EFAULT;
}
spin_lock_irqsave(&pHandle->strCriticalSection, flags);
pstrMessage = pHandle->pstrMessageList;
if (!pstrMessage) {
spin_unlock_irqrestore(&pHandle->strCriticalSection, flags);
PRINT_ER("pstrMessage is null\n");
return -EFAULT;
}
/* check buffer size */
if (u32RecvBufferSize < pstrMessage->u32Length) {
spin_unlock_irqrestore(&pHandle->strCriticalSection, flags);
up(&pHandle->hSem);
PRINT_ER("u32RecvBufferSize overflow\n");
return -EOVERFLOW;
}
/* consume the message */
pHandle->u32ReceiversCount--;
memcpy(pvRecvBuffer, pstrMessage->pvBuffer, pstrMessage->u32Length);
*pu32ReceivedLength = pstrMessage->u32Length;
pHandle->pstrMessageList = pstrMessage->pstrNext;
kfree(pstrMessage->pvBuffer);
kfree(pstrMessage);
spin_unlock_irqrestore(&pHandle->strCriticalSection, flags);
return result;
}