neo_driver.c revision 85ee4c00
1/**********************************************************************
2Copyright 1998, 1999 by Precision Insight, Inc., Cedar Park, Texas.
3
4                        All Rights Reserved
5
6Permission to use, copy, modify, distribute, and sell this software and
7its documentation for any purpose is hereby granted without fee,
8provided that the above copyright notice appear in all copies and that
9both that copyright notice and this permission notice appear in
10supporting documentation, and that the name of Precision Insight not be
11used in advertising or publicity pertaining to distribution of the
12software without specific, written prior permission.  Precision Insight
13and its suppliers make no representations about the suitability of this
14software for any purpose.  It is provided "as is" without express or
15implied warranty.
16
17PRECISION INSIGHT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
18INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
19EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY
20SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
21RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
22CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
23CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24**********************************************************************/
25
26/*
27 * Copyright 1998, 1999 Egbert Eich
28 * Copyright 2000, 2001 SuSE GmbH, Author: Egbert Eich
29 * Copyright 2002 SuSE Linux AG, Author: Egbert Eich
30 * Copyright 2002 Shigehiro Nomura
31 */
32
33
34/*
35 * The original Precision Insight driver for
36 * XFree86 v.3.3 has been sponsored by Red Hat.
37 *
38 * Authors:
39 *   Jens Owen (jens@tungstengraphics.com)
40 *   Kevin E. Martin (kevin@precisioninsight.com)
41 *
42 * Port to Xfree86 v.4.0
43 *   1998, 1999 by Egbert Eich (Egbert.Eich@Physik.TU-Darmstadt.DE)
44 */
45
46#ifdef HAVE_CONFIG_H
47#include "config.h"
48#endif
49
50/* All drivers should typically include these */
51#include "xf86.h"
52#include "xf86_OSproc.h"
53
54/* Everything using inb/outb, etc needs "compiler.h" */
55#include "compiler.h"
56
57#include "xf86Resources.h"
58
59/* Drivers for PCI hardware need this */
60#include "xf86PciInfo.h"
61
62/* Drivers that need to access the PCI config space directly need this */
63#include "xf86Pci.h"
64
65/* All drivers using the vgahw module need this */
66#include "vgaHW.h"
67
68/* All drivers initialising the SW cursor need this */
69#include "mipointer.h"
70
71/* All drivers implementing backing store need this */
72#include "mibstore.h"
73
74/* All drivers using the mi banking wrapper need this */
75#include "mibank.h"
76
77/* All drivers using the mi colormap manipulation need this */
78#include "micmap.h"
79
80#include "xf86cmap.h"
81
82#include "fb.h"
83
84/* Needed by Resources Access Control (RAC) */
85#include "xf86RAC.h"
86
87/* int10 */
88#include "xf86int10.h"
89#include "vbe.h"
90
91/* Needed for Device Data Channel (DDC) support */
92#include "xf86DDC.h"
93
94#include "picturestr.h"
95
96#include "xf86xv.h"
97#include <X11/extensions/Xv.h>
98
99/*
100 * Driver data structures.
101 */
102#include "neo.h"
103#include "neo_reg.h"
104#include "neo_macros.h"
105
106/* These need to be checked */
107#include <X11/X.h>
108#include <X11/Xproto.h>
109#include "scrnintstr.h"
110#include "servermd.h"
111#ifdef XFreeXDGA
112#define _XF86DGA_SERVER_
113#include <X11/extensions/xf86dgastr.h>
114#endif
115
116/* Mandatory functions */
117static const OptionInfoRec *	NEOAvailableOptions(int chipid, int busid);
118static void     NEOIdentify(int flags);
119static Bool     NEOProbe(DriverPtr drv, int flags);
120static Bool     NEOPreInit(ScrnInfoPtr pScrn, int flags);
121static Bool     NEOScreenInit(int Index, ScreenPtr pScreen, int argc,
122                                  char **argv);
123static Bool     NEOEnterVT(int scrnIndex, int flags);
124static void     NEOLeaveVT(int scrnIndex, int flags);
125static Bool     NEOCloseScreen(int scrnIndex, ScreenPtr pScreen);
126static void     NEOFreeScreen(int scrnIndex, int flags);
127static ModeStatus NEOValidMode(int scrnIndex, DisplayModePtr mode,
128                               Bool verbose, int flags);
129
130/* Internally used functions */
131static int      neoFindIsaDevice(GDevPtr dev);
132static Bool     neoModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode);
133static void     neoSave(ScrnInfoPtr pScrn);
134static void     neoRestore(ScrnInfoPtr pScrn, vgaRegPtr VgaReg,
135				 NeoRegPtr NeoReg, Bool restoreText);
136static void     neoLock(ScrnInfoPtr pScrn);
137static void     neoUnlock(ScrnInfoPtr pScrn);
138static Bool	neoMapMem(ScrnInfoPtr pScrn);
139static Bool	neoUnmapMem(ScrnInfoPtr pScrn);
140static void     neoProgramShadowRegs(ScrnInfoPtr pScrn, vgaRegPtr VgaReg,
141				     NeoRegPtr restore);
142static void     neoCalcVCLK(ScrnInfoPtr pScrn, long freq);
143static xf86MonPtr  neo_ddc1(int scrnIndex);
144static Bool     neoDoDDC1(ScrnInfoPtr pScrn);
145static Bool     neoDoDDC2(ScrnInfoPtr pScrn);
146static Bool     neoDoDDCVBE(ScrnInfoPtr pScrn);
147static void     neoProbeDDC(ScrnInfoPtr pScrn, int index);
148static void     NeoDisplayPowerManagementSet(ScrnInfoPtr pScrn,
149				int PowerManagementMode, int flags);
150static int      neoFindMode(int xres, int yres, int depth);
151
152#define NEO_VERSION 4000
153#define NEO_NAME "NEOMAGIC"
154#define NEO_DRIVER_NAME "neomagic"
155
156#define NEO_MAJOR_VERSION PACKAGE_VERSION_MAJOR
157#define NEO_MINOR_VERSION PACKAGE_VERSION_MINOR
158#define NEO_PATCHLEVEL PACKAGE_VERSION_PATCHLEVEL
159
160/*
161 * This is intentionally screen-independent.  It indicates the binding
162 * choice made in the first PreInit.
163 */
164static int pix24bpp = 0;
165
166
167static biosMode bios8[] = {
168    { 320, 240, 0x40 },
169    { 300, 400, 0x42 },
170    { 640, 400, 0x20 },
171    { 640, 480, 0x21 },
172    { 800, 600, 0x23 },
173    { 1024, 768, 0x25 }
174};
175
176static biosMode bios15[] = {
177    { 320, 200, 0x2D },
178    { 640, 480, 0x30 },
179    { 800, 600, 0x33 },
180    { 1024, 768, 0x36 }
181};
182
183static biosMode bios16[] = {
184    { 320, 200, 0x2e },
185    { 320, 240, 0x41 },
186    { 300, 400, 0x43 },
187    { 640, 480, 0x31 },
188    { 800, 600, 0x34 },
189    { 1024, 768, 0x37 }
190};
191
192static biosMode bios24[] = {
193    { 640, 480, 0x32 },
194    { 800, 600, 0x35 },
195    { 1024, 768, 0x38 }
196};
197
198static DisplayModeRec neo800x480Mode = {
199	NULL,           /* prev */
200	NULL,           /* next */
201	"800x480",      /* identifier of this mode */
202	MODE_OK,        /* mode status */
203	M_T_BUILTIN,    /* mode type */
204	35260,		/* Clock frequency */
205	800,		/* HDisplay */
206	856,		/* HSyncStart */
207	1040,		/* HSyncEnd */
208	1056,		/* HTotal */
209	0,		/* HSkew */
210	480,		/* VDisplay */
211	480,		/* VSyncStart */
212	486,		/* VSyncEnd */
213	488,		/* VTotal */
214	0,		/* VScan */
215	V_PHSYNC | V_PVSYNC,	/* Flags */
216	-1,		/* ClockIndex */
217	35260,		/* SynthClock */
218	800,		/* CRTC HDisplay */
219	800,            /* CRTC HBlankStart */
220	856,            /* CRTC HSyncStart */
221	1040,           /* CRTC HSyncEnd */
222	872,            /* CRTC HBlankEnd */
223	1048,           /* CRTC HTotal */
224	0,              /* CRTC HSkew */
225	480,		/* CRTC VDisplay */
226	480,		/* CRTC VBlankStart */
227	480,		/* CRTC VSyncStart */
228	486,		/* CRTC VSyncEnd */
229	487,		/* CRTC VBlankEnd */
230	488,		/* CRTC VTotal */
231	FALSE,		/* CrtcHAdjusted */
232	FALSE,		/* CrtcVAdjusted */
233	0,		/* PrivSize */
234	NULL,		/* Private */
235	0.0,		/* HSync */
236	0.0		/* VRefresh */
237};
238
239static DisplayModeRec neo1024x480Mode = {
240	NULL,           /* prev */
241	NULL,           /* next */
242	"1024x480",      /* identifier of this mode */
243	MODE_OK,        /* mode status */
244	M_T_BUILTIN,    /* mode type */
245	45900,		/* Clock frequency */
246	1024,		/* HDisplay */
247	1048,		/* HSyncStart */
248	1184,		/* HSyncEnd */
249	1344,		/* HTotal */
250	0,		/* HSkew */
251	480,		/* VDisplay */
252	480,		/* VSyncStart */
253	486,		/* VSyncEnd */
254	488,		/* VTotal */
255	0,		/* VScan */
256	V_PHSYNC | V_PVSYNC,	/* Flags */
257	-1,		/* ClockIndex */
258	45900,		/* SynthClock */
259	1024,		/* CRTC HDisplay */
260	1024,            /* CRTC HBlankStart */
261	1048,            /* CRTC HSyncStart */
262	1184,           /* CRTC HSyncEnd */
263	1072,            /* CRTC HBlankEnd */
264	1344,           /* CRTC HTotal */
265	0,              /* CRTC HSkew */
266	480,		/* CRTC VDisplay */
267	480,		/* CRTC VBlankStart */
268	480,		/* CRTC VSyncStart */
269	486,		/* CRTC VSyncEnd */
270	487,		/* CRTC VBlankEnd */
271	488,		/* CRTC VTotal */
272	FALSE,		/* CrtcHAdjusted */
273	FALSE,		/* CrtcVAdjusted */
274	0,		/* PrivSize */
275	NULL,		/* Private */
276	0.0,		/* HSync */
277	0.0		/* VRefresh */
278};
279
280/*
281 * This contains the functions needed by the server after loading the driver
282 * module.  It must be supplied, and gets passed back by the SetupProc
283 * function in the dynamic case.  In the static case, a reference to this
284 * is compiled in, and this requires that the name of this DriverRec be
285 * an upper-case version of the driver name.
286 */
287
288_X_EXPORT DriverRec NEOMAGIC = {
289    NEO_VERSION,
290    NEO_DRIVER_NAME,
291    NEOIdentify,
292    NEOProbe,
293    NEOAvailableOptions,
294    NULL,
295    0
296};
297
298static SymTabRec NEOChipsets[] = {
299    { NM2070,   "neo2070" },
300    { NM2090,   "neo2090" },
301    { NM2093,   "neo2093" },
302    { NM2097,   "neo2097" },
303    { NM2160,   "neo2160" },
304    { NM2200,   "neo2200" },
305    { NM2230,   "neo2230" },
306    { NM2360,   "neo2360" },
307    { NM2380,   "neo2380" },
308    { -1,		 NULL }
309};
310
311/* Conversion PCI ID to chipset name */
312static PciChipsets NEOPCIchipsets[] = {
313    { NM2070,  PCI_CHIP_NM2070,  RES_SHARED_VGA },
314    { NM2090,  PCI_CHIP_NM2090,  RES_SHARED_VGA },
315    { NM2093,  PCI_CHIP_NM2093,  RES_SHARED_VGA },
316    { NM2097,  PCI_CHIP_NM2097,  RES_SHARED_VGA },
317    { NM2160,  PCI_CHIP_NM2160,  RES_SHARED_VGA },
318    { NM2200,  PCI_CHIP_NM2200,  RES_SHARED_VGA },
319    { NM2230,  PCI_CHIP_NM2230,  RES_SHARED_VGA },
320    { NM2360,  PCI_CHIP_NM2360,  RES_SHARED_VGA },
321    { NM2380,  PCI_CHIP_NM2380,  RES_SHARED_VGA },
322    { -1,	     -1,	     RES_UNDEFINED}
323};
324
325#ifdef HAVE_ISA
326static IsaChipsets NEOISAchipsets[] = {
327    { NM2070,               RES_EXCLUSIVE_VGA },
328    { NM2090,               RES_EXCLUSIVE_VGA },
329    { NM2093,               RES_EXCLUSIVE_VGA },
330    { NM2097,               RES_EXCLUSIVE_VGA },
331    { NM2160,               RES_EXCLUSIVE_VGA },
332    { NM2200,               RES_EXCLUSIVE_VGA },
333    { -1,			RES_UNDEFINED }
334};
335#endif
336
337/* The options supported by the Neomagic Driver */
338typedef enum {
339    OPTION_NOLINEAR_MODE,
340    OPTION_NOACCEL,
341    OPTION_SW_CURSOR,
342    OPTION_NO_MMIO,
343    OPTION_INTERN_DISP,
344    OPTION_EXTERN_DISP,
345    OPTION_LCD_CENTER,
346    OPTION_LCD_STRETCH,
347    OPTION_SHADOW_FB,
348    OPTION_PCI_BURST,
349    OPTION_PROG_LCD_MODE_REGS,
350    OPTION_PROG_LCD_MODE_STRETCH,
351    OPTION_OVERRIDE_VALIDATE_MODE,
352    OPTION_SHOWCACHE,
353    OPTION_ROTATE,
354    OPTION_VIDEO_KEY,
355    OPTION_OVERLAYMEM,
356    OPTION_VIDEO_INTERLACE,
357    OPTION_DISPLAY_HEIGHT_480,
358    OPTION_STRANGE_LOCKUPS
359} NEOOpts;
360
361static const OptionInfoRec NEO_2070_Options[] = {
362    { OPTION_NOACCEL,	"NoAccel",	OPTV_BOOLEAN,	{0}, FALSE },
363    { OPTION_SW_CURSOR,	"SWcursor",	OPTV_BOOLEAN,	{0}, FALSE },
364    { OPTION_NO_MMIO,	"noMMIO",	OPTV_BOOLEAN,	{0}, FALSE },
365    { OPTION_INTERN_DISP,"internDisp",	OPTV_BOOLEAN,	{0}, FALSE },
366    { OPTION_EXTERN_DISP,"externDisp",  OPTV_BOOLEAN,	{0}, FALSE },
367    { OPTION_LCD_CENTER, "LcdCenter",	OPTV_BOOLEAN,	{0}, FALSE },
368    { OPTION_LCD_STRETCH, "NoStretch",	OPTV_BOOLEAN,	{0}, FALSE },
369    { OPTION_SHADOW_FB,   "ShadowFB",	OPTV_BOOLEAN,	{0}, FALSE },
370    { OPTION_PCI_BURST,	 "pciBurst",	OPTV_BOOLEAN,   {0}, FALSE },
371    { OPTION_SHOWCACHE,  "ShowCache",   OPTV_BOOLEAN,	{0}, FALSE },
372    { OPTION_ROTATE, 	 "Rotate",	OPTV_ANYSTR,	{0}, FALSE },
373    { OPTION_PROG_LCD_MODE_REGS, "progLcdModeRegs",
374      OPTV_BOOLEAN, {0}, FALSE },
375    { OPTION_PROG_LCD_MODE_STRETCH, "progLcdModeStretch",
376      OPTV_BOOLEAN, {0}, FALSE },
377    { OPTION_OVERRIDE_VALIDATE_MODE, "overrideValidateMode",
378      OPTV_BOOLEAN, {0}, FALSE },
379    { OPTION_VIDEO_KEY, "VideoKey",     OPTV_INTEGER,   {0}, FALSE },
380    { OPTION_OVERLAYMEM, "OverlayMem",  OPTV_INTEGER,   {0}, FALSE },
381    { OPTION_VIDEO_INTERLACE, "Interlace",
382      OPTV_INTEGER,   {0}, FALSE },
383    { -1,                  NULL,           OPTV_NONE,	{0}, FALSE }
384};
385
386static const OptionInfoRec NEOOptions[] = {
387    { OPTION_NOLINEAR_MODE,"NoLinear",  OPTV_BOOLEAN,	{0}, FALSE },
388    { OPTION_NOACCEL,	"NoAccel",	OPTV_BOOLEAN,	{0}, FALSE },
389    { OPTION_SW_CURSOR,	"SWcursor",	OPTV_BOOLEAN,	{0}, FALSE },
390    { OPTION_NO_MMIO,	"noMMIO",	OPTV_BOOLEAN,	{0}, FALSE },
391    { OPTION_INTERN_DISP,"internDisp",	OPTV_BOOLEAN,	{0}, FALSE },
392    { OPTION_EXTERN_DISP,"externDisp",	OPTV_BOOLEAN,	{0}, FALSE },
393    { OPTION_LCD_CENTER, "LcdCenter",	OPTV_BOOLEAN,	{0}, FALSE },
394    { OPTION_SHADOW_FB,  "ShadowFB",	OPTV_BOOLEAN,	{0}, FALSE },
395    { OPTION_LCD_STRETCH,"NoStretch",	OPTV_BOOLEAN,	{0}, FALSE },
396    { OPTION_PCI_BURST,	 "pciBurst",	OPTV_BOOLEAN,	{0}, FALSE },
397    { OPTION_SHOWCACHE,  "ShowCache",   OPTV_BOOLEAN,	{0}, FALSE },
398    { OPTION_ROTATE, 	 "Rotate",	OPTV_ANYSTR,	{0}, FALSE },
399    { OPTION_STRANGE_LOCKUPS, "StrangeLockups", OPTV_BOOLEAN, {0}, FALSE },
400    { OPTION_DISPLAY_HEIGHT_480, "DisplayHeight480",
401      OPTV_BOOLEAN, {0}, FALSE },
402    { OPTION_PROG_LCD_MODE_REGS, "progLcdModeRegs",
403      OPTV_BOOLEAN, {0}, FALSE },
404    { OPTION_PROG_LCD_MODE_STRETCH, "progLcdModeStretch",
405      OPTV_BOOLEAN, {0}, FALSE },
406    { OPTION_OVERRIDE_VALIDATE_MODE, "overrideValidateMode",
407      OPTV_BOOLEAN, {0}, FALSE },
408    { OPTION_VIDEO_KEY, "VideoKey",     OPTV_INTEGER,   {0}, FALSE },
409    { OPTION_OVERLAYMEM, "OverlayMem",  OPTV_INTEGER,   {0}, FALSE },
410    { OPTION_VIDEO_INTERLACE, "Interlace",
411      OPTV_INTEGER,   {0}, FALSE },
412    { -1,                  NULL,           OPTV_NONE,	{0}, FALSE }
413};
414
415#ifdef XFree86LOADER
416
417static MODULESETUPPROTO(neoSetup);
418
419static XF86ModuleVersionInfo neoVersRec =
420{
421	"neomagic",
422	MODULEVENDORSTRING,
423	MODINFOSTRING1,
424	MODINFOSTRING2,
425	XORG_VERSION_CURRENT,
426	NEO_MAJOR_VERSION, NEO_MINOR_VERSION, NEO_PATCHLEVEL,
427	ABI_CLASS_VIDEODRV,
428	ABI_VIDEODRV_VERSION,
429	MOD_CLASS_VIDEODRV,
430	{0,0,0,0}
431};
432
433/*
434 * This is the module init data.
435 * Its name has to be the driver name followed by ModuleData
436 */
437_X_EXPORT XF86ModuleData neomagicModuleData = { &neoVersRec, neoSetup, NULL };
438
439static pointer
440neoSetup(pointer module, pointer opts, int *errmaj, int *errmin)
441{
442    static Bool setupDone = FALSE;
443
444    if (!setupDone) {
445	setupDone = TRUE;
446        xf86AddDriver(&NEOMAGIC, module, 0);
447
448	/*
449	 * The return value must be non-NULL on success even though there
450	 * is no TearDownProc.
451	 */
452  	return (pointer)1;
453    } else {
454	if (errmaj) *errmaj = LDR_ONCEONLY;
455	return NULL;
456    }
457}
458
459#endif /* XFree86LOADER */
460
461static Bool
462NEOGetRec(ScrnInfoPtr pScrn)
463{
464    /*
465     * Allocate a NEORec, and hook it into pScrn->driverPrivate.
466     * pScrn->driverPrivate is initialised to NULL, so we can check if
467     * the allocation has already been done.
468     */
469    if (pScrn->driverPrivate != NULL)
470	return TRUE;
471
472    pScrn->driverPrivate = xnfcalloc(sizeof(NEORec), 1);
473
474    if (pScrn->driverPrivate == NULL)
475	return FALSE;
476        return TRUE;
477}
478
479static void
480NEOFreeRec(ScrnInfoPtr pScrn)
481{
482    if (pScrn->driverPrivate == NULL)
483	return;
484    xfree(pScrn->driverPrivate);
485    pScrn->driverPrivate = NULL;
486}
487
488static const OptionInfoRec *
489NEOAvailableOptions(int chipid, int busid)
490{
491    int chip = (chipid & 0x0000ffff);
492
493    if (chip == PCI_CHIP_NM2070)
494	return NEO_2070_Options;
495    else
496    	return NEOOptions;
497}
498
499/* Mandatory */
500static void
501NEOIdentify(int flags)
502{
503    xf86PrintChipsets(NEO_NAME, "Driver for Neomagic chipsets",
504			NEOChipsets);
505}
506
507/* Mandatory */
508static Bool
509NEOProbe(DriverPtr drv, int flags)
510{
511    Bool foundScreen = FALSE;
512    int numDevSections, numUsed;
513    GDevPtr *devSections;
514    int *usedChips;
515    int i;
516
517    /*
518     * Find the config file Device sections that match this
519     * driver, and return if there are none.
520     */
521    if ((numDevSections = xf86MatchDevice(NEO_DRIVER_NAME,
522					  &devSections)) <= 0) {
523	return FALSE;
524    }
525
526    /* PCI BUS */
527#ifndef XSERVER_LIBPCIACCESS
528    if (xf86GetPciVideoInfo() )
529#endif
530    {
531	numUsed = xf86MatchPciInstances(NEO_NAME, PCI_VENDOR_NEOMAGIC,
532					NEOChipsets, NEOPCIchipsets,
533					devSections,numDevSections,
534					drv, &usedChips);
535
536	if (numUsed > 0) {
537	    if (flags & PROBE_DETECT)
538		foundScreen = TRUE;
539	    else for (i = 0; i < numUsed; i++) {
540		ScrnInfoPtr pScrn = NULL;
541		/* Allocate a ScrnInfoRec and claim the slot */
542		if ((pScrn = xf86ConfigPciEntity(pScrn, 0, usedChips[i],
543						       NEOPCIchipsets,NULL, NULL,
544						       NULL, NULL, NULL))) {
545		    pScrn->driverVersion = NEO_VERSION;
546		    pScrn->driverName    = NEO_DRIVER_NAME;
547		    pScrn->name          = NEO_NAME;
548		    pScrn->Probe         = NEOProbe;
549		    pScrn->PreInit       = NEOPreInit;
550		    pScrn->ScreenInit    = NEOScreenInit;
551		    pScrn->SwitchMode    = NEOSwitchMode;
552		    pScrn->AdjustFrame   = NEOAdjustFrame;
553		    pScrn->EnterVT       = NEOEnterVT;
554		    pScrn->LeaveVT       = NEOLeaveVT;
555		    pScrn->FreeScreen    = NEOFreeScreen;
556		    pScrn->ValidMode     = NEOValidMode;
557		    foundScreen = TRUE;
558		}
559	    }
560	    xfree(usedChips);
561	}
562    }
563
564#ifdef HAVE_ISA
565    /* Isa Bus */
566
567    numUsed = xf86MatchIsaInstances(NEO_NAME,NEOChipsets,NEOISAchipsets,
568				     drv,neoFindIsaDevice,devSections,
569				     numDevSections,&usedChips);
570    if (numUsed > 0) {
571      if (flags & PROBE_DETECT)
572	foundScreen = TRUE;
573      else for (i = 0; i < numUsed; i++) {
574	ScrnInfoPtr pScrn = NULL;
575	if ((pScrn = xf86ConfigIsaEntity(pScrn, 0, usedChips[i],
576					 NEOISAchipsets, NULL, NULL,
577					 NULL, NULL, NULL))) {
578	    pScrn->driverVersion = NEO_VERSION;
579	    pScrn->driverName    = NEO_DRIVER_NAME;
580	    pScrn->name          = NEO_NAME;
581	    pScrn->Probe         = NEOProbe;
582	    pScrn->PreInit       = NEOPreInit;
583	    pScrn->ScreenInit    = NEOScreenInit;
584	    pScrn->SwitchMode    = NEOSwitchMode;
585	    pScrn->AdjustFrame   = NEOAdjustFrame;
586	    pScrn->EnterVT       = NEOEnterVT;
587	    pScrn->LeaveVT       = NEOLeaveVT;
588	    pScrn->FreeScreen    = NEOFreeScreen;
589	    pScrn->ValidMode     = NEOValidMode;
590	    foundScreen = TRUE;
591	}
592      }
593      xfree(usedChips);
594    }
595#endif
596
597    xfree(devSections);
598    return foundScreen;
599}
600
601#ifdef HAVE_ISA
602static int
603neoFindIsaDevice(GDevPtr dev)
604{
605    unsigned int vgaIOBase;
606    unsigned char id;
607
608    vgaIOBase = (inb(0x3CC) & 0x01) ? 0x3D0 : 0x3B0;
609    /* §§§ Too intrusive ? */
610    outw(GRAX, 0x2609); /* Unlock NeoMagic registers */
611
612    outb(vgaIOBase + 4, 0x1A);
613    id = inb(vgaIOBase + 5);
614
615    outw(GRAX, 0x0009); /* Lock NeoMagic registers */
616
617    switch (id) {
618    case PROBED_NM2070 :
619	return NM2070;
620    case PROBED_NM2090 :
621	return NM2090;
622    case PROBED_NM2093 :
623	return NM2093;
624    default :
625	return -1;
626    }
627}
628#endif
629
630/* Mandatory */
631Bool
632NEOPreInit(ScrnInfoPtr pScrn, int flags)
633{
634    ClockRangePtr clockRanges;
635    int i;
636    NEOPtr nPtr;
637    vgaHWPtr hwp;
638    int bppSupport = NoDepth24Support;
639    int videoRam = 896;
640    int maxClock = 65000;
641    int CursorMem = 1024;
642    int CursorOff = 0x100;
643    int linearSize = 1024;
644    int maxWidth = 1024;
645    int maxHeight = 1024;
646    unsigned char type, dpy;
647    int w;
648    int apertureSize;
649    Bool height_480 = FALSE;
650    Bool lcdCenterOptSet = FALSE;
651    char *s;
652
653    if (flags & PROBE_DETECT)  {
654	neoProbeDDC( pScrn, xf86GetEntityInfo(pScrn->entityList[0])->index );
655	return TRUE;
656    }
657
658    /* The vgahw module should be loaded here when needed */
659    if (!xf86LoadSubModule(pScrn, "vgahw"))
660	return FALSE;
661
662    /*
663     * Allocate a vgaHWRec.
664     */
665    if (!vgaHWGetHWRec(pScrn))
666	return FALSE;
667    hwp = VGAHWPTR(pScrn);
668
669    /* Allocate the NeoRec driverPrivate */
670    if (!NEOGetRec(pScrn)) {
671	return FALSE;
672    }
673# define RETURN \
674    { NEOFreeRec(pScrn);\
675			    return FALSE;\
676					     }
677
678    nPtr = NEOPTR(pScrn);
679
680    /* Since, the capabilities are determined by the chipset the very
681     * first thing to do is, figure out the chipset and its capabilities
682     */
683    /* This driver doesn't expect more than one entity per screen */
684    if (pScrn->numEntities > 1)
685	RETURN;
686
687    /* This is the general case */
688    for (i = 0; i<pScrn->numEntities; i++) {
689	nPtr->pEnt = xf86GetEntityInfo(pScrn->entityList[i]);
690	if (nPtr->pEnt->resources) return FALSE;
691	nPtr->NeoChipset = nPtr->pEnt->chipset;
692	pScrn->chipset = (char *)xf86TokenToString(NEOChipsets,
693						   nPtr->pEnt->chipset);
694	/* This driver can handle ISA and PCI buses */
695	if (nPtr->pEnt->location.type == BUS_PCI) {
696	    nPtr->PciInfo = xf86GetPciInfoForEntity(nPtr->pEnt->index);
697#ifndef XSERVER_LIBPCIACCESS
698	    nPtr->PciTag = pciTag(nPtr->PciInfo->bus,
699				  nPtr->PciInfo->device,
700				  nPtr->PciInfo->func);
701#endif
702	}
703    }
704    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Chipset is a ");
705    switch(nPtr->NeoChipset){
706    case NM2070:
707	xf86ErrorF("MagicGraph 128 (NM2070)");
708	break;
709    case NM2090 :
710	xf86ErrorF("MagicGraph 128V (NM2090)");
711	break;
712    case NM2093 :
713	xf86ErrorF("MagicGraph 128ZV (NM2093)");
714	break;
715    case NM2097 :
716	xf86ErrorF("MagicGraph 128ZV+ (NM2097)");
717	break;
718    case NM2160 :
719	xf86ErrorF("MagicGraph 128XD (NM2160)");
720	break;
721    case NM2200 :
722        xf86ErrorF("MagicMedia 256AV (NM2200)");
723	break;
724    case NM2230 :
725        xf86ErrorF("MagicMedia 256AV+ (NM2230)");
726	break;
727    case NM2360 :
728        xf86ErrorF("MagicMedia 256ZX (NM2360)");
729	break;
730    case NM2380 :
731        xf86ErrorF("MagicMedia 256XL+ (NM2380)");
732	break;
733    }
734    xf86ErrorF("\n");
735
736    vgaHWGetIOBase(hwp);
737    nPtr->vgaIOBase = hwp->IOBase;
738    vgaHWSetStdFuncs(hwp);
739
740    /* Determine the panel type */
741    VGAwGR(0x09,0x26);
742    type = VGArGR(0x21);
743    dpy = VGArGR(0x20);
744
745    /* Determine panel width -- used in NeoValidMode. */
746    w = VGArGR(0x20);
747    VGAwGR(0x09,0x00);
748    switch ((w & 0x18) >> 3) {
749    case 0x00 :
750	nPtr->NeoPanelWidth  = 640;
751	nPtr->NeoPanelHeight = 480;
752	break;
753    case 0x01 :
754	nPtr->NeoPanelWidth  = 800;
755	nPtr->NeoPanelHeight = 600;
756	break;
757    case 0x02 :
758	nPtr->NeoPanelWidth  = 1024;
759	nPtr->NeoPanelHeight = 768;
760	break;
761    case 0x03 :
762        /* 1280x1024 panel support needs to be added */
763#ifdef NOT_DONE
764	nPtr->NeoPanelWidth  = 1280;
765	nPtr->NeoPanelHeight = 1024;
766	break;
767#else
768	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
769		     "Only 640x480,\n"
770                     "     800x600,\n"
771                     " and 1024x768 panels are currently supported\n");
772	return FALSE;
773#endif
774    default :
775	nPtr->NeoPanelWidth  = 640;
776	nPtr->NeoPanelHeight = 480;
777	break;
778    }
779
780    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Panel is a %dx%d %s %s display\n",
781	       nPtr->NeoPanelWidth,
782	       nPtr->NeoPanelHeight,
783	       (type & 0x02) ? "color" : "monochrome",
784	       (type & 0x10) ? "TFT" : "dual scan");
785
786
787    switch (nPtr->NeoChipset){
788    case NM2070:
789	bppSupport = NoDepth24Support;
790	videoRam   = 896;
791	maxClock   = 65000;
792	CursorMem  = 2048;
793	CursorOff  = 0x100;
794	linearSize = 1024;
795	maxWidth   = 1024;
796	maxHeight  = 1024;
797	break;
798    case NM2090:
799    case NM2093:
800	bppSupport = Support24bppFb | Support32bppFb |
801	    SupportConvert32to24 | PreferConvert32to24;
802	videoRam   = 1152;
803	maxClock   = 80000;
804	CursorMem  = 2048;
805	CursorOff  = 0x100;
806	linearSize = 2048;
807	maxWidth   = 1024;
808	maxHeight  = 1024;
809	break;
810    case NM2097:
811	bppSupport = Support24bppFb | Support32bppFb |
812	  SupportConvert32to24 | PreferConvert32to24;
813	videoRam   = 1152;
814	maxClock   = 80000;
815	CursorMem  = 1024;
816	CursorOff  = 0x100;
817	linearSize = 2048;
818	maxWidth   = 1024;
819	maxHeight  = 1024;
820	break;
821    case NM2160:
822	bppSupport = Support24bppFb | Support32bppFb |
823	    SupportConvert32to24 | PreferConvert32to24;
824	videoRam   = 2048;
825	maxClock   = 90000;
826	CursorMem  = 1024;
827	CursorOff  = 0x100;
828	linearSize = 2048;
829	maxWidth   = 1024;
830	maxHeight  = 1024;
831	break;
832    case NM2200:
833	bppSupport = Support24bppFb | Support32bppFb |
834	    SupportConvert32to24 | PreferConvert32to24;
835	videoRam   = 2560;
836	maxClock   = 110000;
837	CursorMem  = 1024;
838	CursorOff  = 0x1000;
839	linearSize = 4096;
840	maxWidth   = 1280;
841	maxHeight  = 1024;  /* ???? */
842	break;
843    case NM2230:
844	bppSupport = Support24bppFb | Support32bppFb |
845	    SupportConvert32to24 | PreferConvert32to24;
846	videoRam   = 3008;
847	maxClock   = 110000;
848	CursorMem  = 1024;
849	CursorOff  = 0x1000;
850	linearSize = 4096;
851	maxWidth   = 1280;
852	maxHeight  = 1024;  /* ???? */
853	break;
854    case NM2360:
855	bppSupport = Support24bppFb | Support32bppFb |
856	    SupportConvert32to24 | PreferConvert32to24;
857	videoRam   = 4096;
858	maxClock   = 110000;
859	CursorMem  = 1024;
860	CursorOff  = 0x1000;
861	linearSize = 4096;
862	maxWidth   = 1280;
863	maxHeight  = 1024;  /* ???? */
864	break;
865    case NM2380:
866	bppSupport = Support24bppFb | Support32bppFb |
867	    SupportConvert32to24 | PreferConvert32to24;
868	videoRam   = 6144;
869	maxClock   = 110000;
870	CursorMem  = 1024;
871	CursorOff  = 0x1000;
872	linearSize = 8192;
873	maxWidth   = 1280;
874	maxHeight  = 1024;  /* ???? */
875	break;
876    }
877
878    pScrn->monitor = pScrn->confScreen->monitor;
879
880    if (xf86LoadSubModule(pScrn, "ddc")) {
881#if 1 /* for DDC1 testing */
882	if (!neoDoDDCVBE(pScrn))
883	  if (!neoDoDDC2(pScrn))
884#endif
885	      neoDoDDC1(pScrn);
886    }
887
888    if (!xf86SetDepthBpp(pScrn, 16, 0, 0, bppSupport ))
889	return FALSE;
890    else {
891	/* Check that the returned depth is one we support */
892	switch (pScrn->depth) {
893	case 8:
894	case 15:
895	case 16:
896	    break;
897	case 24:
898	    if (nPtr->NeoChipset != NM2070)
899		break;
900	default:
901	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
902		       "Given depth (%d) is not supported by this driver\n",
903		       pScrn->depth);
904	    return FALSE;
905	}
906    }
907    xf86PrintDepthBpp(pScrn);
908    if (pScrn->depth == 8)
909	pScrn->rgbBits = 6;
910
911    /* Get the depth24 pixmap format */
912    if (pScrn->depth == 24 && pix24bpp == 0)
913	pix24bpp = xf86GetBppFromDepth(pScrn, 24);
914
915    /*
916     * This must happen after pScrn->display has been set because
917     * xf86SetWeight references it.
918     */
919    if (pScrn->depth > 8) {
920	/* The defaults are OK for us */
921	rgb zeros = {0, 0, 0};
922
923	if (!xf86SetWeight(pScrn, zeros, zeros)) {
924	    return FALSE;
925	} else {
926	    /* XXX check that weight returned is supported */
927	    ;
928	}
929    }
930
931    if (!xf86SetDefaultVisual(pScrn, -1))
932	return FALSE;
933
934    if (pScrn->depth > 1) {
935	Gamma zeros = {0.0, 0.0, 0.0};
936
937	if (!xf86SetGamma(pScrn, zeros))
938	    return FALSE;
939    }
940
941    nPtr->strangeLockups = TRUE;
942
943    /* Collect all of the relevant option flags (fill in pScrn->options) */
944    xf86CollectOptions(pScrn, NULL);
945    /* Process the options */
946    if (nPtr->NeoChipset == NM2070) {
947	if (!(nPtr->Options = xalloc(sizeof(NEO_2070_Options))))
948	    return FALSE;
949	memcpy(nPtr->Options, NEO_2070_Options, sizeof(NEO_2070_Options));
950    } else {
951	if (!(nPtr->Options = xalloc(sizeof(NEOOptions))))
952	    return FALSE;
953	memcpy(nPtr->Options, NEOOptions, sizeof(NEOOptions));
954    }
955
956    xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, nPtr->Options);
957
958    xf86GetOptValBool(nPtr->Options, OPTION_NOLINEAR_MODE,&nPtr->noLinear);
959    xf86GetOptValBool(nPtr->Options, OPTION_SW_CURSOR,&nPtr->swCursor);
960    xf86GetOptValBool(nPtr->Options, OPTION_NO_MMIO,&nPtr->noMMIO);
961    xf86GetOptValBool(nPtr->Options, OPTION_INTERN_DISP,&nPtr->internDisp);
962    xf86GetOptValBool(nPtr->Options, OPTION_EXTERN_DISP,&nPtr->externDisp);
963    if (xf86GetOptValBool(nPtr->Options, OPTION_LCD_CENTER,&nPtr->lcdCenter))
964	lcdCenterOptSet = TRUE;
965    xf86GetOptValBool(nPtr->Options, OPTION_LCD_STRETCH,&nPtr->noLcdStretch);
966    xf86GetOptValBool(nPtr->Options, OPTION_SHADOW_FB,&nPtr->shadowFB);
967    xf86GetOptValBool(nPtr->Options, OPTION_SHOWCACHE,&nPtr->showcache);
968    nPtr->onPciBurst = TRUE;
969    xf86GetOptValBool(nPtr->Options, OPTION_PCI_BURST,&nPtr->onPciBurst);
970    xf86GetOptValBool(nPtr->Options,
971		      OPTION_PROG_LCD_MODE_REGS,&nPtr->progLcdRegs);
972    if (xf86GetOptValBool(nPtr->Options,
973		      OPTION_PROG_LCD_MODE_STRETCH,&nPtr->progLcdStretch))
974	nPtr->progLcdStretchOpt = TRUE;
975    xf86GetOptValBool(nPtr->Options,
976		      OPTION_OVERRIDE_VALIDATE_MODE, &nPtr->overrideValidate);
977    xf86GetOptValBool(nPtr->Options, OPTION_DISPLAY_HEIGHT_480,&height_480);
978    xf86GetOptValBool(nPtr->Options, OPTION_STRANGE_LOCKUPS,
979		      &nPtr->strangeLockups);
980    nPtr->noAccelSet =
981	xf86GetOptValBool(nPtr->Options, OPTION_NOACCEL,&nPtr->noAccel);
982
983    nPtr->rotate = 0;
984    if ((s = xf86GetOptValString(nPtr->Options, OPTION_ROTATE))) {
985	if(!xf86NameCmp(s, "CW")) {
986	    /* accel is disabled below for shadowFB */
987	    nPtr->shadowFB = TRUE;
988	    nPtr->swCursor = TRUE;
989	    nPtr->rotate = 1;
990	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
991		       "Rotating screen clockwise - acceleration disabled\n");
992	} else if(!xf86NameCmp(s, "CCW")) {
993	    nPtr->shadowFB = TRUE;
994	    nPtr->swCursor = TRUE;
995	    nPtr->rotate = -1;
996	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,  "Rotating screen"
997		       "counter clockwise - acceleration disabled\n");
998	} else {
999	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "\"%s\" is not a valid"
1000		       "value for Option \"Rotate\"\n", s);
1001	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1002		       "Valid options are \"CW\" or \"CCW\"\n");
1003      }
1004    }
1005
1006    if(xf86GetOptValInteger(nPtr->Options,
1007			    OPTION_VIDEO_KEY, &(nPtr->videoKey))) {
1008        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "video key set to 0x%x\n",
1009		   nPtr->videoKey);
1010    } else {
1011        nPtr->videoKey = (1 << pScrn->offset.red) |
1012	    (1 << pScrn->offset.green) |
1013	    (((pScrn->mask.blue >> pScrn->offset.blue) - 1)
1014	     << pScrn->offset.blue);
1015    }
1016    if(xf86GetOptValInteger(nPtr->Options, OPTION_OVERLAYMEM,
1017			    &(nPtr->overlay))) {
1018        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1019		   "reserve %d bytes for overlay.\n", nPtr->overlay);
1020    } else {
1021	nPtr->overlay = 0;
1022    }
1023    nPtr->interlace = 0;
1024    if(xf86GetOptValInteger(nPtr->Options, OPTION_VIDEO_INTERLACE,
1025			    &(nPtr->interlace))) {
1026	if (nPtr->interlace >= 0  &&  nPtr->interlace <= 2){
1027	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "interlace flag = %d\n",
1028		       nPtr->interlace);
1029	} else {
1030	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1031		       "\"%s\" is not a valid value for "
1032		       "Option \"Interlaced\"\n", s);
1033	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Valid options are  0..2\n");
1034        }
1035    }
1036
1037    if (height_480
1038	&& (nPtr->NeoPanelWidth == 800 || nPtr->NeoPanelWidth == 1024)) {
1039	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,
1040		   "Overriding Panel height: Set to 480\n");
1041	nPtr->NeoPanelHeight = 480;
1042	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,
1043		   "Disabling LCD stretching for panel height 480\n");
1044	nPtr->noLcdStretch = TRUE;
1045	if (!lcdCenterOptSet)
1046	    nPtr->lcdCenter = TRUE;
1047    }
1048
1049    if (nPtr->internDisp && nPtr->externDisp)
1050	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,
1051		   "Simultaneous LCD/CRT display mode\n");
1052    else if (nPtr->externDisp)
1053	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,
1054		   "External CRT only display mode\n");
1055    else  if (nPtr->internDisp)
1056	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,
1057		   "Internal LCD only display mode\n");
1058    else {
1059	nPtr->internDisp = ((dpy & 0x02) == 0x02);
1060    	nPtr->externDisp = ((dpy & 0x01) == 0x01);
1061	if (nPtr->internDisp && nPtr->externDisp)
1062	    xf86DrvMsg(pScrn->scrnIndex,X_PROBED,
1063		       "Simultaneous LCD/CRT display mode\n");
1064	else if (nPtr->externDisp)
1065	    xf86DrvMsg(pScrn->scrnIndex,X_PROBED,
1066		       "External CRT only display mode\n");
1067	else if (nPtr->internDisp)
1068	    xf86DrvMsg(pScrn->scrnIndex,X_PROBED,
1069		       "Internal LCD only display mode\n");
1070	else {
1071	    /* this is a fallback if probed values are bogus */
1072	    nPtr->internDisp = TRUE;
1073	    xf86DrvMsg(pScrn->scrnIndex,X_DEFAULT,
1074		       "Internal LCD only display mode\n");
1075	}
1076    }
1077
1078    if (nPtr->noLcdStretch)
1079	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,
1080		   "Low resolution video modes are not stretched\n");
1081    if (nPtr->lcdCenter)
1082	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,
1083		   "Video modes are centered on the display\n");
1084    if (nPtr->noLinear)
1085	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG, "using nonlinear mode\n");
1086    else
1087	xf86DrvMsg(pScrn->scrnIndex,X_DEFAULT, "using linear mode\n");
1088    if (nPtr->swCursor)
1089	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG, "using sofware cursor\n");
1090    if (nPtr->noMMIO)
1091	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG, "MMIO mode disabled\n");
1092    if (nPtr->onPciBurst)
1093	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG, "using PCI Burst mode\n");
1094    if (nPtr->strangeLockups)
1095	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,
1096		   "Option StrangeLockups set: disabling some acceleration\n");
1097    if (nPtr->showcache)
1098	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,
1099		   "Show chache for debugging\n");
1100    if (nPtr->shadowFB) {
1101	if (nPtr->noLinear) {
1102    	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1103		       "Option \"ShadowFB\" ignored. Not supported without"
1104		       " linear addressing\n");
1105	    nPtr->shadowFB = FALSE;
1106	    nPtr->rotate = 0;
1107	} else {
1108	    nPtr->noAccel = TRUE;
1109	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1110		    "Using \"Shadow Framebuffer\" - acceleration disabled\n");
1111	}
1112    }
1113
1114    nPtr->NeoFbMapSize = linearSize * 1024;
1115    nPtr->NeoCursorOffset = CursorOff;
1116
1117    if (nPtr->pEnt->device->MemBase) {
1118	/* XXX Check this matches a PCI base address */
1119	nPtr->NeoLinearAddr = nPtr->pEnt->device->MemBase;
1120	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1121		   "FB base address is set at 0x%lX.\n",
1122		   nPtr->NeoLinearAddr);
1123    } else {
1124	nPtr->NeoLinearAddr = 0;
1125    }
1126
1127    nPtr->NeoMMIOAddr2 = 0;
1128    nPtr->NeoMMIOBase2 = NULL;
1129    if (nPtr->pEnt->device->IOBase && !nPtr->noMMIO) {
1130	/* XXX Check this matches a PCI base address */
1131	nPtr->NeoMMIOAddr = nPtr->pEnt->device->IOBase;
1132	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1133		   "MMIO base address is set at 0x%lX.\n",
1134		   nPtr->NeoMMIOAddr);
1135    } else {
1136	nPtr->NeoMMIOAddr = 0;
1137    }
1138
1139    if (nPtr->pEnt->location.type == BUS_PCI) {
1140	if (!nPtr->NeoLinearAddr) {
1141	    nPtr->NeoLinearAddr = PCI_REGION_BASE(nPtr->PciInfo, 0, REGION_MEM);
1142	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1143		       "FB base address is set at 0x%lX.\n",
1144		       nPtr->NeoLinearAddr);
1145	}
1146	if (!nPtr->NeoMMIOAddr && !nPtr->noMMIO) {
1147	    switch (nPtr->NeoChipset) {
1148	    case NM2070 :
1149		nPtr->NeoMMIOAddr = nPtr->NeoLinearAddr + 0x100000;
1150		break;
1151	    case NM2090:
1152	    case NM2093:
1153		nPtr->NeoMMIOAddr = nPtr->NeoLinearAddr + 0x200000;
1154		break;
1155	    case NM2160:
1156	    case NM2097:
1157	    case NM2200:
1158	    case NM2230:
1159	    case NM2360:
1160	    case NM2380:
1161		nPtr->NeoMMIOAddr = PCI_REGION_BASE(nPtr->PciInfo, 1, REGION_MEM);
1162		nPtr->NeoMMIOAddr2 = PCI_REGION_BASE(nPtr->PciInfo, 2, REGION_MEM);
1163		break;
1164	    }
1165	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1166		       "MMIO base address is set at 0x%lX.\n",
1167		       nPtr->NeoMMIOAddr);
1168	    if (nPtr->NeoMMIOAddr2 != 0){
1169	        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1170		           "MMIO base address2 is set at 0x%lX.\n",
1171		           nPtr->NeoMMIOAddr2);
1172	    }
1173	}
1174	/* XXX What about VGA resources in OPERATING mode? */
1175	if (xf86RegisterResources(nPtr->pEnt->index, NULL, ResExclusive))
1176	    RETURN;
1177
1178    } else if (nPtr->pEnt->location.type == BUS_ISA) {
1179	unsigned int addr;
1180	resRange linearRes[] = { {ResExcMemBlock|ResBios|ResBus,0,0},_END };
1181
1182	if (!nPtr->NeoLinearAddr) {
1183	    VGAwGR(0x09,0x26);
1184	    addr = VGArGR(0x13);
1185	    VGAwGR(0x09,0x00);
1186	    nPtr->NeoLinearAddr = addr << 20;
1187	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1188		       "FB base address is set at 0x%lX.\n",
1189		       nPtr->NeoLinearAddr);
1190	}
1191	if (!nPtr->NeoMMIOAddr && !nPtr->noMMIO) {
1192	    nPtr->NeoMMIOAddr = nPtr->NeoLinearAddr + 0x100000;
1193	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1194		       "MMIO base address is set at 0x%lX.\n",
1195		       nPtr->NeoMMIOAddr);
1196	}
1197	linearRes[0].rBegin = nPtr->NeoLinearAddr;
1198	linearRes[1].rEnd = nPtr->NeoLinearAddr + nPtr->NeoFbMapSize - 1;
1199	if (xf86RegisterResources(nPtr->pEnt->index,linearRes,ResNone)) {
1200	    nPtr->noLinear = TRUE; /* XXX */
1201	}
1202    } else
1203	RETURN;
1204
1205    if (nPtr->pEnt->device->videoRam != 0) {
1206	pScrn->videoRam = nPtr->pEnt->device->videoRam;
1207	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "VideoRAM: %d kByte\n",
1208		   pScrn->videoRam);
1209    } else {
1210	pScrn->videoRam = videoRam;
1211	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "VideoRAM: %d kByte\n",
1212		   pScrn->videoRam);
1213    }
1214
1215    if (nPtr->pEnt->device->dacSpeeds[0] != 0) {
1216	maxClock = nPtr->pEnt->device->dacSpeeds[0];
1217	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Max Clock: %d kHz\n",
1218		   maxClock);
1219    } else {
1220	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Max Clock: %d kHz\n",
1221		   maxClock);
1222    }
1223
1224    pScrn->progClock = TRUE;
1225    /*
1226     * Setup the ClockRanges, which describe what clock ranges are available,
1227     * and what sort of modes they can be used for.
1228     */
1229    clockRanges = (ClockRangePtr)xnfcalloc(sizeof(ClockRange), 1);
1230    clockRanges->next = NULL;
1231    clockRanges->ClockMulFactor = 1;
1232    clockRanges->minClock = 11000;   /* guessed §§§ */
1233    clockRanges->maxClock = maxClock;
1234    clockRanges->clockIndex = -1;		/* programmable */
1235	clockRanges->interlaceAllowed = FALSE;
1236    clockRanges->doubleScanAllowed = TRUE;
1237
1238    /* Subtract memory for HW cursor */
1239    if (!nPtr->swCursor)
1240	nPtr->NeoCursorMem = CursorMem;
1241    else
1242	nPtr->NeoCursorMem = 0;
1243    apertureSize = (pScrn->videoRam * 1024) - nPtr->NeoCursorMem;
1244
1245    if ((nPtr->NeoPanelWidth == 800) && (nPtr->NeoPanelHeight == 480)) {
1246	neo800x480Mode.next = pScrn->monitor->Modes;
1247	pScrn->monitor->Modes = &neo800x480Mode;
1248    }
1249    if ((nPtr->NeoPanelWidth == 1024) && (nPtr->NeoPanelHeight == 480)) {
1250	neo1024x480Mode.next = pScrn->monitor->Modes;
1251	pScrn->monitor->Modes = &neo1024x480Mode;
1252    }
1253
1254    if (!pScrn->monitor->DDC) {
1255	/*
1256	 * If the monitor parameters are not specified explicitly, set them
1257	 * so that 60Hz modes up to the panel size are allowed.
1258	 */
1259	if (pScrn->monitor->nHsync == 0) {
1260	    pScrn->monitor->nHsync = 1;
1261	    pScrn->monitor->hsync[0].lo = 28;
1262	    pScrn->monitor->hsync[0].hi =
1263				60.0 * 1.07 * nPtr->NeoPanelHeight / 1000.0;
1264	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1265		       "Using hsync range matching panel size: %.2f-%.2f kHz\n",
1266		       pScrn->monitor->hsync[0].lo,
1267		       pScrn->monitor->hsync[0].hi);
1268	}
1269	if (pScrn->monitor->nVrefresh == 0) {
1270	    pScrn->monitor->nVrefresh = 1;
1271	    pScrn->monitor->vrefresh[0].lo = 55.0;
1272	    pScrn->monitor->vrefresh[0].hi = 65.0;
1273	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1274		       "Using vsync range for panel: %.2f-%.2f kHz\n",
1275		       pScrn->monitor->vrefresh[0].lo,
1276		       pScrn->monitor->vrefresh[0].hi);
1277	}
1278    }
1279
1280    /*
1281     * For external displays, limit the width to 1024 pixels or less.
1282     */
1283    {
1284       i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
1285			  pScrn->display->modes, clockRanges,
1286			  NULL, 256, maxWidth,(8 * pScrn->bitsPerPixel),/*§§§*/
1287			  128, maxHeight, pScrn->display->virtualX,
1288			  pScrn->display->virtualY, apertureSize,
1289			  LOOKUP_BEST_REFRESH);
1290
1291       if (i == -1)
1292           RETURN;
1293    }
1294
1295    /* Prune the modes marked as invalid */
1296    xf86PruneDriverModes(pScrn);
1297
1298    if (i == 0 || pScrn->modes == NULL) {
1299	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n");
1300	RETURN;
1301    }
1302
1303    /*
1304     * Set the CRTC parameters for all of the modes based on the type
1305     * of mode, and the chipset's interlace requirements.
1306     *
1307     * Calling this is required if the mode->Crtc* values are used by the
1308     * driver and if the driver doesn't provide code to set them.  They
1309     * are not pre-initialised at all.
1310     */
1311    xf86SetCrtcForModes(pScrn, 0);
1312
1313    /* Set the current mode to the first in the list */
1314    pScrn->currentMode = pScrn->modes;
1315
1316    /* Print the list of modes being used */
1317    xf86PrintModes(pScrn);
1318
1319    /* If monitor resolution is set on the command line, use it */
1320    xf86SetDpi(pScrn, 0, 0);
1321
1322    if (xf86LoadSubModule(pScrn, "fb") == NULL) {
1323	RETURN;
1324    }
1325
1326    if (!nPtr->noLinear) {
1327	if (!xf86LoadSubModule(pScrn, "xaa"))
1328	    RETURN;
1329    }
1330
1331    if (nPtr->shadowFB) {
1332	if (!xf86LoadSubModule(pScrn, "shadow")) {
1333	    RETURN;
1334	}
1335    }
1336
1337    if (!nPtr->swCursor) {
1338	if (!xf86LoadSubModule(pScrn, "ramdac"))
1339	    RETURN;
1340    }
1341    return TRUE;
1342}
1343#undef RETURN
1344
1345/* Mandatory */
1346static Bool
1347NEOEnterVT(int scrnIndex, int flags)
1348{
1349    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1350    NEOPtr nPtr = NEOPTR(pScrn);
1351
1352    /* Should we re-save the text mode on each VT enter? */
1353    if(!neoModeInit(pScrn, pScrn->currentMode))
1354      return FALSE;
1355
1356    if (nPtr->video)
1357	NEOResetVideo(pScrn);
1358
1359    if (nPtr->NeoHWCursorShown)
1360	NeoShowCursor(pScrn);
1361    NEOAdjustFrame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
1362
1363    return TRUE;
1364}
1365
1366/* Mandatory */
1367static void
1368NEOLeaveVT(int scrnIndex, int flags)
1369{
1370    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1371    NEOPtr nPtr = NEOPTR(pScrn);
1372
1373    /* Invalidate the cached acceleration registers */
1374    if (nPtr->NeoHWCursorShown)
1375	NeoHideCursor(pScrn);
1376    neoRestore(pScrn, &(VGAHWPTR(pScrn))->SavedReg, &nPtr->NeoSavedReg, TRUE);
1377    neoLock(pScrn);
1378
1379}
1380
1381static void
1382NEOLoadPalette(
1383   ScrnInfoPtr pScrn,
1384   int numColors,
1385   int *indices,
1386   LOCO *colors,
1387   VisualPtr pVisual
1388){
1389   int i, index, shift, Gshift;
1390   vgaHWPtr hwp = VGAHWPTR(pScrn);
1391
1392   switch(pScrn->depth) {
1393   case 15:
1394	shift = Gshift = 1;
1395	break;
1396   case 16:
1397	shift = 0;
1398        Gshift = 0;
1399	break;
1400   default:
1401	shift = Gshift = 0;
1402	break;
1403   }
1404
1405   for(i = 0; i < numColors; i++) {
1406        index = indices[i];
1407        hwp->writeDacWriteAddr(hwp, index);
1408	DACDelay(hwp);
1409        hwp->writeDacData(hwp, colors[index].red << shift);
1410	DACDelay(hwp);
1411        hwp->writeDacData(hwp, colors[index].green << Gshift);
1412	DACDelay(hwp);
1413        hwp->writeDacData(hwp, colors[index].blue << shift);
1414	DACDelay(hwp);
1415   }
1416}
1417
1418/* Mandatory */
1419static Bool
1420NEOScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
1421{
1422    ScrnInfoPtr pScrn;
1423    vgaHWPtr hwp;
1424    NEOPtr nPtr;
1425    NEOACLPtr nAcl;
1426    int ret;
1427    VisualPtr visual;
1428    int allocatebase, freespace, currentaddr;
1429    unsigned int racflag = RAC_FB;
1430    unsigned char *FBStart;
1431    int height, width, displayWidth;
1432
1433    /*
1434     * we need to get the ScrnInfoRec for this screen, so let's allocate
1435     * one first thing
1436     */
1437    pScrn = xf86Screens[pScreen->myNum];
1438    nPtr = NEOPTR(pScrn);
1439    nAcl = NEOACLPTR(pScrn);
1440
1441    hwp = VGAHWPTR(pScrn);
1442    hwp->MapSize = 0x10000;		/* Standard 64k VGA window */
1443    /* Map the VGA memory */
1444    if (!vgaHWMapMem(pScrn))
1445	return FALSE;
1446
1447    /* Map the Neo memory and possible MMIO areas */
1448    if (!neoMapMem(pScrn))
1449	return FALSE;
1450
1451    /*
1452     * next we save the current state and setup the first mode
1453     */
1454    neoSave(pScrn);
1455
1456    if (!neoModeInit(pScrn,pScrn->currentMode))
1457	return FALSE;
1458    vgaHWSaveScreen(pScreen,SCREEN_SAVER_ON);
1459    NEOAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
1460
1461    /*
1462     * Reset visual list.
1463     */
1464    miClearVisualTypes();
1465
1466    /* Setup the visuals we support. */
1467#if 0
1468    if (!miSetVisualTypes(pScrn->depth,
1469      		      miGetDefaultVisualMask(pScrn->depth),
1470		      pScrn->rgbBits, pScrn->defaultVisual))
1471         return FALSE;
1472#else
1473    if (!miSetVisualTypes(pScrn->depth,
1474      		      miGetDefaultVisualMask(pScrn->depth),
1475		      pScrn->rgbBits, pScrn->defaultVisual))
1476         return FALSE;
1477    if (pScrn->depth > 8) {
1478	if (!miSetVisualTypes(8, miGetDefaultVisualMask(8), 6,
1479			      pScrn->defaultVisual))
1480	    return FALSE;
1481    }
1482#endif
1483    if (!miSetPixmapDepths ()) return FALSE;
1484
1485    /*
1486     * Call the framebuffer layer's ScreenInit function, and fill in other
1487     * pScreen fields.
1488     */
1489    displayWidth = pScrn->displayWidth;
1490    if (nPtr->rotate) {
1491	height = pScrn->virtualX;
1492	width = pScrn->virtualY;
1493    } else {
1494	width = pScrn->virtualX;
1495	height = pScrn->virtualY;
1496    }
1497
1498    if(nPtr->shadowFB) {
1499	nPtr->ShadowPitch = BitmapBytePad(pScrn->bitsPerPixel * width);
1500	nPtr->ShadowPtr = xalloc(nPtr->ShadowPitch * height);
1501	displayWidth = nPtr->ShadowPitch / (pScrn->bitsPerPixel >> 3);
1502	FBStart = nPtr->ShadowPtr;
1503    } else {
1504	nPtr->ShadowPtr = NULL;
1505	FBStart = nPtr->NeoFbBase;
1506    }
1507
1508    ret = fbScreenInit(pScreen, FBStart,
1509			    width, height,
1510			    pScrn->xDpi, pScrn->yDpi,
1511			    displayWidth, pScrn->bitsPerPixel);
1512    if (!ret)
1513	return FALSE;
1514    if (pScrn->depth > 8) {
1515        /* Fixup RGB ordering */
1516        visual = pScreen->visuals + pScreen->numVisuals;
1517        while (--visual >= pScreen->visuals) {
1518	    if ((visual->class | DynamicClass) == DirectColor
1519		&& visual->nplanes > 8) {
1520		visual->offsetRed = pScrn->offset.red;
1521		visual->offsetGreen = pScrn->offset.green;
1522		visual->offsetBlue = pScrn->offset.blue;
1523		visual->redMask = pScrn->mask.red;
1524		visual->greenMask = pScrn->mask.green;
1525		visual->blueMask = pScrn->mask.blue;
1526	    }
1527	}
1528    }
1529
1530    /* must be after RGB ordering fixed */
1531    fbPictureInit(pScreen, 0, 0);
1532
1533    xf86SetBlackWhitePixels(pScreen);
1534
1535    if (!nPtr->shadowFB)
1536	NEODGAInit(pScreen);
1537
1538    nPtr->NeoHWCursorShown = FALSE;
1539    nPtr->NeoHWCursorInitialized = FALSE;
1540    nAcl->UseHWCursor = FALSE;
1541    nAcl->CursorAddress = -1;
1542
1543    if (nPtr->noLinear) {
1544	miBankInfoPtr pBankInfo;
1545
1546	/* Setup the vga banking variables */
1547	pBankInfo = (miBankInfoPtr)xnfcalloc(sizeof(miBankInfoRec),1);
1548	if (pBankInfo == NULL)
1549	    return FALSE;
1550
1551	pBankInfo->pBankA = hwp->Base;
1552	pBankInfo->pBankB = (unsigned char *)hwp->Base;
1553	pBankInfo->BankSize = 0x10000;
1554	pBankInfo->nBankDepth = pScrn->depth;
1555
1556	pBankInfo->SetSourceBank = (miBankProcPtr)NEOSetRead;
1557	pBankInfo->SetDestinationBank =
1558	    (miBankProcPtr)NEOSetWrite;
1559	pBankInfo->SetSourceAndDestinationBanks =
1560	    (miBankProcPtr)NEOSetReadWrite;
1561	if (!miInitializeBanking(pScreen, pScrn->virtualX, pScrn->virtualY,
1562				 pScrn->displayWidth, pBankInfo)) {
1563	    xfree(pBankInfo);
1564	    pBankInfo = NULL;
1565	    return FALSE;
1566	}
1567	xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Using nonlinear mode\n");
1568	xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Using software cursor in "
1569		   "nonlinear mode\n");
1570    } else {
1571	nAcl->cacheStart = -1;
1572	nAcl->cacheEnd = -1;
1573	xf86DrvMsg(pScrn->scrnIndex,X_INFO,
1574		   "Using linear framebuffer at: 0x%08lX\n",
1575		   nPtr->NeoLinearAddr);
1576	/* Setup pointers to free space in video ram */
1577	allocatebase = (pScrn->videoRam << 10);
1578	freespace = allocatebase - pScrn->displayWidth *
1579	    pScrn->virtualY * (pScrn->bitsPerPixel >> 3);
1580	currentaddr = allocatebase;
1581	xf86DrvMsg(scrnIndex, X_PROBED,
1582		   "%d bytes off-screen memory available\n", freespace);
1583
1584	if (nPtr->swCursor || !nPtr->NeoMMIOBase) {
1585	    xf86DrvMsg(scrnIndex, X_CONFIG,
1586		       "Using Software Cursor.\n");
1587	} else if (nPtr->NeoCursorMem <= freespace) {
1588	    currentaddr -= nPtr->NeoCursorMem;
1589	    freespace  -= nPtr->NeoCursorMem;
1590	    /* alignment */
1591	    freespace  -= currentaddr & 0x3FF;
1592	    currentaddr &= 0xfffffc00;
1593	    nAcl->CursorAddress = currentaddr;
1594	    xf86DrvMsg(scrnIndex, X_INFO,
1595		       "Using H/W Cursor.\n");
1596	} else {
1597	    xf86DrvMsg(scrnIndex, X_ERROR,
1598		       "Too little space for H/W cursor.\n");
1599	}
1600
1601	if (!nPtr->noAccel && !nPtr->NeoMMIOBase)
1602	  xf86DrvMsg(pScrn->scrnIndex,X_INFO,
1603		     "Acceleration disabled when not using MMIO\n");
1604
1605	if (nPtr->overlay > 0){
1606	    if (nPtr->overlay > freespace){
1607		xf86DrvMsg(pScrn->scrnIndex,X_INFO,
1608			   "Can not reserve %d bytes for overlay. "
1609			   "Resize to %d bytes.\n",
1610			   nPtr->overlay, freespace);
1611		nPtr->overlay = freespace;
1612	    }
1613	    currentaddr -= nPtr->overlay;
1614	    freespace -= nPtr->overlay;
1615	    nPtr->overlay_offset = currentaddr;
1616	    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"Overlay at 0x%x\n",
1617		       nPtr->overlay_offset);
1618	}
1619
1620	nAcl->cacheStart = currentaddr - freespace;
1621	nAcl->cacheEnd = currentaddr;
1622	freespace = 0;
1623	if (nAcl->cacheStart < nAcl->cacheEnd) {
1624	    BoxRec AvailFBArea;
1625	    int lines = nAcl->cacheEnd /
1626		(pScrn->displayWidth * (pScrn->bitsPerPixel >> 3));
1627	    if (!nPtr->noAccel && nPtr->NeoMMIOBase && lines > 1024)
1628		lines = 1024;
1629	    AvailFBArea.x1 = 0;
1630	    AvailFBArea.y1 = 0;
1631	    AvailFBArea.x2 = pScrn->displayWidth;
1632	    AvailFBArea.y2 = lines;
1633	    xf86InitFBManager(pScreen, &AvailFBArea);
1634
1635	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1636		       "Using %i scanlines of offscreen memory \n",
1637		       lines - pScrn->virtualY);
1638	}
1639
1640	/* Setup the acceleration primitives */
1641	if (!nPtr->noAccel && nPtr->NeoMMIOBase) {
1642	    Bool ret = FALSE;
1643	    if (nAcl->cacheStart >= nAcl->cacheEnd) {
1644		xf86DrvMsg(scrnIndex, X_ERROR,
1645			   "Too little space for pixmap cache.\n");
1646	    }
1647	    switch(nPtr->NeoChipset) {
1648	    case NM2070 :
1649		ret = Neo2070AccelInit(pScreen);
1650		break;
1651	    case NM2090 :
1652	    case NM2093 :
1653		ret = Neo2090AccelInit(pScreen);
1654		break;
1655	    case NM2097 :
1656	    case NM2160 :
1657		ret = Neo2097AccelInit(pScreen);
1658		break;
1659	    case NM2200 :
1660	    case NM2230 :
1661	    case NM2360 :
1662	    case NM2380 :
1663	        ret = Neo2200AccelInit(pScreen);
1664		break;
1665	    }
1666	    xf86DrvMsg(pScrn->scrnIndex,X_INFO,
1667		       "Acceleration %s Initialized\n",ret ? "" : "not");
1668	}
1669
1670    }
1671    miInitializeBackingStore(pScreen);
1672    xf86SetBackingStore(pScreen);
1673    xf86SetSilkenMouse(pScreen);
1674
1675    /* Initialise cursor functions */
1676    miDCInitialize (pScreen, xf86GetPointerScreenFuncs());
1677
1678    if (nAcl->CursorAddress != -1) {
1679      /* HW cursor functions */
1680      if (!NeoCursorInit(pScreen)) {
1681	xf86DrvMsg(scrnIndex, X_ERROR,
1682		   "Hardware cursor initialization failed\n");
1683	return FALSE;
1684      }
1685      nAcl->UseHWCursor = TRUE;
1686      nPtr->NeoHWCursorInitialized = TRUE;
1687    } else
1688      nAcl->UseHWCursor = FALSE;
1689
1690    if (nPtr->shadowFB) {
1691        nPtr->refreshArea = neoRefreshArea;
1692
1693	if(nPtr->rotate) {
1694	    if (!nPtr->PointerMoved) {
1695		nPtr->PointerMoved = pScrn->PointerMoved;
1696		pScrn->PointerMoved = neoPointerMoved;
1697	    }
1698	    switch(pScrn->bitsPerPixel) {
1699	    case 8:	nPtr->refreshArea = neoRefreshArea8;	break;
1700	    case 16:	nPtr->refreshArea = neoRefreshArea16;	break;
1701	    case 24:	nPtr->refreshArea = neoRefreshArea24;	break;
1702	    case 32:	nPtr->refreshArea = neoRefreshArea32;	break;
1703	    }
1704	}
1705#if 0
1706	ShadowFBInit(pScreen, nPtr->refreshArea);
1707#else
1708	shadowInit (pScreen, neoShadowUpdate, 0);
1709#endif
1710    }
1711
1712    /* Initialise default colourmap */
1713    if(!miCreateDefColormap(pScreen))
1714	return FALSE;
1715
1716    if (!xf86HandleColormaps(pScreen, 256, pScrn->rgbBits,
1717                         NEOLoadPalette, NULL,
1718                         CMAP_PALETTED_TRUECOLOR | CMAP_RELOAD_ON_MODE_SWITCH))
1719	return FALSE;
1720
1721    racflag |= RAC_COLORMAP;
1722    if (nPtr->NeoHWCursorInitialized)
1723        racflag |= RAC_CURSOR;
1724
1725    pScrn->racIoFlags = pScrn->racMemFlags = racflag;
1726
1727    NEOInitVideo(pScreen);
1728
1729    pScreen->SaveScreen = vgaHWSaveScreenWeak();
1730
1731    /* Setup DPMS mode */
1732    if (nPtr->NeoChipset != NM2070)
1733	xf86DPMSInit(pScreen, (DPMSSetProcPtr)NeoDisplayPowerManagementSet,
1734		     0);
1735
1736    if (!nPtr->noLinear) {
1737	pScrn->memPhysBase = (unsigned long)nPtr->NeoLinearAddr;
1738	pScrn->fbOffset = 0;
1739    }
1740
1741    /* Wrap the current CloseScreen function */
1742    nPtr->CloseScreen = pScreen->CloseScreen;
1743    pScreen->CloseScreen = NEOCloseScreen;
1744
1745    /* Report any unused options (only for the first generation) */
1746    if (serverGeneration == 1) {
1747	xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
1748    }
1749
1750    return TRUE;
1751}
1752
1753/* Mandatory */
1754Bool
1755NEOSwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
1756{
1757    return neoModeInit(xf86Screens[scrnIndex], mode);
1758}
1759
1760/* Mandatory */
1761void
1762NEOAdjustFrame(int scrnIndex, int x, int y, int flags)
1763{
1764    ScrnInfoPtr pScrn;
1765    NEOPtr nPtr;
1766    vgaHWPtr hwp;
1767    int oldExtCRTDispAddr;
1768    int Base;
1769
1770    pScrn = xf86Screens[scrnIndex];
1771    hwp = VGAHWPTR(pScrn);
1772    nPtr = NEOPTR(pScrn);
1773
1774    if (nPtr->showcache && y) {
1775	int lastline = nPtr->NeoFbMapSize /
1776	    ((pScrn->displayWidth * pScrn->bitsPerPixel) / 8);
1777
1778	lastline -= pScrn->currentMode->VDisplay;
1779	y += pScrn->virtualY - 1;
1780        if (y > lastline) y = lastline;
1781    }
1782
1783    Base = (y * pScrn->displayWidth + x) >> 2;
1784
1785    /* Scale Base by the number of bytes per pixel. */
1786    switch (pScrn->depth) {
1787    case  8 :
1788	break;
1789    case 15 :
1790    case 16 :
1791	Base *= 2;
1792	break;
1793    case 24 :
1794	Base *= 3;
1795	break;
1796    default :
1797	break;
1798    }
1799    /*
1800     * These are the generic starting address registers.
1801     */
1802    VGAwCR(0x0C, (Base & 0x00FF00) >> 8);
1803    VGAwCR(0x0D, (Base & 0x00FF));
1804
1805    /*
1806     * Make sure we don't clobber some other bits that might already
1807     * have been set. NOTE: NM2200 has a writable bit 3, but it shouldn't
1808     * be needed.
1809     */
1810    oldExtCRTDispAddr = VGArGR(0x0E);
1811    VGAwGR(0x0E,(((Base >> 16) & 0x07) | (oldExtCRTDispAddr & 0xf8)));
1812#if 0
1813    /*
1814     * This is a workaround for a higher level bug that causes the cursor
1815     * to be at the wrong position after a virtual screen resolution change
1816     */
1817    if (nPtr->NeoHWCursorInitialized) { /*§§§ do we still need this?*/
1818	NeoRepositionCursor();
1819    }
1820#endif
1821}
1822
1823/* Mandatory */
1824static Bool
1825NEOCloseScreen(int scrnIndex, ScreenPtr pScreen)
1826{
1827    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1828    NEOPtr nPtr = NEOPTR(pScrn);
1829
1830    if(pScrn->vtSema){
1831	if (nPtr->NeoHWCursorShown)
1832	    NeoHideCursor(pScrn);
1833	neoRestore(pScrn, &(VGAHWPTR(pScrn))->SavedReg, &nPtr->NeoSavedReg, TRUE);
1834
1835	neoLock(pScrn);
1836	neoUnmapMem(pScrn);
1837    }
1838    if (nPtr->AccelInfoRec)
1839	XAADestroyInfoRec(nPtr->AccelInfoRec);
1840    if (nPtr->CursorInfo)
1841	xf86DestroyCursorInfoRec(nPtr->CursorInfo);
1842    if (nPtr->ShadowPtr)
1843	xfree(nPtr->ShadowPtr);
1844
1845    pScrn->vtSema = FALSE;
1846    pScreen->CloseScreen = nPtr->CloseScreen;
1847    return (*pScreen->CloseScreen)(scrnIndex, pScreen);
1848}
1849
1850/* Optional */
1851static void
1852NEOFreeScreen(int scrnIndex, int flags)
1853{
1854    if (xf86LoaderCheckSymbol("vgaHWFreeHWRec"))
1855	vgaHWFreeHWRec(xf86Screens[scrnIndex]);
1856    NEOFreeRec(xf86Screens[scrnIndex]);
1857}
1858
1859/* Optional */
1860static ModeStatus
1861NEOValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags)
1862{
1863    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1864    NEOPtr nPtr = NEOPTR(pScrn);
1865    int vDisplay = mode->VDisplay * ((mode->Flags & V_DBLSCAN) ? 2 : 1);
1866
1867    /*
1868     * Is there any LineCompare Bit 10? Where?
1869     * The 9 well known VGA bits give us a maximum height of 1024
1870     */
1871    if (vDisplay > 1024)
1872	return MODE_BAD;
1873
1874    /*
1875     * Limit the modes to just those allowed by the various NeoMagic
1876     * chips.
1877     */
1878
1879    if (nPtr->overrideValidate) {
1880	xf86DrvMsg(scrnIndex, X_WARNING, "display mode validation disabled\n");
1881    } else {
1882	/*
1883	 * When the LCD is active, only allow modes that are (1) equal to
1884	 * or smaller than the size of the panel and (2) are one of the
1885	 * following sizes: 1024x768, 800x600, 640x480.
1886	 */
1887	if (nPtr->internDisp || !nPtr->externDisp) {
1888	    /* Is the mode larger than the LCD panel? */
1889	    if ((mode->HDisplay > nPtr->NeoPanelWidth) ||
1890		(vDisplay > nPtr->NeoPanelHeight)) {
1891		xf86DrvMsg(scrnIndex,X_INFO, "Removing mode (%dx%d) "
1892			   "larger than the LCD panel (%dx%d)\n",
1893			   mode->HDisplay,
1894			   mode->VDisplay,
1895			   nPtr->NeoPanelWidth,
1896			   nPtr->NeoPanelHeight);
1897		return(MODE_BAD);
1898	    }
1899
1900	    /* Is the mode one of the acceptable sizes? */
1901	    switch (mode->HDisplay) {
1902	    case 1280:
1903		if (mode->VDisplay == 1024)
1904		    return(MODE_OK);
1905		break;
1906	    case 1024 :
1907		if (mode->VDisplay == 768)
1908		    return(MODE_OK);
1909		if ((mode->VDisplay == 480) && (nPtr->NeoPanelHeight == 480))
1910		    return(MODE_OK);
1911		break;
1912	    case  800 :
1913		if (mode->VDisplay == 600)
1914		    return(MODE_OK);
1915		if ((mode->VDisplay == 480) && (nPtr->NeoPanelHeight == 480))
1916		    return(MODE_OK);
1917		break;
1918	    case  640 :
1919		if (mode->VDisplay == 480)
1920		    return(MODE_OK);
1921		break;
1922#if 1
1923	    case 320:
1924		if (mode->VDisplay == 240)
1925		    return(MODE_OK);
1926		break;
1927#endif
1928	    default:
1929		break;
1930	    }
1931
1932	    xf86DrvMsg(scrnIndex, X_INFO, "Removing mode (%dx%d) that won't "
1933		       "display properly on LCD\n",
1934		       mode->HDisplay,
1935		       mode->VDisplay);
1936	    return(MODE_BAD);
1937	}
1938    }
1939    return(MODE_OK);
1940}
1941
1942static void
1943neoLock(ScrnInfoPtr pScrn)
1944{
1945    vgaHWPtr hwp = VGAHWPTR(pScrn);
1946
1947    VGAwGR(0x09,0x00);
1948    vgaHWLock(hwp);
1949}
1950
1951static void
1952neoUnlock(ScrnInfoPtr pScrn)
1953{
1954    vgaHWPtr hwp = VGAHWPTR(pScrn);
1955
1956    vgaHWUnlock(hwp);
1957    VGAwGR(0x09,0x26);
1958}
1959
1960static Bool
1961neoMapMem(ScrnInfoPtr pScrn)
1962{
1963    NEOPtr nPtr = NEOPTR(pScrn);
1964    vgaHWPtr hwp = VGAHWPTR(pScrn);
1965
1966    if (!nPtr->noLinear) {
1967	if (!nPtr->noMMIO) {
1968	    if (nPtr->pEnt->location.type == BUS_PCI){
1969
1970#ifndef XSERVER_LIBPCIACCESS
1971		nPtr->NeoMMIOBase =
1972		    xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
1973				  nPtr->PciTag, nPtr->NeoMMIOAddr,
1974				  0x200000L);
1975		if (nPtr->NeoMMIOAddr2 != 0){
1976		    nPtr->NeoMMIOBase2 =
1977		        xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
1978				      nPtr->PciTag, nPtr->NeoMMIOAddr2,
1979				      0x100000L);
1980		}
1981
1982#else
1983		void** result = (void**)&nPtr->NeoMMIOBase;
1984		int err = pci_device_map_range(nPtr->PciInfo,
1985					       nPtr->NeoMMIOAddr,
1986					       0x200000L,
1987					       PCI_DEV_MAP_FLAG_WRITABLE,
1988					       result);
1989		if (err)
1990		    return FALSE;
1991
1992		if (nPtr->NeoMMIOAddr2 != 0){
1993		    result = (void**)&nPtr->NeoMMIOBase2;
1994		    err = pci_device_map_range(nPtr->PciInfo,
1995						   nPtr->NeoMMIOAddr2,
1996						   0x100000L,
1997						   PCI_DEV_MAP_FLAG_WRITABLE,
1998						   result);
1999
2000		    if (err)
2001			return FALSE;
2002		}
2003#endif
2004	    } else
2005		nPtr->NeoMMIOBase =
2006		    xf86MapVidMem(pScrn->scrnIndex,
2007				  VIDMEM_MMIO, nPtr->NeoMMIOAddr,
2008				  0x200000L);
2009	    if (nPtr->NeoMMIOBase == NULL)
2010	        return FALSE;
2011	}
2012
2013	if (nPtr->pEnt->location.type == BUS_PCI)
2014
2015#ifndef XSERVER_LIBPCIACCESS
2016	    nPtr->NeoFbBase =
2017		xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
2018			      nPtr->PciTag,
2019			      (unsigned long)nPtr->NeoLinearAddr,
2020			      nPtr->NeoFbMapSize);
2021#else
2022	{
2023	    void** result = (void**)&nPtr->NeoFbBase;
2024	    int err = pci_device_map_range(nPtr->PciInfo,
2025					   nPtr->NeoLinearAddr,
2026					   nPtr->NeoFbMapSize,
2027					   PCI_DEV_MAP_FLAG_WRITABLE |
2028					   PCI_DEV_MAP_FLAG_WRITE_COMBINE,
2029					   result);
2030	    if (err)
2031		return FALSE;
2032	}
2033#endif
2034	else
2035	    nPtr->NeoFbBase =
2036		xf86MapVidMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
2037			      (unsigned long)nPtr->NeoLinearAddr,
2038			      nPtr->NeoFbMapSize);
2039	if (nPtr->NeoFbBase == NULL)
2040	    return FALSE;
2041    } else {
2042	/* In paged mode Base is the VGA window at 0xA0000 */
2043	nPtr->NeoFbBase = hwp->Base;
2044    }
2045    return TRUE;
2046}
2047
2048/*
2049 * Unmap the framebuffer and MMIO memory.
2050 */
2051
2052static Bool
2053neoUnmapMem(ScrnInfoPtr pScrn)
2054{
2055    NEOPtr nPtr = NEOPTR(pScrn);
2056
2057    if (!nPtr->noLinear) {
2058#ifndef XSERVER_LIBPCIACCESS
2059      if (nPtr->NeoMMIOBase)
2060	  xf86UnMapVidMem(pScrn->scrnIndex, (pointer)nPtr->NeoMMIOBase,
2061			  0x200000L);
2062#else
2063      if (nPtr->NeoMMIOBase)
2064	  pci_device_unmap_range(nPtr->PciInfo, (pointer)nPtr->NeoMMIOBase, 0x200000L);
2065#endif
2066      nPtr->NeoMMIOBase = NULL;
2067#ifndef XSERVER_LIBPCIACCESS
2068      if (nPtr->NeoMMIOBase2)
2069	  xf86UnMapVidMem(pScrn->scrnIndex, (pointer)nPtr->NeoMMIOBase2,
2070			  0x100000L);
2071#else
2072      if (nPtr->NeoMMIOBase2)
2073	  pci_device_unmap_range(nPtr->PciInfo, (pointer)nPtr->NeoMMIOBase2, 0x100000L);
2074#endif
2075      nPtr->NeoMMIOBase2 = NULL;
2076#ifndef XSERVER_LIBPCIACCESS
2077      xf86UnMapVidMem(pScrn->scrnIndex, (pointer)nPtr->NeoFbBase,
2078		    nPtr->NeoFbMapSize);
2079#else
2080      pci_device_unmap_range(nPtr->PciInfo, (pointer)nPtr->NeoFbBase, nPtr->NeoFbMapSize);
2081#endif
2082    }
2083    nPtr->NeoFbBase = NULL;
2084
2085    return TRUE;
2086}
2087
2088static void
2089neoSave(ScrnInfoPtr pScrn)
2090{
2091    vgaRegPtr VgaSave = &VGAHWPTR(pScrn)->SavedReg;
2092    vgaHWPtr hwp = VGAHWPTR(pScrn);
2093    NEOPtr nPtr = NEOPTR(pScrn);
2094    NeoRegPtr save;
2095    int i;
2096
2097    save = &nPtr->NeoSavedReg;
2098
2099    VGAwGR(0x09,0x26);
2100    /*
2101     * Whatever code is needed to get back to bank zero goes here.
2102     */
2103    VGAwGR(0x15,0x00);
2104
2105    /* get generic registers */
2106    vgaHWSave(pScrn, VgaSave, VGA_SR_ALL);
2107
2108    /*
2109     * The port I/O code necessary to read in the extended registers
2110     * into the fields of the vgaNeoRec structure goes here.
2111     */
2112
2113    save->GeneralLockReg = VGArGR(0x0A);
2114
2115    save->ExtCRTDispAddr = VGArGR(0x0E);
2116    if (nPtr->NeoChipset != NM2070) {
2117	save->ExtCRTOffset = VGArGR(0x0F);
2118    }
2119    save->SysIfaceCntl1 = VGArGR(0x10);
2120    save->SysIfaceCntl2 = VGArGR(0x11);
2121    save->SingleAddrPage = VGArGR(0x15);
2122    save->DualAddrPage = VGArGR(0x16);
2123    save->PanelDispCntlReg1 = VGArGR(0x20);
2124    save->PanelDispCntlReg2 = VGArGR(0x25);
2125    save->PanelDispCntlReg3 = VGArGR(0x30);
2126    save->PanelVertCenterReg1 = VGArGR(0x28);
2127    save->PanelVertCenterReg2 = VGArGR(0x29);
2128    save->PanelVertCenterReg3 = VGArGR(0x2A);
2129    if (nPtr->NeoChipset != NM2070) {
2130        save->PanelVertCenterReg4 = VGArGR(0x32);
2131	save->PanelHorizCenterReg1 = VGArGR(0x33);
2132	save->PanelHorizCenterReg2 = VGArGR(0x34);
2133	save->PanelHorizCenterReg3 = VGArGR(0x35);
2134    }
2135    if (nPtr->NeoChipset == NM2160) {
2136        save->PanelHorizCenterReg4 = VGArGR(0x36);
2137    }
2138    if (nPtr->NeoChipset == NM2200 || nPtr->NeoChipset == NM2230
2139	|| nPtr->NeoChipset == NM2360 || nPtr->NeoChipset == NM2380) {
2140	save->PanelHorizCenterReg4 = VGArGR(0x36);
2141	save->PanelVertCenterReg5  = VGArGR(0x37);
2142	save->PanelHorizCenterReg5 = VGArGR(0x38);
2143    }
2144    save->ExtColorModeSelect = VGArGR(0x90);
2145    save->VCLK3NumeratorLow = VGArGR(0x9B);
2146    if (nPtr->NeoChipset == NM2200 || nPtr->NeoChipset == NM2230
2147	|| nPtr->NeoChipset == NM2360 || nPtr->NeoChipset == NM2380)
2148	save->VCLK3NumeratorHigh = VGArGR(0x8F);
2149    save->VCLK3Denominator = VGArGR(0x9F);
2150    save->ProgramVCLK = TRUE;
2151
2152    if (save->reg == NULL)
2153        save->reg = (regSavePtr)xnfcalloc(sizeof(regSaveRec), 1);
2154    else
2155        xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2156		   "Non-NULL reg in NeoSave: reg=%p\n", (void *)save->reg);
2157
2158    save->reg->CR[0x23] = VGArCR(0x23);
2159    save->reg->CR[0x25] = VGArCR(0x25);
2160    save->reg->CR[0x2F] = VGArCR(0x2F);
2161    for (i = 0x40; i <= 0x59; i++) {
2162	save->reg->CR[i] = VGArCR(i);
2163    }
2164    for (i = 0x60; i <= 0x69; i++) {
2165	save->reg->CR[i] = VGArCR(i);
2166    }
2167    for (i = 0x70; i <= NEO_EXT_CR_MAX; i++) {
2168	save->reg->CR[i] = VGArCR(i);
2169    }
2170
2171    for (i = 0x0A; i <= NEO_EXT_GR_MAX; i++) {
2172        save->reg->GR[i] = VGArGR(i);
2173    }
2174}
2175
2176/*
2177 * neoProgramShadowRegs
2178 *
2179 * Setup the shadow registers to their default values.  The NeoSave
2180 * routines will restore the proper values on server exit.
2181 */
2182static void
2183neoProgramShadowRegs(ScrnInfoPtr pScrn, vgaRegPtr VgaReg, NeoRegPtr restore)
2184{
2185    int i;
2186    Bool noProgramShadowRegs;
2187    vgaHWPtr hwp = VGAHWPTR(pScrn);
2188    NEOPtr nPtr = NEOPTR(pScrn);
2189    Bool prog_lcd;
2190
2191    /*
2192     * If display is external only and we want internal
2193     * we need to program the shadow registers.
2194     */
2195    prog_lcd = (((VGArGR(0x20) & 0x3) == 0x1) && nPtr->internDisp);
2196
2197
2198    /*
2199     * Convoluted logic for shadow register programming.
2200     *
2201     * As far as we know, shadow programming is needed for the 2070,
2202     * but not in stretched modes.  Special case this code.
2203     */
2204    switch (nPtr->NeoChipset) {
2205    case NM2070:
2206	/* Program the shadow regs by default */
2207	noProgramShadowRegs = FALSE;
2208	if (!nPtr->progLcdRegs && !prog_lcd)
2209	    noProgramShadowRegs = TRUE;
2210
2211	if (restore->PanelDispCntlReg2 & 0x84) {
2212	    /* Don't program by default if in stretch mode */
2213	    noProgramShadowRegs = TRUE;
2214	    if (nPtr->progLcdStretch)
2215		noProgramShadowRegs = FALSE;
2216	}
2217	break;
2218    case NM2090:
2219    case NM2093:
2220    case NM2097:
2221    case NM2160:
2222    case NM2200:
2223    case NM2230:
2224    case NM2360:
2225    case NM2380:
2226    default:
2227	/* Don't program the shadow regs by default */
2228	noProgramShadowRegs = TRUE;
2229	if (nPtr->progLcdRegs || prog_lcd)
2230	    noProgramShadowRegs = FALSE;
2231
2232	if (restore->PanelDispCntlReg2 & 0x84) {
2233	    /* Only change the behavior if an option is set */
2234	    if (nPtr->progLcdStretchOpt)
2235		noProgramShadowRegs = !nPtr->progLcdStretch;
2236	}
2237	break;
2238    }
2239
2240    if (noProgramShadowRegs) {
2241	xf86DrvMsgVerb(pScrn->scrnIndex,X_INFO,5,"Not programming shadow registers\n");
2242	if (nPtr->NeoSavedReg.reg){
2243	    for (i = 0x40; i <= 0x59; i++) {
2244		VGAwCR(i, nPtr->NeoSavedReg.reg->CR[i]);
2245	    }
2246	    for (i = 0x60; i <= 0x64; i++) {
2247		VGAwCR(i, nPtr->NeoSavedReg.reg->CR[i]);
2248	    }
2249	}
2250    } else {
2251	/*
2252	 * Program the shadow regs based on the panel width.  This works
2253	 * fine for normal sized panels, but what about the odd ones like
2254	 * the Libretto 100 which has an 800x480 panel???
2255	 */
2256	switch (nPtr->NeoPanelWidth) {
2257	case 640 :
2258	    VGAwCR(0x40,0x5F);
2259	    VGAwCR(0x41,0x50);
2260	    VGAwCR(0x42,0x02);
2261	    VGAwCR(0x43,0x55);
2262	    VGAwCR(0x44,0x81);
2263	    VGAwCR(0x45,0x0B);
2264	    VGAwCR(0x46,0x2E);
2265	    VGAwCR(0x47,0xEA);
2266	    VGAwCR(0x48,0x0C);
2267	    VGAwCR(0x49,0xE7);
2268	    VGAwCR(0x4A,0x04);
2269	    VGAwCR(0x4B,0x2D);
2270	    VGAwCR(0x4C,0x28);
2271	    VGAwCR(0x4D,0x90);
2272	    VGAwCR(0x4E,0x2B);
2273	    VGAwCR(0x4F,0xA0);
2274	    break;
2275	case 800 :
2276	    switch (nPtr->NeoPanelHeight) {
2277	    case 600:
2278		VGAwCR(0x40,0x7F);
2279		VGAwCR(0x41,0x63);
2280		VGAwCR(0x42,0x02);
2281		VGAwCR(0x43,0x6C);
2282		VGAwCR(0x44,0x1C);
2283		VGAwCR(0x45,0x72);
2284		VGAwCR(0x46,0xE0);
2285		VGAwCR(0x47,0x58);
2286		VGAwCR(0x48,0x0C);
2287		VGAwCR(0x49,0x57);
2288		VGAwCR(0x4A,0x73);
2289		VGAwCR(0x4B,0x3D);
2290		VGAwCR(0x4C,0x31);
2291		VGAwCR(0x4D,0x01);
2292		VGAwCR(0x4E,0x36);
2293		VGAwCR(0x4F,0x1E);
2294		if (nPtr->NeoChipset != NM2070) {
2295		    VGAwCR(0x50,0x6B);
2296		    VGAwCR(0x51,0x4F);
2297		    VGAwCR(0x52,0x0E);
2298		    VGAwCR(0x53,0x58);
2299		    VGAwCR(0x54,0x88);
2300		    VGAwCR(0x55,0x33);
2301		    VGAwCR(0x56,0x27);
2302		    VGAwCR(0x57,0x16);
2303		    VGAwCR(0x58,0x2C);
2304		    VGAwCR(0x59,0x94);
2305		}
2306		break;
2307	    case 480:
2308		VGAwCR(0x40,0x7F);
2309		VGAwCR(0x41,0x63);
2310		VGAwCR(0x42,0x02);
2311		VGAwCR(0x43,0x6B);
2312		VGAwCR(0x44,0x1B);
2313		VGAwCR(0x45,0x72);
2314		VGAwCR(0x46,0xE0);
2315		VGAwCR(0x47,0x1C);
2316		VGAwCR(0x48,0x00);
2317		VGAwCR(0x49,0x57);
2318		VGAwCR(0x4A,0x73);
2319		VGAwCR(0x4B,0x3E);
2320		VGAwCR(0x4C,0x31);
2321		VGAwCR(0x4D,0x01);
2322		VGAwCR(0x4E,0x36);
2323		VGAwCR(0x4F,0x1E);
2324		VGAwCR(0x50,0x6B);
2325		VGAwCR(0x51,0x4F);
2326		VGAwCR(0x52,0x0E);
2327		VGAwCR(0x53,0x57);
2328		VGAwCR(0x54,0x87);
2329		VGAwCR(0x55,0x33);
2330		VGAwCR(0x56,0x27);
2331		VGAwCR(0x57,0x16);
2332		VGAwCR(0x58,0x2C);
2333		VGAwCR(0x59,0x94);
2334		break;
2335		break;
2336		/* Not done */
2337	    }
2338	    break;
2339	case 1024 :
2340	    switch (nPtr->NeoPanelHeight) {
2341	    case 768:
2342		VGAwCR(0x40,0xA3);
2343		VGAwCR(0x41,0x7F);
2344		VGAwCR(0x42,0x06);
2345		VGAwCR(0x43,0x85);
2346		VGAwCR(0x44,0x96);
2347		VGAwCR(0x45,0x24);
2348		VGAwCR(0x46,0xE5);
2349		VGAwCR(0x47,0x02);
2350		VGAwCR(0x48,0x08);
2351		VGAwCR(0x49,0xFF);
2352		VGAwCR(0x4A,0x25);
2353		VGAwCR(0x4B,0x4F);
2354		VGAwCR(0x4C,0x40);
2355		VGAwCR(0x4D,0x00);
2356		VGAwCR(0x4E,0x44);
2357		VGAwCR(0x4F,0x0C);
2358		VGAwCR(0x50,0x7A);
2359		VGAwCR(0x51,0x56);
2360		VGAwCR(0x52,0x00);
2361		VGAwCR(0x53,0x5D);
2362		VGAwCR(0x54,0x0E);
2363		VGAwCR(0x55,0x3B);
2364		VGAwCR(0x56,0x2B);
2365		VGAwCR(0x57,0x00);
2366		VGAwCR(0x58,0x2F);
2367		VGAwCR(0x59,0x18);
2368		VGAwCR(0x60,0x88);
2369		VGAwCR(0x61,0x63);
2370		VGAwCR(0x62,0x0B);
2371		VGAwCR(0x63,0x69);
2372		VGAwCR(0x64,0x1A);
2373		break;
2374	    case 480:
2375		VGAwCR(0x40,0xA3);
2376		VGAwCR(0x41,0x7F);
2377		VGAwCR(0x42,0x1B);
2378		VGAwCR(0x43,0x89);
2379		VGAwCR(0x44,0x16);
2380		VGAwCR(0x45,0x0B);
2381		VGAwCR(0x46,0x2C);
2382		VGAwCR(0x47,0xE8);
2383		VGAwCR(0x48,0x0C);
2384		VGAwCR(0x49,0xE7);
2385		VGAwCR(0x4A,0x09);
2386		VGAwCR(0x4B,0x4F);
2387		VGAwCR(0x4C,0x40);
2388		VGAwCR(0x4D,0x00);
2389		VGAwCR(0x4E,0x44);
2390		VGAwCR(0x4F,0x0C);
2391		VGAwCR(0x50,0x7A);
2392		VGAwCR(0x51,0x56);
2393		VGAwCR(0x52,0x00);
2394		VGAwCR(0x53,0x5D);
2395		VGAwCR(0x54,0x0E);
2396		VGAwCR(0x55,0x3B);
2397		VGAwCR(0x56,0x2A);
2398		VGAwCR(0x57,0x00);
2399		VGAwCR(0x58,0x2F);
2400		VGAwCR(0x59,0x18);
2401		VGAwCR(0x60,0x88);
2402		VGAwCR(0x61,0x63);
2403		VGAwCR(0x62,0x0B);
2404		VGAwCR(0x63,0x69);
2405		VGAwCR(0x64,0x1A);
2406		break;
2407	    }
2408	    break;
2409	case 1280:
2410#ifdef NOT_DONE
2411	    VGAwCR(0x40,0x?? );
2412            .
2413		.
2414		.
2415		VGAwCR(0x64,0x?? );
2416		break;
2417#else
2418		/* Probe should prevent this case for now */
2419		FatalError("1280 panel support incomplete\n");
2420#endif
2421	}
2422    }
2423}
2424
2425static void
2426neoRestore(ScrnInfoPtr pScrn, vgaRegPtr VgaReg, NeoRegPtr restore,
2427	     Bool restoreText)
2428{
2429    NEOPtr nPtr = NEOPTR(pScrn);
2430    vgaHWPtr hwp = VGAHWPTR(pScrn);
2431    unsigned char temp;
2432    int i;
2433    Bool clock_hi = FALSE;
2434
2435    vgaHWProtect(pScrn,TRUE);		/* Blank the screen */
2436
2437    VGAwGR(0x09,0x26);
2438
2439    /* Init the shadow registers if necessary */
2440    neoProgramShadowRegs(pScrn, VgaReg, restore);
2441
2442    VGAwGR(0x15,0x00);
2443
2444    VGAwGR(0x0A,restore->GeneralLockReg);
2445
2446    /*
2447     * The color mode needs to be set before calling vgaHWRestore
2448     * to ensure the DAC is initialized properly.
2449     *
2450     * NOTE: Make sure we don't change bits make sure we don't change
2451     * any reserved bits.
2452     */
2453    temp = VGArGR(0x90);
2454
2455    switch (nPtr->NeoChipset) {
2456    case NM2070 :
2457	temp &= 0xF0; /* Save bits 7:4 */
2458	temp |= (restore->ExtColorModeSelect & ~0xF0);
2459	break;
2460    case NM2090 :
2461    case NM2093 :
2462    case NM2097 :
2463    case NM2160 :
2464    case NM2200 :
2465    case NM2230 :
2466    case NM2360 :
2467    case NM2380 :
2468	temp &= 0x70; /* Save bits 6:4 */
2469	temp |= (restore->ExtColorModeSelect & ~0x70);
2470	break;
2471    }
2472    VGAwGR(0x90,temp);
2473
2474    /*
2475     * In some rare cases a lockup might occur if we don't delay
2476     * here. (Reported by Miles Lane)
2477     */
2478    xf86UDelay(200000);
2479    /*
2480     * Disable horizontal and vertical graphics and text expansions so
2481     * that vgaHWRestore works properly.
2482     */
2483    temp = VGArGR(0x25);
2484    temp &= 0x39;
2485    VGAwGR(0x25, temp);
2486
2487    /*
2488     * Sleep for 200ms to make sure that the two operations above have
2489     * had time to take effect.
2490     */
2491    xf86UDelay(200000);
2492    /*
2493     * This function handles restoring the generic VGA registers.  */
2494    vgaHWRestore(pScrn, VgaReg,
2495		 VGA_SR_MODE
2496		 | (restoreText ? (VGA_SR_FONTS | VGA_SR_CMAP) : 0));
2497
2498    VGAwGR(0x0E, restore->ExtCRTDispAddr);
2499    VGAwGR(0x0F, restore->ExtCRTOffset);
2500    temp = VGArGR(0x10);
2501    temp &= 0x0F; /* Save bits 3:0 */
2502    temp |= (restore->SysIfaceCntl1 & ~0x0F);
2503    VGAwGR(0x10, temp);
2504
2505    VGAwGR(0x11, restore->SysIfaceCntl2);
2506    VGAwGR(0x15, restore->SingleAddrPage);
2507    VGAwGR(0x16, restore->DualAddrPage);
2508
2509    temp = VGArGR(0x20);
2510    switch (nPtr->NeoChipset) {
2511    case NM2070 :
2512	temp &= 0xFC; /* Save bits 7:2 */
2513	temp |= (restore->PanelDispCntlReg1 & ~0xFC);
2514	break;
2515    case NM2090 :
2516    case NM2093 :
2517    case NM2097 :
2518    case NM2160 :
2519	temp &= 0xDC; /* Save bits 7:6,4:2 */
2520	temp |= (restore->PanelDispCntlReg1 & ~0xDC);
2521	break;
2522    case NM2200 :
2523    case NM2230 :
2524    case NM2360 :
2525    case NM2380 :
2526	temp &= 0x98; /* Save bits 7,4:3 */
2527	temp |= (restore->PanelDispCntlReg1 & ~0x98);
2528	break;
2529    }
2530    VGAwGR(0x20, temp);
2531
2532    temp = VGArGR(0x25);
2533    temp &= 0x38; /* Save bits 5:3 */
2534    temp |= (restore->PanelDispCntlReg2 & ~0x38);
2535    VGAwGR(0x25, temp);
2536
2537    if (nPtr->NeoChipset != NM2070) {
2538	temp = VGArGR(0x30);
2539	temp &= 0xEF; /* Save bits 7:5 and bits 3:0 */
2540	temp |= (restore->PanelDispCntlReg3 & ~0xEF);
2541	VGAwGR(0x30, temp);
2542    }
2543
2544    VGAwGR(0x28, restore->PanelVertCenterReg1);
2545    VGAwGR(0x29, restore->PanelVertCenterReg2);
2546    VGAwGR(0x2a, restore->PanelVertCenterReg3);
2547
2548    if (nPtr->NeoChipset != NM2070) {
2549	VGAwGR(0x32, restore->PanelVertCenterReg4);
2550	VGAwGR(0x33, restore->PanelHorizCenterReg1);
2551	VGAwGR(0x34, restore->PanelHorizCenterReg2);
2552	VGAwGR(0x35, restore->PanelHorizCenterReg3);
2553    }
2554
2555    if (nPtr->NeoChipset == NM2160) {
2556	VGAwGR(0x36, restore->PanelHorizCenterReg4);
2557    }
2558
2559    if (nPtr->NeoChipset == NM2200 || nPtr->NeoChipset == NM2230
2560	|| nPtr->NeoChipset == NM2360 || nPtr->NeoChipset == NM2380) {
2561        VGAwGR(0x36, restore->PanelHorizCenterReg4);
2562        VGAwGR(0x37, restore->PanelVertCenterReg5);
2563        VGAwGR(0x38, restore->PanelHorizCenterReg5);
2564    }
2565    if (nPtr->NeoChipset == NM2200 || nPtr->NeoChipset == NM2230
2566	|| nPtr->NeoChipset == NM2360 || nPtr->NeoChipset == NM2380)
2567	clock_hi = TRUE;
2568
2569    /* Program VCLK3 if needed. */
2570    if (restore->ProgramVCLK
2571	 && ((VGArGR(0x9B) != restore->VCLK3NumeratorLow)
2572	    || (VGArGR(0x9F) !=  restore->VCLK3Denominator)
2573	    || (clock_hi && ((VGArGR(0x8F) & ~0x0f)
2574			     != (restore->VCLK3NumeratorHigh & ~0x0F))))) {
2575	VGAwGR(0x9B, restore->VCLK3NumeratorLow);
2576	if (clock_hi) {
2577	    temp = VGArGR(0x8F);
2578	    temp &= 0x0F; /* Save bits 3:0 */
2579	    temp |= (restore->VCLK3NumeratorHigh & ~0x0F);
2580	    VGAwGR(0x8F, temp);
2581	}
2582	VGAwGR(0x9F, restore->VCLK3Denominator);
2583    }
2584    if (restore->biosMode)
2585	VGAwCR(0x23,restore->biosMode);
2586
2587    if (restore->reg) {
2588	VGAwCR(0x23,restore->reg->CR[0x23]);
2589	VGAwCR(0x25,restore->reg->CR[0x25]);
2590	VGAwCR(0x2F,restore->reg->CR[0x2F]);
2591	for (i = 0x40; i <= 0x59; i++) {
2592	    VGAwCR(i, restore->reg->CR[i]);
2593	}
2594	for (i = 0x60; i <= 0x69; i++) {
2595	    VGAwCR(i, restore->reg->CR[i]);
2596	}
2597	for (i = 0x70; i <= NEO_EXT_CR_MAX; i++) {
2598	    VGAwCR(i, restore->reg->CR[i]);
2599	}
2600
2601	for (i = 0x0a; i <= 0x3f; i++) {
2602	    VGAwGR(i, restore->reg->GR[i]);
2603	}
2604	for (i = 0x90; i <= NEO_EXT_GR_MAX; i++) {
2605	    VGAwGR(i, restore->reg->GR[i]);
2606	}
2607    }
2608
2609    VGAwGR (0x93, 0xc0); /* Gives faster framebuffer writes */
2610
2611    /* Program vertical extension register */
2612    if (nPtr->NeoChipset == NM2200 || nPtr->NeoChipset == NM2230
2613	|| nPtr->NeoChipset == NM2360 || nPtr->NeoChipset == NM2380) {
2614	VGAwCR(0x70, restore->VerticalExt);
2615    }
2616
2617    vgaHWProtect(pScrn, FALSE);		/* Turn on screen */
2618}
2619
2620static Bool
2621neoModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
2622{
2623    NEOPtr nPtr = NEOPTR(pScrn);
2624    NEOACLPtr nAcl = NEOACLPTR(pScrn);
2625    int hoffset, voffset;
2626    vgaHWPtr hwp = VGAHWPTR(pScrn);
2627    NeoRegPtr NeoNew = &nPtr->NeoModeReg;
2628    vgaRegPtr NeoStd = &hwp->ModeReg;
2629    Bool noLcdStretch = nPtr->noLcdStretch;
2630    int clockMul = 1;
2631
2632    neoUnlock(pScrn);
2633
2634    /*
2635     * This will allocate the datastructure and initialize all of the
2636     * generic VGA registers.
2637     */
2638
2639    if (!vgaHWInit(pScrn, mode))
2640	return(FALSE);
2641
2642    /*
2643     * Several registers need to be corrected from the default values
2644     * assigned by vgaHWinit().
2645     */
2646    pScrn->vtSema = TRUE;
2647
2648    /*
2649     * The default value assigned by vgaHW.c is 0x41, but this does
2650     * not work for NeoMagic.
2651     */
2652    NeoStd->Attribute[16] = 0x01;
2653
2654    switch (pScrn->depth) { /*@!@*/
2655    case  8 :
2656	NeoStd->CRTC[0x13] = pScrn->displayWidth >> 3;
2657	NeoNew->ExtCRTOffset   = pScrn->displayWidth >> 11;
2658	NeoNew->ExtColorModeSelect = 0x11;
2659	break;
2660    case 15 :
2661        NeoNew->ExtColorModeSelect = 0x12;
2662	NeoStd->CRTC[0x13] = pScrn->displayWidth >> 2;
2663	NeoNew->ExtCRTOffset   = pScrn->displayWidth >> 10;
2664        break;
2665    case 16 :
2666        NeoNew->ExtColorModeSelect = 0x13;
2667	NeoStd->CRTC[0x13] = pScrn->displayWidth >> 2;
2668	NeoNew->ExtCRTOffset   = pScrn->displayWidth >> 10;
2669	break;
2670    case 24 :
2671	NeoStd->CRTC[0x13] = (pScrn->displayWidth * 3) >> 3;
2672	NeoNew->ExtCRTOffset   = (pScrn->displayWidth * 3) >> 11;
2673	NeoNew->ExtColorModeSelect = 0x14;
2674	break;
2675    default :
2676	break;
2677    }
2678
2679    NeoNew->ExtCRTDispAddr = 0x10;
2680
2681    /* Vertical Extension */
2682    NeoNew->VerticalExt = (((mode->CrtcVTotal -2) & 0x400) >> 10 )
2683      | (((mode->CrtcVDisplay -1) & 0x400) >> 9 )
2684        | (((mode->CrtcVSyncStart) & 0x400) >> 8 )
2685          | (((mode->CrtcVBlankStart - 1) & 0x400) >> 7 );
2686
2687    /* Fast write bursts on unless disabled. */
2688    if (nPtr->onPciBurst) {
2689	NeoNew->SysIfaceCntl1 = 0x30;
2690    } else {
2691	NeoNew->SysIfaceCntl1 = 0x00;
2692    }
2693
2694    /* If they are used, enable linear addressing and/or enable MMIO. */
2695    NeoNew->SysIfaceCntl2 = 0x00;
2696    if (!nPtr->noLinear)
2697	NeoNew->SysIfaceCntl2 |= 0x80;
2698    if (!nPtr->noMMIO)
2699	NeoNew->SysIfaceCntl2 |= 0x40;
2700
2701    /* Enable any user specified display devices. */
2702    NeoNew->PanelDispCntlReg1 = 0x00;
2703    if (nPtr->internDisp) {
2704	NeoNew->PanelDispCntlReg1 |= 0x02;
2705    }
2706    if (nPtr->externDisp) {
2707	NeoNew->PanelDispCntlReg1 |= 0x01;
2708    }
2709
2710#if 0
2711    /*
2712     * This was replaced: if no devices are specified take the
2713     * probed settings. If the probed settings are bogus fallback
2714     * to internal only.
2715     */
2716    /* If the user did not specify any display devices, then... */
2717    if (NeoNew->PanelDispCntlReg1 == 0x00) {
2718	/* Default to internal (i.e., LCD) only. */
2719	NeoNew->PanelDispCntlReg1 |= 0x02;
2720    }
2721#endif
2722    /* If we are using a fixed mode, then tell the chip we are. */
2723    switch (mode->HDisplay) {
2724    case 1280:
2725	NeoNew->PanelDispCntlReg1 |= 0x60;
2726        break;
2727    case 1024:
2728	NeoNew->PanelDispCntlReg1 |= 0x40;
2729        break;
2730    case 800:
2731	NeoNew->PanelDispCntlReg1 |= 0x20;
2732        break;
2733    case 640:
2734    default:
2735        break;
2736    }
2737
2738    /* Setup shadow register locking. */
2739    switch (NeoNew->PanelDispCntlReg1 & 0x03) {
2740    case 0x01 : /* External CRT only mode: */
2741	NeoNew->GeneralLockReg = 0x00;
2742	/* We need to program the VCLK for external display only mode. */
2743	NeoNew->ProgramVCLK = TRUE;
2744	break;
2745    case 0x02 : /* Internal LCD only mode: */
2746    case 0x03 : /* Simultaneous internal/external (LCD/CRT) mode: */
2747	NeoNew->GeneralLockReg = 0x01;
2748	/* Don't program the VCLK when using the LCD. */
2749	NeoNew->ProgramVCLK = FALSE;
2750	break;
2751    }
2752
2753    /*
2754     * If the screen is to be stretched, turn on stretching for the
2755     * various modes.
2756     *
2757     * OPTION_LCD_STRETCH means stretching should be turned off!
2758     */
2759    NeoNew->PanelDispCntlReg2 = 0x00;
2760    NeoNew->PanelDispCntlReg3 = 0x00;
2761    nAcl->NoCursorMode = FALSE;
2762
2763    if ((!noLcdStretch) &&
2764	(NeoNew->PanelDispCntlReg1 & 0x02)) {
2765	if (mode->HDisplay == nPtr->NeoPanelWidth) {
2766	    /*
2767	     * Don't disable the flag.  It will be needed if another mode
2768	     * is selected.
2769	     */
2770	    /*
2771	     * No stretching required when the requested display width
2772	     * equals the panel width.
2773	     */
2774	    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"Stretching disabled\n");
2775	        noLcdStretch = TRUE;
2776	} else {
2777
2778	    switch (mode->HDisplay) {
2779	    case  320 : /* Needs testing.  KEM -- 24 May 98 */
2780	    case  400 : /* Needs testing.  KEM -- 24 May 98 */
2781	    case  640 :
2782	    case  800 :
2783	    case 1024 :
2784		NeoNew->PanelDispCntlReg2 |= 0xC6;
2785		nAcl->NoCursorMode = TRUE;
2786		break;
2787	    default   :
2788		/* No stretching in these modes. */
2789		xf86DrvMsg(pScrn->scrnIndex,X_INFO,
2790			   "Stretching disabled not supported in this mode\n");
2791		noLcdStretch = TRUE;
2792		break;
2793	    }
2794	}
2795    } else if (mode->Flags & V_DBLSCAN) {
2796	nAcl->NoCursorMode = TRUE;
2797    }
2798
2799    /*
2800     * If the screen is to be centerd, turn on the centering for the
2801     * various modes.
2802     */
2803    NeoNew->PanelVertCenterReg1  = 0x00;
2804    NeoNew->PanelVertCenterReg2  = 0x00;
2805    NeoNew->PanelVertCenterReg3  = 0x00;
2806    NeoNew->PanelVertCenterReg4  = 0x00;
2807    NeoNew->PanelVertCenterReg5  = 0x00;
2808    NeoNew->PanelHorizCenterReg1 = 0x00;
2809    NeoNew->PanelHorizCenterReg2 = 0x00;
2810    NeoNew->PanelHorizCenterReg3 = 0x00;
2811    NeoNew->PanelHorizCenterReg4 = 0x00;
2812    NeoNew->PanelHorizCenterReg5 = 0x00;
2813
2814    if (nPtr->lcdCenter &&
2815	(NeoNew->PanelDispCntlReg1 & 0x02)) {
2816	Bool doCenter = FALSE;
2817
2818	hoffset = 0;
2819	voffset = 0;
2820	if (mode->HDisplay == nPtr->NeoPanelWidth) {
2821	    /*
2822	     * No centering required when the requested display width
2823	     * equals the panel width.
2824	     */
2825	} else {
2826	    NeoNew->PanelDispCntlReg3 |= 0x10;
2827	    if (noLcdStretch) {
2828		/* Calculate the horizontal offsets. */
2829		int HDisplay = mode->HDisplay
2830		    << ((mode->VDisplay < 480) ? 1 : 0);
2831		hoffset = ((nPtr->NeoPanelWidth - HDisplay) >> 4) - 1;
2832		if (mode->VDisplay < 480)
2833		    hoffset >>= 1;
2834		doCenter = TRUE;
2835	    } else {
2836		/* Stretched modes cannot be centered. */
2837		hoffset = 0;
2838	    }
2839	}
2840	if (mode->VDisplay == nPtr->NeoPanelHeight) {
2841	    /*
2842	     * No centering required when the requested display width
2843	     * equals the panel width.
2844	     */
2845	} else {
2846	    NeoNew->PanelDispCntlReg2 |= 0x01;
2847	    if (noLcdStretch) {
2848		/* Calculate the vertical offsets. */
2849		int VDisplay = mode->VDisplay
2850		    << ((mode->Flags & V_DBLSCAN) ? 1 : 0);
2851		voffset = ((nPtr->NeoPanelHeight - VDisplay) >> 1) - 2;
2852		doCenter = TRUE;
2853	    } else {
2854		/* Stretched modes cannot be centered. */
2855		voffset = 0;
2856	    }
2857	}
2858
2859	if (doCenter) {
2860	    switch (mode->HDisplay) {
2861	    case  320 : /* Needs testing.  KEM -- 24 May 98 */
2862  		NeoNew->PanelHorizCenterReg3 = hoffset;
2863		NeoNew->PanelVertCenterReg3  = voffset;
2864		break;
2865	    case  400 : /* Needs testing.  KEM -- 24 May 98 */
2866		NeoNew->PanelHorizCenterReg4 = hoffset;
2867		NeoNew->PanelVertCenterReg1  = voffset;
2868		break;
2869	    case  640 :
2870		NeoNew->PanelHorizCenterReg1 = hoffset;
2871		NeoNew->PanelVertCenterReg3  = voffset;
2872		break;
2873	    case  800 :
2874		NeoNew->PanelHorizCenterReg2 = hoffset;
2875		switch (mode->VDisplay) {
2876		case 600:
2877		    NeoNew->PanelVertCenterReg4  = voffset;
2878		    break;
2879		case 480:
2880		    /* Not sure if this is correct */
2881		    NeoNew->PanelVertCenterReg3  = voffset;
2882		    break;
2883		}
2884		break;
2885	    case 1024 :
2886		NeoNew->PanelHorizCenterReg5 = hoffset;
2887		NeoNew->PanelVertCenterReg5  = voffset;
2888		break;
2889	    case 1280 :
2890	    default   :
2891		/* No centering in these modes. */
2892		break;
2893	    }
2894	}
2895    }
2896
2897    if (!noLcdStretch &&
2898	(NeoNew->PanelDispCntlReg1 & 0x02))  {
2899	if (mode->HDisplay != nPtr->NeoPanelWidth)
2900	    nPtr->videoHZoom = (double)nPtr->NeoPanelWidth/mode->HDisplay;
2901	if (mode->VDisplay != nPtr->NeoPanelHeight)
2902	    nPtr->videoVZoom = (double)nPtr->NeoPanelHeight/mode->VDisplay;
2903    } else {
2904	nPtr->videoHZoom = 1.0;
2905	nPtr->videoVZoom = 1.0;
2906    }
2907    /* Do double scan */
2908    if (mode->VDisplay < 480) {
2909	NeoStd->Sequencer[1] |= 0x8;
2910	clockMul = 2;
2911    }
2912
2913    NeoNew->biosMode = neoFindMode(mode->HDisplay,mode->VDisplay,pScrn->depth);
2914
2915    /*
2916     * New->reg should be empty.  Just in
2917     * case it isn't, warn us and clear it anyway.
2918     */
2919    if (NeoNew->reg) {
2920	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2921		   "Non-NULL reg in NeoInit: reg=%p\n", (void *)NeoNew->reg);
2922	xfree(NeoNew->reg);
2923	NeoNew->reg = NULL;
2924    }
2925
2926    /*
2927     * Calculate the VCLK that most closely matches the requested dot
2928     * clock.
2929     */
2930    neoCalcVCLK(pScrn, mode->SynthClock*clockMul);
2931
2932    /* Since we program the clocks ourselves, always use VCLK3. */
2933    NeoStd->MiscOutReg |= 0x0C;
2934
2935    neoRestore(pScrn, NeoStd, NeoNew, FALSE);
2936
2937    return(TRUE);
2938}
2939
2940/*
2941 * neoCalcVCLK --
2942 *
2943 * Determine the closest clock frequency to the one requested.
2944 */
2945#define REF_FREQ 14.31818
2946#define MAX_N 127
2947#define MAX_D 31
2948#define MAX_F 1
2949
2950static void
2951neoCalcVCLK(ScrnInfoPtr pScrn, long freq)
2952{
2953    NEOPtr nPtr = NEOPTR(pScrn);
2954
2955    int n, d, f;
2956    double f_out;
2957    double f_diff;
2958    int n_best = 0, d_best = 1, f_best = 0;
2959    double f_best_diff = 999999.0;
2960    double f_target = freq/1000.0;
2961
2962    for (f = 0; f <= MAX_F; f++)
2963	for (n = 0; n <= MAX_N; n++)
2964	    for (d = 1; d <= MAX_D; d++) {
2965		f_out = (n+1.0)/((d+1.0)*(1<<f))*REF_FREQ;
2966		f_diff = abs(f_out-f_target);
2967		if (f_diff < f_best_diff) {
2968		    f_best_diff = f_diff;
2969		    n_best = n;
2970		    d_best = d;
2971		    f_best = f;
2972		}
2973	    }
2974
2975    if (nPtr->NeoChipset == NM2200 || nPtr->NeoChipset == NM2230
2976	|| nPtr->NeoChipset == NM2360 || nPtr->NeoChipset == NM2380) {
2977        /* NOT_DONE:  We are trying the full range of the 2200 clock.
2978           We should be able to try n up to 2047 */
2979	nPtr->NeoModeReg.VCLK3NumeratorLow  = n_best;
2980	nPtr->NeoModeReg.VCLK3NumeratorHigh = (f_best << 7);
2981    }
2982    else {
2983	nPtr->NeoModeReg.VCLK3NumeratorLow  = n_best | (f_best << 7);
2984    }
2985    nPtr->NeoModeReg.VCLK3Denominator = d_best;
2986#ifdef DEBUG
2987    ErrorF("neoVCLK: f:%f NumLow=%i NumHi=%i Den=%i Df=%f\n",
2988	   f_target,
2989	   nPtr->NeoModeReg.VCLK3NumeratorLow,
2990	   nPtr->NeoModeReg.VCLK3NumeratorHigh,
2991	   nPtr->NeoModeReg.VCLK3Denominator,
2992	   f_best_diff);
2993#endif
2994}
2995
2996/*
2997 * NeoDisplayPowerManagementSet --
2998 *
2999 * Sets VESA Display Power Management Signaling (DPMS) Mode.
3000 */
3001static void
3002NeoDisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode,
3003			     int flags)
3004{
3005    NEOPtr nPtr = NEOPTR(pScrn);
3006    vgaHWPtr hwp = VGAHWPTR(pScrn);
3007    unsigned char SEQ01 = 0;
3008    unsigned char LogicPowerMgmt = 0;
3009    unsigned char LCD_on = 0;
3010
3011    if (!pScrn->vtSema)
3012	return;
3013
3014    switch (PowerManagementMode) {
3015    case DPMSModeOn:
3016	/* Screen: On; HSync: On, VSync: On */
3017	SEQ01 = 0x00;
3018	LogicPowerMgmt = 0x00;
3019	if (nPtr->internDisp || ! nPtr->externDisp)
3020	    LCD_on = 0x02;
3021	else
3022	    LCD_on = 0x00;
3023	break;
3024    case DPMSModeStandby:
3025	/* Screen: Off; HSync: Off, VSync: On */
3026	SEQ01 = 0x20;
3027	LogicPowerMgmt = 0x10;
3028	LCD_on = 0x00;
3029	break;
3030    case DPMSModeSuspend:
3031	/* Screen: Off; HSync: On, VSync: Off */
3032	SEQ01 = 0x20;
3033	LogicPowerMgmt = 0x20;
3034	LCD_on = 0x00;
3035	break;
3036    case DPMSModeOff:
3037	/* Screen: Off; HSync: Off, VSync: Off */
3038	SEQ01 = 0x20;
3039	LogicPowerMgmt = 0x30;
3040	LCD_on = 0x00;
3041	break;
3042    }
3043
3044    /* Turn the screen on/off */
3045    SEQ01 |= VGArSR(0x01) & ~0x20;
3046    VGAwSR(0x01, SEQ01);
3047
3048    /* Turn the LCD on/off */
3049    LCD_on |= VGArGR(0x20) & ~0x02;
3050    VGAwGR(0x20, LCD_on);
3051
3052    /* Set the DPMS mode */
3053    LogicPowerMgmt |= 0x80;
3054    LogicPowerMgmt |= VGArGR(0x01) & ~0xF0;
3055    VGAwGR(0x01,LogicPowerMgmt);
3056}
3057
3058static unsigned int
3059neo_ddc1Read(ScrnInfoPtr pScrn)
3060{
3061    register vgaHWPtr hwp = VGAHWPTR(pScrn);
3062    register unsigned int tmp;
3063
3064    /* This needs to be investigated: we may have to swap this around */
3065    while (!(hwp->readST01(hwp)&0x8)) {};
3066    while (hwp->readST01(hwp)&0x8) {};
3067
3068    tmp = (VGArGR(0xA1) & 0x08);
3069
3070    return (tmp);
3071}
3072
3073static xf86MonPtr
3074neo_ddc1(int scrnIndex)
3075{
3076    vgaHWPtr hwp = VGAHWPTR(xf86Screens[scrnIndex]);
3077    unsigned int reg1, reg2, reg3;
3078    xf86MonPtr ret;
3079
3080    /* initialize chipset */
3081    reg1 = VGArCR(0x21);
3082    reg2 = VGArCR(0x1D);
3083    reg3 = VGArCR(0xA1);
3084    VGAwCR(0x21,0x00);
3085    VGAwCR(0x1D,0x01);  /* some Voodoo */
3086    VGAwGR(0xA1,0x2F);
3087    ret =  xf86DoEDID_DDC1(scrnIndex,vgaHWddc1SetSpeedWeak(),neo_ddc1Read);
3088    /* undo initialization */
3089    VGAwCR(0x21,reg1);
3090    VGAwCR(0x1D,reg2);
3091    VGAwGR(0xA1,reg3);
3092    return ret;
3093}
3094
3095static Bool
3096neoDoDDC1(ScrnInfoPtr pScrn)
3097{
3098    Bool ret = FALSE;
3099    vgaHWPtr hwp = VGAHWPTR(pScrn);
3100
3101    VGAwGR(0x09,0x26);
3102    ret = xf86SetDDCproperties(pScrn,
3103				xf86PrintEDID(neo_ddc1(pScrn->scrnIndex)));
3104    VGAwGR(0x09,0x00);
3105
3106    return ret;
3107}
3108
3109static Bool
3110neoDoDDC2(ScrnInfoPtr pScrn)
3111{
3112    NEOPtr nPtr = NEOPTR(pScrn);
3113    vgaHWPtr hwp = VGAHWPTR(pScrn);
3114    Bool ret = FALSE;
3115
3116    VGAwGR(0x09,0x26);
3117    if (xf86LoadSubModule(pScrn, "i2c")) {
3118	if (neo_I2CInit(pScrn)) {
3119	    ret = xf86SetDDCproperties(pScrn,xf86PrintEDID(xf86DoEDID_DDC2(
3120					      pScrn->scrnIndex,nPtr->I2C)));
3121	}
3122    }
3123    VGAwGR(0x09,0x00);
3124
3125    return ret;
3126}
3127
3128static Bool
3129neoDoDDCVBE(ScrnInfoPtr pScrn)
3130{
3131    NEOPtr nPtr = NEOPTR(pScrn);
3132    vgaHWPtr hwp = VGAHWPTR(pScrn);
3133    vbeInfoPtr pVbe;
3134    Bool ret = FALSE;
3135
3136    VGAwGR(0x09,0x26);
3137    if (xf86LoadSubModule(pScrn, "vbe")) {
3138        if ((pVbe = VBEInit(NULL,nPtr->pEnt->index))) {
3139	  ret = xf86SetDDCproperties(
3140				     pScrn,xf86PrintEDID(vbeDoEDID(pVbe,NULL)));
3141	  vbeFree(pVbe);
3142	}
3143    }
3144    VGAwGR(0x09,0x00);
3145    return ret;
3146}
3147
3148static int
3149neoFindMode(int xres, int yres, int depth)
3150{
3151    int xres_s;
3152    int i, size;
3153    biosMode *mode;
3154
3155    switch (depth) {
3156    case 8:
3157	size = sizeof(bios8) / sizeof(biosMode);
3158	mode = bios8;
3159	break;
3160    case 15:
3161	size = sizeof(bios15) / sizeof(biosMode);
3162	mode = bios15;
3163	break;
3164    case 16:
3165	size = sizeof(bios16) / sizeof(biosMode);
3166	mode = bios16;
3167	break;
3168    case 24:
3169	size = sizeof(bios24) / sizeof(biosMode);
3170	mode = bios24;
3171	break;
3172    default:
3173	return 0;
3174    }
3175
3176    for (i = 0; i < size; i++) {
3177	if (xres <= mode[i].x_res) {
3178	    xres_s = mode[i].x_res;
3179	    for (; i < size; i++) {
3180		if (mode[i].x_res != xres_s)
3181		    return mode[i-1].mode;
3182		if (yres <= mode[i].y_res)
3183		    return mode[i].mode;
3184	    }
3185	}
3186    }
3187    return mode[size - 1].mode;
3188
3189}
3190
3191static void
3192neoProbeDDC(ScrnInfoPtr pScrn, int index)
3193{
3194    vbeInfoPtr pVbe;
3195
3196    if (xf86LoadSubModule(pScrn, "vbe")) {
3197        if ((pVbe = VBEInit(NULL,index))) {
3198	    ConfiguredMonitor = vbeDoEDID(pVbe, NULL);
3199	    vbeFree(pVbe);
3200	}
3201    }
3202}
3203