1 /*- 2 * Copyright (c) 1992-1994 S�ren Schmidt 3 * Copyright (c) 1990 The Regents of the University of California. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * William Jolitz and Don Ahn. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by the University of 20 * California, Berkeley and its contributors. 21 * 4. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * $Id: syscons.c,v 1.51 1994/08/17 19:32:23 sos Exp $ 38 */ 39 40 #include "sc.h" 41 42 #if NSC > 0 43 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/conf.h> 47 #include <sys/ioctl.h> 48 #include <sys/proc.h> 49 #include <sys/user.h> 50 #include <sys/tty.h> 51 #include <sys/uio.h> 52 #include <sys/callout.h> 53 #include <sys/kernel.h> 54 #include <sys/syslog.h> 55 #include <sys/errno.h> 56 #include <sys/malloc.h> 57 #include <machine/console.h> 58 #include <machine/psl.h> 59 #include <machine/frame.h> 60 #include <machine/pc/display.h> 61 #include <i386/isa/isa.h> 62 #include <i386/isa/isa_device.h> 63 #include <i386/isa/timerreg.h> 64 #include <i386/isa/kbdtables.h> 65 #include <i386/i386/cons.h> 66 67 #if !defined(NCONS) 68 #define NCONS 12 69 #endif 70 71 #if !defined(NO_HARDFONTS) 72 #include <i386/isa/iso8859.font> 73 #endif 74 75 /* status flags */ 76 #define LOCK_KEY_MASK 0x0000F 77 #define LED_MASK 0x00007 78 #define UNKNOWN_MODE 0x00010 79 #define KBD_RAW_MODE 0x00020 80 #define SWITCH_WAIT_REL 0x00040 81 #define SWITCH_WAIT_ACQ 0x00080 82 83 /* video hardware memory addresses */ 84 #define VIDEOMEM 0x000A0000 85 86 /* misc defines */ 87 #define MAX_ESC_PAR 5 88 #define TEXT80x25 1 89 #define TEXT80x50 2 90 #define LOAD 1 91 #define SAVE 0 92 #define COL 80 93 #define ROW 25 94 #define BELL_DURATION 5 95 #define BELL_PITCH 800 96 #define TIMER_FREQ 1193182 /* should be in isa.h */ 97 #define CONSOLE_BUFSIZE 1024 98 #define PCBURST 128 99 #define FONT_8_LOADED 0x001 100 #define FONT_14_LOADED 0x002 101 #define FONT_16_LOADED 0x004 102 103 /* defines related to hardware addresses */ 104 #define MONO_BASE 0x3B4 /* crt controller base mono */ 105 #define COLOR_BASE 0x3D4 /* crt controller base color */ 106 #define ATC IO_VGA+0x00 /* attribute controller */ 107 #define TSIDX IO_VGA+0x04 /* timing sequencer idx */ 108 #define TSREG IO_VGA+0x05 /* timing sequencer data */ 109 #define PIXMASK IO_VGA+0x06 /* pixel write mask */ 110 #define PALRADR IO_VGA+0x07 /* palette read address */ 111 #define PALWADR IO_VGA+0x08 /* palette write address */ 112 #define PALDATA IO_VGA+0x09 /* palette data register */ 113 #define GDCIDX IO_VGA+0x0E /* graph data controller idx */ 114 #define GDCREG IO_VGA+0x0F /* graph data controller data */ 115 116 /* special characters */ 117 #define cntlc 0x03 118 #define cntld 0x04 119 #define bs 0x08 120 #define lf 0x0a 121 #define cr 0x0d 122 #define del 0x7f 123 124 typedef struct term_stat { 125 int esc; /* processing escape sequence */ 126 int num_param; /* # of parameters to ESC */ 127 int last_param; /* last parameter # */ 128 int param[MAX_ESC_PAR]; /* contains ESC parameters */ 129 int cur_attr; /* current attributes */ 130 int std_attr; /* normal attributes */ 131 int rev_attr; /* reverse attributes */ 132 } term_stat; 133 134 typedef struct scr_stat { 135 u_short *crt_base; /* address of screen memory */ 136 u_short *scr_buf; /* buffer when off screen */ 137 u_short *crtat; /* cursor address */ 138 int xpos; /* current X position */ 139 int ypos; /* current Y position */ 140 int xsize; /* X size */ 141 int ysize; /* Y size */ 142 term_stat term; /* terminal emulation stuff */ 143 char cursor_start; /* cursor start line # */ 144 char cursor_end; /* cursor end line # */ 145 u_char border; /* border color */ 146 u_short bell_duration; 147 u_short bell_pitch; 148 u_short status; /* status (bitfield) */ 149 u_short mode; /* mode */ 150 pid_t pid; /* pid of controlling proc */ 151 struct proc *proc; /* proc* of controlling proc */ 152 struct vt_mode smode; /* switch mode */ 153 } scr_stat; 154 155 typedef struct default_attr { 156 int std_attr; /* normal attributes */ 157 int rev_attr; /* reverse attributes */ 158 } default_attr; 159 160 static default_attr user_default = { 161 (FG_LIGHTGREY | BG_BLACK) << 8, 162 (FG_BLACK | BG_LIGHTGREY) << 8 163 }; 164 165 static default_attr kernel_default = { 166 (FG_WHITE | BG_BLACK) << 8, 167 (FG_BLACK | BG_LIGHTGREY) << 8 168 }; 169 170 static scr_stat console[NCONS]; 171 static scr_stat *cur_console = &console[0]; 172 static scr_stat *new_scp, *old_scp; 173 static term_stat kernel_console; 174 static default_attr *current_default; 175 static int console_buffer_count; 176 static char console_buffer[CONSOLE_BUFSIZE]; 177 static int switch_in_progress = 0; 178 static u_short *crtat = 0; 179 static u_int crtc_addr = MONO_BASE; 180 static char crtc_vga = 0; 181 static u_char shfts = 0, ctls = 0, alts = 0, agrs = 0, metas = 0; 182 static u_char nlkcnt = 0, clkcnt = 0, slkcnt = 0, alkcnt = 0; 183 static char *font_8 = NULL, *font_14 = NULL, *font_16 = NULL; 184 static int fonts_loaded = 0; 185 static char palette[3*256]; 186 static const u_int n_fkey_tab = sizeof(fkey_tab) / sizeof(*fkey_tab); 187 static int cur_cursor_pos = -1; 188 static char in_putc = 0; 189 static char polling = 0; 190 #if ASYNCH 191 static u_char kbd_reply = 0; 192 #endif 193 static int delayed_next_scr; 194 static char saved_console = -1; /* saved console number */ 195 static long scrn_blank_time = 0; /* screen saver timeout value */ 196 static int scrn_blanked = 0; /* screen saver active flag */ 197 static int scrn_saver = 0; /* screen saver routine */ 198 static long scrn_time_stamp; 199 static u_char scr_map[256]; 200 201 /* function prototypes */ 202 int pcprobe(struct isa_device *dev); 203 int pcattach(struct isa_device *dev); 204 int pcopen(dev_t dev, int flag, int mode, struct proc *p); 205 int pcclose(dev_t dev, int flag, int mode, struct proc *p); 206 int pcread(dev_t dev, struct uio *uio, int flag); 207 int pcwrite(dev_t dev, struct uio *uio, int flag); 208 int pcparam(struct tty *tp, struct termios *t); 209 int pcioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p); 210 void pcxint(dev_t dev); 211 void pcstart(struct tty *tp); 212 void pccnprobe(struct consdev *cp); 213 void pccninit(struct consdev *cp); 214 void pccnputc(dev_t dev, char c); 215 int pccngetc(dev_t dev); 216 void scintr(int unit); 217 int pcmmap(dev_t dev, int offset, int nprot); 218 u_int sgetc(int noblock); 219 int getchar(void); 220 static void scinit(void); 221 static void scput(u_char c); 222 static u_int scgetc(int noblock); 223 static struct tty *get_tty_ptr(dev_t dev); 224 static scr_stat *get_scr_stat(dev_t dev); 225 static int get_scr_num(); 226 static void cursor_shape(int start, int end); 227 static void get_cursor_shape(int *start, int *end); 228 static void cursor_pos(int force); 229 static void clear_screen(scr_stat *scp); 230 static int switch_scr(u_int next_scr); 231 static void exchange_scr(void); 232 static void move_crsr(scr_stat *scp, int x, int y); 233 static void move_up(u_short *s, u_short *d, u_int len); 234 static void move_down(u_short *s, u_short *d, u_int len); 235 static void scan_esc(scr_stat *scp, u_char c); 236 static void ansi_put(scr_stat *scp, u_char c); 237 static u_char *get_fstr(u_int c, u_int *len); 238 static void update_leds(int which); 239 static void kbd_wait(void); 240 static void kbd_cmd(u_char command); 241 static void set_mode(scr_stat *scp); 242 static void set_border(int color); 243 static void copy_font(int direction, int segment, int size, char* font); 244 static void save_palette(void); 245 static void load_palette(void); 246 static void change_winsize(struct tty *tp, int x, int y); 247 248 /* available screen savers */ 249 static void none_saver(int test); 250 static void blank_saver(int test); 251 static void fade_saver(int test); 252 static void star_saver(int test); 253 static void snake_saver(int test); 254 255 static const struct { 256 char *name; 257 void (*routine)(); 258 } screen_savers[] = { 259 { "none", none_saver }, /* 0 */ 260 { "blank", blank_saver }, /* 1 */ 261 { "fade", fade_saver }, /* 2 */ 262 { "star", star_saver }, /* 3 */ 263 { "snake", snake_saver }, /* 4 */ 264 }; 265 #define SCRN_SAVER(arg) (*screen_savers[scrn_saver].routine)(arg) 266 #define NUM_SCRN_SAVERS (sizeof(screen_savers) / sizeof(screen_savers[0])) 267 268 /* OS specific stuff */ 269 #if 0 270 #define VIRTUAL_TTY(x) (pccons[x] = ttymalloc(pccons[x])) 271 #define CONSOLE_TTY (pccons[NCONS] = ttymalloc(pccons[NCONS])) 272 struct tty *pccons[NCONS+1]; 273 #else 274 #define VIRTUAL_TTY(x) &pccons[x] 275 #define CONSOLE_TTY &pccons[NCONS] 276 struct tty pccons[NCONS+1]; 277 #endif 278 #define timeout_t timeout_func_t 279 #define MONO_BUF (KERNBASE+0xB0000) 280 #define CGA_BUF (KERNBASE+0xB8000) 281 #include "ddb.h" 282 #if NDDB > 0 283 #define DDB 1 284 #endif 285 u_short *Crtat = (u_short *)MONO_BUF; 286 void consinit(void) {scinit();} 287 288 struct isa_driver scdriver = { 289 pcprobe, pcattach, "sc", 290 }; 291 292 293 int 294 pcprobe(struct isa_device *dev) 295 { 296 int i, retries = 5; 297 unsigned char val; 298 299 /* Enable interrupts and keyboard controller */ 300 kbd_wait(); 301 outb(KB_STAT, KB_WRITE); 302 kbd_wait(); 303 outb(KB_DATA, KB_MODE); 304 305 /* flush any noise in the buffer */ 306 while (inb(KB_STAT) & KB_BUF_FULL) { 307 DELAY(10); 308 (void) inb(KB_DATA); 309 } 310 311 /* Reset keyboard hardware */ 312 while (retries--) { 313 kbd_wait(); 314 outb(KB_DATA, KB_RESET); 315 for (i=0; i<100000; i++) { 316 DELAY(10); 317 val = inb(KB_DATA); 318 if (val == KB_ACK || val == KB_ECHO) 319 goto gotres; 320 if (val == KB_RESEND) 321 break; 322 } 323 } 324 gotres: 325 if (!retries) 326 printf("scprobe: keyboard won't accept RESET command\n"); 327 else { 328 gotack: 329 DELAY(10); 330 while ((inb(KB_STAT) & KB_BUF_FULL) == 0) DELAY(10); 331 DELAY(10); 332 val = inb(KB_DATA); 333 if (val == KB_ACK) 334 goto gotack; 335 if (val != KB_RESET_DONE) 336 printf("scprobe: keyboard RESET failed %02x\n", val); 337 } 338 return (IO_KBDSIZE); 339 } 340 341 342 int 343 pcattach(struct isa_device *dev) 344 { 345 scr_stat *scp; 346 int start = -1, end = -1, i; 347 348 printf("sc%d: ", dev->id_unit); 349 if (crtc_vga) 350 if (crtc_addr == MONO_BASE) 351 printf("VGA mono"); 352 else 353 printf("VGA color"); 354 else 355 if (crtc_addr == MONO_BASE) 356 printf("MDA/hercules"); 357 else 358 printf("CGA/EGA"); 359 360 if (NCONS > 1) 361 printf(" <%d virtual consoles>\n", NCONS); 362 else 363 printf("\n"); 364 #if defined(FAT_CURSOR) 365 start = 0; 366 end = 18; 367 if (crtc_vga) { 368 #else 369 if (crtc_vga) { 370 get_cursor_shape(&start, &end); 371 #endif 372 #if !defined(NO_HARDFONTS) 373 font_8 = font_8x8; 374 font_14 = font_8x14; 375 font_16 = font_8x16; 376 fonts_loaded = FONT_8_LOADED|FONT_14_LOADED|FONT_16_LOADED; 377 copy_font(LOAD, 1, 8, font_8); 378 copy_font(LOAD, 2, 14, font_14); 379 copy_font(LOAD, 0, 16, font_16); 380 #else 381 font_8 = (char *)malloc(8*256, M_DEVBUF, M_NOWAIT); 382 font_14 = (char *)malloc(14*256, M_DEVBUF, M_NOWAIT); 383 font_16 = (char *)malloc(16*256, M_DEVBUF, M_NOWAIT); 384 copy_font(SAVE, 0, 16, font_16); 385 fonts_loaded = FONT_16_LOADED; 386 #endif 387 save_palette(); 388 } 389 current_default = &user_default; 390 for (i = 0; i < NCONS; i++) { 391 scp = &console[i]; 392 scp->scr_buf = (u_short *)malloc(COL * ROW * 2, 393 M_DEVBUF, M_NOWAIT); 394 scp->mode = TEXT80x25; 395 scp->term.esc = 0; 396 scp->term.std_attr = current_default->std_attr; 397 scp->term.rev_attr = current_default->rev_attr; 398 scp->term.cur_attr = scp->term.std_attr; 399 scp->border = BG_BLACK; 400 scp->cursor_start = start; 401 scp->cursor_end = end; 402 scp->xsize = COL; 403 scp->ysize = ROW; 404 scp->bell_pitch = BELL_PITCH; 405 scp->bell_duration = BELL_DURATION; 406 scp->status = NLKED; 407 scp->pid = 0; 408 scp->proc = NULL; 409 scp->smode.mode = VT_AUTO; 410 if (i > 0) { 411 scp->crt_base = scp->crtat = scp->scr_buf; 412 fillw(scp->term.cur_attr|scr_map[0x20], 413 scp->scr_buf, COL*ROW); 414 } 415 } 416 /* get cursor going */ 417 #if defined(FAT_CURSOR) 418 cursor_shape(console[0].cursor_start, 419 console[0].cursor_end); 420 #endif 421 cursor_pos(1); 422 update_leds(console[0].status); 423 return 0; 424 } 425 426 427 static struct tty 428 *get_tty_ptr(dev_t dev) 429 { 430 int unit = minor(dev); 431 432 if (unit > NCONS) 433 return(NULL); 434 if (unit == NCONS) 435 return(CONSOLE_TTY); 436 return(VIRTUAL_TTY(unit)); 437 } 438 439 440 static scr_stat 441 *get_scr_stat(dev_t dev) 442 { 443 int unit = minor(dev); 444 445 if (unit > NCONS) 446 return(NULL); 447 if (unit == NCONS) 448 return(&console[0]); 449 return(&console[unit]); 450 } 451 452 453 static int 454 get_scr_num() 455 { 456 int i = 0; 457 458 while ((i < NCONS) && (cur_console != &console[i])) i++; 459 return i < NCONS ? i : 0; 460 } 461 462 463 int 464 pcopen(dev_t dev, int flag, int mode, struct proc *p) 465 { 466 struct tty *tp = get_tty_ptr(dev); 467 468 if (!tp) 469 return(ENXIO); 470 471 tp->t_oproc = pcstart; 472 tp->t_param = pcparam; 473 tp->t_dev = dev; 474 if (!(tp->t_state & TS_ISOPEN)) { 475 ttychars(tp); 476 tp->t_iflag = TTYDEF_IFLAG; 477 tp->t_oflag = TTYDEF_OFLAG; 478 tp->t_cflag = TTYDEF_CFLAG; 479 tp->t_lflag = TTYDEF_LFLAG; 480 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 481 pcparam(tp, &tp->t_termios); 482 ttsetwater(tp); 483 } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0) 484 return(EBUSY); 485 tp->t_state |= TS_CARR_ON; 486 tp->t_cflag |= CLOCAL; 487 return((*linesw[tp->t_line].l_open)(dev, tp)); 488 } 489 490 491 int 492 pcclose(dev_t dev, int flag, int mode, struct proc *p) 493 { 494 struct tty *tp = get_tty_ptr(dev); 495 struct scr_stat *scp; 496 497 if (!tp) 498 return(ENXIO); 499 if (minor(dev) < NCONS) { 500 scp = get_scr_stat(tp->t_dev); 501 if (scp->status & SWITCH_WAIT_ACQ) 502 wakeup((caddr_t)&scp->smode); 503 scp->pid = 0; 504 scp->proc = NULL; 505 scp->smode.mode = VT_AUTO; 506 } 507 (*linesw[tp->t_line].l_close)(tp, flag); 508 ttyclose(tp); 509 return(0); 510 } 511 512 513 int 514 pcread(dev_t dev, struct uio *uio, int flag) 515 { 516 struct tty *tp = get_tty_ptr(dev); 517 518 if (!tp) 519 return(ENXIO); 520 return((*linesw[tp->t_line].l_read)(tp, uio, flag)); 521 } 522 523 524 int 525 pcwrite(dev_t dev, struct uio *uio, int flag) 526 { 527 struct tty *tp = get_tty_ptr(dev); 528 529 if (!tp) 530 return(ENXIO); 531 return((*linesw[tp->t_line].l_write)(tp, uio, flag)); 532 } 533 534 535 void 536 scintr(int unit) 537 { 538 static struct tty *cur_tty; 539 int c, len; 540 u_char *cp; 541 542 /* make screensaver happy */ 543 scrn_time_stamp = time.tv_sec; 544 if (scrn_blanked) 545 SCRN_SAVER(0); 546 547 c = scgetc(1); 548 549 cur_tty = VIRTUAL_TTY(get_scr_num()); 550 if (!(cur_tty->t_state & TS_ISOPEN)) 551 cur_tty = CONSOLE_TTY; 552 553 if (!(cur_tty->t_state & TS_ISOPEN) || polling) 554 return; 555 556 switch (c & 0xff00) { 557 case 0x0000: /* normal key */ 558 (*linesw[cur_tty->t_line].l_rint)(c & 0xFF, cur_tty); 559 break; 560 case NOKEY: /* nothing there */ 561 break; 562 case FKEY: /* function key, return string */ 563 if (cp = get_fstr((u_int)c, (u_int *)&len)) { 564 while (len-- > 0) 565 (*linesw[cur_tty->t_line].l_rint) 566 (*cp++ & 0xFF, cur_tty); 567 } 568 break; 569 case MKEY: /* meta is active, prepend ESC */ 570 (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty); 571 (*linesw[cur_tty->t_line].l_rint)(c & 0xFF, cur_tty); 572 break; 573 } 574 } 575 576 577 int 578 pcparam(struct tty *tp, struct termios *t) 579 { 580 int cflag = t->c_cflag; 581 582 /* and copy to tty */ 583 tp->t_ispeed = t->c_ispeed; 584 tp->t_ospeed = t->c_ospeed; 585 tp->t_cflag = cflag; 586 return 0; 587 } 588 589 590 int 591 pcioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) 592 { 593 int i, error; 594 struct tty *tp; 595 struct trapframe *fp; 596 scr_stat *scp; 597 598 tp = get_tty_ptr(dev); 599 if (!tp) 600 return ENXIO; 601 scp = get_scr_stat(tp->t_dev); 602 603 switch (cmd) { /* process console hardware related ioctl's */ 604 605 case CONS_BLANKTIME: /* set screen saver timeout (0 = no saver) */ 606 scrn_blank_time = *(int*)data; 607 return 0; 608 case CONS_SSAVER: /* set screen saver */ 609 { 610 register ssaver_t *sav = (ssaver_t *)data; 611 if (sav->num < 0 || sav->num >= NUM_SCRN_SAVERS) 612 return EIO; 613 SCRN_SAVER(0); 614 scrn_saver = sav->num; 615 scrn_blank_time = sav->time; 616 return 0; 617 } 618 case CONS_GSAVER: /* get screen saver info */ 619 { 620 register ssaver_t *sav = (ssaver_t *)data; 621 if (sav->num < 0) 622 sav->num = scrn_saver; 623 else if (sav->num >= NUM_SCRN_SAVERS) 624 return EIO; 625 sav->time = scrn_blank_time; 626 strcpy(sav->name, screen_savers[sav->num].name); 627 return 0; 628 } 629 case CONS_80x25TEXT: /* set 80x25 text mode */ 630 if (!crtc_vga) 631 return ENXIO; 632 scp->mode = TEXT80x25; 633 scp->ysize = 25; 634 free(scp->scr_buf, M_DEVBUF); 635 scp->scr_buf = (u_short *)malloc(scp->xsize*scp->ysize*2, 636 M_DEVBUF, M_NOWAIT); 637 if (scp != cur_console) 638 scp->crt_base = scp->scr_buf; 639 set_mode(scp); 640 clear_screen(scp); 641 change_winsize(tp, scp->xsize, scp->ysize); 642 return 0; 643 644 case CONS_80x50TEXT: /* set 80x50 text mode */ 645 if (!crtc_vga) 646 return ENXIO; 647 /* is there a 8x8 font loaded ? */ 648 if (fonts_loaded & FONT_8_LOADED) { 649 scp->mode = TEXT80x50; 650 scp->ysize = 50; 651 free(scp->scr_buf, M_DEVBUF); 652 scp->scr_buf = 653 (u_short *)malloc(scp->xsize * scp->ysize * 2, 654 M_DEVBUF, M_NOWAIT); 655 if (scp != cur_console) 656 scp->crt_base = scp->scr_buf; 657 set_mode(scp); 658 clear_screen(scp); 659 change_winsize(tp, scp->xsize, scp->ysize); 660 return 0; 661 } 662 else 663 return EINVAL; 664 665 case CONS_GETVERS: /* get version number */ 666 *(int*)data = 0x103; /* version 1.3 */ 667 return 0; 668 669 case CONS_GETINFO: /* get current (virtual) console info */ 670 { 671 vid_info_t *ptr = (vid_info_t*)data; 672 if (ptr->size == sizeof(struct vid_info)) { 673 ptr->m_num = get_scr_num(); 674 ptr->mv_col = scp->xpos; 675 ptr->mv_row = scp->ypos; 676 ptr->mv_csz = scp->xsize; 677 ptr->mv_rsz = scp->ysize; 678 ptr->mv_norm.fore = (scp->term.std_attr & 0x0f00)>>8; 679 ptr->mv_norm.back = (scp->term.std_attr & 0xf000)>>12; 680 ptr->mv_rev.fore = (scp->term.rev_attr & 0x0f00)>>8; 681 ptr->mv_rev.back = (scp->term.rev_attr & 0xf000)>>12; 682 ptr->mv_grfc.fore = 0; /* not supported */ 683 ptr->mv_grfc.back = 0; /* not supported */ 684 ptr->mv_ovscan = scp->border; 685 ptr->mk_keylock = scp->status & LOCK_KEY_MASK; 686 return 0; 687 } 688 return EINVAL; 689 } 690 691 case VT_SETMODE: /* set screen switcher mode */ 692 bcopy(data, &scp->smode, sizeof(struct vt_mode)); 693 if (scp->smode.mode == VT_PROCESS) { 694 scp->proc = p; 695 scp->pid = scp->proc->p_pid; 696 } 697 return 0; 698 699 case VT_GETMODE: /* get screen switcher mode */ 700 bcopy(&scp->smode, data, sizeof(struct vt_mode)); 701 return 0; 702 703 case VT_RELDISP: /* screen switcher ioctl */ 704 switch(*data) { 705 case VT_FALSE: /* user refuses to release screen, abort */ 706 if (scp == old_scp && (scp->status & SWITCH_WAIT_REL)) { 707 old_scp->status &= ~SWITCH_WAIT_REL; 708 switch_in_progress = 0; 709 return 0; 710 } 711 return EINVAL; 712 713 case VT_TRUE: /* user has released screen, go on */ 714 if (scp == old_scp && (scp->status & SWITCH_WAIT_REL)) { 715 scp->status &= ~SWITCH_WAIT_REL; 716 exchange_scr(); 717 if (new_scp->smode.mode == VT_PROCESS) { 718 new_scp->status |= SWITCH_WAIT_ACQ; 719 psignal(new_scp->proc, 720 new_scp->smode.acqsig); 721 } 722 else 723 switch_in_progress = 0; 724 return 0; 725 } 726 return EINVAL; 727 728 case VT_ACKACQ: /* acquire acknowledged, switch completed */ 729 if (scp == new_scp && (scp->status & SWITCH_WAIT_ACQ)) { 730 scp->status &= ~SWITCH_WAIT_ACQ; 731 switch_in_progress = 0; 732 return 0; 733 } 734 return EINVAL; 735 736 default: 737 return EINVAL; 738 } 739 /* NOT REACHED */ 740 741 case VT_OPENQRY: /* return free virtual console */ 742 for (i = 0; i < NCONS; i++) { 743 tp = VIRTUAL_TTY(i); 744 if (!(tp->t_state & TS_ISOPEN)) { 745 *data = i + 1; 746 return 0; 747 } 748 } 749 return EINVAL; 750 751 case VT_ACTIVATE: /* switch to screen *data */ 752 return switch_scr((*data) - 1); 753 754 case VT_WAITACTIVE: /* wait for switch to occur */ 755 if (*data > NCONS) 756 return EINVAL; 757 if (minor(dev) == (*data) - 1) 758 return 0; 759 if (*data == 0) { 760 if (scp == cur_console) 761 return 0; 762 while ((error=tsleep((caddr_t)&scp->smode, 763 PZERO|PCATCH, "waitvt", 0)) == ERESTART) ; 764 } 765 else 766 while ((error=tsleep( 767 (caddr_t)&console[*(data-1)].smode, 768 PZERO|PCATCH, "waitvt", 0)) == ERESTART) ; 769 return error; 770 771 case VT_GETACTIVE: 772 *data = get_scr_num()+1; 773 return 0; 774 775 case KDENABIO: /* allow io operations */ 776 fp = (struct trapframe *)p->p_md.md_regs; 777 fp->tf_eflags |= PSL_IOPL; 778 return 0; 779 780 case KDDISABIO: /* disallow io operations (default) */ 781 fp = (struct trapframe *)p->p_md.md_regs; 782 fp->tf_eflags &= ~PSL_IOPL; 783 return 0; 784 785 case KDSETMODE: /* set current mode of this (virtual) console */ 786 switch (*data) { 787 case KD_TEXT: /* switch to TEXT (known) mode */ 788 /* restore fonts & palette ! */ 789 if (crtc_vga) { 790 copy_font(LOAD, 0, 16, font_16); 791 copy_font(LOAD, 1, 8, font_8); 792 copy_font(LOAD, 2, 14, font_14); 793 load_palette(); 794 } 795 /* FALL THROUGH */ 796 797 case KD_TEXT1: /* switch to TEXT (known) mode */ 798 /* no restore fonts & palette */ 799 scp->status &= ~UNKNOWN_MODE; 800 set_mode(scp); 801 clear_screen(scp); 802 return 0; 803 804 case KD_GRAPHICS:/* switch to GRAPHICS (unknown) mode */ 805 scp->status |= UNKNOWN_MODE; 806 return 0; 807 default: 808 return EINVAL; 809 } 810 /* NOT REACHED */ 811 812 case KDGETMODE: /* get current mode of this (virtual) console */ 813 *data = (scp->status & UNKNOWN_MODE) ? KD_GRAPHICS : KD_TEXT; 814 return 0; 815 816 case KDSBORDER: /* set border color of this (virtual) console */ 817 if (!crtc_vga) 818 return ENXIO; 819 scp->border = *data; 820 if (scp == cur_console) 821 set_border(scp->border); 822 return 0; 823 824 case KDSKBSTATE: /* set keyboard state (locks) */ 825 if (*data >= 0 && *data <= LOCK_KEY_MASK) { 826 scp->status &= ~LOCK_KEY_MASK; 827 scp->status |= *data; 828 if (scp == cur_console) 829 update_leds(scp->status); 830 return 0; 831 } 832 return EINVAL; 833 834 case KDGKBSTATE: /* get keyboard state (locks) */ 835 *data = scp->status & LOCK_KEY_MASK; 836 return 0; 837 838 case KDSETRAD: /* set keyboard repeat & delay rates */ 839 if (*data & 0x80) 840 return EINVAL; 841 i = spltty(); 842 kbd_cmd(KB_SETRAD); 843 kbd_cmd(*data); 844 splx(i); 845 return 0; 846 847 case KDSKBMODE: /* set keyboard mode */ 848 switch (*data) { 849 case K_RAW: /* switch to RAW scancode mode */ 850 scp->status |= KBD_RAW_MODE; 851 return 0; 852 853 case K_XLATE: /* switch to XLT ascii mode */ 854 if (scp == cur_console && scp->status == KBD_RAW_MODE) 855 shfts = ctls = alts = agrs = metas = 0; 856 scp->status &= ~KBD_RAW_MODE; 857 return 0; 858 default: 859 return EINVAL; 860 } 861 /* NOT REACHED */ 862 863 case KDGKBMODE: /* get keyboard mode */ 864 *data = (scp->status & KBD_RAW_MODE) ? K_RAW : K_XLATE; 865 return 0; 866 867 case KDMKTONE: /* sound the bell */ 868 if (scp == cur_console) 869 sysbeep(scp->bell_pitch, scp->bell_duration); 870 return 0; 871 872 case KIOCSOUND: /* make tone (*data) hz */ 873 if (scp == cur_console) { 874 if (*(int*)data) { 875 int pitch = TIMER_FREQ/(*(int*)data); 876 /* set command for counter 2, 2 byte write */ 877 if (acquire_timer2(TIMER_16BIT|TIMER_SQWAVE)) { 878 return EBUSY; 879 } 880 /* set pitch */ 881 outb(TIMER_CNTR2, pitch); 882 outb(TIMER_CNTR2, (pitch>>8)); 883 /* enable counter 2 output to speaker */ 884 outb(IO_PPI, inb(IO_PPI) | 3); 885 } 886 else { 887 /* disable counter 2 output to speaker */ 888 outb(IO_PPI, inb(IO_PPI) & 0xFC); 889 release_timer2(); 890 } 891 } 892 return 0; 893 894 case KDGKBTYPE: /* get keyboard type */ 895 *data = 0; /* type not known (yet) */ 896 return 0; 897 898 case KDSETLED: /* set keyboard LED status */ 899 if (*data >= 0 && *data <= LED_MASK) { 900 scp->status &= ~LED_MASK; 901 scp->status |= *data; 902 if (scp == cur_console) 903 update_leds(scp->status); 904 return 0; 905 } 906 return EINVAL; 907 908 case KDGETLED: /* get keyboard LED status */ 909 *data = scp->status & LED_MASK; 910 return 0; 911 912 case GETFKEY: /* get functionkey string */ 913 if (*(u_short*)data < n_fkey_tab) { 914 fkeyarg_t *ptr = (fkeyarg_t*)data; 915 bcopy(&fkey_tab[ptr->keynum].str, 916 ptr->keydef, 917 fkey_tab[ptr->keynum].len); 918 ptr->flen = fkey_tab[ptr->keynum].len; 919 return 0; 920 } 921 else 922 return EINVAL; 923 924 case SETFKEY: /* set functionkey string */ 925 if (*(u_short*)data < n_fkey_tab) { 926 fkeyarg_t *ptr = (fkeyarg_t*)data; 927 bcopy(ptr->keydef, 928 &fkey_tab[ptr->keynum].str, 929 min(ptr->flen, MAXFK)); 930 fkey_tab[ptr->keynum].len = min(ptr->flen, MAXFK); 931 return 0; 932 } 933 else 934 return EINVAL; 935 936 case GIO_SCRNMAP: /* get output translation table */ 937 bcopy(&scr_map, data, sizeof(scr_map)); 938 return 0; 939 940 case PIO_SCRNMAP: /* set output translation table */ 941 bcopy(data, &scr_map, sizeof(scr_map)); 942 return 0; 943 944 case GIO_KEYMAP: /* get keyboard translation table */ 945 bcopy(&key_map, data, sizeof(key_map)); 946 return 0; 947 948 case PIO_KEYMAP: /* set keyboard translation table */ 949 bcopy(data, &key_map, sizeof(key_map)); 950 return 0; 951 952 case PIO_FONT8x8: /* set 8x8 dot font */ 953 if (!crtc_vga) 954 return ENXIO; 955 bcopy(data, font_8, 8*256); 956 fonts_loaded |= FONT_8_LOADED; 957 copy_font(LOAD, 1, 8, font_8); 958 return 0; 959 960 case GIO_FONT8x8: /* get 8x8 dot font */ 961 if (!crtc_vga) 962 return ENXIO; 963 if (fonts_loaded & FONT_8_LOADED) { 964 bcopy(font_8, data, 8*256); 965 return 0; 966 } 967 else 968 return ENXIO; 969 970 case PIO_FONT8x14: /* set 8x14 dot font */ 971 if (!crtc_vga) 972 return ENXIO; 973 bcopy(data, font_14, 14*256); 974 fonts_loaded |= FONT_14_LOADED; 975 copy_font(LOAD, 2, 14, font_14); 976 return 0; 977 978 case GIO_FONT8x14: /* get 8x14 dot font */ 979 if (!crtc_vga) 980 return ENXIO; 981 if (fonts_loaded & FONT_14_LOADED) { 982 bcopy(font_14, data, 14*256); 983 return 0; 984 } 985 else 986 return ENXIO; 987 988 case PIO_FONT8x16: /* set 8x16 dot font */ 989 if (!crtc_vga) 990 return ENXIO; 991 bcopy(data, font_16, 16*256); 992 fonts_loaded |= FONT_16_LOADED; 993 copy_font(LOAD, 0, 16, font_16); 994 return 0; 995 996 case GIO_FONT8x16: /* get 8x16 dot font */ 997 if (!crtc_vga) 998 return ENXIO; 999 if (fonts_loaded & FONT_16_LOADED) { 1000 bcopy(font_16, data, 16*256); 1001 return 0; 1002 } 1003 else 1004 return ENXIO; 1005 1006 case CONSOLE_X_MODE_ON: /* just to be compatible */ 1007 if (saved_console < 0) { 1008 saved_console = get_scr_num(); 1009 switch_scr(minor(dev)); 1010 fp = (struct trapframe *)p->p_md.md_regs; 1011 fp->tf_eflags |= PSL_IOPL; 1012 scp->status |= UNKNOWN_MODE; 1013 scp->status |= KBD_RAW_MODE; 1014 return 0; 1015 } 1016 return EAGAIN; 1017 1018 case CONSOLE_X_MODE_OFF:/* just to be compatible */ 1019 fp = (struct trapframe *)p->p_md.md_regs; 1020 fp->tf_eflags &= ~PSL_IOPL; 1021 if (crtc_vga) { 1022 copy_font(LOAD, 0, 16, font_16); 1023 copy_font(LOAD, 1, 8, font_8); 1024 copy_font(LOAD, 2, 14, font_14); 1025 load_palette(); 1026 } 1027 scp->status &= ~UNKNOWN_MODE; 1028 set_mode(scp); 1029 clear_screen(scp); 1030 scp->status &= ~KBD_RAW_MODE; 1031 switch_scr(saved_console); 1032 saved_console = -1; 1033 return 0; 1034 1035 case CONSOLE_X_BELL: /* more compatibility */ 1036 /* 1037 * if set, data is a pointer to a length 2 array of 1038 * integers. data[0] is the pitch in Hz and data[1] 1039 * is the duration in msec. 1040 */ 1041 if (data) 1042 sysbeep(TIMER_FREQ/((int*)data)[0], 1043 ((int*)data)[1]*hz/1000); 1044 else 1045 sysbeep(scp->bell_pitch, scp->bell_duration); 1046 return 0; 1047 1048 default: 1049 break; 1050 } 1051 1052 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 1053 if (error >= 0) 1054 return(error); 1055 error = ttioctl(tp, cmd, data, flag); 1056 if (error >= 0) 1057 return(error); 1058 return(ENOTTY); 1059 } 1060 1061 1062 void 1063 pcxint(dev_t dev) 1064 { 1065 struct tty *tp = get_tty_ptr(dev); 1066 1067 if (!tp) 1068 return; 1069 tp->t_state &= ~TS_BUSY; 1070 if (tp->t_line) 1071 (*linesw[tp->t_line].l_start)(tp); 1072 else 1073 pcstart(tp); 1074 } 1075 1076 1077 void 1078 pcstart(struct tty *tp) 1079 { 1080 struct clist *rbp; 1081 int i, s, len; 1082 u_char buf[PCBURST]; 1083 scr_stat *scp = get_scr_stat(tp->t_dev); 1084 1085 if (scp->status & SLKED) 1086 return; 1087 s = spltty(); 1088 if (!(tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))) { 1089 tp->t_state |= TS_BUSY; 1090 splx(s); 1091 rbp = &tp->t_outq; 1092 while (rbp->c_cc) { 1093 len = q_to_b(rbp, buf, PCBURST); 1094 for (i=0; i<len; i++) 1095 if (buf[i]) ansi_put(scp, buf[i]); 1096 } 1097 s = spltty(); 1098 tp->t_state &= ~TS_BUSY; 1099 #if 0 1100 if (rbp->c_cc) { 1101 tp->t_state |= TS_TIMEOUT; 1102 timeout((timeout_t)ttrstrt, (caddr_t)tp, 1); 1103 } 1104 #endif 1105 if (rbp->c_cc <= tp->t_lowat) { 1106 if (tp->t_state & TS_ASLEEP) { 1107 tp->t_state &= ~TS_ASLEEP; 1108 wakeup((caddr_t)rbp); 1109 } 1110 selwakeup(&tp->t_wsel); 1111 } 1112 } 1113 splx(s); 1114 } 1115 1116 1117 void 1118 pccnprobe(struct consdev *cp) 1119 { 1120 int maj; 1121 1122 /* locate the major number */ 1123 for (maj = 0; maj < nchrdev; maj++) 1124 if ((void*)cdevsw[maj].d_open == (void*)pcopen) 1125 break; 1126 1127 /* initialize required fields */ 1128 cp->cn_dev = makedev(maj, NCONS); 1129 cp->cn_pri = CN_INTERNAL; 1130 } 1131 1132 1133 void 1134 pccninit(struct consdev *cp) 1135 { 1136 scinit(); 1137 } 1138 1139 1140 void 1141 pccnputc(dev_t dev, char c) 1142 { 1143 if (c == '\n') 1144 scput('\r'); 1145 scput(c); 1146 if (cur_console == &console[0]) { 1147 int pos = cur_console->crtat - cur_console->crt_base; 1148 if (pos != cur_cursor_pos) { 1149 cur_cursor_pos = pos; 1150 outb(crtc_addr,14); 1151 outb(crtc_addr+1,pos >> 8); 1152 outb(crtc_addr,15); 1153 outb(crtc_addr+1,pos&0xff); 1154 } 1155 } 1156 } 1157 1158 1159 int 1160 pccngetc(dev_t dev) 1161 { 1162 int s = spltty(); /* block scintr while we poll */ 1163 int c = scgetc(0); 1164 splx(s); 1165 if (c == '\r') c = '\n'; 1166 return(c); 1167 } 1168 1169 1170 static void 1171 none_saver(int test) 1172 { 1173 } 1174 1175 1176 static void 1177 fade_saver(int test) 1178 { 1179 static int count = 0; 1180 int i; 1181 1182 if (test) { 1183 scrn_blanked = 1; 1184 if (count < 64) { 1185 outb(PIXMASK, 0xFF); /* no pixelmask */ 1186 outb(PALWADR, 0x00); 1187 outb(PALDATA, 0); 1188 outb(PALDATA, 0); 1189 outb(PALDATA, 0); 1190 for (i = 3; i < 768; i++) { 1191 if (palette[i] - count > 15) 1192 outb(PALDATA, palette[i]-count); 1193 else 1194 outb(PALDATA, 15); 1195 } 1196 inb(crtc_addr+6); /* reset flip/flop */ 1197 outb(ATC, 0x20); /* enable palette */ 1198 count++; 1199 } 1200 } 1201 else { 1202 count = scrn_blanked = 0; 1203 load_palette(); 1204 } 1205 } 1206 1207 1208 static void 1209 blank_saver(int test) 1210 { 1211 u_char val; 1212 if (test) { 1213 scrn_blanked = 1; 1214 outb(TSIDX, 0x01); val = inb(TSREG); 1215 outb(TSIDX, 0x01); outb(TSREG, val | 0x20); 1216 } 1217 else { 1218 scrn_blanked = 0; 1219 outb(TSIDX, 0x01); val = inb(TSREG); 1220 outb(TSIDX, 0x01); outb(TSREG, val & 0xDF); 1221 } 1222 } 1223 1224 #define NUM_STARS 50 1225 1226 /* 1227 * Alternate saver that got its inspiration from a well known utility 1228 * package for an inferior^H^H^H^H^H^Hfamous OS. 1229 */ 1230 static void 1231 star_saver(int test) 1232 { 1233 scr_stat *scp = cur_console; 1234 int cell, i; 1235 char pattern[] = {"...........++++*** "}; 1236 char colors[] = {FG_DARKGREY, FG_LIGHTGREY, 1237 FG_WHITE, FG_LIGHTCYAN}; 1238 static u_short stars[NUM_STARS][2]; 1239 1240 if (test) { 1241 if (!scrn_blanked) { 1242 bcopy(Crtat, scp->scr_buf, 1243 scp->xsize * scp->ysize * 2); 1244 fillw((FG_LIGHTGREY|BG_BLACK)<<8 | scr_map[0x20], Crtat, 1245 scp->xsize * scp->ysize); 1246 set_border(0); 1247 i = scp->ysize * scp->xsize + 5; 1248 outb(crtc_addr, 14); 1249 outb(crtc_addr+1, i >> 8); 1250 outb(crtc_addr, 15); 1251 outb(crtc_addr+1, i & 0xff); 1252 scrn_blanked = 1; 1253 for(i=0; i<NUM_STARS; i++) { 1254 stars[i][0] = 1255 random() % (scp->xsize*scp->ysize); 1256 stars[i][1] = 0; 1257 } 1258 } 1259 cell = random() % NUM_STARS; 1260 *((u_short*)(Crtat + stars[cell][0])) = 1261 scr_map[pattern[stars[cell][1]]] | 1262 colors[random()%sizeof(colors)] << 8; 1263 if ((stars[cell][1]+=(random()%4)) >= sizeof(pattern)-1) { 1264 stars[cell][0] = random() % (scp->xsize*scp->ysize); 1265 stars[cell][1] = 0; 1266 } 1267 } 1268 else { 1269 if (scrn_blanked) { 1270 bcopy(scp->scr_buf, Crtat, scp->xsize*scp->ysize*2); 1271 cur_cursor_pos = -1; 1272 set_border(scp->border); 1273 scrn_blanked = 0; 1274 } 1275 } 1276 } 1277 1278 1279 static void 1280 snake_saver(int test) 1281 { 1282 const char saves[] = {"FreeBSD-2.0"}; 1283 static u_char *savs[sizeof(saves)-1]; 1284 static int dirx, diry; 1285 int f; 1286 scr_stat *scp = cur_console; 1287 1288 if (test) { 1289 if (!scrn_blanked) { 1290 bcopy(Crtat, scp->scr_buf, 1291 scp->xsize * scp->ysize * 2); 1292 fillw((FG_LIGHTGREY|BG_BLACK)<<8 | scr_map[0x20], 1293 Crtat, scp->xsize * scp->ysize); 1294 set_border(0); 1295 dirx = (scp->xpos ? 1 : -1); 1296 diry = (scp->ypos ? 1297 scp->xsize : -scp->xsize); 1298 for (f=0; f< sizeof(saves)-1; f++) 1299 savs[f] = (u_char *)Crtat + 2 * 1300 (scp->xpos+scp->ypos*scp->xsize); 1301 *(savs[0]) = scr_map[*saves]; 1302 f = scp->ysize * scp->xsize + 5; 1303 outb(crtc_addr, 14); 1304 outb(crtc_addr+1, f >> 8); 1305 outb(crtc_addr, 15); 1306 outb(crtc_addr+1, f & 0xff); 1307 scrn_blanked = 1; 1308 } 1309 if (scrn_blanked++ < 4) 1310 return; 1311 scrn_blanked = 1; 1312 *(savs[sizeof(saves)-2]) = scr_map[0x20]; 1313 for (f=sizeof(saves)-2; f > 0; f--) 1314 savs[f] = savs[f-1]; 1315 f = (savs[0] - (u_char *)Crtat) / 2; 1316 if ((f % scp->xsize) == 0 || 1317 (f % scp->xsize) == scp->xsize - 1 || 1318 (random() % 50) == 0) 1319 dirx = -dirx; 1320 if ((f / scp->xsize) == 0 || 1321 (f / scp->xsize) == scp->ysize - 1 || 1322 (random() % 20) == 0) 1323 diry = -diry; 1324 savs[0] += 2*dirx + 2*diry; 1325 for (f=sizeof(saves)-2; f>=0; f--) 1326 *(savs[f]) = scr_map[saves[f]]; 1327 } 1328 else { 1329 if (scrn_blanked) { 1330 bcopy(scp->scr_buf, Crtat, 1331 scp->xsize * scp->ysize * 2); 1332 cur_cursor_pos = -1; 1333 set_border(scp->border); 1334 scrn_blanked = 0; 1335 } 1336 } 1337 } 1338 1339 1340 static void 1341 cursor_shape(int start, int end) 1342 { 1343 outb(crtc_addr, 10); 1344 outb(crtc_addr+1, start & 0xFF); 1345 outb(crtc_addr, 11); 1346 outb(crtc_addr+1, end & 0xFF); 1347 } 1348 1349 1350 #if !defined(FAT_CURSOR) 1351 static void 1352 get_cursor_shape(int *start, int *end) 1353 { 1354 outb(crtc_addr, 10); 1355 *start = inb(crtc_addr+1) & 0x1F; 1356 outb(crtc_addr, 11); 1357 *end = inb(crtc_addr+1) & 0x1F; 1358 } 1359 #endif 1360 1361 1362 static void 1363 cursor_pos(int force) 1364 { 1365 int pos; 1366 1367 if (cur_console->status & UNKNOWN_MODE) 1368 return; 1369 if (scrn_blank_time && (time.tv_sec > scrn_time_stamp+scrn_blank_time)) 1370 SCRN_SAVER(1); 1371 pos = cur_console->crtat - cur_console->crt_base; 1372 if (force || (!scrn_blanked && pos != cur_cursor_pos)) { 1373 cur_cursor_pos = pos; 1374 outb(crtc_addr, 14); 1375 outb(crtc_addr+1, pos>>8); 1376 outb(crtc_addr, 15); 1377 outb(crtc_addr+1, pos&0xff); 1378 } 1379 timeout((timeout_t)cursor_pos, 0, hz/20); 1380 } 1381 1382 1383 static void 1384 clear_screen(scr_stat *scp) 1385 { 1386 move_crsr(scp, 0, 0); 1387 fillw(scp->term.cur_attr | scr_map[0x20], scp->crt_base, 1388 scp->xsize * scp->ysize); 1389 } 1390 1391 1392 static int 1393 switch_scr(u_int next_scr) 1394 { 1395 if (switch_in_progress && 1396 (cur_console->proc != pfind(cur_console->pid))) 1397 switch_in_progress = 0; 1398 1399 if (next_scr >= NCONS || switch_in_progress) { 1400 sysbeep(BELL_PITCH, BELL_DURATION); 1401 return EINVAL; 1402 } 1403 1404 /* is the wanted virtual console open ? */ 1405 if (next_scr) { 1406 struct tty *tp = VIRTUAL_TTY(next_scr); 1407 if (!(tp->t_state & TS_ISOPEN)) { 1408 sysbeep(BELL_PITCH, BELL_DURATION); 1409 return EINVAL; 1410 } 1411 } 1412 if (in_putc) { /* delay switch if in putc */ 1413 delayed_next_scr = next_scr+1; 1414 return 0; 1415 } 1416 switch_in_progress = 1; 1417 old_scp = cur_console; 1418 new_scp = &console[next_scr]; 1419 wakeup((caddr_t)&new_scp->smode); 1420 if (new_scp == old_scp) { 1421 switch_in_progress = 0; 1422 return 0; 1423 } 1424 1425 /* has controlling process died? */ 1426 if (old_scp->proc && (old_scp->proc != pfind(old_scp->pid))) 1427 old_scp->smode.mode = VT_AUTO; 1428 if (new_scp->proc && (new_scp->proc != pfind(new_scp->pid))) 1429 new_scp->smode.mode = VT_AUTO; 1430 1431 /* check the modes and switch approbiatly */ 1432 if (old_scp->smode.mode == VT_PROCESS) { 1433 old_scp->status |= SWITCH_WAIT_REL; 1434 psignal(old_scp->proc, old_scp->smode.relsig); 1435 } 1436 else { 1437 exchange_scr(); 1438 if (new_scp->smode.mode == VT_PROCESS) { 1439 new_scp->status |= SWITCH_WAIT_ACQ; 1440 psignal(new_scp->proc, new_scp->smode.acqsig); 1441 } 1442 else 1443 switch_in_progress = 0; 1444 } 1445 return 0; 1446 } 1447 1448 1449 static void 1450 exchange_scr(void) 1451 { 1452 struct tty *tp; 1453 1454 bcopy(Crtat, old_scp->scr_buf, old_scp->xsize * old_scp->ysize * 2); 1455 old_scp->crt_base = old_scp->scr_buf; 1456 move_crsr(old_scp, old_scp->xpos, old_scp->ypos); 1457 cur_console = new_scp; 1458 set_mode(new_scp); 1459 new_scp->crt_base = Crtat; 1460 move_crsr(new_scp, new_scp->xpos, new_scp->ypos); 1461 bcopy(new_scp->scr_buf, Crtat, new_scp->xsize * new_scp->ysize * 2); 1462 update_leds(new_scp->status); 1463 if ((old_scp->status & UNKNOWN_MODE) && crtc_vga) { 1464 copy_font(LOAD, 0, 16, font_16); 1465 copy_font(LOAD, 1, 8, font_8); 1466 copy_font(LOAD, 2, 14, font_14); 1467 load_palette(); 1468 } 1469 if (old_scp->status & KBD_RAW_MODE || new_scp->status & KBD_RAW_MODE) 1470 shfts = ctls = alts = agrs = metas = 0; 1471 delayed_next_scr = 0; 1472 } 1473 1474 1475 static void 1476 move_crsr(scr_stat *scp, int x, int y) 1477 { 1478 if (x < 0 || y < 0 || x >= scp->xsize || y >= scp->ysize) 1479 return; 1480 scp->xpos = x; 1481 scp->ypos = y; 1482 scp->crtat = scp->crt_base + scp->ypos * scp->xsize + scp->xpos; 1483 } 1484 1485 1486 static void 1487 move_up(u_short *s, u_short *d, u_int len) 1488 { 1489 s += len; 1490 d += len; 1491 while (len-- > 0) 1492 *--d = *--s; 1493 } 1494 1495 1496 static void 1497 move_down(u_short *s, u_short *d, u_int len) 1498 { 1499 while (len-- > 0) 1500 *d++ = *s++; 1501 } 1502 1503 1504 static void 1505 scan_esc(scr_stat *scp, u_char c) 1506 { 1507 static u_char ansi_col[16] = 1508 {0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15}; 1509 int i, n; 1510 u_short *src, *dst, count; 1511 1512 if (scp->term.esc == 1) { 1513 switch (c) { 1514 1515 case '[': /* Start ESC [ sequence */ 1516 scp->term.esc = 2; 1517 scp->term.last_param = -1; 1518 for (i = scp->term.num_param; i < MAX_ESC_PAR; i++) 1519 scp->term.param[i] = 1; 1520 scp->term.num_param = 0; 1521 return; 1522 1523 case 'M': /* Move cursor up 1 line, scroll if at top */ 1524 if (scp->ypos > 0) 1525 move_crsr(scp, scp->xpos, scp->ypos - 1); 1526 else { 1527 move_up(scp->crt_base, 1528 scp->crt_base + scp->xsize, 1529 (scp->ysize - 1) * scp->xsize); 1530 fillw(scp->term.cur_attr | scr_map[0x20], 1531 scp->crt_base, scp->xsize); 1532 } 1533 break; 1534 #if notyet 1535 case 'Q': 1536 scp->term.esc = 4; 1537 break; 1538 #endif 1539 case 'c': /* Clear screen & home */ 1540 clear_screen(scp); 1541 break; 1542 } 1543 } 1544 else if (scp->term.esc == 2) { 1545 if (c >= '0' && c <= '9') { 1546 if (scp->term.num_param < MAX_ESC_PAR) { 1547 if (scp->term.last_param != scp->term.num_param) { 1548 scp->term.last_param = scp->term.num_param; 1549 scp->term.param[scp->term.num_param] = 0; 1550 } 1551 else 1552 scp->term.param[scp->term.num_param] *= 10; 1553 scp->term.param[scp->term.num_param] += c - '0'; 1554 return; 1555 } 1556 } 1557 scp->term.num_param = scp->term.last_param + 1; 1558 switch (c) { 1559 1560 case ';': 1561 if (scp->term.num_param < MAX_ESC_PAR) 1562 return; 1563 break; 1564 1565 case '=': 1566 scp->term.esc = 3; 1567 scp->term.last_param = -1; 1568 for (i = scp->term.num_param; i < MAX_ESC_PAR; i++) 1569 scp->term.param[i] = 1; 1570 scp->term.num_param = 0; 1571 return; 1572 1573 case 'A': /* up n rows */ 1574 n = scp->term.param[0]; if (n < 1) n = 1; 1575 move_crsr(scp, scp->xpos, scp->ypos - n); 1576 break; 1577 1578 case 'B': /* down n rows */ 1579 n = scp->term.param[0]; if (n < 1) n = 1; 1580 move_crsr(scp, scp->xpos, scp->ypos + n); 1581 break; 1582 1583 case 'C': /* right n columns */ 1584 n = scp->term.param[0]; if (n < 1) n = 1; 1585 move_crsr(scp, scp->xpos + n, scp->ypos); 1586 break; 1587 1588 case 'D': /* left n columns */ 1589 n = scp->term.param[0]; if (n < 1) n = 1; 1590 move_crsr(scp, scp->xpos - n, scp->ypos); 1591 break; 1592 1593 case 'E': /* cursor to start of line n lines down */ 1594 n = scp->term.param[0]; if (n < 1) n = 1; 1595 move_crsr(scp, 0, scp->ypos + n); 1596 break; 1597 1598 case 'F': /* cursor to start of line n lines up */ 1599 n = scp->term.param[0]; if (n < 1) n = 1; 1600 move_crsr(scp, 0, scp->ypos - n); 1601 break; 1602 1603 case 'f': /* System V consoles .. */ 1604 case 'H': /* Cursor move */ 1605 if (scp->term.num_param == 0) 1606 move_crsr(scp, 0, 0); 1607 else if (scp->term.num_param == 2) 1608 move_crsr(scp, scp->term.param[1] - 1, 1609 scp->term.param[0] - 1); 1610 break; 1611 1612 case 'J': /* Clear all or part of display */ 1613 if (scp->term.num_param == 0) 1614 n = 0; 1615 else 1616 n = scp->term.param[0]; 1617 switch (n) { 1618 case 0: /* clear form cursor to end of display */ 1619 fillw(scp->term.cur_attr | scr_map[0x20], 1620 scp->crtat, scp->crt_base + 1621 scp->xsize * scp->ysize - 1622 scp->crtat); 1623 break; 1624 case 1: /* clear from beginning of display to cursor */ 1625 fillw(scp->term.cur_attr | scr_map[0x20], 1626 scp->crt_base, 1627 scp->crtat - scp->crt_base); 1628 break; 1629 case 2: /* clear entire display */ 1630 clear_screen(scp); 1631 break; 1632 } 1633 break; 1634 1635 case 'K': /* Clear all or part of line */ 1636 if (scp->term.num_param == 0) 1637 n = 0; 1638 else 1639 n = scp->term.param[0]; 1640 switch (n) { 1641 case 0: /* clear form cursor to end of line */ 1642 fillw(scp->term.cur_attr | scr_map[0x20], 1643 scp->crtat, scp->xsize - scp->xpos); 1644 break; 1645 case 1: /* clear from beginning of line to cursor */ 1646 fillw(scp->term.cur_attr|scr_map[0x20], 1647 scp->crtat - (scp->xsize - scp->xpos), 1648 (scp->xsize - scp->xpos) + 1); 1649 break; 1650 case 2: /* clear entire line */ 1651 fillw(scp->term.cur_attr|scr_map[0x20], 1652 scp->crtat - (scp->xsize - scp->xpos), 1653 scp->xsize); 1654 break; 1655 } 1656 break; 1657 1658 case 'L': /* Insert n lines */ 1659 n = scp->term.param[0]; if (n < 1) n = 1; 1660 if (n > scp->ysize - scp->ypos) 1661 n = scp->ysize - scp->ypos; 1662 src = scp->crt_base + scp->ypos * scp->xsize; 1663 dst = src + n * scp->xsize; 1664 count = scp->ysize - (scp->ypos + n); 1665 move_up(src, dst, count * scp->xsize); 1666 fillw(scp->term.cur_attr | scr_map[0x20], src, 1667 n * scp->xsize); 1668 break; 1669 1670 case 'M': /* Delete n lines */ 1671 n = scp->term.param[0]; if (n < 1) n = 1; 1672 if (n > scp->ysize - scp->ypos) 1673 n = scp->ysize - scp->ypos; 1674 dst = scp->crt_base + scp->ypos * scp->xsize; 1675 src = dst + n * scp->xsize; 1676 count = scp->ysize - (scp->ypos + n); 1677 move_down(src, dst, count * scp->xsize); 1678 src = dst + count * scp->xsize; 1679 fillw(scp->term.cur_attr | scr_map[0x20], src, 1680 n * scp->xsize); 1681 break; 1682 1683 case 'P': /* Delete n chars */ 1684 n = scp->term.param[0]; if (n < 1) n = 1; 1685 if (n > scp->xsize - scp->xpos) 1686 n = scp->xsize - scp->xpos; 1687 dst = scp->crtat; 1688 src = dst + n; 1689 count = scp->xsize - (scp->xpos + n); 1690 move_down(src, dst, count); 1691 src = dst + count; 1692 fillw(scp->term.cur_attr | scr_map[0x20], src, n); 1693 break; 1694 1695 case '@': /* Insert n chars */ 1696 n = scp->term.param[0]; if (n < 1) n = 1; 1697 if (n > scp->xsize - scp->xpos) 1698 n = scp->xsize - scp->xpos; 1699 src = scp->crtat; 1700 dst = src + n; 1701 count = scp->xsize - (scp->xpos + n); 1702 move_up(src, dst, count); 1703 fillw(scp->term.cur_attr | scr_map[0x20], src, n); 1704 break; 1705 1706 case 'S': /* scroll up n lines */ 1707 n = scp->term.param[0]; if (n < 1) n = 1; 1708 if (n > scp->ypos) 1709 n = scp->ypos; 1710 bcopy(scp->crt_base + (scp->xsize * n), 1711 scp->crt_base, 1712 scp->xsize * (scp->ysize - n) * 1713 sizeof(u_short)); 1714 fillw(scp->term.cur_attr | scr_map[0x20], 1715 scp->crt_base + scp->xsize * 1716 (scp->ysize - 1), 1717 scp->xsize); 1718 break; 1719 1720 case 'T': /* scroll down n lines */ 1721 n = scp->term.param[0]; if (n < 1) n = 1; 1722 if (n > scp->ysize - scp->ypos) 1723 n = scp->ysize - scp->ypos; 1724 bcopy(scp->crt_base, 1725 scp->crt_base + (scp->xsize * n), 1726 scp->xsize * (scp->ysize - n) * 1727 sizeof(u_short)); 1728 fillw(scp->term.cur_attr | scr_map[0x20], 1729 scp->crt_base, scp->xsize); 1730 break; 1731 1732 case 'X': /* delete n characters in line */ 1733 n = scp->term.param[0]; if (n < 1) n = 1; 1734 if (n > scp->xsize - scp->xpos) 1735 n = scp->xsize - scp->xpos; 1736 fillw(scp->term.cur_attr | scr_map[0x20], 1737 scp->crt_base + scp->xpos + 1738 ((scp->xsize*scp->ypos) * sizeof(u_short)), n); 1739 break; 1740 1741 case 'Z': /* move n tabs backwards */ 1742 n = scp->term.param[0]; if (n < 1) n = 1; 1743 if ((i = scp->xpos & 0xf8) == scp->xpos) 1744 i -= 8*n; 1745 else 1746 i -= 8*(n-1); 1747 if (i < 0) 1748 i = 0; 1749 move_crsr(scp, i, scp->ypos); 1750 break; 1751 1752 case '`': /* move cursor to column n */ 1753 n = scp->term.param[0]; if (n < 1) n = 1; 1754 move_crsr(scp, n, scp->ypos); 1755 break; 1756 1757 case 'a': /* move cursor n columns to the right */ 1758 n = scp->term.param[0]; if (n < 1) n = 1; 1759 move_crsr(scp, scp->xpos + n, scp->ypos); 1760 break; 1761 1762 case 'd': /* move cursor to row n */ 1763 n = scp->term.param[0]; if (n < 1) n = 1; 1764 move_crsr(scp, scp->xpos, n); 1765 break; 1766 1767 case 'e': /* move cursor n rows down */ 1768 n = scp->term.param[0]; if (n < 1) n = 1; 1769 move_crsr(scp, scp->xpos, scp->ypos + n); 1770 break; 1771 1772 case 'm': /* change attribute */ 1773 if (scp->term.num_param == 0) { 1774 scp->term.cur_attr = scp->term.std_attr; 1775 break; 1776 } 1777 for (i = 0; i < scp->term.num_param; i++) { 1778 switch (n = scp->term.param[i]) { 1779 case 0: /* back to normal */ 1780 scp->term.cur_attr = scp->term.std_attr; 1781 break; 1782 case 1: /* highlight (bold) */ 1783 scp->term.cur_attr &= 0xFF00; 1784 scp->term.cur_attr |= 0x0800; 1785 break; 1786 case 4: /* highlight (underline) */ 1787 scp->term.cur_attr &= 0xFF00; 1788 scp->term.cur_attr |= 0x0800; 1789 break; 1790 case 5: /* blink */ 1791 scp->term.cur_attr &= 0xFF00; 1792 scp->term.cur_attr |= 0x8000; 1793 break; 1794 case 7: /* reverse video */ 1795 scp->term.cur_attr = scp->term.rev_attr; 1796 break; 1797 case 30: case 31: /* set fg color */ 1798 case 32: case 33: case 34: 1799 case 35: case 36: case 37: 1800 scp->term.cur_attr = 1801 (scp->term.cur_attr & 0xF8FF) 1802 | (ansi_col[(n-30) & 7] << 8); 1803 break; 1804 case 40: case 41: /* set bg color */ 1805 case 42: case 43: case 44: 1806 case 45: case 46: case 47: 1807 scp->term.cur_attr = 1808 (scp->term.cur_attr & 0x8FFF) 1809 | (ansi_col[(n-40) & 7] << 12); 1810 break; 1811 } 1812 } 1813 break; 1814 1815 case 'x': 1816 if (scp->term.num_param == 0) 1817 n = 0; 1818 else 1819 n = scp->term.param[0]; 1820 switch (n) { 1821 case 0: /* reset attributes */ 1822 scp->term.cur_attr = scp->term.std_attr = 1823 current_default->std_attr; 1824 scp->term.rev_attr = current_default->rev_attr; 1825 break; 1826 case 1: /* set ansi background */ 1827 scp->term.cur_attr = scp->term.std_attr = 1828 (scp->term.std_attr & 0x0F00) | 1829 (ansi_col[(scp->term.param[1])&0x0F]<<12); 1830 break; 1831 case 2: /* set ansi foreground */ 1832 scp->term.cur_attr = scp->term.std_attr = 1833 (scp->term.std_attr & 0xF000) | 1834 (ansi_col[(scp->term.param[1])&0x0F]<<8); 1835 break; 1836 case 3: /* set ansi attribute directly */ 1837 scp->term.cur_attr = scp->term.std_attr = 1838 (scp->term.param[1]&0xFF)<<8; 1839 break; 1840 case 5: /* set ansi reverse video background */ 1841 scp->term.rev_attr = 1842 (scp->term.rev_attr & 0x0F00) | 1843 (ansi_col[(scp->term.param[1])&0x0F]<<12); 1844 break; 1845 case 6: /* set ansi reverse video foreground */ 1846 scp->term.rev_attr = 1847 (scp->term.rev_attr & 0xF000) | 1848 (ansi_col[(scp->term.param[1])&0x0F]<<8); 1849 break; 1850 case 7: /* set ansi reverse video directly */ 1851 scp->term.rev_attr = (scp->term.param[1]&0xFF)<<8; 1852 break; 1853 } 1854 break; 1855 1856 case 'z': /* switch to (virtual) console n */ 1857 if (scp->term.num_param == 1) 1858 switch_scr(scp->term.param[0]); 1859 break; 1860 } 1861 } 1862 else if (scp->term.esc == 3) { 1863 if (c >= '0' && c <= '9') { 1864 if (scp->term.num_param < MAX_ESC_PAR) { 1865 if (scp->term.last_param != scp->term.num_param) { 1866 scp->term.last_param = scp->term.num_param; 1867 scp->term.param[scp->term.num_param] = 0; 1868 } 1869 else 1870 scp->term.param[scp->term.num_param] *= 10; 1871 scp->term.param[scp->term.num_param] += c - '0'; 1872 return; 1873 } 1874 } 1875 scp->term.num_param = scp->term.last_param + 1; 1876 switch (c) { 1877 1878 case ';': 1879 if (scp->term.num_param < MAX_ESC_PAR) 1880 return; 1881 break; 1882 1883 case 'A': /* set display border color */ 1884 if (scp->term.num_param == 1) 1885 scp->border=scp->term.param[0] & 0xff; 1886 if (scp == cur_console) 1887 set_border(scp->border); 1888 break; 1889 1890 case 'B': /* set bell pitch and duration */ 1891 if (scp->term.num_param == 2) { 1892 scp->bell_pitch = scp->term.param[0]; 1893 scp->bell_duration = scp->term.param[1]*10; 1894 } 1895 break; 1896 1897 case 'C': /* set cursor shape (start & end line) */ 1898 if (scp->term.num_param == 2) { 1899 scp->cursor_start = scp->term.param[0] & 0x1F; 1900 scp->cursor_end = scp->term.param[1] & 0x1F; 1901 if (scp == cur_console) 1902 cursor_shape(scp->cursor_start, 1903 scp->cursor_end); 1904 } 1905 break; 1906 1907 case 'F': /* set ansi foreground */ 1908 if (scp->term.num_param == 1) 1909 scp->term.cur_attr = scp->term.std_attr = 1910 (scp->term.std_attr & 0xF000) 1911 | ((scp->term.param[0] & 0x0F) << 8); 1912 break; 1913 1914 case 'G': /* set ansi background */ 1915 if (scp->term.num_param == 1) 1916 scp->term.cur_attr = scp->term.std_attr = 1917 (scp->term.std_attr & 0x0F00) 1918 | ((scp->term.param[0] & 0x0F) << 12); 1919 break; 1920 1921 case 'H': /* set ansi reverse video foreground */ 1922 if (scp->term.num_param == 1) 1923 scp->term.rev_attr = 1924 (scp->term.rev_attr & 0xF000) 1925 | ((scp->term.param[0] & 0x0F) << 8); 1926 break; 1927 1928 case 'I': /* set ansi reverse video background */ 1929 if (scp->term.num_param == 1) 1930 scp->term.rev_attr = 1931 (scp->term.rev_attr & 0x0F00) 1932 | ((scp->term.param[0] & 0x0F) << 12); 1933 break; 1934 } 1935 } 1936 scp->term.esc = 0; 1937 } 1938 1939 1940 static void 1941 ansi_put(scr_stat *scp, u_char c) 1942 { 1943 if (scp->status & UNKNOWN_MODE) 1944 return; 1945 1946 /* make screensaver happy */ 1947 if (scp == cur_console) { 1948 scrn_time_stamp = time.tv_sec; 1949 if (scrn_blanked) 1950 SCRN_SAVER(0); 1951 } 1952 in_putc++; 1953 if (scp->term.esc) 1954 scan_esc(scp, c); 1955 else switch(c) { 1956 case 0x1B: /* start escape sequence */ 1957 scp->term.esc = 1; 1958 scp->term.num_param = 0; 1959 break; 1960 case 0x07: 1961 if (scp == cur_console) 1962 sysbeep(scp->bell_pitch, scp->bell_duration); 1963 break; 1964 case '\t': /* non-destructive tab */ 1965 scp->crtat += (8 - scp->xpos % 8); 1966 scp->xpos += (8 - scp->xpos % 8); 1967 break; 1968 case '\b': /* non-destructive backspace */ 1969 if (scp->crtat > scp->crt_base) { 1970 scp->crtat--; 1971 if (scp->xpos > 0) 1972 scp->xpos--; 1973 else { 1974 scp->xpos += scp->xsize - 1; 1975 scp->ypos--; 1976 } 1977 } 1978 break; 1979 case '\r': /* return to pos 0 */ 1980 move_crsr(scp, 0, scp->ypos); 1981 break; 1982 case '\n': /* newline, same pos */ 1983 scp->crtat += scp->xsize; 1984 scp->ypos++; 1985 break; 1986 case '\f': /* form feed, clears screen */ 1987 clear_screen(scp); 1988 break; 1989 default: 1990 /* Print only printables */ 1991 *scp->crtat = (scp->term.cur_attr | scr_map[c]); 1992 scp->crtat++; 1993 if (++scp->xpos >= scp->xsize) { 1994 scp->xpos = 0; 1995 scp->ypos++; 1996 } 1997 break; 1998 } 1999 if (scp->crtat >= scp->crt_base + scp->ysize * scp->xsize) { 2000 bcopy(scp->crt_base + scp->xsize, scp->crt_base, 2001 scp->xsize * (scp->ysize - 1) * sizeof(u_short)); 2002 fillw(scp->term.cur_attr | scr_map[0x20], 2003 scp->crt_base + scp->xsize * (scp->ysize - 1), 2004 scp->xsize); 2005 scp->crtat -= scp->xsize; 2006 scp->ypos--; 2007 } 2008 in_putc--; 2009 if (delayed_next_scr) 2010 switch_scr(delayed_next_scr - 1); 2011 } 2012 2013 2014 static void 2015 scinit(void) 2016 { 2017 u_short volatile *cp = Crtat + (CGA_BUF-MONO_BUF)/sizeof(u_short), was; 2018 unsigned cursorat; 2019 int i; 2020 2021 /* 2022 * catch that once in a blue moon occurence when scinit is called 2023 * TWICE, adding the CGA_BUF offset again -> poooff 2024 */ 2025 if (crtat != 0) 2026 return; 2027 /* 2028 * Crtat initialized to point to MONO buffer, if not present change 2029 * to CGA_BUF offset. ONLY ADD the difference since locore.s adds 2030 * in the remapped offset at the "right" time 2031 */ 2032 was = *cp; 2033 *cp = (u_short) 0xA55A; 2034 if (*cp != 0xA55A) { 2035 crtc_addr = MONO_BASE; 2036 } else { 2037 *cp = was; 2038 crtc_addr = COLOR_BASE; 2039 Crtat = Crtat + (CGA_BUF-MONO_BUF)/sizeof(u_short); 2040 } 2041 2042 /* Extract cursor location */ 2043 outb(crtc_addr,14); 2044 cursorat = inb(crtc_addr+1)<<8 ; 2045 outb(crtc_addr,15); 2046 cursorat |= inb(crtc_addr+1); 2047 crtat = Crtat + cursorat; 2048 2049 /* is this a VGA or higher ? */ 2050 outb(crtc_addr, 7); 2051 if (inb(crtc_addr) == 7) 2052 crtc_vga = 1; 2053 2054 current_default = &user_default; 2055 console[0].crtat = crtat; 2056 console[0].crt_base = Crtat; 2057 console[0].term.esc = 0; 2058 console[0].term.std_attr = current_default->std_attr; 2059 console[0].term.rev_attr = current_default->rev_attr; 2060 console[0].term.cur_attr = current_default->std_attr; 2061 console[0].xpos = cursorat % COL; 2062 console[0].ypos = cursorat / COL; 2063 console[0].border = BG_BLACK;; 2064 console[0].xsize = COL; 2065 console[0].ysize = ROW; 2066 console[0].status = NLKED; 2067 console[0].pid = 0; 2068 console[0].proc = NULL; 2069 console[0].smode.mode = VT_AUTO; 2070 console[0].bell_pitch = BELL_PITCH; 2071 console[0].bell_duration = BELL_DURATION; 2072 kernel_console.esc = 0; 2073 kernel_console.std_attr = kernel_default.std_attr; 2074 kernel_console.rev_attr = kernel_default.rev_attr; 2075 kernel_console.cur_attr = kernel_default.std_attr; 2076 /* initialize mapscrn array to a one to one map */ 2077 for (i=0; i<sizeof(scr_map); i++) 2078 scr_map[i] = i; 2079 clear_screen(&console[0]); 2080 } 2081 2082 2083 static void 2084 scput(u_char c) 2085 { 2086 scr_stat *scp = &console[0]; 2087 term_stat save; 2088 2089 if (crtat == 0) 2090 scinit(); 2091 if( in_putc == 0) { 2092 ++in_putc; 2093 save = scp->term; 2094 scp->term = kernel_console; 2095 current_default = &kernel_default; 2096 ansi_put(scp, c); 2097 kernel_console = scp->term; 2098 current_default = &user_default; 2099 scp->term = save; 2100 --in_putc; 2101 } else { 2102 if( console_buffer_count < CONSOLE_BUFSIZE) 2103 console_buffer[console_buffer_count++] = c; 2104 } 2105 } 2106 2107 2108 static u_char 2109 *get_fstr(u_int c, u_int *len) 2110 { 2111 u_int i; 2112 2113 if (!(c & FKEY)) 2114 return(NULL); 2115 i = (c & 0xFF) - F_FN; 2116 if (i > n_fkey_tab) 2117 return(NULL); 2118 *len = fkey_tab[i].len; 2119 return(fkey_tab[i].str); 2120 } 2121 2122 2123 static void 2124 update_leds(int which) 2125 { 2126 int s; 2127 static u_char xlate_leds[8] = { 0, 4, 2, 6, 1, 5, 3, 7 }; 2128 2129 /* replace CAPS led with ALTGR led for ALTGR keyboards */ 2130 if (key_map.n_keys > ALTGR_OFFSET) { 2131 if (which & ALKED) 2132 which |= CLKED; 2133 else 2134 which &= ~CLKED; 2135 } 2136 s = spltty(); 2137 kbd_cmd(KB_SETLEDS); 2138 kbd_cmd(xlate_leds[which & LED_MASK]); 2139 splx(s); 2140 } 2141 2142 2143 /* 2144 * scgetc(noblock) - get character from keyboard. 2145 * If noblock = 0 wait until a key is pressed. 2146 * Else return NOKEY. 2147 */ 2148 u_int 2149 scgetc(int noblock) 2150 { 2151 u_char scancode, keycode; 2152 u_int state, action; 2153 struct key_t *key; 2154 static u_char esc_flag = 0, compose = 0; 2155 static u_int chr = 0; 2156 2157 next_code: 2158 kbd_wait(); 2159 /* First see if there is something in the keyboard port */ 2160 if (inb(KB_STAT) & KB_BUF_FULL) 2161 scancode = inb(KB_DATA); 2162 else if (noblock) 2163 return(NOKEY); 2164 else 2165 goto next_code; 2166 2167 if (cur_console->status & KBD_RAW_MODE) 2168 return scancode; 2169 #if ASYNCH 2170 if (scancode == KB_ACK || scancode == KB_RESEND) { 2171 kbd_reply = scancode; 2172 if (noblock) 2173 return(NOKEY); 2174 goto next_code; 2175 } 2176 #endif 2177 keycode = scancode & 0x7F; 2178 switch (esc_flag) { 2179 case 0x00: /* normal scancode */ 2180 switch(scancode) { 2181 case 0xB8: /* left alt (compose key) */ 2182 if (compose) { 2183 compose = 0; 2184 if (chr > 255) { 2185 sysbeep(BELL_PITCH, BELL_DURATION); 2186 chr = 0; 2187 } 2188 } 2189 break; 2190 case 0x38: 2191 if (!compose) { 2192 compose = 1; 2193 chr = 0; 2194 } 2195 break; 2196 case 0xE0: 2197 case 0xE1: 2198 esc_flag = scancode; 2199 goto next_code; 2200 } 2201 break; 2202 case 0xE0: /* 0xE0 prefix */ 2203 esc_flag = 0; 2204 switch (keycode) { 2205 case 0x1C: /* right enter key */ 2206 keycode = 0x59; 2207 break; 2208 case 0x1D: /* right ctrl key */ 2209 keycode = 0x5A; 2210 break; 2211 case 0x35: /* keypad divide key */ 2212 keycode = 0x5B; 2213 break; 2214 case 0x37: /* print scrn key */ 2215 keycode = 0x5C; 2216 break; 2217 case 0x38: /* right alt key (alt gr) */ 2218 keycode = 0x5D; 2219 break; 2220 case 0x47: /* grey home key */ 2221 keycode = 0x5E; 2222 break; 2223 case 0x48: /* grey up arrow key */ 2224 keycode = 0x5F; 2225 break; 2226 case 0x49: /* grey page up key */ 2227 keycode = 0x60; 2228 break; 2229 case 0x4B: /* grey left arrow key */ 2230 keycode = 0x61; 2231 break; 2232 case 0x4D: /* grey right arrow key */ 2233 keycode = 0x62; 2234 break; 2235 case 0x4F: /* grey end key */ 2236 keycode = 0x63; 2237 break; 2238 case 0x50: /* grey down arrow key */ 2239 keycode = 0x64; 2240 break; 2241 case 0x51: /* grey page down key */ 2242 keycode = 0x65; 2243 break; 2244 case 0x52: /* grey insert key */ 2245 keycode = 0x66; 2246 break; 2247 case 0x53: /* grey delete key */ 2248 keycode = 0x67; 2249 break; 2250 default: /* ignore everything else */ 2251 goto next_code; 2252 } 2253 break; 2254 case 0xE1: /* 0xE1 prefix */ 2255 esc_flag = 0; 2256 if (keycode == 0x1D) 2257 esc_flag = 0x1D; 2258 goto next_code; 2259 /* NOT REACHED */ 2260 case 0x1D: /* pause / break */ 2261 esc_flag = 0; 2262 if (keycode != 0x45) 2263 goto next_code; 2264 keycode = 0x68; 2265 break; 2266 } 2267 2268 if (compose) { 2269 switch (scancode) { 2270 /* key pressed process it */ 2271 case 0x47: case 0x48: case 0x49: /* keypad 7,8,9 */ 2272 chr = (scancode - 0x40) + chr*10; 2273 goto next_code; 2274 case 0x4B: case 0x4C: case 0x4D: /* keypad 4,5,6 */ 2275 chr = (scancode - 0x47) + chr*10; 2276 goto next_code; 2277 case 0x4F: case 0x50: case 0x51: /* keypad 1,2,3 */ 2278 chr = (scancode - 0x4E) + chr*10; 2279 goto next_code; 2280 case 0x52: /* keypad 0 */ 2281 chr *= 10; 2282 goto next_code; 2283 2284 /* key release, no interest here */ 2285 case 0xC7: case 0xC8: case 0xC9: /* keypad 7,8,9 */ 2286 case 0xCB: case 0xCC: case 0xCD: /* keypad 4,5,6 */ 2287 case 0xCF: case 0xD0: case 0xD1: /* keypad 1,2,3 */ 2288 case 0xD2: /* keypad 0 */ 2289 goto next_code; 2290 2291 case 0x38: /* left alt key */ 2292 break; 2293 default: 2294 if (chr) { 2295 compose = chr = 0; 2296 sysbeep(BELL_PITCH, BELL_DURATION); 2297 goto next_code; 2298 } 2299 break; 2300 } 2301 } 2302 2303 state = (shfts ? 1 : 0 ) | (2 * (ctls ? 1 : 0)) | (4 * (alts ? 1 : 0)); 2304 if ((!agrs && (cur_console->status & ALKED)) 2305 || (agrs && !(cur_console->status & ALKED))) 2306 keycode += ALTGR_OFFSET; 2307 key = &key_map.key[keycode]; 2308 if ( ((key->flgs & FLAG_LOCK_C) && (cur_console->status & CLKED)) 2309 || ((key->flgs & FLAG_LOCK_N) && (cur_console->status & NLKED)) ) 2310 state ^= 1; 2311 2312 /* Check for make/break */ 2313 action = key->map[state]; 2314 if (scancode & 0x80) { /* key released */ 2315 if (key->spcl & 0x80) { 2316 switch (action) { 2317 case LSH: 2318 shfts &= ~1; 2319 break; 2320 case RSH: 2321 shfts &= ~2; 2322 break; 2323 case LCTR: 2324 ctls &= ~1; 2325 break; 2326 case RCTR: 2327 ctls &= ~2; 2328 break; 2329 case LALT: 2330 alts &= ~1; 2331 break; 2332 case RALT: 2333 alts &= ~2; 2334 break; 2335 case NLK: 2336 nlkcnt = 0; 2337 break; 2338 case CLK: 2339 clkcnt = 0; 2340 break; 2341 case SLK: 2342 slkcnt = 0; 2343 break; 2344 case ASH: 2345 agrs = 0; 2346 break; 2347 case ALK: 2348 alkcnt = 0; 2349 break; 2350 case META: 2351 metas = 0; 2352 break; 2353 } 2354 } 2355 if (chr && !compose) { 2356 action = chr; 2357 chr = 0; 2358 return(action); 2359 } 2360 } else { 2361 /* key pressed */ 2362 if (key->spcl & (0x80>>state)) { 2363 switch (action) { 2364 /* LOCKING KEYS */ 2365 case NLK: 2366 if (!nlkcnt) { 2367 nlkcnt++; 2368 if (cur_console->status & NLKED) 2369 cur_console->status &= ~NLKED; 2370 else 2371 cur_console->status |= NLKED; 2372 update_leds(cur_console->status); 2373 } 2374 break; 2375 case CLK: 2376 if (!clkcnt) { 2377 clkcnt++; 2378 if (cur_console->status & CLKED) 2379 cur_console->status &= ~CLKED; 2380 else 2381 cur_console->status |= CLKED; 2382 update_leds(cur_console->status); 2383 } 2384 break; 2385 case SLK: 2386 if (!slkcnt) { 2387 slkcnt++; 2388 if (cur_console->status & SLKED) { 2389 cur_console->status &= ~SLKED; 2390 pcstart(VIRTUAL_TTY(get_scr_num())); 2391 } 2392 else 2393 cur_console->status |= SLKED; 2394 update_leds(cur_console->status); 2395 } 2396 break; 2397 case ALK: 2398 if (!alkcnt) { 2399 alkcnt++; 2400 if (cur_console->status & ALKED) 2401 cur_console->status &= ~ALKED; 2402 else 2403 cur_console->status |= ALKED; 2404 update_leds(cur_console->status); 2405 } 2406 break; 2407 2408 /* NON-LOCKING KEYS */ 2409 case NOP: 2410 break; 2411 case RBT: 2412 shutdown_nice(); 2413 break; 2414 case DBG: 2415 #if DDB > 0 /* try to switch to console 0 */ 2416 if (cur_console->smode.mode == VT_AUTO && 2417 console[0].smode.mode == VT_AUTO) 2418 switch_scr(0); 2419 Debugger("manual escape to debugger"); 2420 return(NOKEY); 2421 #else 2422 printf("No debugger in kernel\n"); 2423 #endif 2424 break; 2425 case LSH: 2426 shfts |= 1; 2427 break; 2428 case RSH: 2429 shfts |= 2; 2430 break; 2431 case LCTR: 2432 ctls |= 1; 2433 break; 2434 case RCTR: 2435 ctls |= 2; 2436 break; 2437 case LALT: 2438 alts |= 1; 2439 break; 2440 case RALT: 2441 alts |= 2; 2442 break; 2443 case ASH: 2444 agrs = 1; 2445 break; 2446 case META: 2447 metas = 1; 2448 break; 2449 case NEXT: 2450 switch_scr((get_scr_num()+1)%NCONS); 2451 break; 2452 default: 2453 if (action >= F_SCR && action <= L_SCR) { 2454 switch_scr(action - F_SCR); 2455 break; 2456 } 2457 if (action >= F_FN && action <= L_FN) 2458 action |= FKEY; 2459 return(action); 2460 } 2461 } 2462 else { 2463 if (metas) 2464 action |= MKEY; 2465 return(action); 2466 } 2467 } 2468 goto next_code; 2469 } 2470 2471 2472 int 2473 getchar(void) 2474 { 2475 u_char thechar; 2476 int s; 2477 2478 polling = 1; 2479 s = splhigh(); 2480 scput('>'); 2481 thechar = (u_char) scgetc(0); 2482 polling = 0; 2483 splx(s); 2484 switch (thechar) { 2485 default: 2486 if (thechar >= scr_map[0x20]) 2487 scput(thechar); 2488 return(thechar); 2489 case cr: 2490 case lf: 2491 scput(cr); scput(lf); 2492 return(lf); 2493 case bs: 2494 case del: 2495 scput(bs); scput(scr_map[0x20]); scput(bs); 2496 return(thechar); 2497 case cntld: 2498 scput('^'); scput('D'); scput('\r'); scput('\n'); 2499 return(0); 2500 } 2501 } 2502 2503 2504 u_int 2505 sgetc(int noblock) 2506 { 2507 return (scgetc(noblock) & 0xff); 2508 } 2509 2510 2511 int 2512 pcmmap(dev_t dev, int offset, int nprot) 2513 { 2514 if (offset > 0x20000) 2515 return EINVAL; 2516 return i386_btop((VIDEOMEM + offset)); 2517 } 2518 2519 2520 static void 2521 kbd_wait(void) 2522 { 2523 int i = 1000; 2524 2525 while (i--) { 2526 if ((inb(KB_STAT) & KB_READY) == 0) 2527 break; 2528 DELAY (10); 2529 } 2530 } 2531 2532 2533 static void 2534 kbd_cmd(u_char command) 2535 { 2536 int retry = 5; 2537 do { 2538 int i = 100000; 2539 2540 kbd_wait(); 2541 #if ASYNCH 2542 kbd_reply = 0; 2543 outb(KB_DATA, command); 2544 while (i--) { 2545 if (kbd_reply == KB_ACK) 2546 return; 2547 if (kbd_reply == KB_RESEND) 2548 break; 2549 } 2550 #else 2551 outb(KB_DATA, command); 2552 while (i--) { 2553 if (inb(KB_STAT) & KB_BUF_FULL) { 2554 int val; 2555 DELAY(10); 2556 val = inb(KB_DATA); 2557 if (val == KB_ACK) 2558 return; 2559 if (val == KB_RESEND) 2560 break; 2561 } 2562 } 2563 #endif 2564 } while (retry--); 2565 } 2566 2567 2568 static void 2569 set_mode(scr_stat *scp) 2570 { 2571 u_char byte; 2572 int s; 2573 2574 if (scp != cur_console) 2575 return; 2576 2577 /* (re)activate cursor */ 2578 untimeout((timeout_t)cursor_pos, 0); 2579 cursor_pos(1); 2580 2581 /* change cursor type if set */ 2582 if (scp->cursor_start != -1 && scp->cursor_end != -1) 2583 cursor_shape(scp->cursor_start, scp->cursor_end); 2584 2585 /* mode change only on VGA's */ 2586 if (!crtc_vga) 2587 return; 2588 2589 /* setup video hardware for the given mode */ 2590 s = splhigh(); 2591 switch(scp->mode) { 2592 case TEXT80x25: 2593 outb(crtc_addr, 9); byte = inb(crtc_addr+1); 2594 outb(crtc_addr, 9); outb(crtc_addr+1, byte | 0x0F); 2595 outb(TSIDX, 0x03); outb(TSREG, 0x00); /* select font 0 */ 2596 break; 2597 case TEXT80x50: 2598 outb(crtc_addr, 9); byte = inb(crtc_addr+1); 2599 outb(crtc_addr, 9); outb(crtc_addr+1, (byte & 0xF0) | 0x07); 2600 outb(TSIDX, 0x03); outb(TSREG, 0x05); /* select font 1 */ 2601 break; 2602 default: 2603 break; 2604 } 2605 splx(s); 2606 2607 /* set border color for this (virtual) console */ 2608 set_border(scp->border); 2609 return; 2610 } 2611 2612 2613 static void 2614 set_border(int color) 2615 { 2616 inb(crtc_addr+6); /* reset flip-flop */ 2617 outb(ATC, 0x11); outb(ATC, color); 2618 inb(crtc_addr+6); /* reset flip-flop */ 2619 outb(ATC, 0x20); /* enable Palette */ 2620 } 2621 2622 2623 static void 2624 copy_font(int direction, int segment, int size, char* font) 2625 { 2626 int ch, line, s; 2627 u_char val; 2628 2629 outb(TSIDX, 0x01); val = inb(TSREG); /* blank screen */ 2630 outb(TSIDX, 0x01); outb(TSREG, val | 0x20); 2631 2632 /* setup vga for loading fonts (graphics plane mode) */ 2633 s = splhigh(); 2634 inb(crtc_addr+6); /* reset flip/flop */ 2635 outb(ATC, 0x30); outb(ATC, 0x01); 2636 outb(TSIDX, 0x02); outb(TSREG, 0x04); 2637 outb(TSIDX, 0x04); outb(TSREG, 0x06); 2638 outb(GDCIDX, 0x04); outb(GDCREG, 0x02); 2639 outb(GDCIDX, 0x05); outb(GDCREG, 0x00); 2640 outb(GDCIDX, 0x06); outb(GDCREG, 0x05); /* addr = a0000, 64kb */ 2641 splx(s); 2642 for (ch=0; ch < 256; ch++) 2643 for (line=0; line < size; line++) 2644 if (direction) 2645 *((char *)atdevbase+(segment*0x4000)+(ch*32)+line) = 2646 font[(ch*size)+line]; 2647 else 2648 font[(ch*size)+line] = 2649 *((char *)atdevbase+(segment*0x4000)+(ch*32)+line); 2650 2651 /* setup vga for text mode again */ 2652 s = splhigh(); 2653 inb(crtc_addr+6); /* reset flip/flop */ 2654 outb(ATC, 0x30); outb(ATC, 0x0C); 2655 outb(TSIDX, 0x02); outb(TSREG, 0x03); 2656 outb(TSIDX, 0x04); outb(TSREG, 0x02); 2657 outb(GDCIDX, 0x04); outb(GDCREG, 0x00); 2658 outb(GDCIDX, 0x05); outb(GDCREG, 0x10); 2659 if (crtc_addr == MONO_BASE) { 2660 outb(GDCIDX, 0x06); outb(GDCREG, 0x0A); /* addr = b0000, 32kb */ 2661 } 2662 else { 2663 outb(GDCIDX, 0x06); outb(GDCREG, 0x0E); /* addr = b8000, 32kb */ 2664 } 2665 splx(s); 2666 outb(TSIDX, 0x01); val = inb(TSREG); /* unblank screen */ 2667 outb(TSIDX, 0x01); outb(TSREG, val & 0xDF); 2668 } 2669 2670 2671 static void 2672 load_palette(void) 2673 { 2674 int i; 2675 2676 outb(PIXMASK, 0xFF); /* no pixelmask */ 2677 outb(PALWADR, 0x00); 2678 for (i=0x00; i<0x300; i++) 2679 outb(PALDATA, palette[i]); 2680 inb(crtc_addr+6); /* reset flip/flop */ 2681 outb(ATC, 0x20); /* enable palette */ 2682 } 2683 2684 2685 static void 2686 save_palette(void) 2687 { 2688 int i; 2689 2690 outb(PALRADR, 0x00); 2691 for (i=0x00; i<0x300; i++) 2692 palette[i] = inb(PALDATA); 2693 inb(crtc_addr+6); /* reset flip/flop */ 2694 } 2695 2696 2697 static void 2698 change_winsize(struct tty *tp, int x, int y) 2699 { 2700 if (tp->t_winsize.ws_col != x || tp->t_winsize.ws_row != y) { 2701 tp->t_winsize.ws_col = x; 2702 tp->t_winsize.ws_row = y; 2703 pgsignal(tp->t_pgrp, SIGWINCH, 1); 2704 } 2705 } 2706 2707 #endif /* NSC */ 2708