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