1 /* $NetBSD: pccons.c,v 1.56 2008/09/13 17:13:57 tsutsui Exp $ */ 2 /* $OpenBSD: pccons.c,v 1.22 1999/01/30 22:39:37 imp Exp $ */ 3 /* NetBSD: pccons.c,v 1.89 1995/05/04 19:35:20 cgd Exp */ 4 5 /*- 6 * Copyright (c) 1990 The Regents of the University of California. 7 * All rights reserved. 8 * 9 * This code is derived from software contributed to Berkeley by 10 * William Jolitz and Don Ahn. 11 * 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * @(#)pccons.c 5.11 (Berkeley) 5/21/91 36 */ 37 38 /*- 39 * Copyright (c) 1993, 1994, 1995 Charles M. Hannum. All rights reserved. 40 * 41 * This code is derived from software contributed to Berkeley by 42 * William Jolitz and Don Ahn. 43 * 44 * Copyright (c) 1994 Charles M. Hannum. 45 * Copyright (c) 1992, 1993 Erik Forsberg. 46 * 47 * Redistribution and use in source and binary forms, with or without 48 * modification, are permitted provided that the following conditions 49 * are met: 50 * 1. Redistributions of source code must retain the above copyright 51 * notice, this list of conditions and the following disclaimer. 52 * 2. Redistributions in binary form must reproduce the above copyright 53 * notice, this list of conditions and the following disclaimer in the 54 * documentation and/or other materials provided with the distribution. 55 * 3. All advertising materials mentioning features or use of this software 56 * must display the following acknowledgement: 57 * This product includes software developed by the University of 58 * California, Berkeley and its contributors. 59 * 4. Neither the name of the University nor the names of its contributors 60 * may be used to endorse or promote products derived from this software 61 * without specific prior written permission. 62 * 63 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 64 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 65 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 66 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 67 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 68 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 69 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 70 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 71 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 72 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 73 * SUCH DAMAGE. 74 * 75 * @(#)pccons.c 5.11 (Berkeley) 5/21/91 76 */ 77 78 /* 79 * code to work keyboard & display for PC-style console 80 */ 81 82 #include <sys/cdefs.h> 83 __KERNEL_RCSID(0, "$NetBSD: pccons.c,v 1.56 2008/09/13 17:13:57 tsutsui Exp $"); 84 85 #include "opt_ddb.h" 86 87 #include <sys/param.h> 88 #include <sys/systm.h> 89 #include <sys/tty.h> 90 #include <sys/callout.h> 91 #include <sys/poll.h> 92 #include <sys/conf.h> 93 #include <sys/vnode.h> 94 #include <sys/kernel.h> 95 #include <sys/kcore.h> 96 #include <sys/device.h> 97 #include <sys/proc.h> 98 #include <sys/kauth.h> 99 100 #include <machine/bus.h> 101 102 #include <dev/ic/pcdisplay.h> 103 #include <machine/pccons.h> 104 #include <machine/kbdreg.h> 105 106 #include <dev/cons.h> 107 #include <dev/isa/isavar.h> 108 109 #include <arc/arc/arcbios.h> 110 #include <arc/dev/pcconsvar.h> 111 112 #include "ioconf.h" 113 114 #define XFREE86_BUG_COMPAT 115 116 #ifndef BEEP_FREQ 117 #define BEEP_FREQ 1600 118 #endif 119 #ifndef BEEP_TIME 120 #define BEEP_TIME (hz/5) 121 #endif 122 123 #define PCBURST 128 124 125 static u_short *Crtat; /* pointer to backing store */ 126 static u_short *crtat; /* pointer to current char */ 127 static u_char async, kernel, polling; /* Really, you don't want to know. */ 128 static u_char lock_state = 0x00, /* all off */ 129 old_lock_state = 0xff, 130 typematic_rate = 0xff, /* don't update until set by user */ 131 old_typematic_rate = 0xff; 132 static u_short cursor_shape = 0xffff, /* don't update until set by user */ 133 old_cursor_shape = 0xffff; 134 static pccons_keymap_t scan_codes[KB_NUM_KEYS];/* keyboard translation table */ 135 int pc_xmode = 0; 136 137 /* 138 * Keyboard output queue. 139 */ 140 int kb_oq_put = 0; 141 int kb_oq_get = 0; 142 u_char kb_oq[8]; 143 144 #define PCUNIT(x) (minor(x)) 145 146 static struct video_state { 147 int cx, cy; /* escape parameters */ 148 int row, col; /* current cursor position */ 149 int nrow, ncol, nchr; /* current screen geometry */ 150 int offset; /* Saved cursor pos */ 151 u_char state; /* parser state */ 152 #define VSS_ESCAPE 1 153 #define VSS_EBRACE 2 154 #define VSS_EPARAM 3 155 char so; /* in standout mode? */ 156 char color; /* color or mono display */ 157 char at; /* normal attributes */ 158 char so_at; /* standout attributes */ 159 } vs; 160 161 static callout_t async_update_ch; 162 163 void pc_xmode_on(void); 164 void pc_xmode_off(void); 165 static u_char kbc_get8042cmd(void); 166 int kbd_cmd(u_char, u_char); 167 static inline int kbd_wait_output(void); 168 static inline int kbd_wait_input(void); 169 void kbd_flush_input(void); 170 void set_cursor_shape(void); 171 void get_cursor_shape(void); 172 void async_update(void); 173 void do_async_update(u_char); 174 175 void pccnputc(dev_t, int c); 176 int pccngetc(dev_t); 177 void pccnpollc(dev_t, int); 178 179 dev_type_open(pcopen); 180 dev_type_close(pcclose); 181 dev_type_read(pcread); 182 dev_type_write(pcwrite); 183 dev_type_ioctl(pcioctl); 184 dev_type_tty(pctty); 185 dev_type_poll(pcpoll); 186 dev_type_mmap(pcmmap); 187 188 const struct cdevsw pc_cdevsw = { 189 pcopen, pcclose, pcread, pcwrite, pcioctl, 190 nostop, pctty, pcpoll, pcmmap, ttykqfilter, D_TTY 191 }; 192 193 #define CHR 2 194 195 char *sget(void); 196 void sput(const u_char *, int); 197 198 void pcstart(struct tty *); 199 int pcparam(struct tty *, struct termios *); 200 static inline void wcopy(void *, void *, u_int); 201 void pc_context_init(bus_space_tag_t, bus_space_tag_t, bus_space_tag_t, 202 struct pccons_config *); 203 204 extern void fillw(int, uint16_t *, int); 205 206 #define KBD_DELAY \ 207 DELAY(10); 208 209 #define crtc_read_1(reg) \ 210 bus_space_read_1(pccons_console_context.pc_crt_iot, \ 211 pccons_console_context.pc_6845_ioh, reg) 212 #define crtc_write_1(reg, data) \ 213 bus_space_write_1(pccons_console_context.pc_crt_iot, \ 214 pccons_console_context.pc_6845_ioh, reg, data) 215 216 struct pccons_context pccons_console_context; 217 218 void 219 kbd_context_init(bus_space_tag_t kbd_iot, struct pccons_config *config) 220 { 221 struct pccons_kbd_context *pkc = &pccons_console_context.pc_pkc; 222 223 if (pkc->pkc_initialized) 224 return; 225 pkc->pkc_initialized = 1; 226 227 pkc->pkc_iot = kbd_iot; 228 229 bus_space_map(kbd_iot, config->pc_kbd_cmdp, 1, 0, 230 &pkc->pkc_cmd_ioh); 231 bus_space_map(kbd_iot, config->pc_kbd_datap, 1, 0, 232 &pkc->pkc_data_ioh); 233 } 234 235 void 236 pc_context_init(bus_space_tag_t crt_iot, bus_space_tag_t crt_memt, 237 bus_space_tag_t kbd_iot, struct pccons_config *config) 238 { 239 struct pccons_context *pc = &pccons_console_context; 240 241 if (pc->pc_initialized) 242 return; 243 pc->pc_initialized = 1; 244 245 kbd_context_init(kbd_iot, config); 246 247 pc->pc_crt_iot = crt_iot; 248 pc->pc_crt_memt = crt_memt; 249 250 bus_space_map(crt_iot, config->pc_mono_iobase, 2, 0, 251 &pc->pc_mono_ioh); 252 bus_space_map(crt_memt, config->pc_mono_memaddr, 0x20000, 0, 253 &pc->pc_mono_memh); 254 bus_space_map(crt_iot, config->pc_cga_iobase, 2, 0, 255 &pc->pc_cga_ioh); 256 bus_space_map(crt_memt, config->pc_cga_memaddr, 0x20000, 0, 257 &pc->pc_cga_memh); 258 259 /* 260 * pc->pc_6845_ioh and pc->pc_crt_memh will be initialized later, 261 * when `Crtat' is initialized. 262 */ 263 264 pc->pc_config = config; 265 266 (*config->pc_init)(); 267 } 268 269 /* 270 * bcopy variant that only moves word-aligned 16-bit entities, 271 * for stupid VGA cards. cnt is required to be an even value. 272 */ 273 static inline void 274 wcopy(void *src, void *tgt, u_int cnt) 275 { 276 uint16_t *from = src; 277 uint16_t *to = tgt; 278 279 cnt >>= 1; 280 if (to < from || to >= from + cnt) 281 while (cnt--) 282 *to++ = *from++; 283 else { 284 to += cnt; 285 from += cnt; 286 while (cnt--) 287 *--to = *--from; 288 } 289 } 290 291 static inline int 292 kbd_wait_output(void) 293 { 294 u_int i; 295 296 for (i = 100000; i; i--) 297 if ((kbd_cmd_read_1() & KBS_IBF) == 0) { 298 KBD_DELAY; 299 return 1; 300 } 301 return 0; 302 } 303 304 static inline int 305 kbd_wait_input(void) 306 { 307 u_int i; 308 309 for (i = 100000; i; i--) 310 if ((kbd_cmd_read_1() & KBS_DIB) != 0) { 311 KBD_DELAY; 312 return 1; 313 } 314 return 0; 315 } 316 317 void 318 kbd_flush_input(void) 319 { 320 uint8_t c; 321 322 while ((c = kbd_cmd_read_1()) & 0x03) 323 if ((c & KBS_DIB) == KBS_DIB) { 324 /* XXX - delay is needed to prevent some keyboards from 325 wedging when the system boots */ 326 delay(6); 327 (void)kbd_data_read_1(); 328 } 329 } 330 331 #if 1 332 /* 333 * Get the current command byte. 334 */ 335 static u_char 336 kbc_get8042cmd(void) 337 { 338 339 if (!kbd_wait_output()) 340 return -1; 341 kbd_cmd_write_1(K_RDCMDBYTE); 342 if (!kbd_wait_input()) 343 return -1; 344 return kbd_data_read_1(); 345 } 346 #endif 347 348 /* 349 * Pass command byte to keyboard controller (8042). 350 */ 351 int 352 kbc_put8042cmd(val) 353 uint8_t val; 354 { 355 356 if (!kbd_wait_output()) 357 return 0; 358 kbd_cmd_write_1(K_LDCMDBYTE); 359 if (!kbd_wait_output()) 360 return 0; 361 kbd_data_write_1(val); 362 return 1; 363 } 364 365 /* 366 * Pass command to keyboard itself 367 */ 368 int 369 kbd_cmd(uint8_t val, uint8_t polled) 370 { 371 u_int retries = 3; 372 u_int i; 373 374 if (!polled) { 375 i = spltty(); 376 if (kb_oq_get == kb_oq_put) { 377 kbd_data_write_1(val); 378 } 379 kb_oq[kb_oq_put] = val; 380 kb_oq_put = (kb_oq_put + 1) & 7; 381 splx(i); 382 return 1; 383 } 384 385 do { 386 if (!kbd_wait_output()) 387 return 0; 388 kbd_data_write_1(val); 389 for (i = 100000; i; i--) { 390 if (kbd_cmd_read_1() & KBS_DIB) { 391 uint8_t c; 392 393 KBD_DELAY; 394 c = kbd_data_read_1(); 395 if (c == KBR_ACK || c == KBR_ECHO) { 396 return 1; 397 } 398 if (c == KBR_RESEND) { 399 break; 400 } 401 #ifdef DIAGNOSTIC 402 printf("kbd_cmd: input char %x lost\n", c); 403 #endif 404 } 405 } 406 } while (--retries); 407 return 0; 408 } 409 410 void 411 set_cursor_shape(void) 412 { 413 414 crtc_write_1(0, 10); 415 crtc_write_1(1, cursor_shape >> 8); 416 crtc_write_1(0, 11); 417 crtc_write_1(1, cursor_shape); 418 old_cursor_shape = cursor_shape; 419 } 420 421 void 422 get_cursor_shape(void) 423 { 424 425 crtc_write_1(0, 10); 426 cursor_shape = crtc_read_1(1) << 8; 427 crtc_write_1(0, 11); 428 cursor_shape |= crtc_read_1(1); 429 430 /* 431 * real 6845's, as found on, MDA, Hercules or CGA cards, do 432 * not support reading the cursor shape registers. the 6845 433 * tri-states it's data bus. This is _normally_ read by the 434 * CPU as either 0x00 or 0xff.. in which case we just use 435 * a line cursor. 436 */ 437 if (cursor_shape == 0x0000 || cursor_shape == 0xffff) 438 cursor_shape = 0x0b10; 439 else 440 cursor_shape &= 0x1f1f; 441 } 442 443 void 444 do_async_update(uint8_t poll) 445 { 446 int pos; 447 static int old_pos = -1; 448 449 async = 0; 450 451 if (lock_state != old_lock_state) { 452 old_lock_state = lock_state; 453 if (!kbd_cmd(KBC_MODEIND, poll) || 454 !kbd_cmd(lock_state, poll)) { 455 printf("pc: timeout updating leds\n"); 456 (void) kbd_cmd(KBC_ENABLE, poll); 457 } 458 } 459 if (typematic_rate != old_typematic_rate) { 460 old_typematic_rate = typematic_rate; 461 if (!kbd_cmd(KBC_TYPEMATIC, poll) || 462 !kbd_cmd(typematic_rate, poll)) { 463 printf("pc: timeout updating typematic rate\n"); 464 (void) kbd_cmd(KBC_ENABLE, poll); 465 } 466 } 467 468 if (pc_xmode > 0) 469 return; 470 471 pos = crtat - Crtat; 472 if (pos != old_pos) { 473 crtc_write_1(0, 14); 474 crtc_write_1(1, pos >> 8); 475 crtc_write_1(0, 15); 476 crtc_write_1(1, pos); 477 old_pos = pos; 478 } 479 if (cursor_shape != old_cursor_shape) 480 set_cursor_shape(); 481 } 482 483 void 484 async_update(void) 485 { 486 487 if (kernel || polling) { 488 if (async) 489 callout_stop(&async_update_ch); 490 do_async_update(1); 491 } else { 492 if (async) 493 return; 494 async = 1; 495 callout_reset(&async_update_ch, 1, 496 (void(*)(void *))do_async_update, NULL); 497 } 498 } 499 500 /* 501 * these are both bad jokes 502 */ 503 int 504 pccons_common_match(bus_space_tag_t crt_iot, bus_space_tag_t crt_memt, 505 bus_space_tag_t kbd_iot, struct pccons_config *config) 506 { 507 int i; 508 509 pc_context_init(crt_iot, crt_memt, kbd_iot, config); 510 511 /* Enable interrupts and keyboard, etc. */ 512 if (!kbc_put8042cmd(CMDBYTE)) { 513 printf("pcprobe: command error\n"); 514 return 0; 515 } 516 517 #if 1 518 /* Flush any garbage. */ 519 kbd_flush_input(); 520 /* Reset the keyboard. */ 521 if (!kbd_cmd(KBC_RESET, 1)) { 522 printf("pcprobe: reset error %d\n", 1); 523 goto lose; 524 } 525 for (i = 600000; i; i--) 526 if ((kbd_cmd_read_1() & KBS_DIB) != 0) { 527 KBD_DELAY; 528 break; 529 } 530 if (i == 0 || kbd_data_read_1() != KBR_RSTDONE) { 531 printf("pcprobe: reset error %d\n", 2); 532 goto lose; 533 } 534 /* 535 * Some keyboards seem to leave a second ack byte after the reset. 536 * This is kind of stupid, but we account for them anyway by just 537 * flushing the buffer. 538 */ 539 kbd_flush_input(); 540 /* Just to be sure. */ 541 if (!kbd_cmd(KBC_ENABLE, 1)) { 542 printf("pcprobe: reset error %d\n", 3); 543 goto lose; 544 } 545 546 /* 547 * Some keyboard/8042 combinations do not seem to work if the keyboard 548 * is set to table 1; in fact, it would appear that some keyboards just 549 * ignore the command altogether. So by default, we use the AT scan 550 * codes and have the 8042 translate them. Unfortunately, this is 551 * known to not work on some PS/2 machines. We try desparately to deal 552 * with this by checking the (lack of a) translate bit in the 8042 and 553 * attempting to set the keyboard to XT mode. If this all fails, well, 554 * tough luck. 555 * 556 * XXX It would perhaps be a better choice to just use AT scan codes 557 * and not bother with this. 558 */ 559 if (kbc_get8042cmd() & KC8_TRANS) { 560 /* The 8042 is translating for us; use AT codes. */ 561 if (!kbd_cmd(KBC_SETTABLE, 1) || !kbd_cmd(2, 1)) { 562 printf("pcprobe: reset error %d\n", 4); 563 goto lose; 564 } 565 } else { 566 /* Stupid 8042; set keyboard to XT codes. */ 567 if (!kbd_cmd(KBC_SETTABLE, 1) || !kbd_cmd(1, 1)) { 568 printf("pcprobe: reset error %d\n", 5); 569 goto lose; 570 } 571 } 572 573 lose: 574 /* 575 * Technically, we should probably fail the probe. But we'll be nice 576 * and allow keyboard-less machines to boot with the console. 577 */ 578 #endif 579 580 return 1; 581 } 582 583 void pccons_common_attach(struct pc_softc *sc, bus_space_tag_t crt_iot, 584 bus_space_tag_t crt_memt, bus_space_tag_t kbd_iot, 585 struct pccons_config *config) 586 { 587 588 printf(": %s\n", vs.color ? "color" : "mono"); 589 callout_init(&async_update_ch, 0); 590 do_async_update(1); 591 } 592 593 int 594 pcopen(dev_t dev, int flag, int mode, struct lwp *l) 595 { 596 struct pc_softc *sc; 597 struct tty *tp; 598 599 sc = device_lookup_private(&pc_cd, PCUNIT(dev)); 600 if (sc == NULL) 601 return ENXIO; 602 603 if (!sc->sc_tty) { 604 tp = sc->sc_tty = ttymalloc(); 605 } 606 else { 607 tp = sc->sc_tty; 608 } 609 610 tp->t_oproc = pcstart; 611 tp->t_param = pcparam; 612 tp->t_dev = dev; 613 614 if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp)) 615 return (EBUSY); 616 617 if ((tp->t_state & TS_ISOPEN) == 0) { 618 ttychars(tp); 619 tp->t_iflag = TTYDEF_IFLAG; 620 tp->t_oflag = TTYDEF_OFLAG; 621 tp->t_cflag = TTYDEF_CFLAG; 622 tp->t_lflag = TTYDEF_LFLAG; 623 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 624 pcparam(tp, &tp->t_termios); 625 ttsetwater(tp); 626 } 627 628 tp->t_state |= TS_CARR_ON; 629 630 return (*tp->t_linesw->l_open)(dev, tp); 631 } 632 633 int 634 pcclose(dev_t dev, int flag, int mode, struct lwp *l) 635 { 636 struct pc_softc *sc = device_lookup_private(&pc_cd, PCUNIT(dev)); 637 struct tty *tp = sc->sc_tty; 638 639 (*tp->t_linesw->l_close)(tp, flag); 640 ttyclose(tp); 641 #ifdef notyet /* XXX */ 642 ttyfree(tp); 643 #endif 644 return 0; 645 } 646 647 int 648 pcread(dev_t dev, struct uio *uio, int flag) 649 { 650 struct pc_softc *sc = device_lookup_private(&pc_cd, PCUNIT(dev)); 651 struct tty *tp = sc->sc_tty; 652 653 return (*tp->t_linesw->l_read)(tp, uio, flag); 654 } 655 656 int 657 pcwrite(dev_t dev, struct uio *uio, int flag) 658 { 659 struct pc_softc *sc = device_lookup_private(&pc_cd, PCUNIT(dev)); 660 struct tty *tp = sc->sc_tty; 661 662 return (*tp->t_linesw->l_write)(tp, uio, flag); 663 } 664 665 int 666 pcpoll(dev_t dev, int events, struct lwp *l) 667 { 668 struct pc_softc *sc = device_lookup_private(&pc_cd, PCUNIT(dev)); 669 struct tty *tp = sc->sc_tty; 670 671 return (*tp->t_linesw->l_poll)(tp, events, l); 672 } 673 674 struct tty * 675 pctty(dev_t dev) 676 { 677 struct pc_softc *sc = device_lookup_private(&pc_cd, PCUNIT(dev)); 678 struct tty *tp = sc->sc_tty; 679 680 return tp; 681 } 682 683 /* 684 * Got a console receive interrupt - 685 * the console processor wants to give us a character. 686 * Catch the character, and see who it goes to. 687 */ 688 int 689 pcintr(void *arg) 690 { 691 struct pc_softc *sc = arg; 692 struct tty *tp = sc->sc_tty; 693 uint8_t *cp; 694 695 if ((kbd_cmd_read_1() & KBS_DIB) == 0) 696 return 0; 697 if (polling) 698 return 1; 699 do { 700 cp = sget(); 701 if (!tp || (tp->t_state & TS_ISOPEN) == 0) 702 return 1; 703 if (cp) 704 do 705 (*tp->t_linesw->l_rint)(*cp++, tp); 706 while (*cp); 707 } while (kbd_cmd_read_1() & KBS_DIB); 708 return 1; 709 } 710 711 int 712 pcioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 713 { 714 struct pc_softc *sc = device_lookup_private(&pc_cd, PCUNIT(dev)); 715 struct tty *tp = sc->sc_tty; 716 int error; 717 718 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l); 719 if (error != EPASSTHROUGH) 720 return error; 721 error = ttioctl(tp, cmd, data, flag, l); 722 if (error != EPASSTHROUGH) 723 return error; 724 725 switch (cmd) { 726 case CONSOLE_X_MODE_ON: 727 pc_xmode_on(); 728 return 0; 729 case CONSOLE_X_MODE_OFF: 730 pc_xmode_off(); 731 return 0; 732 case CONSOLE_X_BELL: 733 /* 734 * If set, data is a pointer to a length 2 array of 735 * integers. data[0] is the pitch in Hz and data[1] 736 * is the duration in msec. 737 */ 738 if (data) 739 sysbeep(((int*)data)[0], 740 (((int*)data)[1] * hz) / 1000); 741 else 742 sysbeep(BEEP_FREQ, BEEP_TIME); 743 return 0; 744 case CONSOLE_SET_TYPEMATIC_RATE: { 745 u_char rate; 746 747 if (!data) 748 return EINVAL; 749 rate = *((u_char *)data); 750 /* 751 * Check that it isn't too big (which would cause it to be 752 * confused with a command). 753 */ 754 if (rate & 0x80) 755 return EINVAL; 756 typematic_rate = rate; 757 async_update(); 758 return 0; 759 } 760 case CONSOLE_SET_KEYMAP: { 761 pccons_keymap_t *map = (pccons_keymap_t *) data; 762 int i; 763 764 if (!data) 765 return EINVAL; 766 for (i = 0; i < KB_NUM_KEYS; i++) 767 if (map[i].unshift[KB_CODE_SIZE-1] || 768 map[i].shift[KB_CODE_SIZE-1] || 769 map[i].ctl[KB_CODE_SIZE-1] || 770 map[i].altgr[KB_CODE_SIZE-1] || 771 map[i].shift_altgr[KB_CODE_SIZE-1]) 772 return EINVAL; 773 774 memcpy(scan_codes, data, sizeof(pccons_keymap_t[KB_NUM_KEYS])); 775 return 0; 776 } 777 case CONSOLE_GET_KEYMAP: 778 if (!data) 779 return EINVAL; 780 memcpy(scan_codes, data, sizeof(pccons_keymap_t[KB_NUM_KEYS])); 781 return 0; 782 783 default: 784 return EPASSTHROUGH; 785 } 786 787 #ifdef DIAGNOSTIC 788 panic("pcioctl: impossible"); 789 #endif 790 } 791 792 void 793 pcstart(struct tty *tp) 794 { 795 struct clist *cl; 796 int s, len; 797 u_char buf[PCBURST]; 798 799 s = spltty(); 800 if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) 801 goto out; 802 tp->t_state |= TS_BUSY; 803 splx(s); 804 /* 805 * We need to do this outside spl since it could be fairly 806 * expensive and we don't want our serial ports to overflow. 807 */ 808 cl = &tp->t_outq; 809 len = q_to_b(cl, buf, PCBURST); 810 sput(buf, len); 811 s = spltty(); 812 tp->t_state &= ~TS_BUSY; 813 if (ttypull(tp)) { 814 tp->t_state |= TS_TIMEOUT; 815 callout_schedule(&tp->t_rstrt_ch, 1); 816 } 817 out: 818 splx(s); 819 } 820 821 /* ARGSUSED */ 822 void pccons_common_cnattach(bus_space_tag_t crt_iot, bus_space_tag_t crt_memt, 823 bus_space_tag_t kbd_iot, struct pccons_config *config) 824 { 825 int maj; 826 static struct consdev pccons = { 827 NULL, NULL, pccngetc, pccnputc, pccnpollc, NULL, NULL, 828 NULL, NODEV, CN_NORMAL 829 }; 830 831 /* 832 * For now, don't screw with it. 833 */ 834 /* crtat = 0; */ 835 836 pc_context_init(crt_iot, crt_memt, kbd_iot, config); 837 838 /* locate the major number */ 839 maj = cdevsw_lookup_major(&pc_cdevsw); 840 pccons.cn_dev = makedev(maj, 0); 841 842 cn_tab = &pccons; 843 } 844 845 /* ARGSUSED */ 846 void 847 pccnputc(dev_t dev, int c) 848 { 849 u_char cc, oldkernel = kernel; 850 851 kernel = 1; 852 if (c == '\n') { 853 sput("\r\n", 2); 854 } else { 855 cc = c; 856 sput(&cc, 1); 857 } 858 kernel = oldkernel; 859 } 860 861 /* ARGSUSED */ 862 int 863 pccngetc(dev_t dev) 864 { 865 char *cp; 866 867 if (pc_xmode > 0) 868 return 0; 869 870 do { 871 /* wait for byte */ 872 while ((kbd_cmd_read_1() & KBS_DIB) == 0); 873 /* see if it's worthwhile */ 874 cp = sget(); 875 } while (!cp); 876 if (*cp == '\r') 877 return '\n'; 878 return *cp; 879 } 880 881 void 882 pccnpollc(dev_t dev, int on) 883 { 884 885 polling = on; 886 if (!on) { 887 int unit; 888 struct pc_softc *sc; 889 int s; 890 891 /* 892 * If disabling polling on a device that's been configured, 893 * make sure there are no bytes left in the FIFO, holding up 894 * the interrupt line. Otherwise we won't get any further 895 * interrupts. 896 */ 897 unit = PCUNIT(dev); 898 if (pc_cd.cd_ndevs > unit) { 899 sc = device_lookup_private(&pc_cd, unit); 900 if (sc != NULL) { 901 s = spltty(); 902 pcintr(sc); 903 splx(s); 904 } 905 } 906 } 907 } 908 909 /* 910 * Set line parameters. 911 */ 912 int 913 pcparam(struct tty *tp, struct termios *t) 914 { 915 916 tp->t_ispeed = t->c_ispeed; 917 tp->t_ospeed = t->c_ospeed; 918 tp->t_cflag = t->c_cflag; 919 return 0; 920 } 921 922 #define wrtchar(c, at) do {\ 923 char *cp0 = (char *)crtat; *cp0++ = (c); *cp0 = (at); crtat++; vs.col++; \ 924 } while (0) 925 926 /* translate ANSI color codes to standard pc ones */ 927 static char fgansitopc[] = { 928 FG_BLACK, FG_RED, FG_GREEN, FG_BROWN, FG_BLUE, 929 FG_MAGENTA, FG_CYAN, FG_LIGHTGREY 930 }; 931 932 static char bgansitopc[] = { 933 BG_BLACK, BG_RED, BG_GREEN, BG_BROWN, BG_BLUE, 934 BG_MAGENTA, BG_CYAN, BG_LIGHTGREY 935 }; 936 937 static u_char iso2ibm437[] = 938 { 939 0, 0, 0, 0, 0, 0, 0, 0, 940 0, 0, 0, 0, 0, 0, 0, 0, 941 0, 0, 0, 0, 0, 0, 0, 0, 942 0, 0, 0, 0, 0, 0, 0, 0, 943 0xff, 0xad, 0x9b, 0x9c, 0, 0x9d, 0, 0x40, 944 0x6f, 0x63, 0x61, 0xae, 0, 0, 0, 0, 945 0xf8, 0xf1, 0xfd, 0x33, 0, 0xe6, 0, 0xfa, 946 0, 0x31, 0x6f, 0xaf, 0xac, 0xab, 0, 0xa8, 947 0x41, 0x41, 0x41, 0x41, 0x8e, 0x8f, 0x92, 0x80, 948 0x45, 0x90, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49, 949 0x81, 0xa5, 0x4f, 0x4f, 0x4f, 0x4f, 0x99, 0x4f, 950 0x4f, 0x55, 0x55, 0x55, 0x9a, 0x59, 0, 0xe1, 951 0x85, 0xa0, 0x83, 0x61, 0x84, 0x86, 0x91, 0x87, 952 0x8a, 0x82, 0x88, 0x89, 0x8d, 0xa1, 0x8c, 0x8b, 953 0, 0xa4, 0x95, 0xa2, 0x93, 0x6f, 0x94, 0x6f, 954 0x6f, 0x97, 0xa3, 0x96, 0x81, 0x98, 0, 0 955 }; 956 957 /* 958 * `pc3' termcap emulation. 959 */ 960 void 961 sput(const u_char *cp, int n) 962 { 963 struct pccons_context *pc = &pccons_console_context; 964 u_char c, scroll = 0; 965 966 if (pc_xmode > 0) 967 return; 968 969 if (crtat == 0) { 970 volatile u_short *dp; 971 u_short was; 972 unsigned cursorat; 973 974 dp = bus_space_vaddr(pc->pc_crt_memt, pc->pc_cga_memh); 975 was = *dp; 976 *dp = 0xA55A; 977 if (*dp != 0xA55A) { 978 dp = bus_space_vaddr(pc->pc_crt_memt, 979 pc->pc_mono_memh); 980 pc->pc_6845_ioh = pc->pc_mono_ioh; 981 pc->pc_crt_memh = pc->pc_mono_memh; 982 vs.color = 0; 983 } else { 984 *dp = was; 985 pc->pc_6845_ioh = pc->pc_cga_ioh; 986 pc->pc_crt_memh = pc->pc_cga_memh; 987 vs.color = 1; 988 } 989 990 #ifdef FAT_CURSOR 991 cursor_shape = 0x0012; 992 #else 993 get_cursor_shape(); 994 #endif 995 996 bios_display_info(&vs.col, &vs.row, &vs.ncol, &vs.nrow); 997 vs.nchr = vs.ncol * vs.nrow; 998 vs.col--; 999 vs.row--; 1000 cursorat = vs.ncol * vs.row + vs.col; 1001 vs.at = FG_LIGHTGREY | BG_BLACK; 1002 1003 Crtat = (u_short *)__UNVOLATILE(dp); 1004 crtat = Crtat + cursorat; 1005 1006 if (vs.color == 0) 1007 vs.so_at = FG_BLACK | BG_LIGHTGREY; 1008 else 1009 vs.so_at = FG_YELLOW | BG_BLACK; 1010 1011 fillw((vs.at << 8) | ' ', crtat, vs.nchr - cursorat); 1012 } 1013 1014 while (n--) { 1015 if (!(c = *cp++)) 1016 continue; 1017 1018 switch (c) { 1019 case 0x1B: 1020 if (vs.state >= VSS_ESCAPE) { 1021 wrtchar(c, vs.so_at); 1022 vs.state = 0; 1023 goto maybe_scroll; 1024 } else 1025 vs.state = VSS_ESCAPE; 1026 break; 1027 1028 case 0x9B: /* CSI */ 1029 vs.cx = vs.cy = 0; 1030 vs.state = VSS_EBRACE; 1031 break; 1032 1033 case '\t': { 1034 int inccol = 8 - (vs.col & 7); 1035 crtat += inccol; 1036 vs.col += inccol; 1037 } 1038 maybe_scroll: 1039 if (vs.col >= vs.ncol) { 1040 vs.col -= vs.ncol; 1041 scroll = 1; 1042 } 1043 break; 1044 1045 case '\b': 1046 if (crtat <= Crtat) 1047 break; 1048 --crtat; 1049 if (--vs.col < 0) 1050 vs.col += vs.ncol; /* non-destructive backspace */ 1051 break; 1052 1053 case '\r': 1054 crtat -= vs.col; 1055 vs.col = 0; 1056 break; 1057 1058 case '\n': 1059 crtat += vs.ncol; 1060 scroll = 1; 1061 break; 1062 1063 default: 1064 switch (vs.state) { 1065 case 0: 1066 if (c == '\a') 1067 sysbeep(BEEP_FREQ, BEEP_TIME); 1068 else { 1069 /* 1070 * If we're outputting multiple printed 1071 * characters, just blast them to the 1072 * screen until we reach the end of the 1073 * buffer or a control character. This 1074 * saves time by short-circuiting the 1075 * switch. 1076 * If we reach the end of the line, we 1077 * break to do a scroll check. 1078 */ 1079 for (;;) { 1080 if (c & 0x80) 1081 c = iso2ibm437[c&0x7f]; 1082 1083 if (vs.so) 1084 wrtchar(c, vs.so_at); 1085 else 1086 wrtchar(c, vs.at); 1087 if (vs.col >= vs.ncol) { 1088 vs.col = 0; 1089 scroll = 1; 1090 break; 1091 } 1092 if (!n || (c = *cp) < ' ') 1093 break; 1094 n--, cp++; 1095 } 1096 } 1097 break; 1098 case VSS_ESCAPE: 1099 switch (c) { 1100 case '[': /* Start ESC [ sequence */ 1101 vs.cx = vs.cy = 0; 1102 vs.state = VSS_EBRACE; 1103 break; 1104 case 'c': /* Create screen & home */ 1105 fillw((vs.at << 8) | ' ', 1106 Crtat, vs.nchr); 1107 crtat = Crtat; 1108 vs.col = 0; 1109 vs.state = 0; 1110 break; 1111 case '7': /* save cursor pos */ 1112 vs.offset = crtat - Crtat; 1113 vs.state = 0; 1114 break; 1115 case '8': /* restore cursor pos */ 1116 crtat = Crtat + vs.offset; 1117 vs.row = vs.offset / vs.ncol; 1118 vs.col = vs.offset % vs.ncol; 1119 vs.state = 0; 1120 break; 1121 default: /* Invalid, clear state */ 1122 wrtchar(c, vs.so_at); 1123 vs.state = 0; 1124 goto maybe_scroll; 1125 } 1126 break; 1127 1128 default: /* VSS_EBRACE or VSS_EPARAM */ 1129 switch (c) { 1130 int pos; 1131 case 'm': 1132 if (!vs.cx) 1133 vs.so = 0; 1134 else 1135 vs.so = 1; 1136 vs.state = 0; 1137 break; 1138 case 'A': { /* back cx rows */ 1139 int cx = vs.cx; 1140 if (cx <= 0) 1141 cx = 1; 1142 else 1143 cx %= vs.nrow; 1144 pos = crtat - Crtat; 1145 pos -= vs.ncol * cx; 1146 if (pos < 0) 1147 pos += vs.nchr; 1148 crtat = Crtat + pos; 1149 vs.state = 0; 1150 break; 1151 } 1152 case 'B': { /* down cx rows */ 1153 int cx = vs.cx; 1154 if (cx <= 0) 1155 cx = 1; 1156 else 1157 cx %= vs.nrow; 1158 pos = crtat - Crtat; 1159 pos += vs.ncol * cx; 1160 if (pos >= vs.nchr) 1161 pos -= vs.nchr; 1162 crtat = Crtat + pos; 1163 vs.state = 0; 1164 break; 1165 } 1166 case 'C': { /* right cursor */ 1167 int cx = vs.cx, 1168 col = vs.col; 1169 if (cx <= 0) 1170 cx = 1; 1171 else 1172 cx %= vs.ncol; 1173 pos = crtat - Crtat; 1174 pos += cx; 1175 col += cx; 1176 if (col >= vs.ncol) { 1177 pos -= vs.ncol; 1178 col -= vs.ncol; 1179 } 1180 vs.col = col; 1181 crtat = Crtat + pos; 1182 vs.state = 0; 1183 break; 1184 } 1185 case 'D': { /* left cursor */ 1186 int cx = vs.cx, 1187 col = vs.col; 1188 if (cx <= 0) 1189 cx = 1; 1190 else 1191 cx %= vs.ncol; 1192 pos = crtat - Crtat; 1193 pos -= cx; 1194 col -= cx; 1195 if (col < 0) { 1196 pos += vs.ncol; 1197 col += vs.ncol; 1198 } 1199 vs.col = col; 1200 crtat = Crtat + pos; 1201 vs.state = 0; 1202 break; 1203 } 1204 case 'J': /* Clear ... */ 1205 switch (vs.cx) { 1206 case 0: 1207 /* ... to end of display */ 1208 fillw((vs.at << 8) | ' ', 1209 crtat, 1210 Crtat + vs.nchr - crtat); 1211 break; 1212 case 1: 1213 /* ... to next location */ 1214 fillw((vs.at << 8) | ' ', 1215 Crtat, 1216 crtat - Crtat + 1); 1217 break; 1218 case 2: 1219 /* ... whole display */ 1220 fillw((vs.at << 8) | ' ', 1221 Crtat, 1222 vs.nchr); 1223 break; 1224 } 1225 vs.state = 0; 1226 break; 1227 case 'K': /* Clear line ... */ 1228 switch (vs.cx) { 1229 case 0: 1230 /* ... current to EOL */ 1231 fillw((vs.at << 8) | ' ', 1232 crtat, 1233 vs.ncol - vs.col); 1234 break; 1235 case 1: 1236 /* ... beginning to next */ 1237 fillw((vs.at << 8) | ' ', 1238 crtat - vs.col, 1239 vs.col + 1); 1240 break; 1241 case 2: 1242 /* ... entire line */ 1243 fillw((vs.at << 8) | ' ', 1244 crtat - vs.col, vs.ncol); 1245 break; 1246 } 1247 vs.state = 0; 1248 break; 1249 case 'f': /* in system V consoles */ 1250 case 'H': { /* Cursor move */ 1251 int cx = vs.cx, 1252 cy = vs.cy; 1253 if (!cx || !cy) { 1254 crtat = Crtat; 1255 vs.col = 0; 1256 } else { 1257 if (cx > vs.nrow) 1258 cx = vs.nrow; 1259 if (cy > vs.ncol) 1260 cy = vs.ncol; 1261 crtat = Crtat + 1262 (cx - 1) * vs.ncol + cy - 1; 1263 vs.col = cy - 1; 1264 } 1265 vs.state = 0; 1266 break; 1267 } 1268 case 'M': { /* delete cx rows */ 1269 u_short *crtAt = crtat - vs.col; 1270 int cx = vs.cx, 1271 row = (crtAt - Crtat) / vs.ncol, 1272 nrow = vs.nrow - row; 1273 if (cx <= 0) 1274 cx = 1; 1275 else if (cx > nrow) 1276 cx = nrow; 1277 if (cx < nrow) 1278 #ifdef PCCONS_FORCE_WORD 1279 wcopy(crtAt + vs.ncol * cx, 1280 crtAt, vs.ncol * (nrow - 1281 cx) * CHR); 1282 #else 1283 memmove(crtAt, 1284 crtAt + vs.ncol * cx, 1285 vs.ncol * (nrow - cx) * 1286 CHR); 1287 #endif 1288 fillw((vs.at << 8) | ' ', 1289 crtAt + vs.ncol * (nrow - cx), 1290 vs.ncol * cx); 1291 vs.state = 0; 1292 break; 1293 } 1294 case 'S': { /* scroll up cx lines */ 1295 int cx = vs.cx; 1296 if (cx <= 0) 1297 cx = 1; 1298 else if (cx > vs.nrow) 1299 cx = vs.nrow; 1300 if (cx < vs.nrow) 1301 #ifdef PCCONS_FORCE_WORD 1302 wcopy(Crtat + vs.ncol * cx, 1303 Crtat, vs.ncol * (vs.nrow - 1304 cx) * CHR); 1305 #else 1306 memmove(Crtat, 1307 Crtat + vs.ncol * cx, 1308 vs.ncol * (vs.nrow - cx) * 1309 CHR); 1310 #endif 1311 fillw((vs.at << 8) | ' ', 1312 Crtat + vs.ncol * (vs.nrow - cx), 1313 vs.ncol * cx); 1314 /* crtat -= vs.ncol * cx; XXX */ 1315 vs.state = 0; 1316 break; 1317 } 1318 case 'L': { /* insert cx rows */ 1319 u_short *crtAt = crtat - vs.col; 1320 int cx = vs.cx, 1321 row = (crtAt - Crtat) / vs.ncol, 1322 nrow = vs.nrow - row; 1323 if (cx <= 0) 1324 cx = 1; 1325 else if (cx > nrow) 1326 cx = nrow; 1327 if (cx < nrow) 1328 #ifdef PCCONS_FORCE_WORD 1329 wcopy(crtAt, 1330 crtAt + vs.ncol * cx, 1331 vs.ncol * (nrow - cx) * 1332 CHR); 1333 #else 1334 memmove(crtAt + vs.ncol * cx, 1335 crtAt, 1336 vs.ncol * (nrow - cx) * 1337 CHR); 1338 #endif 1339 fillw((vs.at << 8) | ' ', crtAt, 1340 vs.ncol * cx); 1341 vs.state = 0; 1342 break; 1343 } 1344 case 'T': { /* scroll down cx lines */ 1345 int cx = vs.cx; 1346 if (cx <= 0) 1347 cx = 1; 1348 else if (cx > vs.nrow) 1349 cx = vs.nrow; 1350 if (cx < vs.nrow) 1351 #ifdef PCCONS_FORCE_WORD 1352 wcopy(Crtat, 1353 Crtat + vs.ncol * cx, 1354 vs.ncol * (vs.nrow - cx) * 1355 CHR); 1356 #else 1357 memmove(Crtat + vs.ncol * cx, 1358 Crtat, 1359 vs.ncol * (vs.nrow - cx) * 1360 CHR); 1361 #endif 1362 fillw((vs.at << 8) | ' ', Crtat, 1363 vs.ncol * cx); 1364 /* crtat += vs.ncol * cx; XXX */ 1365 vs.state = 0; 1366 break; 1367 } 1368 case ';': /* Switch params in cursor def */ 1369 vs.state = VSS_EPARAM; 1370 break; 1371 case 'r': 1372 vs.so_at = (vs.cx & FG_MASK) | 1373 ((vs.cy << 4) & BG_MASK); 1374 vs.state = 0; 1375 break; 1376 case 's': /* save cursor pos */ 1377 vs.offset = crtat - Crtat; 1378 vs.state = 0; 1379 break; 1380 case 'u': /* restore cursor pos */ 1381 crtat = Crtat + vs.offset; 1382 vs.row = vs.offset / vs.ncol; 1383 vs.col = vs.offset % vs.ncol; 1384 vs.state = 0; 1385 break; 1386 case 'x': /* set attributes */ 1387 switch (vs.cx) { 1388 case 0: 1389 vs.at = FG_LIGHTGREY | BG_BLACK; 1390 break; 1391 case 1: 1392 /* ansi background */ 1393 if (!vs.color) 1394 break; 1395 vs.at &= FG_MASK; 1396 vs.at |= bgansitopc[vs.cy & 7]; 1397 break; 1398 case 2: 1399 /* ansi foreground */ 1400 if (!vs.color) 1401 break; 1402 vs.at &= BG_MASK; 1403 vs.at |= fgansitopc[vs.cy & 7]; 1404 break; 1405 case 3: 1406 /* pc text attribute */ 1407 if (vs.state >= VSS_EPARAM) 1408 vs.at = vs.cy; 1409 break; 1410 } 1411 vs.state = 0; 1412 break; 1413 1414 default: /* Only numbers valid here */ 1415 if ((c >= '0') && (c <= '9')) { 1416 if (vs.state >= VSS_EPARAM) { 1417 vs.cy *= 10; 1418 vs.cy += c - '0'; 1419 } else { 1420 vs.cx *= 10; 1421 vs.cx += c - '0'; 1422 } 1423 } else 1424 vs.state = 0; 1425 break; 1426 } 1427 break; 1428 } 1429 } 1430 if (scroll) { 1431 scroll = 0; 1432 /* scroll check */ 1433 if (crtat >= Crtat + vs.nchr) { 1434 if (!kernel) { 1435 int s = spltty(); 1436 if (lock_state & KB_SCROLL) 1437 tsleep(&lock_state, 1438 PUSER, "pcputc", 0); 1439 splx(s); 1440 } 1441 #if PCCONS_FORCE_WORD 1442 wcopy(Crtat + vs.ncol, Crtat, 1443 (vs.nchr - vs.ncol) * CHR); 1444 #else 1445 memmove(Crtat, Crtat + vs.ncol, 1446 (vs.nchr - vs.ncol) * CHR); 1447 #endif 1448 fillw((vs.at << 8) | ' ', 1449 Crtat + vs.nchr - vs.ncol, 1450 vs.ncol); 1451 crtat -= vs.ncol; 1452 } 1453 } 1454 } 1455 async_update(); 1456 } 1457 1458 /* the unshifted code for KB_SHIFT keys is used by X to distinguish between 1459 left and right shift when reading the keyboard map */ 1460 static pccons_keymap_t scan_codes[KB_NUM_KEYS] = { 1461 /* type unshift shift control altgr shift_altgr scancode */ 1462 { KB_NONE, "", "", "", "", ""}, /* 0 unused */ 1463 { KB_ASCII, "\033", "\033", "\033", "", ""}, /* 1 ESCape */ 1464 { KB_ASCII, "1", "!", "!", "", ""}, /* 2 1 */ 1465 { KB_ASCII, "2", "@", "\000", "", ""}, /* 3 2 */ 1466 { KB_ASCII, "3", "#", "#", "", ""}, /* 4 3 */ 1467 { KB_ASCII, "4", "$", "$", "", ""}, /* 5 4 */ 1468 { KB_ASCII, "5", "%", "%", "", ""}, /* 6 5 */ 1469 { KB_ASCII, "6", "^", "\036", "", ""}, /* 7 6 */ 1470 { KB_ASCII, "7", "&", "&", "", ""}, /* 8 7 */ 1471 { KB_ASCII, "8", "*", "\010", "", ""}, /* 9 8 */ 1472 { KB_ASCII, "9", "(", "(", "", ""}, /* 10 9 */ 1473 { KB_ASCII, "0", ")", ")", "", ""}, /* 11 0 */ 1474 { KB_ASCII, "-", "_", "\037", "", ""}, /* 12 - */ 1475 { KB_ASCII, "=", "+", "+", "", ""}, /* 13 = */ 1476 { KB_ASCII, "\177", "\177", "\010", "", ""}, /* 14 backspace */ 1477 { KB_ASCII, "\t", "\t", "\t", "", ""}, /* 15 tab */ 1478 { KB_ASCII, "q", "Q", "\021", "", ""}, /* 16 q */ 1479 { KB_ASCII, "w", "W", "\027", "", ""}, /* 17 w */ 1480 { KB_ASCII, "e", "E", "\005", "", ""}, /* 18 e */ 1481 { KB_ASCII, "r", "R", "\022", "", ""}, /* 19 r */ 1482 { KB_ASCII, "t", "T", "\024", "", ""}, /* 20 t */ 1483 { KB_ASCII, "y", "Y", "\031", "", ""}, /* 21 y */ 1484 { KB_ASCII, "u", "U", "\025", "", ""}, /* 22 u */ 1485 { KB_ASCII, "i", "I", "\011", "", ""}, /* 23 i */ 1486 { KB_ASCII, "o", "O", "\017", "", ""}, /* 24 o */ 1487 { KB_ASCII, "p", "P", "\020", "", ""}, /* 25 p */ 1488 { KB_ASCII, "[", "{", "\033", "", ""}, /* 26 [ */ 1489 { KB_ASCII, "]", "}", "\035", "", ""}, /* 27 ] */ 1490 { KB_ASCII, "\r", "\r", "\n", "", ""}, /* 28 return */ 1491 { KB_CTL, "", "", "", "", ""}, /* 29 control */ 1492 { KB_ASCII, "a", "A", "\001", "", ""}, /* 30 a */ 1493 { KB_ASCII, "s", "S", "\023", "", ""}, /* 31 s */ 1494 { KB_ASCII, "d", "D", "\004", "", ""}, /* 32 d */ 1495 { KB_ASCII, "f", "F", "\006", "", ""}, /* 33 f */ 1496 { KB_ASCII, "g", "G", "\007", "", ""}, /* 34 g */ 1497 { KB_ASCII, "h", "H", "\010", "", ""}, /* 35 h */ 1498 { KB_ASCII, "j", "J", "\n", "", ""}, /* 36 j */ 1499 { KB_ASCII, "k", "K", "\013", "", ""}, /* 37 k */ 1500 { KB_ASCII, "l", "L", "\014", "", ""}, /* 38 l */ 1501 { KB_ASCII, ";", ":", ";", "", ""}, /* 39 ; */ 1502 { KB_ASCII, "'", "\"", "'", "", ""}, /* 40 ' */ 1503 { KB_ASCII, "`", "~", "`", "", ""}, /* 41 ` */ 1504 { KB_SHIFT, "\001", "", "", "", ""}, /* 42 shift */ 1505 { KB_ASCII, "\\", "|", "\034", "", ""}, /* 43 \ */ 1506 { KB_ASCII, "z", "Z", "\032", "", ""}, /* 44 z */ 1507 { KB_ASCII, "x", "X", "\030", "", ""}, /* 45 x */ 1508 { KB_ASCII, "c", "C", "\003", "", ""}, /* 46 c */ 1509 { KB_ASCII, "v", "V", "\026", "", ""}, /* 47 v */ 1510 { KB_ASCII, "b", "B", "\002", "", ""}, /* 48 b */ 1511 { KB_ASCII, "n", "N", "\016", "", ""}, /* 49 n */ 1512 { KB_ASCII, "m", "M", "\r", "", ""}, /* 50 m */ 1513 { KB_ASCII, ",", "<", "<", "", ""}, /* 51 , */ 1514 { KB_ASCII, ".", ">", ">", "", ""}, /* 52 . */ 1515 { KB_ASCII, "/", "?", "\037", "", ""}, /* 53 / */ 1516 { KB_SHIFT, "\002", "", "", "", ""}, /* 54 shift */ 1517 { KB_KP, "*", "*", "*", "", ""}, /* 55 kp * */ 1518 { KB_ALT, "", "", "", "", ""}, /* 56 alt */ 1519 { KB_ASCII, " ", " ", "\000", "", ""}, /* 57 space */ 1520 { KB_CAPS, "", "", "", "", ""}, /* 58 caps */ 1521 { KB_FUNC, "\033[M", "\033[Y", "\033[k", "", ""}, /* 59 f1 */ 1522 { KB_FUNC, "\033[N", "\033[Z", "\033[l", "", ""}, /* 60 f2 */ 1523 { KB_FUNC, "\033[O", "\033[a", "\033[m", "", ""}, /* 61 f3 */ 1524 { KB_FUNC, "\033[P", "\033[b", "\033[n", "", ""}, /* 62 f4 */ 1525 { KB_FUNC, "\033[Q", "\033[c", "\033[o", "", ""}, /* 63 f5 */ 1526 { KB_FUNC, "\033[R", "\033[d", "\033[p", "", ""}, /* 64 f6 */ 1527 { KB_FUNC, "\033[S", "\033[e", "\033[q", "", ""}, /* 65 f7 */ 1528 { KB_FUNC, "\033[T", "\033[f", "\033[r", "", ""}, /* 66 f8 */ 1529 { KB_FUNC, "\033[U", "\033[g", "\033[s", "", ""}, /* 67 f9 */ 1530 { KB_FUNC, "\033[V", "\033[h", "\033[t", "", ""}, /* 68 f10 */ 1531 { KB_NUM, "", "", "", "", ""}, /* 69 num lock */ 1532 { KB_SCROLL, "", "", "", "", ""}, /* 70 scroll lock */ 1533 { KB_KP, "7", "\033[H", "7", "", ""}, /* 71 kp 7 */ 1534 { KB_KP, "8", "\033[A", "8", "", ""}, /* 72 kp 8 */ 1535 { KB_KP, "9", "\033[I", "9", "", ""}, /* 73 kp 9 */ 1536 { KB_KP, "-", "-", "-", "", ""}, /* 74 kp - */ 1537 { KB_KP, "4", "\033[D", "4", "", ""}, /* 75 kp 4 */ 1538 { KB_KP, "5", "\033[E", "5", "", ""}, /* 76 kp 5 */ 1539 { KB_KP, "6", "\033[C", "6", "", ""}, /* 77 kp 6 */ 1540 { KB_KP, "+", "+", "+", "", ""}, /* 78 kp + */ 1541 { KB_KP, "1", "\033[F", "1", "", ""}, /* 79 kp 1 */ 1542 { KB_KP, "2", "\033[B", "2", "", ""}, /* 80 kp 2 */ 1543 { KB_KP, "3", "\033[G", "3", "", ""}, /* 81 kp 3 */ 1544 { KB_KP, "0", "\033[L", "0", "", ""}, /* 82 kp 0 */ 1545 { KB_KP, ",", "\177", ",", "", ""}, /* 83 kp , */ 1546 { KB_NONE, "", "", "", "", ""}, /* 84 0 */ 1547 { KB_NONE, "", "", "", "", ""}, /* 85 0 */ 1548 { KB_NONE, "", "", "", "", ""}, /* 86 0 */ 1549 { KB_FUNC, "\033[W", "\033[i", "\033[u", "", ""}, /* 87 f11 */ 1550 { KB_FUNC, "\033[X", "\033[j", "\033[v", "", ""}, /* 88 f12 */ 1551 { KB_NONE, "", "", "", "", ""}, /* 89 0 */ 1552 { KB_NONE, "", "", "", "", ""}, /* 90 0 */ 1553 { KB_NONE, "", "", "", "", ""}, /* 91 0 */ 1554 { KB_NONE, "", "", "", "", ""}, /* 92 0 */ 1555 { KB_NONE, "", "", "", "", ""}, /* 93 0 */ 1556 { KB_NONE, "", "", "", "", ""}, /* 94 0 */ 1557 { KB_NONE, "", "", "", "", ""}, /* 95 0 */ 1558 { KB_NONE, "", "", "", "", ""}, /* 96 0 */ 1559 { KB_NONE, "", "", "", "", ""}, /* 97 0 */ 1560 { KB_NONE, "", "", "", "", ""}, /* 98 0 */ 1561 { KB_NONE, "", "", "", "", ""}, /* 99 0 */ 1562 { KB_NONE, "", "", "", "", ""}, /* 100 */ 1563 { KB_NONE, "", "", "", "", ""}, /* 101 */ 1564 { KB_NONE, "", "", "", "", ""}, /* 102 */ 1565 { KB_NONE, "", "", "", "", ""}, /* 103 */ 1566 { KB_NONE, "", "", "", "", ""}, /* 104 */ 1567 { KB_NONE, "", "", "", "", ""}, /* 105 */ 1568 { KB_NONE, "", "", "", "", ""}, /* 106 */ 1569 { KB_NONE, "", "", "", "", ""}, /* 107 */ 1570 { KB_NONE, "", "", "", "", ""}, /* 108 */ 1571 { KB_NONE, "", "", "", "", ""}, /* 109 */ 1572 { KB_NONE, "", "", "", "", ""}, /* 110 */ 1573 { KB_NONE, "", "", "", "", ""}, /* 111 */ 1574 { KB_NONE, "", "", "", "", ""}, /* 112 */ 1575 { KB_NONE, "", "", "", "", ""}, /* 113 */ 1576 { KB_NONE, "", "", "", "", ""}, /* 114 */ 1577 { KB_NONE, "", "", "", "", ""}, /* 115 */ 1578 { KB_NONE, "", "", "", "", ""}, /* 116 */ 1579 { KB_NONE, "", "", "", "", ""}, /* 117 */ 1580 { KB_NONE, "", "", "", "", ""}, /* 118 */ 1581 { KB_NONE, "", "", "", "", ""}, /* 119 */ 1582 { KB_NONE, "", "", "", "", ""}, /* 120 */ 1583 { KB_NONE, "", "", "", "", ""}, /* 121 */ 1584 { KB_NONE, "", "", "", "", ""}, /* 122 */ 1585 { KB_NONE, "", "", "", "", ""}, /* 123 */ 1586 { KB_NONE, "", "", "", "", ""}, /* 124 */ 1587 { KB_NONE, "", "", "", "", ""}, /* 125 */ 1588 { KB_NONE, "", "", "", "", ""}, /* 126 */ 1589 { KB_NONE, "", "", "", "", ""} /* 127 */ 1590 }; 1591 1592 /* 1593 * Get characters from the keyboard. If none are present, return NULL. 1594 */ 1595 char * 1596 sget(void) 1597 { 1598 u_char dt; 1599 static u_char extended = 0, shift_state = 0; 1600 static u_char capchar[2]; 1601 1602 top: 1603 KBD_DELAY; 1604 dt = kbd_data_read_1(); 1605 1606 switch (dt) { 1607 case KBR_ACK: case KBR_ECHO: 1608 kb_oq_get = (kb_oq_get + 1) & 7; 1609 if(kb_oq_get != kb_oq_put) { 1610 kbd_data_write_1(kb_oq[kb_oq_get]); 1611 } 1612 goto loop; 1613 case KBR_RESEND: 1614 kbd_data_write_1(kb_oq[kb_oq_get]); 1615 goto loop; 1616 } 1617 1618 if (pc_xmode > 0) { 1619 #if defined(DDB) && defined(XSERVER_DDB) 1620 /* F12 enters the debugger while in X mode */ 1621 if (dt == 88) 1622 Debugger(); 1623 #endif 1624 capchar[0] = dt; 1625 capchar[1] = 0; 1626 /* 1627 * Check for locking keys. 1628 * 1629 * XXX Setting the LEDs this way is a bit bogus. What if the 1630 * keyboard has been remapped in X? 1631 */ 1632 switch (scan_codes[dt & 0x7f].type) { 1633 case KB_NUM: 1634 if (dt & 0x80) { 1635 shift_state &= ~KB_NUM; 1636 break; 1637 } 1638 if (shift_state & KB_NUM) 1639 break; 1640 shift_state |= KB_NUM; 1641 lock_state ^= KB_NUM; 1642 async_update(); 1643 break; 1644 case KB_CAPS: 1645 if (dt & 0x80) { 1646 shift_state &= ~KB_CAPS; 1647 break; 1648 } 1649 if (shift_state & KB_CAPS) 1650 break; 1651 shift_state |= KB_CAPS; 1652 lock_state ^= KB_CAPS; 1653 async_update(); 1654 break; 1655 case KB_SCROLL: 1656 if (dt & 0x80) { 1657 shift_state &= ~KB_SCROLL; 1658 break; 1659 } 1660 if (shift_state & KB_SCROLL) 1661 break; 1662 shift_state |= KB_SCROLL; 1663 lock_state ^= KB_SCROLL; 1664 if ((lock_state & KB_SCROLL) == 0) 1665 wakeup((void *)&lock_state); 1666 async_update(); 1667 break; 1668 } 1669 return capchar; 1670 } 1671 1672 switch (dt) { 1673 case KBR_EXTENDED: 1674 extended = 1; 1675 goto loop; 1676 } 1677 1678 #ifdef DDB 1679 /* 1680 * Check for cntl-alt-esc. 1681 */ 1682 if ((dt == 1) && (shift_state & (KB_CTL | KB_ALT)) == (KB_CTL | KB_ALT)) { 1683 /* XXX - check pccons_is_console */ 1684 Debugger(); 1685 dt |= 0x80; /* discard esc (ddb discarded ctl-alt) */ 1686 } 1687 #endif 1688 1689 /* 1690 * Check for make/break. 1691 */ 1692 if (dt & 0x80) { 1693 /* 1694 * break 1695 */ 1696 dt &= 0x7f; 1697 switch (scan_codes[dt].type) { 1698 case KB_NUM: 1699 shift_state &= ~KB_NUM; 1700 break; 1701 case KB_CAPS: 1702 shift_state &= ~KB_CAPS; 1703 break; 1704 case KB_SCROLL: 1705 shift_state &= ~KB_SCROLL; 1706 break; 1707 case KB_SHIFT: 1708 shift_state &= ~KB_SHIFT; 1709 break; 1710 case KB_ALT: 1711 if (extended) 1712 shift_state &= ~KB_ALTGR; 1713 else 1714 shift_state &= ~KB_ALT; 1715 break; 1716 case KB_CTL: 1717 shift_state &= ~KB_CTL; 1718 break; 1719 } 1720 } else { 1721 /* 1722 * make 1723 */ 1724 switch (scan_codes[dt].type) { 1725 /* 1726 * locking keys 1727 */ 1728 case KB_NUM: 1729 if (shift_state & KB_NUM) 1730 break; 1731 shift_state |= KB_NUM; 1732 lock_state ^= KB_NUM; 1733 async_update(); 1734 break; 1735 case KB_CAPS: 1736 if (shift_state & KB_CAPS) 1737 break; 1738 shift_state |= KB_CAPS; 1739 lock_state ^= KB_CAPS; 1740 async_update(); 1741 break; 1742 case KB_SCROLL: 1743 if (shift_state & KB_SCROLL) 1744 break; 1745 shift_state |= KB_SCROLL; 1746 lock_state ^= KB_SCROLL; 1747 if ((lock_state & KB_SCROLL) == 0) 1748 wakeup((void *)&lock_state); 1749 async_update(); 1750 break; 1751 /* 1752 * non-locking keys 1753 */ 1754 case KB_SHIFT: 1755 shift_state |= KB_SHIFT; 1756 break; 1757 case KB_ALT: 1758 if (extended) 1759 shift_state |= KB_ALTGR; 1760 else 1761 shift_state |= KB_ALT; 1762 break; 1763 case KB_CTL: 1764 shift_state |= KB_CTL; 1765 break; 1766 case KB_ASCII: 1767 /* control has highest priority */ 1768 if (shift_state & KB_CTL) 1769 capchar[0] = scan_codes[dt].ctl[0]; 1770 else if (shift_state & KB_ALTGR) { 1771 if (shift_state & KB_SHIFT) 1772 capchar[0] = scan_codes[dt].shift_altgr[0]; 1773 else 1774 capchar[0] = scan_codes[dt].altgr[0]; 1775 } 1776 else { 1777 if (shift_state & KB_SHIFT) 1778 capchar[0] = scan_codes[dt].shift[0]; 1779 else 1780 capchar[0] = scan_codes[dt].unshift[0]; 1781 } 1782 if ((lock_state & KB_CAPS) && capchar[0] >= 'a' && 1783 capchar[0] <= 'z') { 1784 capchar[0] -= ('a' - 'A'); 1785 } 1786 capchar[0] |= (shift_state & KB_ALT); 1787 extended = 0; 1788 return capchar; 1789 case KB_NONE: 1790 printf("keycode %d\n",dt); 1791 break; 1792 case KB_FUNC: { 1793 char *more_chars; 1794 if (shift_state & KB_SHIFT) 1795 more_chars = scan_codes[dt].shift; 1796 else if (shift_state & KB_CTL) 1797 more_chars = scan_codes[dt].ctl; 1798 else 1799 more_chars = scan_codes[dt].unshift; 1800 extended = 0; 1801 return more_chars; 1802 } 1803 case KB_KP: { 1804 char *more_chars; 1805 if (shift_state & (KB_SHIFT | KB_CTL) || 1806 (lock_state & KB_NUM) == 0 || extended) 1807 more_chars = scan_codes[dt].shift; 1808 else 1809 more_chars = scan_codes[dt].unshift; 1810 extended = 0; 1811 return more_chars; 1812 } 1813 } 1814 } 1815 1816 extended = 0; 1817 loop: 1818 if ((kbd_cmd_read_1() & KBS_DIB) == 0) 1819 return 0; 1820 goto top; 1821 } 1822 1823 paddr_t 1824 pcmmap(dev_t dev, off_t offset, int nprot) 1825 { 1826 struct pccons_context *pc = &pccons_console_context; 1827 paddr_t pa; 1828 1829 if (offset >= 0xa0000 && offset < 0xc0000) { 1830 if (bus_space_paddr(pc->pc_crt_memt, pc->pc_mono_memh, &pa)) 1831 return -1; 1832 pa += offset - pc->pc_config->pc_mono_memaddr; 1833 return mips_btop(pa); 1834 } 1835 if (offset >= 0x0000 && offset < 0x10000) { 1836 if (bus_space_paddr(pc->pc_crt_iot, pc->pc_mono_ioh, &pa)) 1837 return -1; 1838 pa += offset - pc->pc_config->pc_mono_iobase; 1839 return mips_btop(pa); 1840 } 1841 if (offset >= 0x40000000 && offset < 0x40800000) { 1842 if (bus_space_paddr(pc->pc_crt_memt, pc->pc_mono_memh, &pa)) 1843 return (-1); 1844 pa += offset - 0x40000000 - pc->pc_config->pc_mono_memaddr; 1845 return mips_btop(pa); 1846 } 1847 return -1; 1848 } 1849 1850 void 1851 pc_xmode_on(void) 1852 { 1853 if (pc_xmode) 1854 return; 1855 pc_xmode = 1; 1856 1857 #ifdef XFREE86_BUG_COMPAT 1858 /* If still unchanged, get current shape. */ 1859 if (cursor_shape == 0xffff) 1860 get_cursor_shape(); 1861 #endif 1862 } 1863 1864 void 1865 pc_xmode_off(void) 1866 { 1867 if (pc_xmode == 0) 1868 return; 1869 pc_xmode = 0; 1870 1871 #ifdef XFREE86_BUG_COMPAT 1872 /* XXX It would be hard to justify why the X server doesn't do this. */ 1873 set_cursor_shape(); 1874 #endif 1875 async_update(); 1876 } 1877