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