The branch main has been updated by wulf:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=df6ae0577d2c966ac0db9983ae353c24b53067eb

commit df6ae0577d2c966ac0db9983ae353c24b53067eb
Author:     Vladimir Kondratyev <w...@freebsd.org>
AuthorDate: 2025-08-17 21:00:44 +0000
Commit:     Vladimir Kondratyev <w...@freebsd.org>
CommitDate: 2025-08-17 21:00:44 +0000

    hid: Allow serial execution of HID_INTR_START method.
    
    It is required to implement HQ_NO_READAHEAD HID quirk.
    
    Differential revision:  https://reviews.freebsd.org/D51606
---
 sys/dev/hid/hidbus.c    | 41 +++++++++++++++--------------------------
 sys/dev/hid/ietp.c      | 31 +++++++++++++++++++++++--------
 sys/dev/iicbus/iichid.c |  3 ++-
 3 files changed, 40 insertions(+), 35 deletions(-)

diff --git a/sys/dev/hid/hidbus.c b/sys/dev/hid/hidbus.c
index 96d36c8d191d..683449fca49c 100644
--- a/sys/dev/hid/hidbus.c
+++ b/sys/dev/hid/hidbus.c
@@ -65,7 +65,7 @@ struct hidbus_ivars {
        struct mtx                      *mtx;           /* child intr mtx */
        hid_intr_t                      *intr_handler;  /* executed under mtx*/
        void                            *intr_ctx;
-       unsigned int                    refcnt;         /* protected by mtx */
+       bool                            active;         /* protected by mtx */
        struct epoch_context            epoch_ctx;
        CK_STAILQ_ENTRY(hidbus_ivars)   link;
 };
@@ -398,7 +398,7 @@ hidbus_child_detached(device_t bus, device_t child)
        struct hidbus_softc *sc = device_get_softc(bus);
        struct hidbus_ivars *tlc = device_get_ivars(child);
 
-       KASSERT(tlc->refcnt == 0, ("Child device is running"));
+       KASSERT(!tlc->active, ("Child device is running"));
        tlc->mtx = &sc->mtx;
        tlc->intr_handler = NULL;
        tlc->flags &= ~HIDBUS_FLAG_CAN_POLL;
@@ -423,7 +423,7 @@ hidbus_child_deleted(device_t bus, device_t child)
        struct hidbus_ivars *tlc = device_get_ivars(child);
 
        sx_xlock(&sc->sx);
-       KASSERT(tlc->refcnt == 0, ("Child device is running"));
+       KASSERT(!tlc->active, ("Child device is running"));
        CK_STAILQ_REMOVE(&sc->tlcs, tlc, hidbus_ivars, link);
        sx_unlock(&sc->sx);
        epoch_call(INPUT_EPOCH, hidbus_ivar_dtor, &tlc->epoch_ctx);
@@ -572,7 +572,7 @@ hidbus_intr(void *context, void *buf, hid_size_t len)
        if (!HID_IN_POLLING_MODE())
                epoch_enter_preempt(INPUT_EPOCH, &et);
        CK_STAILQ_FOREACH(tlc, &sc->tlcs, link) {
-               if (tlc->refcnt == 0 || tlc->intr_handler == NULL)
+               if (!tlc->active || tlc->intr_handler == NULL)
                        continue;
                if (HID_IN_POLLING_MODE()) {
                        if ((tlc->flags & HIDBUS_FLAG_CAN_POLL) != 0)
@@ -602,21 +602,14 @@ hidbus_intr_start(device_t bus, device_t child)
        MPASS(bus == device_get_parent(child));
        struct hidbus_softc *sc = device_get_softc(bus);
        struct hidbus_ivars *ivar = device_get_ivars(child);
-       struct hidbus_ivars *tlc;
-       bool refcnted = false;
        int error;
 
        if (sx_xlock_sig(&sc->sx) != 0)
                return (EINTR);
-       CK_STAILQ_FOREACH(tlc, &sc->tlcs, link) {
-               refcnted |= (tlc->refcnt != 0);
-               if (tlc == ivar) {
-                       mtx_lock(tlc->mtx);
-                       ++tlc->refcnt;
-                       mtx_unlock(tlc->mtx);
-               }
-       }
-       error = refcnted ? 0 : hid_intr_start(bus);
+       mtx_lock(ivar->mtx);
+       ivar->active = true;
+       mtx_unlock(ivar->mtx);
+       error = hid_intr_start(bus);
        sx_unlock(&sc->sx);
 
        return (error);
@@ -629,21 +622,17 @@ hidbus_intr_stop(device_t bus, device_t child)
        struct hidbus_softc *sc = device_get_softc(bus);
        struct hidbus_ivars *ivar = device_get_ivars(child);
        struct hidbus_ivars *tlc;
-       bool refcnted = false;
+       bool active = false;
        int error;
 
        if (sx_xlock_sig(&sc->sx) != 0)
                return (EINTR);
-       CK_STAILQ_FOREACH(tlc, &sc->tlcs, link) {
-               if (tlc == ivar) {
-                       mtx_lock(tlc->mtx);
-                       MPASS(tlc->refcnt != 0);
-                       --tlc->refcnt;
-                       mtx_unlock(tlc->mtx);
-               }
-               refcnted |= (tlc->refcnt != 0);
-       }
-       error = refcnted ? 0 : hid_intr_stop(bus);
+       mtx_lock(ivar->mtx);
+       ivar->active = false;
+       mtx_unlock(ivar->mtx);
+       CK_STAILQ_FOREACH(tlc, &sc->tlcs, link)
+               active |= tlc->active;
+       error = active ? 0 : hid_intr_stop(bus);
        sx_unlock(&sc->sx);
 
        return (error);
diff --git a/sys/dev/hid/ietp.c b/sys/dev/hid/ietp.c
index 217585a7948b..73a5cb7414d4 100644
--- a/sys/dev/hid/ietp.c
+++ b/sys/dev/hid/ietp.c
@@ -102,6 +102,7 @@ struct ietp_softc {
        device_t                dev;
 
        struct evdev_dev        *evdev;
+       bool                    open;
        uint8_t                 report_id;
        hid_size_t              report_len;
 
@@ -217,13 +218,25 @@ static const struct evdev_methods ietp_evdev_methods = {
 static int
 ietp_ev_open(struct evdev_dev *evdev)
 {
-       return (hid_intr_start(evdev_get_softc(evdev)));
+       struct ietp_softc *sc = evdev_get_softc(evdev);
+       int error;
+
+       error = hid_intr_start(sc->dev);
+       if (error == 0)
+               sc->open = true;
+       return (error);
 }
 
 static int
 ietp_ev_close(struct evdev_dev *evdev)
 {
-       return (hid_intr_stop(evdev_get_softc(evdev)));
+       struct ietp_softc *sc = evdev_get_softc(evdev);
+       int error;
+
+       error = hid_intr_stop(sc->dev);
+       if (error == 0)
+               sc->open = false;
+       return (error);
 }
 
 static int
@@ -275,7 +288,7 @@ ietp_attach(struct ietp_softc *sc)
        evdev_set_id(sc->evdev, hw->idBus, hw->idVendor, hw->idProduct,
            hw->idVersion);
        evdev_set_serial(sc->evdev, hw->serial);
-       evdev_set_methods(sc->evdev, sc->dev, &ietp_evdev_methods);
+       evdev_set_methods(sc->evdev, sc, &ietp_evdev_methods);
        evdev_set_flag(sc->evdev, EVDEV_FLAG_MT_STCOMPAT);
        evdev_set_flag(sc->evdev, EVDEV_FLAG_EXT_EPOCH); /* hidbus child */
 
@@ -584,11 +597,13 @@ ietp_iic_set_absolute_mode(device_t dev, bool enable)
         * Some ASUS touchpads need to be powered on to enter absolute mode.
         */
        require_wakeup = false;
-       for (i = 0; i < nitems(special_fw); i++) {
-               if (sc->ic_type == special_fw[i].ic_type &&
-                   sc->product_id == special_fw[i].product_id) {
-                       require_wakeup = true;
-                       break;
+       if (!sc->open) {
+               for (i = 0; i < nitems(special_fw); i++) {
+                       if (sc->ic_type == special_fw[i].ic_type &&
+                           sc->product_id == special_fw[i].product_id) {
+                               require_wakeup = true;
+                               break;
+                       }
                }
        }
 
diff --git a/sys/dev/iicbus/iichid.c b/sys/dev/iicbus/iichid.c
index 3f1d7a0cefba..fdb4816b8bd9 100644
--- a/sys/dev/iicbus/iichid.c
+++ b/sys/dev/iicbus/iichid.c
@@ -861,7 +861,8 @@ iichid_intr_start(device_t dev, device_t child __unused)
 
        sc = device_get_softc(dev);
        DPRINTF(sc, "iichid device open\n");
-       iichid_set_power_state(sc, IICHID_PS_ON, IICHID_PS_NULL);
+       if (!sc->open)
+               iichid_set_power_state(sc, IICHID_PS_ON, IICHID_PS_NULL);
 
        return (0);
 }

Reply via email to