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