#-
# 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;
}