View | Details | Raw Unified | Return to bug 205690 | Differences between
and this patch

Collapse All | Expand All

(-)b/share/man/man4/psm.4 (-2 / +4 lines)
Lines 340-348 at boot-time. Link Here
340
This will enable
340
This will enable
341
.Nm
341
.Nm
342
to handle packets from guest devices (sticks) and extra buttons.
342
to handle packets from guest devices (sticks) and extra buttons.
343
Similarly, extended support for IBM/Lenovo TrackPoint can be enabled
343
Similarly, extended support for IBM/Lenovo TrackPoint and Elantech touchpads
344
by setting
344
can be enabled by setting
345
.Va hw.psm.trackpoint_support
345
.Va hw.psm.trackpoint_support
346
or
347
.Va hw.psm.elantech_support
346
to
348
to
347
.Em 1
349
.Em 1
348
at boot-time.
350
at boot-time.
(-)b/sys/dev/atkbdc/psm.c (-467 / +1648 lines)
Lines 81-86 __FBSDID("$FreeBSD$"); Link Here
81
#include <sys/sysctl.h>
81
#include <sys/sysctl.h>
82
#include <sys/time.h>
82
#include <sys/time.h>
83
#include <sys/uio.h>
83
#include <sys/uio.h>
84
#include <sys/libkern.h>
84
85
85
#include <sys/limits.h>
86
#include <sys/limits.h>
86
#include <sys/mouse.h>
87
#include <sys/mouse.h>
Lines 161-200 typedef struct packetbuf { Link Here
161
#define	PSM_PACKETQUEUE	128
162
#define	PSM_PACKETQUEUE	128
162
#endif
163
#endif
163
164
164
enum {
165
	SYNAPTICS_SYSCTL_MIN_PRESSURE,
166
	SYNAPTICS_SYSCTL_MAX_PRESSURE,
167
	SYNAPTICS_SYSCTL_MAX_WIDTH,
168
	SYNAPTICS_SYSCTL_MARGIN_TOP,
169
	SYNAPTICS_SYSCTL_MARGIN_RIGHT,
170
	SYNAPTICS_SYSCTL_MARGIN_BOTTOM,
171
	SYNAPTICS_SYSCTL_MARGIN_LEFT,
172
	SYNAPTICS_SYSCTL_NA_TOP,
173
	SYNAPTICS_SYSCTL_NA_RIGHT,
174
	SYNAPTICS_SYSCTL_NA_BOTTOM,
175
	SYNAPTICS_SYSCTL_NA_LEFT,
176
	SYNAPTICS_SYSCTL_WINDOW_MIN,
177
	SYNAPTICS_SYSCTL_WINDOW_MAX,
178
	SYNAPTICS_SYSCTL_MULTIPLICATOR,
179
	SYNAPTICS_SYSCTL_WEIGHT_CURRENT,
180
	SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS,
181
	SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS_NA,
182
	SYNAPTICS_SYSCTL_WEIGHT_LEN_SQUARED,
183
	SYNAPTICS_SYSCTL_DIV_MIN,
184
	SYNAPTICS_SYSCTL_DIV_MAX,
185
	SYNAPTICS_SYSCTL_DIV_MAX_NA,
186
	SYNAPTICS_SYSCTL_DIV_LEN,
187
	SYNAPTICS_SYSCTL_TAP_MAX_DELTA,
188
	SYNAPTICS_SYSCTL_TAP_MIN_QUEUE,
189
	SYNAPTICS_SYSCTL_TAPHOLD_TIMEOUT,
190
	SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA,
191
	SYNAPTICS_SYSCTL_VSCROLL_VER_AREA,
192
	SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA,
193
	SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN,
194
	SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX,
195
	SYNAPTICS_SYSCTL_TOUCHPAD_OFF
196
};
197
198
typedef struct synapticsinfo {
165
typedef struct synapticsinfo {
199
	struct sysctl_ctx_list	 sysctl_ctx;
166
	struct sysctl_ctx_list	 sysctl_ctx;
200
	struct sysctl_oid	*sysctl_tree;
167
	struct sysctl_oid	*sysctl_tree;
Lines 231-236 typedef struct synapticsinfo { Link Here
231
	int			 vscroll_div_min;
198
	int			 vscroll_div_min;
232
	int			 vscroll_div_max;
199
	int			 vscroll_div_max;
233
	int			 touchpad_off;
200
	int			 touchpad_off;
201
	int			 softbuttons_y;
202
	int			 softbutton2_x;
203
	int			 softbutton3_x;
204
	int			 max_x;
205
	int			 max_y;
234
} synapticsinfo_t;
206
} synapticsinfo_t;
235
207
236
typedef struct synapticspacket {
208
typedef struct synapticspacket {
Lines 246-267 typedef struct synapticspacket { Link Here
246
    ((synhw).infoMajor > (major) ||					\
218
    ((synhw).infoMajor > (major) ||					\
247
     ((synhw).infoMajor == (major) && (synhw).infoMinor >= (minor)))
219
     ((synhw).infoMajor == (major) && (synhw).infoMinor >= (minor)))
248
220
249
typedef struct synapticsaction {
221
typedef struct smoother {
250
	synapticspacket_t	queue[SYNAPTICS_PACKETQUEUE];
222
	synapticspacket_t	queue[SYNAPTICS_PACKETQUEUE];
251
	int			queue_len;
223
	int			queue_len;
252
	int			queue_cursor;
224
	int			queue_cursor;
253
	int			window_min;
254
	int			start_x;
225
	int			start_x;
255
	int			start_y;
226
	int			start_y;
256
	int			avg_dx;
227
	int			avg_dx;
257
	int			avg_dy;
228
	int			avg_dy;
258
	int			squelch_x;
229
	int			squelch_x;
259
	int			squelch_y;
230
	int			squelch_y;
231
	int			is_fuzzy;
232
	int			active;
233
} smoother_t;
234
235
typedef struct gesture {
236
	int			window_min;
260
	int			fingers_nb;
237
	int			fingers_nb;
261
	int			tap_button;
238
	int			tap_button;
262
	int			in_taphold;
239
	int			in_taphold;
263
	int			in_vscroll;
240
	int			in_vscroll;
264
} synapticsaction_t;
241
	int			zmax;		/* maximum pressure value */
242
	struct timeval		taptimeout;	/* tap timeout for touchpads */
243
} gesture_t;
265
244
266
enum {
245
enum {
267
	TRACKPOINT_SYSCTL_SENSITIVITY,
246
	TRACKPOINT_SYSCTL_SENSITIVITY,
Lines 295-300 typedef struct trackpointinfo { Link Here
295
	int	skipback;
274
	int	skipback;
296
} trackpointinfo_t;
275
} trackpointinfo_t;
297
276
277
typedef struct finger {
278
	int			x;
279
	int			y;
280
	int			p;
281
	int			w;
282
	int			flags;
283
} finger_t;
284
#define	PSM_FINGERS		2	/* # of processed fingers */
285
#define	PSM_FINGER_IS_PEN	(1<<0)
286
#define	PSM_FINGER_FUZZY	(1<<1)
287
#define	PSM_FINGER_DEFAULT_P	tap_threshold
288
#define	PSM_FINGER_DEFAULT_W	1
289
#define	PSM_FINGER_IS_SET(f) ((f).x != -1 && (f).y != -1 && (f).p != 0)
290
#define	PSM_FINGER_RESET(f) do \
291
	(f) = (finger_t) { .x = -1, .y = -1, .p = 0, .w = 0, .flags = 0 }; \
292
while (0)
293
294
typedef struct elantechhw {
295
	int			hwversion;
296
	int			fwversion;
297
	int			sizex;
298
	int			sizey;
299
	int			dpmmx;
300
	int			dpmmy;
301
	int			ntracesx;
302
	int			ntracesy;
303
	int			issemimt;
304
	int			isclickpad;
305
	int			hascrc;
306
	int			hastrackpad;
307
	int			haspressure;
308
} elantechhw_t;
309
310
/* minimum versions supported by this driver */
311
#define	ELANTECH_HW_IS_V1(fwver) ((fwver) < 0x020030 || (fwver) == 0x020600)
312
313
#define	ELANTECH_MAGIC(magic)				\
314
	((magic)[0] == 0x3c && (magic)[1] == 0x03 &&	\
315
	((magic)[2] == 0xc8 || (magic)[2] == 0x00))
316
317
#define	ELANTECH_FW_ID		0x00
318
#define	ELANTECH_FW_VERSION	0x01
319
#define	ELANTECH_CAPABILITIES	0x02
320
#define	ELANTECH_SAMPLE		0x03
321
#define	ELANTECH_RESOLUTION	0x04
322
#define	ELANTECH_REG_READ	0x10
323
#define	ELANTECH_REG_WRITE	0x11
324
#define	ELANTECH_REG_RDWR	0x00
325
#define	ELANTECH_CUSTOM_CMD	0xf8
326
327
#define	ELANTECH_MAX_FINGERS	PSM_FINGERS
328
329
#define	ELANTECH_FINGER_SET_XYP(pb) (finger_t) {			\
330
    .x = (((pb)->ipacket[1] & 0x0f) << 8) | (pb)->ipacket[2],		\
331
    .y = (((pb)->ipacket[4] & 0x0f) << 8) | (pb)->ipacket[5],		\
332
    .p = ((pb)->ipacket[1] & 0xf0) | (((pb)->ipacket[4] >> 4) & 0x0f),	\
333
    .w = PSM_FINGER_DEFAULT_W,						\
334
    .flags = 0								\
335
}
336
337
enum {
338
	ELANTECH_PKT_NOP,
339
	ELANTECH_PKT_TRACKPOINT,
340
	ELANTECH_PKT_V2_COMMON,
341
	ELANTECH_PKT_V2_2FINGER,
342
	ELANTECH_PKT_V3,
343
	ELANTECH_PKT_V4_STATUS,
344
	ELANTECH_PKT_V4_HEAD,
345
	ELANTECH_PKT_V4_MOTION
346
};
347
348
#define	ELANTECH_PKT_IS_TRACKPOINT(pb) (((pb)->ipacket[3] & 0x0f) == 0x06)
349
#define	ELANTECH_PKT_IS_DEBOUNCE(pb, hwversion) ((hwversion) == 4 ? 0 :	\
350
    (pb)->ipacket[0] == ((hwversion) == 2 ? 0x84 : 0xc4) &&		\
351
    (pb)->ipacket[1] == 0xff && (pb)->ipacket[2] == 0xff &&		\
352
    (pb)->ipacket[3] == 0x02 && (pb)->ipacket[4] == 0xff &&		\
353
    (pb)->ipacket[5] == 0xff)
354
#define	ELANTECH_PKT_IS_V2(pb) 						\
355
    (((pb)->ipacket[0] & 0x0c) == 0x04 && ((pb)->ipacket[3] & 0x0f) == 0x02)
356
#define	ELANTECH_PKT_IS_V3_HEAD(pb, hascrc) ((hascrc) ? 		\
357
    ((pb)->ipacket[3] & 0x09) == 0x08 : 				\
358
    ((pb)->ipacket[0] & 0x0c) == 0x04 && ((pb)->ipacket[3] & 0xcf) == 0x02)
359
#define	ELANTECH_PKT_IS_V3_TAIL(pb, hascrc) ((hascrc) ? 		\
360
    ((pb)->ipacket[3] & 0x09) == 0x09 : 				\
361
    ((pb)->ipacket[0] & 0x0c) == 0x0c && ((pb)->ipacket[3] & 0xce) == 0x0c)
362
#define	ELANTECH_PKT_IS_V4(pb, hascrc) ((hascrc) ? 			\
363
    ((pb)->ipacket[3] & 0x08) == 0x00 :					\
364
    ((pb)->ipacket[0] & 0x0c) == 0x04 && ((pb)->ipacket[3] & 0x1c) == 0x10)
365
366
typedef struct elantechaction {
367
	finger_t		fingers[ELANTECH_MAX_FINGERS];
368
	int			mask;
369
} elantechaction_t;
370
298
/* driver control block */
371
/* driver control block */
299
struct psm_softc {		/* Driver status information */
372
struct psm_softc {		/* Driver status information */
300
	int		unit;
373
	int		unit;
Lines 308-314 struct psm_softc { /* Driver status information */ Link Here
308
	mousehw_t	hw;		/* hardware information */
381
	mousehw_t	hw;		/* hardware information */
309
	synapticshw_t	synhw;		/* Synaptics hardware information */
382
	synapticshw_t	synhw;		/* Synaptics hardware information */
310
	synapticsinfo_t	syninfo;	/* Synaptics configuration */
383
	synapticsinfo_t	syninfo;	/* Synaptics configuration */
311
	synapticsaction_t synaction;	/* Synaptics action context */
384
	smoother_t	smoother[PSM_FINGERS];	/* Motion smoothing */
385
	gesture_t	gesture;	/* Gesture context */
386
	elantechhw_t	elanhw;		/* Elantech hardware information */
387
	elantechaction_t elanaction;	/* Elantech action context */
312
	int		tphw;		/* TrackPoint hardware information */
388
	int		tphw;		/* TrackPoint hardware information */
313
	trackpointinfo_t tpinfo;	/* TrackPoint configuration */
389
	trackpointinfo_t tpinfo;	/* TrackPoint configuration */
314
	mousemode_t	mode;		/* operation mode */
390
	mousemode_t	mode;		/* operation mode */
Lines 324-336 struct psm_softc { /* Driver status information */ Link Here
324
	int		xaverage;	/* average X position */
400
	int		xaverage;	/* average X position */
325
	int		yaverage;	/* average Y position */
401
	int		yaverage;	/* average Y position */
326
	int		squelch; /* level to filter movement at low speed */
402
	int		squelch; /* level to filter movement at low speed */
327
	int		zmax;	/* maximum pressure value for touchpads */
328
	int		syncerrors; /* # of bytes discarded to synchronize */
403
	int		syncerrors; /* # of bytes discarded to synchronize */
329
	int		pkterrors;  /* # of packets failed during quaranteen. */
404
	int		pkterrors;  /* # of packets failed during quaranteen. */
330
	struct timeval	inputtimeout;
405
	struct timeval	inputtimeout;
331
	struct timeval	lastsoftintr;	/* time of last soft interrupt */
406
	struct timeval	lastsoftintr;	/* time of last soft interrupt */
332
	struct timeval	lastinputerr;	/* time last sync error happened */
407
	struct timeval	lastinputerr;	/* time last sync error happened */
333
	struct timeval	taptimeout;	/* tap timeout for touchpads */
408
	struct timeval	idletimeout;
409
	packetbuf_t	idlepacket;	/* packet to send after idle timeout */
334
	int		watchdog;	/* watchdog timer flag */
410
	int		watchdog;	/* watchdog timer flag */
335
	struct callout	callout;	/* watchdog timer call out */
411
	struct callout	callout;	/* watchdog timer call out */
336
	struct callout	softcallout; /* buffer timer call out */
412
	struct callout	softcallout; /* buffer timer call out */
Lines 389-394 TUNABLE_INT("hw.psm.synaptics_support", &synaptics_support); Link Here
389
static int trackpoint_support = 0;
465
static int trackpoint_support = 0;
390
TUNABLE_INT("hw.psm.trackpoint_support", &trackpoint_support);
466
TUNABLE_INT("hw.psm.trackpoint_support", &trackpoint_support);
391
467
468
static int elantech_support = 0;
469
TUNABLE_INT("hw.psm.elantech_support", &elantech_support);
470
392
static int verbose = PSM_DEBUG;
471
static int verbose = PSM_DEBUG;
393
TUNABLE_INT("debug.psm.loglevel", &verbose);
472
TUNABLE_INT("debug.psm.loglevel", &verbose);
394
473
Lines 411-416 typedef struct old_mousemode { Link Here
411
	int	accelfactor;
490
	int	accelfactor;
412
} old_mousemode_t;
491
} old_mousemode_t;
413
492
493
#define SYN_OFFSET(field) offsetof(struct psm_softc, syninfo.field)
494
enum {
495
	SYNAPTICS_SYSCTL_MIN_PRESSURE =		SYN_OFFSET(min_pressure),
496
	SYNAPTICS_SYSCTL_MAX_PRESSURE =		SYN_OFFSET(max_pressure),
497
	SYNAPTICS_SYSCTL_MAX_WIDTH =		SYN_OFFSET(max_width),
498
	SYNAPTICS_SYSCTL_MARGIN_TOP =		SYN_OFFSET(margin_top),
499
	SYNAPTICS_SYSCTL_MARGIN_RIGHT =		SYN_OFFSET(margin_right),
500
	SYNAPTICS_SYSCTL_MARGIN_BOTTOM =	SYN_OFFSET(margin_bottom),
501
	SYNAPTICS_SYSCTL_MARGIN_LEFT =		SYN_OFFSET(margin_left),
502
	SYNAPTICS_SYSCTL_NA_TOP =		SYN_OFFSET(na_top),
503
	SYNAPTICS_SYSCTL_NA_RIGHT =		SYN_OFFSET(na_right),
504
	SYNAPTICS_SYSCTL_NA_BOTTOM =		SYN_OFFSET(na_bottom),
505
	SYNAPTICS_SYSCTL_NA_LEFT = 		SYN_OFFSET(na_left),
506
	SYNAPTICS_SYSCTL_WINDOW_MIN =		SYN_OFFSET(window_min),
507
	SYNAPTICS_SYSCTL_WINDOW_MAX =		SYN_OFFSET(window_max),
508
	SYNAPTICS_SYSCTL_MULTIPLICATOR =	SYN_OFFSET(multiplicator),
509
	SYNAPTICS_SYSCTL_WEIGHT_CURRENT =	SYN_OFFSET(weight_current),
510
	SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS =	SYN_OFFSET(weight_previous),
511
	SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS_NA =	SYN_OFFSET(weight_previous_na),
512
	SYNAPTICS_SYSCTL_WEIGHT_LEN_SQUARED =	SYN_OFFSET(weight_len_squared),
513
	SYNAPTICS_SYSCTL_DIV_MIN =		SYN_OFFSET(div_min),
514
	SYNAPTICS_SYSCTL_DIV_MAX =		SYN_OFFSET(div_max),
515
	SYNAPTICS_SYSCTL_DIV_MAX_NA =		SYN_OFFSET(div_max_na),
516
	SYNAPTICS_SYSCTL_DIV_LEN =		SYN_OFFSET(div_len),
517
	SYNAPTICS_SYSCTL_TAP_MAX_DELTA =	SYN_OFFSET(tap_max_delta),
518
	SYNAPTICS_SYSCTL_TAP_MIN_QUEUE =	SYN_OFFSET(tap_min_queue),
519
	SYNAPTICS_SYSCTL_TAPHOLD_TIMEOUT =	SYN_OFFSET(taphold_timeout),
520
	SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA =	SYN_OFFSET(vscroll_hor_area),
521
	SYNAPTICS_SYSCTL_VSCROLL_VER_AREA =	SYN_OFFSET(vscroll_ver_area),
522
	SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA =	SYN_OFFSET(vscroll_min_delta),
523
	SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN =	SYN_OFFSET(vscroll_div_min),
524
	SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX =	SYN_OFFSET(vscroll_div_max),
525
	SYNAPTICS_SYSCTL_TOUCHPAD_OFF =		SYN_OFFSET(touchpad_off),
526
	SYNAPTICS_SYSCTL_SOFTBUTTONS_Y =	SYN_OFFSET(softbuttons_y),
527
	SYNAPTICS_SYSCTL_SOFTBUTTON2_X =	SYN_OFFSET(softbutton2_x),
528
	SYNAPTICS_SYSCTL_SOFTBUTTON3_X =	SYN_OFFSET(softbutton3_x),
529
};
530
414
/* packet formatting function */
531
/* packet formatting function */
415
typedef int	packetfunc_t(struct psm_softc *, u_char *, int *, int,
532
typedef int	packetfunc_t(struct psm_softc *, u_char *, int *, int,
416
    mousestatus_t *);
533
    mousestatus_t *);
Lines 446-451 static int doopen(struct psm_softc *, int); Link Here
446
static int	reinitialize(struct psm_softc *, int);
563
static int	reinitialize(struct psm_softc *, int);
447
static char	*model_name(int);
564
static char	*model_name(int);
448
static void	psmsoftintr(void *);
565
static void	psmsoftintr(void *);
566
static void	psmsoftintridle(void *);
449
static void	psmintr(void *);
567
static void	psmintr(void *);
450
static void	psmtimeout(void *);
568
static void	psmtimeout(void *);
451
static int	timeelapsed(const struct timeval *, int, int,
569
static int	timeelapsed(const struct timeval *, int, int,
Lines 458-463 static int proc_synaptics(struct psm_softc *, packetbuf_t *, Link Here
458
		    mousestatus_t *, int *, int *, int *);
576
		    mousestatus_t *, int *, int *, int *);
459
static void	proc_versapad(struct psm_softc *, packetbuf_t *,
577
static void	proc_versapad(struct psm_softc *, packetbuf_t *,
460
		    mousestatus_t *, int *, int *, int *);
578
		    mousestatus_t *, int *, int *, int *);
579
static int	proc_elantech(struct psm_softc *, packetbuf_t *,
580
		    mousestatus_t *, int *, int *, int *);
581
static int	psmpalmdetect(struct psm_softc *, finger_t *, int);
582
static void	psmgestures(struct psm_softc *, finger_t *, int,
583
		    mousestatus_t *);
584
static void	psmsmoother(struct psm_softc *, finger_t *, int,
585
		    mousestatus_t *, int *, int *);
461
static int	tame_mouse(struct psm_softc *, packetbuf_t *, mousestatus_t *,
586
static int	tame_mouse(struct psm_softc *, packetbuf_t *, mousestatus_t *,
462
		    u_char *);
587
		    u_char *);
463
588
Lines 480-485 static probefunc_t enable_mmanplus; Link Here
480
static probefunc_t	enable_synaptics;
605
static probefunc_t	enable_synaptics;
481
static probefunc_t	enable_trackpoint;
606
static probefunc_t	enable_trackpoint;
482
static probefunc_t	enable_versapad;
607
static probefunc_t	enable_versapad;
608
static probefunc_t	enable_elantech;
483
609
484
static void set_trackpoint_parameters(struct psm_softc *sc);
610
static void set_trackpoint_parameters(struct psm_softc *sc);
485
static void synaptics_passthrough_on(struct psm_softc *sc);
611
static void synaptics_passthrough_on(struct psm_softc *sc);
Lines 511-516 static struct { Link Here
511
	  0xc8, MOUSE_4DPLUS_PACKETSIZE, enable_4dplus },
637
	  0xc8, MOUSE_4DPLUS_PACKETSIZE, enable_4dplus },
512
	{ MOUSE_MODEL_SYNAPTICS,	/* Synaptics Touchpad */
638
	{ MOUSE_MODEL_SYNAPTICS,	/* Synaptics Touchpad */
513
	  0xc0, MOUSE_SYNAPTICS_PACKETSIZE, enable_synaptics },
639
	  0xc0, MOUSE_SYNAPTICS_PACKETSIZE, enable_synaptics },
640
	{ MOUSE_MODEL_ELANTECH,		/* Elantech Touchpad */
641
	  0x04, MOUSE_ELANTECH_PACKETSIZE, enable_elantech },
514
	{ MOUSE_MODEL_INTELLI,		/* Microsoft IntelliMouse */
642
	{ MOUSE_MODEL_INTELLI,		/* Microsoft IntelliMouse */
515
	  0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_msintelli },
643
	  0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_msintelli },
516
	{ MOUSE_MODEL_GLIDEPOINT,	/* ALPS GlidePoint */
644
	{ MOUSE_MODEL_GLIDEPOINT,	/* ALPS GlidePoint */
Lines 762-767 model_name(int model) Link Here
762
		{ MOUSE_MODEL_4DPLUS,		"4D+ Mouse" },
890
		{ MOUSE_MODEL_4DPLUS,		"4D+ Mouse" },
763
		{ MOUSE_MODEL_SYNAPTICS,	"Synaptics Touchpad" },
891
		{ MOUSE_MODEL_SYNAPTICS,	"Synaptics Touchpad" },
764
		{ MOUSE_MODEL_TRACKPOINT,	"IBM/Lenovo TrackPoint" },
892
		{ MOUSE_MODEL_TRACKPOINT,	"IBM/Lenovo TrackPoint" },
893
		{ MOUSE_MODEL_ELANTECH,		"Elantech Touchpad" },
765
		{ MOUSE_MODEL_GENERIC,		"Generic PS/2 mouse" },
894
		{ MOUSE_MODEL_GENERIC,		"Generic PS/2 mouse" },
766
		{ MOUSE_MODEL_UNKNOWN,		"Unknown" },
895
		{ MOUSE_MODEL_UNKNOWN,		"Unknown" },
767
	};
896
	};
Lines 1504-1509 psmattach(device_t dev) Link Here
1504
	case MOUSE_MODEL_SYNAPTICS:
1633
	case MOUSE_MODEL_SYNAPTICS:
1505
	case MOUSE_MODEL_GLIDEPOINT:
1634
	case MOUSE_MODEL_GLIDEPOINT:
1506
	case MOUSE_MODEL_VERSAPAD:
1635
	case MOUSE_MODEL_VERSAPAD:
1636
	case MOUSE_MODEL_ELANTECH:
1507
		sc->config |= PSM_CONFIG_INITAFTERSUSPEND;
1637
		sc->config |= PSM_CONFIG_INITAFTERSUSPEND;
1508
		break;
1638
		break;
1509
	default:
1639
	default:
Lines 1512-1517 psmattach(device_t dev) Link Here
1512
		break;
1642
		break;
1513
	}
1643
	}
1514
1644
1645
	/* Elantech trackpad`s sync bit differs from touchpad`s one */
1646
	if (sc->hw.model == MOUSE_MODEL_ELANTECH &&
1647
	    (sc->elanhw.hascrc || sc->elanhw.hastrackpad))
1648
		sc->config |= PSM_CONFIG_NOCHECKSYNC;
1649
1515
	if (!verbose)
1650
	if (!verbose)
1516
		printf("psm%d: model %s, device ID %d\n",
1651
		printf("psm%d: model %s, device ID %d\n",
1517
		    unit, model_name(sc->hw.model), sc->hw.hwid & 0x00ff);
1652
		    unit, model_name(sc->hw.model), sc->hw.hwid & 0x00ff);
Lines 2165-2184 psmioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, Link Here
2165
		    (*(int *)addr > PSM_LEVEL_MAX))
2300
		    (*(int *)addr > PSM_LEVEL_MAX))
2166
			return (EINVAL);
2301
			return (EINVAL);
2167
		sc->mode.level = *(int *)addr;
2302
		sc->mode.level = *(int *)addr;
2168
2169
		if (sc->hw.model == MOUSE_MODEL_SYNAPTICS) {
2170
			/*
2171
			 * If we are entering PSM_LEVEL_NATIVE, we want to
2172
			 * enable sending of "extended W mode" packets to
2173
			 * userland. Reset the mode of the touchpad so that the
2174
			 * change in the level is picked up.
2175
			 */
2176
			error = block_mouse_data(sc, &command_byte);
2177
			if (error)
2178
				return (error);
2179
			synaptics_set_mode(sc, synaptics_preferred_mode(sc));
2180
			unblock_mouse_data(sc, command_byte);
2181
		}
2182
		break;
2303
		break;
2183
2304
2184
	case MOUSE_GETSTATUS:
2305
	case MOUSE_GETSTATUS:
Lines 2627-2633 proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms, Link Here
2627
{
2748
{
2628
	static int touchpad_buttons;
2749
	static int touchpad_buttons;
2629
	static int guest_buttons;
2750
	static int guest_buttons;
2630
	int w, x0, y0;
2751
	static finger_t f[PSM_FINGERS];
2752
	int w, id, nfingers, ewcode;
2631
2753
2632
	/* TouchPad PS/2 absolute mode message format with capFourButtons:
2754
	/* TouchPad PS/2 absolute mode message format with capFourButtons:
2633
	 *
2755
	 *
Lines 2683-2688 proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms, Link Here
2683
		return (-1);
2805
		return (-1);
2684
2806
2685
	*x = *y = 0;
2807
	*x = *y = 0;
2808
	ms->button = ms->obutton;
2686
2809
2687
	/*
2810
	/*
2688
	 * Pressure value.
2811
	 * Pressure value.
Lines 2718-2751 proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms, Link Here
2718
		w = 4;
2841
		w = 4;
2719
	}
2842
	}
2720
2843
2721
	/*
2844
	switch (w) {
2722
	 * Handle packets from the guest device. See:
2845
	case 3:
2723
	 * Synaptics PS/2 TouchPad Interfacing Guide, Section 5.1
2846
		/*
2724
	 */
2847
		 * Handle packets from the guest device. See:
2725
	if (w == 3 && sc->synhw.capPassthrough) {
2848
		 * Synaptics PS/2 TouchPad Interfacing Guide, Section 5.1
2726
		*x = ((pb->ipacket[1] & 0x10) ?
2849
		 */
2727
		    pb->ipacket[4] - 256 : pb->ipacket[4]);
2850
		if (sc->synhw.capPassthrough) {
2728
		*y = ((pb->ipacket[1] & 0x20) ?
2851
			*x = ((pb->ipacket[1] & 0x10) ?
2729
		    pb->ipacket[5] - 256 : pb->ipacket[5]);
2852
			    pb->ipacket[4] - 256 : pb->ipacket[4]);
2730
		*z = 0;
2853
			*y = ((pb->ipacket[1] & 0x20) ?
2731
2854
			    pb->ipacket[5] - 256 : pb->ipacket[5]);
2732
		guest_buttons = 0;
2855
			*z = 0;
2733
		if (pb->ipacket[1] & 0x01)
2856
2734
			guest_buttons |= MOUSE_BUTTON1DOWN;
2857
			guest_buttons = 0;
2735
		if (pb->ipacket[1] & 0x04)
2858
			if (pb->ipacket[1] & 0x01)
2736
			guest_buttons |= MOUSE_BUTTON2DOWN;
2859
				guest_buttons |= MOUSE_BUTTON1DOWN;
2737
		if (pb->ipacket[1] & 0x02)
2860
			if (pb->ipacket[1] & 0x04)
2738
			guest_buttons |= MOUSE_BUTTON3DOWN;
2861
				guest_buttons |= MOUSE_BUTTON2DOWN;
2862
				if (pb->ipacket[1] & 0x02)
2863
				guest_buttons |= MOUSE_BUTTON3DOWN;
2864
2865
			ms->button = touchpad_buttons | guest_buttons;
2866
		}
2867
		goto SYNAPTICS_END;
2739
2868
2740
		ms->button = touchpad_buttons | guest_buttons;
2869
	case 2:
2870
		/* Handle Extended W mode packets */
2871
		ewcode = (pb->ipacket[5] & 0xf0) >> 4;
2872
#if PSM_FINGERS > 1
2873
		switch (ewcode) {
2874
		case 1:
2875
			/* Secondary finger */
2876
			if (sc->synhw.capAdvancedGestures)
2877
				f[1] = (finger_t) {
2878
					.x = (((pb->ipacket[4] & 0x0f) << 8) |
2879
					    pb->ipacket[1]) << 1,
2880
					.y = (((pb->ipacket[4] & 0xf0) << 4) |
2881
					    pb->ipacket[2]) << 1,
2882
					.p = ((pb->ipacket[3] & 0x30) |
2883
					    (pb->ipacket[5] & 0x0f)) << 1,
2884
					.w = PSM_FINGER_DEFAULT_W,
2885
					.flags = PSM_FINGER_FUZZY,
2886
				};
2887
			else if (sc->synhw.capReportsV)
2888
				f[1] = (finger_t) {
2889
					.x = (((pb->ipacket[4] & 0x0f) << 8) |
2890
					    (pb->ipacket[1] & 0xfe)) << 1,
2891
					.y = (((pb->ipacket[4] & 0xf0) << 4) |
2892
					    (pb->ipacket[2] & 0xfe)) << 1,
2893
					.p = ((pb->ipacket[3] & 0x30) |
2894
					    (pb->ipacket[5] & 0x0e)) << 1,
2895
					.w = (((pb->ipacket[5] & 0x01) << 2) |
2896
					    ((pb->ipacket[2] & 0x01) << 1) |
2897
					    (pb->ipacket[1] & 0x01)) + 8,
2898
					.flags = PSM_FINGER_FUZZY,
2899
				};
2900
		default:
2901
			break;
2902
		}
2903
#endif
2741
		goto SYNAPTICS_END;
2904
		goto SYNAPTICS_END;
2905
2906
	case 1:
2907
	case 0:
2908
		nfingers = w + 2;
2909
		break;
2910
2911
	default:
2912
		nfingers = 1;
2742
	}
2913
	}
2743
2914
2744
	if (sc->syninfo.touchpad_off) {
2915
	if (sc->syninfo.touchpad_off)
2745
		*x = *y = *z = 0;
2746
		ms->button = ms->obutton;
2747
		goto SYNAPTICS_END;
2916
		goto SYNAPTICS_END;
2748
	}
2749
2917
2750
	/* Button presses */
2918
	/* Button presses */
2751
	touchpad_buttons = 0;
2919
	touchpad_buttons = 0;
Lines 2764-2769 proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms, Link Here
2764
		/* Middle Button */
2932
		/* Middle Button */
2765
		if ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x01)
2933
		if ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x01)
2766
			touchpad_buttons |= MOUSE_BUTTON2DOWN;
2934
			touchpad_buttons |= MOUSE_BUTTON2DOWN;
2935
	} else if (sc->synhw.capExtended && sc->synhw.capClickPad) {
2936
		/* ClickPad Button */
2937
		if ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x01)
2938
			touchpad_buttons = MOUSE_BUTTON1DOWN;
2767
	} else if (sc->synhw.capExtended && (sc->synhw.nExtendedButtons > 0)) {
2939
	} else if (sc->synhw.capExtended && (sc->synhw.nExtendedButtons > 0)) {
2768
		/* Extended Buttons */
2940
		/* Extended Buttons */
2769
		if ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x02) {
2941
		if ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x02) {
Lines 2806-2812 proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms, Link Here
2806
			pb->ipacket[4] &= ~(mask);
2978
			pb->ipacket[4] &= ~(mask);
2807
			pb->ipacket[5] &= ~(mask);
2979
			pb->ipacket[5] &= ~(mask);
2808
		} else	if (!sc->syninfo.directional_scrolls &&
2980
		} else	if (!sc->syninfo.directional_scrolls &&
2809
		    !sc->synaction.in_vscroll) {
2981
		    !sc->gesture.in_vscroll) {
2810
			/*
2982
			/*
2811
			 * Keep reporting MOUSE DOWN until we get a new packet
2983
			 * Keep reporting MOUSE DOWN until we get a new packet
2812
			 * indicating otherwise.
2984
			 * indicating otherwise.
Lines 2814-2906 proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms, Link Here
2814
			touchpad_buttons |= sc->extended_buttons;
2986
			touchpad_buttons |= sc->extended_buttons;
2815
		}
2987
		}
2816
	}
2988
	}
2817
	/* Handle ClickPad. */
2989
2818
	if (sc->synhw.capClickPad &&
2990
	if (sc->synhw.capReportsV && nfingers > 1)
2819
	    ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x01))
2991
		f[0] = (finger_t) {
2820
		touchpad_buttons |= MOUSE_BUTTON1DOWN;
2992
			.x = ((pb->ipacket[3] & 0x10) << 8) |
2993
			    ((pb->ipacket[1] & 0x0f) << 8) |
2994
			    (pb->ipacket[4] & 0xfd),
2995
			.y = ((pb->ipacket[3] & 0x20) << 7) |
2996
			    ((pb->ipacket[1] & 0xf0) << 4) |
2997
			    (pb->ipacket[5] & 0xfd),
2998
			.p = *z & 0xfe,
2999
			.w = (((pb->ipacket[2] & 0x01) << 2) |
3000
			    (pb->ipacket[5] & 0x02) |
3001
			    ((pb->ipacket[4] & 0x02) >> 1)) + 8,
3002
			.flags = PSM_FINGER_FUZZY,
3003
		};
3004
	else
3005
		f[0] = (finger_t) {
3006
			.x = ((pb->ipacket[3] & 0x10) << 8) |
3007
			    ((pb->ipacket[1] & 0x0f) << 8) |
3008
			    pb->ipacket[4],
3009
			.y = ((pb->ipacket[3] & 0x20) << 7) |
3010
			    ((pb->ipacket[1] & 0xf0) << 4) |
3011
			    pb->ipacket[5],
3012
			.p = *z,
3013
			.w = w,
3014
			.flags = nfingers > 1 ? PSM_FINGER_FUZZY : 0,
3015
		};
3016
3017
	/* Ignore hovering and unmeasurable touches */
3018
	if (f[0].p < sc->syninfo.min_pressure || f[0].x < 2)
3019
		nfingers = 0;
3020
3021
	for (id = 0; id < PSM_FINGERS; id++)
3022
		if (id >= nfingers)
3023
			PSM_FINGER_RESET(f[id]);
2821
3024
2822
	ms->button = touchpad_buttons | guest_buttons;
3025
	ms->button = touchpad_buttons | guest_buttons;
2823
3026
3027
	/* Palm detection doesn't terminate the current action. */
3028
	if (!psmpalmdetect(sc, &f[0], nfingers)) {
3029
		psmgestures(sc, &f[0], nfingers, ms);
3030
		for (id = 0; id < PSM_FINGERS; id++)
3031
			psmsmoother(sc, &f[id], id, ms, x, y);
3032
	} else {
3033
		VLOG(2, (LOG_DEBUG, "synaptics: palm detected! (%d)\n", f[0].w));
3034
	}
3035
3036
SYNAPTICS_END:
3037
	/*
3038
	 * Use the extra buttons as a scrollwheel
3039
	 *
3040
	 * XXX X.Org uses the Z axis for vertical wheel only,
3041
	 * whereas moused(8) understands special values to differ
3042
	 * vertical and horizontal wheels.
3043
	 *
3044
	 * xf86-input-mouse needs therefore a small patch to
3045
	 * understand these special values. Without it, the
3046
	 * horizontal wheel acts as a vertical wheel in X.Org.
3047
	 *
3048
	 * That's why the horizontal wheel is disabled by
3049
	 * default for now.
3050
	 */
3051
	if (ms->button & MOUSE_BUTTON4DOWN)
3052
		*z = -1;
3053
	else if (ms->button & MOUSE_BUTTON5DOWN)
3054
		*z = 1;
3055
	else if (ms->button & MOUSE_BUTTON6DOWN)
3056
		*z = -2;
3057
	else if (ms->button & MOUSE_BUTTON7DOWN)
3058
		*z = 2;
3059
	else
3060
		*z = 0;
3061
	ms->button &= ~(MOUSE_BUTTON4DOWN | MOUSE_BUTTON5DOWN |
3062
	    MOUSE_BUTTON6DOWN | MOUSE_BUTTON7DOWN);
3063
3064
	return (0);
3065
}
3066
3067
static int
3068
psmpalmdetect(struct psm_softc *sc, finger_t *f, int nfingers)
3069
{
3070
	if (!(
3071
	    ((sc->synhw.capMultiFinger ||
3072
	      sc->synhw.capAdvancedGestures) && nfingers > 1) ||
3073
	    (sc->synhw.capPalmDetect && f->w <= sc->syninfo.max_width) ||
3074
	    (!sc->synhw.capPalmDetect && f->p <= sc->syninfo.max_pressure) ||
3075
	    (sc->synhw.capPen && f->flags & PSM_FINGER_IS_PEN))) {
3076
		/*
3077
		 * We consider the packet irrelevant for the current
3078
		 * action when:
3079
		 *  - the width isn't comprised in:
3080
		 *    [1; max_width]
3081
		 *  - the pressure isn't comprised in:
3082
		 *    [min_pressure; max_pressure]
3083
		 *  - pen aren't supported but PSM_FINGER_IS_PEN is set
3084
		 */
3085
		return (1);
3086
	}
3087
	return (0);
3088
}
3089
3090
static void
3091
psmgestures(struct psm_softc *sc, finger_t *fingers, int nfingers,
3092
    mousestatus_t *ms)
3093
{
3094
	smoother_t *smoother;
3095
	gesture_t *gest;
3096
	finger_t *f;
3097
	int y_ok, center_button, center_x, right_button, right_x, i;
3098
3099
	f = &fingers[0];
3100
	smoother = &sc->smoother[0];
3101
	gest = &sc->gesture;
3102
3103
	/* Find first active finger. */
3104
	if (nfingers > 0) {
3105
		for (i = 0; i < PSM_FINGERS; i++) {
3106
			if (PSM_FINGER_IS_SET(fingers[i])) {
3107
				f = &fingers[i];
3108
				smoother = &sc->smoother[i];
3109
				break;
3110
			}
3111
		}
3112
	}
3113
2824
	/*
3114
	/*
2825
	 * Check pressure to detect a real wanted action on the
3115
	 * Check pressure to detect a real wanted action on the
2826
	 * touchpad.
3116
	 * touchpad.
2827
	 */
3117
	 */
2828
	if (*z >= sc->syninfo.min_pressure) {
3118
	if (f->p >= sc->syninfo.min_pressure) {
2829
		synapticsaction_t *synaction;
3119
		int x0, y0;
2830
		int cursor, peer, window;
3120
		int dxp, dyp;
2831
		int dx, dy, dxp, dyp;
3121
		int queue_len;
2832
		int max_width, max_pressure;
2833
		int margin_top, margin_right, margin_bottom, margin_left;
3122
		int margin_top, margin_right, margin_bottom, margin_left;
2834
		int na_top, na_right, na_bottom, na_left;
2835
		int window_min, window_max;
3123
		int window_min, window_max;
2836
		int multiplicator;
2837
		int weight_current, weight_previous, weight_len_squared;
2838
		int div_min, div_max, div_len;
2839
		int vscroll_hor_area, vscroll_ver_area;
3124
		int vscroll_hor_area, vscroll_ver_area;
2840
		int two_finger_scroll;
3125
		int two_finger_scroll;
2841
		int len, weight_prev_x, weight_prev_y;
3126
		int max_x, max_y;
2842
		int div_max_x, div_max_y, div_x, div_y;
2843
		int exiting_scroll;
2844
3127
2845
		/* Read sysctl. */
3128
		/* Read sysctl. */
2846
		/* XXX Verify values? */
3129
		/* XXX Verify values? */
2847
		max_width = sc->syninfo.max_width;
2848
		max_pressure = sc->syninfo.max_pressure;
2849
		margin_top = sc->syninfo.margin_top;
3130
		margin_top = sc->syninfo.margin_top;
2850
		margin_right = sc->syninfo.margin_right;
3131
		margin_right = sc->syninfo.margin_right;
2851
		margin_bottom = sc->syninfo.margin_bottom;
3132
		margin_bottom = sc->syninfo.margin_bottom;
2852
		margin_left = sc->syninfo.margin_left;
3133
		margin_left = sc->syninfo.margin_left;
2853
		na_top = sc->syninfo.na_top;
2854
		na_right = sc->syninfo.na_right;
2855
		na_bottom = sc->syninfo.na_bottom;
2856
		na_left = sc->syninfo.na_left;
2857
		window_min = sc->syninfo.window_min;
3134
		window_min = sc->syninfo.window_min;
2858
		window_max = sc->syninfo.window_max;
3135
		window_max = sc->syninfo.window_max;
2859
		multiplicator = sc->syninfo.multiplicator;
2860
		weight_current = sc->syninfo.weight_current;
2861
		weight_previous = sc->syninfo.weight_previous;
2862
		weight_len_squared = sc->syninfo.weight_len_squared;
2863
		div_min = sc->syninfo.div_min;
2864
		div_max = sc->syninfo.div_max;
2865
		div_len = sc->syninfo.div_len;
2866
		vscroll_hor_area = sc->syninfo.vscroll_hor_area;
3136
		vscroll_hor_area = sc->syninfo.vscroll_hor_area;
2867
		vscroll_ver_area = sc->syninfo.vscroll_ver_area;
3137
		vscroll_ver_area = sc->syninfo.vscroll_ver_area;
2868
		two_finger_scroll = sc->syninfo.two_finger_scroll;
3138
		two_finger_scroll = sc->syninfo.two_finger_scroll;
2869
3139
		max_x = sc->syninfo.max_x;
2870
		exiting_scroll = 0;
3140
		max_y = sc->syninfo.max_y;
2871
2872
		/* Palm detection. */
2873
		if (!(
2874
		    ((sc->synhw.capMultiFinger ||
2875
		      sc->synhw.capAdvancedGestures) && (w == 0 || w == 1)) ||
2876
		    (sc->synhw.capPalmDetect && w >= 4 && w <= max_width) ||
2877
		    (!sc->synhw.capPalmDetect && *z <= max_pressure) ||
2878
		    (sc->synhw.capPen && w == 2))) {
2879
			/*
2880
			 * We consider the packet irrelevant for the current
2881
			 * action when:
2882
			 *  - the width isn't comprised in:
2883
			 *    [4; max_width]
2884
			 *  - the pressure isn't comprised in:
2885
			 *    [min_pressure; max_pressure]
2886
			 *  - pen aren't supported but w is 2
2887
			 *
2888
			 *  Note that this doesn't terminate the current action.
2889
			 */
2890
			VLOG(2, (LOG_DEBUG,
2891
			    "synaptics: palm detected! (%d)\n", w));
2892
			goto SYNAPTICS_END;
2893
		}
2894
3141
2895
		/* Read current absolute position. */
3142
		/* Read current absolute position. */
2896
		x0 = ((pb->ipacket[3] & 0x10) << 8) |
3143
		x0 = f->x;
2897
		    ((pb->ipacket[1] & 0x0f) << 8) |
3144
		y0 = f->y;
2898
		    pb->ipacket[4];
3145
2899
		y0 = ((pb->ipacket[3] & 0x20) << 7) |
3146
		/*
2900
		    ((pb->ipacket[1] & 0xf0) << 4) |
3147
		 * Limit the coordinates to the specified margins because
2901
		    pb->ipacket[5];
3148
		 * this area isn't very reliable.
3149
		 */
3150
		if (x0 <= margin_left)
3151
			x0 = margin_left;
3152
		else if (x0 >= max_x - margin_right)
3153
			x0 = max_x - margin_right;
3154
		if (y0 <= margin_bottom)
3155
			y0 = margin_bottom;
3156
		else if (y0 >= max_y - margin_top)
3157
			y0 = max_y - margin_top;
2902
3158
2903
		synaction = &(sc->synaction);
3159
		VLOG(3, (LOG_DEBUG, "synaptics: ipacket: [%d, %d], %d, %d\n",
3160
		    x0, y0, f->p, f->w));
2904
3161
2905
		/*
3162
		/*
2906
		 * If the action is just beginning, init the structure and
3163
		 * If the action is just beginning, init the structure and
Lines 2909-3015 proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms, Link Here
2909
		if (!(sc->flags & PSM_FLAGS_FINGERDOWN)) {
3166
		if (!(sc->flags & PSM_FLAGS_FINGERDOWN)) {
2910
			VLOG(3, (LOG_DEBUG, "synaptics: ----\n"));
3167
			VLOG(3, (LOG_DEBUG, "synaptics: ----\n"));
2911
3168
2912
			/* Store the first point of this action. */
2913
			synaction->start_x = x0;
2914
			synaction->start_y = y0;
2915
			dx = dy = 0;
2916
2917
			/* Initialize queue. */
3169
			/* Initialize queue. */
2918
			synaction->queue_cursor = SYNAPTICS_PACKETQUEUE;
3170
			gest->window_min = window_min;
2919
			synaction->queue_len = 0;
2920
			synaction->window_min = window_min;
2921
2922
			/* Reset average. */
2923
			synaction->avg_dx = 0;
2924
			synaction->avg_dy = 0;
2925
2926
			/* Reset squelch. */
2927
			synaction->squelch_x = 0;
2928
			synaction->squelch_y = 0;
2929
3171
2930
			/* Reset pressure peak. */
3172
			/* Reset pressure peak. */
2931
			sc->zmax = 0;
3173
			gest->zmax = 0;
2932
3174
2933
			/* Reset fingers count. */
3175
			/* Reset fingers count. */
2934
			synaction->fingers_nb = 0;
3176
			gest->fingers_nb = 0;
2935
3177
2936
			/* Reset virtual scrolling state. */
3178
			/* Reset virtual scrolling state. */
2937
			synaction->in_vscroll = 0;
3179
			gest->in_vscroll = 0;
2938
3180
2939
			/* Compute tap timeout. */
3181
			/* Compute tap timeout. */
2940
			sc->taptimeout.tv_sec  = tap_timeout / 1000000;
3182
			gest->taptimeout.tv_sec  = tap_timeout / 1000000;
2941
			sc->taptimeout.tv_usec = tap_timeout % 1000000;
3183
			gest->taptimeout.tv_usec = tap_timeout % 1000000;
2942
			timevaladd(&sc->taptimeout, &sc->lastsoftintr);
3184
			timevaladd(&gest->taptimeout, &sc->lastsoftintr);
2943
3185
2944
			sc->flags |= PSM_FLAGS_FINGERDOWN;
3186
			sc->flags |= PSM_FLAGS_FINGERDOWN;
2945
		} else {
2946
			/* Calculate the current delta. */
2947
			cursor = synaction->queue_cursor;
2948
			dx = x0 - synaction->queue[cursor].x;
2949
			dy = y0 - synaction->queue[cursor].y;
2950
		}
2951
3187
2952
		/* If in tap-hold, add the recorded button. */
3188
			/* Smoother has not been reset yet */
2953
		if (synaction->in_taphold)
3189
			queue_len = 1;
2954
			ms->button |= synaction->tap_button;
3190
		} else
3191
			queue_len = smoother->queue_len + 1;
2955
3192
2956
		/*
2957
		 * From now on, we can use the SYNAPTICS_END label to skip
2958
		 * the current packet.
2959
		 */
2960
3193
2961
		/*
3194
		/* Process ClickPad softbuttons */
2962
		 * Limit the coordinates to the specified margins because
3195
		if (sc->synhw.capClickPad && ms->button & MOUSE_BUTTON1DOWN) {
2963
		 * this area isn't very reliable.
3196
			y_ok = sc->syninfo.softbuttons_y >= 0 ?
2964
		 */
3197
			    f->y < sc->syninfo.softbuttons_y :
2965
		if (x0 <= margin_left)
3198
			    f->y > max_y - sc->syninfo.softbuttons_y;
2966
			x0 = margin_left;
2967
		else if (x0 >= 6143 - margin_right)
2968
			x0 = 6143 - margin_right;
2969
		if (y0 <= margin_bottom)
2970
			y0 = margin_bottom;
2971
		else if (y0 >= 6143 - margin_top)
2972
			y0 = 6143 - margin_top;
2973
3199
2974
		VLOG(3, (LOG_DEBUG, "synaptics: ipacket: [%d, %d], %d, %d\n",
3200
			center_button = MOUSE_BUTTON2DOWN;
2975
		    x0, y0, *z, w));
3201
			center_x = sc->syninfo.softbutton2_x;
3202
			right_button = MOUSE_BUTTON3DOWN;
3203
			right_x = sc->syninfo.softbutton3_x;
2976
3204
2977
		/* Queue this new packet. */
3205
			if (center_x > 0 && right_x > 0 && center_x > right_x) {
2978
		cursor = SYNAPTICS_QUEUE_CURSOR(synaction->queue_cursor - 1);
3206
				center_button = MOUSE_BUTTON3DOWN;
2979
		synaction->queue[cursor].x = x0;
3207
				center_x = sc->syninfo.softbutton3_x;
2980
		synaction->queue[cursor].y = y0;
3208
				right_button = MOUSE_BUTTON2DOWN;
2981
		synaction->queue_cursor = cursor;
3209
				right_x = sc->syninfo.softbutton2_x;
2982
		if (synaction->queue_len < SYNAPTICS_PACKETQUEUE)
3210
			}
2983
			synaction->queue_len++;
3211
2984
		VLOG(5, (LOG_DEBUG,
3212
			if (right_x > 0 && smoother->start_x > right_x && y_ok)
2985
		    "synaptics: cursor[%d]: x=%d, y=%d, dx=%d, dy=%d\n",
3213
				ms->button = (ms->button &
2986
		    cursor, x0, y0, dx, dy));
3214
				    ~MOUSE_BUTTON1DOWN) | right_button;
3215
			else if (center_x > 0 &&
3216
				 smoother->start_x > center_x && y_ok)
3217
				ms->button = (ms->button &
3218
				    ~MOUSE_BUTTON1DOWN) | center_button;
3219
		}
3220
3221
		/* If in tap-hold, add the recorded button. */
3222
		if (gest->in_taphold)
3223
			ms->button |= gest->tap_button;
2987
3224
2988
		/*
3225
		/*
2989
		 * For tap, we keep the maximum number of fingers and the
3226
		 * For tap, we keep the maximum number of fingers and the
2990
		 * pressure peak. Also with multiple fingers, we increase
3227
		 * pressure peak. Also with multiple fingers, we increase
2991
		 * the minimum window.
3228
		 * the minimum window.
2992
		 */
3229
		 */
2993
		switch (w) {
3230
		if (nfingers > 1)
2994
		case 1: /* Three or more fingers. */
3231
			gest->window_min = window_max;
2995
			synaction->fingers_nb = imax(3, synaction->fingers_nb);
3232
		gest->fingers_nb = imax(nfingers, gest->fingers_nb);
2996
			synaction->window_min = window_max;
3233
		gest->zmax = imax(f->p, gest->zmax);
2997
			break;
2998
		case 0: /* Two fingers. */
2999
			synaction->fingers_nb = imax(2, synaction->fingers_nb);
3000
			synaction->window_min = window_max;
3001
			break;
3002
		default: /* One finger or undetectable. */
3003
			synaction->fingers_nb = imax(1, synaction->fingers_nb);
3004
		}
3005
		sc->zmax = imax(*z, sc->zmax);
3006
3234
3007
		/* Do we have enough packets to consider this a movement? */
3235
		/* Do we have enough packets to consider this a gesture? */
3008
		if (synaction->queue_len < synaction->window_min)
3236
		if (queue_len < gest->window_min)
3009
			goto SYNAPTICS_END;
3237
			return;
3010
3238
3011
		/* Is a scrolling action occurring? */
3239
		/* Is a scrolling action occurring? */
3012
		if (!synaction->in_taphold && !synaction->in_vscroll) {
3240
		if (!gest->in_taphold && !ms->button &&
3241
		    (!gest->in_vscroll || two_finger_scroll)) {
3013
			/*
3242
			/*
3014
			 * A scrolling action must not conflict with a tap
3243
			 * A scrolling action must not conflict with a tap
3015
			 * action. Here are the conditions to consider a
3244
			 * action. Here are the conditions to consider a
Lines 3020-3031 proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms, Link Here
3020
			 *       first should be above a configurable minimum
3249
			 *       first should be above a configurable minimum
3021
			 *     . tap timed out
3250
			 *     . tap timed out
3022
			 */
3251
			 */
3023
			dxp = abs(synaction->queue[synaction->queue_cursor].x -
3252
			dxp = abs(x0 - smoother->start_x);
3024
			    synaction->start_x);
3253
			dyp = abs(y0 - smoother->start_y);
3025
			dyp = abs(synaction->queue[synaction->queue_cursor].y -
3026
			    synaction->start_y);
3027
3254
3028
			if (timevalcmp(&sc->lastsoftintr, &sc->taptimeout, >) ||
3255
			if (timevalcmp(&sc->lastsoftintr, &gest->taptimeout, >) ||
3029
			    dxp >= sc->syninfo.vscroll_min_delta ||
3256
			    dxp >= sc->syninfo.vscroll_min_delta ||
3030
			    dyp >= sc->syninfo.vscroll_min_delta) {
3257
			    dyp >= sc->syninfo.vscroll_min_delta) {
3031
				/*
3258
				/*
Lines 3034-3209 proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms, Link Here
3034
				 * as that keeps the maximum number of fingers.
3261
				 * as that keeps the maximum number of fingers.
3035
				 */
3262
				 */
3036
				if (two_finger_scroll) {
3263
				if (two_finger_scroll) {
3037
					if (w == 0) {
3264
					if (nfingers == 2) {
3038
						synaction->in_vscroll +=
3265
						gest->in_vscroll +=
3039
						    dyp ? 2 : 0;
3266
						    dyp ? 2 : 0;
3040
						synaction->in_vscroll +=
3267
						gest->in_vscroll +=
3041
						    dxp ? 1 : 0;
3268
						    dxp ? 1 : 0;
3042
					}
3269
					}
3043
				} else {
3270
				} else {
3044
					/* Check for horizontal scrolling. */
3271
					/* Check for horizontal scrolling. */
3045
					if ((vscroll_hor_area > 0 &&
3272
					if ((vscroll_hor_area > 0 &&
3046
					    synaction->start_y <=
3273
					    smoother->start_y <=
3047
					        vscroll_hor_area) ||
3274
					        vscroll_hor_area) ||
3048
					    (vscroll_hor_area < 0 &&
3275
					    (vscroll_hor_area < 0 &&
3049
					     synaction->start_y >=
3276
					     smoother->start_y >=
3050
					     6143 + vscroll_hor_area))
3277
					     max_y + vscroll_hor_area))
3051
						synaction->in_vscroll += 2;
3278
						gest->in_vscroll += 2;
3052
3279
3053
					/* Check for vertical scrolling. */
3280
					/* Check for vertical scrolling. */
3054
					if ((vscroll_ver_area > 0 &&
3281
					if ((vscroll_ver_area > 0 &&
3055
					    synaction->start_x <=
3282
					    smoother->start_x <=
3056
						vscroll_ver_area) ||
3283
						vscroll_ver_area) ||
3057
					    (vscroll_ver_area < 0 &&
3284
					    (vscroll_ver_area < 0 &&
3058
					     synaction->start_x >=
3285
					     smoother->start_x >=
3059
					     6143 + vscroll_ver_area))
3286
					     max_x + vscroll_ver_area))
3060
						synaction->in_vscroll += 1;
3287
						gest->in_vscroll += 1;
3061
				}
3288
				}
3062
3289
3063
				/* Avoid conflicts if area overlaps. */
3290
				/* Avoid conflicts if area overlaps. */
3064
				if (synaction->in_vscroll >= 3)
3291
				if (gest->in_vscroll >= 3)
3065
					synaction->in_vscroll =
3292
					gest->in_vscroll =
3066
					    (dxp > dyp) ? 2 : 1;
3293
					    (dxp > dyp) ? 2 : 1;
3067
			}
3294
			}
3068
		}
3295
		}
3069
		/*
3296
		/*
3070
		 * Reset two finger scrolling when the number of fingers
3297
		 * Reset two finger scrolling when the number of fingers
3071
		 * is different from two.
3298
		 * is different from two or any button is pressed.
3072
		 */
3299
		 */
3073
		if (two_finger_scroll && w != 0 && synaction->in_vscroll != 0) {
3300
		if (two_finger_scroll && gest->in_vscroll != 0 &&
3074
			synaction->in_vscroll = 0;
3301
		    (nfingers != 2 || ms->button))
3075
			exiting_scroll = 1;
3302
			gest->in_vscroll = 0;
3076
		}
3077
3303
3078
		VLOG(5, (LOG_DEBUG,
3304
		VLOG(5, (LOG_DEBUG,
3079
			"synaptics: virtual scrolling: %s "
3305
			"synaptics: virtual scrolling: %s "
3080
			"(direction=%d, dxp=%d, dyp=%d, fingers=%d)\n",
3306
			"(direction=%d, dxp=%d, dyp=%d, fingers=%d)\n",
3081
			synaction->in_vscroll ? "YES" : "NO",
3307
			gest->in_vscroll ? "YES" : "NO",
3082
			synaction->in_vscroll, dxp, dyp,
3308
			gest->in_vscroll, dxp, dyp,
3083
			synaction->fingers_nb));
3309
			gest->fingers_nb));
3084
3085
		weight_prev_x = weight_prev_y = weight_previous;
3086
		div_max_x = div_max_y = div_max;
3087
3088
		if (synaction->in_vscroll) {
3089
			/* Dividers are different with virtual scrolling. */
3090
			div_min = sc->syninfo.vscroll_div_min;
3091
			div_max_x = div_max_y = sc->syninfo.vscroll_div_max;
3092
		} else {
3093
			/*
3094
			 * There's a lot of noise in coordinates when
3095
			 * the finger is on the touchpad's borders. When
3096
			 * using this area, we apply a special weight and
3097
			 * div.
3098
			 */
3099
			if (x0 <= na_left || x0 >= 6143 - na_right) {
3100
				weight_prev_x = sc->syninfo.weight_previous_na;
3101
				div_max_x = sc->syninfo.div_max_na;
3102
			}
3103
3104
			if (y0 <= na_bottom || y0 >= 6143 - na_top) {
3105
				weight_prev_y = sc->syninfo.weight_previous_na;
3106
				div_max_y = sc->syninfo.div_max_na;
3107
			}
3108
		}
3109
3110
		/*
3111
		 * Calculate weights for the average operands and
3112
		 * the divisor. Both depend on the distance between
3113
		 * the current packet and a previous one (based on the
3114
		 * window width).
3115
		 */
3116
		window = imin(synaction->queue_len, window_max);
3117
		peer = SYNAPTICS_QUEUE_CURSOR(cursor + window - 1);
3118
		dxp = abs(x0 - synaction->queue[peer].x) + 1;
3119
		dyp = abs(y0 - synaction->queue[peer].y) + 1;
3120
		len = (dxp * dxp) + (dyp * dyp);
3121
		weight_prev_x = imin(weight_prev_x,
3122
		    weight_len_squared * weight_prev_x / len);
3123
		weight_prev_y = imin(weight_prev_y,
3124
		    weight_len_squared * weight_prev_y / len);
3125
3126
		len = (dxp + dyp) / 2;
3127
		div_x = div_len * div_max_x / len;
3128
		div_x = imin(div_max_x, div_x);
3129
		div_x = imax(div_min, div_x);
3130
		div_y = div_len * div_max_y / len;
3131
		div_y = imin(div_max_y, div_y);
3132
		div_y = imax(div_min, div_y);
3133
3134
		VLOG(3, (LOG_DEBUG,
3135
		    "synaptics: peer=%d, len=%d, weight=%d/%d, div=%d/%d\n",
3136
		    peer, len, weight_prev_x, weight_prev_y, div_x, div_y));
3137
3138
		/* Compute averages. */
3139
		synaction->avg_dx =
3140
		    (weight_current * dx * multiplicator +
3141
		     weight_prev_x * synaction->avg_dx) /
3142
		    (weight_current + weight_prev_x);
3143
3144
		synaction->avg_dy =
3145
		    (weight_current * dy * multiplicator +
3146
		     weight_prev_y * synaction->avg_dy) /
3147
		    (weight_current + weight_prev_y);
3148
3149
		VLOG(5, (LOG_DEBUG,
3150
		    "synaptics: avg_dx~=%d, avg_dy~=%d\n",
3151
		    synaction->avg_dx / multiplicator,
3152
		    synaction->avg_dy / multiplicator));
3153
3154
		/* Use these averages to calculate x & y. */
3155
		synaction->squelch_x += synaction->avg_dx;
3156
		*x = synaction->squelch_x / (div_x * multiplicator);
3157
		synaction->squelch_x = synaction->squelch_x %
3158
		    (div_x * multiplicator);
3159
3160
		synaction->squelch_y += synaction->avg_dy;
3161
		*y = synaction->squelch_y / (div_y * multiplicator);
3162
		synaction->squelch_y = synaction->squelch_y %
3163
		    (div_y * multiplicator);
3164
3165
		if (synaction->in_vscroll) {
3166
			switch(synaction->in_vscroll) {
3167
			case 1: /* Vertical scrolling. */
3168
				if (*y != 0)
3169
					ms->button |= (*y > 0) ?
3170
					    MOUSE_BUTTON4DOWN :
3171
					    MOUSE_BUTTON5DOWN;
3172
				break;
3173
			case 2: /* Horizontal scrolling. */
3174
				if (*x != 0)
3175
					ms->button |= (*x > 0) ?
3176
					    MOUSE_BUTTON7DOWN :
3177
					    MOUSE_BUTTON6DOWN;
3178
				break;
3179
			}
3180
3181
			/* The pointer is not moved. */
3182
			*x = *y = 0;
3183
		} else {
3184
			/* On exit the x/y pos may jump, ignore this */
3185
			if (exiting_scroll)
3186
				*x = *y = 0;
3187
3310
3188
			VLOG(3, (LOG_DEBUG, "synaptics: [%d, %d] -> [%d, %d]\n",
3189
			    dx, dy, *x, *y));
3190
		}
3191
	} else if (sc->flags & PSM_FLAGS_FINGERDOWN) {
3311
	} else if (sc->flags & PSM_FLAGS_FINGERDOWN) {
3192
		/*
3312
		/*
3193
		 * An action is currently taking place but the pressure
3313
		 * An action is currently taking place but the pressure
3194
		 * dropped under the minimum, putting an end to it.
3314
		 * dropped under the minimum, putting an end to it.
3195
		 */
3315
		 */
3196
		synapticsaction_t *synaction;
3197
		int taphold_timeout, dx, dy, tap_max_delta;
3316
		int taphold_timeout, dx, dy, tap_max_delta;
3198
3317
3199
		synaction = &(sc->synaction);
3318
		dx = abs(smoother->queue[smoother->queue_cursor].x -
3200
		dx = abs(synaction->queue[synaction->queue_cursor].x -
3319
		    smoother->start_x);
3201
		    synaction->start_x);
3320
		dy = abs(smoother->queue[smoother->queue_cursor].y -
3202
		dy = abs(synaction->queue[synaction->queue_cursor].y -
3321
		    smoother->start_y);
3203
		    synaction->start_y);
3204
3322
3205
		/* Max delta is disabled for multi-fingers tap. */
3323
		/* Max delta is disabled for multi-fingers tap. */
3206
		if (synaction->fingers_nb > 1)
3324
		if (gest->fingers_nb > 1)
3207
			tap_max_delta = imax(dx, dy);
3325
			tap_max_delta = imax(dx, dy);
3208
		else
3326
		else
3209
			tap_max_delta = sc->syninfo.tap_max_delta;
3327
			tap_max_delta = sc->syninfo.tap_max_delta;
Lines 3214-3225 proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms, Link Here
3214
		VLOG(3, (LOG_DEBUG,
3332
		VLOG(3, (LOG_DEBUG,
3215
		    "synaptics: zmax=%d, dx=%d, dy=%d, "
3333
		    "synaptics: zmax=%d, dx=%d, dy=%d, "
3216
		    "delta=%d, fingers=%d, queue=%d\n",
3334
		    "delta=%d, fingers=%d, queue=%d\n",
3217
		    sc->zmax, dx, dy, tap_max_delta, synaction->fingers_nb,
3335
		    gest->zmax, dx, dy, tap_max_delta, gest->fingers_nb,
3218
		    synaction->queue_len));
3336
		    smoother->queue_len));
3219
		if (!synaction->in_vscroll && sc->zmax >= tap_threshold &&
3337
		if (!gest->in_vscroll && gest->zmax >= tap_threshold &&
3220
		    timevalcmp(&sc->lastsoftintr, &sc->taptimeout, <=) &&
3338
		    timevalcmp(&sc->lastsoftintr, &gest->taptimeout, <=) &&
3221
		    dx <= tap_max_delta && dy <= tap_max_delta &&
3339
		    dx <= tap_max_delta && dy <= tap_max_delta &&
3222
		    synaction->queue_len >= sc->syninfo.tap_min_queue) {
3340
		    smoother->queue_len >= sc->syninfo.tap_min_queue) {
3223
			/*
3341
			/*
3224
			 * We have a tap if:
3342
			 * We have a tap if:
3225
			 *   - the maximum pressure went over tap_threshold
3343
			 *   - the maximum pressure went over tap_threshold
Lines 3228-3239 proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms, Link Here
3228
			 * To handle tap-hold, we must delay any button push to
3346
			 * To handle tap-hold, we must delay any button push to
3229
			 * the next action.
3347
			 * the next action.
3230
			 */
3348
			 */
3231
			if (synaction->in_taphold) {
3349
			if (gest->in_taphold) {
3232
				/*
3350
				/*
3233
				 * This is the second and last tap of a
3351
				 * This is the second and last tap of a
3234
				 * double tap action, not a tap-hold.
3352
				 * double tap action, not a tap-hold.
3235
				 */
3353
				 */
3236
				synaction->in_taphold = 0;
3354
				gest->in_taphold = 0;
3237
3355
3238
				/*
3356
				/*
3239
				 * For double-tap to work:
3357
				 * For double-tap to work:
Lines 3245-3346 proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms, Link Here
3245
				 */
3363
				 */
3246
				VLOG(2, (LOG_DEBUG,
3364
				VLOG(2, (LOG_DEBUG,
3247
				    "synaptics: button RELEASE: %d\n",
3365
				    "synaptics: button RELEASE: %d\n",
3248
				    synaction->tap_button));
3366
				    gest->tap_button));
3249
				sc->flags |= PSM_FLAGS_FINGERDOWN;
3367
				sc->flags |= PSM_FLAGS_FINGERDOWN;
3368
3369
				/* Schedule button press on next interrupt */
3370
				sc->idletimeout.tv_sec  = psmhz > 1 ?
3371
				    0 : 1;
3372
				sc->idletimeout.tv_usec = psmhz > 1 ?
3373
				    1000000 / psmhz : 0;
3250
			} else {
3374
			} else {
3251
				/*
3375
				/*
3252
				 * This is the first tap: we set the
3376
				 * This is the first tap: we set the
3253
				 * tap-hold state and notify the button
3377
				 * tap-hold state and notify the button
3254
				 * down event.
3378
				 * down event.
3255
				 */
3379
				 */
3256
				synaction->in_taphold = 1;
3380
				gest->in_taphold = 1;
3257
				taphold_timeout = sc->syninfo.taphold_timeout;
3381
				taphold_timeout = sc->syninfo.taphold_timeout;
3258
				sc->taptimeout.tv_sec  = taphold_timeout /
3382
				gest->taptimeout.tv_sec  = taphold_timeout /
3259
				    1000000;
3383
				    1000000;
3260
				sc->taptimeout.tv_usec = taphold_timeout %
3384
				gest->taptimeout.tv_usec = taphold_timeout %
3261
				    1000000;
3385
				    1000000;
3262
				timevaladd(&sc->taptimeout, &sc->lastsoftintr);
3386
				sc->idletimeout = gest->taptimeout;
3387
				timevaladd(&gest->taptimeout,
3388
				    &sc->lastsoftintr);
3263
3389
3264
				switch (synaction->fingers_nb) {
3390
				switch (gest->fingers_nb) {
3265
				case 3:
3391
				case 3:
3266
					synaction->tap_button =
3392
					gest->tap_button =
3267
					    MOUSE_BUTTON2DOWN;
3393
					    MOUSE_BUTTON2DOWN;
3268
					break;
3394
					break;
3269
				case 2:
3395
				case 2:
3270
					synaction->tap_button =
3396
					gest->tap_button =
3271
					    MOUSE_BUTTON3DOWN;
3397
					    MOUSE_BUTTON3DOWN;
3272
					break;
3398
					break;
3273
				default:
3399
				default:
3274
					synaction->tap_button =
3400
					gest->tap_button =
3275
					    MOUSE_BUTTON1DOWN;
3401
					    MOUSE_BUTTON1DOWN;
3276
				}
3402
				}
3277
				VLOG(2, (LOG_DEBUG,
3403
				VLOG(2, (LOG_DEBUG,
3278
				    "synaptics: button PRESS: %d\n",
3404
				    "synaptics: button PRESS: %d\n",
3279
				    synaction->tap_button));
3405
				    gest->tap_button));
3280
				ms->button |= synaction->tap_button;
3406
				ms->button |= gest->tap_button;
3281
			}
3407
			}
3282
		} else {
3408
		} else {
3283
			/*
3409
			/*
3284
			 * Not enough pressure or timeout: reset
3410
			 * Not enough pressure or timeout: reset
3285
			 * tap-hold state.
3411
			 * tap-hold state.
3286
			 */
3412
			 */
3287
			if (synaction->in_taphold) {
3413
			if (gest->in_taphold) {
3288
				VLOG(2, (LOG_DEBUG,
3414
				VLOG(2, (LOG_DEBUG,
3289
				    "synaptics: button RELEASE: %d\n",
3415
				    "synaptics: button RELEASE: %d\n",
3290
				    synaction->tap_button));
3416
				    gest->tap_button));
3291
				synaction->in_taphold = 0;
3417
				gest->in_taphold = 0;
3292
			} else {
3418
			} else {
3293
				VLOG(2, (LOG_DEBUG,
3419
				VLOG(2, (LOG_DEBUG,
3294
				    "synaptics: not a tap-hold\n"));
3420
				    "synaptics: not a tap-hold\n"));
3295
			}
3421
			}
3296
		}
3422
		}
3297
	} else if (!(sc->flags & PSM_FLAGS_FINGERDOWN) &&
3423
	} else if (!(sc->flags & PSM_FLAGS_FINGERDOWN) && gest->in_taphold) {
3298
	    sc->synaction.in_taphold) {
3299
		/*
3424
		/*
3300
		 * For a tap-hold to work, the button must remain down at
3425
		 * For a tap-hold to work, the button must remain down at
3301
		 * least until timeout (where the in_taphold flags will be
3426
		 * least until timeout (where the in_taphold flags will be
3302
		 * cleared) or during the next action.
3427
		 * cleared) or during the next action.
3303
		 */
3428
		 */
3304
		if (timevalcmp(&sc->lastsoftintr, &sc->taptimeout, <=)) {
3429
		if (timevalcmp(&sc->lastsoftintr, &gest->taptimeout, <=)) {
3305
			ms->button |= sc->synaction.tap_button;
3430
			ms->button |= gest->tap_button;
3306
		} else {
3431
		} else {
3307
			VLOG(2, (LOG_DEBUG,
3432
			VLOG(2, (LOG_DEBUG, "synaptics: button RELEASE: %d\n",
3308
			    "synaptics: button RELEASE: %d\n",
3433
			    gest->tap_button));
3309
			    sc->synaction.tap_button));
3434
			gest->in_taphold = 0;
3310
			sc->synaction.in_taphold = 0;
3311
		}
3435
		}
3312
	}
3436
	}
3313
3437
3314
SYNAPTICS_END:
3438
	return;
3315
	/*
3439
}
3316
	 * Use the extra buttons as a scrollwheel
3317
	 *
3318
	 * XXX X.Org uses the Z axis for vertical wheel only,
3319
	 * whereas moused(8) understands special values to differ
3320
	 * vertical and horizontal wheels.
3321
	 *
3322
	 * xf86-input-mouse needs therefore a small patch to
3323
	 * understand these special values. Without it, the
3324
	 * horizontal wheel acts as a vertical wheel in X.Org.
3325
	 *
3326
	 * That's why the horizontal wheel is disabled by
3327
	 * default for now.
3328
	 */
3329
3440
3330
	if (ms->button & MOUSE_BUTTON4DOWN) {
3441
static void
3331
		*z = -1;
3442
psmsmoother(struct psm_softc *sc, finger_t *f, int smoother_id,
3332
		ms->button &= ~MOUSE_BUTTON4DOWN;
3443
    mousestatus_t *ms, int *x, int *y)
3333
	} else if (ms->button & MOUSE_BUTTON5DOWN) {
3444
{
3334
		*z = 1;
3445
	smoother_t *smoother = &sc->smoother[smoother_id];
3335
		ms->button &= ~MOUSE_BUTTON5DOWN;
3446
	gesture_t *gest = &(sc->gesture);
3336
	} else if (ms->button & MOUSE_BUTTON6DOWN) {
3447
3337
		*z = -2;
3448
	/*
3338
		ms->button &= ~MOUSE_BUTTON6DOWN;
3449
	 * Check pressure to detect a real wanted action on the
3339
	} else if (ms->button & MOUSE_BUTTON7DOWN) {
3450
	 * touchpad.
3451
	 */
3452
	if (f->p >= sc->syninfo.min_pressure) {
3453
		int x0, y0;
3454
		int cursor, peer, window;
3455
		int dx, dy, dxp, dyp;
3456
		int max_width, max_pressure;
3457
		int margin_top, margin_right, margin_bottom, margin_left;
3458
		int na_top, na_right, na_bottom, na_left;
3459
		int window_min, window_max;
3460
		int multiplicator;
3461
		int weight_current, weight_previous, weight_len_squared;
3462
		int div_min, div_max, div_len;
3463
		int vscroll_hor_area, vscroll_ver_area;
3464
		int two_finger_scroll;
3465
		int max_x, max_y;
3466
		int len, weight_prev_x, weight_prev_y;
3467
		int div_max_x, div_max_y, div_x, div_y;
3468
		int is_fuzzy;
3469
3470
		/* Read sysctl. */
3471
		/* XXX Verify values? */
3472
		max_width = sc->syninfo.max_width;
3473
		max_pressure = sc->syninfo.max_pressure;
3474
		margin_top = sc->syninfo.margin_top;
3475
		margin_right = sc->syninfo.margin_right;
3476
		margin_bottom = sc->syninfo.margin_bottom;
3477
		margin_left = sc->syninfo.margin_left;
3478
		na_top = sc->syninfo.na_top;
3479
		na_right = sc->syninfo.na_right;
3480
		na_bottom = sc->syninfo.na_bottom;
3481
		na_left = sc->syninfo.na_left;
3482
		window_min = sc->syninfo.window_min;
3483
		window_max = sc->syninfo.window_max;
3484
		multiplicator = sc->syninfo.multiplicator;
3485
		weight_current = sc->syninfo.weight_current;
3486
		weight_previous = sc->syninfo.weight_previous;
3487
		weight_len_squared = sc->syninfo.weight_len_squared;
3488
		div_min = sc->syninfo.div_min;
3489
		div_max = sc->syninfo.div_max;
3490
		div_len = sc->syninfo.div_len;
3491
		vscroll_hor_area = sc->syninfo.vscroll_hor_area;
3492
		vscroll_ver_area = sc->syninfo.vscroll_ver_area;
3493
		two_finger_scroll = sc->syninfo.two_finger_scroll;
3494
		max_x = sc->syninfo.max_x;
3495
		max_y = sc->syninfo.max_y;
3496
3497
		is_fuzzy = (f->flags & PSM_FINGER_FUZZY) != 0;
3498
3499
		/* Read current absolute position. */
3500
		x0 = f->x;
3501
		y0 = f->y;
3502
3503
		/*
3504
		 * Limit the coordinates to the specified margins because
3505
		 * this area isn't very reliable.
3506
		 */
3507
		if (x0 <= margin_left)
3508
			x0 = margin_left;
3509
		else if (x0 >= max_x - margin_right)
3510
			x0 = max_x - margin_right;
3511
		if (y0 <= margin_bottom)
3512
			y0 = margin_bottom;
3513
		else if (y0 >= max_y - margin_top)
3514
			y0 = max_y - margin_top;
3515
3516
		/* If the action is just beginning, init the structure. */
3517
		if (smoother->active == 0) {
3518
			VLOG(3, (LOG_DEBUG, "smoother%d: ---\n", smoother_id));
3519
3520
			/* Store the first point of this action. */
3521
			smoother->start_x = x0;
3522
			smoother->start_y = y0;
3523
			dx = dy = 0;
3524
3525
			/* Initialize queue. */
3526
			smoother->queue_cursor = SYNAPTICS_PACKETQUEUE;
3527
			smoother->queue_len = 0;
3528
3529
			/* Reset average. */
3530
			smoother->avg_dx = 0;
3531
			smoother->avg_dy = 0;
3532
3533
			/* Reset squelch. */
3534
			smoother->squelch_x = 0;
3535
			smoother->squelch_y = 0;
3536
3537
			/* Activate queue */
3538
			smoother->active = 1;
3539
		} else {
3540
			/* Calculate the current delta. */
3541
			cursor = smoother->queue_cursor;
3542
			dx = x0 - smoother->queue[cursor].x;
3543
			dy = y0 - smoother->queue[cursor].y;
3544
		}
3545
3546
		VLOG(3, (LOG_DEBUG, "smoother%d: ipacket: [%d, %d], %d, %d\n",
3547
		    smoother_id, x0, y0, f->p, f->w));
3548
3549
		/* Queue this new packet. */
3550
		cursor = SYNAPTICS_QUEUE_CURSOR(smoother->queue_cursor - 1);
3551
		smoother->queue[cursor].x = x0;
3552
		smoother->queue[cursor].y = y0;
3553
		smoother->queue_cursor = cursor;
3554
		if (smoother->queue_len < SYNAPTICS_PACKETQUEUE)
3555
			smoother->queue_len++;
3556
		VLOG(5, (LOG_DEBUG,
3557
		    "smoother%d: cursor[%d]: x=%d, y=%d, dx=%d, dy=%d\n",
3558
		    smoother_id, cursor, x0, y0, dx, dy));
3559
3560
		/* Do we have enough packets to consider this a movement? */
3561
		if (smoother->queue_len < gest->window_min)
3562
			return;
3563
3564
		weight_prev_x = weight_prev_y = weight_previous;
3565
		div_max_x = div_max_y = div_max;
3566
3567
		if (gest->in_vscroll) {
3568
			/* Dividers are different with virtual scrolling. */
3569
			div_min = sc->syninfo.vscroll_div_min;
3570
			div_max_x = div_max_y = sc->syninfo.vscroll_div_max;
3571
		} else {
3572
			/*
3573
			 * There's a lot of noise in coordinates when
3574
			 * the finger is on the touchpad's borders. When
3575
			 * using this area, we apply a special weight and
3576
			 * div.
3577
			 */
3578
			if (x0 <= na_left || x0 >= max_x - na_right) {
3579
				weight_prev_x = sc->syninfo.weight_previous_na;
3580
				div_max_x = sc->syninfo.div_max_na;
3581
			}
3582
3583
			if (y0 <= na_bottom || y0 >= max_y - na_top) {
3584
				weight_prev_y = sc->syninfo.weight_previous_na;
3585
				div_max_y = sc->syninfo.div_max_na;
3586
			}
3587
		}
3588
3589
		/*
3590
		 * Calculate weights for the average operands and
3591
		 * the divisor. Both depend on the distance between
3592
		 * the current packet and a previous one (based on the
3593
		 * window width).
3594
		 */
3595
		window = imin(smoother->queue_len, window_max);
3596
		peer = SYNAPTICS_QUEUE_CURSOR(cursor + window - 1);
3597
		dxp = abs(x0 - smoother->queue[peer].x) + 1;
3598
		dyp = abs(y0 - smoother->queue[peer].y) + 1;
3599
		len = (dxp * dxp) + (dyp * dyp);
3600
		weight_prev_x = imin(weight_prev_x,
3601
		    weight_len_squared * weight_prev_x / len);
3602
		weight_prev_y = imin(weight_prev_y,
3603
		    weight_len_squared * weight_prev_y / len);
3604
3605
		len = (dxp + dyp) / 2;
3606
		div_x = div_len * div_max_x / len;
3607
		div_x = imin(div_max_x, div_x);
3608
		div_x = imax(div_min, div_x);
3609
		div_y = div_len * div_max_y / len;
3610
		div_y = imin(div_max_y, div_y);
3611
		div_y = imax(div_min, div_y);
3612
3613
		VLOG(3, (LOG_DEBUG,
3614
		    "smoother%d: peer=%d, len=%d, weight=%d/%d, div=%d/%d\n",
3615
		    smoother_id, peer, len, weight_prev_x, weight_prev_y,
3616
		    div_x, div_y));
3617
3618
		/* Compute averages. */
3619
		smoother->avg_dx =
3620
		    (weight_current * dx * multiplicator +
3621
		     weight_prev_x * smoother->avg_dx) /
3622
		    (weight_current + weight_prev_x);
3623
3624
		smoother->avg_dy =
3625
		    (weight_current * dy * multiplicator +
3626
		     weight_prev_y * smoother->avg_dy) /
3627
		    (weight_current + weight_prev_y);
3628
3629
		VLOG(5, (LOG_DEBUG,
3630
		    "smoother%d: avg_dx~=%d, avg_dy~=%d\n", smoother_id,
3631
		    smoother->avg_dx / multiplicator,
3632
		    smoother->avg_dy / multiplicator));
3633
3634
		/* Use these averages to calculate x & y. */
3635
		smoother->squelch_x += smoother->avg_dx;
3636
		dxp = smoother->squelch_x / (div_x * multiplicator);
3637
		smoother->squelch_x = smoother->squelch_x %
3638
		    (div_x * multiplicator);
3639
3640
		smoother->squelch_y += smoother->avg_dy;
3641
		dyp = smoother->squelch_y / (div_y * multiplicator);
3642
		smoother->squelch_y = smoother->squelch_y %
3643
		    (div_y * multiplicator);
3644
3645
		switch(gest->in_vscroll) {
3646
		case 0: /* Pointer movement. */
3647
			/* On real<->fuzzy finger switch the x/y pos jumps */
3648
			if (is_fuzzy == smoother->is_fuzzy) {
3649
				*x += dxp;
3650
				*y += dyp;
3651
			}
3652
3653
			VLOG(3, (LOG_DEBUG, "smoother%d: [%d, %d] -> [%d, %d]\n",
3654
			    smoother_id, dx, dy, dxp, dyp));
3655
			break;
3656
		case 1: /* Vertical scrolling. */
3657
			if (dyp != 0)
3658
				ms->button |= (dyp > 0) ?
3659
				    MOUSE_BUTTON4DOWN : MOUSE_BUTTON5DOWN;
3660
			break;
3661
		case 2: /* Horizontal scrolling. */
3662
			if (dxp != 0)
3663
				ms->button |= (dxp > 0) ?
3664
				    MOUSE_BUTTON7DOWN : MOUSE_BUTTON6DOWN;
3665
			break;
3666
		}
3667
3668
		smoother->is_fuzzy = is_fuzzy;
3669
3670
	} else {
3671
		/*
3672
		 * Deactivate queue. Note: We can not just reset queue here
3673
		 * as these values are still used by gesture processor.
3674
		 * So postpone reset till next touch.
3675
		 */
3676
		smoother->active = 0;
3677
	}
3678
}
3679
3680
static int
3681
proc_elantech(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
3682
    int *x, int *y, int *z)
3683
{
3684
	static int touchpad_button, trackpoint_button;
3685
	finger_t fn, f[ELANTECH_MAX_FINGERS];
3686
	int pkt, id, scale, i, nfingers, mask;
3687
3688
	if (!elantech_support)
3689
		return (0);
3690
3691
	/* Determine packet format and do a sanity check for out of sync packets. */
3692
	if (ELANTECH_PKT_IS_DEBOUNCE(pb, sc->elanhw.hwversion))
3693
		pkt = ELANTECH_PKT_NOP;
3694
	else if (ELANTECH_PKT_IS_TRACKPOINT(pb))
3695
		pkt = ELANTECH_PKT_TRACKPOINT;
3696
	else
3697
	switch (sc->elanhw.hwversion) {
3698
	case 2:
3699
		if (!ELANTECH_PKT_IS_V2(pb))
3700
			return (-1);
3701
3702
		pkt = (pb->ipacket[0] & 0xc0) == 0x80 ?
3703
		    ELANTECH_PKT_V2_2FINGER : ELANTECH_PKT_V2_COMMON;
3704
		break;
3705
	case 3:
3706
		if (!ELANTECH_PKT_IS_V3_HEAD(pb, sc->elanhw.hascrc) &&
3707
		    !ELANTECH_PKT_IS_V3_TAIL(pb, sc->elanhw.hascrc))
3708
			return (-1);
3709
3710
		pkt = ELANTECH_PKT_V3;
3711
		break;
3712
	case 4:
3713
		if (!ELANTECH_PKT_IS_V4(pb, sc->elanhw.hascrc))
3714
			return (-1);
3715
3716
		switch (pb->ipacket[3] & 0x03) {
3717
		case 0x00:
3718
			pkt = ELANTECH_PKT_V4_STATUS;
3719
			break;
3720
		case 0x01:
3721
			pkt = ELANTECH_PKT_V4_HEAD;
3722
			break;
3723
		case 0x02:
3724
			pkt = ELANTECH_PKT_V4_MOTION;
3725
			break;
3726
		default:
3727
			return (-1);
3728
		}
3729
		break;
3730
	default:
3731
		return (-1);
3732
	}
3733
3734
	VLOG(5, (LOG_DEBUG, "elantech: ipacket format: %d\n", pkt));
3735
3736
	for (id = 0; id < ELANTECH_MAX_FINGERS; id++)
3737
		PSM_FINGER_RESET(f[id]);
3738
3739
	*x = *y = *z = 0;
3740
	ms->button = ms->obutton;
3741
3742
	if (sc->syninfo.touchpad_off)
3743
		return (0);
3744
3745
	/* Common legend
3746
	 * L: Left mouse button pressed
3747
	 * R: Right mouse button pressed
3748
	 * N: number of fingers on touchpad
3749
	 * X: absolute x value (horizontal)
3750
	 * Y: absolute y value (vertical)
3751
	 * W; width of the finger touch
3752
	 * P: pressure
3753
	 */
3754
	switch (pkt) {
3755
	case ELANTECH_PKT_V2_COMMON:	/* HW V2. One/Three finger touch */
3756
		/*               7   6   5   4   3   2   1   0 (LSB)
3757
		 * -------------------------------------------
3758
		 * ipacket[0]:  N1  N0  W3  W2   .   .   R   L
3759
		 * ipacket[1]:  P7  P6  P5  P4 X11 X10  X9  X8
3760
		 * ipacket[2]:  X7  X6  X5  X4  X3  X2  X1  X0
3761
		 * ipacket[3]:  N4  VF  W1  W0   .   .   .  B2
3762
		 * ipacket[4]:  P3  P1  P2  P0 Y11 Y10  Y9  Y8
3763
		 * ipacket[5]:  Y7  Y6  Y5  Y4  Y3  Y2  Y1  Y0
3764
		 * -------------------------------------------
3765
		 * N4: set if more than 3 fingers (only in 3 fingers mode)
3766
		 * VF: a kind of flag? (only on EF123, 0 when finger
3767
		 *     is over one of the buttons, 1 otherwise)
3768
		 * B2: (on EF113 only, 0 otherwise), one button pressed
3769
		 * P & W is not reported on EF113 touchpads
3770
		 */
3771
		nfingers = (pb->ipacket[0] & 0xc0) >> 6;
3772
		if (nfingers == 3 && (pb->ipacket[3] & 0x80))
3773
			nfingers = 4;
3774
		mask = (1 << nfingers) - 1;
3775
3776
		fn = ELANTECH_FINGER_SET_XYP(pb);
3777
		if (sc->elanhw.haspressure) {
3778
			fn.w = ((pb->ipacket[0] & 0x30) >> 2) |
3779
			    ((pb->ipacket[3] & 0x30) >> 4);
3780
		} else {
3781
			fn.p = PSM_FINGER_DEFAULT_P;
3782
			fn.w = PSM_FINGER_DEFAULT_W;
3783
		}
3784
3785
		/*
3786
		 * HW v2 dont report exact finger positions when 3 or more
3787
		 * fingers are on touchpad. Use reported value as fingers
3788
		 * position as it is required for tap detection
3789
		 */
3790
		if (nfingers > 2)
3791
			fn.flags = PSM_FINGER_FUZZY;
3792
3793
		for (id = 0; id < imin(nfingers, ELANTECH_MAX_FINGERS); id++)
3794
			f[id] = fn;
3795
		break;
3796
3797
	case ELANTECH_PKT_V2_2FINGER:	/*HW V2. Two finger touch */
3798
		/*               7   6   5   4   3   2   1   0 (LSB)
3799
		 * -------------------------------------------
3800
		 * ipacket[0]:  N1  N0 AY8 AX8   .   .   R   L
3801
		 * ipacket[1]: AX7 AX6 AX5 AX4 AX3 AX2 AX1 AX0
3802
		 * ipacket[2]: AY7 AY6 AY5 AY4 AY3 AY2 AY1 AY0
3803
		 * ipacket[3]:   .   . BY8 BX8   .   .   .   .
3804
		 * ipacket[4]: BX7 BX6 BX5 BX4 BX3 BX2 BX1 BX0
3805
		 * ipacket[5]: BY7 BY6 BY5 BY4 BY3 BY2 BY1 BY0
3806
		 * -------------------------------------------
3807
		 * AX: lower-left finger absolute x value
3808
		 * AY: lower-left finger absolute y value
3809
		 * BX: upper-right finger absolute x value
3810
		 * BY: upper-right finger absolute y value
3811
		 */
3812
		nfingers = 2;
3813
		mask = (1 << nfingers) - 1;
3814
3815
		for (id = 0; id < imin(2, ELANTECH_MAX_FINGERS); id ++)
3816
			f[id] = (finger_t) {
3817
				.x = (((pb->ipacket[id * 3] & 0x10) << 4) |
3818
				    pb->ipacket[id * 3 + 1]) << 2,
3819
				.y = (((pb->ipacket[id * 3] & 0x20) << 3) |
3820
				    pb->ipacket[id * 3 + 2]) << 2,
3821
				.p = PSM_FINGER_DEFAULT_P,
3822
				.w = PSM_FINGER_DEFAULT_W,
3823
				/* HW ver.2 sends bounding box */
3824
				.flags = PSM_FINGER_FUZZY
3825
			};
3826
		break;
3827
3828
	case ELANTECH_PKT_V3:	/* HW Version 3 */
3829
		/*               7   6   5   4   3   2   1   0 (LSB)
3830
		 * -------------------------------------------
3831
		 * ipacket[0]:  N1  N0  W3  W2   0   1   R   L
3832
		 * ipacket[1]:  P7  P6  P5  P4 X11 X10  X9  X8
3833
		 * ipacket[2]:  X7  X6  X5  X4  X3  X2  X1  X0
3834
		 * ipacket[3]:   0   0  W1  W0   0   0   1   0
3835
		 * ipacket[4]:  P3  P1  P2  P0 Y11 Y10  Y9  Y8
3836
		 * ipacket[5]:  Y7  Y6  Y5  Y4  Y3  Y2  Y1  Y0
3837
		 * -------------------------------------------
3838
		 */
3839
		nfingers = (pb->ipacket[0] & 0xc0) >> 6;
3840
		mask = (1 << nfingers) - 1;
3841
		id = nfingers - 1;
3842
3843
		fn = ELANTECH_FINGER_SET_XYP(pb);
3844
		fn.w = ((pb->ipacket[0] & 0x30) >> 2) |
3845
		    ((pb->ipacket[3] & 0x30) >> 4);
3846
3847
		/*
3848
		 * HW v3 dont report exact finger positions when 3 or more
3849
		 * fingers are on touchpad. Use reported value as fingers
3850
		 * position as it is required for tap detection
3851
		 */
3852
		if (nfingers > 1)
3853
			fn.flags = PSM_FINGER_FUZZY;
3854
3855
		for (id = 0; id < imin(nfingers, ELANTECH_MAX_FINGERS); id++)
3856
			f[id] = fn;
3857
3858
		if (nfingers == 2) {
3859
			if (ELANTECH_PKT_IS_V3_HEAD(pb, sc->elanhw.hascrc)) {
3860
				sc->elanaction.fingers[0] = fn;
3861
				return (0);
3862
			} else
3863
				f[0] = sc->elanaction.fingers[0];
3864
		}
3865
		break;
3866
3867
	case ELANTECH_PKT_V4_STATUS:	/* HW Version 4. Status packet */
3868
		/*               7   6   5   4   3   2   1   0 (LSB)
3869
		 * -------------------------------------------
3870
		 * ipacket[0]:   .   .   .   .   0   1   R   L
3871
		 * ipacket[1]:   .   .   .  F4  F3  F2  F1  F0
3872
		 * ipacket[2]:   .   .   .   .   .   .   .   .
3873
		 * ipacket[3]:   .   .   .   1   0   0   0   0
3874
		 * ipacket[4]:  PL   .   .   .   .   .   .   .
3875
		 * ipacket[5]:   .   .   .   .   .   .   .   .
3876
		 * -------------------------------------------
3877
		 * Fn: finger n is on touchpad
3878
		 * PL: palm
3879
		 * HV ver4 sends a status packet to indicate that the numbers
3880
		 * or identities of the fingers has been changed
3881
		 */
3882
3883
		mask = pb->ipacket[1] & 0x1f;
3884
		nfingers = bitcount(mask);
3885
3886
		/* Skip "new finger is on touchpad" packets */
3887
		if ((sc->elanaction.mask & mask) == sc->elanaction.mask &&
3888
		    (mask & ~sc->elanaction.mask)) {
3889
			sc->elanaction.mask = mask;
3890
			return (0);
3891
		}
3892
3893
		break;
3894
3895
	case ELANTECH_PKT_V4_HEAD:	/* HW Version 4. Head packet */
3896
		/*               7   6   5   4   3   2   1   0 (LSB)
3897
		 * -------------------------------------------
3898
		 * ipacket[0]:  W3  W2  W1  W0   0   1   R   L
3899
		 * ipacket[1]:  P7  P6  P5  P4 X11 X10  X9  X8
3900
		 * ipacket[2]:  X7  X6  X5  X4  X3  X2  X1  X0
3901
		 * ipacket[3]: ID2 ID1 ID0   1   0   0   0   1
3902
		 * ipacket[4]:  P3  P1  P2  P0 Y11 Y10  Y9  Y8
3903
		 * ipacket[5]:  Y7  Y6  Y5  Y4  Y3  Y2  Y1  Y0
3904
		 * -------------------------------------------
3905
		 * ID: finger id
3906
		 * HW ver 4 sends head packets in two cases:
3907
		 * 1. One finger touch and movement.
3908
		 * 2. Next after status packet to tell new finger positions.
3909
		 */
3910
		mask = sc->elanaction.mask;
3911
		nfingers = bitcount(mask);
3912
		id = ((pb->ipacket[3] & 0xe0) >> 5) - 1;
3913
3914
		if (id >= 0 && id < ELANTECH_MAX_FINGERS) {
3915
			f[id] = ELANTECH_FINGER_SET_XYP(pb);
3916
			f[id].w = (pb->ipacket[0] & 0xf0) >> 4;
3917
		}
3918
		break;
3919
3920
	case ELANTECH_PKT_V4_MOTION:	/* HW Version 4. Motion packet */
3921
		/*               7   6   5   4   3   2   1   0 (LSB)
3922
		 * -------------------------------------------
3923
		 * ipacket[0]: ID2 ID1 ID0  OF   0   1   R   L
3924
		 * ipacket[1]: DX7 DX6 DX5 DX4 DX3 DX2 DX1 DX0
3925
		 * ipacket[2]: DY7 DY6 DY5 DY4 DY3 DY2 DY1 DY0
3926
		 * ipacket[3]: ID2 ID1 ID0   1   0   0   1   0
3927
		 * ipacket[4]: DX7 DX6 DX5 DX4 DX3 DX2 DX1 DX0
3928
		 * ipacket[5]: DY7 DY6 DY5 DY4 DY3 DY2 DY1 DY0
3929
		 * -------------------------------------------
3930
		 * OF: delta overflows (> 127 or < -128), in this case
3931
		 *     firmware sends us (delta x / 5) and (delta y / 5)
3932
		 * ID: finger id
3933
		 * DX: delta x (two's complement)
3934
		 * XY: delta y (two's complement)
3935
		 * byte 0 ~ 2 for one finger
3936
		 * byte 3 ~ 5 for another finger
3937
		 */
3938
		mask = sc->elanaction.mask;
3939
		nfingers = bitcount(mask);
3940
3941
		scale = (pb->ipacket[0] & 0x10) ? 5 : 1;
3942
		for (i = 0; i <= 3; i += 3) {
3943
			id = ((pb->ipacket[i] & 0xe0) >> 5) - 1;
3944
			if (id < 0 || id >= ELANTECH_MAX_FINGERS)
3945
				continue;
3946
3947
			if (PSM_FINGER_IS_SET(sc->elanaction.fingers[id])) {
3948
				f[id] = sc->elanaction.fingers[id];
3949
				f[id].x += imax(-f[id].x,
3950
				    (signed char)pb->ipacket[i+1] * scale);
3951
				f[id].y += imax(-f[id].y,
3952
				    (signed char)pb->ipacket[i+2] * scale);
3953
			} else {
3954
				VLOG(3, (LOG_DEBUG, "elantech: "
3955
				    "HW v4 motion packet skipped\n"));
3956
			}
3957
		}
3958
3959
		break;
3960
3961
	case ELANTECH_PKT_TRACKPOINT:
3962
		/*               7   6   5   4   3   2   1   0 (LSB)
3963
		 * -------------------------------------------
3964
		 * ipacket[0]:   0   0  SX  SY   0   M   R   L
3965
		 * ipacket[1]: ~SX   0   0   0   0   0   0   0
3966
		 * ipacket[2]: ~SY   0   0   0   0   0   0   0
3967
		 * ipacket[3]:   0   0 ~SY ~SX   0   1   1   0
3968
		 * ipacket[4]:  X7  X6  X5  X4  X3  X2  X1  X0
3969
		 * ipacket[5]:  Y7  Y6  Y5  Y4  Y3  Y2  Y1  Y0
3970
		 * -------------------------------------------
3971
		 * X and Y are written in two's complement spread
3972
		 * over 9 bits with SX/SY the relative top bit and
3973
		 * X7..X0 and Y7..Y0 the lower bits.
3974
		 */
3975
		*x = (pb->ipacket[0] & 0x20) ?
3976
		    pb->ipacket[4] - 256 : pb->ipacket[4];
3977
		*y = (pb->ipacket[0] & 0x10) ?
3978
		    pb->ipacket[5] - 256 : pb->ipacket[5];
3979
3980
		trackpoint_button =
3981
		    ((pb->ipacket[0] & 0x01) ? MOUSE_BUTTON1DOWN : 0) |
3982
		    ((pb->ipacket[0] & 0x02) ? MOUSE_BUTTON3DOWN : 0) |
3983
		    ((pb->ipacket[0] & 0x04) ? MOUSE_BUTTON2DOWN : 0);
3984
3985
		ms->button = touchpad_button | trackpoint_button;
3986
		return (0);
3987
3988
	case ELANTECH_PKT_NOP:
3989
		return (0);
3990
3991
	default:
3992
		return (-1);
3993
	}
3994
3995
	for (id = 0; id < ELANTECH_MAX_FINGERS; id++)
3996
		if (PSM_FINGER_IS_SET(f[id]))
3997
			VLOG(2, (LOG_DEBUG, "elantech: "
3998
			    "finger %d: down [%d, %d], %d, %d, %d\n", id + 1,
3999
			    f[id].x, f[id].y, f[id].p, f[id].w, f[id].flags));
4000
4001
	/* Touchpad button presses */
4002
	if (sc->elanhw.isclickpad) {
4003
		touchpad_button =
4004
		    ((pb->ipacket[0] & 0x03) ? MOUSE_BUTTON1DOWN : 0);
4005
	} else {
4006
		touchpad_button =
4007
		    ((pb->ipacket[0] & 0x01) ? MOUSE_BUTTON1DOWN : 0) |
4008
		    ((pb->ipacket[0] & 0x02) ? MOUSE_BUTTON3DOWN : 0);
4009
	}
4010
4011
	ms->button = touchpad_button | trackpoint_button;
4012
4013
	/* Palm detection doesn't terminate the current action. */
4014
	if (!psmpalmdetect(sc, &f[0], nfingers)) {
4015
		/* Send finger 1 position to gesture processor */
4016
		if (PSM_FINGER_IS_SET(f[0]) || PSM_FINGER_IS_SET(f[1]) ||
4017
		    nfingers == 0)
4018
			psmgestures(sc, &f[0], imin(nfingers, 3), ms);
4019
		/* Send fingers positions to movement smoothers */
4020
		for (id = 0; id < PSM_FINGERS; id++)
4021
			if (PSM_FINGER_IS_SET(f[id]) || !(mask & (1 << id)))
4022
				psmsmoother(sc, &f[id], id, ms, x, y);
4023
	} else {
4024
		VLOG(2, (LOG_DEBUG, "elantech: palm detected! (%d)\n",
4025
		    f[0].w));
4026
	}
4027
4028
	/* Store current finger positions in action context */
4029
	for (id = 0; id < ELANTECH_MAX_FINGERS; id++) {
4030
		if (PSM_FINGER_IS_SET(f[id]))
4031
			sc->elanaction.fingers[id] = f[id];
4032
		if ((sc->elanaction.mask & (1 << id)) && !(mask & (1 << id)))
4033
			PSM_FINGER_RESET(sc->elanaction.fingers[id]);
4034
	}
4035
	sc->elanaction.mask = mask;
4036
4037
	/* Use the extra buttons as a scrollwheel */
4038
	if (ms->button & MOUSE_BUTTON4DOWN)
4039
		*z = -1;
4040
	else if (ms->button & MOUSE_BUTTON5DOWN)
4041
		*z = 1;
4042
	else if (ms->button & MOUSE_BUTTON6DOWN)
4043
		*z = -2;
4044
	else if (ms->button & MOUSE_BUTTON7DOWN)
3340
		*z = 2;
4045
		*z = 2;
3341
		ms->button &= ~MOUSE_BUTTON7DOWN;
4046
	else
3342
	} else
3343
		*z = 0;
4047
		*z = 0;
4048
	ms->button &= ~(MOUSE_BUTTON4DOWN | MOUSE_BUTTON5DOWN |
4049
	    MOUSE_BUTTON6DOWN | MOUSE_BUTTON7DOWN);
3344
4050
3345
	return (0);
4051
	return (0);
3346
}
4052
}
Lines 3413-3418 proc_versapad(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms, Link Here
3413
}
4119
}
3414
4120
3415
static void
4121
static void
4122
psmsoftintridle(void *arg)
4123
{
4124
	struct psm_softc *sc = arg;
4125
	packetbuf_t *pb;
4126
4127
	/* Invoke soft handler only when pqueue is empty. Otherwise it will be
4128
	 * invoked from psmintr soon with pqueue filled with real data */
4129
	if (sc->pqueue_start == sc->pqueue_end &&
4130
	    sc->idlepacket.inputbytes > 0) {
4131
		/* Grow circular queue backwards to avoid race with psmintr */
4132
		if (--sc->pqueue_start < 0)
4133
			sc->pqueue_start = PSM_PACKETQUEUE - 1;
4134
4135
		pb = &sc->pqueue[sc->pqueue_start];
4136
		memcpy(pb, &sc->idlepacket, sizeof(packetbuf_t));
4137
		VLOG(4, (LOG_DEBUG,
4138
		    "psmsoftintridle: %02x %02x %02x %02x %02x %02x\n",
4139
		    pb->ipacket[0], pb->ipacket[1], pb->ipacket[2],
4140
		    pb->ipacket[3], pb->ipacket[4], pb->ipacket[5]));
4141
4142
		psmsoftintr(arg);
4143
	}
4144
}
4145
4146
static void
3416
psmsoftintr(void *arg)
4147
psmsoftintr(void *arg)
3417
{
4148
{
3418
	/*
4149
	/*
Lines 3465-3470 psmsoftintr(void *arg) Link Here
3465
		if (sc->config & PSM_CONFIG_FORCETAP)
4196
		if (sc->config & PSM_CONFIG_FORCETAP)
3466
			ms.button |= ((c & MOUSE_PS2_TAP)) ?
4197
			ms.button |= ((c & MOUSE_PS2_TAP)) ?
3467
			    0 : MOUSE_BUTTON4DOWN;
4198
			    0 : MOUSE_BUTTON4DOWN;
4199
		timevalclear(&sc->idletimeout);
4200
		sc->idlepacket.inputbytes = 0;
3468
4201
3469
		switch (sc->hw.model) {
4202
		switch (sc->hw.model) {
3470
4203
Lines 3603-3608 psmsoftintr(void *arg) Link Here
3603
				goto next;
4336
				goto next;
3604
			break;
4337
			break;
3605
4338
4339
		case MOUSE_MODEL_ELANTECH:
4340
			if (proc_elantech(sc, pb, &ms, &x, &y, &z) != 0)
4341
				goto next;
4342
			break;
4343
3606
		case MOUSE_MODEL_TRACKPOINT:
4344
		case MOUSE_MODEL_TRACKPOINT:
3607
		case MOUSE_MODEL_GENERIC:
4345
		case MOUSE_MODEL_GENERIC:
3608
		default:
4346
		default:
Lines 3627-3632 psmsoftintr(void *arg) Link Here
3627
		}
4365
		}
3628
	}
4366
	}
3629
4367
4368
	/* Store last packet for reinjection if it has not been set already */
4369
	if (timevalisset(&sc->idletimeout) && sc->idlepacket.inputbytes == 0)
4370
		sc->idlepacket = *pb;
4371
3630
	ms.dx = x;
4372
	ms.dx = x;
3631
	ms.dy = y;
4373
	ms.dy = y;
3632
	ms.dz = z;
4374
	ms.dz = z;
Lines 3673-3678 next: Link Here
3673
		pgsigio(&sc->async, SIGIO, 0);
4415
		pgsigio(&sc->async, SIGIO, 0);
3674
	}
4416
	}
3675
	sc->state &= ~PSM_SOFTARMED;
4417
	sc->state &= ~PSM_SOFTARMED;
4418
4419
	/* schedule injection of predefined packet after idletimeout
4420
	 * if no data packets have been received from psmintr */
4421
	if (timevalisset(&sc->idletimeout)) {
4422
		sc->state |= PSM_SOFTARMED;
4423
		callout_reset(&sc->softcallout, tvtohz(&sc->idletimeout),
4424
		    psmsoftintridle, sc);
4425
		VLOG(2, (LOG_DEBUG, "softintr: callout set: %d ticks\n",
4426
		    tvtohz(&sc->idletimeout)));
4427
	}
3676
	splx(s);
4428
	splx(s);
3677
}
4429
}
3678
4430
Lines 4106-4115 enable_4dplus(struct psm_softc *sc, enum probearg arg) Link Here
4106
static int
4858
static int
4107
synaptics_sysctl(SYSCTL_HANDLER_ARGS)
4859
synaptics_sysctl(SYSCTL_HANDLER_ARGS)
4108
{
4860
{
4861
	struct psm_softc *sc;
4109
	int error, arg;
4862
	int error, arg;
4110
4863
4864
	if (oidp->oid_arg1 == NULL || oidp->oid_arg2 < 0 ||
4865
	    oidp->oid_arg2 > SYNAPTICS_SYSCTL_SOFTBUTTON3_X)
4866
		return (EINVAL);
4867
4868
	sc = oidp->oid_arg1;
4869
4111
	/* Read the current value. */
4870
	/* Read the current value. */
4112
	arg = *(int *)oidp->oid_arg1;
4871
	arg = *(int *)((char *)sc + oidp->oid_arg2);
4113
	error = sysctl_handle_int(oidp, &arg, 0, req);
4872
	error = sysctl_handle_int(oidp, &arg, 0, req);
4114
4873
4115
	/* Sanity check. */
4874
	/* Sanity check. */
Lines 4131-4144 synaptics_sysctl(SYSCTL_HANDLER_ARGS) Link Here
4131
			return (EINVAL);
4890
			return (EINVAL);
4132
		break;
4891
		break;
4133
	case SYNAPTICS_SYSCTL_MARGIN_TOP:
4892
	case SYNAPTICS_SYSCTL_MARGIN_TOP:
4134
	case SYNAPTICS_SYSCTL_MARGIN_RIGHT:
4135
	case SYNAPTICS_SYSCTL_MARGIN_BOTTOM:
4893
	case SYNAPTICS_SYSCTL_MARGIN_BOTTOM:
4136
	case SYNAPTICS_SYSCTL_MARGIN_LEFT:
4137
	case SYNAPTICS_SYSCTL_NA_TOP:
4894
	case SYNAPTICS_SYSCTL_NA_TOP:
4138
	case SYNAPTICS_SYSCTL_NA_RIGHT:
4139
	case SYNAPTICS_SYSCTL_NA_BOTTOM:
4895
	case SYNAPTICS_SYSCTL_NA_BOTTOM:
4896
		if (arg < 0 || arg > sc->synhw.maximumYCoord)
4897
			return (EINVAL);
4898
		break;
4899
	case SYNAPTICS_SYSCTL_SOFTBUTTON2_X:
4900
	case SYNAPTICS_SYSCTL_SOFTBUTTON3_X:
4901
		/* Softbuttons is clickpad only feature */
4902
		if (!sc->synhw.capClickPad && arg != 0)
4903
			return (EINVAL);
4904
		/* FALLTHROUGH */
4905
	case SYNAPTICS_SYSCTL_MARGIN_RIGHT:
4906
	case SYNAPTICS_SYSCTL_MARGIN_LEFT:
4907
	case SYNAPTICS_SYSCTL_NA_RIGHT:
4140
	case SYNAPTICS_SYSCTL_NA_LEFT:
4908
	case SYNAPTICS_SYSCTL_NA_LEFT:
4141
		if (arg < 0 || arg > 6143)
4909
		if (arg < 0 || arg > sc->synhw.maximumXCoord)
4142
			return (EINVAL);
4910
			return (EINVAL);
4143
		break;
4911
		break;
4144
	case SYNAPTICS_SYSCTL_WINDOW_MIN:
4912
	case SYNAPTICS_SYSCTL_WINDOW_MIN:
Lines 4168-4175 synaptics_sysctl(SYSCTL_HANDLER_ARGS) Link Here
4168
			return (EINVAL);
4936
			return (EINVAL);
4169
		break;
4937
		break;
4170
	case SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA:
4938
	case SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA:
4939
		if (arg < -sc->synhw.maximumXCoord ||
4940
		    arg > sc->synhw.maximumXCoord)
4941
			return (EINVAL);
4942
		break;
4943
	case SYNAPTICS_SYSCTL_SOFTBUTTONS_Y:
4944
		/* Softbuttons is clickpad only feature */
4945
		if (!sc->synhw.capClickPad && arg != 0)
4946
			return (EINVAL);
4947
		/* FALLTHROUGH */
4171
	case SYNAPTICS_SYSCTL_VSCROLL_VER_AREA:
4948
	case SYNAPTICS_SYSCTL_VSCROLL_VER_AREA:
4172
		if (arg < -6143 || arg > 6143)
4949
		if (arg < -sc->synhw.maximumYCoord ||
4950
		    arg > sc->synhw.maximumYCoord)
4173
			return (EINVAL);
4951
			return (EINVAL);
4174
		break;
4952
		break;
4175
        case SYNAPTICS_SYSCTL_TOUCHPAD_OFF:
4953
        case SYNAPTICS_SYSCTL_TOUCHPAD_OFF:
Lines 4181-4193 synaptics_sysctl(SYSCTL_HANDLER_ARGS) Link Here
4181
	}
4959
	}
4182
4960
4183
	/* Update. */
4961
	/* Update. */
4184
	*(int *)oidp->oid_arg1 = arg;
4962
	*(int *)((char *)sc + oidp->oid_arg2) = arg;
4185
4963
4186
	return (error);
4964
	return (error);
4187
}
4965
}
4188
4966
4189
static void
4967
static void
4190
synaptics_sysctl_create_tree(struct psm_softc *sc)
4968
synaptics_sysctl_create_softbuttons_tree(struct psm_softc *sc)
4969
{
4970
	/*
4971
	 * Set predefined sizes for softbuttons.
4972
	 * Values are taken to match HP Pavilion dv6 clickpad drawings
4973
	 * with thin middle softbutton placed on separator
4974
	 */
4975
4976
	/* hw.psm.synaptics.softbuttons_y */
4977
	sc->syninfo.softbuttons_y = 1700;
4978
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4979
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4980
	    "softbuttons_y", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4981
	    sc, SYNAPTICS_SYSCTL_SOFTBUTTONS_Y,
4982
	    synaptics_sysctl, "I",
4983
	    "Vertical size of softbuttons area");
4984
4985
	/* hw.psm.synaptics.softbutton2_x */
4986
	sc->syninfo.softbutton2_x = 3100;
4987
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4988
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4989
	    "softbutton2_x", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4990
	    sc, SYNAPTICS_SYSCTL_SOFTBUTTON2_X,
4991
	    synaptics_sysctl, "I",
4992
	    "Horisontal position of 2-nd softbutton left edge (0-disable)");
4993
4994
	/* hw.psm.synaptics.softbutton3_x */
4995
	sc->syninfo.softbutton3_x = 3900;
4996
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4997
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4998
	    "softbutton3_x", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4999
	    sc, SYNAPTICS_SYSCTL_SOFTBUTTON3_X,
5000
	    synaptics_sysctl, "I",
5001
	    "Horisontal position of 3-rd softbutton left edge (0-disable)");
5002
}
5003
5004
static void
5005
synaptics_sysctl_create_tree(struct psm_softc *sc, const char *name,
5006
    const char *descr)
4191
{
5007
{
4192
5008
4193
	if (sc->syninfo.sysctl_tree != NULL)
5009
	if (sc->syninfo.sysctl_tree != NULL)
Lines 4196-4203 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4196
	/* Attach extra synaptics sysctl nodes under hw.psm.synaptics */
5012
	/* Attach extra synaptics sysctl nodes under hw.psm.synaptics */
4197
	sysctl_ctx_init(&sc->syninfo.sysctl_ctx);
5013
	sysctl_ctx_init(&sc->syninfo.sysctl_ctx);
4198
	sc->syninfo.sysctl_tree = SYSCTL_ADD_NODE(&sc->syninfo.sysctl_ctx,
5014
	sc->syninfo.sysctl_tree = SYSCTL_ADD_NODE(&sc->syninfo.sysctl_ctx,
4199
	    SYSCTL_STATIC_CHILDREN(_hw_psm), OID_AUTO, "synaptics", CTLFLAG_RD,
5015
	    SYSCTL_STATIC_CHILDREN(_hw_psm), OID_AUTO, name, CTLFLAG_RD,
4200
	    0, "Synaptics TouchPad");
5016
	    0, descr);
4201
5017
4202
	/* hw.psm.synaptics.directional_scrolls. */
5018
	/* hw.psm.synaptics.directional_scrolls. */
4203
	sc->syninfo.directional_scrolls = 0;
5019
	sc->syninfo.directional_scrolls = 0;
Lines 4208-4213 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4208
	    "Enable hardware scrolling pad (if non-zero) or register it as "
5024
	    "Enable hardware scrolling pad (if non-zero) or register it as "
4209
	    "extended buttons (if 0)");
5025
	    "extended buttons (if 0)");
4210
5026
5027
	/* hw.psm.synaptics.max_x. */
5028
	sc->syninfo.max_x = 6143;
5029
	SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx,
5030
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5031
	    "max_x", CTLFLAG_RD|CTLFLAG_ANYBODY,
5032
	    &sc->syninfo.max_x, 0,
5033
	    "Horizontal reporting range");
5034
5035
	/* hw.psm.synaptics.max_y. */
5036
	sc->syninfo.max_y = 6143;
5037
	SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx,
5038
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5039
	    "max_y", CTLFLAG_RD|CTLFLAG_ANYBODY,
5040
	    &sc->syninfo.max_y, 0,
5041
	    "Vertical reporting range");
5042
4211
	/*
5043
	/*
4212
	 * Turn off two finger scroll if we have a
5044
	 * Turn off two finger scroll if we have a
4213
	 * physical area reserved for scrolling or when
5045
	 * physical area reserved for scrolling or when
Lines 4230-4236 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4230
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5062
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4231
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5063
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4232
	    "min_pressure", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5064
	    "min_pressure", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4233
	    &sc->syninfo.min_pressure, SYNAPTICS_SYSCTL_MIN_PRESSURE,
5065
	    sc, SYNAPTICS_SYSCTL_MIN_PRESSURE,
4234
	    synaptics_sysctl, "I",
5066
	    synaptics_sysctl, "I",
4235
	    "Minimum pressure required to start an action");
5067
	    "Minimum pressure required to start an action");
4236
5068
Lines 4239-4245 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4239
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5071
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4240
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5072
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4241
	    "max_pressure", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5073
	    "max_pressure", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4242
	    &sc->syninfo.max_pressure, SYNAPTICS_SYSCTL_MAX_PRESSURE,
5074
	    sc, SYNAPTICS_SYSCTL_MAX_PRESSURE,
4243
	    synaptics_sysctl, "I",
5075
	    synaptics_sysctl, "I",
4244
	    "Maximum pressure to detect palm");
5076
	    "Maximum pressure to detect palm");
4245
5077
Lines 4248-4254 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4248
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5080
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4249
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5081
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4250
	    "max_width", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5082
	    "max_width", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4251
	    &sc->syninfo.max_width, SYNAPTICS_SYSCTL_MAX_WIDTH,
5083
	    sc, SYNAPTICS_SYSCTL_MAX_WIDTH,
4252
	    synaptics_sysctl, "I",
5084
	    synaptics_sysctl, "I",
4253
	    "Maximum finger width to detect palm");
5085
	    "Maximum finger width to detect palm");
4254
5086
Lines 4257-4263 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4257
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5089
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4258
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5090
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4259
	    "margin_top", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5091
	    "margin_top", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4260
	    &sc->syninfo.margin_top, SYNAPTICS_SYSCTL_MARGIN_TOP,
5092
	    sc, SYNAPTICS_SYSCTL_MARGIN_TOP,
4261
	    synaptics_sysctl, "I",
5093
	    synaptics_sysctl, "I",
4262
	    "Top margin");
5094
	    "Top margin");
4263
5095
Lines 4266-4272 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4266
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5098
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4267
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5099
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4268
	    "margin_right", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5100
	    "margin_right", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4269
	    &sc->syninfo.margin_right, SYNAPTICS_SYSCTL_MARGIN_RIGHT,
5101
	    sc, SYNAPTICS_SYSCTL_MARGIN_RIGHT,
4270
	    synaptics_sysctl, "I",
5102
	    synaptics_sysctl, "I",
4271
	    "Right margin");
5103
	    "Right margin");
4272
5104
Lines 4275-4281 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4275
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5107
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4276
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5108
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4277
	    "margin_bottom", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5109
	    "margin_bottom", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4278
	    &sc->syninfo.margin_bottom, SYNAPTICS_SYSCTL_MARGIN_BOTTOM,
5110
	    sc, SYNAPTICS_SYSCTL_MARGIN_BOTTOM,
4279
	    synaptics_sysctl, "I",
5111
	    synaptics_sysctl, "I",
4280
	    "Bottom margin");
5112
	    "Bottom margin");
4281
5113
Lines 4284-4290 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4284
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5116
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4285
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5117
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4286
	    "margin_left", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5118
	    "margin_left", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4287
	    &sc->syninfo.margin_left, SYNAPTICS_SYSCTL_MARGIN_LEFT,
5119
	    sc, SYNAPTICS_SYSCTL_MARGIN_LEFT,
4288
	    synaptics_sysctl, "I",
5120
	    synaptics_sysctl, "I",
4289
	    "Left margin");
5121
	    "Left margin");
4290
5122
Lines 4293-4299 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4293
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5125
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4294
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5126
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4295
	    "na_top", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5127
	    "na_top", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4296
	    &sc->syninfo.na_top, SYNAPTICS_SYSCTL_NA_TOP,
5128
	    sc, SYNAPTICS_SYSCTL_NA_TOP,
4297
	    synaptics_sysctl, "I",
5129
	    synaptics_sysctl, "I",
4298
	    "Top noisy area, where weight_previous_na is used instead "
5130
	    "Top noisy area, where weight_previous_na is used instead "
4299
	    "of weight_previous");
5131
	    "of weight_previous");
Lines 4303-4309 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4303
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5135
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4304
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5136
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4305
	    "na_right", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5137
	    "na_right", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4306
	    &sc->syninfo.na_right, SYNAPTICS_SYSCTL_NA_RIGHT,
5138
	    sc, SYNAPTICS_SYSCTL_NA_RIGHT,
4307
	    synaptics_sysctl, "I",
5139
	    synaptics_sysctl, "I",
4308
	    "Right noisy area, where weight_previous_na is used instead "
5140
	    "Right noisy area, where weight_previous_na is used instead "
4309
	    "of weight_previous");
5141
	    "of weight_previous");
Lines 4313-4319 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4313
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5145
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4314
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5146
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4315
	    "na_bottom", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5147
	    "na_bottom", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4316
	    &sc->syninfo.na_bottom, SYNAPTICS_SYSCTL_NA_BOTTOM,
5148
	    sc, SYNAPTICS_SYSCTL_NA_BOTTOM,
4317
	    synaptics_sysctl, "I",
5149
	    synaptics_sysctl, "I",
4318
	    "Bottom noisy area, where weight_previous_na is used instead "
5150
	    "Bottom noisy area, where weight_previous_na is used instead "
4319
	    "of weight_previous");
5151
	    "of weight_previous");
Lines 4323-4329 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4323
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5155
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4324
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5156
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4325
	    "na_left", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5157
	    "na_left", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4326
	    &sc->syninfo.na_left, SYNAPTICS_SYSCTL_NA_LEFT,
5158
	    sc, SYNAPTICS_SYSCTL_NA_LEFT,
4327
	    synaptics_sysctl, "I",
5159
	    synaptics_sysctl, "I",
4328
	    "Left noisy area, where weight_previous_na is used instead "
5160
	    "Left noisy area, where weight_previous_na is used instead "
4329
	    "of weight_previous");
5161
	    "of weight_previous");
Lines 4333-4339 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4333
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5165
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4334
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5166
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4335
	    "window_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5167
	    "window_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4336
	    &sc->syninfo.window_min, SYNAPTICS_SYSCTL_WINDOW_MIN,
5168
	    sc, SYNAPTICS_SYSCTL_WINDOW_MIN,
4337
	    synaptics_sysctl, "I",
5169
	    synaptics_sysctl, "I",
4338
	    "Minimum window size to start an action");
5170
	    "Minimum window size to start an action");
4339
5171
Lines 4342-4348 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4342
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5174
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4343
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5175
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4344
	    "window_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5176
	    "window_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4345
	    &sc->syninfo.window_max, SYNAPTICS_SYSCTL_WINDOW_MAX,
5177
	    sc, SYNAPTICS_SYSCTL_WINDOW_MAX,
4346
	    synaptics_sysctl, "I",
5178
	    synaptics_sysctl, "I",
4347
	    "Maximum window size");
5179
	    "Maximum window size");
4348
5180
Lines 4351-4357 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4351
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5183
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4352
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5184
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4353
	    "multiplicator", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5185
	    "multiplicator", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4354
	    &sc->syninfo.multiplicator, SYNAPTICS_SYSCTL_MULTIPLICATOR,
5186
	    sc, SYNAPTICS_SYSCTL_MULTIPLICATOR,
4355
	    synaptics_sysctl, "I",
5187
	    synaptics_sysctl, "I",
4356
	    "Multiplicator to increase precision in averages and divisions");
5188
	    "Multiplicator to increase precision in averages and divisions");
4357
5189
Lines 4360-4366 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4360
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5192
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4361
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5193
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4362
	    "weight_current", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5194
	    "weight_current", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4363
	    &sc->syninfo.weight_current, SYNAPTICS_SYSCTL_WEIGHT_CURRENT,
5195
	    sc, SYNAPTICS_SYSCTL_WEIGHT_CURRENT,
4364
	    synaptics_sysctl, "I",
5196
	    synaptics_sysctl, "I",
4365
	    "Weight of the current movement in the new average");
5197
	    "Weight of the current movement in the new average");
4366
5198
Lines 4369-4375 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4369
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5201
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4370
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5202
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4371
	    "weight_previous", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5203
	    "weight_previous", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4372
	    &sc->syninfo.weight_previous, SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS,
5204
	    sc, SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS,
4373
	    synaptics_sysctl, "I",
5205
	    synaptics_sysctl, "I",
4374
	    "Weight of the previous average");
5206
	    "Weight of the previous average");
4375
5207
Lines 4378-4385 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4378
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5210
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4379
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5211
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4380
	    "weight_previous_na", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5212
	    "weight_previous_na", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4381
	    &sc->syninfo.weight_previous_na,
5213
	    sc, SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS_NA,
4382
	    SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS_NA,
4383
	    synaptics_sysctl, "I",
5214
	    synaptics_sysctl, "I",
4384
	    "Weight of the previous average (inside the noisy area)");
5215
	    "Weight of the previous average (inside the noisy area)");
4385
5216
Lines 4388-4395 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4388
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5219
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4389
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5220
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4390
	    "weight_len_squared", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5221
	    "weight_len_squared", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4391
	    &sc->syninfo.weight_len_squared,
5222
	    sc, SYNAPTICS_SYSCTL_WEIGHT_LEN_SQUARED,
4392
	    SYNAPTICS_SYSCTL_WEIGHT_LEN_SQUARED,
4393
	    synaptics_sysctl, "I",
5223
	    synaptics_sysctl, "I",
4394
	    "Length (squared) of segments where weight_previous "
5224
	    "Length (squared) of segments where weight_previous "
4395
	    "starts to decrease");
5225
	    "starts to decrease");
Lines 4399-4405 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4399
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5229
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4400
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5230
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4401
	    "div_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5231
	    "div_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4402
	    &sc->syninfo.div_min, SYNAPTICS_SYSCTL_DIV_MIN,
5232
	    sc, SYNAPTICS_SYSCTL_DIV_MIN,
4403
	    synaptics_sysctl, "I",
5233
	    synaptics_sysctl, "I",
4404
	    "Divisor for fast movements");
5234
	    "Divisor for fast movements");
4405
5235
Lines 4408-4414 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4408
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5238
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4409
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5239
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4410
	    "div_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5240
	    "div_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4411
	    &sc->syninfo.div_max, SYNAPTICS_SYSCTL_DIV_MAX,
5241
	    sc, SYNAPTICS_SYSCTL_DIV_MAX,
4412
	    synaptics_sysctl, "I",
5242
	    synaptics_sysctl, "I",
4413
	    "Divisor for slow movements");
5243
	    "Divisor for slow movements");
4414
5244
Lines 4417-4423 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4417
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5247
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4418
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5248
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4419
	    "div_max_na", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5249
	    "div_max_na", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4420
	    &sc->syninfo.div_max_na, SYNAPTICS_SYSCTL_DIV_MAX_NA,
5250
	    sc, SYNAPTICS_SYSCTL_DIV_MAX_NA,
4421
	    synaptics_sysctl, "I",
5251
	    synaptics_sysctl, "I",
4422
	    "Divisor with slow movements (inside the noisy area)");
5252
	    "Divisor with slow movements (inside the noisy area)");
4423
5253
Lines 4426-4432 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4426
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5256
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4427
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5257
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4428
	    "div_len", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5258
	    "div_len", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4429
	    &sc->syninfo.div_len, SYNAPTICS_SYSCTL_DIV_LEN,
5259
	    sc, SYNAPTICS_SYSCTL_DIV_LEN,
4430
	    synaptics_sysctl, "I",
5260
	    synaptics_sysctl, "I",
4431
	    "Length of segments where div_max starts to decrease");
5261
	    "Length of segments where div_max starts to decrease");
4432
5262
Lines 4435-4441 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4435
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5265
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4436
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5266
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4437
	    "tap_max_delta", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5267
	    "tap_max_delta", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4438
	    &sc->syninfo.tap_max_delta, SYNAPTICS_SYSCTL_TAP_MAX_DELTA,
5268
	    sc, SYNAPTICS_SYSCTL_TAP_MAX_DELTA,
4439
	    synaptics_sysctl, "I",
5269
	    synaptics_sysctl, "I",
4440
	    "Length of segments above which a tap is ignored");
5270
	    "Length of segments above which a tap is ignored");
4441
5271
Lines 4444-4460 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4444
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5274
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4445
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5275
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4446
	    "tap_min_queue", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5276
	    "tap_min_queue", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4447
	    &sc->syninfo.tap_min_queue, SYNAPTICS_SYSCTL_TAP_MIN_QUEUE,
5277
	    sc, SYNAPTICS_SYSCTL_TAP_MIN_QUEUE,
4448
	    synaptics_sysctl, "I",
5278
	    synaptics_sysctl, "I",
4449
	    "Number of packets required to consider a tap");
5279
	    "Number of packets required to consider a tap");
4450
5280
4451
	/* hw.psm.synaptics.taphold_timeout. */
5281
	/* hw.psm.synaptics.taphold_timeout. */
4452
	sc->synaction.in_taphold = 0;
5282
	sc->gesture.in_taphold = 0;
4453
	sc->syninfo.taphold_timeout = tap_timeout;
5283
	sc->syninfo.taphold_timeout = tap_timeout;
4454
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5284
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4455
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5285
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4456
	    "taphold_timeout", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5286
	    "taphold_timeout", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4457
	    &sc->syninfo.taphold_timeout, SYNAPTICS_SYSCTL_TAPHOLD_TIMEOUT,
5287
	    sc, SYNAPTICS_SYSCTL_TAPHOLD_TIMEOUT,
4458
	    synaptics_sysctl, "I",
5288
	    synaptics_sysctl, "I",
4459
	    "Maximum elapsed time between two taps to consider a tap-hold "
5289
	    "Maximum elapsed time between two taps to consider a tap-hold "
4460
	    "action");
5290
	    "action");
Lines 4464-4479 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4464
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5294
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4465
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5295
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4466
	    "vscroll_hor_area", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5296
	    "vscroll_hor_area", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4467
	    &sc->syninfo.vscroll_hor_area, SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA,
5297
	    sc, SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA,
4468
	    synaptics_sysctl, "I",
5298
	    synaptics_sysctl, "I",
4469
	    "Area reserved for horizontal virtual scrolling");
5299
	    "Area reserved for horizontal virtual scrolling");
4470
5300
4471
	/* hw.psm.synaptics.vscroll_ver_area. */
5301
	/* hw.psm.synaptics.vscroll_ver_area. */
4472
	sc->syninfo.vscroll_ver_area = -600;
5302
	sc->syninfo.vscroll_ver_area = -400 - sc->syninfo.margin_right;
4473
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5303
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4474
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5304
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4475
	    "vscroll_ver_area", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5305
	    "vscroll_ver_area", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4476
	    &sc->syninfo.vscroll_ver_area, SYNAPTICS_SYSCTL_VSCROLL_VER_AREA,
5306
	    sc, SYNAPTICS_SYSCTL_VSCROLL_VER_AREA,
4477
	    synaptics_sysctl, "I",
5307
	    synaptics_sysctl, "I",
4478
	    "Area reserved for vertical virtual scrolling");
5308
	    "Area reserved for vertical virtual scrolling");
4479
5309
Lines 4482-4489 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4482
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5312
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4483
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5313
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4484
	    "vscroll_min_delta", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5314
	    "vscroll_min_delta", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4485
	    &sc->syninfo.vscroll_min_delta,
5315
	    sc, SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA,
4486
	    SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA,
4487
	    synaptics_sysctl, "I",
5316
	    synaptics_sysctl, "I",
4488
	    "Minimum movement to consider virtual scrolling");
5317
	    "Minimum movement to consider virtual scrolling");
4489
5318
Lines 4492-4498 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4492
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5321
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4493
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5322
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4494
	    "vscroll_div_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5323
	    "vscroll_div_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4495
	    &sc->syninfo.vscroll_div_min, SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN,
5324
	    sc, SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN,
4496
	    synaptics_sysctl, "I",
5325
	    synaptics_sysctl, "I",
4497
	    "Divisor for fast scrolling");
5326
	    "Divisor for fast scrolling");
4498
5327
Lines 4501-4507 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4501
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5330
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4502
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5331
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4503
	    "vscroll_div_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5332
	    "vscroll_div_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4504
	    &sc->syninfo.vscroll_div_max, SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX,
5333
	    sc, SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX,
4505
	    synaptics_sysctl, "I",
5334
	    synaptics_sysctl, "I",
4506
	    "Divisor for slow scrolling");
5335
	    "Divisor for slow scrolling");
4507
5336
Lines 4510-4537 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4510
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5339
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4511
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5340
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4512
	    "touchpad_off", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5341
	    "touchpad_off", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4513
	    &sc->syninfo.touchpad_off, SYNAPTICS_SYSCTL_TOUCHPAD_OFF,
5342
	    sc, SYNAPTICS_SYSCTL_TOUCHPAD_OFF,
4514
	    synaptics_sysctl, "I",
5343
	    synaptics_sysctl, "I",
4515
	    "Turn off touchpad");
5344
	    "Turn off touchpad");
5345
5346
	sc->syninfo.softbuttons_y = 0;
5347
	sc->syninfo.softbutton2_x = 0;
5348
	sc->syninfo.softbutton3_x = 0;
5349
5350
	/* skip softbuttons sysctl on not clickpads */
5351
	if (sc->synhw.capClickPad)
5352
		synaptics_sysctl_create_softbuttons_tree(sc);
4516
}
5353
}
4517
5354
4518
static int
5355
static int
4519
synaptics_preferred_mode(struct psm_softc *sc) {
5356
synaptics_preferred_mode(struct psm_softc *sc) {
4520
	int mode_byte;
5357
	int mode_byte;
4521
5358
4522
	mode_byte = 0xc0;
5359
	mode_byte = 0xc4;
4523
5360
4524
	/* request wmode where available */
5361
	/* request wmode where available */
4525
	if (sc->synhw.capExtended)
5362
	if (sc->synhw.capExtended)
4526
		mode_byte |= 1;
5363
		mode_byte |= 1;
4527
5364
4528
	/*
4529
	 * Disable gesture processing when native packets are requested. This
4530
	 * enables sending of encapsulated "extended W mode" packets.
4531
	 */
4532
	if (sc->mode.level == PSM_LEVEL_NATIVE)
4533
		mode_byte |= (1 << 2);
4534
4535
	return mode_byte;
5365
	return mode_byte;
4536
}
5366
}
4537
5367
Lines 4546-4552 synaptics_set_mode(struct psm_softc *sc, int mode_byte) { Link Here
4546
	 * Enable advanced gestures mode if supported and we are not entering
5376
	 * Enable advanced gestures mode if supported and we are not entering
4547
	 * passthrough mode.
5377
	 * passthrough mode.
4548
	 */
5378
	 */
4549
	if (sc->synhw.capAdvancedGestures && !(mode_byte & (1 << 5))) {
5379
	if ((sc->synhw.capAdvancedGestures || sc->synhw.capReportsV) &&
5380
	    !(mode_byte & (1 << 5))) {
4550
		mouse_ext_command(sc->kbdc, 3);
5381
		mouse_ext_command(sc->kbdc, 3);
4551
		set_mouse_sampling_rate(sc->kbdc, 0xc8);
5382
		set_mouse_sampling_rate(sc->kbdc, 0xc8);
4552
	}
5383
	}
Lines 4754-4760 enable_synaptics(struct psm_softc *sc, enum probearg arg) Link Here
4754
						     ((status[1] & 0x0f) << 1);
5585
						     ((status[1] & 0x0f) << 1);
4755
				synhw.maximumYCoord = (status[2] << 5) |
5586
				synhw.maximumYCoord = (status[2] << 5) |
4756
						     ((status[1] & 0xf0) >> 3);
5587
						     ((status[1] & 0xf0) >> 3);
5588
			} else {
5589
				/*
5590
				 * Typical bezel limits. Taken from 'Synaptics
5591
				 * PS/2 * TouchPad Interfacing Guide' p.3.2.3.
5592
				 */
5593
				synhw.maximumXCoord = 5472;
5594
				synhw.maximumYCoord = 4448;
4757
			}
5595
			}
5596
4758
			if (synhw.capReportsMin) {
5597
			if (synhw.capReportsMin) {
4759
				if (!set_mouse_scaling(kbdc, 1))
5598
				if (!set_mouse_scaling(kbdc, 1))
4760
					return (FALSE);
5599
					return (FALSE);
Lines 4767-4772 enable_synaptics(struct psm_softc *sc, enum probearg arg) Link Here
4767
						     ((status[1] & 0x0f) << 1);
5606
						     ((status[1] & 0x0f) << 1);
4768
				synhw.minimumYCoord = (status[2] << 5) |
5607
				synhw.minimumYCoord = (status[2] << 5) |
4769
						     ((status[1] & 0xf0) >> 3);
5608
						     ((status[1] & 0xf0) >> 3);
5609
			} else {
5610
				/*
5611
				 * Typical bezel limits. Taken from 'Synaptics
5612
				 * PS/2 * TouchPad Interfacing Guide' p.3.2.3.
5613
				 */
5614
				synhw.minimumXCoord = 1472;
5615
				synhw.minimumYCoord = 1408;
4770
			}
5616
			}
4771
5617
4772
			if (verbose >= 2) {
5618
			if (verbose >= 2) {
Lines 4854-4860 enable_synaptics(struct psm_softc *sc, enum probearg arg) Link Here
4854
5700
4855
	if (arg == PROBE) {
5701
	if (arg == PROBE) {
4856
		/* Create sysctl tree. */
5702
		/* Create sysctl tree. */
4857
		synaptics_sysctl_create_tree(sc);
5703
		synaptics_sysctl_create_tree(sc, "synaptics",
5704
		    "Synaptics TouchPad");
4858
		sc->hw.buttons = buttons;
5705
		sc->hw.buttons = buttons;
4859
	}
5706
	}
4860
5707
Lines 5171-5176 enable_versapad(struct psm_softc *sc, enum probearg arg) Link Here
5171
	return (TRUE);				/* PS/2 absolute mode */
6018
	return (TRUE);				/* PS/2 absolute mode */
5172
}
6019
}
5173
6020
6021
/* Elantech Touchpad */
6022
static int
6023
elantech_read_1(KBDC kbdc, int hwversion, int reg, int *val)
6024
{
6025
	int res, readcmd, retidx;
6026
	int resp[3];
6027
6028
	readcmd = hwversion == 2 ? ELANTECH_REG_READ : ELANTECH_REG_RDWR;
6029
	retidx = hwversion == 4 ? 1 : 0;
6030
6031
	res = send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK;
6032
	res |= send_aux_command(kbdc, readcmd) != PSM_ACK;
6033
	res |= send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK;
6034
	res |= send_aux_command(kbdc, reg) != PSM_ACK;
6035
	res |= get_mouse_status(kbdc, resp, 0, 3) != 3;
6036
6037
	if (res == 0)
6038
		*val = resp[retidx];
6039
6040
	return (res);
6041
}
6042
6043
static int
6044
elantech_write_1(KBDC kbdc, int hwversion, int reg, int val)
6045
{
6046
	int res, writecmd;
6047
6048
	writecmd = hwversion == 2 ? ELANTECH_REG_WRITE : ELANTECH_REG_RDWR;
6049
6050
	res = send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK;
6051
	res |= send_aux_command(kbdc, writecmd) != PSM_ACK;
6052
	res |= send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK;
6053
	res |= send_aux_command(kbdc, reg) != PSM_ACK;
6054
	if (hwversion == 4) {
6055
		res |= send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK;
6056
		res |= send_aux_command(kbdc, writecmd) != PSM_ACK;
6057
	}
6058
	res |= send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK;
6059
	res |= send_aux_command(kbdc, val) != PSM_ACK;
6060
	res |= set_mouse_scaling(kbdc, 1) == 0;
6061
6062
	return (res);
6063
}
6064
6065
static int
6066
elantech_cmd(KBDC kbdc, int hwversion, int cmd, int *resp)
6067
{
6068
	int res;
6069
6070
	if (hwversion == 2) {
6071
		res = set_mouse_scaling(kbdc, 1) == 0;
6072
		res |= mouse_ext_command(kbdc, cmd) == 0;
6073
	} else {
6074
		res = send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK;
6075
		res |= send_aux_command(kbdc, cmd) != PSM_ACK;
6076
	}
6077
	res |= get_mouse_status(kbdc, resp, 0, 3) != 3;
6078
6079
	return (res);
6080
}
6081
6082
static int
6083
elantech_init(KBDC kbdc, elantechhw_t *elanhw)
6084
{
6085
	int i, val, res, hwversion, reg10;
6086
6087
	/* set absolute mode */
6088
	hwversion = elanhw->hwversion;
6089
	reg10 = -1;
6090
	switch (hwversion) {
6091
	case 2:
6092
		reg10 = elanhw->fwversion == 0x020030 ? 0x54 : 0xc4;
6093
		res = elantech_write_1(kbdc, hwversion, 0x10, reg10);
6094
		if (res)
6095
			break;
6096
		res = elantech_write_1(kbdc, hwversion, 0x11, 0x8A);
6097
		break;
6098
	case 3:
6099
		reg10 = 0x0b;
6100
		res = elantech_write_1(kbdc, hwversion, 0x10, reg10);
6101
		break;
6102
	case 4:
6103
		res = elantech_write_1(kbdc, hwversion, 0x07, 0x01);
6104
		break;
6105
	default:
6106
		res = 1;
6107
	}
6108
6109
	/* Read back reg 0x10 to ensure hardware is ready. */
6110
	if (res == 0 && reg10 >= 0) {
6111
		for (i = 0; i < 5; i++) {
6112
			if (elantech_read_1(kbdc, hwversion, 0x10, &val) == 0)
6113
				break;
6114
			DELAY(2000);
6115
		}
6116
		if (i == 5)
6117
			res = 1;
6118
	}
6119
6120
	if (res)
6121
		printf("couldn't set absolute mode\n");
6122
6123
	return (res);
6124
}
6125
6126
static void
6127
elantech_init_synaptics(struct psm_softc *sc)
6128
{
6129
6130
	/* Set capabilites required by movement smother */
6131
	sc->synhw.infoMajor = sc->elanhw.hwversion;
6132
	sc->synhw.infoMinor = sc->elanhw.fwversion;
6133
	sc->synhw.infoXupmm = sc->elanhw.dpmmx;
6134
	sc->synhw.infoYupmm = sc->elanhw.dpmmy;
6135
	sc->synhw.verticalScroll = 0;
6136
	sc->synhw.nExtendedQueries = 4;
6137
	sc->synhw.capExtended = 1;
6138
	sc->synhw.capPassthrough = sc->elanhw.hastrackpad;
6139
	sc->synhw.capClickPad = sc->elanhw.isclickpad;
6140
	sc->synhw.capMultiFinger = 1;
6141
	sc->synhw.capAdvancedGestures = 1;
6142
	sc->synhw.capPalmDetect = 1;
6143
	sc->synhw.capPen = 0;
6144
	sc->synhw.capReportsMax = 1;
6145
	sc->synhw.maximumXCoord = sc->elanhw.sizex;
6146
	sc->synhw.maximumYCoord = sc->elanhw.sizey;
6147
	sc->synhw.capReportsMin = 1;
6148
	sc->synhw.minimumXCoord = 0;
6149
	sc->synhw.minimumYCoord = 0;
6150
6151
	if (sc->syninfo.sysctl_tree == NULL) {
6152
		synaptics_sysctl_create_tree(sc, "elantech",
6153
		    "Elantech Touchpad");
6154
6155
		/*
6156
		 * Adjust synaptic smoother tunables
6157
		 * 1. Disable finger detection pressure threshold. Unlike
6158
		 *    synaptics we assume the finger is acting when packet with
6159
		 *    its X&Y arrives not when pressure exceedes some threshold
6160
		 * 2. Disable unrelated features like margins and noisy areas
6161
		 * 3. Disable virtual scroll areas as 2nd finger is preferable
6162
		 * 4. For clickpads set bottom quarter as 42% - 16% - 42% sized
6163
		 *    softbuttons
6164
		 * 5. Scale down divisors and movement lengths by a factor of 3
6165
		 *    where 3 is Synaptics to Elantech (~2200/800) dpi ratio
6166
		 */
6167
6168
		/* Set reporting range to be equal touchpad size */
6169
		sc->syninfo.max_x = sc->elanhw.sizex;
6170
		sc->syninfo.max_y = sc->elanhw.sizey;
6171
6172
		/* Disable finger detection pressure threshold */
6173
		sc->syninfo.min_pressure = 1;
6174
6175
		/* Use full area of touchpad */
6176
		sc->syninfo.margin_top = 0;
6177
		sc->syninfo.margin_right = 0;
6178
		sc->syninfo.margin_bottom = 0;
6179
		sc->syninfo.margin_left = 0;
6180
6181
		/* Disable noisy area */
6182
		sc->syninfo.na_top = 0;
6183
		sc->syninfo.na_right = 0;
6184
		sc->syninfo.na_bottom = 0;
6185
		sc->syninfo.na_left = 0;
6186
6187
		/* Tune divisors and movement lengths */
6188
		sc->syninfo.weight_len_squared = 200;
6189
		sc->syninfo.div_min = 3;
6190
		sc->syninfo.div_max = 6;
6191
		sc->syninfo.div_max_na = 10;
6192
		sc->syninfo.div_len = 30;
6193
		sc->syninfo.tap_max_delta = 25;
6194
6195
		/* Disable virtual scrolling areas and tune its divisors */
6196
		sc->syninfo.vscroll_hor_area = 0;
6197
		sc->syninfo.vscroll_ver_area = 0;
6198
		sc->syninfo.vscroll_min_delta = 15;
6199
		sc->syninfo.vscroll_div_min = 30;
6200
		sc->syninfo.vscroll_div_max = 50;
6201
6202
		/* Set bottom quarter as 42% - 16% - 42% sized softbuttons */
6203
		if (sc->elanhw.isclickpad) {
6204
			sc->syninfo.softbuttons_y = sc->elanhw.sizey / 4;
6205
			sc->syninfo.softbutton2_x = sc->elanhw.sizex * 11 / 25;
6206
			sc->syninfo.softbutton3_x = sc->elanhw.sizex * 14 / 25;
6207
		}
6208
	}
6209
6210
	return;
6211
}
6212
6213
static int
6214
enable_elantech(struct psm_softc *sc, enum probearg arg)
6215
{
6216
	static const int ic2hw[] =
6217
	/*IC: 0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f */
6218
	    { 0, 0, 2, 0, 2, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0 };
6219
	elantechhw_t elanhw;
6220
	int icversion, hwversion, dptracex, dptracey, id, resp[3], dpix, dpiy;
6221
	KBDC kbdc = sc->kbdc;
6222
6223
	VLOG(3, (LOG_DEBUG, "elantech: BEGIN init\n"));
6224
6225
	set_mouse_scaling(kbdc, 1);
6226
	set_mouse_scaling(kbdc, 1);
6227
	set_mouse_scaling(kbdc, 1);
6228
	if (get_mouse_status(kbdc, resp, 0, 3) != 3)
6229
		return (FALSE);
6230
6231
	if (!ELANTECH_MAGIC(resp))
6232
		return (FALSE);
6233
6234
	/* Identify the Touchpad version. */
6235
	if (elantech_cmd(kbdc, 2, ELANTECH_FW_VERSION, resp))
6236
		return (FALSE);
6237
6238
	bzero(&elanhw, sizeof(elanhw));
6239
6240
	elanhw.fwversion = (resp[0] << 16) | (resp[1] << 8) | resp[2];
6241
	icversion = resp[0] & 0x0f;
6242
	hwversion = ic2hw[icversion];
6243
6244
	if (verbose >= 2)
6245
		printf("Elantech touchpad hardware v.%d firmware v.0x%06x\n",
6246
		    hwversion, elanhw.fwversion);
6247
6248
	if (ELANTECH_HW_IS_V1(elanhw.fwversion)) {
6249
		printf ("  Unsupported touchpad hardware (v1)\n");
6250
		return (FALSE);
6251
	}
6252
	if (hwversion == 0) {
6253
		printf ("  Unknown touchpad hardware (firmware v.0x%06x)\n",
6254
		    elanhw.fwversion);
6255
		return (FALSE);
6256
	}
6257
6258
	/* Get the Touchpad model information. */
6259
	elanhw.hwversion = hwversion;
6260
	elanhw.issemimt = hwversion == 2;
6261
	elanhw.isclickpad = (resp[1] & 0x10) != 0;
6262
	elanhw.hascrc = (resp[1] & 0x40) != 0;
6263
	elanhw.haspressure = elanhw.fwversion >= 0x020800;
6264
6265
	/* Read the capability bits. */
6266
	if (elantech_cmd(kbdc, hwversion, ELANTECH_CAPABILITIES, resp) != 0) {
6267
		printf("  Failed to read capability bits\n");
6268
		return (FALSE);
6269
	}
6270
6271
	elanhw.ntracesx = resp[1] - 1;
6272
	elanhw.ntracesy = resp[2] - 1;
6273
	elanhw.hastrackpad = (resp[0] & 0x80) != 0;
6274
6275
	/* Get the touchpad resolution */
6276
	switch (hwversion) {
6277
	case 4:
6278
		if (elantech_cmd(kbdc, hwversion, ELANTECH_RESOLUTION, resp)
6279
		    == 0) {
6280
			dpix = (resp[1] & 0x0f) * 10 + 790;
6281
			dpiy = ((resp[1] & 0xf0) >> 4) * 10 + 790;
6282
			elanhw.dpmmx = (dpix * 10 + 5) / 254;
6283
			elanhw.dpmmy = (dpiy * 10 + 5) / 254;
6284
			break;
6285
		}
6286
		/* FALLTHROUGH */
6287
	case 2:
6288
	case 3:
6289
		elanhw.dpmmx = elanhw.dpmmy = 32; /* 800 dpi */
6290
		break;
6291
	}
6292
6293
	if (!elantech_support)
6294
		return (FALSE);
6295
6296
	if (elantech_init(kbdc, &elanhw)) {
6297
		printf("couldn't initialize elantech touchpad\n");
6298
		return (FALSE);
6299
	}
6300
6301
	/*
6302
	 * Get the touchpad reporting range.
6303
	 * On HW v.3 touchpads it should be done after switching hardware
6304
	 * to real resolution mode (by setting bit 3 of reg10)
6305
	 */
6306
	if (elantech_cmd(kbdc, hwversion, ELANTECH_FW_ID, resp) != 0) {
6307
		printf("  Failed to read touchpad size\n");
6308
		elanhw.sizex = 10000; /* Arbitrary high values to     */
6309
		elanhw.sizey = 10000; /* prevent clipping in smoother */
6310
	} else if (hwversion == 2) {
6311
		dptracex = dptracey = 64;
6312
		if ((elanhw.fwversion >> 16) == 0x14 && (resp[1] & 0x10) &&
6313
		    !elantech_cmd(kbdc, hwversion, ELANTECH_SAMPLE, resp)) {
6314
			dptracex = resp[1] / 2;
6315
			dptracey = resp[2] / 2;
6316
		}
6317
		elanhw.sizex = (elanhw.ntracesx - 1) * dptracex;
6318
		elanhw.sizey = (elanhw.ntracesy - 1) * dptracey;
6319
	} else {
6320
		elanhw.sizex = (resp[0] & 0x0f) << 8 | resp[1];
6321
		elanhw.sizey = (resp[0] & 0xf0) << 4 | resp[2];
6322
	}
6323
6324
	if (verbose >= 2) {
6325
		printf("  Model information:\n");
6326
		printf("   MaxX:     %d\n", elanhw.sizex);
6327
		printf("   MaxY:     %d\n", elanhw.sizey);
6328
		printf("   DpmmX:    %d\n", elanhw.dpmmx);
6329
		printf("   DpmmY:    %d\n", elanhw.dpmmy);
6330
		printf("   TracesX:  %d\n", elanhw.ntracesx);
6331
		printf("   TracesY:  %d\n", elanhw.ntracesy);
6332
		printf("   SemiMT:   %d\n", elanhw.issemimt);
6333
		printf("   Clickpad: %d\n", elanhw.isclickpad);
6334
		printf("   Trackpad: %d\n", elanhw.hastrackpad);
6335
		printf("   CRC:      %d\n", elanhw.hascrc);
6336
		printf("   Pressure: %d\n", elanhw.haspressure);
6337
	}
6338
6339
	VLOG(3, (LOG_DEBUG, "elantech: END init\n"));
6340
6341
	if (arg == PROBE) {
6342
		sc->elanhw = elanhw;
6343
		sc->hw.buttons = 3;
6344
6345
		/* Initialize synaptics movement smoother */
6346
		elantech_init_synaptics(sc);
6347
6348
		for (id = 0; id < ELANTECH_MAX_FINGERS; id++)
6349
			PSM_FINGER_RESET(sc->elanaction.fingers[id]);
6350
	}
6351
6352
	return (TRUE);
6353
}
6354
5174
/*
6355
/*
5175
 * Return true if 'now' is earlier than (start + (secs.usecs)).
6356
 * Return true if 'now' is earlier than (start + (secs.usecs)).
5176
 * Now may be NULL and the function will fetch the current time from
6357
 * Now may be NULL and the function will fetch the current time from
(-)b/sys/sys/mouse.h (+4 lines)
Lines 170-175 typedef struct synapticshw { Link Here
170
#define MOUSE_MODEL_4DPLUS		12
170
#define MOUSE_MODEL_4DPLUS		12
171
#define MOUSE_MODEL_SYNAPTICS		13
171
#define MOUSE_MODEL_SYNAPTICS		13
172
#define	MOUSE_MODEL_TRACKPOINT		14
172
#define	MOUSE_MODEL_TRACKPOINT		14
173
#define	MOUSE_MODEL_ELANTECH		15
173
174
174
typedef struct mousemode {
175
typedef struct mousemode {
175
	int protocol;		/* MOUSE_PROTO_XXX */
176
	int protocol;		/* MOUSE_PROTO_XXX */
Lines 240-245 typedef struct mousevar { Link Here
240
/* Synaptics Touchpad */
241
/* Synaptics Touchpad */
241
#define MOUSE_SYNAPTICS_PACKETSIZE	6	/* '3' works better */
242
#define MOUSE_SYNAPTICS_PACKETSIZE	6	/* '3' works better */
242
243
244
/* Elantech Touchpad */
245
#define MOUSE_ELANTECH_PACKETSIZE	6
246
243
/* Microsoft Serial mouse data packet */
247
/* Microsoft Serial mouse data packet */
244
#define MOUSE_MSS_PACKETSIZE	3
248
#define MOUSE_MSS_PACKETSIZE	3
245
#define MOUSE_MSS_SYNCMASK	0x40
249
#define MOUSE_MSS_SYNCMASK	0x40
(-)b/usr.sbin/moused/moused.c (+1 lines)
Lines 246-251 static symtab_t rmodels[] = { Link Here
246
    { "4D+ Mouse",		MOUSE_MODEL_4DPLUS,		0 },
246
    { "4D+ Mouse",		MOUSE_MODEL_4DPLUS,		0 },
247
    { "Synaptics Touchpad",	MOUSE_MODEL_SYNAPTICS,		0 },
247
    { "Synaptics Touchpad",	MOUSE_MODEL_SYNAPTICS,		0 },
248
    { "TrackPoint",		MOUSE_MODEL_TRACKPOINT,		0 },
248
    { "TrackPoint",		MOUSE_MODEL_TRACKPOINT,		0 },
249
    { "Elantech Touchpad",	MOUSE_MODEL_ELANTECH,		0 },
249
    { "generic",		MOUSE_MODEL_GENERIC,		0 },
250
    { "generic",		MOUSE_MODEL_GENERIC,		0 },
250
    { NULL,			MOUSE_MODEL_UNKNOWN,		0 },
251
    { NULL,			MOUSE_MODEL_UNKNOWN,		0 },
251
};
252
};

Return to bug 205690