kernel-ark/drivers/staging/rt2860/usb_main_dev.c
Bartlomiej Zolnierkiewicz ca97b83888 Staging: rt28x0: updates from vendor's V2.1.0.0 drivers
Port changes from:

* 2009_0420_RT2860_Linux_STA_V2.1.0.0
* 2009_0302_RT2870_Linux_STA_v2.1.0.0
* 2009_0525_RT3070_Linux_STA_v2.1.1.0

to in-kernel drivers.


From the RT2860 driver release note:

[2.1.0.0]
1. New generation schema for multiple OS porting
2. Fixed Ad-hoc ping failed in noisy environment. (Probe Response has too
    many retry packet then cause "not enough space in MgmtRing")
3. Fixed WPA(2)PSK issue when group cipher of AP is WEP40 or WEP104.
4. Modified iwpriv ra0 get_site_survey:
	In scan list result: Security shows "NONE" when AP is OPEN/NONE,
	shows "WEP" when AP is OPEN/WEP or SHARED/WEP, shows
	"WPAPSK(WPA2PSK)/TKIP(AES)" when AP is WPAPSK(WPA2PSK)/TKIP(AES)
	shows "WPA(WPA2)/TKIP(AES)" when AP is WPA(WPA2)/TKIP(AES)
5. Support kthread.
6. Add New A band channel list region 15 contains the whole channels in
   the A band region 4 and the new CE channel 167,169,171,173
7. Add New IEEE802.11r functionality.
8. Fixed WPA2-Enterprise failed when AP reboot or turn off then turn on.
9. Fixed STA cannot connect to 11B only AP when the setting of is PHY_11GN.


From the RT2870 driver release note:

[V2.1.0.0]
1. New generation schema for multiple OS porting.
2. Fixed Ad-hoc ping failed in noisy environment. (Probe Response has too
   many retry packet then cause "not enough space in MgmtRing").
3. Fixed WPS failed with D-Link DIR-628 in 5GHz.
4. Change FastRoaming in DAT file to AutoRoaming.
5. Support kthread.
6. Add New A band channel list region 15 contains the whole channels in
   the A band region and the new CE channel 167,169,171,173.
7. New IEEE802.11r functionality.


From the RT3070 driver release note:

Version V2.1.1.0
       1. Linux kernel 2.6.29 support.
       2. Fix eFuse write from BIN file bug.

Version 2.1.0.0
       1. New generation schema for multiple OS porting
       2. Fixed Ad-hoc ping failed in noisy environment.
       3. Modified iwpriv ra0 get_site_survey:
       4. Change FastRoaming in DAT file to AutoRoaming.
       5. Support kthread.
       6. New IEEE802.11r functionality.


Tested with RT2860 and RT3070 chipsets.

Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2009-12-11 12:21:44 -08:00

898 lines
25 KiB
C

/*
*************************************************************************
* Ralink Tech Inc.
* 5F., No.36, Taiyuan St., Jhubei City,
* Hsinchu County 302,
* Taiwan, R.O.C.
*
* (c) Copyright 2002-2007, Ralink Technology, Inc.
*
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
* *
*************************************************************************/
#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;
}