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