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 via email to