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