diff options
author | peter <peter@FreeBSD.org> | 1999-01-01 08:23:23 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 1999-01-01 08:23:23 +0000 |
commit | e6cf3a438fea379bc695c779b175c508ca097243 (patch) | |
tree | 97ebf948b34be84395e40d16a1024cb7e7fd4d76 /sys/i386/isa/pcvt/pcvt_ext.c | |
parent | d713c6aca4942e88e9afb66a012c176a3b3c93dd (diff) | |
download | FreeBSD-src-e6cf3a438fea379bc695c779b175c508ca097243.zip FreeBSD-src-e6cf3a438fea379bc695c779b175c508ca097243.tar.gz |
Part 3 of the pcvt/voxware revival.
Reviewed by: core
Diffstat (limited to 'sys/i386/isa/pcvt/pcvt_ext.c')
-rw-r--r-- | sys/i386/isa/pcvt/pcvt_ext.c | 2835 |
1 files changed, 2835 insertions, 0 deletions
diff --git a/sys/i386/isa/pcvt/pcvt_ext.c b/sys/i386/isa/pcvt/pcvt_ext.c new file mode 100644 index 0000000..acf066a --- /dev/null +++ b/sys/i386/isa/pcvt/pcvt_ext.c @@ -0,0 +1,2835 @@ +/* + * Copyright (c) 1992, 1995 Hellmuth Michaelis and Joerg Wunsch. + * + * Copyright (C) 1992, 1993 Soeren Schmidt. + * + * All rights reserved. + * + * For the sake of compatibility, portions of this code regarding the + * X server interface are taken from Soeren Schmidt's syscons driver. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by + * Hellmuth Michaelis, Joerg Wunsch and Soeren Schmidt. + * 4. The name authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * @(#)pcvt_ext.c, 3.20, Last Edit-Date: [Thu Apr 6 10:07:45 1995] + * + */ + +/*---------------------------------------------------------------------------* + * + * pcvt_ext.c VT220 Driver Extended Support Routines + * ------------------------------------------------------ + * + * -hm ------------ Release 3.00 -------------- + * -hm integrating NetBSD-current patches + * -hm applied Onno van der Linden's patch for Cirrus BIOS upgrade + * -hm pcvt_x_hook has to care about fkey labels now + * -hm changed some bcopyb's to bcopy's + * -hm TS_INDEX -> TS_DATA for cirrus (mail from Onno/Charles) + * -jw removed kbc_8042(), and replaced by kbd_emulate_pc() + * -hm X server patch from John Kohl <jtk@kolvir.blrc.ma.us> + * -hm applying Joerg's patch for FreeBSD 2.0 + * -hm enable 132 col support for Trident TVGA8900CL + * -hm applying patch from Joerg fixing Crtat bug + * -hm removed PCVT_FAKE_SYSCONS10 + * -hm fastscroll/Crtat bugfix from Lon Willett + * -hm bell patch from Thomas Eberhardt for NetBSD + * -hm multiple X server bugfixes from Lon Willett + * -hm patch from John Kohl fixing tsleep bug in usl_vt_ioctl() + * -hm bugfix: clear 25th line when switching to a force 24 lines vt + * -jw add some forward declarations + * -hm fixing MDA re-init when leaving X + * -hm patch from John Kohl fixing potential divide by 0 problem + * + *---------------------------------------------------------------------------*/ + +#include "vt.h" +#if NVT > 0 + +#include <i386/isa/pcvt/pcvt_hdr.h> /* global include */ + +#define ISSIGVALID(sig) ((sig) > 0 && (sig) < NSIG) + +static int s3testwritable( void ); +static int et4000_col( int ); +static int wd90c11_col( int ); +static int tri9000_col( int ); +static int v7_1024i_col( int ); +static int s3_928_col( int ); +static int cl_gd542x_col( int ); + +/* storage to save video timing values of 80 columns text mode */ +static union { + u_char generic[11]; + u_char et4000[11]; + u_char wd90c11[12]; + u_char tri9000[13]; + u_char v7_1024i[17]; + u_char s3_928[32]; + u_char cirrus[13]; +} +savearea; + +static int regsaved = 0; /* registers are saved to savearea */ + +/*---------------------------------------------------------------------------* + * + * Find out which video board we are running on, taken from: + * Richard Ferraro: Programmers Guide to the EGA and VGA Cards + * and from David E. Wexelblat's SuperProbe Version 1.0. + * When a board is found, for which 132 column switching is + * provided, the global variable "can_do_132col" is set to 1, + * also the global variable vga_family is set to what we found. + * + * ############################################################### + * ## THIS IS GETTING MORE AND MORE A LARGE SPAGHETTI HACK !!!! ## + * ############################################################### + * + *---------------------------------------------------------------------------*/ +u_char +vga_chipset(void) +{ + u_char *ptr; + u_char byte, oldbyte, old1byte, newbyte; + +#if PCVT_132GENERIC + can_do_132col = 1; /* assumes everyone can do 132 col */ +#else + can_do_132col = 0; /* assumes noone can do 132 col */ +#endif /* PCVT_132GENERIC */ + + vga_family = VGA_F_NONE; + +/*---------------------------------------------------------------------------* + * check for Western Digital / Paradise chipsets + *---------------------------------------------------------------------------*/ + + ptr = (u_char *)Crtat; + + if(color) + ptr += (0xc007d - 0xb8000); + else + ptr += (0xc007d - 0xb0000); + + if((*ptr++ == 'V') && (*ptr++ == 'G') && + (*ptr++ == 'A') && (*ptr++ == '=')) + { + int wd90c10; + + vga_family = VGA_F_WD; + + outb(addr_6845, 0x2b); + oldbyte = inb(addr_6845+1); + outb(addr_6845+1, 0xaa); + newbyte = inb(addr_6845+1); + outb(addr_6845+1, oldbyte); + if(newbyte != 0xaa) + return(VGA_PVGA); /* PVGA1A chip */ + + outb(TS_INDEX, 0x12); + oldbyte = inb(TS_DATA); + outb(TS_DATA, oldbyte & 0xbf); + newbyte = inb(TS_DATA) & 0x40; + if(newbyte != 0) + return(VGA_WD90C00); /* WD90C00 chip */ + + outb(TS_DATA, oldbyte | 0x40); + newbyte = inb(TS_DATA) & 0x40; + if(newbyte == 0) + return(VGA_WD90C00); /* WD90C00 chip */ + + outb(TS_DATA, oldbyte); + + wd90c10 = 0; + outb(TS_INDEX, 0x10); + oldbyte = inb(TS_DATA); + + outb(TS_DATA, oldbyte & 0xfb); + newbyte = inb(TS_DATA) & 0x04; + if(newbyte != 0) + wd90c10 = 1; + + outb(TS_DATA, oldbyte | 0x04); + newbyte = inb(TS_DATA) & 0x04; + if(newbyte == 0) + wd90c10 = 1; + + outb(TS_DATA, oldbyte); + + if(wd90c10) + return(VGA_WD90C10); + else + { + can_do_132col = 1; + return(VGA_WD90C11); + } + } + +/*---------------------------------------------------------------------------* + * check for Trident chipsets + *---------------------------------------------------------------------------*/ + + outb(TS_INDEX, 0x0b); + oldbyte = inb(TS_DATA); + + + outb(TS_INDEX, 0x0b); + outb(TS_DATA, 0x00); + + byte = inb(TS_DATA); /* chipset type */ + + + outb(TS_INDEX, 0x0e); + old1byte = inb(TS_DATA); + + outb(TS_DATA, 0); + newbyte = inb(TS_DATA); + + outb(TS_DATA, (old1byte ^ 0x02)); + + outb(TS_INDEX, 0x0b); + outb(TS_DATA, oldbyte); + + if((newbyte & 0x0f) == 0x02) + { + /* is a trident chip */ + + vga_family = VGA_F_TRI; + + switch(byte) + { + case 0x01: + return(VGA_TR8800BR); + + case 0x02: + return(VGA_TR8800CS); + + case 0x03: + can_do_132col = 1; + return(VGA_TR8900B); + + case 0x04: + case 0x13: + /* Haven't tried, but should work */ + can_do_132col = 1; + return(VGA_TR8900C); + + case 0x23: + can_do_132col = 1; + return(VGA_TR9000); + + case 0x33: + can_do_132col = 1; + return(VGA_TR8900CL); + + case 0x83: + return(VGA_TR9200); + + case 0x93: + return(VGA_TR9100); + + default: + return(VGA_TRUNKNOWN); + } + } + +/*---------------------------------------------------------------------------* + * check for Tseng Labs ET3000/4000 chipsets + *---------------------------------------------------------------------------*/ + + outb(GN_HERCOMPAT, 0x06); + if(color) + outb(GN_DMCNTLC, 0xa0); + else + outb(GN_DMCNTLM, 0xa0); + + /* read old value */ + + if(color) + inb(GN_INPSTAT1C); + else + inb(GN_INPSTAT1M); + outb(ATC_INDEX, ATC_MISC); + oldbyte = inb(ATC_DATAR); + + /* write new value */ + + if(color) + inb(GN_INPSTAT1C); + else + inb(GN_INPSTAT1M); + outb(ATC_INDEX, ATC_MISC); + newbyte = oldbyte ^ 0x10; + outb(ATC_DATAW, newbyte); + + /* read back new value */ + if(color) + inb(GN_INPSTAT1C); + else + inb(GN_INPSTAT1M); + outb(ATC_INDEX, ATC_MISC); + byte = inb(ATC_DATAR); + + /* write back old value */ + if(color) + inb(GN_INPSTAT1C); + else + inb(GN_INPSTAT1M); + outb(ATC_INDEX, ATC_MISC); + outb(ATC_DATAW, oldbyte); + + if(byte == newbyte) /* ET3000 or ET4000 */ + { + vga_family = VGA_F_TSENG; + + outb(addr_6845, CRTC_EXTSTART); + oldbyte = inb(addr_6845+1); + newbyte = oldbyte ^ 0x0f; + outb(addr_6845+1, newbyte); + byte = inb(addr_6845+1); + outb(addr_6845+1, oldbyte); + + if(byte == newbyte) + { + can_do_132col = 1; + return(VGA_ET4000); + } + else + { + return(VGA_ET3000); + } + } + +/*---------------------------------------------------------------------------* + * check for Video7 VGA chipsets + *---------------------------------------------------------------------------*/ + + outb(TS_INDEX, TS_EXTCNTL); /* enable extensions */ + outb(TS_DATA, 0xea); + + outb(addr_6845, CRTC_STARTADRH); + oldbyte = inb(addr_6845+1); + + outb(addr_6845+1, 0x55); + newbyte = inb(addr_6845+1); + + outb(addr_6845, CRTC_V7ID); /* id register */ + byte = inb(addr_6845+1); /* read id */ + + outb(addr_6845, CRTC_STARTADRH); + outb(addr_6845+1, oldbyte); + + outb(TS_INDEX, TS_EXTCNTL); /* disable extensions */ + outb(TS_DATA, 0xae); + + if(byte == (0x55 ^ 0xea)) + { /* is Video 7 */ + + vga_family = VGA_F_V7; + + outb(TS_INDEX, TS_EXTCNTL); /* enable extensions */ + outb(TS_DATA, 0xea); + + outb(TS_INDEX, TS_V7CHIPREV); + byte = inb(TS_DATA); + + outb(TS_INDEX, TS_EXTCNTL); /* disable extensions */ + outb(TS_DATA, 0xae); + + if(byte < 0xff && byte >= 0x80) + return(VGA_V7VEGA); + if(byte < 0x7f && byte >= 0x70) + return(VGA_V7FWVR); + if(byte < 0x5a && byte >= 0x50) + return(VGA_V7V5); + if(byte < 0x4a && byte > 0x40) + { + can_do_132col = 1; + return(VGA_V71024I); + } + return(VGA_V7UNKNOWN); + } + +/*---------------------------------------------------------------------------* + * check for S3 chipsets + *---------------------------------------------------------------------------*/ + + outb(addr_6845, 0x38); /* reg 1 lock register */ + old1byte = inb(addr_6845+1); /* get old value */ + + outb(addr_6845, 0x38); + outb(addr_6845+1, 0x00); /* lock registers */ + + if(s3testwritable() == 0) /* check if locked */ + { + outb(addr_6845, 0x38); + outb(addr_6845+1, 0x48); /* unlock registers */ + + if(s3testwritable() == 1 ) /* check if unlocked */ + { + vga_family = VGA_F_S3; /* FAMILY S3 */ + + outb(addr_6845, 0x30); /* chip id/rev reg */ + byte = inb(addr_6845+1); + + switch(byte & 0xf0) + { + case 0x80: + switch(byte & 0x0f) + { + case 0x01: + outb(addr_6845, 0x38); + outb(addr_6845+1, old1byte); + return VGA_S3_911; + + case 0x02: + outb(addr_6845, 0x38); + outb(addr_6845+1, old1byte); + return VGA_S3_924; + + default: + outb(addr_6845, 0x38); + outb(addr_6845+1, old1byte); + return VGA_S3_UNKNOWN; + } + break; + + case 0xA0: + outb(addr_6845, 0x38); + outb(addr_6845+1, old1byte); + return VGA_S3_80x; + + case 0x90: + case 0xb0: + outb(addr_6845, 0x38); + outb(addr_6845+1, old1byte); + can_do_132col = 1; + return VGA_S3_928; + + default: + outb(addr_6845, 0x38); + outb(addr_6845+1, old1byte); + return VGA_S3_UNKNOWN; + } + } + } + +/*---------------------------------------------------------------------------* + * check for Cirrus chipsets + *---------------------------------------------------------------------------*/ + + outb(TS_INDEX, 6); + oldbyte = inb(TS_DATA); + outb(TS_INDEX, 6); + outb(TS_DATA, 0x12); + outb(TS_INDEX, 6); + newbyte = inb(TS_DATA); + outb(addr_6845, 0x27); + byte = inb(addr_6845 + 1); + outb(TS_INDEX, 6); + outb(TS_DATA, oldbyte); + if (newbyte == 0x12) { + vga_family = VGA_F_CIR; + can_do_132col = 1; + switch ((byte & 0xfc) >> 2) { + case 0x22: + switch (byte & 3) { + case 0: + return VGA_CL_GD5402; + case 1: + return VGA_CL_GD5402r1; + case 2: + return VGA_CL_GD5420; + case 3: + return VGA_CL_GD5420r1; + } + break; + case 0x23: + return VGA_CL_GD5422; + case 0x25: + return VGA_CL_GD5424; + case 0x24: + return VGA_CL_GD5426; + case 0x26: + return VGA_CL_GD5428; + } + } + + return(VGA_UNKNOWN); +} + +/*--------------------------------------------------------------------------- + * test if index 35 lower nibble is writable (taken from SuperProbe 1.0) + *---------------------------------------------------------------------------*/ +static int +s3testwritable(void) +{ + u_char old, new1, new2; + + outb(addr_6845, 0x35); + old = inb(addr_6845+1); /* save */ + + outb(addr_6845, 0x35); + outb(addr_6845+1, (old & 0xf0)); /* write 0 */ + + outb(addr_6845, 0x35); + new1 = (inb(addr_6845+1)) & 0x0f; /* must read 0 */ + + outb(addr_6845, 0x35); + outb(addr_6845+1, (old | 0x0f)); /* write 1 */ + + outb(addr_6845, 0x35); + new2 = (inb(addr_6845+1)) & 0x0f; /* must read 1 */ + + outb(addr_6845, 0x35); + outb(addr_6845+1, old); /* restore */ + + return((new1==0) && (new2==0x0f)); +} + +/*---------------------------------------------------------------------------* + * return ptr to string describing vga type + *---------------------------------------------------------------------------*/ +char * +vga_string(int number) +{ + static char *vga_tab[] = { + "generic", + "et4000", + "et3000", + "pvga1a", + "wd90c00", + "wd90c10", + "wd90c11", + "v7 vega", + "v7 fast", + "v7 ver5", + "v7 1024i", + "unknown v7", + "tvga 8800br", + "tvga 8800cs", + "tvga 8900b", + "tvga 8900c", + "tvga 8900cl", + "tvga 9000", + "tvga 9100", + "tvga 9200", + "unknown trident", + "s3 911", + "s3 924", + "s3 801/805", + "s3 928", + "unkown s3", + "cl-gd5402", + "cl-gd5402r1", + "cl-gd5420", + "cl-gd5420r1", + "cl-gd5422", + "cl-gd5424", + "cl-gd5426", + "cl-gd5428" + }; + return(vga_tab[number]); +} + +/*---------------------------------------------------------------------------* + * toggle vga 80/132 column operation + *---------------------------------------------------------------------------*/ +int +vga_col(struct video_state *svsp, int cols) +{ + int ret = 0; + + if(adaptor_type != VGA_ADAPTOR) + return(0); + + switch(vga_type) + { + case VGA_ET4000: + ret = et4000_col(cols); + break; + + case VGA_WD90C11: + ret = wd90c11_col(cols); + break; + + case VGA_TR8900B: + case VGA_TR8900C: + case VGA_TR8900CL: + case VGA_TR9000: + ret = tri9000_col(cols); + break; + + case VGA_V71024I: + ret = v7_1024i_col(cols); + break; + + case VGA_S3_928: + ret = s3_928_col(cols); + break; + + case VGA_CL_GD5402: + case VGA_CL_GD5402r1: + case VGA_CL_GD5420: + case VGA_CL_GD5420r1: + case VGA_CL_GD5422: + case VGA_CL_GD5424: + case VGA_CL_GD5426: + case VGA_CL_GD5428: + ret = cl_gd542x_col(cols); + break; + + default: + +#if PCVT_132GENERIC + ret = generic_col(cols); +#endif /* PCVT_132GENERIC */ + + break; + } + + if(ret == 0) + return(0); /* failed */ + + svsp->maxcol = cols; + + return(1); +} + +#if PCVT_132GENERIC +/*---------------------------------------------------------------------------* + * toggle 80/132 column operation for "generic" SVGAs + * NB: this is supposed to work on any (S)VGA as long as the monitor + * is able to sync down to 21.5 kHz horizontally. The resulting + * vertical frequency is only 50 Hz, so if there is some better board + * specific algorithm, we avoid using this generic one. + * REPORT ANY FAILURES SO WE CAN IMPROVE THIS + *---------------------------------------------------------------------------*/ + +#if PCVT_EXP_132COL +/* + * Some improved (i.e. higher scan rates) figures for the horizontal + * timing. USE AT YOUR OWN RISK, THIS MIGHT DAMAGE YOUR MONITOR DUE + * TO A LOSS OF HORIZONTAL SYNC! + * The figures have been tested with an ET3000 board along with a + * NEC MultiSync 3D monitor. If you are playing here, consider + * testing with several screen pictures (dark background vs. light + * background, even enlightening the border color may impact the + * result - you can do this e.g. by "scon -p black,42,42,42") + * Remember that all horizontal timing values must be dividable + * by 8! (The scheme below is taken so that nifty kernel hackers + * are able to patch the figures at run-time.) + * + * The actual numbers result in 23 kHz line scan and 54 Hz vertical + * scan. + */ +#endif /* PCVT_EXP_132COL */ + +int +generic_col(int cols) +{ + u_char *sp; + u_char byte; + +#if !PCVT_EXP_132COL + + /* stable figures for any multisync monitor that syncs down to 22 kHz*/ + static volatile u_short htotal = 1312; + static volatile u_short displayend = 1056; + static volatile u_short blankstart = 1072; + static volatile u_short syncstart = 1112; + static volatile u_short syncend = 1280; + +#else /* PCVT_EXP_132COL */ + + /* reduced sync-pulse width and sync delays */ + static volatile u_short htotal = 1232; + static volatile u_short displayend = 1056; + static volatile u_short blankstart = 1056; + static volatile u_short syncstart = 1104; + static volatile u_short syncend = 1168; + +#endif /* PCVT_EXP_132COL */ + + vga_screen_off(); + + /* enable access to first 7 CRTC registers */ + + outb(addr_6845, CRTC_VSYNCE); + byte = inb(addr_6845+1); + outb(addr_6845, CRTC_VSYNCE); + outb(addr_6845+1, byte & 0x7f); + + if(cols == SCR_COL132) /* switch 80 -> 132 */ + { + /* save state of board for 80 columns */ + + if(!regsaved) + { + regsaved = 1; + + sp = savearea.generic; + + outb(addr_6845, 0x00); /* Horizontal Total */ + *sp++ = inb(addr_6845+1); + outb(addr_6845, 0x01); /* Horizontal Display End */ + *sp++ = inb(addr_6845+1); + outb(addr_6845, 0x02); /* Horizontal Blank Start */ + *sp++ = inb(addr_6845+1); + outb(addr_6845, 0x03); /* Horizontal Blank End */ + *sp++ = inb(addr_6845+1); + outb(addr_6845, 0x04); /* Horizontal Retrace Start */ + *sp++ = inb(addr_6845+1); + outb(addr_6845, 0x05); /* Horizontal Retrace End */ + *sp++ = inb(addr_6845+1); + + outb(addr_6845, 0x13); /* Row Offset Register */ + *sp++ = inb(addr_6845+1); + + outb(TS_INDEX, TS_MODE);/* Timing Sequencer */ + *sp++ = inb(TS_DATA); + + if(color) + inb(GN_INPSTAT1C); + else + inb(GN_INPSTAT1M); + /* ATC Mode control */ + outb(ATC_INDEX, ATC_MODE | ATC_ACCESS); + *sp++ = inb(ATC_DATAR); + + if(color) + inb(GN_INPSTAT1C); + else + inb(GN_INPSTAT1M); + /* ATC Horizontal Pixel Panning */ + outb(ATC_INDEX, ATC_HORPIXPAN | ATC_ACCESS); + *sp++ = inb(ATC_DATAR); + + *sp++ = inb(GN_MISCOUTR); /* Misc output register */ + } + + /* setup chipset for 132 column operation */ + + + outb(addr_6845, 0x00); /* Horizontal Total */ + outb(addr_6845+1, (htotal / 8) - 5); + outb(addr_6845, 0x01); /* Horizontal Display End */ + outb(addr_6845+1, (displayend / 8) - 1); + outb(addr_6845, 0x02); /* Horizontal Blank Start */ + outb(addr_6845+1, blankstart / 8); + outb(addr_6845, 0x03); /* Horizontal Blank End */ + outb(addr_6845+1, ((syncend / 8) & 0x1f) | 0x80); + outb(addr_6845, 0x04); /* Horizontal Retrace Start */ + outb(addr_6845+1, syncstart / 8); + outb(addr_6845, 0x05); /* Horizontal Retrace End */ + outb(addr_6845+1, + (((syncend / 8) & 0x20) * 4) + | ((syncend / 8) & 0x1f)); + + outb(addr_6845, 0x13); /* Row Offset Register */ + outb(addr_6845+1, 0x42); + + outb(TS_INDEX, TS_MODE);/* Timing Sequencer */ + outb(TS_DATA, 0x01); /* 8 dot char clock */ + + if(color) + inb(GN_INPSTAT1C); + else + inb(GN_INPSTAT1M); + outb(ATC_INDEX, ATC_MODE | ATC_ACCESS); /* ATC Mode control */ + outb(ATC_DATAW, 0x08); /* Line graphics disable */ + + if(color) + inb(GN_INPSTAT1C); + else + inb(GN_INPSTAT1M); + outb(ATC_INDEX, ATC_HORPIXPAN | ATC_ACCESS); /* ATC Horizontal Pixel Panning */ + outb(ATC_DATAW, 0x00); + + /* Misc output register */ + /* use the 28.322 MHz clock */ + outb(GN_MISCOUTW, (inb(GN_MISCOUTR) & ~0x0c) | 4); + } + else /* switch 132 -> 80 */ + { + if(!regsaved) /* failsafe */ + { + /* disable access to first 7 CRTC registers */ + outb(addr_6845, CRTC_VSYNCE); + outb(addr_6845+1, byte); + vga_screen_on(); + return(0); + } + + sp = savearea.generic; + + outb(addr_6845, 0x00); /* Horizontal Total */ + outb(addr_6845+1, *sp++); + outb(addr_6845, 0x01); /* Horizontal Display End */ + outb(addr_6845+1, *sp++); + outb(addr_6845, 0x02); /* Horizontal Blank Start */ + outb(addr_6845+1, *sp++); + outb(addr_6845, 0x03); /* Horizontal Blank End */ + outb(addr_6845+1, *sp++); + outb(addr_6845, 0x04); /* Horizontal Retrace Start */ + outb(addr_6845+1, *sp++); + outb(addr_6845, 0x05); /* Horizontal Retrace End */ + outb(addr_6845+1, *sp++); + + outb(addr_6845, 0x13); /* Row Offset Register */ + outb(addr_6845+1, *sp++); + + outb(TS_INDEX, TS_MODE);/* Timing Sequencer */ + outb(TS_DATA, *sp++); + + if(color) + inb(GN_INPSTAT1C); + else + inb(GN_INPSTAT1M); + /* ATC Mode control */ + outb(ATC_INDEX, ATC_MODE | ATC_ACCESS); + outb(ATC_DATAW, *sp++); + + if(color) + inb(GN_INPSTAT1C); + else + inb(GN_INPSTAT1M); + /* ATC Horizontal Pixel Panning */ + outb(ATC_INDEX, ATC_HORPIXPAN | ATC_ACCESS); + outb(ATC_DATAW, *sp++); + + outb(GN_MISCOUTW, *sp++); /* Misc output register */ + } + + /* disable access to first 7 CRTC registers */ + + outb(addr_6845, CRTC_VSYNCE); + outb(addr_6845+1, byte); + + vga_screen_on(); + + return(1); +} +#endif /* PCVT_132GENERIC */ + +/*---------------------------------------------------------------------------* + * toggle 80/132 column operation for ET4000 based boards + *---------------------------------------------------------------------------*/ +int +et4000_col(int cols) +{ + u_char *sp; + u_char byte; + + vga_screen_off(); + + /* enable access to first 7 CRTC registers */ + + outb(addr_6845, CRTC_VSYNCE); + byte = inb(addr_6845+1); + outb(addr_6845, CRTC_VSYNCE); + outb(addr_6845+1, byte & 0x7f); + + if(cols == SCR_COL132) /* switch 80 -> 132 */ + { + /* save state of board for 80 columns */ + + if(!regsaved) + { + regsaved = 1; + + sp = savearea.et4000; + + outb(addr_6845, 0x00); /* Horizontal Total */ + *sp++ = inb(addr_6845+1); + outb(addr_6845, 0x01); /* Horizontal Display End */ + *sp++ = inb(addr_6845+1); + outb(addr_6845, 0x02); /* Horizontal Blank Start */ + *sp++ = inb(addr_6845+1); + + outb(addr_6845, 0x04); /* Horizontal Retrace Start */ + *sp++ = inb(addr_6845+1); + outb(addr_6845, 0x05); /* Horizontal Retrace End */ + *sp++ = inb(addr_6845+1); + + outb(addr_6845, 0x13); /* Row Offset Register */ + *sp++ = inb(addr_6845+1); + + outb(addr_6845, 0x34); /* 6845 Compatibility */ + *sp++ = inb(addr_6845+1); + + outb(TS_INDEX, TS_MODE);/* Timing Sequencer */ + *sp++ = inb(TS_DATA); + + if(color) + inb(GN_INPSTAT1C); + else + inb(GN_INPSTAT1M); + /* ATC Mode control */ + outb(ATC_INDEX, ATC_MODE | ATC_ACCESS); + *sp++ = inb(ATC_DATAR); + + if(color) + inb(GN_INPSTAT1C); + else + inb(GN_INPSTAT1M); + /* ATC Horizontal Pixel Panning */ + outb(ATC_INDEX, ATC_HORPIXPAN | ATC_ACCESS); + *sp++ = inb(ATC_DATAR); + + *sp++ = inb(GN_MISCOUTR); /* Misc output register */ + } + + /* setup chipset for 132 column operation */ + + outb(addr_6845, 0x00); /* Horizontal Total */ + outb(addr_6845+1, 0x9f); + outb(addr_6845, 0x01); /* Horizontal Display End */ + outb(addr_6845+1, 0x83); + outb(addr_6845, 0x02); /* Horizontal Blank Start */ + outb(addr_6845+1, 0x84); + + outb(addr_6845, 0x04); /* Horizontal Retrace Start */ + outb(addr_6845+1, 0x8b); + outb(addr_6845, 0x05); /* Horizontal Retrace End */ + outb(addr_6845+1, 0x80); + + outb(addr_6845, 0x13); /* Row Offset Register */ + outb(addr_6845+1, 0x42); + + outb(addr_6845, 0x34); /* 6845 Compatibility */ + outb(addr_6845+1, 0x0a); + + outb(TS_INDEX, TS_MODE);/* Timing Sequencer */ + outb(TS_DATA, 0x01); /* 8 dot char clock */ + + if(color) + inb(GN_INPSTAT1C); + else + inb(GN_INPSTAT1M); + outb(ATC_INDEX, ATC_MODE | ATC_ACCESS); /* ATC Mode control */ + outb(ATC_DATAW, 0x08); /* Line graphics disable */ + + if(color) + inb(GN_INPSTAT1C); + else + inb(GN_INPSTAT1M); + outb(ATC_INDEX, ATC_HORPIXPAN | ATC_ACCESS); /* ATC Horizontal Pixel Panning */ + outb(ATC_DATAW, 0x00); + + /* Misc output register */ + + outb(GN_MISCOUTW, (inb(GN_MISCOUTR) & ~0x0c)); + } + else /* switch 132 -> 80 */ + { + if(!regsaved) /* failsafe */ + { + /* disable access to first 7 CRTC registers */ + outb(addr_6845, CRTC_VSYNCE); + outb(addr_6845+1, byte); + vga_screen_on(); + return(0); + } + + sp = savearea.et4000; + + outb(addr_6845, 0x00); /* Horizontal Total */ + outb(addr_6845+1, *sp++); + + outb(addr_6845, 0x01); /* Horizontal Display End */ + outb(addr_6845+1, *sp++); + outb(addr_6845, 0x02); /* Horizontal Blank Start */ + outb(addr_6845+1, *sp++); + + + outb(addr_6845, 0x04); /* Horizontal Retrace Start */ + outb(addr_6845+1, *sp++); + outb(addr_6845, 0x05); /* Horizontal Retrace End */ + outb(addr_6845+1, *sp++); + + outb(addr_6845, 0x13); /* Row Offset Register */ + outb(addr_6845+1, *sp++); + + outb(addr_6845, 0x34); /* 6845 Compatibility */ + outb(addr_6845+1, *sp++); + + outb(TS_INDEX, TS_MODE);/* Timing Sequencer */ + outb(TS_DATA, *sp++); + + if(color) + inb(GN_INPSTAT1C); + else + inb(GN_INPSTAT1M); + /* ATC Mode control */ + outb(ATC_INDEX, ATC_MODE | ATC_ACCESS); + outb(ATC_DATAW, *sp++); + + if(color) + inb(GN_INPSTAT1C); + else + inb(GN_INPSTAT1M); + /* ATC Horizontal Pixel Panning */ + outb(ATC_INDEX, ATC_HORPIXPAN | ATC_ACCESS); + outb(ATC_DATAW, *sp++); + + outb(GN_MISCOUTW, *sp++); /* Misc output register */ + } + + /* disable access to first 7 CRTC registers */ + + outb(addr_6845, CRTC_VSYNCE); + outb(addr_6845+1, byte); + + vga_screen_on(); + + return(1); +} + +/*---------------------------------------------------------------------------* + * toggle 80/132 column operation for WD/Paradise based boards + * + * when this card does 132 cols, the char map select register (TS_INDEX, + * TS_FONTSEL) function bits get REDEFINED. whoever did design this, + * please don't cross my way ever ....... + * + *---------------------------------------------------------------------------*/ +int +wd90c11_col(int cols) +{ + +#if !PCVT_BACKUP_FONTS + static unsigned char *sv_fontwd[NVGAFONTS]; +#endif /* !PCVT_BACKUP_FONTS */ + + u_char *sp; + u_char byte; + int i; + + vga_screen_off(); + + /* enable access to first 7 CRTC registers */ + + outb(addr_6845, CRTC_VSYNCE); + byte = inb(addr_6845+1); + outb(addr_6845, CRTC_VSYNCE); + outb(addr_6845+1, byte & 0x7f); + + /* enable access to WD/Paradise "control extensions" */ + + outb(GDC_INDEX, GDC_PR5GPLOCK); + outb(GDC_INDEX, 0x05); + outb(addr_6845, CRTC_PR10); + outb(addr_6845, 0x85); + outb(TS_INDEX, TS_UNLOCKSEQ); + outb(TS_DATA, 0x48); + + if(cols == SCR_COL132) /* switch 80 -> 132 */ + { + /* save state of board for 80 columns */ + + if(!regsaved) + { + regsaved = 1; + + /* save current fonts */ + +#if !PCVT_BACKUP_FONTS + for(i = 0; i < totalfonts; i++) + { + if(vgacs[i].loaded) + { + if((sv_fontwd[i] = + (u_char *)malloc(32 * 256, + M_DEVBUF, + M_WAITOK)) + == NULL) + printf("pcvt: no font buffer\n"); + else + vga_move_charset(i, + sv_fontwd[i], + 1); + } + else + { + sv_fontwd[i] = 0; + } + } + +#endif /* !PCVT_BACKUP_FONTS */ + + sp = savearea.wd90c11; + + outb(addr_6845, 0x00); /* Horizontal Total */ + *sp++ = inb(addr_6845+1); + outb(addr_6845, 0x01); /* Horizontal Display End */ + *sp++ = inb(addr_6845+1); + outb(addr_6845, 0x02); /* Horizontal Blank Start */ + *sp++ = inb(addr_6845+1); + outb(addr_6845, 0x03); /* Horizontal Blank End */ + *sp++ = inb(addr_6845+1); + outb(addr_6845, 0x04); /* Horizontal Retrace Start */ + *sp++ = inb(addr_6845+1); + outb(addr_6845, 0x05); /* Horizontal Retrace End */ + *sp++ = inb(addr_6845+1); + + outb(addr_6845, 0x13); /* Row Offset Register */ + *sp++ = inb(addr_6845+1); + + outb(addr_6845, 0x2e); /* misc 1 */ + *sp++ = inb(addr_6845+1); + outb(addr_6845, 0x2f); /* misc 2 */ + *sp++ = inb(addr_6845+1); + + outb(TS_INDEX, 0x10);/* Timing Sequencer */ + *sp++ = inb(TS_DATA); + outb(TS_INDEX, 0x12);/* Timing Sequencer */ + *sp++ = inb(TS_DATA); + + *sp++ = inb(GN_MISCOUTR); /* Misc output register */ + } + + /* setup chipset for 132 column operation */ + + outb(addr_6845, 0x00); /* Horizontal Total */ + outb(addr_6845+1, 0x9c); + outb(addr_6845, 0x01); /* Horizontal Display End */ + outb(addr_6845+1, 0x83); + outb(addr_6845, 0x02); /* Horizontal Blank Start */ + outb(addr_6845+1, 0x84); + outb(addr_6845, 0x03); /* Horizontal Blank End */ + outb(addr_6845+1, 0x9f); + outb(addr_6845, 0x04); /* Horizontal Retrace Start */ + outb(addr_6845+1, 0x8a); + outb(addr_6845, 0x05); /* Horizontal Retrace End */ + outb(addr_6845+1, 0x1c); + + outb(addr_6845, 0x13); /* Row Offset Register */ + outb(addr_6845+1, 0x42); + + outb(addr_6845, 0x2e); /* misc 1 */ + outb(addr_6845+1, 0x04); + outb(addr_6845, 0x2f); /* misc 2 */ + outb(addr_6845+1, 0x00); + + outb(TS_INDEX, 0x10);/* Timing Sequencer */ + outb(TS_DATA, 0x21); + outb(TS_INDEX, 0x12);/* Timing Sequencer */ + outb(TS_DATA, 0x14); + + outb(GN_MISCOUTW, (inb(GN_MISCOUTR) | 0x08)); /* Misc output register */ + + vsp->wd132col = 1; + } + else /* switch 132 -> 80 */ + { + if(!regsaved) /* failsafe */ + { + /* disable access to first 7 CRTC registers */ + + outb(addr_6845, CRTC_VSYNCE); + outb(addr_6845+1, byte); + + /* disable access to WD/Paradise "control extensions" */ + + outb(GDC_INDEX, GDC_PR5GPLOCK); + outb(GDC_INDEX, 0x00); + outb(addr_6845, CRTC_PR10); + outb(addr_6845, 0x00); + outb(TS_INDEX, TS_UNLOCKSEQ); + outb(TS_DATA, 0x00); + + vga_screen_on(); + + return(0); + } + + sp = savearea.wd90c11; + + outb(addr_6845, 0x00); /* Horizontal Total */ + outb(addr_6845+1, *sp++); + outb(addr_6845, 0x01); /* Horizontal Display End */ + outb(addr_6845+1, *sp++); + outb(addr_6845, 0x02); /* Horizontal Blank Start */ + outb(addr_6845+1, *sp++); + outb(addr_6845, 0x03); /* Horizontal Blank End */ + outb(addr_6845+1, *sp++); + outb(addr_6845, 0x04); /* Horizontal Retrace Start */ + outb(addr_6845+1, *sp++); + outb(addr_6845, 0x05); /* Horizontal Retrace End */ + outb(addr_6845+1, *sp++); + + outb(addr_6845, 0x13); /* Row Offset Register */ + outb(addr_6845+1, *sp++); + + outb(addr_6845, 0x2e); /* misc 1 */ + outb(addr_6845+1, *sp++); + outb(addr_6845, 0x2f); /* misc 2 */ + outb(addr_6845+1, *sp++); + + outb(TS_INDEX, 0x10);/* Timing Sequencer */ + outb(addr_6845+1, *sp++); + outb(TS_INDEX, 0x12);/* Timing Sequencer */ + outb(addr_6845+1, *sp++); + + outb(GN_MISCOUTW, *sp++); /* Misc output register */ + + vsp->wd132col = 0; + } + + /* restore fonts */ + +#if !PCVT_BACKUP_FONTS + for(i = 0; i < totalfonts; i++) + { + if(sv_fontwd[i]) + vga_move_charset(i, sv_fontwd[i], 0); + } +#else + for(i = 0; i < totalfonts; i++) + if(saved_charsets[i]) + vga_move_charset(i, 0, 0); +#endif /* !PCVT_BACKUP_FONTS */ + + select_vga_charset(vsp->vga_charset); + + /* disable access to first 7 CRTC registers */ + + outb(addr_6845, CRTC_VSYNCE); + outb(addr_6845+1, byte); + + /* disable access to WD/Paradise "control extensions" */ + + outb(GDC_INDEX, GDC_PR5GPLOCK); + outb(GDC_INDEX, 0x00); + outb(addr_6845, CRTC_PR10); + outb(addr_6845, 0x00); + outb(TS_INDEX, TS_UNLOCKSEQ); + outb(TS_DATA, 0x00); + + vga_screen_on(); + + return(1); +} + +/*---------------------------------------------------------------------------* + * toggle 80/132 column operation for TRIDENT 9000 based boards + *---------------------------------------------------------------------------*/ +int +tri9000_col(int cols) +{ + u_char *sp; + u_char byte; + + vga_screen_off(); + + /* sync reset is necessary to preserve memory contents ... */ + + outb(TS_INDEX, TS_SYNCRESET); + outb(TS_DATA, 0x01); /* synchronous reset */ + + /* disable protection of misc out and other regs */ + + outb(addr_6845, CRTC_MTEST); + byte = inb(addr_6845+1); + outb(addr_6845, CRTC_MTEST); + outb(addr_6845+1, byte & ~0x50); + + /* enable access to first 7 CRTC registers */ + + outb(addr_6845, CRTC_VSYNCE); + byte = inb(addr_6845+1); + outb(addr_6845, CRTC_VSYNCE); + outb(addr_6845+1, byte & 0x7f); + + if(cols == SCR_COL132) /* switch 80 -> 132 */ + { + /* save state of board for 80 columns */ + + if(!regsaved) + { + regsaved = 1; + + sp = savearea.tri9000; + + outb(addr_6845, 0x00); /* Horizontal Total */ + *sp++ = inb(addr_6845+1); + outb(addr_6845, 0x01); /* Horizontal Display End */ + *sp++ = inb(addr_6845+1); + outb(addr_6845, 0x02); /* Horizontal Blank Start */ + *sp++ = inb(addr_6845+1); + outb(addr_6845, 0x03); /* Horizontal Blank End */ + *sp++ = inb(addr_6845+1); + outb(addr_6845, 0x04); /* Horizontal Retrace Start */ + *sp++ = inb(addr_6845+1); + outb(addr_6845, 0x05); /* Horizontal Retrace End */ + *sp++ = inb(addr_6845+1); + + outb(addr_6845, 0x13); + *sp++ = inb(addr_6845+1); + + outb(TS_INDEX, TS_MODE);/* Timing Sequencer */ + *sp++ = inb(TS_DATA); + + outb(TS_INDEX, TS_HWVERS);/* Hardware Version register */ + outb(TS_DATA, 0x00); /* write ANYTHING switches to OLD */ + outb(TS_INDEX, TS_MODEC2); + *sp++ = inb(TS_DATA); + + outb(TS_INDEX, TS_HWVERS);/* Hardware Version register */ + inb(TS_DATA); /* read switches to NEW */ + outb(TS_INDEX, TS_MODEC2); + *sp++ = inb(TS_DATA); + + if(color) + inb(GN_INPSTAT1C); + else + inb(GN_INPSTAT1M); + /* ATC Mode control */ + outb(ATC_INDEX, ATC_MODE | ATC_ACCESS); + *sp++ = inb(ATC_DATAR); + + if(color) + inb(GN_INPSTAT1C); + else + inb(GN_INPSTAT1M); + /* ATC Horizontal Pixel Panning */ + outb(ATC_INDEX, ATC_HORPIXPAN | ATC_ACCESS); + *sp++ = inb(ATC_DATAR); + + *sp++ = inb(GN_MISCOUTR); /* Misc output register */ + } + + /* setup chipset for 132 column operation */ + + outb(addr_6845, 0x00); /* Horizontal Total */ + outb(addr_6845+1, 0x9b); + outb(addr_6845, 0x01); /* Horizontal Display End */ + outb(addr_6845+1, 0x83); + outb(addr_6845, 0x02); /* Horizontal Blank Start */ + outb(addr_6845+1, 0x84); + outb(addr_6845, 0x03); /* Horizontal Blank End */ + outb(addr_6845+1, 0x1e); + outb(addr_6845, 0x04); /* Horizontal Retrace Start */ + outb(addr_6845+1, 0x87); + outb(addr_6845, 0x05); /* Horizontal Retrace End */ + outb(addr_6845+1, 0x1a); + + outb(addr_6845, 0x13); /* Row Offset Register */ + outb(addr_6845+1, 0x42); + + outb(TS_INDEX, TS_MODE);/* Timing Sequencer */ + outb(TS_DATA, 0x01); /* 8 dot char clock */ + + outb(TS_INDEX, TS_HWVERS);/* Hardware Version register */ + outb(TS_DATA, 0x00); /* write ANYTHING switches to OLD */ + outb(TS_INDEX, TS_MODEC2); + outb(TS_DATA, 0x00); + + outb(TS_INDEX, TS_HWVERS);/* Hardware Version register */ + inb(TS_DATA); /* read switches to NEW */ + outb(TS_INDEX, TS_MODEC2); + outb(TS_DATA, 0x01); + + if(color) + inb(GN_INPSTAT1C); + else + inb(GN_INPSTAT1M); + outb(ATC_INDEX, ATC_MODE | ATC_ACCESS); /* ATC Mode control */ + outb(ATC_DATAW, 0x08); /* Line graphics disable */ + + if(color) + inb(GN_INPSTAT1C); + else + inb(GN_INPSTAT1M); + outb(ATC_INDEX, ATC_HORPIXPAN | ATC_ACCESS); /* ATC Horizontal Pixel Panning */ + outb(ATC_DATAW, 0x00); + + outb(GN_MISCOUTW, (inb(GN_MISCOUTR) | 0x0c)); /* Misc output register */ + } + else /* switch 132 -> 80 */ + { + if(!regsaved) /* failsafe */ + { + /* disable access to first 7 CRTC registers */ + outb(addr_6845, CRTC_VSYNCE); + outb(addr_6845+1, byte); + + outb(TS_INDEX, TS_SYNCRESET); + outb(TS_DATA, 0x03); /* clear synchronous reset */ + + vga_screen_on(); + + return(0); + } + + sp = savearea.tri9000; + + outb(addr_6845, 0x00); /* Horizontal Total */ + outb(addr_6845+1, *sp++); + outb(addr_6845, 0x01); /* Horizontal Display End */ + outb(addr_6845+1, *sp++); + outb(addr_6845, 0x02); /* Horizontal Blank Start */ + outb(addr_6845+1, *sp++); + outb(addr_6845, 0x03); /* Horizontal Blank End */ + outb(addr_6845+1, *sp++); + outb(addr_6845, 0x04); /* Horizontal Retrace Start */ + outb(addr_6845+1, *sp++); + outb(addr_6845, 0x05); /* Horizontal Retrace End */ + outb(addr_6845+1, *sp++); + + outb(addr_6845, 0x13); /* Row Offset Register */ + outb(addr_6845+1, *sp++); + + outb(TS_INDEX, TS_MODE);/* Timing Sequencer */ + outb(TS_DATA, *sp++); + + outb(TS_INDEX, TS_HWVERS);/* Hardware Version register */ + outb(TS_DATA, 0x00); /* write ANYTHING switches to OLD */ + outb(TS_INDEX, TS_MODEC2);/* Timing Sequencer */ + outb(TS_DATA, *sp++); + + outb(TS_INDEX, TS_HWVERS);/* Hardware Version register */ + inb(TS_DATA); /* read switches to NEW */ + outb(TS_INDEX, TS_MODEC2);/* Timing Sequencer */ + outb(TS_DATA, *sp++); + + if(color) + inb(GN_INPSTAT1C); + else + inb(GN_INPSTAT1M); + /* ATC Mode control */ + outb(ATC_INDEX, ATC_MODE | ATC_ACCESS); + outb(ATC_DATAW, *sp++); + + if(color) + inb(GN_INPSTAT1C); + else + inb(GN_INPSTAT1M); + /* ATC Horizontal Pixel Panning */ + outb(ATC_INDEX, ATC_HORPIXPAN | ATC_ACCESS); + outb(ATC_DATAW, *sp++); + + outb(GN_MISCOUTW, *sp++); /* Misc output register */ + } + + /* disable access to first 7 CRTC registers */ + + outb(addr_6845, CRTC_VSYNCE); + outb(addr_6845+1, byte); + + outb(TS_INDEX, TS_SYNCRESET); + outb(TS_DATA, 0x03); /* clear synchronous reset */ + + vga_screen_on(); + + return(1); +} + +/*---------------------------------------------------------------------------* + * toggle 80/132 column operation for Video7 VGA 1024i + *---------------------------------------------------------------------------*/ +int +v7_1024i_col(int cols) +{ + u_char *sp; + u_char byte; + u_char save__byte; + + vga_screen_off(); + + /* enable access to first 7 CRTC registers */ + + /* first, enable read access to vertical retrace start/end */ + outb(addr_6845, CRTC_HBLANKE); + byte = inb(addr_6845+1); + outb(addr_6845, CRTC_HBLANKE); + outb(addr_6845+1, (byte | 0x80)); + + /* second, enable access to protected registers */ + outb(addr_6845, CRTC_VSYNCE); + save__byte = byte = inb(addr_6845+1); + byte |= 0x20; /* no irq 2 */ + byte &= 0x6f; /* wr enable, clr irq flag */ + outb(addr_6845, CRTC_VSYNCE); + outb(addr_6845+1, byte); + + outb(TS_INDEX, TS_EXTCNTL); /* enable extensions */ + outb(TS_DATA, 0xea); + + + if(cols == SCR_COL132) /* switch 80 -> 132 */ + { + /* save state of board for 80 columns */ + + if(!regsaved) + { + regsaved = 1; + + sp = savearea.v7_1024i; + + outb(addr_6845, 0x00); /* Horizontal Total */ + *sp++ = inb(addr_6845+1); + outb(addr_6845, 0x01); /* Horizontal Display End */ + *sp++ = inb(addr_6845+1); + outb(addr_6845, 0x02); /* Horizontal Blank Start */ + *sp++ = inb(addr_6845+1); + outb(addr_6845, 0x03); /* Horizontal Blank End */ + *sp++ = inb(addr_6845+1); + outb(addr_6845, 0x04); /* Horizontal Retrace Start */ + *sp++ = inb(addr_6845+1); + outb(addr_6845, 0x05); /* Horizontal Retrace End */ + *sp++ = inb(addr_6845+1); + + outb(addr_6845, 0x13); /* Row Offset Register */ + *sp++ = inb(addr_6845+1); + + outb(TS_INDEX, TS_MODE);/* Timing Sequencer */ + *sp++ = inb(TS_DATA); + + if(color) + inb(GN_INPSTAT1C); + else + inb(GN_INPSTAT1M); + /* ATC Mode control */ + outb(ATC_INDEX, ATC_MODE | ATC_ACCESS); + *sp++ = inb(ATC_DATAR); + + if(color) + inb(GN_INPSTAT1C); + else + inb(GN_INPSTAT1M); + /* ATC Horizontal Pixel Panning */ + outb(ATC_INDEX, ATC_HORPIXPAN | ATC_ACCESS); + *sp++ = inb(ATC_DATAR); + + outb(TS_INDEX, 0x83); + *sp++ = inb(TS_DATA); + + outb(TS_INDEX, 0xa4); + *sp++ = inb(TS_DATA); + + outb(TS_INDEX, 0xe0); + *sp++ = inb(TS_DATA); + + outb(TS_INDEX, 0xe4); + *sp++ = inb(TS_DATA); + + outb(TS_INDEX, 0xf8); + *sp++ = inb(TS_DATA); + + outb(TS_INDEX, 0xfd); + *sp++ = inb(TS_DATA); + + *sp++ = inb(GN_MISCOUTR); /* Misc output register */ + } + + /* setup chipset for 132 column operation */ + + outb(addr_6845, 0x00); /* Horizontal Total */ + outb(addr_6845+1, 0x9c); + outb(addr_6845, 0x01); /* Horizontal Display End */ + outb(addr_6845+1, 0x83); + outb(addr_6845, 0x02); /* Horizontal Blank Start */ + outb(addr_6845+1, 0x86); + outb(addr_6845, 0x03); /* Horizontal Blank End */ + outb(addr_6845+1, 0x9e); + outb(addr_6845, 0x04); /* Horizontal Retrace Start */ + outb(addr_6845+1, 0x89); + outb(addr_6845, 0x05); /* Horizontal Retrace End */ + outb(addr_6845+1, 0x1c); + + outb(addr_6845, 0x13); /* Row Offset Register */ + outb(addr_6845+1, 0x42); + + outb(TS_INDEX, TS_MODE);/* Timing Sequencer */ + outb(TS_DATA, 0x01); /* 8 dot char clock */ + + if(color) + inb(GN_INPSTAT1C); + else + inb(GN_INPSTAT1M); + outb(ATC_INDEX, ATC_MODE | ATC_ACCESS); /* ATC Mode control */ + outb(ATC_DATAW, 0x08); /* Line graphics disable */ + + if(color) + inb(GN_INPSTAT1C); + else + inb(GN_INPSTAT1M); + outb(ATC_INDEX, ATC_HORPIXPAN | ATC_ACCESS); /* ATC Horizontal Pixel Panning */ + outb(ATC_DATAW, 0x00); + + outb(TS_INDEX, TS_SYNCRESET); + outb(TS_DATA, 0x01); /* synchronous reset */ + + outb(TS_INDEX, 0x83); + outb(TS_DATA, 0xa0); + + outb(TS_INDEX, 0xa4); + outb(TS_DATA, 0x1c); + + outb(TS_INDEX, 0xe0); + outb(TS_DATA, 0x00); + + outb(TS_INDEX, 0xe4); + outb(TS_DATA, 0xfe); + + outb(TS_INDEX, 0xf8); + outb(TS_DATA, 0x1b); + + outb(TS_INDEX, 0xfd); + outb(TS_DATA, 0x33); + + byte = inb(GN_MISCOUTR); + byte |= 0x0c; + outb(GN_MISCOUTW, byte); /* Misc output register */ + + outb(TS_INDEX, TS_SYNCRESET); + outb(TS_DATA, 0x03); /* clear synchronous reset */ + } + else /* switch 132 -> 80 */ + { + if(!regsaved) /* failsafe */ + { + outb(TS_INDEX, TS_EXTCNTL); /* disable extensions */ + outb(TS_DATA, 0xae); + + /* disable access to first 7 CRTC registers */ + outb(addr_6845, CRTC_VSYNCE); + outb(addr_6845+1, byte); + vga_screen_on(); + return(0); + } + + sp = savearea.v7_1024i; + + outb(addr_6845, 0x00); /* Horizontal Total */ + outb(addr_6845+1, *sp++); + outb(addr_6845, 0x01); /* Horizontal Display End */ + outb(addr_6845+1, *sp++); + outb(addr_6845, 0x02); /* Horizontal Blank Start */ + outb(addr_6845+1, *sp++); + outb(addr_6845, 0x03); /* Horizontal Blank End */ + outb(addr_6845+1, *sp++); + outb(addr_6845, 0x04); /* Horizontal Retrace Start */ + outb(addr_6845+1, *sp++); + outb(addr_6845, 0x05); /* Horizontal Retrace End */ + outb(addr_6845+1, *sp++); + + outb(addr_6845, 0x13); /* Row Offset Register */ + outb(addr_6845+1, *sp++); + + outb(TS_INDEX, TS_MODE);/* Timing Sequencer */ + outb(TS_DATA, *sp++); + + if(color) + inb(GN_INPSTAT1C); + else + inb(GN_INPSTAT1M); + /* ATC Mode control */ + outb(ATC_INDEX, ATC_MODE | ATC_ACCESS); + outb(ATC_DATAW, *sp++); + + if(color) + inb(GN_INPSTAT1C); + else + inb(GN_INPSTAT1M); + /* ATC Horizontal Pixel Panning */ + outb(ATC_INDEX, ATC_HORPIXPAN | ATC_ACCESS); + outb(ATC_DATAW, *sp++); + + outb(TS_INDEX, TS_SYNCRESET); + outb(TS_DATA, 0x01); /* synchronous reset */ + + outb(TS_INDEX, 0x83); + outb(TS_DATA, *sp++); + + outb(TS_INDEX, 0xa4); + outb(TS_DATA, *sp++); + + outb(TS_INDEX, 0xe0); + outb(TS_DATA, *sp++); + + outb(TS_INDEX, 0xe4); + outb(TS_DATA, *sp++); + + outb(TS_INDEX, 0xf8); + outb(TS_DATA, *sp++); + + outb(TS_INDEX, 0xfd); + outb(TS_DATA, *sp++); + + outb(GN_MISCOUTW, *sp++); /* Misc output register */ + + outb(TS_INDEX, TS_SYNCRESET); + outb(TS_DATA, 0x03); /* clear synchronous reset */ + } + + outb(TS_INDEX, TS_EXTCNTL); /* disable extensions */ + outb(TS_DATA, 0xae); + + /* disable access to first 7 CRTC registers */ + + outb(addr_6845, CRTC_VSYNCE); + outb(addr_6845+1, save__byte); + + vga_screen_on(); + + return(1); +} + +/*---------------------------------------------------------------------------* + * toggle 80/132 column operation for S3 86C928 based boards + *---------------------------------------------------------------------------*/ +int +s3_928_col(int cols) +{ + u_char *sp; + u_char byte; + + vga_screen_off(); + + outb(addr_6845, 0x38); + outb(addr_6845+1, 0x48); /* unlock registers */ + outb(addr_6845, 0x39); + outb(addr_6845+1, 0xa0); /* unlock registers */ + + /* enable access to first 7 CRTC registers */ + + outb(addr_6845, CRTC_VSYNCE); + byte = inb(addr_6845+1); + outb(addr_6845, CRTC_VSYNCE); + outb(addr_6845+1, byte & 0x7f); + + if(cols == SCR_COL132) /* switch 80 -> 132 */ + { + /* save state of board for 80 columns */ + + if(!regsaved) + { + regsaved = 1; + + sp = savearea.s3_928; + + outb(addr_6845, 0x00); /* Horizontal Total */ + *sp++ = inb(addr_6845+1); + outb(addr_6845, 0x01); /* Horizontal Display End */ + *sp++ = inb(addr_6845+1); + outb(addr_6845, 0x02); /* Horizontal Blank Start */ + *sp++ = inb(addr_6845+1); + outb(addr_6845, 0x03); /* Horizontal Blank End */ + *sp++ = inb(addr_6845+1); + outb(addr_6845, 0x04); /* Horizontal Retrace Start */ + *sp++ = inb(addr_6845+1); + outb(addr_6845, 0x05); /* Horizontal Retrace End */ + *sp++ = inb(addr_6845+1); + + outb(addr_6845, 0x13); /* Row Offset Register */ + *sp++ = inb(addr_6845+1); + + outb(addr_6845, 0x34); /* Backward Compat 3 Reg */ + *sp++ = inb(addr_6845+1); + outb(addr_6845, 0x3b); /* Data Xfer Exec Position */ + *sp++ = inb(addr_6845+1); + + outb(addr_6845, 0x42); /* (Clock) Mode Control */ + *sp++ = inb(addr_6845+1); + + outb(TS_INDEX, TS_MODE);/* Timing Sequencer */ + *sp++ = inb(TS_DATA); + + if(color) + inb(GN_INPSTAT1C); + else + inb(GN_INPSTAT1M); + /* ATC Mode control */ + outb(ATC_INDEX, ATC_MODE | ATC_ACCESS); + *sp++ = inb(ATC_DATAR); + + if(color) + inb(GN_INPSTAT1C); + else + inb(GN_INPSTAT1M); + /* ATC Horizontal Pixel Panning */ + outb(ATC_INDEX, ATC_HORPIXPAN | ATC_ACCESS); + *sp++ = inb(ATC_DATAR); + + *sp++ = inb(GN_MISCOUTR); /* Misc output register */ + } + + /* setup chipset for 132 column operation */ + + outb(addr_6845, 0x00); /* Horizontal Total */ + outb(addr_6845+1, 0x9a); + outb(addr_6845, 0x01); /* Horizontal Display End */ + outb(addr_6845+1, 0x83); + outb(addr_6845, 0x02); /* Horizontal Blank Start */ + outb(addr_6845+1, 0x86); + outb(addr_6845, 0x03); /* Horizontal Blank End */ + outb(addr_6845+1, 0x9d); + outb(addr_6845, 0x04); /* Horizontal Retrace Start */ + outb(addr_6845+1, 0x87); + outb(addr_6845, 0x05); /* Horizontal Retrace End */ + outb(addr_6845+1, 0x1b); + + outb(addr_6845, 0x13); /* Row Offset Register */ + outb(addr_6845+1, 0x42); + + outb(addr_6845, 0x34); + outb(addr_6845+1, 0x10);/* enable data xfer pos control */ + outb(addr_6845, 0x3b); + outb(addr_6845+1, 0x90);/* set data xfer pos value */ + + outb(addr_6845, 0x42); /* (Clock) Mode Control */ + outb(addr_6845+1, 0x02);/* Select 40MHz Clock */ + + outb(TS_INDEX, TS_MODE);/* Timing Sequencer */ + outb(TS_DATA, 0x01); /* 8 dot char clock */ + + if(color) + inb(GN_INPSTAT1C); + else + inb(GN_INPSTAT1M); + outb(ATC_INDEX, ATC_MODE | ATC_ACCESS); /* ATC Mode control */ + outb(ATC_DATAW, 0x08); /* Line graphics disable */ + + if(color) + inb(GN_INPSTAT1C); + else + inb(GN_INPSTAT1M); + outb(ATC_INDEX, ATC_HORPIXPAN | ATC_ACCESS); /* ATC Horizontal Pixel Panning */ + outb(ATC_DATAW, 0x00); + + /* Misc output register */ + + outb(GN_MISCOUTW, (inb(GN_MISCOUTR) | 0x0c)); + } + else /* switch 132 -> 80 */ + { + if(!regsaved) /* failsafe */ + { + /* disable access to first 7 CRTC registers */ + outb(addr_6845, CRTC_VSYNCE); + outb(addr_6845+1, byte); + + outb(addr_6845, 0x38); + outb(addr_6845+1, 0x00); /* lock registers */ + outb(addr_6845, 0x39); + outb(addr_6845+1, 0x00); /* lock registers */ + + vga_screen_on(); + return(0); + } + + sp = savearea.s3_928; + + outb(addr_6845, 0x00); /* Horizontal Total */ + outb(addr_6845+1, *sp++); + outb(addr_6845, 0x01); /* Horizontal Display End */ + outb(addr_6845+1, *sp++); + outb(addr_6845, 0x02); /* Horizontal Blank Start */ + outb(addr_6845+1, *sp++); + outb(addr_6845, 0x03); /* Horizontal Blank End */ + outb(addr_6845+1, *sp++); + outb(addr_6845, 0x04); /* Horizontal Retrace Start */ + outb(addr_6845+1, *sp++); + outb(addr_6845, 0x05); /* Horizontal Retrace End */ + outb(addr_6845+1, *sp++); + + outb(addr_6845, 0x13); /* Row Offset Register */ + outb(addr_6845+1, *sp++); + + outb(addr_6845, 0x34); + outb(addr_6845+1, *sp++); + outb(addr_6845, 0x3b); + outb(addr_6845+1, *sp++); + + outb(addr_6845, 0x42); /* Mode control */ + outb(addr_6845+1, *sp++); + + outb(TS_INDEX, TS_MODE);/* Timing Sequencer */ + outb(TS_DATA, *sp++); + + if(color) + inb(GN_INPSTAT1C); + else + inb(GN_INPSTAT1M); + /* ATC Mode control */ + outb(ATC_INDEX, ATC_MODE | ATC_ACCESS); + outb(ATC_DATAW, *sp++); + + if(color) + inb(GN_INPSTAT1C); + else + inb(GN_INPSTAT1M); + /* ATC Horizontal Pixel Panning */ + outb(ATC_INDEX, ATC_HORPIXPAN | ATC_ACCESS); + outb(ATC_DATAW, *sp++); + + outb(GN_MISCOUTW, *sp++); /* Misc output register */ + } + + /* disable access to first 7 CRTC registers */ + + outb(addr_6845, CRTC_VSYNCE); + outb(addr_6845+1, byte); + + outb(addr_6845, 0x38); + outb(addr_6845+1, 0x00); /* lock registers */ + outb(addr_6845, 0x39); + outb(addr_6845+1, 0x00); /* lock registers */ + + vga_screen_on(); + + return(1); +} + +/*---------------------------------------------------------------------------* + * toggle 80/132 column operation for Cirrus Logic 542x based boards + *---------------------------------------------------------------------------*/ +int +cl_gd542x_col(int cols) +{ + u_char *sp; + u_char byte; + + vga_screen_off(); + + /* enable access to first 7 CRTC registers */ + + outb(addr_6845, CRTC_VSYNCE); + byte = inb(addr_6845+1); + outb(addr_6845, CRTC_VSYNCE); + outb(addr_6845+1, byte & 0x7f); + + /* enable access to cirrus extension registers */ + outb(TS_INDEX, 6); + outb(TS_DATA, 0x12); + + if(cols == SCR_COL132) /* switch 80 -> 132 */ + { + /* save state of board for 80 columns */ + + if(!regsaved) + { + regsaved = 1; + + sp = savearea.cirrus; + + outb(addr_6845, 0x00); /* Horizontal Total */ + *sp++ = inb(addr_6845+1); + outb(addr_6845, 0x01); /* Horizontal Display End */ + *sp++ = inb(addr_6845+1); + outb(addr_6845, 0x02); /* Horizontal Blank Start */ + *sp++ = inb(addr_6845+1); + outb(addr_6845, 0x03); /* Horizontal Blank End */ + *sp++ = inb(addr_6845+1); + outb(addr_6845, 0x04); /* Horizontal Retrace Start */ + *sp++ = inb(addr_6845+1); + outb(addr_6845, 0x05); /* Horizontal Retrace End */ + *sp++ = inb(addr_6845+1); + + outb(addr_6845, 0x13); /* Row Offset Register */ + *sp++ = inb(addr_6845+1); + + outb(TS_INDEX, TS_MODE);/* Timing Sequencer */ + *sp++ = inb(TS_DATA); + + + if(color) + inb(GN_INPSTAT1C); + else + inb(GN_INPSTAT1M); + /* ATC Mode control */ + outb(ATC_INDEX, ATC_MODE | ATC_ACCESS); + *sp++ = inb(ATC_DATAR); + + if(color) + inb(GN_INPSTAT1C); + else + inb(GN_INPSTAT1M); + /* ATC Horizontal Pixel Panning */ + outb(ATC_INDEX, ATC_HORPIXPAN | ATC_ACCESS); + *sp++ = inb(ATC_DATAR); + + /* VCLK2 Numerator Register */ + outb(TS_INDEX, 0xd); + *sp++ = inb(TS_DATA); + + /* VCLK2 Denominator and Post-Scalar Value Register */ + outb(TS_INDEX, 0x1d); + *sp++ = inb(TS_DATA); + + /* Misc output register */ + *sp++ = inb(GN_MISCOUTR); + } + + /* setup chipset for 132 column operation */ + + outb(addr_6845, 0x00); /* Horizontal Total */ + outb(addr_6845+1, 0x9f); + outb(addr_6845, 0x01); /* Horizontal Display End */ + outb(addr_6845+1, 0x83); + outb(addr_6845, 0x02); /* Horizontal Blank Start */ + outb(addr_6845+1, 0x84); + outb(addr_6845, 0x03); /* Horizontal Blank End */ + outb(addr_6845+1, 0x82); + outb(addr_6845, 0x04); /* Horizontal Retrace Start */ + outb(addr_6845+1, 0x8a); + outb(addr_6845, 0x05); /* Horizontal Retrace End */ + outb(addr_6845+1, 0x9e); + + outb(addr_6845, 0x13); /* Row Offset Register */ + outb(addr_6845+1, 0x42); + + /* set VCLK2 to 41.164 MHz ..... */ + outb(TS_INDEX, 0xd); /* VCLK2 Numerator Register */ + outb(TS_DATA, 0x45); + + outb(TS_INDEX, 0x1d); /* VCLK2 Denominator and */ + outb(TS_DATA, 0x30); /* Post-Scalar Value Register */ + + /* and use it. */ + outb(GN_MISCOUTW, (inb(GN_MISCOUTR) & ~0x0c) | (2 << 2)); + + outb(TS_INDEX, TS_MODE);/* Timing Sequencer */ + outb(TS_DATA, 0x01); /* 8 dot char clock */ + + if(color) + inb(GN_INPSTAT1C); + else + inb(GN_INPSTAT1M); + outb(ATC_INDEX, ATC_MODE | ATC_ACCESS); /* ATC Mode control */ + outb(ATC_DATAW, 0x08); /* Line graphics disable */ + + if(color) + inb(GN_INPSTAT1C); + else + inb(GN_INPSTAT1M); + outb(ATC_INDEX, ATC_HORPIXPAN | ATC_ACCESS); /* ATC Horizontal Pixel Panning */ + outb(ATC_DATAW, 0x00); + } + else /* switch 132 -> 80 */ + { + if(!regsaved) /* failsafe */ + { + /* disable access to first 7 CRTC registers */ + outb(addr_6845, CRTC_VSYNCE); + outb(addr_6845+1, byte); + + /* disable access to cirrus extension registers */ + outb(TS_INDEX, 6); + outb(TS_DATA, 0); + + vga_screen_on(); + return(0); + } + + sp = savearea.cirrus; + + outb(addr_6845, 0x00); /* Horizontal Total */ + outb(addr_6845+1, *sp++); + outb(addr_6845, 0x01); /* Horizontal Display End */ + outb(addr_6845+1, *sp++); + outb(addr_6845, 0x02); /* Horizontal Blank Start */ + outb(addr_6845+1, *sp++); + outb(addr_6845, 0x03); /* Horizontal Blank End */ + outb(addr_6845+1, *sp++); + outb(addr_6845, 0x04); /* Horizontal Retrace Start */ + outb(addr_6845+1, *sp++); + outb(addr_6845, 0x05); /* Horizontal Retrace End */ + outb(addr_6845+1, *sp++); + + outb(addr_6845, 0x13); /* Row Offset Register */ + outb(addr_6845+1, *sp++); + + outb(TS_INDEX, TS_MODE);/* Timing Sequencer */ + outb(TS_DATA, *sp++); + + if(color) + inb(GN_INPSTAT1C); + else + inb(GN_INPSTAT1M); + /* ATC Mode control */ + outb(ATC_INDEX, ATC_MODE | ATC_ACCESS); + outb(ATC_DATAW, *sp++); + + if(color) + inb(GN_INPSTAT1C); + else + inb(GN_INPSTAT1M); + /* ATC Horizontal Pixel Panning */ + outb(ATC_INDEX, ATC_HORPIXPAN | ATC_ACCESS); + outb(ATC_DATAW, *sp++); + + /* VCLK2 Numerator Register */ + outb(TS_INDEX, 0xd); + outb(TS_DATA, *sp++); + + /* VCLK2 Denominator and Post-Scalar Value Register */ + outb(TS_INDEX, 0x1d); + outb(TS_DATA, *sp++); + + outb(GN_MISCOUTW, *sp++); /* Misc output register */ + } + + /* disable access to cirrus extension registers */ + outb(TS_INDEX, 6); + outb(TS_DATA, 0); + + /* disable access to first 7 CRTC registers */ + + outb(addr_6845, CRTC_VSYNCE); + outb(addr_6845+1, byte); + + vga_screen_on(); + + return(1); +} + +#if PCVT_USL_VT_COMPAT +/*---------------------------------------------------------------------------* + * switch screen from text mode to X-mode and vice versa + *---------------------------------------------------------------------------*/ +void +switch_screen(int n, int oldgrafx, int newgrafx) +{ + +#if PCVT_SCREENSAVER + static unsigned saved_scrnsv_tmo = 0; +#endif /* PCVT_SCREENSAVER */ + +#if !PCVT_KBD_FIFO + int x; +#endif /* !PCVT_KBD_FIFO */ + + int cols = vsp->maxcol; /* get current col val */ + + if(n < 0 || n >= totalscreens) + return; + +#if !PCVT_KBD_FIFO + x = spltty(); /* protect us */ +#endif /* !PCVT_KBD_FIFO */ + + if(!oldgrafx && newgrafx) + { + /* switch from text to graphics */ + +#if PCVT_SCREENSAVER + if((saved_scrnsv_tmo = scrnsv_timeout)) + pcvt_set_scrnsv_tmo(0); /* screensaver off */ +#endif /* PCVT_SCREENSAVER */ + + async_update(UPDATE_STOP); /* status display off */ + } + + if(!oldgrafx) + { + /* switch from text mode */ + + /* video board memory -> kernel memory */ + bcopy(vsp->Crtat, vsp->Memory, + vsp->screen_rows * vsp->maxcol * CHR); + + vsp->Crtat = vsp->Memory; /* operate in memory now */ + } + + /* update global screen pointers/variables */ + current_video_screen = n; /* current screen no */ + +#if !PCVT_NETBSD && !(PCVT_FREEBSD > 110 && PCVT_FREEBSD < 200) + pcconsp = &pccons[n]; /* current tty */ +#elif PCVT_FREEBSD > 110 && PCVT_FREEBSD < 200 + pcconsp = pccons[n]; /* current tty */ +#else + pcconsp = pc_tty[n]; /* current tty */ +#endif + + vsp = &vs[n]; /* current video state ptr */ + + if(oldgrafx && !newgrafx) + { + /* switch from graphics to text mode */ + unsigned i; + + /* restore fonts */ + for(i = 0; i < totalfonts; i++) + if(saved_charsets[i]) + vga_move_charset(i, 0, 0); + +#if PCVT_SCREENSAVER + /* activate screen saver */ + if(saved_scrnsv_tmo) + pcvt_set_scrnsv_tmo(saved_scrnsv_tmo); +#endif /* PCVT_SCREENSAVER */ + + /* re-initialize lost MDA information */ + if(adaptor_type == MDA_ADAPTOR) + { + /* + * Due to the fact that HGC registers are write-only, + * the Xserver can only make guesses about the state + * the HGC adaptor has been before turning on X mode. + * Thus, the display must be re-enabled now, and the + * cursor shape and location restored. + */ + outb(GN_DMCNTLM, 0x28); /* enable display, text mode */ + outb(addr_6845, CRTC_CURSORH); /* select high register */ + outb(addr_6845+1, + ((vsp->Crtat + vsp->cur_offset) - Crtat) >> 8); + outb(addr_6845, CRTC_CURSORL); /* select low register */ + outb(addr_6845+1, + ((vsp->Crtat + vsp->cur_offset) - Crtat)); + + outb(addr_6845, CRTC_CURSTART); /* select high register */ + outb(addr_6845+1, vsp->cursor_start); + outb(addr_6845, CRTC_CUREND); /* select low register */ + outb(addr_6845+1, vsp->cursor_end); + } + + /* make status display happy */ + async_update(UPDATE_START); + } + + if(!newgrafx) + { + /* to text mode */ + + /* kernel memory -> video board memory */ + bcopy(vsp->Crtat, Crtat, + vsp->screen_rows * vsp->maxcol * CHR); + + vsp->Crtat = Crtat; /* operate on screen now */ + + outb(addr_6845, CRTC_STARTADRH); + outb(addr_6845+1, 0); + outb(addr_6845, CRTC_STARTADRL); + outb(addr_6845+1, 0); + } + +#if !PCVT_KBD_FIFO + splx(x); +#endif /* !PCVT_KBD_FIFO */ + + select_vga_charset(vsp->vga_charset); + + if(vsp->maxcol != cols) + vga_col(vsp, vsp->maxcol); /* select 80/132 columns */ + + outb(addr_6845, CRTC_CURSORH); /* select high register */ + outb(addr_6845+1, vsp->cur_offset >> 8); + outb(addr_6845, CRTC_CURSORL); /* select low register */ + outb(addr_6845+1, vsp->cur_offset); + + if(vsp->cursor_on) + { + outb(addr_6845, CRTC_CURSTART); /* select high register */ + outb(addr_6845+1, vsp->cursor_start); + outb(addr_6845, CRTC_CUREND); /* select low register */ + outb(addr_6845+1, vsp->cursor_end); + } + else + { + sw_cursor(0); + } + + if(adaptor_type == VGA_ADAPTOR) + { + unsigned i; + + /* switch VGA DAC palette entries */ + for(i = 0; i < NVGAPEL; i++) + vgapaletteio(i, &vsp->palette[i], 1); + } + + if(!newgrafx) + { + update_led(); /* update led's */ + update_hp(vsp); /* update fkey labels, if present */ + + /* if we switch to a vt with force 24 lines mode and */ + /* pure VT emulation and 25 rows charset, then we have */ + /* to clear the last line on display ... */ + + if(vsp->force24 && (vsp->vt_pure_mode == M_PUREVT) && + (vgacs[vsp->vga_charset].screen_size == SIZ_25ROWS)) + { + fillw(' ', vsp->Crtat + vsp->screen_rows * vsp->maxcol, + vsp->maxcol); + } + } +} + +/*---------------------------------------------------------------------------* + * Change specified vt to VT_AUTO mode + * xxx Maybe this should also reset VT_GRAFX mode; since switching and + * graphics modes are not going to work without VT_PROCESS mode. + *---------------------------------------------------------------------------*/ +static void +set_auto_mode (struct video_state *vsx) +{ + unsigned ostatus = vsx->vt_status; + vsx->smode.mode = VT_AUTO; + vsx->proc = NULL; + vsx->pid = 0; + vsx->vt_status &= ~(VT_WAIT_REL|VT_WAIT_ACK); + if (ostatus & VT_WAIT_ACK) { +#if 0 + assert (!(ostatus&VT_WAIT_REL)); + assert (vsp == vsx && + vt_switch_pending == current_video_screen + 1); + vt_switch_pending = 0; +#else + if (vsp == vsx && + vt_switch_pending == current_video_screen + 1) + vt_switch_pending = 0; +#endif + } + if (ostatus&VT_WAIT_REL) { + int new_screen = vt_switch_pending - 1; +#if 0 + assert(vsp == vsx && vt_switch_pending); + vt_switch_pending = 0; + vgapage (new_screen); +#else + if (vsp == vsx && vt_switch_pending) { + vt_switch_pending = 0; + vgapage (new_screen); + } +#endif + } +} + +/*---------------------------------------------------------------------------* + * Exported function; to be called when a vt is closed down. + * + * Ideally, we would like to be able to recover from an X server crash; + * but in reality, if the server crashes hard while in control of the + * vga board, then you're not likely to be able to use pcvt ttys + * without rebooting. + *---------------------------------------------------------------------------*/ +void +reset_usl_modes (struct video_state *vsx) +{ + /* Clear graphics mode */ + if (vsx->vt_status & VT_GRAFX) { + vsx->vt_status &= ~VT_GRAFX; + if (vsp == vsx) + switch_screen(current_video_screen, 1, 0); + } + + /* Take kbd out of raw mode */ + if (pcvt_kbd_raw && vsp == vsx) { +#if PCVT_SCANSET > 1 + kbd_emulate_pc(0); +#endif /* PCVT_SCANSET > 1 */ + pcvt_kbd_raw = 0; + } + + /* Clear process controlled mode */ + set_auto_mode (vsx); +} + +/*---------------------------------------------------------------------------* + * switch to virtual screen n (0 ... PCVT_NSCREENS-1), VT_USL version + * (the name vgapage() stands for historical reasons) + *---------------------------------------------------------------------------*/ +int +vgapage(int new_screen) +{ + int x; + + if(new_screen < 0 || new_screen >= totalscreens) + return EINVAL; + + /* fallback to VT_AUTO if controlling processes died */ + if(vsp->proc && vsp->proc != pfind(vsp->pid)) + set_auto_mode(vsp); + if(vs[new_screen].proc + && vs[new_screen].proc != pfind(vs[new_screen].pid)) + set_auto_mode(&vs[new_screen]); + + if (!vt_switch_pending && new_screen == current_video_screen) + return 0; + + if(vt_switch_pending && vt_switch_pending != new_screen + 1) { + /* Try resignaling uncooperative X-window servers */ + if (vsp->smode.mode == VT_PROCESS) { + if (vsp->vt_status & VT_WAIT_REL) { + if(vsp->smode.relsig) + psignal(vsp->proc, vsp->smode.relsig); + } else if (vsp->vt_status & VT_WAIT_ACK) { + if(vsp->smode.acqsig) + psignal(vsp->proc, vsp->smode.acqsig); + } + } + return EAGAIN; + } + + vt_switch_pending = new_screen + 1; + + if(vsp->smode.mode == VT_PROCESS) + { + /* we cannot switch immediately here */ + vsp->vt_status |= VT_WAIT_REL; + if(vsp->smode.relsig) + psignal(vsp->proc, vsp->smode.relsig); + } + else + { + struct video_state *old_vsp = vsp; + + switch_screen(new_screen, + vsp->vt_status & VT_GRAFX, + vs[new_screen].vt_status & VT_GRAFX); + + x = spltty(); + if(old_vsp->vt_status & VT_WAIT_ACT) + { + old_vsp->vt_status &= ~VT_WAIT_ACT; + wakeup((caddr_t)&old_vsp->smode); + } + if(vsp->vt_status & VT_WAIT_ACT) + { + vsp->vt_status &= ~VT_WAIT_ACT; + wakeup((caddr_t)&vsp->smode); + } + splx(x); + + if(vsp->smode.mode == VT_PROCESS) + { + /* if _new_ vt is under process control... */ + vsp->vt_status |= VT_WAIT_ACK; + if(vsp->smode.acqsig) + psignal(vsp->proc, vsp->smode.acqsig); + } + else + { + /* we are committed */ + vt_switch_pending = 0; +#if PCVT_FREEBSD > 206 + /* + * XXX: If pcvt is acting as the systems console, + * avoid panics going to the debugger while we are in + * process mode. + */ + if(pcvt_is_console) + cons_unavail = 0; +#endif + } + } + return 0; +} + +/*---------------------------------------------------------------------------* + * ioctl handling for VT_USL mode + *---------------------------------------------------------------------------*/ +int +usl_vt_ioctl(Dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) +{ + int i, j, error, opri; + struct vt_mode newmode; + + switch(cmd) + { + + case VT_SETMODE: + newmode = *(struct vt_mode *)data; + + opri = spltty(); + + if (newmode.mode != VT_PROCESS) { + struct video_state *vsx = &vs[minor(dev)]; + if (vsx->smode.mode == VT_PROCESS) { + if (vsx->proc != p) { + splx(opri); + return EPERM; + } + set_auto_mode(vsx); + } + splx(opri); + return 0; + } + + /* + * NB: XFree86-3.1.1 does the following: + * VT_ACTIVATE (vtnum) + * VT_WAITACTIVE (vtnum) + * VT_SETMODE (VT_PROCESS) + * So it is possible that the screen was switched + * between the WAITACTIVE and the SETMODE (here). This + * can actually happen quite frequently, and it was + * leading to dire consequences. Now it is detected by + * requiring that minor(dev) match current_video_screen. + * An alternative would be to operate on vs[minor(dev)] + * instead of *vsp, but that would leave the server + * confused, because it would believe that its vt was + * currently activated. + */ + if (minor(dev) != current_video_screen) { + splx(opri); + return EPERM; + } + + /* Check for server died */ + if(vsp->proc && vsp->proc != pfind(vsp->pid)) + set_auto_mode(vsp); + + /* Check for server already running */ + if (vsp->smode.mode == VT_PROCESS && vsp->proc != p) + { + splx(opri); + return EBUSY; /* already in use on this VT */ + } + + if (!ISSIGVALID(newmode.relsig) || !ISSIGVALID(newmode.acqsig) + || !ISSIGVALID(newmode.frsig)) + { + splx(opri); + return EINVAL; + } + + vsp->smode = newmode; + vsp->proc = p; + vsp->pid = p->p_pid; + +#if PCVT_FREEBSD > 206 + /* + * XXX: If pcvt is acting as the systems console, + * avoid panics going to the debugger while we are in + * process mode. + */ + if(pcvt_is_console) + cons_unavail = (newmode.mode == VT_PROCESS); +#endif + splx(opri); + return 0; + + case VT_GETMODE: + *(struct vt_mode *)data = vsp->smode; + return 0; + + case VT_RELDISP: + if (minor(dev) != current_video_screen) + return EPERM; + if (vsp->smode.mode != VT_PROCESS) + return EINVAL; + if (vsp->proc != p) + return EPERM; + switch(*(int *)data) { + case VT_FALSE: + /* process refuses to release screen; abort */ + if(vt_switch_pending + && (vsp->vt_status & VT_WAIT_REL)) { + vsp->vt_status &= ~VT_WAIT_REL; + vt_switch_pending = 0; + return 0; + } + break; + + case VT_TRUE: + /* process releases its VT */ + if(vt_switch_pending + && (vsp->vt_status & VT_WAIT_REL)) { + int new_screen = vt_switch_pending - 1; + struct video_state *old_vsp = vsp; + + vsp->vt_status &= ~VT_WAIT_REL; + + switch_screen(new_screen, + vsp->vt_status & VT_GRAFX, + vs[new_screen].vt_status + & VT_GRAFX); + + opri = spltty(); + if(old_vsp->vt_status & VT_WAIT_ACT) + { + old_vsp->vt_status &= ~VT_WAIT_ACT; + wakeup((caddr_t)&old_vsp->smode); + } + if(vsp->vt_status & VT_WAIT_ACT) + { + vsp->vt_status &= ~VT_WAIT_ACT; + wakeup((caddr_t)&vsp->smode); + } + splx(opri); + + if(vsp->smode.mode == VT_PROCESS) { + /* + * if the new vt is also in process + * mode, we have to wait until its + * controlling process acknowledged + * the switch + */ + vsp->vt_status + |= VT_WAIT_ACK; + if(vsp->smode.acqsig) + psignal(vsp->proc, + vsp->smode.acqsig); + } + else + { + /* we are committed */ + vt_switch_pending = 0; +#if PCVT_FREEBSD > 206 + /* XXX */ + if(pcvt_is_console) + cons_unavail = 0; +#endif + } + return 0; + } + break; + + case VT_ACKACQ: + /* new vts controlling process acknowledged */ + if(vsp->vt_status & VT_WAIT_ACK) { + vt_switch_pending = 0; + vsp->vt_status &= ~VT_WAIT_ACK; +#if PCVT_FREEBSD > 206 + /* XXX */ + if(pcvt_is_console) + cons_unavail = 1; +#endif + return 0; + } + break; + } + return EINVAL; /* end case VT_RELDISP */ + + + case VT_OPENQRY: + /* return free vt */ + for(i = 0; i < PCVT_NSCREENS; i++) + if(!vs[i].openf) { + *(int *)data = i + 1; + return 0; + } + return EAGAIN; + + case VT_GETACTIVE: + *(int *)data = current_video_screen + 1; + return 0; + + case VT_ACTIVATE: + return vgapage(*(int *)data - 1); + + case VT_WAITACTIVE: + /* sleep until vt switch happened */ + i = *(int *)data - 1; + + if(i != -1 + && (i < 0 || i >= PCVT_NSCREENS)) + return EINVAL; + + if(i != -1 && current_video_screen == i) + return 0; + + if(i == -1) + i = minor(dev); + + { + int x = spltty(); + error = 0; + while (current_video_screen != i && + (error == 0 || error == ERESTART)) + { + vs[i].vt_status |= VT_WAIT_ACT; + error = tsleep((caddr_t)&vs[i].smode, + PZERO | PCATCH, "waitvt", 0); + } + splx(x); + } + return error; + + case KDENABIO: + /* grant the process IO access; only allowed if euid == 0 */ + /* and insecure */ + { + +#if PCVT_NETBSD > 9 || PCVT_FREEBSD >= 200 + struct trapframe *fp = p->p_md.md_regs; +#elif PCVT_NETBSD || (PCVT_FREEBSD && PCVT_FREEBSD > 102) + struct trapframe *fp = (struct trapframe *)p->p_regs; +#else + struct syscframe *fp = (struct syscframe *)p->p_regs; +#endif + + error = suser(p->p_ucred, &p->p_acflag); + if (error != 0) + return (error); + if (securelevel > 0) + return (EPERM); + +#if PCVT_NETBSD || (PCVT_FREEBSD && PCVT_FREEBSD > 102) + fp->tf_eflags |= PSL_IOPL; +#else + fp->sf_eflags |= PSL_IOPL; +#endif + + return 0; + } + + case KDDISABIO: + /* abandon IO access permission */ + { + +#if PCVT_NETBSD > 9 || PCVT_FREEBSD >= 200 + struct trapframe *fp = p->p_md.md_regs; + fp->tf_eflags &= ~PSL_IOPL; +#elif PCVT_NETBSD || (PCVT_FREEBSD && PCVT_FREEBSD > 102) + struct trapframe *fp = (struct trapframe *)p->p_regs; + fp->tf_eflags &= ~PSL_IOPL; +#else + struct syscframe *fp = (struct syscframe *)p->p_regs; + fp->sf_eflags &= ~PSL_IOPL; +#endif + + return 0; + } + + case KDSETMODE: + { + struct video_state *vsx = &vs[minor(dev)]; + int haschanged = 0; + + if(adaptor_type != VGA_ADAPTOR + && adaptor_type != MDA_ADAPTOR) + /* X will only run on those adaptors */ + return (EINVAL); + + /* set text/graphics mode of current vt */ + switch(*(int *)data) + { + case KD_TEXT: + haschanged = (vsx->vt_status & VT_GRAFX) != 0; + vsx->vt_status &= ~VT_GRAFX; + if(haschanged && vsx == vsp) + switch_screen(current_video_screen, 1, 0); + return 0; + + case KD_GRAPHICS: + /* xxx It might be a good idea to require that + the vt be in process controlled mode here, + and that the calling process is the owner */ + haschanged = (vsx->vt_status & VT_GRAFX) == 0; + vsx->vt_status |= VT_GRAFX; + if(haschanged && vsx == vsp) + switch_screen(current_video_screen, 0, 1); + return 0; + + } + return EINVAL; /* end case KDSETMODE */ + } + + case KDSETRAD: + /* set keyboard repeat and delay */ + return kbdioctl(dev, KBDSTPMAT, data, flag); + + case KDSKBMODE: + switch(*(int *)data) + { + case K_RAW: + +#if PCVT_SCANSET > 1 + /* put keyboard to return ancient PC scan codes */ + kbd_emulate_pc(1); +#endif /* PCVT_SCANSET > 1 */ + + pcvt_kbd_raw = 1; + shift_down = meta_down = altgr_down = ctrl_down = 0; + return 0; + + case K_XLATE: + +#if PCVT_SCANSET > 1 + kbd_emulate_pc(0); +#endif /* PCVT_SCANSET > 1 */ + + pcvt_kbd_raw = 0; + return 0; + } + return EINVAL; /* end KDSKBMODE */ + + case KDMKTONE: + /* ring the speaker */ + if(data) + { + int duration = *(int *)data >> 16; + int pitch = *(int *)data & 0xffff; + +#if PCVT_NETBSD + if(pitch != 0) + { + sysbeep(PCVT_SYSBEEPF / pitch, + duration * hz / 1000); + } +#else /* PCVT_NETBSD */ + sysbeep(pitch, duration * hz / 3000); +#endif /* PCVT_NETBSD */ + + } + else + { + sysbeep(PCVT_SYSBEEPF / 1493, hz / 4); + } + return 0; + + case KDSETLED: + /* set kbd LED status */ + /* unfortunately, the LED definitions between pcvt and */ + /* USL differ some way :-( */ + i = *(int *)data; + j = (i & LED_CAP? KBD_CAPSLOCK: 0) + + (i & LED_NUM? KBD_NUMLOCK: 0) + + (i & LED_SCR? KBD_SCROLLLOCK: 0); + return kbdioctl(dev, KBDSLOCK, (caddr_t)&j, flag); + + case KDGETLED: + /* get kbd LED status */ + if((error = kbdioctl(dev, KBDGLOCK, (caddr_t)&j, flag))) + return error; + i = (j & KBD_CAPSLOCK? LED_CAP: 0) + + (j & KBD_NUMLOCK? LED_NUM: 0) + + (j & KBD_SCROLLLOCK? LED_SCR: 0); + *(int *)data = i; + return 0; + + case GIO_KEYMAP: + get_usl_keymap((keymap_t *)data); + return 0; + } /* end case cmd */ + + return -1; /* inappropriate usl_vt_compat ioctl */ +} +#endif /* PCVT_USL_VT_COMPAT */ + +#endif /* NVT > 0 */ + +/* ------------------------- E O F ------------------------------------------*/ + |