]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/i386/isa/pcvt/pcvt_ext.c
This commit was generated by cvs2svn to compensate for changes in r52744,
[FreeBSD/FreeBSD.git] / sys / i386 / isa / pcvt / pcvt_ext.c
1 /*
2  * Copyright (c) 1992, 1995 Hellmuth Michaelis and Joerg Wunsch.
3  *
4  * Copyright (C) 1992, 1993 Soeren Schmidt.
5  *
6  * All rights reserved.
7  *
8  * For the sake of compatibility, portions of this code regarding the
9  * X server interface are taken from Soeren Schmidt's syscons driver.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *      This product includes software developed by
22  *      Hellmuth Michaelis, Joerg Wunsch and Soeren Schmidt.
23  * 4. The name authors may not be used to endorse or promote products
24  *    derived from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
27  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
28  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
30  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
31  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36  *
37  *
38  * @(#)pcvt_ext.c, 3.20, Last Edit-Date: [Thu Apr  6 10:07:45 1995]
39  *
40  */
41
42 /*---------------------------------------------------------------------------*
43  *
44  *      pcvt_ext.c      VT220 Driver Extended Support Routines
45  *      ------------------------------------------------------
46  *
47  *      -hm     ------------ Release 3.00 --------------
48  *      -hm     integrating NetBSD-current patches
49  *      -hm     applied Onno van der Linden's patch for Cirrus BIOS upgrade
50  *      -hm     pcvt_x_hook has to care about fkey labels now
51  *      -hm     changed some bcopyb's to bcopy's
52  *      -hm     TS_INDEX -> TS_DATA for cirrus (mail from Onno/Charles)
53  *      -jw     removed kbc_8042(), and replaced by kbd_emulate_pc()
54  *      -hm     X server patch from John Kohl <jtk@kolvir.blrc.ma.us>
55  *      -hm     applying Joerg's patch for FreeBSD 2.0
56  *      -hm     enable 132 col support for Trident TVGA8900CL
57  *      -hm     applying patch from Joerg fixing Crtat bug
58  *      -hm     removed PCVT_FAKE_SYSCONS10
59  *      -hm     fastscroll/Crtat bugfix from Lon Willett
60  *      -hm     bell patch from Thomas Eberhardt for NetBSD
61  *      -hm     multiple X server bugfixes from Lon Willett
62  *      -hm     patch from John Kohl fixing tsleep bug in usl_vt_ioctl()
63  *      -hm     bugfix: clear 25th line when switching to a force 24 lines vt
64  *      -jw     add some forward declarations
65  *      -hm     fixing MDA re-init when leaving X
66  *      -hm     patch from John Kohl fixing potential divide by 0 problem
67  *
68  *---------------------------------------------------------------------------*/
69
70 #include "vt.h"
71 #if NVT > 0
72
73 #include <i386/isa/pcvt/pcvt_hdr.h>     /* global include */
74
75 #define ISSIGVALID(sig) ((sig) > 0 && (sig) < NSIG)
76
77 static int  s3testwritable( void );
78 static int  et4000_col( int );
79 static int  wd90c11_col( int );
80 static int  tri9000_col( int );
81 static int  v7_1024i_col( int );
82 static int  s3_928_col( int );
83 static int  cl_gd542x_col( int );
84
85 /* storage to save video timing values of 80 columns text mode */
86 static union {
87         u_char generic[11];
88         u_char et4000[11];
89         u_char wd90c11[12];
90         u_char tri9000[13];
91         u_char v7_1024i[17];
92         u_char s3_928[32];
93         u_char cirrus[13];
94 }
95 savearea;
96
97 static int regsaved = 0;        /* registers are saved to savearea */
98
99 /*---------------------------------------------------------------------------*
100  *
101  *      Find out which video board we are running on, taken from:
102  *      Richard Ferraro: Programmers Guide to the EGA and VGA Cards
103  *      and from David E. Wexelblat's SuperProbe Version 1.0.
104  *      When a board is found, for which 132 column switching is
105  *      provided, the global variable "can_do_132col" is set to 1,
106  *      also the global variable vga_family is set to what we found.
107  *
108  *      ###############################################################
109  *      ## THIS IS GETTING MORE AND MORE A LARGE SPAGHETTI HACK !!!! ##
110  *      ###############################################################
111  *
112  *---------------------------------------------------------------------------*/
113 u_char
114 vga_chipset(void)
115 {
116         u_char *ptr;
117         u_char byte, oldbyte, old1byte, newbyte;
118
119 #if PCVT_132GENERIC
120         can_do_132col = 1;      /* assumes everyone can do 132 col */
121 #else
122         can_do_132col = 0;      /* assumes noone can do 132 col */
123 #endif /* PCVT_132GENERIC */
124
125         vga_family = VGA_F_NONE;
126
127 /*---------------------------------------------------------------------------*
128  *      check for Western Digital / Paradise chipsets
129  *---------------------------------------------------------------------------*/
130
131         ptr = (u_char *)Crtat;
132
133         if(color)
134                 ptr += (0xc007d - 0xb8000);
135         else
136                 ptr += (0xc007d - 0xb0000);
137
138         if((*ptr++ == 'V') && (*ptr++ == 'G') &&
139            (*ptr++ == 'A') && (*ptr++ == '='))
140         {
141                 int wd90c10;
142
143                 vga_family = VGA_F_WD;
144
145                 outb(addr_6845, 0x2b);
146                 oldbyte = inb(addr_6845+1);
147                 outb(addr_6845+1, 0xaa);
148                 newbyte = inb(addr_6845+1);
149                 outb(addr_6845+1, oldbyte);
150                 if(newbyte != 0xaa)
151                         return(VGA_PVGA);       /* PVGA1A chip */
152
153                 outb(TS_INDEX, 0x12);
154                 oldbyte = inb(TS_DATA);
155                 outb(TS_DATA, oldbyte & 0xbf);
156                 newbyte = inb(TS_DATA) & 0x40;
157                 if(newbyte != 0)
158                         return(VGA_WD90C00);    /* WD90C00 chip */
159
160                 outb(TS_DATA, oldbyte | 0x40);
161                 newbyte = inb(TS_DATA) & 0x40;
162                 if(newbyte == 0)
163                         return(VGA_WD90C00);    /* WD90C00 chip */
164
165                 outb(TS_DATA, oldbyte);
166
167                 wd90c10 = 0;
168                 outb(TS_INDEX, 0x10);
169                 oldbyte = inb(TS_DATA);
170
171                 outb(TS_DATA, oldbyte & 0xfb);
172                 newbyte = inb(TS_DATA) & 0x04;
173                 if(newbyte != 0)
174                         wd90c10 = 1;
175
176                 outb(TS_DATA, oldbyte | 0x04);
177                 newbyte = inb(TS_DATA) & 0x04;
178                 if(newbyte == 0)
179                         wd90c10 = 1;
180
181                 outb(TS_DATA, oldbyte);
182
183                 if(wd90c10)
184                         return(VGA_WD90C10);
185                 else
186                 {
187                         can_do_132col = 1;
188                         return(VGA_WD90C11);
189                 }
190         }
191
192 /*---------------------------------------------------------------------------*
193  *      check for Trident chipsets
194  *---------------------------------------------------------------------------*/
195
196         outb(TS_INDEX, 0x0b);
197         oldbyte = inb(TS_DATA);
198
199
200         outb(TS_INDEX, 0x0b);
201         outb(TS_DATA, 0x00);
202
203         byte = inb(TS_DATA);    /* chipset type */
204
205
206         outb(TS_INDEX, 0x0e);
207         old1byte = inb(TS_DATA);
208
209         outb(TS_DATA, 0);
210         newbyte = inb(TS_DATA);
211
212         outb(TS_DATA, (old1byte ^ 0x02));
213
214         outb(TS_INDEX, 0x0b);
215         outb(TS_DATA, oldbyte);
216
217         if((newbyte & 0x0f) == 0x02)
218         {
219                 /* is a trident chip */
220
221                 vga_family = VGA_F_TRI;
222
223                 switch(byte)
224                 {
225                         case 0x01:
226                                 return(VGA_TR8800BR);
227
228                         case 0x02:
229                                 return(VGA_TR8800CS);
230
231                         case 0x03:
232                                 can_do_132col = 1;
233                                 return(VGA_TR8900B);
234
235                         case 0x04:
236                         case 0x13:
237         /* Haven't tried, but should work */
238                                 can_do_132col = 1;
239                                 return(VGA_TR8900C);
240
241                         case 0x23:
242                                 can_do_132col = 1;
243                                 return(VGA_TR9000);
244
245                         case 0x33:
246                                 can_do_132col = 1;
247                                 return(VGA_TR8900CL);
248
249                         case 0x83:
250                                 return(VGA_TR9200);
251
252                         case 0x93:
253                                 return(VGA_TR9100);
254
255                         default:
256                                 return(VGA_TRUNKNOWN);
257                 }
258         }
259
260 /*---------------------------------------------------------------------------*
261  *      check for Tseng Labs ET3000/4000 chipsets
262  *---------------------------------------------------------------------------*/
263
264         outb(GN_HERCOMPAT, 0x06);
265         if(color)
266                 outb(GN_DMCNTLC, 0xa0);
267         else
268                 outb(GN_DMCNTLM, 0xa0);
269
270         /* read old value */
271
272         if(color)
273                 inb(GN_INPSTAT1C);
274         else
275                 inb(GN_INPSTAT1M);
276         outb(ATC_INDEX, ATC_MISC);
277         oldbyte = inb(ATC_DATAR);
278
279         /* write new value */
280
281         if(color)
282                 inb(GN_INPSTAT1C);
283         else
284                 inb(GN_INPSTAT1M);
285         outb(ATC_INDEX, ATC_MISC);
286         newbyte = oldbyte ^ 0x10;
287         outb(ATC_DATAW, newbyte);
288
289         /* read back new value */
290         if(color)
291                 inb(GN_INPSTAT1C);
292         else
293                 inb(GN_INPSTAT1M);
294         outb(ATC_INDEX, ATC_MISC);
295         byte = inb(ATC_DATAR);
296
297         /* write back old value */
298         if(color)
299                 inb(GN_INPSTAT1C);
300         else
301                 inb(GN_INPSTAT1M);
302         outb(ATC_INDEX, ATC_MISC);
303         outb(ATC_DATAW, oldbyte);
304
305         if(byte == newbyte)     /* ET3000 or ET4000 */
306         {
307                 vga_family = VGA_F_TSENG;
308
309                 outb(addr_6845, CRTC_EXTSTART);
310                 oldbyte = inb(addr_6845+1);
311                 newbyte = oldbyte ^ 0x0f;
312                 outb(addr_6845+1, newbyte);
313                 byte = inb(addr_6845+1);
314                 outb(addr_6845+1, oldbyte);
315
316                 if(byte == newbyte)
317                 {
318                         can_do_132col = 1;
319                         return(VGA_ET4000);
320                 }
321                 else
322                 {
323                         return(VGA_ET3000);
324                 }
325         }
326
327 /*---------------------------------------------------------------------------*
328  *      check for Video7 VGA chipsets
329  *---------------------------------------------------------------------------*/
330
331         outb(TS_INDEX, TS_EXTCNTL);     /* enable extensions */
332         outb(TS_DATA, 0xea);
333
334         outb(addr_6845, CRTC_STARTADRH);
335         oldbyte = inb(addr_6845+1);
336
337         outb(addr_6845+1, 0x55);
338         newbyte = inb(addr_6845+1);
339
340         outb(addr_6845, CRTC_V7ID);     /* id register */
341         byte = inb(addr_6845+1);        /* read id */
342
343         outb(addr_6845, CRTC_STARTADRH);
344         outb(addr_6845+1, oldbyte);
345
346         outb(TS_INDEX, TS_EXTCNTL);     /* disable extensions */
347         outb(TS_DATA, 0xae);
348
349         if(byte == (0x55 ^ 0xea))
350         {                                       /* is Video 7 */
351
352                 vga_family = VGA_F_V7;
353
354                 outb(TS_INDEX, TS_EXTCNTL);     /* enable extensions */
355                 outb(TS_DATA, 0xea);
356
357                 outb(TS_INDEX, TS_V7CHIPREV);
358                 byte = inb(TS_DATA);
359
360                 outb(TS_INDEX, TS_EXTCNTL);     /* disable extensions */
361                 outb(TS_DATA, 0xae);
362
363                 if(byte < 0xff && byte >= 0x80)
364                         return(VGA_V7VEGA);
365                 if(byte < 0x7f && byte >= 0x70)
366                         return(VGA_V7FWVR);
367                 if(byte < 0x5a && byte >= 0x50)
368                         return(VGA_V7V5);
369                 if(byte < 0x4a && byte > 0x40)
370                 {
371                         can_do_132col = 1;
372                         return(VGA_V71024I);
373                 }
374                 return(VGA_V7UNKNOWN);
375         }
376
377 /*---------------------------------------------------------------------------*
378  *      check for S3 chipsets
379  *---------------------------------------------------------------------------*/
380
381         outb(addr_6845, 0x38);          /* reg 1 lock register */
382         old1byte = inb(addr_6845+1);    /* get old value */
383
384         outb(addr_6845, 0x38);
385         outb(addr_6845+1, 0x00);        /* lock registers */
386
387         if(s3testwritable() == 0)       /* check if locked */
388         {
389                 outb(addr_6845, 0x38);
390                 outb(addr_6845+1, 0x48);        /* unlock registers */
391
392                 if(s3testwritable() == 1 )      /* check if unlocked */
393                 {
394                         vga_family = VGA_F_S3;  /* FAMILY S3  */
395
396                         outb(addr_6845, 0x30);  /* chip id/rev reg */
397                         byte = inb(addr_6845+1);
398
399                         switch(byte & 0xf0)
400                         {
401                                 case 0x80:
402                                         switch(byte & 0x0f)
403                                         {
404                                                 case 0x01:
405                                                         outb(addr_6845, 0x38);
406                                                         outb(addr_6845+1, old1byte);
407                                                         return VGA_S3_911;
408
409                                                 case 0x02:
410                                                         outb(addr_6845, 0x38);
411                                                         outb(addr_6845+1, old1byte);
412                                                         return VGA_S3_924;
413
414                                                 default:
415                                                         outb(addr_6845, 0x38);
416                                                         outb(addr_6845+1, old1byte);
417                                                         return VGA_S3_UNKNOWN;
418                                         }
419                                         break;
420
421                                 case 0xA0:
422                                         outb(addr_6845, 0x38);
423                                         outb(addr_6845+1, old1byte);
424                                         return VGA_S3_80x;
425
426                                 case 0x90:
427                                 case 0xb0:
428                                         outb(addr_6845, 0x38);
429                                         outb(addr_6845+1, old1byte);
430                                         can_do_132col = 1;
431                                         return VGA_S3_928;
432
433                                 default:
434                                         outb(addr_6845, 0x38);
435                                         outb(addr_6845+1, old1byte);
436                                         return VGA_S3_UNKNOWN;
437                         }
438                 }
439         }
440
441 /*---------------------------------------------------------------------------*
442  *      check for Cirrus chipsets
443  *---------------------------------------------------------------------------*/
444
445         outb(TS_INDEX, 6);
446         oldbyte = inb(TS_DATA);
447         outb(TS_INDEX, 6);
448         outb(TS_DATA, 0x12);
449         outb(TS_INDEX, 6);
450         newbyte = inb(TS_DATA);
451         outb(addr_6845, 0x27);
452         byte = inb(addr_6845 + 1);
453         outb(TS_INDEX, 6);
454         outb(TS_DATA, oldbyte);
455         if (newbyte == 0x12) {
456                 vga_family = VGA_F_CIR;
457                 can_do_132col = 1;
458                 switch ((byte & 0xfc) >> 2) {
459                 case 0x22:
460                         switch (byte & 3) {
461                         case 0:
462                                 return VGA_CL_GD5402;
463                         case 1:
464                                 return VGA_CL_GD5402r1;
465                         case 2:
466                                 return VGA_CL_GD5420;
467                         case 3:
468                                 return VGA_CL_GD5420r1;
469                         }
470                         break;
471                 case 0x23:
472                         return VGA_CL_GD5422;
473                 case 0x25:
474                         return VGA_CL_GD5424;
475                 case 0x24:
476                         return VGA_CL_GD5426;
477                 case 0x26:
478                         return VGA_CL_GD5428;
479                 }
480         }
481
482         return(VGA_UNKNOWN);
483 }
484
485 /*---------------------------------------------------------------------------
486  * test if index 35 lower nibble is writable (taken from SuperProbe 1.0)
487  *---------------------------------------------------------------------------*/
488 static int
489 s3testwritable(void)
490 {
491         u_char old, new1, new2;
492
493         outb(addr_6845, 0x35);
494         old = inb(addr_6845+1);                 /* save */
495
496         outb(addr_6845, 0x35);
497         outb(addr_6845+1, (old & 0xf0));        /* write 0 */
498
499         outb(addr_6845, 0x35);
500         new1 = (inb(addr_6845+1)) & 0x0f;       /* must read 0 */
501
502         outb(addr_6845, 0x35);
503         outb(addr_6845+1, (old | 0x0f));        /* write 1 */
504
505         outb(addr_6845, 0x35);
506         new2 = (inb(addr_6845+1)) & 0x0f;       /* must read 1 */
507
508         outb(addr_6845, 0x35);
509         outb(addr_6845+1, old);                 /* restore */
510
511         return((new1==0) && (new2==0x0f));
512 }
513
514 /*---------------------------------------------------------------------------*
515  *      return ptr to string describing vga type
516  *---------------------------------------------------------------------------*/
517 char *
518 vga_string(int number)
519 {
520         static char *vga_tab[] = {
521                 "generic",
522                 "et4000",
523                 "et3000",
524                 "pvga1a",
525                 "wd90c00",
526                 "wd90c10",
527                 "wd90c11",
528                 "v7 vega",
529                 "v7 fast",
530                 "v7 ver5",
531                 "v7 1024i",
532                 "unknown v7",
533                 "tvga 8800br",
534                 "tvga 8800cs",
535                 "tvga 8900b",
536                 "tvga 8900c",
537                 "tvga 8900cl",
538                 "tvga 9000",
539                 "tvga 9100",
540                 "tvga 9200",
541                 "unknown trident",
542                 "s3 911",
543                 "s3 924",
544                 "s3 801/805",
545                 "s3 928",
546                 "unkown s3",
547                 "cl-gd5402",
548                 "cl-gd5402r1",
549                 "cl-gd5420",
550                 "cl-gd5420r1",
551                 "cl-gd5422",
552                 "cl-gd5424",
553                 "cl-gd5426",
554                 "cl-gd5428"
555         };
556         return(vga_tab[number]);
557 }
558
559 /*---------------------------------------------------------------------------*
560  *      toggle vga 80/132 column operation
561  *---------------------------------------------------------------------------*/
562 int
563 vga_col(struct video_state *svsp, int cols)
564 {
565         int ret = 0;
566
567         if(adaptor_type != VGA_ADAPTOR)
568                 return(0);
569
570         switch(vga_type)
571         {
572                 case VGA_ET4000:
573                         ret = et4000_col(cols);
574                         break;
575
576                 case VGA_WD90C11:
577                         ret = wd90c11_col(cols);
578                         break;
579
580                 case VGA_TR8900B:
581                 case VGA_TR8900C:
582                 case VGA_TR8900CL:
583                 case VGA_TR9000:
584                         ret = tri9000_col(cols);
585                         break;
586
587                 case VGA_V71024I:
588                         ret = v7_1024i_col(cols);
589                         break;
590
591                 case VGA_S3_928:
592                         ret = s3_928_col(cols);
593                         break;
594
595                 case VGA_CL_GD5402:
596                 case VGA_CL_GD5402r1:
597                 case VGA_CL_GD5420:
598                 case VGA_CL_GD5420r1:
599                 case VGA_CL_GD5422:
600                 case VGA_CL_GD5424:
601                 case VGA_CL_GD5426:
602                 case VGA_CL_GD5428:
603                         ret = cl_gd542x_col(cols);
604                         break;
605
606                 default:
607
608 #if PCVT_132GENERIC
609                         ret = generic_col(cols);
610 #endif /* PCVT_132GENERIC */
611
612                         break;
613         }
614
615         if(ret == 0)
616                 return(0);      /* failed */
617
618         svsp->maxcol = cols;
619
620         return(1);
621 }
622
623 #if PCVT_132GENERIC
624 /*---------------------------------------------------------------------------*
625  *      toggle 80/132 column operation for "generic" SVGAs
626  *      NB: this is supposed to work on any (S)VGA as long as the monitor
627  *      is able to sync down to 21.5 kHz horizontally. The resulting
628  *      vertical frequency is only 50 Hz, so if there is some better board
629  *      specific algorithm, we avoid using this generic one.
630  *      REPORT ANY FAILURES SO WE CAN IMPROVE THIS
631  *---------------------------------------------------------------------------*/
632
633 #if PCVT_EXP_132COL
634 /*
635  *      Some improved (i.e. higher scan rates) figures for the horizontal
636  *      timing. USE AT YOUR OWN RISK, THIS MIGHT DAMAGE YOUR MONITOR DUE
637  *      TO A LOSS OF HORIZONTAL SYNC!
638  *      The figures have been tested with an ET3000 board along with a
639  *      NEC MultiSync 3D monitor. If you are playing here, consider
640  *      testing with several screen pictures (dark background vs. light
641  *      background, even enlightening the border color may impact the
642  *      result - you can do this e.g. by "scon -p black,42,42,42")
643  *      Remember that all horizontal timing values must be dividable
644  *      by 8! (The scheme below is taken so that nifty kernel hackers
645  *      are able to patch the figures at run-time.)
646  *
647  *      The actual numbers result in 23 kHz line scan and 54 Hz vertical
648  *      scan.
649  */
650 #endif /* PCVT_EXP_132COL */
651
652 int
653 generic_col(int cols)
654 {
655         u_char *sp;
656         u_char byte;
657
658 #if !PCVT_EXP_132COL
659
660         /* stable figures for any multisync monitor that syncs down to 22 kHz*/
661         static volatile u_short htotal = 1312;
662         static volatile u_short displayend = 1056;
663         static volatile u_short blankstart = 1072;
664         static volatile u_short syncstart = 1112;
665         static volatile u_short syncend = 1280;
666
667 #else /* PCVT_EXP_132COL */
668
669         /* reduced sync-pulse width and sync delays */
670         static volatile u_short htotal = 1232;
671         static volatile u_short displayend = 1056;
672         static volatile u_short blankstart = 1056;
673         static volatile u_short syncstart = 1104;
674         static volatile u_short syncend = 1168;
675
676 #endif /* PCVT_EXP_132COL */
677
678         vga_screen_off();
679
680         /* enable access to first 7 CRTC registers */
681
682         outb(addr_6845, CRTC_VSYNCE);
683         byte = inb(addr_6845+1);
684         outb(addr_6845, CRTC_VSYNCE);
685         outb(addr_6845+1, byte & 0x7f);
686
687         if(cols == SCR_COL132)          /* switch 80 -> 132 */
688         {
689                 /* save state of board for 80 columns */
690
691                 if(!regsaved)
692                 {
693                         regsaved = 1;
694
695                         sp = savearea.generic;
696
697                         outb(addr_6845, 0x00);  /* Horizontal Total */
698                         *sp++ = inb(addr_6845+1);
699                         outb(addr_6845, 0x01);  /* Horizontal Display End */
700                         *sp++ = inb(addr_6845+1);
701                         outb(addr_6845, 0x02);  /* Horizontal Blank Start */
702                         *sp++ = inb(addr_6845+1);
703                         outb(addr_6845, 0x03);  /* Horizontal Blank End */
704                         *sp++ = inb(addr_6845+1);
705                         outb(addr_6845, 0x04);  /* Horizontal Retrace Start */
706                         *sp++ = inb(addr_6845+1);
707                         outb(addr_6845, 0x05);  /* Horizontal Retrace End */
708                         *sp++ = inb(addr_6845+1);
709
710                         outb(addr_6845, 0x13);  /* Row Offset Register */
711                         *sp++ = inb(addr_6845+1);
712
713                         outb(TS_INDEX, TS_MODE);/* Timing Sequencer */
714                         *sp++ = inb(TS_DATA);
715
716                         if(color)
717                                 inb(GN_INPSTAT1C);
718                         else
719                                 inb(GN_INPSTAT1M);
720                         /* ATC Mode control */
721                         outb(ATC_INDEX, ATC_MODE | ATC_ACCESS);
722                         *sp++ = inb(ATC_DATAR);
723
724                         if(color)
725                                 inb(GN_INPSTAT1C);
726                         else
727                                 inb(GN_INPSTAT1M);
728                         /* ATC Horizontal Pixel Panning */
729                         outb(ATC_INDEX, ATC_HORPIXPAN | ATC_ACCESS);
730                         *sp++ = inb(ATC_DATAR);
731
732                         *sp++ = inb(GN_MISCOUTR); /* Misc output register */
733                 }
734
735                 /* setup chipset for 132 column operation */
736
737
738                 outb(addr_6845, 0x00);  /* Horizontal Total */
739                 outb(addr_6845+1, (htotal / 8) - 5);
740                 outb(addr_6845, 0x01);  /* Horizontal Display End */
741                 outb(addr_6845+1, (displayend / 8) - 1);
742                 outb(addr_6845, 0x02);  /* Horizontal Blank Start */
743                 outb(addr_6845+1, blankstart / 8);
744                 outb(addr_6845, 0x03);  /* Horizontal Blank End */
745                 outb(addr_6845+1, ((syncend / 8) & 0x1f) | 0x80);
746                 outb(addr_6845, 0x04);  /* Horizontal Retrace Start */
747                 outb(addr_6845+1, syncstart / 8);
748                 outb(addr_6845, 0x05);  /* Horizontal Retrace End */
749                 outb(addr_6845+1,
750                      (((syncend / 8) & 0x20) * 4)
751                      | ((syncend / 8) & 0x1f));
752
753                 outb(addr_6845, 0x13);  /* Row Offset Register */
754                 outb(addr_6845+1, 0x42);
755
756                 outb(TS_INDEX, TS_MODE);/* Timing Sequencer */
757                 outb(TS_DATA, 0x01);    /* 8 dot char clock */
758
759                 if(color)
760                         inb(GN_INPSTAT1C);
761                 else
762                         inb(GN_INPSTAT1M);
763                 outb(ATC_INDEX, ATC_MODE | ATC_ACCESS); /* ATC Mode control */
764                 outb(ATC_DATAW, 0x08);  /* Line graphics disable */
765
766                 if(color)
767                         inb(GN_INPSTAT1C);
768                 else
769                         inb(GN_INPSTAT1M);
770                 outb(ATC_INDEX, ATC_HORPIXPAN | ATC_ACCESS); /* ATC Horizontal Pixel Panning */
771                 outb(ATC_DATAW, 0x00);
772
773                 /* Misc output register */
774                 /* use the 28.322 MHz clock */
775                 outb(GN_MISCOUTW, (inb(GN_MISCOUTR) & ~0x0c) | 4);
776         }
777         else    /* switch 132 -> 80 */
778         {
779                 if(!regsaved)                   /* failsafe */
780                 {
781                         /* disable access to first 7 CRTC registers */
782                         outb(addr_6845, CRTC_VSYNCE);
783                         outb(addr_6845+1, byte);
784                         vga_screen_on();
785                         return(0);
786                 }
787
788                 sp = savearea.generic;
789
790                 outb(addr_6845, 0x00);  /* Horizontal Total */
791                 outb(addr_6845+1, *sp++);
792                 outb(addr_6845, 0x01);  /* Horizontal Display End */
793                 outb(addr_6845+1, *sp++);
794                 outb(addr_6845, 0x02);  /* Horizontal Blank Start */
795                 outb(addr_6845+1, *sp++);
796                 outb(addr_6845, 0x03);  /* Horizontal Blank End */
797                 outb(addr_6845+1, *sp++);
798                 outb(addr_6845, 0x04);  /* Horizontal Retrace Start */
799                 outb(addr_6845+1, *sp++);
800                 outb(addr_6845, 0x05);  /* Horizontal Retrace End */
801                 outb(addr_6845+1, *sp++);
802
803                 outb(addr_6845, 0x13);  /* Row Offset Register */
804                 outb(addr_6845+1, *sp++);
805
806                 outb(TS_INDEX, TS_MODE);/* Timing Sequencer */
807                 outb(TS_DATA, *sp++);
808
809                 if(color)
810                         inb(GN_INPSTAT1C);
811                 else
812                         inb(GN_INPSTAT1M);
813                 /* ATC Mode control */
814                 outb(ATC_INDEX, ATC_MODE | ATC_ACCESS);
815                 outb(ATC_DATAW, *sp++);
816
817                 if(color)
818                         inb(GN_INPSTAT1C);
819                 else
820                         inb(GN_INPSTAT1M);
821                 /* ATC Horizontal Pixel Panning */
822                 outb(ATC_INDEX, ATC_HORPIXPAN | ATC_ACCESS);
823                 outb(ATC_DATAW, *sp++);
824
825                 outb(GN_MISCOUTW, *sp++);       /* Misc output register */
826         }
827
828         /* disable access to first 7 CRTC registers */
829
830         outb(addr_6845, CRTC_VSYNCE);
831         outb(addr_6845+1, byte);
832
833         vga_screen_on();
834
835         return(1);
836 }
837 #endif /* PCVT_132GENERIC */
838
839 /*---------------------------------------------------------------------------*
840  *      toggle 80/132 column operation for ET4000 based boards
841  *---------------------------------------------------------------------------*/
842 int
843 et4000_col(int cols)
844 {
845         u_char *sp;
846         u_char byte;
847
848         vga_screen_off();
849
850         /* enable access to first 7 CRTC registers */
851
852         outb(addr_6845, CRTC_VSYNCE);
853         byte = inb(addr_6845+1);
854         outb(addr_6845, CRTC_VSYNCE);
855         outb(addr_6845+1, byte & 0x7f);
856
857         if(cols == SCR_COL132)          /* switch 80 -> 132 */
858         {
859                 /* save state of board for 80 columns */
860
861                 if(!regsaved)
862                 {
863                         regsaved = 1;
864
865                         sp = savearea.et4000;
866
867                         outb(addr_6845, 0x00);  /* Horizontal Total */
868                         *sp++ = inb(addr_6845+1);
869                         outb(addr_6845, 0x01);  /* Horizontal Display End */
870                         *sp++ = inb(addr_6845+1);
871                         outb(addr_6845, 0x02);  /* Horizontal Blank Start */
872                         *sp++ = inb(addr_6845+1);
873
874                         outb(addr_6845, 0x04);  /* Horizontal Retrace Start */
875                         *sp++ = inb(addr_6845+1);
876                         outb(addr_6845, 0x05);  /* Horizontal Retrace End */
877                         *sp++ = inb(addr_6845+1);
878
879                         outb(addr_6845, 0x13);  /* Row Offset Register */
880                         *sp++ = inb(addr_6845+1);
881
882                         outb(addr_6845, 0x34);  /* 6845 Compatibility */
883                         *sp++ = inb(addr_6845+1);
884
885                         outb(TS_INDEX, TS_MODE);/* Timing Sequencer */
886                         *sp++ = inb(TS_DATA);
887
888                         if(color)
889                                 inb(GN_INPSTAT1C);
890                         else
891                                 inb(GN_INPSTAT1M);
892                         /* ATC Mode control */
893                         outb(ATC_INDEX, ATC_MODE | ATC_ACCESS);
894                         *sp++ = inb(ATC_DATAR);
895
896                         if(color)
897                                 inb(GN_INPSTAT1C);
898                         else
899                                 inb(GN_INPSTAT1M);
900                         /* ATC Horizontal Pixel Panning */
901                         outb(ATC_INDEX, ATC_HORPIXPAN | ATC_ACCESS);
902                         *sp++ = inb(ATC_DATAR);
903
904                         *sp++ = inb(GN_MISCOUTR);       /* Misc output register */
905                 }
906
907                 /* setup chipset for 132 column operation */
908
909                 outb(addr_6845, 0x00);  /* Horizontal Total */
910                 outb(addr_6845+1, 0x9f);
911                 outb(addr_6845, 0x01);  /* Horizontal Display End */
912                 outb(addr_6845+1, 0x83);
913                 outb(addr_6845, 0x02);  /* Horizontal Blank Start */
914                 outb(addr_6845+1, 0x84);
915
916                 outb(addr_6845, 0x04);  /* Horizontal Retrace Start */
917                 outb(addr_6845+1, 0x8b);
918                 outb(addr_6845, 0x05);  /* Horizontal Retrace End */
919                 outb(addr_6845+1, 0x80);
920
921                 outb(addr_6845, 0x13);  /* Row Offset Register */
922                 outb(addr_6845+1, 0x42);
923
924                 outb(addr_6845, 0x34);  /* 6845 Compatibility */
925                 outb(addr_6845+1, 0x0a);
926
927                 outb(TS_INDEX, TS_MODE);/* Timing Sequencer */
928                 outb(TS_DATA, 0x01);    /* 8 dot char clock */
929
930                 if(color)
931                         inb(GN_INPSTAT1C);
932                 else
933                         inb(GN_INPSTAT1M);
934                 outb(ATC_INDEX, ATC_MODE | ATC_ACCESS); /* ATC Mode control */
935                 outb(ATC_DATAW, 0x08);  /* Line graphics disable */
936
937                 if(color)
938                         inb(GN_INPSTAT1C);
939                 else
940                         inb(GN_INPSTAT1M);
941                 outb(ATC_INDEX, ATC_HORPIXPAN | ATC_ACCESS); /* ATC Horizontal Pixel Panning */
942                 outb(ATC_DATAW, 0x00);
943
944                 /* Misc output register */
945
946                 outb(GN_MISCOUTW, (inb(GN_MISCOUTR) & ~0x0c));
947         }
948         else    /* switch 132 -> 80 */
949         {
950                 if(!regsaved)                   /* failsafe */
951                 {
952                         /* disable access to first 7 CRTC registers */
953                         outb(addr_6845, CRTC_VSYNCE);
954                         outb(addr_6845+1, byte);
955                         vga_screen_on();
956                         return(0);
957                 }
958
959                 sp = savearea.et4000;
960
961                 outb(addr_6845, 0x00);  /* Horizontal Total */
962                 outb(addr_6845+1, *sp++);
963
964                 outb(addr_6845, 0x01);  /* Horizontal Display End */
965                 outb(addr_6845+1, *sp++);
966                 outb(addr_6845, 0x02);  /* Horizontal Blank Start */
967                 outb(addr_6845+1, *sp++);
968
969
970                 outb(addr_6845, 0x04);  /* Horizontal Retrace Start */
971                 outb(addr_6845+1, *sp++);
972                 outb(addr_6845, 0x05);  /* Horizontal Retrace End */
973                 outb(addr_6845+1, *sp++);
974
975                 outb(addr_6845, 0x13);  /* Row Offset Register */
976                 outb(addr_6845+1, *sp++);
977
978                 outb(addr_6845, 0x34);  /* 6845 Compatibility */
979                 outb(addr_6845+1, *sp++);
980
981                 outb(TS_INDEX, TS_MODE);/* Timing Sequencer */
982                 outb(TS_DATA, *sp++);
983
984                 if(color)
985                         inb(GN_INPSTAT1C);
986                 else
987                         inb(GN_INPSTAT1M);
988                 /* ATC Mode control */
989                 outb(ATC_INDEX, ATC_MODE | ATC_ACCESS);
990                 outb(ATC_DATAW, *sp++);
991
992                 if(color)
993                         inb(GN_INPSTAT1C);
994                 else
995                         inb(GN_INPSTAT1M);
996                 /* ATC Horizontal Pixel Panning */
997                 outb(ATC_INDEX, ATC_HORPIXPAN | ATC_ACCESS);
998                 outb(ATC_DATAW, *sp++);
999
1000                 outb(GN_MISCOUTW, *sp++);       /* Misc output register */
1001         }
1002
1003         /* disable access to first 7 CRTC registers */
1004
1005         outb(addr_6845, CRTC_VSYNCE);
1006         outb(addr_6845+1, byte);
1007
1008         vga_screen_on();
1009
1010         return(1);
1011 }
1012
1013 /*---------------------------------------------------------------------------*
1014  *      toggle 80/132 column operation for WD/Paradise based boards
1015  *
1016  *      when this card does 132 cols, the char map select register (TS_INDEX,
1017  *      TS_FONTSEL) function bits get REDEFINED. whoever did design this,
1018  *      please don't cross my way ever .......
1019  *
1020  *---------------------------------------------------------------------------*/
1021 int
1022 wd90c11_col(int cols)
1023 {
1024
1025 #if !PCVT_BACKUP_FONTS
1026         static unsigned char *sv_fontwd[NVGAFONTS];
1027 #endif /*  !PCVT_BACKUP_FONTS */
1028
1029         u_char *sp;
1030         u_char byte;
1031         int i;
1032
1033         vga_screen_off();
1034
1035         /* enable access to first 7 CRTC registers */
1036
1037         outb(addr_6845, CRTC_VSYNCE);
1038         byte = inb(addr_6845+1);
1039         outb(addr_6845, CRTC_VSYNCE);
1040         outb(addr_6845+1, byte & 0x7f);
1041
1042         /* enable access to WD/Paradise "control extensions" */
1043
1044         outb(GDC_INDEX, GDC_PR5GPLOCK);
1045         outb(GDC_INDEX, 0x05);
1046         outb(addr_6845, CRTC_PR10);
1047         outb(addr_6845, 0x85);
1048         outb(TS_INDEX, TS_UNLOCKSEQ);
1049         outb(TS_DATA, 0x48);
1050
1051         if(cols == SCR_COL132)          /* switch 80 -> 132 */
1052         {
1053                 /* save state of board for 80 columns */
1054
1055                 if(!regsaved)
1056                 {
1057                         regsaved = 1;
1058
1059                         /* save current fonts */
1060
1061 #if !PCVT_BACKUP_FONTS
1062                         for(i = 0; i < totalfonts; i++)
1063                         {
1064                                 if(vgacs[i].loaded)
1065                                 {
1066                                         if((sv_fontwd[i] =
1067                                             (u_char *)malloc(32 * 256,
1068                                                              M_DEVBUF,
1069                                                              M_WAITOK))
1070                                            == NULL)
1071                                                 printf("pcvt: no font buffer\n");
1072                                         else
1073                                                 vga_move_charset(i,
1074                                                                  sv_fontwd[i],
1075                                                                  1);
1076                                 }
1077                                 else
1078                                 {
1079                                         sv_fontwd[i] = 0;
1080                                 }
1081                         }
1082
1083 #endif /* !PCVT_BACKUP_FONTS */
1084
1085                         sp = savearea.wd90c11;
1086
1087                         outb(addr_6845, 0x00);  /* Horizontal Total */
1088                         *sp++ = inb(addr_6845+1);
1089                         outb(addr_6845, 0x01);  /* Horizontal Display End */
1090                         *sp++ = inb(addr_6845+1);
1091                         outb(addr_6845, 0x02);  /* Horizontal Blank Start */
1092                         *sp++ = inb(addr_6845+1);
1093                         outb(addr_6845, 0x03);  /* Horizontal Blank End */
1094                         *sp++ = inb(addr_6845+1);
1095                         outb(addr_6845, 0x04);  /* Horizontal Retrace Start */
1096                         *sp++ = inb(addr_6845+1);
1097                         outb(addr_6845, 0x05);  /* Horizontal Retrace End */
1098                         *sp++ = inb(addr_6845+1);
1099
1100                         outb(addr_6845, 0x13);  /* Row Offset Register */
1101                         *sp++ = inb(addr_6845+1);
1102
1103                         outb(addr_6845, 0x2e);  /* misc 1 */
1104                         *sp++ = inb(addr_6845+1);
1105                         outb(addr_6845, 0x2f);  /* misc 2 */
1106                         *sp++ = inb(addr_6845+1);
1107
1108                         outb(TS_INDEX, 0x10);/* Timing Sequencer */
1109                         *sp++ = inb(TS_DATA);
1110                         outb(TS_INDEX, 0x12);/* Timing Sequencer */
1111                         *sp++ = inb(TS_DATA);
1112
1113                         *sp++ = inb(GN_MISCOUTR);       /* Misc output register */
1114                 }
1115
1116                 /* setup chipset for 132 column operation */
1117
1118                 outb(addr_6845, 0x00);  /* Horizontal Total */
1119                 outb(addr_6845+1, 0x9c);
1120                 outb(addr_6845, 0x01);  /* Horizontal Display End */
1121                 outb(addr_6845+1, 0x83);
1122                 outb(addr_6845, 0x02);  /* Horizontal Blank Start */
1123                 outb(addr_6845+1, 0x84);
1124                 outb(addr_6845, 0x03);  /* Horizontal Blank End */
1125                 outb(addr_6845+1, 0x9f);
1126                 outb(addr_6845, 0x04);  /* Horizontal Retrace Start */
1127                 outb(addr_6845+1, 0x8a);
1128                 outb(addr_6845, 0x05);  /* Horizontal Retrace End */
1129                 outb(addr_6845+1, 0x1c);
1130
1131                 outb(addr_6845, 0x13);  /* Row Offset Register */
1132                 outb(addr_6845+1, 0x42);
1133
1134                 outb(addr_6845, 0x2e);  /* misc 1 */
1135                 outb(addr_6845+1, 0x04);
1136                 outb(addr_6845, 0x2f);  /* misc 2 */
1137                 outb(addr_6845+1, 0x00);
1138
1139                 outb(TS_INDEX, 0x10);/* Timing Sequencer */
1140                 outb(TS_DATA, 0x21);
1141                 outb(TS_INDEX, 0x12);/* Timing Sequencer */
1142                 outb(TS_DATA, 0x14);
1143
1144                 outb(GN_MISCOUTW, (inb(GN_MISCOUTR) | 0x08));   /* Misc output register */
1145
1146                 vsp->wd132col = 1;
1147         }
1148         else    /* switch 132 -> 80 */
1149         {
1150                 if(!regsaved)                   /* failsafe */
1151                 {
1152                         /* disable access to first 7 CRTC registers */
1153
1154                         outb(addr_6845, CRTC_VSYNCE);
1155                         outb(addr_6845+1, byte);
1156
1157                         /* disable access to WD/Paradise "control extensions" */
1158
1159                         outb(GDC_INDEX, GDC_PR5GPLOCK);
1160                         outb(GDC_INDEX, 0x00);
1161                         outb(addr_6845, CRTC_PR10);
1162                         outb(addr_6845, 0x00);
1163                         outb(TS_INDEX, TS_UNLOCKSEQ);
1164                         outb(TS_DATA, 0x00);
1165
1166                         vga_screen_on();
1167
1168                         return(0);
1169                 }
1170
1171                 sp = savearea.wd90c11;
1172
1173                 outb(addr_6845, 0x00);  /* Horizontal Total */
1174                 outb(addr_6845+1, *sp++);
1175                 outb(addr_6845, 0x01);  /* Horizontal Display End */
1176                 outb(addr_6845+1, *sp++);
1177                 outb(addr_6845, 0x02);  /* Horizontal Blank Start */
1178                 outb(addr_6845+1, *sp++);
1179                 outb(addr_6845, 0x03);  /* Horizontal Blank End */
1180                 outb(addr_6845+1, *sp++);
1181                 outb(addr_6845, 0x04);  /* Horizontal Retrace Start */
1182                 outb(addr_6845+1, *sp++);
1183                 outb(addr_6845, 0x05);  /* Horizontal Retrace End */
1184                 outb(addr_6845+1, *sp++);
1185
1186                 outb(addr_6845, 0x13);  /* Row Offset Register */
1187                 outb(addr_6845+1, *sp++);
1188
1189                 outb(addr_6845, 0x2e);  /* misc 1 */
1190                 outb(addr_6845+1, *sp++);
1191                 outb(addr_6845, 0x2f);  /* misc 2 */
1192                 outb(addr_6845+1, *sp++);
1193
1194                 outb(TS_INDEX, 0x10);/* Timing Sequencer */
1195                 outb(addr_6845+1, *sp++);
1196                 outb(TS_INDEX, 0x12);/* Timing Sequencer */
1197                 outb(addr_6845+1, *sp++);
1198
1199                 outb(GN_MISCOUTW, *sp++);       /* Misc output register */
1200
1201                 vsp->wd132col = 0;
1202         }
1203
1204         /* restore fonts */
1205
1206 #if !PCVT_BACKUP_FONTS
1207         for(i = 0; i < totalfonts; i++)
1208         {
1209                 if(sv_fontwd[i])
1210                         vga_move_charset(i, sv_fontwd[i], 0);
1211         }
1212 #else
1213         for(i = 0; i < totalfonts; i++)
1214                 if(saved_charsets[i])
1215                         vga_move_charset(i, 0, 0);
1216 #endif /* !PCVT_BACKUP_FONTS */
1217
1218         select_vga_charset(vsp->vga_charset);
1219
1220         /* disable access to first 7 CRTC registers */
1221
1222         outb(addr_6845, CRTC_VSYNCE);
1223         outb(addr_6845+1, byte);
1224
1225         /* disable access to WD/Paradise "control extensions" */
1226
1227         outb(GDC_INDEX, GDC_PR5GPLOCK);
1228         outb(GDC_INDEX, 0x00);
1229         outb(addr_6845, CRTC_PR10);
1230         outb(addr_6845, 0x00);
1231         outb(TS_INDEX, TS_UNLOCKSEQ);
1232         outb(TS_DATA, 0x00);
1233
1234         vga_screen_on();
1235
1236         return(1);
1237 }
1238
1239 /*---------------------------------------------------------------------------*
1240  *      toggle 80/132 column operation for TRIDENT 9000 based boards
1241  *---------------------------------------------------------------------------*/
1242 int
1243 tri9000_col(int cols)
1244 {
1245         u_char *sp;
1246         u_char byte;
1247
1248         vga_screen_off();
1249
1250         /* sync reset is necessary to preserve memory contents ... */
1251
1252         outb(TS_INDEX, TS_SYNCRESET);
1253         outb(TS_DATA, 0x01);    /* synchronous reset */
1254
1255         /* disable protection of misc out and other regs */
1256
1257         outb(addr_6845, CRTC_MTEST);
1258         byte = inb(addr_6845+1);
1259         outb(addr_6845, CRTC_MTEST);
1260         outb(addr_6845+1, byte & ~0x50);
1261
1262         /* enable access to first 7 CRTC registers */
1263
1264         outb(addr_6845, CRTC_VSYNCE);
1265         byte = inb(addr_6845+1);
1266         outb(addr_6845, CRTC_VSYNCE);
1267         outb(addr_6845+1, byte & 0x7f);
1268
1269         if(cols == SCR_COL132)          /* switch 80 -> 132 */
1270         {
1271                 /* save state of board for 80 columns */
1272
1273                 if(!regsaved)
1274                 {
1275                         regsaved = 1;
1276
1277                         sp = savearea.tri9000;
1278
1279                         outb(addr_6845, 0x00);  /* Horizontal Total */
1280                         *sp++ = inb(addr_6845+1);
1281                         outb(addr_6845, 0x01);  /* Horizontal Display End */
1282                         *sp++ = inb(addr_6845+1);
1283                         outb(addr_6845, 0x02);  /* Horizontal Blank Start */
1284                         *sp++ = inb(addr_6845+1);
1285                         outb(addr_6845, 0x03);  /* Horizontal Blank End */
1286                         *sp++ = inb(addr_6845+1);
1287                         outb(addr_6845, 0x04);  /* Horizontal Retrace Start */
1288                         *sp++ = inb(addr_6845+1);
1289                         outb(addr_6845, 0x05);  /* Horizontal Retrace End */
1290                         *sp++ = inb(addr_6845+1);
1291
1292                         outb(addr_6845, 0x13);
1293                         *sp++ = inb(addr_6845+1);
1294
1295                         outb(TS_INDEX, TS_MODE);/* Timing Sequencer */
1296                         *sp++ = inb(TS_DATA);
1297
1298                         outb(TS_INDEX, TS_HWVERS);/* Hardware Version register */
1299                         outb(TS_DATA, 0x00);      /* write ANYTHING switches to OLD */
1300                         outb(TS_INDEX, TS_MODEC2);
1301                         *sp++ = inb(TS_DATA);
1302
1303                         outb(TS_INDEX, TS_HWVERS);/* Hardware Version register */
1304                         inb(TS_DATA);             /* read switches to NEW */
1305                         outb(TS_INDEX, TS_MODEC2);
1306                         *sp++ = inb(TS_DATA);
1307
1308                         if(color)
1309                                 inb(GN_INPSTAT1C);
1310                         else
1311                                 inb(GN_INPSTAT1M);
1312                         /* ATC Mode control */
1313                         outb(ATC_INDEX, ATC_MODE | ATC_ACCESS);
1314                         *sp++ = inb(ATC_DATAR);
1315
1316                         if(color)
1317                                 inb(GN_INPSTAT1C);
1318                         else
1319                                 inb(GN_INPSTAT1M);
1320                         /* ATC Horizontal Pixel Panning */
1321                         outb(ATC_INDEX, ATC_HORPIXPAN | ATC_ACCESS);
1322                         *sp++ = inb(ATC_DATAR);
1323
1324                         *sp++ = inb(GN_MISCOUTR);       /* Misc output register */
1325                 }
1326
1327                 /* setup chipset for 132 column operation */
1328
1329                 outb(addr_6845, 0x00);  /* Horizontal Total */
1330                 outb(addr_6845+1, 0x9b);
1331                 outb(addr_6845, 0x01);  /* Horizontal Display End */
1332                 outb(addr_6845+1, 0x83);
1333                 outb(addr_6845, 0x02);  /* Horizontal Blank Start */
1334                 outb(addr_6845+1, 0x84);
1335                 outb(addr_6845, 0x03);  /* Horizontal Blank End */
1336                 outb(addr_6845+1, 0x1e);
1337                 outb(addr_6845, 0x04);  /* Horizontal Retrace Start */
1338                 outb(addr_6845+1, 0x87);
1339                 outb(addr_6845, 0x05);  /* Horizontal Retrace End */
1340                 outb(addr_6845+1, 0x1a);
1341
1342                 outb(addr_6845, 0x13);  /* Row Offset Register */
1343                 outb(addr_6845+1, 0x42);
1344
1345                 outb(TS_INDEX, TS_MODE);/* Timing Sequencer */
1346                 outb(TS_DATA, 0x01);    /* 8 dot char clock */
1347
1348                 outb(TS_INDEX, TS_HWVERS);/* Hardware Version register */
1349                 outb(TS_DATA, 0x00);      /* write ANYTHING switches to OLD */
1350                 outb(TS_INDEX, TS_MODEC2);
1351                 outb(TS_DATA, 0x00);
1352
1353                 outb(TS_INDEX, TS_HWVERS);/* Hardware Version register */
1354                 inb(TS_DATA);             /* read switches to NEW */
1355                 outb(TS_INDEX, TS_MODEC2);
1356                 outb(TS_DATA, 0x01);
1357
1358                 if(color)
1359                         inb(GN_INPSTAT1C);
1360                 else
1361                         inb(GN_INPSTAT1M);
1362                 outb(ATC_INDEX, ATC_MODE | ATC_ACCESS); /* ATC Mode control */
1363                 outb(ATC_DATAW, 0x08);  /* Line graphics disable */
1364
1365                 if(color)
1366                         inb(GN_INPSTAT1C);
1367                 else
1368                         inb(GN_INPSTAT1M);
1369                 outb(ATC_INDEX, ATC_HORPIXPAN | ATC_ACCESS); /* ATC Horizontal Pixel Panning */
1370                 outb(ATC_DATAW, 0x00);
1371
1372                 outb(GN_MISCOUTW, (inb(GN_MISCOUTR) | 0x0c));   /* Misc output register */
1373         }
1374         else    /* switch 132 -> 80 */
1375         {
1376                 if(!regsaved)                   /* failsafe */
1377                 {
1378                         /* disable access to first 7 CRTC registers */
1379                         outb(addr_6845, CRTC_VSYNCE);
1380                         outb(addr_6845+1, byte);
1381
1382                         outb(TS_INDEX, TS_SYNCRESET);
1383                         outb(TS_DATA, 0x03);    /* clear synchronous reset */
1384
1385                         vga_screen_on();
1386
1387                         return(0);
1388                 }
1389
1390                 sp = savearea.tri9000;
1391
1392                 outb(addr_6845, 0x00);  /* Horizontal Total */
1393                 outb(addr_6845+1, *sp++);
1394                 outb(addr_6845, 0x01);  /* Horizontal Display End */
1395                 outb(addr_6845+1, *sp++);
1396                 outb(addr_6845, 0x02);  /* Horizontal Blank Start */
1397                 outb(addr_6845+1, *sp++);
1398                 outb(addr_6845, 0x03);  /* Horizontal Blank End */
1399                 outb(addr_6845+1, *sp++);
1400                 outb(addr_6845, 0x04);  /* Horizontal Retrace Start */
1401                 outb(addr_6845+1, *sp++);
1402                 outb(addr_6845, 0x05);  /* Horizontal Retrace End */
1403                 outb(addr_6845+1, *sp++);
1404
1405                 outb(addr_6845, 0x13);  /* Row Offset Register */
1406                 outb(addr_6845+1, *sp++);
1407
1408                 outb(TS_INDEX, TS_MODE);/* Timing Sequencer */
1409                 outb(TS_DATA, *sp++);
1410
1411                 outb(TS_INDEX, TS_HWVERS);/* Hardware Version register */
1412                 outb(TS_DATA, 0x00);      /* write ANYTHING switches to OLD */
1413                 outb(TS_INDEX, TS_MODEC2);/* Timing Sequencer */
1414                 outb(TS_DATA, *sp++);
1415
1416                 outb(TS_INDEX, TS_HWVERS);/* Hardware Version register */
1417                 inb(TS_DATA);             /* read switches to NEW */
1418                 outb(TS_INDEX, TS_MODEC2);/* Timing Sequencer */
1419                 outb(TS_DATA, *sp++);
1420
1421                 if(color)
1422                         inb(GN_INPSTAT1C);
1423                 else
1424                         inb(GN_INPSTAT1M);
1425                 /* ATC Mode control */
1426                 outb(ATC_INDEX, ATC_MODE | ATC_ACCESS);
1427                 outb(ATC_DATAW, *sp++);
1428
1429                 if(color)
1430                         inb(GN_INPSTAT1C);
1431                 else
1432                         inb(GN_INPSTAT1M);
1433                 /* ATC Horizontal Pixel Panning */
1434                 outb(ATC_INDEX, ATC_HORPIXPAN | ATC_ACCESS);
1435                 outb(ATC_DATAW, *sp++);
1436
1437                 outb(GN_MISCOUTW, *sp++);       /* Misc output register */
1438         }
1439
1440         /* disable access to first 7 CRTC registers */
1441
1442         outb(addr_6845, CRTC_VSYNCE);
1443         outb(addr_6845+1, byte);
1444
1445         outb(TS_INDEX, TS_SYNCRESET);
1446         outb(TS_DATA, 0x03);    /* clear synchronous reset */
1447
1448         vga_screen_on();
1449
1450         return(1);
1451 }
1452
1453 /*---------------------------------------------------------------------------*
1454  *      toggle 80/132 column operation for Video7 VGA 1024i
1455  *---------------------------------------------------------------------------*/
1456 int
1457 v7_1024i_col(int cols)
1458 {
1459         u_char *sp;
1460         u_char byte;
1461         u_char save__byte;
1462
1463         vga_screen_off();
1464
1465         /* enable access to first 7 CRTC registers */
1466
1467         /* first, enable read access to vertical retrace start/end */
1468         outb(addr_6845, CRTC_HBLANKE);
1469         byte = inb(addr_6845+1);
1470         outb(addr_6845, CRTC_HBLANKE);
1471         outb(addr_6845+1, (byte | 0x80));
1472
1473         /* second, enable access to protected registers */
1474         outb(addr_6845, CRTC_VSYNCE);
1475         save__byte = byte = inb(addr_6845+1);
1476         byte |= 0x20;   /* no irq 2 */
1477         byte &= 0x6f;   /* wr enable, clr irq flag */
1478         outb(addr_6845, CRTC_VSYNCE);
1479         outb(addr_6845+1, byte);
1480
1481         outb(TS_INDEX, TS_EXTCNTL);     /* enable extensions */
1482         outb(TS_DATA, 0xea);
1483
1484
1485         if(cols == SCR_COL132)          /* switch 80 -> 132 */
1486         {
1487                 /* save state of board for 80 columns */
1488
1489                 if(!regsaved)
1490                 {
1491                         regsaved = 1;
1492
1493                         sp = savearea.v7_1024i;
1494
1495                         outb(addr_6845, 0x00);  /* Horizontal Total */
1496                         *sp++ = inb(addr_6845+1);
1497                         outb(addr_6845, 0x01);  /* Horizontal Display End */
1498                         *sp++ = inb(addr_6845+1);
1499                         outb(addr_6845, 0x02);  /* Horizontal Blank Start */
1500                         *sp++ = inb(addr_6845+1);
1501                         outb(addr_6845, 0x03);  /* Horizontal Blank End */
1502                         *sp++ = inb(addr_6845+1);
1503                         outb(addr_6845, 0x04);  /* Horizontal Retrace Start */
1504                         *sp++ = inb(addr_6845+1);
1505                         outb(addr_6845, 0x05);  /* Horizontal Retrace End */
1506                         *sp++ = inb(addr_6845+1);
1507
1508                         outb(addr_6845, 0x13);  /* Row Offset Register */
1509                         *sp++ = inb(addr_6845+1);
1510
1511                         outb(TS_INDEX, TS_MODE);/* Timing Sequencer */
1512                         *sp++ = inb(TS_DATA);
1513
1514                         if(color)
1515                                 inb(GN_INPSTAT1C);
1516                         else
1517                                 inb(GN_INPSTAT1M);
1518                         /* ATC Mode control */
1519                         outb(ATC_INDEX, ATC_MODE | ATC_ACCESS);
1520                         *sp++ = inb(ATC_DATAR);
1521
1522                         if(color)
1523                                 inb(GN_INPSTAT1C);
1524                         else
1525                                 inb(GN_INPSTAT1M);
1526                         /* ATC Horizontal Pixel Panning */
1527                         outb(ATC_INDEX, ATC_HORPIXPAN | ATC_ACCESS);
1528                         *sp++ = inb(ATC_DATAR);
1529
1530                         outb(TS_INDEX, 0x83);
1531                         *sp++ = inb(TS_DATA);
1532
1533                         outb(TS_INDEX, 0xa4);
1534                         *sp++ = inb(TS_DATA);
1535
1536                         outb(TS_INDEX, 0xe0);
1537                         *sp++ = inb(TS_DATA);
1538
1539                         outb(TS_INDEX, 0xe4);
1540                         *sp++ = inb(TS_DATA);
1541
1542                         outb(TS_INDEX, 0xf8);
1543                         *sp++ = inb(TS_DATA);
1544
1545                         outb(TS_INDEX, 0xfd);
1546                         *sp++ = inb(TS_DATA);
1547
1548                         *sp++ = inb(GN_MISCOUTR);       /* Misc output register */
1549                 }
1550
1551                 /* setup chipset for 132 column operation */
1552
1553                 outb(addr_6845, 0x00);  /* Horizontal Total */
1554                 outb(addr_6845+1, 0x9c);
1555                 outb(addr_6845, 0x01);  /* Horizontal Display End */
1556                 outb(addr_6845+1, 0x83);
1557                 outb(addr_6845, 0x02);  /* Horizontal Blank Start */
1558                 outb(addr_6845+1, 0x86);
1559                 outb(addr_6845, 0x03);  /* Horizontal Blank End */
1560                 outb(addr_6845+1, 0x9e);
1561                 outb(addr_6845, 0x04);  /* Horizontal Retrace Start */
1562                 outb(addr_6845+1, 0x89);
1563                 outb(addr_6845, 0x05);  /* Horizontal Retrace End */
1564                 outb(addr_6845+1, 0x1c);
1565
1566                 outb(addr_6845, 0x13);  /* Row Offset Register */
1567                 outb(addr_6845+1, 0x42);
1568
1569                 outb(TS_INDEX, TS_MODE);/* Timing Sequencer */
1570                 outb(TS_DATA, 0x01);    /* 8 dot char clock */
1571
1572                 if(color)
1573                         inb(GN_INPSTAT1C);
1574                 else
1575                         inb(GN_INPSTAT1M);
1576                 outb(ATC_INDEX, ATC_MODE | ATC_ACCESS); /* ATC Mode control */
1577                 outb(ATC_DATAW, 0x08);  /* Line graphics disable */
1578
1579                 if(color)
1580                         inb(GN_INPSTAT1C);
1581                 else
1582                         inb(GN_INPSTAT1M);
1583                 outb(ATC_INDEX, ATC_HORPIXPAN | ATC_ACCESS); /* ATC Horizontal Pixel Panning */
1584                 outb(ATC_DATAW, 0x00);
1585
1586                 outb(TS_INDEX, TS_SYNCRESET);
1587                 outb(TS_DATA, 0x01);    /* synchronous reset */
1588
1589                 outb(TS_INDEX, 0x83);
1590                 outb(TS_DATA, 0xa0);
1591
1592                 outb(TS_INDEX, 0xa4);
1593                 outb(TS_DATA, 0x1c);
1594
1595                 outb(TS_INDEX, 0xe0);
1596                 outb(TS_DATA, 0x00);
1597
1598                 outb(TS_INDEX, 0xe4);
1599                 outb(TS_DATA, 0xfe);
1600
1601                 outb(TS_INDEX, 0xf8);
1602                 outb(TS_DATA, 0x1b);
1603
1604                 outb(TS_INDEX, 0xfd);
1605                 outb(TS_DATA, 0x33);
1606
1607                 byte = inb(GN_MISCOUTR);
1608                 byte |= 0x0c;
1609                 outb(GN_MISCOUTW, byte);        /* Misc output register */
1610
1611                 outb(TS_INDEX, TS_SYNCRESET);
1612                 outb(TS_DATA, 0x03);    /* clear synchronous reset */
1613         }
1614         else    /* switch 132 -> 80 */
1615         {
1616                 if(!regsaved)                   /* failsafe */
1617                 {
1618                         outb(TS_INDEX, TS_EXTCNTL);     /* disable extensions */
1619                         outb(TS_DATA, 0xae);
1620
1621                         /* disable access to first 7 CRTC registers */
1622                         outb(addr_6845, CRTC_VSYNCE);
1623                         outb(addr_6845+1, byte);
1624                         vga_screen_on();
1625                         return(0);
1626                 }
1627
1628                 sp = savearea.v7_1024i;
1629
1630                 outb(addr_6845, 0x00);  /* Horizontal Total */
1631                 outb(addr_6845+1, *sp++);
1632                 outb(addr_6845, 0x01);  /* Horizontal Display End */
1633                 outb(addr_6845+1, *sp++);
1634                 outb(addr_6845, 0x02);  /* Horizontal Blank Start */
1635                 outb(addr_6845+1, *sp++);
1636                 outb(addr_6845, 0x03);  /* Horizontal Blank End */
1637                 outb(addr_6845+1, *sp++);
1638                 outb(addr_6845, 0x04);  /* Horizontal Retrace Start */
1639                 outb(addr_6845+1, *sp++);
1640                 outb(addr_6845, 0x05);  /* Horizontal Retrace End */
1641                 outb(addr_6845+1, *sp++);
1642
1643                 outb(addr_6845, 0x13);  /* Row Offset Register */
1644                 outb(addr_6845+1, *sp++);
1645
1646                 outb(TS_INDEX, TS_MODE);/* Timing Sequencer */
1647                 outb(TS_DATA, *sp++);
1648
1649                 if(color)
1650                         inb(GN_INPSTAT1C);
1651                 else
1652                         inb(GN_INPSTAT1M);
1653                 /* ATC Mode control */
1654                 outb(ATC_INDEX, ATC_MODE | ATC_ACCESS);
1655                 outb(ATC_DATAW, *sp++);
1656
1657                 if(color)
1658                         inb(GN_INPSTAT1C);
1659                 else
1660                         inb(GN_INPSTAT1M);
1661                 /* ATC Horizontal Pixel Panning */
1662                 outb(ATC_INDEX, ATC_HORPIXPAN | ATC_ACCESS);
1663                 outb(ATC_DATAW, *sp++);
1664
1665                 outb(TS_INDEX, TS_SYNCRESET);
1666                 outb(TS_DATA, 0x01);    /* synchronous reset */
1667
1668                 outb(TS_INDEX, 0x83);
1669                 outb(TS_DATA, *sp++);
1670
1671                 outb(TS_INDEX, 0xa4);
1672                 outb(TS_DATA, *sp++);
1673
1674                 outb(TS_INDEX, 0xe0);
1675                 outb(TS_DATA, *sp++);
1676
1677                 outb(TS_INDEX, 0xe4);
1678                 outb(TS_DATA, *sp++);
1679
1680                 outb(TS_INDEX, 0xf8);
1681                 outb(TS_DATA, *sp++);
1682
1683                 outb(TS_INDEX, 0xfd);
1684                 outb(TS_DATA, *sp++);
1685
1686                 outb(GN_MISCOUTW, *sp++);       /* Misc output register */
1687
1688                 outb(TS_INDEX, TS_SYNCRESET);
1689                 outb(TS_DATA, 0x03);    /* clear synchronous reset */
1690         }
1691
1692         outb(TS_INDEX, TS_EXTCNTL);     /* disable extensions */
1693         outb(TS_DATA, 0xae);
1694
1695         /* disable access to first 7 CRTC registers */
1696
1697         outb(addr_6845, CRTC_VSYNCE);
1698         outb(addr_6845+1, save__byte);
1699
1700         vga_screen_on();
1701
1702         return(1);
1703 }
1704
1705 /*---------------------------------------------------------------------------*
1706  *      toggle 80/132 column operation for S3 86C928 based boards
1707  *---------------------------------------------------------------------------*/
1708 int
1709 s3_928_col(int cols)
1710 {
1711         u_char *sp;
1712         u_char byte;
1713
1714         vga_screen_off();
1715
1716         outb(addr_6845, 0x38);
1717         outb(addr_6845+1, 0x48);        /* unlock registers */
1718         outb(addr_6845, 0x39);
1719         outb(addr_6845+1, 0xa0);        /* unlock registers */
1720
1721         /* enable access to first 7 CRTC registers */
1722
1723         outb(addr_6845, CRTC_VSYNCE);
1724         byte = inb(addr_6845+1);
1725         outb(addr_6845, CRTC_VSYNCE);
1726         outb(addr_6845+1, byte & 0x7f);
1727
1728         if(cols == SCR_COL132)          /* switch 80 -> 132 */
1729         {
1730                 /* save state of board for 80 columns */
1731
1732                 if(!regsaved)
1733                 {
1734                         regsaved = 1;
1735
1736                         sp = savearea.s3_928;
1737
1738                         outb(addr_6845, 0x00);  /* Horizontal Total */
1739                         *sp++ = inb(addr_6845+1);
1740                         outb(addr_6845, 0x01);  /* Horizontal Display End */
1741                         *sp++ = inb(addr_6845+1);
1742                         outb(addr_6845, 0x02);  /* Horizontal Blank Start */
1743                         *sp++ = inb(addr_6845+1);
1744                         outb(addr_6845, 0x03);  /* Horizontal Blank End */
1745                         *sp++ = inb(addr_6845+1);
1746                         outb(addr_6845, 0x04);  /* Horizontal Retrace Start */
1747                         *sp++ = inb(addr_6845+1);
1748                         outb(addr_6845, 0x05);  /* Horizontal Retrace End */
1749                         *sp++ = inb(addr_6845+1);
1750
1751                         outb(addr_6845, 0x13);  /* Row Offset Register */
1752                         *sp++ = inb(addr_6845+1);
1753
1754                         outb(addr_6845, 0x34);  /* Backward Compat 3 Reg */
1755                         *sp++ = inb(addr_6845+1);
1756                         outb(addr_6845, 0x3b);  /* Data Xfer Exec Position */
1757                         *sp++ = inb(addr_6845+1);
1758
1759                         outb(addr_6845, 0x42);  /* (Clock) Mode Control */
1760                         *sp++ = inb(addr_6845+1);
1761
1762                         outb(TS_INDEX, TS_MODE);/* Timing Sequencer */
1763                         *sp++ = inb(TS_DATA);
1764
1765                         if(color)
1766                                 inb(GN_INPSTAT1C);
1767                         else
1768                                 inb(GN_INPSTAT1M);
1769                         /* ATC Mode control */
1770                         outb(ATC_INDEX, ATC_MODE | ATC_ACCESS);
1771                         *sp++ = inb(ATC_DATAR);
1772
1773                         if(color)
1774                                 inb(GN_INPSTAT1C);
1775                         else
1776                                 inb(GN_INPSTAT1M);
1777                         /* ATC Horizontal Pixel Panning */
1778                         outb(ATC_INDEX, ATC_HORPIXPAN | ATC_ACCESS);
1779                         *sp++ = inb(ATC_DATAR);
1780
1781                         *sp++ = inb(GN_MISCOUTR);       /* Misc output register */
1782                 }
1783
1784                 /* setup chipset for 132 column operation */
1785
1786                 outb(addr_6845, 0x00);  /* Horizontal Total */
1787                 outb(addr_6845+1, 0x9a);
1788                 outb(addr_6845, 0x01);  /* Horizontal Display End */
1789                 outb(addr_6845+1, 0x83);
1790                 outb(addr_6845, 0x02);  /* Horizontal Blank Start */
1791                 outb(addr_6845+1, 0x86);
1792                 outb(addr_6845, 0x03);  /* Horizontal Blank End */
1793                 outb(addr_6845+1, 0x9d);
1794                 outb(addr_6845, 0x04);  /* Horizontal Retrace Start */
1795                 outb(addr_6845+1, 0x87);
1796                 outb(addr_6845, 0x05);  /* Horizontal Retrace End */
1797                 outb(addr_6845+1, 0x1b);
1798
1799                 outb(addr_6845, 0x13);  /* Row Offset Register */
1800                 outb(addr_6845+1, 0x42);
1801
1802                 outb(addr_6845, 0x34);
1803                 outb(addr_6845+1, 0x10);/* enable data xfer pos control */
1804                 outb(addr_6845, 0x3b);
1805                 outb(addr_6845+1, 0x90);/* set data xfer pos value */
1806
1807                 outb(addr_6845, 0x42);  /* (Clock) Mode Control */
1808                 outb(addr_6845+1, 0x02);/* Select 40MHz Clock */
1809
1810                 outb(TS_INDEX, TS_MODE);/* Timing Sequencer */
1811                 outb(TS_DATA, 0x01);    /* 8 dot char clock */
1812
1813                 if(color)
1814                         inb(GN_INPSTAT1C);
1815                 else
1816                         inb(GN_INPSTAT1M);
1817                 outb(ATC_INDEX, ATC_MODE | ATC_ACCESS); /* ATC Mode control */
1818                 outb(ATC_DATAW, 0x08);  /* Line graphics disable */
1819
1820                 if(color)
1821                         inb(GN_INPSTAT1C);
1822                 else
1823                         inb(GN_INPSTAT1M);
1824                 outb(ATC_INDEX, ATC_HORPIXPAN | ATC_ACCESS); /* ATC Horizontal Pixel Panning */
1825                 outb(ATC_DATAW, 0x00);
1826
1827                 /* Misc output register */
1828
1829                 outb(GN_MISCOUTW, (inb(GN_MISCOUTR) | 0x0c));
1830         }
1831         else    /* switch 132 -> 80 */
1832         {
1833                 if(!regsaved)                   /* failsafe */
1834                 {
1835                         /* disable access to first 7 CRTC registers */
1836                         outb(addr_6845, CRTC_VSYNCE);
1837                         outb(addr_6845+1, byte);
1838
1839                         outb(addr_6845, 0x38);
1840                         outb(addr_6845+1, 0x00);        /* lock registers */
1841                         outb(addr_6845, 0x39);
1842                         outb(addr_6845+1, 0x00);        /* lock registers */
1843
1844                         vga_screen_on();
1845                         return(0);
1846                 }
1847
1848                 sp = savearea.s3_928;
1849
1850                 outb(addr_6845, 0x00);  /* Horizontal Total */
1851                 outb(addr_6845+1, *sp++);
1852                 outb(addr_6845, 0x01);  /* Horizontal Display End */
1853                 outb(addr_6845+1, *sp++);
1854                 outb(addr_6845, 0x02);  /* Horizontal Blank Start */
1855                 outb(addr_6845+1, *sp++);
1856                 outb(addr_6845, 0x03);  /* Horizontal Blank End */
1857                 outb(addr_6845+1, *sp++);
1858                 outb(addr_6845, 0x04);  /* Horizontal Retrace Start */
1859                 outb(addr_6845+1, *sp++);
1860                 outb(addr_6845, 0x05);  /* Horizontal Retrace End */
1861                 outb(addr_6845+1, *sp++);
1862
1863                 outb(addr_6845, 0x13);  /* Row Offset Register */
1864                 outb(addr_6845+1, *sp++);
1865
1866                 outb(addr_6845, 0x34);
1867                 outb(addr_6845+1, *sp++);
1868                 outb(addr_6845, 0x3b);
1869                 outb(addr_6845+1, *sp++);
1870
1871                 outb(addr_6845, 0x42);  /* Mode control */
1872                 outb(addr_6845+1, *sp++);
1873
1874                 outb(TS_INDEX, TS_MODE);/* Timing Sequencer */
1875                 outb(TS_DATA, *sp++);
1876
1877                 if(color)
1878                         inb(GN_INPSTAT1C);
1879                 else
1880                         inb(GN_INPSTAT1M);
1881                 /* ATC Mode control */
1882                 outb(ATC_INDEX, ATC_MODE | ATC_ACCESS);
1883                 outb(ATC_DATAW, *sp++);
1884
1885                 if(color)
1886                         inb(GN_INPSTAT1C);
1887                 else
1888                         inb(GN_INPSTAT1M);
1889                 /* ATC Horizontal Pixel Panning */
1890                 outb(ATC_INDEX, ATC_HORPIXPAN | ATC_ACCESS);
1891                 outb(ATC_DATAW, *sp++);
1892
1893                 outb(GN_MISCOUTW, *sp++);       /* Misc output register */
1894         }
1895
1896         /* disable access to first 7 CRTC registers */
1897
1898         outb(addr_6845, CRTC_VSYNCE);
1899         outb(addr_6845+1, byte);
1900
1901         outb(addr_6845, 0x38);
1902         outb(addr_6845+1, 0x00);        /* lock registers */
1903         outb(addr_6845, 0x39);
1904         outb(addr_6845+1, 0x00);        /* lock registers */
1905
1906         vga_screen_on();
1907
1908         return(1);
1909 }
1910
1911 /*---------------------------------------------------------------------------*
1912  *      toggle 80/132 column operation for Cirrus Logic 542x based boards
1913  *---------------------------------------------------------------------------*/
1914 int
1915 cl_gd542x_col(int cols)
1916 {
1917         u_char *sp;
1918         u_char byte;
1919
1920         vga_screen_off();
1921
1922         /* enable access to first 7 CRTC registers */
1923
1924         outb(addr_6845, CRTC_VSYNCE);
1925         byte = inb(addr_6845+1);
1926         outb(addr_6845, CRTC_VSYNCE);
1927         outb(addr_6845+1, byte & 0x7f);
1928
1929         /* enable access to cirrus extension registers */
1930         outb(TS_INDEX, 6);
1931         outb(TS_DATA, 0x12);
1932
1933         if(cols == SCR_COL132)          /* switch 80 -> 132 */
1934         {
1935                 /* save state of board for 80 columns */
1936
1937                 if(!regsaved)
1938                 {
1939                         regsaved = 1;
1940
1941                         sp = savearea.cirrus;
1942
1943                         outb(addr_6845, 0x00);  /* Horizontal Total */
1944                         *sp++ = inb(addr_6845+1);
1945                         outb(addr_6845, 0x01);  /* Horizontal Display End */
1946                         *sp++ = inb(addr_6845+1);
1947                         outb(addr_6845, 0x02);  /* Horizontal Blank Start */
1948                         *sp++ = inb(addr_6845+1);
1949                         outb(addr_6845, 0x03);  /* Horizontal Blank End */
1950                         *sp++ = inb(addr_6845+1);
1951                         outb(addr_6845, 0x04);  /* Horizontal Retrace Start */
1952                         *sp++ = inb(addr_6845+1);
1953                         outb(addr_6845, 0x05);  /* Horizontal Retrace End */
1954                         *sp++ = inb(addr_6845+1);
1955
1956                         outb(addr_6845, 0x13);  /* Row Offset Register */
1957                         *sp++ = inb(addr_6845+1);
1958
1959                         outb(TS_INDEX, TS_MODE);/* Timing Sequencer */
1960                         *sp++ = inb(TS_DATA);
1961
1962
1963                         if(color)
1964                                 inb(GN_INPSTAT1C);
1965                         else
1966                                 inb(GN_INPSTAT1M);
1967                         /* ATC Mode control */
1968                         outb(ATC_INDEX, ATC_MODE | ATC_ACCESS);
1969                         *sp++ = inb(ATC_DATAR);
1970
1971                         if(color)
1972                                 inb(GN_INPSTAT1C);
1973                         else
1974                                 inb(GN_INPSTAT1M);
1975                         /* ATC Horizontal Pixel Panning */
1976                         outb(ATC_INDEX, ATC_HORPIXPAN | ATC_ACCESS);
1977                         *sp++ = inb(ATC_DATAR);
1978
1979                         /* VCLK2 Numerator Register */
1980                         outb(TS_INDEX, 0xd);
1981                         *sp++ = inb(TS_DATA);
1982
1983                         /* VCLK2 Denominator and Post-Scalar Value Register */
1984                         outb(TS_INDEX, 0x1d);
1985                         *sp++ = inb(TS_DATA);
1986
1987                         /* Misc output register */
1988                         *sp++ = inb(GN_MISCOUTR);
1989                 }
1990
1991                 /* setup chipset for 132 column operation */
1992
1993                 outb(addr_6845, 0x00);  /* Horizontal Total */
1994                 outb(addr_6845+1, 0x9f);
1995                 outb(addr_6845, 0x01);  /* Horizontal Display End */
1996                 outb(addr_6845+1, 0x83);
1997                 outb(addr_6845, 0x02);  /* Horizontal Blank Start */
1998                 outb(addr_6845+1, 0x84);
1999                 outb(addr_6845, 0x03);  /* Horizontal Blank End */
2000                 outb(addr_6845+1, 0x82);
2001                 outb(addr_6845, 0x04);  /* Horizontal Retrace Start */
2002                 outb(addr_6845+1, 0x8a);
2003                 outb(addr_6845, 0x05);  /* Horizontal Retrace End */
2004                 outb(addr_6845+1, 0x9e);
2005
2006                 outb(addr_6845, 0x13);  /* Row Offset Register */
2007                 outb(addr_6845+1, 0x42);
2008
2009                 /* set VCLK2 to 41.164 MHz ..... */
2010                 outb(TS_INDEX, 0xd);    /* VCLK2 Numerator Register */
2011                 outb(TS_DATA, 0x45);
2012
2013                 outb(TS_INDEX, 0x1d);   /* VCLK2 Denominator and */
2014                 outb(TS_DATA, 0x30);   /* Post-Scalar Value Register */
2015
2016                 /* and use it. */
2017                 outb(GN_MISCOUTW, (inb(GN_MISCOUTR) & ~0x0c) | (2 << 2));
2018
2019                 outb(TS_INDEX, TS_MODE);/* Timing Sequencer */
2020                 outb(TS_DATA, 0x01);    /* 8 dot char clock */
2021
2022                 if(color)
2023                         inb(GN_INPSTAT1C);
2024                 else
2025                         inb(GN_INPSTAT1M);
2026                 outb(ATC_INDEX, ATC_MODE | ATC_ACCESS); /* ATC Mode control */
2027                 outb(ATC_DATAW, 0x08);  /* Line graphics disable */
2028
2029                 if(color)
2030                         inb(GN_INPSTAT1C);
2031                 else
2032                         inb(GN_INPSTAT1M);
2033                 outb(ATC_INDEX, ATC_HORPIXPAN | ATC_ACCESS); /* ATC Horizontal Pixel Panning */
2034                 outb(ATC_DATAW, 0x00);
2035         }
2036         else    /* switch 132 -> 80 */
2037         {
2038                 if(!regsaved)                   /* failsafe */
2039                 {
2040                         /* disable access to first 7 CRTC registers */
2041                         outb(addr_6845, CRTC_VSYNCE);
2042                         outb(addr_6845+1, byte);
2043
2044                         /* disable access to cirrus extension registers */
2045                         outb(TS_INDEX, 6);
2046                         outb(TS_DATA, 0);
2047
2048                         vga_screen_on();
2049                         return(0);
2050                 }
2051
2052                 sp = savearea.cirrus;
2053
2054                 outb(addr_6845, 0x00);  /* Horizontal Total */
2055                 outb(addr_6845+1, *sp++);
2056                 outb(addr_6845, 0x01);  /* Horizontal Display End */
2057                 outb(addr_6845+1, *sp++);
2058                 outb(addr_6845, 0x02);  /* Horizontal Blank Start */
2059                 outb(addr_6845+1, *sp++);
2060                 outb(addr_6845, 0x03);  /* Horizontal Blank End */
2061                 outb(addr_6845+1, *sp++);
2062                 outb(addr_6845, 0x04);  /* Horizontal Retrace Start */
2063                 outb(addr_6845+1, *sp++);
2064                 outb(addr_6845, 0x05);  /* Horizontal Retrace End */
2065                 outb(addr_6845+1, *sp++);
2066
2067                 outb(addr_6845, 0x13);  /* Row Offset Register */
2068                 outb(addr_6845+1, *sp++);
2069
2070                 outb(TS_INDEX, TS_MODE);/* Timing Sequencer */
2071                 outb(TS_DATA, *sp++);
2072
2073                 if(color)
2074                         inb(GN_INPSTAT1C);
2075                 else
2076                         inb(GN_INPSTAT1M);
2077                 /* ATC Mode control */
2078                 outb(ATC_INDEX, ATC_MODE | ATC_ACCESS);
2079                 outb(ATC_DATAW, *sp++);
2080
2081                 if(color)
2082                         inb(GN_INPSTAT1C);
2083                 else
2084                         inb(GN_INPSTAT1M);
2085                 /* ATC Horizontal Pixel Panning */
2086                 outb(ATC_INDEX, ATC_HORPIXPAN | ATC_ACCESS);
2087                 outb(ATC_DATAW, *sp++);
2088
2089                 /* VCLK2 Numerator Register */
2090                 outb(TS_INDEX, 0xd);
2091                 outb(TS_DATA, *sp++);
2092
2093                 /* VCLK2 Denominator and Post-Scalar Value Register */
2094                 outb(TS_INDEX, 0x1d);
2095                 outb(TS_DATA, *sp++);
2096
2097                 outb(GN_MISCOUTW, *sp++);       /* Misc output register */
2098         }
2099
2100         /* disable access to cirrus extension registers */
2101         outb(TS_INDEX, 6);
2102         outb(TS_DATA, 0);
2103
2104         /* disable access to first 7 CRTC registers */
2105
2106         outb(addr_6845, CRTC_VSYNCE);
2107         outb(addr_6845+1, byte);
2108
2109         vga_screen_on();
2110
2111         return(1);
2112 }
2113
2114 #if PCVT_USL_VT_COMPAT
2115 /*---------------------------------------------------------------------------*
2116  *      switch screen from text mode to X-mode and vice versa
2117  *---------------------------------------------------------------------------*/
2118 void
2119 switch_screen(int n, int oldgrafx, int newgrafx)
2120 {
2121
2122 #if PCVT_SCREENSAVER
2123         static unsigned saved_scrnsv_tmo = 0;
2124 #endif  /* PCVT_SCREENSAVER */
2125
2126 #if !PCVT_KBD_FIFO
2127         int x;
2128 #endif  /* !PCVT_KBD_FIFO */
2129
2130         int cols = vsp->maxcol;         /* get current col val */
2131
2132         if(n < 0 || n >= totalscreens)
2133                 return;
2134
2135 #if !PCVT_KBD_FIFO
2136         x = spltty();                   /* protect us */
2137 #endif  /* !PCVT_KBD_FIFO */
2138
2139         if(!oldgrafx && newgrafx)
2140         {
2141                 /* switch from text to graphics */
2142
2143 #if PCVT_SCREENSAVER
2144                 if((saved_scrnsv_tmo = scrnsv_timeout))
2145                         pcvt_set_scrnsv_tmo(0); /* screensaver off */
2146 #endif /* PCVT_SCREENSAVER */
2147
2148                 async_update(UPDATE_STOP);      /* status display off */
2149         }
2150
2151         if(!oldgrafx)
2152         {
2153                 /* switch from text mode */
2154
2155                 /* video board memory -> kernel memory */
2156                 bcopy(vsp->Crtat, vsp->Memory,
2157                       vsp->screen_rows * vsp->maxcol * CHR);
2158
2159                 vsp->Crtat = vsp->Memory;       /* operate in memory now */
2160         }
2161
2162         /* update global screen pointers/variables */
2163         current_video_screen = n;       /* current screen no */
2164
2165 #if !PCVT_NETBSD && !(PCVT_FREEBSD > 110 && PCVT_FREEBSD < 200)
2166         pcconsp = &pccons[n];           /* current tty */
2167 #elif PCVT_FREEBSD > 110 && PCVT_FREEBSD < 200
2168         pcconsp = pccons[n];            /* current tty */
2169 #else
2170         pcconsp = pc_tty[n];            /* current tty */
2171 #endif
2172
2173         vsp = &vs[n];                   /* current video state ptr */
2174
2175         if(oldgrafx && !newgrafx)
2176         {
2177                 /* switch from graphics to text mode */
2178                 unsigned i;
2179
2180                 /* restore fonts */
2181                 for(i = 0; i < totalfonts; i++)
2182                         if(saved_charsets[i])
2183                                 vga_move_charset(i, 0, 0);
2184
2185 #if PCVT_SCREENSAVER
2186                 /* activate screen saver */
2187                 if(saved_scrnsv_tmo)
2188                         pcvt_set_scrnsv_tmo(saved_scrnsv_tmo);
2189 #endif /* PCVT_SCREENSAVER */
2190
2191                 /* re-initialize lost MDA information */
2192                 if(adaptor_type == MDA_ADAPTOR)
2193                 {
2194                     /*
2195                      * Due to the fact that HGC registers are write-only,
2196                      * the Xserver can only make guesses about the state
2197                      * the HGC adaptor has been before turning on X mode.
2198                      * Thus, the display must be re-enabled now, and the
2199                      * cursor shape and location restored.
2200                      */
2201                     outb(GN_DMCNTLM, 0x28); /* enable display, text mode */
2202                     outb(addr_6845, CRTC_CURSORH); /* select high register */
2203                     outb(addr_6845+1,
2204                          ((vsp->Crtat + vsp->cur_offset) - Crtat) >> 8);
2205                     outb(addr_6845, CRTC_CURSORL); /* select low register */
2206                     outb(addr_6845+1,
2207                          ((vsp->Crtat + vsp->cur_offset) - Crtat));
2208
2209                     outb(addr_6845, CRTC_CURSTART); /* select high register */
2210                     outb(addr_6845+1, vsp->cursor_start);
2211                     outb(addr_6845, CRTC_CUREND); /* select low register */
2212                     outb(addr_6845+1, vsp->cursor_end);
2213                 }
2214
2215                 /* make status display happy */
2216                 async_update(UPDATE_START);
2217         }
2218
2219         if(!newgrafx)
2220         {
2221                 /* to text mode */
2222
2223                 /* kernel memory -> video board memory */
2224                 bcopy(vsp->Crtat, Crtat,
2225                       vsp->screen_rows * vsp->maxcol * CHR);
2226
2227                 vsp->Crtat = Crtat;             /* operate on screen now */
2228
2229                 outb(addr_6845, CRTC_STARTADRH);
2230                 outb(addr_6845+1, 0);
2231                 outb(addr_6845, CRTC_STARTADRL);
2232                 outb(addr_6845+1, 0);
2233         }
2234
2235 #if !PCVT_KBD_FIFO
2236         splx(x);
2237 #endif  /* !PCVT_KBD_FIFO */
2238
2239         select_vga_charset(vsp->vga_charset);
2240
2241         if(vsp->maxcol != cols)
2242                 vga_col(vsp, vsp->maxcol);      /* select 80/132 columns */
2243
2244         outb(addr_6845, CRTC_CURSORH);  /* select high register */
2245         outb(addr_6845+1, vsp->cur_offset >> 8);
2246         outb(addr_6845, CRTC_CURSORL);  /* select low register */
2247         outb(addr_6845+1, vsp->cur_offset);
2248
2249         if(vsp->cursor_on)
2250         {
2251                 outb(addr_6845, CRTC_CURSTART); /* select high register */
2252                 outb(addr_6845+1, vsp->cursor_start);
2253                 outb(addr_6845, CRTC_CUREND);   /* select low register */
2254                 outb(addr_6845+1, vsp->cursor_end);
2255         }
2256         else
2257         {
2258                 sw_cursor(0);
2259         }
2260
2261         if(adaptor_type == VGA_ADAPTOR)
2262         {
2263                 unsigned i;
2264
2265                 /* switch VGA DAC palette entries */
2266                 for(i = 0; i < NVGAPEL; i++)
2267                         vgapaletteio(i, &vsp->palette[i], 1);
2268         }
2269
2270         if(!newgrafx)
2271         {
2272                 update_led();   /* update led's */
2273                 update_hp(vsp); /* update fkey labels, if present */
2274
2275                 /* if we switch to a vt with force 24 lines mode and    */
2276                 /* pure VT emulation and 25 rows charset, then we have  */
2277                 /* to clear the last line on display ...                */
2278
2279                 if(vsp->force24 && (vsp->vt_pure_mode == M_PUREVT) &&
2280                         (vgacs[vsp->vga_charset].screen_size == SIZ_25ROWS))
2281                 {
2282                         fillw(' ', vsp->Crtat + vsp->screen_rows * vsp->maxcol,
2283                                 vsp->maxcol);
2284                 }
2285         }
2286 }
2287
2288 /*---------------------------------------------------------------------------*
2289  *      Change specified vt to VT_AUTO mode
2290  *      xxx Maybe this should also reset VT_GRAFX mode; since switching and
2291  *      graphics modes are not going to work without VT_PROCESS mode.
2292  *---------------------------------------------------------------------------*/
2293 static void
2294 set_auto_mode (struct video_state *vsx)
2295 {
2296         unsigned ostatus = vsx->vt_status;
2297         vsx->smode.mode = VT_AUTO;
2298         vsx->proc = NULL;
2299         vsx->pid = 0;
2300         vsx->vt_status &= ~(VT_WAIT_REL|VT_WAIT_ACK);
2301         if (ostatus & VT_WAIT_ACK) {
2302 #if 0
2303                 assert (!(ostatus&VT_WAIT_REL));
2304                 assert (vsp == vsx &&
2305                         vt_switch_pending == current_video_screen + 1);
2306                 vt_switch_pending = 0;
2307 #else
2308                 if (vsp == vsx &&
2309                     vt_switch_pending == current_video_screen + 1)
2310                         vt_switch_pending = 0;
2311 #endif
2312         }
2313         if (ostatus&VT_WAIT_REL) {
2314                 int new_screen = vt_switch_pending - 1;
2315 #if 0
2316                 assert(vsp == vsx && vt_switch_pending);
2317                 vt_switch_pending = 0;
2318                 vgapage (new_screen);
2319 #else
2320                 if (vsp == vsx && vt_switch_pending) {
2321                         vt_switch_pending = 0;
2322                         vgapage (new_screen);
2323                 }
2324 #endif
2325         }
2326 }
2327
2328 /*---------------------------------------------------------------------------*
2329  *      Exported function; to be called when a vt is closed down.
2330  *
2331  *      Ideally, we would like to be able to recover from an X server crash;
2332  *      but in reality, if the server crashes hard while in control of the
2333  *      vga board, then you're not likely to be able to use pcvt ttys
2334  *      without rebooting.
2335  *---------------------------------------------------------------------------*/
2336 void
2337 reset_usl_modes (struct video_state *vsx)
2338 {
2339         /* Clear graphics mode */
2340         if (vsx->vt_status & VT_GRAFX) {
2341             vsx->vt_status &= ~VT_GRAFX;
2342             if (vsp == vsx)
2343                 switch_screen(current_video_screen, 1, 0);
2344         }
2345
2346         /* Take kbd out of raw mode */
2347         if (pcvt_kbd_raw && vsp == vsx) {
2348 #if PCVT_SCANSET > 1
2349                 kbd_emulate_pc(0);
2350 #endif /* PCVT_SCANSET > 1 */
2351                 pcvt_kbd_raw = 0;
2352         }
2353
2354         /* Clear process controlled mode */
2355         set_auto_mode (vsx);
2356 }
2357
2358 /*---------------------------------------------------------------------------*
2359  *      switch to virtual screen n (0 ... PCVT_NSCREENS-1), VT_USL version
2360  *      (the name vgapage() stands for historical reasons)
2361  *---------------------------------------------------------------------------*/
2362 int
2363 vgapage(int new_screen)
2364 {
2365         int x;
2366
2367         if(new_screen < 0 || new_screen >= totalscreens)
2368                 return EINVAL;
2369
2370         /* fallback to VT_AUTO if controlling processes died */
2371         if(vsp->proc && vsp->proc != pfind(vsp->pid))
2372                 set_auto_mode(vsp);
2373         if(vs[new_screen].proc
2374            && vs[new_screen].proc != pfind(vs[new_screen].pid))
2375                 set_auto_mode(&vs[new_screen]);
2376
2377         if (!vt_switch_pending && new_screen == current_video_screen)
2378                 return 0;
2379
2380         if(vt_switch_pending && vt_switch_pending != new_screen + 1) {
2381                 /* Try resignaling uncooperative X-window servers */
2382                 if (vsp->smode.mode == VT_PROCESS) {
2383                         if (vsp->vt_status & VT_WAIT_REL) {
2384                                 if(vsp->smode.relsig)
2385                                         psignal(vsp->proc, vsp->smode.relsig);
2386                         } else if (vsp->vt_status & VT_WAIT_ACK) {
2387                                 if(vsp->smode.acqsig)
2388                                         psignal(vsp->proc, vsp->smode.acqsig);
2389                         }
2390                 }
2391                 return EAGAIN;
2392         }
2393
2394         vt_switch_pending = new_screen + 1;
2395
2396         if(vsp->smode.mode == VT_PROCESS)
2397         {
2398                 /* we cannot switch immediately here */
2399                 vsp->vt_status |= VT_WAIT_REL;
2400                 if(vsp->smode.relsig)
2401                         psignal(vsp->proc, vsp->smode.relsig);
2402         }
2403         else
2404         {
2405                 struct video_state *old_vsp = vsp;
2406
2407                 switch_screen(new_screen,
2408                               vsp->vt_status & VT_GRAFX,
2409                               vs[new_screen].vt_status & VT_GRAFX);
2410
2411                 x = spltty();
2412                 if(old_vsp->vt_status & VT_WAIT_ACT)
2413                 {
2414                         old_vsp->vt_status &= ~VT_WAIT_ACT;
2415                         wakeup((caddr_t)&old_vsp->smode);
2416                 }
2417                 if(vsp->vt_status & VT_WAIT_ACT)
2418                 {
2419                         vsp->vt_status &= ~VT_WAIT_ACT;
2420                         wakeup((caddr_t)&vsp->smode);
2421                 }
2422                 splx(x);
2423
2424                 if(vsp->smode.mode == VT_PROCESS)
2425                 {
2426                         /* if _new_ vt is under process control... */
2427                         vsp->vt_status |= VT_WAIT_ACK;
2428                         if(vsp->smode.acqsig)
2429                                 psignal(vsp->proc, vsp->smode.acqsig);
2430                 }
2431                 else
2432                 {
2433                         /* we are committed */
2434                         vt_switch_pending = 0;
2435 #if PCVT_FREEBSD > 206
2436                         /*
2437                          * XXX: If pcvt is acting as the systems console,
2438                          * avoid panics going to the debugger while we are in
2439                          * process mode.
2440                          */
2441                         if(pcvt_is_console)
2442                                 cons_unavail = 0;
2443 #endif
2444                 }
2445         }
2446         return 0;
2447 }
2448
2449 /*---------------------------------------------------------------------------*
2450  *      ioctl handling for VT_USL mode
2451  *---------------------------------------------------------------------------*/
2452 int
2453 usl_vt_ioctl(Dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
2454 {
2455         int i, j, error, opri;
2456         struct vt_mode newmode;
2457
2458         switch(cmd)
2459         {
2460
2461         case VT_SETMODE:
2462                 newmode = *(struct vt_mode *)data;
2463
2464                 opri = spltty();
2465
2466                 if (newmode.mode != VT_PROCESS) {
2467                         struct video_state *vsx = &vs[minor(dev)];
2468                         if (vsx->smode.mode == VT_PROCESS) {
2469                                 if (vsx->proc != p) {
2470                                         splx(opri);
2471                                         return EPERM;
2472                                 }
2473                                 set_auto_mode(vsx);
2474                         }
2475                         splx(opri);
2476                         return 0;
2477                 }
2478
2479                 /*
2480                  * NB: XFree86-3.1.1 does the following:
2481                  *              VT_ACTIVATE (vtnum)
2482                  *              VT_WAITACTIVE (vtnum)
2483                  *              VT_SETMODE (VT_PROCESS)
2484                  * So it is possible that the screen was switched
2485                  * between the WAITACTIVE and the SETMODE (here).  This
2486                  * can actually happen quite frequently, and it was
2487                  * leading to dire consequences. Now it is detected by
2488                  * requiring that minor(dev) match current_video_screen.
2489                  * An alternative would be to operate on vs[minor(dev)]
2490                  * instead of *vsp, but that would leave the server
2491                  * confused, because it would believe that its vt was
2492                  * currently activated.
2493                  */
2494                 if (minor(dev) != current_video_screen) {
2495                         splx(opri);
2496                         return EPERM;
2497                 }
2498
2499                 /* Check for server died */
2500                 if(vsp->proc && vsp->proc != pfind(vsp->pid))
2501                         set_auto_mode(vsp);
2502
2503                 /* Check for server already running */
2504                 if (vsp->smode.mode == VT_PROCESS && vsp->proc != p)
2505                 {
2506                         splx(opri);
2507                         return EBUSY; /* already in use on this VT */
2508                 }
2509
2510                 if (!ISSIGVALID(newmode.relsig) || !ISSIGVALID(newmode.acqsig)
2511                     || !ISSIGVALID(newmode.frsig))
2512                 {
2513                         splx(opri);
2514                         return EINVAL;
2515                 }
2516
2517                 vsp->smode = newmode;
2518                 vsp->proc = p;
2519                 vsp->pid = p->p_pid;
2520
2521 #if PCVT_FREEBSD > 206
2522                 /*
2523                  * XXX: If pcvt is acting as the systems console,
2524                  * avoid panics going to the debugger while we are in
2525                  * process mode.
2526                  */
2527                 if(pcvt_is_console)
2528                         cons_unavail = (newmode.mode == VT_PROCESS);
2529 #endif
2530                 splx(opri);
2531                 return 0;
2532
2533         case VT_GETMODE:
2534                 *(struct vt_mode *)data = vsp->smode;
2535                 return 0;
2536
2537         case VT_RELDISP:
2538                 if (minor(dev) != current_video_screen)
2539                         return EPERM;
2540                 if (vsp->smode.mode != VT_PROCESS)
2541                         return EINVAL;
2542                 if (vsp->proc != p)
2543                         return EPERM;
2544                 switch(*(int *)data) {
2545                 case VT_FALSE:
2546                         /* process refuses to release screen; abort */
2547                         if(vt_switch_pending
2548                            && (vsp->vt_status & VT_WAIT_REL)) {
2549                                 vsp->vt_status &= ~VT_WAIT_REL;
2550                                 vt_switch_pending = 0;
2551                                 return 0;
2552                         }
2553                         break;
2554
2555                 case VT_TRUE:
2556                         /* process releases its VT */
2557                         if(vt_switch_pending
2558                            && (vsp->vt_status & VT_WAIT_REL)) {
2559                                 int new_screen = vt_switch_pending - 1;
2560                                 struct video_state *old_vsp = vsp;
2561
2562                                 vsp->vt_status &= ~VT_WAIT_REL;
2563
2564                                 switch_screen(new_screen,
2565                                               vsp->vt_status & VT_GRAFX,
2566                                               vs[new_screen].vt_status
2567                                               & VT_GRAFX);
2568
2569                                 opri = spltty();
2570                                 if(old_vsp->vt_status & VT_WAIT_ACT)
2571                                 {
2572                                         old_vsp->vt_status &= ~VT_WAIT_ACT;
2573                                         wakeup((caddr_t)&old_vsp->smode);
2574                                 }
2575                                 if(vsp->vt_status & VT_WAIT_ACT)
2576                                 {
2577                                         vsp->vt_status &= ~VT_WAIT_ACT;
2578                                         wakeup((caddr_t)&vsp->smode);
2579                                 }
2580                                 splx(opri);
2581
2582                                 if(vsp->smode.mode == VT_PROCESS) {
2583                                         /*
2584                                          * if the new vt is also in process
2585                                          * mode, we have to wait until its
2586                                          * controlling process acknowledged
2587                                          * the switch
2588                                          */
2589                                         vsp->vt_status
2590                                                 |= VT_WAIT_ACK;
2591                                         if(vsp->smode.acqsig)
2592                                                 psignal(vsp->proc,
2593                                                         vsp->smode.acqsig);
2594                                 }
2595                                 else
2596                                 {
2597                                         /* we are committed */
2598                                         vt_switch_pending = 0;
2599 #if PCVT_FREEBSD > 206
2600                                         /* XXX */
2601                                         if(pcvt_is_console)
2602                                                 cons_unavail = 0;
2603 #endif
2604                                 }
2605                                 return 0;
2606                         }
2607                         break;
2608
2609                 case VT_ACKACQ:
2610                         /* new vts controlling process acknowledged */
2611                         if(vsp->vt_status & VT_WAIT_ACK) {
2612                                 vt_switch_pending = 0;
2613                                 vsp->vt_status &= ~VT_WAIT_ACK;
2614 #if PCVT_FREEBSD > 206
2615                                 /* XXX */
2616                                 if(pcvt_is_console)
2617                                         cons_unavail = 1;
2618 #endif
2619                                 return 0;
2620                         }
2621                         break;
2622                 }
2623                 return EINVAL;  /* end case VT_RELDISP */
2624
2625
2626         case VT_OPENQRY:
2627                 /* return free vt */
2628                 for(i = 0; i < PCVT_NSCREENS; i++)
2629                         if(!vs[i].openf) {
2630                                 *(int *)data = i + 1;
2631                                 return 0;
2632                         }
2633                 return EAGAIN;
2634
2635         case VT_GETACTIVE:
2636                 *(int *)data = current_video_screen + 1;
2637                 return 0;
2638
2639         case VT_ACTIVATE:
2640                 return vgapage(*(int *)data - 1);
2641
2642         case VT_WAITACTIVE:
2643                 /* sleep until vt switch happened */
2644                 i = *(int *)data - 1;
2645
2646                 if(i != -1
2647                    && (i < 0 || i >= PCVT_NSCREENS))
2648                         return EINVAL;
2649
2650                 if(i != -1 && current_video_screen == i)
2651                         return 0;
2652
2653                 if(i == -1)
2654                         i = minor(dev);
2655
2656                 {
2657                         int x = spltty();
2658                         error = 0;
2659                         while (current_video_screen != i &&
2660                                (error == 0 || error == ERESTART))
2661                         {
2662                                 vs[i].vt_status |= VT_WAIT_ACT;
2663                                 error = tsleep((caddr_t)&vs[i].smode,
2664                                                PZERO | PCATCH, "waitvt", 0);
2665                         }
2666                         splx(x);
2667                 }
2668                 return error;
2669
2670         case KDENABIO:
2671                 /* grant the process IO access; only allowed if euid == 0 */
2672                 /* and insecure */
2673         {
2674
2675 #if PCVT_NETBSD > 9 || PCVT_FREEBSD >= 200
2676                 struct trapframe *fp = p->p_md.md_regs;
2677 #elif PCVT_NETBSD || (PCVT_FREEBSD && PCVT_FREEBSD > 102)
2678                 struct trapframe *fp = (struct trapframe *)p->p_regs;
2679 #else
2680                 struct syscframe *fp = (struct syscframe *)p->p_regs;
2681 #endif
2682
2683                 error = suser(p);
2684                 if (error != 0)
2685                         return (error);
2686                 if (securelevel > 0)
2687                         return (EPERM);
2688
2689 #if PCVT_NETBSD || (PCVT_FREEBSD && PCVT_FREEBSD > 102)
2690                 fp->tf_eflags |= PSL_IOPL;
2691 #else
2692                 fp->sf_eflags |= PSL_IOPL;
2693 #endif
2694
2695                 return 0;
2696         }
2697
2698         case KDDISABIO:
2699                 /* abandon IO access permission */
2700         {
2701
2702 #if PCVT_NETBSD > 9 || PCVT_FREEBSD >= 200
2703                 struct trapframe *fp = p->p_md.md_regs;
2704                 fp->tf_eflags &= ~PSL_IOPL;
2705 #elif PCVT_NETBSD || (PCVT_FREEBSD && PCVT_FREEBSD > 102)
2706                 struct trapframe *fp = (struct trapframe *)p->p_regs;
2707                 fp->tf_eflags &= ~PSL_IOPL;
2708 #else
2709                 struct syscframe *fp = (struct syscframe *)p->p_regs;
2710                 fp->sf_eflags &= ~PSL_IOPL;
2711 #endif
2712
2713                 return 0;
2714         }
2715
2716         case KDSETMODE:
2717         {
2718                 struct video_state *vsx = &vs[minor(dev)];
2719                 int haschanged = 0;
2720
2721                 if(adaptor_type != VGA_ADAPTOR
2722                    && adaptor_type != MDA_ADAPTOR)
2723                         /* X will only run on those adaptors */
2724                         return (EINVAL);
2725
2726                 /* set text/graphics mode of current vt */
2727                 switch(*(int *)data)
2728                 {
2729                 case KD_TEXT:
2730                         haschanged = (vsx->vt_status & VT_GRAFX) != 0;
2731                         vsx->vt_status &= ~VT_GRAFX;
2732                         if(haschanged && vsx == vsp)
2733                                 switch_screen(current_video_screen, 1, 0);
2734                         return 0;
2735
2736                 case KD_GRAPHICS:
2737                         /* xxx It might be a good idea to require that
2738                            the vt be in process controlled mode here,
2739                            and that the calling process is the owner */
2740                         haschanged = (vsx->vt_status & VT_GRAFX) == 0;
2741                         vsx->vt_status |= VT_GRAFX;
2742                         if(haschanged && vsx == vsp)
2743                                 switch_screen(current_video_screen, 0, 1);
2744                         return 0;
2745
2746                 }
2747                 return EINVAL;  /* end case KDSETMODE */
2748         }
2749
2750         case KDSETRAD:
2751                 /* set keyboard repeat and delay */
2752                 return kbdioctl(dev, KBDSTPMAT, data, flag);
2753
2754         case KDSKBMODE:
2755                 switch(*(int *)data)
2756                 {
2757                 case K_RAW:
2758
2759 #if PCVT_SCANSET > 1
2760                         /* put keyboard to return ancient PC scan codes */
2761                         kbd_emulate_pc(1);
2762 #endif /* PCVT_SCANSET > 1 */
2763
2764                         pcvt_kbd_raw = 1;
2765                         shift_down = meta_down = altgr_down = ctrl_down = 0;
2766                         return 0;
2767
2768                 case K_XLATE:
2769
2770 #if PCVT_SCANSET > 1
2771                         kbd_emulate_pc(0);
2772 #endif /* PCVT_SCANSET > 1 */
2773
2774                         pcvt_kbd_raw = 0;
2775                         return 0;
2776                 }
2777                 return EINVAL;  /* end KDSKBMODE */
2778
2779         case KDMKTONE:
2780                 /* ring the speaker */
2781                 if(data)
2782                 {
2783                         int duration = *(int *)data >> 16;
2784                         int pitch = *(int *)data & 0xffff;
2785
2786 #if PCVT_NETBSD
2787                         if(pitch != 0)
2788                         {
2789                             sysbeep(PCVT_SYSBEEPF / pitch,
2790                                     duration * hz / 1000);
2791                         }
2792 #else /* PCVT_NETBSD */
2793                         sysbeep(pitch, duration * hz / 3000);
2794 #endif /* PCVT_NETBSD */
2795
2796                 }
2797                 else
2798                 {
2799                         sysbeep(PCVT_SYSBEEPF / 1493, hz / 4);
2800                 }
2801                 return 0;
2802
2803         case KDSETLED:
2804                 /* set kbd LED status */
2805                 /* unfortunately, the LED definitions between pcvt and */
2806                 /* USL differ some way :-( */
2807                 i = *(int *)data;
2808                 j = (i & LED_CAP? KBD_CAPSLOCK: 0)
2809                         + (i & LED_NUM? KBD_NUMLOCK: 0)
2810                         + (i & LED_SCR? KBD_SCROLLLOCK: 0);
2811                 return kbdioctl(dev, KBDSLOCK, (caddr_t)&j, flag);
2812
2813         case KDGETLED:
2814                 /* get kbd LED status */
2815                 if((error = kbdioctl(dev, KBDGLOCK, (caddr_t)&j, flag)))
2816                         return error;
2817                 i = (j & KBD_CAPSLOCK? LED_CAP: 0)
2818                         + (j & KBD_NUMLOCK? LED_NUM: 0)
2819                         + (j & KBD_SCROLLLOCK? LED_SCR: 0);
2820                 *(int *)data = i;
2821                 return 0;
2822
2823         case GIO_KEYMAP:
2824                 get_usl_keymap((keymap_t *)data);
2825                 return 0;
2826         }                       /* end case cmd */
2827
2828         return -1;              /* inappropriate usl_vt_compat ioctl */
2829 }
2830 #endif /* PCVT_USL_VT_COMPAT */
2831
2832 #endif  /* NVT > 0 */
2833
2834 /* ------------------------- E O F ------------------------------------------*/
2835