1 /* $OpenBSD: if_wi_pcmcia.c,v 1.75 2019/12/31 10:05:33 mpi Exp $ */ 2 /* $NetBSD: if_wi_pcmcia.c,v 1.14 2001/11/26 04:34:56 ichiro Exp $ */ 3 4 /* 5 * Copyright (c) 1997, 1998, 1999 6 * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by Bill Paul. 19 * 4. Neither the name of the author nor the names of any co-contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 27 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 33 * THE POSSIBILITY OF SUCH DAMAGE. 34 * 35 * From: if_wi.c,v 1.7 1999/07/04 14:40:22 wpaul Exp $ 36 */ 37 38 /* 39 * Lucent WaveLAN/IEEE 802.11 PCMCIA driver for OpenBSD. 40 * 41 * Originally written by Bill Paul <wpaul@ctr.columbia.edu> 42 * Electrical Engineering Department 43 * Columbia University, New York City 44 */ 45 46 #include <sys/param.h> 47 #include <sys/systm.h> 48 #include <sys/timeout.h> 49 #include <sys/socket.h> 50 #include <sys/device.h> 51 #include <sys/tree.h> 52 53 #include <net/if.h> 54 #include <net/if_media.h> 55 56 #include <netinet/in.h> 57 #include <netinet/if_ether.h> 58 59 #include <net80211/ieee80211_var.h> 60 #include <net80211/ieee80211_ioctl.h> 61 62 #include <machine/bus.h> 63 64 #include <dev/pcmcia/pcmciareg.h> 65 #include <dev/pcmcia/pcmciavar.h> 66 #include <dev/pcmcia/pcmciadevs.h> 67 68 #include <dev/ic/if_wireg.h> 69 #include <dev/ic/if_wi_ieee.h> 70 #include <dev/ic/if_wivar.h> 71 72 int wi_pcmcia_match(struct device *, void *, void *); 73 void wi_pcmcia_attach(struct device *, struct device *, void *); 74 int wi_pcmcia_detach(struct device *, int); 75 int wi_pcmcia_activate(struct device *, int); 76 void wi_pcmcia_wakeup(struct wi_softc *); 77 78 struct wi_pcmcia_softc { 79 struct wi_softc sc_wi; 80 81 struct pcmcia_io_handle sc_pcioh; 82 int sc_io_window; 83 struct pcmcia_function *sc_pf; 84 }; 85 86 struct cfattach wi_pcmcia_ca = { 87 sizeof (struct wi_pcmcia_softc), wi_pcmcia_match, wi_pcmcia_attach, 88 wi_pcmcia_detach, wi_pcmcia_activate 89 }; 90 91 static const struct wi_pcmcia_product { 92 u_int16_t pp_vendor; 93 u_int16_t pp_product; 94 const char *pp_cisinfo[4]; 95 } wi_pcmcia_products[] = { 96 { PCMCIA_VENDOR_LUCENT, 97 PCMCIA_PRODUCT_LUCENT_WAVELAN_IEEE, 98 PCMCIA_CIS_LUCENT_WAVELAN_IEEE 99 }, 100 { PCMCIA_VENDOR_3COM, 101 PCMCIA_PRODUCT_3COM_3CRWE737A, 102 PCMCIA_CIS_3COM_3CRWE737A 103 }, 104 { PCMCIA_VENDOR_3COM, 105 PCMCIA_PRODUCT_3COM_3CRWE777A, 106 PCMCIA_CIS_3COM_3CRWE777A 107 }, 108 { PCMCIA_VENDOR_COREGA, 109 PCMCIA_PRODUCT_COREGA_WIRELESS_LAN_PCC_11, 110 PCMCIA_CIS_COREGA_WIRELESS_LAN_PCC_11 111 }, 112 { PCMCIA_VENDOR_COREGA, 113 PCMCIA_PRODUCT_COREGA_WIRELESS_LAN_PCCA_11, 114 PCMCIA_CIS_COREGA_WIRELESS_LAN_PCCA_11 115 }, 116 { PCMCIA_VENDOR_COREGA, 117 PCMCIA_PRODUCT_COREGA_WIRELESS_LAN_PCCB_11, 118 PCMCIA_CIS_COREGA_WIRELESS_LAN_PCCB_11 119 }, 120 { PCMCIA_VENDOR_COREGA, 121 PCMCIA_PRODUCT_COREGA_WIRELESS_LAN_PCCL_11, 122 PCMCIA_CIS_COREGA_WIRELESS_LAN_PCCL_11 123 }, 124 { PCMCIA_VENDOR_COREGA, 125 PCMCIA_PRODUCT_COREGA_WIRELESS_LAN_WLCFL_11, 126 PCMCIA_CIS_COREGA_WIRELESS_LAN_WLCFL_11 127 }, 128 { PCMCIA_VENDOR_INTEL, 129 PCMCIA_PRODUCT_INTEL_PRO_WLAN_2011, 130 PCMCIA_CIS_INTEL_PRO_WLAN_2011 131 }, 132 { PCMCIA_VENDOR_INTERSIL, 133 PCMCIA_PRODUCT_INTERSIL_PRISM2, 134 PCMCIA_CIS_INTERSIL_PRISM2 135 }, 136 { PCMCIA_VENDOR_SAMSUNG, 137 PCMCIA_PRODUCT_SAMSUNG_SWL_2000N, 138 PCMCIA_CIS_SAMSUNG_SWL_2000N 139 }, 140 { PCMCIA_VENDOR_LINKSYS2, 141 PCMCIA_PRODUCT_LINKSYS2_IWN, 142 PCMCIA_CIS_LINKSYS2_IWN 143 }, 144 { PCMCIA_VENDOR_LINKSYS2, 145 PCMCIA_PRODUCT_LINKSYS2_IWN2, 146 PCMCIA_CIS_LINKSYS2_IWN2 147 }, 148 { PCMCIA_VENDOR_LINKSYS2, 149 PCMCIA_PRODUCT_LINKSYS2_WCF11, 150 PCMCIA_CIS_LINKSYS2_WCF11 151 }, 152 { PCMCIA_VENDOR_LUCENT, 153 PCMCIA_PRODUCT_LUCENT_WAVELAN_IEEE, 154 PCMCIA_CIS_SMC_2632W 155 }, 156 { PCMCIA_VENDOR_LUCENT, 157 PCMCIA_PRODUCT_LUCENT_WAVELAN_IEEE, 158 PCMCIA_CIS_NANOSPEED_PRISM2 159 }, 160 { PCMCIA_VENDOR_ELSA, 161 PCMCIA_PRODUCT_ELSA_XI300_IEEE, 162 PCMCIA_CIS_ELSA_XI300_IEEE 163 }, 164 { PCMCIA_VENDOR_ELSA, 165 PCMCIA_PRODUCT_ELSA_XI325_IEEE, 166 PCMCIA_CIS_ELSA_XI325_IEEE 167 }, 168 { PCMCIA_VENDOR_ELSA, 169 PCMCIA_PRODUCT_ELSA_WNB11CFZ, 170 PCMCIA_CIS_ELSA_WNB11CFZ 171 }, 172 { PCMCIA_VENDOR_COMPAQ, 173 PCMCIA_PRODUCT_COMPAQ_NC5004, 174 PCMCIA_CIS_COMPAQ_NC5004 175 }, 176 { PCMCIA_VENDOR_CONTEC, 177 PCMCIA_PRODUCT_CONTEC_FX_DS110_PCC, 178 PCMCIA_CIS_CONTEC_FX_DS110_PCC 179 }, 180 { PCMCIA_VENDOR_TDK, 181 PCMCIA_PRODUCT_TDK_LAK_CD011WL, 182 PCMCIA_CIS_TDK_LAK_CD011WL 183 }, 184 { PCMCIA_VENDOR_LUCENT, 185 PCMCIA_PRODUCT_LUCENT_WAVELAN_IEEE, 186 PCMCIA_CIS_NEC_CMZ_RT_WP 187 }, 188 { PCMCIA_VENDOR_LUCENT, 189 PCMCIA_PRODUCT_LUCENT_WAVELAN_IEEE, 190 PCMCIA_CIS_NTT_ME_WLAN 191 }, 192 { PCMCIA_VENDOR_ADDTRON, 193 PCMCIA_PRODUCT_ADDTRON_AWP100, 194 PCMCIA_CIS_ADDTRON_AWP100 195 }, 196 { PCMCIA_VENDOR_LUCENT, 197 PCMCIA_PRODUCT_LUCENT_WAVELAN_IEEE, 198 PCMCIA_CIS_CABLETRON_ROAMABOUT 199 }, 200 { PCMCIA_VENDOR_IODATA2, 201 PCMCIA_PRODUCT_IODATA2_WCF12, 202 PCMCIA_CIS_IODATA2_WCF12 203 }, 204 { PCMCIA_VENDOR_IODATA2, 205 PCMCIA_PRODUCT_IODATA2_WNB11PCM, 206 PCMCIA_CIS_IODATA2_WNB11PCM 207 }, 208 { PCMCIA_VENDOR_GEMTEK, 209 PCMCIA_PRODUCT_GEMTEK_WLAN, 210 PCMCIA_CIS_GEMTEK_WLAN 211 }, 212 { PCMCIA_VENDOR_ELSA, 213 PCMCIA_PRODUCT_ELSA_XI800_IEEE, 214 PCMCIA_CIS_ELSA_XI800_IEEE 215 }, 216 { PCMCIA_VENDOR_BUFFALO, 217 PCMCIA_PRODUCT_BUFFALO_WLI_PCM_S11, 218 PCMCIA_CIS_BUFFALO_WLI_PCM_S11 219 }, 220 { PCMCIA_VENDOR_BUFFALO, 221 PCMCIA_PRODUCT_BUFFALO_WLI_CF_S11G, 222 PCMCIA_CIS_BUFFALO_WLI_CF_S11G 223 }, 224 { PCMCIA_VENDOR_EMTAC, 225 PCMCIA_PRODUCT_EMTAC_WLAN, 226 PCMCIA_CIS_EMTAC_WLAN 227 }, 228 { PCMCIA_VENDOR_SIMPLETECH, 229 PCMCIA_PRODUCT_SIMPLETECH_SPECTRUM24_ALT, 230 PCMCIA_CIS_SIMPLETECH_SPECTRUM24_ALT 231 }, 232 { PCMCIA_VENDOR_ERICSSON, 233 PCMCIA_PRODUCT_ERICSSON_WIRELESSLAN, 234 PCMCIA_CIS_ERICSSON_WIRELESSLAN 235 }, 236 { PCMCIA_VENDOR_PROXIM, 237 PCMCIA_PRODUCT_PROXIM_RANGELANDS_8430, 238 PCMCIA_CIS_PROXIM_RANGELANDS_8430 239 }, 240 { PCMCIA_VENDOR_ACTIONTEC, 241 PCMCIA_PRODUCT_ACTIONTEC_HWC01170, 242 PCMCIA_CIS_ACTIONTEC_HWC01170 243 }, 244 { PCMCIA_VENDOR_NOKIA, 245 PCMCIA_PRODUCT_NOKIA_C020_WLAN, 246 PCMCIA_CIS_NOKIA_C020_WLAN 247 }, 248 { PCMCIA_VENDOR_NOKIA, 249 PCMCIA_PRODUCT_NOKIA_C110_WLAN, 250 PCMCIA_CIS_NOKIA_C110_WLAN 251 }, 252 { PCMCIA_VENDOR_NETGEAR2, 253 PCMCIA_PRODUCT_NETGEAR2_MA401RA, 254 PCMCIA_CIS_NETGEAR2_MA401RA 255 }, 256 { PCMCIA_VENDOR_NETGEAR2, 257 PCMCIA_PRODUCT_NETGEAR2_DWL650, 258 PCMCIA_CIS_NETGEAR2_DWL650 259 }, 260 { PCMCIA_VENDOR_AIRVAST, 261 PCMCIA_PRODUCT_AIRVAST_WN_100, 262 PCMCIA_CIS_AIRVAST_WN_100 263 }, 264 { PCMCIA_VENDOR_SIEMENS, 265 PCMCIA_PRODUCT_SIEMENS_SS1021, 266 PCMCIA_CIS_SIEMENS_SS1021 267 }, 268 { PCMCIA_VENDOR_PROXIM, 269 PCMCIA_PRODUCT_PROXIM_HARMONY_80211B, 270 PCMCIA_CIS_PROXIM_HARMONY_80211B 271 }, 272 { PCMCIA_VENDOR_MICROSOFT, 273 PCMCIA_PRODUCT_MICROSOFT_MN520, 274 PCMCIA_CIS_MICROSOFT_MN520 275 }, 276 { PCMCIA_VENDOR_ADAPTEC2, 277 PCMCIA_PRODUCT_ADAPTEC2_AWN8030, 278 PCMCIA_CIS_ADAPTEC2_AWN8030 279 }, 280 { PCMCIA_VENDOR_ASUS, 281 PCMCIA_PRODUCT_ASUS_WL_100, 282 PCMCIA_CIS_ASUS_WL_100 283 }, 284 { PCMCIA_VENDOR_SENAO, 285 PCMCIA_PRODUCT_SENAO_EL2511CD2EM, 286 PCMCIA_CIS_SENAO_EL2511CD2EM 287 }, 288 { PCMCIA_VENDOR_ARTEM, 289 PCMCIA_PRODUCT_ARTEM_ONAIR, 290 PCMCIA_CIS_ARTEM_ONAIR 291 }, 292 { PCMCIA_VENDOR_PLANEX, 293 PCMCIA_PRODUCT_PLANEX_GWNS11H, 294 PCMCIA_CIS_PLANEX_GWNS11H 295 }, 296 { PCMCIA_VENDOR_SYMBOL, 297 PCMCIA_PRODUCT_SYMBOL_LA4100, 298 PCMCIA_CIS_SYMBOL_LA4100 299 }, 300 { PCMCIA_VENDOR_BAY, 301 PCMCIA_PRODUCT_BAY_EMOBILITY_11B, 302 PCMCIA_CIS_BAY_EMOBILITY_11B 303 }, 304 { PCMCIA_VENDOR_GREYCELL, 305 PCMCIA_PRODUCT_GREYCELL_DWL650H, 306 PCMCIA_CIS_GREYCELL_DWL650H 307 }, 308 { PCMCIA_VENDOR_FUJITSU, 309 PCMCIA_PRODUCT_FUJITSU_WL110, 310 PCMCIA_CIS_FUJITSU_WL110 311 }, 312 { PCMCIA_VENDOR_ALLIEDTELESIS, 313 PCMCIA_PRODUCT_ALLIEDTELESIS_WR211PCM, 314 PCMCIA_CIS_ALLIEDTELESIS_WR211PCM 315 }, 316 { PCMCIA_VENDOR_HWN, 317 PCMCIA_PRODUCT_HWN_AIRWAY80211, 318 PCMCIA_CIS_HWN_AIRWAY80211 319 }, 320 { PCMCIA_VENDOR_SOCKET, 321 PCMCIA_PRODUCT_SOCKET_LP_WLAN_CF, 322 PCMCIA_CIS_SOCKET_LP_WLAN_CF 323 } 324 }; 325 326 static const struct wi_pcmcia_product *wi_lookup(struct pcmcia_attach_args *pa); 327 328 const struct wi_pcmcia_product * 329 wi_lookup(struct pcmcia_attach_args *pa) 330 { 331 const struct wi_pcmcia_product *pp; 332 const struct wi_pcmcia_product *epp = wi_pcmcia_products + 333 sizeof(wi_pcmcia_products) / sizeof(wi_pcmcia_products[0]); 334 335 /* 336 * Several PRISM II-based cards use the Lucent WaveLAN vendor 337 * and product IDs so we match by CIS information first. 338 */ 339 for (pp = wi_pcmcia_products; pp < epp; pp++) { 340 if (pa->card->cis1_info[0] != NULL && 341 pp->pp_cisinfo[0] != NULL && 342 strcmp(pa->card->cis1_info[0], pp->pp_cisinfo[0]) == 0 && 343 pa->card->cis1_info[1] != NULL && 344 pp->pp_cisinfo[1] != NULL && 345 strcmp(pa->card->cis1_info[1], pp->pp_cisinfo[1]) == 0) 346 return (pp); 347 } 348 349 /* Match by vendor/product ID. */ 350 for (pp = wi_pcmcia_products; pp < epp; pp++) { 351 if (pa->manufacturer != PCMCIA_VENDOR_INVALID && 352 pa->manufacturer == pp->pp_vendor && 353 pa->product != PCMCIA_PRODUCT_INVALID && 354 pa->product == pp->pp_product) 355 return (pp); 356 } 357 358 return (NULL); 359 } 360 361 int 362 wi_pcmcia_match(struct device *parent, void *match, void *aux) 363 { 364 struct pcmcia_attach_args *pa = aux; 365 366 if (wi_lookup(pa) != NULL) 367 return (1); 368 return (0); 369 } 370 371 void 372 wi_pcmcia_attach(struct device *parent, struct device *self, void *aux) 373 { 374 struct wi_pcmcia_softc *psc = (struct wi_pcmcia_softc *)self; 375 struct wi_softc *sc = &psc->sc_wi; 376 struct pcmcia_attach_args *pa = aux; 377 struct pcmcia_function *pf = pa->pf; 378 struct pcmcia_config_entry *cfe = SIMPLEQ_FIRST(&pf->cfe_head); 379 const char *intrstr; 380 int state = 0; 381 382 psc->sc_pf = pf; 383 384 /* Enable the card. */ 385 pcmcia_function_init(pf, cfe); 386 if (pcmcia_function_enable(pf)) { 387 printf(": function enable failed\n"); 388 goto bad; 389 } 390 state++; 391 392 if (pcmcia_io_alloc(pf, 0, WI_IOSIZ, WI_IOSIZ, &psc->sc_pcioh)) { 393 printf(": can't alloc i/o space\n"); 394 goto bad; 395 } 396 state++; 397 398 if (pcmcia_io_map(pf, PCMCIA_WIDTH_IO16, 0, WI_IOSIZ, 399 &psc->sc_pcioh, &psc->sc_io_window)) { 400 printf(": can't map i/o space\n"); 401 goto bad; 402 } 403 state++; 404 405 printf(" port 0x%lx/%lu", psc->sc_pcioh.addr, 406 (u_long)psc->sc_pcioh.size); 407 408 sc->wi_ltag = sc->wi_btag = psc->sc_pcioh.iot; 409 sc->wi_lhandle = sc->wi_bhandle = psc->sc_pcioh.ioh; 410 sc->wi_cor_offset = WI_COR_OFFSET; 411 sc->wi_flags |= WI_FLAGS_BUS_PCMCIA; 412 413 /* Make sure interrupts are disabled. */ 414 CSR_WRITE_2(sc, WI_INT_EN, 0); 415 CSR_WRITE_2(sc, WI_EVENT_ACK, 0xffff); 416 417 /* Establish the interrupt. */ 418 sc->sc_ih = pcmcia_intr_establish(pa->pf, IPL_NET, wi_intr, psc, 419 sc->sc_dev.dv_xname); 420 if (sc->sc_ih == NULL) { 421 printf("%s: can't establish interrupt\n", 422 sc->sc_dev.dv_xname); 423 goto bad; 424 } 425 426 intrstr = pcmcia_intr_string(psc->sc_pf, sc->sc_ih); 427 printf("%s%s\n", *intrstr ? ", " : "", intrstr); 428 if (wi_attach(sc, &wi_func_io) == 0) 429 return; 430 431 /* wi_attach() failed, do some cleanup */ 432 pcmcia_intr_disestablish(psc->sc_pf, sc->sc_ih); 433 sc->sc_ih = NULL; 434 435 bad: 436 if (state > 2) 437 pcmcia_io_unmap(pf, psc->sc_io_window); 438 if (state > 1) 439 pcmcia_io_free(pf, &psc->sc_pcioh); 440 if (state > 0) 441 pcmcia_function_disable(pf); 442 } 443 444 int 445 wi_pcmcia_detach(struct device *dev, int flags) 446 { 447 struct wi_pcmcia_softc *psc = (struct wi_pcmcia_softc *)dev; 448 struct wi_softc *sc = &psc->sc_wi; 449 struct ifnet *ifp = &sc->sc_ic.ic_if; 450 451 if (!(sc->wi_flags & WI_FLAGS_ATTACHED)) 452 return (0); 453 454 wi_detach(sc); 455 456 sc->wi_flags = 0; 457 458 pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window); 459 pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh); 460 461 ether_ifdetach(ifp); 462 if_detach(ifp); 463 464 return (0); 465 } 466 467 int 468 wi_pcmcia_activate(struct device *dev, int act) 469 { 470 struct wi_pcmcia_softc *psc = (struct wi_pcmcia_softc *)dev; 471 struct wi_softc *sc = &psc->sc_wi; 472 struct ifnet *ifp = &sc->sc_ic.ic_if; 473 474 switch (act) { 475 case DVACT_SUSPEND: 476 ifp->if_timer = 0; 477 if (ifp->if_flags & IFF_RUNNING) 478 wi_stop(sc); 479 sc->wi_flags &= ~WI_FLAGS_INITIALIZED; 480 if (sc->sc_ih != NULL) 481 pcmcia_intr_disestablish(psc->sc_pf, sc->sc_ih); 482 sc->sc_ih = NULL; 483 pcmcia_function_disable(psc->sc_pf); 484 break; 485 case DVACT_RESUME: 486 pcmcia_function_enable(psc->sc_pf); 487 sc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET, 488 wi_intr, sc, sc->sc_dev.dv_xname); 489 break; 490 case DVACT_WAKEUP: 491 wi_pcmcia_wakeup(sc); 492 break; 493 case DVACT_DEACTIVATE: 494 if (sc->sc_ih != NULL) 495 pcmcia_intr_disestablish(psc->sc_pf, sc->sc_ih); 496 sc->sc_ih = NULL; 497 pcmcia_function_disable(psc->sc_pf); 498 break; 499 } 500 return (0); 501 } 502 503 void 504 wi_pcmcia_wakeup(struct wi_softc *sc) 505 { 506 int s; 507 508 s = splnet(); 509 while (sc->wi_flags & WI_FLAGS_BUSY) 510 tsleep_nsec(&sc->wi_flags, 0, "wipwr", INFSLP); 511 sc->wi_flags |= WI_FLAGS_BUSY; 512 513 wi_cor_reset(sc); 514 wi_init(sc); 515 516 sc->wi_flags &= ~WI_FLAGS_BUSY; 517 wakeup(&sc->wi_flags); 518 splx(s); 519 } 520