1 //============================================================================
2 // Copyright (c) 1996-2002 Winbond Electronic Corporation
8 // Processing the Tx message and put into down layer
10 //============================================================================
11 #include <linux/usb.h>
18 Wb35Tx_get_tx_buffer(phw_data_t pHwData, u8 **pBuffer)
20 PWB35TX pWb35Tx = &pHwData->Wb35Tx;
22 *pBuffer = pWb35Tx->TxBuffer[0];
26 void Wb35Tx_start(phw_data_t pHwData)
28 PWB35TX pWb35Tx = &pHwData->Wb35Tx;
30 // Allow only one thread to run into function
31 if (atomic_inc_return(&pWb35Tx->TxFireCounter) == 1) {
32 pWb35Tx->EP4vm_state = VM_RUNNING;
35 atomic_dec(&pWb35Tx->TxFireCounter);
39 void Wb35Tx(phw_data_t pHwData)
41 PWB35TX pWb35Tx = &pHwData->Wb35Tx;
42 struct wb35_adapter *adapter = pHwData->adapter;
44 PMDS pMds = &adapter->Mds;
45 struct urb * pUrb = (struct urb *)pWb35Tx->Tx4Urb;
50 if (pHwData->SurpriseRemove || pHwData->HwStop)
57 SendIndex = pWb35Tx->TxSendIndex;
58 if (!pMds->TxOwner[SendIndex]) //No more data need to be sent, return immediately
61 pTxBufferAddress = pWb35Tx->TxBuffer[SendIndex];
65 usb_fill_bulk_urb(pUrb, pHwData->WbUsb.udev,
66 usb_sndbulkpipe(pHwData->WbUsb.udev, 4),
67 pTxBufferAddress, pMds->TxBufferSize[ SendIndex ],
68 Wb35Tx_complete, pHwData);
70 pWb35Tx->EP4vm_state = VM_RUNNING;
71 retv = usb_submit_urb(pUrb, GFP_ATOMIC);
73 printk("EP4 Tx Irp sending error\n");
77 // Check if driver needs issue Irp for EP2
78 pWb35Tx->TxFillCount += pMds->TxCountInBuffer[SendIndex];
79 if (pWb35Tx->TxFillCount > 12)
80 Wb35Tx_EP2VM_start( pHwData );
82 pWb35Tx->ByteTransfer += pMds->TxBufferSize[SendIndex];
86 pWb35Tx->EP4vm_state = VM_STOP;
87 atomic_dec(&pWb35Tx->TxFireCounter);
91 void Wb35Tx_complete(struct urb * pUrb)
93 phw_data_t pHwData = pUrb->context;
94 struct wb35_adapter *adapter = pHwData->adapter;
95 PWB35TX pWb35Tx = &pHwData->Wb35Tx;
96 PMDS pMds = &adapter->Mds;
98 printk("wb35: tx complete\n");
100 pWb35Tx->EP4vm_state = VM_COMPLETED;
101 pWb35Tx->EP4VM_status = pUrb->status; //Store the last result of Irp
102 pMds->TxOwner[ pWb35Tx->TxSendIndex ] = 0;// Set the owner. Free the owner bit always.
103 pWb35Tx->TxSendIndex++;
104 pWb35Tx->TxSendIndex %= MAX_USB_TX_BUFFER_NUMBER;
106 if (pHwData->SurpriseRemove || pHwData->HwStop) // Let WbWlanHalt to handle surprise remove
109 if (pWb35Tx->tx_halt)
112 // The URB is completed, check the result
113 if (pWb35Tx->EP4VM_status != 0) {
114 printk("URB submission failed\n");
115 pWb35Tx->EP4vm_state = VM_STOP;
124 atomic_dec(&pWb35Tx->TxFireCounter);
125 pWb35Tx->EP4vm_state = VM_STOP;
128 void Wb35Tx_reset_descriptor( phw_data_t pHwData )
130 PWB35TX pWb35Tx = &pHwData->Wb35Tx;
132 pWb35Tx->TxSendIndex = 0;
133 pWb35Tx->tx_halt = 0;
136 unsigned char Wb35Tx_initial(phw_data_t pHwData)
138 PWB35TX pWb35Tx = &pHwData->Wb35Tx;
140 pWb35Tx->Tx4Urb = usb_alloc_urb(0, GFP_ATOMIC);
141 if (!pWb35Tx->Tx4Urb)
144 pWb35Tx->Tx2Urb = usb_alloc_urb(0, GFP_ATOMIC);
145 if (!pWb35Tx->Tx2Urb)
147 usb_free_urb( pWb35Tx->Tx4Urb );
154 //======================================================
155 void Wb35Tx_stop(phw_data_t pHwData)
157 PWB35TX pWb35Tx = &pHwData->Wb35Tx;
159 // Trying to canceling the Trp of EP2
160 if (pWb35Tx->EP2vm_state == VM_RUNNING)
161 usb_unlink_urb( pWb35Tx->Tx2Urb ); // Only use unlink, let Wb35Tx_destrot to free them
163 WBDEBUG(("EP2 Tx stop\n"));
166 // Trying to canceling the Irp of EP4
167 if (pWb35Tx->EP4vm_state == VM_RUNNING)
168 usb_unlink_urb( pWb35Tx->Tx4Urb ); // Only use unlink, let Wb35Tx_destrot to free them
170 WBDEBUG(("EP4 Tx stop\n"));
174 //======================================================
175 void Wb35Tx_destroy(phw_data_t pHwData)
177 PWB35TX pWb35Tx = &pHwData->Wb35Tx;
181 msleep(10); // Delay for waiting function enter 940623.1.a
182 } while( (pWb35Tx->EP2vm_state != VM_STOP) && (pWb35Tx->EP4vm_state != VM_STOP) );
183 msleep(10); // Delay for waiting function enter 940623.1.b
186 usb_free_urb( pWb35Tx->Tx4Urb );
189 usb_free_urb( pWb35Tx->Tx2Urb );
192 WBDEBUG(("Wb35Tx_destroy OK\n"));
196 void Wb35Tx_CurrentTime(phw_data_t pHwData, u32 TimeCount)
198 PWB35TX pWb35Tx = &pHwData->Wb35Tx;
199 unsigned char Trigger = false;
201 if (pWb35Tx->TxTimer > TimeCount)
203 else if (TimeCount > (pWb35Tx->TxTimer+500))
207 pWb35Tx->TxTimer = TimeCount;
208 Wb35Tx_EP2VM_start( pHwData );
212 void Wb35Tx_EP2VM_start(phw_data_t pHwData)
214 PWB35TX pWb35Tx = &pHwData->Wb35Tx;
216 // Allow only one thread to run into function
217 if (atomic_inc_return(&pWb35Tx->TxResultCount) == 1) {
218 pWb35Tx->EP2vm_state = VM_RUNNING;
219 Wb35Tx_EP2VM( pHwData );
222 atomic_dec(&pWb35Tx->TxResultCount);
226 void Wb35Tx_EP2VM(phw_data_t pHwData)
228 PWB35TX pWb35Tx = &pHwData->Wb35Tx;
229 struct urb * pUrb = (struct urb *)pWb35Tx->Tx2Urb;
230 u32 * pltmp = (u32 *)pWb35Tx->EP2_buf;
233 if (pHwData->SurpriseRemove || pHwData->HwStop)
236 if (pWb35Tx->tx_halt)
242 usb_fill_int_urb( pUrb, pHwData->WbUsb.udev, usb_rcvintpipe(pHwData->WbUsb.udev,2),
243 pltmp, MAX_INTERRUPT_LENGTH, Wb35Tx_EP2VM_complete, pHwData, 32);
245 pWb35Tx->EP2vm_state = VM_RUNNING;
246 retv = usb_submit_urb(pUrb, GFP_ATOMIC);
250 WBDEBUG(("EP2 Tx Irp sending error\n"));
257 pWb35Tx->EP2vm_state = VM_STOP;
258 atomic_dec(&pWb35Tx->TxResultCount);
262 void Wb35Tx_EP2VM_complete(struct urb * pUrb)
264 phw_data_t pHwData = pUrb->context;
265 T02_DESCRIPTOR T02, TSTATUS;
266 struct wb35_adapter *adapter = pHwData->adapter;
267 PWB35TX pWb35Tx = &pHwData->Wb35Tx;
268 u32 * pltmp = (u32 *)pWb35Tx->EP2_buf;
270 u16 InterruptInLength;
274 pWb35Tx->EP2vm_state = VM_COMPLETED;
275 pWb35Tx->EP2VM_status = pUrb->status;
277 // For Linux 2.4. Interrupt will always trigger
278 if (pHwData->SurpriseRemove || pHwData->HwStop) // Let WbWlanHalt to handle surprise remove
281 if (pWb35Tx->tx_halt)
284 //The Urb is completed, check the result
285 if (pWb35Tx->EP2VM_status != 0) {
286 WBDEBUG(("EP2 IoCompleteRoutine return error\n"));
287 pWb35Tx->EP2vm_state= VM_STOP;
291 // Update the Tx result
292 InterruptInLength = pUrb->actual_length;
293 // Modify for minimum memory access and DWORD alignment.
294 T02.value = cpu_to_le32(pltmp[0]) >> 8; // [31:8] -> [24:0]
295 InterruptInLength -= 1;// 20051221.1.c Modify the follow for more stable
296 InterruptInLength >>= 2; // InterruptInLength/4
297 for (i = 1; i <= InterruptInLength; i++) {
298 T02.value |= ((cpu_to_le32(pltmp[i]) & 0xff) << 24);
300 TSTATUS.value = T02.value; //20061009 anson's endian
301 Mds_SendComplete( adapter, &TSTATUS );
302 T02.value = cpu_to_le32(pltmp[i]) >> 8;
307 atomic_dec(&pWb35Tx->TxResultCount);
308 pWb35Tx->EP2vm_state = VM_STOP;