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