syscons.c revision 677
1/*- 2 * Copyright (c) 1990 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * William Jolitz and Don Ahn. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 */ 37/* 38 * Heavily modified by S�ren Schmidt (sos@login.dkuug.dk) to provide: 39 * 40 * virtual consoles, SYSV ioctl's, ANSI emulation .... 41 * 42 * @(#)syscons.c 1.1 931021 43 * 44 * Derived from: 45 * @(#)pccons.c 5.11 (Berkeley) 5/21/91 46 */ 47 48#define STAR_SAVER 49#define FAT_CURSOR 50 51#include "param.h" 52#include "conf.h" 53#include "ioctl.h" 54#include "proc.h" 55#include "user.h" 56#include "tty.h" 57#include "uio.h" 58#include "callout.h" 59#include "systm.h" 60#include "kernel.h" 61#include "syslog.h" 62#include "errno.h" 63#include "malloc.h" 64#include "i386/isa/icu.h" 65#include "i386/isa/isa.h" 66#include "i386/isa/isa_device.h" 67#include "i386/isa/timerreg.h" 68#include "i386/i386/cons.h" 69#include "machine/console.h" 70#include "machine/psl.h" 71#include "machine/frame.h" 72#include "machine/pc/display.h" 73#include "sc.h" 74#include "iso8859.font" 75#include "kbdtables.h" 76 77#if !defined(NetBSD) 78#include "ddb.h" 79#if NDDB > 0 80#define DDB 81#endif 82#endif 83 84#if NSC > 0 85 86#ifndef NCONS 87#define NCONS 12 88#endif 89 90/* status flags */ 91#define LOCK_KEY_MASK 0x0000F 92#define LED_MASK 0x00007 93#define UNKNOWN_MODE 0x00010 94#define KBD_RAW_MODE 0x00020 95#define SWITCH_WAIT_REL 0x00040 96#define SWITCH_WAIT_ACQ 0x00080 97 98/* virtual video memory addresses */ 99#if !defined(NetBSD) 100#define MONO_BUF 0xFE0B0000 101#define CGA_BUF 0xFE0B8000 102#define VGA_BUF 0xFE0A0000 103#endif 104#define VIDEOMEM 0x000A0000 105 106/* misc defines */ 107#define MAX_ESC_PAR 3 108#define TEXT80x25 1 109#define TEXT80x50 2 110#define COL 80 111#define ROW 25 112#define BELL_DURATION 10 113#define BELL_PITCH 800 114#define TIMER_FREQ 1193182 /* should be in isa.h */ 115#define PCBURST 128 116 117/* defines related to hardware addresses */ 118#define MONO_BASE 0x3B4 /* crt controller base mono */ 119#define COLOR_BASE 0x3D4 /* crt controller base color */ 120#define ATC IO_VGA+0x00 /* attribute controller */ 121#define TSIDX IO_VGA+0x04 /* timing sequencer idx */ 122#define TSREG IO_VGA+0x05 /* timing sequencer data */ 123#define PIXMASK IO_VGA+0x06 /* pixel write mask */ 124#define PALRADR IO_VGA+0x07 /* palette read address */ 125#define PALWADR IO_VGA+0x08 /* palette write address */ 126#define PALDATA IO_VGA+0x09 /* palette data register */ 127#define GDCIDX IO_VGA+0x0E /* graph data controller idx */ 128#define GDCREG IO_VGA+0x0F /* graph data controller data */ 129 130typedef struct term_stat { 131 int esc; /* processing escape sequence */ 132 int n_par; /* # of parameters to ESC */ 133 int last_par; /* last parameter # */ 134 int par[MAX_ESC_PAR]; /* contains ESC parameters */ 135 int attr; /* current attributes */ 136 int std_attr; /* normal attributes */ 137 int rev_attr; /* reverse attributes */ 138} term_stat; 139 140typedef struct scr_stat { 141 u_short *crt_base; /* address of screen memory */ 142 u_short *scr; /* buffer when off screen */ 143 u_short *crtat; /* cursor address */ 144 int posx; /* current X position */ 145 int posy; /* current Y position */ 146 int max_posx; /* X size */ 147 int max_posy; /* X size */ 148 term_stat term; /* terminal emulation stuff */ 149 char cursor_start; /* cursor start line # */ 150 char cursor_end; /* cursor start end # */ 151 u_char border; /* border color */ 152 u_short bell_duration; 153 u_short bell_pitch; 154 u_short status; /* status (bitfield) */ 155 u_short mode; /* mode */ 156 pid_t pid; /* pid of controlling proc */ 157 struct proc *proc; /* proc* of controlling proc */ 158 struct vt_mode smode; /* switch mode */ 159} scr_stat; 160 161typedef struct default_attr { 162 int std_attr; /* normal attributes */ 163 int rev_attr; /* reverse attributes */ 164} default_attr; 165 166static default_attr user_default = { 167 (FG_LIGHTGREY | BG_BLACK) << 8, 168 (FG_BLACK | BG_LIGHTGREY) << 8 169}; 170 171static default_attr kernel_default = { 172 (FG_WHITE | BG_BLACK) << 8, 173 (FG_BLACK | BG_LIGHTGREY) << 8 174}; 175 176static scr_stat console[NCONS]; 177static scr_stat *cur_console = &console[0]; 178static scr_stat *new_scp, *old_scp; 179static term_stat kernel_console; 180static default_attr *current_default; 181static int switch_in_progress = 0; 182static u_short *crtat = 0; 183static u_int crtc_addr = MONO_BASE; 184static char crtc_vga = 0; 185static u_char shfts = 0, ctls = 0, alts = 0, agrs = 0, metas = 0; 186static u_char nlkcnt = 0, clkcnt = 0, slkcnt = 0, alkcnt = 0; 187static char palette[3*256]; 188static const u_int n_fkey_tab = sizeof(fkey_tab) / sizeof(*fkey_tab); 189static int cur_cursor_pos = -1; 190static char in_putc = 0; 191static char polling = 0; 192static int nx_scr; 193static char saved_console = -1; /* saved console number */ 194static long scrn_blank_time = 0; /* screen saver timout value */ 195static int scrn_blanked = 0; /* screen saver active flag */ 196static long scrn_time_stamp; 197static u_char scr_map[256]; 198static struct tty *cur_tty = NULL; 199 200#if defined(NetBSD) 201extern u_short *Crtat; 202struct tty *pc_tty[NCONS]; 203int ttrstrt(); 204#else 205u_short *Crtat = (u_short *)MONO_BUF; 206struct tty pccons[NCONS]; 207#define timeout_t caddr_t 208#endif 209 210extern int hz; 211extern struct timeval time; 212 213/* special characters */ 214#define cntlc 0x03 215#define cntld 0x04 216#define bs 0x08 217#define lf 0x0a 218#define cr 0x0d 219#define del 0x7f 220 221/* function prototypes */ 222int pcprobe(struct isa_device *dev); 223int pcattach(struct isa_device *dev); 224int pcopen(dev_t dev, int flag, int mode, struct proc *p); 225int pcclose(dev_t dev, int flag, int mode, struct proc *p); 226int pcread(dev_t dev, struct uio *uio, int flag); 227int pcwrite(dev_t dev, struct uio *uio, int flag); 228int pcparam(struct tty *tp, struct termios *t); 229int pcioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p); 230int pcxint(dev_t dev); 231int pcstart(struct tty *tp); 232int pccnprobe(struct consdev *cp); 233int pccninit(struct consdev *cp); 234int pccnputc(dev_t dev, char c); 235int pccngetc(dev_t dev); 236int scintr(dev_t dev, int irq, int cpl); 237int pcmmap(dev_t dev, int offset, int nprot); 238u_int sgetc(int noblock); 239int getchar(void); 240static void reset_cpu(void); 241static void scrn_saver(int test); 242static struct tty *get_tty_ptr(dev_t dev); 243static scr_stat *get_scr_stat(dev_t dev); 244static int get_scr_num(scr_stat *scp); 245static void cursor_shape(int start, int end); 246static void get_cursor_shape(int *start, int *end); 247static void cursor_pos(void); 248static void clear_screen(scr_stat *scp); 249static switch_scr(u_int next_scr); 250static void exchange_scr(void); 251static void move_crsr(scr_stat *scp, int x, int y); 252static void move_up(u_short *s, u_short *d, u_int len); 253static void move_down(u_short *s, u_short *d, u_int len); 254static void scan_esc(scr_stat *scp, u_char c); 255static void ansi_put(scr_stat *scp, u_char c); 256static void scinit(void); 257static void sput(u_char c); 258static u_char *get_fstr(u_int c, u_int *len); 259static update_leds(int which); 260static void kbd_wait(void); 261static void kbd_cmd(u_char command); 262static void set_mode(scr_stat *scp); 263static void set_border(int color); 264static load_font(int segment, int size, char* font); 265static void save_palette(void); 266static void load_palette(void); 267static change_winsize(struct tty *tp, int x, int y); 268 269struct isa_driver scdriver = { 270 pcprobe, pcattach, "sc", 271}; 272 273#if !defined(NetBSD) 274void consinit(void) 275{ 276 scinit(); 277} 278#endif 279 280int pcprobe(struct isa_device *dev) 281{ 282 u_char c; 283 int again = 0; 284 285 /* Enable interrupts and keyboard controller */ 286 kbd_wait(); 287 outb(KB_STAT, KB_WRITE); 288 kbd_cmd(0x4D); 289 290 /* Start keyboard stuff RESET */ 291 kbd_cmd(KB_RESET); 292 while ((c=inb(KB_DATA)) != KB_ACK) { 293 if ((c == 0xFE) || (c == 0xFF)) { 294 if (!again) 295 printf("KEYBOARD disconnected: RECONNECT \n"); 296 kbd_cmd(KB_RESET); 297 again = 1; 298 } 299 } 300 kbd_wait(); 301 return (IO_KBDSIZE); 302} 303 304 305int pcattach(struct isa_device *dev) 306{ 307 scr_stat *scp; 308 int start = -1, end = -1, i; 309 310 printf("sc%d: ", dev->id_unit); 311 if (crtc_vga) 312 if (crtc_addr == MONO_BASE) 313 printf("VGA mono"); 314 else 315 printf("VGA color"); 316 else 317 if (crtc_addr == MONO_BASE) 318 printf("MDA/hercules"); 319 else 320 printf("CGA/EGA"); 321 322 if (NCONS > 1) 323 printf(" <%d virtual consoles>\n", NCONS); 324 else 325 printf("\n"); 326#ifdef FAT_CURSOR 327 start = 0; 328 end = 18; 329 if (crtc_vga) { 330#else 331 if (crtc_vga) { 332 get_cursor_shape(&start, &end); 333#endif 334 save_palette(); 335 load_font(0, 16, font_8x16); 336 load_font(1, 8, font_8x8); 337 load_font(2, 14, font_8x14); 338 } 339 current_default = &user_default; 340 for (i = 0; i < NCONS; i++) { 341 scp = &console[i]; 342 scp->scr = (u_short *)malloc(COL * ROW * 2, M_DEVBUF, M_NOWAIT); 343 scp->mode = TEXT80x25; 344 scp->term.esc = 0; 345 scp->term.std_attr = current_default->std_attr; 346 scp->term.rev_attr = current_default->rev_attr; 347 scp->term.attr = scp->term.std_attr; 348 scp->border = BG_BLACK; 349 scp->cursor_start = start; 350 scp->cursor_end = end; 351 scp->max_posx = COL; 352 scp->max_posy = ROW; 353 scp->bell_pitch = BELL_PITCH; 354 scp->bell_duration = BELL_DURATION; 355 scp->status = 0; 356 scp->pid = 0; 357 scp->proc = NULL; 358 scp->smode.mode = VT_AUTO; 359 if (i > 0) { 360 scp->crt_base = scp->crtat = scp->scr; 361 fillw(scp->term.attr|scr_map[0x20], scp->scr, COL*ROW); 362 } 363 } 364 /* get cursor going */ 365#ifdef FAT_CURSOR 366 cursor_shape(console[0].cursor_start, 367 console[0].cursor_end); 368#endif 369 cursor_pos(); 370} 371 372 373static struct tty *get_tty_ptr(dev_t dev) 374{ 375 int unit = minor(dev); 376 377 if (unit >= NCONS) 378 return(NULL); 379#if defined(NetBSD) 380 if (!pc_tty[unit]) 381 pc_tty[unit] = ttymalloc(); 382 return(pc_tty[unit]); 383#else 384 return(&pccons[unit]); 385#endif 386} 387 388 389static scr_stat *get_scr_stat(dev_t dev) 390{ 391 int unit = minor(dev); 392 393 if (unit >= NCONS) 394 return(NULL); 395 return(&console[unit]); 396} 397 398 399static int get_scr_num(scr_stat *scp) /* allways call with legal scp !! */ 400{ 401 int i = 0; 402 403 while ((i < NCONS) && (cur_console != &console[i])) i++; 404 return i; 405} 406 407pcopen(dev_t dev, int flag, int mode, struct proc *p) 408{ 409 struct tty *tp = get_tty_ptr(dev); 410 411 if (!tp) 412 return(ENXIO); 413 if (!cur_tty) 414 cur_tty = tp; 415 tp->t_oproc = (void*)pcstart; 416 tp->t_param = pcparam; 417 tp->t_dev = dev; 418 if ((tp->t_state & TS_ISOPEN) == 0) { 419 tp->t_state |= TS_WOPEN; 420 ttychars(tp); 421 tp->t_iflag = TTYDEF_IFLAG; 422 tp->t_oflag = TTYDEF_OFLAG; 423 tp->t_cflag = TTYDEF_CFLAG; 424 tp->t_lflag = TTYDEF_LFLAG; 425 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 426 pcparam(tp, &tp->t_termios); 427 ttsetwater(tp); 428 } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0) 429 return(EBUSY); 430 tp->t_state |= TS_CARR_ON; 431 return((*linesw[tp->t_line].l_open)(dev, tp)); 432} 433 434 435pcclose(dev_t dev, int flag, int mode, struct proc *p) 436{ 437 struct tty *tp = get_tty_ptr(dev); 438 struct scr_stat *scp; 439 440 if (!tp) 441 return(ENXIO); 442 scp = get_scr_stat(tp->t_dev); 443 scp->pid = 0; 444 scp->proc = NULL; 445 scp->smode.mode = VT_AUTO; 446 (*linesw[tp->t_line].l_close)(tp, flag); 447 ttyclose(tp); 448 return(0); 449} 450 451 452pcread(dev_t dev, struct uio *uio, int flag) 453{ 454 struct tty *tp = get_tty_ptr(dev); 455 456 if (!tp) 457 return(ENXIO); 458 return((*linesw[tp->t_line].l_read)(tp, uio, flag)); 459} 460 461 462pcwrite(dev_t dev, struct uio *uio, int flag) 463{ 464 struct tty *tp = get_tty_ptr(dev); 465 466 if (!tp) 467 return(ENXIO); 468 return((*linesw[tp->t_line].l_write)(tp, uio, flag)); 469} 470 471 472/* 473 * Got a console interrupt, keyboard action ! 474 * Catch the character, and see who it goes to. 475 */ 476scintr(dev_t dev, int irq, int cpl) 477{ 478 int c, len; 479 u_char *cp; 480 481 /* make screensaver happy */ 482 scrn_time_stamp = time.tv_sec; 483 if (scrn_blanked) 484 scrn_saver(0); 485 486 c = sgetc(1); 487 if (!cur_tty) 488 return; 489 if ((cur_tty->t_state & TS_ISOPEN) == 0 || polling) 490 return; 491 492 switch (c & 0xff00) { 493 case 0x0000: /* normal key */ 494 (*linesw[cur_tty->t_line].l_rint)(c & 0xFF, cur_tty); 495 break; 496 case NOKEY: /* nothing there */ 497 return; 498 case FKEY: /* function key, return string */ 499 if (cp = get_fstr((u_int)c, (u_int *)&len)) { 500 while (len-- > 0) 501 (*linesw[cur_tty->t_line].l_rint) 502 (*cp++ & 0xFF, cur_tty); 503 } 504 break; 505 case MKEY: /* meta is active, prepend ESC */ 506 (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty); 507 (*linesw[cur_tty->t_line].l_rint)(c & 0xFF, cur_tty); 508 break; 509 } 510} 511 512 513/* 514 * Set line parameters 515 */ 516pcparam(struct tty *tp, struct termios *t) 517{ 518 int cflag = t->c_cflag; 519 520 /* and copy to tty */ 521 tp->t_ispeed = t->c_ispeed; 522 tp->t_ospeed = t->c_ospeed; 523 tp->t_cflag = cflag; 524 return(0); 525} 526 527 528#if defined(NetBSD) 529#define frametype struct trapframe 530#define eflags tf_eflags 531#else 532#define frametype struct syscframe 533#define eflags sf_eflags 534#endif 535 536pcioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) 537{ 538 int i, error; 539 struct tty *tp; 540 frametype *fp; 541 scr_stat *scp; 542 543 tp = get_tty_ptr(dev); 544 if (!tp) 545 return ENXIO; 546 scp = get_scr_stat(tp->t_dev); 547 548 switch (cmd) { /* process console hardware related ioctl's */ 549 550 case CONS_BLANKTIME: /* set screen saver timeout (0 = no saver) */ 551 scrn_blank_time = *(int*)data; 552 return 0; 553 554 case CONS_80x25TEXT: /* set 80x25 text mode */ 555 if (!crtc_vga) 556 return ENXIO; 557 scp->mode = TEXT80x25; 558 scp->max_posy = 25; 559 free(scp->scr, M_DEVBUF); 560 scp->scr = (u_short *)malloc(scp->max_posx*scp->max_posy*2, 561 M_DEVBUF, M_NOWAIT); 562 if (scp != cur_console) 563 scp->crt_base = scp->scr; 564 set_mode(scp); 565 clear_screen(scp); 566 change_winsize(tp, scp->max_posx, scp->max_posy); 567 return 0; 568 569 case CONS_80x50TEXT: /* set 80x50 text mode */ 570 if (!crtc_vga) 571 return ENXIO; 572 scp->mode = TEXT80x50; 573 scp->max_posy = 50; 574 free(scp->scr, M_DEVBUF); 575 scp->scr = (u_short *)malloc(scp->max_posx*scp->max_posy*2, 576 M_DEVBUF, M_NOWAIT); 577 if (scp != cur_console) 578 scp->crt_base = scp->scr; 579 set_mode(scp); 580 clear_screen(scp); 581 change_winsize(tp, scp->max_posx, scp->max_posy); 582 return 0; 583 584 case CONS_GETVERS: /* get version number */ 585 *(int*)data = 0x100; /* version 1.0 */ 586 return 0; 587 588 case CONS_GETINFO: /* get current (virtual) console info */ 589 if (*data == sizeof(struct vid_info)) { 590 vid_info_t *ptr = (vid_info_t*)data; 591 ptr->m_num = get_scr_num(scp); 592 ptr->mv_col = scp->posx; 593 ptr->mv_row = scp->posy; 594 ptr->mv_csz = scp->max_posx; 595 ptr->mv_rsz = scp->max_posy; 596 ptr->mv_norm.fore = (scp->term.std_attr & 0x0f00)>>8; 597 ptr->mv_norm.back = (scp->term.std_attr & 0xf000)>>12; 598 ptr->mv_rev.fore = (scp->term.rev_attr & 0x0f00)>>8; 599 ptr->mv_rev.back = (scp->term.rev_attr & 0xf000)>>12; 600 ptr->mv_grfc.fore = 0; /* not supported */ 601 ptr->mv_grfc.back = 0; /* not supported */ 602 ptr->mv_ovscan = scp->border; 603 ptr->mk_keylock = scp->status & LOCK_KEY_MASK; 604 return 0; 605 } 606 return EINVAL; 607 608 case VT_SETMODE: /* set screen switcher mode */ 609 bcopy(data, &scp->smode, sizeof(struct vt_mode)); 610 if (scp->smode.mode == VT_PROCESS) { 611 scp->proc = p; 612 scp->pid = scp->proc->p_pid; 613 } 614 return 0; 615 616 case VT_GETMODE: /* get screen switcher mode */ 617 bcopy(&scp->smode, data, sizeof(struct vt_mode)); 618 return 0; 619 620 case VT_RELDISP: /* screen switcher ioctl */ 621 switch(*data) { 622 case VT_FALSE: /* user refuses to release screen, abort */ 623 if (scp == old_scp && (scp->status & SWITCH_WAIT_REL)) { 624 old_scp->status &= ~SWITCH_WAIT_REL; 625 switch_in_progress = 0; 626 return 0; 627 } 628 return EINVAL; 629 630 case VT_TRUE: /* user has released screen, go on */ 631 if (scp == old_scp && (scp->status & SWITCH_WAIT_REL)) { 632 scp->status &= ~SWITCH_WAIT_REL; 633 exchange_scr(); 634 if (new_scp->smode.mode == VT_PROCESS) { 635 new_scp->status |= SWITCH_WAIT_ACQ; 636 psignal(new_scp->proc, 637 new_scp->smode.acqsig); 638 } 639 else 640 switch_in_progress = 0; 641 return 0; 642 } 643 return EINVAL; 644 645 case VT_ACKACQ: /* acquire acknowledged, switch completed */ 646 if (scp == new_scp && (scp->status & SWITCH_WAIT_ACQ)) { 647 scp->status &= ~SWITCH_WAIT_ACQ; 648 switch_in_progress = 0; 649 return 0; 650 } 651 return EINVAL; 652 653 default: 654 return EINVAL; 655 } 656 /* NOT REACHED */ 657 658 case VT_OPENQRY: /* return free virtual console */ 659 for (i = 0; i < NCONS; i++) 660#if defined(NetBSD) 661 if (!(pc_tty[i]->t_state & TS_ISOPEN)) { 662#else 663 if (!(pccons[i].t_state & TS_ISOPEN)) { 664#endif 665 *data = i + 1; 666 return 0; 667 } 668 return EINVAL; 669 /* NOT REACHED */ 670 671 case VT_ACTIVATE: /* switch to screen *data */ 672 return switch_scr((*data) - 1); 673 674 case VT_WAITACTIVE: /* wait for switch to occur */ 675 if (*data > NCONS) 676 return EINVAL; 677 if (minor(dev) == (*data) - 1) 678 return 0; 679 if (*data == 0) { 680 if (scp == cur_console) 681 return 0; 682 while ((error=tsleep((caddr_t)&scp->smode, 683 PZERO|PCATCH, "waitvt", 0)) == ERESTART) ; 684 } 685 else 686 while ((error=tsleep( 687 (caddr_t)&console[*data].smode, 688 PZERO|PCATCH, "waitvt", 0)) == ERESTART) ; 689 return error; 690 691 case VT_GETACTIVE: 692 *data = get_scr_num(scp)+1; 693 return 0; 694 695 case KDENABIO: /* allow io operations */ 696 fp = (frametype *)p->p_regs; 697 fp->eflags |= PSL_IOPL; 698 return 0; 699 700 case KDDISABIO: /* disallow io operations (default) */ 701 fp = (frametype *)p->p_regs; 702 fp->eflags &= ~PSL_IOPL; 703 return 0; 704 705 case KDSETMODE: /* set current mode of this (virtual) console */ 706 switch (*data) { 707 case KD_TEXT: /* switch to TEXT (known) mode */ 708 /* restore fonts & palette ! */ 709 if (crtc_vga) { 710 load_font(0, 16, font_8x16); 711 load_font(1, 8, font_8x8); 712 load_font(2, 14, font_8x14); 713 load_palette(); 714 } 715 /* FALL THROUGH */ 716 717 case KD_TEXT1: /* switch to TEXT (known) mode */ 718 /* no restore fonts & palette */ 719 scp->status &= ~UNKNOWN_MODE; 720 set_mode(scp); 721 clear_screen(scp); 722 return 0; 723 724 case KD_GRAPHICS:/* switch to GRAPHICS (unknown) mode */ 725 scp->status |= UNKNOWN_MODE; 726 return 0; 727 default: 728 return EINVAL; 729 } 730 /* NOT REACHED */ 731 732 case KDGETMODE: /* get current mode of this (virtual) console */ 733 *data = (scp->status & UNKNOWN_MODE) ? KD_GRAPHICS : KD_TEXT; 734 return 0; 735 736 case KDSBORDER: /* set border color of this (virtual) console */ 737 if (!crtc_vga) 738 return ENXIO; 739 scp->border = *data; 740 if (scp == cur_console) 741 set_border(scp->border); 742 return 0; 743 744 case KDSKBSTATE: /* set keyboard state (locks) */ 745 if (*data >= 0 && *data <= LOCK_KEY_MASK) { 746 scp->status &= ~LOCK_KEY_MASK; 747 scp->status |= *data; 748 if (scp == cur_console) 749 update_leds(scp->status & LED_MASK); 750 return 0; 751 } 752 return EINVAL; 753 754 case KDGKBSTATE: /* get keyboard state (locks) */ 755 *data = scp->status & LOCK_KEY_MASK; 756 return 0; 757 758 case KDSETRAD: /* set keyboard repeat & delay rates */ 759 if (*(u_char*)data < 0x80) { 760 kbd_cmd(KB_SETRAD); 761 kbd_cmd(*data & 0x7f); 762 return 0; 763 } 764 return EINVAL; 765 766 case KDSKBMODE: /* set keyboard mode */ 767 switch (*data) { 768 case K_RAW: /* switch to RAW scancode mode */ 769 scp->status |= KBD_RAW_MODE; 770 return 0; 771 772 case K_XLATE: /* switch to XLT ascii mode */ 773 scp->status &= ~KBD_RAW_MODE; 774 return 0; 775 default: 776 return EINVAL; 777 } 778 /* NOT REACHED */ 779 780 case KDGKBMODE: /* get keyboard mode */ 781 *data = (scp->status & KBD_RAW_MODE) ? K_RAW : K_XLATE; 782 return 0; 783 784 case KDMKTONE: /* sound the bell */ 785 if (scp == cur_console) 786 sysbeep(scp->bell_pitch, scp->bell_duration); 787 return 0; 788 789 case KIOCSOUND: /* make tone (*data) hz */ 790 if (scp == cur_console) { 791 if (*(int*)data) { 792 int pitch = TIMER_FREQ/(*(int*)data); 793 /* enable counter 2 */ 794 outb(0x61, inb(0x61) | 3); 795 /* set command for counter 2, 2 byte write */ 796 outb(TIMER_MODE, 797 TIMER_SEL2|TIMER_16BIT|TIMER_SQWAVE); 798 /* set pitch */ 799 outb(TIMER_CNTR2, pitch); 800 outb(TIMER_CNTR2, (pitch>>8)); 801 } 802 else { 803 /* disable counter 2 */ 804 outb(0x61, inb(0x61) & 0xFC); 805 } 806 } 807 return 0; 808 809 case KDGKBTYPE: /* get keyboard type */ 810 *data = 0; /* type not known (yet) */ 811 return 0; 812 813 case KDSETLED: /* set keyboard LED status */ 814 if (*data >= 0 && *data <= LED_MASK) { 815 scp->status &= ~LED_MASK; 816 scp->status |= *data; 817 if (scp == cur_console) 818 update_leds(scp->status & LED_MASK); 819 return 0; 820 } 821 return EINVAL; 822 823 case KDGETLED: /* get keyboard LED status */ 824 *data = scp->status & LED_MASK; 825 return 0; 826 827 case GETFKEY: /* get functionkey string */ 828 if (*(u_short*)data < n_fkey_tab) { 829 fkeyarg_t *ptr = (fkeyarg_t*)data; 830 bcopy(&fkey_tab[ptr->keynum].str, 831 ptr->keydef, 832 fkey_tab[ptr->keynum].len); 833 ptr->flen = fkey_tab[ptr->keynum].len; 834 return 0; 835 } 836 else 837 return EINVAL; 838 839 case SETFKEY: /* set functionkey string */ 840 if (*(u_short*)data < n_fkey_tab) { 841 fkeyarg_t *ptr = (fkeyarg_t*)data; 842 bcopy(ptr->keydef, 843 &fkey_tab[ptr->keynum].str, 844 min(ptr->flen, MAXFK)); 845 fkey_tab[ptr->keynum].len = min(ptr->flen, MAXFK); 846 return 0; 847 } 848 else 849 return EINVAL; 850 851 case GIO_SCRNMAP: /* get output translation table */ 852 bcopy(&scr_map, data, sizeof(scr_map)); 853 return 0; 854 855 case PIO_SCRNMAP: /* set output translation table */ 856 bcopy(data, &scr_map, sizeof(scr_map)); 857 return 0; 858 859 case GIO_KEYMAP: /* get keyboard translation table */ 860 bcopy(&key_map, data, sizeof(key_map)); 861 return 0; 862 863 case PIO_KEYMAP: /* set keyboard translation table */ 864 bcopy(data, &key_map, sizeof(key_map)); 865 return 0; 866 867 case PIO_FONT8x8: /* set 8x8 dot font */ 868 if (!crtc_vga) 869 return ENXIO; 870 bcopy(data, &font_8x8, sizeof(font_8x8)); 871 load_font(1, 8, font_8x8); 872 return 0; 873 874 case GIO_FONT8x8: /* get 8x8 dot font */ 875 if (!crtc_vga) 876 return ENXIO; 877 bcopy(&font_8x8, data, sizeof(font_8x8)); 878 return 0; 879 880 case PIO_FONT8x14: /* set 8x14 dot font */ 881 if (!crtc_vga) 882 return ENXIO; 883 bcopy(data, &font_8x14, sizeof(font_8x14)); 884 load_font(2, 14, font_8x14); 885 return 0; 886 887 case GIO_FONT8x14: /* get 8x14 dot font */ 888 if (!crtc_vga) 889 return ENXIO; 890 bcopy(&font_8x14, data, sizeof(font_8x14)); 891 return 0; 892 893 case PIO_FONT8x16: /* set 8x16 dot font */ 894 if (!crtc_vga) 895 return ENXIO; 896 bcopy(data, &font_8x16, sizeof(font_8x16)); 897 load_font(0, 16, font_8x16); 898 return 0; 899 900 case GIO_FONT8x16: /* get 8x16 dot font */ 901 if (!crtc_vga) 902 return ENXIO; 903 bcopy(&font_8x16, data, sizeof(font_8x16)); 904 return 0; 905 906 case CONSOLE_X_MODE_ON: /* just to be compatible */ 907 if (saved_console < 0) { 908 saved_console = get_scr_num(cur_console); 909 switch_scr(minor(dev)); 910 fp = (frametype *)p->p_regs; 911 fp->eflags |= PSL_IOPL; 912 scp->status |= UNKNOWN_MODE; 913 scp->status |= KBD_RAW_MODE; 914 return 0; 915 } 916 return EAGAIN; 917 918 case CONSOLE_X_MODE_OFF:/* just to be compatible */ 919 fp = (frametype *)p->p_regs; 920 fp->eflags &= ~PSL_IOPL; 921 if (crtc_vga) { 922 load_font(0, 16, font_8x16); 923 load_font(1, 8, font_8x8); 924 load_font(2, 14, font_8x14); 925 load_palette(); 926 } 927 scp->status &= ~UNKNOWN_MODE; 928 set_mode(scp); 929 clear_screen(scp); 930 scp->status &= ~KBD_RAW_MODE; 931 switch_scr(saved_console); 932 saved_console = -1; 933 return 0; 934 935 case CONSOLE_X_BELL: /* more compatibility */ 936 /* 937 * if set, data is a pointer to a length 2 array of 938 * integers. data[0] is the pitch in Hz and data[1] 939 * is the duration in msec. 940 */ 941 if (data) 942 sysbeep(TIMER_FREQ/((int*)data)[0], 943 ((int*)data)[1]*hz/3000); 944 else 945 sysbeep(scp->bell_pitch, scp->bell_duration); 946 return 0; 947 948 default: 949 break; 950 } 951 952 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 953 if (error >= 0) 954 return(error); 955 error = ttioctl(tp, cmd, data, flag); 956 if (error >= 0) 957 return(error); 958 return(ENOTTY); 959} 960 961 962pcxint(dev_t dev) 963{ 964 int unit = minor(dev); 965 966#if defined(NetBSD) 967 if (!pc_tty[unit]) 968 return; 969 pc_tty[unit]->t_state &= ~TS_BUSY; 970 if (pc_tty[unit]->t_line) 971 (*linesw[pc_tty[unit]->t_line].l_start)(pc_tty[unit]); 972 else 973 pcstart(pc_tty[unit]); 974#else 975 pccons[unit].t_state &= ~TS_BUSY; 976 if (pccons[unit].t_line) 977 (*linesw[pccons[unit].t_line].l_start)(&pccons[unit]); 978 else 979 pcstart(&pccons[unit]); 980#endif 981} 982 983 984pcstart(struct tty *tp) 985{ 986#if defined(NetBSD) 987 struct clist *rbp; 988 int i, s, len; 989 u_char buf[PCBURST]; 990 scr_stat *scp = get_scr_stat(tp->t_dev); 991 992 if (scp->status & SLKED) 993 return; 994 s = spltty(); 995 if (!(tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))) { 996 tp->t_state |= TS_BUSY; 997 splx(s); 998 rbp = &tp->t_outq; 999 len = q_to_b(rbp, buf, PCBURST); 1000 for (i=0; i<len; i++) 1001 if (buf[i]) ansi_put(scp, buf[i]); 1002 s = spltty(); 1003 tp->t_state &= ~TS_BUSY; 1004 if (rbp->c_cc) { 1005 tp->t_state |= TS_TIMEOUT; 1006 timeout((timeout_t)ttrstrt, (caddr_t)tp, 1); 1007 } 1008 if (rbp->c_cc <= tp->t_lowat) { 1009 if (tp->t_state & TS_ASLEEP) { 1010 tp->t_state &= ~TS_ASLEEP; 1011 wakeup((caddr_t)rbp); 1012 } 1013 selwakeup(&tp->t_wsel); 1014 } 1015 1016 } 1017 splx(s); 1018#else 1019 int c, s; 1020 scr_stat *scp = get_scr_stat(tp->t_dev); 1021 1022 s = spltty(); 1023 if (!(tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))) 1024 for (;;) { 1025 if (RB_LEN(&tp->t_out) <= tp->t_lowat) { 1026 if (tp->t_state & TS_ASLEEP) { 1027 tp->t_state &= ~TS_ASLEEP; 1028 wakeup((caddr_t)&tp->t_out); 1029 } 1030 if (tp->t_wsel) { 1031 selwakeup(tp->t_wsel, 1032 tp->t_state & TS_WCOLL); 1033 tp->t_wsel = 0; 1034 tp->t_state &= ~TS_WCOLL; 1035 } 1036 } 1037 if (RB_LEN(&tp->t_out) == 0) 1038 break; 1039 if (scp->status & SLKED) 1040 break; 1041 c = getc(&tp->t_out); 1042 tp->t_state |= TS_BUSY; 1043 splx(s); 1044 ansi_put(scp, c); 1045 s = spltty(); 1046 tp->t_state &= ~TS_BUSY; 1047 } 1048 splx(s); 1049#endif 1050} 1051 1052 1053pccnprobe(struct consdev *cp) 1054{ 1055 int maj; 1056 1057 /* locate the major number */ 1058 for (maj = 0; maj < nchrdev; maj++) 1059 if (cdevsw[maj].d_open == pcopen) 1060 break; 1061 1062 /* initialize required fields */ 1063 cp->cn_dev = makedev(maj, 0); 1064#if !defined(NetBSD) 1065 cp->cn_tp = &pccons[0]; 1066#endif 1067 cp->cn_pri = CN_INTERNAL; 1068} 1069 1070 1071pccninit(struct consdev *cp) 1072{ 1073 scinit(); 1074} 1075 1076 1077pccnputc(dev_t dev, char c) 1078{ 1079 int pos; 1080 1081 if (cur_console->status & UNKNOWN_MODE) 1082 return; 1083 if (c == '\n') 1084 sput('\r'); 1085 sput(c); 1086 pos = cur_console->crtat - cur_console->crt_base; 1087 if (pos != cur_cursor_pos) { 1088 cur_cursor_pos = pos; 1089 outb(crtc_addr,14); 1090 outb(crtc_addr+1,pos >> 8); 1091 outb(crtc_addr,15); 1092 outb(crtc_addr+1,pos&0xff); 1093 } 1094} 1095 1096 1097pccngetc(dev_t dev) 1098{ 1099 int c, s; 1100 1101 s = spltty(); /* block scintr while we poll */ 1102 c = sgetc(0); 1103 splx(s); 1104 if (c == '\r') c = '\n'; 1105 return(c); 1106} 1107 1108#if !defined(STAR_SAVER) && !defined(SNAKE_SAVER) 1109 1110static void scrn_saver(int test) 1111{ 1112 u_char val; 1113 1114 if (test) { 1115 scrn_blanked = 1; 1116 outb(TSIDX, 0x01); val = inb(TSREG); 1117 outb(TSIDX, 0x01); outb(TSREG, val | 0x20); 1118 } 1119 else { 1120 scrn_blanked = 0; 1121 outb(TSIDX, 0x01); val = inb(TSREG); 1122 outb(TSIDX, 0x01); outb(TSREG, val & 0xDF); 1123 } 1124} 1125#endif 1126#if defined(STAR_SAVER) || defined(SNAKE_SAVER) 1127 1128static u_long rand_next = 1; 1129 1130static rand() 1131{ 1132 return ((rand_next = rand_next * 1103515245 + 12345) & 0x7FFFFFFF); 1133} 1134#endif 1135#ifdef STAR_SAVER 1136/* 1137 * Alternate saver that got its inspiration from a well known utility 1138 * package for an unfamous OS. 1139 */ 1140 1141#define NUM_STARS 50 1142 1143static void scrn_saver(int test) 1144{ 1145 scr_stat *scp = cur_console; 1146 int cell, i; 1147 char pattern[] = {"...........++++*** "}; 1148 char colors[] = {FG_DARKGREY, FG_LIGHTGREY, 1149 FG_WHITE, FG_LIGHTCYAN}; 1150 static u_short stars[NUM_STARS][2]; 1151 1152 if (test) { 1153 if (!scrn_blanked) { 1154 bcopy(Crtat, scp->scr, 1155 scp->max_posx * scp->max_posy * 2); 1156 fillw((FG_LIGHTGREY|BG_BLACK)<<8 | scr_map[0x20], Crtat, 1157 scp->max_posx * scp->max_posy); 1158 set_border(0); 1159 i = scp->max_posy * scp->max_posx + 5; 1160 outb(crtc_addr, 14); 1161 outb(crtc_addr+1, i >> 8); 1162 outb(crtc_addr, 15); 1163 outb(crtc_addr+1, i & 0xff); 1164 scrn_blanked = 1; 1165 for(i=0; i<NUM_STARS; i++) { 1166 stars[i][0] = 1167 rand() % (scp->max_posx*scp->max_posy); 1168 stars[i][1] = 0; 1169 } 1170 } 1171 cell = rand() % NUM_STARS; 1172 *((u_short*)(Crtat + stars[cell][0])) = 1173 scr_map[pattern[stars[cell][1]]] | 1174 colors[rand()%sizeof(colors)] << 8; 1175 if ((stars[cell][1]+=(rand()%4)) >= sizeof(pattern)-1) { 1176 stars[cell][0] = rand() % (scp->max_posx*scp->max_posy); 1177 stars[cell][1] = 0; 1178 } 1179 } 1180 else { 1181 if (scrn_blanked) { 1182 bcopy(scp->scr, Crtat, scp->max_posx*scp->max_posy*2); 1183 cur_cursor_pos = -1; 1184 set_border(scp->border); 1185 scrn_blanked = 0; 1186 } 1187 } 1188} 1189#endif 1190#ifdef SNAKE_SAVER 1191/* 1192 * alternative screen saver for cards that do not like blanking 1193 */ 1194 1195static void scrn_saver(int test) 1196{ 1197 const char saves[] = {"FreeBSD"}; 1198 static u_char *savs[sizeof(saves)-1]; 1199 static int dirx, diry; 1200 int f; 1201 scr_stat *scp = cur_console; 1202 1203 if (test) { 1204 if (!scrn_blanked) { 1205 bcopy(Crtat, scp->scr, 1206 scp->max_posx * scp->max_posy * 2); 1207 fillw((FG_LIGHTGREY|BG_BLACK)<<8 | scr_map[0x20], Crtat, 1208 scp->max_posx * scp->max_posy); 1209 set_border(0); 1210 dirx = (scp->posx ? 1 : -1); 1211 diry = (scp->posy ? 1212 scp->max_posx : -scp->max_posx); 1213 for (f=0; f< sizeof(saves)-1; f++) 1214 savs[f] = (u_char *)Crtat + 2 * 1215 (scp->posx+scp->posy*scp->max_posx); 1216 *(savs[0]) = scr_map[*saves]; 1217 f = scp->max_posy * scp->max_posx + 5; 1218 outb(crtc_addr, 14); 1219 outb(crtc_addr+1, f >> 8); 1220 outb(crtc_addr, 15); 1221 outb(crtc_addr+1, f & 0xff); 1222 scrn_blanked = 1; 1223 } 1224 if (scrn_blanked++ < 4) 1225 return; 1226 scrn_blanked = 1; 1227 *(savs[sizeof(saves)-2]) = scr_map[0x20]; 1228 for (f=sizeof(saves)-2; f > 0; f--) 1229 savs[f] = savs[f-1]; 1230 f = (savs[0] - (u_char *)Crtat) / 2; 1231 if ((f % scp->max_posx) == 0 || 1232 (f % scp->max_posx) == scp->max_posx - 1 || 1233 (rand() % 50) == 0) 1234 dirx = -dirx; 1235 if ((f / scp->max_posx) == 0 || 1236 (f / scp->max_posx) == scp->max_posy - 1 || 1237 (rand() % 20) == 0) 1238 diry = -diry; 1239 savs[0] += 2*dirx + 2*diry; 1240 for (f=sizeof(saves)-2; f>=0; f--) 1241 *(savs[f]) = scr_map[saves[f]]; 1242 } 1243 else { 1244 if (scrn_blanked) { 1245 bcopy(scp->scr, Crtat, 1246 scp->max_posx * scp->max_posy * 2); 1247 cur_cursor_pos = -1; 1248 set_border(scp->border); 1249 scrn_blanked = 0; 1250 } 1251 } 1252} 1253#endif 1254 1255static void cursor_shape(int start, int end) 1256{ 1257 outb(crtc_addr, 10); 1258 outb(crtc_addr+1, start & 0xFF); 1259 outb(crtc_addr, 11); 1260 outb(crtc_addr+1, end & 0xFF); 1261} 1262 1263 1264static void get_cursor_shape(int *start, int *end) 1265{ 1266 outb(crtc_addr, 10); 1267 *start = inb(crtc_addr+1) & 0x1F; 1268 outb(crtc_addr, 11); 1269 *end = inb(crtc_addr+1) & 0x1F; 1270} 1271 1272 1273static void cursor_pos(void) 1274{ 1275 int pos; 1276 1277 if (cur_console->status & UNKNOWN_MODE) 1278 return; 1279 if (scrn_blank_time && (time.tv_sec > scrn_time_stamp+scrn_blank_time)) 1280 scrn_saver(1); 1281 pos = cur_console->crtat - cur_console->crt_base; 1282 if (!scrn_blanked && pos != cur_cursor_pos) { 1283 cur_cursor_pos = pos; 1284 outb(crtc_addr, 14); 1285 outb(crtc_addr+1, pos>>8); 1286 outb(crtc_addr, 15); 1287 outb(crtc_addr+1, pos&0xff); 1288 } 1289 timeout((timeout_t)cursor_pos, 0, hz/20); 1290} 1291 1292 1293static void clear_screen(scr_stat *scp) 1294{ 1295 move_crsr(scp, 0, 0); 1296 fillw(scp->term.attr | scr_map[0x20], scp->crt_base, 1297 scp->max_posx * scp->max_posy); 1298} 1299 1300 1301static switch_scr(u_int next_scr) 1302{ 1303 if (in_putc) { /* don't switch if in putc */ 1304 nx_scr = next_scr+1; 1305 return 0; 1306 } 1307 if (switch_in_progress && 1308 (cur_console->proc != pfind(cur_console->pid))) 1309 switch_in_progress = 0; 1310 if (next_scr >= NCONS || switch_in_progress) { 1311 sysbeep(BELL_PITCH, BELL_DURATION); 1312 return -1; 1313 } 1314 switch_in_progress = 1; 1315 old_scp = cur_console; 1316 new_scp = &console[next_scr]; 1317 wakeup((caddr_t)&new_scp->smode); 1318 if (new_scp == old_scp) { 1319 switch_in_progress = 0; 1320 return 0; 1321 } 1322 1323 /* has controlling process died? */ 1324 if (old_scp->proc && (old_scp->proc != pfind(old_scp->pid))) 1325 old_scp->smode.mode = VT_AUTO; 1326 if (new_scp->proc && (new_scp->proc != pfind(new_scp->pid))) 1327 new_scp->smode.mode = VT_AUTO; 1328 1329 /* check the modes and switch approbiatly */ 1330 if (old_scp->smode.mode == VT_PROCESS) { 1331 old_scp->status |= SWITCH_WAIT_REL; 1332 psignal(old_scp->proc, old_scp->smode.relsig); 1333 } 1334 else { 1335 exchange_scr(); 1336 if (new_scp->smode.mode == VT_PROCESS) { 1337 new_scp->status |= SWITCH_WAIT_ACQ; 1338 psignal(new_scp->proc, new_scp->smode.acqsig); 1339 } 1340 else 1341 switch_in_progress = 0; 1342 } 1343 return 0; 1344} 1345 1346 1347static void exchange_scr(void) 1348{ 1349 bcopy(Crtat, old_scp->scr, old_scp->max_posx * old_scp->max_posy * 2); 1350 old_scp->crt_base = old_scp->scr; 1351 move_crsr(old_scp, old_scp->posx, old_scp->posy); 1352 cur_console = new_scp; 1353#if defined(NetBSD) 1354 cur_tty = pc_tty[get_scr_num(new_scp)]; 1355#else 1356 cur_tty = &pccons[get_scr_num(new_scp)]; 1357#endif 1358 if (old_scp->status & KBD_RAW_MODE || new_scp->status & KBD_RAW_MODE) 1359 shfts = ctls = alts = agrs = metas = 0; 1360 update_leds(new_scp->status & LED_MASK); 1361 set_mode(new_scp); 1362 new_scp->crt_base = Crtat; 1363 move_crsr(new_scp, new_scp->posx, new_scp->posy); 1364 bcopy(new_scp->scr, Crtat, new_scp->max_posx * new_scp->max_posy * 2); 1365 nx_scr = 0; 1366} 1367 1368 1369static void move_crsr(scr_stat *scp, int x, int y) 1370{ 1371 if (x < 0 || y < 0 || x >= scp->max_posx || y >= scp->max_posy) 1372 return; 1373 scp->posx = x; 1374 scp->posy = y; 1375 scp->crtat = scp->crt_base + scp->posy * scp->max_posx + scp->posx; 1376} 1377 1378 1379static void move_up(u_short *s, u_short *d, u_int len) 1380{ 1381 s += len; 1382 d += len; 1383 while (len-- > 0) 1384 *--d = *--s; 1385} 1386 1387 1388static void move_down(u_short *s, u_short *d, u_int len) 1389{ 1390 while (len-- > 0) 1391 *d++ = *s++; 1392} 1393 1394 1395static void scan_esc(scr_stat *scp, u_char c) 1396{ 1397 static u_char ansi_col[16] = 1398 {0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15}; 1399 int i, n; 1400 u_short *src, *dst, count; 1401 1402 if (scp->term.esc == 1) { 1403 switch (c) { 1404 1405 case '[': /* Start ESC [ sequence */ 1406 scp->term.esc = 2; 1407 scp->term.last_par = -1; 1408 for (i = scp->term.n_par; i < MAX_ESC_PAR; i++) 1409 scp->term.par[i] = 1; 1410 scp->term.n_par = 0; 1411 return; 1412 1413 case 'M': /* Move cursor up 1 line, scroll if at top */ 1414 if (scp->posy > 0) 1415 move_crsr(scp, scp->posx, scp->posy - 1); 1416 else { 1417 move_up(scp->crt_base, 1418 scp->crt_base + scp->max_posx, 1419 (scp->max_posy - 1) * scp->max_posx); 1420 fillw(scp->term.attr | scr_map[0x20], 1421 scp->crt_base, scp->max_posx); 1422 } 1423 break; 1424#if notyet 1425 case 'Q': 1426 scp->term.esc = 4; 1427 break; 1428#endif 1429 case 'c': /* Clear screen & home */ 1430 clear_screen(scp); 1431 break; 1432 } 1433 } 1434 else if (scp->term.esc == 2) { 1435 if (c >= '0' && c <= '9') { 1436 if (scp->term.n_par < MAX_ESC_PAR) { 1437 if (scp->term.last_par != scp->term.n_par) { 1438 scp->term.last_par = scp->term.n_par; 1439 scp->term.par[scp->term.n_par] = 0; 1440 } 1441 else 1442 scp->term.par[scp->term.n_par] *= 10; 1443 scp->term.par[scp->term.n_par] += c - '0'; 1444 return; 1445 } 1446 } 1447 scp->term.n_par = scp->term.last_par + 1; 1448 switch (c) { 1449 1450 case ';': 1451 if (scp->term.n_par < MAX_ESC_PAR) 1452 return; 1453 break; 1454 1455 case '=': 1456 scp->term.esc = 3; 1457 scp->term.last_par = -1; 1458 for (i = scp->term.n_par; i < MAX_ESC_PAR; i++) 1459 scp->term.par[i] = 1; 1460 scp->term.n_par = 0; 1461 return; 1462 1463 case 'A': /* up n rows */ 1464 n = scp->term.par[0]; if (n < 1) n = 1; 1465 move_crsr(scp, scp->posx, scp->posy - n); 1466 break; 1467 1468 case 'B': /* down n rows */ 1469 n = scp->term.par[0]; if (n < 1) n = 1; 1470 move_crsr(scp, scp->posx, scp->posy + n); 1471 break; 1472 1473 case 'C': /* right n columns */ 1474 n = scp->term.par[0]; if (n < 1) n = 1; 1475 move_crsr(scp, scp->posx + n, scp->posy); 1476 break; 1477 1478 case 'D': /* left n columns */ 1479 n = scp->term.par[0]; if (n < 1) n = 1; 1480 move_crsr(scp, scp->posx - n, scp->posy); 1481 break; 1482 1483 case 'E': /* cursor to start of line n lines down */ 1484 n = scp->term.par[0]; if (n < 1) n = 1; 1485 move_crsr(scp, 0, scp->posy + n); 1486 break; 1487 1488 case 'F': /* cursor to start of line n lines up */ 1489 n = scp->term.par[0]; if (n < 1) n = 1; 1490 move_crsr(scp, 0, scp->posy - n); 1491 break; 1492 1493 case 'f': /* System V consoles .. */ 1494 case 'H': /* Cursor move */ 1495 if (scp->term.n_par == 0) 1496 move_crsr(scp, 0, 0); 1497 else if (scp->term.n_par == 2) 1498 move_crsr(scp, scp->term.par[1] - 1, 1499 scp->term.par[0] - 1); 1500 break; 1501 1502 case 'J': /* Clear all or part of display */ 1503 if (scp->term.n_par == 0) 1504 n = 0; 1505 else 1506 n = scp->term.par[0]; 1507 switch (n) { 1508 case 0: /* clear form cursor to end of display */ 1509 fillw(scp->term.attr | scr_map[0x20], 1510 scp->crtat, scp->crt_base + 1511 scp->max_posx * scp->max_posy - 1512 scp->crtat); 1513 break; 1514 case 1: /* clear from beginning of display to cursor */ 1515 fillw(scp->term.attr | scr_map[0x20], 1516 scp->crt_base, 1517 scp->crtat - scp->crt_base); 1518 break; 1519 case 2: /* clear entire display */ 1520 clear_screen(scp); 1521 break; 1522 } 1523 break; 1524 1525 case 'K': /* Clear all or part of line */ 1526 if (scp->term.n_par == 0) 1527 n = 0; 1528 else 1529 n = scp->term.par[0]; 1530 switch (n) { 1531 case 0: /* clear form cursor to end of line */ 1532 fillw(scp->term.attr | scr_map[0x20], 1533 scp->crtat, scp->max_posx - scp->posx); 1534 break; 1535 case 1: /* clear from beginning of line to cursor */ 1536 fillw(scp->term.attr|scr_map[0x20], 1537 scp->crtat - (scp->max_posx - scp->posx), 1538 (scp->max_posx - scp->posx) + 1); 1539 break; 1540 case 2: /* clear entire line */ 1541 fillw(scp->term.attr|scr_map[0x20], 1542 scp->crtat - (scp->max_posx - scp->posx), 1543 scp->max_posx); 1544 break; 1545 } 1546 break; 1547 1548 case 'L': /* Insert n lines */ 1549 n = scp->term.par[0]; if (n < 1) n = 1; 1550 if (n > scp->max_posy - scp->posy) 1551 n = scp->max_posy - scp->posy; 1552 src = scp->crt_base + scp->posy * scp->max_posx; 1553 dst = src + n * scp->max_posx; 1554 count = scp->max_posy - (scp->posy + n); 1555 move_up(src, dst, count * scp->max_posx); 1556 fillw(scp->term.attr | scr_map[0x20], src, 1557 n * scp->max_posx); 1558 break; 1559 1560 case 'M': /* Delete n lines */ 1561 n = scp->term.par[0]; if (n < 1) n = 1; 1562 if (n > scp->max_posy - scp->posy) 1563 n = scp->max_posy - scp->posy; 1564 dst = scp->crt_base + scp->posy * scp->max_posx; 1565 src = dst + n * scp->max_posx; 1566 count = scp->max_posy - (scp->posy + n); 1567 move_down(src, dst, count * scp->max_posx); 1568 src = dst + count * scp->max_posx; 1569 fillw(scp->term.attr | scr_map[0x20], src, 1570 n * scp->max_posx); 1571 break; 1572 1573 case 'P': /* Delete n chars */ 1574 n = scp->term.par[0]; if (n < 1) n = 1; 1575 if (n > scp->max_posx - scp->posx) 1576 n = scp->max_posx - scp->posx; 1577 dst = scp->crtat; 1578 src = dst + n; 1579 count = scp->max_posx - (scp->posx + n); 1580 move_down(src, dst, count); 1581 src = dst + count; 1582 fillw(scp->term.attr | scr_map[0x20], src, n); 1583 break; 1584 1585 case '@': /* Insert n chars */ 1586 n = scp->term.par[0]; if (n < 1) n = 1; 1587 if (n > scp->max_posx - scp->posx) 1588 n = scp->max_posx - scp->posx; 1589 src = scp->crtat; 1590 dst = src + n; 1591 count = scp->max_posx - (scp->posx + n); 1592 move_up(src, dst, count); 1593 fillw(scp->term.attr | scr_map[0x20], src, n); 1594 break; 1595 1596 case 'S': /* scroll up n lines */ 1597 n = scp->term.par[0]; if (n < 1) n = 1; 1598 bcopy(scp->crt_base + (scp->max_posx * n), 1599 scp->crt_base, 1600 scp->max_posx * (scp->max_posy - n) * 1601 sizeof(u_short)); 1602 fillw(scp->term.attr | scr_map[0x20], 1603 scp->crt_base + scp->max_posx * 1604 (scp->max_posy - 1), 1605 scp->max_posx); 1606 break; 1607 1608 case 'T': /* scroll down n lines */ 1609 n = scp->term.par[0]; if (n < 1) n = 1; 1610 bcopy(scp->crt_base, 1611 scp->crt_base + (scp->max_posx * n), 1612 scp->max_posx * (scp->max_posy - n) * 1613 sizeof(u_short)); 1614 fillw(scp->term.attr | scr_map[0x20], scp->crt_base, 1615 scp->max_posx); 1616 break; 1617 1618 case 'X': /* delete n characters in line */ 1619 n = scp->term.par[0]; if (n < 1) n = 1; 1620 fillw(scp->term.attr | scr_map[0x20], 1621 scp->crt_base + scp->posx + 1622 ((scp->max_posx*scp->posy) * sizeof(u_short)), n); 1623 break; 1624 1625 case 'Z': /* move n tabs backwards */ 1626 n = scp->term.par[0]; if (n < 1) n = 1; 1627 if ((i = scp->posx & 0xf8) == scp->posx) 1628 i -= 8*n; 1629 else 1630 i -= 8*(n-1); 1631 if (i < 0) 1632 i = 0; 1633 move_crsr(scp, i, scp->posy); 1634 break; 1635 1636 case '`': /* move cursor to column n */ 1637 n = scp->term.par[0]; if (n < 1) n = 1; 1638 move_crsr(scp, n, scp->posy); 1639 break; 1640 1641 case 'a': /* move cursor n columns to the right */ 1642 n = scp->term.par[0]; if (n < 1) n = 1; 1643 move_crsr(scp, scp->posx + n, scp->posy); 1644 break; 1645 1646 case 'd': /* move cursor to row n */ 1647 n = scp->term.par[0]; if (n < 1) n = 1; 1648 move_crsr(scp, scp->posx, n); 1649 break; 1650 1651 case 'e': /* move cursor n rows down */ 1652 n = scp->term.par[0]; if (n < 1) n = 1; 1653 move_crsr(scp, scp->posx, scp->posy + n); 1654 break; 1655 1656 case 'm': /* change attribute */ 1657 if (scp->term.n_par == 0) 1658 n = 0; 1659 else 1660 n = scp->term.par[0]; 1661 switch (n) { 1662 case 0: /* back to normal */ 1663 scp->term.attr = scp->term.std_attr; 1664 break; 1665 case 1: /* highlight (bold) */ 1666 scp->term.attr &= 0xFF00; 1667 scp->term.attr |= 0x0800; 1668 break; 1669 case 4: /* highlight (underline) */ 1670 scp->term.attr &= 0x0F00; 1671 scp->term.attr |= 0x0800; 1672 break; 1673 case 5: /* blink */ 1674 scp->term.attr &= 0xFF00; 1675 scp->term.attr |= 0x8000; 1676 break; 1677 case 7: /* reverse video */ 1678 scp->term.attr = scp->term.rev_attr; 1679 break; 1680 case 30: case 31: case 32: case 33: /* set fg color */ 1681 case 34: case 35: case 36: case 37: 1682 scp->term.attr = (scp->term.attr & 0xF0FF) 1683 | (ansi_col[(n - 30) & 7] << 8); 1684 break; 1685 case 40: case 41: case 42: case 43: /* set bg color */ 1686 case 44: case 45: case 46: case 47: 1687 scp->term.attr = (scp->term.attr & 0x0FFF) 1688 | (ansi_col[(n - 40) & 7] << 12); 1689 break; 1690 } 1691 break; 1692 1693 case 'x': 1694 if (scp->term.n_par == 0) 1695 n = 0; 1696 else 1697 n = scp->term.par[0]; 1698 switch (n) { 1699 case 0: /* reset attributes */ 1700 scp->term.attr = scp->term.std_attr = 1701 current_default->std_attr; 1702 scp->term.rev_attr = current_default->rev_attr; 1703 break; 1704 case 1: /* set ansi background */ 1705 scp->term.attr = scp->term.std_attr = 1706 (scp->term.std_attr & 0x0F00) | 1707 (ansi_col[(scp->term.par[1])&0x0F]<<12); 1708 break; 1709 case 2: /* set ansi foreground */ 1710 scp->term.attr = scp->term.std_attr = 1711 (scp->term.std_attr & 0xF000) | 1712 (ansi_col[(scp->term.par[1])&0x0F]<<8); 1713 break; 1714 case 3: /* set ansi attribute directly */ 1715 scp->term.attr = scp->term.std_attr = 1716 (scp->term.par[1]&0xFF)<<8; 1717 break; 1718 case 5: /* set ansi reverse video background */ 1719 scp->term.rev_attr = 1720 (scp->term.rev_attr & 0x0F00) | 1721 (ansi_col[(scp->term.par[1])&0x0F]<<12); 1722 break; 1723 case 6: /* set ansi reverse video foreground */ 1724 scp->term.rev_attr = 1725 (scp->term.rev_attr & 0xF000) | 1726 (ansi_col[(scp->term.par[1])&0x0F]<<8); 1727 break; 1728 case 7: /* set ansi reverse video directly */ 1729 scp->term.rev_attr = (scp->term.par[1]&0xFF)<<8; 1730 break; 1731 } 1732 break; 1733 1734 case 'z': /* switch to (virtual) console n */ 1735 if (scp->term.n_par == 1) 1736 switch_scr(scp->term.par[0]); 1737 break; 1738 } 1739 } 1740 else if (scp->term.esc == 3) { 1741 if (c >= '0' && c <= '9') { 1742 if (scp->term.n_par < MAX_ESC_PAR) { 1743 if (scp->term.last_par != scp->term.n_par) { 1744 scp->term.last_par = scp->term.n_par; 1745 scp->term.par[scp->term.n_par] = 0; 1746 } 1747 else 1748 scp->term.par[scp->term.n_par] *= 10; 1749 scp->term.par[scp->term.n_par] += c - '0'; 1750 return; 1751 } 1752 } 1753 scp->term.n_par = scp->term.last_par + 1; 1754 switch (c) { 1755 1756 case ';': 1757 if (scp->term.n_par < MAX_ESC_PAR) 1758 return; 1759 break; 1760 1761 case 'A': /* set display border color */ 1762 if (scp->term.n_par == 1) 1763 scp->border=scp->term.par[0] & 0xff; 1764 if (scp == cur_console) 1765 set_border(scp->border); 1766 break; 1767 1768 case 'B': /* set bell pitch and duration */ 1769 if (scp->term.n_par == 2) { 1770 scp->bell_pitch = scp->term.par[0]; 1771 scp->bell_duration = scp->term.par[1]*10; 1772 } 1773 break; 1774 1775 case 'C': /* set cursor shape (start & end line) */ 1776 if (scp->term.n_par == 2) { 1777 scp->cursor_start = scp->term.par[0] & 0x1F; 1778 scp->cursor_end = scp->term.par[1] & 0x1F; 1779 if (scp == cur_console) 1780 cursor_shape(scp->cursor_start, 1781 scp->cursor_end); 1782 } 1783 break; 1784 1785 case 'F': /* set ansi foreground */ 1786 if (scp->term.n_par == 1) 1787 scp->term.attr = scp->term.std_attr = 1788 (scp->term.std_attr & 0xF000) 1789 | ((scp->term.par[0] & 0x0F) << 8); 1790 break; 1791 1792 case 'G': /* set ansi background */ 1793 if (scp->term.n_par == 1) 1794 scp->term.attr = scp->term.std_attr = 1795 (scp->term.std_attr & 0x0F00) 1796 | ((scp->term.par[0] & 0x0F) << 12); 1797 break; 1798 1799 case 'H': /* set ansi reverse video foreground */ 1800 if (scp->term.n_par == 1) 1801 scp->term.rev_attr = 1802 (scp->term.rev_attr & 0xF000) 1803 | ((scp->term.par[0] & 0x0F) << 8); 1804 break; 1805 1806 case 'I': /* set ansi reverse video background */ 1807 if (scp->term.n_par == 1) 1808 scp->term.rev_attr = 1809 (scp->term.rev_attr & 0x0F00) 1810 | ((scp->term.par[0] & 0x0F) << 12); 1811 break; 1812 } 1813 } 1814 scp->term.esc = 0; 1815} 1816 1817 1818static void ansi_put(scr_stat *scp, u_char c) 1819{ 1820 if (scp->status & UNKNOWN_MODE) 1821 return; 1822 1823 /* make screensaver happy */ 1824 if (scp == cur_console) { 1825 scrn_time_stamp = time.tv_sec; 1826 if (scrn_blanked) 1827 scrn_saver(0); 1828 } 1829 in_putc++; 1830 if (scp->term.esc) 1831 scan_esc(scp, c); 1832 else switch(c) { 1833 case 0x1B: /* start escape sequence */ 1834 scp->term.esc = 1; 1835 scp->term.n_par = 0; 1836 break; 1837 case 0x07: 1838 if (scp == cur_console) 1839 sysbeep(scp->bell_pitch, scp->bell_duration); 1840 break; 1841 case '\t': /* non-destructive tab */ 1842 scp->crtat += (8 - scp->posx % 8); 1843 scp->posx += (8 - scp->posx % 8); 1844 break; 1845 case '\b': /* non-destructive backspace */ 1846 if (scp->crtat > scp->crt_base) { 1847 scp->crtat--; 1848 if (scp->posx > 0) 1849 scp->posx--; 1850 else { 1851 scp->posx += scp->max_posx - 1; 1852 scp->posy--; 1853 } 1854 } 1855 break; 1856 case '\r': /* return to pos 0 */ 1857 move_crsr(scp, 0, scp->posy); 1858 break; 1859 case '\n': /* newline, same pos */ 1860 scp->crtat += scp->max_posx; 1861 scp->posy++; 1862 break; 1863 case '\f': /* form feed, clears screen */ 1864 clear_screen(scp); 1865 break; 1866 default: 1867 /* Print only printables */ 1868 *scp->crtat = (scp->term.attr | scr_map[c]); 1869 scp->crtat++; 1870 if (++scp->posx >= scp->max_posx) { 1871 scp->posx = 0; 1872 scp->posy++; 1873 } 1874 break; 1875 } 1876 if (scp->crtat >= scp->crt_base + scp->max_posy * scp->max_posx) { 1877 bcopy(scp->crt_base + scp->max_posx, scp->crt_base, 1878 scp->max_posx * (scp->max_posy - 1) * sizeof(u_short)); 1879 fillw(scp->term.attr | scr_map[0x20], 1880 scp->crt_base + scp->max_posx * (scp->max_posy - 1), 1881 scp->max_posx); 1882 scp->crtat -= scp->max_posx; 1883 scp->posy--; 1884 } 1885 in_putc--; 1886 if (nx_scr) 1887 switch_scr(nx_scr - 1); 1888} 1889 1890static void scinit(void) 1891{ 1892 u_short volatile *cp = Crtat + (CGA_BUF-MONO_BUF)/sizeof(u_short), was; 1893 unsigned cursorat; 1894 int i; 1895 1896 /* 1897 * catch that once in a blue moon occurence when scinit is called 1898 * TWICE, adding the CGA_BUF offset again -> poooff 1899 */ 1900 if (crtat != 0) 1901 return; 1902 /* 1903 * Crtat initialized to point to MONO buffer, if not present change 1904 * to CGA_BUF offset. ONLY ADD the difference since locore.s adds 1905 * in the remapped offset at the right time 1906 */ 1907 was = *cp; 1908 *cp = (u_short) 0xA55A; 1909 if (*cp != 0xA55A) { 1910 crtc_addr = MONO_BASE; 1911 } else { 1912 *cp = was; 1913 crtc_addr = COLOR_BASE; 1914 Crtat = Crtat + (CGA_BUF-MONO_BUF)/sizeof(u_short); 1915 } 1916 1917 /* Extract cursor location */ 1918 outb(crtc_addr,14); 1919 cursorat = inb(crtc_addr+1)<<8 ; 1920 outb(crtc_addr,15); 1921 cursorat |= inb(crtc_addr+1); 1922 crtat = Crtat + cursorat; 1923 1924 /* is this a VGA or higher ? */ 1925 outb(crtc_addr, 7); 1926 if (inb(crtc_addr) == 7) 1927 crtc_vga = 1; 1928 1929 current_default = &user_default; 1930 console[0].crtat = crtat; 1931 console[0].crt_base = Crtat; 1932 console[0].term.esc = 0; 1933 console[0].term.std_attr = current_default->std_attr; 1934 console[0].term.rev_attr = current_default->rev_attr; 1935 console[0].term.attr = current_default->std_attr; 1936 console[0].posx = cursorat % COL; 1937 console[0].posy = cursorat / COL; 1938 console[0].border = BG_BLACK;; 1939 console[0].max_posx = COL; 1940 console[0].max_posy = ROW; 1941 console[0].status = 0; 1942 console[0].pid = 0; 1943 console[0].proc = NULL; 1944 console[0].smode.mode = VT_AUTO; 1945 console[0].bell_pitch = BELL_PITCH; 1946 console[0].bell_duration = BELL_DURATION; 1947 kernel_console.esc = 0; 1948 kernel_console.std_attr = kernel_default.std_attr; 1949 kernel_console.rev_attr = kernel_default.rev_attr; 1950 kernel_console.attr = kernel_default.std_attr; 1951 /* initialize mapscrn array to */ 1952 for (i=0; i<sizeof(scr_map); i++) 1953 scr_map[i] = i; 1954 clear_screen(&console[0]); 1955} 1956 1957 1958static void sput(u_char c) 1959{ 1960 scr_stat *scp = &console[0]; 1961 term_stat save; 1962 1963 if (crtat == 0) 1964 scinit(); 1965 save = scp->term; 1966 scp->term = kernel_console; 1967 current_default = &kernel_default; 1968 ansi_put(scp, c); 1969 kernel_console = scp->term; 1970 current_default = &user_default; 1971 scp->term = save; 1972} 1973 1974 1975static u_char *get_fstr(u_int c, u_int *len) 1976{ 1977 u_int i; 1978 1979 if (!(c & FKEY)) 1980 return(NULL); 1981 i = (c & 0xFF) - F_FN; 1982 if (i > n_fkey_tab) 1983 return(NULL); 1984 *len = fkey_tab[i].len; 1985 return(fkey_tab[i].str); 1986} 1987 1988 1989static update_leds(int which) 1990{ 1991 u_char xlate_leds[8] = { 0, 4, 2, 6, 1, 5, 3, 7 }; 1992 1993 kbd_cmd(KB_SETLEDS); /* LED Command */ 1994 kbd_cmd(xlate_leds[which & LED_MASK]); 1995 kbd_wait(); 1996} 1997 1998 1999static volatile void reset_cpu(void) 2000{ 2001 while (1) { 2002 kbd_cmd(KB_RESET_CPU); /* Reset Command */ 2003 DELAY(4000000); 2004 kbd_cmd(KB_RESET); /* Keyboard Reset Command */ 2005 } 2006} 2007 2008 2009/* 2010 * sgetc(noblock) : get a character from the keyboard. 2011 * If noblock = 0 wait until a key is gotten. Otherwise return NOKEY. 2012 */ 2013u_int sgetc(int noblock) 2014{ 2015 u_char val, code, release; 2016 u_int state, action; 2017 struct key_t *key; 2018 static u_char esc_flag = 0, compose = 0; 2019 static u_int chr = 0; 2020 2021next_code: 2022 kbd_wait(); 2023 /* First see if there is something in the keyboard port */ 2024 if (inb(KB_STAT) & KB_BUF_FULL) 2025 val = inb(KB_DATA); 2026 else if (noblock) 2027 return(NOKEY); 2028 else 2029 goto next_code; 2030 2031 if (cur_console->status & KBD_RAW_MODE) 2032 return val; 2033 2034 code = val & 0x7F; 2035 release = val & 0x80; 2036 2037 switch (esc_flag) { 2038 case 0x00: /* normal scancode */ 2039 switch(code) { 2040 case 0x38: /* left alt (compose key) */ 2041 if (release && compose) { 2042 compose = 0; 2043 if (chr > 255) { 2044 sysbeep(BELL_PITCH, BELL_DURATION); 2045 chr = 0; 2046 } 2047 } 2048 else { 2049 if (!compose) { 2050 compose = 1; 2051 chr = 0; 2052 } 2053 } 2054 break; 2055 case 0x60: 2056 case 0x61: 2057 esc_flag = code; 2058 goto next_code; 2059 } 2060 break; 2061 case 0x60: /* 0xE0 prefix */ 2062 esc_flag = 0; 2063 switch (code) { 2064 case 0x1c: /* right enter key */ 2065 code = 0x59; 2066 break; 2067 case 0x1d: /* right ctrl key */ 2068 code = 0x5a; 2069 break; 2070 case 0x35: /* keypad divide key */ 2071 code = 0x5b; 2072 break; 2073 case 0x37: /* print scrn key */ 2074 code = 0x5c; 2075 break; 2076 case 0x38: /* right alt key (alt gr) */ 2077 code = 0x5d; 2078 break; 2079 case 0x47: /* grey home key */ 2080 code = 0x5e; 2081 break; 2082 case 0x48: /* grey up arrow key */ 2083 code = 0x5f; 2084 break; 2085 case 0x49: /* grey page up key */ 2086 code = 0x60; 2087 break; 2088 case 0x4b: /* grey left arrow key */ 2089 code = 0x61; 2090 break; 2091 case 0x4d: /* grey right arrow key */ 2092 code = 0x62; 2093 break; 2094 case 0x4f: /* grey end key */ 2095 code = 0x63; 2096 break; 2097 case 0x50: /* grey down arrow key */ 2098 code = 0x64; 2099 break; 2100 case 0x51: /* grey page down key */ 2101 code = 0x65; 2102 break; 2103 case 0x52: /* grey insert key */ 2104 code = 0x66; 2105 break; 2106 case 0x53: /* grey delete key */ 2107 code = 0x67; 2108 break; 2109 default: /* ignore everything else */ 2110 goto next_code; 2111 } 2112 break; 2113 case 0x61: /* 0xE1 prefix */ 2114 esc_flag = 0; 2115 if (code == 0x1D) 2116 esc_flag = 0x1D; 2117 goto next_code; 2118 /* NOT REACHED */ 2119 case 0x1D: /* pause / break */ 2120 esc_flag = 0; 2121 if (code != 0x45) 2122 goto next_code; 2123 code = 0x68; 2124 break; 2125 } 2126 2127 if (compose) { 2128 switch (code) { 2129 case 0x47: 2130 case 0x48: /* keypad 7,8,9 */ 2131 case 0x49: 2132 if (!release) 2133 chr = (code - 0x40) + chr*10; 2134 goto next_code; 2135 case 0x4b: 2136 case 0x4c: /* keypad 4,5,6 */ 2137 case 0x4d: 2138 if (!release) 2139 chr = (code - 0x47) + chr*10; 2140 goto next_code; 2141 case 0x4f: 2142 case 0x50: /* keypad 1,2,3 */ 2143 case 0x51: 2144 if (!release) 2145 chr = (code - 0x4e) + chr*10; 2146 goto next_code; 2147 case 0x52: /* keypad 0 */ 2148 if (!release) 2149 chr *= 10; 2150 goto next_code; 2151 case 0x38: /* left alt key */ 2152 break; 2153 default: 2154 if (chr) { 2155 compose = chr = 0; 2156 sysbeep(BELL_PITCH, BELL_DURATION); 2157 goto next_code; 2158 } 2159 break; 2160 } 2161 } 2162 2163 state = (shfts ? 1 : 0 ) | (2 * (ctls ? 1 : 0)) | (4 * (alts ? 1 : 0)); 2164 if ((!agrs && (cur_console->status & ALKED)) 2165 || (agrs && !(cur_console->status & ALKED))) 2166 code += ALTGR_OFFSET; 2167 key = &key_map.key[code]; 2168 if ( ((key->flgs & FLAG_LOCK_C) && (cur_console->status & CLKED)) 2169 || ((key->flgs & FLAG_LOCK_N) && (cur_console->status & NLKED)) ) 2170 state ^= 1; 2171 2172 /* Check for make/break */ 2173 action = key->map[state]; 2174 if (release) { /* key released */ 2175 if (key->spcl & 0x80) { 2176 switch (action) { 2177 case LSH: 2178 shfts &= ~1; 2179 break; 2180 case RSH: 2181 shfts &= ~2; 2182 break; 2183 case LCTR: 2184 ctls &= ~1; 2185 break; 2186 case RCTR: 2187 ctls &= ~2; 2188 break; 2189 case LALT: 2190 alts &= ~1; 2191 break; 2192 case RALT: 2193 alts &= ~2; 2194 break; 2195 case NLK: 2196 nlkcnt = 0; 2197 break; 2198 case CLK: 2199 clkcnt = 0; 2200 break; 2201 case SLK: 2202 slkcnt = 0; 2203 break; 2204 case ASH: 2205 agrs = 0; 2206 break; 2207 case ALK: 2208 alkcnt = 0; 2209 break; 2210 case META: 2211 metas = 0; 2212 break; 2213 } 2214 } 2215 if (chr && !compose) { 2216 action = chr; 2217 chr = 0; 2218 return (action); 2219 } 2220 } else { 2221 /* key pressed */ 2222 if (key->spcl & (0x80>>state)) { 2223 switch (action) { 2224 /* LOCKING KEYS */ 2225 case NLK: 2226 if (!nlkcnt) { 2227 nlkcnt++; 2228 if (cur_console->status & NLKED) 2229 cur_console->status &= ~NLKED; 2230 else 2231 cur_console->status |= NLKED; 2232 update_leds(cur_console->status & LED_MASK); 2233 } 2234 break; 2235 case CLK: 2236 if (!clkcnt) { 2237 clkcnt++; 2238 if (cur_console->status & CLKED) 2239 cur_console->status &= ~CLKED; 2240 else 2241 cur_console->status |= CLKED; 2242 update_leds(cur_console->status & LED_MASK); 2243 } 2244 break; 2245 case SLK: 2246 if (!slkcnt) { 2247 slkcnt++; 2248 if (cur_console->status & SLKED) { 2249 cur_console->status &= ~SLKED; 2250#if defined(NetBSD) 2251 pcstart(pc_tty[get_scr_num(cur_console)]); 2252#else 2253 pcstart(&pccons[get_scr_num(cur_console)]); 2254#endif 2255 } 2256 else 2257 cur_console->status |= SLKED; 2258 update_leds(cur_console->status & LED_MASK); 2259 } 2260 break; 2261 case ALK: 2262 if (!alkcnt) { 2263 alkcnt++; 2264 if (cur_console->status & ALKED) 2265 cur_console->status &= ~ALKED; 2266 else 2267 cur_console->status |= ALKED; 2268 } 2269 break; 2270 2271 /* NON-LOCKING KEYS */ 2272 case NOP: 2273 break; 2274 case RBT: 2275 cpu_reset(); 2276 break; 2277 case DBG: 2278#if DDB > 0 /* try to switch to console 0 */ 2279 if (cur_console->smode.mode == VT_AUTO && 2280 console[0].smode.mode == VT_AUTO) 2281 switch_scr(0); 2282 Debugger(); 2283 return(NOKEY); 2284#else 2285 printf("No debugger in kernel\n"); 2286#endif 2287 break; 2288 case LSH: 2289 shfts |= 1; 2290 break; 2291 case RSH: 2292 shfts |= 2; 2293 break; 2294 case LCTR: 2295 ctls |= 1; 2296 break; 2297 case RCTR: 2298 ctls |= 2; 2299 break; 2300 case LALT: 2301 alts |= 1; 2302 break; 2303 case RALT: 2304 alts |= 2; 2305 break; 2306 case ASH: 2307 agrs = 1; 2308 break; 2309 case META: 2310 metas = 1; 2311 break; 2312 case NEXT: 2313 switch_scr((get_scr_num(cur_console)+1)%NCONS); 2314 break; 2315 default: 2316 if (action >= F_SCR && action <= L_SCR) { 2317 switch_scr(action - F_SCR); 2318 break; 2319 } 2320 if (action >= F_FN && action <= L_FN) 2321 action |= FKEY; 2322 return(action); 2323 } 2324 } 2325 else { 2326 if (metas) 2327 action |= MKEY; 2328 return(action); 2329 } 2330 } 2331 goto next_code; 2332} 2333 2334 2335int getchar(void) 2336{ 2337 char thechar; 2338 int s; 2339 2340 polling = 1; 2341 s = splhigh(); 2342 sput('>'); 2343 thechar = (char) sgetc(0); 2344 polling = 0; 2345 splx(s); 2346 switch (thechar) { 2347 default: 2348 if (thechar >= scr_map[0x20]) 2349 sput(thechar); 2350 return(thechar); 2351 case cr: 2352 case lf: 2353 sput(cr); sput(lf); 2354 return(lf); 2355 case bs: 2356 case del: 2357 sput(bs); sput(scr_map[0x20]); sput(bs); 2358 return(thechar); 2359 case cntld: 2360 sput('^'); sput('D'); sput('\r'); sput('\n'); 2361 return(0); 2362 } 2363} 2364 2365 2366int pcmmap(dev_t dev, int offset, int nprot) 2367{ 2368 if (offset > 0x20000) 2369 return EINVAL; 2370 return i386_btop((VIDEOMEM + offset)); 2371} 2372 2373 2374static void kbd_wait(void) 2375{ 2376 int i; 2377 for (i=0; i<10000; i++) 2378 if ((inb(KB_STAT) & KB_READY) == 0) 2379 break; 2380} 2381 2382 2383static void kbd_cmd(u_char command) 2384{ 2385 kbd_wait(); 2386 outb(KB_DATA, command); 2387} 2388 2389 2390static void set_mode(scr_stat *scp) 2391{ 2392 u_char byte; 2393 int s; 2394 2395 if (scp != cur_console) 2396 return; 2397 2398 /* (re)activate cursor */ 2399 untimeout((timeout_t)cursor_pos, 0); 2400 cursor_pos(); 2401 2402 /* change cursor type if set */ 2403 if (scp->cursor_start != -1 && scp->cursor_end != -1) 2404 cursor_shape(scp->cursor_start, scp->cursor_end); 2405 2406 /* mode change only on VGA's */ 2407 if (!crtc_vga) 2408 return; 2409 2410 /* setup video hardware for the given mode */ 2411 s = splhigh(); 2412 switch(scp->mode) { 2413 case TEXT80x25: 2414 outb(crtc_addr, 9); byte = inb(crtc_addr+1); 2415 outb(crtc_addr, 9); outb(crtc_addr+1, byte | 0x0F); 2416 outb(TSIDX, 0x03); outb(TSREG, 0x00); /* select font 0 */ 2417 break; 2418 case TEXT80x50: 2419 outb(crtc_addr, 9); byte = inb(crtc_addr+1); 2420 outb(crtc_addr, 9); outb(crtc_addr+1, (byte & 0xF0) | 0x07); 2421 outb(TSIDX, 0x03); outb(TSREG, 0x05); /* select font 1 */ 2422 break; 2423 default: 2424 break; 2425 } 2426 splx(s); 2427 2428 /* set border color for this (virtual) console */ 2429 set_border(scp->border); 2430 return; 2431} 2432 2433 2434static void set_border(int color) 2435{ 2436 inb(crtc_addr+6); /* reset flip-flop */ 2437 outb(ATC, 0x11); outb(ATC, color); 2438 inb(crtc_addr+6); /* reset flip-flop */ 2439 outb(ATC, 0x20); /* enable Palette */ 2440} 2441 2442static load_font(int segment, int size, char* font) 2443{ 2444 int ch, line, s; 2445 u_char val; 2446 2447 outb(TSIDX, 0x01); val = inb(TSREG); /* blank screen */ 2448 outb(TSIDX, 0x01); outb(TSREG, val | 0x20); 2449 2450 /* setup vga for loading fonts (graphics plane mode) */ 2451 s = splhigh(); 2452 inb(crtc_addr+6); /* reset flip/flop */ 2453 outb(ATC, 0x30); outb(ATC, 0x01); 2454 outb(TSIDX, 0x02); outb(TSREG, 0x04); 2455 outb(TSIDX, 0x04); outb(TSREG, 0x06); 2456 outb(GDCIDX, 0x04); outb(GDCREG, 0x02); 2457 outb(GDCIDX, 0x05); outb(GDCREG, 0x00); 2458 outb(GDCIDX, 0x06); outb(GDCREG, 0x05); /* addr = a0000, 64kb */ 2459 splx(s); 2460 for (ch=0; ch < 256; ch++) 2461 for (line=0; line < size; line++) 2462 *((char *)atdevbase+(segment*0x4000)+(ch*32)+line) = 2463 font[(ch*size)+line]; 2464 /* setup vga for text mode again */ 2465 s = splhigh(); 2466 inb(crtc_addr+6); /* reset flip/flop */ 2467 outb(ATC, 0x30); outb(ATC, 0x0C); 2468 outb(TSIDX, 0x02); outb(TSREG, 0x03); 2469 outb(TSIDX, 0x04); outb(TSREG, 0x02); 2470 outb(GDCIDX, 0x04); outb(GDCREG, 0x00); 2471 outb(GDCIDX, 0x05); outb(GDCREG, 0x10); 2472 if (crtc_addr == MONO_BASE) { 2473 outb(GDCIDX, 0x06); outb(GDCREG, 0x0A); /* addr = b0000, 32kb */ 2474 } 2475 else { 2476 outb(GDCIDX, 0x06); outb(GDCREG, 0x0E); /* addr = b8000, 32kb */ 2477 } 2478 splx(s); 2479 outb(TSIDX, 0x01); val = inb(TSREG); /* unblank screen */ 2480 outb(TSIDX, 0x01); outb(TSREG, val & 0xDF); 2481} 2482 2483 2484static void load_palette(void) 2485{ 2486 int i; 2487 2488 outb(PIXMASK, 0xFF); /* no pixelmask */ 2489 outb(PALWADR, 0x00); 2490 for (i=0x00; i<0x300; i++) 2491 outb(PALDATA, palette[i]); 2492 inb(crtc_addr+6); /* reset flip/flop */ 2493 outb(ATC, 0x20); /* enable palette */ 2494} 2495 2496static void save_palette(void) 2497{ 2498 int i; 2499 2500 outb(PALRADR, 0x00); 2501 for (i=0x00; i<0x300; i++) 2502 palette[i] = inb(PALDATA); 2503 inb(crtc_addr+6); /* reset flip/flop */ 2504} 2505 2506 2507static change_winsize(struct tty *tp, int x, int y) 2508{ 2509 if (tp->t_winsize.ws_col != x || tp->t_winsize.ws_row != y) { 2510 tp->t_winsize.ws_col = x; 2511 tp->t_winsize.ws_row = y; 2512 pgsignal(tp->t_pgrp, SIGWINCH, 1); 2513 } 2514} 2515 2516#endif /* NSC */ 2517