1 /* $NetBSD: dnkbd.c,v 1.16 2025/05/27 18:44:31 tsutsui Exp $ */ 2 /* $OpenBSD: dnkbd.c,v 1.17 2009/07/23 21:05:56 blambert Exp $ */ 3 4 /* 5 * Copyright (c) 2005, Miodrag Vallat 6 * Copyright (c) 1997 Michael Smith. 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 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 /* 31 * Driver for the Apollo Domain keyboard and mouse. 32 * 33 * Random notes on the Apollo keyboard : 34 * 35 * - Powers up in 'cooked' mode, where the alpha keys generate ascii rather 36 * than make/break codes. Other keys seem to behave OK though. 37 * 38 * - Alt L/R keys generate two-byte sequence : 39 * make break 40 * L 0xfe,2 0xfe,3 41 * R 0xfe,0 0xfe,1 42 * 43 * - Mouse activity shows up inline in 4-byte packets introduced with 0xdf. 44 * Byte 1 is 1MRL0000 where M, R, L are the mouse buttons, and 0 is 45 * down, 1 is up. 46 * Byte 2 is 2's complement X movement, +ve to the right. 47 * Byte 3 is 2's complement Y movement, +ve is up. 48 * 49 * - Keyboard recognises commands sent to it, all preceded by 0xff. Commands 50 * are echoed once sent completely. 51 * 52 * 0x00 go to cooked mode. 53 * 0x01 go to 'raw' (scancode) mode. 54 * 0x12,0x21 status report as <id1>\r<id2>\r<model>\r followed by 0xff 55 * and then the cooked/raw status. 56 * 0x21,0x81 beep on 57 * 0x21,0x82 beep off 58 * 59 * Some version examples : 60 * 61 * <3-@> <1-0> <SD-03687-MS> Apollo p/n 007121 REV 00 ('old-style' US layout) 62 * <3-@> <2-0> <SD-03683-MS> Apollo p/n 007121 REV 01 ('old-style' US layout) 63 * <3-@> <2-0> <SD-03980-MS> Apollo 3500? keyboard. 64 * <3-@> <X-X> <RX-60857-HW> HP p/n A1630-82001 R2 65 * ('new-style' off 425t, US layout), 66 * also Apollo p/n 014555-002 67 * ('new-style' off DN5500, US layout). 68 */ 69 70 #include "opt_wsdisplay_compat.h" 71 72 #include "wsdisplay.h" 73 #include "wsmouse.h" 74 75 #include <sys/param.h> 76 #include <sys/systm.h> 77 #include <sys/device.h> 78 #include <sys/ioctl.h> 79 #include <sys/kernel.h> 80 #include <sys/callout.h> 81 #include <sys/conf.h> 82 #include <sys/bus.h> 83 #include <sys/cpu.h> 84 85 #include <machine/autoconf.h> 86 87 #include <dev/cons.h> 88 89 #include <dev/wscons/wsconsio.h> 90 #include <dev/wscons/wskbdvar.h> 91 #include <dev/wscons/wsksymdef.h> 92 #include <dev/wscons/wsksymvar.h> 93 #if NWSDISPLAY > 0 94 #include <dev/wscons/wsdisplayvar.h> 95 #endif 96 #if NWSMOUSE > 0 97 #include <dev/wscons/wsmousevar.h> 98 #endif 99 100 #include <dev/ic/ns16550reg.h> 101 #include <dev/ic/comreg.h> 102 103 #include <hp300/dev/dnkbdmap.h> 104 #include <hp300/dev/frodoreg.h> 105 #include <hp300/dev/frodovar.h> 106 107 #include "hilkbd.h" 108 #include "ioconf.h" 109 110 /* 111 * Keyboard key codes 112 */ 113 114 #define DNKEY_CAPSLOCK 0x7e 115 #define DNKEY_REPEAT 0x7f 116 #define DNKEY_RELEASE 0x80 117 #define DNKEY_CHANNEL 0xff 118 119 /* 120 * Channels 121 */ 122 123 #define DNCHANNEL_RESET 0x00 124 #define DNCHANNEL_KBD 0x01 125 #define DNCHANNEL_MOUSE 0x02 126 127 /* 128 * Keyboard modes 129 */ 130 131 #define DNMODE_COOKED 0x00 132 #define DNMODE_RAW 0x01 133 134 /* 135 * Keyboard commands 136 */ 137 138 #define DNCMD_PREFIX 0xff 139 #define DNCMD_COOKED DNMODE_COOKED 140 #define DNCMD_RAW DNMODE_RAW 141 #define DNCMD_IDENT_1 0x12 142 #define DNCMD_IDENT_2 0x21 143 144 /* 145 * Bell commands 146 */ 147 148 #define DNCMD_BELL 0x21 149 #define DNCMD_BELL_ON 0x81 150 #define DNCMD_BELL_OFF 0x82 151 152 /* 153 * Mouse status 154 */ 155 156 #define DNBUTTON_L 0x10 157 #define DNBUTTON_R 0x20 158 #define DNBUTTON_M 0x40 159 160 struct dnkbd_softc { 161 device_t sc_dev; 162 bus_space_tag_t sc_bst; 163 bus_space_handle_t sc_bsh; 164 165 int sc_flags; 166 #define SF_ENABLED 0x01 /* keyboard enabled */ 167 #define SF_CONSOLE 0x02 /* keyboard is console */ 168 #define SF_POLLING 0x04 /* polling mode */ 169 #define SF_PLUGGED 0x08 /* keyboard has been seen plugged */ 170 #define SF_ATTACHED 0x10 /* subdevices have been attached */ 171 #define SF_MOUSE 0x20 /* mouse enabled */ 172 #define SF_BELL 0x40 /* bell is active */ 173 #define SF_BELL_TMO 0x80 /* bell stop timeout is scheduled */ 174 175 u_int sc_identlen; 176 #define MAX_IDENTLEN 32 177 char sc_ident[MAX_IDENTLEN]; 178 kbd_t sc_layout; 179 180 enum { STATE_KEYBOARD, STATE_MOUSE, STATE_CHANNEL, STATE_ECHO } 181 sc_state, sc_prevstate; 182 u_int sc_echolen; 183 184 uint8_t sc_mousepkt[3]; /* mouse packet being constructed */ 185 u_int sc_mousepos; /* index in above */ 186 187 struct callout sc_bellstop_tmo; 188 189 device_t sc_wskbddev; 190 #if NWSMOUSE > 0 191 device_t sc_wsmousedev; 192 #endif 193 194 #ifdef WSDISPLAY_COMPAT_RAWKBD 195 int sc_rawkbd; 196 #endif 197 }; 198 199 static int dnkbd_match(device_t, cfdata_t, void *); 200 static void dnkbd_attach(device_t, device_t, void *); 201 202 CFATTACH_DECL_NEW(dnkbd, sizeof(struct dnkbd_softc), 203 dnkbd_match, dnkbd_attach, NULL, NULL); 204 205 static void dnkbd_init(struct dnkbd_softc *, uint16_t, uint16_t); 206 static int dnkbd_enable(void *, int); 207 static void dnkbd_set_leds(void *, int); 208 static int dnkbd_ioctl(void *, u_long, void *, int, struct lwp *); 209 210 static const struct wskbd_accessops dnkbd_accessops = { 211 .enable = dnkbd_enable, 212 .set_leds = dnkbd_set_leds, 213 .ioctl = dnkbd_ioctl 214 }; 215 216 #if NWSMOUSE > 0 217 static int dnmouse_enable(void *); 218 static int dnmouse_ioctl(void *, u_long, void *, int, struct lwp *); 219 static void dnmouse_disable(void *); 220 221 static const struct wsmouse_accessops dnmouse_accessops = { 222 dnmouse_enable, 223 dnmouse_ioctl, 224 dnmouse_disable 225 }; 226 #endif 227 228 static void dnkbd_bell(void *, u_int, u_int, u_int); 229 static void dnkbd_cngetc(void *, u_int *, int *); 230 static void dnkbd_cnpollc(void *, int); 231 232 static const struct wskbd_consops dnkbd_consops = { 233 .getc = dnkbd_cngetc, 234 .pollc = dnkbd_cnpollc, 235 .bell = dnkbd_bell 236 }; 237 238 static struct wskbd_mapdata dnkbd_keymapdata = { 239 .keydesc = dnkbd_keydesctab, 240 .layout = 241 #ifdef DNKBD_LAYOUT 242 DNKBD_LAYOUT 243 #else 244 KB_US 245 #endif 246 }; 247 248 typedef enum { EVENT_NONE, EVENT_KEYBOARD, EVENT_MOUSE } dnevent; 249 250 #define APCIBRD(x) (500000 / (x)) 251 252 static void dnevent_kbd(struct dnkbd_softc *, int); 253 static void dnevent_kbd_internal(struct dnkbd_softc *, int); 254 static void dnevent_mouse(struct dnkbd_softc *, uint8_t *); 255 static void dnkbd_attach_subdevices(struct dnkbd_softc *); 256 static void dnkbd_bellstop(void *); 257 static void dnkbd_decode(int, u_int *, int *); 258 static dnevent dnkbd_input(struct dnkbd_softc *, int); 259 static int dnkbd_intr(void *); 260 static int dnkbd_pollin(struct dnkbd_softc *, u_int); 261 static int dnkbd_pollout(struct dnkbd_softc *, int); 262 static int dnkbd_probe(struct dnkbd_softc *); 263 static int dnkbd_send(struct dnkbd_softc *, const uint8_t *, size_t); 264 static void dnkbd_break(struct dnkbd_softc *, int); 265 266 int 267 dnkbd_match(device_t parent, cfdata_t cf, void *aux) 268 { 269 struct frodo_attach_args *fa = aux; 270 271 if (strcmp(fa->fa_name, dnkbd_cd.cd_name) != 0) 272 return 0; 273 274 if (machineid == HP_382) { 275 /* 382 has frodo but no Domain keyboard connector. */ 276 return 0; 277 } 278 279 /* only attach to the first frodo port */ 280 return fa->fa_offset == FRODO_APCI_OFFSET(0); 281 } 282 283 void 284 dnkbd_attach(device_t parent, device_t self, void *aux) 285 { 286 struct dnkbd_softc *sc = device_private(self); 287 struct frodo_attach_args *fa = aux; 288 289 aprint_normal(": "); 290 291 sc->sc_dev = self; 292 sc->sc_bst = fa->fa_bst; 293 if (bus_space_map(sc->sc_bst, fa->fa_base + fa->fa_offset, 294 FRODO_APCISPACE, 0, &sc->sc_bsh) != 0) { 295 aprint_error(": can't map i/o space\n"); 296 return; 297 } 298 299 callout_init(&sc->sc_bellstop_tmo, 0); 300 callout_setfunc(&sc->sc_bellstop_tmo, dnkbd_bellstop, sc); 301 302 /* reset the port */ 303 dnkbd_init(sc, 1200, LCR_8BITS | LCR_PEVEN | LCR_PENAB); 304 305 frodo_intr_establish(parent, dnkbd_intr, sc, fa->fa_line, ISRPRI_TTY); 306 307 /* send break to reset keyboard state */ 308 dnkbd_break(sc, 1); 309 delay(10 * 1000); /* 10ms for 12 space bits */ 310 dnkbd_break(sc, 0); 311 delay(10 * 1000); 312 313 /* probe for keyboard */ 314 if (dnkbd_probe(sc) != 0) { 315 aprint_normal("no keyboard\n"); 316 return; 317 } 318 319 dnkbd_attach_subdevices(sc); 320 } 321 322 void 323 dnkbd_init(struct dnkbd_softc *sc, uint16_t rate, uint16_t lctl) 324 { 325 bus_space_tag_t bst; 326 bus_space_handle_t bsh; 327 u_int divisor; 328 329 bst = sc->sc_bst; 330 bsh = sc->sc_bsh; 331 332 divisor = APCIBRD(rate); 333 bus_space_write_1(bst, bsh, com_lctl, LCR_DLAB); 334 bus_space_write_1(bst, bsh, com_dlbl, divisor & 0xff); 335 bus_space_write_1(bst, bsh, com_dlbh, (divisor >> 8) & 0xff); 336 bus_space_write_1(bst, bsh, com_lctl, lctl); 337 bus_space_write_1(bst, bsh, com_ier, IER_ERXRDY | IER_ETXRDY); 338 bus_space_write_1(bst, bsh, com_fifo, 339 FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_1); 340 bus_space_write_1(bst, bsh, com_mcr, MCR_DTR | MCR_RTS); 341 342 delay(100); 343 (void)bus_space_read_1(bst, bsh, com_iir); 344 } 345 346 void 347 dnkbd_attach_subdevices(struct dnkbd_softc *sc) 348 { 349 struct wskbddev_attach_args ka; 350 #if NWSMOUSE > 0 351 struct wsmousedev_attach_args ma; 352 #endif 353 #if NHILKBD > 0 354 extern int hil_is_console; 355 #endif 356 357 /* 358 * If both hilkbd and dnkbd are configured, prefer the Domain 359 * keyboard as console (if we are here, we know the keyboard is 360 * plugged), unless the console keyboard has been claimed already 361 * (i.e. late hotplug with hil keyboard plugged first). 362 */ 363 #if NWSDISPLAY > 0 364 if (cn_tab->cn_putc == wsdisplay_cnputc) { 365 #if NHILKBD > 0 366 if (hil_is_console == -1) { 367 ka.console = 1; 368 hil_is_console = 0; 369 } else 370 ka.console = 0; 371 #else 372 ka.console = 1; 373 #endif 374 } else 375 #endif 376 { 377 ka.console = 0; 378 } 379 380 ka.keymap = &dnkbd_keymapdata; 381 ka.accessops = &dnkbd_accessops; 382 ka.accesscookie = sc; 383 #ifndef DKKBD_LAYOUT 384 dnkbd_keymapdata.layout = sc->sc_layout; 385 #endif 386 387 if (ka.console) { 388 sc->sc_flags = SF_PLUGGED | SF_CONSOLE | SF_ENABLED; 389 wskbd_cnattach(&dnkbd_consops, sc, &dnkbd_keymapdata); 390 } else { 391 sc->sc_flags = SF_PLUGGED; 392 } 393 394 sc->sc_wskbddev = config_found(sc->sc_dev, &ka, wskbddevprint, 395 CFARGS(.iattr = "wskbddev")); 396 397 #if NWSMOUSE > 0 398 ma.accessops = &dnmouse_accessops; 399 ma.accesscookie = sc; 400 401 sc->sc_wsmousedev = config_found(sc->sc_dev, &ma, wsmousedevprint, 402 CFARGS(.iattr = "wsmousedev")); 403 #endif 404 405 SET(sc->sc_flags, SF_ATTACHED); 406 } 407 408 int 409 dnkbd_probe(struct dnkbd_softc *sc) 410 { 411 int dat, rc, flags; 412 uint8_t cmdbuf[2]; 413 char rspbuf[MAX_IDENTLEN], *word, *end; 414 u_int i; 415 int s; 416 417 s = spltty(); 418 flags = sc->sc_flags; 419 SET(sc->sc_flags, SF_POLLING); 420 sc->sc_state = STATE_CHANNEL; 421 splx(s); 422 423 /* 424 * Switch keyboard to raw mode. 425 */ 426 cmdbuf[0] = DNCMD_RAW; 427 rc = dnkbd_send(sc, cmdbuf, 1); 428 if (rc != 0) 429 goto out; 430 431 /* 432 * Send the identify command. 433 */ 434 cmdbuf[0] = DNCMD_IDENT_1; 435 cmdbuf[1] = DNCMD_IDENT_2; 436 rc = dnkbd_send(sc, cmdbuf, 2); 437 if (rc != 0) 438 goto out; 439 440 for (i = 0; ; i++) { 441 dat = dnkbd_pollin(sc, 10000); 442 if (dat == -1) 443 break; 444 445 if (i < sizeof(rspbuf)) 446 rspbuf[i] = dat; 447 } 448 449 if (i > sizeof(rspbuf) || i == 0) { 450 aprint_error_dev(sc->sc_dev, 451 "unexpected identify string length %d\n", i); 452 rc = ENXIO; 453 goto out; 454 } 455 456 /* 457 * Make sure the identification string is NULL terminated 458 * (overwriting the keyboard mode byte if necessary). 459 */ 460 i--; 461 if (rspbuf[i] != 0) 462 rspbuf[i] = 0; 463 464 /* 465 * Now display the identification strings, if they changed. 466 */ 467 if (i != sc->sc_identlen || memcmp(rspbuf, sc->sc_ident, i) != 0) { 468 sc->sc_layout = KB_US; 469 sc->sc_identlen = i; 470 memcpy(sc->sc_ident, rspbuf, i); 471 472 if (cold == 0) 473 aprint_normal_dev(sc->sc_dev, ""); 474 aprint_normal("model "); 475 word = rspbuf; 476 for (i = 0; i < 3; i++) { 477 end = strchr(word, '\r'); 478 if (end == NULL) 479 break; 480 *end++ = '\0'; 481 aprint_normal("<%s> ", word); 482 /* 483 * Parse the layout code if applicable 484 */ 485 if (i == 1 && *word++ == '3') { 486 if (*word == '-') 487 word++; 488 switch (*word) { 489 #if 0 490 default: 491 case ' ': 492 sc->sc_layout = KB_US; 493 break; 494 #endif 495 case 'a': 496 sc->sc_layout = KB_DE; 497 break; 498 case 'b': 499 sc->sc_layout = KB_FR; 500 break; 501 case 'c': 502 sc->sc_layout = KB_DK; 503 break; 504 case 'd': 505 sc->sc_layout = KB_SV; 506 break; 507 case 'e': 508 sc->sc_layout = KB_UK; 509 break; 510 case 'f': 511 sc->sc_layout = KB_JP; 512 break; 513 case 'g': 514 sc->sc_layout = KB_SG; 515 break; 516 } 517 } 518 word = end; 519 } 520 aprint_normal("\n"); 521 } 522 523 /* 524 * Ready to work, the default channel is the keyboard. 525 */ 526 sc->sc_state = STATE_KEYBOARD; 527 528 out: 529 s = spltty(); 530 sc->sc_flags = flags; 531 splx(s); 532 533 return rc; 534 } 535 536 /* 537 * State machine. 538 * 539 * In raw mode, the keyboard may feed us the following sequences: 540 * - on the keyboard channel: 541 * + a raw key code, in the range 0x01-0x7e, or'ed with 0x80 if key release. 542 * + the key repeat sequence 0x7f. 543 * - on the mouse channel: 544 * + a 3 byte mouse sequence (buttons state, dx move, dy move). 545 * - at any time: 546 * + a 2 byte channel sequence (0xff followed by the channel number) telling 547 * us which device the following input will come from. 548 * + if we get 0xff but an invalid channel number, this is a command echo. 549 * Currently we only handle this for bell commands, which size are known. 550 * Other commands are issued through dnkbd_send() which ``eats'' the echo. 551 * 552 * Older keyboards reset the channel to the keyboard (by sending ff 01) after 553 * every mouse packet. 554 */ 555 556 dnevent 557 dnkbd_input(struct dnkbd_softc *sc, int dat) 558 { 559 dnevent event = EVENT_NONE; 560 561 switch (sc->sc_state) { 562 case STATE_KEYBOARD: 563 switch (dat) { 564 case DNKEY_REPEAT: 565 /* 566 * We ignore event repeats, as wskbd does its own 567 * soft repeat processing. 568 */ 569 break; 570 case DNKEY_CHANNEL: 571 sc->sc_prevstate = sc->sc_state; 572 sc->sc_state = STATE_CHANNEL; 573 break; 574 default: 575 event = EVENT_KEYBOARD; 576 break; 577 } 578 break; 579 580 case STATE_MOUSE: 581 if (dat == DNKEY_CHANNEL && sc->sc_mousepos == 0) { 582 sc->sc_prevstate = sc->sc_state; 583 sc->sc_state = STATE_CHANNEL; 584 } else { 585 sc->sc_mousepkt[sc->sc_mousepos++] = dat; 586 if (sc->sc_mousepos == sizeof(sc->sc_mousepkt)) { 587 sc->sc_mousepos = 0; 588 event = EVENT_MOUSE; 589 } 590 } 591 break; 592 593 case STATE_CHANNEL: 594 switch (dat) { 595 case DNKEY_CHANNEL: 596 /* 597 * During hotplug, we might get spurious 0xff bytes. 598 * Ignore them. 599 */ 600 break; 601 case DNCHANNEL_RESET: 602 /* 603 * Identify the keyboard again. This will switch it to 604 * raw mode again. If this fails, we'll consider the 605 * keyboard as unplugged (to ignore further events until 606 * a successful reset). 607 */ 608 if (dnkbd_probe(sc) == 0) { 609 /* 610 * We need to attach wskbd and wsmouse children 611 * if this is a live first plug. 612 */ 613 if (!ISSET(sc->sc_flags, SF_ATTACHED)) 614 dnkbd_attach_subdevices(sc); 615 SET(sc->sc_flags, SF_PLUGGED); 616 } else { 617 CLR(sc->sc_flags, SF_PLUGGED); 618 } 619 620 sc->sc_state = STATE_KEYBOARD; 621 break; 622 case DNCHANNEL_KBD: 623 sc->sc_state = STATE_KEYBOARD; 624 break; 625 case DNCHANNEL_MOUSE: 626 sc->sc_state = STATE_MOUSE; 627 sc->sc_mousepos = 0; /* just in case */ 628 break; 629 case DNCMD_BELL: 630 /* 631 * We are getting a bell command echoed to us. 632 * Ignore it. 633 */ 634 sc->sc_state = STATE_ECHO; 635 sc->sc_echolen = 1; /* one byte to follow */ 636 break; 637 default: 638 printf("%s: unexpected channel byte %02x\n", 639 device_xname(sc->sc_dev), dat); 640 break; 641 } 642 break; 643 644 case STATE_ECHO: 645 if (--sc->sc_echolen == 0) { 646 /* get back to the state we were in before the echo */ 647 sc->sc_state = sc->sc_prevstate; 648 } 649 break; 650 } 651 652 return event; 653 } 654 655 /* 656 * Event breakers. 657 */ 658 659 void 660 dnkbd_decode(int keycode, u_int *type, int *key) 661 { 662 *type = (keycode & DNKEY_RELEASE) ? 663 WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN; 664 *key = (keycode & ~DNKEY_RELEASE); 665 } 666 667 void 668 dnevent_kbd(struct dnkbd_softc *sc, int dat) 669 { 670 if (!ISSET(sc->sc_flags, SF_PLUGGED)) 671 return; 672 673 if (sc->sc_wskbddev == NULL) 674 return; 675 676 if (!ISSET(sc->sc_flags, SF_ENABLED)) 677 return; 678 679 /* 680 * Even in raw mode, the caps lock key is treated specially: 681 * first key press causes event 0x7e, release causes no event; 682 * then a new key press causes nothing, and release causes 683 * event 0xfe. Moreover, while kept down, it does not produce 684 * repeat events. 685 * 686 * So the best we can do is fake the missed events, but this 687 * will not allow the capslock key to be remapped as a control 688 * key since it will not be possible to chord it with anything. 689 */ 690 dnevent_kbd_internal(sc, dat); 691 if ((dat & ~DNKEY_RELEASE) == DNKEY_CAPSLOCK) 692 dnevent_kbd_internal(sc, dat ^ DNKEY_RELEASE); 693 } 694 695 void 696 dnevent_kbd_internal(struct dnkbd_softc *sc, int dat) 697 { 698 u_int type; 699 int key; 700 int s; 701 702 dnkbd_decode(dat, &type, &key); 703 704 #ifdef WSDISPLAY_COMPAT_RAWKBD 705 if (sc->sc_rawkbd) { 706 u_char cbuf[2]; 707 int c, j; 708 709 j = 0; 710 c = dnkbd_raw[key]; 711 if (c != 0) { 712 /* fake extended scancode if necessary */ 713 if (c & 0x80) 714 cbuf[j++] = 0xe0; 715 cbuf[j] = c & 0x7f; 716 if (type == WSCONS_EVENT_KEY_UP) 717 cbuf[j] |= 0x80; 718 j++; 719 } 720 721 if (j != 0) { 722 s = spltty(); 723 wskbd_rawinput(sc->sc_wskbddev, cbuf, j); 724 splx(s); 725 } 726 } else 727 #endif 728 { 729 s = spltty(); 730 wskbd_input(sc->sc_wskbddev, type, key); 731 splx(s); 732 } 733 } 734 735 #if NWSMOUSE > 0 736 void 737 dnevent_mouse(struct dnkbd_softc *sc, uint8_t *dat) 738 { 739 if (!ISSET(sc->sc_flags, SF_PLUGGED)) 740 return; 741 742 if (sc->sc_wsmousedev == NULL) 743 return; 744 745 if (!ISSET(sc->sc_flags, SF_MOUSE)) 746 return; 747 748 /* 749 * First byte is button status. It has the 0x80 bit always set, and 750 * the next 3 bits are *cleared* when the mouse buttons are pressed. 751 */ 752 #ifdef DEBUG 753 if (!ISSET(*dat, 0x80)) { 754 printf("%s: incorrect mouse packet %02x %02x %02x\n", 755 device_xname(sc->sc_dev), dat[0], dat[1], dat[2]); 756 return; 757 } 758 #endif 759 760 wsmouse_input(sc->sc_wsmousedev, 761 (~dat[0] & (DNBUTTON_L | DNBUTTON_M | DNBUTTON_R)) >> 4, 762 (int8_t)dat[1], (int8_t)dat[2], 0, 0, WSMOUSE_INPUT_DELTA); 763 } 764 #endif 765 766 /* 767 * Low-level communication routines. 768 */ 769 770 int 771 dnkbd_pollin(struct dnkbd_softc *sc, u_int tries) 772 { 773 bus_space_tag_t bst; 774 bus_space_handle_t bsh; 775 u_int cnt; 776 777 bst = sc->sc_bst; 778 bsh = sc->sc_bsh; 779 780 for (cnt = tries; cnt != 0; cnt--) { 781 if (bus_space_read_1(bst, bsh, com_lsr) & LSR_RXRDY) 782 break; 783 DELAY(10); 784 } 785 786 if (cnt == 0) 787 return -1; 788 else 789 return (int)bus_space_read_1(bst, bsh, com_data); 790 } 791 792 int 793 dnkbd_pollout(struct dnkbd_softc *sc, int dat) 794 { 795 bus_space_tag_t bst; 796 bus_space_handle_t bsh; 797 u_int cnt; 798 799 bst = sc->sc_bst; 800 bsh = sc->sc_bsh; 801 802 for (cnt = 10000; cnt != 0; cnt--) { 803 if (bus_space_read_1(bst, bsh, com_lsr) & LSR_TXRDY) 804 break; 805 DELAY(10); 806 } 807 if (cnt == 0) 808 return EBUSY; 809 else { 810 bus_space_write_1(bst, bsh, com_data, dat); 811 return 0; 812 } 813 } 814 815 int 816 dnkbd_send(struct dnkbd_softc *sc, const uint8_t *cmdbuf, size_t cmdlen) 817 { 818 int cnt, rc, dat; 819 u_int cmdpos; 820 821 /* drain rxfifo */ 822 for (cnt = 10; cnt != 0; cnt--) { 823 if (dnkbd_pollin(sc, 10) == -1) 824 break; 825 } 826 if (cnt == 0) 827 return EBUSY; 828 829 /* send command escape */ 830 if ((rc = dnkbd_pollout(sc, DNCMD_PREFIX)) != 0) 831 return rc; 832 833 /* send command buffer */ 834 for (cmdpos = 0; cmdpos < cmdlen; cmdpos++) { 835 if ((rc = dnkbd_pollout(sc, cmdbuf[cmdpos])) != 0) 836 return rc; 837 } 838 839 /* wait for command echo */ 840 do { 841 dat = dnkbd_pollin(sc, 10000); 842 if (dat == -1) 843 return EIO; 844 } while (dat != DNCMD_PREFIX); 845 846 for (cmdpos = 0; cmdpos < cmdlen; cmdpos++) { 847 dat = dnkbd_pollin(sc, 10000); 848 if (dat != cmdbuf[cmdpos]) 849 return EIO; 850 } 851 852 return 0; 853 } 854 855 void 856 dnkbd_break(struct dnkbd_softc *sc, int onoff) 857 { 858 bus_space_tag_t bst; 859 bus_space_handle_t bsh; 860 uint8_t reg; 861 862 bst = sc->sc_bst; 863 bsh = sc->sc_bsh; 864 865 reg = bus_space_read_1(bst, bsh, com_lctl); 866 if (onoff) 867 reg |= LCR_SBREAK; 868 else 869 reg &= ~LCR_SBREAK; 870 bus_space_write_1(bst, bsh, com_lctl, reg); 871 } 872 873 int 874 dnkbd_intr(void *v) 875 { 876 struct dnkbd_softc *sc = v; 877 bus_space_tag_t bst; 878 bus_space_handle_t bsh; 879 uint8_t iir, lsr, c; 880 int claimed = 0; 881 882 bst = sc->sc_bst; 883 bsh = sc->sc_bsh; 884 885 for (;;) { 886 iir = bus_space_read_1(bst, bsh, com_iir); 887 888 switch (iir & IIR_IMASK) { 889 case IIR_RLS: 890 /* 891 * Line status change. This should never happen, 892 * so silently ack the interrupt. 893 */ 894 c = bus_space_read_1(bst, bsh, com_lsr); 895 break; 896 897 case IIR_RXRDY: 898 case IIR_RXTOUT: 899 /* 900 * Data available. We process it byte by byte, 901 * unless we are doing polling work... 902 */ 903 if (ISSET(sc->sc_flags, SF_POLLING)) { 904 return 1; 905 } 906 907 for (;;) { 908 c = bus_space_read_1(bst, bsh, com_data); 909 switch (dnkbd_input(sc, c)) { 910 case EVENT_KEYBOARD: 911 dnevent_kbd(sc, c); 912 break; 913 #if NWSMOUSE > 0 914 case EVENT_MOUSE: 915 dnevent_mouse(sc, sc->sc_mousepkt); 916 break; 917 #endif 918 default: /* appease gcc */ 919 break; 920 } 921 lsr = bus_space_read_1(bst, bsh, com_lsr) & 922 LSR_RCV_MASK; 923 if (lsr == 0) 924 break; 925 else if (lsr != LSR_RXRDY) { 926 /* ignore error */ 927 break; 928 } 929 } 930 break; 931 932 case IIR_TXRDY: 933 /* 934 * Transmit available. Since we do all our commands 935 * in polling mode, we do not need to do anything here. 936 */ 937 break; 938 939 default: 940 if (iir & IIR_NOPEND) 941 return claimed; 942 /* FALLTHROUGH */ 943 944 case IIR_MLSC: 945 /* 946 * Modem status change. This should never happen, 947 * so silently ack the interrupt. 948 */ 949 c = bus_space_read_1(bst, bsh, com_msr); 950 break; 951 } 952 953 claimed = 1; 954 } 955 } 956 957 /* 958 * Wskbd callbacks 959 */ 960 961 int 962 dnkbd_enable(void *v, int on) 963 { 964 struct dnkbd_softc *sc = v; 965 966 if (on) { 967 if (ISSET(sc->sc_flags, SF_ENABLED)) 968 return EBUSY; 969 SET(sc->sc_flags, SF_ENABLED); 970 } else { 971 if (ISSET(sc->sc_flags, SF_CONSOLE)) 972 return EBUSY; 973 CLR(sc->sc_flags, SF_ENABLED); 974 } 975 976 return 0; 977 } 978 979 void 980 dnkbd_set_leds(void *v, int leds) 981 { 982 /* 983 * Not supported. There is only one LED on this keyboard, and 984 * is hardware tied to the caps lock key. 985 */ 986 } 987 988 int 989 dnkbd_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l) 990 { 991 #ifdef WSDISPLAY_COMPAT_RAWKBD 992 struct dnkbd_softc *sc = v; 993 #endif 994 995 #define WSKBD_TYPE_UNKNOWN 0 996 997 switch (cmd) { 998 case WSKBDIO_GTYPE: 999 *(int *)data = WSKBD_TYPE_UNKNOWN; /* XXX */ 1000 return 0; 1001 case WSKBDIO_SETLEDS: 1002 return ENXIO; 1003 case WSKBDIO_GETLEDS: 1004 *(int *)data = 0; 1005 return 0; 1006 case WSKBDIO_COMPLEXBELL: 1007 #define d ((struct wskbd_bell_data *)data) 1008 dnkbd_bell(v, d->period, d->pitch, d->volume); 1009 #undef d 1010 return 0; 1011 #ifdef WSDISPLAY_COMPAT_RAWKBD 1012 case WSKBDIO_SETMODE: 1013 sc->sc_rawkbd = *(int *)data == WSKBD_RAW; 1014 return 0; 1015 #endif 1016 } 1017 1018 return EPASSTHROUGH; 1019 } 1020 1021 #if NWSMOUSE > 0 1022 /* 1023 * Wsmouse callbacks 1024 */ 1025 1026 int 1027 dnmouse_enable(void *v) 1028 { 1029 struct dnkbd_softc *sc = v; 1030 1031 if (ISSET(sc->sc_flags, SF_MOUSE)) 1032 return EBUSY; 1033 SET(sc->sc_flags, SF_MOUSE); 1034 1035 return 0; 1036 } 1037 1038 int 1039 dnmouse_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l) 1040 { 1041 #if 0 1042 struct dnkbd_softc *sc = v; 1043 #endif 1044 1045 #define WSMOUSE_TYPE_UNKNOWN 0 1046 1047 switch (cmd) { 1048 case WSMOUSEIO_GTYPE: 1049 *(int *)data = WSMOUSE_TYPE_UNKNOWN; /* XXX */ 1050 return 0; 1051 } 1052 1053 return -1; 1054 } 1055 1056 void 1057 dnmouse_disable(void *v) 1058 { 1059 struct dnkbd_softc *sc = v; 1060 1061 CLR(sc->sc_flags, SF_MOUSE); 1062 } 1063 #endif 1064 1065 /* 1066 * Console support 1067 */ 1068 1069 void 1070 dnkbd_cngetc(void *v, u_int *type, int *data) 1071 { 1072 static int lastdat = 0; 1073 struct dnkbd_softc *sc = v; 1074 int s; 1075 int dat; 1076 1077 /* Take care of caps lock */ 1078 if ((lastdat & ~DNKEY_RELEASE) == DNKEY_CAPSLOCK) { 1079 dat = lastdat ^ DNKEY_RELEASE; 1080 lastdat = 0; 1081 } else { 1082 for (;;) { 1083 s = splhigh(); 1084 dat = dnkbd_pollin(sc, 10000); 1085 if (dat != -1) { 1086 if (dnkbd_input(sc, dat) == EVENT_KEYBOARD) { 1087 splx(s); 1088 break; 1089 } 1090 } 1091 splx(s); 1092 } 1093 lastdat = dat; 1094 } 1095 1096 dnkbd_decode(dat, type, data); 1097 } 1098 1099 void 1100 dnkbd_cnpollc(void *v, int on) 1101 { 1102 struct dnkbd_softc *sc = v; 1103 1104 if (on) 1105 SET(sc->sc_flags, SF_POLLING); 1106 else 1107 CLR(sc->sc_flags, SF_POLLING); 1108 } 1109 1110 /* 1111 * Bell routines. 1112 */ 1113 void 1114 dnkbd_bell(void *v, u_int period, u_int pitch, u_int volume) 1115 { 1116 struct dnkbd_softc *sc = v; 1117 int s; 1118 1119 s = spltty(); 1120 1121 if (pitch == 0 || period == 0 || volume == 0) { 1122 if (ISSET(sc->sc_flags, SF_BELL_TMO)) { 1123 callout_stop(&sc->sc_bellstop_tmo); 1124 dnkbd_bellstop(v); 1125 } 1126 } else { 1127 1128 if (!ISSET(sc->sc_flags, SF_BELL)) { 1129 dnkbd_pollout(sc, DNCMD_PREFIX); 1130 dnkbd_pollout(sc, DNCMD_BELL); 1131 dnkbd_pollout(sc, DNCMD_BELL_ON); 1132 SET(sc->sc_flags, SF_BELL); 1133 } 1134 1135 if (ISSET(sc->sc_flags, SF_BELL_TMO)) 1136 callout_stop(&sc->sc_bellstop_tmo); 1137 callout_schedule(&sc->sc_bellstop_tmo, period); 1138 SET(sc->sc_flags, SF_BELL_TMO); 1139 } 1140 1141 splx(s); 1142 } 1143 1144 void 1145 dnkbd_bellstop(void *v) 1146 { 1147 struct dnkbd_softc *sc = v; 1148 int s; 1149 1150 s = spltty(); 1151 1152 dnkbd_pollout(sc, DNCMD_PREFIX); 1153 dnkbd_pollout(sc, DNCMD_BELL); 1154 dnkbd_pollout(sc, DNCMD_BELL_OFF); 1155 CLR(sc->sc_flags, SF_BELL); 1156 CLR(sc->sc_flags, SF_BELL_TMO); 1157 1158 splx(s); 1159 } 1160