summaryrefslogtreecommitdiff
path: root/src/atiprobe.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/atiprobe.c')
-rw-r--r--src/atiprobe.c2353
1 files changed, 2353 insertions, 0 deletions
diff --git a/src/atiprobe.c b/src/atiprobe.c
new file mode 100644
index 0000000..05d2f34
--- /dev/null
+++ b/src/atiprobe.c
@@ -0,0 +1,2353 @@
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atiprobe.c,v 1.54 2003/01/01 19:16:33 tsi Exp $ */
+/*
+ * Copyright 1997 through 2003 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of Marc Aurele La France not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. Marc Aurele La France makes no representations
+ * about the suitability of this software for any purpose. It is provided
+ * "as-is" without express or implied warranty.
+ *
+ * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
+ * EVENT SHALL MARC AURELE LA FRANCE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "ati.h"
+#include "atiadapter.h"
+#include "atiadjust.h"
+#include "atibus.h"
+#include "atichip.h"
+#include "aticonsole.h"
+#include "atiident.h"
+#include "atimach64io.h"
+#include "atimodule.h"
+#include "atipreinit.h"
+#include "atiprobe.h"
+#include "atiscreen.h"
+#include "ativalid.h"
+#include "ativersion.h"
+#include "atividmem.h"
+#include "atiwonderio.h"
+
+#include "radeon_probe.h"
+#include "radeon_version.h"
+#include "r128_probe.h"
+#include "r128_version.h"
+
+/*
+ * NOTES:
+ *
+ * - The driver private structures (ATIRec's) are allocated here, rather than
+ * in ATIPreInit(). This allows ATIProbe() to pass information to later
+ * stages.
+ * - A minor point, perhaps, is that XF86Config Chipset names denote functional
+ * levels, rather than specific graphics controller chips.
+ * - ATIProbe() does not call xf86MatchPciInstances(), because ATIProbe()
+ * should be able to match a mix of PCI and non-PCI devices to XF86Config
+ * Device sections. Also, PCI configuration space for Mach32's is to be
+ * largely ignored.
+ */
+
+#ifdef XFree86LOADER
+
+/*
+ * The following exists to prevent the compiler from considering entry points
+ * defined in a separate module from being constants.
+ */
+static xf86PreInitProc * const volatile PreInitProc = ATIPreInit;
+static xf86ScreenInitProc * const volatile ScreenInitProc = ATIScreenInit;
+static xf86SwitchModeProc * const volatile SwitchModeProc = ATISwitchMode;
+static xf86AdjustFrameProc * const volatile AdjustFrameProc = ATIAdjustFrame;
+static xf86EnterVTProc * const volatile EnterVTProc = ATIEnterVT;
+static xf86LeaveVTProc * const volatile LeaveVTProc = ATILeaveVT;
+static xf86FreeScreenProc * const volatile FreeScreenProc = ATIFreeScreen;
+static xf86ValidModeProc * const volatile ValidModeProc = ATIValidMode;
+
+#define ATIPreInit PreInitProc
+#define ATIScreenInit ScreenInitProc
+#define ATISwitchMode SwitchModeProc
+#define ATIAdjustFrame AdjustFrameProc
+#define ATIEnterVT EnterVTProc
+#define ATILeaveVT LeaveVTProc
+#define ATIFreeScreen FreeScreenProc
+#define ATIValidMode ValidModeProc
+
+#endif
+
+/* Used as a temporary buffer */
+#define Identifier ((char *)(pATI->MMIOCache))
+
+/*
+ * An internal structure definition to facilitate the matching of detected
+ * adapters to XF86Config Device sections.
+ */
+typedef struct _ATIGDev
+{
+ GDevPtr pGDev;
+ int iATIPtr;
+ CARD8 Chipset;
+} ATIGDev, *ATIGDevPtr;
+
+#ifndef AVOID_CPIO
+
+/*
+ * Definitions for I/O conflict avoidance.
+ */
+#define LongPort(_Port) GetBits(_Port, PCIGETIO(SPARSE_IO_BASE))
+#define DetectedVGA (1 << 0)
+#define Detected8514A (1 << 1)
+#define DetectedMach64 (1 << 2)
+#define Allowed (1 << 3)
+#define DoProbe (1 << 4)
+typedef struct
+{
+ IOADDRESS Base;
+ CARD8 Size;
+ CARD8 Flag;
+} PortRec, *PortPtr;
+
+/*
+ * ATIScanPCIBases --
+ *
+ * This function loops though a device's PCI registered bases and accumulates
+ * a list of block I/O bases in use in the system.
+ */
+static void
+ATIScanPCIBases
+(
+ PortPtr *PCIPorts,
+ int *nPCIPort,
+ const CARD32 *pBase,
+ const int *pSize,
+ const CARD8 ProbeFlag
+)
+{
+ IOADDRESS Base;
+ int i, j;
+
+ for (i = 6; --i >= 0; pBase++, pSize++)
+ {
+ if (*pBase & PCI_MAP_IO)
+ {
+ Base = *pBase & ~IO_BYTE_SELECT;
+ for (j = 0; ; j++)
+ {
+ if (j >= *nPCIPort)
+ {
+ (*nPCIPort)++;
+ *PCIPorts = (PortPtr)xnfrealloc(*PCIPorts,
+ *nPCIPort * SizeOf(PortRec));
+ (*PCIPorts)[j].Base = Base;
+ (*PCIPorts)[j].Size = (CARD8)*pSize;
+ (*PCIPorts)[j].Flag = ProbeFlag;
+ break;
+ }
+
+ if (Base == (*PCIPorts)[j].Base)
+ break;
+ }
+
+ continue;
+ }
+
+ /* Allow for 64-bit addresses */
+ if (!PCI_MAP_IS64BITMEM(*pBase))
+ continue;
+
+ i--;
+ pBase++;
+ pSize++;
+ }
+}
+
+/*
+ * ATICheckSparseIOBases --
+ *
+ * This function checks whether a sparse I/O base can safely be probed.
+ */
+static CARD8
+ATICheckSparseIOBases
+(
+ pciVideoPtr pVideo,
+ CARD8 *ProbeFlags,
+ const IOADDRESS IOBase,
+ const int Count,
+ const Bool Override
+)
+{
+ CARD32 FirstPort, LastPort;
+
+ if (!pVideo || !xf86IsPrimaryPci(pVideo))
+ {
+ FirstPort = LongPort(IOBase);
+ LastPort = LongPort(IOBase + Count - 1);
+
+ for (; FirstPort <= LastPort; FirstPort++)
+ {
+ CARD8 ProbeFlag = ProbeFlags[FirstPort];
+
+ if (ProbeFlag & DoProbe)
+ continue;
+
+ if (!(ProbeFlag & Allowed))
+ return ProbeFlag;
+
+ if (Override)
+ continue;
+
+ /* User might wish to override this decision */
+ xf86Msg(X_WARNING,
+ ATI_NAME ": Sparse I/O base 0x%04X not probed.\n", IOBase);
+ return Allowed;
+ }
+ }
+
+ return DoProbe;
+}
+
+/*
+ * ATIClaimSparseIOBases --
+ *
+ * This function updates the sparse I/O base table with information from the
+ * hardware probes.
+ */
+static void
+ATIClaimSparseIOBases
+(
+ CARD8 *ProbeFlags,
+ const IOADDRESS IOBase,
+ const int Count,
+ const CARD8 ProbeFlag
+)
+{
+ CARD32 FirstPort = LongPort(IOBase),
+ LastPort = LongPort(IOBase + Count - 1);
+
+ for (; FirstPort <= LastPort; FirstPort++)
+ ProbeFlags[FirstPort] = ProbeFlag;
+}
+
+/*
+ * ATIVGAProbe --
+ *
+ * This function looks for an IBM standard VGA, or clone, and sets
+ * pATI->VGAAdapter if one is found.
+ */
+static ATIPtr
+ATIVGAProbe
+(
+ ATIPtr pVGA
+)
+{
+ CARD8 IOValue1, IOValue2, IOValue3;
+
+ if (!pVGA)
+ pVGA = (ATIPtr)xnfcalloc(1, SizeOf(ATIRec));
+
+ /*
+ * VGA has one more attribute register than EGA. See if it can be read and
+ * written. Note that the CRTC registers are not used here, so there's no
+ * need to unlock them.
+ */
+ ATISetVGAIOBase(pVGA, inb(R_GENMO));
+ (void)inb(GENS1(pVGA->CPIO_VGABase));
+ IOValue1 = inb(ATTRX);
+ (void)inb(GENS1(pVGA->CPIO_VGABase));
+ IOValue2 = GetReg(ATTRX, 0x14U | 0x20U);
+ outb(ATTRX, IOValue2 ^ 0x0FU);
+ IOValue3 = GetReg(ATTRX, 0x14U | 0x20U);
+ outb(ATTRX, IOValue2);
+ outb(ATTRX, IOValue1);
+ (void)inb(GENS1(pVGA->CPIO_VGABase));
+ if (IOValue3 == (IOValue2 ^ 0x0FU))
+ {
+ /* VGA device detected */
+ if (pVGA->Chip == ATI_CHIP_NONE)
+ pVGA->Chip = ATI_CHIP_VGA;
+ if (pVGA->VGAAdapter == ATI_ADAPTER_NONE)
+ pVGA->VGAAdapter = ATI_ADAPTER_VGA;
+ if (pVGA->Adapter == ATI_ADAPTER_NONE)
+ pVGA->Adapter = ATI_ADAPTER_VGA;
+ }
+ else
+ pVGA->VGAAdapter = ATI_ADAPTER_NONE;
+
+ return pVGA;
+}
+
+/*
+ * ATIVGAWonderProbe --
+ *
+ * This function determines if ATI extended VGA registers can be accessed
+ * through the I/O port specified by pATI->CPIO_VGAWonder. If not, the
+ * function resets pATI->CPIO_VGAWonder to zero.
+ */
+static void
+ATIVGAWonderProbe
+(
+ pciVideoPtr pVideo,
+ ATIPtr pATI,
+ ATIPtr p8514,
+ CARD8 *ProbeFlags
+)
+{
+ CARD8 IOValue1, IOValue2, IOValue3, IOValue4, IOValue5, IOValue6;
+
+ switch (ATICheckSparseIOBases(pVideo, ProbeFlags,
+ pATI->CPIO_VGAWonder, 2, TRUE))
+ {
+ case 0:
+ xf86Msg(X_WARNING,
+ ATI_NAME ": Expected VGA Wonder capability could not be"
+ " detected at I/O port 0x%04X because it would conflict with"
+ " a non-video PCI/AGP device.\n", pATI->CPIO_VGAWonder);
+ pATI->CPIO_VGAWonder = 0;
+ break;
+
+ case Detected8514A:
+ xf86Msg(X_WARNING,
+ ATI_NAME ": Expected VGA Wonder capability could not be"
+ " detected at I/O port 0x%04X because it would conflict with"
+ " a %s %s.\n", pATI->CPIO_VGAWonder,
+ ATIBusNames[p8514->BusType], ATIAdapterNames[p8514->Adapter]);
+ pATI->CPIO_VGAWonder = 0;
+ break;
+
+ case DetectedMach64:
+ xf86Msg(X_WARNING,
+ ATI_NAME ": Expected VGA Wonder capability could not be"
+ " detected at I/O port 0x%04X because it would conflict with"
+ " a Mach64.\n", pATI->CPIO_VGAWonder);
+ pATI->CPIO_VGAWonder = 0;
+ break;
+
+ case DetectedVGA:
+ default: /* Must be DoProbe */
+ if (pVideo && !xf86IsPrimaryPci(pVideo) &&
+ (pATI->Chip <= ATI_CHIP_88800GXD))
+ {
+ /* Set up extended VGA register addressing */
+ PutReg(GRAX, 0x50U, GetByte(pATI->CPIO_VGAWonder, 0));
+ PutReg(GRAX, 0x51U,
+ GetByte(pATI->CPIO_VGAWonder, 1) | pATI->VGAOffset);
+ }
+ /*
+ * Register 0xBB is used by the BIOS to keep track of various
+ * things (monitor type, etc.). Except for 18800-x's, register
+ * 0xBC must be zero and causes the adapter to enter a test mode
+ * when written to with a non-zero value.
+ */
+ IOValue1 = inb(pATI->CPIO_VGAWonder);
+ IOValue2 = ATIGetExtReg(IOValue1);
+ IOValue3 = ATIGetExtReg(0xBBU);
+ ATIPutExtReg(0xBBU, IOValue3 ^ 0xAAU);
+ IOValue4 = ATIGetExtReg(0xBBU);
+ ATIPutExtReg(0xBBU, IOValue3 ^ 0x55U);
+ IOValue5 = ATIGetExtReg(0xBBU);
+ ATIPutExtReg(0xBBU, IOValue3);
+ if (pATI->Chip <= ATI_CHIP_18800_1)
+ IOValue6 = 0;
+ else
+ IOValue6 = ATIGetExtReg(0xBCU);
+ ATIPutExtReg(IOValue1, IOValue2);
+
+ if ((IOValue4 == (IOValue3 ^ 0xAAU)) &&
+ (IOValue5 == (IOValue3 ^ 0x55U)) &&
+ (IOValue6 == 0))
+ {
+ xf86MsgVerb(X_INFO, 3,
+ ATI_NAME ": VGA Wonder at I/O port 0x%04X detected.\n",
+ pATI->CPIO_VGAWonder);
+ }
+ else
+ {
+ xf86Msg(X_WARNING,
+ ATI_NAME ": Expected VGA Wonder capability at I/O port"
+ " 0x%04X was not detected.\n", pATI->CPIO_VGAWonder);
+ pATI->CPIO_VGAWonder = 0;
+ }
+ break;
+ }
+}
+
+/*
+ * ATI8514Probe --
+ *
+ * This function looks for an 8514/A compatible and returns an ATIRec if one is
+ * found. The function also determines whether or not the detected 8514/A
+ * compatible device is actually a Mach8 or Mach32, and sets pATI->Adapter
+ * accordingly.
+ */
+static ATIPtr
+ATI8514Probe
+(
+ pciVideoPtr pVideo
+)
+{
+ ATIPtr pATI = NULL;
+ CARD16 IOValue1, IOValue2;
+
+ /*
+ * Save register value to be modified, just in case there is no 8514/A
+ * compatible accelerator. Note that, in more ways than one,
+ * SUBSYS_STAT == SUBSYS_CNTL.
+ */
+ IOValue1 = inw(SUBSYS_STAT);
+ IOValue2 = IOValue1 & _8PLANE;
+
+ /* Reset any 8514/A compatible adapter that might be present */
+ outw(SUBSYS_CNTL, IOValue2 | (GPCTRL_RESET | CHPTEST_NORMAL));
+ outw(SUBSYS_CNTL, IOValue2 | (GPCTRL_ENAB | CHPTEST_NORMAL |
+ RVBLNKFLG | RPICKFLAG | RINVALIDIO | RGPIDLE));
+
+ /* Probe for an 8514/A compatible */
+ IOValue2 = inw(ERR_TERM);
+ outw(ERR_TERM, 0x5A5AU);
+ ProbeWaitIdleEmpty();
+ if (inw(ERR_TERM) == 0x5A5AU)
+ {
+ outw(ERR_TERM, 0x2525U);
+ if (inw(ERR_TERM) == 0x2525U)
+ {
+ pATI = (ATIPtr)xnfcalloc(1, SizeOf(ATIRec));
+ pATI->Adapter = ATI_ADAPTER_8514A;
+ pATI->ChipHasSUBSYS_CNTL = TRUE;
+ pATI->PCIInfo = pVideo;
+ }
+ }
+ outw(ERR_TERM, IOValue2);
+
+ /* Restore register value clobbered by 8514/A reset attempt */
+ if (!pATI)
+ {
+ outw(SUBSYS_CNTL, IOValue1);
+ return NULL;
+ }
+
+ /* Ensure any Mach8 or Mach32 is not in 8514/A emulation mode */
+ IOValue1 = inw(CLOCK_SEL);
+ outw(CLOCK_SEL, IOValue1);
+ ProbeWaitIdleEmpty();
+
+ IOValue1 = IOValue2 = inw(ROM_ADDR_1);
+ outw(ROM_ADDR_1, 0x5555U);
+ ProbeWaitIdleEmpty();
+ if (inw(ROM_ADDR_1) == 0x5555U)
+ {
+ outw(ROM_ADDR_1, 0x2A2AU);
+ ProbeWaitIdleEmpty();
+ if (inw(ROM_ADDR_1) == 0x2A2AU)
+ pATI->Adapter = ATI_ADAPTER_MACH8;
+ }
+ outw(ROM_ADDR_1, IOValue1);
+
+ if (pATI->Adapter == ATI_ADAPTER_MACH8)
+ {
+ /* A Mach8 or Mach32 has been detected */
+ IOValue1 = inw(READ_SRC_X);
+ outw(DESTX_DIASTP, 0xAAAAU);
+ ProbeWaitIdleEmpty();
+ if (inw(READ_SRC_X) == 0x02AAU)
+ pATI->Adapter = ATI_ADAPTER_MACH32;
+
+ outw(DESTX_DIASTP, 0x5555U);
+ ProbeWaitIdleEmpty();
+ if (inw(READ_SRC_X) == 0x0555U)
+ {
+ if (pATI->Adapter != ATI_ADAPTER_MACH32)
+ pATI->Adapter = ATI_ADAPTER_8514A;
+ }
+ else
+ {
+ if (pATI->Adapter != ATI_ADAPTER_MACH8)
+ pATI->Adapter = ATI_ADAPTER_8514A;
+ }
+ outw(DESTX_DIASTP, IOValue1);
+ }
+
+ switch (pATI->Adapter)
+ {
+ case ATI_ADAPTER_8514A:
+ pATI->Coprocessor = ATI_CHIP_8514A;
+ IOValue1 = inb(EXT_CONFIG_3);
+ outb(EXT_CONFIG_3, IOValue1 & 0x0FU);
+ if (!(inb(EXT_CONFIG_3) & 0xF0U))
+ {
+ outb(EXT_CONFIG_3, IOValue1 | 0xF0U);
+ if ((inb(EXT_CONFIG_3) & 0xF0U) == 0xF0U)
+ pATI->Coprocessor = ATI_CHIP_CT480;
+ }
+ outb(EXT_CONFIG_3, IOValue1);
+ break;
+
+ case ATI_ADAPTER_MACH8:
+ pATI->Coprocessor = ATI_CHIP_38800_1;
+ if (inw(CONFIG_STATUS_1) & MC_BUS)
+ pATI->BusType = ATI_BUS_MCA16;
+ break;
+
+ case ATI_ADAPTER_MACH32:
+ IOValue1 = inw(CONFIG_STATUS_1);
+ pATI->BusType = GetBits(IOValue1, BUS_TYPE);
+ pATI->BIOSBase = 0x000C0000U +
+ (GetBits(IOValue2, BIOS_BASE_SEGMENT) << 11);
+ if (!(IOValue1 & (_8514_ONLY | CHIP_DIS)))
+ {
+ pATI->VGAAdapter = ATI_ADAPTER_MACH32;
+ if ((xf86ReadBIOS(pATI->BIOSBase, 0x10U,
+ (pointer)(&pATI->CPIO_VGAWonder),
+ SizeOf(pATI->CPIO_VGAWonder)) <
+ SizeOf(pATI->CPIO_VGAWonder)) ||
+ !(pATI->CPIO_VGAWonder &= SPARSE_IO_PORT))
+ pATI->CPIO_VGAWonder = 0x01CEU;
+ pATI->VGAOffset = 0x80U;
+ }
+
+ ATIMach32ChipID(pATI);
+ break;
+
+ default:
+ break;
+ }
+
+ return pATI;
+}
+
+#endif /* AVOID_CPIO */
+
+/*
+ * ATIDetectMach64 --
+ *
+ * This function determines if a Mach64 is detectable at a particular base
+ * address.
+ */
+static Bool
+ATIDetectMach64
+(
+ ATIPtr pATI,
+ const CARD16 ChipType,
+ const ATIChipType Chip
+)
+{
+ CARD32 IOValue, bus_cntl, gen_test_cntl;
+
+ (void)ATIMapApertures(-1, pATI); /* Ignore errors */
+
+#ifdef AVOID_CPIO
+
+ if (!pATI->pBlock[0])
+ {
+ ATIUnmapApertures(-1, pATI);
+ return FALSE;
+ }
+
+#endif /* AVOID_CPIO */
+
+ /* Make sure any Mach64 is not in some weird state */
+ bus_cntl = inr(BUS_CNTL);
+ if (Chip < ATI_CHIP_264VTB)
+ outr(BUS_CNTL,
+ (bus_cntl & ~(BUS_HOST_ERR_INT_EN | BUS_FIFO_ERR_INT_EN)) |
+ (BUS_HOST_ERR_INT | BUS_FIFO_ERR_INT));
+ else if (Chip < ATI_CHIP_264VT4)
+ outr(BUS_CNTL, (bus_cntl & ~BUS_HOST_ERR_INT_EN) | BUS_HOST_ERR_INT);
+
+ gen_test_cntl = inr(GEN_TEST_CNTL);
+ IOValue = gen_test_cntl &
+ (GEN_OVR_OUTPUT_EN | GEN_OVR_POLARITY | GEN_CUR_EN | GEN_BLOCK_WR_EN);
+ outr(GEN_TEST_CNTL, IOValue | GEN_GUI_EN);
+ outr(GEN_TEST_CNTL, IOValue);
+ outr(GEN_TEST_CNTL, IOValue | GEN_GUI_EN);
+
+ /* See if a Mach64 answers */
+ IOValue = inr(SCRATCH_REG0);
+
+ /* Test odd bits */
+ outr(SCRATCH_REG0, 0x55555555U);
+ if (inr(SCRATCH_REG0) == 0x55555555U)
+ {
+ /* Test even bits */
+ outr(SCRATCH_REG0, 0xAAAAAAAAU);
+ if (inr(SCRATCH_REG0) == 0xAAAAAAAAU)
+ {
+ /*
+ * *Something* has a R/W 32-bit register at this address. Try to
+ * make sure it's a Mach64. The following assumes that ATI will
+ * not be producing any more adapters that do not register
+ * themselves in PCI configuration space.
+ */
+ ATIMach64ChipID(pATI, ChipType);
+ if ((pATI->Chip != ATI_CHIP_Mach64) ||
+ (pATI->CPIODecoding == BLOCK_IO))
+ pATI->Adapter = ATI_ADAPTER_MACH64;
+ }
+ }
+
+ /* Restore clobbered register value */
+ outr(SCRATCH_REG0, IOValue);
+
+ /* If no Mach64 was detected, return now */
+ if (pATI->Adapter != ATI_ADAPTER_MACH64)
+ {
+ outr(GEN_TEST_CNTL, gen_test_cntl);
+ outr(BUS_CNTL, bus_cntl);
+ ATIUnmapApertures(-1, pATI);
+ return FALSE;
+ }
+
+ /* Determine legacy BIOS address */
+ pATI->BIOSBase = 0x000C0000U +
+ (GetBits(inr(SCRATCH_REG1), BIOS_BASE_SEGMENT) << 11);
+
+ ATIUnmapApertures(-1, pATI);
+ pATI->PCIInfo = NULL;
+ return TRUE;
+}
+
+#ifdef AVOID_CPIO
+
+/*
+ * ATIMach64Probe --
+ *
+ * This function looks for a Mach64 at a particular MMIO address and returns an
+ * ATIRec if one is found.
+ */
+static ATIPtr
+ATIMach64Probe
+(
+ pciVideoPtr pVideo,
+ const IOADDRESS IOBase,
+ const CARD8 IODecoding,
+ const ATIChipType Chip
+)
+{
+ ATIPtr pATI = (ATIPtr)xnfcalloc(1, SizeOf(ATIRec));
+ CARD16 ChipType = 0;
+
+ pATI->CPIOBase = IOBase;
+ pATI->CPIODecoding = IODecoding;
+
+ if (pVideo)
+ {
+ pATI->PCIInfo = pVideo;
+ ChipType = pVideo->chipType;
+
+ /*
+ * Probe through auxiliary MMIO aperture if one exists. Because such
+ * apertures can be enabled/disabled only through PCI, this probes no
+ * further.
+ */
+ if ((pVideo->size[2] >= 12) &&
+ (pATI->Block0Base = pVideo->memBase[2]) &&
+ (pATI->Block0Base < (CARD32)(-1 << pVideo->size[2])))
+ {
+ pATI->Block0Base += 0x00000400U;
+ goto LastProbe;
+ }
+
+ /*
+ * Probe through the primary MMIO aperture that exists at the tail end
+ * of the linear aperture. Test for both 8MB and 4MB linear apertures.
+ */
+ if ((pVideo->size[0] >= 22) && (pATI->Block0Base = pVideo->memBase[0]))
+ {
+ pATI->Block0Base += 0x007FFC00U;
+ if ((pVideo->size[0] >= 23) &&
+ ATIDetectMach64(pATI, ChipType, Chip))
+ return pATI;
+
+ pATI->Block0Base -= 0x00400000U;
+ if (ATIDetectMach64(pATI, ChipType, Chip))
+ return pATI;
+ }
+ }
+
+ /*
+ * A last, perhaps desparate, probe attempt. Note that if this succeeds,
+ * there's a VGA in the system and it's likely the PIO version of the
+ * driver should be used instead (barring OS issues).
+ */
+ pATI->Block0Base = 0x000BFC00U;
+
+LastProbe:
+ if (ATIDetectMach64(pATI, ChipType, Chip))
+ return pATI;
+
+ xfree(pATI);
+ return NULL;
+}
+
+#else /* AVOID_CPIO */
+
+/*
+ * ATIMach64Probe --
+ *
+ * This function looks for a Mach64 at a particular PIO address and returns an
+ * ATIRec if one is found.
+ */
+static ATIPtr
+ATIMach64Probe
+(
+ pciVideoPtr pVideo,
+ const IOADDRESS IOBase,
+ const CARD8 IODecoding,
+ const ATIChipType Chip
+)
+{
+ ATIPtr pATI;
+ CARD32 IOValue;
+ CARD16 ChipType = 0;
+
+ if (!IOBase)
+ return NULL;
+
+ if (pVideo)
+ {
+ if ((IODecoding == BLOCK_IO) &&
+ ((pVideo->size[1] < 8) ||
+ (IOBase >= (CARD32)(-1 << pVideo->size[1]))))
+ return NULL;
+
+ ChipType = pVideo->chipType;
+ }
+
+ pATI = (ATIPtr)xnfcalloc(1, SizeOf(ATIRec));
+ pATI->CPIOBase = IOBase;
+ pATI->CPIODecoding = IODecoding;
+ pATI->PCIInfo = pVideo;
+
+ if (!ATIDetectMach64(pATI, ChipType, Chip))
+ {
+ xfree(pATI);
+ return NULL;
+ }
+
+ /*
+ * Determine VGA capability. VGA can always be enabled on integrated
+ * controllers. For the GX/CX, it's a board strap.
+ */
+ if (pATI->Chip >= ATI_CHIP_264CT)
+ pATI->VGAAdapter = ATI_ADAPTER_MACH64;
+ else
+ {
+ IOValue = inr(CONFIG_STATUS64_0);
+ pATI->BusType = GetBits(IOValue, CFG_BUS_TYPE);
+ IOValue &= (CFG_VGA_EN | CFG_CHIP_EN);
+ if (pATI->Chip == ATI_CHIP_88800CX)
+ IOValue |= CFG_VGA_EN;
+ if (IOValue == (CFG_VGA_EN | CFG_CHIP_EN))
+ {
+ pATI->VGAAdapter = ATI_ADAPTER_MACH64;
+ pATI->CPIO_VGAWonder = 0x01CEU;
+ pATI->VGAOffset = 0x80U;
+ }
+ }
+
+ return pATI;
+}
+
+/*
+ * ATIAssignVGA --
+ *
+ * This function is called to associate a VGA interface with an accelerator.
+ * This is done by temporarily configuring the accelerator to route VGA RAMDAC
+ * I/O through the accelerator's RAMDAC. A value is then written through the
+ * VGA DAC ports and a check is made to see if the same value shows up on the
+ * accelerator side.
+ */
+static void
+ATIAssignVGA
+(
+ pciVideoPtr pVideo,
+ ATIPtr *ppVGA,
+ ATIPtr pATI,
+ ATIPtr p8514,
+ CARD8 *ProbeFlags
+)
+{
+ ATIPtr pVGA = *ppVGA;
+ CARD8 OldDACMask;
+
+ /* Assume unassignable VGA */
+ pATI->VGAAdapter = ATI_ADAPTER_NONE;
+
+ /* If no assignable VGA, return now */
+ if ((pATI != pVGA) && (!pVGA || (pVGA->Adapter > ATI_ADAPTER_VGA)))
+ return;
+
+ switch (pATI->Adapter)
+ {
+ case ATI_ADAPTER_8514A:
+ {
+ /*
+ * Assumption: Bit DISABPASSTHRU in ADVFUNC_CNTL is already
+ * off.
+ */
+ OldDACMask = inb(VGA_DAC_MASK);
+
+ if (inb(IBM_DAC_MASK) == OldDACMask)
+ {
+ outb(VGA_DAC_MASK, 0xA5U);
+ if (inb(IBM_DAC_MASK) == 0xA5U)
+ pATI->VGAAdapter = ATI_ADAPTER_VGA;
+ }
+
+ outb(VGA_DAC_MASK, OldDACMask);
+ }
+ break;
+
+ case ATI_ADAPTER_MACH8:
+ {
+ CARD16 ClockSel = inw(CLOCK_SEL);
+
+ if (ClockSel & DISABPASSTHRU)
+ outw(CLOCK_SEL, ClockSel & ~DISABPASSTHRU);
+
+ ProbeWaitIdleEmpty();
+
+ OldDACMask = inb(VGA_DAC_MASK);
+
+ if (inb(IBM_DAC_MASK) == OldDACMask)
+ {
+ outb(VGA_DAC_MASK, 0xA5U);
+ if (inb(IBM_DAC_MASK) == 0xA5U)
+ pATI->VGAAdapter = ATI_ADAPTER_VGA;
+ }
+
+ outb(VGA_DAC_MASK, OldDACMask);
+
+ if (ClockSel & DISABPASSTHRU)
+ outw(CLOCK_SEL, ClockSel);
+ }
+ break;
+
+ case ATI_ADAPTER_MACH32:
+ {
+ CARD16 ClockSel = inw(CLOCK_SEL),
+ MiscOptions = inw(MISC_OPTIONS);
+
+ if (ClockSel & DISABPASSTHRU)
+ outw(CLOCK_SEL, ClockSel & ~DISABPASSTHRU);
+ if (MiscOptions & (DISABLE_VGA | DISABLE_DAC))
+ outw(MISC_OPTIONS,
+ MiscOptions & ~(DISABLE_VGA | DISABLE_DAC));
+
+ ProbeWaitIdleEmpty();
+
+ OldDACMask = inb(VGA_DAC_MASK);
+
+ if (inb(IBM_DAC_MASK) == OldDACMask)
+ {
+ outb(VGA_DAC_MASK, 0xA5U);
+ if (inb(IBM_DAC_MASK) == 0xA5U)
+ pATI->VGAAdapter = ATI_ADAPTER_MACH32;
+ }
+
+ outb(VGA_DAC_MASK, OldDACMask);
+
+ if (ClockSel & DISABPASSTHRU)
+ outw(CLOCK_SEL, ClockSel);
+ if (MiscOptions & (DISABLE_VGA | DISABLE_DAC))
+ outw(MISC_OPTIONS, MiscOptions);
+ }
+ break;
+
+ case ATI_ADAPTER_MACH64:
+ {
+ CARD32 DACCntl = inr(DAC_CNTL);
+
+ if (!(DACCntl & DAC_VGA_ADR_EN))
+ outr(DAC_CNTL, DACCntl | DAC_VGA_ADR_EN);
+
+ OldDACMask = inb(VGA_DAC_MASK);
+
+ if (in8(M64_DAC_MASK) == OldDACMask)
+ {
+ outb(VGA_DAC_MASK, 0xA5U);
+ if (in8(M64_DAC_MASK) == 0xA5U)
+ pATI->VGAAdapter = ATI_ADAPTER_MACH64;
+ }
+
+ outb(VGA_DAC_MASK, OldDACMask);
+
+ if (!(DACCntl & DAC_VGA_ADR_EN))
+ outr(DAC_CNTL, DACCntl);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (pATI->VGAAdapter == ATI_ADAPTER_NONE)
+ {
+ pATI->CPIO_VGAWonder = 0;
+ return;
+ }
+
+ if (pATI->CPIO_VGAWonder)
+ {
+ ATIVGAWonderProbe(pVideo, pATI, p8514, ProbeFlags);
+ if (!pATI->CPIO_VGAWonder)
+ {
+ /*
+ * Some adapters are reputed to append ATI extended VGA registers
+ * to the VGA Graphics controller registers. In particular, 0x01CE
+ * cannot, in general, be used in a PCI environment due to routing
+ * of I/O through the bus tree.
+ */
+ pATI->CPIO_VGAWonder = GRAX;
+ ATIVGAWonderProbe(pVideo, pATI, p8514, ProbeFlags);
+ }
+ }
+
+ if (pATI == pVGA)
+ {
+ pATI->SharedVGA = TRUE;
+ return;
+ }
+
+ /* Assign the VGA to this adapter */
+ xfree(pVGA);
+ *ppVGA = pATI;
+
+ xf86MsgVerb(X_INFO, 3, ATI_NAME ": VGA assigned to this adapter.\n");
+}
+
+/*
+ * ATIClaimVGA --
+ *
+ * Attempt to assign a non-shareable VGA to an accelerator. If successful,
+ * update ProbeFlags array.
+ */
+static void
+ATIClaimVGA
+(
+ pciVideoPtr pVideo,
+ ATIPtr *ppVGA,
+ ATIPtr pATI,
+ ATIPtr p8514,
+ CARD8 *ProbeFlags,
+ int Detected
+)
+{
+ ATIAssignVGA(pVideo, ppVGA, pATI, p8514, ProbeFlags);
+ if (pATI->VGAAdapter == ATI_ADAPTER_NONE)
+ return;
+
+ ATIClaimSparseIOBases(ProbeFlags, MonochromeIOBase, 48, Detected);
+ if (!pATI->CPIO_VGAWonder)
+ return;
+
+ ATIClaimSparseIOBases(ProbeFlags, pATI->CPIO_VGAWonder, 2, Detected);
+}
+
+/*
+ * ATIFindVGA --
+ *
+ * This function determines if a VGA associated with an ATI PCI adapter is
+ * shareable.
+ */
+static void
+ATIFindVGA
+(
+ pciVideoPtr pVideo,
+ ATIPtr *ppVGA,
+ ATIPtr *ppATI,
+ ATIPtr p8514,
+ CARD8 *ProbeFlags
+)
+{
+ ATIPtr pATI = *ppATI;
+
+ if (!*ppVGA)
+ {
+ /*
+ * An ATI PCI adapter has been detected at this point, and its VGA, if
+ * any, is shareable. Ensure the VGA isn't in sleep mode.
+ */
+ outb(GENENA, 0x16U);
+ outb(GENVS, 0x01U);
+ outb(GENENA, 0x0EU);
+
+ pATI = ATIVGAProbe(pATI);
+ if (pATI->VGAAdapter == ATI_ADAPTER_NONE)
+ return;
+
+ ppVGA = ppATI;
+ }
+
+ ATIAssignVGA(pVideo, ppVGA, pATI, p8514, ProbeFlags);
+}
+
+#endif /* AVOID_CPIO */
+
+/*
+ * ATIProbe --
+ *
+ * This function is called once, at the start of the first server generation to
+ * do a minimal probe for supported hardware.
+ */
+Bool
+ATIProbe
+(
+ DriverPtr pDriver,
+ int flags
+)
+{
+ ATIPtr pATI, *ATIPtrs = NULL;
+ GDevPtr *GDevs, pGDev;
+ pciVideoPtr pVideo, *xf86PciVideoInfo = xf86GetPciVideoInfo();
+ pciConfigPtr pPCI;
+ ATIGDev *ATIGDevs = NULL, *pATIGDev;
+ ScrnInfoPtr pScreenInfo;
+ CARD32 PciReg;
+ Bool ProbeSuccess = FALSE;
+ Bool DoRage128 = FALSE, DoRadeon = FALSE;
+ int i, j, k;
+ int nGDev, nATIGDev = -1, nATIPtr = 0;
+ int Chipset;
+ ATIChipType Chip;
+
+#ifndef AVOID_CPIO
+
+ ATIPtr pVGA = NULL, p8514 = NULL;
+ ATIPtr pMach64[3] = {NULL, NULL, NULL};
+ pciConfigPtr *xf86PciInfo = xf86GetPciConfigInfo();
+ PortPtr PCIPorts = NULL;
+ int nPCIPort = 0;
+ CARD8 fChipsets[ATI_CHIPSET_MAX];
+ static const IOADDRESS Mach64SparseIOBases[] = {0x02ECU, 0x01CCU, 0x01C8U};
+ CARD8 ProbeFlags[LongPort(SPARSE_IO_BASE) + 1];
+
+ unsigned long BIOSBase;
+ static const CARD8 ATISignature[] = " 761295520";
+# define SignatureSize 10
+# define PrefixSize 0x50U
+# define BIOSSignature 0x30U
+ CARD8 BIOS[PrefixSize];
+# define BIOSWord(_n) (BIOS[_n] | (BIOS[(_n) + 1] << 8))
+
+#endif /* AVOID_CPIO */
+
+# define AddAdapter(_p) \
+ do \
+ { \
+ nATIPtr++; \
+ ATIPtrs = (ATIPtr *)xnfrealloc(ATIPtrs, SizeOf(ATIPtr) * nATIPtr); \
+ ATIPtrs[nATIPtr - 1] = (_p); \
+ (_p)->iEntity = -2; \
+ } while (0)
+
+#ifndef AVOID_CPIO
+
+ (void)memset(fChipsets, FALSE, SizeOf(fChipsets));
+
+#endif /* AVOID_CPIO */
+
+ if (!(flags & PROBE_DETECT))
+ {
+ /*
+ * Get a list of XF86Config device sections whose "Driver" is either
+ * not specified, or specified as this driver. From this list,
+ * eliminate those device sections that specify a "Chipset" or a
+ * "ChipID" not recognised by the driver. Those device sections that
+ * specify a "ChipRev" without a "ChipID" are also weeded out.
+ */
+ nATIGDev = 0;
+ if ((nGDev = xf86MatchDevice(ATI_NAME, &GDevs)) > 0)
+ {
+ ATIGDevs = (ATIGDevPtr)xnfcalloc(nGDev, SizeOf(ATIGDev));
+
+ for (i = 0, pATIGDev = ATIGDevs; i < nGDev; i++)
+ {
+ pGDev = GDevs[i];
+ Chipset = ATIIdentProbe(pGDev->chipset);
+ if (Chipset == -1)
+ continue;
+
+ if ((pGDev->chipID > (int)((CARD16)(-1))) ||
+ (pGDev->chipRev > (int)((CARD8)(-1))))
+ continue;
+
+ if (pGDev->chipID >= 0)
+ {
+ if (ATIChipID(pGDev->chipID, 0) == ATI_CHIP_Mach64)
+ continue;
+ }
+ else
+ {
+ if (pGDev->chipRev >= 0)
+ continue;
+ }
+
+ pATIGDev->pGDev = pGDev;
+ pATIGDev->Chipset = Chipset;
+ nATIGDev++;
+ pATIGDev++;
+
+ xf86MsgVerb(X_INFO, 3,
+ ATI_NAME ": Candidate \"Device\" section \"%s\".\n",
+ pGDev->identifier);
+
+#ifndef AVOID_CPIO
+
+ fChipsets[Chipset] = TRUE;
+
+#endif /* AVOID_CPIO */
+
+ }
+
+ xfree(GDevs);
+
+ if (!nATIGDev)
+ {
+ xfree(ATIGDevs);
+ ATIGDevs = NULL;
+ }
+ }
+
+ if (xf86MatchDevice(R128_NAME, NULL) > 0)
+ DoRage128 = TRUE;
+ if (xf86MatchDevice(RADEON_NAME, NULL) > 0)
+ DoRadeon = TRUE;
+ }
+
+#ifndef AVOID_CPIO
+
+ /*
+ * Collect hardware information. This must be done with care to avoid
+ * lockups due to overlapping I/O port assignments.
+ *
+ * First, scan PCI configuration space for registered I/O ports (which will
+ * be block I/O bases). Each such port is used to generate a list of
+ * sparse I/O bases it precludes. This list is then used to decide whether
+ * or not certain sparse I/O probes are done. Unfortunately, this assumes
+ * that any registered I/O base actually reserves upto the full 256 ports
+ * allowed by the PCI specification. This assumption holds true for PCI
+ * Mach64, but probably doesn't for other device types. For some things,
+ * such as video devices, the number of ports a base represents is
+ * determined by the server's PCI probe, but, for other devices, this
+ * cannot be done by a user-level process without jeopardizing system
+ * integrity. This information should ideally be retrieved from the OS's
+ * own PCI probe (if any), but there's currently no portable way of doing
+ * so. The following allows sparse I/O probes to be forced in certain
+ * circumstances when an appropriate chipset specification is used in any
+ * XF86Config Device section.
+ *
+ * Note that this is not bullet-proof. Lockups can still occur, but they
+ * will usually be due to devices that are misconfigured to respond to the
+ * same I/O ports as 8514/A's or ATI sparse I/O devices without registering
+ * them in PCI configuration space.
+ */
+ if (nATIGDev)
+ {
+ if (xf86PciVideoInfo)
+ {
+ for (i = 0; (pVideo = xf86PciVideoInfo[i++]); )
+ {
+ if (pVideo->vendor == PCI_VENDOR_ATI)
+ continue;
+
+ pPCI = pVideo->thisCard;
+
+ ATIScanPCIBases(&PCIPorts, &nPCIPort,
+ &pPCI->pci_base0, pVideo->size,
+ (pciReadLong(pPCI->tag, PCI_CMD_STAT_REG) &
+ PCI_CMD_IO_ENABLE) ? 0 : Allowed);
+ }
+ }
+
+ /* Check non-video PCI devices for I/O bases */
+ if (xf86PciInfo)
+ {
+ for (i = 0; (pPCI = xf86PciInfo[i++]); )
+ {
+ if ((pPCI->pci_vendor == PCI_VENDOR_ATI) ||
+ (pPCI->pci_base_class == PCI_CLASS_BRIDGE) ||
+ (pPCI->pci_header_type &
+ ~GetByte(PCI_HEADER_MULTIFUNCTION, 2)))
+ continue;
+
+ ATIScanPCIBases(&PCIPorts, &nPCIPort,
+ &pPCI->pci_base0, pPCI->basesize,
+ (pciReadLong(pPCI->tag, PCI_CMD_STAT_REG) &
+ PCI_CMD_IO_ENABLE) ? 0 : Allowed);
+ }
+ }
+
+ /* Generate ProbeFlags array from list of registered PCI I/O bases */
+ (void)memset(ProbeFlags, Allowed | DoProbe, SizeOf(ProbeFlags));
+ for (i = 0; i < nPCIPort; i++)
+ {
+ CARD32 Base = PCIPorts[i].Base;
+ CARD16 Count = (1 << PCIPorts[i].Size) - 1;
+ CARD8 ProbeFlag = PCIPorts[i].Flag;
+
+ /*
+ * The following reduction of Count is based on the assumption that
+ * PCI-registered I/O port ranges do not overlap.
+ */
+ for (j = 0; j < nPCIPort; j++)
+ {
+ CARD32 Base2 = PCIPorts[j].Base;
+
+ if (Base < Base2)
+ while ((Base + Count) >= Base2)
+ Count >>= 1;
+ }
+
+ Base = LongPort(Base);
+ Count = LongPort((Count | IO_BYTE_SELECT) + 1);
+ while (Count--)
+ ProbeFlags[Base++] &= ProbeFlag;
+ }
+
+ xfree(PCIPorts);
+
+ /*
+ * A note on probe strategy. I/O and memory response by certain PCI
+ * devices has been disabled by the common layer at this point,
+ * including any devices this driver might be interested in. The
+ * following does sparse I/O probes, followed by block I/O probes.
+ * Block I/O probes are dictated by what is found to be of interest in
+ * PCI configuration space. All this will detect ATI adapters that do
+ * not implement this disablement, pre-PCI or not.
+ *
+ * PCI configuration space is then scanned again for ATI devices that
+ * failed to be detected the first time around. Each such device is
+ * probed for again, this time with I/O temporarily enabled through
+ * PCI.
+ */
+ if (ATICheckSparseIOBases(NULL, ProbeFlags, ATTRX, 16, TRUE) ==
+ DoProbe)
+ {
+ pATI = ATIVGAProbe(NULL);
+ if (pATI->Adapter == ATI_ADAPTER_NONE)
+ {
+ xfree(pATI);
+
+ xf86MsgVerb(X_INFO, 4,
+ ATI_NAME ": Unshared VGA not detected.\n");
+ }
+ else
+ {
+ /*
+ * Claim all MDA/HGA/CGA/EGA/VGA I/O ports. This might need to
+ * be more selective.
+ */
+ ATIClaimSparseIOBases(ProbeFlags, MonochromeIOBase, 48,
+ DetectedVGA);
+
+ pVGA = pATI;
+ strcpy(Identifier, "Unshared VGA");
+ xf86MsgVerb(X_INFO, 3,
+ ATI_NAME ": %s detected.\n", Identifier);
+ }
+ }
+ else
+ {
+ xf86MsgVerb(X_INFO, 2, ATI_NAME ": Unshared VGA not probed.\n");
+ }
+
+ if (ATICheckSparseIOBases(NULL, ProbeFlags, 0x02E8U, 8,
+ fChipsets[ATI_CHIPSET_IBM8514] ||
+ fChipsets[ATI_CHIPSET_MACH8] ||
+ fChipsets[ATI_CHIPSET_MACH32]) == DoProbe)
+ {
+ if ((pATI = ATI8514Probe(NULL)))
+ {
+ strcpy(Identifier, "Unshared 8514/A");
+ xf86MsgVerb(X_INFO, 3,
+ ATI_NAME ": %s detected.\n", Identifier);
+
+ AddAdapter(p8514 = pATI);
+
+ if ((pATI->VGAAdapter != ATI_ADAPTER_NONE) ||
+ (pATI->Coprocessor != ATI_CHIP_NONE))
+ ATIClaimVGA(NULL, &pVGA, pATI, p8514, ProbeFlags,
+ Detected8514A);
+
+ ATIClaimSparseIOBases(ProbeFlags, 0x02E8U, 8, Detected8514A);
+ }
+ else
+ {
+ xf86MsgVerb(X_INFO, 4,
+ ATI_NAME ": Unshared 8514/A not detected.\n");
+ }
+ }
+ else
+ {
+ xf86MsgVerb(X_INFO, 2,
+ ATI_NAME ": Unshared 8514/A not probed.\n");
+ }
+
+ for (i = 0; i < NumberOf(Mach64SparseIOBases); i++)
+ {
+ if (ATICheckSparseIOBases(NULL, ProbeFlags, Mach64SparseIOBases[i],
+ 4, fChipsets[ATI_CHIPSET_MACH64]) != DoProbe)
+ {
+ xf86MsgVerb(X_INFO, 2,
+ ATI_NAME ": Unshared Mach64 at PIO base 0x%04X not"
+ " probed.\n",
+ Mach64SparseIOBases[i]);
+ continue;
+ }
+
+ pATI = ATIMach64Probe(NULL, Mach64SparseIOBases[i], SPARSE_IO, 0);
+ if (!pATI)
+ {
+ xf86MsgVerb(X_INFO, 4,
+ ATI_NAME ": Unshared Mach64 at PIO base 0x%04X not"
+ " detected.\n", Mach64SparseIOBases[i]);
+ continue;
+ }
+
+ sprintf(Identifier, "Unshared Mach64 at sparse PIO base 0x%04lX",
+ Mach64SparseIOBases[i]);
+ xf86MsgVerb(X_INFO, 3, ATI_NAME ": %s detected.\n", Identifier);
+
+ AddAdapter(pMach64[i] = pATI);
+
+ if (pATI->VGAAdapter != ATI_ADAPTER_NONE)
+ ATIClaimVGA(NULL, &pVGA, pATI, p8514, ProbeFlags,
+ DetectedMach64);
+
+ ATIClaimSparseIOBases(ProbeFlags, Mach64SparseIOBases[i], 4,
+ DetectedMach64);
+ }
+ }
+
+#endif /* AVOID_CPIO */
+
+ if (xf86PciVideoInfo)
+ {
+ if (nATIGDev)
+ {
+
+#ifndef AVOID_NON_PCI
+
+#ifdef AVOID_CPIO
+
+ /* PCI sparse I/O adapters can still be used through MMIO */
+ for (i = 0; (pVideo = xf86PciVideoInfo[i++]); )
+ {
+ if ((pVideo->vendor != PCI_VENDOR_ATI) ||
+ (pVideo->chipType == PCI_CHIP_MACH32) ||
+ pVideo->size[1])
+ continue;
+
+ pPCI = pVideo->thisCard;
+ PciReg = pciReadLong(pPCI->tag, PCI_REG_USERCONFIG);
+
+ /* Possibly fix block I/O indicator */
+ if (PciReg & 0x00000004U)
+ pciWriteLong(pPCI->tag, PCI_REG_USERCONFIG,
+ PciReg & ~0x00000004U);
+
+ Chip = ATIChipID(pVideo->chipType, pVideo->chipRev);
+
+ /*
+ * The CPIO base used by the adapter is of little concern here.
+ */
+ pATI = ATIMach64Probe(pVideo, 0, SPARSE_IO, Chip);
+ if (!pATI)
+ continue;
+
+ sprintf(Identifier,
+ "Unshared PCI sparse I/O Mach64 in slot %d:%d:%d",
+ pVideo->bus, pVideo->device, pVideo->func);
+ xf86MsgVerb(X_INFO, 3,
+ ATI_NAME ": %s detected through Block 0 at 0x%08X.\n",
+ Identifier, pATI->Block0Base);
+ AddAdapter(pATI);
+ pATI->PCIInfo = pVideo;
+ }
+
+#endif /* AVOID_CPIO */
+
+ for (i = 0; (pVideo = xf86PciVideoInfo[i++]); )
+ {
+ if ((pVideo->vendor != PCI_VENDOR_ATI) ||
+ (pVideo->chipType == PCI_CHIP_MACH32) ||
+ !pVideo->size[1])
+ continue;
+
+ /* For now, ignore Rage128's and Radeon's */
+ Chip = ATIChipID(pVideo->chipType, pVideo->chipRev);
+ if (Chip > ATI_CHIP_Mach64)
+ continue;
+
+ pPCI = pVideo->thisCard;
+
+ /*
+ * Possibly fix block I/O indicator in PCI configuration space.
+ */
+ PciReg = pciReadLong(pPCI->tag, PCI_REG_USERCONFIG);
+ if (!(PciReg & 0x00000004U))
+ pciWriteLong(pPCI->tag, PCI_REG_USERCONFIG,
+ PciReg | 0x00000004U);
+
+ pATI =
+ ATIMach64Probe(pVideo, pVideo->ioBase[1], BLOCK_IO, Chip);
+ if (!pATI)
+ continue;
+
+ sprintf(Identifier, "Unshared PCI/AGP Mach64 in slot %d:%d:%d",
+ pVideo->bus, pVideo->device, pVideo->func);
+ xf86MsgVerb(X_INFO, 3,
+ ATI_NAME ": %s detected.\n", Identifier);
+ AddAdapter(pATI);
+
+#ifndef AVOID_CPIO
+
+ /* This is probably not necessary */
+ if (pATI->VGAAdapter != ATI_ADAPTER_NONE)
+ ATIClaimVGA(pVideo, &pVGA, pATI, p8514,
+ ProbeFlags, DetectedMach64);
+
+#endif /* AVOID_CPIO */
+
+ }
+
+#endif /* AVOID_NON_PCI */
+
+#ifndef AVOID_CPIO
+
+ /*
+ * This is the second pass through PCI configuration space. Much
+ * of this is verbiage to deal with potential situations that are
+ * very unlikely to occur in practice.
+ *
+ * First, look for non-ATI shareable VGA's. For now, these must
+ * the primary device.
+ */
+ if (ATICheckSparseIOBases(NULL, ProbeFlags, ATTRX, 16, TRUE) ==
+ DoProbe)
+ {
+ for (i = 0; (pVideo = xf86PciVideoInfo[i++]); )
+ {
+ if ((pVideo->vendor == PCI_VENDOR_ATI) ||
+ !xf86IsPrimaryPci(pVideo))
+ continue;
+
+ if (!xf86CheckPciSlot(pVideo->bus,
+ pVideo->device,
+ pVideo->func))
+ continue;
+
+ xf86SetPciVideo(pVideo, MEM_IO);
+
+ pATI = ATIVGAProbe(NULL);
+ if (pATI->Adapter == ATI_ADAPTER_NONE)
+ {
+ xfree(pATI);
+ xf86Msg(X_WARNING,
+ ATI_NAME ": PCI/AGP VGA compatible in slot"
+ " %d:%d:%d could not be detected!\n",
+ pVideo->bus, pVideo->device, pVideo->func);
+ }
+ else
+ {
+ sprintf(Identifier,
+ "Shared non-ATI VGA in PCI/AGP slot %d:%d:%d",
+ pVideo->bus, pVideo->device, pVideo->func);
+ xf86MsgVerb(X_INFO, 3, ATI_NAME ": %s detected.\n",
+ Identifier);
+ AddAdapter(pATI);
+ pATI->SharedVGA = TRUE;
+ pATI->BusType = ATI_BUS_PCI;
+ pATI->PCIInfo = pVideo;
+ }
+
+ xf86SetPciVideo(NULL, NONE);
+ }
+ }
+
+ /* Next, look for PCI Mach32's */
+ for (i = 0; (pVideo = xf86PciVideoInfo[i++]); )
+ {
+ if ((pVideo->vendor != PCI_VENDOR_ATI) ||
+ (pVideo->chipType != PCI_CHIP_MACH32))
+ continue;
+
+ switch (ATICheckSparseIOBases(pVideo, ProbeFlags,
+ 0x02E8U, 8, TRUE))
+ {
+ case 0:
+ xf86Msg(X_WARNING,
+ ATI_NAME ": PCI Mach32 in slot %d:%d:%d will not"
+ " be enabled\n because it conflicts with a"
+ " non-video PCI/AGP device.\n",
+ pVideo->bus, pVideo->device, pVideo->func);
+ break;
+
+ case Detected8514A:
+ if ((p8514->BusType >= ATI_BUS_PCI) && !p8514->PCIInfo)
+ p8514->PCIInfo = pVideo;
+ else
+ xf86Msg(X_WARNING,
+ ATI_NAME ": PCI Mach32 in slot %d:%d:%d will"
+ " not be enabled\n because it conflicts with"
+ " another %s %s.\n",
+ pVideo->bus, pVideo->device, pVideo->func,
+ ATIBusNames[p8514->BusType],
+ ATIAdapterNames[p8514->Adapter]);
+ break;
+
+ case DetectedMach64:
+ xf86Msg(X_WARNING,
+ ATI_NAME ": PCI Mach32 in slot %d:%d:%d will not"
+ " be enabled\n because it conflicts with a Mach64"
+ " at I/O base 0x02EC.\n",
+ pVideo->bus, pVideo->device, pVideo->func);
+ break;
+
+ default: /* Must be DoProbe */
+ if (!xf86CheckPciSlot(pVideo->bus,
+ pVideo->device,
+ pVideo->func))
+ continue;
+
+ xf86SetPciVideo(pVideo, MEM_IO);
+
+ if (!(pATI = ATI8514Probe(pVideo)))
+ xf86Msg(X_WARNING,
+ ATI_NAME ": PCI Mach32 in slot %d:%d:%d could"
+ " not be detected!\n",
+ pVideo->bus, pVideo->device, pVideo->func);
+ else
+ {
+ sprintf(Identifier,
+ "Shared 8514/A in PCI slot %d:%d:%d",
+ pVideo->bus, pVideo->device, pVideo->func);
+ xf86MsgVerb(X_INFO, 3,
+ ATI_NAME ": %s detected.\n", Identifier);
+ if (pATI->Adapter != ATI_ADAPTER_MACH32)
+ xf86Msg(X_WARNING,
+ ATI_NAME ": PCI Mach32 in slot %d:%d:%d"
+ " could only be detected as an %s!\n",
+ pVideo->bus, pVideo->device, pVideo->func,
+ ATIAdapterNames[pATI->Adapter]);
+
+ AddAdapter(pATI);
+ pATI->SharedAccelerator = TRUE;
+
+ if ((pATI->VGAAdapter != ATI_ADAPTER_NONE) ||
+ (pATI->Coprocessor != ATI_CHIP_NONE))
+ ATIFindVGA(pVideo, &pVGA, &pATI, p8514,
+ ProbeFlags);
+ }
+
+ xf86SetPciVideo(NULL, NONE);
+ break;
+ }
+ }
+
+ /* Next, look for sparse I/O Mach64's */
+ for (i = 0; (pVideo = xf86PciVideoInfo[i++]); )
+ {
+ if ((pVideo->vendor != PCI_VENDOR_ATI) ||
+ (pVideo->chipType == PCI_CHIP_MACH32) ||
+ pVideo->size[1])
+ continue;
+
+ pPCI = pVideo->thisCard;
+ PciReg = pciReadLong(pPCI->tag, PCI_REG_USERCONFIG);
+ j = PciReg & 0x03U;
+ if (j == 0x03U)
+ xf86Msg(X_WARNING,
+ ATI_NAME ": PCI Mach64 in slot %d:%d:%d cannot be"
+ " enabled\n because it has neither a block, nor a"
+ " sparse, I/O base.\n",
+ pVideo->bus, pVideo->device, pVideo->func);
+ else switch(ATICheckSparseIOBases(pVideo, ProbeFlags,
+ Mach64SparseIOBases[j], 4, TRUE))
+ {
+ case 0:
+ xf86Msg(X_WARNING,
+ ATI_NAME ": PCI Mach64 in slot %d:%d:%d will not"
+ " be enabled\n because it conflicts with another"
+ " non-video PCI device.\n",
+ pVideo->bus, pVideo->device, pVideo->func);
+ break;
+
+ case Detected8514A:
+ xf86Msg(X_WARNING,
+ ATI_NAME ": PCI Mach64 in slot %d:%d:%d will not"
+ " be enabled\n because it conflicts with an %s.\n",
+ pVideo->bus, pVideo->device, pVideo->func,
+ ATIAdapterNames[p8514->Adapter]);
+ break;
+
+ case DetectedMach64:
+ pATI = pMach64[j];
+ if ((pATI->BusType >= ATI_BUS_PCI) && !pATI->PCIInfo)
+ pATI->PCIInfo = pVideo;
+ else
+ xf86Msg(X_WARNING,
+ ATI_NAME ": PCI Mach64 in slot %d:%d:%d will"
+ " not be enabled\n because it conflicts with"
+ " another %s Mach64 at sparse I/O base"
+ " 0x%04X.\n",
+ pVideo->bus, pVideo->device, pVideo->func,
+ ATIBusNames[pATI->BusType],
+ Mach64SparseIOBases[j]);
+ break;
+
+ default: /* Must be DoProbe */
+ if (!xf86CheckPciSlot(pVideo->bus,
+ pVideo->device,
+ pVideo->func))
+ continue;
+
+ /* Possibly fix block I/O indicator */
+ if (PciReg & 0x00000004U)
+ pciWriteLong(pPCI->tag, PCI_REG_USERCONFIG,
+ PciReg & ~0x00000004U);
+
+ xf86SetPciVideo(pVideo, MEM_IO);
+
+ Chip = ATIChipID(pVideo->chipType, pVideo->chipRev);
+ pATI = ATIMach64Probe(pVideo, Mach64SparseIOBases[j],
+ SPARSE_IO, Chip);
+ if (!pATI)
+ xf86Msg(X_WARNING,
+ ATI_NAME ": PCI Mach64 in slot %d:%d:%d could"
+ " not be detected!\n",
+ pVideo->bus, pVideo->device, pVideo->func);
+ else
+ {
+ sprintf(Identifier,
+ "Shared PCI Mach64 in slot %d:%d:%d",
+ pVideo->bus, pVideo->device, pVideo->func);
+ xf86MsgVerb(X_INFO, 3,
+ ATI_NAME ": %s with sparse PIO base 0x%04X"
+ " detected.\n", Identifier,
+ Mach64SparseIOBases[j]);
+ AddAdapter(pATI);
+ pATI->SharedAccelerator = TRUE;
+ pATI->PCIInfo = pVideo;
+
+ if (pATI->VGAAdapter != ATI_ADAPTER_NONE)
+ ATIFindVGA(pVideo, &pVGA, &pATI, p8514,
+ ProbeFlags);
+ }
+
+ xf86SetPciVideo(NULL, NONE);
+ break;
+ }
+ }
+
+#else /* AVOID_CPIO */
+
+ for (i = 0; (pVideo = xf86PciVideoInfo[i++]); )
+ {
+ if ((pVideo->vendor != PCI_VENDOR_ATI) ||
+ (pVideo->chipType == PCI_CHIP_MACH32) ||
+ pVideo->size[1])
+ continue;
+
+ /* Check if this one has already been detected */
+ for (j = 0; j < nATIPtr; j++)
+ {
+ pATI = ATIPtrs[j];
+ if (pATI->PCIInfo == pVideo)
+ goto SkipThisSlot;
+ }
+
+ if (!xf86CheckPciSlot(pVideo->bus,
+ pVideo->device,
+ pVideo->func))
+ continue;
+
+ xf86SetPciVideo(pVideo, MEM_IO);
+
+ Chip = ATIChipID(pVideo->chipType, pVideo->chipRev);
+
+ /* The adapter's CPIO base is of little concern here */
+ pATI = ATIMach64Probe(pVideo, 0, SPARSE_IO, Chip);
+ if (pATI)
+ {
+ sprintf(Identifier, "Shared PCI Mach64 in slot %d:%d:%d",
+ pVideo->bus, pVideo->device, pVideo->func);
+ xf86MsgVerb(X_INFO, 3,
+ ATI_NAME ": %s with Block 0 base 0x%08X detected.\n",
+ Identifier, pATI->Block0Base);
+ AddAdapter(pATI);
+ pATI->SharedAccelerator = TRUE;
+ pATI->PCIInfo = pVideo;
+ }
+ else
+ {
+ xf86Msg(X_WARNING,
+ ATI_NAME ": PCI Mach64 in slot %d:%d:%d could not be"
+ " detected!\n",
+ pVideo->bus, pVideo->device, pVideo->func);
+ }
+
+ xf86SetPciVideo(NULL, NONE);
+
+ SkipThisSlot:;
+ }
+
+#endif /* AVOID_CPIO */
+
+ }
+
+ /* Lastly, look for block I/O devices */
+ for (i = 0; (pVideo = xf86PciVideoInfo[i++]); )
+ {
+ if ((pVideo->vendor != PCI_VENDOR_ATI) ||
+ (pVideo->chipType == PCI_CHIP_MACH32) ||
+ !pVideo->size[1])
+ continue;
+
+ /* Check for Rage128's, Radeon's and later adapters */
+ Chip = ATIChipID(pVideo->chipType, pVideo->chipRev);
+ if (Chip > ATI_CHIP_Mach64)
+ {
+ switch (Chip)
+ {
+ case ATI_CHIP_RAGE128GL:
+ case ATI_CHIP_RAGE128VR:
+ case ATI_CHIP_RAGE128PROULTRA:
+ case ATI_CHIP_RAGE128PROGL:
+ case ATI_CHIP_RAGE128PROVR:
+ case ATI_CHIP_RAGE128MOBILITY3:
+ case ATI_CHIP_RAGE128MOBILITY4:
+ DoRage128 = TRUE;
+ continue;
+
+ case ATI_CHIP_RADEON:
+ case ATI_CHIP_RADEONVE:
+ case ATI_CHIP_RADEONMOBILITY6:
+ case ATI_CHIP_RADEONMOBILITY7:
+ case ATI_CHIP_R200:
+ case ATI_CHIP_RV200:
+ case ATI_CHIP_RV250:
+ case ATI_CHIP_RADEONMOBILITY9:
+ case ATI_CHIP_R300:
+ DoRadeon = TRUE;
+ continue;
+
+ case ATI_CHIP_HDTV:
+ default:
+ continue;
+ }
+ }
+
+ if (!nATIGDev)
+ continue;
+
+ /* Check if this one has already been detected */
+ for (j = 0; j < nATIPtr; j++)
+ {
+ pATI = ATIPtrs[j];
+ if (pATI->CPIOBase == pVideo->ioBase[1])
+ goto SetPCIInfo;
+ }
+
+ if (!xf86CheckPciSlot(pVideo->bus, pVideo->device, pVideo->func))
+ continue;
+
+ /* Probe for it */
+ xf86SetPciVideo(pVideo, MEM_IO);
+
+ pATI = ATIMach64Probe(pVideo, pVideo->ioBase[1], BLOCK_IO, Chip);
+ if (pATI)
+ {
+ sprintf(Identifier, "Shared PCI/AGP Mach64 in slot %d:%d:%d",
+ pVideo->bus, pVideo->device, pVideo->func);
+ xf86MsgVerb(X_INFO, 3, ATI_NAME ": %s detected.\n",
+ Identifier);
+ AddAdapter(pATI);
+ pATI->SharedAccelerator = TRUE;
+
+#ifndef AVOID_CPIO
+
+ if (pATI->VGAAdapter != ATI_ADAPTER_NONE)
+ ATIFindVGA(pVideo, &pVGA, &pATI, p8514, ProbeFlags);
+
+#endif /* AVOID_CPIO */
+
+ }
+
+ xf86SetPciVideo(NULL, NONE);
+
+ if (!pATI)
+ {
+ xf86Msg(X_WARNING,
+ ATI_NAME ": PCI/AGP Mach64 in slot %d:%d:%d could not be"
+ " detected!\n", pVideo->bus, pVideo->device, pVideo->func);
+ continue;
+ }
+
+ SetPCIInfo:
+ pATI->PCIInfo = pVideo;
+ }
+ }
+
+#ifndef AVOID_CPIO
+
+ /*
+ * At this point, if there's a non-shareable VGA with its own framebuffer,
+ * find out if it's an ATI VGA Wonder.
+ */
+ do
+ {
+ if (!nATIGDev || !pVGA || (pVGA->VGAAdapter > ATI_ADAPTER_VGA))
+ break;
+
+ /* If it has not been assigned to a coprocessor, keep track of it */
+ if (pVGA->Coprocessor == ATI_CHIP_NONE)
+ AddAdapter(pVGA);
+
+ /*
+ * A VGA should have installed its int 10 vector. Use that to find the
+ * VGA BIOS. If this fails, scan all legacy BIOS segments, in 512-byte
+ * increments.
+ */
+ if (xf86ReadBIOS(0U, 0x42U, BIOS, 2) != 2)
+ goto NoVGAWonder;
+
+ pATI = NULL;
+ BIOSBase = 0;
+ if (!(BIOS[0] & 0x1FU)) /* Otherwise there's no 512-byte alignment */
+ BIOSBase = ((BIOS[1] << 8) | BIOS[0]) << 4;
+
+ /* Look for its BIOS */
+ for(; ; BIOSBase += 0x00000200U)
+ {
+ if (!BIOSBase)
+ goto SkipBiosSegment;
+
+ if (BIOSBase >= 0x000F8000U)
+ goto NoVGAWonder;
+
+ /* Skip over those that are already known */
+ for (i = 0; i < nATIPtr; i++)
+ if (ATIPtrs[i]->BIOSBase == BIOSBase)
+ goto SkipBiosSegment;
+
+ /* Get first 80 bytes of video BIOS */
+ if (xf86ReadBIOS(BIOSBase, 0, BIOS, SizeOf(BIOS)) !=
+ SizeOf(BIOS))
+ goto NoVGAWonder;
+
+ if ((BIOS[0x00U] != 0x55U) || (BIOS[0x01U] != 0xAAU))
+ goto SkipBiosSegment;
+
+ if ((BIOS[0x1EU] == 'I') &&
+ (BIOS[0x1FU] == 'B') &&
+ (BIOS[0x20U] == 'M'))
+ break;
+
+ /* XXX Should PCI BIOS signature be checked for here ? */
+ if ((BIOS[0x20U] == 'P') &&
+ (BIOS[0x21U] == 'C') &&
+ (BIOS[0x22U] == 'I'))
+ break;
+
+ SkipBiosSegment:
+ if (pATI)
+ continue;
+
+ pATI = pVGA;
+ BIOSBase = 0x000C0000U - 0x00000200U;
+ }
+
+ pVGA->BIOSBase = BIOSBase;
+
+ /* Look for the ATI signature string */
+ if (memcmp(BIOS + BIOSSignature, ATISignature, SignatureSize))
+ break;
+
+ if (BIOS[0x40U] != '3')
+ break;
+
+ switch (BIOS[0x41U])
+ {
+ case '1':
+ /* This is a Mach8 or VGA Wonder adapter of some kind */
+ if ((BIOS[0x43U] >= '1') && (BIOS[0x43U] <= '6'))
+ pVGA->Chip = BIOS[0x43U] - ('1' - ATI_CHIP_18800);
+
+ switch (BIOS[0x43U])
+ {
+ case '1': /* ATI_CHIP_18800 */
+ pVGA->VGAOffset = 0xB0U;
+ pVGA->VGAAdapter = ATI_ADAPTER_V3;
+ break;
+
+ case '2': /* ATI_CHIP_18800_1 */
+ pVGA->VGAOffset = 0xB0U;
+ if (BIOS[0x42U] & 0x10U)
+ pVGA->VGAAdapter = ATI_ADAPTER_V5;
+ else
+ pVGA->VGAAdapter = ATI_ADAPTER_V4;
+ break;
+
+ case '3': /* ATI_CHIP_28800_2 */
+ case '4': /* ATI_CHIP_28800_4 */
+ case '5': /* ATI_CHIP_28800_5 */
+ case '6': /* ATI_CHIP_28800_6 */
+ pVGA->VGAOffset = 0xA0U;
+ if (BIOS[0x44U] & 0x80U)
+ pVGA->VGAAdapter = ATI_ADAPTER_XL;
+ else
+ pVGA->VGAAdapter = ATI_ADAPTER_PLUS;
+ break;
+
+ case 'a': /* A crippled Mach32 */
+ case 'b':
+ case 'c':
+ pVGA->VGAOffset = 0x80U;
+ pVGA->VGAAdapter = ATI_ADAPTER_NONISA;
+ ATIMach32ChipID(pVGA);
+ ProbeWaitIdleEmpty();
+ if (inw(SUBSYS_STAT) != (CARD16)(-1))
+ pVGA->ChipHasSUBSYS_CNTL = TRUE;
+ break;
+#if 0
+ case ' ': /* A crippled Mach64 */
+ pVGA->VGAOffset = 0x80U;
+ pVGA->VGAAdapter = ATI_ADAPTER_NONISA;
+ ATIMach64ChipID(pVGA, 0);
+ break;
+#endif
+ default:
+ break;
+ }
+
+ if (pVGA->VGAAdapter == ATI_ADAPTER_NONE)
+ break;
+
+ /* Set VGA Wonder I/O port */
+ pVGA->CPIO_VGAWonder = BIOSWord(0x10U) & SPARSE_IO_PORT;
+ if (!pVGA->CPIO_VGAWonder)
+ pVGA->CPIO_VGAWonder = 0x01CEU;
+
+ ATIVGAWonderProbe(NULL, pVGA, p8514, ProbeFlags);
+ break;
+#if 0
+ case '2':
+ pVGA->VGAOffset = 0xB0U; /* Presumably */
+ pVGA->VGAAdapter = ATI_ADAPTER_EGA_PLUS;
+ break;
+
+ case '3':
+ pVGA->VGAOffset = 0xB0U; /* Presumably */
+ pVGA->VGAAdapter = ATI_ADAPTER_BASIC;
+ break;
+
+ case '?': /* A crippled Mach64 */
+ pVGA->VGAAdapter = ATI_ADAPTER_NONISA;
+ ATIMach64ChipID(pVGA, 0);
+ break;
+#endif
+ default:
+ break;
+ }
+
+ if (pVGA->Adapter <= ATI_ADAPTER_VGA)
+ pVGA->Adapter = pVGA->VGAAdapter;
+
+NoVGAWonder:;
+ } while (0);
+
+#endif /* AVOID_CPIO */
+
+ /*
+ * Re-order list of detected devices so that the primary device is before
+ * any other PCI device.
+ */
+ for (i = 0; i < nATIPtr; i++)
+ {
+ if (!ATIPtrs[i]->PCIInfo)
+ continue;
+
+ for (j = i; j < nATIPtr; j++)
+ {
+ pATI = ATIPtrs[j];
+ if (!xf86IsPrimaryPci(pATI->PCIInfo))
+ continue;
+
+ for (; j > i; j--)
+ ATIPtrs[j] = ATIPtrs[j - 1];
+ ATIPtrs[j] = pATI;
+ break;
+ }
+
+ break;
+ }
+
+ if (flags & PROBE_DETECT)
+ {
+ /*
+ * No XF86Config information available, so use the default Chipset of
+ * "ati", and as many device sections as there are adapters.
+ */
+ for (i = 0; i < nATIPtr; i++)
+ {
+ pATI = ATIPtrs[i];
+
+#ifndef AVOID_CPIO
+
+ if ((pATI->Adapter != ATI_ADAPTER_VGA) &&
+ ((pATI->Adapter != ATI_ADAPTER_8514A) ||
+ ((pATI->VGAAdapter != ATI_ADAPTER_VGA) &&
+ (pATI->VGAAdapter != ATI_ADAPTER_NONE))))
+
+#endif /* AVOID_CPIO */
+
+ {
+ ProbeSuccess = TRUE;
+ pGDev = xf86AddDeviceToConfigure(ATI_DRIVER_NAME,
+ pATI->PCIInfo, ATI_CHIPSET_ATI);
+ if (pGDev)
+ {
+ /* Fill in additional information */
+ pGDev->vendor = ATI_NAME;
+ pGDev->chipset = (char *)ATIChipsetNames[ATI_CHIPSET_ATI];
+ if (!pATI->PCIInfo)
+ pGDev->busID = NULL;
+ }
+ }
+
+ xfree(pATI);
+ }
+ }
+ else
+ {
+ /*
+ * Assign detected devices to XF86Config Device sections. This is done
+ * by comparing certain Device section specifications against the
+ * corresponding adapter information. Begin with those specifications
+ * that are independent of the adapter's bus location.
+ */
+ for (i = 0, pATIGDev = ATIGDevs; i < nATIGDev; i++, pATIGDev++)
+ {
+ pGDev = pATIGDev->pGDev;
+
+ for (j = 0; j < nATIPtr; j++)
+ {
+ pATI = ATIPtrs[j];
+
+ /*
+ * First check the Chipset specification. The placement of
+ * "break" and "continue" statements here is carefully chosen
+ * to produce the intended behaviour for each Chipset value.
+ */
+ switch (pATIGDev->Chipset)
+ {
+ case ATI_CHIPSET_ATI:
+
+#ifndef AVOID_CPIO
+
+ if (pATI->Adapter == ATI_ADAPTER_VGA)
+ continue;
+ if (pATI->Adapter != ATI_ADAPTER_8514A)
+ break;
+ /* Fall through */
+
+ case ATI_CHIPSET_ATIVGA:
+ if (pATI->VGAAdapter == ATI_ADAPTER_VGA)
+ continue;
+ /* Fall through */
+
+ case ATI_CHIPSET_IBMVGA:
+ if (pATI->VGAAdapter == ATI_ADAPTER_NONE)
+ continue;
+ break;
+
+ case ATI_CHIPSET_VGAWONDER:
+ if (!pATI->CPIO_VGAWonder)
+ continue;
+ break;
+
+ case ATI_CHIPSET_IBM8514:
+ if (pATI->Adapter == ATI_ADAPTER_8514A)
+ break;
+ /* Fall through */
+
+ case ATI_CHIPSET_MACH8:
+ if (pATI->Adapter == ATI_ADAPTER_MACH8)
+ break;
+ /* Fall through */
+
+ case ATI_CHIPSET_MACH32:
+ if (pATI->Adapter == ATI_ADAPTER_MACH32)
+ break;
+ continue;
+
+#endif /* AVOID_CPIO */
+
+ case ATI_CHIPSET_MACH64:
+ if (pATI->Adapter == ATI_ADAPTER_MACH64)
+ break;
+ continue;
+
+ default:
+ continue;
+ }
+
+ /*
+ * The ChipID and ChipRev specifications are compared next.
+ * First, require these to be unspecified for anything other
+ * than Mach32 or Mach64 adapters. ChipRev is also required to
+ * be unspecified for Mach32's. ChipID is optional for
+ * Mach32's, and both specifications are optional for Mach64's.
+ * Lastly, allow both specifications to override their detected
+ * value in the case of Mach64 adapters whose ChipID is
+ * unrecognised.
+ */
+ pVideo = pATI->PCIInfo;
+ if (pGDev->chipID >= 0)
+ {
+ if ((pATI->ChipType != pGDev->chipID) &&
+ (!pVideo || (pGDev->chipID != pVideo->chipType)))
+ {
+ if ((pATI->Adapter != ATI_ADAPTER_MACH64) ||
+ (pATI->Chip != ATI_CHIP_Mach64))
+ continue;
+
+ Chip = ATIChipID(pGDev->chipID, 0);
+ if ((Chip <= ATI_CHIP_264GTB) ||
+ (Chip == ATI_CHIP_Mach64))
+ continue;
+ }
+ if ((pGDev->chipRev >= 0) &&
+ (pATI->ChipRev != pGDev->chipRev) &&
+ (!pVideo || (pGDev->chipRev != pVideo->chipRev) ||
+ (pGDev->chipID != pVideo->chipType)))
+ {
+ if (pATI->Chip < ATI_CHIP_264CT)
+ continue;
+
+ if (pATI->Chip != ATI_CHIP_Mach64)
+ {
+ /*
+ * There are two foundry codes for UMC. Some
+ * adapters will advertise one in CONFIG_CHIP_ID
+ * and the other in PCI configuration space. For
+ * matching purposes, make both codes compare
+ * equal.
+ */
+# define UMC_IGNORE \
+ (ATI_FOUNDRY_UMC ^ ATI_FOUNDRY_UMCA)
+# define UMC_NOCARE \
+ GetBits(SetBits(UMC_IGNORE, CFG_CHIP_FOUNDRY), \
+ CFG_CHIP_REV)
+
+ if ((pATI->ChipRev ^ pGDev->chipRev) & ~UMC_NOCARE)
+ continue;
+
+ if ((pATI->ChipFoundry != ATI_FOUNDRY_UMC) &&
+ (pATI->ChipFoundry != ATI_FOUNDRY_UMCA))
+ continue;
+
+ k = GetBits(pGDev->chipRev,
+ GetBits(CFG_CHIP_FOUNDRY, CFG_CHIP_REV));
+ if ((k != ATI_FOUNDRY_UMC) &&
+ (k != ATI_FOUNDRY_UMCA))
+ continue;
+ }
+ }
+ }
+
+ /*
+ * IOBase is next. This is the first specification that is
+ * potentially dependent on bus location. It is only allowed
+ * for Mach64 adapters, and is optional.
+ */
+ if (pGDev->IOBase && (pATI->CPIOBase != pGDev->IOBase))
+ continue;
+
+ /*
+ * Compare BusID's. This specification is only allowed for PCI
+ * Mach32's or Mach64's and is optional.
+ */
+ if (pGDev->busID && pGDev->busID[0])
+ {
+ pVideo = pATI->PCIInfo;
+
+#ifndef AVOID_CPIO
+
+ if (!pVideo)
+ continue;
+
+#endif /* AVOID_CPIO */
+
+ if (!xf86ComparePciBusString(pGDev->busID,
+ pVideo->bus, pVideo->device, pVideo->func))
+ continue;
+ }
+
+ /*
+ * Ensure no two adapters are assigned to the same XF86Config
+ * Device section.
+ */
+ if (pATIGDev->iATIPtr)
+ {
+ if (pATIGDev->iATIPtr < 0)
+ break;
+
+ xf86Msg(X_ERROR,
+ ATI_NAME ": XF86Config Device section \"%s\" may not"
+ " be assigned to more than one adapter.\n",
+ pGDev->identifier);
+ pATIGDev->iATIPtr = -1;
+ break;
+ }
+
+ /* Assign adapter */
+ pATIGDev->iATIPtr = j + 1;
+
+ /*
+ * For compatibility with previous releases, assign the first
+ * applicable adapter if there is only one Device section.
+ */
+ if (nATIGDev == 1)
+ break;
+ }
+ }
+
+ /*
+ * Ensure no two XF86Config Device sections are assigned to the same
+ * adapter. Then, generate screens for any that are left.
+ */
+ for (i = 0, pATIGDev = ATIGDevs; i < nATIGDev; i++, pATIGDev++)
+ {
+ pGDev = pATIGDev->pGDev;
+
+ j = pATIGDev->iATIPtr;
+ if (j <= 0)
+ continue;
+
+ for (k = i; ++k < nATIGDev; )
+ {
+ if (j == ATIGDevs[k].iATIPtr)
+ {
+ xf86Msg(X_ERROR,
+ ATI_NAME ": XF86Config Device sections \"%s\" and"
+ " \"%s\" may not be assigned to the same adapter.\n",
+ pGDev->identifier, ATIGDevs[k].pGDev->identifier);
+ pATIGDev->iATIPtr = ATIGDevs[k].iATIPtr = -1;
+ }
+ }
+
+ j = ATIGDevs[i].iATIPtr;
+ if (j <= 0)
+ continue;
+
+ pATI = ATIPtrs[j - 1];
+
+ xf86MsgVerb(X_INFO, 3,
+ ATI_NAME ": %s assigned to %sactive \"Device\" section"
+ " \"%s\".\n",
+ Identifier, pGDev->active ? "" : "in", pGDev->identifier);
+
+ /*
+ * Attach adapter to XF86Config Device section and register its
+ * resources.
+ */
+ if (ATIClaimBusSlot(pDriver, pATIGDev->Chipset,
+ pGDev, pGDev->active, pATI) < 0)
+ {
+ xf86Msg(X_ERROR,
+ ATI_NAME ": Could not claim bus slot for %s.\n",
+ Identifier);
+ continue;
+ }
+
+ if (!pGDev->active)
+ continue;
+
+ /* Allocate screen */
+ pScreenInfo = xf86AllocateScreen(pDriver, 0);
+
+#ifdef XFree86LOADER
+
+ if (!xf86LoadSubModule(pScreenInfo, "atimisc"))
+ {
+ xf86Msg(X_ERROR,
+ ATI_NAME ": Failed to load \"atimisc\" module.\n");
+ xf86DeleteScreen(pScreenInfo->scrnIndex, 0);
+ continue;
+ }
+
+ xf86LoaderReqSymLists(ATISymbols, NULL);
+
+#endif
+
+ /* Attach device to screen */
+ xf86AddEntityToScreen(pScreenInfo, pATI->iEntity);
+
+ ATIPtrs[j - 1] = NULL;
+
+ /* Fill in probe data */
+ pScreenInfo->driverVersion = ATI_VERSION_CURRENT;
+ pScreenInfo->driverName = ATI_DRIVER_NAME;
+ pScreenInfo->name = ATI_NAME;
+ pScreenInfo->Probe = ATIProbe;
+ pScreenInfo->PreInit = ATIPreInit;
+ pScreenInfo->ScreenInit = ATIScreenInit;
+ pScreenInfo->SwitchMode = ATISwitchMode;
+ pScreenInfo->AdjustFrame = ATIAdjustFrame;
+ pScreenInfo->EnterVT = ATIEnterVT;
+ pScreenInfo->LeaveVT = ATILeaveVT;
+ pScreenInfo->FreeScreen = ATIFreeScreen;
+ pScreenInfo->ValidMode = ATIValidMode;
+
+ pScreenInfo->driverPrivate = pATI;
+
+ pATI->Chipset = pATIGDev->Chipset;
+
+ ProbeSuccess = TRUE;
+ }
+
+ /* Deal with unassigned adapters */
+ for (i = 0; i < nATIPtr; i++)
+ {
+ if (!(pATI = ATIPtrs[i]))
+ continue;
+
+#ifndef AVOID_CPIO
+
+ if (pATI->Adapter > ATI_ADAPTER_VGA)
+
+#endif /* AVOID_CPIO */
+
+ {
+ if (pATI->iEntity < 0)
+ (void)ATIClaimBusSlot(pDriver, 0, NULL, FALSE, pATI);
+ }
+
+ xfree(pATI);
+ }
+
+ xfree(ATIGDevs);
+ }
+
+ xfree(ATIPtrs);
+
+ /* Call Rage 128 driver probe */
+ if (DoRage128 && R128Probe(pDriver, flags))
+ ProbeSuccess = TRUE;
+
+ /* Call Radeon driver probe */
+ if (DoRadeon && RADEONProbe(pDriver, flags))
+ ProbeSuccess = TRUE;
+
+ return ProbeSuccess;
+}