Merge 4.3-rc5 into staging-next
[firefly-linux-kernel-4.4.55.git] / drivers / staging / wilc1000 / wilc_msgqueue.c
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  */
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  */
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  */
56 int wilc_mq_send(WILC_MsgQueueHandle *pHandle,
57                              const void *pvSendBuffer, u32 u32SendBufferSize)
58 {
59         int result = 0;
60         unsigned long flags;
61         Message *pstrMessage = NULL;
62
63         if ((!pHandle) || (u32SendBufferSize == 0) || (!pvSendBuffer)) {
64                 PRINT_ER("pHandle or pvSendBuffer is null\n");
65                 result = -EFAULT;
66                 goto ERRORHANDLER;
67         }
68
69         if (pHandle->bExiting) {
70                 PRINT_ER("pHandle fail\n");
71                 result = -EFAULT;
72                 goto ERRORHANDLER;
73         }
74
75         spin_lock_irqsave(&pHandle->strCriticalSection, flags);
76
77         /* construct a new message */
78         pstrMessage = kmalloc(sizeof(Message), GFP_ATOMIC);
79         if (!pstrMessage)
80                 return -ENOMEM;
81         pstrMessage->u32Length = u32SendBufferSize;
82         pstrMessage->pstrNext = NULL;
83         pstrMessage->pvBuffer = kmalloc(u32SendBufferSize, GFP_ATOMIC);
84         if (!pstrMessage->pvBuffer) {
85                 result = -ENOMEM;
86                 goto ERRORHANDLER;
87         }
88         memcpy(pstrMessage->pvBuffer, pvSendBuffer, u32SendBufferSize);
89
90         /* add it to the message queue */
91         if (!pHandle->pstrMessageList) {
92                 pHandle->pstrMessageList  = pstrMessage;
93         } else {
94                 Message *pstrTailMsg = pHandle->pstrMessageList;
95
96                 while (pstrTailMsg->pstrNext)
97                         pstrTailMsg = pstrTailMsg->pstrNext;
98
99                 pstrTailMsg->pstrNext = pstrMessage;
100         }
101
102         spin_unlock_irqrestore(&pHandle->strCriticalSection, flags);
103
104         up(&pHandle->hSem);
105
106 ERRORHANDLER:
107         /* error occured, free any allocations */
108         if (pstrMessage) {
109                 kfree(pstrMessage->pvBuffer);
110                 kfree(pstrMessage);
111         }
112
113         return result;
114 }
115
116 /*!
117  *  @author             syounan
118  *  @date               1 Sep 2010
119  *  @note               copied from FLO glue implementatuion
120  *  @version            1.0
121  */
122 int wilc_mq_recv(WILC_MsgQueueHandle *pHandle,
123                              void *pvRecvBuffer, u32 u32RecvBufferSize,
124                              u32 *pu32ReceivedLength)
125 {
126         Message *pstrMessage;
127         int result = 0;
128         unsigned long flags;
129
130         if ((!pHandle) || (u32RecvBufferSize == 0)
131             || (!pvRecvBuffer) || (!pu32ReceivedLength)) {
132                 PRINT_ER("pHandle or pvRecvBuffer is null\n");
133                 return -EINVAL;
134         }
135
136         if (pHandle->bExiting) {
137                 PRINT_ER("pHandle fail\n");
138                 return -EFAULT;
139         }
140
141         spin_lock_irqsave(&pHandle->strCriticalSection, flags);
142         pHandle->u32ReceiversCount++;
143         spin_unlock_irqrestore(&pHandle->strCriticalSection, flags);
144
145         down(&pHandle->hSem);
146
147         /* other non-timeout scenarios */
148         if (result) {
149                 PRINT_ER("Non-timeout\n");
150                 return result;
151         }
152
153         if (pHandle->bExiting) {
154                 PRINT_ER("pHandle fail\n");
155                 return -EFAULT;
156         }
157
158         spin_lock_irqsave(&pHandle->strCriticalSection, flags);
159
160         pstrMessage = pHandle->pstrMessageList;
161         if (!pstrMessage) {
162                 spin_unlock_irqrestore(&pHandle->strCriticalSection, flags);
163                 PRINT_ER("pstrMessage is null\n");
164                 return -EFAULT;
165         }
166         /* check buffer size */
167         if (u32RecvBufferSize < pstrMessage->u32Length) {
168                 spin_unlock_irqrestore(&pHandle->strCriticalSection, flags);
169                 up(&pHandle->hSem);
170                 PRINT_ER("u32RecvBufferSize overflow\n");
171                 return -EOVERFLOW;
172         }
173
174         /* consume the message */
175         pHandle->u32ReceiversCount--;
176         memcpy(pvRecvBuffer, pstrMessage->pvBuffer, pstrMessage->u32Length);
177         *pu32ReceivedLength = pstrMessage->u32Length;
178
179         pHandle->pstrMessageList = pstrMessage->pstrNext;
180
181         kfree(pstrMessage->pvBuffer);
182         kfree(pstrMessage);
183
184         spin_unlock_irqrestore(&pHandle->strCriticalSection, flags);
185
186         return result;
187 }