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