# # Fri Feb 28 10:35:11 MET 1997 # Tage Stabell-Kulx # tage@acm.org # IBM ThinkPad 560 # NetBSD # 1.2 # 3.2 # SVGA # tgui9660xgi # 12.1 # TFT # Use cy9382.c and link with -li386 # //// Tage Stabell-Kuloe | e-mail: tage@ACM.org //// /// Department of Computer Science/IMR | Phone : +47-776-44032 /// // 9037 University of Tromsoe, Norway | Fax : +47-776-44580 // / "'oe' is '\o' in TeX" | URL:http://www.cs.uit.no/~tage/ /* * Copyright (c) 1996 * Ipsilon Networks, Inc. * * 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 Ipsilon Networks, Inc. * 4. The name of Ipsilon Networks, Inc., may not be used to endorse or * promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY IPSILON NETWORKS, INC., ``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 IPSILON NETWORKS, INC., 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. * */ /* * cy9382 - allow ThinkPad 560's (with Trident Cyber9382 chip) * to run 800x600 on XFree86 3.1.2E. * * Author: Greg Minshall * Linux hacks: Valery Petrov * NetBSD hacks: Tage Stabell-Kulx . Also separated * FreeBSD from "UNIX". */ /* * linux also defines 'unix', so figure out something which is * unique (just to make the code look slightly nicer). */ #if defined(linux) #define LINUX #undef UNIX #endif #if (defined(unix) && !(defined(linux))) #define UNIX #undef LINUX #endif #include #include #include #if defined(UNIX) #ifdef __NetBSD__ # include # include #endif #include #include #include #endif /* defined(UNIX) */ #if defined(LINUX) #include #endif /* defined(LINUX) */ #include /* * On FreeBSD, out(port, value). * On Linux, out(value, port). */ #if defined(UNIX) #define _outb(x,y) outb(x,y) #endif /* defined(UNIX) */ #if defined(LINUX) #define _outb(x,y) outb(y,x) #endif /* defined(LINUX) */ /* make sure we figured out how to work */ #if !defined(_outb) #error "neither Unix nor Linux!" #endif /* * Trident specific things (thanks to Kendall Bennett !) */ inline static void tri_olddefs(void) { _outb(0x3c4, 0xb); _outb(0x3c5, 0xb); } inline static void tri_newdefs(void) { tri_olddefs(); (void) inb(0x3c5); } inline static void tri_unlock(void) { unsigned a; tri_newdefs(); _outb(0x3c4, 0xe); a = inb(0x3c5); a |= 0x80; /* unlock registers */ _outb(0x3c5, a); } inline static void tri_lock(void) { unsigned a; tri_newdefs(); _outb(0x3c4, 0xe); a = inb(0x3c5); a &= ~0x80; /* unlock registers */ _outb(0x3c5, a); } /* * get a value directly from a port (no index) */ int g_et(int port) { return inb(port); } /* * get a value from an index off a port */ int g_etx(int port, int index) { switch (port) { case 0x3c5: case 0x3cf: case 0x3d5: _outb(port-1, index); return inb(port); break; case 0x3c1: inb(0x3da); /* set port to point at index */ _outb(port, index); return inb(port); break; default: fprintf(stderr, "unknown port 0x%x\n", port); exit(1); /*NOTREACHED*/ } } void p_utx(int port, int index, int value) { switch (port) { case 0x3c5: case 0x3cf: _outb(port-1, index); _outb(port, value); break; case 0x3c1: inb(0x3da); /* set port to point at index */ _outb(port-1, index); _outb(port-1, value); break; default: fprintf(stderr, "unknown port 0x%x in p_utx\n", port); exit(1); } } void p_rint(int port) { printf("0x%x = 0x%x\n", port, g_et(port)); } void p_rintx(int port, int index) { printf("0x%x/0x%x = 0x%x\n", port, index, g_etx(port, index)); } void p_rintxs(int port, int indexlow, int indexhigh) { int i; printf("0x%x/0x%x-0x%x =", port, indexlow, indexhigh); while (indexlow <= indexhigh) { i = g_etx(port, indexlow); printf(" 0x%02x", i); indexlow++; } printf("\n"); } /* * Dump a number of the registers */ void dumpregs(void) { p_rint(0x3cc); p_rint(0x3c2); p_rint(0x3da); p_rint(0x3c3); p_rint(0x46e8); p_rintxs(0x3c5, 0, 4); p_rintxs(0x3cf, 0, 8); p_rintxs(0x3c1, 0, 0x14); p_rint(0x3d4); p_rintxs(0x3d5, 0, 0x18); p_rintxs(0x3c5, 8, 0x10); p_rintxs(0x3cf, 0x70, 0x73); p_rint(0x3d8); p_rint(0x3d9); p_rintxs(0x3cf, 0x0e, 0x0f); /* XXX */ p_rintxs(0x3cf, 0x5a, 0x5f); p_rintx(0x3d5, 0x19); p_rintxs(0x3d5, 0x1e, 0x3c); p_rintxs(0x3d5, 0x5c, 0x5e); p_rintxs(0x3d5, 0x51, 0x52); p_rintxs(0x3d5, 0x55, 0x5b); p_rintxs(0x3d5, 0x40, 0x50); p_rintxs(0x3d5, 0x70, 0x77); p_rintxs(0x3cf, 0x30, 0x34); p_rintxs(0x3cf, 0x40, 0x48); p_rintxs(0x3cf, 0x50, 0x54); p_rintx(0x3d5, 0); p_rintxs(0x3d5, 3, 7); p_rintxs(0x3d5, 0x10, 0x11); p_rintx(0x3d5, 0x16); } /* * are we running on a cyber 9382? * * (presumably, we could be more liberal, i.e., accept * more boards. however, since i don't know the impact * of trying this on random boards, i am into being * as conservative as possible.) */ int isitcyber(void) { if (g_etx(0x3c5, 0xb) != 0xd3) { fprintf(stderr, "does not appear to be a Trident 9660/80/9385/2\n"); return 0; } if (g_etx(0x3c5, 0x9) != 0x33) { fprintf(stderr, "does not appear to be a 9382\n"); return 0; } return 1; /* Yes! */ } void usage(char *cmd) { fprintf(stderr, "usage: %s {-d} {-b|-s}\n", cmd); fprintf(stderr, "(-b allows for 800x600; -s centers for smaller sizes)\n"); exit(1); } int main(int argc, char *argv[]) { char *cmd = argv[0]; int bflag, sflag; int ch, action; /* * FreeBSD and Linux differ on how to give a process * access to x86 "in" and "out" I/O instructions. */ #if defined(__FreeBSD__) /* /dev/io gives us access to x86 in() and out() instructions */ if (open("/dev/io", O_RDWR, 0) < 0) { perror("unable to open /dev/io"); fprintf(stderr, "(this is the device used (on FreeBSD 2.1, at least) to\n"); fprintf(stderr, "get permission to issue 8086 IN and OUT instructions.)\n"); fprintf(stderr, "you may need to run %s as 'root'\n", cmd); fprintf(stderr, "(or, 'chown root %s; chmod 4755 %s'.)\n", cmd, cmd); exit(1); } #endif /* defined(__FreeBSD__) */ #if defined(LINUX) /* * Changed by lera@chaos.ph.utexas.edu: iopl enables an access * to all ports, ioperm(0x3c1, 0x1a, 1) is safer but will only * enable 3c1-3da addr. */ if (iopl(3)){ fprintf(stderr, "Can not enable port access through iopl(3)\n"); fprintf(stderr, "to get permission to issue instructions.)\n"); fprintf(stderr, "you may need to run %s as 'root'\n", cmd); fprintf(stderr, "(or, 'chown root %s; chmod 4755 %s'.)\n", cmd, cmd); exit(1); } #endif /* defined(LINUX) */ #if defined(__NetBSD__) /* * NetBSD is almost identical to Linux (in this respect :-) */ if ( i386_iopl(I386_GET_IOPERM)) { fprintf(stderr, "Can not enable port access through i386_iopl(3)\n"); fprintf(stderr, "to get permission to issue instructions.)\n"); fprintf(stderr, "you may need to run %s as 'root'\n", cmd); fprintf(stderr, "(or, 'chown root %s; chmod 4755 %s'.)\n", cmd, cmd); exit(1); } #endif /* NetBSD*/ /* make sure we are running on what we think we are * running on (9382) */ if (!isitcyber()) { exit(1); } bflag = sflag = 0; action = 0; while ((ch = getopt(argc, argv, "bsdcl")) != EOF) { switch (ch) { case 'b': /* big (600) lines */ if (bflag || sflag) { usage(cmd); /*NOTREACHED*/ } bflag++; break; case 's': /* small (480 or less) lines */ if (bflag || sflag) { usage(cmd); /*NOTREACHED*/ } sflag++; break; case 'd': dumpregs(); action++; break; case '?': default: usage(cmd); /*NOTREACHED*/ } } if (bflag) { ch = g_etx(0x3cf, 0x31)&0x8f; tri_unlock(); p_utx(0x3cf, 0x31, ch|0x10); /* 3fc.31[6:4] = 1 (600) */ tri_lock(); action++; } if (sflag) { ch = g_etx(0x3cf, 0x31)&0x8f; tri_unlock(); p_utx(0x3cf, 0x31, ch); /* 3fc.31[6:4] = 0 (480) */ tri_lock(); action++; } #if 0 /* this works (turns off screen) */ p_utx(0x3c5, 1, 0x21); p_rintx(0x3c5, 1); #endif /* 0 */ if (action == 0) { usage(cmd); /*NOTREACHED*/ } return 0; }