I still haven't figured out why ihidev doesn't receive interrupts
for I2C devices on Intel 100 series and newer.
But on an Intel 300 series laptop, I noticed that the Elan
touchscreen (ims at ihidev) does actually generate interrupts while
the Elan touchpad (imt at ihidev) doesn't. In this scenario, we can
disable polling on the touchscreen to save some power and make input
smoother.
This diff always sets up the interrupt even when polling is
requested, and if the interrupt handler ever fires when polling is
enabled, disable polling.
Index: dev/acpi/dwiic_acpi.c
===================================================================
RCS file: /cvs/src/sys/dev/acpi/dwiic_acpi.c,v
retrieving revision 1.8
diff -u -p -u -p -r1.8 dwiic_acpi.c
--- dev/acpi/dwiic_acpi.c 1 Jul 2018 11:37:11 -0000 1.8
+++ dev/acpi/dwiic_acpi.c 16 Mar 2019 15:39:34 -0000
@@ -462,8 +462,9 @@ dwiic_acpi_found_ihidev(struct dwiic_sof
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)) {
Index: dev/i2c/i2cvar.h
===================================================================
RCS file: /cvs/src/sys/dev/i2c/i2cvar.h,v
retrieving revision 1.16
diff -u -p -u -p -r1.16 i2cvar.h
--- dev/i2c/i2cvar.h 23 Apr 2016 09:40:28 -0000 1.16
+++ dev/i2c/i2cvar.h 16 Mar 2019 15:39:34 -0000
@@ -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 */
};
/*
Index: dev/i2c/ihidev.c
===================================================================
RCS file: /cvs/src/sys/dev/i2c/ihidev.c,v
retrieving revision 1.18
diff -u -p -u -p -r1.18 ihidev.c
--- dev/i2c/ihidev.c 20 Sep 2018 01:19:56 -0000 1.18
+++ dev/i2c/ihidev.c 16 Mar 2019 15:39:34 -0000
@@ -128,7 +128,7 @@ ihidev_attach(struct device *parent, str
printf(", can't establish interrupt");
}
- if (sc->sc_ih == NULL) {
+ if (ia->ia_poll) {
printf(" (polling)");
sc->sc_poll = 1;
sc->sc_fastpoll = 1;
@@ -580,6 +580,16 @@ ihidev_hid_desc_parse(struct ihidev_soft
return (0);
}
+void
+ihidev_poll(void *arg)
+{
+ struct ihidev_softc *sc = arg;
+
+ sc->sc_dopoll = 1;
+ ihidev_intr(sc);
+ sc->sc_dopoll = 0;
+}
+
int
ihidev_intr(void *arg)
{
@@ -590,6 +600,13 @@ ihidev_intr(void *arg)
u_char *p;
u_int rep = 0;
+ if (sc->sc_poll && !sc->sc_dopoll) {
+ printf("%s: received interrupt while polling, disabling "
+ "polling\n", sc->sc_dev.dv_xname);
+ sc->sc_poll = 0;
+ timeout_del(&sc->sc_timer);
+ }
+
/*
* XXX: force I2C_F_POLL for now to avoid dwiic interrupting
* while we are interrupting
@@ -741,7 +758,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);
}
Index: dev/i2c/ihidev.h
===================================================================
RCS file: /cvs/src/sys/dev/i2c/ihidev.h,v
retrieving revision 1.6
diff -u -p -u -p -r1.6 ihidev.h
--- dev/i2c/ihidev.h 25 Aug 2018 18:32:05 -0000 1.6
+++ dev/i2c/ihidev.h 16 Mar 2019 15:39:34 -0000
@@ -89,6 +89,7 @@ struct ihidev_softc {
int sc_refcnt;
int sc_poll;
+ int sc_dopoll;
int sc_fastpoll;
struct timeout sc_timer;
};