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