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