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