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