1 /* $NetBSD: pccons.c,v 1.39 2005/01/22 07:35:34 tsutsui Exp $ */ 2 /* $OpenBSD: pccons.c,v 1.22 1999/01/30 22:39:37 imp Exp $ */ 3 /* NetBSD: pccons.c,v 1.89 1995/05/04 19:35:20 cgd Exp */ 4 5 /*- 6 * Copyright (c) 1990 The Regents of the University of California. 7 * All rights reserved. 8 * 9 * This code is derived from software contributed to Berkeley by 10 * William Jolitz and Don Ahn. 11 * 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * @(#)pccons.c 5.11 (Berkeley) 5/21/91 36 */ 37 38 /*- 39 * Copyright (c) 1993, 1994, 1995 Charles M. Hannum. All rights reserved. 40 * 41 * This code is derived from software contributed to Berkeley by 42 * William Jolitz and Don Ahn. 43 * 44 * Copyright (c) 1994 Charles M. Hannum. 45 * Copyright (c) 1992, 1993 Erik Forsberg. 46 * 47 * Redistribution and use in source and binary forms, with or without 48 * modification, are permitted provided that the following conditions 49 * are met: 50 * 1. Redistributions of source code must retain the above copyright 51 * notice, this list of conditions and the following disclaimer. 52 * 2. Redistributions in binary form must reproduce the above copyright 53 * notice, this list of conditions and the following disclaimer in the 54 * documentation and/or other materials provided with the distribution. 55 * 3. All advertising materials mentioning features or use of this software 56 * must display the following acknowledgement: 57 * This product includes software developed by the University of 58 * California, Berkeley and its contributors. 59 * 4. Neither the name of the University nor the names of its contributors 60 * may be used to endorse or promote products derived from this software 61 * without specific prior written permission. 62 * 63 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 64 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 65 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 66 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 67 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 68 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 69 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 70 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 71 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 72 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 73 * SUCH DAMAGE. 74 * 75 * @(#)pccons.c 5.11 (Berkeley) 5/21/91 76 */ 77 78 /* 79 * code to work keyboard & display for PC-style console 80 */ 81 82 #include <sys/cdefs.h> 83 __KERNEL_RCSID(0, "$NetBSD: pccons.c,v 1.39 2005/01/22 07:35:34 tsutsui Exp $"); 84 85 #include "opt_ddb.h" 86 87 #include <sys/param.h> 88 #include <sys/systm.h> 89 #include <sys/tty.h> 90 #include <sys/callout.h> 91 #include <sys/poll.h> 92 #include <sys/conf.h> 93 #include <sys/vnode.h> 94 #include <sys/kernel.h> 95 #include <sys/kcore.h> 96 #include <sys/device.h> 97 #include <sys/proc.h> 98 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 proc *p) 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 && p->p_ucred->cr_uid != 0) 623 return EBUSY; 624 tp->t_state |= TS_CARR_ON; 625 626 return (*tp->t_linesw->l_open)(dev, tp); 627 } 628 629 int 630 pcclose(dev_t dev, int flag, int mode, struct proc *p) 631 { 632 struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)]; 633 struct tty *tp = sc->sc_tty; 634 635 (*tp->t_linesw->l_close)(tp, flag); 636 ttyclose(tp); 637 #ifdef notyet /* XXX */ 638 ttyfree(tp); 639 #endif 640 return 0; 641 } 642 643 int 644 pcread(dev_t dev, struct uio *uio, int flag) 645 { 646 struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)]; 647 struct tty *tp = sc->sc_tty; 648 649 return (*tp->t_linesw->l_read)(tp, uio, flag); 650 } 651 652 int 653 pcwrite(dev_t dev, struct uio *uio, int flag) 654 { 655 struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)]; 656 struct tty *tp = sc->sc_tty; 657 658 return (*tp->t_linesw->l_write)(tp, uio, flag); 659 } 660 661 int 662 pcpoll(dev_t dev, int events, struct proc *p) 663 { 664 struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)]; 665 struct tty *tp = sc->sc_tty; 666 667 return (*tp->t_linesw->l_poll)(tp, events, p); 668 } 669 670 struct tty * 671 pctty(dev_t dev) 672 { 673 struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)]; 674 struct tty *tp = sc->sc_tty; 675 676 return tp; 677 } 678 679 /* 680 * Got a console receive interrupt - 681 * the console processor wants to give us a character. 682 * Catch the character, and see who it goes to. 683 */ 684 int 685 pcintr(void *arg) 686 { 687 struct pc_softc *sc = arg; 688 struct tty *tp = sc->sc_tty; 689 uint8_t *cp; 690 691 if ((kbd_cmd_read_1() & KBS_DIB) == 0) 692 return 0; 693 if (polling) 694 return 1; 695 do { 696 cp = sget(); 697 if (!tp || (tp->t_state & TS_ISOPEN) == 0) 698 return 1; 699 if (cp) 700 do 701 (*tp->t_linesw->l_rint)(*cp++, tp); 702 while (*cp); 703 } while (kbd_cmd_read_1() & KBS_DIB); 704 return 1; 705 } 706 707 int 708 pcioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 709 { 710 struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)]; 711 struct tty *tp = sc->sc_tty; 712 int error; 713 714 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, p); 715 if (error != EPASSTHROUGH) 716 return error; 717 error = ttioctl(tp, cmd, data, flag, p); 718 if (error != EPASSTHROUGH) 719 return error; 720 721 switch (cmd) { 722 case CONSOLE_X_MODE_ON: 723 pc_xmode_on(); 724 return 0; 725 case CONSOLE_X_MODE_OFF: 726 pc_xmode_off(); 727 return 0; 728 case CONSOLE_X_BELL: 729 /* 730 * If set, data is a pointer to a length 2 array of 731 * integers. data[0] is the pitch in Hz and data[1] 732 * is the duration in msec. 733 */ 734 if (data) 735 sysbeep(((int*)data)[0], 736 (((int*)data)[1] * hz) / 1000); 737 else 738 sysbeep(BEEP_FREQ, BEEP_TIME); 739 return 0; 740 case CONSOLE_SET_TYPEMATIC_RATE: { 741 u_char rate; 742 743 if (!data) 744 return EINVAL; 745 rate = *((u_char *)data); 746 /* 747 * Check that it isn't too big (which would cause it to be 748 * confused with a command). 749 */ 750 if (rate & 0x80) 751 return EINVAL; 752 typematic_rate = rate; 753 async_update(); 754 return 0; 755 } 756 case CONSOLE_SET_KEYMAP: { 757 pccons_keymap_t *map = (pccons_keymap_t *) data; 758 int i; 759 760 if (!data) 761 return EINVAL; 762 for (i = 0; i < KB_NUM_KEYS; i++) 763 if (map[i].unshift[KB_CODE_SIZE-1] || 764 map[i].shift[KB_CODE_SIZE-1] || 765 map[i].ctl[KB_CODE_SIZE-1] || 766 map[i].altgr[KB_CODE_SIZE-1] || 767 map[i].shift_altgr[KB_CODE_SIZE-1]) 768 return EINVAL; 769 770 bcopy(data, scan_codes, sizeof(pccons_keymap_t[KB_NUM_KEYS])); 771 return 0; 772 } 773 case CONSOLE_GET_KEYMAP: 774 if (!data) 775 return EINVAL; 776 bcopy(scan_codes, data, sizeof(pccons_keymap_t[KB_NUM_KEYS])); 777 return 0; 778 779 default: 780 return EPASSTHROUGH; 781 } 782 783 #ifdef DIAGNOSTIC 784 panic("pcioctl: impossible"); 785 #endif 786 } 787 788 void 789 pcstart(struct tty *tp) 790 { 791 struct clist *cl; 792 int s, len; 793 u_char buf[PCBURST]; 794 795 s = spltty(); 796 if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) 797 goto out; 798 tp->t_state |= TS_BUSY; 799 splx(s); 800 /* 801 * We need to do this outside spl since it could be fairly 802 * expensive and we don't want our serial ports to overflow. 803 */ 804 cl = &tp->t_outq; 805 len = q_to_b(cl, buf, PCBURST); 806 sput(buf, len); 807 s = spltty(); 808 tp->t_state &= ~TS_BUSY; 809 if (cl->c_cc) { 810 tp->t_state |= TS_TIMEOUT; 811 callout_reset(&tp->t_rstrt_ch, 1, ttrstrt, tp); 812 } 813 if (cl->c_cc <= tp->t_lowat) { 814 if (tp->t_state & TS_ASLEEP) { 815 tp->t_state &= ~TS_ASLEEP; 816 wakeup(cl); 817 } 818 selwakeup(&tp->t_wsel); 819 } 820 out: 821 splx(s); 822 } 823 824 /* ARGSUSED */ 825 void pccons_common_cnattach(bus_space_tag_t crt_iot, bus_space_tag_t crt_memt, 826 bus_space_tag_t kbd_iot, struct pccons_config *config) 827 { 828 int maj; 829 static struct consdev pccons = { 830 NULL, NULL, pccngetc, pccnputc, pccnpollc, NULL, NULL, 831 NULL, NODEV, CN_NORMAL 832 }; 833 834 /* 835 * For now, don't screw with it. 836 */ 837 /* crtat = 0; */ 838 839 pc_context_init(crt_iot, crt_memt, kbd_iot, config); 840 841 /* locate the major number */ 842 maj = cdevsw_lookup_major(&pc_cdevsw); 843 pccons.cn_dev = makedev(maj, 0); 844 845 cn_tab = &pccons; 846 } 847 848 /* ARGSUSED */ 849 void 850 pccnputc(dev_t dev, int c) 851 { 852 u_char cc, oldkernel = kernel; 853 854 kernel = 1; 855 if (c == '\n') { 856 sput("\r\n", 2); 857 } else { 858 cc = c; 859 sput(&cc, 1); 860 } 861 kernel = oldkernel; 862 } 863 864 /* ARGSUSED */ 865 int 866 pccngetc(dev_t dev) 867 { 868 char *cp; 869 870 if (pc_xmode > 0) 871 return 0; 872 873 do { 874 /* wait for byte */ 875 while ((kbd_cmd_read_1() & KBS_DIB) == 0); 876 /* see if it's worthwhile */ 877 cp = sget(); 878 } while (!cp); 879 if (*cp == '\r') 880 return '\n'; 881 return *cp; 882 } 883 884 void 885 pccnpollc(dev_t dev, int on) 886 { 887 888 polling = on; 889 if (!on) { 890 int unit; 891 struct pc_softc *sc; 892 int s; 893 894 /* 895 * If disabling polling on a device that's been configured, 896 * make sure there are no bytes left in the FIFO, holding up 897 * the interrupt line. Otherwise we won't get any further 898 * interrupts. 899 */ 900 unit = PCUNIT(dev); 901 if (pc_cd.cd_ndevs > unit) { 902 sc = pc_cd.cd_devs[unit]; 903 if (sc != 0) { 904 s = spltty(); 905 pcintr(sc); 906 splx(s); 907 } 908 } 909 } 910 } 911 912 /* 913 * Set line parameters. 914 */ 915 int 916 pcparam(struct tty *tp, struct termios *t) 917 { 918 919 tp->t_ispeed = t->c_ispeed; 920 tp->t_ospeed = t->c_ospeed; 921 tp->t_cflag = t->c_cflag; 922 return 0; 923 } 924 925 #define wrtchar(c, at) do {\ 926 char *cp = (char *)crtat; *cp++ = (c); *cp = (at); crtat++; vs.col++; \ 927 } while (0) 928 929 /* translate ANSI color codes to standard pc ones */ 930 static char fgansitopc[] = { 931 FG_BLACK, FG_RED, FG_GREEN, FG_BROWN, FG_BLUE, 932 FG_MAGENTA, FG_CYAN, FG_LIGHTGREY 933 }; 934 935 static char bgansitopc[] = { 936 BG_BLACK, BG_RED, BG_GREEN, BG_BROWN, BG_BLUE, 937 BG_MAGENTA, BG_CYAN, BG_LIGHTGREY 938 }; 939 940 static u_char iso2ibm437[] = 941 { 942 0, 0, 0, 0, 0, 0, 0, 0, 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 0xff, 0xad, 0x9b, 0x9c, 0, 0x9d, 0, 0x40, 947 0x6f, 0x63, 0x61, 0xae, 0, 0, 0, 0, 948 0xf8, 0xf1, 0xfd, 0x33, 0, 0xe6, 0, 0xfa, 949 0, 0x31, 0x6f, 0xaf, 0xac, 0xab, 0, 0xa8, 950 0x41, 0x41, 0x41, 0x41, 0x8e, 0x8f, 0x92, 0x80, 951 0x45, 0x90, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49, 952 0x81, 0xa5, 0x4f, 0x4f, 0x4f, 0x4f, 0x99, 0x4f, 953 0x4f, 0x55, 0x55, 0x55, 0x9a, 0x59, 0, 0xe1, 954 0x85, 0xa0, 0x83, 0x61, 0x84, 0x86, 0x91, 0x87, 955 0x8a, 0x82, 0x88, 0x89, 0x8d, 0xa1, 0x8c, 0x8b, 956 0, 0xa4, 0x95, 0xa2, 0x93, 0x6f, 0x94, 0x6f, 957 0x6f, 0x97, 0xa3, 0x96, 0x81, 0x98, 0, 0 958 }; 959 960 /* 961 * `pc3' termcap emulation. 962 */ 963 void 964 sput(u_char *cp, int n) 965 { 966 struct pccons_context *pc = &pccons_console_context; 967 u_char c, scroll = 0; 968 969 if (pc_xmode > 0) 970 return; 971 972 if (crtat == 0) { 973 volatile u_short *cp; 974 u_short was; 975 unsigned cursorat; 976 977 cp = bus_space_vaddr(pc->pc_crt_memt, pc->pc_cga_memh); 978 was = *cp; 979 *cp = 0xA55A; 980 if (*cp != 0xA55A) { 981 cp = bus_space_vaddr(pc->pc_crt_memt, 982 pc->pc_mono_memh); 983 pc->pc_6845_ioh = pc->pc_mono_ioh; 984 pc->pc_crt_memh = pc->pc_mono_memh; 985 vs.color = 0; 986 } else { 987 *cp = was; 988 pc->pc_6845_ioh = pc->pc_cga_ioh; 989 pc->pc_crt_memh = pc->pc_cga_memh; 990 vs.color = 1; 991 } 992 993 #ifdef FAT_CURSOR 994 cursor_shape = 0x0012; 995 #else 996 get_cursor_shape(); 997 #endif 998 999 bios_display_info(&vs.col, &vs.row, &vs.ncol, &vs.nrow); 1000 vs.nchr = vs.ncol * vs.nrow; 1001 vs.col--; 1002 vs.row--; 1003 cursorat = vs.ncol * vs.row + vs.col; 1004 vs.at = FG_LIGHTGREY | BG_BLACK; 1005 1006 Crtat = (u_short *)cp; 1007 crtat = Crtat + cursorat; 1008 1009 if (vs.color == 0) 1010 vs.so_at = FG_BLACK | BG_LIGHTGREY; 1011 else 1012 vs.so_at = FG_YELLOW | BG_BLACK; 1013 1014 fillw((vs.at << 8) | ' ', crtat, vs.nchr - cursorat); 1015 } 1016 1017 while (n--) { 1018 if (!(c = *cp++)) 1019 continue; 1020 1021 switch (c) { 1022 case 0x1B: 1023 if (vs.state >= VSS_ESCAPE) { 1024 wrtchar(c, vs.so_at); 1025 vs.state = 0; 1026 goto maybe_scroll; 1027 } else 1028 vs.state = VSS_ESCAPE; 1029 break; 1030 1031 case 0x9B: /* CSI */ 1032 vs.cx = vs.cy = 0; 1033 vs.state = VSS_EBRACE; 1034 break; 1035 1036 case '\t': { 1037 int inccol = 8 - (vs.col & 7); 1038 crtat += inccol; 1039 vs.col += inccol; 1040 } 1041 maybe_scroll: 1042 if (vs.col >= vs.ncol) { 1043 vs.col -= vs.ncol; 1044 scroll = 1; 1045 } 1046 break; 1047 1048 case '\b': 1049 if (crtat <= Crtat) 1050 break; 1051 --crtat; 1052 if (--vs.col < 0) 1053 vs.col += vs.ncol; /* non-destructive backspace */ 1054 break; 1055 1056 case '\r': 1057 crtat -= vs.col; 1058 vs.col = 0; 1059 break; 1060 1061 case '\n': 1062 crtat += vs.ncol; 1063 scroll = 1; 1064 break; 1065 1066 default: 1067 switch (vs.state) { 1068 case 0: 1069 if (c == '\a') 1070 sysbeep(BEEP_FREQ, BEEP_TIME); 1071 else { 1072 /* 1073 * If we're outputting multiple printed 1074 * characters, just blast them to the 1075 * screen until we reach the end of the 1076 * buffer or a control character. This 1077 * saves time by short-circuiting the 1078 * switch. 1079 * If we reach the end of the line, we 1080 * break to do a scroll check. 1081 */ 1082 for (;;) { 1083 if (c & 0x80) 1084 c = iso2ibm437[c&0x7f]; 1085 1086 if (vs.so) 1087 wrtchar(c, vs.so_at); 1088 else 1089 wrtchar(c, vs.at); 1090 if (vs.col >= vs.ncol) { 1091 vs.col = 0; 1092 scroll = 1; 1093 break; 1094 } 1095 if (!n || (c = *cp) < ' ') 1096 break; 1097 n--, cp++; 1098 } 1099 } 1100 break; 1101 case VSS_ESCAPE: 1102 switch (c) { 1103 case '[': /* Start ESC [ sequence */ 1104 vs.cx = vs.cy = 0; 1105 vs.state = VSS_EBRACE; 1106 break; 1107 case 'c': /* Create screen & home */ 1108 fillw((vs.at << 8) | ' ', 1109 Crtat, vs.nchr); 1110 crtat = Crtat; 1111 vs.col = 0; 1112 vs.state = 0; 1113 break; 1114 case '7': /* save cursor pos */ 1115 vs.offset = crtat - Crtat; 1116 vs.state = 0; 1117 break; 1118 case '8': /* restore cursor pos */ 1119 crtat = Crtat + vs.offset; 1120 vs.row = vs.offset / vs.ncol; 1121 vs.col = vs.offset % vs.ncol; 1122 vs.state = 0; 1123 break; 1124 default: /* Invalid, clear state */ 1125 wrtchar(c, vs.so_at); 1126 vs.state = 0; 1127 goto maybe_scroll; 1128 } 1129 break; 1130 1131 default: /* VSS_EBRACE or VSS_EPARAM */ 1132 switch (c) { 1133 int pos; 1134 case 'm': 1135 if (!vs.cx) 1136 vs.so = 0; 1137 else 1138 vs.so = 1; 1139 vs.state = 0; 1140 break; 1141 case 'A': { /* back cx rows */ 1142 int cx = vs.cx; 1143 if (cx <= 0) 1144 cx = 1; 1145 else 1146 cx %= vs.nrow; 1147 pos = crtat - Crtat; 1148 pos -= vs.ncol * cx; 1149 if (pos < 0) 1150 pos += vs.nchr; 1151 crtat = Crtat + pos; 1152 vs.state = 0; 1153 break; 1154 } 1155 case 'B': { /* down cx rows */ 1156 int cx = vs.cx; 1157 if (cx <= 0) 1158 cx = 1; 1159 else 1160 cx %= vs.nrow; 1161 pos = crtat - Crtat; 1162 pos += vs.ncol * cx; 1163 if (pos >= vs.nchr) 1164 pos -= vs.nchr; 1165 crtat = Crtat + pos; 1166 vs.state = 0; 1167 break; 1168 } 1169 case 'C': { /* right cursor */ 1170 int cx = vs.cx, 1171 col = vs.col; 1172 if (cx <= 0) 1173 cx = 1; 1174 else 1175 cx %= vs.ncol; 1176 pos = crtat - Crtat; 1177 pos += cx; 1178 col += cx; 1179 if (col >= vs.ncol) { 1180 pos -= vs.ncol; 1181 col -= vs.ncol; 1182 } 1183 vs.col = col; 1184 crtat = Crtat + pos; 1185 vs.state = 0; 1186 break; 1187 } 1188 case 'D': { /* left cursor */ 1189 int cx = vs.cx, 1190 col = vs.col; 1191 if (cx <= 0) 1192 cx = 1; 1193 else 1194 cx %= vs.ncol; 1195 pos = crtat - Crtat; 1196 pos -= cx; 1197 col -= cx; 1198 if (col < 0) { 1199 pos += vs.ncol; 1200 col += vs.ncol; 1201 } 1202 vs.col = col; 1203 crtat = Crtat + pos; 1204 vs.state = 0; 1205 break; 1206 } 1207 case 'J': /* Clear ... */ 1208 switch (vs.cx) { 1209 case 0: 1210 /* ... to end of display */ 1211 fillw((vs.at << 8) | ' ', 1212 crtat, 1213 Crtat + vs.nchr - crtat); 1214 break; 1215 case 1: 1216 /* ... to next location */ 1217 fillw((vs.at << 8) | ' ', 1218 Crtat, 1219 crtat - Crtat + 1); 1220 break; 1221 case 2: 1222 /* ... whole display */ 1223 fillw((vs.at << 8) | ' ', 1224 Crtat, 1225 vs.nchr); 1226 break; 1227 } 1228 vs.state = 0; 1229 break; 1230 case 'K': /* Clear line ... */ 1231 switch (vs.cx) { 1232 case 0: 1233 /* ... current to EOL */ 1234 fillw((vs.at << 8) | ' ', 1235 crtat, 1236 vs.ncol - vs.col); 1237 break; 1238 case 1: 1239 /* ... beginning to next */ 1240 fillw((vs.at << 8) | ' ', 1241 crtat - vs.col, 1242 vs.col + 1); 1243 break; 1244 case 2: 1245 /* ... entire line */ 1246 fillw((vs.at << 8) | ' ', 1247 crtat - vs.col, vs.ncol); 1248 break; 1249 } 1250 vs.state = 0; 1251 break; 1252 case 'f': /* in system V consoles */ 1253 case 'H': { /* Cursor move */ 1254 int cx = vs.cx, 1255 cy = vs.cy; 1256 if (!cx || !cy) { 1257 crtat = Crtat; 1258 vs.col = 0; 1259 } else { 1260 if (cx > vs.nrow) 1261 cx = vs.nrow; 1262 if (cy > vs.ncol) 1263 cy = vs.ncol; 1264 crtat = Crtat + 1265 (cx - 1) * vs.ncol + cy - 1; 1266 vs.col = cy - 1; 1267 } 1268 vs.state = 0; 1269 break; 1270 } 1271 case 'M': { /* delete cx rows */ 1272 u_short *crtAt = crtat - vs.col; 1273 int cx = vs.cx, 1274 row = (crtAt - Crtat) / vs.ncol, 1275 nrow = vs.nrow - row; 1276 if (cx <= 0) 1277 cx = 1; 1278 else if (cx > nrow) 1279 cx = nrow; 1280 if (cx < nrow) 1281 #ifdef PCCONS_FORCE_WORD 1282 wcopy(crtAt + vs.ncol * cx, 1283 crtAt, vs.ncol * (nrow - 1284 cx) * CHR); 1285 #else 1286 bcopy(crtAt + vs.ncol * cx, 1287 crtAt, vs.ncol * (nrow - 1288 cx) * CHR); 1289 #endif 1290 fillw((vs.at << 8) | ' ', 1291 crtAt + vs.ncol * (nrow - cx), 1292 vs.ncol * cx); 1293 vs.state = 0; 1294 break; 1295 } 1296 case 'S': { /* scroll up cx lines */ 1297 int cx = vs.cx; 1298 if (cx <= 0) 1299 cx = 1; 1300 else if (cx > vs.nrow) 1301 cx = vs.nrow; 1302 if (cx < vs.nrow) 1303 #ifdef PCCONS_FORCE_WORD 1304 wcopy(Crtat + vs.ncol * cx, 1305 Crtat, vs.ncol * (vs.nrow - 1306 cx) * CHR); 1307 #else 1308 bcopy(Crtat + vs.ncol * cx, 1309 Crtat, vs.ncol * (vs.nrow - 1310 cx) * CHR); 1311 #endif 1312 fillw((vs.at << 8) | ' ', 1313 Crtat + vs.ncol * (vs.nrow - cx), 1314 vs.ncol * cx); 1315 /* crtat -= vs.ncol * cx; XXX */ 1316 vs.state = 0; 1317 break; 1318 } 1319 case 'L': { /* insert cx rows */ 1320 u_short *crtAt = crtat - vs.col; 1321 int cx = vs.cx, 1322 row = (crtAt - Crtat) / vs.ncol, 1323 nrow = vs.nrow - row; 1324 if (cx <= 0) 1325 cx = 1; 1326 else if (cx > nrow) 1327 cx = nrow; 1328 if (cx < nrow) 1329 #ifdef PCCONS_FORCE_WORD 1330 wcopy(crtAt, 1331 crtAt + vs.ncol * cx, 1332 vs.ncol * (nrow - cx) * 1333 CHR); 1334 #else 1335 bcopy(crtAt, 1336 crtAt + vs.ncol * cx, 1337 vs.ncol * (nrow - cx) * 1338 CHR); 1339 #endif 1340 fillw((vs.at << 8) | ' ', crtAt, 1341 vs.ncol * cx); 1342 vs.state = 0; 1343 break; 1344 } 1345 case 'T': { /* scroll down cx lines */ 1346 int cx = vs.cx; 1347 if (cx <= 0) 1348 cx = 1; 1349 else if (cx > vs.nrow) 1350 cx = vs.nrow; 1351 if (cx < vs.nrow) 1352 #ifdef PCCONS_FORCE_WORD 1353 wcopy(Crtat, 1354 Crtat + vs.ncol * cx, 1355 vs.ncol * (vs.nrow - cx) * 1356 CHR); 1357 #else 1358 bcopy(Crtat, 1359 Crtat + vs.ncol * cx, 1360 vs.ncol * (vs.nrow - cx) * 1361 CHR); 1362 #endif 1363 fillw((vs.at << 8) | ' ', Crtat, 1364 vs.ncol * cx); 1365 /* crtat += vs.ncol * cx; XXX */ 1366 vs.state = 0; 1367 break; 1368 } 1369 case ';': /* Switch params in cursor def */ 1370 vs.state = VSS_EPARAM; 1371 break; 1372 case 'r': 1373 vs.so_at = (vs.cx & FG_MASK) | 1374 ((vs.cy << 4) & BG_MASK); 1375 vs.state = 0; 1376 break; 1377 case 's': /* save cursor pos */ 1378 vs.offset = crtat - Crtat; 1379 vs.state = 0; 1380 break; 1381 case 'u': /* restore cursor pos */ 1382 crtat = Crtat + vs.offset; 1383 vs.row = vs.offset / vs.ncol; 1384 vs.col = vs.offset % vs.ncol; 1385 vs.state = 0; 1386 break; 1387 case 'x': /* set attributes */ 1388 switch (vs.cx) { 1389 case 0: 1390 vs.at = FG_LIGHTGREY | BG_BLACK; 1391 break; 1392 case 1: 1393 /* ansi background */ 1394 if (!vs.color) 1395 break; 1396 vs.at &= FG_MASK; 1397 vs.at |= bgansitopc[vs.cy & 7]; 1398 break; 1399 case 2: 1400 /* ansi foreground */ 1401 if (!vs.color) 1402 break; 1403 vs.at &= BG_MASK; 1404 vs.at |= fgansitopc[vs.cy & 7]; 1405 break; 1406 case 3: 1407 /* pc text attribute */ 1408 if (vs.state >= VSS_EPARAM) 1409 vs.at = vs.cy; 1410 break; 1411 } 1412 vs.state = 0; 1413 break; 1414 1415 default: /* Only numbers valid here */ 1416 if ((c >= '0') && (c <= '9')) { 1417 if (vs.state >= VSS_EPARAM) { 1418 vs.cy *= 10; 1419 vs.cy += c - '0'; 1420 } else { 1421 vs.cx *= 10; 1422 vs.cx += c - '0'; 1423 } 1424 } else 1425 vs.state = 0; 1426 break; 1427 } 1428 break; 1429 } 1430 } 1431 if (scroll) { 1432 scroll = 0; 1433 /* scroll check */ 1434 if (crtat >= Crtat + vs.nchr) { 1435 if (!kernel) { 1436 int s = spltty(); 1437 if (lock_state & KB_SCROLL) 1438 tsleep(&lock_state, 1439 PUSER, "pcputc", 0); 1440 splx(s); 1441 } 1442 #if PCCONS_FORCE_WORD 1443 wcopy(Crtat + vs.ncol, Crtat, 1444 (vs.nchr - vs.ncol) * CHR); 1445 #else 1446 bcopy(Crtat + vs.ncol, Crtat, 1447 (vs.nchr - vs.ncol) * CHR); 1448 #endif 1449 fillw((vs.at << 8) | ' ', 1450 Crtat + vs.nchr - vs.ncol, 1451 vs.ncol); 1452 crtat -= vs.ncol; 1453 } 1454 } 1455 } 1456 async_update(); 1457 } 1458 1459 /* the unshifted code for KB_SHIFT keys is used by X to distinguish between 1460 left and right shift when reading the keyboard map */ 1461 static pccons_keymap_t scan_codes[KB_NUM_KEYS] = { 1462 /* type unshift shift control altgr shift_altgr scancode */ 1463 { KB_NONE, "", "", "", "", ""}, /* 0 unused */ 1464 { KB_ASCII, "\033", "\033", "\033", "", ""}, /* 1 ESCape */ 1465 { KB_ASCII, "1", "!", "!", "", ""}, /* 2 1 */ 1466 { KB_ASCII, "2", "@", "\000", "", ""}, /* 3 2 */ 1467 { KB_ASCII, "3", "#", "#", "", ""}, /* 4 3 */ 1468 { KB_ASCII, "4", "$", "$", "", ""}, /* 5 4 */ 1469 { KB_ASCII, "5", "%", "%", "", ""}, /* 6 5 */ 1470 { KB_ASCII, "6", "^", "\036", "", ""}, /* 7 6 */ 1471 { KB_ASCII, "7", "&", "&", "", ""}, /* 8 7 */ 1472 { KB_ASCII, "8", "*", "\010", "", ""}, /* 9 8 */ 1473 { KB_ASCII, "9", "(", "(", "", ""}, /* 10 9 */ 1474 { KB_ASCII, "0", ")", ")", "", ""}, /* 11 0 */ 1475 { KB_ASCII, "-", "_", "\037", "", ""}, /* 12 - */ 1476 { KB_ASCII, "=", "+", "+", "", ""}, /* 13 = */ 1477 { KB_ASCII, "\177", "\177", "\010", "", ""}, /* 14 backspace */ 1478 { KB_ASCII, "\t", "\t", "\t", "", ""}, /* 15 tab */ 1479 { KB_ASCII, "q", "Q", "\021", "", ""}, /* 16 q */ 1480 { KB_ASCII, "w", "W", "\027", "", ""}, /* 17 w */ 1481 { KB_ASCII, "e", "E", "\005", "", ""}, /* 18 e */ 1482 { KB_ASCII, "r", "R", "\022", "", ""}, /* 19 r */ 1483 { KB_ASCII, "t", "T", "\024", "", ""}, /* 20 t */ 1484 { KB_ASCII, "y", "Y", "\031", "", ""}, /* 21 y */ 1485 { KB_ASCII, "u", "U", "\025", "", ""}, /* 22 u */ 1486 { KB_ASCII, "i", "I", "\011", "", ""}, /* 23 i */ 1487 { KB_ASCII, "o", "O", "\017", "", ""}, /* 24 o */ 1488 { KB_ASCII, "p", "P", "\020", "", ""}, /* 25 p */ 1489 { KB_ASCII, "[", "{", "\033", "", ""}, /* 26 [ */ 1490 { KB_ASCII, "]", "}", "\035", "", ""}, /* 27 ] */ 1491 { KB_ASCII, "\r", "\r", "\n", "", ""}, /* 28 return */ 1492 { KB_CTL, "", "", "", "", ""}, /* 29 control */ 1493 { KB_ASCII, "a", "A", "\001", "", ""}, /* 30 a */ 1494 { KB_ASCII, "s", "S", "\023", "", ""}, /* 31 s */ 1495 { KB_ASCII, "d", "D", "\004", "", ""}, /* 32 d */ 1496 { KB_ASCII, "f", "F", "\006", "", ""}, /* 33 f */ 1497 { KB_ASCII, "g", "G", "\007", "", ""}, /* 34 g */ 1498 { KB_ASCII, "h", "H", "\010", "", ""}, /* 35 h */ 1499 { KB_ASCII, "j", "J", "\n", "", ""}, /* 36 j */ 1500 { KB_ASCII, "k", "K", "\013", "", ""}, /* 37 k */ 1501 { KB_ASCII, "l", "L", "\014", "", ""}, /* 38 l */ 1502 { KB_ASCII, ";", ":", ";", "", ""}, /* 39 ; */ 1503 { KB_ASCII, "'", "\"", "'", "", ""}, /* 40 ' */ 1504 { KB_ASCII, "`", "~", "`", "", ""}, /* 41 ` */ 1505 { KB_SHIFT, "\001", "", "", "", ""}, /* 42 shift */ 1506 { KB_ASCII, "\\", "|", "\034", "", ""}, /* 43 \ */ 1507 { KB_ASCII, "z", "Z", "\032", "", ""}, /* 44 z */ 1508 { KB_ASCII, "x", "X", "\030", "", ""}, /* 45 x */ 1509 { KB_ASCII, "c", "C", "\003", "", ""}, /* 46 c */ 1510 { KB_ASCII, "v", "V", "\026", "", ""}, /* 47 v */ 1511 { KB_ASCII, "b", "B", "\002", "", ""}, /* 48 b */ 1512 { KB_ASCII, "n", "N", "\016", "", ""}, /* 49 n */ 1513 { KB_ASCII, "m", "M", "\r", "", ""}, /* 50 m */ 1514 { KB_ASCII, ",", "<", "<", "", ""}, /* 51 , */ 1515 { KB_ASCII, ".", ">", ">", "", ""}, /* 52 . */ 1516 { KB_ASCII, "/", "?", "\037", "", ""}, /* 53 / */ 1517 { KB_SHIFT, "\002", "", "", "", ""}, /* 54 shift */ 1518 { KB_KP, "*", "*", "*", "", ""}, /* 55 kp * */ 1519 { KB_ALT, "", "", "", "", ""}, /* 56 alt */ 1520 { KB_ASCII, " ", " ", "\000", "", ""}, /* 57 space */ 1521 { KB_CAPS, "", "", "", "", ""}, /* 58 caps */ 1522 { KB_FUNC, "\033[M", "\033[Y", "\033[k", "", ""}, /* 59 f1 */ 1523 { KB_FUNC, "\033[N", "\033[Z", "\033[l", "", ""}, /* 60 f2 */ 1524 { KB_FUNC, "\033[O", "\033[a", "\033[m", "", ""}, /* 61 f3 */ 1525 { KB_FUNC, "\033[P", "\033[b", "\033[n", "", ""}, /* 62 f4 */ 1526 { KB_FUNC, "\033[Q", "\033[c", "\033[o", "", ""}, /* 63 f5 */ 1527 { KB_FUNC, "\033[R", "\033[d", "\033[p", "", ""}, /* 64 f6 */ 1528 { KB_FUNC, "\033[S", "\033[e", "\033[q", "", ""}, /* 65 f7 */ 1529 { KB_FUNC, "\033[T", "\033[f", "\033[r", "", ""}, /* 66 f8 */ 1530 { KB_FUNC, "\033[U", "\033[g", "\033[s", "", ""}, /* 67 f9 */ 1531 { KB_FUNC, "\033[V", "\033[h", "\033[t", "", ""}, /* 68 f10 */ 1532 { KB_NUM, "", "", "", "", ""}, /* 69 num lock */ 1533 { KB_SCROLL, "", "", "", "", ""}, /* 70 scroll lock */ 1534 { KB_KP, "7", "\033[H", "7", "", ""}, /* 71 kp 7 */ 1535 { KB_KP, "8", "\033[A", "8", "", ""}, /* 72 kp 8 */ 1536 { KB_KP, "9", "\033[I", "9", "", ""}, /* 73 kp 9 */ 1537 { KB_KP, "-", "-", "-", "", ""}, /* 74 kp - */ 1538 { KB_KP, "4", "\033[D", "4", "", ""}, /* 75 kp 4 */ 1539 { KB_KP, "5", "\033[E", "5", "", ""}, /* 76 kp 5 */ 1540 { KB_KP, "6", "\033[C", "6", "", ""}, /* 77 kp 6 */ 1541 { KB_KP, "+", "+", "+", "", ""}, /* 78 kp + */ 1542 { KB_KP, "1", "\033[F", "1", "", ""}, /* 79 kp 1 */ 1543 { KB_KP, "2", "\033[B", "2", "", ""}, /* 80 kp 2 */ 1544 { KB_KP, "3", "\033[G", "3", "", ""}, /* 81 kp 3 */ 1545 { KB_KP, "0", "\033[L", "0", "", ""}, /* 82 kp 0 */ 1546 { KB_KP, ",", "\177", ",", "", ""}, /* 83 kp , */ 1547 { KB_NONE, "", "", "", "", ""}, /* 84 0 */ 1548 { KB_NONE, "", "", "", "", ""}, /* 85 0 */ 1549 { KB_NONE, "", "", "", "", ""}, /* 86 0 */ 1550 { KB_FUNC, "\033[W", "\033[i", "\033[u", "", ""}, /* 87 f11 */ 1551 { KB_FUNC, "\033[X", "\033[j", "\033[v", "", ""}, /* 88 f12 */ 1552 { KB_NONE, "", "", "", "", ""}, /* 89 0 */ 1553 { KB_NONE, "", "", "", "", ""}, /* 90 0 */ 1554 { KB_NONE, "", "", "", "", ""}, /* 91 0 */ 1555 { KB_NONE, "", "", "", "", ""}, /* 92 0 */ 1556 { KB_NONE, "", "", "", "", ""}, /* 93 0 */ 1557 { KB_NONE, "", "", "", "", ""}, /* 94 0 */ 1558 { KB_NONE, "", "", "", "", ""}, /* 95 0 */ 1559 { KB_NONE, "", "", "", "", ""}, /* 96 0 */ 1560 { KB_NONE, "", "", "", "", ""}, /* 97 0 */ 1561 { KB_NONE, "", "", "", "", ""}, /* 98 0 */ 1562 { KB_NONE, "", "", "", "", ""}, /* 99 0 */ 1563 { KB_NONE, "", "", "", "", ""}, /* 100 */ 1564 { KB_NONE, "", "", "", "", ""}, /* 101 */ 1565 { KB_NONE, "", "", "", "", ""}, /* 102 */ 1566 { KB_NONE, "", "", "", "", ""}, /* 103 */ 1567 { KB_NONE, "", "", "", "", ""}, /* 104 */ 1568 { KB_NONE, "", "", "", "", ""}, /* 105 */ 1569 { KB_NONE, "", "", "", "", ""}, /* 106 */ 1570 { KB_NONE, "", "", "", "", ""}, /* 107 */ 1571 { KB_NONE, "", "", "", "", ""}, /* 108 */ 1572 { KB_NONE, "", "", "", "", ""}, /* 109 */ 1573 { KB_NONE, "", "", "", "", ""}, /* 110 */ 1574 { KB_NONE, "", "", "", "", ""}, /* 111 */ 1575 { KB_NONE, "", "", "", "", ""}, /* 112 */ 1576 { KB_NONE, "", "", "", "", ""}, /* 113 */ 1577 { KB_NONE, "", "", "", "", ""}, /* 114 */ 1578 { KB_NONE, "", "", "", "", ""}, /* 115 */ 1579 { KB_NONE, "", "", "", "", ""}, /* 116 */ 1580 { KB_NONE, "", "", "", "", ""}, /* 117 */ 1581 { KB_NONE, "", "", "", "", ""}, /* 118 */ 1582 { KB_NONE, "", "", "", "", ""}, /* 119 */ 1583 { KB_NONE, "", "", "", "", ""}, /* 120 */ 1584 { KB_NONE, "", "", "", "", ""}, /* 121 */ 1585 { KB_NONE, "", "", "", "", ""}, /* 122 */ 1586 { KB_NONE, "", "", "", "", ""}, /* 123 */ 1587 { KB_NONE, "", "", "", "", ""}, /* 124 */ 1588 { KB_NONE, "", "", "", "", ""}, /* 125 */ 1589 { KB_NONE, "", "", "", "", ""}, /* 126 */ 1590 { KB_NONE, "", "", "", "", ""} /* 127 */ 1591 }; 1592 1593 /* 1594 * Get characters from the keyboard. If none are present, return NULL. 1595 */ 1596 char * 1597 sget(void) 1598 { 1599 u_char dt; 1600 static u_char extended = 0, shift_state = 0; 1601 static u_char capchar[2]; 1602 1603 top: 1604 KBD_DELAY; 1605 dt = kbd_data_read_1(); 1606 1607 switch (dt) { 1608 case KBR_ACK: case KBR_ECHO: 1609 kb_oq_get = (kb_oq_get + 1) & 7; 1610 if(kb_oq_get != kb_oq_put) { 1611 kbd_data_write_1(kb_oq[kb_oq_get]); 1612 } 1613 goto loop; 1614 case KBR_RESEND: 1615 kbd_data_write_1(kb_oq[kb_oq_get]); 1616 goto loop; 1617 } 1618 1619 if (pc_xmode > 0) { 1620 #if defined(DDB) && defined(XSERVER_DDB) 1621 /* F12 enters the debugger while in X mode */ 1622 if (dt == 88) 1623 Debugger(); 1624 #endif 1625 capchar[0] = dt; 1626 capchar[1] = 0; 1627 /* 1628 * Check for locking keys. 1629 * 1630 * XXX Setting the LEDs this way is a bit bogus. What if the 1631 * keyboard has been remapped in X? 1632 */ 1633 switch (scan_codes[dt & 0x7f].type) { 1634 case KB_NUM: 1635 if (dt & 0x80) { 1636 shift_state &= ~KB_NUM; 1637 break; 1638 } 1639 if (shift_state & KB_NUM) 1640 break; 1641 shift_state |= KB_NUM; 1642 lock_state ^= KB_NUM; 1643 async_update(); 1644 break; 1645 case KB_CAPS: 1646 if (dt & 0x80) { 1647 shift_state &= ~KB_CAPS; 1648 break; 1649 } 1650 if (shift_state & KB_CAPS) 1651 break; 1652 shift_state |= KB_CAPS; 1653 lock_state ^= KB_CAPS; 1654 async_update(); 1655 break; 1656 case KB_SCROLL: 1657 if (dt & 0x80) { 1658 shift_state &= ~KB_SCROLL; 1659 break; 1660 } 1661 if (shift_state & KB_SCROLL) 1662 break; 1663 shift_state |= KB_SCROLL; 1664 lock_state ^= KB_SCROLL; 1665 if ((lock_state & KB_SCROLL) == 0) 1666 wakeup((caddr_t)&lock_state); 1667 async_update(); 1668 break; 1669 } 1670 return capchar; 1671 } 1672 1673 switch (dt) { 1674 case KBR_EXTENDED: 1675 extended = 1; 1676 goto loop; 1677 } 1678 1679 #ifdef DDB 1680 /* 1681 * Check for cntl-alt-esc. 1682 */ 1683 if ((dt == 1) && (shift_state & (KB_CTL | KB_ALT)) == (KB_CTL | KB_ALT)) { 1684 /* XXX - check pccons_is_console */ 1685 Debugger(); 1686 dt |= 0x80; /* discard esc (ddb discarded ctl-alt) */ 1687 } 1688 #endif 1689 1690 /* 1691 * Check for make/break. 1692 */ 1693 if (dt & 0x80) { 1694 /* 1695 * break 1696 */ 1697 dt &= 0x7f; 1698 switch (scan_codes[dt].type) { 1699 case KB_NUM: 1700 shift_state &= ~KB_NUM; 1701 break; 1702 case KB_CAPS: 1703 shift_state &= ~KB_CAPS; 1704 break; 1705 case KB_SCROLL: 1706 shift_state &= ~KB_SCROLL; 1707 break; 1708 case KB_SHIFT: 1709 shift_state &= ~KB_SHIFT; 1710 break; 1711 case KB_ALT: 1712 if (extended) 1713 shift_state &= ~KB_ALTGR; 1714 else 1715 shift_state &= ~KB_ALT; 1716 break; 1717 case KB_CTL: 1718 shift_state &= ~KB_CTL; 1719 break; 1720 } 1721 } else { 1722 /* 1723 * make 1724 */ 1725 switch (scan_codes[dt].type) { 1726 /* 1727 * locking keys 1728 */ 1729 case KB_NUM: 1730 if (shift_state & KB_NUM) 1731 break; 1732 shift_state |= KB_NUM; 1733 lock_state ^= KB_NUM; 1734 async_update(); 1735 break; 1736 case KB_CAPS: 1737 if (shift_state & KB_CAPS) 1738 break; 1739 shift_state |= KB_CAPS; 1740 lock_state ^= KB_CAPS; 1741 async_update(); 1742 break; 1743 case KB_SCROLL: 1744 if (shift_state & KB_SCROLL) 1745 break; 1746 shift_state |= KB_SCROLL; 1747 lock_state ^= KB_SCROLL; 1748 if ((lock_state & KB_SCROLL) == 0) 1749 wakeup((caddr_t)&lock_state); 1750 async_update(); 1751 break; 1752 /* 1753 * non-locking keys 1754 */ 1755 case KB_SHIFT: 1756 shift_state |= KB_SHIFT; 1757 break; 1758 case KB_ALT: 1759 if (extended) 1760 shift_state |= KB_ALTGR; 1761 else 1762 shift_state |= KB_ALT; 1763 break; 1764 case KB_CTL: 1765 shift_state |= KB_CTL; 1766 break; 1767 case KB_ASCII: 1768 /* control has highest priority */ 1769 if (shift_state & KB_CTL) 1770 capchar[0] = scan_codes[dt].ctl[0]; 1771 else if (shift_state & KB_ALTGR) { 1772 if (shift_state & KB_SHIFT) 1773 capchar[0] = scan_codes[dt].shift_altgr[0]; 1774 else 1775 capchar[0] = scan_codes[dt].altgr[0]; 1776 } 1777 else { 1778 if (shift_state & KB_SHIFT) 1779 capchar[0] = scan_codes[dt].shift[0]; 1780 else 1781 capchar[0] = scan_codes[dt].unshift[0]; 1782 } 1783 if ((lock_state & KB_CAPS) && capchar[0] >= 'a' && 1784 capchar[0] <= 'z') { 1785 capchar[0] -= ('a' - 'A'); 1786 } 1787 capchar[0] |= (shift_state & KB_ALT); 1788 extended = 0; 1789 return capchar; 1790 case KB_NONE: 1791 printf("keycode %d\n",dt); 1792 break; 1793 case KB_FUNC: { 1794 char *more_chars; 1795 if (shift_state & KB_SHIFT) 1796 more_chars = scan_codes[dt].shift; 1797 else if (shift_state & KB_CTL) 1798 more_chars = scan_codes[dt].ctl; 1799 else 1800 more_chars = scan_codes[dt].unshift; 1801 extended = 0; 1802 return more_chars; 1803 } 1804 case KB_KP: { 1805 char *more_chars; 1806 if (shift_state & (KB_SHIFT | KB_CTL) || 1807 (lock_state & KB_NUM) == 0 || extended) 1808 more_chars = scan_codes[dt].shift; 1809 else 1810 more_chars = scan_codes[dt].unshift; 1811 extended = 0; 1812 return more_chars; 1813 } 1814 } 1815 } 1816 1817 extended = 0; 1818 loop: 1819 if ((kbd_cmd_read_1() & KBS_DIB) == 0) 1820 return 0; 1821 goto top; 1822 } 1823 1824 paddr_t 1825 pcmmap(dev_t dev, off_t offset, int nprot) 1826 { 1827 struct pccons_context *pc = &pccons_console_context; 1828 paddr_t pa; 1829 1830 if (offset >= 0xa0000 && offset < 0xc0000) { 1831 if (bus_space_paddr(pc->pc_crt_memt, pc->pc_mono_memh, &pa)) 1832 return -1; 1833 pa += offset - pc->pc_config->pc_mono_memaddr; 1834 return mips_btop(pa); 1835 } 1836 if (offset >= 0x0000 && offset < 0x10000) { 1837 if (bus_space_paddr(pc->pc_crt_iot, pc->pc_mono_ioh, &pa)) 1838 return -1; 1839 pa += offset - pc->pc_config->pc_mono_iobase; 1840 return mips_btop(pa); 1841 } 1842 if (offset >= 0x40000000 && offset < 0x40800000) { 1843 if (bus_space_paddr(pc->pc_crt_memt, pc->pc_mono_memh, &pa)) 1844 return (-1); 1845 pa += offset - 0x40000000 - pc->pc_config->pc_mono_memaddr; 1846 return mips_btop(pa); 1847 } 1848 return -1; 1849 } 1850 1851 void 1852 pc_xmode_on(void) 1853 { 1854 if (pc_xmode) 1855 return; 1856 pc_xmode = 1; 1857 1858 #ifdef XFREE86_BUG_COMPAT 1859 /* If still unchanged, get current shape. */ 1860 if (cursor_shape == 0xffff) 1861 get_cursor_shape(); 1862 #endif 1863 } 1864 1865 void 1866 pc_xmode_off(void) 1867 { 1868 if (pc_xmode == 0) 1869 return; 1870 pc_xmode = 0; 1871 1872 #ifdef XFREE86_BUG_COMPAT 1873 /* XXX It would be hard to justify why the X server doesn't do this. */ 1874 set_cursor_shape(); 1875 #endif 1876 async_update(); 1877 } 1878