tech-net archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
powerd(8) radio_button event; wpi(4) implementation
Hello,
as described in a previous thread ("wpi0: radio is disabled by hardware
switch"), in order to get userland notifications when the wifi switch
is turned on or off (e.g. to start/stop wpa_supplicant), I implemented
a new sysmon_pswitch(9) switch type, PSWITCH_TYPE_RADIO. I also
changed wpi(4) so that it would report button "pressed" and "released"
events (which would be better described as "on" and "off" but
this is what sysmon_pswitch(9) knows for buttons).
With the attached patch (against netbsd-7, but -current should'nt be much
different), and an extra radio_button script in /etc/powerd/scripts/,
wpa_suplicant is automatically started when I turn the radio button
on, and stopped when I turn the radio button off (the driver takes care of
taking the interface down itself).
Does anyone object to this change ?
--
Manuel Bouyer <bouyer%antioche.eu.org@localhost>
NetBSD: 26 ans d'experience feront toujours la difference
--
Index: share/man/man9/sysmon_pswitch.9
===================================================================
RCS file: /cvsroot/src/share/man/man9/sysmon_pswitch.9,v
retrieving revision 1.5
diff -u -p -u -r1.5 sysmon_pswitch.9
--- share/man/man9/sysmon_pswitch.9 18 Mar 2014 18:20:40 -0000 1.5
+++ share/man/man9/sysmon_pswitch.9 19 Dec 2014 15:48:22 -0000
@@ -75,6 +75,7 @@ The following types are defined:
.It PSWITCH_TYPE_RESET
.It PSWITCH_TYPE_ACADAPTER
.It PSWITCH_TYPE_HOTKEY
+.It PSWITCH_TYPE_RADIO
.El
.Pp
If the type is
Index: sys/dev/pci/if_wpi.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/if_wpi.c,v
retrieving revision 1.68
diff -u -p -u -r1.68 if_wpi.c
--- sys/dev/pci/if_wpi.c 8 Aug 2014 10:17:07 -0000 1.68
+++ sys/dev/pci/if_wpi.c 19 Dec 2014 15:48:24 -0000
@@ -39,6 +39,7 @@ __KERNEL_RCSID(0, "$NetBSD: if_wpi.c,v 1
#include <sys/kauth.h>
#include <sys/callout.h>
#include <sys/proc.h>
+#include <sys/kthread.h>
#include <sys/bus.h>
#include <machine/endian.h>
@@ -48,6 +49,8 @@ __KERNEL_RCSID(0, "$NetBSD: if_wpi.c,v 1
#include <dev/pci/pcivar.h>
#include <dev/pci/pcidevs.h>
+#include <dev/sysmon/sysmonvar.h>
+
#include <net/bpf.h>
#include <net/if.h>
#include <net/if_arp.h>
@@ -153,6 +156,7 @@ static void wpi_stop(struct ifnet *, int
static bool wpi_resume(device_t, const pmf_qual_t *);
static int wpi_getrfkill(struct wpi_softc *);
static void wpi_sysctlattach(struct wpi_softc *);
+static void wpi_rsw_thread(void *);
#ifdef WPI_DEBUG
#define DPRINTF(x) do { if (wpi_debug > 0) printf x; } while (0)
@@ -214,6 +218,22 @@ wpi_attach(device_t parent __unused, dev
sc->sc_pct = pa->pa_pc;
sc->sc_pcitag = pa->pa_tag;
+ sc->sc_rsw_status = WPI_RSW_UNKNOWN;
+ sc->sc_rsw.smpsw_name = device_xname(self);
+ sc->sc_rsw.smpsw_type = PSWITCH_TYPE_RADIO;
+ error = sysmon_pswitch_register(&sc->sc_rsw);
+ if (error) {
+ aprint_error_dev(self,
+ "unable to register radio switch with sysmon\n");
+ return;
+ }
+ mutex_init(&sc->sc_rsw_mtx, MUTEX_DEFAULT, IPL_NONE);
+ cv_init(&sc->sc_rsw_cv, "wpirsw");
+ if (kthread_create(PRI_NONE, 0, NULL,
+ wpi_rsw_thread, sc, &sc->sc_rsw_lwp, "%s", device_xname(self))) {
+ aprint_error_dev(self, "couldn't create switch thread\n");
+ }
+
callout_init(&sc->calib_to, 0);
callout_setfunc(&sc->calib_to, wpi_calib_timeout, sc);
@@ -411,6 +431,13 @@ wpi_detach(device_t self, int flags __un
pci_intr_disestablish(sc->sc_pct, sc->sc_ih);
sc->sc_ih = NULL;
}
+ mutex_enter(&sc->sc_rsw_mtx);
+ sc->sc_dying = 1;
+ cv_signal(&sc->sc_rsw_cv);
+ while (sc->sc_rsw_lwp != NULL)
+ cv_wait(&sc->sc_rsw_cv, &sc->sc_rsw_mtx);
+ mutex_exit(&sc->sc_rsw_mtx);
+ sysmon_pswitch_unregister(&sc->sc_rsw);
bus_space_unmap(sc->sc_st, sc->sc_sh, sc->sc_sz);
@@ -418,7 +445,8 @@ wpi_detach(device_t self, int flags __un
sc->fw_used = false;
wpi_release_firmware();
}
-
+ cv_destroy(&sc->sc_rsw_cv);
+ mutex_destroy(&sc->sc_rsw_mtx);
return 0;
}
@@ -1688,6 +1716,8 @@ wpi_notif_intr(struct wpi_softc *sc)
if (le32toh(*status) & 1) {
/* the radio button has to be pushed */
+ /* wake up thread to signal powerd */
+ cv_signal(&sc->sc_rsw_cv);
aprint_error_dev(sc->sc_dev,
"Radio transmitter is off\n");
/* turn the interface down */
@@ -3167,9 +3197,13 @@ wpi_init(struct ifnet *ifp)
goto fail1;
/* Check the status of the radio switch */
- if (wpi_getrfkill(sc)) {
+ mutex_enter(&sc->sc_rsw_mtx);
+ error = wpi_getrfkill(sc);
+ mutex_exit(&sc->sc_rsw_mtx);
+ if (error) {
aprint_error_dev(sc->sc_dev,
"radio is disabled by hardware switch\n");
+ ifp->if_flags &= ~IFF_UP;
error = EBUSY;
goto fail1;
}
@@ -3275,6 +3309,23 @@ wpi_getrfkill(struct wpi_softc *sc)
tmp = wpi_mem_read(sc, WPI_MEM_RFKILL);
wpi_mem_unlock(sc);
+ KASSERT(mutex_owned(&sc->sc_rsw_mtx));
+ if (tmp & 0x01) {
+ /* switch is on */
+ if (sc->sc_rsw_status != WPI_RSW_ON) {
+ sc->sc_rsw_status = WPI_RSW_ON;
+ sysmon_pswitch_event(&sc->sc_rsw,
+ PSWITCH_EVENT_PRESSED);
+ }
+ } else {
+ /* switch is off */
+ if (sc->sc_rsw_status != WPI_RSW_OFF) {
+ sc->sc_rsw_status = WPI_RSW_OFF;
+ sysmon_pswitch_event(&sc->sc_rsw,
+ PSWITCH_EVENT_RELEASED);
+ }
+ }
+
return !(tmp & 0x01);
}
@@ -3288,7 +3339,9 @@ wpi_sysctl_radio(SYSCTLFN_ARGS)
node = *rnode;
sc = (struct wpi_softc *)node.sysctl_data;
+ mutex_enter(&sc->sc_rsw_mtx);
val = !wpi_getrfkill(sc);
+ mutex_exit(&sc->sc_rsw_mtx);
node.sysctl_data = &val;
error = sysctl_lookup(SYSCTLFN_CALL(&node));
@@ -3333,3 +3386,22 @@ wpi_sysctlattach(struct wpi_softc *sc)
err:
aprint_error("%s: sysctl_createv failed (rc = %d)\n", __func__, rc);
}
+
+static void
+wpi_rsw_thread(void *arg)
+{
+ struct wpi_softc *sc = (struct wpi_softc *)arg;
+
+ mutex_enter(&sc->sc_rsw_mtx);
+ for (;;) {
+ cv_timedwait(&sc->sc_rsw_cv, &sc->sc_rsw_mtx, hz);
+ if (sc->sc_dying) {
+ sc->sc_rsw_lwp = NULL;
+ cv_broadcast(&sc->sc_rsw_cv);
+ mutex_exit(&sc->sc_rsw_mtx);
+ kthread_exit(0);
+ }
+ wpi_getrfkill(sc);
+ }
+}
+
Index: sys/dev/pci/if_wpivar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/if_wpivar.h,v
retrieving revision 1.18
diff -u -p -u -r1.18 if_wpivar.h
--- sys/dev/pci/if_wpivar.h 9 Aug 2014 15:07:06 -0000 1.18
+++ sys/dev/pci/if_wpivar.h 19 Dec 2014 15:48:24 -0000
@@ -187,4 +187,13 @@ struct wpi_softc {
bool is_scanning;
struct sysctllog *sc_sysctllog;
+ struct sysmon_pswitch sc_rsw; /* for radio switch events */
+ int sc_rsw_status;
+#define WPI_RSW_UNKNOWN 0
+#define WPI_RSW_OFF 1
+#define WPI_RSW_ON 2
+ struct lwp *sc_rsw_lwp;
+ struct kmutex sc_rsw_mtx;
+ struct kcondvar sc_rsw_cv;
+ int sc_dying;
};
Index: sys/dev/sysmon/sysmon_power.c
===================================================================
RCS file: /cvsroot/src/sys/dev/sysmon/sysmon_power.c,v
retrieving revision 1.47
diff -u -p -u -r1.47 sysmon_power.c
--- sys/dev/sysmon/sysmon_power.c 10 Aug 2014 16:44:36 -0000 1.47
+++ sys/dev/sysmon/sysmon_power.c 19 Dec 2014 15:48:24 -0000
@@ -121,6 +121,7 @@ static const struct power_event_descript
{ PSWITCH_TYPE_RESET, "reset_button" },
{ PSWITCH_TYPE_ACADAPTER, "acadapter" },
{ PSWITCH_TYPE_HOTKEY, "hotkey_button" },
+ { PSWITCH_TYPE_RADIO, "radio_button" },
{ -1, NULL }
};
Index: sys/sys/power.h
===================================================================
RCS file: /cvsroot/src/sys/sys/power.h,v
retrieving revision 1.19
diff -u -p -u -r1.19 power.h
--- sys/sys/power.h 30 Mar 2013 19:05:20 -0000 1.19
+++ sys/sys/power.h 19 Dec 2014 15:48:26 -0000
@@ -83,6 +83,10 @@
* of switch has state. We know if it is open
* or closed.
*
+ * Radio switch This is e.g. the switch of the transmitter
+ * of a wifi interface. We know if it is
+ * on or off.
+ *
*/
#define PSWITCH_TYPE_POWER 0 /* power button */
@@ -111,6 +115,7 @@
#define PSWITCH_HK_VOLUME_DOWN "volume-down"
#define PSWITCH_HK_VOLUME_MUTE "volume-mute"
#endif /* THINKPAD_NORMAL_HOTKEYS */
+#define PSWITCH_TYPE_RADIO 6 /* radio switch */
#define PSWITCH_EVENT_PRESSED 0 /* button pressed, lid closed, AC off */
#define PSWITCH_EVENT_RELEASED 1 /* button released, lid open, AC on */
Home |
Main Index |
Thread Index |
Old Index