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