xref: /openbsd/sys/dev/pckbc/pms.c (revision 4bdff4be)
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
50 extern int mouse_has_softbtn;
51 #else
52 int 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 
65 struct pms_softc;
66 
67 struct 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 
85 struct 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 
108 struct 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 
126 struct 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 
149 struct 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 
186 static 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 
197 static 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 
235 static struct wsmouse_param synaptics_params[] = {
236 	{ WSMOUSECFG_PRESSURE_LO, SYNAPTICS_PRESSURE_LO },
237 	{ WSMOUSECFG_PRESSURE_HI, SYNAPTICS_PRESSURE_HI }
238 };
239 
240 static struct wsmouse_param alps_params[] = {
241 	{ WSMOUSECFG_SMOOTHING, 3 }
242 };
243 
244 int	pmsprobe(struct device *, void *, void *);
245 void	pmsattach(struct device *, struct device *, void *);
246 int	pmsactivate(struct device *, int);
247 
248 void	pmsinput(void *, int);
249 
250 int	pms_change_state(struct pms_softc *, int, int);
251 
252 int	pms_ioctl(void *, u_long, caddr_t, int, struct proc *);
253 int	pms_enable(void *);
254 void	pms_disable(void *);
255 
256 int	pms_sec_ioctl(void *, u_long, caddr_t, int, struct proc *);
257 int	pms_sec_enable(void *);
258 void	pms_sec_disable(void *);
259 
260 int	pms_cmd(struct pms_softc *, u_char *, int, u_char *, int);
261 int	pms_spec_cmd(struct pms_softc *, int);
262 int	pms_get_devid(struct pms_softc *, u_char *);
263 int	pms_get_status(struct pms_softc *, u_char *);
264 int	pms_set_rate(struct pms_softc *, int);
265 int	pms_set_resolution(struct pms_softc *, int);
266 int	pms_set_scaling(struct pms_softc *, int);
267 int	pms_reset(struct pms_softc *);
268 int	pms_dev_enable(struct pms_softc *);
269 int	pms_dev_disable(struct pms_softc *);
270 void	pms_protocol_lookup(struct pms_softc *);
271 void	pms_reset_detect(struct pms_softc *, int);
272 void	pms_reset_task(void *);
273 void	pms_reset_timo(void *);
274 
275 int	pms_enable_intelli(struct pms_softc *);
276 
277 int	pms_ioctl_mouse(struct pms_softc *, u_long, caddr_t, int, struct proc *);
278 int	pms_sync_mouse(struct pms_softc *, int);
279 void	pms_proc_mouse(struct pms_softc *);
280 
281 int	pms_enable_synaptics(struct pms_softc *);
282 int	pms_ioctl_synaptics(struct pms_softc *, u_long, caddr_t, int, struct proc *);
283 int	pms_sync_synaptics(struct pms_softc *, int);
284 void	pms_proc_synaptics(struct pms_softc *);
285 void	pms_disable_synaptics(struct pms_softc *);
286 
287 int	pms_enable_alps(struct pms_softc *);
288 int	pms_ioctl_alps(struct pms_softc *, u_long, caddr_t, int, struct proc *);
289 int	pms_sync_alps(struct pms_softc *, int);
290 void	pms_proc_alps(struct pms_softc *);
291 
292 int	pms_enable_elantech_v1(struct pms_softc *);
293 int	pms_enable_elantech_v2(struct pms_softc *);
294 int	pms_enable_elantech_v3(struct pms_softc *);
295 int	pms_enable_elantech_v4(struct pms_softc *);
296 int	pms_ioctl_elantech(struct pms_softc *, u_long, caddr_t, int,
297     struct proc *);
298 int	pms_sync_elantech_v1(struct pms_softc *, int);
299 int	pms_sync_elantech_v2(struct pms_softc *, int);
300 int	pms_sync_elantech_v3(struct pms_softc *, int);
301 int	pms_sync_elantech_v4(struct pms_softc *, int);
302 void	pms_proc_elantech_v1(struct pms_softc *);
303 void	pms_proc_elantech_v2(struct pms_softc *);
304 void	pms_proc_elantech_v3(struct pms_softc *);
305 void	pms_proc_elantech_v4(struct pms_softc *);
306 
307 int	synaptics_knock(struct pms_softc *);
308 int	synaptics_set_mode(struct pms_softc *, int, int);
309 int	synaptics_query(struct pms_softc *, int, int *);
310 int	synaptics_get_hwinfo(struct pms_softc *);
311 void	synaptics_sec_proc(struct pms_softc *);
312 
313 int	alps_sec_proc(struct pms_softc *);
314 int	alps_get_hwinfo(struct pms_softc *);
315 
316 int	elantech_knock(struct pms_softc *);
317 int	elantech_get_hwinfo_v1(struct pms_softc *);
318 int	elantech_get_hwinfo_v2(struct pms_softc *);
319 int	elantech_get_hwinfo_v3(struct pms_softc *);
320 int	elantech_get_hwinfo_v4(struct pms_softc *);
321 int	elantech_ps2_cmd(struct pms_softc *, u_char);
322 int	elantech_set_absolute_mode_v1(struct pms_softc *);
323 int	elantech_set_absolute_mode_v2(struct pms_softc *);
324 int	elantech_set_absolute_mode_v3(struct pms_softc *);
325 int	elantech_set_absolute_mode_v4(struct pms_softc *);
326 
327 const struct cfattach pms_ca = {
328 	sizeof(struct pms_softc), pmsprobe, pmsattach, NULL,
329 	pmsactivate
330 };
331 
332 struct cfdriver pms_cd = {
333 	NULL, "pms", DV_DULL
334 };
335 
336 const struct wsmouse_accessops pms_accessops = {
337 	pms_enable,
338 	pms_ioctl,
339 	pms_disable,
340 };
341 
342 const struct wsmouse_accessops pms_sec_accessops = {
343 	pms_sec_enable,
344 	pms_sec_ioctl,
345 	pms_sec_disable,
346 };
347 
348 const 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 
423 int
424 pms_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 
435 int
436 pms_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 
447 int
448 pms_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 
456 int
457 pms_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 
465 int
466 pms_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 
475 int
476 pms_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 
485 int
486 pms_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 
502 int
503 pms_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 
518 int
519 pms_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 
531 int
532 pms_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 
544 void
545 pms_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  */
566 void
567 pms_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 
586 void
587 pms_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 
603 void
604 pms_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 
627 int
628 pms_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 
643 int
644 pms_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 
670 int
671 pms_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 
690 void
691 pms_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 
710 int
711 pmsprobe(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 
737 void
738 pmsattach(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 
777 int
778 pmsactivate(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 
797 int
798 pms_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 
856 int
857 pms_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 
869 void
870 pms_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 
879 int
880 pms_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 
890 int
891 pms_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 
903 void
904 pms_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 
913 int
914 pms_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
927 static inline void
928 pms_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 
939 void
940 pmsinput(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 
973 int
974 synaptics_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 
994 int
995 synaptics_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 
1009 int
1010 synaptics_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 
1103 void
1104 synaptics_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 
1123 int
1124 synaptics_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 
1139 int
1140 pms_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 
1227 err:
1228 	pms_reset(sc);
1229 
1230 	return (0);
1231 }
1232 
1233 int
1234 pms_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 
1267 int
1268 pms_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 
1286 void
1287 pms_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 
1388 void
1389 pms_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 
1398 int
1399 alps_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 
1431 int
1432 alps_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 
1470 int
1471 pms_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 
1564 err:
1565 	pms_reset(sc);
1566 
1567 	return (0);
1568 }
1569 
1570 int
1571 pms_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 
1602 int
1603 pms_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 
1636 void
1637 pms_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 
1699 int
1700 elantech_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 
1733 int
1734 elantech_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 
1773 int
1774 elantech_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 
1805 int
1806 elantech_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 
1825 int
1826 elantech_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 
1865 int
1866 elantech_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 
1928 int
1929 elantech_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 
1965 int
1966 elantech_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 
2017 int
2018 elantech_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 
2026 int
2027 elantech_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 
2045 int
2046 pms_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 
2087 err:
2088 	pms_reset(sc);
2089 
2090 	return (0);
2091 }
2092 
2093 int
2094 pms_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 
2131 err:
2132 	pms_reset(sc);
2133 
2134 	return (0);
2135 }
2136 
2137 int
2138 pms_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 
2175 err:
2176 	pms_reset(sc);
2177 
2178 	return (0);
2179 }
2180 
2181 int
2182 pms_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 
2229 err:
2230 	pms_reset(sc);
2231 
2232 	return (0);
2233 }
2234 
2235 int
2236 pms_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 
2269 int
2270 pms_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 
2311 int
2312 pms_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 
2362 int
2363 pms_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]. */
2389 static inline int
2390 elantech_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 
2402 int
2403 pms_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 
2429 void
2430 pms_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 
2479 void
2480 pms_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 
2516 void
2517 pms_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 
2570 void
2571 pms_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