svn commit: r328636 - in head/sys: dev/atkbdc sys

Vladimir Kondratyev wulf at FreeBSD.org
Wed Jan 31 21:15:00 UTC 2018


Author: wulf
Date: Wed Jan 31 21:14:59 2018
New Revision: 328636
URL: https://svnweb.freebsd.org/changeset/base/328636

Log:
  psm(4): Add support for HP EliteBook 1040 ForcePads.
  
  ForcePads do not have any physical buttons, instead they detect click
  based on finger pressure. Forcepads erroneously report button click
  if there are 2 or more fingers on the touchpad breaking multifinger
  gestures. To workaround this start reporting a click only after
  4 consecutive single touch packets has been received. Skip these packets
  in case more contacts appear.
  
  PR:		223369
  Reported by:	Neel Chauhan <neel at neelc.org>
  Tested by:	Neel Chauhan <neel at neelc.org>
  Reviewed by:	gonzo
  Approved by:	gonzo

Modified:
  head/sys/dev/atkbdc/psm.c
  head/sys/sys/mouse.h

Modified: head/sys/dev/atkbdc/psm.c
==============================================================================
--- head/sys/dev/atkbdc/psm.c	Wed Jan 31 18:13:33 2018	(r328635)
+++ head/sys/dev/atkbdc/psm.c	Wed Jan 31 21:14:59 2018	(r328636)
@@ -132,6 +132,13 @@ __FBSDID("$FreeBSD$");
 
 #define	PSMCPNP_DRIVER_NAME	"psmcpnp"
 
+struct psmcpnp_softc {
+	enum {
+		PSMCPNP_GENERIC,
+		PSMCPNP_FORCEPAD,
+	} type;		/* Based on PnP ID */
+};
+
 /* input queue */
 #define	PSM_BUFSIZE		960
 #define	PSM_SMALLBUFSIZE	240
@@ -416,6 +423,7 @@ struct psm_softc {		/* Driver status information */
 	int		squelch; /* level to filter movement at low speed */
 	int		syncerrors; /* # of bytes discarded to synchronize */
 	int		pkterrors;  /* # of packets failed during quaranteen. */
+	int		fpcount;	/* forcePad valid packet counter */
 	struct timeval	inputtimeout;
 	struct timeval	lastsoftintr;	/* time of last soft interrupt */
 	struct timeval	lastinputerr;	/* time last sync error happened */
@@ -3183,7 +3191,7 @@ proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, 
 	static int touchpad_buttons;
 	static int guest_buttons;
 	static finger_t f[PSM_FINGERS];
-	int w, id, nfingers, ewcode, extended_buttons;
+	int w, id, nfingers, ewcode, extended_buttons, clickpad_pressed;
 
 	extended_buttons = 0;
 
@@ -3445,10 +3453,6 @@ proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, 
 			extended_buttons |= sc->extended_buttons;
 		}
 	}
-	/* Handle ClickPad */
-	if (sc->synhw.capClickPad &&
-	    ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x01))
-		touchpad_buttons |= MOUSE_BUTTON1DOWN;
 
 	if (sc->synhw.capReportsV && nfingers > 1)
 		f[0] = (finger_t) {
@@ -3481,6 +3485,36 @@ proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, 
 	if (f[0].p < sc->syninfo.min_pressure || f[0].x < 2)
 		nfingers = 0;
 
+	/* Handle ClickPad */
+	if (sc->synhw.capClickPad) {
+		clickpad_pressed = (pb->ipacket[0] ^ pb->ipacket[3]) & 0x01;
+		if (sc->synhw.forcePad) {
+			/*
+			 * Forcepads erroneously report button click if there
+			 * are 2 or more fingers on the touchpad breaking
+			 * multifinger gestures. To workaround this start
+			 * reporting a click only after 4 consecutive single
+			 * touch packets has been received.
+			 * Skip these packets in case more contacts appear.
+			 */
+			switch (nfingers) {
+			case 0:
+				sc->fpcount = 0;
+				break;
+			case 1:
+				if (clickpad_pressed && sc->fpcount < INT_MAX)
+					++sc->fpcount;
+				/* FALLTHROUGH */
+			default:
+				if (!clickpad_pressed)
+					sc->fpcount = 0;
+				if (sc->fpcount >= sc->syninfo.window_min)
+					touchpad_buttons |= MOUSE_BUTTON1DOWN;
+			}
+		} else if (clickpad_pressed)
+			touchpad_buttons |= MOUSE_BUTTON1DOWN;
+	}
+
 	for (id = 0; id < PSM_FINGERS; id++)
 		if (id >= nfingers)
 			PSM_FINGER_RESET(f[id]);
@@ -5998,6 +6032,8 @@ synaptics_set_mode(struct psm_softc *sc, int mode_byte
 static int
 enable_synaptics(struct psm_softc *sc, enum probearg arg)
 {
+	device_t psmcpnp;
+	struct psmcpnp_softc *psmcpnp_sc;
 	KBDC kbdc = sc->kbdc;
 	synapticshw_t synhw;
 	int status[3];
@@ -6075,6 +6111,10 @@ enable_synaptics(struct psm_softc *sc, enum probearg a
 		return (FALSE);
 	}
 
+	psmcpnp = devclass_get_device(devclass_find(PSMCPNP_DRIVER_NAME),
+	    sc->unit);
+	psmcpnp_sc = (psmcpnp != NULL) ? device_get_softc(psmcpnp) : NULL;
+
 	/* Set the different capabilities when they exist. */
 	buttons = 0;
 	synhw.capExtended = (status[0] & 0x80) != 0;
@@ -6229,6 +6269,20 @@ enable_synaptics(struct psm_softc *sc, enum probearg a
 				synhw.minimumYCoord = 1408;
 			}
 
+			/*
+			 * ClickPad properties are not exported through PS/2
+			 * protocol. Detection is based on controller's PnP ID.
+			 */
+			if (synhw.capClickPad && psmcpnp_sc != NULL) {
+				switch (psmcpnp_sc->type) {
+				case PSMCPNP_FORCEPAD:
+					synhw.forcePad = 1;
+					break;
+				default:
+					break;
+				}
+			}
+
 			if (verbose >= 2) {
 				printf("  Continued capabilities:\n");
 				printf("   capClickPad: %d\n",
@@ -6265,6 +6319,10 @@ enable_synaptics(struct psm_softc *sc, enum probearg a
 					printf("   minimumYCoord: %d\n",
 					       synhw.minimumYCoord);
 				}
+				if (synhw.capClickPad) {
+					printf("   forcePad: %d\n",
+					       synhw.forcePad);
+				}
 			}
 			buttons += synhw.capClickPad;
 		}
@@ -7090,7 +7148,7 @@ static device_method_t psmcpnp_methods[] = {
 static driver_t psmcpnp_driver = {
 	PSMCPNP_DRIVER_NAME,
 	psmcpnp_methods,
-	1,			/* no softc */
+	sizeof(struct psmcpnp_softc),
 };
 
 static struct isa_pnp_id psmcpnp_ids[] = {
@@ -7110,6 +7168,13 @@ static struct isa_pnp_id psmcpnp_ids[] = {
 	{ 0 }
 };
 
+/* _HID list for quirk detection. Any device below has _CID from psmcpnp_ids */
+static struct isa_pnp_id forcepad_ids[] = {
+	{ 0x0d302e4f, "HP PS/2 forcepad port" },	/* SYN300D, EB 1040 */
+	{ 0x14302e4f, "HP PS/2 forcepad port" },	/* SYN3014, EB 1040 */
+	{ 0 }
+};
+
 static int
 create_a_copy(device_t atkbdc, device_t me)
 {
@@ -7136,11 +7201,16 @@ create_a_copy(device_t atkbdc, device_t me)
 static int
 psmcpnp_probe(device_t dev)
 {
+	struct psmcpnp_softc *sc = device_get_softc(dev);
 	struct resource *res;
 	u_long irq;
 	int rid;
 
-	if (ISA_PNP_PROBE(device_get_parent(dev), dev, psmcpnp_ids))
+	if (ISA_PNP_PROBE(device_get_parent(dev), dev, forcepad_ids) == 0)
+		sc->type = PSMCPNP_FORCEPAD;
+	else if (ISA_PNP_PROBE(device_get_parent(dev), dev, psmcpnp_ids) == 0)
+		sc->type = PSMCPNP_GENERIC;
+	else
 		return (ENXIO);
 
 	/*

Modified: head/sys/sys/mouse.h
==============================================================================
--- head/sys/sys/mouse.h	Wed Jan 31 18:13:33 2018	(r328635)
+++ head/sys/sys/mouse.h	Wed Jan 31 21:14:59 2018	(r328636)
@@ -137,6 +137,7 @@ typedef struct synapticshw {
 	int maximumYCoord;
 	int infoXupmm;
 	int infoYupmm;
+	int forcePad;
 } synapticshw_t;
 
 /* iftype */


More information about the svn-src-head mailing list