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