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