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