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