apm_driver.c revision 0dd80ee0
1
2#ifdef HAVE_CONFIG_H
3#include "config.h"
4#endif
5
6#include "apm.h"
7#include "xf86cmap.h"
8#include "shadowfb.h"
9#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 6
10#include "xf86Resources.h"
11#include "xf86RAC.h"
12#endif
13#include "xf86int10.h"
14#include "vbe.h"
15
16#include "opaque.h"
17#ifdef HAVE_XEXTPROTO_71
18#include <X11/extensions/dpmsconst.h>
19#else
20#define DPMS_SERVER
21#include <X11/extensions/dpms.h>
22#endif
23
24
25#define APM_VERSION		4000
26#define APM_NAME		"APM"
27#define APM_DRIVER_NAME		"apm"
28#define APM_MAJOR_VERSION       PACKAGE_VERSION_MAJOR
29#define APM_MINOR_VERSION       PACKAGE_VERSION_MINOR
30#define APM_PATCHLEVEL          PACKAGE_VERSION_PATCHLEVEL
31
32#define PCI_VENDOR_ALLIANCE     0x1142
33#define PCI_CHIP_AP6422         0x6422
34#define PCI_CHIP_AT24           0x6424
35#define PCI_CHIP_AT3D	        0x643D
36
37/* bytes to save for text/font data */
38#define TEXT_AMOUNT 32768
39
40/* Mandatory functions */
41static const OptionInfoRec *	ApmAvailableOptions(int chipid, int busid);
42static void     ApmIdentify(int flags);
43static Bool     ApmProbe(DriverPtr drv, int flags);
44static Bool     ApmPreInit(ScrnInfoPtr pScrn, int flags);
45static Bool     ApmScreenInit(SCREEN_INIT_ARGS_DECL);
46static Bool     ApmEnterVT(VT_FUNC_ARGS_DECL);
47static void     ApmLeaveVT(VT_FUNC_ARGS_DECL);
48static Bool     ApmCloseScreen(CLOSE_SCREEN_ARGS_DECL);
49static void     ApmFreeScreen(FREE_SCREEN_ARGS_DECL);
50static ModeStatus ApmValidMode(SCRN_ARG_TYPE arg, DisplayModePtr mode,
51                               Bool verbose, int flags);
52static Bool	ApmSaveScreen(ScreenPtr pScreen, int mode);
53static void	ApmUnlock(ApmPtr pApm);
54static void	ApmLock(ApmPtr pApm);
55static void	ApmRestore(ScrnInfoPtr pScrn, vgaRegPtr vgaReg,
56			    ApmRegPtr ApmReg);
57static void	ApmLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices,
58				LOCO *colors, VisualPtr pVisual);
59static void	ApmDisplayPowerManagementSet(ScrnInfoPtr pScrn,
60					     int PowerManagementMode,
61					     int flags);
62static void	ApmProbeDDC(ScrnInfoPtr pScrn, int index);
63
64#ifdef XF86RUSH
65int ApmPixmapIndex = -1;
66static unsigned long ApmGeneration = 0;
67#endif
68
69_X_EXPORT DriverRec APM = {
70	APM_VERSION,
71	APM_DRIVER_NAME,
72	ApmIdentify,
73	ApmProbe,
74	ApmAvailableOptions,
75	NULL,
76	0
77};
78
79static SymTabRec ApmChipsets[] = {
80    { AP6422,	"AP6422"	},
81    { AT24,	"AT24"		},
82    { AT3D,	"AT3D"		},
83    { -1,	NULL		}
84};
85
86static PciChipsets ApmPciChipsets[] = {
87    { PCI_CHIP_AP6422,	PCI_CHIP_AP6422,	RES_SHARED_VGA },
88    { PCI_CHIP_AT24,	PCI_CHIP_AT24,		RES_SHARED_VGA },
89    { PCI_CHIP_AT3D,	PCI_CHIP_AT3D,		RES_SHARED_VGA },
90    { -1,			-1,		RES_UNDEFINED }
91};
92
93typedef enum {
94    OPTION_SET_MCLK,
95    OPTION_SW_CURSOR,
96    OPTION_HW_CURSOR,
97    OPTION_NOLINEAR,
98    OPTION_NOACCEL,
99    OPTION_SHADOW_FB,
100    OPTION_PCI_BURST,
101    OPTION_REMAP_DPMS_ON,
102    OPTION_REMAP_DPMS_STANDBY,
103    OPTION_REMAP_DPMS_SUSPEND,
104    OPTION_REMAP_DPMS_OFF,
105    OPTION_PCI_RETRY
106} ApmOpts;
107
108static const OptionInfoRec ApmOptions[] =
109{
110    {OPTION_SET_MCLK, "SetMclk", OPTV_FREQ,
111	{0}, FALSE},
112    {OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN,
113	{0}, FALSE},
114    {OPTION_HW_CURSOR, "HWcursor", OPTV_BOOLEAN,
115	{0}, TRUE},
116    {OPTION_NOLINEAR, "NoLinear", OPTV_BOOLEAN,
117	{0}, FALSE},
118    {OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN,
119	{0}, FALSE},
120    {OPTION_SHADOW_FB, "ShadowFB", OPTV_BOOLEAN,
121	{0}, FALSE},
122    {OPTION_PCI_BURST, "pci_burst", OPTV_BOOLEAN,
123	{0}, FALSE},
124    {OPTION_REMAP_DPMS_ON, "Remap_DPMS_On", OPTV_ANYSTR,
125	{0}, FALSE},
126    {OPTION_REMAP_DPMS_STANDBY, "Remap_DPMS_Standby", OPTV_ANYSTR,
127	{0}, FALSE},
128    {OPTION_REMAP_DPMS_SUSPEND, "Remap_DPMS_Suspend", OPTV_ANYSTR,
129	{0}, FALSE},
130    {OPTION_REMAP_DPMS_OFF, "Remap_DPMS_Off", OPTV_ANYSTR,
131	{0}, FALSE},
132    {OPTION_PCI_RETRY, "PciRetry", OPTV_BOOLEAN,
133	{0}, FALSE},
134    {-1, NULL, OPTV_NONE,
135	{0}, FALSE}
136};
137
138#ifdef XFree86LOADER
139
140static XF86ModuleVersionInfo apmVersRec = {
141    "apm",
142    MODULEVENDORSTRING,
143    MODINFOSTRING1,
144    MODINFOSTRING2,
145    XORG_VERSION_CURRENT,
146    APM_MAJOR_VERSION, APM_MINOR_VERSION, APM_PATCHLEVEL,
147    ABI_CLASS_VIDEODRV,			/* This is a video driver */
148    ABI_VIDEODRV_VERSION,
149    MOD_CLASS_VIDEODRV,
150    {0,0,0,0}
151};
152
153static MODULESETUPPROTO(apmSetup);
154
155/*
156 * This is the module init data.
157 * Its name has to be the driver name followed by ModuleData.
158 */
159_X_EXPORT XF86ModuleData apmModuleData = { &apmVersRec, apmSetup, NULL };
160
161static pointer
162apmSetup(pointer module, pointer opts, int *errmaj, int *errmain)
163{
164    static Bool setupDone = FALSE;
165
166    if (!setupDone) {
167	setupDone = TRUE;
168	xf86AddDriver(&APM, module, 0);
169
170	return (pointer)1;
171    }
172    else {
173	if (errmaj) *errmaj = LDR_ONCEONLY;
174	return NULL;
175    }
176}
177#endif
178
179static Bool
180ApmGetRec(ScrnInfoPtr pScrn)
181{
182    if (pScrn->driverPrivate)
183	return TRUE;
184    pScrn->driverPrivate = xnfcalloc(sizeof(ApmRec), 1);
185    /* pScrn->driverPrivate != NULL at this point */
186
187    return TRUE;
188}
189
190static void
191ApmFreeRec(ScrnInfoPtr pScrn)
192{
193    free(pScrn->driverPrivate);
194    pScrn->driverPrivate = NULL;
195}
196
197
198/* unlock Alliance registers */
199static void
200ApmUnlock(ApmPtr pApm)
201{
202    if (pApm->Chipset >= AT3D)
203	ApmWriteSeq(0x10, 0x12);
204    else
205	wrinx(pApm->xport, 0x10, 0x12);
206}
207
208/* lock Alliance registers */
209static void
210ApmLock(ApmPtr pApm)
211{
212    if (pApm->Chipset >= AT3D)
213	ApmWriteSeq(0x10, pApm->savedSR10 ? 0 : 0x12);
214    else
215	wrinx(pApm->xport, 0x10, pApm->savedSR10 ? 0 : 0x12);
216}
217
218static void
219ApmIdentify(int flags)
220{
221    xf86PrintChipsets(APM_NAME, "driver for the Alliance chipsets",
222		      ApmChipsets);
223}
224
225static const OptionInfoRec *
226ApmAvailableOptions(int chipid, int busid)
227{
228    return ApmOptions;
229}
230
231static void
232ApmAssignFPtr(ScrnInfoPtr pScrn)
233{
234    pScrn->driverVersion	= APM_VERSION;
235    pScrn->driverName		= APM_DRIVER_NAME;
236    pScrn->name			= APM_NAME;
237    pScrn->Probe		= ApmProbe;
238    pScrn->PreInit		= ApmPreInit;
239    pScrn->ScreenInit		= ApmScreenInit;
240    pScrn->SwitchMode		= ApmSwitchMode;
241    pScrn->AdjustFrame		= ApmAdjustFrame;
242    pScrn->EnterVT		= ApmEnterVT;
243    pScrn->LeaveVT		= ApmLeaveVT;
244    pScrn->FreeScreen		= ApmFreeScreen;
245    pScrn->ValidMode		= ApmValidMode;
246}
247
248static Bool
249ApmProbe(DriverPtr drv, int flags)
250{
251    int			numDevSections, numUsed, i;
252    GDevPtr		*DevSections;
253    int			*usedChips;
254    int			foundScreen = FALSE;
255
256    /*
257     * Check if there is a chipset override in the config file
258     */
259    if ((numDevSections = xf86MatchDevice(APM_DRIVER_NAME,
260					   &DevSections)) <= 0)
261	return FALSE;
262
263    /*
264     * We need to probe the hardware first. We then need to see how this
265     * fits in with what is given in the config file, and allow the config
266     * file info to override any contradictions.
267     */
268
269#ifndef XSERVER_LIBPCIACCESS
270    if (xf86GetPciVideoInfo() == NULL) {
271	return FALSE;
272    }
273#endif
274    numUsed = xf86MatchPciInstances(APM_NAME, PCI_VENDOR_ALLIANCE,
275		    ApmChipsets, ApmPciChipsets, DevSections, numDevSections,
276		    drv, &usedChips);
277
278    if (numUsed > 0) {
279	if (flags & PROBE_DETECT)
280	    foundScreen = TRUE;
281	else for (i = 0; i < numUsed; i++) {
282	    ScrnInfoPtr	pScrn;
283
284	    /*
285	     * Allocate a ScrnInfoRec and claim the slot
286	     */
287	    pScrn = NULL;
288	    if ((pScrn = xf86ConfigPciEntity(pScrn, 0, usedChips[i],
289						   ApmPciChipsets, NULL,
290						   NULL,NULL,NULL,NULL))){
291
292		/*
293		 * Fill in what we can of the ScrnInfoRec
294		 */
295		ApmAssignFPtr(pScrn);
296		foundScreen = TRUE;
297	    }
298	}
299    }
300
301
302    free(DevSections);
303    return foundScreen;
304}
305
306/*
307 * GetAccelPitchValues -
308 *
309 * This function returns a list of display width (pitch) values that can
310 * be used in accelerated mode.
311 */
312static int *
313GetAccelPitchValues(ScrnInfoPtr pScrn)
314{
315    int *linePitches = NULL;
316    int linep[] = {640, 800, 1024, 1152, 1280, 0};
317
318    if (sizeof linep > 0) {
319	linePitches = (int *)xnfalloc(sizeof linep);
320	memcpy(linePitches, linep, sizeof linep);
321    }
322
323    return linePitches;
324}
325
326static unsigned int
327ddc1Read(ScrnInfoPtr pScrn)
328{
329    APMDECL(pScrn);
330    unsigned char	tmp;
331
332    tmp = RDXB_IOP(0xD0);
333    WRXB_IOP(0xD0, tmp & 0x07);
334    while (STATUS_IOP() & 0x800);
335    while (!(STATUS_IOP() & 0x800));
336    return (STATUS_IOP() & STATUS_SDA) != 0;
337}
338
339static void
340ApmProbeDDC(ScrnInfoPtr pScrn, int index)
341{
342    vbeInfoPtr pVbe;
343
344    if (xf86LoadSubModule(pScrn, "vbe")) {
345        pVbe = VBEInit(NULL, index);
346        ConfiguredMonitor = vbeDoEDID(pVbe, NULL);
347	vbeFree(pVbe);
348    }
349}
350
351static Bool
352ApmPreInit(ScrnInfoPtr pScrn, int flags)
353{
354    APMDECL(pScrn);
355    EntityInfoPtr	pEnt;
356    vgaHWPtr		hwp;
357    MessageType		from;
358    char		*mod = NULL, *req = NULL, *s;
359    ClockRangePtr	clockRanges;
360    int			i;
361    xf86MonPtr		MonInfo = NULL;
362    double		real;
363
364    /*
365     * Note: This function is only called once at server startup, and
366     * not at the start of each server generation.  This means that
367     * only things that are persistent across server generations can
368     * be initialised here.  xf86Screens[] is (pScrn is a pointer to one
369     * of these).  Privates allocated using xf86AllocateScrnInfoPrivateIndex()
370     * are too, and should be used for data that must persist across
371     * server generations.
372     *
373     * Per-generation data should be allocated with
374     * AllocateScreenPrivateIndex() from the ScreenInit() function.
375     */
376
377    /* Check the number of entities, and fail if it isn't one. */
378    if (pScrn->numEntities != 1)
379	return FALSE;
380
381    /* Allocate the ApmRec driverPrivate */
382    if (!ApmGetRec(pScrn)) {
383	return FALSE;
384    }
385    pApm = APMPTR(pScrn);
386
387    /* Get the entity */
388    pEnt = pApm->pEnt	= xf86GetEntityInfo(pScrn->entityList[0]);
389    if (pEnt->location.type == BUS_PCI) {
390	pApm->PciInfo	= xf86GetPciInfoForEntity(pEnt->index);
391#ifndef XSERVER_LIBPCIACCESS
392	pApm->PciTag	= pciTag(pApm->PciInfo->bus, pApm->PciInfo->device,
393				 pApm->PciInfo->func);
394#endif
395    }
396    else {
397	pApm->PciInfo	= NULL;
398#ifndef XSERVER_LIBPCIACCESS
399	pApm->PciTag	= 0;
400#endif
401    }
402
403    if (flags & PROBE_DETECT) {
404        ApmProbeDDC(pScrn, pEnt->index);
405        return TRUE;
406    }
407
408    /* The vgahw module should be allocated here when needed */
409    if (!xf86LoadSubModule(pScrn, "vgahw"))
410	return FALSE;
411
412    /*
413     * Allocate a vgaHWRec
414     */
415    if (!vgaHWGetHWRec(pScrn))
416	return FALSE;
417
418    hwp = VGAHWPTR(pScrn);
419    vgaHWSetStdFuncs(hwp);
420    vgaHWGetIOBase(hwp);
421#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 12
422#define PIOOFFSET hwp->PIOOffset
423#else
424/* FIXME reintroduce domain support */
425#define PIOOFFSET 0
426#endif
427    pApm->iobase = PIOOFFSET;
428    pApm->xport = PIOOFFSET + 0x3C4;
429
430    /* Set pScrn->monitor */
431    pScrn->monitor = pScrn->confScreen->monitor;
432
433    /* XXX: Access funcs */
434    /*
435     * The first thing we should figure out is the depth, bpp, etc.
436     */
437    if (!xf86SetDepthBpp(pScrn, 0, 0, 0, Support24bppFb | Support32bppFb)) {
438	return FALSE;
439    } else {
440	/* Check that the returned depth is one we support */
441	switch (pScrn->depth) {
442	case 4:
443	case 8:
444	case 15:
445	case 16:
446	case 24:
447	    /* OK */
448	    break;
449	default:
450	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
451		       "Given depth (%d) is not supported by this driver\n",
452		       pScrn->depth);
453	    return FALSE;
454	}
455    }
456    xf86PrintDepthBpp(pScrn);
457
458    /*
459     * This must happen after pScrn->display has been set because
460     * xf86SetWeight references it.
461     */
462    if (pScrn->depth > 8) {
463	/* The defaults are OK for us */
464	rgb zeros = {0, 0, 0};
465
466	if (!xf86SetWeight(pScrn, zeros, zeros)) {
467	    return FALSE;
468	} else {
469	    /* XXX check that weight returned is supported */
470            ;
471        }
472    }
473
474    if (!xf86SetDefaultVisual(pScrn, -1)) {
475	return FALSE;
476    } else {
477	if (pScrn->depth > 8 && pScrn->defaultVisual != TrueColor) {
478	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Given default visual"
479		       " (%s) is not supported at depth %d\n",
480		       xf86GetVisualName(pScrn->defaultVisual), pScrn->depth);
481	    return FALSE;
482	}
483    }
484
485    /* We use a programmable clock */
486    pScrn->progClock = TRUE;
487
488    /* Collect all of the relevant option flags (fill in pScrn->options) */
489    xf86CollectOptions(pScrn, NULL);
490
491    /* Process the options */
492    if (!(pApm->Options = malloc(sizeof(ApmOptions))))
493	return FALSE;
494    memcpy(pApm->Options, ApmOptions, sizeof(ApmOptions));
495    xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pApm->Options);
496
497    pApm->scrnIndex = pScrn->scrnIndex;
498    /* Set the bits per RGB for 8bpp mode */
499    if (pScrn->depth > 1 && pScrn->depth <= 8) {
500	/* Default to 8 */
501	pScrn->rgbBits = 8;
502    }
503    from = X_DEFAULT;
504    pApm->hwCursor = FALSE;
505    if (xf86GetOptValBool(pApm->Options, OPTION_HW_CURSOR, &pApm->hwCursor))
506	from = X_CONFIG;
507    if (xf86ReturnOptValBool(pApm->Options, OPTION_SW_CURSOR, FALSE)) {
508	from = X_CONFIG;
509	pApm->hwCursor = FALSE;
510    }
511    xf86DrvMsg(pScrn->scrnIndex, from, "Using %s cursor\n",
512		pApm->hwCursor ? "HW" : "SW");
513    from = X_DEFAULT;
514    if (pScrn->bitsPerPixel < 8)
515	pApm->NoAccel = TRUE;
516    if (xf86ReturnOptValBool(pApm->Options, OPTION_NOACCEL, FALSE)) {
517	from = X_CONFIG;
518	pApm->NoAccel = TRUE;
519    }
520    if (pApm->NoAccel)
521	xf86DrvMsg(pScrn->scrnIndex, from, "Acceleration disabled\n");
522    if (xf86GetOptValFreq(pApm->Options, OPTION_SET_MCLK, OPTUNITS_MHZ, &real)) {
523	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "MCLK used is %.1f MHz\n", real);
524	pApm->MemClk = (int)(real * 1000.0);
525    }
526    if (xf86ReturnOptValBool(pApm->Options, OPTION_SHADOW_FB, FALSE)) {
527	pApm->ShadowFB = TRUE;
528	pApm->NoAccel = TRUE;
529	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
530		"Using \"Shadow Framebuffer\" - acceleration disabled\n");
531    }
532    if (xf86ReturnOptValBool(pApm->Options, OPTION_PCI_RETRY, FALSE)) {
533	if (xf86ReturnOptValBool(pApm->Options, OPTION_PCI_BURST, FALSE)) {
534	  pApm->UsePCIRetry = TRUE;
535	  xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "PCI retry enabled\n");
536	}
537	else
538	  xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "\"pci_retry\" option requires pci_burst \"on\".\n");
539    }
540    pApm->DPMSMask[DPMSModeOn]		= DPMSModeOn;
541    pApm->DPMSMask[DPMSModeStandby]	= DPMSModeStandby;
542    pApm->DPMSMask[DPMSModeSuspend]	= DPMSModeSuspend;
543    pApm->DPMSMask[DPMSModeOff]		= DPMSModeOff;
544    if ((s = xf86GetOptValString(pApm->Options, OPTION_REMAP_DPMS_ON))) {
545	if (!strcmp(s, "on"))
546	    pApm->DPMSMask[DPMSModeOn] = DPMSModeOn;
547	else if (!strcmp(s, "standby"))
548	    pApm->DPMSMask[DPMSModeOn] = DPMSModeStandby;
549	else if (!strcmp(s, "suspend"))
550	    pApm->DPMSMask[DPMSModeOn] = DPMSModeSuspend;
551	else if (!strcmp(s, "off"))
552	    pApm->DPMSMask[DPMSModeOn] = DPMSModeOff;
553	else if (s[0] >= '0' && s[0] <= '9') {
554	    pApm->DPMSMask[DPMSModeOn] = strtol(s, NULL, 0);
555	    if (pApm->DPMSMask[DPMSModeOn] > (sizeof pApm->DPMSMask)-1)
556		pApm->DPMSMask[DPMSModeOn] = (sizeof pApm->DPMSMask) - 1;
557	}
558    }
559    if ((s = xf86GetOptValString(pApm->Options, OPTION_REMAP_DPMS_STANDBY))) {
560	if (!strcmp(s, "on"))
561	    pApm->DPMSMask[DPMSModeStandby] = DPMSModeOn;
562	else if (!strcmp(s, "standby"))
563	    pApm->DPMSMask[DPMSModeStandby] = DPMSModeStandby;
564	else if (!strcmp(s, "suspend"))
565	    pApm->DPMSMask[DPMSModeStandby] = DPMSModeSuspend;
566	else if (!strcmp(s, "off"))
567	    pApm->DPMSMask[DPMSModeStandby] = DPMSModeOff;
568	else if (s[0] >= '0' && s[0] <= '9') {
569	    pApm->DPMSMask[DPMSModeStandby] = strtol(s, NULL, 0);
570	    if (pApm->DPMSMask[DPMSModeStandby] > (sizeof pApm->DPMSMask)-1)
571		pApm->DPMSMask[DPMSModeStandby] = (sizeof pApm->DPMSMask) - 1;
572	}
573    }
574    if ((s = xf86GetOptValString(pApm->Options, OPTION_REMAP_DPMS_SUSPEND))) {
575	if (!strcmp(s, "on"))
576	    pApm->DPMSMask[DPMSModeSuspend] = DPMSModeOn;
577	else if (!strcmp(s, "standby"))
578	    pApm->DPMSMask[DPMSModeSuspend] = DPMSModeStandby;
579	else if (!strcmp(s, "suspend"))
580	    pApm->DPMSMask[DPMSModeSuspend] = DPMSModeSuspend;
581	else if (!strcmp(s, "off"))
582	    pApm->DPMSMask[DPMSModeSuspend] = DPMSModeOff;
583	else if (s[0] >= '0' && s[0] <= '9') {
584	    pApm->DPMSMask[DPMSModeSuspend] = strtol(s, NULL, 0);
585	    if (pApm->DPMSMask[DPMSModeSuspend] > (sizeof pApm->DPMSMask)-1)
586		pApm->DPMSMask[DPMSModeSuspend] = (sizeof pApm->DPMSMask) - 1;
587	}
588    }
589    if ((s = xf86GetOptValString(pApm->Options, OPTION_REMAP_DPMS_OFF))) {
590	if (!strcmp(s, "on"))
591	    pApm->DPMSMask[DPMSModeOff] = DPMSModeOn;
592	else if (!strcmp(s, "standby"))
593	    pApm->DPMSMask[DPMSModeOff] = DPMSModeStandby;
594	else if (!strcmp(s, "suspend"))
595	    pApm->DPMSMask[DPMSModeOff] = DPMSModeSuspend;
596	else if (!strcmp(s, "off"))
597	    pApm->DPMSMask[DPMSModeOff] = DPMSModeOff;
598	else if (s[0] >= '0' && s[0] <= '9') {
599	    pApm->DPMSMask[DPMSModeOff] = strtol(s, NULL, 0);
600	    if (pApm->DPMSMask[DPMSModeOff] > (sizeof pApm->DPMSMask)-1)
601		pApm->DPMSMask[DPMSModeOff] = (sizeof pApm->DPMSMask) - 1;
602	}
603    }
604
605    /*
606     * Set the Chipset and ChipRev, allowing config file entries to
607     * override.
608     */
609    if (pEnt->device->chipset && *pEnt->device->chipset) {
610	pScrn->chipset = pEnt->device->chipset;
611        pApm->Chipset = xf86StringToToken(ApmChipsets, pScrn->chipset);
612        from = X_CONFIG;
613    } else if (pEnt->device->chipID >= 0) {
614	pApm->Chipset = pEnt->device->chipID;
615	pScrn->chipset = (char *)xf86TokenToString(ApmChipsets, pApm->Chipset);
616
617	from = X_CONFIG;
618	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipID override: 0x%04X\n",
619		   pApm->Chipset);
620    } else {
621	from = X_PROBED;
622	if (pApm->PciInfo)
623	    pApm->Chipset = PCI_DEV_DEVICE_ID(pApm->PciInfo);
624	else
625	    pApm->Chipset = pEnt->chipset;
626	pScrn->chipset = (char *)xf86TokenToString(ApmChipsets, pApm->Chipset);
627    }
628    if (pScrn->bitsPerPixel == 24 && pApm->Chipset < AT24) {
629	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
630		   "Given depth (%d) is not supported by this driver\n",
631		   pScrn->depth);
632	return FALSE;
633    }
634    if (pEnt->device->chipRev >= 0) {
635	pApm->ChipRev = pEnt->device->chipRev;
636	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n",
637		   pApm->ChipRev);
638    } else if (pApm->PciInfo) {
639        pApm->ChipRev = PCI_DEV_REVISION(pApm->PciInfo);
640    }
641
642    /*
643     * This shouldn't happen because such problems should be caught in
644     * ApmProbe(), but check it just in case.
645     */
646    if (pScrn->chipset == NULL) {
647	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
648		   "ChipID 0x%04X is not recognised\n", pApm->Chipset);
649	return FALSE;
650    }
651    if (pApm->Chipset < 0) {
652	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
653		   "Chipset \"%s\" is not recognised\n", pScrn->chipset);
654	return FALSE;
655    }
656
657    xf86DrvMsg(pScrn->scrnIndex, from, "Chipset: \"%s\"\n", pScrn->chipset);
658
659    if (pEnt->device->MemBase != 0) {
660	pApm->LinAddress = pEnt->device->MemBase;
661	from = X_CONFIG;
662    } else if (pApm->PciInfo) {
663        pApm->LinAddress = PCI_REGION_BASE(pApm->PciInfo, 0, REGION_MEM) & 0xFF800000;
664	from = X_PROBED;
665    } else {
666	/*
667	 * VESA local bus.
668	 * Pray that 2048MB works.
669	 */
670	pApm->LinAddress = 0x80000000;
671    }
672
673    xf86DrvMsg(pScrn->scrnIndex, from, "Linear framebuffer at 0x%lX\n",
674	       (unsigned long)pApm->LinAddress);
675
676    if (xf86LoadSubModule(pScrn, "ddc")) {
677	if (xf86LoadSubModule(pScrn, "i2c")) {
678	    pApm->I2C = TRUE;
679	}
680    }
681
682    if (pApm->Chipset >= AT3D)
683	pApm->LinMapSize  = 16 * 1024 * 1024;
684    else
685	pApm->LinMapSize  =  6 * 1024 * 1024;
686    pApm->FbMapSize   =  4 * 1024 * 1024;
687
688    if (xf86LoadSubModule(pScrn, "int10")) {
689	void	*ptr;
690
691	xf86DrvMsg(pScrn->scrnIndex,X_INFO,"initializing int10\n");
692	ptr = xf86InitInt10(pEnt->index);
693	if (ptr)
694	    xf86FreeInt10(ptr);
695    }
696
697#ifndef XSERVER_LIBPCIACCESS
698    xf86RegisterResources(pEnt->index, NULL, ResNone);
699    xf86SetOperatingState(resVga, pEnt->index, ResDisableOpr);
700    pScrn->racMemFlags = 0;	/* For noLinear, access to 0xA0000 */
701    if (pApm->VGAMap)
702	pScrn->racIoFlags = 0;
703    else
704	pScrn->racIoFlags = RAC_COLORMAP | RAC_VIEWPORT;
705#endif
706    if (pEnt->device->videoRam != 0) {
707	pScrn->videoRam = pEnt->device->videoRam;
708	from = X_CONFIG;
709    } else if (pApm->Chipset >= AT3D) {
710	unsigned char		d9, db, uc;
711	/*unsigned long		save;*/
712	volatile unsigned char	*LinMap;
713
714#ifndef XSERVER_LIBPCIACCESS
715	LinMap = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
716				     pApm->PciTag, pApm->LinAddress,
717				     pApm->LinMapSize);
718#else
719	{
720	    void** result = (void**)&LinMap;
721	    int err = pci_device_map_range(pApm->PciInfo,
722					   pApm->LinAddress,
723					   pApm->LinMapSize,
724					   PCI_DEV_MAP_FLAG_WRITABLE,
725					   result);
726
727	    if (err)
728		return FALSE;
729	}
730#endif
731
732	/*save = pciReadLong(pApm->PciTag, PCI_CMD_STAT_REG);
733	pciWriteLong(pApm->PciTag, PCI_CMD_STAT_REG, save | PCI_CMD_MEM_ENABLE);*/
734	d9 = LinMap[0xFFECD9];
735	db = LinMap[0xFFECDB];
736	LinMap[0xFFECDB] = (db & 0xF4) | 0x0A;
737	LinMap[0xFFECD9] = (d9 & 0xCF) | 0x20;
738	LinMap[0xFFF3C4] = 0x1C;
739	uc = LinMap[0xFFF3C5];
740	LinMap[0xFFF3C5] = 0x3F;
741	LinMap[0xFFF3C4] = 0x20;
742	pScrn->videoRam = LinMap[0xFFF3C5] * 64;
743	LinMap[0xFFF3C4] = 0x10;
744	pApm->savedSR10 = LinMap[0xFFF3C5];
745	LinMap[0xFFF3C4] = 0x1E;
746	pApm->xbase  = LinMap[0xFFF3C5];
747	LinMap[0xFFF3C4] = 0x1F;
748	pApm->xbase |= LinMap[0xFFF3C5] << 8;
749	LinMap[0xFFF3C4] = 0x1C;
750	LinMap[0xFFF3C5] = uc;
751	LinMap[0xFFECDB] = db;
752	LinMap[0xFFECD9] = d9;
753	/*pciWriteLong(pApm->PciTag, PCI_CMD_STAT_REG, save);*/
754	xf86UnMapVidMem(pScrn->scrnIndex, (pointer)LinMap, pApm->LinMapSize);
755	from = X_PROBED;
756    }
757    else {
758	/*unsigned long		save;
759
760	save = pciReadLong(pApm->PciTag, PCI_CMD_STAT_REG);
761	pciWriteLong(pApm->PciTag, PCI_CMD_STAT_REG, save | PCI_CMD_IO_ENABLE);*/
762	pApm->savedSR10 = rdinx(pApm->xport, 0x10);
763	wrinx(pApm->xport, 0x10, 0x12);
764	pScrn->videoRam = rdinx(pApm->xport, 0x20) * 64;
765	pApm->xbase = rdinx(pApm->xport, 0x1F) << 8;
766	pApm->xbase |= rdinx(pApm->xport, 0x1E);
767	pApm->xbase += pApm->iobase;
768	wrinx(pApm->xport, 0x10, pApm->savedSR10 ? 0 : 0x12);
769	/*pciWriteLong(pApm->PciTag, PCI_CMD_STAT_REG, save);*/
770	from = X_PROBED;
771    }
772    if (pApm->Chipset < AT3D && pScrn->videoRam >= 4096)
773	pScrn->videoRam -= 32;
774
775    xf86DrvMsg(pScrn->scrnIndex, from, "VideoRAM: %d kByte\n",
776               pScrn->videoRam);
777
778#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 12
779    if (!xf86IsPc98())
780#endif
781    {
782	hwp->MapSize = 0x10000;
783	vgaHWMapMem(pScrn);
784	if (pApm->I2C) {
785	    if (!ApmI2CInit(pScrn)) {
786		xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"I2C initialization failed\n");
787	    }
788	    else {
789		MonInfo = xf86DoEDID_DDC2(XF86_SCRN_ARG(pScrn),pApm->I2CPtr);
790	    }
791	}
792	if (0 && !MonInfo)
793	    MonInfo = xf86DoEDID_DDC1(XF86_SCRN_ARG(pScrn),vgaHWddc1SetSpeed,ddc1Read);
794	if (MonInfo) {
795	    xf86PrintEDID(MonInfo);
796	    xf86SetDDCproperties(pScrn, MonInfo);
797	}
798	pScrn->monitor->DDC = MonInfo;
799    }
800
801    /* The gamma fields must be initialised when using the new cmap code */
802    if (pScrn->depth > 1) {
803	Gamma zeros = {0.0, 0.0, 0.0};
804
805	if (!xf86SetGamma(pScrn, zeros)) {
806	    return FALSE;
807	}
808    }
809
810    pApm->MinClock = 23125;
811    xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "Min pixel clock set to %d MHz\n",
812	       pApm->MinClock / 1000);
813
814    /*
815     * If the user has specified ramdac speed in the XF86Config
816     * file, we respect that setting.
817     */
818    from = X_DEFAULT;
819    if (pEnt->device->dacSpeeds[0]) {
820	int speed = 0;
821
822	switch (pScrn->bitsPerPixel) {
823	case 4:
824	case 8:
825	   speed = pEnt->device->dacSpeeds[DAC_BPP8];
826	   break;
827	case 16:
828	   speed = pEnt->device->dacSpeeds[DAC_BPP16];
829	   break;
830	case 24:
831	   speed = pEnt->device->dacSpeeds[DAC_BPP24];
832	   break;
833	case 32:
834	   speed = pEnt->device->dacSpeeds[DAC_BPP32];
835	   break;
836	}
837	if (speed == 0)
838	    pApm->MaxClock = pEnt->device->dacSpeeds[0];
839	else
840	    pApm->MaxClock = speed;
841	from = X_CONFIG;
842    } else {
843	switch(pApm->Chipset)
844	{
845	  /* These values come from the Manual for AT24 and AT3D
846	     in the overview of various modes. I've taken the largest
847	     number for the different modes. Alliance wouldn't
848	     tell me what the maximum frequency was, so...
849	   */
850	  case AT24:
851	       switch(pScrn->bitsPerPixel)
852	       {
853		 case 4:
854		 case 8:
855		      pApm->MaxClock = 160000;
856		      break;
857		 case 16:
858		      pApm->MaxClock = 144000;
859		      break;
860		 case 24:
861		      pApm->MaxClock = 75000; /* Hmm. */
862		      break;
863		 case 32:
864		      pApm->MaxClock = 94500;
865		      break;
866		 default:
867		      return FALSE;
868	       }
869	       break;
870	  case AT3D:
871	       switch(pScrn->bitsPerPixel)
872	       {
873		 case 4:
874		 case 8:
875		      pApm->MaxClock = 175500;
876		      break;
877		 case 16:
878		      pApm->MaxClock = 144000;
879		      break;
880		 case 24:
881		      pApm->MaxClock = 94000; /* Changed from 75000 by Grenié */
882		      break;
883		 case 32:
884		      pApm->MaxClock = 94500;
885		      break;
886		 default:
887		      return FALSE;
888	       }
889	       break;
890	  case AP6422:
891	       switch(pScrn->bitsPerPixel)
892	       {
893		 case 4:
894		 case 8:
895		      pApm->MaxClock = 135000;
896		      break;
897		 case 16:
898		      pApm->MaxClock = 75000;
899		      break;
900		 case 32:
901		      pApm->MaxClock = 60000;
902		      break;
903		 default:
904		      return FALSE;
905	       }
906	       break;
907	  default:
908	       pApm->MaxClock = 135000;
909	       break;
910	}
911    }
912    xf86DrvMsg(pScrn->scrnIndex, from, "Max pixel clock is %d MHz\n",
913	       pApm->MaxClock / 1000);
914
915    /*
916     * Setup the ClockRanges, which describe what clock ranges are available,
917     * and what sort of modes they can be used for.
918     */
919    clockRanges = (ClockRangePtr)xnfcalloc(sizeof(ClockRange), 1);
920    clockRanges->next = NULL;
921    clockRanges->minClock = pApm->MinClock;
922    clockRanges->maxClock = pApm->MaxClock;
923    clockRanges->clockIndex = -1;		/* programmable */
924    clockRanges->interlaceAllowed = FALSE;	/* XXX change this */
925    clockRanges->doubleScanAllowed = FALSE;	/* XXX check this */
926
927    /* Select valid modes from those available */
928    if (pApm->NoAccel) {
929	/*
930	 * XXX Assuming min pitch 256, max 2048
931	 * XXX Assuming min height 128, max 1024 (changed EE)
932	 */
933	i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
934			      pScrn->display->modes, clockRanges,
935			      NULL, 256, 2048,
936			      pScrn->bitsPerPixel, 128, 1024,
937			      pScrn->display->virtualX,
938			      pScrn->display->virtualY,
939			      pApm->FbMapSize,
940			      LOOKUP_BEST_REFRESH);
941    } else {
942	/*
943	 * XXX Assuming min height 128, max 2048
944	 */
945	i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
946			      pScrn->display->modes, clockRanges,
947			      GetAccelPitchValues(pScrn), 0, 0,
948			      pScrn->bitsPerPixel, 128, 1024,
949			      pScrn->display->virtualX,
950			      pScrn->display->virtualY,
951			      pApm->FbMapSize,
952			      LOOKUP_BEST_REFRESH);
953    }
954
955    if (i == -1) {
956	ApmFreeRec(pScrn);
957	return FALSE;
958    }
959
960    /* Prune the modes marked as invalid */
961    xf86PruneDriverModes(pScrn);
962
963    if (i == 0 || pScrn->modes == NULL) {
964	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n");
965	ApmFreeRec(pScrn);
966	return FALSE;
967    }
968
969    xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V);
970
971    /* Set the current mode to the first in the list */
972    pScrn->currentMode = pScrn->modes;
973
974    /* Print the list of modes being used */
975    xf86PrintModes(pScrn);
976
977    /* Set display resolution */
978    xf86SetDpi(pScrn, 0, 0);
979
980    /* Load bpp-specific modules */
981    switch (pScrn->bitsPerPixel) {
982    case 8:
983    case 16:
984    case 24:
985    case 32:
986	mod = "fb";
987	break;
988    }
989
990    if (mod && xf86LoadSubModule(pScrn, mod) == NULL) {
991	ApmFreeRec(pScrn);
992	return FALSE;
993    }
994
995    /* Load XAA if needed */
996    if (!pApm->NoAccel) {
997#ifdef HAVE_XAA_H
998	if (!xf86LoadSubModule(pScrn, "xaa")) {
999	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Falling back to shadowfb\n");
1000	    pApm->NoAccel = TRUE;
1001	    pApm->ShadowFB = TRUE;
1002	}
1003#else
1004	pApm->NoAccel = TRUE;
1005	pApm->ShadowFB = TRUE;
1006#endif
1007    }
1008
1009    /* Load ramdac if needed */
1010    if (pApm->hwCursor) {
1011	if (!xf86LoadSubModule(pScrn, "ramdac")) {
1012	    ApmFreeRec(pScrn);
1013	    return FALSE;
1014	}
1015    }
1016
1017    /* Load shadowfb if needed */
1018    if (pApm->ShadowFB) {
1019	if (!xf86LoadSubModule(pScrn, "shadowfb")) {
1020	    ApmFreeRec(pScrn);
1021	    return FALSE;
1022	}
1023    }
1024
1025    pApm->CurrentLayout.displayWidth	= pScrn->virtualX;
1026    pApm->CurrentLayout.displayHeight	= pScrn->virtualY;
1027    pApm->CurrentLayout.bitsPerPixel	= pScrn->bitsPerPixel;
1028    pApm->CurrentLayout.bytesPerScanline= (pApm->CurrentLayout.displayWidth * pApm->CurrentLayout.bitsPerPixel) >> 3;
1029    pApm->CurrentLayout.depth		= pScrn->depth;
1030    pApm->CurrentLayout.Scanlines	= 2 * (pScrn->videoRam << 10) / pApm->CurrentLayout.bytesPerScanline;
1031    if (pScrn->bitsPerPixel == 24)
1032	pApm->CurrentLayout.mask32	= 3;
1033    else
1034	pApm->CurrentLayout.mask32	= 32 / pScrn->bitsPerPixel - 1;
1035
1036    return TRUE;
1037}
1038
1039/*
1040 * Map the framebuffer and MMIO memory.
1041 */
1042
1043static Bool
1044ApmMapMem(ScrnInfoPtr pScrn)
1045{
1046    APMDECL(pScrn);
1047    vgaHWPtr	hwp = VGAHWPTR(pScrn);
1048
1049#ifndef XSERVER_LIBPCIACCESS
1050    pApm->LinMap = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
1051				 pApm->PciTag,
1052				 (unsigned long)pApm->LinAddress,
1053				 pApm->LinMapSize);
1054#else
1055    {
1056	void** result = (void**)&pApm->LinMap;
1057	int err = pci_device_map_range(pApm->PciInfo,
1058				       pApm->LinAddress,
1059				       pApm->LinMapSize,
1060				       PCI_DEV_MAP_FLAG_WRITABLE |
1061				       PCI_DEV_MAP_FLAG_WRITE_COMBINE,
1062				       result);
1063
1064	if (err)
1065	    return FALSE;
1066    }
1067#endif
1068
1069
1070    if (pApm->LinMap == NULL)
1071	return FALSE;
1072
1073    if (pApm->Chipset >= AT3D) {
1074	pApm->FbBase = (void *)(((char *)pApm->LinMap) + 0x800000);
1075	pApm->VGAMap = ((char *)pApm->LinMap) + 0xFFF000;
1076	pApm->MemMap = ((char *)pApm->LinMap) + 0xFFEC00;
1077	pApm->BltMap = (void *)(((char *)pApm->LinMap) + 0x3F8000);
1078    }
1079    else {
1080	pApm->FbBase = (void *)pApm->LinMap;
1081	pApm->VGAMap = NULL;
1082	if (pScrn->videoRam == 6 * 1024 - 32) {
1083	    pApm->MemMap = ((char *)pApm->LinMap) + 0x5FF800;
1084	    pApm->BltMap = (void *)(((char *)pApm->LinMap) + 0x5F8000);
1085	}
1086	else {
1087	    pApm->MemMap = ((char *)pApm->LinMap) + 0x3FF800;
1088	    pApm->BltMap = (void *)(((char *)pApm->LinMap) + 0x3F8000);
1089	}
1090    }
1091
1092    /*
1093     * Initialize chipset
1094     */
1095    pApm->c9 = RDXB(0xC9);
1096    if (pApm->Chipset >= AT3D) {
1097	pApm->d9 = RDXB(0xD9);
1098	pApm->db = RDXB(0xDB);
1099
1100	/* If you change these two, change them also in apm_funcs.c */
1101	WRXB(0xDB, (pApm->db & 0xF4) | 0x0A);
1102	WRXB(0xD9, (pApm->d9 & 0xCF) | 0x20);
1103
1104	vgaHWSetMmioFuncs(hwp, (CARD8 *)pApm->LinMap, 0xFFF000);
1105    }
1106    if (pApm->Chipset >= AP6422)
1107	WRXB(0xC9, pApm->c9 | 0x10);
1108
1109    /*
1110     * Save color mode
1111     */
1112    pApm->MiscOut = hwp->readMiscOut(hwp);
1113
1114    return TRUE;
1115}
1116
1117/*
1118 * Unmap the framebuffer and MMIO memory
1119 */
1120
1121static Bool
1122ApmUnmapMem(ScrnInfoPtr pScrn)
1123{
1124    APMDECL(pScrn);
1125    vgaHWPtr	hwp = VGAHWPTR(pScrn);
1126
1127    /*
1128     * Reset color mode
1129     */
1130    hwp->writeMiscOut(hwp, pApm->MiscOut);
1131    if (pApm->LinMap) {
1132	if (pApm->Chipset >= AT3D) {
1133	    WRXB(0xD9, pApm->d9);
1134	    WRXB(0xDB, pApm->db);
1135	}
1136	WRXB(0xC9, pApm->c9);
1137	xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pApm->LinMap, pApm->LinMapSize);
1138	pApm->LinMap = NULL;
1139    }
1140    else if (pApm->FbBase)
1141	xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pApm->LinMap, 0x10000);
1142
1143    return TRUE;
1144}
1145
1146/*
1147 * This function saves the video state.
1148 */
1149static void
1150ApmSave(ScrnInfoPtr pScrn)
1151{
1152    APMDECL(pScrn);
1153    ApmRegPtr	ApmReg = &pApm->SavedReg;
1154    vgaHWPtr	hwp    = VGAHWPTR(pScrn);
1155
1156    if (pApm->VGAMap) {
1157	ApmReg->SEQ[0x1B] = ApmReadSeq(0x1B);
1158	ApmReg->SEQ[0x1C] = ApmReadSeq(0x1C);
1159
1160	/*
1161	 * Save fonts
1162	 */
1163	if (!(hwp->SavedReg.Attribute[0x10] & 1)) {
1164	    if (pApm->FontInfo || (pApm->FontInfo = malloc(TEXT_AMOUNT))) {
1165		int locked;
1166
1167		locked = ApmReadSeq(0x10);
1168		if (locked)
1169		    ApmWriteSeq(0x10, 0x12);
1170		ApmWriteSeq(0x1C, 0x3F);
1171		memcpy(pApm->FontInfo, pApm->FbBase, TEXT_AMOUNT);
1172		ApmWriteSeq(0x1C, ApmReg->SEQ[0x1C]);
1173		if (locked)
1174		    ApmWriteSeq(0x10, 0);
1175	    }
1176	}
1177	/*
1178	 * This function will handle creating the data structure and filling
1179	 * in the generic VGA portion.
1180	 */
1181	vgaHWSave(pScrn, &hwp->SavedReg, VGA_SR_MODE | VGA_SR_CMAP);
1182
1183	/* Hardware cursor registers. */
1184	ApmReg->EX[XR140] = RDXL(0x140);
1185	ApmReg->EX[XR144] = RDXW(0x144);
1186	ApmReg->EX[XR148] = RDXL(0x148);
1187	ApmReg->EX[XR14C] = RDXW(0x14C);
1188
1189	ApmReg->CRT[0x19] = ApmReadCrtc(0x19);
1190	ApmReg->CRT[0x1A] = ApmReadCrtc(0x1A);
1191	ApmReg->CRT[0x1B] = ApmReadCrtc(0x1B);
1192	ApmReg->CRT[0x1C] = ApmReadCrtc(0x1C);
1193	ApmReg->CRT[0x1D] = ApmReadCrtc(0x1D);
1194	ApmReg->CRT[0x1E] = ApmReadCrtc(0x1E);
1195
1196	/* RAMDAC registers. */
1197	ApmReg->EX[XRE8] = RDXL(0xE8);
1198	ApmReg->EX[XREC] = RDXL(0xEC);
1199
1200	/* Color correction */
1201	ApmReg->EX[XRE0] = RDXL(0xE0);
1202
1203	ApmReg->EX[XR80] = RDXB(0x80);
1204    }
1205    else {
1206	/*
1207	 * This function will handle creating the data structure and filling
1208	 * in the generic VGA portion.
1209	 */
1210	vgaHWSave(pScrn, &hwp->SavedReg, VGA_SR_ALL);
1211
1212	ApmReg->SEQ[0x1B] = rdinx(pApm->xport, 0x1B);
1213	ApmReg->SEQ[0x1C] = rdinx(pApm->xport, 0x1C);
1214
1215	/* Hardware cursor registers. */
1216	ApmReg->EX[XR140] = RDXL(0x140);
1217	ApmReg->EX[XR144] = RDXW(0x144);
1218	ApmReg->EX[XR148] = RDXL(0x148);
1219	ApmReg->EX[XR14C] = RDXW(0x14C);
1220
1221	ApmReg->CRT[0x19] = rdinx(pApm->iobase + 0x3D4, 0x19);
1222	ApmReg->CRT[0x1A] = rdinx(pApm->iobase + 0x3D4, 0x1A);
1223	ApmReg->CRT[0x1B] = rdinx(pApm->iobase + 0x3D4, 0x1B);
1224	ApmReg->CRT[0x1C] = rdinx(pApm->iobase + 0x3D4, 0x1C);
1225	ApmReg->CRT[0x1D] = rdinx(pApm->iobase + 0x3D4, 0x1D);
1226	ApmReg->CRT[0x1E] = rdinx(pApm->iobase + 0x3D4, 0x1E);
1227
1228	/* RAMDAC registers. */
1229	ApmReg->EX[XRE8] = RDXL(0xE8);
1230	ApmReg->EX[XREC] = RDXL(0xEC);
1231
1232	/* Color correction */
1233	ApmReg->EX[XRE0] = RDXL(0xE0);
1234
1235	ApmReg->EX[XR80] = RDXB(0x80);
1236    }
1237}
1238
1239#define WITHIN(v,c1,c2) (((v) >= (c1)) && ((v) <= (c2)))
1240
1241static unsigned
1242comp_lmn(ApmPtr pApm, long clock)
1243{
1244  int     n, m, l, f;
1245  double  fvco;
1246  double  fout;
1247  double  fmax, fmin;
1248  double  fref;
1249  double  fvco_goal;
1250  double  k, c;
1251  double fout_best = 0;
1252  unsigned int best = 0;
1253
1254  if (pApm->Chipset >= AT3D)
1255    fmax = 370000.0;
1256  else
1257    fmax = 250000.0;
1258
1259  fref = 14318.0;
1260  fmin = fmax / 2.0;
1261
1262  for (m = 1; m <= 5; m++)
1263  {
1264    for (l = 3; l >= 0; l--)
1265    {
1266      for (n = 8; n <= 127; n++)
1267      {
1268        fout = ((double)(n + 1) * fref)/((double)(m + 1) * (1 << l));
1269        fvco_goal = (double)clock * (double)(1 << l);
1270        fvco = fout * (double)(1 << l);
1271        if (!WITHIN(fvco, 0.99*fvco_goal, 1.01*fvco_goal))
1272          continue;
1273        if (!WITHIN(fvco, fmin, fmax))
1274          continue;
1275        if (!WITHIN(fvco / (double)(n+1), 300.0, 300000.0))
1276          continue;
1277        if (!WITHIN(fref / (double)(m+1), 300.0, 300000.0))
1278          continue;
1279
1280	if (fout_best != 0) {
1281	    double diff_new = clock - fout;
1282	    double diff_old = clock - best;
1283	    diff_new = diff_new < 0 ? -diff_new : diff_new;
1284	    diff_old = diff_old < 0 ? -diff_old : diff_old;
1285	    if (diff_new > diff_old)
1286		continue;
1287	}
1288	fout_best = fout;
1289
1290        /* The following formula was empirically derived by
1291           matching a number of fvco values with acceptable
1292           values of f.
1293
1294           (fvco can be 185MHz - 370MHz on AT3D)
1295           (fvco can be 125MHz - 250MHz on AT24/AP6422)
1296
1297           The table that was measured up follows:
1298
1299           AT3D
1300
1301           fvco       f
1302           (125)     (x-7) guess
1303           200       5-7
1304           219       4-7
1305           253       3-6
1306           289       2-5
1307           320       0-4
1308           (400)     (0-x) guess
1309
1310           AT24
1311
1312           fvco       f
1313           126       7
1314           200       5-7
1315           211       4-7
1316
1317           AP6422
1318
1319           fvco       f
1320           126       7
1321           169       5-7
1322           200       4-5
1323           211       4-5
1324
1325           From this, a function "f = k * fvco + c" was derived.
1326
1327           For AT3D, this table was measured with MCLK == 50MHz.
1328           The driver has since been set to use MCLK == 57.3MHz for,
1329           but I don't think that makes a difference here.
1330         */
1331
1332        if (pApm->Chipset >= AT24)
1333        {
1334          k = 7.0 / (175.0 - 380.0);
1335          c = -k * 380.0;
1336          f = (int)(k * fvco/1000.0 + c + 0.5);
1337          if (f > 7) f = 7;
1338          if (f < 0) f = 0;
1339        } else { /* i.e AP6422 */
1340          c = (211.0*6.0-169.0*4.5)/(211.0-169.0);
1341          k = (4.5-c)/211.0;
1342          f = (int)(k * fvco/1000.0 + c + 0.5);
1343          if (f > 7) f = 7;
1344          if (f < 0) f = 0;
1345        }
1346
1347        best =  (n << 16) | (m << 8) | (l << 2) | (f << 4);
1348      }
1349    }
1350  }
1351
1352  if (fout_best != 0)
1353      return best;
1354
1355  xf86DrvMsg(pApm->scrnIndex, X_PROBED,
1356		"Cannot find register values for clock %6.2f MHz. "
1357		"Please use a (slightly) different clock.\n",
1358		 (double)clock / 1000.0);
1359  return 0;
1360}
1361
1362/*
1363 * Initialise a new mode.  This is currently still using the old
1364 * "initialise struct, restore/write struct to HW" model.  That could
1365 * be changed.
1366 */
1367
1368static Bool
1369ApmModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
1370{
1371    APMDECL(pScrn);
1372    ApmRegPtr	ApmReg = &pApm->ModeReg;
1373    vgaHWPtr	hwp;
1374
1375
1376    /* set clockIndex to "2" for programmable clocks */
1377    if (pScrn->progClock)
1378	mode->ClockIndex = 2;
1379
1380    /* prepare standard VGA register contents */
1381    if (!vgaHWInit(pScrn, mode))
1382	return FALSE;
1383    pScrn->vtSema = TRUE;
1384    hwp = VGAHWPTR(pScrn);
1385
1386    hwp->writeMiscOut(hwp, pApm->MiscOut | 0x0F);
1387
1388#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 12
1389    if (xf86IsPc98())
1390       outb(0xFAC, 0xFF);
1391#endif
1392
1393    memcpy(ApmReg, &pApm->SavedReg, sizeof pApm->SavedReg);
1394
1395    /*
1396     * The APM chips have a scale factor of 8 for the
1397     * scanline offset. There are four extended bit in addition
1398     * to the 8 VGA bits.
1399     */
1400    {
1401	int offset;
1402
1403	offset = (pApm->CurrentLayout.displayWidth *
1404		  pApm->CurrentLayout.bitsPerPixel / 8)	>> 3;
1405	hwp->ModeReg.CRTC[0x13] = offset;
1406	/* Bit 8 resides at CR1C bits 7:4. */
1407	ApmReg->CRT[0x1C] = (offset & 0xF00) >> 4;
1408    }
1409
1410    /* Set pixel depth. */
1411    switch(pApm->CurrentLayout.bitsPerPixel)
1412    {
1413    case 4:
1414	 ApmReg->EX[XR80] = 0x01;
1415	 break;
1416    case 8:
1417	 ApmReg->EX[XR80] = 0x02;
1418	 break;
1419    case 16:
1420	 if (pApm->CurrentLayout.depth == 15)
1421	     ApmReg->EX[XR80] = 0x0C;
1422	 else
1423	     ApmReg->EX[XR80] = 0x0D;
1424	 break;
1425    case 24:
1426	 ApmReg->EX[XR80] = 0x0E;
1427	 break;
1428    case 32:
1429	 ApmReg->EX[XR80] = 0x0F;
1430	 break;
1431    default:
1432	 FatalError("Unsupported bit depth %d\n", pApm->CurrentLayout.depth);
1433	 break;
1434    }
1435
1436    /* Set banking register to zero. */
1437    ApmReg->EX[XRC0] = 0;
1438
1439    /* Handle the CRTC overflow bits. */
1440    {
1441	unsigned char val;
1442	/* Vertical Overflow. */
1443	val = 0;
1444	if ((mode->CrtcVTotal - 2) & 0x400)
1445	    val |= 0x01;
1446	if ((mode->CrtcVDisplay - 1) & 0x400)
1447	    val |= 0x02;
1448	/* VBlankStart is equal to VSyncStart + 1. */
1449	if (mode->CrtcVSyncStart & 0x400)
1450	    val |= 0x04;
1451	/* VRetraceStart is equal to VSyncStart + 1. */
1452	if (mode->CrtcVSyncStart & 0x400)
1453	    val |= 0x08;
1454	ApmReg->CRT[0x1A] = val;
1455
1456	/* Horizontal Overflow. */
1457	val = 0;
1458	if ((mode->CrtcHTotal / 8 - 5) & 0x100)
1459	    val |= 1;
1460	if ((mode->CrtcHDisplay / 8 - 1) & 0x100)
1461	    val |= 2;
1462	/* HBlankStart is equal to HSyncStart - 1. */
1463	if ((mode->CrtcHSyncStart / 8 - 1) & 0x100)
1464	    val |= 4;
1465	/* HRetraceStart is equal to HSyncStart. */
1466	if ((mode->CrtcHSyncStart / 8) & 0x100)
1467	    val |= 8;
1468	ApmReg->CRT[0x1B] = val;
1469
1470	/* Assume the CRTC is not KGA (see vgaHWInit) */
1471	hwp->ModeReg.CRTC[3] = (hwp->ModeReg.CRTC[3] & 0xE0) |
1472				(((mode->CrtcHBlankEnd >> 3) - 1) & 0x1F);
1473	hwp->ModeReg.CRTC[5]  = ((((mode->CrtcHBlankEnd >> 3) - 1) & 0x20) << 2)
1474				| (hwp->ModeReg.CRTC[5] & 0x7F);
1475	hwp->ModeReg.CRTC[22] = (mode->CrtcVBlankEnd - 1) & 0xFF;
1476    }
1477    ApmReg->CRT[0x1E] = 1;          /* disable autoreset feature */
1478
1479    /* Program clock select. */
1480    ApmReg->EX[XREC] = comp_lmn(pApm, mode->Clock);
1481    if (!ApmReg->EX[XREC])
1482      return FALSE;
1483    hwp->ModeReg.MiscOutReg |= 0x0C;
1484
1485    /* Set up the RAMDAC registers. */
1486
1487    if (pApm->CurrentLayout.bitsPerPixel > 8)
1488	/* Get rid of white border. */
1489	hwp->ModeReg.Attribute[0x11] = 0x00;
1490    else
1491	hwp->ModeReg.Attribute[0x11] = 0xFF;
1492    if (pApm->MemClk)
1493	ApmReg->EX[XRE8] = comp_lmn(pApm, pApm->MemClk);
1494    else if (pApm->Chipset >= AT3D)
1495	ApmReg->EX[XRE8] = 0x071F01E8; /* Enable 58MHz MCLK (actually 57.3 MHz)
1496				       This is what is used in the Windows
1497				       drivers. The BIOS sets it to 50MHz. */
1498    else
1499	ApmReg->EX[XRE8] = RDXL(0xE8); /* No change */
1500
1501    ApmReg->EX[XRE0] = 0x10;
1502
1503    /* If you change it, change in apm_funcs.c as well */
1504    if (pApm->Chipset >= AT3D) {
1505	ApmReg->SEQ[0x1B] = 0x20;
1506	ApmReg->SEQ[0x1C] = 0x2F;
1507    }
1508    else {
1509	ApmReg->SEQ[0x1B] = 0x24;
1510	if (pScrn->videoRam >= 6 * 1024)
1511	    ApmReg->SEQ[0x1C] = 0x2F;
1512	else
1513	    ApmReg->SEQ[0x1C] = 0x2D;
1514    }
1515
1516    /* ICICICICI */
1517    ApmRestore(pScrn, &hwp->ModeReg, ApmReg);
1518
1519    return TRUE;
1520}
1521
1522/*
1523 * Restore the initial mode.
1524 */
1525static void
1526ApmRestore(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, ApmRegPtr ApmReg)
1527{
1528    APMDECL(pScrn);
1529
1530    vgaHWProtect(pScrn, TRUE);
1531    ApmUnlock(pApm);
1532
1533    if (pApm->VGAMap) {
1534	/*
1535	 * Restore fonts
1536	 */
1537	if (!(vgaReg->Attribute[0x10] & 1) && pApm->FontInfo) {
1538	    ApmWriteSeq(0x1C, 0x3F);
1539	    memcpy(pApm->FbBase, pApm->FontInfo, TEXT_AMOUNT);
1540	}
1541
1542	/* Set aperture index to 0. */
1543	WRXW(0xC0, 0);
1544
1545	/*
1546	 * Write the extended registers first
1547	 */
1548	ApmWriteSeq(0x1B, ApmReg->SEQ[0x1B]);
1549	ApmWriteSeq(0x1C, ApmReg->SEQ[0x1C]);
1550
1551	/* Hardware cursor registers. */
1552	WRXL(0x140, ApmReg->EX[XR140]);
1553	WRXW(0x144, ApmReg->EX[XR144]);
1554	WRXL(0x148, ApmReg->EX[XR148]);
1555	WRXW(0x14C, ApmReg->EX[XR14C]);
1556
1557	ApmWriteCrtc(0x19, ApmReg->CRT[0x19]);
1558	ApmWriteCrtc(0x1A, ApmReg->CRT[0x1A]);
1559	ApmWriteCrtc(0x1B, ApmReg->CRT[0x1B]);
1560	ApmWriteCrtc(0x1D, ApmReg->CRT[0x1D]);
1561	ApmWriteCrtc(0x1E, ApmReg->CRT[0x1E]);
1562
1563	/* RAMDAC registers. */
1564	WRXL(0xE8, ApmReg->EX[XRE8]);
1565
1566	WRXL(0xEC, ApmReg->EX[XREC] & ~(1 << 7));
1567	WRXL(0xEC, ApmReg->EX[XREC] | (1 << 7)); /* Do a PLL resync */
1568
1569	/* Color correction */
1570	WRXL(0xE0, ApmReg->EX[XRE0]);
1571
1572	/*
1573	 * This function handles restoring the generic VGA registers.
1574	 */
1575	vgaHWRestore(pScrn, vgaReg, VGA_SR_MODE | VGA_SR_CMAP);
1576
1577	/* set these after setting the default VGA registers */
1578	ApmWriteCrtc(0x1C, ApmReg->CRT[0x1C]);
1579	WRXB(0x80, ApmReg->EX[XR80]);
1580    }
1581    else {
1582	/* Set aperture index to 0. */
1583	WRXW(0xC0, 0);
1584
1585	/*
1586	 * Write the extended registers first
1587	 */
1588	wrinx(pApm->xport, 0x1B, ApmReg->SEQ[0x1B]);
1589	wrinx(pApm->xport, 0x1C, ApmReg->SEQ[0x1C]);
1590
1591	/* Hardware cursor registers. */
1592	WRXL(0x140, ApmReg->EX[XR140]);
1593	WRXW(0x144, ApmReg->EX[XR144]);
1594	WRXL(0x148, ApmReg->EX[XR148]);
1595	WRXW(0x14C, ApmReg->EX[XR14C]);
1596
1597	wrinx(pApm->iobase + 0x3D4, 0x19, ApmReg->CRT[0x19]);
1598	wrinx(pApm->iobase + 0x3D4, 0x1A, ApmReg->CRT[0x1A]);
1599	wrinx(pApm->iobase + 0x3D4, 0x1B, ApmReg->CRT[0x1B]);
1600	wrinx(pApm->iobase + 0x3D4, 0x1C, ApmReg->CRT[0x1C]);
1601	wrinx(pApm->iobase + 0x3D4, 0x1D, ApmReg->CRT[0x1D]);
1602	wrinx(pApm->iobase + 0x3D4, 0x1E, ApmReg->CRT[0x1E]);
1603
1604	/* RAMDAC registers. */
1605	WRXL(0xE8, ApmReg->EX[XRE8]);
1606	WRXL(0xEC, ApmReg->EX[XREC] & ~(1 << 7));
1607	WRXL(0xEC, ApmReg->EX[XREC] | (1 << 7)); /* Do a PLL resync */
1608
1609	/* Color correction */
1610	WRXL(0xE0, ApmReg->EX[XRE0]);
1611
1612	WRXB(0x80, ApmReg->EX[XR80]);
1613
1614	/*
1615	 * This function handles restoring the generic VGA registers.
1616	 */
1617	vgaHWRestore(pScrn, vgaReg, VGA_SR_ALL);
1618    }
1619
1620    vgaHWProtect(pScrn, FALSE);
1621}
1622
1623
1624/* Refresh a region of the shadow framebuffer to the screen */
1625static void
1626ApmRefreshArea(ScrnInfoPtr pScrn, int num, BoxPtr pbox)
1627{
1628    APMDECL(pScrn);
1629    int width, height, Bpp, FBPitch;
1630    unsigned char *src, *dst;
1631
1632    Bpp = pApm->CurrentLayout.bitsPerPixel >> 3;
1633    FBPitch = pApm->CurrentLayout.bytesPerScanline;
1634
1635    while(num--) {
1636	width = (pbox->x2 - pbox->x1) * Bpp;
1637	height = pbox->y2 - pbox->y1;
1638	src = pApm->ShadowPtr + (pbox->y1 * pApm->ShadowPitch) +
1639						(pbox->x1 * Bpp);
1640	dst = (unsigned char *)pApm->FbBase + (pbox->y1 * FBPitch) + (pbox->x1 * Bpp);
1641
1642	while(height--) {
1643	    memcpy(dst, src, width);
1644	    dst += FBPitch;
1645	    src += pApm->ShadowPitch;
1646	}
1647
1648	pbox++;
1649    }
1650}
1651
1652
1653/* Mandatory */
1654
1655/* This gets called at the start of each server generation */
1656
1657static Bool
1658ApmScreenInit(SCREEN_INIT_ARGS_DECL)
1659{
1660    ScrnInfoPtr		pScrn = xf86ScreenToScrn(pScreen);
1661    APMDECL(pScrn);
1662    int			ret;
1663    unsigned char	*FbBase;
1664
1665    pApm->pScreen = pScreen;
1666
1667    /* Map the chip memory and MMIO areas */
1668    if (!ApmMapMem(pScrn))
1669	return FALSE;
1670
1671    /* No memory reserved yet */
1672    pApm->OffscreenReserved = 0;
1673
1674    /* Save the current state */
1675    ApmSave(pScrn);
1676
1677    /* Initialise the first mode */
1678    ApmModeInit(pScrn, pScrn->currentMode);
1679    pApm->CurrentLayout.pMode = pScrn->currentMode;
1680
1681    /* Darken the screen for aesthetic reasons and set the viewport */
1682    ApmSaveScreen(pScreen, SCREEN_SAVER_ON);
1683    ApmAdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0));
1684
1685    /*
1686     * Reset fb's visual list.
1687     */
1688    miClearVisualTypes();
1689
1690    /* Setup the visuals we support. */
1691
1692    /*
1693     * For bpp > 8, the default visuals are not acceptable because we only
1694     * support TrueColor and not DirectColor.  To deal with this, call
1695     * miSetVisualTypes for each visual supported.
1696     */
1697
1698    if (pApm->CurrentLayout.bitsPerPixel > 8) {
1699	if (!miSetVisualTypes(pScrn->depth, TrueColorMask, pScrn->rgbBits,
1700				pScrn->defaultVisual))
1701	    return FALSE;
1702    } else {
1703	if (!miSetVisualTypes(pScrn->depth,
1704			      miGetDefaultVisualMask(pScrn->depth),
1705			      pScrn->rgbBits, pScrn->defaultVisual))
1706	    return FALSE;
1707    }
1708
1709    /*
1710     * Call the framebuffer layer's ScreenInit function, and fill in other
1711     * pScreen fields.
1712     */
1713
1714    if(pApm->ShadowFB) {
1715	pApm->ShadowPitch =
1716		((pScrn->virtualX * pScrn->bitsPerPixel >> 3) + 3) & ~3L;
1717	pApm->ShadowPtr = malloc(pApm->ShadowPitch * pScrn->virtualY);
1718	FbBase = pApm->ShadowPtr;
1719    } else {
1720	pApm->ShadowPtr = NULL;
1721	FbBase = pApm->FbBase;
1722    }
1723
1724    /* Reserve memory */
1725    ApmHWCursorReserveSpace(pApm);
1726    ApmAccelReserveSpace(pApm);
1727
1728    miSetPixmapDepths();
1729
1730    switch (pScrn->bitsPerPixel) {
1731    case 8:
1732    case 16:
1733    case 24:
1734    case 32:
1735	ret = fbScreenInit(pScreen, FbBase, pScrn->virtualX,
1736	    pScrn->virtualY, pScrn->xDpi, pScrn->yDpi,
1737	    pScrn->displayWidth, pScrn->bitsPerPixel);
1738	break;
1739    default:
1740	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1741	    "Internal error: invalid bpp (%d) in ApmScrnInit\n",
1742	    pScrn->bitsPerPixel);
1743	ret = FALSE;
1744	break;
1745    }
1746    if (!ret)
1747	return FALSE;
1748
1749    if (pScrn->bitsPerPixel > 8) {
1750	VisualPtr	visual;
1751
1752	/* Fixup RGB ordering */
1753	visual = pScreen->visuals + pScreen->numVisuals;
1754	while (--visual >= pScreen->visuals) {
1755	    if ((visual->class | DynamicClass) == DirectColor) {
1756		visual->offsetRed = pScrn->offset.red;
1757		visual->offsetGreen = pScrn->offset.green;
1758		visual->offsetBlue = pScrn->offset.blue;
1759		visual->redMask = pScrn->mask.red;
1760		visual->greenMask = pScrn->mask.green;
1761		visual->blueMask = pScrn->mask.blue;
1762	    }
1763	}
1764    }
1765
1766    /* must be after visual RGB order fixed */
1767    if (pScrn->bitsPerPixel > 4)
1768	fbPictureInit(pScreen, 0, 0);
1769
1770    xf86SetBlackWhitePixels(pScreen);
1771
1772    if (!pApm->ShadowFB) {       /* hardware cursor needs to wrap this layer */
1773	if(!ApmDGAInit(pScreen)) {
1774	    xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"DGA initialization failed\n");
1775	}
1776    }
1777
1778    /*
1779     * Initialize the acceleration interface.
1780     */
1781#ifdef HAVE_XAA_H
1782    if (!pApm->NoAccel) {
1783	ApmAccelInit(pScreen);		/* set up XAA interface */
1784    }
1785#endif
1786
1787    miInitializeBackingStore(pScreen);
1788    xf86SetBackingStore(pScreen);
1789    xf86SetSilkenMouse(pScreen);
1790
1791    /* Initialise cursor functions */
1792    miDCInitialize (pScreen, xf86GetPointerScreenFuncs());
1793
1794    /* Initialize HW cursor layer (after DGA and SW cursor) */
1795    if (pApm->hwCursor) {
1796	if (!ApmHWCursorInit(pScreen))
1797            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1798                "Hardware cursor initialization failed\n");
1799    }
1800
1801
1802    /* Initialise default colourmap */
1803    if (!miCreateDefColormap(pScreen))
1804	return FALSE;
1805
1806    /*
1807     * Initialize colormap layer.
1808     * Must follow initialization of the default colormap.
1809     */
1810    if (!xf86HandleColormaps(pScreen, 256, 8, ApmLoadPalette, NULL,
1811				CMAP_RELOAD_ON_MODE_SWITCH)) {
1812	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Colormap initialization failed\n");
1813	return FALSE;
1814    }
1815
1816    if (pApm->ShadowFB)
1817	ShadowFBInit(pScreen, ApmRefreshArea);
1818
1819    xf86DPMSInit(pScreen, ApmDisplayPowerManagementSet, 0);
1820
1821    ApmInitVideo(pScreen);
1822
1823    pScreen->SaveScreen  = ApmSaveScreen;
1824
1825    pApm->CloseScreen = pScreen->CloseScreen;
1826    pScreen->CloseScreen = ApmCloseScreen;
1827
1828    pScrn->memPhysBase = pApm->LinAddress;
1829    pScrn->fbOffset = (((char *)pApm->FbBase) - ((char *)pApm->LinMap));
1830
1831    /* Report any unused options (only for the first generation) */
1832    if (serverGeneration == 1) {
1833	xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
1834    }
1835
1836#ifdef XF86RUSH
1837    if (ApmGeneration != serverGeneration) {
1838	if ((ApmPixmapIndex = AllocatePixmapPrivateIndex()) < 0)
1839	    return FALSE;
1840	ApmGeneration = serverGeneration;
1841    }
1842
1843    if (!AllocatePixmapPrivate(pScreen, ApmPixmapIndex, sizeof(ApmPixmapRec)))
1844	return FALSE;
1845#endif
1846
1847    /* Done */
1848    return TRUE;
1849}
1850
1851/* mandatory */
1852static void
1853ApmLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors,
1854	       VisualPtr pVisual)
1855{
1856    APMDECL(pScrn);
1857    int i, index, last = -1;
1858
1859    if (pApm->VGAMap) {
1860	for (i = 0; i < numColors; i++) {
1861	    index = indices[i];
1862	    if (index != last)
1863		ApmWriteDacWriteAddr(index);
1864	    last = index + 1;
1865	    ApmWriteDacData(colors[index].red);
1866	    ApmWriteDacData(colors[index].green);
1867	    ApmWriteDacData(colors[index].blue);
1868	}
1869    }
1870    else {
1871	for (i = 0; i < numColors; i++) {
1872	    index = indices[i];
1873	    if (index != last)
1874		outb(pApm->iobase + 0x3C8, index);
1875	    last = index + 1;
1876	    outb(pApm->iobase + 0x3C9, colors[index].red);
1877	    outb(pApm->iobase + 0x3C9, colors[index].green);
1878	    outb(pApm->iobase + 0x3C9, colors[index].blue);
1879	}
1880    }
1881}
1882
1883/* Usually mandatory */
1884Bool
1885ApmSwitchMode(SWITCH_MODE_ARGS_DECL)
1886{
1887    SCRN_INFO_PTR(arg);
1888    return ApmModeInit(pScrn, mode);
1889}
1890
1891/*
1892 * This function is used to initialize the Start Address - the first
1893 * displayed location in the video memory.
1894 */
1895/* Usually mandatory */
1896void
1897ApmAdjustFrame(ADJUST_FRAME_ARGS_DECL)
1898{
1899    SCRN_INFO_PTR(arg);
1900    APMDECL(pScrn);
1901    int Base;
1902
1903    if (pApm->CurrentLayout.bitsPerPixel == 24)
1904	x = (x + 3) & ~3;
1905    Base = ((y * pApm->CurrentLayout.displayWidth + x) * (pApm->CurrentLayout.bitsPerPixel / 8)) >> 2;
1906    /*
1907     * These are the generic starting address registers.
1908     */
1909    if (pApm->VGAMap) {
1910	ApmWriteCrtc(0x0C, Base >> 8);
1911	ApmWriteCrtc(0x0D, Base);
1912
1913	/*
1914	 * Here the high-order bits are masked and shifted, and put into
1915	 * the appropriate extended registers.
1916	 */
1917	ApmWriteCrtc(0x1C, (ApmReadCrtc(0x1C) & 0xF0) | ((Base & 0x0F0000) >> 16));
1918    }
1919    else {
1920	outw(pApm->iobase + 0x3D4, (Base & 0x00FF00) | 0x0C);
1921	outw(pApm->iobase + 0x3D4, ((Base & 0x00FF) << 8) | 0x0D);
1922
1923	/*
1924	 * Here the high-order bits are masked and shifted, and put into
1925	 * the appropriate extended registers.
1926	 */
1927	modinx(pApm->iobase + 0x3D4, 0x1C, 0x0F, (Base & 0x0F0000) >> 16);
1928    }
1929}
1930
1931/*
1932 * This is called when VT switching back to the X server.  Its job is
1933 * to reinitialise the video mode.
1934 *
1935 * We may wish to unmap video/MMIO memory too.
1936 */
1937
1938/* Mandatory */
1939static Bool
1940ApmEnterVT(VT_FUNC_ARGS_DECL)
1941{
1942    SCRN_INFO_PTR(arg);
1943    APMDECL(pScrn);
1944    vgaHWPtr	hwp = VGAHWPTR(pScrn);
1945
1946    if (pApm->Chipset >= AT3D) {
1947	/* If you change it, change it also in apm_funcs.c */
1948	WRXB(0xDB, (pApm->db & 0xF4) | 0x0A | pApm->Rush);
1949	WRXB(0xD9, (pApm->d9 & 0xCF) | 0x20);
1950    }
1951    if (pApm->Chipset >= AP6422)
1952	WRXB(0xC9, pApm->c9 | 0x10);
1953    ApmUnlock(APMPTR(pScrn));
1954    vgaHWUnlock(hwp);
1955    /*
1956     * Set color mode
1957     */
1958    hwp->writeMiscOut(hwp, pApm->MiscOut | 0x0F);
1959
1960    if (!ApmModeInit(pScrn, pScrn->currentMode))
1961	return FALSE;
1962    ApmAdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0));
1963
1964    return TRUE;
1965}
1966
1967/* Mandatory */
1968static void
1969ApmLeaveVT(VT_FUNC_ARGS_DECL)
1970{
1971    SCRN_INFO_PTR(arg);
1972    APMDECL(pScrn);
1973    vgaHWPtr	hwp = VGAHWPTR(pScrn);
1974
1975    ApmRestore(pScrn, &hwp->SavedReg, &pApm->SavedReg);
1976    /*
1977     * Reset color mode
1978     */
1979    (*hwp->writeMiscOut)(hwp, pApm->MiscOut);
1980    vgaHWLock(hwp);
1981    ApmLock(pApm);
1982    if (pApm->Chipset >= AT3D) {
1983	WRXB(0xD9, pApm->d9);
1984	WRXB(0xDB, pApm->db);
1985    }
1986    WRXB(0xC9, pApm->c9);
1987
1988#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 12
1989    if (xf86IsPc98())
1990	outb(0xFAC, 0xFE);
1991#endif
1992}
1993
1994/*
1995 * This is called at the end of each server generation.  It restores the
1996 * original (text) mode.  It should really also unmap the video memory too.
1997 */
1998
1999/* Mandatory */
2000static Bool
2001ApmCloseScreen(CLOSE_SCREEN_ARGS_DECL)
2002{
2003    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
2004    vgaHWPtr	hwp = VGAHWPTR(pScrn);
2005    APMDECL(pScrn);
2006
2007    if (pScrn->vtSema) {
2008	ApmRestore(pScrn, &hwp->SavedReg, &pApm->SavedReg);
2009	vgaHWLock(hwp);
2010	ApmUnmapMem(pScrn);
2011    }
2012#ifdef HAVE_XAA_H
2013    if(pApm->AccelInfoRec)
2014	XAADestroyInfoRec(pApm->AccelInfoRec);
2015    if(pApm->DGAXAAInfo)
2016	XAADestroyInfoRec(pApm->DGAXAAInfo);
2017    pApm->AccelInfoRec = NULL;
2018#endif
2019    if(pApm->CursorInfoRec)
2020	xf86DestroyCursorInfoRec(pApm->CursorInfoRec);
2021    pApm->CursorInfoRec = NULL;
2022    free(pApm->DGAModes);
2023    free(pApm->adaptor);
2024
2025    pScrn->vtSema = FALSE;
2026
2027#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 12
2028    if (xf86IsPc98())
2029	outb(0xFAC, 0xFE);
2030#endif
2031
2032    pScreen->CloseScreen = pApm->CloseScreen;
2033    return (*pScreen->CloseScreen)(CLOSE_SCREEN_ARGS);
2034}
2035
2036/* Free up any per-generation data structures */
2037
2038/* Optional */
2039static void
2040ApmFreeScreen(FREE_SCREEN_ARGS_DECL)
2041{
2042    SCRN_INFO_PTR(arg);
2043    vgaHWFreeHWRec(pScrn);
2044    ApmFreeRec(pScrn);
2045}
2046
2047/* Checks if a mode is suitable for the selected chipset. */
2048
2049/* Optional */
2050static ModeStatus
2051ApmValidMode(SCRN_ARG_TYPE arg, DisplayModePtr mode, Bool verbose, int flags)
2052{
2053    if (mode->Flags & V_INTERLACE)
2054	return(MODE_BAD);
2055
2056    return(MODE_OK);
2057}
2058
2059
2060/*
2061 * ApmDisplayPowerManagementSet --
2062 *
2063 * Sets VESA Display Power Management Signaling (DPMS) Mode.
2064 */
2065static void
2066ApmDisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode,
2067			     int flags)
2068{
2069    APMDECL(pScrn);
2070    unsigned char dpmsreg, tmp;
2071
2072    if (PowerManagementMode < sizeof pApm->DPMSMask &&
2073	    PowerManagementMode >= 0)
2074	PowerManagementMode = pApm->DPMSMask[PowerManagementMode];
2075    switch (PowerManagementMode)
2076    {
2077    case DPMSModeOn:
2078	/* Screen: On; HSync: On, VSync: On */
2079	dpmsreg = 0x00;
2080	break;
2081    case DPMSModeStandby:
2082	/* Screen: Off; HSync: Off, VSync: On */
2083	dpmsreg = 0x01;
2084	break;
2085    case DPMSModeSuspend:
2086	/* Screen: Off; HSync: On, VSync: Off */
2087	dpmsreg = 0x02;
2088	break;
2089    case DPMSModeOff:
2090	/* Screen: Off; HSync: Off, VSync: Off */
2091	dpmsreg = 0x03;
2092	break;
2093    default:
2094	dpmsreg = 0;
2095    }
2096    tmp = RDXB(0xD0);
2097    WRXB(0xD0, (tmp & 0xFC) | dpmsreg);
2098}
2099
2100static Bool
2101ApmSaveScreen(ScreenPtr pScreen, int mode)
2102{
2103    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
2104    Bool unblank;
2105
2106    unblank = xf86IsUnblank(mode);
2107
2108    if (unblank)
2109	SetTimeSinceLastInputEvent();
2110
2111    if (pScrn->vtSema)
2112	vgaHWBlankScreen(pScrn, unblank);
2113    return TRUE;
2114}
2115
2116#ifdef APM_DEBUG
2117unsigned char _L_ACR(unsigned char *x);
2118unsigned char _L_ACR(unsigned char *x)
2119{
2120    return *x;
2121}
2122
2123unsigned short _L_ASR(unsigned short *x);
2124unsigned short _L_ASR(unsigned short *x)
2125{
2126    return *x;
2127}
2128
2129unsigned int _L_AIR(unsigned int *x);
2130unsigned int _L_AIR(unsigned int *x)
2131{
2132    return *x;
2133}
2134
2135void _L_ACW(char *x, char y);
2136void _L_ACW(char *x, char y)
2137{
2138    *x = y;
2139}
2140
2141void _L_ASW(short *x, short y);
2142void _L_ASW(short *x, short y)
2143{
2144    *x = y;
2145}
2146
2147void _L_AIW(int *x, int y);
2148void _L_AIW(int *x, int y)
2149{
2150    *x = y;
2151}
2152#endif
2153