From c55519ff75224222f4668c92ae3733059269f575 Mon Sep 17 00:00:00 2001
From: Greg Kroah-Hartman <gregkh@suse.de>
Date: Wed, 17 Dec 2008 17:04:23 -0800
Subject: Staging: add rt2870 wireless driver

This is the Ralink RT2870 driver from the company that does horrible
things like reading a config file from /etc.  However, the driver that
is currently under development from the wireless development community
is not working at all yet, so distros and users are using this version
instead (quite common hardware on a lot of netbook machines).

So here is this driver, for now, until the wireless developers get a
"clean" version into the main tree, or until this version is cleaned up
sufficiently to move out of the staging tree.

Ported to the Linux build system and cleaned up a bit already by me.

Cc: Linux wireless <linux-wireless@vger.kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 drivers/staging/Kconfig                        |    2 +
 drivers/staging/Makefile                       |    1 +
 drivers/staging/rt2870/2870_main_dev.c         | 1612 +++++
 drivers/staging/rt2870/Kconfig                 |    6 +
 drivers/staging/rt2870/Makefile                |   47 +
 drivers/staging/rt2870/TODO                    |   10 +
 drivers/staging/rt2870/aironet.h               |  210 +
 drivers/staging/rt2870/ap.h                    |  562 ++
 drivers/staging/rt2870/chlist.h                | 1296 ++++
 drivers/staging/rt2870/common/2870_rtmp_init.c | 1778 +++++
 drivers/staging/rt2870/common/action.c         | 1046 +++
 drivers/staging/rt2870/common/action.h         |   68 +
 drivers/staging/rt2870/common/ba_action.c      | 1798 +++++
 drivers/staging/rt2870/common/cmm_data.c       | 2734 ++++++++
 drivers/staging/rt2870/common/cmm_data_2870.c  |  963 +++
 drivers/staging/rt2870/common/cmm_info.c       | 3712 ++++++++++
 drivers/staging/rt2870/common/cmm_sanity.c     | 1663 +++++
 drivers/staging/rt2870/common/cmm_sync.c       |  711 ++
 drivers/staging/rt2870/common/cmm_wpa.c        | 1654 +++++
 drivers/staging/rt2870/common/dfs.c            |  453 ++
 drivers/staging/rt2870/common/eeprom.c         |  254 +
 drivers/staging/rt2870/common/firmware.h       |  558 ++
 drivers/staging/rt2870/common/md5.c            | 1427 ++++
 drivers/staging/rt2870/common/mlme.c           | 8609 ++++++++++++++++++++++++
 drivers/staging/rt2870/common/netif_block.c    |  144 +
 drivers/staging/rt2870/common/rtmp_init.c      | 4132 ++++++++++++
 drivers/staging/rt2870/common/rtmp_tkip.c      | 1613 +++++
 drivers/staging/rt2870/common/rtmp_wep.c       |  508 ++
 drivers/staging/rt2870/common/rtusb_bulk.c     | 1981 ++++++
 drivers/staging/rt2870/common/rtusb_data.c     |  229 +
 drivers/staging/rt2870/common/rtusb_io.c       | 2006 ++++++
 drivers/staging/rt2870/common/spectrum.c       | 1876 ++++++
 drivers/staging/rt2870/dfs.h                   |  100 +
 drivers/staging/rt2870/leap.h                  |  215 +
 drivers/staging/rt2870/link_list.h             |  134 +
 drivers/staging/rt2870/md4.h                   |   42 +
 drivers/staging/rt2870/md5.h                   |  107 +
 drivers/staging/rt2870/mlme.h                  | 1471 ++++
 drivers/staging/rt2870/netif_block.h           |   58 +
 drivers/staging/rt2870/oid.h                   | 1091 +++
 drivers/staging/rt2870/rt2870.h                |  761 +++
 drivers/staging/rt2870/rt28xx.h                | 2689 ++++++++
 drivers/staging/rt2870/rt_ate.c                | 6452 ++++++++++++++++++
 drivers/staging/rt2870/rt_ate.h                |  315 +
 drivers/staging/rt2870/rt_config.h             |  104 +
 drivers/staging/rt2870/rt_linux.c              | 1095 +++
 drivers/staging/rt2870/rt_linux.h              |  908 +++
 drivers/staging/rt2870/rt_main_dev.c           | 1863 +++++
 drivers/staging/rt2870/rt_profile.c            | 2016 ++++++
 drivers/staging/rt2870/rtmp.h                  | 7586 +++++++++++++++++++++
 drivers/staging/rt2870/rtmp_ckipmic.h          |  113 +
 drivers/staging/rt2870/rtmp_def.h              | 1622 +++++
 drivers/staging/rt2870/rtmp_type.h             |   94 +
 drivers/staging/rt2870/spectrum.h              |  322 +
 drivers/staging/rt2870/spectrum_def.h          |   95 +
 drivers/staging/rt2870/sta/aironet.c           | 1312 ++++
 drivers/staging/rt2870/sta/assoc.c             | 2039 ++++++
 drivers/staging/rt2870/sta/auth.c              |  474 ++
 drivers/staging/rt2870/sta/auth_rsp.c          |  166 +
 drivers/staging/rt2870/sta/connect.c           | 2822 ++++++++
 drivers/staging/rt2870/sta/dls.c               | 2210 ++++++
 drivers/staging/rt2870/sta/rtmp_data.c         | 2619 +++++++
 drivers/staging/rt2870/sta/sanity.c            |  420 ++
 drivers/staging/rt2870/sta/sync.c              | 1753 +++++
 drivers/staging/rt2870/sta/wpa.c               | 2107 ++++++
 drivers/staging/rt2870/sta_ioctl.c             | 7068 +++++++++++++++++++
 drivers/staging/rt2870/sta_ioctl.c.patch       |   18 +
 drivers/staging/rt2870/tmp60                   | 7037 +++++++++++++++++++
 drivers/staging/rt2870/tmp61                   | 7037 +++++++++++++++++++
 drivers/staging/rt2870/wpa.h                   |  357 +
 70 files changed, 110355 insertions(+)
 create mode 100644 drivers/staging/rt2870/2870_main_dev.c
 create mode 100644 drivers/staging/rt2870/Kconfig
 create mode 100644 drivers/staging/rt2870/Makefile
 create mode 100644 drivers/staging/rt2870/TODO
 create mode 100644 drivers/staging/rt2870/aironet.h
 create mode 100644 drivers/staging/rt2870/ap.h
 create mode 100644 drivers/staging/rt2870/chlist.h
 create mode 100644 drivers/staging/rt2870/common/2870_rtmp_init.c
 create mode 100644 drivers/staging/rt2870/common/action.c
 create mode 100644 drivers/staging/rt2870/common/action.h
 create mode 100644 drivers/staging/rt2870/common/ba_action.c
 create mode 100644 drivers/staging/rt2870/common/cmm_data.c
 create mode 100644 drivers/staging/rt2870/common/cmm_data_2870.c
 create mode 100644 drivers/staging/rt2870/common/cmm_info.c
 create mode 100644 drivers/staging/rt2870/common/cmm_sanity.c
 create mode 100644 drivers/staging/rt2870/common/cmm_sync.c
 create mode 100644 drivers/staging/rt2870/common/cmm_wpa.c
 create mode 100644 drivers/staging/rt2870/common/dfs.c
 create mode 100644 drivers/staging/rt2870/common/eeprom.c
 create mode 100644 drivers/staging/rt2870/common/firmware.h
 create mode 100644 drivers/staging/rt2870/common/md5.c
 create mode 100644 drivers/staging/rt2870/common/mlme.c
 create mode 100644 drivers/staging/rt2870/common/netif_block.c
 create mode 100644 drivers/staging/rt2870/common/rtmp_init.c
 create mode 100644 drivers/staging/rt2870/common/rtmp_tkip.c
 create mode 100644 drivers/staging/rt2870/common/rtmp_wep.c
 create mode 100644 drivers/staging/rt2870/common/rtusb_bulk.c
 create mode 100644 drivers/staging/rt2870/common/rtusb_data.c
 create mode 100644 drivers/staging/rt2870/common/rtusb_io.c
 create mode 100644 drivers/staging/rt2870/common/spectrum.c
 create mode 100644 drivers/staging/rt2870/dfs.h
 create mode 100644 drivers/staging/rt2870/leap.h
 create mode 100644 drivers/staging/rt2870/link_list.h
 create mode 100644 drivers/staging/rt2870/md4.h
 create mode 100644 drivers/staging/rt2870/md5.h
 create mode 100644 drivers/staging/rt2870/mlme.h
 create mode 100644 drivers/staging/rt2870/netif_block.h
 create mode 100644 drivers/staging/rt2870/oid.h
 create mode 100644 drivers/staging/rt2870/rt2870.h
 create mode 100644 drivers/staging/rt2870/rt28xx.h
 create mode 100644 drivers/staging/rt2870/rt_ate.c
 create mode 100644 drivers/staging/rt2870/rt_ate.h
 create mode 100644 drivers/staging/rt2870/rt_config.h
 create mode 100644 drivers/staging/rt2870/rt_linux.c
 create mode 100644 drivers/staging/rt2870/rt_linux.h
 create mode 100644 drivers/staging/rt2870/rt_main_dev.c
 create mode 100644 drivers/staging/rt2870/rt_profile.c
 create mode 100644 drivers/staging/rt2870/rtmp.h
 create mode 100644 drivers/staging/rt2870/rtmp_ckipmic.h
 create mode 100644 drivers/staging/rt2870/rtmp_def.h
 create mode 100644 drivers/staging/rt2870/rtmp_type.h
 create mode 100644 drivers/staging/rt2870/spectrum.h
 create mode 100644 drivers/staging/rt2870/spectrum_def.h
 create mode 100644 drivers/staging/rt2870/sta/aironet.c
 create mode 100644 drivers/staging/rt2870/sta/assoc.c
 create mode 100644 drivers/staging/rt2870/sta/auth.c
 create mode 100644 drivers/staging/rt2870/sta/auth_rsp.c
 create mode 100644 drivers/staging/rt2870/sta/connect.c
 create mode 100644 drivers/staging/rt2870/sta/dls.c
 create mode 100644 drivers/staging/rt2870/sta/rtmp_data.c
 create mode 100644 drivers/staging/rt2870/sta/sanity.c
 create mode 100644 drivers/staging/rt2870/sta/sync.c
 create mode 100644 drivers/staging/rt2870/sta/wpa.c
 create mode 100644 drivers/staging/rt2870/sta_ioctl.c
 create mode 100644 drivers/staging/rt2870/sta_ioctl.c.patch
 create mode 100644 drivers/staging/rt2870/tmp60
 create mode 100644 drivers/staging/rt2870/tmp61
 create mode 100644 drivers/staging/rt2870/wpa.h

diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 9845eab9ebf..e2f57e9b694 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -71,6 +71,8 @@ source "drivers/staging/otus/Kconfig"
 
 source "drivers/staging/rt2860/Kconfig"
 
+source "drivers/staging/rt2870/Kconfig"
+
 source "drivers/staging/benet/Kconfig"
 
 source "drivers/staging/comedi/Kconfig"
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 968f333a659..94efc9df5a8 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_POCH)		+= poch/
 obj-$(CONFIG_AGNX)		+= agnx/
 obj-$(CONFIG_OTUS)		+= otus/
 obj-$(CONFIG_RT2860)		+= rt2860/
+obj-$(CONFIG_RT2870)		+= rt2870/
 obj-$(CONFIG_BENET)		+= benet/
 obj-$(CONFIG_COMEDI)		+= comedi/
 obj-$(CONFIG_ASUS_OLED)		+= asus_oled/
diff --git a/drivers/staging/rt2870/2870_main_dev.c b/drivers/staging/rt2870/2870_main_dev.c
new file mode 100644
index 00000000000..91da4e2298a
--- /dev/null
+++ b/drivers/staging/rt2870/2870_main_dev.c
@@ -0,0 +1,1612 @@
+/*
+ *************************************************************************
+ * Ralink Tech Inc.
+ * 5F., No.36, Taiyuan St., Jhubei City,
+ * Hsinchu County 302,
+ * Taiwan, R.O.C.
+ *
+ * (c) Copyright 2002-2007, Ralink Technology, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify  *
+ * it under the terms of the GNU General Public License as published by  *
+ * the Free Software Foundation; either version 2 of the License, or     *
+ * (at your option) any later version.                                   *
+ *                                                                       *
+ * This program is distributed in the hope that it will be useful,       *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ * GNU General Public License for more details.                          *
+ *                                                                       *
+ * You should have received a copy of the GNU General Public License     *
+ * along with this program; if not, write to the                         *
+ * Free Software Foundation, Inc.,                                       *
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ *                                                                       *
+ *************************************************************************
+
+    Module Name:
+    rtmp_main.c
+
+    Abstract:
+    main initialization routines
+
+    Revision History:
+    Who         When            What
+    --------    ----------      ----------------------------------------------
+    Name        Date            Modification logs
+    Jan Lee		01-10-2005	    modified
+	Sample		Jun/01/07		Merge RT2870 and RT2860 drivers.
+*/
+
+#include "rt_config.h"
+
+
+// Following information will be show when you run 'modinfo'
+// *** If you have a solution for the bug in current version of driver, please mail to me.
+// Otherwise post to forum in ralinktech's web site(www.ralinktech.com) and let all users help you. ***
+MODULE_AUTHOR("Paul Lin <paul_lin@ralinktech.com>");
+MODULE_DESCRIPTION("RT2870 Wireless Lan Linux Driver");
+#ifdef CONFIG_STA_SUPPORT
+MODULE_LICENSE("GPL");
+#ifdef MODULE_VERSION
+MODULE_VERSION(STA_DRIVER_VERSION);
+#endif
+#endif // CONFIG_STA_SUPPORT //
+
+#ifdef MULTIPLE_CARD_SUPPORT
+// record whether the card in the card list is used in the card file
+extern UINT8  MC_CardUsed[];
+#endif // MULTIPLE_CARD_SUPPORT //
+
+/* 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. */
+
+extern INT __devinit rt28xx_probe(IN void *_dev_p, IN void *_dev_id_p,
+									IN UINT argc, OUT PRTMP_ADAPTER *ppAd);
+
+
+/* module table */
+struct usb_device_id    rtusb_usb_id[] = RT2870_USB_DEVICES;
+INT const               rtusb_usb_id_len = sizeof(rtusb_usb_id) / sizeof(struct usb_device_id);
+MODULE_DEVICE_TABLE(usb, rtusb_usb_id);
+
+#ifndef PF_NOFREEZE
+#define PF_NOFREEZE  0
+#endif
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+
+/**************************************************************************/
+/**************************************************************************/
+//tested for kernel 2.4 series
+/**************************************************************************/
+/**************************************************************************/
+static void *rtusb_probe(struct usb_device *dev, UINT interface,
+						const struct usb_device_id *id_table);
+static void rtusb_disconnect(struct usb_device *dev, void *ptr);
+
+struct usb_driver rtusb_driver = {
+		name:"rt2870",
+		probe:rtusb_probe,
+		disconnect:rtusb_disconnect,
+		id_table:rtusb_usb_id,
+	};
+
+#else
+
+#ifdef CONFIG_PM
+static int rt2870_suspend(struct usb_interface *intf, pm_message_t state);
+static int rt2870_resume(struct usb_interface *intf);
+#endif // CONFIG_PM //
+
+/**************************************************************************/
+/**************************************************************************/
+//tested for kernel 2.6series
+/**************************************************************************/
+/**************************************************************************/
+static int rtusb_probe (struct usb_interface *intf,
+						const struct usb_device_id *id);
+static void rtusb_disconnect(struct usb_interface *intf);
+
+struct usb_driver rtusb_driver = {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
+	.owner = THIS_MODULE,
+#endif
+	.name="rt2870",
+	.probe=rtusb_probe,
+	.disconnect=rtusb_disconnect,
+	.id_table=rtusb_usb_id,
+
+#ifdef CONFIG_PM
+	suspend:	rt2870_suspend,
+	resume:		rt2870_resume,
+#endif
+	};
+
+#ifdef CONFIG_PM
+
+VOID RT2860RejectPendingPackets(
+	IN	PRTMP_ADAPTER	pAd)
+{
+	// clear PS packets
+	// clear TxSw packets
+}
+
+static int rt2870_suspend(
+	struct usb_interface *intf,
+	pm_message_t state)
+{
+	struct net_device *net_dev;
+	PRTMP_ADAPTER pAd = usb_get_intfdata(intf);
+
+
+	DBGPRINT(RT_DEBUG_TRACE, ("===> rt2870_suspend()\n"));
+	net_dev = pAd->net_dev;
+	netif_device_detach (net_dev);
+
+	pAd->PM_FlgSuspend = 1;
+	if (netif_running(net_dev)) {
+		RTUSBCancelPendingBulkInIRP(pAd);
+		RTUSBCancelPendingBulkOutIRP(pAd);
+	}
+	DBGPRINT(RT_DEBUG_TRACE, ("<=== rt2870_suspend()\n"));
+	return 0;
+}
+
+static int rt2870_resume(
+	struct usb_interface *intf)
+{
+	struct net_device *net_dev;
+	PRTMP_ADAPTER pAd = usb_get_intfdata(intf);
+
+
+	DBGPRINT(RT_DEBUG_TRACE, ("===> rt2870_resume()\n"));
+
+	pAd->PM_FlgSuspend = 0;
+	net_dev = pAd->net_dev;
+	netif_device_attach (net_dev);
+	netif_start_queue(net_dev);
+	netif_carrier_on(net_dev);
+	netif_wake_queue(net_dev);
+
+	DBGPRINT(RT_DEBUG_TRACE, ("<=== rt2870_resume()\n"));
+	return 0;
+}
+#endif // CONFIG_PM //
+#endif // LINUX_VERSION_CODE //
+
+
+// Init driver module
+INT __init rtusb_init(void)
+{
+	printk("rtusb init --->\n");
+	return usb_register(&rtusb_driver);
+}
+
+// Deinit driver module
+VOID __exit rtusb_exit(void)
+{
+	usb_deregister(&rtusb_driver);
+	printk("<--- rtusb exit\n");
+}
+
+module_init(rtusb_init);
+module_exit(rtusb_exit);
+
+
+
+
+/*---------------------------------------------------------------------	*/
+/* function declarations												*/
+/*---------------------------------------------------------------------	*/
+
+/*
+========================================================================
+Routine Description:
+    MLME kernel thread.
+
+Arguments:
+	*Context			the pAd, driver control block pointer
+
+Return Value:
+    0					close the thread
+
+Note:
+========================================================================
+*/
+INT MlmeThread(
+	IN void *Context)
+{
+	PRTMP_ADAPTER	pAd = (PRTMP_ADAPTER)Context;
+	POS_COOKIE	pObj;
+	int status;
+
+	pObj = (POS_COOKIE)pAd->OS_Cookie;
+
+	rtmp_os_thread_init("rt2870MlmeThread", (PVOID)&(pAd->mlmeComplete));
+
+	while (pAd->mlme_kill == 0)
+	{
+		/* lock the device pointers */
+		//down(&(pAd->mlme_semaphore));
+		status = down_interruptible(&(pAd->mlme_semaphore));
+
+		/* lock the device pointers , need to check if required*/
+		//down(&(pAd->usbdev_semaphore));
+
+		if (!pAd->PM_FlgSuspend)
+		MlmeHandler(pAd);
+
+		/* unlock the device pointers */
+		//up(&(pAd->usbdev_semaphore));
+		if (status != 0)
+		{
+			RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS);
+			break;
+		}
+	}
+
+	/* 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().
+	 */
+	DBGPRINT(RT_DEBUG_TRACE,( "<---%s\n",__FUNCTION__));
+
+	pObj->MLMEThr_pid = THREAD_PID_INIT_VALUE;
+
+	complete_and_exit (&pAd->mlmeComplete, 0);
+	return 0;
+
+}
+
+
+/*
+========================================================================
+Routine Description:
+    USB command kernel thread.
+
+Arguments:
+	*Context			the pAd, driver control block pointer
+
+Return Value:
+    0					close the thread
+
+Note:
+========================================================================
+*/
+INT RTUSBCmdThread(
+	IN void * Context)
+{
+	PRTMP_ADAPTER	pAd = (PRTMP_ADAPTER)Context;
+	POS_COOKIE		pObj;
+	int status;
+
+	pObj = (POS_COOKIE)pAd->OS_Cookie;
+
+	rtmp_os_thread_init("rt2870CmdThread", (PVOID)&(pAd->CmdQComplete));
+
+	NdisAcquireSpinLock(&pAd->CmdQLock);
+	pAd->CmdQ.CmdQState = RT2870_THREAD_RUNNING;
+	NdisReleaseSpinLock(&pAd->CmdQLock);
+
+	while (pAd->CmdQ.CmdQState == RT2870_THREAD_RUNNING)
+	{
+		/* lock the device pointers */
+		//down(&(pAd->RTUSBCmd_semaphore));
+		status = down_interruptible(&(pAd->RTUSBCmd_semaphore));
+
+		if (pAd->CmdQ.CmdQState == RT2870_THREAD_STOPED)
+			break;
+
+		if (status != 0)
+		{
+			RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS);
+			break;
+		}
+		/* lock the device pointers , need to check if required*/
+		//down(&(pAd->usbdev_semaphore));
+
+		if (!pAd->PM_FlgSuspend)
+		CMDHandler(pAd);
+
+		/* unlock the device pointers */
+		//up(&(pAd->usbdev_semaphore));
+	}
+
+	if (!pAd->PM_FlgSuspend)
+	{	// Clear the CmdQElements.
+		CmdQElmt	*pCmdQElmt = NULL;
+
+		NdisAcquireSpinLock(&pAd->CmdQLock);
+		pAd->CmdQ.CmdQState = RT2870_THREAD_STOPED;
+		while(pAd->CmdQ.size)
+		{
+			RTUSBDequeueCmd(&pAd->CmdQ, &pCmdQElmt);
+			if (pCmdQElmt)
+			{
+				if (pCmdQElmt->CmdFromNdis == TRUE)
+				{
+					if (pCmdQElmt->buffer != NULL)
+						NdisFreeMemory(pCmdQElmt->buffer, pCmdQElmt->bufferlength, 0);
+
+					NdisFreeMemory(pCmdQElmt, sizeof(CmdQElmt), 0);
+				}
+				else
+				{
+					if ((pCmdQElmt->buffer != NULL) && (pCmdQElmt->bufferlength != 0))
+						NdisFreeMemory(pCmdQElmt->buffer, pCmdQElmt->bufferlength, 0);
+		            {
+						NdisFreeMemory(pCmdQElmt, sizeof(CmdQElmt), 0);
+					}
+				}
+			}
+		}
+
+		NdisReleaseSpinLock(&pAd->CmdQLock);
+	}
+	/* 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().
+	 */
+	DBGPRINT(RT_DEBUG_TRACE,( "<---RTUSBCmdThread\n"));
+
+	pObj->RTUSBCmdThr_pid = THREAD_PID_INIT_VALUE;
+
+	complete_and_exit (&pAd->CmdQComplete, 0);
+	return 0;
+
+}
+
+
+static void RT2870_TimerQ_Handle(RTMP_ADAPTER *pAd)
+{
+	int status;
+	RALINK_TIMER_STRUCT	*pTimer;
+	RT2870_TIMER_ENTRY	*pEntry;
+	unsigned long	irqFlag;
+
+	while(!pAd->TimerFunc_kill)
+	{
+//		printk("waiting for event!\n");
+		pTimer = NULL;
+
+		status = down_interruptible(&(pAd->RTUSBTimer_semaphore));
+
+		if (pAd->TimerQ.status == RT2870_THREAD_STOPED)
+			break;
+
+		// event happened.
+		while(pAd->TimerQ.pQHead)
+		{
+			RTMP_IRQ_LOCK(&pAd->TimerQLock, irqFlag);
+			pEntry = pAd->TimerQ.pQHead;
+			if (pEntry)
+			{
+				pTimer = pEntry->pRaTimer;
+
+				// update pQHead
+				pAd->TimerQ.pQHead = pEntry->pNext;
+				if (pEntry == pAd->TimerQ.pQTail)
+					pAd->TimerQ.pQTail = NULL;
+
+				// return this queue entry to timerQFreeList.
+				pEntry->pNext = pAd->TimerQ.pQPollFreeList;
+				pAd->TimerQ.pQPollFreeList = pEntry;
+			}
+			RTMP_IRQ_UNLOCK(&pAd->TimerQLock, irqFlag);
+
+			if (pTimer)
+			{
+				if (pTimer->handle != NULL)
+				if (!pAd->PM_FlgSuspend)
+					pTimer->handle(NULL, (PVOID) pTimer->cookie, NULL, pTimer);
+				if ((pTimer->Repeat) && (pTimer->State == FALSE))
+					RTMP_OS_Add_Timer(&pTimer->TimerObj, pTimer->TimerValue);
+			}
+		}
+
+		if (status != 0)
+		{
+			pAd->TimerQ.status = RT2870_THREAD_STOPED;
+			RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS);
+			break;
+		}
+	}
+}
+
+
+INT TimerQThread(
+	IN OUT PVOID Context)
+{
+	PRTMP_ADAPTER	pAd;
+	POS_COOKIE	pObj;
+
+	pAd = (PRTMP_ADAPTER)Context;
+	pObj = (POS_COOKIE) pAd->OS_Cookie;
+
+	rtmp_os_thread_init("rt2870TimerQHandle", (PVOID)&(pAd->TimerQComplete));
+
+	RT2870_TimerQ_Handle(pAd);
+
+	/* 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().
+	 */
+	DBGPRINT(RT_DEBUG_TRACE,( "<---%s\n",__FUNCTION__));
+
+	pObj->TimerQThr_pid = THREAD_PID_INIT_VALUE;
+
+	complete_and_exit(&pAd->TimerQComplete, 0);
+	return 0;
+
+}
+
+
+RT2870_TIMER_ENTRY *RT2870_TimerQ_Insert(
+	IN RTMP_ADAPTER *pAd,
+	IN RALINK_TIMER_STRUCT *pTimer)
+{
+	RT2870_TIMER_ENTRY *pQNode = NULL, *pQTail;
+	unsigned long irqFlags;
+
+
+	RTMP_IRQ_LOCK(&pAd->TimerQLock, irqFlags);
+	if (pAd->TimerQ.status & RT2870_THREAD_CAN_DO_INSERT)
+	{
+		if(pAd->TimerQ.pQPollFreeList)
+		{
+			pQNode = pAd->TimerQ.pQPollFreeList;
+			pAd->TimerQ.pQPollFreeList = pQNode->pNext;
+
+			pQNode->pRaTimer = pTimer;
+			pQNode->pNext = NULL;
+
+			pQTail = pAd->TimerQ.pQTail;
+			if (pAd->TimerQ.pQTail != NULL)
+				pQTail->pNext = pQNode;
+			pAd->TimerQ.pQTail = pQNode;
+			if (pAd->TimerQ.pQHead == NULL)
+				pAd->TimerQ.pQHead = pQNode;
+		}
+		RTMP_IRQ_UNLOCK(&pAd->TimerQLock, irqFlags);
+
+		if (pQNode)
+			up(&pAd->RTUSBTimer_semaphore);
+			//wake_up(&timerWaitQ);
+	}
+	else
+	{
+		RTMP_IRQ_UNLOCK(&pAd->TimerQLock, irqFlags);
+	}
+	return pQNode;
+}
+
+
+BOOLEAN RT2870_TimerQ_Remove(
+	IN RTMP_ADAPTER *pAd,
+	IN RALINK_TIMER_STRUCT *pTimer)
+{
+	RT2870_TIMER_ENTRY *pNode, *pPrev = NULL;
+	unsigned long irqFlags;
+
+	RTMP_IRQ_LOCK(&pAd->TimerQLock, irqFlags);
+	if (pAd->TimerQ.status >= RT2870_THREAD_INITED)
+	{
+		pNode = pAd->TimerQ.pQHead;
+		while (pNode)
+		{
+			if (pNode->pRaTimer == pTimer)
+				break;
+			pPrev = pNode;
+			pNode = pNode->pNext;
+		}
+
+		// Now move it to freeList queue.
+		if (pNode)
+		{
+			if (pNode == pAd->TimerQ.pQHead)
+				pAd->TimerQ.pQHead = pNode->pNext;
+			if (pNode == pAd->TimerQ.pQTail)
+				pAd->TimerQ.pQTail = pPrev;
+			if (pPrev != NULL)
+				pPrev->pNext = pNode->pNext;
+
+			// return this queue entry to timerQFreeList.
+			pNode->pNext = pAd->TimerQ.pQPollFreeList;
+			pAd->TimerQ.pQPollFreeList = pNode;
+		}
+	}
+	RTMP_IRQ_UNLOCK(&pAd->TimerQLock, irqFlags);
+
+	return TRUE;
+}
+
+
+void RT2870_TimerQ_Exit(RTMP_ADAPTER *pAd)
+{
+	RT2870_TIMER_ENTRY *pTimerQ;
+	unsigned long irqFlags;
+
+	RTMP_IRQ_LOCK(&pAd->TimerQLock, irqFlags);
+	while (pAd->TimerQ.pQHead)
+	{
+		pTimerQ = pAd->TimerQ.pQHead;
+		pAd->TimerQ.pQHead = pTimerQ->pNext;
+		// remove the timeQ
+	}
+	pAd->TimerQ.pQPollFreeList = NULL;
+	os_free_mem(pAd, pAd->TimerQ.pTimerQPoll);
+	pAd->TimerQ.pQTail = NULL;
+	pAd->TimerQ.pQHead = NULL;
+	pAd->TimerQ.status = RT2870_THREAD_STOPED;
+	RTMP_IRQ_UNLOCK(&pAd->TimerQLock, irqFlags);
+
+}
+
+
+void RT2870_TimerQ_Init(RTMP_ADAPTER *pAd)
+{
+	int 	i;
+	RT2870_TIMER_ENTRY *pQNode, *pEntry;
+	unsigned long irqFlags;
+
+	NdisAllocateSpinLock(&pAd->TimerQLock);
+
+	RTMP_IRQ_LOCK(&pAd->TimerQLock, irqFlags);
+	NdisZeroMemory(&pAd->TimerQ, sizeof(pAd->TimerQ));
+	//InterlockedExchange(&pAd->TimerQ.count, 0);
+
+	/* Initialise the wait q head */
+	//init_waitqueue_head(&timerWaitQ);
+
+	os_alloc_mem(pAd, &pAd->TimerQ.pTimerQPoll, sizeof(RT2870_TIMER_ENTRY) * TIMER_QUEUE_SIZE_MAX);
+	if (pAd->TimerQ.pTimerQPoll)
+	{
+		pEntry = NULL;
+		pQNode = (RT2870_TIMER_ENTRY *)pAd->TimerQ.pTimerQPoll;
+		for (i = 0 ;i <TIMER_QUEUE_SIZE_MAX; i++)
+		{
+			pQNode->pNext = pEntry;
+			pEntry = pQNode;
+			pQNode++;
+		}
+		pAd->TimerQ.pQPollFreeList = pEntry;
+		pAd->TimerQ.pQHead = NULL;
+		pAd->TimerQ.pQTail = NULL;
+		pAd->TimerQ.status = RT2870_THREAD_INITED;
+	}
+	RTMP_IRQ_UNLOCK(&pAd->TimerQLock, irqFlags);
+}
+
+
+VOID RT2870_WatchDog(IN RTMP_ADAPTER *pAd)
+{
+	PHT_TX_CONTEXT		pHTTXContext;
+	int 					idx;
+	ULONG				irqFlags;
+	PURB		   		pUrb;
+	BOOLEAN				needDumpSeq = FALSE;
+	UINT32          	MACValue;
+
+
+	idx = 0;
+	RTMP_IO_READ32(pAd, TXRXQ_PCNT, &MACValue);
+	if ((MACValue & 0xff) !=0 )
+	{
+		DBGPRINT(RT_DEBUG_TRACE, ("TX QUEUE 0 Not EMPTY(Value=0x%0x). !!!!!!!!!!!!!!!\n", MACValue));
+		RTMP_IO_WRITE32(pAd, PBF_CFG, 0xf40012);
+		while((MACValue &0xff) != 0 && (idx++ < 10))
+		{
+		        RTMP_IO_READ32(pAd, TXRXQ_PCNT, &MACValue);
+		        NdisMSleep(1);
+		}
+		RTMP_IO_WRITE32(pAd, PBF_CFG, 0xf40006);
+	}
+
+	idx = 0;
+	if ((MACValue & 0xff00) !=0 )
+	{
+		DBGPRINT(RT_DEBUG_TRACE, ("TX QUEUE 1 Not EMPTY(Value=0x%0x). !!!!!!!!!!!!!!!\n", MACValue));
+		RTMP_IO_WRITE32(pAd, PBF_CFG, 0xf4000a);
+		while((MACValue &0xff00) != 0 && (idx++ < 10))
+		{
+			RTMP_IO_READ32(pAd, TXRXQ_PCNT, &MACValue);
+			NdisMSleep(1);
+		}
+		RTMP_IO_WRITE32(pAd, PBF_CFG, 0xf40006);
+	}
+
+
+	if (pAd->watchDogRxOverFlowCnt >= 2)
+	{
+		DBGPRINT(RT_DEBUG_TRACE, ("Maybe the Rx Bulk-In hanged! Cancel the pending Rx bulks request!\n"));
+		if ((!RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS |
+									fRTMP_ADAPTER_BULKIN_RESET |
+									fRTMP_ADAPTER_HALT_IN_PROGRESS |
+									fRTMP_ADAPTER_NIC_NOT_EXIST))))
+		{
+			DBGPRINT(RT_DEBUG_TRACE, ("Call CMDTHREAD_RESET_BULK_IN to cancel the pending Rx Bulk!\n"));
+			RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKIN_RESET);
+			RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_IN, NULL, 0);
+			needDumpSeq = TRUE;
+		}
+		pAd->watchDogRxOverFlowCnt = 0;
+	}
+
+
+	for (idx = 0; idx < NUM_OF_TX_RING; idx++)
+	{
+		pUrb = NULL;
+
+		RTMP_IRQ_LOCK(&pAd->BulkOutLock[idx], irqFlags);
+		if ((pAd->BulkOutPending[idx] == TRUE) && pAd->watchDogTxPendingCnt)
+		{
+			pAd->watchDogTxPendingCnt[idx]++;
+
+			if ((pAd->watchDogTxPendingCnt[idx] > 2) &&
+				 (!RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST | fRTMP_ADAPTER_BULKOUT_RESET)))
+				)
+			{
+				// FIXME: Following code just support single bulk out. If you wanna support multiple bulk out. Modify it!
+				pHTTXContext = (PHT_TX_CONTEXT)(&pAd->TxContext[idx]);
+				if (pHTTXContext->IRPPending)
+				{	// Check TxContext.
+					pUrb = pHTTXContext->pUrb;
+				}
+				else if (idx == MGMTPIPEIDX)
+				{
+					PTX_CONTEXT pMLMEContext, pNULLContext, pPsPollContext;
+
+					//Check MgmtContext.
+					pMLMEContext = (PTX_CONTEXT)(pAd->MgmtRing.Cell[pAd->MgmtRing.TxDmaIdx].AllocVa);
+					pPsPollContext = (PTX_CONTEXT)(&pAd->PsPollContext);
+					pNULLContext = (PTX_CONTEXT)(&pAd->NullContext);
+
+					if (pMLMEContext->IRPPending)
+					{
+						ASSERT(pMLMEContext->IRPPending);
+						pUrb = pMLMEContext->pUrb;
+					}
+					else if (pNULLContext->IRPPending)
+					{
+						ASSERT(pNULLContext->IRPPending);
+						pUrb = pNULLContext->pUrb;
+					}
+					else if (pPsPollContext->IRPPending)
+					{
+						ASSERT(pPsPollContext->IRPPending);
+						pUrb = pPsPollContext->pUrb;
+					}
+				}
+
+				RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[idx], irqFlags);
+
+				DBGPRINT(RT_DEBUG_TRACE, ("Maybe the Tx Bulk-Out hanged! Cancel the pending Tx bulks request of idx(%d)!\n", idx));
+				if (pUrb)
+				{
+					DBGPRINT(RT_DEBUG_TRACE, ("Unlink the pending URB!\n"));
+					// unlink it now
+					RTUSB_UNLINK_URB(pUrb);
+					// Sleep 200 microseconds to give cancellation time to work
+					RTMPusecDelay(200);
+					needDumpSeq = TRUE;
+				}
+				else
+				{
+					DBGPRINT(RT_DEBUG_ERROR, ("Unkonw bulkOut URB maybe hanged!!!!!!!!!!!!\n"));
+				}
+			}
+			else
+			{
+				RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[idx], irqFlags);
+			}
+		}
+		else
+		{
+			RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[idx], irqFlags);
+		}
+	}
+
+#ifdef DOT11_N_SUPPORT
+	// For Sigma debug, dump the ba_reordering sequence.
+	if((needDumpSeq == TRUE) && (pAd->CommonCfg.bDisableReordering == 0))
+	{
+		USHORT				Idx;
+		PBA_REC_ENTRY		pBAEntry = NULL;
+		UCHAR				count = 0;
+		struct reordering_mpdu *mpdu_blk;
+
+		Idx = pAd->MacTab.Content[BSSID_WCID].BARecWcidArray[0];
+
+		pBAEntry = &pAd->BATable.BARecEntry[Idx];
+		if((pBAEntry->list.qlen > 0) && (pBAEntry->list.next != NULL))
+		{
+			DBGPRINT(RT_DEBUG_TRACE, ("NICUpdateRawCounters():The Queueing pkt in reordering buffer:\n"));
+			NdisAcquireSpinLock(&pBAEntry->RxReRingLock);
+			mpdu_blk = pBAEntry->list.next;
+			while (mpdu_blk)
+			{
+				DBGPRINT(RT_DEBUG_TRACE, ("\t%d:Seq-%d, bAMSDU-%d!\n", count, mpdu_blk->Sequence, mpdu_blk->bAMSDU));
+				mpdu_blk = mpdu_blk->next;
+				count++;
+			}
+
+			DBGPRINT(RT_DEBUG_TRACE, ("\npBAEntry->LastIndSeq=%d!\n", pBAEntry->LastIndSeq));
+			NdisReleaseSpinLock(&pBAEntry->RxReRingLock);
+		}
+	}
+#endif // DOT11_N_SUPPORT //
+}
+
+/*
+========================================================================
+Routine Description:
+    Release allocated resources.
+
+Arguments:
+    *dev				Point to the PCI or USB device
+	pAd					driver control block pointer
+
+Return Value:
+    None
+
+Note:
+========================================================================
+*/
+static void _rtusb_disconnect(struct usb_device *dev, PRTMP_ADAPTER pAd)
+{
+	struct net_device	*net_dev = NULL;
+
+
+	DBGPRINT(RT_DEBUG_ERROR, ("rtusb_disconnect: unregister usbnet usb-%s-%s\n",
+				dev->bus->bus_name, dev->devpath));
+	if (!pAd)
+	{
+#ifdef MULTIPLE_CARD_SUPPORT
+		if ((pAd->MC_RowID >= 0) && (pAd->MC_RowID <= MAX_NUM_OF_MULTIPLE_CARD))
+			MC_CardUsed[pAd->MC_RowID] = 0; // not clear MAC address
+#endif // MULTIPLE_CARD_SUPPORT //
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)	/* kernel 2.4 series */
+		while(MOD_IN_USE > 0)
+		{
+			MOD_DEC_USE_COUNT;
+		}
+#else
+		usb_put_dev(dev);
+#endif // LINUX_VERSION_CODE //
+
+		printk("rtusb_disconnect: pAd == NULL!\n");
+		return;
+	}
+	RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST);
+
+
+
+	// for debug, wait to show some messages to /proc system
+	udelay(1);
+
+
+
+
+	net_dev = pAd->net_dev;
+	if (pAd->net_dev != NULL)
+	{
+		printk("rtusb_disconnect: unregister_netdev(), dev->name=%s!\n", net_dev->name);
+		unregister_netdev (pAd->net_dev);
+	}
+	udelay(1);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)	/* kernel 2.4 series */
+#else
+	flush_scheduled_work();
+#endif // LINUX_VERSION_CODE //
+	udelay(1);
+
+	// free net_device memory
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)	/* kernel 2.4 series */
+	kfree(net_dev);
+#else
+	free_netdev(net_dev);
+#endif // LINUX_VERSION_CODE //
+
+	// free adapter memory
+	RTMPFreeAdapter(pAd);
+
+	// release a use of the usb device structure
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)	/* kernel 2.4 series */
+	while(MOD_IN_USE > 0)
+	{
+		MOD_DEC_USE_COUNT;
+	}
+#else
+	usb_put_dev(dev);
+#endif // LINUX_VERSION_CODE //
+	udelay(1);
+
+	DBGPRINT(RT_DEBUG_ERROR, (" RTUSB disconnect successfully\n"));
+}
+
+
+/*
+========================================================================
+Routine Description:
+    Probe RT28XX chipset.
+
+Arguments:
+    *dev				Point to the PCI or USB device
+	interface
+	*id_table			Point to the PCI or USB device ID
+
+Return Value:
+    None
+
+Note:
+========================================================================
+*/
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)	/* kernel 2.4 series */
+static void *rtusb_probe(struct usb_device *dev, UINT interface,
+						const struct usb_device_id *id)
+{
+	PRTMP_ADAPTER pAd;
+	rt28xx_probe((void *)dev, (void *)id, interface, &pAd);
+	return (void *)pAd;
+}
+
+//Disconnect function is called within exit routine
+static void rtusb_disconnect(struct usb_device *dev, void *ptr)
+{
+	_rtusb_disconnect(dev, ((PRTMP_ADAPTER)ptr));
+}
+
+#else	/* kernel 2.6 series */
+static int rtusb_probe (struct usb_interface *intf,
+						const struct usb_device_id *id)
+{
+	PRTMP_ADAPTER pAd;
+	return (int)rt28xx_probe((void *)intf, (void *)id, 0, &pAd);
+}
+
+
+static void rtusb_disconnect(struct usb_interface *intf)
+{
+	struct usb_device   *dev = interface_to_usbdev(intf);
+	PRTMP_ADAPTER       pAd;
+
+
+	pAd = usb_get_intfdata(intf);
+	usb_set_intfdata(intf, NULL);
+
+	_rtusb_disconnect(dev, pAd);
+}
+#endif // LINUX_VERSION_CODE //
+
+
+/*
+========================================================================
+Routine Description:
+    Close kernel threads.
+
+Arguments:
+	*pAd				the raxx interface data pointer
+
+Return Value:
+    NONE
+
+Note:
+========================================================================
+*/
+VOID RT28xxThreadTerminate(
+	IN RTMP_ADAPTER *pAd)
+{
+	POS_COOKIE	pObj = (POS_COOKIE) pAd->OS_Cookie;
+	INT			ret;
+
+
+	// Sleep 50 milliseconds so pending io might finish normally
+	RTMPusecDelay(50000);
+
+	// We want to wait until all pending receives and sends to the
+	// device object. We cancel any
+	// irps. Wait until sends and receives have stopped.
+	RTUSBCancelPendingIRPs(pAd);
+
+	// Terminate Threads
+	CHECK_PID_LEGALITY(pObj->TimerQThr_pid)
+	{
+		POS_COOKIE pObj = (POS_COOKIE)pAd->OS_Cookie;
+
+		printk("Terminate the TimerQThr_pid=%d!\n", GET_PID_NUMBER(pObj->TimerQThr_pid));
+		mb();
+		pAd->TimerFunc_kill = 1;
+		mb();
+		ret = KILL_THREAD_PID(pObj->TimerQThr_pid, SIGTERM, 1);
+		if (ret)
+		{
+			printk(KERN_WARNING "%s: unable to stop TimerQThread, pid=%d, ret=%d!\n",
+					pAd->net_dev->name, GET_PID_NUMBER(pObj->TimerQThr_pid), ret);
+		}
+		else
+		{
+			wait_for_completion(&pAd->TimerQComplete);
+			pObj->TimerQThr_pid = THREAD_PID_INIT_VALUE;
+		}
+	}
+
+	CHECK_PID_LEGALITY(pObj->MLMEThr_pid)
+	{
+		printk("Terminate the MLMEThr_pid=%d!\n", GET_PID_NUMBER(pObj->MLMEThr_pid));
+		mb();
+		pAd->mlme_kill = 1;
+		//RT28XX_MLME_HANDLER(pAd);
+		mb();
+		ret = KILL_THREAD_PID(pObj->MLMEThr_pid, SIGTERM, 1);
+		if (ret)
+		{
+			printk (KERN_WARNING "%s: unable to Mlme thread, pid=%d, ret=%d!\n",
+					pAd->net_dev->name, GET_PID_NUMBER(pObj->MLMEThr_pid), ret);
+		}
+		else
+		{
+			//wait_for_completion (&pAd->notify);
+			wait_for_completion (&pAd->mlmeComplete);
+			pObj->MLMEThr_pid = THREAD_PID_INIT_VALUE;
+		}
+	}
+
+	CHECK_PID_LEGALITY(pObj->RTUSBCmdThr_pid)
+	{
+		printk("Terminate the RTUSBCmdThr_pid=%d!\n", GET_PID_NUMBER(pObj->RTUSBCmdThr_pid));
+		mb();
+		NdisAcquireSpinLock(&pAd->CmdQLock);
+		pAd->CmdQ.CmdQState = RT2870_THREAD_STOPED;
+		NdisReleaseSpinLock(&pAd->CmdQLock);
+		mb();
+		//RTUSBCMDUp(pAd);
+		ret = KILL_THREAD_PID(pObj->RTUSBCmdThr_pid, SIGTERM, 1);
+		if (ret)
+		{
+			printk(KERN_WARNING "%s: unable to RTUSBCmd thread, pid=%d, ret=%d!\n",
+					pAd->net_dev->name, GET_PID_NUMBER(pObj->RTUSBCmdThr_pid), ret);
+		}
+		else
+		{
+			//wait_for_completion (&pAd->notify);
+			wait_for_completion (&pAd->CmdQComplete);
+			pObj->RTUSBCmdThr_pid = THREAD_PID_INIT_VALUE;
+	}
+	}
+
+
+	// Kill tasklets
+	pAd->mlme_kill = 0;
+	pAd->CmdQ.CmdQState = RT2870_THREAD_UNKNOWN;
+	pAd->TimerFunc_kill = 0;
+}
+
+
+void kill_thread_task(IN PRTMP_ADAPTER pAd)
+{
+	POS_COOKIE pObj;
+
+	pObj = (POS_COOKIE) pAd->OS_Cookie;
+
+	tasklet_kill(&pObj->rx_done_task);
+	tasklet_kill(&pObj->mgmt_dma_done_task);
+	tasklet_kill(&pObj->ac0_dma_done_task);
+	tasklet_kill(&pObj->ac1_dma_done_task);
+	tasklet_kill(&pObj->ac2_dma_done_task);
+	tasklet_kill(&pObj->ac3_dma_done_task);
+	tasklet_kill(&pObj->hcca_dma_done_task);
+	tasklet_kill(&pObj->tbtt_task);
+
+}
+
+
+/*
+========================================================================
+Routine Description:
+    Check the chipset vendor/product ID.
+
+Arguments:
+    _dev_p				Point to the PCI or USB device
+
+Return Value:
+    TRUE				Check ok
+	FALSE				Check fail
+
+Note:
+========================================================================
+*/
+BOOLEAN RT28XXChipsetCheck(
+	IN void *_dev_p)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)	/* kernel 2.4 series */
+	struct usb_device *dev_p = (struct usb_device *)_dev_p;
+#else
+	struct usb_interface *intf = (struct usb_interface *)_dev_p;
+	struct usb_device *dev_p = interface_to_usbdev(intf);
+#endif // LINUX_VERSION_CODE //
+	UINT32 i;
+
+
+	for(i=0; i<rtusb_usb_id_len; i++)
+	{
+		if (dev_p->descriptor.idVendor == rtusb_usb_id[i].idVendor &&
+			dev_p->descriptor.idProduct == rtusb_usb_id[i].idProduct)
+		{
+			printk("rt2870: idVendor = 0x%x, idProduct = 0x%x\n",
+					dev_p->descriptor.idVendor, dev_p->descriptor.idProduct);
+			break;
+		}
+	}
+
+	if (i == rtusb_usb_id_len)
+	{
+		printk("rt2870: Error! Device Descriptor not matching!\n");
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+
+/*
+========================================================================
+Routine Description:
+    Init net device structure.
+
+Arguments:
+    _dev_p				Point to the PCI or USB device
+    *net_dev			Point to the net device
+	*pAd				the raxx interface data pointer
+
+Return Value:
+    TRUE				Init ok
+	FALSE				Init fail
+
+Note:
+========================================================================
+*/
+BOOLEAN RT28XXNetDevInit(
+	IN void 				*_dev_p,
+	IN struct  net_device	*net_dev,
+	IN RTMP_ADAPTER 		*pAd)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)	/* kernel 2.4 series */
+	struct usb_device *dev_p = (struct usb_device *)_dev_p;
+#else
+	struct usb_interface *intf = (struct usb_interface *)_dev_p;
+	struct usb_device *dev_p = interface_to_usbdev(intf);
+#endif // LINUX_VERSION_CODE //
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)	/* kernel 2.4 series */
+	pAd->config = dev_p->config;
+#else
+	pAd->config = &dev_p->config->desc;
+#endif // LINUX_VERSION_CODE //
+	return TRUE;
+}
+
+
+/*
+========================================================================
+Routine Description:
+    Init net device structure.
+
+Arguments:
+    _dev_p				Point to the PCI or USB device
+	*pAd				the raxx interface data pointer
+
+Return Value:
+    TRUE				Config ok
+	FALSE				Config fail
+
+Note:
+========================================================================
+*/
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+BOOLEAN RT28XXProbePostConfig(
+	IN void 				*_dev_p,
+	IN RTMP_ADAPTER 		*pAd,
+	IN INT32				interface)
+{
+	struct usb_device *dev_p = (struct usb_device *)_dev_p;
+	struct usb_interface *intf;
+	struct usb_interface_descriptor *iface_desc;
+	struct usb_endpoint_descriptor *endpoint;
+	ULONG BulkOutIdx;
+	UINT32 i;
+
+
+	/* get the active interface descriptor */
+	intf = &dev_p->actconfig->interface[interface];
+	iface_desc = &intf->altsetting[0];
+
+	/* get # of enpoints */
+	pAd->NumberOfPipes = iface_desc->bNumEndpoints;
+	DBGPRINT(RT_DEBUG_TRACE, ("NumEndpoints=%d\n", iface_desc->bNumEndpoints));
+
+	/* Configure Pipes */
+	endpoint = &iface_desc->endpoint[0];
+	BulkOutIdx = 0;
+
+	for(i=0; i<pAd->NumberOfPipes; i++)
+	{
+		if ((endpoint[i].bmAttributes == USB_ENDPOINT_XFER_BULK) &&
+			((endpoint[i].bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN))
+		{
+			pAd->BulkInEpAddr = endpoint[i].bEndpointAddress;
+			pAd->BulkInMaxPacketSize = endpoint[i].wMaxPacketSize;
+
+			DBGPRINT_RAW(RT_DEBUG_TRACE,
+				("BULK IN MaximumPacketSize = %d\n", pAd->BulkInMaxPacketSize));
+			DBGPRINT_RAW(RT_DEBUG_TRACE,
+				("EP address = 0x%2x  \n", endpoint[i].bEndpointAddress));
+		}
+		else if ((endpoint[i].bmAttributes == USB_ENDPOINT_XFER_BULK) &&
+				((endpoint[i].bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT))
+		{
+			// There are 6 bulk out EP. EP6 highest priority.
+			// EP1-4 is EDCA.  EP5 is HCCA.
+			pAd->BulkOutEpAddr[BulkOutIdx++] = endpoint[i].bEndpointAddress;
+			pAd->BulkOutMaxPacketSize = endpoint[i].wMaxPacketSize;
+
+			DBGPRINT_RAW(RT_DEBUG_TRACE,
+				("BULK OUT MaximumPacketSize = %d\n", pAd->BulkOutMaxPacketSize));
+			DBGPRINT_RAW(RT_DEBUG_TRACE,
+				("EP address = 0x%2x  \n", endpoint[i].bEndpointAddress));
+		}
+	}
+
+	if (!(pAd->BulkInEpAddr && pAd->BulkOutEpAddr[0]))
+	{
+		printk("Could not find both bulk-in and bulk-out endpoints\n");
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+#else
+BOOLEAN RT28XXProbePostConfig(
+	IN void 				*_dev_p,
+	IN RTMP_ADAPTER 		*pAd,
+	IN INT32				interface)
+{
+	struct usb_interface *intf = (struct usb_interface *)_dev_p;
+	struct usb_host_interface *iface_desc;
+	ULONG BulkOutIdx;
+	UINT32 i;
+
+
+	/* get the active interface descriptor */
+	iface_desc = intf->cur_altsetting;
+
+	/* get # of enpoints  */
+	pAd->NumberOfPipes = iface_desc->desc.bNumEndpoints;
+	DBGPRINT(RT_DEBUG_TRACE,
+			("NumEndpoints=%d\n", iface_desc->desc.bNumEndpoints));
+
+	/* Configure Pipes */
+	BulkOutIdx = 0;
+
+	for(i=0; i<pAd->NumberOfPipes; i++)
+	{
+		if ((iface_desc->endpoint[i].desc.bmAttributes ==
+				USB_ENDPOINT_XFER_BULK) &&
+			((iface_desc->endpoint[i].desc.bEndpointAddress &
+				USB_ENDPOINT_DIR_MASK) == USB_DIR_IN))
+		{
+			pAd->BulkInEpAddr = iface_desc->endpoint[i].desc.bEndpointAddress;
+			pAd->BulkInMaxPacketSize = iface_desc->endpoint[i].desc.wMaxPacketSize;
+
+			DBGPRINT_RAW(RT_DEBUG_TRACE,
+				("BULK IN MaximumPacketSize = %d\n", pAd->BulkInMaxPacketSize));
+			DBGPRINT_RAW(RT_DEBUG_TRACE,
+				("EP address = 0x%2x\n", iface_desc->endpoint[i].desc.bEndpointAddress));
+		}
+		else if ((iface_desc->endpoint[i].desc.bmAttributes ==
+					USB_ENDPOINT_XFER_BULK) &&
+				((iface_desc->endpoint[i].desc.bEndpointAddress &
+					USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT))
+		{
+			// there are 6 bulk out EP. EP6 highest priority.
+			// EP1-4 is EDCA.  EP5 is HCCA.
+			pAd->BulkOutEpAddr[BulkOutIdx++] = iface_desc->endpoint[i].desc.bEndpointAddress;
+			pAd->BulkOutMaxPacketSize = iface_desc->endpoint[i].desc.wMaxPacketSize;
+
+			DBGPRINT_RAW(RT_DEBUG_TRACE,
+				("BULK OUT MaximumPacketSize = %d\n", pAd->BulkOutMaxPacketSize));
+			DBGPRINT_RAW(RT_DEBUG_TRACE,
+				("EP address = 0x%2x  \n", iface_desc->endpoint[i].desc.bEndpointAddress));
+		}
+	}
+
+	if (!(pAd->BulkInEpAddr && pAd->BulkOutEpAddr[0]))
+	{
+		printk("%s: Could not find both bulk-in and bulk-out endpoints\n", __FUNCTION__);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+#endif // LINUX_VERSION_CODE //
+
+
+/*
+========================================================================
+Routine Description:
+    Disable DMA.
+
+Arguments:
+	*pAd				the raxx interface data pointer
+
+Return Value:
+	None
+
+Note:
+========================================================================
+*/
+VOID RT28XXDMADisable(
+	IN RTMP_ADAPTER 		*pAd)
+{
+	// no use
+}
+
+
+
+/*
+========================================================================
+Routine Description:
+    Enable DMA.
+
+Arguments:
+	*pAd				the raxx interface data pointer
+
+Return Value:
+	None
+
+Note:
+========================================================================
+*/
+VOID RT28XXDMAEnable(
+	IN RTMP_ADAPTER 		*pAd)
+{
+	WPDMA_GLO_CFG_STRUC	GloCfg;
+	USB_DMA_CFG_STRUC	UsbCfg;
+	int					i = 0;
+
+
+	RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x4);
+	do
+	{
+		RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word);
+		if ((GloCfg.field.TxDMABusy == 0)  && (GloCfg.field.RxDMABusy == 0))
+			break;
+
+		DBGPRINT(RT_DEBUG_TRACE, ("==>  DMABusy\n"));
+		RTMPusecDelay(1000);
+		i++;
+	}while ( i <200);
+
+
+	RTMPusecDelay(50);
+	GloCfg.field.EnTXWriteBackDDONE = 1;
+	GloCfg.field.EnableRxDMA = 1;
+	GloCfg.field.EnableTxDMA = 1;
+	DBGPRINT(RT_DEBUG_TRACE, ("<== WRITE DMA offset 0x208 = 0x%x\n", GloCfg.word));
+	RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, GloCfg.word);
+
+	UsbCfg.word = 0;
+	UsbCfg.field.phyclear = 0;
+	/* usb version is 1.1,do not use bulk in aggregation */
+	if (pAd->BulkInMaxPacketSize == 512)
+			UsbCfg.field.RxBulkAggEn = 1;
+	/* for last packet, PBF might use more than limited, so minus 2 to prevent from error */
+	UsbCfg.field.RxBulkAggLmt = (MAX_RXBULK_SIZE /1024)-3;
+	UsbCfg.field.RxBulkAggTOut = 0x80; /* 2006-10-18 */
+	UsbCfg.field.RxBulkEn = 1;
+	UsbCfg.field.TxBulkEn = 1;
+
+	RTUSBWriteMACRegister(pAd, USB_DMA_CFG, UsbCfg.word);
+
+}
+
+/*
+========================================================================
+Routine Description:
+    Write Beacon buffer to Asic.
+
+Arguments:
+	*pAd				the raxx interface data pointer
+
+Return Value:
+	None
+
+Note:
+========================================================================
+*/
+VOID RT28xx_UpdateBeaconToAsic(
+	IN RTMP_ADAPTER		*pAd,
+	IN INT				apidx,
+	IN ULONG			FrameLen,
+	IN ULONG			UpdatePos)
+{
+	PUCHAR        	pBeaconFrame = NULL;
+	UCHAR  			*ptr;
+	UINT  			i, padding;
+	BEACON_SYNC_STRUCT	*pBeaconSync = pAd->CommonCfg.pBeaconSync;
+	UINT32			longValue;
+	BOOLEAN			bBcnReq = FALSE;
+	UCHAR			bcn_idx = 0;
+
+
+	if (pBeaconFrame == NULL)
+	{
+		DBGPRINT(RT_DEBUG_ERROR,("pBeaconFrame is NULL!\n"));
+		return;
+	}
+
+	if (pBeaconSync == NULL)
+	{
+		DBGPRINT(RT_DEBUG_ERROR,("pBeaconSync is NULL!\n"));
+		return;
+	}
+
+	//if ((pAd->WdsTab.Mode == WDS_BRIDGE_MODE) ||
+	//	((pAd->ApCfg.MBSSID[apidx].MSSIDDev == NULL) || !(pAd->ApCfg.MBSSID[apidx].MSSIDDev->flags & IFF_UP))
+	//	)
+	if (bBcnReq == FALSE)
+	{
+		/* when the ra interface is down, do not send its beacon frame */
+		/* clear all zero */
+		for(i=0; i<TXWI_SIZE; i+=4) {
+			RTMP_IO_WRITE32(pAd, pAd->BeaconOffset[bcn_idx] + i, 0x00);
+		}
+		pBeaconSync->BeaconBitMap &= (~(BEACON_BITMAP_MASK & (1 << bcn_idx)));
+		NdisZeroMemory(pBeaconSync->BeaconTxWI[bcn_idx], TXWI_SIZE);
+	}
+	else
+	{
+		ptr = (PUCHAR)&pAd->BeaconTxWI;
+#ifdef RT_BIG_ENDIAN
+		RTMPWIEndianChange(ptr, TYPE_TXWI);
+#endif
+		if (NdisEqualMemory(pBeaconSync->BeaconTxWI[bcn_idx], &pAd->BeaconTxWI, TXWI_SIZE) == FALSE)
+		{	// If BeaconTxWI changed, we need to rewrite the TxWI for the Beacon frames.
+			pBeaconSync->BeaconBitMap &= (~(BEACON_BITMAP_MASK & (1 << bcn_idx)));
+			NdisMoveMemory(pBeaconSync->BeaconTxWI[bcn_idx], &pAd->BeaconTxWI, TXWI_SIZE);
+		}
+
+		if ((pBeaconSync->BeaconBitMap & (1 << bcn_idx)) != (1 << bcn_idx))
+		{
+			for (i=0; i<TXWI_SIZE; i+=4)  // 16-byte TXWI field
+			{
+				longValue =  *ptr + (*(ptr+1)<<8) + (*(ptr+2)<<16) + (*(ptr+3)<<24);
+				RTMP_IO_WRITE32(pAd, pAd->BeaconOffset[bcn_idx] + i, longValue);
+				ptr += 4;
+			}
+		}
+
+		ptr = pBeaconSync->BeaconBuf[bcn_idx];
+		padding = (FrameLen & 0x01);
+		NdisZeroMemory((PUCHAR)(pBeaconFrame + FrameLen), padding);
+		FrameLen += padding;
+		for (i = 0 ; i < FrameLen /*HW_BEACON_OFFSET*/; i += 2)
+		{
+			if (NdisEqualMemory(ptr, pBeaconFrame, 2) == FALSE)
+			{
+				NdisMoveMemory(ptr, pBeaconFrame, 2);
+				//shortValue = *ptr + (*(ptr+1)<<8);
+				//RTMP_IO_WRITE8(pAd, pAd->BeaconOffset[bcn_idx] + TXWI_SIZE + i, shortValue);
+				RTUSBMultiWrite(pAd, pAd->BeaconOffset[bcn_idx] + TXWI_SIZE + i, ptr, 2);
+			}
+			ptr +=2;
+			pBeaconFrame += 2;
+		}
+
+		pBeaconSync->BeaconBitMap |= (1 << bcn_idx);
+	}
+
+}
+
+
+VOID RT2870_BssBeaconStop(
+	IN RTMP_ADAPTER *pAd)
+{
+	BEACON_SYNC_STRUCT	*pBeaconSync;
+	int i, offset;
+	BOOLEAN	Cancelled = TRUE;
+
+	pBeaconSync = pAd->CommonCfg.pBeaconSync;
+	if (pBeaconSync && pBeaconSync->EnableBeacon)
+	{
+		INT NumOfBcn;
+
+
+#ifdef CONFIG_STA_SUPPORT
+		IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
+		{
+			NumOfBcn = MAX_MESH_NUM;
+		}
+#endif // CONFIG_STA_SUPPORT //
+
+		RTMPCancelTimer(&pAd->CommonCfg.BeaconUpdateTimer, &Cancelled);
+
+		for(i=0; i<NumOfBcn; i++)
+		{
+			NdisZeroMemory(pBeaconSync->BeaconBuf[i], HW_BEACON_OFFSET);
+			NdisZeroMemory(pBeaconSync->BeaconTxWI[i], TXWI_SIZE);
+
+			for (offset=0; offset<HW_BEACON_OFFSET; offset+=4)
+				RTMP_IO_WRITE32(pAd, pAd->BeaconOffset[i] + offset, 0x00);
+
+			pBeaconSync->CapabilityInfoLocationInBeacon[i] = 0;
+			pBeaconSync->TimIELocationInBeacon[i] = 0;
+		}
+		pBeaconSync->BeaconBitMap = 0;
+		pBeaconSync->DtimBitOn = 0;
+	}
+}
+
+
+VOID RT2870_BssBeaconStart(
+	IN RTMP_ADAPTER *pAd)
+{
+	int apidx;
+	BEACON_SYNC_STRUCT	*pBeaconSync;
+//	LARGE_INTEGER 	tsfTime, deltaTime;
+
+	pBeaconSync = pAd->CommonCfg.pBeaconSync;
+	if (pBeaconSync && pBeaconSync->EnableBeacon)
+	{
+		INT NumOfBcn;
+
+
+#ifdef CONFIG_STA_SUPPORT
+		IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
+		{
+			NumOfBcn = MAX_MESH_NUM;
+		}
+#endif // CONFIG_STA_SUPPORT //
+
+		for(apidx=0; apidx<NumOfBcn; apidx++)
+		{
+			UCHAR CapabilityInfoLocationInBeacon = 0;
+			UCHAR TimIELocationInBeacon = 0;
+
+			NdisZeroMemory(pBeaconSync->BeaconBuf[apidx], HW_BEACON_OFFSET);
+			pBeaconSync->CapabilityInfoLocationInBeacon[apidx] = CapabilityInfoLocationInBeacon;
+			pBeaconSync->TimIELocationInBeacon[apidx] = TimIELocationInBeacon;
+			NdisZeroMemory(pBeaconSync->BeaconTxWI[apidx], TXWI_SIZE);
+		}
+		pBeaconSync->BeaconBitMap = 0;
+		pBeaconSync->DtimBitOn = 0;
+		pAd->CommonCfg.BeaconUpdateTimer.Repeat = TRUE;
+
+		pAd->CommonCfg.BeaconAdjust = 0;
+		pAd->CommonCfg.BeaconFactor = 0xffffffff / (pAd->CommonCfg.BeaconPeriod << 10);
+		pAd->CommonCfg.BeaconRemain = (0xffffffff % (pAd->CommonCfg.BeaconPeriod << 10)) + 1;
+		printk("RT2870_BssBeaconStart:BeaconFactor=%d, BeaconRemain=%d!\n", pAd->CommonCfg.BeaconFactor, pAd->CommonCfg.BeaconRemain);
+		RTMPSetTimer(&pAd->CommonCfg.BeaconUpdateTimer, pAd->CommonCfg.BeaconPeriod);
+
+	}
+}
+
+
+VOID RT2870_BssBeaconInit(
+	IN RTMP_ADAPTER *pAd)
+{
+	BEACON_SYNC_STRUCT	*pBeaconSync;
+	int i;
+
+	NdisAllocMemory(pAd->CommonCfg.pBeaconSync, sizeof(BEACON_SYNC_STRUCT), MEM_ALLOC_FLAG);
+	if (pAd->CommonCfg.pBeaconSync)
+	{
+		pBeaconSync = pAd->CommonCfg.pBeaconSync;
+		NdisZeroMemory(pBeaconSync, sizeof(BEACON_SYNC_STRUCT));
+		for(i=0; i < HW_BEACON_MAX_COUNT; i++)
+		{
+			NdisZeroMemory(pBeaconSync->BeaconBuf[i], HW_BEACON_OFFSET);
+			pBeaconSync->CapabilityInfoLocationInBeacon[i] = 0;
+			pBeaconSync->TimIELocationInBeacon[i] = 0;
+			NdisZeroMemory(pBeaconSync->BeaconTxWI[i], TXWI_SIZE);
+		}
+		pBeaconSync->BeaconBitMap = 0;
+
+		//RTMPInitTimer(pAd, &pAd->CommonCfg.BeaconUpdateTimer, GET_TIMER_FUNCTION(BeaconUpdateExec), pAd, TRUE);
+		pBeaconSync->EnableBeacon = TRUE;
+	}
+}
+
+
+VOID RT2870_BssBeaconExit(
+	IN RTMP_ADAPTER *pAd)
+{
+	BEACON_SYNC_STRUCT	*pBeaconSync;
+	BOOLEAN	Cancelled = TRUE;
+	int i;
+
+	if (pAd->CommonCfg.pBeaconSync)
+	{
+		pBeaconSync = pAd->CommonCfg.pBeaconSync;
+		pBeaconSync->EnableBeacon = FALSE;
+		RTMPCancelTimer(&pAd->CommonCfg.BeaconUpdateTimer, &Cancelled);
+		pBeaconSync->BeaconBitMap = 0;
+
+		for(i=0; i<HW_BEACON_MAX_COUNT; i++)
+		{
+			NdisZeroMemory(pBeaconSync->BeaconBuf[i], HW_BEACON_OFFSET);
+			pBeaconSync->CapabilityInfoLocationInBeacon[i] = 0;
+			pBeaconSync->TimIELocationInBeacon[i] = 0;
+			NdisZeroMemory(pBeaconSync->BeaconTxWI[i], TXWI_SIZE);
+		}
+
+		NdisFreeMemory(pAd->CommonCfg.pBeaconSync, HW_BEACON_OFFSET * HW_BEACON_MAX_COUNT, 0);
+		pAd->CommonCfg.pBeaconSync = NULL;
+	}
+}
+
+VOID BeaconUpdateExec(
+    IN PVOID SystemSpecific1,
+    IN PVOID FunctionContext,
+    IN PVOID SystemSpecific2,
+    IN PVOID SystemSpecific3)
+{
+	PRTMP_ADAPTER	pAd = (PRTMP_ADAPTER)FunctionContext;
+	LARGE_INTEGER	tsfTime_a;//, tsfTime_b, deltaTime_exp, deltaTime_ab;
+	UINT32			delta, remain, remain_low, remain_high;
+//	BOOLEAN			positive;
+
+	ReSyncBeaconTime(pAd);
+
+
+
+	RTMP_IO_READ32(pAd, TSF_TIMER_DW0, &tsfTime_a.u.LowPart);
+	RTMP_IO_READ32(pAd, TSF_TIMER_DW1, &tsfTime_a.u.HighPart);
+
+
+	//positive=getDeltaTime(tsfTime_a, expectedTime, &deltaTime_exp);
+	remain_high = pAd->CommonCfg.BeaconRemain * tsfTime_a.u.HighPart;
+	remain_low = tsfTime_a.u.LowPart % (pAd->CommonCfg.BeaconPeriod << 10);
+	remain = (remain_high + remain_low)%(pAd->CommonCfg.BeaconPeriod << 10);
+	delta = (pAd->CommonCfg.BeaconPeriod << 10) - remain;
+
+	pAd->CommonCfg.BeaconUpdateTimer.TimerValue = (delta >> 10) + 10;
+
+}
+
diff --git a/drivers/staging/rt2870/Kconfig b/drivers/staging/rt2870/Kconfig
new file mode 100644
index 00000000000..8398d9797e1
--- /dev/null
+++ b/drivers/staging/rt2870/Kconfig
@@ -0,0 +1,6 @@
+config RT2870
+	tristate "Ralink 2870 wireless support"
+	depends on USB && X86 && WLAN_80211
+	---help---
+	  This is an experimental driver for the Ralink 2870 wireless chip.
+
diff --git a/drivers/staging/rt2870/Makefile b/drivers/staging/rt2870/Makefile
new file mode 100644
index 00000000000..1a015f408e6
--- /dev/null
+++ b/drivers/staging/rt2870/Makefile
@@ -0,0 +1,47 @@
+obj-$(CONFIG_RT2870)	+= rt2870sta.o
+
+# TODO: all of these should be removed
+EXTRA_CFLAGS += -DLINUX -DAGGREGATION_SUPPORT -DPIGGYBACK_SUPPORT -DWMM_SUPPORT
+EXTRA_CFLAGS += -DRT2870
+EXTRA_CFLAGS += -DCONFIG_STA_SUPPORT
+EXTRA_CFLAGS += -DDBG
+EXTRA_CFLAGS += -DDOT11_N_SUPPORT
+EXTRA_CFLAGS += -DWPA_SUPPLICANT_SUPPORT
+EXTRA_CFLAGS += -DNATIVE_WPA_SUPPLICANT_SUPPORT
+
+rt2870sta-objs :=		\
+	common/md5.o		\
+	common/mlme.o		\
+	common/rtmp_wep.o	\
+	common/action.o		\
+	common/cmm_data.o	\
+	common/rtmp_init.o	\
+	common/rtmp_tkip.o	\
+	common/cmm_sync.o	\
+	common/eeprom.o		\
+	common/cmm_sanity.o	\
+	common/cmm_info.o	\
+	common/cmm_wpa.o	\
+	common/dfs.o		\
+	common/spectrum.o	\
+	sta/assoc.o		\
+	sta/aironet.o		\
+	sta/auth.o		\
+	sta/auth_rsp.o		\
+	sta/sync.o		\
+	sta/sanity.o		\
+	sta/rtmp_data.o		\
+	sta/connect.o		\
+	sta/wpa.o		\
+	rt_linux.o		\
+	rt_profile.o		\
+	rt_main_dev.o		\
+	sta_ioctl.o		\
+	common/ba_action.o	\
+	2870_main_dev.o		\
+	common/2870_rtmp_init.o	\
+	common/rtusb_io.o	\
+	common/rtusb_bulk.o	\
+	common/rtusb_data.o	\
+	common/cmm_data_2870.o
+
diff --git a/drivers/staging/rt2870/TODO b/drivers/staging/rt2870/TODO
new file mode 100644
index 00000000000..eae1ac47d3f
--- /dev/null
+++ b/drivers/staging/rt2870/TODO
@@ -0,0 +1,10 @@
+TODO:
+	- checkpatch.pl clean
+	- sparse clean
+	- port to in-kernel 80211 stack
+	- remove reading from /etc/ config files
+	- review by the wireless developer community
+
+Please send any patches or complaints about this driver to Greg
+Kroah-Hartman <greg@kroah.com> and don't bother the upstream wireless
+kernel developers about it, they want nothing to do with it.
diff --git a/drivers/staging/rt2870/aironet.h b/drivers/staging/rt2870/aironet.h
new file mode 100644
index 00000000000..1e07b19b8cd
--- /dev/null
+++ b/drivers/staging/rt2870/aironet.h
@@ -0,0 +1,210 @@
+/*
+ *************************************************************************
+ * Ralink Tech Inc.
+ * 5F., No.36, Taiyuan St., Jhubei City,
+ * Hsinchu County 302,
+ * Taiwan, R.O.C.
+ *
+ * (c) Copyright 2002-2007, Ralink Technology, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify  *
+ * it under the terms of the GNU General Public License as published by  *
+ * the Free Software Foundation; either version 2 of the License, or     *
+ * (at your option) any later version.                                   *
+ *                                                                       *
+ * This program is distributed in the hope that it will be useful,       *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ * GNU General Public License for more details.                          *
+ *                                                                       *
+ * You should have received a copy of the GNU General Public License     *
+ * along with this program; if not, write to the                         *
+ * Free Software Foundation, Inc.,                                       *
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ *                                                                       *
+ *************************************************************************
+
+	Module Name:
+	aironet.h
+
+	Abstract:
+
+	Revision History:
+	Who			When			What
+	--------	----------		----------------------------------------------
+	Name		Date			Modification logs
+	Paul Lin	04-06-15		Initial
+*/
+
+#ifndef	__AIRONET_H__
+#define	__AIRONET_H__
+
+// Measurement Type definition
+#define	MSRN_TYPE_UNUSED				0
+#define	MSRN_TYPE_CHANNEL_LOAD_REQ		1
+#define	MSRN_TYPE_NOISE_HIST_REQ		2
+#define	MSRN_TYPE_BEACON_REQ			3
+#define	MSRN_TYPE_FRAME_REQ				4
+
+// Scan Mode in Beacon Request
+#define	MSRN_SCAN_MODE_PASSIVE			0
+#define	MSRN_SCAN_MODE_ACTIVE			1
+#define	MSRN_SCAN_MODE_BEACON_TABLE		2
+
+// PHY type definition for Aironet beacon report, CCX 2 table 36-9
+#define	PHY_FH							1
+#define	PHY_DSS							2
+#define	PHY_UNUSED						3
+#define	PHY_OFDM						4
+#define	PHY_HR_DSS						5
+#define	PHY_ERP							6
+
+// RPI table in dBm
+#define	RPI_0			0			//	Power <= -87
+#define	RPI_1			1			//	-87 < Power <= -82
+#define	RPI_2			2			//	-82 < Power <= -77
+#define	RPI_3			3			//	-77 < Power <= -72
+#define	RPI_4			4			//	-72 < Power <= -67
+#define	RPI_5			5			//	-67 < Power <= -62
+#define	RPI_6			6			//	-62 < Power <= -57
+#define	RPI_7			7			//	-57 < Power
+
+// Cisco Aironet IAPP definetions
+#define	AIRONET_IAPP_TYPE					0x32
+#define	AIRONET_IAPP_SUBTYPE_REQUEST		0x01
+#define	AIRONET_IAPP_SUBTYPE_REPORT			0x81
+
+// Measurement Request detail format
+typedef	struct	_MEASUREMENT_REQUEST	{
+	UCHAR	Channel;
+	UCHAR	ScanMode;			// Use only in beacon request, other requests did not use this field
+	USHORT	Duration;
+}	MEASUREMENT_REQUEST, *PMEASUREMENT_REQUEST;
+
+// Beacon Measurement Report
+// All these field might change to UCHAR, because we didn't do anything to these report.
+// We copy all these beacons and report to CCX 2 AP.
+typedef	struct	_BEACON_REPORT	{
+	UCHAR	Channel;
+	UCHAR	Spare;
+	USHORT	Duration;
+	UCHAR	PhyType;			// Definiation is listed above table 36-9
+	UCHAR	RxPower;
+	UCHAR	BSSID[6];
+	UCHAR	ParentTSF[4];
+	UCHAR	TargetTSF[8];
+	USHORT	BeaconInterval;
+	USHORT	CapabilityInfo;
+}	BEACON_REPORT, *PBEACON_REPORT;
+
+// Frame Measurement Report (Optional)
+typedef	struct	_FRAME_REPORT	{
+	UCHAR	Channel;
+	UCHAR	Spare;
+	USHORT	Duration;
+	UCHAR	TA;
+	UCHAR	BSSID[6];
+	UCHAR	RSSI;
+	UCHAR	Count;
+}	FRAME_REPORT, *PFRAME_REPORT;
+
+#pragma pack(1)
+// Channel Load Report
+typedef	struct	_CHANNEL_LOAD_REPORT	{
+	UCHAR	Channel;
+	UCHAR	Spare;
+	USHORT	Duration;
+	UCHAR	CCABusy;
+}	CHANNEL_LOAD_REPORT, *PCHANNEL_LOAD_REPORT;
+#pragma pack()
+
+// Nosie Histogram Report
+typedef	struct	_NOISE_HIST_REPORT	{
+	UCHAR	Channel;
+	UCHAR	Spare;
+	USHORT	Duration;
+	UCHAR	Density[8];
+}	NOISE_HIST_REPORT, *PNOISE_HIST_REPORT;
+
+// Radio Management Capability element
+typedef	struct	_RADIO_MANAGEMENT_CAPABILITY	{
+	UCHAR	Eid;				// TODO: Why the Eid is 1 byte, not normal 2 bytes???
+	UCHAR	Length;
+	UCHAR	AironetOui[3];		// AIronet OUI (00 40 96)
+	UCHAR	Type;				// Type / Version
+	USHORT	Status;				// swap16 required
+}	RADIO_MANAGEMENT_CAPABILITY, *PRADIO_MANAGEMENT_CAPABILITY;
+
+// Measurement Mode Bit definition
+typedef	struct	_MEASUREMENT_MODE	{
+	UCHAR	Rsvd:4;
+	UCHAR	Report:1;
+	UCHAR	NotUsed:1;
+	UCHAR	Enable:1;
+	UCHAR	Parallel:1;
+}	MEASUREMENT_MODE, *PMEASUREMENT_MODE;
+
+// Measurement Request element, This is little endian mode
+typedef	struct	_MEASUREMENT_REQUEST_ELEMENT	{
+	USHORT				Eid;
+	USHORT				Length;				// swap16 required
+	USHORT				Token;				// non-zero unique token
+	UCHAR				Mode;				// Measurement Mode
+	UCHAR				Type;				// Measurement type
+}	MEASUREMENT_REQUEST_ELEMENT, *PMEASUREMENT_REQUEST_ELEMENT;
+
+// Measurement Report element, This is little endian mode
+typedef	struct	_MEASUREMENT_REPORT_ELEMENT	{
+	USHORT				Eid;
+	USHORT				Length;				// swap16 required
+	USHORT				Token;				// non-zero unique token
+	UCHAR				Mode;				// Measurement Mode
+	UCHAR				Type;				// Measurement type
+}	MEASUREMENT_REPORT_ELEMENT, *PMEASUREMENT_REPORT_ELEMENT;
+
+// Cisco Aironet IAPP Frame Header, Network byte order used
+typedef	struct	_AIRONET_IAPP_HEADER {
+	UCHAR	CiscoSnapHeader[8];	// 8 bytes Cisco snap header
+	USHORT	Length;				// IAPP ID & length, remember to swap16 in LE system
+	UCHAR	Type;				// IAPP type
+	UCHAR	SubType;			// IAPP subtype
+	UCHAR	DA[6];				// Destination MAC address
+	UCHAR	SA[6];				// Source MAC address
+	USHORT	Token;				// Dialog token, no need to swap16 since it is for yoken usage only
+}	AIRONET_IAPP_HEADER, *PAIRONET_IAPP_HEADER;
+
+// Radio Measurement Request frame
+typedef	struct	_AIRONET_RM_REQUEST_FRAME	{
+    AIRONET_IAPP_HEADER	IAPP;			// Common header
+	UCHAR				Delay;			// Activation Delay
+	UCHAR				Offset;			// Measurement offset
+}	AIRONET_RM_REQUEST_FRAME, *PAIRONET_RM_REQUEST_FRAME;
+
+// Radio Measurement Report frame
+typedef	struct	_AIRONET_RM_REPORT_FRAME	{
+    AIRONET_IAPP_HEADER	IAPP;			// Common header
+}	AIRONET_RM_REPORT_FRAME, *PAIRONET_RM_REPORT_FRAME;
+
+// Saved element request actions which will saved in StaCfg.
+typedef	struct	_RM_REQUEST_ACTION	{
+	MEASUREMENT_REQUEST_ELEMENT	ReqElem;		// Saved request element
+	MEASUREMENT_REQUEST			Measurement;	// Saved measurement within the request element
+}	RM_REQUEST_ACTION, *PRM_REQUEST_ACTION;
+
+// CCX administration control
+typedef	union	_CCX_CONTROL	{
+	struct	{
+		UINT32		Enable:1;			// Enable CCX2
+		UINT32		LeapEnable:1;		// Enable LEAP at CCX2
+		UINT32		RMEnable:1;			// Radio Measurement Enable
+		UINT32		DCRMEnable:1;		// Non serving channel Radio Measurement enable
+		UINT32		QOSEnable:1;		// Enable QOS for CCX 2.0 support
+		UINT32		FastRoamEnable:1;	// Enable fast roaming
+		UINT32		Rsvd:2;				// Not used
+		UINT32		dBmToRoam:8;		// the condition to roam when receiving Rssi less than this value. It's negative value.
+		UINT32		TuLimit:16;			// Limit for different channel scan
+	}	field;
+	UINT32			word;
+}	CCX_CONTROL, *PCCX_CONTROL;
+
+#endif	// __AIRONET_H__
diff --git a/drivers/staging/rt2870/ap.h b/drivers/staging/rt2870/ap.h
new file mode 100644
index 00000000000..0dc55751679
--- /dev/null
+++ b/drivers/staging/rt2870/ap.h
@@ -0,0 +1,562 @@
+/*
+ *************************************************************************
+ * Ralink Tech Inc.
+ * 5F., No.36, Taiyuan St., Jhubei City,
+ * Hsinchu County 302,
+ * Taiwan, R.O.C.
+ *
+ * (c) Copyright 2002-2007, Ralink Technology, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify  *
+ * it under the terms of the GNU General Public License as published by  *
+ * the Free Software Foundation; either version 2 of the License, or     *
+ * (at your option) any later version.                                   *
+ *