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