Staging: add w35und wifi driver
[deliverable/linux.git] / drivers / staging / winbond / linux / wb35tx.c
1 //============================================================================
2 // Copyright (c) 1996-2002 Winbond Electronic Corporation
3 //
4 // Module Name:
5 // Wb35Tx.c
6 //
7 // Abstract:
8 // Processing the Tx message and put into down layer
9 //
10 //============================================================================
11 #include "sysdef.h"
12
13
14 unsigned char
15 Wb35Tx_get_tx_buffer(phw_data_t pHwData, PUCHAR *pBuffer )
16 {
17 PWB35TX pWb35Tx = &pHwData->Wb35Tx;
18
19 *pBuffer = pWb35Tx->TxBuffer[0];
20 return TRUE;
21 }
22
23 void Wb35Tx_start(phw_data_t pHwData)
24 {
25 PWB35TX pWb35Tx = &pHwData->Wb35Tx;
26
27 // Allow only one thread to run into function
28 if (OS_ATOMIC_INC(pHwData->Adapter, &pWb35Tx->TxFireCounter) == 1) {
29 pWb35Tx->EP4vm_state = VM_RUNNING;
30 Wb35Tx(pHwData);
31 } else
32 OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Tx->TxFireCounter );
33 }
34
35
36 void Wb35Tx(phw_data_t pHwData)
37 {
38 PWB35TX pWb35Tx = &pHwData->Wb35Tx;
39 PADAPTER Adapter = pHwData->Adapter;
40 PUCHAR pTxBufferAddress;
41 PMDS pMds = &Adapter->Mds;
42 struct urb * pUrb = (struct urb *)pWb35Tx->Tx4Urb;
43 int retv;
44 u32 SendIndex;
45
46
47 if (pHwData->SurpriseRemove || pHwData->HwStop)
48 goto cleanup;
49
50 if (pWb35Tx->tx_halt)
51 goto cleanup;
52
53 // Ownership checking
54 SendIndex = pWb35Tx->TxSendIndex;
55 if (!pMds->TxOwner[SendIndex]) //No more data need to be sent, return immediately
56 goto cleanup;
57
58 pTxBufferAddress = pWb35Tx->TxBuffer[SendIndex];
59 //
60 // Issuing URB
61 //
62 usb_fill_bulk_urb(pUrb, pHwData->WbUsb.udev,
63 usb_sndbulkpipe(pHwData->WbUsb.udev, 4),
64 pTxBufferAddress, pMds->TxBufferSize[ SendIndex ],
65 Wb35Tx_complete, pHwData);
66
67 pWb35Tx->EP4vm_state = VM_RUNNING;
68 retv = wb_usb_submit_urb( pUrb );
69 if (retv<0) {
70 printk("EP4 Tx Irp sending error\n");
71 goto cleanup;
72 }
73
74 // Check if driver needs issue Irp for EP2
75 pWb35Tx->TxFillCount += pMds->TxCountInBuffer[SendIndex];
76 if (pWb35Tx->TxFillCount > 12)
77 Wb35Tx_EP2VM_start( pHwData );
78
79 pWb35Tx->ByteTransfer += pMds->TxBufferSize[SendIndex];
80 return;
81
82 cleanup:
83 pWb35Tx->EP4vm_state = VM_STOP;
84 OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Tx->TxFireCounter );
85 }
86
87
88 void Wb35Tx_complete(struct urb * pUrb)
89 {
90 phw_data_t pHwData = pUrb->context;
91 PADAPTER Adapter = (PADAPTER)pHwData->Adapter;
92 PWB35TX pWb35Tx = &pHwData->Wb35Tx;
93 PMDS pMds = &Adapter->Mds;
94
95 printk("wb35: tx complete\n");
96 // Variable setting
97 pWb35Tx->EP4vm_state = VM_COMPLETED;
98 pWb35Tx->EP4VM_status = pUrb->status; //Store the last result of Irp
99 pMds->TxOwner[ pWb35Tx->TxSendIndex ] = 0;// Set the owner. Free the owner bit always.
100 pWb35Tx->TxSendIndex++;
101 pWb35Tx->TxSendIndex %= MAX_USB_TX_BUFFER_NUMBER;
102
103 do {
104 if (pHwData->SurpriseRemove || pHwData->HwStop) // Let WbWlanHalt to handle surprise remove
105 break;
106
107 if (pWb35Tx->tx_halt)
108 break;
109
110 // The URB is completed, check the result
111 if (pWb35Tx->EP4VM_status != 0) {
112 printk("URB submission failed\n");
113 pWb35Tx->EP4vm_state = VM_STOP;
114 break; // Exit while(FALSE);
115 }
116
117 Mds_Tx(Adapter);
118 Wb35Tx(pHwData);
119 return;
120 } while(FALSE);
121
122 OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Tx->TxFireCounter );
123 pWb35Tx->EP4vm_state = VM_STOP;
124 }
125
126 void Wb35Tx_reset_descriptor( phw_data_t pHwData )
127 {
128 PWB35TX pWb35Tx = &pHwData->Wb35Tx;
129
130 pWb35Tx->TxSendIndex = 0;
131 pWb35Tx->tx_halt = 0;
132 }
133
134 unsigned char Wb35Tx_initial(phw_data_t pHwData)
135 {
136 PWB35TX pWb35Tx = &pHwData->Wb35Tx;
137
138 pWb35Tx->Tx4Urb = wb_usb_alloc_urb(0);
139 if (!pWb35Tx->Tx4Urb)
140 return FALSE;
141
142 pWb35Tx->Tx2Urb = wb_usb_alloc_urb(0);
143 if (!pWb35Tx->Tx2Urb)
144 {
145 usb_free_urb( pWb35Tx->Tx4Urb );
146 return FALSE;
147 }
148
149 return TRUE;
150 }
151
152 //======================================================
153 void Wb35Tx_stop(phw_data_t pHwData)
154 {
155 PWB35TX pWb35Tx = &pHwData->Wb35Tx;
156
157 // Trying to canceling the Trp of EP2
158 if (pWb35Tx->EP2vm_state == VM_RUNNING)
159 usb_unlink_urb( pWb35Tx->Tx2Urb ); // Only use unlink, let Wb35Tx_destrot to free them
160 #ifdef _PE_TX_DUMP_
161 WBDEBUG(("EP2 Tx stop\n"));
162 #endif
163
164 // Trying to canceling the Irp of EP4
165 if (pWb35Tx->EP4vm_state == VM_RUNNING)
166 usb_unlink_urb( pWb35Tx->Tx4Urb ); // Only use unlink, let Wb35Tx_destrot to free them
167 #ifdef _PE_TX_DUMP_
168 WBDEBUG(("EP4 Tx stop\n"));
169 #endif
170 }
171
172 //======================================================
173 void Wb35Tx_destroy(phw_data_t pHwData)
174 {
175 PWB35TX pWb35Tx = &pHwData->Wb35Tx;
176
177 // Wait for VM stop
178 do {
179 OS_SLEEP(10000); // Delay for waiting function enter 940623.1.a
180 } while( (pWb35Tx->EP2vm_state != VM_STOP) && (pWb35Tx->EP4vm_state != VM_STOP) );
181 OS_SLEEP(10000); // Delay for waiting function enter 940623.1.b
182
183 if (pWb35Tx->Tx4Urb)
184 usb_free_urb( pWb35Tx->Tx4Urb );
185
186 if (pWb35Tx->Tx2Urb)
187 usb_free_urb( pWb35Tx->Tx2Urb );
188
189 #ifdef _PE_TX_DUMP_
190 WBDEBUG(("Wb35Tx_destroy OK\n"));
191 #endif
192 }
193
194 void Wb35Tx_CurrentTime(phw_data_t pHwData, u32 TimeCount)
195 {
196 PWB35TX pWb35Tx = &pHwData->Wb35Tx;
197 unsigned char Trigger = FALSE;
198
199 if (pWb35Tx->TxTimer > TimeCount)
200 Trigger = TRUE;
201 else if (TimeCount > (pWb35Tx->TxTimer+500))
202 Trigger = TRUE;
203
204 if (Trigger) {
205 pWb35Tx->TxTimer = TimeCount;
206 Wb35Tx_EP2VM_start( pHwData );
207 }
208 }
209
210 void Wb35Tx_EP2VM_start(phw_data_t pHwData)
211 {
212 PWB35TX pWb35Tx = &pHwData->Wb35Tx;
213
214 // Allow only one thread to run into function
215 if (OS_ATOMIC_INC( pHwData->Adapter, &pWb35Tx->TxResultCount ) == 1) {
216 pWb35Tx->EP2vm_state = VM_RUNNING;
217 Wb35Tx_EP2VM( pHwData );
218 }
219 else
220 OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Tx->TxResultCount );
221 }
222
223
224 void Wb35Tx_EP2VM(phw_data_t pHwData)
225 {
226 PWB35TX pWb35Tx = &pHwData->Wb35Tx;
227 struct urb * pUrb = (struct urb *)pWb35Tx->Tx2Urb;
228 PULONG pltmp = (PULONG)pWb35Tx->EP2_buf;
229 int retv;
230
231 do {
232 if (pHwData->SurpriseRemove || pHwData->HwStop)
233 break;
234
235 if (pWb35Tx->tx_halt)
236 break;
237
238 //
239 // Issuing URB
240 //
241 usb_fill_int_urb( pUrb, pHwData->WbUsb.udev, usb_rcvintpipe(pHwData->WbUsb.udev,2),
242 pltmp, MAX_INTERRUPT_LENGTH, Wb35Tx_EP2VM_complete, pHwData, 32);
243
244 pWb35Tx->EP2vm_state = VM_RUNNING;
245 retv = wb_usb_submit_urb( pUrb );
246
247 if(retv < 0) {
248 #ifdef _PE_TX_DUMP_
249 WBDEBUG(("EP2 Tx Irp sending error\n"));
250 #endif
251 break;
252 }
253
254 return;
255
256 } while(FALSE);
257
258 pWb35Tx->EP2vm_state = VM_STOP;
259 OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Tx->TxResultCount );
260 }
261
262
263 void Wb35Tx_EP2VM_complete(struct urb * pUrb)
264 {
265 phw_data_t pHwData = pUrb->context;
266 T02_DESCRIPTOR T02, TSTATUS;
267 PADAPTER Adapter = (PADAPTER)pHwData->Adapter;
268 PWB35TX pWb35Tx = &pHwData->Wb35Tx;
269 PULONG pltmp = (PULONG)pWb35Tx->EP2_buf;
270 u32 i;
271 u16 InterruptInLength;
272
273
274 // Variable setting
275 pWb35Tx->EP2vm_state = VM_COMPLETED;
276 pWb35Tx->EP2VM_status = pUrb->status;
277
278 do {
279 // For Linux 2.4. Interrupt will always trigger
280 if( pHwData->SurpriseRemove || pHwData->HwStop ) // Let WbWlanHalt to handle surprise remove
281 break;
282
283 if( pWb35Tx->tx_halt )
284 break;
285
286 //The Urb is completed, check the result
287 if (pWb35Tx->EP2VM_status != 0) {
288 WBDEBUG(("EP2 IoCompleteRoutine return error\n"));
289 pWb35Tx->EP2vm_state= VM_STOP;
290 break; // Exit while(FALSE);
291 }
292
293 // Update the Tx result
294 InterruptInLength = pUrb->actual_length;
295 // Modify for minimum memory access and DWORD alignment.
296 T02.value = cpu_to_le32(pltmp[0]) >> 8; // [31:8] -> [24:0]
297 InterruptInLength -= 1;// 20051221.1.c Modify the follow for more stable
298 InterruptInLength >>= 2; // InterruptInLength/4
299 for (i=1; i<=InterruptInLength; i++) {
300 T02.value |= ((cpu_to_le32(pltmp[i]) & 0xff) << 24);
301
302 TSTATUS.value = T02.value; //20061009 anson's endian
303 Mds_SendComplete( Adapter, &TSTATUS );
304 T02.value = cpu_to_le32(pltmp[i]) >> 8;
305 }
306
307 return;
308 } while(FALSE);
309
310 OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Tx->TxResultCount );
311 pWb35Tx->EP2vm_state = VM_STOP;
312 }
313
This page took 0.042691 seconds and 5 git commands to generate.