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