diff options
Diffstat (limited to 'sys/i386/isa/pcvt/pcvt_ext.c')
-rw-r--r-- | sys/i386/isa/pcvt/pcvt_ext.c | 2613 |
1 files changed, 2613 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..56460eb --- /dev/null +++ b/sys/i386/isa/pcvt/pcvt_ext.c @@ -0,0 +1,2613 @@ +/* + * 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 Jan 5 15:54:10 1995] + * + */ + +/*---------------------------------------------------------------------------* + * + * pcvt_ext.c VT220 Driver Extended Support Routines + * ------------------------------------------------------ + * + * written by Hellmuth Michaelis, hm@hcshh.hcs.de and + * Joerg Wunsch, joerg_wunsch@uriah.sax.de + * + * -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 + * + *---------------------------------------------------------------------------*/ + +#include "vt.h" +#if NVT > 0 + +#include "pcvt_hdr.h" /* global include */ + +static int s3testwritable( void ); + +/* 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); +} + +/*---------------------------------------------------------------------------* + * switch screen from text mode to X-mode and vice versa + *---------------------------------------------------------------------------*/ +#if PCVT_USL_VT_COMPAT +static void +pcvt_x_hook(int tografx) +{ + int i; + +#if PCVT_SCREENSAVER + static unsigned saved_scrnsv_tmo = 0; +#endif /* PCVT_SCREENSAVER*/ + +#if PCVT_NETBSD + extern u_short *Crtat; +#endif /* PCVT_NETBSD */ + + /* save area for graphics mode switch */ + + if(!tografx) + { + /* into standard text mode */ + /* step 1: restore fonts */ + for(i = 0; i < totalfonts; i++) + if(saved_charsets[i]) + vga_move_charset(i, 0, 0); + + +#if PCVT_SCREENSAVER + /* step 2: activate screen saver */ + if(saved_scrnsv_tmo) + pcvt_set_scrnsv_tmo(saved_scrnsv_tmo); +#endif /* PCVT_SCREENSAVER */ + + /* step 3: 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. + */ + /* enable display, text mode */ + outb(GN_DMCNTLM, 0x28); + + /* restore cursor mode and shape */ + outb(addr_6845, CRTC_CURSORH); + outb(addr_6845+1, + ((vsp->Crtat + vsp->cur_offset) - Crtat) >> 8); + outb(addr_6845, CRTC_CURSORL); + outb(addr_6845+1, + ((vsp->Crtat + vsp->cur_offset) - Crtat)); + + outb(addr_6845, CRTC_CURSTART); + outb(addr_6845+1, vsp->cursor_start); + outb(addr_6845, CRTC_CUREND); + outb(addr_6845+1, vsp->cursor_end); + } + + /* step 4: restore screen and re-enable text output */ + + /* kernel memory -> video board memory */ + bcopy(vsp->Memory, Crtat, + vsp->screen_rowsize * 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); + + /* step 5: update leds and if applicable fkey labels */ + update_led(); + update_hp(vsp); + + /* step 6: make status display happy */ + async_update(UPDATE_START); + } + else /* tografx */ + { + /* switch to graphics mode: save everything we need */ + + /* step 1: deactivate screensaver */ + +#if PCVT_SCREENSAVER + if(saved_scrnsv_tmo = scrnsv_timeout) + pcvt_set_scrnsv_tmo(0); /* turn it off */ +#endif /* PCVT_SCREENSAVER */ + + /* step 2: handle status display */ + + async_update(UPDATE_STOP); /* turn off */ + + /* step 3: disable text output and save screen contents */ + + /* video board memory -> kernel memory */ + bcopy(vsp->Crtat, vsp->Memory, + vsp->screen_rowsize * vsp->maxcol * CHR); + + vsp->Crtat = vsp->Memory; /* operate in memory now */ + } +} + +/*---------------------------------------------------------------------------* + * 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; + + if(vsp->proc != pfind(vsp->pid)) + vt_switch_pending = 0; + + if(vt_switch_pending) + return EAGAIN; + + vt_switch_pending = new_screen + 1; + + x = spltty(); + if(vs[new_screen].vt_status & VT_WAIT_ACT) + { + wakeup((caddr_t)&vs[new_screen].smode); + vs[new_screen].vt_status &= ~VT_WAIT_ACT; + } + splx(x); + + if(new_screen == current_video_screen) + { + vt_switch_pending = 0; + return 0; + } + + /* fallback to VT_AUTO if controlling processes died */ + if(vsp->proc + && vsp->proc != pfind(vsp->pid)) + vsp->smode.mode = VT_AUTO; + if(vs[new_screen].proc + && vs[new_screen].proc != pfind(vs[new_screen].pid)) + vs[new_screen].smode.mode = VT_AUTO; + + 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 + { + int modechange = 0; + + if((vs[new_screen].vt_status & VT_GRAFX) != + (vsp->vt_status & VT_GRAFX)) + { + if(vsp->vt_status & VT_GRAFX) + modechange = 1; /* to text */ + else + modechange = 2; /* to grfx */ + } + + if(modechange == 2) + pcvt_x_hook(1); + + switch_screen(new_screen, vsp->vt_status & VT_GRAFX); + + if(modechange == 1) + pcvt_x_hook(0); + + 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 comitted */ + vt_switch_pending = 0; + } + 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; + + switch(cmd) + { + +#if PCVT_FAKE_SYSCONS10 + case CONS_GETVERS: + *(int *)data = 0x100; /* fake syscons 1.0 */ + return 0; +#endif /* PCVT_FAKE_SYSCONS10 */ + + case VT_SETMODE: + +/*--------------------------------------------------------------------------- + from John Kohl <jtk@kolvir.blrc.ma.us>: + + I think I tracked down the problem I had on NetBSD-current/i386 with + pcvt and losing keyboard control to a fresh X server trying to grab the + graphics mode on the same virtual console as an existing server. I + didn't have problems when I ran 'xinit -- :1' from another virtual + console; only when I ran it _from within an xterm_ did I have problems. + + Here's a patch which seems to fix the immediate problem; it makes the + VT_SETMODE fail if something tries to set process mode on the same VT as + an active process. However, this doesn't mean that "xinit -- vtY :1" + will start an X server on vtY--the context at the time of the VT_PROCESS + may still be the current virtual console if the existing X server + doesn't yield before the new one tries to set VT_PROCESS mode. Maybe + there's some missing handshake on the console switch completing. +---------------------------------------------------------------------------*/ + + if (vsp->smode.mode == VT_PROCESS && + ((struct vt_mode *)data)->mode == VT_PROCESS && + vsp->proc != p) + return EBUSY; /* already in use on this VT */ + +/* end of patch */ + + vsp->smode = *(struct vt_mode *)data; + if(vsp->smode.mode == VT_PROCESS) { + vsp->proc = p; + vsp->pid = p->p_pid; + } + return 0; + + case VT_GETMODE: + *(struct vt_mode *)data = vsp->smode; + return 0; + + case VT_RELDISP: + switch(*(int *)data) { + case VT_FALSE: + /* process refuses to release screen; abort */ + if(vt_switch_pending + && vt_switch_pending - 1 == current_video_screen + && (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 + && minor(dev) == current_video_screen + && (vsp->vt_status & VT_WAIT_REL)) { + int new_screen = vt_switch_pending - 1; + int modechange = 0; + + vsp->vt_status &= ~VT_WAIT_REL; + + if((vs[new_screen].vt_status & VT_GRAFX) != + (vsp->vt_status & VT_GRAFX)) + { + if(vsp->vt_status & VT_GRAFX) + modechange = 1; /* to text */ + else + modechange = 2; /* to grfx */ + } + + if(modechange == 2) + pcvt_x_hook(1); + + switch_screen(new_screen, + vsp->vt_status & VT_GRAFX); + + if(modechange == 1) + pcvt_x_hook(0); + + 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 comitted */ + vt_switch_pending = 0; + 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; + 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 + && minor(dev) == i) + return 0; + + if(i == -1) + { + int x = spltty(); + vsp->vt_status |= VT_WAIT_ACT; + while((error = tsleep((caddr_t)&vsp->smode, + PZERO | PCATCH, "waitvt", 0)) + == ERESTART) + ; + vsp->vt_status &= ~VT_WAIT_ACT; + splx(x); + } + else + { + int x = spltty(); + vs[i].vt_status |= VT_WAIT_ACT; + while((error = tsleep((caddr_t)&vs[i].smode, + PZERO | PCATCH, "waitvt", 0)) + == ERESTART) + ; + vs[i].vt_status &= ~VT_WAIT_ACT; + splx(x); + } + return error; + + case KDENABIO: + /* grant the process IO access; only allowed if euid == 0 */ + { +#if PCVT_NETBSD > 9 || PCVT_FREEBSD >= 200 + struct trapframe *fp = (struct trapframe *)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 /* PCVT_NETBSD || PCVT_FREEBSD > 102 */ + + if(suser(p->p_ucred, &p->p_acflag) != 0) + return (EPERM); + +#if PCVT_NETBSD || (PCVT_FREEBSD && PCVT_FREEBSD > 102) + fp->tf_eflags |= PSL_IOPL; +#else + fp->sf_eflags |= PSL_IOPL; +#endif /* PCVT_NETBSD || PCVT_FREEBSD > 102 */ + + return 0; + } + + case KDDISABIO: + /* abandon IO access permission */ + { +#if PCVT_NETBSD > 9 || PCVT_FREEBSD >= 200 + struct trapframe *fp = (struct trapframe *)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 /* PCVT_NETBSD || PCVT_FREEBSD > 102 */ + + 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) + pcvt_x_hook(0); + return 0; + + case KD_GRAPHICS: + haschanged = (vsx->vt_status & VT_GRAFX) == 0; + vsx->vt_status |= VT_GRAFX; + if(haschanged && vsx == vsp) + pcvt_x_hook(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; + + sysbeep(pitch, duration * hz / 3000); + } + 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 ------------------------------------------*/ + |