Download raw body.
ihidev: be less aggressive with reset, fix T14s
On Sat, Oct 12, 2024 at 02:53:08PM +0200, Tobias Heider wrote:
> This diff fixes the ihidev keyboard on the Lenovo T14s Gen6.
> It turns out that this device doesn't like to receive multiple reset
> commands at all, after looking at other drivers it seems like we are
> the only ones that reset so aggressively.
>
> The diff replaces all but one occurrences of ihidev_reset() with the
> new ihidev_poweron() which only sends a power on command instead of
> always doing both.
>
> It would probably make sense to test this extensively on a range of hardware,
> Linux has a quirk to add explicit resets but that seems to only be needed for
> very few devices (ALPS 0x44e, possibly more).
> If break with this we might want to add a quirk to still reset them.
>
Thank you for finding this. Works on my t14s gen6
> diff 502b52cbdf550ec88ed0fcdac323f77049e93d3d 56627129dafdc9ab5465cdd1d777aa09e63460c1
> commit - 502b52cbdf550ec88ed0fcdac323f77049e93d3d
> commit + 56627129dafdc9ab5465cdd1d777aa09e63460c1
> blob - 4e65a4bf350b37ad5567a0c8d6535bd4e3c9cdbe
> blob + f6b8cc7b3436dc6c9bff99c817d4e5e2a45c3f44
> --- sys/dev/i2c/ihidev.c
> +++ sys/dev/i2c/ihidev.c
> @@ -67,6 +67,7 @@ int ihidev_activate(struct device *, int);
>
> int ihidev_hid_command(struct ihidev_softc *, int, void *);
> int ihidev_intr(void *);
> +int ihidev_poweron(struct ihidev_softc *);
> int ihidev_reset(struct ihidev_softc *);
> int ihidev_hid_desc_parse(struct ihidev_softc *);
>
> @@ -248,7 +249,7 @@ ihidev_activate(struct device *self, int act)
> sc->sc_dev.dv_xname);
> break;
> case DVACT_WAKEUP:
> - ihidev_reset(sc);
> + ihidev_poweron(sc);
> sc->sc_dying = 0;
> if (sc->sc_poll && timeout_initialized(&sc->sc_timer))
> timeout_add(&sc->sc_timer, 2000);
> @@ -525,7 +526,7 @@ ihidev_hid_command(struct ihidev_softc *sc, int hidcmd
> }
>
> int
> -ihidev_reset(struct ihidev_softc *sc)
> +ihidev_poweron(struct ihidev_softc *sc)
> {
> DPRINTF(("%s: resetting\n", sc->sc_dev.dv_xname));
>
> @@ -536,6 +537,16 @@ ihidev_reset(struct ihidev_softc *sc)
>
> ihidev_sleep(sc, 100);
>
> + return 0;
> +}
> +
> +
> +int
> +ihidev_reset(struct ihidev_softc *sc)
> +{
> + if (ihidev_poweron(sc))
> + return (1);
> +
> if (ihidev_hid_command(sc, I2C_HID_CMD_RESET, 0)) {
> printf("%s: failed to reset hardware\n", sc->sc_dev.dv_xname);
>
> @@ -784,7 +795,7 @@ ihidev_open(struct ihidev *scd)
> return (0);
>
> /* power on */
> - ihidev_reset(sc);
> + ihidev_poweron(sc);
>
> if (sc->sc_poll) {
> if (!timeout_initialized(&sc->sc_timer))
>
ihidev: be less aggressive with reset, fix T14s