pms.c revision 1.87
1/* $OpenBSD: pms.c,v 1.87 2018/05/13 14:48:19 bru Exp $ */
2/* $NetBSD: psm.c,v 1.11 2000/06/05 22:20:57 sommerfeld Exp $ */
3
4/*-
5 * Copyright (c) 1994 Charles M. Hannum.
6 * Copyright (c) 1992, 1993 Erik Forsberg.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 *
15 * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED
16 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
17 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
18 * NO EVENT SHALL I BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
22 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <sys/param.h>
28#include <sys/systm.h>
29#include <sys/rwlock.h>
30#include <sys/device.h>
31#include <sys/ioctl.h>
32#include <sys/malloc.h>
33#include <sys/task.h>
34#include <sys/timeout.h>
35
36#include <machine/bus.h>
37
38#include <dev/ic/pckbcvar.h>
39
40#include <dev/pckbc/pmsreg.h>
41
42#include <dev/wscons/wsconsio.h>
43#include <dev/wscons/wsmousevar.h>
44
45#if defined(__i386__) || defined(__amd64__)
46#include "acpi.h"
47#endif
48
49#if !defined(SMALL_KERNEL) && NACPI > 0
50extern int mouse_has_softbtn;
51#else
52int mouse_has_softbtn;
53#endif
54
55#ifdef DEBUG
56#define DPRINTF(x...)	do { printf(x); } while (0);
57#else
58#define DPRINTF(x...)
59#endif
60
61#define DEVNAME(sc)	((sc)->sc_dev.dv_xname)
62
63#define WSMOUSE_BUTTON(x)	(1 << ((x) - 1))
64
65struct pms_softc;
66
67struct pms_protocol {
68	int type;
69#define PMS_STANDARD		0
70#define PMS_INTELLI		1
71#define PMS_SYNAPTICS		2
72#define PMS_ALPS		3
73#define PMS_ELANTECH_V1		4
74#define PMS_ELANTECH_V2		5
75#define PMS_ELANTECH_V3		6
76#define PMS_ELANTECH_V4		7
77	u_int packetsize;
78	int (*enable)(struct pms_softc *);
79	int (*ioctl)(struct pms_softc *, u_long, caddr_t, int, struct proc *);
80	int (*sync)(struct pms_softc *, int);
81	void (*proc)(struct pms_softc *);
82	void (*disable)(struct pms_softc *);
83};
84
85struct synaptics_softc {
86	int identify;
87	int capabilities, ext_capabilities, ext2_capabilities;
88	int model, ext_model;
89	int modes;
90
91	int mode;
92
93	int mask;
94#define SYNAPTICS_MASK_NEWABS_STRICT	0xc8
95#define SYNAPTICS_MASK_NEWABS_RELAXED	0xc0
96#define SYNAPTICS_VALID_NEWABS_FIRST	0x80
97#define SYNAPTICS_VALID_NEWABS_NEXT	0xc0
98
99	u_int sec_buttons;
100
101#define SYNAPTICS_PRESSURE_HI		30
102#define SYNAPTICS_PRESSURE_LO		25
103#define SYNAPTICS_PRESSURE		SYNAPTICS_PRESSURE_HI
104#define SYNAPTICS_SCALE			4
105#define SYNAPTICS_MAX_FINGERS		3
106};
107
108struct alps_softc {
109	int model;
110#define ALPS_GLIDEPOINT		(1 << 1)
111#define ALPS_DUALPOINT		(1 << 2)
112#define ALPS_PASSTHROUGH	(1 << 3)
113#define ALPS_INTERLEAVED	(1 << 4)
114
115	int mask;
116	int version;
117
118	u_int gesture;
119
120	u_int sec_buttons;	/* trackpoint */
121
122	int old_x, old_y;
123#define ALPS_PRESSURE		40
124};
125
126struct elantech_softc {
127	int flags;
128#define ELANTECH_F_REPORTS_PRESSURE	0x01
129#define ELANTECH_F_HAS_ROCKER		0x02
130#define ELANTECH_F_2FINGER_PACKET	0x04
131#define ELANTECH_F_HW_V1_OLD		0x08
132#define ELANTECH_F_CRC_ENABLED		0x10
133#define ELANTECH_F_TRACKPOINT		0x20
134	int fw_version;
135
136	u_int mt_slots;
137
138	int width;
139
140	u_char parity[256];
141	u_char p1, p2, p3;
142
143	int max_x, max_y;
144	int old_x, old_y;
145};
146
147struct pms_softc {		/* driver status information */
148	struct device sc_dev;
149
150	pckbc_tag_t sc_kbctag;
151
152	int sc_state;
153#define PMS_STATE_DISABLED	0
154#define PMS_STATE_ENABLED	1
155#define PMS_STATE_SUSPENDED	2
156
157	struct rwlock sc_state_lock;
158
159	int sc_dev_enable;
160#define PMS_DEV_IGNORE		0x00
161#define PMS_DEV_PRIMARY		0x01
162#define PMS_DEV_SECONDARY	0x02
163
164	struct task sc_rsttask;
165	struct timeout sc_rsttimo;
166	int sc_rststate;
167#define PMS_RST_COMMENCE	0x01
168#define PMS_RST_ANNOUNCED	0x02
169
170	int poll;
171	int inputstate;
172
173	const struct pms_protocol *protocol;
174	struct synaptics_softc *synaptics;
175	struct alps_softc *alps;
176	struct elantech_softc *elantech;
177
178	u_char packet[8];
179
180	struct device *sc_wsmousedev;
181	struct device *sc_sec_wsmousedev;
182};
183
184static const u_int butmap[8] = {
185	0,
186	WSMOUSE_BUTTON(1),
187	WSMOUSE_BUTTON(3),
188	WSMOUSE_BUTTON(1) | WSMOUSE_BUTTON(3),
189	WSMOUSE_BUTTON(2),
190	WSMOUSE_BUTTON(1) | WSMOUSE_BUTTON(2),
191	WSMOUSE_BUTTON(2) | WSMOUSE_BUTTON(3),
192	WSMOUSE_BUTTON(1) | WSMOUSE_BUTTON(2) | WSMOUSE_BUTTON(3)
193};
194
195static const struct alps_model {
196	int version;
197	int mask;
198	int model;
199} alps_models[] = {
200	{ 0x2021, 0xf8, ALPS_DUALPOINT | ALPS_PASSTHROUGH },
201	{ 0x2221, 0xf8, ALPS_DUALPOINT | ALPS_PASSTHROUGH },
202	{ 0x2222, 0xff, ALPS_DUALPOINT | ALPS_PASSTHROUGH },
203	{ 0x3222, 0xf8, ALPS_DUALPOINT | ALPS_PASSTHROUGH },
204	{ 0x5212, 0xff, ALPS_DUALPOINT | ALPS_PASSTHROUGH | ALPS_INTERLEAVED },
205	{ 0x5321, 0xf8, ALPS_GLIDEPOINT },
206	{ 0x5322, 0xf8, ALPS_GLIDEPOINT },
207	{ 0x603b, 0xf8, ALPS_GLIDEPOINT },
208	{ 0x6222, 0xcf, ALPS_DUALPOINT | ALPS_PASSTHROUGH | ALPS_INTERLEAVED },
209	{ 0x6321, 0xf8, ALPS_GLIDEPOINT },
210	{ 0x6322, 0xf8, ALPS_GLIDEPOINT },
211	{ 0x6323, 0xf8, ALPS_GLIDEPOINT },
212	{ 0x6324, 0x8f, ALPS_GLIDEPOINT },
213	{ 0x6325, 0xef, ALPS_GLIDEPOINT },
214	{ 0x6326, 0xf8, ALPS_GLIDEPOINT },
215	{ 0x7301, 0xf8, ALPS_DUALPOINT },
216	{ 0x7321, 0xf8, ALPS_GLIDEPOINT },
217	{ 0x7322, 0xf8, ALPS_GLIDEPOINT },
218	{ 0x7325, 0xcf, ALPS_GLIDEPOINT },
219#if 0
220	/*
221	 * This model has a clitpad sending almost compatible PS2
222	 * packets but not compatible enough to be used with the
223	 * ALPS protocol.
224	 */
225	{ 0x633b, 0xf8, ALPS_DUALPOINT | ALPS_PASSTHROUGH },
226
227	{ 0x7326, 0, 0 },	/* XXX Uses unknown v3 protocol */
228
229	{ 0x7331, 0x8f, ALPS_DUALPOINT },	/* not supported */
230#endif
231};
232
233static struct wsmouse_param synaptics_params[] = {
234	{ WSMOUSECFG_PRESSURE_LO, SYNAPTICS_PRESSURE_LO },
235	{ WSMOUSECFG_PRESSURE_HI, SYNAPTICS_PRESSURE_HI }
236};
237
238static struct wsmouse_param alps_params[] = {
239	{ WSMOUSECFG_SMOOTHING, 3 }
240};
241
242int	pmsprobe(struct device *, void *, void *);
243void	pmsattach(struct device *, struct device *, void *);
244int	pmsactivate(struct device *, int);
245
246void	pmsinput(void *, int);
247
248int	pms_change_state(struct pms_softc *, int, int);
249
250int	pms_ioctl(void *, u_long, caddr_t, int, struct proc *);
251int	pms_enable(void *);
252void	pms_disable(void *);
253
254int	pms_sec_ioctl(void *, u_long, caddr_t, int, struct proc *);
255int	pms_sec_enable(void *);
256void	pms_sec_disable(void *);
257
258int	pms_cmd(struct pms_softc *, u_char *, int, u_char *, int);
259int	pms_spec_cmd(struct pms_softc *, int);
260int	pms_get_devid(struct pms_softc *, u_char *);
261int	pms_get_status(struct pms_softc *, u_char *);
262int	pms_set_rate(struct pms_softc *, int);
263int	pms_set_resolution(struct pms_softc *, int);
264int	pms_set_scaling(struct pms_softc *, int);
265int	pms_reset(struct pms_softc *);
266int	pms_dev_enable(struct pms_softc *);
267int	pms_dev_disable(struct pms_softc *);
268void	pms_protocol_lookup(struct pms_softc *);
269void	pms_reset_detect(struct pms_softc *, int);
270void	pms_reset_task(void *);
271void	pms_reset_timo(void *);
272
273int	pms_enable_intelli(struct pms_softc *);
274
275int	pms_ioctl_mouse(struct pms_softc *, u_long, caddr_t, int, struct proc *);
276int	pms_sync_mouse(struct pms_softc *, int);
277void	pms_proc_mouse(struct pms_softc *);
278
279int	pms_enable_synaptics(struct pms_softc *);
280int	pms_ioctl_synaptics(struct pms_softc *, u_long, caddr_t, int, struct proc *);
281int	pms_sync_synaptics(struct pms_softc *, int);
282void	pms_proc_synaptics(struct pms_softc *);
283void	pms_disable_synaptics(struct pms_softc *);
284
285int	pms_enable_alps(struct pms_softc *);
286int	pms_ioctl_alps(struct pms_softc *, u_long, caddr_t, int, struct proc *);
287int	pms_sync_alps(struct pms_softc *, int);
288void	pms_proc_alps(struct pms_softc *);
289
290int	pms_enable_elantech_v1(struct pms_softc *);
291int	pms_enable_elantech_v2(struct pms_softc *);
292int	pms_enable_elantech_v3(struct pms_softc *);
293int	pms_enable_elantech_v4(struct pms_softc *);
294int	pms_ioctl_elantech(struct pms_softc *, u_long, caddr_t, int,
295    struct proc *);
296int	pms_sync_elantech_v1(struct pms_softc *, int);
297int	pms_sync_elantech_v2(struct pms_softc *, int);
298int	pms_sync_elantech_v3(struct pms_softc *, int);
299int	pms_sync_elantech_v4(struct pms_softc *, int);
300void	pms_proc_elantech_v1(struct pms_softc *);
301void	pms_proc_elantech_v2(struct pms_softc *);
302void	pms_proc_elantech_v3(struct pms_softc *);
303void	pms_proc_elantech_v4(struct pms_softc *);
304
305int	synaptics_knock(struct pms_softc *);
306int	synaptics_set_mode(struct pms_softc *, int);
307int	synaptics_query(struct pms_softc *, int, int *);
308int	synaptics_get_hwinfo(struct pms_softc *);
309void	synaptics_sec_proc(struct pms_softc *);
310
311int	alps_sec_proc(struct pms_softc *);
312int	alps_get_hwinfo(struct pms_softc *);
313
314int	elantech_knock(struct pms_softc *);
315int	elantech_get_hwinfo_v1(struct pms_softc *);
316int	elantech_get_hwinfo_v2(struct pms_softc *);
317int	elantech_get_hwinfo_v3(struct pms_softc *);
318int	elantech_get_hwinfo_v4(struct pms_softc *);
319int	elantech_ps2_cmd(struct pms_softc *, u_char);
320int	elantech_set_absolute_mode_v1(struct pms_softc *);
321int	elantech_set_absolute_mode_v2(struct pms_softc *);
322int	elantech_set_absolute_mode_v3(struct pms_softc *);
323int	elantech_set_absolute_mode_v4(struct pms_softc *);
324
325struct cfattach pms_ca = {
326	sizeof(struct pms_softc), pmsprobe, pmsattach, NULL,
327	pmsactivate
328};
329
330struct cfdriver pms_cd = {
331	NULL, "pms", DV_DULL
332};
333
334const struct wsmouse_accessops pms_accessops = {
335	pms_enable,
336	pms_ioctl,
337	pms_disable,
338};
339
340const struct wsmouse_accessops pms_sec_accessops = {
341	pms_sec_enable,
342	pms_sec_ioctl,
343	pms_sec_disable,
344};
345
346const struct pms_protocol pms_protocols[] = {
347	/* Generic PS/2 mouse */
348	{
349		PMS_STANDARD, 3,
350		NULL,
351		pms_ioctl_mouse,
352		pms_sync_mouse,
353		pms_proc_mouse,
354		NULL
355	},
356	/* Synaptics touchpad */
357	{
358		PMS_SYNAPTICS, 6,
359		pms_enable_synaptics,
360		pms_ioctl_synaptics,
361		pms_sync_synaptics,
362		pms_proc_synaptics,
363		pms_disable_synaptics
364	},
365	/* ALPS touchpad */
366	{
367		PMS_ALPS, 6,
368		pms_enable_alps,
369		pms_ioctl_alps,
370		pms_sync_alps,
371		pms_proc_alps,
372		NULL
373	},
374	/* Elantech touchpad (hardware version 1) */
375	{
376		PMS_ELANTECH_V1, 4,
377		pms_enable_elantech_v1,
378		pms_ioctl_elantech,
379		pms_sync_elantech_v1,
380		pms_proc_elantech_v1,
381		NULL
382	},
383	/* Elantech touchpad (hardware version 2) */
384	{
385		PMS_ELANTECH_V2, 6,
386		pms_enable_elantech_v2,
387		pms_ioctl_elantech,
388		pms_sync_elantech_v2,
389		pms_proc_elantech_v2,
390		NULL
391	},
392	/* Elantech touchpad (hardware version 3) */
393	{
394		PMS_ELANTECH_V3, 6,
395		pms_enable_elantech_v3,
396		pms_ioctl_elantech,
397		pms_sync_elantech_v3,
398		pms_proc_elantech_v3,
399		NULL
400	},
401	/* Elantech touchpad (hardware version 4) */
402	{
403		PMS_ELANTECH_V4, 6,
404		pms_enable_elantech_v4,
405		pms_ioctl_elantech,
406		pms_sync_elantech_v4,
407		pms_proc_elantech_v4,
408		NULL
409	},
410	/* Microsoft IntelliMouse */
411	{
412		PMS_INTELLI, 4,
413		pms_enable_intelli,
414		pms_ioctl_mouse,
415		pms_sync_mouse,
416		pms_proc_mouse,
417		NULL
418	},
419};
420
421int
422pms_cmd(struct pms_softc *sc, u_char *cmd, int len, u_char *resp, int resplen)
423{
424	if (sc->poll) {
425		return pckbc_poll_cmd(sc->sc_kbctag, PCKBC_AUX_SLOT,
426		    cmd, len, resplen, resp, 1);
427	} else {
428		return pckbc_enqueue_cmd(sc->sc_kbctag, PCKBC_AUX_SLOT,
429		    cmd, len, resplen, 1, resp);
430	}
431}
432
433int
434pms_spec_cmd(struct pms_softc *sc, int cmd)
435{
436	if (pms_set_scaling(sc, 1) ||
437	    pms_set_resolution(sc, (cmd >> 6) & 0x03) ||
438	    pms_set_resolution(sc, (cmd >> 4) & 0x03) ||
439	    pms_set_resolution(sc, (cmd >> 2) & 0x03) ||
440	    pms_set_resolution(sc, (cmd >> 0) & 0x03))
441		return (-1);
442	return (0);
443}
444
445int
446pms_get_devid(struct pms_softc *sc, u_char *resp)
447{
448	u_char cmd[1];
449
450	cmd[0] = PMS_SEND_DEV_ID;
451	return (pms_cmd(sc, cmd, 1, resp, 1));
452}
453
454int
455pms_get_status(struct pms_softc *sc, u_char *resp)
456{
457	u_char cmd[1];
458
459	cmd[0] = PMS_SEND_DEV_STATUS;
460	return (pms_cmd(sc, cmd, 1, resp, 3));
461}
462
463int
464pms_set_rate(struct pms_softc *sc, int value)
465{
466	u_char cmd[2];
467
468	cmd[0] = PMS_SET_SAMPLE;
469	cmd[1] = value;
470	return (pms_cmd(sc, cmd, 2, NULL, 0));
471}
472
473int
474pms_set_resolution(struct pms_softc *sc, int value)
475{
476	u_char cmd[2];
477
478	cmd[0] = PMS_SET_RES;
479	cmd[1] = value;
480	return (pms_cmd(sc, cmd, 2, NULL, 0));
481}
482
483int
484pms_set_scaling(struct pms_softc *sc, int scale)
485{
486	u_char cmd[1];
487
488	switch (scale) {
489	case 1:
490	default:
491		cmd[0] = PMS_SET_SCALE11;
492		break;
493	case 2:
494		cmd[0] = PMS_SET_SCALE21;
495		break;
496	}
497	return (pms_cmd(sc, cmd, 1, NULL, 0));
498}
499
500int
501pms_reset(struct pms_softc *sc)
502{
503	u_char cmd[1], resp[2];
504	int res;
505
506	cmd[0] = PMS_RESET;
507	res = pms_cmd(sc, cmd, 1, resp, 2);
508#ifdef DEBUG
509	if (res || resp[0] != PMS_RSTDONE || resp[1] != 0)
510		printf("%s: reset error %d (response 0x%02x, type 0x%02x)\n",
511		    DEVNAME(sc), res, resp[0], resp[1]);
512#endif
513	return (res);
514}
515
516int
517pms_dev_enable(struct pms_softc *sc)
518{
519	u_char cmd[1];
520	int res;
521
522	cmd[0] = PMS_DEV_ENABLE;
523	res = pms_cmd(sc, cmd, 1, NULL, 0);
524	if (res)
525		printf("%s: enable error\n", DEVNAME(sc));
526	return (res);
527}
528
529int
530pms_dev_disable(struct pms_softc *sc)
531{
532	u_char cmd[1];
533	int res;
534
535	cmd[0] = PMS_DEV_DISABLE;
536	res = pms_cmd(sc, cmd, 1, NULL, 0);
537	if (res)
538		printf("%s: disable error\n", DEVNAME(sc));
539	return (res);
540}
541
542void
543pms_protocol_lookup(struct pms_softc *sc)
544{
545	int i;
546
547	sc->protocol = &pms_protocols[0];
548	for (i = 1; i < nitems(pms_protocols); i++) {
549		pms_reset(sc);
550		if (pms_protocols[i].enable(sc)) {
551			sc->protocol = &pms_protocols[i];
552			break;
553		}
554	}
555
556	DPRINTF("%s: protocol type %d\n", DEVNAME(sc), sc->protocol->type);
557}
558
559/*
560 * Detect reset announcement ([0xaa, 0x0]).
561 * The sequence will be sent as input on rare occasions when the touchpad was
562 * reset due to a power failure.
563 */
564void
565pms_reset_detect(struct pms_softc *sc, int data)
566{
567	switch (sc->sc_rststate) {
568	case PMS_RST_COMMENCE:
569		if (data == 0x0) {
570			sc->sc_rststate = PMS_RST_ANNOUNCED;
571			timeout_add_msec(&sc->sc_rsttimo, 100);
572		} else if (data != PMS_RSTDONE) {
573			sc->sc_rststate = 0;
574		}
575		break;
576	default:
577		if (data == PMS_RSTDONE)
578			sc->sc_rststate = PMS_RST_COMMENCE;
579		else
580			sc->sc_rststate = 0;
581	}
582}
583
584void
585pms_reset_timo(void *v)
586{
587	struct pms_softc *sc = v;
588	int s = spltty();
589
590	/*
591	 * Do nothing if the reset was a false positive or if the device already
592	 * is disabled.
593	 */
594	if (sc->sc_rststate == PMS_RST_ANNOUNCED &&
595	    sc->sc_state != PMS_STATE_DISABLED)
596		task_add(systq, &sc->sc_rsttask);
597
598	splx(s);
599}
600
601void
602pms_reset_task(void *v)
603{
604	struct pms_softc *sc = v;
605	int s = spltty();
606
607#ifdef DIAGNOSTIC
608	printf("%s: device reset (state = %d)\n", DEVNAME(sc), sc->sc_rststate);
609#endif
610
611	rw_enter_write(&sc->sc_state_lock);
612
613	if (sc->sc_sec_wsmousedev != NULL)
614		pms_change_state(sc, PMS_STATE_DISABLED, PMS_DEV_SECONDARY);
615	pms_change_state(sc, PMS_STATE_DISABLED, PMS_DEV_PRIMARY);
616
617	pms_change_state(sc, PMS_STATE_ENABLED, PMS_DEV_PRIMARY);
618	if (sc->sc_sec_wsmousedev != NULL)
619		pms_change_state(sc, PMS_STATE_ENABLED, PMS_DEV_SECONDARY);
620
621	rw_exit_write(&sc->sc_state_lock);
622	splx(s);
623}
624
625int
626pms_enable_intelli(struct pms_softc *sc)
627{
628	u_char resp;
629
630	/* the special sequence to enable the third button and the roller */
631	if (pms_set_rate(sc, PMS_INTELLI_MAGIC1) ||
632	    pms_set_rate(sc, PMS_INTELLI_MAGIC2) ||
633	    pms_set_rate(sc, PMS_INTELLI_MAGIC3) ||
634	    pms_get_devid(sc, &resp) ||
635	    resp != PMS_INTELLI_ID)
636		return (0);
637
638	return (1);
639}
640
641int
642pms_ioctl_mouse(struct pms_softc *sc, u_long cmd, caddr_t data, int flag,
643    struct proc *p)
644{
645	int i;
646
647	switch (cmd) {
648	case WSMOUSEIO_GTYPE:
649		*(u_int *)data = WSMOUSE_TYPE_PS2;
650		break;
651	case WSMOUSEIO_SRES:
652		i = ((int) *(u_int *)data - 12) / 25;
653		/* valid values are {0,1,2,3} */
654		if (i < 0)
655			i = 0;
656		if (i > 3)
657			i = 3;
658
659		if (pms_set_resolution(sc, i))
660			printf("%s: SET_RES command error\n", DEVNAME(sc));
661		break;
662	default:
663		return (-1);
664	}
665	return (0);
666}
667
668int
669pms_sync_mouse(struct pms_softc *sc, int data)
670{
671	if (sc->inputstate != 0)
672		return (0);
673
674	switch (sc->protocol->type) {
675	case PMS_STANDARD:
676		if ((data & 0xc0) != 0)
677			return (-1);
678		break;
679	case PMS_INTELLI:
680		if ((data & 0x08) != 0x08)
681			return (-1);
682		break;
683	}
684
685	return (0);
686}
687
688void
689pms_proc_mouse(struct pms_softc *sc)
690{
691	u_int buttons;
692	int  dx, dy, dz;
693
694	buttons = butmap[sc->packet[0] & PMS_PS2_BUTTONSMASK];
695	dx = (sc->packet[0] & PMS_PS2_XNEG) ?
696	    (int)sc->packet[1] - 256 : sc->packet[1];
697	dy = (sc->packet[0] & PMS_PS2_YNEG) ?
698	    (int)sc->packet[2] - 256 : sc->packet[2];
699
700	if (sc->protocol->type == PMS_INTELLI)
701		dz = (signed char)sc->packet[3];
702	else
703		dz = 0;
704
705	WSMOUSE_INPUT(sc->sc_wsmousedev, buttons, dx, dy, dz, 0);
706}
707
708int
709pmsprobe(struct device *parent, void *match, void *aux)
710{
711	struct pckbc_attach_args *pa = aux;
712	u_char cmd[1], resp[2];
713	int res;
714
715	if (pa->pa_slot != PCKBC_AUX_SLOT)
716		return (0);
717
718	/* Flush any garbage. */
719	pckbc_flush(pa->pa_tag, pa->pa_slot);
720
721	/* reset the device */
722	cmd[0] = PMS_RESET;
723	res = pckbc_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 2, resp, 1);
724	if (res || resp[0] != PMS_RSTDONE || resp[1] != 0) {
725#ifdef DEBUG
726		printf("pms: reset error %d (response 0x%02x, type 0x%02x)\n",
727		    res, resp[0], resp[1]);
728#endif
729		return (0);
730	}
731
732	return (1);
733}
734
735void
736pmsattach(struct device *parent, struct device *self, void *aux)
737{
738	struct pms_softc *sc = (void *)self;
739	struct pckbc_attach_args *pa = aux;
740	struct wsmousedev_attach_args a;
741
742	sc->sc_kbctag = pa->pa_tag;
743
744	pckbc_set_inputhandler(sc->sc_kbctag, PCKBC_AUX_SLOT,
745	    pmsinput, sc, DEVNAME(sc));
746
747	printf("\n");
748
749	a.accessops = &pms_accessops;
750	a.accesscookie = sc;
751
752	rw_init(&sc->sc_state_lock, "pmsst");
753
754	/*
755	 * Attach the wsmouse, saving a handle to it.
756	 * Note that we don't need to check this pointer against NULL
757	 * here or in pmsintr, because if this fails pms_enable() will
758	 * never be called, so pmsinput() will never be called.
759	 */
760	sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint);
761
762	task_set(&sc->sc_rsttask, pms_reset_task, sc);
763	timeout_set(&sc->sc_rsttimo, pms_reset_timo, sc);
764
765	sc->poll = 1;
766	sc->sc_dev_enable = 0;
767
768	/* See if the device understands an extended (touchpad) protocol. */
769	pms_protocol_lookup(sc);
770
771	/* no interrupts until enabled */
772	pms_change_state(sc, PMS_STATE_DISABLED, PMS_DEV_IGNORE);
773}
774
775int
776pmsactivate(struct device *self, int act)
777{
778	struct pms_softc *sc = (struct pms_softc *)self;
779
780	switch (act) {
781	case DVACT_SUSPEND:
782		if (sc->sc_state == PMS_STATE_ENABLED)
783			pms_change_state(sc, PMS_STATE_SUSPENDED,
784			    PMS_DEV_IGNORE);
785		break;
786	case DVACT_RESUME:
787		if (sc->sc_state == PMS_STATE_SUSPENDED)
788			pms_change_state(sc, PMS_STATE_ENABLED,
789			    PMS_DEV_IGNORE);
790		break;
791	}
792	return (0);
793}
794
795int
796pms_change_state(struct pms_softc *sc, int newstate, int dev)
797{
798	if (dev != PMS_DEV_IGNORE) {
799		switch (newstate) {
800		case PMS_STATE_ENABLED:
801			if (sc->sc_dev_enable & dev)
802				return (EBUSY);
803
804			sc->sc_dev_enable |= dev;
805
806			if (sc->sc_state == PMS_STATE_ENABLED)
807				return (0);
808
809			break;
810		case PMS_STATE_DISABLED:
811			sc->sc_dev_enable &= ~dev;
812
813			if (sc->sc_dev_enable)
814				return (0);
815
816			break;
817		}
818	}
819
820	switch (newstate) {
821	case PMS_STATE_ENABLED:
822		sc->inputstate = 0;
823		sc->sc_rststate = 0;
824
825		pckbc_slot_enable(sc->sc_kbctag, PCKBC_AUX_SLOT, 1);
826
827		if (sc->poll)
828			pckbc_flush(sc->sc_kbctag, PCKBC_AUX_SLOT);
829
830		pms_reset(sc);
831		if (sc->protocol->enable != NULL &&
832		    sc->protocol->enable(sc) == 0)
833			pms_protocol_lookup(sc);
834
835		pms_dev_enable(sc);
836		break;
837	case PMS_STATE_DISABLED:
838	case PMS_STATE_SUSPENDED:
839		pms_dev_disable(sc);
840
841		if (sc->protocol->disable)
842			sc->protocol->disable(sc);
843
844		pckbc_slot_enable(sc->sc_kbctag, PCKBC_AUX_SLOT, 0);
845		break;
846	}
847
848	sc->sc_state = newstate;
849	sc->poll = (newstate == PMS_STATE_SUSPENDED) ? 1 : 0;
850
851	return (0);
852}
853
854int
855pms_enable(void *v)
856{
857	struct pms_softc *sc = v;
858	int rv;
859
860	rw_enter_write(&sc->sc_state_lock);
861	rv = pms_change_state(sc, PMS_STATE_ENABLED, PMS_DEV_PRIMARY);
862	rw_exit_write(&sc->sc_state_lock);
863
864	return (rv);
865}
866
867void
868pms_disable(void *v)
869{
870	struct pms_softc *sc = v;
871
872	rw_enter_write(&sc->sc_state_lock);
873	pms_change_state(sc, PMS_STATE_DISABLED, PMS_DEV_PRIMARY);
874	rw_exit_write(&sc->sc_state_lock);
875}
876
877int
878pms_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
879{
880	struct pms_softc *sc = v;
881
882	if (sc->protocol->ioctl)
883		return (sc->protocol->ioctl(sc, cmd, data, flag, p));
884	else
885		return (-1);
886}
887
888int
889pms_sec_enable(void *v)
890{
891	struct pms_softc *sc = v;
892	int rv;
893
894	rw_enter_write(&sc->sc_state_lock);
895	rv = pms_change_state(sc, PMS_STATE_ENABLED, PMS_DEV_SECONDARY);
896	rw_exit_write(&sc->sc_state_lock);
897
898	return (rv);
899}
900
901void
902pms_sec_disable(void *v)
903{
904	struct pms_softc *sc = v;
905
906	rw_enter_write(&sc->sc_state_lock);
907	pms_change_state(sc, PMS_STATE_DISABLED, PMS_DEV_SECONDARY);
908	rw_exit_write(&sc->sc_state_lock);
909}
910
911int
912pms_sec_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
913{
914	switch (cmd) {
915	case WSMOUSEIO_GTYPE:
916		*(u_int *)data = WSMOUSE_TYPE_PS2;
917		break;
918	default:
919		return (-1);
920	}
921	return (0);
922}
923
924void
925pmsinput(void *vsc, int data)
926{
927	struct pms_softc *sc = vsc;
928
929	if (sc->sc_state != PMS_STATE_ENABLED) {
930		/* Interrupts are not expected.  Discard the byte. */
931		return;
932	}
933
934	sc->packet[sc->inputstate] = data;
935	pms_reset_detect(sc, data);
936	if (sc->protocol->sync(sc, data)) {
937#ifdef DIAGNOSTIC
938		printf("%s: not in sync yet, discard input "
939		    "(state = %d, data = %#x)\n",
940		    DEVNAME(sc), sc->inputstate, data);
941#endif
942
943		sc->inputstate = 0;
944		return;
945	}
946
947	sc->inputstate++;
948
949	if (sc->inputstate != sc->protocol->packetsize)
950		return;
951
952	sc->inputstate = 0;
953	sc->protocol->proc(sc);
954}
955
956int
957synaptics_set_mode(struct pms_softc *sc, int mode)
958{
959	struct synaptics_softc *syn = sc->synaptics;
960
961	if (pms_spec_cmd(sc, mode) ||
962	    pms_set_rate(sc, SYNAPTICS_CMD_SET_MODE))
963		return (-1);
964
965	syn->mode = mode;
966
967	return (0);
968}
969
970int
971synaptics_query(struct pms_softc *sc, int query, int *val)
972{
973	u_char resp[3];
974
975	if (pms_spec_cmd(sc, query) ||
976	    pms_get_status(sc, resp))
977		return (-1);
978
979	if (val)
980		*val = (resp[0] << 16) | (resp[1] << 8) | resp[2];
981
982	return (0);
983}
984
985int
986synaptics_get_hwinfo(struct pms_softc *sc)
987{
988	struct synaptics_softc *syn = sc->synaptics;
989	struct wsmousehw *hw;
990	int resolution = 0, max_coords = 0, min_coords = 0;
991
992	hw = wsmouse_get_hw(sc->sc_wsmousedev);
993
994	if (synaptics_query(sc, SYNAPTICS_QUE_IDENTIFY, &syn->identify))
995		return (-1);
996	if (synaptics_query(sc, SYNAPTICS_QUE_CAPABILITIES,
997	    &syn->capabilities))
998		return (-1);
999	if (synaptics_query(sc, SYNAPTICS_QUE_MODEL, &syn->model))
1000		return (-1);
1001	if ((SYNAPTICS_CAP_EXTENDED_QUERIES(syn->capabilities) >= 1) &&
1002	    synaptics_query(sc, SYNAPTICS_QUE_EXT_MODEL, &syn->ext_model))
1003		return (-1);
1004	if ((SYNAPTICS_CAP_EXTENDED_QUERIES(syn->capabilities) >= 4) &&
1005	    synaptics_query(sc, SYNAPTICS_QUE_EXT_CAPABILITIES,
1006		&syn->ext_capabilities))
1007		return (-1);
1008	if ((SYNAPTICS_ID_MAJOR(syn->identify) >= 4) &&
1009	    synaptics_query(sc, SYNAPTICS_QUE_RESOLUTION, &resolution))
1010		return (-1);
1011	if ((SYNAPTICS_CAP_EXTENDED_QUERIES(syn->capabilities) >= 5) &&
1012	    (syn->ext_capabilities & SYNAPTICS_EXT_CAP_MAX_COORDS) &&
1013	    synaptics_query(sc, SYNAPTICS_QUE_EXT_MAX_COORDS, &max_coords))
1014		return (-1);
1015	if ((SYNAPTICS_CAP_EXTENDED_QUERIES(syn->capabilities) >= 7 ||
1016	    SYNAPTICS_ID_FULL(syn->identify) == 0x801) &&
1017	    (syn->ext_capabilities & SYNAPTICS_EXT_CAP_MIN_COORDS) &&
1018	    synaptics_query(sc, SYNAPTICS_QUE_EXT_MIN_COORDS, &min_coords))
1019		return (-1);
1020
1021	if (SYNAPTICS_ID_FULL(syn->identify) >= 0x705) {
1022		if (synaptics_query(sc, SYNAPTICS_QUE_MODES, &syn->modes))
1023			return (-1);
1024		if ((syn->modes & SYNAPTICS_EXT2_CAP) &&
1025		    synaptics_query(sc, SYNAPTICS_QUE_EXT2_CAPABILITIES,
1026		    &syn->ext2_capabilities))
1027			return (-1);
1028	}
1029
1030	if ((syn->ext_capabilities & SYNAPTICS_EXT_CAP_CLICKPAD) &&
1031	    !(syn->ext2_capabilities & SYNAPTICS_EXT2_CAP_BUTTONS_STICK)
1032	    && mouse_has_softbtn)
1033		hw->type = WSMOUSE_TYPE_SYNAP_SBTN;
1034	else
1035		hw->type = WSMOUSE_TYPE_SYNAPTICS;
1036
1037	hw->hw_type = (syn->ext_capabilities & SYNAPTICS_EXT_CAP_CLICKPAD)
1038	    ? WSMOUSEHW_CLICKPAD : WSMOUSEHW_TOUCHPAD;
1039
1040	if (resolution & SYNAPTICS_RESOLUTION_VALID) {
1041		hw->h_res = SYNAPTICS_RESOLUTION_X(resolution);
1042		hw->v_res = SYNAPTICS_RESOLUTION_Y(resolution);
1043	}
1044
1045	hw->x_min = (min_coords ?
1046	    SYNAPTICS_X_LIMIT(min_coords) : SYNAPTICS_XMIN_BEZEL);
1047	hw->y_min = (min_coords ?
1048	    SYNAPTICS_Y_LIMIT(min_coords) : SYNAPTICS_YMIN_BEZEL);
1049	hw->x_max = (max_coords ?
1050	    SYNAPTICS_X_LIMIT(max_coords) : SYNAPTICS_XMAX_BEZEL);
1051	hw->y_max = (max_coords ?
1052	    SYNAPTICS_Y_LIMIT(max_coords) : SYNAPTICS_YMAX_BEZEL);
1053
1054	hw->contacts_max = SYNAPTICS_MAX_FINGERS;
1055
1056	syn->sec_buttons = 0;
1057
1058	if (SYNAPTICS_EXT_MODEL_BUTTONS(syn->ext_model) > 8)
1059		syn->ext_model &= ~0xf000;
1060
1061	if ((syn->model & SYNAPTICS_MODEL_NEWABS) == 0) {
1062		printf("%s: don't support Synaptics OLDABS\n", DEVNAME(sc));
1063		return (-1);
1064	}
1065
1066	if ((SYNAPTICS_ID_MAJOR(syn->identify) == 5) &&
1067	    (SYNAPTICS_ID_MINOR(syn->identify) == 9))
1068		syn->mask = SYNAPTICS_MASK_NEWABS_RELAXED;
1069	else
1070		syn->mask = SYNAPTICS_MASK_NEWABS_STRICT;
1071
1072	return (0);
1073}
1074
1075void
1076synaptics_sec_proc(struct pms_softc *sc)
1077{
1078	struct synaptics_softc *syn = sc->synaptics;
1079	u_int buttons;
1080	int dx, dy;
1081
1082	if ((sc->sc_dev_enable & PMS_DEV_SECONDARY) == 0)
1083		return;
1084
1085	buttons = butmap[sc->packet[1] & PMS_PS2_BUTTONSMASK];
1086	buttons |= syn->sec_buttons;
1087	dx = (sc->packet[1] & PMS_PS2_XNEG) ?
1088	    (int)sc->packet[4] - 256 : sc->packet[4];
1089	dy = (sc->packet[1] & PMS_PS2_YNEG) ?
1090	    (int)sc->packet[5] - 256 : sc->packet[5];
1091
1092	WSMOUSE_INPUT(sc->sc_sec_wsmousedev, buttons, dx, dy, 0, 0);
1093}
1094
1095int
1096synaptics_knock(struct pms_softc *sc)
1097{
1098	u_char resp[3];
1099
1100	if (pms_set_resolution(sc, 0) ||
1101	    pms_set_resolution(sc, 0) ||
1102	    pms_set_resolution(sc, 0) ||
1103	    pms_set_resolution(sc, 0) ||
1104	    pms_get_status(sc, resp) ||
1105	    resp[1] != SYNAPTICS_ID_MAGIC)
1106		return (-1);
1107
1108	return (0);
1109}
1110
1111int
1112pms_enable_synaptics(struct pms_softc *sc)
1113{
1114	struct synaptics_softc *syn = sc->synaptics;
1115	struct wsmousedev_attach_args a;
1116	int mode, i;
1117
1118	if (synaptics_knock(sc)) {
1119		if (sc->synaptics == NULL)
1120			goto err;
1121		/*
1122		 * Some synaptics touchpads don't resume quickly.
1123		 * Retry a few times.
1124		 */
1125		for (i = 10; i > 0; --i) {
1126			printf("%s: device not resuming, retrying\n",
1127			    DEVNAME(sc));
1128			pms_reset(sc);
1129			if (synaptics_knock(sc) == 0)
1130				break;
1131			delay(100000);
1132		}
1133		if (i == 0) {
1134			printf("%s: lost device\n", DEVNAME(sc));
1135			goto err;
1136		}
1137	}
1138
1139	if (sc->synaptics == NULL) {
1140		sc->synaptics = syn = malloc(sizeof(struct synaptics_softc),
1141		    M_DEVBUF, M_WAITOK | M_ZERO);
1142		if (syn == NULL) {
1143			printf("%s: synaptics: not enough memory\n",
1144			    DEVNAME(sc));
1145			goto err;
1146		}
1147
1148		if (synaptics_get_hwinfo(sc)) {
1149			free(sc->synaptics, M_DEVBUF,
1150			    sizeof(struct synaptics_softc));
1151			sc->synaptics = NULL;
1152			goto err;
1153		}
1154
1155		/* enable pass-through PS/2 port if supported */
1156		if (syn->capabilities & SYNAPTICS_CAP_PASSTHROUGH) {
1157			a.accessops = &pms_sec_accessops;
1158			a.accesscookie = sc;
1159			sc->sc_sec_wsmousedev = config_found((void *)sc, &a,
1160			    wsmousedevprint);
1161		}
1162
1163		if (wsmouse_configure(sc->sc_wsmousedev, synaptics_params,
1164		    nitems(synaptics_params)))
1165			goto err;
1166
1167		printf("%s: Synaptics %s, firmware %d.%d, 0x%x 0x%x\n",
1168		    DEVNAME(sc),
1169		    (syn->ext_capabilities & SYNAPTICS_EXT_CAP_CLICKPAD ?
1170			"clickpad" : "touchpad"),
1171		    SYNAPTICS_ID_MAJOR(syn->identify),
1172		    SYNAPTICS_ID_MINOR(syn->identify),
1173		    syn->model, syn->ext_model);
1174	}
1175
1176	mode = SYNAPTICS_ABSOLUTE_MODE | SYNAPTICS_HIGH_RATE;
1177	if (SYNAPTICS_ID_MAJOR(syn->identify) >= 4)
1178		mode |= SYNAPTICS_DISABLE_GESTURE;
1179	if (syn->capabilities & SYNAPTICS_CAP_EXTENDED)
1180		mode |= SYNAPTICS_W_MODE;
1181	if (synaptics_set_mode(sc, mode))
1182		goto err;
1183
1184	/* enable advanced gesture mode if supported */
1185	if ((syn->ext_capabilities & SYNAPTICS_EXT_CAP_ADV_GESTURE) &&
1186	    (pms_spec_cmd(sc, SYNAPTICS_QUE_MODEL) ||
1187	     pms_set_rate(sc, SYNAPTICS_CMD_SET_ADV_GESTURE_MODE)))
1188		goto err;
1189
1190	return (1);
1191
1192err:
1193	pms_reset(sc);
1194
1195	return (0);
1196}
1197
1198int
1199pms_ioctl_synaptics(struct pms_softc *sc, u_long cmd, caddr_t data, int flag,
1200    struct proc *p)
1201{
1202	struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data;
1203	struct wsmousehw *hw;
1204	int wsmode;
1205
1206	hw = wsmouse_get_hw(sc->sc_wsmousedev);
1207	switch (cmd) {
1208	case WSMOUSEIO_GTYPE:
1209		*(u_int *)data = hw->type;
1210		break;
1211	case WSMOUSEIO_GCALIBCOORDS:
1212		wsmc->minx = hw->x_min;
1213		wsmc->maxx = hw->x_max;
1214		wsmc->miny = hw->y_min;
1215		wsmc->maxy = hw->y_max;
1216		wsmc->swapxy = 0;
1217		wsmc->resx = hw->h_res;
1218		wsmc->resy = hw->v_res;
1219		break;
1220	case WSMOUSEIO_SETMODE:
1221		wsmode = *(u_int *)data;
1222		if (wsmode != WSMOUSE_COMPAT && wsmode != WSMOUSE_NATIVE)
1223			return (EINVAL);
1224		wsmouse_set_mode(sc->sc_wsmousedev, wsmode);
1225		break;
1226	default:
1227		return (-1);
1228	}
1229	return (0);
1230}
1231
1232int
1233pms_sync_synaptics(struct pms_softc *sc, int data)
1234{
1235	struct synaptics_softc *syn = sc->synaptics;
1236
1237	switch (sc->inputstate) {
1238	case 0:
1239		if ((data & syn->mask) != SYNAPTICS_VALID_NEWABS_FIRST)
1240			return (-1);
1241		break;
1242	case 3:
1243		if ((data & syn->mask) != SYNAPTICS_VALID_NEWABS_NEXT)
1244			return (-1);
1245		break;
1246	}
1247
1248	return (0);
1249}
1250
1251void
1252pms_proc_synaptics(struct pms_softc *sc)
1253{
1254	struct synaptics_softc *syn = sc->synaptics;
1255	u_int buttons;
1256	int x, y, z, w, fingerwidth;
1257
1258	w = ((sc->packet[0] & 0x30) >> 2) | ((sc->packet[0] & 0x04) >> 1) |
1259	    ((sc->packet[3] & 0x04) >> 2);
1260	z = sc->packet[2];
1261
1262	if ((syn->capabilities & SYNAPTICS_CAP_EXTENDED) == 0) {
1263		/*
1264		 * Emulate W mode for models that don't provide it. Bit 3
1265		 * of the w-input signals a touch ("finger"), Bit 2 and
1266		 * the "gesture" bits 1-0 can be ignored.
1267		 */
1268		if (w & 8)
1269			w = 4;
1270		else
1271			z = w = 0;
1272	}
1273
1274
1275	if ((syn->capabilities & SYNAPTICS_CAP_PASSTHROUGH) && w == 3) {
1276		synaptics_sec_proc(sc);
1277		return;
1278	}
1279
1280	if ((sc->sc_dev_enable & PMS_DEV_PRIMARY) == 0)
1281		return;
1282
1283	/* XXX ignore advanced gesture packet, not yet supported */
1284	if ((syn->ext_capabilities & SYNAPTICS_EXT_CAP_ADV_GESTURE) && w == 2)
1285		return;
1286
1287	x = ((sc->packet[3] & 0x10) << 8) | ((sc->packet[1] & 0x0f) << 8) |
1288	    sc->packet[4];
1289	y = ((sc->packet[3] & 0x20) << 7) | ((sc->packet[1] & 0xf0) << 4) |
1290	    sc->packet[5];
1291
1292	buttons = ((sc->packet[0] & sc->packet[3]) & 0x01) ?
1293	    WSMOUSE_BUTTON(1) : 0;
1294	buttons |= ((sc->packet[0] & sc->packet[3]) & 0x02) ?
1295	    WSMOUSE_BUTTON(3) : 0;
1296
1297	if (syn->ext_capabilities & SYNAPTICS_EXT_CAP_CLICKPAD) {
1298		buttons |= ((sc->packet[0] ^ sc->packet[3]) & 0x01) ?
1299		    WSMOUSE_BUTTON(1) : 0;
1300	} else if (syn->capabilities & SYNAPTICS_CAP_MIDDLE_BUTTON) {
1301		buttons |= ((sc->packet[0] ^ sc->packet[3]) & 0x01) ?
1302		    WSMOUSE_BUTTON(2) : 0;
1303	}
1304
1305	if (syn->capabilities & SYNAPTICS_CAP_FOUR_BUTTON) {
1306		buttons |= ((sc->packet[0] ^ sc->packet[3]) & 0x01) ?
1307		    WSMOUSE_BUTTON(4) : 0;
1308		buttons |= ((sc->packet[0] ^ sc->packet[3]) & 0x02) ?
1309		    WSMOUSE_BUTTON(5) : 0;
1310	} else if (SYNAPTICS_EXT_MODEL_BUTTONS(syn->ext_model) &&
1311	    ((sc->packet[0] ^ sc->packet[3]) & 0x02)) {
1312		if (syn->ext2_capabilities & SYNAPTICS_EXT2_CAP_BUTTONS_STICK) {
1313			/*
1314			 * Trackstick buttons on this machine are wired to the
1315			 * trackpad as extra buttons, so route the event
1316			 * through the trackstick interface as normal buttons
1317			 */
1318			syn->sec_buttons =
1319			    (sc->packet[4] & 0x01) ? WSMOUSE_BUTTON(1) : 0;
1320			syn->sec_buttons |=
1321			    (sc->packet[5] & 0x01) ? WSMOUSE_BUTTON(3) : 0;
1322			syn->sec_buttons |=
1323			    (sc->packet[4] & 0x02) ? WSMOUSE_BUTTON(2) : 0;
1324			wsmouse_buttons(
1325			    sc->sc_sec_wsmousedev, syn->sec_buttons);
1326			wsmouse_input_sync(sc->sc_sec_wsmousedev);
1327			return;
1328		}
1329
1330		buttons |= (sc->packet[4] & 0x01) ? WSMOUSE_BUTTON(6) : 0;
1331		buttons |= (sc->packet[5] & 0x01) ? WSMOUSE_BUTTON(7) : 0;
1332		buttons |= (sc->packet[4] & 0x02) ? WSMOUSE_BUTTON(8) : 0;
1333		buttons |= (sc->packet[5] & 0x02) ? WSMOUSE_BUTTON(9) : 0;
1334		buttons |= (sc->packet[4] & 0x04) ? WSMOUSE_BUTTON(10) : 0;
1335		buttons |= (sc->packet[5] & 0x04) ? WSMOUSE_BUTTON(11) : 0;
1336		buttons |= (sc->packet[4] & 0x08) ? WSMOUSE_BUTTON(12) : 0;
1337		buttons |= (sc->packet[5] & 0x08) ? WSMOUSE_BUTTON(13) : 0;
1338		x &= ~0x0f;
1339		y &= ~0x0f;
1340	}
1341
1342	if (z) {
1343		fingerwidth = max(w, 4);
1344		w = (w < 2 ? w + 2 : 1);
1345	} else {
1346		fingerwidth = 0;
1347		w = 0;
1348	}
1349	wsmouse_set(sc->sc_wsmousedev, WSMOUSE_TOUCH_WIDTH, fingerwidth, 0);
1350	WSMOUSE_TOUCH(sc->sc_wsmousedev, buttons, x, y, z, w);
1351}
1352
1353void
1354pms_disable_synaptics(struct pms_softc *sc)
1355{
1356	struct synaptics_softc *syn = sc->synaptics;
1357
1358	if (syn->capabilities & SYNAPTICS_CAP_SLEEP)
1359		synaptics_set_mode(sc, SYNAPTICS_SLEEP_MODE |
1360		    SYNAPTICS_DISABLE_GESTURE);
1361}
1362
1363int
1364alps_sec_proc(struct pms_softc *sc)
1365{
1366	struct alps_softc *alps = sc->alps;
1367	int dx, dy, pos = 0;
1368
1369	if ((sc->packet[0] & PMS_ALPS_PS2_MASK) == PMS_ALPS_PS2_VALID) {
1370		/*
1371		 * We need to keep buttons states because interleaved
1372		 * packets only signalize x/y movements.
1373		 */
1374		alps->sec_buttons = butmap[sc->packet[0] & PMS_PS2_BUTTONSMASK];
1375	} else if ((sc->packet[3] & PMS_ALPS_INTERLEAVED_MASK) ==
1376	    PMS_ALPS_INTERLEAVED_VALID) {
1377		sc->inputstate = 3;
1378		pos = 3;
1379	} else {
1380		return (0);
1381	}
1382
1383	if ((sc->sc_dev_enable & PMS_DEV_SECONDARY) == 0)
1384		return (1);
1385
1386	dx = (sc->packet[pos] & PMS_PS2_XNEG) ?
1387	    (int)sc->packet[pos + 1] - 256 : sc->packet[pos + 1];
1388	dy = (sc->packet[pos] & PMS_PS2_YNEG) ?
1389	    (int)sc->packet[pos + 2] - 256 : sc->packet[pos + 2];
1390
1391	WSMOUSE_INPUT(sc->sc_sec_wsmousedev, alps->sec_buttons, dx, dy, 0, 0);
1392
1393	return (1);
1394}
1395
1396int
1397alps_get_hwinfo(struct pms_softc *sc)
1398{
1399	struct alps_softc *alps = sc->alps;
1400	u_char resp[3];
1401	int i;
1402	struct wsmousehw *hw;
1403
1404	if (pms_set_resolution(sc, 0) ||
1405	    pms_set_scaling(sc, 2) ||
1406	    pms_set_scaling(sc, 2) ||
1407	    pms_set_scaling(sc, 2) ||
1408	    pms_get_status(sc, resp)) {
1409		DPRINTF("%s: alps: model query error\n", DEVNAME(sc));
1410		return (-1);
1411	}
1412
1413	alps->version = (resp[0] << 8) | (resp[1] << 4) | (resp[2] / 20 + 1);
1414
1415	for (i = 0; i < nitems(alps_models); i++)
1416		if (alps->version == alps_models[i].version) {
1417			alps->model = alps_models[i].model;
1418			alps->mask = alps_models[i].mask;
1419
1420			hw = wsmouse_get_hw(sc->sc_wsmousedev);
1421			hw->type = WSMOUSE_TYPE_ALPS;
1422			hw->hw_type = WSMOUSEHW_TOUCHPAD;
1423			hw->x_min = ALPS_XMIN_BEZEL;
1424			hw->y_min = ALPS_YMIN_BEZEL;
1425			hw->x_max = ALPS_XMAX_BEZEL;
1426			hw->y_max = ALPS_YMAX_BEZEL;
1427			hw->contacts_max = 1;
1428
1429			return (0);
1430		}
1431
1432	return (-1);
1433}
1434
1435int
1436pms_enable_alps(struct pms_softc *sc)
1437{
1438	struct alps_softc *alps = sc->alps;
1439	struct wsmousedev_attach_args a;
1440	u_char resp[3];
1441
1442	if (pms_set_resolution(sc, 0) ||
1443	    pms_set_scaling(sc, 1) ||
1444	    pms_set_scaling(sc, 1) ||
1445	    pms_set_scaling(sc, 1) ||
1446	    pms_get_status(sc, resp) ||
1447	    resp[0] != PMS_ALPS_MAGIC1 ||
1448	    resp[1] != PMS_ALPS_MAGIC2 ||
1449	    (resp[2] != PMS_ALPS_MAGIC3_1 && resp[2] != PMS_ALPS_MAGIC3_2 &&
1450	    resp[2] != PMS_ALPS_MAGIC3_3))
1451		goto err;
1452
1453	if (sc->alps == NULL) {
1454		sc->alps = alps = malloc(sizeof(struct alps_softc),
1455		    M_DEVBUF, M_WAITOK | M_ZERO);
1456		if (alps == NULL) {
1457			printf("%s: alps: not enough memory\n", DEVNAME(sc));
1458			goto err;
1459		}
1460
1461		if (alps_get_hwinfo(sc)) {
1462			free(sc->alps, M_DEVBUF, sizeof(struct alps_softc));
1463			sc->alps = NULL;
1464			goto err;
1465		}
1466
1467		if (wsmouse_configure(sc->sc_wsmousedev, alps_params,
1468		    nitems(alps_params))) {
1469			free(sc->alps, M_DEVBUF, sizeof(struct alps_softc));
1470			sc->alps = NULL;
1471			printf("%s: setup failed\n", DEVNAME(sc));
1472			goto err;
1473		}
1474
1475		printf("%s: ALPS %s, version 0x%04x\n", DEVNAME(sc),
1476		    (alps->model & ALPS_DUALPOINT ? "Dualpoint" : "Glidepoint"),
1477		    alps->version);
1478
1479
1480		if (alps->model & ALPS_DUALPOINT) {
1481			a.accessops = &pms_sec_accessops;
1482			a.accesscookie = sc;
1483			sc->sc_sec_wsmousedev = config_found((void *)sc, &a,
1484			    wsmousedevprint);
1485		}
1486	}
1487
1488	if (alps->model == 0)
1489		goto err;
1490
1491	if ((alps->model & ALPS_PASSTHROUGH) &&
1492	   (pms_set_scaling(sc, 2) ||
1493	    pms_set_scaling(sc, 2) ||
1494	    pms_set_scaling(sc, 2) ||
1495	    pms_dev_disable(sc))) {
1496		DPRINTF("%s: alps: passthrough on error\n", DEVNAME(sc));
1497		goto err;
1498	}
1499
1500	if (pms_dev_disable(sc) ||
1501	    pms_dev_disable(sc) ||
1502	    pms_set_rate(sc, 0x0a)) {
1503		DPRINTF("%s: alps: tapping error\n", DEVNAME(sc));
1504		goto err;
1505	}
1506
1507	if (pms_dev_disable(sc) ||
1508	    pms_dev_disable(sc) ||
1509	    pms_dev_disable(sc) ||
1510	    pms_dev_disable(sc) ||
1511	    pms_dev_enable(sc)) {
1512		DPRINTF("%s: alps: absolute mode error\n", DEVNAME(sc));
1513		goto err;
1514	}
1515
1516	if ((alps->model & ALPS_PASSTHROUGH) &&
1517	   (pms_set_scaling(sc, 1) ||
1518	    pms_set_scaling(sc, 1) ||
1519	    pms_set_scaling(sc, 1) ||
1520	    pms_dev_disable(sc))) {
1521		DPRINTF("%s: alps: passthrough off error\n", DEVNAME(sc));
1522		goto err;
1523	}
1524
1525	alps->sec_buttons = 0;
1526
1527	return (1);
1528
1529err:
1530	pms_reset(sc);
1531
1532	return (0);
1533}
1534
1535int
1536pms_ioctl_alps(struct pms_softc *sc, u_long cmd, caddr_t data, int flag,
1537    struct proc *p)
1538{
1539	struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data;
1540	int wsmode;
1541	struct wsmousehw *hw;
1542
1543	switch (cmd) {
1544	case WSMOUSEIO_GTYPE:
1545		*(u_int *)data = WSMOUSE_TYPE_ALPS;
1546		break;
1547	case WSMOUSEIO_GCALIBCOORDS:
1548		hw = wsmouse_get_hw(sc->sc_wsmousedev);
1549		wsmc->minx = hw->x_min;
1550		wsmc->maxx = hw->x_max;
1551		wsmc->miny = hw->y_min;
1552		wsmc->maxy = hw->y_max;
1553		wsmc->swapxy = 0;
1554		break;
1555	case WSMOUSEIO_SETMODE:
1556		wsmode = *(u_int *)data;
1557		if (wsmode != WSMOUSE_COMPAT && wsmode != WSMOUSE_NATIVE)
1558			return (EINVAL);
1559		wsmouse_set_mode(sc->sc_wsmousedev, wsmode);
1560		break;
1561	default:
1562		return (-1);
1563	}
1564	return (0);
1565}
1566
1567int
1568pms_sync_alps(struct pms_softc *sc, int data)
1569{
1570	struct alps_softc *alps = sc->alps;
1571
1572	if ((alps->model & ALPS_DUALPOINT) &&
1573	    (sc->packet[0] & PMS_ALPS_PS2_MASK) == PMS_ALPS_PS2_VALID) {
1574		if (sc->inputstate == 2)
1575			sc->inputstate += 3;
1576		return (0);
1577	}
1578
1579	switch (sc->inputstate) {
1580	case 0:
1581		if ((data & alps->mask) != alps->mask)
1582			return (-1);
1583		break;
1584	case 1:
1585	case 2:
1586	case 3:
1587		if ((data & PMS_ALPS_MASK) != PMS_ALPS_VALID)
1588			return (-1);
1589		break;
1590	case 4:
1591	case 5:
1592		if ((alps->model & ALPS_INTERLEAVED) == 0 &&
1593		    (data & PMS_ALPS_MASK) != PMS_ALPS_VALID)
1594			return (-1);
1595		break;
1596	}
1597
1598	return (0);
1599}
1600
1601void
1602pms_proc_alps(struct pms_softc *sc)
1603{
1604	struct alps_softc *alps = sc->alps;
1605	int x, y, z, dx, dy;
1606	u_int buttons, gesture;
1607
1608	if ((alps->model & ALPS_DUALPOINT) && alps_sec_proc(sc))
1609		return;
1610
1611	x = sc->packet[1] | ((sc->packet[2] & 0x78) << 4);
1612	y = sc->packet[4] | ((sc->packet[3] & 0x70) << 3);
1613	z = sc->packet[5];
1614
1615	buttons = ((sc->packet[3] & 1) ? WSMOUSE_BUTTON(1) : 0) |
1616	    ((sc->packet[3] & 2) ? WSMOUSE_BUTTON(3) : 0) |
1617	    ((sc->packet[3] & 4) ? WSMOUSE_BUTTON(2) : 0);
1618
1619	if ((sc->sc_dev_enable & PMS_DEV_SECONDARY) && z == ALPS_Z_MAGIC) {
1620		dx = (x > ALPS_XSEC_BEZEL / 2) ? (x - ALPS_XSEC_BEZEL) : x;
1621		dy = (y > ALPS_YSEC_BEZEL / 2) ? (y - ALPS_YSEC_BEZEL) : y;
1622
1623		WSMOUSE_INPUT(sc->sc_sec_wsmousedev, buttons, dx, dy, 0, 0);
1624
1625		return;
1626	}
1627
1628	if ((sc->sc_dev_enable & PMS_DEV_PRIMARY) == 0)
1629		return;
1630
1631	/*
1632	 * XXX The Y-axis is in the oposit direction compared to
1633	 * Synaptics touchpads and PS/2 mouses.
1634	 * It's why we need to translate the y value here for both
1635	 * NATIVE and COMPAT modes.
1636	 */
1637	y = ALPS_YMAX_BEZEL - y + ALPS_YMIN_BEZEL;
1638
1639	if (alps->gesture == ALPS_TAP) {
1640		/* Report a touch with the tap coordinates. */
1641		WSMOUSE_TOUCH(sc->sc_wsmousedev, buttons,
1642		    alps->old_x, alps->old_y, ALPS_PRESSURE, 0);
1643		if (z > 0) {
1644			/*
1645			 * The hardware doesn't send a null pressure
1646			 * event when dragging starts.
1647			 */
1648			WSMOUSE_TOUCH(sc->sc_wsmousedev, buttons,
1649			    alps->old_x, alps->old_y, 0, 0);
1650		}
1651	}
1652
1653	gesture = sc->packet[2] & 0x03;
1654	if (gesture != ALPS_TAP)
1655		WSMOUSE_TOUCH(sc->sc_wsmousedev, buttons, x, y, z, 0);
1656
1657	if (alps->gesture != ALPS_DRAG || gesture != ALPS_TAP)
1658		alps->gesture = gesture;
1659
1660	alps->old_x = x;
1661	alps->old_y = y;
1662}
1663
1664int
1665elantech_set_absolute_mode_v1(struct pms_softc *sc)
1666{
1667	int i;
1668	u_char resp[3];
1669
1670	/* Enable absolute mode. Magic numbers from Linux driver. */
1671	if (pms_spec_cmd(sc, ELANTECH_CMD_WRITE_REG) ||
1672	    pms_spec_cmd(sc, 0x10) ||
1673	    pms_spec_cmd(sc, 0x16) ||
1674	    pms_set_scaling(sc, 1) ||
1675	    pms_spec_cmd(sc, ELANTECH_CMD_WRITE_REG) ||
1676	    pms_spec_cmd(sc, 0x11) ||
1677	    pms_spec_cmd(sc, 0x8f) ||
1678	    pms_set_scaling(sc, 1))
1679		return (-1);
1680
1681	/* Read back reg 0x10 to ensure hardware is ready. */
1682	for (i = 0; i < 5; i++) {
1683		if (pms_spec_cmd(sc, ELANTECH_CMD_READ_REG) ||
1684		    pms_spec_cmd(sc, 0x10) ||
1685		    pms_get_status(sc, resp) == 0)
1686			break;
1687		delay(2000);
1688	}
1689	if (i == 5)
1690		return (-1);
1691
1692	if ((resp[0] & ELANTECH_ABSOLUTE_MODE) == 0)
1693		return (-1);
1694
1695	return (0);
1696}
1697
1698int
1699elantech_set_absolute_mode_v2(struct pms_softc *sc)
1700{
1701	int i;
1702	u_char resp[3];
1703	u_char reg10 = (sc->elantech->fw_version == 0x20030 ? 0x54 : 0xc4);
1704
1705	/* Enable absolute mode. Magic numbers from Linux driver. */
1706	if (elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
1707	    elantech_ps2_cmd(sc, ELANTECH_CMD_WRITE_REG) ||
1708	    elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
1709	    elantech_ps2_cmd(sc, 0x10) ||
1710	    elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
1711	    elantech_ps2_cmd(sc, reg10) ||
1712	    pms_set_scaling(sc, 1) ||
1713	    elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
1714	    elantech_ps2_cmd(sc, ELANTECH_CMD_WRITE_REG) ||
1715	    elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
1716	    elantech_ps2_cmd(sc, 0x11) ||
1717	    elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
1718	    elantech_ps2_cmd(sc, 0x88) ||
1719	    pms_set_scaling(sc, 1))
1720		return (-1);
1721
1722	/* Read back reg 0x10 to ensure hardware is ready. */
1723	for (i = 0; i < 5; i++) {
1724		if (elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
1725		    elantech_ps2_cmd(sc, ELANTECH_CMD_READ_REG) ||
1726		    elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
1727		    elantech_ps2_cmd(sc, 0x10) ||
1728		    pms_get_status(sc, resp) == 0)
1729			break;
1730		delay(2000);
1731	}
1732	if (i == 5)
1733		return (-1);
1734
1735	return (0);
1736}
1737
1738int
1739elantech_set_absolute_mode_v3(struct pms_softc *sc)
1740{
1741	int i;
1742	u_char resp[3];
1743
1744	/* Enable absolute mode. Magic numbers from Linux driver. */
1745	if (elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
1746	    elantech_ps2_cmd(sc, ELANTECH_CMD_READ_WRITE_REG) ||
1747	    elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
1748	    elantech_ps2_cmd(sc, 0x10) ||
1749	    elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
1750	    elantech_ps2_cmd(sc, 0x0b) ||
1751	    pms_set_scaling(sc, 1))
1752		return (-1);
1753
1754	/* Read back reg 0x10 to ensure hardware is ready. */
1755	for (i = 0; i < 5; i++) {
1756		if (elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
1757		    elantech_ps2_cmd(sc, ELANTECH_CMD_READ_WRITE_REG) ||
1758		    elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
1759		    elantech_ps2_cmd(sc, 0x10) ||
1760		    pms_get_status(sc, resp) == 0)
1761			break;
1762		delay(2000);
1763	}
1764	if (i == 5)
1765		return (-1);
1766
1767	return (0);
1768}
1769
1770int
1771elantech_set_absolute_mode_v4(struct pms_softc *sc)
1772{
1773	/* Enable absolute mode. Magic numbers from Linux driver. */
1774	if (elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
1775	    elantech_ps2_cmd(sc, ELANTECH_CMD_READ_WRITE_REG) ||
1776	    elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
1777	    elantech_ps2_cmd(sc, 0x07) ||
1778	    elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
1779	    elantech_ps2_cmd(sc, ELANTECH_CMD_READ_WRITE_REG) ||
1780	    elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) ||
1781	    elantech_ps2_cmd(sc, 0x01) ||
1782	    pms_set_scaling(sc, 1))
1783		return (-1);
1784
1785	/* v4 has no register 0x10 to read response from */
1786
1787	return (0);
1788}
1789
1790int
1791elantech_get_hwinfo_v1(struct pms_softc *sc)
1792{
1793	struct elantech_softc *elantech = sc->elantech;
1794	struct wsmousehw *hw;
1795	int fw_version;
1796	u_char capabilities[3];
1797
1798	if (synaptics_query(sc, ELANTECH_QUE_FW_VER, &fw_version))
1799		return (-1);
1800
1801	if (fw_version < 0x20030 || fw_version == 0x20600) {
1802		if (fw_version < 0x20000)
1803			elantech->flags |= ELANTECH_F_HW_V1_OLD;
1804	} else
1805		return (-1);
1806
1807	elantech->fw_version = fw_version;
1808
1809	if (pms_spec_cmd(sc, ELANTECH_QUE_CAPABILITIES) ||
1810	    pms_get_status(sc, capabilities))
1811		return (-1);
1812
1813	if (capabilities[0] & ELANTECH_CAP_HAS_ROCKER)
1814		elantech->flags |= ELANTECH_F_HAS_ROCKER;
1815
1816	if (elantech_set_absolute_mode_v1(sc))
1817		return (-1);
1818
1819	hw = wsmouse_get_hw(sc->sc_wsmousedev);
1820	hw->type = WSMOUSE_TYPE_ELANTECH;
1821	hw->hw_type = WSMOUSEHW_TOUCHPAD;
1822	hw->x_min = ELANTECH_V1_X_MIN;
1823	hw->x_max = ELANTECH_V1_X_MAX;
1824	hw->y_min = ELANTECH_V1_Y_MIN;
1825	hw->y_max = ELANTECH_V1_Y_MAX;
1826
1827	return (0);
1828}
1829
1830int
1831elantech_get_hwinfo_v2(struct pms_softc *sc)
1832{
1833	struct elantech_softc *elantech = sc->elantech;
1834	struct wsmousehw *hw;
1835	int fw_version, ic_ver;
1836	u_char capabilities[3];
1837	int i, fixed_dpi;
1838	u_char resp[3];
1839
1840	if (synaptics_query(sc, ELANTECH_QUE_FW_VER, &fw_version))
1841		return (-1);
1842
1843	ic_ver = (fw_version & 0x0f0000) >> 16;
1844	if (ic_ver != 2 && ic_ver != 4)
1845		return (-1);
1846
1847	elantech->fw_version = fw_version;
1848	if (fw_version >= 0x20800)
1849		elantech->flags |= ELANTECH_F_REPORTS_PRESSURE;
1850
1851	if (pms_spec_cmd(sc, ELANTECH_QUE_CAPABILITIES) ||
1852	    pms_get_status(sc, capabilities))
1853		return (-1);
1854
1855	if (elantech_set_absolute_mode_v2(sc))
1856		return (-1);
1857
1858	hw = wsmouse_get_hw(sc->sc_wsmousedev);
1859	hw->type = WSMOUSE_TYPE_ELANTECH;
1860	hw->hw_type = WSMOUSEHW_TOUCHPAD;
1861
1862	if (fw_version == 0x20800 || fw_version == 0x20b00 ||
1863	    fw_version == 0x20030) {
1864		hw->x_max = ELANTECH_V2_X_MAX;
1865		hw->y_max = ELANTECH_V2_Y_MAX;
1866	} else {
1867		if (pms_spec_cmd(sc, ELANTECH_QUE_FW_ID) ||
1868		    pms_get_status(sc, resp))
1869			return (-1);
1870		fixed_dpi = resp[1] & 0x10;
1871		i = (fw_version > 0x20800 && fw_version < 0x20900) ? 1 : 2;
1872		if ((fw_version >> 16) == 0x14 && fixed_dpi) {
1873			if (pms_spec_cmd(sc, ELANTECH_QUE_SAMPLE) ||
1874			    pms_get_status(sc, resp))
1875				return (-1);
1876			hw->x_max = (capabilities[1] - i) * resp[1] / 2;
1877			hw->y_max = (capabilities[2] - i) * resp[2] / 2;
1878		} else if (fw_version == 0x040216) {
1879			hw->x_max = 819;
1880			hw->y_max = 405;
1881		} else if (fw_version == 0x040219 || fw_version == 0x040215) {
1882			hw->x_max = 900;
1883			hw->y_max = 500;
1884		} else {
1885			hw->x_max = (capabilities[1] - i) * 64;
1886			hw->y_max = (capabilities[2] - i) * 64;
1887		}
1888	}
1889
1890	return (0);
1891}
1892
1893int
1894elantech_get_hwinfo_v3(struct pms_softc *sc)
1895{
1896	struct elantech_softc *elantech = sc->elantech;
1897	struct wsmousehw *hw;
1898	int fw_version;
1899	u_char resp[3];
1900
1901	if (synaptics_query(sc, ELANTECH_QUE_FW_VER, &fw_version))
1902		return (-1);
1903
1904	if (((fw_version & 0x0f0000) >> 16) != 5)
1905		return (-1);
1906
1907	elantech->fw_version = fw_version;
1908	elantech->flags |= ELANTECH_F_REPORTS_PRESSURE;
1909
1910	if ((fw_version & 0x4000) == 0x4000)
1911		elantech->flags |= ELANTECH_F_CRC_ENABLED;
1912
1913	if (elantech_set_absolute_mode_v3(sc))
1914		return (-1);
1915
1916	if (pms_spec_cmd(sc, ELANTECH_QUE_FW_ID) ||
1917	    pms_get_status(sc, resp))
1918		return (-1);
1919
1920	hw = wsmouse_get_hw(sc->sc_wsmousedev);
1921	hw->x_max = elantech->max_x = (resp[0] & 0x0f) << 8 | resp[1];
1922	hw->y_max = elantech->max_y = (resp[0] & 0xf0) << 4 | resp[2];
1923
1924	hw->type = WSMOUSE_TYPE_ELANTECH;
1925	hw->hw_type = WSMOUSEHW_TOUCHPAD;
1926
1927	return (0);
1928}
1929
1930int
1931elantech_get_hwinfo_v4(struct pms_softc *sc)
1932{
1933	struct elantech_softc *elantech = sc->elantech;
1934	struct wsmousehw *hw;
1935	int fw_version;
1936	u_char capabilities[3];
1937	u_char resp[3];
1938
1939	if (synaptics_query(sc, ELANTECH_QUE_FW_VER, &fw_version))
1940		return (-1);
1941
1942	if ((fw_version & 0x0f0000) >> 16 != 6
1943	    && (fw_version & 0x0f0000) >> 16 != 8
1944	    && (fw_version & 0x0f0000) >> 16 != 15)
1945		return (-1);
1946
1947	elantech->fw_version = fw_version;
1948	elantech->flags |= ELANTECH_F_REPORTS_PRESSURE;
1949
1950	if (elantech_set_absolute_mode_v4(sc))
1951		return (-1);
1952
1953	if (pms_spec_cmd(sc, ELANTECH_QUE_CAPABILITIES) ||
1954	    pms_get_status(sc, capabilities))
1955		return (-1);
1956
1957	if (pms_spec_cmd(sc, ELANTECH_QUE_FW_ID) ||
1958	    pms_get_status(sc, resp))
1959		return (-1);
1960
1961	hw = wsmouse_get_hw(sc->sc_wsmousedev);
1962	hw->x_max = (resp[0] & 0x0f) << 8 | resp[1];
1963	hw->y_max = (resp[0] & 0xf0) << 4 | resp[2];
1964
1965	if ((capabilities[1] < 2) || (capabilities[1] > hw->x_max))
1966		return (-1);
1967
1968	if (capabilities[0] & ELANTECH_CAP_TRACKPOINT)
1969		elantech->flags |= ELANTECH_F_TRACKPOINT;
1970
1971	hw->type = WSMOUSE_TYPE_ELANTECH;
1972	hw->hw_type = WSMOUSEHW_CLICKPAD;
1973	hw->mt_slots = ELANTECH_MAX_FINGERS;
1974
1975	elantech->width = hw->x_max / (capabilities[1] - 1);
1976
1977	return (0);
1978}
1979
1980int
1981elantech_ps2_cmd(struct pms_softc *sc, u_char command)
1982{
1983	u_char cmd[1];
1984
1985	cmd[0] = command;
1986	return (pms_cmd(sc, cmd, 1, NULL, 0));
1987}
1988
1989int
1990elantech_knock(struct pms_softc *sc)
1991{
1992	u_char resp[3];
1993
1994	if (pms_dev_disable(sc) ||
1995	    pms_set_scaling(sc, 1) ||
1996	    pms_set_scaling(sc, 1) ||
1997	    pms_set_scaling(sc, 1) ||
1998	    pms_get_status(sc, resp) ||
1999	    resp[0] != PMS_ELANTECH_MAGIC1 ||
2000	    resp[1] != PMS_ELANTECH_MAGIC2 ||
2001	    (resp[2] != PMS_ELANTECH_MAGIC3_1 &&
2002	    resp[2] != PMS_ELANTECH_MAGIC3_2))
2003		return (-1);
2004
2005	return (0);
2006}
2007
2008int
2009pms_enable_elantech_v1(struct pms_softc *sc)
2010{
2011	struct elantech_softc *elantech = sc->elantech;
2012	int i;
2013
2014	if (elantech_knock(sc))
2015		goto err;
2016
2017	if (sc->elantech == NULL) {
2018		sc->elantech = elantech = malloc(sizeof(struct elantech_softc),
2019		    M_DEVBUF, M_WAITOK | M_ZERO);
2020		if (elantech == NULL) {
2021			printf("%s: elantech: not enough memory\n",
2022			    DEVNAME(sc));
2023			goto err;
2024		}
2025
2026		if (elantech_get_hwinfo_v1(sc)) {
2027			free(sc->elantech, M_DEVBUF,
2028			    sizeof(struct elantech_softc));
2029			sc->elantech = NULL;
2030			goto err;
2031		}
2032		if (wsmouse_configure(sc->sc_wsmousedev, NULL, 0)) {
2033			free(sc->elantech, M_DEVBUF,
2034			    sizeof(struct elantech_softc));
2035			sc->elantech = NULL;
2036			printf("%s: elantech: setup failed\n", DEVNAME(sc));
2037			goto err;
2038		}
2039
2040		printf("%s: Elantech Touchpad, version %d, firmware 0x%x\n",
2041		    DEVNAME(sc), 1, sc->elantech->fw_version);
2042	} else if (elantech_set_absolute_mode_v1(sc))
2043		goto err;
2044
2045	for (i = 0; i < nitems(sc->elantech->parity); i++)
2046		sc->elantech->parity[i] = sc->elantech->parity[i & (i - 1)] ^ 1;
2047
2048	return (1);
2049
2050err:
2051	pms_reset(sc);
2052
2053	return (0);
2054}
2055
2056int
2057pms_enable_elantech_v2(struct pms_softc *sc)
2058{
2059	struct elantech_softc *elantech = sc->elantech;
2060
2061	if (elantech_knock(sc))
2062		goto err;
2063
2064	if (sc->elantech == NULL) {
2065		sc->elantech = elantech = malloc(sizeof(struct elantech_softc),
2066		    M_DEVBUF, M_WAITOK | M_ZERO);
2067		if (elantech == NULL) {
2068			printf("%s: elantech: not enough memory\n",
2069			    DEVNAME(sc));
2070			goto err;
2071		}
2072
2073		if (elantech_get_hwinfo_v2(sc)) {
2074			free(sc->elantech, M_DEVBUF,
2075			    sizeof(struct elantech_softc));
2076			sc->elantech = NULL;
2077			goto err;
2078		}
2079		if (wsmouse_configure(sc->sc_wsmousedev, NULL, 0)) {
2080			free(sc->elantech, M_DEVBUF,
2081			    sizeof(struct elantech_softc));
2082			sc->elantech = NULL;
2083			printf("%s: elantech: setup failed\n", DEVNAME(sc));
2084			goto err;
2085		}
2086
2087		printf("%s: Elantech Touchpad, version %d, firmware 0x%x\n",
2088		    DEVNAME(sc), 2, sc->elantech->fw_version);
2089	} else if (elantech_set_absolute_mode_v2(sc))
2090		goto err;
2091
2092	return (1);
2093
2094err:
2095	pms_reset(sc);
2096
2097	return (0);
2098}
2099
2100int
2101pms_enable_elantech_v3(struct pms_softc *sc)
2102{
2103	struct elantech_softc *elantech = sc->elantech;
2104
2105	if (elantech_knock(sc))
2106		goto err;
2107
2108	if (sc->elantech == NULL) {
2109		sc->elantech = elantech = malloc(sizeof(struct elantech_softc),
2110		    M_DEVBUF, M_WAITOK | M_ZERO);
2111		if (elantech == NULL) {
2112			printf("%s: elantech: not enough memory\n",
2113			    DEVNAME(sc));
2114			goto err;
2115		}
2116
2117		if (elantech_get_hwinfo_v3(sc)) {
2118			free(sc->elantech, M_DEVBUF,
2119			    sizeof(struct elantech_softc));
2120			sc->elantech = NULL;
2121			goto err;
2122		}
2123		if (wsmouse_configure(sc->sc_wsmousedev, NULL, 0)) {
2124			free(sc->elantech, M_DEVBUF,
2125			    sizeof(struct elantech_softc));
2126			sc->elantech = NULL;
2127			printf("%s: elantech: setup failed\n", DEVNAME(sc));
2128			goto err;
2129		}
2130
2131		printf("%s: Elantech Touchpad, version %d, firmware 0x%x\n",
2132		    DEVNAME(sc), 3, sc->elantech->fw_version);
2133	} else if (elantech_set_absolute_mode_v3(sc))
2134		goto err;
2135
2136	return (1);
2137
2138err:
2139	pms_reset(sc);
2140
2141	return (0);
2142}
2143
2144int
2145pms_enable_elantech_v4(struct pms_softc *sc)
2146{
2147	struct elantech_softc *elantech = sc->elantech;
2148	struct wsmousedev_attach_args a;
2149
2150	if (elantech_knock(sc))
2151		goto err;
2152
2153	if (sc->elantech == NULL) {
2154		sc->elantech = elantech = malloc(sizeof(struct elantech_softc),
2155		    M_DEVBUF, M_WAITOK | M_ZERO);
2156		if (elantech == NULL) {
2157			printf("%s: elantech: not enough memory\n",
2158			    DEVNAME(sc));
2159			goto err;
2160		}
2161
2162		if (elantech_get_hwinfo_v4(sc)) {
2163			free(sc->elantech, M_DEVBUF,
2164			    sizeof(struct elantech_softc));
2165			sc->elantech = NULL;
2166			goto err;
2167		}
2168		if (wsmouse_configure(sc->sc_wsmousedev, NULL, 0)) {
2169			free(sc->elantech, M_DEVBUF,
2170			    sizeof(struct elantech_softc));
2171			sc->elantech = NULL;
2172			printf("%s: elantech: setup failed\n", DEVNAME(sc));
2173			goto err;
2174		}
2175
2176		printf("%s: Elantech Clickpad, version %d, firmware 0x%x\n",
2177		    DEVNAME(sc), 4, sc->elantech->fw_version);
2178
2179		if (sc->elantech->flags & ELANTECH_F_TRACKPOINT) {
2180			a.accessops = &pms_sec_accessops;
2181			a.accesscookie = sc;
2182			sc->sc_sec_wsmousedev = config_found((void *) sc, &a,
2183			    wsmousedevprint);
2184		}
2185
2186	} else if (elantech_set_absolute_mode_v4(sc))
2187		goto err;
2188
2189	return (1);
2190
2191err:
2192	pms_reset(sc);
2193
2194	return (0);
2195}
2196
2197int
2198pms_ioctl_elantech(struct pms_softc *sc, u_long cmd, caddr_t data, int flag,
2199    struct proc *p)
2200{
2201	struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data;
2202	struct wsmousehw *hw;
2203	int wsmode;
2204
2205	switch (cmd) {
2206	case WSMOUSEIO_GTYPE:
2207		*(u_int *)data = WSMOUSE_TYPE_ELANTECH;
2208		break;
2209	case WSMOUSEIO_GCALIBCOORDS:
2210		hw = wsmouse_get_hw(sc->sc_wsmousedev);
2211		wsmc->minx = hw->x_min;
2212		wsmc->maxx = hw->x_max;
2213		wsmc->miny = hw->y_min;
2214		wsmc->maxy = hw->y_max;
2215		wsmc->swapxy = 0;
2216		wsmc->resx = hw->h_res;
2217		wsmc->resy = hw->v_res;
2218		break;
2219	case WSMOUSEIO_SETMODE:
2220		wsmode = *(u_int *)data;
2221		if (wsmode != WSMOUSE_COMPAT && wsmode != WSMOUSE_NATIVE)
2222			return (EINVAL);
2223		wsmouse_set_mode(sc->sc_wsmousedev, wsmode);
2224		break;
2225	default:
2226		return (-1);
2227	}
2228	return (0);
2229}
2230
2231int
2232pms_sync_elantech_v1(struct pms_softc *sc, int data)
2233{
2234	struct elantech_softc *elantech = sc->elantech;
2235	u_char p;
2236
2237	switch (sc->inputstate) {
2238	case 0:
2239		if (elantech->flags & ELANTECH_F_HW_V1_OLD) {
2240			elantech->p1 = (data & 0x20) >> 5;
2241			elantech->p2 = (data & 0x10) >> 4;
2242		} else {
2243			elantech->p1 = (data & 0x10) >> 4;
2244			elantech->p2 = (data & 0x20) >> 5;
2245		}
2246		elantech->p3 = (data & 0x04) >> 2;
2247		return (0);
2248	case 1:
2249		p = elantech->p1;
2250		break;
2251	case 2:
2252		p = elantech->p2;
2253		break;
2254	case 3:
2255		p = elantech->p3;
2256		break;
2257	default:
2258		return (-1);
2259	}
2260
2261	if (data < 0 || data >= nitems(elantech->parity) ||
2262	    elantech->parity[data] != p)
2263		return (-1);
2264
2265	return (0);
2266}
2267
2268int
2269pms_sync_elantech_v2(struct pms_softc *sc, int data)
2270{
2271	struct elantech_softc *elantech = sc->elantech;
2272
2273	/* Variants reporting pressure always have the same constant bits. */
2274	if (elantech->flags & ELANTECH_F_REPORTS_PRESSURE) {
2275		if (sc->inputstate == 0 && (data & 0x0c) != 0x04)
2276			return (-1);
2277		if (sc->inputstate == 3 && (data & 0x0f) != 0x02)
2278			return (-1);
2279		return (0);
2280	}
2281
2282	/* For variants not reporting pressure, 1 and 3 finger touch packets
2283	 * have different constant bits than 2 finger touch packets. */
2284	switch (sc->inputstate) {
2285	case 0:
2286		if ((data & 0xc0) == 0x80) {
2287			if ((data & 0x0c) != 0x0c)
2288				return (-1);
2289			elantech->flags |= ELANTECH_F_2FINGER_PACKET;
2290		} else {
2291			if ((data & 0x3c) != 0x3c)
2292				return (-1);
2293			elantech->flags &= ~ELANTECH_F_2FINGER_PACKET;
2294		}
2295		break;
2296	case 1:
2297	case 4:
2298		if (elantech->flags & ELANTECH_F_2FINGER_PACKET)
2299			break;
2300		if ((data & 0xf0) != 0x00)
2301			return (-1);
2302		break;
2303	case 3:
2304		if (elantech->flags & ELANTECH_F_2FINGER_PACKET) {
2305			if ((data & 0x0e) != 0x08)
2306				return (-1);
2307		} else {
2308			if ((data & 0x3e) != 0x38)
2309				return (-1);
2310		}
2311		break;
2312	default:
2313		break;
2314	}
2315
2316	return (0);
2317}
2318
2319int
2320pms_sync_elantech_v3(struct pms_softc *sc, int data)
2321{
2322	struct elantech_softc *elantech = sc->elantech;
2323
2324	switch (sc->inputstate) {
2325	case 0:
2326		if (elantech->flags & ELANTECH_F_CRC_ENABLED)
2327			break;
2328		if ((data & 0x0c) != 0x04 && (data & 0x0c) != 0x0c)
2329			return (-1);
2330		break;
2331	case 3:
2332		if (elantech->flags & ELANTECH_F_CRC_ENABLED) {
2333			if ((data & 0x09) != 0x08 && (data & 0x09) != 0x09)
2334				return (-1);
2335		} else {
2336			if ((data & 0xcf) != 0x02 && (data & 0xce) != 0x0c)
2337				return (-1);
2338		}
2339		break;
2340	}
2341
2342	return (0);
2343}
2344
2345/* Extract the type bits from packet[3]. */
2346static inline int
2347elantech_packet_type(u_char b)
2348{
2349	return ((b & 4) ? (b & 0xcf) : (b & 0x1f));
2350}
2351
2352int
2353pms_sync_elantech_v4(struct pms_softc *sc, int data)
2354{
2355	if (sc->inputstate == 0) {
2356		if ((data & 0x0c) == 0x04)
2357			return (0);
2358		if ((sc->elantech->flags & ELANTECH_F_TRACKPOINT)
2359		    && (data & 0xc8) == 0)
2360			return (0);
2361		return (-1);
2362	}
2363	if (sc->inputstate == 3) {
2364		switch (elantech_packet_type(data)) {
2365		case ELANTECH_V4_PKT_STATUS:
2366		case ELANTECH_V4_PKT_HEAD:
2367		case ELANTECH_V4_PKT_MOTION:
2368			return ((sc->packet[0] & 4) ? 0 : -1);
2369		case ELANTECH_PKT_TRACKPOINT:
2370			return ((sc->packet[0] & 0xc8) == 0
2371			    && sc->packet[1] == ((data & 0x10) << 3)
2372			    && sc->packet[2] == ((data & 0x20) << 2)
2373			    && (data ^ (sc->packet[0] & 0x30)) == 0x36
2374			    ? 0 : -1);
2375		}
2376		return (-1);
2377	}
2378	return (0);
2379}
2380
2381void
2382pms_proc_elantech_v1(struct pms_softc *sc)
2383{
2384	struct elantech_softc *elantech = sc->elantech;
2385	int x, y, w, z;
2386	u_int buttons;
2387
2388	buttons = butmap[sc->packet[0] & 3];
2389
2390	if (elantech->flags & ELANTECH_F_HAS_ROCKER) {
2391		if (sc->packet[0] & 0x40) /* up */
2392			buttons |= WSMOUSE_BUTTON(4);
2393		if (sc->packet[0] & 0x80) /* down */
2394			buttons |= WSMOUSE_BUTTON(5);
2395	}
2396
2397	if (elantech->flags & ELANTECH_F_HW_V1_OLD)
2398		w = ((sc->packet[1] & 0x80) >> 7) +
2399		    ((sc->packet[1] & 0x30) >> 4);
2400	else
2401		w = (sc->packet[0] & 0xc0) >> 6;
2402
2403	/* Hardware version 1 doesn't report pressure. */
2404	if (w) {
2405		x = ((sc->packet[1] & 0x0c) << 6) | sc->packet[2];
2406		y = ((sc->packet[1] & 0x03) << 8) | sc->packet[3];
2407		z = SYNAPTICS_PRESSURE;
2408	} else {
2409		x = elantech->old_x;
2410		y = elantech->old_y;
2411		z = 0;
2412	}
2413
2414	WSMOUSE_TOUCH(sc->sc_wsmousedev, buttons, x, y, z, w);
2415}
2416
2417void
2418pms_proc_elantech_v2(struct pms_softc *sc)
2419{
2420	const u_char debounce_pkt[] = { 0x84, 0xff, 0xff, 0x02, 0xff, 0xff };
2421	struct elantech_softc *elantech = sc->elantech;
2422	int x, y, w, z;
2423	u_int buttons;
2424
2425	/*
2426	 * The hardware sends this packet when in debounce state.
2427	 * The packet should be ignored.
2428	 */
2429	if (!memcmp(sc->packet, debounce_pkt, sizeof(debounce_pkt)))
2430		return;
2431
2432	buttons = butmap[sc->packet[0] & 3];
2433
2434	w = (sc->packet[0] & 0xc0) >> 6;
2435	if (w == 1 || w == 3) {
2436		x = ((sc->packet[1] & 0x0f) << 8) | sc->packet[2];
2437		y = ((sc->packet[4] & 0x0f) << 8) | sc->packet[5];
2438		if (elantech->flags & ELANTECH_F_REPORTS_PRESSURE)
2439			z = ((sc->packet[1] & 0xf0) |
2440			    (sc->packet[4] & 0xf0) >> 4);
2441		else
2442			z = SYNAPTICS_PRESSURE;
2443	} else if (w == 2) {
2444		x = (((sc->packet[0] & 0x10) << 4) | sc->packet[1]) << 2;
2445		y = (((sc->packet[0] & 0x20) << 3) | sc->packet[2]) << 2;
2446		z = SYNAPTICS_PRESSURE;
2447	} else {
2448		x = elantech->old_x;
2449		y = elantech->old_y;
2450		z = 0;
2451	}
2452
2453	WSMOUSE_TOUCH(sc->sc_wsmousedev, buttons, x, y, z, w);
2454}
2455
2456void
2457pms_proc_elantech_v3(struct pms_softc *sc)
2458{
2459	const u_char debounce_pkt[] = { 0xc4, 0xff, 0xff, 0x02, 0xff, 0xff };
2460	struct elantech_softc *elantech = sc->elantech;
2461	int x, y, w, z;
2462	u_int buttons;
2463
2464	buttons = butmap[sc->packet[0] & 3];
2465
2466	x = ((sc->packet[1] & 0x0f) << 8 | sc->packet[2]);
2467	y = ((sc->packet[4] & 0x0f) << 8 | sc->packet[5]);
2468	z = 0;
2469	w = (sc->packet[0] & 0xc0) >> 6;
2470	if (w == 2) {
2471		/*
2472		 * Two-finger touch causes two packets -- a head packet
2473		 * and a tail packet. We report a single event and ignore
2474		 * the tail packet.
2475		 */
2476		if (elantech->flags & ELANTECH_F_CRC_ENABLED) {
2477			if ((sc->packet[3] & 0x09) != 0x08)
2478				return;
2479		} else {
2480			/* The hardware sends this packet when in debounce state.
2481	 		 * The packet should be ignored. */
2482			if (!memcmp(sc->packet, debounce_pkt, sizeof(debounce_pkt)))
2483				return;
2484			if ((sc->packet[0] & 0x0c) != 0x04 &&
2485	    		(sc->packet[3] & 0xcf) != 0x02) {
2486				/* not the head packet -- ignore */
2487				return;
2488			}
2489		}
2490	}
2491
2492	/* Prevent jumping cursor if pad isn't touched or reports garbage. */
2493	if (w == 0 ||
2494	    ((x == 0 || y == 0 || x == elantech->max_x || y == elantech->max_y)
2495	    && (x != elantech->old_x || y != elantech->old_y))) {
2496		x = elantech->old_x;
2497		y = elantech->old_y;
2498	}
2499
2500	if (elantech->flags & ELANTECH_F_REPORTS_PRESSURE)
2501		z = (sc->packet[1] & 0xf0) | ((sc->packet[4] & 0xf0) >> 4);
2502	else if (w)
2503		z = SYNAPTICS_PRESSURE;
2504
2505	WSMOUSE_TOUCH(sc->sc_wsmousedev, buttons, x, y, z, w);
2506	elantech->old_x = x;
2507	elantech->old_y = y;
2508}
2509
2510void
2511pms_proc_elantech_v4(struct pms_softc *sc)
2512{
2513	struct elantech_softc *elantech = sc->elantech;
2514	struct device *sc_wsmousedev = sc->sc_wsmousedev;
2515	int id, weight, n, x, y, z;
2516	u_int buttons, slots;
2517
2518	switch (elantech_packet_type(sc->packet[3])) {
2519	case ELANTECH_V4_PKT_STATUS:
2520		slots = elantech->mt_slots;
2521		elantech->mt_slots = sc->packet[1] & 0x1f;
2522		slots &= ~elantech->mt_slots;
2523		for (id = 0; slots; id++, slots >>= 1) {
2524			if (slots & 1)
2525				wsmouse_mtstate(sc_wsmousedev, id, 0, 0, 0);
2526		}
2527		break;
2528
2529	case ELANTECH_V4_PKT_HEAD:
2530		id = ((sc->packet[3] & 0xe0) >> 5) - 1;
2531		if (id > -1 && id < ELANTECH_MAX_FINGERS) {
2532			x = ((sc->packet[1] & 0x0f) << 8) | sc->packet[2];
2533			y = ((sc->packet[4] & 0x0f) << 8) | sc->packet[5];
2534			z = (sc->packet[1] & 0xf0)
2535			    | ((sc->packet[4] & 0xf0) >> 4);
2536			wsmouse_mtstate(sc_wsmousedev, id, x, y, z);
2537		}
2538		break;
2539
2540	case ELANTECH_V4_PKT_MOTION:
2541		weight = (sc->packet[0] & 0x10) ? ELANTECH_V4_WEIGHT_VALUE : 1;
2542		for (n = 0; n < 6; n += 3) {
2543			id = ((sc->packet[n] & 0xe0) >> 5) - 1;
2544			if (id < 0 || id >= ELANTECH_MAX_FINGERS)
2545				continue;
2546			x = weight * (signed char)sc->packet[n + 1];
2547			y = weight * (signed char)sc->packet[n + 2];
2548			z = WSMOUSE_DEFAULT_PRESSURE;
2549			wsmouse_set(sc_wsmousedev, WSMOUSE_MT_REL_X, x, id);
2550			wsmouse_set(sc_wsmousedev, WSMOUSE_MT_REL_Y, y, id);
2551			wsmouse_set(sc_wsmousedev, WSMOUSE_MT_PRESSURE, z, id);
2552		}
2553		break;
2554
2555	case ELANTECH_PKT_TRACKPOINT:
2556		if (sc->sc_dev_enable & PMS_DEV_SECONDARY) {
2557			x = sc->packet[4] - 0x100 + (sc->packet[1] << 1);
2558			y = sc->packet[5] - 0x100 + (sc->packet[2] << 1);
2559			buttons = butmap[sc->packet[0] & 7];
2560			WSMOUSE_INPUT(sc->sc_sec_wsmousedev,
2561			    buttons, x, y, 0, 0);
2562		}
2563		return;
2564
2565	default:
2566		printf("%s: unknown packet type 0x%x\n", DEVNAME(sc),
2567		    sc->packet[3] & 0x1f);
2568		return;
2569	}
2570
2571	buttons = butmap[sc->packet[0] & 3];
2572	wsmouse_buttons(sc_wsmousedev, buttons);
2573
2574	wsmouse_input_sync(sc_wsmousedev);
2575}
2576