adding GNU dc ("desk calculator")
[unix-history] / sys / i386 / isa / codrv / co_vga.c
CommitLineData
15637ed4
RG
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 */
39static 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
52static char isinitialized = 0; /* =1: console/vtys initialized */
53u_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 */
57static int scrblanksave; /* save position cursor */
58static u_short *scrbuf = 0; /* buffer for screen saver */
59static char *card2name(int id);
60
61/* find video config */
62static 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
76int 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 */
153void 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
161void 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 */
180static struct cursorshape playsave = { -1,-1 };
181
182#if SCRSAVER == 1
183/*ARGSUSED*/
184static 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
235static 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
299ERROR! NEED SCRSAVER=1 OR 2
300#endif /* SCRSAVER=2 */
301#endif /* SCRSAVER=1 */
302
303/* XXX graphics */
304static 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 */
316void 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*/
339static void display_off(int arg,int ctime) {}
340static void display_on() {}
341void 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 */
346void 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 */
374void 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 */
398void 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
406void 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 */
420void 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
458not_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;
552foundp: outb(0x3c5,save1);
553foundp2: 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
732static 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 */
757int 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
781int 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
793int 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
805static char modesave;
806
807void 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
825void 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
859static 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 */
875int 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 */
904void 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 */
923void 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 */
941void 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 */
959void 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 */
977void 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 */
998void 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 */
1015void 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 */
1031void 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 */
1049void 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
1073void 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 */
1097void 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 */
1125void 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 */
1153void 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 */
1178void 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
1201static u_short fgansitopc[] =
1202{ FG_BLACK, FG_RED, FG_GREEN, FG_BROWN, FG_BLUE,
1203 FG_MAGENTA, FG_CYAN, FG_LIGHTGREY
1204};
1205
1206static 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 */
1219void 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
1258void vga_selectfont(struct vty *vp,int fontnr)
1259{
1260 vp->op->f2 = (fontnr==2);
1261}
1262
1263void 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 */
1273int 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 */
1284void 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
1293void vga_initvideo() {}
1294
1295#endif
1296#endif /* NPC=0 */
1297#endif /* NCO=1 */