1 /* $NetBSD: adb_kbd.c,v 1.36 2025/06/16 08:00:50 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.36 2025/06/16 08:00:50 macallan Exp $"); 36 37 #ifdef _KERNEL_OPT 38 #include "opt_ddb.h" 39 #endif 40 41 #include <sys/param.h> 42 #include <sys/device.h> 43 #include <sys/sysctl.h> 44 #include <sys/condvar.h> 45 46 #include <dev/wscons/wsconsio.h> 47 #include <dev/wscons/wskbdvar.h> 48 #include <dev/wscons/wsksymdef.h> 49 #include <dev/wscons/wsksymvar.h> 50 #include <dev/wscons/wsmousevar.h> 51 52 #include <dev/sysmon/sysmonvar.h> 53 #include <dev/sysmon/sysmon_taskq.h> 54 55 #include <machine/autoconf.h> 56 57 #include <dev/adb/adbvar.h> 58 #include <dev/adb/adb_keymap.h> 59 60 #include "ioconf.h" 61 62 #include "opt_wsdisplay_compat.h" 63 #include "opt_adbkbd.h" 64 #include "adbdebug.h" 65 #include "wsmouse.h" 66 67 struct adbkbd_softc { 68 device_t sc_dev; 69 struct adb_device *sc_adbdev; 70 struct adb_bus_accessops *sc_ops; 71 device_t sc_wskbddev; 72 #if NWSMOUSE > 0 73 device_t sc_wsmousedev; 74 #endif 75 struct sysmon_pswitch sc_sm_pbutton; 76 int sc_leds; 77 int sc_have_led_control; 78 int sc_power_button_delay; 79 int sc_msg_len; 80 kcondvar_t sc_event; 81 kmutex_t sc_interlock; 82 int sc_poll; 83 int sc_polled_chars; 84 int sc_trans[3]; 85 int sc_capslock; 86 uint32_t sc_timestamp; 87 #ifdef WSDISPLAY_COMPAT_RAWKBD 88 int sc_rawkbd; 89 #endif 90 int sc_emul_usb; 91 bool sc_power_dbg; 92 93 uint32_t sc_power; 94 uint8_t sc_buffer[16]; 95 uint8_t sc_pollbuf[16]; 96 uint8_t sc_us, sc_pe; 97 }; 98 99 /* 100 * Function declarations. 101 */ 102 static int adbkbd_match(device_t, cfdata_t, void *); 103 static void adbkbd_attach(device_t, device_t, void *); 104 105 static void adbkbd_initleds(struct adbkbd_softc *); 106 static void adbkbd_keys(struct adbkbd_softc *, uint8_t, uint8_t); 107 static inline void adbkbd_key(struct adbkbd_softc *, uint8_t); 108 static int adbkbd_wait(struct adbkbd_softc *, int); 109 110 /* Driver definition. */ 111 CFATTACH_DECL_NEW(adbkbd, sizeof(struct adbkbd_softc), 112 adbkbd_match, adbkbd_attach, NULL, NULL); 113 114 static int adbkbd_enable(void *, int); 115 static int adbkbd_ioctl(void *, u_long, void *, int, struct lwp *); 116 static void adbkbd_set_leds(void *, int); 117 static void adbkbd_handler(void *, int, uint8_t *); 118 static void adbkbd_powerbutton(void *); 119 120 struct wskbd_accessops adbkbd_accessops = { 121 adbkbd_enable, 122 adbkbd_set_leds, 123 adbkbd_ioctl, 124 }; 125 126 static void adbkbd_cngetc(void *, u_int *, int *); 127 static void adbkbd_cnpollc(void *, int); 128 129 struct wskbd_consops adbkbd_consops = { 130 adbkbd_cngetc, 131 adbkbd_cnpollc, 132 }; 133 134 struct wskbd_mapdata adbkbd_keymapdata = { 135 akbd_keydesctab, 136 #ifdef ADBKBD_LAYOUT 137 ADBKBD_LAYOUT, 138 #else 139 KB_US | KB_APPLE, 140 #endif 141 }; 142 143 #if NWSMOUSE > 0 144 static int adbkms_enable(void *); 145 static int adbkms_ioctl(void *, u_long, void *, int, struct lwp *); 146 static void adbkms_disable(void *); 147 148 const struct wsmouse_accessops adbkms_accessops = { 149 adbkms_enable, 150 adbkms_ioctl, 151 adbkms_disable, 152 }; 153 154 static int adbkbd_sysctl_mid(SYSCTLFN_ARGS); 155 static int adbkbd_sysctl_right(SYSCTLFN_ARGS); 156 static int adbkbd_sysctl_usb(SYSCTLFN_ARGS); 157 158 #endif /* NWSMOUSE > 0 */ 159 160 static void adbkbd_setup_sysctl(struct adbkbd_softc *); 161 162 #ifdef ADBKBD_DEBUG 163 #define DPRINTF printf 164 #else 165 #define DPRINTF while (0) printf 166 #endif 167 168 static int adbkbd_is_console = 0; 169 static int adbkbd_console_attached = 0; 170 171 static int 172 adbkbd_match(device_t parent, cfdata_t cf, void *aux) 173 { 174 struct adb_attach_args *aaa = aux; 175 176 if (aaa->dev->original_addr == ADBADDR_KBD) 177 return 1; 178 else 179 return 0; 180 } 181 182 static void 183 adbkbd_attach(device_t parent, device_t self, void *aux) 184 { 185 struct adbkbd_softc *sc = device_private(self); 186 struct adb_attach_args *aaa = aux; 187 short cmd; 188 struct wskbddev_attach_args a; 189 #if NWSMOUSE > 0 190 struct wsmousedev_attach_args am; 191 #endif 192 uint8_t buffer[2]; 193 194 sc->sc_dev = self; 195 sc->sc_ops = aaa->ops; 196 sc->sc_adbdev = aaa->dev; 197 sc->sc_adbdev->cookie = sc; 198 sc->sc_adbdev->handler = adbkbd_handler; 199 mutex_init(&sc->sc_interlock, MUTEX_DEFAULT, IPL_NONE); 200 cv_init(&sc->sc_event, "adbkbd"); 201 sc->sc_us = ADBTALK(sc->sc_adbdev->current_addr, 0); 202 203 sc->sc_leds = 0; /* initially off */ 204 sc->sc_have_led_control = 0; 205 206 /* 207 * If this is != 0 then pushing the power button will not immadiately 208 * send a shutdown event to sysmon but instead require another key 209 * press within 5 seconds with a gap of at least two seconds. The 210 * reason to do this is the fact that some PowerBook keyboards, 211 * like the 2400, 3400 and original G3 have their power buttons 212 * right next to the backspace key and it's extremely easy to hit 213 * it by accident. 214 * On most other keyboards the power button is sufficiently far out 215 * of the way so we don't need this. 216 */ 217 sc->sc_power_button_delay = 0; 218 sc->sc_msg_len = 0; 219 sc->sc_poll = 0; 220 sc->sc_capslock = 0; 221 sc->sc_trans[1] = 103; /* F11 */ 222 sc->sc_trans[2] = 111; /* F12 */ 223 224 /* 225 * Most ADB keyboards send 0x7f 0x7f when the power button is pressed. 226 * Some older PowerBooks, like the 3400c, will send a single scancode 227 * 0x7e instead. Unfortunately Fn-Command on some more recent *Books 228 * sends the same scancode, so by default sc_power is set to a value 229 * that can't occur as a scancode and only set to 0x7e on hardware that 230 * needs it 231 */ 232 sc->sc_power = 0xffff; 233 sc->sc_timestamp = 0; 234 sc->sc_emul_usb = ADB_EMUL_USB_NONE; 235 #ifdef ADBKBD_POWER_DDB 236 sc->sc_power_dbg = TRUE; 237 #else 238 sc->sc_power_dbg = FALSE; 239 #endif 240 241 aprint_normal(" addr %d: ", sc->sc_adbdev->current_addr); 242 243 switch (sc->sc_adbdev->handler_id) { 244 case ADB_STDKBD: 245 aprint_normal("standard keyboard\n"); 246 break; 247 case ADB_ISOKBD: 248 aprint_normal("standard keyboard (ISO layout)\n"); 249 break; 250 case ADB_EXTKBD: 251 cmd = ADBTALK(sc->sc_adbdev->current_addr, 1); 252 sc->sc_msg_len = 0; 253 sc->sc_ops->send(sc->sc_ops->cookie, sc->sc_poll, cmd, 0, NULL); 254 adbkbd_wait(sc, 10); 255 256 /* Ignore Logitech MouseMan/Trackman pseudo keyboard */ 257 /* XXX needs testing */ 258 if (sc->sc_buffer[2] == 0x9a && sc->sc_buffer[3] == 0x20) { 259 aprint_normal("Mouseman (non-EMP) pseudo keyboard\n"); 260 return; 261 } else if (sc->sc_buffer[2] == 0x9a && 262 sc->sc_buffer[3] == 0x21) { 263 aprint_normal("Trackman (non-EMP) pseudo keyboard\n"); 264 return; 265 } else { 266 aprint_normal("extended keyboard\n"); 267 adbkbd_initleds(sc); 268 } 269 break; 270 case ADB_EXTISOKBD: 271 aprint_normal("extended keyboard (ISO layout)\n"); 272 adbkbd_initleds(sc); 273 break; 274 case ADB_KBDII: 275 aprint_normal("keyboard II\n"); 276 break; 277 case ADB_ISOKBDII: 278 aprint_normal("keyboard II (ISO layout)\n"); 279 break; 280 case ADB_PBKBD: 281 aprint_normal("PowerBook keyboard\n"); 282 sc->sc_power = 0x7e; 283 sc->sc_power_button_delay = 1; 284 break; 285 case ADB_PBISOKBD: 286 aprint_normal("PowerBook keyboard (ISO layout)\n"); 287 sc->sc_power = 0x7e; 288 sc->sc_power_button_delay = 1; 289 break; 290 case ADB_ADJKPD: 291 aprint_normal("adjustable keypad\n"); 292 break; 293 case ADB_ADJKBD: 294 aprint_normal("adjustable keyboard\n"); 295 break; 296 case ADB_ADJISOKBD: 297 aprint_normal("adjustable keyboard (ISO layout)\n"); 298 break; 299 case ADB_ADJJAPKBD: 300 aprint_normal("adjustable keyboard (Japanese layout)\n"); 301 break; 302 case ADB_PBEXTISOKBD: 303 aprint_normal("PowerBook extended keyboard (ISO layout)\n"); 304 sc->sc_power_button_delay = 1; 305 sc->sc_power = 0x7e; 306 break; 307 case ADB_PBEXTJAPKBD: 308 aprint_normal("PowerBook extended keyboard (Japanese layout)\n"); 309 sc->sc_power_button_delay = 1; 310 sc->sc_power = 0x7e; 311 break; 312 case ADB_JPKBDII: 313 aprint_normal("keyboard II (Japanese layout)\n"); 314 break; 315 case ADB_PBEXTKBD: 316 aprint_normal("PowerBook extended keyboard\n"); 317 sc->sc_power_button_delay = 1; 318 sc->sc_power = 0x7e; 319 break; 320 case ADB_DESIGNKBD: 321 aprint_normal("extended keyboard\n"); 322 adbkbd_initleds(sc); 323 break; 324 case ADB_PBJPKBD: 325 aprint_normal("PowerBook keyboard (Japanese layout)\n"); 326 sc->sc_power_button_delay = 1; 327 sc->sc_power = 0x7e; 328 break; 329 case ADB_PBG3KBD: 330 aprint_normal("PowerBook G3 keyboard\n"); 331 break; 332 case ADB_PBG3JPKBD: 333 aprint_normal("PowerBook G3 keyboard (Japanese layout)\n"); 334 break; 335 case ADB_IBOOKKBD: 336 aprint_normal("iBook keyboard\n"); 337 break; 338 default: 339 aprint_normal("mapped device (%d)\n", sc->sc_adbdev->handler_id); 340 break; 341 } 342 343 /* 344 * try to switch to extended protocol 345 * as in, tell the keyboard to distinguish between left and right 346 * Shift, Control and Alt keys 347 */ 348 cmd = ADBLISTEN(sc->sc_adbdev->current_addr, 3); 349 buffer[0] = sc->sc_adbdev->current_addr; 350 buffer[1] = 3; 351 sc->sc_msg_len = 0; 352 sc->sc_ops->send(sc->sc_ops->cookie, sc->sc_poll, cmd, 2, buffer); 353 adbkbd_wait(sc, 10); 354 355 cmd = ADBTALK(sc->sc_adbdev->current_addr, 3); 356 sc->sc_msg_len = 0; 357 sc->sc_ops->send(sc->sc_ops->cookie, sc->sc_poll, cmd, 0, NULL); 358 adbkbd_wait(sc, 10); 359 if ((sc->sc_msg_len == 4) && (sc->sc_buffer[3] == 3)) { 360 aprint_verbose_dev(sc->sc_dev, "extended protocol enabled\n"); 361 } 362 363 #ifdef ADBKBD_DEBUG 364 cmd = ADBTALK(sc->sc_adbdev->current_addr, 1); 365 sc->sc_msg_len = 0; 366 sc->sc_ops->send(sc->sc_ops->cookie, sc->sc_poll, cmd, 0, NULL); 367 adbkbd_wait(sc, 10); 368 printf("buffer: %02x %02x\n", sc->sc_buffer[0], sc->sc_buffer[1]); 369 #endif 370 371 if (adbkbd_is_console && (adbkbd_console_attached == 0)) { 372 wskbd_cnattach(&adbkbd_consops, sc, &adbkbd_keymapdata); 373 adbkbd_console_attached = 1; 374 a.console = 1; 375 } else { 376 a.console = 0; 377 } 378 a.keymap = &adbkbd_keymapdata; 379 a.accessops = &adbkbd_accessops; 380 a.accesscookie = sc; 381 382 sc->sc_wskbddev = config_found(self, &a, wskbddevprint, 383 CFARGS(.iattr = "wskbddev")); 384 #ifdef ADBKBD_EMUL_USB 385 /* Values from Linux's drivers/macintosh/adbhud.c */ 386 switch (sc->sc_adbdev->handler_id) { 387 case ADB_ISOKBD: /* FALLTHROUGH */ 388 case ADB_EXTISOKBD: /* FALLTHROUGH */ 389 case 0x07: /* FALLTHROUGH */ 390 case ADB_ISOKBDII: /* FALLTHROUGH */ 391 case ADB_PBISOKBD: /* FALLTHROUGH */ 392 case ADB_ADJISOKBD: /* FALLTHROUGH */ 393 case ADB_PBEXTISOKBD: /* FALLTHROUGH */ 394 case 0x19: /* FALLTHROUGH */ 395 case 0x1d: /* FALLTHROUGH */ 396 case 0xc1: /* FALLTHROUGH */ 397 case ADB_IBOOKKBD: /* FALLTHROUGH */ 398 case 0xc7: 399 sc->sc_emul_usb = ADB_EMUL_USB_ISO; 400 wskbd_set_evtrans(sc->sc_wskbddev, adb_to_usb_iso, 128); 401 break; 402 #ifdef notyet 403 case ADB_ADJJAPKBD: /* FALLTHROUGH */ 404 case ADB_PBEXTJAPKBD: /* FALLTHROUGH */ 405 case ADB_JPKBDII: /* FALLTHROUGH */ 406 case 0x17: /* FALLTHROUGH */ 407 case 0x1a: /* FALLTHROUGH */ 408 case ADB_PBJPKBD: /* FALLTHROUGH */ 409 case 0xc2: /* FALLTHROUGH */ 410 case 0xc5: /* FALLTHROUGH */ 411 case 0xc8: /* FALLTHROUGH */ 412 case 0xc9: 413 sc->sc_emul_usb = ADB_EMUL_USB_JIS; 414 wskbd_set_evtrans(sc->sc_wskbddev, adb_to_usb_jis, 128); 415 break; 416 #endif 417 case ADB_STDKBD: /* FALLTHROUGH */ 418 case ADB_EXTKBD: /* FALLTHROUGH */ 419 case 0x03: /* FALLTHROUGH */ 420 case 0x06: /* FALLTHROUGH */ 421 case ADB_KBDII: /* FALLTHROUGH */ 422 case ADB_PBKBD: /* FALLTHROUGH */ 423 case ADB_ADJKBD: /* FALLTHROUGH */ 424 case ADB_PBEXTKBD: /* FALLTHROUGH */ 425 case ADB_DESIGNKBD: /* FALLTHROUGH */ 426 case 0x1c: /* FALLTHROUGH */ 427 case 0xc0: /* FALLTHROUGH */ 428 case ADB_PBG3KBD: /* FALLTHROUGH */ 429 case 0xc6: /* FALLTHROUGH */ 430 default: /* default to ANSI for unknown values */ 431 sc->sc_emul_usb = ADB_EMUL_USB_ANSI; 432 wskbd_set_evtrans(sc->sc_wskbddev, adb_to_usb_ansi, 128); 433 break; 434 } 435 #endif /* ADBKBD_EMUL_USB */ 436 437 #if NWSMOUSE > 0 438 /* attach the mouse device */ 439 am.accessops = &adbkms_accessops; 440 am.accesscookie = sc; 441 sc->sc_wsmousedev = config_found(self, &am, wsmousedevprint, 442 CFARGS(.iattr = "wsmousedev")); 443 #endif 444 adbkbd_setup_sysctl(sc); 445 446 /* finally register the power button */ 447 sysmon_task_queue_init(); 448 memset(&sc->sc_sm_pbutton, 0, sizeof(struct sysmon_pswitch)); 449 sc->sc_sm_pbutton.smpsw_name = device_xname(sc->sc_dev); 450 sc->sc_sm_pbutton.smpsw_type = PSWITCH_TYPE_POWER; 451 if (sysmon_pswitch_register(&sc->sc_sm_pbutton) != 0) 452 aprint_error_dev(sc->sc_dev, 453 "unable to register power button with sysmon\n"); 454 } 455 456 static void 457 adbkbd_handler(void *cookie, int len, uint8_t *data) 458 { 459 struct adbkbd_softc *sc = cookie; 460 461 #ifdef ADBKBD_DEBUG 462 int i; 463 printf("%s: %02x - ", device_xname(sc->sc_dev), sc->sc_us); 464 for (i = 0; i < len; i++) { 465 printf(" %02x", data[i]); 466 } 467 printf("\n"); 468 #endif 469 if (len >= 2) { 470 if (data[1] == sc->sc_us) { 471 adbkbd_keys(sc, data[2], data[3]); 472 return; 473 } else { 474 memcpy(sc->sc_buffer, data, len); 475 } 476 sc->sc_msg_len = len; 477 cv_signal(&sc->sc_event); 478 } else { 479 DPRINTF("bogus message\n"); 480 } 481 } 482 483 static int 484 adbkbd_wait(struct adbkbd_softc *sc, int timeout) 485 { 486 int cnt = 0; 487 488 if (sc->sc_poll) { 489 while (sc->sc_msg_len == 0) { 490 sc->sc_ops->poll(sc->sc_ops->cookie); 491 } 492 } else { 493 mutex_enter(&sc->sc_interlock); 494 while ((sc->sc_msg_len == 0) && (cnt < timeout)) { 495 cv_timedwait(&sc->sc_event, &sc->sc_interlock, hz); 496 cnt++; 497 } 498 mutex_exit(&sc->sc_interlock); 499 } 500 return (sc->sc_msg_len > 0); 501 } 502 503 static void 504 adbkbd_keys(struct adbkbd_softc *sc, uint8_t k1, uint8_t k2) 505 { 506 507 /* keyboard event processing */ 508 509 DPRINTF("[%02x %02x]", k1, k2); 510 511 if (((k1 == k2) && (k1 == 0x7f)) || (k1 == sc->sc_power)) { 512 uint32_t now = time_second; 513 uint32_t diff = now - sc->sc_timestamp; 514 515 sc->sc_timestamp = now; 516 if (((diff > 1) && (diff < 5)) || 517 (sc->sc_power_button_delay == 0)) { 518 #ifdef DDB 519 if (sc->sc_power_dbg) { 520 Debugger(); 521 return; 522 } 523 #endif 524 /* power button, report to sysmon */ 525 sc->sc_pe = k1; 526 sysmon_task_queue_sched(0, adbkbd_powerbutton, sc); 527 } 528 } else { 529 530 adbkbd_key(sc, k1); 531 if (k2 != 0xff) 532 adbkbd_key(sc, k2); 533 } 534 } 535 536 static void 537 adbkbd_powerbutton(void *cookie) 538 { 539 struct adbkbd_softc *sc = cookie; 540 541 sysmon_pswitch_event(&sc->sc_sm_pbutton, 542 ADBK_PRESS(sc->sc_pe) ? PSWITCH_EVENT_PRESSED : 543 PSWITCH_EVENT_RELEASED); 544 545 } 546 547 static inline void 548 adbkbd_key(struct adbkbd_softc *sc, uint8_t k) 549 { 550 551 if (sc->sc_poll) { 552 if (sc->sc_polled_chars >= 16) { 553 aprint_error_dev(sc->sc_dev,"polling buffer is full\n"); 554 } 555 sc->sc_pollbuf[sc->sc_polled_chars] = k; 556 sc->sc_polled_chars++; 557 return; 558 } 559 560 #if NWSMOUSE > 0 561 /* translate some keys to mouse events */ 562 if (sc->sc_wsmousedev != NULL) { 563 if (ADBK_KEYVAL(k) == sc->sc_trans[1]) { 564 wsmouse_input(sc->sc_wsmousedev, ADBK_PRESS(k) ? 2 : 0, 565 0, 0, 0, 0, 566 WSMOUSE_INPUT_DELTA); 567 return; 568 } 569 if (ADBK_KEYVAL(k) == sc->sc_trans[2]) { 570 wsmouse_input(sc->sc_wsmousedev, ADBK_PRESS(k) ? 4 : 0, 571 0, 0, 0, 0, 572 WSMOUSE_INPUT_DELTA); 573 return; 574 } 575 } 576 #endif 577 578 #ifdef WSDISPLAY_COMPAT_RAWKBD 579 if (sc->sc_rawkbd) { 580 char cbuf[2]; 581 int s; 582 583 cbuf[0] = k; 584 585 s = spltty(); 586 wskbd_rawinput(sc->sc_wskbddev, cbuf, 1); 587 splx(s); 588 } else { 589 #endif 590 591 if (ADBK_KEYVAL(k) == 0x39) { 592 /* caps lock - send up and down */ 593 if (ADBK_PRESS(k) != sc->sc_capslock) { 594 sc->sc_capslock = ADBK_PRESS(k); 595 wskbd_input(sc->sc_wskbddev, 596 WSCONS_EVENT_KEY_DOWN, 0x39); 597 wskbd_input(sc->sc_wskbddev, 598 WSCONS_EVENT_KEY_UP, 0x39); 599 } 600 } else { 601 /* normal event */ 602 int type; 603 604 type = ADBK_PRESS(k) ? 605 WSCONS_EVENT_KEY_DOWN : WSCONS_EVENT_KEY_UP; 606 wskbd_input(sc->sc_wskbddev, type, ADBK_KEYVAL(k)); 607 } 608 #ifdef WSDISPLAY_COMPAT_RAWKBD 609 } 610 #endif 611 } 612 613 /* 614 * Set the keyboard LED's. 615 * 616 * Automatically translates from ioctl/softc format to the 617 * actual keyboard register format 618 */ 619 static void 620 adbkbd_set_leds(void *cookie, int leds) 621 { 622 struct adbkbd_softc *sc = cookie; 623 int aleds; 624 short cmd; 625 uint8_t buffer[2]; 626 627 DPRINTF("adbkbd_set_leds: %02x\n", leds); 628 if ((leds & 0x07) == (sc->sc_leds & 0x07)) 629 return; 630 631 if (sc->sc_have_led_control) { 632 633 aleds = (~leds & 0x04) | 3; 634 if (leds & 1) 635 aleds &= ~2; 636 if (leds & 2) 637 aleds &= ~1; 638 639 buffer[0] = 0xff; 640 buffer[1] = aleds | 0xf8; 641 642 cmd = ADBLISTEN(sc->sc_adbdev->current_addr, 2); 643 sc->sc_ops->send(sc->sc_ops->cookie, sc->sc_poll, cmd, 2, 644 buffer); 645 } 646 647 sc->sc_leds = leds & 7; 648 } 649 650 static void 651 adbkbd_initleds(struct adbkbd_softc *sc) 652 { 653 short cmd; 654 655 /* talk R2 */ 656 cmd = ADBTALK(sc->sc_adbdev->current_addr, 2); 657 sc->sc_msg_len = 0; 658 sc->sc_ops->send(sc->sc_ops->cookie, sc->sc_poll, cmd, 0, NULL); 659 if (!adbkbd_wait(sc, 10)) { 660 aprint_error_dev(sc->sc_dev, "unable to read LED state\n"); 661 return; 662 } 663 sc->sc_have_led_control = 1; 664 DPRINTF("have LED control\n"); 665 return; 666 } 667 668 static int 669 adbkbd_enable(void *v, int on) 670 { 671 return 0; 672 } 673 674 static int 675 adbkbd_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l) 676 { 677 struct adbkbd_softc *sc = (struct adbkbd_softc *) v; 678 679 switch (cmd) { 680 681 case WSKBDIO_GTYPE: 682 if (sc->sc_emul_usb != ADB_EMUL_USB_NONE) { 683 *(int *)data = WSKBD_TYPE_USB; 684 } else { 685 *(int *)data = WSKBD_TYPE_ADB; 686 } 687 return 0; 688 case WSKBDIO_SETLEDS: 689 adbkbd_set_leds(sc, *(int *)data); 690 return 0; 691 case WSKBDIO_GETLEDS: 692 *(int *)data = sc->sc_leds; 693 return 0; 694 #ifdef WSDISPLAY_COMPAT_RAWKBD 695 case WSKBDIO_SETMODE: 696 sc->sc_rawkbd = *(int *)data == WSKBD_RAW; 697 return 0; 698 #endif 699 } 700 701 return EPASSTHROUGH; 702 } 703 704 int 705 adbkbd_cnattach(void) 706 { 707 708 adbkbd_is_console = 1; 709 return 0; 710 } 711 712 static void 713 adbkbd_cngetc(void *v, u_int *type, int *data) 714 { 715 struct adbkbd_softc *sc = v; 716 int key, press, val; 717 int s; 718 719 s = splhigh(); 720 721 KASSERT(sc->sc_poll); 722 723 DPRINTF("polling..."); 724 while (sc->sc_polled_chars == 0) { 725 sc->sc_ops->poll(sc->sc_ops->cookie); 726 } 727 DPRINTF(" got one\n"); 728 splx(s); 729 730 key = sc->sc_pollbuf[0]; 731 sc->sc_polled_chars--; 732 memmove(sc->sc_pollbuf, sc->sc_pollbuf + 1, 733 sc->sc_polled_chars); 734 735 press = ADBK_PRESS(key); 736 val = ADBK_KEYVAL(key); 737 738 *data = val; 739 *type = press ? WSCONS_EVENT_KEY_DOWN : WSCONS_EVENT_KEY_UP; 740 } 741 742 static void 743 adbkbd_cnpollc(void *v, int on) 744 { 745 struct adbkbd_softc *sc = v; 746 747 sc->sc_poll = on; 748 if (!on) { 749 int i; 750 751 /* feed the poll buffer's content to wskbd */ 752 for (i = 0; i < sc->sc_polled_chars; i++) { 753 adbkbd_key(sc, sc->sc_pollbuf[i]); 754 } 755 sc->sc_polled_chars = 0; 756 } 757 } 758 759 #if NWSMOUSE > 0 760 /* stuff for the pseudo mouse */ 761 static int 762 adbkms_enable(void *v) 763 { 764 return 0; 765 } 766 767 static int 768 adbkms_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l) 769 { 770 771 switch (cmd) { 772 case WSMOUSEIO_GTYPE: 773 *(u_int *)data = WSMOUSE_TYPE_PSEUDO; 774 break; 775 776 default: 777 return (EPASSTHROUGH); 778 } 779 return (0); 780 } 781 782 static void 783 adbkms_disable(void *v) 784 { 785 } 786 787 static int 788 adbkbd_sysctl_mid(SYSCTLFN_ARGS) 789 { 790 struct sysctlnode node = *rnode; 791 struct adbkbd_softc *sc=(struct adbkbd_softc *)node.sysctl_data; 792 const int *np = newp; 793 int reg; 794 795 DPRINTF("adbkbd_sysctl_mid\n"); 796 reg = sc->sc_trans[1]; 797 if (np) { 798 /* we're asked to write */ 799 node.sysctl_data = ® 800 if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) { 801 802 sc->sc_trans[1] = *(int *)node.sysctl_data; 803 return 0; 804 } 805 return EINVAL; 806 } else { 807 node.sysctl_data = ® 808 node.sysctl_size = 4; 809 return (sysctl_lookup(SYSCTLFN_CALL(&node))); 810 } 811 } 812 813 static int 814 adbkbd_sysctl_right(SYSCTLFN_ARGS) 815 { 816 struct sysctlnode node = *rnode; 817 struct adbkbd_softc *sc=(struct adbkbd_softc *)node.sysctl_data; 818 const int *np = newp; 819 int reg; 820 821 DPRINTF("adbkbd_sysctl_right\n"); 822 reg = sc->sc_trans[2]; 823 if (np) { 824 /* we're asked to write */ 825 node.sysctl_data = ® 826 if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) { 827 828 sc->sc_trans[2] = *(int *)node.sysctl_data; 829 return 0; 830 } 831 return EINVAL; 832 } else { 833 node.sysctl_data = ® 834 node.sysctl_size = 4; 835 return (sysctl_lookup(SYSCTLFN_CALL(&node))); 836 } 837 } 838 839 #endif /* NWSMOUSE > 0 */ 840 841 static int 842 adbkbd_sysctl_usb(SYSCTLFN_ARGS) 843 { 844 struct sysctlnode node = *rnode; 845 struct adbkbd_softc *sc=(struct adbkbd_softc *)node.sysctl_data; 846 const int *np = newp; 847 int reg; 848 849 DPRINTF("%s\n", __func__); 850 reg = sc->sc_emul_usb; 851 if (np) { 852 /* we're asked to write */ 853 node.sysctl_data = ® 854 if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) { 855 856 sc->sc_emul_usb = *(int *)node.sysctl_data; 857 switch (sc->sc_emul_usb) { 858 case ADB_EMUL_USB_NONE: 859 wskbd_set_evtrans(sc->sc_wskbddev, NULL, 0); 860 break; 861 case ADB_EMUL_USB_ANSI: 862 wskbd_set_evtrans(sc->sc_wskbddev, 863 adb_to_usb_ansi, 128); 864 break; 865 case ADB_EMUL_USB_ISO: 866 wskbd_set_evtrans(sc->sc_wskbddev, 867 adb_to_usb_iso, 128); 868 break; 869 case ADB_EMUL_USB_JIS: 870 wskbd_set_evtrans(sc->sc_wskbddev, 871 adb_to_usb_jis, 128); 872 break; 873 default: 874 return EINVAL; 875 break; 876 } 877 return 0; 878 } 879 return EINVAL; 880 } else { 881 node.sysctl_data = ® 882 node.sysctl_size = sizeof(reg); 883 return (sysctl_lookup(SYSCTLFN_CALL(&node))); 884 } 885 } 886 887 static int 888 adbkbd_sysctl_dbg(SYSCTLFN_ARGS) 889 { 890 struct sysctlnode node = *rnode; 891 struct adbkbd_softc *sc=(struct adbkbd_softc *)node.sysctl_data; 892 const int *np = newp; 893 bool reg; 894 895 DPRINTF("%s\n", __func__); 896 reg = sc->sc_power_dbg; 897 if (np) { 898 /* we're asked to write */ 899 node.sysctl_data = ® 900 if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) { 901 902 sc->sc_power_dbg = *(bool *)node.sysctl_data; 903 return 0; 904 } 905 return EINVAL; 906 } else { 907 node.sysctl_data = ® 908 node.sysctl_size = sizeof(reg); 909 return (sysctl_lookup(SYSCTLFN_CALL(&node))); 910 } 911 } 912 913 static void 914 adbkbd_setup_sysctl(struct adbkbd_softc *sc) 915 { 916 const struct sysctlnode *me, *node; 917 int ret; 918 919 DPRINTF("%s: sysctl setup\n", device_xname(sc->sc_dev)); 920 ret = sysctl_createv(NULL, 0, NULL, &me, 921 CTLFLAG_READWRITE, 922 CTLTYPE_NODE, device_xname(sc->sc_dev), NULL, 923 NULL, 0, NULL, 0, 924 CTL_MACHDEP, CTL_CREATE, CTL_EOL); 925 ret = sysctl_createv(NULL, 0, NULL, 926 (void *)&node, 927 CTLFLAG_READWRITE | CTLFLAG_OWNDESC, 928 CTLTYPE_INT, "emulate_usb", "USB keyboard emulation", 929 adbkbd_sysctl_usb, 1, (void *)sc, 0, CTL_MACHDEP, 930 me->sysctl_num, CTL_CREATE, CTL_EOL); 931 ret = sysctl_createv(NULL, 0, NULL, 932 (void *)&node, 933 CTLFLAG_READWRITE | CTLFLAG_OWNDESC, 934 CTLTYPE_BOOL, "power_ddb", "power button triggers ddb", 935 adbkbd_sysctl_dbg, 1, (void *)sc, 0, CTL_MACHDEP, 936 me->sysctl_num, CTL_CREATE, CTL_EOL); 937 #if NWSMOUSE > 0 938 if (sc->sc_wsmousedev != NULL) { 939 ret = sysctl_createv(NULL, 0, NULL, 940 (void *)&node, 941 CTLFLAG_READWRITE | CTLFLAG_OWNDESC, 942 CTLTYPE_INT, "middle", "middle mouse button", 943 adbkbd_sysctl_mid, 1, (void *)sc, 0, CTL_MACHDEP, 944 me->sysctl_num, CTL_CREATE, CTL_EOL); 945 946 ret = sysctl_createv(NULL, 0, NULL, 947 (void *)&node, 948 CTLFLAG_READWRITE | CTLFLAG_OWNDESC, 949 CTLTYPE_INT, "right", "right mouse button", 950 adbkbd_sysctl_right, 2, (void *)sc, 0, CTL_MACHDEP, 951 me->sysctl_num, CTL_CREATE, CTL_EOL); 952 } 953 #endif /* NWSMOUSE > 0 */ 954 955 (void)ret; 956 } 957 958 SYSCTL_SETUP(sysctl_adbkbdtrans_setup, "adbkbd translator setup") 959 { 960 961 sysctl_createv(NULL, 0, NULL, NULL, 962 CTLFLAG_PERMANENT, 963 CTLTYPE_NODE, "machdep", NULL, 964 NULL, 0, NULL, 0, 965 CTL_MACHDEP, CTL_EOL); 966 } 967