summaryrefslogblamecommitdiffstats
path: root/drivers/staging/wilc1000/wilc_msgqueue.c
blob: 41244ce942ba26021b223cc66c77d1a09bd3fa5e (plain) (tree)
1
2
3
4
5
6
7
8
9
10
 
                          
                           






                                                            
                                                
 
                                                     


                                        
                                  
                            







                                                            
                                                 
 
                                 


                                                  
                                   


                                             
                                          
                                                                         
 
                                                











                                                            
                                              
                                                                             
 
                                        


                                    
                                                                        


                                                                      
                                





                                                               
                                                           


                                                   
                                                                       
                                                            
                                                                       
 
                                         
                                        


                                                                
 
                                             
                                                            
 




                                                                    
                           



                                                         
                                  
                                                     
                                           





                            





                                                            
                                              
                                                                       
                                                     
 
                             
                                        
                            
 

                                                          


                                                                      
                                






                                                                    
                             
 















                                                                            
                                   





                                                                                    
                                           




                                                                             
                                                                                    



                                                                 

                                             

                                                                            







                                

#include "wilc_msgqueue.h"
#include <linux/spinlock.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 WILC_SUCCESS;
}

/*!
 *  @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 WILC_SUCCESS;
}

/*!
 *  @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)
{
	int s32RetStatus = WILC_SUCCESS;
	unsigned long flags;
	Message *pstrMessage = NULL;

	if ((!pHandle) || (u32SendBufferSize == 0) || (!pvSendBuffer)) {
		WILC_ERRORREPORT(s32RetStatus, WILC_INVALID_ARGUMENT);
	}

	if (pHandle->bExiting) {
		WILC_ERRORREPORT(s32RetStatus, WILC_FAIL);
	}

	spin_lock_irqsave(&pHandle->strCriticalSection, flags);

	/* construct a new message */
	pstrMessage = kmalloc(sizeof(Message), GFP_ATOMIC);
	WILC_NULLCHECK(s32RetStatus, pstrMessage);
	pstrMessage->u32Length = u32SendBufferSize;
	pstrMessage->pstrNext = NULL;
	pstrMessage->pvBuffer = kmalloc(u32SendBufferSize, GFP_ATOMIC);
	WILC_NULLCHECK(s32RetStatus, pstrMessage->pvBuffer);
	memcpy(pstrMessage->pvBuffer, pvSendBuffer, u32SendBufferSize);

	/* 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);

	WILC_CATCH(s32RetStatus)
	{
		/* error occured, free any allocations */
		if (pstrMessage) {
			kfree(pstrMessage->pvBuffer);
			kfree(pstrMessage);
		}
	}

	return s32RetStatus;
}

/*!
 *  @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 s32RetStatus = WILC_SUCCESS;
	unsigned long flags;

	if ((!pHandle) || (u32RecvBufferSize == 0)
	    || (!pvRecvBuffer) || (!pu32ReceivedLength)) {
		WILC_ERRORREPORT(s32RetStatus, WILC_INVALID_ARGUMENT);
	}

	if (pHandle->bExiting) {
		WILC_ERRORREPORT(s32RetStatus, WILC_FAIL);
	}

	spin_lock_irqsave(&pHandle->strCriticalSection, flags);
	pHandle->u32ReceiversCount++;
	spin_unlock_irqrestore(&pHandle->strCriticalSection, flags);

	down(&pHandle->hSem);

	if (s32RetStatus == WILC_TIMEOUT) {
		/* timed out, just exit without consumeing the message */
		spin_lock_irqsave(&pHandle->strCriticalSection, flags);
		pHandle->u32ReceiversCount--;
		spin_unlock_irqrestore(&pHandle->strCriticalSection, flags);
	} else {
		/* other non-timeout scenarios */
		WILC_ERRORCHECK(s32RetStatus);

		if (pHandle->bExiting) {
			WILC_ERRORREPORT(s32RetStatus, WILC_FAIL);
		}

		spin_lock_irqsave(&pHandle->strCriticalSection, flags);

		pstrMessage = pHandle->pstrMessageList;
		if (!pstrMessage) {
			spin_unlock_irqrestore(&pHandle->strCriticalSection, flags);
			WILC_ERRORREPORT(s32RetStatus, WILC_FAIL);
		}
		/* check buffer size */
		if (u32RecvBufferSize < pstrMessage->u32Length)	{
			spin_unlock_irqrestore(&pHandle->strCriticalSection, flags);
			up(&pHandle->hSem);
			WILC_ERRORREPORT(s32RetStatus, WILC_BUFFER_OVERFLOW);
		}

		/* 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);
	}

	WILC_CATCH(s32RetStatus)
	{
	}

	return s32RetStatus;
}