Support for ALPS touchpads

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Support for ALPS touchpads

Martin Pieuchot-2
The diff below adds support for ALPS touchpads to the pms(4) driver.

I'm looking for testers with or without ALPS hardware, especially if you
have a touchpad, to be sure it doesn't break anything.

Currently, ALPS DualPoint are untested and support for special buttons
(back, forward, etc) is missing because I don't have such hardware.

I use the following synaptics(4) configuration for edge scrolling and
simple left tapping:

xinput set-prop /dev/wsmouse0 "Synaptics Finger" 25 30 60
xinput set-int-prop /dev/wsmouse0 "Synaptics Tap Action" 8 0 0 2 3 1 0 0
xinput set-int-prop /dev/wsmouse0 "Synaptics Click Action" 8 1 0 0
xinput set-int-prop /dev/wsmouse0 "Synaptics Edge Scrolling" 8 1 0 0


Compared to the previous version, I left the Y-axis translation because
it's also needed for the COMPAT mode.

Comments?

Martin


Index: pms.c
===================================================================
RCS file: /cvs/src/sys/dev/pckbc/pms.c,v
retrieving revision 1.21
diff -u -p -r1.21 pms.c
--- pms.c 24 Aug 2011 15:34:25 -0000 1.21
+++ pms.c 4 Sep 2011 18:11:32 -0000
@@ -39,6 +39,14 @@
 #include <dev/wscons/wsconsio.h>
 #include <dev/wscons/wsmousevar.h>
 
+#define DEBUG
+
+#ifdef DEBUG
+#define DPRINTF(x...) do { printf(x); } while (0);
+#else
+#define DPRINTF(x...)
+#endif
+
 #define DEVNAME(sc) ((sc)->sc_dev.dv_xname)
 
 #define WSMOUSE_BUTTON(x) (1 << ((x) - 1))
@@ -50,6 +58,7 @@ struct pms_protocol {
 #define PMS_STANDARD 0
 #define PMS_INTELLI 1
 #define PMS_SYNAPTICS 2
+#define PMS_ALPS 3
  u_int packetsize;
  int (*enable)(struct pms_softc *);
  int (*ioctl)(struct pms_softc *, u_long, caddr_t, int, struct proc *);
@@ -78,6 +87,22 @@ struct synaptics_softc {
 #define SYNAPTICS_PRESSURE 30
 };
 
+struct alps_softc {
+ int model;
+#define ALPS_PASSTHROUGH (1 << 1)
+
+
+ int min_x, min_y;
+ int max_x, max_y;
+ int old_fin;
+
+ /* Compat mode */
+ int wsmode;
+ int old_x, old_y;
+ u_int old_buttons;
+#define ALPS_PRESSURE 40
+};
+
 struct pms_softc { /* driver status information */
  struct device sc_dev;
 
@@ -98,6 +123,7 @@ struct pms_softc { /* driver status inf
 
  const struct pms_protocol *protocol;
  struct synaptics_softc *synaptics;
+ struct alps_softc *alps;
 
  u_char packet[8];
 
@@ -116,6 +142,19 @@ static const u_int butmap[8] = {
  WSMOUSE_BUTTON(1) | WSMOUSE_BUTTON(2) | WSMOUSE_BUTTON(3)
 };
 
+static const struct alps_quirk {
+ int version;
+ int model;
+} alps_quirks[] = {
+ { 0x2021, ALPS_PASSTHROUGH },
+ { 0x2221, ALPS_PASSTHROUGH },
+ { 0x2222, ALPS_PASSTHROUGH },
+ { 0x3222, ALPS_PASSTHROUGH },
+ { 0x5212, ALPS_PASSTHROUGH },
+ { 0x6222, ALPS_PASSTHROUGH },
+ { 0x633b, ALPS_PASSTHROUGH },
+};
+
 int pmsprobe(struct device *, void *, void *);
 void pmsattach(struct device *, struct device *, void *);
 int pmsactivate(struct device *, int);
@@ -150,6 +189,11 @@ int pms_sync_synaptics(struct pms_softc
 void pms_proc_synaptics(struct pms_softc *);
 void pms_disable_synaptics(struct pms_softc *);
 
+int pms_enable_alps(struct pms_softc *);
+int pms_ioctl_alps(struct pms_softc *, u_long, caddr_t, int, struct proc *);
+int pms_sync_alps(struct pms_softc *, int);
+void pms_proc_alps(struct pms_softc *);
+
 int synaptics_set_mode(struct pms_softc *, int);
 int synaptics_query(struct pms_softc *, int, int *);
 int synaptics_get_hwinfo(struct pms_softc *);
@@ -160,6 +204,8 @@ int synaptics_pt_ioctl(void *, u_long, c
 int synaptics_pt_enable(void *);
 void synaptics_pt_disable(void *);
 
+int alps_get_hwinfo(struct pms_softc *);
+
 struct cfattach pms_ca = {
  sizeof(struct pms_softc), pmsprobe, pmsattach, NULL,
  pmsactivate
@@ -208,7 +254,16 @@ const struct pms_protocol pms_protocols[
  pms_sync_synaptics,
  pms_proc_synaptics,
  pms_disable_synaptics
- }
+ },
+ /* ALPS touchpad */
+ {
+ PMS_ALPS, 6,
+ pms_enable_alps,
+ pms_ioctl_alps,
+ pms_sync_alps,
+ pms_proc_alps,
+ NULL
+ },
 };
 
 int
@@ -965,4 +1020,226 @@ pms_disable_synaptics(struct pms_softc *
  if (syn->capabilities & SYNAPTICS_CAP_SLEEP)
  synaptics_set_mode(sc, SYNAPTICS_SLEEP_MODE |
     SYNAPTICS_DISABLE_GESTURE);
+}
+
+int
+alps_get_hwinfo(struct pms_softc *sc)
+{
+ struct alps_softc *alps = sc->alps;
+ u_char resp[3];
+ int version, i;
+
+ if (pms_set_resolution(sc, 0) ||
+    pms_set_scaling(sc, 2) ||
+    pms_set_scaling(sc, 2) ||
+    pms_set_scaling(sc, 2) ||
+    pms_get_status(sc, resp)) {
+ DPRINTF("%s: alps: model query error\n", DEVNAME(sc));
+ return (-1);
+ }
+
+ version = (resp[0] << 8) | (resp[1] << 4) | (resp[2] / 20 + 1);
+
+ printf("%s: ALPS touchpad, version 0x%04x\n", DEVNAME(sc), version);
+
+ for (i = 0; i < nitems(alps_quirks); i++)
+ if (version == alps_quirks[i].version) {
+ alps->model = alps_quirks[i].model;
+ break;
+ }
+
+ return (0);
+}
+
+int
+pms_enable_alps(struct pms_softc *sc)
+{
+ struct alps_softc *alps = sc->alps;
+ u_char resp[3];
+
+ if (pms_set_resolution(sc, 0) ||
+    pms_set_scaling(sc, 1) ||
+    pms_set_scaling(sc, 1) ||
+    pms_set_scaling(sc, 1) ||
+    pms_get_status(sc, resp) ||
+    resp[0] != PMS_ALPS_MAGIC1 ||
+    resp[1] != PMS_ALPS_MAGIC2 ||
+    (resp[2] != PMS_ALPS_MAGIC3_1 && resp[2] != PMS_ALPS_MAGIC3_2))
+ return (0);
+
+ if (sc->alps == NULL) {
+ sc->alps = alps = malloc(sizeof(struct alps_softc),
+    M_DEVBUF, M_WAITOK | M_ZERO);
+ if (alps == NULL) {
+ printf("%s: alps: not enough memory\n", DEVNAME(sc));
+ return (0);
+ }
+
+ if (alps_get_hwinfo(sc))
+ return (0);
+
+ alps->min_x = ALPS_XMIN_BEZEL;
+ alps->min_y = ALPS_YMIN_BEZEL;
+ alps->max_x = ALPS_XMAX_BEZEL;
+ alps->max_y = ALPS_YMAX_BEZEL;
+
+ alps->wsmode = WSMOUSE_COMPAT;
+ }
+
+ if ((alps->model & ALPS_PASSTHROUGH) &&
+   (pms_set_scaling(sc, 2) ||
+    pms_set_scaling(sc, 2) ||
+    pms_set_scaling(sc, 2) ||
+    pms_dev_disable(sc))) {
+ DPRINTF("%s: alps: passthrough on error\n", DEVNAME(sc));
+ return (0);
+ }
+
+ if (pms_dev_disable(sc) ||
+    pms_dev_disable(sc) ||
+    pms_set_rate(sc, 0x0a)) {
+ DPRINTF("%s: alps: tapping error\n", DEVNAME(sc));
+ return (0);
+ }
+
+ if (pms_dev_disable(sc) ||
+    pms_dev_disable(sc) ||
+    pms_dev_disable(sc) ||
+    pms_dev_disable(sc) ||
+    pms_dev_enable(sc)) {
+ DPRINTF("%s: alps: absolute mode error\n", DEVNAME(sc));
+ return (0);
+ }
+
+ if ((alps->model & ALPS_PASSTHROUGH) &&
+   (pms_set_scaling(sc, 1) ||
+    pms_set_scaling(sc, 1) ||
+    pms_set_scaling(sc, 1) ||
+    pms_dev_disable(sc))) {
+ DPRINTF("%s: alps: passthrough off error\n", DEVNAME(sc));
+ return (0);
+ }
+
+ return (1);
+}
+
+int
+pms_ioctl_alps(struct pms_softc *sc, u_long cmd, caddr_t data, int flag,
+    struct proc *p)
+{
+ struct alps_softc *alps = sc->alps;
+ struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data;
+ int wsmode;
+
+ switch (cmd) {
+ case WSMOUSEIO_GTYPE:
+ *(u_int *)data = WSMOUSE_TYPE_SYNAPTICS;
+ break;
+ case WSMOUSEIO_GCALIBCOORDS:
+ wsmc->minx = alps->min_x;
+ wsmc->maxx = alps->max_x;
+ wsmc->miny = alps->min_y;
+ wsmc->maxy = alps->max_y;
+ wsmc->swapxy = 0;
+ break;
+ case WSMOUSEIO_SETMODE:
+ wsmode = *(u_int *)data;
+ if (wsmode != WSMOUSE_COMPAT && wsmode != WSMOUSE_NATIVE)
+ return (EINVAL);
+ alps->wsmode = wsmode;
+ break;
+ default:
+ return (-1);
+ }
+ return (0);
+}
+
+int
+pms_sync_alps(struct pms_softc *sc, int data)
+{
+ switch (sc->inputstate) {
+ case 0:
+ if ((data & 0xf8) != 0xf8) /* XXX model dependant? */
+ return (-1);
+ break;
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ if ((data & 0x80) != 0)
+ return (-1);
+ break;
+ }
+
+ return (0);
+}
+
+void
+pms_proc_alps(struct pms_softc *sc)
+{
+ struct alps_softc *alps = sc->alps;
+ int x, y, z, dx, dy;
+ u_int buttons;
+ int fin, ges;
+
+ x = sc->packet[1] | ((sc->packet[2] & 0x78) << 4);
+ y = sc->packet[4] | ((sc->packet[3] & 0x70) << 3);
+ z = sc->packet[5];
+
+ /*
+ * XXX The Y-axis is in the oposit direction compared to
+ * Synaptics touchpads and PS/2 mouses.
+ * It's why we need to translate the y value here for both
+ * NATIVE and COMPAT modes.
+ */
+ y = ALPS_YMAX_BEZEL - y + ALPS_YMIN_BEZEL;
+
+ buttons = ((sc->packet[3] & 1) ? WSMOUSE_BUTTON(1) : 0) |
+    ((sc->packet[3] & 2) ? WSMOUSE_BUTTON(3) : 0) |
+    ((sc->packet[3] & 4) ? WSMOUSE_BUTTON(2) : 0);
+
+ if (alps->wsmode == WSMOUSE_NATIVE) {
+ if (z == 127) {
+ /* DualPoint touchpads are not absolute. */
+ wsmouse_input(sc->sc_wsmousedev, buttons, x, y, 0, 0,
+    WSMOUSE_INPUT_DELTA);
+ return;
+ }
+
+ ges = sc->packet[2] & 0x01;
+ fin = sc->packet[2] & 0x02;
+
+ /* Simulate click (tap) */
+ if (ges && !fin)
+ z = 35;
+
+ /* Generate a null pressure event (needed for tap & drag) */
+ if (ges && fin && !alps->old_fin)
+ z = 0;
+
+ wsmouse_input(sc->sc_wsmousedev, buttons, x, y, z, 0,
+    WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y |
+    WSMOUSE_INPUT_ABSOLUTE_Z);
+
+ alps->old_fin = fin;
+ } else {
+ dx = dy = 0;
+ if (z > ALPS_PRESSURE) {
+ dx = x - alps->old_x;
+ dy = y - alps->old_y;
+
+ /* Prevent jump */
+ dx = abs(dx) > 50 ? 0 : dx;
+ dy = abs(dy) > 50 ? 0 : dy;
+ }
+
+ if (dx || dy || buttons != alps->old_buttons)
+ wsmouse_input(sc->sc_wsmousedev, buttons, dx, dy, 0, 0,
+    WSMOUSE_INPUT_DELTA);
+
+ alps->old_x = x;
+ alps->old_y = y;
+ alps->old_buttons = buttons;
+ }
 }
Index: pmsreg.h
===================================================================
RCS file: /cvs/src/sys/dev/pckbc/pmsreg.h,v
retrieving revision 1.4
diff -u -p -r1.4 pmsreg.h
--- pmsreg.h 24 Aug 2011 15:34:25 -0000 1.4
+++ pmsreg.h 4 Sep 2011 17:38:48 -0000
@@ -37,6 +37,11 @@
 #define PMS_INTELLI_MAGIC3 80
 #define PMS_INTELLI_ID 0x03
 
+#define PMS_ALPS_MAGIC1 0
+#define PMS_ALPS_MAGIC2 0
+#define PMS_ALPS_MAGIC3_1 10
+#define PMS_ALPS_MAGIC3_2 100
+
 /* Synaptics queries */
 #define SYNAPTICS_QUE_IDENTIFY 0x00
 #define SYNAPTICS_QUE_MODES 0x01
@@ -120,5 +125,10 @@
 #define SYNAPTICS_XMAX_BEZEL 5472
 #define SYNAPTICS_YMIN_BEZEL 1408
 #define SYNAPTICS_YMAX_BEZEL 4448
+
+#define ALPS_XMIN_BEZEL 130
+#define ALPS_XMAX_BEZEL 840
+#define ALPS_YMIN_BEZEL 130
+#define ALPS_YMAX_BEZEL 640
 
 #endif /* SYS_DEV_PCKBC_PMSREG_H */

Reply | Threaded
Open this post in threaded view
|

Re: Support for ALPS touchpads

Martin Pieuchot-2
On 04/09/11(Sun) 21:36, Martin Pieuchot wrote:

> The diff below adds support for ALPS touchpads to the pms(4) driver.
>
> I'm looking for testers with or without ALPS hardware, especially if you
> have a touchpad, to be sure it doesn't break anything.
>
> Currently, ALPS DualPoint are untested and support for special buttons
> (back, forward, etc) is missing because I don't have such hardware.
>
> I use the following synaptics(4) configuration for edge scrolling and
> simple left tapping:
>
> xinput set-prop /dev/wsmouse0 "Synaptics Finger" 25 30 60
> xinput set-int-prop /dev/wsmouse0 "Synaptics Tap Action" 8 0 0 2 3 1 0 0
> xinput set-int-prop /dev/wsmouse0 "Synaptics Click Action" 8 1 0 0
> xinput set-int-prop /dev/wsmouse0 "Synaptics Edge Scrolling" 8 1 0 0
>
>
> Compared to the previous version, I left the Y-axis translation because
> it's also needed for the COMPAT mode.

New version of the diff. Recent ALPS touchpads use a totally different
protocol and are not supported.

Martin

Index: pms.c
===================================================================
RCS file: /cvs/src/sys/dev/pckbc/pms.c,v
retrieving revision 1.21
diff -u -p -r1.21 pms.c
--- pms.c 24 Aug 2011 15:34:25 -0000 1.21
+++ pms.c 6 Sep 2011 09:19:24 -0000
@@ -39,6 +39,14 @@
 #include <dev/wscons/wsconsio.h>
 #include <dev/wscons/wsmousevar.h>
 
+#define DEBUG
+
+#ifdef DEBUG
+#define DPRINTF(x...) do { printf(x); } while (0);
+#else
+#define DPRINTF(x...)
+#endif
+
 #define DEVNAME(sc) ((sc)->sc_dev.dv_xname)
 
 #define WSMOUSE_BUTTON(x) (1 << ((x) - 1))
@@ -50,6 +58,7 @@ struct pms_protocol {
 #define PMS_STANDARD 0
 #define PMS_INTELLI 1
 #define PMS_SYNAPTICS 2
+#define PMS_ALPS 3
  u_int packetsize;
  int (*enable)(struct pms_softc *);
  int (*ioctl)(struct pms_softc *, u_long, caddr_t, int, struct proc *);
@@ -78,6 +87,22 @@ struct synaptics_softc {
 #define SYNAPTICS_PRESSURE 30
 };
 
+struct alps_softc {
+ int model;
+#define ALPS_UNSUPPORTED (1 << 1)
+#define ALPS_PASSTHROUGH (1 << 2)
+
+ int min_x, min_y;
+ int max_x, max_y;
+ int old_fin;
+
+ /* Compat mode */
+ int wsmode;
+ int old_x, old_y;
+ u_int old_buttons;
+#define ALPS_PRESSURE 40
+};
+
 struct pms_softc { /* driver status information */
  struct device sc_dev;
 
@@ -98,6 +123,7 @@ struct pms_softc { /* driver status inf
 
  const struct pms_protocol *protocol;
  struct synaptics_softc *synaptics;
+ struct alps_softc *alps;
 
  u_char packet[8];
 
@@ -116,6 +142,20 @@ static const u_int butmap[8] = {
  WSMOUSE_BUTTON(1) | WSMOUSE_BUTTON(2) | WSMOUSE_BUTTON(3)
 };
 
+static const struct alps_quirk {
+ int version;
+ int model;
+} alps_quirks[] = {
+ { 0x2021, ALPS_PASSTHROUGH },
+ { 0x2221, ALPS_PASSTHROUGH },
+ { 0x2222, ALPS_PASSTHROUGH },
+ { 0x3222, ALPS_PASSTHROUGH },
+ { 0x5212, ALPS_PASSTHROUGH },
+ { 0x6222, ALPS_PASSTHROUGH },
+ { 0x633b, ALPS_PASSTHROUGH },
+ { 0x7326, ALPS_UNSUPPORTED }, /* XXX Uses unknown v3 protocol */
+};
+
 int pmsprobe(struct device *, void *, void *);
 void pmsattach(struct device *, struct device *, void *);
 int pmsactivate(struct device *, int);
@@ -150,6 +190,11 @@ int pms_sync_synaptics(struct pms_softc
 void pms_proc_synaptics(struct pms_softc *);
 void pms_disable_synaptics(struct pms_softc *);
 
+int pms_enable_alps(struct pms_softc *);
+int pms_ioctl_alps(struct pms_softc *, u_long, caddr_t, int, struct proc *);
+int pms_sync_alps(struct pms_softc *, int);
+void pms_proc_alps(struct pms_softc *);
+
 int synaptics_set_mode(struct pms_softc *, int);
 int synaptics_query(struct pms_softc *, int, int *);
 int synaptics_get_hwinfo(struct pms_softc *);
@@ -160,6 +205,8 @@ int synaptics_pt_ioctl(void *, u_long, c
 int synaptics_pt_enable(void *);
 void synaptics_pt_disable(void *);
 
+int alps_get_hwinfo(struct pms_softc *);
+
 struct cfattach pms_ca = {
  sizeof(struct pms_softc), pmsprobe, pmsattach, NULL,
  pmsactivate
@@ -208,7 +255,16 @@ const struct pms_protocol pms_protocols[
  pms_sync_synaptics,
  pms_proc_synaptics,
  pms_disable_synaptics
- }
+ },
+ /* ALPS touchpad */
+ {
+ PMS_ALPS, 6,
+ pms_enable_alps,
+ pms_ioctl_alps,
+ pms_sync_alps,
+ pms_proc_alps,
+ NULL
+ },
 };
 
 int
@@ -483,6 +539,8 @@ pmsattach(struct device *parent, struct
  sc->protocol = &pms_protocols[i];
  }
 
+ DPRINTF("%s: protocol type %d\n", DEVNAME(sc), sc->protocol->type);
+
  /* no interrupts until enabled */
  pms_change_state(sc, PMS_STATE_DISABLED, PMS_DEV_IGNORE);
 }
@@ -965,4 +1023,238 @@ pms_disable_synaptics(struct pms_softc *
  if (syn->capabilities & SYNAPTICS_CAP_SLEEP)
  synaptics_set_mode(sc, SYNAPTICS_SLEEP_MODE |
     SYNAPTICS_DISABLE_GESTURE);
+}
+
+int
+alps_get_hwinfo(struct pms_softc *sc)
+{
+ struct alps_softc *alps = sc->alps;
+ u_char resp[3];
+ int version, i;
+
+ if (pms_set_resolution(sc, 0) ||
+    pms_set_scaling(sc, 2) ||
+    pms_set_scaling(sc, 2) ||
+    pms_set_scaling(sc, 2) ||
+    pms_get_status(sc, resp)) {
+ DPRINTF("%s: alps: model query error\n", DEVNAME(sc));
+ return (-1);
+ }
+
+ version = (resp[0] << 8) | (resp[1] << 4) | (resp[2] / 20 + 1);
+
+ printf("%s: ALPS touchpad, version 0x%04x", DEVNAME(sc), version);
+
+ for (i = 0; i < nitems(alps_quirks); i++)
+ if (version == alps_quirks[i].version) {
+ alps->model = alps_quirks[i].model;
+ break;
+ }
+
+ if (alps->model & ALPS_UNSUPPORTED)
+ printf(" (unsupported)");
+ printf("\n");
+
+ return (0);
+}
+
+int
+pms_enable_alps(struct pms_softc *sc)
+{
+ struct alps_softc *alps = sc->alps;
+ u_char resp[3];
+
+ if (pms_set_resolution(sc, 0) ||
+    pms_set_scaling(sc, 1) ||
+    pms_set_scaling(sc, 1) ||
+    pms_set_scaling(sc, 1) ||
+    pms_get_status(sc, resp) ||
+    resp[0] != PMS_ALPS_MAGIC1 ||
+    resp[1] != PMS_ALPS_MAGIC2 ||
+    (resp[2] != PMS_ALPS_MAGIC3_1 && resp[2] != PMS_ALPS_MAGIC3_2))
+ return (0);
+
+ if (sc->alps == NULL) {
+ sc->alps = alps = malloc(sizeof(struct alps_softc),
+    M_DEVBUF, M_WAITOK | M_ZERO);
+ if (alps == NULL) {
+ printf("%s: alps: not enough memory\n", DEVNAME(sc));
+ goto err;
+ }
+
+ if (alps_get_hwinfo(sc))
+ goto err;
+
+ alps->min_x = ALPS_XMIN_BEZEL;
+ alps->min_y = ALPS_YMIN_BEZEL;
+ alps->max_x = ALPS_XMAX_BEZEL;
+ alps->max_y = ALPS_YMAX_BEZEL;
+
+ alps->wsmode = WSMOUSE_COMPAT;
+ }
+
+ if (alps->model & ALPS_UNSUPPORTED)
+ goto err;
+
+ if ((alps->model & ALPS_PASSTHROUGH) &&
+   (pms_set_scaling(sc, 2) ||
+    pms_set_scaling(sc, 2) ||
+    pms_set_scaling(sc, 2) ||
+    pms_dev_disable(sc))) {
+ DPRINTF("%s: alps: passthrough on error\n", DEVNAME(sc));
+ goto err;
+ }
+
+ if (pms_dev_disable(sc) ||
+    pms_dev_disable(sc) ||
+    pms_set_rate(sc, 0x0a)) {
+ DPRINTF("%s: alps: tapping error\n", DEVNAME(sc));
+ goto err;
+ }
+
+ if (pms_dev_disable(sc) ||
+    pms_dev_disable(sc) ||
+    pms_dev_disable(sc) ||
+    pms_dev_disable(sc) ||
+    pms_dev_enable(sc)) {
+ DPRINTF("%s: alps: absolute mode error\n", DEVNAME(sc));
+ goto err;
+ }
+
+ if ((alps->model & ALPS_PASSTHROUGH) &&
+   (pms_set_scaling(sc, 1) ||
+    pms_set_scaling(sc, 1) ||
+    pms_set_scaling(sc, 1) ||
+    pms_dev_disable(sc))) {
+ DPRINTF("%s: alps: passthrough off error\n", DEVNAME(sc));
+ goto err;
+ }
+
+ return (1);
+
+err:
+ pms_reset(sc);
+
+ return (0);
+}
+
+int
+pms_ioctl_alps(struct pms_softc *sc, u_long cmd, caddr_t data, int flag,
+    struct proc *p)
+{
+ struct alps_softc *alps = sc->alps;
+ struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data;
+ int wsmode;
+
+ switch (cmd) {
+ case WSMOUSEIO_GTYPE:
+ *(u_int *)data = WSMOUSE_TYPE_SYNAPTICS;
+ break;
+ case WSMOUSEIO_GCALIBCOORDS:
+ wsmc->minx = alps->min_x;
+ wsmc->maxx = alps->max_x;
+ wsmc->miny = alps->min_y;
+ wsmc->maxy = alps->max_y;
+ wsmc->swapxy = 0;
+ break;
+ case WSMOUSEIO_SETMODE:
+ wsmode = *(u_int *)data;
+ if (wsmode != WSMOUSE_COMPAT && wsmode != WSMOUSE_NATIVE)
+ return (EINVAL);
+ alps->wsmode = wsmode;
+ break;
+ default:
+ return (-1);
+ }
+ return (0);
+}
+
+int
+pms_sync_alps(struct pms_softc *sc, int data)
+{
+ switch (sc->inputstate) {
+ case 0:
+ if ((data & 0xf8) != 0xf8) /* XXX model dependant? */
+ return (-1);
+ break;
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ if ((data & 0x80) != 0)
+ return (-1);
+ break;
+ }
+
+ return (0);
+}
+
+void
+pms_proc_alps(struct pms_softc *sc)
+{
+ struct alps_softc *alps = sc->alps;
+ int x, y, z, dx, dy;
+ u_int buttons;
+ int fin, ges;
+
+ x = sc->packet[1] | ((sc->packet[2] & 0x78) << 4);
+ y = sc->packet[4] | ((sc->packet[3] & 0x70) << 3);
+ z = sc->packet[5];
+
+ /*
+ * XXX The Y-axis is in the oposit direction compared to
+ * Synaptics touchpads and PS/2 mouses.
+ * It's why we need to translate the y value here for both
+ * NATIVE and COMPAT modes.
+ */
+ y = ALPS_YMAX_BEZEL - y + ALPS_YMIN_BEZEL;
+
+ buttons = ((sc->packet[3] & 1) ? WSMOUSE_BUTTON(1) : 0) |
+    ((sc->packet[3] & 2) ? WSMOUSE_BUTTON(3) : 0) |
+    ((sc->packet[3] & 4) ? WSMOUSE_BUTTON(2) : 0);
+
+ if (alps->wsmode == WSMOUSE_NATIVE) {
+ if (z == 127) {
+ /* DualPoint touchpads are not absolute. */
+ wsmouse_input(sc->sc_wsmousedev, buttons, x, y, 0, 0,
+    WSMOUSE_INPUT_DELTA);
+ return;
+ }
+
+ ges = sc->packet[2] & 0x01;
+ fin = sc->packet[2] & 0x02;
+
+ /* Simulate click (tap) */
+ if (ges && !fin)
+ z = 35;
+
+ /* Generate a null pressure event (needed for tap & drag) */
+ if (ges && fin && !alps->old_fin)
+ z = 0;
+
+ wsmouse_input(sc->sc_wsmousedev, buttons, x, y, z, 0,
+    WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y |
+    WSMOUSE_INPUT_ABSOLUTE_Z);
+
+ alps->old_fin = fin;
+ } else {
+ dx = dy = 0;
+ if (z > ALPS_PRESSURE) {
+ dx = x - alps->old_x;
+ dy = y - alps->old_y;
+
+ /* Prevent jump */
+ dx = abs(dx) > 50 ? 0 : dx;
+ dy = abs(dy) > 50 ? 0 : dy;
+ }
+
+ if (dx || dy || buttons != alps->old_buttons)
+ wsmouse_input(sc->sc_wsmousedev, buttons, dx, dy, 0, 0,
+    WSMOUSE_INPUT_DELTA);
+
+ alps->old_x = x;
+ alps->old_y = y;
+ alps->old_buttons = buttons;
+ }
 }
Index: pmsreg.h
===================================================================
RCS file: /cvs/src/sys/dev/pckbc/pmsreg.h,v
retrieving revision 1.4
diff -u -p -r1.4 pmsreg.h
--- pmsreg.h 24 Aug 2011 15:34:25 -0000 1.4
+++ pmsreg.h 6 Sep 2011 07:32:05 -0000
@@ -37,6 +37,11 @@
 #define PMS_INTELLI_MAGIC3 80
 #define PMS_INTELLI_ID 0x03
 
+#define PMS_ALPS_MAGIC1 0
+#define PMS_ALPS_MAGIC2 0
+#define PMS_ALPS_MAGIC3_1 10
+#define PMS_ALPS_MAGIC3_2 100
+
 /* Synaptics queries */
 #define SYNAPTICS_QUE_IDENTIFY 0x00
 #define SYNAPTICS_QUE_MODES 0x01
@@ -120,5 +125,10 @@
 #define SYNAPTICS_XMAX_BEZEL 5472
 #define SYNAPTICS_YMIN_BEZEL 1408
 #define SYNAPTICS_YMAX_BEZEL 4448
+
+#define ALPS_XMIN_BEZEL 130
+#define ALPS_XMAX_BEZEL 840
+#define ALPS_YMIN_BEZEL 130
+#define ALPS_YMAX_BEZEL 640
 
 #endif /* SYS_DEV_PCKBC_PMSREG_H */

Reply | Threaded
Open this post in threaded view
|

Re: Support for ALPS touchpads

Alexandr Shadchin-2
On Tue, Sep 06, 2011 at 02:25:47PM +0200, Martin Pieuchot wrote:

> On 04/09/11(Sun) 21:36, Martin Pieuchot wrote:
> > The diff below adds support for ALPS touchpads to the pms(4) driver.
> >
> > I'm looking for testers with or without ALPS hardware, especially if you
> > have a touchpad, to be sure it doesn't break anything.
> >
> > Currently, ALPS DualPoint are untested and support for special buttons
> > (back, forward, etc) is missing because I don't have such hardware.
> >
> > I use the following synaptics(4) configuration for edge scrolling and
> > simple left tapping:
> >
> > xinput set-prop /dev/wsmouse0 "Synaptics Finger" 25 30 60
> > xinput set-int-prop /dev/wsmouse0 "Synaptics Tap Action" 8 0 0 2 3 1 0 0
> > xinput set-int-prop /dev/wsmouse0 "Synaptics Click Action" 8 1 0 0
> > xinput set-int-prop /dev/wsmouse0 "Synaptics Edge Scrolling" 8 1 0 0
> >
> >
> > Compared to the previous version, I left the Y-axis translation because
> > it's also needed for the COMPAT mode.
>
> New version of the diff. Recent ALPS touchpads use a totally different
> protocol and are not supported.
>
> Martin
>
> Index: pms.c
> ===================================================================
> RCS file: /cvs/src/sys/dev/pckbc/pms.c,v
> retrieving revision 1.21
> diff -u -p -r1.21 pms.c
> --- pms.c 24 Aug 2011 15:34:25 -0000 1.21
> +++ pms.c 6 Sep 2011 09:19:24 -0000
> @@ -39,6 +39,14 @@
>  #include <dev/wscons/wsconsio.h>
>  #include <dev/wscons/wsmousevar.h>
>  
> +#define DEBUG
> +
> +#ifdef DEBUG
> +#define DPRINTF(x...) do { printf(x); } while (0);
> +#else
> +#define DPRINTF(x...)
> +#endif
> +
>  #define DEVNAME(sc) ((sc)->sc_dev.dv_xname)
>  
>  #define WSMOUSE_BUTTON(x) (1 << ((x) - 1))
> @@ -50,6 +58,7 @@ struct pms_protocol {
>  #define PMS_STANDARD 0
>  #define PMS_INTELLI 1
>  #define PMS_SYNAPTICS 2
> +#define PMS_ALPS 3
>   u_int packetsize;
>   int (*enable)(struct pms_softc *);
>   int (*ioctl)(struct pms_softc *, u_long, caddr_t, int, struct proc *);
> @@ -78,6 +87,22 @@ struct synaptics_softc {
>  #define SYNAPTICS_PRESSURE 30
>  };
>  
> +struct alps_softc {
> + int model;
> +#define ALPS_UNSUPPORTED (1 << 1)
> +#define ALPS_PASSTHROUGH (1 << 2)
> +
> + int min_x, min_y;
> + int max_x, max_y;
> + int old_fin;
> +
> + /* Compat mode */
> + int wsmode;
> + int old_x, old_y;
> + u_int old_buttons;
> +#define ALPS_PRESSURE 40
> +};
> +
>  struct pms_softc { /* driver status information */
>   struct device sc_dev;
>  
> @@ -98,6 +123,7 @@ struct pms_softc { /* driver status inf
>  
>   const struct pms_protocol *protocol;
>   struct synaptics_softc *synaptics;
> + struct alps_softc *alps;
>  
>   u_char packet[8];
>  
> @@ -116,6 +142,20 @@ static const u_int butmap[8] = {
>   WSMOUSE_BUTTON(1) | WSMOUSE_BUTTON(2) | WSMOUSE_BUTTON(3)
>  };
>  
> +static const struct alps_quirk {
> + int version;
> + int model;
> +} alps_quirks[] = {
> + { 0x2021, ALPS_PASSTHROUGH },
> + { 0x2221, ALPS_PASSTHROUGH },
> + { 0x2222, ALPS_PASSTHROUGH },
> + { 0x3222, ALPS_PASSTHROUGH },
> + { 0x5212, ALPS_PASSTHROUGH },
> + { 0x6222, ALPS_PASSTHROUGH },
> + { 0x633b, ALPS_PASSTHROUGH },
> + { 0x7326, ALPS_UNSUPPORTED }, /* XXX Uses unknown v3 protocol */
> +};

Using { 0x7326, ALPS_UNSUPPORTED } is not best idea.

Instead
        if (alps->model & ALPS_UNSUPPORTED)
use
        if (alps->model == 0)
or even better
        #define ALPS_UNSUPPORTED 0
        ...
        if (alps->model == ALPS_UNSUPPORTED)

If the device is not in alps_quirks, then it will automatically be
ALPS_UNSUPPORTED. No need to register each device is not supported.

> +
>  int pmsprobe(struct device *, void *, void *);
>  void pmsattach(struct device *, struct device *, void *);
>  int pmsactivate(struct device *, int);
> @@ -150,6 +190,11 @@ int pms_sync_synaptics(struct pms_softc
>  void pms_proc_synaptics(struct pms_softc *);
>  void pms_disable_synaptics(struct pms_softc *);
>  
> +int pms_enable_alps(struct pms_softc *);
> +int pms_ioctl_alps(struct pms_softc *, u_long, caddr_t, int, struct proc *);
> +int pms_sync_alps(struct pms_softc *, int);
> +void pms_proc_alps(struct pms_softc *);
> +
>  int synaptics_set_mode(struct pms_softc *, int);
>  int synaptics_query(struct pms_softc *, int, int *);
>  int synaptics_get_hwinfo(struct pms_softc *);
> @@ -160,6 +205,8 @@ int synaptics_pt_ioctl(void *, u_long, c
>  int synaptics_pt_enable(void *);
>  void synaptics_pt_disable(void *);
>  
> +int alps_get_hwinfo(struct pms_softc *);
> +
>  struct cfattach pms_ca = {
>   sizeof(struct pms_softc), pmsprobe, pmsattach, NULL,
>   pmsactivate
> @@ -208,7 +255,16 @@ const struct pms_protocol pms_protocols[
>   pms_sync_synaptics,
>   pms_proc_synaptics,
>   pms_disable_synaptics
> - }
> + },
> + /* ALPS touchpad */
> + {
> + PMS_ALPS, 6,
> + pms_enable_alps,
> + pms_ioctl_alps,
> + pms_sync_alps,
> + pms_proc_alps,
> + NULL
> + },
>  };
>  
>  int
> @@ -483,6 +539,8 @@ pmsattach(struct device *parent, struct
>   sc->protocol = &pms_protocols[i];
>   }
>  
> + DPRINTF("%s: protocol type %d\n", DEVNAME(sc), sc->protocol->type);
> +
>   /* no interrupts until enabled */
>   pms_change_state(sc, PMS_STATE_DISABLED, PMS_DEV_IGNORE);
>  }
> @@ -965,4 +1023,238 @@ pms_disable_synaptics(struct pms_softc *
>   if (syn->capabilities & SYNAPTICS_CAP_SLEEP)
>   synaptics_set_mode(sc, SYNAPTICS_SLEEP_MODE |
>      SYNAPTICS_DISABLE_GESTURE);
> +}
> +
> +int
> +alps_get_hwinfo(struct pms_softc *sc)
> +{
> + struct alps_softc *alps = sc->alps;
> + u_char resp[3];
> + int version, i;
> +
> + if (pms_set_resolution(sc, 0) ||
> +    pms_set_scaling(sc, 2) ||
> +    pms_set_scaling(sc, 2) ||
> +    pms_set_scaling(sc, 2) ||
> +    pms_get_status(sc, resp)) {
> + DPRINTF("%s: alps: model query error\n", DEVNAME(sc));
> + return (-1);
> + }
> +
> + version = (resp[0] << 8) | (resp[1] << 4) | (resp[2] / 20 + 1);
> +
> + printf("%s: ALPS touchpad, version 0x%04x", DEVNAME(sc), version);
> +
> + for (i = 0; i < nitems(alps_quirks); i++)
> + if (version == alps_quirks[i].version) {
> + alps->model = alps_quirks[i].model;
> + break;
> + }
> +
> + if (alps->model & ALPS_UNSUPPORTED)
> + printf(" (unsupported)");
> + printf("\n");
> +
> + return (0);
> +}
> +
> +int
> +pms_enable_alps(struct pms_softc *sc)
> +{
> + struct alps_softc *alps = sc->alps;
> + u_char resp[3];
> +
> + if (pms_set_resolution(sc, 0) ||
> +    pms_set_scaling(sc, 1) ||
> +    pms_set_scaling(sc, 1) ||
> +    pms_set_scaling(sc, 1) ||
> +    pms_get_status(sc, resp) ||
> +    resp[0] != PMS_ALPS_MAGIC1 ||
> +    resp[1] != PMS_ALPS_MAGIC2 ||
> +    (resp[2] != PMS_ALPS_MAGIC3_1 && resp[2] != PMS_ALPS_MAGIC3_2))
> + return (0);
> +
> + if (sc->alps == NULL) {
> + sc->alps = alps = malloc(sizeof(struct alps_softc),
> +    M_DEVBUF, M_WAITOK | M_ZERO);
> + if (alps == NULL) {
> + printf("%s: alps: not enough memory\n", DEVNAME(sc));
> + goto err;
> + }
> +
> + if (alps_get_hwinfo(sc))
> + goto err;
> +
> + alps->min_x = ALPS_XMIN_BEZEL;
> + alps->min_y = ALPS_YMIN_BEZEL;
> + alps->max_x = ALPS_XMAX_BEZEL;
> + alps->max_y = ALPS_YMAX_BEZEL;
> +
> + alps->wsmode = WSMOUSE_COMPAT;
> + }
> +
> + if (alps->model & ALPS_UNSUPPORTED)
> + goto err;
> +
> + if ((alps->model & ALPS_PASSTHROUGH) &&
> +   (pms_set_scaling(sc, 2) ||
> +    pms_set_scaling(sc, 2) ||
> +    pms_set_scaling(sc, 2) ||
> +    pms_dev_disable(sc))) {
> + DPRINTF("%s: alps: passthrough on error\n", DEVNAME(sc));
> + goto err;
> + }
> +
> + if (pms_dev_disable(sc) ||
> +    pms_dev_disable(sc) ||
> +    pms_set_rate(sc, 0x0a)) {
> + DPRINTF("%s: alps: tapping error\n", DEVNAME(sc));
> + goto err;
> + }
> +
> + if (pms_dev_disable(sc) ||
> +    pms_dev_disable(sc) ||
> +    pms_dev_disable(sc) ||
> +    pms_dev_disable(sc) ||
> +    pms_dev_enable(sc)) {
> + DPRINTF("%s: alps: absolute mode error\n", DEVNAME(sc));
> + goto err;
> + }
> +
> + if ((alps->model & ALPS_PASSTHROUGH) &&
> +   (pms_set_scaling(sc, 1) ||
> +    pms_set_scaling(sc, 1) ||
> +    pms_set_scaling(sc, 1) ||
> +    pms_dev_disable(sc))) {
> + DPRINTF("%s: alps: passthrough off error\n", DEVNAME(sc));
> + goto err;
> + }
> +
> + return (1);
> +
> +err:
> + pms_reset(sc);
> +
> + return (0);
> +}
> +
> +int
> +pms_ioctl_alps(struct pms_softc *sc, u_long cmd, caddr_t data, int flag,
> +    struct proc *p)
> +{
> + struct alps_softc *alps = sc->alps;
> + struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data;
> + int wsmode;
> +
> + switch (cmd) {
> + case WSMOUSEIO_GTYPE:
> + *(u_int *)data = WSMOUSE_TYPE_SYNAPTICS;
> + break;
> + case WSMOUSEIO_GCALIBCOORDS:
> + wsmc->minx = alps->min_x;
> + wsmc->maxx = alps->max_x;
> + wsmc->miny = alps->min_y;
> + wsmc->maxy = alps->max_y;
> + wsmc->swapxy = 0;
> + break;
> + case WSMOUSEIO_SETMODE:
> + wsmode = *(u_int *)data;
> + if (wsmode != WSMOUSE_COMPAT && wsmode != WSMOUSE_NATIVE)
> + return (EINVAL);
> + alps->wsmode = wsmode;
> + break;
> + default:
> + return (-1);
> + }
> + return (0);
> +}
> +
> +int
> +pms_sync_alps(struct pms_softc *sc, int data)
> +{
> + switch (sc->inputstate) {
> + case 0:
> + if ((data & 0xf8) != 0xf8) /* XXX model dependant? */
> + return (-1);
> + break;
> + case 1:
> + case 2:
> + case 3:
> + case 4:
> + case 5:
> + if ((data & 0x80) != 0)
> + return (-1);
> + break;
> + }
> +
> + return (0);
> +}
> +
> +void
> +pms_proc_alps(struct pms_softc *sc)
> +{
> + struct alps_softc *alps = sc->alps;
> + int x, y, z, dx, dy;
> + u_int buttons;
> + int fin, ges;
> +
> + x = sc->packet[1] | ((sc->packet[2] & 0x78) << 4);
> + y = sc->packet[4] | ((sc->packet[3] & 0x70) << 3);
> + z = sc->packet[5];
> +
> + /*
> + * XXX The Y-axis is in the oposit direction compared to
> + * Synaptics touchpads and PS/2 mouses.
> + * It's why we need to translate the y value here for both
> + * NATIVE and COMPAT modes.
> + */
> + y = ALPS_YMAX_BEZEL - y + ALPS_YMIN_BEZEL;
> +
> + buttons = ((sc->packet[3] & 1) ? WSMOUSE_BUTTON(1) : 0) |
> +    ((sc->packet[3] & 2) ? WSMOUSE_BUTTON(3) : 0) |
> +    ((sc->packet[3] & 4) ? WSMOUSE_BUTTON(2) : 0);
> +
> + if (alps->wsmode == WSMOUSE_NATIVE) {
> + if (z == 127) {
> + /* DualPoint touchpads are not absolute. */
> + wsmouse_input(sc->sc_wsmousedev, buttons, x, y, 0, 0,
> +    WSMOUSE_INPUT_DELTA);
> + return;
> + }
> +
> + ges = sc->packet[2] & 0x01;
> + fin = sc->packet[2] & 0x02;
> +
> + /* Simulate click (tap) */
> + if (ges && !fin)
> + z = 35;
> +
> + /* Generate a null pressure event (needed for tap & drag) */
> + if (ges && fin && !alps->old_fin)
> + z = 0;
> +
> + wsmouse_input(sc->sc_wsmousedev, buttons, x, y, z, 0,
> +    WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y |
> +    WSMOUSE_INPUT_ABSOLUTE_Z);
> +
> + alps->old_fin = fin;
> + } else {
> + dx = dy = 0;
> + if (z > ALPS_PRESSURE) {
> + dx = x - alps->old_x;
> + dy = y - alps->old_y;
> +
> + /* Prevent jump */
> + dx = abs(dx) > 50 ? 0 : dx;
> + dy = abs(dy) > 50 ? 0 : dy;
> + }
> +
> + if (dx || dy || buttons != alps->old_buttons)
> + wsmouse_input(sc->sc_wsmousedev, buttons, dx, dy, 0, 0,
> +    WSMOUSE_INPUT_DELTA);
> +
> + alps->old_x = x;
> + alps->old_y = y;
> + alps->old_buttons = buttons;
> + }
>  }
> Index: pmsreg.h
> ===================================================================
> RCS file: /cvs/src/sys/dev/pckbc/pmsreg.h,v
> retrieving revision 1.4
> diff -u -p -r1.4 pmsreg.h
> --- pmsreg.h 24 Aug 2011 15:34:25 -0000 1.4
> +++ pmsreg.h 6 Sep 2011 07:32:05 -0000
> @@ -37,6 +37,11 @@
>  #define PMS_INTELLI_MAGIC3 80
>  #define PMS_INTELLI_ID 0x03
>  
> +#define PMS_ALPS_MAGIC1 0
> +#define PMS_ALPS_MAGIC2 0
> +#define PMS_ALPS_MAGIC3_1 10
> +#define PMS_ALPS_MAGIC3_2 100
> +
>  /* Synaptics queries */
>  #define SYNAPTICS_QUE_IDENTIFY 0x00
>  #define SYNAPTICS_QUE_MODES 0x01
> @@ -120,5 +125,10 @@
>  #define SYNAPTICS_XMAX_BEZEL 5472
>  #define SYNAPTICS_YMIN_BEZEL 1408
>  #define SYNAPTICS_YMAX_BEZEL 4448
> +
> +#define ALPS_XMIN_BEZEL 130
> +#define ALPS_XMAX_BEZEL 840
> +#define ALPS_YMIN_BEZEL 130
> +#define ALPS_YMAX_BEZEL 640
>  
>  #endif /* SYS_DEV_PCKBC_PMSREG_H */

--
Alexandr Shadchin

Reply | Threaded
Open this post in threaded view
|

Re: Support for ALPS touchpads

Martin Pieuchot-2
On 15/09/11(Thu) 00:10, Alexandr Shadchin wrote:

> [...]
>
> Using { 0x7326, ALPS_UNSUPPORTED } is not best idea.
>
> Instead
> if (alps->model & ALPS_UNSUPPORTED)
> use
> if (alps->model == 0)
> or even better
> #define ALPS_UNSUPPORTED 0
> ...
> if (alps->model == ALPS_UNSUPPORTED)
>
> If the device is not in alps_quirks, then it will automatically be
> ALPS_UNSUPPORTED. No need to register each device is not supported.

New version with a list of models.

Any regression with a Synaptics touchpad?


Index: pms.c
===================================================================
RCS file: /cvs/src/sys/dev/pckbc/pms.c,v
retrieving revision 1.21
diff -u -p -r1.21 pms.c
--- pms.c 24 Aug 2011 15:34:25 -0000 1.21
+++ pms.c 19 Sep 2011 07:33:22 -0000
@@ -39,6 +39,12 @@
 #include <dev/wscons/wsconsio.h>
 #include <dev/wscons/wsmousevar.h>
 
+#ifdef DEBUG
+#define DPRINTF(x...) do { printf(x); } while (0);
+#else
+#define DPRINTF(x...)
+#endif
+
 #define DEVNAME(sc) ((sc)->sc_dev.dv_xname)
 
 #define WSMOUSE_BUTTON(x) (1 << ((x) - 1))
@@ -50,6 +56,7 @@ struct pms_protocol {
 #define PMS_STANDARD 0
 #define PMS_INTELLI 1
 #define PMS_SYNAPTICS 2
+#define PMS_ALPS 3
  u_int packetsize;
  int (*enable)(struct pms_softc *);
  int (*ioctl)(struct pms_softc *, u_long, caddr_t, int, struct proc *);
@@ -78,6 +85,20 @@ struct synaptics_softc {
 #define SYNAPTICS_PRESSURE 30
 };
 
+struct alps_softc {
+ int model;
+
+ int min_x, min_y;
+ int max_x, max_y;
+ int old_fin;
+
+ /* Compat mode */
+ int wsmode;
+ int old_x, old_y;
+ u_int old_buttons;
+#define ALPS_PRESSURE 40
+};
+
 struct pms_softc { /* driver status information */
  struct device sc_dev;
 
@@ -98,6 +119,7 @@ struct pms_softc { /* driver status inf
 
  const struct pms_protocol *protocol;
  struct synaptics_softc *synaptics;
+ struct alps_softc *alps;
 
  u_char packet[8];
 
@@ -116,6 +138,33 @@ static const u_int butmap[8] = {
  WSMOUSE_BUTTON(1) | WSMOUSE_BUTTON(2) | WSMOUSE_BUTTON(3)
 };
 
+static const struct alps_model {
+ int version;
+ int model;
+} alps_models[] = {
+ { 0x2021, ALPS_DUALPOINT | ALPS_PASSTHROUGH },
+ { 0x2221, ALPS_DUALPOINT | ALPS_PASSTHROUGH },
+ { 0x2222, ALPS_DUALPOINT | ALPS_PASSTHROUGH },
+ { 0x3222, ALPS_DUALPOINT | ALPS_PASSTHROUGH },
+ { 0x5212, ALPS_DUALPOINT | ALPS_PASSTHROUGH },
+ { 0x5321, ALPS_GLIDEPOINT },
+ { 0x5322, ALPS_GLIDEPOINT },
+ { 0x603b, ALPS_GLIDEPOINT },
+ { 0x6222, ALPS_DUALPOINT | ALPS_PASSTHROUGH },
+ { 0x6321, ALPS_GLIDEPOINT },
+ { 0x6322, ALPS_GLIDEPOINT },
+ { 0x6323, ALPS_GLIDEPOINT },
+ { 0x6324, ALPS_GLIDEPOINT },
+ { 0x6325, ALPS_GLIDEPOINT },
+ { 0x6326, ALPS_GLIDEPOINT },
+ { 0x633b, ALPS_DUALPOINT | ALPS_PASSTHROUGH },
+ { 0x7301, ALPS_DUALPOINT },
+ { 0x7321, ALPS_GLIDEPOINT },
+ { 0x7322, ALPS_GLIDEPOINT },
+ { 0x7325, ALPS_GLIDEPOINT },
+ { 0x7326, ALPS_UNSUPPORTED }, /* XXX Uses unknown v3 protocol */
+};
+
 int pmsprobe(struct device *, void *, void *);
 void pmsattach(struct device *, struct device *, void *);
 int pmsactivate(struct device *, int);
@@ -150,6 +199,11 @@ int pms_sync_synaptics(struct pms_softc
 void pms_proc_synaptics(struct pms_softc *);
 void pms_disable_synaptics(struct pms_softc *);
 
+int pms_enable_alps(struct pms_softc *);
+int pms_ioctl_alps(struct pms_softc *, u_long, caddr_t, int, struct proc *);
+int pms_sync_alps(struct pms_softc *, int);
+void pms_proc_alps(struct pms_softc *);
+
 int synaptics_set_mode(struct pms_softc *, int);
 int synaptics_query(struct pms_softc *, int, int *);
 int synaptics_get_hwinfo(struct pms_softc *);
@@ -160,6 +214,8 @@ int synaptics_pt_ioctl(void *, u_long, c
 int synaptics_pt_enable(void *);
 void synaptics_pt_disable(void *);
 
+int alps_get_hwinfo(struct pms_softc *);
+
 struct cfattach pms_ca = {
  sizeof(struct pms_softc), pmsprobe, pmsattach, NULL,
  pmsactivate
@@ -208,7 +264,16 @@ const struct pms_protocol pms_protocols[
  pms_sync_synaptics,
  pms_proc_synaptics,
  pms_disable_synaptics
- }
+ },
+ /* ALPS touchpad */
+ {
+ PMS_ALPS, 6,
+ pms_enable_alps,
+ pms_ioctl_alps,
+ pms_sync_alps,
+ pms_proc_alps,
+ NULL
+ },
 };
 
 int
@@ -483,6 +548,8 @@ pmsattach(struct device *parent, struct
  sc->protocol = &pms_protocols[i];
  }
 
+ DPRINTF("%s: protocol type %d\n", DEVNAME(sc), sc->protocol->type);
+
  /* no interrupts until enabled */
  pms_change_state(sc, PMS_STATE_DISABLED, PMS_DEV_IGNORE);
 }
@@ -965,4 +1032,238 @@ pms_disable_synaptics(struct pms_softc *
  if (syn->capabilities & SYNAPTICS_CAP_SLEEP)
  synaptics_set_mode(sc, SYNAPTICS_SLEEP_MODE |
     SYNAPTICS_DISABLE_GESTURE);
+}
+
+int
+alps_get_hwinfo(struct pms_softc *sc)
+{
+ struct alps_softc *alps = sc->alps;
+ u_char resp[3];
+ int version, i;
+
+ if (pms_set_resolution(sc, 0) ||
+    pms_set_scaling(sc, 2) ||
+    pms_set_scaling(sc, 2) ||
+    pms_set_scaling(sc, 2) ||
+    pms_get_status(sc, resp)) {
+ DPRINTF("%s: alps: model query error\n", DEVNAME(sc));
+ return (-1);
+ }
+
+ version = (resp[0] << 8) | (resp[1] << 4) | (resp[2] / 20 + 1);
+
+ printf("%s: ALPS touchpad, version 0x%04x", DEVNAME(sc), version);
+
+ for (i = 0; i < nitems(alps_models); i++)
+ if (version == alps_models[i].version) {
+ alps->model = alps_models[i].model;
+ break;
+ }
+
+ if (alps->model == ALPS_UNSUPPORTED)
+ printf(" (unsupported)");
+ printf("\n");
+
+ return (0);
+}
+
+int
+pms_enable_alps(struct pms_softc *sc)
+{
+ struct alps_softc *alps = sc->alps;
+ u_char resp[3];
+
+ if (pms_set_resolution(sc, 0) ||
+    pms_set_scaling(sc, 1) ||
+    pms_set_scaling(sc, 1) ||
+    pms_set_scaling(sc, 1) ||
+    pms_get_status(sc, resp) ||
+    resp[0] != PMS_ALPS_MAGIC1 ||
+    resp[1] != PMS_ALPS_MAGIC2 ||
+    (resp[2] != PMS_ALPS_MAGIC3_1 && resp[2] != PMS_ALPS_MAGIC3_2))
+ return (0);
+
+ if (sc->alps == NULL) {
+ sc->alps = alps = malloc(sizeof(struct alps_softc),
+    M_DEVBUF, M_WAITOK | M_ZERO);
+ if (alps == NULL) {
+ printf("%s: alps: not enough memory\n", DEVNAME(sc));
+ goto err;
+ }
+
+ if (alps_get_hwinfo(sc))
+ goto err;
+
+ alps->min_x = ALPS_XMIN_BEZEL;
+ alps->min_y = ALPS_YMIN_BEZEL;
+ alps->max_x = ALPS_XMAX_BEZEL;
+ alps->max_y = ALPS_YMAX_BEZEL;
+
+ alps->wsmode = WSMOUSE_COMPAT;
+ }
+
+ if (alps->model == ALPS_UNSUPPORTED)
+ goto err;
+
+ if ((alps->model & ALPS_PASSTHROUGH) &&
+   (pms_set_scaling(sc, 2) ||
+    pms_set_scaling(sc, 2) ||
+    pms_set_scaling(sc, 2) ||
+    pms_dev_disable(sc))) {
+ DPRINTF("%s: alps: passthrough on error\n", DEVNAME(sc));
+ goto err;
+ }
+
+ if (pms_dev_disable(sc) ||
+    pms_dev_disable(sc) ||
+    pms_set_rate(sc, 0x0a)) {
+ DPRINTF("%s: alps: tapping error\n", DEVNAME(sc));
+ goto err;
+ }
+
+ if (pms_dev_disable(sc) ||
+    pms_dev_disable(sc) ||
+    pms_dev_disable(sc) ||
+    pms_dev_disable(sc) ||
+    pms_dev_enable(sc)) {
+ DPRINTF("%s: alps: absolute mode error\n", DEVNAME(sc));
+ goto err;
+ }
+
+ if ((alps->model & ALPS_PASSTHROUGH) &&
+   (pms_set_scaling(sc, 1) ||
+    pms_set_scaling(sc, 1) ||
+    pms_set_scaling(sc, 1) ||
+    pms_dev_disable(sc))) {
+ DPRINTF("%s: alps: passthrough off error\n", DEVNAME(sc));
+ goto err;
+ }
+
+ return (1);
+
+err:
+ pms_reset(sc);
+
+ return (0);
+}
+
+int
+pms_ioctl_alps(struct pms_softc *sc, u_long cmd, caddr_t data, int flag,
+    struct proc *p)
+{
+ struct alps_softc *alps = sc->alps;
+ struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data;
+ int wsmode;
+
+ switch (cmd) {
+ case WSMOUSEIO_GTYPE:
+ *(u_int *)data = WSMOUSE_TYPE_SYNAPTICS;
+ break;
+ case WSMOUSEIO_GCALIBCOORDS:
+ wsmc->minx = alps->min_x;
+ wsmc->maxx = alps->max_x;
+ wsmc->miny = alps->min_y;
+ wsmc->maxy = alps->max_y;
+ wsmc->swapxy = 0;
+ break;
+ case WSMOUSEIO_SETMODE:
+ wsmode = *(u_int *)data;
+ if (wsmode != WSMOUSE_COMPAT && wsmode != WSMOUSE_NATIVE)
+ return (EINVAL);
+ alps->wsmode = wsmode;
+ break;
+ default:
+ return (-1);
+ }
+ return (0);
+}
+
+int
+pms_sync_alps(struct pms_softc *sc, int data)
+{
+ switch (sc->inputstate) {
+ case 0:
+ if ((data & 0xf8) != 0xf8) /* XXX model dependant? */
+ return (-1);
+ break;
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ if ((data & 0x80) != 0)
+ return (-1);
+ break;
+ }
+
+ return (0);
+}
+
+void
+pms_proc_alps(struct pms_softc *sc)
+{
+ struct alps_softc *alps = sc->alps;
+ int x, y, z, dx, dy;
+ u_int buttons;
+ int fin, ges;
+
+ x = sc->packet[1] | ((sc->packet[2] & 0x78) << 4);
+ y = sc->packet[4] | ((sc->packet[3] & 0x70) << 3);
+ z = sc->packet[5];
+
+ /*
+ * XXX The Y-axis is in the oposit direction compared to
+ * Synaptics touchpads and PS/2 mouses.
+ * It's why we need to translate the y value here for both
+ * NATIVE and COMPAT modes.
+ */
+ y = ALPS_YMAX_BEZEL - y + ALPS_YMIN_BEZEL;
+
+ buttons = ((sc->packet[3] & 1) ? WSMOUSE_BUTTON(1) : 0) |
+    ((sc->packet[3] & 2) ? WSMOUSE_BUTTON(3) : 0) |
+    ((sc->packet[3] & 4) ? WSMOUSE_BUTTON(2) : 0);
+
+ if (alps->wsmode == WSMOUSE_NATIVE) {
+ if (z == 127) {
+ /* DualPoint touchpads are not absolute. */
+ wsmouse_input(sc->sc_wsmousedev, buttons, x, y, 0, 0,
+    WSMOUSE_INPUT_DELTA);
+ return;
+ }
+
+ ges = sc->packet[2] & 0x01;
+ fin = sc->packet[2] & 0x02;
+
+ /* Simulate click (tap) */
+ if (ges && !fin)
+ z = 35;
+
+ /* Generate a null pressure event (needed for tap & drag) */
+ if (ges && fin && !alps->old_fin)
+ z = 0;
+
+ wsmouse_input(sc->sc_wsmousedev, buttons, x, y, z, 0,
+    WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y |
+    WSMOUSE_INPUT_ABSOLUTE_Z);
+
+ alps->old_fin = fin;
+ } else {
+ dx = dy = 0;
+ if (z > ALPS_PRESSURE) {
+ dx = x - alps->old_x;
+ dy = y - alps->old_y;
+
+ /* Prevent jump */
+ dx = abs(dx) > 50 ? 0 : dx;
+ dy = abs(dy) > 50 ? 0 : dy;
+ }
+
+ if (dx || dy || buttons != alps->old_buttons)
+ wsmouse_input(sc->sc_wsmousedev, buttons, dx, dy, 0, 0,
+    WSMOUSE_INPUT_DELTA);
+
+ alps->old_x = x;
+ alps->old_y = y;
+ alps->old_buttons = buttons;
+ }
 }
Index: pmsreg.h
===================================================================
RCS file: /cvs/src/sys/dev/pckbc/pmsreg.h,v
retrieving revision 1.4
diff -u -p -r1.4 pmsreg.h
--- pmsreg.h 24 Aug 2011 15:34:25 -0000 1.4
+++ pmsreg.h 19 Sep 2011 07:30:06 -0000
@@ -37,6 +37,11 @@
 #define PMS_INTELLI_MAGIC3 80
 #define PMS_INTELLI_ID 0x03
 
+#define PMS_ALPS_MAGIC1 0
+#define PMS_ALPS_MAGIC2 0
+#define PMS_ALPS_MAGIC3_1 10
+#define PMS_ALPS_MAGIC3_2 100
+
 /* Synaptics queries */
 #define SYNAPTICS_QUE_IDENTIFY 0x00
 #define SYNAPTICS_QUE_MODES 0x01
@@ -88,6 +93,11 @@
 #define SYNAPTICS_MODEL_SIMPLC (1 << 5)
 #define SYNAPTICS_MODEL_GEOMETRY(m) ((m) & 0x0f)
 
+#define ALPS_UNSUPPORTED (1 << 0)
+#define ALPS_GLIDEPOINT (1 << 1)
+#define ALPS_DUALPOINT (1 << 2)
+#define ALPS_PASSTHROUGH (1 << 3)
+
 /* Resolutions */
 #define SYNAPTICS_RESOLUTION_X(r) (((r) >> 16) & 0xff)
 #define SYNAPTICS_RESOLUTION_Y(r) ((r) & 0xff)
@@ -120,5 +130,10 @@
 #define SYNAPTICS_XMAX_BEZEL 5472
 #define SYNAPTICS_YMIN_BEZEL 1408
 #define SYNAPTICS_YMAX_BEZEL 4448
+
+#define ALPS_XMIN_BEZEL 130
+#define ALPS_XMAX_BEZEL 840
+#define ALPS_YMIN_BEZEL 130
+#define ALPS_YMAX_BEZEL 640
 
 #endif /* SYS_DEV_PCKBC_PMSREG_H */

Reply | Threaded
Open this post in threaded view
|

Re: Support for ALPS touchpads

Martin Pieuchot-2
On 19/09/11(Mon) 09:46, Martin Pieuchot wrote:

> On 15/09/11(Thu) 00:10, Alexandr Shadchin wrote:
> > [...]
> >
> > Using { 0x7326, ALPS_UNSUPPORTED } is not best idea.
> >
> > Instead
> > if (alps->model & ALPS_UNSUPPORTED)
> > use
> > if (alps->model == 0)
> > or even better
> > #define ALPS_UNSUPPORTED 0
> > ...
> > if (alps->model == ALPS_UNSUPPORTED)
> >
> > If the device is not in alps_quirks, then it will automatically be
> > ALPS_UNSUPPORTED. No need to register each device is not supported.
>
> New version with a list of models.
>
> Any regression with a Synaptics touchpad?

Apparently some Synaptics touchpads also respond to the ALPS query.

Updated diff below treats every device not listed in alps_models as
unsupported and should fix the regression.

Ok?

Index: pms.c
===================================================================
RCS file: /cvs/src/sys/dev/pckbc/pms.c,v
retrieving revision 1.21
diff -u -p -r1.21 pms.c
--- pms.c 24 Aug 2011 15:34:25 -0000 1.21
+++ pms.c 19 Sep 2011 13:43:00 -0000
@@ -39,6 +39,12 @@
 #include <dev/wscons/wsconsio.h>
 #include <dev/wscons/wsmousevar.h>
 
+#ifdef DEBUG
+#define DPRINTF(x...) do { printf(x); } while (0);
+#else
+#define DPRINTF(x...)
+#endif
+
 #define DEVNAME(sc) ((sc)->sc_dev.dv_xname)
 
 #define WSMOUSE_BUTTON(x) (1 << ((x) - 1))
@@ -50,6 +56,7 @@ struct pms_protocol {
 #define PMS_STANDARD 0
 #define PMS_INTELLI 1
 #define PMS_SYNAPTICS 2
+#define PMS_ALPS 3
  u_int packetsize;
  int (*enable)(struct pms_softc *);
  int (*ioctl)(struct pms_softc *, u_long, caddr_t, int, struct proc *);
@@ -78,6 +85,21 @@ struct synaptics_softc {
 #define SYNAPTICS_PRESSURE 30
 };
 
+struct alps_softc {
+ int model;
+ int version;
+
+ int min_x, min_y;
+ int max_x, max_y;
+ int old_fin;
+
+ /* Compat mode */
+ int wsmode;
+ int old_x, old_y;
+ u_int old_buttons;
+#define ALPS_PRESSURE 40
+};
+
 struct pms_softc { /* driver status information */
  struct device sc_dev;
 
@@ -98,6 +120,7 @@ struct pms_softc { /* driver status inf
 
  const struct pms_protocol *protocol;
  struct synaptics_softc *synaptics;
+ struct alps_softc *alps;
 
  u_char packet[8];
 
@@ -116,6 +139,35 @@ static const u_int butmap[8] = {
  WSMOUSE_BUTTON(1) | WSMOUSE_BUTTON(2) | WSMOUSE_BUTTON(3)
 };
 
+static const struct alps_model {
+ int version;
+ int model;
+} alps_models[] = {
+ { 0x2021, ALPS_DUALPOINT | ALPS_PASSTHROUGH },
+ { 0x2221, ALPS_DUALPOINT | ALPS_PASSTHROUGH },
+ { 0x2222, ALPS_DUALPOINT | ALPS_PASSTHROUGH },
+ { 0x3222, ALPS_DUALPOINT | ALPS_PASSTHROUGH },
+ { 0x5212, ALPS_DUALPOINT | ALPS_PASSTHROUGH },
+ { 0x5321, ALPS_GLIDEPOINT },
+ { 0x5322, ALPS_GLIDEPOINT },
+ { 0x603b, ALPS_GLIDEPOINT },
+ { 0x6222, ALPS_DUALPOINT | ALPS_PASSTHROUGH },
+ { 0x6321, ALPS_GLIDEPOINT },
+ { 0x6322, ALPS_GLIDEPOINT },
+ { 0x6323, ALPS_GLIDEPOINT },
+ { 0x6324, ALPS_GLIDEPOINT },
+ { 0x6325, ALPS_GLIDEPOINT },
+ { 0x6326, ALPS_GLIDEPOINT },
+ { 0x633b, ALPS_DUALPOINT | ALPS_PASSTHROUGH },
+ { 0x7301, ALPS_DUALPOINT },
+ { 0x7321, ALPS_GLIDEPOINT },
+ { 0x7322, ALPS_GLIDEPOINT },
+ { 0x7325, ALPS_GLIDEPOINT },
+#if 0
+ { 0x7326, 0 }, /* XXX Uses unknown v3 protocol */
+#endif
+};
+
 int pmsprobe(struct device *, void *, void *);
 void pmsattach(struct device *, struct device *, void *);
 int pmsactivate(struct device *, int);
@@ -150,6 +202,11 @@ int pms_sync_synaptics(struct pms_softc
 void pms_proc_synaptics(struct pms_softc *);
 void pms_disable_synaptics(struct pms_softc *);
 
+int pms_enable_alps(struct pms_softc *);
+int pms_ioctl_alps(struct pms_softc *, u_long, caddr_t, int, struct proc *);
+int pms_sync_alps(struct pms_softc *, int);
+void pms_proc_alps(struct pms_softc *);
+
 int synaptics_set_mode(struct pms_softc *, int);
 int synaptics_query(struct pms_softc *, int, int *);
 int synaptics_get_hwinfo(struct pms_softc *);
@@ -160,6 +217,8 @@ int synaptics_pt_ioctl(void *, u_long, c
 int synaptics_pt_enable(void *);
 void synaptics_pt_disable(void *);
 
+int alps_get_hwinfo(struct pms_softc *);
+
 struct cfattach pms_ca = {
  sizeof(struct pms_softc), pmsprobe, pmsattach, NULL,
  pmsactivate
@@ -208,7 +267,16 @@ const struct pms_protocol pms_protocols[
  pms_sync_synaptics,
  pms_proc_synaptics,
  pms_disable_synaptics
- }
+ },
+ /* ALPS touchpad */
+ {
+ PMS_ALPS, 6,
+ pms_enable_alps,
+ pms_ioctl_alps,
+ pms_sync_alps,
+ pms_proc_alps,
+ NULL
+ },
 };
 
 int
@@ -483,6 +551,8 @@ pmsattach(struct device *parent, struct
  sc->protocol = &pms_protocols[i];
  }
 
+ DPRINTF("%s: protocol type %d\n", DEVNAME(sc), sc->protocol->type);
+
  /* no interrupts until enabled */
  pms_change_state(sc, PMS_STATE_DISABLED, PMS_DEV_IGNORE);
 }
@@ -965,4 +1035,234 @@ pms_disable_synaptics(struct pms_softc *
  if (syn->capabilities & SYNAPTICS_CAP_SLEEP)
  synaptics_set_mode(sc, SYNAPTICS_SLEEP_MODE |
     SYNAPTICS_DISABLE_GESTURE);
+}
+
+int
+alps_get_hwinfo(struct pms_softc *sc)
+{
+ struct alps_softc *alps = sc->alps;
+ u_char resp[3];
+ int i;
+
+ if (pms_set_resolution(sc, 0) ||
+    pms_set_scaling(sc, 2) ||
+    pms_set_scaling(sc, 2) ||
+    pms_set_scaling(sc, 2) ||
+    pms_get_status(sc, resp)) {
+ DPRINTF("%s: alps: model query error\n", DEVNAME(sc));
+ return (-1);
+ }
+
+ alps->version = (resp[0] << 8) | (resp[1] << 4) | (resp[2] / 20 + 1);
+
+ for (i = 0; i < nitems(alps_models); i++)
+ if (alps->version == alps_models[i].version) {
+ alps->model = alps_models[i].model;
+ return (0);
+ }
+
+ return (-1);
+
+}
+
+int
+pms_enable_alps(struct pms_softc *sc)
+{
+ struct alps_softc *alps = sc->alps;
+ u_char resp[3];
+
+ if (pms_set_resolution(sc, 0) ||
+    pms_set_scaling(sc, 1) ||
+    pms_set_scaling(sc, 1) ||
+    pms_set_scaling(sc, 1) ||
+    pms_get_status(sc, resp) ||
+    resp[0] != PMS_ALPS_MAGIC1 ||
+    resp[1] != PMS_ALPS_MAGIC2 ||
+    (resp[2] != PMS_ALPS_MAGIC3_1 && resp[2] != PMS_ALPS_MAGIC3_2))
+ return (0);
+
+ if (sc->alps == NULL) {
+ sc->alps = alps = malloc(sizeof(struct alps_softc),
+    M_DEVBUF, M_WAITOK | M_ZERO);
+ if (alps == NULL) {
+ printf("%s: alps: not enough memory\n", DEVNAME(sc));
+ goto err;
+ }
+
+ if (alps_get_hwinfo(sc))
+ goto err;
+
+ printf("%s: ALPS %s, version 0x%04x\n", DEVNAME(sc),
+    (alps->model & ALPS_DUALPOINT ? "Dualpoint" : "Glidepoint"),
+    alps->version);
+
+ alps->min_x = ALPS_XMIN_BEZEL;
+ alps->min_y = ALPS_YMIN_BEZEL;
+ alps->max_x = ALPS_XMAX_BEZEL;
+ alps->max_y = ALPS_YMAX_BEZEL;
+
+ alps->wsmode = WSMOUSE_COMPAT;
+ }
+
+ if ((alps->model & ALPS_PASSTHROUGH) &&
+   (pms_set_scaling(sc, 2) ||
+    pms_set_scaling(sc, 2) ||
+    pms_set_scaling(sc, 2) ||
+    pms_dev_disable(sc))) {
+ DPRINTF("%s: alps: passthrough on error\n", DEVNAME(sc));
+ goto err;
+ }
+
+ if (pms_dev_disable(sc) ||
+    pms_dev_disable(sc) ||
+    pms_set_rate(sc, 0x0a)) {
+ DPRINTF("%s: alps: tapping error\n", DEVNAME(sc));
+ goto err;
+ }
+
+ if (pms_dev_disable(sc) ||
+    pms_dev_disable(sc) ||
+    pms_dev_disable(sc) ||
+    pms_dev_disable(sc) ||
+    pms_dev_enable(sc)) {
+ DPRINTF("%s: alps: absolute mode error\n", DEVNAME(sc));
+ goto err;
+ }
+
+ if ((alps->model & ALPS_PASSTHROUGH) &&
+   (pms_set_scaling(sc, 1) ||
+    pms_set_scaling(sc, 1) ||
+    pms_set_scaling(sc, 1) ||
+    pms_dev_disable(sc))) {
+ DPRINTF("%s: alps: passthrough off error\n", DEVNAME(sc));
+ goto err;
+ }
+
+ return (1);
+
+err:
+ pms_reset(sc);
+
+ return (0);
+}
+
+int
+pms_ioctl_alps(struct pms_softc *sc, u_long cmd, caddr_t data, int flag,
+    struct proc *p)
+{
+ struct alps_softc *alps = sc->alps;
+ struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data;
+ int wsmode;
+
+ switch (cmd) {
+ case WSMOUSEIO_GTYPE:
+ *(u_int *)data = WSMOUSE_TYPE_SYNAPTICS;
+ break;
+ case WSMOUSEIO_GCALIBCOORDS:
+ wsmc->minx = alps->min_x;
+ wsmc->maxx = alps->max_x;
+ wsmc->miny = alps->min_y;
+ wsmc->maxy = alps->max_y;
+ wsmc->swapxy = 0;
+ break;
+ case WSMOUSEIO_SETMODE:
+ wsmode = *(u_int *)data;
+ if (wsmode != WSMOUSE_COMPAT && wsmode != WSMOUSE_NATIVE)
+ return (EINVAL);
+ alps->wsmode = wsmode;
+ break;
+ default:
+ return (-1);
+ }
+ return (0);
+}
+
+int
+pms_sync_alps(struct pms_softc *sc, int data)
+{
+ switch (sc->inputstate) {
+ case 0:
+ if ((data & 0xf8) != 0xf8) /* XXX model dependant? */
+ return (-1);
+ break;
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ if ((data & 0x80) != 0)
+ return (-1);
+ break;
+ }
+
+ return (0);
+}
+
+void
+pms_proc_alps(struct pms_softc *sc)
+{
+ struct alps_softc *alps = sc->alps;
+ int x, y, z, dx, dy;
+ u_int buttons;
+ int fin, ges;
+
+ x = sc->packet[1] | ((sc->packet[2] & 0x78) << 4);
+ y = sc->packet[4] | ((sc->packet[3] & 0x70) << 3);
+ z = sc->packet[5];
+
+ /*
+ * XXX The Y-axis is in the oposit direction compared to
+ * Synaptics touchpads and PS/2 mouses.
+ * It's why we need to translate the y value here for both
+ * NATIVE and COMPAT modes.
+ */
+ y = ALPS_YMAX_BEZEL - y + ALPS_YMIN_BEZEL;
+
+ buttons = ((sc->packet[3] & 1) ? WSMOUSE_BUTTON(1) : 0) |
+    ((sc->packet[3] & 2) ? WSMOUSE_BUTTON(3) : 0) |
+    ((sc->packet[3] & 4) ? WSMOUSE_BUTTON(2) : 0);
+
+ if (alps->wsmode == WSMOUSE_NATIVE) {
+ if (z == 127) {
+ /* DualPoint touchpads are not absolute. */
+ wsmouse_input(sc->sc_wsmousedev, buttons, x, y, 0, 0,
+    WSMOUSE_INPUT_DELTA);
+ return;
+ }
+
+ ges = sc->packet[2] & 0x01;
+ fin = sc->packet[2] & 0x02;
+
+ /* Simulate click (tap) */
+ if (ges && !fin)
+ z = 35;
+
+ /* Generate a null pressure event (needed for tap & drag) */
+ if (ges && fin && !alps->old_fin)
+ z = 0;
+
+ wsmouse_input(sc->sc_wsmousedev, buttons, x, y, z, 0,
+    WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y |
+    WSMOUSE_INPUT_ABSOLUTE_Z);
+
+ alps->old_fin = fin;
+ } else {
+ dx = dy = 0;
+ if (z > ALPS_PRESSURE) {
+ dx = x - alps->old_x;
+ dy = y - alps->old_y;
+
+ /* Prevent jump */
+ dx = abs(dx) > 50 ? 0 : dx;
+ dy = abs(dy) > 50 ? 0 : dy;
+ }
+
+ if (dx || dy || buttons != alps->old_buttons)
+ wsmouse_input(sc->sc_wsmousedev, buttons, dx, dy, 0, 0,
+    WSMOUSE_INPUT_DELTA);
+
+ alps->old_x = x;
+ alps->old_y = y;
+ alps->old_buttons = buttons;
+ }
 }
Index: pmsreg.h
===================================================================
RCS file: /cvs/src/sys/dev/pckbc/pmsreg.h,v
retrieving revision 1.4
diff -u -p -r1.4 pmsreg.h
--- pmsreg.h 24 Aug 2011 15:34:25 -0000 1.4
+++ pmsreg.h 19 Sep 2011 13:55:08 -0000
@@ -37,6 +37,11 @@
 #define PMS_INTELLI_MAGIC3 80
 #define PMS_INTELLI_ID 0x03
 
+#define PMS_ALPS_MAGIC1 0
+#define PMS_ALPS_MAGIC2 0
+#define PMS_ALPS_MAGIC3_1 10
+#define PMS_ALPS_MAGIC3_2 100
+
 /* Synaptics queries */
 #define SYNAPTICS_QUE_IDENTIFY 0x00
 #define SYNAPTICS_QUE_MODES 0x01
@@ -88,6 +93,10 @@
 #define SYNAPTICS_MODEL_SIMPLC (1 << 5)
 #define SYNAPTICS_MODEL_GEOMETRY(m) ((m) & 0x0f)
 
+#define ALPS_GLIDEPOINT (1 << 1)
+#define ALPS_DUALPOINT (1 << 2)
+#define ALPS_PASSTHROUGH (1 << 3)
+
 /* Resolutions */
 #define SYNAPTICS_RESOLUTION_X(r) (((r) >> 16) & 0xff)
 #define SYNAPTICS_RESOLUTION_Y(r) ((r) & 0xff)
@@ -120,5 +129,10 @@
 #define SYNAPTICS_XMAX_BEZEL 5472
 #define SYNAPTICS_YMIN_BEZEL 1408
 #define SYNAPTICS_YMAX_BEZEL 4448
+
+#define ALPS_XMIN_BEZEL 130
+#define ALPS_XMAX_BEZEL 840
+#define ALPS_YMIN_BEZEL 130
+#define ALPS_YMAX_BEZEL 640
 
 #endif /* SYS_DEV_PCKBC_PMSREG_H */