/*************************************************************************** 
 * 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_main.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"

unsigned long flagg;
ULONG	debug = RT_DEBUG_OFF;
MODULE_PARM(debug, "i");
MODULE_PARM_DESC(debug, "Enable level: accepted values: 1 to switch debug on, 0 to switch debug off.");

#define KERNEL_20424	0x20418
#define KERNEL_20418	0x20412

#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
/* Kernel thread and vars, which handles packets that are completed. Only
 * packets that have a "complete" function are sent here. This way, the
 * completion is run out of kernel context, and doesn't block the rest of
 * the stack. */
static int mlme_kill;
static int RTUSBCmd_kill;
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0) */

extern	const struct iw_handler_def rt2500usb_iw_handler_def;

static struct usb_device_id rtusb_usb_id[] =
	RTUSB_DEVICES
;
/* the number of entries in array above */
int const rtusb_usb_id_len =
	sizeof(rtusb_usb_id) / sizeof(struct usb_device_id);

#ifndef PF_NOFREEZE
#define PF_NOFREEZE  0
#endif
/**************************************************************************/
/**************************************************************************/
//tested for kernel 2.4 series
/**************************************************************************/
/**************************************************************************/
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)


static void usb_rtusb_disconnect(struct usb_device *dev, void *ptr);
static void *usb_rtusb_probe(struct usb_device *dev, UINT interface,
				const struct usb_device_id *id_table);

struct usb_driver rtusb_driver = {
		name:"rt2500usb",
		probe:usb_rtusb_probe,
		disconnect:usb_rtusb_disconnect,
		id_table:rtusb_usb_id,
	};
#else
/**************************************************************************/
/**************************************************************************/
//tested for kernel 2.6series
/**************************************************************************/
/**************************************************************************/
static int usb_rtusb_probe (struct usb_interface *intf,
					  const struct usb_device_id *id);

static void usb_rtusb_disconnect(struct usb_interface *intf);

struct usb_driver rtusb_driver = {
	.owner =	THIS_MODULE,
	.name="rtusb",
	.probe=usb_rtusb_probe,
	.disconnect=usb_rtusb_disconnect,
	.id_table=rtusb_usb_id,
	};


#endif


//static void USB_RxPacketComplete_bh(unsigned long data)
//{
//	RTUSBRxPacket(data);
//}

#if 0

#define MAX_JIFFY_OFFSET ((~0UL >> 1)-1)

static inline unsigned int jiffies_to_msecs(const unsigned long j)
{
#if HZ <= 1000 && !(1000 % HZ)
         return (1000 / HZ) * j;
#elif HZ > 1000 && !(HZ % 1000)
         return (j + (HZ / 1000) - 1)/(HZ / 1000);
#else
         return (j * 1000) / HZ;
#endif
}

static inline unsigned long msecs_to_jiffies(const unsigned int m)
{
         if (m > jiffies_to_msecs(MAX_JIFFY_OFFSET))
                 return MAX_JIFFY_OFFSET;
#if HZ <= 1000 && !(1000 % HZ)
         return (m + (1000 / HZ) - 1) / (1000 / HZ);
#elif HZ > 1000 && !(HZ % 1000)
         return m * (HZ / 1000);
 #else
         return (m * HZ + 999) / 1000;
 #endif
}
/**
* msleep - sleep safely even with waitqueue interruptions
* @msecs: Time in milliseconds to sleep for
*/
 void msleep(unsigned int msecs)
{
	unsigned long timeout = msecs_to_jiffies(msecs) + 1;

	while (timeout)
	{
		set_current_state(TASK_UNINTERRUPTIBLE);
		timeout = schedule_timeout(timeout);
	}
}



#endif

struct net_device_stats *
rt_getstats(struct net_device *dev)
{
	PRT2570ADAPTER pAd = (PRT2570ADAPTER)dev->priv;
	struct net_device_stats *stats= &pAd->net_device_stats;

	stats->rx_bytes = pAd->RalinkCounters.ReceivedByteCount;
	stats->rx_packets = pAd->Counters.GoodReceives;
	stats->rx_errors = pAd->Counters.RxErrors;

	stats->tx_bytes = pAd->RalinkCounters.TransmittedByteCount;
	stats->tx_packets = pAd->Counters.GoodTransmits;
	stats->tx_errors = pAd->Counters.TxErrors;
	return stats;
}

#if WIRELESS_EXT >= 12
/*
    ========================================================================

    Routine Description:
        get wireless statistics

    Arguments:
        net_dev                     Pointer to net_device

    Return Value:
        struct iw_statistics

    Note:
        This function will be called when query /proc

    ========================================================================
*/
struct iw_statistics *RTUSB_get_wireless_stats(
    IN  struct net_device *net_dev)
{
    PRT2570ADAPTER pAd = (PRT2570ADAPTER)net_dev->priv;

    DBGPRINT(RT_DEBUG_TRACE, "--->RTUSB_get_wireless_stats \n");

    // TODO: All elements are zero before be implemented

    pAd->iw_stats.status = 0;                       // Status - device dependent for now

    pAd->iw_stats.qual.qual = pAd->Mlme.ChannelQuality;//pAd->Mlme.RoamCqi;            // link quality (%retries, SNR, %missed beacons or better...)
    pAd->iw_stats.qual.level = pAd->PortCfg.LastRssi - RSSI_TO_DBM_OFFSET;   // signal level (dBm)
        
    pAd->iw_stats.qual.noise = (pAd->PortCfg.LastR17Value > BBP_R17_DYNAMIC_UP_BOUND) ? BBP_R17_DYNAMIC_UP_BOUND : ((ULONG) pAd->PortCfg.LastR17Value);           // noise level (dBm)
    pAd->iw_stats.qual.updated = 1;     // Flags to know if updated

    pAd->iw_stats.discard.nwid = 0;     // Rx : Wrong nwid/essid
    pAd->iw_stats.miss.beacon = 0;      // Missed beacons/superframe

    // pAd->iw_stats.discard.code, discard.fragment, discard.retries, discard.misc has counted in other place

    return &pAd->iw_stats;
}
#endif

int rt2570_set_mac_address(struct net_device *net_dev, void *addr)
{
	RT2570ADAPTER		*pAd = net_dev->priv;
	struct sockaddr		*mac = (struct sockaddr*) addr;

	if(netif_running(net_dev))
		return -EBUSY;

	if(!is_valid_ether_addr(&mac->sa_data[0]))
		return -EINVAL;

#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,20)) 	
	BUG_ON(net_dev->addr_len != ETH_ALEN);
#endif	
	
	memcpy(net_dev->dev_addr, mac->sa_data, ETH_ALEN);
	memcpy(&pAd->CurrentAddress, &mac->sa_data, ETH_ALEN);

	printk(KERN_INFO "***rt2x00***: Info - Mac address changed to: %02x:%02x:%02x:%02x:%02x:%02x.\n", net_dev->dev_addr[0], net_dev->dev_addr[1], net_dev->dev_addr[2], net_dev->dev_addr[3], net_dev->dev_addr[4], net_dev->dev_addr[5]);

	return RTUSBWriteHWMACAddress(pAd);
}

VOID	RTUSBHalt(
	IN	PRT2570ADAPTER	pAdapter, BOOLEAN IsFree)
{
	MLME_DISASSOC_REQ_STRUCT DisReq;
	MLME_QUEUE_ELEM          MsgElem;
	
	DBGPRINT(RT_DEBUG_TRACE, "====> RTUSBHalt\n");
	// before set flag fRTMP_ADAPTER_HALT_IN_PROGRESS, 
	// we should send a disassoc frame to our AP.
	//
#if 1
	if (!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_REMOVE_IN_PROGRESS))
	{
		if (INFRA_ON(pAdapter)) 
		{
			COPY_MAC_ADDR(&DisReq.Addr, &pAdapter->PortCfg.Bssid);
			DisReq.Reason =  REASON_DISASSOC_STA_LEAVING;

			MsgElem.Machine = ASSOC_STATE_MACHINE;
			MsgElem.MsgType = MT2_MLME_DISASSOC_REQ;
			MsgElem.MsgLen = sizeof(MLME_DISASSOC_REQ_STRUCT);
			memcpy(MsgElem.Msg, &DisReq, sizeof(MLME_DISASSOC_REQ_STRUCT));

			MlmeDisassocReqAction(pAdapter, &MsgElem);
			NdisMSleep(1000);
		}

		// disable BEACON generation and other BEACON related hardware timers
		AsicDisableSync(pAdapter);
	}
#endif
	RTMP_SET_FLAG(pAdapter, fRTMP_ADAPTER_HALT_IN_PROGRESS);

	RTUSBCleanUpMLMEWaitQueue(pAdapter);
	RTUSBCleanUpMLMEBulkOutQueue(pAdapter);

	// Free MLME stuff
	MlmeHalt(pAdapter);
	ReleaseAdapter(pAdapter, IsFree);

	RTMP_CLEAR_FLAG(pAdapter, fRTMP_ADAPTER_HALT_IN_PROGRESS);
}

VOID CMDHandler(
    IN PRT2570ADAPTER pAdapter) 
{
	PCmdQElmt	cmdqelmt;
	PUCHAR	pData;
	NDIS_STATUS	NdisStatus = NDIS_STATUS_SUCCESS;

	while (pAdapter->CmdQ.size > 0)
	{
		NdisStatus = NDIS_STATUS_SUCCESS;
		NdisAcquireSpinLock(&pAdapter->CmdQLock);
		RTUSBDequeueCmd(&pAdapter->CmdQ, &cmdqelmt);
		NdisReleaseSpinLock(&pAdapter->CmdQLock);
		if (cmdqelmt == NULL)
			break;
		pData = cmdqelmt->buffer;
		switch (cmdqelmt->command)
		{
			case	RT_OID_CHECK_GPIO:
			{
				USHORT data;
				// Read GPIO pin0 as Hardware controlled radio state
				RTUSBReadMACRegister(pAdapter, MAC_CSR19, &data);
				if (data & 0x80)
				{
					pAdapter->PortCfg.bHwRadio = TRUE;
				}
				else
				{
					pAdapter->PortCfg.bHwRadio = FALSE;
				}
				if (pAdapter->PortCfg.bRadio != (pAdapter->PortCfg.bHwRadio && pAdapter->PortCfg.bSwRadio))
				{
					pAdapter->PortCfg.bRadio = (pAdapter->PortCfg.bHwRadio && pAdapter->PortCfg.bSwRadio);
					if (pAdapter->PortCfg.bRadio == TRUE)
					{
						MlmeRadioOn(pAdapter);
						// Update extra information
						pAdapter->ExtraInfo = EXTRA_INFO_CLEAR;
					}
					else
					{
						MlmeRadioOff(pAdapter);
						// Update extra information
						pAdapter->ExtraInfo = HW_RADIO_OFF;
					}
				}		
			}
			break;

			case	RT_OID_PERIODIC_EXECUT:
				PeriodicExec(pAdapter);
			break;

			case	OID_802_11_BSSID_LIST_SCAN:
			{
				if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE)
				{
					DBGPRINT_RAW(RT_DEBUG_TRACE, "!!! MLME busy (Line#%d)!!!\n", __LINE__);
					MlmeRestartStateMachine(pAdapter);
					MlmePostRestartStateMachine(pAdapter);
				}

				//Now = jiffies;
				pAdapter->Mlme.CntlAux.CurrReqIsFromNdis = FALSE;
				// Reset Missed scan number
				pAdapter->PortCfg.IgnoredScanNumber = 0;
				//pAdapter->PortCfg.LastScanTime = Now;
				MlmeEnqueue(pAdapter,
					MLME_CNTL_STATE_MACHINE,
					OID_802_11_BSSID_LIST_SCAN,
					0,
					NULL);
				RTUSBUp(pAdapter, &pAdapter->mlme_semaphore);
			}
			break;
			
			case	RT_OID_802_11_BSSID:
			{

				if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE)
				{
					DBGPRINT_RAW(RT_DEBUG_TRACE, "!!! MLME busy (Line#%d)!!!\n", __LINE__);
					MlmeRestartStateMachine(pAdapter);
					MlmePostRestartStateMachine(pAdapter);
				}

				pAdapter->Mlme.CntlAux.CurrReqIsFromNdis = FALSE;

				// Reset allowed scan retries
				pAdapter->PortCfg.IgnoredScanNumber = 0;

				MlmeEnqueue(pAdapter,
					MLME_CNTL_STATE_MACHINE,
					RT_OID_802_11_BSSID,
					cmdqelmt->bufferlength,
					cmdqelmt->buffer);
				RTUSBUp(pAdapter, &pAdapter->mlme_semaphore);
			}
			break;
			
			case	OID_802_11_SSID:
			{
				if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE)
				{
					DBGPRINT_RAW(RT_DEBUG_TRACE, "!!! MLME busy (Line#%d)!!!\n", __LINE__);
					MlmeRestartStateMachine(pAdapter);
					MlmePostRestartStateMachine(pAdapter);
				}

				pAdapter->Mlme.CntlAux.CurrReqIsFromNdis = FALSE;

				// Reset allowed scan retries
				pAdapter->PortCfg.IgnoredScanNumber = 0;

				MlmeEnqueue(pAdapter,
						MLME_CNTL_STATE_MACHINE,
						OID_802_11_SSID,
						cmdqelmt->bufferlength, 
						pData);
				RTUSBUp(pAdapter, &pAdapter->mlme_semaphore);
			}
			break;

			case	OID_802_11_DISASSOCIATE:
			{
				if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE)
				{
					DBGPRINT_RAW(RT_DEBUG_TRACE, "!!! MLME busy (Line#%d)!!!\n", __LINE__);
					MlmeRestartStateMachine(pAdapter);
					MlmePostRestartStateMachine(pAdapter);
				}

				// Set to immediately send the media disconnect event
				pAdapter->Mlme.CntlAux.CurrReqIsFromNdis = TRUE;

				MlmeEnqueue(pAdapter,
					MLME_CNTL_STATE_MACHINE,
					OID_802_11_DISASSOCIATE,
					0,
					NULL);
				RTUSBUp(pAdapter, &pAdapter->mlme_semaphore);
			}
			break;

			case	OID_802_11_RX_ANTENNA_SELECTED:
			{
				UCHAR	RxValue;
				NDIS_802_11_ANTENNA	Antenna = *(NDIS_802_11_ANTENNA *)pData;
				DBGPRINT_RAW(RT_DEBUG_TRACE, "Set::OID_802_11_RX_ANTENNA_SELECTED (=%d)\n", Antenna);
				if(Antenna == 0xFFFFFFFF)
				{// Diversity
					pAdapter->PortCfg.CurrentRxAntenna = (UCHAR)Antenna;
					RTUSBReadBBPRegister(pAdapter, BBP_Rx_Configure, &RxValue);
					RxValue = (RxValue & 0xFC) | 0x01;
					RTUSBWriteBBPRegister(pAdapter, BBP_Rx_Configure, RxValue);
				}
				else if(Antenna < pAdapter->PortCfg.NumberOfAntenna)
				{
					pAdapter->PortCfg.CurrentRxAntenna = (UCHAR)Antenna;

					RTUSBReadBBPRegister(pAdapter, BBP_Rx_Configure, &RxValue);
					if(Antenna == 0)
					{// Antenna A
						RxValue = (RxValue & 0xFC) | 0x00;
					}
					else if(Antenna == 1)
					{// Antenna B
						RxValue = (RxValue & 0xFC) | 0x02;
					}
					RTUSBWriteBBPRegister(pAdapter, BBP_Rx_Configure, RxValue);
				}
			}
			break;

			case	OID_802_11_TX_ANTENNA_SELECTED:
			{
				NDIS_802_11_ANTENNA	Antenna = *(NDIS_802_11_ANTENNA *)pData;
				DBGPRINT_RAW(RT_DEBUG_TRACE, "Set::OID_802_11_TX_ANTENNA_SELECTED (=%d)\n", Antenna);
				if ((Antenna != 0xFFFFFFFF) && (Antenna >= pAdapter->PortCfg.NumberOfAntenna))
				{
				}
				else
				{
					UCHAR	TxValue;
					USHORT	Value5, Value6;
					pAdapter->PortCfg.CurrentTxAntenna = (UCHAR)Antenna;
					RTUSBReadBBPRegister(pAdapter, BBP_Tx_Configure, &TxValue);
					RTUSBReadMACRegister(pAdapter, PHY_CSR5, &Value5);
					RTUSBReadMACRegister(pAdapter, PHY_CSR6, &Value6);
					if(Antenna == 0xFFFFFFFF)
					{// Diversity
						TxValue = (TxValue & 0xFC) | 0x01;
						Value5 = (Value5 & 0xFFFC) | 0x0001;
						Value6 = (Value6 & 0xFFFC) | 0x0001;
					}
					else if(Antenna == 0)
					{// Antenna A
						TxValue = (TxValue & 0xFC) | 0x00;
						Value5 = (Value5 & 0xFFFC) | 0x0000;
						Value6 = (Value6 & 0xFFFC) | 0x0000;
					}
					else if(Antenna == 1)
					{// Antenna B
						TxValue = (TxValue & 0xFC) | 0x02;
						Value5 = (Value5 & 0xFFFC) | 0x0002;
						Value6 = (Value6 & 0xFFFC) | 0x0002;
					}
					RTUSBWriteBBPRegister(pAdapter, BBP_Tx_Configure, TxValue);
					RTUSBWriteMACRegister(pAdapter, PHY_CSR5, Value5);
					RTUSBWriteMACRegister(pAdapter, PHY_CSR6, Value6);
				}
			}
			break;

			case	RT_OID_SINGLE_WRITE_MAC:
			{
				USHORT	Offset, Value;
				Offset = *((PUSHORT)pData);
				Value = *((PUSHORT)(pData + 2));
				DBGPRINT_RAW(RT_DEBUG_INFO, "offset = 0x%04x	value = 0x%04x\n", Offset, Value);
				RTUSBWriteMACRegister(pAdapter, Offset, Value);
			}
			break;
			
			case	RT_OID_SINGLE_READ_MAC:
			{
				USHORT	Offset = *((PUSHORT)pData);
				PUSHORT	pValue = (PUSHORT)(pData + 2);
				DBGPRINT_RAW(RT_DEBUG_INFO, "offset = 0x%04x\n", Offset);
				RTUSBReadMACRegister(pAdapter, Offset, pValue);
				DBGPRINT_RAW(RT_DEBUG_INFO, "value = 0x%04x\n", *pValue);
			}
			break;

			case	RT_OID_MULTI_READ_MAC:
			{
				USHORT	Offset = *((PUSHORT)pData);
				USHORT	Length = *((PUSHORT)(pData + 2));
				RTUSBMultiReadMAC(pAdapter, Offset, pData + 4, Length);
			}
			break;

			case	RT_OID_MULTI_WRITE_MAC:
			{
				USHORT	Offset = *((PUSHORT)pData);
				USHORT	Length = *((PUSHORT)(pData + 2));
				RTUSBMultiWriteMAC(pAdapter, Offset, pData + 4, Length);
			}
			break;

			case	RT_OID_USB_VENDOR_EEPROM_READ:
			{
				USHORT	Offset = *((PUSHORT)pData);
				USHORT	Length = *((PUSHORT)(pData + 2));
				RTUSBReadEEPROM(pAdapter, Offset, pData + 4, Length);
			}
			break;
				    
			case	RT_OID_USB_VENDOR_EEPROM_WRITE:
			{
				USHORT	Offset = *((PUSHORT)pData);
#if 0
				USHORT	Length = *((PUSHORT)(pData + 2));
				RTUSBWriteEEPROM(pAdapter, Offset, pData + 4, Length);
#else//F/W restricts the max EEPROM write size to 62 bytes.
				USHORT	Residual = *((PUSHORT)(pData + 2));
				pData += 4;
				while (Residual > 62)
				{
				RTUSBWriteEEPROM(pAdapter, Offset, pData, 62);
				Offset += 62;
				Residual -= 62;
				pData += 62;
				}
				RTUSBWriteEEPROM(pAdapter, Offset, pData, Residual);
#endif
			}
			break;

			case	RT_OID_USB_VENDOR_ENTER_TESTMODE:
				RTUSB_VendorRequest(pAdapter,
					0,
					DEVICE_VENDOR_REQUEST_OUT,
					0x1,
					0x4,
					0x1,
					NULL,
					0);
					break;

			case	RT_OID_USB_VENDOR_EXIT_TESTMODE:
				RTUSB_VendorRequest(pAdapter,
					0,
					DEVICE_VENDOR_REQUEST_OUT,
					0x1,
					0x4,
					0x0,
					NULL,
					0);
			break;

			case	RT_OID_USB_RESET_BULK_OUT:
				DBGPRINT_RAW(RT_DEBUG_ERROR, "RT_OID_USB_RESET_BULK_OUT\n");
			break;

			case	RT_OID_USB_RESET_BULK_IN:
					{
				int	i;
				DBGPRINT_RAW(RT_DEBUG_ERROR, "!!!!!RT_OID_USB_RESET_BULK_IN\n");
				DBGPRINT_RAW(RT_DEBUG_ERROR, "!!!!!RT_OID_USB_RESET_BULK_IN\n");
				DBGPRINT_RAW(RT_DEBUG_ERROR, "!!!!!RT_OID_USB_RESET_BULK_IN\n");
				RTMP_SET_FLAG(pAdapter, fRTMP_ADAPTER_RESET_PIPE_IN_PROGRESS);
				RT2570InitializeAsic(pAdapter);
				RTUSBWriteMACRegister(pAdapter, TXRX_CSR2, 1);
				for (i = 0; i < RX_RING_SIZE; i++)
				{
					PRX_CONTEXT  pRxContext = &(pAdapter->RxContext[i]);

					if (pRxContext->pUrb != NULL)
					{
						usb_kill_urb(pRxContext->pUrb);
						usb_free_urb(pRxContext->pUrb);
						pRxContext->pUrb = NULL;
					}
					if (pRxContext->TransferBuffer != NULL)
					{
						FreeMemory(pRxContext->TransferBuffer); 
						pRxContext->TransferBuffer = NULL;
					}

				}
				NICInitRecv(pAdapter);
				RTMP_CLEAR_FLAG(pAdapter, fRTMP_ADAPTER_RESET_PIPE_IN_PROGRESS);
				if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BULKIN_RESET))
				{
					RTMP_CLEAR_FLAG(pAdapter, fRTMP_ADAPTER_BULKIN_RESET);
				}

				if (!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RADIO_OFF))
				{
					RTUSBBulkReceive(pAdapter);
					RTUSBWriteMACRegister(pAdapter, TXRX_CSR2, 0x7e);
				}
				}
			break;

			case	RT_OID_802_11_STA_CONFIG:
			{
				RT_802_11_STA_CONFIG *pStaConfig = (RT_802_11_STA_CONFIG *)pData;
				if (pStaConfig->EnableTxBurst != pAdapter->PortCfg.EnableTxBurst)
				{
					pAdapter->PortCfg.EnableTxBurst = pStaConfig->EnableTxBurst;
					//Currently Tx burst mode is only implemented in infrastructure mode.
					if (INFRA_ON(pAdapter))
					{
						if (pAdapter->PortCfg.EnableTxBurst)
						{
							//Extend slot time if any encryption method is used to give ASIC more time to do encryption/decryption during Tx burst mode.
							if (pAdapter->PortCfg.WepStatus != Ndis802_11EncryptionDisabled)
								RTUSBWriteMACRegister(pAdapter, MAC_CSR10, 0x20);
							//Set CWmin/CWmax to 0.
							RTUSBWriteMACRegister(pAdapter, MAC_CSR22, 0x100);
						}
						else
						{
							if (pAdapter->PortCfg.WepStatus != Ndis802_11EncryptionDisabled)
								AsicSetSlotTime(pAdapter, (BOOLEAN)pAdapter->PortCfg.ShortSlotInUsed);
							RTUSBWriteMACRegister(pAdapter, MAC_CSR22, 0x53);
						}
					}
				}
				pAdapter->PortCfg.EnableTurboRate = pStaConfig->EnableTurboRate;
				pAdapter->PortCfg.UseBGProtection = pStaConfig->UseBGProtection;
				//pAdapter->PortCfg.UseShortSlotTime = pStaConfig->UseShortSlotTime;
				pAdapter->PortCfg.UseShortSlotTime = 1; // 2003-10-30 always SHORT SLOT capable
				if (pAdapter->PortCfg.AdhocMode != pStaConfig->AdhocMode)
				{
					// allow dynamic change of "USE OFDM rate or not" in ADHOC mode
					// if setting changed, need to reset current TX rate as well as BEACON frame format
					pAdapter->PortCfg.AdhocMode = pStaConfig->AdhocMode;
					if (pAdapter->PortCfg.BssType == BSS_INDEP)
					{
						MlmeUpdateTxRates(pAdapter, FALSE);
						MakeIbssBeacon(pAdapter);
					}
				}
				DBGPRINT(RT_DEBUG_TRACE, "Set::RT_OID_802_11_STA_CONFIG (Burst=%d,72/100=%d,Protection=%d,ShortSlot=%d,Adhoc=%d\n",
				pStaConfig->EnableTxBurst,
				pStaConfig->EnableTurboRate,
				pStaConfig->UseBGProtection,
				pStaConfig->UseShortSlotTime,
				pStaConfig->AdhocMode);
			}
			break;

			case	RT_OID_SET_PSM_BIT_SAVE:
				MlmeSetPsmBit(pAdapter, PWR_SAVE);
				EnqueueNullFrame(pAdapter, pAdapter->PortCfg.TxRate);
				break;

				case	RT_OID_SET_RADIO:
					if (pAdapter->PortCfg.bRadio == TRUE){
						MlmeRadioOn(pAdapter);
						// Update extra information
						pAdapter->ExtraInfo = EXTRA_INFO_CLEAR;
					}
					else{
						MlmeRadioOff(pAdapter);
						// Update extra information
						pAdapter->ExtraInfo = SW_RADIO_OFF;
					}
					break;

				case	RT_OID_RESET_FROM_ERROR:
				case	RT_OID_RESET_FROM_NDIS:
					{
						UINT	i = 0;

						RTUSBRejectPendingPackets(pAdapter);//reject all NDIS packets waiting in TX queue
						RTUSBCleanUpDataBulkOutQueue(pAdapter);
						MlmeSuspend(pAdapter);

						//Add code to access necessary registers here.
						//disable Rx
						RTUSBWriteMACRegister(pAdapter, TXRX_CSR2, 1);
						//Ask our device to complete any pending bulk in IRP.
						while ((atomic_read(&pAdapter->PendingRx) > 0) || (pAdapter->BulkOutPending == TRUE))
						{
							if (atomic_read(&pAdapter->PendingRx) > 0)
							{
								DBGPRINT_RAW(RT_DEBUG_TRACE, "BulkIn IRP Pending!!!\n");
								RTUSB_VendorRequest(pAdapter,
													0,
													DEVICE_VENDOR_REQUEST_OUT,
													0x0C,
													0x0,
													0x0,
													NULL,
													0);
							}

							if (pAdapter->BulkOutPending == TRUE)
							{
								DBGPRINT_RAW(RT_DEBUG_TRACE, "BulkOut IRP Pending!!!\n");
								if (i == 0)
								{
									RTUSBCancelPendingBulkOutIRP(pAdapter);
									i++;
								}
							}

							NdisMSleep(500000);
						}

						NICResetFromError(pAdapter);
						if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_HARDWARE_ERROR))
						{
							RTMP_CLEAR_FLAG(pAdapter, fRTMP_ADAPTER_HARDWARE_ERROR);
						}
						if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BULKIN_RESET))
						{
							RTMP_CLEAR_FLAG(pAdapter, fRTMP_ADAPTER_BULKIN_RESET);
						}
						if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BULKOUT_RESET))
						{
							RTMP_CLEAR_FLAG(pAdapter, fRTMP_ADAPTER_BULKOUT_RESET);
						}

						RTMP_CLEAR_FLAG(pAdapter, fRTMP_ADAPTER_RESET_IN_PROGRESS);

						if ((!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RADIO_OFF)) &&
							(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_HALT_IN_PROGRESS)) &&
							(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_REMOVE_IN_PROGRESS)))
						{
							MlmeResume(pAdapter);
							RTUSBBulkReceive(pAdapter);
							RTUSBWriteMACRegister(pAdapter, TXRX_CSR2, 0x7e);
						}
					}
					break;

				case	RT_OID_LINK_DOWN:
					DBGPRINT_RAW(RT_DEBUG_TRACE, "LinkDown(RT_OID_LINK_DOWN)\n");
					LinkDown(pAdapter);
					break;

				case	RT_OID_VENDOR_WRITE_BBP:
					{
						UCHAR	Offset, Value;
						Offset = *((PUCHAR)pData);
						Value = *((PUCHAR)(pData + 1));
						RTUSBWriteBBPRegister(pAdapter, Offset, Value);
					}
					break;

				case	RT_OID_VENDOR_READ_BBP:
					{
						UCHAR	Offset = *((PUCHAR)pData);
						PUCHAR	pValue = (PUCHAR)(pData + 1);

						DBGPRINT_RAW(RT_DEBUG_INFO, "offset = 0x%02x\n", Offset);
						RTUSBReadBBPRegister(pAdapter, Offset, pValue);
						DBGPRINT_RAW(RT_DEBUG_INFO, "value = 0x%02x\n", *pValue);
					}
					break;

				case	RT_OID_VENDOR_WRITE_RF:
					{
						ULONG	Value = *((PULONG)pData);

						DBGPRINT_RAW(RT_DEBUG_INFO, "value = 0x%08x\n", Value);
						RTUSBWriteRFRegister(pAdapter, Value);
					}
					break;
				    
				case	RT_OID_802_11_RESET_COUNTERS:
					{
						UCHAR	Value[22];

						RTUSBMultiReadMAC(pAdapter, STA_CSR0, Value, 22);
					}
					break;


				case	RT_OID_USB_VENDOR_RESET:
					RTUSB_VendorRequest(pAdapter,
										0,
										DEVICE_VENDOR_REQUEST_OUT,
										1,
										1,
										0,
										NULL,
										0);
					break;

				case	RT_OID_USB_VENDOR_UNPLUG:
					RTUSB_VendorRequest(pAdapter,
										0,
										DEVICE_VENDOR_REQUEST_OUT,
										1,
										2,
										0,
										NULL,
										0);
					break;

				case	RT_OID_USB_VENDOR_SWITCH_FUNCTION:
					RTUSBWriteMACRegister(pAdapter, MAC_CSR13, 0x2121);
					RTUSBWriteMACRegister(pAdapter, MAC_CSR14, 0x1e1e);
					RTUSBWriteMACRegister(pAdapter, MAC_CSR1, 3);
					RTUSBWriteMACRegister(pAdapter, PHY_CSR4, 0xf);

					RTUSB_VendorRequest(pAdapter,
										0,
										DEVICE_VENDOR_REQUEST_OUT,
										1,
										3,
										0,
										NULL,
										0);
					break;

				case	RT_OID_VENDOR_FLIP_IQ:
					{
						USHORT	Value1, Value2;
						RTUSBReadMACRegister(pAdapter, PHY_CSR5, &Value1);
						RTUSBReadMACRegister(pAdapter, PHY_CSR6, &Value2);
						if (*pData == 1)
						{
							DBGPRINT_RAW(RT_DEBUG_INFO, "I/Q Flip\n");
							Value1 = Value1 | 0x0004;
							Value2 = Value2 | 0x0004;
						}
						else
						{
							DBGPRINT_RAW(RT_DEBUG_INFO, "I/Q Not Flip\n");
							Value1 = Value1 & 0xFFFB;
							Value2 = Value2 & 0xFFFB;
						}
						RTUSBWriteMACRegister(pAdapter, PHY_CSR5, Value1);
						RTUSBWriteMACRegister(pAdapter, PHY_CSR6, Value2);
					}
					break;

				case	RT_OID_UPDATE_TX_RATE:
					MlmeUpdateTxRates(pAdapter, FALSE);
					if (ADHOC_ON(pAdapter))
						MakeIbssBeacon(pAdapter);
					break;

#if 0
				case	RT_OID_UPDATE_R17:
					switch ((pAdapter->SET_R17_FLAG % 3)) 
					{
						case 1:				        	
							RTUSBWriteBBPRegister(pAdapter, 17, pAdapter->BBPTuningParameters.BBPR17LowSensitivity);
							RTUSBWriteBBPRegister(pAdapter, 24, pAdapter->BBPTuningParameters.R24HigherValue);
							RTUSBWriteBBPRegister(pAdapter, 25, pAdapter->BBPTuningParameters.R25HigherValue);
							RTUSBWriteBBPRegister(pAdapter, 61, pAdapter->BBPTuningParameters.R61HigherValue);
							DBGPRINT(RT_DEBUG_TRACE,("RT_OID_UPDATE_1 R17 = %x\n",pAdapter->BBPTuningParameters.BBPR17LowSensitivity));
							break;
						case 2:
							RTUSBWriteBBPRegister(pAdapter, 17, pAdapter->PortCfg.BbpTuning.VgcUpperBound);
							RTUSBWriteBBPRegister(pAdapter, 24, pAdapter->BBPTuningParameters.R24LowerValue);
							RTUSBWriteBBPRegister(pAdapter, 25, pAdapter->BBPTuningParameters.R25LowerValue);
							RTUSBWriteBBPRegister(pAdapter, 61, pAdapter->BBPTuningParameters.R61LowerValue);
							DBGPRINT(RT_DEBUG_TRACE,("RT_OID_UPDATE_2 R17 = %x\n",pAdapter->PortCfg.BbpTuning.VgcUpperBound));
							break;
						case 0:
							RTUSBWriteBBPRegister(pAdapter, 17, pAdapter->BBPR17InitValue);
							RTUSBWriteBBPRegister(pAdapter, 24, pAdapter->BBPTuningParameters.R24LowerValue);
							RTUSBWriteBBPRegister(pAdapter, 25, pAdapter->BBPTuningParameters.R25LowerValue);
							RTUSBWriteBBPRegister(pAdapter, 61, pAdapter->BBPTuningParameters.R61LowerValue);
							DBGPRINT(RT_DEBUG_TRACE,("RT_OID_UPDATE_0 R17 = %x\n",pAdapter->BBPR17InitValue));
							break;     
					}
					break;
#endif
				case	RT_OID_802_11_PREAMBLE:
					{
						ULONG	Preamble = *((PULONG)(cmdqelmt->buffer));
						if (Preamble == Rt802_11PreambleShort)
						{
							pAdapter->PortCfg.WindowsTxPreamble = Preamble;
							MlmeSetTxPreamble(pAdapter, Rt802_11PreambleShort);
						}
						else if ((Preamble == Rt802_11PreambleLong) || (Preamble == Rt802_11PreambleAuto))
						{
							// if user wants AUTO, initialize to LONG here, then change according to AP's
							// capability upon association.
							pAdapter->PortCfg.WindowsTxPreamble = Preamble;
							MlmeSetTxPreamble(pAdapter, Rt802_11PreambleLong);
						}
						DBGPRINT(RT_DEBUG_TRACE, "Set::RT_OID_802_11_SET_PREAMBLE (=%d)\n", Preamble);
					}
					break;

				case	OID_802_11_NETWORK_TYPE_IN_USE:
					{
						NDIS_802_11_NETWORK_TYPE	NetType = *(PNDIS_802_11_NETWORK_TYPE)(cmdqelmt->buffer);
						if (NetType == Ndis802_11DS)
							RTMPSetPhyMode(pAdapter, PHY_11B);
						else if (NetType == Ndis802_11OFDM24)
							RTMPSetPhyMode(pAdapter, PHY_11BG_MIXED);
						else if (NetType == Ndis802_11OFDM5)
							RTMPSetPhyMode(pAdapter, PHY_11A);
						DBGPRINT(RT_DEBUG_ERROR, "Set::OID_802_11_NETWORK_TYPE_IN_USE (=%d)\n",NetType);
					}
					break;

				case	RT_OID_802_11_PHY_MODE:
					{
						ULONG	phymode = *(ULONG *)(cmdqelmt->buffer);
						RTMPSetPhyMode(pAdapter, phymode);
						DBGPRINT(RT_DEBUG_ERROR, "Set::RT_OID_802_11_SET_PHY_MODE (=%d)\n", phymode);
					}
					break;

				case	OID_802_11_WEP_STATUS:
					{
						USHORT	Value;
						NDIS_802_11_WEP_STATUS	WepStatus = *(PNDIS_802_11_WEP_STATUS)pData;
						if (pAdapter->PortCfg.WepStatus != WepStatus)
						{
							// Config has changed
							pAdapter->bConfigChanged = TRUE;
							pAdapter->PortCfg.WepStatus = WepStatus;
							pAdapter->PortCfg.OrigWepStatus = WepStatus;
							pAdapter->PortCfg.PairCipher = WepStatus;
							pAdapter->PortCfg.GroupCipher = WepStatus;								
						}
							
						if ((WepStatus == Ndis802_11Encryption1Enabled) && (pAdapter->PortCfg.SharedKey[pAdapter->PortCfg.DefaultKeyId].KeyLen != 0))
						{
							if (pAdapter->PortCfg.SharedKey[pAdapter->PortCfg.DefaultKeyId].KeyLen <= 5)
								pAdapter->PortCfg.CipherAlg = CIPHER_WEP64;
							else
								pAdapter->PortCfg.CipherAlg = CIPHER_WEP128;

							RTUSBReadMACRegister(pAdapter, TXRX_CSR0, &Value);
							Value &= 0xfe00;
							Value |= ((LENGTH_802_11 << 3) | (pAdapter->PortCfg.CipherAlg));
							RTUSBWriteMACRegister(pAdapter, TXRX_CSR0, Value);
						}
						else if (WepStatus == Ndis802_11Encryption2Enabled)
						{
							pAdapter->PortCfg.CipherAlg = CIPHER_TKIP;

							RTUSBReadMACRegister(pAdapter, TXRX_CSR0, &Value);
							Value &= 0xfe00;
							Value |= ((LENGTH_802_11 << 3) | (pAdapter->PortCfg.CipherAlg));
							RTUSBWriteMACRegister(pAdapter, TXRX_CSR0, Value);
						}
						else if (WepStatus == Ndis802_11Encryption3Enabled)
						{
							pAdapter->PortCfg.CipherAlg = CIPHER_AES;

							RTUSBReadMACRegister(pAdapter, TXRX_CSR0, &Value);
							Value &= 0xfe00;
							Value |= ((LENGTH_802_11 << 3) | (pAdapter->PortCfg.CipherAlg));
							RTUSBWriteMACRegister(pAdapter, TXRX_CSR0, Value);
						}
						else if (WepStatus == Ndis802_11EncryptionDisabled)
						{
							pAdapter->PortCfg.CipherAlg = CIPHER_NONE;

							RTUSBReadMACRegister(pAdapter, TXRX_CSR0, &Value);
							Value &= 0xfe00;
							RTUSBWriteMACRegister(pAdapter, TXRX_CSR0, Value);
						}
						DBGPRINT(RT_DEBUG_TRACE, "OID_802_11_WEP_STATUS::TXRX_CSR0 (value=0x%x)\n", Value);
					}
					break;

				case	OID_802_11_ADD_WEP:
					{
						ULONG	KeyIdx;
						TXRX_CSR0_STRUC  TxRxCsr0;
						PNDIS_802_11_WEP	pWepKey = (PNDIS_802_11_WEP)pData;

						KeyIdx = pWepKey->KeyIndex & 0x0fffffff;
						if (KeyIdx <= 4)
						{
							pAdapter->PortCfg.SharedKey[KeyIdx].KeyLen = (UCHAR)pWepKey->KeyLength;
							memset(pAdapter->PortCfg.SharedKey[KeyIdx].Key, 0, MAX_LEN_OF_KEY);
							memcpy(pAdapter->PortCfg.SharedKey[KeyIdx].Key, &pWepKey->KeyMaterial, pWepKey->KeyLength);

							RTUSBMultiWriteMAC(pAdapter, (USHORT)(SEC_CSR0 + KeyIdx * 0x10), pAdapter->PortCfg.SharedKey[KeyIdx].Key, 16);//steven:always write 16 bytes.

							if (pWepKey->KeyIndex & 0x80000000)
							{
								// Default key for tx (shared key)
								pAdapter->PortCfg.DefaultKeyId = (UCHAR)KeyIdx;

								if (pWepKey->KeyLength <= 5)
									pAdapter->PortCfg.CipherAlg = CIPHER_WEP64;
								else
									pAdapter->PortCfg.CipherAlg = CIPHER_WEP128;

								RTUSBReadMACRegister(pAdapter, TXRX_CSR0, &TxRxCsr0.value);
								TxRxCsr0.value &= 0xfe00;
								TxRxCsr0.field.IVOffset = LENGTH_802_11;
								TxRxCsr0.field.Algorithm = pAdapter->PortCfg.CipherAlg;
								TxRxCsr0.field.KeyID |= (0x01 << KeyIdx);
						DBGPRINT(RT_DEBUG_TRACE, "Set::TXRX_CSR0 (value=0x%x)\n", TxRxCsr0.value);
								RTUSBWriteMACRegister(pAdapter, TXRX_CSR0, TxRxCsr0.value);
							}
						}
						DBGPRINT(RT_DEBUG_TRACE, "Set::OID_802_11_ADD_WEP (id=%d, Len=%d-byte)\n", KeyIdx, pWepKey->KeyLength);
					}
					break;
				    
				case	OID_802_11_ADD_KEY_WEP:
					{
						PNDIS_802_11_KEY	pKey = (PNDIS_802_11_KEY)pData;
						TXRX_CSR0_STRUC  TxRxCsr0;							
						ULONG	KeyIdx = pKey->KeyIndex & 0x0fffffff;

						// it is a shared key
						if (KeyIdx <= 4)
						{
							pAdapter->PortCfg.SharedKey[KeyIdx].KeyLen = (UCHAR)pKey->KeyLength;

							memset(pAdapter->PortCfg.SharedKey[KeyIdx].Key, 0, MAX_LEN_OF_KEY);
							memcpy(pAdapter->PortCfg.SharedKey[KeyIdx].Key, &pKey->KeyMaterial, pKey->KeyLength);
							RTUSBMultiWriteMAC(pAdapter, (USHORT)(SEC_CSR0 + KeyIdx * 0x10), pAdapter->PortCfg.SharedKey[KeyIdx].Key, 16);

							if (pKey->KeyIndex & 0x80000000)
							{
								// Default key for tx (shared key)
								pAdapter->PortCfg.DefaultKeyId = (UCHAR)KeyIdx;

								if (pKey->KeyLength <= 5)
									pAdapter->PortCfg.CipherAlg = CIPHER_WEP64;
								else
									pAdapter->PortCfg.CipherAlg = CIPHER_WEP128;

								RTUSBReadMACRegister(pAdapter, TXRX_CSR0, &TxRxCsr0.value);
								TxRxCsr0.value &= 0xfe00;
								TxRxCsr0.field.IVOffset = LENGTH_802_11;
								TxRxCsr0.field.Algorithm = pAdapter->PortCfg.CipherAlg;
								TxRxCsr0.field.KeyID |= (0x01 << KeyIdx);
								RTUSBWriteMACRegister(pAdapter, TXRX_CSR0, TxRxCsr0.value);									
								DBGPRINT(RT_DEBUG_TRACE, "Set::OID_802_11_ADD_WEP TXRX_CSR0=(0x%08x)\n",TxRxCsr0.value);								
							}
						}
					}
					break;

				case	OID_802_11_ADD_KEY:
					DBGPRINT(RT_DEBUG_TRACE, "Set::OID_802_11_ADD_KEY  \n");								
{
	int	i = 0;
		DBGPRINT(RT_DEBUG_INFO,"pKey->KeyMaterial = ");
		for (i = 0; i < 16; i++)
		{
			DBGPRINT_RAW(RT_DEBUG_INFO,"%02x:",
			  ((PNDIS_802_11_KEY)pData)->KeyMaterial[i]);
		}
		DBGPRINT_RAW(RT_DEBUG_INFO,"\n");						
}
					NdisStatus = RTMPWPAAddKeyProc(pAdapter, pData);
							RTUSBBulkReceive(pAdapter);

					break;

				case	OID_802_11_REMOVE_KEY:
					NdisStatus = RTMPWPARemoveKeyProc(pAdapter, pData);
					break;

				case RT_OID_REMOVE_ALLKEYS:
					RTMPWPARemoveAllKeys(pAdapter);
					break;
#if 0
				case RT_OID_802_11_QUERY_HARDWARE_REGISTER:
					NdisStatus = RTUSBQueryHardWareRegister(pAdapter, pData);
					break;
				case RT_OID_802_11_SET_HARDWARE_REGISTER:
					NdisStatus = RTMPSetHardWareRegister(pAdapter, pData);
					break;
#endif					
			
			default:
			break;
		}

		if (cmdqelmt->CmdFromNdis == TRUE)
		{
			if ((cmdqelmt->command != OID_802_11_BSSID_LIST_SCAN) &&
				(cmdqelmt->command != RT_OID_802_11_BSSID) &&
				(cmdqelmt->command != OID_802_11_SSID) &&
				(cmdqelmt->command != OID_802_11_DISASSOCIATE))
			{
			}

			if ((cmdqelmt->command != RT_OID_SINGLE_READ_MAC) &&
				(cmdqelmt->command != RT_OID_MULTI_READ_MAC) &&
				(cmdqelmt->command != RT_OID_VENDOR_READ_BBP) &&
#ifdef DBG					
				(cmdqelmt->command != RT_OID_802_11_QUERY_HARDWARE_REGISTER) &&
#endif					
				(cmdqelmt->command != RT_OID_USB_VENDOR_EEPROM_READ))
			{
				if (cmdqelmt->buffer != NULL)
					kfree(cmdqelmt->buffer);
			}
			
			kfree((PCmdQElmt)cmdqelmt);
		}
		else
			cmdqelmt->InUse = FALSE;			

	}


}

static int usb_rtusb_open(struct net_device *net_dev)
{

	PRT2570ADAPTER pAdapter = (PRT2570ADAPTER) net_dev->priv;
	NDIS_STATUS 	Status = NDIS_STATUS_SUCCESS;
	NDIS_802_11_WEP WepKey;

	printk("RT25usb  Driver version %x.%x.%x\n", DRV_MAJORVERSION,DRV_MINORVERSION, DRV_SUBVERSION);

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
    if (!try_module_get(THIS_MODULE))
    {
        DBGPRINT(RT_DEBUG_ERROR, "%s: cannot reserve module\n", __FUNCTION__);
        return -1;
    }
#else
    MOD_INC_USE_COUNT;
#endif

	init_MUTEX(&(pAdapter->usbdev_semaphore));
	
	// init mediastate to disconnected
	pAdapter->MediaState = NdisMediaStateDisconnected;
	
	pAdapter->rx_bh.func = RTUSBRxPacket;
	// Init  RTMP_ADAPTER CmdQElements
	Status = RT2570InitAdapterBlock(pAdapter);
	if (Status != NDIS_STATUS_SUCCESS)
	{
		return Status;
	}

	//NdisAllocateSpinLock
	// Init send data structures and related parameters
	//
	Status = NICInitTransmit(pAdapter);
	if (Status != NDIS_STATUS_SUCCESS)
	{
		return Status;
	}

	//
	// Init receive data structures and related parameters
	//
	Status = NICInitRecv(pAdapter);
	if (Status != NDIS_STATUS_SUCCESS)
	{
		goto out;
	}

	RT2570InitializeAsic(pAdapter);
	// RTMPReadParametersFromFile(pAdapter);
	// Init the hardware and set up everything
	//
	
	NICReadEEPROMParameters(pAdapter);

	NICInitAsicFromEEPROM(pAdapter);

	RTUSBWriteHWMACAddress(pAdapter);
	
	// initialize MLME
	Status = MlmeInit(pAdapter);
	if(Status != NDIS_STATUS_SUCCESS)
	{
		goto out;
	}

	// mlmethread flag restart
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
	mlme_kill = 0;
	RTUSBCmd_kill =0;
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0) */
	CreateThreads(net_dev);

	// at every open handler, copy mac address.
	memcpy(pAdapter->net->dev_addr, pAdapter->CurrentAddress, pAdapter->net->addr_len);

	// Clear Reset Flag before starting receiving/transmitting
	RTMP_CLEAR_FLAG(pAdapter, fRTMP_ADAPTER_RESET_IN_PROGRESS);

	
	if (!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RADIO_OFF))
	{
		RTUSBBulkReceive(pAdapter);
		RTUSBWriteMACRegister(pAdapter, TXRX_CSR2, 0x7e);
	} 
	// start as if the link is up
	//netif_device_attach (pAdapter->net);
	// Start net interface tx /rx
	netif_start_queue(net_dev);
	netif_carrier_on(net_dev);
	netif_wake_queue(net_dev);

	if (pAdapter->PortCfg.WepStatus != Ndis802_11WEPDisabled)
	{
		memcpy(WepKey.KeyMaterial, pAdapter->PortCfg.SharedKey[pAdapter->PortCfg.DefaultKeyId].Key, pAdapter->PortCfg.SharedKey[pAdapter->PortCfg.DefaultKeyId].KeyLen);
                WepKey.KeyIndex = 0x80000000 + pAdapter->PortCfg.DefaultKeyId;
                WepKey.KeyLength = pAdapter->PortCfg.SharedKey[pAdapter->PortCfg.DefaultKeyId].KeyLen;
		RTUSBEnqueueCmdFromNdis(pAdapter, OID_802_11_ADD_WEP, TRUE, &WepKey, sizeof(WepKey));
	}

	return 0;
out:
	ReleaseAdapter(pAdapter, FALSE);

	return 0;

}


#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
static int usb_rtusb_close(struct net_device *net)
{
	PRT2570ADAPTER pAdapter = (PRT2570ADAPTER) net->priv;
	int ret;
	DECLARE_WAIT_QUEUE_HEAD (unlink_wakeup); 
	DECLARE_WAITQUEUE (wait, current);
	int	i = 0;
	printk("enter usb_rtusb_close( )\n");
	DBGPRINT(RT_DEBUG_TEMP,"-->usb_rt2570_close \n");
	netif_carrier_off(pAdapter->net);
	netif_stop_queue(pAdapter->net);

	DBGPRINT(RT_DEBUG_TEMP,"Ensure there are no more active urbs \n");
	// ensure there are no more active urbs. 
	add_wait_queue (&unlink_wakeup, &wait);
	pAdapter->wait = &unlink_wakeup;
	// maybe wait for deletions to finish.
	while ((i < 10) && atomic_read(&pAdapter->PendingRx) > 0) {
		//msleep(UNLINK_TIMEOUT_MS);
		i++;
		DBGPRINT ( RT_DEBUG_TEMP,"waited for %d urb to complete\n", atomic_read(&pAdapter->PendingRx));
	}
	pAdapter->wait = NULL;
	remove_wait_queue (&unlink_wakeup, &wait); 

#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
	if (pAdapter->MLMEThr_pid >= 0)
	{
		mlme_kill = 1;
		RTUSBUp(pAdapter, (&(pAdapter->mlme_semaphore)));
		wmb(); // need to check
		ret = kill_proc (pAdapter->MLMEThr_pid, SIGTERM, 1);
		if (ret) 
		{
			printk (KERN_ERR "%s: unable to signal thread\n", pAdapter->net->name);
			return ret;
		}
		wait_for_completion (&pAdapter->notify);
	}
	if (pAdapter->RTUSBCmdThr_pid>= 0)
	{
		RTUSBCmd_kill = 1;
		RTUSBUp(pAdapter, (&(pAdapter->RTUSBCmd_semaphore)));
		wmb(); // need to check
		ret = kill_proc (pAdapter->RTUSBCmdThr_pid, SIGTERM, 1);
		if (ret) 
		{
			printk (KERN_ERR "%s: unable to signal thread\n", pAdapter->net->name);
			return ret;
		}
		wait_for_completion (&pAdapter->notify);
	}
#else
	if (pAdapter->MLMEThr_active)
	{
		ret = kthread_stop(pAdapter->MLMEThr);
		if (ret) 
		{
			printk (KERN_ERR "%s: unable to stop thread\n", pAdapter->net->name);
			return ret;
		}
	}
	if (pAdapter->RTUSBCmdThr_active)
	{
		ret = kthread_stop(pAdapter->RTUSBCmdThr);
		if (ret) 
		{
			printk (KERN_ERR "%s: unable to stop thread\n", pAdapter->net->name);
			return ret;
		}
	}
#endif
	RTUSBHalt( pAdapter, FALSE);
	DBGPRINT(RT_DEBUG_TEMP,"<--usb_rt2570_close\n");

	MOD_DEC_USE_COUNT;

	return 0;
}

int MlmeThread(void * Context)
{
	PRT2570ADAPTER	pAdapter = (PRT2570ADAPTER)Context;
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
	pAdapter->MLMEThr_active = 1;
#else
	daemonize();
	current->flags |= PF_NOFREEZE;
	/* signal that we've started the thread */
	complete(&(pAdapter->notify));
#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) */

	while (1)
	{
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
		if (kthread_should_stop())
			break;
#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) */
		/* lock the device pointers */
		down(&(pAdapter->mlme_semaphore));

#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
		if (mlme_kill)
			break;
#endif
		/* lock the device pointers , need to check if required*/
		down(&(pAdapter->usbdev_semaphore));
		MlmeHandler(pAdapter);		

		/* unlock the device pointers */
		up(&(pAdapter->usbdev_semaphore));
	}

#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
	/* notify the exit routine that we're actually exiting now 
	*
	* complete()/wait_for_completion() is similar to up()/down(),
	* except that complete() is safe in the case where the structure
	* is getting deleted in a parallel mode of execution (i.e. just
	* after the down() -- that's necessary for the thread-shutdown
	* case.
	*
	* complete_and_exit() goes even further than this -- it is safe in
	* the case that the thread of the caller is going away (not just
	* the structure) -- this is necessary for the module-remove case.
	* This is important in preemption kernels, which transfer the flow
	* of execution immediately upon a complete().
	*/
	complete_and_exit (&pAdapter->notify, 0);
	DBGPRINT(RT_DEBUG_TRACE, "<---MlmeThread\n");
#else
	DBGPRINT(RT_DEBUG_TRACE, "MlmeThread end\n");
	pAdapter->MLMEThr_active = 0;
#endif
	return 0;
}

int RTUSBCmdThread(void * Context)
{
	PRT2570ADAPTER	pAdapter = (PRT2570ADAPTER)Context;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
	daemonize();
	current->flags |= PF_NOFREEZE;
	/* signal that we've started the thread */
	complete(&(pAdapter->notify));
#else
	pAdapter->RTUSBCmdThr_active = 1;
#endif

	while (1)
	{
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
		if (kthread_should_stop())
			break;
#endif

		/* lock the device pointers */
		down(&(pAdapter->RTUSBCmd_semaphore));
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
		if (RTUSBCmd_kill)
			break;
#endif
		/* lock the device pointers , need to check if required*/
		down(&(pAdapter->usbdev_semaphore));
		CMDHandler(pAdapter);		

		/* unlock the device pointers */
		up(&(pAdapter->usbdev_semaphore));
	}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
	complete_and_exit (&pAdapter->notify, 0);
	DBGPRINT(RT_DEBUG_TRACE, "<---RTUSBCmdThread\n");
#else
	DBGPRINT(RT_DEBUG_TRACE, "RTUSBCmdThread end\n");
	pAdapter->RTUSBCmdThr_active = 0;
#endif
	return 0;
}

static void *usb_rtusb_probe(struct usb_device *dev, UINT interface,
				const struct usb_device_id *id_table)
{	
	PRT2570ADAPTER pAdapter = (PRT2570ADAPTER)NULL;
	int i;
	struct net_device *netdev;
	int res = -ENOMEM;
 
	
	for (i = 0; i < rtusb_usb_id_len; i++)
	{
		if (le16_to_cpu(dev->descriptor.idVendor) == rtusb_usb_id[i].idVendor &&
			le16_to_cpu(dev->descriptor.idProduct) == rtusb_usb_id[i].idProduct)
		{
			printk("idVendor = 0x%x, idProduct = 0x%x \n",
				le16_to_cpu(dev->descriptor.idVendor),
				le16_to_cpu(dev->descriptor.idProduct));
			break;
		}
	}
	if (i == rtusb_usb_id_len) {
		printk("Device Descriptor not matching\n");
		return NULL;
	}

	netdev = alloc_etherdev(sizeof (*pAdapter));
	if(!netdev)
	{
		//if (!(pAdapter->net = init_etherdev(0, 0) )) {
		printk("alloc_etherdev failed\n");
			
		MOD_DEC_USE_COUNT;
		usb_dec_dev_use(dev);
		return NULL;
	}
	
	pAdapter = netdev->priv;
	pAdapter->net = netdev;
	netif_stop_queue(netdev);
	pAdapter->config = dev->config;
	pAdapter->usb = dev;
	SET_MODULE_OWNER(pAdapter->net);
	ether_setup(pAdapter->net);
	netdev->open = usb_rtusb_open;
	netdev->hard_start_xmit = RTUSBSendPackets;
	netdev->stop = usb_rtusb_close;
	netdev->priv = pAdapter;
	netdev->get_stats = rt_getstats;
#if WIRELESS_EXT >= 11
	netdev->get_wireless_stats = RTUSB_get_wireless_stats;
	netdev->wireless_handlers = (struct iw_handler_def *) &rt2500usb_iw_handler_def;
#endif
	netdev->set_mac_address = rt2570_set_mac_address;
	netdev->do_ioctl = usb_rt2570_ioctl;
	pAdapter->net->hard_header_len = 14;
	pAdapter->net->mtu = 1500;
	pAdapter->net->addr_len = 6;
	pAdapter->net->weight = 64;
	pAdapter->MediaState = NdisMediaStateDisconnected;


	{// find available 
		int 	i=0;
		char	slot_name[IFNAMSIZ];
		struct net_device	*device;

		for (i = 0; i < 8; i++)
		{
			sprintf(slot_name, "rausb%d", i);
			
			for (device = dev_base; device != NULL; device = device->next)
			{
				if (strncmp(device->name, slot_name, 6) == 0)
				{
					break;
				}
			}
			if(device == NULL)	break;
		}
		if(i == 8)
		{
			DBGPRINT(RT_DEBUG_ERROR, "No available slot name\n");
			return NULL;
		}

		sprintf(pAdapter->net->name, "rausb%d", i);
		DBGPRINT(RT_DEBUG_ERROR, "usbdevice->name %s\n",pAdapter->net->name);
	}

	//pAdapter->rx_bh.data = (unsigned long)pAdapter;

	pAdapter->rx_bh.func = RTUSBRxPacket;
	res = register_netdev(pAdapter->net);
	if (res)
		goto out3;

	// start as if the link is up
	// netif_device_attach (pAdapter->net);

	PortCfgInit(pAdapter);

	return pAdapter;
out3:
	printk("3 register_netdev failed err=%d\n",res);

	return NULL;
}
//Disconnect function is called within exit routine
static void usb_rtusb_disconnect(struct usb_device *dev, void *ptr)
{
	PRT2570ADAPTER pAdapter = (PRT2570ADAPTER) ptr;
	

	if (!pAdapter)
		return;
	
	tasklet_kill(&pAdapter->rx_bh);
	RTMP_SET_FLAG(pAdapter, fRTMP_ADAPTER_REMOVE_IN_PROGRESS);
	// for debug, wait to show some messages to /proc system
	udelay(1);
	//After Add Thread implementation, Upon exec there, pAdapter->net seems becomes NULL, 
	//need to check why???
	//assert(pAdapter->net != NULL)
	if(pAdapter->net != NULL)
	{
		printk("unregister_netdev( )\n");
		unregister_netdev (pAdapter->net);
	}

	DBGPRINT(RT_DEBUG_ERROR,"<=== RTUSB disconnect successfully\n");

}

#else
static int usb_rtusb_close(struct net_device *net)
{
	PRT2570ADAPTER pAdapter = (PRT2570ADAPTER) net->priv;
	int ret;
	DECLARE_WAIT_QUEUE_HEAD (unlink_wakeup); 
	DECLARE_WAITQUEUE (wait, current);
	int	i = 0;
	netif_carrier_off(pAdapter->net);
	netif_stop_queue(pAdapter->net);

	// ensure there are no more active urbs. 
	add_wait_queue (&unlink_wakeup, &wait);
	pAdapter->wait = &unlink_wakeup;
	
	// maybe wait for deletions to finish.
	while ((i < 25) && atomic_read(&pAdapter->PendingRx) > 0) {
#if LINUX_VERSION_CODE >KERNEL_VERSION(2,6,9)

		msleep(UNLINK_TIMEOUT_MS);
#endif
		i++;
	}
	pAdapter->wait = NULL;
	remove_wait_queue (&unlink_wakeup, &wait); 

#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
	if (pAdapter->MLMEThr_pid >= 0)
	{
		mlme_kill = 1;
		RTUSBUp(pAdapter, (&(pAdapter->mlme_semaphore)));
		wmb(); // need to check
		ret = kill_proc (pAdapter->MLMEThr_pid, SIGTERM, 1);
		if (ret) 
		{
			printk (KERN_ERR "%s: unable to signal thread\n", pAdapter->net->name);
			return ret;
		}
		wait_for_completion (&pAdapter->notify);
	}
	if (pAdapter->RTUSBCmdThr_pid>= 0)
	{
		RTUSBCmd_kill = 1;
		RTUSBUp(pAdapter, (&(pAdapter->RTUSBCmd_semaphore)));
		wmb(); // need to check
		ret = kill_proc (pAdapter->RTUSBCmdThr_pid, SIGTERM, 1);
		if (ret) 
		{
			printk (KERN_ERR "%s: unable to signal thread\n", pAdapter->net->name);
			return ret;
		}
		wait_for_completion (&pAdapter->notify);
	}
#else
	if (pAdapter->MLMEThr_active)
	{
		ret = kthread_stop(pAdapter->MLMEThr);
		if (ret) 
		{
			printk (KERN_ERR "%s: unable to stop thread\n", pAdapter->net->name);
			return ret;
		}
	}
	if (pAdapter->RTUSBCmdThr_active)
	{
		ret = kthread_stop(pAdapter->RTUSBCmdThr);
		if (ret) 
		{
			printk (KERN_ERR "%s: unable to stop thread\n", pAdapter->net->name);
			return ret;
		}
	}
#endif
	RTUSBHalt( pAdapter, FALSE);
	DBGPRINT(RT_DEBUG_TEMP,"<--usb_rt2570_close\n");

	module_put(THIS_MODULE);

	return 0;
}

int MlmeThread(void * Context)
{
	PRT2570ADAPTER	pAdapter = (PRT2570ADAPTER)Context;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
	daemonize("rt2500usb");
	allow_signal(SIGTERM);
	current->flags |= PF_NOFREEZE;
	/* signal that we've started the thread */
	complete(&(pAdapter->notify));
#else
	pAdapter->MLMEThr_active = 1;
#endif

	while (1)
	{
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
		if (kthread_should_stop())
			break;
#endif
		/* lock the device pointers */
		down(&(pAdapter->mlme_semaphore));

#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
		if (mlme_kill)
			break;
#endif
		/* lock the device pointers , need to check if required*/
		down(&(pAdapter->usbdev_semaphore));

		MlmeHandler(pAdapter);		

		/* unlock the device pointers */
		up(&(pAdapter->usbdev_semaphore));
	}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
	complete_and_exit (&pAdapter->notify, 0);
	DBGPRINT(RT_DEBUG_TRACE, "<---MlmeThread\n");
#else
	DBGPRINT(RT_DEBUG_TRACE, "MlmeThread end\n");
	pAdapter->MLMEThr_active = 0;
#endif
	return 0;
}

int RTUSBCmdThread(void * Context)
{

	PRT2570ADAPTER	pAdapter = (PRT2570ADAPTER)Context;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
	daemonize("rt2500usb");
	allow_signal(SIGTERM);
	current->flags |= PF_NOFREEZE;
	/* signal that we've started the thread */
	complete(&(pAdapter->notify));
#else
	pAdapter->RTUSBCmdThr_active = 1;
#endif

	while (1)
	{
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
		if (kthread_should_stop())
			break;
#endif
		/* lock the device pointers */
		down(&(pAdapter->RTUSBCmd_semaphore));
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
		if (RTUSBCmd_kill)
			break;
#endif
		/* lock the device pointers , need to check if required*/
		down(&(pAdapter->usbdev_semaphore));

		CMDHandler(pAdapter);		

		/* unlock the device pointers */
		up(&(pAdapter->usbdev_semaphore));
	}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
	complete_and_exit (&pAdapter->notify, 0);
	DBGPRINT(RT_DEBUG_TRACE, "<---RTUSBCmdThread\n");
#else
	DBGPRINT(RT_DEBUG_TRACE, "RTUSBCmdThread end\n");
	pAdapter->RTUSBCmdThr_active = 0;
#endif
	return 0;
}

static int usb_rtusb_probe (struct usb_interface *intf,
					  const struct usb_device_id *id)
{	
	struct usb_device *dev = interface_to_usbdev(intf);
	PRT2570ADAPTER pAdapter = (PRT2570ADAPTER)NULL;
	int i;
	struct net_device *netdev;
	int res = -ENOMEM;
 
	
	usb_get_dev(dev);
	for (i = 0; i < rtusb_usb_id_len; i++)
	{
		if (le16_to_cpu(dev->descriptor.idVendor) == rtusb_usb_id[i].idVendor &&
			le16_to_cpu(dev->descriptor.idProduct) == rtusb_usb_id[i].idProduct)
		{
			printk("idVendor = 0x%x, idProduct = 0x%x \n",
				le16_to_cpu(dev->descriptor.idVendor),
				le16_to_cpu(dev->descriptor.idProduct));
			break;
		}
	}
	if (i == rtusb_usb_id_len) {
		printk("Device Descriptor not matching\n");
		return res;
	}

	netdev = alloc_etherdev(sizeof (*pAdapter));
	if(!netdev)
	{
		//if (!(pAdapter->net = init_etherdev(0, 0) )) {
		printk("alloc_etherdev failed\n");
	
		module_put(THIS_MODULE);
		return res;
	}
	
	pAdapter = netdev->priv;
	pAdapter->net = netdev;
	netif_stop_queue(netdev);
	pAdapter->config = &dev->config->desc;
	pAdapter->usb = dev;
	SET_MODULE_OWNER(pAdapter->net);
	ether_setup(pAdapter->net);
	netdev->open = usb_rtusb_open;
	netdev->stop = usb_rtusb_close;
	netdev->priv = pAdapter;
	netdev->hard_start_xmit = RTUSBSendPackets;
	netdev->get_stats = rt_getstats;
#if 1
#if WIRELESS_EXT >= 12
	netdev->get_wireless_stats = RTUSB_get_wireless_stats;
	netdev->wireless_handlers = (struct iw_handler_def *) &rt2500usb_iw_handler_def;
#endif
	netdev->do_ioctl = usb_rt2570_ioctl;
#endif
	pAdapter->net->set_mac_address = rt2570_set_mac_address;
	pAdapter->net->hard_header_len = 14;
	pAdapter->net->mtu = 1500;
	pAdapter->net->addr_len = 6;
	pAdapter->net->weight = 64;
	pAdapter->MediaState = NdisMediaStateDisconnected;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
	pAdapter->MLMEThr_pid= -1;
	pAdapter->RTUSBCmdThr_pid= -1;
#else
	pAdapter->MLMEThr_active = 0;
	pAdapter->RTUSBCmdThr_active = 0;
#endif
	RTMP_SET_FLAG(pAdapter, fRTMP_ADAPTER_RESET_IN_PROGRESS);

	SET_NETDEV_DEV(pAdapter->net, &intf->dev);

	{// find available 
		int 	i=0;
		char	slot_name[IFNAMSIZ];
		struct net_device	*device;

		for (i = 0; i < 8; i++)
		{
			sprintf(slot_name, "rausb%d", i);
			
			for (device = dev_base; device != NULL; device = device->next)
			{
				if (strncmp(device->name, slot_name, 6) == 0)
				{
					break;
				}
			}
			if(device == NULL)	break;
		}
		if(i == 8)
		{
			DBGPRINT(RT_DEBUG_ERROR, "No available slot name\n");
			return res;
		}

		sprintf(pAdapter->net->name, "rausb%d", i);
	}

	pAdapter->rx_bh.func = RTUSBRxPacket;
	//bottom half data is assign at  each task_scheduler
	//pAdapter->rx_bh.data = (unsigned long)pAdapter;

	res = register_netdev(pAdapter->net);
	if (res)
		goto out3;

	usb_set_intfdata(intf, pAdapter);

	PortCfgInit(pAdapter);

	return 0;
out3:
	printk("3 register_netdev failed err=%d\n",res);
	free_netdev(netdev);

	return -1;
}
static void usb_rtusb_disconnect(struct usb_interface *intf)
{
	struct usb_device *dev = interface_to_usbdev(intf);
	PRT2570ADAPTER pAdapter = (PRT2570ADAPTER)NULL;
	
	pAdapter = usb_get_intfdata(intf);

	usb_set_intfdata(intf, NULL);
	RTMP_SET_FLAG(pAdapter, fRTMP_ADAPTER_REMOVE_IN_PROGRESS);
	DBGPRINT(RT_DEBUG_ERROR,"unregister usbnet usb-%s-%s\n",
		dev->bus->bus_name, dev->devpath);
	if (!pAdapter)
		return;
	
	tasklet_kill(&pAdapter->rx_bh);
	// for debug, wait to show some messages to /proc system
	udelay(1);
	//After Add Thread implementation, Upon exec there, pAdapter->net seems becomes NULL, 
	//need to check why???
	//assert(pAdapter->net != NULL)
	if(pAdapter->net != NULL)
	{
		printk("unregister_netdev( )\n");
		unregister_netdev (pAdapter->net);
	}
	udelay(1);
	flush_scheduled_work ();
	udelay(1);

	free_netdev(pAdapter->net);
	usb_put_dev(dev);
	udelay(1);
	DBGPRINT(RT_DEBUG_ERROR,"<=== RTUSB disconnect successfully\n");

}

#endif


 int __init usb_rtusb_init(void)
{
	DBGPRINT(RT_DEBUG_ERROR,"enter rtusb init( )\n");

	return usb_register(&rtusb_driver);
}
 void __exit usb_rtusb_exit(void)
{
	udelay(1);
	udelay(1);
	usb_deregister(&rtusb_driver);
	printk("<===usb_rtusb_exit\n");
}

/**************************************************************/
MODULE_DESCRIPTION("Ralink RT2570 usb 802.11g WLAN driver " DRV_VERSION " " DRV_RELDATE);
MODULE_AUTHOR("http://rt2x00.sourceforge.net");
MODULE_DEVICE_TABLE(usb, rtusb_usb_id);
MODULE_LICENSE("GPL");

module_init(usb_rtusb_init);	// initialization function
module_exit(usb_rtusb_exit);	// exit function
/**************************************************************/
