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