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