diff options
author | Damien Bergamini <damien@cvs.openbsd.org> | 2009-09-20 20:04:08 +0000 |
---|---|---|
committer | Damien Bergamini <damien@cvs.openbsd.org> | 2009-09-20 20:04:08 +0000 |
commit | a8c19d41e3a23c8d15abd92805d8790a21d94390 (patch) | |
tree | 90f407b92e6b94ada3e5954c49431580f382ae5a /sys/dev | |
parent | ec236804e86c8361d96d2fb87389dda5a740e52f (diff) |
Implement a detach function in wpi(4) and iwn(4).
Some laptops will power off the PCIe socket when the radio kill
switch is turned on.
Reported and tested by Frantisek Holop on iwn(4).
Initial diff for iwn(4) by jsg@
Some additional bits by Frantisek Holop (sensor_detach).
Some tweaks and adaptation to wpi(4) by me.
Fixes kernel/6223.
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/pci/if_iwn.c | 45 | ||||
-rw-r--r-- | sys/dev/pci/if_wpi.c | 44 |
2 files changed, 85 insertions, 4 deletions
diff --git a/sys/dev/pci/if_iwn.c b/sys/dev/pci/if_iwn.c index bb5acd0bb30..ade4a6ae78c 100644 --- a/sys/dev/pci/if_iwn.c +++ b/sys/dev/pci/if_iwn.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_iwn.c,v 1.62 2009/08/10 17:21:15 damien Exp $ */ +/* $OpenBSD: if_iwn.c,v 1.63 2009/09/20 20:04:07 damien Exp $ */ /*- * Copyright (c) 2007-2009 Damien Bergamini <damien.bergamini@free.fr> @@ -99,6 +99,7 @@ void iwn_sensor_attach(struct iwn_softc *); #if NBPFILTER > 0 void iwn_radiotap_attach(struct iwn_softc *); #endif +int iwn_detach(struct device *, int); void iwn_power(int, void *); int iwn_nic_lock(struct iwn_softc *); int iwn_eeprom_lock(struct iwn_softc *); @@ -318,7 +319,7 @@ struct cfdriver iwn_cd = { }; struct cfattach iwn_ca = { - sizeof (struct iwn_softc), iwn_match, iwn_attach + sizeof (struct iwn_softc), iwn_match, iwn_attach, iwn_detach }; int @@ -646,6 +647,46 @@ iwn_radiotap_attach(struct iwn_softc *sc) } #endif +int +iwn_detach(struct device *self, int flags) +{ + struct iwn_softc *sc = (struct iwn_softc *)self; + struct ifnet *ifp = &sc->sc_ic.ic_if; + int s, qid; + + s = splnet(); + timeout_del(&sc->calib_to); + + /* Uninstall interrupt handler. */ + if (sc->sc_ih != NULL) + pci_intr_disestablish(sc->sc_pct, sc->sc_ih); + + ieee80211_ifdetach(ifp); + if_detach(ifp); + splx(s); + + /* Free DMA resources. */ + iwn_free_rx_ring(sc, &sc->rxq); + for (qid = 0; qid < sc->sc_hal->ntxqs; qid++) + iwn_free_tx_ring(sc, &sc->txq[qid]); + iwn_free_sched(sc); + iwn_free_kw(sc); + iwn_free_fwmem(sc); + +#ifndef SMALL_KERNEL + /* Detach the thermal sensor. */ + sensor_detach(&sc->sensordev, &sc->sensor); + sensordev_deinstall(&sc->sensordev); +#endif + + if (sc->powerhook != NULL) + powerhook_disestablish(sc->powerhook); + + bus_space_unmap(sc->sc_st, sc->sc_sh, sc->sc_sz); + + return 0; +} + void iwn_power(int why, void *arg) { diff --git a/sys/dev/pci/if_wpi.c b/sys/dev/pci/if_wpi.c index 5578e57766d..4c77d491ee6 100644 --- a/sys/dev/pci/if_wpi.c +++ b/sys/dev/pci/if_wpi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_wpi.c,v 1.91 2009/08/10 17:21:15 damien Exp $ */ +/* $OpenBSD: if_wpi.c,v 1.92 2009/09/20 20:04:07 damien Exp $ */ /*- * Copyright (c) 2006-2008 @@ -78,6 +78,7 @@ void wpi_sensor_attach(struct wpi_softc *); #if NBPFILTER > 0 void wpi_radiotap_attach(struct wpi_softc *); #endif +int wpi_detach(struct device *, int); void wpi_power(int, void *); int wpi_nic_lock(struct wpi_softc *); int wpi_read_prom_data(struct wpi_softc *, uint32_t, void *, int); @@ -165,7 +166,7 @@ struct cfdriver wpi_cd = { }; struct cfattach wpi_ca = { - sizeof (struct wpi_softc), wpi_match, wpi_attach + sizeof (struct wpi_softc), wpi_match, wpi_attach, wpi_detach }; int @@ -382,6 +383,45 @@ wpi_radiotap_attach(struct wpi_softc *sc) } #endif +int +wpi_detach(struct device *self, int flags) +{ + struct wpi_softc *sc = (struct wpi_softc *)self; + struct ifnet *ifp = &sc->sc_ic.ic_if; + int s, qid; + + s = splnet(); + timeout_del(&sc->calib_to); + + /* Uninstall interrupt handler. */ + if (sc->sc_ih != NULL) + pci_intr_disestablish(sc->sc_pct, sc->sc_ih); + + ieee80211_ifdetach(ifp); + if_detach(ifp); + splx(s); + + /* Free DMA resources. */ + wpi_free_rx_ring(sc, &sc->rxq); + for (qid = 0; qid < WPI_NTXQUEUES; qid++) + wpi_free_tx_ring(sc, &sc->txq[qid]); + wpi_free_shared(sc); + wpi_free_fwmem(sc); + +#ifndef SMALL_KERNEL + /* Detach the thermal sensor. */ + sensor_detach(&sc->sensordev, &sc->sensor); + sensordev_deinstall(&sc->sensordev); +#endif + + if (sc->powerhook != NULL) + powerhook_disestablish(sc->powerhook); + + bus_space_unmap(sc->sc_st, sc->sc_sh, sc->sc_sz); + + return 0; +} + void wpi_power(int why, void *arg) { |