syscons.c revision 27426
1/*- 2 * Copyright (c) 1992-1997 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.224 1997/07/14 03:36:50 yokota Exp $ 29 */ 30 31#include "sc.h" 32#include "apm.h" 33#include "opt_ddb.h" 34#include "opt_syscons.h" 35 36#if NSC > 0 37#include <sys/param.h> 38#include <sys/systm.h> 39#include <sys/conf.h> 40#include <sys/proc.h> 41#include <sys/signalvar.h> 42#include <sys/tty.h> 43#include <sys/uio.h> 44#include <sys/callout.h> 45#include <sys/kernel.h> 46#include <sys/syslog.h> 47#include <sys/errno.h> 48#include <sys/malloc.h> 49#ifdef DEVFS 50#include <sys/devfsext.h> 51#endif 52 53#include <machine/clock.h> 54#include <machine/cons.h> 55#include <machine/console.h> 56#include <machine/md_var.h> 57#include <machine/psl.h> 58#include <machine/frame.h> 59#include <machine/pc/display.h> 60#include <machine/apm_bios.h> 61#include <machine/random.h> 62 63#include <vm/vm.h> 64#include <vm/vm_param.h> 65#include <vm/pmap.h> 66 67#include <i386/isa/isa.h> 68#include <i386/isa/isa_device.h> 69#include <i386/isa/timerreg.h> 70#include <i386/isa/kbdtables.h> 71#include <i386/isa/kbdio.h> 72#include <i386/isa/syscons.h> 73 74#if !defined(MAXCONS) 75#define MAXCONS 16 76#endif 77 78#define COLD 0 79#define WARM 1 80 81/* XXX use sc_bcopy where video memory is concerned */ 82#define sc_bcopy generic_bcopy 83extern void generic_bcopy(const void *, void *, size_t); 84 85static default_attr user_default = { 86 (FG_LIGHTGREY | BG_BLACK) << 8, 87 (FG_BLACK | BG_LIGHTGREY) << 8 88}; 89 90static default_attr kernel_default = { 91 (FG_WHITE | BG_BLACK) << 8, 92 (FG_BLACK | BG_LIGHTGREY) << 8 93}; 94 95static scr_stat main_console; 96static scr_stat *console[MAXCONS]; 97#ifdef DEVFS 98static void *sc_devfs_token[MAXCONS]; 99#endif 100 scr_stat *cur_console; 101static scr_stat *new_scp, *old_scp; 102static term_stat kernel_console; 103static default_attr *current_default; 104static int flags = 0; 105static int sc_port = IO_KBD; 106static KBDC sc_kbdc = NULL; 107static char init_done = COLD; 108static u_short sc_buffer[ROW*COL]; 109static char switch_in_progress = FALSE; 110static char write_in_progress = FALSE; 111static char blink_in_progress = FALSE; 112static int blinkrate = 0; 113 u_int crtc_addr = MONO_BASE; 114 char crtc_type = KD_MONO; 115 char crtc_vga = FALSE; 116static u_char shfts = 0, ctls = 0, alts = 0, agrs = 0, metas = 0; 117static u_char nlkcnt = 0, clkcnt = 0, slkcnt = 0, alkcnt = 0; 118static const u_int n_fkey_tab = sizeof(fkey_tab) / sizeof(*fkey_tab); 119static int delayed_next_scr = FALSE; 120static long scrn_blank_time = 0; /* screen saver timeout value */ 121 int scrn_blanked = 0; /* screen saver active flag */ 122static long scrn_time_stamp; 123 u_char scr_map[256]; 124 u_char scr_rmap[256]; 125 char *video_mode_ptr = NULL; 126 int fonts_loaded = 0; 127 char font_8[256*8]; 128 char font_14[256*14]; 129 char font_16[256*16]; 130 char palette[256*3]; 131static char vgaregs[64]; 132static char *cut_buffer; 133static u_short mouse_and_mask[16] = { 134 0xc000, 0xe000, 0xf000, 0xf800, 135 0xfc00, 0xfe00, 0xff00, 0xff80, 136 0xfe00, 0x1e00, 0x1f00, 0x0f00, 137 0x0f00, 0x0000, 0x0000, 0x0000 138 }; 139static u_short mouse_or_mask[16] = { 140 0x0000, 0x4000, 0x6000, 0x7000, 141 0x7800, 0x7c00, 0x7e00, 0x6800, 142 0x0c00, 0x0c00, 0x0600, 0x0600, 143 0x0000, 0x0000, 0x0000, 0x0000 144 }; 145 146static void none_saver(int blank) { } 147static void (*current_saver)(int blank) = none_saver; 148int (*sc_user_ioctl)(dev_t dev, int cmd, caddr_t data, 149 int flag, struct proc *p) = NULL; 150 151/* OS specific stuff */ 152#ifdef not_yet_done 153#define VIRTUAL_TTY(x) (sccons[x] = ttymalloc(sccons[x])) 154struct CONSOLE_TTY (sccons[MAXCONS] = ttymalloc(sccons[MAXCONS])) 155struct MOUSE_TTY (sccons[MAXCONS+1] = ttymalloc(sccons[MAXCONS+1])) 156struct tty *sccons[MAXCONS+2]; 157#else 158#define VIRTUAL_TTY(x) &sccons[x] 159#define CONSOLE_TTY &sccons[MAXCONS] 160#define MOUSE_TTY &sccons[MAXCONS+1] 161static struct tty sccons[MAXCONS+2]; 162#endif 163#define SC_MOUSE 128 164#define SC_CONSOLE 255 165#define MONO_BUF pa_to_va(0xB0000) 166#define CGA_BUF pa_to_va(0xB8000) 167u_short *Crtat; 168static const int nsccons = MAXCONS+2; 169 170#define WRAPHIST(scp, pointer, offset)\ 171 ((scp->history) + ((((pointer) - (scp->history)) + (scp->history_size)\ 172 + (offset)) % (scp->history_size))) 173#define ISSIGVALID(sig) ((sig) > 0 && (sig) < NSIG) 174 175/* this should really be in `rtc.h' */ 176#define RTC_EQUIPMENT 0x14 177 178/* prototypes */ 179static int scattach(struct isa_device *dev); 180static int scparam(struct tty *tp, struct termios *t); 181static int scprobe(struct isa_device *dev); 182static int scvidprobe(int unit, int flags); 183static int sckbdprobe(int unit, int flags); 184static void scstart(struct tty *tp); 185static void scmousestart(struct tty *tp); 186static void scinit(void); 187static u_int scgetc(u_int flags); 188#define SCGETC_CN 1 189#define SCGETC_NONBLOCK 2 190static scr_stat *get_scr_stat(dev_t dev); 191static scr_stat *alloc_scp(void); 192static void init_scp(scr_stat *scp); 193static int get_scr_num(void); 194static timeout_t scrn_timer; 195static void stop_scrn_saver(void (*saver)(int)); 196static void clear_screen(scr_stat *scp); 197static int switch_scr(scr_stat *scp, u_int next_scr); 198static void exchange_scr(void); 199static inline void move_crsr(scr_stat *scp, int x, int y); 200static void scan_esc(scr_stat *scp, u_char c); 201static void draw_cursor_image(scr_stat *scp); 202static void remove_cursor_image(scr_stat *scp); 203static void ansi_put(scr_stat *scp, u_char *buf, int len); 204static u_char *get_fstr(u_int c, u_int *len); 205static void history_to_screen(scr_stat *scp); 206static int history_up_line(scr_stat *scp); 207static int history_down_line(scr_stat *scp); 208static int mask2attr(struct term_stat *term); 209static void set_keyboard(int command, int data); 210static void update_leds(int which); 211static void set_vgaregs(char *modetable); 212static void read_vgaregs(char *buf); 213static int comp_vgaregs(u_char *buf1, u_char *buf2); 214static void dump_vgaregs(u_char *buf); 215static void set_font_mode(void); 216static void set_normal_mode(void); 217static void set_destructive_cursor(scr_stat *scp); 218static void set_mouse_pos(scr_stat *scp); 219static void mouse_cut_start(scr_stat *scp); 220static void mouse_cut_end(scr_stat *scp); 221static void mouse_paste(scr_stat *scp); 222static void draw_mouse_image(scr_stat *scp); 223static void remove_mouse_image(scr_stat *scp); 224static void draw_cutmarking(scr_stat *scp); 225static void remove_cutmarking(scr_stat *scp); 226static void save_palette(void); 227static void do_bell(scr_stat *scp, int pitch, int duration); 228static timeout_t blink_screen; 229#ifdef SC_SPLASH_SCREEN 230static void toggle_splash_screen(scr_stat *scp); 231#endif 232 233struct isa_driver scdriver = { 234 scprobe, scattach, "sc", 1 235}; 236 237static d_open_t scopen; 238static d_close_t scclose; 239static d_read_t scread; 240static d_write_t scwrite; 241static d_ioctl_t scioctl; 242static d_devtotty_t scdevtotty; 243static d_mmap_t scmmap; 244 245#define CDEV_MAJOR 12 246static struct cdevsw scdevsw = { 247 scopen, scclose, scread, scwrite, 248 scioctl, nullstop, noreset, scdevtotty, 249 ttselect, scmmap, nostrategy, "sc", NULL, -1 }; 250 251/* 252 * These functions need to be before calls to them so they can be inlined. 253 */ 254static inline void 255draw_cursor_image(scr_stat *scp) 256{ 257 u_short cursor_image, *ptr = Crtat + (scp->cursor_pos - scp->scr_buf); 258 u_short prev_image; 259 260 /* do we have a destructive cursor ? */ 261 if (flags & CHAR_CURSOR) { 262 prev_image = scp->cursor_saveunder; 263 cursor_image = *ptr & 0x00ff; 264 if (cursor_image == DEAD_CHAR) 265 cursor_image = prev_image & 0x00ff; 266 cursor_image |= *(scp->cursor_pos) & 0xff00; 267 scp->cursor_saveunder = cursor_image; 268 /* update the cursor bitmap if the char under the cursor has changed */ 269 if (prev_image != cursor_image) 270 set_destructive_cursor(scp); 271 /* modify cursor_image */ 272 if (!(flags & BLINK_CURSOR)||((flags & BLINK_CURSOR)&&(blinkrate & 4))){ 273 /* 274 * When the mouse pointer is at the same position as the cursor, 275 * the cursor bitmap needs to be updated even if the char under 276 * the cursor hasn't changed, because the mouse pionter may 277 * have moved by a few dots within the cursor cel. 278 */ 279 if ((prev_image == cursor_image) 280 && (cursor_image != *(scp->cursor_pos))) 281 set_destructive_cursor(scp); 282 cursor_image &= 0xff00; 283 cursor_image |= DEAD_CHAR; 284 } 285 } 286 else { 287 cursor_image = (*(ptr) & 0x00ff) | *(scp->cursor_pos) & 0xff00; 288 scp->cursor_saveunder = cursor_image; 289 if (!(flags & BLINK_CURSOR)||((flags & BLINK_CURSOR)&&(blinkrate & 4))){ 290 if ((cursor_image & 0x7000) == 0x7000) { 291 cursor_image &= 0x8fff; 292 if(!(cursor_image & 0x0700)) 293 cursor_image |= 0x0700; 294 } else { 295 cursor_image |= 0x7000; 296 if ((cursor_image & 0x0700) == 0x0700) 297 cursor_image &= 0xf0ff; 298 } 299 } 300 } 301 *ptr = cursor_image; 302} 303 304static inline void 305remove_cursor_image(scr_stat *scp) 306{ 307 *(Crtat + (scp->cursor_oldpos - scp->scr_buf)) = scp->cursor_saveunder; 308} 309 310static inline void 311move_crsr(scr_stat *scp, int x, int y) 312{ 313 if (x < 0) 314 x = 0; 315 if (y < 0) 316 y = 0; 317 if (x >= scp->xsize) 318 x = scp->xsize-1; 319 if (y >= scp->ysize) 320 y = scp->ysize-1; 321 scp->xpos = x; 322 scp->ypos = y; 323 scp->cursor_pos = scp->scr_buf + scp->ypos * scp->xsize + scp->xpos; 324} 325 326static int 327scprobe(struct isa_device *dev) 328{ 329 if (!scvidprobe(dev->id_unit, dev->id_flags)) { 330 if (bootverbose) 331 printf("sc%d: no video adapter is found.\n", dev->id_unit); 332 return (0); 333 } 334 335 sc_port = dev->id_iobase; 336 if (sckbdprobe(dev->id_unit, dev->id_flags)) 337 return (IO_KBDSIZE); 338 else 339 return ((dev->id_flags & DETECT_KBD) ? 0 : IO_KBDSIZE); 340} 341 342/* probe video adapters, return TRUE if found */ 343static int 344scvidprobe(int unit, int flags) 345{ 346 /* 347 * XXX don't try to `printf' anything here, the console may not have 348 * been configured yet. 349 */ 350 u_short volatile *cp; 351 u_short was; 352 u_long pa; 353 u_long segoff; 354 355 /* do this test only once */ 356 if (init_done != COLD) 357 return (Crtat != 0); 358 359 /* 360 * Finish defaulting crtc variables for a mono screen. Crtat is a 361 * bogus common variable so that it can be shared with pcvt, so it 362 * can't be statically initialized. XXX. 363 */ 364 Crtat = (u_short *)MONO_BUF; 365 crtc_type = KD_MONO; 366 /* If CGA memory seems to work, switch to color. */ 367 cp = (u_short *)CGA_BUF; 368 was = *cp; 369 *cp = (u_short) 0xA55A; 370 if (*cp == 0xA55A) { 371 Crtat = (u_short *)CGA_BUF; 372 crtc_addr = COLOR_BASE; 373 crtc_type = KD_CGA; 374 } else { 375 cp = Crtat; 376 was = *cp; 377 *cp = (u_short) 0xA55A; 378 if (*cp != 0xA55A) { 379 /* no screen at all, bail out */ 380 Crtat = 0; 381 return FALSE; 382 } 383 } 384 *cp = was; 385 386 /* 387 * Check rtc and BIOS date area. 388 * XXX: don't use BIOSDATA_EQUIPMENT, it is not a dead copy 389 * of RTC_EQUIPMENT. The bit 4 and 5 of the ETC_EQUIPMENT are 390 * zeros for EGA and VGA. However, the EGA/VGA BIOS will set 391 * these bits in BIOSDATA_EQUIPMENT according to the monitor 392 * type detected. 393 */ 394 switch ((rtcin(RTC_EQUIPMENT) >> 4) & 3) { /* bit 4 and 5 */ 395 case 0: /* EGA/VGA, or nothing */ 396 crtc_type = KD_EGA; 397 /* the color adapter may be in the 40x25 mode... XXX */ 398 break; 399 case 1: /* CGA 40x25 */ 400 /* switch to the 80x25 mode? XXX */ 401 /* FALL THROUGH */ 402 case 2: /* CGA 80x25 */ 403 /* `crtc_type' has already been set... */ 404 /* crtc_type = KD_CGA; */ 405 break; 406 case 3: /* MDA */ 407 /* `crtc_type' has already been set... */ 408 /* crtc_type = KD_MONO; */ 409 break; 410 } 411 412 /* is this a VGA or higher ? */ 413 outb(crtc_addr, 7); 414 if (inb(crtc_addr) == 7) { 415 416 crtc_type = KD_VGA; 417 crtc_vga = TRUE; 418 read_vgaregs(vgaregs); 419 420 /* Get the BIOS video mode pointer */ 421 segoff = *(u_long *)pa_to_va(0x4a8); 422 pa = (((segoff & 0xffff0000) >> 12) + (segoff & 0xffff)); 423 if (ISMAPPED(pa, sizeof(u_long))) { 424 segoff = *(u_long *)pa_to_va(pa); 425 pa = (((segoff & 0xffff0000) >> 12) + (segoff & 0xffff)); 426 if (ISMAPPED(pa, 64)) 427 video_mode_ptr = (char *)pa_to_va(pa); 428 } 429 } 430 431 return TRUE; 432} 433 434/* probe the keyboard, return TRUE if found */ 435static int 436sckbdprobe(int unit, int flags) 437{ 438 int codeset; 439 int c = -1; 440 int m; 441 442 sc_kbdc = kbdc_open(sc_port); 443 444 if (!kbdc_lock(sc_kbdc, TRUE)) { 445 /* driver error? */ 446 printf("sc%d: unable to lock the controller.\n", unit); 447 return ((flags & DETECT_KBD) ? FALSE : TRUE); 448 } 449 450 /* discard anything left after UserConfig */ 451 empty_both_buffers(sc_kbdc, 10); 452 453 /* save the current keyboard controller command byte */ 454 m = kbdc_get_device_mask(sc_kbdc) & ~KBD_KBD_CONTROL_BITS; 455 c = get_controller_command_byte(sc_kbdc); 456 if (c == -1) { 457 /* CONTROLLER ERROR */ 458 printf("sc%d: unable to get the current command byte value.\n", unit); 459 goto fail; 460 } 461 if (bootverbose) 462 printf("sc%d: the current keyboard controller command byte %04x\n", 463 unit, c); 464#if 0 465 /* override the keyboard lock switch */ 466 c |= KBD_OVERRIDE_KBD_LOCK; 467#endif 468 469 /* 470 * The keyboard may have been screwed up by the boot block. 471 * We may just be able to recover from error by testing the controller 472 * and the keyboard port. The controller command byte needs to be saved 473 * before this recovery operation, as some controllers seem to set 474 * the command byte to particular values. 475 */ 476 test_controller(sc_kbdc); 477 test_kbd_port(sc_kbdc); 478 479 /* enable the keyboard port, but disable the keyboard intr. */ 480 if (!set_controller_command_byte(sc_kbdc, 481 KBD_KBD_CONTROL_BITS, 482 KBD_ENABLE_KBD_PORT | KBD_DISABLE_KBD_INT)) { 483 /* CONTROLLER ERROR 484 * there is very little we can do... 485 */ 486 printf("sc%d: unable to set the command byte.\n", unit); 487 goto fail; 488 } 489 490 /* 491 * Check if we have an XT keyboard before we attempt to reset it. 492 * The procedure assumes that the keyboard and the controller have 493 * been set up properly by BIOS and have not been messed up 494 * during the boot process. 495 */ 496 codeset = -1; 497 if (flags & XT_KEYBD) 498 /* the user says there is a XT keyboard */ 499 codeset = 1; 500#ifdef DETECT_XT_KEYBOARD 501 else if ((c & KBD_TRANSLATION) == 0) { 502 /* SET_SCANCODE_SET is not always supported; ignore error */ 503 if (send_kbd_command_and_data(sc_kbdc, KBDC_SET_SCANCODE_SET, 0) 504 == KBD_ACK) 505 codeset = read_kbd_data(sc_kbdc); 506 } 507 if (bootverbose) 508 printf("sc%d: keyboard scancode set %d\n", unit, codeset); 509#endif /* DETECT_XT_KEYBOARD */ 510 511 if (flags & KBD_NORESET) { 512 write_kbd_command(sc_kbdc, KBDC_ECHO); 513 if (read_kbd_data(sc_kbdc) != KBD_ECHO) { 514 empty_both_buffers(sc_kbdc, 10); 515 test_controller(sc_kbdc); 516 test_kbd_port(sc_kbdc); 517 if (bootverbose) 518 printf("sc%d: failed to get response from the keyboard.\n", 519 unit); 520 goto fail; 521 } 522 } else { 523 /* reset keyboard hardware */ 524 if (!reset_kbd(sc_kbdc)) { 525 /* KEYBOARD ERROR 526 * Keyboard reset may fail either because the keyboard doen't 527 * exist, or because the keyboard doesn't pass the self-test, 528 * or the keyboard controller on the motherboard and the keyboard 529 * somehow fail to shake hands. It is just possible, particularly 530 * in the last case, that the keyoard controller may be left 531 * in a hung state. test_controller() and test_kbd_port() appear 532 * to bring the keyboard controller back (I don't know why and 533 * how, though.) 534 */ 535 empty_both_buffers(sc_kbdc, 10); 536 test_controller(sc_kbdc); 537 test_kbd_port(sc_kbdc); 538 /* We could disable the keyboard port and interrupt... but, 539 * the keyboard may still exist (see above). 540 */ 541 if (bootverbose) 542 printf("sc%d: failed to reset the keyboard.\n", unit); 543 goto fail; 544 } 545 } 546 547 /* 548 * Allow us to set the XT_KEYBD flag in UserConfig so that keyboards 549 * such as those on the IBM ThinkPad laptop computers can be used 550 * with the standard console driver. 551 */ 552 if (codeset == 1) { 553 if (send_kbd_command_and_data( 554 sc_kbdc, KBDC_SET_SCANCODE_SET, codeset) == KBD_ACK) { 555 /* XT kbd doesn't need scan code translation */ 556 c &= ~KBD_TRANSLATION; 557 } else { 558 /* KEYBOARD ERROR 559 * The XT kbd isn't usable unless the proper scan code set 560 * is selected. 561 */ 562 printf("sc%d: unable to set the XT keyboard mode.\n", unit); 563 goto fail; 564 } 565 } 566 /* enable the keyboard port and intr. */ 567 if (!set_controller_command_byte(sc_kbdc, 568 KBD_KBD_CONTROL_BITS | KBD_TRANSLATION | KBD_OVERRIDE_KBD_LOCK, 569 (c & (KBD_TRANSLATION | KBD_OVERRIDE_KBD_LOCK)) 570 | KBD_ENABLE_KBD_PORT | KBD_ENABLE_KBD_INT)) { 571 /* CONTROLLER ERROR 572 * This is serious; we are left with the disabled keyboard intr. 573 */ 574 printf("sc%d: unable to enable the keyboard port and intr.\n", unit); 575 goto fail; 576 } 577 578succeed: 579 kbdc_set_device_mask(sc_kbdc, m | KBD_KBD_CONTROL_BITS), 580 kbdc_lock(sc_kbdc, FALSE); 581 return TRUE; 582 583fail: 584 if (c != -1) 585 /* try to restore the command byte as before, if possible */ 586 set_controller_command_byte(sc_kbdc, 0xff, c); 587 kbdc_set_device_mask(sc_kbdc, 588 (flags & DETECT_KBD) ? m : m | KBD_KBD_CONTROL_BITS); 589 kbdc_lock(sc_kbdc, FALSE); 590 return FALSE; 591} 592 593#if NAPM > 0 594static int 595scresume(void *dummy) 596{ 597 shfts = ctls = alts = agrs = metas = 0; 598 return 0; 599} 600#endif 601 602static int 603scattach(struct isa_device *dev) 604{ 605 scr_stat *scp; 606 dev_t cdev = makedev(CDEV_MAJOR, 0); 607#ifdef DEVFS 608 int vc; 609#endif 610 611 scinit(); 612 flags = dev->id_flags; 613 if (!crtc_vga) 614 flags &= ~CHAR_CURSOR; 615 616 scp = console[0]; 617 618 if (crtc_vga) { 619 cut_buffer = (char *)malloc(scp->xsize*scp->ysize, M_DEVBUF, M_NOWAIT); 620 } 621 622 scp->scr_buf = (u_short *)malloc(scp->xsize*scp->ysize*sizeof(u_short), 623 M_DEVBUF, M_NOWAIT); 624 625 /* copy temporary buffer to final buffer */ 626 bcopy(sc_buffer, scp->scr_buf, scp->xsize * scp->ysize * sizeof(u_short)); 627 628 scp->cursor_pos = scp->cursor_oldpos = 629 scp->scr_buf + scp->xpos + scp->ypos * scp->xsize; 630 scp->mouse_pos = scp->mouse_oldpos = 631 scp->scr_buf + ((scp->mouse_ypos/scp->font_size)*scp->xsize + 632 scp->mouse_xpos/8); 633 634 /* initialize history buffer & pointers */ 635 scp->history_head = scp->history_pos = scp->history = 636 (u_short *)malloc(scp->history_size*sizeof(u_short), 637 M_DEVBUF, M_NOWAIT); 638 bzero(scp->history_head, scp->history_size*sizeof(u_short)); 639 640 /* initialize cursor stuff */ 641 if (!(scp->status & UNKNOWN_MODE)) 642 draw_cursor_image(scp); 643 644 /* get screen update going */ 645 scrn_timer(NULL); 646 647 update_leds(scp->status); 648 649 if (bootverbose) { 650 printf("sc%d: BIOS video mode:%d\n", 651 dev->id_unit, *(u_char *)pa_to_va(0x449)); 652 printf("sc%d: VGA registers upon power-up\n", dev->id_unit); 653 dump_vgaregs(vgaregs); 654 printf("sc%d: video mode:%d\n", dev->id_unit, scp->mode); 655 if (video_mode_ptr != NULL) { 656 printf("sc%d: VGA registers for mode:%d\n", 657 dev->id_unit, scp->mode); 658 dump_vgaregs(video_mode_ptr + (64*scp->mode)); 659 } 660 } 661 662 printf("sc%d: ", dev->id_unit); 663 switch(crtc_type) { 664 case KD_VGA: 665 if (crtc_addr == MONO_BASE) 666 printf("VGA mono"); 667 else 668 printf("VGA color"); 669 break; 670 case KD_EGA: 671 if (crtc_addr == MONO_BASE) 672 printf("EGA mono"); 673 else 674 printf("EGA color"); 675 break; 676 case KD_CGA: 677 printf("CGA"); 678 break; 679 case KD_MONO: 680 case KD_HERCULES: 681 default: 682 printf("MDA/hercules"); 683 break; 684 } 685 printf(" <%d virtual consoles, flags=0x%x>\n", MAXCONS, flags); 686 687#if NAPM > 0 688 scp->r_hook.ah_fun = scresume; 689 scp->r_hook.ah_arg = NULL; 690 scp->r_hook.ah_name = "system keyboard"; 691 scp->r_hook.ah_order = APM_MID_ORDER; 692 apm_hook_establish(APM_HOOK_RESUME , &scp->r_hook); 693#endif 694 695 cdevsw_add(&cdev, &scdevsw, NULL); 696 697#ifdef DEVFS 698 for (vc = 0; vc < MAXCONS; vc++) 699 sc_devfs_token[vc] = devfs_add_devswf(&scdevsw, vc, DV_CHR, UID_ROOT, 700 GID_WHEEL, 0600, "ttyv%n", vc); 701#endif 702 return 0; 703} 704 705struct tty 706*scdevtotty(dev_t dev) 707{ 708 int unit = minor(dev); 709 710 if (init_done == COLD) 711 return(NULL); 712 if (unit == SC_CONSOLE) 713 return CONSOLE_TTY; 714 if (unit == SC_MOUSE) 715 return MOUSE_TTY; 716 if (unit >= MAXCONS || unit < 0) 717 return(NULL); 718 return VIRTUAL_TTY(unit); 719} 720 721int 722scopen(dev_t dev, int flag, int mode, struct proc *p) 723{ 724 struct tty *tp = scdevtotty(dev); 725 726 if (!tp) 727 return(ENXIO); 728 729 tp->t_oproc = (minor(dev) == SC_MOUSE) ? scmousestart : scstart; 730 tp->t_param = scparam; 731 tp->t_dev = dev; 732 if (!(tp->t_state & TS_ISOPEN)) { 733 ttychars(tp); 734 /* Use the current setting of the <-- key as default VERASE. */ 735 /* If the Delete key is preferable, an stty is necessary */ 736 tp->t_cc[VERASE] = key_map.key[0x0e].map[0]; 737 tp->t_iflag = TTYDEF_IFLAG; 738 tp->t_oflag = TTYDEF_OFLAG; 739 tp->t_cflag = TTYDEF_CFLAG; 740 tp->t_lflag = TTYDEF_LFLAG; 741 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 742 scparam(tp, &tp->t_termios); 743 ttsetwater(tp); 744 (*linesw[tp->t_line].l_modem)(tp, 1); 745 } 746 else 747 if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) 748 return(EBUSY); 749 if (minor(dev) < MAXCONS && !console[minor(dev)]) { 750 console[minor(dev)] = alloc_scp(); 751 } 752 if (minor(dev)<MAXCONS && !tp->t_winsize.ws_col && !tp->t_winsize.ws_row) { 753 tp->t_winsize.ws_col = console[minor(dev)]->xsize; 754 tp->t_winsize.ws_row = console[minor(dev)]->ysize; 755 } 756 return ((*linesw[tp->t_line].l_open)(dev, tp)); 757} 758 759int 760scclose(dev_t dev, int flag, int mode, struct proc *p) 761{ 762 struct tty *tp = scdevtotty(dev); 763 struct scr_stat *scp; 764 765 if (!tp) 766 return(ENXIO); 767 if (minor(dev) < MAXCONS) { 768 scp = get_scr_stat(tp->t_dev); 769 if (scp->status & SWITCH_WAIT_ACQ) 770 wakeup((caddr_t)&scp->smode); 771#if not_yet_done 772 if (scp == &main_console) { 773 scp->pid = 0; 774 scp->proc = NULL; 775 scp->smode.mode = VT_AUTO; 776 } 777 else { 778 free(scp->scr_buf, M_DEVBUF); 779 if (scp->history != NULL) 780 free(scp->history, M_DEVBUF); 781 free(scp, M_DEVBUF); 782 console[minor(dev)] = NULL; 783 } 784#else 785 scp->pid = 0; 786 scp->proc = NULL; 787 scp->smode.mode = VT_AUTO; 788#endif 789 } 790 spltty(); 791 (*linesw[tp->t_line].l_close)(tp, flag); 792 ttyclose(tp); 793 spl0(); 794 return(0); 795} 796 797int 798scread(dev_t dev, struct uio *uio, int flag) 799{ 800 struct tty *tp = scdevtotty(dev); 801 802 if (!tp) 803 return(ENXIO); 804 return((*linesw[tp->t_line].l_read)(tp, uio, flag)); 805} 806 807int 808scwrite(dev_t dev, struct uio *uio, int flag) 809{ 810 struct tty *tp = scdevtotty(dev); 811 812 if (!tp) 813 return(ENXIO); 814 return((*linesw[tp->t_line].l_write)(tp, uio, flag)); 815} 816 817void 818scintr(int unit) 819{ 820 static struct tty *cur_tty; 821 int c, len; 822 u_char *cp; 823 824 /* make screensaver happy */ 825 scrn_time_stamp = mono_time.tv_sec; 826 827 /* 828 * Loop while there is still input to get from the keyboard. 829 * I don't think this is nessesary, and it doesn't fix 830 * the Xaccel-2.1 keyboard hang, but it can't hurt. XXX 831 */ 832 while ((c = scgetc(SCGETC_NONBLOCK)) != NOKEY) { 833 834 cur_tty = VIRTUAL_TTY(get_scr_num()); 835 if (!(cur_tty->t_state & TS_ISOPEN)) 836 if (!((cur_tty = CONSOLE_TTY)->t_state & TS_ISOPEN)) 837 continue; 838 839 switch (c & 0xff00) { 840 case 0x0000: /* normal key */ 841 (*linesw[cur_tty->t_line].l_rint)(c & 0xFF, cur_tty); 842 break; 843 case FKEY: /* function key, return string */ 844 if (cp = get_fstr((u_int)c, (u_int *)&len)) { 845 while (len-- > 0) 846 (*linesw[cur_tty->t_line].l_rint)(*cp++ & 0xFF, cur_tty); 847 } 848 break; 849 case MKEY: /* meta is active, prepend ESC */ 850 (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty); 851 (*linesw[cur_tty->t_line].l_rint)(c & 0xFF, cur_tty); 852 break; 853 case BKEY: /* backtab fixed sequence (esc [ Z) */ 854 (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty); 855 (*linesw[cur_tty->t_line].l_rint)('[', cur_tty); 856 (*linesw[cur_tty->t_line].l_rint)('Z', cur_tty); 857 break; 858 } 859 } 860 861 if (cur_console->status & MOUSE_ENABLED) { 862 cur_console->status &= ~MOUSE_VISIBLE; 863 remove_mouse_image(cur_console); 864 } 865} 866 867static int 868scparam(struct tty *tp, struct termios *t) 869{ 870 tp->t_ispeed = t->c_ispeed; 871 tp->t_ospeed = t->c_ospeed; 872 tp->t_cflag = t->c_cflag; 873 return 0; 874} 875 876int 877scioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) 878{ 879 int error; 880 u_int i; 881 struct tty *tp; 882 scr_stat *scp; 883 884 tp = scdevtotty(dev); 885 if (!tp) 886 return ENXIO; 887 scp = get_scr_stat(tp->t_dev); 888 889 /* If there is a user_ioctl function call that first */ 890 if (sc_user_ioctl) { 891 if (error = (*sc_user_ioctl)(dev, cmd, data, flag, p)) 892 return error; 893 } 894 895 switch (cmd) { /* process console hardware related ioctl's */ 896 897 case GIO_ATTR: /* get current attributes */ 898 *(int*)data = (scp->term.cur_attr >> 8) & 0xFF; 899 return 0; 900 901 case GIO_COLOR: /* is this a color console ? */ 902 if (crtc_addr == COLOR_BASE) 903 *(int*)data = 1; 904 else 905 *(int*)data = 0; 906 return 0; 907 908 case CONS_CURRENT: /* get current adapter type */ 909 *(int *)data = crtc_type; 910 return 0; 911 912 case CONS_GET: /* get current video mode */ 913 *(int*)data = scp->mode; 914 return 0; 915 916 case CONS_BLANKTIME: /* set screen saver timeout (0 = no saver) */ 917 if (*(int *)data < 0) 918 return EINVAL; 919 scrn_blank_time = *(int *)data; 920 if (scrn_blank_time == 0) 921 scrn_time_stamp = mono_time.tv_sec; 922 return 0; 923 924 case CONS_CURSORTYPE: /* set cursor type blink/noblink */ 925 if ((*(int*)data) & 0x01) 926 flags |= BLINK_CURSOR; 927 else 928 flags &= ~BLINK_CURSOR; 929 if ((*(int*)data) & 0x02) { 930 if (!crtc_vga) 931 return ENXIO; 932 flags |= CHAR_CURSOR; 933 } else 934 flags &= ~CHAR_CURSOR; 935 /* 936 * The cursor shape is global property; all virtual consoles 937 * are affected. Update the cursor in the current console... 938 */ 939 if (!(cur_console->status & UNKNOWN_MODE)) { 940 remove_cursor_image(cur_console); 941 if (flags & CHAR_CURSOR) 942 set_destructive_cursor(cur_console); 943 draw_cursor_image(cur_console); 944 } 945 return 0; 946 947 case CONS_BELLTYPE: /* set bell type sound/visual */ 948 if (*data) 949 flags |= VISUAL_BELL; 950 else 951 flags &= ~VISUAL_BELL; 952 return 0; 953 954 case CONS_HISTORY: /* set history size */ 955 if (*data) { 956 if (cur_console->status & BUFFER_SAVED) 957 return EBUSY; 958 if (scp->history != NULL) 959 free(scp->history, M_DEVBUF); 960 scp->history_size = *(int*)data; 961 if (scp->history_size < scp->ysize) 962 scp->history = NULL; 963 else { 964 scp->history_size *= scp->xsize; 965 scp->history_head = scp->history_pos = scp->history = 966 (u_short *)malloc(scp->history_size*sizeof(u_short), 967 M_DEVBUF, M_WAITOK); 968 bzero(scp->history_head, scp->history_size*sizeof(u_short)); 969 } 970 return 0; 971 } 972 else 973 return EINVAL; 974 975 case CONS_MOUSECTL: /* control mouse arrow */ 976 { 977 mouse_info_t *mouse = (mouse_info_t*)data; 978 979 if (!crtc_vga) 980 return ENXIO; 981 982 switch (mouse->operation) { 983 case MOUSE_MODE: 984 if (ISSIGVALID(mouse->u.mode.signal)) { 985 scp->mouse_signal = mouse->u.mode.signal; 986 scp->mouse_proc = p; 987 scp->mouse_pid = p->p_pid; 988 } 989 else { 990 scp->mouse_signal = 0; 991 scp->mouse_proc = NULL; 992 scp->mouse_pid = 0; 993 } 994 break; 995 996 case MOUSE_SHOW: 997 if (!(scp->status & MOUSE_ENABLED)) { 998 scp->status |= (MOUSE_ENABLED | MOUSE_VISIBLE); 999 scp->mouse_oldpos = scp->mouse_pos; 1000 mark_all(scp); 1001 } 1002 else 1003 return EINVAL; 1004 break; 1005 1006 case MOUSE_HIDE: 1007 if (scp->status & MOUSE_ENABLED) { 1008 scp->status &= ~(MOUSE_ENABLED | MOUSE_VISIBLE); 1009 mark_all(scp); 1010 } 1011 else 1012 return EINVAL; 1013 break; 1014 1015 case MOUSE_MOVEABS: 1016 scp->mouse_xpos = mouse->u.data.x; 1017 scp->mouse_ypos = mouse->u.data.y; 1018 set_mouse_pos(scp); 1019 break; 1020 1021 case MOUSE_MOVEREL: 1022 scp->mouse_xpos += mouse->u.data.x; 1023 scp->mouse_ypos += mouse->u.data.y; 1024 set_mouse_pos(scp); 1025 break; 1026 1027 case MOUSE_GETINFO: 1028 mouse->u.data.x = scp->mouse_xpos; 1029 mouse->u.data.y = scp->mouse_ypos; 1030 mouse->u.data.buttons = scp->mouse_buttons; 1031 break; 1032 1033 case MOUSE_ACTION: 1034 /* this should maybe only be settable from /dev/consolectl SOS */ 1035 /* send out mouse event on /dev/sysmouse */ 1036 if (cur_console->status & MOUSE_ENABLED) 1037 cur_console->status |= MOUSE_VISIBLE; 1038 if ((MOUSE_TTY)->t_state & TS_ISOPEN) { 1039 u_char buf[5]; 1040 int i; 1041 1042 buf[0] = 0x80 | ((~mouse->u.data.buttons) & 0x07); 1043 buf[1] = (mouse->u.data.x & 0x1fe >> 1); 1044 buf[3] = (mouse->u.data.x & 0x1ff) - buf[1]; 1045 buf[2] = -(mouse->u.data.y & 0x1fe >> 1); 1046 buf[4] = -(mouse->u.data.y & 0x1ff) - buf[2]; 1047 for (i=0; i<5; i++) 1048 (*linesw[(MOUSE_TTY)->t_line].l_rint)(buf[i],MOUSE_TTY); 1049 } 1050 cur_console->mouse_xpos += mouse->u.data.x; 1051 cur_console->mouse_ypos += mouse->u.data.y; 1052 if (cur_console->mouse_signal) { 1053 cur_console->mouse_buttons = mouse->u.data.buttons; 1054 /* has controlling process died? */ 1055 if (cur_console->mouse_proc && 1056 (cur_console->mouse_proc != pfind(cur_console->mouse_pid))){ 1057 cur_console->mouse_signal = 0; 1058 cur_console->mouse_proc = NULL; 1059 cur_console->mouse_pid = 0; 1060 } 1061 else 1062 psignal(cur_console->mouse_proc, cur_console->mouse_signal); 1063 } 1064 else { 1065 /* process button presses */ 1066 if (cur_console->mouse_buttons != mouse->u.data.buttons) { 1067 cur_console->mouse_buttons = mouse->u.data.buttons; 1068 if (!(cur_console->status & UNKNOWN_MODE)) { 1069 if (cur_console->mouse_buttons & LEFT_BUTTON) 1070 mouse_cut_start(cur_console); 1071 else 1072 mouse_cut_end(cur_console); 1073 if (cur_console->mouse_buttons & RIGHT_BUTTON || 1074 cur_console->mouse_buttons & MIDDLE_BUTTON) 1075 mouse_paste(cur_console); 1076 } 1077 } 1078 } 1079 if (mouse->u.data.x != 0 || mouse->u.data.y != 0) 1080 set_mouse_pos(cur_console); 1081 break; 1082 1083 default: 1084 return EINVAL; 1085 } 1086 /* make screensaver happy */ 1087 scrn_time_stamp = mono_time.tv_sec; 1088 return 0; 1089 } 1090 1091 case CONS_GETINFO: /* get current (virtual) console info */ 1092 { 1093 vid_info_t *ptr = (vid_info_t*)data; 1094 if (ptr->size == sizeof(struct vid_info)) { 1095 ptr->m_num = get_scr_num(); 1096 ptr->mv_col = scp->xpos; 1097 ptr->mv_row = scp->ypos; 1098 ptr->mv_csz = scp->xsize; 1099 ptr->mv_rsz = scp->ysize; 1100 ptr->mv_norm.fore = (scp->term.std_color & 0x0f00)>>8; 1101 ptr->mv_norm.back = (scp->term.std_color & 0xf000)>>12; 1102 ptr->mv_rev.fore = (scp->term.rev_color & 0x0f00)>>8; 1103 ptr->mv_rev.back = (scp->term.rev_color & 0xf000)>>12; 1104 ptr->mv_grfc.fore = 0; /* not supported */ 1105 ptr->mv_grfc.back = 0; /* not supported */ 1106 ptr->mv_ovscan = scp->border; 1107 ptr->mk_keylock = scp->status & LOCK_KEY_MASK; 1108 return 0; 1109 } 1110 return EINVAL; 1111 } 1112 1113 case CONS_GETVERS: /* get version number */ 1114 *(int*)data = 0x200; /* version 2.0 */ 1115 return 0; 1116 1117 /* VGA TEXT MODES */ 1118 case SW_VGA_C40x25: 1119 case SW_VGA_C80x25: case SW_VGA_M80x25: 1120 case SW_VGA_C80x30: case SW_VGA_M80x30: 1121 case SW_VGA_C80x50: case SW_VGA_M80x50: 1122 case SW_VGA_C80x60: case SW_VGA_M80x60: 1123 case SW_B40x25: case SW_C40x25: 1124 case SW_B80x25: case SW_C80x25: 1125 case SW_ENH_B40x25: case SW_ENH_C40x25: 1126 case SW_ENH_B80x25: case SW_ENH_C80x25: 1127 case SW_ENH_B80x43: case SW_ENH_C80x43: 1128 case SW_EGAMONO80x25: 1129 1130 if (!crtc_vga || video_mode_ptr == NULL) 1131 return ENXIO; 1132 switch (cmd & 0xff) { 1133 case M_VGA_C80x60: case M_VGA_M80x60: 1134 if (!(fonts_loaded & FONT_8)) 1135 return EINVAL; 1136 scp->xsize = 80; 1137 scp->ysize = 60; 1138 break; 1139 case M_VGA_C80x50: case M_VGA_M80x50: 1140 if (!(fonts_loaded & FONT_8)) 1141 return EINVAL; 1142 scp->xsize = 80; 1143 scp->ysize = 50; 1144 break; 1145 case M_ENH_B80x43: case M_ENH_C80x43: 1146 if (!(fonts_loaded & FONT_8)) 1147 return EINVAL; 1148 scp->xsize = 80; 1149 scp->ysize = 43; 1150 break; 1151 case M_VGA_C80x30: case M_VGA_M80x30: 1152 scp->xsize = 80; 1153 scp->ysize = 30; 1154 break; 1155 case M_ENH_C40x25: case M_ENH_B40x25: 1156 case M_ENH_C80x25: case M_ENH_B80x25: 1157 case M_EGAMONO80x25: 1158 if (!(fonts_loaded & FONT_14)) 1159 return EINVAL; 1160 /* FALL THROUGH */ 1161 default: 1162 if ((cmd & 0xff) > M_VGA_CG320) 1163 return EINVAL; 1164 else 1165 scp->xsize = *(video_mode_ptr+((cmd&0xff)*64)); 1166 scp->ysize = *(video_mode_ptr+((cmd&0xff)*64)+1)+1; 1167 break; 1168 } 1169 scp->mode = cmd & 0xff; 1170 free(scp->scr_buf, M_DEVBUF); 1171 scp->scr_buf = (u_short *) 1172 malloc(scp->xsize*scp->ysize*sizeof(u_short), M_DEVBUF, M_WAITOK); 1173 scp->cursor_pos = scp->cursor_oldpos = 1174 scp->scr_buf + scp->xpos + scp->ypos * scp->xsize; 1175 scp->mouse_pos = scp->mouse_oldpos = 1176 scp->scr_buf + ((scp->mouse_ypos/scp->font_size)*scp->xsize + 1177 scp->mouse_xpos/8); 1178 free(cut_buffer, M_DEVBUF); 1179 cut_buffer = (char *)malloc(scp->xsize*scp->ysize, M_DEVBUF, M_NOWAIT); 1180 cut_buffer[0] = 0x00; 1181 if (scp == cur_console) 1182 set_mode(scp); 1183 scp->status &= ~UNKNOWN_MODE; 1184 clear_screen(scp); 1185 if (tp->t_winsize.ws_col != scp->xsize 1186 || tp->t_winsize.ws_row != scp->ysize) { 1187 tp->t_winsize.ws_col = scp->xsize; 1188 tp->t_winsize.ws_row = scp->ysize; 1189 pgsignal(tp->t_pgrp, SIGWINCH, 1); 1190 } 1191 return 0; 1192 1193 /* GRAPHICS MODES */ 1194 case SW_BG320: case SW_BG640: 1195 case SW_CG320: case SW_CG320_D: case SW_CG640_E: 1196 case SW_CG640x350: case SW_ENH_CG640: 1197 case SW_BG640x480: case SW_CG640x480: case SW_VGA_CG320: 1198 1199 if (!crtc_vga || video_mode_ptr == NULL) 1200 return ENXIO; 1201 scp->mode = cmd & 0xFF; 1202 scp->xpixel = (*(video_mode_ptr + (scp->mode*64))) * 8; 1203 scp->ypixel = (*(video_mode_ptr + (scp->mode*64) + 1) + 1) * 1204 (*(video_mode_ptr + (scp->mode*64) + 2)); 1205 if (scp == cur_console) 1206 set_mode(scp); 1207 scp->status |= UNKNOWN_MODE; /* graphics mode */ 1208 /* clear_graphics();*/ 1209 1210 if (tp->t_winsize.ws_xpixel != scp->xpixel 1211 || tp->t_winsize.ws_ypixel != scp->ypixel) { 1212 tp->t_winsize.ws_xpixel = scp->xpixel; 1213 tp->t_winsize.ws_ypixel = scp->ypixel; 1214 pgsignal(tp->t_pgrp, SIGWINCH, 1); 1215 } 1216 return 0; 1217 1218 case VT_SETMODE: /* set screen switcher mode */ 1219 { 1220 struct vt_mode *mode; 1221 1222 mode = (struct vt_mode *)data; 1223 if (ISSIGVALID(mode->relsig) && ISSIGVALID(mode->acqsig) && 1224 ISSIGVALID(mode->frsig)) { 1225 bcopy(data, &scp->smode, sizeof(struct vt_mode)); 1226 if (scp->smode.mode == VT_PROCESS) { 1227 scp->proc = p; 1228 scp->pid = scp->proc->p_pid; 1229 } 1230 return 0; 1231 } else 1232 return EINVAL; 1233 } 1234 1235 case VT_GETMODE: /* get screen switcher mode */ 1236 bcopy(&scp->smode, data, sizeof(struct vt_mode)); 1237 return 0; 1238 1239 case VT_RELDISP: /* screen switcher ioctl */ 1240 switch(*data) { 1241 case VT_FALSE: /* user refuses to release screen, abort */ 1242 if (scp == old_scp && (scp->status & SWITCH_WAIT_REL)) { 1243 old_scp->status &= ~SWITCH_WAIT_REL; 1244 switch_in_progress = FALSE; 1245 return 0; 1246 } 1247 return EINVAL; 1248 1249 case VT_TRUE: /* user has released screen, go on */ 1250 if (scp == old_scp && (scp->status & SWITCH_WAIT_REL)) { 1251 scp->status &= ~SWITCH_WAIT_REL; 1252 exchange_scr(); 1253 if (new_scp->smode.mode == VT_PROCESS) { 1254 new_scp->status |= SWITCH_WAIT_ACQ; 1255 psignal(new_scp->proc, new_scp->smode.acqsig); 1256 } 1257 else 1258 switch_in_progress = FALSE; 1259 return 0; 1260 } 1261 return EINVAL; 1262 1263 case VT_ACKACQ: /* acquire acknowledged, switch completed */ 1264 if (scp == new_scp && (scp->status & SWITCH_WAIT_ACQ)) { 1265 scp->status &= ~SWITCH_WAIT_ACQ; 1266 switch_in_progress = FALSE; 1267 return 0; 1268 } 1269 return EINVAL; 1270 1271 default: 1272 return EINVAL; 1273 } 1274 /* NOT REACHED */ 1275 1276 case VT_OPENQRY: /* return free virtual console */ 1277 for (i = 0; i < MAXCONS; i++) { 1278 tp = VIRTUAL_TTY(i); 1279 if (!(tp->t_state & TS_ISOPEN)) { 1280 *data = i + 1; 1281 return 0; 1282 } 1283 } 1284 return EINVAL; 1285 1286 case VT_ACTIVATE: /* switch to screen *data */ 1287 return switch_scr(scp, (*data) - 1); 1288 1289 case VT_WAITACTIVE: /* wait for switch to occur */ 1290 if (*data > MAXCONS || *data < 0) 1291 return EINVAL; 1292 if (minor(dev) == (*data) - 1) 1293 return 0; 1294 if (*data == 0) { 1295 if (scp == cur_console) 1296 return 0; 1297 } 1298 else 1299 scp = console[(*data) - 1]; 1300 while ((error=tsleep((caddr_t)&scp->smode, PZERO|PCATCH, 1301 "waitvt", 0)) == ERESTART) ; 1302 return error; 1303 1304 case VT_GETACTIVE: 1305 *data = get_scr_num()+1; 1306 return 0; 1307 1308 case KDENABIO: /* allow io operations */ 1309 error = suser(p->p_ucred, &p->p_acflag); 1310 if (error != 0) 1311 return error; 1312 if (securelevel > 0) 1313 return EPERM; 1314 p->p_md.md_regs->tf_eflags |= PSL_IOPL; 1315 return 0; 1316 1317 case KDDISABIO: /* disallow io operations (default) */ 1318 p->p_md.md_regs->tf_eflags &= ~PSL_IOPL; 1319 return 0; 1320 1321 case KDSETMODE: /* set current mode of this (virtual) console */ 1322 switch (*data) { 1323 case KD_TEXT: /* switch to TEXT (known) mode */ 1324 /* restore fonts & palette ! */ 1325 if (crtc_vga) { 1326 if (fonts_loaded & FONT_8) 1327 copy_font(LOAD, FONT_8, font_8); 1328 if (fonts_loaded & FONT_14) 1329 copy_font(LOAD, FONT_14, font_14); 1330 if (fonts_loaded & FONT_16) 1331 copy_font(LOAD, FONT_16, font_16); 1332 load_palette(palette); 1333 } 1334 /* FALL THROUGH */ 1335 1336 case KD_TEXT1: /* switch to TEXT (known) mode */ 1337 /* no restore fonts & palette */ 1338 if (crtc_vga && video_mode_ptr) 1339 set_mode(scp); 1340 scp->status &= ~UNKNOWN_MODE; 1341 clear_screen(scp); 1342 return 0; 1343 1344 case KD_GRAPHICS: /* switch to GRAPHICS (unknown) mode */ 1345 scp->status |= UNKNOWN_MODE; 1346 return 0; 1347 default: 1348 return EINVAL; 1349 } 1350 /* NOT REACHED */ 1351 1352 case KDGETMODE: /* get current mode of this (virtual) console */ 1353 *data = (scp->status & UNKNOWN_MODE) ? KD_GRAPHICS : KD_TEXT; 1354 return 0; 1355 1356 case KDSBORDER: /* set border color of this (virtual) console */ 1357 scp->border = *data; 1358 if (scp == cur_console) 1359 set_border(scp->border); 1360 return 0; 1361 1362 case KDSKBSTATE: /* set keyboard state (locks) */ 1363 if (*data >= 0 && *data <= LOCK_KEY_MASK) { 1364 scp->status &= ~LOCK_KEY_MASK; 1365 scp->status |= *data; 1366 if (scp == cur_console) 1367 update_leds(scp->status); 1368 return 0; 1369 } 1370 return EINVAL; 1371 1372 case KDGKBSTATE: /* get keyboard state (locks) */ 1373 *data = scp->status & LOCK_KEY_MASK; 1374 return 0; 1375 1376 case KDSETRAD: /* set keyboard repeat & delay rates */ 1377 if (*data & 0x80) 1378 return EINVAL; 1379 if (sc_kbdc != NULL) 1380 set_keyboard(KBDC_SET_TYPEMATIC, *data); 1381 return 0; 1382 1383 case KDSKBMODE: /* set keyboard mode */ 1384 switch (*data) { 1385 case K_RAW: /* switch to RAW scancode mode */ 1386 scp->status |= KBD_RAW_MODE; 1387 return 0; 1388 1389 case K_XLATE: /* switch to XLT ascii mode */ 1390 if (scp == cur_console && scp->status & KBD_RAW_MODE) 1391 shfts = ctls = alts = agrs = metas = 0; 1392 scp->status &= ~KBD_RAW_MODE; 1393 return 0; 1394 default: 1395 return EINVAL; 1396 } 1397 /* NOT REACHED */ 1398 1399 case KDGKBMODE: /* get keyboard mode */ 1400 *data = (scp->status & KBD_RAW_MODE) ? K_RAW : K_XLATE; 1401 return 0; 1402 1403 case KDMKTONE: /* sound the bell */ 1404 if (*(int*)data) 1405 do_bell(scp, (*(int*)data)&0xffff, 1406 (((*(int*)data)>>16)&0xffff)*hz/1000); 1407 else 1408 do_bell(scp, scp->bell_pitch, scp->bell_duration); 1409 return 0; 1410 1411 case KIOCSOUND: /* make tone (*data) hz */ 1412 if (scp == cur_console) { 1413 if (*(int*)data) { 1414 int pitch = timer_freq / *(int*)data; 1415 1416 /* set command for counter 2, 2 byte write */ 1417 if (acquire_timer2(TIMER_16BIT|TIMER_SQWAVE)) 1418 return EBUSY; 1419 1420 /* set pitch */ 1421 outb(TIMER_CNTR2, pitch); 1422 outb(TIMER_CNTR2, (pitch>>8)); 1423 1424 /* enable counter 2 output to speaker */ 1425 outb(IO_PPI, inb(IO_PPI) | 3); 1426 } 1427 else { 1428 /* disable counter 2 output to speaker */ 1429 outb(IO_PPI, inb(IO_PPI) & 0xFC); 1430 release_timer2(); 1431 } 1432 } 1433 return 0; 1434 1435 case KDGKBTYPE: /* get keyboard type */ 1436 *data = 0; /* type not known (yet) */ 1437 return 0; 1438 1439 case KDSETLED: /* set keyboard LED status */ 1440 if (*data >= 0 && *data <= LED_MASK) { 1441 scp->status &= ~LED_MASK; 1442 scp->status |= *data; 1443 if (scp == cur_console) 1444 update_leds(scp->status); 1445 return 0; 1446 } 1447 return EINVAL; 1448 1449 case KDGETLED: /* get keyboard LED status */ 1450 *data = scp->status & LED_MASK; 1451 return 0; 1452 1453 case GETFKEY: /* get functionkey string */ 1454 if (*(u_short*)data < n_fkey_tab) { 1455 fkeyarg_t *ptr = (fkeyarg_t*)data; 1456 bcopy(&fkey_tab[ptr->keynum].str, ptr->keydef, 1457 fkey_tab[ptr->keynum].len); 1458 ptr->flen = fkey_tab[ptr->keynum].len; 1459 return 0; 1460 } 1461 else 1462 return EINVAL; 1463 1464 case SETFKEY: /* set functionkey string */ 1465 if (*(u_short*)data < n_fkey_tab) { 1466 fkeyarg_t *ptr = (fkeyarg_t*)data; 1467 bcopy(ptr->keydef, &fkey_tab[ptr->keynum].str, 1468 min(ptr->flen, MAXFK)); 1469 fkey_tab[ptr->keynum].len = min(ptr->flen, MAXFK); 1470 return 0; 1471 } 1472 else 1473 return EINVAL; 1474 1475 case GIO_SCRNMAP: /* get output translation table */ 1476 bcopy(&scr_map, data, sizeof(scr_map)); 1477 return 0; 1478 1479 case PIO_SCRNMAP: /* set output translation table */ 1480 bcopy(data, &scr_map, sizeof(scr_map)); 1481 for (i=0; i<sizeof(scr_map); i++) 1482 scr_rmap[scr_map[i]] = i; 1483 return 0; 1484 1485 case GIO_KEYMAP: /* get keyboard translation table */ 1486 bcopy(&key_map, data, sizeof(key_map)); 1487 return 0; 1488 1489 case PIO_KEYMAP: /* set keyboard translation table */ 1490 bcopy(data, &key_map, sizeof(key_map)); 1491 return 0; 1492 1493 case PIO_FONT8x8: /* set 8x8 dot font */ 1494 if (!crtc_vga) 1495 return ENXIO; 1496 bcopy(data, font_8, 8*256); 1497 fonts_loaded |= FONT_8; 1498 if (!(cur_console->status & UNKNOWN_MODE)) { 1499 copy_font(LOAD, FONT_8, font_8); 1500 if (flags & CHAR_CURSOR) 1501 set_destructive_cursor(cur_console); 1502 } 1503 return 0; 1504 1505 case GIO_FONT8x8: /* get 8x8 dot font */ 1506 if (!crtc_vga) 1507 return ENXIO; 1508 if (fonts_loaded & FONT_8) { 1509 bcopy(font_8, data, 8*256); 1510 return 0; 1511 } 1512 else 1513 return ENXIO; 1514 1515 case PIO_FONT8x14: /* set 8x14 dot font */ 1516 if (!crtc_vga) 1517 return ENXIO; 1518 bcopy(data, font_14, 14*256); 1519 fonts_loaded |= FONT_14; 1520 if (!(cur_console->status & UNKNOWN_MODE)) { 1521 copy_font(LOAD, FONT_14, font_14); 1522 if (flags & CHAR_CURSOR) 1523 set_destructive_cursor(cur_console); 1524 } 1525 return 0; 1526 1527 case GIO_FONT8x14: /* get 8x14 dot font */ 1528 if (!crtc_vga) 1529 return ENXIO; 1530 if (fonts_loaded & FONT_14) { 1531 bcopy(font_14, data, 14*256); 1532 return 0; 1533 } 1534 else 1535 return ENXIO; 1536 1537 case PIO_FONT8x16: /* set 8x16 dot font */ 1538 if (!crtc_vga) 1539 return ENXIO; 1540 bcopy(data, font_16, 16*256); 1541 fonts_loaded |= FONT_16; 1542 if (!(cur_console->status & UNKNOWN_MODE)) { 1543 copy_font(LOAD, FONT_16, font_16); 1544 if (flags & CHAR_CURSOR) 1545 set_destructive_cursor(cur_console); 1546 } 1547 return 0; 1548 1549 case GIO_FONT8x16: /* get 8x16 dot font */ 1550 if (!crtc_vga) 1551 return ENXIO; 1552 if (fonts_loaded & FONT_16) { 1553 bcopy(font_16, data, 16*256); 1554 return 0; 1555 } 1556 else 1557 return ENXIO; 1558 default: 1559 break; 1560 } 1561 1562 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 1563 if (error >= 0) 1564 return(error); 1565 error = ttioctl(tp, cmd, data, flag); 1566 if (error >= 0) 1567 return(error); 1568 return(ENOTTY); 1569} 1570 1571static void 1572scstart(struct tty *tp) 1573{ 1574 struct clist *rbp; 1575 int s, len; 1576 u_char buf[PCBURST]; 1577 scr_stat *scp = get_scr_stat(tp->t_dev); 1578 1579 if (scp->status & SLKED || blink_in_progress) 1580 return; /* XXX who repeats the call when the above flags are cleared? */ 1581 s = spltty(); 1582 if (!(tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))) { 1583 tp->t_state |= TS_BUSY; 1584 rbp = &tp->t_outq; 1585 while (rbp->c_cc) { 1586 len = q_to_b(rbp, buf, PCBURST); 1587 splx(s); 1588 ansi_put(scp, buf, len); 1589 s = spltty(); 1590 } 1591 tp->t_state &= ~TS_BUSY; 1592 ttwwakeup(tp); 1593 } 1594 splx(s); 1595} 1596 1597static void 1598scmousestart(struct tty *tp) 1599{ 1600 struct clist *rbp; 1601 int s; 1602 u_char buf[PCBURST]; 1603 1604 s = spltty(); 1605 if (!(tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))) { 1606 tp->t_state |= TS_BUSY; 1607 rbp = &tp->t_outq; 1608 while (rbp->c_cc) { 1609 q_to_b(rbp, buf, PCBURST); 1610 } 1611 tp->t_state &= ~TS_BUSY; 1612 ttwwakeup(tp); 1613 } 1614 splx(s); 1615} 1616 1617void 1618sccnprobe(struct consdev *cp) 1619{ 1620 struct isa_device *dvp; 1621 1622 /* 1623 * Take control if we are the highest priority enabled display device. 1624 */ 1625 dvp = find_display(); 1626 if (dvp == NULL || dvp->id_driver != &scdriver) { 1627 cp->cn_pri = CN_DEAD; 1628 return; 1629 } 1630 1631 if (!scvidprobe(dvp->id_unit, dvp->id_flags)) { 1632 cp->cn_pri = CN_DEAD; 1633 return; 1634 } 1635 1636 /* initialize required fields */ 1637 cp->cn_dev = makedev(CDEV_MAJOR, SC_CONSOLE); 1638 cp->cn_pri = CN_INTERNAL; 1639 1640 sc_kbdc = kbdc_open(sc_port); 1641} 1642 1643void 1644sccninit(struct consdev *cp) 1645{ 1646 scinit(); 1647} 1648 1649void 1650sccnputc(dev_t dev, int c) 1651{ 1652 u_char buf[1]; 1653 int s; 1654 scr_stat *scp = console[0]; 1655 term_stat save = scp->term; 1656 1657 scp->term = kernel_console; 1658 current_default = &kernel_default; 1659 if (scp == cur_console && !(scp->status & UNKNOWN_MODE)) 1660 remove_cursor_image(scp); 1661 buf[0] = c; 1662 ansi_put(scp, buf, 1); 1663 kernel_console = scp->term; 1664 current_default = &user_default; 1665 scp->term = save; 1666 s = splclock(); 1667 if (scp == cur_console && !(scp->status & UNKNOWN_MODE)) { 1668 if (/* timer not running && */ (scp->start <= scp->end)) { 1669 sc_bcopy(scp->scr_buf + scp->start, Crtat + scp->start, 1670 (1 + scp->end - scp->start) * sizeof(u_short)); 1671 scp->start = scp->xsize * scp->ysize; 1672 scp->end = 0; 1673 } 1674 scp->cursor_oldpos = scp->cursor_pos; 1675 draw_cursor_image(scp); 1676 } 1677 splx(s); 1678} 1679 1680int 1681sccngetc(dev_t dev) 1682{ 1683 int s = spltty(); /* block scintr and scrn_timer while we poll */ 1684 int c; 1685 1686 /* 1687 * Stop the screen saver if necessary. 1688 * What if we have been running in the screen saver code... XXX 1689 */ 1690 if (scrn_blanked > 0) 1691 stop_scrn_saver(current_saver); 1692 1693 c = scgetc(SCGETC_CN); 1694 1695 /* make sure the screen saver won't be activated soon */ 1696 scrn_time_stamp = mono_time.tv_sec; 1697 splx(s); 1698 return(c); 1699} 1700 1701int 1702sccncheckc(dev_t dev) 1703{ 1704 int c, s; 1705 1706 s = spltty(); 1707 if (scrn_blanked > 0) 1708 stop_scrn_saver(current_saver); 1709 c = scgetc(SCGETC_CN | SCGETC_NONBLOCK); 1710 if (c != NOKEY) 1711 scrn_time_stamp = mono_time.tv_sec; 1712 splx(s); 1713 return(c == NOKEY ? -1 : c); /* c == -1 can't happen */ 1714} 1715 1716static scr_stat 1717*get_scr_stat(dev_t dev) 1718{ 1719 int unit = minor(dev); 1720 1721 if (unit == SC_CONSOLE) 1722 return console[0]; 1723 if (unit >= MAXCONS || unit < 0) 1724 return(NULL); 1725 return console[unit]; 1726} 1727 1728static int 1729get_scr_num() 1730{ 1731 int i = 0; 1732 1733 while ((i < MAXCONS) && (cur_console != console[i])) 1734 i++; 1735 return i < MAXCONS ? i : 0; 1736} 1737 1738static void 1739scrn_timer(void *arg) 1740{ 1741 scr_stat *scp = cur_console; 1742 int s = spltty(); 1743 1744 /* 1745 * With release 2.1 of the Xaccel server, the keyboard is left 1746 * hanging pretty often. Apparently an interrupt from the 1747 * keyboard is lost, and I don't know why (yet). 1748 * This ugly hack calls scintr if input is ready for the keyboard 1749 * and conveniently hides the problem. XXX 1750 */ 1751 /* Try removing anything stuck in the keyboard controller; whether 1752 * it's a keyboard scan code or mouse data. `scintr()' doesn't 1753 * read the mouse data directly, but `kbdio' routines will, as a 1754 * side effect. 1755 */ 1756 if (kbdc_lock(sc_kbdc, TRUE)) { 1757 /* 1758 * We have seen the lock flag is not set. Let's reset the flag early; 1759 * otherwise `update_led()' failes which may want the lock 1760 * during `scintr()'. 1761 */ 1762 kbdc_lock(sc_kbdc, FALSE); 1763 if (kbdc_data_ready(sc_kbdc)) 1764 scintr(0); 1765 } 1766 1767 /* should we just return ? */ 1768 if ((scp->status&UNKNOWN_MODE) || blink_in_progress || switch_in_progress) { 1769 timeout(scrn_timer, NULL, hz / 10); 1770 splx(s); 1771 return; 1772 } 1773 1774 /* should we stop the screen saver? */ 1775 if (mono_time.tv_sec <= scrn_time_stamp + scrn_blank_time) 1776 if (scrn_blanked > 0) 1777 stop_scrn_saver(current_saver); 1778 1779 if (scrn_blanked <= 0) { 1780 /* update screen image */ 1781 if (scp->start <= scp->end) { 1782 sc_bcopy(scp->scr_buf + scp->start, Crtat + scp->start, 1783 (1 + scp->end - scp->start) * sizeof(u_short)); 1784 } 1785 1786 /* update "pseudo" mouse pointer image */ 1787 if ((scp->status & MOUSE_VISIBLE) && crtc_vga) { 1788 /* did mouse move since last time ? */ 1789 if (scp->status & MOUSE_MOVED) { 1790 /* do we need to remove old mouse pointer image ? */ 1791 if (scp->mouse_cut_start != NULL || 1792 (scp->mouse_pos-scp->scr_buf) <= scp->start || 1793 (scp->mouse_pos+scp->xsize+1-scp->scr_buf) >= scp->end) { 1794 remove_mouse_image(scp); 1795 } 1796 scp->status &= ~MOUSE_MOVED; 1797 draw_mouse_image(scp); 1798 } 1799 else { 1800 /* mouse didn't move, has it been overwritten ? */ 1801 if ((scp->mouse_pos+scp->xsize+1-scp->scr_buf) >= scp->start && 1802 (scp->mouse_pos - scp->scr_buf) <= scp->end) { 1803 draw_mouse_image(scp); 1804 } 1805 } 1806 } 1807 1808 /* update cursor image */ 1809 if (scp->status & CURSOR_ENABLED) { 1810 /* did cursor move since last time ? */ 1811 if (scp->cursor_pos != scp->cursor_oldpos) { 1812 /* do we need to remove old cursor image ? */ 1813 if ((scp->cursor_oldpos - scp->scr_buf) < scp->start || 1814 ((scp->cursor_oldpos - scp->scr_buf) > scp->end)) { 1815 remove_cursor_image(scp); 1816 } 1817 scp->cursor_oldpos = scp->cursor_pos; 1818 draw_cursor_image(scp); 1819 } 1820 else { 1821 /* cursor didn't move, has it been overwritten ? */ 1822 if (scp->cursor_pos - scp->scr_buf >= scp->start && 1823 scp->cursor_pos - scp->scr_buf <= scp->end) { 1824 draw_cursor_image(scp); 1825 } else { 1826 /* if its a blinking cursor, we may have to update it */ 1827 if (flags & BLINK_CURSOR) 1828 draw_cursor_image(scp); 1829 } 1830 } 1831 blinkrate++; 1832 } 1833 1834 if (scp->mouse_cut_start != NULL) 1835 draw_cutmarking(scp); 1836 1837 scp->end = 0; 1838 scp->start = scp->xsize*scp->ysize; 1839 } 1840 1841 /* should we activate the screen saver? */ 1842 if ((scrn_blank_time != 0) 1843 && (mono_time.tv_sec > scrn_time_stamp + scrn_blank_time)) 1844 (*current_saver)(TRUE); 1845 1846 timeout(scrn_timer, NULL, hz / 25); 1847 splx(s); 1848} 1849 1850int 1851add_scrn_saver(void (*this_saver)(int)) 1852{ 1853 if (current_saver != none_saver) 1854 return EBUSY; 1855 current_saver = this_saver; 1856 return 0; 1857} 1858 1859int 1860remove_scrn_saver(void (*this_saver)(int)) 1861{ 1862 if (current_saver != this_saver) 1863 return EINVAL; 1864 1865 /* 1866 * In order to prevent `current_saver' from being called by 1867 * the timeout routine `scrn_timer()' while we manipulate 1868 * the saver list, we shall set `current_saver' to `none_saver' 1869 * before stopping the current saver, rather than blocking by `splXX()'. 1870 */ 1871 current_saver = none_saver; 1872 if (scrn_blanked > 0) 1873 stop_scrn_saver(this_saver); 1874 1875 return 0; 1876} 1877 1878static void 1879stop_scrn_saver(void (*saver)(int)) 1880{ 1881 (*saver)(FALSE); 1882 scrn_time_stamp = mono_time.tv_sec; 1883 mark_all(cur_console); 1884} 1885 1886static void 1887clear_screen(scr_stat *scp) 1888{ 1889 move_crsr(scp, 0, 0); 1890 scp->cursor_oldpos = scp->cursor_pos; 1891 fillw(scp->term.cur_color | scr_map[0x20], scp->scr_buf, 1892 scp->xsize * scp->ysize); 1893 mark_all(scp); 1894 remove_cutmarking(scp); 1895} 1896 1897static int 1898switch_scr(scr_stat *scp, u_int next_scr) 1899{ 1900 if (switch_in_progress && (cur_console->proc != pfind(cur_console->pid))) 1901 switch_in_progress = FALSE; 1902 1903 if (next_scr >= MAXCONS || switch_in_progress || 1904 (cur_console->smode.mode == VT_AUTO 1905 && cur_console->status & UNKNOWN_MODE)) { 1906 do_bell(scp, BELL_PITCH, BELL_DURATION); 1907 return EINVAL; 1908 } 1909 1910 /* is the wanted virtual console open ? */ 1911 if (next_scr) { 1912 struct tty *tp = VIRTUAL_TTY(next_scr); 1913 if (!(tp->t_state & TS_ISOPEN)) { 1914 do_bell(scp, BELL_PITCH, BELL_DURATION); 1915 return EINVAL; 1916 } 1917 } 1918 /* delay switch if actively updating screen */ 1919 if (write_in_progress || blink_in_progress) { 1920 delayed_next_scr = next_scr+1; 1921 return 0; 1922 } 1923 switch_in_progress = TRUE; 1924 old_scp = cur_console; 1925 new_scp = console[next_scr]; 1926 wakeup((caddr_t)&new_scp->smode); 1927 if (new_scp == old_scp) { 1928 switch_in_progress = FALSE; 1929 delayed_next_scr = FALSE; 1930 return 0; 1931 } 1932 1933 /* has controlling process died? */ 1934 if (old_scp->proc && (old_scp->proc != pfind(old_scp->pid))) 1935 old_scp->smode.mode = VT_AUTO; 1936 if (new_scp->proc && (new_scp->proc != pfind(new_scp->pid))) 1937 new_scp->smode.mode = VT_AUTO; 1938 1939 /* check the modes and switch appropriately */ 1940 if (old_scp->smode.mode == VT_PROCESS) { 1941 old_scp->status |= SWITCH_WAIT_REL; 1942 psignal(old_scp->proc, old_scp->smode.relsig); 1943 } 1944 else { 1945 exchange_scr(); 1946 if (new_scp->smode.mode == VT_PROCESS) { 1947 new_scp->status |= SWITCH_WAIT_ACQ; 1948 psignal(new_scp->proc, new_scp->smode.acqsig); 1949 } 1950 else 1951 switch_in_progress = FALSE; 1952 } 1953 return 0; 1954} 1955 1956static void 1957exchange_scr(void) 1958{ 1959 move_crsr(old_scp, old_scp->xpos, old_scp->ypos); 1960 cur_console = new_scp; 1961 if (old_scp->mode != new_scp->mode || (old_scp->status & UNKNOWN_MODE)){ 1962 if (crtc_vga && video_mode_ptr) 1963 set_mode(new_scp); 1964 } 1965 move_crsr(new_scp, new_scp->xpos, new_scp->ypos); 1966 if (!(new_scp->status & UNKNOWN_MODE) && (flags & CHAR_CURSOR)) 1967 set_destructive_cursor(new_scp); 1968 if ((old_scp->status & UNKNOWN_MODE) && crtc_vga) 1969 load_palette(palette); 1970 if (old_scp->status & KBD_RAW_MODE || new_scp->status & KBD_RAW_MODE) 1971 shfts = ctls = alts = agrs = metas = 0; 1972 update_leds(new_scp->status); 1973 delayed_next_scr = FALSE; 1974 mark_all(new_scp); 1975} 1976 1977static void 1978scan_esc(scr_stat *scp, u_char c) 1979{ 1980 static u_char ansi_col[16] = 1981 {0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15}; 1982 int i, n; 1983 u_short *src, *dst, count; 1984 1985 if (scp->term.esc == 1) { 1986 switch (c) { 1987 1988 case '7': /* Save cursor position */ 1989 scp->saved_xpos = scp->xpos; 1990 scp->saved_ypos = scp->ypos; 1991 break; 1992 1993 case '8': /* Restore saved cursor position */ 1994 if (scp->saved_xpos >= 0 && scp->saved_ypos >= 0) 1995 move_crsr(scp, scp->saved_xpos, scp->saved_ypos); 1996 break; 1997 1998 case '[': /* Start ESC [ sequence */ 1999 scp->term.esc = 2; 2000 scp->term.last_param = -1; 2001 for (i = scp->term.num_param; i < MAX_ESC_PAR; i++) 2002 scp->term.param[i] = 1; 2003 scp->term.num_param = 0; 2004 return; 2005 2006 case 'M': /* Move cursor up 1 line, scroll if at top */ 2007 if (scp->ypos > 0) 2008 move_crsr(scp, scp->xpos, scp->ypos - 1); 2009 else { 2010 bcopy(scp->scr_buf, scp->scr_buf + scp->xsize, 2011 (scp->ysize - 1) * scp->xsize * sizeof(u_short)); 2012 fillw(scp->term.cur_color | scr_map[0x20], 2013 scp->scr_buf, scp->xsize); 2014 mark_all(scp); 2015 } 2016 break; 2017#if notyet 2018 case 'Q': 2019 scp->term.esc = 4; 2020 break; 2021#endif 2022 case 'c': /* Clear screen & home */ 2023 clear_screen(scp); 2024 break; 2025 } 2026 } 2027 else if (scp->term.esc == 2) { 2028 if (c >= '0' && c <= '9') { 2029 if (scp->term.num_param < MAX_ESC_PAR) { 2030 if (scp->term.last_param != scp->term.num_param) { 2031 scp->term.last_param = scp->term.num_param; 2032 scp->term.param[scp->term.num_param] = 0; 2033 } 2034 else 2035 scp->term.param[scp->term.num_param] *= 10; 2036 scp->term.param[scp->term.num_param] += c - '0'; 2037 return; 2038 } 2039 } 2040 scp->term.num_param = scp->term.last_param + 1; 2041 switch (c) { 2042 2043 case ';': 2044 if (scp->term.num_param < MAX_ESC_PAR) 2045 return; 2046 break; 2047 2048 case '=': 2049 scp->term.esc = 3; 2050 scp->term.last_param = -1; 2051 for (i = scp->term.num_param; i < MAX_ESC_PAR; i++) 2052 scp->term.param[i] = 1; 2053 scp->term.num_param = 0; 2054 return; 2055 2056 case 'A': /* up n rows */ 2057 n = scp->term.param[0]; if (n < 1) n = 1; 2058 move_crsr(scp, scp->xpos, scp->ypos - n); 2059 break; 2060 2061 case 'B': /* down n rows */ 2062 n = scp->term.param[0]; if (n < 1) n = 1; 2063 move_crsr(scp, scp->xpos, scp->ypos + n); 2064 break; 2065 2066 case 'C': /* right n columns */ 2067 n = scp->term.param[0]; if (n < 1) n = 1; 2068 move_crsr(scp, scp->xpos + n, scp->ypos); 2069 break; 2070 2071 case 'D': /* left n columns */ 2072 n = scp->term.param[0]; if (n < 1) n = 1; 2073 move_crsr(scp, scp->xpos - n, scp->ypos); 2074 break; 2075 2076 case 'E': /* cursor to start of line n lines down */ 2077 n = scp->term.param[0]; if (n < 1) n = 1; 2078 move_crsr(scp, 0, scp->ypos + n); 2079 break; 2080 2081 case 'F': /* cursor to start of line n lines up */ 2082 n = scp->term.param[0]; if (n < 1) n = 1; 2083 move_crsr(scp, 0, scp->ypos - n); 2084 break; 2085 2086 case 'f': /* Cursor move */ 2087 case 'H': 2088 if (scp->term.num_param == 0) 2089 move_crsr(scp, 0, 0); 2090 else if (scp->term.num_param == 2) 2091 move_crsr(scp, scp->term.param[1] - 1, scp->term.param[0] - 1); 2092 break; 2093 2094 case 'J': /* Clear all or part of display */ 2095 if (scp->term.num_param == 0) 2096 n = 0; 2097 else 2098 n = scp->term.param[0]; 2099 switch (n) { 2100 case 0: /* clear form cursor to end of display */ 2101 fillw(scp->term.cur_color | scr_map[0x20], 2102 scp->cursor_pos, 2103 scp->scr_buf + scp->xsize * scp->ysize - scp->cursor_pos); 2104 mark_for_update(scp, scp->cursor_pos - scp->scr_buf); 2105 mark_for_update(scp, scp->xsize * scp->ysize); 2106 remove_cutmarking(scp); 2107 break; 2108 case 1: /* clear from beginning of display to cursor */ 2109 fillw(scp->term.cur_color | scr_map[0x20], 2110 scp->scr_buf, 2111 scp->cursor_pos - scp->scr_buf); 2112 mark_for_update(scp, 0); 2113 mark_for_update(scp, scp->cursor_pos - scp->scr_buf); 2114 remove_cutmarking(scp); 2115 break; 2116 case 2: /* clear entire display */ 2117 fillw(scp->term.cur_color | scr_map[0x20], scp->scr_buf, 2118 scp->xsize * scp->ysize); 2119 mark_all(scp); 2120 remove_cutmarking(scp); 2121 break; 2122 } 2123 break; 2124 2125 case 'K': /* Clear all or part of line */ 2126 if (scp->term.num_param == 0) 2127 n = 0; 2128 else 2129 n = scp->term.param[0]; 2130 switch (n) { 2131 case 0: /* clear form cursor to end of line */ 2132 fillw(scp->term.cur_color | scr_map[0x20], 2133 scp->cursor_pos, 2134 scp->xsize - scp->xpos); 2135 mark_for_update(scp, scp->cursor_pos - scp->scr_buf); 2136 mark_for_update(scp, scp->cursor_pos - scp->scr_buf + 2137 scp->xsize - scp->xpos); 2138 break; 2139 case 1: /* clear from beginning of line to cursor */ 2140 fillw(scp->term.cur_color | scr_map[0x20], 2141 scp->cursor_pos - scp->xpos, 2142 scp->xpos + 1); 2143 mark_for_update(scp, scp->ypos * scp->xsize); 2144 mark_for_update(scp, scp->cursor_pos - scp->scr_buf); 2145 break; 2146 case 2: /* clear entire line */ 2147 fillw(scp->term.cur_color | scr_map[0x20], 2148 scp->cursor_pos - scp->xpos, 2149 scp->xsize); 2150 mark_for_update(scp, scp->ypos * scp->xsize); 2151 mark_for_update(scp, (scp->ypos + 1) * scp->xsize); 2152 break; 2153 } 2154 break; 2155 2156 case 'L': /* Insert n lines */ 2157 n = scp->term.param[0]; if (n < 1) n = 1; 2158 if (n > scp->ysize - scp->ypos) 2159 n = scp->ysize - scp->ypos; 2160 src = scp->scr_buf + scp->ypos * scp->xsize; 2161 dst = src + n * scp->xsize; 2162 count = scp->ysize - (scp->ypos + n); 2163 bcopy(src, dst, count * scp->xsize * sizeof(u_short)); 2164 fillw(scp->term.cur_color | scr_map[0x20], src, 2165 n * scp->xsize); 2166 mark_for_update(scp, scp->ypos * scp->xsize); 2167 mark_for_update(scp, scp->xsize * scp->ysize); 2168 break; 2169 2170 case 'M': /* Delete n lines */ 2171 n = scp->term.param[0]; if (n < 1) n = 1; 2172 if (n > scp->ysize - scp->ypos) 2173 n = scp->ysize - scp->ypos; 2174 dst = scp->scr_buf + scp->ypos * scp->xsize; 2175 src = dst + n * scp->xsize; 2176 count = scp->ysize - (scp->ypos + n); 2177 bcopy(src, dst, count * scp->xsize * sizeof(u_short)); 2178 src = dst + count * scp->xsize; 2179 fillw(scp->term.cur_color | scr_map[0x20], src, 2180 n * scp->xsize); 2181 mark_for_update(scp, scp->ypos * scp->xsize); 2182 mark_for_update(scp, scp->xsize * scp->ysize); 2183 break; 2184 2185 case 'P': /* Delete n chars */ 2186 n = scp->term.param[0]; if (n < 1) n = 1; 2187 if (n > scp->xsize - scp->xpos) 2188 n = scp->xsize - scp->xpos; 2189 dst = scp->cursor_pos; 2190 src = dst + n; 2191 count = scp->xsize - (scp->xpos + n); 2192 bcopy(src, dst, count * sizeof(u_short)); 2193 src = dst + count; 2194 fillw(scp->term.cur_color | scr_map[0x20], src, n); 2195 mark_for_update(scp, scp->cursor_pos - scp->scr_buf); 2196 mark_for_update(scp, scp->cursor_pos - scp->scr_buf + n + count); 2197 break; 2198 2199 case '@': /* Insert n chars */ 2200 n = scp->term.param[0]; if (n < 1) n = 1; 2201 if (n > scp->xsize - scp->xpos) 2202 n = scp->xsize - scp->xpos; 2203 src = scp->cursor_pos; 2204 dst = src + n; 2205 count = scp->xsize - (scp->xpos + n); 2206 bcopy(src, dst, count * sizeof(u_short)); 2207 fillw(scp->term.cur_color | scr_map[0x20], src, n); 2208 mark_for_update(scp, scp->cursor_pos - scp->scr_buf); 2209 mark_for_update(scp, scp->cursor_pos - scp->scr_buf + n + count); 2210 break; 2211 2212 case 'S': /* scroll up n lines */ 2213 n = scp->term.param[0]; if (n < 1) n = 1; 2214 if (n > scp->ysize) 2215 n = scp->ysize; 2216 bcopy(scp->scr_buf + (scp->xsize * n), 2217 scp->scr_buf, 2218 scp->xsize * (scp->ysize - n) * sizeof(u_short)); 2219 fillw(scp->term.cur_color | scr_map[0x20], 2220 scp->scr_buf + scp->xsize * (scp->ysize - n), 2221 scp->xsize * n); 2222 mark_all(scp); 2223 break; 2224 2225 case 'T': /* scroll down n lines */ 2226 n = scp->term.param[0]; if (n < 1) n = 1; 2227 if (n > scp->ysize) 2228 n = scp->ysize; 2229 bcopy(scp->scr_buf, 2230 scp->scr_buf + (scp->xsize * n), 2231 scp->xsize * (scp->ysize - n) * 2232 sizeof(u_short)); 2233 fillw(scp->term.cur_color | scr_map[0x20], 2234 scp->scr_buf, scp->xsize * n); 2235 mark_all(scp); 2236 break; 2237 2238 case 'X': /* erase n characters in line */ 2239 n = scp->term.param[0]; if (n < 1) n = 1; 2240 if (n > scp->xsize - scp->xpos) 2241 n = scp->xsize - scp->xpos; 2242 fillw(scp->term.cur_color | scr_map[0x20], 2243 scp->cursor_pos, n); 2244 mark_for_update(scp, scp->cursor_pos - scp->scr_buf); 2245 mark_for_update(scp, scp->cursor_pos - scp->scr_buf + n); 2246 break; 2247 2248 case 'Z': /* move n tabs backwards */ 2249 n = scp->term.param[0]; if (n < 1) n = 1; 2250 if ((i = scp->xpos & 0xf8) == scp->xpos) 2251 i -= 8*n; 2252 else 2253 i -= 8*(n-1); 2254 if (i < 0) 2255 i = 0; 2256 move_crsr(scp, i, scp->ypos); 2257 break; 2258 2259 case '`': /* move cursor to column n */ 2260 n = scp->term.param[0]; if (n < 1) n = 1; 2261 move_crsr(scp, n - 1, scp->ypos); 2262 break; 2263 2264 case 'a': /* move cursor n columns to the right */ 2265 n = scp->term.param[0]; if (n < 1) n = 1; 2266 move_crsr(scp, scp->xpos + n, scp->ypos); 2267 break; 2268 2269 case 'd': /* move cursor to row n */ 2270 n = scp->term.param[0]; if (n < 1) n = 1; 2271 move_crsr(scp, scp->xpos, n - 1); 2272 break; 2273 2274 case 'e': /* move cursor n rows down */ 2275 n = scp->term.param[0]; if (n < 1) n = 1; 2276 move_crsr(scp, scp->xpos, scp->ypos + n); 2277 break; 2278 2279 case 'm': /* change attribute */ 2280 if (scp->term.num_param == 0) { 2281 scp->term.attr_mask = NORMAL_ATTR; 2282 scp->term.cur_attr = 2283 scp->term.cur_color = scp->term.std_color; 2284 break; 2285 } 2286 for (i = 0; i < scp->term.num_param; i++) { 2287 switch (n = scp->term.param[i]) { 2288 case 0: /* back to normal */ 2289 scp->term.attr_mask = NORMAL_ATTR; 2290 scp->term.cur_attr = 2291 scp->term.cur_color = scp->term.std_color; 2292 break; 2293 case 1: /* bold */ 2294 scp->term.attr_mask |= BOLD_ATTR; 2295 scp->term.cur_attr = mask2attr(&scp->term); 2296 break; 2297 case 4: /* underline */ 2298 scp->term.attr_mask |= UNDERLINE_ATTR; 2299 scp->term.cur_attr = mask2attr(&scp->term); 2300 break; 2301 case 5: /* blink */ 2302 scp->term.attr_mask |= BLINK_ATTR; 2303 scp->term.cur_attr = mask2attr(&scp->term); 2304 break; 2305 case 7: /* reverse video */ 2306 scp->term.attr_mask |= REVERSE_ATTR; 2307 scp->term.cur_attr = mask2attr(&scp->term); 2308 break; 2309 case 30: case 31: /* set fg color */ 2310 case 32: case 33: case 34: 2311 case 35: case 36: case 37: 2312 scp->term.attr_mask |= FOREGROUND_CHANGED; 2313 scp->term.cur_color = 2314 (scp->term.cur_color&0xF000) | (ansi_col[(n-30)&7]<<8); 2315 scp->term.cur_attr = mask2attr(&scp->term); 2316 break; 2317 case 40: case 41: /* set bg color */ 2318 case 42: case 43: case 44: 2319 case 45: case 46: case 47: 2320 scp->term.attr_mask |= BACKGROUND_CHANGED; 2321 scp->term.cur_color = 2322 (scp->term.cur_color&0x0F00) | (ansi_col[(n-40)&7]<<12); 2323 scp->term.cur_attr = mask2attr(&scp->term); 2324 break; 2325 } 2326 } 2327 break; 2328 2329 case 's': /* Save cursor position */ 2330 scp->saved_xpos = scp->xpos; 2331 scp->saved_ypos = scp->ypos; 2332 break; 2333 2334 case 'u': /* Restore saved cursor position */ 2335 if (scp->saved_xpos >= 0 && scp->saved_ypos >= 0) 2336 move_crsr(scp, scp->saved_xpos, scp->saved_ypos); 2337 break; 2338 2339 case 'x': 2340 if (scp->term.num_param == 0) 2341 n = 0; 2342 else 2343 n = scp->term.param[0]; 2344 switch (n) { 2345 case 0: /* reset attributes */ 2346 scp->term.attr_mask = NORMAL_ATTR; 2347 scp->term.cur_attr = 2348 scp->term.cur_color = scp->term.std_color = 2349 current_default->std_color; 2350 scp->term.rev_color = current_default->rev_color; 2351 break; 2352 case 1: /* set ansi background */ 2353 scp->term.attr_mask &= ~BACKGROUND_CHANGED; 2354 scp->term.cur_color = scp->term.std_color = 2355 (scp->term.std_color & 0x0F00) | 2356 (ansi_col[(scp->term.param[1])&0x0F]<<12); 2357 scp->term.cur_attr = mask2attr(&scp->term); 2358 break; 2359 case 2: /* set ansi foreground */ 2360 scp->term.attr_mask &= ~FOREGROUND_CHANGED; 2361 scp->term.cur_color = scp->term.std_color = 2362 (scp->term.std_color & 0xF000) | 2363 (ansi_col[(scp->term.param[1])&0x0F]<<8); 2364 scp->term.cur_attr = mask2attr(&scp->term); 2365 break; 2366 case 3: /* set ansi attribute directly */ 2367 scp->term.attr_mask &= ~(FOREGROUND_CHANGED|BACKGROUND_CHANGED); 2368 scp->term.cur_color = scp->term.std_color = 2369 (scp->term.param[1]&0xFF)<<8; 2370 scp->term.cur_attr = mask2attr(&scp->term); 2371 break; 2372 case 5: /* set ansi reverse video background */ 2373 scp->term.rev_color = 2374 (scp->term.rev_color & 0x0F00) | 2375 (ansi_col[(scp->term.param[1])&0x0F]<<12); 2376 scp->term.cur_attr = mask2attr(&scp->term); 2377 break; 2378 case 6: /* set ansi reverse video foreground */ 2379 scp->term.rev_color = 2380 (scp->term.rev_color & 0xF000) | 2381 (ansi_col[(scp->term.param[1])&0x0F]<<8); 2382 scp->term.cur_attr = mask2attr(&scp->term); 2383 break; 2384 case 7: /* set ansi reverse video directly */ 2385 scp->term.rev_color = 2386 (scp->term.param[1]&0xFF)<<8; 2387 scp->term.cur_attr = mask2attr(&scp->term); 2388 break; 2389 } 2390 break; 2391 2392 case 'z': /* switch to (virtual) console n */ 2393 if (scp->term.num_param == 1) 2394 switch_scr(scp, scp->term.param[0]); 2395 break; 2396 } 2397 } 2398 else if (scp->term.esc == 3) { 2399 if (c >= '0' && c <= '9') { 2400 if (scp->term.num_param < MAX_ESC_PAR) { 2401 if (scp->term.last_param != scp->term.num_param) { 2402 scp->term.last_param = scp->term.num_param; 2403 scp->term.param[scp->term.num_param] = 0; 2404 } 2405 else 2406 scp->term.param[scp->term.num_param] *= 10; 2407 scp->term.param[scp->term.num_param] += c - '0'; 2408 return; 2409 } 2410 } 2411 scp->term.num_param = scp->term.last_param + 1; 2412 switch (c) { 2413 2414 case ';': 2415 if (scp->term.num_param < MAX_ESC_PAR) 2416 return; 2417 break; 2418 2419 case 'A': /* set display border color */ 2420 if (scp->term.num_param == 1) { 2421 scp->border=scp->term.param[0] & 0xff; 2422 if (scp == cur_console) 2423 set_border(scp->border); 2424 } 2425 break; 2426 2427 case 'B': /* set bell pitch and duration */ 2428 if (scp->term.num_param == 2) { 2429 scp->bell_pitch = scp->term.param[0]; 2430 scp->bell_duration = scp->term.param[1]*10; 2431 } 2432 break; 2433 2434 case 'C': /* set cursor type & shape */ 2435 if (scp->term.num_param == 1) { 2436 if (scp->term.param[0] & 0x01) 2437 flags |= BLINK_CURSOR; 2438 else 2439 flags &= ~BLINK_CURSOR; 2440 if ((scp->term.param[0] & 0x02) && crtc_vga) 2441 flags |= CHAR_CURSOR; 2442 else 2443 flags &= ~CHAR_CURSOR; 2444 } 2445 else if (scp->term.num_param == 2) { 2446 scp->cursor_start = scp->term.param[0] & 0x1F; 2447 scp->cursor_end = scp->term.param[1] & 0x1F; 2448 } 2449 /* 2450 * The cursor shape is global property; all virtual consoles 2451 * are affected. Update the cursor in the current console... 2452 */ 2453 if (!(cur_console->status & UNKNOWN_MODE)) { 2454 remove_cursor_image(cur_console); 2455 if (crtc_vga && (flags & CHAR_CURSOR)) 2456 set_destructive_cursor(cur_console); 2457 draw_cursor_image(cur_console); 2458 } 2459 break; 2460 2461 case 'F': /* set ansi foreground */ 2462 if (scp->term.num_param == 1) { 2463 scp->term.attr_mask &= ~FOREGROUND_CHANGED; 2464 scp->term.cur_color = scp->term.std_color = 2465 (scp->term.std_color & 0xF000) 2466 | ((scp->term.param[0] & 0x0F) << 8); 2467 scp->term.cur_attr = mask2attr(&scp->term); 2468 } 2469 break; 2470 2471 case 'G': /* set ansi background */ 2472 if (scp->term.num_param == 1) { 2473 scp->term.attr_mask &= ~BACKGROUND_CHANGED; 2474 scp->term.cur_color = scp->term.std_color = 2475 (scp->term.std_color & 0x0F00) 2476 | ((scp->term.param[0] & 0x0F) << 12); 2477 scp->term.cur_attr = mask2attr(&scp->term); 2478 } 2479 break; 2480 2481 case 'H': /* set ansi reverse video foreground */ 2482 if (scp->term.num_param == 1) { 2483 scp->term.rev_color = 2484 (scp->term.rev_color & 0xF000) 2485 | ((scp->term.param[0] & 0x0F) << 8); 2486 scp->term.cur_attr = mask2attr(&scp->term); 2487 } 2488 break; 2489 2490 case 'I': /* set ansi reverse video background */ 2491 if (scp->term.num_param == 1) { 2492 scp->term.rev_color = 2493 (scp->term.rev_color & 0x0F00) 2494 | ((scp->term.param[0] & 0x0F) << 12); 2495 scp->term.cur_attr = mask2attr(&scp->term); 2496 } 2497 break; 2498 } 2499 } 2500 scp->term.esc = 0; 2501} 2502 2503static void 2504ansi_put(scr_stat *scp, u_char *buf, int len) 2505{ 2506 u_char *ptr = buf; 2507 2508 /* make screensaver happy */ 2509 if (scp == cur_console) 2510 scrn_time_stamp = mono_time.tv_sec; 2511 2512 write_in_progress++; 2513outloop: 2514 if (scp->term.esc) { 2515 scan_esc(scp, *ptr++); 2516 len--; 2517 } 2518 else if (PRINTABLE(*ptr)) { /* Print only printables */ 2519 int cnt = len <= (scp->xsize-scp->xpos) ? len : (scp->xsize-scp->xpos); 2520 u_short cur_attr = scp->term.cur_attr; 2521 u_short *cursor_pos = scp->cursor_pos; 2522 do { 2523 /* 2524 * gcc-2.6.3 generates poor (un)sign extension code. Casting the 2525 * pointers in the following to volatile should have no effect, 2526 * but in fact speeds up this inner loop from 26 to 18 cycles 2527 * (+ cache misses) on i486's. 2528 */ 2529#define UCVP(ucp) ((u_char volatile *)(ucp)) 2530 *cursor_pos++ = UCVP(scr_map)[*UCVP(ptr)] | cur_attr; 2531 ptr++; 2532 cnt--; 2533 } while (cnt && PRINTABLE(*ptr)); 2534 len -= (cursor_pos - scp->cursor_pos); 2535 scp->xpos += (cursor_pos - scp->cursor_pos); 2536 mark_for_update(scp, scp->cursor_pos - scp->scr_buf); 2537 mark_for_update(scp, cursor_pos - scp->scr_buf); 2538 scp->cursor_pos = cursor_pos; 2539 if (scp->xpos >= scp->xsize) { 2540 scp->xpos = 0; 2541 scp->ypos++; 2542 } 2543 } 2544 else { 2545 switch(*ptr) { 2546 case 0x07: 2547 do_bell(scp, scp->bell_pitch, scp->bell_duration); 2548 break; 2549 2550 case 0x08: /* non-destructive backspace */ 2551 if (scp->cursor_pos > scp->scr_buf) { 2552 mark_for_update(scp, scp->cursor_pos - scp->scr_buf); 2553 scp->cursor_pos--; 2554 mark_for_update(scp, scp->cursor_pos - scp->scr_buf); 2555 if (scp->xpos > 0) 2556 scp->xpos--; 2557 else { 2558 scp->xpos += scp->xsize - 1; 2559 scp->ypos--; 2560 } 2561 } 2562 break; 2563 2564 case 0x09: /* non-destructive tab */ 2565 mark_for_update(scp, scp->cursor_pos - scp->scr_buf); 2566 scp->cursor_pos += (8 - scp->xpos % 8u); 2567 mark_for_update(scp, scp->cursor_pos - scp->scr_buf); 2568 if ((scp->xpos += (8 - scp->xpos % 8u)) >= scp->xsize) { 2569 scp->xpos = 0; 2570 scp->ypos++; 2571 } 2572 break; 2573 2574 case 0x0a: /* newline, same pos */ 2575 mark_for_update(scp, scp->cursor_pos - scp->scr_buf); 2576 scp->cursor_pos += scp->xsize; 2577 mark_for_update(scp, scp->cursor_pos - scp->scr_buf); 2578 scp->ypos++; 2579 break; 2580 2581 case 0x0c: /* form feed, clears screen */ 2582 clear_screen(scp); 2583 break; 2584 2585 case 0x0d: /* return, return to pos 0 */ 2586 mark_for_update(scp, scp->cursor_pos - scp->scr_buf); 2587 scp->cursor_pos -= scp->xpos; 2588 mark_for_update(scp, scp->cursor_pos - scp->scr_buf); 2589 scp->xpos = 0; 2590 break; 2591 2592 case 0x1b: /* start escape sequence */ 2593 scp->term.esc = 1; 2594 scp->term.num_param = 0; 2595 break; 2596 } 2597 ptr++; len--; 2598 } 2599 /* do we have to scroll ?? */ 2600 if (scp->cursor_pos >= scp->scr_buf + scp->ysize * scp->xsize) { 2601 remove_cutmarking(scp); 2602 if (scp->history) { 2603 bcopy(scp->scr_buf, scp->history_head, 2604 scp->xsize * sizeof(u_short)); 2605 scp->history_head += scp->xsize; 2606 if (scp->history_head + scp->xsize > 2607 scp->history + scp->history_size) 2608 scp->history_head = scp->history; 2609 } 2610 bcopy(scp->scr_buf + scp->xsize, scp->scr_buf, 2611 scp->xsize * (scp->ysize - 1) * sizeof(u_short)); 2612 fillw(scp->term.cur_color | scr_map[0x20], 2613 scp->scr_buf + scp->xsize * (scp->ysize - 1), 2614 scp->xsize); 2615 scp->cursor_pos -= scp->xsize; 2616 scp->ypos--; 2617 mark_all(scp); 2618 } 2619 if (len) 2620 goto outloop; 2621 write_in_progress--; 2622 if (delayed_next_scr) 2623 switch_scr(scp, delayed_next_scr - 1); 2624} 2625 2626static void 2627scinit(void) 2628{ 2629 u_int hw_cursor; 2630 u_int i; 2631 2632 if (init_done != COLD) 2633 return; 2634 init_done = WARM; 2635 2636 /* 2637 * Ensure a zero start address. This is mainly to recover after 2638 * switching from pcvt using userconfig(). The registers are w/o 2639 * for old hardware so it's too hard to relocate the active screen 2640 * memory. 2641 */ 2642 outb(crtc_addr, 12); 2643 outb(crtc_addr + 1, 0); 2644 outb(crtc_addr, 13); 2645 outb(crtc_addr + 1, 0); 2646 2647 /* extract cursor location */ 2648 outb(crtc_addr, 14); 2649 hw_cursor = inb(crtc_addr + 1) << 8; 2650 outb(crtc_addr, 15); 2651 hw_cursor |= inb(crtc_addr + 1); 2652 2653 /* 2654 * Validate cursor location. It may be off the screen. Then we must 2655 * not use it for the initial buffer offset. 2656 */ 2657 if (hw_cursor >= ROW * COL) 2658 hw_cursor = (ROW - 1) * COL; 2659 2660 /* move hardware cursor out of the way */ 2661 outb(crtc_addr, 14); 2662 outb(crtc_addr + 1, 0xff); 2663 outb(crtc_addr, 15); 2664 outb(crtc_addr + 1, 0xff); 2665 2666 /* set up the first console */ 2667 current_default = &user_default; 2668 console[0] = &main_console; 2669 init_scp(console[0]); 2670 cur_console = console[0]; 2671 2672 /* discard the video mode table if we are not familiar with it... */ 2673 if (video_mode_ptr) { 2674 if (comp_vgaregs(vgaregs, video_mode_ptr + 64*console[0]->mode)) 2675 video_mode_ptr = NULL; 2676 } 2677 2678 /* copy screen to temporary buffer */ 2679 sc_bcopy(Crtat, sc_buffer, 2680 console[0]->xsize * console[0]->ysize * sizeof(u_short)); 2681 2682 console[0]->scr_buf = console[0]->mouse_pos = sc_buffer; 2683 console[0]->cursor_pos = console[0]->cursor_oldpos = sc_buffer + hw_cursor; 2684 console[0]->cursor_saveunder = *console[0]->cursor_pos; 2685 console[0]->xpos = hw_cursor % COL; 2686 console[0]->ypos = hw_cursor / COL; 2687 for (i=1; i<MAXCONS; i++) 2688 console[i] = NULL; 2689 kernel_console.esc = 0; 2690 kernel_console.attr_mask = NORMAL_ATTR; 2691 kernel_console.cur_attr = 2692 kernel_console.cur_color = kernel_console.std_color = 2693 kernel_default.std_color; 2694 kernel_console.rev_color = kernel_default.rev_color; 2695 2696 /* initialize mapscrn arrays to a one to one map */ 2697 for (i=0; i<sizeof(scr_map); i++) { 2698 scr_map[i] = scr_rmap[i] = i; 2699 } 2700 2701 /* Save font and palette if VGA */ 2702 if (crtc_vga) { 2703 copy_font(SAVE, FONT_16, font_16); 2704 fonts_loaded = FONT_16; 2705 save_palette(); 2706 set_destructive_cursor(console[0]); 2707 } 2708 2709#ifdef SC_SPLASH_SCREEN 2710 /* 2711 * Now put up a graphics image, and maybe cycle a 2712 * couble of palette entries for simple animation. 2713 */ 2714 toggle_splash_screen(cur_console); 2715#endif 2716} 2717 2718static scr_stat 2719*alloc_scp() 2720{ 2721 scr_stat *scp; 2722 2723 scp = (scr_stat *)malloc(sizeof(scr_stat), M_DEVBUF, M_WAITOK); 2724 init_scp(scp); 2725 scp->scr_buf = scp->cursor_pos = scp->cursor_oldpos = 2726 (u_short *)malloc(scp->xsize*scp->ysize*sizeof(u_short), 2727 M_DEVBUF, M_WAITOK); 2728 scp->mouse_pos = scp->mouse_oldpos = 2729 scp->scr_buf + ((scp->mouse_ypos/scp->font_size)*scp->xsize + 2730 scp->mouse_xpos/8); 2731 scp->history_head = scp->history_pos = scp->history = 2732 (u_short *)malloc(scp->history_size*sizeof(u_short), 2733 M_DEVBUF, M_WAITOK); 2734 bzero(scp->history_head, scp->history_size*sizeof(u_short)); 2735/* SOS 2736 if (crtc_vga && video_mode_ptr) 2737 set_mode(scp); 2738*/ 2739 clear_screen(scp); 2740 scp->cursor_saveunder = *scp->cursor_pos; 2741 return scp; 2742} 2743 2744static void 2745init_scp(scr_stat *scp) 2746{ 2747 if (crtc_vga) 2748 if (crtc_addr == MONO_BASE) 2749 scp->mode = M_VGA_M80x25; 2750 else 2751 scp->mode = M_VGA_C80x25; 2752 else 2753 if (crtc_addr == MONO_BASE) 2754 scp->mode = M_B80x25; 2755 else 2756 scp->mode = M_C80x25; 2757 2758 scp->font_size = 16; 2759 scp->xsize = COL; 2760 scp->ysize = ROW; 2761 scp->xpos = scp->ypos = 0; 2762 scp->saved_xpos = scp->saved_ypos = -1; 2763 scp->start = scp->xsize * scp->ysize; 2764 scp->end = 0; 2765 scp->term.esc = 0; 2766 scp->term.attr_mask = NORMAL_ATTR; 2767 scp->term.cur_attr = 2768 scp->term.cur_color = scp->term.std_color = 2769 current_default->std_color; 2770 scp->term.rev_color = current_default->rev_color; 2771 scp->border = BG_BLACK; 2772 scp->cursor_start = *(char *)pa_to_va(0x461); 2773 scp->cursor_end = *(char *)pa_to_va(0x460); 2774 scp->mouse_xpos = scp->xsize*8/2; 2775 scp->mouse_ypos = scp->ysize*scp->font_size/2; 2776 scp->mouse_cut_start = scp->mouse_cut_end = NULL; 2777 scp->mouse_signal = 0; 2778 scp->mouse_pid = 0; 2779 scp->mouse_proc = NULL; 2780 scp->bell_pitch = BELL_PITCH; 2781 scp->bell_duration = BELL_DURATION; 2782 scp->status = (*(char *)pa_to_va(0x417) & 0x20) ? NLKED : 0; 2783 scp->status |= CURSOR_ENABLED; 2784 scp->pid = 0; 2785 scp->proc = NULL; 2786 scp->smode.mode = VT_AUTO; 2787 scp->history_head = scp->history_pos = scp->history = NULL; 2788 scp->history_size = HISTORY_SIZE; 2789} 2790 2791static u_char 2792*get_fstr(u_int c, u_int *len) 2793{ 2794 u_int i; 2795 2796 if (!(c & FKEY)) 2797 return(NULL); 2798 i = (c & 0xFF) - F_FN; 2799 if (i > n_fkey_tab) 2800 return(NULL); 2801 *len = fkey_tab[i].len; 2802 return(fkey_tab[i].str); 2803} 2804 2805static void 2806history_to_screen(scr_stat *scp) 2807{ 2808 int i; 2809 2810 for (i=0; i<scp->ysize; i++) 2811 bcopy(scp->history + (((scp->history_pos - scp->history) + 2812 scp->history_size-((i+1)*scp->xsize))%scp->history_size), 2813 scp->scr_buf + (scp->xsize * (scp->ysize-1 - i)), 2814 scp->xsize * sizeof(u_short)); 2815 mark_all(scp); 2816} 2817 2818static int 2819history_up_line(scr_stat *scp) 2820{ 2821 if (WRAPHIST(scp, scp->history_pos, -(scp->xsize*scp->ysize)) != 2822 scp->history_head) { 2823 scp->history_pos = WRAPHIST(scp, scp->history_pos, -scp->xsize); 2824 history_to_screen(scp); 2825 return 0; 2826 } 2827 else 2828 return -1; 2829} 2830 2831static int 2832history_down_line(scr_stat *scp) 2833{ 2834 if (scp->history_pos != scp->history_head) { 2835 scp->history_pos = WRAPHIST(scp, scp->history_pos, scp->xsize); 2836 history_to_screen(scp); 2837 return 0; 2838 } 2839 else 2840 return -1; 2841} 2842 2843/* 2844 * scgetc(flags) - get character from keyboard. 2845 * If flags & SCGETC_CN, then avoid harmful side effects. 2846 * If flags & SCGETC_NONBLOCK, then wait until a key is pressed, else 2847 * return NOKEY if there is nothing there. 2848 */ 2849static u_int 2850scgetc(u_int flags) 2851{ 2852 struct key_t *key; 2853 u_char scancode, keycode; 2854 u_int state, action; 2855 int c; 2856 static u_char esc_flag = 0, compose = 0; 2857 static u_int chr = 0; 2858 2859next_code: 2860 /* first see if there is something in the keyboard port */ 2861 if (flags & SCGETC_NONBLOCK) { 2862 c = read_kbd_data_no_wait(sc_kbdc); 2863 if (c == -1) 2864 return(NOKEY); 2865 } else { 2866 do { 2867 c = read_kbd_data(sc_kbdc); 2868 } while(c == -1); 2869 } 2870 scancode = (u_char)c; 2871 2872 /* do the /dev/random device a favour */ 2873 if (!(flags & SCGETC_CN)) 2874 add_keyboard_randomness(scancode); 2875 2876 if (cur_console->status & KBD_RAW_MODE) 2877 return scancode; 2878 2879 keycode = scancode & 0x7F; 2880 switch (esc_flag) { 2881 case 0x00: /* normal scancode */ 2882 switch(scancode) { 2883 case 0xB8: /* left alt (compose key) */ 2884 if (compose) { 2885 compose = 0; 2886 if (chr > 255) { 2887 do_bell(cur_console, 2888 BELL_PITCH, BELL_DURATION); 2889 chr = 0; 2890 } 2891 } 2892 break; 2893 case 0x38: 2894 if (!compose) { 2895 compose = 1; 2896 chr = 0; 2897 } 2898 break; 2899 case 0xE0: 2900 case 0xE1: 2901 esc_flag = scancode; 2902 goto next_code; 2903 } 2904 break; 2905 case 0xE0: /* 0xE0 prefix */ 2906 esc_flag = 0; 2907 switch (keycode) { 2908 case 0x1C: /* right enter key */ 2909 keycode = 0x59; 2910 break; 2911 case 0x1D: /* right ctrl key */ 2912 keycode = 0x5A; 2913 break; 2914 case 0x35: /* keypad divide key */ 2915 keycode = 0x5B; 2916 break; 2917 case 0x37: /* print scrn key */ 2918 keycode = 0x5C; 2919 break; 2920 case 0x38: /* right alt key (alt gr) */ 2921 keycode = 0x5D; 2922 break; 2923 case 0x47: /* grey home key */ 2924 keycode = 0x5E; 2925 break; 2926 case 0x48: /* grey up arrow key */ 2927 keycode = 0x5F; 2928 break; 2929 case 0x49: /* grey page up key */ 2930 keycode = 0x60; 2931 break; 2932 case 0x4B: /* grey left arrow key */ 2933 keycode = 0x61; 2934 break; 2935 case 0x4D: /* grey right arrow key */ 2936 keycode = 0x62; 2937 break; 2938 case 0x4F: /* grey end key */ 2939 keycode = 0x63; 2940 break; 2941 case 0x50: /* grey down arrow key */ 2942 keycode = 0x64; 2943 break; 2944 case 0x51: /* grey page down key */ 2945 keycode = 0x65; 2946 break; 2947 case 0x52: /* grey insert key */ 2948 keycode = 0x66; 2949 break; 2950 case 0x53: /* grey delete key */ 2951 keycode = 0x67; 2952 break; 2953 2954 /* the following 3 are only used on the MS "Natural" keyboard */ 2955 case 0x5b: /* left Window key */ 2956 keycode = 0x69; 2957 break; 2958 case 0x5c: /* right Window key */ 2959 keycode = 0x6a; 2960 break; 2961 case 0x5d: /* menu key */ 2962 keycode = 0x6b; 2963 break; 2964 default: /* ignore everything else */ 2965 goto next_code; 2966 } 2967 break; 2968 case 0xE1: /* 0xE1 prefix */ 2969 esc_flag = 0; 2970 if (keycode == 0x1D) 2971 esc_flag = 0x1D; 2972 goto next_code; 2973 /* NOT REACHED */ 2974 case 0x1D: /* pause / break */ 2975 esc_flag = 0; 2976 if (keycode != 0x45) 2977 goto next_code; 2978 keycode = 0x68; 2979 break; 2980 } 2981 2982 /* if scroll-lock pressed allow history browsing */ 2983 if (cur_console->history && cur_console->status & SLKED) { 2984 int i; 2985 2986 cur_console->status &= ~CURSOR_ENABLED; 2987 if (!(cur_console->status & BUFFER_SAVED)) { 2988 cur_console->status |= BUFFER_SAVED; 2989 cur_console->history_save = cur_console->history_head; 2990 2991 /* copy screen into top of history buffer */ 2992 for (i=0; i<cur_console->ysize; i++) { 2993 bcopy(cur_console->scr_buf + (cur_console->xsize * i), 2994 cur_console->history_head, 2995 cur_console->xsize * sizeof(u_short)); 2996 cur_console->history_head += cur_console->xsize; 2997 if (cur_console->history_head + cur_console->xsize > 2998 cur_console->history + cur_console->history_size) 2999 cur_console->history_head=cur_console->history; 3000 } 3001 cur_console->history_pos = cur_console->history_head; 3002 history_to_screen(cur_console); 3003 } 3004 switch (scancode) { 3005 case 0x47: /* home key */ 3006 cur_console->history_pos = cur_console->history_head; 3007 history_to_screen(cur_console); 3008 goto next_code; 3009 3010 case 0x4F: /* end key */ 3011 cur_console->history_pos = 3012 WRAPHIST(cur_console, cur_console->history_head, 3013 cur_console->xsize*cur_console->ysize); 3014 history_to_screen(cur_console); 3015 goto next_code; 3016 3017 case 0x48: /* up arrow key */ 3018 if (history_up_line(cur_console)) 3019 do_bell(cur_console, BELL_PITCH, BELL_DURATION); 3020 goto next_code; 3021 3022 case 0x50: /* down arrow key */ 3023 if (history_down_line(cur_console)) 3024 do_bell(cur_console, BELL_PITCH, BELL_DURATION); 3025 goto next_code; 3026 3027 case 0x49: /* page up key */ 3028 for (i=0; i<cur_console->ysize; i++) 3029 if (history_up_line(cur_console)) { 3030 do_bell(cur_console, BELL_PITCH, BELL_DURATION); 3031 break; 3032 } 3033 goto next_code; 3034 3035 case 0x51: /* page down key */ 3036 for (i=0; i<cur_console->ysize; i++) 3037 if (history_down_line(cur_console)) { 3038 do_bell(cur_console, BELL_PITCH, BELL_DURATION); 3039 break; 3040 } 3041 goto next_code; 3042 } 3043 } 3044 3045 if (compose) { 3046 switch (scancode) { 3047 /* key pressed process it */ 3048 case 0x47: case 0x48: case 0x49: /* keypad 7,8,9 */ 3049 chr = (scancode - 0x40) + chr*10; 3050 goto next_code; 3051 case 0x4B: case 0x4C: case 0x4D: /* keypad 4,5,6 */ 3052 chr = (scancode - 0x47) + chr*10; 3053 goto next_code; 3054 case 0x4F: case 0x50: case 0x51: /* keypad 1,2,3 */ 3055 chr = (scancode - 0x4E) + chr*10; 3056 goto next_code; 3057 case 0x52: /* keypad 0 */ 3058 chr *= 10; 3059 goto next_code; 3060 3061 /* key release, no interest here */ 3062 case 0xC7: case 0xC8: case 0xC9: /* keypad 7,8,9 */ 3063 case 0xCB: case 0xCC: case 0xCD: /* keypad 4,5,6 */ 3064 case 0xCF: case 0xD0: case 0xD1: /* keypad 1,2,3 */ 3065 case 0xD2: /* keypad 0 */ 3066 goto next_code; 3067 3068 case 0x38: /* left alt key */ 3069 break; 3070 default: 3071 if (chr) { 3072 compose = chr = 0; 3073 do_bell(cur_console, BELL_PITCH, BELL_DURATION); 3074 goto next_code; 3075 } 3076 break; 3077 } 3078 } 3079 3080 state = (shfts ? 1 : 0 ) | (2 * (ctls ? 1 : 0)) | (4 * (alts ? 1 : 0)); 3081 if ((!agrs && (cur_console->status & ALKED)) 3082 || (agrs && !(cur_console->status & ALKED))) 3083 keycode += ALTGR_OFFSET; 3084 key = &key_map.key[keycode]; 3085 if ( ((key->flgs & FLAG_LOCK_C) && (cur_console->status & CLKED)) 3086 || ((key->flgs & FLAG_LOCK_N) && (cur_console->status & NLKED)) ) 3087 state ^= 1; 3088 3089 /* Check for make/break */ 3090 action = key->map[state]; 3091 if (scancode & 0x80) { /* key released */ 3092 if (key->spcl & (0x80>>state)) { 3093 switch (action) { 3094 case LSH: 3095 shfts &= ~1; 3096 break; 3097 case RSH: 3098 shfts &= ~2; 3099 break; 3100 case LCTR: 3101 ctls &= ~1; 3102 break; 3103 case RCTR: 3104 ctls &= ~2; 3105 break; 3106 case LALT: 3107 alts &= ~1; 3108 break; 3109 case RALT: 3110 alts &= ~2; 3111 break; 3112 case NLK: 3113 nlkcnt = 0; 3114 break; 3115 case CLK: 3116 clkcnt = 0; 3117 break; 3118 case SLK: 3119 slkcnt = 0; 3120 break; 3121 case ASH: 3122 agrs = 0; 3123 break; 3124 case ALK: 3125 alkcnt = 0; 3126 break; 3127 case META: 3128 metas = 0; 3129 break; 3130 } 3131 } 3132 if (chr && !compose) { 3133 action = chr; 3134 chr = 0; 3135 return(action); 3136 } 3137 } else { 3138 /* key pressed */ 3139 if (key->spcl & (0x80>>state)) { 3140 switch (action) { 3141 /* LOCKING KEYS */ 3142 case NLK: 3143#ifdef SC_SPLASH_SCREEN 3144 toggle_splash_screen(cur_console); /* SOS XXX */ 3145#endif 3146 if (!nlkcnt) { 3147 nlkcnt++; 3148 if (cur_console->status & NLKED) 3149 cur_console->status &= ~NLKED; 3150 else 3151 cur_console->status |= NLKED; 3152 update_leds(cur_console->status); 3153 } 3154 break; 3155 case CLK: 3156 if (!clkcnt) { 3157 clkcnt++; 3158 if (cur_console->status & CLKED) 3159 cur_console->status &= ~CLKED; 3160 else 3161 cur_console->status |= CLKED; 3162 update_leds(cur_console->status); 3163 } 3164 break; 3165 case SLK: 3166 if (!slkcnt) { 3167 slkcnt++; 3168 if (cur_console->status & SLKED) { 3169 cur_console->status &= ~SLKED; 3170 if (cur_console->status & BUFFER_SAVED){ 3171 int i; 3172 u_short *ptr = cur_console->history_save; 3173 3174 for (i=0; i<cur_console->ysize; i++) { 3175 bcopy(ptr, 3176 cur_console->scr_buf + 3177 (cur_console->xsize*i), 3178 cur_console->xsize * sizeof(u_short)); 3179 ptr += cur_console->xsize; 3180 if (ptr + cur_console->xsize > 3181 cur_console->history + 3182 cur_console->history_size) 3183 ptr = cur_console->history; 3184 } 3185 cur_console->status &= ~BUFFER_SAVED; 3186 cur_console->history_head=cur_console->history_save; 3187 cur_console->status |= CURSOR_ENABLED; 3188 mark_all(cur_console); 3189 } 3190 scstart(VIRTUAL_TTY(get_scr_num())); 3191 } 3192 else 3193 cur_console->status |= SLKED; 3194 update_leds(cur_console->status); 3195 } 3196 break; 3197 case ALK: 3198 if (!alkcnt) { 3199 alkcnt++; 3200 if (cur_console->status & ALKED) 3201 cur_console->status &= ~ALKED; 3202 else 3203 cur_console->status |= ALKED; 3204 update_leds(cur_console->status); 3205 } 3206 break; 3207 3208 /* NON-LOCKING KEYS */ 3209 case NOP: 3210 break; 3211 case SPSC: 3212#ifdef SC_SPLASH_SCREEN 3213 toggle_splash_screen(cur_console); 3214#endif 3215 break; 3216 case RBT: 3217 shutdown_nice(); 3218 break; 3219 case SUSP: 3220#if NAPM > 0 3221 apm_suspend(); 3222#endif 3223 break; 3224 3225 case DBG: 3226#ifdef DDB /* try to switch to console 0 */ 3227 if (cur_console->smode.mode == VT_AUTO && 3228 console[0]->smode.mode == VT_AUTO) 3229 switch_scr(cur_console, 0); 3230 Debugger("manual escape to debugger"); 3231#else 3232 printf("No debugger in kernel\n"); 3233#endif 3234 break; 3235 case LSH: 3236 shfts |= 1; 3237 break; 3238 case RSH: 3239 shfts |= 2; 3240 break; 3241 case LCTR: 3242 ctls |= 1; 3243 break; 3244 case RCTR: 3245 ctls |= 2; 3246 break; 3247 case LALT: 3248 alts |= 1; 3249 break; 3250 case RALT: 3251 alts |= 2; 3252 break; 3253 case ASH: 3254 agrs = 1; 3255 break; 3256 case META: 3257 metas = 1; 3258 break; 3259 case NEXT: 3260 { 3261 int next, this = get_scr_num(); 3262 for (next = this+1; next != this; next = (next+1)%MAXCONS) { 3263 struct tty *tp = VIRTUAL_TTY(next); 3264 if (tp->t_state & TS_ISOPEN) { 3265 switch_scr(cur_console, next); 3266 break; 3267 } 3268 } 3269 } 3270 break; 3271 case BTAB: 3272 return(BKEY); 3273 default: 3274 if (action >= F_SCR && action <= L_SCR) { 3275 switch_scr(cur_console, action - F_SCR); 3276 break; 3277 } 3278 if (action >= F_FN && action <= L_FN) 3279 action |= FKEY; 3280 return(action); 3281 } 3282 } 3283 else { 3284 if (metas) 3285 action |= MKEY; 3286 return(action); 3287 } 3288 } 3289 goto next_code; 3290} 3291 3292int 3293scmmap(dev_t dev, int offset, int nprot) 3294{ 3295 if (offset > 0x20000 - PAGE_SIZE) 3296 return -1; 3297 return i386_btop((VIDEOMEM + offset)); 3298} 3299 3300/* 3301 * Calculate hardware attributes word using logical attributes mask and 3302 * hardware colors 3303 */ 3304 3305static int 3306mask2attr(struct term_stat *term) 3307{ 3308 int attr, mask = term->attr_mask; 3309 3310 if (mask & REVERSE_ATTR) { 3311 attr = ((mask & FOREGROUND_CHANGED) ? 3312 ((term->cur_color & 0xF000) >> 4) : 3313 (term->rev_color & 0x0F00)) | 3314 ((mask & BACKGROUND_CHANGED) ? 3315 ((term->cur_color & 0x0F00) << 4) : 3316 (term->rev_color & 0xF000)); 3317 } else 3318 attr = term->cur_color; 3319 3320 /* XXX: underline mapping for Hercules adapter can be better */ 3321 if (mask & (BOLD_ATTR | UNDERLINE_ATTR)) 3322 attr ^= 0x0800; 3323 if (mask & BLINK_ATTR) 3324 attr ^= 0x8000; 3325 3326 return attr; 3327} 3328 3329static void 3330set_keyboard(int command, int data) 3331{ 3332 int s; 3333 int c; 3334 3335 if (sc_kbdc == NULL) 3336 return; 3337 3338 /* prevent the timeout routine from polling the keyboard */ 3339 if (!kbdc_lock(sc_kbdc, TRUE)) 3340 return; 3341 3342 /* disable the keyboard and mouse interrupt */ 3343 s = spltty(); 3344#if 0 3345 c = get_controller_command_byte(sc_kbdc); 3346 if ((c == -1) 3347 || !set_controller_command_byte(sc_kbdc, 3348 kbdc_get_device_mask(sc_kbdc), 3349 KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT 3350 | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { 3351 /* CONTROLLER ERROR */ 3352 kbdc_lock(sc_kbdc, FALSE); 3353 splx(s); 3354 return; 3355 } 3356 /* 3357 * Now that the keyboard controller is told not to generate 3358 * the keyboard and mouse interrupts, call `splx()' to allow 3359 * the other tty interrupts. The clock interrupt may also occur, 3360 * but the timeout routine (`scrn_timer()') will be blocked 3361 * by the lock flag set via `kbdc_lock()' 3362 */ 3363 splx(s); 3364#endif 3365 3366 if (send_kbd_command_and_data(sc_kbdc, command, data) != KBD_ACK) 3367 send_kbd_command(sc_kbdc, KBDC_ENABLE_KBD); 3368 3369#if 0 3370 /* restore the interrupts */ 3371 if (!set_controller_command_byte(sc_kbdc, 3372 kbdc_get_device_mask(sc_kbdc), 3373 c & (KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS))) { 3374 /* CONTROLLER ERROR */ 3375 } 3376#else 3377 splx(s); 3378#endif 3379 kbdc_lock(sc_kbdc, FALSE); 3380} 3381 3382static void 3383update_leds(int which) 3384{ 3385 static u_char xlate_leds[8] = { 0, 4, 2, 6, 1, 5, 3, 7 }; 3386 3387 /* replace CAPS led with ALTGR led for ALTGR keyboards */ 3388 if (key_map.n_keys > ALTGR_OFFSET) { 3389 if (which & ALKED) 3390 which |= CLKED; 3391 else 3392 which &= ~CLKED; 3393 } 3394 3395 set_keyboard(KBDC_SET_LEDS, xlate_leds[which & LED_MASK]); 3396} 3397 3398void 3399set_mode(scr_stat *scp) 3400{ 3401 char *modetable; 3402 char special_modetable[64]; 3403 3404 if (scp != cur_console) 3405 return; 3406 3407 /* setup video hardware for the given mode */ 3408 switch (scp->mode) { 3409 case M_VGA_M80x60: 3410 bcopy(video_mode_ptr+(64*M_VGA_M80x25), &special_modetable, 64); 3411 goto special_80x60; 3412 3413 case M_VGA_C80x60: 3414 bcopy(video_mode_ptr+(64*M_VGA_C80x25), &special_modetable, 64); 3415special_80x60: 3416 special_modetable[2] = 0x08; 3417 special_modetable[19] = 0x47; 3418 goto special_480l; 3419 3420 case M_VGA_M80x30: 3421 bcopy(video_mode_ptr+(64*M_VGA_M80x25), &special_modetable, 64); 3422 goto special_80x30; 3423 3424 case M_VGA_C80x30: 3425 bcopy(video_mode_ptr+(64*M_VGA_C80x25), &special_modetable, 64); 3426special_80x30: 3427 special_modetable[19] = 0x4f; 3428special_480l: 3429 special_modetable[9] |= 0xc0; 3430 special_modetable[16] = 0x08; 3431 special_modetable[17] = 0x3e; 3432 special_modetable[26] = 0xea; 3433 special_modetable[28] = 0xdf; 3434 special_modetable[31] = 0xe7; 3435 special_modetable[32] = 0x04; 3436 modetable = special_modetable; 3437 goto setup_mode; 3438 3439 case M_ENH_B80x43: 3440 bcopy(video_mode_ptr+(64*M_ENH_B80x25), &special_modetable, 64); 3441 goto special_80x43; 3442 3443 case M_ENH_C80x43: 3444 bcopy(video_mode_ptr+(64*M_ENH_C80x25), &special_modetable, 64); 3445special_80x43: 3446 special_modetable[28] = 87; 3447 goto special_80x50; 3448 3449 case M_VGA_M80x50: 3450 bcopy(video_mode_ptr+(64*M_VGA_M80x25), &special_modetable, 64); 3451 goto special_80x50; 3452 3453 case M_VGA_C80x50: 3454 bcopy(video_mode_ptr+(64*M_VGA_C80x25), &special_modetable, 64); 3455special_80x50: 3456 special_modetable[2] = 8; 3457 special_modetable[19] = 7; 3458 modetable = special_modetable; 3459 goto setup_mode; 3460 3461 case M_VGA_C40x25: case M_VGA_C80x25: 3462 case M_VGA_M80x25: 3463 case M_B40x25: case M_C40x25: 3464 case M_B80x25: case M_C80x25: 3465 case M_ENH_B40x25: case M_ENH_C40x25: 3466 case M_ENH_B80x25: case M_ENH_C80x25: 3467 case M_EGAMONO80x25: 3468 3469 modetable = video_mode_ptr + (scp->mode * 64); 3470setup_mode: 3471 set_vgaregs(modetable); 3472 scp->font_size = *(modetable + 2); 3473 3474 /* set font type (size) */ 3475 if (scp->font_size < 14) { 3476 if (fonts_loaded & FONT_8) 3477 copy_font(LOAD, FONT_8, font_8); 3478 outb(TSIDX, 0x03); outb(TSREG, 0x0A); /* font 2 */ 3479 } else if (scp->font_size >= 16) { 3480 if (fonts_loaded & FONT_16) 3481 copy_font(LOAD, FONT_16, font_16); 3482 outb(TSIDX, 0x03); outb(TSREG, 0x00); /* font 0 */ 3483 } else { 3484 if (fonts_loaded & FONT_14) 3485 copy_font(LOAD, FONT_14, font_14); 3486 outb(TSIDX, 0x03); outb(TSREG, 0x05); /* font 1 */ 3487 } 3488 if (flags & CHAR_CURSOR) 3489 set_destructive_cursor(scp); 3490 mark_all(scp); 3491 break; 3492 3493 case M_BG320: case M_CG320: case M_BG640: 3494 case M_CG320_D: case M_CG640_E: 3495 case M_CG640x350: case M_ENH_CG640: 3496 case M_BG640x480: case M_CG640x480: case M_VGA_CG320: 3497 3498 set_vgaregs(video_mode_ptr + (scp->mode * 64)); 3499 scp->font_size = FONT_NONE; 3500 break; 3501 3502 default: 3503 /* call user defined function XXX */ 3504 break; 3505 } 3506 3507 /* set border color for this (virtual) console */ 3508 set_border(scp->border); 3509 return; 3510} 3511 3512void 3513set_border(u_char color) 3514{ 3515 switch (crtc_type) { 3516 case KD_EGA: 3517 case KD_VGA: 3518 inb(crtc_addr + 6); /* reset flip-flop */ 3519 outb(ATC, 0x11); outb(ATC, color); 3520 inb(crtc_addr + 6); /* reset flip-flop */ 3521 outb(ATC, 0x20); /* enable Palette */ 3522 break; 3523 case KD_CGA: 3524 outb(crtc_addr + 5, color & 0x0f); /* color select register */ 3525 break; 3526 case KD_MONO: 3527 case KD_HERCULES: 3528 default: 3529 break; 3530 } 3531} 3532 3533static void 3534set_vgaregs(char *modetable) 3535{ 3536 int i, s = splhigh(); 3537 3538 outb(TSIDX, 0x00); outb(TSREG, 0x01); /* stop sequencer */ 3539 outb(TSIDX, 0x07); outb(TSREG, 0x00); /* unlock registers */ 3540 for (i=0; i<4; i++) { /* program sequencer */ 3541 outb(TSIDX, i+1); 3542 outb(TSREG, modetable[i+5]); 3543 } 3544 outb(MISC, modetable[9]); /* set dot-clock */ 3545 outb(TSIDX, 0x00); outb(TSREG, 0x03); /* start sequencer */ 3546 outb(crtc_addr, 0x11); 3547 outb(crtc_addr+1, inb(crtc_addr+1) & 0x7F); 3548 for (i=0; i<25; i++) { /* program crtc */ 3549 outb(crtc_addr, i); 3550 if (i == 14 || i == 15) /* no hardware cursor */ 3551 outb(crtc_addr+1, 0xff); 3552 else 3553 outb(crtc_addr+1, modetable[i+10]); 3554 } 3555 inb(crtc_addr+6); /* reset flip-flop */ 3556 for (i=0; i<20; i++) { /* program attribute ctrl */ 3557 outb(ATC, i); 3558 outb(ATC, modetable[i+35]); 3559 } 3560 for (i=0; i<9; i++) { /* program graph data ctrl */ 3561 outb(GDCIDX, i); 3562 outb(GDCREG, modetable[i+55]); 3563 } 3564 inb(crtc_addr+6); /* reset flip-flop */ 3565 outb(ATC, 0x20); /* enable palette */ 3566 splx(s); 3567} 3568 3569static void 3570read_vgaregs(char *buf) 3571{ 3572 int i, j; 3573 int s; 3574 3575 bzero(buf, 64); 3576 3577 s = splhigh(); 3578 3579 outb(TSIDX, 0x00); outb(TSREG, 0x01); /* stop sequencer */ 3580 outb(TSIDX, 0x07); outb(TSREG, 0x00); /* unlock registers */ 3581 for (i=0, j=5; i<4; i++) { 3582 outb(TSIDX, i+1); 3583 buf[j++] = inb(TSREG); 3584 } 3585 buf[9] = inb(MISC + 10); /* dot-clock */ 3586 outb(TSIDX, 0x00); outb(TSREG, 0x03); /* start sequencer */ 3587 3588 for (i=0, j=10; i<25; i++) { /* crtc */ 3589 outb(crtc_addr, i); 3590 buf[j++] = inb(crtc_addr+1); 3591 } 3592 for (i=0, j=35; i<20; i++) { /* attribute ctrl */ 3593 inb(crtc_addr+6); /* reset flip-flop */ 3594 outb(ATC, i); 3595 buf[j++] = inb(ATC + 1); 3596 } 3597 for (i=0, j=55; i<9; i++) { /* graph data ctrl */ 3598 outb(GDCIDX, i); 3599 buf[j++] = inb(GDCREG); 3600 } 3601 inb(crtc_addr+6); /* reset flip-flop */ 3602 outb(ATC, 0x20); /* enable palette */ 3603 3604 buf[0] = *(char *)pa_to_va(0x44a); /* COLS */ 3605 buf[1] = *(char *)pa_to_va(0x484); /* ROWS */ 3606 buf[2] = *(char *)pa_to_va(0x485); /* POINTS */ 3607 buf[3] = *(char *)pa_to_va(0x44c); 3608 buf[4] = *(char *)pa_to_va(0x44d); 3609 3610 splx(s); 3611} 3612 3613static int 3614comp_vgaregs(u_char *buf1, u_char *buf2) 3615{ 3616 int i; 3617 3618 for(i = 0; i < 20; ++i) { 3619 if (*buf1++ != *buf2++) 3620 return 1; 3621 } 3622 buf1 += 2; /* skip the cursor shape */ 3623 buf2 += 2; 3624 for(i = 22; i < 24; ++i) { 3625 if (*buf1++ != *buf2++) 3626 return 1; 3627 } 3628 buf1 += 2; /* skip the cursor position */ 3629 buf2 += 2; 3630 for(i = 26; i < 64; ++i) { 3631 if (*buf1++ != *buf2++) 3632 return 1; 3633 } 3634 return 0; 3635} 3636 3637static void 3638dump_vgaregs(u_char *buf) 3639{ 3640 int i; 3641 3642 for(i = 0; i < 64;) { 3643 printf("%02x ", buf[i]); 3644 if ((++i % 16) == 0) 3645 printf("\n"); 3646 } 3647} 3648 3649static void 3650set_font_mode() 3651{ 3652 int s = splhigh(); 3653 3654 /* setup vga for loading fonts (graphics plane mode) */ 3655 inb(crtc_addr+6); /* reset flip-flop */ 3656 outb(ATC, 0x10); outb(ATC, 0x01); 3657 inb(crtc_addr+6); /* reset flip-flop */ 3658 outb(ATC, 0x20); /* enable palette */ 3659 3660#if SLOW_VGA 3661 outb(TSIDX, 0x02); outb(TSREG, 0x04); 3662 outb(TSIDX, 0x04); outb(TSREG, 0x06); 3663 outb(GDCIDX, 0x04); outb(GDCREG, 0x02); 3664 outb(GDCIDX, 0x05); outb(GDCREG, 0x00); 3665 outb(GDCIDX, 0x06); outb(GDCREG, 0x05); 3666#else 3667 outw(TSIDX, 0x0402); 3668 outw(TSIDX, 0x0604); 3669 outw(GDCIDX, 0x0204); 3670 outw(GDCIDX, 0x0005); 3671 outw(GDCIDX, 0x0506); /* addr = a0000, 64kb */ 3672#endif 3673 splx(s); 3674} 3675 3676static void 3677set_normal_mode() 3678{ 3679 char *modetable; 3680 int s = splhigh(); 3681 3682 switch (cur_console->mode) { 3683 case M_VGA_M80x60: 3684 case M_VGA_M80x50: 3685 case M_VGA_M80x30: 3686 modetable = video_mode_ptr + (64*M_VGA_M80x25); 3687 break; 3688 3689 case M_VGA_C80x60: 3690 case M_VGA_C80x50: 3691 case M_VGA_C80x30: 3692 modetable = video_mode_ptr + (64*M_VGA_C80x25); 3693 break; 3694 3695 case M_ENH_B80x43: 3696 modetable = video_mode_ptr + (64*M_ENH_B80x25); 3697 break; 3698 3699 case M_ENH_C80x43: 3700 modetable = video_mode_ptr + (64*M_ENH_C80x25); 3701 break; 3702 3703 case M_VGA_C40x25: case M_VGA_C80x25: 3704 case M_VGA_M80x25: 3705 case M_B40x25: case M_C40x25: 3706 case M_B80x25: case M_C80x25: 3707 case M_ENH_B40x25: case M_ENH_C40x25: 3708 case M_ENH_B80x25: case M_ENH_C80x25: 3709 case M_EGAMONO80x25: 3710 3711 case M_BG320: case M_CG320: case M_BG640: 3712 case M_CG320_D: case M_CG640_E: 3713 case M_CG640x350: case M_ENH_CG640: 3714 case M_BG640x480: case M_CG640x480: case M_VGA_CG320: 3715 modetable = video_mode_ptr + (cur_console->mode * 64); 3716 break; 3717 3718 default: 3719 modetable = video_mode_ptr + (64*M_VGA_C80x25); 3720 } 3721 3722 if (video_mode_ptr == NULL) 3723 modetable = vgaregs; 3724 3725 /* setup vga for normal operation mode again */ 3726 inb(crtc_addr+6); /* reset flip-flop */ 3727 outb(ATC, 0x10); outb(ATC, modetable[0x10+35]); 3728 inb(crtc_addr+6); /* reset flip-flop */ 3729 outb(ATC, 0x20); /* enable palette */ 3730#if SLOW_VGA 3731 outb(TSIDX, 0x02); outb(TSREG, modetable[0x02+4]); 3732 outb(TSIDX, 0x04); outb(TSREG, modetable[0x04+4]); 3733 outb(GDCIDX, 0x04); outb(GDCREG, modetable[0x04+55]); 3734 outb(GDCIDX, 0x05); outb(GDCREG, modetable[0x05+55]); 3735 outb(GDCIDX, 0x06); outb(GDCREG, modetable[0x06+55]); 3736 if (crtc_addr == MONO_BASE) { 3737 outb(GDCIDX, 0x06); outb(GDCREG,(modetable[0x06+55] & 0x03) | 0x08); 3738 } 3739 else { 3740 outb(GDCIDX, 0x06); outb(GDCREG,(modetable[0x06+55] & 0x03) | 0x0c); 3741 } 3742#else 3743 outw(TSIDX, 0x0002 | (modetable[0x02+4]<<8)); 3744 outw(TSIDX, 0x0004 | (modetable[0x04+4]<<8)); 3745 outw(GDCIDX, 0x0004 | (modetable[0x04+55]<<8)); 3746 outw(GDCIDX, 0x0005 | (modetable[0x05+55]<<8)); 3747 if (crtc_addr == MONO_BASE) 3748 outw(GDCIDX, 0x0006 | (((modetable[0x06+55] & 0x03) | 0x08)<<8)); 3749 else 3750 outw(GDCIDX, 0x0006 | (((modetable[0x06+55] & 0x03) | 0x0c)<<8)); 3751#endif 3752 splx(s); 3753} 3754 3755void 3756copy_font(int operation, int font_type, char* font_image) 3757{ 3758 int ch, line, segment, fontsize; 3759 u_char val; 3760 3761 /* dont mess with console we dont know video mode on */ 3762 if (cur_console->status & UNKNOWN_MODE) 3763 return; 3764 3765 switch (font_type) { 3766 default: 3767 case FONT_8: 3768 segment = 0x8000; 3769 fontsize = 8; 3770 break; 3771 case FONT_14: 3772 segment = 0x4000; 3773 fontsize = 14; 3774 break; 3775 case FONT_16: 3776 segment = 0x0000; 3777 fontsize = 16; 3778 break; 3779 } 3780 outb(TSIDX, 0x01); val = inb(TSREG); /* disable screen */ 3781 outb(TSIDX, 0x01); outb(TSREG, val | 0x20); 3782 set_font_mode(); 3783 for (ch=0; ch < 256; ch++) 3784 for (line=0; line < fontsize; line++) 3785 if (operation) 3786 *(char *)pa_to_va(VIDEOMEM+(segment)+(ch*32)+line) = 3787 font_image[(ch*fontsize)+line]; 3788 else 3789 font_image[(ch*fontsize)+line] = 3790 *(char *)pa_to_va(VIDEOMEM+(segment)+(ch*32)+line); 3791 set_normal_mode(); 3792 outb(TSIDX, 0x01); outb(TSREG, val & 0xDF); /* enable screen */ 3793} 3794 3795static void 3796set_destructive_cursor(scr_stat *scp) 3797{ 3798 u_char cursor[32]; 3799 caddr_t address; 3800 int i; 3801 char *font_buffer; 3802 3803 3804 if (scp->font_size < 14) { 3805 font_buffer = font_8; 3806 address = (caddr_t)VIDEOMEM + 0x8000; 3807 } 3808 else if (scp->font_size >= 16) { 3809 font_buffer = font_16; 3810 address = (caddr_t)VIDEOMEM; 3811 } 3812 else { 3813 font_buffer = font_14; 3814 address = (caddr_t)VIDEOMEM + 0x4000; 3815 } 3816 3817 if (scp->status & MOUSE_VISIBLE) { 3818 if ((scp->cursor_saveunder & 0xff) == 0xd0) 3819 bcopy(&scp->mouse_cursor[0], cursor, scp->font_size); 3820 else if ((scp->cursor_saveunder & 0xff) == 0xd1) 3821 bcopy(&scp->mouse_cursor[32], cursor, scp->font_size); 3822 else if ((scp->cursor_saveunder & 0xff) == 0xd2) 3823 bcopy(&scp->mouse_cursor[64], cursor, scp->font_size); 3824 else if ((scp->cursor_saveunder & 0xff) == 0xd3) 3825 bcopy(&scp->mouse_cursor[96], cursor, scp->font_size); 3826 else 3827 bcopy(font_buffer+((scp->cursor_saveunder & 0xff)*scp->font_size), 3828 cursor, scp->font_size); 3829 } 3830 else 3831 bcopy(font_buffer + ((scp->cursor_saveunder & 0xff) * scp->font_size), 3832 cursor, scp->font_size); 3833 for (i=0; i<32; i++) 3834 if ((i >= scp->cursor_start && i <= scp->cursor_end) || 3835 (scp->cursor_start >= scp->font_size && i == scp->font_size - 1)) 3836 cursor[i] |= 0xff; 3837#if 1 3838 while (!(inb(crtc_addr+6) & 0x08)) /* wait for vertical retrace */ ; 3839#endif 3840 set_font_mode(); 3841 sc_bcopy(cursor, (char *)pa_to_va(address) + DEAD_CHAR * 32, 32); 3842 set_normal_mode(); 3843} 3844 3845static void 3846set_mouse_pos(scr_stat *scp) 3847{ 3848 static int last_xpos = -1, last_ypos = -1; 3849 /* 3850 * the margins imposed here are not ideal, we loose 3851 * a couble of pixels on the borders.. 3852 */ 3853 if (scp->mouse_xpos < 0) 3854 scp->mouse_xpos = 0; 3855 if (scp->mouse_ypos < 0) 3856 scp->mouse_ypos = 0; 3857 if (scp->mouse_xpos > (scp->xsize*8)-2) 3858 scp->mouse_xpos = (scp->xsize*8)-2; 3859 if (scp->mouse_ypos > (scp->ysize*scp->font_size)-2) 3860 scp->mouse_ypos = (scp->ysize*scp->font_size)-2; 3861 3862 if (scp->status & UNKNOWN_MODE) 3863 return; 3864 3865 if (scp->mouse_xpos != last_xpos || scp->mouse_ypos != last_ypos) { 3866 scp->status |= MOUSE_MOVED; 3867 3868 scp->mouse_pos = scp->scr_buf + 3869 ((scp->mouse_ypos/scp->font_size)*scp->xsize + scp->mouse_xpos/8); 3870 3871 if ((scp->status & MOUSE_VISIBLE) && (scp->status & MOUSE_CUTTING)) { 3872 u_short *ptr; 3873 int i = 0; 3874 3875 mark_for_update(scp, scp->mouse_cut_start - scp->scr_buf); 3876 mark_for_update(scp, scp->mouse_cut_end - scp->scr_buf); 3877 scp->mouse_cut_end = scp->mouse_pos; 3878 for (ptr = (scp->mouse_cut_start > scp->mouse_cut_end 3879 ? scp->mouse_cut_end : scp->mouse_cut_start); 3880 ptr <= (scp->mouse_cut_start > scp->mouse_cut_end 3881 ? scp->mouse_cut_start : scp->mouse_cut_end); 3882 ptr++) { 3883 cut_buffer[i++] = *ptr & 0xff; 3884 if (((ptr - scp->scr_buf) % scp->xsize) == (scp->xsize - 1)) { 3885 cut_buffer[i++] = '\n'; 3886 } 3887 } 3888 cut_buffer[i] = 0x00; 3889 } 3890 } 3891} 3892 3893static void 3894mouse_cut_start(scr_stat *scp) 3895{ 3896 int i; 3897 3898 if (scp->status & MOUSE_VISIBLE) { 3899 if (scp->mouse_pos == scp->mouse_cut_start && 3900 scp->mouse_cut_start == scp->mouse_cut_end) { 3901 cut_buffer[0] = 0x00; 3902 remove_cutmarking(scp); 3903 } 3904 else { 3905 scp->mouse_cut_start = scp->mouse_cut_end = scp->mouse_pos; 3906 cut_buffer[0] = *scp->mouse_cut_start & 0xff; 3907 cut_buffer[1] = 0x00; 3908 scp->status |= MOUSE_CUTTING; 3909 } 3910 mark_all(scp); 3911 /* delete all other screens cut markings */ 3912 for (i=0; i<MAXCONS; i++) { 3913 if (console[i] == NULL || console[i] == scp) 3914 continue; 3915 remove_cutmarking(console[i]); 3916 } 3917 } 3918} 3919 3920static void 3921mouse_cut_end(scr_stat *scp) 3922{ 3923 if (scp->status & MOUSE_VISIBLE) { 3924 scp->status &= ~MOUSE_CUTTING; 3925 } 3926} 3927 3928static void 3929mouse_paste(scr_stat *scp) 3930{ 3931 if (scp->status & MOUSE_VISIBLE) { 3932 struct tty *tp; 3933 u_char *ptr = cut_buffer; 3934 3935 tp = VIRTUAL_TTY(get_scr_num()); 3936 while (*ptr) 3937 (*linesw[tp->t_line].l_rint)(scr_rmap[*ptr++], tp); 3938 } 3939} 3940 3941static void 3942draw_mouse_image(scr_stat *scp) 3943{ 3944 caddr_t address; 3945 int i; 3946 char *font_buffer; 3947 u_short buffer[32]; 3948 u_short xoffset, yoffset; 3949 u_short *crt_pos = Crtat + (scp->mouse_pos - scp->scr_buf); 3950 int font_size = scp->font_size; 3951 3952 if (font_size < 14) { 3953 font_buffer = font_8; 3954 address = (caddr_t)VIDEOMEM + 0x8000; 3955 } 3956 else if (font_size >= 16) { 3957 font_buffer = font_16; 3958 address = (caddr_t)VIDEOMEM; 3959 } 3960 else { 3961 font_buffer = font_14; 3962 address = (caddr_t)VIDEOMEM + 0x4000; 3963 } 3964 xoffset = scp->mouse_xpos % 8; 3965 yoffset = scp->mouse_ypos % font_size; 3966 3967 /* prepare mousepointer char's bitmaps */ 3968 bcopy(font_buffer + ((*(scp->mouse_pos) & 0xff) * font_size), 3969 &scp->mouse_cursor[0], font_size); 3970 bcopy(font_buffer + ((*(scp->mouse_pos+1) & 0xff) * font_size), 3971 &scp->mouse_cursor[32], font_size); 3972 bcopy(font_buffer + ((*(scp->mouse_pos+scp->xsize) & 0xff) * font_size), 3973 &scp->mouse_cursor[64], font_size); 3974 bcopy(font_buffer + ((*(scp->mouse_pos+scp->xsize+1) & 0xff) * font_size), 3975 &scp->mouse_cursor[96], font_size); 3976 for (i=0; i<font_size; i++) { 3977 buffer[i] = scp->mouse_cursor[i]<<8 | scp->mouse_cursor[i+32]; 3978 buffer[i+font_size]=scp->mouse_cursor[i+64]<<8|scp->mouse_cursor[i+96]; 3979 } 3980 3981 /* now and-or in the mousepointer image */ 3982 for (i=0; i<16; i++) { 3983 buffer[i+yoffset] = 3984 ( buffer[i+yoffset] & ~(mouse_and_mask[i] >> xoffset)) 3985 | (mouse_or_mask[i] >> xoffset); 3986 } 3987 for (i=0; i<font_size; i++) { 3988 scp->mouse_cursor[i] = (buffer[i] & 0xff00) >> 8; 3989 scp->mouse_cursor[i+32] = buffer[i] & 0xff; 3990 scp->mouse_cursor[i+64] = (buffer[i+font_size] & 0xff00) >> 8; 3991 scp->mouse_cursor[i+96] = buffer[i+font_size] & 0xff; 3992 } 3993 3994 scp->mouse_oldpos = scp->mouse_pos; 3995 3996 /* wait for vertical retrace to avoid jitter on some videocards */ 3997#if 1 3998 while (!(inb(crtc_addr+6) & 0x08)) /* idle */ ; 3999#endif 4000 set_font_mode(); 4001 sc_bcopy(scp->mouse_cursor, (char *)pa_to_va(address) + 0xd0 * 32, 128); 4002 set_normal_mode(); 4003 *(crt_pos) = (*(scp->mouse_pos)&0xff00)|0xd0; 4004 *(crt_pos+scp->xsize) = (*(scp->mouse_pos+scp->xsize)&0xff00)|0xd2; 4005 if (scp->mouse_xpos < (scp->xsize-1)*8) { 4006 *(crt_pos+1) = (*(scp->mouse_pos+1)&0xff00)|0xd1; 4007 *(crt_pos+scp->xsize+1) = (*(scp->mouse_pos+scp->xsize+1)&0xff00)|0xd3; 4008 } 4009 mark_for_update(scp, scp->mouse_pos - scp->scr_buf); 4010 mark_for_update(scp, scp->mouse_pos + scp->xsize + 1 - scp->scr_buf); 4011} 4012 4013static void 4014remove_mouse_image(scr_stat *scp) 4015{ 4016 u_short *crt_pos = Crtat + (scp->mouse_oldpos - scp->scr_buf); 4017 4018 *(crt_pos) = *(scp->mouse_oldpos); 4019 *(crt_pos+1) = *(scp->mouse_oldpos+1); 4020 *(crt_pos+scp->xsize) = *(scp->mouse_oldpos+scp->xsize); 4021 *(crt_pos+scp->xsize+1) = *(scp->mouse_oldpos+scp->xsize+1); 4022 mark_for_update(scp, scp->mouse_oldpos - scp->scr_buf); 4023 mark_for_update(scp, scp->mouse_oldpos + scp->xsize + 1 - scp->scr_buf); 4024} 4025 4026static void 4027draw_cutmarking(scr_stat *scp) 4028{ 4029 u_short *ptr; 4030 u_short och, nch; 4031 4032 for (ptr=scp->scr_buf; ptr<=(scp->scr_buf+(scp->xsize*scp->ysize)); ptr++) { 4033 nch = och = *(Crtat + (ptr - scp->scr_buf)); 4034 /* are we outside the selected area ? */ 4035 if ( ptr < (scp->mouse_cut_start > scp->mouse_cut_end ? 4036 scp->mouse_cut_end : scp->mouse_cut_start) || 4037 ptr > (scp->mouse_cut_start > scp->mouse_cut_end ? 4038 scp->mouse_cut_start : scp->mouse_cut_end)) { 4039 if (ptr != scp->cursor_pos) 4040 nch = (och & 0xff) | (*ptr & 0xff00); 4041 } 4042 else { 4043 /* are we clear of the cursor image ? */ 4044 if (ptr != scp->cursor_pos) 4045 nch = (och & 0x88ff) | (*ptr & 0x7000)>>4 | (*ptr & 0x0700)<<4; 4046 else { 4047 if (flags & CHAR_CURSOR) 4048 nch = (och & 0x88ff)|(*ptr & 0x7000)>>4|(*ptr & 0x0700)<<4; 4049 else 4050 if (!(flags & BLINK_CURSOR)) 4051 nch = (och & 0xff) | (*ptr & 0xff00); 4052 } 4053 } 4054 if (nch != och) 4055 *(Crtat + (ptr - scp->scr_buf)) = nch; 4056 } 4057} 4058 4059static void 4060remove_cutmarking(scr_stat *scp) 4061{ 4062 scp->mouse_cut_start = scp->mouse_cut_end = NULL; 4063 scp->status &= ~MOUSE_CUTTING; 4064 mark_all(scp); 4065} 4066 4067static void 4068save_palette(void) 4069{ 4070 int i; 4071 4072 outb(PALRADR, 0x00); 4073 for (i=0x00; i<0x300; i++) 4074 palette[i] = inb(PALDATA); 4075 inb(crtc_addr+6); /* reset flip/flop */ 4076} 4077 4078void 4079load_palette(char *palette) 4080{ 4081 int i; 4082 4083 outb(PIXMASK, 0xFF); /* no pixelmask */ 4084 outb(PALWADR, 0x00); 4085 for (i=0x00; i<0x300; i++) 4086 outb(PALDATA, palette[i]); 4087 inb(crtc_addr+6); /* reset flip/flop */ 4088 outb(ATC, 0x20); /* enable palette */ 4089} 4090 4091static void 4092do_bell(scr_stat *scp, int pitch, int duration) 4093{ 4094 if (flags & VISUAL_BELL) { 4095 if (blink_in_progress) 4096 return; 4097 blink_in_progress = 4; 4098 if (scp != cur_console) 4099 blink_in_progress += 2; 4100 blink_screen(cur_console); 4101 } else { 4102 if (scp != cur_console) 4103 pitch *= 2; 4104 sysbeep(pitch, duration); 4105 } 4106} 4107 4108static void 4109blink_screen(void *arg) 4110{ 4111 scr_stat *scp = arg; 4112 4113 if ((scp->status & UNKNOWN_MODE) || (blink_in_progress <= 1)) { 4114 blink_in_progress = FALSE; 4115 mark_all(scp); 4116 if (delayed_next_scr) 4117 switch_scr(scp, delayed_next_scr - 1); 4118 } 4119 else { 4120 if (blink_in_progress & 1) 4121 fillw(kernel_default.std_color | scr_map[0x20], 4122 Crtat, scp->xsize * scp->ysize); 4123 else 4124 fillw(kernel_default.rev_color | scr_map[0x20], 4125 Crtat, scp->xsize * scp->ysize); 4126 blink_in_progress--; 4127 timeout(blink_screen, scp, hz / 10); 4128 } 4129} 4130 4131#ifdef SC_SPLASH_SCREEN 4132static void 4133toggle_splash_screen(scr_stat *scp) 4134{ 4135 static int toggle = 0; 4136 static u_char save_mode; 4137 int s; 4138 4139 if (video_mode_ptr == NULL) 4140 return; 4141 4142 s = splhigh(); 4143 if (toggle) { 4144 scp->mode = save_mode; 4145 scp->status &= ~UNKNOWN_MODE; 4146 set_mode(scp); 4147 load_palette(palette); 4148 toggle = 0; 4149 } 4150 else { 4151 save_mode = scp->mode; 4152 scp->mode = M_VGA_CG320; 4153 scp->status |= UNKNOWN_MODE; 4154 set_mode(scp); 4155 /* load image */ 4156 toggle = 1; 4157 } 4158 splx(s); 4159} 4160#endif 4161#endif /* NSC */ 4162