1 /* $NetBSD: dnkbd.c,v 1.7 2014/04/24 12:10:27 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 <sys/param.h> 73 #include <sys/systm.h> 74 #include <sys/device.h> 75 #include <sys/ioctl.h> 76 #include <sys/kernel.h> 77 #include <sys/callout.h> 78 #include <sys/conf.h> 79 #include <sys/bus.h> 80 #include <sys/cpu.h> 81 82 #include <machine/autoconf.h> 83 84 #include <dev/cons.h> 85 86 #include <dev/wscons/wsconsio.h> 87 #include <dev/wscons/wskbdvar.h> 88 #include <dev/wscons/wsksymdef.h> 89 #include <dev/wscons/wsksymvar.h> 90 #include "wsmouse.h" 91 #if NWSMOUSE > 0 92 #include <dev/wscons/wsmousevar.h> 93 #endif 94 95 #include <dev/ic/ns16550reg.h> 96 #include <dev/ic/comreg.h> 97 98 #include <hp300/dev/dnkbdmap.h> 99 #include <hp300/dev/frodoreg.h> 100 #include <hp300/dev/frodovar.h> 101 102 #include "hilkbd.h" 103 #include "ioconf.h" 104 105 /* 106 * Keyboard key codes 107 */ 108 109 #define DNKEY_CAPSLOCK 0x7e 110 #define DNKEY_REPEAT 0x7f 111 #define DNKEY_RELEASE 0x80 112 #define DNKEY_CHANNEL 0xff 113 114 /* 115 * Channels 116 */ 117 118 #define DNCHANNEL_RESET 0x00 119 #define DNCHANNEL_KBD 0x01 120 #define DNCHANNEL_MOUSE 0x02 121 122 /* 123 * Keyboard modes 124 */ 125 126 #define DNMODE_COOKED 0x00 127 #define DNMODE_RAW 0x01 128 129 /* 130 * Keyboard commands 131 */ 132 133 #define DNCMD_PREFIX 0xff 134 #define DNCMD_COOKED DNMODE_COOKED 135 #define DNCMD_RAW DNMODE_RAW 136 #define DNCMD_IDENT_1 0x12 137 #define DNCMD_IDENT_2 0x21 138 139 /* 140 * Bell commands 141 */ 142 143 #define DNCMD_BELL 0x21 144 #define DNCMD_BELL_ON 0x81 145 #define DNCMD_BELL_OFF 0x82 146 147 /* 148 * Mouse status 149 */ 150 151 #define DNBUTTON_L 0x10 152 #define DNBUTTON_R 0x20 153 #define DNBUTTON_M 0x40 154 155 struct dnkbd_softc { 156 device_t sc_dev; 157 bus_space_tag_t sc_bst; 158 bus_space_handle_t sc_bsh; 159 160 int sc_flags; 161 #define SF_ENABLED 0x01 /* keyboard enabled */ 162 #define SF_CONSOLE 0x02 /* keyboard is console */ 163 #define SF_POLLING 0x04 /* polling mode */ 164 #define SF_PLUGGED 0x08 /* keyboard has been seen plugged */ 165 #define SF_ATTACHED 0x10 /* subdevices have been attached */ 166 #define SF_MOUSE 0x20 /* mouse enabled */ 167 #define SF_BELL 0x40 /* bell is active */ 168 #define SF_BELL_TMO 0x80 /* bell stop timeout is scheduled */ 169 170 u_int sc_identlen; 171 #define MAX_IDENTLEN 32 172 char sc_ident[MAX_IDENTLEN]; 173 kbd_t sc_layout; 174 175 enum { STATE_KEYBOARD, STATE_MOUSE, STATE_CHANNEL, STATE_ECHO } 176 sc_state, sc_prevstate; 177 u_int sc_echolen; 178 179 uint8_t sc_mousepkt[3]; /* mouse packet being constructed */ 180 u_int sc_mousepos; /* index in above */ 181 182 struct callout sc_bellstop_tmo; 183 184 device_t sc_wskbddev; 185 #if NWSMOUSE > 0 186 device_t sc_wsmousedev; 187 #endif 188 189 #ifdef WSDISPLAY_COMPAT_RAWKBD 190 int sc_rawkbd; 191 int sc_nrep; 192 char sc_rep[2]; /* at most, one key */ 193 struct callout sc_rawrepeat_ch; 194 #define REP_DELAY1 400 195 #define REP_DELAYN 100 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 #ifdef WSDISPLAY_COMPAT_RAWKBD 263 static void dnkbd_rawrepeat(void *); 264 #endif 265 static int dnkbd_send(struct dnkbd_softc *, const uint8_t *, size_t); 266 267 int 268 dnkbd_match(device_t parent, cfdata_t cf, void *aux) 269 { 270 struct frodo_attach_args *fa = aux; 271 272 if (strcmp(fa->fa_name, dnkbd_cd.cd_name) != 0) 273 return 0; 274 275 if (machineid == HP_382) { 276 /* 382 has frodo but no Domain keyboard connector. */ 277 return 0; 278 } 279 280 /* only attach to the first frodo port */ 281 return fa->fa_offset == FRODO_APCI_OFFSET(0); 282 } 283 284 void 285 dnkbd_attach(device_t parent, device_t self, void *aux) 286 { 287 struct dnkbd_softc *sc = device_private(self); 288 struct frodo_attach_args *fa = aux; 289 290 aprint_normal(": "); 291 292 sc->sc_dev = self; 293 sc->sc_bst = fa->fa_bst; 294 if (bus_space_map(sc->sc_bst, fa->fa_base + fa->fa_offset, 295 FRODO_APCISPACE, 0, &sc->sc_bsh) != 0) { 296 aprint_error(": can't map i/o space\n"); 297 return; 298 } 299 300 callout_init(&sc->sc_bellstop_tmo, 0); 301 callout_setfunc(&sc->sc_bellstop_tmo, dnkbd_bellstop, sc); 302 #ifdef WSDISPLAY_COMPAT_RAWKBD 303 callout_init(&sc->sc_rawrepeat_ch, 0); 304 callout_setfunc(&sc->sc_rawrepeat_ch, dnkbd_rawrepeat, sc); 305 #endif 306 307 /* reset the port */ 308 dnkbd_init(sc, 1200, LCR_8BITS | LCR_PEVEN | LCR_PENAB); 309 310 frodo_intr_establish(parent, dnkbd_intr, sc, fa->fa_line, IPL_VM); 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 (major(cn_tab->cn_dev) == devsw_name2chr("wsdisplay", NULL, 0)) { 363 #if NHILKBD > 0 364 if (hil_is_console == -1) { 365 ka.console = 1; 366 hil_is_console = 0; 367 } else 368 ka.console = 0; 369 #else 370 ka.console = 1; 371 #endif 372 } else 373 ka.console = 0; 374 375 ka.keymap = &dnkbd_keymapdata; 376 ka.accessops = &dnkbd_accessops; 377 ka.accesscookie = sc; 378 #ifndef DKKBD_LAYOUT 379 dnkbd_keymapdata.layout = sc->sc_layout; 380 #endif 381 382 if (ka.console) { 383 sc->sc_flags = SF_PLUGGED | SF_CONSOLE | SF_ENABLED; 384 wskbd_cnattach(&dnkbd_consops, sc, &dnkbd_keymapdata); 385 } else { 386 sc->sc_flags = SF_PLUGGED; 387 } 388 389 sc->sc_wskbddev = 390 config_found_ia(sc->sc_dev, "wskbddev", &ka, wskbddevprint); 391 392 #if NWSMOUSE > 0 393 ma.accessops = &dnmouse_accessops; 394 ma.accesscookie = sc; 395 396 sc->sc_wsmousedev = 397 config_found_ia(sc->sc_dev, "wsmousedev", &ma, wsmousedevprint); 398 #endif 399 400 SET(sc->sc_flags, SF_ATTACHED); 401 } 402 403 int 404 dnkbd_probe(struct dnkbd_softc *sc) 405 { 406 int dat, rc, flags; 407 uint8_t cmdbuf[2]; 408 char rspbuf[MAX_IDENTLEN], *word, *end; 409 u_int i; 410 int s; 411 412 s = spltty(); 413 flags = sc->sc_flags; 414 SET(sc->sc_flags, SF_POLLING); 415 sc->sc_state = STATE_CHANNEL; 416 splx(s); 417 418 /* 419 * Switch keyboard to raw mode. 420 */ 421 cmdbuf[0] = DNCMD_RAW; 422 rc = dnkbd_send(sc, cmdbuf, 1); 423 if (rc != 0) 424 goto out; 425 426 /* 427 * Send the identify command. 428 */ 429 cmdbuf[0] = DNCMD_IDENT_1; 430 cmdbuf[1] = DNCMD_IDENT_2; 431 rc = dnkbd_send(sc, cmdbuf, 2); 432 if (rc != 0) 433 goto out; 434 435 for (i = 0; ; i++) { 436 dat = dnkbd_pollin(sc, 10000); 437 if (dat == -1) 438 break; 439 440 if (i < sizeof(rspbuf)) 441 rspbuf[i] = dat; 442 } 443 444 if (i > sizeof(rspbuf) || i == 0) { 445 aprint_error_dev(sc->sc_dev, 446 "unexpected identify string length %d\n", i); 447 rc = ENXIO; 448 goto out; 449 } 450 451 /* 452 * Make sure the identification string is NULL terminated 453 * (overwriting the keyboard mode byte if necessary). 454 */ 455 i--; 456 if (rspbuf[i] != 0) 457 rspbuf[i] = 0; 458 459 /* 460 * Now display the identification strings, if they changed. 461 */ 462 if (i != sc->sc_identlen || memcmp(rspbuf, sc->sc_ident, i) != 0) { 463 sc->sc_layout = KB_US; 464 sc->sc_identlen = i; 465 memcpy(sc->sc_ident, rspbuf, i); 466 467 if (cold == 0) 468 aprint_normal_dev(sc->sc_dev, ""); 469 aprint_normal("model "); 470 word = rspbuf; 471 for (i = 0; i < 3; i++) { 472 end = strchr(word, '\r'); 473 if (end == NULL) 474 break; 475 *end++ = '\0'; 476 aprint_normal("<%s> ", word); 477 /* 478 * Parse the layout code if applicable 479 */ 480 if (i == 1 && *word++ == '3') { 481 if (*word == '-') 482 word++; 483 switch (*word) { 484 #if 0 485 default: 486 case ' ': 487 sc->sc_layout = KB_US; 488 break; 489 #endif 490 case 'a': 491 sc->sc_layout = KB_DE; 492 break; 493 case 'b': 494 sc->sc_layout = KB_FR; 495 break; 496 case 'c': 497 sc->sc_layout = KB_DK; 498 break; 499 case 'd': 500 sc->sc_layout = KB_SV; 501 break; 502 case 'e': 503 sc->sc_layout = KB_UK; 504 break; 505 case 'f': 506 sc->sc_layout = KB_JP; 507 break; 508 case 'g': 509 sc->sc_layout = KB_SG; 510 break; 511 } 512 } 513 word = end; 514 } 515 aprint_normal("\n"); 516 } 517 518 /* 519 * Ready to work, the default channel is the keyboard. 520 */ 521 sc->sc_state = STATE_KEYBOARD; 522 523 out: 524 s = spltty(); 525 sc->sc_flags = flags; 526 splx(s); 527 528 return rc; 529 } 530 531 /* 532 * State machine. 533 * 534 * In raw mode, the keyboard may feed us the following sequences: 535 * - on the keyboard channel: 536 * + a raw key code, in the range 0x01-0x7e, or'ed with 0x80 if key release. 537 * + the key repeat sequence 0x7f. 538 * - on the mouse channel: 539 * + a 3 byte mouse sequence (buttons state, dx move, dy move). 540 * - at any time: 541 * + a 2 byte channel sequence (0xff followed by the channel number) telling 542 * us which device the following input will come from. 543 * + if we get 0xff but an invalid channel number, this is a command echo. 544 * Currently we only handle this for bell commands, which size are known. 545 * Other commands are issued through dnkbd_send() which ``eats'' the echo. 546 * 547 * Older keyboards reset the channel to the keyboard (by sending ff 01) after 548 * every mouse packet. 549 */ 550 551 dnevent 552 dnkbd_input(struct dnkbd_softc *sc, int dat) 553 { 554 dnevent event = EVENT_NONE; 555 556 switch (sc->sc_state) { 557 case STATE_KEYBOARD: 558 switch (dat) { 559 case DNKEY_REPEAT: 560 /* 561 * We ignore event repeats, as wskbd does its own 562 * soft repeat processing. 563 */ 564 break; 565 case DNKEY_CHANNEL: 566 sc->sc_prevstate = sc->sc_state; 567 sc->sc_state = STATE_CHANNEL; 568 break; 569 default: 570 event = EVENT_KEYBOARD; 571 break; 572 } 573 break; 574 575 case STATE_MOUSE: 576 if (dat == DNKEY_CHANNEL && sc->sc_mousepos == 0) { 577 sc->sc_prevstate = sc->sc_state; 578 sc->sc_state = STATE_CHANNEL; 579 } else { 580 sc->sc_mousepkt[sc->sc_mousepos++] = dat; 581 if (sc->sc_mousepos == sizeof(sc->sc_mousepkt)) { 582 sc->sc_mousepos = 0; 583 event = EVENT_MOUSE; 584 } 585 } 586 break; 587 588 case STATE_CHANNEL: 589 switch (dat) { 590 case DNKEY_CHANNEL: 591 /* 592 * During hotplug, we might get spurious 0xff bytes. 593 * Ignore them. 594 */ 595 break; 596 case DNCHANNEL_RESET: 597 /* 598 * Identify the keyboard again. This will switch it to 599 * raw mode again. If this fails, we'll consider the 600 * keyboard as unplugged (to ignore further events until 601 * a successful reset). 602 */ 603 if (dnkbd_probe(sc) == 0) { 604 /* 605 * We need to attach wskbd and wsmouse children 606 * if this is a live first plug. 607 */ 608 if (!ISSET(sc->sc_flags, SF_ATTACHED)) 609 dnkbd_attach_subdevices(sc); 610 SET(sc->sc_flags, SF_PLUGGED); 611 } else { 612 CLR(sc->sc_flags, SF_PLUGGED); 613 } 614 615 sc->sc_state = STATE_KEYBOARD; 616 break; 617 case DNCHANNEL_KBD: 618 sc->sc_state = STATE_KEYBOARD; 619 break; 620 case DNCHANNEL_MOUSE: 621 sc->sc_state = STATE_MOUSE; 622 sc->sc_mousepos = 0; /* just in case */ 623 break; 624 case DNCMD_BELL: 625 /* 626 * We are getting a bell command echoed to us. 627 * Ignore it. 628 */ 629 sc->sc_state = STATE_ECHO; 630 sc->sc_echolen = 1; /* one byte to follow */ 631 break; 632 default: 633 printf("%s: unexpected channel byte %02x\n", 634 device_xname(sc->sc_dev), dat); 635 break; 636 } 637 break; 638 639 case STATE_ECHO: 640 if (--sc->sc_echolen == 0) { 641 /* get back to the state we were in before the echo */ 642 sc->sc_state = sc->sc_prevstate; 643 } 644 break; 645 } 646 647 return event; 648 } 649 650 /* 651 * Event breakers. 652 */ 653 654 void 655 dnkbd_decode(int keycode, u_int *type, int *key) 656 { 657 *type = (keycode & DNKEY_RELEASE) ? 658 WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN; 659 *key = (keycode & ~DNKEY_RELEASE); 660 } 661 662 void 663 dnevent_kbd(struct dnkbd_softc *sc, int dat) 664 { 665 if (!ISSET(sc->sc_flags, SF_PLUGGED)) 666 return; 667 668 if (sc->sc_wskbddev == NULL) 669 return; 670 671 if (!ISSET(sc->sc_flags, SF_ENABLED)) 672 return; 673 674 /* 675 * Even in raw mode, the caps lock key is treated specially: 676 * first key press causes event 0x7e, release causes no event; 677 * then a new key press causes nothing, and release causes 678 * event 0xfe. Moreover, while kept down, it does not produce 679 * repeat events. 680 * 681 * So the best we can do is fake the missed events, but this 682 * will not allow the capslock key to be remapped as a control 683 * key since it will not be possible to chord it with anything. 684 */ 685 dnevent_kbd_internal(sc, dat); 686 if ((dat & ~DNKEY_RELEASE) == DNKEY_CAPSLOCK) 687 dnevent_kbd_internal(sc, dat ^ DNKEY_RELEASE); 688 } 689 690 void 691 dnevent_kbd_internal(struct dnkbd_softc *sc, int dat) 692 { 693 u_int type; 694 int key; 695 int s; 696 697 dnkbd_decode(dat, &type, &key); 698 699 #ifdef WSDISPLAY_COMPAT_RAWKBD 700 if (sc->sc_rawkbd) { 701 u_char cbuf[2]; 702 int c, j = 0; 703 704 c = dnkbd_raw[key]; 705 if (c != 0) { 706 /* fake extended scancode if necessary */ 707 if (c & 0x80) 708 cbuf[j++] = 0xe0; 709 cbuf[j] = c & 0x7f; 710 if (type == WSCONS_EVENT_KEY_UP) 711 cbuf[j] |= 0x80; 712 else { 713 /* remember pressed key for autorepeat */ 714 memcpy(sc->sc_rep, cbuf, sizeof(sc->sc_rep)); 715 } 716 j++; 717 } 718 719 if (j != 0) { 720 s = spltty(); 721 wskbd_rawinput(sc->sc_wskbddev, cbuf, j); 722 splx(s); 723 callout_stop(&sc->sc_rawrepeat_ch); 724 sc->sc_nrep = j; 725 callout_schedule(&sc->sc_rawrepeat_ch, 726 mstohz(REP_DELAY1)); 727 } 728 } else 729 #endif 730 { 731 s = spltty(); 732 wskbd_input(sc->sc_wskbddev, type, key); 733 splx(s); 734 } 735 } 736 737 #ifdef WSDISPLAY_COMPAT_RAWKBD 738 void 739 dnkbd_rawrepeat(void *v) 740 { 741 struct dnkbd_softc *sc = v; 742 int s; 743 744 s = spltty(); 745 wskbd_rawinput(sc->sc_wskbddev, sc->sc_rep, sc->sc_nrep); 746 splx(s); 747 748 callout_schedule(&sc->sc_rawrepeat_ch, mstohz(REP_DELAYN)); 749 } 750 #endif 751 752 #if NWSMOUSE > 0 753 void 754 dnevent_mouse(struct dnkbd_softc *sc, uint8_t *dat) 755 { 756 if (!ISSET(sc->sc_flags, SF_PLUGGED)) 757 return; 758 759 if (sc->sc_wsmousedev == NULL) 760 return; 761 762 if (!ISSET(sc->sc_flags, SF_MOUSE)) 763 return; 764 765 /* 766 * First byte is button status. It has the 0x80 bit always set, and 767 * the next 3 bits are *cleared* when the mouse buttons are pressed. 768 */ 769 #ifdef DEBUG 770 if (!ISSET(*dat, 0x80)) { 771 printf("%s: incorrect mouse packet %02x %02x %02x\n", 772 device_xname(sc->sc_dev), dat[0], dat[1], dat[2]); 773 return; 774 } 775 #endif 776 777 wsmouse_input(sc->sc_wsmousedev, 778 (~dat[0] & (DNBUTTON_L | DNBUTTON_M | DNBUTTON_R)) >> 4, 779 (int8_t)dat[1], (int8_t)dat[2], 0, 0, WSMOUSE_INPUT_DELTA); 780 } 781 #endif 782 783 /* 784 * Low-level communication routines. 785 */ 786 787 int 788 dnkbd_pollin(struct dnkbd_softc *sc, u_int tries) 789 { 790 bus_space_tag_t bst; 791 bus_space_handle_t bsh; 792 u_int cnt; 793 794 bst = sc->sc_bst; 795 bsh = sc->sc_bsh; 796 797 for (cnt = tries; cnt != 0; cnt--) { 798 if (bus_space_read_1(bst, bsh, com_lsr) & LSR_RXRDY) 799 break; 800 DELAY(10); 801 } 802 803 if (cnt == 0) 804 return -1; 805 else 806 return (int)bus_space_read_1(bst, bsh, com_data); 807 } 808 809 int 810 dnkbd_pollout(struct dnkbd_softc *sc, int dat) 811 { 812 bus_space_tag_t bst; 813 bus_space_handle_t bsh; 814 u_int cnt; 815 816 bst = sc->sc_bst; 817 bsh = sc->sc_bsh; 818 819 for (cnt = 10000; cnt != 0; cnt--) { 820 if (bus_space_read_1(bst, bsh, com_lsr) & LSR_TXRDY) 821 break; 822 DELAY(10); 823 } 824 if (cnt == 0) 825 return EBUSY; 826 else { 827 bus_space_write_1(bst, bsh, com_data, dat); 828 return 0; 829 } 830 } 831 832 int 833 dnkbd_send(struct dnkbd_softc *sc, const uint8_t *cmdbuf, size_t cmdlen) 834 { 835 int cnt, rc, dat; 836 u_int cmdpos; 837 838 /* drain rxfifo */ 839 for (cnt = 10; cnt != 0; cnt--) { 840 if (dnkbd_pollin(sc, 10) == -1) 841 break; 842 } 843 if (cnt == 0) 844 return EBUSY; 845 846 /* send command escape */ 847 if ((rc = dnkbd_pollout(sc, DNCMD_PREFIX)) != 0) 848 return rc; 849 850 /* send command buffer */ 851 for (cmdpos = 0; cmdpos < cmdlen; cmdpos++) { 852 if ((rc = dnkbd_pollout(sc, cmdbuf[cmdpos])) != 0) 853 return rc; 854 } 855 856 /* wait for command echo */ 857 do { 858 dat = dnkbd_pollin(sc, 10000); 859 if (dat == -1) 860 return EIO; 861 } while (dat != DNCMD_PREFIX); 862 863 for (cmdpos = 0; cmdpos < cmdlen; cmdpos++) { 864 dat = dnkbd_pollin(sc, 10000); 865 if (dat != cmdbuf[cmdpos]) 866 return EIO; 867 } 868 869 return 0; 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 callout_stop(&sc->sc_rawrepeat_ch); 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