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