1 
2 #include "wilc_msgqueue.h"
3 #include <linux/spinlock.h>
4 #include "linux_wlan_common.h"
5 #include <linux/errno.h>
6 #include <linux/slab.h>
7 
8 /*!
9  *  @author		syounan
10  *  @date		1 Sep 2010
11  *  @note		copied from FLO glue implementatuion
12  *  @version		1.0
13  */
wilc_mq_create(WILC_MsgQueueHandle * pHandle)14 int wilc_mq_create(WILC_MsgQueueHandle *pHandle)
15 {
16 	spin_lock_init(&pHandle->strCriticalSection);
17 	sema_init(&pHandle->hSem, 0);
18 	pHandle->pstrMessageList = NULL;
19 	pHandle->u32ReceiversCount = 0;
20 	pHandle->bExiting = false;
21 	return 0;
22 }
23 
24 /*!
25  *  @author		syounan
26  *  @date		1 Sep 2010
27  *  @note		copied from FLO glue implementatuion
28  *  @version		1.0
29  */
wilc_mq_destroy(WILC_MsgQueueHandle * pHandle)30 int wilc_mq_destroy(WILC_MsgQueueHandle *pHandle)
31 {
32 	pHandle->bExiting = true;
33 
34 	/* Release any waiting receiver thread. */
35 	while (pHandle->u32ReceiversCount > 0) {
36 		up(&pHandle->hSem);
37 		pHandle->u32ReceiversCount--;
38 	}
39 
40 	while (pHandle->pstrMessageList) {
41 		Message *pstrMessge = pHandle->pstrMessageList->pstrNext;
42 
43 		kfree(pHandle->pstrMessageList);
44 		pHandle->pstrMessageList = pstrMessge;
45 	}
46 
47 	return 0;
48 }
49 
50 /*!
51  *  @author		syounan
52  *  @date		1 Sep 2010
53  *  @note		copied from FLO glue implementatuion
54  *  @version		1.0
55  */
wilc_mq_send(WILC_MsgQueueHandle * pHandle,const void * pvSendBuffer,u32 u32SendBufferSize)56 int wilc_mq_send(WILC_MsgQueueHandle *pHandle,
57 			     const void *pvSendBuffer, u32 u32SendBufferSize)
58 {
59 	unsigned long flags;
60 	Message *pstrMessage = NULL;
61 
62 	if ((!pHandle) || (u32SendBufferSize == 0) || (!pvSendBuffer)) {
63 		PRINT_ER("pHandle or pvSendBuffer is null\n");
64 		return -EFAULT;
65 	}
66 
67 	if (pHandle->bExiting) {
68 		PRINT_ER("pHandle fail\n");
69 		return -EFAULT;
70 	}
71 
72 	/* construct a new message */
73 	pstrMessage = kmalloc(sizeof(Message), GFP_ATOMIC);
74 	if (!pstrMessage)
75 		return -ENOMEM;
76 
77 	pstrMessage->u32Length = u32SendBufferSize;
78 	pstrMessage->pstrNext = NULL;
79 	pstrMessage->pvBuffer = kmemdup(pvSendBuffer, u32SendBufferSize,
80 					GFP_ATOMIC);
81 	if (!pstrMessage->pvBuffer) {
82 		kfree(pstrMessage);
83 		return -ENOMEM;
84 	}
85 
86 	spin_lock_irqsave(&pHandle->strCriticalSection, flags);
87 
88 	/* add it to the message queue */
89 	if (!pHandle->pstrMessageList) {
90 		pHandle->pstrMessageList  = pstrMessage;
91 	} else {
92 		Message *pstrTailMsg = pHandle->pstrMessageList;
93 
94 		while (pstrTailMsg->pstrNext)
95 			pstrTailMsg = pstrTailMsg->pstrNext;
96 
97 		pstrTailMsg->pstrNext = pstrMessage;
98 	}
99 
100 	spin_unlock_irqrestore(&pHandle->strCriticalSection, flags);
101 
102 	up(&pHandle->hSem);
103 
104 	return 0;
105 }
106 
107 /*!
108  *  @author		syounan
109  *  @date		1 Sep 2010
110  *  @note		copied from FLO glue implementatuion
111  *  @version		1.0
112  */
wilc_mq_recv(WILC_MsgQueueHandle * pHandle,void * pvRecvBuffer,u32 u32RecvBufferSize,u32 * pu32ReceivedLength)113 int wilc_mq_recv(WILC_MsgQueueHandle *pHandle,
114 			     void *pvRecvBuffer, u32 u32RecvBufferSize,
115 			     u32 *pu32ReceivedLength)
116 {
117 	Message *pstrMessage;
118 	int result = 0;
119 	unsigned long flags;
120 
121 	if ((!pHandle) || (u32RecvBufferSize == 0)
122 	    || (!pvRecvBuffer) || (!pu32ReceivedLength)) {
123 		PRINT_ER("pHandle or pvRecvBuffer is null\n");
124 		return -EINVAL;
125 	}
126 
127 	if (pHandle->bExiting) {
128 		PRINT_ER("pHandle fail\n");
129 		return -EFAULT;
130 	}
131 
132 	spin_lock_irqsave(&pHandle->strCriticalSection, flags);
133 	pHandle->u32ReceiversCount++;
134 	spin_unlock_irqrestore(&pHandle->strCriticalSection, flags);
135 
136 	down(&pHandle->hSem);
137 
138 	/* other non-timeout scenarios */
139 	if (result) {
140 		PRINT_ER("Non-timeout\n");
141 		return result;
142 	}
143 
144 	if (pHandle->bExiting) {
145 		PRINT_ER("pHandle fail\n");
146 		return -EFAULT;
147 	}
148 
149 	spin_lock_irqsave(&pHandle->strCriticalSection, flags);
150 
151 	pstrMessage = pHandle->pstrMessageList;
152 	if (!pstrMessage) {
153 		spin_unlock_irqrestore(&pHandle->strCriticalSection, flags);
154 		PRINT_ER("pstrMessage is null\n");
155 		return -EFAULT;
156 	}
157 	/* check buffer size */
158 	if (u32RecvBufferSize < pstrMessage->u32Length)	{
159 		spin_unlock_irqrestore(&pHandle->strCriticalSection, flags);
160 		up(&pHandle->hSem);
161 		PRINT_ER("u32RecvBufferSize overflow\n");
162 		return -EOVERFLOW;
163 	}
164 
165 	/* consume the message */
166 	pHandle->u32ReceiversCount--;
167 	memcpy(pvRecvBuffer, pstrMessage->pvBuffer, pstrMessage->u32Length);
168 	*pu32ReceivedLength = pstrMessage->u32Length;
169 
170 	pHandle->pstrMessageList = pstrMessage->pstrNext;
171 
172 	kfree(pstrMessage->pvBuffer);
173 	kfree(pstrMessage);
174 
175 	spin_unlock_irqrestore(&pHandle->strCriticalSection, flags);
176 
177 	return result;
178 }
179