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