summaryrefslogtreecommitdiff
path: root/src/apm_driver.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/apm_driver.c')
-rw-r--r--src/apm_driver.c2371
1 files changed, 2371 insertions, 0 deletions
diff --git a/src/apm_driver.c b/src/apm_driver.c
new file mode 100644
index 0000000..dd877d3
--- /dev/null
+++ b/src/apm_driver.c
@@ -0,0 +1,2371 @@
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/apm/apm_driver.c,v 1.61 2002/10/16 21:13:46 dawes Exp $ */
+
+#include "apm.h"
+#include "xf86cmap.h"
+#include "shadowfb.h"
+#include "xf86Resources.h"
+#include "xf86int10.h"
+#include "xf86RAC.h"
+#include "vbe.h"
+
+#include "opaque.h"
+#define DPMS_SERVER
+#include "extensions/dpms.h"
+
+#define VERSION 4000
+#define APM_NAME "APM"
+#define APM_DRIVER_NAME "apm"
+#define APM_MAJOR_VERSION 1
+#define APM_MINOR_VERSION 0
+#define APM_PATCHLEVEL 0
+#ifndef PCI_CHIP_AT3D
+#define PCI_CHIP_AT3D 0x643D
+#endif
+
+/* bytes to save for text/font data */
+#define TEXT_AMOUNT 32768
+
+/* Mandatory functions */
+static const OptionInfoRec * ApmAvailableOptions(int chipid, int busid);
+static void ApmIdentify(int flags);
+static Bool ApmProbe(DriverPtr drv, int flags);
+static Bool ApmPreInit(ScrnInfoPtr pScrn, int flags);
+static Bool ApmScreenInit(int Index, ScreenPtr pScreen, int argc,
+ char **argv);
+static Bool ApmEnterVT(int scrnIndex, int flags);
+static void ApmLeaveVT(int scrnIndex, int flags);
+static Bool ApmCloseScreen(int scrnIndex, ScreenPtr pScreen);
+static void ApmFreeScreen(int scrnIndex, int flags);
+static int ApmValidMode(int scrnIndex, DisplayModePtr mode,
+ Bool verbose, int flags);
+static Bool ApmSaveScreen(ScreenPtr pScreen, int mode);
+static void ApmUnlock(ApmPtr pApm);
+static void ApmLock(ApmPtr pApm);
+static void ApmRestore(ScrnInfoPtr pScrn, vgaRegPtr vgaReg,
+ ApmRegPtr ApmReg);
+static void ApmLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices,
+ LOCO *colors, VisualPtr pVisual);
+static void ApmDisplayPowerManagementSet(ScrnInfoPtr pScrn,
+ int PowerManagementMode,
+ int flags);
+static void ApmProbeDDC(ScrnInfoPtr pScrn, int index);
+
+
+int ApmPixmapIndex = -1;
+static unsigned long ApmGeneration = 0;
+
+DriverRec APM = {
+ VERSION,
+ APM_DRIVER_NAME,
+ ApmIdentify,
+ ApmProbe,
+ ApmAvailableOptions,
+ NULL,
+ 0
+};
+
+static SymTabRec ApmChipsets[] = {
+ { AP6422, "AP6422" },
+ { AT24, "AT24" },
+ { AT3D, "AT3D" },
+ { -1, NULL }
+};
+
+static PciChipsets ApmPciChipsets[] = {
+ { PCI_CHIP_AP6422, PCI_CHIP_AP6422, RES_SHARED_VGA },
+ { PCI_CHIP_AT24, PCI_CHIP_AT24, RES_SHARED_VGA },
+ { PCI_CHIP_AT3D, PCI_CHIP_AT3D, RES_SHARED_VGA },
+ { -1, -1, RES_UNDEFINED }
+};
+
+static IsaChipsets ApmIsaChipsets[] = {
+ { PCI_CHIP_AP6422, RES_EXCLUSIVE_VGA},
+ {-1, RES_UNDEFINED}
+};
+
+typedef enum {
+ OPTION_SET_MCLK,
+ OPTION_SW_CURSOR,
+ OPTION_HW_CURSOR,
+ OPTION_NOLINEAR,
+ OPTION_NOACCEL,
+ OPTION_SHADOW_FB,
+ OPTION_PCI_BURST,
+ OPTION_REMAP_DPMS_ON,
+ OPTION_REMAP_DPMS_STANDBY,
+ OPTION_REMAP_DPMS_SUSPEND,
+ OPTION_REMAP_DPMS_OFF,
+ OPTION_PCI_RETRY
+} ApmOpts;
+
+static const OptionInfoRec ApmOptions[] =
+{
+ {OPTION_SET_MCLK, "SetMclk", OPTV_FREQ,
+ {0}, FALSE},
+ {OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN,
+ {0}, FALSE},
+ {OPTION_HW_CURSOR, "HWcursor", OPTV_BOOLEAN,
+ {0}, TRUE},
+ {OPTION_NOLINEAR, "NoLinear", OPTV_BOOLEAN,
+ {0}, FALSE},
+ {OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN,
+ {0}, FALSE},
+ {OPTION_SHADOW_FB, "ShadowFB", OPTV_BOOLEAN,
+ {0}, FALSE},
+ {OPTION_PCI_BURST, "pci_burst", OPTV_BOOLEAN,
+ {0}, FALSE},
+ {OPTION_REMAP_DPMS_ON, "Remap_DPMS_On", OPTV_ANYSTR,
+ {0}, FALSE},
+ {OPTION_REMAP_DPMS_STANDBY, "Remap_DPMS_Standby", OPTV_ANYSTR,
+ {0}, FALSE},
+ {OPTION_REMAP_DPMS_SUSPEND, "Remap_DPMS_Suspend", OPTV_ANYSTR,
+ {0}, FALSE},
+ {OPTION_REMAP_DPMS_OFF, "Remap_DPMS_Off", OPTV_ANYSTR,
+ {0}, FALSE},
+ {OPTION_PCI_RETRY, "PciRetry", OPTV_BOOLEAN,
+ {0}, FALSE},
+ {-1, NULL, OPTV_NONE,
+ {0}, FALSE}
+};
+
+/*
+ * List of symbols from other modules that this module references. This
+ * list is used to tell the loader that it is OK for symbols here to be
+ * unresolved providing that it hasn't been told that they haven't been
+ * told that they are essential via a call to xf86LoaderReqSymbols() or
+ * xf86LoaderReqSymLists(). The purpose is this is to avoid warnings about
+ * unresolved symbols that are not required.
+ */
+
+static const char *vgahwSymbols[] = {
+ "vgaHWBlankScreen",
+ "vgaHWCursor",
+ "vgaHWFreeHWRec",
+ "vgaHWGetHWRec",
+ "vgaHWGetIOBase",
+ "vgaHWInit",
+ "vgaHWLock",
+ "vgaHWMapMem",
+ "vgaHWProtect",
+ "vgaHWRestore",
+ "vgaHWSave",
+ "vgaHWSetMmioFuncs",
+ "vgaHWUnlock",
+ NULL
+};
+
+static const char *xaaSymbols[] = {
+ "XAACreateInfoRec",
+ "XAACursorInfoRec",
+ "XAACursorInit",
+ "XAADestroyInfoRec",
+ "XAAGlyphScanlineFuncLSBFirst",
+ "XAAInit",
+ "XAAQueryBestSize",
+ "XAAReverseBitOrder",
+ "XAARestoreCursor",
+ "XAAScreenIndex",
+ "XAAStippleScanlineFuncMSBFirst",
+ "XAAWarpCursor",
+ NULL
+};
+
+static const char *ramdacSymbols[] = {
+ "xf86CreateCursorInfoRec",
+ "xf86DestroyCursorInfoRec",
+ "xf86InitCursor",
+ NULL
+};
+
+static const char *vbeSymbols[] = {
+ "VBEInit",
+ "vbeDoEDID",
+ "vbeFree",
+ NULL
+};
+
+static const char *ddcSymbols[] = {
+ "xf86DoEDID_DDC1",
+ "xf86DoEDID_DDC2",
+ "xf86PrintEDID",
+ NULL
+};
+
+static const char *i2cSymbols[] = {
+ "xf86CreateI2CBusRec",
+ "xf86I2CBusInit",
+ NULL
+};
+
+static const char *shadowSymbols[] = {
+ "ShadowFBInit",
+ NULL
+};
+
+static const char *miscfbSymbols[] = {
+ "xf1bppScreenInit",
+ "xf4bppScreenInit",
+ NULL
+};
+
+static const char *fbSymbols[] = {
+ "fbPictureInit",
+ "fbScreenInit",
+ NULL
+};
+
+static const char *int10Symbols[] = {
+ "xf86Free10",
+ "xf86InitInt10",
+ NULL
+};
+
+#ifdef XFree86LOADER
+
+static XF86ModuleVersionInfo apmVersRec = {
+ "apm",
+ MODULEVENDORSTRING,
+ MODINFOSTRING1,
+ MODINFOSTRING2,
+ XF86_VERSION_CURRENT,
+ APM_MAJOR_VERSION, APM_MINOR_VERSION, APM_PATCHLEVEL,
+ ABI_CLASS_VIDEODRV, /* This is a video driver */
+ ABI_VIDEODRV_VERSION,
+ MOD_CLASS_VIDEODRV,
+ {0,0,0,0}
+};
+
+static MODULESETUPPROTO(apmSetup);
+
+/*
+ * This is the module init data.
+ * Its name has to be the driver name followed by ModuleData.
+ */
+XF86ModuleData apmModuleData = { &apmVersRec, apmSetup, NULL };
+
+static pointer
+apmSetup(pointer module, pointer opts, int *errmaj, int *errmain)
+{
+ static Bool setupDone = FALSE;
+
+ if (!setupDone) {
+ setupDone = TRUE;
+ xf86AddDriver(&APM, module, 0);
+
+ LoaderRefSymLists(vgahwSymbols, fbSymbols, xaaSymbols,
+ miscfbSymbols, ramdacSymbols, vbeSymbols,
+ ddcSymbols, i2cSymbols, shadowSymbols,
+ int10Symbols, NULL);
+
+ return (pointer)1;
+ }
+ else {
+ if (errmaj) *errmaj = LDR_ONCEONLY;
+ return NULL;
+ }
+}
+#endif
+
+static Bool
+ApmGetRec(ScrnInfoPtr pScrn)
+{
+ if (pScrn->driverPrivate)
+ return TRUE;
+ pScrn->driverPrivate = xnfcalloc(sizeof(ApmRec), 1);
+ /* pScrn->driverPrivate != NULL at this point */
+
+ return TRUE;
+}
+
+static void
+ApmFreeRec(ScrnInfoPtr pScrn)
+{
+ if (pScrn->driverPrivate) {
+ xfree(pScrn->driverPrivate);
+ pScrn->driverPrivate = NULL;
+ }
+}
+
+
+/* unlock Alliance registers */
+static void
+ApmUnlock(ApmPtr pApm)
+{
+ if (pApm->Chipset >= AT3D && !pApm->noLinear)
+ ApmWriteSeq(0x10, 0x12);
+ else
+ wrinx(pApm->xport, 0x10, 0x12);
+}
+
+/* lock Alliance registers */
+static void
+ApmLock(ApmPtr pApm)
+{
+ if (pApm->Chipset >= AT3D && !pApm->noLinear)
+ ApmWriteSeq(0x10, pApm->savedSR10 ? 0 : 0x12);
+ else
+ wrinx(pApm->xport, 0x10, pApm->savedSR10 ? 0 : 0x12);
+}
+
+static void
+ApmIdentify(int flags)
+{
+ xf86PrintChipsets(APM_NAME, "driver for the Alliance chipsets",
+ ApmChipsets);
+}
+
+static const OptionInfoRec *
+ApmAvailableOptions(int chipid, int busid)
+{
+ return ApmOptions;
+}
+
+static int
+ApmFindIsaDevice(GDevPtr dev)
+{
+ char save = rdinx(0x3C4, 0x10);
+ int i;
+ int apmChip = -1;
+
+ /*
+ * Start by probing the VGA chipset.
+ */
+ outw(0x3C4, 0x1210);
+ if (rdinx(0x3C4, 0x11) == 'P' && rdinx(0x3C4, 0x12) == 'r' &&
+ rdinx(0x3C4, 0x13) == 'o') {
+ char id_ap6420[] = "6420";
+ char id_ap6422[] = "6422";
+ char id_at24[] = "6424";
+ char id_at3d[] = "AT3D";
+ char idstring[] = " ";
+
+ /*
+ * Must be an Alliance !!!
+ */
+ for (i = 0; i < 4; i++)
+ idstring[i] = rdinx(0x3C4, 0x14 + i);
+ if (!memcmp(id_ap6420, idstring, 4) ||
+ !memcmp(id_ap6422, idstring, 4))
+ apmChip = AP6422;
+ else if (!memcmp(id_at24, idstring, 4))
+ apmChip = AT24;
+ else if (!memcmp(id_at3d, idstring, 4))
+ apmChip = AT3D;
+ if (apmChip >= 0) {
+ int apm_xbase;
+
+ apm_xbase = (rdinx(0x3C4, 0x1F) << 8) | rdinx(0x3C4, 0x1E);
+
+ if (!(wrinx(0x3C4, 0x1D, 0xCA >> 2), inb(apm_xbase + 2))) {
+ /*
+ * TODO Not PCI
+ */
+ }
+
+ }
+ }
+ wrinx(0x3C4, 0x10, save);
+
+ return apmChip;
+}
+
+static void
+ApmAssignFPtr(ScrnInfoPtr pScrn)
+{
+ pScrn->driverVersion = VERSION;
+ pScrn->driverName = APM_DRIVER_NAME;
+ pScrn->name = APM_NAME;
+ pScrn->Probe = ApmProbe;
+ pScrn->PreInit = ApmPreInit;
+ pScrn->ScreenInit = ApmScreenInit;
+ pScrn->SwitchMode = ApmSwitchMode;
+ pScrn->AdjustFrame = ApmAdjustFrame;
+ pScrn->EnterVT = ApmEnterVT;
+ pScrn->LeaveVT = ApmLeaveVT;
+ pScrn->FreeScreen = ApmFreeScreen;
+ pScrn->ValidMode = ApmValidMode;
+}
+
+static Bool
+ApmProbe(DriverPtr drv, int flags)
+{
+ int numDevSections, numUsed, i;
+ GDevPtr *DevSections;
+ int *usedChips;
+ int foundScreen = FALSE;
+
+ /*
+ * Check if there is a chipset override in the config file
+ */
+ if ((numDevSections = xf86MatchDevice(APM_DRIVER_NAME,
+ &DevSections)) <= 0)
+ return FALSE;
+
+ /*
+ * We need to probe the hardware first. We then need to see how this
+ * fits in with what is given in the config file, and allow the config
+ * file info to override any contradictions.
+ */
+
+ if (xf86GetPciVideoInfo() == NULL) {
+ return FALSE;
+ }
+ numUsed = xf86MatchPciInstances(APM_NAME, PCI_VENDOR_ALLIANCE,
+ ApmChipsets, ApmPciChipsets, DevSections, numDevSections,
+ drv, &usedChips);
+
+ if (numUsed > 0) {
+ if (flags & PROBE_DETECT)
+ foundScreen = TRUE;
+ else for (i = 0; i < numUsed; i++) {
+ ScrnInfoPtr pScrn;
+
+ /*
+ * Allocate a ScrnInfoRec and claim the slot
+ */
+ pScrn = NULL;
+ if ((pScrn = xf86ConfigPciEntity(pScrn, 0, usedChips[i],
+ ApmPciChipsets, NULL,
+ NULL,NULL,NULL,NULL))){
+
+ /*
+ * Fill in what we can of the ScrnInfoRec
+ */
+ ApmAssignFPtr(pScrn);
+ foundScreen = TRUE;
+ }
+ }
+ }
+
+ /* Check for non-PCI cards */
+ numUsed = xf86MatchIsaInstances(APM_NAME, ApmChipsets,
+ ApmIsaChipsets, drv, ApmFindIsaDevice, DevSections,
+ numDevSections, &usedChips);
+ if (numUsed > 0) {
+ if (flags & PROBE_DETECT)
+ foundScreen = TRUE;
+ else for (i = 0; i < numUsed; i++) {
+ ScrnInfoPtr pScrn = NULL;
+ if ((pScrn = xf86ConfigIsaEntity(pScrn, 0, usedChips[i],
+ ApmIsaChipsets, NULL, NULL, NULL,
+ NULL, NULL))) {
+ /*
+ * Fill in what we can of the ScrnInfoRec
+ */
+ ApmAssignFPtr(pScrn);
+ foundScreen = TRUE;
+ }
+ }
+ }
+ xfree(DevSections);
+ return foundScreen;
+}
+
+/*
+ * GetAccelPitchValues -
+ *
+ * This function returns a list of display width (pitch) values that can
+ * be used in accelerated mode.
+ */
+static int *
+GetAccelPitchValues(ScrnInfoPtr pScrn)
+{
+ int *linePitches = NULL;
+ int linep[] = {640, 800, 1024, 1152, 1280, 1600, 0};
+
+ if (sizeof linep > 0) {
+ linePitches = (int *)xnfalloc(sizeof linep);
+ memcpy(linePitches, linep, sizeof linep);
+ }
+
+ return linePitches;
+}
+
+static unsigned int
+ddc1Read(ScrnInfoPtr pScrn)
+{
+ APMDECL(pScrn);
+ unsigned char tmp;
+
+ tmp = RDXB_IOP(0xD0);
+ WRXB_IOP(0xD0, tmp & 0x07);
+ while (STATUS_IOP() & 0x800);
+ while (!(STATUS_IOP() & 0x800));
+ return (STATUS_IOP() & STATUS_SDA) != 0;
+}
+
+static void
+ApmProbeDDC(ScrnInfoPtr pScrn, int index)
+{
+ vbeInfoPtr pVbe;
+
+ if (xf86LoadSubModule(pScrn, "vbe")) {
+ pVbe = VBEInit(NULL, index);
+ ConfiguredMonitor = vbeDoEDID(pVbe, NULL);
+ vbeFree(pVbe);
+ }
+}
+
+static Bool
+ApmPreInit(ScrnInfoPtr pScrn, int flags)
+{
+ APMDECL(pScrn);
+ EntityInfoPtr pEnt;
+ vgaHWPtr hwp;
+ MessageType from;
+ char *mod = NULL, *req = NULL, *s;
+ ClockRangePtr clockRanges;
+ int i;
+ xf86MonPtr MonInfo = NULL;
+ double real;
+
+ /*
+ * Note: This function is only called once at server startup, and
+ * not at the start of each server generation. This means that
+ * only things that are persistent across server generations can
+ * be initialised here. xf86Screens[] is (pScrn is a pointer to one
+ * of these). Privates allocated using xf86AllocateScrnInfoPrivateIndex()
+ * are too, and should be used for data that must persist across
+ * server generations.
+ *
+ * Per-generation data should be allocated with
+ * AllocateScreenPrivateIndex() from the ScreenInit() function.
+ */
+
+ /* Check the number of entities, and fail if it isn't one. */
+ if (pScrn->numEntities != 1)
+ return FALSE;
+
+ /* Allocate the ApmRec driverPrivate */
+ if (!ApmGetRec(pScrn)) {
+ return FALSE;
+ }
+ pApm = APMPTR(pScrn);
+
+ /* Get the entity */
+ pEnt = pApm->pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
+ if (pEnt->location.type == BUS_PCI) {
+ pApm->PciInfo = xf86GetPciInfoForEntity(pEnt->index);
+ pApm->PciTag = pciTag(pApm->PciInfo->bus, pApm->PciInfo->device,
+ pApm->PciInfo->func);
+ }
+ else {
+ pApm->PciInfo = NULL;
+ pApm->PciTag = 0;
+ }
+
+ if (flags & PROBE_DETECT) {
+ ApmProbeDDC(pScrn, pEnt->index);
+ return TRUE;
+ }
+
+ /* The vgahw module should be allocated here when needed */
+ if (!xf86LoadSubModule(pScrn, "vgahw"))
+ return FALSE;
+
+ xf86LoaderReqSymLists(vgahwSymbols, NULL);
+
+ /*
+ * Allocate a vgaHWRec
+ */
+ if (!vgaHWGetHWRec(pScrn))
+ return FALSE;
+
+ hwp = VGAHWPTR(pScrn);
+ vgaHWGetIOBase(hwp);
+ pApm->iobase = hwp->PIOOffset;
+ pApm->xport = hwp->PIOOffset + 0x3C4;
+
+ /* Set pScrn->monitor */
+ pScrn->monitor = pScrn->confScreen->monitor;
+
+ /* XXX: Access funcs */
+ /*
+ * The first thing we should figure out is the depth, bpp, etc.
+ */
+ if (!xf86SetDepthBpp(pScrn, 0, 0, 0, Support24bppFb | Support32bppFb)) {
+ return FALSE;
+ } else {
+ /* Check that the returned depth is one we support */
+ switch (pScrn->depth) {
+ case 4:
+ case 8:
+ case 15:
+ case 16:
+ case 24:
+ /* OK */
+ break;
+ default:
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Given depth (%d) is not supported by this driver\n",
+ pScrn->depth);
+ return FALSE;
+ }
+ }
+ xf86PrintDepthBpp(pScrn);
+
+ /*
+ * This must happen after pScrn->display has been set because
+ * xf86SetWeight references it.
+ */
+ if (pScrn->depth > 8) {
+ /* The defaults are OK for us */
+ rgb zeros = {0, 0, 0};
+
+ if (!xf86SetWeight(pScrn, zeros, zeros)) {
+ return FALSE;
+ } else {
+ /* XXX check that weight returned is supported */
+ ;
+ }
+ }
+
+ if (!xf86SetDefaultVisual(pScrn, -1)) {
+ return FALSE;
+ } else {
+ if (pScrn->depth > 8 && pScrn->defaultVisual != TrueColor) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Given default visual"
+ " (%s) is not supported at depth %d\n",
+ xf86GetVisualName(pScrn->defaultVisual), pScrn->depth);
+ return FALSE;
+ }
+ }
+
+ /* We use a programmable clock */
+ pScrn->progClock = TRUE;
+
+ /* Collect all of the relevant option flags (fill in pScrn->options) */
+ xf86CollectOptions(pScrn, NULL);
+
+ /* Process the options */
+ if (!(pApm->Options = xalloc(sizeof(ApmOptions))))
+ return FALSE;
+ memcpy(pApm->Options, ApmOptions, sizeof(ApmOptions));
+ xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pApm->Options);
+
+ pApm->scrnIndex = pScrn->scrnIndex;
+ /* Set the bits per RGB for 8bpp mode */
+ if (pScrn->depth > 1 && pScrn->depth <= 8) {
+ /* Default to 8 */
+ pScrn->rgbBits = 8;
+ }
+ if (xf86ReturnOptValBool(pApm->Options, OPTION_NOLINEAR, FALSE)) {
+ pApm->noLinear = TRUE;
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "No linear framebuffer\n");
+ }
+ from = X_DEFAULT;
+ pApm->hwCursor = FALSE;
+ if (xf86GetOptValBool(pApm->Options, OPTION_HW_CURSOR, &pApm->hwCursor))
+ from = X_CONFIG;
+ if (pApm->noLinear ||
+ xf86ReturnOptValBool(pApm->Options, OPTION_SW_CURSOR, FALSE)) {
+ from = X_CONFIG;
+ pApm->hwCursor = FALSE;
+ }
+ xf86DrvMsg(pScrn->scrnIndex, from, "Using %s cursor\n",
+ pApm->hwCursor ? "HW" : "SW");
+ from = X_DEFAULT;
+ if (pScrn->bitsPerPixel < 8)
+ pApm->NoAccel = TRUE;
+ if (xf86ReturnOptValBool(pApm->Options, OPTION_NOACCEL, FALSE)) {
+ from = X_CONFIG;
+ pApm->NoAccel = TRUE;
+ }
+ if (pApm->NoAccel)
+ xf86DrvMsg(pScrn->scrnIndex, from, "Acceleration disabled\n");
+ if (xf86GetOptValFreq(pApm->Options, OPTION_SET_MCLK, OPTUNITS_MHZ, &real)) {
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "MCLK used is %.1f MHz\n", real);
+ pApm->MemClk = (int)(real * 1000.0);
+ }
+ if (xf86ReturnOptValBool(pApm->Options, OPTION_SHADOW_FB, FALSE)) {
+ pApm->ShadowFB = TRUE;
+ pApm->NoAccel = TRUE;
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
+ "Using \"Shadow Framebuffer\" - acceleration disabled\n");
+ }
+ if (xf86ReturnOptValBool(pApm->Options, OPTION_PCI_RETRY, FALSE)) {
+ if (xf86ReturnOptValBool(pApm->Options, OPTION_PCI_BURST, FALSE)) {
+ pApm->UsePCIRetry = TRUE;
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "PCI retry enabled\n");
+ }
+ else
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "\"pci_retry\" option requires pci_burst \"on\".\n");
+ }
+ pApm->DPMSMask[DPMSModeOn] = DPMSModeOn;
+ pApm->DPMSMask[DPMSModeStandby] = DPMSModeStandby;
+ pApm->DPMSMask[DPMSModeSuspend] = DPMSModeSuspend;
+ pApm->DPMSMask[DPMSModeOff] = DPMSModeOff;
+ if ((s = xf86GetOptValString(pApm->Options, OPTION_REMAP_DPMS_ON))) {
+ if (!strcmp(s, "on"))
+ pApm->DPMSMask[DPMSModeOn] = DPMSModeOn;
+ else if (!strcmp(s, "standby"))
+ pApm->DPMSMask[DPMSModeOn] = DPMSModeStandby;
+ else if (!strcmp(s, "suspend"))
+ pApm->DPMSMask[DPMSModeOn] = DPMSModeSuspend;
+ else if (!strcmp(s, "off"))
+ pApm->DPMSMask[DPMSModeOn] = DPMSModeOff;
+ else if (s[0] >= '0' && s[0] <= '9') {
+ pApm->DPMSMask[DPMSModeOn] = strtol(s, NULL, 0);
+ if (pApm->DPMSMask[DPMSModeOn] > (sizeof pApm->DPMSMask)-1)
+ pApm->DPMSMask[DPMSModeOn] = (sizeof pApm->DPMSMask) - 1;
+ }
+ }
+ if ((s = xf86GetOptValString(pApm->Options, OPTION_REMAP_DPMS_STANDBY))) {
+ if (!strcmp(s, "on"))
+ pApm->DPMSMask[DPMSModeStandby] = DPMSModeOn;
+ else if (!strcmp(s, "standby"))
+ pApm->DPMSMask[DPMSModeStandby] = DPMSModeStandby;
+ else if (!strcmp(s, "suspend"))
+ pApm->DPMSMask[DPMSModeStandby] = DPMSModeSuspend;
+ else if (!strcmp(s, "off"))
+ pApm->DPMSMask[DPMSModeStandby] = DPMSModeOff;
+ else if (s[0] >= '0' && s[0] <= '9') {
+ pApm->DPMSMask[DPMSModeStandby] = strtol(s, NULL, 0);
+ if (pApm->DPMSMask[DPMSModeStandby] > (sizeof pApm->DPMSMask)-1)
+ pApm->DPMSMask[DPMSModeStandby] = (sizeof pApm->DPMSMask) - 1;
+ }
+ }
+ if ((s = xf86GetOptValString(pApm->Options, OPTION_REMAP_DPMS_SUSPEND))) {
+ if (!strcmp(s, "on"))
+ pApm->DPMSMask[DPMSModeSuspend] = DPMSModeOn;
+ else if (!strcmp(s, "standby"))
+ pApm->DPMSMask[DPMSModeSuspend] = DPMSModeStandby;
+ else if (!strcmp(s, "suspend"))
+ pApm->DPMSMask[DPMSModeSuspend] = DPMSModeSuspend;
+ else if (!strcmp(s, "off"))
+ pApm->DPMSMask[DPMSModeSuspend] = DPMSModeOff;
+ else if (s[0] >= '0' && s[0] <= '9') {
+ pApm->DPMSMask[DPMSModeSuspend] = strtol(s, NULL, 0);
+ if (pApm->DPMSMask[DPMSModeSuspend] > (sizeof pApm->DPMSMask)-1)
+ pApm->DPMSMask[DPMSModeSuspend] = (sizeof pApm->DPMSMask) - 1;
+ }
+ }
+ if ((s = xf86GetOptValString(pApm->Options, OPTION_REMAP_DPMS_OFF))) {
+ if (!strcmp(s, "on"))
+ pApm->DPMSMask[DPMSModeOff] = DPMSModeOn;
+ else if (!strcmp(s, "standby"))
+ pApm->DPMSMask[DPMSModeOff] = DPMSModeStandby;
+ else if (!strcmp(s, "suspend"))
+ pApm->DPMSMask[DPMSModeOff] = DPMSModeSuspend;
+ else if (!strcmp(s, "off"))
+ pApm->DPMSMask[DPMSModeOff] = DPMSModeOff;
+ else if (s[0] >= '0' && s[0] <= '9') {
+ pApm->DPMSMask[DPMSModeOff] = strtol(s, NULL, 0);
+ if (pApm->DPMSMask[DPMSModeOff] > (sizeof pApm->DPMSMask)-1)
+ pApm->DPMSMask[DPMSModeOff] = (sizeof pApm->DPMSMask) - 1;
+ }
+ }
+
+ /*
+ * Set the Chipset and ChipRev, allowing config file entries to
+ * override.
+ */
+ if (pEnt->device->chipset && *pEnt->device->chipset) {
+ pScrn->chipset = pEnt->device->chipset;
+ pApm->Chipset = xf86StringToToken(ApmChipsets, pScrn->chipset);
+ from = X_CONFIG;
+ } else if (pEnt->device->chipID >= 0) {
+ pApm->Chipset = pEnt->device->chipID;
+ pScrn->chipset = (char *)xf86TokenToString(ApmChipsets, pApm->Chipset);
+
+ from = X_CONFIG;
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipID override: 0x%04X\n",
+ pApm->Chipset);
+ } else {
+ from = X_PROBED;
+ if (pApm->PciInfo)
+ pApm->Chipset = pApm->PciInfo->chipType;
+ else
+ pApm->Chipset = pEnt->chipset;
+ pScrn->chipset = (char *)xf86TokenToString(ApmChipsets, pApm->Chipset);
+ }
+ if (pScrn->bitsPerPixel == 24 && pApm->Chipset < AT24) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Given depth (%d) is not supported by this driver\n",
+ pScrn->depth);
+ return FALSE;
+ }
+ if (pEnt->device->chipRev >= 0) {
+ pApm->ChipRev = pEnt->device->chipRev;
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n",
+ pApm->ChipRev);
+ } else if (pApm->PciInfo) {
+ pApm->ChipRev = pApm->PciInfo->chipRev;
+ }
+
+ /*
+ * This shouldn't happen because such problems should be caught in
+ * ApmProbe(), but check it just in case.
+ */
+ if (pScrn->chipset == NULL) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "ChipID 0x%04X is not recognised\n", pApm->Chipset);
+ return FALSE;
+ }
+ if (pApm->Chipset < 0) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Chipset \"%s\" is not recognised\n", pScrn->chipset);
+ return FALSE;
+ }
+
+ xf86DrvMsg(pScrn->scrnIndex, from, "Chipset: \"%s\"\n", pScrn->chipset);
+
+ if (pEnt->device->MemBase != 0) {
+ pApm->LinAddress = pEnt->device->MemBase;
+ from = X_CONFIG;
+ } else if (pApm->PciInfo) {
+ pApm->LinAddress = pApm->PciInfo->memBase[0] & 0xFF800000;
+ from = X_PROBED;
+ } else {
+ /*
+ * VESA local bus.
+ * Pray that 2048MB works.
+ */
+ pApm->LinAddress = 0x80000000;
+ }
+
+ xf86DrvMsg(pScrn->scrnIndex, from, "Linear framebuffer at 0x%lX\n",
+ (unsigned long)pApm->LinAddress);
+
+ if (xf86LoadSubModule(pScrn, "ddc")) {
+ xf86LoaderReqSymLists(ddcSymbols, NULL);
+ if (xf86LoadSubModule(pScrn, "i2c")) {
+ xf86LoaderReqSymLists(i2cSymbols, NULL);
+ pApm->I2C = TRUE;
+ }
+ }
+
+ if (pApm->noLinear) {
+ /*
+ * TODO not AT3D.
+ * XXX ICI XXX
+ */
+ pApm->LinMapSize = 4 * 1024 * 1024 /* 0x10000 */;
+ pApm->FbMapSize = 4 * 1024 * 1024 /* 0x10000 */;
+ if (pApm->Chipset >= AT3D)
+ pApm->LinAddress += 8 * 1024 * 1024 /* 0xA0000 */;
+ }
+ else {
+ if (pApm->Chipset >= AT3D)
+ pApm->LinMapSize = 16 * 1024 * 1024;
+ else
+ pApm->LinMapSize = 6 * 1024 * 1024;
+ pApm->FbMapSize = 4 * 1024 * 1024;
+ }
+
+ if (xf86LoadSubModule(pScrn, "int10")) {
+ void *ptr;
+
+ xf86LoaderReqSymLists(int10Symbols, NULL);
+ xf86DrvMsg(pScrn->scrnIndex,X_INFO,"initializing int10\n");
+ ptr = xf86InitInt10(pEnt->index);
+ if (ptr)
+ xf86FreeInt10(ptr);
+ }
+
+ xf86RegisterResources(pEnt->index, NULL, ResNone);
+ xf86SetOperatingState(resVga, pEnt->index, ResDisableOpr);
+ pScrn->racMemFlags = 0; /* For noLinear, access to 0xA0000 */
+ if (pApm->VGAMap)
+ pScrn->racIoFlags = 0;
+ else
+ pScrn->racIoFlags = RAC_COLORMAP | RAC_VIEWPORT;
+
+ if (pEnt->device->videoRam != 0) {
+ pScrn->videoRam = pEnt->device->videoRam;
+ from = X_CONFIG;
+ } else if (!pApm->noLinear && pApm->Chipset >= AT3D) {
+ unsigned char d9, db, uc;
+ /*unsigned long save;*/
+ volatile unsigned char *LinMap;
+
+ LinMap = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
+ pApm->PciTag, pApm->LinAddress,
+ pApm->LinMapSize);
+ /*save = pciReadLong(pApm->PciTag, PCI_CMD_STAT_REG);
+ pciWriteLong(pApm->PciTag, PCI_CMD_STAT_REG, save | PCI_CMD_MEM_ENABLE);*/
+ d9 = LinMap[0xFFECD9];
+ db = LinMap[0xFFECDB];
+ LinMap[0xFFECDB] = (db & 0xF4) | 0x0A;
+ LinMap[0xFFECD9] = (d9 & 0xCF) | 0x20;
+ LinMap[0xFFF3C4] = 0x1C;
+ uc = LinMap[0xFFF3C5];
+ LinMap[0xFFF3C5] = 0x3F;
+ LinMap[0xFFF3C4] = 0x20;
+ pScrn->videoRam = LinMap[0xFFF3C5] * 64;
+ LinMap[0xFFF3C4] = 0x10;
+ pApm->savedSR10 = LinMap[0xFFF3C5];
+ LinMap[0xFFF3C4] = 0x1E;
+ pApm->xbase = LinMap[0xFFF3C5];
+ LinMap[0xFFF3C4] = 0x1F;
+ pApm->xbase |= LinMap[0xFFF3C5] << 8;
+ LinMap[0xFFF3C4] = 0x1C;
+ LinMap[0xFFF3C5] = uc;
+ LinMap[0xFFECDB] = db;
+ LinMap[0xFFECD9] = d9;
+ /*pciWriteLong(pApm->PciTag, PCI_CMD_STAT_REG, save);*/
+ xf86UnMapVidMem(pScrn->scrnIndex, (pointer)LinMap, pApm->LinMapSize);
+ from = X_PROBED;
+ }
+ else {
+ /*unsigned long save;
+
+ save = pciReadLong(pApm->PciTag, PCI_CMD_STAT_REG);
+ pciWriteLong(pApm->PciTag, PCI_CMD_STAT_REG, save | PCI_CMD_IO_ENABLE);*/
+ pApm->savedSR10 = rdinx(pApm->xport, 0x10);
+ wrinx(pApm->xport, 0x10, 0x12);
+ pScrn->videoRam = rdinx(pApm->xport, 0x20) * 64;
+ pApm->xbase = rdinx(pApm->xport, 0x1F) << 8;
+ pApm->xbase |= rdinx(pApm->xport, 0x1E);
+ pApm->xbase += pApm->iobase;
+ wrinx(pApm->xport, 0x10, pApm->savedSR10 ? 0 : 0x12);
+ /*pciWriteLong(pApm->PciTag, PCI_CMD_STAT_REG, save);*/
+ from = X_PROBED;
+ }
+ if (pApm->Chipset < AT3D && pScrn->videoRam >= 4096)
+ pScrn->videoRam -= 32;
+
+ xf86DrvMsg(pScrn->scrnIndex, from, "VideoRAM: %d kByte\n",
+ pScrn->videoRam);
+
+ if (!xf86IsPc98()) {
+ hwp->MapSize = 0x10000;
+ vgaHWMapMem(pScrn);
+ if (pApm->I2C) {
+ if (!ApmI2CInit(pScrn)) {
+ xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"I2C initialization failed\n");
+ }
+ else {
+ MonInfo = xf86DoEDID_DDC2(pScrn->scrnIndex,pApm->I2CPtr);
+ }
+ }
+ if (0 && !MonInfo)
+ MonInfo = xf86DoEDID_DDC1(pScrn->scrnIndex,vgaHWddc1SetSpeed,ddc1Read);
+ if (MonInfo)
+ xf86PrintEDID(MonInfo);
+ pScrn->monitor->DDC = MonInfo;
+ }
+
+ /* The gamma fields must be initialised when using the new cmap code */
+ if (pScrn->depth > 1) {
+ Gamma zeros = {0.0, 0.0, 0.0};
+
+ if (!xf86SetGamma(pScrn, zeros)) {
+ return FALSE;
+ }
+ }
+
+ pApm->MinClock = 23125;
+ xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "Min pixel clock set to %d MHz\n",
+ pApm->MinClock / 1000);
+
+ /*
+ * If the user has specified ramdac speed in the XF86Config
+ * file, we respect that setting.
+ */
+ from = X_DEFAULT;
+ if (pEnt->device->dacSpeeds[0]) {
+ int speed = 0;
+
+ switch (pScrn->bitsPerPixel) {
+ case 4:
+ case 8:
+ speed = pEnt->device->dacSpeeds[DAC_BPP8];
+ break;
+ case 16:
+ speed = pEnt->device->dacSpeeds[DAC_BPP16];
+ break;
+ case 24:
+ speed = pEnt->device->dacSpeeds[DAC_BPP24];
+ break;
+ case 32:
+ speed = pEnt->device->dacSpeeds[DAC_BPP32];
+ break;
+ }
+ if (speed == 0)
+ pApm->MaxClock = pEnt->device->dacSpeeds[0];
+ else
+ pApm->MaxClock = speed;
+ from = X_CONFIG;
+ } else {
+ switch(pApm->Chipset)
+ {
+ /* These values come from the Manual for AT24 and AT3D
+ in the overview of various modes. I've taken the largest
+ number for the different modes. Alliance wouldn't
+ tell me what the maximum frequency was, so...
+ */
+ case AT24:
+ switch(pScrn->bitsPerPixel)
+ {
+ case 4:
+ case 8:
+ pApm->MaxClock = 160000;
+ break;
+ case 16:
+ pApm->MaxClock = 144000;
+ break;
+ case 24:
+ pApm->MaxClock = 75000; /* Hmm. */
+ break;
+ case 32:
+ pApm->MaxClock = 94500;
+ break;
+ default:
+ return FALSE;
+ }
+ break;
+ case AT3D:
+ switch(pScrn->bitsPerPixel)
+ {
+ case 4:
+ case 8:
+ pApm->MaxClock = 175500;
+ break;
+ case 16:
+ pApm->MaxClock = 144000;
+ break;
+ case 24:
+ pApm->MaxClock = 94000; /* Changed from 75000 by Grenié */
+ break;
+ case 32:
+ pApm->MaxClock = 94500;
+ break;
+ default:
+ return FALSE;
+ }
+ break;
+ case AP6422:
+ switch(pScrn->bitsPerPixel)
+ {
+ case 4:
+ case 8:
+ pApm->MaxClock = 135000;
+ break;
+ case 16:
+ pApm->MaxClock = 75000;
+ break;
+ case 32:
+ pApm->MaxClock = 60000;
+ break;
+ default:
+ return FALSE;
+ }
+ break;
+ default:
+ pApm->MaxClock = 135000;
+ break;
+ }
+ }
+ xf86DrvMsg(pScrn->scrnIndex, from, "Max pixel clock is %d MHz\n",
+ pApm->MaxClock / 1000);
+
+ /*
+ * Setup the ClockRanges, which describe what clock ranges are available,
+ * and what sort of modes they can be used for.
+ */
+ clockRanges = (ClockRangePtr)xnfcalloc(sizeof(ClockRange), 1);
+ clockRanges->next = NULL;
+ clockRanges->minClock = pApm->MinClock;
+ clockRanges->maxClock = pApm->MaxClock;
+ clockRanges->clockIndex = -1; /* programmable */
+ clockRanges->interlaceAllowed = FALSE; /* XXX change this */
+ clockRanges->doubleScanAllowed = FALSE; /* XXX check this */
+
+ /* Select valid modes from those available */
+ if (pApm->NoAccel) {
+ /*
+ * XXX Assuming min pitch 256, max 2048
+ * XXX Assuming min height 128, max 2048
+ */
+ i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
+ pScrn->display->modes, clockRanges,
+ NULL, 256, 2048,
+ pScrn->bitsPerPixel, 128, 2048,
+ pScrn->display->virtualX,
+ pScrn->display->virtualY,
+ pApm->FbMapSize,
+ LOOKUP_BEST_REFRESH);
+ } else {
+ /*
+ * XXX Assuming min height 128, max 2048
+ */
+ i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
+ pScrn->display->modes, clockRanges,
+ GetAccelPitchValues(pScrn), 0, 0,
+ pScrn->bitsPerPixel, 128, 2048,
+ pScrn->display->virtualX,
+ pScrn->display->virtualY,
+ pApm->FbMapSize,
+ LOOKUP_BEST_REFRESH);
+ }
+
+ if (i == -1) {
+ ApmFreeRec(pScrn);
+ return FALSE;
+ }
+
+ /* Prune the modes marked as invalid */
+ xf86PruneDriverModes(pScrn);
+
+ if (i == 0 || pScrn->modes == NULL) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n");
+ ApmFreeRec(pScrn);
+ return FALSE;
+ }
+
+ xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V);
+
+ /* Set the current mode to the first in the list */
+ pScrn->currentMode = pScrn->modes;
+
+ /* Print the list of modes being used */
+ xf86PrintModes(pScrn);
+
+ /* Set display resolution */
+ xf86SetDpi(pScrn, 0, 0);
+
+ /* Load bpp-specific modules */
+ switch (pScrn->bitsPerPixel) {
+ case 1:
+ mod = "xf1bpp";
+ req = "xf1bppScreenInit";
+ break;
+ case 4:
+ mod = "xf4bpp";
+ req = "xf4bppScreenInit";
+ break;
+ case 8:
+ case 16:
+ case 24:
+ case 32:
+ mod = "fb";
+ break;
+ }
+
+ if (mod && xf86LoadSubModule(pScrn, mod) == NULL) {
+ ApmFreeRec(pScrn);
+ return FALSE;
+ }
+
+ if (mod) {
+ if (req) {
+ xf86LoaderReqSymbols(req, NULL);
+ } else {
+ xf86LoaderReqSymLists(fbSymbols, NULL);
+ }
+ }
+
+ /* Load XAA if needed */
+ if (!pApm->NoAccel) {
+ if (!xf86LoadSubModule(pScrn, "xaa")) {
+ ApmFreeRec(pScrn);
+ return FALSE;
+ }
+ xf86LoaderReqSymLists(xaaSymbols, NULL);
+ }
+
+ /* Load ramdac if needed */
+ if (pApm->hwCursor) {
+ if (!xf86LoadSubModule(pScrn, "ramdac")) {
+ ApmFreeRec(pScrn);
+ return FALSE;
+ }
+ xf86LoaderReqSymLists(ramdacSymbols, NULL);
+ }
+
+ /* Load shadowfb if needed */
+ if (pApm->ShadowFB) {
+ if (!xf86LoadSubModule(pScrn, "shadowfb")) {
+ ApmFreeRec(pScrn);
+ return FALSE;
+ }
+ xf86LoaderReqSymLists(shadowSymbols, NULL);
+ }
+
+ pApm->CurrentLayout.displayWidth = pScrn->virtualX;
+ pApm->CurrentLayout.displayHeight = pScrn->virtualY;
+ pApm->CurrentLayout.bitsPerPixel = pScrn->bitsPerPixel;
+ pApm->CurrentLayout.bytesPerScanline= (pApm->CurrentLayout.displayWidth * pApm->CurrentLayout.bitsPerPixel) >> 3;
+ pApm->CurrentLayout.depth = pScrn->depth;
+ pApm->CurrentLayout.Scanlines = 2 * (pScrn->videoRam << 10) / pApm->CurrentLayout.bytesPerScanline;
+ if (pScrn->bitsPerPixel == 24)
+ pApm->CurrentLayout.mask32 = 3;
+ else
+ pApm->CurrentLayout.mask32 = 32 / pScrn->bitsPerPixel - 1;
+
+ return TRUE;
+}
+
+/*
+ * Map the framebuffer and MMIO memory.
+ */
+
+static Bool
+ApmMapMem(ScrnInfoPtr pScrn)
+{
+ APMDECL(pScrn);
+ vgaHWPtr hwp = VGAHWPTR(pScrn);
+
+ pApm->LinMap = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
+ pApm->PciTag,
+ (unsigned long)pApm->LinAddress,
+ pApm->LinMapSize);
+ if (pApm->LinMap == NULL)
+ return FALSE;
+
+ if (!pApm->noLinear) {
+ if (pApm->Chipset >= AT3D) {
+ pApm->FbBase = (void *)(((char *)pApm->LinMap) + 0x800000);
+ pApm->VGAMap = ((char *)pApm->LinMap) + 0xFFF000;
+ pApm->MemMap = ((char *)pApm->LinMap) + 0xFFEC00;
+ pApm->BltMap = (void *)(((char *)pApm->LinMap) + 0x3F8000);
+ }
+ else {
+ pApm->FbBase = (void *)pApm->LinMap;
+ pApm->VGAMap = NULL;
+ if (pScrn->videoRam == 6 * 1024 - 32) {
+ pApm->MemMap = ((char *)pApm->LinMap) + 0x5FF800;
+ pApm->BltMap = (void *)(((char *)pApm->LinMap) + 0x5F8000);
+ }
+ else {
+ pApm->MemMap = ((char *)pApm->LinMap) + 0x3FF800;
+ pApm->BltMap = (void *)(((char *)pApm->LinMap) + 0x3F8000);
+ }
+ }
+
+ /*
+ * Initialize chipset
+ */
+ pApm->c9 = RDXB(0xC9);
+ if (pApm->Chipset >= AT3D) {
+ pApm->d9 = RDXB(0xD9);
+ pApm->db = RDXB(0xDB);
+
+ /* If you change these two, change them also in apm_funcs.c */
+ WRXB(0xDB, (pApm->db & 0xF4) | 0x0A);
+ WRXB(0xD9, (pApm->d9 & 0xCF) | 0x20);
+
+ vgaHWSetMmioFuncs(hwp, (CARD8 *)pApm->LinMap, 0xFFF000);
+ }
+ if (pApm->Chipset >= AP6422)
+ WRXB(0xC9, pApm->c9 | 0x10);
+ }
+ else {
+ pApm->FbBase = pApm->LinMap;
+
+ /*
+ * Initialize chipset
+ */
+ if (pApm->Chipset >= AT3D) {
+ pApm->d9 = RDXB_IOP(0xD9);
+ pApm->db = RDXB_IOP(0xDB);
+ WRXB_IOP(0xDB, pApm->db & 0xF4);
+ }
+ }
+ /*
+ * Save color mode
+ */
+ pApm->MiscOut = hwp->readMiscOut(hwp);
+
+ return TRUE;
+}
+
+/*
+ * Unmap the framebuffer and MMIO memory
+ */
+
+static Bool
+ApmUnmapMem(ScrnInfoPtr pScrn)
+{
+ APMDECL(pScrn);
+ vgaHWPtr hwp = VGAHWPTR(pScrn);
+
+ /*
+ * Reset color mode
+ */
+ hwp->writeMiscOut(hwp, pApm->MiscOut);
+ if (pApm->LinMap) {
+ if (pApm->Chipset >= AT3D) {
+ if (!pApm->noLinear) {
+ WRXB(0xD9, pApm->d9);
+ WRXB(0xDB, pApm->db);
+ }
+ else {
+ WRXB_IOP(0xD9, pApm->d9);
+ WRXB_IOP(0xDB, pApm->db);
+ }
+ }
+ WRXB(0xC9, pApm->c9);
+ xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pApm->LinMap, pApm->LinMapSize);
+ pApm->LinMap = NULL;
+ }
+ else if (pApm->FbBase)
+ xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pApm->LinMap, 0x10000);
+
+ return TRUE;
+}
+
+/*
+ * This function saves the video state.
+ */
+static void
+ApmSave(ScrnInfoPtr pScrn)
+{
+ APMDECL(pScrn);
+ ApmRegPtr ApmReg = &pApm->SavedReg;
+ vgaHWPtr hwp = VGAHWPTR(pScrn);
+
+ if (pApm->VGAMap) {
+ ApmReg->SEQ[0x1B] = ApmReadSeq(0x1B);
+ ApmReg->SEQ[0x1C] = ApmReadSeq(0x1C);
+
+ /*
+ * Save fonts
+ */
+ if (!(hwp->SavedReg.Attribute[0x10] & 1)) {
+ if (pApm->FontInfo || (pApm->FontInfo = (pointer)xalloc(TEXT_AMOUNT))) {
+ int locked;
+
+ locked = ApmReadSeq(0x10);
+ if (locked)
+ ApmWriteSeq(0x10, 0x12);
+ ApmWriteSeq(0x1C, 0x3F);
+ memcpy(pApm->FontInfo, pApm->FbBase, TEXT_AMOUNT);
+ ApmWriteSeq(0x1C, ApmReg->SEQ[0x1C]);
+ if (locked)
+ ApmWriteSeq(0x10, 0);
+ }
+ }
+ /*
+ * This function will handle creating the data structure and filling
+ * in the generic VGA portion.
+ */
+ vgaHWSave(pScrn, &hwp->SavedReg, VGA_SR_MODE | VGA_SR_CMAP);
+
+ /* Hardware cursor registers. */
+ ApmReg->EX[XR140] = RDXL(0x140);
+ ApmReg->EX[XR144] = RDXW(0x144);
+ ApmReg->EX[XR148] = RDXL(0x148);
+ ApmReg->EX[XR14C] = RDXW(0x14C);
+
+ ApmReg->CRT[0x19] = ApmReadCrtc(0x19);
+ ApmReg->CRT[0x1A] = ApmReadCrtc(0x1A);
+ ApmReg->CRT[0x1B] = ApmReadCrtc(0x1B);
+ ApmReg->CRT[0x1C] = ApmReadCrtc(0x1C);
+ ApmReg->CRT[0x1D] = ApmReadCrtc(0x1D);
+ ApmReg->CRT[0x1E] = ApmReadCrtc(0x1E);
+
+ /* RAMDAC registers. */
+ ApmReg->EX[XRE8] = RDXL(0xE8);
+ ApmReg->EX[XREC] = RDXL(0xEC);
+
+ /* Color correction */
+ ApmReg->EX[XRE0] = RDXL(0xE0);
+
+ ApmReg->EX[XR80] = RDXB(0x80);
+ }
+ else {
+ /*
+ * This function will handle creating the data structure and filling
+ * in the generic VGA portion.
+ */
+ vgaHWSave(pScrn, &hwp->SavedReg, VGA_SR_ALL);
+
+ ApmReg->SEQ[0x1B] = rdinx(pApm->xport, 0x1B);
+ ApmReg->SEQ[0x1C] = rdinx(pApm->xport, 0x1C);
+
+ /* Hardware cursor registers. */
+ if (pApm->noLinear) {
+ ApmReg->EX[XR140] = RDXL_IOP(0x140);
+ ApmReg->EX[XR144] = RDXW_IOP(0x144);
+ ApmReg->EX[XR148] = RDXL_IOP(0x148);
+ ApmReg->EX[XR14C] = RDXW_IOP(0x14C);
+ }
+ else {
+ ApmReg->EX[XR140] = RDXL(0x140);
+ ApmReg->EX[XR144] = RDXW(0x144);
+ ApmReg->EX[XR148] = RDXL(0x148);
+ ApmReg->EX[XR14C] = RDXW(0x14C);
+ }
+
+ ApmReg->CRT[0x19] = rdinx(pApm->iobase + 0x3D4, 0x19);
+ ApmReg->CRT[0x1A] = rdinx(pApm->iobase + 0x3D4, 0x1A);
+ ApmReg->CRT[0x1B] = rdinx(pApm->iobase + 0x3D4, 0x1B);
+ ApmReg->CRT[0x1C] = rdinx(pApm->iobase + 0x3D4, 0x1C);
+ ApmReg->CRT[0x1D] = rdinx(pApm->iobase + 0x3D4, 0x1D);
+ ApmReg->CRT[0x1E] = rdinx(pApm->iobase + 0x3D4, 0x1E);
+
+ if (pApm->noLinear) {
+ /* RAMDAC registers. */
+ ApmReg->EX[XRE8] = RDXL_IOP(0xE8);
+ ApmReg->EX[XREC] = RDXL_IOP(0xEC);
+
+ /* Color correction */
+ ApmReg->EX[XRE0] = RDXL_IOP(0xE0);
+
+ ApmReg->EX[XR80] = RDXB_IOP(0x80);
+ }
+ else {
+ /* RAMDAC registers. */
+ ApmReg->EX[XRE8] = RDXL(0xE8);
+ ApmReg->EX[XREC] = RDXL(0xEC);
+
+ /* Color correction */
+ ApmReg->EX[XRE0] = RDXL(0xE0);
+
+ ApmReg->EX[XR80] = RDXB(0x80);
+ }
+ }
+}
+
+#define WITHIN(v,c1,c2) (((v) >= (c1)) && ((v) <= (c2)))
+
+static unsigned
+comp_lmn(ApmPtr pApm, long clock)
+{
+ int n, m, l, f;
+ double fvco;
+ double fout;
+ double fmax, fmin;
+ double fref;
+ double fvco_goal;
+ double k, c;
+
+ if (pApm->Chipset >= AT3D)
+ fmax = 370000.0;
+ else
+ fmax = 250000.0;
+
+ fref = 14318.0;
+ fmin = fmax / 2.0;
+
+ for (m = 1; m <= 5; m++)
+ {
+ for (l = 3; l >= 0; l--)
+ {
+ for (n = 8; n <= 127; n++)
+ {
+ fout = ((double)(n + 1) * fref)/((double)(m + 1) * (1 << l));
+ fvco_goal = (double)clock * (double)(1 << l);
+ fvco = fout * (double)(1 << l);
+ if (!WITHIN(fvco, 0.995*fvco_goal, 1.005*fvco_goal))
+ continue;
+ if (!WITHIN(fvco, fmin, fmax))
+ continue;
+ if (!WITHIN(fvco / (double)(n+1), 300.0, 300000.0))
+ continue;
+ if (!WITHIN(fref / (double)(m+1), 300.0, 300000.0))
+ continue;
+
+ /* The following formula was empirically derived by
+ matching a number of fvco values with acceptable
+ values of f.
+
+ (fvco can be 185MHz - 370MHz on AT3D)
+ (fvco can be 125MHz - 250MHz on AT24/AP6422)
+
+ The table that was measured up follows:
+
+ AT3D
+
+ fvco f
+ (125) (x-7) guess
+ 200 5-7
+ 219 4-7
+ 253 3-6
+ 289 2-5
+ 320 0-4
+ (400) (0-x) guess
+
+ AT24
+
+ fvco f
+ 126 7
+ 200 5-7
+ 211 4-7
+
+ AP6422
+
+ fvco f
+ 126 7
+ 169 5-7
+ 200 4-5
+ 211 4-5
+
+ From this, a function "f = k * fvco + c" was derived.
+
+ For AT3D, this table was measured with MCLK == 50MHz.
+ The driver has since been set to use MCLK == 57.3MHz for,
+ but I don't think that makes a difference here.
+ */
+
+ if (pApm->Chipset >= AT24)
+ {
+ k = 7.0 / (175.0 - 380.0);
+ c = -k * 380.0;
+ f = (int)(k * fvco/1000.0 + c + 0.5);
+ if (f > 7) f = 7;
+ if (f < 0) f = 0;
+ } else { /* i.e AP6422 */
+ c = (211.0*6.0-169.0*4.5)/(211.0-169.0);
+ k = (4.5-c)/211.0;
+ f = (int)(k * fvco/1000.0 + c + 0.5);
+ if (f > 7) f = 7;
+ if (f < 0) f = 0;
+ }
+
+ return (n << 16) | (m << 8) | (l << 2) | (f << 4);
+ }
+ }
+ }
+ xf86DrvMsg(pApm->scrnIndex, X_PROBED,
+ "Cannot find register values for clock %6.2f MHz. "
+ "Please use a (slightly) different clock.\n",
+ (double)clock / 1000.0);
+ return 0;
+}
+
+/*
+ * Initialise a new mode. This is currently still using the old
+ * "initialise struct, restore/write struct to HW" model. That could
+ * be changed.
+ */
+
+static Bool
+ApmModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
+{
+ APMDECL(pScrn);
+ ApmRegPtr ApmReg = &pApm->ModeReg;
+ vgaHWPtr hwp;
+
+
+ /* set clockIndex to "2" for programmable clocks */
+ if (pScrn->progClock)
+ mode->ClockIndex = 2;
+
+ /* prepare standard VGA register contents */
+ if (!vgaHWInit(pScrn, mode))
+ return FALSE;
+ pScrn->vtSema = TRUE;
+ hwp = VGAHWPTR(pScrn);
+
+ hwp->writeMiscOut(hwp, pApm->MiscOut | 0x0F);
+
+ if (xf86IsPc98())
+ outb(0xFAC, 0xFF);
+
+ memcpy(ApmReg, &pApm->SavedReg, sizeof pApm->SavedReg);
+
+ /*
+ * The APM chips have a scale factor of 8 for the
+ * scanline offset. There are four extended bit in addition
+ * to the 8 VGA bits.
+ */
+ {
+ int offset;
+
+ offset = (pApm->CurrentLayout.displayWidth *
+ pApm->CurrentLayout.bitsPerPixel / 8) >> 3;
+ hwp->ModeReg.CRTC[0x13] = offset;
+ /* Bit 8 resides at CR1C bits 7:4. */
+ ApmReg->CRT[0x1C] = (offset & 0xF00) >> 4;
+ }
+
+ /* Set pixel depth. */
+ switch(pApm->CurrentLayout.bitsPerPixel)
+ {
+ case 4:
+ ApmReg->EX[XR80] = 0x01;
+ break;
+ case 8:
+ ApmReg->EX[XR80] = 0x02;
+ break;
+ case 16:
+ if (pApm->CurrentLayout.depth == 15)
+ ApmReg->EX[XR80] = 0x0C;
+ else
+ ApmReg->EX[XR80] = 0x0D;
+ break;
+ case 24:
+ ApmReg->EX[XR80] = 0x0E;
+ break;
+ case 32:
+ ApmReg->EX[XR80] = 0x0F;
+ break;
+ default:
+ FatalError("Unsupported bit depth %d\n", pApm->CurrentLayout.depth);
+ break;
+ }
+
+ /* Set banking register to zero. */
+ ApmReg->EX[XRC0] = 0;
+
+ /* Handle the CRTC overflow bits. */
+ {
+ unsigned char val;
+ /* Vertical Overflow. */
+ val = 0;
+ if ((mode->CrtcVTotal - 2) & 0x400)
+ val |= 0x01;
+ if ((mode->CrtcVDisplay - 1) & 0x400)
+ val |= 0x02;
+ /* VBlankStart is equal to VSyncStart + 1. */
+ if (mode->CrtcVSyncStart & 0x400)
+ val |= 0x04;
+ /* VRetraceStart is equal to VSyncStart + 1. */
+ if (mode->CrtcVSyncStart & 0x400)
+ val |= 0x08;
+ ApmReg->CRT[0x1A] = val;
+
+ /* Horizontal Overflow. */
+ val = 0;
+ if ((mode->CrtcHTotal / 8 - 5) & 0x100)
+ val |= 1;
+ if ((mode->CrtcHDisplay / 8 - 1) & 0x100)
+ val |= 2;
+ /* HBlankStart is equal to HSyncStart - 1. */
+ if ((mode->CrtcHSyncStart / 8 - 1) & 0x100)
+ val |= 4;
+ /* HRetraceStart is equal to HSyncStart. */
+ if ((mode->CrtcHSyncStart / 8) & 0x100)
+ val |= 8;
+ ApmReg->CRT[0x1B] = val;
+
+ /* Assume the CRTC is not KGA (see vgaHWInit) */
+ hwp->ModeReg.CRTC[3] = (hwp->ModeReg.CRTC[3] & 0xE0) |
+ (((mode->CrtcHBlankEnd >> 3) - 1) & 0x1F);
+ hwp->ModeReg.CRTC[5] = ((((mode->CrtcHBlankEnd >> 3) - 1) & 0x20) << 2)
+ | (hwp->ModeReg.CRTC[5] & 0x7F);
+ hwp->ModeReg.CRTC[22] = (mode->CrtcVBlankEnd - 1) & 0xFF;
+ }
+ ApmReg->CRT[0x1E] = 1; /* disable autoreset feature */
+
+ /* Program clock select. */
+ ApmReg->EX[XREC] = comp_lmn(pApm, mode->Clock);
+ if (!ApmReg->EX[XREC])
+ return FALSE;
+ hwp->ModeReg.MiscOutReg |= 0x0C;
+
+ /* Set up the RAMDAC registers. */
+
+ if (pApm->CurrentLayout.bitsPerPixel > 8)
+ /* Get rid of white border. */
+ hwp->ModeReg.Attribute[0x11] = 0x00;
+ else
+ hwp->ModeReg.Attribute[0x11] = 0xFF;
+ if (pApm->MemClk)
+ ApmReg->EX[XRE8] = comp_lmn(pApm, pApm->MemClk);
+ else if (pApm->Chipset >= AT3D)
+ ApmReg->EX[XRE8] = 0x071F01E8; /* Enable 58MHz MCLK (actually 57.3 MHz)
+ This is what is used in the Windows
+ drivers. The BIOS sets it to 50MHz. */
+ else if (!pApm->noLinear)
+ ApmReg->EX[XRE8] = RDXL(0xE8); /* No change */
+ else
+ ApmReg->EX[XRE8] = RDXL_IOP(0xE8); /* No change */
+
+ ApmReg->EX[XRE0] = 0x10;
+
+ /* If you change it, change in apm_funcs.c as well */
+ if (pApm->Chipset >= AT3D) {
+ ApmReg->SEQ[0x1B] = 0x20;
+ ApmReg->SEQ[0x1C] = 0x2F;
+ }
+ else {
+ ApmReg->SEQ[0x1B] = 0x24;
+ if (pScrn->videoRam >= 6 * 1024)
+ ApmReg->SEQ[0x1C] = 0x2F;
+ else
+ ApmReg->SEQ[0x1C] = 0x2D;
+ }
+
+ /* ICICICICI */
+ ApmRestore(pScrn, &hwp->ModeReg, ApmReg);
+
+ return TRUE;
+}
+
+/*
+ * Restore the initial mode.
+ */
+static void
+ApmRestore(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, ApmRegPtr ApmReg)
+{
+ APMDECL(pScrn);
+
+ vgaHWProtect(pScrn, TRUE);
+ ApmUnlock(pApm);
+
+ if (pApm->VGAMap) {
+ /*
+ * Restore fonts
+ */
+ if (!(vgaReg->Attribute[0x10] & 1) && pApm->FontInfo) {
+ ApmWriteSeq(0x1C, 0x3F);
+ memcpy(pApm->FbBase, pApm->FontInfo, TEXT_AMOUNT);
+ }
+
+ /* Set aperture index to 0. */
+ WRXW(0xC0, 0);
+
+ /*
+ * Write the extended registers first
+ */
+ ApmWriteSeq(0x1B, ApmReg->SEQ[0x1B]);
+ ApmWriteSeq(0x1C, ApmReg->SEQ[0x1C]);
+
+ /* Hardware cursor registers. */
+ WRXL(0x140, ApmReg->EX[XR140]);
+ WRXW(0x144, ApmReg->EX[XR144]);
+ WRXL(0x148, ApmReg->EX[XR148]);
+ WRXW(0x14C, ApmReg->EX[XR14C]);
+
+ ApmWriteCrtc(0x19, ApmReg->CRT[0x19]);
+ ApmWriteCrtc(0x1A, ApmReg->CRT[0x1A]);
+ ApmWriteCrtc(0x1B, ApmReg->CRT[0x1B]);
+ ApmWriteCrtc(0x1C, ApmReg->CRT[0x1C]);
+ ApmWriteCrtc(0x1D, ApmReg->CRT[0x1D]);
+ ApmWriteCrtc(0x1E, ApmReg->CRT[0x1E]);
+
+ /* RAMDAC registers. */
+ WRXL(0xE8, ApmReg->EX[XRE8]);
+ WRXL(0xEC, ApmReg->EX[XREC] & ~(1 << 7));
+ WRXL(0xEC, ApmReg->EX[XREC] | (1 << 7)); /* Do a PLL resync */
+
+ /* Color correction */
+ WRXL(0xE0, ApmReg->EX[XRE0]);
+
+ WRXB(0x80, ApmReg->EX[XR80]);
+
+ /*
+ * This function handles restoring the generic VGA registers.
+ */
+ vgaHWRestore(pScrn, vgaReg, VGA_SR_MODE | VGA_SR_CMAP);
+ }
+ else {
+ /* Set aperture index to 0. */
+ if (pApm->noLinear)
+ WRXW_IOP(0xC0, 0);
+ else
+ WRXW(0xC0, 0);
+
+ /*
+ * Write the extended registers first
+ */
+ wrinx(pApm->xport, 0x1B, ApmReg->SEQ[0x1B]);
+ wrinx(pApm->xport, 0x1C, ApmReg->SEQ[0x1C]);
+
+ /* Hardware cursor registers. */
+ if (pApm->noLinear) {
+ WRXL_IOP(0x140, ApmReg->EX[XR140]);
+ WRXW_IOP(0x144, ApmReg->EX[XR144]);
+ WRXL_IOP(0x148, ApmReg->EX[XR148]);
+ WRXW_IOP(0x14C, ApmReg->EX[XR14C]);
+ }
+ else {
+ WRXL(0x140, ApmReg->EX[XR140]);
+ WRXW(0x144, ApmReg->EX[XR144]);
+ WRXL(0x148, ApmReg->EX[XR148]);
+ WRXW(0x14C, ApmReg->EX[XR14C]);
+ }
+
+ wrinx(pApm->iobase + 0x3D4, 0x19, ApmReg->CRT[0x19]);
+ wrinx(pApm->iobase + 0x3D4, 0x1A, ApmReg->CRT[0x1A]);
+ wrinx(pApm->iobase + 0x3D4, 0x1B, ApmReg->CRT[0x1B]);
+ wrinx(pApm->iobase + 0x3D4, 0x1C, ApmReg->CRT[0x1C]);
+ wrinx(pApm->iobase + 0x3D4, 0x1D, ApmReg->CRT[0x1D]);
+ wrinx(pApm->iobase + 0x3D4, 0x1E, ApmReg->CRT[0x1E]);
+
+ /* RAMDAC registers. */
+ if (pApm->noLinear) {
+ WRXL_IOP(0xE8, ApmReg->EX[XRE8]);
+ WRXL_IOP(0xEC, ApmReg->EX[XREC] & ~(1 << 7));
+ WRXL_IOP(0xEC, ApmReg->EX[XREC] | (1 << 7)); /* Do a PLL resync */
+ }
+ else {
+ WRXL(0xE8, ApmReg->EX[XRE8]);
+ WRXL(0xEC, ApmReg->EX[XREC] & ~(1 << 7));
+ WRXL(0xEC, ApmReg->EX[XREC] | (1 << 7)); /* Do a PLL resync */
+ }
+
+ /* Color correction */
+ if (pApm->noLinear)
+ WRXL_IOP(0xE0, ApmReg->EX[XRE0]);
+ else
+ WRXL(0xE0, ApmReg->EX[XRE0]);
+
+ if (pApm->noLinear)
+ WRXB_IOP(0x80, ApmReg->EX[XR80]);
+ else
+ WRXB(0x80, ApmReg->EX[XR80]);
+
+ /*
+ * This function handles restoring the generic VGA registers.
+ */
+ vgaHWRestore(pScrn, vgaReg, VGA_SR_ALL);
+ }
+
+ vgaHWProtect(pScrn, FALSE);
+}
+
+
+/* Refresh a region of the shadow framebuffer to the screen */
+static void
+ApmRefreshArea(ScrnInfoPtr pScrn, int num, BoxPtr pbox)
+{
+ APMDECL(pScrn);
+ int width, height, Bpp, FBPitch;
+ unsigned char *src, *dst;
+
+ Bpp = pApm->CurrentLayout.bitsPerPixel >> 3;
+ FBPitch = pApm->CurrentLayout.bytesPerScanline;
+
+ while(num--) {
+ width = (pbox->x2 - pbox->x1) * Bpp;
+ height = pbox->y2 - pbox->y1;
+ src = pApm->ShadowPtr + (pbox->y1 * pApm->ShadowPitch) +
+ (pbox->x1 * Bpp);
+ dst = (unsigned char *)pApm->FbBase + (pbox->y1 * FBPitch) + (pbox->x1 * Bpp);
+
+ while(height--) {
+ memcpy(dst, src, width);
+ dst += FBPitch;
+ src += pApm->ShadowPitch;
+ }
+
+ pbox++;
+ }
+}
+
+
+/* Mandatory */
+
+/* This gets called at the start of each server generation */
+
+static Bool
+ApmScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ APMDECL(pScrn);
+ int ret;
+ unsigned char *FbBase;
+
+ pApm->pScreen = pScreen;
+
+ /* Map the chip memory and MMIO areas */
+ if (pApm->noLinear) {
+ pApm->saveCmd = pciReadLong(pApm->PciTag, PCI_CMD_STAT_REG);
+ pciWriteLong(pApm->PciTag, PCI_CMD_STAT_REG, pApm->saveCmd | (PCI_CMD_IO_ENABLE|PCI_CMD_MEM_ENABLE));
+ pApm->FbBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
+ pApm->PciTag, 0xA0000, 0x10000);
+ }
+ else
+ if (!ApmMapMem(pScrn))
+ return FALSE;
+
+ /* No memory reserved yet */
+ pApm->OffscreenReserved = 0;
+
+ /* Save the current state */
+ ApmSave(pScrn);
+
+ /* Initialise the first mode */
+ ApmModeInit(pScrn, pScrn->currentMode);
+ pApm->CurrentLayout.pMode = pScrn->currentMode;
+
+ /* Darken the screen for aesthetic reasons and set the viewport */
+ ApmSaveScreen(pScreen, SCREEN_SAVER_ON);
+ ApmAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
+
+ /*
+ * Reset fb's visual list.
+ */
+ miClearVisualTypes();
+
+ /* Setup the visuals we support. */
+
+ /*
+ * For bpp > 8, the default visuals are not acceptable because we only
+ * support TrueColor and not DirectColor. To deal with this, call
+ * miSetVisualTypes for each visual supported.
+ */
+
+ if (pApm->CurrentLayout.bitsPerPixel > 8) {
+ if (!miSetVisualTypes(pScrn->depth, TrueColorMask, pScrn->rgbBits,
+ pScrn->defaultVisual))
+ return FALSE;
+ } else {
+ if (!miSetVisualTypes(pScrn->depth,
+ miGetDefaultVisualMask(pScrn->depth),
+ pScrn->rgbBits, pScrn->defaultVisual))
+ return FALSE;
+ }
+
+ /*
+ * Call the framebuffer layer's ScreenInit function, and fill in other
+ * pScreen fields.
+ */
+
+ if(pApm->ShadowFB) {
+ pApm->ShadowPitch =
+ ((pScrn->virtualX * pScrn->bitsPerPixel >> 3) + 3) & ~3L;
+ pApm->ShadowPtr = xalloc(pApm->ShadowPitch * pScrn->virtualY);
+ FbBase = pApm->ShadowPtr;
+ } else {
+ pApm->ShadowPtr = NULL;
+ FbBase = pApm->FbBase;
+ }
+
+ /* Reserve memory */
+ ApmHWCursorReserveSpace(pApm);
+ ApmAccelReserveSpace(pApm);
+
+ miSetPixmapDepths();
+
+ switch (pScrn->bitsPerPixel) {
+ case 1:
+ ret = xf1bppScreenInit(pScreen, FbBase,
+ pScrn->virtualX, pScrn->virtualY,
+ pScrn->xDpi, pScrn->yDpi,
+ pScrn->displayWidth);
+ break;
+ case 4:
+ ret = xf4bppScreenInit(pScreen, FbBase,
+ pScrn->virtualX, pScrn->virtualY,
+ pScrn->xDpi, pScrn->yDpi,
+ pScrn->displayWidth);
+ break;
+ case 8:
+ case 16:
+ case 24:
+ case 32:
+ ret = fbScreenInit(pScreen, FbBase, pScrn->virtualX,
+ pScrn->virtualY, pScrn->xDpi, pScrn->yDpi,
+ pScrn->displayWidth, pScrn->bitsPerPixel);
+ break;
+ default:
+ xf86DrvMsg(scrnIndex, X_ERROR,
+ "Internal error: invalid bpp (%d) in ApmScrnInit\n",
+ pScrn->bitsPerPixel);
+ ret = FALSE;
+ break;
+ }
+ if (!ret)
+ return FALSE;
+
+ if (pScrn->bitsPerPixel > 8) {
+ VisualPtr visual;
+
+ /* Fixup RGB ordering */
+ visual = pScreen->visuals + pScreen->numVisuals;
+ while (--visual >= pScreen->visuals) {
+ if ((visual->class | DynamicClass) == DirectColor) {
+ visual->offsetRed = pScrn->offset.red;
+ visual->offsetGreen = pScrn->offset.green;
+ visual->offsetBlue = pScrn->offset.blue;
+ visual->redMask = pScrn->mask.red;
+ visual->greenMask = pScrn->mask.green;
+ visual->blueMask = pScrn->mask.blue;
+ }
+ }
+ }
+
+ /* must be after visual RGB order fixed */
+ if (pScrn->bitsPerPixel > 4)
+ fbPictureInit(pScreen, 0, 0);
+
+ xf86SetBlackWhitePixels(pScreen);
+
+ if (!pApm->ShadowFB) { /* hardware cursor needs to wrap this layer */
+ if(!ApmDGAInit(pScreen)) {
+ xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"DGA initialization failed\n");
+ }
+ }
+
+ miInitializeBackingStore(pScreen);
+ xf86SetBackingStore(pScreen);
+ xf86SetSilkenMouse(pScreen);
+
+ /* Initialise cursor functions */
+ miDCInitialize (pScreen, xf86GetPointerScreenFuncs());
+
+ /* Initialize HW cursor layer (after DGA and SW cursor) */
+ if (pApm->hwCursor) {
+ if (!ApmHWCursorInit(pScreen))
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Hardware cursor initialization failed\n");
+ }
+
+ /*
+ * Initialize the acceleration interface.
+ */
+ if (!pApm->NoAccel) {
+ ApmAccelInit(pScreen); /* set up XAA interface */
+ }
+
+ /* Initialise default colourmap */
+ if (!miCreateDefColormap(pScreen))
+ return FALSE;
+
+ /*
+ * Initialize colormap layer.
+ * Must follow initialization of the default colormap.
+ */
+ if (!xf86HandleColormaps(pScreen, 256, 8, ApmLoadPalette, NULL,
+ CMAP_RELOAD_ON_MODE_SWITCH)) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Colormap initialization failed\n");
+ return FALSE;
+ }
+
+ if (pApm->ShadowFB)
+ ShadowFBInit(pScreen, ApmRefreshArea);
+
+ xf86DPMSInit(pScreen, ApmDisplayPowerManagementSet, 0);
+
+ if (pApm->noLinear)
+ ApmInitVideo_IOP(pScreen);
+ else
+ ApmInitVideo(pScreen);
+
+ pScreen->SaveScreen = ApmSaveScreen;
+
+ pApm->CloseScreen = pScreen->CloseScreen;
+ pScreen->CloseScreen = ApmCloseScreen;
+
+ pScrn->memPhysBase = pApm->LinAddress;
+ pScrn->fbOffset = (((char *)pApm->FbBase) - ((char *)pApm->LinMap));
+
+ /* Report any unused options (only for the first generation) */
+ if (serverGeneration == 1) {
+ xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
+ }
+
+ if (ApmGeneration != serverGeneration) {
+ if ((ApmPixmapIndex = AllocatePixmapPrivateIndex()) < 0)
+ return FALSE;
+ ApmGeneration = serverGeneration;
+ }
+
+ if (!AllocatePixmapPrivate(pScreen, ApmPixmapIndex, sizeof(ApmPixmapRec)))
+ return FALSE;
+
+ /* Done */
+ return TRUE;
+}
+
+/* mandatory */
+static void
+ApmLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors,
+ VisualPtr pVisual)
+{
+ APMDECL(pScrn);
+ int i, index, last = -1;
+
+ if (pApm->VGAMap) {
+ for (i = 0; i < numColors; i++) {
+ index = indices[i];
+ if (index != last)
+ ApmWriteDacWriteAddr(index);
+ last = index + 1;
+ ApmWriteDacData(colors[index].red);
+ ApmWriteDacData(colors[index].green);
+ ApmWriteDacData(colors[index].blue);
+ }
+ }
+ else {
+ for (i = 0; i < numColors; i++) {
+ index = indices[i];
+ if (index != last)
+ outb(pApm->iobase + 0x3C8, index);
+ last = index + 1;
+ outb(pApm->iobase + 0x3C9, colors[index].red);
+ outb(pApm->iobase + 0x3C9, colors[index].green);
+ outb(pApm->iobase + 0x3C9, colors[index].blue);
+ }
+ }
+}
+
+/* Usually mandatory */
+Bool
+ApmSwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
+{
+ return ApmModeInit(xf86Screens[scrnIndex], mode);
+}
+
+/*
+ * This function is used to initialize the Start Address - the first
+ * displayed location in the video memory.
+ */
+/* Usually mandatory */
+void
+ApmAdjustFrame(int scrnIndex, int x, int y, int flags)
+{
+ ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+ APMDECL(pScrn);
+ int Base;
+
+ if (pApm->CurrentLayout.bitsPerPixel == 24)
+ x = (x + 3) & ~3;
+ Base = ((y * pApm->CurrentLayout.displayWidth + x) * (pApm->CurrentLayout.bitsPerPixel / 8)) >> 2;
+ /*
+ * These are the generic starting address registers.
+ */
+ if (pApm->VGAMap) {
+ ApmWriteCrtc(0x0C, Base >> 8);
+ ApmWriteCrtc(0x0D, Base);
+
+ /*
+ * Here the high-order bits are masked and shifted, and put into
+ * the appropriate extended registers.
+ */
+ ApmWriteCrtc(0x1C, (ApmReadCrtc(0x1C) & 0xF0) | ((Base & 0x0F0000) >> 16));
+ }
+ else {
+ outw(pApm->iobase + 0x3D4, (Base & 0x00FF00) | 0x0C);
+ outw(pApm->iobase + 0x3D4, ((Base & 0x00FF) << 8) | 0x0D);
+
+ /*
+ * Here the high-order bits are masked and shifted, and put into
+ * the appropriate extended registers.
+ */
+ modinx(pApm->iobase + 0x3D4, 0x1C, 0x0F, (Base & 0x0F0000) >> 16);
+ }
+}
+
+/*
+ * This is called when VT switching back to the X server. Its job is
+ * to reinitialise the video mode.
+ *
+ * We may wish to unmap video/MMIO memory too.
+ */
+
+/* Mandatory */
+static Bool
+ApmEnterVT(int scrnIndex, int flags)
+{
+ ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+ APMDECL(pScrn);
+ vgaHWPtr hwp = VGAHWPTR(pScrn);
+
+ if (pApm->Chipset >= AT3D) {
+ if (!pApm->noLinear) {
+ /* If you change it, change it also in apm_funcs.c */
+ WRXB(0xDB, (pApm->db & 0xF4) | 0x0A | pApm->Rush);
+ WRXB(0xD9, (pApm->d9 & 0xCF) | 0x20);
+ }
+ else {
+ WRXB_IOP(0xDB, pApm->db & 0xF4);
+ }
+ }
+ if (pApm->Chipset >= AP6422)
+ WRXB(0xC9, pApm->c9 | 0x10);
+ ApmUnlock(APMPTR(pScrn));
+ vgaHWUnlock(hwp);
+ /*
+ * Set color mode
+ */
+ hwp->writeMiscOut(hwp, pApm->MiscOut | 0x0F);
+
+ if (!ApmModeInit(pScrn, pScrn->currentMode))
+ return FALSE;
+ ApmAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
+
+ return TRUE;
+}
+
+/* Mandatory */
+static void
+ApmLeaveVT(int scrnIndex, int flags)
+{
+ ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+ APMDECL(pScrn);
+ vgaHWPtr hwp = VGAHWPTR(pScrn);
+
+ ApmRestore(pScrn, &hwp->SavedReg, &pApm->SavedReg);
+ /*
+ * Reset color mode
+ */
+ (*hwp->writeMiscOut)(hwp, pApm->MiscOut);
+ vgaHWLock(hwp);
+ ApmLock(pApm);
+ if (pApm->Chipset >= AT3D) {
+ if (!pApm->noLinear) {
+ WRXB(0xD9, pApm->d9);
+ WRXB(0xDB, pApm->db);
+ }
+ else {
+ WRXB_IOP(0xD9, pApm->d9);
+ WRXB_IOP(0xDB, pApm->db);
+ }
+ }
+ WRXB(0xC9, pApm->c9);
+
+ if (xf86IsPc98())
+ outb(0xFAC, 0xFE);
+}
+
+/*
+ * This is called at the end of each server generation. It restores the
+ * original (text) mode. It should really also unmap the video memory too.
+ */
+
+/* Mandatory */
+static Bool
+ApmCloseScreen(int scrnIndex, ScreenPtr pScreen)
+{
+ ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+ vgaHWPtr hwp = VGAHWPTR(pScrn);
+ APMDECL(pScrn);
+
+ if (pScrn->vtSema) {
+ ApmRestore(pScrn, &hwp->SavedReg, &pApm->SavedReg);
+ vgaHWLock(hwp);
+ ApmUnmapMem(pScrn);
+ }
+ if(pApm->AccelInfoRec)
+ XAADestroyInfoRec(pApm->AccelInfoRec);
+ if(pApm->DGAXAAInfo)
+ XAADestroyInfoRec(pApm->DGAXAAInfo);
+ pApm->AccelInfoRec = NULL;
+ if(pApm->CursorInfoRec)
+ xf86DestroyCursorInfoRec(pApm->CursorInfoRec);
+ pApm->CursorInfoRec = NULL;
+ if (pApm->DGAModes)
+ xfree(pApm->DGAModes);
+ if (pApm->I2CPtr)
+ xf86DestroyI2CBusRec(pApm->I2CPtr, TRUE, TRUE);
+ pApm->I2CPtr = NULL;
+ if (pApm->adaptor)
+ xfree(pApm->adaptor);
+
+ pScrn->vtSema = FALSE;
+
+ if (xf86IsPc98())
+ outb(0xFAC, 0xFE);
+
+ pScreen->CloseScreen = pApm->CloseScreen;
+ return (*pScreen->CloseScreen)(scrnIndex, pScreen);
+}
+
+/* Free up any per-generation data structures */
+
+/* Optional */
+static void
+ApmFreeScreen(int scrnIndex, int flags)
+{
+ vgaHWFreeHWRec(xf86Screens[scrnIndex]);
+ ApmFreeRec(xf86Screens[scrnIndex]);
+}
+
+/* Checks if a mode is suitable for the selected chipset. */
+
+/* Optional */
+static int
+ApmValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags)
+{
+ if (mode->Flags & V_INTERLACE)
+ return(MODE_BAD);
+
+ return(MODE_OK);
+}
+
+
+/*
+ * ApmDisplayPowerManagementSet --
+ *
+ * Sets VESA Display Power Management Signaling (DPMS) Mode.
+ */
+static void
+ApmDisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode,
+ int flags)
+{
+ APMDECL(pScrn);
+ unsigned char dpmsreg, tmp;
+
+ if (PowerManagementMode < sizeof pApm->DPMSMask &&
+ PowerManagementMode >= 0)
+ PowerManagementMode = pApm->DPMSMask[PowerManagementMode];
+ switch (PowerManagementMode)
+ {
+ case DPMSModeOn:
+ /* Screen: On; HSync: On, VSync: On */
+ dpmsreg = 0x00;
+ break;
+ case DPMSModeStandby:
+ /* Screen: Off; HSync: Off, VSync: On */
+ dpmsreg = 0x01;
+ break;
+ case DPMSModeSuspend:
+ /* Screen: Off; HSync: On, VSync: Off */
+ dpmsreg = 0x02;
+ break;
+ case DPMSModeOff:
+ /* Screen: Off; HSync: Off, VSync: Off */
+ dpmsreg = 0x03;
+ break;
+ default:
+ dpmsreg = 0;
+ }
+ if (pApm->noLinear) {
+ tmp = RDXB_IOP(0xD0);
+ WRXB_IOP(0xD0, (tmp & 0xFC) | dpmsreg);
+ } else {
+ tmp = RDXB(0xD0);
+ WRXB(0xD0, (tmp & 0xFC) | dpmsreg);
+ }
+}
+
+static Bool
+ApmSaveScreen(ScreenPtr pScreen, int mode)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ Bool unblank;
+
+ unblank = xf86IsUnblank(mode);
+
+ if (unblank)
+ SetTimeSinceLastInputEvent();
+
+ if (pScrn->vtSema)
+ vgaHWBlankScreen(pScrn, unblank);
+ return TRUE;
+}
+
+#ifdef APM_DEBUG
+unsigned char _L_ACR(unsigned char *x);
+unsigned char _L_ACR(unsigned char *x)
+{
+ return *x;
+}
+
+unsigned short _L_ASR(unsigned short *x);
+unsigned short _L_ASR(unsigned short *x)
+{
+ return *x;
+}
+
+unsigned int _L_AIR(unsigned int *x);
+unsigned int _L_AIR(unsigned int *x)
+{
+ return *x;
+}
+
+void _L_ACW(char *x, char y);
+void _L_ACW(char *x, char y)
+{
+ *x = y;
+}
+
+void _L_ASW(short *x, short y);
+void _L_ASW(short *x, short y)
+{
+ *x = y;
+}
+
+void _L_AIW(int *x, int y);
+void _L_AIW(int *x, int y)
+{
+ *x = y;
+}
+#endif