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