Linux-2.6.33.2/drivers/staging/rt2860/rt_usb.c

/*
 *************************************************************************
 * 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(struct rt_rtmp_adapter *pAd)
{
	struct rt_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(struct rt_rtmp_adapter *pAd)
{
	int ret;
	struct rt_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)
{
	struct rt_rtmp_adapter *pAd;
	struct urb *pUrb;
	struct os_cookie *pObj;
	struct rt_ht_tx_context *pHTTXContext;
	u8 BulkOutPipeId;
	int Status;
	unsigned long IrqFlags;

	pUrb = (struct urb *)data;
	pHTTXContext = (struct rt_ht_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)
{
	struct rt_rtmp_adapter *pAd;
	struct rt_tx_context *pNullContext;
	struct urb *pUrb;
	int Status;
	unsigned long irqFlag;

	pUrb = (struct urb *)data;
	pNullContext = (struct rt_tx_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)
{
	struct rt_rtmp_adapter *pAd;
	struct rt_tx_context *pRTSContext;
	struct urb *pUrb;
	int Status;
	unsigned long irqFlag;

	pUrb = (struct urb *)data;
	pRTSContext = (struct rt_tx_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)
{
	struct rt_rtmp_adapter *pAd;
	struct rt_tx_context *pPsPollContext;
	struct urb *pUrb;
	int Status;

	pUrb = (struct urb *)data;
	pPsPollContext = (struct rt_tx_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;
	struct rt_rx_context *pRxContext;
	struct rt_rtmp_adapter *pAd;
	int Status;
	unsigned int IrqFlags;

	pUrb = (struct urb *)data;
	pRxContext = (struct rt_rx_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)
{
	struct rt_rtmp_adapter *pAd;
	struct rt_tx_context *pMLMEContext;
	int index;
	void *pPacket;
	struct urb *pUrb;
	int Status;
	unsigned long IrqFlags;

	pUrb = (struct urb *)data;
	pMLMEContext = (struct rt_tx_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)
{
	struct rt_rtmp_adapter *pAd;
	struct rt_ht_tx_context *pHTTXContext;
	u8 BulkOutPipeId = 3;
	struct urb *pUrb;

	pUrb = (struct urb *)data;
	pHTTXContext = (struct rt_ht_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)
{
	struct rt_rtmp_adapter *pAd;
	struct rt_ht_tx_context *pHTTXContext;
	u8 BulkOutPipeId = 2;
	struct urb *pUrb;

	pUrb = (struct urb *)data;
	pHTTXContext = (struct rt_ht_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)
{
	struct rt_rtmp_adapter *pAd;
	struct rt_ht_tx_context *pHTTXContext;
	u8 BulkOutPipeId = 1;
	struct urb *pUrb;

	pUrb = (struct urb *)data;
	pHTTXContext = (struct rt_ht_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)
{
	struct rt_rtmp_adapter *pAd;
	struct rt_ht_tx_context *pHTTXContext;
	u8 BulkOutPipeId = 0;
	struct urb *pUrb;

	pUrb = (struct urb *)data;
	pHTTXContext = (struct rt_ht_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(struct rt_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(struct rt_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);
}