#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
#define TEXT_AMOUNT 32768
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 ModeStatus 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}
};
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",
"XAAReverseBitOrder",
"XAAStippleScanlineFuncMSBFirst",
NULL
};
static const char *ramdacSymbols[] = {
"xf86CreateCursorInfoRec",
"xf86DestroyCursorInfoRec",
"xf86InitCursor",
NULL
};
#ifdef XFree86LOADER
static const char *vbeSymbols[] = {
"VBEInit",
"vbeDoEDID",
"vbeFree",
NULL
};
#endif
static const char *ddcSymbols[] = {
"xf86DoEDID_DDC1",
"xf86DoEDID_DDC2",
"xf86PrintEDID",
NULL
};
static const char *i2cSymbols[] = {
"xf86CreateI2CBusRec",
"xf86I2CBusInit",
NULL
};
static const char *shadowSymbols[] = {
"ShadowFBInit",
NULL
};
#ifdef XFree86LOADER
static const char *miscfbSymbols[] = {
"xf1bppScreenInit",
"xf4bppScreenInit",
NULL
};
#endif
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,
ABI_VIDEODRV_VERSION,
MOD_CLASS_VIDEODRV,
{0,0,0,0}
};
static MODULESETUPPROTO(apmSetup);
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);
return TRUE;
}
static void
ApmFreeRec(ScrnInfoPtr pScrn)
{
if (pScrn->driverPrivate) {
xfree(pScrn->driverPrivate);
pScrn->driverPrivate = NULL;
}
}
static void
ApmUnlock(ApmPtr pApm)
{
if (pApm->Chipset >= AT3D && !pApm->noLinear)
ApmWriteSeq(0x10, 0x12);
else
wrinx(pApm->xport, 0x10, 0x12);
}
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;
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[] = " ";
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))) {
}
}
}
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;
if ((numDevSections = xf86MatchDevice(APM_DRIVER_NAME,
&DevSections)) <= 0)
return FALSE;
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;
pScrn = NULL;
if ((pScrn = xf86ConfigPciEntity(pScrn, 0, usedChips[i],
ApmPciChipsets, NULL,
NULL,NULL,NULL,NULL))){
ApmAssignFPtr(pScrn);
foundScreen = TRUE;
}
}
}
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))) {
ApmAssignFPtr(pScrn);
foundScreen = TRUE;
}
}
}
xfree(DevSections);
return foundScreen;
}
static int *
GetAccelPitchValues(ScrnInfoPtr pScrn)
{
int *linePitches = NULL;
int linep[] = {640, 800, 1024, 1152, 1280, 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;
if (pScrn->numEntities != 1)
return FALSE;
if (!ApmGetRec(pScrn)) {
return FALSE;
}
pApm = APMPTR(pScrn);
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;
}
if (!xf86LoadSubModule(pScrn, "vgahw"))
return FALSE;
xf86LoaderReqSymLists(vgahwSymbols, NULL);
if (!vgaHWGetHWRec(pScrn))
return FALSE;
hwp = VGAHWPTR(pScrn);
vgaHWGetIOBase(hwp);
pApm->iobase = hwp->PIOOffset;
pApm->xport = hwp->PIOOffset + 0x3C4;
pScrn->monitor = pScrn->confScreen->monitor;
if (!xf86SetDepthBpp(pScrn, 0, 0, 0, Support24bppFb | Support32bppFb)) {
return FALSE;
} else {
switch (pScrn->depth) {
case 4:
case 8:
case 15:
case 16:
case 24:
break;
default:
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Given depth (%d) is not supported by this driver\n",
pScrn->depth);
return FALSE;
}
}
xf86PrintDepthBpp(pScrn);
if (pScrn->depth > 8) {
rgb zeros = {0, 0, 0};
if (!xf86SetWeight(pScrn, zeros, zeros)) {
return FALSE;
} else {
;
}
}
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;
}
}
pScrn->progClock = TRUE;
xf86CollectOptions(pScrn, NULL);
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;
if (pScrn->depth > 1 && pScrn->depth <= 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;
}
}
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;
}
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 {
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) {
pApm->LinMapSize = 4 * 1024 * 1024 ;
pApm->FbMapSize = 4 * 1024 * 1024 ;
if (pApm->Chipset >= AT3D)
pApm->LinAddress += 8 * 1024 * 1024 ;
}
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;
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;
volatile unsigned char *LinMap;
LinMap = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
pApm->PciTag, pApm->LinAddress,
pApm->LinMapSize);
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;
xf86UnMapVidMem(pScrn->scrnIndex, (pointer)LinMap, pApm->LinMapSize);
from = X_PROBED;
}
else {
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);
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;
}
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);
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)
{
case AT24:
switch(pScrn->bitsPerPixel)
{
case 4:
case 8:
pApm->MaxClock = 160000;
break;
case 16:
pApm->MaxClock = 144000;
break;
case 24:
pApm->MaxClock = 75000;
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;
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);
clockRanges = (ClockRangePtr)xnfcalloc(sizeof(ClockRange), 1);
clockRanges->next = NULL;
clockRanges->minClock = pApm->MinClock;
clockRanges->maxClock = pApm->MaxClock;
clockRanges->clockIndex = -1;
clockRanges->interlaceAllowed = FALSE;
clockRanges->doubleScanAllowed = FALSE;
if (pApm->NoAccel) {
i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
pScrn->display->modes, clockRanges,
NULL, 256, 2048,
pScrn->bitsPerPixel, 128, 1024,
pScrn->display->virtualX,
pScrn->display->virtualY,
pApm->FbMapSize,
LOOKUP_BEST_REFRESH);
} else {
i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
pScrn->display->modes, clockRanges,
GetAccelPitchValues(pScrn), 0, 0,
pScrn->bitsPerPixel, 128, 1024,
pScrn->display->virtualX,
pScrn->display->virtualY,
pApm->FbMapSize,
LOOKUP_BEST_REFRESH);
}
if (i == -1) {
ApmFreeRec(pScrn);
return FALSE;
}
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);
pScrn->currentMode = pScrn->modes;
xf86PrintModes(pScrn);
xf86SetDpi(pScrn, 0, 0);
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);
}
}
if (!pApm->NoAccel) {
if (!xf86LoadSubModule(pScrn, "xaa")) {
ApmFreeRec(pScrn);
return FALSE;
}
xf86LoaderReqSymLists(xaaSymbols, NULL);
}
if (pApm->hwCursor) {
if (!xf86LoadSubModule(pScrn, "ramdac")) {
ApmFreeRec(pScrn);
return FALSE;
}
xf86LoaderReqSymLists(ramdacSymbols, NULL);
}
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;
}
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);
}
}
pApm->c9 = RDXB(0xC9);
if (pApm->Chipset >= AT3D) {
pApm->d9 = RDXB(0xD9);
pApm->db = RDXB(0xDB);
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;
if (pApm->Chipset >= AT3D) {
pApm->d9 = RDXB_IOP(0xD9);
pApm->db = RDXB_IOP(0xDB);
WRXB_IOP(0xDB, pApm->db & 0xF4);
}
}
pApm->MiscOut = hwp->readMiscOut(hwp);
return TRUE;
}
static Bool
ApmUnmapMem(ScrnInfoPtr pScrn)
{
APMDECL(pScrn);
vgaHWPtr hwp = VGAHWPTR(pScrn);
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;
}
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);
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);
}
}
vgaHWSave(pScrn, &hwp->SavedReg, VGA_SR_MODE | VGA_SR_CMAP);
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);
ApmReg->EX[XRE8] = RDXL(0xE8);
ApmReg->EX[XREC] = RDXL(0xEC);
ApmReg->EX[XRE0] = RDXL(0xE0);
ApmReg->EX[XR80] = RDXB(0x80);
}
else {
vgaHWSave(pScrn, &hwp->SavedReg, VGA_SR_ALL);
ApmReg->SEQ[0x1B] = rdinx(pApm->xport, 0x1B);
ApmReg->SEQ[0x1C] = rdinx(pApm->xport, 0x1C);
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) {
ApmReg->EX[XRE8] = RDXL_IOP(0xE8);
ApmReg->EX[XREC] = RDXL_IOP(0xEC);
ApmReg->EX[XRE0] = RDXL_IOP(0xE0);
ApmReg->EX[XR80] = RDXB_IOP(0x80);
}
else {
ApmReg->EX[XRE8] = RDXL(0xE8);
ApmReg->EX[XREC] = RDXL(0xEC);
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;
double fout_best = 0;
unsigned int best = 0;
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.99*fvco_goal, 1.01*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;
if (fout_best != 0) {
double diff_new = clock - fout;
double diff_old = clock - best;
diff_new = diff_new < 0 ? -diff_new : diff_new;
diff_old = diff_old < 0 ? -diff_old : diff_old;
if (diff_new > diff_old)
continue;
}
fout_best = fout;
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 {
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;
}
best = (n << 16) | (m << 8) | (l << 2) | (f << 4);
}
}
}
if (fout_best != 0)
return best;
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;
}
static Bool
ApmModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
{
APMDECL(pScrn);
ApmRegPtr ApmReg = &pApm->ModeReg;
vgaHWPtr hwp;
if (pScrn->progClock)
mode->ClockIndex = 2;
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);
{
int offset;
offset = (pApm->CurrentLayout.displayWidth *
pApm->CurrentLayout.bitsPerPixel / 8) >> 3;
hwp->ModeReg.CRTC[0x13] = offset;
ApmReg->CRT[0x1C] = (offset & 0xF00) >> 4;
}
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;
}
ApmReg->EX[XRC0] = 0;
{
unsigned char val;
val = 0;
if ((mode->CrtcVTotal - 2) & 0x400)
val |= 0x01;
if ((mode->CrtcVDisplay - 1) & 0x400)
val |= 0x02;
if (mode->CrtcVSyncStart & 0x400)
val |= 0x04;
if (mode->CrtcVSyncStart & 0x400)
val |= 0x08;
ApmReg->CRT[0x1A] = val;
val = 0;
if ((mode->CrtcHTotal / 8 - 5) & 0x100)
val |= 1;
if ((mode->CrtcHDisplay / 8 - 1) & 0x100)
val |= 2;
if ((mode->CrtcHSyncStart / 8 - 1) & 0x100)
val |= 4;
if ((mode->CrtcHSyncStart / 8) & 0x100)
val |= 8;
ApmReg->CRT[0x1B] = val;
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;
ApmReg->EX[XREC] = comp_lmn(pApm, mode->Clock);
if (!ApmReg->EX[XREC])
return FALSE;
hwp->ModeReg.MiscOutReg |= 0x0C;
if (pApm->CurrentLayout.bitsPerPixel > 8)
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;
else if (!pApm->noLinear)
ApmReg->EX[XRE8] = RDXL(0xE8);
else
ApmReg->EX[XRE8] = RDXL_IOP(0xE8);
ApmReg->EX[XRE0] = 0x10;
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;
}
ApmRestore(pScrn, &hwp->ModeReg, ApmReg);
return TRUE;
}
static void
ApmRestore(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, ApmRegPtr ApmReg)
{
APMDECL(pScrn);
vgaHWProtect(pScrn, TRUE);
ApmUnlock(pApm);
if (pApm->VGAMap) {
if (!(vgaReg->Attribute[0x10] & 1) && pApm->FontInfo) {
ApmWriteSeq(0x1C, 0x3F);
memcpy(pApm->FbBase, pApm->FontInfo, TEXT_AMOUNT);
}
WRXW(0xC0, 0);
ApmWriteSeq(0x1B, ApmReg->SEQ[0x1B]);
ApmWriteSeq(0x1C, ApmReg->SEQ[0x1C]);
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(0x1D, ApmReg->CRT[0x1D]);
ApmWriteCrtc(0x1E, ApmReg->CRT[0x1E]);
WRXL(0xE8, ApmReg->EX[XRE8]);
WRXL(0xEC, ApmReg->EX[XREC] & ~(1 << 7));
WRXL(0xEC, ApmReg->EX[XREC] | (1 << 7));
WRXL(0xE0, ApmReg->EX[XRE0]);
vgaHWRestore(pScrn, vgaReg, VGA_SR_MODE | VGA_SR_CMAP);
ApmWriteCrtc(0x1C, ApmReg->CRT[0x1C]);
WRXB(0x80, ApmReg->EX[XR80]);
}
else {
if (pApm->noLinear)
WRXW_IOP(0xC0, 0);
else
WRXW(0xC0, 0);
wrinx(pApm->xport, 0x1B, ApmReg->SEQ[0x1B]);
wrinx(pApm->xport, 0x1C, ApmReg->SEQ[0x1C]);
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]);
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));
}
else {
WRXL(0xE8, ApmReg->EX[XRE8]);
WRXL(0xEC, ApmReg->EX[XREC] & ~(1 << 7));
WRXL(0xEC, ApmReg->EX[XREC] | (1 << 7));
}
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]);
vgaHWRestore(pScrn, vgaReg, VGA_SR_ALL);
}
vgaHWProtect(pScrn, FALSE);
}
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++;
}
}
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;
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;
pApm->OffscreenReserved = 0;
ApmSave(pScrn);
ApmModeInit(pScrn, pScrn->currentMode);
pApm->CurrentLayout.pMode = pScrn->currentMode;
ApmSaveScreen(pScreen, SCREEN_SAVER_ON);
ApmAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
miClearVisualTypes();
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;
}
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;
}
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;
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;
}
}
}
if (pScrn->bitsPerPixel > 4)
fbPictureInit(pScreen, 0, 0);
xf86SetBlackWhitePixels(pScreen);
if (!pApm->ShadowFB) {
if(!ApmDGAInit(pScreen)) {
xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"DGA initialization failed\n");
}
}
if (!pApm->NoAccel) {
ApmAccelInit(pScreen);
}
miInitializeBackingStore(pScreen);
xf86SetBackingStore(pScreen);
xf86SetSilkenMouse(pScreen);
miDCInitialize (pScreen, xf86GetPointerScreenFuncs());
if (pApm->hwCursor) {
if (!ApmHWCursorInit(pScreen))
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Hardware cursor initialization failed\n");
}
if (!miCreateDefColormap(pScreen))
return FALSE;
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));
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;
return TRUE;
}
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);
}
}
}
Bool
ApmSwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
{
return ApmModeInit(xf86Screens[scrnIndex], mode);
}
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;
if (pApm->VGAMap) {
ApmWriteCrtc(0x0C, Base >> 8);
ApmWriteCrtc(0x0D, Base);
ApmWriteCrtc(0x1C, (ApmReadCrtc(0x1C) & 0xF0) | ((Base & 0x0F0000) >> 16));
}
else {
outw(pApm->iobase + 0x3D4, (Base & 0x00FF00) | 0x0C);
outw(pApm->iobase + 0x3D4, ((Base & 0x00FF) << 8) | 0x0D);
modinx(pApm->iobase + 0x3D4, 0x1C, 0x0F, (Base & 0x0F0000) >> 16);
}
}
static Bool
ApmEnterVT(int scrnIndex, int flags)
{
ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
APMDECL(pScrn);
vgaHWPtr hwp = VGAHWPTR(pScrn);
if (pApm->Chipset >= AT3D) {
if (!pApm->noLinear) {
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);
hwp->writeMiscOut(hwp, pApm->MiscOut | 0x0F);
if (!ApmModeInit(pScrn, pScrn->currentMode))
return FALSE;
ApmAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
return TRUE;
}
static void
ApmLeaveVT(int scrnIndex, int flags)
{
ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
APMDECL(pScrn);
vgaHWPtr hwp = VGAHWPTR(pScrn);
ApmRestore(pScrn, &hwp->SavedReg, &pApm->SavedReg);
(*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);
}
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->adaptor)
xfree(pApm->adaptor);
pScrn->vtSema = FALSE;
if (xf86IsPc98())
outb(0xFAC, 0xFE);
pScreen->CloseScreen = pApm->CloseScreen;
return (*pScreen->CloseScreen)(scrnIndex, pScreen);
}
static void
ApmFreeScreen(int scrnIndex, int flags)
{
vgaHWFreeHWRec(xf86Screens[scrnIndex]);
ApmFreeRec(xf86Screens[scrnIndex]);
}
static ModeStatus
ApmValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags)
{
if (mode->Flags & V_INTERLACE)
return(MODE_BAD);
return(MODE_OK);
}
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:
dpmsreg = 0x00;
break;
case DPMSModeStandby:
dpmsreg = 0x01;
break;
case DPMSModeSuspend:
dpmsreg = 0x02;
break;
case DPMSModeOff:
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