summaryrefslogtreecommitdiff
path: root/drivers/staging/rt2860/usb_main_dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/rt2860/usb_main_dev.c')
-rw-r--r--drivers/staging/rt2860/usb_main_dev.c897
1 files changed, 897 insertions, 0 deletions
diff --git a/drivers/staging/rt2860/usb_main_dev.c b/drivers/staging/rt2860/usb_main_dev.c
new file mode 100644
index 00000000000..16e1bbfce43
--- /dev/null
+++ b/drivers/staging/rt2860/usb_main_dev.c
@@ -0,0 +1,897 @@
+/*
+ *************************************************************************
+ * 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. *
+ * *
+ *************************************************************************/
+
+#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/RT3070 Wireless Lan Linux Driver");
+MODULE_LICENSE("GPL");
+#ifdef MODULE_VERSION
+MODULE_VERSION(STA_DRIVER_VERSION);
+#endif
+
+
+/* module table */
+struct usb_device_id rtusb_usb_id[] = {
+#ifdef RT2870
+ {USB_DEVICE(0x148F,0x2770)}, /* Ralink */
+ {USB_DEVICE(0x148F,0x2870)}, /* Ralink */
+ {USB_DEVICE(0x07B8,0x2870)}, /* AboCom */
+ {USB_DEVICE(0x07B8,0x2770)}, /* AboCom */
+ {USB_DEVICE(0x0DF6,0x0039)}, /* Sitecom 2770 */
+ {USB_DEVICE(0x083A,0x7512)}, /* Arcadyan 2770 */
+ {USB_DEVICE(0x0789,0x0162)}, /* Logitec 2870 */
+ {USB_DEVICE(0x0789,0x0163)}, /* Logitec 2870 */
+ {USB_DEVICE(0x0789,0x0164)}, /* Logitec 2870 */
+ {USB_DEVICE(0x177f,0x0302)}, /* lsusb */
+ {USB_DEVICE(0x0B05,0x1731)}, /* Asus */
+ {USB_DEVICE(0x0B05,0x1732)}, /* Asus */
+ {USB_DEVICE(0x0B05,0x1742)}, /* Asus */
+ {USB_DEVICE(0x0DF6,0x0017)}, /* Sitecom */
+ {USB_DEVICE(0x0DF6,0x002B)}, /* Sitecom */
+ {USB_DEVICE(0x0DF6,0x002C)}, /* Sitecom */
+ {USB_DEVICE(0x0DF6,0x002D)}, /* Sitecom */
+ {USB_DEVICE(0x14B2,0x3C06)}, /* Conceptronic */
+ {USB_DEVICE(0x14B2,0x3C28)}, /* Conceptronic */
+ {USB_DEVICE(0x2019,0xED06)}, /* Planex Communications, Inc. */
+ {USB_DEVICE(0x07D1,0x3C09)}, /* D-Link */
+ {USB_DEVICE(0x07D1,0x3C11)}, /* D-Link */
+ {USB_DEVICE(0x14B2,0x3C07)}, /* AL */
+ {USB_DEVICE(0x050D,0x8053)}, /* Belkin */
+ {USB_DEVICE(0x14B2,0x3C23)}, /* Airlink */
+ {USB_DEVICE(0x14B2,0x3C27)}, /* Airlink */
+ {USB_DEVICE(0x07AA,0x002F)}, /* Corega */
+ {USB_DEVICE(0x07AA,0x003C)}, /* Corega */
+ {USB_DEVICE(0x07AA,0x003F)}, /* Corega */
+ {USB_DEVICE(0x1044,0x800B)}, /* Gigabyte */
+ {USB_DEVICE(0x15A9,0x0006)}, /* Sparklan */
+ {USB_DEVICE(0x083A,0xB522)}, /* SMC */
+ {USB_DEVICE(0x083A,0xA618)}, /* SMC */
+ {USB_DEVICE(0x083A,0x8522)}, /* Arcadyan */
+ {USB_DEVICE(0x083A,0x7522)}, /* Arcadyan */
+ {USB_DEVICE(0x0CDE,0x0022)}, /* ZCOM */
+ {USB_DEVICE(0x0586,0x3416)}, /* Zyxel */
+ {USB_DEVICE(0x0CDE,0x0025)}, /* Zyxel */
+ {USB_DEVICE(0x1740,0x9701)}, /* EnGenius */
+ {USB_DEVICE(0x1740,0x9702)}, /* EnGenius */
+ {USB_DEVICE(0x0471,0x200f)}, /* Philips */
+ {USB_DEVICE(0x14B2,0x3C25)}, /* Draytek */
+ {USB_DEVICE(0x13D3,0x3247)}, /* AzureWave */
+ {USB_DEVICE(0x083A,0x6618)}, /* Accton */
+ {USB_DEVICE(0x15c5,0x0008)}, /* Amit */
+ {USB_DEVICE(0x0E66,0x0001)}, /* Hawking */
+ {USB_DEVICE(0x0E66,0x0003)}, /* Hawking */
+ {USB_DEVICE(0x129B,0x1828)}, /* Siemens */
+ {USB_DEVICE(0x157E,0x300E)}, /* U-Media */
+ {USB_DEVICE(0x050d,0x805c)},
+ {USB_DEVICE(0x050d,0x815c)},
+ {USB_DEVICE(0x1482,0x3C09)}, /* Abocom*/
+ {USB_DEVICE(0x14B2,0x3C09)}, /* Alpha */
+ {USB_DEVICE(0x04E8,0x2018)}, /* samsung */
+ {USB_DEVICE(0x5A57,0x0280)}, /* Zinwell */
+ {USB_DEVICE(0x5A57,0x0282)}, /* Zinwell */
+ {USB_DEVICE(0x7392,0x7718)},
+ {USB_DEVICE(0x7392,0x7717)},
+ {USB_DEVICE(0x1737,0x0070)}, /* Linksys WUSB100 */
+ {USB_DEVICE(0x1737,0x0071)}, /* Linksys WUSB600N */
+ {USB_DEVICE(0x0411,0x00e8)}, /* Buffalo WLI-UC-G300N*/
+ {USB_DEVICE(0x050d,0x815c)}, /* Belkin F5D8053 */
+#endif // RT2870 //
+#ifdef RT3070
+ {USB_DEVICE(0x148F,0x3070)}, /* Ralink 3070 */
+ {USB_DEVICE(0x148F,0x3071)}, /* Ralink 3071 */
+ {USB_DEVICE(0x148F,0x3072)}, /* Ralink 3072 */
+ {USB_DEVICE(0x0DB0,0x3820)}, /* Ralink 3070 */
+ {USB_DEVICE(0x0DF6,0x003E)}, /* Sitecom 3070 */
+ {USB_DEVICE(0x0DF6,0x0042)}, /* Sitecom 3072 */
+ {USB_DEVICE(0x14B2,0x3C12)}, /* AL 3070 */
+ {USB_DEVICE(0x18C5,0x0012)}, /* Corega 3070 */
+ {USB_DEVICE(0x083A,0x7511)}, /* Arcadyan 3070 */
+ {USB_DEVICE(0x1740,0x9703)}, /* EnGenius 3070 */
+ {USB_DEVICE(0x1740,0x9705)}, /* EnGenius 3071 */
+ {USB_DEVICE(0x1740,0x9706)}, /* EnGenius 3072 */
+ {USB_DEVICE(0x13D3,0x3273)}, /* AzureWave 3070*/
+ {USB_DEVICE(0x1044,0x800D)}, /* Gigabyte GN-WB32L 3070 */
+ {USB_DEVICE(0x2019,0xAB25)}, /* Planex Communications, Inc. RT3070 */
+ {USB_DEVICE(0x07B8,0x3070)}, /* AboCom 3070 */
+ {USB_DEVICE(0x07B8,0x3071)}, /* AboCom 3071 */
+ {USB_DEVICE(0x07B8,0x3072)}, /* Abocom 3072 */
+ {USB_DEVICE(0x7392,0x7711)}, /* Edimax 3070 */
+ {USB_DEVICE(0x1A32,0x0304)}, /* Quanta 3070 */
+ {USB_DEVICE(0x1EDA,0x2310)}, /* AirTies 3070 */
+ {USB_DEVICE(0x07D1,0x3C0A)}, /* D-Link 3072 */
+ {USB_DEVICE(0x07D1,0x3C0D)}, /* D-Link 3070 */
+ {USB_DEVICE(0x07D1,0x3C0E)}, /* D-Link 3070 */
+ {USB_DEVICE(0x07D1,0x3C0F)}, /* D-Link 3070 */
+ {USB_DEVICE(0x1D4D,0x000C)}, /* Pegatron Corporation 3070 */
+ {USB_DEVICE(0x1D4D,0x000E)}, /* Pegatron Corporation 3070 */
+ {USB_DEVICE(0x5A57,0x5257)}, /* Zinwell 3070 */
+ {USB_DEVICE(0x5A57,0x0283)}, /* Zinwell 3072 */
+ {USB_DEVICE(0x04BB,0x0945)}, /* I-O DATA 3072 */
+ {USB_DEVICE(0x203D,0x1480)}, /* Encore 3070 */
+#endif // RT3070 //
+ { USB_DEVICE(0x0DF6, 0x003F) }, /* Sitecom WL-608 */
+ { USB_DEVICE(0x1737, 0x0077) }, /* Linksys WUSB54GC-EU v3 */
+ { USB_DEVICE(0x2001, 0x3C09) }, /* D-Link */
+ { USB_DEVICE(0x2001, 0x3C0A) }, /* D-Link 3072*/
+ { USB_DEVICE(0x2019, 0xED14) }, /* Planex Communications, Inc. */
+ { }/* Terminating entry */
+};
+
+INT const rtusb_usb_id_len = sizeof(rtusb_usb_id) / sizeof(struct usb_device_id);
+
+MODULE_DEVICE_TABLE(usb, rtusb_usb_id);
+
+static void rt2870_disconnect(
+ IN struct usb_device *dev,
+ IN PRTMP_ADAPTER pAd);
+
+static int __devinit rt2870_probe(
+ IN struct usb_interface *intf,
+ IN struct usb_device *usb_dev,
+ IN const struct usb_device_id *dev_id,
+ IN RTMP_ADAPTER **ppAd);
+
+#ifndef PF_NOFREEZE
+#define PF_NOFREEZE 0
+#endif
+
+
+extern int rt28xx_close(IN struct net_device *net_dev);
+extern int rt28xx_open(struct net_device *net_dev);
+
+static BOOLEAN USBDevConfigInit(
+ IN struct usb_device *dev,
+ IN struct usb_interface *intf,
+ IN RTMP_ADAPTER *pAd);
+
+
+/*
+========================================================================
+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)
+{
+ struct usb_interface *intf = (struct usb_interface *)_dev_p;
+ struct usb_device *dev_p = interface_to_usbdev(intf);
+ 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;
+}
+
+/**************************************************************************/
+/**************************************************************************/
+//tested for kernel 2.6series
+/**************************************************************************/
+/**************************************************************************/
+
+#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 //
+
+static int rtusb_probe (struct usb_interface *intf,
+ const struct usb_device_id *id);
+static void rtusb_disconnect(struct usb_interface *intf);
+
+static BOOLEAN USBDevConfigInit(
+ IN struct usb_device *dev,
+ IN struct usb_interface *intf,
+ IN RTMP_ADAPTER *pAd)
+{
+ 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 = le2cpu16(iface_desc->endpoint[i].desc.wMaxPacketSize);
+
+ DBGPRINT_RAW(RT_DEBUG_TRACE, ("BULK IN MaxPacketSize = %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 = le2cpu16(iface_desc->endpoint[i].desc.wMaxPacketSize);
+
+ DBGPRINT_RAW(RT_DEBUG_TRACE, ("BULK OUT MaxPacketSize = %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;
+ }
+
+ pAd->config = &dev->config->desc;
+ usb_set_intfdata(intf, pAd);
+
+ return TRUE;
+
+}
+
+
+
+static int rtusb_probe (struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ RTMP_ADAPTER *pAd;
+ struct usb_device *dev;
+ int rv;
+
+ dev = interface_to_usbdev(intf);
+ dev = usb_get_dev(dev);
+
+ rv = rt2870_probe(intf, dev, id, &pAd);
+ if (rv != 0)
+ usb_put_dev(dev);
+
+ return rv;
+}
+
+
+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);
+
+ rt2870_disconnect(dev, pAd);
+}
+
+
+struct usb_driver rtusb_driver = {
+ .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 RT2870RejectPendingPackets(
+ 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 //
+
+// 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)
+{
+ RTMP_ADAPTER *pAd;
+ RTMP_OS_TASK *pTask;
+ int status;
+ status = 0;
+
+ pTask = (RTMP_OS_TASK *)Context;
+ pAd = (PRTMP_ADAPTER)pTask->priv;
+
+ RtmpOSTaskCustomize(pTask);
+
+ while(!pTask->task_killed)
+ {
+#ifdef KTHREAD_SUPPORT
+ RTMP_WAIT_EVENT_INTERRUPTIBLE(pAd, pTask);
+#else
+ RTMP_SEM_EVENT_WAIT(&(pTask->taskSema), status);
+
+ /* unlock the device pointers */
+ if (status != 0)
+ {
+ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS);
+ break;
+ }
+#endif
+
+ /* lock the device pointers , need to check if required*/
+ //down(&(pAd->usbdev_semaphore));
+
+ if (!pAd->PM_FlgSuspend)
+ MlmeHandler(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__));
+#ifndef KTHREAD_SUPPORT
+ pTask->taskPID = THREAD_PID_INIT_VALUE;
+ complete_and_exit (&pTask->taskComplete, 0);
+#endif
+ 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)
+{
+ RTMP_ADAPTER *pAd;
+ RTMP_OS_TASK *pTask;
+ int status;
+ status = 0;
+
+ pTask = (RTMP_OS_TASK *)Context;
+ pAd = (PRTMP_ADAPTER)pTask->priv;
+
+ RtmpOSTaskCustomize(pTask);
+
+ NdisAcquireSpinLock(&pAd->CmdQLock);
+ pAd->CmdQ.CmdQState = RTMP_TASK_STAT_RUNNING;
+ NdisReleaseSpinLock(&pAd->CmdQLock);
+
+ while (pAd && pAd->CmdQ.CmdQState == RTMP_TASK_STAT_RUNNING)
+ {
+#ifdef KTHREAD_SUPPORT
+ RTMP_WAIT_EVENT_INTERRUPTIBLE(pAd, pTask);
+#else
+ /* lock the device pointers */
+ RTMP_SEM_EVENT_WAIT(&(pTask->taskSema), status);
+
+ if (status != 0)
+ {
+ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS);
+ break;
+ }
+#endif
+
+ if (pAd->CmdQ.CmdQState == RTMP_TASK_STAT_STOPED)
+ break;
+
+ if (!pAd->PM_FlgSuspend)
+ CMDHandler(pAd);
+ }
+
+ if (pAd && !pAd->PM_FlgSuspend)
+ { // Clear the CmdQElements.
+ CmdQElmt *pCmdQElmt = NULL;
+
+ NdisAcquireSpinLock(&pAd->CmdQLock);
+ pAd->CmdQ.CmdQState = RTMP_TASK_STAT_STOPED;
+ while(pAd->CmdQ.size)
+ {
+ RTUSBDequeueCmd(&pAd->CmdQ, &pCmdQElmt);
+ if (pCmdQElmt)
+ {
+ if (pCmdQElmt->CmdFromNdis == TRUE)
+ {
+ if (pCmdQElmt->buffer != NULL)
+ os_free_mem(pAd, pCmdQElmt->buffer);
+ os_free_mem(pAd, (PUCHAR)pCmdQElmt);
+ }
+ else
+ {
+ if ((pCmdQElmt->buffer != NULL) && (pCmdQElmt->bufferlength != 0))
+ os_free_mem(pAd, pCmdQElmt->buffer);
+ os_free_mem(pAd, (PUCHAR)pCmdQElmt);
+ }
+ }
+ }
+
+ 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"));
+
+#ifndef KTHREAD_SUPPORT
+ pTask->taskPID = THREAD_PID_INIT_VALUE;
+ complete_and_exit (&pTask->taskComplete, 0);
+#endif
+ return 0;
+
+}
+
+
+VOID RTUSBWatchDog(IN RTMP_ADAPTER *pAd)
+{
+ PHT_TX_CONTEXT pHTTXContext;
+ int idx;
+ ULONG irqFlags;
+ PURB pUrb;
+ BOOLEAN needDumpSeq = FALSE;
+ UINT32 MACValue;
+ UINT32 TxRxQ_Pcnt;
+
+ 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);
+ RTMPusecDelay(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;
+ }
+
+ RTUSBReadMACRegister(pAd, 0x438, &TxRxQ_Pcnt);
+
+ 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)
+ {
+ INT actual_length=0,transfer_buffer_length=0;
+ BOOLEAN isDataPacket=FALSE;
+ 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;
+
+ actual_length=pUrb->actual_length;
+ transfer_buffer_length=pUrb->transfer_buffer_length;
+ isDataPacket=TRUE;
+ }
+ 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);
+
+
+ printk("%d:%d LTL=%d , TL=%d L:%d\n",idx,pAd->watchDogTxPendingCnt[idx],pAd->TransferedLength[idx]
+ ,actual_length,transfer_buffer_length);
+
+ if (pUrb)
+ {
+ if ((isDataPacket
+ && pAd->TransferedLength[idx]==actual_length
+ && pAd->TransferedLength[idx]<transfer_buffer_length
+ && actual_length!=0
+// && TxRxQ_Pcnt==0
+ && pAd->watchDogTxPendingCnt[idx]>3)
+ || isDataPacket==FALSE || pAd->watchDogTxPendingCnt[idx]>6)
+ {
+ DBGPRINT(RT_DEBUG_TRACE, ("Maybe the Tx Bulk-Out hanged! Cancel the pending Tx bulks request of idx(%d)!\n", idx));
+ 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);
+ }
+
+ if (isDataPacket==TRUE)
+ pAd->TransferedLength[idx]=actual_length;
+ }
+ else
+ {
+ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[idx], irqFlags);
+ }
+ }
+
+ // 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);
+ }
+ }
+}
+
+/*
+========================================================================
+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 rt2870_disconnect(struct usb_device *dev, PRTMP_ADAPTER pAd)
+{
+ DBGPRINT(RT_DEBUG_ERROR, ("rtusb_disconnect: unregister usbnet usb-%s-%s\n",
+ dev->bus->bus_name, dev->devpath));
+ if (!pAd)
+ {
+ usb_put_dev(dev);
+ 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);
+
+
+ RtmpPhyNetDevExit(pAd, pAd->net_dev);
+
+ // FIXME: Shall we need following delay and flush the schedule??
+ udelay(1);
+ flush_scheduled_work();
+ udelay(1);
+
+ // free the root net_device
+ RtmpOSNetDevFree(pAd->net_dev);
+
+ RtmpRaDevCtrlExit(pAd);
+
+ // release a use of the usb device structure
+ usb_put_dev(dev);
+ udelay(1);
+
+ DBGPRINT(RT_DEBUG_ERROR, (" RTUSB disconnect successfully\n"));
+}
+
+
+static int __devinit rt2870_probe(
+ IN struct usb_interface *intf,
+ IN struct usb_device *usb_dev,
+ IN const struct usb_device_id *dev_id,
+ IN RTMP_ADAPTER **ppAd)
+{
+ struct net_device *net_dev = NULL;
+ RTMP_ADAPTER *pAd = (RTMP_ADAPTER *) NULL;
+ INT status, rv;
+ PVOID handle;
+ RTMP_OS_NETDEV_OP_HOOK netDevHook;
+
+
+ DBGPRINT(RT_DEBUG_TRACE, ("===>rt2870_probe()!\n"));
+
+ // Check chipset vendor/product ID
+ //if (RT28XXChipsetCheck(_dev_p) == FALSE)
+ // goto err_out;
+
+//RtmpDevInit=============================================
+ // Allocate RTMP_ADAPTER adapter structure
+ handle = kmalloc(sizeof(struct os_cookie), GFP_KERNEL);
+ if (handle == NULL)
+ {
+ printk("rt2870_probe(): Allocate memory for os handle failed!\n");
+ return -ENOMEM;
+ }
+ ((POS_COOKIE)handle)->pUsb_Dev = usb_dev;
+
+ rv = RTMPAllocAdapterBlock(handle, &pAd);
+ if (rv != NDIS_STATUS_SUCCESS)
+ {
+ kfree(handle);
+ goto err_out;
+ }
+
+//USBDevInit==============================================
+ if (USBDevConfigInit(usb_dev, intf, pAd) == FALSE)
+ goto err_out_free_radev;
+
+ RtmpRaDevCtrlInit(pAd, RTMP_DEV_INF_USB);
+
+//NetDevInit==============================================
+ net_dev = RtmpPhyNetDevInit(pAd, &netDevHook);
+ if (net_dev == NULL)
+ goto err_out_free_radev;
+
+ // Here are the net_device structure with usb specific parameters.
+ /* for supporting Network Manager.
+ * Set the sysfs physical device reference for the network logical device if set prior to registration will
+ * cause a symlink during initialization.
+ */
+ SET_NETDEV_DEV(net_dev, &(usb_dev->dev));
+
+ pAd->StaCfg.OriDevType = net_dev->type;
+
+//All done, it's time to register the net device to linux kernel.
+ // Register this device
+ status = RtmpOSNetDevAttach(net_dev, &netDevHook);
+ if (status != 0)
+ goto err_out_free_netdev;
+
+#ifdef KTHREAD_SUPPORT
+ init_waitqueue_head(&pAd->mlmeTask.kthread_q);
+ init_waitqueue_head(&pAd->timerTask.kthread_q);
+ init_waitqueue_head(&pAd->cmdQTask.kthread_q);
+#endif
+
+ *ppAd = pAd;
+
+ DBGPRINT(RT_DEBUG_TRACE, ("<===rt2870_probe()!\n"));
+
+ return 0;
+
+ /* --------------------------- ERROR HANDLE --------------------------- */
+err_out_free_netdev:
+ RtmpOSNetDevFree(net_dev);
+
+err_out_free_radev:
+ RTMPFreeAdapter(pAd);
+
+err_out:
+ *ppAd = NULL;
+
+ return -1;
+
+}