Larry Finger | 2865d42 | 2010-08-20 10:15:30 -0500 | [diff] [blame] | 1 | /****************************************************************************** |
| 2 | * usb_intf.c |
| 3 | * |
| 4 | * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. |
| 5 | * Linux device driver for RTL8192SU |
| 6 | * |
| 7 | * This program is free software; you can redistribute it and/or modify it |
| 8 | * under the terms of version 2 of the GNU General Public License as |
| 9 | * published by the Free Software Foundation. |
| 10 | * |
| 11 | * This program is distributed in the hope that it will be useful, but WITHOUT |
| 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| 14 | * more details. |
| 15 | * |
| 16 | * You should have received a copy of the GNU General Public License along with |
| 17 | * this program; if not, write to the Free Software Foundation, Inc., |
| 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA |
| 19 | * |
| 20 | * Modifications for inclusion into the Linux staging tree are |
| 21 | * Copyright(c) 2010 Larry Finger. All rights reserved. |
| 22 | * |
| 23 | * Contact information: |
| 24 | * WLAN FAE <wlanfae@realtek.com> |
| 25 | * Larry Finger <Larry.Finger@lwfinger.net> |
| 26 | * |
| 27 | ******************************************************************************/ |
| 28 | |
| 29 | #define _HCI_INTF_C_ |
| 30 | |
Ali Bahar | 359140a | 2011-09-04 03:14:11 +0800 | [diff] [blame] | 31 | #include <linux/usb.h> |
Stephen Rothwell | 81e07c0 | 2011-10-04 18:32:57 +1100 | [diff] [blame] | 32 | #include <linux/module.h> |
Larry Finger | 2080913 | 2012-02-25 18:10:21 -0600 | [diff] [blame] | 33 | #include <linux/firmware.h> |
Ali Bahar | 359140a | 2011-09-04 03:14:11 +0800 | [diff] [blame] | 34 | |
Larry Finger | 2865d42 | 2010-08-20 10:15:30 -0500 | [diff] [blame] | 35 | #include "osdep_service.h" |
| 36 | #include "drv_types.h" |
| 37 | #include "recv_osdep.h" |
| 38 | #include "xmit_osdep.h" |
| 39 | #include "rtl8712_efuse.h" |
| 40 | #include "usb_vendor_req.h" |
| 41 | #include "usb_ops.h" |
| 42 | #include "usb_osintf.h" |
| 43 | |
Larry Finger | 5a3acb0 | 2010-08-31 10:22:02 -0500 | [diff] [blame] | 44 | #define DRVER "v7_0.20100831" |
Larry Finger | 2865d42 | 2010-08-20 10:15:30 -0500 | [diff] [blame] | 45 | |
| 46 | static struct usb_interface *pintf; |
| 47 | |
| 48 | static int r871xu_drv_init(struct usb_interface *pusb_intf, |
| 49 | const struct usb_device_id *pdid); |
| 50 | |
| 51 | static void r871xu_dev_remove(struct usb_interface *pusb_intf); |
| 52 | |
| 53 | static struct usb_device_id rtl871x_usb_id_tbl[] = { |
Axel Köllhofer | 6b28405 | 2011-01-22 14:33:50 -0600 | [diff] [blame] | 54 | |
| 55 | /* RTL8188SU */ |
| 56 | /* Realtek */ |
| 57 | {USB_DEVICE(0x0BDA, 0x8171)}, |
Larry Finger | 2865d42 | 2010-08-20 10:15:30 -0500 | [diff] [blame] | 58 | {USB_DEVICE(0x0bda, 0x8173)}, |
Larry Finger | 2865d42 | 2010-08-20 10:15:30 -0500 | [diff] [blame] | 59 | {USB_DEVICE(0x0bda, 0x8712)}, |
| 60 | {USB_DEVICE(0x0bda, 0x8713)}, |
| 61 | {USB_DEVICE(0x0bda, 0xC512)}, |
Axel Köllhofer | 6b28405 | 2011-01-22 14:33:50 -0600 | [diff] [blame] | 62 | /* Abocom */ |
Larry Finger | 2865d42 | 2010-08-20 10:15:30 -0500 | [diff] [blame] | 63 | {USB_DEVICE(0x07B8, 0x8188)}, |
Axel Köllhofer | 6b28405 | 2011-01-22 14:33:50 -0600 | [diff] [blame] | 64 | /* ASUS */ |
| 65 | {USB_DEVICE(0x0B05, 0x1786)}, |
| 66 | {USB_DEVICE(0x0B05, 0x1791)}, /* 11n mode disable */ |
Larry Finger | 2865d42 | 2010-08-20 10:15:30 -0500 | [diff] [blame] | 67 | /* Belkin */ |
Axel Köllhofer | 6b28405 | 2011-01-22 14:33:50 -0600 | [diff] [blame] | 68 | {USB_DEVICE(0x050D, 0x945A)}, |
| 69 | /* Corega */ |
| 70 | {USB_DEVICE(0x07AA, 0x0047)}, |
| 71 | /* D-Link */ |
| 72 | {USB_DEVICE(0x2001, 0x3306)}, |
| 73 | {USB_DEVICE(0x07D1, 0x3306)}, /* 11n mode disable */ |
Larry Finger | 2865d42 | 2010-08-20 10:15:30 -0500 | [diff] [blame] | 74 | /* Edimax */ |
| 75 | {USB_DEVICE(0x7392, 0x7611)}, |
Axel Köllhofer | 6b28405 | 2011-01-22 14:33:50 -0600 | [diff] [blame] | 76 | /* EnGenius */ |
| 77 | {USB_DEVICE(0x1740, 0x9603)}, |
| 78 | /* Hawking */ |
| 79 | {USB_DEVICE(0x0E66, 0x0016)}, |
| 80 | /* Hercules */ |
| 81 | {USB_DEVICE(0x06F8, 0xE034)}, |
| 82 | {USB_DEVICE(0x06F8, 0xE032)}, |
| 83 | /* Logitec */ |
| 84 | {USB_DEVICE(0x0789, 0x0167)}, |
| 85 | /* PCI */ |
| 86 | {USB_DEVICE(0x2019, 0xAB28)}, |
| 87 | {USB_DEVICE(0x2019, 0xED16)}, |
Larry Finger | 2865d42 | 2010-08-20 10:15:30 -0500 | [diff] [blame] | 88 | /* Sitecom */ |
Axel Köllhofer | 6b28405 | 2011-01-22 14:33:50 -0600 | [diff] [blame] | 89 | {USB_DEVICE(0x0DF6, 0x0057)}, |
Larry Finger | 2865d42 | 2010-08-20 10:15:30 -0500 | [diff] [blame] | 90 | {USB_DEVICE(0x0DF6, 0x0045)}, |
Axel Köllhofer | 6b28405 | 2011-01-22 14:33:50 -0600 | [diff] [blame] | 91 | {USB_DEVICE(0x0DF6, 0x0059)}, /* 11n mode disable */ |
| 92 | {USB_DEVICE(0x0DF6, 0x004B)}, |
Larry Finger | 1793bf1 | 2012-01-07 10:07:03 -0600 | [diff] [blame] | 93 | {USB_DEVICE(0x0DF6, 0x005B)}, |
Larry Finger | c7caf4d | 2011-12-11 10:27:54 -0600 | [diff] [blame] | 94 | {USB_DEVICE(0x0DF6, 0x005D)}, |
Axel Köllhofer | 6b28405 | 2011-01-22 14:33:50 -0600 | [diff] [blame] | 95 | {USB_DEVICE(0x0DF6, 0x0063)}, |
| 96 | /* Sweex */ |
| 97 | {USB_DEVICE(0x177F, 0x0154)}, |
| 98 | /* Thinkware */ |
| 99 | {USB_DEVICE(0x0BDA, 0x5077)}, |
| 100 | /* Toshiba */ |
| 101 | {USB_DEVICE(0x1690, 0x0752)}, |
| 102 | /* - */ |
| 103 | {USB_DEVICE(0x20F4, 0x646B)}, |
| 104 | {USB_DEVICE(0x083A, 0xC512)}, |
| 105 | |
| 106 | /* RTL8191SU */ |
| 107 | /* Realtek */ |
| 108 | {USB_DEVICE(0x0BDA, 0x8172)}, |
Martin Krause | 07b99cf | 2012-03-02 13:01:40 +0100 | [diff] [blame] | 109 | {USB_DEVICE(0x0BDA, 0x8192)}, |
Axel Köllhofer | 6b28405 | 2011-01-22 14:33:50 -0600 | [diff] [blame] | 110 | /* Amigo */ |
| 111 | {USB_DEVICE(0x0EB0, 0x9061)}, |
| 112 | /* ASUS/EKB */ |
Axel Köllhofer | 6b28405 | 2011-01-22 14:33:50 -0600 | [diff] [blame] | 113 | {USB_DEVICE(0x13D3, 0x3323)}, |
| 114 | {USB_DEVICE(0x13D3, 0x3311)}, /* 11n mode disable */ |
| 115 | {USB_DEVICE(0x13D3, 0x3342)}, |
| 116 | /* ASUS/EKBLenovo */ |
| 117 | {USB_DEVICE(0x13D3, 0x3333)}, |
| 118 | {USB_DEVICE(0x13D3, 0x3334)}, |
| 119 | {USB_DEVICE(0x13D3, 0x3335)}, /* 11n mode disable */ |
| 120 | {USB_DEVICE(0x13D3, 0x3336)}, /* 11n mode disable */ |
| 121 | /* ASUS/Media BOX */ |
| 122 | {USB_DEVICE(0x13D3, 0x3309)}, |
| 123 | /* Belkin */ |
| 124 | {USB_DEVICE(0x050D, 0x815F)}, |
| 125 | /* D-Link */ |
| 126 | {USB_DEVICE(0x07D1, 0x3302)}, |
| 127 | {USB_DEVICE(0x07D1, 0x3300)}, |
| 128 | {USB_DEVICE(0x07D1, 0x3303)}, |
| 129 | /* Edimax */ |
| 130 | {USB_DEVICE(0x7392, 0x7612)}, |
| 131 | /* EnGenius */ |
| 132 | {USB_DEVICE(0x1740, 0x9605)}, |
| 133 | /* Guillemot */ |
| 134 | {USB_DEVICE(0x06F8, 0xE031)}, |
Larry Finger | 2865d42 | 2010-08-20 10:15:30 -0500 | [diff] [blame] | 135 | /* Hawking */ |
| 136 | {USB_DEVICE(0x0E66, 0x0015)}, |
Axel Köllhofer | 6b28405 | 2011-01-22 14:33:50 -0600 | [diff] [blame] | 137 | /* Mediao */ |
Larry Finger | 2865d42 | 2010-08-20 10:15:30 -0500 | [diff] [blame] | 138 | {USB_DEVICE(0x13D3, 0x3306)}, |
Axel Köllhofer | 6b28405 | 2011-01-22 14:33:50 -0600 | [diff] [blame] | 139 | /* PCI */ |
| 140 | {USB_DEVICE(0x2019, 0xED18)}, |
| 141 | {USB_DEVICE(0x2019, 0x4901)}, |
| 142 | /* Sitecom */ |
| 143 | {USB_DEVICE(0x0DF6, 0x0058)}, |
| 144 | {USB_DEVICE(0x0DF6, 0x0049)}, |
| 145 | {USB_DEVICE(0x0DF6, 0x004C)}, |
| 146 | {USB_DEVICE(0x0DF6, 0x0064)}, |
| 147 | /* Skyworth */ |
| 148 | {USB_DEVICE(0x14b2, 0x3300)}, |
| 149 | {USB_DEVICE(0x14b2, 0x3301)}, |
| 150 | {USB_DEVICE(0x14B2, 0x3302)}, |
| 151 | /* - */ |
| 152 | {USB_DEVICE(0x04F2, 0xAFF2)}, |
| 153 | {USB_DEVICE(0x04F2, 0xAFF5)}, |
| 154 | {USB_DEVICE(0x04F2, 0xAFF6)}, |
| 155 | {USB_DEVICE(0x13D3, 0x3339)}, |
| 156 | {USB_DEVICE(0x13D3, 0x3340)}, /* 11n mode disable */ |
| 157 | {USB_DEVICE(0x13D3, 0x3341)}, /* 11n mode disable */ |
Larry Finger | 2865d42 | 2010-08-20 10:15:30 -0500 | [diff] [blame] | 158 | {USB_DEVICE(0x13D3, 0x3310)}, |
Larry Finger | 2865d42 | 2010-08-20 10:15:30 -0500 | [diff] [blame] | 159 | {USB_DEVICE(0x13D3, 0x3325)}, |
Axel Köllhofer | 6b28405 | 2011-01-22 14:33:50 -0600 | [diff] [blame] | 160 | |
| 161 | /* RTL8192SU */ |
| 162 | /* Realtek */ |
| 163 | {USB_DEVICE(0x0BDA, 0x8174)}, |
Axel Köllhofer | 6b28405 | 2011-01-22 14:33:50 -0600 | [diff] [blame] | 164 | /* Belkin */ |
| 165 | {USB_DEVICE(0x050D, 0x845A)}, |
| 166 | /* Corega */ |
| 167 | {USB_DEVICE(0x07AA, 0x0051)}, |
| 168 | /* Edimax */ |
| 169 | {USB_DEVICE(0x7392, 0x7622)}, |
| 170 | /* NEC */ |
| 171 | {USB_DEVICE(0x0409, 0x02B6)}, |
Larry Finger | 2865d42 | 2010-08-20 10:15:30 -0500 | [diff] [blame] | 172 | {} |
| 173 | }; |
| 174 | |
| 175 | MODULE_DEVICE_TABLE(usb, rtl871x_usb_id_tbl); |
| 176 | |
| 177 | static struct specific_device_id specific_device_id_tbl[] = { |
| 178 | {.idVendor = 0x0b05, .idProduct = 0x1791, |
| 179 | .flags = SPEC_DEV_ID_DISABLE_HT}, |
Axel Köllhofer | 6b28405 | 2011-01-22 14:33:50 -0600 | [diff] [blame] | 180 | {.idVendor = 0x0df6, .idProduct = 0x0059, |
| 181 | .flags = SPEC_DEV_ID_DISABLE_HT}, |
| 182 | {.idVendor = 0x13d3, .idProduct = 0x3306, |
| 183 | .flags = SPEC_DEV_ID_DISABLE_HT}, |
Larry Finger | 2865d42 | 2010-08-20 10:15:30 -0500 | [diff] [blame] | 184 | {.idVendor = 0x13D3, .idProduct = 0x3311, |
| 185 | .flags = SPEC_DEV_ID_DISABLE_HT}, |
Axel Köllhofer | 6b28405 | 2011-01-22 14:33:50 -0600 | [diff] [blame] | 186 | {.idVendor = 0x13d3, .idProduct = 0x3335, |
| 187 | .flags = SPEC_DEV_ID_DISABLE_HT}, |
| 188 | {.idVendor = 0x13d3, .idProduct = 0x3336, |
| 189 | .flags = SPEC_DEV_ID_DISABLE_HT}, |
| 190 | {.idVendor = 0x13d3, .idProduct = 0x3340, |
| 191 | .flags = SPEC_DEV_ID_DISABLE_HT}, |
| 192 | {.idVendor = 0x13d3, .idProduct = 0x3341, |
| 193 | .flags = SPEC_DEV_ID_DISABLE_HT}, |
Larry Finger | 2865d42 | 2010-08-20 10:15:30 -0500 | [diff] [blame] | 194 | {} |
| 195 | }; |
| 196 | |
| 197 | struct drv_priv { |
| 198 | struct usb_driver r871xu_drv; |
| 199 | int drv_registered; |
| 200 | }; |
| 201 | |
| 202 | #ifdef CONFIG_PM |
| 203 | static int r871x_suspend(struct usb_interface *pusb_intf, pm_message_t state) |
| 204 | { |
| 205 | struct net_device *pnetdev = usb_get_intfdata(pusb_intf); |
| 206 | |
| 207 | printk(KERN_INFO "r8712: suspending...\n"); |
| 208 | if (!pnetdev || !netif_running(pnetdev)) { |
| 209 | printk(KERN_INFO "r8712: unable to suspend\n"); |
| 210 | return 0; |
| 211 | } |
| 212 | if (pnetdev->netdev_ops->ndo_stop) |
| 213 | pnetdev->netdev_ops->ndo_stop(pnetdev); |
| 214 | mdelay(10); |
| 215 | netif_device_detach(pnetdev); |
| 216 | return 0; |
| 217 | } |
| 218 | |
| 219 | static int r871x_resume(struct usb_interface *pusb_intf) |
| 220 | { |
| 221 | struct net_device *pnetdev = usb_get_intfdata(pusb_intf); |
| 222 | |
| 223 | printk(KERN_INFO "r8712: resuming...\n"); |
| 224 | if (!pnetdev || !netif_running(pnetdev)) { |
| 225 | printk(KERN_INFO "r8712: unable to resume\n"); |
| 226 | return 0; |
| 227 | } |
| 228 | netif_device_attach(pnetdev); |
| 229 | if (pnetdev->netdev_ops->ndo_open) |
| 230 | pnetdev->netdev_ops->ndo_open(pnetdev); |
| 231 | return 0; |
| 232 | } |
| 233 | |
| 234 | static int r871x_reset_resume(struct usb_interface *pusb_intf) |
| 235 | { |
| 236 | /* dummy routine */ |
| 237 | return 0; |
| 238 | } |
| 239 | |
| 240 | #endif |
| 241 | |
| 242 | static struct drv_priv drvpriv = { |
| 243 | .r871xu_drv.name = "r8712u", |
| 244 | .r871xu_drv.id_table = rtl871x_usb_id_tbl, |
| 245 | .r871xu_drv.probe = r871xu_drv_init, |
| 246 | .r871xu_drv.disconnect = r871xu_dev_remove, |
| 247 | #ifdef CONFIG_PM |
| 248 | .r871xu_drv.suspend = r871x_suspend, |
| 249 | .r871xu_drv.resume = r871x_resume, |
| 250 | .r871xu_drv.reset_resume = r871x_reset_resume, |
| 251 | #endif |
| 252 | }; |
| 253 | |
| 254 | static uint r8712_usb_dvobj_init(struct _adapter *padapter) |
| 255 | { |
| 256 | uint status = _SUCCESS; |
| 257 | struct usb_device_descriptor *pdev_desc; |
| 258 | struct usb_host_config *phost_conf; |
| 259 | struct usb_config_descriptor *pconf_desc; |
| 260 | struct usb_host_interface *phost_iface; |
| 261 | struct usb_interface_descriptor *piface_desc; |
| 262 | struct dvobj_priv *pdvobjpriv = &padapter->dvobjpriv; |
| 263 | struct usb_device *pusbd = pdvobjpriv->pusbdev; |
| 264 | |
| 265 | pdvobjpriv->padapter = padapter; |
| 266 | padapter->EepromAddressSize = 6; |
| 267 | pdev_desc = &pusbd->descriptor; |
| 268 | phost_conf = pusbd->actconfig; |
| 269 | pconf_desc = &phost_conf->desc; |
| 270 | phost_iface = &pintf->altsetting[0]; |
| 271 | piface_desc = &phost_iface->desc; |
| 272 | pdvobjpriv->nr_endpoint = piface_desc->bNumEndpoints; |
| 273 | if (pusbd->speed == USB_SPEED_HIGH) { |
| 274 | pdvobjpriv->ishighspeed = true; |
| 275 | printk(KERN_INFO "r8712u: USB_SPEED_HIGH with %d endpoints\n", |
| 276 | pdvobjpriv->nr_endpoint); |
| 277 | } else { |
| 278 | pdvobjpriv->ishighspeed = false; |
| 279 | printk(KERN_INFO "r8712u: USB_SPEED_LOW with %d endpoints\n", |
| 280 | pdvobjpriv->nr_endpoint); |
| 281 | } |
| 282 | if ((r8712_alloc_io_queue(padapter)) == _FAIL) |
| 283 | status = _FAIL; |
Larry Finger | 2865d42 | 2010-08-20 10:15:30 -0500 | [diff] [blame] | 284 | return status; |
| 285 | } |
| 286 | |
| 287 | static void r8712_usb_dvobj_deinit(struct _adapter *padapter) |
| 288 | { |
| 289 | } |
| 290 | |
| 291 | void rtl871x_intf_stop(struct _adapter *padapter) |
| 292 | { |
| 293 | /*disable_hw_interrupt*/ |
| 294 | if (padapter->bSurpriseRemoved == false) { |
| 295 | /*device still exists, so driver can do i/o operation |
| 296 | * TODO: */ |
| 297 | } |
| 298 | |
| 299 | /* cancel in irp */ |
| 300 | if (padapter->dvobjpriv.inirp_deinit != NULL) |
| 301 | padapter->dvobjpriv.inirp_deinit(padapter); |
| 302 | /* cancel out irp */ |
| 303 | r8712_usb_write_port_cancel(padapter); |
| 304 | /* TODO:cancel other irps */ |
| 305 | } |
| 306 | |
| 307 | void r871x_dev_unload(struct _adapter *padapter) |
| 308 | { |
| 309 | if (padapter->bup == true) { |
| 310 | /*s1.*/ |
| 311 | padapter->bDriverStopped = true; |
| 312 | |
| 313 | /*s3.*/ |
| 314 | rtl871x_intf_stop(padapter); |
| 315 | |
| 316 | /*s4.*/ |
| 317 | r8712_stop_drv_threads(padapter); |
| 318 | |
| 319 | /*s5.*/ |
| 320 | if (padapter->bSurpriseRemoved == false) { |
| 321 | padapter->hw_init_completed = false; |
| 322 | rtl8712_hal_deinit(padapter); |
| 323 | } |
| 324 | |
| 325 | /*s6.*/ |
| 326 | if (padapter->dvobj_deinit) |
| 327 | padapter->dvobj_deinit(padapter); |
| 328 | padapter->bup = false; |
| 329 | } |
| 330 | } |
| 331 | |
| 332 | static void disable_ht_for_spec_devid(const struct usb_device_id *pdid, |
| 333 | struct _adapter *padapter) |
| 334 | { |
| 335 | u16 vid, pid; |
| 336 | u32 flags; |
| 337 | int i; |
| 338 | int num = sizeof(specific_device_id_tbl) / |
| 339 | sizeof(struct specific_device_id); |
| 340 | |
| 341 | for (i = 0; i < num; i++) { |
| 342 | vid = specific_device_id_tbl[i].idVendor; |
| 343 | pid = specific_device_id_tbl[i].idProduct; |
| 344 | flags = specific_device_id_tbl[i].flags; |
| 345 | |
| 346 | if ((pdid->idVendor == vid) && (pdid->idProduct == pid) && |
| 347 | (flags&SPEC_DEV_ID_DISABLE_HT)) { |
| 348 | padapter->registrypriv.ht_enable = 0; |
| 349 | padapter->registrypriv.cbw40_enable = 0; |
| 350 | padapter->registrypriv.ampdu_enable = 0; |
| 351 | } |
| 352 | } |
| 353 | } |
| 354 | |
| 355 | static u8 key_2char2num(u8 hch, u8 lch) |
| 356 | { |
| 357 | return (hex_to_bin(hch) << 4) | hex_to_bin(lch); |
| 358 | } |
| 359 | |
| 360 | /* |
| 361 | * drv_init() - a device potentially for us |
| 362 | * |
| 363 | * notes: drv_init() is called when the bus driver has located a card for us |
| 364 | * to support. We accept the new device by returning 0. |
| 365 | */ |
| 366 | static int r871xu_drv_init(struct usb_interface *pusb_intf, |
| 367 | const struct usb_device_id *pdid) |
| 368 | { |
| 369 | uint status; |
| 370 | struct _adapter *padapter = NULL; |
| 371 | struct dvobj_priv *pdvobjpriv; |
| 372 | struct net_device *pnetdev; |
Ali Bahar | ee5b1aa | 2011-09-04 03:14:21 +0800 | [diff] [blame] | 373 | struct usb_device *udev; |
Larry Finger | 2865d42 | 2010-08-20 10:15:30 -0500 | [diff] [blame] | 374 | |
| 375 | printk(KERN_INFO "r8712u: DriverVersion: %s\n", DRVER); |
| 376 | /* In this probe function, O.S. will provide the usb interface pointer |
| 377 | * to driver. We have to increase the reference count of the usb device |
| 378 | * structure by using the usb_get_dev function. |
| 379 | */ |
Ali Bahar | ee5b1aa | 2011-09-04 03:14:21 +0800 | [diff] [blame] | 380 | udev = interface_to_usbdev(pusb_intf); |
| 381 | usb_get_dev(udev); |
Larry Finger | 2865d42 | 2010-08-20 10:15:30 -0500 | [diff] [blame] | 382 | pintf = pusb_intf; |
| 383 | /* step 1. */ |
| 384 | pnetdev = r8712_init_netdev(); |
| 385 | if (!pnetdev) |
| 386 | goto error; |
Ali Bahar | ee5b1aa | 2011-09-04 03:14:21 +0800 | [diff] [blame] | 387 | padapter = netdev_priv(pnetdev); |
Larry Finger | 2865d42 | 2010-08-20 10:15:30 -0500 | [diff] [blame] | 388 | disable_ht_for_spec_devid(pdid, padapter); |
| 389 | pdvobjpriv = &padapter->dvobjpriv; |
| 390 | pdvobjpriv->padapter = padapter; |
Ali Bahar | ee5b1aa | 2011-09-04 03:14:21 +0800 | [diff] [blame] | 391 | padapter->dvobjpriv.pusbdev = udev; |
Larry Finger | 8c213fa59 | 2012-02-05 21:12:26 -0600 | [diff] [blame] | 392 | padapter->pusb_intf = pusb_intf; |
Larry Finger | 2865d42 | 2010-08-20 10:15:30 -0500 | [diff] [blame] | 393 | usb_set_intfdata(pusb_intf, pnetdev); |
| 394 | SET_NETDEV_DEV(pnetdev, &pusb_intf->dev); |
| 395 | /* step 2. */ |
| 396 | padapter->dvobj_init = &r8712_usb_dvobj_init; |
| 397 | padapter->dvobj_deinit = &r8712_usb_dvobj_deinit; |
| 398 | padapter->halpriv.hal_bus_init = &r8712_usb_hal_bus_init; |
| 399 | padapter->dvobjpriv.inirp_init = &r8712_usb_inirp_init; |
| 400 | padapter->dvobjpriv.inirp_deinit = &r8712_usb_inirp_deinit; |
| 401 | /* step 3. |
| 402 | * initialize the dvobj_priv |
| 403 | */ |
| 404 | if (padapter->dvobj_init == NULL) |
| 405 | goto error; |
| 406 | else { |
| 407 | status = padapter->dvobj_init(padapter); |
| 408 | if (status != _SUCCESS) |
| 409 | goto error; |
| 410 | } |
| 411 | /* step 4. */ |
| 412 | status = r8712_init_drv_sw(padapter); |
| 413 | if (status == _FAIL) |
| 414 | goto error; |
| 415 | /* step 5. read efuse/eeprom data and get mac_addr */ |
| 416 | { |
| 417 | int i, offset; |
| 418 | u8 mac[6]; |
| 419 | u8 tmpU1b, AutoloadFail, eeprom_CustomerID; |
| 420 | u8 *pdata = padapter->eeprompriv.efuse_eeprom_data; |
| 421 | |
| 422 | tmpU1b = r8712_read8(padapter, EE_9346CR);/*CR9346*/ |
| 423 | |
| 424 | /* To check system boot selection.*/ |
| 425 | printk(KERN_INFO "r8712u: Boot from %s: Autoload %s\n", |
| 426 | (tmpU1b & _9356SEL) ? "EEPROM" : "EFUSE", |
| 427 | (tmpU1b & _EEPROM_EN) ? "OK" : "Failed"); |
| 428 | |
| 429 | /* To check autoload success or not.*/ |
| 430 | if (tmpU1b & _EEPROM_EN) { |
| 431 | AutoloadFail = true; |
| 432 | /* The following operations prevent Efuse leakage by |
| 433 | * turning on 2.5V. |
| 434 | */ |
| 435 | tmpU1b = r8712_read8(padapter, EFUSE_TEST+3); |
| 436 | r8712_write8(padapter, EFUSE_TEST + 3, tmpU1b | 0x80); |
| 437 | msleep(20); |
| 438 | r8712_write8(padapter, EFUSE_TEST + 3, |
| 439 | (tmpU1b & (~BIT(7)))); |
| 440 | |
| 441 | /* Retrieve Chip version. |
| 442 | * Recognize IC version by Reg0x4 BIT15. |
| 443 | */ |
| 444 | tmpU1b = (u8)((r8712_read32(padapter, PMC_FSM) >> 15) & |
| 445 | 0x1F); |
| 446 | if (tmpU1b == 0x3) |
| 447 | padapter->registrypriv.chip_version = |
| 448 | RTL8712_3rdCUT; |
| 449 | else |
| 450 | padapter->registrypriv.chip_version = |
| 451 | (tmpU1b >> 1) + 1; |
| 452 | switch (padapter->registrypriv.chip_version) { |
| 453 | case RTL8712_1stCUT: |
| 454 | case RTL8712_2ndCUT: |
| 455 | case RTL8712_3rdCUT: |
| 456 | break; |
| 457 | default: |
| 458 | padapter->registrypriv.chip_version = |
| 459 | RTL8712_2ndCUT; |
| 460 | break; |
| 461 | } |
| 462 | |
| 463 | for (i = 0, offset = 0; i < 128; i += 8, offset++) |
| 464 | r8712_efuse_pg_packet_read(padapter, offset, |
| 465 | &pdata[i]); |
| 466 | |
| 467 | if (r8712_initmac) { |
| 468 | /* Users specify the mac address */ |
| 469 | int jj, kk; |
| 470 | |
| 471 | for (jj = 0, kk = 0; jj < ETH_ALEN; |
| 472 | jj++, kk += 3) |
| 473 | mac[jj] = |
| 474 | key_2char2num(r8712_initmac[kk], |
| 475 | r8712_initmac[kk + 1]); |
| 476 | } else { |
| 477 | /* Use the mac address stored in the Efuse |
| 478 | * offset = 0x12 for usb in efuse |
| 479 | */ |
| 480 | memcpy(mac, &pdata[0x12], ETH_ALEN); |
| 481 | } |
| 482 | eeprom_CustomerID = pdata[0x52]; |
| 483 | switch (eeprom_CustomerID) { |
| 484 | case EEPROM_CID_ALPHA: |
| 485 | padapter->eeprompriv.CustomerID = |
| 486 | RT_CID_819x_ALPHA; |
| 487 | break; |
| 488 | case EEPROM_CID_CAMEO: |
| 489 | padapter->eeprompriv.CustomerID = |
| 490 | RT_CID_819x_CAMEO; |
| 491 | break; |
| 492 | case EEPROM_CID_SITECOM: |
| 493 | padapter->eeprompriv.CustomerID = |
| 494 | RT_CID_819x_Sitecom; |
| 495 | break; |
| 496 | case EEPROM_CID_COREGA: |
| 497 | padapter->eeprompriv.CustomerID = |
| 498 | RT_CID_COREGA; |
| 499 | break; |
| 500 | case EEPROM_CID_Senao: |
| 501 | padapter->eeprompriv.CustomerID = |
| 502 | RT_CID_819x_Senao; |
| 503 | break; |
| 504 | case EEPROM_CID_EDIMAX_BELKIN: |
| 505 | padapter->eeprompriv.CustomerID = |
| 506 | RT_CID_819x_Edimax_Belkin; |
| 507 | break; |
| 508 | case EEPROM_CID_SERCOMM_BELKIN: |
| 509 | padapter->eeprompriv.CustomerID = |
| 510 | RT_CID_819x_Sercomm_Belkin; |
| 511 | break; |
| 512 | case EEPROM_CID_WNC_COREGA: |
| 513 | padapter->eeprompriv.CustomerID = |
| 514 | RT_CID_819x_WNC_COREGA; |
| 515 | break; |
| 516 | case EEPROM_CID_WHQL: |
| 517 | break; |
| 518 | case EEPROM_CID_NetCore: |
| 519 | padapter->eeprompriv.CustomerID = |
| 520 | RT_CID_819x_Netcore; |
| 521 | break; |
| 522 | case EEPROM_CID_CAMEO1: |
| 523 | padapter->eeprompriv.CustomerID = |
| 524 | RT_CID_819x_CAMEO1; |
| 525 | break; |
| 526 | case EEPROM_CID_CLEVO: |
| 527 | padapter->eeprompriv.CustomerID = |
| 528 | RT_CID_819x_CLEVO; |
| 529 | break; |
| 530 | default: |
| 531 | padapter->eeprompriv.CustomerID = |
| 532 | RT_CID_DEFAULT; |
| 533 | break; |
| 534 | } |
| 535 | printk(KERN_INFO "r8712u: CustomerID = 0x%.4x\n", |
| 536 | padapter->eeprompriv.CustomerID); |
| 537 | /* Led mode */ |
| 538 | switch (padapter->eeprompriv.CustomerID) { |
| 539 | case RT_CID_DEFAULT: |
| 540 | case RT_CID_819x_ALPHA: |
| 541 | case RT_CID_819x_CAMEO: |
| 542 | padapter->ledpriv.LedStrategy = SW_LED_MODE1; |
| 543 | padapter->ledpriv.bRegUseLed = true; |
| 544 | break; |
| 545 | case RT_CID_819x_Sitecom: |
| 546 | padapter->ledpriv.LedStrategy = SW_LED_MODE2; |
| 547 | padapter->ledpriv.bRegUseLed = true; |
| 548 | break; |
| 549 | case RT_CID_COREGA: |
| 550 | case RT_CID_819x_Senao: |
| 551 | padapter->ledpriv.LedStrategy = SW_LED_MODE3; |
| 552 | padapter->ledpriv.bRegUseLed = true; |
| 553 | break; |
| 554 | case RT_CID_819x_Edimax_Belkin: |
| 555 | padapter->ledpriv.LedStrategy = SW_LED_MODE4; |
| 556 | padapter->ledpriv.bRegUseLed = true; |
| 557 | break; |
| 558 | case RT_CID_819x_Sercomm_Belkin: |
| 559 | padapter->ledpriv.LedStrategy = SW_LED_MODE5; |
| 560 | padapter->ledpriv.bRegUseLed = true; |
| 561 | break; |
| 562 | case RT_CID_819x_WNC_COREGA: |
| 563 | padapter->ledpriv.LedStrategy = SW_LED_MODE6; |
| 564 | padapter->ledpriv.bRegUseLed = true; |
| 565 | break; |
| 566 | default: |
| 567 | padapter->ledpriv.LedStrategy = SW_LED_MODE0; |
| 568 | padapter->ledpriv.bRegUseLed = false; |
| 569 | break; |
| 570 | } |
| 571 | } else |
| 572 | AutoloadFail = false; |
| 573 | if (((mac[0] == 0xff) && (mac[1] == 0xff) && |
| 574 | (mac[2] == 0xff) && (mac[3] == 0xff) && |
| 575 | (mac[4] == 0xff) && (mac[5] == 0xff)) || |
| 576 | ((mac[0] == 0x00) && (mac[1] == 0x00) && |
| 577 | (mac[2] == 0x00) && (mac[3] == 0x00) && |
| 578 | (mac[4] == 0x00) && (mac[5] == 0x00)) || |
| 579 | (AutoloadFail == false)) { |
| 580 | mac[0] = 0x00; |
| 581 | mac[1] = 0xe0; |
| 582 | mac[2] = 0x4c; |
| 583 | mac[3] = 0x87; |
| 584 | mac[4] = 0x00; |
| 585 | mac[5] = 0x00; |
| 586 | } |
| 587 | if (r8712_initmac) { |
| 588 | /* Make sure the user did not select a multicast |
| 589 | * address by setting bit 1 of first octet. |
| 590 | */ |
| 591 | mac[0] &= 0xFE; |
| 592 | printk(KERN_INFO "r8712u: MAC Address from user = " |
| 593 | "%pM\n", mac); |
| 594 | } else |
| 595 | printk(KERN_INFO "r8712u: MAC Address from efuse = " |
| 596 | "%pM\n", mac); |
| 597 | memcpy(pnetdev->dev_addr, mac, ETH_ALEN); |
| 598 | } |
Larry Finger | 8c213fa59 | 2012-02-05 21:12:26 -0600 | [diff] [blame] | 599 | /* step 6. Load the firmware asynchronously */ |
| 600 | if (rtl871x_load_fw(padapter)) |
Larry Finger | 2865d42 | 2010-08-20 10:15:30 -0500 | [diff] [blame] | 601 | goto error; |
Ali Bahar | ee5b1aa | 2011-09-04 03:14:21 +0800 | [diff] [blame] | 602 | spin_lock_init(&padapter->lockRxFF0Filter); |
Larry Finger | 8c213fa59 | 2012-02-05 21:12:26 -0600 | [diff] [blame] | 603 | mutex_init(&padapter->mutex_start); |
Larry Finger | 2865d42 | 2010-08-20 10:15:30 -0500 | [diff] [blame] | 604 | return 0; |
| 605 | error: |
Ali Bahar | ee5b1aa | 2011-09-04 03:14:21 +0800 | [diff] [blame] | 606 | usb_put_dev(udev); |
Larry Finger | 2865d42 | 2010-08-20 10:15:30 -0500 | [diff] [blame] | 607 | usb_set_intfdata(pusb_intf, NULL); |
| 608 | if (padapter->dvobj_deinit != NULL) |
| 609 | padapter->dvobj_deinit(padapter); |
| 610 | if (pnetdev) |
Ali Bahar | 7bcd9ce | 2011-09-04 03:14:06 +0800 | [diff] [blame] | 611 | free_netdev(pnetdev); |
Larry Finger | 2865d42 | 2010-08-20 10:15:30 -0500 | [diff] [blame] | 612 | return -ENODEV; |
| 613 | } |
| 614 | |
| 615 | /* rmmod module & unplug(SurpriseRemoved) will call r871xu_dev_remove() |
| 616 | * => how to recognize both */ |
| 617 | static void r871xu_dev_remove(struct usb_interface *pusb_intf) |
| 618 | { |
| 619 | struct net_device *pnetdev = usb_get_intfdata(pusb_intf); |
Joe Perches | e33196e | 2010-11-15 13:12:32 -0800 | [diff] [blame] | 620 | struct _adapter *padapter = netdev_priv(pnetdev); |
Larry Finger | 2865d42 | 2010-08-20 10:15:30 -0500 | [diff] [blame] | 621 | struct usb_device *udev = interface_to_usbdev(pusb_intf); |
| 622 | |
Ali Bahar | ee5b1aa | 2011-09-04 03:14:21 +0800 | [diff] [blame] | 623 | usb_set_intfdata(pusb_intf, NULL); |
Larry Finger | 2865d42 | 2010-08-20 10:15:30 -0500 | [diff] [blame] | 624 | if (padapter) { |
Larry Finger | ee6aeff | 2012-03-02 21:06:49 -0600 | [diff] [blame] | 625 | if (padapter->fw_found) |
| 626 | release_firmware(padapter->fw); |
| 627 | /* never exit with a firmware callback pending */ |
| 628 | wait_for_completion(&padapter->rtl8712_fw_ready); |
Larry Finger | 2865d42 | 2010-08-20 10:15:30 -0500 | [diff] [blame] | 629 | if (drvpriv.drv_registered == true) |
| 630 | padapter->bSurpriseRemoved = true; |
| 631 | if (pnetdev != NULL) { |
| 632 | /* will call netdev_close() */ |
| 633 | unregister_netdev(pnetdev); |
| 634 | } |
| 635 | flush_scheduled_work(); |
| 636 | udelay(1); |
Ali Bahar | 6c19d86 | 2011-09-04 03:14:14 +0800 | [diff] [blame] | 637 | /*Stop driver mlme relation timer */ |
Larry Finger | 8c213fa59 | 2012-02-05 21:12:26 -0600 | [diff] [blame] | 638 | if (padapter->fw_found) |
| 639 | r8712_stop_drv_timers(padapter); |
Larry Finger | 2865d42 | 2010-08-20 10:15:30 -0500 | [diff] [blame] | 640 | r871x_dev_unload(padapter); |
| 641 | r8712_free_drv_sw(padapter); |
| 642 | } |
| 643 | usb_set_intfdata(pusb_intf, NULL); |
| 644 | /* decrease the reference count of the usb device structure |
| 645 | * when disconnect */ |
| 646 | usb_put_dev(udev); |
| 647 | /* If we didn't unplug usb dongle and remove/insert modlue, driver |
| 648 | * fails on sitesurvey for the first time when device is up. |
| 649 | * Reset usb port for sitesurvey fail issue. */ |
| 650 | if (udev->state != USB_STATE_NOTATTACHED) |
| 651 | usb_reset_device(udev); |
| 652 | return; |
| 653 | } |
| 654 | |
| 655 | static int __init r8712u_drv_entry(void) |
| 656 | { |
| 657 | drvpriv.drv_registered = true; |
| 658 | return usb_register(&drvpriv.r871xu_drv); |
| 659 | } |
| 660 | |
| 661 | static void __exit r8712u_drv_halt(void) |
| 662 | { |
| 663 | drvpriv.drv_registered = false; |
| 664 | usb_deregister(&drvpriv.r871xu_drv); |
| 665 | printk(KERN_INFO "r8712u: Driver unloaded\n"); |
| 666 | } |
| 667 | |
| 668 | module_init(r8712u_drv_entry); |
| 669 | module_exit(r8712u_drv_halt); |