Make sure state changes are properly serialized.
authormpi <mpi@openbsd.org>
Tue, 19 Aug 2014 12:24:04 +0000 (12:24 +0000)
committermpi <mpi@openbsd.org>
Tue, 19 Aug 2014 12:24:04 +0000 (12:24 +0000)
When pms(4) is attached to a touchpad it generally presents two different
wsmouse(4) devices: one for the touchpad itself and one for the clitpad
and/or some interleaved packets.  But since both devices are writing to
the same pckbc slot, a race can occur if they try to change the state at
the same time.

So prevent two process opening the two /dev/wsmouse* node at the same time
to corrupt the magic sequences needed to enable/disable the touchpad.

ok schadchin@

sys/dev/pckbc/pms.c

index 77904ae..c0df81b 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: pms.c,v 1.52 2014/07/12 18:48:52 tedu Exp $ */
+/* $OpenBSD: pms.c,v 1.53 2014/08/19 12:24:04 mpi Exp $ */
 /* $NetBSD: psm.c,v 1.11 2000/06/05 22:20:57 sommerfeld Exp $ */
 
 /*-
@@ -26,6 +26,7 @@
 
 #include <sys/param.h>
 #include <sys/systm.h>
+#include <sys/rwlock.h>
 #include <sys/device.h>
 #include <sys/ioctl.h>
 #include <sys/malloc.h>
@@ -148,6 +149,8 @@ struct pms_softc {          /* driver status information */
 #define PMS_STATE_ENABLED      1
 #define PMS_STATE_SUSPENDED    2
 
+       struct rwlock sc_state_lock;
+
        int sc_dev_enable;
 #define PMS_DEV_IGNORE         0x00
 #define PMS_DEV_PRIMARY                0x01
@@ -662,6 +665,8 @@ pmsattach(struct device *parent, struct device *self, void *aux)
        a.accessops = &pms_accessops;
        a.accesscookie = sc;
 
+       rw_init(&sc->sc_state_lock, "pmsst");
+
        /*
         * Attach the wsmouse, saving a handle to it.
         * Note that we don't need to check this pointer against NULL
@@ -762,8 +767,13 @@ int
 pms_enable(void *v)
 {
        struct pms_softc *sc = v;
+       int rv;
 
-       return pms_change_state(sc, PMS_STATE_ENABLED, PMS_DEV_PRIMARY);
+       rw_enter_write(&sc->sc_state_lock);
+       rv = pms_change_state(sc, PMS_STATE_ENABLED, PMS_DEV_PRIMARY);
+       rw_exit_write(&sc->sc_state_lock);
+
+       return (rv);
 }
 
 void
@@ -771,7 +781,9 @@ pms_disable(void *v)
 {
        struct pms_softc *sc = v;
 
+       rw_enter_write(&sc->sc_state_lock);
        pms_change_state(sc, PMS_STATE_DISABLED, PMS_DEV_PRIMARY);
+       rw_exit_write(&sc->sc_state_lock);
 }
 
 int
@@ -789,8 +801,13 @@ int
 pms_sec_enable(void *v)
 {
        struct pms_softc *sc = v;
+       int rv;
+
+       rw_enter_write(&sc->sc_state_lock);
+       rv = pms_change_state(sc, PMS_STATE_ENABLED, PMS_DEV_SECONDARY);
+       rw_exit_write(&sc->sc_state_lock);
 
-       return (pms_change_state(sc, PMS_STATE_ENABLED, PMS_DEV_SECONDARY));
+       return (rv);
 }
 
 void
@@ -798,7 +815,9 @@ pms_sec_disable(void *v)
 {
        struct pms_softc *sc = v;
 
+       rw_enter_write(&sc->sc_state_lock);
        pms_change_state(sc, PMS_STATE_DISABLED, PMS_DEV_SECONDARY);
+       rw_exit_write(&sc->sc_state_lock);
 }
 
 int