/* $XConsortium: RamDac.c /main/17 1996/10/25 07:00:23 kaleb $ */ /* * (c) Copyright 1993,1994 by David Wexelblat * * 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 * Harald Koenig * */ /* $XFree86: xc/programs/Xserver/hw/xfree86/SuperProbe/RamDac.c,v 3.26.2.9 1999/06/17 16:24:03 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 *)); static 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; int ret=0; /* * 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; int i; 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; int i; 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; { Byte daccomm; 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; { Byte daccomm; 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, daccomm, readmask; int i; 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; }