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 __func__, 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;
408 We need to copy SavedPad when following condition matched!
409 1. Not the last round of the TxQueue and
410 2. any match of following cases:
411 (1). The End Position of this bulk out is reach to the Currenct Write position and
412 the TxInfo and related header already write to the CurWritePosition.
413 =>(ENextBulkOutPosition == CurWritePosition) && (CurWriteRealPos > CurWritePosition)
415 (2). The EndPosition of the bulk out is not reach to the Current Write Position.
416 =>(ENextBulkOutPosition != CurWritePosition)
418 if ((bTxQLastRound == FALSE) &&
419 (((pHTTXContext->ENextBulkOutPosition ==
420 pHTTXContext->CurWritePosition)
421 && (pHTTXContext->CurWriteRealPos >
422 pHTTXContext->CurWritePosition))
423 || (pHTTXContext->ENextBulkOutPosition !=
424 pHTTXContext->CurWritePosition))
426 NdisMoveMemory(pHTTXContext->SavedPad,
427 &pWirelessPkt[pHTTXContext->
428 ENextBulkOutPosition], 8);
429 pHTTXContext->bCopySavePad = TRUE;
430 if (RTMPEqualMemory(pHTTXContext->SavedPad, allzero, 4)) {
431 u8 *pBuf = &pHTTXContext->SavedPad[0];
432 DBGPRINT_RAW(RT_DEBUG_ERROR,
433 ("WARNING-Zero-3:%02x%02x%02x%02x%02x%02x%02x%02x,CWPos=%ld, CWRPos=%ld, bCW=%d, NBPos=%ld, TBPos=%ld, TBSize=%ld\n",
434 pBuf[0], pBuf[1], pBuf[2], pBuf[3],
435 pBuf[4], pBuf[5], pBuf[6], pBuf[7],
436 pHTTXContext->CurWritePosition,
437 pHTTXContext->CurWriteRealPos,
438 pHTTXContext->bCurWriting,
439 pHTTXContext->NextBulkOutPosition,
440 TmpBulkEndPos, ThisBulkSize));
442 pBuf = &pWirelessPkt[pHTTXContext->CurWritePosition];
443 DBGPRINT_RAW(RT_DEBUG_ERROR,
444 ("\tCWPos=%02x%02x%02x%02x%02x%02x%02x%02x\n",
445 pBuf[0], pBuf[1], pBuf[2], pBuf[3],
446 pBuf[4], pBuf[5], pBuf[6], pBuf[7]));
448 /*DBGPRINT(RT_DEBUG_LOUD,("ENPos==CWPos=%ld, CWRPos=%ld, bCSPad=%d!\n", pHTTXContext->CurWritePosition, pHTTXContext->CurWriteRealPos, pHTTXContext->bCopySavePad)); */
451 if (pAd->bForcePrintTX == TRUE)
452 DBGPRINT(RT_DEBUG_TRACE,
453 ("BulkOut-A:Size=%ld, CWPos=%ld, NBPos=%ld, ENBPos=%ld, bCopy=%d!\n",
454 ThisBulkSize, pHTTXContext->CurWritePosition,
455 pHTTXContext->NextBulkOutPosition,
456 pHTTXContext->ENextBulkOutPosition,
457 pHTTXContext->bCopySavePad));
458 /*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)); */
460 /* USB DMA engine requires to pad extra 4 bytes. This pad doesn't count into real bulkoutsize. */
461 pAppendant = &pWirelessPkt[TmpBulkEndPos];
462 NdisZeroMemory(pAppendant, 8);
464 pHTTXContext->LastOne = TRUE;
465 if ((ThisBulkSize % pAd->BulkOutMaxPacketSize) == 0)
467 pHTTXContext->BulkOutSize = ThisBulkSize;
469 pAd->watchDogTxPendingCnt[BulkOutPipeId] = 1;
470 BULK_OUT_UNLOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags2);
472 /* Init Tx context descriptor */
473 RTUSBInitHTTxDesc(pAd, pHTTXContext, BulkOutPipeId, ThisBulkSize,
474 (usb_complete_t) RTUSBBulkOutDataPacketComplete);
476 pUrb = pHTTXContext->pUrb;
477 if ((ret = RTUSB_SUBMIT_URB(pUrb)) != 0) {
478 DBGPRINT(RT_DEBUG_ERROR,
479 ("RTUSBBulkOutDataPacket: Submit Tx URB failed %d\n",
482 BULK_OUT_LOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags);
483 pAd->BulkOutPending[BulkOutPipeId] = FALSE;
484 pAd->watchDogTxPendingCnt[BulkOutPipeId] = 0;
485 BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags);
490 BULK_OUT_LOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags);
491 pHTTXContext->IRPPending = TRUE;
492 BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags);
497 void RTUSBBulkOutDataPacketComplete(struct urb *pUrb, struct pt_regs * pt_regs)
499 struct rt_ht_tx_context *pHTTXContext;
500 struct rt_rtmp_adapter *pAd;
501 struct os_cookie *pObj;
504 pHTTXContext = (struct rt_ht_tx_context *)pUrb->context;
505 pAd = pHTTXContext->pAd;
506 pObj = (struct os_cookie *)pAd->OS_Cookie;
508 /* Store BulkOut PipeId */
509 BulkOutPipeId = pHTTXContext->BulkOutPipeId;
510 pAd->BulkOutDataOneSecCount++;
512 switch (BulkOutPipeId) {
514 pObj->ac0_dma_done_task.data = (unsigned long)pUrb;
515 tasklet_hi_schedule(&pObj->ac0_dma_done_task);
518 pObj->ac1_dma_done_task.data = (unsigned long)pUrb;
519 tasklet_hi_schedule(&pObj->ac1_dma_done_task);
522 pObj->ac2_dma_done_task.data = (unsigned long)pUrb;
523 tasklet_hi_schedule(&pObj->ac2_dma_done_task);
526 pObj->ac3_dma_done_task.data = (unsigned long)pUrb;
527 tasklet_hi_schedule(&pObj->ac3_dma_done_task);
534 ========================================================================
542 Note: NULL frame use BulkOutPipeId = 0
544 ========================================================================
546 void RTUSBBulkOutNullFrame(struct rt_rtmp_adapter *pAd)
548 struct rt_tx_context *pNullContext = &(pAd->NullContext);
551 unsigned long IrqFlags;
553 RTMP_IRQ_LOCK(&pAd->BulkOutLock[0], IrqFlags);
554 if ((pAd->BulkOutPending[0] == TRUE)
555 || RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NEED_STOP_TX)) {
556 RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], IrqFlags);
559 pAd->BulkOutPending[0] = TRUE;
560 pAd->watchDogTxPendingCnt[0] = 1;
561 pNullContext->IRPPending = TRUE;
562 RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], IrqFlags);
564 /* Increase Total transmit byte counter */
565 pAd->RalinkCounters.TransmittedByteCount += pNullContext->BulkOutSize;
567 /* Clear Null frame bulk flag */
568 RTUSB_CLEAR_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NULL);
570 /* Init Tx context descriptor */
571 RTUSBInitTxDesc(pAd, pNullContext, 0,
572 (usb_complete_t) RTUSBBulkOutNullFrameComplete);
574 pUrb = pNullContext->pUrb;
575 if ((ret = RTUSB_SUBMIT_URB(pUrb)) != 0) {
576 RTMP_IRQ_LOCK(&pAd->BulkOutLock[0], IrqFlags);
577 pAd->BulkOutPending[0] = FALSE;
578 pAd->watchDogTxPendingCnt[0] = 0;
579 pNullContext->IRPPending = FALSE;
580 RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], IrqFlags);
582 DBGPRINT(RT_DEBUG_ERROR,
583 ("RTUSBBulkOutNullFrame: Submit Tx URB failed %d\n",
590 /* NULL frame use BulkOutPipeId = 0 */
591 void RTUSBBulkOutNullFrameComplete(struct urb *pUrb, struct pt_regs * pt_regs)
593 struct rt_rtmp_adapter *pAd;
594 struct rt_tx_context *pNullContext;
596 struct os_cookie *pObj;
598 pNullContext = (struct rt_tx_context *)pUrb->context;
599 pAd = pNullContext->pAd;
600 Status = pUrb->status;
602 pObj = (struct os_cookie *)pAd->OS_Cookie;
603 pObj->null_frame_complete_task.data = (unsigned long)pUrb;
604 tasklet_hi_schedule(&pObj->null_frame_complete_task);
608 ========================================================================
616 Note: MLME use BulkOutPipeId = 0
618 ========================================================================
620 void RTUSBBulkOutMLMEPacket(struct rt_rtmp_adapter *pAd, u8 Index)
622 struct rt_tx_context *pMLMEContext;
625 unsigned long IrqFlags;
628 (struct rt_tx_context *)pAd->MgmtRing.Cell[pAd->MgmtRing.TxDmaIdx].AllocVa;
629 pUrb = pMLMEContext->pUrb;
631 if ((pAd->MgmtRing.TxSwFreeIdx >= MGMT_RING_SIZE) ||
632 (pMLMEContext->InUse == FALSE) ||
633 (pMLMEContext->bWaitingBulkOut == FALSE)) {
635 /* Clear MLME bulk flag */
636 RTUSB_CLEAR_BULK_FLAG(pAd, fRTUSB_BULK_OUT_MLME);
641 RTMP_IRQ_LOCK(&pAd->BulkOutLock[MGMTPIPEIDX], IrqFlags);
642 if ((pAd->BulkOutPending[MGMTPIPEIDX] == TRUE)
643 || RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NEED_STOP_TX)) {
644 RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[MGMTPIPEIDX], IrqFlags);
648 pAd->BulkOutPending[MGMTPIPEIDX] = TRUE;
649 pAd->watchDogTxPendingCnt[MGMTPIPEIDX] = 1;
650 pMLMEContext->IRPPending = TRUE;
651 pMLMEContext->bWaitingBulkOut = FALSE;
652 RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[MGMTPIPEIDX], IrqFlags);
654 /* Increase Total transmit byte counter */
655 pAd->RalinkCounters.TransmittedByteCount += pMLMEContext->BulkOutSize;
657 /* Clear MLME bulk flag */
658 RTUSB_CLEAR_BULK_FLAG(pAd, fRTUSB_BULK_OUT_MLME);
660 /* Init Tx context descriptor */
661 RTUSBInitTxDesc(pAd, pMLMEContext, MGMTPIPEIDX,
662 (usb_complete_t) RTUSBBulkOutMLMEPacketComplete);
664 /*For mgmt urb buffer, because we use sk_buff, so we need to notify the USB controller do dma mapping. */
665 pUrb->transfer_dma = 0;
666 pUrb->transfer_flags &= (~URB_NO_TRANSFER_DMA_MAP);
668 pUrb = pMLMEContext->pUrb;
669 if ((ret = RTUSB_SUBMIT_URB(pUrb)) != 0) {
670 DBGPRINT(RT_DEBUG_ERROR,
671 ("RTUSBBulkOutMLMEPacket: Submit MLME URB failed %d\n",
673 RTMP_IRQ_LOCK(&pAd->BulkOutLock[MGMTPIPEIDX], IrqFlags);
674 pAd->BulkOutPending[MGMTPIPEIDX] = FALSE;
675 pAd->watchDogTxPendingCnt[MGMTPIPEIDX] = 0;
676 pMLMEContext->IRPPending = FALSE;
677 pMLMEContext->bWaitingBulkOut = TRUE;
678 RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[MGMTPIPEIDX], IrqFlags);
682 /*DBGPRINT_RAW(RT_DEBUG_INFO, ("<---RTUSBBulkOutMLMEPacket \n")); */
683 /* printk("<---RTUSBBulkOutMLMEPacket,Cpu=%d!, Dma=%d, SwIdx=%d!\n", pAd->MgmtRing.TxCpuIdx, pAd->MgmtRing.TxDmaIdx, pAd->MgmtRing.TxSwFreeIdx); */
686 void RTUSBBulkOutMLMEPacketComplete(struct urb *pUrb, struct pt_regs * pt_regs)
688 struct rt_tx_context *pMLMEContext;
689 struct rt_rtmp_adapter *pAd;
691 struct os_cookie *pObj;
694 /*DBGPRINT_RAW(RT_DEBUG_INFO, ("--->RTUSBBulkOutMLMEPacketComplete\n")); */
695 pMLMEContext = (struct rt_tx_context *)pUrb->context;
696 pAd = pMLMEContext->pAd;
697 pObj = (struct os_cookie *)pAd->OS_Cookie;
698 Status = pUrb->status;
699 index = pMLMEContext->SelfIdx;
701 pObj->mgmt_dma_done_task.data = (unsigned long)pUrb;
702 tasklet_hi_schedule(&pObj->mgmt_dma_done_task);
706 ========================================================================
714 Note: PsPoll use BulkOutPipeId = 0
716 ========================================================================
718 void RTUSBBulkOutPsPoll(struct rt_rtmp_adapter *pAd)
720 struct rt_tx_context *pPsPollContext = &(pAd->PsPollContext);
723 unsigned long IrqFlags;
725 RTMP_IRQ_LOCK(&pAd->BulkOutLock[0], IrqFlags);
726 if ((pAd->BulkOutPending[0] == TRUE)
727 || RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NEED_STOP_TX)) {
728 RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], IrqFlags);
731 pAd->BulkOutPending[0] = TRUE;
732 pAd->watchDogTxPendingCnt[0] = 1;
733 pPsPollContext->IRPPending = TRUE;
734 RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], IrqFlags);
736 /* Clear PS-Poll bulk flag */
737 RTUSB_CLEAR_BULK_FLAG(pAd, fRTUSB_BULK_OUT_PSPOLL);
739 /* Init Tx context descriptor */
740 RTUSBInitTxDesc(pAd, pPsPollContext, MGMTPIPEIDX,
741 (usb_complete_t) RTUSBBulkOutPsPollComplete);
743 pUrb = pPsPollContext->pUrb;
744 if ((ret = RTUSB_SUBMIT_URB(pUrb)) != 0) {
745 RTMP_IRQ_LOCK(&pAd->BulkOutLock[0], IrqFlags);
746 pAd->BulkOutPending[0] = FALSE;
747 pAd->watchDogTxPendingCnt[0] = 0;
748 pPsPollContext->IRPPending = FALSE;
749 RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], IrqFlags);
751 DBGPRINT(RT_DEBUG_ERROR,
752 ("RTUSBBulkOutPsPoll: Submit Tx URB failed %d\n",
759 /* PS-Poll frame use BulkOutPipeId = 0 */
760 void RTUSBBulkOutPsPollComplete(struct urb *pUrb, struct pt_regs * pt_regs)
762 struct rt_rtmp_adapter *pAd;
763 struct rt_tx_context *pPsPollContext;
765 struct os_cookie *pObj;
767 pPsPollContext = (struct rt_tx_context *)pUrb->context;
768 pAd = pPsPollContext->pAd;
769 Status = pUrb->status;
771 pObj = (struct os_cookie *)pAd->OS_Cookie;
772 pObj->pspoll_frame_complete_task.data = (unsigned long)pUrb;
773 tasklet_hi_schedule(&pObj->pspoll_frame_complete_task);
776 void DoBulkIn(struct rt_rtmp_adapter *pAd)
778 struct rt_rx_context *pRxContext;
781 unsigned long IrqFlags;
783 RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags);
784 pRxContext = &(pAd->RxContext[pAd->NextRxBulkInIndex]);
785 if ((pAd->PendingRx > 0) || (pRxContext->Readable == TRUE)
786 || (pRxContext->InUse == TRUE)) {
787 RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags);
790 pRxContext->InUse = TRUE;
791 pRxContext->IRPPending = TRUE;
794 RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags);
796 /* Init Rx context descriptor */
797 NdisZeroMemory(pRxContext->TransferBuffer, pRxContext->BulkInOffset);
798 RTUSBInitRxDesc(pAd, pRxContext);
800 pUrb = pRxContext->pUrb;
801 if ((ret = RTUSB_SUBMIT_URB(pUrb)) != 0) { /* fail */
803 RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags);
804 pRxContext->InUse = FALSE;
805 pRxContext->IRPPending = FALSE;
808 RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags);
809 DBGPRINT(RT_DEBUG_ERROR,
810 ("RTUSBBulkReceive: Submit Rx URB failed %d\n", ret));
811 } else { /* success */
812 ASSERT((pRxContext->InUse == pRxContext->IRPPending));
813 /*printk("BIDone, Pend=%d,BIIdx=%d,BIRIdx=%d!\n", pAd->PendingRx, pAd->NextRxBulkInIndex, pAd->NextRxBulkInReadIndex); */
818 ========================================================================
821 USB_RxPacket initializes a URB and uses the Rx IRP to submit it
822 to USB. It checks if an Rx Descriptor is available and passes the
823 the coresponding buffer to be filled. If no descriptor is available
824 fails the request. When setting the completion routine we pass our
825 Adapter Object as Context.
830 TRUE found matched tuple cache
831 FALSE no matched found
835 ========================================================================
837 #define fRTMP_ADAPTER_NEED_STOP_RX \
838 (fRTMP_ADAPTER_NIC_NOT_EXIST | fRTMP_ADAPTER_HALT_IN_PROGRESS | \
839 fRTMP_ADAPTER_RADIO_OFF | fRTMP_ADAPTER_RESET_IN_PROGRESS | \
840 fRTMP_ADAPTER_REMOVE_IN_PROGRESS | fRTMP_ADAPTER_BULKIN_RESET)
842 #define fRTMP_ADAPTER_NEED_STOP_HANDLE_RX \
843 (fRTMP_ADAPTER_NIC_NOT_EXIST | fRTMP_ADAPTER_HALT_IN_PROGRESS | \
844 fRTMP_ADAPTER_RADIO_OFF | fRTMP_ADAPTER_RESET_IN_PROGRESS | \
845 fRTMP_ADAPTER_REMOVE_IN_PROGRESS)
847 void RTUSBBulkReceive(struct rt_rtmp_adapter *pAd)
849 struct rt_rx_context *pRxContext;
850 unsigned long IrqFlags;
853 if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NEED_STOP_HANDLE_RX))
858 RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags);
859 pRxContext = &(pAd->RxContext[pAd->NextRxBulkInReadIndex]);
860 if (((pRxContext->InUse == FALSE)
861 && (pRxContext->Readable == TRUE))
862 && (pRxContext->bRxHandling == FALSE)) {
863 pRxContext->bRxHandling = TRUE;
864 RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags);
866 /* read RxContext, Since not */
867 STARxDoneInterruptHandle(pAd, TRUE);
869 /* Finish to handle this bulkIn buffer. */
870 RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags);
871 pRxContext->BulkInOffset = 0;
872 pRxContext->Readable = FALSE;
873 pRxContext->bRxHandling = FALSE;
874 pAd->ReadPosition = 0;
875 pAd->TransferBufferLength = 0;
876 INC_RING_INDEX(pAd->NextRxBulkInReadIndex,
878 RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags);
881 RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags);
886 if (!(RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NEED_STOP_RX)))
892 ========================================================================
895 This routine process Rx Irp and call rx complete function.
898 DeviceObject Pointer to the device object for next lower
899 device. DeviceObject passed in here belongs to
900 the next lower driver in the stack because we
901 were invoked via IoCallDriver in USB_RxPacket
902 AND it is not OUR device object
903 Irp Ptr to completed IRP
904 Context Ptr to our Adapter object (context specified
905 in IoSetCompletionRoutine
908 Always returns STATUS_MORE_PROCESSING_REQUIRED
911 Always returns STATUS_MORE_PROCESSING_REQUIRED
912 ========================================================================
914 void RTUSBBulkRxComplete(struct urb *pUrb, struct pt_regs *pt_regs)
916 /* use a receive tasklet to handle received packets; */
917 /* or sometimes hardware IRQ will be disabled here, so we can not */
918 /* use spin_lock_bh()/spin_unlock_bh() after IRQ is disabled. :< */
919 struct rt_rx_context *pRxContext;
920 struct rt_rtmp_adapter *pAd;
921 struct os_cookie *pObj;
923 pRxContext = (struct rt_rx_context *)pUrb->context;
924 pAd = pRxContext->pAd;
925 pObj = (struct os_cookie *)pAd->OS_Cookie;
927 pObj->rx_done_task.data = (unsigned long)pUrb;
928 tasklet_hi_schedule(&pObj->rx_done_task);
933 ========================================================================
943 ========================================================================
945 void RTUSBKickBulkOut(struct rt_rtmp_adapter *pAd)
947 /* BulkIn Reset will reset whole USB PHY. So we need to make sure fRTMP_ADAPTER_BULKIN_RESET not flaged. */
948 if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NEED_STOP_TX)
950 /* 2. PS-Poll frame is next */
951 if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_PSPOLL))
952 RTUSBBulkOutPsPoll(pAd);
953 /* 5. Mlme frame is next */
954 else if ((RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_MLME)) ||
955 (pAd->MgmtRing.TxSwFreeIdx < MGMT_RING_SIZE)) {
956 RTUSBBulkOutMLMEPacket(pAd, pAd->MgmtRing.TxDmaIdx);
958 /* 6. Data frame normal is next */
959 if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL)) {
960 if (((!RTMP_TEST_FLAG
961 (pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
964 (pAd, fOP_STATUS_MEDIA_STATE_CONNECTED))
966 RTUSBBulkOutDataPacket(pAd, 0,
968 NextBulkOutIndex[0]);
971 if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL_2)) {
972 if (((!RTMP_TEST_FLAG
973 (pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
976 (pAd, fOP_STATUS_MEDIA_STATE_CONNECTED))
978 RTUSBBulkOutDataPacket(pAd, 1,
980 NextBulkOutIndex[1]);
983 if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL_3)) {
984 if (((!RTMP_TEST_FLAG
985 (pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
988 (pAd, fOP_STATUS_MEDIA_STATE_CONNECTED))
990 RTUSBBulkOutDataPacket(pAd, 2,
992 NextBulkOutIndex[2]);
995 if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL_4)) {
996 if (((!RTMP_TEST_FLAG
997 (pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
1000 (pAd, fOP_STATUS_MEDIA_STATE_CONNECTED))
1002 RTUSBBulkOutDataPacket(pAd, 3,
1004 NextBulkOutIndex[3]);
1007 /* 7. Null frame is the last */
1008 else if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NULL)) {
1010 (pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) {
1011 RTUSBBulkOutNullFrame(pAd);
1014 /* 8. No data avaliable */
1021 ========================================================================
1023 Routine Description:
1024 Call from Reset action after BulkOut failed.
1031 ========================================================================
1033 void RTUSBCleanUpDataBulkOutQueue(struct rt_rtmp_adapter *pAd)
1036 struct rt_ht_tx_context *pTxContext;
1038 DBGPRINT(RT_DEBUG_TRACE, ("--->CleanUpDataBulkOutQueue\n"));
1040 for (Idx = 0; Idx < 4; Idx++) {
1041 pTxContext = &pAd->TxContext[Idx];
1043 pTxContext->CurWritePosition = pTxContext->NextBulkOutPosition;
1044 pTxContext->LastOne = FALSE;
1045 NdisAcquireSpinLock(&pAd->BulkOutLock[Idx]);
1046 pAd->BulkOutPending[Idx] = FALSE;
1047 NdisReleaseSpinLock(&pAd->BulkOutLock[Idx]);
1050 DBGPRINT(RT_DEBUG_TRACE, ("<---CleanUpDataBulkOutQueue\n"));
1054 ========================================================================
1056 Routine Description:
1064 ========================================================================
1066 void RTUSBCleanUpMLMEBulkOutQueue(struct rt_rtmp_adapter *pAd)
1068 DBGPRINT(RT_DEBUG_TRACE, ("--->CleanUpMLMEBulkOutQueue\n"));
1069 DBGPRINT(RT_DEBUG_TRACE, ("<---CleanUpMLMEBulkOutQueue\n"));
1073 ========================================================================
1075 Routine Description:
1083 ========================================================================
1085 void RTUSBCancelPendingIRPs(struct rt_rtmp_adapter *pAd)
1087 RTUSBCancelPendingBulkInIRP(pAd);
1088 RTUSBCancelPendingBulkOutIRP(pAd);
1092 ========================================================================
1094 Routine Description:
1102 ========================================================================
1104 void RTUSBCancelPendingBulkInIRP(struct rt_rtmp_adapter *pAd)
1106 struct rt_rx_context *pRxContext;
1109 DBGPRINT_RAW(RT_DEBUG_TRACE, ("--->RTUSBCancelPendingBulkInIRP\n"));
1110 for (i = 0; i < (RX_RING_SIZE); i++) {
1111 pRxContext = &(pAd->RxContext[i]);
1112 if (pRxContext->IRPPending == TRUE) {
1113 RTUSB_UNLINK_URB(pRxContext->pUrb);
1114 pRxContext->IRPPending = FALSE;
1115 pRxContext->InUse = FALSE;
1116 /*NdisInterlockedDecrement(&pAd->PendingRx); */
1117 /*pAd->PendingRx--; */
1120 DBGPRINT_RAW(RT_DEBUG_TRACE, ("<---RTUSBCancelPendingBulkInIRP\n"));
1124 ========================================================================
1126 Routine Description:
1134 ========================================================================
1136 void RTUSBCancelPendingBulkOutIRP(struct rt_rtmp_adapter *pAd)
1138 struct rt_ht_tx_context *pHTTXContext;
1139 struct rt_tx_context *pMLMEContext;
1140 struct rt_tx_context *pBeaconContext;
1141 struct rt_tx_context *pNullContext;
1142 struct rt_tx_context *pPsPollContext;
1143 struct rt_tx_context *pRTSContext;
1145 /* unsigned int IrqFlags; */
1146 /* spinlock_t *pLock; */
1147 /* BOOLEAN *pPending; */
1149 /* pLock = &pAd->BulkOutLock[MGMTPIPEIDX]; */
1150 /* pPending = &pAd->BulkOutPending[MGMTPIPEIDX]; */
1152 for (Idx = 0; Idx < 4; Idx++) {
1153 pHTTXContext = &(pAd->TxContext[Idx]);
1155 if (pHTTXContext->IRPPending == TRUE) {
1157 /* Get the USB_CONTEXT and cancel it's IRP; the completion routine will itself */
1158 /* remove it from the HeadPendingSendList and NULL out HeadPendingSendList */
1159 /* when the last IRP on the list has been cancelled; that's how we exit this loop */
1162 RTUSB_UNLINK_URB(pHTTXContext->pUrb);
1164 /* Sleep 200 microseconds to give cancellation time to work */
1168 pAd->BulkOutPending[Idx] = FALSE;
1171 /*RTMP_IRQ_LOCK(pLock, IrqFlags); */
1172 for (i = 0; i < MGMT_RING_SIZE; i++) {
1173 pMLMEContext = (struct rt_tx_context *)pAd->MgmtRing.Cell[i].AllocVa;
1174 if (pMLMEContext && (pMLMEContext->IRPPending == TRUE)) {
1176 /* Get the USB_CONTEXT and cancel it's IRP; the completion routine will itself */
1177 /* remove it from the HeadPendingSendList and NULL out HeadPendingSendList */
1178 /* when the last IRP on the list has been cancelled; that's how we exit this loop */
1181 RTUSB_UNLINK_URB(pMLMEContext->pUrb);
1182 pMLMEContext->IRPPending = FALSE;
1184 /* Sleep 200 microsecs to give cancellation time to work */
1188 pAd->BulkOutPending[MGMTPIPEIDX] = FALSE;
1189 /*RTMP_IRQ_UNLOCK(pLock, IrqFlags); */
1191 for (i = 0; i < BEACON_RING_SIZE; i++) {
1192 pBeaconContext = &(pAd->BeaconContext[i]);
1194 if (pBeaconContext->IRPPending == TRUE) {
1196 /* Get the USB_CONTEXT and cancel it's IRP; the completion routine will itself */
1197 /* remove it from the HeadPendingSendList and NULL out HeadPendingSendList */
1198 /* when the last IRP on the list has been cancelled; that's how we exit this loop */
1201 RTUSB_UNLINK_URB(pBeaconContext->pUrb);
1203 /* Sleep 200 microsecs to give cancellation time to work */
1208 pNullContext = &(pAd->NullContext);
1209 if (pNullContext->IRPPending == TRUE)
1210 RTUSB_UNLINK_URB(pNullContext->pUrb);
1212 pRTSContext = &(pAd->RTSContext);
1213 if (pRTSContext->IRPPending == TRUE)
1214 RTUSB_UNLINK_URB(pRTSContext->pUrb);
1216 pPsPollContext = &(pAd->PsPollContext);
1217 if (pPsPollContext->IRPPending == TRUE)
1218 RTUSB_UNLINK_URB(pPsPollContext->pUrb);
1220 for (Idx = 0; Idx < 4; Idx++) {
1221 NdisAcquireSpinLock(&pAd->BulkOutLock[Idx]);
1222 pAd->BulkOutPending[Idx] = FALSE;
1223 NdisReleaseSpinLock(&pAd->BulkOutLock[Idx]);
1227 #endif /* RTMP_MAC_USB // */