| 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 | * Many improvements based on this source are made by Holger Veit. |
| 8 | * |
| 9 | * Redistribution and use in source and binary forms, with or without |
| 10 | * modification, are permitted provided that the following conditions |
| 11 | * are met: |
| 12 | * 1. Redistributions of source code must retain the above copyright |
| 13 | * notice, this list of conditions and the following disclaimer. |
| 14 | * 2. Redistributions in binary form must reproduce the above copyright |
| 15 | * notice, this list of conditions and the following disclaimer in the |
| 16 | * documentation and/or other materials provided with the distribution. |
| 17 | * 3. All advertising materials mentioning features or use of this software |
| 18 | * must display the following acknowledgement: |
| 19 | * This product includes software developed by the University of |
| 20 | * California, Berkeley and its contributors. |
| 21 | * 4. Neither the name of the University nor the names of its contributors |
| 22 | * may be used to endorse or promote products derived from this software |
| 23 | * without specific prior written permission. |
| 24 | * |
| 25 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
| 26 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
| 29 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 30 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| 31 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 32 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| 33 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| 34 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 35 | * SUCH DAMAGE. |
| 36 | * |
| 37 | * @(#) $RCSfile: co_vga.c,v $ $Revision: 1.11 $ (Berkeley) $Date: 93/01/23 23:14:55 $ |
| 38 | */ |
| 39 | static char rcsid[] = "$Header: /usr/src/sys.386bsd/i386/isa/codrv/RCS/co_vga.c,v 1.11 93/01/23 23:14:55 root Exp Locker: root $"; |
| 40 | |
| 41 | /* |
| 42 | * History: see CO_HISTORY |
| 43 | */ |
| 44 | |
| 45 | #include "co.h" |
| 46 | #include "pc.h" |
| 47 | #if NCO == 1 |
| 48 | #if NPC == 0 |
| 49 | |
| 50 | #include "co_hdr.h" |
| 51 | |
| 52 | static char isinitialized = 0; /* =1: console/vtys initialized */ |
| 53 | u_short *Crtat = (u_short *)MONO_BUF; /* The only absolute location that is |
| 54 | * known from video memory, everything |
| 55 | * else derived from it, |
| 56 | * modified by device probe */ |
| 57 | static int scrblanksave; /* save position cursor */ |
| 58 | static u_short *scrbuf = 0; /* buffer for screen saver */ |
| 59 | static char *card2name(int id); |
| 60 | |
| 61 | /* find video config */ |
| 62 | static void probe_video() |
| 63 | { |
| 64 | vga_whoami(); |
| 65 | if (vds.color) { |
| 66 | Crtat += (CGA_BUF-MONO_BUF)/CHR; |
| 67 | vds.iobase = 0x3D0; /* color */ |
| 68 | } else |
| 69 | vds.iobase = 0x3B0; /* mono */ |
| 70 | |
| 71 | vds.encoding[0] = XLAT2PC8; |
| 72 | vds.encoding[1] = NOFONT; |
| 73 | vds.f89bit = vds.cardtype >= VG_EGA ? 9 : 8; |
| 74 | } |
| 75 | |
| 76 | int coattach(struct isa_device *dev) |
| 77 | { |
| 78 | struct cursorshape cs; |
| 79 | struct kbd_hotkey spec; |
| 80 | int i; |
| 81 | |
| 82 | /* re-initialize ALL vtys */ |
| 83 | vty_init(0); |
| 84 | |
| 85 | /* initialize the ioctl subsystem */ |
| 86 | coioctl_init(); |
| 87 | |
| 88 | printf(" %s", card2name(vds.cardtype)); |
| 89 | if (vds.cardsubtype>=0) |
| 90 | printf("/0x%02x", vds.cardsubtype); |
| 91 | |
| 92 | printf(" ram %dk io 0x%x kbd 0x%x", vds.ram, vds.iobase, kbs.id); |
| 93 | |
| 94 | if (nvty>1) printf(" vtys %d",nvty); |
| 95 | |
| 96 | /* create a save buffer for screen saver */ |
| 97 | if (!scrbuf) /* XXX modify with different screen sizes */ |
| 98 | scrbuf = (u_short*)malloc(vtys[0].size*CHR, M_TEMP, M_NOWAIT); |
| 99 | if (!scrbuf) |
| 100 | panic("coattach: no screen buffer"); |
| 101 | |
| 102 | #ifdef FAT_CURSOR |
| 103 | cs.start = 0; |
| 104 | cs.end = 18; |
| 105 | vga_setcshape(&cs); |
| 106 | #endif FAT_CURSOR |
| 107 | |
| 108 | vds.blanking = 0; |
| 109 | vds.scrtimeout = BLANKTIMEOUT; |
| 110 | vga_doblanking(BLANKSTART); |
| 111 | vga_cursor(0); |
| 112 | |
| 113 | /* define the basic special function keys |
| 114 | * CTRL-ALT-DEL (Reset) |
| 115 | * CTRL-ALT-ESC (Debugger) |
| 116 | * CTRL-ALT-F1 (VTY-1) |
| 117 | * CTRL-ALT-F2 (VTY-2) |
| 118 | * CTRL-ALT-F3 (VTY-3) |
| 119 | * CTRL-ALT-F4 (VTY-4) |
| 120 | * CTRL-ALT-F5 (VTY-5) |
| 121 | * CTRL-ALT-F6 (VTY-6) |
| 122 | * CTRL-ALT-F7 (VTY-7) |
| 123 | * CTRL-ALT-F8 (VTY-8) |
| 124 | * CTRL-ALT-F9 (VTY-9) |
| 125 | * CTRL-ALT-F10 (VTY-10) |
| 126 | * CTRL-ALT-F11 (VTY-11) |
| 127 | * CTRL-ALT-F12 (VTY-12) |
| 128 | */ |
| 129 | spec.key = 104; /*DEL*/ |
| 130 | spec.modifier = KBD_EXT_CA; /*CTRL-ALT*/ |
| 131 | spec.function = KBD_RESETKEY; |
| 132 | kbd_sethotkey(&spec); |
| 133 | #if NDDB > 0 |
| 134 | spec.key = 110; /*ESC*/ |
| 135 | spec.function = KBD_DEBUGKEY; |
| 136 | kbd_sethotkey(&spec); |
| 137 | #endif |
| 138 | for (i=0; i<12; i++) { |
| 139 | spec.key = 112+i; |
| 140 | spec.function = i; |
| 141 | kbd_sethotkey(&spec); |
| 142 | } |
| 143 | } |
| 144 | |
| 145 | /* |
| 146 | * vga_cursor(): |
| 147 | * reassigns cursor position, updated by the rescheduling clock |
| 148 | * which is a index (0-1999) into the text area. Note that the |
| 149 | * cursor is a "foreground" character, it's color determined by |
| 150 | * the fg_at attribute. Thus if fg_at is left as 0, (FG_BLACK), |
| 151 | * as when a portion of screen memory is 0, the cursor may dissappear. |
| 152 | */ |
| 153 | void vga_setcursorpos(int pos) |
| 154 | { |
| 155 | outb(vds.iobase+4, M6845_CURSORH); |
| 156 | outb(vds.iobase+5, pos>> 8); |
| 157 | outb(vds.iobase+4, M6845_CURSORL); |
| 158 | outb(vds.iobase+5, pos); |
| 159 | } |
| 160 | |
| 161 | void vga_cursor(int a) |
| 162 | { |
| 163 | vga_setcursorpos(actvty->crtat-actvty->Crtat); |
| 164 | |
| 165 | if (a == 0 && actvty->visible == 1) |
| 166 | timeout(vga_cursor, 0, hz/10); |
| 167 | } |
| 168 | |
| 169 | #ifndef MINITERM |
| 170 | /* Screen saver function: |
| 171 | * XXX to be changed for graphics console |
| 172 | * |
| 173 | * if screenblanking is enabled, the display is switched off after delay |
| 174 | * given in scrtimeout (in sec.) |
| 175 | * Any key hit restarts display again and restarts the timer. |
| 176 | * scrtimeout = 0 disables blanking. |
| 177 | * Also, blanking is suspended if console_x_mode is active, because it |
| 178 | * is supposed that X11 has its own facilities to turn off display. |
| 179 | */ |
| 180 | static struct cursorshape playsave = { -1,-1 }; |
| 181 | |
| 182 | #if SCRSAVER == 1 |
| 183 | /*ARGSUSED*/ |
| 184 | static void display_off(int arg,int ctime) |
| 185 | { |
| 186 | static int play1,play2,play3,play4; |
| 187 | int dir[] = { -79,-81,79,81 }; |
| 188 | register s; |
| 189 | int size = actvty->size; |
| 190 | |
| 191 | if (!actvty->visible) return; /* no show on invisible screen */ |
| 192 | |
| 193 | if (vds.blanking==1) { |
| 194 | |
| 195 | /* This idea was in parts borrowed from Linux, since I |
| 196 | * was too lazy to play around with the video registers |
| 197 | * (although there are suited bits to switch) |
| 198 | * screenplay originally by me (holgi) |
| 199 | */ |
| 200 | bcopy(actvty->Crtat,scrbuf,size*CHR); |
| 201 | fillw(0x0820,actvty->Crtat, actvty->size); |
| 202 | scrblanksave = actvty->crtat-actvty->Crtat; |
| 203 | vds.blanking = 2; |
| 204 | play1 = actvty->crtat-actvty->Crtat; |
| 205 | play2 = time.tv_sec; |
| 206 | play3 = 7; |
| 207 | play4 = 1; |
| 208 | untimeout(vga_cursor, 0); |
| 209 | } |
| 210 | |
| 211 | /* some animation */ |
| 212 | s = spltty(); |
| 213 | vga_setcursorpos(play1); |
| 214 | if (!play3) { |
| 215 | play2 = (play2 % 1237) + 997; |
| 216 | play3 = 4 + (play2 % 9); |
| 217 | if (((play2>>3)&3)==play4) |
| 218 | play4=(play4+1)%4; |
| 219 | else |
| 220 | play4=(play2>>3)&3; |
| 221 | } else play3--; |
| 222 | play1 += dir[play4]; |
| 223 | if (play1<0) play1 += size; |
| 224 | else if (play1 >= size) play1 -= size; |
| 225 | timeout(display_off,0,hz/4); |
| 226 | splx(s); |
| 227 | } |
| 228 | |
| 229 | #else |
| 230 | #if SCRSAVER == 2 /* moving snake by Chr. Robitschko */ |
| 231 | |
| 232 | /* XXX This code could be merged with the standard saver, because there are |
| 233 | not many modifications, but I need things to do for the next version */ |
| 234 | |
| 235 | static void display_off(int arg,int ctime) |
| 236 | { |
| 237 | int dir[] = { -79,-81,79,81 }; |
| 238 | register s, f; |
| 239 | #ifdef NETBSD |
| 240 | const char snake[] = { "NetBSD" }; |
| 241 | #else |
| 242 | const char snake[] = { "386BSD" }; |
| 243 | #endif |
| 244 | const int snlen = sizeof(snake) - 1; |
| 245 | static char *snpos[snlen]; |
| 246 | static int play1,play2,play3,play4; |
| 247 | struct cursorshape cs; |
| 248 | |
| 249 | int size = actvty->size; |
| 250 | |
| 251 | if (!actvty->visible) return; /* no show on invisible screen */ |
| 252 | |
| 253 | if (vds.blanking==1) { |
| 254 | |
| 255 | /* disable cursor -hv- */ |
| 256 | vga_getcshape(&playsave); |
| 257 | cs.start = 31; |
| 258 | cs.end = 30; |
| 259 | vga_setcshape(&cs); |
| 260 | |
| 261 | bcopy(actvty->Crtat,scrbuf,size*CHR); |
| 262 | fillw(0x0820,actvty->Crtat, actvty->size); |
| 263 | scrblanksave = actvty->crtat-actvty->Crtat; |
| 264 | vds.blanking = 2; |
| 265 | play1 = actvty->crtat-actvty->Crtat; |
| 266 | play2 = time.tv_sec; |
| 267 | play3 = 7; |
| 268 | play4 = 1; |
| 269 | for (f=0; f<snlen; f++) |
| 270 | snpos[f] = (char *)0; |
| 271 | untimeout(vga_cursor, 0); |
| 272 | } |
| 273 | |
| 274 | /* some animation */ |
| 275 | s = spltty(); |
| 276 | if (snpos[snlen-1]) *snpos[snlen-1] = ' '; |
| 277 | for (f=snlen-1; f>0; f--) |
| 278 | snpos[f] = snpos[f-1]; |
| 279 | snpos[0] = (char *)(Crtat + play1); |
| 280 | for (f=snlen-1; f>=0; f--) |
| 281 | if (snpos[f]) *snpos[f] = snake[f]; |
| 282 | |
| 283 | if (!play3) { |
| 284 | play2 = (play2 % 1237) + 997; |
| 285 | play3 = 4 + (play2 % 9); |
| 286 | if (((play2>>3)&1)==play4%2) |
| 287 | play4=(play4+1)%4; |
| 288 | else |
| 289 | play4=(play2>>3)&3; |
| 290 | } else play3--; |
| 291 | play1 += dir[play4]; |
| 292 | if (play1<0) play1 += size; |
| 293 | else if (play1 >= size) play1 -= size; |
| 294 | timeout(display_off,0,hz/4); |
| 295 | splx(s); |
| 296 | } |
| 297 | |
| 298 | #else |
| 299 | ERROR! NEED SCRSAVER=1 OR 2 |
| 300 | #endif /* SCRSAVER=2 */ |
| 301 | #endif /* SCRSAVER=1 */ |
| 302 | |
| 303 | /* XXX graphics */ |
| 304 | static void display_on() |
| 305 | { |
| 306 | /* reload old content */ |
| 307 | if (vds.blanking==2) { |
| 308 | bcopy(scrbuf,actvty->Crtat,actvty->size*CHR); |
| 309 | if (playsave.start != -1) vga_setcshape(&playsave); |
| 310 | vga_setcursorpos(scrblanksave); |
| 311 | vga_cursor(0); |
| 312 | } |
| 313 | } |
| 314 | |
| 315 | /* XXX graphics */ |
| 316 | void vga_doblanking(int fct) |
| 317 | { |
| 318 | /* restore display, just in case */ |
| 319 | display_on(); |
| 320 | |
| 321 | /* timer was started, stop */ |
| 322 | if (vds.blanking<3) |
| 323 | untimeout(display_off,0); |
| 324 | |
| 325 | vds.blanking = 0; |
| 326 | |
| 327 | if (fct==BLANKSTART) { |
| 328 | if (vds.scrtimeout) { |
| 329 | /* start it */ |
| 330 | timeout(display_off,0,vds.scrtimeout*hz); |
| 331 | vds.blanking = 1; |
| 332 | } |
| 333 | } |
| 334 | /*else if(fct==BLANKSTOP) vds.blanking = 0;*/ |
| 335 | } |
| 336 | |
| 337 | #else /* MINITERM */ |
| 338 | /*ARGSUSED*/ |
| 339 | static void display_off(int arg,int ctime) {} |
| 340 | static void display_on() {} |
| 341 | void vga_doblanking(int fct) {} |
| 342 | #endif |
| 343 | |
| 344 | /* normally called by init_main to do local initialisation */ |
| 345 | /* called by sput, if anyone is faster than init_main, e.g. ddb */ |
| 346 | void consinit () |
| 347 | { |
| 348 | if (isinitialized == 0) |
| 349 | { |
| 350 | /* find out video card */ |
| 351 | probe_video(); |
| 352 | |
| 353 | /* initialize video device */ |
| 354 | emul_initvideo(); |
| 355 | |
| 356 | /* disable screensaver */ |
| 357 | vds.blanking = 3; |
| 358 | |
| 359 | /* initialize a single terminal */ |
| 360 | vty_init(1); |
| 361 | |
| 362 | isinitialized = 1; |
| 363 | |
| 364 | /* NetBSD would like to have this, |
| 365 | * and for 386bsd it doesn't make problems */ |
| 366 | cons_normal(); |
| 367 | } |
| 368 | } |
| 369 | |
| 370 | /* |
| 371 | * sput calls vtemul_exec for terminal emulation |
| 372 | * if ka, use kernel attributes. |
| 373 | */ |
| 374 | void sput(int vtynum, XCHAR c, int ka) |
| 375 | { |
| 376 | register struct vty *act; |
| 377 | |
| 378 | if (!isinitialized) |
| 379 | consinit(); |
| 380 | |
| 381 | /* necessary: turn on display again */ |
| 382 | if (vds.blanking==2) vga_doblanking(BLANKSTART); |
| 383 | |
| 384 | /* select vty */ |
| 385 | act = &vtys[vtynum]; |
| 386 | |
| 387 | /* select attribute set */ |
| 388 | act->op = ka ? &act->om[1] : &act->om[0]; |
| 389 | |
| 390 | /* process input */ |
| 391 | vtemul_exec(act, c); |
| 392 | |
| 393 | /* re-set cursor position */ |
| 394 | if (ka) vga_cursor(1); |
| 395 | } |
| 396 | |
| 397 | /* both routines used by init_main for more portability */ |
| 398 | void cons_highlight() |
| 399 | { |
| 400 | register struct vty *p = &vtys[0]; |
| 401 | |
| 402 | p->op = &p->om[1]; |
| 403 | emul_setattributes(p,3,15); |
| 404 | } |
| 405 | |
| 406 | void cons_normal() |
| 407 | { |
| 408 | register struct vty *p = &vtys[0]; |
| 409 | p->op = &p->om[1]; |
| 410 | emul_setattributes(p,0,0); |
| 411 | } |
| 412 | |
| 413 | /* |
| 414 | * vga_whoami: try to detect whether a SVGA is present |
| 415 | * see Ferraro, Programmer's guide to the EGA/VGA cards for more info |
| 416 | */ |
| 417 | /* |
| 418 | * Try to identify, which video card is in the system |
| 419 | */ |
| 420 | void vga_whoami() |
| 421 | { |
| 422 | register int iobase; |
| 423 | u_char *cp; |
| 424 | u_char *videobios; |
| 425 | u_short *vp; |
| 426 | u_short vsave; |
| 427 | volatile u_char lock,save1,save2,save3,save4; |
| 428 | |
| 429 | vds.color = 1; /* default */ |
| 430 | vds.cardtype = VG_UNKNOWN; |
| 431 | vds.cardsubtype = -1; |
| 432 | vds.ram = 64; |
| 433 | |
| 434 | /* first look whether there is RAM in the COLOR region, if this is |
| 435 | * a mono card, there is none |
| 436 | */ |
| 437 | vp = Crtat + (CGA_BUF-MONO_BUF)/CHR; |
| 438 | vsave = *vp; |
| 439 | *vp = 0xCC33; |
| 440 | DELAY(100); /* wait 100 us, doesn't help if you buffer your isa |
| 441 | * bus lines with large capacitors :-) |
| 442 | */ |
| 443 | if (*vp == 0xCC33) goto not_a_mono; |
| 444 | else { |
| 445 | /* we are paranoid */ |
| 446 | *vp = 0xA55A; |
| 447 | DELAY(100); |
| 448 | if (*vp == 0xA55A) goto not_a_mono; |
| 449 | } |
| 450 | |
| 451 | /* oh, that poor owner has only a MDA/Hercules card :-) */ |
| 452 | *vp = vsave; |
| 453 | vds.ram = 16; |
| 454 | vds.color = 0; |
| 455 | vds.cardtype = VG_MONO; |
| 456 | return; |
| 457 | |
| 458 | not_a_mono: |
| 459 | *vp = vsave; |
| 460 | |
| 461 | /* there is RAM in the ???B8000 region, look which color card we have |
| 462 | * Hmmm... the ancient CGA was supported by the ROMBIOS, and had no ROM |
| 463 | * on board, but the EGA's and VGA's have |
| 464 | */ |
| 465 | videobios = cp = (u_char*)Crtat + (EGA_BIOS-MONO_BUF); |
| 466 | |
| 467 | /* Some machines map video BIOS to e0000 instead of c0000. |
| 468 | * Check it now. |
| 469 | */ |
| 470 | if (*cp != 0x55 || *(cp+1) != 0xAA) |
| 471 | videobios = cp = (u_char*)Crtat + (ALTEGA_BIOS-MONO_BUF); |
| 472 | |
| 473 | if (*cp != 0x55 || *(cp+1) != 0xAA) { |
| 474 | /* There is no ROM ID. |
| 475 | * you do not plan to run X11 with this card, do you? |
| 476 | */ |
| 477 | vds.ram = 16; |
| 478 | vds.cardtype = VG_CGA; |
| 479 | return; |
| 480 | } |
| 481 | |
| 482 | /* this is an EGA or a VGA or a SVGA or something else quite strange |
| 483 | * so lets look whether this is a VGA. We know that several EGA |
| 484 | * registers are readonly, which is really a design fault. |
| 485 | * so just look, whether we can write and read something into |
| 486 | * such a register: this will hold for the CRT address register at |
| 487 | * iobase+4 and the graphics control address |
| 488 | */ |
| 489 | |
| 490 | if (inb(0x3cc) & 1) { |
| 491 | iobase = vds.iobase = 0x3D0; |
| 492 | } else |
| 493 | { |
| 494 | iobase = vds.iobase = 0x3B0; |
| 495 | vds.color = 0; |
| 496 | } |
| 497 | |
| 498 | outb(iobase+4, 7); |
| 499 | DELAY(100); |
| 500 | if (inb(iobase+4) != 7) vds.cardtype = VG_EGA; |
| 501 | else { |
| 502 | outb(0x3ce,2); |
| 503 | DELAY(100); |
| 504 | if (inb(0x3ce) != 2) vds.cardtype = VG_EGA; |
| 505 | } |
| 506 | if (vds.cardtype==VG_EGA) { |
| 507 | vds.ram = 64; /* for simplicity assume the worst */ |
| 508 | return; |
| 509 | } |
| 510 | |
| 511 | /* There is a problem now: 8514/A adapters also have ROM, unfortunately |
| 512 | * I don't have sufficient information about the 8514/A and the XGA, |
| 513 | * so just don't try 386BSD with it ! |
| 514 | */ |
| 515 | |
| 516 | /* I don't know whether this already qualifies for a VGA, so |
| 517 | * someone may add some code here, but for now I am persuaded that I |
| 518 | * have a VGA at this point. This might be a SVGA, however, so let's |
| 519 | * look if this assumption is true. Hard stuff follows... |
| 520 | * refer to Ferraro: Programmer's Guide to the EGA and VGA Cards |
| 521 | * 2nd ed, Addison-Wesley, 1990 |
| 522 | */ |
| 523 | vds.cardtype = VG_VGA; |
| 524 | |
| 525 | /* unlock paradise registers */ |
| 526 | outb(iobase+4, 0x11); lock = inb(iobase+5); outb(iobase+5, lock & 0x7f); |
| 527 | |
| 528 | /* now check for a PVGA1 */ |
| 529 | cp = videobios + 0x007d; |
| 530 | if (*cp=='V' && *(cp+1)=='G' && *(cp+2)=='A' && *(cp+3)=='=') { |
| 531 | /* this is a paradise, now check which one */ |
| 532 | vds.cardtype = VG_PARADISE; |
| 533 | outw(0x3CE, 0x050F); |
| 534 | outw(iobase+4, 0x8529); |
| 535 | outb(iobase+4,0x2b); save1 = inb(iobase+5); |
| 536 | outb(iobase+5,0xaa); save2 = inb(iobase+5); |
| 537 | outb(iobase+5,save1); |
| 538 | if (save2 != 0xaa) { vds.cardsubtype = 0x01; goto foundp2; } |
| 539 | outb(0x3c4,0x12); save1 = inb(0x3c5); |
| 540 | outb(0x3c5,save1 & 0xbf); save2 = inb(0x3c5) & 0x40; |
| 541 | if (save2) { vds.cardsubtype = 0x01; goto foundp2; } |
| 542 | outb(0x3c5,save1 | 0x40); save2 = inb(0x3c5) & 0x40; |
| 543 | if (!save2) { vds.cardsubtype = 0x02; goto foundp; } |
| 544 | outb(0x3c5,save1); |
| 545 | save3 = 0; |
| 546 | outb(0x3c4,0x10); save1 = inb(0x3c5); |
| 547 | outb(0x3c5, save1 & 0xfb); save2 = inb(0x3c5) & 0x04; |
| 548 | if (save2) save3 = 1; |
| 549 | outb(0x3c5, save1 | 0x04); save2 = inb(0x3c5) & 0x04; |
| 550 | if (!save2) save3 = 1; |
| 551 | vds.cardsubtype = save3 ? 0x03 : 0x04; |
| 552 | foundp: outb(0x3c5,save1); |
| 553 | foundp2: if (vds.cardsubtype != -1) { |
| 554 | /* find ram */ |
| 555 | outb(0x3ce,0x0b); |
| 556 | switch(inb(0x3cf) & 0xc0) { |
| 557 | case 0x80: vds.ram = 512; break; |
| 558 | case 0xc0: vds.ram = 1024; break; |
| 559 | default: vds.ram = 256; |
| 560 | } |
| 561 | return; |
| 562 | } |
| 563 | } |
| 564 | |
| 565 | /* Strategy: The ET4000 uses the reg 3x5/33, the ET3000 uses the 3x5/23 |
| 566 | * uniquely, the WD paradises also use 3x5/33. So check for Paradise |
| 567 | * first, and if it's not, check for 3000/4000 with these registers |
| 568 | */ |
| 569 | /* Is this a TSENG? */ |
| 570 | outb(0x3bf, 3); |
| 571 | outb(iobase+8,0xa0); |
| 572 | |
| 573 | save1 = inb(iobase+0x0A); |
| 574 | outb(0x3C0, 0x20|0x16); save2 = inb(0x3C1); |
| 575 | outb(0x3C0, save2 ^ 0x10); |
| 576 | outb(0x3C0, 0x20|0x16); save3 = inb(0x3C1); |
| 577 | outb(0x3C0, save2); |
| 578 | if (save3 == (save2 ^ 0x10)) { |
| 579 | /* assume it is a Tseng, but which one */ |
| 580 | outb(iobase+4, 0x23); save2 = inb(iobase+5); |
| 581 | outb(iobase+5, save2 ^ 0x07); save3 = inb(iobase+5); |
| 582 | outb(iobase+5, save2); |
| 583 | if (save3 == (save2 ^ 0x07)) { |
| 584 | vds.ram = 512; |
| 585 | vds.cardtype = VG_ET3000; |
| 586 | } else |
| 587 | { |
| 588 | /* same experiment for reg 33 */ |
| 589 | outb(iobase+4, 0x33); save2 = inb(iobase+5); |
| 590 | outb(iobase+5, save2 ^ 0x0f); save3 = inb(iobase+5); |
| 591 | outb(iobase+5, save2); |
| 592 | if (save3 == (save2 ^ 0x0f)) { |
| 593 | vds.cardtype = VG_ET4000; |
| 594 | outb(iobase+4,0x37); |
| 595 | switch (inb(iobase+5) & 03) { |
| 596 | case 1: vds.ram = 256; break; |
| 597 | case 2: vds.ram = 512; break; |
| 598 | case 3: vds.ram = 1024; break; |
| 599 | } |
| 600 | } |
| 601 | } |
| 602 | } |
| 603 | /* cleanup for TSENG */ |
| 604 | outb(0x3bf, 1); |
| 605 | outb(iobase+8, 0xa0); |
| 606 | |
| 607 | if (vds.cardtype != VG_VGA) return; |
| 608 | |
| 609 | /* now look for the GENOAs */ |
| 610 | cp = videobios + 0x37; |
| 611 | cp += (u_char)*cp; /* at 0x37 is the offset to the real signature */ |
| 612 | if (*cp==0x77 && *(cp+2)==0x66 && *(cp+3)==0x99) { |
| 613 | /* this is a GENOA. Note that the GENOAs 5xxx are |
| 614 | * really TSENG ET3000, so they should have fallen |
| 615 | * through the sieve above already, if not, something's |
| 616 | * quite strange here, so I don't believe its a GENOA |
| 617 | */ |
| 618 | vds.cardtype = VG_GENOA; |
| 619 | vds.cardsubtype = *(cp+1); |
| 620 | switch (vds.cardsubtype) { |
| 621 | default: |
| 622 | case 0x33: /* shouldn't reach this */ |
| 623 | case 0x55: vds.cardtype = VG_VGA; return; |
| 624 | case 0x22: |
| 625 | case 0x00: vds.ram = 256; return; |
| 626 | case 0x11: vds.ram = 512; return; |
| 627 | } |
| 628 | /*NOTREACHED*/ |
| 629 | } |
| 630 | |
| 631 | /* |
| 632 | * Look for the Tridents |
| 633 | */ |
| 634 | outb(0x3c4, 0x0e); save1 = inb(0x3c5); |
| 635 | outb(0x3c5, 0); save2 = inb(0x3c5) & 0x0f; |
| 636 | outb(0x3c5, save1 ^ 0x02); |
| 637 | if (save2==0x02) { |
| 638 | /* is a Trident */ |
| 639 | vds.cardtype = VG_TVGA; |
| 640 | outb(0x3c4, 0x0b); |
| 641 | outb(0x3c5, 0); |
| 642 | save1 = inb(0x3c5); |
| 643 | /* restore "old mode", recommended by |
| 644 | * chmr@edvz.tu-graz.ac.at (Christoph Robitschko) |
| 645 | */ |
| 646 | outb(0x3c5, 0); |
| 647 | vds.cardsubtype = save1; |
| 648 | if (save1== 0xfd) /*TVGA 9000*/ |
| 649 | vds.ram = 1024; |
| 650 | else |
| 651 | vds.ram = 512; /* There is 3c4/1f, but I don't know the encoding */ |
| 652 | |
| 653 | return; |
| 654 | } |
| 655 | |
| 656 | /* for the moment X11 does not know any more chips, but |
| 657 | * I found some more in Ferraro's book |
| 658 | * |
| 659 | * Video 7 |
| 660 | */ |
| 661 | outw(0x3c4,0xea06); |
| 662 | outb(iobase+4,0x0c); save1 = inb(iobase+5); |
| 663 | outb(iobase+5,0x55); save2 = inb(iobase+5); |
| 664 | outb(iobase+4,0x1f); save3 = inb(iobase+5); |
| 665 | outb(iobase+4,0x0c); outb(iobase+5,save1); |
| 666 | if (save3 == (0x55^0xea)) { |
| 667 | /* this is a video 7 */ |
| 668 | vds.cardtype = VG_VIDEO7; |
| 669 | outb(0x3c4, 0x8e); |
| 670 | vds.cardsubtype = inb(0x3c5); |
| 671 | if (vds.cardsubtype > 0x40 && vds.cardsubtype < 0x4a) |
| 672 | vds.ram = 1024; /* 1024i */ |
| 673 | else |
| 674 | vds.ram = 512; |
| 675 | return; |
| 676 | } |
| 677 | |
| 678 | /* C&T Chips, I'm not sure about that, in particular the |
| 679 | * strange 46E8 port, I somewhere heard that I/O space is |
| 680 | * 0000-03FF only, but I don't know whether any chipset |
| 681 | * clips this range. Anyway... |
| 682 | */ |
| 683 | outb(0x46e8,0x1e); |
| 684 | if (inb(0x104)==0xa5) { |
| 685 | outb(0x103, 0x80); outb(0x46e8, 0x0e); |
| 686 | outb(0x3d6, 0); |
| 687 | vds.cardtype = VG_CHIPS; |
| 688 | vds.cardsubtype = inb(0x3d7) & 0xf0; |
| 689 | switch(vds.cardsubtype) { |
| 690 | case 0x10: |
| 691 | outb(0x3d6, 0x3a); save1=inb(0x3d7); |
| 692 | outb(0x3d7, 0xaa); save2=inb(0x3d7); |
| 693 | outb(0x3d7, save1); |
| 694 | if (save2==0xaa) { |
| 695 | vds.cardsubtype = 0x11; |
| 696 | vds.ram = 1024; |
| 697 | } else |
| 698 | vds.ram = 256; |
| 699 | break; |
| 700 | case 0x20: vds.ram = 256; break; |
| 701 | case 0x30: vds.ram = 1024; break; |
| 702 | case 0x50: vds.ram = 256; |
| 703 | } |
| 704 | outb(0x46e8, 0x1e); outb(0x103, 0); |
| 705 | } |
| 706 | outb(0x46e8, 0x0e); |
| 707 | |
| 708 | /* the two ATI's */ |
| 709 | cp = videobios + 0x0031; |
| 710 | if (!bcmp(cp,"761295520",9)) { |
| 711 | /* is an ATI, also unsure about the numbers */ |
| 712 | vds.cardtype = VG_ATI; |
| 713 | cp = videobios + 0x0042; |
| 714 | vds.cardsubtype = *cp | (*(cp+1)<<8); |
| 715 | vp = (u_short *) videobios + 0010; |
| 716 | vds._atiext = *vp; |
| 717 | outb(*vp,0xbb); save1 = inb((*vp)+1); |
| 718 | vds.ram = (save1 & 0x20) ? 512 : 256; |
| 719 | |
| 720 | return; |
| 721 | } |
| 722 | |
| 723 | /* I don't know more types, so assume |
| 724 | * it is a VGA (at least looks as if) |
| 725 | */ |
| 726 | vds.ram = 256; |
| 727 | vds.cardtype = VG_VGA; |
| 728 | return; |
| 729 | |
| 730 | } |
| 731 | |
| 732 | static char *card2name(int id) |
| 733 | { |
| 734 | static char *nametable[] = { |
| 735 | /* 0 */ "UNKNOWN", |
| 736 | /* 1 */ "MDA/Hercules", |
| 737 | /* 2 */ "CGA", |
| 738 | /* 3 */ "EGA", |
| 739 | /* 4 */ "VGA", |
| 740 | /* 5 */ "C&T", |
| 741 | /* 6 */ "Genoa VGA", |
| 742 | /* 7 */ "Paradise VGA", |
| 743 | /* 8 */ "Trident VGA", |
| 744 | /* 9 */ "Tseng ET3000", |
| 745 | /* 10 */ "Tseng ET4000", |
| 746 | /* 11 */ "Video7 VGA", |
| 747 | /* 12 */ "ATI VGA", |
| 748 | 0, |
| 749 | }; |
| 750 | |
| 751 | return nametable[id]; |
| 752 | } |
| 753 | |
| 754 | /* |
| 755 | * set cursor shape |
| 756 | */ |
| 757 | int vga_setcshape(struct cursorshape *data) |
| 758 | { |
| 759 | register s,e; |
| 760 | |
| 761 | s = data->start; |
| 762 | e = data->end; |
| 763 | |
| 764 | /* I don't do error correction here, the user should pass |
| 765 | * correct and checked data! Note: The registers allow 5 Bits == 31 |
| 766 | */ |
| 767 | if (s<0 || s>31 || e<0 || e>31) return EINVAL; |
| 768 | |
| 769 | /* the Tridents seem to have the feature to switch off |
| 770 | * cursor when start is 0 (not verified) |
| 771 | */ |
| 772 | if (vds.cardtype==VG_TVGA && s==0) s=1; |
| 773 | |
| 774 | outb(vds.iobase+4, M6845_CURSTART); |
| 775 | outb(vds.iobase+5, s); |
| 776 | outb(vds.iobase+4, M6845_CUREND); |
| 777 | outb(vds.iobase+5, e); |
| 778 | } |
| 779 | |
| 780 | #ifndef MINITERM |
| 781 | int vga_getcshape(struct cursorshape *data) |
| 782 | { |
| 783 | /* update from registers */ |
| 784 | outb(vds.iobase+4, M6845_CURSTART); |
| 785 | data->start = inb(vds.iobase+5) & 0x1F; |
| 786 | outb(vds.iobase+4, M6845_CUREND); |
| 787 | data->end = inb(vds.iobase+5) & 0x1F; |
| 788 | |
| 789 | return 0; |
| 790 | } |
| 791 | #endif |
| 792 | |
| 793 | int vga_getvideoinfo(struct videoinfo *data) |
| 794 | { |
| 795 | int i; |
| 796 | |
| 797 | bcopy(card2name(vds.cardtype),data->name,20); |
| 798 | data->type = vds.cardtype; |
| 799 | data->subtype = vds.cardsubtype; |
| 800 | data->ram = vds.ram; |
| 801 | data->iobase = vds.iobase; |
| 802 | return 0; |
| 803 | } |
| 804 | |
| 805 | static char modesave; |
| 806 | |
| 807 | void vga_enablecg() |
| 808 | { |
| 809 | register iobase = vds.iobase; |
| 810 | |
| 811 | while((inb(iobase+10)&0x08)==0); /* wait for vertical blanking */ |
| 812 | inb(iobase+10); |
| 813 | outb(0x3C0,0x30); modesave = inb(0x3C1); |
| 814 | inb(iobase+10); |
| 815 | outb(0x3C0,0x30); outb(0x3C0, 0x01); /* graphics mode */ |
| 816 | /* outw(0x3c4,0x0100);*/ /* hold sequencer synch reset */ |
| 817 | outw(0x3c4,0x0402); /* write enable map "page" */ |
| 818 | outw(0x3c4,0x0604); /* set sequential addressing */ |
| 819 | /* outw(0x3c4,0x0300);*/ /* release sequencer synch reset */ |
| 820 | outw(0x3ce,0x0204); /* select map "page" for cpu reading */ |
| 821 | outw(0x3ce,0x0005); /* RM=0,O/E=0,WM=00 */ |
| 822 | outw(0x3ce,0x0d06); /* map at "B8000" */ |
| 823 | } |
| 824 | |
| 825 | void vga_disablecg() |
| 826 | { |
| 827 | register iobase10 = vds.iobase+10; |
| 828 | char seq; |
| 829 | |
| 830 | inb(iobase10); |
| 831 | outb(0x3C0,0x30); outb(0x3C0, modesave); /* alpha mode */ |
| 832 | /* outw(0x3c4,0x0100);*/ /* hold sequencer synch reset */ |
| 833 | outw(0x3c4,0x0302); /* write enable text pages */ |
| 834 | outw(0x3c4,0x0304); /* set O/E addressing */ |
| 835 | /* outw(0x3c4,0x0300);*/ /* release sequencer synch reset */ |
| 836 | outw(0x3ce,0x0004); /* select map 0 for cpu reading */ |
| 837 | outw(0x3ce,0x1005); /* RM=0,O/E=0,WM=00 */ |
| 838 | outw(0x3ce,0x0e06); /* map at "B8000", Chain O/E */ |
| 839 | |
| 840 | /* set the 8/9 bit according to the state of vds.f89 |
| 841 | * The little problem is that with a EGA we have to guess |
| 842 | * the old value (but it is usually 0x03) |
| 843 | */ |
| 844 | if (vds.cardtype != VG_EGA) { |
| 845 | inb(iobase10); |
| 846 | outb(0x3c0,0x20|0x10); |
| 847 | seq = inb(0x3c1); |
| 848 | } |
| 849 | else |
| 850 | seq = 0x03; |
| 851 | inb(iobase10); |
| 852 | outb(0x3c0,0x20|0x10); |
| 853 | if (vds.f89bit == 9) outb(0x3c0, seq | 0x04); |
| 854 | else outb(0x3c0, seq & ~0x04); |
| 855 | |
| 856 | while(inb(iobase10)&0x08); /* wait for end of vertical blanking */ |
| 857 | } |
| 858 | |
| 859 | static u_char iso2pc8[] = { |
| 860 | /*A0*/ 0xff,0xad,0x9b,0x9c,0xfe,0x9d,0x7c,0x15, |
| 861 | /*A8*/ 0xfe,0xfe,0xa6,0xae,0xaa,0x2d,0xfe,0xfe, |
| 862 | /*B0*/ 0xf8,0xf1,0xfd,0xfe,0xfe,0xe6,0x14,0xf9, |
| 863 | /*B8*/ 0xfe,0xfe,0xa7,0xaf,0xac,0xfd,0xfe,0xa8, |
| 864 | /*C0*/ 0xfe,0xfe,0xfe,0xfe,0x8e,0x8f,0x92,0x80, |
| 865 | /*C8*/ 0xfe,0x90,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe, |
| 866 | /*D0*/ 0xfe,0xa5,0xfe,0xfe,0xfe,0xfe,0x99,0xfe, |
| 867 | /*D8*/ 0xfe,0xfe,0xfe,0xfe,0x9a,0xfe,0xfe,0xe1, |
| 868 | /*E0*/ 0x85,0xa0,0x83,0xfe,0x84,0x86,0x91,0x87, |
| 869 | /*E8*/ 0x8a,0x82,0x88,0x89,0x8d,0xa1,0x8c,0x8b, |
| 870 | /*F0*/ 0xfe,0xa4,0x95,0xa2,0x93,0xfe,0x94,0xf6, |
| 871 | /*F8*/ 0xfe,0x97,0xa3,0x96,0x81,0xfe,0xfe,0x98 |
| 872 | }; |
| 873 | |
| 874 | /* needs attribute byte to select font */ |
| 875 | int vga_xlatiso646(struct vty *vp,u_short *at,u_short *sat,int c) |
| 876 | { |
| 877 | int f2flag = vp->op->f2; |
| 878 | |
| 879 | if (vds.encoding[1] != NOFONT) { /* second font loaded? */ |
| 880 | if (f2flag) { |
| 881 | *at |= 0x08; /* select font 2 */ |
| 882 | *sat |= 0x08; |
| 883 | } else |
| 884 | { |
| 885 | *at &= 0xF7; |
| 886 | *sat &= 0xF7; |
| 887 | } |
| 888 | } else f2flag = 0; /* ignore font switch */ |
| 889 | |
| 890 | /* need to translate character? */ |
| 891 | if (f2flag==0 && vds.encoding[0]==XLAT2PC8) |
| 892 | return (c<0xa0) ? c : iso2pc8[c-0xa0]; |
| 893 | else |
| 894 | return c; |
| 895 | } |
| 896 | |
| 897 | /*********************************************************************** |
| 898 | * Support functions for the terminal emulator |
| 899 | **********************************************************************/ |
| 900 | #ifndef GFX_CONSOLE |
| 901 | /* |
| 902 | * moves the cursor up n lines |
| 903 | */ |
| 904 | void vga_cursorup(struct vty *vp, int n) |
| 905 | { |
| 906 | register pos; |
| 907 | |
| 908 | if (n <= 0) n = 1; |
| 909 | |
| 910 | pos = vp->crtat - vp->Crtat; |
| 911 | pos -= vp->ncol * n; |
| 912 | vp->row--; |
| 913 | if (pos < 0) { |
| 914 | pos += vp->size; |
| 915 | vp->row = vp->nrow-1; |
| 916 | } |
| 917 | vp->crtat = vp->Crtat + pos; |
| 918 | } |
| 919 | |
| 920 | /* |
| 921 | * moves the cursor down n lines |
| 922 | */ |
| 923 | void vga_cursordown(struct vty *vp, int n) |
| 924 | { |
| 925 | register pos; |
| 926 | |
| 927 | if (n <= 0) n = 1; |
| 928 | pos = vp->crtat - vp->Crtat; |
| 929 | pos += vp->ncol * n; |
| 930 | vp->row++; |
| 931 | if (pos >= vp->size) { |
| 932 | pos -= vp->size; |
| 933 | vp->row = 0; |
| 934 | } |
| 935 | vp->crtat = vp->Crtat + pos; |
| 936 | } |
| 937 | |
| 938 | /* |
| 939 | * moves the cursor left n columns |
| 940 | */ |
| 941 | void vga_cursorleft(struct vty *vp, int n) |
| 942 | { |
| 943 | register pos; |
| 944 | |
| 945 | if (n <= 0) n = 1; |
| 946 | pos = vp->crtat - vp->Crtat; |
| 947 | pos -= n; vp->col -= n; |
| 948 | if (vp->col < 0) { |
| 949 | vp->col += vp->ncol; |
| 950 | pos += vp->ncol; /* cursor stays on same line */ |
| 951 | } |
| 952 | vp->crtat = vp->Crtat + pos; |
| 953 | } |
| 954 | |
| 955 | /* |
| 956 | * moves the cursor right n columns |
| 957 | * wrap=1: cursor stays on same line |
| 958 | */ |
| 959 | void vga_cursorright(struct vty *vp, int n, int wrap) |
| 960 | { |
| 961 | register pos; |
| 962 | |
| 963 | if (n <= 0) n = 1; |
| 964 | pos = vp->crtat - vp->Crtat; |
| 965 | pos += n; vp->col += n; |
| 966 | if (wrap && vp->col >= vp->ncol) { |
| 967 | vp->col -= vp->ncol; |
| 968 | pos -= vp->ncol; /* cursor stays on same line */ |
| 969 | } |
| 970 | vp->crtat = vp->Crtat + (pos % vp->size); |
| 971 | } |
| 972 | |
| 973 | /* |
| 974 | * scrollup n lines and fill free space with default attribute |
| 975 | * cm = 1: also move cursor |
| 976 | */ |
| 977 | void vga_scrollup(struct vty *vp,int n, int cm) |
| 978 | { |
| 979 | u_short attr = vp->op->def_at; |
| 980 | int blkx,blky; |
| 981 | |
| 982 | if (n <= 0) n = 1; |
| 983 | blkx = vp->ncol*n; |
| 984 | blky = vp->size - blkx; |
| 985 | |
| 986 | bcopy(vp->Crtat+blkx, vp->Crtat, blky*CHR); |
| 987 | fillw((attr <<8)+' ', vp->Crtat+blky, blkx); |
| 988 | if (cm) { |
| 989 | vp->crtat -= blkx; |
| 990 | vp->row-= n; |
| 991 | } |
| 992 | } |
| 993 | |
| 994 | #ifndef MINITERM |
| 995 | /* |
| 996 | * scroll down n lines and fill free space with default attribute |
| 997 | */ |
| 998 | void vga_scrolldown(struct vty *vp, int n) |
| 999 | { |
| 1000 | u_short attr = vp->op->def_at; |
| 1001 | int blkx; |
| 1002 | |
| 1003 | if (n <= 0) n = 1; |
| 1004 | blkx = vp->ncol*n; |
| 1005 | |
| 1006 | bcopy(vp->Crtat, vp->Crtat+blkx, (vp->size-blkx)*CHR); |
| 1007 | fillw((attr <<8)+' ', vp->Crtat, blkx); |
| 1008 | /* XXX vp->crtat += blkx; */ |
| 1009 | } |
| 1010 | #endif /*!MINITERM*/ |
| 1011 | |
| 1012 | /* |
| 1013 | * set the absolute cursor position (row,col = 0..max) |
| 1014 | */ |
| 1015 | void vga_cursormove(struct vty *vp, int row, int col) |
| 1016 | { |
| 1017 | if (row==0 || col==0) { |
| 1018 | vp->crtat = vp->Crtat; |
| 1019 | vp->row = 0; |
| 1020 | vp->col = 0; |
| 1021 | } else if (col <= vp->ncol && row <= vp->nrow) { |
| 1022 | vp->crtat = vp->Crtat + (row - 1) * vp->ncol + col - 1; |
| 1023 | vp->col = col - 1; |
| 1024 | vp->row = row - 1; |
| 1025 | } |
| 1026 | } |
| 1027 | |
| 1028 | /* |
| 1029 | * cursorrelative: move cursor relative, don't check for outside of screen |
| 1030 | */ |
| 1031 | void vga_cursorrelative(struct vty *vp, int dx, int dy) |
| 1032 | { |
| 1033 | int incr = dy*vp->ncol + dx; |
| 1034 | int pos = vp->crtat - vp->Crtat; |
| 1035 | |
| 1036 | /* if ((pos+incr) < 0 || (pos+incr) >= vp->size) |
| 1037 | return; |
| 1038 | */ vp->crtat += incr; |
| 1039 | vp->col = (vp->col+dx) % vp->ncol; |
| 1040 | vp->row = (vp->row+dy) % vp->nrow; |
| 1041 | } |
| 1042 | |
| 1043 | /* |
| 1044 | * Clear screen with default attr |
| 1045 | * mode = 0: from cursor to end of screen |
| 1046 | * = 1: cursor position only |
| 1047 | * = 2: whole display |
| 1048 | */ |
| 1049 | void vga_clearcursor(struct vty *vp, int mode) |
| 1050 | { |
| 1051 | u_short attr = (vp->op->def_at << 8) | ' '; |
| 1052 | |
| 1053 | /* clear ... */ |
| 1054 | switch (mode) { |
| 1055 | case 0: /* ... to end of display */ |
| 1056 | fillw(attr, vp->crtat, vp->Crtat + vp->size - vp->crtat); |
| 1057 | break; |
| 1058 | case 1: /* ... to next location */ |
| 1059 | fillw(attr, vp->Crtat, vp->crtat - vp->Crtat + 1); |
| 1060 | break; |
| 1061 | case 2: /* ... whole display */ |
| 1062 | fillw(attr, vp->Crtat, vp->size); |
| 1063 | } |
| 1064 | } |
| 1065 | |
| 1066 | /* |
| 1067 | * Clear line and fill with default attr |
| 1068 | * mode = 0: from cursor to end of line |
| 1069 | * = 1: from beginning to cursor |
| 1070 | * = 2: whole line |
| 1071 | */ |
| 1072 | #ifndef MINITERM |
| 1073 | void vga_clearline(struct vty *vp, int mode) |
| 1074 | { |
| 1075 | u_short attr = (vp->op->def_at << 8) | ' '; |
| 1076 | |
| 1077 | /* clear ... */ |
| 1078 | switch (mode) { |
| 1079 | case 0: /* ... current to EOL */ |
| 1080 | fillw(attr, vp->crtat, |
| 1081 | vp->ncol - (vp->crtat - vp->Crtat) % vp->ncol); |
| 1082 | break; |
| 1083 | case 1: /* ... beginning to next */ |
| 1084 | fillw(attr, |
| 1085 | vp->crtat - (vp->crtat - vp->Crtat) % vp->ncol, |
| 1086 | ((vp->crtat - vp->Crtat) % vp->ncol) + 1); |
| 1087 | break; |
| 1088 | case 2: /* ... entire line */ |
| 1089 | fillw(attr, vp->crtat - (vp->crtat - vp->Crtat) % vp->ncol, |
| 1090 | vp->ncol); |
| 1091 | } |
| 1092 | } |
| 1093 | |
| 1094 | /* |
| 1095 | * delete n lines from cursor position to end, pull up lines with default attr |
| 1096 | */ |
| 1097 | void vga_deleteline(struct vty *vp, int n) |
| 1098 | { |
| 1099 | u_short *crtend,*pp; |
| 1100 | u_short attr = (vp->op->def_at <<8) | ' '; |
| 1101 | |
| 1102 | if (n <= 0) n = 1; |
| 1103 | |
| 1104 | /* Work from beginning of line */ |
| 1105 | vp->crtat -= (vp->crtat - vp->Crtat) % vp->ncol; |
| 1106 | vp->col = 0; |
| 1107 | crtend = vp->Crtat + vp->size; |
| 1108 | |
| 1109 | /* Cap affected area at bottom of screen */ |
| 1110 | if ((pp = (vp->crtat + n*vp->ncol)) > crtend) { |
| 1111 | n = (crtend-vp->crtat) / vp->ncol; |
| 1112 | pp = crtend; |
| 1113 | } |
| 1114 | |
| 1115 | /* If there's visible lines left, move them up */ |
| 1116 | if (pp < crtend) { |
| 1117 | bcopy(pp, vp->crtat, (crtend-pp)*CHR); |
| 1118 | } |
| 1119 | fillw(attr, crtend - n*vp->ncol, n*vp->ncol); |
| 1120 | } |
| 1121 | |
| 1122 | /* |
| 1123 | * insert n lines from cursor position to end, fill with default attr |
| 1124 | */ |
| 1125 | void vga_insertline(struct vty *vp, int n) |
| 1126 | { |
| 1127 | u_short *crtend,*pp; |
| 1128 | u_short attr = (vp->op->def_at << 8) | ' '; |
| 1129 | |
| 1130 | if (n <= 0) n = 1; |
| 1131 | |
| 1132 | /* Work from beginning of line */ |
| 1133 | vp->crtat -= (vp->crtat - vp->Crtat) % vp->ncol; |
| 1134 | vp->col = 0; |
| 1135 | crtend = vp->Crtat + vp->size; |
| 1136 | |
| 1137 | /* Cap affected area at bottom of screen */ |
| 1138 | if ((pp = (vp->crtat + n*vp->ncol)) > crtend) { |
| 1139 | n = (crtend-vp->crtat) / vp->ncol; |
| 1140 | pp = crtend; |
| 1141 | } |
| 1142 | |
| 1143 | /* If there's visible lines left, move them down */ |
| 1144 | if (pp < crtend) { |
| 1145 | bcopy(vp->crtat, pp, (crtend-pp)*CHR); |
| 1146 | } |
| 1147 | fillw(attr, vp->crtat, n*vp->ncol); |
| 1148 | } |
| 1149 | |
| 1150 | /* |
| 1151 | * Delete n chars in line, fill free space with default attr |
| 1152 | */ |
| 1153 | void vga_deletechars(struct vty *vp, int n) |
| 1154 | { |
| 1155 | u_short *crtend,*pp; |
| 1156 | u_short attr = (vp->op->def_at << 8) | ' '; |
| 1157 | |
| 1158 | if (n <= 0) n = 1; |
| 1159 | |
| 1160 | /* Point to end of current line */ |
| 1161 | pp = vp->crtat + (vp->ncol - (vp->crtat-vp->Crtat) % vp->ncol); |
| 1162 | |
| 1163 | /* Cap delete to end of current line */ |
| 1164 | if ((vp->crtat+n) > pp) |
| 1165 | n = pp-vp->crtat; |
| 1166 | |
| 1167 | /* If visible characters, move in */ |
| 1168 | if ((vp->crtat+n) < pp) |
| 1169 | bcopy(vp->crtat+n, vp->crtat, ((pp-vp->crtat)-n)*CHR); |
| 1170 | |
| 1171 | /* Blank out space at end of line */ |
| 1172 | fillw(attr, pp-n, n); |
| 1173 | } |
| 1174 | |
| 1175 | /* |
| 1176 | * Delete n chars in line, fill free space with default attr |
| 1177 | */ |
| 1178 | void vga_insertchars(struct vty *vp, int n) |
| 1179 | { |
| 1180 | u_short *crtend,*pp; |
| 1181 | u_short attr = (vp->op->def_at << 8) | ' '; |
| 1182 | |
| 1183 | if (n <= 0) n = 1; |
| 1184 | |
| 1185 | /* Point to end of current line */ |
| 1186 | pp = vp->crtat + (vp-> ncol - (vp->crtat-vp->Crtat) % vp->ncol); |
| 1187 | |
| 1188 | /* Cap insert to end of current line */ |
| 1189 | if ((vp->crtat+n) > pp) |
| 1190 | n = pp-vp->crtat; |
| 1191 | |
| 1192 | /* If visible characters, move out */ |
| 1193 | if ((vp->crtat) < pp) |
| 1194 | bcopy(vp->crtat, vp->crtat+n, ((pp-vp->crtat)-n)*CHR); |
| 1195 | |
| 1196 | /* Blank out space at new positions */ |
| 1197 | fillw(attr, vp->crtat, n); |
| 1198 | } |
| 1199 | #endif /*!MINITERM*/ |
| 1200 | |
| 1201 | static u_short fgansitopc[] = |
| 1202 | { FG_BLACK, FG_RED, FG_GREEN, FG_BROWN, FG_BLUE, |
| 1203 | FG_MAGENTA, FG_CYAN, FG_LIGHTGREY |
| 1204 | }; |
| 1205 | |
| 1206 | static u_short bgansitopc[] = |
| 1207 | { BG_BLACK, BG_RED, BG_GREEN, BG_BROWN, BG_BLUE, |
| 1208 | BG_MAGENTA, BG_CYAN, BG_LIGHTGREY |
| 1209 | }; |
| 1210 | |
| 1211 | /* |
| 1212 | * set attributes |
| 1213 | * mode = 0: reset normal attributes, attr=0: std, attr=1: kernel |
| 1214 | * mode = 1: set ansi color background |
| 1215 | * mode = 2: set ansi color foreground |
| 1216 | * mode = 3: set PC attribute |
| 1217 | * mode = 4: reset standout attributes (extension!) |
| 1218 | */ |
| 1219 | void vga_setattributes(struct vty *vp, int mode, int attr) |
| 1220 | { |
| 1221 | struct outmode *o = vp->op; |
| 1222 | |
| 1223 | switch (mode) { |
| 1224 | case 0: /* reset to normal attributes */ |
| 1225 | if (o == &vp->om[0]) { /* std */ |
| 1226 | o->fg_at = vds.color ? DEF_STD_C_FGAT : DEF_STD_M_FGAT; |
| 1227 | o->bg_at = DEF_STD_BGAT; |
| 1228 | } else |
| 1229 | { /* kernel */ |
| 1230 | o->fg_at = vds.color ? DEF_KERN_C_FGAT : DEF_KERN_M_FGAT; |
| 1231 | o->bg_at = DEF_KERN_BGAT; |
| 1232 | } |
| 1233 | /* asa@kiae.su: fix to allow non-black background */ |
| 1234 | /*o->def_at = o->fg_at | o->bg_at;*/ |
| 1235 | break; |
| 1236 | |
| 1237 | case 1: /* ansi background */ |
| 1238 | if (vds.color) |
| 1239 | o->bg_at = bgansitopc[attr & 7]; |
| 1240 | break; |
| 1241 | |
| 1242 | case 2: /* ansi foreground */ |
| 1243 | if (vds.color) |
| 1244 | o->fg_at = fgansitopc[attr & 7]; |
| 1245 | break; |
| 1246 | |
| 1247 | case 3: /* pc text attribute */ |
| 1248 | o->fg_at = attr & 0x8f; |
| 1249 | o->bg_at = attr & 0x70; |
| 1250 | break; |
| 1251 | |
| 1252 | case 4: /* set so attribute to default */ |
| 1253 | vp->so_at = vds.color ? DEF_SO_C_AT : DEF_SO_M_AT; |
| 1254 | } |
| 1255 | o->def_at = o->fg_at | o->bg_at; /* asa@kiae.su */ |
| 1256 | } |
| 1257 | |
| 1258 | void vga_selectfont(struct vty *vp,int fontnr) |
| 1259 | { |
| 1260 | vp->op->f2 = (fontnr==2); |
| 1261 | } |
| 1262 | |
| 1263 | void vga_wrtchar(struct vty *vp, u_int c, u_int at) |
| 1264 | { |
| 1265 | *(vp->crtat++) = (u_short)(at<<8)|c; |
| 1266 | vp->col++; |
| 1267 | } |
| 1268 | |
| 1269 | /* |
| 1270 | * check whether crtat points to outside the screen |
| 1271 | * = 0: no, = -1: less than top of screen, =1: below bottom of screen |
| 1272 | */ |
| 1273 | int vga_checkcursor(struct vty *vp) |
| 1274 | { |
| 1275 | if (vp->crtat < vp->Crtat) return -1; |
| 1276 | if (vp->crtat >= vp->Crtat+vp->size) return 1; |
| 1277 | return 0; |
| 1278 | } |
| 1279 | |
| 1280 | /* |
| 1281 | * return a char to the vty, i.e. simulate an (ASCII) keypress, |
| 1282 | * used to return status messages (not for pc3) |
| 1283 | */ |
| 1284 | void vga_sendchar(struct vty *vp, XCHAR c) |
| 1285 | { |
| 1286 | /* XXX modify for real (=char) XCHAR type */ |
| 1287 | |
| 1288 | /* is it opened? */ |
| 1289 | if (vp->ttycnt) |
| 1290 | (*linesw[vp->ttyp->t_line].l_rint)(c & 0xFF, vp->ttyp); |
| 1291 | } |
| 1292 | |
| 1293 | void vga_initvideo() {} |
| 1294 | |
| 1295 | #endif |
| 1296 | #endif /* NPC=0 */ |
| 1297 | #endif /* NCO=1 */ |