/*************************************************************************** 
 * RT2x00 SourceForge Project - http://rt2x00.sourceforge.net              * 
 *                                                                         * 
 *   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.             * 
 *                                                                         * 
 *   Licensed under the GNU GPL                                            * 
 *   Original code supplied under license from RaLink Inc, 2004.           * 
 ***************************************************************************/

/*************************************************************************** 
 *	Module Name:	rtusb_bulk.c
 *
 *	Abstract:
 *
 *	Revision History:
 *	Who		When		What
 *	--------	----------	-------------------------------
 *	Name		Date		Modification logs
 *	Jan Lee		2005-06-01	Release
 *	RobinC		02-06-2005	usb_kill_urb fixes for kernels =>2.6.7
 ***************************************************************************/

#include	"rt_config.h"
#ifndef URB_ASYNC_UNLINK
#define URB_ASYNC_UNLINK	0
#endif
//typedef VOID (*STATE_MACHINE_FUNC)(VOID *Adaptor, MLME_QUEUE_ELEM *Elem);

void RTusb_fill_bulk_urb (struct urb *pUrb,
	struct usb_device *usb,
	unsigned int bulkpipe,
	void *TransferBuf,
	int BufSize,
	usb_complete_t Complete,
	void *Context)
{

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
usb_fill_bulk_urb(pUrb, usb, bulkpipe, TransferBuf, BufSize, Complete, Context);	


#else
FILL_BULK_URB(pUrb, usb, bulkpipe, TransferBuf, BufSize, Complete, Context);	
#endif

}

/*
	========================================================================
	
	Routine Description:

	Arguments:

	Return Value:

	IRQL = 
	
	Note:
	
	========================================================================
*/
VOID	RTUSBBulkOutDataPacket(
	IN	PRT2570ADAPTER	pAdapter,
	IN	UCHAR	Index)
{
	PTX_CONTEXT pTxContext;
	PURB			pUrb;
	int ret = 0;
					
	NdisAcquireSpinLock(&pAdapter->BulkOutLock);
	if (pAdapter->BulkOutPending == TRUE)
	{
		NdisReleaseSpinLock(&pAdapter->BulkOutLock);
		return;
	}
	pAdapter->BulkOutPending = TRUE;
	NdisReleaseSpinLock(&pAdapter->BulkOutLock);
	pTxContext = &(pAdapter->TxContext[Index]);

	// Increase Total transmit byte counter
	pAdapter->RalinkCounters.TransmittedByteCount +=  pTxContext->BulkOutSize;

	// Clear Data flag
	RTUSB_CLEAR_BULK_FLAG(pAdapter, fRTUSB_BULK_OUT_DATA_FRAG);
	//The Data Bulk out protection is to Test InUse flag, temporarily not CLEAR DATA_NORMAL flag to test
	//RTUSB_CLEAR_BULK_FLAG(pAdapter, fRTUSB_BULK_OUT_DATA_NORMAL);
	pUrb = pTxContext->pUrb;
	if (pTxContext->InUse != TRUE)
	{
		DBGPRINT(RT_DEBUG_ERROR, "RTUSBBulkOutDataPacket failed, pTxContext->InUse != TRUE, Index %d, NextBulkOutIndex %d\n", Index, pAdapter->NextBulkOutIndex);
		NdisAcquireSpinLock(&pAdapter->BulkOutLock);
		pAdapter->BulkOutPending = FALSE;
		NdisReleaseSpinLock(&pAdapter->BulkOutLock);
		return;
	}
	else if (pAdapter->MediaState == NdisMediaStateDisconnected &&
		  !( pAdapter->PortCfg.BssType == BSS_MONITOR && pAdapter->PortCfg.MallowRFMONTx == TRUE   )
		)
	{
		//
		// Since there is no connection, so we need to empty the Tx Bulk out Ring.
		//
		while (atomic_read(&pAdapter->TxCount) > 0)
		{
			DBGPRINT(RT_DEBUG_ERROR, "RTUSBBulkOutDataPacket failed, snice NdisMediaStateDisconnected discard NextBulkOutIndex %d, NextIndex = %d\n", pAdapter->NextBulkOutIndex, pAdapter->NextTxIndex);
			FREE_TX_RING(pAdapter, pTxContext);			
			pTxContext = &(pAdapter->TxContext[pAdapter->NextBulkOutIndex]);
		}

		NdisAcquireSpinLock(&pAdapter->BulkOutLock);
		pAdapter->BulkOutPending = FALSE;
		NdisReleaseSpinLock(&pAdapter->BulkOutLock);
		
		return;
	}
		
	pTxContext->IRPPending = TRUE;

	RTusb_fill_bulk_urb(pUrb,
		pAdapter->usb,
		usb_sndbulkpipe(pAdapter->usb, 1),
		pTxContext->TransferBuffer,
		pTxContext->BulkOutSize,
		RTUSBBulkOutDataPacketComplete,
		pTxContext);

	if((ret = rtusb_submit_urb(pUrb))!=0)
	{
		DBGPRINT(RT_DEBUG_ERROR,"Submit Tx URB failed %d\n", ret);
		return;
	}
	DBGPRINT(RT_DEBUG_INFO,"<==RTUSBBulkOutDataPacket BulkOutSize = %d\n", pTxContext->BulkOutSize);

	return;
}

/*
	========================================================================
	
	Routine Description:

	Arguments:

	Return Value:

	IRQL = 
	
	Note:
	
	========================================================================
*/
VOID	RTUSBBulkOutNullFrame(
	IN	PRT2570ADAPTER	pAdapter)
{
	PTX_CONTEXT	pNullContext = &(pAdapter->NullContext);
	PURB			pUrb;
	int ret = 0;

	NdisAcquireSpinLock(&pAdapter->BulkOutLock);
	if (pAdapter->BulkOutPending == TRUE)
	{
		NdisReleaseSpinLock(&pAdapter->BulkOutLock);
		return;
	}
	pAdapter->BulkOutPending = TRUE;
	NdisReleaseSpinLock(&pAdapter->BulkOutLock);
	// Increase Total transmit byte counter
	pAdapter->RalinkCounters.TransmittedByteCount +=  pNullContext->BulkOutSize;

	DBGPRINT_RAW(RT_DEBUG_INFO, "--->RTUSBBulkOutNullFrame \n");
	
	pUrb = pNullContext->pUrb;
	RTusb_fill_bulk_urb(pUrb,
		pAdapter->usb,
		usb_sndbulkpipe(pAdapter->usb, 1),
		pNullContext->TransferBuffer,
		pNullContext->BulkOutSize,
		RTUSBBulkOutNullFrameComplete,
		pNullContext);

	if((ret = rtusb_submit_urb(pUrb))!=0)
	{
		DBGPRINT(RT_DEBUG_ERROR,"Submit Tx URB failed %d\n", ret);
		return;
	}
	DBGPRINT(RT_DEBUG_INFO,"<==RTUSBBulkOutDataPacket\n");

	return;
}

/*
	========================================================================
	
	Routine Description:

	Arguments:

	Return Value:

	IRQL = 
	
	Note:
	
	========================================================================
*/
VOID	RTUSBBulkOutMLMEPacket(
	IN	PRT2570ADAPTER	pAdapter,
	IN	UCHAR			Index)
{
	PTX_CONTEXT		pMLMEContext;
	PURB			pUrb;
	int ret = 0;
					
	pMLMEContext = &pAdapter->MLMEContext[Index];
	NdisAcquireSpinLock(&pAdapter->BulkOutLock);
	if (pAdapter->BulkOutPending == TRUE)
	{
		NdisReleaseSpinLock(&pAdapter->BulkOutLock);
		return;
	}
	pAdapter->BulkOutPending = TRUE;
	NdisReleaseSpinLock(&pAdapter->BulkOutLock);

	// Increase Total transmit byte counter
	pAdapter->RalinkCounters.TransmittedByteCount +=  pMLMEContext->BulkOutSize;

	// Clear MLME bulk flag
	RTUSB_CLEAR_BULK_FLAG(pAdapter, fRTUSB_BULK_OUT_MLME);

	DBGPRINT(RT_DEBUG_INFO, "RTUSBBulkOutMLMEPacket::PrioRingFirstIndex = %d, PrioRingTxCnt = %d, PopMgmtIndex = %d, PushMgmtIndex = %d, NextMLMEIndex = %d\n", 
			pAdapter->PrioRingFirstIndex, 
			pAdapter->PrioRingTxCnt, pAdapter->PopMgmtIndex, pAdapter->PushMgmtIndex, pAdapter->NextMLMEIndex);

	pMLMEContext->IRPPending = TRUE;

	pUrb = pMLMEContext->pUrb;
		
	RTusb_fill_bulk_urb(pUrb,
		pAdapter->usb,
		usb_sndbulkpipe(pAdapter->usb, 1),
		pMLMEContext->TransferBuffer,
		pMLMEContext->BulkOutSize,
		RTUSBBulkOutMLMEPacketComplete,
		pMLMEContext);
	
	if((ret = rtusb_submit_urb(pUrb))!=0)
	{
		DBGPRINT(RT_DEBUG_ERROR,"Submit MLME URB failed %d\n", ret);
		return;
	}
	DBGPRINT(RT_DEBUG_INFO,"<==RTUSBBulkOutMLMEPacket\n");

	return;
}








#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)

VOID RTUSBBulkOutDataPacketComplete(purbb_t pUrb,struct pt_regs *pt_regs)
{
	PTX_CONTEXT 	pTxContext;
	PRT2570ADAPTER	pAdapter;
	NTSTATUS		status;

	DBGPRINT_RAW(RT_DEBUG_INFO, "--->RTUSBBulkOutDataPacketComplete\n");
	pTxContext= (PTX_CONTEXT)pUrb->context;
	pAdapter = pTxContext->pAdapter;
	status = pUrb->status;
	if (status == USB_ST_NOERROR)
 	{
		if (pTxContext->LastOne == TRUE)
		{
			pAdapter->Counters.GoodTransmits++;
			FREE_TX_RING(pAdapter, pTxContext);

			if (!skb_queue_empty(&pAdapter->SendTxWaitQueue))
			{
				RTUSBDeQueuePacket(pAdapter);
			}
		}
		else
		{
			if ((!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RESET_IN_PROGRESS)) &&
				(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_HALT_IN_PROGRESS)) &&
				(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_REMOVE_IN_PROGRESS)) &&
				(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BULKOUT_RESET)))
			{
				FREE_TX_RING(pAdapter, pTxContext);
				// Indicate next one is frag data which has highest priority
				RTUSB_SET_BULK_FLAG(pAdapter, fRTUSB_BULK_OUT_DATA_FRAG);
			}
			else
			{
				while (pTxContext->LastOne != TRUE)
				{
					FREE_TX_RING(pAdapter, pTxContext);
					pTxContext = &(pAdapter->TxContext[pAdapter->NextBulkOutIndex]);
				}
				
				FREE_TX_RING(pAdapter, pTxContext);
			}
		}
 	}
	NdisAcquireSpinLock(&pAdapter->BulkOutLock);
	pAdapter->BulkOutPending = FALSE;
	NdisReleaseSpinLock(&pAdapter->BulkOutLock);
	// Always call Bulk routine, even reset bulk.
	// The protectioon of rest bulk should be in BulkOut routine
	RTUSBKickBulkOut(pAdapter);

	
}

VOID  RTUSBBulkOutNullFrameComplete(purbb_t pUrb,struct pt_regs *pt_regs)
{
	PRT2570ADAPTER	pAdapter;
	PTX_CONTEXT	pNullContext;
	NTSTATUS		status;
	
	pNullContext= (PTX_CONTEXT)pUrb->context;
	pAdapter = pNullContext->pAdapter;

	DBGPRINT_RAW(RT_DEBUG_INFO, "--->RTUSBBulkOutNullFrameComplete\n");

	// Reset Null frame context flags
	pNullContext->IRPPending = FALSE;
	pNullContext->InUse = FALSE;
	// Clear Null frame bulk flag
	RTUSB_CLEAR_BULK_FLAG(pAdapter, fRTUSB_BULK_OUT_DATA_NULL);

	status = pUrb->status;
	if (status == USB_ST_NOERROR)
	{
		// Don't worry about the queue is empty or not, this function will check itself
		RTUSBDeQueuePacket(pAdapter);
	}
	else
	{
		if ((!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RESET_IN_PROGRESS)) &&
			(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_HALT_IN_PROGRESS)) &&
			(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_REMOVE_IN_PROGRESS)) &&
			(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BULKOUT_RESET)))
		{
			DBGPRINT_RAW(RT_DEBUG_ERROR, "Bulk Out Null Frame Failed\n");
			RTMP_SET_FLAG(pAdapter, fRTMP_ADAPTER_BULKOUT_RESET);
			RTUSBEnqueueInternalCmd(pAdapter, RT_OID_USB_RESET_BULK_OUT);
		}
	}

	NdisAcquireSpinLock(&pAdapter->BulkOutLock);
	pAdapter->BulkOutPending = FALSE;
	NdisReleaseSpinLock(&pAdapter->BulkOutLock);

	// Always call Bulk routine, even reset bulk.
	// The protectioon of rest bulk should be in BulkOut routine
	RTUSBKickBulkOut(pAdapter);

	DBGPRINT_RAW(RT_DEBUG_INFO, "<---RTUSBBulkOutNullFrameComplete\n");

}

VOID	RTUSBBulkOutMLMEPacketComplete(purbb_t pUrb,struct pt_regs *pt_regs)
{
	PTX_CONTEXT			pMLMEContext;
	PRT2570ADAPTER		pAdapter;
	NTSTATUS		status;

	pMLMEContext= (PTX_CONTEXT)pUrb->context;
	pAdapter = pMLMEContext->pAdapter;
	status = pUrb->status;

	pAdapter->PrioRingTxCnt--;
	pAdapter->PrioRingFirstIndex++;
	if (pAdapter->PrioRingFirstIndex >= PRIO_RING_SIZE)
	{
		pAdapter->PrioRingFirstIndex = 0;
	}	

	DBGPRINT(RT_DEBUG_TRACE, ":: = %d,  = %d,   = %d,   = %d,   = %d\n", 
			pAdapter->PrioRingFirstIndex, 
			pAdapter->PrioRingTxCnt, pAdapter->PopMgmtIndex, pAdapter->PushMgmtIndex, pAdapter->NextMLMEIndex);
	
	// Reset MLME context flags
	pMLMEContext->IRPPending 	= FALSE;
	pMLMEContext->InUse 		= FALSE;
	
	if (status == STATUS_SUCCESS)
	{
		// Don't worry about the queue is empty or not, this function will check itself
		RTUSBDequeueMLMEPacket(pAdapter);
	}
#if 0
	else if (status != STATUS_CANCELLED)
	{
		if ((!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RESET_IN_PROGRESS)) &&
			(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_HALT_IN_PROGRESS)) &&
			(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_REMOVE_IN_PROGRESS)) &&
			(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BULKOUT_RESET)))
		{
			DBGPRINT_RAW(RT_DEBUG_ERROR, "Bulk Out MLME Failed\n");
			RTMP_SET_FLAG(pAdapter, fRTMP_ADAPTER_BULKOUT_RESET);
			RTUSBEnqueueInternalCmd(pAdapter, RT_OID_USB_RESET_BULK_OUT);
		}
	}
#endif
	NdisAcquireSpinLock(&pAdapter->BulkOutLock);
	pAdapter->BulkOutPending = FALSE;
	NdisReleaseSpinLock(&pAdapter->BulkOutLock);

	// Always call Bulk routine, even reset bulk.
	// The protectioon of rest bulk should be in BulkOut routine
	RTUSBKickBulkOut(pAdapter);

	DBGPRINT_RAW(RT_DEBUG_INFO, "<---RTUSBBulkOutMLMEPacketComplete\n");

}

/*
	========================================================================

	Routine Description:
		This routine process Rx Irp and call rx complete function.
		
	Arguments:
		DeviceObject	Pointer to the device object for next lower
						device. DeviceObject passed in here belongs to
						the next lower driver in the stack because we
						were invoked via IoCallDriver in USB_RxPacket
						AND it is not OUR device object
	  Irp				Ptr to completed IRP
	  Context			Ptr to our Adapter object (context specified
						in IoSetCompletionRoutine
		
	Return Value:
		Always returns STATUS_MORE_PROCESSING_REQUIRED

	Note:
		Always returns STATUS_MORE_PROCESSING_REQUIRED
	========================================================================
*/
VOID	RTUSBBulkRxComplete(purbb_t pUrb,struct pt_regs *pt_regs)
{

	PRX_CONTEXT 	pRxContext;
	PRT2570ADAPTER	pAdapter;
	NTSTATUS		status;
	
	pRxContext= (PRX_CONTEXT)pUrb->context;
	pAdapter = pRxContext->pAdapter;

	//
	// We have a number of cases:
	//		1) The USB read timed out and we received no data.
	//		2) The USB read timed out and we received some data.
	//		3) The USB read was successful and fully filled our irp buffer.
	//		4) The irp was cancelled.
	//		5) Some other failure from the USB device object.
	//
	
	//
	// Free the IRP  and its mdl because they were	alloced by us
	//
#if 0
	if ( (atomread = (atomic_read(&pRxContext->IrpLock))) == IRPLOCK_CANCE_START)
	{
		atomic_dec(&pAdapter->PendingRx);
		atomic_set(&pRxContext->IrpLock, IRPLOCK_CANCE_COMPLETE);	
	}
#endif
	status = pUrb->status;
	atomic_set(&pRxContext->IrpLock, IRPLOCK_COMPLETED);
	atomic_dec(&pAdapter->PendingRx);
	
	switch (status)
	{
		case 0:
			 if ((status == USB_ST_NOERROR) && (atomic_read(&pRxContext->IrpLock) != IRPLOCK_CANCE_START))
			{
				//RTUSBRxPacket(pUrb);
				pAdapter->rx_bh.data = (unsigned long)pUrb;
				tasklet_schedule(&pAdapter->rx_bh);
				break;
				
			}// STATUS_SUCCESS
		DBGPRINT(RT_DEBUG_TEMP,"==> RTUSBBulkRxComplete  (IrpLock) = %d\n", atomic_read(&pRxContext->IrpLock));
				break;
		
		case -ECONNRESET:		// async unlink
		case -ESHUTDOWN:		// hardware gone = -108
			pUrb = NULL;
		DBGPRINT(RT_DEBUG_TEMP,"==> RTUSBBulkRxComplete Error code = %d\n", status);
			//tasklet_schedule(&pAdapter->rx_bh);
			break;

	}
#if 0
	 if ((status == USB_ST_NOERROR) && (atomic_read(&pRxContext->IrpLock) != IRPLOCK_CANCE_START))
	{
		RTUSBRxPacket(pUrb);
		//tasklet_schedule(&pAdapter->rx_bh);
		
	}// STATUS_SUCCESS
	else
	{
		DBGPRINT(RT_DEBUG_TEMP,"==> RTUSBBulkRxComplete Error code = %d\n", status);
		pRxContext->InUse = FALSE;

		if ((!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RESET_IN_PROGRESS)) &&
			(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BULKIN_RESET)) &&
			(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_HALT_IN_PROGRESS)) &&
			(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_REMOVE_IN_PROGRESS)))
		{
			DBGPRINT_RAW(RT_DEBUG_ERROR, "Bulk In Failed\n");
			RTMP_SET_FLAG(pAdapter, fRTMP_ADAPTER_BULKIN_RESET);
			RTUSBEnqueueInternalCmd(pAdapter, RT_OID_USB_RESET_BULK_IN);
		}
	}

#endif
}

VOID	RTUSBBulkOutPsPollComplete(purbb_t pUrb, struct pt_regs *pt_regs)
{
	PTX_CONTEXT	pPsPollContext;
	PRT2570ADAPTER	pAdapter;
	NTSTATUS		status;
	
	pPsPollContext= (PTX_CONTEXT)pUrb->context;
	pAdapter = pPsPollContext->pAdapter;
	pPsPollContext->IRPPending 	= FALSE;
	pPsPollContext->InUse 		= FALSE;
	status = pUrb->status;
	if (status == USB_ST_NOERROR)
	{
		// Don't worry about the queue is empty or not, this function will check itself
		RTUSBDeQueuePacket(pAdapter);
	}
	else
	{
		if ((!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RESET_IN_PROGRESS)) &&
			(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_HALT_IN_PROGRESS)) &&
			(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_REMOVE_IN_PROGRESS)) &&
			(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BULKOUT_RESET)))
		{
			DBGPRINT_RAW(RT_DEBUG_ERROR, "Bulk Out Null Frame Failed\n");
			RTMP_SET_FLAG(pAdapter, fRTMP_ADAPTER_BULKOUT_RESET);
			RTUSBEnqueueInternalCmd(pAdapter, RT_OID_USB_RESET_BULK_OUT);
		}
	}

	NdisAcquireSpinLock(&pAdapter->BulkOutLock);
	pAdapter->BulkOutPending = FALSE;
	NdisReleaseSpinLock(&pAdapter->BulkOutLock);

	// Always call Bulk routine, even reset bulk.
	// The protectioon of rest bulk should be in BulkOut routine
	RTUSBKickBulkOut(pAdapter);

	DBGPRINT_RAW(RT_DEBUG_INFO, "<---RTUSBBulkOutNullFrameComplete\n");

}
VOID RTUSBBulkOutBeaconComplete(purbb_t pUrb,struct pt_regs *pt_regs)
{
	PRT2570ADAPTER	pAdapter;
	PTX_CONTEXT	pBeaconContext;
	
	pBeaconContext= (PTX_CONTEXT)pUrb->context;
	pAdapter = pBeaconContext->pAdapter;

	DBGPRINT_RAW(RT_DEBUG_TEMP, "--->RTUSBBulkOutBeaconComplete\n");

	// Reset Null frame context flags
	pBeaconContext->IRPPending = FALSE;
	pBeaconContext->InUse = FALSE;

	NdisAcquireSpinLock(&pAdapter->BulkOutLock);
	pAdapter->BulkOutPending = FALSE;
	NdisReleaseSpinLock(&pAdapter->BulkOutLock);

	// Always call Bulk routine, even reset bulk.
	// The protectioon of rest bulk should be in BulkOut routine
	RTUSBKickBulkOut(pAdapter);

}

#else

VOID RTUSBBulkOutDataPacketComplete(purbb_t pUrb)
{
	PTX_CONTEXT 	pTxContext;
	PRT2570ADAPTER	pAdapter;
	NTSTATUS		status;

	DBGPRINT_RAW(RT_DEBUG_INFO, "--->RTUSBBulkOutDataPacketComplete\n");
	pTxContext= (PTX_CONTEXT)pUrb->context;
	pAdapter = pTxContext->pAdapter;
	status = pUrb->status;
	if (status == USB_ST_NOERROR)
 	{
		if (pTxContext->LastOne == TRUE)
		{
			pAdapter->Counters.GoodTransmits++;
			FREE_TX_RING(pAdapter, pTxContext);

			if (!skb_queue_empty(&pAdapter->SendTxWaitQueue))
			{
				RTUSBDeQueuePacket(pAdapter);
			}
		}
		else
		{
			if ((!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RESET_IN_PROGRESS)) &&
				(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_HALT_IN_PROGRESS)) &&
				(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_REMOVE_IN_PROGRESS)) &&
				(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BULKOUT_RESET)))
			{
				FREE_TX_RING(pAdapter, pTxContext);
				// Indicate next one is frag data which has highest priority
				RTUSB_SET_BULK_FLAG(pAdapter, fRTUSB_BULK_OUT_DATA_FRAG);
			}
			else
			{
				while (pTxContext->LastOne != TRUE)
				{
					FREE_TX_RING(pAdapter, pTxContext);
					pTxContext = &(pAdapter->TxContext[pAdapter->NextBulkOutIndex]);
				}
				
				FREE_TX_RING(pAdapter, pTxContext);
			}
		}
 	}
	NdisAcquireSpinLock(&pAdapter->BulkOutLock);
	pAdapter->BulkOutPending = FALSE;
	NdisReleaseSpinLock(&pAdapter->BulkOutLock);
	// Always call Bulk routine, even reset bulk.
	// The protectioon of rest bulk should be in BulkOut routine
	RTUSBKickBulkOut(pAdapter);

	
}


VOID  RTUSBBulkOutNullFrameComplete(purbb_t pUrb)
{
	PRT2570ADAPTER	pAdapter;
	PTX_CONTEXT	pNullContext;
	NTSTATUS		status;
	
	pNullContext= (PTX_CONTEXT)pUrb->context;
	pAdapter = pNullContext->pAdapter;

	DBGPRINT_RAW(RT_DEBUG_INFO, "--->RTUSBBulkOutNullFrameComplete\n");

	// Reset Null frame context flags
	pNullContext->IRPPending = FALSE;
	pNullContext->InUse = FALSE;
	// Clear Null frame bulk flag
	RTUSB_CLEAR_BULK_FLAG(pAdapter, fRTUSB_BULK_OUT_DATA_NULL);

	status = pUrb->status;
	if (status == USB_ST_NOERROR)
	{
		// Don't worry about the queue is empty or not, this function will check itself
		RTUSBDeQueuePacket(pAdapter);
	}
	else
	{
		if ((!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RESET_IN_PROGRESS)) &&
			(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_HALT_IN_PROGRESS)) &&
			(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_REMOVE_IN_PROGRESS)) &&
			(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BULKOUT_RESET)))
		{
			DBGPRINT_RAW(RT_DEBUG_ERROR, "Bulk Out Null Frame Failed\n");
			RTMP_SET_FLAG(pAdapter, fRTMP_ADAPTER_BULKOUT_RESET);
			RTUSBEnqueueInternalCmd(pAdapter, RT_OID_USB_RESET_BULK_OUT);
		}
	}

	NdisAcquireSpinLock(&pAdapter->BulkOutLock);
	pAdapter->BulkOutPending = FALSE;
	NdisReleaseSpinLock(&pAdapter->BulkOutLock);

	// Always call Bulk routine, even reset bulk.
	// The protectioon of rest bulk should be in BulkOut routine
	RTUSBKickBulkOut(pAdapter);

	DBGPRINT_RAW(RT_DEBUG_INFO, "<---RTUSBBulkOutNullFrameComplete\n");

}

VOID  RTUSBBulkOutMLMEPacketComplete(purbb_t pUrb)
{
	PTX_CONTEXT			pMLMEContext;
	PRT2570ADAPTER		pAdapter;
	NTSTATUS		status;

	pMLMEContext= (PTX_CONTEXT)pUrb->context;
	pAdapter = pMLMEContext->pAdapter;
	status = pUrb->status;

	pAdapter->PrioRingTxCnt--;
	pAdapter->PrioRingFirstIndex++;
	if (pAdapter->PrioRingFirstIndex >= PRIO_RING_SIZE)
	{
		pAdapter->PrioRingFirstIndex = 0;
	}	

	DBGPRINT(RT_DEBUG_INFO, "RTUSBBulkOutMLMEPacketComplete::PrioRingFirstIndex = %d, PrioRingTxCnt = %d, PopMgmtIndex = %d, PushMgmtIndex = %d, NextMLMEIndex = %d\n", 
			pAdapter->PrioRingFirstIndex, 
			pAdapter->PrioRingTxCnt, pAdapter->PopMgmtIndex, pAdapter->PushMgmtIndex, pAdapter->NextMLMEIndex);

	
	// Reset MLME context flags
	pMLMEContext->IRPPending 	= FALSE;
	pMLMEContext->InUse 		= FALSE;
	
	if (status == STATUS_SUCCESS)
	{
		// Don't worry about the queue is empty or not, this function will check itself
		RTUSBDequeueMLMEPacket(pAdapter);
	}
#if 0
	else if (status != STATUS_CANCELLED)
	{
		if ((!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RESET_IN_PROGRESS)) &&
			(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_HALT_IN_PROGRESS)) &&
			(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_REMOVE_IN_PROGRESS)) &&
			(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BULKOUT_RESET)))
		{
			DBGPRINT_RAW(RT_DEBUG_ERROR, "Bulk Out MLME Failed\n");
			RTMP_SET_FLAG(pAdapter, fRTMP_ADAPTER_BULKOUT_RESET);
			RTUSBEnqueueInternalCmd(pAdapter, RT_OID_USB_RESET_BULK_OUT);
		}
	}
#endif
	NdisAcquireSpinLock(&pAdapter->BulkOutLock);
	pAdapter->BulkOutPending = FALSE;
	NdisReleaseSpinLock(&pAdapter->BulkOutLock);

	// Always call Bulk routine, even reset bulk.
	// The protectioon of rest bulk should be in BulkOut routine
	RTUSBKickBulkOut(pAdapter);

	DBGPRINT_RAW(RT_DEBUG_INFO, "<---RTUSBBulkOutMLMEPacketComplete\n");

}

/*
	========================================================================

	Routine Description:
		This routine process Rx Irp and call rx complete function.
		
	Arguments:
		DeviceObject	Pointer to the device object for next lower
						device. DeviceObject passed in here belongs to
						the next lower driver in the stack because we
						were invoked via IoCallDriver in USB_RxPacket
						AND it is not OUR device object
	  Irp				Ptr to completed IRP
	  Context			Ptr to our Adapter object (context specified
						in IoSetCompletionRoutine
		
	Return Value:
		Always returns STATUS_MORE_PROCESSING_REQUIRED

	Note:
		Always returns STATUS_MORE_PROCESSING_REQUIRED
	========================================================================
*/
VOID	RTUSBBulkRxComplete(purbb_t pUrb)
{

	PRX_CONTEXT 	pRxContext;
	PRT2570ADAPTER	pAdapter;
	NTSTATUS		status;
	
	pRxContext= (PRX_CONTEXT)pUrb->context;
	pAdapter = pRxContext->pAdapter;

	//
	// We have a number of cases:
	//		1) The USB read timed out and we received no data.
	//		2) The USB read timed out and we received some data.
	//		3) The USB read was successful and fully filled our irp buffer.
	//		4) The irp was cancelled.
	//		5) Some other failure from the USB device object.
	//
	
	//
	// Free the IRP  and its mdl because they were	alloced by us
	//
#if 0
	if ( (atomread = (atomic_read(&pRxContext->IrpLock))) == IRPLOCK_CANCE_START)
	{
		atomic_dec(&pAdapter->PendingRx);
		atomic_set(&pRxContext->IrpLock, IRPLOCK_CANCE_COMPLETE);	
	}
#endif
	status = pUrb->status;
	atomic_set(&pRxContext->IrpLock, IRPLOCK_COMPLETED);
	atomic_dec(&pAdapter->PendingRx);
	
	switch (status)
	{
		case 0:
			 if ((status == USB_ST_NOERROR) && (atomic_read(&pRxContext->IrpLock) != IRPLOCK_CANCE_START))
			{
				//RTUSBRxPacket(pUrb);
				pAdapter->rx_bh.data = (unsigned long)pUrb;
				tasklet_schedule(&pAdapter->rx_bh);
				break;
				
			}// STATUS_SUCCESS
		DBGPRINT(RT_DEBUG_TEMP,"==> RTUSBBulkRxComplete  (IrpLock) = %d\n", atomic_read(&pRxContext->IrpLock));
				break;
		
		case -ECONNRESET:		// async unlink
		case -ESHUTDOWN:		// hardware gone = -108
			pUrb = NULL;
		DBGPRINT(RT_DEBUG_ERROR,"==> RTUSBBulkRxComplete Error code = %d\n", status);
			//tasklet_schedule(&pAdapter->rx_bh);
			break;

	}
#if 0
	 if ((status == USB_ST_NOERROR) && (atomic_read(&pRxContext->IrpLock) != IRPLOCK_CANCE_START))
	{
		RTUSBRxPacket(pUrb);
		//tasklet_schedule(&pAdapter->rx_bh);
		
	}// STATUS_SUCCESS
	else
	{
		DBGPRINT(RT_DEBUG_TEMP,"==> RTUSBBulkRxComplete Error code = %d\n", status);
		pRxContext->InUse = FALSE;

		if ((!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RESET_IN_PROGRESS)) &&
			(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BULKIN_RESET)) &&
			(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_HALT_IN_PROGRESS)) &&
			(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_REMOVE_IN_PROGRESS)))
		{
			DBGPRINT_RAW(RT_DEBUG_ERROR, "Bulk In Failed\n");
			RTMP_SET_FLAG(pAdapter, fRTMP_ADAPTER_BULKIN_RESET);
			RTUSBEnqueueInternalCmd(pAdapter, RT_OID_USB_RESET_BULK_IN);
		}
	}

#endif
}
VOID	RTUSBBulkOutPsPollComplete(purbb_t pUrb)
{
	PTX_CONTEXT	pPsPollContext;
	PRT2570ADAPTER	pAdapter;
	NTSTATUS		status;
	
	pPsPollContext= (PTX_CONTEXT)pUrb->context;
	pAdapter = pPsPollContext->pAdapter;
	pPsPollContext->IRPPending 	= FALSE;
	pPsPollContext->InUse 		= FALSE;
	status = pUrb->status;
	if (status == USB_ST_NOERROR)
	{
		// Don't worry about the queue is empty or not, this function will check itself
		RTUSBDeQueuePacket(pAdapter);
	}
	else
	{
		if ((!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RESET_IN_PROGRESS)) &&
			(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_HALT_IN_PROGRESS)) &&
			(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_REMOVE_IN_PROGRESS)) &&
			(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BULKOUT_RESET)))
		{
			DBGPRINT_RAW(RT_DEBUG_ERROR, "Bulk Out Null Frame Failed\n");
			RTMP_SET_FLAG(pAdapter, fRTMP_ADAPTER_BULKOUT_RESET);
			RTUSBEnqueueInternalCmd(pAdapter, RT_OID_USB_RESET_BULK_OUT);
		}
	}

	NdisAcquireSpinLock(&pAdapter->BulkOutLock);
	pAdapter->BulkOutPending = FALSE;
	NdisReleaseSpinLock(&pAdapter->BulkOutLock);

	// Always call Bulk routine, even reset bulk.
	// The protectioon of rest bulk should be in BulkOut routine
	RTUSBKickBulkOut(pAdapter);

	DBGPRINT_RAW(RT_DEBUG_INFO, "<---RTUSBBulkOutNullFrameComplete\n");

}
VOID RTUSBBulkOutBeaconComplete(purbb_t pUrb)
{

	PTX_CONTEXT		pBeaconContext;
	PRT2570ADAPTER	pAdapter;
	NTSTATUS		status;
	
	pBeaconContext= (PTX_CONTEXT)pUrb->context;
	pAdapter = pBeaconContext->pAdapter;
	pBeaconContext->IRPPending 	= FALSE;
	pBeaconContext->InUse 		= FALSE;
	status = pUrb->status;

	if (status != USB_ST_NOERROR)
	{
		if ((!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RESET_IN_PROGRESS)) &&
			(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_HALT_IN_PROGRESS)) &&
			(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_REMOVE_IN_PROGRESS)) &&
			(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BULKOUT_RESET)))
		{
			DBGPRINT_RAW(RT_DEBUG_ERROR, "Bulk Out Beacon Frame Failed\n");
			RTMP_SET_FLAG(pAdapter, fRTMP_ADAPTER_BULKOUT_RESET);
			RTUSBEnqueueInternalCmd(pAdapter, RT_OID_USB_RESET_BULK_OUT);
		}
	}
	NdisAcquireSpinLock(&pAdapter->BulkOutLock);
	pAdapter->BulkOutPending = FALSE;
	NdisReleaseSpinLock(&pAdapter->BulkOutLock);

	// Always call Bulk routine, even reset bulk.
	// The protectioon of rest bulk should be in BulkOut routine
	RTUSBKickBulkOut(pAdapter);

}

#endif
/*
	========================================================================
	
	Routine Description:

	Arguments:

	Return Value:

	IRQL = 
	
	Note:
	
	========================================================================
*/
VOID RTUSBBulkOutBeacon(
	IN PRT2570ADAPTER	pAdapter,
	IN INT 			BeaconIndex)
{
	PTX_CONTEXT pBeaconContext;
	PURB			pUrb;
	int ret = 0;
	
	NdisAcquireSpinLock(&pAdapter->BulkOutLock);
	if (pAdapter->BulkOutPending == TRUE)
	{
		NdisReleaseSpinLock(&pAdapter->BulkOutLock);
		return;
	}
	pAdapter->BulkOutPending = TRUE;
	NdisReleaseSpinLock(&pAdapter->BulkOutLock);

	
	// Clear Beacon 0, 1 flag and set beacon 1 flag if required
	if (RTUSB_TEST_BULK_FLAG(pAdapter, fRTUSB_BULK_OUT_BEACON_0))
	{
		// Clear beacon 0 flag
		RTUSB_CLEAR_BULK_FLAG(pAdapter, fRTUSB_BULK_OUT_BEACON_0);
		// Set beacon 1 flag
		RTUSB_SET_BULK_FLAG (pAdapter, fRTUSB_BULK_OUT_BEACON_1);
	}
	else
	{
		// Clear beacon 1 flag
		RTUSB_CLEAR_BULK_FLAG(pAdapter, fRTUSB_BULK_OUT_BEACON_1);
	}
	
	pBeaconContext  = &pAdapter->BeaconContext[BeaconIndex];
	DBGPRINT_RAW(RT_DEBUG_TEMP, "--->RTUSBBulkOutBeacon BulkOutSize %d\n",pBeaconContext->BulkOutSize);
	pUrb = pBeaconContext->pUrb;
	RTusb_fill_bulk_urb(pUrb,
		pAdapter->usb,
		usb_sndbulkpipe(pAdapter->usb, 1),
		pBeaconContext->TransferBuffer,
		pBeaconContext->BulkOutSize,
		RTUSBBulkOutBeaconComplete,
		pBeaconContext);

	if((ret = rtusb_submit_urb(pUrb))!=0)
	{
		DBGPRINT(RT_DEBUG_ERROR,"Submit Tx URB failed %d\n", ret);
		return;
	}
	
	DBGPRINT_RAW(RT_DEBUG_INFO, "<---RTUSBBulkOutBeacon \n");
}


/*
	========================================================================
	
	Routine Description:

	Arguments:

	Return Value:

	IRQL = 
	
	Note:
	
	========================================================================
*/
VOID	RTUSBBulkOutPsPoll(
	IN	PRT2570ADAPTER	pAdapter)
{
	PTX_CONTEXT	pPsPollContext = &(pAdapter->PsPollContext);
	PURB			pUrb;
	int ret = 0;

	NdisAcquireSpinLock(&pAdapter->BulkOutLock);
	if (pAdapter->BulkOutPending == TRUE)
	{
		NdisReleaseSpinLock(&pAdapter->BulkOutLock);
		return;
	}
	pAdapter->BulkOutPending = TRUE;
	NdisReleaseSpinLock(&pAdapter->BulkOutLock);

	// Clear PS-Poll bulk flag
	RTUSB_CLEAR_BULK_FLAG(pAdapter, fRTUSB_BULK_OUT_PSPOLL);

	DBGPRINT_RAW(RT_DEBUG_INFO, "--->RTUSBBulkOutPsPollFrame \n");
	
	pUrb = pPsPollContext->pUrb;
	RTusb_fill_bulk_urb(pUrb,
		pAdapter->usb,
		usb_sndbulkpipe(pAdapter->usb, 1),
		pPsPollContext->TransferBuffer,
		pPsPollContext->BulkOutSize,
		RTUSBBulkOutPsPollComplete,
		pPsPollContext);

	if((ret = rtusb_submit_urb(pUrb))!=0)
	{
		DBGPRINT(RT_DEBUG_ERROR,"Submit Tx URB failed %d\n", ret);
		return;
	}
	DBGPRINT(RT_DEBUG_INFO,"<==RTUSBBulkOutPsPollPacket\n");

	return;


}


/*
	========================================================================

	Routine Description:
	USB_RxPacket initializes a URB and uses the Rx IRP to submit it
	to USB. It checks if an Rx Descriptor is available and passes the
	the coresponding buffer to be filled. If no descriptor is available
	fails the request. When setting the completion routine we pass our
	Adapter Object as Context.
		
	Arguments:
		
	Return Value:
		TRUE			found matched tuple cache
		FALSE			no matched found

	Note:
	
	========================================================================
*/
VOID	RTUSBBulkReceive(
	IN	PRT2570ADAPTER	pAdapter)
{
	
	PRX_CONTEXT pRxContext;
	PURB			pUrb;
	int ret = 0;

	if ((RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_REMOVE_IN_PROGRESS))||
		(RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RADIO_OFF))||
		(RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RESET_PIPE_IN_PROGRESS)))
		{
	DBGPRINT(RT_DEBUG_TEMP,"==>RTUSBBulkReceive, pAdapter->NextRxBulkInIndex = %d\n",pAdapter->NextRxBulkInIndex);
		return;
		}
	//DBGPRINT(RT_DEBUG_TEMP,"==>RTUSBBulkReceive, pAdapter->NextRxBulkInIndex = %d\n",pAdapter->NextRxBulkInIndex);
	pRxContext = &(pAdapter->RxContext[pAdapter->NextRxBulkInIndex]);
	pRxContext->InUse = TRUE;
	pAdapter->NextRxBulkInIndex = (pAdapter->NextRxBulkInIndex + 1) % RX_RING_SIZE;

	pUrb = pRxContext->pUrb;
		
	atomic_set(&pRxContext->IrpLock, IRPLOCK_CANCELABLE);	
	atomic_add(1, &pAdapter->PendingRx);
	memset(pRxContext->TransferBuffer, 0, BUFFER_SIZE);
	RTusb_fill_bulk_urb(pUrb,
		pAdapter->usb,
		usb_rcvbulkpipe(pAdapter->usb, 1),
		pRxContext->TransferBuffer,
		BUFFER_SIZE,
		RTUSBBulkRxComplete,
		pRxContext);
	
	if((ret = rtusb_submit_urb(pUrb))!=0)
	{
		DBGPRINT(RT_DEBUG_ERROR,"Submit Rx URB failed %d\n", ret);
		return;
	}

	return;
}

/*
	========================================================================
	
	Routine Description:

	Arguments:

	Return Value:

	IRQL = 
	
	Note:
	
	========================================================================
*/
VOID	RTUSBKickBulkOut(
	IN	PRT2570ADAPTER pAdapter)
{
	int	RoundOver = 0;
	do
	{
		// greedy to bulk out. protection are in BulkOut function using InUse parameter
		if (++RoundOver > 2)
			break;
		
		if (!(RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_REMOVE_IN_PROGRESS)) &&
			!(RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_HALT_IN_PROGRESS)) &&
			!(RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RESET_IN_PROGRESS)) &&
			!(RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BULKOUT_RESET)) &&
			!(RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RADIO_OFF)))
		{
			// Start aribritrating Bulk out candidates

			// 0. Check if no flags set, we will do a dequeue from MLME and Data
			//if (pAdapter->BulkFlags == 0x0)
			//{
			//	RTUSBDequeueMLMEPacket(pAdapter);
			//	RTUSBDeQueuePacket(pAdapter);
			//}
		
			// 1. Data Fragment has highest priority
			if (RTUSB_TEST_BULK_FLAG(pAdapter, fRTUSB_BULK_OUT_DATA_FRAG))
			{
				RTUSBBulkOutDataPacket(pAdapter, pAdapter->NextBulkOutIndex);
			}
			
			// 2. PS-Poll frame is next
			else if (RTUSB_TEST_BULK_FLAG(pAdapter, fRTUSB_BULK_OUT_PSPOLL))
			{
				RTUSBBulkOutPsPoll(pAdapter);
			}
			
			// 3. Beacon 0, guarding beacon frame is next
			else if (RTUSB_TEST_BULK_FLAG(pAdapter, fRTUSB_BULK_OUT_BEACON_0))
			{
				RTUSBBulkOutBeacon(pAdapter, 0);
			}

			// 4. Beacon 1, beacon frame body is next
			else if (RTUSB_TEST_BULK_FLAG(pAdapter, fRTUSB_BULK_OUT_BEACON_1))
			{
				RTUSBBulkOutBeacon(pAdapter, 1);
			}

			// 5. Mlme frame is next
			else if (RTUSB_TEST_BULK_FLAG(pAdapter, fRTUSB_BULK_OUT_MLME))
			{
				RTUSBBulkOutMLMEPacket(pAdapter, pAdapter->PrioRingFirstIndex);
			}

			// 6. Data frame normal is next
			else if (RTUSB_TEST_BULK_FLAG(pAdapter, fRTUSB_BULK_OUT_DATA_NORMAL))
			{
				if ((!LOCAL_TX_RING_EMPTY(pAdapter)) && 
					((!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) && 
					(pAdapter->MediaState == NdisMediaStateConnected)))
				{
					RTUSBBulkOutDataPacket(pAdapter, pAdapter->NextBulkOutIndex);
				}
			}

			// 7. Null frame is the last
			else if (RTUSB_TEST_BULK_FLAG(pAdapter, fRTUSB_BULK_OUT_DATA_NULL))
			{
				if (!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
				{
					RTUSBBulkOutNullFrame(pAdapter);
				}
			}
			
			// 8. No data avaliable
			else
			{
				// Do nothing, or dequeue MLME and Data
				//RTUSBDequeueMLMEPacket(pAdapter);
				//RTUSBDeQueuePacket(pAdapter);
			}
		}
	}while(TRUE);
	DBGPRINT_RAW(RT_DEBUG_INFO,"<---RTUSBKickBulkOut\n");
}

/*
	========================================================================
	
	Routine Description:

	Arguments:

	Return Value:

	IRQL = 
	
	Note:
	
	========================================================================
*/
VOID	RTUSBCleanUpDataBulkOutQueue(
	IN	PRT2570ADAPTER	pAdapter)
{
	PTX_CONTEXT pTxContext;			

	DBGPRINT(RT_DEBUG_TRACE, "--->CleanUpDataBulkOutQueue\n");
				
	while (!LOCAL_TX_RING_EMPTY(pAdapter))
	{			
		pTxContext 					= &(pAdapter->TxContext[pAdapter->NextBulkOutIndex]);
		pTxContext->LastOne 		= FALSE;
		pTxContext->InUse 			= FALSE;
		pAdapter->NextBulkOutIndex 	= (pAdapter->NextBulkOutIndex + 1) % TX_RING_SIZE;
	}
	
	NdisAcquireSpinLock(&pAdapter->BulkOutLock);
	pAdapter->BulkOutPending = FALSE;
	NdisReleaseSpinLock(&pAdapter->BulkOutLock);

	DBGPRINT(RT_DEBUG_TRACE, "<---CleanUpDataBulkOutQueue\n");
}

/*
	========================================================================
	
	Routine Description:

	Arguments:

	Return Value:

	IRQL = 
	
	Note:
	
	========================================================================
*/
VOID	RTUSBCleanUpMLMEBulkOutQueue(
	IN	PRT2570ADAPTER	pAdapter)
{
	DBGPRINT(RT_DEBUG_TRACE, "--->CleanUpMLMEBulkOutQueue\n");

	NdisAcquireSpinLock(&pAdapter->MLMEQLock);
	while (pAdapter->PrioRingTxCnt > 0)
	{
		pAdapter->MLMEContext[pAdapter->PrioRingFirstIndex].InUse = FALSE;
			
		pAdapter->PrioRingFirstIndex++;
		if (pAdapter->PrioRingFirstIndex >= PRIO_RING_SIZE)
		{
			pAdapter->PrioRingFirstIndex = 0;
		}

		pAdapter->PrioRingTxCnt--;
	}
	NdisReleaseSpinLock(&pAdapter->MLMEQLock);

	DBGPRINT(RT_DEBUG_TRACE, "<---CleanUpMLMEBulkOutQueue\n");
}

/*
	========================================================================
	
	Routine Description:

	Arguments:

	Return Value:

	IRQL = 
	
	Note:
	
	========================================================================
*/
VOID	RTUSBCancelPendingIRPs(
	IN	PRT2570ADAPTER	pAdapter)
{
	RTUSBCancelPendingBulkInIRP(pAdapter);
	RTUSBCancelPendingBulkOutIRP(pAdapter);
}

/*
	========================================================================
	
	Routine Description:

	Arguments:

	Return Value:

	IRQL = 
	
	Note:
	
	========================================================================
*/
VOID	RTUSBCancelPendingBulkInIRP(
	IN	PRT2570ADAPTER	pAdapter)
{
	PRX_CONTEXT	pRxContext;
	UINT		i;

	DBGPRINT_RAW(RT_DEBUG_TRACE,"--->RTUSBCancelPendingBulkInIRP\n");
	for ( i = 0; i < RX_RING_SIZE; i++)
	{
		pRxContext = &(pAdapter->RxContext[i]);
		if(atomic_read(&pRxContext->IrpLock) == IRPLOCK_CANCELABLE)
		{
			usb_kill_urb(pRxContext->pUrb);
		}
		atomic_set(&pRxContext->IrpLock, IRPLOCK_CANCE_START);
	}
	DBGPRINT_RAW(RT_DEBUG_TRACE,"<---RTUSBCancelPendingBulkInIRP\n");
}

/*
	========================================================================
	
	Routine Description:

	Arguments:

	Return Value:

	IRQL = 
	
	Note:
	
	========================================================================
*/
VOID	RTUSBCancelPendingBulkOutIRP(
	IN	PRT2570ADAPTER	pAdapter)
{
	PTX_CONTEXT		pTxContext;
	PTX_CONTEXT		pMLMEContext;
	PTX_CONTEXT		pBeaconContext;
	PTX_CONTEXT		pNullContext;
	PTX_CONTEXT		pPsPollContext;
	UINT		i;
	
	DBGPRINT_RAW(RT_DEBUG_TRACE,"--->RTUSBCancelPendingBulkOutIRP\n");
	for ( i = 0; i < TX_RING_SIZE; i++)
	{
		pTxContext = &(pAdapter->TxContext[i]);
		if (pTxContext->IRPPending == TRUE)
		{
			usb_kill_urb(pTxContext->pUrb);
		}
	}

	for (i = 0; i < PRIO_RING_SIZE; i++)
	{
		pMLMEContext = &(pAdapter->MLMEContext[i]);

		if(pMLMEContext->IRPPending == TRUE)
		{

			// Get the USB_CONTEXT and cancel it's IRP; the completion routine will itself
			// remove it from the HeadPendingSendList and NULL out HeadPendingSendList
			//  when the last IRP on the list has been  cancelled; that's how we exit this loop
			//

			usb_kill_urb(pMLMEContext->pUrb);

			// Sleep 200 microsecs to give cancellation time to work
			NdisMSleep(200);
		}
	}

	for (i = 0; i < BEACON_RING_SIZE; i++)
	{
		pBeaconContext = &(pAdapter->BeaconContext[i]);

		if(pBeaconContext->IRPPending == TRUE)
		{

			// Get the USB_CONTEXT and cancel it's IRP; the completion routine will itself
			// remove it from the HeadPendingSendList and NULL out HeadPendingSendList
			//  when the last IRP on the list has been  cancelled; that's how we exit this loop
			//

			usb_kill_urb(pBeaconContext->pUrb);

			// Sleep 200 microsecs to give cancellation time to work
			NdisMSleep(200);
		}
	}

	pNullContext = &(pAdapter->NullContext);
	if (pNullContext->IRPPending == TRUE)
	usb_kill_urb(pNullContext->pUrb);

	pPsPollContext = &(pAdapter->PsPollContext);
	if (pPsPollContext->IRPPending == TRUE)
	usb_kill_urb(pPsPollContext->pUrb);

	NdisAcquireSpinLock(&pAdapter->BulkOutLock);
	pAdapter->BulkOutPending = FALSE;
	NdisReleaseSpinLock(&pAdapter->BulkOutLock);
	
	DBGPRINT_RAW(RT_DEBUG_TRACE,"<---RTUSBCancelPendingBulkOutIRP\n");
	
}

