/* $XConsortium: RamDac.c /main/17 1996/10/25 07:00:23 kaleb $ */
/*
* (c) Copyright 1993,1994 by David Wexelblat <dwex@xfree86.org>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* DAVID WEXELBLAT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of David Wexelblat shall not be
* used in advertising or otherwise to promote the sale, use or other dealings
* in this Software without prior written authorization from David Wexelblat.
*
* Contributing Authors:
* Robin Cutshaw <robin@xfree86.org>
* Harald Koenig <koenig@tat.physik.uni-tuebingen.de>
*
*/
/* $XFree86: xc/programs/Xserver/hw/xfree86/SuperProbe/RamDac.c,v 3.26.2.8 1998/12/22 11:23:16 hohndel Exp $ */
#include "Probe.h"
static Word Ports[] = {0x000, 0x000, 0x3C6, 0x3C7, 0x3C8, 0x3C9};
#define NUMPORTS (sizeof(Ports)/sizeof(Word))
#define RED 0
#define GREEN 1
#define BLUE 2
static void ReadPelReg __STDCARGS((Byte, Byte *));
static void WritePelReg __STDCARGS((Byte, Byte *));
static Byte SetComm __STDCARGS((Byte));
static Bool Width8Check __STDCARGS((void));
static Bool TestDACBit __STDCARGS((Byte, Byte, Byte));
static Bool S3_Bt485Check __STDCARGS((int *));
static Bool S3_TVP3020Check __STDCARGS((int *));
static Bool S3_ATT498Check __STDCARGS((int *));
static Bool S3_STG1700Check __STDCARGS((int *));
static Bool S3_GENDACCheck __STDCARGS((int *));
static void CheckMach32 __STDCARGS((int, int *));
static void CheckMach64 __STDCARGS((int, int *));
void CheckMatrox __STDCARGS((int, int *));
#ifdef __STDC__
static void ReadPelReg(Byte Index, Byte *Pixel)
#else
static void ReadPelReg(Index, Pixel)
Byte Index;
Byte *Pixel;
#endif
{
outp(0x3C7, Index);
Pixel[RED] = inp(0x3C9);
Pixel[GREEN] = inp(0x3C9);
Pixel[BLUE] = inp(0x3C9);
return;
}
#ifdef __STDC__
static void WritePelReg(Byte Index, Byte *Pixel)
#else
static void WritePelReg(Index, Pixel)
Byte Index;
Byte *Pixel;
#endif
{
outp(0x3C8, Index);
outp(0x3C9, Pixel[RED]);
outp(0x3C9, Pixel[GREEN]);
outp(0x3C9, Pixel[BLUE]);
return;
}
#ifdef __STDC__
static Byte SetComm(Byte Comm)
#else
static Byte SetComm(Comm)
Byte Comm;
#endif
{
(void) dactocomm();
outp(0x3C6, Comm);
(void) dactocomm();
return(inp(0x3C6));
}
static Bool Width8Check()
{
Byte old, x, v;
Byte pix[3];
old = inp(0x3C8);
ReadPelReg(0xFF, pix);
v = pix[RED];
pix[RED]= 0xFF;
WritePelReg(0xFF, pix);
ReadPelReg(0xFF, pix);
x = pix[RED];
pix[RED] = v;
WritePelReg(0xFF, pix);
outp(0x3C8, old);
return(x == 0xFF);
}
#ifdef __STDC__
static Bool TestDACBit(Byte Bit, Byte OldComm, Byte OldPel)
#else
static Bool TestDACBit(Bit, OldComm, OldPel)
Byte Bit;
Byte OldComm;
Byte OldPel;
#endif
{
Byte tmp;
dactopel();
outp(0x3C6, OldPel & (Bit ^ 0xFF));
(void) dactocomm();
outp(0x3C6, OldComm | Bit);
tmp = inp(0x3C6);
outp(0x3C6, tmp & (Bit ^ 0xFF));
return((tmp & Bit) != 0);
}
static Bool S3_Bt485Check(RamDac)
int *RamDac;
{
Byte old1, old2, old3, old4;
Byte lock1, lock2;
Bool Found = FALSE;
Bool DoChecks = FALSE;
lock1 = rdinx(CRTC_IDX, 0x38);
lock2 = rdinx(CRTC_IDX, 0x39);
wrinx(CRTC_IDX, 0x38, 0x48);
wrinx(CRTC_IDX, 0x39, 0xA5);
old1 = inp(0x3C6);
old2 = rdinx(CRTC_IDX, 0x55);
outp(0x3C6, 0x0F);
wrinx(CRTC_IDX, 0x55, (old2 & 0xFC) | 0x02);
old3 = inp(0x3C6);
if ((old3 & 0x80) == 0x80)
{
Found = TRUE;
if ((old3 & 0xC0) == 0x80)
{
*RamDac = DAC_BT485;
DoChecks = TRUE;
}
else if ((old3 & 0xF0) == 0xD0)
{
DoChecks = TRUE;
*RamDac = DAC_ATT505;
}
else
{
*RamDac = DAC_UNKNOWN;
}
}
else if ((old3 & 0xF0) == 0x40)
{
Found = TRUE;
*RamDac = DAC_ATT504;
DoChecks = TRUE;
}
else
{
/* Perhaps status reg is hidden behind CR3 */
wrinx(CRTC_IDX, 0x55, (old2 & 0xFC) | 0x01);
old3 = inp(0x3C6);
if ((old3 & 0x80) == 0x80)
{
/* OK. CR3 is active... */
wrinx(CRTC_IDX, 0x55, (old2 & 0xFC) | 0x00);
old3 = inp(0x3C8);
outp(0x3C8, 0x00);
wrinx(CRTC_IDX, 0x55, (old2 & 0xFC) | 0x02);
old4 = inp(0x3C6);
if ((old4 & 0x80) == 0x80)
{
Found = TRUE;
if ((old4 & 0xC0) == 0x80)
{
*RamDac = DAC_BT485;
}
else if ((old4 & 0xF0) == 0xD0)
{
*RamDac = DAC_ATT505;
}
else
{
*RamDac = DAC_UNKNOWN;
}
}
else if ((old4 & 0xF0) == 0x40)
{
Found = TRUE;
*RamDac = DAC_ATT504;
}
if ((Found) && (*RamDac != DAC_UNKNOWN))
{
*RamDac |= DAC_6_8_PROGRAM;
if (Width8Check())
{
*RamDac |= DAC_8BIT;
}
}
wrinx(CRTC_IDX, 0x55, (old2 & 0xFC) | 0x00);
outp(0x3C8, old3);
}
}
if (DoChecks)
{
*RamDac |= DAC_6_8_PROGRAM;
if (Width8Check())
{
*RamDac |= DAC_8BIT;
}
}
wrinx(CRTC_IDX, 0x55, old2);
outp(0x3C6, old1);
wrinx(CRTC_IDX, 0x39, lock2);
wrinx(CRTC_IDX, 0x38, lock1);
return(Found);
}
static Bool S3_TVP3020Check(RamDac)
int *RamDac;
{
Byte old1, old2, old3, old4;
Byte lock1, lock2;
Bool Found = FALSE;
/*
* TI ViewPoint TVP3020 support - Robin Cutshaw
*
* The 3020 has 8 direct registers accessed through standard
* VGA registers 0x3C8, 0x3C9, 0x3C6, and 0x3C7. Bit 0 of
* CR55 is used to map these four register to the low four
* or high four direct 3020 registers. The high register set
* includes index and data registers which are used to address
* indirect registers 0x00-0x3F and 0xFF. Indirect register
* 0x3F is the chip ID register which will always return 0x20.
*/
lock1 = rdinx(CRTC_IDX, 0x38);
lock2 = rdinx(CRTC_IDX, 0x39);
wrinx(CRTC_IDX, 0x38, 0x48);
wrinx(CRTC_IDX, 0x39, 0xA5);
old1 = inp(0x3C6);
old2 = rdinx(CRTC_IDX, 0x55);
wrinx(CRTC_IDX, 0x55, (old2 & 0xFC) | 0x01); /* high four registers */
old3 = inp(0x3C6); /* read current index register value */
outp(0x3C6, 0x3F); /* write ID register index to index register */
old4 = inp(0x3C7); /* read ID register from data register */
if (old4 == 0x20) {
Found = TRUE;
*RamDac = DAC_TVP3020 | DAC_6_8_PROGRAM;
wrinx(CRTC_IDX, 0x55, (old2 & 0xFC) | 0x00); /* regular VGA */
if (Width8Check())
{
*RamDac |= DAC_8BIT;
}
} else {
Byte old5, old6;
/* check for Ti3025 hiding behind Bt485 mode */
old5 = rdinx(CRTC_IDX, 0x5C);
/* clear 0x20 (RS4) for 3020 mode */
wrinx(CRTC_IDX, 0x5C, old5 & 0xDF);
/* already twiddled CR55 above */
old6 = inp(0x3C6); /* read current index register value */
outp(0x3C6, 0x3F); /* write ID register index to index register */
old4 = inp(0x3C7); /* read ID register from data register */
if (old4 == 0x25) {
Found = TRUE;
*RamDac = DAC_TVP3025 | DAC_6_8_PROGRAM;
wrinx(CRTC_IDX, 0x55, (old2 & 0xFC) | 0x00); /* regular VGA */
if (Width8Check())
{
*RamDac |= DAC_8BIT;
}
wrinx(CRTC_IDX, 0x55, (old2 & 0xFC) | 0x01);
}
outp(0x3C6, old6); /* restore index register value */
wrinx(CRTC_IDX, 0x5C, old5); /* restore 5C */
}
wrinx(CRTC_IDX, 0x55, (old2 & 0xFC) | 0x01); /* high four registers */
outp(0x3C6, old3); /* restore index register value */
wrinx(CRTC_IDX, 0x55, old2);
outp(0x3C6, old1);
wrinx(CRTC_IDX, 0x39, lock2);
wrinx(CRTC_IDX, 0x38, lock1);
return(Found);
}
static Bool S3_TVP3026Check(RamDac)
int *RamDac;
{
Byte old1, old2, old3, old4, old5;
Byte lock1, lock2;
Bool Found = FALSE;
/*
* TI ViewPoint TVP3026/3030 support - Harald Koenig
*
* The 3026/3030 have 16 direct registers accessed through standard
* VGA registers 0x3C8, 0x3C9, 0x3C6, and 0x3C7. Bits 0,1 of
* CR55 are used to map these four register to sets of four
* direct 3026/3030 registers each. The 00 register set includes
* the index register and the 10 register set includes the
* data register which are used to address indirect registers
* 0x00-0x3F and 0xFF. Indirect register 0x3F is the
* chip ID register which will always return 0x26.
*/
lock1 = rdinx(CRTC_IDX, 0x38);
lock2 = rdinx(CRTC_IDX, 0x39);
wrinx(CRTC_IDX, 0x38, 0x48);
wrinx(CRTC_IDX, 0x39, 0xA5);
old1 = inp(0x3C6);
old2 = rdinx(CRTC_IDX, 0x55);
old5 = rdinx(CRTC_IDX, 0x45);
wrinx(CRTC_IDX, 0x45, old5 & ~0x20);
wrinx(CRTC_IDX, 0x55, (old2 & 0xFC) | 0x00); /* 00 four registers */
old3 = inp(0x3C8); /* read current index register value */
outp(0x3C8, 0x3F); /* write ID register index to index register */
wrinx(CRTC_IDX, 0x55, (old2 & 0xFC) | 0x02); /* 10 four registers */
old4 = inp(0x3C6); /* read ID register from data register */
if (old4 == 0x26 || old4 == 0x30) {
outp(0x3C6, ~old4); /* check if ID register is read only */
if (inp(0x3C6) != old4) {
outp(0x3C6, old4);
}
else {
Found = TRUE;
if (old4 == 0x26)
*RamDac = DAC_TVP3026 | DAC_6_8_PROGRAM;
else /* old4 == 0x30 */
*RamDac = DAC_TVP3030 | DAC_6_8_PROGRAM;
wrinx(CRTC_IDX, 0x55, (old2 & 0xFC) | 0x00); /* regular VGA */
if (Width8Check())
{
*RamDac |= DAC_8BIT;
}
}
}
wrinx(CRTC_IDX, 0x55, (old2 & 0xFC) | 0x00); /* 00 four registers */
outp(0x3C8, old3); /* restore index register value */
wrinx(CRTC_IDX, 0x55, old2);
wrinx(CRTC_IDX, 0x45, old5);
outp(0x3C6, old1);
wrinx(CRTC_IDX, 0x39, lock2);
wrinx(CRTC_IDX, 0x38, lock1);
return(Found);
}
static Bool S3_IBMRGBCheck(RamDac)
int *RamDac;
{
Byte lock1, lock2;
Bool Found = FALSE;
unsigned char CR43, CR55, dac[3], lut[6];
unsigned char ilow, ihigh, id, rev, id2, rev2;
int i,j;
/*
* IBM RGB52x support - Harald Koenig
*/
lock1 = rdinx(CRTC_IDX, 0x38);
lock2 = rdinx(CRTC_IDX, 0x39);
wrinx(CRTC_IDX, 0x38, 0x48);
wrinx(CRTC_IDX, 0x39, 0xA5);
CR43 = rdinx(CRTC_IDX, 0x43);
CR55 = rdinx(CRTC_IDX, 0x55);
wrinx(CRTC_IDX, 0x43, CR43 & ~0x02);
wrinx(CRTC_IDX, 0x55, CR55 & ~0x03);
/* save DAC and first LUT entries */
for (i=0; i<3; i++)
dac[i] = inp(0x3c6+i);
for (i=j=0; i<2; i++) {
outp(0x3c7, i);
lut[j++] = inp(0x3c9);
lut[j++] = inp(0x3c9);
lut[j++] = inp(0x3c9);
}
wrinx(CRTC_IDX, 0x55, (CR55 & ~0x03) | 0x01); /* set RS2 */
/* read ID and revision */
ilow = inp(0x3c8);
ihigh = inp(0x3c9);
outp(0x3c9, 0); /* index high */
outp(0x3c8, 0);
rev = inp(0x3c6);
outp(0x3c8, 1);
id = inp(0x3c6);
/* known IDs:
1 = RGB525
2 = RGB524, RGB528
*/
if (id >= 1 && id <= 2) {
/* check if ID and revision are read only */
outp(0x3c8, 0);
outp(0x3c6, ~rev);
outp(0x3c8, 1);
outp(0x3c6, ~id);
outp(0x3c8, 0);
rev2 = inp(0x3c6);
outp(0x3c8, 1);
id2 = inp(0x3c6);
if (id == id2 && rev == rev2) { /* IBM RGB52x found */
Found = TRUE;
switch(id) {
case 1:
*RamDac = DAC_IBMRGB525 | DAC_6_8_PROGRAM;
break;
case 2:
outp(0x3c8, 0x70);
id2 = inp(0x3c6);
if ((id2 & 0x03) == 3)
*RamDac = DAC_IBMRGB528 | DAC_6_8_PROGRAM;
else
*RamDac = DAC_IBMRGB524 | DAC_6_8_PROGRAM;
break;
}
}
else {
outp(0x3c8, 0);
outp(0x3c6, rev);
outp(0x3c8, 1);
outp(0x3c6, id);
}
}
outp(0x3c8, ilow);
outp(0x3c9, ihigh);
wrinx(CRTC_IDX, 0x55, CR55 & ~0x03);
/* restore DAC and first LUT entries */
for (i=j=0; i<2; i++) {
outp(0x3c8, i);
outp(0x3c9, lut[j++]);
outp(0x3c9 ,lut[j++]);
outp(0x3c9 ,lut[j++]);
}
for (i=0; i<3; i++)
outp(0x3c6+i, dac[i]);
wrinx(CRTC_IDX, 0x43, CR43);
wrinx(CRTC_IDX, 0x55, CR55);
if (Found && Width8Check()) {
*RamDac |= DAC_8BIT;
}
wrinx(CRTC_IDX, 0x39, lock2);
wrinx(CRTC_IDX, 0x38, lock1);
return(Found);
}
static Bool S3_ATT498Check(RamDac)
int *RamDac;
{
Byte mir, dir, daccomm = 0;
Bool Found = FALSE;
/*
* ATT20C498 support - Harald Koenig
* ATT20C409 and
* ATT20C499 support - Dirk Hohndel
*
* The ATT498 has 4 direct registers accessed through standard
* VGA registers 0x3C8, 0x3C9, 0x3C6, and 0x3C7 and 6 indirect
* registers accessed through a back door by successive reads
* on RMR (Pixel read mask register 0x3C6).
*/
dactocomm();
inp(0x3C6); /* reading CR0 */
mir = inp(0x3C6);
dir = inp(0x3C6);
dactopel();
if ((mir == 0x84) && (dir == 0x98)) {
daccomm = getdaccomm();
SetComm(0);
SetComm(0x0a);
if (getdaccomm() == 0)
*RamDac = DAC_ATT22C498;
else
*RamDac = DAC_ATT498;
SetComm(daccomm);
Found = TRUE;
*RamDac |= DAC_6_8_PROGRAM;
}
else if( (mir = 0x84) && (dir == 0x09) ) {
SetComm(daccomm);
*RamDac = DAC_ATT409 | DAC_6_8_PROGRAM;
Found = TRUE;
}
else if( (mir = 0x84) && (dir == 0x99) ) {
SetComm(daccomm);
*RamDac = DAC_ATT499 | DAC_6_8_PROGRAM;
Found = TRUE;
}
return(Found);
}
static Bool CH8398Check(RamDac)
int *RamDac;
{
/* This dac does not provide much information to distinguish itself. */
/* So this probe may not be suitable, unless you know that the ch8398 */
/* is a possibility. */
Byte cid;
Bool Found = FALSE;
dactopel();
inp(0x3c6);
inp(0x3c6);
inp(0x3c6);
cid = inp(0x3c6); /* device ID */
if (cid == 0xc0) {
Found = TRUE;
*RamDac = DAC_CH8398;
}
dactopel();
return Found;
}
static Bool S3_STG1700Check(RamDac)
int *RamDac;
{
Byte cid, did, daccomm, readmask;
Bool Found = FALSE;
readmask = inp(0x3c6);
dactopel();
daccomm = getdaccomm();
SetComm(daccomm | 0x10);
dactocomm();
inp(0x3C6);
outp(0x3c6, 0x00);
outp(0x3c6, 0x00);
cid = inp(0x3c6); /* company ID */
did = inp(0x3c6); /* device ID */
dactopel();
outp(0x3c6,readmask);
SetComm(daccomm);
if ((cid == 0x44) && (did == 0x00)) {
Found = TRUE;
*RamDac = DAC_STG1700;
*RamDac |= DAC_6_8_PROGRAM;
}
if ((cid == 0x44) && (did == 0x02)) {
Found = TRUE;
*RamDac = DAC_STG1702;
*RamDac |= DAC_6_8_PROGRAM;
}
if ((cid == 0x44) && (did == 0x03)) {
Found = TRUE;
*RamDac = DAC_STG1703;
*RamDac |= DAC_6_8_PROGRAM;
}
return(Found);
}
static Bool S3_GENDACCheck(RamDac)
int *RamDac;
{
int i;
Bool Found = FALSE;
Byte lock1, lock2;
Byte saveCR55, savelut[6];
long clock01, clock23;
/* probe for S3 GENDAC or SDAC */
/*
* S3 GENDAC and SDAC have two fixed read only PLL clocks
* CLK0 f0: 25.255MHz M-byte 0x28 N-byte 0x61
* CLK0 f1: 28.311MHz M-byte 0x3d N-byte 0x62
* which can be used to detect GENDAC and SDAC since there is no chip-id
* for the GENDAC.
*
* NOTE: for the GENDAC on a MIRO 10SD (805+GENDAC) reading PLL values
* for CLK0 f0 and f1 always returns 0x7f (but is documented "read only)
*/
lock1 = rdinx(CRTC_IDX, 0x38);
lock2 = rdinx(CRTC_IDX, 0x39);
wrinx(CRTC_IDX, 0x38, 0x48);
wrinx(CRTC_IDX, 0x39, 0xA5);
saveCR55 = rdinx(CRTC_IDX, 0x55);
wrinx(CRTC_IDX, 0x55, saveCR55 & ~1);
outp(0x3c7,0);
for(i=0; i<2*3; i++) /* save first two LUT entries */
savelut[i] = inp(0x3c9);
outp(0x3c8,0);
for(i=0; i<2*3; i++) /* set first two LUT entries to zero */
outp(0x3c9,0);
wrinx(CRTC_IDX, 0x55, saveCR55 | 1);
outp(0x3c7,0);
for(i=clock01=0; i<4; i++)
clock01 = (clock01 << 8) | (inp(0x3c9) & 0xff);
for(i=clock23=0; i<4; i++)
clock23 = (clock23 << 8) | (inp(0x3c9) & 0xff);
wrinx(CRTC_IDX, 0x55, saveCR55 & ~1);
outp(0x3c8,0);
for(i=0; i<2*3; i++) /* restore first two LUT entries */
outp(0x3c9,savelut[i]);
wrinx(CRTC_IDX, 0x55, saveCR55);
wrinx(CRTC_IDX, 0x39, lock2);
wrinx(CRTC_IDX, 0x38, lock1);
if ( clock01 == 0x28613d62 ||
(clock01 == 0x7f7f7f7f && clock23 != 0x7f7f7f7f)) {
Found = TRUE;
dactopel();
inp(0x3c6);
inp(0x3c6);
inp(0x3c6);
/* the fourth read will show the SDAC chip ID and revision */
if (((i=inp(0x3c6)) & 0xf0) == 0x70)
*RamDac = DAC_S3_SDAC;
else
*RamDac = DAC_S3_GENDAC;
dactopel();
}
return(Found);
}
static Bool Tseng_GENDACCheck(RamDac)
int *RamDac;
{
int i;
Bool Found = FALSE;
Byte saveCR31, savelut[6];
Byte saveHercComp, saveModeContr;
long clock01, clock23;
/* probe for Tseng GENDAC or SDAC */
/*
* S3 GENDAC and SDAC have two fixed read only PLL clocks
* CLK0 f0: 25.255MHz M-byte 0x28 N-byte 0x61
* CLK0 f1: 28.311MHz M-byte 0x3d N-byte 0x62
* which can be used to detect GENDAC and SDAC since there is no chip-id
* for the GENDAC.
*/
saveHercComp = inp(0x3BF);
saveModeContr= inp(0x3D8);
outp(0x3BF, 0x03); /* unlock ET4000 special */
outp(0x3D8, 0xA0);
saveCR31 = rdinx(CRTC_IDX, 0x31);
wrinx(CRTC_IDX, 0x31, saveCR31 & ~0x40);
outp(0x3c7,0);
for(i=0; i<2*3; i++) /* save first two LUT entries */
savelut[i] = inp(0x3c9);
outp(0x3c8,0);
for(i=0; i<2*3; i++) /* set first two LUT entries to zero */
outp(0x3c9,0);
wrinx(CRTC_IDX, 0x31, saveCR31 | 0x40);
outp(0x3c7,0);
for(i=clock01=0; i<4; i++)
clock01 = (clock01 << 8) | (inp(0x3c9) & 0xff);
for(i=clock23=0; i<4; i++)
clock23 = (clock23 << 8) | (inp(0x3c9) & 0xff);
wrinx(CRTC_IDX, 0x31, saveCR31 & ~0x40);
outp(0x3c8,0);
for(i=0; i<2*3; i++) /* restore first two LUT entries */
outp(0x3c9,savelut[i]);
wrinx(CRTC_IDX, 0x31, saveCR31);
outp(0x3BF, saveHercComp);
outp(0x3D8, saveModeContr);
if ( clock01 == 0x28613d62 ||
(clock01 == 0x7f7f7f7f && clock23 != 0x7f7f7f7f)) {
Found = TRUE;
dactopel();
inp(0x3c6);
inp(0x3c6);
inp(0x3c6);
/* the fourth read will show the SDAC chip ID and revision */
if (((i=inp(0x3c6)) & 0xf0) == 0xb0)
*RamDac = DAC_ICS5341;
else
*RamDac = DAC_ICS5301; /* ID code ICS5301 = 0xf0 */
dactopel();
}
return(Found);
}
static Bool S3_SC15025Check(RamDac)
int *RamDac;
{
Byte c,id[4];
int i;
Bool Found = FALSE;
/*
* Sierra 15025 support - Harald Koenig
*
* The SC15025 has 9 indexed extended registers which can be accessed
* by setting bit 0x10 in the command register.
* In extended registers 0x9-0xC an identification code is stored
* should be 53 3a b1 41
*/
c = getdaccomm();
SetComm(c | 0x10); /* enable extened data registers */
for (i=0; i<4; i++) {
outp(0x3C7, 0x9+i);
id[i] = inp(0x3C8);
}
SetComm(c); /* restore command register */
dactopel();
if (id[0] == 'S' && /* Sierra */
((id[1]<<8)|id[2]) == 15025) { /* unique for the SC 15025/26 */
if (id[3] != 'A') { /* version number */
fprintf(stderr,"*** ==> New Sierra SC 15025/26 version (%x) found, please report!\n",id[3]);
}
Found = TRUE;
*RamDac = DAC_SIERRA24;
*RamDac |= DAC_6_8_PROGRAM;
}
return(Found);
}
static Bool ARK_ZOOMDACCheck(RamDac)
int *RamDac;
{
/*
* This DAC has the same ID as an AT&T ATT20C498, but
* with an ARK chip it is reasonable to assume it's a ZOOMDAC.
*/
Byte cid, did;
Bool Found = FALSE;
dactopel();
dactocomm();
inp(0x3C6);
cid = inp(0x3c6); /* company ID */
did = inp(0x3c6); /* device ID */
dactopel();
if ((cid == 0x84) && (did == 0x98)) {
Found = TRUE;
*RamDac = DAC_ZOOMDAC;
*RamDac |= DAC_6_8_PROGRAM;
}
return(Found);
}
static void CheckMach32(ChipSet, RamDac)
int ChipSet;
int *RamDac;
{
Word Port = CONFIG_STATUS_1;
EnableIOPorts(1, &Port);
switch ((inpw(Port) & 0x0E00) >> 9)
{
case 0x00:
*RamDac = DAC_ATI68830;
break;
case 0x01:
*RamDac = DAC_SIERRA15_16;
break;
case 0x02:
*RamDac = DAC_ATI68875;
*RamDac |= DAC_6_8_PROGRAM;
if (Width8Check())
{
*RamDac |= DAC_8BIT;
}
break;
case 0x03:
*RamDac = DAC_STANDARD;
break;
case 0x04:
*RamDac = DAC_ATIMISC24;
*RamDac |= DAC_6_8_PROGRAM;
if (Width8Check())
{
*RamDac |= DAC_8BIT;
}
break;
case 0x05:
*RamDac = DAC_ATI68860;
*RamDac |= DAC_6_8_PROGRAM;
if (Width8Check())
{
*RamDac |= DAC_8BIT;
}
break;
case 0x06:
*RamDac = DAC_STG1700;
*RamDac |= DAC_6_8_PROGRAM;
break;
case 0x07:
*RamDac = DAC_ATT498;
*RamDac |= DAC_6_8_PROGRAM;
break;
}
DisableIOPorts(1, &Port);
return;
}
static void CheckMach64(ChipSet, RamDac)
int ChipSet;
int *RamDac;
{
extern Word ATIMach64DAC_CNTL, ATIMach64SCRATCH_REG1;
if (ChipSet >= CHIP_ATI264CT)
{
*RamDac = DAC_ATI_INTERNAL;
*RamDac |= DAC_6_8_PROGRAM;
if (Width8Check())
*RamDac |= DAC_8BIT;
return;
}
EnableIOPorts(1, &ATIMach64DAC_CNTL);
EnableIOPorts(1, &ATIMach64SCRATCH_REG1);
switch (((inpl(ATIMach64DAC_CNTL) & 0x00070000) |
(inpl(ATIMach64SCRATCH_REG1) & 0x0000F000)) >> 12)
{
case 0x10:
*RamDac = DAC_IBMRGB525;
*RamDac |= DAC_6_8_PROGRAM;
break;
case 0x20:
*RamDac = DAC_ATI68875;
*RamDac |= DAC_6_8_PROGRAM;
break;
case 0x27:
case 0x57:
*RamDac = DAC_TVP3025;
*RamDac |= DAC_6_8_PROGRAM;
break;
case 0x30:
*RamDac = DAC_STANDARD;
break;
case 0x40:
*RamDac = DAC_ATIMISC24;
break;
case 0x41:
*RamDac = DAC_ATT491;
break;
case 0x42:
*RamDac = DAC_SIERRA24;
break;
case 0x43:
*RamDac = DAC_MU9C1880;
break;
case 0x44:
*RamDac = DAC_IMSG174;
break;
case 0x50:
case 0x51:
*RamDac = DAC_ATI68860;
*RamDac |= DAC_6_8_PROGRAM;
break;
case 0x60:
*RamDac = DAC_STG1700;
*RamDac |= DAC_6_8_PROGRAM;
break;
case 0x61:
*RamDac = DAC_ATT498;
*RamDac |= DAC_6_8_PROGRAM;
break;
case 0x70:
*RamDac = DAC_STG1702;
*RamDac |= DAC_6_8_PROGRAM;
break;
case 0x71:
*RamDac = DAC_SIERRA24;
break;
case 0x72:
*RamDac = DAC_ATT498;
*RamDac |= DAC_6_8_PROGRAM;
break;
case 0x73:
*RamDac = DAC_STG1703;
*RamDac |= DAC_6_8_PROGRAM;
break;
case 0x74:
*RamDac = DAC_CH8398;
*RamDac |= DAC_6_8_PROGRAM;
break;
case 0x75:
*RamDac = DAC_ATT408;
*RamDac |= DAC_6_8_PROGRAM;
break;
default:
break;
}
if (Width8Check())
{
*RamDac |= DAC_8BIT;
}
DisableIOPorts(1, &ATIMach64DAC_CNTL);
DisableIOPorts(1, &ATIMach64SCRATCH_REG1);
return;
}
void Probe_RamDac(Chipset, RamDac)
int Chipset;
int *RamDac;
{
Byte x, y, z, u, v, oldcomm, oldpel, notcomm, tmp;
Bool dac8, dac8now;
*RamDac = DAC_STANDARD;
Ports[0] = CRTC_IDX;
Ports[1] = CRTC_REG;
EnableIOPorts(NUMPORTS, Ports);
/*
* Handle special cases.
*/
if (Chipset == CHIP_AL2101)
{
*RamDac = DAC_ALG1101;
if (Width8Check())
{
*RamDac |= DAC_8BIT;
}
DisableIOPorts(NUMPORTS, Ports);
return;
}
else if (SVGA_VENDOR(Chipset) == V_ATI)
{
extern Bool Crippled_Mach32, Crippled_Mach64;
if ((Chipset < CHIP_ATI68800_3) || Crippled_Mach32)
{
if (ReadBIOS(0x44, &x, 1) != 1)
{
fprintf(stderr, "%s: Failed to read ATI BIOS data\n",
MyName);
DisableIOPorts(NUMPORTS, Ports);
return;
}
if (x & 0x80)
{
*RamDac = DAC_ATI68830;
if (Width8Check())
{
*RamDac |= DAC_8BIT;
}
DisableIOPorts(NUMPORTS, Ports);
return;
}
}
else if (!Crippled_Mach64)
{
if (Chipset <= CHIP_ATI88800GXC)
{
CheckMach32(Chipset, RamDac);
if (DAC_CHIP(*RamDac) != DAC_ATIMISC24)
{
DisableIOPorts(NUMPORTS, Ports);
return;
}
}
else
{
CheckMach64(Chipset, RamDac);
DisableIOPorts(NUMPORTS, Ports);
return;
}
}
}
else if ((SVGA_VENDOR(Chipset) == V_CIRRUS) &&
(Chipset >= CHIP_CL5420))
{
if ((Chipset == CHIP_CL5420) || (Chipset >= CHIP_CL5410))
{
*RamDac = DAC_CIRRUSA;
}
else
{
*RamDac = DAC_CIRRUSB;
}
if (Width8Check())
{
*RamDac |= DAC_8BIT;
}
DisableIOPorts(NUMPORTS, Ports);
return;
}
else if ((SVGA_VENDOR(Chipset) == V_S3) && (Chipset >= CHIP_S3_928D))
{
if (S3_TVP3026Check(RamDac))
{
DisableIOPorts(NUMPORTS, Ports);
return;
}
if (S3_IBMRGBCheck(RamDac))
{
DisableIOPorts(NUMPORTS, Ports);
return;
}
if (S3_TVP3020Check(RamDac))
{
DisableIOPorts(NUMPORTS, Ports);
return;
}
if (S3_Bt485Check(RamDac))
{
DisableIOPorts(NUMPORTS, Ports);
return;
}
if (S3_ATT498Check(RamDac))
{
DisableIOPorts(NUMPORTS, Ports);
return;
}
if (S3_STG1700Check(RamDac))
{
DisableIOPorts(NUMPORTS, Ports);
return;
}
if (S3_GENDACCheck(RamDac))
{
DisableIOPorts(NUMPORTS, Ports);
return;
}
if (S3_SC15025Check(RamDac))
{
DisableIOPorts(NUMPORTS, Ports);
return;
}
}
else if ( ((SVGA_VENDOR(Chipset) == V_S3) && (Chipset >= CHIP_S3_801B))
||(SVGA_VENDOR(Chipset) == V_TSENG) )
{
if ( (Chipset == CHIP_ET6K) || (Chipset == CHIP_ET6K1) || (Chipset == CHIP_ET6K3) )
{
*RamDac = DAC_ET6K;
}
if (S3_GENDACCheck(RamDac))
{
DisableIOPorts(NUMPORTS, Ports);
return;
}
if (S3_STG1700Check(RamDac))
{
DisableIOPorts(NUMPORTS, Ports);
return;
}
if (CH8398Check(RamDac))
{
DisableIOPorts(NUMPORTS, Ports);
return;
}
if ( (SVGA_VENDOR(Chipset) == V_TSENG) && ( Chipset != CHIP_ET6K )
&& ( Chipset != CHIP_ET6K1 ) && ( Chipset != CHIP_ET6K3 ) )
{
if (Tseng_GENDACCheck(RamDac))
{
DisableIOPorts(NUMPORTS, Ports);
return;
}
}
}
else if (SVGA_VENDOR(Chipset) == V_MATROX)
{
if (Chipset == CHIP_MGA2085PX)
*RamDac = DAC_BT485;
if (Chipset == CHIP_MGA2064W)
*RamDac = DAC_TVP3026;
if ((Chipset == CHIP_MGA2164W)||(Chipset == CHIP_MGA2164WAGP))
*RamDac = DAC_TVP3026;
if (Chipset == CHIP_MGA1064SG)
*RamDac = DAC_MGA1064SG;
if ((Chipset == CHIP_MGAG100PCI)||(Chipset == CHIP_MGAG100AGP))
*RamDac = DAC_MGAG100;
if ((Chipset == CHIP_MGAG200PCI)||(Chipset == CHIP_MGAG200AGP))
*RamDac = DAC_MGAG200;
DisableIOPorts(NUMPORTS, Ports);
return;
}
else if ( (SVGA_VENDOR(Chipset) == V_TRIDENT) &&
(Chipset >= CHIP_TVGA9000I) )
{
if (Chipset <= CHIP_TVGA9440)
*RamDac = DAC_TKD8001;
else
*RamDac = DAC_TGUIDAC;
DisableIOPorts(NUMPORTS, Ports);
return;
}
else if (SVGA_VENDOR(Chipset) == V_ARK)
{
if (ARK_ZOOMDACCheck(RamDac))
{
DisableIOPorts(NUMPORTS, Ports);
return;
}
if (S3_STG1700Check(RamDac))
{
DisableIOPorts(NUMPORTS, Ports);
return;
}
}
else if (SVGA_VENDOR(Chipset) == V_ALLIANCE)
{
if (Chipset == CHIP_ALSC6422 || Chipset == CHIP_ALSCAT24)
{
*RamDac = DAC_ALSC_642x;
}
if (S3_STG1700Check(RamDac))
{
DisableIOPorts(NUMPORTS, Ports);
return;
}
}
else if (SVGA_VENDOR(Chipset) == V_SIS)
{
if ((Chipset >= CHIP_SIS86C201) && (Chipset <= CHIP_SIS6326))
*RamDac = DAC_SIS;
}
/*
* Save current state.
*/
(void) dactocomm();
oldcomm = inp(0x3C6);
dactopel();
oldpel = inp(0x3C6);
/*
* Do 8-bit-wide check.
*/
(void) dactocomm();
outp(0x3C6, 0x00);
dac8 = Width8Check();
dactopel();
/*
* Check whether this DAC has a HiColor-style command register.
*/
notcomm = ~oldcomm;
outp(0x3C6, notcomm);
(void) dactocomm();
v = inp(0x3C6);
if (v != notcomm)
{
/*
* Check for early-generation HiColor-style DAC.
*/
if ((SetComm(0xE0) & 0xE0) != 0xE0)
{
dactopel();
x = inp(0x3C6);
do
{
/*
* Wait for same value twice.
*/
y = x;
x = inp(0x3C6);
}
while (x != y);
z = x;
u = dactocomm();
if (u != 0x8E)
{
/*
* If command register is 0x8E, we've got an SS24;
*/
y = 8;
do
{
x = inp(0x3C6);
y--;
}
while ((x != 0x8E) && (y != 0));
}
else
{
x = u;
}
if (x == 0x8E)
{
*RamDac = DAC_SS24;
}
else
{
/*
* Sierra SC11486
*/
*RamDac = DAC_SIERRA15;
}
dactopel();
}
else
{
/*
* New generation of advanced DACs
*/
if ((SetComm(0x60) & 0xE0) == 0x00)
{
/*
* AT&T 20C490/20C493
*/
if ((SetComm(0x02) & 0x02) != 0x00)
{
*RamDac = DAC_ATT490;
*RamDac |= DAC_6_8_PROGRAM;
}
else
{
*RamDac = DAC_ATT493;
}
}
else
{
x = SetComm(oldcomm);
if (inp(0x3C6) == notcomm)
{
if (SetComm(0xFF) != 0xFF)
{
*RamDac = DAC_ACUMOS;
}
else
{
(void) Width8Check();
dactocomm();
tmp = inp(0x3C6);
dactocomm();
outp(0x3C6, (tmp | 0x02) & 0xFE);
dac8now = Width8Check();
if (dac8now)
{
if (Width8Check())
{
*RamDac = DAC_ATT491;
*RamDac |= DAC_6_8_PROGRAM;
}
else
{
*RamDac = DAC_CIRRUS24;
}
}
else
{
*RamDac = DAC_ATT492;
}
}
}
else
{
if (trigdac() == notcomm)
{
*RamDac = DAC_CIRRUS24;
}
else
{
dactopel();
outp(0x3C6, 0xFF);
switch (trigdac())
{
case 0x44:
*RamDac = DAC_MUSIC4870;
break;
case 0x82:
*RamDac = DAC_MUSIC4910;
break;
case 0x8E:
*RamDac = DAC_SS24;
break;
default:
if (TestDACBit(0x10,oldcomm,oldpel))
{
*RamDac = DAC_SIERRA24;
*RamDac |= DAC_6_8_PROGRAM;
}
else if (TestDACBit(0x04,oldcomm,oldpel))
{
*RamDac = DAC_UNKNOWN;
}
else
{
*RamDac = DAC_SIERRA15_16;
}
break;
}
}
}
}
}
dactocomm();
outp(0x3C6, oldcomm);
}
dactopel();
outp(0x3C6, oldpel);
/*
* If no special DAC found, check for the EDSUN DAC.
*/
if (*RamDac == DAC_STANDARD)
{
/*
* Write "CEGEDSUN" + mode to DAC index 0xDE (222)
*/
waitforretrace();
outp(0x3C8, 0xDE);
outp(0x3C9, (Byte)'C');
outp(0x3C9, (Byte)'E');
outp(0x3C9, (Byte)'G');
outp(0x3C8, 0xDE);
outp(0x3C9, (Byte)'E');
outp(0x3C9, (Byte)'D');
outp(0x3C9, (Byte)'S');
outp(0x3C8, 0xDE);
outp(0x3C9, (Byte)'U');
outp(0x3C9, (Byte)'N');
outp(0x3C9, (Byte)'\n');
/*
* Should be in CEG mode now.
*/
outp(0x3C6, 0xFF);
x = (inp(0x3C6) >> 4) & 0x07;
if (x < 0x07)
{
*RamDac = DAC_EDSUN;
waitforretrace();
outp(0x3C8, 0xDF);
outp(0x3C9, 0x00);
}
}
/*
* Remember if DAC was in 8-bit mode.
*/
if (dac8)
{
*RamDac |= DAC_8BIT;
}
DisableIOPorts(NUMPORTS, Ports);
return;
}