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