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