usb_main_dev.c 28.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
/*
 *************************************************************************
 * 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"

29 30 31
/* 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. *** */
32 33 34 35 36 37 38 39 40 41
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
42 43 44 45 46
	{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 */
47
	{USB_DEVICE(0x0DF6, 0x003F)},	/* Sitecom 2770 */
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
	{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 */
67
	{USB_DEVICE(0x050D, 0x825B)},	/* Belkin */
68
	{USB_DEVICE(0x050D, 0x935A)},	/* Belkin F6D4050 v1 */
69
	{USB_DEVICE(0x050D, 0x935B)},	/* Belkin F6D4050 v2 */
70 71 72 73 74 75 76 77 78 79 80 81 82
	{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 */
83
	{USB_DEVICE(0x0586, 0x341a)},	/* Zyxel NWD-270N */
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
	{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 */
100 101
	{USB_DEVICE(0x04E8, 0x2018)},	/* samsung linkstick2 */
	{USB_DEVICE(0x1690, 0x0740)},	/* Askey */
102 103 104 105
	{USB_DEVICE(0x5A57, 0x0280)},	/* Zinwell */
	{USB_DEVICE(0x5A57, 0x0282)},	/* Zinwell */
	{USB_DEVICE(0x7392, 0x7718)},
	{USB_DEVICE(0x7392, 0x7717)},
106
	{USB_DEVICE(0x0411, 0x016f)},	/* MelCo.,Inc. WLI-UC-G301N */
107 108 109 110
	{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 */
111
	{USB_DEVICE(0x100D, 0x9031)},	/* Motorola 2770 */
112
#endif /* RT2870 // */
113
#ifdef RT3070
114 115 116 117
	{USB_DEVICE(0x148F, 0x3070)},	/* Ralink 3070 */
	{USB_DEVICE(0x148F, 0x3071)},	/* Ralink 3071 */
	{USB_DEVICE(0x148F, 0x3072)},	/* Ralink 3072 */
	{USB_DEVICE(0x0DB0, 0x3820)},	/* Ralink 3070 */
118 119 120 121
	{USB_DEVICE(0x0DB0, 0x871C)},	/* Ralink 3070 */
	{USB_DEVICE(0x0DB0, 0x822C)},	/* Ralink 3070 */
	{USB_DEVICE(0x0DB0, 0x871B)},	/* Ralink 3070 */
	{USB_DEVICE(0x0DB0, 0x822B)},	/* Ralink 3070 */
122 123
	{USB_DEVICE(0x0DF6, 0x003E)},	/* Sitecom 3070 */
	{USB_DEVICE(0x0DF6, 0x0042)},	/* Sitecom 3072 */
124 125
	{USB_DEVICE(0x0DF6, 0x0048)},	/* Sitecom 3070 */
	{USB_DEVICE(0x0DF6, 0x0047)},	/* Sitecom 3071 */
126 127 128
	{USB_DEVICE(0x14B2, 0x3C12)},	/* AL 3070 */
	{USB_DEVICE(0x18C5, 0x0012)},	/* Corega 3070 */
	{USB_DEVICE(0x083A, 0x7511)},	/* Arcadyan 3070 */
129 130
	{USB_DEVICE(0x083A, 0xA701)},	/* SMC 3070 */
	{USB_DEVICE(0x083A, 0xA702)},	/* SMC 3072 */
131 132 133
	{USB_DEVICE(0x1740, 0x9703)},	/* EnGenius 3070 */
	{USB_DEVICE(0x1740, 0x9705)},	/* EnGenius 3071 */
	{USB_DEVICE(0x1740, 0x9706)},	/* EnGenius 3072 */
134 135 136
	{USB_DEVICE(0x1740, 0x9707)},	/* EnGenius 3070 */
	{USB_DEVICE(0x1740, 0x9708)},	/* EnGenius 3071 */
	{USB_DEVICE(0x1740, 0x9709)},	/* EnGenius 3072 */
137
	{USB_DEVICE(0x13D3, 0x3273)},	/* AzureWave 3070 */
138
	{USB_DEVICE(0x13D3, 0x3305)},	/* AzureWave 3070*/
139 140 141 142 143 144 145 146 147 148 149 150
	{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 */
151 152
	{USB_DEVICE(0x07D1, 0x3C16)},	/* D-Link 3070 */
	{USB_DEVICE(0x07D1, 0x3C17)},	/* D-Link 8070 */
153 154 155 156 157
	{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 */
158 159
	{USB_DEVICE(0x04BB, 0x0947)},	/* I-O DATA 3070 */
	{USB_DEVICE(0x04BB, 0x0948)},	/* I-O DATA 3072 */
160
	{USB_DEVICE(0x203D, 0x1480)},	/* Encore 3070 */
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
	{USB_DEVICE(0x20B8, 0x8888)},	/* PARA INDUSTRIAL 3070 */
	{USB_DEVICE(0x0B05, 0x1784)},	/* Asus 3072 */
	{USB_DEVICE(0x203D, 0x14A9)},	/* Encore 3070*/
	{USB_DEVICE(0x0DB0, 0x899A)},	/* MSI 3070*/
	{USB_DEVICE(0x0DB0, 0x3870)},	/* MSI 3070*/
	{USB_DEVICE(0x0DB0, 0x870A)},	/* MSI 3070*/
	{USB_DEVICE(0x0DB0, 0x6899)},	/* MSI 3070 */
	{USB_DEVICE(0x0DB0, 0x3822)},	/* MSI 3070 */
	{USB_DEVICE(0x0DB0, 0x3871)},	/* MSI 3070 */
	{USB_DEVICE(0x0DB0, 0x871A)},	/* MSI 3070 */
	{USB_DEVICE(0x0DB0, 0x822A)},	/* MSI 3070 */
	{USB_DEVICE(0x0DB0, 0x3821)},	/* Ralink 3070 */
	{USB_DEVICE(0x0DB0, 0x821A)},	/* Ralink 3070 */
	{USB_DEVICE(0x083A, 0xA703)},	/* IO-MAGIC */
	{USB_DEVICE(0x13D3, 0x3307)},	/* Azurewave */
	{USB_DEVICE(0x13D3, 0x3321)},	/* Azurewave */
	{USB_DEVICE(0x07FA, 0x7712)},	/* Edimax */
	{USB_DEVICE(0x0789, 0x0166)},	/* Edimax */
	{USB_DEVICE(0x148F, 0x2070)},	/* Edimax */
180
#endif /* RT3070 // */
181 182 183 184 185
	{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 */
186 187
};

188
int const rtusb_usb_id_len =
189
    sizeof(rtusb_usb_id) / sizeof(struct usb_device_id);
190 191 192

MODULE_DEVICE_TABLE(usb, rtusb_usb_id);

193
static void rt2870_disconnect(struct usb_device *dev, struct rt_rtmp_adapter *pAd);
194

195 196 197
static int __devinit rt2870_probe(IN struct usb_interface *intf,
				  IN struct usb_device *usb_dev,
				  IN const struct usb_device_id *dev_id,
198
				  struct rt_rtmp_adapter **ppAd);
199 200 201 202 203 204 205 206

#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);

207 208
static BOOLEAN USBDevConfigInit(IN struct usb_device *dev,
				IN struct usb_interface *intf,
209
				struct rt_rtmp_adapter *pAd);
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225

/*
========================================================================
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:
========================================================================
*/
226
BOOLEAN RT28XXChipsetCheck(IN void *_dev_p)
227 228 229
{
	struct usb_interface *intf = (struct usb_interface *)_dev_p;
	struct usb_device *dev_p = interface_to_usbdev(intf);
230
	u32 i;
231

232
	for (i = 0; i < rtusb_usb_id_len; i++) {
233
		if (dev_p->descriptor.idVendor == rtusb_usb_id[i].idVendor &&
234
		    dev_p->descriptor.idProduct == rtusb_usb_id[i].idProduct) {
235
			printk("rt2870: idVendor = 0x%x, idProduct = 0x%x\n",
236 237
			       dev_p->descriptor.idVendor,
			       dev_p->descriptor.idProduct);
238 239 240 241
			break;
		}
	}

242
	if (i == rtusb_usb_id_len) {
243 244 245 246 247 248 249 250 251
		printk("rt2870: Error! Device Descriptor not matching!\n");
		return FALSE;
	}

	return TRUE;
}

/**************************************************************************/
/**************************************************************************/
252
/*tested for kernel 2.6series */
253 254 255 256 257 258
/**************************************************************************/
/**************************************************************************/

#ifdef CONFIG_PM
static int rt2870_suspend(struct usb_interface *intf, pm_message_t state);
static int rt2870_resume(struct usb_interface *intf);
259
#endif /* CONFIG_PM // */
260

261 262
static BOOLEAN USBDevConfigInit(IN struct usb_device *dev,
				IN struct usb_interface *intf,
263
				struct rt_rtmp_adapter *pAd)
264 265
{
	struct usb_host_interface *iface_desc;
266 267
	unsigned long BulkOutIdx;
	u32 i;
268 269 270 271 272 273

	/* get the active interface descriptor */
	iface_desc = intf->cur_altsetting;

	/* get # of enpoints  */
	pAd->NumberOfPipes = iface_desc->desc.bNumEndpoints;
274 275
	DBGPRINT(RT_DEBUG_TRACE,
		 ("NumEndpoints=%d\n", iface_desc->desc.bNumEndpoints));
276 277 278 279

	/* Configure Pipes */
	BulkOutIdx = 0;

280
	for (i = 0; i < pAd->NumberOfPipes; i++) {
281
		if ((iface_desc->endpoint[i].desc.bmAttributes ==
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304
		     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)) {
305 306
			/* there are 6 bulk out EP. EP6 highest priority. */
			/* EP1-4 is EDCA.  EP5 is HCCA. */
307 308 309 310 311 312 313 314 315 316 317 318 319
			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));
320 321 322
		}
	}

323 324 325 326
	if (!(pAd->BulkInEpAddr && pAd->BulkOutEpAddr[0])) {
		printk
		    ("%s: Could not find both bulk-in and bulk-out endpoints\n",
		     __FUNCTION__);
327 328 329 330 331 332 333 334 335 336
		return FALSE;
	}

	pAd->config = &dev->config->desc;
	usb_set_intfdata(intf, pAd);

	return TRUE;

}

337
static int __devinit rtusb_probe(struct usb_interface *intf,
338
		       const struct usb_device_id *id)
339
{
340
	struct rt_rtmp_adapter *pAd;
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355
	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)
{
356
	struct usb_device *dev = interface_to_usbdev(intf);
357
	struct rt_rtmp_adapter *pAd;
358 359 360 361 362 363 364 365

	pAd = usb_get_intfdata(intf);
	usb_set_intfdata(intf, NULL);

	rt2870_disconnect(dev, pAd);
}

struct usb_driver rtusb_driver = {
366 367 368 369
	.name = "rt2870",
	.probe = rtusb_probe,
	.disconnect = rtusb_disconnect,
	.id_table = rtusb_usb_id,
370 371

#ifdef CONFIG_PM
372 373
suspend:rt2870_suspend,
resume:rt2870_resume,
374
#endif
375
};
376 377 378

#ifdef CONFIG_PM

379
void RT2870RejectPendingPackets(struct rt_rtmp_adapter *pAd)
380
{
381 382
	/* clear PS packets */
	/* clear TxSw packets */
383 384
}

385
static int rt2870_suspend(struct usb_interface *intf, pm_message_t state)
386 387
{
	struct net_device *net_dev;
388
	struct rt_rtmp_adapter *pAd = usb_get_intfdata(intf);
389 390 391 392 393 394 395 396 397 398 399 400 401 402

	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;
}

403
static int rt2870_resume(struct usb_interface *intf)
404 405
{
	struct net_device *net_dev;
406
	struct rt_rtmp_adapter *pAd = usb_get_intfdata(intf);
407 408 409 410 411 412 413 414 415 416 417 418 419

	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;
}
420
#endif /* CONFIG_PM // */
421

422
/* Init driver module */
423
int __init rtusb_init(void)
424 425 426 427 428
{
	printk("rtusb init --->\n");
	return usb_register(&rtusb_driver);
}

429
/* Deinit driver module */
430
void __exit rtusb_exit(void)
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456
{
	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:
========================================================================
*/
457
int MlmeThread(IN void *Context)
458
{
459 460
	struct rt_rtmp_adapter *pAd;
	struct rt_rtmp_os_task *pTask;
461 462 463
	int status;
	status = 0;

464 465
	pTask = Context;
	pAd = pTask->priv;
466 467 468

	RtmpOSTaskCustomize(pTask);

469
	while (!pTask->task_killed) {
470 471 472 473 474 475
#ifdef KTHREAD_SUPPORT
		RTMP_WAIT_EVENT_INTERRUPTIBLE(pAd, pTask);
#else
		RTMP_SEM_EVENT_WAIT(&(pTask->taskSema), status);

		/* unlock the device pointers */
476
		if (status != 0) {
477 478 479 480 481
			RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS);
			break;
		}
#endif

482
		/* lock the device pointers , need to check if required */
483
		/*down(&(pAd->usbdev_semaphore)); */
484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502

		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().
	 */
503
	DBGPRINT(RT_DEBUG_TRACE, ("<---%s\n", __FUNCTION__));
504 505
#ifndef KTHREAD_SUPPORT
	pTask->taskPID = THREAD_PID_INIT_VALUE;
506
	complete_and_exit(&pTask->taskComplete, 0);
507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525
#endif
	return 0;

}

/*
========================================================================
Routine Description:
    USB command kernel thread.

Arguments:
	*Context			the pAd, driver control block pointer

Return Value:
    0					close the thread

Note:
========================================================================
*/
526
int RTUSBCmdThread(IN void *Context)
527
{
528 529
	struct rt_rtmp_adapter *pAd;
	struct rt_rtmp_os_task *pTask;
530 531 532
	int status;
	status = 0;

533 534
	pTask = Context;
	pAd = pTask->priv;
535 536 537 538 539 540 541

	RtmpOSTaskCustomize(pTask);

	NdisAcquireSpinLock(&pAd->CmdQLock);
	pAd->CmdQ.CmdQState = RTMP_TASK_STAT_RUNNING;
	NdisReleaseSpinLock(&pAd->CmdQLock);

542
	while (pAd && pAd->CmdQ.CmdQState == RTMP_TASK_STAT_RUNNING) {
543 544 545 546 547 548
#ifdef KTHREAD_SUPPORT
		RTMP_WAIT_EVENT_INTERRUPTIBLE(pAd, pTask);
#else
		/* lock the device pointers */
		RTMP_SEM_EVENT_WAIT(&(pTask->taskSema), status);

549
		if (status != 0) {
550 551 552 553 554 555 556 557 558 559 560 561
			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);
	}

562
	if (pAd && !pAd->PM_FlgSuspend) {	/* Clear the CmdQElements. */
563
		struct rt_cmdqelmt *pCmdQElmt = NULL;
564 565 566

		NdisAcquireSpinLock(&pAd->CmdQLock);
		pAd->CmdQ.CmdQState = RTMP_TASK_STAT_STOPED;
567
		while (pAd->CmdQ.size) {
568
			RTUSBDequeueCmd(&pAd->CmdQ, &pCmdQElmt);
569 570
			if (pCmdQElmt) {
				if (pCmdQElmt->CmdFromNdis == TRUE) {
571
					if (pCmdQElmt->buffer != NULL)
572 573
						os_free_mem(pAd,
							    pCmdQElmt->buffer);
574
					os_free_mem(pAd, (u8 *)pCmdQElmt);
575 576 577 578 579
				} else {
					if ((pCmdQElmt->buffer != NULL)
					    && (pCmdQElmt->bufferlength != 0))
						os_free_mem(pAd,
							    pCmdQElmt->buffer);
580
					os_free_mem(pAd, (u8 *)pCmdQElmt);
581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600
				}
			}
		}

		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().
	 */
601
	DBGPRINT(RT_DEBUG_TRACE, ("<---RTUSBCmdThread\n"));
602 603 604

#ifndef KTHREAD_SUPPORT
	pTask->taskPID = THREAD_PID_INIT_VALUE;
605
	complete_and_exit(&pTask->taskComplete, 0);
606 607 608 609 610
#endif
	return 0;

}

611
void RTUSBWatchDog(struct rt_rtmp_adapter *pAd)
612
{
613
	struct rt_ht_tx_context *pHTTXContext;
614
	int idx;
615
	unsigned long irqFlags;
616 617
	PURB pUrb;
	BOOLEAN needDumpSeq = FALSE;
618 619
	u32 MACValue;
	u32 TxRxQ_Pcnt;
620 621 622

	idx = 0;
	RTMP_IO_READ32(pAd, TXRXQ_PCNT, &MACValue);
623 624
	if ((MACValue & 0xff) != 0) {
		DBGPRINT(RT_DEBUG_TRACE,
625
			 ("TX QUEUE 0 Not EMPTY(Value=0x%0x)!\n",
626
			  MACValue));
627
		RTMP_IO_WRITE32(pAd, PBF_CFG, 0xf40012);
628 629 630
		while ((MACValue & 0xff) != 0 && (idx++ < 10)) {
			RTMP_IO_READ32(pAd, TXRXQ_PCNT, &MACValue);
			RTMPusecDelay(1);
631 632 633 634
		}
		RTMP_IO_WRITE32(pAd, PBF_CFG, 0xf40006);
	}

635 636 637 638 639 640 641 642 643 644 645
	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"));
646
			RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKIN_RESET);
647 648
			RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_IN,
						NULL, 0);
649 650 651 652 653 654 655
			needDumpSeq = TRUE;
		}
		pAd->watchDogRxOverFlowCnt = 0;
	}

	RTUSBReadMACRegister(pAd, 0x438, &TxRxQ_Pcnt);

656
	for (idx = 0; idx < NUM_OF_TX_RING; idx++) {
657 658 659
		pUrb = NULL;

		RTMP_IRQ_LOCK(&pAd->BulkOutLock[idx], irqFlags);
660 661
		if ((pAd->BulkOutPending[idx] == TRUE)
		    && pAd->watchDogTxPendingCnt) {
662
			int actual_length = 0, transfer_buffer_length = 0;
663
			BOOLEAN isDataPacket = FALSE;
664 665 666
			pAd->watchDogTxPendingCnt[idx]++;

			if ((pAd->watchDogTxPendingCnt[idx] > 2) &&
667 668 669 670 671 672 673
			    (!RTMP_TEST_FLAG
			     (pAd,
			      (fRTMP_ADAPTER_RESET_IN_PROGRESS |
			       fRTMP_ADAPTER_HALT_IN_PROGRESS |
			       fRTMP_ADAPTER_NIC_NOT_EXIST |
			       fRTMP_ADAPTER_BULKOUT_RESET)))
			    ) {
674
				/* FIXME: Following code just support single bulk out. If you wanna support multiple bulk out. Modify it! */
675
				pHTTXContext =
676
				    (struct rt_ht_tx_context *)(&pAd->TxContext[idx]);
677
				if (pHTTXContext->IRPPending) {	/* Check TxContext. */
678 679
					pUrb = pHTTXContext->pUrb;

680 681 682 683 684
					actual_length = pUrb->actual_length;
					transfer_buffer_length =
					    pUrb->transfer_buffer_length;
					isDataPacket = TRUE;
				} else if (idx == MGMTPIPEIDX) {
685 686
					struct rt_tx_context *pMLMEContext, *pNULLContext,
					    *pPsPollContext;
687

688
					/*Check MgmtContext. */
689
					pMLMEContext =
690
					    (struct rt_tx_context *)(pAd->MgmtRing.
691 692 693 694
							   Cell[pAd->MgmtRing.
								TxDmaIdx].
							   AllocVa);
					pPsPollContext =
695
					    (struct rt_tx_context *)(&pAd->PsPollContext);
696
					pNULLContext =
697
					    (struct rt_tx_context *)(&pAd->NullContext);
698 699 700 701

					if (pMLMEContext->IRPPending) {
						ASSERT(pMLMEContext->
						       IRPPending);
702
						pUrb = pMLMEContext->pUrb;
703 704 705
					} else if (pNULLContext->IRPPending) {
						ASSERT(pNULLContext->
						       IRPPending);
706
						pUrb = pNULLContext->pUrb;
707 708 709
					} else if (pPsPollContext->IRPPending) {
						ASSERT(pPsPollContext->
						       IRPPending);
710 711 712 713
						pUrb = pPsPollContext->pUrb;
					}
				}

714 715
				RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[idx],
						irqFlags);
716

717 718 719 720
				printk(KERN_INFO "%d:%lu LTL=%d , TL=%d L:%d\n",
				       idx, pAd->watchDogTxPendingCnt[idx],
				       pAd->TransferedLength[idx],
				       actual_length, transfer_buffer_length);
721

722
				if (pUrb) {
723
					if ((isDataPacket
724 725 726 727 728
					     && pAd->TransferedLength[idx] ==
					     actual_length
					     && pAd->TransferedLength[idx] <
					     transfer_buffer_length
					     && actual_length != 0
729
/*                                      && TxRxQ_Pcnt==0 */
730 731 732 733 734 735 736 737 738 739
					     && 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"));
740
						/* unlink it now */
741
						RTUSB_UNLINK_URB(pUrb);
742 743
						/* Sleep 200 microseconds to give cancellation time to work */
						/*RTMPusecDelay(200); */
744
						needDumpSeq = TRUE;
745
					}
746 747
				} else {
					DBGPRINT(RT_DEBUG_ERROR,
748
						 ("Unknown bulkOut URB maybe hanged!\n"));
749
				}
750 751 752
			} else {
				RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[idx],
						irqFlags);
753 754
			}

755 756 757
			if (isDataPacket == TRUE)
				pAd->TransferedLength[idx] = actual_length;
		} else {
758 759 760 761
			RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[idx], irqFlags);
		}
	}

762
	/* For Sigma debug, dump the ba_reordering sequence. */
763
	if ((needDumpSeq == TRUE) && (pAd->CommonCfg.bDisableReordering == 0)) {
764
		u16 Idx;
765
		struct rt_ba_rec_entry *pBAEntry = NULL;
766
		u8 count = 0;
767 768 769 770 771
		struct reordering_mpdu *mpdu_blk;

		Idx = pAd->MacTab.Content[BSSID_WCID].BARecWcidArray[0];

		pBAEntry = &pAd->BATable.BARecEntry[Idx];
772 773 774
		if ((pBAEntry->list.qlen > 0) && (pBAEntry->list.next != NULL)) {
			DBGPRINT(RT_DEBUG_TRACE,
				 ("NICUpdateRawCounters():The Queueing pkt in reordering buffer:\n"));
775 776
			NdisAcquireSpinLock(&pBAEntry->RxReRingLock);
			mpdu_blk = pBAEntry->list.next;
777 778 779 780 781
			while (mpdu_blk) {
				DBGPRINT(RT_DEBUG_TRACE,
					 ("\t%d:Seq-%d, bAMSDU-%d!\n", count,
					  mpdu_blk->Sequence,
					  mpdu_blk->bAMSDU));
782 783 784 785
				mpdu_blk = mpdu_blk->next;
				count++;
			}

786 787 788
			DBGPRINT(RT_DEBUG_TRACE,
				 ("\npBAEntry->LastIndSeq=%d!\n",
				  pBAEntry->LastIndSeq));
789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808
			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:
========================================================================
*/
809
static void rt2870_disconnect(struct usb_device *dev, struct rt_rtmp_adapter *pAd)
810
{
811 812 813 814
	DBGPRINT(RT_DEBUG_ERROR,
		 ("rtusb_disconnect: unregister usbnet usb-%s-%s\n",
		  dev->bus->bus_name, dev->devpath));
	if (!pAd) {
815 816 817 818 819 820
		usb_put_dev(dev);
		printk("rtusb_disconnect: pAd == NULL!\n");
		return;
	}
	RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST);

821
	/* for debug, wait to show some messages to /proc system */
822 823 824 825
	udelay(1);

	RtmpPhyNetDevExit(pAd, pAd->net_dev);

826
	/* FIXME: Shall we need following delay and flush the schedule?? */
827 828 829 830
	udelay(1);
	flush_scheduled_work();
	udelay(1);

831
	/* free the root net_device */
832 833 834 835
	RtmpOSNetDevFree(pAd->net_dev);

	RtmpRaDevCtrlExit(pAd);

836
	/* release a use of the usb device structure */
837 838 839 840 841 842
	usb_put_dev(dev);
	udelay(1);

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

843 844 845
static int __devinit rt2870_probe(IN struct usb_interface *intf,
				  IN struct usb_device *usb_dev,
				  IN const struct usb_device_id *dev_id,
846
				  struct rt_rtmp_adapter **ppAd)
847
{
848
	struct net_device *net_dev = NULL;
849
	struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)NULL;
850 851
	int status, rv;
	void *handle;
852
	struct rt_rtmp_os_netdev_op_hook netDevHook;
853 854 855

	DBGPRINT(RT_DEBUG_TRACE, ("===>rt2870_probe()!\n"));

856 857 858
	/* Check chipset vendor/product ID */
	/*if (RT28XXChipsetCheck(_dev_p) == FALSE) */
	/*      goto err_out; */
859

860
/*RtmpDevInit============================================= */
861
	/* Allocate struct rt_rtmp_adapter adapter structure */
862
	handle = kmalloc(sizeof(struct os_cookie), GFP_KERNEL);
863 864 865
	if (handle == NULL) {
		printk
		    ("rt2870_probe(): Allocate memory for os handle failed!\n");
866 867
		return -ENOMEM;
	}
868
	((struct os_cookie *)handle)->pUsb_Dev = usb_dev;
869 870

	rv = RTMPAllocAdapterBlock(handle, &pAd);
871
	if (rv != NDIS_STATUS_SUCCESS) {
872 873 874
		kfree(handle);
		goto err_out;
	}
875
/*USBDevInit============================================== */
876 877 878 879 880
	if (USBDevConfigInit(usb_dev, intf, pAd) == FALSE)
		goto err_out_free_radev;

	RtmpRaDevCtrlInit(pAd, RTMP_DEV_INF_USB);

881
/*NetDevInit============================================== */
882 883 884 885
	net_dev = RtmpPhyNetDevInit(pAd, &netDevHook);
	if (net_dev == NULL)
		goto err_out_free_radev;

886
	/* Here are the net_device structure with usb specific parameters. */
887
	/* for supporting Network Manager.
888 889
	 * Set the sysfs physical device reference for the network logical device if set prior to registration will
	 * cause a symlink during initialization.
890 891 892
	 */
	SET_NETDEV_DEV(net_dev, &(usb_dev->dev));

893
	pAd->StaCfg.OriDevType = net_dev->type;
894

895 896
/*All done, it's time to register the net device to linux kernel. */
	/* Register this device */
897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925
	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;

}