syscons.c revision 12078
1/*- 2 * Copyright (c) 1992-1995 S�ren Schmidt 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer 10 * in this position and unchanged. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software withough specific prior written permission 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * $Id: syscons.c,v 1.127 1995/10/28 16:58:04 markm Exp $ 29 */ 30 31#include "sc.h" 32#include "apm.h" 33#if NSC > 0 34#include <sys/param.h> 35#include <sys/systm.h> 36#include <sys/conf.h> 37#include <sys/ioctl.h> 38#include <sys/proc.h> 39#include <sys/user.h> 40#include <sys/tty.h> 41#include <sys/uio.h> 42#include <sys/callout.h> 43#include <sys/kernel.h> 44#include <sys/syslog.h> 45#include <sys/errno.h> 46#include <sys/malloc.h> 47#include <sys/devconf.h> 48 49#include <machine/clock.h> 50#include <machine/cons.h> 51#include <machine/console.h> 52#include <machine/psl.h> 53#include <machine/frame.h> 54#include <machine/pc/display.h> 55#include <machine/apm_bios.h> 56#include <machine/random.h> 57 58#include <i386/isa/isa.h> 59#include <i386/isa/isa_device.h> 60#include <i386/isa/timerreg.h> 61#include <i386/isa/kbdtables.h> 62#include <i386/isa/syscons.h> 63 64#if !defined(MAXCONS) 65#define MAXCONS 16 66#endif 67 68/* this may break on older VGA's but is usefull on real 32 bit systems */ 69#define bcopyw bcopy 70 71static default_attr user_default = { 72 (FG_LIGHTGREY | BG_BLACK) << 8, 73 (FG_BLACK | BG_LIGHTGREY) << 8 74}; 75 76static default_attr kernel_default = { 77 (FG_WHITE | BG_BLACK) << 8, 78 (FG_BLACK | BG_LIGHTGREY) << 8 79}; 80 81static scr_stat main_console; 82static scr_stat *console[MAXCONS]; 83 scr_stat *cur_console; 84static scr_stat *new_scp, *old_scp; 85static term_stat kernel_console; 86static default_attr *current_default; 87static char init_done = FALSE; 88static int configuration = 0; 89static char switch_in_progress = FALSE; 90static char blink_in_progress = FALSE; 91static char write_in_progress = FALSE; 92 u_int crtc_addr = MONO_BASE; 93static char crtc_vga = FALSE; 94static u_char shfts = 0, ctls = 0, alts = 0, agrs = 0, metas = 0; 95static u_char nlkcnt = 0, clkcnt = 0, slkcnt = 0, alkcnt = 0; 96static char *font_8 = NULL, *font_14 = NULL, *font_16 = NULL; 97static int fonts_loaded = 0; 98 char palette[3*256]; 99static const u_int n_fkey_tab = sizeof(fkey_tab) / sizeof(*fkey_tab); 100static int delayed_next_scr = FALSE; 101static long scrn_blank_time = 0; /* screen saver timeout value */ 102 int scrn_blanked = FALSE; /* screen saver active flag */ 103static int scrn_saver = 0; /* screen saver routine */ 104static long scrn_time_stamp; 105 u_char scr_map[256]; 106static char *video_mode_ptr = NULL; 107#if ASYNCH 108static u_char kbd_reply = 0; 109#endif 110 111static u_short mouse_and_mask[16] = { 112 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00, 0xff80, 113 0xfe00, 0x1e00, 0x1f00, 0x0f00, 0x0f00, 0x0000, 0x0000, 0x0000 114}; 115static u_short mouse_or_mask[16] = { 116 0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7c00, 0x7e00, 0x6800, 117 0x0c00, 0x0c00, 0x0600, 0x0600, 0x0000, 0x0000, 0x0000, 0x0000 118}; 119 120extern void none_saver(int blank); 121void none_saver(int blank) { } 122void (*current_saver) __P((int blank)) = none_saver; 123 124/* OS specific stuff */ 125#ifdef not_yet_done 126#define VIRTUAL_TTY(x) (sccons[x] = ttymalloc(sccons[x])) 127struct CONSOLE_TTY (sccons[MAXCONS] = ttymalloc(sccons[MAXCONS])) 128struct tty *sccons[MAXCONS+1]; 129#else 130#define VIRTUAL_TTY(x) &sccons[x] 131#define CONSOLE_TTY &sccons[MAXCONS] 132struct tty sccons[MAXCONS+1]; 133int nsccons = MAXCONS+1; 134#endif 135#define MONO_BUF pa_to_va(0xB0000) 136#define CGA_BUF pa_to_va(0xB8000) 137u_short *Crtat; 138 139#define WRAPHIST(scp, pointer, offset)\ 140 ((scp->history) + ((((pointer) - (scp->history)) + (scp->history_size)\ 141 + (offset)) % (scp->history_size))) 142 143struct isa_driver scdriver = { 144 scprobe, scattach, "sc", 1 145}; 146 147static d_open_t scopen; 148static d_close_t scclose; 149static d_rdwr_t scread; 150static d_rdwr_t scwrite; 151static d_ioctl_t scioctl; 152static d_ttycv_t scdevtotty; 153static d_mmap_t scmmap; 154 155static struct cdevsw scdevsw = { 156 scopen, scclose, scread, scwrite, 157 scioctl, nullstop, noreset, scdevtotty, 158 ttselect, scmmap, nostrategy, 159}; 160 161int 162scprobe(struct isa_device *dev) 163{ 164 int i, retries = 5; 165 unsigned char val; 166 167 /* Enable interrupts and keyboard controller */ 168 kbd_wait(); 169 outb(KB_STAT, KB_WRITE); 170 kbd_wait(); 171 outb(KB_DATA, KB_MODE); 172 173 /* flush any noise in the buffer */ 174 while (inb(KB_STAT) & KB_BUF_FULL) { 175 DELAY(10); 176 (void) inb(KB_DATA); 177 } 178 179 /* Reset keyboard hardware */ 180 while (retries--) { 181 kbd_wait(); 182 outb(KB_DATA, KB_RESET); 183 for (i=0; i<100000; i++) { 184 DELAY(10); 185 val = inb(KB_DATA); 186 if (val == KB_ACK || val == KB_ECHO) 187 goto gotres; 188 if (val == KB_RESEND) 189 break; 190 } 191 } 192gotres: 193 if (!retries) 194 printf("scprobe: keyboard won't accept RESET command\n"); 195 else { 196gotack: 197 DELAY(10); 198 while ((inb(KB_STAT) & KB_BUF_FULL) == 0) DELAY(10); 199 DELAY(10); 200 val = inb(KB_DATA); 201 if (val == KB_ACK) 202 goto gotack; 203 if (val != KB_RESET_DONE) 204 printf("scprobe: keyboard RESET failed %02x\n", val); 205 } 206#ifdef XT_KEYBOARD 207 kbd_wait(); 208 outb(KB_DATA, 0xF0); 209 kbd_wait(); 210 outb(KB_DATA, 1); 211 kbd_wait(); 212#endif /* XT_KEYBOARD */ 213 return (IO_KBDSIZE); 214} 215 216static struct kern_devconf kdc_sc[NSC] = { 217 0, 0, 0, /* filled in by dev_attach */ 218 "sc", 0, { MDDT_ISA, 0, "tty" }, 219 isa_generic_externalize, 0, 0, ISA_EXTERNALLEN, 220 &kdc_isa0, /* parent */ 221 0, /* parentdata */ 222 DC_BUSY, /* the console is almost always busy */ 223 "Graphics console", 224 DC_CLS_DISPLAY /* class */ 225}; 226 227static inline void 228sc_registerdev(struct isa_device *id) 229{ 230 if(id->id_unit) 231 kdc_sc[id->id_unit] = kdc_sc[0]; 232 kdc_sc[id->id_unit].kdc_unit = id->id_unit; 233 kdc_sc[id->id_unit].kdc_isa = id; 234 dev_attach(&kdc_sc[id->id_unit]); 235} 236 237#if NAPM > 0 238static int 239scresume(void *dummy) 240{ 241 shfts = 0; 242 ctls = 0; 243 alts = 0; 244 agrs = 0; 245 metas = 0; 246 return 0; 247} 248#endif 249 250int 251scattach(struct isa_device *dev) 252{ 253 scr_stat *scp; 254 255 scinit(); 256 configuration = dev->id_flags; 257 258 scp = console[0]; 259 260 if (crtc_vga) { 261 font_8 = (char *)malloc(8*256, M_DEVBUF, M_NOWAIT); 262 font_14 = (char *)malloc(14*256, M_DEVBUF, M_NOWAIT); 263 font_16 = (char *)malloc(16*256, M_DEVBUF, M_NOWAIT); 264 copy_font(SAVE, FONT_16, font_16); 265 fonts_loaded = FONT_16; 266 scp->font = FONT_16; 267 save_palette(); 268 } 269 270 scp->scr_buf = (u_short *)malloc(scp->xsize*scp->ysize*sizeof(u_short), 271 M_DEVBUF, M_NOWAIT); 272 /* copy screen to buffer */ 273 bcopyw(Crtat, scp->scr_buf, scp->xsize * scp->ysize * sizeof(u_short)); 274 scp->cursor_pos = scp->scr_buf + scp->xpos + scp->ypos * scp->xsize; 275 scp->mouse_pos = scp->scr_buf; 276 277 /* initialize history buffer & pointers */ 278 scp->history_head = scp->history_pos = scp->history = 279 (u_short *)malloc(scp->history_size*sizeof(u_short), 280 M_DEVBUF, M_NOWAIT); 281 bzero(scp->history_head, scp->history_size*sizeof(u_short)); 282 283 /* initialize cursor stuff */ 284 draw_cursor(scp, TRUE); 285 if (crtc_vga && (configuration & CHAR_CURSOR)) 286 set_destructive_cursor(scp, TRUE); 287 288 /* get screen update going */ 289 scrn_timer(); 290 291 update_leds(scp->status); 292 sc_registerdev(dev); 293 294 printf("sc%d: ", dev->id_unit); 295 if (crtc_vga) 296 if (crtc_addr == MONO_BASE) 297 printf("VGA mono"); 298 else 299 printf("VGA color"); 300 else 301 if (crtc_addr == MONO_BASE) 302 printf("MDA/hercules"); 303 else 304 printf("CGA/EGA"); 305 printf(" <%d virtual consoles, flags=0x%x>\n", MAXCONS, configuration); 306 307#if NAPM > 0 308 scp->r_hook.ah_fun = scresume; 309 scp->r_hook.ah_arg = NULL; 310 scp->r_hook.ah_name = "system keyboard"; 311 scp->r_hook.ah_order = APM_MID_ORDER; 312 apm_hook_establish(APM_HOOK_RESUME , &scp->r_hook); 313#endif 314 315 register_cdev("sc", &scdevsw); 316 317 return 0; 318} 319 320struct tty 321*scdevtotty(dev_t dev) 322{ 323 int unit = minor(dev); 324 325 if (unit > MAXCONS || unit < 0) 326 return(NULL); 327 if (unit == MAXCONS) 328 return CONSOLE_TTY; 329 return VIRTUAL_TTY(unit); 330} 331 332static scr_stat 333*get_scr_stat(dev_t dev) 334{ 335 int unit = minor(dev); 336 337 if (unit > MAXCONS || unit < 0) 338 return(NULL); 339 if (unit == MAXCONS) 340 return console[0]; 341 return console[unit]; 342} 343 344static int 345get_scr_num() 346{ 347 int i = 0; 348 349 while ((i < MAXCONS) && (cur_console != console[i])) 350 i++; 351 return i < MAXCONS ? i : 0; 352} 353 354int 355scopen(dev_t dev, int flag, int mode, struct proc *p) 356{ 357 struct tty *tp = scdevtotty(dev); 358 359 if (!tp) 360 return(ENXIO); 361 362 tp->t_oproc = scstart; 363 tp->t_param = scparam; 364 tp->t_dev = dev; 365 if (!(tp->t_state & TS_ISOPEN)) { 366 ttychars(tp); 367 tp->t_iflag = TTYDEF_IFLAG; 368 tp->t_oflag = TTYDEF_OFLAG; 369 tp->t_cflag = TTYDEF_CFLAG; 370 tp->t_lflag = TTYDEF_LFLAG; 371 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 372 scparam(tp, &tp->t_termios); 373 ttsetwater(tp); 374 (*linesw[tp->t_line].l_modem)(tp, 1); 375 } 376 else 377 if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) 378 return(EBUSY); 379 if (!console[minor(dev)]) 380 console[minor(dev)] = alloc_scp(); 381 return((*linesw[tp->t_line].l_open)(dev, tp)); 382} 383 384int 385scclose(dev_t dev, int flag, int mode, struct proc *p) 386{ 387 struct tty *tp = scdevtotty(dev); 388 struct scr_stat *scp; 389 390 if (!tp) 391 return(ENXIO); 392 if (minor(dev) < MAXCONS) { 393 scp = get_scr_stat(tp->t_dev); 394 if (scp->status & SWITCH_WAIT_ACQ) 395 wakeup((caddr_t)&scp->smode); 396#if not_yet_done 397 if (scp == &main_console) { 398 scp->pid = 0; 399 scp->proc = NULL; 400 scp->smode.mode = VT_AUTO; 401 } 402 else { 403 free(scp->scr_buf, M_DEVBUF); 404 free(scp->history, M_DEVBUF); 405 free(scp, M_DEVBUF); 406 console[minor(dev)] = NULL; 407 } 408#else 409 scp->pid = 0; 410 scp->proc = NULL; 411 scp->smode.mode = VT_AUTO; 412#endif 413 } 414 (*linesw[tp->t_line].l_close)(tp, flag); 415 ttyclose(tp); 416 return(0); 417} 418 419int 420scread(dev_t dev, struct uio *uio, int flag) 421{ 422 struct tty *tp = scdevtotty(dev); 423 424 if (!tp) 425 return(ENXIO); 426 return((*linesw[tp->t_line].l_read)(tp, uio, flag)); 427} 428 429int 430scwrite(dev_t dev, struct uio *uio, int flag) 431{ 432 struct tty *tp = scdevtotty(dev); 433 434 if (!tp) 435 return(ENXIO); 436 return((*linesw[tp->t_line].l_write)(tp, uio, flag)); 437} 438 439void 440scintr(int unit) 441{ 442 static struct tty *cur_tty; 443 int c, len; 444 u_char *cp; 445 446 /* make screensaver happy */ 447 scrn_time_stamp = time.tv_sec; 448 if (scrn_blanked) { 449 (*current_saver)(FALSE); 450 cur_console->start = 0; 451 cur_console->end = cur_console->xsize * cur_console->ysize; 452 } 453 454 c = scgetc(1); 455 456 cur_tty = VIRTUAL_TTY(get_scr_num()); 457 if (!(cur_tty->t_state & TS_ISOPEN)) 458 if (!((cur_tty = CONSOLE_TTY)->t_state & TS_ISOPEN)) 459 return; 460 461 switch (c & 0xff00) { 462 case 0x0000: /* normal key */ 463 (*linesw[cur_tty->t_line].l_rint)(c & 0xFF, cur_tty); 464 break; 465 case NOKEY: /* nothing there */ 466 break; 467 case FKEY: /* function key, return string */ 468 if (cp = get_fstr((u_int)c, (u_int *)&len)) { 469 while (len-- > 0) 470 (*linesw[cur_tty->t_line].l_rint)(*cp++ & 0xFF, cur_tty); 471 } 472 break; 473 case MKEY: /* meta is active, prepend ESC */ 474 (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty); 475 (*linesw[cur_tty->t_line].l_rint)(c & 0xFF, cur_tty); 476 break; 477 case BKEY: /* backtab fixed sequence (esc [ Z) */ 478 (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty); 479 (*linesw[cur_tty->t_line].l_rint)('[', cur_tty); 480 (*linesw[cur_tty->t_line].l_rint)('Z', cur_tty); 481 break; 482 } 483} 484 485int 486scparam(struct tty *tp, struct termios *t) 487{ 488 tp->t_ispeed = t->c_ispeed; 489 tp->t_ospeed = t->c_ospeed; 490 tp->t_cflag = t->c_cflag; 491 return 0; 492} 493 494int 495scioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) 496{ 497 int i, error; 498 struct tty *tp; 499 struct trapframe *fp; 500 scr_stat *scp; 501 502 tp = scdevtotty(dev); 503 if (!tp) 504 return ENXIO; 505 scp = get_scr_stat(tp->t_dev); 506 507 switch (cmd) { /* process console hardware related ioctl's */ 508 509 case GIO_ATTR: /* get current attributes */ 510 *(int*)data = scp->term.cur_attr; 511 return 0; 512 513 case GIO_COLOR: /* is this a color console ? */ 514 if (crtc_addr == COLOR_BASE) 515 *(int*)data = 1; 516 else 517 *(int*)data = 0; 518 return 0; 519 520 case CONS_CURRENT: /* get current adapter type */ 521 if (crtc_vga) 522 *(int*)data = KD_VGA; 523 else 524 if (crtc_addr == MONO_BASE) 525 *(int*)data = KD_MONO; 526 else 527 *(int*)data = KD_CGA; 528 return 0; 529 530 case CONS_GET: /* get current video mode */ 531 *(int*)data = scp->mode; 532 return 0; 533 534 case CONS_BLANKTIME: /* set screen saver timeout (0 = no saver) */ 535 scrn_blank_time = *(int*)data; 536 return 0; 537 538 case CONS_CURSORTYPE: /* set cursor type blink/noblink */ 539 if ((*(int*)data) & 0x01) 540 configuration |= BLINK_CURSOR; 541 else 542 configuration &= ~BLINK_CURSOR; 543 if ((*(int*)data) & 0x02) { 544 configuration |= CHAR_CURSOR; 545 set_destructive_cursor(scp, TRUE); 546 } else 547 configuration &= ~CHAR_CURSOR; 548 return 0; 549 550 case CONS_BELLTYPE: /* set bell type sound/visual */ 551 if (*data) 552 configuration |= VISUAL_BELL; 553 else 554 configuration &= ~VISUAL_BELL; 555 return 0; 556 557 case CONS_HISTORY: /* set history size */ 558 if (*data) { 559 free(scp->history, M_DEVBUF); 560 scp->history_size = *(int*)data; 561 if (scp->history_size < scp->ysize) 562 scp->history = NULL; 563 else { 564 scp->history_size *= scp->xsize; 565 scp->history_head = scp->history_pos = scp->history = 566 (u_short *)malloc(scp->history_size*sizeof(u_short), 567 M_DEVBUF, M_WAITOK); 568 bzero(scp->history_head, scp->history_size*sizeof(u_short)); 569 } 570 return 0; 571 } 572 else 573 return EINVAL; 574 575 case CONS_MOUSECTL: /* control mouse arrow */ 576 { 577 mouse_info_t *mouse = (mouse_info_t*)data; 578 int fontsize; 579 580 switch (scp->font) { 581 default: 582 case FONT_8: 583 fontsize = 8; break; 584 case FONT_14: 585 fontsize = 14; break; 586 case FONT_16: 587 fontsize = 16; break; 588 } 589 switch (mouse->operation) { 590 case MOUSE_SHOW: 591 if (!(scp->status & MOUSE_ENABLED)) { 592 scp->mouse_oldpos = Crtat + (scp->mouse_pos - scp->scr_buf); 593 scp->status |= (UPDATE_MOUSE | MOUSE_ENABLED); 594 } 595 else 596 return EINVAL; 597 break; 598 599 case MOUSE_HIDE: 600 if (scp->status & MOUSE_ENABLED) { 601 scp->status &= ~MOUSE_ENABLED; 602 scp->status |= UPDATE_MOUSE; 603 } 604 else 605 return EINVAL; 606 break; 607 608 case MOUSE_MOVEABS: 609 scp->mouse_xpos = mouse->x; 610 scp->mouse_ypos = mouse->y; 611 goto set_mouse_pos; 612 613 case MOUSE_MOVEREL: 614 scp->mouse_xpos += mouse->x; 615 scp->mouse_ypos += mouse->y; 616set_mouse_pos: 617 if (scp->mouse_xpos < 0) 618 scp->mouse_xpos = 0; 619 if (scp->mouse_ypos < 0) 620 scp->mouse_ypos = 0; 621 if (scp->mouse_xpos >= scp->xsize*8) 622 scp->mouse_xpos = (scp->xsize*8)-1; 623 if (scp->mouse_ypos >= scp->ysize*fontsize) 624 scp->mouse_ypos = (scp->ysize*fontsize)-1; 625 scp->mouse_pos = scp->scr_buf + 626 (scp->mouse_ypos/fontsize)*scp->xsize + scp->mouse_xpos/8; 627 if (scp->status & MOUSE_ENABLED) 628 scp->status |= UPDATE_MOUSE; 629 break; 630 631 case MOUSE_GETPOS: 632 mouse->x = scp->mouse_xpos; 633 mouse->y = scp->mouse_ypos; 634 return 0; 635 636 default: 637 return EINVAL; 638 } 639 /* make screensaver happy */ 640 if (scp == cur_console) { 641 scrn_time_stamp = time.tv_sec; 642 if (scrn_blanked) { 643 (*current_saver)(FALSE); 644 cur_console->start = 0; 645 cur_console->end = cur_console->xsize * cur_console->ysize; 646 } 647 } 648 return 0; 649 } 650 651 case CONS_GETINFO: /* get current (virtual) console info */ 652 { 653 vid_info_t *ptr = (vid_info_t*)data; 654 if (ptr->size == sizeof(struct vid_info)) { 655 ptr->m_num = get_scr_num(); 656 ptr->mv_col = scp->xpos; 657 ptr->mv_row = scp->ypos; 658 ptr->mv_csz = scp->xsize; 659 ptr->mv_rsz = scp->ysize; 660 ptr->mv_norm.fore = (scp->term.std_attr & 0x0f00)>>8; 661 ptr->mv_norm.back = (scp->term.std_attr & 0xf000)>>12; 662 ptr->mv_rev.fore = (scp->term.rev_attr & 0x0f00)>>8; 663 ptr->mv_rev.back = (scp->term.rev_attr & 0xf000)>>12; 664 ptr->mv_grfc.fore = 0; /* not supported */ 665 ptr->mv_grfc.back = 0; /* not supported */ 666 ptr->mv_ovscan = scp->border; 667 ptr->mk_keylock = scp->status & LOCK_KEY_MASK; 668 return 0; 669 } 670 return EINVAL; 671 } 672 673 case CONS_GETVERS: /* get version number */ 674 *(int*)data = 0x200; /* version 2.0 */ 675 return 0; 676 677 /* VGA TEXT MODES */ 678 case SW_VGA_C40x25: 679 case SW_VGA_C80x25: case SW_VGA_M80x25: 680 case SW_VGA_C80x30: case SW_VGA_M80x30: 681 case SW_VGA_C80x50: case SW_VGA_M80x50: 682 case SW_VGA_C80x60: case SW_VGA_M80x60: 683 case SW_B40x25: case SW_C40x25: 684 case SW_B80x25: case SW_C80x25: 685 case SW_ENH_B40x25: case SW_ENH_C40x25: 686 case SW_ENH_B80x25: case SW_ENH_C80x25: 687 case SW_ENH_B80x43: case SW_ENH_C80x43: 688 689 if (!crtc_vga || video_mode_ptr == NULL) 690 return ENXIO; 691 switch (cmd & 0xff) { 692 case M_VGA_C80x60: case M_VGA_M80x60: 693 if (!(fonts_loaded & FONT_8)) 694 return EINVAL; 695 scp->xsize = 80; 696 scp->ysize = 60; 697 break; 698 case M_VGA_C80x50: case M_VGA_M80x50: 699 if (!(fonts_loaded & FONT_8)) 700 return EINVAL; 701 scp->xsize = 80; 702 scp->ysize = 50; 703 break; 704 case M_ENH_B80x43: case M_ENH_C80x43: 705 if (!(fonts_loaded & FONT_8)) 706 return EINVAL; 707 scp->xsize = 80; 708 scp->ysize = 43; 709 break; 710 case M_VGA_C80x30: case M_VGA_M80x30: 711 scp->xsize = 80; 712 scp->ysize = 30; 713 break; 714 default: 715 if ((cmd & 0xff) > M_VGA_CG320) 716 return EINVAL; 717 else 718 scp->xsize = *(video_mode_ptr+((cmd&0xff)*64)); 719 scp->ysize = *(video_mode_ptr+((cmd&0xff)*64)+1)+1; 720 break; 721 } 722 scp->mode = cmd & 0xff; 723 scp->status &= ~UNKNOWN_MODE; /* text mode */ 724 free(scp->scr_buf, M_DEVBUF); 725 scp->scr_buf = (u_short *)malloc(scp->xsize*scp->ysize*sizeof(u_short), 726 M_DEVBUF, M_WAITOK); 727 if (scp == cur_console) 728 set_mode(scp); 729 clear_screen(scp); 730 if (tp->t_winsize.ws_col != scp->xsize 731 || tp->t_winsize.ws_row != scp->ysize) { 732 tp->t_winsize.ws_col = scp->xsize; 733 tp->t_winsize.ws_row = scp->ysize; 734 pgsignal(tp->t_pgrp, SIGWINCH, 1); 735 } 736 return 0; 737 738 /* GRAPHICS MODES */ 739 case SW_BG320: case SW_BG640: 740 case SW_CG320: case SW_CG320_D: case SW_CG640_E: 741 case SW_CG640x350: case SW_ENH_CG640: 742 case SW_BG640x480: case SW_CG640x480: case SW_VGA_CG320: 743 744 if (!crtc_vga || video_mode_ptr == NULL) 745 return ENXIO; 746 scp->mode = cmd & 0xFF; 747 scp->status |= UNKNOWN_MODE; /* graphics mode */ 748 scp->xsize = (*(video_mode_ptr + (scp->mode*64))) * 8; 749 scp->ysize = (*(video_mode_ptr + (scp->mode*64) + 1) + 1) * 750 (*(video_mode_ptr + (scp->mode*64) + 2)); 751 set_mode(scp); 752 /* clear_graphics();*/ 753 754 if (tp->t_winsize.ws_xpixel != scp->xsize 755 || tp->t_winsize.ws_ypixel != scp->ysize) { 756 tp->t_winsize.ws_xpixel = scp->xsize; 757 tp->t_winsize.ws_ypixel = scp->ysize; 758 pgsignal(tp->t_pgrp, SIGWINCH, 1); 759 } 760 return 0; 761 762 case VT_SETMODE: /* set screen switcher mode */ 763 bcopy(data, &scp->smode, sizeof(struct vt_mode)); 764 if (scp->smode.mode == VT_PROCESS) { 765 scp->proc = p; 766 scp->pid = scp->proc->p_pid; 767 } 768 return 0; 769 770 case VT_GETMODE: /* get screen switcher mode */ 771 bcopy(&scp->smode, data, sizeof(struct vt_mode)); 772 return 0; 773 774 case VT_RELDISP: /* screen switcher ioctl */ 775 switch(*data) { 776 case VT_FALSE: /* user refuses to release screen, abort */ 777 if (scp == old_scp && (scp->status & SWITCH_WAIT_REL)) { 778 old_scp->status &= ~SWITCH_WAIT_REL; 779 switch_in_progress = FALSE; 780 return 0; 781 } 782 return EINVAL; 783 784 case VT_TRUE: /* user has released screen, go on */ 785 if (scp == old_scp && (scp->status & SWITCH_WAIT_REL)) { 786 scp->status &= ~SWITCH_WAIT_REL; 787 exchange_scr(); 788 if (new_scp->smode.mode == VT_PROCESS) { 789 new_scp->status |= SWITCH_WAIT_ACQ; 790 psignal(new_scp->proc, new_scp->smode.acqsig); 791 } 792 else 793 switch_in_progress = FALSE; 794 return 0; 795 } 796 return EINVAL; 797 798 case VT_ACKACQ: /* acquire acknowledged, switch completed */ 799 if (scp == new_scp && (scp->status & SWITCH_WAIT_ACQ)) { 800 scp->status &= ~SWITCH_WAIT_ACQ; 801 switch_in_progress = FALSE; 802 return 0; 803 } 804 return EINVAL; 805 806 default: 807 return EINVAL; 808 } 809 /* NOT REACHED */ 810 811 case VT_OPENQRY: /* return free virtual console */ 812 for (i = 0; i < MAXCONS; i++) { 813 tp = VIRTUAL_TTY(i); 814 if (!(tp->t_state & TS_ISOPEN)) { 815 *data = i + 1; 816 return 0; 817 } 818 } 819 return EINVAL; 820 821 case VT_ACTIVATE: /* switch to screen *data */ 822 return switch_scr(scp, (*data) - 1); 823 824 case VT_WAITACTIVE: /* wait for switch to occur */ 825 if (*data > MAXCONS || *data < 0) 826 return EINVAL; 827 if (minor(dev) == (*data) - 1) 828 return 0; 829 if (*data == 0) { 830 if (scp == cur_console) 831 return 0; 832 } 833 else 834 scp = console[(*data) - 1]; 835 while ((error=tsleep((caddr_t)&scp->smode, PZERO|PCATCH, 836 "waitvt", 0)) == ERESTART) ; 837 return error; 838 839 case VT_GETACTIVE: 840 *data = get_scr_num()+1; 841 return 0; 842 843 case KDENABIO: /* allow io operations */ 844 error = suser(p->p_ucred, &p->p_acflag); 845 if (error != 0) 846 return error; 847 fp = (struct trapframe *)p->p_md.md_regs; 848 fp->tf_eflags |= PSL_IOPL; 849 return 0; 850 851 case KDDISABIO: /* disallow io operations (default) */ 852 fp = (struct trapframe *)p->p_md.md_regs; 853 fp->tf_eflags &= ~PSL_IOPL; 854 return 0; 855 856 case KDSETMODE: /* set current mode of this (virtual) console */ 857 switch (*data) { 858 case KD_TEXT: /* switch to TEXT (known) mode */ 859 /* restore fonts & palette ! */ 860 if (crtc_vga) { 861 if (fonts_loaded & FONT_8) 862 copy_font(LOAD, FONT_8, font_8); 863 if (fonts_loaded & FONT_14) 864 copy_font(LOAD, FONT_14, font_14); 865 if (fonts_loaded & FONT_16) 866 copy_font(LOAD, FONT_16, font_16); 867 if (configuration & CHAR_CURSOR) 868 set_destructive_cursor(scp, TRUE); 869 load_palette(); 870 } 871 /* FALL THROUGH */ 872 873 case KD_TEXT1: /* switch to TEXT (known) mode */ 874 /* no restore fonts & palette */ 875 scp->status &= ~UNKNOWN_MODE; 876 if (crtc_vga && video_mode_ptr) 877 set_mode(scp); 878 clear_screen(scp); 879 return 0; 880 881 case KD_GRAPHICS: /* switch to GRAPHICS (unknown) mode */ 882 scp->status |= UNKNOWN_MODE; 883 return 0; 884 default: 885 return EINVAL; 886 } 887 /* NOT REACHED */ 888 889 case KDGETMODE: /* get current mode of this (virtual) console */ 890 *data = (scp->status & UNKNOWN_MODE) ? KD_GRAPHICS : KD_TEXT; 891 return 0; 892 893 case KDSBORDER: /* set border color of this (virtual) console */ 894 if (!crtc_vga) 895 return ENXIO; 896 scp->border = *data; 897 if (scp == cur_console) 898 set_border(scp->border); 899 return 0; 900 901 case KDSKBSTATE: /* set keyboard state (locks) */ 902 if (*data >= 0 && *data <= LOCK_KEY_MASK) { 903 scp->status &= ~LOCK_KEY_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 KDGKBSTATE: /* get keyboard state (locks) */ 912 *data = scp->status & LOCK_KEY_MASK; 913 return 0; 914 915 case KDSETRAD: /* set keyboard repeat & delay rates */ 916 if (*data & 0x80) 917 return EINVAL; 918 i = spltty(); 919 kbd_cmd(KB_SETRAD); 920 kbd_cmd(*data); 921 splx(i); 922 return 0; 923 924 case KDSKBMODE: /* set keyboard mode */ 925 switch (*data) { 926 case K_RAW: /* switch to RAW scancode mode */ 927 scp->status |= KBD_RAW_MODE; 928 return 0; 929 930 case K_XLATE: /* switch to XLT ascii mode */ 931 if (scp == cur_console && scp->status == KBD_RAW_MODE) 932 shfts = ctls = alts = agrs = metas = 0; 933 scp->status &= ~KBD_RAW_MODE; 934 return 0; 935 default: 936 return EINVAL; 937 } 938 /* NOT REACHED */ 939 940 case KDGKBMODE: /* get keyboard mode */ 941 *data = (scp->status & KBD_RAW_MODE) ? K_RAW : K_XLATE; 942 return 0; 943 944 case KDMKTONE: /* sound the bell */ 945 if (*(int*)data) 946 do_bell(scp, (*(int*)data)&0xffff, 947 (((*(int*)data)>>16)&0xffff)*hz/1000); 948 else 949 do_bell(scp, scp->bell_pitch, scp->bell_duration); 950 return 0; 951 952 case KIOCSOUND: /* make tone (*data) hz */ 953 if (scp == cur_console) { 954 if (*(int*)data) { 955 int pitch = TIMER_FREQ/(*(int*)data); 956 957 /* set command for counter 2, 2 byte write */ 958 if (acquire_timer2(TIMER_16BIT|TIMER_SQWAVE)) 959 return EBUSY; 960 961 /* set pitch */ 962 outb(TIMER_CNTR2, pitch); 963 outb(TIMER_CNTR2, (pitch>>8)); 964 965 /* enable counter 2 output to speaker */ 966 outb(IO_PPI, inb(IO_PPI) | 3); 967 } 968 else { 969 /* disable counter 2 output to speaker */ 970 outb(IO_PPI, inb(IO_PPI) & 0xFC); 971 release_timer2(); 972 } 973 } 974 return 0; 975 976 case KDGKBTYPE: /* get keyboard type */ 977 *data = 0; /* type not known (yet) */ 978 return 0; 979 980 case KDSETLED: /* set keyboard LED status */ 981 if (*data >= 0 && *data <= LED_MASK) { 982 scp->status &= ~LED_MASK; 983 scp->status |= *data; 984 if (scp == cur_console) 985 update_leds(scp->status); 986 return 0; 987 } 988 return EINVAL; 989 990 case KDGETLED: /* get keyboard LED status */ 991 *data = scp->status & LED_MASK; 992 return 0; 993 994 case GETFKEY: /* get functionkey string */ 995 if (*(u_short*)data < n_fkey_tab) { 996 fkeyarg_t *ptr = (fkeyarg_t*)data; 997 bcopy(&fkey_tab[ptr->keynum].str, ptr->keydef, 998 fkey_tab[ptr->keynum].len); 999 ptr->flen = fkey_tab[ptr->keynum].len; 1000 return 0; 1001 } 1002 else 1003 return EINVAL; 1004 1005 case SETFKEY: /* set functionkey string */ 1006 if (*(u_short*)data < n_fkey_tab) { 1007 fkeyarg_t *ptr = (fkeyarg_t*)data; 1008 bcopy(ptr->keydef, &fkey_tab[ptr->keynum].str, 1009 min(ptr->flen, MAXFK)); 1010 fkey_tab[ptr->keynum].len = min(ptr->flen, MAXFK); 1011 return 0; 1012 } 1013 else 1014 return EINVAL; 1015 1016 case GIO_SCRNMAP: /* get output translation table */ 1017 bcopy(&scr_map, data, sizeof(scr_map)); 1018 return 0; 1019 1020 case PIO_SCRNMAP: /* set output translation table */ 1021 bcopy(data, &scr_map, sizeof(scr_map)); 1022 return 0; 1023 1024 case GIO_KEYMAP: /* get keyboard translation table */ 1025 bcopy(&key_map, data, sizeof(key_map)); 1026 return 0; 1027 1028 case PIO_KEYMAP: /* set keyboard translation table */ 1029 bcopy(data, &key_map, sizeof(key_map)); 1030 return 0; 1031 1032 case PIO_FONT8x8: /* set 8x8 dot font */ 1033 if (!crtc_vga) 1034 return ENXIO; 1035 bcopy(data, font_8, 8*256); 1036 fonts_loaded |= FONT_8; 1037 copy_font(LOAD, FONT_8, font_8); 1038 if (configuration & CHAR_CURSOR) 1039 set_destructive_cursor(scp, TRUE); 1040 return 0; 1041 1042 case GIO_FONT8x8: /* get 8x8 dot font */ 1043 if (!crtc_vga) 1044 return ENXIO; 1045 if (fonts_loaded & FONT_8) { 1046 bcopy(font_8, data, 8*256); 1047 return 0; 1048 } 1049 else 1050 return ENXIO; 1051 1052 case PIO_FONT8x14: /* set 8x14 dot font */ 1053 if (!crtc_vga) 1054 return ENXIO; 1055 bcopy(data, font_14, 14*256); 1056 fonts_loaded |= FONT_14; 1057 copy_font(LOAD, FONT_14, font_14); 1058 if (configuration & CHAR_CURSOR) 1059 set_destructive_cursor(scp, TRUE); 1060 return 0; 1061 1062 case GIO_FONT8x14: /* get 8x14 dot font */ 1063 if (!crtc_vga) 1064 return ENXIO; 1065 if (fonts_loaded & FONT_14) { 1066 bcopy(font_14, data, 14*256); 1067 return 0; 1068 } 1069 else 1070 return ENXIO; 1071 1072 case PIO_FONT8x16: /* set 8x16 dot font */ 1073 if (!crtc_vga) 1074 return ENXIO; 1075 bcopy(data, font_16, 16*256); 1076 fonts_loaded |= FONT_16; 1077 copy_font(LOAD, FONT_16, font_16); 1078 if (configuration & CHAR_CURSOR) 1079 set_destructive_cursor(scp, TRUE); 1080 return 0; 1081 1082 case GIO_FONT8x16: /* get 8x16 dot font */ 1083 if (!crtc_vga) 1084 return ENXIO; 1085 if (fonts_loaded & FONT_16) { 1086 bcopy(font_16, data, 16*256); 1087 return 0; 1088 } 1089 else 1090 return ENXIO; 1091 default: 1092 break; 1093 } 1094 1095 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 1096 if (error >= 0) 1097 return(error); 1098 error = ttioctl(tp, cmd, data, flag); 1099 if (error >= 0) 1100 return(error); 1101 return(ENOTTY); 1102} 1103 1104void 1105scstart(struct tty *tp) 1106{ 1107 struct clist *rbp; 1108 int i, s, len; 1109 u_char buf[PCBURST]; 1110 scr_stat *scp = get_scr_stat(tp->t_dev); 1111 1112 /* XXX who repeats the call when the above flags are cleared? */ 1113 if (scp->status & SLKED || blink_in_progress) 1114 return; 1115 s = spltty(); 1116 if (!(tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))) { 1117 tp->t_state |= TS_BUSY; 1118 rbp = &tp->t_outq; 1119 while (rbp->c_cc) { 1120 len = q_to_b(rbp, buf, PCBURST); 1121 splx(s); 1122 ansi_put(scp, buf, len); 1123 s = spltty(); 1124 } 1125 tp->t_state &= ~TS_BUSY; 1126 ttwwakeup(tp); 1127 } 1128 splx(s); 1129} 1130 1131void 1132sccnprobe(struct consdev *cp) 1133{ 1134 struct isa_device *dvp; 1135 int maj; 1136 1137 /* 1138 * Take control if we are the highest priority enabled display device. 1139 */ 1140 dvp = find_display(); 1141 maj = getmajorbyname("sc"); 1142 if (dvp->id_driver != &scdriver || maj < 0) { 1143 cp->cn_pri = CN_DEAD; 1144 return; 1145 } 1146 1147 /* initialize required fields */ 1148 cp->cn_dev = makedev(maj, MAXCONS); 1149 cp->cn_pri = CN_INTERNAL; 1150} 1151 1152void 1153sccninit(struct consdev *cp) 1154{ 1155 scinit(); 1156} 1157 1158void 1159sccnputc(dev_t dev, int c) 1160{ 1161 u_char buf[1]; 1162 scr_stat *scp = console[0]; 1163 term_stat save = scp->term; 1164 1165 scp->term = kernel_console; 1166 current_default = &kernel_default; 1167 if (scp->scr_buf == Crtat) 1168 draw_cursor(scp, FALSE); 1169 buf[0] = c; 1170 ansi_put(scp, buf, 1); 1171 kernel_console = scp->term; 1172 current_default = &user_default; 1173 scp->term = save; 1174 if (scp == cur_console /* && scrn_timer not running */) { 1175 if (scp->scr_buf != Crtat && (scp->start <= scp->end)) { 1176 bcopyw(scp->scr_buf + scp->start, Crtat + scp->start, 1177 (1 + scp->end - scp->start) * sizeof(u_short)); 1178 scp->start = scp->xsize * scp->ysize; 1179 scp->end = 0; 1180 scp->status &= ~CURSOR_SHOWN; 1181 } 1182 draw_cursor(scp, TRUE); 1183 } 1184} 1185 1186int 1187sccngetc(dev_t dev) 1188{ 1189 int s = spltty(); /* block scintr while we poll */ 1190 int c = scgetc(0); 1191 splx(s); 1192 return(c); 1193} 1194 1195int 1196sccncheckc(dev_t dev) 1197{ 1198 return (scgetc(1) & 0xff); 1199} 1200 1201static void 1202scrn_timer() 1203{ 1204 static int cursor_blinkrate; 1205 scr_stat *scp = cur_console; 1206 1207 /* should we just return ? */ 1208 if ((scp->status&UNKNOWN_MODE) || blink_in_progress || switch_in_progress) { 1209 timeout((timeout_func_t)scrn_timer, 0, hz/10); 1210 return; 1211 } 1212 1213 if (!scrn_blanked) { 1214 /* update screen image */ 1215 if (scp->start <= scp->end) { 1216 bcopyw(scp->scr_buf + scp->start, Crtat + scp->start, 1217 (1 + scp->end - scp->start) * sizeof(u_short)); 1218 scp->status &= ~CURSOR_SHOWN; 1219 scp->start = scp->xsize * scp->ysize; 1220 scp->end = 0; 1221 } 1222 /* update "pseudo" mouse arrow */ 1223 if ((scp->status & MOUSE_ENABLED) && (scp->status & UPDATE_MOUSE)) 1224 draw_mouse_image(scp); 1225 1226 /* update cursor image */ 1227 if (scp->status & CURSOR_ENABLED) 1228 draw_cursor(scp, 1229 !(configuration&BLINK_CURSOR) || !(cursor_blinkrate++&0x04)); 1230 } 1231 if (scrn_blank_time && (time.tv_sec>scrn_time_stamp+scrn_blank_time)) 1232 (*current_saver)(TRUE); 1233 timeout((timeout_func_t)scrn_timer, 0, hz/25); 1234} 1235 1236static void 1237clear_screen(scr_stat *scp) 1238{ 1239 move_crsr(scp, 0, 0); 1240 fillw(scp->term.cur_attr | scr_map[0x20], scp->scr_buf, 1241 scp->xsize * scp->ysize); 1242 mark_all(scp); 1243} 1244 1245static int 1246switch_scr(scr_stat *scp, u_int next_scr) 1247{ 1248 if (switch_in_progress && (cur_console->proc != pfind(cur_console->pid))) 1249 switch_in_progress = FALSE; 1250 1251 if (next_scr >= MAXCONS || switch_in_progress || 1252 (cur_console->smode.mode == VT_AUTO 1253 && cur_console->status & UNKNOWN_MODE)) { 1254 do_bell(scp, BELL_PITCH, BELL_DURATION); 1255 return EINVAL; 1256 } 1257 1258 /* is the wanted virtual console open ? */ 1259 if (next_scr) { 1260 struct tty *tp = VIRTUAL_TTY(next_scr); 1261 if (!(tp->t_state & TS_ISOPEN)) { 1262 do_bell(scp, BELL_PITCH, BELL_DURATION); 1263 return EINVAL; 1264 } 1265 } 1266 /* delay switch if actively updating screen */ 1267 if (write_in_progress || blink_in_progress) { 1268 delayed_next_scr = next_scr+1; 1269 return 0; 1270 } 1271 switch_in_progress = TRUE; 1272 old_scp = cur_console; 1273 new_scp = console[next_scr]; 1274 wakeup((caddr_t)&new_scp->smode); 1275 if (new_scp == old_scp) { 1276 switch_in_progress = FALSE; 1277 delayed_next_scr = FALSE; 1278 return 0; 1279 } 1280 1281 /* has controlling process died? */ 1282 if (old_scp->proc && (old_scp->proc != pfind(old_scp->pid))) 1283 old_scp->smode.mode = VT_AUTO; 1284 if (new_scp->proc && (new_scp->proc != pfind(new_scp->pid))) 1285 new_scp->smode.mode = VT_AUTO; 1286 1287 /* check the modes and switch approbiatly */ 1288 if (old_scp->smode.mode == VT_PROCESS) { 1289 old_scp->status |= SWITCH_WAIT_REL; 1290 psignal(old_scp->proc, old_scp->smode.relsig); 1291 } 1292 else { 1293 exchange_scr(); 1294 if (new_scp->smode.mode == VT_PROCESS) { 1295 new_scp->status |= SWITCH_WAIT_ACQ; 1296 psignal(new_scp->proc, new_scp->smode.acqsig); 1297 } 1298 else 1299 switch_in_progress = FALSE; 1300 } 1301 return 0; 1302} 1303 1304static void 1305exchange_scr(void) 1306{ 1307 move_crsr(old_scp, old_scp->xpos, old_scp->ypos); 1308 cur_console = new_scp; 1309 if (old_scp->mode != new_scp->mode || (old_scp->status & UNKNOWN_MODE)){ 1310 if (crtc_vga && video_mode_ptr) 1311 set_mode(new_scp); 1312 } 1313 move_crsr(new_scp, new_scp->xpos, new_scp->ypos); 1314 if ((old_scp->status & UNKNOWN_MODE) && crtc_vga) { 1315 if (fonts_loaded & FONT_8) 1316 copy_font(LOAD, FONT_8, font_8); 1317 if (fonts_loaded & FONT_14) 1318 copy_font(LOAD, FONT_14, font_14); 1319 if (fonts_loaded & FONT_16) 1320 copy_font(LOAD, FONT_16, font_16); 1321 if (configuration & CHAR_CURSOR) 1322 set_destructive_cursor(new_scp, TRUE); 1323 load_palette(); 1324 } 1325 if (old_scp->status & KBD_RAW_MODE || new_scp->status & KBD_RAW_MODE) 1326 shfts = ctls = alts = agrs = metas = 0; 1327 update_leds(new_scp->status); 1328 delayed_next_scr = FALSE; 1329 bcopyw(new_scp->scr_buf, Crtat, 1330 (new_scp->xsize*new_scp->ysize)*sizeof(u_short)); 1331 new_scp->status &= ~CURSOR_SHOWN; 1332} 1333 1334static inline void 1335move_crsr(scr_stat *scp, int x, int y) 1336{ 1337 if (x < 0 || y < 0 || x >= scp->xsize || y >= scp->ysize) 1338 return; 1339 scp->xpos = x; 1340 scp->ypos = y; 1341 mark_for_update(scp, scp->cursor_pos - scp->scr_buf); 1342 scp->cursor_pos = scp->scr_buf + scp->ypos * scp->xsize + scp->xpos; 1343 mark_for_update(scp, scp->cursor_pos - scp->scr_buf); 1344} 1345 1346static void 1347scan_esc(scr_stat *scp, u_char c) 1348{ 1349 static u_char ansi_col[16] = 1350 {0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15}; 1351 int i, n; 1352 u_short *src, *dst, count; 1353 1354 if (scp->term.esc == 1) { 1355 switch (c) { 1356 1357 case '[': /* Start ESC [ sequence */ 1358 scp->term.esc = 2; 1359 scp->term.last_param = -1; 1360 for (i = scp->term.num_param; i < MAX_ESC_PAR; i++) 1361 scp->term.param[i] = 1; 1362 scp->term.num_param = 0; 1363 return; 1364 1365 case 'M': /* Move cursor up 1 line, scroll if at top */ 1366 if (scp->ypos > 0) 1367 move_crsr(scp, scp->xpos, scp->ypos - 1); 1368 else { 1369 bcopyw(scp->scr_buf, scp->scr_buf + scp->xsize, 1370 (scp->ysize - 1) * scp->xsize * sizeof(u_short)); 1371 fillw(scp->term.cur_attr | scr_map[0x20], 1372 scp->scr_buf, scp->xsize); 1373 mark_all(scp); 1374 } 1375 break; 1376#if notyet 1377 case 'Q': 1378 scp->term.esc = 4; 1379 break; 1380#endif 1381 case 'c': /* Clear screen & home */ 1382 clear_screen(scp); 1383 break; 1384 } 1385 } 1386 else if (scp->term.esc == 2) { 1387 if (c >= '0' && c <= '9') { 1388 if (scp->term.num_param < MAX_ESC_PAR) { 1389 if (scp->term.last_param != scp->term.num_param) { 1390 scp->term.last_param = scp->term.num_param; 1391 scp->term.param[scp->term.num_param] = 0; 1392 } 1393 else 1394 scp->term.param[scp->term.num_param] *= 10; 1395 scp->term.param[scp->term.num_param] += c - '0'; 1396 return; 1397 } 1398 } 1399 scp->term.num_param = scp->term.last_param + 1; 1400 switch (c) { 1401 1402 case ';': 1403 if (scp->term.num_param < MAX_ESC_PAR) 1404 return; 1405 break; 1406 1407 case '=': 1408 scp->term.esc = 3; 1409 scp->term.last_param = -1; 1410 for (i = scp->term.num_param; i < MAX_ESC_PAR; i++) 1411 scp->term.param[i] = 1; 1412 scp->term.num_param = 0; 1413 return; 1414 1415 case 'A': /* up n rows */ 1416 n = scp->term.param[0]; if (n < 1) n = 1; 1417 move_crsr(scp, scp->xpos, scp->ypos - n); 1418 break; 1419 1420 case 'B': /* down n rows */ 1421 n = scp->term.param[0]; if (n < 1) n = 1; 1422 move_crsr(scp, scp->xpos, scp->ypos + n); 1423 break; 1424 1425 case 'C': /* right n columns */ 1426 n = scp->term.param[0]; if (n < 1) n = 1; 1427 move_crsr(scp, scp->xpos + n, scp->ypos); 1428 break; 1429 1430 case 'D': /* left n columns */ 1431 n = scp->term.param[0]; if (n < 1) n = 1; 1432 move_crsr(scp, scp->xpos - n, scp->ypos); 1433 break; 1434 1435 case 'E': /* cursor to start of line n lines down */ 1436 n = scp->term.param[0]; if (n < 1) n = 1; 1437 move_crsr(scp, 0, scp->ypos + n); 1438 break; 1439 1440 case 'F': /* cursor to start of line n lines up */ 1441 n = scp->term.param[0]; if (n < 1) n = 1; 1442 move_crsr(scp, 0, scp->ypos - n); 1443 break; 1444 1445 case 'f': /* Cursor move */ 1446 case 'H': 1447 if (scp->term.num_param == 0) 1448 move_crsr(scp, 0, 0); 1449 else if (scp->term.num_param == 2) 1450 move_crsr(scp, scp->term.param[1] - 1, scp->term.param[0] - 1); 1451 break; 1452 1453 case 'J': /* Clear all or part of display */ 1454 if (scp->term.num_param == 0) 1455 n = 0; 1456 else 1457 n = scp->term.param[0]; 1458 switch (n) { 1459 case 0: /* clear form cursor to end of display */ 1460 fillw(scp->term.cur_attr | scr_map[0x20], 1461 scp->cursor_pos, 1462 scp->scr_buf + scp->xsize * scp->ysize - scp->cursor_pos); 1463 mark_for_update(scp, scp->cursor_pos - scp->scr_buf); 1464 mark_for_update(scp, scp->xsize * scp->ysize); 1465 break; 1466 case 1: /* clear from beginning of display to cursor */ 1467 fillw(scp->term.cur_attr | scr_map[0x20], 1468 scp->scr_buf, 1469 scp->cursor_pos - scp->scr_buf); 1470 mark_for_update(scp, 0); 1471 mark_for_update(scp, scp->cursor_pos - scp->scr_buf); 1472 break; 1473 case 2: /* clear entire display */ 1474 clear_screen(scp); 1475 break; 1476 } 1477 break; 1478 1479 case 'K': /* Clear all or part of line */ 1480 if (scp->term.num_param == 0) 1481 n = 0; 1482 else 1483 n = scp->term.param[0]; 1484 switch (n) { 1485 case 0: /* clear form cursor to end of line */ 1486 fillw(scp->term.cur_attr | scr_map[0x20], 1487 scp->cursor_pos, 1488 scp->xsize - scp->xpos); 1489 mark_for_update(scp, scp->cursor_pos - scp->scr_buf); 1490 mark_for_update(scp, scp->cursor_pos - scp->scr_buf + 1491 scp->xsize - scp->xpos); 1492 break; 1493 case 1: /* clear from beginning of line to cursor */ 1494 fillw(scp->term.cur_attr|scr_map[0x20], 1495 scp->cursor_pos - (scp->xsize - scp->xpos), 1496 (scp->xsize - scp->xpos) + 1); 1497 mark_for_update(scp, scp->ypos * scp->xsize); 1498 mark_for_update(scp, scp->cursor_pos - scp->scr_buf); 1499 break; 1500 case 2: /* clear entire line */ 1501 fillw(scp->term.cur_attr|scr_map[0x20], 1502 scp->cursor_pos - (scp->xsize - scp->xpos), 1503 scp->xsize); 1504 mark_for_update(scp, scp->ypos * scp->xsize); 1505 mark_for_update(scp, (scp->ypos + 1) * scp->xsize); 1506 break; 1507 } 1508 break; 1509 1510 case 'L': /* Insert n lines */ 1511 n = scp->term.param[0]; if (n < 1) n = 1; 1512 if (n > scp->ysize - scp->ypos) 1513 n = scp->ysize - scp->ypos; 1514 src = scp->scr_buf + scp->ypos * scp->xsize; 1515 dst = src + n * scp->xsize; 1516 count = scp->ysize - (scp->ypos + n); 1517 bcopyw(src, dst, count * scp->xsize * sizeof(u_short)); 1518 fillw(scp->term.cur_attr | scr_map[0x20], src, 1519 n * scp->xsize); 1520 mark_for_update(scp, scp->ypos * scp->xsize); 1521 mark_for_update(scp, scp->xsize * scp->ysize); 1522 break; 1523 1524 case 'M': /* Delete n lines */ 1525 n = scp->term.param[0]; if (n < 1) n = 1; 1526 if (n > scp->ysize - scp->ypos) 1527 n = scp->ysize - scp->ypos; 1528 dst = scp->scr_buf + scp->ypos * scp->xsize; 1529 src = dst + n * scp->xsize; 1530 count = scp->ysize - (scp->ypos + n); 1531 bcopyw(src, dst, count * scp->xsize * sizeof(u_short)); 1532 src = dst + count * scp->xsize; 1533 fillw(scp->term.cur_attr | scr_map[0x20], src, 1534 n * scp->xsize); 1535 mark_for_update(scp, scp->ypos * scp->xsize); 1536 mark_for_update(scp, scp->xsize * scp->ysize); 1537 break; 1538 1539 case 'P': /* Delete n chars */ 1540 n = scp->term.param[0]; if (n < 1) n = 1; 1541 if (n > scp->xsize - scp->xpos) 1542 n = scp->xsize - scp->xpos; 1543 dst = scp->cursor_pos; 1544 src = dst + n; 1545 count = scp->xsize - (scp->xpos + n); 1546 bcopyw(src, dst, count * sizeof(u_short)); 1547 src = dst + count; 1548 fillw(scp->term.cur_attr | scr_map[0x20], src, n); 1549 mark_for_update(scp, scp->cursor_pos - scp->scr_buf); 1550 mark_for_update(scp, scp->cursor_pos - scp->scr_buf + n + count); 1551 break; 1552 1553 case '@': /* Insert n chars */ 1554 n = scp->term.param[0]; if (n < 1) n = 1; 1555 if (n > scp->xsize - scp->xpos) 1556 n = scp->xsize - scp->xpos; 1557 src = scp->cursor_pos; 1558 dst = src + n; 1559 count = scp->xsize - (scp->xpos + n); 1560 bcopyw(src, dst, count * sizeof(u_short)); 1561 fillw(scp->term.cur_attr | scr_map[0x20], src, n); 1562 mark_for_update(scp, scp->cursor_pos - scp->scr_buf); 1563 mark_for_update(scp, scp->cursor_pos - scp->scr_buf + n + count); 1564 break; 1565 1566 case 'S': /* scroll up n lines */ 1567 n = scp->term.param[0]; if (n < 1) n = 1; 1568 if (n > scp->ysize) 1569 n = scp->ysize; 1570 bcopyw(scp->scr_buf + (scp->xsize * n), 1571 scp->scr_buf, 1572 scp->xsize * (scp->ysize - n) * sizeof(u_short)); 1573 fillw(scp->term.cur_attr | scr_map[0x20], 1574 scp->scr_buf + scp->xsize * (scp->ysize - n), 1575 scp->xsize * n); 1576 mark_all(scp); 1577 break; 1578 1579 case 'T': /* scroll down n lines */ 1580 n = scp->term.param[0]; if (n < 1) n = 1; 1581 if (n > scp->ysize) 1582 n = scp->ysize; 1583 bcopyw(scp->scr_buf, 1584 scp->scr_buf + (scp->xsize * n), 1585 scp->xsize * (scp->ysize - n) * 1586 sizeof(u_short)); 1587 fillw(scp->term.cur_attr | scr_map[0x20], 1588 scp->scr_buf, scp->xsize * n); 1589 mark_all(scp); 1590 break; 1591 1592 case 'X': /* erase n characters in line */ 1593 n = scp->term.param[0]; if (n < 1) n = 1; 1594 if (n > scp->xsize - scp->xpos) 1595 n = scp->xsize - scp->xpos; 1596 fillw(scp->term.cur_attr | scr_map[0x20], 1597 scp->scr_buf + scp->xpos + 1598 ((scp->xsize*scp->ypos) * sizeof(u_short)), n); 1599 mark_for_update(scp, scp->cursor_pos - scp->scr_buf); 1600 mark_for_update(scp, scp->cursor_pos - scp->scr_buf + n); 1601 break; 1602 1603 case 'Z': /* move n tabs backwards */ 1604 n = scp->term.param[0]; if (n < 1) n = 1; 1605 if ((i = scp->xpos & 0xf8) == scp->xpos) 1606 i -= 8*n; 1607 else 1608 i -= 8*(n-1); 1609 if (i < 0) 1610 i = 0; 1611 move_crsr(scp, i, scp->ypos); 1612 break; 1613 1614 case '`': /* move cursor to column n */ 1615 n = scp->term.param[0]; if (n < 1) n = 1; 1616 move_crsr(scp, n - 1, scp->ypos); 1617 break; 1618 1619 case 'a': /* move cursor n columns to the right */ 1620 n = scp->term.param[0]; if (n < 1) n = 1; 1621 move_crsr(scp, scp->xpos + n, scp->ypos); 1622 break; 1623 1624 case 'd': /* move cursor to row n */ 1625 n = scp->term.param[0]; if (n < 1) n = 1; 1626 move_crsr(scp, scp->xpos, n - 1); 1627 break; 1628 1629 case 'e': /* move cursor n rows down */ 1630 n = scp->term.param[0]; if (n < 1) n = 1; 1631 move_crsr(scp, scp->xpos, scp->ypos + n); 1632 break; 1633 1634 case 'm': /* change attribute */ 1635 if (scp->term.num_param == 0) { 1636 scp->term.cur_attr = scp->term.std_attr; 1637 break; 1638 } 1639 for (i = 0; i < scp->term.num_param; i++) { 1640 switch (n = scp->term.param[i]) { 1641 case 0: /* back to normal */ 1642 scp->term.cur_attr = scp->term.std_attr; 1643 break; 1644 case 1: /* highlight (bold) */ 1645 scp->term.cur_attr &= 0xFF00; 1646 scp->term.cur_attr |= 0x0800; 1647 break; 1648 case 4: /* highlight (underline) */ 1649 scp->term.cur_attr &= 0xFF00; 1650 scp->term.cur_attr |= 0x0800; 1651 break; 1652 case 5: /* blink */ 1653 scp->term.cur_attr &= 0xFF00; 1654 scp->term.cur_attr |= 0x8000; 1655 break; 1656 case 7: /* reverse video */ 1657 scp->term.cur_attr = scp->term.rev_attr; 1658 break; 1659 case 30: case 31: /* set fg color */ 1660 case 32: case 33: case 34: 1661 case 35: case 36: case 37: 1662 scp->term.cur_attr = 1663 (scp->term.cur_attr&0xF8FF) | (ansi_col[(n-30)&7]<<8); 1664 break; 1665 case 40: case 41: /* set bg color */ 1666 case 42: case 43: case 44: 1667 case 45: case 46: case 47: 1668 scp->term.cur_attr = 1669 (scp->term.cur_attr&0x8FFF) | (ansi_col[(n-40)&7]<<12); 1670 break; 1671 } 1672 } 1673 break; 1674 1675 case 'x': 1676 if (scp->term.num_param == 0) 1677 n = 0; 1678 else 1679 n = scp->term.param[0]; 1680 switch (n) { 1681 case 0: /* reset attributes */ 1682 scp->term.cur_attr = scp->term.std_attr = 1683 current_default->std_attr; 1684 scp->term.rev_attr = current_default->rev_attr; 1685 break; 1686 case 1: /* set ansi background */ 1687 scp->term.cur_attr = scp->term.std_attr = 1688 (scp->term.std_attr & 0x0F00) | 1689 (ansi_col[(scp->term.param[1])&0x0F]<<12); 1690 break; 1691 case 2: /* set ansi foreground */ 1692 scp->term.cur_attr = scp->term.std_attr = 1693 (scp->term.std_attr & 0xF000) | 1694 (ansi_col[(scp->term.param[1])&0x0F]<<8); 1695 break; 1696 case 3: /* set ansi attribute directly */ 1697 scp->term.cur_attr = scp->term.std_attr = 1698 (scp->term.param[1]&0xFF)<<8; 1699 break; 1700 case 5: /* set ansi reverse video background */ 1701 scp->term.rev_attr = 1702 (scp->term.rev_attr & 0x0F00) | 1703 (ansi_col[(scp->term.param[1])&0x0F]<<12); 1704 break; 1705 case 6: /* set ansi reverse video foreground */ 1706 scp->term.rev_attr = 1707 (scp->term.rev_attr & 0xF000) | 1708 (ansi_col[(scp->term.param[1])&0x0F]<<8); 1709 break; 1710 case 7: /* set ansi reverse video directly */ 1711 scp->term.rev_attr = 1712 (scp->term.param[1]&0xFF)<<8; 1713 break; 1714 } 1715 break; 1716 1717 case 'z': /* switch to (virtual) console n */ 1718 if (scp->term.num_param == 1) 1719 switch_scr(scp, scp->term.param[0]); 1720 break; 1721 } 1722 } 1723 else if (scp->term.esc == 3) { 1724 if (c >= '0' && c <= '9') { 1725 if (scp->term.num_param < MAX_ESC_PAR) { 1726 if (scp->term.last_param != scp->term.num_param) { 1727 scp->term.last_param = scp->term.num_param; 1728 scp->term.param[scp->term.num_param] = 0; 1729 } 1730 else 1731 scp->term.param[scp->term.num_param] *= 10; 1732 scp->term.param[scp->term.num_param] += c - '0'; 1733 return; 1734 } 1735 } 1736 scp->term.num_param = scp->term.last_param + 1; 1737 switch (c) { 1738 1739 case ';': 1740 if (scp->term.num_param < MAX_ESC_PAR) 1741 return; 1742 break; 1743 1744 case 'A': /* set display border color */ 1745 if (scp->term.num_param == 1) 1746 scp->border=scp->term.param[0] & 0xff; 1747 if (scp == cur_console) 1748 set_border(scp->border); 1749 break; 1750 1751 case 'B': /* set bell pitch and duration */ 1752 if (scp->term.num_param == 2) { 1753 scp->bell_pitch = scp->term.param[0]; 1754 scp->bell_duration = scp->term.param[1]*10; 1755 } 1756 break; 1757 1758 case 'C': /* set cursor type & shape */ 1759 if (scp->term.num_param == 1) { 1760 if (scp->term.param[0] & 0x01) 1761 configuration |= BLINK_CURSOR; 1762 else 1763 configuration &= ~BLINK_CURSOR; 1764 if (scp->term.param[0] & 0x02) { 1765 configuration |= CHAR_CURSOR; 1766 set_destructive_cursor(scp, TRUE); 1767 } else 1768 configuration &= ~CHAR_CURSOR; 1769 } 1770 else if (scp->term.num_param == 2) { 1771 scp->cursor_start = scp->term.param[0] & 0x1F; 1772 scp->cursor_end = scp->term.param[1] & 0x1F; 1773 if (configuration & CHAR_CURSOR) 1774 set_destructive_cursor(scp, TRUE); 1775 } 1776 break; 1777 1778 case 'F': /* set ansi foreground */ 1779 if (scp->term.num_param == 1) 1780 scp->term.cur_attr = scp->term.std_attr = 1781 (scp->term.std_attr & 0xF000) 1782 | ((scp->term.param[0] & 0x0F) << 8); 1783 break; 1784 1785 case 'G': /* set ansi background */ 1786 if (scp->term.num_param == 1) 1787 scp->term.cur_attr = scp->term.std_attr = 1788 (scp->term.std_attr & 0x0F00) 1789 | ((scp->term.param[0] & 0x0F) << 12); 1790 break; 1791 1792 case 'H': /* set ansi reverse video foreground */ 1793 if (scp->term.num_param == 1) 1794 scp->term.rev_attr = 1795 (scp->term.rev_attr & 0xF000) 1796 | ((scp->term.param[0] & 0x0F) << 8); 1797 break; 1798 1799 case 'I': /* set ansi reverse video background */ 1800 if (scp->term.num_param == 1) 1801 scp->term.rev_attr = 1802 (scp->term.rev_attr & 0x0F00) 1803 | ((scp->term.param[0] & 0x0F) << 12); 1804 break; 1805 } 1806 } 1807 scp->term.esc = 0; 1808} 1809 1810static inline void 1811draw_cursor(scr_stat *scp, int show) 1812{ 1813 if (show && !(scp->status & CURSOR_SHOWN)) { 1814 u_short cursor_image = *(Crtat + (scp->cursor_pos - scp->scr_buf)); 1815 1816 scp->cursor_saveunder = cursor_image; 1817 if (configuration & CHAR_CURSOR) { 1818 set_destructive_cursor(scp, FALSE); 1819 cursor_image = (cursor_image & 0xff00) | DEAD_CHAR; 1820 } 1821 else { 1822 if ((cursor_image & 0x7000) == 0x7000) { 1823 cursor_image &= 0x8fff; 1824 if(!(cursor_image & 0x0700)) 1825 cursor_image |= 0x0700; 1826 } else { 1827 cursor_image |= 0x7000; 1828 if ((cursor_image & 0x0700) == 0x0700) 1829 cursor_image &= 0xf0ff; 1830 } 1831 } 1832 *(Crtat + (scp->cursor_pos - scp->scr_buf)) = cursor_image; 1833 mark_for_update(scp, scp->cursor_pos - scp->scr_buf); 1834 scp->status |= CURSOR_SHOWN; 1835 } 1836 if (!show && (scp->status & CURSOR_SHOWN)) { 1837 *(Crtat + (scp->cursor_pos - scp->scr_buf)) = scp->cursor_saveunder; 1838 mark_for_update(scp, scp->cursor_pos - scp->scr_buf); 1839 scp->status &= ~CURSOR_SHOWN; 1840 } 1841} 1842 1843static void 1844ansi_put(scr_stat *scp, u_char *buf, int len) 1845{ 1846 u_char *ptr = buf; 1847 1848 if (scp->status & UNKNOWN_MODE) 1849 return; 1850 1851 /* make screensaver happy */ 1852 if (scp == cur_console) { 1853 scrn_time_stamp = time.tv_sec; 1854 if (scrn_blanked) { 1855 (*current_saver)(FALSE); 1856 cur_console->start = 0; 1857 cur_console->end = cur_console->xsize * cur_console->ysize; 1858 } 1859 } 1860 write_in_progress++; 1861outloop: 1862 if (scp->term.esc) { 1863 scan_esc(scp, *ptr++); 1864 len--; 1865 } 1866 else if (PRINTABLE(*ptr)) { /* Print only printables */ 1867 int cnt = len <= (scp->xsize-scp->xpos) ? len : (scp->xsize-scp->xpos); 1868 u_short cur_attr = scp->term.cur_attr; 1869 u_short *cursor_pos = scp->cursor_pos; 1870 do { 1871 /* 1872 * gcc-2.6.3 generates poor (un)sign extension code. Casting the 1873 * pointers in the following to volatile should have no effect, 1874 * but in fact speeds up this inner loop from 26 to 18 cycles 1875 * (+ cache misses) on i486's. 1876 */ 1877#define UCVP(ucp) ((u_char volatile *)(ucp)) 1878 *cursor_pos++ = UCVP(scr_map)[*UCVP(ptr)] | cur_attr; 1879 ptr++; 1880 cnt--; 1881 } while (cnt && PRINTABLE(*ptr)); 1882 len -= (cursor_pos - scp->cursor_pos); 1883 scp->xpos += (cursor_pos - scp->cursor_pos); 1884 mark_for_update(scp, scp->cursor_pos - scp->scr_buf); 1885 mark_for_update(scp, cursor_pos - scp->scr_buf); 1886 scp->cursor_pos = cursor_pos; 1887 if (scp->xpos >= scp->xsize) { 1888 scp->xpos = 0; 1889 scp->ypos++; 1890 } 1891 } 1892 else { 1893 switch(*ptr) { 1894 case 0x07: 1895 do_bell(scp, scp->bell_pitch, scp->bell_duration); 1896 break; 1897 1898 case 0x08: /* non-destructive backspace */ 1899 if (scp->cursor_pos > scp->scr_buf) { 1900 mark_for_update(scp, scp->cursor_pos - scp->scr_buf); 1901 scp->cursor_pos--; 1902 mark_for_update(scp, scp->cursor_pos - scp->scr_buf); 1903 if (scp->xpos > 0) 1904 scp->xpos--; 1905 else { 1906 scp->xpos += scp->xsize - 1; 1907 scp->ypos--; 1908 } 1909 } 1910 break; 1911 1912 case 0x09: /* non-destructive tab */ 1913 mark_for_update(scp, scp->cursor_pos - scp->scr_buf); 1914 scp->cursor_pos += (8 - scp->xpos % 8u); 1915 mark_for_update(scp, scp->cursor_pos - scp->scr_buf); 1916 if ((scp->xpos += (8 - scp->xpos % 8u)) >= scp->xsize) { 1917 scp->xpos = 0; 1918 scp->ypos++; 1919 } 1920 break; 1921 1922 case 0x0a: /* newline, same pos */ 1923 mark_for_update(scp, scp->cursor_pos - scp->scr_buf); 1924 scp->cursor_pos += scp->xsize; 1925 mark_for_update(scp, scp->cursor_pos - scp->scr_buf); 1926 scp->ypos++; 1927 break; 1928 1929 case 0x0c: /* form feed, clears screen */ 1930 clear_screen(scp); 1931 break; 1932 1933 case 0x0d: /* return, return to pos 0 */ 1934 mark_for_update(scp, scp->cursor_pos - scp->scr_buf); 1935 scp->cursor_pos -= scp->xpos; 1936 mark_for_update(scp, scp->cursor_pos - scp->scr_buf); 1937 scp->xpos = 0; 1938 break; 1939 1940 case 0x1b: /* start escape sequence */ 1941 scp->term.esc = 1; 1942 scp->term.num_param = 0; 1943 break; 1944 } 1945 ptr++; len--; 1946 } 1947 /* do we have to scroll ?? */ 1948 if (scp->cursor_pos >= scp->scr_buf + scp->ysize * scp->xsize) { 1949 if (scp->history) { 1950 bcopyw(scp->scr_buf, scp->history_head, 1951 scp->xsize * sizeof(u_short)); 1952 scp->history_head += scp->xsize; 1953 if (scp->history_head + scp->xsize > 1954 scp->history + scp->history_size) 1955 scp->history_head = scp->history; 1956 } 1957 bcopyw(scp->scr_buf + scp->xsize, scp->scr_buf, 1958 scp->xsize * (scp->ysize - 1) * sizeof(u_short)); 1959 fillw(scp->term.cur_attr | scr_map[0x20], 1960 scp->scr_buf + scp->xsize * (scp->ysize - 1), 1961 scp->xsize); 1962 scp->cursor_pos -= scp->xsize; 1963 scp->ypos--; 1964 mark_all(scp); 1965 } 1966 if (len) 1967 goto outloop; 1968 write_in_progress--; 1969 if (delayed_next_scr) 1970 switch_scr(scp, delayed_next_scr - 1); 1971} 1972 1973static void 1974scinit(void) 1975{ 1976 u_short volatile *cp; 1977 u_short was; 1978 unsigned hw_cursor, startaddr; 1979 int i; 1980 1981 if (init_done) 1982 return; 1983 init_done = TRUE; 1984 /* 1985 * Finish defaulting crtc variables for a mono screen. Crtat is a 1986 * bogus common variable so that it can be shared with pcvt, so it 1987 * can't be statically initialized. XXX. 1988 */ 1989 Crtat = (u_short *)MONO_BUF; 1990 /* 1991 * If CGA memory seems to work, switch to color. 1992 */ 1993 cp = (u_short *)CGA_BUF; 1994 was = *cp; 1995 *cp = (u_short) 0xA55A; 1996 if (*cp == 0xA55A) { 1997 Crtat = (u_short *)cp; 1998 crtc_addr = COLOR_BASE; 1999 } 2000 *cp = was; 2001 2002 /* 2003 * Ensure a zero start address. This is mainly to recover after 2004 * switching from pcvt using userconfig(). The registers are r/o 2005 * for old hardware so it's too hard to relocate the active screen 2006 * memory. 2007 */ 2008 outb(crtc_addr, 12); 2009 outb(crtc_addr + 1, 0); 2010 outb(crtc_addr, 13); 2011 outb(crtc_addr + 1, 0); 2012 2013 /* extract cursor location */ 2014 outb(crtc_addr, 14); 2015 hw_cursor = inb(crtc_addr + 1) << 8; 2016 outb(crtc_addr, 15); 2017 hw_cursor |= inb(crtc_addr + 1); 2018 2019 /* move hardware cursor out of the way */ 2020 outb(crtc_addr, 14); 2021 outb(crtc_addr + 1, 0xff); 2022 outb(crtc_addr, 15); 2023 outb(crtc_addr + 1, 0xff); 2024 2025 /* is this a VGA or higher ? */ 2026 outb(crtc_addr, 7); 2027 if (inb(crtc_addr) == 7) { 2028 u_long pa; 2029 u_long segoff; 2030 2031 crtc_vga = TRUE; 2032 /* 2033 * Get the BIOS video mode pointer. 2034 */ 2035 segoff = *(u_long *)pa_to_va(0x4a8); 2036 pa = (((segoff & 0xffff0000) >> 12) + (segoff & 0xffff)); 2037 if (ISMAPPED(pa, sizeof(u_long))) { 2038 segoff = *(u_long *)pa_to_va(pa); 2039 pa = (((segoff & 0xffff0000) >> 12) + (segoff & 0xffff)); 2040 if (ISMAPPED(pa, 64)) 2041 video_mode_ptr = (char *)pa_to_va(pa); 2042 } 2043 } 2044 current_default = &user_default; 2045 console[0] = &main_console; 2046 init_scp(console[0]); 2047 console[0]->scr_buf = console[0]->mouse_pos = Crtat; 2048 console[0]->cursor_pos = Crtat + hw_cursor; 2049 console[0]->xpos = hw_cursor % COL; 2050 console[0]->ypos = hw_cursor / COL; 2051 cur_console = console[0]; 2052 for (i=1; i<MAXCONS; i++) 2053 console[i] = NULL; 2054 kernel_console.esc = 0; 2055 kernel_console.std_attr = kernel_default.std_attr; 2056 kernel_console.rev_attr = kernel_default.rev_attr; 2057 kernel_console.cur_attr = kernel_default.std_attr; 2058 /* initialize mapscrn array to a one to one map */ 2059 for (i=0; i<sizeof(scr_map); i++) 2060 scr_map[i] = i; 2061} 2062 2063static scr_stat 2064*alloc_scp() 2065{ 2066 scr_stat *scp; 2067 2068 scp = (scr_stat *)malloc(sizeof(scr_stat), M_DEVBUF, M_WAITOK); 2069 init_scp(scp); 2070 scp->scr_buf = scp->cursor_pos = scp->scr_buf = scp->mouse_pos = 2071 (u_short *)malloc(scp->xsize*scp->ysize*sizeof(u_short), 2072 M_DEVBUF, M_WAITOK); 2073 scp->history_head = scp->history_pos = scp->history = 2074 (u_short *)malloc(scp->history_size*sizeof(u_short), 2075 M_DEVBUF, M_WAITOK); 2076 bzero(scp->history_head, scp->history_size*sizeof(u_short)); 2077 if (crtc_vga && video_mode_ptr) 2078 set_mode(scp); 2079 clear_screen(scp); 2080 return scp; 2081} 2082 2083static void 2084init_scp(scr_stat *scp) 2085{ 2086 scp->mode = M_VGA_C80x25; 2087 scp->font = FONT_16; 2088 scp->xsize = COL; 2089 scp->ysize = ROW; 2090 scp->start = COL * ROW; 2091 scp->end = 0; 2092 scp->term.esc = 0; 2093 scp->term.std_attr = current_default->std_attr; 2094 scp->term.rev_attr = current_default->rev_attr; 2095 scp->term.cur_attr = scp->term.std_attr; 2096 scp->border = BG_BLACK; 2097 scp->cursor_start = *(char *)pa_to_va(0x461); 2098 scp->cursor_end = *(char *)pa_to_va(0x460); 2099 scp->mouse_xpos = scp->mouse_ypos = 0; 2100 scp->bell_pitch = BELL_PITCH; 2101 scp->bell_duration = BELL_DURATION; 2102 scp->status = (*(char *)pa_to_va(0x417) & 0x20) ? NLKED : 0; 2103 scp->status |= CURSOR_ENABLED; 2104 scp->pid = 0; 2105 scp->proc = NULL; 2106 scp->smode.mode = VT_AUTO; 2107 scp->history_head = scp->history_pos = scp->history = NULL; 2108 scp->history_size = HISTORY_SIZE; 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 2125static void 2126update_leds(int which) 2127{ 2128 int s; 2129 static u_char xlate_leds[8] = { 0, 4, 2, 6, 1, 5, 3, 7 }; 2130 2131 /* replace CAPS led with ALTGR led for ALTGR keyboards */ 2132 if (key_map.n_keys > ALTGR_OFFSET) { 2133 if (which & ALKED) 2134 which |= CLKED; 2135 else 2136 which &= ~CLKED; 2137 } 2138 s = spltty(); 2139 kbd_cmd(KB_SETLEDS); 2140 kbd_cmd(xlate_leds[which & LED_MASK]); 2141 splx(s); 2142} 2143 2144static void 2145history_to_screen(scr_stat *scp) 2146{ 2147 int i; 2148 2149 for (i=0; i<scp->ysize; i++) 2150 bcopyw(scp->history + (((scp->history_pos - scp->history) + 2151 scp->history_size-((i+1)*scp->xsize))%scp->history_size), 2152 scp->scr_buf + (scp->xsize * (scp->ysize-1 - i)), 2153 scp->xsize * sizeof(u_short)); 2154 mark_all(scp); 2155} 2156 2157static int 2158history_up_line(scr_stat *scp) 2159{ 2160 if (WRAPHIST(scp, scp->history_pos, -(scp->xsize*scp->ysize)) != 2161 scp->history_head) { 2162 scp->history_pos = WRAPHIST(scp, scp->history_pos, -scp->xsize); 2163 history_to_screen(scp); 2164 return 0; 2165 } 2166 else 2167 return -1; 2168} 2169 2170static int 2171history_down_line(scr_stat *scp) 2172{ 2173 if (scp->history_pos != scp->history_head) { 2174 scp->history_pos = WRAPHIST(scp, scp->history_pos, scp->xsize); 2175 history_to_screen(scp); 2176 return 0; 2177 } 2178 else 2179 return -1; 2180} 2181 2182/* 2183 * scgetc(noblock) - get character from keyboard. 2184 * If noblock = 0 wait until a key is pressed. 2185 * Else return NOKEY. 2186 */ 2187u_int 2188scgetc(int noblock) 2189{ 2190 u_char scancode, keycode; 2191 u_int state, action; 2192 struct key_t *key; 2193 static u_char esc_flag = 0, compose = 0; 2194 static u_int chr = 0; 2195 2196next_code: 2197 kbd_wait(); 2198 /* First see if there is something in the keyboard port */ 2199 if (inb(KB_STAT) & KB_BUF_FULL) 2200 scancode = inb(KB_DATA); 2201 else if (noblock) 2202 return(NOKEY); 2203 else 2204 goto next_code; 2205 2206 add_keyboard_randomness(scancode); 2207 2208 if (cur_console->status & KBD_RAW_MODE) 2209 return scancode; 2210#if ASYNCH 2211 if (scancode == KB_ACK || scancode == KB_RESEND) { 2212 kbd_reply = scancode; 2213 if (noblock) 2214 return(NOKEY); 2215 goto next_code; 2216 } 2217#endif 2218 keycode = scancode & 0x7F; 2219 switch (esc_flag) { 2220 case 0x00: /* normal scancode */ 2221 switch(scancode) { 2222 case 0xB8: /* left alt (compose key) */ 2223 if (compose) { 2224 compose = 0; 2225 if (chr > 255) { 2226 do_bell(cur_console, 2227 BELL_PITCH, BELL_DURATION); 2228 chr = 0; 2229 } 2230 } 2231 break; 2232 case 0x38: 2233 if (!compose) { 2234 compose = 1; 2235 chr = 0; 2236 } 2237 break; 2238 case 0xE0: 2239 case 0xE1: 2240 esc_flag = scancode; 2241 goto next_code; 2242 } 2243 break; 2244 case 0xE0: /* 0xE0 prefix */ 2245 esc_flag = 0; 2246 switch (keycode) { 2247 case 0x1C: /* right enter key */ 2248 keycode = 0x59; 2249 break; 2250 case 0x1D: /* right ctrl key */ 2251 keycode = 0x5A; 2252 break; 2253 case 0x35: /* keypad divide key */ 2254 keycode = 0x5B; 2255 break; 2256 case 0x37: /* print scrn key */ 2257 keycode = 0x5C; 2258 break; 2259 case 0x38: /* right alt key (alt gr) */ 2260 keycode = 0x5D; 2261 break; 2262 case 0x47: /* grey home key */ 2263 keycode = 0x5E; 2264 break; 2265 case 0x48: /* grey up arrow key */ 2266 keycode = 0x5F; 2267 break; 2268 case 0x49: /* grey page up key */ 2269 keycode = 0x60; 2270 break; 2271 case 0x4B: /* grey left arrow key */ 2272 keycode = 0x61; 2273 break; 2274 case 0x4D: /* grey right arrow key */ 2275 keycode = 0x62; 2276 break; 2277 case 0x4F: /* grey end key */ 2278 keycode = 0x63; 2279 break; 2280 case 0x50: /* grey down arrow key */ 2281 keycode = 0x64; 2282 break; 2283 case 0x51: /* grey page down key */ 2284 keycode = 0x65; 2285 break; 2286 case 0x52: /* grey insert key */ 2287 keycode = 0x66; 2288 break; 2289 case 0x53: /* grey delete key */ 2290 keycode = 0x67; 2291 break; 2292 2293 /* the following 3 are only used on the MS "Natural" keyboard */ 2294 case 0x5b: /* left Window key */ 2295 keycode = 0x69; 2296 break; 2297 case 0x5c: /* right Window key */ 2298 keycode = 0x6a; 2299 break; 2300 case 0x5d: /* menu key */ 2301 keycode = 0x6b; 2302 break; 2303 default: /* ignore everything else */ 2304 goto next_code; 2305 } 2306 break; 2307 case 0xE1: /* 0xE1 prefix */ 2308 esc_flag = 0; 2309 if (keycode == 0x1D) 2310 esc_flag = 0x1D; 2311 goto next_code; 2312 /* NOT REACHED */ 2313 case 0x1D: /* pause / break */ 2314 esc_flag = 0; 2315 if (keycode != 0x45) 2316 goto next_code; 2317 keycode = 0x68; 2318 break; 2319 } 2320 2321 /* if scroll-lock pressed allow history browsing */ 2322 if (cur_console->history && cur_console->status & SLKED) { 2323 int i; 2324 2325 cur_console->status &= ~CURSOR_ENABLED; 2326 if (!(cur_console->status & BUFFER_SAVED)) { 2327 cur_console->status |= BUFFER_SAVED; 2328 cur_console->history_save = cur_console->history_head; 2329 2330 /* copy screen into top of history buffer */ 2331 for (i=0; i<cur_console->ysize; i++) { 2332 bcopyw(cur_console->scr_buf + (cur_console->xsize * i), 2333 cur_console->history_head, 2334 cur_console->xsize * sizeof(u_short)); 2335 cur_console->history_head += cur_console->xsize; 2336 if (cur_console->history_head + cur_console->xsize > 2337 cur_console->history + cur_console->history_size) 2338 cur_console->history_head=cur_console->history; 2339 } 2340 cur_console->history_pos = cur_console->history_head; 2341 history_to_screen(cur_console); 2342 } 2343 switch (scancode) { 2344 case 0x47: /* home key */ 2345 cur_console->history_pos = cur_console->history_head; 2346 history_to_screen(cur_console); 2347 goto next_code; 2348 2349 case 0x4F: /* end key */ 2350 cur_console->history_pos = 2351 WRAPHIST(cur_console, cur_console->history_head, 2352 cur_console->xsize*cur_console->ysize); 2353 history_to_screen(cur_console); 2354 goto next_code; 2355 2356 case 0x48: /* up arrow key */ 2357 if (history_up_line(cur_console)) 2358 do_bell(cur_console, BELL_PITCH, BELL_DURATION); 2359 goto next_code; 2360 2361 case 0x50: /* down arrow key */ 2362 if (history_down_line(cur_console)) 2363 do_bell(cur_console, BELL_PITCH, BELL_DURATION); 2364 goto next_code; 2365 2366 case 0x49: /* page up key */ 2367 for (i=0; i<cur_console->ysize; i++) 2368 if (history_up_line(cur_console)) { 2369 do_bell(cur_console, BELL_PITCH, BELL_DURATION); 2370 break; 2371 } 2372 goto next_code; 2373 2374 case 0x51: /* page down key */ 2375 for (i=0; i<cur_console->ysize; i++) 2376 if (history_down_line(cur_console)) { 2377 do_bell(cur_console, BELL_PITCH, BELL_DURATION); 2378 break; 2379 } 2380 goto next_code; 2381 } 2382 } 2383 2384 if (compose) { 2385 switch (scancode) { 2386 /* key pressed process it */ 2387 case 0x47: case 0x48: case 0x49: /* keypad 7,8,9 */ 2388 chr = (scancode - 0x40) + chr*10; 2389 goto next_code; 2390 case 0x4B: case 0x4C: case 0x4D: /* keypad 4,5,6 */ 2391 chr = (scancode - 0x47) + chr*10; 2392 goto next_code; 2393 case 0x4F: case 0x50: case 0x51: /* keypad 1,2,3 */ 2394 chr = (scancode - 0x4E) + chr*10; 2395 goto next_code; 2396 case 0x52: /* keypad 0 */ 2397 chr *= 10; 2398 goto next_code; 2399 2400 /* key release, no interest here */ 2401 case 0xC7: case 0xC8: case 0xC9: /* keypad 7,8,9 */ 2402 case 0xCB: case 0xCC: case 0xCD: /* keypad 4,5,6 */ 2403 case 0xCF: case 0xD0: case 0xD1: /* keypad 1,2,3 */ 2404 case 0xD2: /* keypad 0 */ 2405 goto next_code; 2406 2407 case 0x38: /* left alt key */ 2408 break; 2409 default: 2410 if (chr) { 2411 compose = chr = 0; 2412 do_bell(cur_console, BELL_PITCH, BELL_DURATION); 2413 goto next_code; 2414 } 2415 break; 2416 } 2417 } 2418 2419 state = (shfts ? 1 : 0 ) | (2 * (ctls ? 1 : 0)) | (4 * (alts ? 1 : 0)); 2420 if ((!agrs && (cur_console->status & ALKED)) 2421 || (agrs && !(cur_console->status & ALKED))) 2422 keycode += ALTGR_OFFSET; 2423 key = &key_map.key[keycode]; 2424 if ( ((key->flgs & FLAG_LOCK_C) && (cur_console->status & CLKED)) 2425 || ((key->flgs & FLAG_LOCK_N) && (cur_console->status & NLKED)) ) 2426 state ^= 1; 2427 2428 /* Check for make/break */ 2429 action = key->map[state]; 2430 if (scancode & 0x80) { /* key released */ 2431 if (key->spcl & 0x80) { 2432 switch (action) { 2433 case LSH: 2434 shfts &= ~1; 2435 break; 2436 case RSH: 2437 shfts &= ~2; 2438 break; 2439 case LCTR: 2440 ctls &= ~1; 2441 break; 2442 case RCTR: 2443 ctls &= ~2; 2444 break; 2445 case LALT: 2446 alts &= ~1; 2447 break; 2448 case RALT: 2449 alts &= ~2; 2450 break; 2451 case NLK: 2452 nlkcnt = 0; 2453 break; 2454 case CLK: 2455 clkcnt = 0; 2456 break; 2457 case SLK: 2458 slkcnt = 0; 2459 break; 2460 case ASH: 2461 agrs = 0; 2462 break; 2463 case ALK: 2464 alkcnt = 0; 2465 break; 2466 case META: 2467 metas = 0; 2468 break; 2469 } 2470 } 2471 if (chr && !compose) { 2472 action = chr; 2473 chr = 0; 2474 return(action); 2475 } 2476 } else { 2477 /* key pressed */ 2478 if (key->spcl & (0x80>>state)) { 2479 switch (action) { 2480 /* LOCKING KEYS */ 2481 case NLK: 2482 if (!nlkcnt) { 2483 nlkcnt++; 2484 if (cur_console->status & NLKED) 2485 cur_console->status &= ~NLKED; 2486 else 2487 cur_console->status |= NLKED; 2488 update_leds(cur_console->status); 2489 } 2490 break; 2491 case CLK: 2492 if (!clkcnt) { 2493 clkcnt++; 2494 if (cur_console->status & CLKED) 2495 cur_console->status &= ~CLKED; 2496 else 2497 cur_console->status |= CLKED; 2498 update_leds(cur_console->status); 2499 } 2500 break; 2501 case SLK: 2502 if (!slkcnt) { 2503 slkcnt++; 2504 if (cur_console->status & SLKED) { 2505 cur_console->status &= ~SLKED; 2506 if (cur_console->status & BUFFER_SAVED){ 2507 int i; 2508 u_short *ptr = cur_console->history_save; 2509 2510 for (i=0; i<cur_console->ysize; i++) { 2511 bcopyw(ptr, 2512 cur_console->scr_buf + 2513 (cur_console->xsize*i), 2514 cur_console->xsize * sizeof(u_short)); 2515 ptr += cur_console->xsize; 2516 if (ptr + cur_console->xsize > 2517 cur_console->history + 2518 cur_console->history_size) 2519 ptr = cur_console->history; 2520 } 2521 cur_console->status &= ~BUFFER_SAVED; 2522 cur_console->history_head=cur_console->history_save; 2523 cur_console->status |= CURSOR_ENABLED; 2524 mark_all(cur_console); 2525 } 2526 scstart(VIRTUAL_TTY(get_scr_num())); 2527 } 2528 else 2529 cur_console->status |= SLKED; 2530 update_leds(cur_console->status); 2531 } 2532 break; 2533 case ALK: 2534 if (!alkcnt) { 2535 alkcnt++; 2536 if (cur_console->status & ALKED) 2537 cur_console->status &= ~ALKED; 2538 else 2539 cur_console->status |= ALKED; 2540 update_leds(cur_console->status); 2541 } 2542 break; 2543 2544 /* NON-LOCKING KEYS */ 2545 case NOP: 2546 break; 2547 case RBT: 2548 shutdown_nice(); 2549 break; 2550 case SUSP: 2551#if NAPM > 0 2552 apm_suspend(); 2553#endif 2554 break; 2555 2556 case DBG: 2557#ifdef DDB /* try to switch to console 0 */ 2558 if (cur_console->smode.mode == VT_AUTO && 2559 console[0]->smode.mode == VT_AUTO) 2560 switch_scr(cur_console, 0); 2561 Debugger("manual escape to debugger"); 2562 return(NOKEY); 2563#else 2564 printf("No debugger in kernel\n"); 2565#endif 2566 break; 2567 case LSH: 2568 shfts |= 1; 2569 break; 2570 case RSH: 2571 shfts |= 2; 2572 break; 2573 case LCTR: 2574 ctls |= 1; 2575 break; 2576 case RCTR: 2577 ctls |= 2; 2578 break; 2579 case LALT: 2580 alts |= 1; 2581 break; 2582 case RALT: 2583 alts |= 2; 2584 break; 2585 case ASH: 2586 agrs = 1; 2587 break; 2588 case META: 2589 metas = 1; 2590 break; 2591 case NEXT: 2592 switch_scr(cur_console, (get_scr_num() + 1) % MAXCONS); 2593 break; 2594 case BTAB: 2595 return(BKEY); 2596 default: 2597 if (action >= F_SCR && action <= L_SCR) { 2598 switch_scr(cur_console, action - F_SCR); 2599 break; 2600 } 2601 if (action >= F_FN && action <= L_FN) 2602 action |= FKEY; 2603 return(action); 2604 } 2605 } 2606 else { 2607 if (metas) 2608 action |= MKEY; 2609 return(action); 2610 } 2611 } 2612 goto next_code; 2613} 2614 2615int 2616scmmap(dev_t dev, int offset, int nprot) 2617{ 2618 if (offset > 0x20000 - PAGE_SIZE) 2619 return -1; 2620 return i386_btop((VIDEOMEM + offset)); 2621} 2622 2623static void 2624kbd_wait(void) 2625{ 2626 int i = 1000; 2627 2628 while (i--) { 2629 if ((inb(KB_STAT) & KB_READY) == 0) 2630 break; 2631 DELAY (10); 2632 } 2633} 2634 2635static void 2636kbd_cmd(u_char command) 2637{ 2638 int retry = 5; 2639 do { 2640 int i = 100000; 2641 2642 kbd_wait(); 2643#if ASYNCH 2644 kbd_reply = 0; 2645 outb(KB_DATA, command); 2646 while (i--) { 2647 if (kbd_reply == KB_ACK) 2648 return; 2649 if (kbd_reply == KB_RESEND) 2650 break; 2651 } 2652#else 2653 outb(KB_DATA, command); 2654 while (i--) { 2655 if (inb(KB_STAT) & KB_BUF_FULL) { 2656 int val; 2657 DELAY(10); 2658 val = inb(KB_DATA); 2659 if (val == KB_ACK) 2660 return; 2661 if (val == KB_RESEND) 2662 break; 2663 } 2664 } 2665#endif 2666 } while (retry--); 2667} 2668 2669static void 2670set_mode(scr_stat *scp) 2671{ 2672 char *modetable; 2673 char special_modetable[64]; 2674 int mode, font_size; 2675 2676 if (scp != cur_console) 2677 return; 2678 2679 /* setup video hardware for the given mode */ 2680 switch (scp->mode) { 2681 case M_VGA_M80x60: 2682 bcopyw(video_mode_ptr+(64*M_VGA_M80x25),&special_modetable, 64); 2683 goto special_80x60; 2684 2685 case M_VGA_C80x60: 2686 bcopyw(video_mode_ptr+(64*M_VGA_C80x25),&special_modetable, 64); 2687special_80x60: 2688 special_modetable[2] = 0x08; 2689 special_modetable[19] = 0x47; 2690 goto special_480l; 2691 2692 case M_VGA_M80x30: 2693 bcopyw(video_mode_ptr+(64*M_VGA_M80x25),&special_modetable, 64); 2694 goto special_80x30; 2695 2696 case M_VGA_C80x30: 2697 bcopyw(video_mode_ptr+(64*M_VGA_C80x25),&special_modetable, 64); 2698special_80x30: 2699 special_modetable[19] = 0x4f; 2700special_480l: 2701 special_modetable[9] |= 0xc0; 2702 special_modetable[16] = 0x08; 2703 special_modetable[17] = 0x3e; 2704 special_modetable[26] = 0xea; 2705 special_modetable[28] = 0xdf; 2706 special_modetable[31] = 0xe7; 2707 special_modetable[32] = 0x04; 2708 modetable = special_modetable; 2709 goto setup_mode; 2710 2711 case M_ENH_B80x43: 2712 bcopyw(video_mode_ptr+(64*M_ENH_B80x25),&special_modetable, 64); 2713 goto special_80x43; 2714 2715 case M_ENH_C80x43: 2716 bcopyw(video_mode_ptr+(64*M_ENH_C80x25),&special_modetable, 64); 2717special_80x43: 2718 special_modetable[28] = 87; 2719 goto special_80x50; 2720 2721 case M_VGA_M80x50: 2722 bcopyw(video_mode_ptr+(64*M_VGA_M80x25),&special_modetable, 64); 2723 goto special_80x50; 2724 2725 case M_VGA_C80x50: 2726 bcopyw(video_mode_ptr+(64*M_VGA_C80x25),&special_modetable, 64); 2727special_80x50: 2728 special_modetable[2] = 8; 2729 special_modetable[19] = 7; 2730 modetable = special_modetable; 2731 goto setup_mode; 2732 2733 case M_VGA_C40x25: case M_VGA_C80x25: 2734 case M_VGA_M80x25: 2735 case M_B40x25: case M_C40x25: 2736 case M_B80x25: case M_C80x25: 2737 case M_ENH_B40x25: case M_ENH_C40x25: 2738 case M_ENH_B80x25: case M_ENH_C80x25: 2739 2740 modetable = video_mode_ptr + (scp->mode * 64); 2741setup_mode: 2742 set_vgaregs(modetable); 2743 font_size = *(modetable + 2); 2744 2745 /* set font type (size) */ 2746 switch (font_size) { 2747 case 0x10: 2748 outb(TSIDX, 0x03); outb(TSREG, 0x00); /* font 0 */ 2749 scp->font = FONT_16; 2750 break; 2751 case 0x0E: 2752 outb(TSIDX, 0x03); outb(TSREG, 0x05); /* font 1 */ 2753 scp->font = FONT_14; 2754 break; 2755 default: 2756 case 0x08: 2757 outb(TSIDX, 0x03); outb(TSREG, 0x0A); /* font 2 */ 2758 scp->font = FONT_8; 2759 break; 2760 } 2761 if (configuration & CHAR_CURSOR) 2762 set_destructive_cursor(scp, TRUE); 2763 break; 2764 2765 case M_BG320: case M_CG320: case M_BG640: 2766 case M_CG320_D: case M_CG640_E: 2767 case M_CG640x350: case M_ENH_CG640: 2768 case M_BG640x480: case M_CG640x480: case M_VGA_CG320: 2769 2770 set_vgaregs(video_mode_ptr + (scp->mode * 64)); 2771 break; 2772 2773 default: 2774 /* call user defined function XXX */ 2775 break; 2776 } 2777 2778 /* set border color for this (virtual) console */ 2779 set_border(scp->border); 2780 return; 2781} 2782 2783void 2784set_border(int color) 2785{ 2786 inb(crtc_addr+6); /* reset flip-flop */ 2787 outb(ATC, 0x11); outb(ATC, color); 2788 inb(crtc_addr+6); /* reset flip-flop */ 2789 outb(ATC, 0x20); /* enable Palette */ 2790} 2791 2792static void 2793set_vgaregs(char *modetable) 2794{ 2795 int i, s = splhigh(); 2796 2797 outb(TSIDX, 0x00); outb(TSREG, 0x01); /* stop sequencer */ 2798 outb(TSIDX, 0x07); outb(TSREG, 0x00); /* unlock registers */ 2799 for (i=0; i<4; i++) { /* program sequencer */ 2800 outb(TSIDX, i+1); 2801 outb(TSREG, modetable[i+5]); 2802 } 2803 outb(MISC, modetable[9]); /* set dot-clock */ 2804 outb(TSIDX, 0x00); outb(TSREG, 0x03); /* start sequencer */ 2805 outb(crtc_addr, 0x11); 2806 outb(crtc_addr+1, inb(crtc_addr+1) & 0x7F); 2807 for (i=0; i<25; i++) { /* program crtc */ 2808 outb(crtc_addr, i); 2809 if (i == 14 || i == 15) /* no hardware cursor */ 2810 outb(crtc_addr+1, 0xff); 2811 else 2812 outb(crtc_addr+1, modetable[i+10]); 2813 } 2814 inb(crtc_addr+6); /* reset flip-flop */ 2815 for (i=0; i<20; i++) { /* program attribute ctrl */ 2816 outb(ATC, i); 2817 outb(ATC, modetable[i+35]); 2818 } 2819 for (i=0; i<9; i++) { /* program graph data ctrl */ 2820 outb(GDCIDX, i); 2821 outb(GDCREG, modetable[i+55]); 2822 } 2823 inb(crtc_addr+6); /* reset flip-flop */ 2824 outb(ATC ,0x20); /* enable palette */ 2825 splx(s); 2826} 2827 2828static void 2829set_font_mode() 2830{ 2831 /* setup vga for loading fonts (graphics plane mode) */ 2832 inb(crtc_addr+6); 2833 outb(ATC, 0x30); outb(ATC, 0x01); 2834#if SLOW_VGA 2835 outb(TSIDX, 0x02); outb(TSREG, 0x04); 2836 outb(TSIDX, 0x04); outb(TSREG, 0x06); 2837 outb(GDCIDX, 0x04); outb(GDCREG, 0x02); 2838 outb(GDCIDX, 0x05); outb(GDCREG, 0x00); 2839 outb(GDCIDX, 0x06); outb(GDCREG, 0x05); 2840#else 2841 outw(TSIDX, 0x0402); 2842 outw(TSIDX, 0x0604); 2843 outw(GDCIDX, 0x0204); 2844 outw(GDCIDX, 0x0005); 2845 outw(GDCIDX, 0x0506); /* addr = a0000, 64kb */ 2846#endif 2847} 2848 2849static void 2850set_normal_mode() 2851{ 2852 int s = splhigh(); 2853 2854 /* setup vga for normal operation mode again */ 2855 inb(crtc_addr+6); 2856 outb(ATC, 0x30); outb(ATC, 0x0C); 2857#if SLOW_VGA 2858 outb(TSIDX, 0x02); outb(TSREG, 0x03); 2859 outb(TSIDX, 0x04); outb(TSREG, 0x02); 2860 outb(GDCIDX, 0x04); outb(GDCREG, 0x00); 2861 outb(GDCIDX, 0x05); outb(GDCREG, 0x10); 2862 if (crtc_addr == MONO_BASE) { 2863 outb(GDCIDX, 0x06); outb(GDCREG, 0x0A); /* addr = b0000, 32kb */ 2864 } 2865 else { 2866 outb(GDCIDX, 0x06); outb(GDCREG, 0x0E); /* addr = b8000, 32kb */ 2867 } 2868#else 2869 outw(TSIDX, 0x0302); 2870 outw(TSIDX, 0x0204); 2871 outw(GDCIDX, 0x0004); 2872 outw(GDCIDX, 0x1005); 2873 if (crtc_addr == MONO_BASE) 2874 outw(GDCIDX, 0x0A06); /* addr = b0000, 32kb */ 2875 else 2876 outw(GDCIDX, 0x0E06); /* addr = b8000, 32kb */ 2877#endif 2878 splx(s); 2879} 2880 2881static void 2882copy_font(int operation, int font_type, char* font_image) 2883{ 2884 int ch, line, segment, fontsize; 2885 u_char val; 2886 2887 switch (font_type) { 2888 default: 2889 case FONT_8: 2890 segment = 0x8000; 2891 fontsize = 8; 2892 break; 2893 case FONT_14: 2894 segment = 0x4000; 2895 fontsize = 14; 2896 break; 2897 case FONT_16: 2898 segment = 0x0000; 2899 fontsize = 16; 2900 break; 2901 } 2902 outb(TSIDX, 0x01); val = inb(TSREG); /* disable screen */ 2903 outb(TSIDX, 0x01); outb(TSREG, val | 0x20); 2904 set_font_mode(); 2905 for (ch=0; ch < 256; ch++) 2906 for (line=0; line < fontsize; line++) 2907 if (operation) 2908 *(char *)pa_to_va(VIDEOMEM+(segment)+(ch*32)+line) = 2909 font_image[(ch*fontsize)+line]; 2910 else 2911 font_image[(ch*fontsize)+line] = 2912 *(char *)pa_to_va(VIDEOMEM+(segment)+(ch*32)+line); 2913 set_normal_mode(); 2914 outb(TSIDX, 0x01); outb(TSREG, val & 0xDF); /* enable screen */ 2915} 2916 2917static void 2918set_destructive_cursor(scr_stat *scp, int force) 2919{ 2920 u_char cursor[32]; 2921 caddr_t address; 2922 int i, font_size; 2923 char *font_buffer; 2924 static u_char old_saveunder = DEAD_CHAR; 2925 2926 if (!force && (scp->cursor_saveunder & 0xFF) == old_saveunder) 2927 return; 2928 old_saveunder = force ? DEAD_CHAR : scp->cursor_saveunder & 0xFF; 2929 switch (scp->font) { 2930 default: 2931 case FONT_8: 2932 font_size = 8; 2933 font_buffer = font_8; 2934 address = (caddr_t)VIDEOMEM + 0x8000; 2935 break; 2936 case FONT_14: 2937 font_size = 14; 2938 font_buffer = font_14; 2939 address = (caddr_t)VIDEOMEM + 0x4000; 2940 break; 2941 case FONT_16: 2942 font_size = 16; 2943 font_buffer = font_16; 2944 address = (caddr_t)VIDEOMEM; 2945 break; 2946 } 2947 bcopyw(font_buffer + ((scp->cursor_saveunder & 0xff) * font_size), 2948 cursor, font_size); 2949 for (i=0; i<32; i++) 2950 if ((i >= scp->cursor_start && i <= scp->cursor_end) || 2951 (scp->cursor_start >= font_size && i == font_size - 1)) 2952 cursor[i] |= 0xff; 2953 while (!(inb(crtc_addr+6) & 0x08)) /* wait for vertical retrace */ ; 2954 set_font_mode(); 2955 bcopy(cursor, (char *)pa_to_va(address) + DEAD_CHAR * 32, 32); 2956 set_normal_mode(); 2957} 2958 2959static void 2960draw_mouse_image(scr_stat *scp) 2961{ 2962 caddr_t address; 2963 int i, font_size; 2964 char *font_buffer; 2965 u_short buffer[32]; 2966 u_short xoffset, yoffset; 2967 u_short *crt_pos = Crtat + (scp->mouse_pos - scp->scr_buf); 2968 2969 xoffset = scp->mouse_xpos % 8; 2970 switch (scp->font) { 2971 default: 2972 case FONT_8: 2973 font_size = 8; 2974 font_buffer = font_8; 2975 yoffset = scp->mouse_ypos % 8; 2976 address = (caddr_t)VIDEOMEM + 0x8000; 2977 break; 2978 case FONT_14: 2979 font_size = 14; 2980 font_buffer = font_14; 2981 yoffset = scp->mouse_ypos % 14; 2982 address = (caddr_t)VIDEOMEM + 0x4000; 2983 break; 2984 case FONT_16: 2985 font_size = 16; 2986 font_buffer = font_16; 2987 yoffset = scp->mouse_ypos % 16; 2988 address = (caddr_t)VIDEOMEM; 2989 break; 2990 } 2991 2992 bcopyw(font_buffer + ((*(scp->mouse_pos) & 0xff) * font_size), 2993 &scp->mouse_cursor[0], font_size); 2994 bcopyw(font_buffer + ((*(scp->mouse_pos+1) & 0xff) * font_size), 2995 &scp->mouse_cursor[32], font_size); 2996 bcopyw(font_buffer + ((*(scp->mouse_pos+scp->xsize) & 0xff) * font_size), 2997 &scp->mouse_cursor[64], font_size); 2998 bcopyw(font_buffer + ((*(scp->mouse_pos+scp->xsize+1) & 0xff) * font_size), 2999 &scp->mouse_cursor[96], font_size); 3000 3001 for (i=0; i<font_size; i++) { 3002 buffer[i] = scp->mouse_cursor[i]<<8 | scp->mouse_cursor[i+32]; 3003 buffer[i+font_size]=scp->mouse_cursor[i+64]<<8|scp->mouse_cursor[i+96]; 3004 } 3005 for (i=0; i<16; i++) { 3006 buffer[i+yoffset] = 3007 ( buffer[i+yoffset] & ~(mouse_and_mask[i] >> xoffset)) 3008 | (mouse_or_mask[i] >> xoffset); 3009 } 3010 for (i=0; i<font_size; i++) { 3011 scp->mouse_cursor[i] = (buffer[i] & 0xff00) >> 8; 3012 scp->mouse_cursor[i+32] = buffer[i] & 0xff; 3013 scp->mouse_cursor[i+64] = (buffer[i+font_size] & 0xff00) >> 8; 3014 scp->mouse_cursor[i+96] = buffer[i+font_size] & 0xff; 3015 } 3016 if (scp->status & UPDATE_MOUSE) { 3017 u_short *ptr = scp->scr_buf + (scp->mouse_oldpos - Crtat); 3018 3019 if (crt_pos != scp->mouse_oldpos) { 3020 *(scp->mouse_oldpos) = scp->mouse_saveunder[0]; 3021 *(scp->mouse_oldpos+1) = scp->mouse_saveunder[1]; 3022 *(scp->mouse_oldpos+scp->xsize) = scp->mouse_saveunder[2]; 3023 *(scp->mouse_oldpos+scp->xsize+1) = scp->mouse_saveunder[3]; 3024 } 3025 scp->mouse_saveunder[0] = *(scp->mouse_pos); 3026 scp->mouse_saveunder[1] = *(scp->mouse_pos+1); 3027 scp->mouse_saveunder[2] = *(scp->mouse_pos+scp->xsize); 3028 scp->mouse_saveunder[3] = *(scp->mouse_pos+scp->xsize+1); 3029 if ((scp->cursor_pos == (ptr)) || 3030 (scp->cursor_pos == (ptr+1)) || 3031 (scp->cursor_pos == (ptr+scp->xsize)) || 3032 (scp->cursor_pos == (ptr+scp->xsize+1)) || 3033 (scp->cursor_pos == (scp->mouse_pos)) || 3034 (scp->cursor_pos == (scp->mouse_pos+1)) || 3035 (scp->cursor_pos == (scp->mouse_pos+scp->xsize)) || 3036 (scp->cursor_pos == (scp->mouse_pos+scp->xsize+1))) 3037 scp->status &= ~CURSOR_SHOWN; 3038 } 3039 scp->mouse_oldpos = crt_pos; 3040 while (!(inb(crtc_addr+6) & 0x08)) /* wait for vertical retrace */ ; 3041 *(crt_pos) = *(scp->mouse_pos)&0xff00|0xd0; 3042 *(crt_pos+1) = *(scp->mouse_pos+1)&0xff00|0xd1; 3043 *(crt_pos+scp->xsize) = *(scp->mouse_pos+scp->xsize)&0xff00|0xd2; 3044 *(crt_pos+scp->xsize+1) = *(scp->mouse_pos+scp->xsize+1)&0xff00|0xd3; 3045 set_font_mode(); 3046 bcopy(scp->mouse_cursor, (char *)pa_to_va(address) + 0xd0 * 32, 128); 3047 set_normal_mode(); 3048} 3049 3050static void 3051save_palette(void) 3052{ 3053 int i; 3054 3055 outb(PALRADR, 0x00); 3056 for (i=0x00; i<0x300; i++) 3057 palette[i] = inb(PALDATA); 3058 inb(crtc_addr+6); /* reset flip/flop */ 3059} 3060 3061void 3062load_palette(void) 3063{ 3064 int i; 3065 3066 outb(PIXMASK, 0xFF); /* no pixelmask */ 3067 outb(PALWADR, 0x00); 3068 for (i=0x00; i<0x300; i++) 3069 outb(PALDATA, palette[i]); 3070 inb(crtc_addr+6); /* reset flip/flop */ 3071 outb(ATC, 0x20); /* enable palette */ 3072} 3073 3074static void 3075do_bell(scr_stat *scp, int pitch, int duration) 3076{ 3077 if (scp == cur_console) { 3078 if (configuration & VISUAL_BELL) { 3079 if (blink_in_progress) 3080 return; 3081 blink_in_progress = 4; 3082 blink_screen(scp); 3083 timeout((timeout_func_t)blink_screen, scp, hz/10); 3084 } 3085 else 3086 sysbeep(pitch, duration); 3087 } 3088} 3089 3090static void 3091blink_screen(scr_stat *scp) 3092{ 3093 if (blink_in_progress > 1) { 3094 if (blink_in_progress & 1) 3095 fillw(kernel_default.std_attr | scr_map[0x20], 3096 Crtat, scp->xsize * scp->ysize); 3097 else 3098 fillw(kernel_default.rev_attr | scr_map[0x20], 3099 Crtat, scp->xsize * scp->ysize); 3100 blink_in_progress--; 3101 timeout((timeout_func_t)blink_screen, scp, hz/10); 3102 } 3103 else { 3104 blink_in_progress = FALSE; 3105 mark_all(scp); 3106 if (delayed_next_scr) 3107 switch_scr(scp, delayed_next_scr - 1); 3108 } 3109} 3110 3111#endif /* NSC */ 3112