| /* |
| ************************************************************************* |
| * Ralink Tech Inc. |
| * 5F., No.36, Taiyuan St., Jhubei City, |
| * Hsinchu County 302, |
| * Taiwan, R.O.C. |
| * |
| * (c) Copyright 2002-2007, Ralink Technology, Inc. |
| * |
| * This program is free software; you can redistribute it and/or modify * |
| * it under the terms of the GNU General Public License as published by * |
| * the Free Software Foundation; either version 2 of the License, or * |
| * (at your option) any later version. * |
| * * |
| * This program is distributed in the hope that it will be useful, * |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of * |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
| * GNU General Public License for more details. * |
| * * |
| * You should have received a copy of the GNU General Public License * |
| * along with this program; if not, write to the * |
| * Free Software Foundation, Inc., * |
| * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * |
| * * |
| ************************************************************************* |
| |
| Module Name: |
| rtusb_bulk.c |
| |
| Abstract: |
| |
| Revision History: |
| Who When What |
| -------- ---------- ---------------------------------------------- |
| Name Date Modification logs |
| |
| */ |
| |
| #include "rt_config.h" |
| |
| void dump_urb(struct urb *purb) |
| { |
| printk("urb :0x%08lx\n", (unsigned long)purb); |
| printk("\tdev :0x%08lx\n", (unsigned long)purb->dev); |
| printk("\t\tdev->state :0x%d\n", purb->dev->state); |
| printk("\tpipe :0x%08x\n", purb->pipe); |
| printk("\tstatus :%d\n", purb->status); |
| printk("\ttransfer_flags :0x%08x\n", purb->transfer_flags); |
| printk("\ttransfer_buffer :0x%08lx\n", |
| (unsigned long)purb->transfer_buffer); |
| printk("\ttransfer_buffer_length:%d\n", purb->transfer_buffer_length); |
| printk("\tactual_length :%d\n", purb->actual_length); |
| printk("\tsetup_packet :0x%08lx\n", |
| (unsigned long)purb->setup_packet); |
| printk("\tstart_frame :%d\n", purb->start_frame); |
| printk("\tnumber_of_packets :%d\n", purb->number_of_packets); |
| printk("\tinterval :%d\n", purb->interval); |
| printk("\terror_count :%d\n", purb->error_count); |
| printk("\tcontext :0x%08lx\n", |
| (unsigned long)purb->context); |
| printk("\tcomplete :0x%08lx\n\n", |
| (unsigned long)purb->complete); |
| } |
| |
| /* |
| ======================================================================== |
| Routine Description: |
| Create kernel threads & tasklets. |
| |
| Arguments: |
| *net_dev Pointer to wireless net device interface |
| |
| Return Value: |
| NDIS_STATUS_SUCCESS |
| NDIS_STATUS_FAILURE |
| |
| Note: |
| ======================================================================== |
| */ |
| int RtmpMgmtTaskInit(IN RTMP_ADAPTER * pAd) |
| { |
| RTMP_OS_TASK *pTask; |
| int status; |
| |
| /* |
| Creat TimerQ Thread, We need init timerQ related structure before create the timer thread. |
| */ |
| RtmpTimerQInit(pAd); |
| |
| pTask = &pAd->timerTask; |
| RtmpOSTaskInit(pTask, "RtmpTimerTask", pAd); |
| status = RtmpOSTaskAttach(pTask, RtmpTimerQThread, pTask); |
| if (status == NDIS_STATUS_FAILURE) { |
| printk(KERN_WARNING "%s: unable to start RtmpTimerQThread\n", |
| RTMP_OS_NETDEV_GET_DEVNAME(pAd->net_dev)); |
| return NDIS_STATUS_FAILURE; |
| } |
| |
| /* Creat MLME Thread */ |
| pTask = &pAd->mlmeTask; |
| RtmpOSTaskInit(pTask, "RtmpMlmeTask", pAd); |
| status = RtmpOSTaskAttach(pTask, MlmeThread, pTask); |
| if (status == NDIS_STATUS_FAILURE) { |
| printk(KERN_WARNING "%s: unable to start MlmeThread\n", |
| RTMP_OS_NETDEV_GET_DEVNAME(pAd->net_dev)); |
| return NDIS_STATUS_FAILURE; |
| } |
| |
| /* Creat Command Thread */ |
| pTask = &pAd->cmdQTask; |
| RtmpOSTaskInit(pTask, "RtmpCmdQTask", pAd); |
| status = RtmpOSTaskAttach(pTask, RTUSBCmdThread, pTask); |
| if (status == NDIS_STATUS_FAILURE) { |
| printk(KERN_WARNING "%s: unable to start RTUSBCmdThread\n", |
| RTMP_OS_NETDEV_GET_DEVNAME(pAd->net_dev)); |
| return NDIS_STATUS_FAILURE; |
| } |
| |
| return NDIS_STATUS_SUCCESS; |
| } |
| |
| /* |
| ======================================================================== |
| Routine Description: |
| Close kernel threads. |
| |
| Arguments: |
| *pAd the raxx interface data pointer |
| |
| Return Value: |
| NONE |
| |
| Note: |
| ======================================================================== |
| */ |
| void RtmpMgmtTaskExit(IN RTMP_ADAPTER * pAd) |
| { |
| int ret; |
| RTMP_OS_TASK *pTask; |
| |
| /* Sleep 50 milliseconds so pending io might finish normally */ |
| RTMPusecDelay(50000); |
| |
| /* We want to wait until all pending receives and sends to the */ |
| /* device object. We cancel any */ |
| /* irps. Wait until sends and receives have stopped. */ |
| RTUSBCancelPendingIRPs(pAd); |
| |
| /* We need clear timerQ related structure before exits of the timer thread. */ |
| RtmpTimerQExit(pAd); |
| |
| /* Terminate Mlme Thread */ |
| pTask = &pAd->mlmeTask; |
| ret = RtmpOSTaskKill(pTask); |
| if (ret == NDIS_STATUS_FAILURE) { |
| DBGPRINT(RT_DEBUG_ERROR, ("%s: kill task(%s) failed!\n", |
| RTMP_OS_NETDEV_GET_DEVNAME(pAd-> |
| net_dev), |
| pTask->taskName)); |
| } |
| |
| /* Terminate cmdQ thread */ |
| pTask = &pAd->cmdQTask; |
| #ifdef KTHREAD_SUPPORT |
| if (pTask->kthread_task) |
| #else |
| CHECK_PID_LEGALITY(pTask->taskPID) |
| #endif |
| { |
| mb(); |
| NdisAcquireSpinLock(&pAd->CmdQLock); |
| pAd->CmdQ.CmdQState = RTMP_TASK_STAT_STOPED; |
| NdisReleaseSpinLock(&pAd->CmdQLock); |
| mb(); |
| /*RTUSBCMDUp(pAd); */ |
| ret = RtmpOSTaskKill(pTask); |
| if (ret == NDIS_STATUS_FAILURE) { |
| DBGPRINT(RT_DEBUG_ERROR, ("%s: kill task(%s) failed!\n", |
| RTMP_OS_NETDEV_GET_DEVNAME |
| (pAd->net_dev), |
| pTask->taskName)); |
| } |
| pAd->CmdQ.CmdQState = RTMP_TASK_STAT_UNKNOWN; |
| } |
| |
| /* Terminate timer thread */ |
| pTask = &pAd->timerTask; |
| ret = RtmpOSTaskKill(pTask); |
| if (ret == NDIS_STATUS_FAILURE) { |
| DBGPRINT(RT_DEBUG_ERROR, ("%s: kill task(%s) failed!\n", |
| RTMP_OS_NETDEV_GET_DEVNAME(pAd-> |
| net_dev), |
| pTask->taskName)); |
| } |
| |
| } |
| |
| static void rtusb_dataout_complete(unsigned long data) |
| { |
| PRTMP_ADAPTER pAd; |
| struct urb *pUrb; |
| struct os_cookie *pObj; |
| PHT_TX_CONTEXT pHTTXContext; |
| u8 BulkOutPipeId; |
| int Status; |
| unsigned long IrqFlags; |
| |
| pUrb = (struct urb *)data; |
| pHTTXContext = (PHT_TX_CONTEXT) pUrb->context; |
| pAd = pHTTXContext->pAd; |
| pObj = (struct os_cookie *)pAd->OS_Cookie; |
| Status = pUrb->status; |
| |
| /* Store BulkOut PipeId */ |
| BulkOutPipeId = pHTTXContext->BulkOutPipeId; |
| pAd->BulkOutDataOneSecCount++; |
| |
| /*DBGPRINT(RT_DEBUG_LOUD, ("Done-B(%d):I=0x%lx, CWPos=%ld, NBPos=%ld, ENBPos=%ld, bCopy=%d!\n", BulkOutPipeId, in_interrupt(), pHTTXContext->CurWritePosition, */ |
| /* pHTTXContext->NextBulkOutPosition, pHTTXContext->ENextBulkOutPosition, pHTTXContext->bCopySavePad)); */ |
| |
| RTMP_IRQ_LOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); |
| pAd->BulkOutPending[BulkOutPipeId] = FALSE; |
| pHTTXContext->IRPPending = FALSE; |
| pAd->watchDogTxPendingCnt[BulkOutPipeId] = 0; |
| |
| if (Status == USB_ST_NOERROR) { |
| pAd->BulkOutComplete++; |
| |
| RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); |
| |
| pAd->Counters8023.GoodTransmits++; |
| /*RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); */ |
| FREE_HTTX_RING(pAd, BulkOutPipeId, pHTTXContext); |
| /*RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); */ |
| |
| } else /* STATUS_OTHER */ |
| { |
| u8 *pBuf; |
| |
| pAd->BulkOutCompleteOther++; |
| |
| pBuf = |
| &pHTTXContext->TransferBuffer->field. |
| WirelessPacket[pHTTXContext->NextBulkOutPosition]; |
| |
| if (!RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | |
| fRTMP_ADAPTER_HALT_IN_PROGRESS | |
| fRTMP_ADAPTER_NIC_NOT_EXIST | |
| fRTMP_ADAPTER_BULKOUT_RESET))) { |
| RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); |
| pAd->bulkResetPipeid = BulkOutPipeId; |
| pAd->bulkResetReq[BulkOutPipeId] = pAd->BulkOutReq; |
| } |
| RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); |
| |
| DBGPRINT_RAW(RT_DEBUG_ERROR, |
| ("BulkOutDataPacket failed: ReasonCode=%d!\n", |
| Status)); |
| DBGPRINT_RAW(RT_DEBUG_ERROR, |
| ("\t>>BulkOut Req=0x%lx, Complete=0x%lx, Other=0x%lx\n", |
| pAd->BulkOutReq, pAd->BulkOutComplete, |
| pAd->BulkOutCompleteOther)); |
| DBGPRINT_RAW(RT_DEBUG_ERROR, |
| ("\t>>BulkOut Header:%x %x %x %x %x %x %x %x\n", |
| pBuf[0], pBuf[1], pBuf[2], pBuf[3], pBuf[4], |
| pBuf[5], pBuf[6], pBuf[7])); |
| /*DBGPRINT_RAW(RT_DEBUG_ERROR, (">>BulkOutCompleteCancel=0x%x, BulkOutCompleteOther=0x%x\n", pAd->BulkOutCompleteCancel, pAd->BulkOutCompleteOther)); */ |
| |
| } |
| |
| /* */ |
| /* bInUse = TRUE, means some process are filling TX data, after that must turn on bWaitingBulkOut */ |
| /* bWaitingBulkOut = TRUE, means the TX data are waiting for bulk out. */ |
| /* */ |
| /*RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); */ |
| if ((pHTTXContext->ENextBulkOutPosition != |
| pHTTXContext->CurWritePosition) |
| && (pHTTXContext->ENextBulkOutPosition != |
| (pHTTXContext->CurWritePosition + 8)) |
| && !RTUSB_TEST_BULK_FLAG(pAd, |
| (fRTUSB_BULK_OUT_DATA_FRAG << |
| BulkOutPipeId))) { |
| /* Indicate There is data avaliable */ |
| RTUSB_SET_BULK_FLAG(pAd, |
| (fRTUSB_BULK_OUT_DATA_NORMAL << |
| BulkOutPipeId)); |
| } |
| /*RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); */ |
| |
| /* Always call Bulk routine, even reset bulk. */ |
| /* The protection of rest bulk should be in BulkOut routine */ |
| RTUSBKickBulkOut(pAd); |
| } |
| |
| static void rtusb_null_frame_done_tasklet(unsigned long data) |
| { |
| PRTMP_ADAPTER pAd; |
| PTX_CONTEXT pNullContext; |
| struct urb *pUrb; |
| int Status; |
| unsigned long irqFlag; |
| |
| pUrb = (struct urb *)data; |
| pNullContext = (PTX_CONTEXT) pUrb->context; |
| pAd = pNullContext->pAd; |
| Status = pUrb->status; |
| |
| /* Reset Null frame context flags */ |
| RTMP_IRQ_LOCK(&pAd->BulkOutLock[0], irqFlag); |
| pNullContext->IRPPending = FALSE; |
| pNullContext->InUse = FALSE; |
| pAd->BulkOutPending[0] = FALSE; |
| pAd->watchDogTxPendingCnt[0] = 0; |
| |
| if (Status == USB_ST_NOERROR) { |
| RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], irqFlag); |
| |
| RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); |
| } else /* STATUS_OTHER */ |
| { |
| if ((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) && |
| (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) && |
| (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) && |
| (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET))) { |
| DBGPRINT_RAW(RT_DEBUG_ERROR, |
| ("Bulk Out Null Frame Failed, ReasonCode=%d!\n", |
| Status)); |
| RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); |
| pAd->bulkResetPipeid = |
| (MGMTPIPEIDX | BULKOUT_MGMT_RESET_FLAG); |
| RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], irqFlag); |
| RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, |
| NULL, 0); |
| } else { |
| RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], irqFlag); |
| } |
| } |
| |
| /* Always call Bulk routine, even reset bulk. */ |
| /* The protectioon of rest bulk should be in BulkOut routine */ |
| RTUSBKickBulkOut(pAd); |
| } |
| |
| static void rtusb_rts_frame_done_tasklet(unsigned long data) |
| { |
| PRTMP_ADAPTER pAd; |
| PTX_CONTEXT pRTSContext; |
| struct urb *pUrb; |
| int Status; |
| unsigned long irqFlag; |
| |
| pUrb = (struct urb *)data; |
| pRTSContext = (PTX_CONTEXT) pUrb->context; |
| pAd = pRTSContext->pAd; |
| Status = pUrb->status; |
| |
| /* Reset RTS frame context flags */ |
| RTMP_IRQ_LOCK(&pAd->BulkOutLock[0], irqFlag); |
| pRTSContext->IRPPending = FALSE; |
| pRTSContext->InUse = FALSE; |
| |
| if (Status == USB_ST_NOERROR) { |
| RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], irqFlag); |
| RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); |
| } else /* STATUS_OTHER */ |
| { |
| if ((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) && |
| (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) && |
| (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) && |
| (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET))) { |
| DBGPRINT_RAW(RT_DEBUG_ERROR, |
| ("Bulk Out RTS Frame Failed\n")); |
| RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); |
| pAd->bulkResetPipeid = |
| (MGMTPIPEIDX | BULKOUT_MGMT_RESET_FLAG); |
| RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], irqFlag); |
| RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, |
| NULL, 0); |
| } else { |
| RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], irqFlag); |
| } |
| } |
| |
| RTMP_SEM_LOCK(&pAd->BulkOutLock[pRTSContext->BulkOutPipeId]); |
| pAd->BulkOutPending[pRTSContext->BulkOutPipeId] = FALSE; |
| RTMP_SEM_UNLOCK(&pAd->BulkOutLock[pRTSContext->BulkOutPipeId]); |
| |
| /* Always call Bulk routine, even reset bulk. */ |
| /* The protectioon of rest bulk should be in BulkOut routine */ |
| RTUSBKickBulkOut(pAd); |
| |
| } |
| |
| static void rtusb_pspoll_frame_done_tasklet(unsigned long data) |
| { |
| PRTMP_ADAPTER pAd; |
| PTX_CONTEXT pPsPollContext; |
| struct urb *pUrb; |
| int Status; |
| |
| pUrb = (struct urb *)data; |
| pPsPollContext = (PTX_CONTEXT) pUrb->context; |
| pAd = pPsPollContext->pAd; |
| Status = pUrb->status; |
| |
| /* Reset PsPoll context flags */ |
| pPsPollContext->IRPPending = FALSE; |
| pPsPollContext->InUse = FALSE; |
| pAd->watchDogTxPendingCnt[0] = 0; |
| |
| if (Status == USB_ST_NOERROR) { |
| RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); |
| } else /* STATUS_OTHER */ |
| { |
| if ((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) && |
| (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) && |
| (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) && |
| (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET))) { |
| DBGPRINT_RAW(RT_DEBUG_ERROR, |
| ("Bulk Out PSPoll Failed\n")); |
| RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); |
| pAd->bulkResetPipeid = |
| (MGMTPIPEIDX | BULKOUT_MGMT_RESET_FLAG); |
| RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, |
| NULL, 0); |
| } |
| } |
| |
| RTMP_SEM_LOCK(&pAd->BulkOutLock[0]); |
| pAd->BulkOutPending[0] = FALSE; |
| RTMP_SEM_UNLOCK(&pAd->BulkOutLock[0]); |
| |
| /* Always call Bulk routine, even reset bulk. */ |
| /* The protectioon of rest bulk should be in BulkOut routine */ |
| RTUSBKickBulkOut(pAd); |
| |
| } |
| |
| /* |
| ======================================================================== |
| Routine Description: |
| Handle received packets. |
| |
| Arguments: |
| data - URB information pointer |
| |
| Return Value: |
| None |
| |
| Note: |
| ======================================================================== |
| */ |
| static void rx_done_tasklet(unsigned long data) |
| { |
| struct urb *pUrb; |
| PRX_CONTEXT pRxContext; |
| PRTMP_ADAPTER pAd; |
| int Status; |
| unsigned int IrqFlags; |
| |
| pUrb = (struct urb *)data; |
| pRxContext = (PRX_CONTEXT) pUrb->context; |
| pAd = pRxContext->pAd; |
| Status = pUrb->status; |
| |
| RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags); |
| pRxContext->InUse = FALSE; |
| pRxContext->IRPPending = FALSE; |
| pRxContext->BulkInOffset += pUrb->actual_length; |
| /*NdisInterlockedDecrement(&pAd->PendingRx); */ |
| pAd->PendingRx--; |
| |
| if (Status == USB_ST_NOERROR) { |
| pAd->BulkInComplete++; |
| pAd->NextRxBulkInPosition = 0; |
| if (pRxContext->BulkInOffset) /* As jan's comment, it may bulk-in success but size is zero. */ |
| { |
| pRxContext->Readable = TRUE; |
| INC_RING_INDEX(pAd->NextRxBulkInIndex, RX_RING_SIZE); |
| } |
| RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); |
| } else /* STATUS_OTHER */ |
| { |
| pAd->BulkInCompleteFail++; |
| /* Still read this packet although it may comtain wrong bytes. */ |
| pRxContext->Readable = FALSE; |
| RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); |
| |
| /* Parsing all packets. because after reset, the index will reset to all zero. */ |
| if ((!RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | |
| fRTMP_ADAPTER_BULKIN_RESET | |
| fRTMP_ADAPTER_HALT_IN_PROGRESS | |
| fRTMP_ADAPTER_NIC_NOT_EXIST)))) { |
| |
| DBGPRINT_RAW(RT_DEBUG_ERROR, |
| ("Bulk In Failed. Status=%d, BIIdx=0x%x, BIRIdx=0x%x, actual_length= 0x%x\n", |
| Status, pAd->NextRxBulkInIndex, |
| pAd->NextRxBulkInReadIndex, |
| pRxContext->pUrb->actual_length)); |
| |
| RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKIN_RESET); |
| RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_IN, |
| NULL, 0); |
| } |
| } |
| |
| ASSERT((pRxContext->InUse == pRxContext->IRPPending)); |
| |
| RTUSBBulkReceive(pAd); |
| |
| return; |
| |
| } |
| |
| static void rtusb_mgmt_dma_done_tasklet(unsigned long data) |
| { |
| PRTMP_ADAPTER pAd; |
| PTX_CONTEXT pMLMEContext; |
| int index; |
| void *pPacket; |
| struct urb *pUrb; |
| int Status; |
| unsigned long IrqFlags; |
| |
| pUrb = (struct urb *)data; |
| pMLMEContext = (PTX_CONTEXT) pUrb->context; |
| pAd = pMLMEContext->pAd; |
| Status = pUrb->status; |
| index = pMLMEContext->SelfIdx; |
| |
| ASSERT((pAd->MgmtRing.TxDmaIdx == index)); |
| |
| RTMP_IRQ_LOCK(&pAd->BulkOutLock[MGMTPIPEIDX], IrqFlags); |
| |
| if (Status != USB_ST_NOERROR) { |
| /*Bulk-Out fail status handle */ |
| if ((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) && |
| (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) && |
| (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) && |
| (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET))) { |
| DBGPRINT_RAW(RT_DEBUG_ERROR, |
| ("Bulk Out MLME Failed, Status=%d!\n", |
| Status)); |
| /* TODO: How to handle about the MLMEBulkOut failed issue. Need to resend the mgmt pkt? */ |
| RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); |
| pAd->bulkResetPipeid = |
| (MGMTPIPEIDX | BULKOUT_MGMT_RESET_FLAG); |
| } |
| } |
| |
| pAd->BulkOutPending[MGMTPIPEIDX] = FALSE; |
| RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[MGMTPIPEIDX], IrqFlags); |
| |
| RTMP_IRQ_LOCK(&pAd->MLMEBulkOutLock, IrqFlags); |
| /* Reset MLME context flags */ |
| pMLMEContext->IRPPending = FALSE; |
| pMLMEContext->InUse = FALSE; |
| pMLMEContext->bWaitingBulkOut = FALSE; |
| pMLMEContext->BulkOutSize = 0; |
| |
| pPacket = pAd->MgmtRing.Cell[index].pNdisPacket; |
| pAd->MgmtRing.Cell[index].pNdisPacket = NULL; |
| |
| /* Increase MgmtRing Index */ |
| INC_RING_INDEX(pAd->MgmtRing.TxDmaIdx, MGMT_RING_SIZE); |
| pAd->MgmtRing.TxSwFreeIdx++; |
| RTMP_IRQ_UNLOCK(&pAd->MLMEBulkOutLock, IrqFlags); |
| |
| /* No-matter success or fail, we free the mgmt packet. */ |
| if (pPacket) |
| RTMPFreeNdisPacket(pAd, pPacket); |
| |
| if ((RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | |
| fRTMP_ADAPTER_HALT_IN_PROGRESS | |
| fRTMP_ADAPTER_NIC_NOT_EXIST)))) { |
| /* do nothing and return directly. */ |
| } else { |
| if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET) && ((pAd->bulkResetPipeid & BULKOUT_MGMT_RESET_FLAG) == BULKOUT_MGMT_RESET_FLAG)) { /* For Mgmt Bulk-Out failed, ignore it now. */ |
| RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, |
| NULL, 0); |
| } else { |
| |
| /* Always call Bulk routine, even reset bulk. */ |
| /* The protectioon of rest bulk should be in BulkOut routine */ |
| if (pAd->MgmtRing.TxSwFreeIdx < |
| MGMT_RING_SIZE |
| /* pMLMEContext->bWaitingBulkOut == TRUE */ ) { |
| RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_MLME); |
| } |
| RTUSBKickBulkOut(pAd); |
| } |
| } |
| |
| } |
| |
| static void rtusb_ac3_dma_done_tasklet(unsigned long data) |
| { |
| PRTMP_ADAPTER pAd; |
| PHT_TX_CONTEXT pHTTXContext; |
| u8 BulkOutPipeId = 3; |
| struct urb *pUrb; |
| |
| pUrb = (struct urb *)data; |
| pHTTXContext = (PHT_TX_CONTEXT) pUrb->context; |
| pAd = pHTTXContext->pAd; |
| |
| rtusb_dataout_complete((unsigned long)pUrb); |
| |
| if ((RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | |
| fRTMP_ADAPTER_HALT_IN_PROGRESS | |
| fRTMP_ADAPTER_NIC_NOT_EXIST)))) { |
| /* do nothing and return directly. */ |
| } else { |
| if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET)) { |
| RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, |
| NULL, 0); |
| } else { |
| pHTTXContext = &pAd->TxContext[BulkOutPipeId]; |
| if ((pAd->TxSwQueue[BulkOutPipeId].Number > 0) && |
| /*((pHTTXContext->CurWritePosition > (pHTTXContext->NextBulkOutPosition + 0x6000)) || (pHTTXContext->NextBulkOutPosition > pHTTXContext->CurWritePosition + 0x6000)) && */ |
| (pAd->DeQueueRunning[BulkOutPipeId] == FALSE) && |
| (pHTTXContext->bCurWriting == FALSE)) { |
| RTMPDeQueuePacket(pAd, FALSE, BulkOutPipeId, |
| MAX_TX_PROCESS); |
| } |
| |
| RTUSB_SET_BULK_FLAG(pAd, |
| fRTUSB_BULK_OUT_DATA_NORMAL << 3); |
| RTUSBKickBulkOut(pAd); |
| } |
| } |
| |
| return; |
| } |
| |
| static void rtusb_ac2_dma_done_tasklet(unsigned long data) |
| { |
| PRTMP_ADAPTER pAd; |
| PHT_TX_CONTEXT pHTTXContext; |
| u8 BulkOutPipeId = 2; |
| struct urb *pUrb; |
| |
| pUrb = (struct urb *)data; |
| pHTTXContext = (PHT_TX_CONTEXT) pUrb->context; |
| pAd = pHTTXContext->pAd; |
| |
| rtusb_dataout_complete((unsigned long)pUrb); |
| |
| if ((RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | |
| fRTMP_ADAPTER_HALT_IN_PROGRESS | |
| fRTMP_ADAPTER_NIC_NOT_EXIST)))) { |
| /* do nothing and return directly. */ |
| } else { |
| if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET)) { |
| RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, |
| NULL, 0); |
| } else { |
| pHTTXContext = &pAd->TxContext[BulkOutPipeId]; |
| if ((pAd->TxSwQueue[BulkOutPipeId].Number > 0) && |
| /*((pHTTXContext->CurWritePosition > (pHTTXContext->NextBulkOutPosition + 0x6000)) || (pHTTXContext->NextBulkOutPosition > pHTTXContext->CurWritePosition + 0x6000)) && */ |
| (pAd->DeQueueRunning[BulkOutPipeId] == FALSE) && |
| (pHTTXContext->bCurWriting == FALSE)) { |
| RTMPDeQueuePacket(pAd, FALSE, BulkOutPipeId, |
| MAX_TX_PROCESS); |
| } |
| |
| RTUSB_SET_BULK_FLAG(pAd, |
| fRTUSB_BULK_OUT_DATA_NORMAL << 2); |
| RTUSBKickBulkOut(pAd); |
| } |
| } |
| |
| return; |
| } |
| |
| static void rtusb_ac1_dma_done_tasklet(unsigned long data) |
| { |
| PRTMP_ADAPTER pAd; |
| PHT_TX_CONTEXT pHTTXContext; |
| u8 BulkOutPipeId = 1; |
| struct urb *pUrb; |
| |
| pUrb = (struct urb *)data; |
| pHTTXContext = (PHT_TX_CONTEXT) pUrb->context; |
| pAd = pHTTXContext->pAd; |
| |
| rtusb_dataout_complete((unsigned long)pUrb); |
| |
| if ((RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | |
| fRTMP_ADAPTER_HALT_IN_PROGRESS | |
| fRTMP_ADAPTER_NIC_NOT_EXIST)))) { |
| /* do nothing and return directly. */ |
| } else { |
| if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET)) { |
| RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, |
| NULL, 0); |
| } else { |
| pHTTXContext = &pAd->TxContext[BulkOutPipeId]; |
| if ((pAd->TxSwQueue[BulkOutPipeId].Number > 0) && |
| /*((pHTTXContext->CurWritePosition > (pHTTXContext->NextBulkOutPosition + 0x6000)) || (pHTTXContext->NextBulkOutPosition > pHTTXContext->CurWritePosition + 0x6000)) && */ |
| (pAd->DeQueueRunning[BulkOutPipeId] == FALSE) && |
| (pHTTXContext->bCurWriting == FALSE)) { |
| RTMPDeQueuePacket(pAd, FALSE, BulkOutPipeId, |
| MAX_TX_PROCESS); |
| } |
| |
| RTUSB_SET_BULK_FLAG(pAd, |
| fRTUSB_BULK_OUT_DATA_NORMAL << 1); |
| RTUSBKickBulkOut(pAd); |
| } |
| } |
| return; |
| |
| } |
| |
| static void rtusb_ac0_dma_done_tasklet(unsigned long data) |
| { |
| PRTMP_ADAPTER pAd; |
| PHT_TX_CONTEXT pHTTXContext; |
| u8 BulkOutPipeId = 0; |
| struct urb *pUrb; |
| |
| pUrb = (struct urb *)data; |
| pHTTXContext = (PHT_TX_CONTEXT) pUrb->context; |
| pAd = pHTTXContext->pAd; |
| |
| rtusb_dataout_complete((unsigned long)pUrb); |
| |
| if ((RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | |
| fRTMP_ADAPTER_HALT_IN_PROGRESS | |
| fRTMP_ADAPTER_NIC_NOT_EXIST)))) { |
| /* do nothing and return directly. */ |
| } else { |
| if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET)) { |
| RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, |
| NULL, 0); |
| } else { |
| pHTTXContext = &pAd->TxContext[BulkOutPipeId]; |
| if ((pAd->TxSwQueue[BulkOutPipeId].Number > 0) && |
| /* ((pHTTXContext->CurWritePosition > (pHTTXContext->NextBulkOutPosition + 0x6000)) || (pHTTXContext->NextBulkOutPosition > pHTTXContext->CurWritePosition + 0x6000)) && */ |
| (pAd->DeQueueRunning[BulkOutPipeId] == FALSE) && |
| (pHTTXContext->bCurWriting == FALSE)) { |
| RTMPDeQueuePacket(pAd, FALSE, BulkOutPipeId, |
| MAX_TX_PROCESS); |
| } |
| |
| RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL); |
| RTUSBKickBulkOut(pAd); |
| } |
| } |
| |
| return; |
| |
| } |
| |
| int RtmpNetTaskInit(IN RTMP_ADAPTER * pAd) |
| { |
| struct os_cookie *pObj = (struct os_cookie *)pAd->OS_Cookie; |
| |
| /* Create receive tasklet */ |
| tasklet_init(&pObj->rx_done_task, rx_done_tasklet, (unsigned long)pAd); |
| tasklet_init(&pObj->mgmt_dma_done_task, rtusb_mgmt_dma_done_tasklet, |
| (unsigned long)pAd); |
| tasklet_init(&pObj->ac0_dma_done_task, rtusb_ac0_dma_done_tasklet, |
| (unsigned long)pAd); |
| tasklet_init(&pObj->ac1_dma_done_task, rtusb_ac1_dma_done_tasklet, |
| (unsigned long)pAd); |
| tasklet_init(&pObj->ac2_dma_done_task, rtusb_ac2_dma_done_tasklet, |
| (unsigned long)pAd); |
| tasklet_init(&pObj->ac3_dma_done_task, rtusb_ac3_dma_done_tasklet, |
| (unsigned long)pAd); |
| tasklet_init(&pObj->tbtt_task, tbtt_tasklet, (unsigned long)pAd); |
| tasklet_init(&pObj->null_frame_complete_task, |
| rtusb_null_frame_done_tasklet, (unsigned long)pAd); |
| tasklet_init(&pObj->rts_frame_complete_task, |
| rtusb_rts_frame_done_tasklet, (unsigned long)pAd); |
| tasklet_init(&pObj->pspoll_frame_complete_task, |
| rtusb_pspoll_frame_done_tasklet, (unsigned long)pAd); |
| |
| return NDIS_STATUS_SUCCESS; |
| } |
| |
| void RtmpNetTaskExit(IN RTMP_ADAPTER * pAd) |
| { |
| struct os_cookie *pObj; |
| |
| pObj = (struct os_cookie *)pAd->OS_Cookie; |
| |
| tasklet_kill(&pObj->rx_done_task); |
| tasklet_kill(&pObj->mgmt_dma_done_task); |
| tasklet_kill(&pObj->ac0_dma_done_task); |
| tasklet_kill(&pObj->ac1_dma_done_task); |
| tasklet_kill(&pObj->ac2_dma_done_task); |
| tasklet_kill(&pObj->ac3_dma_done_task); |
| tasklet_kill(&pObj->tbtt_task); |
| tasklet_kill(&pObj->null_frame_complete_task); |
| tasklet_kill(&pObj->rts_frame_complete_task); |
| tasklet_kill(&pObj->pspoll_frame_complete_task); |
| } |