diff options
Diffstat (limited to 'sys/dev/ic')
-rw-r--r-- | sys/dev/ic/bcw.c | 540 |
1 files changed, 263 insertions, 277 deletions
diff --git a/sys/dev/ic/bcw.c b/sys/dev/ic/bcw.c index 1a3b64514fe..dc092a73cb0 100644 --- a/sys/dev/ic/bcw.c +++ b/sys/dev/ic/bcw.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bcw.c,v 1.81 2007/03/31 09:48:02 mglocker Exp $ */ +/* $OpenBSD: bcw.c,v 1.82 2007/03/31 23:38:03 mglocker Exp $ */ /* * Copyright (c) 2006 Jon Simola <jsimola@gmail.com> @@ -149,11 +149,13 @@ int bcw_80211_core_init(struct bcw_softc *, int); uint8_t bcw_sprom_crc8(uint8_t, uint8_t); uint8_t bcw_sprom_crc(const uint16_t *); int bcw_sprom_read(struct bcw_softc *, uint16_t *); -int bcw_sprom_extract(struct bcw_softc *); +int bcw_sprom_get(struct bcw_softc *); +void bcw_microcode_init_fbf(struct bcw_softc *); /* * PHY */ +int bcw_phy_get(struct bcw_softc *); int bcw_phy_init(struct bcw_softc *); void bcw_phy_initg(struct bcw_softc *); void bcw_phy_initb2(struct bcw_softc *); @@ -196,6 +198,7 @@ int bcw_phy_connect(struct bcw_softc *, int); /* * Radio */ +int bcw_radio_get(struct bcw_softc *); void bcw_radio_off(struct bcw_softc *); void bcw_radio_on(struct bcw_softc *); void bcw_radio_nrssi_hw_write(struct bcw_softc *, @@ -904,7 +907,6 @@ bcw_attach(struct bcw_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; struct ifnet *ifp = &ic->ic_if; - int error; int i; uint32_t sbval; uint32_t core_id, core_rev, core_vendor; @@ -959,8 +961,6 @@ bcw_attach(struct bcw_softc *sc) /* powercontrol init is done if a common core exists */ bcw_pc_init(sc); - bcw_pc_set_clock(sc, BCW_PCTL_CLK_FAST); - sbval = BCW_READ(sc, BCW_CORE_COMMON_CHIPID); sc->sc_chip_id = (sbval & 0x0000ffff); sc->sc_chip_rev = (sbval & 0x000f0000) >> 16; @@ -1045,54 +1045,65 @@ bcw_attach(struct bcw_softc *sc) sc->sc_chip_id, sc->sc_chip_rev, sc->sc_chip_pkg, sc->sc_numcores)); - bcw_iocore_enable(sc, (1 << 1)); + bcw_pc_set_clock(sc, BCW_PCTL_CLK_FAST); - /* Reset and Identify each core */ + /* + * Get SPROM values and save them where they belong + */ + bcw_sprom_get(sc); + + /* Identify each core and reset the 802.11 cores */ for (i = 0; i < sc->sc_numcores; i++) { - if (bcw_change_core(sc, i) == 0) { - sbval = BCW_READ(sc, BCW_CIR_SBID_HI); + if (bcw_change_core(sc, i)) { + printf("%s: Failed change to core %d\n", + sc->sc_dev.dv_xname, i); + continue; + } - sc->sc_core[i].id = (sbval & 0x00008ff0) >> 4; - sc->sc_core[i].rev = - ((sbval & 0x00007000) >> 8 | (sbval & 0x0000000f)); + sbval = BCW_READ(sc, BCW_CIR_SBID_HI); + sc->sc_core[i].id = (sbval & 0x00008ff0) >> 4; + sc->sc_core[i].rev = ((sbval & 0x00007000) >> 8 | + (sbval & 0x0000000f)); - switch (sc->sc_core[i].id) { + switch (sc->sc_core[i].id) { + case BCW_CORE_COMMON: + sc->sc_core_common = &sc->sc_core[i]; + break; #if 0 - case BCW_CORE_COMMON: - sc->sc_core_common = &sc->sc_core[i]; - break; - case BCW_CORE_PCI: - (sc->sc_ca == NULL) + case BCW_CORE_PCI: + (sc->sc_ca == NULL) + sc->sc_core_bus = &sc->sc_core[i]; + break; + case BCW_CORE_PCMCIA: + if (sc->sc_pa == NULL) sc->sc_core_bus = &sc->sc_core[i]; - break; - case BCW_CORE_PCMCIA: - if (sc->sc_pa == NULL) - sc->sc_core_bus = &sc->sc_core[i]; - break; + break; #endif - case BCW_CORE_80211: - bcw_80211_core_reset(sc, 1); - bcw_radio_off(sc); - sc->sc_core_80211 = &sc->sc_core[i]; - break; - case BCW_CORE_NONEXIST: - sc->sc_numcores = i + 1; - break; - default: - /* Ignore all other core types */ - break; - } - DPRINTF(("%s: core %d is type 0x%x rev %d\n", - sc->sc_dev.dv_xname, i, - sc->sc_core[i].id, sc->sc_core[i].rev)); - /* XXX Fill out the core location vars */ - sbval = BCW_READ(sc, BCW_SBTPSFLAG); - sc->sc_core[i].backplane_flag = - sbval & SBTPS_BACKPLANEFLAGMASK; - sc->sc_core[i].index = i; - } else - DPRINTF(("%s: Failed change to core %d", - sc->sc_dev.dv_xname, i)); + case BCW_CORE_80211: + sc->sc_core_80211 = &sc->sc_core[i]; + bcw_80211_core_reset(sc, 1); + if (bcw_phy_get(sc)) + return; + if (bcw_radio_get(sc)) + return; + if (bcw_validate_chip_access(sc)) + return; + bcw_radio_off(sc); + bcw_microcode_init_fbf(sc); + break; + case BCW_CORE_NONEXIST: + sc->sc_numcores = i + 1; + break; + default: + /* ignore all other core types */ + break; + } + + sc->sc_core[i].index = i; + + DPRINTF(("%s: core %d is type 0x%x rev %d\n", + sc->sc_dev.dv_xname, sc->sc_core[i].index, + sc->sc_core[i].id, sc->sc_core[i].rev)); } /* turn crystal off */ @@ -1106,150 +1117,12 @@ bcw_attach(struct bcw_softc *sc) */ bcw_change_core(sc, sc->sc_core_80211->index); - sbval = BCW_READ16(sc, 0x3E0); - sc->sc_phy_ver = (sbval & 0xf000) >> 12; - sc->sc_phy_rev = sbval & 0xf; - sc->sc_phy_type = (sbval & 0xf00) >> 8; - - DPRINTF(("%s: PHY version %d revision %d ", - sc->sc_dev.dv_xname, sc->sc_phy_ver, sc->sc_phy_rev)); - - switch (sc->sc_phy_type) { - case BCW_PHY_TYPEA: - DPRINTF(("PHY %d (A)\n", sc->sc_phy_type)); - break; - case BCW_PHY_TYPEB: - DPRINTF(("PHY %d (B)\n", sc->sc_phy_type)); - break; - case BCW_PHY_TYPEG: - DPRINTF(("PHY %d (G)\n", sc->sc_phy_type)); - break; - case BCW_PHY_TYPEN: - DPRINTF(("PHY %d (N)\n", sc->sc_phy_type)); - break; - default: - DPRINTF(("Unrecognizeable PHY type %d\n", - sc->sc_phy_type)); - break; - } - - /* - * Initialize softc vars - */ +#if 0 sc->sc_phy_lopairs = malloc(sizeof(struct bcw_lopair) * BCW_LO_COUNT, M_DEVBUF, M_NOWAIT); bcw_phy_prepare_init(sc); bcw_radio_prepare_init(sc); - - /* - * Query the RadioID register, on a 4317 use a lookup instead - * XXX Different PHYs have different radio register layouts, so - * a wrapper func should be written. - * Getting the RadioID is the only 32bit operation done with the - * Radio registers, and requires seperate 16bit reads from the low - * and the high data addresses. - */ - if (sc->sc_chip_id != 0x4317) { - BCW_WRITE16(sc, BCW_MMIO_RADIO_CONTROL, BCW_RADIO_ID); - sbval = BCW_READ16(sc, BCW_MMIO_RADIO_DATA_HIGH); - sbval <<= 16; - BCW_WRITE16(sc, BCW_MMIO_RADIO_CONTROL, BCW_RADIO_ID); - sc->sc_radio_mnf = - sbval | BCW_READ16(sc, BCW_MMIO_RADIO_DATA_LOW); - } else { - switch (sc->sc_chip_rev) { - case 0: - sc->sc_radio_mnf = 0x3205017F; - break; - case 1: - sc->sc_radio_mnf = 0x4205017f; - break; - default: - sc->sc_radio_mnf = 0x5205017f; - } - } - - sc->sc_radio_rev = (sc->sc_radio_mnf & 0xf0000000) >> 28; - sc->sc_radio_ver = (sc->sc_radio_mnf & 0x0ffff000) >> 12; - - DPRINTF(("%s: Radio Rev %d, Ver 0x%x, Manuf 0x%x\n", - sc->sc_dev.dv_xname, sc->sc_radio_rev, sc->sc_radio_ver, - sc->sc_radio_mnf & 0xfff)); - - error = bcw_validate_chip_access(sc); - if (error) { - printf("%s: failed Chip Access Validation at %d\n", - sc->sc_dev.dv_xname, error); - return; - } - - /* Test for valid PHY/revision combinations, probably a simpler way */ - if (sc->sc_phy_type == BCW_PHY_TYPEA) { - switch (sc->sc_phy_rev) { - case 2: - case 3: - case 5: - case 6: - case 7: - break; - default: - printf("%s: invalid PHY A revision %d\n", - sc->sc_dev.dv_xname, sc->sc_phy_rev); - return; - } - } - if (sc->sc_phy_type == BCW_PHY_TYPEB) { - switch (sc->sc_phy_rev) { - case 2: - case 4: - case 7: - break; - default: - printf("%s: invalid PHY B revision %d\n", - sc->sc_dev.dv_xname, sc->sc_phy_rev); - return; - } - } - if (sc->sc_phy_type == BCW_PHY_TYPEG) { - switch(sc->sc_phy_rev) { - case 1: - case 2: - case 4: - case 6: - case 7: - case 8: - break; - default: - printf("%s: invalid PHY G revision %d\n", - sc->sc_dev.dv_xname, sc->sc_phy_rev); - return; - } - } - - /* test for valid radio revisions */ - if ((sc->sc_phy_type == BCW_PHY_TYPEA) & - (sc->sc_radio_ver != 0x2060)) { - printf("%s: invalid PHY A radio 0x%x\n", - sc->sc_dev.dv_xname, sc->sc_radio_ver); - return; - } - if ((sc->sc_phy_type == BCW_PHY_TYPEB) & - ((sc->sc_radio_ver & 0xfff0) != 0x2050)) { - printf("%s: invalid PHY B radio 0x%x\n", - sc->sc_dev.dv_xname, sc->sc_radio_ver); - return; - } - if ((sc->sc_phy_type == BCW_PHY_TYPEG) & - (sc->sc_radio_ver != 0x2050)) { - printf("%s: invalid PHY G radio 0x%x\n", - sc->sc_dev.dv_xname, sc->sc_radio_ver); - return; - } - - /* - * Extract SPROM values and save them where they belong - */ - bcw_sprom_extract(sc); +#endif /* * Set MAC address @@ -1261,32 +1134,6 @@ bcw_attach(struct bcw_softc *sc) printf(", address %s\n", ether_sprintf(ic->ic_myaddr)); /* - * Init the Microcode Flags Bitfield - * - * http://bcm-specs.sipsolutions.net/MicrocodeFlagsBitfield - */ - sbval = 0; - if (sc->sc_phy_type == BCW_PHY_TYPEA || - sc->sc_phy_type == BCW_PHY_TYPEB || - sc->sc_phy_type == BCW_PHY_TYPEG) - sbval |= 2; - if (sc->sc_phy_type == BCW_PHY_TYPEG && sc->sc_phy_rev == 1) - sbval |= 0x20; - if (sc->sc_phy_type == BCW_PHY_TYPEG && - sc->sc_sprom.boardflags & BCW_BF_PACTRL) - sbval |= 0x40; - if (sc->sc_phy_type == BCW_PHY_TYPEG && sc->sc_phy_rev < 3) - sbval |= 0x8; - if (sc->sc_sprom.boardflags & BCW_BF_XTAL) - sbval |= 0x400; - if (sc->sc_phy_type == BCW_PHY_TYPEB) - sbval |= 0x4; - if (sc->sc_radio_ver == 0x2050 && sc->sc_radio_rev <= 5) - sbval |= 0x40000; - /* XXX device not up and PCI bus with rev =< 10 set 0x80000 */ - bcw_shm_write32(sc, BCW_SHM_SHARED, BCW_UCODEFLAGS_OFFSET, sbval); - - /* * Initialize the TSSI to DBM table * The method is described at * http://bcm-specs.sipsolutions.net/TSSI_to_DBM_Table @@ -1671,6 +1518,11 @@ bcw_init(struct ifnet *ifp) int error; uint32_t coremask = 0; + sc->sc_phy_lopairs = malloc(sizeof(struct bcw_lopair) * BCW_LO_COUNT, + M_DEVBUF, M_NOWAIT); + bcw_phy_prepare_init(sc); /* XXX probably unpack function */ + bcw_radio_prepare_init(sc); /* XXX probably unpack function */ + bcw_pc_crystal_on(sc); bcw_pc_init(sc); @@ -1834,93 +1686,71 @@ bcw_tick(void *v) /* * Validate Chip Access * - * This function ensures that the chip is setup correctly and is ready - * for use. + * This function ensures that the 80211 core is setup correctly and + * and is read for use. * * http://bcm-specs.sipsolutions.net/ValidateChipAccess */ int bcw_validate_chip_access(struct bcw_softc *sc) { - uint32_t save,val; - - /* Make sure we're dealing with the wireless core */ - bcw_change_core(sc, sc->sc_core_80211->index); + uint32_t save, val; - /* - * We use the offset of zero a lot here to reset the SHM pointer to the - * beginning of it's memory area, as it automatically moves on every - * access to the SHM DATA registers - */ - - /* Backup SHM uCode Revision before we clobber it */ - BCW_WRITE(sc, BCW_MMIO_SHM_CONTROL, (BCW_SHM_SHARED << 16) + 0); - save = BCW_READ(sc, BCW_MMIO_SHM_DATA); + /* test 1 (this test is just for the 80211 core) */ + if (sc->sc_core[sc->sc_currentcore].id != BCW_CORE_80211) + goto fail; - /* write test value */ - BCW_WRITE(sc, BCW_MMIO_SHM_CONTROL, (BCW_SHM_SHARED << 16) + 0); - BCW_WRITE(sc, BCW_MMIO_SHM_DATA, 0xaa5555aa); - /* Read it back */ - BCW_WRITE(sc, BCW_MMIO_SHM_CONTROL, (BCW_SHM_SHARED << 16) + 0); + /* save value */ + save = bcw_shm_read32(sc, BCW_SHM_SHARED, 0); - val = BCW_READ(sc, BCW_MMIO_SHM_DATA); + /* test 2 */ + bcw_shm_write32(sc, BCW_SHM_SHARED, 0, 0xaa5555aa); + val = bcw_shm_read32(sc, BCW_SHM_SHARED, 0); if (val != 0xaa5555aa) - return (1); - - /* write 2nd test value */ - BCW_WRITE(sc, BCW_MMIO_SHM_CONTROL, (BCW_SHM_SHARED << 16) + 0); - BCW_WRITE(sc, BCW_MMIO_SHM_DATA, 0x55aaaa55); - /* Read it back */ - BCW_WRITE(sc, BCW_MMIO_SHM_CONTROL, (BCW_SHM_SHARED << 16) + 0); + goto fail; - val = BCW_READ(sc, BCW_MMIO_SHM_DATA); + /* test 3 */ + bcw_shm_write32(sc, BCW_SHM_SHARED, 0, 0x55aaaa55); + val = bcw_shm_read32(sc, BCW_SHM_SHARED, 0); if (val != 0x55aaaa55) - return 2; + goto fail; + + /* restore value */ + bcw_shm_write32(sc, BCW_SHM_SHARED, 0, save); - /* Restore the saved value now that we're done */ - BCW_WRITE(sc, BCW_MMIO_SHM_CONTROL, (BCW_SHM_SHARED << 16) + 0); - BCW_WRITE(sc, BCW_MMIO_SHM_DATA, save); if (sc->sc_core_80211->rev >= 3) { - /* do some test writes and reads against the TSF */ - /* - * This works during the attach, but the spec at - * http://bcm-specs.sipsolutions.net/Timing - * say that we're reading/writing silly places, so these regs - * are not quite documented yet - */ + /* test 4 */ BCW_WRITE16(sc, 0x18c, 0xaaaa); BCW_WRITE(sc, 0x18c, 0xccccbbbb); val = BCW_READ16(sc, 0x604); - if (val != 0xbbbb) return 3; + if (val != 0xbbbb) + goto fail; + /* test 5 */ val = BCW_READ16(sc, 0x606); - if (val != 0xcccc) return 4; - /* re-clear the TSF since we just filled it with garbage */ - BCW_WRITE(sc, 0x18c, 0x0); + if (val != 0xcccc) + goto fail; + BCW_WRITE(sc, 0x18c, 0); } - /* Check the Status Bit Field for some unknown bits */ + /* test 6 */ val = BCW_READ(sc, BCW_MMIO_SBF); - if ((val | 0x80000000) != 0x80000400 ) { - printf("%s: Warning, SBF is 0x%x, expected 0x80000400\n", - sc->sc_dev.dv_xname, val); - /* May not be a critical failure, just warn for now */ - //return (5); - } - /* Verify there are no interrupts active on the core */ + if ((val | 0x80000000) != 0x80000400) + goto fail; + + /* test 7 */ val = BCW_READ(sc, BCW_MMIO_GIR); - if (val != 0) { - DPRINTF(("Failed Pending Interrupt test with val=0x%x\n", val)); - return (6); - } + if (val != 0) + goto fail; + + /* test 8 */ + if (sc->sc_phy_type > BCW_PHY_TYPEG) + goto fail; - /* Above G means it's unsupported currently, like N */ - if (sc->sc_phy_type > BCW_PHY_TYPEG) { - DPRINTF(("PHY type %d greater than supported type %d\n", - sc->sc_phy_type, BCW_PHY_TYPEG)); - return (7); - } - return (0); + +fail: + printf("%s: Chip Access Validation failed!\n", sc->sc_dev.dv_xname); + return (1); } int @@ -3222,12 +3052,12 @@ bcw_sprom_read(struct bcw_softc *sc, uint16_t *sprom) } /* - * Extract whole SPROM content + * Get whole SPROM content * * http://bcm-specs.sipsolutions.net/SPROM */ int -bcw_sprom_extract(struct bcw_softc *sc) +bcw_sprom_get(struct bcw_softc *sc) { uint16_t val; uint16_t *sprom; @@ -3333,9 +3163,98 @@ bcw_sprom_extract(struct bcw_softc *sc) } /* + * Init the Microcode Flags Bitfield + * + * http://bcm-specs.sipsolutions.net/MicrocodeFlagsBitfield + */ +void +bcw_microcode_init_fbf(struct bcw_softc *sc) +{ + uint32_t val; + + val = 0; + if (sc->sc_phy_type == BCW_PHY_TYPEA || + sc->sc_phy_type == BCW_PHY_TYPEB || + sc->sc_phy_type == BCW_PHY_TYPEG) + val |= 2; + if (sc->sc_phy_type == BCW_PHY_TYPEG && sc->sc_phy_rev == 1) + val |= 0x20; + if (sc->sc_phy_type == BCW_PHY_TYPEG && + sc->sc_sprom.boardflags & BCW_BF_PACTRL) + val |= 0x40; + if (sc->sc_phy_type == BCW_PHY_TYPEG && sc->sc_phy_rev < 3) + val |= 0x8; + if (sc->sc_sprom.boardflags & BCW_BF_XTAL) + val |= 0x400; + if (sc->sc_phy_type == BCW_PHY_TYPEB) + val |= 0x4; + if (sc->sc_radio_ver == 0x2050 && sc->sc_radio_rev <= 5) + val |= 0x40000; + /* XXX device not up and PCI bus with rev =< 10 set 0x80000 */ + + bcw_shm_write32(sc, BCW_SHM_SHARED, BCW_UCODEFLAGS_OFFSET, val); +} + +/* * PHY */ int +bcw_phy_get(struct bcw_softc *sc) +{ + uint32_t val; + + val = BCW_READ16(sc, 0x3E0); + sc->sc_phy_ver = (val & 0xf000) >> 12; + sc->sc_phy_rev = val & 0xf; + sc->sc_phy_type = (val & 0xf00) >> 8; + + switch (sc->sc_phy_type) { + case BCW_PHY_TYPEA: + DPRINTF(("%s: PHY %d (A) ", + sc->sc_dev.dv_xname, sc->sc_phy_type)); + if (sc->sc_phy_rev != 2 && + sc->sc_phy_rev != 3 && + sc->sc_phy_rev != 5 && + sc->sc_phy_rev != 6 && + sc->sc_phy_rev != 7) { + printf("has invalid revision %d!\n", sc->sc_phy_rev); + return (1); + } + break; + case BCW_PHY_TYPEB: + DPRINTF(("%s: PHY %d (B) ", + sc->sc_dev.dv_xname, sc->sc_phy_type)); + if (sc->sc_phy_rev != 2 && + sc->sc_phy_rev != 4 && + sc->sc_phy_rev != 7) { + printf("has invalid revision %d!\n", sc->sc_phy_rev); + return (1); + } + break; + case BCW_PHY_TYPEG: + DPRINTF(("%s: PHY %d (G) ", + sc->sc_dev.dv_xname, sc->sc_phy_type)); + if (sc->sc_phy_rev != 1 && + sc->sc_phy_rev != 2 && + sc->sc_phy_rev != 4 && + sc->sc_phy_rev != 6 && + sc->sc_phy_rev != 7 && + sc->sc_phy_rev != 8) { + printf("has invalid revision %d!\n", sc->sc_phy_rev); + return (1); + } + break; + default: + DPRINTF(("Unknown PHY type %d!\n", sc->sc_phy_type)); + return (1); + } + + DPRINTF(("ver %d rev %d\n", sc->sc_phy_ver, sc->sc_phy_rev)); + + return (0); +} + +int bcw_phy_init(struct bcw_softc *sc) { int error = ENODEV; @@ -5365,6 +5284,73 @@ out: /* * Radio */ +int +bcw_radio_get(struct bcw_softc *sc) +{ + uint32_t val; + + /* + * Query the RadioID register, on a 4317 use a lookup instead + * XXX Different PHYs have different radio register layouts, so + * a wrapper func should be written. + * Getting the RadioID is the only 32bit operation done with the + * Radio registers, and requires seperate 16bit reads from the low + * and the high data addresses. + */ + if (sc->sc_chip_id != 0x4317) { + BCW_WRITE16(sc, BCW_MMIO_RADIO_CONTROL, BCW_RADIO_ID); + val = BCW_READ16(sc, BCW_MMIO_RADIO_DATA_HIGH); + val <<= 16; + BCW_WRITE16(sc, BCW_MMIO_RADIO_CONTROL, BCW_RADIO_ID); + sc->sc_radio_mnf = + val | BCW_READ16(sc, BCW_MMIO_RADIO_DATA_LOW); + } else { + switch (sc->sc_chip_rev) { + case 0: + sc->sc_radio_mnf = 0x3205017F; + break; + case 1: + sc->sc_radio_mnf = 0x4205017f; + break; + default: + sc->sc_radio_mnf = 0x5205017f; + } + } + + sc->sc_radio_rev = (sc->sc_radio_mnf & 0xf0000000) >> 28; + sc->sc_radio_ver = (sc->sc_radio_mnf & 0x0ffff000) >> 12; + + switch (sc->sc_phy_type) { + case BCW_PHY_TYPEA: + if (sc->sc_radio_ver != 0x2060) { + printf("%s: invalid PHY A radio 0x%x!\n", + sc->sc_dev.dv_xname, sc->sc_radio_ver); + return (1); + } + break; + case BCW_PHY_TYPEB: + if ((sc->sc_radio_ver & 0xfff0) != 0x2050) { + printf("%s: invalid PHY B radio 0x%x!\n", + sc->sc_dev.dv_xname, sc->sc_radio_ver); + return (1); + } + break; + case BCW_PHY_TYPEG: + if (sc->sc_radio_ver != 0x2050) { + printf("%s: invalid PHY G radio 0x%x!\n", + sc->sc_dev.dv_xname, sc->sc_radio_ver); + return (1); + } + break; + } + + DPRINTF(("%s: Radio rev %d ver 0x%x mnf 0x%x\n", + sc->sc_dev.dv_xname, sc->sc_radio_rev, sc->sc_radio_ver, + sc->sc_radio_mnf & 0xfff)); + + return (0); +} + void bcw_radio_off(struct bcw_softc *sc) { |