xref: /netbsd-src/sys/dev/adb/adb_ms.c (revision 48491f9819751125d121614a85f27fc971ad5fe6)
1*48491f98Sandvar /*	$NetBSD: adb_ms.c,v 1.22 2024/02/11 10:36:40 andvar Exp $	*/
2fcde3ac6Smacallan 
3fcde3ac6Smacallan /*
4fcde3ac6Smacallan  * Copyright (C) 1998	Colin Wood
556221938Smacallan  * Copyright (C) 2006, 2007 Michael Lorenz
6fcde3ac6Smacallan  * All rights reserved.
7fcde3ac6Smacallan  *
8fcde3ac6Smacallan  * Redistribution and use in source and binary forms, with or without
9fcde3ac6Smacallan  * modification, are permitted provided that the following conditions
10fcde3ac6Smacallan  * are met:
11fcde3ac6Smacallan  * 1. Redistributions of source code must retain the above copyright
12fcde3ac6Smacallan  *    notice, this list of conditions and the following disclaimer.
13fcde3ac6Smacallan  * 2. Redistributions in binary form must reproduce the above copyright
14fcde3ac6Smacallan  *    notice, this list of conditions and the following disclaimer in the
15fcde3ac6Smacallan  *    documentation and/or other materials provided with the distribution.
16fcde3ac6Smacallan  * 3. All advertising materials mentioning features or use of this software
17fcde3ac6Smacallan  *    must display the following acknowledgement:
18fcde3ac6Smacallan  *	This product includes software developed by Colin Wood.
19fcde3ac6Smacallan  * 4. The name of the author may not be used to endorse or promote products
20fcde3ac6Smacallan  *    derived from this software without specific prior written permission.
21fcde3ac6Smacallan  *
22fcde3ac6Smacallan  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23fcde3ac6Smacallan  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24fcde3ac6Smacallan  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25fcde3ac6Smacallan  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26fcde3ac6Smacallan  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27fcde3ac6Smacallan  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28fcde3ac6Smacallan  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29fcde3ac6Smacallan  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30fcde3ac6Smacallan  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31fcde3ac6Smacallan  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32fcde3ac6Smacallan  */
33fcde3ac6Smacallan 
34fcde3ac6Smacallan #include <sys/cdefs.h>
35*48491f98Sandvar __KERNEL_RCSID(0, "$NetBSD: adb_ms.c,v 1.22 2024/02/11 10:36:40 andvar Exp $");
36fcde3ac6Smacallan 
37fcde3ac6Smacallan #include <sys/param.h>
38fcde3ac6Smacallan #include <sys/device.h>
39fcde3ac6Smacallan #include <sys/fcntl.h>
40fcde3ac6Smacallan #include <sys/poll.h>
41fcde3ac6Smacallan #include <sys/select.h>
42fcde3ac6Smacallan #include <sys/proc.h>
43fcde3ac6Smacallan #include <sys/signalvar.h>
44fcde3ac6Smacallan #include <sys/systm.h>
45fcde3ac6Smacallan #include <sys/kernel.h>
46b184e0b1Stsutsui #include <sys/sysctl.h>
47fcde3ac6Smacallan 
48fcde3ac6Smacallan #include <machine/autoconf.h>
49fcde3ac6Smacallan 
50fcde3ac6Smacallan #include <dev/wscons/wsconsio.h>
51fcde3ac6Smacallan #include <dev/wscons/wsmousevar.h>
52fcde3ac6Smacallan 
53fcde3ac6Smacallan #include <machine/adbsys.h>
54fcde3ac6Smacallan #include <dev/adb/adbvar.h>
55fcde3ac6Smacallan 
56fcde3ac6Smacallan #include "adbdebug.h"
57fcde3ac6Smacallan 
58fcde3ac6Smacallan #ifdef ADBMS_DEBUG
59fcde3ac6Smacallan #define DPRINTF printf
60fcde3ac6Smacallan #else
61fcde3ac6Smacallan #define DPRINTF while (0) printf
62fcde3ac6Smacallan #endif
63fcde3ac6Smacallan 
64fcde3ac6Smacallan /*
65fcde3ac6Smacallan  * State info, per mouse instance.
66fcde3ac6Smacallan  */
67fcde3ac6Smacallan struct adbms_softc {
685d109a29Smatt 	device_t	sc_dev;
69fcde3ac6Smacallan 	struct adb_device *sc_adbdev;
70fcde3ac6Smacallan 	struct adb_bus_accessops *sc_ops;
71fcde3ac6Smacallan 
72fcde3ac6Smacallan 	/* Extended Mouse Protocol info, faked for non-EMP mice */
73fcde3ac6Smacallan 	u_int8_t	sc_class;	/* mouse class (mouse, trackball) */
74fcde3ac6Smacallan 	u_int8_t	sc_buttons;	/* number of buttons */
75fcde3ac6Smacallan 	u_int32_t	sc_res;		/* mouse resolution (dpi) */
76fcde3ac6Smacallan 	char		sc_devid[5];	/* device indentifier */
77fcde3ac6Smacallan 	uint8_t		sc_us;		/* cmd to watch for */
78fcde3ac6Smacallan 	int		sc_mb;		/* current button state */
79cbab9cadSchs 	device_t	sc_wsmousedev;
80fcde3ac6Smacallan 	/* helpers for trackpads */
81fcde3ac6Smacallan 	int		sc_down;
82fcde3ac6Smacallan 	/*
83fcde3ac6Smacallan 	 * trackpad protocol variant. Known so far:
84fcde3ac6Smacallan 	 * 2 buttons - PowerBook 3400, single events on button 3 and 4 indicate
85fcde3ac6Smacallan 	 *             finger down and up
86fcde3ac6Smacallan 	 * 4 buttons - iBook G4, button 6 indicates finger down, button 4 is
87fcde3ac6Smacallan 	 *             always down
88fcde3ac6Smacallan 	 */
89fcde3ac6Smacallan 	int		sc_x, sc_y;
90b184e0b1Stsutsui 	int		sc_tapping;
91fcde3ac6Smacallan 	/* buffers */
92fcde3ac6Smacallan 	int		sc_poll;
93fcde3ac6Smacallan 	int		sc_msg_len;
94fcde3ac6Smacallan 	int		sc_event;
95fcde3ac6Smacallan 	uint8_t		sc_buffer[16];
96fcde3ac6Smacallan };
97fcde3ac6Smacallan 
98fcde3ac6Smacallan /* EMP device classes */
99fcde3ac6Smacallan #define MSCLASS_TABLET		0
100fcde3ac6Smacallan #define MSCLASS_MOUSE		1
101fcde3ac6Smacallan #define MSCLASS_TRACKBALL	2
102fcde3ac6Smacallan #define MSCLASS_TRACKPAD	3
103fcde3ac6Smacallan 
104fcde3ac6Smacallan /*
105fcde3ac6Smacallan  * Function declarations.
106fcde3ac6Smacallan  */
1075d109a29Smatt static int	adbms_match(device_t, cfdata_t, void *);
1085d109a29Smatt static void	adbms_attach(device_t, device_t, void *);
109fcde3ac6Smacallan static void	ems_init(struct adbms_softc *);
110fcde3ac6Smacallan static void	init_trackpad(struct adbms_softc *);
111fcde3ac6Smacallan static void	adbms_init_mouse(struct adbms_softc *);
112fcde3ac6Smacallan static void	adbms_init_turbo(struct adbms_softc *);
113fcde3ac6Smacallan static void	adbms_init_uspeed(struct adbms_softc *);
114fcde3ac6Smacallan static void	adbms_process_event(struct adbms_softc *, int, uint8_t *);
115fcde3ac6Smacallan static int	adbms_send_sync(struct adbms_softc *, uint8_t, int, uint8_t *);
116fcde3ac6Smacallan 
117fcde3ac6Smacallan /* Driver definition. */
1185d109a29Smatt CFATTACH_DECL_NEW(adbms, sizeof(struct adbms_softc),
119fcde3ac6Smacallan     adbms_match, adbms_attach, NULL, NULL);
120fcde3ac6Smacallan 
121fcde3ac6Smacallan static int adbms_enable(void *);
12253524e44Schristos static int adbms_ioctl(void *, u_long, void *, int, struct lwp *);
123fcde3ac6Smacallan static void adbms_disable(void *);
124fcde3ac6Smacallan 
125fcde3ac6Smacallan /*
126fcde3ac6Smacallan  * handle tapping the trackpad
127fcde3ac6Smacallan  * different pads report different button counts and use slightly different
128fcde3ac6Smacallan  * protocols
129fcde3ac6Smacallan  */
130fcde3ac6Smacallan static void adbms_mangle_2(struct adbms_softc *, int);
131fcde3ac6Smacallan static void adbms_mangle_4(struct adbms_softc *, int);
132fcde3ac6Smacallan static void adbms_handler(void *, int, uint8_t *);
133fcde3ac6Smacallan static int  adbms_wait(struct adbms_softc *, int);
134b184e0b1Stsutsui static int  sysctl_adbms_tap(SYSCTLFN_ARGS);
135fcde3ac6Smacallan 
136fcde3ac6Smacallan const struct wsmouse_accessops adbms_accessops = {
137fcde3ac6Smacallan 	adbms_enable,
138fcde3ac6Smacallan 	adbms_ioctl,
139fcde3ac6Smacallan 	adbms_disable,
140fcde3ac6Smacallan };
141fcde3ac6Smacallan 
142fcde3ac6Smacallan static int
adbms_match(device_t parent,cfdata_t cf,void * aux)1435d109a29Smatt adbms_match(device_t parent, cfdata_t cf, void *aux)
144fcde3ac6Smacallan {
145fcde3ac6Smacallan 	struct adb_attach_args *aaa = aux;
146fcde3ac6Smacallan 
147fcde3ac6Smacallan 	if (aaa->dev->original_addr == ADBADDR_MS)
148fcde3ac6Smacallan 		return 1;
149fcde3ac6Smacallan 	else
150fcde3ac6Smacallan 		return 0;
151fcde3ac6Smacallan }
152fcde3ac6Smacallan 
153fcde3ac6Smacallan static void
adbms_attach(device_t parent,device_t self,void * aux)1545d109a29Smatt adbms_attach(device_t parent, device_t self, void *aux)
155fcde3ac6Smacallan {
1565d109a29Smatt 	struct adbms_softc *sc = device_private(self);
157fcde3ac6Smacallan 	struct adb_attach_args *aaa = aux;
158fcde3ac6Smacallan 	struct wsmousedev_attach_args a;
159fcde3ac6Smacallan 
1605d109a29Smatt 	sc->sc_dev = self;
161fcde3ac6Smacallan 	sc->sc_ops = aaa->ops;
162fcde3ac6Smacallan 	sc->sc_adbdev = aaa->dev;
163fcde3ac6Smacallan 	sc->sc_adbdev->cookie = sc;
164fcde3ac6Smacallan 	sc->sc_adbdev->handler = adbms_handler;
165fcde3ac6Smacallan 	sc->sc_us = ADBTALK(sc->sc_adbdev->current_addr, 0);
166d92688e1Smacallan 	printf(" addr %d: ", sc->sc_adbdev->current_addr);
167fcde3ac6Smacallan 
168fcde3ac6Smacallan 	sc->sc_class = MSCLASS_MOUSE;
169fcde3ac6Smacallan 	sc->sc_buttons = 1;
170fcde3ac6Smacallan 	sc->sc_res = 100;
171fcde3ac6Smacallan 	sc->sc_devid[0] = 0;
172fcde3ac6Smacallan 	sc->sc_devid[4] = 0;
173fcde3ac6Smacallan 	sc->sc_poll = 0;
174fcde3ac6Smacallan 	sc->sc_msg_len = 0;
175b184e0b1Stsutsui 	sc->sc_tapping = 1;
176fcde3ac6Smacallan 
177fcde3ac6Smacallan 	ems_init(sc);
178fcde3ac6Smacallan 
179fcde3ac6Smacallan 	/* print out the type of mouse we have */
180fcde3ac6Smacallan 	switch (sc->sc_adbdev->handler_id) {
181fcde3ac6Smacallan 	case ADBMS_100DPI:
182756a508cSchristos 		printf("%d-button, %u dpi mouse\n", sc->sc_buttons,
183756a508cSchristos 		    sc->sc_res);
184fcde3ac6Smacallan 		break;
185fcde3ac6Smacallan 	case ADBMS_200DPI:
186fcde3ac6Smacallan 		sc->sc_res = 200;
187756a508cSchristos 		printf("%d-button, %u dpi mouse\n", sc->sc_buttons,
188756a508cSchristos 		    sc->sc_res);
189fcde3ac6Smacallan 		break;
190fcde3ac6Smacallan 	case ADBMS_MSA3:
191756a508cSchristos 		printf("Mouse Systems A3 mouse, %d-button, %u dpi\n",
192756a508cSchristos 		    sc->sc_buttons, sc->sc_res);
193fcde3ac6Smacallan 		break;
194fcde3ac6Smacallan 	case ADBMS_USPEED:
195fcde3ac6Smacallan 		printf("MicroSpeed mouse, default parameters\n");
196fcde3ac6Smacallan 		break;
197fcde3ac6Smacallan 	case ADBMS_UCONTOUR:
198fcde3ac6Smacallan 		printf("Contour mouse, default parameters\n");
199fcde3ac6Smacallan 		break;
200fcde3ac6Smacallan 	case ADBMS_TURBO:
201fcde3ac6Smacallan 		printf("Kensington Turbo Mouse\n");
202fcde3ac6Smacallan 		break;
203fcde3ac6Smacallan 	case ADBMS_EXTENDED:
204fcde3ac6Smacallan 		if (sc->sc_devid[0] == '\0') {
205fcde3ac6Smacallan 			printf("Logitech ");
206fcde3ac6Smacallan 			switch (sc->sc_class) {
207fcde3ac6Smacallan 			case MSCLASS_MOUSE:
208fcde3ac6Smacallan 				printf("MouseMan (non-EMP) mouse");
209fcde3ac6Smacallan 				break;
210fcde3ac6Smacallan 			case MSCLASS_TRACKBALL:
211fcde3ac6Smacallan 				printf("TrackMan (non-EMP) trackball");
212fcde3ac6Smacallan 				break;
213fcde3ac6Smacallan 			default:
214fcde3ac6Smacallan 				printf("non-EMP relative positioning device");
215fcde3ac6Smacallan 				break;
216fcde3ac6Smacallan 			}
217fcde3ac6Smacallan 			printf("\n");
218fcde3ac6Smacallan 		} else {
219fcde3ac6Smacallan 			printf("EMP ");
220fcde3ac6Smacallan 			switch (sc->sc_class) {
221fcde3ac6Smacallan 			case MSCLASS_TABLET:
222fcde3ac6Smacallan 				printf("tablet");
223fcde3ac6Smacallan 				break;
224fcde3ac6Smacallan 			case MSCLASS_MOUSE:
225fcde3ac6Smacallan 				printf("mouse");
226fcde3ac6Smacallan 				break;
227fcde3ac6Smacallan 			case MSCLASS_TRACKBALL:
228fcde3ac6Smacallan 				printf("trackball");
229fcde3ac6Smacallan 				break;
230fcde3ac6Smacallan 			case MSCLASS_TRACKPAD:
231fcde3ac6Smacallan 				printf("trackpad");
232fcde3ac6Smacallan 				init_trackpad(sc);
233fcde3ac6Smacallan 				break;
234fcde3ac6Smacallan 			default:
235fcde3ac6Smacallan 				printf("unknown device");
236fcde3ac6Smacallan 				break;
237fcde3ac6Smacallan 			}
238756a508cSchristos 			printf(" <%s> %d-button, %u dpi\n", sc->sc_devid,
239756a508cSchristos 			    sc->sc_buttons, sc->sc_res);
240fcde3ac6Smacallan 		}
241fcde3ac6Smacallan 		break;
242fcde3ac6Smacallan 	default:
243fcde3ac6Smacallan 		printf("relative positioning device (mouse?) (%d)\n",
244fcde3ac6Smacallan 			sc->sc_adbdev->handler_id);
245fcde3ac6Smacallan 		break;
246fcde3ac6Smacallan 	}
247fcde3ac6Smacallan 
248fcde3ac6Smacallan 	a.accessops = &adbms_accessops;
249fcde3ac6Smacallan 	a.accesscookie = sc;
250c7fb772bSthorpej 	sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint, CFARGS_NONE);
251fcde3ac6Smacallan }
252fcde3ac6Smacallan 
253fcde3ac6Smacallan 
254fcde3ac6Smacallan /*
255fcde3ac6Smacallan  * Initialize extended mouse support -- probes devices as described
256fcde3ac6Smacallan  * in Inside Macintosh: Devices, Chapter 5 "ADB Manager".
257fcde3ac6Smacallan  *
258fcde3ac6Smacallan  * Extended Mouse Protocol is documented in TechNote HW1:
259fcde3ac6Smacallan  * 	"ADB - The Untold Story:  Space Aliens Ate My Mouse"
260fcde3ac6Smacallan  *
261fcde3ac6Smacallan  * Supports: Extended Mouse Protocol, MicroSpeed Mouse Deluxe,
262fcde3ac6Smacallan  * 	     Mouse Systems A^3 Mouse, Logitech non-EMP MouseMan
263fcde3ac6Smacallan  */
264fcde3ac6Smacallan void
ems_init(struct adbms_softc * sc)265fcde3ac6Smacallan ems_init(struct adbms_softc *sc)
266fcde3ac6Smacallan {
267fcde3ac6Smacallan 
268fcde3ac6Smacallan 	DPRINTF("ems_init %d\n", sc->sc_adbdev->handler_id);
269fcde3ac6Smacallan 
270fcde3ac6Smacallan 	switch (sc->sc_adbdev->handler_id) {
271fcde3ac6Smacallan 		case ADBMS_USPEED:
272fcde3ac6Smacallan 		case ADBMS_UCONTOUR:
273fcde3ac6Smacallan 			adbms_init_uspeed(sc);
274fcde3ac6Smacallan 			return;
275fcde3ac6Smacallan 		case ADBMS_TURBO:
276fcde3ac6Smacallan 			adbms_init_turbo(sc);
277fcde3ac6Smacallan 			return;
278fcde3ac6Smacallan 		case ADBMS_100DPI:
279fcde3ac6Smacallan 		case ADBMS_200DPI:
280fcde3ac6Smacallan 			adbms_init_mouse(sc);
281fcde3ac6Smacallan 	}
282fcde3ac6Smacallan }
283fcde3ac6Smacallan 
284fcde3ac6Smacallan static void
adbms_init_uspeed(struct adbms_softc * sc)285fcde3ac6Smacallan adbms_init_uspeed(struct adbms_softc *sc)
286fcde3ac6Smacallan {
287fcde3ac6Smacallan 	uint8_t cmd, addr, buffer[4];
288fcde3ac6Smacallan 
289fcde3ac6Smacallan 	addr = sc->sc_adbdev->current_addr;
290fcde3ac6Smacallan 
291fcde3ac6Smacallan 	/* Found MicroSpeed Mouse Deluxe Mac or Contour Mouse */
292fcde3ac6Smacallan 	cmd = ADBLISTEN(addr, 1);
293fcde3ac6Smacallan 
294fcde3ac6Smacallan 	/*
295fcde3ac6Smacallan 	 * To setup the MicroSpeed or the Contour, it appears
296fcde3ac6Smacallan 	 * that we can send the following command to the mouse
297fcde3ac6Smacallan 	 * and then expect data back in the form:
298fcde3ac6Smacallan 	 *  buffer[0] = 4 (bytes)
299fcde3ac6Smacallan 	 *  buffer[1], buffer[2] as std. mouse
300fcde3ac6Smacallan 	 *  buffer[3] = buffer[4] = 0xff when no buttons
301fcde3ac6Smacallan 	 *   are down.  When button N down, bit N is clear.
302fcde3ac6Smacallan 	 * buffer[4]'s locking mask enables a
303fcde3ac6Smacallan 	 * click to toggle the button down state--sort of
304fcde3ac6Smacallan 	 * like the "Easy Access" shift/control/etc. keys.
305fcde3ac6Smacallan 	 * buffer[3]'s alternative speed mask enables using
306fcde3ac6Smacallan 	 * different speed when the corr. button is down
307fcde3ac6Smacallan 	 */
308fcde3ac6Smacallan 	buffer[0] = 0x00;	/* Alternative speed */
309fcde3ac6Smacallan 	buffer[1] = 0x00;	/* speed = maximum */
310fcde3ac6Smacallan 	buffer[2] = 0x10;	/* enable extended protocol,
311fcde3ac6Smacallan 				 * lower bits = alt. speed mask
312fcde3ac6Smacallan 				 *            = 0000b
313fcde3ac6Smacallan 				 */
314fcde3ac6Smacallan 	buffer[3] = 0x07;	/* Locking mask = 0000b,
315fcde3ac6Smacallan 				 * enable buttons = 0111b
316fcde3ac6Smacallan 				 */
317fcde3ac6Smacallan 	adbms_send_sync(sc, cmd, 4, buffer);
318fcde3ac6Smacallan 
319fcde3ac6Smacallan 	sc->sc_buttons = 3;
320fcde3ac6Smacallan 	sc->sc_res = 200;
321fcde3ac6Smacallan }
322fcde3ac6Smacallan 
3238982eab2Smacallan static int
adbms_turbo_csum(uint8_t * d)3248982eab2Smacallan adbms_turbo_csum(uint8_t *d)
3258982eab2Smacallan {
3268982eab2Smacallan 	int i = 0, sum = 0;
3278982eab2Smacallan 
3288982eab2Smacallan 	for (i = 0; i < 7; i++)
3298982eab2Smacallan 		sum ^= d[i];
3308982eab2Smacallan 	return (sum ^ 0xff);
3318982eab2Smacallan }
3328982eab2Smacallan 
333fcde3ac6Smacallan static void
adbms_init_turbo(struct adbms_softc * sc)334fcde3ac6Smacallan adbms_init_turbo(struct adbms_softc *sc)
335fcde3ac6Smacallan {
336fcde3ac6Smacallan 	uint8_t addr;
337fcde3ac6Smacallan 
338fcde3ac6Smacallan 	/* Found Kensington Turbo Mouse */
339d9f28dceSmacallan 
340d9f28dceSmacallan /*
341d9f28dceSmacallan  * byte 1 assigns what which button does
342d9f28dceSmacallan  - 0x08 - button 1 - 1, button 2 - nothing
343d9f28dceSmacallan  - 0x09 - both buttons - 1
344*48491f98Sandvar  - 0x0a - button 1 - 1, button 2 - toggle 1
345d9f28dceSmacallan  - 0x0b - button 1 - 1, button 2 - nothing
346d9f28dceSmacallan  - 0x0c - button 1 - 1, button 2 - 2
347d9f28dceSmacallan  - 0x0e - button 1 - 1, button 2 - 3
348d9f28dceSmacallan  - 0x0f - button 1 - 1, button 2 - toggle 3
349d9f28dceSmacallan  - 0x10 - button 1 toggle 1, button 2 nothing
350d9f28dceSmacallan  - 0x11 - button 1 - toggle 1, button 2 - 1
351d9f28dceSmacallan  - 0x12 - both toggle 1
352d9f28dceSmacallan  - 0x14 - button 1 toggle 1, button 2 - 2
353d9f28dceSmacallan  - 0x21 - button 1 - 2, button 2 - 1
354d9f28dceSmacallan  - 0x31 - button 1 - 3, button 2 - 1
355d9f28dceSmacallan  * byte 4 programs a delay for button presses, apparently in 1/100 seconds
3568982eab2Smacallan  * byte 7 is a simple XOR checksum, writes will only stick if it's valid
3578982eab2Smacallan           as in, b[7] = (b[0] ^ b[1] ^ ... ^ b[6]) ^ 0xff
358d9f28dceSmacallan  */
359d9f28dceSmacallan 
360d9f28dceSmacallan 	/* this seems to be the most reasonable default */
3618982eab2Smacallan 	static u_char data[] =
3628982eab2Smacallan 		{ 0xa5, 0x0e, 0, 0, 1, 0xff, 0xff, 0/*0x55*/ };
363fcde3ac6Smacallan 
364fcde3ac6Smacallan 	addr = sc->sc_adbdev->current_addr;
365fcde3ac6Smacallan 
366d9f28dceSmacallan #ifdef ADBMS_DEBUG
367d9f28dceSmacallan 	{
368d9f28dceSmacallan 		int i;
369d9f28dceSmacallan 		adbms_send_sync(sc, ADBTALK(addr, 2), 0, NULL);
370d9f28dceSmacallan 		printf("reg *");
371d9f28dceSmacallan 		for (i = 0; i < sc->sc_msg_len; i++)
372d9f28dceSmacallan 			printf(" %02x", sc->sc_buffer[i]);
373d9f28dceSmacallan 		printf("\n");
374d9f28dceSmacallan 	}
375d9f28dceSmacallan #endif
376d9f28dceSmacallan 
377fcde3ac6Smacallan 	adbms_send_sync(sc, ADBFLUSH(addr), 0, NULL);
3788982eab2Smacallan 	data[7] = adbms_turbo_csum(data);
3798982eab2Smacallan 	adbms_send_sync(sc, ADBLISTEN(addr, 2), 8, data);
38099da6529Smacallan 
381d9f28dceSmacallan 
38299da6529Smacallan #ifdef ADBMS_DEBUG
38399da6529Smacallan 	int i, reg;
38499da6529Smacallan 	for (reg = 1; reg < 4; reg++) {
38599da6529Smacallan 		adbms_send_sync(sc, ADBTALK(addr, reg), 0, NULL);
38699da6529Smacallan 		printf("reg %d", reg);
38799da6529Smacallan 		for (i = 0; i < sc->sc_msg_len; i++)
38899da6529Smacallan 			printf(" %02x", sc->sc_buffer[i]);
38999da6529Smacallan 		printf("\n");
39099da6529Smacallan 	}
39199da6529Smacallan #endif
392fcde3ac6Smacallan }
393fcde3ac6Smacallan 
394fcde3ac6Smacallan static void
adbms_init_mouse(struct adbms_softc * sc)395fcde3ac6Smacallan adbms_init_mouse(struct adbms_softc *sc)
396fcde3ac6Smacallan {
397fcde3ac6Smacallan 	int len;
398fcde3ac6Smacallan 	uint8_t cmd, addr, buffer[16];
399fcde3ac6Smacallan 
400fcde3ac6Smacallan 	addr = sc->sc_adbdev->current_addr;
401fcde3ac6Smacallan 	/* found a mouse */
402fcde3ac6Smacallan 	cmd = ADBTALK(addr, 3);
403fcde3ac6Smacallan 	if (!adbms_send_sync(sc, cmd, 0, NULL)) {
404fcde3ac6Smacallan #ifdef ADBMS_DEBUG
405fcde3ac6Smacallan 		printf("adb: ems_init timed out\n");
406fcde3ac6Smacallan #endif
407fcde3ac6Smacallan 		return;
408fcde3ac6Smacallan 	}
409fcde3ac6Smacallan 
410fcde3ac6Smacallan 	/* Attempt to initialize Extended Mouse Protocol */
411fcde3ac6Smacallan 	len = sc->sc_msg_len;
412fcde3ac6Smacallan 	memcpy(buffer, sc->sc_buffer, len);
413fcde3ac6Smacallan 	DPRINTF("buffer: %02x %02x\n", buffer[0], buffer[1]);
414fcde3ac6Smacallan 	buffer[1] = 4; /* make handler ID 4 */
415fcde3ac6Smacallan 	cmd = ADBLISTEN(addr, 3);
416fcde3ac6Smacallan 	if (!adbms_send_sync(sc, cmd, len, buffer)) {
417fcde3ac6Smacallan #ifdef ADBMS_DEBUG
418fcde3ac6Smacallan 		printf("adb: ems_init timed out\n");
419fcde3ac6Smacallan #endif
420fcde3ac6Smacallan 		return;
421fcde3ac6Smacallan 	}
422fcde3ac6Smacallan 
423fcde3ac6Smacallan 	/*
424fcde3ac6Smacallan 	 * Check to see if successful, if not
425fcde3ac6Smacallan 	 * try to initialize it as other types
426fcde3ac6Smacallan 	 */
427fcde3ac6Smacallan 	cmd = ADBTALK(addr, 3);
428fcde3ac6Smacallan 	if (!adbms_send_sync(sc, cmd, 0, NULL)) {
429fcde3ac6Smacallan 		DPRINTF("timeout checking for EMP switch\n");
430fcde3ac6Smacallan 		return;
431fcde3ac6Smacallan 	}
432fcde3ac6Smacallan 	DPRINTF("new handler ID: %02x\n", sc->sc_buffer[1]);
433fcde3ac6Smacallan 	if (sc->sc_buffer[1] == ADBMS_EXTENDED) {
434fcde3ac6Smacallan 		sc->sc_adbdev->handler_id = ADBMS_EXTENDED;
435fcde3ac6Smacallan 		cmd = ADBTALK(addr, 1);
436fcde3ac6Smacallan 		if(!adbms_send_sync(sc, cmd, 0, NULL)) {
437fcde3ac6Smacallan 			DPRINTF("adb: ems_init timed out\n");
438fcde3ac6Smacallan 			return;
439fcde3ac6Smacallan 		}
440fcde3ac6Smacallan 
441fcde3ac6Smacallan 		len = sc->sc_msg_len;
442fcde3ac6Smacallan 		memcpy(buffer, sc->sc_buffer, len);
443fcde3ac6Smacallan 
444fcde3ac6Smacallan 		if (sc->sc_msg_len == 8) {
445756a508cSchristos 			uint16_t res;
446fcde3ac6Smacallan 			/* we have a true EMP device */
447fcde3ac6Smacallan #ifdef ADB_PRINT_EMP
448fcde3ac6Smacallan 
449fcde3ac6Smacallan 			printf("EMP: %02x %02x %02x %02x %02x %02x %02x %02x\n",
450fcde3ac6Smacallan 			    buffer[0], buffer[1], buffer[2], buffer[3],
451fcde3ac6Smacallan 			    buffer[4], buffer[5], buffer[6], buffer[7]);
452fcde3ac6Smacallan #endif
453756a508cSchristos 			memcpy(sc->sc_devid, &buffer[0], 4);
454756a508cSchristos 			memcpy(&res, &buffer[4], sizeof(res));
455756a508cSchristos 			sc->sc_res = res;
456fcde3ac6Smacallan 			sc->sc_class = buffer[6];
457fcde3ac6Smacallan 			sc->sc_buttons = buffer[7];
458fcde3ac6Smacallan 		} else if (buffer[0] == 0x9a &&
459fcde3ac6Smacallan 		    ((buffer[1] == 0x20) || (buffer[1] == 0x21))) {
460fcde3ac6Smacallan 			/*
461fcde3ac6Smacallan 			 * Set up non-EMP Mouseman/Trackman to put
462fcde3ac6Smacallan 			 * button bits in 3rd byte instead of sending
463fcde3ac6Smacallan 			 * via pseudo keyboard device.
464fcde3ac6Smacallan 			 */
465fcde3ac6Smacallan 			if (buffer[1] == 0x21)
466fcde3ac6Smacallan 				sc->sc_class = MSCLASS_TRACKBALL;
467fcde3ac6Smacallan 			else
468fcde3ac6Smacallan 				sc->sc_class = MSCLASS_MOUSE;
469fcde3ac6Smacallan 
470fcde3ac6Smacallan 			cmd = ADBLISTEN(addr, 1);
471fcde3ac6Smacallan 			buffer[0]=0x00;
472fcde3ac6Smacallan 			buffer[1]=0x81;
473fcde3ac6Smacallan 			adbms_send_sync(sc, cmd, 2, buffer);
474fcde3ac6Smacallan 
475fcde3ac6Smacallan 			cmd = ADBLISTEN(addr, 1);
476fcde3ac6Smacallan 			buffer[0]=0x01;
477fcde3ac6Smacallan 			buffer[1]=0x81;
478fcde3ac6Smacallan 			adbms_send_sync(sc, cmd, 2, buffer);
479fcde3ac6Smacallan 
480fcde3ac6Smacallan 			cmd = ADBLISTEN(addr, 1);
481fcde3ac6Smacallan 			buffer[0]=0x02;
482fcde3ac6Smacallan 			buffer[1]=0x81;
483fcde3ac6Smacallan 			adbms_send_sync(sc, cmd, 2, buffer);
484fcde3ac6Smacallan 
485fcde3ac6Smacallan 			cmd = ADBLISTEN(addr, 1);
486fcde3ac6Smacallan 			buffer[0]=0x03;
487fcde3ac6Smacallan 			buffer[1]=0x38;
488fcde3ac6Smacallan 			adbms_send_sync(sc, cmd, 2, buffer);
489fcde3ac6Smacallan 
490fcde3ac6Smacallan 			sc->sc_buttons = 3;
491fcde3ac6Smacallan 			sc->sc_res = 400;
492fcde3ac6Smacallan 		}
493fcde3ac6Smacallan 	} else {
494fcde3ac6Smacallan 		/* Attempt to initialize as an A3 mouse */
495fcde3ac6Smacallan 		buffer[1] = 0x03; /* make handler ID 3 */
496fcde3ac6Smacallan 		cmd = ADBLISTEN(addr, 3);
497fcde3ac6Smacallan 		if (!adbms_send_sync(sc, cmd, len, buffer)) {
498fcde3ac6Smacallan #ifdef ADBMS_DEBUG
499fcde3ac6Smacallan 			printf("adb: ems_init timed out\n");
500fcde3ac6Smacallan #endif
501fcde3ac6Smacallan 			return;
502fcde3ac6Smacallan 		}
503fcde3ac6Smacallan 
504fcde3ac6Smacallan 		/*
505fcde3ac6Smacallan 		 * Check to see if successful, if not
506fcde3ac6Smacallan 		 * try to initialize it as other types
507fcde3ac6Smacallan 		 */
508fcde3ac6Smacallan 		cmd = ADBTALK(addr, 3);
509fcde3ac6Smacallan 		if(adbms_send_sync(sc, cmd, 0, NULL)) {
510fcde3ac6Smacallan 			len = sc->sc_msg_len;
511fcde3ac6Smacallan 			memcpy(buffer, sc->sc_buffer, len);
512fcde3ac6Smacallan 			if (buffer[1] == ADBMS_MSA3) {
513fcde3ac6Smacallan 				sc->sc_adbdev->handler_id = ADBMS_MSA3;
514fcde3ac6Smacallan 				/* Initialize as above */
515fcde3ac6Smacallan 				cmd = ADBLISTEN(addr, 2);
516fcde3ac6Smacallan 				/* listen 2 */
517fcde3ac6Smacallan 				buffer[0] = 0x00;
518fcde3ac6Smacallan 				/* Irrelevant, buffer has 0x77 */
519fcde3ac6Smacallan 				buffer[2] = 0x07;
520fcde3ac6Smacallan 				/*
521fcde3ac6Smacallan 				 * enable 3 button mode = 0111b,
522fcde3ac6Smacallan 				 * speed = normal
523fcde3ac6Smacallan 				 */
524fcde3ac6Smacallan 				adbms_send_sync(sc, cmd, 3, buffer);
525fcde3ac6Smacallan 				sc->sc_buttons = 3;
526fcde3ac6Smacallan 				sc->sc_res = 300;
527fcde3ac6Smacallan 			}
528fcde3ac6Smacallan 		}
529fcde3ac6Smacallan 	}
530fcde3ac6Smacallan }
531fcde3ac6Smacallan 
532fcde3ac6Smacallan static void
adbms_handler(void * cookie,int len,uint8_t * data)533fcde3ac6Smacallan adbms_handler(void *cookie, int len, uint8_t *data)
534fcde3ac6Smacallan {
535fcde3ac6Smacallan 	struct adbms_softc *sc = cookie;
536fcde3ac6Smacallan 
537fcde3ac6Smacallan #ifdef ADBMS_DEBUG
538fcde3ac6Smacallan 	int i;
5395d109a29Smatt 	printf("%s: %02x - ", device_xname(sc->sc_dev), sc->sc_us);
540fcde3ac6Smacallan 	for (i = 0; i < len; i++) {
541fcde3ac6Smacallan 		printf(" %02x", data[i]);
542fcde3ac6Smacallan 	}
543fcde3ac6Smacallan 	printf("\n");
544fcde3ac6Smacallan #endif
545fcde3ac6Smacallan 	if (len >= 2) {
546fcde3ac6Smacallan 		memcpy(sc->sc_buffer, &data[2], len - 2);
547fcde3ac6Smacallan 		sc->sc_msg_len = len - 2;
548fcde3ac6Smacallan 		if (data[1] == sc->sc_us) {
549fcde3ac6Smacallan 			/* make sense of the mouse message */
550fcde3ac6Smacallan 			adbms_process_event(sc, sc->sc_msg_len, sc->sc_buffer);
551fcde3ac6Smacallan 			return;
552fcde3ac6Smacallan 		}
553fcde3ac6Smacallan 		wakeup(&sc->sc_event);
554fcde3ac6Smacallan 	} else {
555fcde3ac6Smacallan 		DPRINTF("bogus message\n");
556fcde3ac6Smacallan 	}
557fcde3ac6Smacallan }
558fcde3ac6Smacallan 
559fcde3ac6Smacallan static void
adbms_process_event(struct adbms_softc * sc,int len,uint8_t * buffer)560fcde3ac6Smacallan adbms_process_event(struct adbms_softc *sc, int len, uint8_t *buffer)
561fcde3ac6Smacallan {
562fcde3ac6Smacallan 	int buttons = 0, mask, dx, dy, i;
563fcde3ac6Smacallan 	int button_bit = 1;
564fcde3ac6Smacallan 
565fcde3ac6Smacallan 	if ((sc->sc_adbdev->handler_id == ADBMS_EXTENDED) && (sc->sc_devid[0] == 0)) {
566fcde3ac6Smacallan 		/* massage the data to look like EMP data */
567fcde3ac6Smacallan 		if ((buffer[2] & 0x04) == 0x04)
568fcde3ac6Smacallan 			buffer[0] &= 0x7f;
569fcde3ac6Smacallan 		else
570fcde3ac6Smacallan 			buffer[0] |= 0x80;
571fcde3ac6Smacallan 		if ((buffer[2] & 0x02) == 0x02)
572fcde3ac6Smacallan 			buffer[1] &= 0x7f;
573fcde3ac6Smacallan 		else
574fcde3ac6Smacallan 			buffer[1] |= 0x80;
575fcde3ac6Smacallan 		if ((buffer[2] & 0x01) == 0x01)
576fcde3ac6Smacallan 			buffer[2] = 0x00;
577fcde3ac6Smacallan 		else
578fcde3ac6Smacallan 			buffer[2] = 0x80;
579fcde3ac6Smacallan 	}
580fcde3ac6Smacallan 
581fcde3ac6Smacallan 	switch (sc->sc_adbdev->handler_id) {
582fcde3ac6Smacallan 		case ADBMS_USPEED:
583fcde3ac6Smacallan 		case ADBMS_UCONTOUR:
584fcde3ac6Smacallan 			/* MicroSpeed mouse and Contour mouse */
585fcde3ac6Smacallan 			if (len == 4)
586fcde3ac6Smacallan 				buttons = (~buffer[3]) & 0xff;
587fcde3ac6Smacallan 			else
588fcde3ac6Smacallan 				buttons = (buffer[1] & 0x80) ? 0 : 1;
589fcde3ac6Smacallan 			break;
590fcde3ac6Smacallan 		case ADBMS_MSA3:
591fcde3ac6Smacallan 			/* Mouse Systems A3 mouse */
592fcde3ac6Smacallan 			if (len == 3)
593fcde3ac6Smacallan 				buttons = (~buffer[2]) & 0x07;
594fcde3ac6Smacallan 			else
595fcde3ac6Smacallan 				buttons = (buffer[0] & 0x80) ? 0 : 1;
596fcde3ac6Smacallan 			break;
597fcde3ac6Smacallan 		default:
598fcde3ac6Smacallan 			/* Classic Mouse Protocol (up to 2 buttons) */
599fcde3ac6Smacallan 			for (i = 0; i < 2; i++, button_bit <<= 1)
600fcde3ac6Smacallan 				/* 0 when button down */
601fcde3ac6Smacallan 				if (!(buffer[i] & 0x80))
602fcde3ac6Smacallan 					buttons |= button_bit;
603fcde3ac6Smacallan 				else
604fcde3ac6Smacallan 					buttons &= ~button_bit;
605fcde3ac6Smacallan 			/* Extended Protocol (up to 6 more buttons) */
606fcde3ac6Smacallan 			for (mask = 0x80; i < len;
607fcde3ac6Smacallan 			     i += (mask == 0x80), button_bit <<= 1) {
608fcde3ac6Smacallan 				/* 0 when button down */
609fcde3ac6Smacallan 				if (!(buffer[i] & mask))
610fcde3ac6Smacallan 					buttons |= button_bit;
611fcde3ac6Smacallan 				else
612fcde3ac6Smacallan 					buttons &= ~button_bit;
613fcde3ac6Smacallan 				mask = ((mask >> 4) & 0xf)
614fcde3ac6Smacallan 					| ((mask & 0xf) << 4);
615fcde3ac6Smacallan 			}
616fcde3ac6Smacallan 			break;
617fcde3ac6Smacallan 	}
618fcde3ac6Smacallan 
61999da6529Smacallan 	if ((sc->sc_adbdev->handler_id != ADBMS_EXTENDED) &&
62099da6529Smacallan 	    (sc->sc_adbdev->handler_id != ADBMS_TURBO)) {
621fcde3ac6Smacallan 		dx = ((int)(buffer[1] & 0x3f)) - ((buffer[1] & 0x40) ? 64 : 0);
622fcde3ac6Smacallan 		dy = ((int)(buffer[0] & 0x3f)) - ((buffer[0] & 0x40) ? 64 : 0);
623e38e5b40Smacallan 	} else {
624e38e5b40Smacallan 		/* EMP crap, additional motion bits */
625e38e5b40Smacallan 		int shift = 7, ddx, ddy, sign, smask;
626e38e5b40Smacallan 
627e38e5b40Smacallan #ifdef ADBMS_DEBUG
628e38e5b40Smacallan 		printf("EMP packet:");
629e38e5b40Smacallan 		for (i = 0; i < len; i++)
630e38e5b40Smacallan 			printf(" %02x", buffer[i]);
631e38e5b40Smacallan 		printf("\n");
632e38e5b40Smacallan #endif
633e38e5b40Smacallan 		dx = (int)buffer[1] & 0x7f;
634e38e5b40Smacallan 		dy = (int)buffer[0] & 0x7f;
635e38e5b40Smacallan 		for (i = 2; i < len; i++) {
636e38e5b40Smacallan 			ddx = (buffer[i] & 0x07);
637e38e5b40Smacallan 			ddy = (buffer[i] & 0x70) >> 4;
638e38e5b40Smacallan 			dx |= (ddx << shift);
639e38e5b40Smacallan 			dy |= (ddy << shift);
640e38e5b40Smacallan 			shift += 3;
641e38e5b40Smacallan 		}
642e38e5b40Smacallan 		sign = 1 << (shift - 1);
643e38e5b40Smacallan 		smask = 0xffffffff << shift;
644e38e5b40Smacallan 		if (dx & sign)
645e38e5b40Smacallan 			dx |= smask;
646e38e5b40Smacallan 		if (dy & sign)
647e38e5b40Smacallan 			dy |= smask;
648e38e5b40Smacallan #ifdef ADBMS_DEBUG
649e38e5b40Smacallan 		printf("%d %d %08x %d\n", dx, dy, smask, shift);
650e38e5b40Smacallan #endif
651e38e5b40Smacallan 	}
652fcde3ac6Smacallan 
653fcde3ac6Smacallan 	if (sc->sc_class == MSCLASS_TRACKPAD) {
654fcde3ac6Smacallan 
655b184e0b1Stsutsui 		if (sc->sc_tapping == 1) {
656fcde3ac6Smacallan 			if (sc->sc_down) {
657fcde3ac6Smacallan 				/* finger is down - collect motion data */
658fcde3ac6Smacallan 				sc->sc_x += dx;
659fcde3ac6Smacallan 				sc->sc_y += dy;
660fcde3ac6Smacallan 			}
661fcde3ac6Smacallan 			DPRINTF("buttons: %02x\n", buttons);
662fcde3ac6Smacallan 			switch (sc->sc_buttons) {
663fcde3ac6Smacallan 				case 2:
664fcde3ac6Smacallan 					buttons |= ((buttons & 2) >> 1);
665fcde3ac6Smacallan 					adbms_mangle_2(sc, buttons);
666fcde3ac6Smacallan 					break;
667fcde3ac6Smacallan 				case 4:
668fcde3ac6Smacallan 					adbms_mangle_4(sc, buttons);
669fcde3ac6Smacallan 					break;
670fcde3ac6Smacallan 			}
671b184e0b1Stsutsui 		}
672fcde3ac6Smacallan 		/* filter the pseudo-buttons out */
673fcde3ac6Smacallan 		buttons &= 1;
674fcde3ac6Smacallan 	}
675fcde3ac6Smacallan 
676fcde3ac6Smacallan 	if (sc->sc_wsmousedev)
677fcde3ac6Smacallan 		wsmouse_input(sc->sc_wsmousedev, sc->sc_mb | buttons,
678fcde3ac6Smacallan 			      dx, -dy, 0, 0,
679fcde3ac6Smacallan 			      WSMOUSE_INPUT_DELTA);
680fcde3ac6Smacallan #if NAED > 0
681fcde3ac6Smacallan 	aed_input(&new_event);
682fcde3ac6Smacallan #endif
683fcde3ac6Smacallan }
684fcde3ac6Smacallan 
685fcde3ac6Smacallan static void
adbms_mangle_2(struct adbms_softc * sc,int buttons)686fcde3ac6Smacallan adbms_mangle_2(struct adbms_softc *sc, int buttons)
687fcde3ac6Smacallan {
688fcde3ac6Smacallan 
689fcde3ac6Smacallan 	if (buttons & 4) {
690fcde3ac6Smacallan 		/* finger down on pad */
691fcde3ac6Smacallan 		if (sc->sc_down == 0) {
692fcde3ac6Smacallan 			sc->sc_down = 1;
693fcde3ac6Smacallan 			sc->sc_x = 0;
694fcde3ac6Smacallan 			sc->sc_y = 0;
695fcde3ac6Smacallan 		}
696fcde3ac6Smacallan 	}
697fcde3ac6Smacallan 	if (buttons & 8) {
698fcde3ac6Smacallan 		/* finger up */
699fcde3ac6Smacallan 		if (sc->sc_down) {
700fcde3ac6Smacallan 			if (((sc->sc_x * sc->sc_x +
701ba9742b0Smacallan 			    sc->sc_y * sc->sc_y) < 3) &&
702fcde3ac6Smacallan 			    (sc->sc_wsmousedev)) {
703fcde3ac6Smacallan 				/*
704fcde3ac6Smacallan 				 * if there wasn't much movement between
705fcde3ac6Smacallan 				 * finger down and up again we assume
706fcde3ac6Smacallan 				 * someone tapped the pad and we just
707fcde3ac6Smacallan 				 * send a mouse button event
708fcde3ac6Smacallan 				 */
709fcde3ac6Smacallan 				wsmouse_input(sc->sc_wsmousedev,
710fcde3ac6Smacallan 				    1, 0, 0, 0, 0, WSMOUSE_INPUT_DELTA);
711fcde3ac6Smacallan 			}
712fcde3ac6Smacallan 			sc->sc_down = 0;
713fcde3ac6Smacallan 		}
714fcde3ac6Smacallan 	}
715fcde3ac6Smacallan }
716fcde3ac6Smacallan 
717fcde3ac6Smacallan static void
adbms_mangle_4(struct adbms_softc * sc,int buttons)718fcde3ac6Smacallan adbms_mangle_4(struct adbms_softc *sc, int buttons)
719fcde3ac6Smacallan {
720fcde3ac6Smacallan 
721fcde3ac6Smacallan 	if (buttons & 0x20) {
722fcde3ac6Smacallan 		/* finger down on pad */
723fcde3ac6Smacallan 		if (sc->sc_down == 0) {
724fcde3ac6Smacallan 			sc->sc_down = 1;
725fcde3ac6Smacallan 			sc->sc_x = 0;
726fcde3ac6Smacallan 			sc->sc_y = 0;
727fcde3ac6Smacallan 		}
728fcde3ac6Smacallan 	}
729fcde3ac6Smacallan 	if ((buttons & 0x20) == 0) {
730fcde3ac6Smacallan 		/* finger up */
731fcde3ac6Smacallan 		if (sc->sc_down) {
732fcde3ac6Smacallan 			if (((sc->sc_x * sc->sc_x +
733ba9742b0Smacallan 			    sc->sc_y * sc->sc_y) < 3) &&
734fcde3ac6Smacallan 			    (sc->sc_wsmousedev)) {
735fcde3ac6Smacallan 				/*
736fcde3ac6Smacallan 				 * if there wasn't much movement between
737fcde3ac6Smacallan 				 * finger down and up again we assume
738fcde3ac6Smacallan 				 * someone tapped the pad and we just
739fcde3ac6Smacallan 				 * send a mouse button event
740fcde3ac6Smacallan 				 */
741fcde3ac6Smacallan 				wsmouse_input(sc->sc_wsmousedev,
742fcde3ac6Smacallan 				    1, 0, 0, 0, 0, WSMOUSE_INPUT_DELTA);
743fcde3ac6Smacallan 			}
744fcde3ac6Smacallan 			sc->sc_down = 0;
745fcde3ac6Smacallan 		}
746fcde3ac6Smacallan 	}
747fcde3ac6Smacallan }
748fcde3ac6Smacallan 
749fcde3ac6Smacallan static int
adbms_enable(void * v)750fcde3ac6Smacallan adbms_enable(void *v)
751fcde3ac6Smacallan {
752fcde3ac6Smacallan 	return 0;
753fcde3ac6Smacallan }
754fcde3ac6Smacallan 
755fcde3ac6Smacallan static int
adbms_ioctl(void * v,u_long cmd,void * data,int flag,struct lwp * l)75653524e44Schristos adbms_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
757fcde3ac6Smacallan {
758fcde3ac6Smacallan 
759fcde3ac6Smacallan 	switch (cmd) {
760fcde3ac6Smacallan 	case WSMOUSEIO_GTYPE:
761fcde3ac6Smacallan 		*(u_int *)data = WSMOUSE_TYPE_ADB;
762fcde3ac6Smacallan 		break;
763fcde3ac6Smacallan 
764fcde3ac6Smacallan 	default:
765fcde3ac6Smacallan 		return (EPASSTHROUGH);
766fcde3ac6Smacallan 	}
767fcde3ac6Smacallan 	return (0);
768fcde3ac6Smacallan }
769fcde3ac6Smacallan 
770fcde3ac6Smacallan static void
adbms_disable(void * v)771fcde3ac6Smacallan adbms_disable(void *v)
772fcde3ac6Smacallan {
773fcde3ac6Smacallan }
774fcde3ac6Smacallan 
775fcde3ac6Smacallan static void
init_trackpad(struct adbms_softc * sc)776fcde3ac6Smacallan init_trackpad(struct adbms_softc *sc)
777fcde3ac6Smacallan {
77895065fc5Smacallan 	const struct sysctlnode *me = NULL, *node = NULL;
779b184e0b1Stsutsui 	int cmd, addr, ret;
780fcde3ac6Smacallan 	uint8_t buffer[16];
781fcde3ac6Smacallan 	uint8_t b2[] = {0x99, 0x94, 0x19, 0xff, 0xb2, 0x8a, 0x1b, 0x50};
782fcde3ac6Smacallan 
783fcde3ac6Smacallan 	addr = sc->sc_adbdev->current_addr;
784fcde3ac6Smacallan 	cmd = ADBTALK(addr, 1);
785fcde3ac6Smacallan 	if (!adbms_send_sync(sc, cmd, 0, NULL))
786fcde3ac6Smacallan 		return;
787fcde3ac6Smacallan 
788fcde3ac6Smacallan 	if (sc->sc_msg_len != 8)
789fcde3ac6Smacallan 		return;
790fcde3ac6Smacallan 
791fcde3ac6Smacallan 	memcpy(buffer, sc->sc_buffer, 8);
792fcde3ac6Smacallan 
793fcde3ac6Smacallan 	/* now whack the pad */
794fcde3ac6Smacallan 	cmd = ADBLISTEN(addr, 1);
795fcde3ac6Smacallan 	buffer[6] = 0x0d;
796fcde3ac6Smacallan 	adbms_send_sync(sc, cmd, 8, buffer);
797fcde3ac6Smacallan 
798fcde3ac6Smacallan 	delay(1000);
799fcde3ac6Smacallan 	cmd = ADBLISTEN(addr, 2);
800fcde3ac6Smacallan 	adbms_send_sync(sc, cmd, 8, b2);
801fcde3ac6Smacallan 
802fcde3ac6Smacallan 	delay(1000);
803fcde3ac6Smacallan 	cmd = ADBLISTEN(addr, 1);
804fcde3ac6Smacallan 	buffer[6] = 0x03;
805fcde3ac6Smacallan 	adbms_send_sync(sc, cmd, 8, buffer);
806fcde3ac6Smacallan 
807fcde3ac6Smacallan 	cmd = ADBFLUSH(addr);
808fcde3ac6Smacallan 	adbms_send_sync(sc, cmd, 0, NULL);
809fcde3ac6Smacallan 	delay(1000);
810b184e0b1Stsutsui 
811b184e0b1Stsutsui 	/*
812631d5867Smbalmer 	 * setup a sysctl node to control whether tapping the pad should
813b184e0b1Stsutsui 	 * trigger mouse button events
814b184e0b1Stsutsui 	 */
815b184e0b1Stsutsui 
816b184e0b1Stsutsui 	sc->sc_tapping = 1;
817b184e0b1Stsutsui 
81895065fc5Smacallan 	ret = sysctl_createv(NULL, 0, NULL, &me,
819b184e0b1Stsutsui 	    CTLFLAG_READWRITE,
8205d109a29Smatt 	    CTLTYPE_NODE, device_xname(sc->sc_dev), NULL,
821b184e0b1Stsutsui 	    NULL, 0, NULL, 0,
822b184e0b1Stsutsui 	    CTL_MACHDEP, CTL_CREATE, CTL_EOL);
823b184e0b1Stsutsui 
82495065fc5Smacallan 	ret = sysctl_createv(NULL, 0, NULL, &node,
82595065fc5Smacallan 	    CTLFLAG_READWRITE | CTLFLAG_OWNDESC,
826b184e0b1Stsutsui 	    CTLTYPE_INT, "tapping", "tapping the pad causes button events",
827e21a34c2Sdsl 	    sysctl_adbms_tap, 1, (void *)sc, 0,
828b184e0b1Stsutsui 	    CTL_MACHDEP, me->sysctl_num, CTL_CREATE, CTL_EOL);
8297bc55a44Snisimura 
8307bc55a44Snisimura 	(void)ret;
831fcde3ac6Smacallan }
832fcde3ac6Smacallan 
833fcde3ac6Smacallan static int
adbms_wait(struct adbms_softc * sc,int timeout)834fcde3ac6Smacallan adbms_wait(struct adbms_softc *sc, int timeout)
835fcde3ac6Smacallan {
836fcde3ac6Smacallan 	int cnt = 0;
837fcde3ac6Smacallan 
838fcde3ac6Smacallan 	if (sc->sc_poll) {
839fcde3ac6Smacallan 		while (sc->sc_msg_len == -1) {
840fcde3ac6Smacallan 			sc->sc_ops->poll(sc->sc_ops->cookie);
841fcde3ac6Smacallan 		}
842fcde3ac6Smacallan 	} else {
843fcde3ac6Smacallan 		while ((sc->sc_msg_len == -1) && (cnt < timeout)) {
844ba9742b0Smacallan 			tsleep(&sc->sc_event, 0, "adbmsio", hz);
845fcde3ac6Smacallan 			cnt++;
846fcde3ac6Smacallan 		}
847fcde3ac6Smacallan 	}
848fcde3ac6Smacallan 	return (sc->sc_msg_len > 0);
849fcde3ac6Smacallan }
850fcde3ac6Smacallan 
851fcde3ac6Smacallan static int
adbms_send_sync(struct adbms_softc * sc,uint8_t cmd,int len,uint8_t * msg)852fcde3ac6Smacallan adbms_send_sync(struct adbms_softc *sc, uint8_t cmd, int len, uint8_t *msg)
853fcde3ac6Smacallan {
854fcde3ac6Smacallan 	int i;
855fcde3ac6Smacallan 
856fcde3ac6Smacallan 	sc->sc_msg_len = -1;
857fcde3ac6Smacallan 	DPRINTF("send: %02x", cmd);
858fcde3ac6Smacallan 	for (i = 0; i < len; i++)
859fcde3ac6Smacallan 		DPRINTF(" %02x", msg[i]);
860fcde3ac6Smacallan 	DPRINTF("\n");
861fcde3ac6Smacallan 	sc->sc_ops->send(sc->sc_ops->cookie, sc->sc_poll, cmd, len, msg);
86299da6529Smacallan 	adbms_wait(sc, 3);
863fcde3ac6Smacallan 	return (sc->sc_msg_len != -1);
864fcde3ac6Smacallan }
865b184e0b1Stsutsui 
866b184e0b1Stsutsui static int
sysctl_adbms_tap(SYSCTLFN_ARGS)867b184e0b1Stsutsui sysctl_adbms_tap(SYSCTLFN_ARGS)
868b184e0b1Stsutsui {
869b184e0b1Stsutsui 	struct sysctlnode node = *rnode;
870b184e0b1Stsutsui 	struct adbms_softc *sc = node.sysctl_data;
871b184e0b1Stsutsui 
872b184e0b1Stsutsui 	node.sysctl_idata = sc->sc_tapping;
873b184e0b1Stsutsui 
874b184e0b1Stsutsui 	if (newp) {
875b184e0b1Stsutsui 
876b184e0b1Stsutsui 		/* we're asked to write */
877b184e0b1Stsutsui 		node.sysctl_data = &sc->sc_tapping;
878b184e0b1Stsutsui 		if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) {
879b184e0b1Stsutsui 
88095065fc5Smacallan 			sc->sc_tapping = (*(int *)node.sysctl_data == 0) ? 0 : 1;
881b184e0b1Stsutsui 			return 0;
882b184e0b1Stsutsui 		}
883b184e0b1Stsutsui 		return EINVAL;
884b184e0b1Stsutsui 	} else {
885b184e0b1Stsutsui 
88695065fc5Smacallan 		node.sysctl_data = &sc->sc_tapping;
887b184e0b1Stsutsui 		node.sysctl_size = 4;
888b184e0b1Stsutsui 		return (sysctl_lookup(SYSCTLFN_CALL(&node)));
889b184e0b1Stsutsui 	}
890b184e0b1Stsutsui 
891b184e0b1Stsutsui 	return 0;
892b184e0b1Stsutsui }
893b184e0b1Stsutsui 
894b184e0b1Stsutsui SYSCTL_SETUP(sysctl_ams_setup, "sysctl ams subtree setup")
895b184e0b1Stsutsui {
896b184e0b1Stsutsui 
897b184e0b1Stsutsui 	sysctl_createv(NULL, 0, NULL, NULL,
898b184e0b1Stsutsui 		       CTLFLAG_PERMANENT,
899b184e0b1Stsutsui 		       CTLTYPE_NODE, "machdep", NULL,
900b184e0b1Stsutsui 		       NULL, 0, NULL, 0,
901b184e0b1Stsutsui 		       CTL_MACHDEP, CTL_EOL);
902b184e0b1Stsutsui }
903