svn commit: r307576 - in stable/11/sys: dev/atkbdc sys
Oleksandr Tymoshenko
gonzo at FreeBSD.org
Tue Oct 18 20:17:59 UTC 2016
Author: gonzo
Date: Tue Oct 18 20:17:57 2016
New Revision: 307576
URL: https://svnweb.freebsd.org/changeset/base/307576
Log:
MFC r306355, r306474, r306746:
r306355:
Add Elantech trackpad support
Elantech trackpads are found in some laptops like the Asus UX31E. They
are "synaptics compatible" but use a slightly different protocol.
Elantech hardware support is not enabled by default and just like
Synaptic or TrackPoint devices it should be enabled by setting
tunable, in this case hw.psm.elantech_support, to non-zero value
PR: 205690
Submitted by: Vladimir Kondratyev <wulf at cicgroup.ru>
MFC after: 1 week
r306474:
Replace explicit TUNABLE_INT to sysctl with CTLFLAG_TUN
- Replace tunables-only hw.psm.synaptics_support, hw.psm.trackpoint_support,
and hw.psm.elantech_support with respective sysctls declared with
CTLFLAG_TUN. It simplifies checking them in userland, also makes them
easier to get discovered by user
- Get rid of debug.psm.loglevel and hw.psm.tap_enabled TUNABLE_INT
declaration by adding CTLFLAG_TUN to read/write sysctls that were
already declared for these tunables.
Suggested by: jhb
r306746:
Fix extended buttons support on synaptic clickpad
Fix regression introduced by r306355 on synaptic clickpads with
extended buttons (buttons stopped working)
PR: 205690
Submitted by: Vladimir Kondratyev <wulf at cicgroup.ru>
Modified:
stable/11/sys/dev/atkbdc/psm.c
stable/11/sys/sys/mouse.h
Directory Properties:
stable/11/ (props changed)
Modified: stable/11/sys/dev/atkbdc/psm.c
==============================================================================
--- stable/11/sys/dev/atkbdc/psm.c Tue Oct 18 19:15:43 2016 (r307575)
+++ stable/11/sys/dev/atkbdc/psm.c Tue Oct 18 20:17:57 2016 (r307576)
@@ -81,6 +81,7 @@ __FBSDID("$FreeBSD$");
#include <sys/sysctl.h>
#include <sys/time.h>
#include <sys/uio.h>
+#include <sys/libkern.h>
#include <sys/limits.h>
#include <sys/mouse.h>
@@ -161,40 +162,6 @@ typedef struct packetbuf {
#define PSM_PACKETQUEUE 128
#endif
-enum {
- SYNAPTICS_SYSCTL_MIN_PRESSURE,
- SYNAPTICS_SYSCTL_MAX_PRESSURE,
- SYNAPTICS_SYSCTL_MAX_WIDTH,
- SYNAPTICS_SYSCTL_MARGIN_TOP,
- SYNAPTICS_SYSCTL_MARGIN_RIGHT,
- SYNAPTICS_SYSCTL_MARGIN_BOTTOM,
- SYNAPTICS_SYSCTL_MARGIN_LEFT,
- SYNAPTICS_SYSCTL_NA_TOP,
- SYNAPTICS_SYSCTL_NA_RIGHT,
- SYNAPTICS_SYSCTL_NA_BOTTOM,
- SYNAPTICS_SYSCTL_NA_LEFT,
- SYNAPTICS_SYSCTL_WINDOW_MIN,
- SYNAPTICS_SYSCTL_WINDOW_MAX,
- SYNAPTICS_SYSCTL_MULTIPLICATOR,
- SYNAPTICS_SYSCTL_WEIGHT_CURRENT,
- SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS,
- SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS_NA,
- SYNAPTICS_SYSCTL_WEIGHT_LEN_SQUARED,
- SYNAPTICS_SYSCTL_DIV_MIN,
- SYNAPTICS_SYSCTL_DIV_MAX,
- SYNAPTICS_SYSCTL_DIV_MAX_NA,
- SYNAPTICS_SYSCTL_DIV_LEN,
- SYNAPTICS_SYSCTL_TAP_MAX_DELTA,
- SYNAPTICS_SYSCTL_TAP_MIN_QUEUE,
- SYNAPTICS_SYSCTL_TAPHOLD_TIMEOUT,
- SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA,
- SYNAPTICS_SYSCTL_VSCROLL_VER_AREA,
- SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA,
- SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN,
- SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX,
- SYNAPTICS_SYSCTL_TOUCHPAD_OFF
-};
-
typedef struct synapticsinfo {
struct sysctl_ctx_list sysctl_ctx;
struct sysctl_oid *sysctl_tree;
@@ -231,6 +198,11 @@ typedef struct synapticsinfo {
int vscroll_div_min;
int vscroll_div_max;
int touchpad_off;
+ int softbuttons_y;
+ int softbutton2_x;
+ int softbutton3_x;
+ int max_x;
+ int max_y;
} synapticsinfo_t;
typedef struct synapticspacket {
@@ -246,22 +218,29 @@ typedef struct synapticspacket {
((synhw).infoMajor > (major) || \
((synhw).infoMajor == (major) && (synhw).infoMinor >= (minor)))
-typedef struct synapticsaction {
+typedef struct smoother {
synapticspacket_t queue[SYNAPTICS_PACKETQUEUE];
int queue_len;
int queue_cursor;
- int window_min;
int start_x;
int start_y;
int avg_dx;
int avg_dy;
int squelch_x;
int squelch_y;
+ int is_fuzzy;
+ int active;
+} smoother_t;
+
+typedef struct gesture {
+ int window_min;
int fingers_nb;
int tap_button;
int in_taphold;
int in_vscroll;
-} synapticsaction_t;
+ int zmax; /* maximum pressure value */
+ struct timeval taptimeout; /* tap timeout for touchpads */
+} gesture_t;
enum {
TRACKPOINT_SYSCTL_SENSITIVITY,
@@ -295,6 +274,100 @@ typedef struct trackpointinfo {
int skipback;
} trackpointinfo_t;
+typedef struct finger {
+ int x;
+ int y;
+ int p;
+ int w;
+ int flags;
+} finger_t;
+#define PSM_FINGERS 2 /* # of processed fingers */
+#define PSM_FINGER_IS_PEN (1<<0)
+#define PSM_FINGER_FUZZY (1<<1)
+#define PSM_FINGER_DEFAULT_P tap_threshold
+#define PSM_FINGER_DEFAULT_W 1
+#define PSM_FINGER_IS_SET(f) ((f).x != -1 && (f).y != -1 && (f).p != 0)
+#define PSM_FINGER_RESET(f) do { \
+ (f) = (finger_t) { .x = -1, .y = -1, .p = 0, .w = 0, .flags = 0 }; \
+} while (0)
+
+typedef struct elantechhw {
+ int hwversion;
+ int fwversion;
+ int sizex;
+ int sizey;
+ int dpmmx;
+ int dpmmy;
+ int ntracesx;
+ int ntracesy;
+ int issemimt;
+ int isclickpad;
+ int hascrc;
+ int hastrackpoint;
+ int haspressure;
+} elantechhw_t;
+
+/* minimum versions supported by this driver */
+#define ELANTECH_HW_IS_V1(fwver) ((fwver) < 0x020030 || (fwver) == 0x020600)
+
+#define ELANTECH_MAGIC(magic) \
+ ((magic)[0] == 0x3c && (magic)[1] == 0x03 && \
+ ((magic)[2] == 0xc8 || (magic)[2] == 0x00))
+
+#define ELANTECH_FW_ID 0x00
+#define ELANTECH_FW_VERSION 0x01
+#define ELANTECH_CAPABILITIES 0x02
+#define ELANTECH_SAMPLE 0x03
+#define ELANTECH_RESOLUTION 0x04
+#define ELANTECH_REG_READ 0x10
+#define ELANTECH_REG_WRITE 0x11
+#define ELANTECH_REG_RDWR 0x00
+#define ELANTECH_CUSTOM_CMD 0xf8
+
+#define ELANTECH_MAX_FINGERS PSM_FINGERS
+
+#define ELANTECH_FINGER_SET_XYP(pb) (finger_t) { \
+ .x = (((pb)->ipacket[1] & 0x0f) << 8) | (pb)->ipacket[2], \
+ .y = (((pb)->ipacket[4] & 0x0f) << 8) | (pb)->ipacket[5], \
+ .p = ((pb)->ipacket[1] & 0xf0) | (((pb)->ipacket[4] >> 4) & 0x0f), \
+ .w = PSM_FINGER_DEFAULT_W, \
+ .flags = 0 \
+}
+
+enum {
+ ELANTECH_PKT_NOP,
+ ELANTECH_PKT_TRACKPOINT,
+ ELANTECH_PKT_V2_COMMON,
+ ELANTECH_PKT_V2_2FINGER,
+ ELANTECH_PKT_V3,
+ ELANTECH_PKT_V4_STATUS,
+ ELANTECH_PKT_V4_HEAD,
+ ELANTECH_PKT_V4_MOTION
+};
+
+#define ELANTECH_PKT_IS_TRACKPOINT(pb) (((pb)->ipacket[3] & 0x0f) == 0x06)
+#define ELANTECH_PKT_IS_DEBOUNCE(pb, hwversion) ((hwversion) == 4 ? 0 : \
+ (pb)->ipacket[0] == ((hwversion) == 2 ? 0x84 : 0xc4) && \
+ (pb)->ipacket[1] == 0xff && (pb)->ipacket[2] == 0xff && \
+ (pb)->ipacket[3] == 0x02 && (pb)->ipacket[4] == 0xff && \
+ (pb)->ipacket[5] == 0xff)
+#define ELANTECH_PKT_IS_V2(pb) \
+ (((pb)->ipacket[0] & 0x0c) == 0x04 && ((pb)->ipacket[3] & 0x0f) == 0x02)
+#define ELANTECH_PKT_IS_V3_HEAD(pb, hascrc) ((hascrc) ? \
+ ((pb)->ipacket[3] & 0x09) == 0x08 : \
+ ((pb)->ipacket[0] & 0x0c) == 0x04 && ((pb)->ipacket[3] & 0xcf) == 0x02)
+#define ELANTECH_PKT_IS_V3_TAIL(pb, hascrc) ((hascrc) ? \
+ ((pb)->ipacket[3] & 0x09) == 0x09 : \
+ ((pb)->ipacket[0] & 0x0c) == 0x0c && ((pb)->ipacket[3] & 0xce) == 0x0c)
+#define ELANTECH_PKT_IS_V4(pb, hascrc) ((hascrc) ? \
+ ((pb)->ipacket[3] & 0x08) == 0x00 : \
+ ((pb)->ipacket[0] & 0x0c) == 0x04 && ((pb)->ipacket[3] & 0x1c) == 0x10)
+
+typedef struct elantechaction {
+ finger_t fingers[ELANTECH_MAX_FINGERS];
+ int mask;
+} elantechaction_t;
+
/* driver control block */
struct psm_softc { /* Driver status information */
int unit;
@@ -308,7 +381,10 @@ struct psm_softc { /* Driver status inf
mousehw_t hw; /* hardware information */
synapticshw_t synhw; /* Synaptics hardware information */
synapticsinfo_t syninfo; /* Synaptics configuration */
- synapticsaction_t synaction; /* Synaptics action context */
+ smoother_t smoother[PSM_FINGERS]; /* Motion smoothing */
+ gesture_t gesture; /* Gesture context */
+ elantechhw_t elanhw; /* Elantech hardware information */
+ elantechaction_t elanaction; /* Elantech action context */
int tphw; /* TrackPoint hardware information */
trackpointinfo_t tpinfo; /* TrackPoint configuration */
mousemode_t mode; /* operation mode */
@@ -324,13 +400,13 @@ struct psm_softc { /* Driver status inf
int xaverage; /* average X position */
int yaverage; /* average Y position */
int squelch; /* level to filter movement at low speed */
- int zmax; /* maximum pressure value for touchpads */
int syncerrors; /* # of bytes discarded to synchronize */
int pkterrors; /* # of packets failed during quaranteen. */
struct timeval inputtimeout;
struct timeval lastsoftintr; /* time of last soft interrupt */
struct timeval lastinputerr; /* time last sync error happened */
- struct timeval taptimeout; /* tap timeout for touchpads */
+ struct timeval idletimeout;
+ packetbuf_t idlepacket; /* packet to send after idle timeout */
int watchdog; /* watchdog timer flag */
struct callout callout; /* watchdog timer call out */
struct callout softcallout; /* buffer timer call out */
@@ -381,16 +457,10 @@ static devclass_t psm_devclass;
/* Tunables */
static int tap_enabled = -1;
-TUNABLE_INT("hw.psm.tap_enabled", &tap_enabled);
-
+static int verbose = PSM_DEBUG;
static int synaptics_support = 0;
-TUNABLE_INT("hw.psm.synaptics_support", &synaptics_support);
-
static int trackpoint_support = 0;
-TUNABLE_INT("hw.psm.trackpoint_support", &trackpoint_support);
-
-static int verbose = PSM_DEBUG;
-TUNABLE_INT("debug.psm.loglevel", &verbose);
+static int elantech_support = 0;
/* for backward compatibility */
#define OLD_MOUSE_GETHWINFO _IOR('M', 1, old_mousehw_t)
@@ -411,6 +481,44 @@ typedef struct old_mousemode {
int accelfactor;
} old_mousemode_t;
+#define SYN_OFFSET(field) offsetof(struct psm_softc, syninfo.field)
+enum {
+ SYNAPTICS_SYSCTL_MIN_PRESSURE = SYN_OFFSET(min_pressure),
+ SYNAPTICS_SYSCTL_MAX_PRESSURE = SYN_OFFSET(max_pressure),
+ SYNAPTICS_SYSCTL_MAX_WIDTH = SYN_OFFSET(max_width),
+ SYNAPTICS_SYSCTL_MARGIN_TOP = SYN_OFFSET(margin_top),
+ SYNAPTICS_SYSCTL_MARGIN_RIGHT = SYN_OFFSET(margin_right),
+ SYNAPTICS_SYSCTL_MARGIN_BOTTOM = SYN_OFFSET(margin_bottom),
+ SYNAPTICS_SYSCTL_MARGIN_LEFT = SYN_OFFSET(margin_left),
+ SYNAPTICS_SYSCTL_NA_TOP = SYN_OFFSET(na_top),
+ SYNAPTICS_SYSCTL_NA_RIGHT = SYN_OFFSET(na_right),
+ SYNAPTICS_SYSCTL_NA_BOTTOM = SYN_OFFSET(na_bottom),
+ SYNAPTICS_SYSCTL_NA_LEFT = SYN_OFFSET(na_left),
+ SYNAPTICS_SYSCTL_WINDOW_MIN = SYN_OFFSET(window_min),
+ SYNAPTICS_SYSCTL_WINDOW_MAX = SYN_OFFSET(window_max),
+ SYNAPTICS_SYSCTL_MULTIPLICATOR = SYN_OFFSET(multiplicator),
+ SYNAPTICS_SYSCTL_WEIGHT_CURRENT = SYN_OFFSET(weight_current),
+ SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS = SYN_OFFSET(weight_previous),
+ SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS_NA = SYN_OFFSET(weight_previous_na),
+ SYNAPTICS_SYSCTL_WEIGHT_LEN_SQUARED = SYN_OFFSET(weight_len_squared),
+ SYNAPTICS_SYSCTL_DIV_MIN = SYN_OFFSET(div_min),
+ SYNAPTICS_SYSCTL_DIV_MAX = SYN_OFFSET(div_max),
+ SYNAPTICS_SYSCTL_DIV_MAX_NA = SYN_OFFSET(div_max_na),
+ SYNAPTICS_SYSCTL_DIV_LEN = SYN_OFFSET(div_len),
+ SYNAPTICS_SYSCTL_TAP_MAX_DELTA = SYN_OFFSET(tap_max_delta),
+ SYNAPTICS_SYSCTL_TAP_MIN_QUEUE = SYN_OFFSET(tap_min_queue),
+ SYNAPTICS_SYSCTL_TAPHOLD_TIMEOUT = SYN_OFFSET(taphold_timeout),
+ SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA = SYN_OFFSET(vscroll_hor_area),
+ SYNAPTICS_SYSCTL_VSCROLL_VER_AREA = SYN_OFFSET(vscroll_ver_area),
+ SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA = SYN_OFFSET(vscroll_min_delta),
+ SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN = SYN_OFFSET(vscroll_div_min),
+ SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX = SYN_OFFSET(vscroll_div_max),
+ SYNAPTICS_SYSCTL_TOUCHPAD_OFF = SYN_OFFSET(touchpad_off),
+ SYNAPTICS_SYSCTL_SOFTBUTTONS_Y = SYN_OFFSET(softbuttons_y),
+ SYNAPTICS_SYSCTL_SOFTBUTTON2_X = SYN_OFFSET(softbutton2_x),
+ SYNAPTICS_SYSCTL_SOFTBUTTON3_X = SYN_OFFSET(softbutton3_x),
+};
+
/* packet formatting function */
typedef int packetfunc_t(struct psm_softc *, u_char *, int *, int,
mousestatus_t *);
@@ -446,6 +554,7 @@ static int doopen(struct psm_softc *, in
static int reinitialize(struct psm_softc *, int);
static char *model_name(int);
static void psmsoftintr(void *);
+static void psmsoftintridle(void *);
static void psmintr(void *);
static void psmtimeout(void *);
static int timeelapsed(const struct timeval *, int, int,
@@ -458,6 +567,13 @@ static int proc_synaptics(struct psm_sof
mousestatus_t *, int *, int *, int *);
static void proc_versapad(struct psm_softc *, packetbuf_t *,
mousestatus_t *, int *, int *, int *);
+static int proc_elantech(struct psm_softc *, packetbuf_t *,
+ mousestatus_t *, int *, int *, int *);
+static int psmpalmdetect(struct psm_softc *, finger_t *, int);
+static void psmgestures(struct psm_softc *, finger_t *, int,
+ mousestatus_t *);
+static void psmsmoother(struct psm_softc *, finger_t *, int,
+ mousestatus_t *, int *, int *);
static int tame_mouse(struct psm_softc *, packetbuf_t *, mousestatus_t *,
u_char *);
@@ -480,6 +596,7 @@ static probefunc_t enable_mmanplus;
static probefunc_t enable_synaptics;
static probefunc_t enable_trackpoint;
static probefunc_t enable_versapad;
+static probefunc_t enable_elantech;
static void set_trackpoint_parameters(struct psm_softc *sc);
static void synaptics_passthrough_on(struct psm_softc *sc);
@@ -511,6 +628,8 @@ static struct {
0xc8, MOUSE_4DPLUS_PACKETSIZE, enable_4dplus },
{ MOUSE_MODEL_SYNAPTICS, /* Synaptics Touchpad */
0xc0, MOUSE_SYNAPTICS_PACKETSIZE, enable_synaptics },
+ { MOUSE_MODEL_ELANTECH, /* Elantech Touchpad */
+ 0x04, MOUSE_ELANTECH_PACKETSIZE, enable_elantech },
{ MOUSE_MODEL_INTELLI, /* Microsoft IntelliMouse */
0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_msintelli },
{ MOUSE_MODEL_GLIDEPOINT, /* ALPS GlidePoint */
@@ -762,6 +881,7 @@ model_name(int model)
{ MOUSE_MODEL_4DPLUS, "4D+ Mouse" },
{ MOUSE_MODEL_SYNAPTICS, "Synaptics Touchpad" },
{ MOUSE_MODEL_TRACKPOINT, "IBM/Lenovo TrackPoint" },
+ { MOUSE_MODEL_ELANTECH, "Elantech Touchpad" },
{ MOUSE_MODEL_GENERIC, "Generic PS/2 mouse" },
{ MOUSE_MODEL_UNKNOWN, "Unknown" },
};
@@ -1504,6 +1624,7 @@ psmattach(device_t dev)
case MOUSE_MODEL_SYNAPTICS:
case MOUSE_MODEL_GLIDEPOINT:
case MOUSE_MODEL_VERSAPAD:
+ case MOUSE_MODEL_ELANTECH:
sc->config |= PSM_CONFIG_INITAFTERSUSPEND;
break;
default:
@@ -1512,6 +1633,11 @@ psmattach(device_t dev)
break;
}
+ /* Elantech trackpad`s sync bit differs from touchpad`s one */
+ if (sc->hw.model == MOUSE_MODEL_ELANTECH &&
+ (sc->elanhw.hascrc || sc->elanhw.hastrackpoint))
+ sc->config |= PSM_CONFIG_NOCHECKSYNC;
+
if (!verbose)
printf("psm%d: model %s, device ID %d\n",
unit, model_name(sc->hw.model), sc->hw.hwid & 0x00ff);
@@ -2165,20 +2291,6 @@ psmioctl(struct cdev *dev, u_long cmd, c
(*(int *)addr > PSM_LEVEL_MAX))
return (EINVAL);
sc->mode.level = *(int *)addr;
-
- if (sc->hw.model == MOUSE_MODEL_SYNAPTICS) {
- /*
- * If we are entering PSM_LEVEL_NATIVE, we want to
- * enable sending of "extended W mode" packets to
- * userland. Reset the mode of the touchpad so that the
- * change in the level is picked up.
- */
- error = block_mouse_data(sc, &command_byte);
- if (error)
- return (error);
- synaptics_set_mode(sc, synaptics_preferred_mode(sc));
- unblock_mouse_data(sc, command_byte);
- }
break;
case MOUSE_GETSTATUS:
@@ -2339,7 +2451,7 @@ psmtimeout(void *arg)
static SYSCTL_NODE(_debug, OID_AUTO, psm, CTLFLAG_RD, 0, "ps/2 mouse");
static SYSCTL_NODE(_hw, OID_AUTO, psm, CTLFLAG_RD, 0, "ps/2 mouse");
-SYSCTL_INT(_debug_psm, OID_AUTO, loglevel, CTLFLAG_RW, &verbose, 0,
+SYSCTL_INT(_debug_psm, OID_AUTO, loglevel, CTLFLAG_RWTUN, &verbose, 0,
"Verbosity level");
static int psmhz = 20;
@@ -2361,7 +2473,7 @@ static int pkterrthresh = 2;
SYSCTL_INT(_debug_psm, OID_AUTO, pkterrthresh, CTLFLAG_RW, &pkterrthresh, 0,
"Number of error packets allowed before reinitializing the mouse");
-SYSCTL_INT(_hw_psm, OID_AUTO, tap_enabled, CTLFLAG_RW, &tap_enabled, 0,
+SYSCTL_INT(_hw_psm, OID_AUTO, tap_enabled, CTLFLAG_RWTUN, &tap_enabled, 0,
"Enable tap and drag gestures");
static int tap_threshold = PSM_TAP_THRESHOLD;
SYSCTL_INT(_hw_psm, OID_AUTO, tap_threshold, CTLFLAG_RW, &tap_threshold, 0,
@@ -2370,6 +2482,16 @@ static int tap_timeout = PSM_TAP_TIMEOUT
SYSCTL_INT(_hw_psm, OID_AUTO, tap_timeout, CTLFLAG_RW, &tap_timeout, 0,
"Tap timeout for touchpads");
+/* Tunables */
+SYSCTL_INT(_hw_psm, OID_AUTO, synaptics_support, CTLFLAG_RDTUN,
+ &synaptics_support, 0, "Enable support for Synaptics touchpads");
+
+SYSCTL_INT(_hw_psm, OID_AUTO, trackpoint_support, CTLFLAG_RDTUN,
+ &trackpoint_support, 0, "Enable support for IBM/Lenovo TrackPoint");
+
+SYSCTL_INT(_hw_psm, OID_AUTO, elantech_support, CTLFLAG_RDTUN,
+ &elantech_support, 0, "Enable support for Elantech touchpads");
+
static void
psmintr(void *arg)
{
@@ -2627,7 +2749,10 @@ proc_synaptics(struct psm_softc *sc, pac
{
static int touchpad_buttons;
static int guest_buttons;
- int w, x0, y0;
+ static finger_t f[PSM_FINGERS];
+ int w, id, nfingers, ewcode, extended_buttons;
+
+ extended_buttons = 0;
/* TouchPad PS/2 absolute mode message format with capFourButtons:
*
@@ -2683,6 +2808,7 @@ proc_synaptics(struct psm_softc *sc, pac
return (-1);
*x = *y = 0;
+ ms->button = ms->obutton;
/*
* Pressure value.
@@ -2718,34 +2844,80 @@ proc_synaptics(struct psm_softc *sc, pac
w = 4;
}
- /*
- * Handle packets from the guest device. See:
- * Synaptics PS/2 TouchPad Interfacing Guide, Section 5.1
- */
- if (w == 3 && sc->synhw.capPassthrough) {
- *x = ((pb->ipacket[1] & 0x10) ?
- pb->ipacket[4] - 256 : pb->ipacket[4]);
- *y = ((pb->ipacket[1] & 0x20) ?
- pb->ipacket[5] - 256 : pb->ipacket[5]);
- *z = 0;
+ switch (w) {
+ case 3:
+ /*
+ * Handle packets from the guest device. See:
+ * Synaptics PS/2 TouchPad Interfacing Guide, Section 5.1
+ */
+ if (sc->synhw.capPassthrough) {
+ *x = ((pb->ipacket[1] & 0x10) ?
+ pb->ipacket[4] - 256 : pb->ipacket[4]);
+ *y = ((pb->ipacket[1] & 0x20) ?
+ pb->ipacket[5] - 256 : pb->ipacket[5]);
+ *z = 0;
+
+ guest_buttons = 0;
+ if (pb->ipacket[1] & 0x01)
+ guest_buttons |= MOUSE_BUTTON1DOWN;
+ if (pb->ipacket[1] & 0x04)
+ guest_buttons |= MOUSE_BUTTON2DOWN;
+ if (pb->ipacket[1] & 0x02)
+ guest_buttons |= MOUSE_BUTTON3DOWN;
- guest_buttons = 0;
- if (pb->ipacket[1] & 0x01)
- guest_buttons |= MOUSE_BUTTON1DOWN;
- if (pb->ipacket[1] & 0x04)
- guest_buttons |= MOUSE_BUTTON2DOWN;
- if (pb->ipacket[1] & 0x02)
- guest_buttons |= MOUSE_BUTTON3DOWN;
+ ms->button = touchpad_buttons | guest_buttons |
+ sc->extended_buttons;
+ }
+ goto SYNAPTICS_END;
- ms->button = touchpad_buttons | guest_buttons;
+ case 2:
+ /* Handle Extended W mode packets */
+ ewcode = (pb->ipacket[5] & 0xf0) >> 4;
+#if PSM_FINGERS > 1
+ switch (ewcode) {
+ case 1:
+ /* Secondary finger */
+ if (sc->synhw.capAdvancedGestures)
+ f[1] = (finger_t) {
+ .x = (((pb->ipacket[4] & 0x0f) << 8) |
+ pb->ipacket[1]) << 1,
+ .y = (((pb->ipacket[4] & 0xf0) << 4) |
+ pb->ipacket[2]) << 1,
+ .p = ((pb->ipacket[3] & 0x30) |
+ (pb->ipacket[5] & 0x0f)) << 1,
+ .w = PSM_FINGER_DEFAULT_W,
+ .flags = PSM_FINGER_FUZZY,
+ };
+ else if (sc->synhw.capReportsV)
+ f[1] = (finger_t) {
+ .x = (((pb->ipacket[4] & 0x0f) << 8) |
+ (pb->ipacket[1] & 0xfe)) << 1,
+ .y = (((pb->ipacket[4] & 0xf0) << 4) |
+ (pb->ipacket[2] & 0xfe)) << 1,
+ .p = ((pb->ipacket[3] & 0x30) |
+ (pb->ipacket[5] & 0x0e)) << 1,
+ .w = (((pb->ipacket[5] & 0x01) << 2) |
+ ((pb->ipacket[2] & 0x01) << 1) |
+ (pb->ipacket[1] & 0x01)) + 8,
+ .flags = PSM_FINGER_FUZZY,
+ };
+ default:
+ break;
+ }
+#endif
goto SYNAPTICS_END;
+
+ case 1:
+ case 0:
+ nfingers = w + 2;
+ break;
+
+ default:
+ nfingers = 1;
}
- if (sc->syninfo.touchpad_off) {
- *x = *y = *z = 0;
- ms->button = ms->obutton;
+ if (sc->syninfo.touchpad_off)
goto SYNAPTICS_END;
- }
/* Button presses */
touchpad_buttons = 0;
@@ -2769,21 +2941,21 @@ proc_synaptics(struct psm_softc *sc, pac
if ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x02) {
if (sc->syninfo.directional_scrolls) {
if (pb->ipacket[4] & 0x01)
- touchpad_buttons |= MOUSE_BUTTON4DOWN;
+ extended_buttons |= MOUSE_BUTTON4DOWN;
if (pb->ipacket[5] & 0x01)
- touchpad_buttons |= MOUSE_BUTTON5DOWN;
+ extended_buttons |= MOUSE_BUTTON5DOWN;
if (pb->ipacket[4] & 0x02)
- touchpad_buttons |= MOUSE_BUTTON6DOWN;
+ extended_buttons |= MOUSE_BUTTON6DOWN;
if (pb->ipacket[5] & 0x02)
- touchpad_buttons |= MOUSE_BUTTON7DOWN;
+ extended_buttons |= MOUSE_BUTTON7DOWN;
} else {
if (pb->ipacket[4] & 0x01)
- touchpad_buttons |= MOUSE_BUTTON1DOWN;
+ extended_buttons |= MOUSE_BUTTON1DOWN;
if (pb->ipacket[5] & 0x01)
- touchpad_buttons |= MOUSE_BUTTON3DOWN;
+ extended_buttons |= MOUSE_BUTTON3DOWN;
if (pb->ipacket[4] & 0x02)
- touchpad_buttons |= MOUSE_BUTTON2DOWN;
- sc->extended_buttons = touchpad_buttons;
+ extended_buttons |= MOUSE_BUTTON2DOWN;
+ sc->extended_buttons = extended_buttons;
}
/*
@@ -2806,101 +2978,193 @@ proc_synaptics(struct psm_softc *sc, pac
pb->ipacket[4] &= ~(mask);
pb->ipacket[5] &= ~(mask);
} else if (!sc->syninfo.directional_scrolls &&
- !sc->synaction.in_vscroll) {
+ !sc->gesture.in_vscroll) {
/*
* Keep reporting MOUSE DOWN until we get a new packet
* indicating otherwise.
*/
- touchpad_buttons |= sc->extended_buttons;
+ extended_buttons |= sc->extended_buttons;
}
}
- /* Handle ClickPad. */
+ /* Handle ClickPad */
if (sc->synhw.capClickPad &&
((pb->ipacket[0] ^ pb->ipacket[3]) & 0x01))
touchpad_buttons |= MOUSE_BUTTON1DOWN;
- ms->button = touchpad_buttons | guest_buttons;
+ if (sc->synhw.capReportsV && nfingers > 1)
+ f[0] = (finger_t) {
+ .x = ((pb->ipacket[3] & 0x10) << 8) |
+ ((pb->ipacket[1] & 0x0f) << 8) |
+ (pb->ipacket[4] & 0xfd),
+ .y = ((pb->ipacket[3] & 0x20) << 7) |
+ ((pb->ipacket[1] & 0xf0) << 4) |
+ (pb->ipacket[5] & 0xfd),
+ .p = *z & 0xfe,
+ .w = (((pb->ipacket[2] & 0x01) << 2) |
+ (pb->ipacket[5] & 0x02) |
+ ((pb->ipacket[4] & 0x02) >> 1)) + 8,
+ .flags = PSM_FINGER_FUZZY,
+ };
+ else
+ f[0] = (finger_t) {
+ .x = ((pb->ipacket[3] & 0x10) << 8) |
+ ((pb->ipacket[1] & 0x0f) << 8) |
+ pb->ipacket[4],
+ .y = ((pb->ipacket[3] & 0x20) << 7) |
+ ((pb->ipacket[1] & 0xf0) << 4) |
+ pb->ipacket[5],
+ .p = *z,
+ .w = w,
+ .flags = nfingers > 1 ? PSM_FINGER_FUZZY : 0,
+ };
+
+ /* Ignore hovering and unmeasurable touches */
+ if (f[0].p < sc->syninfo.min_pressure || f[0].x < 2)
+ nfingers = 0;
+
+ for (id = 0; id < PSM_FINGERS; id++)
+ if (id >= nfingers)
+ PSM_FINGER_RESET(f[id]);
+
+ ms->button = touchpad_buttons;
+
+ /* Palm detection doesn't terminate the current action. */
+ if (!psmpalmdetect(sc, &f[0], nfingers)) {
+ psmgestures(sc, &f[0], nfingers, ms);
+ for (id = 0; id < PSM_FINGERS; id++)
+ psmsmoother(sc, &f[id], id, ms, x, y);
+ } else {
+ VLOG(2, (LOG_DEBUG, "synaptics: palm detected! (%d)\n", f[0].w));
+ }
+
+ ms->button |= extended_buttons | guest_buttons;
+
+SYNAPTICS_END:
+ /*
+ * Use the extra buttons as a scrollwheel
+ *
+ * XXX X.Org uses the Z axis for vertical wheel only,
+ * whereas moused(8) understands special values to differ
+ * vertical and horizontal wheels.
+ *
+ * xf86-input-mouse needs therefore a small patch to
+ * understand these special values. Without it, the
+ * horizontal wheel acts as a vertical wheel in X.Org.
+ *
+ * That's why the horizontal wheel is disabled by
+ * default for now.
+ */
+ if (ms->button & MOUSE_BUTTON4DOWN)
+ *z = -1;
+ else if (ms->button & MOUSE_BUTTON5DOWN)
+ *z = 1;
+ else if (ms->button & MOUSE_BUTTON6DOWN)
+ *z = -2;
+ else if (ms->button & MOUSE_BUTTON7DOWN)
+ *z = 2;
+ else
+ *z = 0;
+ ms->button &= ~(MOUSE_BUTTON4DOWN | MOUSE_BUTTON5DOWN |
+ MOUSE_BUTTON6DOWN | MOUSE_BUTTON7DOWN);
+
+ return (0);
+}
+
+static int
+psmpalmdetect(struct psm_softc *sc, finger_t *f, int nfingers)
+{
+ if (!(
+ ((sc->synhw.capMultiFinger ||
+ sc->synhw.capAdvancedGestures) && nfingers > 1) ||
+ (sc->synhw.capPalmDetect && f->w <= sc->syninfo.max_width) ||
+ (!sc->synhw.capPalmDetect && f->p <= sc->syninfo.max_pressure) ||
+ (sc->synhw.capPen && f->flags & PSM_FINGER_IS_PEN))) {
+ /*
+ * We consider the packet irrelevant for the current
+ * action when:
+ * - the width isn't comprised in:
+ * [1; max_width]
+ * - the pressure isn't comprised in:
+ * [min_pressure; max_pressure]
+ * - pen aren't supported but PSM_FINGER_IS_PEN is set
+ */
+ return (1);
+ }
+ return (0);
+}
+
+static void
+psmgestures(struct psm_softc *sc, finger_t *fingers, int nfingers,
+ mousestatus_t *ms)
+{
+ smoother_t *smoother;
+ gesture_t *gest;
+ finger_t *f;
+ int y_ok, center_button, center_x, right_button, right_x, i;
+
+ f = &fingers[0];
+ smoother = &sc->smoother[0];
+ gest = &sc->gesture;
+
+ /* Find first active finger. */
+ if (nfingers > 0) {
+ for (i = 0; i < PSM_FINGERS; i++) {
+ if (PSM_FINGER_IS_SET(fingers[i])) {
+ f = &fingers[i];
+ smoother = &sc->smoother[i];
+ break;
+ }
+ }
+ }
/*
* Check pressure to detect a real wanted action on the
* touchpad.
*/
- if (*z >= sc->syninfo.min_pressure) {
- synapticsaction_t *synaction;
- int cursor, peer, window;
- int dx, dy, dxp, dyp;
- int max_width, max_pressure;
+ if (f->p >= sc->syninfo.min_pressure) {
+ int x0, y0;
+ int dxp, dyp;
+ int start_x, start_y;
+ int queue_len;
int margin_top, margin_right, margin_bottom, margin_left;
- int na_top, na_right, na_bottom, na_left;
int window_min, window_max;
- int multiplicator;
- int weight_current, weight_previous, weight_len_squared;
- int div_min, div_max, div_len;
int vscroll_hor_area, vscroll_ver_area;
int two_finger_scroll;
- int len, weight_prev_x, weight_prev_y;
- int div_max_x, div_max_y, div_x, div_y;
- int exiting_scroll;
+ int max_x, max_y;
/* Read sysctl. */
/* XXX Verify values? */
- max_width = sc->syninfo.max_width;
- max_pressure = sc->syninfo.max_pressure;
margin_top = sc->syninfo.margin_top;
margin_right = sc->syninfo.margin_right;
margin_bottom = sc->syninfo.margin_bottom;
margin_left = sc->syninfo.margin_left;
- na_top = sc->syninfo.na_top;
- na_right = sc->syninfo.na_right;
- na_bottom = sc->syninfo.na_bottom;
- na_left = sc->syninfo.na_left;
window_min = sc->syninfo.window_min;
window_max = sc->syninfo.window_max;
- multiplicator = sc->syninfo.multiplicator;
- weight_current = sc->syninfo.weight_current;
- weight_previous = sc->syninfo.weight_previous;
- weight_len_squared = sc->syninfo.weight_len_squared;
- div_min = sc->syninfo.div_min;
- div_max = sc->syninfo.div_max;
- div_len = sc->syninfo.div_len;
vscroll_hor_area = sc->syninfo.vscroll_hor_area;
vscroll_ver_area = sc->syninfo.vscroll_ver_area;
two_finger_scroll = sc->syninfo.two_finger_scroll;
-
- exiting_scroll = 0;
-
- /* Palm detection. */
- if (!(
- ((sc->synhw.capMultiFinger ||
- sc->synhw.capAdvancedGestures) && (w == 0 || w == 1)) ||
- (sc->synhw.capPalmDetect && w >= 4 && w <= max_width) ||
- (!sc->synhw.capPalmDetect && *z <= max_pressure) ||
- (sc->synhw.capPen && w == 2))) {
- /*
- * We consider the packet irrelevant for the current
- * action when:
- * - the width isn't comprised in:
- * [4; max_width]
- * - the pressure isn't comprised in:
- * [min_pressure; max_pressure]
- * - pen aren't supported but w is 2
- *
- * Note that this doesn't terminate the current action.
- */
- VLOG(2, (LOG_DEBUG,
- "synaptics: palm detected! (%d)\n", w));
- goto SYNAPTICS_END;
- }
+ max_x = sc->syninfo.max_x;
+ max_y = sc->syninfo.max_y;
/* Read current absolute position. */
- x0 = ((pb->ipacket[3] & 0x10) << 8) |
- ((pb->ipacket[1] & 0x0f) << 8) |
- pb->ipacket[4];
- y0 = ((pb->ipacket[3] & 0x20) << 7) |
- ((pb->ipacket[1] & 0xf0) << 4) |
- pb->ipacket[5];
+ x0 = f->x;
+ y0 = f->y;
+
+ /*
+ * Limit the coordinates to the specified margins because
+ * this area isn't very reliable.
+ */
+ if (x0 <= margin_left)
+ x0 = margin_left;
+ else if (x0 >= max_x - margin_right)
+ x0 = max_x - margin_right;
+ if (y0 <= margin_bottom)
+ y0 = margin_bottom;
+ else if (y0 >= max_y - margin_top)
+ y0 = max_y - margin_top;
- synaction = &(sc->synaction);
+ VLOG(3, (LOG_DEBUG, "synaptics: ipacket: [%d, %d], %d, %d\n",
+ x0, y0, f->p, f->w));
/*
* If the action is just beginning, init the structure and
@@ -2909,107 +3173,82 @@ proc_synaptics(struct psm_softc *sc, pac
if (!(sc->flags & PSM_FLAGS_FINGERDOWN)) {
VLOG(3, (LOG_DEBUG, "synaptics: ----\n"));
- /* Store the first point of this action. */
- synaction->start_x = x0;
- synaction->start_y = y0;
- dx = dy = 0;
-
/* Initialize queue. */
- synaction->queue_cursor = SYNAPTICS_PACKETQUEUE;
- synaction->queue_len = 0;
- synaction->window_min = window_min;
-
- /* Reset average. */
- synaction->avg_dx = 0;
- synaction->avg_dy = 0;
-
- /* Reset squelch. */
- synaction->squelch_x = 0;
- synaction->squelch_y = 0;
+ gest->window_min = window_min;
/* Reset pressure peak. */
- sc->zmax = 0;
+ gest->zmax = 0;
/* Reset fingers count. */
- synaction->fingers_nb = 0;
+ gest->fingers_nb = 0;
/* Reset virtual scrolling state. */
- synaction->in_vscroll = 0;
+ gest->in_vscroll = 0;
/* Compute tap timeout. */
- sc->taptimeout.tv_sec = tap_timeout / 1000000;
- sc->taptimeout.tv_usec = tap_timeout % 1000000;
- timevaladd(&sc->taptimeout, &sc->lastsoftintr);
+ gest->taptimeout.tv_sec = tap_timeout / 1000000;
+ gest->taptimeout.tv_usec = tap_timeout % 1000000;
+ timevaladd(&gest->taptimeout, &sc->lastsoftintr);
sc->flags |= PSM_FLAGS_FINGERDOWN;
+
+ /* Smoother has not been reset yet */
+ queue_len = 1;
+ start_x = x0;
+ start_y = y0;
} else {
- /* Calculate the current delta. */
- cursor = synaction->queue_cursor;
- dx = x0 - synaction->queue[cursor].x;
- dy = y0 - synaction->queue[cursor].y;
+ queue_len = smoother->queue_len + 1;
+ start_x = smoother->start_x;
+ start_y = smoother->start_y;
}
- /* If in tap-hold, add the recorded button. */
- if (synaction->in_taphold)
- ms->button |= synaction->tap_button;
-
- /*
- * From now on, we can use the SYNAPTICS_END label to skip
- * the current packet.
- */
-
- /*
- * Limit the coordinates to the specified margins because
- * this area isn't very reliable.
- */
- if (x0 <= margin_left)
- x0 = margin_left;
- else if (x0 >= 6143 - margin_right)
- x0 = 6143 - margin_right;
- if (y0 <= margin_bottom)
- y0 = margin_bottom;
- else if (y0 >= 6143 - margin_top)
- y0 = 6143 - margin_top;
+ /* Process ClickPad softbuttons */
+ if (sc->synhw.capClickPad && ms->button & MOUSE_BUTTON1DOWN) {
+ y_ok = sc->syninfo.softbuttons_y >= 0 ?
+ start_y < sc->syninfo.softbuttons_y :
+ start_y > max_y - sc->syninfo.softbuttons_y;
+
+ center_button = MOUSE_BUTTON2DOWN;
+ center_x = sc->syninfo.softbutton2_x;
+ right_button = MOUSE_BUTTON3DOWN;
+ right_x = sc->syninfo.softbutton3_x;
+
+ if (center_x > 0 && right_x > 0 && center_x > right_x) {
+ center_button = MOUSE_BUTTON3DOWN;
+ center_x = sc->syninfo.softbutton3_x;
+ right_button = MOUSE_BUTTON2DOWN;
+ right_x = sc->syninfo.softbutton2_x;
+ }
- VLOG(3, (LOG_DEBUG, "synaptics: ipacket: [%d, %d], %d, %d\n",
- x0, y0, *z, w));
+ if (right_x > 0 && start_x > right_x && y_ok)
+ ms->button = (ms->button &
+ ~MOUSE_BUTTON1DOWN) | right_button;
+ else if (center_x > 0 && start_x > center_x && y_ok)
+ ms->button = (ms->button &
+ ~MOUSE_BUTTON1DOWN) | center_button;
+ }
- /* Queue this new packet. */
- cursor = SYNAPTICS_QUEUE_CURSOR(synaction->queue_cursor - 1);
- synaction->queue[cursor].x = x0;
- synaction->queue[cursor].y = y0;
- synaction->queue_cursor = cursor;
- if (synaction->queue_len < SYNAPTICS_PACKETQUEUE)
- synaction->queue_len++;
- VLOG(5, (LOG_DEBUG,
- "synaptics: cursor[%d]: x=%d, y=%d, dx=%d, dy=%d\n",
- cursor, x0, y0, dx, dy));
+ /* If in tap-hold, add the recorded button. */
+ if (gest->in_taphold)
+ ms->button |= gest->tap_button;
/*
* For tap, we keep the maximum number of fingers and the
* pressure peak. Also with multiple fingers, we increase
* the minimum window.
*/
- switch (w) {
- case 1: /* Three or more fingers. */
- synaction->fingers_nb = imax(3, synaction->fingers_nb);
- synaction->window_min = window_max;
- break;
- case 0: /* Two fingers. */
- synaction->fingers_nb = imax(2, synaction->fingers_nb);
- synaction->window_min = window_max;
- break;
- default: /* One finger or undetectable. */
- synaction->fingers_nb = imax(1, synaction->fingers_nb);
- }
- sc->zmax = imax(*z, sc->zmax);
-
- /* Do we have enough packets to consider this a movement? */
- if (synaction->queue_len < synaction->window_min)
- goto SYNAPTICS_END;
+ if (nfingers > 1)
+ gest->window_min = window_max;
+ gest->fingers_nb = imax(nfingers, gest->fingers_nb);
+ gest->zmax = imax(f->p, gest->zmax);
+
+ /* Do we have enough packets to consider this a gesture? */
+ if (queue_len < gest->window_min)
+ return;
/* Is a scrolling action occurring? */
- if (!synaction->in_taphold && !synaction->in_vscroll) {
+ if (!gest->in_taphold && !ms->button &&
+ (!gest->in_vscroll || two_finger_scroll)) {
/*
* A scrolling action must not conflict with a tap
* action. Here are the conditions to consider a
@@ -3020,12 +3259,10 @@ proc_synaptics(struct psm_softc *sc, pac
* first should be above a configurable minimum
* . tap timed out
*/
- dxp = abs(synaction->queue[synaction->queue_cursor].x -
- synaction->start_x);
- dyp = abs(synaction->queue[synaction->queue_cursor].y -
- synaction->start_y);
+ dxp = abs(x0 - start_x);
+ dyp = abs(y0 - start_y);
- if (timevalcmp(&sc->lastsoftintr, &sc->taptimeout, >) ||
+ if (timevalcmp(&sc->lastsoftintr, &gest->taptimeout, >) ||
dxp >= sc->syninfo.vscroll_min_delta ||
dyp >= sc->syninfo.vscroll_min_delta) {
/*
@@ -3034,176 +3271,65 @@ proc_synaptics(struct psm_softc *sc, pac
* as that keeps the maximum number of fingers.
*/
if (two_finger_scroll) {
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-stable-11
mailing list