Commit | Line | Data |
---|---|---|
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 | */ | |
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 */ |