1 /* $NetBSD: adb_kbd.c,v 1.11 2007/10/10 18:36:52 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_kbd.c,v 1.11 2007/10/10 18:36:52 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/systm.h> 44 #include <sys/kernel.h> 45 #include <sys/sysctl.h> 46 47 #include <dev/wscons/wsconsio.h> 48 #include <dev/wscons/wskbdvar.h> 49 #include <dev/wscons/wsksymdef.h> 50 #include <dev/wscons/wsksymvar.h> 51 #include <dev/wscons/wsmousevar.h> 52 53 #include <dev/sysmon/sysmonvar.h> 54 #include <dev/sysmon/sysmon_taskq.h> 55 56 #include <machine/autoconf.h> 57 #include <machine/keyboard.h> 58 #include <machine/adbsys.h> 59 60 #include <dev/adb/adbvar.h> 61 #include <dev/adb/adb_keymap.h> 62 63 #include "opt_wsdisplay_compat.h" 64 #include "adbdebug.h" 65 #include "wsmouse.h" 66 67 struct adbkbd_softc { 68 struct device sc_dev; 69 struct adb_device *sc_adbdev; 70 struct adb_bus_accessops *sc_ops; 71 struct device *sc_wskbddev; 72 #if NWSMOUSE > 0 73 struct device *sc_wsmousedev; 74 #endif 75 struct sysmon_pswitch sc_sm_pbutton; 76 int sc_leds; 77 int sc_have_led_control; 78 int sc_msg_len; 79 int sc_event; 80 int sc_poll; 81 int sc_polled_chars; 82 int sc_trans[3]; 83 int sc_capslock; 84 uint32_t sc_timestamp; 85 #ifdef WSDISPLAY_COMPAT_RAWKBD 86 int sc_rawkbd; 87 #endif 88 uint8_t sc_buffer[16]; 89 uint8_t sc_pollbuf[16]; 90 uint8_t sc_us; 91 uint8_t sc_power, sc_pe; 92 }; 93 94 /* 95 * Function declarations. 96 */ 97 static int adbkbd_match(struct device *, struct cfdata *, void *); 98 static void adbkbd_attach(struct device *, struct device *, void *); 99 100 static void adbkbd_initleds(struct adbkbd_softc *); 101 static void adbkbd_keys(struct adbkbd_softc *, uint8_t, uint8_t); 102 static inline void adbkbd_key(struct adbkbd_softc *, uint8_t); 103 static int adbkbd_wait(struct adbkbd_softc *, int); 104 105 /* Driver definition. */ 106 CFATTACH_DECL(adbkbd, sizeof(struct adbkbd_softc), 107 adbkbd_match, adbkbd_attach, NULL, NULL); 108 109 extern struct cfdriver adbkbd_cd; 110 111 static int adbkbd_enable(void *, int); 112 static int adbkbd_ioctl(void *, u_long, void *, int, struct lwp *); 113 static void adbkbd_set_leds(void *, int); 114 static void adbkbd_handler(void *, int, uint8_t *); 115 static void adbkbd_powerbutton(void *); 116 117 struct wskbd_accessops adbkbd_accessops = { 118 adbkbd_enable, 119 adbkbd_set_leds, 120 adbkbd_ioctl, 121 }; 122 123 static void adbkbd_cngetc(void *, u_int *, int *); 124 static void adbkbd_cnpollc(void *, int); 125 126 struct wskbd_consops adbkbd_consops = { 127 adbkbd_cngetc, 128 adbkbd_cnpollc, 129 }; 130 131 struct wskbd_mapdata adbkbd_keymapdata = { 132 akbd_keydesctab, 133 #ifdef AKBD_LAYOUT 134 AKBD_LAYOUT, 135 #else 136 KB_US, 137 #endif 138 }; 139 140 #if NWSMOUSE > 0 141 static int adbkms_enable(void *); 142 static int adbkms_ioctl(void *, u_long, void *, int, struct lwp *); 143 static void adbkms_disable(void *); 144 145 const struct wsmouse_accessops adbkms_accessops = { 146 adbkms_enable, 147 adbkms_ioctl, 148 adbkms_disable, 149 }; 150 151 static int adbkbd_sysctl_button(SYSCTLFN_ARGS); 152 static void adbkbd_setup_sysctl(struct adbkbd_softc *); 153 154 #endif /* NWSMOUSE > 0 */ 155 156 #ifdef ADBKBD_DEBUG 157 #define DPRINTF printf 158 #else 159 #define DPRINTF while (0) printf 160 #endif 161 162 static int adbkbd_is_console = 0; 163 static int adbkbd_console_attached = 0; 164 165 static int 166 adbkbd_match(parent, cf, aux) 167 struct device *parent; 168 struct cfdata *cf; 169 void *aux; 170 { 171 struct adb_attach_args *aaa = aux; 172 173 if (aaa->dev->original_addr == ADBADDR_KBD) 174 return 1; 175 else 176 return 0; 177 } 178 179 static void 180 adbkbd_attach(struct device *parent, struct device *self, void *aux) 181 { 182 struct adbkbd_softc *sc = (struct adbkbd_softc *)self; 183 struct adb_attach_args *aaa = aux; 184 short cmd; 185 struct wskbddev_attach_args a; 186 #if NWSMOUSE > 0 187 struct wsmousedev_attach_args am; 188 #endif 189 190 sc->sc_ops = aaa->ops; 191 sc->sc_adbdev = aaa->dev; 192 sc->sc_adbdev->cookie = sc; 193 sc->sc_adbdev->handler = adbkbd_handler; 194 sc->sc_us = ADBTALK(sc->sc_adbdev->current_addr, 0); 195 196 sc->sc_leds = 0; /* initially off */ 197 sc->sc_have_led_control = 0; 198 sc->sc_msg_len = 0; 199 sc->sc_poll = 0; 200 sc->sc_capslock = 0; 201 sc->sc_trans[1] = 103; /* F11 */ 202 sc->sc_trans[2] = 111; /* F12 */ 203 sc->sc_power = 0x7f; 204 sc->sc_timestamp = 0; 205 206 printf(" addr %d: ", sc->sc_adbdev->current_addr); 207 208 switch (sc->sc_adbdev->handler_id) { 209 case ADB_STDKBD: 210 printf("standard keyboard\n"); 211 break; 212 case ADB_ISOKBD: 213 printf("standard keyboard (ISO layout)\n"); 214 break; 215 case ADB_EXTKBD: 216 cmd = ADBTALK(sc->sc_adbdev->current_addr, 1); 217 sc->sc_msg_len = 0; 218 sc->sc_ops->send(sc->sc_ops->cookie, sc->sc_poll, cmd, 0, NULL); 219 adbkbd_wait(sc, 10); 220 221 /* Ignore Logitech MouseMan/Trackman pseudo keyboard */ 222 /* XXX needs testing */ 223 if (sc->sc_buffer[2] == 0x9a && sc->sc_buffer[3] == 0x20) { 224 printf("Mouseman (non-EMP) pseudo keyboard\n"); 225 return; 226 } else if (sc->sc_buffer[2] == 0x9a && 227 sc->sc_buffer[3] == 0x21) { 228 printf("Trackman (non-EMP) pseudo keyboard\n"); 229 return; 230 } else { 231 printf("extended keyboard\n"); 232 adbkbd_initleds(sc); 233 } 234 break; 235 case ADB_EXTISOKBD: 236 printf("extended keyboard (ISO layout)\n"); 237 adbkbd_initleds(sc); 238 break; 239 case ADB_KBDII: 240 printf("keyboard II\n"); 241 break; 242 case ADB_ISOKBDII: 243 printf("keyboard II (ISO layout)\n"); 244 break; 245 case ADB_PBKBD: 246 printf("PowerBook keyboard\n"); 247 sc->sc_power = 0x7e; 248 break; 249 case ADB_PBISOKBD: 250 printf("PowerBook keyboard (ISO layout)\n"); 251 sc->sc_power = 0x7e; 252 break; 253 case ADB_ADJKPD: 254 printf("adjustable keypad\n"); 255 break; 256 case ADB_ADJKBD: 257 printf("adjustable keyboard\n"); 258 break; 259 case ADB_ADJISOKBD: 260 printf("adjustable keyboard (ISO layout)\n"); 261 break; 262 case ADB_ADJJAPKBD: 263 printf("adjustable keyboard (Japanese layout)\n"); 264 break; 265 case ADB_PBEXTISOKBD: 266 printf("PowerBook extended keyboard (ISO layout)\n"); 267 sc->sc_power = 0x7e; 268 break; 269 case ADB_PBEXTJAPKBD: 270 printf("PowerBook extended keyboard (Japanese layout)\n"); 271 sc->sc_power = 0x7e; 272 break; 273 case ADB_JPKBDII: 274 printf("keyboard II (Japanese layout)\n"); 275 break; 276 case ADB_PBEXTKBD: 277 printf("PowerBook extended keyboard\n"); 278 sc->sc_power = 0x7e; 279 break; 280 case ADB_DESIGNKBD: 281 printf("extended keyboard\n"); 282 adbkbd_initleds(sc); 283 break; 284 case ADB_PBJPKBD: 285 printf("PowerBook keyboard (Japanese layout)\n"); 286 sc->sc_power = 0x7e; 287 break; 288 case ADB_PBG3KBD: 289 printf("PowerBook G3 keyboard\n"); 290 sc->sc_power = 0x7e; 291 break; 292 case ADB_PBG3JPKBD: 293 printf("PowerBook G3 keyboard (Japanese layout)\n"); 294 sc->sc_power = 0x7e; 295 break; 296 case ADB_IBOOKKBD: 297 printf("iBook keyboard\n"); 298 break; 299 default: 300 printf("mapped device (%d)\n", sc->sc_adbdev->handler_id); 301 break; 302 } 303 304 if (adbkbd_is_console && (adbkbd_console_attached == 0)) { 305 wskbd_cnattach(&adbkbd_consops, sc, &adbkbd_keymapdata); 306 adbkbd_console_attached = 1; 307 a.console = 1; 308 } else { 309 a.console = 0; 310 } 311 a.keymap = &adbkbd_keymapdata; 312 a.accessops = &adbkbd_accessops; 313 a.accesscookie = sc; 314 315 sc->sc_wskbddev = config_found_ia(self, "wskbddev", &a, wskbddevprint); 316 317 #if NWSMOUSE > 0 318 /* attach the mouse device */ 319 am.accessops = &adbkms_accessops; 320 am.accesscookie = sc; 321 sc->sc_wsmousedev = config_found_ia(self, "wsmousedev", &am, 322 wsmousedevprint); 323 324 if (sc->sc_wsmousedev != NULL) 325 adbkbd_setup_sysctl(sc); 326 #endif 327 328 /* finally register the power button */ 329 sysmon_task_queue_init(); 330 memset(&sc->sc_sm_pbutton, 0, sizeof(struct sysmon_pswitch)); 331 sc->sc_sm_pbutton.smpsw_name = sc->sc_dev.dv_xname; 332 sc->sc_sm_pbutton.smpsw_type = PSWITCH_TYPE_POWER; 333 if (sysmon_pswitch_register(&sc->sc_sm_pbutton) != 0) 334 printf("%s: unable to register power button with sysmon\n", 335 sc->sc_dev.dv_xname); 336 } 337 338 static void 339 adbkbd_handler(void *cookie, int len, uint8_t *data) 340 { 341 struct adbkbd_softc *sc = cookie; 342 343 #ifdef ADBKBD_DEBUG 344 int i; 345 printf("%s: %02x - ", sc->sc_dev.dv_xname, sc->sc_us); 346 for (i = 0; i < len; i++) { 347 printf(" %02x", data[i]); 348 } 349 printf("\n"); 350 #endif 351 if (len >= 2) { 352 if (data[1] == sc->sc_us) { 353 adbkbd_keys(sc, data[2], data[3]); 354 return; 355 } else { 356 memcpy(sc->sc_buffer, data, len); 357 } 358 sc->sc_msg_len = len; 359 wakeup(&sc->sc_event); 360 } else { 361 DPRINTF("bogus message\n"); 362 } 363 } 364 365 static int 366 adbkbd_wait(struct adbkbd_softc *sc, int timeout) 367 { 368 int cnt = 0; 369 370 if (sc->sc_poll) { 371 while (sc->sc_msg_len == 0) { 372 sc->sc_ops->poll(sc->sc_ops->cookie); 373 } 374 } else { 375 while ((sc->sc_msg_len == 0) && (cnt < timeout)) { 376 tsleep(&sc->sc_event, 0, "adbkbdio", hz); 377 cnt++; 378 } 379 } 380 return (sc->sc_msg_len > 0); 381 } 382 383 static void 384 adbkbd_keys(struct adbkbd_softc *sc, uint8_t k1, uint8_t k2) 385 { 386 387 /* keyboard event processing */ 388 389 DPRINTF("[%02x %02x]", k1, k2); 390 391 if (((k1 == k2) && (k1 == 0x7f)) || (k1 == sc->sc_power)) { 392 uint32_t now = time_second; 393 uint32_t diff = now - sc->sc_timestamp; 394 395 sc->sc_timestamp = now; 396 if ((diff > 1) && (diff < 5)) { 397 398 /* power button, report to sysmon */ 399 sc->sc_pe = k1; 400 401 sysmon_task_queue_sched(0, adbkbd_powerbutton, sc); 402 } 403 } else { 404 405 adbkbd_key(sc, k1); 406 if (k2 != 0xff) 407 adbkbd_key(sc, k2); 408 } 409 } 410 411 static void 412 adbkbd_powerbutton(void *cookie) 413 { 414 struct adbkbd_softc *sc = cookie; 415 416 sysmon_pswitch_event(&sc->sc_sm_pbutton, 417 ADBK_PRESS(sc->sc_pe) ? PSWITCH_EVENT_PRESSED : 418 PSWITCH_EVENT_RELEASED); 419 } 420 421 static inline void 422 adbkbd_key(struct adbkbd_softc *sc, uint8_t k) 423 { 424 425 if (sc->sc_poll) { 426 if (sc->sc_polled_chars >= 16) { 427 printf("%s: polling buffer is full\n", 428 sc->sc_dev.dv_xname); 429 } 430 sc->sc_pollbuf[sc->sc_polled_chars] = k; 431 sc->sc_polled_chars++; 432 return; 433 } 434 435 #if NWSMOUSE > 0 436 /* translate some keys to mouse events */ 437 if (sc->sc_wsmousedev != NULL) { 438 if (ADBK_KEYVAL(k) == sc->sc_trans[1]) { 439 wsmouse_input(sc->sc_wsmousedev, ADBK_PRESS(k) ? 2 : 0, 440 0, 0, 0, 0, 441 WSMOUSE_INPUT_DELTA); 442 return; 443 } 444 if (ADBK_KEYVAL(k) == sc->sc_trans[2]) { 445 wsmouse_input(sc->sc_wsmousedev, ADBK_PRESS(k) ? 4 : 0, 446 0, 0, 0, 0, 447 WSMOUSE_INPUT_DELTA); 448 return; 449 } 450 } 451 #endif 452 453 #ifdef WSDISPLAY_COMPAT_RAWKBD 454 if (sc->sc_rawkbd) { 455 char cbuf[2]; 456 int s; 457 458 cbuf[0] = k; 459 460 s = spltty(); 461 wskbd_rawinput(sc->sc_wskbddev, cbuf, 1); 462 splx(s); 463 } else { 464 #endif 465 466 if (ADBK_KEYVAL(k) == 0x39) { 467 /* caps lock - send up and down */ 468 if (ADBK_PRESS(k) != sc->sc_capslock) { 469 sc->sc_capslock = ADBK_PRESS(k); 470 wskbd_input(sc->sc_wskbddev, 471 WSCONS_EVENT_KEY_DOWN, 0x39); 472 wskbd_input(sc->sc_wskbddev, 473 WSCONS_EVENT_KEY_UP, 0x39); 474 } 475 } else { 476 /* normal event */ 477 int type; 478 479 type = ADBK_PRESS(k) ? 480 WSCONS_EVENT_KEY_DOWN : WSCONS_EVENT_KEY_UP; 481 wskbd_input(sc->sc_wskbddev, type, ADBK_KEYVAL(k)); 482 } 483 #ifdef WSDISPLAY_COMPAT_RAWKBD 484 } 485 #endif 486 } 487 488 /* 489 * Set the keyboard LED's. 490 * 491 * Automatically translates from ioctl/softc format to the 492 * actual keyboard register format 493 */ 494 static void 495 adbkbd_set_leds(void *cookie, int leds) 496 { 497 struct adbkbd_softc *sc = cookie; 498 int aleds; 499 short cmd; 500 uint8_t buffer[2]; 501 502 DPRINTF("adbkbd_set_leds: %02x\n", leds); 503 if ((leds & 0x07) == (sc->sc_leds & 0x07)) 504 return; 505 506 if (sc->sc_have_led_control) { 507 508 aleds = (~leds & 0x04) | 3; 509 if (leds & 1) 510 aleds &= ~2; 511 if (leds & 2) 512 aleds &= ~1; 513 514 buffer[0] = 0xff; 515 buffer[1] = aleds | 0xf8; 516 517 cmd = ADBLISTEN(sc->sc_adbdev->current_addr, 2); 518 sc->sc_ops->send(sc->sc_ops->cookie, sc->sc_poll, cmd, 2, 519 buffer); 520 } 521 522 sc->sc_leds = leds & 7; 523 } 524 525 static void 526 adbkbd_initleds(struct adbkbd_softc *sc) 527 { 528 short cmd; 529 530 /* talk R2 */ 531 cmd = ADBTALK(sc->sc_adbdev->current_addr, 2); 532 sc->sc_msg_len = 0; 533 sc->sc_ops->send(sc->sc_ops->cookie, sc->sc_poll, cmd, 0, NULL); 534 if (!adbkbd_wait(sc, 10)) { 535 printf("unable to read LED state\n"); 536 return; 537 } 538 sc->sc_have_led_control = 1; 539 DPRINTF("have LED control\n"); 540 return; 541 } 542 543 static int 544 adbkbd_enable(void *v, int on) 545 { 546 return 0; 547 } 548 549 static int 550 adbkbd_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l) 551 { 552 struct adbkbd_softc *sc = (struct adbkbd_softc *) v; 553 554 switch (cmd) { 555 556 case WSKBDIO_GTYPE: 557 *(int *)data = WSKBD_TYPE_ADB; 558 return 0; 559 case WSKBDIO_SETLEDS: 560 adbkbd_set_leds(sc, *(int *)data); 561 return 0; 562 case WSKBDIO_GETLEDS: 563 *(int *)data = sc->sc_leds; 564 return 0; 565 #ifdef WSDISPLAY_COMPAT_RAWKBD 566 case WSKBDIO_SETMODE: 567 sc->sc_rawkbd = *(int *)data == WSKBD_RAW; 568 return 0; 569 #endif 570 } 571 572 return EPASSTHROUGH; 573 } 574 575 int 576 adbkbd_cnattach() 577 { 578 579 adbkbd_is_console = 1; 580 return 0; 581 } 582 583 static void 584 adbkbd_cngetc(void *v, u_int *type, int *data) 585 { 586 struct adbkbd_softc *sc = v; 587 int key, press, val; 588 int s; 589 590 s = splhigh(); 591 592 KASSERT(sc->sc_poll); 593 594 DPRINTF("polling..."); 595 while (sc->sc_polled_chars == 0) { 596 sc->sc_ops->poll(sc->sc_ops->cookie); 597 } 598 DPRINTF(" got one\n"); 599 splx(s); 600 601 key = sc->sc_pollbuf[0]; 602 sc->sc_polled_chars--; 603 memmove(sc->sc_pollbuf, sc->sc_pollbuf + 1, 604 sc->sc_polled_chars); 605 606 press = ADBK_PRESS(key); 607 val = ADBK_KEYVAL(key); 608 609 *data = val; 610 *type = press ? WSCONS_EVENT_KEY_DOWN : WSCONS_EVENT_KEY_UP; 611 } 612 613 static void 614 adbkbd_cnpollc(void *v, int on) 615 { 616 struct adbkbd_softc *sc = v; 617 618 sc->sc_poll = on; 619 if (!on) { 620 int i; 621 622 /* feed the poll buffer's content to wskbd */ 623 for (i = 0; i < sc->sc_polled_chars; i++) { 624 adbkbd_key(sc, sc->sc_pollbuf[i]); 625 } 626 sc->sc_polled_chars = 0; 627 } 628 } 629 630 #if NWSMOUSE > 0 631 /* stuff for the pseudo mouse */ 632 static int 633 adbkms_enable(void *v) 634 { 635 return 0; 636 } 637 638 static int 639 adbkms_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l) 640 { 641 642 switch (cmd) { 643 case WSMOUSEIO_GTYPE: 644 *(u_int *)data = WSMOUSE_TYPE_PSEUDO; 645 break; 646 647 default: 648 return (EPASSTHROUGH); 649 } 650 return (0); 651 } 652 653 static void 654 adbkms_disable(void *v) 655 { 656 } 657 658 static void 659 adbkbd_setup_sysctl(struct adbkbd_softc *sc) 660 { 661 struct sysctlnode *node, *me; 662 int ret; 663 664 DPRINTF("%s: sysctl setup\n", sc->sc_dev.dv_xname); 665 ret = sysctl_createv(NULL, 0, NULL, (const struct sysctlnode **)&me, 666 CTLFLAG_READWRITE, 667 CTLTYPE_NODE, sc->sc_dev.dv_xname, NULL, 668 NULL, 0, NULL, 0, 669 CTL_MACHDEP, CTL_CREATE, CTL_EOL); 670 671 ret = sysctl_createv(NULL, 0, NULL, 672 (const struct sysctlnode **)&node, 673 CTLFLAG_READWRITE | CTLFLAG_OWNDESC | CTLFLAG_IMMEDIATE, 674 CTLTYPE_INT, "middle", "middle mouse button", adbkbd_sysctl_button, 675 1, NULL, 0, CTL_MACHDEP, me->sysctl_num, CTL_CREATE, 676 CTL_EOL); 677 node->sysctl_data = sc; 678 679 ret = sysctl_createv(NULL, 0, NULL, 680 (const struct sysctlnode **)&node, 681 CTLFLAG_READWRITE | CTLFLAG_OWNDESC | CTLFLAG_IMMEDIATE, 682 CTLTYPE_INT, "right", "right mouse button", adbkbd_sysctl_button, 683 2, NULL, 0, CTL_MACHDEP, me->sysctl_num, CTL_CREATE, 684 CTL_EOL); 685 node->sysctl_data = sc; 686 } 687 688 static int 689 adbkbd_sysctl_button(SYSCTLFN_ARGS) 690 { 691 struct sysctlnode node = *rnode; 692 struct adbkbd_softc *sc=(struct adbkbd_softc *)node.sysctl_data; 693 const int *np = newp; 694 int btn = node.sysctl_idata, reg; 695 696 DPRINTF("adbkbd_sysctl_button %d\n", btn); 697 node.sysctl_idata = sc->sc_trans[btn]; 698 reg = sc->sc_trans[btn]; 699 if (np) { 700 /* we're asked to write */ 701 node.sysctl_data = ® 702 if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) { 703 704 sc->sc_trans[btn] = node.sysctl_idata; 705 return 0; 706 } 707 return EINVAL; 708 } else { 709 node.sysctl_size = 4; 710 return (sysctl_lookup(SYSCTLFN_CALL(&node))); 711 } 712 } 713 714 SYSCTL_SETUP(sysctl_adbkbdtrans_setup, "adbkbd translator setup") 715 { 716 717 sysctl_createv(NULL, 0, NULL, NULL, 718 CTLFLAG_PERMANENT, 719 CTLTYPE_NODE, "machdep", NULL, 720 NULL, 0, NULL, 0, 721 CTL_MACHDEP, CTL_EOL); 722 } 723 #endif /* NWSMOUSE > 0 */ 724