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