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
Wb35Tx_get_tx_buffer(phw_data_t pHwData,u8 ** pBuffer)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
Wb35Tx_complete(struct urb * pUrb)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
Wb35Tx(struct wbsoft_priv * adapter)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
Wb35Tx_start(struct wbsoft_priv * adapter)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
Wb35Tx_initial(phw_data_t pHwData)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 //======================================================
Wb35Tx_stop(phw_data_t pHwData)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 //======================================================
Wb35Tx_destroy(phw_data_t pHwData)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
Wb35Tx_CurrentTime(struct wbsoft_priv * adapter,u32 TimeCount)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
Wb35Tx_EP2VM_complete(struct urb * pUrb)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
Wb35Tx_EP2VM(struct wbsoft_priv * adapter)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
Wb35Tx_EP2VM_start(struct wbsoft_priv * adapter)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 }
306