1 /* $OpenBSD: if_wi_pcmcia.c,v 1.15 2001/12/05 21:04:11 mickey 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 52 #include <net/if.h> 53 #include <net/if_dl.h> 54 #include <net/if_media.h> 55 56 #ifdef INET 57 #include <netinet/in.h> 58 #include <netinet/if_ether.h> 59 #endif 60 61 #include <net/if_ieee80211.h> 62 63 #include <machine/bus.h> 64 65 #include <dev/pcmcia/pcmciareg.h> 66 #include <dev/pcmcia/pcmciavar.h> 67 #include <dev/pcmcia/pcmciadevs.h> 68 69 #include <dev/ic/if_wireg.h> 70 #include <dev/ic/if_wi_ieee.h> 71 #include <dev/ic/if_wivar.h> 72 73 int wi_pcmcia_match __P((struct device *, void *, void *)); 74 void wi_pcmcia_attach __P((struct device *, struct device *, void *)); 75 int wi_pcmcia_detach __P((struct device *, int)); 76 int wi_pcmcia_activate __P((struct device *, enum devact)); 77 void wi_pcmcia_attach __P((struct device *, struct device *, void *)); 78 79 int wi_intr __P((void *)); 80 int wi_attach __P((struct wi_softc *, int)); 81 void wi_init __P((void *)); 82 void wi_stop __P((struct wi_softc *)); 83 84 struct wi_pcmcia_softc { 85 struct wi_softc sc_wi; 86 87 struct pcmcia_io_handle sc_pcioh; 88 int sc_io_window; 89 struct pcmcia_function *sc_pf; 90 }; 91 92 struct cfattach wi_pcmcia_ca = { 93 sizeof (struct wi_pcmcia_softc), wi_pcmcia_match, wi_pcmcia_attach, 94 wi_pcmcia_detach, wi_pcmcia_activate 95 }; 96 97 static const struct wi_pcmcia_product { 98 u_int16_t pp_vendor; 99 u_int16_t pp_product; 100 const char *pp_cisinfo[4]; 101 const char *pp_name; 102 } wi_pcmcia_products[] = { 103 { PCMCIA_VENDOR_LUCENT, 104 PCMCIA_PRODUCT_LUCENT_WAVELAN_IEEE, 105 PCMCIA_CIS_LUCENT_WAVELAN_IEEE, 106 "WaveLAN/IEEE" 107 }, 108 { PCMCIA_VENDOR_3COM, 109 PCMCIA_PRODUCT_3COM_3CRWE737A, 110 PCMCIA_CIS_3COM_3CRWE737A, 111 "3Com AirConnect Wireless LAN" 112 }, 113 { PCMCIA_VENDOR_COREGA, 114 PCMCIA_PRODUCT_COREGA_WIRELESS_LAN_PCC_11, 115 PCMCIA_CIS_COREGA_WIRELESS_LAN_PCC_11, 116 "Corega Wireless LAN PCC-11" 117 }, 118 { PCMCIA_VENDOR_COREGA, 119 PCMCIA_PRODUCT_COREGA_WIRELESS_LAN_PCCA_11, 120 PCMCIA_CIS_COREGA_WIRELESS_LAN_PCCA_11, 121 "Corega Wireless LAN PCCA-11", 122 }, 123 { PCMCIA_VENDOR_COREGA, 124 PCMCIA_PRODUCT_COREGA_WIRELESS_LAN_PCCB_11, 125 PCMCIA_CIS_COREGA_WIRELESS_LAN_PCCB_11, 126 "Corega Wireless LAN PCCB-11", 127 }, 128 { PCMCIA_VENDOR_INTEL, 129 PCMCIA_PRODUCT_INTEL_PRO_WLAN_2011, 130 PCMCIA_CIS_INTEL_PRO_WLAN_2011, 131 "Intel PRO/Wireless 2011", 132 }, 133 { PCMCIA_VENDOR_INTERSIL, 134 PCMCIA_PRODUCT_INTERSIL_PRISM2, 135 PCMCIA_CIS_INTERSIL_PRISM2, 136 "Intersil Prism II", 137 }, 138 { PCMCIA_VENDOR_SAMSUNG, 139 PCMCIA_PRODUCT_SAMSUNG_SWL_2000N, 140 PCMCIA_CIS_SAMSUNG_SWL_2000N, 141 "Samsung MagicLAN SWL-2000N", 142 }, 143 { PCMCIA_VENDOR_LINKSYS2, 144 PCMCIA_PRODUCT_LINKSYS2_IWN, 145 PCMCIA_CIS_LINKSYS2_IWN, 146 "Linksys Instant Wireless Network", 147 }, 148 { PCMCIA_VENDOR_LUCENT, 149 PCMCIA_PRODUCT_LUCENT_WAVELAN_IEEE, 150 PCMCIA_CIS_SMC_2632W, 151 "SMC 2632 EZ Connect Wireless PC Card", 152 }, 153 { PCMCIA_VENDOR_LUCENT, 154 PCMCIA_PRODUCT_LUCENT_WAVELAN_IEEE, 155 PCMCIA_CIS_NANOSPEED_PRISM2, 156 "NANOSPEED ROOT-RZ2000 WLAN Card", 157 }, 158 { PCMCIA_VENDOR_ELSA, 159 PCMCIA_PRODUCT_ELSA_XI300_IEEE, 160 PCMCIA_CIS_ELSA_XI300_IEEE, 161 "XI300 Wireless LAN", 162 }, 163 { PCMCIA_VENDOR_COMPAQ, 164 PCMCIA_PRODUCT_COMPAQ_NC5004, 165 PCMCIA_CIS_COMPAQ_NC5004, 166 "Compaq Agency NC5004 Wireless Card", 167 }, 168 { PCMCIA_VENDOR_CONTEC, 169 PCMCIA_PRODUCT_CONTEC_FX_DS110_PCC, 170 PCMCIA_CIS_CONTEC_FX_DS110_PCC, 171 "Contec FLEXLAN/FX-DS110-PCC", 172 }, 173 { PCMCIA_VENDOR_TDK, 174 PCMCIA_PRODUCT_TDK_LAK_CD011WL, 175 PCMCIA_CIS_TDK_LAK_CD011WL, 176 "TDK LAK-CD011WL", 177 }, 178 { PCMCIA_VENDOR_LUCENT, 179 PCMCIA_PRODUCT_LUCENT_WAVELAN_IEEE, 180 PCMCIA_CIS_NEC_CMZ_RT_WP, 181 "NEC Wireless Card CMZ-RT-WP", 182 }, 183 { PCMCIA_VENDOR_LUCENT, 184 PCMCIA_PRODUCT_LUCENT_WAVELAN_IEEE, 185 PCMCIA_CIS_NTT_ME_WLAN, 186 "NTT-ME 11Mbps Wireless LAN PC Card", 187 }, 188 { PCMCIA_VENDOR_ADDTRON, 189 PCMCIA_PRODUCT_ADDTRON_AWP100, 190 PCMCIA_CIS_ADDTRON_AWP100, 191 "Addtron AWP-100", 192 }, 193 { PCMCIA_VENDOR_LUCENT, 194 PCMCIA_PRODUCT_LUCENT_WAVELAN_IEEE, 195 PCMCIA_CIS_CABLETRON_ROAMABOUT, 196 "Cabletron RoamAbout", 197 }, 198 { PCMCIA_VENDOR_IODATA2, 199 PCMCIA_PRODUCT_IODATA2_WNB11PCM, 200 PCMCIA_CIS_IODATA2_WNB11PCM, 201 "I-O DATA WN-B11/PCM", 202 }, 203 { PCMCIA_VENDOR_GEMTEK, 204 PCMCIA_PRODUCT_GEMTEK_WLAN, 205 PCMCIA_CIS_GEMTEK_WLAN, 206 "GEMTEK Prism2_5 WaveLAN Card" 207 }, 208 { PCMCIA_VENDOR_ELSA, 209 PCMCIA_PRODUCT_ELSA_XI800_IEEE, 210 PCMCIA_CIS_ELSA_XI800_IEEE, 211 "ELSA XI800 CF Wireless LAN" 212 }, 213 { PCMCIA_VENDOR_BUFFALO, 214 PCMCIA_PRODUCT_BUFFALO_WLI_PCM_S11, 215 PCMCIA_CIS_BUFFALO_WLI_PCM_S11, 216 "BUFFALO AirStation 11Mbps WLAN" 217 }, 218 { PCMCIA_VENDOR_BUFFALO, 219 PCMCIA_PRODUCT_BUFFALO_WLI_CF_S11G, 220 PCMCIA_CIS_BUFFALO_WLI_CF_S11G, 221 "BUFFALO AirStation 11Mbps CF WLAN" 222 }, 223 { PCMCIA_VENDOR_EMTAC, 224 PCMCIA_PRODUCT_EMTAC_WLAN, 225 PCMCIA_CIS_EMTAC_WLAN, 226 "EMTAC A2424i 11Mbps WLAN Card" 227 }, 228 { PCMCIA_VENDOR_SIMPLETECH, 229 PCMCIA_PRODUCT_SIMPLETECH_SPECTRUM24_ALT, 230 PCMCIA_CIS_SIMPLETECH_SPECTRUM24_ALT, 231 "LA4111 Spectrum24 WLAN PC Card" 232 }, 233 { 0, 234 0, 235 { NULL, NULL, NULL, NULL }, 236 NULL, 237 } 238 }; 239 240 static const struct wi_pcmcia_product *wi_lookup __P((struct pcmcia_attach_args *pa)); 241 242 const struct wi_pcmcia_product * 243 wi_lookup(pa) 244 struct pcmcia_attach_args *pa; 245 { 246 const struct wi_pcmcia_product *pp; 247 248 /* 249 * Several PRISM II-based cards use the Lucent WaveLAN vendor 250 * and product IDs so we match by CIS information first. 251 */ 252 for (pp = wi_pcmcia_products; pp->pp_name != NULL; pp++) { 253 if (pa->card->cis1_info[0] != NULL && 254 pp->pp_cisinfo[0] != NULL && 255 strcmp(pa->card->cis1_info[0], pp->pp_cisinfo[0]) == 0 && 256 pa->card->cis1_info[1] != NULL && 257 pp->pp_cisinfo[1] != NULL && 258 strcmp(pa->card->cis1_info[1], pp->pp_cisinfo[1]) == 0) 259 return (pp); 260 } 261 262 /* Match by vendor/product ID. */ 263 for (pp = wi_pcmcia_products; pp->pp_name != NULL; pp++) { 264 if (pa->manufacturer != PCMCIA_VENDOR_INVALID && 265 pa->manufacturer == pp->pp_vendor && 266 pa->product != PCMCIA_PRODUCT_INVALID && 267 pa->product == pp->pp_product) 268 return (pp); 269 } 270 271 return (NULL); 272 } 273 274 int 275 wi_pcmcia_match(parent, match, aux) 276 struct device *parent; 277 void *match, *aux; 278 { 279 struct pcmcia_attach_args *pa = aux; 280 281 if (wi_lookup(pa) != NULL) 282 return (1); 283 return (0); 284 } 285 286 void 287 wi_pcmcia_attach(parent, self, aux) 288 struct device *parent, *self; 289 void *aux; 290 { 291 struct wi_pcmcia_softc *psc = (struct wi_pcmcia_softc *)self; 292 struct wi_softc *sc = &psc->sc_wi; 293 struct pcmcia_attach_args *pa = aux; 294 struct pcmcia_function *pf = pa->pf; 295 struct pcmcia_config_entry *cfe = pf->cfe_head.sqh_first; 296 int state = 0; 297 298 psc->sc_pf = pf; 299 300 /* Enable the card. */ 301 pcmcia_function_init(pf, cfe); 302 if (pcmcia_function_enable(pf)) { 303 printf(": function enable failed\n"); 304 goto bad; 305 } 306 state++; 307 308 if (pcmcia_io_alloc(pf, 0, WI_IOSIZ, WI_IOSIZ, &psc->sc_pcioh)) { 309 printf(": can't alloc i/o space\n"); 310 goto bad; 311 } 312 state++; 313 314 if (pcmcia_io_map(pf, PCMCIA_WIDTH_IO16, 0, WI_IOSIZ, 315 &psc->sc_pcioh, &psc->sc_io_window)) { 316 printf(": can't map io space\n"); 317 goto bad; 318 } 319 state++; 320 321 sc->wi_btag = psc->sc_pcioh.iot; 322 sc->wi_bhandle = psc->sc_pcioh.ioh; 323 324 /* Make sure interrupts are disabled. */ 325 CSR_WRITE_2(sc, WI_INT_EN, 0); 326 CSR_WRITE_2(sc, WI_EVENT_ACK, 0xffff); 327 328 /* Establish the interrupt. */ 329 sc->sc_ih = pcmcia_intr_establish(pa->pf, IPL_NET, wi_intr, psc, ""); 330 if (sc->sc_ih == NULL) { 331 printf("%s: couldn't establish interrupt\n", 332 sc->sc_dev.dv_xname); 333 goto bad; 334 } 335 336 wi_attach(sc, 0); 337 return; 338 339 bad: 340 if (state > 2) 341 pcmcia_io_unmap(pf, psc->sc_io_window); 342 if (state > 1) 343 pcmcia_io_free(pf, &psc->sc_pcioh); 344 if (state > 0) 345 pcmcia_function_disable(pf); 346 } 347 348 int 349 wi_pcmcia_detach(dev, flags) 350 struct device *dev; 351 int flags; 352 { 353 struct wi_pcmcia_softc *psc = (struct wi_pcmcia_softc *)dev; 354 struct wi_softc *sc = &psc->sc_wi; 355 struct ifnet *ifp = &sc->arpcom.ac_if; 356 357 pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window); 358 pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh); 359 360 ether_ifdetach(ifp); 361 if_detach(ifp); 362 363 return (0); 364 } 365 366 int 367 wi_pcmcia_activate(dev, act) 368 struct device *dev; 369 enum devact act; 370 { 371 struct wi_pcmcia_softc *psc = (struct wi_pcmcia_softc *)dev; 372 struct wi_softc *sc = &psc->sc_wi; 373 struct ifnet *ifp = &sc->arpcom.ac_if; 374 int s; 375 376 s = splnet(); 377 switch (act) { 378 case DVACT_ACTIVATE: 379 pcmcia_function_enable(psc->sc_pf); 380 sc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET, 381 wi_intr, sc, sc->sc_dev.dv_xname); 382 wi_init(sc); 383 break; 384 385 case DVACT_DEACTIVATE: 386 ifp->if_timer = 0; 387 if (ifp->if_flags & IFF_RUNNING) 388 wi_stop(sc); 389 pcmcia_intr_disestablish(psc->sc_pf, sc->sc_ih); 390 pcmcia_function_disable(psc->sc_pf); 391 break; 392 } 393 splx(s); 394 return (0); 395 } 396