1 /* $NetBSD: dnkbd.c,v 1.15 2024/01/16 05:48:28 thorpej 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 dnkbd_enable, 212 dnkbd_set_leds, 213 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 dnkbd_cngetc, 234 dnkbd_cnpollc, 235 dnkbd_bell 236 }; 237 238 static struct wskbd_mapdata dnkbd_keymapdata = { 239 dnkbd_keydesctab, 240 #ifdef DNKBD_LAYOUT 241 DNKBD_LAYOUT 242 #else 243 KB_US 244 #endif 245 }; 246 247 typedef enum { EVENT_NONE, EVENT_KEYBOARD, EVENT_MOUSE } dnevent; 248 249 #define APCIBRD(x) (500000 / (x)) 250 251 static void dnevent_kbd(struct dnkbd_softc *, int); 252 static void dnevent_kbd_internal(struct dnkbd_softc *, int); 253 static void dnevent_mouse(struct dnkbd_softc *, uint8_t *); 254 static void dnkbd_attach_subdevices(struct dnkbd_softc *); 255 static void dnkbd_bellstop(void *); 256 static void dnkbd_decode(int, u_int *, int *); 257 static dnevent dnkbd_input(struct dnkbd_softc *, int); 258 static int dnkbd_intr(void *); 259 static int dnkbd_pollin(struct dnkbd_softc *, u_int); 260 static int dnkbd_pollout(struct dnkbd_softc *, int); 261 static int dnkbd_probe(struct dnkbd_softc *); 262 static int dnkbd_send(struct dnkbd_softc *, const uint8_t *, size_t); 263 static void dnkbd_break(struct dnkbd_softc *, int); 264 265 int 266 dnkbd_match(device_t parent, cfdata_t cf, void *aux) 267 { 268 struct frodo_attach_args *fa = aux; 269 270 if (strcmp(fa->fa_name, dnkbd_cd.cd_name) != 0) 271 return 0; 272 273 if (machineid == HP_382) { 274 /* 382 has frodo but no Domain keyboard connector. */ 275 return 0; 276 } 277 278 /* only attach to the first frodo port */ 279 return fa->fa_offset == FRODO_APCI_OFFSET(0); 280 } 281 282 void 283 dnkbd_attach(device_t parent, device_t self, void *aux) 284 { 285 struct dnkbd_softc *sc = device_private(self); 286 struct frodo_attach_args *fa = aux; 287 288 aprint_normal(": "); 289 290 sc->sc_dev = self; 291 sc->sc_bst = fa->fa_bst; 292 if (bus_space_map(sc->sc_bst, fa->fa_base + fa->fa_offset, 293 FRODO_APCISPACE, 0, &sc->sc_bsh) != 0) { 294 aprint_error(": can't map i/o space\n"); 295 return; 296 } 297 298 callout_init(&sc->sc_bellstop_tmo, 0); 299 callout_setfunc(&sc->sc_bellstop_tmo, dnkbd_bellstop, sc); 300 301 /* reset the port */ 302 dnkbd_init(sc, 1200, LCR_8BITS | LCR_PEVEN | LCR_PENAB); 303 304 frodo_intr_establish(parent, dnkbd_intr, sc, fa->fa_line, ISRPRI_TTY); 305 306 /* send break to reset keyboard state */ 307 dnkbd_break(sc, 1); 308 delay(10 * 1000); /* 10ms for 12 space bits */ 309 dnkbd_break(sc, 0); 310 delay(10 * 1000); 311 312 /* probe for keyboard */ 313 if (dnkbd_probe(sc) != 0) { 314 aprint_normal("no keyboard\n"); 315 return; 316 } 317 318 dnkbd_attach_subdevices(sc); 319 } 320 321 void 322 dnkbd_init(struct dnkbd_softc *sc, uint16_t rate, uint16_t lctl) 323 { 324 bus_space_tag_t bst; 325 bus_space_handle_t bsh; 326 u_int divisor; 327 328 bst = sc->sc_bst; 329 bsh = sc->sc_bsh; 330 331 divisor = APCIBRD(rate); 332 bus_space_write_1(bst, bsh, com_lctl, LCR_DLAB); 333 bus_space_write_1(bst, bsh, com_dlbl, divisor & 0xff); 334 bus_space_write_1(bst, bsh, com_dlbh, (divisor >> 8) & 0xff); 335 bus_space_write_1(bst, bsh, com_lctl, lctl); 336 bus_space_write_1(bst, bsh, com_ier, IER_ERXRDY | IER_ETXRDY); 337 bus_space_write_1(bst, bsh, com_fifo, 338 FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_1); 339 bus_space_write_1(bst, bsh, com_mcr, MCR_DTR | MCR_RTS); 340 341 delay(100); 342 (void)bus_space_read_1(bst, bsh, com_iir); 343 } 344 345 void 346 dnkbd_attach_subdevices(struct dnkbd_softc *sc) 347 { 348 struct wskbddev_attach_args ka; 349 #if NWSMOUSE > 0 350 struct wsmousedev_attach_args ma; 351 #endif 352 #if NHILKBD > 0 353 extern int hil_is_console; 354 #endif 355 356 /* 357 * If both hilkbd and dnkbd are configured, prefer the Domain 358 * keyboard as console (if we are here, we know the keyboard is 359 * plugged), unless the console keyboard has been claimed already 360 * (i.e. late hotplug with hil keyboard plugged first). 361 */ 362 #if NWSDISPLAY > 0 363 if (cn_tab->cn_putc == wsdisplay_cnputc) { 364 #if NHILKBD > 0 365 if (hil_is_console == -1) { 366 ka.console = 1; 367 hil_is_console = 0; 368 } else 369 ka.console = 0; 370 #else 371 ka.console = 1; 372 #endif 373 } else 374 #endif 375 { 376 ka.console = 0; 377 } 378 379 ka.keymap = &dnkbd_keymapdata; 380 ka.accessops = &dnkbd_accessops; 381 ka.accesscookie = sc; 382 #ifndef DKKBD_LAYOUT 383 dnkbd_keymapdata.layout = sc->sc_layout; 384 #endif 385 386 if (ka.console) { 387 sc->sc_flags = SF_PLUGGED | SF_CONSOLE | SF_ENABLED; 388 wskbd_cnattach(&dnkbd_consops, sc, &dnkbd_keymapdata); 389 } else { 390 sc->sc_flags = SF_PLUGGED; 391 } 392 393 sc->sc_wskbddev = config_found(sc->sc_dev, &ka, wskbddevprint, 394 CFARGS(.iattr = "wskbddev")); 395 396 #if NWSMOUSE > 0 397 ma.accessops = &dnmouse_accessops; 398 ma.accesscookie = sc; 399 400 sc->sc_wsmousedev = config_found(sc->sc_dev, &ma, wsmousedevprint, 401 CFARGS(.iattr = "wsmousedev")); 402 #endif 403 404 SET(sc->sc_flags, SF_ATTACHED); 405 } 406 407 int 408 dnkbd_probe(struct dnkbd_softc *sc) 409 { 410 int dat, rc, flags; 411 uint8_t cmdbuf[2]; 412 char rspbuf[MAX_IDENTLEN], *word, *end; 413 u_int i; 414 int s; 415 416 s = spltty(); 417 flags = sc->sc_flags; 418 SET(sc->sc_flags, SF_POLLING); 419 sc->sc_state = STATE_CHANNEL; 420 splx(s); 421 422 /* 423 * Switch keyboard to raw mode. 424 */ 425 cmdbuf[0] = DNCMD_RAW; 426 rc = dnkbd_send(sc, cmdbuf, 1); 427 if (rc != 0) 428 goto out; 429 430 /* 431 * Send the identify command. 432 */ 433 cmdbuf[0] = DNCMD_IDENT_1; 434 cmdbuf[1] = DNCMD_IDENT_2; 435 rc = dnkbd_send(sc, cmdbuf, 2); 436 if (rc != 0) 437 goto out; 438 439 for (i = 0; ; i++) { 440 dat = dnkbd_pollin(sc, 10000); 441 if (dat == -1) 442 break; 443 444 if (i < sizeof(rspbuf)) 445 rspbuf[i] = dat; 446 } 447 448 if (i > sizeof(rspbuf) || i == 0) { 449 aprint_error_dev(sc->sc_dev, 450 "unexpected identify string length %d\n", i); 451 rc = ENXIO; 452 goto out; 453 } 454 455 /* 456 * Make sure the identification string is NULL terminated 457 * (overwriting the keyboard mode byte if necessary). 458 */ 459 i--; 460 if (rspbuf[i] != 0) 461 rspbuf[i] = 0; 462 463 /* 464 * Now display the identification strings, if they changed. 465 */ 466 if (i != sc->sc_identlen || memcmp(rspbuf, sc->sc_ident, i) != 0) { 467 sc->sc_layout = KB_US; 468 sc->sc_identlen = i; 469 memcpy(sc->sc_ident, rspbuf, i); 470 471 if (cold == 0) 472 aprint_normal_dev(sc->sc_dev, ""); 473 aprint_normal("model "); 474 word = rspbuf; 475 for (i = 0; i < 3; i++) { 476 end = strchr(word, '\r'); 477 if (end == NULL) 478 break; 479 *end++ = '\0'; 480 aprint_normal("<%s> ", word); 481 /* 482 * Parse the layout code if applicable 483 */ 484 if (i == 1 && *word++ == '3') { 485 if (*word == '-') 486 word++; 487 switch (*word) { 488 #if 0 489 default: 490 case ' ': 491 sc->sc_layout = KB_US; 492 break; 493 #endif 494 case 'a': 495 sc->sc_layout = KB_DE; 496 break; 497 case 'b': 498 sc->sc_layout = KB_FR; 499 break; 500 case 'c': 501 sc->sc_layout = KB_DK; 502 break; 503 case 'd': 504 sc->sc_layout = KB_SV; 505 break; 506 case 'e': 507 sc->sc_layout = KB_UK; 508 break; 509 case 'f': 510 sc->sc_layout = KB_JP; 511 break; 512 case 'g': 513 sc->sc_layout = KB_SG; 514 break; 515 } 516 } 517 word = end; 518 } 519 aprint_normal("\n"); 520 } 521 522 /* 523 * Ready to work, the default channel is the keyboard. 524 */ 525 sc->sc_state = STATE_KEYBOARD; 526 527 out: 528 s = spltty(); 529 sc->sc_flags = flags; 530 splx(s); 531 532 return rc; 533 } 534 535 /* 536 * State machine. 537 * 538 * In raw mode, the keyboard may feed us the following sequences: 539 * - on the keyboard channel: 540 * + a raw key code, in the range 0x01-0x7e, or'ed with 0x80 if key release. 541 * + the key repeat sequence 0x7f. 542 * - on the mouse channel: 543 * + a 3 byte mouse sequence (buttons state, dx move, dy move). 544 * - at any time: 545 * + a 2 byte channel sequence (0xff followed by the channel number) telling 546 * us which device the following input will come from. 547 * + if we get 0xff but an invalid channel number, this is a command echo. 548 * Currently we only handle this for bell commands, which size are known. 549 * Other commands are issued through dnkbd_send() which ``eats'' the echo. 550 * 551 * Older keyboards reset the channel to the keyboard (by sending ff 01) after 552 * every mouse packet. 553 */ 554 555 dnevent 556 dnkbd_input(struct dnkbd_softc *sc, int dat) 557 { 558 dnevent event = EVENT_NONE; 559 560 switch (sc->sc_state) { 561 case STATE_KEYBOARD: 562 switch (dat) { 563 case DNKEY_REPEAT: 564 /* 565 * We ignore event repeats, as wskbd does its own 566 * soft repeat processing. 567 */ 568 break; 569 case DNKEY_CHANNEL: 570 sc->sc_prevstate = sc->sc_state; 571 sc->sc_state = STATE_CHANNEL; 572 break; 573 default: 574 event = EVENT_KEYBOARD; 575 break; 576 } 577 break; 578 579 case STATE_MOUSE: 580 if (dat == DNKEY_CHANNEL && sc->sc_mousepos == 0) { 581 sc->sc_prevstate = sc->sc_state; 582 sc->sc_state = STATE_CHANNEL; 583 } else { 584 sc->sc_mousepkt[sc->sc_mousepos++] = dat; 585 if (sc->sc_mousepos == sizeof(sc->sc_mousepkt)) { 586 sc->sc_mousepos = 0; 587 event = EVENT_MOUSE; 588 } 589 } 590 break; 591 592 case STATE_CHANNEL: 593 switch (dat) { 594 case DNKEY_CHANNEL: 595 /* 596 * During hotplug, we might get spurious 0xff bytes. 597 * Ignore them. 598 */ 599 break; 600 case DNCHANNEL_RESET: 601 /* 602 * Identify the keyboard again. This will switch it to 603 * raw mode again. If this fails, we'll consider the 604 * keyboard as unplugged (to ignore further events until 605 * a successful reset). 606 */ 607 if (dnkbd_probe(sc) == 0) { 608 /* 609 * We need to attach wskbd and wsmouse children 610 * if this is a live first plug. 611 */ 612 if (!ISSET(sc->sc_flags, SF_ATTACHED)) 613 dnkbd_attach_subdevices(sc); 614 SET(sc->sc_flags, SF_PLUGGED); 615 } else { 616 CLR(sc->sc_flags, SF_PLUGGED); 617 } 618 619 sc->sc_state = STATE_KEYBOARD; 620 break; 621 case DNCHANNEL_KBD: 622 sc->sc_state = STATE_KEYBOARD; 623 break; 624 case DNCHANNEL_MOUSE: 625 sc->sc_state = STATE_MOUSE; 626 sc->sc_mousepos = 0; /* just in case */ 627 break; 628 case DNCMD_BELL: 629 /* 630 * We are getting a bell command echoed to us. 631 * Ignore it. 632 */ 633 sc->sc_state = STATE_ECHO; 634 sc->sc_echolen = 1; /* one byte to follow */ 635 break; 636 default: 637 printf("%s: unexpected channel byte %02x\n", 638 device_xname(sc->sc_dev), dat); 639 break; 640 } 641 break; 642 643 case STATE_ECHO: 644 if (--sc->sc_echolen == 0) { 645 /* get back to the state we were in before the echo */ 646 sc->sc_state = sc->sc_prevstate; 647 } 648 break; 649 } 650 651 return event; 652 } 653 654 /* 655 * Event breakers. 656 */ 657 658 void 659 dnkbd_decode(int keycode, u_int *type, int *key) 660 { 661 *type = (keycode & DNKEY_RELEASE) ? 662 WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN; 663 *key = (keycode & ~DNKEY_RELEASE); 664 } 665 666 void 667 dnevent_kbd(struct dnkbd_softc *sc, int dat) 668 { 669 if (!ISSET(sc->sc_flags, SF_PLUGGED)) 670 return; 671 672 if (sc->sc_wskbddev == NULL) 673 return; 674 675 if (!ISSET(sc->sc_flags, SF_ENABLED)) 676 return; 677 678 /* 679 * Even in raw mode, the caps lock key is treated specially: 680 * first key press causes event 0x7e, release causes no event; 681 * then a new key press causes nothing, and release causes 682 * event 0xfe. Moreover, while kept down, it does not produce 683 * repeat events. 684 * 685 * So the best we can do is fake the missed events, but this 686 * will not allow the capslock key to be remapped as a control 687 * key since it will not be possible to chord it with anything. 688 */ 689 dnevent_kbd_internal(sc, dat); 690 if ((dat & ~DNKEY_RELEASE) == DNKEY_CAPSLOCK) 691 dnevent_kbd_internal(sc, dat ^ DNKEY_RELEASE); 692 } 693 694 void 695 dnevent_kbd_internal(struct dnkbd_softc *sc, int dat) 696 { 697 u_int type; 698 int key; 699 int s; 700 701 dnkbd_decode(dat, &type, &key); 702 703 #ifdef WSDISPLAY_COMPAT_RAWKBD 704 if (sc->sc_rawkbd) { 705 u_char cbuf[2]; 706 int c, j; 707 708 j = 0; 709 c = dnkbd_raw[key]; 710 if (c != 0) { 711 /* fake extended scancode if necessary */ 712 if (c & 0x80) 713 cbuf[j++] = 0xe0; 714 cbuf[j] = c & 0x7f; 715 if (type == WSCONS_EVENT_KEY_UP) 716 cbuf[j] |= 0x80; 717 j++; 718 } 719 720 if (j != 0) { 721 s = spltty(); 722 wskbd_rawinput(sc->sc_wskbddev, cbuf, j); 723 splx(s); 724 } 725 } else 726 #endif 727 { 728 s = spltty(); 729 wskbd_input(sc->sc_wskbddev, type, key); 730 splx(s); 731 } 732 } 733 734 #if NWSMOUSE > 0 735 void 736 dnevent_mouse(struct dnkbd_softc *sc, uint8_t *dat) 737 { 738 if (!ISSET(sc->sc_flags, SF_PLUGGED)) 739 return; 740 741 if (sc->sc_wsmousedev == NULL) 742 return; 743 744 if (!ISSET(sc->sc_flags, SF_MOUSE)) 745 return; 746 747 /* 748 * First byte is button status. It has the 0x80 bit always set, and 749 * the next 3 bits are *cleared* when the mouse buttons are pressed. 750 */ 751 #ifdef DEBUG 752 if (!ISSET(*dat, 0x80)) { 753 printf("%s: incorrect mouse packet %02x %02x %02x\n", 754 device_xname(sc->sc_dev), dat[0], dat[1], dat[2]); 755 return; 756 } 757 #endif 758 759 wsmouse_input(sc->sc_wsmousedev, 760 (~dat[0] & (DNBUTTON_L | DNBUTTON_M | DNBUTTON_R)) >> 4, 761 (int8_t)dat[1], (int8_t)dat[2], 0, 0, WSMOUSE_INPUT_DELTA); 762 } 763 #endif 764 765 /* 766 * Low-level communication routines. 767 */ 768 769 int 770 dnkbd_pollin(struct dnkbd_softc *sc, u_int tries) 771 { 772 bus_space_tag_t bst; 773 bus_space_handle_t bsh; 774 u_int cnt; 775 776 bst = sc->sc_bst; 777 bsh = sc->sc_bsh; 778 779 for (cnt = tries; cnt != 0; cnt--) { 780 if (bus_space_read_1(bst, bsh, com_lsr) & LSR_RXRDY) 781 break; 782 DELAY(10); 783 } 784 785 if (cnt == 0) 786 return -1; 787 else 788 return (int)bus_space_read_1(bst, bsh, com_data); 789 } 790 791 int 792 dnkbd_pollout(struct dnkbd_softc *sc, int dat) 793 { 794 bus_space_tag_t bst; 795 bus_space_handle_t bsh; 796 u_int cnt; 797 798 bst = sc->sc_bst; 799 bsh = sc->sc_bsh; 800 801 for (cnt = 10000; cnt != 0; cnt--) { 802 if (bus_space_read_1(bst, bsh, com_lsr) & LSR_TXRDY) 803 break; 804 DELAY(10); 805 } 806 if (cnt == 0) 807 return EBUSY; 808 else { 809 bus_space_write_1(bst, bsh, com_data, dat); 810 return 0; 811 } 812 } 813 814 int 815 dnkbd_send(struct dnkbd_softc *sc, const uint8_t *cmdbuf, size_t cmdlen) 816 { 817 int cnt, rc, dat; 818 u_int cmdpos; 819 820 /* drain rxfifo */ 821 for (cnt = 10; cnt != 0; cnt--) { 822 if (dnkbd_pollin(sc, 10) == -1) 823 break; 824 } 825 if (cnt == 0) 826 return EBUSY; 827 828 /* send command escape */ 829 if ((rc = dnkbd_pollout(sc, DNCMD_PREFIX)) != 0) 830 return rc; 831 832 /* send command buffer */ 833 for (cmdpos = 0; cmdpos < cmdlen; cmdpos++) { 834 if ((rc = dnkbd_pollout(sc, cmdbuf[cmdpos])) != 0) 835 return rc; 836 } 837 838 /* wait for command echo */ 839 do { 840 dat = dnkbd_pollin(sc, 10000); 841 if (dat == -1) 842 return EIO; 843 } while (dat != DNCMD_PREFIX); 844 845 for (cmdpos = 0; cmdpos < cmdlen; cmdpos++) { 846 dat = dnkbd_pollin(sc, 10000); 847 if (dat != cmdbuf[cmdpos]) 848 return EIO; 849 } 850 851 return 0; 852 } 853 854 void 855 dnkbd_break(struct dnkbd_softc *sc, int onoff) 856 { 857 bus_space_tag_t bst; 858 bus_space_handle_t bsh; 859 uint8_t reg; 860 861 bst = sc->sc_bst; 862 bsh = sc->sc_bsh; 863 864 reg = bus_space_read_1(bst, bsh, com_lctl); 865 if (onoff) 866 reg |= LCR_SBREAK; 867 else 868 reg &= ~LCR_SBREAK; 869 bus_space_write_1(bst, bsh, com_lctl, reg); 870 } 871 872 int 873 dnkbd_intr(void *v) 874 { 875 struct dnkbd_softc *sc = v; 876 bus_space_tag_t bst; 877 bus_space_handle_t bsh; 878 uint8_t iir, lsr, c; 879 int claimed = 0; 880 881 bst = sc->sc_bst; 882 bsh = sc->sc_bsh; 883 884 for (;;) { 885 iir = bus_space_read_1(bst, bsh, com_iir); 886 887 switch (iir & IIR_IMASK) { 888 case IIR_RLS: 889 /* 890 * Line status change. This should never happen, 891 * so silently ack the interrupt. 892 */ 893 c = bus_space_read_1(bst, bsh, com_lsr); 894 break; 895 896 case IIR_RXRDY: 897 case IIR_RXTOUT: 898 /* 899 * Data available. We process it byte by byte, 900 * unless we are doing polling work... 901 */ 902 if (ISSET(sc->sc_flags, SF_POLLING)) { 903 return 1; 904 } 905 906 for (;;) { 907 c = bus_space_read_1(bst, bsh, com_data); 908 switch (dnkbd_input(sc, c)) { 909 case EVENT_KEYBOARD: 910 dnevent_kbd(sc, c); 911 break; 912 #if NWSMOUSE > 0 913 case EVENT_MOUSE: 914 dnevent_mouse(sc, sc->sc_mousepkt); 915 break; 916 #endif 917 default: /* appease gcc */ 918 break; 919 } 920 lsr = bus_space_read_1(bst, bsh, com_lsr) & 921 LSR_RCV_MASK; 922 if (lsr == 0) 923 break; 924 else if (lsr != LSR_RXRDY) { 925 /* ignore error */ 926 break; 927 } 928 } 929 break; 930 931 case IIR_TXRDY: 932 /* 933 * Transmit available. Since we do all our commands 934 * in polling mode, we do not need to do anything here. 935 */ 936 break; 937 938 default: 939 if (iir & IIR_NOPEND) 940 return claimed; 941 /* FALLTHROUGH */ 942 943 case IIR_MLSC: 944 /* 945 * Modem status change. This should never happen, 946 * so silently ack the interrupt. 947 */ 948 c = bus_space_read_1(bst, bsh, com_msr); 949 break; 950 } 951 952 claimed = 1; 953 } 954 } 955 956 /* 957 * Wskbd callbacks 958 */ 959 960 int 961 dnkbd_enable(void *v, int on) 962 { 963 struct dnkbd_softc *sc = v; 964 965 if (on) { 966 if (ISSET(sc->sc_flags, SF_ENABLED)) 967 return EBUSY; 968 SET(sc->sc_flags, SF_ENABLED); 969 } else { 970 if (ISSET(sc->sc_flags, SF_CONSOLE)) 971 return EBUSY; 972 CLR(sc->sc_flags, SF_ENABLED); 973 } 974 975 return 0; 976 } 977 978 void 979 dnkbd_set_leds(void *v, int leds) 980 { 981 /* 982 * Not supported. There is only one LED on this keyboard, and 983 * is hardware tied to the caps lock key. 984 */ 985 } 986 987 int 988 dnkbd_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l) 989 { 990 #ifdef WSDISPLAY_COMPAT_RAWKBD 991 struct dnkbd_softc *sc = v; 992 #endif 993 994 #define WSKBD_TYPE_UNKNOWN 0 995 996 switch (cmd) { 997 case WSKBDIO_GTYPE: 998 *(int *)data = WSKBD_TYPE_UNKNOWN; /* XXX */ 999 return 0; 1000 case WSKBDIO_SETLEDS: 1001 return ENXIO; 1002 case WSKBDIO_GETLEDS: 1003 *(int *)data = 0; 1004 return 0; 1005 case WSKBDIO_COMPLEXBELL: 1006 #define d ((struct wskbd_bell_data *)data) 1007 dnkbd_bell(v, d->period, d->pitch, d->volume); 1008 #undef d 1009 return 0; 1010 #ifdef WSDISPLAY_COMPAT_RAWKBD 1011 case WSKBDIO_SETMODE: 1012 sc->sc_rawkbd = *(int *)data == WSKBD_RAW; 1013 return 0; 1014 #endif 1015 } 1016 1017 return EPASSTHROUGH; 1018 } 1019 1020 #if NWSMOUSE > 0 1021 /* 1022 * Wsmouse callbacks 1023 */ 1024 1025 int 1026 dnmouse_enable(void *v) 1027 { 1028 struct dnkbd_softc *sc = v; 1029 1030 if (ISSET(sc->sc_flags, SF_MOUSE)) 1031 return EBUSY; 1032 SET(sc->sc_flags, SF_MOUSE); 1033 1034 return 0; 1035 } 1036 1037 int 1038 dnmouse_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l) 1039 { 1040 #if 0 1041 struct dnkbd_softc *sc = v; 1042 #endif 1043 1044 #define WSMOUSE_TYPE_UNKNOWN 0 1045 1046 switch (cmd) { 1047 case WSMOUSEIO_GTYPE: 1048 *(int *)data = WSMOUSE_TYPE_UNKNOWN; /* XXX */ 1049 return 0; 1050 } 1051 1052 return -1; 1053 } 1054 1055 void 1056 dnmouse_disable(void *v) 1057 { 1058 struct dnkbd_softc *sc = v; 1059 1060 CLR(sc->sc_flags, SF_MOUSE); 1061 } 1062 #endif 1063 1064 /* 1065 * Console support 1066 */ 1067 1068 void 1069 dnkbd_cngetc(void *v, u_int *type, int *data) 1070 { 1071 static int lastdat = 0; 1072 struct dnkbd_softc *sc = v; 1073 int s; 1074 int dat; 1075 1076 /* Take care of caps lock */ 1077 if ((lastdat & ~DNKEY_RELEASE) == DNKEY_CAPSLOCK) { 1078 dat = lastdat ^ DNKEY_RELEASE; 1079 lastdat = 0; 1080 } else { 1081 for (;;) { 1082 s = splhigh(); 1083 dat = dnkbd_pollin(sc, 10000); 1084 if (dat != -1) { 1085 if (dnkbd_input(sc, dat) == EVENT_KEYBOARD) { 1086 splx(s); 1087 break; 1088 } 1089 } 1090 splx(s); 1091 } 1092 lastdat = dat; 1093 } 1094 1095 dnkbd_decode(dat, type, data); 1096 } 1097 1098 void 1099 dnkbd_cnpollc(void *v, int on) 1100 { 1101 struct dnkbd_softc *sc = v; 1102 1103 if (on) 1104 SET(sc->sc_flags, SF_POLLING); 1105 else 1106 CLR(sc->sc_flags, SF_POLLING); 1107 } 1108 1109 /* 1110 * Bell routines. 1111 */ 1112 void 1113 dnkbd_bell(void *v, u_int period, u_int pitch, u_int volume) 1114 { 1115 struct dnkbd_softc *sc = v; 1116 int s; 1117 1118 s = spltty(); 1119 1120 if (pitch == 0 || period == 0 || volume == 0) { 1121 if (ISSET(sc->sc_flags, SF_BELL_TMO)) { 1122 callout_stop(&sc->sc_bellstop_tmo); 1123 dnkbd_bellstop(v); 1124 } 1125 } else { 1126 1127 if (!ISSET(sc->sc_flags, SF_BELL)) { 1128 dnkbd_pollout(sc, DNCMD_PREFIX); 1129 dnkbd_pollout(sc, DNCMD_BELL); 1130 dnkbd_pollout(sc, DNCMD_BELL_ON); 1131 SET(sc->sc_flags, SF_BELL); 1132 } 1133 1134 if (ISSET(sc->sc_flags, SF_BELL_TMO)) 1135 callout_stop(&sc->sc_bellstop_tmo); 1136 callout_schedule(&sc->sc_bellstop_tmo, period); 1137 SET(sc->sc_flags, SF_BELL_TMO); 1138 } 1139 1140 splx(s); 1141 } 1142 1143 void 1144 dnkbd_bellstop(void *v) 1145 { 1146 struct dnkbd_softc *sc = v; 1147 int s; 1148 1149 s = spltty(); 1150 1151 dnkbd_pollout(sc, DNCMD_PREFIX); 1152 dnkbd_pollout(sc, DNCMD_BELL); 1153 dnkbd_pollout(sc, DNCMD_BELL_OFF); 1154 CLR(sc->sc_flags, SF_BELL); 1155 CLR(sc->sc_flags, SF_BELL_TMO); 1156 1157 splx(s); 1158 } 1159