]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/staging/winbond/linux/wb35tx.c
dock: make dock driver not a module
[linux-2.6-omap-h63xx.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