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