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