Annotation of sys/dev/pci/if_wi_pci.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: if_wi_pci.c,v 1.43 2006/11/26 19:46:28 deraadt Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 2001-2003 Todd C. Miller <Todd.Miller@courtesan.com>
! 5: *
! 6: * Permission to use, copy, modify, and distribute this software for any
! 7: * purpose with or without fee is hereby granted, provided that the above
! 8: * copyright notice and this permission notice appear in all copies.
! 9: *
! 10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 17: *
! 18: * Sponsored in part by the Defense Advanced Research Projects
! 19: * Agency (DARPA) and Air Force Research Laboratory, Air Force
! 20: * Materiel Command, USAF, under agreement number F39502-99-1-0512.
! 21: */
! 22:
! 23: /*
! 24: * PCI attachment for the Wavelan driver. There are two basic types
! 25: * of PCI card supported:
! 26: *
! 27: * 1) Cards based on the Prism2.5 Mini-PCI chipset
! 28: * 2) Cards that use a dumb PCMCIA->PCI bridge
! 29: *
! 30: * Only the first type are "true" PCI cards.
! 31: *
! 32: * The latter are simply PCMCIA cards (or the guts of same) with some
! 33: * type of dumb PCMCIA->PCI bridge. They are "dumb" in that they
! 34: * are not true PCMCIA bridges and really just serve to deal with
! 35: * the different interrupt types and timings of the ISA vs. PCI bus.
! 36: *
! 37: * The following bridge types are supported:
! 38: * o PLX 9052 (the most common)
! 39: * o TMD 7160 (found in some NDC/Sohoware NCP130 cards)
! 40: * o ACEX EP1K30 (really a PLD, found in Symbol cards and their OEMs)
! 41: */
! 42:
! 43: #include <sys/param.h>
! 44: #include <sys/systm.h>
! 45: #include <sys/device.h>
! 46: #include <sys/timeout.h>
! 47: #include <sys/socket.h>
! 48: #include <sys/tree.h>
! 49:
! 50: #include <net/if.h>
! 51: #include <net/if_dl.h>
! 52: #include <net/if_media.h>
! 53:
! 54: #ifdef INET
! 55: #include <netinet/in.h>
! 56: #include <netinet/if_ether.h>
! 57: #endif
! 58:
! 59: #include <net80211/ieee80211_var.h>
! 60: #include <net80211/ieee80211_ioctl.h>
! 61:
! 62: #include <machine/bus.h>
! 63:
! 64: #include <dev/pci/pcireg.h>
! 65: #include <dev/pci/pcivar.h>
! 66: #include <dev/pci/pcidevs.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: /* For printing CIS of the actual PCMCIA card */
! 73: #define CIS_MFG_NAME_OFFSET 0x16
! 74: #define CIS_INFO_SIZE 256
! 75:
! 76: const struct wi_pci_product *wi_pci_lookup(struct pci_attach_args *pa);
! 77: int wi_pci_match(struct device *, void *, void *);
! 78: void wi_pci_attach(struct device *, struct device *, void *);
! 79: int wi_pci_acex_attach(struct pci_attach_args *pa, struct wi_softc *sc);
! 80: int wi_pci_plx_attach(struct pci_attach_args *pa, struct wi_softc *sc);
! 81: int wi_pci_tmd_attach(struct pci_attach_args *pa, struct wi_softc *sc);
! 82: int wi_pci_native_attach(struct pci_attach_args *pa, struct wi_softc *sc);
! 83: int wi_pci_common_attach(struct pci_attach_args *pa, struct wi_softc *sc);
! 84: void wi_pci_plx_print_cis(struct wi_softc *);
! 85: void wi_pci_power(int, void *);
! 86:
! 87: struct wi_pci_softc {
! 88: struct wi_softc sc_wi; /* real softc */
! 89: void *sc_powerhook;
! 90: };
! 91:
! 92: struct cfattach wi_pci_ca = {
! 93: sizeof (struct wi_pci_softc), wi_pci_match, wi_pci_attach
! 94: };
! 95:
! 96: static const struct wi_pci_product {
! 97: pci_vendor_id_t pp_vendor;
! 98: pci_product_id_t pp_product;
! 99: int (*pp_attach)(struct pci_attach_args *pa, struct wi_softc *sc);
! 100: } wi_pci_products[] = {
! 101: { PCI_VENDOR_GLOBALSUN, PCI_PRODUCT_GLOBALSUN_GL24110P, wi_pci_plx_attach },
! 102: { PCI_VENDOR_GLOBALSUN, PCI_PRODUCT_GLOBALSUN_GL24110P02, wi_pci_plx_attach },
! 103: { PCI_VENDOR_GLOBALSUN, PCI_PRODUCT_GLOBALSUN_GL24110P03, wi_pci_plx_attach },
! 104: { PCI_VENDOR_GLOBALSUN, PCI_PRODUCT_GLOBALSUN_8031, wi_pci_plx_attach },
! 105: { PCI_VENDOR_EUMITCOM, PCI_PRODUCT_EUMITCOM_WL11000P, wi_pci_plx_attach },
! 106: { PCI_VENDOR_USR2, PCI_PRODUCT_USR2_WL11000P, wi_pci_plx_attach },
! 107: { PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3CRWE777A, wi_pci_plx_attach },
! 108: { PCI_VENDOR_NETGEAR, PCI_PRODUCT_NETGEAR_MA301, wi_pci_plx_attach },
! 109: { PCI_VENDOR_EFFICIENTNETS, PCI_PRODUCT_EFFICIENTNETS_SS1023, wi_pci_plx_attach },
! 110: { PCI_VENDOR_ADDTRON, PCI_PRODUCT_ADDTRON_AWA100, wi_pci_plx_attach },
! 111: { PCI_VENDOR_BELKIN, PCI_PRODUCT_BELKIN_F5D6000, wi_pci_plx_attach },
! 112: { PCI_VENDOR_NDC, PCI_PRODUCT_NDC_NCP130, wi_pci_plx_attach },
! 113: { PCI_VENDOR_NDC, PCI_PRODUCT_NDC_NCP130A2, wi_pci_tmd_attach },
! 114: { PCI_VENDOR_INTERSIL, PCI_PRODUCT_INTERSIL_MINI_PCI_WLAN, wi_pci_native_attach },
! 115: { PCI_VENDOR_INTERSIL, PCI_PRODUCT_INTERSIL_ISL3872, wi_pci_native_attach },
! 116: { PCI_VENDOR_SAMSUNG, PCI_PRODUCT_SAMSUNG_SWL2210P, wi_pci_native_attach },
! 117: { PCI_VENDOR_NORTEL, PCI_PRODUCT_NORTEL_211818A, wi_pci_acex_attach },
! 118: { PCI_VENDOR_SYMBOL, PCI_PRODUCT_SYMBOL_LA41X3, wi_pci_acex_attach },
! 119: { 0, 0, 0 }
! 120: };
! 121:
! 122: const struct wi_pci_product *
! 123: wi_pci_lookup(struct pci_attach_args *pa)
! 124: {
! 125: const struct wi_pci_product *pp;
! 126:
! 127: for (pp = wi_pci_products; pp->pp_product != 0; pp++) {
! 128: if (PCI_VENDOR(pa->pa_id) == pp->pp_vendor &&
! 129: PCI_PRODUCT(pa->pa_id) == pp->pp_product)
! 130: return (pp);
! 131: }
! 132:
! 133: return (NULL);
! 134: }
! 135:
! 136: int
! 137: wi_pci_match(struct device *parent, void *match, void *aux)
! 138: {
! 139: return (wi_pci_lookup(aux) != NULL);
! 140: }
! 141:
! 142: void
! 143: wi_pci_attach(struct device *parent, struct device *self, void *aux)
! 144: {
! 145: struct wi_pci_softc *psc = (struct wi_pci_softc *)self;
! 146: struct wi_softc *sc = (struct wi_softc *)self;
! 147: struct pci_attach_args *pa = aux;
! 148: const struct wi_pci_product *pp;
! 149:
! 150: pp = wi_pci_lookup(pa);
! 151: if (pp->pp_attach(pa, sc) != 0)
! 152: return;
! 153: printf("\n");
! 154: wi_attach(sc, &wi_func_io);
! 155:
! 156: psc->sc_powerhook = powerhook_establish(wi_pci_power, sc);
! 157: }
! 158:
! 159: void
! 160: wi_pci_power(int why, void *arg)
! 161: {
! 162: struct wi_softc *sc = (struct wi_softc *)arg;
! 163:
! 164: if (why == PWR_RESUME) {
! 165: if (sc->sc_ic.ic_if.if_flags & IFF_UP)
! 166: wi_init(sc);
! 167: }
! 168: }
! 169:
! 170: /*
! 171: * ACEX EP1K30-based PCMCIA->PCI bridge attachment.
! 172: *
! 173: * The ACEX EP1K30 is a programmable logic device (PLD) used as a
! 174: * PCMCIA->PCI bridge on the Symbol LA4123 and its OEM equivalents
! 175: * (such as the Nortel E-mobility 211818-A). There are 3 I/O ports:
! 176: * BAR0 at 0x10 appears to be a command port.
! 177: * BAR1 at 0x14 contains COR at offset 0xe0.
! 178: * BAR2 at 0x18 maps the actual PCMCIA card.
! 179: *
! 180: * The datasheet for the ACEX EP1K30 is available from Altera but that
! 181: * doesn't really help much since we don't know how it is programmed.
! 182: * Details for this attachment were gleaned from a version of the
! 183: * Linux orinoco driver modified by Tobias Hoffmann based on
! 184: * what he discoverd from the Windows driver.
! 185: */
! 186: int
! 187: wi_pci_acex_attach(struct pci_attach_args *pa, struct wi_softc *sc)
! 188: {
! 189: bus_space_handle_t commandh, localh, ioh;
! 190: bus_space_tag_t commandt, localt;
! 191: bus_space_tag_t iot = pa->pa_iot;
! 192: bus_size_t commandsize, localsize, iosize;
! 193: int i;
! 194:
! 195: if (pci_mapreg_map(pa, WI_ACEX_CMDRES, PCI_MAPREG_TYPE_IO,
! 196: 0, &commandt, &commandh, NULL, &commandsize, 0) != 0) {
! 197: printf(": can't map command I/O space\n");
! 198: return (ENXIO);
! 199: }
! 200:
! 201: if (pci_mapreg_map(pa, WI_ACEX_LOCALRES, PCI_MAPREG_TYPE_IO,
! 202: 0, &localt, &localh, NULL, &localsize, 0) != 0) {
! 203: printf(": can't map local I/O space\n");
! 204: bus_space_unmap(commandt, commandh, commandsize);
! 205: return (ENXIO);
! 206: }
! 207: sc->wi_ltag = localt;
! 208: sc->wi_lhandle = localh;
! 209:
! 210: if (pci_mapreg_map(pa, WI_TMD_IORES, PCI_MAPREG_TYPE_IO,
! 211: 0, &iot, &ioh, NULL, &iosize, 0) != 0) {
! 212: printf(": can't map I/O space\n");
! 213: bus_space_unmap(localt, localh, localsize);
! 214: bus_space_unmap(commandt, commandh, commandsize);
! 215: return (ENXIO);
! 216: }
! 217: sc->wi_btag = iot;
! 218: sc->wi_bhandle = ioh;
! 219:
! 220: /*
! 221: * Setup bridge chip.
! 222: */
! 223: if (bus_space_read_4(commandt, commandh, 0) & 1) {
! 224: printf(": bridge not ready\n");
! 225: bus_space_unmap(iot, ioh, iosize);
! 226: bus_space_unmap(localt, localh, localsize);
! 227: bus_space_unmap(commandt, commandh, commandsize);
! 228: return (ENXIO);
! 229: }
! 230: bus_space_write_4(commandt, commandh, 2, 0x118);
! 231: bus_space_write_4(commandt, commandh, 2, 0x108);
! 232: DELAY(30 * 1000);
! 233: bus_space_write_4(commandt, commandh, 2, 0x8);
! 234: for (i = 0; i < 30; i++) {
! 235: DELAY(30 * 1000);
! 236: if (bus_space_read_4(commandt, commandh, 0) & 0x10)
! 237: break;
! 238: }
! 239: if (i == 30) {
! 240: printf(": bridge timeout\n");
! 241: bus_space_unmap(iot, ioh, iosize);
! 242: bus_space_unmap(localt, localh, localsize);
! 243: bus_space_unmap(commandt, commandh, commandsize);
! 244: return (ENXIO);
! 245: }
! 246: if ((bus_space_read_4(localt, localh, 0xe0) & 1) ||
! 247: (bus_space_read_4(localt, localh, 0xe2) & 1) ||
! 248: (bus_space_read_4(localt, localh, 0xe4) & 1)) {
! 249: printf(": failed bridge setup\n");
! 250: bus_space_unmap(iot, ioh, iosize);
! 251: bus_space_unmap(localt, localh, localsize);
! 252: bus_space_unmap(commandt, commandh, commandsize);
! 253: return (ENXIO);
! 254: }
! 255:
! 256: if (wi_pci_common_attach(pa, sc) != 0) {
! 257: bus_space_unmap(iot, ioh, iosize);
! 258: bus_space_unmap(localt, localh, localsize);
! 259: bus_space_unmap(commandt, commandh, commandsize);
! 260: return (ENXIO);
! 261: }
! 262:
! 263: /*
! 264: * Enable I/O mode and level interrupts on the embedded PCMCIA
! 265: * card.
! 266: */
! 267: bus_space_write_1(localt, localh, WI_ACEX_COR_OFFSET, WI_COR_IOMODE);
! 268: sc->wi_cor_offset = WI_ACEX_COR_OFFSET;
! 269:
! 270: /* Unmap registers we no longer need access to. */
! 271: bus_space_unmap(commandt, commandh, commandsize);
! 272:
! 273: return (0);
! 274: }
! 275:
! 276: /*
! 277: * PLX 9052-based PCMCIA->PCI bridge attachment.
! 278: *
! 279: * These are often sold as "PCI wireless card adapters" and are
! 280: * sold by several vendors. Most are simply rebadged versions of the
! 281: * Eumitcom WL11000P or Global Sun Technology GL24110P02.
! 282: * These cards use the PLX 9052 dumb bridge chip to connect a PCMCIA
! 283: * wireless card to the PCI bus. Because it is a dumb bridge and
! 284: * not a true PCMCIA bridge, the PCMCIA subsystem is not involved
! 285: * (or even required). The PLX 9052 provides multiple PCI address
! 286: * space mappings. The primary mappings at PCI registers 0x10 (mem)
! 287: * and 0x14 (I/O) are for the PLX chip itself, *NOT* the PCMCIA card.
! 288: * The mem and I/O spaces for the PCMCIA card are mapped to 0x18 and
! 289: * 0x1C respectively.
! 290: * The PLX 9050/9052 datasheet may be downloaded from PLX at
! 291: * http://www.plxtech.com/products/toolbox/9050.htm
! 292: */
! 293: int
! 294: wi_pci_plx_attach(struct pci_attach_args *pa, struct wi_softc *sc)
! 295: {
! 296: bus_space_handle_t localh, ioh, memh;
! 297: bus_space_tag_t localt;
! 298: bus_space_tag_t iot = pa->pa_iot;
! 299: bus_space_tag_t memt = pa->pa_memt;
! 300: bus_size_t localsize, memsize, iosize;
! 301: u_int32_t intcsr;
! 302:
! 303: if (pci_mapreg_map(pa, WI_PLX_MEMRES, PCI_MAPREG_TYPE_MEM, 0,
! 304: &memt, &memh, NULL, &memsize, 0) != 0) {
! 305: printf(": can't map mem space\n");
! 306: return (ENXIO);
! 307: }
! 308: sc->wi_ltag = memt;
! 309: sc->wi_lhandle = memh;
! 310:
! 311: if (pci_mapreg_map(pa, WI_PLX_IORES,
! 312: PCI_MAPREG_TYPE_IO, 0, &iot, &ioh, NULL, &iosize, 0) != 0) {
! 313: printf(": can't map I/O space\n");
! 314: bus_space_unmap(memt, memh, memsize);
! 315: return (ENXIO);
! 316: }
! 317: sc->wi_btag = iot;
! 318: sc->wi_bhandle = ioh;
! 319:
! 320: /*
! 321: * Some cards, such as the PLX version of the NDC NCP130,
! 322: * don't have the PLX local registers mapped. In general
! 323: * this is OK since on those cards the serial EEPROM has
! 324: * already set things up for us.
! 325: * As such, we don't consider an error here to be fatal.
! 326: */
! 327: localsize = 0;
! 328: if (pci_mapreg_type(pa->pa_pc, pa->pa_tag, WI_PLX_LOCALRES)
! 329: == PCI_MAPREG_TYPE_IO) {
! 330: if (pci_mapreg_map(pa, WI_PLX_LOCALRES, PCI_MAPREG_TYPE_IO,
! 331: 0, &localt, &localh, NULL, &localsize, 0) != 0)
! 332: printf(": can't map PLX I/O space\n");
! 333: }
! 334:
! 335: if (wi_pci_common_attach(pa, sc) != 0) {
! 336: if (localsize)
! 337: bus_space_unmap(localt, localh, localsize);
! 338: bus_space_unmap(iot, ioh, iosize);
! 339: bus_space_unmap(memt, memh, memsize);
! 340: return (ENXIO);
! 341: }
! 342:
! 343: if (localsize != 0) {
! 344: intcsr = bus_space_read_4(localt, localh,
! 345: WI_PLX_INTCSR);
! 346:
! 347: /*
! 348: * The Netgear MA301 has local interrupt 1 active
! 349: * when there is no card in the adapter. We bail
! 350: * early in this case since our attempt to check
! 351: * for the presence of a card later will hang the
! 352: * MA301.
! 353: */
! 354: if (intcsr & WI_PLX_LINT1STAT) {
! 355: printf("\n%s: no PCMCIA card detected in bridge card\n",
! 356: WI_PRT_ARG(sc));
! 357: pci_intr_disestablish(pa->pa_pc, sc->sc_ih);
! 358: if (localsize)
! 359: bus_space_unmap(localt, localh, localsize);
! 360: bus_space_unmap(iot, ioh, iosize);
! 361: bus_space_unmap(memt, memh, memsize);
! 362: return (ENXIO);
! 363: }
! 364:
! 365: /*
! 366: * Enable PCI interrupts on the PLX chip if they are
! 367: * not already enabled. On most adapters the serial
! 368: * EEPROM has done this for us but some (such as
! 369: * the Netgear MA301) do not.
! 370: */
! 371: if (!(intcsr & WI_PLX_INTEN)) {
! 372: intcsr |= WI_PLX_INTEN;
! 373: bus_space_write_4(localt, localh, WI_PLX_INTCSR,
! 374: intcsr);
! 375: }
! 376: }
! 377:
! 378: /*
! 379: * Enable I/O mode and level interrupts on the PCMCIA card.
! 380: * The PCMCIA card's COR is the first byte after the CIS.
! 381: */
! 382: bus_space_write_1(memt, memh, WI_PLX_COR_OFFSET, WI_COR_IOMODE);
! 383: sc->wi_cor_offset = WI_PLX_COR_OFFSET;
! 384:
! 385: if (localsize != 0) {
! 386: /*
! 387: * Test the presence of a wi(4) card by writing
! 388: * a magic number to the first software support
! 389: * register and then reading it back.
! 390: */
! 391: CSR_WRITE_2(sc, WI_SW0, WI_DRVR_MAGIC);
! 392: DELAY(1000);
! 393: if (CSR_READ_2(sc, WI_SW0) != WI_DRVR_MAGIC) {
! 394: printf("\n%s: no PCMCIA card detected in bridge card\n",
! 395: WI_PRT_ARG(sc));
! 396: pci_intr_disestablish(pa->pa_pc, sc->sc_ih);
! 397: if (localsize)
! 398: bus_space_unmap(localt, localh, localsize);
! 399: bus_space_unmap(iot, ioh, iosize);
! 400: bus_space_unmap(memt, memh, memsize);
! 401: return (ENXIO);
! 402: }
! 403:
! 404: /* Unmap registers we no longer need access to. */
! 405: bus_space_unmap(localt, localh, localsize);
! 406:
! 407: /* Print PCMCIA card's CIS strings. */
! 408: wi_pci_plx_print_cis(sc);
! 409: }
! 410:
! 411: return (0);
! 412: }
! 413:
! 414: /*
! 415: * TMD 7160-based PCMCIA->PCI bridge attachment.
! 416: *
! 417: * The TMD7160 dumb bridge chip is used on some versions of the
! 418: * NDC/Sohoware NCP130. The TMD7160 provides two PCI I/O registers.
! 419: * The first, at 0x14, maps to the Prism2 COR.
! 420: * The second, at 0x18, is for the Prism2 chip itself.
! 421: *
! 422: * The datasheet for the TMD7160 does not seem to be publicly available.
! 423: * Details for this attachment were gleaned from a version of the
! 424: * Linux WLAN driver modified by NDC.
! 425: */
! 426: int
! 427: wi_pci_tmd_attach(struct pci_attach_args *pa, struct wi_softc *sc)
! 428: {
! 429: bus_space_handle_t localh, ioh;
! 430: bus_space_tag_t localt;
! 431: bus_space_tag_t iot = pa->pa_iot;
! 432: bus_size_t localsize, iosize;
! 433:
! 434: if (pci_mapreg_map(pa, WI_TMD_LOCALRES, PCI_MAPREG_TYPE_IO,
! 435: 0, &localt, &localh, NULL, &localsize, 0) != 0) {
! 436: printf(": can't map TMD I/O space\n");
! 437: return (ENXIO);
! 438: }
! 439: sc->wi_ltag = localt;
! 440: sc->wi_lhandle = localh;
! 441:
! 442: if (pci_mapreg_map(pa, WI_TMD_IORES, PCI_MAPREG_TYPE_IO,
! 443: 0, &iot, &ioh, NULL, &iosize, 0) != 0) {
! 444: printf(": can't map I/O space\n");
! 445: bus_space_unmap(localt, localh, localsize);
! 446: return (ENXIO);
! 447: }
! 448: sc->wi_btag = iot;
! 449: sc->wi_bhandle = ioh;
! 450:
! 451: if (wi_pci_common_attach(pa, sc) != 0) {
! 452: bus_space_unmap(iot, ioh, iosize);
! 453: bus_space_unmap(localt, localh, localsize);
! 454: return (ENXIO);
! 455: }
! 456:
! 457: /*
! 458: * Enable I/O mode and level interrupts on the embedded PCMCIA
! 459: * card. The PCMCIA card's COR is the first byte of BAR 0.
! 460: */
! 461: bus_space_write_1(localt, localh, 0, WI_COR_IOMODE);
! 462: sc->wi_cor_offset = 0;
! 463:
! 464: return (0);
! 465: }
! 466:
! 467: int
! 468: wi_pci_native_attach(struct pci_attach_args *pa, struct wi_softc *sc)
! 469: {
! 470: bus_space_handle_t ioh;
! 471: bus_space_tag_t iot = pa->pa_iot;
! 472: bus_size_t iosize;
! 473:
! 474: if (pci_mapreg_map(pa, WI_PCI_CBMA, PCI_MAPREG_TYPE_MEM,
! 475: 0, &iot, &ioh, NULL, &iosize, 0) != 0) {
! 476: printf(": can't map mem space\n");
! 477: return (ENXIO);
! 478: }
! 479: sc->wi_ltag = iot;
! 480: sc->wi_lhandle = ioh;
! 481: sc->wi_btag = iot;
! 482: sc->wi_bhandle = ioh;
! 483: sc->sc_pci = 1;
! 484:
! 485: if (wi_pci_common_attach(pa, sc) != 0) {
! 486: bus_space_unmap(iot, ioh, iosize);
! 487: return (ENXIO);
! 488: }
! 489:
! 490: /* Do a soft reset of the HFA3842 MAC core */
! 491: bus_space_write_2(iot, ioh, WI_PCI_COR_OFFSET, WI_COR_SOFT_RESET);
! 492: DELAY(100*1000); /* 100 m sec */
! 493: bus_space_write_2(iot, ioh, WI_PCI_COR_OFFSET, WI_COR_CLEAR);
! 494: DELAY(100*1000); /* 100 m sec */
! 495: sc->wi_cor_offset = WI_PCI_COR_OFFSET;
! 496:
! 497: return (0);
! 498: }
! 499:
! 500: int
! 501: wi_pci_common_attach(struct pci_attach_args *pa, struct wi_softc *sc)
! 502: {
! 503: pci_intr_handle_t ih;
! 504: pci_chipset_tag_t pc = pa->pa_pc;
! 505: const char *intrstr;
! 506:
! 507: /* Make sure interrupts are disabled. */
! 508: CSR_WRITE_2(sc, WI_INT_EN, 0);
! 509: CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF);
! 510:
! 511: /* Map and establish the interrupt. */
! 512: if (pci_intr_map(pa, &ih)) {
! 513: printf(": couldn't map interrupt\n");
! 514: return (ENXIO);
! 515: }
! 516: intrstr = pci_intr_string(pc, ih);
! 517: sc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, wi_intr, sc,
! 518: sc->sc_dev.dv_xname);
! 519: if (sc->sc_ih == NULL) {
! 520: printf(": couldn't establish interrupt");
! 521: if (intrstr != NULL)
! 522: printf(" at %s", intrstr);
! 523: printf("\n");
! 524: return (ENXIO);
! 525: }
! 526: printf(": %s", intrstr);
! 527:
! 528: return (0);
! 529: }
! 530:
! 531: void
! 532: wi_pci_plx_print_cis(struct wi_softc *sc)
! 533: {
! 534: int i, stringno;
! 535: char cisbuf[CIS_INFO_SIZE];
! 536: char *cis_strings[3];
! 537: u_int8_t value;
! 538: const u_int8_t cis_magic[] = {
! 539: 0x01, 0x03, 0x00, 0x00, 0xff, 0x17, 0x04, 0x67
! 540: };
! 541:
! 542: /* Make sure the CIS data is valid. */
! 543: for (i = 0; i < 8; i++) {
! 544: value = bus_space_read_1(sc->wi_ltag, sc->wi_lhandle, i * 2);
! 545: if (value != cis_magic[i])
! 546: return;
! 547: }
! 548:
! 549: cis_strings[0] = cisbuf;
! 550: stringno = 0;
! 551: for (i = 0; i < CIS_INFO_SIZE && stringno < 3; i++) {
! 552: cisbuf[i] = bus_space_read_1(sc->wi_ltag,
! 553: sc->wi_lhandle, (CIS_MFG_NAME_OFFSET + i) * 2);
! 554: if (cisbuf[i] == '\0' && ++stringno < 3)
! 555: cis_strings[stringno] = &cisbuf[i + 1];
! 556: }
! 557: cisbuf[CIS_INFO_SIZE - 1] = '\0';
! 558: printf("\n%s: \"%s, %s, %s\"", WI_PRT_ARG(sc),
! 559: cis_strings[0], cis_strings[1], cis_strings[2]);
! 560: }
CVSweb