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