2 *************************************************************************
4 * 5F., No.36, Taiyuan St., Jhubei City,
8 * (c) Copyright 2002-2007, Ralink Technology, Inc.
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
15 * This program is distributed in the hope that it will be useful, *
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
18 * GNU General Public License for more details. *
20 * You should have received a copy of the GNU General Public License *
21 * along with this program; if not, write to the *
22 * Free Software Foundation, Inc., *
23 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
25 *************************************************************************
34 -------- ---------- ----------------------------------------------
35 Name Date Modification logs
36 Paul Lin 06-25-2004 created
42 #include "../rt_config.h"
43 /* Match total 6 bulkout endpoint to corresponding queue. */
45 { FIFO_EDCA, FIFO_EDCA, FIFO_EDCA, FIFO_EDCA, FIFO_EDCA, FIFO_MGMT };
47 /*static BOOLEAN SingleBulkOut = FALSE; */
49 void RTUSB_FILL_BULK_URB(struct urb *pUrb,
50 struct usb_device *pUsb_Dev,
51 unsigned int bulkpipe,
53 int BufSize, usb_complete_t Complete, void *pContext)
56 usb_fill_bulk_urb(pUrb, pUsb_Dev, bulkpipe, pTransferBuf, BufSize,
57 (usb_complete_t) Complete, pContext);
61 void RTUSBInitTxDesc(struct rt_rtmp_adapter *pAd,
62 struct rt_tx_context *pTxContext,
63 u8 BulkOutPipeId, IN usb_complete_t Func)
67 struct os_cookie *pObj = (struct os_cookie *)pAd->OS_Cookie;
69 pUrb = pTxContext->pUrb;
72 /* Store BulkOut PipeId */
73 pTxContext->BulkOutPipeId = BulkOutPipeId;
75 if (pTxContext->bAggregatible) {
76 pSrc = &pTxContext->TransferBuffer->Aggregation[2];
79 (u8 *)pTxContext->TransferBuffer->field.WirelessPacket;
82 /*Initialize a tx bulk urb */
83 RTUSB_FILL_BULK_URB(pUrb,
85 usb_sndbulkpipe(pObj->pUsb_Dev,
86 pAd->BulkOutEpAddr[BulkOutPipeId]),
87 pSrc, pTxContext->BulkOutSize, Func, pTxContext);
89 if (pTxContext->bAggregatible)
91 (pTxContext->data_dma + TX_BUFFER_NORMSIZE + 2);
93 pUrb->transfer_dma = pTxContext->data_dma;
95 pUrb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
99 void RTUSBInitHTTxDesc(struct rt_rtmp_adapter *pAd,
100 struct rt_ht_tx_context *pTxContext,
102 unsigned long BulkOutSize, IN usb_complete_t Func)
106 struct os_cookie *pObj = (struct os_cookie *)pAd->OS_Cookie;
108 pUrb = pTxContext->pUrb;
111 /* Store BulkOut PipeId */
112 pTxContext->BulkOutPipeId = BulkOutPipeId;
115 &pTxContext->TransferBuffer->field.WirelessPacket[pTxContext->
116 NextBulkOutPosition];
118 /*Initialize a tx bulk urb */
119 RTUSB_FILL_BULK_URB(pUrb,
121 usb_sndbulkpipe(pObj->pUsb_Dev,
122 pAd->BulkOutEpAddr[BulkOutPipeId]),
123 pSrc, BulkOutSize, Func, pTxContext);
126 (pTxContext->data_dma + pTxContext->NextBulkOutPosition);
127 pUrb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
131 void RTUSBInitRxDesc(struct rt_rtmp_adapter *pAd, struct rt_rx_context *pRxContext)
134 struct os_cookie *pObj = (struct os_cookie *)pAd->OS_Cookie;
135 unsigned long RX_bulk_size;
137 pUrb = pRxContext->pUrb;
140 if (pAd->BulkInMaxPacketSize == 64)
143 RX_bulk_size = MAX_RXBULK_SIZE;
145 /*Initialize a rx bulk urb */
146 RTUSB_FILL_BULK_URB(pUrb,
148 usb_rcvbulkpipe(pObj->pUsb_Dev, pAd->BulkInEpAddr),
150 TransferBuffer[pAd->NextRxBulkInPosition]),
151 RX_bulk_size - (pAd->NextRxBulkInPosition),
152 (usb_complete_t) RTUSBBulkRxComplete,
155 pUrb->transfer_dma = pRxContext->data_dma + pAd->NextRxBulkInPosition;
156 pUrb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
161 ========================================================================
171 ========================================================================
174 #define BULK_OUT_LOCK(pLock, IrqFlags) \
175 if(1 /*!(in_interrupt() & 0xffff0000)*/) \
176 RTMP_IRQ_LOCK((pLock), IrqFlags);
178 #define BULK_OUT_UNLOCK(pLock, IrqFlags) \
179 if(1 /*!(in_interrupt() & 0xffff0000)*/) \
180 RTMP_IRQ_UNLOCK((pLock), IrqFlags);
182 void RTUSBBulkOutDataPacket(struct rt_rtmp_adapter *pAd,
183 u8 BulkOutPipeId, u8 Index)
186 struct rt_ht_tx_context *pHTTXContext;
189 struct rt_txinfo *pTxInfo, *pLastTxInfo = NULL;
190 struct rt_txwi * pTxWI;
191 unsigned long TmpBulkEndPos, ThisBulkSize;
192 unsigned long IrqFlags = 0, IrqFlags2 = 0;
193 u8 *pWirelessPkt, *pAppendant;
194 BOOLEAN bTxQLastRound = FALSE;
195 u8 allzero[4] = { 0x0, 0x0, 0x0, 0x0 };
197 BULK_OUT_LOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags);
198 if ((pAd->BulkOutPending[BulkOutPipeId] == TRUE)
199 || RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NEED_STOP_TX)) {
200 BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags);
203 pAd->BulkOutPending[BulkOutPipeId] = TRUE;
205 if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)
207 pAd->BulkOutPending[BulkOutPipeId] = FALSE;
208 BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags);
211 BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags);
213 pHTTXContext = &(pAd->TxContext[BulkOutPipeId]);
215 BULK_OUT_LOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags2);
216 if ((pHTTXContext->ENextBulkOutPosition ==
217 pHTTXContext->CurWritePosition)
218 || ((pHTTXContext->ENextBulkOutPosition - 8) ==
219 pHTTXContext->CurWritePosition)) {
220 BULK_OUT_UNLOCK(&pAd->TxContextQueueLock[BulkOutPipeId],
223 BULK_OUT_LOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags);
224 pAd->BulkOutPending[BulkOutPipeId] = FALSE;
226 /* Clear Data flag */
227 RTUSB_CLEAR_BULK_FLAG(pAd,
228 (fRTUSB_BULK_OUT_DATA_FRAG <<
230 RTUSB_CLEAR_BULK_FLAG(pAd,
231 (fRTUSB_BULK_OUT_DATA_NORMAL <<
234 BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags);
237 /* Clear Data flag */
238 RTUSB_CLEAR_BULK_FLAG(pAd,
239 (fRTUSB_BULK_OUT_DATA_FRAG << BulkOutPipeId));
240 RTUSB_CLEAR_BULK_FLAG(pAd,
241 (fRTUSB_BULK_OUT_DATA_NORMAL << BulkOutPipeId));
243 /*DBGPRINT(RT_DEBUG_TRACE,("BulkOut-B:I=0x%lx, CWPos=%ld, CWRPos=%ld, NBPos=%ld, ENBPos=%ld, bCopy=%d!\n", in_interrupt(), */
244 /* pHTTXContext->CurWritePosition, pHTTXContext->CurWriteRealPos, pHTTXContext->NextBulkOutPosition, */
245 /* pHTTXContext->ENextBulkOutPosition, pHTTXContext->bCopySavePad)); */
246 pHTTXContext->NextBulkOutPosition = pHTTXContext->ENextBulkOutPosition;
248 TmpBulkEndPos = pHTTXContext->NextBulkOutPosition;
249 pWirelessPkt = &pHTTXContext->TransferBuffer->field.WirelessPacket[0];
251 if ((pHTTXContext->bCopySavePad == TRUE)) {
252 if (RTMPEqualMemory(pHTTXContext->SavedPad, allzero, 4)) {
253 DBGPRINT_RAW(RT_DEBUG_ERROR,
254 ("e1, allzero : %x %x %x %x %x %x %x %x \n",
255 pHTTXContext->SavedPad[0],
256 pHTTXContext->SavedPad[1],
257 pHTTXContext->SavedPad[2],
258 pHTTXContext->SavedPad[3]
259 , pHTTXContext->SavedPad[4],
260 pHTTXContext->SavedPad[5],
261 pHTTXContext->SavedPad[6],
262 pHTTXContext->SavedPad[7]));
264 NdisMoveMemory(&pWirelessPkt[TmpBulkEndPos],
265 pHTTXContext->SavedPad, 8);
266 pHTTXContext->bCopySavePad = FALSE;
267 if (pAd->bForcePrintTX == TRUE)
268 DBGPRINT(RT_DEBUG_TRACE,
269 ("RTUSBBulkOutDataPacket --> COPY PAD. CurWrite = %ld, NextBulk = %ld. ENextBulk = %ld.\n",
270 pHTTXContext->CurWritePosition,
271 pHTTXContext->NextBulkOutPosition,
272 pHTTXContext->ENextBulkOutPosition));
276 pTxInfo = (struct rt_txinfo *)& pWirelessPkt[TmpBulkEndPos];
278 (struct rt_txwi *) & pWirelessPkt[TmpBulkEndPos + TXINFO_SIZE];
280 if (pAd->bForcePrintTX == TRUE)
281 DBGPRINT(RT_DEBUG_TRACE,
282 ("RTUSBBulkOutDataPacket AMPDU = %d.\n",
285 /* add by Iverson, limit BulkOut size to 4k to pass WMM b mode 2T1R test items */
286 /*if ((ThisBulkSize != 0) && (pTxWI->AMPDU == 0)) */
287 if ((ThisBulkSize != 0) && (pTxWI->PHYMODE == MODE_CCK)) {
288 if (((ThisBulkSize & 0xffff8000) != 0)
289 || ((ThisBulkSize & 0x1000) == 0x1000)) {
290 /* Limit BulkOut size to about 4k bytes. */
291 pHTTXContext->ENextBulkOutPosition =
295 if (((pAd->BulkOutMaxPacketSize < 512)
296 && ((ThisBulkSize & 0xfffff800) !=
298 /*|| ( (ThisBulkSize != 0) && (pTxWI->AMPDU == 0)) */
300 /* For USB 1.1 or peer which didn't support AMPDU, limit the BulkOut size. */
301 /* For performence in b/g mode, now just check for USB 1.1 and didn't care about the APMDU or not! 2008/06/04. */
302 pHTTXContext->ENextBulkOutPosition =
309 if (((ThisBulkSize & 0xffff8000) != 0) || ((ThisBulkSize & 0x6000) == 0x6000)) { /* Limit BulkOut size to about 24k bytes. */
310 pHTTXContext->ENextBulkOutPosition =
313 } else if (((pAd->BulkOutMaxPacketSize < 512) && ((ThisBulkSize & 0xfffff800) != 0)) /*|| ( (ThisBulkSize != 0) && (pTxWI->AMPDU == 0)) */ ) { /* For USB 1.1 or peer which didn't support AMPDU, limit the BulkOut size. */
314 /* For performence in b/g mode, now just check for USB 1.1 and didn't care about the APMDU or not! 2008/06/04. */
315 pHTTXContext->ENextBulkOutPosition =
321 if (TmpBulkEndPos == pHTTXContext->CurWritePosition) {
322 pHTTXContext->ENextBulkOutPosition = TmpBulkEndPos;
326 if (pTxInfo->QSEL != FIFO_EDCA) {
327 DBGPRINT(RT_DEBUG_ERROR,
328 ("%s(): ====> pTxInfo->QueueSel(%d)!= FIFO_EDCA!!!!\n",
329 __FUNCTION__, pTxInfo->QSEL));
330 DBGPRINT(RT_DEBUG_ERROR,
331 ("\tCWPos=%ld, NBPos=%ld, ENBPos=%ld, bCopy=%d!\n",
332 pHTTXContext->CurWritePosition,
333 pHTTXContext->NextBulkOutPosition,
334 pHTTXContext->ENextBulkOutPosition,
335 pHTTXContext->bCopySavePad));
336 hex_dump("Wrong QSel Pkt:",
337 (u8 *)& pWirelessPkt[TmpBulkEndPos],
338 (pHTTXContext->CurWritePosition -
339 pHTTXContext->NextBulkOutPosition));
342 if (pTxInfo->USBDMATxPktLen <= 8) {
343 BULK_OUT_UNLOCK(&pAd->TxContextQueueLock[BulkOutPipeId],
345 DBGPRINT(RT_DEBUG_ERROR /*RT_DEBUG_TRACE */ ,
346 ("e2, USBDMATxPktLen==0, Size=%ld, bCSPad=%d, CWPos=%ld, NBPos=%ld, CWRPos=%ld!\n",
347 pHTTXContext->BulkOutSize,
348 pHTTXContext->bCopySavePad,
349 pHTTXContext->CurWritePosition,
350 pHTTXContext->NextBulkOutPosition,
351 pHTTXContext->CurWriteRealPos));
353 DBGPRINT_RAW(RT_DEBUG_ERROR /*RT_DEBUG_TRACE */
355 ("%x %x %x %x %x %x %x %x \n",
356 pHTTXContext->SavedPad[0],
357 pHTTXContext->SavedPad[1],
358 pHTTXContext->SavedPad[2],
359 pHTTXContext->SavedPad[3]
360 , pHTTXContext->SavedPad[4],
361 pHTTXContext->SavedPad[5],
362 pHTTXContext->SavedPad[6],
363 pHTTXContext->SavedPad[7]));
365 pAd->bForcePrintTX = TRUE;
366 BULK_OUT_LOCK(&pAd->BulkOutLock[BulkOutPipeId],
368 pAd->BulkOutPending[BulkOutPipeId] = FALSE;
369 BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId],
371 /*DBGPRINT(RT_DEBUG_LOUD,("Out:pTxInfo->USBDMATxPktLen=%d!\n", pTxInfo->USBDMATxPktLen)); */
374 /* Increase Total transmit byte counter */
375 pAd->RalinkCounters.OneSecTransmittedByteCount +=
376 pTxWI->MPDUtotalByteCount;
377 pAd->RalinkCounters.TransmittedByteCount +=
378 pTxWI->MPDUtotalByteCount;
380 pLastTxInfo = pTxInfo;
382 /* Make sure we use EDCA QUEUE. */
383 pTxInfo->QSEL = FIFO_EDCA;
384 ThisBulkSize += (pTxInfo->USBDMATxPktLen + 4);
385 TmpBulkEndPos += (pTxInfo->USBDMATxPktLen + 4);
387 if (TmpBulkEndPos != pHTTXContext->CurWritePosition)
388 pTxInfo->USBDMANextVLD = 1;
390 if (pTxInfo->SwUseLastRound == 1) {
391 if (pHTTXContext->CurWritePosition == 8)
392 pTxInfo->USBDMANextVLD = 0;
393 pTxInfo->SwUseLastRound = 0;
395 bTxQLastRound = TRUE;
396 pHTTXContext->ENextBulkOutPosition = 8;
403 /* adjust the pTxInfo->USBDMANextVLD value of last pTxInfo. */
405 pLastTxInfo->USBDMANextVLD = 0;
409 We need to copy SavedPad when following condition matched!
410 1. Not the last round of the TxQueue and
411 2. any match of following cases:
412 (1). The End Position of this bulk out is reach to the Currenct Write position and
413 the TxInfo and related header already write to the CurWritePosition.
414 =>(ENextBulkOutPosition == CurWritePosition) && (CurWriteRealPos > CurWritePosition)
416 (2). The EndPosition of the bulk out is not reach to the Current Write Position.
417 =>(ENextBulkOutPosition != CurWritePosition)
419 if ((bTxQLastRound == FALSE) &&
420 (((pHTTXContext->ENextBulkOutPosition ==
421 pHTTXContext->CurWritePosition)
422 && (pHTTXContext->CurWriteRealPos >
423 pHTTXContext->CurWritePosition))
424 || (pHTTXContext->ENextBulkOutPosition !=
425 pHTTXContext->CurWritePosition))
427 NdisMoveMemory(pHTTXContext->SavedPad,
428 &pWirelessPkt[pHTTXContext->
429 ENextBulkOutPosition], 8);
430 pHTTXContext->bCopySavePad = TRUE;
431 if (RTMPEqualMemory(pHTTXContext->SavedPad, allzero, 4)) {
432 u8 *pBuf = &pHTTXContext->SavedPad[0];
433 DBGPRINT_RAW(RT_DEBUG_ERROR,
434 ("WARNING-Zero-3:%02x%02x%02x%02x%02x%02x%02x%02x,CWPos=%ld, CWRPos=%ld, bCW=%d, NBPos=%ld, TBPos=%ld, TBSize=%ld\n",
435 pBuf[0], pBuf[1], pBuf[2], pBuf[3],
436 pBuf[4], pBuf[5], pBuf[6], pBuf[7],
437 pHTTXContext->CurWritePosition,
438 pHTTXContext->CurWriteRealPos,
439 pHTTXContext->bCurWriting,
440 pHTTXContext->NextBulkOutPosition,
441 TmpBulkEndPos, ThisBulkSize));
443 pBuf = &pWirelessPkt[pHTTXContext->CurWritePosition];
444 DBGPRINT_RAW(RT_DEBUG_ERROR,
445 ("\tCWPos=%02x%02x%02x%02x%02x%02x%02x%02x\n",
446 pBuf[0], pBuf[1], pBuf[2], pBuf[3],
447 pBuf[4], pBuf[5], pBuf[6], pBuf[7]));
449 /*DBGPRINT(RT_DEBUG_LOUD,("ENPos==CWPos=%ld, CWRPos=%ld, bCSPad=%d!\n", pHTTXContext->CurWritePosition, pHTTXContext->CurWriteRealPos, pHTTXContext->bCopySavePad)); */
452 if (pAd->bForcePrintTX == TRUE)
453 DBGPRINT(RT_DEBUG_TRACE,
454 ("BulkOut-A:Size=%ld, CWPos=%ld, NBPos=%ld, ENBPos=%ld, bCopy=%d!\n",
455 ThisBulkSize, pHTTXContext->CurWritePosition,
456 pHTTXContext->NextBulkOutPosition,
457 pHTTXContext->ENextBulkOutPosition,
458 pHTTXContext->bCopySavePad));
459 /*DBGPRINT(RT_DEBUG_LOUD,("BulkOut-A:Size=%ld, CWPos=%ld, CWRPos=%ld, NBPos=%ld, ENBPos=%ld, bCopy=%d, bLRound=%d!\n", ThisBulkSize, pHTTXContext->CurWritePosition, pHTTXContext->CurWriteRealPos, pHTTXContext->NextBulkOutPosition, pHTTXContext->ENextBulkOutPosition, pHTTXContext->bCopySavePad, bTxQLastRound)); */
461 /* USB DMA engine requires to pad extra 4 bytes. This pad doesn't count into real bulkoutsize. */
462 pAppendant = &pWirelessPkt[TmpBulkEndPos];
463 NdisZeroMemory(pAppendant, 8);
465 pHTTXContext->LastOne = TRUE;
466 if ((ThisBulkSize % pAd->BulkOutMaxPacketSize) == 0)
468 pHTTXContext->BulkOutSize = ThisBulkSize;
470 pAd->watchDogTxPendingCnt[BulkOutPipeId] = 1;
471 BULK_OUT_UNLOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags2);
473 /* Init Tx context descriptor */
474 RTUSBInitHTTxDesc(pAd, pHTTXContext, BulkOutPipeId, ThisBulkSize,
475 (usb_complete_t) RTUSBBulkOutDataPacketComplete);
477 pUrb = pHTTXContext->pUrb;
478 if ((ret = RTUSB_SUBMIT_URB(pUrb)) != 0) {
479 DBGPRINT(RT_DEBUG_ERROR,
480 ("RTUSBBulkOutDataPacket: Submit Tx URB failed %d\n",
483 BULK_OUT_LOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags);
484 pAd->BulkOutPending[BulkOutPipeId] = FALSE;
485 pAd->watchDogTxPendingCnt[BulkOutPipeId] = 0;
486 BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags);
491 BULK_OUT_LOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags);
492 pHTTXContext->IRPPending = TRUE;
493 BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags);
498 void RTUSBBulkOutDataPacketComplete(struct urb *pUrb, struct pt_regs * pt_regs)
500 struct rt_ht_tx_context *pHTTXContext;
501 struct rt_rtmp_adapter *pAd;
502 struct os_cookie *pObj;
505 pHTTXContext = (struct rt_ht_tx_context *)pUrb->context;
506 pAd = pHTTXContext->pAd;
507 pObj = (struct os_cookie *)pAd->OS_Cookie;
509 /* Store BulkOut PipeId */
510 BulkOutPipeId = pHTTXContext->BulkOutPipeId;
511 pAd->BulkOutDataOneSecCount++;
513 switch (BulkOutPipeId) {
515 pObj->ac0_dma_done_task.data = (unsigned long)pUrb;
516 tasklet_hi_schedule(&pObj->ac0_dma_done_task);
519 pObj->ac1_dma_done_task.data = (unsigned long)pUrb;
520 tasklet_hi_schedule(&pObj->ac1_dma_done_task);
523 pObj->ac2_dma_done_task.data = (unsigned long)pUrb;
524 tasklet_hi_schedule(&pObj->ac2_dma_done_task);
527 pObj->ac3_dma_done_task.data = (unsigned long)pUrb;
528 tasklet_hi_schedule(&pObj->ac3_dma_done_task);
535 ========================================================================
543 Note: NULL frame use BulkOutPipeId = 0
545 ========================================================================
547 void RTUSBBulkOutNullFrame(struct rt_rtmp_adapter *pAd)
549 struct rt_tx_context *pNullContext = &(pAd->NullContext);
552 unsigned long IrqFlags;
554 RTMP_IRQ_LOCK(&pAd->BulkOutLock[0], IrqFlags);
555 if ((pAd->BulkOutPending[0] == TRUE)
556 || RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NEED_STOP_TX)) {
557 RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], IrqFlags);
560 pAd->BulkOutPending[0] = TRUE;
561 pAd->watchDogTxPendingCnt[0] = 1;
562 pNullContext->IRPPending = TRUE;
563 RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], IrqFlags);
565 /* Increase Total transmit byte counter */
566 pAd->RalinkCounters.TransmittedByteCount += pNullContext->BulkOutSize;
568 /* Clear Null frame bulk flag */
569 RTUSB_CLEAR_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NULL);
571 /* Init Tx context descriptor */
572 RTUSBInitTxDesc(pAd, pNullContext, 0,
573 (usb_complete_t) RTUSBBulkOutNullFrameComplete);
575 pUrb = pNullContext->pUrb;
576 if ((ret = RTUSB_SUBMIT_URB(pUrb)) != 0) {
577 RTMP_IRQ_LOCK(&pAd->BulkOutLock[0], IrqFlags);
578 pAd->BulkOutPending[0] = FALSE;
579 pAd->watchDogTxPendingCnt[0] = 0;
580 pNullContext->IRPPending = FALSE;
581 RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], IrqFlags);
583 DBGPRINT(RT_DEBUG_ERROR,
584 ("RTUSBBulkOutNullFrame: Submit Tx URB failed %d\n",
591 /* NULL frame use BulkOutPipeId = 0 */
592 void RTUSBBulkOutNullFrameComplete(struct urb *pUrb, struct pt_regs * pt_regs)
594 struct rt_rtmp_adapter *pAd;
595 struct rt_tx_context *pNullContext;
597 struct os_cookie *pObj;
599 pNullContext = (struct rt_tx_context *)pUrb->context;
600 pAd = pNullContext->pAd;
601 Status = pUrb->status;
603 pObj = (struct os_cookie *)pAd->OS_Cookie;
604 pObj->null_frame_complete_task.data = (unsigned long)pUrb;
605 tasklet_hi_schedule(&pObj->null_frame_complete_task);
609 ========================================================================
617 Note: MLME use BulkOutPipeId = 0
619 ========================================================================
621 void RTUSBBulkOutMLMEPacket(struct rt_rtmp_adapter *pAd, u8 Index)
623 struct rt_tx_context *pMLMEContext;
626 unsigned long IrqFlags;
629 (struct rt_tx_context *)pAd->MgmtRing.Cell[pAd->MgmtRing.TxDmaIdx].AllocVa;
630 pUrb = pMLMEContext->pUrb;
632 if ((pAd->MgmtRing.TxSwFreeIdx >= MGMT_RING_SIZE) ||
633 (pMLMEContext->InUse == FALSE) ||
634 (pMLMEContext->bWaitingBulkOut == FALSE)) {
636 /* Clear MLME bulk flag */
637 RTUSB_CLEAR_BULK_FLAG(pAd, fRTUSB_BULK_OUT_MLME);
642 RTMP_IRQ_LOCK(&pAd->BulkOutLock[MGMTPIPEIDX], IrqFlags);
643 if ((pAd->BulkOutPending[MGMTPIPEIDX] == TRUE)
644 || RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NEED_STOP_TX)) {
645 RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[MGMTPIPEIDX], IrqFlags);
649 pAd->BulkOutPending[MGMTPIPEIDX] = TRUE;
650 pAd->watchDogTxPendingCnt[MGMTPIPEIDX] = 1;
651 pMLMEContext->IRPPending = TRUE;
652 pMLMEContext->bWaitingBulkOut = FALSE;
653 RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[MGMTPIPEIDX], IrqFlags);
655 /* Increase Total transmit byte counter */
656 pAd->RalinkCounters.TransmittedByteCount += pMLMEContext->BulkOutSize;
658 /* Clear MLME bulk flag */
659 RTUSB_CLEAR_BULK_FLAG(pAd, fRTUSB_BULK_OUT_MLME);
661 /* Init Tx context descriptor */
662 RTUSBInitTxDesc(pAd, pMLMEContext, MGMTPIPEIDX,
663 (usb_complete_t) RTUSBBulkOutMLMEPacketComplete);
665 /*For mgmt urb buffer, because we use sk_buff, so we need to notify the USB controller do dma mapping. */
666 pUrb->transfer_dma = 0;
667 pUrb->transfer_flags &= (~URB_NO_TRANSFER_DMA_MAP);
669 pUrb = pMLMEContext->pUrb;
670 if ((ret = RTUSB_SUBMIT_URB(pUrb)) != 0) {
671 DBGPRINT(RT_DEBUG_ERROR,
672 ("RTUSBBulkOutMLMEPacket: Submit MLME URB failed %d\n",
674 RTMP_IRQ_LOCK(&pAd->BulkOutLock[MGMTPIPEIDX], IrqFlags);
675 pAd->BulkOutPending[MGMTPIPEIDX] = FALSE;
676 pAd->watchDogTxPendingCnt[MGMTPIPEIDX] = 0;
677 pMLMEContext->IRPPending = FALSE;
678 pMLMEContext->bWaitingBulkOut = TRUE;
679 RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[MGMTPIPEIDX], IrqFlags);
683 /*DBGPRINT_RAW(RT_DEBUG_INFO, ("<---RTUSBBulkOutMLMEPacket \n")); */
684 /* printk("<---RTUSBBulkOutMLMEPacket,Cpu=%d!, Dma=%d, SwIdx=%d!\n", pAd->MgmtRing.TxCpuIdx, pAd->MgmtRing.TxDmaIdx, pAd->MgmtRing.TxSwFreeIdx); */
687 void RTUSBBulkOutMLMEPacketComplete(struct urb *pUrb, struct pt_regs * pt_regs)
689 struct rt_tx_context *pMLMEContext;
690 struct rt_rtmp_adapter *pAd;
692 struct os_cookie *pObj;
695 /*DBGPRINT_RAW(RT_DEBUG_INFO, ("--->RTUSBBulkOutMLMEPacketComplete\n")); */
696 pMLMEContext = (struct rt_tx_context *)pUrb->context;
697 pAd = pMLMEContext->pAd;
698 pObj = (struct os_cookie *)pAd->OS_Cookie;
699 Status = pUrb->status;
700 index = pMLMEContext->SelfIdx;
702 pObj->mgmt_dma_done_task.data = (unsigned long)pUrb;
703 tasklet_hi_schedule(&pObj->mgmt_dma_done_task);
707 ========================================================================
715 Note: PsPoll use BulkOutPipeId = 0
717 ========================================================================
719 void RTUSBBulkOutPsPoll(struct rt_rtmp_adapter *pAd)
721 struct rt_tx_context *pPsPollContext = &(pAd->PsPollContext);
724 unsigned long IrqFlags;
726 RTMP_IRQ_LOCK(&pAd->BulkOutLock[0], IrqFlags);
727 if ((pAd->BulkOutPending[0] == TRUE)
728 || RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NEED_STOP_TX)) {
729 RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], IrqFlags);
732 pAd->BulkOutPending[0] = TRUE;
733 pAd->watchDogTxPendingCnt[0] = 1;
734 pPsPollContext->IRPPending = TRUE;
735 RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], IrqFlags);
737 /* Clear PS-Poll bulk flag */
738 RTUSB_CLEAR_BULK_FLAG(pAd, fRTUSB_BULK_OUT_PSPOLL);
740 /* Init Tx context descriptor */
741 RTUSBInitTxDesc(pAd, pPsPollContext, MGMTPIPEIDX,
742 (usb_complete_t) RTUSBBulkOutPsPollComplete);
744 pUrb = pPsPollContext->pUrb;
745 if ((ret = RTUSB_SUBMIT_URB(pUrb)) != 0) {
746 RTMP_IRQ_LOCK(&pAd->BulkOutLock[0], IrqFlags);
747 pAd->BulkOutPending[0] = FALSE;
748 pAd->watchDogTxPendingCnt[0] = 0;
749 pPsPollContext->IRPPending = FALSE;
750 RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], IrqFlags);
752 DBGPRINT(RT_DEBUG_ERROR,
753 ("RTUSBBulkOutPsPoll: Submit Tx URB failed %d\n",
760 /* PS-Poll frame use BulkOutPipeId = 0 */
761 void RTUSBBulkOutPsPollComplete(struct urb *pUrb, struct pt_regs * pt_regs)
763 struct rt_rtmp_adapter *pAd;
764 struct rt_tx_context *pPsPollContext;
766 struct os_cookie *pObj;
768 pPsPollContext = (struct rt_tx_context *)pUrb->context;
769 pAd = pPsPollContext->pAd;
770 Status = pUrb->status;
772 pObj = (struct os_cookie *)pAd->OS_Cookie;
773 pObj->pspoll_frame_complete_task.data = (unsigned long)pUrb;
774 tasklet_hi_schedule(&pObj->pspoll_frame_complete_task);
777 void DoBulkIn(struct rt_rtmp_adapter *pAd)
779 struct rt_rx_context *pRxContext;
782 unsigned long IrqFlags;
784 RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags);
785 pRxContext = &(pAd->RxContext[pAd->NextRxBulkInIndex]);
786 if ((pAd->PendingRx > 0) || (pRxContext->Readable == TRUE)
787 || (pRxContext->InUse == TRUE)) {
788 RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags);
791 pRxContext->InUse = TRUE;
792 pRxContext->IRPPending = TRUE;
795 RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags);
797 /* Init Rx context descriptor */
798 NdisZeroMemory(pRxContext->TransferBuffer, pRxContext->BulkInOffset);
799 RTUSBInitRxDesc(pAd, pRxContext);
801 pUrb = pRxContext->pUrb;
802 if ((ret = RTUSB_SUBMIT_URB(pUrb)) != 0) { /* fail */
804 RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags);
805 pRxContext->InUse = FALSE;
806 pRxContext->IRPPending = FALSE;
809 RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags);
810 DBGPRINT(RT_DEBUG_ERROR,
811 ("RTUSBBulkReceive: Submit Rx URB failed %d\n", ret));
812 } else { /* success */
813 ASSERT((pRxContext->InUse == pRxContext->IRPPending));
814 /*printk("BIDone, Pend=%d,BIIdx=%d,BIRIdx=%d!\n", pAd->PendingRx, pAd->NextRxBulkInIndex, pAd->NextRxBulkInReadIndex); */
819 ========================================================================
822 USB_RxPacket initializes a URB and uses the Rx IRP to submit it
823 to USB. It checks if an Rx Descriptor is available and passes the
824 the coresponding buffer to be filled. If no descriptor is available
825 fails the request. When setting the completion routine we pass our
826 Adapter Object as Context.
831 TRUE found matched tuple cache
832 FALSE no matched found
836 ========================================================================
838 #define fRTMP_ADAPTER_NEED_STOP_RX \
839 (fRTMP_ADAPTER_NIC_NOT_EXIST | fRTMP_ADAPTER_HALT_IN_PROGRESS | \
840 fRTMP_ADAPTER_RADIO_OFF | fRTMP_ADAPTER_RESET_IN_PROGRESS | \
841 fRTMP_ADAPTER_REMOVE_IN_PROGRESS | fRTMP_ADAPTER_BULKIN_RESET)
843 #define fRTMP_ADAPTER_NEED_STOP_HANDLE_RX \
844 (fRTMP_ADAPTER_NIC_NOT_EXIST | fRTMP_ADAPTER_HALT_IN_PROGRESS | \
845 fRTMP_ADAPTER_RADIO_OFF | fRTMP_ADAPTER_RESET_IN_PROGRESS | \
846 fRTMP_ADAPTER_REMOVE_IN_PROGRESS)
848 void RTUSBBulkReceive(struct rt_rtmp_adapter *pAd)
850 struct rt_rx_context *pRxContext;
851 unsigned long IrqFlags;
854 if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NEED_STOP_HANDLE_RX))
859 RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags);
860 pRxContext = &(pAd->RxContext[pAd->NextRxBulkInReadIndex]);
861 if (((pRxContext->InUse == FALSE)
862 && (pRxContext->Readable == TRUE))
863 && (pRxContext->bRxHandling == FALSE)) {
864 pRxContext->bRxHandling = TRUE;
865 RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags);
867 /* read RxContext, Since not */
868 STARxDoneInterruptHandle(pAd, TRUE);
870 /* Finish to handle this bulkIn buffer. */
871 RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags);
872 pRxContext->BulkInOffset = 0;
873 pRxContext->Readable = FALSE;
874 pRxContext->bRxHandling = FALSE;
875 pAd->ReadPosition = 0;
876 pAd->TransferBufferLength = 0;
877 INC_RING_INDEX(pAd->NextRxBulkInReadIndex,
879 RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags);
882 RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags);
887 if (!(RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NEED_STOP_RX)))
893 ========================================================================
896 This routine process Rx Irp and call rx complete function.
899 DeviceObject Pointer to the device object for next lower
900 device. DeviceObject passed in here belongs to
901 the next lower driver in the stack because we
902 were invoked via IoCallDriver in USB_RxPacket
903 AND it is not OUR device object
904 Irp Ptr to completed IRP
905 Context Ptr to our Adapter object (context specified
906 in IoSetCompletionRoutine
909 Always returns STATUS_MORE_PROCESSING_REQUIRED
912 Always returns STATUS_MORE_PROCESSING_REQUIRED
913 ========================================================================
915 void RTUSBBulkRxComplete(struct urb *pUrb, struct pt_regs *pt_regs)
917 /* use a receive tasklet to handle received packets; */
918 /* or sometimes hardware IRQ will be disabled here, so we can not */
919 /* use spin_lock_bh()/spin_unlock_bh() after IRQ is disabled. :< */
920 struct rt_rx_context *pRxContext;
921 struct rt_rtmp_adapter *pAd;
922 struct os_cookie *pObj;
924 pRxContext = (struct rt_rx_context *)pUrb->context;
925 pAd = pRxContext->pAd;
926 pObj = (struct os_cookie *)pAd->OS_Cookie;
928 pObj->rx_done_task.data = (unsigned long)pUrb;
929 tasklet_hi_schedule(&pObj->rx_done_task);
934 ========================================================================
944 ========================================================================
946 void RTUSBKickBulkOut(struct rt_rtmp_adapter *pAd)
948 /* BulkIn Reset will reset whole USB PHY. So we need to make sure fRTMP_ADAPTER_BULKIN_RESET not flaged. */
949 if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NEED_STOP_TX)
951 /* 2. PS-Poll frame is next */
952 if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_PSPOLL)) {
953 RTUSBBulkOutPsPoll(pAd);
955 /* 5. Mlme frame is next */
956 else if ((RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_MLME)) ||
957 (pAd->MgmtRing.TxSwFreeIdx < MGMT_RING_SIZE)) {
958 RTUSBBulkOutMLMEPacket(pAd, pAd->MgmtRing.TxDmaIdx);
960 /* 6. Data frame normal is next */
961 if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL)) {
962 if (((!RTMP_TEST_FLAG
963 (pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
966 (pAd, fOP_STATUS_MEDIA_STATE_CONNECTED))
968 RTUSBBulkOutDataPacket(pAd, 0,
970 NextBulkOutIndex[0]);
973 if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL_2)) {
974 if (((!RTMP_TEST_FLAG
975 (pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
978 (pAd, fOP_STATUS_MEDIA_STATE_CONNECTED))
980 RTUSBBulkOutDataPacket(pAd, 1,
982 NextBulkOutIndex[1]);
985 if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL_3)) {
986 if (((!RTMP_TEST_FLAG
987 (pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
990 (pAd, fOP_STATUS_MEDIA_STATE_CONNECTED))
992 RTUSBBulkOutDataPacket(pAd, 2,
994 NextBulkOutIndex[2]);
997 if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL_4)) {
998 if (((!RTMP_TEST_FLAG
999 (pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
1001 (!OPSTATUS_TEST_FLAG
1002 (pAd, fOP_STATUS_MEDIA_STATE_CONNECTED))
1004 RTUSBBulkOutDataPacket(pAd, 3,
1006 NextBulkOutIndex[3]);
1009 /* 7. Null frame is the last */
1010 else if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NULL)) {
1012 (pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) {
1013 RTUSBBulkOutNullFrame(pAd);
1016 /* 8. No data avaliable */
1024 ========================================================================
1026 Routine Description:
1027 Call from Reset action after BulkOut failed.
1034 ========================================================================
1036 void RTUSBCleanUpDataBulkOutQueue(struct rt_rtmp_adapter *pAd)
1039 struct rt_ht_tx_context *pTxContext;
1041 DBGPRINT(RT_DEBUG_TRACE, ("--->CleanUpDataBulkOutQueue\n"));
1043 for (Idx = 0; Idx < 4; Idx++) {
1044 pTxContext = &pAd->TxContext[Idx];
1046 pTxContext->CurWritePosition = pTxContext->NextBulkOutPosition;
1047 pTxContext->LastOne = FALSE;
1048 NdisAcquireSpinLock(&pAd->BulkOutLock[Idx]);
1049 pAd->BulkOutPending[Idx] = FALSE;
1050 NdisReleaseSpinLock(&pAd->BulkOutLock[Idx]);
1053 DBGPRINT(RT_DEBUG_TRACE, ("<---CleanUpDataBulkOutQueue\n"));
1057 ========================================================================
1059 Routine Description:
1067 ========================================================================
1069 void RTUSBCleanUpMLMEBulkOutQueue(struct rt_rtmp_adapter *pAd)
1071 DBGPRINT(RT_DEBUG_TRACE, ("--->CleanUpMLMEBulkOutQueue\n"));
1072 DBGPRINT(RT_DEBUG_TRACE, ("<---CleanUpMLMEBulkOutQueue\n"));
1076 ========================================================================
1078 Routine Description:
1086 ========================================================================
1088 void RTUSBCancelPendingIRPs(struct rt_rtmp_adapter *pAd)
1090 RTUSBCancelPendingBulkInIRP(pAd);
1091 RTUSBCancelPendingBulkOutIRP(pAd);
1095 ========================================================================
1097 Routine Description:
1105 ========================================================================
1107 void RTUSBCancelPendingBulkInIRP(struct rt_rtmp_adapter *pAd)
1109 struct rt_rx_context *pRxContext;
1112 DBGPRINT_RAW(RT_DEBUG_TRACE, ("--->RTUSBCancelPendingBulkInIRP\n"));
1113 for (i = 0; i < (RX_RING_SIZE); i++) {
1114 pRxContext = &(pAd->RxContext[i]);
1115 if (pRxContext->IRPPending == TRUE) {
1116 RTUSB_UNLINK_URB(pRxContext->pUrb);
1117 pRxContext->IRPPending = FALSE;
1118 pRxContext->InUse = FALSE;
1119 /*NdisInterlockedDecrement(&pAd->PendingRx); */
1120 /*pAd->PendingRx--; */
1123 DBGPRINT_RAW(RT_DEBUG_TRACE, ("<---RTUSBCancelPendingBulkInIRP\n"));
1127 ========================================================================
1129 Routine Description:
1137 ========================================================================
1139 void RTUSBCancelPendingBulkOutIRP(struct rt_rtmp_adapter *pAd)
1141 struct rt_ht_tx_context *pHTTXContext;
1142 struct rt_tx_context *pMLMEContext;
1143 struct rt_tx_context *pBeaconContext;
1144 struct rt_tx_context *pNullContext;
1145 struct rt_tx_context *pPsPollContext;
1146 struct rt_tx_context *pRTSContext;
1148 /* unsigned int IrqFlags; */
1149 /* spinlock_t *pLock; */
1150 /* BOOLEAN *pPending; */
1152 /* pLock = &pAd->BulkOutLock[MGMTPIPEIDX]; */
1153 /* pPending = &pAd->BulkOutPending[MGMTPIPEIDX]; */
1155 for (Idx = 0; Idx < 4; Idx++) {
1156 pHTTXContext = &(pAd->TxContext[Idx]);
1158 if (pHTTXContext->IRPPending == TRUE) {
1160 /* Get the USB_CONTEXT and cancel it's IRP; the completion routine will itself */
1161 /* remove it from the HeadPendingSendList and NULL out HeadPendingSendList */
1162 /* when the last IRP on the list has been cancelled; that's how we exit this loop */
1165 RTUSB_UNLINK_URB(pHTTXContext->pUrb);
1167 /* Sleep 200 microseconds to give cancellation time to work */
1171 pAd->BulkOutPending[Idx] = FALSE;
1174 /*RTMP_IRQ_LOCK(pLock, IrqFlags); */
1175 for (i = 0; i < MGMT_RING_SIZE; i++) {
1176 pMLMEContext = (struct rt_tx_context *)pAd->MgmtRing.Cell[i].AllocVa;
1177 if (pMLMEContext && (pMLMEContext->IRPPending == TRUE)) {
1179 /* Get the USB_CONTEXT and cancel it's IRP; the completion routine will itself */
1180 /* remove it from the HeadPendingSendList and NULL out HeadPendingSendList */
1181 /* when the last IRP on the list has been cancelled; that's how we exit this loop */
1184 RTUSB_UNLINK_URB(pMLMEContext->pUrb);
1185 pMLMEContext->IRPPending = FALSE;
1187 /* Sleep 200 microsecs to give cancellation time to work */
1191 pAd->BulkOutPending[MGMTPIPEIDX] = FALSE;
1192 /*RTMP_IRQ_UNLOCK(pLock, IrqFlags); */
1194 for (i = 0; i < BEACON_RING_SIZE; i++) {
1195 pBeaconContext = &(pAd->BeaconContext[i]);
1197 if (pBeaconContext->IRPPending == TRUE) {
1199 /* Get the USB_CONTEXT and cancel it's IRP; the completion routine will itself */
1200 /* remove it from the HeadPendingSendList and NULL out HeadPendingSendList */
1201 /* when the last IRP on the list has been cancelled; that's how we exit this loop */
1204 RTUSB_UNLINK_URB(pBeaconContext->pUrb);
1206 /* Sleep 200 microsecs to give cancellation time to work */
1211 pNullContext = &(pAd->NullContext);
1212 if (pNullContext->IRPPending == TRUE)
1213 RTUSB_UNLINK_URB(pNullContext->pUrb);
1215 pRTSContext = &(pAd->RTSContext);
1216 if (pRTSContext->IRPPending == TRUE)
1217 RTUSB_UNLINK_URB(pRTSContext->pUrb);
1219 pPsPollContext = &(pAd->PsPollContext);
1220 if (pPsPollContext->IRPPending == TRUE)
1221 RTUSB_UNLINK_URB(pPsPollContext->pUrb);
1223 for (Idx = 0; Idx < 4; Idx++) {
1224 NdisAcquireSpinLock(&pAd->BulkOutLock[Idx]);
1225 pAd->BulkOutPending[Idx] = FALSE;
1226 NdisReleaseSpinLock(&pAd->BulkOutLock[Idx]);
1230 #endif /* RTMP_MAC_USB // */