12865d42cSLarry Finger /****************************************************************************** 22865d42cSLarry Finger * usb_intf.c 32865d42cSLarry Finger * 42865d42cSLarry Finger * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. 52865d42cSLarry Finger * Linux device driver for RTL8192SU 62865d42cSLarry Finger * 72865d42cSLarry Finger * This program is free software; you can redistribute it and/or modify it 82865d42cSLarry Finger * under the terms of version 2 of the GNU General Public License as 92865d42cSLarry Finger * published by the Free Software Foundation. 102865d42cSLarry Finger * 112865d42cSLarry Finger * This program is distributed in the hope that it will be useful, but WITHOUT 122865d42cSLarry Finger * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 132865d42cSLarry Finger * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 142865d42cSLarry Finger * more details. 152865d42cSLarry Finger * 162865d42cSLarry Finger * You should have received a copy of the GNU General Public License along with 172865d42cSLarry Finger * this program; if not, write to the Free Software Foundation, Inc., 182865d42cSLarry Finger * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA 192865d42cSLarry Finger * 202865d42cSLarry Finger * Modifications for inclusion into the Linux staging tree are 212865d42cSLarry Finger * Copyright(c) 2010 Larry Finger. All rights reserved. 222865d42cSLarry Finger * 232865d42cSLarry Finger * Contact information: 242865d42cSLarry Finger * WLAN FAE <wlanfae@realtek.com> 252865d42cSLarry Finger * Larry Finger <Larry.Finger@lwfinger.net> 262865d42cSLarry Finger * 272865d42cSLarry Finger ******************************************************************************/ 282865d42cSLarry Finger 292865d42cSLarry Finger #define _HCI_INTF_C_ 302865d42cSLarry Finger 31359140aaSAli Bahar #include <linux/usb.h> 3281e07c06SStephen Rothwell #include <linux/module.h> 332080913eSLarry Finger #include <linux/firmware.h> 34359140aaSAli Bahar 352865d42cSLarry Finger #include "osdep_service.h" 362865d42cSLarry Finger #include "drv_types.h" 372865d42cSLarry Finger #include "recv_osdep.h" 382865d42cSLarry Finger #include "xmit_osdep.h" 392865d42cSLarry Finger #include "rtl8712_efuse.h" 402865d42cSLarry Finger #include "usb_vendor_req.h" 412865d42cSLarry Finger #include "usb_ops.h" 422865d42cSLarry Finger #include "usb_osintf.h" 432865d42cSLarry Finger 445a3acb04SLarry Finger #define DRVER "v7_0.20100831" 452865d42cSLarry Finger 462865d42cSLarry Finger static struct usb_interface *pintf; 472865d42cSLarry Finger 482865d42cSLarry Finger static int r871xu_drv_init(struct usb_interface *pusb_intf, 492865d42cSLarry Finger const struct usb_device_id *pdid); 502865d42cSLarry Finger 512865d42cSLarry Finger static void r871xu_dev_remove(struct usb_interface *pusb_intf); 522865d42cSLarry Finger 532865d42cSLarry Finger static struct usb_device_id rtl871x_usb_id_tbl[] = { 546b284053SAxel Köllhofer 556b284053SAxel Köllhofer /* RTL8188SU */ 566b284053SAxel Köllhofer /* Realtek */ 576b284053SAxel Köllhofer {USB_DEVICE(0x0BDA, 0x8171)}, 582865d42cSLarry Finger {USB_DEVICE(0x0bda, 0x8173)}, 592865d42cSLarry Finger {USB_DEVICE(0x0bda, 0x8712)}, 602865d42cSLarry Finger {USB_DEVICE(0x0bda, 0x8713)}, 612865d42cSLarry Finger {USB_DEVICE(0x0bda, 0xC512)}, 622865d42cSLarry Finger /* Abocom */ 632865d42cSLarry Finger {USB_DEVICE(0x07B8, 0x8188)}, 646b284053SAxel Köllhofer /* ASUS */ 656b284053SAxel Köllhofer {USB_DEVICE(0x0B05, 0x1786)}, 666b284053SAxel Köllhofer {USB_DEVICE(0x0B05, 0x1791)}, /* 11n mode disable */ 672865d42cSLarry Finger /* Belkin */ 686b284053SAxel Köllhofer {USB_DEVICE(0x050D, 0x945A)}, 696b284053SAxel Köllhofer /* Corega */ 706b284053SAxel Köllhofer {USB_DEVICE(0x07AA, 0x0047)}, 716b284053SAxel Köllhofer /* D-Link */ 726b284053SAxel Köllhofer {USB_DEVICE(0x2001, 0x3306)}, 736b284053SAxel Köllhofer {USB_DEVICE(0x07D1, 0x3306)}, /* 11n mode disable */ 742865d42cSLarry Finger /* Edimax */ 752865d42cSLarry Finger {USB_DEVICE(0x7392, 0x7611)}, 766b284053SAxel Köllhofer /* EnGenius */ 776b284053SAxel Köllhofer {USB_DEVICE(0x1740, 0x9603)}, 786b284053SAxel Köllhofer /* Hawking */ 796b284053SAxel Köllhofer {USB_DEVICE(0x0E66, 0x0016)}, 806b284053SAxel Köllhofer /* Hercules */ 816b284053SAxel Köllhofer {USB_DEVICE(0x06F8, 0xE034)}, 826b284053SAxel Köllhofer {USB_DEVICE(0x06F8, 0xE032)}, 836b284053SAxel Köllhofer /* Logitec */ 846b284053SAxel Köllhofer {USB_DEVICE(0x0789, 0x0167)}, 856b284053SAxel Köllhofer /* PCI */ 866b284053SAxel Köllhofer {USB_DEVICE(0x2019, 0xAB28)}, 876b284053SAxel Köllhofer {USB_DEVICE(0x2019, 0xED16)}, 882865d42cSLarry Finger /* Sitecom */ 896b284053SAxel Köllhofer {USB_DEVICE(0x0DF6, 0x0057)}, 902865d42cSLarry Finger {USB_DEVICE(0x0DF6, 0x0045)}, 916b284053SAxel Köllhofer {USB_DEVICE(0x0DF6, 0x0059)}, /* 11n mode disable */ 926b284053SAxel Köllhofer {USB_DEVICE(0x0DF6, 0x004B)}, 931793bf1dSLarry Finger {USB_DEVICE(0x0DF6, 0x005B)}, 94c7caf4d4SLarry Finger {USB_DEVICE(0x0DF6, 0x005D)}, 956b284053SAxel Köllhofer {USB_DEVICE(0x0DF6, 0x0063)}, 966b284053SAxel Köllhofer /* Sweex */ 976b284053SAxel Köllhofer {USB_DEVICE(0x177F, 0x0154)}, 986b284053SAxel Köllhofer /* Thinkware */ 996b284053SAxel Köllhofer {USB_DEVICE(0x0BDA, 0x5077)}, 1006b284053SAxel Köllhofer /* Toshiba */ 1016b284053SAxel Köllhofer {USB_DEVICE(0x1690, 0x0752)}, 1026b284053SAxel Köllhofer /* - */ 1036b284053SAxel Köllhofer {USB_DEVICE(0x20F4, 0x646B)}, 1046b284053SAxel Köllhofer {USB_DEVICE(0x083A, 0xC512)}, 1056b284053SAxel Köllhofer 1066b284053SAxel Köllhofer /* RTL8191SU */ 1076b284053SAxel Köllhofer /* Realtek */ 1086b284053SAxel Köllhofer {USB_DEVICE(0x0BDA, 0x8172)}, 1096b284053SAxel Köllhofer /* Amigo */ 1106b284053SAxel Köllhofer {USB_DEVICE(0x0EB0, 0x9061)}, 1116b284053SAxel Köllhofer /* ASUS/EKB */ 1126b284053SAxel Köllhofer {USB_DEVICE(0x0BDA, 0x8172)}, 1136b284053SAxel Köllhofer {USB_DEVICE(0x13D3, 0x3323)}, 1146b284053SAxel Köllhofer {USB_DEVICE(0x13D3, 0x3311)}, /* 11n mode disable */ 1156b284053SAxel Köllhofer {USB_DEVICE(0x13D3, 0x3342)}, 1166b284053SAxel Köllhofer /* ASUS/EKBLenovo */ 1176b284053SAxel Köllhofer {USB_DEVICE(0x13D3, 0x3333)}, 1186b284053SAxel Köllhofer {USB_DEVICE(0x13D3, 0x3334)}, 1196b284053SAxel Köllhofer {USB_DEVICE(0x13D3, 0x3335)}, /* 11n mode disable */ 1206b284053SAxel Köllhofer {USB_DEVICE(0x13D3, 0x3336)}, /* 11n mode disable */ 1216b284053SAxel Köllhofer /* ASUS/Media BOX */ 1226b284053SAxel Köllhofer {USB_DEVICE(0x13D3, 0x3309)}, 1236b284053SAxel Köllhofer /* Belkin */ 1246b284053SAxel Köllhofer {USB_DEVICE(0x050D, 0x815F)}, 1256b284053SAxel Köllhofer /* D-Link */ 1266b284053SAxel Köllhofer {USB_DEVICE(0x07D1, 0x3302)}, 1276b284053SAxel Köllhofer {USB_DEVICE(0x07D1, 0x3300)}, 1286b284053SAxel Köllhofer {USB_DEVICE(0x07D1, 0x3303)}, 1296b284053SAxel Köllhofer /* Edimax */ 1306b284053SAxel Köllhofer {USB_DEVICE(0x7392, 0x7612)}, 1316b284053SAxel Köllhofer /* EnGenius */ 1326b284053SAxel Köllhofer {USB_DEVICE(0x1740, 0x9605)}, 1336b284053SAxel Köllhofer /* Guillemot */ 1346b284053SAxel Köllhofer {USB_DEVICE(0x06F8, 0xE031)}, 1352865d42cSLarry Finger /* Hawking */ 1362865d42cSLarry Finger {USB_DEVICE(0x0E66, 0x0015)}, 1376b284053SAxel Köllhofer /* Mediao */ 1382865d42cSLarry Finger {USB_DEVICE(0x13D3, 0x3306)}, 1396b284053SAxel Köllhofer /* PCI */ 1406b284053SAxel Köllhofer {USB_DEVICE(0x2019, 0xED18)}, 1416b284053SAxel Köllhofer {USB_DEVICE(0x2019, 0x4901)}, 1426b284053SAxel Köllhofer /* Sitecom */ 1436b284053SAxel Köllhofer {USB_DEVICE(0x0DF6, 0x0058)}, 1446b284053SAxel Köllhofer {USB_DEVICE(0x0DF6, 0x0049)}, 1456b284053SAxel Köllhofer {USB_DEVICE(0x0DF6, 0x004C)}, 1466b284053SAxel Köllhofer {USB_DEVICE(0x0DF6, 0x0064)}, 1476b284053SAxel Köllhofer /* Skyworth */ 1486b284053SAxel Köllhofer {USB_DEVICE(0x14b2, 0x3300)}, 1496b284053SAxel Köllhofer {USB_DEVICE(0x14b2, 0x3301)}, 1506b284053SAxel Köllhofer {USB_DEVICE(0x14B2, 0x3302)}, 1516b284053SAxel Köllhofer /* - */ 1526b284053SAxel Köllhofer {USB_DEVICE(0x04F2, 0xAFF2)}, 1536b284053SAxel Köllhofer {USB_DEVICE(0x04F2, 0xAFF5)}, 1546b284053SAxel Köllhofer {USB_DEVICE(0x04F2, 0xAFF6)}, 1556b284053SAxel Köllhofer {USB_DEVICE(0x13D3, 0x3339)}, 1566b284053SAxel Köllhofer {USB_DEVICE(0x13D3, 0x3340)}, /* 11n mode disable */ 1576b284053SAxel Köllhofer {USB_DEVICE(0x13D3, 0x3341)}, /* 11n mode disable */ 1582865d42cSLarry Finger {USB_DEVICE(0x13D3, 0x3310)}, 1592865d42cSLarry Finger {USB_DEVICE(0x13D3, 0x3325)}, 1606b284053SAxel Köllhofer 1616b284053SAxel Köllhofer /* RTL8192SU */ 1626b284053SAxel Köllhofer /* Realtek */ 1636b284053SAxel Köllhofer {USB_DEVICE(0x0BDA, 0x8174)}, 1646b284053SAxel Köllhofer {USB_DEVICE(0x0BDA, 0x8174)}, 1656b284053SAxel Köllhofer /* Belkin */ 1666b284053SAxel Köllhofer {USB_DEVICE(0x050D, 0x845A)}, 1676b284053SAxel Köllhofer /* Corega */ 1686b284053SAxel Köllhofer {USB_DEVICE(0x07AA, 0x0051)}, 1696b284053SAxel Köllhofer /* Edimax */ 1706b284053SAxel Köllhofer {USB_DEVICE(0x7392, 0x7622)}, 1716b284053SAxel Köllhofer /* NEC */ 1726b284053SAxel Köllhofer {USB_DEVICE(0x0409, 0x02B6)}, 1732865d42cSLarry Finger {} 1742865d42cSLarry Finger }; 1752865d42cSLarry Finger 1762865d42cSLarry Finger MODULE_DEVICE_TABLE(usb, rtl871x_usb_id_tbl); 1772865d42cSLarry Finger 1782865d42cSLarry Finger static struct specific_device_id specific_device_id_tbl[] = { 1792865d42cSLarry Finger {.idVendor = 0x0b05, .idProduct = 0x1791, 1802865d42cSLarry Finger .flags = SPEC_DEV_ID_DISABLE_HT}, 1816b284053SAxel Köllhofer {.idVendor = 0x0df6, .idProduct = 0x0059, 1826b284053SAxel Köllhofer .flags = SPEC_DEV_ID_DISABLE_HT}, 1836b284053SAxel Köllhofer {.idVendor = 0x13d3, .idProduct = 0x3306, 1846b284053SAxel Köllhofer .flags = SPEC_DEV_ID_DISABLE_HT}, 1852865d42cSLarry Finger {.idVendor = 0x13D3, .idProduct = 0x3311, 1862865d42cSLarry Finger .flags = SPEC_DEV_ID_DISABLE_HT}, 1876b284053SAxel Köllhofer {.idVendor = 0x13d3, .idProduct = 0x3335, 1886b284053SAxel Köllhofer .flags = SPEC_DEV_ID_DISABLE_HT}, 1896b284053SAxel Köllhofer {.idVendor = 0x13d3, .idProduct = 0x3336, 1906b284053SAxel Köllhofer .flags = SPEC_DEV_ID_DISABLE_HT}, 1916b284053SAxel Köllhofer {.idVendor = 0x13d3, .idProduct = 0x3340, 1926b284053SAxel Köllhofer .flags = SPEC_DEV_ID_DISABLE_HT}, 1936b284053SAxel Köllhofer {.idVendor = 0x13d3, .idProduct = 0x3341, 1946b284053SAxel Köllhofer .flags = SPEC_DEV_ID_DISABLE_HT}, 1952865d42cSLarry Finger {} 1962865d42cSLarry Finger }; 1972865d42cSLarry Finger 1982865d42cSLarry Finger struct drv_priv { 1992865d42cSLarry Finger struct usb_driver r871xu_drv; 2002865d42cSLarry Finger int drv_registered; 2012865d42cSLarry Finger }; 2022865d42cSLarry Finger 2032865d42cSLarry Finger #ifdef CONFIG_PM 2042865d42cSLarry Finger static int r871x_suspend(struct usb_interface *pusb_intf, pm_message_t state) 2052865d42cSLarry Finger { 2062865d42cSLarry Finger struct net_device *pnetdev = usb_get_intfdata(pusb_intf); 2072865d42cSLarry Finger 2082865d42cSLarry Finger printk(KERN_INFO "r8712: suspending...\n"); 2092865d42cSLarry Finger if (!pnetdev || !netif_running(pnetdev)) { 2102865d42cSLarry Finger printk(KERN_INFO "r8712: unable to suspend\n"); 2112865d42cSLarry Finger return 0; 2122865d42cSLarry Finger } 2132865d42cSLarry Finger if (pnetdev->netdev_ops->ndo_stop) 2142865d42cSLarry Finger pnetdev->netdev_ops->ndo_stop(pnetdev); 2152865d42cSLarry Finger mdelay(10); 2162865d42cSLarry Finger netif_device_detach(pnetdev); 2172865d42cSLarry Finger return 0; 2182865d42cSLarry Finger } 2192865d42cSLarry Finger 2202865d42cSLarry Finger static int r871x_resume(struct usb_interface *pusb_intf) 2212865d42cSLarry Finger { 2222865d42cSLarry Finger struct net_device *pnetdev = usb_get_intfdata(pusb_intf); 2232865d42cSLarry Finger 2242865d42cSLarry Finger printk(KERN_INFO "r8712: resuming...\n"); 2252865d42cSLarry Finger if (!pnetdev || !netif_running(pnetdev)) { 2262865d42cSLarry Finger printk(KERN_INFO "r8712: unable to resume\n"); 2272865d42cSLarry Finger return 0; 2282865d42cSLarry Finger } 2292865d42cSLarry Finger netif_device_attach(pnetdev); 2302865d42cSLarry Finger if (pnetdev->netdev_ops->ndo_open) 2312865d42cSLarry Finger pnetdev->netdev_ops->ndo_open(pnetdev); 2322865d42cSLarry Finger return 0; 2332865d42cSLarry Finger } 2342865d42cSLarry Finger 2352865d42cSLarry Finger static int r871x_reset_resume(struct usb_interface *pusb_intf) 2362865d42cSLarry Finger { 2372865d42cSLarry Finger /* dummy routine */ 2382865d42cSLarry Finger return 0; 2392865d42cSLarry Finger } 2402865d42cSLarry Finger 2412865d42cSLarry Finger #endif 2422865d42cSLarry Finger 2432865d42cSLarry Finger static struct drv_priv drvpriv = { 2442865d42cSLarry Finger .r871xu_drv.name = "r8712u", 2452865d42cSLarry Finger .r871xu_drv.id_table = rtl871x_usb_id_tbl, 2462865d42cSLarry Finger .r871xu_drv.probe = r871xu_drv_init, 2472865d42cSLarry Finger .r871xu_drv.disconnect = r871xu_dev_remove, 2482865d42cSLarry Finger #ifdef CONFIG_PM 2492865d42cSLarry Finger .r871xu_drv.suspend = r871x_suspend, 2502865d42cSLarry Finger .r871xu_drv.resume = r871x_resume, 2512865d42cSLarry Finger .r871xu_drv.reset_resume = r871x_reset_resume, 2522865d42cSLarry Finger #endif 2532865d42cSLarry Finger }; 2542865d42cSLarry Finger 2552865d42cSLarry Finger static uint r8712_usb_dvobj_init(struct _adapter *padapter) 2562865d42cSLarry Finger { 2572865d42cSLarry Finger uint status = _SUCCESS; 2582865d42cSLarry Finger struct usb_device_descriptor *pdev_desc; 2592865d42cSLarry Finger struct usb_host_config *phost_conf; 2602865d42cSLarry Finger struct usb_config_descriptor *pconf_desc; 2612865d42cSLarry Finger struct usb_host_interface *phost_iface; 2622865d42cSLarry Finger struct usb_interface_descriptor *piface_desc; 2632865d42cSLarry Finger struct dvobj_priv *pdvobjpriv = &padapter->dvobjpriv; 2642865d42cSLarry Finger struct usb_device *pusbd = pdvobjpriv->pusbdev; 2652865d42cSLarry Finger 2662865d42cSLarry Finger pdvobjpriv->padapter = padapter; 2672865d42cSLarry Finger padapter->EepromAddressSize = 6; 2682865d42cSLarry Finger pdev_desc = &pusbd->descriptor; 2692865d42cSLarry Finger phost_conf = pusbd->actconfig; 2702865d42cSLarry Finger pconf_desc = &phost_conf->desc; 2712865d42cSLarry Finger phost_iface = &pintf->altsetting[0]; 2722865d42cSLarry Finger piface_desc = &phost_iface->desc; 2732865d42cSLarry Finger pdvobjpriv->nr_endpoint = piface_desc->bNumEndpoints; 2742865d42cSLarry Finger if (pusbd->speed == USB_SPEED_HIGH) { 2752865d42cSLarry Finger pdvobjpriv->ishighspeed = true; 2762865d42cSLarry Finger printk(KERN_INFO "r8712u: USB_SPEED_HIGH with %d endpoints\n", 2772865d42cSLarry Finger pdvobjpriv->nr_endpoint); 2782865d42cSLarry Finger } else { 2792865d42cSLarry Finger pdvobjpriv->ishighspeed = false; 2802865d42cSLarry Finger printk(KERN_INFO "r8712u: USB_SPEED_LOW with %d endpoints\n", 2812865d42cSLarry Finger pdvobjpriv->nr_endpoint); 2822865d42cSLarry Finger } 2832865d42cSLarry Finger if ((r8712_alloc_io_queue(padapter)) == _FAIL) 2842865d42cSLarry Finger status = _FAIL; 2852865d42cSLarry Finger return status; 2862865d42cSLarry Finger } 2872865d42cSLarry Finger 2882865d42cSLarry Finger static void r8712_usb_dvobj_deinit(struct _adapter *padapter) 2892865d42cSLarry Finger { 2902865d42cSLarry Finger } 2912865d42cSLarry Finger 2922865d42cSLarry Finger void rtl871x_intf_stop(struct _adapter *padapter) 2932865d42cSLarry Finger { 2942865d42cSLarry Finger /*disable_hw_interrupt*/ 2952865d42cSLarry Finger if (padapter->bSurpriseRemoved == false) { 2962865d42cSLarry Finger /*device still exists, so driver can do i/o operation 2972865d42cSLarry Finger * TODO: */ 2982865d42cSLarry Finger } 2992865d42cSLarry Finger 3002865d42cSLarry Finger /* cancel in irp */ 3012865d42cSLarry Finger if (padapter->dvobjpriv.inirp_deinit != NULL) 3022865d42cSLarry Finger padapter->dvobjpriv.inirp_deinit(padapter); 3032865d42cSLarry Finger /* cancel out irp */ 3042865d42cSLarry Finger r8712_usb_write_port_cancel(padapter); 3052865d42cSLarry Finger /* TODO:cancel other irps */ 3062865d42cSLarry Finger } 3072865d42cSLarry Finger 3082865d42cSLarry Finger void r871x_dev_unload(struct _adapter *padapter) 3092865d42cSLarry Finger { 3102865d42cSLarry Finger if (padapter->bup == true) { 3112865d42cSLarry Finger /*s1.*/ 3122865d42cSLarry Finger padapter->bDriverStopped = true; 3132865d42cSLarry Finger 3142865d42cSLarry Finger /*s3.*/ 3152865d42cSLarry Finger rtl871x_intf_stop(padapter); 3162865d42cSLarry Finger 3172865d42cSLarry Finger /*s4.*/ 3182865d42cSLarry Finger r8712_stop_drv_threads(padapter); 3192865d42cSLarry Finger 3202865d42cSLarry Finger /*s5.*/ 3212865d42cSLarry Finger if (padapter->bSurpriseRemoved == false) { 3222865d42cSLarry Finger padapter->hw_init_completed = false; 3232865d42cSLarry Finger rtl8712_hal_deinit(padapter); 3242865d42cSLarry Finger } 3252865d42cSLarry Finger 3262865d42cSLarry Finger /*s6.*/ 3272865d42cSLarry Finger if (padapter->dvobj_deinit) 3282865d42cSLarry Finger padapter->dvobj_deinit(padapter); 3292865d42cSLarry Finger padapter->bup = false; 3302865d42cSLarry Finger } 3312865d42cSLarry Finger } 3322865d42cSLarry Finger 3332865d42cSLarry Finger static void disable_ht_for_spec_devid(const struct usb_device_id *pdid, 3342865d42cSLarry Finger struct _adapter *padapter) 3352865d42cSLarry Finger { 3362865d42cSLarry Finger u16 vid, pid; 3372865d42cSLarry Finger u32 flags; 3382865d42cSLarry Finger int i; 3392865d42cSLarry Finger int num = sizeof(specific_device_id_tbl) / 3402865d42cSLarry Finger sizeof(struct specific_device_id); 3412865d42cSLarry Finger 3422865d42cSLarry Finger for (i = 0; i < num; i++) { 3432865d42cSLarry Finger vid = specific_device_id_tbl[i].idVendor; 3442865d42cSLarry Finger pid = specific_device_id_tbl[i].idProduct; 3452865d42cSLarry Finger flags = specific_device_id_tbl[i].flags; 3462865d42cSLarry Finger 3472865d42cSLarry Finger if ((pdid->idVendor == vid) && (pdid->idProduct == pid) && 3482865d42cSLarry Finger (flags&SPEC_DEV_ID_DISABLE_HT)) { 3492865d42cSLarry Finger padapter->registrypriv.ht_enable = 0; 3502865d42cSLarry Finger padapter->registrypriv.cbw40_enable = 0; 3512865d42cSLarry Finger padapter->registrypriv.ampdu_enable = 0; 3522865d42cSLarry Finger } 3532865d42cSLarry Finger } 3542865d42cSLarry Finger } 3552865d42cSLarry Finger 3562865d42cSLarry Finger static u8 key_2char2num(u8 hch, u8 lch) 3572865d42cSLarry Finger { 3582865d42cSLarry Finger return (hex_to_bin(hch) << 4) | hex_to_bin(lch); 3592865d42cSLarry Finger } 3602865d42cSLarry Finger 3612865d42cSLarry Finger /* 3622865d42cSLarry Finger * drv_init() - a device potentially for us 3632865d42cSLarry Finger * 3642865d42cSLarry Finger * notes: drv_init() is called when the bus driver has located a card for us 3652865d42cSLarry Finger * to support. We accept the new device by returning 0. 3662865d42cSLarry Finger */ 3672865d42cSLarry Finger static int r871xu_drv_init(struct usb_interface *pusb_intf, 3682865d42cSLarry Finger const struct usb_device_id *pdid) 3692865d42cSLarry Finger { 3702865d42cSLarry Finger uint status; 3712865d42cSLarry Finger struct _adapter *padapter = NULL; 3722865d42cSLarry Finger struct dvobj_priv *pdvobjpriv; 3732865d42cSLarry Finger struct net_device *pnetdev; 374ee5b1aadSAli Bahar struct usb_device *udev; 3752865d42cSLarry Finger 3762865d42cSLarry Finger printk(KERN_INFO "r8712u: DriverVersion: %s\n", DRVER); 3772865d42cSLarry Finger /* In this probe function, O.S. will provide the usb interface pointer 3782865d42cSLarry Finger * to driver. We have to increase the reference count of the usb device 3792865d42cSLarry Finger * structure by using the usb_get_dev function. 3802865d42cSLarry Finger */ 381ee5b1aadSAli Bahar udev = interface_to_usbdev(pusb_intf); 382ee5b1aadSAli Bahar usb_get_dev(udev); 3832865d42cSLarry Finger pintf = pusb_intf; 3842865d42cSLarry Finger /* step 1. */ 3852865d42cSLarry Finger pnetdev = r8712_init_netdev(); 3862865d42cSLarry Finger if (!pnetdev) 3872865d42cSLarry Finger goto error; 388ee5b1aadSAli Bahar padapter = netdev_priv(pnetdev); 3892865d42cSLarry Finger disable_ht_for_spec_devid(pdid, padapter); 3902865d42cSLarry Finger pdvobjpriv = &padapter->dvobjpriv; 3912865d42cSLarry Finger pdvobjpriv->padapter = padapter; 392ee5b1aadSAli Bahar padapter->dvobjpriv.pusbdev = udev; 3938c213fa5SLarry Finger padapter->pusb_intf = pusb_intf; 3942865d42cSLarry Finger usb_set_intfdata(pusb_intf, pnetdev); 3952865d42cSLarry Finger SET_NETDEV_DEV(pnetdev, &pusb_intf->dev); 3962865d42cSLarry Finger /* step 2. */ 3972865d42cSLarry Finger padapter->dvobj_init = &r8712_usb_dvobj_init; 3982865d42cSLarry Finger padapter->dvobj_deinit = &r8712_usb_dvobj_deinit; 3992865d42cSLarry Finger padapter->halpriv.hal_bus_init = &r8712_usb_hal_bus_init; 4002865d42cSLarry Finger padapter->dvobjpriv.inirp_init = &r8712_usb_inirp_init; 4012865d42cSLarry Finger padapter->dvobjpriv.inirp_deinit = &r8712_usb_inirp_deinit; 4022865d42cSLarry Finger /* step 3. 4032865d42cSLarry Finger * initialize the dvobj_priv 4042865d42cSLarry Finger */ 4052865d42cSLarry Finger if (padapter->dvobj_init == NULL) 4062865d42cSLarry Finger goto error; 4072865d42cSLarry Finger else { 4082865d42cSLarry Finger status = padapter->dvobj_init(padapter); 4092865d42cSLarry Finger if (status != _SUCCESS) 4102865d42cSLarry Finger goto error; 4112865d42cSLarry Finger } 4122865d42cSLarry Finger /* step 4. */ 4132865d42cSLarry Finger status = r8712_init_drv_sw(padapter); 4142865d42cSLarry Finger if (status == _FAIL) 4152865d42cSLarry Finger goto error; 4162865d42cSLarry Finger /* step 5. read efuse/eeprom data and get mac_addr */ 4172865d42cSLarry Finger { 4182865d42cSLarry Finger int i, offset; 4192865d42cSLarry Finger u8 mac[6]; 4202865d42cSLarry Finger u8 tmpU1b, AutoloadFail, eeprom_CustomerID; 4212865d42cSLarry Finger u8 *pdata = padapter->eeprompriv.efuse_eeprom_data; 4222865d42cSLarry Finger 4232865d42cSLarry Finger tmpU1b = r8712_read8(padapter, EE_9346CR);/*CR9346*/ 4242865d42cSLarry Finger 4252865d42cSLarry Finger /* To check system boot selection.*/ 4262865d42cSLarry Finger printk(KERN_INFO "r8712u: Boot from %s: Autoload %s\n", 4272865d42cSLarry Finger (tmpU1b & _9356SEL) ? "EEPROM" : "EFUSE", 4282865d42cSLarry Finger (tmpU1b & _EEPROM_EN) ? "OK" : "Failed"); 4292865d42cSLarry Finger 4302865d42cSLarry Finger /* To check autoload success or not.*/ 4312865d42cSLarry Finger if (tmpU1b & _EEPROM_EN) { 4322865d42cSLarry Finger AutoloadFail = true; 4332865d42cSLarry Finger /* The following operations prevent Efuse leakage by 4342865d42cSLarry Finger * turning on 2.5V. 4352865d42cSLarry Finger */ 4362865d42cSLarry Finger tmpU1b = r8712_read8(padapter, EFUSE_TEST+3); 4372865d42cSLarry Finger r8712_write8(padapter, EFUSE_TEST + 3, tmpU1b | 0x80); 4382865d42cSLarry Finger msleep(20); 4392865d42cSLarry Finger r8712_write8(padapter, EFUSE_TEST + 3, 4402865d42cSLarry Finger (tmpU1b & (~BIT(7)))); 4412865d42cSLarry Finger 4422865d42cSLarry Finger /* Retrieve Chip version. 4432865d42cSLarry Finger * Recognize IC version by Reg0x4 BIT15. 4442865d42cSLarry Finger */ 4452865d42cSLarry Finger tmpU1b = (u8)((r8712_read32(padapter, PMC_FSM) >> 15) & 4462865d42cSLarry Finger 0x1F); 4472865d42cSLarry Finger if (tmpU1b == 0x3) 4482865d42cSLarry Finger padapter->registrypriv.chip_version = 4492865d42cSLarry Finger RTL8712_3rdCUT; 4502865d42cSLarry Finger else 4512865d42cSLarry Finger padapter->registrypriv.chip_version = 4522865d42cSLarry Finger (tmpU1b >> 1) + 1; 4532865d42cSLarry Finger switch (padapter->registrypriv.chip_version) { 4542865d42cSLarry Finger case RTL8712_1stCUT: 4552865d42cSLarry Finger case RTL8712_2ndCUT: 4562865d42cSLarry Finger case RTL8712_3rdCUT: 4572865d42cSLarry Finger break; 4582865d42cSLarry Finger default: 4592865d42cSLarry Finger padapter->registrypriv.chip_version = 4602865d42cSLarry Finger RTL8712_2ndCUT; 4612865d42cSLarry Finger break; 4622865d42cSLarry Finger } 4632865d42cSLarry Finger 4642865d42cSLarry Finger for (i = 0, offset = 0; i < 128; i += 8, offset++) 4652865d42cSLarry Finger r8712_efuse_pg_packet_read(padapter, offset, 4662865d42cSLarry Finger &pdata[i]); 4672865d42cSLarry Finger 4682865d42cSLarry Finger if (r8712_initmac) { 4692865d42cSLarry Finger /* Users specify the mac address */ 4702865d42cSLarry Finger int jj, kk; 4712865d42cSLarry Finger 4722865d42cSLarry Finger for (jj = 0, kk = 0; jj < ETH_ALEN; 4732865d42cSLarry Finger jj++, kk += 3) 4742865d42cSLarry Finger mac[jj] = 4752865d42cSLarry Finger key_2char2num(r8712_initmac[kk], 4762865d42cSLarry Finger r8712_initmac[kk + 1]); 4772865d42cSLarry Finger } else { 4782865d42cSLarry Finger /* Use the mac address stored in the Efuse 4792865d42cSLarry Finger * offset = 0x12 for usb in efuse 4802865d42cSLarry Finger */ 4812865d42cSLarry Finger memcpy(mac, &pdata[0x12], ETH_ALEN); 4822865d42cSLarry Finger } 4832865d42cSLarry Finger eeprom_CustomerID = pdata[0x52]; 4842865d42cSLarry Finger switch (eeprom_CustomerID) { 4852865d42cSLarry Finger case EEPROM_CID_ALPHA: 4862865d42cSLarry Finger padapter->eeprompriv.CustomerID = 4872865d42cSLarry Finger RT_CID_819x_ALPHA; 4882865d42cSLarry Finger break; 4892865d42cSLarry Finger case EEPROM_CID_CAMEO: 4902865d42cSLarry Finger padapter->eeprompriv.CustomerID = 4912865d42cSLarry Finger RT_CID_819x_CAMEO; 4922865d42cSLarry Finger break; 4932865d42cSLarry Finger case EEPROM_CID_SITECOM: 4942865d42cSLarry Finger padapter->eeprompriv.CustomerID = 4952865d42cSLarry Finger RT_CID_819x_Sitecom; 4962865d42cSLarry Finger break; 4972865d42cSLarry Finger case EEPROM_CID_COREGA: 4982865d42cSLarry Finger padapter->eeprompriv.CustomerID = 4992865d42cSLarry Finger RT_CID_COREGA; 5002865d42cSLarry Finger break; 5012865d42cSLarry Finger case EEPROM_CID_Senao: 5022865d42cSLarry Finger padapter->eeprompriv.CustomerID = 5032865d42cSLarry Finger RT_CID_819x_Senao; 5042865d42cSLarry Finger break; 5052865d42cSLarry Finger case EEPROM_CID_EDIMAX_BELKIN: 5062865d42cSLarry Finger padapter->eeprompriv.CustomerID = 5072865d42cSLarry Finger RT_CID_819x_Edimax_Belkin; 5082865d42cSLarry Finger break; 5092865d42cSLarry Finger case EEPROM_CID_SERCOMM_BELKIN: 5102865d42cSLarry Finger padapter->eeprompriv.CustomerID = 5112865d42cSLarry Finger RT_CID_819x_Sercomm_Belkin; 5122865d42cSLarry Finger break; 5132865d42cSLarry Finger case EEPROM_CID_WNC_COREGA: 5142865d42cSLarry Finger padapter->eeprompriv.CustomerID = 5152865d42cSLarry Finger RT_CID_819x_WNC_COREGA; 5162865d42cSLarry Finger break; 5172865d42cSLarry Finger case EEPROM_CID_WHQL: 5182865d42cSLarry Finger break; 5192865d42cSLarry Finger case EEPROM_CID_NetCore: 5202865d42cSLarry Finger padapter->eeprompriv.CustomerID = 5212865d42cSLarry Finger RT_CID_819x_Netcore; 5222865d42cSLarry Finger break; 5232865d42cSLarry Finger case EEPROM_CID_CAMEO1: 5242865d42cSLarry Finger padapter->eeprompriv.CustomerID = 5252865d42cSLarry Finger RT_CID_819x_CAMEO1; 5262865d42cSLarry Finger break; 5272865d42cSLarry Finger case EEPROM_CID_CLEVO: 5282865d42cSLarry Finger padapter->eeprompriv.CustomerID = 5292865d42cSLarry Finger RT_CID_819x_CLEVO; 5302865d42cSLarry Finger break; 5312865d42cSLarry Finger default: 5322865d42cSLarry Finger padapter->eeprompriv.CustomerID = 5332865d42cSLarry Finger RT_CID_DEFAULT; 5342865d42cSLarry Finger break; 5352865d42cSLarry Finger } 5362865d42cSLarry Finger printk(KERN_INFO "r8712u: CustomerID = 0x%.4x\n", 5372865d42cSLarry Finger padapter->eeprompriv.CustomerID); 5382865d42cSLarry Finger /* Led mode */ 5392865d42cSLarry Finger switch (padapter->eeprompriv.CustomerID) { 5402865d42cSLarry Finger case RT_CID_DEFAULT: 5412865d42cSLarry Finger case RT_CID_819x_ALPHA: 5422865d42cSLarry Finger case RT_CID_819x_CAMEO: 5432865d42cSLarry Finger padapter->ledpriv.LedStrategy = SW_LED_MODE1; 5442865d42cSLarry Finger padapter->ledpriv.bRegUseLed = true; 5452865d42cSLarry Finger break; 5462865d42cSLarry Finger case RT_CID_819x_Sitecom: 5472865d42cSLarry Finger padapter->ledpriv.LedStrategy = SW_LED_MODE2; 5482865d42cSLarry Finger padapter->ledpriv.bRegUseLed = true; 5492865d42cSLarry Finger break; 5502865d42cSLarry Finger case RT_CID_COREGA: 5512865d42cSLarry Finger case RT_CID_819x_Senao: 5522865d42cSLarry Finger padapter->ledpriv.LedStrategy = SW_LED_MODE3; 5532865d42cSLarry Finger padapter->ledpriv.bRegUseLed = true; 5542865d42cSLarry Finger break; 5552865d42cSLarry Finger case RT_CID_819x_Edimax_Belkin: 5562865d42cSLarry Finger padapter->ledpriv.LedStrategy = SW_LED_MODE4; 5572865d42cSLarry Finger padapter->ledpriv.bRegUseLed = true; 5582865d42cSLarry Finger break; 5592865d42cSLarry Finger case RT_CID_819x_Sercomm_Belkin: 5602865d42cSLarry Finger padapter->ledpriv.LedStrategy = SW_LED_MODE5; 5612865d42cSLarry Finger padapter->ledpriv.bRegUseLed = true; 5622865d42cSLarry Finger break; 5632865d42cSLarry Finger case RT_CID_819x_WNC_COREGA: 5642865d42cSLarry Finger padapter->ledpriv.LedStrategy = SW_LED_MODE6; 5652865d42cSLarry Finger padapter->ledpriv.bRegUseLed = true; 5662865d42cSLarry Finger break; 5672865d42cSLarry Finger default: 5682865d42cSLarry Finger padapter->ledpriv.LedStrategy = SW_LED_MODE0; 5692865d42cSLarry Finger padapter->ledpriv.bRegUseLed = false; 5702865d42cSLarry Finger break; 5712865d42cSLarry Finger } 5722865d42cSLarry Finger } else 5732865d42cSLarry Finger AutoloadFail = false; 5742865d42cSLarry Finger if (((mac[0] == 0xff) && (mac[1] == 0xff) && 5752865d42cSLarry Finger (mac[2] == 0xff) && (mac[3] == 0xff) && 5762865d42cSLarry Finger (mac[4] == 0xff) && (mac[5] == 0xff)) || 5772865d42cSLarry Finger ((mac[0] == 0x00) && (mac[1] == 0x00) && 5782865d42cSLarry Finger (mac[2] == 0x00) && (mac[3] == 0x00) && 5792865d42cSLarry Finger (mac[4] == 0x00) && (mac[5] == 0x00)) || 5802865d42cSLarry Finger (AutoloadFail == false)) { 5812865d42cSLarry Finger mac[0] = 0x00; 5822865d42cSLarry Finger mac[1] = 0xe0; 5832865d42cSLarry Finger mac[2] = 0x4c; 5842865d42cSLarry Finger mac[3] = 0x87; 5852865d42cSLarry Finger mac[4] = 0x00; 5862865d42cSLarry Finger mac[5] = 0x00; 5872865d42cSLarry Finger } 5882865d42cSLarry Finger if (r8712_initmac) { 5892865d42cSLarry Finger /* Make sure the user did not select a multicast 5902865d42cSLarry Finger * address by setting bit 1 of first octet. 5912865d42cSLarry Finger */ 5922865d42cSLarry Finger mac[0] &= 0xFE; 5932865d42cSLarry Finger printk(KERN_INFO "r8712u: MAC Address from user = " 5942865d42cSLarry Finger "%pM\n", mac); 5952865d42cSLarry Finger } else 5962865d42cSLarry Finger printk(KERN_INFO "r8712u: MAC Address from efuse = " 5972865d42cSLarry Finger "%pM\n", mac); 5982865d42cSLarry Finger memcpy(pnetdev->dev_addr, mac, ETH_ALEN); 5992865d42cSLarry Finger } 6008c213fa5SLarry Finger /* step 6. Load the firmware asynchronously */ 6018c213fa5SLarry Finger if (rtl871x_load_fw(padapter)) 6022865d42cSLarry Finger goto error; 603ee5b1aadSAli Bahar spin_lock_init(&padapter->lockRxFF0Filter); 6048c213fa5SLarry Finger mutex_init(&padapter->mutex_start); 6052865d42cSLarry Finger return 0; 6062865d42cSLarry Finger error: 607ee5b1aadSAli Bahar usb_put_dev(udev); 6082865d42cSLarry Finger usb_set_intfdata(pusb_intf, NULL); 6092865d42cSLarry Finger if (padapter->dvobj_deinit != NULL) 6102865d42cSLarry Finger padapter->dvobj_deinit(padapter); 6112865d42cSLarry Finger if (pnetdev) 6127bcd9ce6SAli Bahar free_netdev(pnetdev); 6132865d42cSLarry Finger return -ENODEV; 6142865d42cSLarry Finger } 6152865d42cSLarry Finger 6162865d42cSLarry Finger /* rmmod module & unplug(SurpriseRemoved) will call r871xu_dev_remove() 6172865d42cSLarry Finger * => how to recognize both */ 6182865d42cSLarry Finger static void r871xu_dev_remove(struct usb_interface *pusb_intf) 6192865d42cSLarry Finger { 6202865d42cSLarry Finger struct net_device *pnetdev = usb_get_intfdata(pusb_intf); 621e33196e1SJoe Perches struct _adapter *padapter = netdev_priv(pnetdev); 6222865d42cSLarry Finger struct usb_device *udev = interface_to_usbdev(pusb_intf); 6232865d42cSLarry Finger 6242080913eSLarry Finger if (padapter->fw_found) 6252080913eSLarry Finger release_firmware(padapter->fw); 6262080913eSLarry Finger /* never exit with a firmware callback pending */ 6272080913eSLarry Finger wait_for_completion(&padapter->rtl8712_fw_ready); 628ee5b1aadSAli Bahar usb_set_intfdata(pusb_intf, NULL); 6292865d42cSLarry Finger if (padapter) { 6302865d42cSLarry Finger if (drvpriv.drv_registered == true) 6312865d42cSLarry Finger padapter->bSurpriseRemoved = true; 6322865d42cSLarry Finger if (pnetdev != NULL) { 6332865d42cSLarry Finger /* will call netdev_close() */ 6342865d42cSLarry Finger unregister_netdev(pnetdev); 6352865d42cSLarry Finger } 6362865d42cSLarry Finger flush_scheduled_work(); 6372865d42cSLarry Finger udelay(1); 6386c19d86bSAli Bahar /*Stop driver mlme relation timer */ 6398c213fa5SLarry Finger if (padapter->fw_found) 6406c19d86bSAli Bahar r8712_stop_drv_timers(padapter); 6412865d42cSLarry Finger r871x_dev_unload(padapter); 6422865d42cSLarry Finger r8712_free_drv_sw(padapter); 6432865d42cSLarry Finger } 6442865d42cSLarry Finger usb_set_intfdata(pusb_intf, NULL); 6452865d42cSLarry Finger /* decrease the reference count of the usb device structure 6462865d42cSLarry Finger * when disconnect */ 6472865d42cSLarry Finger usb_put_dev(udev); 6482865d42cSLarry Finger /* If we didn't unplug usb dongle and remove/insert modlue, driver 6492865d42cSLarry Finger * fails on sitesurvey for the first time when device is up. 6502865d42cSLarry Finger * Reset usb port for sitesurvey fail issue. */ 6512865d42cSLarry Finger if (udev->state != USB_STATE_NOTATTACHED) 6522865d42cSLarry Finger usb_reset_device(udev); 6532865d42cSLarry Finger return; 6542865d42cSLarry Finger } 6552865d42cSLarry Finger 6562865d42cSLarry Finger static int __init r8712u_drv_entry(void) 6572865d42cSLarry Finger { 6582865d42cSLarry Finger drvpriv.drv_registered = true; 6592865d42cSLarry Finger return usb_register(&drvpriv.r871xu_drv); 6602865d42cSLarry Finger } 6612865d42cSLarry Finger 6622865d42cSLarry Finger static void __exit r8712u_drv_halt(void) 6632865d42cSLarry Finger { 6642865d42cSLarry Finger drvpriv.drv_registered = false; 6652865d42cSLarry Finger usb_deregister(&drvpriv.r871xu_drv); 6662865d42cSLarry Finger printk(KERN_INFO "r8712u: Driver unloaded\n"); 6672865d42cSLarry Finger } 6682865d42cSLarry Finger 6692865d42cSLarry Finger module_init(r8712u_drv_entry); 6702865d42cSLarry Finger module_exit(r8712u_drv_halt); 671