Re: pms: reset announcement

2017-10-29 Thread Ulf Brosziewski
Looks fine to me.  I made some tests on a T420, with explicitly
triggered resets, and the detection and the "reset task" worked
as expected.  There are noticeable delays, but I don't think
optimizing would be worth the effort (if it happens too often,
you may want to repair or exchange your touchpad).

Maybe we can generalize that later.  Very rarely, I observe a
similar phenomenon with my Elantech-v4 touchpad (two not-in-sync
messages, then data reporting stops, which is to be expected
after a PS/2 reset).

But here is a little puzzle:  There are no constant bits in
byte 2 and 3 and byte 5 and 6 of Absolute Mode packets, so
theoretically [0xaa, 0x00] may be a valid part of a packet,
starting at byte 2 or byte 5 (there is no overlap on other
positions).  Is there a simple and sound way to exclude false
positive errors?  Or can we simply ignore it because it's
improbable enough or impossible?  (If not, a change of the
logic could be necessary: don't interrupt the normal processing
when the sequence is detected, and check the state of the
device in pms_reset_task).

On 10/29/2017 09:35 AM, Anton Lindqvist wrote:
> Hi,
> Every now and then, my Synaptics touchpad stops working and no further
> interrupts are received for the device. The following message appears in
> the log:
> 
>   pms0: not in sync yet, discard input (state = 0)
> 
> Examining the bytes received prior to the halt reveals the sequence
> [0xaa, 0x00] which denotes a Synaptics reset announcement[1]. This
> sequence is sent after the touchpad experienced a loss of power and the
> device is reset. Since any altered setting prior to the reset is lost
> the device must be re-enabled in order to continue functioning. The
> simplest(?) way is to disable and then enable the device (many thanks to
> bru@ for helping out with this part).
> 
> Testing this diff on hardware equipped with a Synaptics touchpad would be much
> appreciated. Even if you never experienced a reset in order make sure no
> regression is introduced.
> 
> In addition, I'm looking for feedback and OKs.
> 
> [1] 
> https://www.aquaphoenix.com/hardware/ledlamp/reference/synaptics_touchpad_interfacing_guide.pdf#page=32
> 
> Index: pms.c
> ===
> RCS file: /cvs/src/sys/dev/pckbc/pms.c,v
> retrieving revision 1.81
> diff -u -p -r1.81 pms.c
> --- pms.c 28 Oct 2017 14:31:29 -  1.81
> +++ pms.c 28 Oct 2017 16:55:22 -
> @@ -30,6 +30,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  
>  #include 
>  
> @@ -88,6 +89,8 @@ struct synaptics_softc {
>  
>   int mode;
>  
> + int annstate;   /* announcement state */
> +
>   int mask;
>  #define SYNAPTICS_MASK_NEWABS_STRICT 0xc8
>  #define SYNAPTICS_MASK_NEWABS_RELAXED0xc0
> @@ -158,6 +161,8 @@ struct pms_softc {/* driver status inf
>  #define PMS_DEV_PRIMARY  0x01
>  #define PMS_DEV_SECONDARY0x02
>  
> + struct task sc_reset_task;
> +
>   int poll;
>   int inputstate;
>  
> @@ -255,6 +260,7 @@ int   pms_reset(struct pms_softc *);
>  int  pms_dev_enable(struct pms_softc *);
>  int  pms_dev_disable(struct pms_softc *);
>  void pms_protocol_lookup(struct pms_softc *);
> +void pms_reset_task(void *);
>  
>  int  pms_enable_intelli(struct pms_softc *);
>  
> @@ -293,6 +299,7 @@ int   synaptics_set_mode(struct pms_softc 
>  int  synaptics_query(struct pms_softc *, int, int *);
>  int  synaptics_get_hwinfo(struct pms_softc *);
>  void synaptics_sec_proc(struct pms_softc *);
> +int  synaptics_is_reset(struct pms_softc *, int);
>  
>  int  alps_sec_proc(struct pms_softc *);
>  int  alps_get_hwinfo(struct pms_softc *);
> @@ -542,6 +549,32 @@ pms_protocol_lookup(struct pms_softc *sc
>   DPRINTF("%s: protocol type %d\n", DEVNAME(sc), sc->protocol->type);
>  }
>  
> +void
> +pms_reset_task(void *v)
> +{
> + struct pms_softc *sc = v;
> +
> + rw_enter_write(>sc_state_lock);
> +
> + /* Do nothing if the device already is disabled. */
> + if (sc->sc_state == PMS_STATE_DISABLED)
> + goto done;
> +
> +#ifdef DIAGNOSTIC
> + printf("%s: device reset\n", DEVNAME(sc));
> +#endif
> + if (sc->sc_sec_wsmousedev != NULL)
> + pms_change_state(sc, PMS_STATE_DISABLED, PMS_DEV_SECONDARY);
> + pms_change_state(sc, PMS_STATE_DISABLED, PMS_DEV_PRIMARY);
> +
> + pms_change_state(sc, PMS_STATE_ENABLED, PMS_DEV_PRIMARY);
> + if (sc->sc_sec_wsmousedev != NULL)
> + pms_change_state(sc, PMS_STATE_ENABLED, PMS_DEV_SECONDARY);
> +
> +done:
> + rw_exit_write(>sc_state_lock);
> +}
> +
>  int
>  pms_enable_intelli(struct pms_softc *sc)
>  {
> @@ -679,6 +712,8 @@ pmsattach(struct device *parent, struct 
>*/
>   sc->sc_wsmousedev = config_found(self, , wsmousedevprint);
>  
> + task_set(>sc_reset_task, pms_reset_task, sc);
> +
>   sc->poll = 1;
>   sc->sc_dev_enable = 0;
>  
> @@ -850,9 +885,11 @@ pmsinput(void *vsc, int data)
>   

pms: reset announcement

2017-10-29 Thread Anton Lindqvist
Hi,
Every now and then, my Synaptics touchpad stops working and no further
interrupts are received for the device. The following message appears in
the log:

  pms0: not in sync yet, discard input (state = 0)

Examining the bytes received prior to the halt reveals the sequence
[0xaa, 0x00] which denotes a Synaptics reset announcement[1]. This
sequence is sent after the touchpad experienced a loss of power and the
device is reset. Since any altered setting prior to the reset is lost
the device must be re-enabled in order to continue functioning. The
simplest(?) way is to disable and then enable the device (many thanks to
bru@ for helping out with this part).

Testing this diff on hardware equipped with a Synaptics touchpad would be much
appreciated. Even if you never experienced a reset in order make sure no
regression is introduced.

In addition, I'm looking for feedback and OKs.

[1] 
https://www.aquaphoenix.com/hardware/ledlamp/reference/synaptics_touchpad_interfacing_guide.pdf#page=32

Index: pms.c
===
RCS file: /cvs/src/sys/dev/pckbc/pms.c,v
retrieving revision 1.81
diff -u -p -r1.81 pms.c
--- pms.c   28 Oct 2017 14:31:29 -  1.81
+++ pms.c   28 Oct 2017 16:55:22 -
@@ -30,6 +30,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 
@@ -88,6 +89,8 @@ struct synaptics_softc {
 
int mode;
 
+   int annstate;   /* announcement state */
+
int mask;
 #define SYNAPTICS_MASK_NEWABS_STRICT   0xc8
 #define SYNAPTICS_MASK_NEWABS_RELAXED  0xc0
@@ -158,6 +161,8 @@ struct pms_softc {  /* driver status inf
 #define PMS_DEV_PRIMARY0x01
 #define PMS_DEV_SECONDARY  0x02
 
+   struct task sc_reset_task;
+
int poll;
int inputstate;
 
@@ -255,6 +260,7 @@ int pms_reset(struct pms_softc *);
 intpms_dev_enable(struct pms_softc *);
 intpms_dev_disable(struct pms_softc *);
 void   pms_protocol_lookup(struct pms_softc *);
+void   pms_reset_task(void *);
 
 intpms_enable_intelli(struct pms_softc *);
 
@@ -293,6 +299,7 @@ int synaptics_set_mode(struct pms_softc 
 intsynaptics_query(struct pms_softc *, int, int *);
 intsynaptics_get_hwinfo(struct pms_softc *);
 void   synaptics_sec_proc(struct pms_softc *);
+intsynaptics_is_reset(struct pms_softc *, int);
 
 intalps_sec_proc(struct pms_softc *);
 intalps_get_hwinfo(struct pms_softc *);
@@ -542,6 +549,32 @@ pms_protocol_lookup(struct pms_softc *sc
DPRINTF("%s: protocol type %d\n", DEVNAME(sc), sc->protocol->type);
 }
 
+void
+pms_reset_task(void *v)
+{
+   struct pms_softc *sc = v;
+
+   rw_enter_write(>sc_state_lock);
+
+   /* Do nothing if the device already is disabled. */
+   if (sc->sc_state == PMS_STATE_DISABLED)
+   goto done;
+
+#ifdef DIAGNOSTIC
+   printf("%s: device reset\n", DEVNAME(sc));
+#endif
+   if (sc->sc_sec_wsmousedev != NULL)
+   pms_change_state(sc, PMS_STATE_DISABLED, PMS_DEV_SECONDARY);
+   pms_change_state(sc, PMS_STATE_DISABLED, PMS_DEV_PRIMARY);
+
+   pms_change_state(sc, PMS_STATE_ENABLED, PMS_DEV_PRIMARY);
+   if (sc->sc_sec_wsmousedev != NULL)
+   pms_change_state(sc, PMS_STATE_ENABLED, PMS_DEV_SECONDARY);
+
+done:
+   rw_exit_write(>sc_state_lock);
+}
+
 int
 pms_enable_intelli(struct pms_softc *sc)
 {
@@ -679,6 +712,8 @@ pmsattach(struct device *parent, struct 
 */
sc->sc_wsmousedev = config_found(self, , wsmousedevprint);
 
+   task_set(>sc_reset_task, pms_reset_task, sc);
+
sc->poll = 1;
sc->sc_dev_enable = 0;
 
@@ -850,9 +885,11 @@ pmsinput(void *vsc, int data)
sc->packet[sc->inputstate] = data;
if (sc->protocol->sync(sc, data)) {
 #ifdef DIAGNOSTIC
-   printf("%s: not in sync yet, discard input (state %d)\n",
-   DEVNAME(sc), sc->inputstate);
+   printf("%s: not in sync yet, discard input "
+   "(state = %d, data = %#x)\n",
+   DEVNAME(sc), sc->inputstate, data);
 #endif
+
sc->inputstate = 0;
return;
}
@@ -1021,6 +1058,35 @@ synaptics_knock(struct pms_softc *sc)
return (0);
 }
 
+/*
+ * Recognize reset announcement ([0xaa, 0x0]).
+ * The sequence will be sent as input on rare occasions when the touchpad was
+ * reset due to a power failure.
+ */
+int
+synaptics_is_reset(struct pms_softc *sc, int data)
+{
+   struct synaptics_softc *syn = sc->synaptics;
+
+   switch (syn->annstate) {
+   case 0:
+   if (data == PMS_RSTDONE) {
+   syn->annstate++;
+   return (0);
+   }
+   break;
+   case 1:
+   if (data == 0) {
+   syn->annstate = 0;
+   return (1);
+   }
+   break;
+   }
+   syn->annstate = 0;
+
+   return (0);
+}
+
 int