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

Collapse All | Expand All

(-)b/sys/dev/atkbdc/psm.c (-463 / +1639 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;
2832
		int max_width, max_pressure;
2833
		int margin_top, margin_right, margin_bottom, margin_left;
3121
		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;
3122
		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;
3123
		int vscroll_hor_area, vscroll_ver_area;
2840
		int two_finger_scroll;
3124
		int two_finger_scroll;
2841
		int len, weight_prev_x, weight_prev_y;
3125
		int max_x, max_y;
2842
		int div_max_x, div_max_y, div_x, div_y;
2843
		int exiting_scroll;
2844
3126
2845
		/* Read sysctl. */
3127
		/* Read sysctl. */
2846
		/* XXX Verify values? */
3128
		/* XXX Verify values? */
2847
		max_width = sc->syninfo.max_width;
2848
		max_pressure = sc->syninfo.max_pressure;
2849
		margin_top = sc->syninfo.margin_top;
3129
		margin_top = sc->syninfo.margin_top;
2850
		margin_right = sc->syninfo.margin_right;
3130
		margin_right = sc->syninfo.margin_right;
2851
		margin_bottom = sc->syninfo.margin_bottom;
3131
		margin_bottom = sc->syninfo.margin_bottom;
2852
		margin_left = sc->syninfo.margin_left;
3132
		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;
3133
		window_min = sc->syninfo.window_min;
2858
		window_max = sc->syninfo.window_max;
3134
		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;
3135
		vscroll_hor_area = sc->syninfo.vscroll_hor_area;
2867
		vscroll_ver_area = sc->syninfo.vscroll_ver_area;
3136
		vscroll_ver_area = sc->syninfo.vscroll_ver_area;
2868
		two_finger_scroll = sc->syninfo.two_finger_scroll;
3137
		two_finger_scroll = sc->syninfo.two_finger_scroll;
2869
3138
		max_x = sc->syninfo.max_x;
2870
		exiting_scroll = 0;
3139
		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
3140
2895
		/* Read current absolute position. */
3141
		/* Read current absolute position. */
2896
		x0 = ((pb->ipacket[3] & 0x10) << 8) |
3142
		x0 = f->x;
2897
		    ((pb->ipacket[1] & 0x0f) << 8) |
3143
		y0 = f->y;
2898
		    pb->ipacket[4];
3144
2899
		y0 = ((pb->ipacket[3] & 0x20) << 7) |
3145
		/*
2900
		    ((pb->ipacket[1] & 0xf0) << 4) |
3146
		 * Limit the coordinates to the specified margins because
2901
		    pb->ipacket[5];
3147
		 * this area isn't very reliable.
3148
		 */
3149
		if (x0 <= margin_left)
3150
			x0 = margin_left;
3151
		else if (x0 >= max_x - margin_right)
3152
			x0 = max_x - margin_right;
3153
		if (y0 <= margin_bottom)
3154
			y0 = margin_bottom;
3155
		else if (y0 >= max_y - margin_top)
3156
			y0 = max_y - margin_top;
2902
3157
2903
		synaction = &(sc->synaction);
3158
		VLOG(3, (LOG_DEBUG, "synaptics: ipacket: [%d, %d], %d, %d\n",
3159
		    x0, y0, f->p, f->w));
2904
3160
2905
		/*
3161
		/*
2906
		 * If the action is just beginning, init the structure and
3162
		 * 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)) {
3165
		if (!(sc->flags & PSM_FLAGS_FINGERDOWN)) {
2910
			VLOG(3, (LOG_DEBUG, "synaptics: ----\n"));
3166
			VLOG(3, (LOG_DEBUG, "synaptics: ----\n"));
2911
3167
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. */
3168
			/* Initialize queue. */
2918
			synaction->queue_cursor = SYNAPTICS_PACKETQUEUE;
3169
			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
3170
2930
			/* Reset pressure peak. */
3171
			/* Reset pressure peak. */
2931
			sc->zmax = 0;
3172
			gest->zmax = 0;
2932
3173
2933
			/* Reset fingers count. */
3174
			/* Reset fingers count. */
2934
			synaction->fingers_nb = 0;
3175
			gest->fingers_nb = 0;
2935
3176
2936
			/* Reset virtual scrolling state. */
3177
			/* Reset virtual scrolling state. */
2937
			synaction->in_vscroll = 0;
3178
			gest->in_vscroll = 0;
2938
3179
2939
			/* Compute tap timeout. */
3180
			/* Compute tap timeout. */
2940
			sc->taptimeout.tv_sec  = tap_timeout / 1000000;
3181
			gest->taptimeout.tv_sec  = tap_timeout / 1000000;
2941
			sc->taptimeout.tv_usec = tap_timeout % 1000000;
3182
			gest->taptimeout.tv_usec = tap_timeout % 1000000;
2942
			timevaladd(&sc->taptimeout, &sc->lastsoftintr);
3183
			timevaladd(&gest->taptimeout, &sc->lastsoftintr);
2943
3184
2944
			sc->flags |= PSM_FLAGS_FINGERDOWN;
3185
			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
		}
3186
		}
2951
3187
2952
		/* If in tap-hold, add the recorded button. */
2953
		if (synaction->in_taphold)
2954
			ms->button |= synaction->tap_button;
2955
3188
2956
		/*
3189
		/* Process ClickPad softbuttons */
2957
		 * From now on, we can use the SYNAPTICS_END label to skip
3190
		if (sc->synhw.capClickPad && ms->button & MOUSE_BUTTON1DOWN) {
2958
		 * the current packet.
3191
			y_ok = sc->syninfo.softbuttons_y >= 0 ?
2959
		 */
3192
			    f->y < sc->syninfo.softbuttons_y :
3193
			    f->y > max_y - sc->syninfo.softbuttons_y;
2960
3194
2961
		/*
3195
			center_button = MOUSE_BUTTON2DOWN;
2962
		 * Limit the coordinates to the specified margins because
3196
			center_x = sc->syninfo.softbutton2_x;
2963
		 * this area isn't very reliable.
3197
			right_button = MOUSE_BUTTON3DOWN;
2964
		 */
3198
			right_x = sc->syninfo.softbutton3_x;
2965
		if (x0 <= margin_left)
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
			if (center_x > 0 && right_x > 0 && center_x > right_x) {
2975
		    x0, y0, *z, w));
3201
				center_button = MOUSE_BUTTON3DOWN;
3202
				center_x = sc->syninfo.softbutton3_x;
3203
				right_button = MOUSE_BUTTON2DOWN;
3204
				right_x = sc->syninfo.softbutton2_x;
3205
			}
2976
3206
2977
		/* Queue this new packet. */
3207
			if (right_x > 0 && smoother->start_x > right_x && y_ok)
2978
		cursor = SYNAPTICS_QUEUE_CURSOR(synaction->queue_cursor - 1);
3208
				ms->button = (ms->button &
2979
		synaction->queue[cursor].x = x0;
3209
				    ~MOUSE_BUTTON1DOWN) | right_button;
2980
		synaction->queue[cursor].y = y0;
3210
			else if (center_x > 0 &&
2981
		synaction->queue_cursor = cursor;
3211
				 smoother->start_x > center_x && y_ok)
2982
		if (synaction->queue_len < SYNAPTICS_PACKETQUEUE)
3212
				ms->button = (ms->button &
2983
			synaction->queue_len++;
3213
				    ~MOUSE_BUTTON1DOWN) | center_button;
2984
		VLOG(5, (LOG_DEBUG,
3214
		}
2985
		    "synaptics: cursor[%d]: x=%d, y=%d, dx=%d, dy=%d\n",
3215
2986
		    cursor, x0, y0, dx, dy));
3216
		/* If in tap-hold, add the recorded button. */
3217
		if (gest->in_taphold)
3218
			ms->button |= gest->tap_button;
2987
3219
2988
		/*
3220
		/*
2989
		 * For tap, we keep the maximum number of fingers and the
3221
		 * For tap, we keep the maximum number of fingers and the
2990
		 * pressure peak. Also with multiple fingers, we increase
3222
		 * pressure peak. Also with multiple fingers, we increase
2991
		 * the minimum window.
3223
		 * the minimum window.
2992
		 */
3224
		 */
2993
		switch (w) {
3225
		if (nfingers > 1)
2994
		case 1: /* Three or more fingers. */
3226
			gest->window_min = window_max;
2995
			synaction->fingers_nb = imax(3, synaction->fingers_nb);
3227
		gest->fingers_nb = imax(nfingers, gest->fingers_nb);
2996
			synaction->window_min = window_max;
3228
		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
3229
3007
		/* Do we have enough packets to consider this a movement? */
3230
		/* Do we have enough packets to consider this a gesture? */
3008
		if (synaction->queue_len < synaction->window_min)
3231
		if (smoother->queue_len + 1 < gest->window_min)
3009
			goto SYNAPTICS_END;
3232
			return;
3010
3233
3011
		/* Is a scrolling action occurring? */
3234
		/* Is a scrolling action occurring? */
3012
		if (!synaction->in_taphold && !synaction->in_vscroll) {
3235
		if (!gest->in_taphold && !ms->button &&
3236
		    (!gest->in_vscroll || two_finger_scroll)) {
3013
			/*
3237
			/*
3014
			 * A scrolling action must not conflict with a tap
3238
			 * A scrolling action must not conflict with a tap
3015
			 * action. Here are the conditions to consider a
3239
			 * 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
3244
			 *       first should be above a configurable minimum
3021
			 *     . tap timed out
3245
			 *     . tap timed out
3022
			 */
3246
			 */
3023
			dxp = abs(synaction->queue[synaction->queue_cursor].x -
3247
			dxp = abs(x0 - smoother->start_x);
3024
			    synaction->start_x);
3248
			dyp = abs(y0 - smoother->start_y);
3025
			dyp = abs(synaction->queue[synaction->queue_cursor].y -
3026
			    synaction->start_y);
3027
3249
3028
			if (timevalcmp(&sc->lastsoftintr, &sc->taptimeout, >) ||
3250
			if (timevalcmp(&sc->lastsoftintr, &gest->taptimeout, >) ||
3029
			    dxp >= sc->syninfo.vscroll_min_delta ||
3251
			    dxp >= sc->syninfo.vscroll_min_delta ||
3030
			    dyp >= sc->syninfo.vscroll_min_delta) {
3252
			    dyp >= sc->syninfo.vscroll_min_delta) {
3031
				/*
3253
				/*
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.
3256
				 * as that keeps the maximum number of fingers.
3035
				 */
3257
				 */
3036
				if (two_finger_scroll) {
3258
				if (two_finger_scroll) {
3037
					if (w == 0) {
3259
					if (nfingers == 2) {
3038
						synaction->in_vscroll +=
3260
						gest->in_vscroll +=
3039
						    dyp ? 2 : 0;
3261
						    dyp ? 2 : 0;
3040
						synaction->in_vscroll +=
3262
						gest->in_vscroll +=
3041
						    dxp ? 1 : 0;
3263
						    dxp ? 1 : 0;
3042
					}
3264
					}
3043
				} else {
3265
				} else {
3044
					/* Check for horizontal scrolling. */
3266
					/* Check for horizontal scrolling. */
3045
					if ((vscroll_hor_area > 0 &&
3267
					if ((vscroll_hor_area > 0 &&
3046
					    synaction->start_y <=
3268
					    smoother->start_y <=
3047
					        vscroll_hor_area) ||
3269
					        vscroll_hor_area) ||
3048
					    (vscroll_hor_area < 0 &&
3270
					    (vscroll_hor_area < 0 &&
3049
					     synaction->start_y >=
3271
					     smoother->start_y >=
3050
					     6143 + vscroll_hor_area))
3272
					     max_y + vscroll_hor_area))
3051
						synaction->in_vscroll += 2;
3273
						gest->in_vscroll += 2;
3052
3274
3053
					/* Check for vertical scrolling. */
3275
					/* Check for vertical scrolling. */
3054
					if ((vscroll_ver_area > 0 &&
3276
					if ((vscroll_ver_area > 0 &&
3055
					    synaction->start_x <=
3277
					    smoother->start_x <=
3056
						vscroll_ver_area) ||
3278
						vscroll_ver_area) ||
3057
					    (vscroll_ver_area < 0 &&
3279
					    (vscroll_ver_area < 0 &&
3058
					     synaction->start_x >=
3280
					     smoother->start_x >=
3059
					     6143 + vscroll_ver_area))
3281
					     max_x + vscroll_ver_area))
3060
						synaction->in_vscroll += 1;
3282
						gest->in_vscroll += 1;
3061
				}
3283
				}
3062
3284
3063
				/* Avoid conflicts if area overlaps. */
3285
				/* Avoid conflicts if area overlaps. */
3064
				if (synaction->in_vscroll >= 3)
3286
				if (gest->in_vscroll >= 3)
3065
					synaction->in_vscroll =
3287
					gest->in_vscroll =
3066
					    (dxp > dyp) ? 2 : 1;
3288
					    (dxp > dyp) ? 2 : 1;
3067
			}
3289
			}
3068
		}
3290
		}
3069
		/*
3291
		/*
3070
		 * Reset two finger scrolling when the number of fingers
3292
		 * Reset two finger scrolling when the number of fingers
3071
		 * is different from two.
3293
		 * is different from two or any button is pressed.
3072
		 */
3294
		 */
3073
		if (two_finger_scroll && w != 0 && synaction->in_vscroll != 0) {
3295
		if (two_finger_scroll && gest->in_vscroll != 0 &&
3074
			synaction->in_vscroll = 0;
3296
		    (nfingers != 2 || ms->button))
3075
			exiting_scroll = 1;
3297
			gest->in_vscroll = 0;
3076
		}
3077
3298
3078
		VLOG(5, (LOG_DEBUG,
3299
		VLOG(5, (LOG_DEBUG,
3079
			"synaptics: virtual scrolling: %s "
3300
			"synaptics: virtual scrolling: %s "
3080
			"(direction=%d, dxp=%d, dyp=%d, fingers=%d)\n",
3301
			"(direction=%d, dxp=%d, dyp=%d, fingers=%d)\n",
3081
			synaction->in_vscroll ? "YES" : "NO",
3302
			gest->in_vscroll ? "YES" : "NO",
3082
			synaction->in_vscroll, dxp, dyp,
3303
			gest->in_vscroll, dxp, dyp,
3083
			synaction->fingers_nb));
3304
			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
3305
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
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) {
3306
	} else if (sc->flags & PSM_FLAGS_FINGERDOWN) {
3192
		/*
3307
		/*
3193
		 * An action is currently taking place but the pressure
3308
		 * An action is currently taking place but the pressure
3194
		 * dropped under the minimum, putting an end to it.
3309
		 * dropped under the minimum, putting an end to it.
3195
		 */
3310
		 */
3196
		synapticsaction_t *synaction;
3197
		int taphold_timeout, dx, dy, tap_max_delta;
3311
		int taphold_timeout, dx, dy, tap_max_delta;
3198
3312
3199
		synaction = &(sc->synaction);
3313
		dx = abs(smoother->queue[smoother->queue_cursor].x -
3200
		dx = abs(synaction->queue[synaction->queue_cursor].x -
3314
		    smoother->start_x);
3201
		    synaction->start_x);
3315
		dy = abs(smoother->queue[smoother->queue_cursor].y -
3202
		dy = abs(synaction->queue[synaction->queue_cursor].y -
3316
		    smoother->start_y);
3203
		    synaction->start_y);
3204
3317
3205
		/* Max delta is disabled for multi-fingers tap. */
3318
		/* Max delta is disabled for multi-fingers tap. */
3206
		if (synaction->fingers_nb > 1)
3319
		if (gest->fingers_nb > 1)
3207
			tap_max_delta = imax(dx, dy);
3320
			tap_max_delta = imax(dx, dy);
3208
		else
3321
		else
3209
			tap_max_delta = sc->syninfo.tap_max_delta;
3322
			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,
3327
		VLOG(3, (LOG_DEBUG,
3215
		    "synaptics: zmax=%d, dx=%d, dy=%d, "
3328
		    "synaptics: zmax=%d, dx=%d, dy=%d, "
3216
		    "delta=%d, fingers=%d, queue=%d\n",
3329
		    "delta=%d, fingers=%d, queue=%d\n",
3217
		    sc->zmax, dx, dy, tap_max_delta, synaction->fingers_nb,
3330
		    gest->zmax, dx, dy, tap_max_delta, gest->fingers_nb,
3218
		    synaction->queue_len));
3331
		    smoother->queue_len));
3219
		if (!synaction->in_vscroll && sc->zmax >= tap_threshold &&
3332
		if (!gest->in_vscroll && gest->zmax >= tap_threshold &&
3220
		    timevalcmp(&sc->lastsoftintr, &sc->taptimeout, <=) &&
3333
		    timevalcmp(&sc->lastsoftintr, &gest->taptimeout, <=) &&
3221
		    dx <= tap_max_delta && dy <= tap_max_delta &&
3334
		    dx <= tap_max_delta && dy <= tap_max_delta &&
3222
		    synaction->queue_len >= sc->syninfo.tap_min_queue) {
3335
		    smoother->queue_len >= sc->syninfo.tap_min_queue) {
3223
			/*
3336
			/*
3224
			 * We have a tap if:
3337
			 * We have a tap if:
3225
			 *   - the maximum pressure went over tap_threshold
3338
			 *   - 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
3341
			 * To handle tap-hold, we must delay any button push to
3229
			 * the next action.
3342
			 * the next action.
3230
			 */
3343
			 */
3231
			if (synaction->in_taphold) {
3344
			if (gest->in_taphold) {
3232
				/*
3345
				/*
3233
				 * This is the second and last tap of a
3346
				 * This is the second and last tap of a
3234
				 * double tap action, not a tap-hold.
3347
				 * double tap action, not a tap-hold.
3235
				 */
3348
				 */
3236
				synaction->in_taphold = 0;
3349
				gest->in_taphold = 0;
3237
3350
3238
				/*
3351
				/*
3239
				 * For double-tap to work:
3352
				 * For double-tap to work:
Lines 3245-3346 proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms, Link Here
3245
				 */
3358
				 */
3246
				VLOG(2, (LOG_DEBUG,
3359
				VLOG(2, (LOG_DEBUG,
3247
				    "synaptics: button RELEASE: %d\n",
3360
				    "synaptics: button RELEASE: %d\n",
3248
				    synaction->tap_button));
3361
				    gest->tap_button));
3249
				sc->flags |= PSM_FLAGS_FINGERDOWN;
3362
				sc->flags |= PSM_FLAGS_FINGERDOWN;
3363
3364
				/* Schedule button press on next interrupt */
3365
				sc->idletimeout.tv_sec  = psmhz > 1 ?
3366
				    0 : 1;
3367
				sc->idletimeout.tv_usec = psmhz > 1 ?
3368
				    1000000 / psmhz : 0;
3250
			} else {
3369
			} else {
3251
				/*
3370
				/*
3252
				 * This is the first tap: we set the
3371
				 * This is the first tap: we set the
3253
				 * tap-hold state and notify the button
3372
				 * tap-hold state and notify the button
3254
				 * down event.
3373
				 * down event.
3255
				 */
3374
				 */
3256
				synaction->in_taphold = 1;
3375
				gest->in_taphold = 1;
3257
				taphold_timeout = sc->syninfo.taphold_timeout;
3376
				taphold_timeout = sc->syninfo.taphold_timeout;
3258
				sc->taptimeout.tv_sec  = taphold_timeout /
3377
				gest->taptimeout.tv_sec  = taphold_timeout /
3259
				    1000000;
3378
				    1000000;
3260
				sc->taptimeout.tv_usec = taphold_timeout %
3379
				gest->taptimeout.tv_usec = taphold_timeout %
3261
				    1000000;
3380
				    1000000;
3262
				timevaladd(&sc->taptimeout, &sc->lastsoftintr);
3381
				sc->idletimeout = gest->taptimeout;
3382
				timevaladd(&gest->taptimeout,
3383
				    &sc->lastsoftintr);
3263
3384
3264
				switch (synaction->fingers_nb) {
3385
				switch (gest->fingers_nb) {
3265
				case 3:
3386
				case 3:
3266
					synaction->tap_button =
3387
					gest->tap_button =
3267
					    MOUSE_BUTTON2DOWN;
3388
					    MOUSE_BUTTON2DOWN;
3268
					break;
3389
					break;
3269
				case 2:
3390
				case 2:
3270
					synaction->tap_button =
3391
					gest->tap_button =
3271
					    MOUSE_BUTTON3DOWN;
3392
					    MOUSE_BUTTON3DOWN;
3272
					break;
3393
					break;
3273
				default:
3394
				default:
3274
					synaction->tap_button =
3395
					gest->tap_button =
3275
					    MOUSE_BUTTON1DOWN;
3396
					    MOUSE_BUTTON1DOWN;
3276
				}
3397
				}
3277
				VLOG(2, (LOG_DEBUG,
3398
				VLOG(2, (LOG_DEBUG,
3278
				    "synaptics: button PRESS: %d\n",
3399
				    "synaptics: button PRESS: %d\n",
3279
				    synaction->tap_button));
3400
				    gest->tap_button));
3280
				ms->button |= synaction->tap_button;
3401
				ms->button |= gest->tap_button;
3281
			}
3402
			}
3282
		} else {
3403
		} else {
3283
			/*
3404
			/*
3284
			 * Not enough pressure or timeout: reset
3405
			 * Not enough pressure or timeout: reset
3285
			 * tap-hold state.
3406
			 * tap-hold state.
3286
			 */
3407
			 */
3287
			if (synaction->in_taphold) {
3408
			if (gest->in_taphold) {
3288
				VLOG(2, (LOG_DEBUG,
3409
				VLOG(2, (LOG_DEBUG,
3289
				    "synaptics: button RELEASE: %d\n",
3410
				    "synaptics: button RELEASE: %d\n",
3290
				    synaction->tap_button));
3411
				    gest->tap_button));
3291
				synaction->in_taphold = 0;
3412
				gest->in_taphold = 0;
3292
			} else {
3413
			} else {
3293
				VLOG(2, (LOG_DEBUG,
3414
				VLOG(2, (LOG_DEBUG,
3294
				    "synaptics: not a tap-hold\n"));
3415
				    "synaptics: not a tap-hold\n"));
3295
			}
3416
			}
3296
		}
3417
		}
3297
	} else if (!(sc->flags & PSM_FLAGS_FINGERDOWN) &&
3418
	} else if (!(sc->flags & PSM_FLAGS_FINGERDOWN) && gest->in_taphold) {
3298
	    sc->synaction.in_taphold) {
3299
		/*
3419
		/*
3300
		 * For a tap-hold to work, the button must remain down at
3420
		 * For a tap-hold to work, the button must remain down at
3301
		 * least until timeout (where the in_taphold flags will be
3421
		 * least until timeout (where the in_taphold flags will be
3302
		 * cleared) or during the next action.
3422
		 * cleared) or during the next action.
3303
		 */
3423
		 */
3304
		if (timevalcmp(&sc->lastsoftintr, &sc->taptimeout, <=)) {
3424
		if (timevalcmp(&sc->lastsoftintr, &gest->taptimeout, <=)) {
3305
			ms->button |= sc->synaction.tap_button;
3425
			ms->button |= gest->tap_button;
3306
		} else {
3426
		} else {
3307
			VLOG(2, (LOG_DEBUG,
3427
			VLOG(2, (LOG_DEBUG, "synaptics: button RELEASE: %d\n",
3308
			    "synaptics: button RELEASE: %d\n",
3428
			    gest->tap_button));
3309
			    sc->synaction.tap_button));
3429
			gest->in_taphold = 0;
3310
			sc->synaction.in_taphold = 0;
3311
		}
3430
		}
3312
	}
3431
	}
3313
3432
3314
SYNAPTICS_END:
3433
	return;
3434
}
3435
3436
static void
3437
psmsmoother(struct psm_softc *sc, finger_t *f, int smoother_id,
3438
    mousestatus_t *ms, int *x, int *y)
3439
{
3440
	smoother_t *smoother = &sc->smoother[smoother_id];
3441
	gesture_t *gest = &(sc->gesture);
3442
3315
	/*
3443
	/*
3316
	 * Use the extra buttons as a scrollwheel
3444
	 * Check pressure to detect a real wanted action on the
3317
	 *
3445
	 * touchpad.
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
	 */
3446
	 */
3329
3447
	if (f->p >= sc->syninfo.min_pressure) {
3330
	if (ms->button & MOUSE_BUTTON4DOWN) {
3448
		int x0, y0;
3331
		*z = -1;
3449
		int cursor, peer, window;
3332
		ms->button &= ~MOUSE_BUTTON4DOWN;
3450
		int dx, dy, dxp, dyp;
3333
	} else if (ms->button & MOUSE_BUTTON5DOWN) {
3451
		int max_width, max_pressure;
3452
		int margin_top, margin_right, margin_bottom, margin_left;
3453
		int na_top, na_right, na_bottom, na_left;
3454
		int window_min, window_max;
3455
		int multiplicator;
3456
		int weight_current, weight_previous, weight_len_squared;
3457
		int div_min, div_max, div_len;
3458
		int vscroll_hor_area, vscroll_ver_area;
3459
		int two_finger_scroll;
3460
		int max_x, max_y;
3461
		int len, weight_prev_x, weight_prev_y;
3462
		int div_max_x, div_max_y, div_x, div_y;
3463
		int is_fuzzy;
3464
3465
		/* Read sysctl. */
3466
		/* XXX Verify values? */
3467
		max_width = sc->syninfo.max_width;
3468
		max_pressure = sc->syninfo.max_pressure;
3469
		margin_top = sc->syninfo.margin_top;
3470
		margin_right = sc->syninfo.margin_right;
3471
		margin_bottom = sc->syninfo.margin_bottom;
3472
		margin_left = sc->syninfo.margin_left;
3473
		na_top = sc->syninfo.na_top;
3474
		na_right = sc->syninfo.na_right;
3475
		na_bottom = sc->syninfo.na_bottom;
3476
		na_left = sc->syninfo.na_left;
3477
		window_min = sc->syninfo.window_min;
3478
		window_max = sc->syninfo.window_max;
3479
		multiplicator = sc->syninfo.multiplicator;
3480
		weight_current = sc->syninfo.weight_current;
3481
		weight_previous = sc->syninfo.weight_previous;
3482
		weight_len_squared = sc->syninfo.weight_len_squared;
3483
		div_min = sc->syninfo.div_min;
3484
		div_max = sc->syninfo.div_max;
3485
		div_len = sc->syninfo.div_len;
3486
		vscroll_hor_area = sc->syninfo.vscroll_hor_area;
3487
		vscroll_ver_area = sc->syninfo.vscroll_ver_area;
3488
		two_finger_scroll = sc->syninfo.two_finger_scroll;
3489
		max_x = sc->syninfo.max_x;
3490
		max_y = sc->syninfo.max_y;
3491
3492
		is_fuzzy = (f->flags & PSM_FINGER_FUZZY) != 0;
3493
3494
		/* Read current absolute position. */
3495
		x0 = f->x;
3496
		y0 = f->y;
3497
3498
		/*
3499
		 * Limit the coordinates to the specified margins because
3500
		 * this area isn't very reliable.
3501
		 */
3502
		if (x0 <= margin_left)
3503
			x0 = margin_left;
3504
		else if (x0 >= max_x - margin_right)
3505
			x0 = max_x - margin_right;
3506
		if (y0 <= margin_bottom)
3507
			y0 = margin_bottom;
3508
		else if (y0 >= max_y - margin_top)
3509
			y0 = max_y - margin_top;
3510
3511
		/* If the action is just beginning, init the structure. */
3512
		if (smoother->active == 0) {
3513
			VLOG(3, (LOG_DEBUG, "smoother%d: ---\n", smoother_id));
3514
3515
			/* Store the first point of this action. */
3516
			smoother->start_x = x0;
3517
			smoother->start_y = y0;
3518
			dx = dy = 0;
3519
3520
			/* Initialize queue. */
3521
			smoother->queue_cursor = SYNAPTICS_PACKETQUEUE;
3522
			smoother->queue_len = 0;
3523
3524
			/* Reset average. */
3525
			smoother->avg_dx = 0;
3526
			smoother->avg_dy = 0;
3527
3528
			/* Reset squelch. */
3529
			smoother->squelch_x = 0;
3530
			smoother->squelch_y = 0;
3531
3532
			/* Activate queue */
3533
			smoother->active = 1;
3534
		} else {
3535
			/* Calculate the current delta. */
3536
			cursor = smoother->queue_cursor;
3537
			dx = x0 - smoother->queue[cursor].x;
3538
			dy = y0 - smoother->queue[cursor].y;
3539
		}
3540
3541
		VLOG(3, (LOG_DEBUG, "smoother%d: ipacket: [%d, %d], %d, %d\n",
3542
		    smoother_id, x0, y0, f->p, f->w));
3543
3544
		/* Queue this new packet. */
3545
		cursor = SYNAPTICS_QUEUE_CURSOR(smoother->queue_cursor - 1);
3546
		smoother->queue[cursor].x = x0;
3547
		smoother->queue[cursor].y = y0;
3548
		smoother->queue_cursor = cursor;
3549
		if (smoother->queue_len < SYNAPTICS_PACKETQUEUE)
3550
			smoother->queue_len++;
3551
		VLOG(5, (LOG_DEBUG,
3552
		    "smoother%d: cursor[%d]: x=%d, y=%d, dx=%d, dy=%d\n",
3553
		    smoother_id, cursor, x0, y0, dx, dy));
3554
3555
		/* Do we have enough packets to consider this a movement? */
3556
		if (smoother->queue_len < gest->window_min)
3557
			return;
3558
3559
		weight_prev_x = weight_prev_y = weight_previous;
3560
		div_max_x = div_max_y = div_max;
3561
3562
		if (gest->in_vscroll) {
3563
			/* Dividers are different with virtual scrolling. */
3564
			div_min = sc->syninfo.vscroll_div_min;
3565
			div_max_x = div_max_y = sc->syninfo.vscroll_div_max;
3566
		} else {
3567
			/*
3568
			 * There's a lot of noise in coordinates when
3569
			 * the finger is on the touchpad's borders. When
3570
			 * using this area, we apply a special weight and
3571
			 * div.
3572
			 */
3573
			if (x0 <= na_left || x0 >= max_x - na_right) {
3574
				weight_prev_x = sc->syninfo.weight_previous_na;
3575
				div_max_x = sc->syninfo.div_max_na;
3576
			}
3577
3578
			if (y0 <= na_bottom || y0 >= max_y - na_top) {
3579
				weight_prev_y = sc->syninfo.weight_previous_na;
3580
				div_max_y = sc->syninfo.div_max_na;
3581
			}
3582
		}
3583
3584
		/*
3585
		 * Calculate weights for the average operands and
3586
		 * the divisor. Both depend on the distance between
3587
		 * the current packet and a previous one (based on the
3588
		 * window width).
3589
		 */
3590
		window = imin(smoother->queue_len, window_max);
3591
		peer = SYNAPTICS_QUEUE_CURSOR(cursor + window - 1);
3592
		dxp = abs(x0 - smoother->queue[peer].x) + 1;
3593
		dyp = abs(y0 - smoother->queue[peer].y) + 1;
3594
		len = (dxp * dxp) + (dyp * dyp);
3595
		weight_prev_x = imin(weight_prev_x,
3596
		    weight_len_squared * weight_prev_x / len);
3597
		weight_prev_y = imin(weight_prev_y,
3598
		    weight_len_squared * weight_prev_y / len);
3599
3600
		len = (dxp + dyp) / 2;
3601
		div_x = div_len * div_max_x / len;
3602
		div_x = imin(div_max_x, div_x);
3603
		div_x = imax(div_min, div_x);
3604
		div_y = div_len * div_max_y / len;
3605
		div_y = imin(div_max_y, div_y);
3606
		div_y = imax(div_min, div_y);
3607
3608
		VLOG(3, (LOG_DEBUG,
3609
		    "smoother%d: peer=%d, len=%d, weight=%d/%d, div=%d/%d\n",
3610
		    smoother_id, peer, len, weight_prev_x, weight_prev_y,
3611
		    div_x, div_y));
3612
3613
		/* Compute averages. */
3614
		smoother->avg_dx =
3615
		    (weight_current * dx * multiplicator +
3616
		     weight_prev_x * smoother->avg_dx) /
3617
		    (weight_current + weight_prev_x);
3618
3619
		smoother->avg_dy =
3620
		    (weight_current * dy * multiplicator +
3621
		     weight_prev_y * smoother->avg_dy) /
3622
		    (weight_current + weight_prev_y);
3623
3624
		VLOG(5, (LOG_DEBUG,
3625
		    "smoother%d: avg_dx~=%d, avg_dy~=%d\n", smoother_id,
3626
		    smoother->avg_dx / multiplicator,
3627
		    smoother->avg_dy / multiplicator));
3628
3629
		/* Use these averages to calculate x & y. */
3630
		smoother->squelch_x += smoother->avg_dx;
3631
		dxp = smoother->squelch_x / (div_x * multiplicator);
3632
		smoother->squelch_x = smoother->squelch_x %
3633
		    (div_x * multiplicator);
3634
3635
		smoother->squelch_y += smoother->avg_dy;
3636
		dyp = smoother->squelch_y / (div_y * multiplicator);
3637
		smoother->squelch_y = smoother->squelch_y %
3638
		    (div_y * multiplicator);
3639
3640
		switch(gest->in_vscroll) {
3641
		case 0: /* Pointer movement. */
3642
			/* On real<->fuzzy finger switch the x/y pos jumps */
3643
			if (is_fuzzy == smoother->is_fuzzy) {
3644
				*x += dxp;
3645
				*y += dyp;
3646
			}
3647
3648
			VLOG(3, (LOG_DEBUG, "smoother%d: [%d, %d] -> [%d, %d]\n",
3649
			    smoother_id, dx, dy, dxp, dyp));
3650
			break;
3651
		case 1: /* Vertical scrolling. */
3652
			if (dyp != 0)
3653
				ms->button |= (dyp > 0) ?
3654
				    MOUSE_BUTTON4DOWN : MOUSE_BUTTON5DOWN;
3655
			break;
3656
		case 2: /* Horizontal scrolling. */
3657
			if (dxp != 0)
3658
				ms->button |= (dxp > 0) ?
3659
				    MOUSE_BUTTON7DOWN : MOUSE_BUTTON6DOWN;
3660
			break;
3661
		}
3662
3663
		smoother->is_fuzzy = is_fuzzy;
3664
3665
	} else {
3666
		/*
3667
		 * Deactivate queue. Note: We can not just reset queue here
3668
		 * as these values are still used by gesture processor.
3669
		 * So postpone reset till next touch.
3670
		 */
3671
		smoother->active = 0;
3672
	}
3673
}
3674
3675
static int
3676
proc_elantech(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
3677
    int *x, int *y, int *z)
3678
{
3679
	static int touchpad_button, trackpoint_button;
3680
	finger_t fn, f[ELANTECH_MAX_FINGERS];
3681
	int pkt, id, scale, i, nfingers, mask;
3682
3683
	if (!elantech_support)
3684
		return (0);
3685
3686
	/* Determine packet format and do a sanity check for out of sync packets. */
3687
	if (ELANTECH_PKT_IS_DEBOUNCE(pb, sc->elanhw.hwversion))
3688
		pkt = ELANTECH_PKT_NOP;
3689
	else if (ELANTECH_PKT_IS_TRACKPOINT(pb))
3690
		pkt = ELANTECH_PKT_TRACKPOINT;
3691
	else
3692
	switch (sc->elanhw.hwversion) {
3693
	case 2:
3694
		if (!ELANTECH_PKT_IS_V2(pb))
3695
			return (-1);
3696
3697
		pkt = (pb->ipacket[0] & 0xc0) == 0x80 ?
3698
		    ELANTECH_PKT_V2_2FINGER : ELANTECH_PKT_V2_COMMON;
3699
		break;
3700
	case 3:
3701
		if (!ELANTECH_PKT_IS_V3_HEAD(pb, sc->elanhw.hascrc) &&
3702
		    !ELANTECH_PKT_IS_V3_TAIL(pb, sc->elanhw.hascrc))
3703
			return (-1);
3704
3705
		pkt = ELANTECH_PKT_V3;
3706
		break;
3707
	case 4:
3708
		if (!ELANTECH_PKT_IS_V4(pb, sc->elanhw.hascrc))
3709
			return (-1);
3710
3711
		switch (pb->ipacket[3] & 0x03) {
3712
		case 0x00:
3713
			pkt = ELANTECH_PKT_V4_STATUS;
3714
			break;
3715
		case 0x01:
3716
			pkt = ELANTECH_PKT_V4_HEAD;
3717
			break;
3718
		case 0x02:
3719
			pkt = ELANTECH_PKT_V4_MOTION;
3720
			break;
3721
		default:
3722
			return (-1);
3723
		}
3724
		break;
3725
	default:
3726
		return (-1);
3727
	}
3728
3729
	VLOG(5, (LOG_DEBUG, "elantech: ipacket format: %d\n", pkt));
3730
3731
	for (id = 0; id < ELANTECH_MAX_FINGERS; id++)
3732
		PSM_FINGER_RESET(f[id]);
3733
3734
	*x = *y = *z = 0;
3735
	ms->button = ms->obutton;
3736
3737
	if (sc->syninfo.touchpad_off)
3738
		return (0);
3739
3740
	/* Common legend
3741
	 * L: Left mouse button pressed
3742
	 * R: Right mouse button pressed
3743
	 * N: number of fingers on touchpad
3744
	 * X: absolute x value (horizontal)
3745
	 * Y: absolute y value (vertical)
3746
	 * W; width of the finger touch
3747
	 * P: pressure
3748
	 */
3749
	switch (pkt) {
3750
	case ELANTECH_PKT_V2_COMMON:	/* HW V2. One/Three finger touch */
3751
		/*               7   6   5   4   3   2   1   0 (LSB)
3752
		 * -------------------------------------------
3753
		 * ipacket[0]:  N1  N0  W3  W2   .   .   R   L
3754
		 * ipacket[1]:  P7  P6  P5  P4 X11 X10  X9  X8
3755
		 * ipacket[2]:  X7  X6  X5  X4  X3  X2  X1  X0
3756
		 * ipacket[3]:  N4  VF  W1  W0   .   .   .  B2
3757
		 * ipacket[4]:  P3  P1  P2  P0 Y11 Y10  Y9  Y8
3758
		 * ipacket[5]:  Y7  Y6  Y5  Y4  Y3  Y2  Y1  Y0
3759
		 * -------------------------------------------
3760
		 * N4: set if more than 3 fingers (only in 3 fingers mode)
3761
		 * VF: a kind of flag? (only on EF123, 0 when finger
3762
		 *     is over one of the buttons, 1 otherwise)
3763
		 * B2: (on EF113 only, 0 otherwise), one button pressed
3764
		 * P & W is not reported on EF113 touchpads
3765
		 */
3766
		nfingers = (pb->ipacket[0] & 0xc0) >> 6;
3767
		if (nfingers == 3 && (pb->ipacket[3] & 0x80))
3768
			nfingers = 4;
3769
		mask = (1 << nfingers) - 1;
3770
3771
		fn = ELANTECH_FINGER_SET_XYP(pb);
3772
		if (sc->elanhw.haspressure) {
3773
			fn.w = ((pb->ipacket[0] & 0x30) >> 2) |
3774
			    ((pb->ipacket[3] & 0x30) >> 4);
3775
		} else {
3776
			fn.p = PSM_FINGER_DEFAULT_P;
3777
			fn.w = PSM_FINGER_DEFAULT_W;
3778
		}
3779
3780
		/*
3781
		 * HW v2 dont report exact finger positions when 3 or more
3782
		 * fingers are on touchpad. Use reported value as fingers
3783
		 * position as it is required for tap detection
3784
		 */
3785
		if (nfingers > 2)
3786
			fn.flags = PSM_FINGER_FUZZY;
3787
3788
		for (id = 0; id < imin(nfingers, ELANTECH_MAX_FINGERS); id++)
3789
			f[id] = fn;
3790
		break;
3791
3792
	case ELANTECH_PKT_V2_2FINGER:	/*HW V2. Two finger touch */
3793
		/*               7   6   5   4   3   2   1   0 (LSB)
3794
		 * -------------------------------------------
3795
		 * ipacket[0]:  N1  N0 AY8 AX8   .   .   R   L
3796
		 * ipacket[1]: AX7 AX6 AX5 AX4 AX3 AX2 AX1 AX0
3797
		 * ipacket[2]: AY7 AY6 AY5 AY4 AY3 AY2 AY1 AY0
3798
		 * ipacket[3]:   .   . BY8 BX8   .   .   .   .
3799
		 * ipacket[4]: BX7 BX6 BX5 BX4 BX3 BX2 BX1 BX0
3800
		 * ipacket[5]: BY7 BY6 BY5 BY4 BY3 BY2 BY1 BY0
3801
		 * -------------------------------------------
3802
		 * AX: lower-left finger absolute x value
3803
		 * AY: lower-left finger absolute y value
3804
		 * BX: upper-right finger absolute x value
3805
		 * BY: upper-right finger absolute y value
3806
		 */
3807
		nfingers = 2;
3808
		mask = (1 << nfingers) - 1;
3809
3810
		for (id = 0; id < imin(2, ELANTECH_MAX_FINGERS); id ++)
3811
			f[id] = (finger_t) {
3812
				.x = (((pb->ipacket[id * 3] & 0x10) << 4) |
3813
				    pb->ipacket[id * 3 + 1]) << 2,
3814
				.y = (((pb->ipacket[id * 3] & 0x20) << 3) |
3815
				    pb->ipacket[id * 3 + 2]) << 2,
3816
				.p = PSM_FINGER_DEFAULT_P,
3817
				.w = PSM_FINGER_DEFAULT_W,
3818
				/* HW ver.2 sends bounding box */
3819
				.flags = PSM_FINGER_FUZZY
3820
			};
3821
		break;
3822
3823
	case ELANTECH_PKT_V3:	/* HW Version 3 */
3824
		/*               7   6   5   4   3   2   1   0 (LSB)
3825
		 * -------------------------------------------
3826
		 * ipacket[0]:  N1  N0  W3  W2   0   1   R   L
3827
		 * ipacket[1]:  P7  P6  P5  P4 X11 X10  X9  X8
3828
		 * ipacket[2]:  X7  X6  X5  X4  X3  X2  X1  X0
3829
		 * ipacket[3]:   0   0  W1  W0   0   0   1   0
3830
		 * ipacket[4]:  P3  P1  P2  P0 Y11 Y10  Y9  Y8
3831
		 * ipacket[5]:  Y7  Y6  Y5  Y4  Y3  Y2  Y1  Y0
3832
		 * -------------------------------------------
3833
		 */
3834
		nfingers = (pb->ipacket[0] & 0xc0) >> 6;
3835
		mask = (1 << nfingers) - 1;
3836
		id = nfingers - 1;
3837
3838
		fn = ELANTECH_FINGER_SET_XYP(pb);
3839
		fn.w = ((pb->ipacket[0] & 0x30) >> 2) |
3840
		    ((pb->ipacket[3] & 0x30) >> 4);
3841
3842
		/*
3843
		 * HW v3 dont report exact finger positions when 3 or more
3844
		 * fingers are on touchpad. Use reported value as fingers
3845
		 * position as it is required for tap detection
3846
		 */
3847
		if (nfingers > 1)
3848
			fn.flags = PSM_FINGER_FUZZY;
3849
3850
		for (id = 0; id < imin(nfingers, ELANTECH_MAX_FINGERS); id++)
3851
			f[id] = fn;
3852
3853
		if (nfingers == 2) {
3854
			if (ELANTECH_PKT_IS_V3_HEAD(pb, sc->elanhw.hascrc)) {
3855
				sc->elanaction.fingers[0] = fn;
3856
				return (0);
3857
			} else
3858
				f[0] = sc->elanaction.fingers[0];
3859
		}
3860
		break;
3861
3862
	case ELANTECH_PKT_V4_STATUS:	/* HW Version 4. Status packet */
3863
		/*               7   6   5   4   3   2   1   0 (LSB)
3864
		 * -------------------------------------------
3865
		 * ipacket[0]:   .   .   .   .   0   1   R   L
3866
		 * ipacket[1]:   .   .   .  F4  F3  F2  F1  F0
3867
		 * ipacket[2]:   .   .   .   .   .   .   .   .
3868
		 * ipacket[3]:   .   .   .   1   0   0   0   0
3869
		 * ipacket[4]:  PL   .   .   .   .   .   .   .
3870
		 * ipacket[5]:   .   .   .   .   .   .   .   .
3871
		 * -------------------------------------------
3872
		 * Fn: finger n is on touchpad
3873
		 * PL: palm
3874
		 * HV ver4 sends a status packet to indicate that the numbers
3875
		 * or identities of the fingers has been changed
3876
		 */
3877
3878
		mask = pb->ipacket[1] & 0x1f;
3879
		nfingers = bitcount(mask);
3880
3881
		/* Skip "new finger is on touchpad" packets */
3882
		if ((sc->elanaction.mask & mask) == sc->elanaction.mask &&
3883
		    (mask & ~sc->elanaction.mask)) {
3884
			sc->elanaction.mask = mask;
3885
			return (0);
3886
		}
3887
3888
		break;
3889
3890
	case ELANTECH_PKT_V4_HEAD:	/* HW Version 4. Head packet */
3891
		/*               7   6   5   4   3   2   1   0 (LSB)
3892
		 * -------------------------------------------
3893
		 * ipacket[0]:  W3  W2  W1  W0   0   1   R   L
3894
		 * ipacket[1]:  P7  P6  P5  P4 X11 X10  X9  X8
3895
		 * ipacket[2]:  X7  X6  X5  X4  X3  X2  X1  X0
3896
		 * ipacket[3]: ID2 ID1 ID0   1   0   0   0   1
3897
		 * ipacket[4]:  P3  P1  P2  P0 Y11 Y10  Y9  Y8
3898
		 * ipacket[5]:  Y7  Y6  Y5  Y4  Y3  Y2  Y1  Y0
3899
		 * -------------------------------------------
3900
		 * ID: finger id
3901
		 * HW ver 4 sends head packets in two cases:
3902
		 * 1. One finger touch and movement.
3903
		 * 2. Next after status packet to tell new finger positions.
3904
		 */
3905
		mask = sc->elanaction.mask;
3906
		nfingers = bitcount(mask);
3907
		id = ((pb->ipacket[3] & 0xe0) >> 5) - 1;
3908
3909
		if (id >= 0 && id < ELANTECH_MAX_FINGERS) {
3910
			f[id] = ELANTECH_FINGER_SET_XYP(pb);
3911
			f[id].w = (pb->ipacket[0] & 0xf0) >> 4;
3912
		}
3913
		break;
3914
3915
	case ELANTECH_PKT_V4_MOTION:	/* HW Version 4. Motion packet */
3916
		/*               7   6   5   4   3   2   1   0 (LSB)
3917
		 * -------------------------------------------
3918
		 * ipacket[0]: ID2 ID1 ID0  OF   0   1   R   L
3919
		 * ipacket[1]: DX7 DX6 DX5 DX4 DX3 DX2 DX1 DX0
3920
		 * ipacket[2]: DY7 DY6 DY5 DY4 DY3 DY2 DY1 DY0
3921
		 * ipacket[3]: ID2 ID1 ID0   1   0   0   1   0
3922
		 * ipacket[4]: DX7 DX6 DX5 DX4 DX3 DX2 DX1 DX0
3923
		 * ipacket[5]: DY7 DY6 DY5 DY4 DY3 DY2 DY1 DY0
3924
		 * -------------------------------------------
3925
		 * OF: delta overflows (> 127 or < -128), in this case
3926
		 *     firmware sends us (delta x / 5) and (delta y / 5)
3927
		 * ID: finger id
3928
		 * DX: delta x (two's complement)
3929
		 * XY: delta y (two's complement)
3930
		 * byte 0 ~ 2 for one finger
3931
		 * byte 3 ~ 5 for another finger
3932
		 */
3933
		mask = sc->elanaction.mask;
3934
		nfingers = bitcount(mask);
3935
3936
		scale = (pb->ipacket[0] & 0x10) ? 5 : 1;
3937
		for (i = 0; i <= 3; i += 3) {
3938
			id = ((pb->ipacket[i] & 0xe0) >> 5) - 1;
3939
			if (id < 0 || id >= ELANTECH_MAX_FINGERS)
3940
				continue;
3941
3942
			if (PSM_FINGER_IS_SET(sc->elanaction.fingers[id])) {
3943
				f[id] = sc->elanaction.fingers[id];
3944
				f[id].x += imax(-f[id].x,
3945
				    (signed char)pb->ipacket[i+1] * scale);
3946
				f[id].y += imax(-f[id].y,
3947
				    (signed char)pb->ipacket[i+2] * scale);
3948
			} else {
3949
				VLOG(3, (LOG_DEBUG, "elantech: "
3950
				    "HW v4 motion packet skipped\n"));
3951
			}
3952
		}
3953
3954
		break;
3955
3956
	case ELANTECH_PKT_TRACKPOINT:
3957
		/*               7   6   5   4   3   2   1   0 (LSB)
3958
		 * -------------------------------------------
3959
		 * ipacket[0]:   0   0  SX  SY   0   M   R   L
3960
		 * ipacket[1]: ~SX   0   0   0   0   0   0   0
3961
		 * ipacket[2]: ~SY   0   0   0   0   0   0   0
3962
		 * ipacket[3]:   0   0 ~SY ~SX   0   1   1   0
3963
		 * ipacket[4]:  X7  X6  X5  X4  X3  X2  X1  X0
3964
		 * ipacket[5]:  Y7  Y6  Y5  Y4  Y3  Y2  Y1  Y0
3965
		 * -------------------------------------------
3966
		 * X and Y are written in two's complement spread
3967
		 * over 9 bits with SX/SY the relative top bit and
3968
		 * X7..X0 and Y7..Y0 the lower bits.
3969
		 */
3970
		*x = (pb->ipacket[0] & 0x20) ?
3971
		    pb->ipacket[4] - 256 : pb->ipacket[4];
3972
		*y = (pb->ipacket[0] & 0x10) ?
3973
		    pb->ipacket[5] - 256 : pb->ipacket[5];
3974
3975
		trackpoint_button =
3976
		    ((pb->ipacket[0] & 0x01) ? MOUSE_BUTTON1DOWN : 0) |
3977
		    ((pb->ipacket[0] & 0x02) ? MOUSE_BUTTON3DOWN : 0) |
3978
		    ((pb->ipacket[0] & 0x04) ? MOUSE_BUTTON2DOWN : 0);
3979
3980
		ms->button = touchpad_button | trackpoint_button;
3981
		return (0);
3982
3983
	case ELANTECH_PKT_NOP:
3984
		return (0);
3985
3986
	default:
3987
		return (-1);
3988
	}
3989
3990
	for (id = 0; id < ELANTECH_MAX_FINGERS; id++)
3991
		if (PSM_FINGER_IS_SET(f[id]))
3992
			VLOG(2, (LOG_DEBUG, "elantech: "
3993
			    "finger %d: down [%d, %d], %d, %d, %d\n", id + 1,
3994
			    f[id].x, f[id].y, f[id].p, f[id].w, f[id].flags));
3995
3996
	/* Touchpad button presses */
3997
	if (sc->elanhw.isclickpad) {
3998
		touchpad_button =
3999
		    ((pb->ipacket[0] & 0x03) ? MOUSE_BUTTON1DOWN : 0);
4000
	} else {
4001
		touchpad_button =
4002
		    ((pb->ipacket[0] & 0x01) ? MOUSE_BUTTON1DOWN : 0) |
4003
		    ((pb->ipacket[0] & 0x02) ? MOUSE_BUTTON3DOWN : 0);
4004
	}
4005
4006
	ms->button = touchpad_button | trackpoint_button;
4007
4008
	/* Palm detection doesn't terminate the current action. */
4009
	if (!psmpalmdetect(sc, &f[0], nfingers)) {
4010
		/* Send finger 1 position to gesture processor */
4011
		if (PSM_FINGER_IS_SET(f[0]) || PSM_FINGER_IS_SET(f[1]) ||
4012
		    nfingers == 0)
4013
			psmgestures(sc, &f[0], imin(nfingers, 3), ms);
4014
		/* Send fingers positions to movement smoothers */
4015
		for (id = 0; id < PSM_FINGERS; id++)
4016
			if (PSM_FINGER_IS_SET(f[id]) || !(mask & (1 << id)))
4017
				psmsmoother(sc, &f[id], id, ms, x, y);
4018
	} else {
4019
		VLOG(2, (LOG_DEBUG, "elantech: palm detected! (%d)\n",
4020
		    f[0].w));
4021
	}
4022
4023
	/* Store current finger positions in action context */
4024
	for (id = 0; id < ELANTECH_MAX_FINGERS; id++) {
4025
		if (PSM_FINGER_IS_SET(f[id]))
4026
			sc->elanaction.fingers[id] = f[id];
4027
		if ((sc->elanaction.mask & (1 << id)) && !(mask & (1 << id)))
4028
			PSM_FINGER_RESET(sc->elanaction.fingers[id]);
4029
	}
4030
	sc->elanaction.mask = mask;
4031
4032
	/* Use the extra buttons as a scrollwheel */
4033
	if (ms->button & MOUSE_BUTTON4DOWN)
4034
		*z = -1;
4035
	else if (ms->button & MOUSE_BUTTON5DOWN)
3334
		*z = 1;
4036
		*z = 1;
3335
		ms->button &= ~MOUSE_BUTTON5DOWN;
4037
	else if (ms->button & MOUSE_BUTTON6DOWN)
3336
	} else if (ms->button & MOUSE_BUTTON6DOWN) {
3337
		*z = -2;
4038
		*z = -2;
3338
		ms->button &= ~MOUSE_BUTTON6DOWN;
4039
	else if (ms->button & MOUSE_BUTTON7DOWN)
3339
	} else if (ms->button & MOUSE_BUTTON7DOWN) {
3340
		*z = 2;
4040
		*z = 2;
3341
		ms->button &= ~MOUSE_BUTTON7DOWN;
4041
	else
3342
	} else
3343
		*z = 0;
4042
		*z = 0;
4043
	ms->button &= ~(MOUSE_BUTTON4DOWN | MOUSE_BUTTON5DOWN |
4044
	    MOUSE_BUTTON6DOWN | MOUSE_BUTTON7DOWN);
3344
4045
3345
	return (0);
4046
	return (0);
3346
}
4047
}
Lines 3413-3418 proc_versapad(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms, Link Here
3413
}
4114
}
3414
4115
3415
static void
4116
static void
4117
psmsoftintridle(void *arg)
4118
{
4119
	struct psm_softc *sc = arg;
4120
	packetbuf_t *pb;
4121
4122
	/* Invoke soft handler only when pqueue is empty. Otherwise it will be
4123
	 * invoked from psmintr soon with pqueue filled with real data */
4124
	if (sc->pqueue_start == sc->pqueue_end &&
4125
	    sc->idlepacket.inputbytes > 0) {
4126
		/* Grow circular queue backwards to avoid race with psmintr */
4127
		if (--sc->pqueue_start < 0)
4128
			sc->pqueue_start = PSM_PACKETQUEUE - 1;
4129
4130
		pb = &sc->pqueue[sc->pqueue_start];
4131
		memcpy(pb, &sc->idlepacket, sizeof(packetbuf_t));
4132
		VLOG(4, (LOG_DEBUG,
4133
		    "psmsoftintridle: %02x %02x %02x %02x %02x %02x\n",
4134
		    pb->ipacket[0], pb->ipacket[1], pb->ipacket[2],
4135
		    pb->ipacket[3], pb->ipacket[4], pb->ipacket[5]));
4136
4137
		psmsoftintr(arg);
4138
	}
4139
}
4140
4141
static void
3416
psmsoftintr(void *arg)
4142
psmsoftintr(void *arg)
3417
{
4143
{
3418
	/*
4144
	/*
Lines 3465-3470 psmsoftintr(void *arg) Link Here
3465
		if (sc->config & PSM_CONFIG_FORCETAP)
4191
		if (sc->config & PSM_CONFIG_FORCETAP)
3466
			ms.button |= ((c & MOUSE_PS2_TAP)) ?
4192
			ms.button |= ((c & MOUSE_PS2_TAP)) ?
3467
			    0 : MOUSE_BUTTON4DOWN;
4193
			    0 : MOUSE_BUTTON4DOWN;
4194
		timevalclear(&sc->idletimeout);
4195
		sc->idlepacket.inputbytes = 0;
3468
4196
3469
		switch (sc->hw.model) {
4197
		switch (sc->hw.model) {
3470
4198
Lines 3603-3608 psmsoftintr(void *arg) Link Here
3603
				goto next;
4331
				goto next;
3604
			break;
4332
			break;
3605
4333
4334
		case MOUSE_MODEL_ELANTECH:
4335
			if (proc_elantech(sc, pb, &ms, &x, &y, &z) != 0)
4336
				goto next;
4337
			break;
4338
3606
		case MOUSE_MODEL_TRACKPOINT:
4339
		case MOUSE_MODEL_TRACKPOINT:
3607
		case MOUSE_MODEL_GENERIC:
4340
		case MOUSE_MODEL_GENERIC:
3608
		default:
4341
		default:
Lines 3627-3632 psmsoftintr(void *arg) Link Here
3627
		}
4360
		}
3628
	}
4361
	}
3629
4362
4363
	/* Store last packet for reinjection if it has not been set already */
4364
	if (timevalisset(&sc->idletimeout) && sc->idlepacket.inputbytes == 0)
4365
		sc->idlepacket = *pb;
4366
3630
	ms.dx = x;
4367
	ms.dx = x;
3631
	ms.dy = y;
4368
	ms.dy = y;
3632
	ms.dz = z;
4369
	ms.dz = z;
Lines 3673-3678 next: Link Here
3673
		pgsigio(&sc->async, SIGIO, 0);
4410
		pgsigio(&sc->async, SIGIO, 0);
3674
	}
4411
	}
3675
	sc->state &= ~PSM_SOFTARMED;
4412
	sc->state &= ~PSM_SOFTARMED;
4413
4414
	/* schedule injection of predefined packet after idletimeout
4415
	 * if no data packets have been received from psmintr */
4416
	if (timevalisset(&sc->idletimeout)) {
4417
		sc->state |= PSM_SOFTARMED;
4418
		callout_reset(&sc->softcallout, tvtohz(&sc->idletimeout),
4419
		    psmsoftintridle, sc);
4420
		VLOG(2, (LOG_DEBUG, "softintr: callout set: %d ticks\n",
4421
		    tvtohz(&sc->idletimeout)));
4422
	}
3676
	splx(s);
4423
	splx(s);
3677
}
4424
}
3678
4425
Lines 4106-4115 enable_4dplus(struct psm_softc *sc, enum probearg arg) Link Here
4106
static int
4853
static int
4107
synaptics_sysctl(SYSCTL_HANDLER_ARGS)
4854
synaptics_sysctl(SYSCTL_HANDLER_ARGS)
4108
{
4855
{
4856
	struct psm_softc *sc;
4109
	int error, arg;
4857
	int error, arg;
4110
4858
4859
	if (oidp->oid_arg1 == NULL || oidp->oid_arg2 < 0 ||
4860
	    oidp->oid_arg2 > SYNAPTICS_SYSCTL_SOFTBUTTON3_X)
4861
		return (EINVAL);
4862
4863
	sc = oidp->oid_arg1;
4864
4111
	/* Read the current value. */
4865
	/* Read the current value. */
4112
	arg = *(int *)oidp->oid_arg1;
4866
	arg = *(int *)((char *)sc + oidp->oid_arg2);
4113
	error = sysctl_handle_int(oidp, &arg, 0, req);
4867
	error = sysctl_handle_int(oidp, &arg, 0, req);
4114
4868
4115
	/* Sanity check. */
4869
	/* Sanity check. */
Lines 4131-4144 synaptics_sysctl(SYSCTL_HANDLER_ARGS) Link Here
4131
			return (EINVAL);
4885
			return (EINVAL);
4132
		break;
4886
		break;
4133
	case SYNAPTICS_SYSCTL_MARGIN_TOP:
4887
	case SYNAPTICS_SYSCTL_MARGIN_TOP:
4134
	case SYNAPTICS_SYSCTL_MARGIN_RIGHT:
4135
	case SYNAPTICS_SYSCTL_MARGIN_BOTTOM:
4888
	case SYNAPTICS_SYSCTL_MARGIN_BOTTOM:
4136
	case SYNAPTICS_SYSCTL_MARGIN_LEFT:
4137
	case SYNAPTICS_SYSCTL_NA_TOP:
4889
	case SYNAPTICS_SYSCTL_NA_TOP:
4138
	case SYNAPTICS_SYSCTL_NA_RIGHT:
4139
	case SYNAPTICS_SYSCTL_NA_BOTTOM:
4890
	case SYNAPTICS_SYSCTL_NA_BOTTOM:
4891
		if (arg < 0 || arg > sc->synhw.maximumYCoord)
4892
			return (EINVAL);
4893
		break;
4894
	case SYNAPTICS_SYSCTL_SOFTBUTTON2_X:
4895
	case SYNAPTICS_SYSCTL_SOFTBUTTON3_X:
4896
		/* Softbuttons is clickpad only feature */
4897
		if (!sc->synhw.capClickPad && arg != 0)
4898
			return (EINVAL);
4899
		/* FALLTHROUGH */
4900
	case SYNAPTICS_SYSCTL_MARGIN_RIGHT:
4901
	case SYNAPTICS_SYSCTL_MARGIN_LEFT:
4902
	case SYNAPTICS_SYSCTL_NA_RIGHT:
4140
	case SYNAPTICS_SYSCTL_NA_LEFT:
4903
	case SYNAPTICS_SYSCTL_NA_LEFT:
4141
		if (arg < 0 || arg > 6143)
4904
		if (arg < 0 || arg > sc->synhw.maximumXCoord)
4142
			return (EINVAL);
4905
			return (EINVAL);
4143
		break;
4906
		break;
4144
	case SYNAPTICS_SYSCTL_WINDOW_MIN:
4907
	case SYNAPTICS_SYSCTL_WINDOW_MIN:
Lines 4168-4175 synaptics_sysctl(SYSCTL_HANDLER_ARGS) Link Here
4168
			return (EINVAL);
4931
			return (EINVAL);
4169
		break;
4932
		break;
4170
	case SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA:
4933
	case SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA:
4934
		if (arg < -sc->synhw.maximumXCoord ||
4935
		    arg > sc->synhw.maximumXCoord)
4936
			return (EINVAL);
4937
		break;
4938
	case SYNAPTICS_SYSCTL_SOFTBUTTONS_Y:
4939
		/* Softbuttons is clickpad only feature */
4940
		if (!sc->synhw.capClickPad && arg != 0)
4941
			return (EINVAL);
4942
		/* FALLTHROUGH */
4171
	case SYNAPTICS_SYSCTL_VSCROLL_VER_AREA:
4943
	case SYNAPTICS_SYSCTL_VSCROLL_VER_AREA:
4172
		if (arg < -6143 || arg > 6143)
4944
		if (arg < -sc->synhw.maximumYCoord ||
4945
		    arg > sc->synhw.maximumYCoord)
4173
			return (EINVAL);
4946
			return (EINVAL);
4174
		break;
4947
		break;
4175
        case SYNAPTICS_SYSCTL_TOUCHPAD_OFF:
4948
        case SYNAPTICS_SYSCTL_TOUCHPAD_OFF:
Lines 4181-4193 synaptics_sysctl(SYSCTL_HANDLER_ARGS) Link Here
4181
	}
4954
	}
4182
4955
4183
	/* Update. */
4956
	/* Update. */
4184
	*(int *)oidp->oid_arg1 = arg;
4957
	*(int *)((char *)sc + oidp->oid_arg2) = arg;
4185
4958
4186
	return (error);
4959
	return (error);
4187
}
4960
}
4188
4961
4189
static void
4962
static void
4190
synaptics_sysctl_create_tree(struct psm_softc *sc)
4963
synaptics_sysctl_create_softbuttons_tree(struct psm_softc *sc)
4964
{
4965
	/*
4966
	 * Set predefined sizes for softbuttons.
4967
	 * Values are taken to match HP Pavilion dv6 clickpad drawings
4968
	 * with thin middle softbutton placed on separator
4969
	 */
4970
4971
	/* hw.psm.synaptics.softbuttons_y */
4972
	sc->syninfo.softbuttons_y = 1700;
4973
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4974
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4975
	    "softbuttons_y", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4976
	    sc, SYNAPTICS_SYSCTL_SOFTBUTTONS_Y,
4977
	    synaptics_sysctl, "I",
4978
	    "Vertical size of softbuttons area");
4979
4980
	/* hw.psm.synaptics.softbutton2_x */
4981
	sc->syninfo.softbutton2_x = 3100;
4982
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4983
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4984
	    "softbutton2_x", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4985
	    sc, SYNAPTICS_SYSCTL_SOFTBUTTON2_X,
4986
	    synaptics_sysctl, "I",
4987
	    "Horisontal position of 2-nd softbutton left edge (0-disable)");
4988
4989
	/* hw.psm.synaptics.softbutton3_x */
4990
	sc->syninfo.softbutton3_x = 3900;
4991
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4992
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4993
	    "softbutton3_x", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4994
	    sc, SYNAPTICS_SYSCTL_SOFTBUTTON3_X,
4995
	    synaptics_sysctl, "I",
4996
	    "Horisontal position of 3-rd softbutton left edge (0-disable)");
4997
}
4998
4999
static void
5000
synaptics_sysctl_create_tree(struct psm_softc *sc, const char *name,
5001
    const char *descr)
4191
{
5002
{
4192
5003
4193
	if (sc->syninfo.sysctl_tree != NULL)
5004
	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 */
5007
	/* Attach extra synaptics sysctl nodes under hw.psm.synaptics */
4197
	sysctl_ctx_init(&sc->syninfo.sysctl_ctx);
5008
	sysctl_ctx_init(&sc->syninfo.sysctl_ctx);
4198
	sc->syninfo.sysctl_tree = SYSCTL_ADD_NODE(&sc->syninfo.sysctl_ctx,
5009
	sc->syninfo.sysctl_tree = SYSCTL_ADD_NODE(&sc->syninfo.sysctl_ctx,
4199
	    SYSCTL_STATIC_CHILDREN(_hw_psm), OID_AUTO, "synaptics", CTLFLAG_RD,
5010
	    SYSCTL_STATIC_CHILDREN(_hw_psm), OID_AUTO, name, CTLFLAG_RD,
4200
	    0, "Synaptics TouchPad");
5011
	    0, descr);
4201
5012
4202
	/* hw.psm.synaptics.directional_scrolls. */
5013
	/* hw.psm.synaptics.directional_scrolls. */
4203
	sc->syninfo.directional_scrolls = 0;
5014
	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 "
5019
	    "Enable hardware scrolling pad (if non-zero) or register it as "
4209
	    "extended buttons (if 0)");
5020
	    "extended buttons (if 0)");
4210
5021
5022
	/* hw.psm.synaptics.max_x. */
5023
	sc->syninfo.max_x = 6143;
5024
	SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx,
5025
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5026
	    "max_x", CTLFLAG_RD|CTLFLAG_ANYBODY,
5027
	    &sc->syninfo.max_x, 0,
5028
	    "Horizontal reporting range");
5029
5030
	/* hw.psm.synaptics.max_y. */
5031
	sc->syninfo.max_y = 6143;
5032
	SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx,
5033
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5034
	    "max_y", CTLFLAG_RD|CTLFLAG_ANYBODY,
5035
	    &sc->syninfo.max_y, 0,
5036
	    "Vertical reporting range");
5037
4211
	/*
5038
	/*
4212
	 * Turn off two finger scroll if we have a
5039
	 * Turn off two finger scroll if we have a
4213
	 * physical area reserved for scrolling or when
5040
	 * 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,
5057
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4231
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5058
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4232
	    "min_pressure", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5059
	    "min_pressure", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4233
	    &sc->syninfo.min_pressure, SYNAPTICS_SYSCTL_MIN_PRESSURE,
5060
	    sc, SYNAPTICS_SYSCTL_MIN_PRESSURE,
4234
	    synaptics_sysctl, "I",
5061
	    synaptics_sysctl, "I",
4235
	    "Minimum pressure required to start an action");
5062
	    "Minimum pressure required to start an action");
4236
5063
Lines 4239-4245 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4239
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5066
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4240
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5067
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4241
	    "max_pressure", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5068
	    "max_pressure", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4242
	    &sc->syninfo.max_pressure, SYNAPTICS_SYSCTL_MAX_PRESSURE,
5069
	    sc, SYNAPTICS_SYSCTL_MAX_PRESSURE,
4243
	    synaptics_sysctl, "I",
5070
	    synaptics_sysctl, "I",
4244
	    "Maximum pressure to detect palm");
5071
	    "Maximum pressure to detect palm");
4245
5072
Lines 4248-4254 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4248
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5075
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4249
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5076
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4250
	    "max_width", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5077
	    "max_width", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4251
	    &sc->syninfo.max_width, SYNAPTICS_SYSCTL_MAX_WIDTH,
5078
	    sc, SYNAPTICS_SYSCTL_MAX_WIDTH,
4252
	    synaptics_sysctl, "I",
5079
	    synaptics_sysctl, "I",
4253
	    "Maximum finger width to detect palm");
5080
	    "Maximum finger width to detect palm");
4254
5081
Lines 4257-4263 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4257
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5084
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4258
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5085
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4259
	    "margin_top", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5086
	    "margin_top", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4260
	    &sc->syninfo.margin_top, SYNAPTICS_SYSCTL_MARGIN_TOP,
5087
	    sc, SYNAPTICS_SYSCTL_MARGIN_TOP,
4261
	    synaptics_sysctl, "I",
5088
	    synaptics_sysctl, "I",
4262
	    "Top margin");
5089
	    "Top margin");
4263
5090
Lines 4266-4272 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4266
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5093
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4267
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5094
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4268
	    "margin_right", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5095
	    "margin_right", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4269
	    &sc->syninfo.margin_right, SYNAPTICS_SYSCTL_MARGIN_RIGHT,
5096
	    sc, SYNAPTICS_SYSCTL_MARGIN_RIGHT,
4270
	    synaptics_sysctl, "I",
5097
	    synaptics_sysctl, "I",
4271
	    "Right margin");
5098
	    "Right margin");
4272
5099
Lines 4275-4281 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4275
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5102
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4276
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5103
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4277
	    "margin_bottom", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5104
	    "margin_bottom", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4278
	    &sc->syninfo.margin_bottom, SYNAPTICS_SYSCTL_MARGIN_BOTTOM,
5105
	    sc, SYNAPTICS_SYSCTL_MARGIN_BOTTOM,
4279
	    synaptics_sysctl, "I",
5106
	    synaptics_sysctl, "I",
4280
	    "Bottom margin");
5107
	    "Bottom margin");
4281
5108
Lines 4284-4290 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4284
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5111
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4285
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5112
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4286
	    "margin_left", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5113
	    "margin_left", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4287
	    &sc->syninfo.margin_left, SYNAPTICS_SYSCTL_MARGIN_LEFT,
5114
	    sc, SYNAPTICS_SYSCTL_MARGIN_LEFT,
4288
	    synaptics_sysctl, "I",
5115
	    synaptics_sysctl, "I",
4289
	    "Left margin");
5116
	    "Left margin");
4290
5117
Lines 4293-4299 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4293
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5120
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4294
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5121
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4295
	    "na_top", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5122
	    "na_top", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4296
	    &sc->syninfo.na_top, SYNAPTICS_SYSCTL_NA_TOP,
5123
	    sc, SYNAPTICS_SYSCTL_NA_TOP,
4297
	    synaptics_sysctl, "I",
5124
	    synaptics_sysctl, "I",
4298
	    "Top noisy area, where weight_previous_na is used instead "
5125
	    "Top noisy area, where weight_previous_na is used instead "
4299
	    "of weight_previous");
5126
	    "of weight_previous");
Lines 4303-4309 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4303
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5130
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4304
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5131
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4305
	    "na_right", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5132
	    "na_right", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4306
	    &sc->syninfo.na_right, SYNAPTICS_SYSCTL_NA_RIGHT,
5133
	    sc, SYNAPTICS_SYSCTL_NA_RIGHT,
4307
	    synaptics_sysctl, "I",
5134
	    synaptics_sysctl, "I",
4308
	    "Right noisy area, where weight_previous_na is used instead "
5135
	    "Right noisy area, where weight_previous_na is used instead "
4309
	    "of weight_previous");
5136
	    "of weight_previous");
Lines 4313-4319 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4313
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5140
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4314
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5141
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4315
	    "na_bottom", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5142
	    "na_bottom", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4316
	    &sc->syninfo.na_bottom, SYNAPTICS_SYSCTL_NA_BOTTOM,
5143
	    sc, SYNAPTICS_SYSCTL_NA_BOTTOM,
4317
	    synaptics_sysctl, "I",
5144
	    synaptics_sysctl, "I",
4318
	    "Bottom noisy area, where weight_previous_na is used instead "
5145
	    "Bottom noisy area, where weight_previous_na is used instead "
4319
	    "of weight_previous");
5146
	    "of weight_previous");
Lines 4323-4329 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4323
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5150
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4324
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5151
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4325
	    "na_left", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5152
	    "na_left", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4326
	    &sc->syninfo.na_left, SYNAPTICS_SYSCTL_NA_LEFT,
5153
	    sc, SYNAPTICS_SYSCTL_NA_LEFT,
4327
	    synaptics_sysctl, "I",
5154
	    synaptics_sysctl, "I",
4328
	    "Left noisy area, where weight_previous_na is used instead "
5155
	    "Left noisy area, where weight_previous_na is used instead "
4329
	    "of weight_previous");
5156
	    "of weight_previous");
Lines 4333-4339 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4333
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5160
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4334
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5161
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4335
	    "window_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5162
	    "window_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4336
	    &sc->syninfo.window_min, SYNAPTICS_SYSCTL_WINDOW_MIN,
5163
	    sc, SYNAPTICS_SYSCTL_WINDOW_MIN,
4337
	    synaptics_sysctl, "I",
5164
	    synaptics_sysctl, "I",
4338
	    "Minimum window size to start an action");
5165
	    "Minimum window size to start an action");
4339
5166
Lines 4342-4348 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4342
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5169
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4343
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5170
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4344
	    "window_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5171
	    "window_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4345
	    &sc->syninfo.window_max, SYNAPTICS_SYSCTL_WINDOW_MAX,
5172
	    sc, SYNAPTICS_SYSCTL_WINDOW_MAX,
4346
	    synaptics_sysctl, "I",
5173
	    synaptics_sysctl, "I",
4347
	    "Maximum window size");
5174
	    "Maximum window size");
4348
5175
Lines 4351-4357 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4351
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5178
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4352
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5179
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4353
	    "multiplicator", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5180
	    "multiplicator", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4354
	    &sc->syninfo.multiplicator, SYNAPTICS_SYSCTL_MULTIPLICATOR,
5181
	    sc, SYNAPTICS_SYSCTL_MULTIPLICATOR,
4355
	    synaptics_sysctl, "I",
5182
	    synaptics_sysctl, "I",
4356
	    "Multiplicator to increase precision in averages and divisions");
5183
	    "Multiplicator to increase precision in averages and divisions");
4357
5184
Lines 4360-4366 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4360
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5187
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4361
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5188
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4362
	    "weight_current", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5189
	    "weight_current", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4363
	    &sc->syninfo.weight_current, SYNAPTICS_SYSCTL_WEIGHT_CURRENT,
5190
	    sc, SYNAPTICS_SYSCTL_WEIGHT_CURRENT,
4364
	    synaptics_sysctl, "I",
5191
	    synaptics_sysctl, "I",
4365
	    "Weight of the current movement in the new average");
5192
	    "Weight of the current movement in the new average");
4366
5193
Lines 4369-4375 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4369
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5196
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4370
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5197
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4371
	    "weight_previous", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5198
	    "weight_previous", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4372
	    &sc->syninfo.weight_previous, SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS,
5199
	    sc, SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS,
4373
	    synaptics_sysctl, "I",
5200
	    synaptics_sysctl, "I",
4374
	    "Weight of the previous average");
5201
	    "Weight of the previous average");
4375
5202
Lines 4378-4385 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4378
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5205
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4379
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5206
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4380
	    "weight_previous_na", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5207
	    "weight_previous_na", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4381
	    &sc->syninfo.weight_previous_na,
5208
	    sc, SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS_NA,
4382
	    SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS_NA,
4383
	    synaptics_sysctl, "I",
5209
	    synaptics_sysctl, "I",
4384
	    "Weight of the previous average (inside the noisy area)");
5210
	    "Weight of the previous average (inside the noisy area)");
4385
5211
Lines 4388-4395 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4388
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5214
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4389
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5215
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4390
	    "weight_len_squared", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5216
	    "weight_len_squared", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4391
	    &sc->syninfo.weight_len_squared,
5217
	    sc, SYNAPTICS_SYSCTL_WEIGHT_LEN_SQUARED,
4392
	    SYNAPTICS_SYSCTL_WEIGHT_LEN_SQUARED,
4393
	    synaptics_sysctl, "I",
5218
	    synaptics_sysctl, "I",
4394
	    "Length (squared) of segments where weight_previous "
5219
	    "Length (squared) of segments where weight_previous "
4395
	    "starts to decrease");
5220
	    "starts to decrease");
Lines 4399-4405 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4399
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5224
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4400
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5225
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4401
	    "div_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5226
	    "div_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4402
	    &sc->syninfo.div_min, SYNAPTICS_SYSCTL_DIV_MIN,
5227
	    sc, SYNAPTICS_SYSCTL_DIV_MIN,
4403
	    synaptics_sysctl, "I",
5228
	    synaptics_sysctl, "I",
4404
	    "Divisor for fast movements");
5229
	    "Divisor for fast movements");
4405
5230
Lines 4408-4414 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4408
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5233
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4409
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5234
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4410
	    "div_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5235
	    "div_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4411
	    &sc->syninfo.div_max, SYNAPTICS_SYSCTL_DIV_MAX,
5236
	    sc, SYNAPTICS_SYSCTL_DIV_MAX,
4412
	    synaptics_sysctl, "I",
5237
	    synaptics_sysctl, "I",
4413
	    "Divisor for slow movements");
5238
	    "Divisor for slow movements");
4414
5239
Lines 4417-4423 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4417
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5242
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4418
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5243
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4419
	    "div_max_na", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5244
	    "div_max_na", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4420
	    &sc->syninfo.div_max_na, SYNAPTICS_SYSCTL_DIV_MAX_NA,
5245
	    sc, SYNAPTICS_SYSCTL_DIV_MAX_NA,
4421
	    synaptics_sysctl, "I",
5246
	    synaptics_sysctl, "I",
4422
	    "Divisor with slow movements (inside the noisy area)");
5247
	    "Divisor with slow movements (inside the noisy area)");
4423
5248
Lines 4426-4432 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4426
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5251
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4427
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5252
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4428
	    "div_len", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5253
	    "div_len", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4429
	    &sc->syninfo.div_len, SYNAPTICS_SYSCTL_DIV_LEN,
5254
	    sc, SYNAPTICS_SYSCTL_DIV_LEN,
4430
	    synaptics_sysctl, "I",
5255
	    synaptics_sysctl, "I",
4431
	    "Length of segments where div_max starts to decrease");
5256
	    "Length of segments where div_max starts to decrease");
4432
5257
Lines 4435-4441 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4435
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5260
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4436
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5261
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4437
	    "tap_max_delta", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5262
	    "tap_max_delta", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4438
	    &sc->syninfo.tap_max_delta, SYNAPTICS_SYSCTL_TAP_MAX_DELTA,
5263
	    sc, SYNAPTICS_SYSCTL_TAP_MAX_DELTA,
4439
	    synaptics_sysctl, "I",
5264
	    synaptics_sysctl, "I",
4440
	    "Length of segments above which a tap is ignored");
5265
	    "Length of segments above which a tap is ignored");
4441
5266
Lines 4444-4460 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4444
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5269
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4445
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5270
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4446
	    "tap_min_queue", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5271
	    "tap_min_queue", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4447
	    &sc->syninfo.tap_min_queue, SYNAPTICS_SYSCTL_TAP_MIN_QUEUE,
5272
	    sc, SYNAPTICS_SYSCTL_TAP_MIN_QUEUE,
4448
	    synaptics_sysctl, "I",
5273
	    synaptics_sysctl, "I",
4449
	    "Number of packets required to consider a tap");
5274
	    "Number of packets required to consider a tap");
4450
5275
4451
	/* hw.psm.synaptics.taphold_timeout. */
5276
	/* hw.psm.synaptics.taphold_timeout. */
4452
	sc->synaction.in_taphold = 0;
5277
	sc->gesture.in_taphold = 0;
4453
	sc->syninfo.taphold_timeout = tap_timeout;
5278
	sc->syninfo.taphold_timeout = tap_timeout;
4454
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5279
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4455
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5280
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4456
	    "taphold_timeout", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5281
	    "taphold_timeout", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4457
	    &sc->syninfo.taphold_timeout, SYNAPTICS_SYSCTL_TAPHOLD_TIMEOUT,
5282
	    sc, SYNAPTICS_SYSCTL_TAPHOLD_TIMEOUT,
4458
	    synaptics_sysctl, "I",
5283
	    synaptics_sysctl, "I",
4459
	    "Maximum elapsed time between two taps to consider a tap-hold "
5284
	    "Maximum elapsed time between two taps to consider a tap-hold "
4460
	    "action");
5285
	    "action");
Lines 4464-4479 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4464
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5289
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4465
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5290
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4466
	    "vscroll_hor_area", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5291
	    "vscroll_hor_area", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4467
	    &sc->syninfo.vscroll_hor_area, SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA,
5292
	    sc, SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA,
4468
	    synaptics_sysctl, "I",
5293
	    synaptics_sysctl, "I",
4469
	    "Area reserved for horizontal virtual scrolling");
5294
	    "Area reserved for horizontal virtual scrolling");
4470
5295
4471
	/* hw.psm.synaptics.vscroll_ver_area. */
5296
	/* hw.psm.synaptics.vscroll_ver_area. */
4472
	sc->syninfo.vscroll_ver_area = -600;
5297
	sc->syninfo.vscroll_ver_area = -400 - sc->syninfo.margin_right;
4473
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5298
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4474
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5299
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4475
	    "vscroll_ver_area", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5300
	    "vscroll_ver_area", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4476
	    &sc->syninfo.vscroll_ver_area, SYNAPTICS_SYSCTL_VSCROLL_VER_AREA,
5301
	    sc, SYNAPTICS_SYSCTL_VSCROLL_VER_AREA,
4477
	    synaptics_sysctl, "I",
5302
	    synaptics_sysctl, "I",
4478
	    "Area reserved for vertical virtual scrolling");
5303
	    "Area reserved for vertical virtual scrolling");
4479
5304
Lines 4482-4489 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4482
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5307
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4483
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5308
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4484
	    "vscroll_min_delta", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5309
	    "vscroll_min_delta", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4485
	    &sc->syninfo.vscroll_min_delta,
5310
	    sc, SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA,
4486
	    SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA,
4487
	    synaptics_sysctl, "I",
5311
	    synaptics_sysctl, "I",
4488
	    "Minimum movement to consider virtual scrolling");
5312
	    "Minimum movement to consider virtual scrolling");
4489
5313
Lines 4492-4498 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4492
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5316
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4493
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5317
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4494
	    "vscroll_div_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5318
	    "vscroll_div_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4495
	    &sc->syninfo.vscroll_div_min, SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN,
5319
	    sc, SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN,
4496
	    synaptics_sysctl, "I",
5320
	    synaptics_sysctl, "I",
4497
	    "Divisor for fast scrolling");
5321
	    "Divisor for fast scrolling");
4498
5322
Lines 4501-4507 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4501
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5325
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4502
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5326
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4503
	    "vscroll_div_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5327
	    "vscroll_div_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4504
	    &sc->syninfo.vscroll_div_max, SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX,
5328
	    sc, SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX,
4505
	    synaptics_sysctl, "I",
5329
	    synaptics_sysctl, "I",
4506
	    "Divisor for slow scrolling");
5330
	    "Divisor for slow scrolling");
4507
5331
Lines 4510-4537 synaptics_sysctl_create_tree(struct psm_softc *sc) Link Here
4510
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5334
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4511
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5335
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4512
	    "touchpad_off", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5336
	    "touchpad_off", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4513
	    &sc->syninfo.touchpad_off, SYNAPTICS_SYSCTL_TOUCHPAD_OFF,
5337
	    sc, SYNAPTICS_SYSCTL_TOUCHPAD_OFF,
4514
	    synaptics_sysctl, "I",
5338
	    synaptics_sysctl, "I",
4515
	    "Turn off touchpad");
5339
	    "Turn off touchpad");
5340
5341
	sc->syninfo.softbuttons_y = 0;
5342
	sc->syninfo.softbutton2_x = 0;
5343
	sc->syninfo.softbutton3_x = 0;
5344
5345
	/* skip softbuttons sysctl on not clickpads */
5346
	if (sc->synhw.capClickPad)
5347
		synaptics_sysctl_create_softbuttons_tree(sc);
4516
}
5348
}
4517
5349
4518
static int
5350
static int
4519
synaptics_preferred_mode(struct psm_softc *sc) {
5351
synaptics_preferred_mode(struct psm_softc *sc) {
4520
	int mode_byte;
5352
	int mode_byte;
4521
5353
4522
	mode_byte = 0xc0;
5354
	mode_byte = 0xc4;
4523
5355
4524
	/* request wmode where available */
5356
	/* request wmode where available */
4525
	if (sc->synhw.capExtended)
5357
	if (sc->synhw.capExtended)
4526
		mode_byte |= 1;
5358
		mode_byte |= 1;
4527
5359
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;
5360
	return mode_byte;
4536
}
5361
}
4537
5362
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
5371
	 * Enable advanced gestures mode if supported and we are not entering
4547
	 * passthrough mode.
5372
	 * passthrough mode.
4548
	 */
5373
	 */
4549
	if (sc->synhw.capAdvancedGestures && !(mode_byte & (1 << 5))) {
5374
	if ((sc->synhw.capAdvancedGestures || sc->synhw.capReportsV) &&
5375
	    !(mode_byte & (1 << 5))) {
4550
		mouse_ext_command(sc->kbdc, 3);
5376
		mouse_ext_command(sc->kbdc, 3);
4551
		set_mouse_sampling_rate(sc->kbdc, 0xc8);
5377
		set_mouse_sampling_rate(sc->kbdc, 0xc8);
4552
	}
5378
	}
Lines 4754-4760 enable_synaptics(struct psm_softc *sc, enum probearg arg) Link Here
4754
						     ((status[1] & 0x0f) << 1);
5580
						     ((status[1] & 0x0f) << 1);
4755
				synhw.maximumYCoord = (status[2] << 5) |
5581
				synhw.maximumYCoord = (status[2] << 5) |
4756
						     ((status[1] & 0xf0) >> 3);
5582
						     ((status[1] & 0xf0) >> 3);
5583
			} else {
5584
				/*
5585
				 * Typical bezel limits. Taken from 'Synaptics
5586
				 * PS/2 * TouchPad Interfacing Guide' p.3.2.3.
5587
				 */
5588
				synhw.maximumXCoord = 5472;
5589
				synhw.maximumYCoord = 4448;
4757
			}
5590
			}
5591
4758
			if (synhw.capReportsMin) {
5592
			if (synhw.capReportsMin) {
4759
				if (!set_mouse_scaling(kbdc, 1))
5593
				if (!set_mouse_scaling(kbdc, 1))
4760
					return (FALSE);
5594
					return (FALSE);
Lines 4767-4772 enable_synaptics(struct psm_softc *sc, enum probearg arg) Link Here
4767
						     ((status[1] & 0x0f) << 1);
5601
						     ((status[1] & 0x0f) << 1);
4768
				synhw.minimumYCoord = (status[2] << 5) |
5602
				synhw.minimumYCoord = (status[2] << 5) |
4769
						     ((status[1] & 0xf0) >> 3);
5603
						     ((status[1] & 0xf0) >> 3);
5604
			} else {
5605
				/*
5606
				 * Typical bezel limits. Taken from 'Synaptics
5607
				 * PS/2 * TouchPad Interfacing Guide' p.3.2.3.
5608
				 */
5609
				synhw.minimumXCoord = 1472;
5610
				synhw.minimumYCoord = 1408;
4770
			}
5611
			}
4771
5612
4772
			if (verbose >= 2) {
5613
			if (verbose >= 2) {
Lines 4854-4860 enable_synaptics(struct psm_softc *sc, enum probearg arg) Link Here
4854
5695
4855
	if (arg == PROBE) {
5696
	if (arg == PROBE) {
4856
		/* Create sysctl tree. */
5697
		/* Create sysctl tree. */
4857
		synaptics_sysctl_create_tree(sc);
5698
		synaptics_sysctl_create_tree(sc, "synaptics",
5699
		    "Synaptics TouchPad");
4858
		sc->hw.buttons = buttons;
5700
		sc->hw.buttons = buttons;
4859
	}
5701
	}
4860
5702
Lines 5171-5176 enable_versapad(struct psm_softc *sc, enum probearg arg) Link Here
5171
	return (TRUE);				/* PS/2 absolute mode */
6013
	return (TRUE);				/* PS/2 absolute mode */
5172
}
6014
}
5173
6015
6016
/* Elantech Touchpad */
6017
static int
6018
elantech_read_1(KBDC kbdc, int hwversion, int reg, int *val)
6019
{
6020
	int res, readcmd, retidx;
6021
	int resp[3];
6022
6023
	readcmd = hwversion == 2 ? ELANTECH_REG_READ : ELANTECH_REG_RDWR;
6024
	retidx = hwversion == 4 ? 1 : 0;
6025
6026
	res = send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK;
6027
	res |= send_aux_command(kbdc, readcmd) != PSM_ACK;
6028
	res |= send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK;
6029
	res |= send_aux_command(kbdc, reg) != PSM_ACK;
6030
	res |= get_mouse_status(kbdc, resp, 0, 3) != 3;
6031
6032
	if (res == 0)
6033
		*val = resp[retidx];
6034
6035
	return (res);
6036
}
6037
6038
static int
6039
elantech_write_1(KBDC kbdc, int hwversion, int reg, int val)
6040
{
6041
	int res, writecmd;
6042
6043
	writecmd = hwversion == 2 ? ELANTECH_REG_WRITE : ELANTECH_REG_RDWR;
6044
6045
	res = send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK;
6046
	res |= send_aux_command(kbdc, writecmd) != PSM_ACK;
6047
	res |= send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK;
6048
	res |= send_aux_command(kbdc, reg) != PSM_ACK;
6049
	if (hwversion == 4) {
6050
		res |= send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK;
6051
		res |= send_aux_command(kbdc, writecmd) != PSM_ACK;
6052
	}
6053
	res |= send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK;
6054
	res |= send_aux_command(kbdc, val) != PSM_ACK;
6055
	res |= set_mouse_scaling(kbdc, 1) == 0;
6056
6057
	return (res);
6058
}
6059
6060
static int
6061
elantech_cmd(KBDC kbdc, int hwversion, int cmd, int *resp)
6062
{
6063
	int res;
6064
6065
	if (hwversion == 2) {
6066
		res = set_mouse_scaling(kbdc, 1) == 0;
6067
		res |= mouse_ext_command(kbdc, cmd) == 0;
6068
	} else {
6069
		res = send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK;
6070
		res |= send_aux_command(kbdc, cmd) != PSM_ACK;
6071
	}
6072
	res |= get_mouse_status(kbdc, resp, 0, 3) != 3;
6073
6074
	return (res);
6075
}
6076
6077
static int
6078
elantech_init(KBDC kbdc, elantechhw_t *elanhw)
6079
{
6080
	int i, val, res, hwversion, reg10;
6081
6082
	/* set absolute mode */
6083
	hwversion = elanhw->hwversion;
6084
	reg10 = -1;
6085
	switch (hwversion) {
6086
	case 2:
6087
		reg10 = elanhw->fwversion == 0x020030 ? 0x54 : 0xc4;
6088
		res = elantech_write_1(kbdc, hwversion, 0x10, reg10);
6089
		if (res)
6090
			break;
6091
		res = elantech_write_1(kbdc, hwversion, 0x11, 0x8A);
6092
		break;
6093
	case 3:
6094
		reg10 = 0x0b;
6095
		res = elantech_write_1(kbdc, hwversion, 0x10, reg10);
6096
		break;
6097
	case 4:
6098
		res = elantech_write_1(kbdc, hwversion, 0x07, 0x01);
6099
		break;
6100
	default:
6101
		res = 1;
6102
	}
6103
6104
	/* Read back reg 0x10 to ensure hardware is ready. */
6105
	if (res == 0 && reg10 >= 0) {
6106
		for (i = 0; i < 5; i++) {
6107
			if (elantech_read_1(kbdc, hwversion, 0x10, &val) == 0)
6108
				break;
6109
			DELAY(2000);
6110
		}
6111
		if (i == 5)
6112
			res = 1;
6113
	}
6114
6115
	if (res)
6116
		printf("couldn't set absolute mode\n");
6117
6118
	return (res);
6119
}
6120
6121
static void
6122
elantech_init_synaptics(struct psm_softc *sc)
6123
{
6124
6125
	/* Set capabilites required by movement smother */
6126
	sc->synhw.infoMajor = sc->elanhw.hwversion;
6127
	sc->synhw.infoMinor = sc->elanhw.fwversion;
6128
	sc->synhw.infoXupmm = sc->elanhw.dpmmx;
6129
	sc->synhw.infoYupmm = sc->elanhw.dpmmy;
6130
	sc->synhw.verticalScroll = 0;
6131
	sc->synhw.nExtendedQueries = 4;
6132
	sc->synhw.capExtended = 1;
6133
	sc->synhw.capPassthrough = sc->elanhw.hastrackpad;
6134
	sc->synhw.capClickPad = sc->elanhw.isclickpad;
6135
	sc->synhw.capMultiFinger = 1;
6136
	sc->synhw.capAdvancedGestures = 1;
6137
	sc->synhw.capPalmDetect = 1;
6138
	sc->synhw.capPen = 0;
6139
	sc->synhw.capReportsMax = 1;
6140
	sc->synhw.maximumXCoord = sc->elanhw.sizex;
6141
	sc->synhw.maximumYCoord = sc->elanhw.sizey;
6142
	sc->synhw.capReportsMin = 1;
6143
	sc->synhw.minimumXCoord = 0;
6144
	sc->synhw.minimumYCoord = 0;
6145
6146
	if (sc->syninfo.sysctl_tree == NULL) {
6147
		synaptics_sysctl_create_tree(sc, "elantech",
6148
		    "Elantech Touchpad");
6149
6150
		/*
6151
		 * Adjust synaptic smoother tunables
6152
		 * 1. Disable finger detection pressure threshold. Unlike
6153
		 *    synaptics we assume the finger is acting when packet with
6154
		 *    its X&Y arrives not when pressure exceedes some threshold
6155
		 * 2. Disable unrelated features like margins and noisy areas
6156
		 * 3. Disable virtual scroll areas as 2nd finger is preferable
6157
		 * 4. For clickpads set bottom quarter as 42% - 16% - 42% sized
6158
		 *    softbuttons
6159
		 * 5. Scale down divisors and movement lengths by a factor of 3
6160
		 *    where 3 is Synaptics to Elantech (~2200/800) dpi ratio
6161
		 */
6162
6163
		/* Set reporting range to be equal touchpad size */
6164
		sc->syninfo.max_x = sc->elanhw.sizex;
6165
		sc->syninfo.max_y = sc->elanhw.sizey;
6166
6167
		/* Disable finger detection pressure threshold */
6168
		sc->syninfo.min_pressure = 1;
6169
6170
		/* Use full area of touchpad */
6171
		sc->syninfo.margin_top = 0;
6172
		sc->syninfo.margin_right = 0;
6173
		sc->syninfo.margin_bottom = 0;
6174
		sc->syninfo.margin_left = 0;
6175
6176
		/* Disable noisy area */
6177
		sc->syninfo.na_top = 0;
6178
		sc->syninfo.na_right = 0;
6179
		sc->syninfo.na_bottom = 0;
6180
		sc->syninfo.na_left = 0;
6181
6182
		/* Tune divisors and movement lengths */
6183
		sc->syninfo.weight_len_squared = 200;
6184
		sc->syninfo.div_min = 3;
6185
		sc->syninfo.div_max = 6;
6186
		sc->syninfo.div_max_na = 10;
6187
		sc->syninfo.div_len = 30;
6188
		sc->syninfo.tap_max_delta = 25;
6189
6190
		/* Disable virtual scrolling areas and tune its divisors */
6191
		sc->syninfo.vscroll_hor_area = 0;
6192
		sc->syninfo.vscroll_ver_area = 0;
6193
		sc->syninfo.vscroll_min_delta = 15;
6194
		sc->syninfo.vscroll_div_min = 30;
6195
		sc->syninfo.vscroll_div_max = 50;
6196
6197
		/* Set bottom quarter as 42% - 16% - 42% sized softbuttons */
6198
		if (sc->elanhw.isclickpad) {
6199
			sc->syninfo.softbuttons_y = sc->elanhw.sizey / 4;
6200
			sc->syninfo.softbutton2_x = sc->elanhw.sizex * 11 / 25;
6201
			sc->syninfo.softbutton3_x = sc->elanhw.sizex * 14 / 25;
6202
		}
6203
	}
6204
6205
	return;
6206
}
6207
6208
static int
6209
enable_elantech(struct psm_softc *sc, enum probearg arg)
6210
{
6211
	static const int ic2hw[] =
6212
	/*IC: 0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f */
6213
	    { 0, 0, 2, 0, 2, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0 };
6214
	elantechhw_t elanhw;
6215
	int icversion, hwversion, dptracex, dptracey, id, resp[3], dpix, dpiy;
6216
	KBDC kbdc = sc->kbdc;
6217
6218
	VLOG(3, (LOG_DEBUG, "elantech: BEGIN init\n"));
6219
6220
	set_mouse_scaling(kbdc, 1);
6221
	set_mouse_scaling(kbdc, 1);
6222
	set_mouse_scaling(kbdc, 1);
6223
	if (get_mouse_status(kbdc, resp, 0, 3) != 3)
6224
		return (FALSE);
6225
6226
	if (!ELANTECH_MAGIC(resp))
6227
		return (FALSE);
6228
6229
	/* Identify the Touchpad version. */
6230
	if (elantech_cmd(kbdc, 2, ELANTECH_FW_VERSION, resp))
6231
		return (FALSE);
6232
6233
	bzero(&elanhw, sizeof(elanhw));
6234
6235
	elanhw.fwversion = (resp[0] << 16) | (resp[1] << 8) | resp[2];
6236
	icversion = resp[0] & 0x0f;
6237
	hwversion = ic2hw[icversion];
6238
6239
	if (verbose >= 2)
6240
		printf("Elantech touchpad hardware v.%d firmware v.0x%06x\n",
6241
		    hwversion, elanhw.fwversion);
6242
6243
	if (ELANTECH_HW_IS_V1(elanhw.fwversion)) {
6244
		printf ("  Unsupported touchpad hardware (v1)\n");
6245
		return (FALSE);
6246
	}
6247
	if (hwversion == 0) {
6248
		printf ("  Unknown touchpad hardware (firmware v.0x%06x)\n",
6249
		    elanhw.fwversion);
6250
		return (FALSE);
6251
	}
6252
6253
	/* Get the Touchpad model information. */
6254
	elanhw.hwversion = hwversion;
6255
	elanhw.issemimt = hwversion == 2;
6256
	elanhw.isclickpad = (resp[1] & 0x10) != 0;
6257
	elanhw.hascrc = (resp[1] & 0x40) != 0;
6258
	elanhw.haspressure = elanhw.fwversion >= 0x020800;
6259
6260
	/* Read the capability bits. */
6261
	if (elantech_cmd(kbdc, hwversion, ELANTECH_CAPABILITIES, resp) != 0) {
6262
		printf("  Failed to read capability bits\n");
6263
		return (FALSE);
6264
	}
6265
6266
	elanhw.ntracesx = resp[1] - 1;
6267
	elanhw.ntracesy = resp[2] - 1;
6268
	elanhw.hastrackpad = (resp[0] & 0x80) != 0;
6269
6270
	/* Get the touchpad resolution */
6271
	switch (hwversion) {
6272
	case 4:
6273
		if (elantech_cmd(kbdc, hwversion, ELANTECH_RESOLUTION, resp)
6274
		    == 0) {
6275
			dpix = (resp[1] & 0x0f) * 10 + 790;
6276
			dpiy = ((resp[1] & 0xf0) >> 4) * 10 + 790;
6277
			elanhw.dpmmx = (dpix * 10 + 5) / 254;
6278
			elanhw.dpmmy = (dpiy * 10 + 5) / 254;
6279
			break;
6280
		}
6281
		/* FALLTHROUGH */
6282
	case 2:
6283
	case 3:
6284
		elanhw.dpmmx = elanhw.dpmmy = 32; /* 800 dpi */
6285
		break;
6286
	}
6287
6288
	if (!elantech_support)
6289
		return (FALSE);
6290
6291
	if (elantech_init(kbdc, &elanhw)) {
6292
		printf("couldn't initialize elantech touchpad\n");
6293
		return (FALSE);
6294
	}
6295
6296
	/*
6297
	 * Get the touchpad reporting range.
6298
	 * On HW v.3 touchpads it should be done after switching hardware
6299
	 * to real resolution mode (by setting bit 3 of reg10)
6300
	 */
6301
	if (elantech_cmd(kbdc, hwversion, ELANTECH_FW_ID, resp) != 0) {
6302
		printf("  Failed to read touchpad size\n");
6303
		elanhw.sizex = 10000; /* Arbitrary high values to     */
6304
		elanhw.sizey = 10000; /* prevent clipping in smoother */
6305
	} else if (hwversion == 2) {
6306
		dptracex = dptracey = 64;
6307
		if ((elanhw.fwversion >> 16) == 0x14 && (resp[1] & 0x10) &&
6308
		    !elantech_cmd(kbdc, hwversion, ELANTECH_SAMPLE, resp)) {
6309
			dptracex = resp[1] / 2;
6310
			dptracey = resp[2] / 2;
6311
		}
6312
		elanhw.sizex = (elanhw.ntracesx - 1) * dptracex;
6313
		elanhw.sizey = (elanhw.ntracesy - 1) * dptracey;
6314
	} else {
6315
		elanhw.sizex = (resp[0] & 0x0f) << 8 | resp[1];
6316
		elanhw.sizey = (resp[0] & 0xf0) << 4 | resp[2];
6317
	}
6318
6319
	if (verbose >= 2) {
6320
		printf("  Model information:\n");
6321
		printf("   MaxX:     %d\n", elanhw.sizex);
6322
		printf("   MaxY:     %d\n", elanhw.sizey);
6323
		printf("   DpmmX:    %d\n", elanhw.dpmmx);
6324
		printf("   DpmmY:    %d\n", elanhw.dpmmy);
6325
		printf("   TracesX:  %d\n", elanhw.ntracesx);
6326
		printf("   TracesY:  %d\n", elanhw.ntracesy);
6327
		printf("   SemiMT:   %d\n", elanhw.issemimt);
6328
		printf("   Clickpad: %d\n", elanhw.isclickpad);
6329
		printf("   Trackpad: %d\n", elanhw.hastrackpad);
6330
		printf("   CRC:      %d\n", elanhw.hascrc);
6331
		printf("   Pressure: %d\n", elanhw.haspressure);
6332
	}
6333
6334
	VLOG(3, (LOG_DEBUG, "elantech: END init\n"));
6335
6336
	if (arg == PROBE) {
6337
		sc->elanhw = elanhw;
6338
		sc->hw.buttons = 3;
6339
6340
		/* Initialize synaptics movement smoother */
6341
		elantech_init_synaptics(sc);
6342
6343
		for (id = 0; id < ELANTECH_MAX_FINGERS; id++)
6344
			PSM_FINGER_RESET(sc->elanaction.fingers[id]);
6345
	}
6346
6347
	return (TRUE);
6348
}
6349
5174
/*
6350
/*
5175
 * Return true if 'now' is earlier than (start + (secs.usecs)).
6351
 * Return true if 'now' is earlier than (start + (secs.usecs)).
5176
 * Now may be NULL and the function will fetch the current time from
6352
 * 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