summaryrefslogtreecommitdiffstats
path: root/sys/dev/i2c/ihidev.c
diff options
context:
space:
mode:
authorjcs <jcs@openbsd.org>2019-07-22 14:37:06 +0000
committerjcs <jcs@openbsd.org>2019-07-22 14:37:06 +0000
commitd03221a8a1ef36fb9a6812f51de016cc43f8918e (patch)
tree423ce9f82c7e6cab116bbc5ebdd35238d34ab962 /sys/dev/i2c/ihidev.c
parentIn secure mode (-S), skip sending mail when executing the :pre[serve] (diff)
downloadwireguard-openbsd-d03221a8a1ef36fb9a6812f51de016cc43f8918e.tar.xz
wireguard-openbsd-d03221a8a1ef36fb9a6812f51de016cc43f8918e.zip
Even when polling is requested, install ihidev's interrupt handler
If an interrupt is received, turn off polling and rely on interrupts. This may happen after S3 resume. Also properly shut down polling during suspend and start it up again on resume only after dwiic is back in action.
Diffstat (limited to 'sys/dev/i2c/ihidev.c')
-rw-r--r--sys/dev/i2c/ihidev.c69
1 files changed, 62 insertions, 7 deletions
diff --git a/sys/dev/i2c/ihidev.c b/sys/dev/i2c/ihidev.c
index 50670975742..686d9f3986a 100644
--- a/sys/dev/i2c/ihidev.c
+++ b/sys/dev/i2c/ihidev.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ihidev.c,v 1.19 2019/04/08 17:50:45 jcs Exp $ */
+/* $OpenBSD: ihidev.c,v 1.20 2019/07/22 14:37:06 jcs Exp $ */
/*
* HID-over-i2c driver
*
@@ -63,6 +63,7 @@ static int I2C_HID_POWER_OFF = 0x1;
int ihidev_match(struct device *, void *, void *);
void ihidev_attach(struct device *, struct device *, void *);
int ihidev_detach(struct device *, int);
+int ihidev_activate(struct device *, int);
int ihidev_hid_command(struct ihidev_softc *, int, void *);
int ihidev_intr(void *);
@@ -80,7 +81,7 @@ struct cfattach ihidev_ca = {
ihidev_match,
ihidev_attach,
ihidev_detach,
- NULL
+ ihidev_activate,
};
struct cfdriver ihidev_cd = {
@@ -128,7 +129,7 @@ ihidev_attach(struct device *parent, struct device *self, void *aux)
printf(", can't establish interrupt");
}
- if (sc->sc_ih == NULL) {
+ if (ia->ia_poll) {
printf(" (polling)");
sc->sc_poll = 1;
sc->sc_fastpoll = 1;
@@ -227,6 +228,39 @@ ihidev_detach(struct device *self, int flags)
return (0);
}
+int
+ihidev_activate(struct device *self, int act)
+{
+ struct ihidev_softc *sc = (struct ihidev_softc *)self;
+
+ DPRINTF(("%s(%d)\n", __func__, act));
+
+ switch (act) {
+ case DVACT_QUIESCE:
+ sc->sc_dying = 1;
+ if (sc->sc_poll && timeout_initialized(&sc->sc_timer)) {
+ DPRINTF(("%s: canceling polling\n",
+ sc->sc_dev.dv_xname));
+ timeout_del_barrier(&sc->sc_timer);
+ }
+ if (ihidev_hid_command(sc, I2C_HID_CMD_SET_POWER,
+ &I2C_HID_POWER_OFF))
+ printf("%s: failed to power down\n",
+ sc->sc_dev.dv_xname);
+ break;
+ case DVACT_WAKEUP:
+ ihidev_reset(sc);
+ sc->sc_dying = 0;
+ if (sc->sc_poll && timeout_initialized(&sc->sc_timer))
+ timeout_add(&sc->sc_timer, 2000);
+ break;
+ }
+
+ config_activate_children(self, act);
+
+ return 0;
+}
+
void
ihidev_sleep(struct ihidev_softc *sc, int ms)
{
@@ -580,6 +614,16 @@ ihidev_hid_desc_parse(struct ihidev_softc *sc)
return (0);
}
+void
+ihidev_poll(void *arg)
+{
+ struct ihidev_softc *sc = arg;
+
+ sc->sc_frompoll = 1;
+ ihidev_intr(sc);
+ sc->sc_frompoll = 0;
+}
+
int
ihidev_intr(void *arg)
{
@@ -589,6 +633,16 @@ ihidev_intr(void *arg)
u_char *p;
u_int rep = 0;
+ if (sc->sc_dying)
+ return 1;
+
+ if (sc->sc_poll && !sc->sc_frompoll) {
+ DPRINTF(("%s: received interrupt while polling, disabling "
+ "polling\n", sc->sc_dev.dv_xname));
+ sc->sc_poll = 0;
+ timeout_del_barrier(&sc->sc_timer);
+ }
+
/*
* XXX: force I2C_F_POLL for now to avoid dwiic interrupting
* while we are interrupting
@@ -660,7 +714,7 @@ ihidev_intr(void *arg)
scd->sc_intr(scd, p, psize);
- if (sc->sc_poll && fast != sc->sc_fastpoll) {
+ if (sc->sc_poll && (fast != sc->sc_fastpoll)) {
DPRINTF(("%s: %s->%s polling\n", sc->sc_dev.dv_xname,
sc->sc_fastpoll ? "fast" : "slow",
fast ? "fast" : "slow"));
@@ -668,7 +722,8 @@ ihidev_intr(void *arg)
}
more_polling:
- if (sc->sc_poll && sc->sc_refcnt && !timeout_pending(&sc->sc_timer))
+ if (sc->sc_poll && sc->sc_refcnt && !sc->sc_dying &&
+ !timeout_pending(&sc->sc_timer))
timeout_add_msec(&sc->sc_timer,
sc->sc_fastpoll ? FAST_POLL_MS : SLOW_POLL_MS);
@@ -740,7 +795,7 @@ ihidev_open(struct ihidev *scd)
if (sc->sc_poll) {
if (!timeout_initialized(&sc->sc_timer))
- timeout_set(&sc->sc_timer, (void *)ihidev_intr, sc);
+ timeout_set(&sc->sc_timer, (void *)ihidev_poll, sc);
if (!timeout_pending(&sc->sc_timer))
timeout_add(&sc->sc_timer, FAST_POLL_MS);
}
@@ -766,7 +821,7 @@ ihidev_close(struct ihidev *scd)
/* no sub-devices open, conserve power */
- if (sc->sc_poll)
+ if (sc->sc_poll && timeout_pending(&sc->sc_timer))
timeout_del(&sc->sc_timer);
if (ihidev_hid_command(sc, I2C_HID_CMD_SET_POWER, &I2C_HID_POWER_OFF))