Commit | Line | Data |
---|---|---|
6112fd6e LL |
1 | /* |
2 | * ============================================================================ | |
3 | * Copyright (c) 1996-2002 Winbond Electronic Corporation | |
4 | * | |
5 | * Module Name: | |
6 | * Wb35Rx.c | |
7 | * | |
8 | * Abstract: | |
9 | * Processing the Rx message from down layer | |
10 | * | |
11 | * ============================================================================ | |
12 | */ | |
80aba536 | 13 | #include <linux/usb.h> |
5a0e3ad6 | 14 | #include <linux/slab.h> |
80aba536 | 15 | |
7fff1316 | 16 | #include "core.h" |
66101de1 | 17 | #include "sysdef.h" |
80aba536 | 18 | #include "wb35rx_f.h" |
66101de1 | 19 | |
c139a814 | 20 | static void packet_came(struct ieee80211_hw *hw, char *pRxBufferAddress, int PacketSize) |
66101de1 | 21 | { |
7fff1316 | 22 | struct wbsoft_priv *priv = hw->priv; |
c139a814 PE |
23 | struct sk_buff *skb; |
24 | struct ieee80211_rx_status rx_status = {0}; | |
66101de1 | 25 | |
c139a814 PE |
26 | if (!priv->enabled) |
27 | return; | |
28 | ||
29 | skb = dev_alloc_skb(PacketSize); | |
30 | if (!skb) { | |
31 | printk("Not enough memory for packet, FIXME\n"); | |
32 | return; | |
33 | } | |
34 | ||
6112fd6e | 35 | memcpy(skb_put(skb, PacketSize), pRxBufferAddress, PacketSize); |
c139a814 | 36 | |
f1d58c25 JB |
37 | memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); |
38 | ieee80211_rx_irqsafe(hw, skb); | |
66101de1 PM |
39 | } |
40 | ||
27d46421 | 41 | static void Wb35Rx_adjust(struct wb35_descriptor *pRxDes) |
c139a814 | 42 | { |
6112fd6e | 43 | u32 *pRxBufferAddress; |
c139a814 PE |
44 | u32 DecryptionMethod; |
45 | u32 i; | |
46 | u16 BufferSize; | |
47 | ||
48 | DecryptionMethod = pRxDes->R01.R01_decryption_method; | |
49 | pRxBufferAddress = pRxDes->buffer_address[0]; | |
50 | BufferSize = pRxDes->buffer_size[0]; | |
51 | ||
6112fd6e LL |
52 | /* Adjust the last part of data. Only data left */ |
53 | BufferSize -= 4; /* For CRC-32 */ | |
c139a814 PE |
54 | if (DecryptionMethod) |
55 | BufferSize -= 4; | |
6112fd6e | 56 | if (DecryptionMethod == 3) /* For CCMP */ |
c139a814 PE |
57 | BufferSize -= 4; |
58 | ||
6112fd6e LL |
59 | /* Adjust the IV field which after 802.11 header and ICV field. */ |
60 | if (DecryptionMethod == 1) { /* For WEP */ | |
61 | for (i = 6; i > 0; i--) | |
62 | pRxBufferAddress[i] = pRxBufferAddress[i - 1]; | |
c139a814 | 63 | pRxDes->buffer_address[0] = pRxBufferAddress + 1; |
6112fd6e LL |
64 | BufferSize -= 4; /* 4 byte for IV */ |
65 | } else if (DecryptionMethod) { /* For TKIP and CCMP */ | |
66 | for (i = 7; i > 1; i--) | |
67 | pRxBufferAddress[i] = pRxBufferAddress[i - 2]; | |
68 | pRxDes->buffer_address[0] = pRxBufferAddress + 2; /* Update the descriptor, shift 8 byte */ | |
69 | BufferSize -= 8; /* 8 byte for IV + ICV */ | |
c139a814 PE |
70 | } |
71 | pRxDes->buffer_size[0] = BufferSize; | |
72 | } | |
73 | ||
74 | static u16 Wb35Rx_indicate(struct ieee80211_hw *hw) | |
66101de1 | 75 | { |
6112fd6e LL |
76 | struct wbsoft_priv *priv = hw->priv; |
77 | struct hw_data *pHwData = &priv->sHwData; | |
27d46421 | 78 | struct wb35_descriptor RxDes; |
6112fd6e LL |
79 | struct wb35_rx *pWb35Rx = &pHwData->Wb35Rx; |
80 | u8 *pRxBufferAddress; | |
81 | u16 PacketSize; | |
82 | u16 stmp, BufferSize, stmp2 = 0; | |
83 | u32 RxBufferId; | |
66101de1 | 84 | |
6112fd6e | 85 | /* Only one thread be allowed to run into the following */ |
c139a814 PE |
86 | do { |
87 | RxBufferId = pWb35Rx->RxProcessIndex; | |
6112fd6e | 88 | if (pWb35Rx->RxOwner[RxBufferId]) /* Owner by VM */ |
c139a814 | 89 | break; |
dc7e04fe | 90 | |
c139a814 PE |
91 | pWb35Rx->RxProcessIndex++; |
92 | pWb35Rx->RxProcessIndex %= MAX_USB_RX_BUFFER_NUMBER; | |
dc7e04fe | 93 | |
c139a814 | 94 | pRxBufferAddress = pWb35Rx->pDRx; |
6112fd6e | 95 | BufferSize = pWb35Rx->RxBufferSize[RxBufferId]; |
dc7e04fe | 96 | |
6112fd6e | 97 | /* Parse the bulkin buffer */ |
c139a814 | 98 | while (BufferSize >= 4) { |
6112fd6e | 99 | if ((cpu_to_le32(*(u32 *)pRxBufferAddress) & 0x0fffffff) == RX_END_TAG) /* Is ending? */ |
c139a814 | 100 | break; |
dc7e04fe | 101 | |
6112fd6e | 102 | /* Get the R00 R01 first */ |
c139a814 PE |
103 | RxDes.R00.value = le32_to_cpu(*(u32 *)pRxBufferAddress); |
104 | PacketSize = (u16)RxDes.R00.R00_receive_byte_count; | |
6112fd6e LL |
105 | RxDes.R01.value = le32_to_cpu(*((u32 *)(pRxBufferAddress + 4))); |
106 | /* For new DMA 4k */ | |
c139a814 PE |
107 | if ((PacketSize & 0x03) > 0) |
108 | PacketSize -= 4; | |
dc7e04fe | 109 | |
6112fd6e | 110 | /* Basic check for Rx length. Is length valid? */ |
c139a814 | 111 | if (PacketSize > MAX_PACKET_SIZE) { |
6112fd6e | 112 | #ifdef _PE_RX_DUMP_ |
0c59dbaa | 113 | printk("Serious ERROR : Rx data size too long, size =%d\n", PacketSize); |
6112fd6e | 114 | #endif |
dc7e04fe | 115 | |
c139a814 PE |
116 | pWb35Rx->EP3vm_state = VM_STOP; |
117 | pWb35Rx->Ep3ErrorCount2++; | |
118 | break; | |
119 | } | |
dc7e04fe | 120 | |
6112fd6e LL |
121 | /* |
122 | * Wb35Rx_indicate() is called synchronously so it isn't | |
123 | * necessary to set "RxDes.Desctriptor_ID = RxBufferID;" | |
124 | */ | |
125 | BufferSize -= 8; /* subtract 8 byte for 35's USB header length */ | |
c139a814 | 126 | pRxBufferAddress += 8; |
dc7e04fe | 127 | |
c139a814 PE |
128 | RxDes.buffer_address[0] = pRxBufferAddress; |
129 | RxDes.buffer_size[0] = PacketSize; | |
130 | RxDes.buffer_number = 1; | |
131 | RxDes.buffer_start_index = 0; | |
132 | RxDes.buffer_total_size = RxDes.buffer_size[0]; | |
133 | Wb35Rx_adjust(&RxDes); | |
dc7e04fe | 134 | |
c139a814 | 135 | packet_came(hw, pRxBufferAddress, PacketSize); |
dc7e04fe | 136 | |
6112fd6e | 137 | /* Move RxBuffer point to the next */ |
c139a814 | 138 | stmp = PacketSize + 3; |
6112fd6e | 139 | stmp &= ~0x03; /* 4n alignment */ |
c139a814 PE |
140 | pRxBufferAddress += stmp; |
141 | BufferSize -= stmp; | |
142 | stmp2 += stmp; | |
143 | } | |
144 | ||
6112fd6e LL |
145 | /* Reclaim resource */ |
146 | pWb35Rx->RxOwner[RxBufferId] = 1; | |
c139a814 | 147 | } while (true); |
c139a814 | 148 | return stmp2; |
66101de1 PM |
149 | } |
150 | ||
c139a814 PE |
151 | static void Wb35Rx(struct ieee80211_hw *hw); |
152 | ||
153 | static void Wb35Rx_Complete(struct urb *urb) | |
66101de1 | 154 | { |
6112fd6e LL |
155 | struct ieee80211_hw *hw = urb->context; |
156 | struct wbsoft_priv *priv = hw->priv; | |
157 | struct hw_data *pHwData = &priv->sHwData; | |
158 | struct wb35_rx *pWb35Rx = &pHwData->Wb35Rx; | |
159 | u8 *pRxBufferAddress; | |
160 | u32 SizeCheck; | |
161 | u16 BulkLength; | |
162 | u32 RxBufferId; | |
163 | R00_DESCRIPTOR R00; | |
164 | ||
165 | /* Variable setting */ | |
66101de1 | 166 | pWb35Rx->EP3vm_state = VM_COMPLETED; |
6112fd6e | 167 | pWb35Rx->EP3VM_status = urb->status; /* Store the last result of Irp */ |
66101de1 | 168 | |
dc7e04fe | 169 | RxBufferId = pWb35Rx->CurrentRxBufferId; |
66101de1 | 170 | |
dc7e04fe | 171 | pRxBufferAddress = pWb35Rx->pDRx; |
a55a89b1 | 172 | BulkLength = (u16)urb->actual_length; |
66101de1 | 173 | |
6112fd6e | 174 | /* The IRP is completed */ |
dc7e04fe | 175 | pWb35Rx->EP3vm_state = VM_COMPLETED; |
66101de1 | 176 | |
6112fd6e | 177 | if (pHwData->SurpriseRemove || pHwData->HwStop) /* Must be here, or RxBufferId is invalid */ |
dc7e04fe PE |
178 | goto error; |
179 | ||
180 | if (pWb35Rx->rx_halt) | |
181 | goto error; | |
182 | ||
6112fd6e LL |
183 | /* Start to process the data only in successful condition */ |
184 | pWb35Rx->RxOwner[RxBufferId] = 0; /* Set the owner to driver */ | |
dc7e04fe PE |
185 | R00.value = le32_to_cpu(*(u32 *)pRxBufferAddress); |
186 | ||
6112fd6e | 187 | /* The URB is completed, check the result */ |
dc7e04fe | 188 | if (pWb35Rx->EP3VM_status != 0) { |
6112fd6e | 189 | #ifdef _PE_USB_STATE_DUMP_ |
0c59dbaa | 190 | printk("EP3 IoCompleteRoutine return error\n"); |
6112fd6e | 191 | #endif |
dc7e04fe PE |
192 | pWb35Rx->EP3vm_state = VM_STOP; |
193 | goto error; | |
194 | } | |
195 | ||
6112fd6e | 196 | /* For recovering. check if operating in single USB mode */ |
dc7e04fe | 197 | if (!HAL_USB_MODE_BURST(pHwData)) { |
6112fd6e | 198 | SizeCheck = R00.R00_receive_byte_count; |
dc7e04fe PE |
199 | if ((SizeCheck & 0x03) > 0) |
200 | SizeCheck -= 4; | |
201 | SizeCheck = (SizeCheck + 3) & ~0x03; | |
6112fd6e | 202 | SizeCheck += 12; /* 8 + 4 badbeef */ |
dc7e04fe PE |
203 | if ((BulkLength > 1600) || |
204 | (SizeCheck > 1600) || | |
205 | (BulkLength != SizeCheck) || | |
6112fd6e | 206 | (BulkLength == 0)) { /* Add for fail Urb */ |
66101de1 | 207 | pWb35Rx->EP3vm_state = VM_STOP; |
dc7e04fe | 208 | pWb35Rx->Ep3ErrorCount2++; |
66101de1 | 209 | } |
dc7e04fe | 210 | } |
66101de1 | 211 | |
6112fd6e | 212 | /* Indicating the receiving data */ |
dc7e04fe | 213 | pWb35Rx->ByteReceived += BulkLength; |
6112fd6e | 214 | pWb35Rx->RxBufferSize[RxBufferId] = BulkLength; |
66101de1 | 215 | |
6112fd6e | 216 | if (!pWb35Rx->RxOwner[RxBufferId]) |
7fff1316 | 217 | Wb35Rx_indicate(hw); |
66101de1 | 218 | |
dc7e04fe | 219 | kfree(pWb35Rx->pDRx); |
6112fd6e | 220 | /* Do the next receive */ |
7fff1316 | 221 | Wb35Rx(hw); |
dc7e04fe | 222 | return; |
66101de1 | 223 | |
dc7e04fe | 224 | error: |
6112fd6e | 225 | pWb35Rx->RxOwner[RxBufferId] = 1; /* Set the owner to hardware */ |
44e8541c | 226 | atomic_dec(&pWb35Rx->RxFireCounter); |
66101de1 PM |
227 | pWb35Rx->EP3vm_state = VM_STOP; |
228 | } | |
229 | ||
6112fd6e | 230 | /* This function cannot reentrain */ |
c139a814 | 231 | static void Wb35Rx(struct ieee80211_hw *hw) |
66101de1 | 232 | { |
6112fd6e LL |
233 | struct wbsoft_priv *priv = hw->priv; |
234 | struct hw_data *pHwData = &priv->sHwData; | |
235 | struct wb35_rx *pWb35Rx = &pHwData->Wb35Rx; | |
236 | u8 *pRxBufferAddress; | |
237 | struct urb *urb = pWb35Rx->RxUrb; | |
238 | int retv; | |
239 | u32 RxBufferId; | |
240 | ||
241 | /* Issuing URB */ | |
c139a814 PE |
242 | if (pHwData->SurpriseRemove || pHwData->HwStop) |
243 | goto error; | |
66101de1 | 244 | |
c139a814 PE |
245 | if (pWb35Rx->rx_halt) |
246 | goto error; | |
66101de1 | 247 | |
6112fd6e | 248 | /* Get RxBuffer's ID */ |
c139a814 PE |
249 | RxBufferId = pWb35Rx->RxBufferId; |
250 | if (!pWb35Rx->RxOwner[RxBufferId]) { | |
6112fd6e LL |
251 | /* It's impossible to run here. */ |
252 | #ifdef _PE_RX_DUMP_ | |
0c59dbaa | 253 | printk("Rx driver fifo unavailable\n"); |
6112fd6e | 254 | #endif |
c139a814 PE |
255 | goto error; |
256 | } | |
257 | ||
6112fd6e | 258 | /* Update buffer point, then start to bulkin the data from USB */ |
c139a814 PE |
259 | pWb35Rx->RxBufferId++; |
260 | pWb35Rx->RxBufferId %= MAX_USB_RX_BUFFER_NUMBER; | |
261 | ||
262 | pWb35Rx->CurrentRxBufferId = RxBufferId; | |
263 | ||
264 | pWb35Rx->pDRx = kzalloc(MAX_USB_RX_BUFFER, GFP_ATOMIC); | |
265 | if (!pWb35Rx->pDRx) { | |
266 | printk("w35und: Rx memory alloc failed\n"); | |
267 | goto error; | |
268 | } | |
269 | pRxBufferAddress = pWb35Rx->pDRx; | |
270 | ||
271 | usb_fill_bulk_urb(urb, pHwData->WbUsb.udev, | |
272 | usb_rcvbulkpipe(pHwData->WbUsb.udev, 3), | |
273 | pRxBufferAddress, MAX_USB_RX_BUFFER, | |
274 | Wb35Rx_Complete, hw); | |
275 | ||
276 | pWb35Rx->EP3vm_state = VM_RUNNING; | |
277 | ||
278 | retv = usb_submit_urb(urb, GFP_ATOMIC); | |
279 | ||
280 | if (retv != 0) { | |
281 | printk("Rx URB sending error\n"); | |
282 | goto error; | |
66101de1 | 283 | } |
c139a814 PE |
284 | return; |
285 | ||
286 | error: | |
6112fd6e | 287 | /* VM stop */ |
c139a814 PE |
288 | pWb35Rx->EP3vm_state = VM_STOP; |
289 | atomic_dec(&pWb35Rx->RxFireCounter); | |
66101de1 PM |
290 | } |
291 | ||
c139a814 | 292 | void Wb35Rx_start(struct ieee80211_hw *hw) |
66101de1 | 293 | { |
6112fd6e LL |
294 | struct wbsoft_priv *priv = hw->priv; |
295 | struct hw_data *pHwData = &priv->sHwData; | |
296 | struct wb35_rx *pWb35Rx = &pHwData->Wb35Rx; | |
66101de1 | 297 | |
6112fd6e | 298 | /* Allow only one thread to run into the Wb35Rx() function */ |
c139a814 PE |
299 | if (atomic_inc_return(&pWb35Rx->RxFireCounter) == 1) { |
300 | pWb35Rx->EP3vm_state = VM_RUNNING; | |
301 | Wb35Rx(hw); | |
302 | } else | |
303 | atomic_dec(&pWb35Rx->RxFireCounter); | |
66101de1 PM |
304 | } |
305 | ||
6112fd6e | 306 | static void Wb35Rx_reset_descriptor(struct hw_data *pHwData) |
66101de1 | 307 | { |
6112fd6e LL |
308 | struct wb35_rx *pWb35Rx = &pHwData->Wb35Rx; |
309 | u32 i; | |
66101de1 PM |
310 | |
311 | pWb35Rx->ByteReceived = 0; | |
312 | pWb35Rx->RxProcessIndex = 0; | |
313 | pWb35Rx->RxBufferId = 0; | |
314 | pWb35Rx->EP3vm_state = VM_STOP; | |
315 | pWb35Rx->rx_halt = 0; | |
316 | ||
6112fd6e LL |
317 | /* Initial the Queue. The last buffer is reserved for used if the Rx resource is unavailable. */ |
318 | for (i = 0; i < MAX_USB_RX_BUFFER_NUMBER; i++) | |
66101de1 PM |
319 | pWb35Rx->RxOwner[i] = 1; |
320 | } | |
321 | ||
6112fd6e | 322 | unsigned char Wb35Rx_initial(struct hw_data *pHwData) |
66101de1 | 323 | { |
eb62f3ea | 324 | struct wb35_rx *pWb35Rx = &pHwData->Wb35Rx; |
66101de1 | 325 | |
6112fd6e LL |
326 | /* Initial the Buffer Queue */ |
327 | Wb35Rx_reset_descriptor(pHwData); | |
66101de1 | 328 | |
c139a814 | 329 | pWb35Rx->RxUrb = usb_alloc_urb(0, GFP_ATOMIC); |
6112fd6e | 330 | return !!pWb35Rx->RxUrb; |
66101de1 PM |
331 | } |
332 | ||
6112fd6e | 333 | void Wb35Rx_stop(struct hw_data *pHwData) |
3cae503b | 334 | { |
eb62f3ea | 335 | struct wb35_rx *pWb35Rx = &pHwData->Wb35Rx; |
3cae503b | 336 | |
6112fd6e | 337 | /* Canceling the Irp if already sends it out. */ |
c139a814 | 338 | if (pWb35Rx->EP3vm_state == VM_RUNNING) { |
6112fd6e LL |
339 | usb_unlink_urb(pWb35Rx->RxUrb); /* Only use unlink, let Wb35Rx_destroy to free them */ |
340 | #ifdef _PE_RX_DUMP_ | |
0c59dbaa | 341 | printk("EP3 Rx stop\n"); |
6112fd6e | 342 | #endif |
3cae503b | 343 | } |
3cae503b | 344 | } |
66101de1 | 345 | |
6112fd6e LL |
346 | /* Needs process context */ |
347 | void Wb35Rx_destroy(struct hw_data *pHwData) | |
66101de1 | 348 | { |
eb62f3ea | 349 | struct wb35_rx *pWb35Rx = &pHwData->Wb35Rx; |
66101de1 | 350 | |
66101de1 | 351 | do { |
6112fd6e | 352 | msleep(10); /* Delay for waiting function enter */ |
c139a814 | 353 | } while (pWb35Rx->EP3vm_state != VM_STOP); |
6112fd6e | 354 | msleep(10); /* Delay for waiting function exit */ |
66101de1 | 355 | |
c139a814 | 356 | if (pWb35Rx->RxUrb) |
6112fd6e LL |
357 | usb_free_urb(pWb35Rx->RxUrb); |
358 | #ifdef _PE_RX_DUMP_ | |
0c59dbaa | 359 | printk("Wb35Rx_destroy OK\n"); |
6112fd6e | 360 | #endif |
66101de1 PM |
361 | } |
362 |