diff options
author | Todd C. Miller <millert@cvs.openbsd.org> | 2004-07-15 16:11:52 +0000 |
---|---|---|
committer | Todd C. Miller <millert@cvs.openbsd.org> | 2004-07-15 16:11:52 +0000 |
commit | 8bc09206f301281d1df09ef8d0ad8a63dc4ed313 (patch) | |
tree | 8a72f1f1586040762cb60f89f5555b21855a8e54 /sys/dev/ic | |
parent | e92558d4bbf50a96368749c42f376f5aa4001f72 (diff) |
Totally revamp/re-organize device initialization using clue from the
reference driver. From NetBSD (dyoung).
Diffstat (limited to 'sys/dev/ic')
-rw-r--r-- | sys/dev/ic/atw.c | 414 |
1 files changed, 251 insertions, 163 deletions
diff --git a/sys/dev/ic/atw.c b/sys/dev/ic/atw.c index 30432248d60..3e2c366df4f 100644 --- a/sys/dev/ic/atw.c +++ b/sys/dev/ic/atw.c @@ -1,5 +1,5 @@ -/* $OpenBSD: atw.c,v 1.18 2004/07/15 15:50:51 millert Exp $ */ -/* $NetBSD: atw.c,v 1.63 2004/07/15 07:25:40 dyoung Exp $ */ +/* $OpenBSD: atw.c,v 1.19 2004/07/15 16:11:51 millert Exp $ */ +/* $NetBSD: atw.c,v 1.64 2004/07/15 07:26:17 dyoung Exp $ */ /*- * Copyright (c) 1998, 1999, 2000, 2002, 2003, 2004 The NetBSD Foundation, Inc. @@ -43,7 +43,7 @@ #include <sys/cdefs.h> #if defined(__NetBSD__) -__KERNEL_RCSID(0, "$NetBSD: atw.c,v 1.63 2004/07/15 07:25:40 dyoung Exp $"); +__KERNEL_RCSID(0, "$NetBSD: atw.c,v 1.64 2004/07/15 07:26:17 dyoung Exp $"); #endif #include "bpfilter.h" @@ -190,55 +190,87 @@ void atw_si4126_print(struct atw_softc *); void atw_print_stats(struct atw_softc *); #endif +/* ifnet methods */ void atw_start(struct ifnet *); void atw_watchdog(struct ifnet *); int atw_ioctl(struct ifnet *, u_long, caddr_t); int atw_init(struct ifnet *); -void atw_txdrain(struct atw_softc *); void atw_stop(struct ifnet *, int); -void atw_reset(struct atw_softc *); -int atw_read_srom(struct atw_softc *); - -void atw_shutdown(void *); +/* Device attachment */ +void atw_attach(struct atw_softc *); +int atw_detach(struct atw_softc *); +/* Rx/Tx process */ void atw_rxdrain(struct atw_softc *); +void atw_txdrain(struct atw_softc *); int atw_add_rxbuf(struct atw_softc *, int); void atw_idle(struct atw_softc *, u_int32_t); +/* Device (de)activation and power state */ int atw_enable(struct atw_softc *); void atw_disable(struct atw_softc *); void atw_power(int, void *); +void atw_shutdown(void *); +void atw_reset(struct atw_softc *); +/* Interrupt handlers */ void atw_rxintr(struct atw_softc *); void atw_txintr(struct atw_softc *); void atw_linkintr(struct atw_softc *, u_int32_t); +/* 802.11 state machine */ int atw_newstate(struct ieee80211com *, enum ieee80211_state, int); +int atw_tune(struct atw_softc *); +void atw_recv_mgmt(struct ieee80211com *, struct mbuf *, + struct ieee80211_node *, int, int, u_int32_t); +void atw_next_scan(void *); + +/* Device initialization */ +void atw_wcsr_init(struct atw_softc *); +void atw_cmdr_init(struct atw_softc *); +void atw_tofs2_init(struct atw_softc *); +void atw_txlmt_init(struct atw_softc *); +void atw_test1_init(struct atw_softc *); +void atw_rf_reset(struct atw_softc *); +void atw_cfp_init(struct atw_softc *); +void atw_tofs0_init(struct atw_softc *); +void atw_ifs_init(struct atw_softc *); +void atw_response_times_init(struct atw_softc *); +void atw_bbp_io_init(struct atw_softc *); +void atw_nar_init(struct atw_softc *); + +/* RAM/ROM utilities */ +void atw_clear_sram(struct atw_softc *); +void atw_write_sram(struct atw_softc *, u_int, u_int8_t *, u_int); +int atw_read_srom(struct atw_softc *); + +/* BSS setup */ void atw_tsf(struct atw_softc *); void atw_start_beacon(struct atw_softc *, int); -void atw_write_wep(struct atw_softc *); void atw_write_bssid(struct atw_softc *); void atw_write_ssid(struct atw_softc *); void atw_write_sup_rates(struct atw_softc *); -void atw_clear_sram(struct atw_softc *); -void atw_write_sram(struct atw_softc *, u_int, u_int8_t *, u_int); +void atw_write_wep(struct atw_softc *); + +/* Media */ int atw_media_change(struct ifnet *); void atw_media_status(struct ifnet *, struct ifmediareq *); + void atw_filter_setup(struct atw_softc *); + +/* 802.11 utilities */ void atw_frame_setdurs(struct atw_softc *, struct atw_frame *, int, int); -static __inline uint32_t atw_last_even_tsft(uint32_t, uint32_t, uint32_t); -static __inline void atw_tsft(struct atw_softc *, uint32_t *, uint32_t *); +struct ieee80211_node *atw_node_alloc(struct ieee80211com *); +void atw_node_free(struct ieee80211com *, struct ieee80211_node *); void atw_recv_beacon(struct ieee80211com *, struct mbuf *, struct ieee80211_node *, int, int, u_int32_t); -void atw_recv_mgmt(struct ieee80211com *, struct mbuf *, - struct ieee80211_node *, int, int, u_int32_t); -void atw_node_free(struct ieee80211com *, struct ieee80211_node *); -void atw_next_scan(void *); -struct ieee80211_node *atw_node_alloc(struct ieee80211com *); - -int atw_tune(struct atw_softc *); +static __inline uint32_t atw_last_even_tsft(uint32_t, uint32_t, uint32_t); +static __inline void atw_tsft(struct atw_softc *, uint32_t *, uint32_t *); +/* + * Tuner/transceiver/modem + */ void atw_bbp_io_enable(struct atw_softc *, int); /* RFMD RF3000 Baseband Processor */ @@ -937,58 +969,45 @@ atw_clear_sram(struct atw_softc *sc) * set TX rate */ -/* - * atw_init: [ ifnet interface function ] - * - * Initialize the interface. Must be called at splnet(). +/* Tell the ADM8211 to raise ATW_INTR_LINKOFF if 7 beacon intervals pass + * without receiving a beacon with the preferred BSSID & SSID. + * atw_write_bssid & atw_write_ssid set the BSSID & SSID. */ -int -atw_init(struct ifnet *ifp) +void +atw_wcsr_init(struct atw_softc *sc) { - struct atw_softc *sc = ifp->if_softc; - struct ieee80211com *ic = &sc->sc_ic; - struct atw_txsoft *txs; - struct atw_rxsoft *rxs; - u_int32_t reg; - int i, error = 0; + uint32_t wcsr; - if ((error = atw_enable(sc)) != 0) - goto out; + wcsr = ATW_READ(sc, ATW_WCSR); + wcsr &= ~(ATW_WCSR_BLN_MASK|ATW_WCSR_LSOE|ATW_WCSR_MPRE|ATW_WCSR_LSOE); + wcsr |= LSHIFT(7, ATW_WCSR_BLN_MASK); + ATW_WRITE(sc, ATW_WCSR, wcsr); /* XXX resets wake-up status bits */ - /* - * Cancel any pending I/O. This also resets. - */ - atw_stop(ifp, 0); - - ic->ic_bss->ni_chan = ic->ic_ibss_chan; - DPRINTF(sc, ("%s: channel %d freq %d flags 0x%04x\n", - __func__, ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan), - ic->ic_bss->ni_chan->ic_freq, ic->ic_bss->ni_chan->ic_flags)); - - /* Turn off APM??? (A binary-only driver does this.) - * - * Set Rx store-and-forward mode. - */ - reg = ATW_READ(sc, ATW_CMDR); - reg &= ~ATW_CMDR_APM; - reg &= ~ATW_CMDR_DRT_MASK; - reg |= ATW_CMDR_RTE | LSHIFT(0x2, ATW_CMDR_DRT_MASK); - - ATW_WRITE(sc, ATW_CMDR, reg); + DPRINTF(sc, ("%s: %s reg[WCSR] = %08x\n", + sc->sc_dev.dv_xname, __func__, ATW_READ(sc, ATW_WCSR))); +} - /* Set data rate for PLCP Signal field, 1Mbps = 10 x 100Kb/s. - * - * XXX a binary-only driver sets a different service field than - * 0. why? - */ - reg = ATW_READ(sc, ATW_PLCPHD); - reg &= ~(ATW_PLCPHD_SERVICE_MASK|ATW_PLCPHD_SIGNAL_MASK); - reg |= LSHIFT(10, ATW_PLCPHD_SIGNAL_MASK) | - LSHIFT(0xb0, ATW_PLCPHD_SERVICE_MASK); - ATW_WRITE(sc, ATW_PLCPHD, reg); +/* Turn off power management. Set Rx store-and-forward mode. */ +void +atw_cmdr_init(struct atw_softc *sc) +{ + uint32_t cmdr; + cmdr = ATW_READ(sc, ATW_CMDR); + cmdr &= ~ATW_CMDR_APM; + cmdr |= ATW_CMDR_RTE; + cmdr &= ~ATW_CMDR_DRT_MASK; + cmdr |= ATW_CMDR_DRT_SF; + + ATW_WRITE(sc, ATW_CMDR, cmdr); +} +void +atw_tofs2_init(struct atw_softc *sc) +{ + uint32_t tofs2; /* XXX this magic can probably be figured out from the RFMD docs */ - reg = LSHIFT(4, ATW_TOFS2_PWR1UP_MASK) | /* 8 ms = 4 * 2 ms */ +#ifndef ATW_REFSLAVE + tofs2 = LSHIFT(4, ATW_TOFS2_PWR1UP_MASK) | /* 8 ms = 4 * 2 ms */ LSHIFT(13, ATW_TOFS2_PWR0PAPE_MASK) | /* 13 us */ LSHIFT(8, ATW_TOFS2_PWR1PAPE_MASK) | /* 8 us */ LSHIFT(5, ATW_TOFS2_PWR0TRSW_MASK) | /* 5 us */ @@ -996,22 +1015,71 @@ atw_init(struct ifnet *ifp) LSHIFT(13, ATW_TOFS2_PWR0PE2_MASK) | /* 13 us */ LSHIFT(4, ATW_TOFS2_PWR1PE2_MASK) | /* 4 us */ LSHIFT(5, ATW_TOFS2_PWR0TXPE_MASK); /* 5 us */ - ATW_WRITE(sc, ATW_TOFS2, reg); +#else + /* XXX new magic from reference driver source */ + tofs2 = LSHIFT(8, ATW_TOFS2_PWR1UP_MASK) | /* 8 ms = 4 * 2 ms */ + LSHIFT(8, ATW_TOFS2_PWR0PAPE_MASK) | /* 13 us */ + LSHIFT(1, ATW_TOFS2_PWR1PAPE_MASK) | /* 8 us */ + LSHIFT(5, ATW_TOFS2_PWR0TRSW_MASK) | /* 5 us */ + LSHIFT(12, ATW_TOFS2_PWR1TRSW_MASK) | /* 12 us */ + LSHIFT(13, ATW_TOFS2_PWR0PE2_MASK) | /* 13 us */ + LSHIFT(1, ATW_TOFS2_PWR1PE2_MASK) | /* 4 us */ + LSHIFT(8, ATW_TOFS2_PWR0TXPE_MASK); /* 5 us */ +#endif + ATW_WRITE(sc, ATW_TOFS2, tofs2); +} +void +atw_nar_init(struct atw_softc *sc) +{ + ATW_WRITE(sc, ATW_NAR, ATW_NAR_SF|ATW_NAR_PB); +} + +void +atw_txlmt_init(struct atw_softc *sc) +{ ATW_WRITE(sc, ATW_TXLMT, LSHIFT(512, ATW_TXLMT_MTMLT_MASK) | - LSHIFT(224, ATW_TXLMT_SRTYLIM_MASK)); + LSHIFT(1, ATW_TXLMT_SRTYLIM_MASK)); +} + +void +atw_test1_init(struct atw_softc *sc) +{ + uint32_t test1; + + test1 = ATW_READ(sc, ATW_TEST1); + test1 &= ~(ATW_TEST1_DBGREAD_MASK|ATW_TEST1_CONTROL); + /* XXX magic 0x1 */ + test1 |= LSHIFT(0x1, ATW_TEST1_DBGREAD_MASK) | ATW_TEST1_CONTROL; + ATW_WRITE(sc, ATW_TEST1, test1); +} +void +atw_rf_reset(struct atw_softc *sc) +{ /* XXX this resets an Intersil RF front-end? */ /* TBD condition on Intersil RFType? */ ATW_WRITE(sc, ATW_SYNRF, ATW_SYNRF_INTERSIL_EN); DELAY(10 * 1000); ATW_WRITE(sc, ATW_SYNRF, 0); DELAY(5 * 1000); +} + +/* Set 16 TU max duration for the contention-free period (CFP). */ +void +atw_cfp_init(struct atw_softc *sc) +{ + uint32_t cfpp; - /* 16 TU max duration for contention-free period */ - reg = ATW_READ(sc, ATW_CFPP) & ~ATW_CFPP_CFPMD; - ATW_WRITE(sc, ATW_CFPP, reg | LSHIFT(16, ATW_CFPP_CFPMD)); + cfpp = ATW_READ(sc, ATW_CFPP); + cfpp &= ~ATW_CFPP_CFPMD; + cfpp |= LSHIFT(16, ATW_CFPP_CFPMD); + ATW_WRITE(sc, ATW_CFPP, cfpp); +} +void +atw_tofs0_init(struct atw_softc *sc) +{ /* XXX I guess that the Cardbus clock is 22MHz? * I am assuming that the role of ATW_TOFS0_USCNT is * to divide the bus clock to get a 1MHz clock---the datasheet is not @@ -1023,25 +1091,45 @@ atw_init(struct ifnet *ifp) ATW_WRITE(sc, ATW_TOFS0, LSHIFT(22, ATW_TOFS0_USCNT_MASK) | ATW_TOFS0_TUCNT_MASK /* set all bits in TUCNT */); +} - /* Initialize interframe spacing. EIFS=0x64 is used by a binary-only - * driver. Go figure. +/* Initialize interframe spacing: 802.11b slot time, SIFS, DIFS, EIFS. */ +void +atw_ifs_init(struct atw_softc *sc) +{ + uint32_t ifst; + /* XXX EIFS=0x64, SIFS=110 are used by the reference driver. + * Go figure. + */ + ifst = LSHIFT(IEEE80211_DUR_DS_SLOT, ATW_IFST_SLOT_MASK) | + LSHIFT(22 * 5 /* IEEE80211_DUR_DS_SIFS */ /* # of 22MHz cycles */, + ATW_IFST_SIFS_MASK) | + LSHIFT(IEEE80211_DUR_DS_DIFS, ATW_IFST_DIFS_MASK) | + LSHIFT(0x64 /* IEEE80211_DUR_DS_EIFS */, ATW_IFST_EIFS_MASK); + + ATW_WRITE(sc, ATW_IFST, ifst); +} + +void +atw_response_times_init(struct atw_softc *sc) +{ + /* XXX More magic. Relates to ACK timing? The datasheet seems to + * indicate that the MAC expects at least SIFS + MIRT microseconds + * to pass after it transmits a frame that requires a response; + * it waits at most SIFS + MART microseconds for the response. + * Surely this is not the ACK timeout? */ - reg = LSHIFT(IEEE80211_DUR_DS_SLOT, ATW_IFST_SLOT_MASK) | - LSHIFT(22 * IEEE80211_DUR_DS_SIFS /* # of 22MHz cycles */, - ATW_IFST_SIFS_MASK) | - LSHIFT(IEEE80211_DUR_DS_DIFS, ATW_IFST_DIFS_MASK) | - LSHIFT(0x64 /* IEEE80211_DUR_DS_EIFS */, ATW_IFST_EIFS_MASK); - ATW_WRITE(sc, ATW_IFST, reg); - - /* XXX More magic. Might relate to ACK timing. */ ATW_WRITE(sc, ATW_RSPT, LSHIFT(0xffff, ATW_RSPT_MART_MASK) | LSHIFT(0xff, ATW_RSPT_MIRT_MASK)); +} - /* Set up the MMI read/write addresses for the BBP. - * - * TBD find out the Marvel settings. - */ +/* Set up the MMI read/write addresses for the baseband. The Tx/Rx + * engines read and write baseband registers after Rx and before + * Tx, respectively. + */ +void +atw_bbp_io_init(struct atw_softc *sc) +{ switch (sc->sc_bbptype) { case ATW_BBPTYPE_INTERSIL: ATW_WRITE(sc, ATW_MMIWADDR, ATW_MMIWADDR_INTERSIL); @@ -1049,91 +1137,92 @@ atw_init(struct ifnet *ifp) ATW_WRITE(sc, ATW_MMIRADDR2, ATW_MMIRADDR2_INTERSIL); break; case ATW_BBPTYPE_MARVEL: + /* TBD find out the Marvel settings. */ break; case ATW_BBPTYPE_RFMD: + default: ATW_WRITE(sc, ATW_MMIWADDR, ATW_MMIWADDR_RFMD); ATW_WRITE(sc, ATW_MMIRADDR1, ATW_MMIRADDR1_RFMD); ATW_WRITE(sc, ATW_MMIRADDR2, ATW_MMIRADDR2_RFMD); - default: break; } - - sc->sc_wepctl = 0; ATW_WRITE(sc, ATW_MACTEST, ATW_MACTEST_MMI_USETXCLK); +} - if ((error = atw_rf3000_init(sc)) != 0) +/* + * atw_init: [ ifnet interface function ] + * + * Initialize the interface. Must be called at splnet(). + */ +int +atw_init(struct ifnet *ifp) +{ + struct atw_softc *sc = ifp->if_softc; + struct ieee80211com *ic = &sc->sc_ic; + struct atw_txsoft *txs; + struct atw_rxsoft *rxs; + int i, error = 0; + + if ((error = atw_enable(sc)) != 0) goto out; /* - * Initialize the PCI Access Register. + * Cancel any pending I/O. This also resets. */ - sc->sc_busmode = ATW_PAR_BAR; /* XXX what is this? */ + atw_stop(ifp, 0); - /* - * If we're allowed to do so, use Memory Read Line - * and Memory Read Multiple. + ic->ic_bss->ni_chan = ic->ic_ibss_chan; + DPRINTF(sc, ("%s: channel %d freq %d flags 0x%04x\n", + __func__, ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan), + ic->ic_bss->ni_chan->ic_freq, ic->ic_bss->ni_chan->ic_flags)); + + atw_wcsr_init(sc); + + atw_cmdr_init(sc); + + /* Set data rate for PLCP Signal field, 1Mbps = 10 x 100Kb/s. * - * XXX Should we use Memory Write and Invalidate? + * XXX Set transmit power for ATIM, RTS, Beacon. */ - if (sc->sc_flags & ATWF_MRL) - sc->sc_busmode |= ATW_PAR_MRLE; - if (sc->sc_flags & ATWF_MRM) - sc->sc_busmode |= ATW_PAR_MRME; - if (sc->sc_flags & ATWF_MWI) - sc->sc_busmode |= ATW_PAR_MWIE; - if (sc->sc_maxburst == 0) - sc->sc_maxburst = 8; /* ADM8211 default */ - - switch (sc->sc_cacheline) { - default: - /* Use burst length. */ - break; - case 8: - sc->sc_busmode |= ATW_PAR_CAL_8DW; - break; - case 16: - sc->sc_busmode |= ATW_PAR_CAL_16DW; - break; - case 32: - sc->sc_busmode |= ATW_PAR_CAL_32DW; - break; - } - switch (sc->sc_maxburst) { - case 1: - sc->sc_busmode |= ATW_PAR_PBL_1DW; - break; - case 2: - sc->sc_busmode |= ATW_PAR_PBL_2DW; - break; - case 4: - sc->sc_busmode |= ATW_PAR_PBL_4DW; - break; - case 8: - sc->sc_busmode |= ATW_PAR_PBL_8DW; - break; - case 16: - sc->sc_busmode |= ATW_PAR_PBL_16DW; - break; - case 32: - sc->sc_busmode |= ATW_PAR_PBL_32DW; - break; - default: - sc->sc_busmode |= ATW_PAR_PBL_8DW; - break; - } + ATW_WRITE(sc, ATW_PLCPHD, LSHIFT(10, ATW_PLCPHD_SIGNAL_MASK) | + LSHIFT(0xb0, ATW_PLCPHD_SERVICE_MASK)); + + atw_tofs2_init(sc); + + atw_nar_init(sc); + + atw_txlmt_init(sc); + + atw_test1_init(sc); + + atw_rf_reset(sc); + + atw_cfp_init(sc); + + atw_tofs0_init(sc); + + atw_ifs_init(sc); + + /* XXX Fall asleep after one second of inactivity. + * XXX A frame may only dribble in for 65536us. + */ + ATW_WRITE(sc, ATW_RMD, + LSHIFT(1, ATW_RMD_PCNT) | LSHIFT(0xffff, ATW_RMD_RMRD_MASK)); + + atw_response_times_init(sc); + + atw_bbp_io_init(sc); + + ATW_WRITE(sc, ATW_STSR, 0xffffffff); + + if ((error = atw_rf3000_init(sc)) != 0) + goto out; ATW_WRITE(sc, ATW_PAR, sc->sc_busmode); DPRINTF(sc, ("%s: ATW_PAR %08x busmode %08x\n", sc->sc_dev.dv_xname, ATW_READ(sc, ATW_PAR), sc->sc_busmode)); /* - * Initialize the OPMODE register. We don't write it until - * we're ready to begin the transmit and receive processes. - */ - sc->sc_opmode = ATW_NAR_SR | ATW_NAR_ST | - sc->sc_txth[sc->sc_txthresh].txth_opmode; - - /* * Initialize the transmit descriptor ring. */ memset(sc->sc_txdescs, 0, sizeof(sc->sc_txdescs)); @@ -1185,15 +1274,6 @@ atw_init(struct ifnet *ifp) } sc->sc_rxptr = 0; - /* disable all wake-up events */ - ATW_CLR(sc, ATW_WCSR, ATW_WCSR_WP1E|ATW_WCSR_WP2E|ATW_WCSR_WP3E| - ATW_WCSR_WP4E|ATW_WCSR_WP5E|ATW_WCSR_TSFTWE| - ATW_WCSR_TIMWE|ATW_WCSR_ATIMWE|ATW_WCSR_KEYWE| - ATW_WCSR_WFRE|ATW_WCSR_MPRE|ATW_WCSR_LSOE); - - /* ack all wake-up events */ - ATW_SET(sc, ATW_WCSR, 0); - /* * Initialize the interrupt mask and enable interrupts. */ @@ -1225,8 +1305,12 @@ atw_init(struct ifnet *ifp) /* * Give the transmit and receive rings to the ADM8211. */ - ATW_WRITE(sc, ATW_TDBD, ATW_CDTXADDR(sc, sc->sc_txnext)); ATW_WRITE(sc, ATW_RDB, ATW_CDRXADDR(sc, sc->sc_rxptr)); + ATW_WRITE(sc, ATW_TDBD, ATW_CDTXADDR(sc, sc->sc_txnext)); + + sc->sc_txthresh = 0; + sc->sc_opmode = ATW_NAR_SR | ATW_NAR_ST | + sc->sc_txth[sc->sc_txthresh].txth_opmode; /* common 802.11 configuration */ ic->ic_flags &= ~IEEE80211_F_IBSSON; @@ -1243,8 +1327,6 @@ atw_init(struct ifnet *ifp) break; } - atw_start_beacon(sc, 0); - switch (ic->ic_opmode) { case IEEE80211_M_AHDEMO: case IEEE80211_M_HOSTAP: @@ -1256,11 +1338,15 @@ atw_init(struct ifnet *ifp) break; } + sc->sc_wepctl = 0; + atw_write_ssid(sc); atw_write_sup_rates(sc); if (ic->ic_caps & IEEE80211_C_WEP) atw_write_wep(sc); + ic->ic_state = IEEE80211_S_INIT; + /* * Set the receive filter. This will start the transmit and * receive processes. @@ -1277,12 +1363,14 @@ atw_init(struct ifnet *ifp) */ ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; - ic->ic_state = IEEE80211_S_INIT; - if (ic->ic_opmode != IEEE80211_M_MONITOR) - error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); - else + /* send no beacons, yet. */ + atw_start_beacon(sc, 0); + + if (ic->ic_opmode == IEEE80211_M_MONITOR) error = ieee80211_new_state(ic, IEEE80211_S_RUN, -1); + else + error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); out: if (error) { ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); |