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