These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / 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         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  */
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 }