git: df6ae0577d2c - main - hid: Allow serial execution of HID_INTR_START method.

From: Vladimir Kondratyev <wulf_at_FreeBSD.org>
Date: Sun, 17 Aug 2025 21:02:27 UTC
The branch main has been updated by wulf:

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

commit df6ae0577d2c966ac0db9983ae353c24b53067eb
Author:     Vladimir Kondratyev <wulf@FreeBSD.org>
AuthorDate: 2025-08-17 21:00:44 +0000
Commit:     Vladimir Kondratyev <wulf@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);
 }