summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorDamien Bergamini <damien@cvs.openbsd.org>2009-09-20 20:04:08 +0000
committerDamien Bergamini <damien@cvs.openbsd.org>2009-09-20 20:04:08 +0000
commita8c19d41e3a23c8d15abd92805d8790a21d94390 (patch)
tree90f407b92e6b94ada3e5954c49431580f382ae5a /sys/dev
parentec236804e86c8361d96d2fb87389dda5a740e52f (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.c45
-rw-r--r--sys/dev/pci/if_wpi.c44
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)
{