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