From: Kirill A. Korinsky Subject: Re: sys/ihidev: replace HONOR's touchpad quirk To: tech@openbsd.org Date: Wed, 27 May 2026 02:03:30 +0200 deraadt@ suggested to send the first byte to that device. It actually works and I started to dig around... Seems that the touchpad ignores the first command and it is a kind wakeup call. Replacing it to just touch an address works the same way. It was observed that sending anything to the touchpad wakes it up but it ignores the command that was sent. If it was GET_REPORT, when read reads series of 0xff. Sending anything to oher bus does not wake it up, but just touch it's address works. It smells like missed "wakeup" and I had checked linux sources in few places, here and where, but I haven't found anything similar to such wakeup call. So, here a very narrow quirk replacment for affected device. Thoughts? Ok? Index: sys/dev/fdt/qciic_fdt.c =================================================================== RCS file: /home/cvs/src/sys/dev/fdt/qciic_fdt.c,v diff -u -p -r1.4 qciic_fdt.c --- sys/dev/fdt/qciic_fdt.c 24 May 2026 10:36:01 -0000 1.4 +++ sys/dev/fdt/qciic_fdt.c 26 May 2026 23:30:50 -0000 @@ -38,6 +38,7 @@ #define GENI_M_CMD0 0x600 #define GENI_M_CMD0_OPCODE_I2C_WRITE (0x1 << 27) #define GENI_M_CMD0_OPCODE_I2C_READ (0x2 << 27) +#define GENI_M_CMD0_OPCODE_I2C_ADDR_ONLY (0x4 << 27) #define GENI_M_CMD0_SLV_ADDR_SHIFT 9 #define GENI_M_CMD0_STOP_STRETCH (1 << 2) #define GENI_M_IRQ_STATUS 0x610 @@ -222,6 +223,15 @@ qciic_fdt_exec(void *cookie, i2c_op_t op if (buflen == 0 && I2C_OP_STOP_P(op)) m_param &= ~GENI_M_CMD0_STOP_STRETCH; + + if (cmdlen == 0 && buflen == 0 && I2C_OP_WRITE_P(op)) { + stat = HREAD4(sc, GENI_M_IRQ_STATUS); + HWRITE4(sc, GENI_M_IRQ_CLEAR, stat); + m_cmd = GENI_M_CMD0_OPCODE_I2C_ADDR_ONLY | m_param; + HWRITE4(sc, GENI_M_CMD0, m_cmd); + + return qciic_fdt_wait(sc, GENI_M_IRQ_CMD_DONE); + } if (cmdlen > 0) { stat = HREAD4(sc, GENI_M_IRQ_STATUS); Index: sys/dev/i2c/ihidev.c =================================================================== RCS file: /home/cvs/src/sys/dev/i2c/ihidev.c,v diff -u -p -r1.43 ihidev.c --- sys/dev/i2c/ihidev.c 23 May 2026 11:10:57 -0000 1.43 +++ sys/dev/i2c/ihidev.c 26 May 2026 23:36:08 -0000 @@ -76,7 +76,7 @@ int ihidev_maxrepid(void *buf, int len); int ihidev_print(void *aux, const char *pnp); int ihidev_submatch(struct device *parent, void *cf, void *aux); -#define IHIDEV_QUIRK_RE_POWER_ON 0x1 +#define IHIDEV_QUIRK_WAKEUP 0x1 const struct ihidev_quirks { uint16_t ihq_vid; @@ -84,7 +84,7 @@ const struct ihidev_quirks { int ihq_quirks; } ihidev_devs[] = { /* HONOR MagicBook Art 14 Touchpad (QTEC0002) */ - { 0x35cc, 0x0104, IHIDEV_QUIRK_RE_POWER_ON }, + { 0x35cc, 0x0104, IHIDEV_QUIRK_WAKEUP }, }; const struct cfattach ihidev_ca = { @@ -402,6 +402,16 @@ ihidev_hid_command(struct ihidev_softc * */ tmprep = malloc(report_len, M_DEVBUF, M_WAITOK | M_ZERO); + if (sc->sc_quirks & IHIDEV_QUIRK_WAKEUP) { + /* + * Some devices, for example HONOR's Touchpad (QTEC0002) + * ignores the first command and returns all 0xff bytes + * unless it was "woke up" by an addressed transaction. + */ + iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, + NULL, 0, NULL, 0, 0); + } + /* type 3 id 8: 22 00 38 02 23 00 */ res = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, &cmd, cmdlen, tmprep, report_len, 0); @@ -653,23 +663,6 @@ ihidev_hid_desc_parse(struct ihidev_soft printf("%s: failed fetching HID report\n", sc->sc_dev.dv_xname); return (1); - } - - if (sc->sc_quirks & IHIDEV_QUIRK_RE_POWER_ON) { - if (ihidev_poweron(sc)) - return (1); - - /* - * 7.2.8 states that a device shall not respond back - * after receiving the power on command, and must ensure - * that it transitions to power on state in less than 1 - * second. The ihidev_poweron function uses a shorter - * sleep, sufficient for the ON-RESET sequence. Here, - * however, it sleeps for the full second to accommodate - * cold boot scenarios on affected devices. - */ - - ihidev_sleep(sc, 1000); } return (0); -- wbr, Kirill