]>
Commit | Line | Data |
---|---|---|
66101de1 PM |
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 | //============================================================================ | |
80aba536 | 11 | #include <linux/usb.h> |
5a0e3ad6 | 12 | #include <linux/gfp.h> |
66101de1 | 13 | |
80aba536 | 14 | #include "wb35tx_f.h" |
9ce922fd | 15 | #include "mds_f.h" |
80aba536 | 16 | #include "sysdef.h" |
66101de1 PM |
17 | |
18 | unsigned char | |
8e41b4b6 | 19 | Wb35Tx_get_tx_buffer(struct hw_data * pHwData, u8 **pBuffer) |
66101de1 | 20 | { |
eb62f3ea | 21 | struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx; |
66101de1 PM |
22 | |
23 | *pBuffer = pWb35Tx->TxBuffer[0]; | |
279b6ccc | 24 | return true; |
66101de1 PM |
25 | } |
26 | ||
5c58093e PE |
27 | static void Wb35Tx(struct wbsoft_priv *adapter); |
28 | ||
29 | static void Wb35Tx_complete(struct urb * pUrb) | |
66101de1 | 30 | { |
5c58093e | 31 | struct wbsoft_priv *adapter = pUrb->context; |
8e41b4b6 | 32 | struct hw_data * pHwData = &adapter->sHwData; |
eb62f3ea | 33 | struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx; |
b7caf94f | 34 | struct wb35_mds *pMds = &adapter->Mds; |
66101de1 | 35 | |
5c58093e PE |
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; | |
66101de1 | 43 | |
5c58093e PE |
44 | if (pHwData->SurpriseRemove || pHwData->HwStop) // Let WbWlanHalt to handle surprise remove |
45 | goto error; | |
66101de1 | 46 | |
5c58093e PE |
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) | |
66101de1 | 67 | { |
8e41b4b6 | 68 | struct hw_data * pHwData = &adapter->sHwData; |
eb62f3ea | 69 | struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx; |
8b384e0c | 70 | u8 *pTxBufferAddress; |
b7caf94f | 71 | struct wb35_mds *pMds = &adapter->Mds; |
66101de1 PM |
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 ], | |
42c84bb4 | 95 | Wb35Tx_complete, adapter); |
66101de1 PM |
96 | |
97 | pWb35Tx->EP4vm_state = VM_RUNNING; | |
7c126043 | 98 | retv = usb_submit_urb(pUrb, GFP_ATOMIC); |
66101de1 PM |
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) | |
42c84bb4 | 107 | Wb35Tx_EP2VM_start(adapter); |
66101de1 PM |
108 | |
109 | pWb35Tx->ByteTransfer += pMds->TxBufferSize[SendIndex]; | |
110 | return; | |
111 | ||
112 | cleanup: | |
113 | pWb35Tx->EP4vm_state = VM_STOP; | |
44e8541c | 114 | atomic_dec(&pWb35Tx->TxFireCounter); |
66101de1 PM |
115 | } |
116 | ||
5c58093e | 117 | void Wb35Tx_start(struct wbsoft_priv *adapter) |
66101de1 | 118 | { |
8e41b4b6 | 119 | struct hw_data * pHwData = &adapter->sHwData; |
eb62f3ea | 120 | struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx; |
66101de1 | 121 | |
5c58093e PE |
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); | |
66101de1 PM |
128 | } |
129 | ||
8e41b4b6 | 130 | unsigned char Wb35Tx_initial(struct hw_data * pHwData) |
66101de1 | 131 | { |
eb62f3ea | 132 | struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx; |
66101de1 | 133 | |
f3d20188 | 134 | pWb35Tx->Tx4Urb = usb_alloc_urb(0, GFP_ATOMIC); |
66101de1 | 135 | if (!pWb35Tx->Tx4Urb) |
279b6ccc | 136 | return false; |
66101de1 | 137 | |
f3d20188 | 138 | pWb35Tx->Tx2Urb = usb_alloc_urb(0, GFP_ATOMIC); |
66101de1 PM |
139 | if (!pWb35Tx->Tx2Urb) |
140 | { | |
141 | usb_free_urb( pWb35Tx->Tx4Urb ); | |
279b6ccc | 142 | return false; |
66101de1 PM |
143 | } |
144 | ||
279b6ccc | 145 | return true; |
66101de1 PM |
146 | } |
147 | ||
148 | //====================================================== | |
8e41b4b6 | 149 | void Wb35Tx_stop(struct hw_data * pHwData) |
66101de1 | 150 | { |
eb62f3ea | 151 | struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx; |
66101de1 PM |
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_ | |
0c59dbaa | 157 | printk("EP2 Tx stop\n"); |
66101de1 PM |
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_ | |
0c59dbaa | 164 | printk("EP4 Tx stop\n"); |
66101de1 PM |
165 | #endif |
166 | } | |
167 | ||
168 | //====================================================== | |
8e41b4b6 | 169 | void Wb35Tx_destroy(struct hw_data * pHwData) |
66101de1 | 170 | { |
eb62f3ea | 171 | struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx; |
66101de1 PM |
172 | |
173 | // Wait for VM stop | |
174 | do { | |
34222e0a | 175 | msleep(10); // Delay for waiting function enter 940623.1.a |
66101de1 | 176 | } while( (pWb35Tx->EP2vm_state != VM_STOP) && (pWb35Tx->EP4vm_state != VM_STOP) ); |
34222e0a | 177 | msleep(10); // Delay for waiting function enter 940623.1.b |
66101de1 PM |
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_ | |
0c59dbaa | 186 | printk("Wb35Tx_destroy OK\n"); |
66101de1 PM |
187 | #endif |
188 | } | |
189 | ||
1e8a2b60 | 190 | void Wb35Tx_CurrentTime(struct wbsoft_priv *adapter, u32 TimeCount) |
66101de1 | 191 | { |
8e41b4b6 | 192 | struct hw_data * pHwData = &adapter->sHwData; |
eb62f3ea | 193 | struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx; |
279b6ccc | 194 | unsigned char Trigger = false; |
66101de1 PM |
195 | |
196 | if (pWb35Tx->TxTimer > TimeCount) | |
279b6ccc | 197 | Trigger = true; |
66101de1 | 198 | else if (TimeCount > (pWb35Tx->TxTimer+500)) |
279b6ccc | 199 | Trigger = true; |
66101de1 PM |
200 | |
201 | if (Trigger) { | |
202 | pWb35Tx->TxTimer = TimeCount; | |
42c84bb4 | 203 | Wb35Tx_EP2VM_start(adapter); |
66101de1 PM |
204 | } |
205 | } | |
206 | ||
5c58093e | 207 | static void Wb35Tx_EP2VM(struct wbsoft_priv *adapter); |
66101de1 | 208 | |
5c58093e | 209 | static void Wb35Tx_EP2VM_complete(struct urb * pUrb) |
66101de1 | 210 | { |
1e8a2b60 | 211 | struct wbsoft_priv *adapter = pUrb->context; |
8e41b4b6 | 212 | struct hw_data * pHwData = &adapter->sHwData; |
66101de1 | 213 | T02_DESCRIPTOR T02, TSTATUS; |
eb62f3ea | 214 | struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx; |
8b384e0c | 215 | u32 * pltmp = (u32 *)pWb35Tx->EP2_buf; |
66101de1 PM |
216 | u32 i; |
217 | u16 InterruptInLength; | |
218 | ||
219 | ||
220 | // Variable setting | |
221 | pWb35Tx->EP2vm_state = VM_COMPLETED; | |
222 | pWb35Tx->EP2VM_status = pUrb->status; | |
223 | ||
dc7e04fe PE |
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) { | |
0c59dbaa | 233 | printk("EP2 IoCompleteRoutine return error\n"); |
dc7e04fe PE |
234 | pWb35Tx->EP2vm_state= VM_STOP; |
235 | goto error; | |
236 | } | |
66101de1 | 237 | |
dc7e04fe PE |
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 | |
88ebc4b9 | 248 | Mds_SendComplete( adapter, &TSTATUS ); |
dc7e04fe PE |
249 | T02.value = cpu_to_le32(pltmp[i]) >> 8; |
250 | } | |
251 | ||
252 | return; | |
253 | error: | |
44e8541c | 254 | atomic_dec(&pWb35Tx->TxResultCount); |
66101de1 PM |
255 | pWb35Tx->EP2vm_state = VM_STOP; |
256 | } | |
257 | ||
5c58093e PE |
258 | static void Wb35Tx_EP2VM(struct wbsoft_priv *adapter) |
259 | { | |
8e41b4b6 | 260 | struct hw_data * pHwData = &adapter->sHwData; |
eb62f3ea | 261 | struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx; |
5c58093e PE |
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_ | |
0c59dbaa | 283 | printk("EP2 Tx Irp sending error\n"); |
5c58093e PE |
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 | { | |
8e41b4b6 | 296 | struct hw_data * pHwData = &adapter->sHwData; |
eb62f3ea | 297 | struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx; |
5c58093e PE |
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 | } |