1 /* $NetBSD: pccons.c,v 1.53 2007/11/19 18:51:37 ad 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.53 2007/11/19 18:51:37 ad 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 vale. 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 int unit = PCUNIT(dev); 598 struct tty *tp; 599 600 if (unit >= pc_cd.cd_ndevs) 601 return ENXIO; 602 sc = pc_cd.cd_devs[unit]; 603 if (sc == 0) 604 return ENXIO; 605 606 if (!sc->sc_tty) { 607 tp = sc->sc_tty = ttymalloc(); 608 } 609 else { 610 tp = sc->sc_tty; 611 } 612 613 tp->t_oproc = pcstart; 614 tp->t_param = pcparam; 615 tp->t_dev = dev; 616 617 if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp)) 618 return (EBUSY); 619 620 if ((tp->t_state & TS_ISOPEN) == 0) { 621 ttychars(tp); 622 tp->t_iflag = TTYDEF_IFLAG; 623 tp->t_oflag = TTYDEF_OFLAG; 624 tp->t_cflag = TTYDEF_CFLAG; 625 tp->t_lflag = TTYDEF_LFLAG; 626 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 627 pcparam(tp, &tp->t_termios); 628 ttsetwater(tp); 629 } 630 631 tp->t_state |= TS_CARR_ON; 632 633 return (*tp->t_linesw->l_open)(dev, tp); 634 } 635 636 int 637 pcclose(dev_t dev, int flag, int mode, struct lwp *l) 638 { 639 struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)]; 640 struct tty *tp = sc->sc_tty; 641 642 (*tp->t_linesw->l_close)(tp, flag); 643 ttyclose(tp); 644 #ifdef notyet /* XXX */ 645 ttyfree(tp); 646 #endif 647 return 0; 648 } 649 650 int 651 pcread(dev_t dev, struct uio *uio, int flag) 652 { 653 struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)]; 654 struct tty *tp = sc->sc_tty; 655 656 return (*tp->t_linesw->l_read)(tp, uio, flag); 657 } 658 659 int 660 pcwrite(dev_t dev, struct uio *uio, int flag) 661 { 662 struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)]; 663 struct tty *tp = sc->sc_tty; 664 665 return (*tp->t_linesw->l_write)(tp, uio, flag); 666 } 667 668 int 669 pcpoll(dev_t dev, int events, struct lwp *l) 670 { 671 struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)]; 672 struct tty *tp = sc->sc_tty; 673 674 return (*tp->t_linesw->l_poll)(tp, events, l); 675 } 676 677 struct tty * 678 pctty(dev_t dev) 679 { 680 struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)]; 681 struct tty *tp = sc->sc_tty; 682 683 return tp; 684 } 685 686 /* 687 * Got a console receive interrupt - 688 * the console processor wants to give us a character. 689 * Catch the character, and see who it goes to. 690 */ 691 int 692 pcintr(void *arg) 693 { 694 struct pc_softc *sc = arg; 695 struct tty *tp = sc->sc_tty; 696 uint8_t *cp; 697 698 if ((kbd_cmd_read_1() & KBS_DIB) == 0) 699 return 0; 700 if (polling) 701 return 1; 702 do { 703 cp = sget(); 704 if (!tp || (tp->t_state & TS_ISOPEN) == 0) 705 return 1; 706 if (cp) 707 do 708 (*tp->t_linesw->l_rint)(*cp++, tp); 709 while (*cp); 710 } while (kbd_cmd_read_1() & KBS_DIB); 711 return 1; 712 } 713 714 int 715 pcioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 716 { 717 struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)]; 718 struct tty *tp = sc->sc_tty; 719 int error; 720 721 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l); 722 if (error != EPASSTHROUGH) 723 return error; 724 error = ttioctl(tp, cmd, data, flag, l); 725 if (error != EPASSTHROUGH) 726 return error; 727 728 switch (cmd) { 729 case CONSOLE_X_MODE_ON: 730 pc_xmode_on(); 731 return 0; 732 case CONSOLE_X_MODE_OFF: 733 pc_xmode_off(); 734 return 0; 735 case CONSOLE_X_BELL: 736 /* 737 * If set, data is a pointer to a length 2 array of 738 * integers. data[0] is the pitch in Hz and data[1] 739 * is the duration in msec. 740 */ 741 if (data) 742 sysbeep(((int*)data)[0], 743 (((int*)data)[1] * hz) / 1000); 744 else 745 sysbeep(BEEP_FREQ, BEEP_TIME); 746 return 0; 747 case CONSOLE_SET_TYPEMATIC_RATE: { 748 u_char rate; 749 750 if (!data) 751 return EINVAL; 752 rate = *((u_char *)data); 753 /* 754 * Check that it isn't too big (which would cause it to be 755 * confused with a command). 756 */ 757 if (rate & 0x80) 758 return EINVAL; 759 typematic_rate = rate; 760 async_update(); 761 return 0; 762 } 763 case CONSOLE_SET_KEYMAP: { 764 pccons_keymap_t *map = (pccons_keymap_t *) data; 765 int i; 766 767 if (!data) 768 return EINVAL; 769 for (i = 0; i < KB_NUM_KEYS; i++) 770 if (map[i].unshift[KB_CODE_SIZE-1] || 771 map[i].shift[KB_CODE_SIZE-1] || 772 map[i].ctl[KB_CODE_SIZE-1] || 773 map[i].altgr[KB_CODE_SIZE-1] || 774 map[i].shift_altgr[KB_CODE_SIZE-1]) 775 return EINVAL; 776 777 bcopy(data, scan_codes, sizeof(pccons_keymap_t[KB_NUM_KEYS])); 778 return 0; 779 } 780 case CONSOLE_GET_KEYMAP: 781 if (!data) 782 return EINVAL; 783 bcopy(scan_codes, data, sizeof(pccons_keymap_t[KB_NUM_KEYS])); 784 return 0; 785 786 default: 787 return EPASSTHROUGH; 788 } 789 790 #ifdef DIAGNOSTIC 791 panic("pcioctl: impossible"); 792 #endif 793 } 794 795 void 796 pcstart(struct tty *tp) 797 { 798 int s, len; 799 u_char buf[PCBURST]; 800 801 s = spltty(); 802 if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) 803 goto out; 804 tp->t_state |= TS_BUSY; 805 splx(s); 806 /* 807 * We need to do this outside spl since it could be fairly 808 * expensive and we don't want our serial ports to overflow. 809 */ 810 len = q_to_b(cl, buf, PCBURST); 811 sput(buf, len); 812 s = spltty(); 813 tp->t_state &= ~TS_BUSY; 814 if (ttypull(tp)) { 815 tp->t_state |= TS_TIMEOUT; 816 callout_schedule(&tp->t_rstrt_ch, 1); 817 } 818 out: 819 splx(s); 820 } 821 822 /* ARGSUSED */ 823 void pccons_common_cnattach(bus_space_tag_t crt_iot, bus_space_tag_t crt_memt, 824 bus_space_tag_t kbd_iot, struct pccons_config *config) 825 { 826 int maj; 827 static struct consdev pccons = { 828 NULL, NULL, pccngetc, pccnputc, pccnpollc, NULL, NULL, 829 NULL, NODEV, CN_NORMAL 830 }; 831 832 /* 833 * For now, don't screw with it. 834 */ 835 /* crtat = 0; */ 836 837 pc_context_init(crt_iot, crt_memt, kbd_iot, config); 838 839 /* locate the major number */ 840 maj = cdevsw_lookup_major(&pc_cdevsw); 841 pccons.cn_dev = makedev(maj, 0); 842 843 cn_tab = &pccons; 844 } 845 846 /* ARGSUSED */ 847 void 848 pccnputc(dev_t dev, int c) 849 { 850 u_char cc, oldkernel = kernel; 851 852 kernel = 1; 853 if (c == '\n') { 854 sput("\r\n", 2); 855 } else { 856 cc = c; 857 sput(&cc, 1); 858 } 859 kernel = oldkernel; 860 } 861 862 /* ARGSUSED */ 863 int 864 pccngetc(dev_t dev) 865 { 866 char *cp; 867 868 if (pc_xmode > 0) 869 return 0; 870 871 do { 872 /* wait for byte */ 873 while ((kbd_cmd_read_1() & KBS_DIB) == 0); 874 /* see if it's worthwhile */ 875 cp = sget(); 876 } while (!cp); 877 if (*cp == '\r') 878 return '\n'; 879 return *cp; 880 } 881 882 void 883 pccnpollc(dev_t dev, int on) 884 { 885 886 polling = on; 887 if (!on) { 888 int unit; 889 struct pc_softc *sc; 890 int s; 891 892 /* 893 * If disabling polling on a device that's been configured, 894 * make sure there are no bytes left in the FIFO, holding up 895 * the interrupt line. Otherwise we won't get any further 896 * interrupts. 897 */ 898 unit = PCUNIT(dev); 899 if (pc_cd.cd_ndevs > unit) { 900 sc = pc_cd.cd_devs[unit]; 901 if (sc != 0) { 902 s = spltty(); 903 pcintr(sc); 904 splx(s); 905 } 906 } 907 } 908 } 909 910 /* 911 * Set line parameters. 912 */ 913 int 914 pcparam(struct tty *tp, struct termios *t) 915 { 916 917 tp->t_ispeed = t->c_ispeed; 918 tp->t_ospeed = t->c_ospeed; 919 tp->t_cflag = t->c_cflag; 920 return 0; 921 } 922 923 #define wrtchar(c, at) do {\ 924 char *cp0 = (char *)crtat; *cp0++ = (c); *cp0 = (at); crtat++; vs.col++; \ 925 } while (0) 926 927 /* translate ANSI color codes to standard pc ones */ 928 static char fgansitopc[] = { 929 FG_BLACK, FG_RED, FG_GREEN, FG_BROWN, FG_BLUE, 930 FG_MAGENTA, FG_CYAN, FG_LIGHTGREY 931 }; 932 933 static char bgansitopc[] = { 934 BG_BLACK, BG_RED, BG_GREEN, BG_BROWN, BG_BLUE, 935 BG_MAGENTA, BG_CYAN, BG_LIGHTGREY 936 }; 937 938 static u_char iso2ibm437[] = 939 { 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 0, 0, 0, 0, 0, 0, 0, 0, 944 0xff, 0xad, 0x9b, 0x9c, 0, 0x9d, 0, 0x40, 945 0x6f, 0x63, 0x61, 0xae, 0, 0, 0, 0, 946 0xf8, 0xf1, 0xfd, 0x33, 0, 0xe6, 0, 0xfa, 947 0, 0x31, 0x6f, 0xaf, 0xac, 0xab, 0, 0xa8, 948 0x41, 0x41, 0x41, 0x41, 0x8e, 0x8f, 0x92, 0x80, 949 0x45, 0x90, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49, 950 0x81, 0xa5, 0x4f, 0x4f, 0x4f, 0x4f, 0x99, 0x4f, 951 0x4f, 0x55, 0x55, 0x55, 0x9a, 0x59, 0, 0xe1, 952 0x85, 0xa0, 0x83, 0x61, 0x84, 0x86, 0x91, 0x87, 953 0x8a, 0x82, 0x88, 0x89, 0x8d, 0xa1, 0x8c, 0x8b, 954 0, 0xa4, 0x95, 0xa2, 0x93, 0x6f, 0x94, 0x6f, 955 0x6f, 0x97, 0xa3, 0x96, 0x81, 0x98, 0, 0 956 }; 957 958 /* 959 * `pc3' termcap emulation. 960 */ 961 void 962 sput(const u_char *cp, int n) 963 { 964 struct pccons_context *pc = &pccons_console_context; 965 u_char c, scroll = 0; 966 967 if (pc_xmode > 0) 968 return; 969 970 if (crtat == 0) { 971 volatile u_short *dp; 972 u_short was; 973 unsigned cursorat; 974 975 dp = bus_space_vaddr(pc->pc_crt_memt, pc->pc_cga_memh); 976 was = *dp; 977 *dp = 0xA55A; 978 if (*dp != 0xA55A) { 979 dp = bus_space_vaddr(pc->pc_crt_memt, 980 pc->pc_mono_memh); 981 pc->pc_6845_ioh = pc->pc_mono_ioh; 982 pc->pc_crt_memh = pc->pc_mono_memh; 983 vs.color = 0; 984 } else { 985 *dp = was; 986 pc->pc_6845_ioh = pc->pc_cga_ioh; 987 pc->pc_crt_memh = pc->pc_cga_memh; 988 vs.color = 1; 989 } 990 991 #ifdef FAT_CURSOR 992 cursor_shape = 0x0012; 993 #else 994 get_cursor_shape(); 995 #endif 996 997 bios_display_info(&vs.col, &vs.row, &vs.ncol, &vs.nrow); 998 vs.nchr = vs.ncol * vs.nrow; 999 vs.col--; 1000 vs.row--; 1001 cursorat = vs.ncol * vs.row + vs.col; 1002 vs.at = FG_LIGHTGREY | BG_BLACK; 1003 1004 Crtat = (u_short *)__UNVOLATILE(dp); 1005 crtat = Crtat + cursorat; 1006 1007 if (vs.color == 0) 1008 vs.so_at = FG_BLACK | BG_LIGHTGREY; 1009 else 1010 vs.so_at = FG_YELLOW | BG_BLACK; 1011 1012 fillw((vs.at << 8) | ' ', crtat, vs.nchr - cursorat); 1013 } 1014 1015 while (n--) { 1016 if (!(c = *cp++)) 1017 continue; 1018 1019 switch (c) { 1020 case 0x1B: 1021 if (vs.state >= VSS_ESCAPE) { 1022 wrtchar(c, vs.so_at); 1023 vs.state = 0; 1024 goto maybe_scroll; 1025 } else 1026 vs.state = VSS_ESCAPE; 1027 break; 1028 1029 case 0x9B: /* CSI */ 1030 vs.cx = vs.cy = 0; 1031 vs.state = VSS_EBRACE; 1032 break; 1033 1034 case '\t': { 1035 int inccol = 8 - (vs.col & 7); 1036 crtat += inccol; 1037 vs.col += inccol; 1038 } 1039 maybe_scroll: 1040 if (vs.col >= vs.ncol) { 1041 vs.col -= vs.ncol; 1042 scroll = 1; 1043 } 1044 break; 1045 1046 case '\b': 1047 if (crtat <= Crtat) 1048 break; 1049 --crtat; 1050 if (--vs.col < 0) 1051 vs.col += vs.ncol; /* non-destructive backspace */ 1052 break; 1053 1054 case '\r': 1055 crtat -= vs.col; 1056 vs.col = 0; 1057 break; 1058 1059 case '\n': 1060 crtat += vs.ncol; 1061 scroll = 1; 1062 break; 1063 1064 default: 1065 switch (vs.state) { 1066 case 0: 1067 if (c == '\a') 1068 sysbeep(BEEP_FREQ, BEEP_TIME); 1069 else { 1070 /* 1071 * If we're outputting multiple printed 1072 * characters, just blast them to the 1073 * screen until we reach the end of the 1074 * buffer or a control character. This 1075 * saves time by short-circuiting the 1076 * switch. 1077 * If we reach the end of the line, we 1078 * break to do a scroll check. 1079 */ 1080 for (;;) { 1081 if (c & 0x80) 1082 c = iso2ibm437[c&0x7f]; 1083 1084 if (vs.so) 1085 wrtchar(c, vs.so_at); 1086 else 1087 wrtchar(c, vs.at); 1088 if (vs.col >= vs.ncol) { 1089 vs.col = 0; 1090 scroll = 1; 1091 break; 1092 } 1093 if (!n || (c = *cp) < ' ') 1094 break; 1095 n--, cp++; 1096 } 1097 } 1098 break; 1099 case VSS_ESCAPE: 1100 switch (c) { 1101 case '[': /* Start ESC [ sequence */ 1102 vs.cx = vs.cy = 0; 1103 vs.state = VSS_EBRACE; 1104 break; 1105 case 'c': /* Create screen & home */ 1106 fillw((vs.at << 8) | ' ', 1107 Crtat, vs.nchr); 1108 crtat = Crtat; 1109 vs.col = 0; 1110 vs.state = 0; 1111 break; 1112 case '7': /* save cursor pos */ 1113 vs.offset = crtat - Crtat; 1114 vs.state = 0; 1115 break; 1116 case '8': /* restore cursor pos */ 1117 crtat = Crtat + vs.offset; 1118 vs.row = vs.offset / vs.ncol; 1119 vs.col = vs.offset % vs.ncol; 1120 vs.state = 0; 1121 break; 1122 default: /* Invalid, clear state */ 1123 wrtchar(c, vs.so_at); 1124 vs.state = 0; 1125 goto maybe_scroll; 1126 } 1127 break; 1128 1129 default: /* VSS_EBRACE or VSS_EPARAM */ 1130 switch (c) { 1131 int pos; 1132 case 'm': 1133 if (!vs.cx) 1134 vs.so = 0; 1135 else 1136 vs.so = 1; 1137 vs.state = 0; 1138 break; 1139 case 'A': { /* back cx rows */ 1140 int cx = vs.cx; 1141 if (cx <= 0) 1142 cx = 1; 1143 else 1144 cx %= vs.nrow; 1145 pos = crtat - Crtat; 1146 pos -= vs.ncol * cx; 1147 if (pos < 0) 1148 pos += vs.nchr; 1149 crtat = Crtat + pos; 1150 vs.state = 0; 1151 break; 1152 } 1153 case 'B': { /* down cx rows */ 1154 int cx = vs.cx; 1155 if (cx <= 0) 1156 cx = 1; 1157 else 1158 cx %= vs.nrow; 1159 pos = crtat - Crtat; 1160 pos += vs.ncol * cx; 1161 if (pos >= vs.nchr) 1162 pos -= vs.nchr; 1163 crtat = Crtat + pos; 1164 vs.state = 0; 1165 break; 1166 } 1167 case 'C': { /* right cursor */ 1168 int cx = vs.cx, 1169 col = vs.col; 1170 if (cx <= 0) 1171 cx = 1; 1172 else 1173 cx %= vs.ncol; 1174 pos = crtat - Crtat; 1175 pos += cx; 1176 col += cx; 1177 if (col >= vs.ncol) { 1178 pos -= vs.ncol; 1179 col -= vs.ncol; 1180 } 1181 vs.col = col; 1182 crtat = Crtat + pos; 1183 vs.state = 0; 1184 break; 1185 } 1186 case 'D': { /* left cursor */ 1187 int cx = vs.cx, 1188 col = vs.col; 1189 if (cx <= 0) 1190 cx = 1; 1191 else 1192 cx %= vs.ncol; 1193 pos = crtat - Crtat; 1194 pos -= cx; 1195 col -= cx; 1196 if (col < 0) { 1197 pos += vs.ncol; 1198 col += vs.ncol; 1199 } 1200 vs.col = col; 1201 crtat = Crtat + pos; 1202 vs.state = 0; 1203 break; 1204 } 1205 case 'J': /* Clear ... */ 1206 switch (vs.cx) { 1207 case 0: 1208 /* ... to end of display */ 1209 fillw((vs.at << 8) | ' ', 1210 crtat, 1211 Crtat + vs.nchr - crtat); 1212 break; 1213 case 1: 1214 /* ... to next location */ 1215 fillw((vs.at << 8) | ' ', 1216 Crtat, 1217 crtat - Crtat + 1); 1218 break; 1219 case 2: 1220 /* ... whole display */ 1221 fillw((vs.at << 8) | ' ', 1222 Crtat, 1223 vs.nchr); 1224 break; 1225 } 1226 vs.state = 0; 1227 break; 1228 case 'K': /* Clear line ... */ 1229 switch (vs.cx) { 1230 case 0: 1231 /* ... current to EOL */ 1232 fillw((vs.at << 8) | ' ', 1233 crtat, 1234 vs.ncol - vs.col); 1235 break; 1236 case 1: 1237 /* ... beginning to next */ 1238 fillw((vs.at << 8) | ' ', 1239 crtat - vs.col, 1240 vs.col + 1); 1241 break; 1242 case 2: 1243 /* ... entire line */ 1244 fillw((vs.at << 8) | ' ', 1245 crtat - vs.col, vs.ncol); 1246 break; 1247 } 1248 vs.state = 0; 1249 break; 1250 case 'f': /* in system V consoles */ 1251 case 'H': { /* Cursor move */ 1252 int cx = vs.cx, 1253 cy = vs.cy; 1254 if (!cx || !cy) { 1255 crtat = Crtat; 1256 vs.col = 0; 1257 } else { 1258 if (cx > vs.nrow) 1259 cx = vs.nrow; 1260 if (cy > vs.ncol) 1261 cy = vs.ncol; 1262 crtat = Crtat + 1263 (cx - 1) * vs.ncol + cy - 1; 1264 vs.col = cy - 1; 1265 } 1266 vs.state = 0; 1267 break; 1268 } 1269 case 'M': { /* delete cx rows */ 1270 u_short *crtAt = crtat - vs.col; 1271 int cx = vs.cx, 1272 row = (crtAt - Crtat) / vs.ncol, 1273 nrow = vs.nrow - row; 1274 if (cx <= 0) 1275 cx = 1; 1276 else if (cx > nrow) 1277 cx = nrow; 1278 if (cx < nrow) 1279 #ifdef PCCONS_FORCE_WORD 1280 wcopy(crtAt + vs.ncol * cx, 1281 crtAt, vs.ncol * (nrow - 1282 cx) * CHR); 1283 #else 1284 bcopy(crtAt + vs.ncol * cx, 1285 crtAt, vs.ncol * (nrow - 1286 cx) * 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 bcopy(Crtat + vs.ncol * cx, 1307 Crtat, vs.ncol * (vs.nrow - 1308 cx) * 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 bcopy(crtAt, 1334 crtAt + vs.ncol * cx, 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 bcopy(Crtat, 1357 Crtat + vs.ncol * cx, 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 bcopy(Crtat + vs.ncol, Crtat, 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