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