diff options
author | Joshua Stein <jcs@cvs.openbsd.org> | 2019-07-22 14:37:07 +0000 |
---|---|---|
committer | Joshua Stein <jcs@cvs.openbsd.org> | 2019-07-22 14:37:07 +0000 |
commit | 9eaa639926cd482e5712a57777dd2d41317749a3 (patch) | |
tree | 8240383e97b5a609203d3ca299a6b22200ad8ac6 /sys | |
parent | d98de6a33fbf3013598e78a4f06fd956b2dd094e (diff) |
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')
-rw-r--r-- | sys/dev/acpi/dwiic_acpi.c | 7 | ||||
-rw-r--r-- | sys/dev/i2c/i2cvar.h | 3 | ||||
-rw-r--r-- | sys/dev/i2c/ihidev.c | 69 | ||||
-rw-r--r-- | sys/dev/i2c/ihidev.h | 4 |
4 files changed, 71 insertions, 12 deletions
diff --git a/sys/dev/acpi/dwiic_acpi.c b/sys/dev/acpi/dwiic_acpi.c index b03642402cc..620e65f6421 100644 --- a/sys/dev/acpi/dwiic_acpi.c +++ b/sys/dev/acpi/dwiic_acpi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dwiic_acpi.c,v 1.9 2019/07/16 19:12:32 jcs Exp $ */ +/* $OpenBSD: dwiic_acpi.c,v 1.10 2019/07/22 14:37:06 jcs Exp $ */ /* * Synopsys DesignWare I2C controller * @@ -457,8 +457,9 @@ dwiic_acpi_found_ihidev(struct dwiic_softc *sc, struct aml_node *node, aml_freevalue(&res); - if (!sc->sc_poll_ihidev && - !(crs.irq_int == 0 && crs.gpio_int_node == NULL)) + if (sc->sc_poll_ihidev) + ia.ia_poll = 1; + if (!(crs.irq_int == 0 && crs.gpio_int_node == NULL)) ia.ia_intr = &crs; if (config_found(sc->sc_iic, &ia, dwiic_i2c_print)) { diff --git a/sys/dev/i2c/i2cvar.h b/sys/dev/i2c/i2cvar.h index bf9d06647ba..aaba3294055 100644 --- a/sys/dev/i2c/i2cvar.h +++ b/sys/dev/i2c/i2cvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: i2cvar.h,v 1.16 2016/04/23 09:40:28 kettenis Exp $ */ +/* $OpenBSD: i2cvar.h,v 1.17 2019/07/22 14:37:06 jcs Exp $ */ /* $NetBSD: i2cvar.h,v 1.1 2003/09/30 00:35:31 thorpej Exp $ */ /* @@ -113,6 +113,7 @@ struct i2c_attach_args { char *ia_name; /* chip name */ void *ia_cookie; /* pass extra info from bus to dev */ void *ia_intr; /* interrupt info */ + int ia_poll; /* to force polling */ }; /* 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)) diff --git a/sys/dev/i2c/ihidev.h b/sys/dev/i2c/ihidev.h index a9ff60f182d..dde7cef5ab5 100644 --- a/sys/dev/i2c/ihidev.h +++ b/sys/dev/i2c/ihidev.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ihidev.h,v 1.6 2018/08/25 18:32:05 jcs Exp $ */ +/* $OpenBSD: ihidev.h,v 1.7 2019/07/22 14:37:06 jcs Exp $ */ /* * HID-over-i2c driver * @@ -89,8 +89,10 @@ struct ihidev_softc { int sc_refcnt; int sc_poll; + int sc_frompoll; int sc_fastpoll; struct timeout sc_timer; + int sc_dying; }; struct ihidev { |