Index: sys/dev/iwn/if_iwnvar.h =================================================================== --- sys/dev/iwn/if_iwnvar.h (revision 27) +++ sys/dev/iwn/if_iwnvar.h (working copy) @@ -259,8 +259,6 @@ struct iwn_softc { /* Tasks used by the driver */ struct task sc_reinit_task; - struct task sc_radioon_task; - struct task sc_radiooff_task; int calib_cnt; struct iwn_calib_state calib; Index: sys/dev/iwn/if_iwn.c =================================================================== --- sys/dev/iwn/if_iwn.c (revision 27) +++ sys/dev/iwn/if_iwn.c (working copy) @@ -69,10 +69,13 @@ __FBSDID("$FreeBSD: head/sys/dev/iwn/if_iwn.c 1984 #include #include +#include + #include #include static int iwn_probe(device_t); +static int iwn_rfkill_state(void *); static int iwn_attach(device_t); const struct iwn_hal *iwn_hal_attach(struct iwn_softc *); void iwn_radiotap_attach(struct iwn_softc *); @@ -227,8 +230,6 @@ static int iwn_setregdomain(struct ieee80211com *, struct ieee80211_regdomain *, int, struct ieee80211_channel []); static void iwn_hw_reset(void *, int); -static void iwn_radio_on(void *, int); -static void iwn_radio_off(void *, int); static void iwn_sysctlattach(struct iwn_softc *); static int iwn_shutdown(device_t); static int iwn_suspend(device_t); @@ -369,6 +370,15 @@ iwn_probe(device_t dev) } static int +iwn_rfkill_state(void *arg) +{ + struct ieee80211com *ic = arg; + struct iwn_softc *sc = ic->ic_ifp->if_softc; + + return !(IWN_READ(sc, IWN_GP_CNTRL) & IWN_GP_CNTRL_RFKILL); +} + +static int iwn_attach(device_t dev) { struct iwn_softc *sc = (struct iwn_softc *)device_get_softc(dev); @@ -432,8 +442,6 @@ iwn_attach(device_t dev) IWN_LOCK_INIT(sc); callout_init_mtx(&sc->sc_timer_to, &sc->sc_mtx, 0); TASK_INIT(&sc->sc_reinit_task, 0, iwn_hw_reset, sc ); - TASK_INIT(&sc->sc_radioon_task, 0, iwn_radio_on, sc ); - TASK_INIT(&sc->sc_radiooff_task, 0, iwn_radio_off, sc ); /* Attach Hardware Abstraction Layer. */ hal = iwn_hal_attach(sc); @@ -620,6 +628,11 @@ iwn_attach(device_t dev) ic->ic_ampdu_tx_stop = iwn_ampdu_tx_stop; #endif + /* RF kill hard switches. */ + ic->ic_rfkill->rf_hard_switch_state = &iwn_rfkill_state; + rfkill_set_state(ic->ic_rfkill, RFKILL_HARD_SWITCH, + iwn_rfkill_state(ic), 0); + iwn_radiotap_attach(sc); iwn_sysctlattach(sc); @@ -635,6 +648,16 @@ iwn_attach(device_t dev) } ieee80211_announce(ic); + + /* + * When disabled by a RF kill switch, enable interrupts early to + * receive RF toggle notifications. + */ + if (ic->ic_rfkill->rf_isblocked(ic->ic_rfkill)) { + IWN_WRITE(sc, IWN_INT, 0xffffffff); + IWN_WRITE(sc, IWN_INT_MASK, IWN_INT_MASK_DEF); + } + return 0; fail: iwn_cleanup(dev); @@ -787,8 +810,6 @@ iwn_cleanup(device_t dev) ic = ifp->if_l2com; ieee80211_draintask(ic, &sc->sc_reinit_task); - ieee80211_draintask(ic, &sc->sc_radioon_task); - ieee80211_draintask(ic, &sc->sc_radiooff_task); iwn_stop(sc); callout_drain(&sc->sc_timer_to); @@ -2568,16 +2589,15 @@ iwn_rftoggle_intr(struct iwn_softc *sc) { struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; - uint32_t tmp = IWN_READ(sc, IWN_GP_CNTRL); + int rfstate = iwn_rfkill_state(ic); IWN_LOCK_ASSERT(sc); device_printf(sc->sc_dev, "RF switch: radio %s\n", - (tmp & IWN_GP_CNTRL_RFKILL) ? "enabled" : "disabled"); - if (tmp & IWN_GP_CNTRL_RFKILL) - ieee80211_runtask(ic, &sc->sc_radioon_task); - else - ieee80211_runtask(ic, &sc->sc_radiooff_task); + rfstate ? "disabled" : "enabled"); + IWN_UNLOCK(sc); + rfkill_set_state(ic->ic_rfkill, RFKILL_HARD_SWITCH, rfstate, 1); + IWN_LOCK(sc); } /* @@ -3336,9 +3356,8 @@ iwn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t d { struct iwn_softc *sc = ifp->if_softc; struct ieee80211com *ic = ifp->if_l2com; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); struct ifreq *ifr = (struct ifreq *) data; - int error = 0, startall = 0, stop = 0; + int error = 0, startall = 0; switch (cmd) { case SIOCSIFFLAGS: @@ -3346,10 +3365,7 @@ iwn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t d if (ifp->if_flags & IFF_UP) { if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { iwn_init_locked(sc); - if (IWN_READ(sc, IWN_GP_CNTRL) & IWN_GP_CNTRL_RFKILL) - startall = 1; - else - stop = 1; + startall = 1; } } else { if (ifp->if_drv_flags & IFF_DRV_RUNNING) @@ -3358,8 +3374,6 @@ iwn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t d IWN_UNLOCK(sc); if (startall) ieee80211_start_all(ic); - else if (stop) - ieee80211_stop(vap); break; case SIOCGIFMEDIA: error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); @@ -5976,6 +5990,7 @@ void iwn_hw_stop(struct iwn_softc *sc) { const struct iwn_hal *hal = sc->sc_hal; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; uint32_t tmp; int chnl, qid, ntries; @@ -6024,6 +6039,15 @@ iwn_hw_stop(struct iwn_softc *sc) /* Power OFF adapter. */ iwn_apm_stop(sc); + + /* + * If the device is blocked by a hardware switch, enable interrupts to + * receive RF toggle notifications. + */ + if (ic->ic_rfkill->rf_isblocked(ic->ic_rfkill)) { + IWN_WRITE(sc, IWN_INT, 0xffffffff); + IWN_WRITE(sc, IWN_INT_MASK, sc->int_mask); + } } void @@ -6045,17 +6069,6 @@ iwn_init_locked(struct iwn_softc *sc) sc->int_mask = IWN_INT_MASK_DEF; sc->sc_flags &= ~IWN_FLAG_USE_ICT; - /* Check that the radio is not disabled by hardware switch. */ - if (!(IWN_READ(sc, IWN_GP_CNTRL) & IWN_GP_CNTRL_RFKILL)) { - device_printf(sc->sc_dev, - "radio is disabled by hardware switch\n"); - - /* Enable interrupts to get RF toggle notifications. */ - IWN_WRITE(sc, IWN_INT, 0xffffffff); - IWN_WRITE(sc, IWN_INT_MASK, sc->int_mask); - return; - } - /* Read firmware images from the filesystem. */ error = iwn_read_firmware(sc); if (error != 0) { @@ -6266,36 +6279,6 @@ iwn_hw_reset(void *arg0, int pending) } static void -iwn_radio_on(void *arg0, int pending) -{ - struct iwn_softc *sc = arg0; - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - - iwn_init(sc); - ieee80211_init(vap); -} - -static void -iwn_radio_off(void *arg0, int pending) -{ - struct iwn_softc *sc = arg0; - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - - iwn_stop(sc); - ieee80211_stop(vap); - - /* Enable interrupts to get RF toggle notification. */ - IWN_LOCK(sc); - IWN_WRITE(sc, IWN_INT, 0xffffffff); - IWN_WRITE(sc, IWN_INT_MASK, sc->int_mask); - IWN_UNLOCK(sc); -} - -static void iwn_sysctlattach(struct iwn_softc *sc) { struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev); @@ -6412,5 +6395,6 @@ static devclass_t iwn_devclass; DRIVER_MODULE(iwn, pci, iwn_driver, iwn_devclass, 0, 0); MODULE_DEPEND(iwn, pci, 1, 1, 1); MODULE_DEPEND(iwn, firmware, 1, 1, 1); +MODULE_DEPEND(iwn, rfkill, 1, 1, 1); MODULE_DEPEND(iwn, wlan, 1, 1, 1); MODULE_DEPEND(iwn, wlan_amrr, 1, 1, 1);