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

Collapse All | Expand All

(-)sys/dev/atkbdc/psm.c (-158 / +1221 lines)
Lines 81-86 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 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 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;
202
	int			 softbuttons_y;
203
	int			 softbutton2_x;
204
	int			 softbutton3_x;
205
	int			 softbutton_nomove;
234
} synapticsinfo_t;
206
} synapticsinfo_t;
235
207
236
typedef struct synapticspacket {
208
typedef struct synapticspacket {
Lines 295-300 Link Here
295
	int	skipback;
267
	int	skipback;
296
} trackpointinfo_t;
268
} trackpointinfo_t;
297
269
270
typedef struct finger {
271
	int			x;
272
	int			y;
273
	int			p;
274
	int			w;
275
	int			flags;
276
} finger_t;
277
#define	PSM_GESTURE_FINGERS	2
278
#define	PSM_FINGER_IS_PEN	(1<<0)
279
#define	PSM_FINGER_FUZZY	(1<<1)
280
#define	PSM_FINGER_IS_SET(f) ((f).x != -1 && (f).y != -1 && (f).p != 0)
281
#define	PSM_FINGER_RESET(f) do \
282
	(f) = (finger_t) { .x = -1, .y = -1, .p = 0, .w = 0, .flags = 0 }; \
283
while (0)
284
285
typedef struct elantechhw {
286
	int			hwversion;
287
	int			fwversion;
288
	int			sizex;
289
	int			sizey;
290
	int			dpix;
291
	int			dpiy;
292
	int			ntracesx;
293
	int			ntracesy;
294
	int			isclickpad;
295
	int			hascrc;
296
	int			hastrackpad;
297
	int			haspressure;
298
} elantechhw_t;
299
300
/* minimum versions supported by this driver */
301
#define	ELANTECH_HW_IS_V1(fwver) ((fwver) < 0x020030 || (fwver) == 0x020600)
302
303
#define	ELANTECH_MAGIC(magic)				\
304
	((magic)[0] == 0x3c && (magic)[1] == 0x03 &&	\
305
	((magic)[2] == 0xc8 || (magic)[2] == 0x00))
306
307
#define	ELANTECH_FW_ID		0x00
308
#define	ELANTECH_FW_VERSION	0x01
309
#define	ELANTECH_CAPABILITIES	0x02
310
#define	ELANTECH_SAMPLE		0x03
311
#define	ELANTECH_RESOLUTION	0x04
312
#define	ELANTECH_REG_READ	0x10
313
#define	ELANTECH_REG_WRITE	0x11
314
#define	ELANTECH_REG_RDWR	0x00
315
#define	ELANTECH_CUSTOM_CMD	0xf8
316
317
#define	ELANTECH_FINGER_DEFAULT_P tap_threshold
318
#define	ELANTECH_FINGER_DEFAULT_W 1
319
#define	ELANTECH_FINGER_SET_XYP(pb) (finger_t) {			\
320
    .x = (((pb)->ipacket[1] & 0x0f) << 8) | (pb)->ipacket[2],		\
321
    .y = (((pb)->ipacket[4] & 0x0f) << 8) | (pb)->ipacket[5],		\
322
    .p = ((pb)->ipacket[1] & 0xf0) | (((pb)->ipacket[4] >> 4) & 0x0f),	\
323
    .w = ELANTECH_FINGER_DEFAULT_W,					\
324
    .flags = 0								\
325
}
326
327
enum {
328
	ELANTECH_PKT_NOP,
329
	ELANTECH_PKT_TRACKPOINT,
330
	ELANTECH_PKT_V2_COMMON,
331
	ELANTECH_PKT_V2_2FINGER,
332
	ELANTECH_PKT_V3,
333
	ELANTECH_PKT_V4_STATUS,
334
	ELANTECH_PKT_V4_HEAD,
335
	ELANTECH_PKT_V4_MOTION
336
};
337
338
#define	ELANTECH_PKT_IS_TRACKPOINT(pb) (((pb)->ipacket[3] & 0x0f) == 0x06)
339
#define	ELANTECH_PKT_IS_DEBOUNCE(pb, hwversion) ((hwversion) == 4 ? 0 :	\
340
    (pb)->ipacket[0] == ((hwversion) == 2 ? 0x84 : 0xc4) &&		\
341
    (pb)->ipacket[1] == 0xff && (pb)->ipacket[2] == 0xff &&		\
342
    (pb)->ipacket[3] == 0x02 && (pb)->ipacket[4] == 0xff &&		\
343
    (pb)->ipacket[5] == 0xff)
344
#define	ELANTECH_PKT_IS_V2(pb) 						\
345
    (((pb)->ipacket[0] & 0x0c) == 0x04 && ((pb)->ipacket[3] & 0x0f) == 0x02)
346
#define	ELANTECH_PKT_IS_V3_HEAD(pb, hascrc) ((hascrc) ? 		\
347
    ((pb)->ipacket[3] & 0x09) == 0x08 : 				\
348
    ((pb)->ipacket[0] & 0x0c) == 0x04 && ((pb)->ipacket[3] & 0xcf) == 0x02)
349
#define	ELANTECH_PKT_IS_V3_TAIL(pb, hascrc) ((hascrc) ? 		\
350
    ((pb)->ipacket[3] & 0x09) == 0x09 : 				\
351
    ((pb)->ipacket[0] & 0x0c) == 0x0c && ((pb)->ipacket[3] & 0xce) == 0x0c)
352
#define	ELANTECH_PKT_IS_V4(pb, hascrc) ((hascrc) ? 			\
353
    ((pb)->ipacket[3] & 0x08) == 0x00 :					\
354
    ((pb)->ipacket[0] & 0x0c) == 0x04 && ((pb)->ipacket[3] & 0x1c) == 0x10)
355
356
typedef struct elantechaction {
357
	finger_t		fingers[PSM_GESTURE_FINGERS];
358
	int			nfingers;
359
} elantechaction_t;
360
298
/* driver control block */
361
/* driver control block */
299
struct psm_softc {		/* Driver status information */
362
struct psm_softc {		/* Driver status information */
300
	int		unit;
363
	int		unit;
Lines 308-314 Link Here
308
	mousehw_t	hw;		/* hardware information */
371
	mousehw_t	hw;		/* hardware information */
309
	synapticshw_t	synhw;		/* Synaptics hardware information */
372
	synapticshw_t	synhw;		/* Synaptics hardware information */
310
	synapticsinfo_t	syninfo;	/* Synaptics configuration */
373
	synapticsinfo_t	syninfo;	/* Synaptics configuration */
311
	synapticsaction_t synaction;	/* Synaptics action context */
374
	synapticsaction_t
375
	    synaction[PSM_GESTURE_FINGERS]; /* Synaptics action context */
376
	elantechhw_t	elanhw;		/* Elantech hardware information */
377
	elantechaction_t elanaction;	/* Elantech action context */
312
	int		tphw;		/* TrackPoint hardware information */
378
	int		tphw;		/* TrackPoint hardware information */
313
	trackpointinfo_t tpinfo;	/* TrackPoint configuration */
379
	trackpointinfo_t tpinfo;	/* TrackPoint configuration */
314
	mousemode_t	mode;		/* operation mode */
380
	mousemode_t	mode;		/* operation mode */
Lines 331-336 Link Here
331
	struct timeval	lastsoftintr;	/* time of last soft interrupt */
397
	struct timeval	lastsoftintr;	/* time of last soft interrupt */
332
	struct timeval	lastinputerr;	/* time last sync error happened */
398
	struct timeval	lastinputerr;	/* time last sync error happened */
333
	struct timeval	taptimeout;	/* tap timeout for touchpads */
399
	struct timeval	taptimeout;	/* tap timeout for touchpads */
400
	struct timeval	idletimeout;
401
	packetbuf_t	idlepacket;	/* packet to send after idle timeout */
334
	int		watchdog;	/* watchdog timer flag */
402
	int		watchdog;	/* watchdog timer flag */
335
	struct callout	callout;	/* watchdog timer call out */
403
	struct callout	callout;	/* watchdog timer call out */
336
	struct callout	softcallout; /* buffer timer call out */
404
	struct callout	softcallout; /* buffer timer call out */
Lines 389-394 Link Here
389
static int trackpoint_support = 0;
457
static int trackpoint_support = 0;
390
TUNABLE_INT("hw.psm.trackpoint_support", &trackpoint_support);
458
TUNABLE_INT("hw.psm.trackpoint_support", &trackpoint_support);
391
459
460
static int elantech_support = 0;
461
TUNABLE_INT("hw.psm.elantech_support", &elantech_support);
462
392
static int verbose = PSM_DEBUG;
463
static int verbose = PSM_DEBUG;
393
TUNABLE_INT("debug.psm.loglevel", &verbose);
464
TUNABLE_INT("debug.psm.loglevel", &verbose);
394
465
Lines 411-416 Link Here
411
	int	accelfactor;
482
	int	accelfactor;
412
} old_mousemode_t;
483
} old_mousemode_t;
413
484
485
#define SYN_OFFSET(field) offsetof(struct psm_softc, syninfo.field)
486
enum {
487
	SYNAPTICS_SYSCTL_MIN_PRESSURE =		SYN_OFFSET(min_pressure),
488
	SYNAPTICS_SYSCTL_MAX_PRESSURE =		SYN_OFFSET(max_pressure),
489
	SYNAPTICS_SYSCTL_MAX_WIDTH =		SYN_OFFSET(max_width),
490
	SYNAPTICS_SYSCTL_MARGIN_TOP =		SYN_OFFSET(margin_top),
491
	SYNAPTICS_SYSCTL_MARGIN_RIGHT =		SYN_OFFSET(margin_right),
492
	SYNAPTICS_SYSCTL_MARGIN_BOTTOM =	SYN_OFFSET(margin_bottom),
493
	SYNAPTICS_SYSCTL_MARGIN_LEFT =		SYN_OFFSET(margin_left),
494
	SYNAPTICS_SYSCTL_NA_TOP =		SYN_OFFSET(na_top),
495
	SYNAPTICS_SYSCTL_NA_RIGHT =		SYN_OFFSET(na_right),
496
	SYNAPTICS_SYSCTL_NA_BOTTOM =		SYN_OFFSET(na_bottom),
497
	SYNAPTICS_SYSCTL_NA_LEFT = 		SYN_OFFSET(na_left),
498
	SYNAPTICS_SYSCTL_WINDOW_MIN =		SYN_OFFSET(window_min),
499
	SYNAPTICS_SYSCTL_WINDOW_MAX =		SYN_OFFSET(window_max),
500
	SYNAPTICS_SYSCTL_MULTIPLICATOR =	SYN_OFFSET(multiplicator),
501
	SYNAPTICS_SYSCTL_WEIGHT_CURRENT =	SYN_OFFSET(weight_current),
502
	SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS =	SYN_OFFSET(weight_previous),
503
	SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS_NA =	SYN_OFFSET(weight_previous_na),
504
	SYNAPTICS_SYSCTL_WEIGHT_LEN_SQUARED =	SYN_OFFSET(weight_len_squared),
505
	SYNAPTICS_SYSCTL_DIV_MIN =		SYN_OFFSET(div_min),
506
	SYNAPTICS_SYSCTL_DIV_MAX =		SYN_OFFSET(div_max),
507
	SYNAPTICS_SYSCTL_DIV_MAX_NA =		SYN_OFFSET(div_max_na),
508
	SYNAPTICS_SYSCTL_DIV_LEN =		SYN_OFFSET(div_len),
509
	SYNAPTICS_SYSCTL_TAP_MAX_DELTA =	SYN_OFFSET(tap_max_delta),
510
	SYNAPTICS_SYSCTL_TAP_MIN_QUEUE =	SYN_OFFSET(tap_min_queue),
511
	SYNAPTICS_SYSCTL_TAPHOLD_TIMEOUT =	SYN_OFFSET(taphold_timeout),
512
	SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA =	SYN_OFFSET(vscroll_hor_area),
513
	SYNAPTICS_SYSCTL_VSCROLL_VER_AREA =	SYN_OFFSET(vscroll_ver_area),
514
	SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA =	SYN_OFFSET(vscroll_min_delta),
515
	SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN =	SYN_OFFSET(vscroll_div_min),
516
	SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX =	SYN_OFFSET(vscroll_div_max),
517
	SYNAPTICS_SYSCTL_TOUCHPAD_OFF =		SYN_OFFSET(touchpad_off),
518
	SYNAPTICS_SYSCTL_SOFTBUTTONS =		SYN_OFFSET(softbuttons),
519
	SYNAPTICS_SYSCTL_SOFTBUTTONS_Y =	SYN_OFFSET(softbuttons_y),
520
	SYNAPTICS_SYSCTL_SOFTBUTTON2_X =	SYN_OFFSET(softbutton2_x),
521
	SYNAPTICS_SYSCTL_SOFTBUTTON3_X =	SYN_OFFSET(softbutton3_x),
522
	SYNAPTICS_SYSCTL_SOFTBUTTON_NOMOVE =	SYN_OFFSET(softbutton_nomove)
523
};
524
414
/* packet formatting function */
525
/* packet formatting function */
415
typedef int	packetfunc_t(struct psm_softc *, u_char *, int *, int,
526
typedef int	packetfunc_t(struct psm_softc *, u_char *, int *, int,
416
    mousestatus_t *);
527
    mousestatus_t *);
Lines 446-451 Link Here
446
static int	reinitialize(struct psm_softc *, int);
557
static int	reinitialize(struct psm_softc *, int);
447
static char	*model_name(int);
558
static char	*model_name(int);
448
static void	psmsoftintr(void *);
559
static void	psmsoftintr(void *);
560
static void	psmsoftintridle(void *);
449
static void	psmintr(void *);
561
static void	psmintr(void *);
450
static void	psmtimeout(void *);
562
static void	psmtimeout(void *);
451
static int	timeelapsed(const struct timeval *, int, int,
563
static int	timeelapsed(const struct timeval *, int, int,
Lines 458-463 Link Here
458
		    mousestatus_t *, int *, int *, int *);
570
		    mousestatus_t *, int *, int *, int *);
459
static void	proc_versapad(struct psm_softc *, packetbuf_t *,
571
static void	proc_versapad(struct psm_softc *, packetbuf_t *,
460
		    mousestatus_t *, int *, int *, int *);
572
		    mousestatus_t *, int *, int *, int *);
573
static int	proc_elantech(struct psm_softc *, packetbuf_t *,
574
		    mousestatus_t *, int *, int *, int *);
575
static void	psmgestures(struct psm_softc *, synapticsaction_t *, finger_t,
576
		    int, mousestatus_t *, int *, int *);
577
static int	psmsoftbuttons(struct psm_softc *, finger_t, int);
461
static int	tame_mouse(struct psm_softc *, packetbuf_t *, mousestatus_t *,
578
static int	tame_mouse(struct psm_softc *, packetbuf_t *, mousestatus_t *,
462
		    u_char *);
579
		    u_char *);
463
580
Lines 480-485 Link Here
480
static probefunc_t	enable_synaptics;
597
static probefunc_t	enable_synaptics;
481
static probefunc_t	enable_trackpoint;
598
static probefunc_t	enable_trackpoint;
482
static probefunc_t	enable_versapad;
599
static probefunc_t	enable_versapad;
600
static probefunc_t	enable_elantech;
483
601
484
static void set_trackpoint_parameters(struct psm_softc *sc);
602
static void set_trackpoint_parameters(struct psm_softc *sc);
485
static void synaptics_passthrough_on(struct psm_softc *sc);
603
static void synaptics_passthrough_on(struct psm_softc *sc);
Lines 511-516 Link Here
511
	  0xc8, MOUSE_4DPLUS_PACKETSIZE, enable_4dplus },
629
	  0xc8, MOUSE_4DPLUS_PACKETSIZE, enable_4dplus },
512
	{ MOUSE_MODEL_SYNAPTICS,	/* Synaptics Touchpad */
630
	{ MOUSE_MODEL_SYNAPTICS,	/* Synaptics Touchpad */
513
	  0xc0, MOUSE_SYNAPTICS_PACKETSIZE, enable_synaptics },
631
	  0xc0, MOUSE_SYNAPTICS_PACKETSIZE, enable_synaptics },
632
	{ MOUSE_MODEL_ELANTECH,		/* Elantech Touchpad */
633
	  0x04, MOUSE_ELANTECH_PACKETSIZE, enable_elantech },
514
	{ MOUSE_MODEL_INTELLI,		/* Microsoft IntelliMouse */
634
	{ MOUSE_MODEL_INTELLI,		/* Microsoft IntelliMouse */
515
	  0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_msintelli },
635
	  0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_msintelli },
516
	{ MOUSE_MODEL_GLIDEPOINT,	/* ALPS GlidePoint */
636
	{ MOUSE_MODEL_GLIDEPOINT,	/* ALPS GlidePoint */
Lines 762-767 Link Here
762
		{ MOUSE_MODEL_4DPLUS,		"4D+ Mouse" },
882
		{ MOUSE_MODEL_4DPLUS,		"4D+ Mouse" },
763
		{ MOUSE_MODEL_SYNAPTICS,	"Synaptics Touchpad" },
883
		{ MOUSE_MODEL_SYNAPTICS,	"Synaptics Touchpad" },
764
		{ MOUSE_MODEL_TRACKPOINT,	"IBM/Lenovo TrackPoint" },
884
		{ MOUSE_MODEL_TRACKPOINT,	"IBM/Lenovo TrackPoint" },
885
		{ MOUSE_MODEL_ELANTECH,		"Elantech Touchpad" },
765
		{ MOUSE_MODEL_GENERIC,		"Generic PS/2 mouse" },
886
		{ MOUSE_MODEL_GENERIC,		"Generic PS/2 mouse" },
766
		{ MOUSE_MODEL_UNKNOWN,		"Unknown" },
887
		{ MOUSE_MODEL_UNKNOWN,		"Unknown" },
767
	};
888
	};
Lines 1504-1509 Link Here
1504
	case MOUSE_MODEL_SYNAPTICS:
1625
	case MOUSE_MODEL_SYNAPTICS:
1505
	case MOUSE_MODEL_GLIDEPOINT:
1626
	case MOUSE_MODEL_GLIDEPOINT:
1506
	case MOUSE_MODEL_VERSAPAD:
1627
	case MOUSE_MODEL_VERSAPAD:
1628
	case MOUSE_MODEL_ELANTECH:
1507
		sc->config |= PSM_CONFIG_INITAFTERSUSPEND;
1629
		sc->config |= PSM_CONFIG_INITAFTERSUSPEND;
1508
		break;
1630
		break;
1509
	default:
1631
	default:
Lines 2627-2633 Link Here
2627
{
2749
{
2628
	static int touchpad_buttons;
2750
	static int touchpad_buttons;
2629
	static int guest_buttons;
2751
	static int guest_buttons;
2630
	int w, x0, y0;
2752
	finger_t f;
2753
	int w, nfingers;
2631
2754
2632
	/* TouchPad PS/2 absolute mode message format with capFourButtons:
2755
	/* TouchPad PS/2 absolute mode message format with capFourButtons:
2633
	 *
2756
	 *
Lines 2806-2812 Link Here
2806
			pb->ipacket[4] &= ~(mask);
2929
			pb->ipacket[4] &= ~(mask);
2807
			pb->ipacket[5] &= ~(mask);
2930
			pb->ipacket[5] &= ~(mask);
2808
		} else	if (!sc->syninfo.directional_scrolls &&
2931
		} else	if (!sc->syninfo.directional_scrolls &&
2809
		    !sc->synaction.in_vscroll) {
2932
		    !sc->synaction[0].in_vscroll) {
2810
			/*
2933
			/*
2811
			 * Keep reporting MOUSE DOWN until we get a new packet
2934
			 * Keep reporting MOUSE DOWN until we get a new packet
2812
			 * indicating otherwise.
2935
			 * indicating otherwise.
Lines 2814-2832 Link Here
2814
			touchpad_buttons |= sc->extended_buttons;
2937
			touchpad_buttons |= sc->extended_buttons;
2815
		}
2938
		}
2816
	}
2939
	}
2940
2941
	f.x = ((pb->ipacket[3] & 0x10) << 8) |
2942
	    ((pb->ipacket[1] & 0x0f) << 8) |
2943
	    pb->ipacket[4];
2944
	f.y = ((pb->ipacket[3] & 0x20) << 7) |
2945
	    ((pb->ipacket[1] & 0xf0) << 4) |
2946
	    pb->ipacket[5];
2947
	f.p = *z;
2948
	f.w = w;
2949
	f.flags |= w == 2 ? PSM_FINGER_IS_PEN : 0;
2950
	f.flags |= w < 2 ? PSM_FINGER_FUZZY : 0;
2951
	nfingers = w < 2 ? w + 2 : 1;
2952
2817
	/* Handle ClickPad. */
2953
	/* Handle ClickPad. */
2818
	if (sc->synhw.capClickPad &&
2954
	if (sc->synhw.capClickPad)
2819
	    ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x01))
2955
		touchpad_buttons |= psmsoftbuttons(sc, f,
2820
		touchpad_buttons |= MOUSE_BUTTON1DOWN;
2956
		    (pb->ipacket[0] ^ pb->ipacket[3]) & 0x01);
2821
2957
2822
	ms->button = touchpad_buttons | guest_buttons;
2958
	ms->button = touchpad_buttons | guest_buttons;
2823
2959
2960
	psmgestures(sc, &sc->synaction[0], f, nfingers, ms, x, y);
2961
2962
SYNAPTICS_END:
2824
	/*
2963
	/*
2964
	 * Use the extra buttons as a scrollwheel
2965
	 *
2966
	 * XXX X.Org uses the Z axis for vertical wheel only,
2967
	 * whereas moused(8) understands special values to differ
2968
	 * vertical and horizontal wheels.
2969
	 *
2970
	 * xf86-input-mouse needs therefore a small patch to
2971
	 * understand these special values. Without it, the
2972
	 * horizontal wheel acts as a vertical wheel in X.Org.
2973
	 *
2974
	 * That's why the horizontal wheel is disabled by
2975
	 * default for now.
2976
	 */
2977
	if (ms->button & MOUSE_BUTTON4DOWN) {
2978
		*z = -1;
2979
		ms->button &= ~MOUSE_BUTTON4DOWN;
2980
	} else if (ms->button & MOUSE_BUTTON5DOWN) {
2981
		*z = 1;
2982
		ms->button &= ~MOUSE_BUTTON5DOWN;
2983
	} else if (ms->button & MOUSE_BUTTON6DOWN) {
2984
		*z = -2;
2985
		ms->button &= ~MOUSE_BUTTON6DOWN;
2986
	} else if (ms->button & MOUSE_BUTTON7DOWN) {
2987
		*z = 2;
2988
		ms->button &= ~MOUSE_BUTTON7DOWN;
2989
	} else
2990
		*z = 0;
2991
2992
	return (0);
2993
}
2994
2995
static void
2996
psmgestures(struct psm_softc *sc, synapticsaction_t *synaction, finger_t f,
2997
    int nfingers, mousestatus_t *ms, int *x, int *y)
2998
{
2999
	*x = *y = 0;
3000
3001
	/*
2825
	 * Check pressure to detect a real wanted action on the
3002
	 * Check pressure to detect a real wanted action on the
2826
	 * touchpad.
3003
	 * touchpad.
2827
	 */
3004
	 */
2828
	if (*z >= sc->syninfo.min_pressure) {
3005
	if (f.p >= sc->syninfo.min_pressure) {
2829
		synapticsaction_t *synaction;
3006
		int x0, y0;
2830
		int cursor, peer, window;
3007
		int cursor, peer, window;
2831
		int dx, dy, dxp, dyp;
3008
		int dx, dy, dxp, dyp;
2832
		int max_width, max_pressure;
3009
		int max_width, max_pressure;
Lines 2838-2843 Link Here
2838
		int div_min, div_max, div_len;
3015
		int div_min, div_max, div_len;
2839
		int vscroll_hor_area, vscroll_ver_area;
3016
		int vscroll_hor_area, vscroll_ver_area;
2840
		int two_finger_scroll;
3017
		int two_finger_scroll;
3018
		int max_x, max_y;
2841
		int len, weight_prev_x, weight_prev_y;
3019
		int len, weight_prev_x, weight_prev_y;
2842
		int div_max_x, div_max_y, div_x, div_y;
3020
		int div_max_x, div_max_y, div_x, div_y;
2843
		int exiting_scroll;
3021
		int exiting_scroll;
Lines 2866-2871 Link Here
2866
		vscroll_hor_area = sc->syninfo.vscroll_hor_area;
3044
		vscroll_hor_area = sc->syninfo.vscroll_hor_area;
2867
		vscroll_ver_area = sc->syninfo.vscroll_ver_area;
3045
		vscroll_ver_area = sc->syninfo.vscroll_ver_area;
2868
		two_finger_scroll = sc->syninfo.two_finger_scroll;
3046
		two_finger_scroll = sc->syninfo.two_finger_scroll;
3047
		max_x = sc->synhw.maximumXCoord;
3048
		max_y = sc->synhw.maximumYCoord;
2869
3049
2870
		exiting_scroll = 0;
3050
		exiting_scroll = 0;
2871
3051
Lines 2872-2907 Link Here
2872
		/* Palm detection. */
3052
		/* Palm detection. */
2873
		if (!(
3053
		if (!(
2874
		    ((sc->synhw.capMultiFinger ||
3054
		    ((sc->synhw.capMultiFinger ||
2875
		      sc->synhw.capAdvancedGestures) && (w == 0 || w == 1)) ||
3055
		      sc->synhw.capAdvancedGestures) && nfingers > 1) ||
2876
		    (sc->synhw.capPalmDetect && w >= 4 && w <= max_width) ||
3056
		    (sc->synhw.capPalmDetect && f.w <= max_width) ||
2877
		    (!sc->synhw.capPalmDetect && *z <= max_pressure) ||
3057
		    (!sc->synhw.capPalmDetect && f.p <= max_pressure) ||
2878
		    (sc->synhw.capPen && w == 2))) {
3058
		    (sc->synhw.capPen && f.flags & PSM_FINGER_IS_PEN))) {
2879
			/*
3059
			/*
2880
			 * We consider the packet irrelevant for the current
3060
			 * We consider the packet irrelevant for the current
2881
			 * action when:
3061
			 * action when:
2882
			 *  - the width isn't comprised in:
3062
			 *  - the width isn't comprised in:
2883
			 *    [4; max_width]
3063
			 *    [1; max_width]
2884
			 *  - the pressure isn't comprised in:
3064
			 *  - the pressure isn't comprised in:
2885
			 *    [min_pressure; max_pressure]
3065
			 *    [min_pressure; max_pressure]
2886
			 *  - pen aren't supported but w is 2
3066
			 *  - pen aren't supported but PSM_FiNGER_IS_PEN is set
2887
			 *
3067
			 *
2888
			 *  Note that this doesn't terminate the current action.
3068
			 *  Note that this doesn't terminate the current action.
2889
			 */
3069
			 */
2890
			VLOG(2, (LOG_DEBUG,
3070
			VLOG(2, (LOG_DEBUG,
2891
			    "synaptics: palm detected! (%d)\n", w));
3071
			    "synaptics: palm detected! (%d)\n", f.w));
2892
			goto SYNAPTICS_END;
3072
			return;
2893
		}
3073
		}
2894
3074
2895
		/* Read current absolute position. */
3075
		/* Read current absolute position. */
2896
		x0 = ((pb->ipacket[3] & 0x10) << 8) |
3076
		x0 = f.x;
2897
		    ((pb->ipacket[1] & 0x0f) << 8) |
3077
		y0 = f.y;
2898
		    pb->ipacket[4];
2899
		y0 = ((pb->ipacket[3] & 0x20) << 7) |
2900
		    ((pb->ipacket[1] & 0xf0) << 4) |
2901
		    pb->ipacket[5];
2902
3078
2903
		synaction = &(sc->synaction);
2904
2905
		/*
3079
		/*
2906
		 * If the action is just beginning, init the structure and
3080
		 * If the action is just beginning, init the structure and
2907
		 * compute tap timeout.
3081
		 * compute tap timeout.
Lines 2964-2978 Link Here
2964
		 */
3138
		 */
2965
		if (x0 <= margin_left)
3139
		if (x0 <= margin_left)
2966
			x0 = margin_left;
3140
			x0 = margin_left;
2967
		else if (x0 >= 6143 - margin_right)
3141
		else if (x0 >= max_x - margin_right)
2968
			x0 = 6143 - margin_right;
3142
			x0 = max_x - margin_right;
2969
		if (y0 <= margin_bottom)
3143
		if (y0 <= margin_bottom)
2970
			y0 = margin_bottom;
3144
			y0 = margin_bottom;
2971
		else if (y0 >= 6143 - margin_top)
3145
		else if (y0 >= max_y - margin_top)
2972
			y0 = 6143 - margin_top;
3146
			y0 = max_y - margin_top;
2973
3147
2974
		VLOG(3, (LOG_DEBUG, "synaptics: ipacket: [%d, %d], %d, %d\n",
3148
		VLOG(3, (LOG_DEBUG, "synaptics: ipacket: [%d, %d], %d, %d\n",
2975
		    x0, y0, *z, w));
3149
		    x0, y0, f.p, f.w));
2976
3150
2977
		/* Queue this new packet. */
3151
		/* Queue this new packet. */
2978
		cursor = SYNAPTICS_QUEUE_CURSOR(synaction->queue_cursor - 1);
3152
		cursor = SYNAPTICS_QUEUE_CURSOR(synaction->queue_cursor - 1);
Lines 2990-3015 Link Here
2990
		 * pressure peak. Also with multiple fingers, we increase
3164
		 * pressure peak. Also with multiple fingers, we increase
2991
		 * the minimum window.
3165
		 * the minimum window.
2992
		 */
3166
		 */
2993
		switch (w) {
3167
		if (nfingers > 1)
2994
		case 1: /* Three or more fingers. */
2995
			synaction->fingers_nb = imax(3, synaction->fingers_nb);
2996
			synaction->window_min = window_max;
3168
			synaction->window_min = window_max;
2997
			break;
3169
		synaction->fingers_nb = imax(nfingers, synaction->fingers_nb);
2998
		case 0: /* Two fingers. */
3170
		sc->zmax = imax(f.p, sc->zmax);
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
3171
3007
		/* Do we have enough packets to consider this a movement? */
3172
		/* Do we have enough packets to consider this a movement? */
3008
		if (synaction->queue_len < synaction->window_min)
3173
		if (synaction->queue_len < synaction->window_min)
3009
			goto SYNAPTICS_END;
3174
			return;
3010
3175
3011
		/* Is a scrolling action occurring? */
3176
		/* Is a scrolling action occurring? */
3012
		if (!synaction->in_taphold && !synaction->in_vscroll) {
3177
		if (!synaction->in_taphold &&
3178
		    (!synaction->in_vscroll || two_finger_scroll)) {
3013
			/*
3179
			/*
3014
			 * A scrolling action must not conflict with a tap
3180
			 * A scrolling action must not conflict with a tap
3015
			 * action. Here are the conditions to consider a
3181
			 * action. Here are the conditions to consider a
Lines 3034-3040 Link Here
3034
				 * as that keeps the maximum number of fingers.
3200
				 * as that keeps the maximum number of fingers.
3035
				 */
3201
				 */
3036
				if (two_finger_scroll) {
3202
				if (two_finger_scroll) {
3037
					if (w == 0) {
3203
					if (nfingers == 2) {
3038
						synaction->in_vscroll +=
3204
						synaction->in_vscroll +=
3039
						    dyp ? 2 : 0;
3205
						    dyp ? 2 : 0;
3040
						synaction->in_vscroll +=
3206
						synaction->in_vscroll +=
Lines 3047-3053 Link Here
3047
					        vscroll_hor_area) ||
3213
					        vscroll_hor_area) ||
3048
					    (vscroll_hor_area < 0 &&
3214
					    (vscroll_hor_area < 0 &&
3049
					     synaction->start_y >=
3215
					     synaction->start_y >=
3050
					     6143 + vscroll_hor_area))
3216
					     max_y + vscroll_hor_area))
3051
						synaction->in_vscroll += 2;
3217
						synaction->in_vscroll += 2;
3052
3218
3053
					/* Check for vertical scrolling. */
3219
					/* Check for vertical scrolling. */
Lines 3056-3062 Link Here
3056
						vscroll_ver_area) ||
3222
						vscroll_ver_area) ||
3057
					    (vscroll_ver_area < 0 &&
3223
					    (vscroll_ver_area < 0 &&
3058
					     synaction->start_x >=
3224
					     synaction->start_x >=
3059
					     6143 + vscroll_ver_area))
3225
					     max_x + vscroll_ver_area))
3060
						synaction->in_vscroll += 1;
3226
						synaction->in_vscroll += 1;
3061
				}
3227
				}
3062
3228
Lines 3070-3077 Link Here
3070
		 * Reset two finger scrolling when the number of fingers
3236
		 * Reset two finger scrolling when the number of fingers
3071
		 * is different from two.
3237
		 * is different from two.
3072
		 */
3238
		 */
3073
		if (two_finger_scroll && w != 0 && synaction->in_vscroll != 0) {
3239
		if (two_finger_scroll && nfingers != 2 && synaction->in_vscroll != 0) {
3074
			synaction->in_vscroll = 0;
3240
 			synaction->in_vscroll = 0;
3075
			exiting_scroll = 1;
3241
			exiting_scroll = 1;
3076
		}
3242
		}
3077
3243
Lines 3096-3107 Link Here
3096
			 * using this area, we apply a special weight and
3262
			 * using this area, we apply a special weight and
3097
			 * div.
3263
			 * div.
3098
			 */
3264
			 */
3099
			if (x0 <= na_left || x0 >= 6143 - na_right) {
3265
			if (x0 <= na_left || x0 >= max_x - na_right) {
3100
				weight_prev_x = sc->syninfo.weight_previous_na;
3266
				weight_prev_x = sc->syninfo.weight_previous_na;
3101
				div_max_x = sc->syninfo.div_max_na;
3267
				div_max_x = sc->syninfo.div_max_na;
3102
			}
3268
			}
3103
3269
3104
			if (y0 <= na_bottom || y0 >= 6143 - na_top) {
3270
			if (y0 <= na_bottom || y0 >= max_y - na_top) {
3105
				weight_prev_y = sc->syninfo.weight_previous_na;
3271
				weight_prev_y = sc->syninfo.weight_previous_na;
3106
				div_max_y = sc->syninfo.div_max_na;
3272
				div_max_y = sc->syninfo.div_max_na;
3107
			}
3273
			}
Lines 3193-3202 Link Here
3193
		 * An action is currently taking place but the pressure
3359
		 * An action is currently taking place but the pressure
3194
		 * dropped under the minimum, putting an end to it.
3360
		 * dropped under the minimum, putting an end to it.
3195
		 */
3361
		 */
3196
		synapticsaction_t *synaction;
3197
		int taphold_timeout, dx, dy, tap_max_delta;
3362
		int taphold_timeout, dx, dy, tap_max_delta;
3198
3363
3199
		synaction = &(sc->synaction);
3200
		dx = abs(synaction->queue[synaction->queue_cursor].x -
3364
		dx = abs(synaction->queue[synaction->queue_cursor].x -
3201
		    synaction->start_x);
3365
		    synaction->start_x);
3202
		dy = abs(synaction->queue[synaction->queue_cursor].y -
3366
		dy = abs(synaction->queue[synaction->queue_cursor].y -
Lines 3247-3252 Link Here
3247
				    "synaptics: button RELEASE: %d\n",
3411
				    "synaptics: button RELEASE: %d\n",
3248
				    synaction->tap_button));
3412
				    synaction->tap_button));
3249
				sc->flags |= PSM_FLAGS_FINGERDOWN;
3413
				sc->flags |= PSM_FLAGS_FINGERDOWN;
3414
3415
				/* Schedule button press on next interrupt */
3416
				sc->idletimeout.tv_sec  = psmhz > 1 ?
3417
				    0 : 1;
3418
				sc->idletimeout.tv_usec = psmhz > 1 ?
3419
				    1000000 / psmhz : 0;
3250
			} else {
3420
			} else {
3251
				/*
3421
				/*
3252
				 * This is the first tap: we set the
3422
				 * This is the first tap: we set the
Lines 3259-3264 Link Here
3259
				    1000000;
3429
				    1000000;
3260
				sc->taptimeout.tv_usec = taphold_timeout %
3430
				sc->taptimeout.tv_usec = taphold_timeout %
3261
				    1000000;
3431
				    1000000;
3432
				sc->idletimeout = sc->taptimeout;
3262
				timevaladd(&sc->taptimeout, &sc->lastsoftintr);
3433
				timevaladd(&sc->taptimeout, &sc->lastsoftintr);
3263
3434
3264
				switch (synaction->fingers_nb) {
3435
				switch (synaction->fingers_nb) {
Lines 3295-3301 Link Here
3295
			}
3466
			}
3296
		}
3467
		}
3297
	} else if (!(sc->flags & PSM_FLAGS_FINGERDOWN) &&
3468
	} else if (!(sc->flags & PSM_FLAGS_FINGERDOWN) &&
3298
	    sc->synaction.in_taphold) {
3469
	    synaction->in_taphold) {
3299
		/*
3470
		/*
3300
		 * For a tap-hold to work, the button must remain down at
3471
		 * For a tap-hold to work, the button must remain down at
3301
		 * least until timeout (where the in_taphold flags will be
3472
		 * least until timeout (where the in_taphold flags will be
Lines 3302-3346 Link Here
3302
		 * cleared) or during the next action.
3473
		 * cleared) or during the next action.
3303
		 */
3474
		 */
3304
		if (timevalcmp(&sc->lastsoftintr, &sc->taptimeout, <=)) {
3475
		if (timevalcmp(&sc->lastsoftintr, &sc->taptimeout, <=)) {
3305
			ms->button |= sc->synaction.tap_button;
3476
			ms->button |= synaction->tap_button;
3306
		} else {
3477
		} else {
3307
			VLOG(2, (LOG_DEBUG,
3478
			VLOG(2, (LOG_DEBUG,
3308
			    "synaptics: button RELEASE: %d\n",
3479
			    "synaptics: button RELEASE: %d\n",
3309
			    sc->synaction.tap_button));
3480
			    synaction->tap_button));
3310
			sc->synaction.in_taphold = 0;
3481
			synaction->in_taphold = 0;
3311
		}
3482
		}
3312
	}
3483
	}
3313
3484
3314
SYNAPTICS_END:
3485
	return;
3486
}
3487
3488
static int
3489
psmsoftbuttons(struct psm_softc *sc, finger_t f, int pressed)
3490
{
3491
	static int button = 0;
3492
	int y_ok, center_button, center_x, right_button, right_x;
3493
3494
	/* Dont change clickpad softbutton after pressing */
3495
	if (pressed && !button) {
3496
		y_ok = sc->syninfo.softbuttons_y >= 0 ?
3497
		    f.y < sc->syninfo.softbuttons_y :
3498
		    f.y > sc->synhw.maximumYCoord - sc->syninfo.softbuttons_y;
3499
3500
		center_button = MOUSE_BUTTON2DOWN;
3501
		center_x = sc->syninfo.softbutton2_x;
3502
		right_button = MOUSE_BUTTON3DOWN;
3503
		right_x = sc->syninfo.softbutton3_x;
3504
3505
		if (center_x > 0 && right_x > 0 && center_x > right_x) {
3506
			center_button = MOUSE_BUTTON3DOWN;
3507
			center_x = sc->syninfo.softbutton3_x;
3508
			right_button = MOUSE_BUTTON2DOWN;
3509
			right_x = sc->syninfo.softbutton2_x;
3510
		}
3511
3512
		if (right_x > 0 && f.x > right_x && y_ok)
3513
			button = right_button;
3514
		else if (center_x > 0 && f.x > center_x && y_ok)
3515
			button = center_button;
3516
		else
3517
			button = MOUSE_BUTTON1DOWN;
3518
		VLOG(2, (LOG_DEBUG, "softbutton: PRESS: %d\n", button));
3519
	}
3520
3521
	/* Clickpad releases */
3522
	if (!pressed && button) {
3523
		VLOG(2, (LOG_DEBUG, "softbutton: RELEASE: %d\n", button));
3524
		button = 0;
3525
	}
3526
3527
	return (button);
3528
}
3529
3530
static int
3531
proc_elantech(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
3532
    int *x, int *y, int *z)
3533
{
3534
	static int touchpad_button, trackpoint_button;
3535
	static int v4nfingers = 0;
3536
	finger_t fn, f[PSM_GESTURE_FINGERS];
3537
	int pkt, id, scale, i, nfingers, reset_queue;
3538
3539
	if (!elantech_support)
3540
		return (0);
3541
3542
	/* Determine packet format and do a sanity check for out of sync packets. */
3543
	if (ELANTECH_PKT_IS_DEBOUNCE(pb, sc->elanhw.hwversion))
3544
		pkt = ELANTECH_PKT_NOP;
3545
	else if (ELANTECH_PKT_IS_TRACKPOINT(pb))
3546
		pkt = ELANTECH_PKT_TRACKPOINT;
3547
	else
3548
	switch (sc->elanhw.hwversion) {
3549
	case 2:
3550
		if (!ELANTECH_PKT_IS_V2(pb))
3551
			return (-1);
3552
3553
		pkt = (pb->ipacket[0] & 0xc0) == 0x80 ?
3554
		    ELANTECH_PKT_V2_2FINGER : ELANTECH_PKT_V2_COMMON;
3555
		break;
3556
	case 3:
3557
		if (!ELANTECH_PKT_IS_V3_HEAD(pb, sc->elanhw.hascrc) &&
3558
		    !ELANTECH_PKT_IS_V3_TAIL(pb, sc->elanhw.hascrc))
3559
			return (-1);
3560
3561
		pkt = ELANTECH_PKT_V3;
3562
		break;
3563
	case 4:
3564
		if (!ELANTECH_PKT_IS_V4(pb, sc->elanhw.hascrc))
3565
			return (-1);
3566
3567
		switch (pb->ipacket[3] & 0x03) {
3568
		case 0x00:
3569
			pkt = ELANTECH_PKT_V4_STATUS;
3570
			break;
3571
		case 0x01:
3572
			pkt = ELANTECH_PKT_V4_HEAD;
3573
			break;
3574
		case 0x02:
3575
			pkt = ELANTECH_PKT_V4_MOTION;
3576
			break;
3577
		default:
3578
			return (-1);
3579
		}
3580
		break;
3581
	default:
3582
		return (-1);
3583
	}
3584
3585
	VLOG(5, (LOG_DEBUG, "elantech: ipacket format: %d\n", pkt));
3586
3587
	for (id = 0; id < PSM_GESTURE_FINGERS; id++)
3588
		PSM_FINGER_RESET(f[id]);
3589
3590
	*x = *y = *z = 0;
3591
	ms->button = ms->obutton;
3592
3593
	if (sc->syninfo.touchpad_off)
3594
		return (0);
3595
3596
	/* Common legend
3597
	 * L: Left mouse button pressed
3598
	 * R: Right mouse button pressed
3599
	 * N: number of fingers on touchpad
3600
	 * X: absolute x value (horizontal)
3601
	 * Y: absolute y value (vertical)
3602
	 * W; width of the finger touch
3603
	 * P: pressure
3604
	 */
3605
	switch (pkt) {
3606
	case ELANTECH_PKT_V2_COMMON:	/* HW V2. One/Three finger touch */
3607
		/*               7   6   5   4   3   2   1   0 (LSB)
3608
		 * -------------------------------------------
3609
		 * ipacket[0]:  N1  N0  W3  W2   .   .   R   L
3610
		 * ipacket[1]:  P7  P6  P5  P4 X11 X10  X9  X8
3611
		 * ipacket[2]:  X7  X6  X5  X4  X3  X2  X1  X0
3612
		 * ipacket[3]:  N4  VF  W1  W0   .   .   .  B2
3613
		 * ipacket[4]:  P3  P1  P2  P0 Y11 Y10  Y9  Y8
3614
		 * ipacket[5]:  Y7  Y6  Y5  Y4  Y3  Y2  Y1  Y0
3615
		 * -------------------------------------------
3616
		 * N4: set if more than 3 fingers (only in 3 fingers mode)
3617
		 * VF: a kind of flag? (only on EF123, 0 when finger
3618
		 *     is over one of the buttons, 1 otherwise)
3619
		 * B2: (on EF113 only, 0 otherwise), one button pressed
3620
		 * P & W is not reported on EF113 touchpads
3621
		 */
3622
		nfingers = (pb->ipacket[0] & 0xc0) >> 6;
3623
3624
		fn = ELANTECH_FINGER_SET_XYP(pb);
3625
		if (sc->elanhw.haspressure) {
3626
			fn.w = ((pb->ipacket[0] & 0x30) >> 2) |
3627
			    ((pb->ipacket[3] & 0x30) >> 4);
3628
		} else {
3629
			fn.p = ELANTECH_FINGER_DEFAULT_P;
3630
			fn.w = ELANTECH_FINGER_DEFAULT_W;
3631
		}
3632
3633
		/*
3634
		 * HW v2 dont report exact finger positions when 3 or more
3635
		 * fingers are on touchpad. Use reported value as fingers
3636
		 * position as it is required for tap detection
3637
		 */
3638
		if (nfingers > 2) {
3639
			fn.flags = PSM_FINGER_FUZZY;
3640
			f[0] = f[1] = fn;
3641
		}
3642
3643
		id = nfingers - 1;
3644
		if (id >= 0 && id < PSM_GESTURE_FINGERS)
3645
			f[id] = fn;
3646
		break;
3647
3648
	case ELANTECH_PKT_V2_2FINGER:	/*HW V2. Two finger touch */
3649
		/*               7   6   5   4   3   2   1   0 (LSB)
3650
		 * -------------------------------------------
3651
		 * ipacket[0]:  N1  N0 AY8 AX8   .   .   R   L
3652
		 * ipacket[1]: AX7 AX6 AX5 AX4 AX3 AX2 AX1 AX0
3653
		 * ipacket[2]: AY7 AY6 AY5 AY4 AY3 AY2 AY1 AY0
3654
		 * ipacket[3]:   .   . BY8 BX8   .   .   .   .
3655
		 * ipacket[4]: BX7 BX6 BX5 BX4 BX3 BX2 BX1 BX0
3656
		 * ipacket[5]: BY7 BY6 BY5 BY4 BY3 BY2 BY1 BY0
3657
		 * -------------------------------------------
3658
		 * AX: lower-left finger absolute x value
3659
		 * AY: lower-left finger absolute y value
3660
		 * BX: upper-right finger absolute x value
3661
		 * BY: upper-right finger absolute y value
3662
		 */
3663
		nfingers = 2;
3664
3665
		VLOG(5, (LOG_DEBUG, "elantech: v2 BBX: [%d, %d] [%d, %d]\n",
3666
		    ((pb->ipacket[0] & 0x10) << 4) | pb->ipacket[1],
3667
		    ((pb->ipacket[0] & 0x20) << 3) | pb->ipacket[2],
3668
		    ((pb->ipacket[3] & 0x10) << 4) | pb->ipacket[4],
3669
		    ((pb->ipacket[3] & 0x20) << 3) | pb->ipacket[5]
3670
		));
3671
		for (id = 0; id < imin(2, PSM_GESTURE_FINGERS); id ++)
3672
			f[id] = (finger_t) {
3673
				.x = (((pb->ipacket[id * 3] & 0x10) << 4) |
3674
				    pb->ipacket[id * 3 + 1]) << 2,
3675
				.y = (((pb->ipacket[id * 3] & 0x20) << 3) |
3676
				    pb->ipacket[id * 3 + 2]) << 2,
3677
				.p = ELANTECH_FINGER_DEFAULT_P,
3678
				.w = ELANTECH_FINGER_DEFAULT_W,
3679
				/* HW ver.2 sends bounding box */
3680
				.flags = PSM_FINGER_FUZZY
3681
			};
3682
		break;
3683
3684
	case ELANTECH_PKT_V3:	/* HW Version 3 */
3685
		/*               7   6   5   4   3   2   1   0 (LSB)
3686
		 * -------------------------------------------
3687
		 * ipacket[0]:  N1  N0  W3  W2   0   1   R   L
3688
		 * ipacket[1]:  P7  P6  P5  P4 X11 X10  X9  X8
3689
		 * ipacket[2]:  X7  X6  X5  X4  X3  X2  X1  X0
3690
		 * ipacket[3]:   0   0  W1  W0   0   0   1   0
3691
		 * ipacket[4]:  P3  P1  P2  P0 Y11 Y10  Y9  Y8
3692
		 * ipacket[5]:  Y7  Y6  Y5  Y4  Y3  Y2  Y1  Y0
3693
		 * -------------------------------------------
3694
		 */
3695
		nfingers = (pb->ipacket[0] & 0xc0) >> 6;
3696
		id = nfingers - 1;
3697
3698
		fn = ELANTECH_FINGER_SET_XYP(pb);
3699
		fn.w = ((pb->ipacket[0] & 0x30) >> 2) |
3700
		    ((pb->ipacket[3] & 0x30) >> 4);
3701
3702
		/*
3703
		 * HW v3 dont report exact finger positions when 3 or more
3704
		 * fingers are on touchpad. Use reported value as fingers
3705
		 * position as it is required for tap detection
3706
		 */
3707
		if (nfingers > 2) {
3708
			fn.flags = PSM_FINGER_FUZZY;
3709
			f[0] = f[1] = fn;
3710
		}
3711
3712
		if (nfingers == 2 &&
3713
		    ELANTECH_PKT_IS_V3_HEAD(pb, sc->elanhw.hascrc))
3714
			id = 0;
3715
3716
		if (id >= 0 && id < PSM_GESTURE_FINGERS) {
3717
			f[id] = fn;
3718
		}
3719
		break;
3720
3721
	case ELANTECH_PKT_V4_STATUS:	/* HW Version 4. Status packet */
3722
		/*               7   6   5   4   3   2   1   0 (LSB)
3723
		 * -------------------------------------------
3724
		 * ipacket[0]:   .   .   .   .   0   1   R   L
3725
		 * ipacket[1]:   .   .   .  F4  F3  F2  F1  F0
3726
		 * ipacket[2]:   .   .   .   .   .   .   .   .
3727
		 * ipacket[3]:   .   .   .   1   0   0   0   0
3728
		 * ipacket[4]:  PL   .   .   .   .   .   .   .
3729
		 * ipacket[5]:   .   .   .   .   .   .   .   .
3730
		 * -------------------------------------------
3731
		 * Fn: finger n is on touchpad
3732
		 * PL: palm
3733
		 * HV ver4 sends a status packet to indicate that the numbers
3734
		 * or identities of the fingers has been changed
3735
		 */
3736
3737
		v4nfingers = fls(pb->ipacket[1] & 0x1f);
3738
3739
		if (v4nfingers > sc->elanaction.nfingers)
3740
			return (0);
3741
3742
		nfingers = v4nfingers;
3743
3744
		break;
3745
3746
	case ELANTECH_PKT_V4_HEAD:	/* HW Version 4. Head packet */
3747
		/*               7   6   5   4   3   2   1   0 (LSB)
3748
		 * -------------------------------------------
3749
		 * ipacket[0]:  W3  W2  W1  W0   0   1   R   L
3750
		 * ipacket[1]:  P7  P6  P5  P4 X11 X10  X9  X8
3751
		 * ipacket[2]:  X7  X6  X5  X4  X3  X2  X1  X0
3752
		 * ipacket[3]: ID2 ID1 ID0   1   0   0   0   1
3753
		 * ipacket[4]:  P3  P1  P2  P0 Y11 Y10  Y9  Y8
3754
		 * ipacket[5]:  Y7  Y6  Y5  Y4  Y3  Y2  Y1  Y0
3755
		 * -------------------------------------------
3756
		 * ID: finger id
3757
		 * HW ver 4 sends head packets in two cases:
3758
		 * 1. One finger touch and movement.
3759
		 * 2. Next after status packet to tell new finger positions.
3760
		 */
3761
		nfingers = v4nfingers;
3762
		id = ((pb->ipacket[3] & 0xe0) >> 5) - 1;
3763
3764
		if (id >= 0 && id < PSM_GESTURE_FINGERS) {
3765
			f[id] = ELANTECH_FINGER_SET_XYP(pb);
3766
			f[id].w = (pb->ipacket[0] & 0xf0) >> 4;
3767
		}
3768
		break;
3769
3770
	case ELANTECH_PKT_V4_MOTION:	/* HW Version 4. Motion packet */
3771
		/*               7   6   5   4   3   2   1   0 (LSB)
3772
		 * -------------------------------------------
3773
		 * ipacket[0]: ID2 ID1 ID0  OF   0   1   R   L
3774
		 * ipacket[1]: DX7 DX6 DX5 DX4 DX3 DX2 DX1 DX0
3775
		 * ipacket[2]: DY7 DY6 DY5 DY4 DY3 DY2 DY1 DY0
3776
		 * ipacket[3]: ID2 ID1 ID0   1   0   0   1   0
3777
		 * ipacket[4]: DX7 DX6 DX5 DX4 DX3 DX2 DX1 DX0
3778
		 * ipacket[5]: DY7 DY6 DY5 DY4 DY3 DY2 DY1 DY0
3779
		 * -------------------------------------------
3780
		 * OF: delta overflows (> 127 or < -128), in this case
3781
		 *     firmware sends us (delta x / 5) and (delta y / 5)
3782
		 * ID: finger id
3783
		 * DX: delta x (two's complement)
3784
		 * XY: delta y (two's complement)
3785
		 * byte 0 ~ 2 for one finger
3786
		 * byte 3 ~ 5 for another finger
3787
		 */
3788
		nfingers = v4nfingers;
3789
3790
		scale = (pb->ipacket[0] & 0x10) ? 5 : 1;
3791
		for (i = 0; i <= 3; i += 3) {
3792
			id = ((pb->ipacket[i] & 0xe0) >> 5) - 1;
3793
			if (id < 0 || id >= PSM_GESTURE_FINGERS)
3794
				continue;
3795
3796
			if (PSM_FINGER_IS_SET(sc->elanaction.fingers[id])) {
3797
				f[id] = sc->elanaction.fingers[id];
3798
				f[id].x += imax(-f[id].x,
3799
				    (signed char)pb->ipacket[i+1] * scale);
3800
				f[id].y += imax(-f[id].y,
3801
				    (signed char)pb->ipacket[i+2] * scale);
3802
			} else {
3803
				VLOG(3, (LOG_DEBUG, "elantech: "
3804
				    "HW v4 motion packet skipped\n"));
3805
			}
3806
		}
3807
3808
		break;
3809
3810
	case ELANTECH_PKT_TRACKPOINT:
3811
		/*               7   6   5   4   3   2   1   0 (LSB)
3812
		 * -------------------------------------------
3813
		 * ipacket[0]:   0   0  SX  SY   0   M   R   L
3814
		 * ipacket[1]: ~SX   0   0   0   0   0   0   0
3815
		 * ipacket[2]: ~SY   0   0   0   0   0   0   0
3816
		 * ipacket[3]:   0   0 ~SY ~SX   0   1   1   0
3817
		 * ipacket[4]:  X7  X6  X5  X4  X3  X2  X1  X0
3818
		 * ipacket[5]:  Y7  Y6  Y5  Y4  Y3  Y2  Y1  Y0
3819
		 * -------------------------------------------
3820
		 * X and Y are written in two's complement spread
3821
		 * over 9 bits with SX/SY the relative top bit and
3822
		 * X7..X0 and Y7..Y0 the lower bits.
3823
		 */
3824
		*x = (pb->ipacket[0] & 0x20) ?
3825
		    pb->ipacket[4] - 256 : pb->ipacket[4];
3826
		*y = (pb->ipacket[0] & 0x10) ?
3827
		    pb->ipacket[5] - 256 : pb->ipacket[5];
3828
3829
		trackpoint_button =
3830
		    ((pb->ipacket[0] & 0x01) ? MOUSE_BUTTON1DOWN : 0) |
3831
		    ((pb->ipacket[0] & 0x02) ? MOUSE_BUTTON3DOWN : 0) |
3832
		    ((pb->ipacket[0] & 0x04) ? MOUSE_BUTTON2DOWN : 0);
3833
3834
		ms->button = touchpad_button | trackpoint_button;
3835
		return (0);
3836
3837
	case ELANTECH_PKT_NOP:
3838
		return (0);
3839
3840
	default:
3841
		return (-1);
3842
	}
3843
3844
	for (id = 0; id < PSM_GESTURE_FINGERS; id++)
3845
		if (PSM_FINGER_IS_SET(f[id]))
3846
			VLOG(2, (LOG_DEBUG, "elantech: "
3847
			    "finger %d: down [%d, %d], %d, %d, %d\n", id + 1,
3848
			    f[id].x, f[id].y, f[id].p, f[id].w, f[id].flags));
3849
3850
	/* Touchpad button presses */
3851
	if (sc->elanhw.isclickpad) {
3852
		touchpad_button =
3853
		    psmsoftbuttons(sc, f[0], pb->ipacket[0] & 0x03);
3854
	} else {
3855
		touchpad_button =
3856
		    ((pb->ipacket[0] & 0x01) ? MOUSE_BUTTON1DOWN : 0) |
3857
		    ((pb->ipacket[0] & 0x02) ? MOUSE_BUTTON3DOWN : 0);
3858
	}
3859
3860
	ms->button = touchpad_button | trackpoint_button;
3861
3315
	/*
3862
	/*
3316
	 * Use the extra buttons as a scrollwheel
3863
	 * Send finger positions to movement smoother.
3317
	 *
3864
	 * Try to avoid nonreenterable code paths of movement smoother
3318
	 * XXX X.Org uses the Z axis for vertical wheel only,
3865
	 * like initialization and tap processing for 2nd finger.
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
	 */
3866
	 */
3867
	for (id = 0; id < PSM_GESTURE_FINGERS; id++) {
3329
3868
3330
	if (ms->button & MOUSE_BUTTON4DOWN) {
3869
		if (!(PSM_FINGER_IS_SET(f[id]) || (id == 0 && nfingers == 0)))
3870
			continue;
3871
		if (id == 1 && sc->syninfo.two_finger_scroll == 0)
3872
			continue;
3873
3874
		reset_queue = 0;
3875
3876
		/* Avoid cursor jumping on switching real<->fuzzy position */
3877
		if (PSM_FINGER_IS_SET(f[id]) &&
3878
		    ((f[id].flags & PSM_FINGER_FUZZY) !=
3879
		     (sc->elanaction.fingers[id].flags & PSM_FINGER_FUZZY)))
3880
			reset_queue = 1;
3881
3882
		/* Reset 2-nd finger synaction queue on action start */
3883
		if (id > 0 && !PSM_FINGER_IS_SET(sc->elanaction.fingers[id])) {
3884
			reset_queue = 1;
3885
		}
3886
3887
		if (reset_queue) {
3888
			VLOG(3, (LOG_DEBUG, "elantech: "
3889
			    "finger %d: reset synaptics queue\n", id + 1));
3890
			sc->synaction[id].queue_cursor = 0;
3891
			sc->synaction[id].queue_len = 0;
3892
			sc->synaction[id].queue[0].x = f[id].x;
3893
			sc->synaction[id].queue[0].y = f[id].y;
3894
			sc->synaction[id].start_x = f[id].x;
3895
			sc->synaction[id].start_y = f[id].y;
3896
			sc->synaction[id].window_min = sc->syninfo.window_min;
3897
			sc->synaction[id].squelch_x = 0;
3898
			sc->synaction[id].squelch_y = 0;
3899
			sc->synaction[id].avg_dx = 0;
3900
			sc->synaction[id].avg_dy = 0;
3901
			sc->synaction[id].fingers_nb = 0;
3902
			sc->synaction[id].in_vscroll = 0;
3903
		}
3904
3905
		/* prevent palm detection for fuzzy finger touches */
3906
		if (f[id].flags & PSM_FINGER_FUZZY) {
3907
			f[id].p = ELANTECH_FINGER_DEFAULT_P;
3908
			f[id].w = ELANTECH_FINGER_DEFAULT_W;
3909
		}
3910
3911
		psmgestures(sc, &sc->synaction[id], f[id], imin(nfingers, 3),
3912
		    ms, x, y);
3913
	}
3914
3915
	/* Store current finger positions in action context */
3916
	sc->elanaction.nfingers = nfingers;
3917
	for (id = 0; id < PSM_GESTURE_FINGERS; id++) {
3918
		if (PSM_FINGER_IS_SET(f[id]))
3919
			sc->elanaction.fingers[id] = f[id];
3920
		if (id >= nfingers)
3921
			PSM_FINGER_RESET(sc->elanaction.fingers[id]);
3922
	}
3923
3924
	/* Use the extra buttons as a scrollwheel */
3925
	if (ms->button & MOUSE_BUTTON4DOWN)
3331
		*z = -1;
3926
		*z = -1;
3332
		ms->button &= ~MOUSE_BUTTON4DOWN;
3927
	else if (ms->button & MOUSE_BUTTON5DOWN)
3333
	} else if (ms->button & MOUSE_BUTTON5DOWN) {
3334
		*z = 1;
3928
		*z = 1;
3335
		ms->button &= ~MOUSE_BUTTON5DOWN;
3929
	else if (ms->button & MOUSE_BUTTON6DOWN)
3336
	} else if (ms->button & MOUSE_BUTTON6DOWN) {
3337
		*z = -2;
3930
		*z = -2;
3338
		ms->button &= ~MOUSE_BUTTON6DOWN;
3931
	else if (ms->button & MOUSE_BUTTON7DOWN)
3339
	} else if (ms->button & MOUSE_BUTTON7DOWN) {
3340
		*z = 2;
3932
		*z = 2;
3341
		ms->button &= ~MOUSE_BUTTON7DOWN;
3933
	else
3342
	} else
3343
		*z = 0;
3934
		*z = 0;
3935
	ms->button &= ~(MOUSE_BUTTON4DOWN | MOUSE_BUTTON5DOWN |
3936
	    MOUSE_BUTTON6DOWN | MOUSE_BUTTON7DOWN);
3344
3937
3345
	return (0);
3938
	return (0);
3346
}
3939
}
Lines 3413-3418 Link Here
3413
}
4006
}
3414
4007
3415
static void
4008
static void
4009
psmsoftintridle(void *arg)
4010
{
4011
	struct psm_softc *sc = arg;
4012
	packetbuf_t *pb;
4013
4014
	/* Invoke soft handler only when pqueue is empty. Otherwise it will be
4015
	 * invoked from psmintr soon with pqueue filled with real data */
4016
	if (sc->pqueue_start == sc->pqueue_end &&
4017
	    sc->idlepacket.inputbytes > 0) {
4018
		/* Grow circular queue backwards to avoid race with psmintr */
4019
		if (--sc->pqueue_start < 0)
4020
			sc->pqueue_start = PSM_PACKETQUEUE - 1;
4021
4022
		pb = &sc->pqueue[sc->pqueue_start];
4023
		memcpy(pb, &sc->idlepacket, sizeof(packetbuf_t));
4024
		VLOG(4, (LOG_DEBUG,
4025
		    "psmsoftintridle: %02x %02x %02x %02x %02x %02x\n",
4026
		    pb->ipacket[0], pb->ipacket[1], pb->ipacket[2],
4027
		    pb->ipacket[3], pb->ipacket[4], pb->ipacket[5]));
4028
4029
		psmsoftintr(arg);
4030
	}
4031
}
4032
4033
static void
3416
psmsoftintr(void *arg)
4034
psmsoftintr(void *arg)
3417
{
4035
{
3418
	/*
4036
	/*
Lines 3465-3470 Link Here
3465
		if (sc->config & PSM_CONFIG_FORCETAP)
4083
		if (sc->config & PSM_CONFIG_FORCETAP)
3466
			ms.button |= ((c & MOUSE_PS2_TAP)) ?
4084
			ms.button |= ((c & MOUSE_PS2_TAP)) ?
3467
			    0 : MOUSE_BUTTON4DOWN;
4085
			    0 : MOUSE_BUTTON4DOWN;
4086
		timevalclear(&sc->idletimeout);
4087
		sc->idlepacket.inputbytes = 0;
3468
4088
3469
		switch (sc->hw.model) {
4089
		switch (sc->hw.model) {
3470
4090
Lines 3603-3608 Link Here
3603
				goto next;
4223
				goto next;
3604
			break;
4224
			break;
3605
4225
4226
		case MOUSE_MODEL_ELANTECH:
4227
			if (proc_elantech(sc, pb, &ms, &x, &y, &z) != 0)
4228
				goto next;
4229
			break;
4230
3606
		case MOUSE_MODEL_TRACKPOINT:
4231
		case MOUSE_MODEL_TRACKPOINT:
3607
		case MOUSE_MODEL_GENERIC:
4232
		case MOUSE_MODEL_GENERIC:
3608
		default:
4233
		default:
Lines 3627-3632 Link Here
3627
		}
4252
		}
3628
	}
4253
	}
3629
4254
4255
	/* Store last packet for reinjection if it has not been set already */
4256
	if (timevalisset(&sc->idletimeout) && sc->idlepacket.inputbytes == 0)
4257
		sc->idlepacket = *pb;
4258
3630
	ms.dx = x;
4259
	ms.dx = x;
3631
	ms.dy = y;
4260
	ms.dy = y;
3632
	ms.dz = z;
4261
	ms.dz = z;
Lines 3673-3678 Link Here
3673
		pgsigio(&sc->async, SIGIO, 0);
4302
		pgsigio(&sc->async, SIGIO, 0);
3674
	}
4303
	}
3675
	sc->state &= ~PSM_SOFTARMED;
4304
	sc->state &= ~PSM_SOFTARMED;
4305
4306
	/* schedule injection of predefined packet after idletimeout
4307
	 * if no data packets have been received from psmintr */
4308
	if (timevalisset(&sc->idletimeout)) {
4309
		sc->state |= PSM_SOFTARMED;
4310
		callout_reset(&sc->softcallout, tvtohz(&sc->idletimeout),
4311
		    psmsoftintridle, sc);
4312
		VLOG(2, (LOG_DEBUG, "softintr: callout set: %d ticks\n",
4313
		    tvtohz(&sc->idletimeout)));
4314
	}
3676
	splx(s);
4315
	splx(s);
3677
}
4316
}
3678
4317
Lines 4106-4115 Link Here
4106
static int
4745
static int
4107
synaptics_sysctl(SYSCTL_HANDLER_ARGS)
4746
synaptics_sysctl(SYSCTL_HANDLER_ARGS)
4108
{
4747
{
4748
	struct psm_softc *sc;
4109
	int error, arg;
4749
	int error, arg;
4110
4750
4751
	if (oidp->oid_arg1 == NULL || oidp->oid_arg2 < 0 ||
4752
	    oidp->oid_arg2 > SYNAPTICS_SYSCTL_SOFTBUTTON_NOMOVE)
4753
		return (EINVAL);
4754
4755
	sc = oidp->oid_arg1;
4756
4111
	/* Read the current value. */
4757
	/* Read the current value. */
4112
	arg = *(int *)oidp->oid_arg1;
4758
	arg = *(int *)((char *)sc + oidp->oid_arg2);
4113
	error = sysctl_handle_int(oidp, &arg, 0, req);
4759
	error = sysctl_handle_int(oidp, &arg, 0, req);
4114
4760
4115
	/* Sanity check. */
4761
	/* Sanity check. */
Lines 4131-4144 Link Here
4131
			return (EINVAL);
4777
			return (EINVAL);
4132
		break;
4778
		break;
4133
	case SYNAPTICS_SYSCTL_MARGIN_TOP:
4779
	case SYNAPTICS_SYSCTL_MARGIN_TOP:
4780
	case SYNAPTICS_SYSCTL_MARGIN_BOTTOM:
4781
	case SYNAPTICS_SYSCTL_NA_TOP:
4782
	case SYNAPTICS_SYSCTL_NA_BOTTOM:
4783
		if (arg < 0 || arg > sc->synhw.maximumYCoord)
4784
			return (EINVAL);
4785
		break;
4134
	case SYNAPTICS_SYSCTL_MARGIN_RIGHT:
4786
	case SYNAPTICS_SYSCTL_MARGIN_RIGHT:
4135
	case SYNAPTICS_SYSCTL_MARGIN_BOTTOM:
4136
	case SYNAPTICS_SYSCTL_MARGIN_LEFT:
4787
	case SYNAPTICS_SYSCTL_MARGIN_LEFT:
4137
	case SYNAPTICS_SYSCTL_NA_TOP:
4138
	case SYNAPTICS_SYSCTL_NA_RIGHT:
4788
	case SYNAPTICS_SYSCTL_NA_RIGHT:
4139
	case SYNAPTICS_SYSCTL_NA_BOTTOM:
4140
	case SYNAPTICS_SYSCTL_NA_LEFT:
4789
	case SYNAPTICS_SYSCTL_NA_LEFT:
4141
		if (arg < 0 || arg > 6143)
4790
	case SYNAPTICS_SYSCTL_SOFTBUTTON2_X:
4791
	case SYNAPTICS_SYSCTL_SOFTBUTTON3_X:
4792
		if (arg < 0 || arg > sc->synhw.maximumXCoord)
4142
			return (EINVAL);
4793
			return (EINVAL);
4143
		break;
4794
		break;
4144
	case SYNAPTICS_SYSCTL_WINDOW_MIN:
4795
	case SYNAPTICS_SYSCTL_WINDOW_MIN:
Lines 4168-4193 Link Here
4168
			return (EINVAL);
4819
			return (EINVAL);
4169
		break;
4820
		break;
4170
	case SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA:
4821
	case SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA:
4822
		if (arg < -sc->synhw.maximumXCoord ||
4823
		    arg > sc->synhw.maximumXCoord)
4824
			return (EINVAL);
4825
		break;
4171
	case SYNAPTICS_SYSCTL_VSCROLL_VER_AREA:
4826
	case SYNAPTICS_SYSCTL_VSCROLL_VER_AREA:
4172
		if (arg < -6143 || arg > 6143)
4827
	case SYNAPTICS_SYSCTL_SOFTBUTTONS_Y:
4828
		if (arg < -sc->synhw.maximumYCoord ||
4829
		    arg > sc->synhw.maximumYCoord)
4173
			return (EINVAL);
4830
			return (EINVAL);
4174
		break;
4831
		break;
4175
        case SYNAPTICS_SYSCTL_TOUCHPAD_OFF:
4832
        case SYNAPTICS_SYSCTL_TOUCHPAD_OFF:
4833
	case SYNAPTICS_SYSCTL_SOFTBUTTON_NOMOVE:
4176
		if (arg < 0 || arg > 1)
4834
		if (arg < 0 || arg > 1)
4177
			return (EINVAL);
4835
			return (EINVAL);
4178
		break;
4836
		break;
4837
	case SYNAPTICS_SYSCTL_SOFTBUTTONS:
4838
		/* Softbuttons is clickpad only feature */
4839
		if (!sc->synhw.capClickPad && arg != 0)
4840
			return (EINVAL);
4841
		/* Set predefined sizes for softbuttons */
4842
		switch (arg) {
4843
		case 3:
4844
			sc->syninfo.softbutton3_x =
4845
			    sc->synhw.maximumXCoord * 2 / 3;
4846
			sc->syninfo.softbutton2_x =
4847
			    sc->synhw.maximumXCoord / 3;
4848
			sc->syninfo.softbuttons_y =
4849
			    sc->synhw.maximumYCoord / 4;
4850
			break;
4851
		case 2:
4852
			sc->syninfo.softbutton3_x =
4853
			    sc->synhw.maximumXCoord / 2;
4854
			sc->syninfo.softbutton2_x = 0;
4855
			sc->syninfo.softbuttons_y =
4856
			    sc->synhw.maximumYCoord / 4;
4857
			break;
4858
		case 1:
4859
		case 0:
4860
			sc->syninfo.softbutton3_x = 0;
4861
			sc->syninfo.softbutton2_x = 0;
4862
			sc->syninfo.softbuttons_y = 0;
4863
			break;
4864
		default:
4865
			return (EINVAL);
4866
		}
4867
		break;
4179
	default:
4868
	default:
4180
		return (EINVAL);
4869
		return (EINVAL);
4181
	}
4870
	}
4182
4871
4183
	/* Update. */
4872
	/* Update. */
4184
	*(int *)oidp->oid_arg1 = arg;
4873
	*(int *)((char *)sc + oidp->oid_arg2) = arg;
4185
4874
4186
	return (error);
4875
	return (error);
4187
}
4876
}
4188
4877
4189
static void
4878
static void
4190
synaptics_sysctl_create_tree(struct psm_softc *sc)
4879
synaptics_sysctl_create_tree(struct psm_softc *sc, const char *name,
4880
    const char *descr)
4191
{
4881
{
4192
4882
4193
	if (sc->syninfo.sysctl_tree != NULL)
4883
	if (sc->syninfo.sysctl_tree != NULL)
Lines 4196-4203 Link Here
4196
	/* Attach extra synaptics sysctl nodes under hw.psm.synaptics */
4886
	/* Attach extra synaptics sysctl nodes under hw.psm.synaptics */
4197
	sysctl_ctx_init(&sc->syninfo.sysctl_ctx);
4887
	sysctl_ctx_init(&sc->syninfo.sysctl_ctx);
4198
	sc->syninfo.sysctl_tree = SYSCTL_ADD_NODE(&sc->syninfo.sysctl_ctx,
4888
	sc->syninfo.sysctl_tree = SYSCTL_ADD_NODE(&sc->syninfo.sysctl_ctx,
4199
	    SYSCTL_STATIC_CHILDREN(_hw_psm), OID_AUTO, "synaptics", CTLFLAG_RD,
4889
	    SYSCTL_STATIC_CHILDREN(_hw_psm), OID_AUTO, name, CTLFLAG_RD,
4200
	    0, "Synaptics TouchPad");
4890
	    0, descr);
4201
4891
4202
	/* hw.psm.synaptics.directional_scrolls. */
4892
	/* hw.psm.synaptics.directional_scrolls. */
4203
	sc->syninfo.directional_scrolls = 0;
4893
	sc->syninfo.directional_scrolls = 0;
Lines 4230-4236 Link Here
4230
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4920
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4231
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4921
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4232
	    "min_pressure", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4922
	    "min_pressure", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4233
	    &sc->syninfo.min_pressure, SYNAPTICS_SYSCTL_MIN_PRESSURE,
4923
	    sc, SYNAPTICS_SYSCTL_MIN_PRESSURE,
4234
	    synaptics_sysctl, "I",
4924
	    synaptics_sysctl, "I",
4235
	    "Minimum pressure required to start an action");
4925
	    "Minimum pressure required to start an action");
4236
4926
Lines 4239-4245 Link Here
4239
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4929
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4240
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4930
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4241
	    "max_pressure", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4931
	    "max_pressure", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4242
	    &sc->syninfo.max_pressure, SYNAPTICS_SYSCTL_MAX_PRESSURE,
4932
	    sc, SYNAPTICS_SYSCTL_MAX_PRESSURE,
4243
	    synaptics_sysctl, "I",
4933
	    synaptics_sysctl, "I",
4244
	    "Maximum pressure to detect palm");
4934
	    "Maximum pressure to detect palm");
4245
4935
Lines 4248-4254 Link Here
4248
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4938
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4249
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4939
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4250
	    "max_width", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4940
	    "max_width", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4251
	    &sc->syninfo.max_width, SYNAPTICS_SYSCTL_MAX_WIDTH,
4941
	    sc, SYNAPTICS_SYSCTL_MAX_WIDTH,
4252
	    synaptics_sysctl, "I",
4942
	    synaptics_sysctl, "I",
4253
	    "Maximum finger width to detect palm");
4943
	    "Maximum finger width to detect palm");
4254
4944
Lines 4257-4263 Link Here
4257
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4947
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4258
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4948
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4259
	    "margin_top", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4949
	    "margin_top", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4260
	    &sc->syninfo.margin_top, SYNAPTICS_SYSCTL_MARGIN_TOP,
4950
	    sc, SYNAPTICS_SYSCTL_MARGIN_TOP,
4261
	    synaptics_sysctl, "I",
4951
	    synaptics_sysctl, "I",
4262
	    "Top margin");
4952
	    "Top margin");
4263
4953
Lines 4266-4272 Link Here
4266
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4956
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4267
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4957
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4268
	    "margin_right", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4958
	    "margin_right", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4269
	    &sc->syninfo.margin_right, SYNAPTICS_SYSCTL_MARGIN_RIGHT,
4959
	    sc, SYNAPTICS_SYSCTL_MARGIN_RIGHT,
4270
	    synaptics_sysctl, "I",
4960
	    synaptics_sysctl, "I",
4271
	    "Right margin");
4961
	    "Right margin");
4272
4962
Lines 4275-4281 Link Here
4275
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4965
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4276
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4966
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4277
	    "margin_bottom", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4967
	    "margin_bottom", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4278
	    &sc->syninfo.margin_bottom, SYNAPTICS_SYSCTL_MARGIN_BOTTOM,
4968
	    sc, SYNAPTICS_SYSCTL_MARGIN_BOTTOM,
4279
	    synaptics_sysctl, "I",
4969
	    synaptics_sysctl, "I",
4280
	    "Bottom margin");
4970
	    "Bottom margin");
4281
4971
Lines 4284-4290 Link Here
4284
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4974
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4285
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4975
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4286
	    "margin_left", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4976
	    "margin_left", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4287
	    &sc->syninfo.margin_left, SYNAPTICS_SYSCTL_MARGIN_LEFT,
4977
	    sc, SYNAPTICS_SYSCTL_MARGIN_LEFT,
4288
	    synaptics_sysctl, "I",
4978
	    synaptics_sysctl, "I",
4289
	    "Left margin");
4979
	    "Left margin");
4290
4980
Lines 4293-4299 Link Here
4293
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4983
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4294
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4984
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4295
	    "na_top", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4985
	    "na_top", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4296
	    &sc->syninfo.na_top, SYNAPTICS_SYSCTL_NA_TOP,
4986
	    sc, SYNAPTICS_SYSCTL_NA_TOP,
4297
	    synaptics_sysctl, "I",
4987
	    synaptics_sysctl, "I",
4298
	    "Top noisy area, where weight_previous_na is used instead "
4988
	    "Top noisy area, where weight_previous_na is used instead "
4299
	    "of weight_previous");
4989
	    "of weight_previous");
Lines 4303-4309 Link Here
4303
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4993
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4304
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4994
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4305
	    "na_right", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4995
	    "na_right", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4306
	    &sc->syninfo.na_right, SYNAPTICS_SYSCTL_NA_RIGHT,
4996
	    sc, SYNAPTICS_SYSCTL_NA_RIGHT,
4307
	    synaptics_sysctl, "I",
4997
	    synaptics_sysctl, "I",
4308
	    "Right noisy area, where weight_previous_na is used instead "
4998
	    "Right noisy area, where weight_previous_na is used instead "
4309
	    "of weight_previous");
4999
	    "of weight_previous");
Lines 4313-4319 Link Here
4313
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5003
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4314
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5004
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4315
	    "na_bottom", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5005
	    "na_bottom", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4316
	    &sc->syninfo.na_bottom, SYNAPTICS_SYSCTL_NA_BOTTOM,
5006
	    sc, SYNAPTICS_SYSCTL_NA_BOTTOM,
4317
	    synaptics_sysctl, "I",
5007
	    synaptics_sysctl, "I",
4318
	    "Bottom noisy area, where weight_previous_na is used instead "
5008
	    "Bottom noisy area, where weight_previous_na is used instead "
4319
	    "of weight_previous");
5009
	    "of weight_previous");
Lines 4323-4329 Link Here
4323
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5013
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4324
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5014
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4325
	    "na_left", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5015
	    "na_left", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4326
	    &sc->syninfo.na_left, SYNAPTICS_SYSCTL_NA_LEFT,
5016
	    sc, SYNAPTICS_SYSCTL_NA_LEFT,
4327
	    synaptics_sysctl, "I",
5017
	    synaptics_sysctl, "I",
4328
	    "Left noisy area, where weight_previous_na is used instead "
5018
	    "Left noisy area, where weight_previous_na is used instead "
4329
	    "of weight_previous");
5019
	    "of weight_previous");
Lines 4333-4339 Link Here
4333
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5023
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4334
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5024
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4335
	    "window_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5025
	    "window_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4336
	    &sc->syninfo.window_min, SYNAPTICS_SYSCTL_WINDOW_MIN,
5026
	    sc, SYNAPTICS_SYSCTL_WINDOW_MIN,
4337
	    synaptics_sysctl, "I",
5027
	    synaptics_sysctl, "I",
4338
	    "Minimum window size to start an action");
5028
	    "Minimum window size to start an action");
4339
5029
Lines 4342-4348 Link Here
4342
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5032
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4343
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5033
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4344
	    "window_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5034
	    "window_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4345
	    &sc->syninfo.window_max, SYNAPTICS_SYSCTL_WINDOW_MAX,
5035
	    sc, SYNAPTICS_SYSCTL_WINDOW_MAX,
4346
	    synaptics_sysctl, "I",
5036
	    synaptics_sysctl, "I",
4347
	    "Maximum window size");
5037
	    "Maximum window size");
4348
5038
Lines 4351-4357 Link Here
4351
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5041
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4352
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5042
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4353
	    "multiplicator", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5043
	    "multiplicator", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4354
	    &sc->syninfo.multiplicator, SYNAPTICS_SYSCTL_MULTIPLICATOR,
5044
	    sc, SYNAPTICS_SYSCTL_MULTIPLICATOR,
4355
	    synaptics_sysctl, "I",
5045
	    synaptics_sysctl, "I",
4356
	    "Multiplicator to increase precision in averages and divisions");
5046
	    "Multiplicator to increase precision in averages and divisions");
4357
5047
Lines 4360-4366 Link Here
4360
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5050
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4361
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5051
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4362
	    "weight_current", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5052
	    "weight_current", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4363
	    &sc->syninfo.weight_current, SYNAPTICS_SYSCTL_WEIGHT_CURRENT,
5053
	    sc, SYNAPTICS_SYSCTL_WEIGHT_CURRENT,
4364
	    synaptics_sysctl, "I",
5054
	    synaptics_sysctl, "I",
4365
	    "Weight of the current movement in the new average");
5055
	    "Weight of the current movement in the new average");
4366
5056
Lines 4369-4375 Link Here
4369
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5059
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4370
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5060
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4371
	    "weight_previous", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5061
	    "weight_previous", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4372
	    &sc->syninfo.weight_previous, SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS,
5062
	    sc, SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS,
4373
	    synaptics_sysctl, "I",
5063
	    synaptics_sysctl, "I",
4374
	    "Weight of the previous average");
5064
	    "Weight of the previous average");
4375
5065
Lines 4378-4385 Link Here
4378
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5068
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4379
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5069
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4380
	    "weight_previous_na", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5070
	    "weight_previous_na", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4381
	    &sc->syninfo.weight_previous_na,
5071
	    sc, SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS_NA,
4382
	    SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS_NA,
4383
	    synaptics_sysctl, "I",
5072
	    synaptics_sysctl, "I",
4384
	    "Weight of the previous average (inside the noisy area)");
5073
	    "Weight of the previous average (inside the noisy area)");
4385
5074
Lines 4388-4395 Link Here
4388
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5077
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4389
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5078
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4390
	    "weight_len_squared", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5079
	    "weight_len_squared", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4391
	    &sc->syninfo.weight_len_squared,
5080
	    sc, SYNAPTICS_SYSCTL_WEIGHT_LEN_SQUARED,
4392
	    SYNAPTICS_SYSCTL_WEIGHT_LEN_SQUARED,
4393
	    synaptics_sysctl, "I",
5081
	    synaptics_sysctl, "I",
4394
	    "Length (squared) of segments where weight_previous "
5082
	    "Length (squared) of segments where weight_previous "
4395
	    "starts to decrease");
5083
	    "starts to decrease");
Lines 4399-4405 Link Here
4399
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5087
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4400
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5088
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4401
	    "div_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5089
	    "div_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4402
	    &sc->syninfo.div_min, SYNAPTICS_SYSCTL_DIV_MIN,
5090
	    sc, SYNAPTICS_SYSCTL_DIV_MIN,
4403
	    synaptics_sysctl, "I",
5091
	    synaptics_sysctl, "I",
4404
	    "Divisor for fast movements");
5092
	    "Divisor for fast movements");
4405
5093
Lines 4408-4414 Link Here
4408
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5096
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4409
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5097
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4410
	    "div_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5098
	    "div_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4411
	    &sc->syninfo.div_max, SYNAPTICS_SYSCTL_DIV_MAX,
5099
	    sc, SYNAPTICS_SYSCTL_DIV_MAX,
4412
	    synaptics_sysctl, "I",
5100
	    synaptics_sysctl, "I",
4413
	    "Divisor for slow movements");
5101
	    "Divisor for slow movements");
4414
5102
Lines 4417-4423 Link Here
4417
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5105
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4418
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5106
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4419
	    "div_max_na", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5107
	    "div_max_na", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4420
	    &sc->syninfo.div_max_na, SYNAPTICS_SYSCTL_DIV_MAX_NA,
5108
	    sc, SYNAPTICS_SYSCTL_DIV_MAX_NA,
4421
	    synaptics_sysctl, "I",
5109
	    synaptics_sysctl, "I",
4422
	    "Divisor with slow movements (inside the noisy area)");
5110
	    "Divisor with slow movements (inside the noisy area)");
4423
5111
Lines 4426-4432 Link Here
4426
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5114
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4427
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5115
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4428
	    "div_len", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5116
	    "div_len", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4429
	    &sc->syninfo.div_len, SYNAPTICS_SYSCTL_DIV_LEN,
5117
	    sc, SYNAPTICS_SYSCTL_DIV_LEN,
4430
	    synaptics_sysctl, "I",
5118
	    synaptics_sysctl, "I",
4431
	    "Length of segments where div_max starts to decrease");
5119
	    "Length of segments where div_max starts to decrease");
4432
5120
Lines 4435-4441 Link Here
4435
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5123
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4436
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5124
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4437
	    "tap_max_delta", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5125
	    "tap_max_delta", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4438
	    &sc->syninfo.tap_max_delta, SYNAPTICS_SYSCTL_TAP_MAX_DELTA,
5126
	    sc, SYNAPTICS_SYSCTL_TAP_MAX_DELTA,
4439
	    synaptics_sysctl, "I",
5127
	    synaptics_sysctl, "I",
4440
	    "Length of segments above which a tap is ignored");
5128
	    "Length of segments above which a tap is ignored");
4441
5129
Lines 4444-4460 Link Here
4444
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5132
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4445
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5133
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4446
	    "tap_min_queue", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5134
	    "tap_min_queue", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4447
	    &sc->syninfo.tap_min_queue, SYNAPTICS_SYSCTL_TAP_MIN_QUEUE,
5135
	    sc, SYNAPTICS_SYSCTL_TAP_MIN_QUEUE,
4448
	    synaptics_sysctl, "I",
5136
	    synaptics_sysctl, "I",
4449
	    "Number of packets required to consider a tap");
5137
	    "Number of packets required to consider a tap");
4450
5138
4451
	/* hw.psm.synaptics.taphold_timeout. */
5139
	/* hw.psm.synaptics.taphold_timeout. */
4452
	sc->synaction.in_taphold = 0;
5140
	sc->synaction[0].in_taphold = 0;
4453
	sc->syninfo.taphold_timeout = tap_timeout;
5141
	sc->syninfo.taphold_timeout = tap_timeout;
4454
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5142
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4455
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5143
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4456
	    "taphold_timeout", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5144
	    "taphold_timeout", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4457
	    &sc->syninfo.taphold_timeout, SYNAPTICS_SYSCTL_TAPHOLD_TIMEOUT,
5145
	    sc, SYNAPTICS_SYSCTL_TAPHOLD_TIMEOUT,
4458
	    synaptics_sysctl, "I",
5146
	    synaptics_sysctl, "I",
4459
	    "Maximum elapsed time between two taps to consider a tap-hold "
5147
	    "Maximum elapsed time between two taps to consider a tap-hold "
4460
	    "action");
5148
	    "action");
Lines 4464-4470 Link Here
4464
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5152
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4465
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5153
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4466
	    "vscroll_hor_area", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5154
	    "vscroll_hor_area", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4467
	    &sc->syninfo.vscroll_hor_area, SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA,
5155
	    sc, SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA,
4468
	    synaptics_sysctl, "I",
5156
	    synaptics_sysctl, "I",
4469
	    "Area reserved for horizontal virtual scrolling");
5157
	    "Area reserved for horizontal virtual scrolling");
4470
5158
Lines 4473-4479 Link Here
4473
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5161
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4474
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5162
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4475
	    "vscroll_ver_area", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5163
	    "vscroll_ver_area", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4476
	    &sc->syninfo.vscroll_ver_area, SYNAPTICS_SYSCTL_VSCROLL_VER_AREA,
5164
	    sc, SYNAPTICS_SYSCTL_VSCROLL_VER_AREA,
4477
	    synaptics_sysctl, "I",
5165
	    synaptics_sysctl, "I",
4478
	    "Area reserved for vertical virtual scrolling");
5166
	    "Area reserved for vertical virtual scrolling");
4479
5167
Lines 4482-4489 Link Here
4482
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5170
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4483
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5171
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4484
	    "vscroll_min_delta", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5172
	    "vscroll_min_delta", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4485
	    &sc->syninfo.vscroll_min_delta,
5173
	    sc, SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA,
4486
	    SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA,
4487
	    synaptics_sysctl, "I",
5174
	    synaptics_sysctl, "I",
4488
	    "Minimum movement to consider virtual scrolling");
5175
	    "Minimum movement to consider virtual scrolling");
4489
5176
Lines 4492-4498 Link Here
4492
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5179
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4493
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5180
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4494
	    "vscroll_div_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5181
	    "vscroll_div_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4495
	    &sc->syninfo.vscroll_div_min, SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN,
5182
	    sc, SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN,
4496
	    synaptics_sysctl, "I",
5183
	    synaptics_sysctl, "I",
4497
	    "Divisor for fast scrolling");
5184
	    "Divisor for fast scrolling");
4498
5185
Lines 4501-4507 Link Here
4501
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5188
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4502
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5189
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4503
	    "vscroll_div_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5190
	    "vscroll_div_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4504
	    &sc->syninfo.vscroll_div_max, SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX,
5191
	    sc, SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX,
4505
	    synaptics_sysctl, "I",
5192
	    synaptics_sysctl, "I",
4506
	    "Divisor for slow scrolling");
5193
	    "Divisor for slow scrolling");
4507
5194
Lines 4510-4518 Link Here
4510
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5197
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4511
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5198
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4512
	    "touchpad_off", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5199
	    "touchpad_off", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4513
	    &sc->syninfo.touchpad_off, SYNAPTICS_SYSCTL_TOUCHPAD_OFF,
5200
	    sc, SYNAPTICS_SYSCTL_TOUCHPAD_OFF,
4514
	    synaptics_sysctl, "I",
5201
	    synaptics_sysctl, "I",
4515
	    "Turn off touchpad");
5202
	    "Turn off touchpad");
5203
5204
	sc->syninfo.softbuttons = 0;
5205
	sc->syninfo.softbuttons_y = 0;
5206
	sc->syninfo.softbutton2_x = 0;
5207
	sc->syninfo.softbutton3_x = 0;
5208
	sc->syninfo.softbutton_nomove = 0;
5209
5210
	/* skip softbuttons sysctl on not clickpads */
5211
	if (!sc->synhw.capClickPad)
5212
		return;
5213
5214
	/* hw.psm.synaptics.softbuttons */
5215
	sc->syninfo.softbuttons = 3;
5216
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5217
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5218
	    "softbuttons", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5219
	    sc, SYNAPTICS_SYSCTL_SOFTBUTTONS,
5220
	    synaptics_sysctl, "I",
5221
	    "Enables top or bottom edges to be a softbuttons on clickpads");
5222
5223
	/* hw.psm.synaptics.softbuttons_y */
5224
	sc->syninfo.softbuttons_y = sc->synhw.maximumYCoord / 4;
5225
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5226
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5227
	    "softbuttons_y", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5228
	    sc, SYNAPTICS_SYSCTL_SOFTBUTTONS_Y,
5229
	    synaptics_sysctl, "I",
5230
	    "Vertical size of softbuttons area");
5231
5232
	/* hw.psm.synaptics.softbutton2_x */
5233
	sc->syninfo.softbutton2_x = sc->synhw.maximumXCoord / 3;
5234
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5235
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5236
	    "softbutton2_x", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5237
	    sc, SYNAPTICS_SYSCTL_SOFTBUTTON2_X,
5238
	    synaptics_sysctl, "I",
5239
	    "Horisontal position of 2-nd softbutton left edge (0-disable)");
5240
5241
	/* hw.psm.synaptics.softbutton3_x */
5242
	sc->syninfo.softbutton3_x = sc->synhw.maximumXCoord * 2 / 3;
5243
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5244
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5245
	    "softbutton3_x", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5246
	    sc, SYNAPTICS_SYSCTL_SOFTBUTTON3_X,
5247
	    synaptics_sysctl, "I",
5248
	    "Horisontal position of 3-rd softbutton left edge (0-disable)");
5249
5250
	/* hw.psm.synaptics.softbutton_nomove */
5251
	sc->syninfo.softbutton_nomove = 0;
5252
	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
5253
	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
5254
	    "softbutton_nomove", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
5255
	    sc, SYNAPTICS_SYSCTL_SOFTBUTTON_NOMOVE,
5256
	    synaptics_sysctl, "I",
5257
	    "Disable movement on the bottom edge area so it works as buttons");
4516
}
5258
}
4517
5259
4518
static int
5260
static int
Lines 4854-4860 Link Here
4854
5596
4855
	if (arg == PROBE) {
5597
	if (arg == PROBE) {
4856
		/* Create sysctl tree. */
5598
		/* Create sysctl tree. */
4857
		synaptics_sysctl_create_tree(sc);
5599
		synaptics_sysctl_create_tree(sc, "synaptics",
5600
		    "Synaptics TouchPad");
4858
		sc->hw.buttons = buttons;
5601
		sc->hw.buttons = buttons;
4859
	}
5602
	}
4860
5603
Lines 5171-5176 Link Here
5171
	return (TRUE);				/* PS/2 absolute mode */
5914
	return (TRUE);				/* PS/2 absolute mode */
5172
}
5915
}
5173
5916
5917
/* Elantech Touchpad */
5918
static int
5919
elantech_read_1(KBDC kbdc, int hwversion, int reg, int *val)
5920
{
5921
	int res, readcmd, retidx;
5922
	int resp[3];
5923
5924
	readcmd = hwversion == 2 ? ELANTECH_REG_READ : ELANTECH_REG_RDWR;
5925
	retidx = hwversion == 4 ? 1 : 0;
5926
5927
	res = send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK;
5928
	res |= send_aux_command(kbdc, readcmd) != PSM_ACK;
5929
	res |= send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK;
5930
	res |= send_aux_command(kbdc, reg) != PSM_ACK;
5931
	res |= get_mouse_status(kbdc, resp, 0, 3) != 3;
5932
5933
	if (res == 0)
5934
		*val = resp[retidx];
5935
5936
	return (res);
5937
}
5938
5939
static int
5940
elantech_write_1(KBDC kbdc, int hwversion, int reg, int val)
5941
{
5942
	int res, writecmd;
5943
5944
	writecmd = hwversion == 2 ? ELANTECH_REG_WRITE : ELANTECH_REG_RDWR;
5945
5946
	res = send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK;
5947
	res |= send_aux_command(kbdc, writecmd) != PSM_ACK;
5948
	res |= send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK;
5949
	res |= send_aux_command(kbdc, reg) != PSM_ACK;
5950
	if (hwversion == 4) {
5951
		res |= send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK;
5952
		res |= send_aux_command(kbdc, writecmd) != PSM_ACK;
5953
	}
5954
	res |= send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK;
5955
	res |= send_aux_command(kbdc, val) != PSM_ACK;
5956
	res |= set_mouse_scaling(kbdc, 1) == 0;
5957
5958
	return (res);
5959
}
5960
5961
static int
5962
elantech_cmd(KBDC kbdc, int hwversion, int cmd, int *resp)
5963
{
5964
	int res;
5965
5966
	if (hwversion == 2) {
5967
		res = set_mouse_scaling(kbdc, 1) == 0;
5968
		res |= mouse_ext_command(kbdc, cmd) == 0;
5969
	} else {
5970
		res = send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK;
5971
		res |= send_aux_command(kbdc, cmd) != PSM_ACK;
5972
	}
5973
	res |= get_mouse_status(kbdc, resp, 0, 3) != 3;
5974
5975
	return (res);
5976
}
5977
5978
static int
5979
elantech_init(KBDC kbdc, elantechhw_t *elanhw)
5980
{
5981
	int i, val, res, hwversion, reg10;
5982
5983
	/* set absolute mode */
5984
	hwversion = elanhw->hwversion;
5985
	reg10 = -1;
5986
	switch (hwversion) {
5987
	case 2:
5988
		reg10 = elanhw->fwversion == 0x020030 ? 0x54 : 0xc4;
5989
		res = elantech_write_1(kbdc, hwversion, 0x10, reg10);
5990
		if (res)
5991
			break;
5992
		res = elantech_write_1(kbdc, hwversion, 0x11, 0x8A);
5993
		break;
5994
	case 3:
5995
		reg10 = 0x0b;
5996
		res = elantech_write_1(kbdc, hwversion, 0x10, reg10);
5997
		break;
5998
	case 4:
5999
		res = elantech_write_1(kbdc, hwversion, 0x07, 0x01);
6000
		break;
6001
	default:
6002
		res = 1;
6003
	}
6004
6005
	/* Read back reg 0x10 to ensure hardware is ready. */
6006
	if (res == 0 && reg10 >= 0) {
6007
		for (i = 0; i < 5; i++) {
6008
			if (elantech_read_1(kbdc, hwversion, 0x10, &val) == 0)
6009
				break;
6010
			pause("elan", 1);
6011
		}
6012
		if (i == 5)
6013
			res = 1;
6014
	}
6015
6016
	if (res)
6017
		printf("couldn't set absolute mode\n");
6018
6019
	return (res);
6020
}
6021
6022
static void
6023
elantech_init_synaptics(struct psm_softc *sc)
6024
{
6025
6026
	/* Set capabilites required by movement smother */
6027
	sc->synhw.infoMajor = sc->elanhw.hwversion;
6028
	sc->synhw.infoMinor = sc->elanhw.fwversion;
6029
	sc->synhw.infoXupmm = (sc->elanhw.dpix * 10 + 5) / 254;
6030
	sc->synhw.infoYupmm = (sc->elanhw.dpiy * 10 + 5) / 254;
6031
	sc->synhw.verticalScroll = 0;
6032
	sc->synhw.nExtendedQueries = 4;
6033
	sc->synhw.capExtended = 1;
6034
	sc->synhw.capPassthrough = sc->elanhw.hastrackpad;
6035
	sc->synhw.capClickPad = sc->elanhw.isclickpad;
6036
	sc->synhw.capMultiFinger = 1;
6037
	sc->synhw.capPalmDetect = 1;
6038
	sc->synhw.capPen = 0;
6039
	sc->synhw.capReportsMax = 1;
6040
	sc->synhw.maximumXCoord = sc->elanhw.sizex;
6041
	sc->synhw.maximumYCoord = sc->elanhw.sizey;
6042
	sc->synhw.capReportsMin = 1;
6043
	sc->synhw.minimumXCoord = 0;
6044
	sc->synhw.minimumYCoord = 0;
6045
6046
	if (sc->syninfo.sysctl_tree == NULL) {
6047
		synaptics_sysctl_create_tree(sc, "elantech",
6048
		    "Elantech Touchpad");
6049
6050
		/*
6051
		 * Adjust synaptic smoother tunables
6052
		 * 1. Disable finger detection pressure threshold. Unlike
6053
		 *    synaptics we assume the finger is acting when packet with
6054
		 *    its X&Y arrives not when pressure exceedes some threshold
6055
		 * 2. Disable unrelated features like margins and noisy areas
6056
		 * 3. Disable virtual scroll areas as 2nd finger is preferable
6057
		 * 4. Scale down divisors and movement lengths by a factor of 3
6058
		 *    where 3 is Synaptics to Elantech (~2200/800) dpi ratio
6059
		 */
6060
6061
		/* Disable finger detection pressure threshold */
6062
		sc->syninfo.min_pressure = 1;
6063
6064
		/* Use full area of touchpad */
6065
		sc->syninfo.margin_top = 0;
6066
		sc->syninfo.margin_right = 0;
6067
		sc->syninfo.margin_bottom = 0;
6068
		sc->syninfo.margin_left = 0;
6069
		/* Disable noisy area */
6070
		sc->syninfo.na_top = 0;
6071
		sc->syninfo.na_right = 0;
6072
		sc->syninfo.na_bottom = 0;
6073
		sc->syninfo.na_left = 0;
6074
6075
		/* tune divisors and movement lengths */
6076
		sc->syninfo.weight_len_squared = 200;
6077
		sc->syninfo.div_min = 3;
6078
		sc->syninfo.div_max = 6;
6079
		sc->syninfo.div_max_na = 10;
6080
		sc->syninfo.div_len = 30;
6081
		sc->syninfo.tap_max_delta = 25;
6082
6083
		/* disable virtual scrolling areas and tune its divisors */
6084
		sc->syninfo.vscroll_hor_area = 0;
6085
		sc->syninfo.vscroll_ver_area = 0;
6086
		sc->syninfo.vscroll_min_delta = 15;
6087
		sc->syninfo.vscroll_div_min = 30;
6088
		sc->syninfo.vscroll_div_max = 50;
6089
	}
6090
6091
	return;
6092
}
6093
6094
static int
6095
enable_elantech(struct psm_softc *sc, enum probearg arg)
6096
{
6097
	static const int ic2hw[] =
6098
	/*IC: 0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f */
6099
	    { 0, 0, 2, 0, 2, 3, 4, 4, 4, 4, 4, 0, 0, 4, 4, 0 };
6100
	elantechhw_t elanhw;
6101
	int icversion, hwversion, dptracex, dptracey, id, resp[3];
6102
	KBDC kbdc = sc->kbdc;
6103
6104
	VLOG(3, (LOG_DEBUG, "elantech: BEGIN init\n"));
6105
6106
	set_mouse_scaling(kbdc, 1);
6107
	set_mouse_scaling(kbdc, 1);
6108
	set_mouse_scaling(kbdc, 1);
6109
	if (get_mouse_status(kbdc, resp, 0, 3) != 3)
6110
		return (FALSE);
6111
6112
	if (!ELANTECH_MAGIC(resp))
6113
		return (FALSE);
6114
6115
	/* Identify the Touchpad version. */
6116
	if (elantech_cmd(kbdc, 2, ELANTECH_FW_VERSION, resp))
6117
		return (FALSE);
6118
6119
	bzero(&elanhw, sizeof(elanhw));
6120
6121
	elanhw.fwversion = (resp[0] << 16) | (resp[1] << 8) | resp[2];
6122
	icversion = resp[0] & 0x0f;
6123
	hwversion = ic2hw[icversion];
6124
6125
	if (verbose >= 2)
6126
		printf("Elantech touchpad hardware v.%d firmware v.0x%06x\n",
6127
		    hwversion, elanhw.fwversion);
6128
6129
	if (ELANTECH_HW_IS_V1(elanhw.fwversion)) {
6130
		printf ("  Unsupported touchpad hardware (v1)\n");
6131
		return (FALSE);
6132
	}
6133
	if (hwversion == 0) {
6134
		printf ("  Unknown touchpad hardware (firmware v.0x%06x)\n",
6135
		    elanhw.fwversion);
6136
		return (FALSE);
6137
	}
6138
6139
	/* Get the Touchpad model information. */
6140
	elanhw.hwversion = hwversion;
6141
	elanhw.isclickpad = (resp[1] & 0x10) != 0;
6142
	elanhw.hascrc = (resp[1] & 0x40) != 0;
6143
	elanhw.haspressure = elanhw.fwversion >= 0x020800;
6144
6145
	/* Read the capability bits. */
6146
	if (elantech_cmd(kbdc, hwversion, ELANTECH_CAPABILITIES, resp) != 0) {
6147
		printf("  Failed to read capability bits\n");
6148
		return (FALSE);
6149
	}
6150
6151
	elanhw.ntracesx = resp[1] - 1;
6152
	elanhw.ntracesy = resp[2] - 1;
6153
	elanhw.hastrackpad = (resp[0] & 0x80) != 0;
6154
6155
	/* Get the touchpad resolution */
6156
	switch (hwversion) {
6157
	case 2:
6158
		elanhw.dpix = elanhw.dpiy = 400;
6159
		break;
6160
	case 4:
6161
		if (elantech_cmd(kbdc, hwversion, ELANTECH_RESOLUTION, resp)
6162
		    == 0) {
6163
			elanhw.dpix = (resp[1] & 0x0f) * 10 + 790;
6164
			elanhw.dpiy = ((resp[1] & 0xf0) >> 4) * 10 + 790;
6165
			break;
6166
		}
6167
		/* FALLTHROUGH */
6168
	case 3:
6169
		elanhw.dpix = elanhw.dpiy = 800;
6170
		break;
6171
	}
6172
6173
	if (!elantech_support)
6174
		return (FALSE);
6175
6176
	if (elantech_init(kbdc, &elanhw)) {
6177
		printf("couldn't initialize elantech touchpad\n");
6178
		return (FALSE);
6179
	}
6180
6181
	/*
6182
	 * Get the touchpad reporting range.
6183
	 * On HW v.3 touchpads it should be done after switching hardware
6184
	 * to real resolution mode (by setting bit 3 of reg10)
6185
	 */
6186
	if (elantech_cmd(kbdc, hwversion, ELANTECH_FW_ID, resp) != 0) {
6187
		printf("  Failed to read touchpad size\n");
6188
		elanhw.sizex = 10000; /* Arbitrary high values to     */
6189
		elanhw.sizey = 10000; /* prevent clipping in smoother */
6190
	} else if (hwversion == 2) {
6191
		dptracex = dptracey = 64;
6192
		if ((elanhw.fwversion >> 16) == 0x14 && (resp[1] & 0x10) &&
6193
		    !elantech_cmd(kbdc, hwversion, ELANTECH_SAMPLE, resp)) {
6194
			dptracex = resp[1] / 2;
6195
			dptracey = resp[2] / 2;
6196
		}
6197
		elanhw.sizex = (elanhw.ntracesx - 1) * dptracex;
6198
		elanhw.sizey = (elanhw.ntracesy - 1) * dptracey;
6199
	} else {
6200
		elanhw.sizex = (resp[0] & 0x0f) << 8 | resp[1];
6201
		elanhw.sizey = (resp[0] & 0xf0) << 4 | resp[2];
6202
	}
6203
6204
	if (verbose >= 2) {
6205
		printf("  Model information:\n");
6206
		printf("   MaxX:     %d\n", elanhw.sizex);
6207
		printf("   MaxY:     %d\n", elanhw.sizey);
6208
		printf("   DpiX:     %d\n", elanhw.dpix);
6209
		printf("   DpiY:     %d\n", elanhw.dpiy);
6210
		printf("   TracesX:  %d\n", elanhw.ntracesx);
6211
		printf("   TracesY:  %d\n", elanhw.ntracesy);
6212
		printf("   Clickpad: %d\n", elanhw.isclickpad);
6213
		printf("   Trackpad: %d\n", elanhw.hastrackpad);
6214
		printf("   CRC:      %d\n", elanhw.hascrc);
6215
		printf("   Pressure: %d\n", elanhw.haspressure);
6216
	}
6217
6218
	VLOG(3, (LOG_DEBUG, "elantech: END init\n"));
6219
6220
	if (arg == PROBE) {
6221
		sc->elanhw = elanhw;
6222
		sc->hw.buttons = 3;
6223
6224
		/* Initialize synaptics movement smoother */
6225
		elantech_init_synaptics(sc);
6226
6227
		for (id = 0; id < PSM_GESTURE_FINGERS; id++)
6228
			PSM_FINGER_RESET(sc->elanaction.fingers[id]);
6229
6230
		if (elanhw.hascrc)
6231
			sc->config |= PSM_CONFIG_NOCHECKSYNC;
6232
	}
6233
6234
	return (TRUE);
6235
}
6236
5174
/*
6237
/*
5175
 * Return true if 'now' is earlier than (start + (secs.usecs)).
6238
 * Return true if 'now' is earlier than (start + (secs.usecs)).
5176
 * Now may be NULL and the function will fetch the current time from
6239
 * Now may be NULL and the function will fetch the current time from
(-)sys/sys/mouse.h (+4 lines)
Lines 170-175 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 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
(-)usr.sbin/moused/moused.c (+1 lines)
Lines 246-251 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