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