1 //============================================================================
2 // Copyright (c) 1996-2002 Winbond Electronic Corporation
8 // Processing the Tx message and put into down layer
10 //============================================================================
15 Wb35Tx_get_tx_buffer(phw_data_t pHwData, u8 **pBuffer)
17 PWB35TX pWb35Tx = &pHwData->Wb35Tx;
19 *pBuffer = pWb35Tx->TxBuffer[0];
23 void Wb35Tx_start(phw_data_t pHwData)
25 PWB35TX pWb35Tx = &pHwData->Wb35Tx;
27 // Allow only one thread to run into function
28 if (OS_ATOMIC_INC(pHwData->Adapter, &pWb35Tx->TxFireCounter) == 1) {
29 pWb35Tx->EP4vm_state = VM_RUNNING;
32 OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Tx->TxFireCounter );
36 void Wb35Tx(phw_data_t pHwData)
38 PWB35TX pWb35Tx = &pHwData->Wb35Tx;
39 PADAPTER Adapter = pHwData->Adapter;
41 PMDS pMds = &Adapter->Mds;
42 struct urb * pUrb = (struct urb *)pWb35Tx->Tx4Urb;
47 if (pHwData->SurpriseRemove || pHwData->HwStop)
54 SendIndex = pWb35Tx->TxSendIndex;
55 if (!pMds->TxOwner[SendIndex]) //No more data need to be sent, return immediately
58 pTxBufferAddress = pWb35Tx->TxBuffer[SendIndex];
62 usb_fill_bulk_urb(pUrb, pHwData->WbUsb.udev,
63 usb_sndbulkpipe(pHwData->WbUsb.udev, 4),
64 pTxBufferAddress, pMds->TxBufferSize[ SendIndex ],
65 Wb35Tx_complete, pHwData);
67 pWb35Tx->EP4vm_state = VM_RUNNING;
68 retv = wb_usb_submit_urb( pUrb );
70 printk("EP4 Tx Irp sending error\n");
74 // Check if driver needs issue Irp for EP2
75 pWb35Tx->TxFillCount += pMds->TxCountInBuffer[SendIndex];
76 if (pWb35Tx->TxFillCount > 12)
77 Wb35Tx_EP2VM_start( pHwData );
79 pWb35Tx->ByteTransfer += pMds->TxBufferSize[SendIndex];
83 pWb35Tx->EP4vm_state = VM_STOP;
84 OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Tx->TxFireCounter );
88 void Wb35Tx_complete(struct urb * pUrb)
90 phw_data_t pHwData = pUrb->context;
91 PADAPTER Adapter = (PADAPTER)pHwData->Adapter;
92 PWB35TX pWb35Tx = &pHwData->Wb35Tx;
93 PMDS pMds = &Adapter->Mds;
95 printk("wb35: tx complete\n");
97 pWb35Tx->EP4vm_state = VM_COMPLETED;
98 pWb35Tx->EP4VM_status = pUrb->status; //Store the last result of Irp
99 pMds->TxOwner[ pWb35Tx->TxSendIndex ] = 0;// Set the owner. Free the owner bit always.
100 pWb35Tx->TxSendIndex++;
101 pWb35Tx->TxSendIndex %= MAX_USB_TX_BUFFER_NUMBER;
103 if (pHwData->SurpriseRemove || pHwData->HwStop) // Let WbWlanHalt to handle surprise remove
106 if (pWb35Tx->tx_halt)
109 // The URB is completed, check the result
110 if (pWb35Tx->EP4VM_status != 0) {
111 printk("URB submission failed\n");
112 pWb35Tx->EP4vm_state = VM_STOP;
121 OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Tx->TxFireCounter );
122 pWb35Tx->EP4vm_state = VM_STOP;
125 void Wb35Tx_reset_descriptor( phw_data_t pHwData )
127 PWB35TX pWb35Tx = &pHwData->Wb35Tx;
129 pWb35Tx->TxSendIndex = 0;
130 pWb35Tx->tx_halt = 0;
133 unsigned char Wb35Tx_initial(phw_data_t pHwData)
135 PWB35TX pWb35Tx = &pHwData->Wb35Tx;
137 pWb35Tx->Tx4Urb = wb_usb_alloc_urb(0);
138 if (!pWb35Tx->Tx4Urb)
141 pWb35Tx->Tx2Urb = wb_usb_alloc_urb(0);
142 if (!pWb35Tx->Tx2Urb)
144 usb_free_urb( pWb35Tx->Tx4Urb );
151 //======================================================
152 void Wb35Tx_stop(phw_data_t pHwData)
154 PWB35TX pWb35Tx = &pHwData->Wb35Tx;
156 // Trying to canceling the Trp of EP2
157 if (pWb35Tx->EP2vm_state == VM_RUNNING)
158 usb_unlink_urb( pWb35Tx->Tx2Urb ); // Only use unlink, let Wb35Tx_destrot to free them
160 WBDEBUG(("EP2 Tx stop\n"));
163 // Trying to canceling the Irp of EP4
164 if (pWb35Tx->EP4vm_state == VM_RUNNING)
165 usb_unlink_urb( pWb35Tx->Tx4Urb ); // Only use unlink, let Wb35Tx_destrot to free them
167 WBDEBUG(("EP4 Tx stop\n"));
171 //======================================================
172 void Wb35Tx_destroy(phw_data_t pHwData)
174 PWB35TX pWb35Tx = &pHwData->Wb35Tx;
178 OS_SLEEP(10000); // Delay for waiting function enter 940623.1.a
179 } while( (pWb35Tx->EP2vm_state != VM_STOP) && (pWb35Tx->EP4vm_state != VM_STOP) );
180 OS_SLEEP(10000); // Delay for waiting function enter 940623.1.b
183 usb_free_urb( pWb35Tx->Tx4Urb );
186 usb_free_urb( pWb35Tx->Tx2Urb );
189 WBDEBUG(("Wb35Tx_destroy OK\n"));
193 void Wb35Tx_CurrentTime(phw_data_t pHwData, u32 TimeCount)
195 PWB35TX pWb35Tx = &pHwData->Wb35Tx;
196 unsigned char Trigger = FALSE;
198 if (pWb35Tx->TxTimer > TimeCount)
200 else if (TimeCount > (pWb35Tx->TxTimer+500))
204 pWb35Tx->TxTimer = TimeCount;
205 Wb35Tx_EP2VM_start( pHwData );
209 void Wb35Tx_EP2VM_start(phw_data_t pHwData)
211 PWB35TX pWb35Tx = &pHwData->Wb35Tx;
213 // Allow only one thread to run into function
214 if (OS_ATOMIC_INC( pHwData->Adapter, &pWb35Tx->TxResultCount ) == 1) {
215 pWb35Tx->EP2vm_state = VM_RUNNING;
216 Wb35Tx_EP2VM( pHwData );
219 OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Tx->TxResultCount );
223 void Wb35Tx_EP2VM(phw_data_t pHwData)
225 PWB35TX pWb35Tx = &pHwData->Wb35Tx;
226 struct urb * pUrb = (struct urb *)pWb35Tx->Tx2Urb;
227 u32 * pltmp = (u32 *)pWb35Tx->EP2_buf;
230 if (pHwData->SurpriseRemove || pHwData->HwStop)
233 if (pWb35Tx->tx_halt)
239 usb_fill_int_urb( pUrb, pHwData->WbUsb.udev, usb_rcvintpipe(pHwData->WbUsb.udev,2),
240 pltmp, MAX_INTERRUPT_LENGTH, Wb35Tx_EP2VM_complete, pHwData, 32);
242 pWb35Tx->EP2vm_state = VM_RUNNING;
243 retv = wb_usb_submit_urb( pUrb );
247 WBDEBUG(("EP2 Tx Irp sending error\n"));
254 pWb35Tx->EP2vm_state = VM_STOP;
255 OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Tx->TxResultCount );
259 void Wb35Tx_EP2VM_complete(struct urb * pUrb)
261 phw_data_t pHwData = pUrb->context;
262 T02_DESCRIPTOR T02, TSTATUS;
263 PADAPTER Adapter = (PADAPTER)pHwData->Adapter;
264 PWB35TX pWb35Tx = &pHwData->Wb35Tx;
265 u32 * pltmp = (u32 *)pWb35Tx->EP2_buf;
267 u16 InterruptInLength;
271 pWb35Tx->EP2vm_state = VM_COMPLETED;
272 pWb35Tx->EP2VM_status = pUrb->status;
274 // For Linux 2.4. Interrupt will always trigger
275 if (pHwData->SurpriseRemove || pHwData->HwStop) // Let WbWlanHalt to handle surprise remove
278 if (pWb35Tx->tx_halt)
281 //The Urb is completed, check the result
282 if (pWb35Tx->EP2VM_status != 0) {
283 WBDEBUG(("EP2 IoCompleteRoutine return error\n"));
284 pWb35Tx->EP2vm_state= VM_STOP;
288 // Update the Tx result
289 InterruptInLength = pUrb->actual_length;
290 // Modify for minimum memory access and DWORD alignment.
291 T02.value = cpu_to_le32(pltmp[0]) >> 8; // [31:8] -> [24:0]
292 InterruptInLength -= 1;// 20051221.1.c Modify the follow for more stable
293 InterruptInLength >>= 2; // InterruptInLength/4
294 for (i = 1; i <= InterruptInLength; i++) {
295 T02.value |= ((cpu_to_le32(pltmp[i]) & 0xff) << 24);
297 TSTATUS.value = T02.value; //20061009 anson's endian
298 Mds_SendComplete( Adapter, &TSTATUS );
299 T02.value = cpu_to_le32(pltmp[i]) >> 8;
304 OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Tx->TxResultCount );
305 pWb35Tx->EP2vm_state = VM_STOP;