/* $XFree86: xc/programs/Xserver/hw/xfree86/vga256/drivers/ark/ark_driver.c,v 3.1 1995/05/27 03:15:03 dawes Exp $ */
/*
 * Copyright 1994  The XFree86 Project
 *
 * Permission is hereby granted, free of charge, to any person obtaining a 
 * copy of this software and associated documentation files (the "Software"), 
 * to deal in the Software without restriction, including without limitation 
 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 
 * and/or sell copies of the Software, and to permit persons to whom the 
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL 
 * DAVID WEXELBLAT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 
 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
 * SOFTWARE.
 * 
 * Written by Harm Hanemaayer (hhanemaa@cs.ruu.nl).
 */


/*
 * This is a driver for ARK Logic chips.
 * The following chips are supported:
 *
 *	- ARK1000PV (32-bit DRAM, PCI or VESA bus, 8-bit RAMDAC inteface)
 *	- ARK2000PV (64-bit DRAM, PCI or VESA bus, 16-bit RAMDAC interface)
 *
 *	The driver does not support the older ARK1000VL yet, althought it
 * 	may work if you let the driver think it is an ARK1000PV.
 *
 * This initial driver supports 8bpp only, the default max dotclock
 * is 80 MHz.
 *
 * The ARK chips use an external clock generator and RAMDAC. There
 * are 16 external clock frequencies, and for cards that are set up with
 * a set of useful fixed clocks, the driver should provide fairly
 * complete SVGA functionality. Cards that have a different type
 * of clock device will need specific support for that clock device,
 * although the standard VGA 25 MHz clock will be available yielding
 * 640x480x256.
 *
 * The driver will use linear addressing by default on both VESA-bus and
 * PCI. If this gives problems, banked operation can be selected with
 * the "nolinear" option in the Device section of the XF86Config file.
 *
 * With linear addressing enabled, 16bpp is supported given a
 * suitable RAMDAC and clock availability, as would 32bpp on the ARK2000PV.
 */

/*
 * Used registers:
 *
 * VGA Misc Output holds bits of 0-1 of the clock select index.
 * SR11 (Video Clock Select) bits 6-7 hold bits 2-3 of the clock
 *	select index.
 * SR1D bit 0 unlocks the extended registers.
 * SR10 bits 6-7 hold the amount of video memory.
 * CR50 bits 3-7 have the chip ID:
 *	0b10010 for ARK1000PV
 *	0b10011 for ARK2000PV
 * SR15 holds the Aperture Write Index (for banking).
 * SR16 holds the Aperture Read Index.
 * SR12 holds the aperture size in bits 0-1.
 * SR13 holds the low byte of the aperture base address (bits 16-23).
 * SR14 holds the high byte of the aperature base address (bits 24-31).
 * CR40 holds extended timing bits:
 *	Bit 3 holds bit 8 of the scanline offset.
 * SR11 bits 0-1 hold the Giant Shift Register mode,
 *	bits 2-3 hold the COP pixel size.
 * CR40 Extended horizontal CRTC timing bits.
 * CR41 Extended vertical CRTC timing bits.
 * CR42 Interlace retrace value.
 * CR44 VGA Enhancement bits:
 *	Bit 0 disabled RAMDAC access.
 *	Bit 2 sets interlaced CRTC timing.
 * SR18 holds the display FIFO size and threshold.
 * CR46 is the pixel clock control register:
 *	Bit 2 selects 16-bit output to RAMDAC (8-bit if zero).
 *	Bit 6 inverts the pixel clock.
 *	(Register is only used for ARK2000PV).
 * SR20-27, SR29, SR2A are hardware cursor registers.
 * SR28 and SR2B are hardware cursor registers on the ARK2000PV.
 */

/* The following defines the default max allowed raw clock frequency. */
#define ARK_DEFAULT_MAX_RAW_CLOCK_IN_KHZ	80000

/*
 * The following indicates whether high dot clocks 8bpp modes using
 * pixel multiplexing/RAMDAC clock doubling on a 16-bit RAMDAC
 * interface is supported. It cannot work currently because the SVGA
 * server can't handle required raw clocks that are half the pixel clock.
 */
 
/* #define ARK_8BPP_MULTIPLEXING_SUPPORTED */


/*
 * These are X and server generic header files.
 */
#include "X.h"
#include "input.h"
#include "screenint.h"

/*
 * These are XFree86-specific header files
 */
#include "compiler.h"
#include "xf86.h"
#include "xf86Priv.h"
#include "xf86_OSlib.h"
#include "xf86_HWlib.h"
#include "vga.h"

/*
 * If the driver makes use of XF86Config 'Option' flags, the following will be
 * required
 */
#define XCONFIG_FLAGS_ONLY
#include "xf86_Config.h"

#ifdef XF86VGA16
#define MONOVGA
#endif

#if !defined(MONOVGA) && !defined(XF86VGA16)
#include "vga256.h"
#endif

#include "ark_cursor.h"

extern vgaHWCursorRec vgaHWCursor;



/*
 * Driver data structures.
 */
typedef struct {
	/*
	 * This structure defines all of the register-level information
	 * that must be stored to define a video mode for this chipset.
	 * The 'vgaHWRec' member must be first, and contains all of the
	 * standard VGA register information, as well as saved text and
	 * font data.
	 */
	vgaHWRec std;               /* good old IBM VGA */
  	/* 
	 * Any other registers or other data that the new chipset needs
	 * to be saved should be defined here.  The Init/Save/Restore
	 * functions will manipulate theses fields.  Examples of things
	 * that would go here are registers that contain bank select
	 * registers, or extended clock select bits, or extensions to 
	 * the timing registers.  Use 'unsigned char' as the type for
	 * these registers.
	 */
	unsigned char SR10;
	unsigned char SR11;
	unsigned char SR12;
	unsigned char SR13;
	unsigned char SR14;
	unsigned char SR15;
	unsigned char SR16;
	unsigned char SR18;
	unsigned char SR20, SR21, SR22, SR23, SR24;	/* Hardware cursor. */
	unsigned char SR25, SR26, SR27, SR29, SR2A;
	unsigned char SR28, SR2B;
	unsigned char CR40;
	unsigned char CR41;
	unsigned char CR42;
	unsigned char CR44;
	unsigned char CR46;
	/* RAMDAC registers. */
	unsigned char DACCOMMAND;
	unsigned char STG17XX[3];	/* In addition to DACCOMMAND. */
} vgaArkRec, *vgaArkPtr;


/*
 * Forward definitions for the functions that make up the driver.  See
 * the definitions of these functions for the real scoop.
 */
static Bool     ArkProbe();
static char *   ArkIdent();
static Bool     ArkClockSelect();
static void     ArkEnterLeave();
static Bool     ArkInit();
static Bool	ArkValidMode();
static void *   ArkSave();
static void     ArkRestore();
static void     ArkAdjust();
static void	ArkFbInit();
/*
 * These are the bank select functions.  There are defined in stub_bank.s
 */
void     ArkSetRead();
void     ArkSetWrite();
void     ArkSetReadWrite();

/*
 * This data structure defines the driver itself.  The data structure is
 * initialized with the functions that make up the driver and some data 
 * that defines how the driver operates.
 */
vgaVideoChipRec ARK = {
	/* 
	 * Function pointers
	 */
	ArkProbe,
	ArkIdent,
	ArkEnterLeave,
	ArkInit,
	ArkValidMode,
	ArkSave,
	ArkRestore,
	ArkAdjust,
	vgaHWSaveScreen,
	(void (*)())NoopDDA,
	ArkFbInit,
	ArkSetRead,
	ArkSetWrite,
	ArkSetReadWrite,
	/*
	 * This is the size of the mapped memory window, usually 64k.
	 */
	0x10000,		
	/*
	 * This is the size of a video memory bank for this chipset.
	 */
	0x10000,
	/*
	 * This is the number of bits by which an address is shifted
	 * right to determine the bank number for that address.
	 */
	16,
	/*
	 * This is the bitmask used to determine the address within a
	 * specific bank.
	 */
	0xFFFF,
	/*
	 * These are the bottom and top addresses for reads inside a
	 * given bank.
	 */
	0x00000, 0x10000,
	/*
	 * And corresponding limits for writes.
	 */
	0x00000, 0x10000,
	/*
	 * Whether this chipset supports a single bank register or
	 * seperate read and write bank registers.
	 */
	TRUE,
	/*
	 * If the chipset requires vertical timing numbers to be divided
	 * by two for interlaced modes, set this to VGA_DIVIDE_VERT.
	 */
	VGA_DIVIDE_VERT,
	/*
	 * This is a dummy initialization for the set of option flags
	 * that this driver supports.  It gets filled in properly in the
	 * probe function, if the probe succeeds (assuming the driver
	 * supports any such flags).
	 */
	{0,},
	/*
	 * This determines the multiple to which the virtual width of
	 * the display must be rounded for the 256-color server.  This
	 * will normally be 8, but may be 4 or 16 for some servers.
	 */
	8,
	/*
	 * If the driver includes support for a linear-mapped frame buffer
	 * for the detected configuration this should be set to TRUE in the
	 * Probe or FbInit function.  In most cases it should be FALSE.
	 */
	FALSE,
	/*
	 * This is the physical base address of the linear-mapped frame
	 * buffer (when used).  Set it to 0 when not in use.
	 */
	0,
	/*
	 * This is the size  of the linear-mapped frame buffer (when used).
	 * Set it to 0 when not in use.
	 */
	0,
	/*
	 * This is TRUE if the driver has support for 16bpp for the detected
	 * configuration. It must be set in the Probe function.
	 * It most cases it should be FALSE.
	 */
	FALSE,
	/*
	 * This is TRUE if the driver has support for 32bpp for the detected
	 * configuration.
	 */
	FALSE,
	/*
	 * This is a pointer to a list of builtin driver modes.
	 * This is rarely used, and in must cases, set it to NULL
	 */
	NULL,
	/*
	 * This is a factor that can be used to scale the raw clocks
	 * to pixel clocks.  This is rarely used, and in most cases, set
	 * it to 1.
	 */
	1,
};

/*
 * This is a convenience macro, so that entries in the driver structure
 * can simply be dereferenced with 'new->xxx'.
 */
#define new ((vgaArkPtr)vgaNewVideoState)

/*
 * If your chipset uses non-standard I/O ports, you need to define an
 * array of ports, and an integer containing the array size.  The
 * generic VGA ports are defined in vgaHW.c.
 */
static unsigned Ark_ExtPorts[] = { 0x3CB, 0x400 };
static int Num_Ark_ExtPorts =
	(sizeof(Ark_ExtPorts)/sizeof(Ark_ExtPorts[0]));

#define VESA	0
#define PCI	1

static int arkChip, arkBus, arkRamdac;
static int arkDacPathWidth, arkMultiplexingThreshold;
static int arkUse8bitColorComponents;
static int arkDisplayableMemory;

#define ARK1000VL	0
#define ARK1000PV	1
#define ARK2000PV	2

static SymTabRec chipsets[] = {
	{ ARK1000VL,	"ark1000vl" },
	{ ARK1000PV,	"ark1000pv" },
	{ ARK2000PV,	"ark2000pv" },
	{ -1,		"" },
};

#define ATT490	0
#define ATT498	1
#define ZOOMDAC 2
#define STG1700 3

static SymTabRec ramdacs[] = {
	{ ATT490,	"att20c490" },	/* Industry-standard 8-bit DAC */
	{ ATT490,	"ark1491a" },
	{ ATT490,	"w30c491" },	/* IC Works */
	{ ATT498,	"att20c498" },	/* Industry-standard 16-bit DAC */
	{ ATT498,	"w30c498" },	/* IC Works */
	{ ZOOMDAC,	"w30c516" },	/* IC Works ZoomDac */
	{ ZOOMDAC,	"zoomdac" },
	{ STG1700,	"stg1700" },
	{ -1,		"" },
};


/*
 * ArkIdent --
 *
 * Returns the string name for supported chipset 'n'.  Most drivers only
 * support one chipset, but multiple version may require that the driver
 * identify them individually (e.g. the Trident driver).  The Ident function
 * should return a string if 'n' is valid, or NULL otherwise.  The
 * server will call this function when listing supported chipsets, with 'n' 
 * incrementing from 0, until the function returns NULL.  The 'Probe'
 * function should call this function to get the string name for a chipset
 * and when comparing against an XF86Config-supplied chipset value.  This
 * cuts down on the number of places errors can creep in.
 */
static char *
ArkIdent(n)
int n;
{
	if (chipsets[n].token < 0)
		return NULL;
	else
		return chipsets[n].name;
}


/*
 * ArkClockSelect --
 * 
 * This function selects the dot-clock with index 'no'.  In most cases
 * this is done my setting the correct bits in various registers (generic
 * VGA uses two bits in the Miscellaneous Output Register to select from
 * 4 clocks).  Care must be taken to protect any other bits in these
 * registers by fetching their values and masking off the other bits.
 *
 * This function returns FALSE if the passed index is invalid or if the
 * clock can't be set for some reason.
 */
static Bool
ArkClockSelect(no)
int no;
{
	static unsigned char save1, save2;
	unsigned char temp;

	switch(no)
	{
	case CLK_REG_SAVE:
		/*
		 * Here all of the registers that can be affected by
		 * clock setting should be saved into static variables.
		 */
		save1 = inb(0x3CC);
		save2 = rdinx(0x3C4, 0x11);
		break;
	case CLK_REG_RESTORE:
		/*
		 * Here all the previously saved registers are restored.
		 */
		outb(0x3C2, save1);
		modinx(0x3C4, 0x11, 0xC0, save2);
		break;
	default:
		/* 
	 	 * These are the generic two low-order bits of the clock select 
		 */
		temp = inb(0x3CC);
		outb(0x3C2, ( temp & 0xF3) | ((no << 2) & 0x0C));
		/* Two high bits. */
		modinx(0x3C4, 0x11, 0xC0, (no & 0xC) << 4);
	}
	return(TRUE);
}


/*
 * ArkProbe --
 *
 * This is the function that makes a yes/no decision about whether or not
 * a chipset supported by this driver is present or not.  The server will
 * call each driver's probe function in sequence, until one returns TRUE
 * or they all fail.
 *
 */
static Bool
ArkProbe()
{
	int maxclock8bpp, maxclock16bpp, maxclock32bpp;

	/*
	 * Set up I/O ports to be used by this card.  Only do the second
	 * xf86AddIOPorts() if there are non-standard ports for this
	 * chipset.
	 */
	xf86ClearIOPortList(vga256InfoRec.scrnIndex);
	xf86AddIOPorts(vga256InfoRec.scrnIndex, Num_VGA_IOPorts, VGA_IOPorts);
	xf86AddIOPorts(vga256InfoRec.scrnIndex, 
		       Num_Ark_ExtPorts, Ark_ExtPorts);

	/*
	 * First we attempt to figure out if one of the supported chipsets
	 * is present.
	 */
	if (vga256InfoRec.chipset)
	{
		/*
		 * This is the easy case.  The user has specified the
		 * chipset in the XF86Config file.  All we need to do here
		 * is a string comparison against each of the supported
		 * names available from the Ident() function.  If this
		 * driver supports more than one chipset, there would be
		 * nested conditionals here (see the Trident and WD drivers
		 * for examples).
		 */
		arkChip = xf86StringToToken(chipsets, vga256InfoRec.chipset);
		if (arkChip >= 0)
			ArkEnterLeave(ENTER);
		else
			return FALSE;
    	}
  	else
	{
		/*
		 * OK.  We have to actually test the hardware.  The
		 * EnterLeave() function (described below) unlocks access
		 * to registers that may be locked, and for OSs that require
		 * it, enables I/O access.  So we do this before we probe,
		 * even though we don't know for sure that this chipset
		 * is present.
		 */
		unsigned char CR50, id, rev;
		ArkEnterLeave(ENTER);

		/*
		 * Check for read/writability of all the "Software Scratch"
		 * registers.
		 */
		if (!testinx(0x3C4, 0x1E)
		|| !testinx(0x3C4, 0x1F)
		|| !testinx(0x3C4, 0x1A)
		|| !testinx(0x3C4, 0x1B)) {
			ArkEnterLeave(LEAVE);
			return FALSE;
		}

		CR50 = rdinx(vgaIOBase + 4, 0x50);
		id = CR50 >> 3;
		rev = CR50 & 7;

		switch (CR50 >> 3) {
		case 0x12 :
			arkChip = ARK1000PV;
			break;
		case 0x13 :
			arkChip = ARK2000PV;
			break;
		default :
			ErrorF("%s %s: ark: Unknown ARK chip (id = 0x%02X, rev = %d)\n",
				XCONFIG_PROBED, vga256InfoRec.name,
				id, rev);
			ArkEnterLeave(LEAVE);
			return FALSE;
		}
    	}

	vga256InfoRec.chipset = ArkIdent(arkChip);

	/*
	 * If the user has specified the amount of memory in the XF86Config
	 * file, we respect that setting.
	 */
  	if (!vga256InfoRec.videoRam)
    	{
		/*
		 * Otherwise, do whatever chipset-specific things are 
		 * necessary to figure out how much memory (in kBytes) is 
		 * available.
		 */
		unsigned char SR10;
		SR10 = rdinx(0x3C4, 0x10);
		if (arkChip == ARK1000PV)
			if ((SR10 & 0x40) == 0)
				vga256InfoRec.videoRam = 1024;
			else
				vga256InfoRec.videoRam = 2048;
		if (arkChip == ARK2000PV)
			if ((SR10 & 0xC0) == 0)
				vga256InfoRec.videoRam = 1024;
			else
			if ((SR10 & 0xC0) == 0x40)
				vga256InfoRec.videoRam = 2048;
			else
				vga256InfoRec.videoRam = 4096;
    	}

	if (rdinx(0x3C4, 0x19) & 0x80)
		arkBus = VESA;
	else
		arkBus = PCI;

	/*
	 * Again, if the user has specified the clock values in the XF86Config
	 * file, we respect those choices.
	 */
  	if (!vga256InfoRec.clocks)
    	{
		/*
		 * This utility function will probe for the clock values.
		 * It is passed the number of supported clocks, and a
		 * pointer to the clock-select function.
		 */
      		vgaGetClocks(16, ArkClockSelect);
    	}

	/*
	 * Parse the specified RAMDAC and determine sane maximum
	 * supported pixel clock limits. Unsupported depths will
	 * be ruled out out by a max dot clock of 0.
	 */
	arkRamdac = xf86StringToToken(ramdacs, vga256InfoRec.ramdac);
	maxclock8bpp = 0;
	maxclock16bpp = 0;
	maxclock32bpp = 0;
	arkDacPathWidth = 8;
	arkMultiplexingThreshold = 999999;
	arkUse8bitColorComponents = FALSE;
	if (vga256InfoRec.dacSpeed <= 0)
		vga256InfoRec.dacSpeed = 80000;
	switch (arkRamdac) {
	case ATT490 :	/* Industry-standard 8-bit DAC. */
		maxclock8bpp = vga256InfoRec.dacSpeed;
		maxclock16bpp = maxclock8bpp / 2;
		break;
	case ATT498 :	/* Industry-standard 16-bit DAC. */
	case STG1700 :	/* Same limits as 498. */
		/*
		 * Trust the DAC speed rating for 8bpp (use RAMDAC
		 * clock doubling for high clocks, 16-bit path).
		 */
#ifdef ARK_8BPP_MULTIPLEXING_SUPPORTED
		maxclock8bpp = vga256InfoRec.dacSpeed;
#else
		maxclock8bpp = ARK_DEFAULT_MAX_RAW_CLOCK_IN_KHZ;
#endif
		if (vga256InfoRec.dacSpeed >= 135000)
			maxclock16bpp = 110000;
		else	/* 110 MHz 8bpp rated */
			maxclock16bpp = 80000;
		maxclock32bpp = maxclock16bpp / 2;
		arkDacPathWidth = 16;
#ifdef ARK_8BPP_MULTIPLEXING_SUPPORTED
		arkMultiplexingThreshold = maxclock8bpp / 2;
#else
		arkMultiplexingThreshold = 999999;
#endif
		break;
	case ZOOMDAC :
		/*
		 * IC Works ZoomDAC, used on Hercules Stingray 64
		 * and Stingray Pro/V.
		 */
#ifdef ARK_8BPP_MULTIPLEXING_SUPPORTED
		maxclock8bpp = vga256InfoRec.dacSpeed;
#else
		maxclock8bpp = ARK_DEFAULT_MAX_RAW_CLOCK_IN_KHZ;
#endif
		if (arkChip == ARK1000PV) {
			/* Uses only 8-bit path to 16-bit RAMDAC. */
			if (vga256InfoRec.dacSpeed >= 135000)
				maxclock16bpp = 67500;
			else	/* 110 MHz rated. */
				maxclock16bpp = 55000;
			break;
		}
		/* ARK2000PV, 16-bit path to RAMDAC. */
		if (vga256InfoRec.dacSpeed >= 135000)
			maxclock16bpp = 135000;
		else	/* 110 MHz rated. */
			maxclock16bpp = 110000;
		maxclock32bpp = maxclock16bpp / 2;
		arkDacPathWidth = 16;
#ifdef ARK_8BPP_MULTIPLEXING_SUPPORTED
		arkMultiplexingThreshold = maxclock8bpp / 2;
#else
		arkMultiplexingThreshold = 999999;
#endif
		break;
	default :
		/* Unknown DAC. Only allow 8pp at conservative rate. */
		maxclock8bpp = ARK_DEFAULT_MAX_RAW_CLOCK_IN_KHZ;
		break;
	}
	/* Adjust max dot clocks according to chip PCLK limits. */
	if (arkChip == ARK1000PV) {
		if (maxclock8bpp > 120000)
			maxclock8bpp = 120000;
		if (maxclock16bpp > 60000)
			maxclock16bpp = 60000;
	}
	if (arkChip == ARK2000PV) {
		if (maxclock8bpp > 240000)
			maxclock8bpp = 240000;
		if (maxclock16bpp > 120000)
			maxclock16bpp = 120000;
		if (maxclock32bpp > 60000)
			maxclock32bpp = 60000;
	}
	/*
	 * It would be nice to know the memory clock to adjust
	 * the max clocks according to DRAM bandwidth. For now
	 * just interpret the "S3MClk" value if given in the
	 * XF86Config file.
	 */
	if (vga256InfoRec.s3MClk != 0) {
		int DRAM_bandwidth, bandwidth_limit;
		DRAM_bandwidth = vga256InfoRec.s3MClk * 2;
		if (arkChip == ARK2000PV && vga256InfoRec.videoRam >= 2048)
			/* 64-bit DRAM bus. */
			DRAM_bandwidth *= 2;
	         /*
	          * Calculate highest acceptable DRAM bandwidth in Mbytes/s
	          * to be taken up by screen refresh. Satisfies
	          *	total bandwidth >= refresh bandwidth * 1.1
	          */
		bandwidth_limit = (DRAM_bandwidth * 10) / 11;
		if (maxclock8bpp > bandwidth_limit)
			maxclock8bpp = bandwidth_limit;
		if (maxclock16bpp > bandwidth_limit / 2)
			maxclock16bpp = bandwidth_limit / 2;
		if (maxclock32bpp > bandwidth_limit / 4)
			maxclock32bpp = bandwidth_limit / 4;
	}
	/*
	 * Set the raw clock dividing factor. For 16bpp with an
	 * 8-bit DAC path, the raw clock is double the pixel clock.
	 * The same happens for 32bpp with a 16-bit DAC path.
	 */
 	if (arkChip == ARK1000PV || arkDacPathWidth == 8) {
		/* 8-bit RAMDAC path. */
		if (vgaBitsPerPixel == 16) {
			ARK.ChipClockScaleFactor = 2;
			maxclock16bpp *= 2;
		}
		if (vgaBitsPerPixel == 32) {
			/* Unlikely to happen (currently can't). */
			ARK.ChipClockScaleFactor = 4;
			maxclock32bpp *= 4;
		}
	}
	if (arkDacPathWidth == 16) {
		/* 16-bit RAMDAC path. */
		if (vgaBitsPerPixel == 32) {
			ARK.ChipClockScaleFactor = 2;
			maxclock32bpp *= 2;
		}
		/*
		 * A problem arises with "multiplexing" at 8bpp.
		 * The scaling factor would have to be 0.5, and
		 * it would only apply to certain modes. The current
		 * interface does not seem to be able to handle this.
		 */
	}
	if (vgaBitsPerPixel == 8)
		vga256InfoRec.maxClock = maxclock8bpp;
	if (vgaBitsPerPixel == 16)
		vga256InfoRec.maxClock = maxclock16bpp;
	if (vgaBitsPerPixel == 32)
		vga256InfoRec.maxClock = maxclock32bpp;

	/* Use linear addressing by default. */
	if (!OFLG_ISSET(OPTION_NOLINEAR_MODE, &vga256InfoRec.options)) {
		ARK.ChipUseLinearAddressing = TRUE;
		if (vga256InfoRec.MemBase != 0)
			ARK.ChipLinearBase =
				vga256InfoRec.MemBase;
		else
			if (arkBus == PCI)
				ARK.ChipLinearBase =
					(rdinx(0x3C4, 0x13) << 16) +
					(rdinx(0x3C4, 0x14) << 24);
			else
				/* VESA local bus. */
				/* Pray that 2048MB works. */
				ARK.ChipLinearBase = 0x80000000;
		ARK.ChipLinearSize = vga256InfoRec.videoRam * 1024;
		if (maxclock16bpp > 0)
			ARK.ChipHas16bpp = TRUE;
		if (arkChip == ARK2000PV && maxclock32bpp > 0)
			ARK.ChipHas32bpp = TRUE;
	}

	/*
	 * Last we fill in the remaining data structures.  We specify
	 * the chipset name, using the Ident() function and an appropriate
	 * index.  We set a boolean for whether or not this driver supports
	 * banking for the Monochrome server.  And we set up a list of all
	 * the option flags that this driver can make use of.
	 */
  	vga256InfoRec.bankedMono = FALSE;
 	OFLG_SET(OPTION_NOLINEAR_MODE, &ARK.ChipOptionFlags);
  	return TRUE;
}

/*
 * ArkFbInit --
 *      enable speedups for the chips that support it
 */
static void
ArkFbInit()
{
	int offscreen_available;

	if (xf86Verbose && ARK.ChipUseLinearAddressing)
		ErrorF("%s %s: %s: Using linear framebuffer at 0x%08X (%s)\n",
			XCONFIG_PROBED, vga256InfoRec.name,
			vga256InfoRec.chipset, ARK.ChipLinearBase,
			arkBus == PCI ? "PCI bus" : "VL bus");

	arkDisplayableMemory = vga256InfoRec.virtualX * vga256InfoRec.virtualY
		* (vgaBitsPerPixel / 8);
	offscreen_available = vga256InfoRec.videoRam * 1024 -
		arkDisplayableMemory;

	if (xf86Verbose)
		ErrorF("%s %s: %s: %d bytes off-screen video memory available\n",
			XCONFIG_PROBED, vga256InfoRec.name,
			vga256InfoRec.chipset, offscreen_available);
    
    	/*
    	 * Currently, the hardware cursor is not supported at 8bpp
    	 * due to a framebuffer code architecture issue.
    	 */
	if (!OFLG_ISSET(OPTION_SW_CURSOR, &vga256InfoRec.options)
	&& vgaBitsPerPixel != 8) {
		if (offscreen_available < 256)
			ErrorF("%s %s: %s: Not enough off-screen video memory for hardware cursor\n",
				XCONFIG_PROBED, vga256InfoRec.name,
				vga256InfoRec.chipset);
		else {
			/*
			 * OK, there's at least 256 bytes available
			 * at the end of video memory to store
			 * the cursor image, so we can use the hardware
			 * cursor.
			 */
			arkCursorWidth = 32;
			arkCursorHeight = 32;
			vgaHWCursor.Initialized = TRUE;
			vgaHWCursor.Init = ArkCursorInit;
			vgaHWCursor.Restore = ArkRestoreCursor;
			vgaHWCursor.Warp = ArkWarpCursor;
			vgaHWCursor.QueryBestSize = ArkQueryBestSize;
			if (xf86Verbose)
				ErrorF("%s %s: %s: Using hardware cursor\n",
					XCONFIG_PROBED, vga256InfoRec.name,
					vga256InfoRec.chipset);
		}
	}
}


/*
 * ArkEnterLeave --
 *
 * This function is called when the virtual terminal on which the server
 * is running is entered or left, as well as when the server starts up
 * and is shut down.  Its function is to obtain and relinquish I/O 
 * permissions for the SVGA device.  This includes unlocking access to
 * any registers that may be protected on the chipset, and locking those
 * registers again on exit.
 */
static void 
ArkEnterLeave(enter)
Bool enter;
{
	/*
	 * The value of the lock register is saved at the first
	 * "Enter" call, restored at a "Leave". This reduces the
	 * risk of messing up the registers of another chipset.
	 */
	static int enterCalled = FALSE;
	static int savedSR1D;
	unsigned char temp;

  	if (enter)
    	{
		xf86EnableIOPorts(vga256InfoRec.scrnIndex);

		/* 
		 * This is a global.  The CRTC base address depends on
		 * whether the VGA is functioning in color or mono mode.
		 * This is just a convenient place to initialize this
		 * variable.
		 */
      		vgaIOBase = (inb(0x3CC) & 0x01) ? 0x3D0 : 0x3B0;

		/*
		 * Here we deal with register-level access locks.  This
		 * is a generic VGA protection; most SVGA chipsets have
		 * similar register locks for their extended registers
		 * as well.
		 */
      		/* Unprotect CRTC[0-7] */
      		outb(vgaIOBase + 4, 0x11); temp = inb(vgaIOBase + 5);
      		outb(vgaIOBase + 5, temp & 0x7F);
      		if (enterCalled == FALSE) {
      			savedSR1D = rdinx(0x3C4, 0x1D);
      			enterCalled = TRUE;
      		}
      		/* Set bit 0 of SR1D. */
      		modinx(0x3C4, 0x1D, 0x01, 0x01);
    	}
  	else
    	{
		/*
		 * Here undo what was done above.
		 */

		/* Protect CRTC[0-7] */
		outb(vgaIOBase + 4, 0x11); temp = inb(vgaIOBase + 5);
		outb(vgaIOBase + 5, (temp & 0x7F) | 0x80);

		wrinx(0x3C4, 0x1D, savedSR1D);

		xf86DisableIOPorts(vga256InfoRec.scrnIndex);
	}
}

/*
 * ArkRestore --
 *
 * This function restores a video mode.  It basically writes out all of
 * the registers that have previously been saved in the vgaArkRec data 
 * structure.
 *
 * Note that "Restore" is a little bit incorrect.  This function is also
 * used when the server enters/changes video modes.  The mode definitions 
 * have previously been initialized by the Init() function, below.
 */
static void 
ArkRestore(restore)
vgaArkPtr restore;
{
	/*
	 * Whatever code is needed to get things back to bank zero should be
	 * placed here.  Things should be in the same state as when the
	 * Save/Init was done.
	 */

	/* Set Read and Write aperture index to 0. */
	wrinx(0x3C4, 0x15, 0x00);
	wrinx(0x3C4, 0x16, 0x00);

	/*
	 * Write the extended registers fist so that textmode font
	 * restoration can succeed.
	 */
	wrinx(0x3C4, 0x10, restore->SR10);
	if (restore->std.NoClock >= 0)
		wrinx(0x3C4, 0x11, restore->SR11);
	else
		/* Don't modify the clock select bits in SR11. */
		modinx(0x3C4, 0x11, 0x3F, restore->SR11);
	wrinx(0x3C4, 0x12, restore->SR12);
	wrinx(0x3C4, 0x13, restore->SR13);
	wrinx(0x3C4, 0x14, restore->SR14);

	wrinx(0x3C4, 0x15, restore->SR15);
	wrinx(0x3C4, 0x16, restore->SR16);
	wrinx(0x3C4, 0x18, restore->SR18);

	/* Hardware cursor registers. */
	wrinx(0x3C4, 0x20, restore->SR20);
	wrinx(0x3C4, 0x21, restore->SR21);
	wrinx(0x3C4, 0x22, restore->SR22);
	wrinx(0x3C4, 0x23, restore->SR23);
	wrinx(0x3C4, 0x24, restore->SR24);
	wrinx(0x3C4, 0x25, restore->SR25);
	wrinx(0x3C4, 0x26, restore->SR26);
	wrinx(0x3C4, 0x27, restore->SR27);
	wrinx(0x3C4, 0x29, restore->SR29);
	wrinx(0x3C4, 0x2A, restore->SR2A);
	if (arkChip == ARK2000PV) {
		wrinx(0x3C4, 0x28, restore->SR28);
		wrinx(0x3C4, 0x2B, restore->SR2B);
	}

 	wrinx(vgaIOBase + 4, 0x40, restore->CR40);
 	wrinx(vgaIOBase + 4, 0x41, restore->CR41);
 	wrinx(vgaIOBase + 4, 0x42, restore->CR42);
 	wrinx(vgaIOBase + 4, 0x44, restore->CR44);
 	if (arkChip == ARK2000PV)
	 	wrinx(vgaIOBase + 4, 0x46, restore->CR46);

	/* RAMDAC registers. */
	if (arkRamdac == ATT490 || arkRamdac == ATT498
	|| arkRamdac == ZOOMDAC || arkRamdac == STG1700)
		xf86setdaccomm(restore->DACCOMMAND);
	if (arkRamdac == STG1700) {
		xf86dactocomm();
		inb(0x3C6);		/* Skip command reg. */
		outb(0x3C6, 0x03);	/* Index low. */
		outb(0x3C6, 0x00);	/* Index high. */
		outb(0x3C6, restore->STG17XX[0]); /* Primary pixel mode. */
		outb(0x3C6, restore->STG17XX[1]); /* Secondary pixel mode. */
		outb(0x3C6, restore->STG17XX[2]); /* PLL control. */
		usleep(500);
		xf86dactopel();
	}

	/*
	 * This function handles restoring the generic VGA registers.
	 */
	vgaHWRestore((vgaHWPtr)restore);

}

/*
 * ArkSave --
 *
 * This function saves the video state.  It reads all of the SVGA registers
 * into the vgaArkRec data structure.  There is in general no need to
 * mask out bits here - just read the registers.
 */
static void *
ArkSave(save)
vgaArkPtr save;
{
	/*
	 * Whatever code is needed to get back to bank zero goes here.
	 */

	/* Set Read and Write aperture index to 0. */
	wrinx(0x3C4, 0x15, 0x00);
	wrinx(0x3C4, 0x16, 0x00);

	/*
	 * This function will handle creating the data structure and filling
	 * in the generic VGA portion.
	 */
	save = (vgaArkPtr)vgaHWSave((vgaHWPtr)save, sizeof(vgaArkRec));

	save->SR10 = rdinx(0x3C4, 0x10);
	save->SR11 = rdinx(0x3C4, 0x11);
	save->SR12 = rdinx(0x3C4, 0x12);
	save->SR13 = rdinx(0x3C4, 0x13);
	save->SR14 = rdinx(0x3C4, 0x14);
	save->SR15 = rdinx(0x3C4, 0x15);
	save->SR16 = rdinx(0x3C4, 0x16);
	save->SR18 = rdinx(0x3C4, 0x18);

	/* Hardware cursor registers. */
	save->SR20 = rdinx(0x3C4, 0x20);
	save->SR21 = rdinx(0x3C4, 0x21);
	save->SR22 = rdinx(0x3C4, 0x22);
	save->SR23 = rdinx(0x3C4, 0x23);
	save->SR24 = rdinx(0x3C4, 0x24);
	save->SR25 = rdinx(0x3C4, 0x25);
	save->SR26 = rdinx(0x3C4, 0x26);
	save->SR27 = rdinx(0x3C4, 0x27);
	save->SR29 = rdinx(0x3C4, 0x29);
	save->SR2A = rdinx(0x3C4, 0x2A);
	if (arkChip == ARK2000PV) {
		save->SR28 = rdinx(0x3C4, 0x28);
		save->SR2B = rdinx(0x3C4, 0x2B);
	}

	save->CR40 = rdinx(vgaIOBase + 4,  0x40);
	save->CR41 = rdinx(vgaIOBase + 4,  0x41);
	save->CR42 = rdinx(vgaIOBase + 4,  0x42);
	save->CR44 = rdinx(vgaIOBase + 4,  0x44);
 	if (arkChip == ARK2000PV)
		save->CR46 = rdinx(vgaIOBase + 4,  0x46);

	/* RAMDAC registers. */
	if (arkRamdac == ATT490 || arkRamdac == ATT498
	|| arkRamdac == ZOOMDAC || arkRamdac == STG1700)
		save->DACCOMMAND = xf86getdaccomm();
	if (arkRamdac == STG1700) {
		xf86dactocomm();
		inb(0x3C6);		/* Skip command reg. */
		outb(0x3C6, 0x03);	/* Index low. */
		outb(0x3C6, 0x00);	/* Index high. */
		save->STG17XX[0] = inb(0x3C6);	/* Primary pixel mode. */
		save->STG17XX[1] = inb(0x3C6);	/* Secondary pixel mode. */
		save->STG17XX[2] = inb(0x3C6);	/* PLL control. */
		xf86dactopel();
	}

  	return ((void *) save);
}

/*
 * ArkInit --
 *
 * This is the most important function (after the Probe) function.  This
 * function fills in the vgaArkRec with all of the register values needed
 * to enable either a 256-color mode (for the color server) or a 16-color
 * mode (for the monochrome server).
 *
 * The 'mode' parameter describes the video mode.  The 'mode' structure 
 * as well as the 'vga256InfoRec' structure can be dereferenced for
 * information that is needed to initialize the mode.  The 'new' macro
 * (see definition above) is used to simply fill in the structure.
 */
static Bool
ArkInit(mode)
DisplayModePtr mode;
{
	int multiplexing;

	/* 
	 * Determine if 8bpp clock doubling is to be used
	 * (two pixels sent over a 16-bit RAMDAC path each
	 * clock, with a raw clock half the pixel rate).
	 */
	multiplexing = 0;
	if (vgaBitsPerPixel == 8 && arkDacPathWidth == 16
	&& vga256InfoRec.clock[mode->Clock] > arkMultiplexingThreshold)
		multiplexing = 1;

	/*
	 * Scale the horizontal CRTC timings if required. This
	 * must be done before the VGA CRTC register values
	 * are initialized.
	 */
	if (ARK.ChipClockScaleFactor == 2)
		if (!mode->CrtcHAdjusted) {
			mode->CrtcHDisplay <<= 1;
			mode->CrtcHSyncStart <<= 1;
			mode->CrtcHSyncEnd <<= 1;
			mode->CrtcHTotal <<= 1;
			mode->CrtcHAdjusted = TRUE;
		}
	if (ARK.ChipClockScaleFactor == 4)
		if (!mode->CrtcHAdjusted) {
			mode->CrtcHDisplay <<= 2;
			mode->CrtcHSyncStart <<= 2;
			mode->CrtcHSyncEnd <<= 2;
			mode->CrtcHTotal <<= 2;
			mode->CrtcHAdjusted = TRUE;
		}
	if (multiplexing)
		/*
		 * This is linked to the fact that the
		 * ChipClockScaleFactor is (should be) equal to 0.5.
		 */
		if (!mode->CrtcHAdjusted) {
			mode->CrtcHDisplay >>= 1;
			mode->CrtcHSyncStart >>= 1;
			mode->CrtcHSyncEnd >>= 1;
			mode->CrtcHTotal >>= 1;
			mode->CrtcHAdjusted = TRUE;
		}

	/*
	 * This will allocate the datastructure and initialize all of the
	 * generic VGA registers.
	 */
	if (!vgaHWInit(mode,sizeof(vgaArkRec)))
		return(FALSE);

	/*
	 * Here all of the other fields of 'new' get filled in, to
	 * handle the SVGA extended registers.  It is also allowable
	 * to override generic registers whenever necessary.
	 *
	 */

	/*
	 * The ARK chips have a scale factor of 8 for the 
	 * scanline offset. There is one extended bit in addition
	 * to the 8 VGA bits. This results in a max logical scanline
	 * width of 4088 bytes.
	 */
	{
		int offset;
		offset = (vga256InfoRec.virtualX *
			vga256InfoRec.bitsPerPixel / 8)	>> 3;
		new->std.CRTC[0x13] = offset;
		/* Bit 8 resides at CR40 bit 3. */
		new->CR40 = rdinx(vgaIOBase, 0x40) & ~0x08;
		new->CR40 |= (offset & 0x100) >> 5;
	}

	/* Set Giant Shift Register for SVGA mode and set COP pixel depth. */
	new->SR11 = rdinx(0x3C4, 0x11) & ~0x0F;
	if (vga256InfoRec.bitsPerPixel == 8)
		new->SR11 |= 0x06;
	if (vga256InfoRec.bitsPerPixel == 16)
		new->SR11 |= 0x0A;
	if (vga256InfoRec.bitsPerPixel == 32)
		if (arkChip == ARK2000PV)
			new->SR11 |= 0x0E;
		else
			/*
			 * The AR1000PV can't accelerate 32bpp, but
			 * there may be a DAC that can skip the fourth
			 * byte of each pixel, making 640x400 possible
			 * with a raw clock of 100 MHz. So program
			 * the COP for 8bpp.
			 */
			new->SR11 |= 0x06;

	/*
	 * Enable VESA Super VGA memory organisation.
	 * Also enable Linear Addressing and COP.
	 * Linear addressing also seems to be required for banked
	 * operation.
	 */
	new->SR10 = rdinx(0x3C4, 0x10) & ~0x1F;
	new->SR10 |= 0x1F;
	if (ARK.ChipUseLinearAddressing) {
		/*
		 * Linear addressing; program the aperture base address
		 * bits 16-31.
		 */
		new->SR13 = ARK.ChipLinearBase >> 16; /* Bits 16-23. */
		new->SR14 = ARK.ChipLinearBase >> 24; /* Bits 24-31. */
		/* Program the aperture size. */
		new->SR12 = rdinx(0x3C4, 0x12) & ~0x03;
		if (ARK.ChipLinearSize == 1024 * 1024)
			new->SR12 |= 0x01;
		if (ARK.ChipLinearSize == 2048 * 1024)
			new->SR12 |= 0x02;
		if (ARK.ChipLinearSize == 4096 * 1024)
			new->SR12 |= 0x03;
	}
	else {
		/* Banking; Map aperture at 0xA0000. */
		new->SR13 = 0x0A;
		new->SR14 = 0x00;
		/* Set 64K aperture (set bits 0-1 of SR12 to 0). */
		new->SR12 = rdinx(0x3C4, 0x12) & ~0x03;
	}
	/* Set banking registers to zero. */
	new->SR15 = 0;
	new->SR16 = 0;


	/* Handle the CRTC overflow bits. */
	{
		unsigned char val;
		/* Vertical Overflow. */
		val = 0;
		if ((mode->CrtcVTotal - 2) & 0x400)
			val |= 0x80;
		if ((mode->CrtcVDisplay - 1) & 0x400)
			val |= 0x40;
		/* VBlankStart is equal to VSyncStart + 1. */
		if (mode->CrtcVSyncStart & 0x400)
			val |= 0x20;
		/* VRetraceStart is equal to VSyncStart + 1. */
		if (mode->CrtcVSyncStart & 0x400)
			val |= 0x10;
		new->CR40 = val;

		/* Horizontal Overflow. */
		val = rdinx(vgaIOBase + 4, 0x41);
		val &= 0x0F;
		/*
		 * Bit 3 (bit 9 of the scanline offset) was
		 * initialized earlier.
		 */
		if ((mode->CrtcHTotal / 8 - 5) & 0x100)
			val |= 0x80;
		if ((mode->CrtcHDisplay / 8 - 1) & 0x100)
			val |= 0x40;
		/* HBlankStart is equal to HSyncStart - 1. */
		if ((mode->CrtcHSyncStart / 8 - 1) & 0x100)
			val |= 0x20;
		/* HRetraceStart is equal to HSyncStart. */
		if ((mode->CrtcHSyncStart / 8) & 0x100)
			val |= 0x10;
		new->CR41 = val;
	}
	/* Set VGA Enhancement register. */
	/* No interlace, standard character clock. */
	new->CR44 = rdinx(vgaIOBase + 4, 0x44) & ~0x34;
	new->CR42 = 0;
	if (mode->Flags & V_INTERLACE) {
		/* Set mid-scan vertical retrace start. */
		new->CR42 = (mode->CrtcHTotal / 8 - 5) / 2;
		new->CR44 |= 0x04;	/* Interlaced flag. */
	}

	/* Set the display FIFO threshold. */
	{
		int threshold;
		unsigned char val;
		val = rdinx(0x3C4, 0x18);
		if (arkChip == ARK1000PV) {
			threshold = 4;	/* A guess. */
			val |= 0x08;	/* Enable full FIFO (8-deep). */
			val &= ~0x07;
			val |= threshold;
		}
		if (arkChip == ARK2000PV) {
			threshold = 12;	/* A guess. */
			val &= 0x40;
			val |= 0x10;	/* 32-deep FIFO. */
			val |= (threshold & 0x0E) >> 1;
			if (threshold & 0x01)
				val |= 0x80;
			if (threshold & 0x10)
				val |= 0x20;
		}
		new->SR18 = val;
	}

	/* Select 8 or 16-bit video output to RAMDAC on 2000PV. */
	if (arkChip == ARK2000PV) {
		int dac16;
		new->CR46 = rdinx(vgaIOBase + 4, 0x46) & ~0x04;	/* 8-bit */
		dac16 = 0;
		if (multiplexing)
			/* High resolution 8bpp with 16-bit DAC. */
			dac16 = 1;
		if (vga256InfoRec.bitsPerPixel == 16)
			/* 16bpp at pixel rate. */
			dac16 = 1;
		/* Note: with an 8-bit DAC, 16bpp is Clock * 2. */
		if (vga256InfoRec.bitsPerPixel == 32)
			/* 32bpp at Clock * 2. */
			dac16 = 1;
		if (arkDacPathWidth == 8)
			/* If an 8-bit DAC is used, forget it. */
			dac16 = 0;
		if (dac16)
			new->CR46 |= 0x04; /* 16-bit */
	}

	/*
	 * A special case - when using an external clock-setting program,
	 * this function must not change bits associated with the clock
	 * selection.  This condition can be checked by the condition:
	 *
	 *	if (new->std.NoClock >= 0)
	 *		initialize clock-select bits.
	 */

	if (new->std.NoClock >= 0) {
		/* Program clock select. */
		new->std.MiscOutReg &= ~0xC;
		new->std.MiscOutReg |= (new->std.NoClock & 3) << 2;
		/* The rest of SR11 was initialized earlier. */
		new->SR11 &= ~0xC0;
		new->SR11 |= (new->std.NoClock & 0xC) << 4;
	}

	/* Set up the RAMDAC registers. */

	if (arkRamdac == ATT490) {
		new->DACCOMMAND = 0x00;
		if (vgaBitsPerPixel == 16 && xf86weight.green == 5)
			/* 5-5-5 RGB. */
			new->DACCOMMAND = 0xA0;
		if (vgaBitsPerPixel == 16 && xf86weight.green == 6)
			/* 5-6-5 RGB. */
			new->DACCOMMAND = 0xC0;
	}
	if (arkRamdac == ATT498 || arkRamdac == ZOOMDAC) {
		new->DACCOMMAND = 0x00;
		if (vgaBitsPerPixel == 8 && multiplexing)
			new->DACCOMMAND = 0x20;
		if (vgaBitsPerPixel == 16 && arkDacPathWidth == 16)
			if (xf86weight.green == 5)
				new->DACCOMMAND = 0x10;
			else
				new->DACCOMMAND = 0x30;
		if (vgaBitsPerPixel == 16 && arkDacPathWidth == 8)
			/* Only 5-6-5 supported. */
			new->DACCOMMAND = 0x60;
		if (vgaBitsPerPixel == 32 && arkDacPathWidth == 16)
			new->DACCOMMAND = 0x50;
	}
	if (arkRamdac == STG1700) {
		/* This is adapted from accel/s3init.c. */
		int pixmode;
		new->DACCOMMAND = (xf86getdaccomm() & 0x06) | 0x10;
		new->STG17XX[2] = 0x00;	/* XXXX Guess. */
		pixmode = 0;
		if (vgaBitsPerPixel == 8 && multiplexing) {
			/* Enable extended modes. */
			new->DACCOMMAND |= 0x08;
			pixmode = 5;
			new->STG17XX[2] = 0x02;	/* 64-135 MHz pixclk. */
			/*
			 * XXXX What is the normal value for STG1700[2]
			 * (the PLL control register)? Assume it
			 * is zero (see above).
			 */
		}
		if (vgaBitsPerPixel == 16 && arkDacPathWidth == 16)
			if (xf86weight.green == 5) {
				new->DACCOMMAND |= 0xA8;
				pixmode = 0x02;
			}
			else {
				new->DACCOMMAND |= 0xC8;
				pixmode = 0x03;
			}
		if (vgaBitsPerPixel == 32 && arkDacPathWidth == 16) {
			new->DACCOMMAND = 0xE8;
			pixmode = 0x04;
		}
		new->STG17XX[0] = pixmode;	/* Primary pixel mode. */
		new->STG17XX[1] = pixmode;	/* Secondary pixel mode. */
	}
	if (arkRamdac == ATT490 || arkRamdac == ATT498
	|| arkRamdac == ZOOMDAC || arkRamdac == STG1700)
		if (vgaBitsPerPixel == 8 && arkUse8bitColorComponents)
			new->DACCOMMAND |= 0x02;
	if (vgaBitsPerPixel > 8)
		/* Get rid of white border. */
		new->std.Attribute[0x11] = 0x00;

	/*
	 * Hardware cursor registers.
	 * Generally the SVGA server will take care of enabling the
	 * cursor after a mode switch.
	 */
	new->SR20 = rdinx(0x3C4, 0x20);
	new->SR21 = rdinx(0x3C4, 0x21);
	new->SR22 = rdinx(0x3C4, 0x22);
	new->SR23 = rdinx(0x3C4, 0x23);
	new->SR24 = rdinx(0x3C4, 0x24);
	new->SR25 = rdinx(0x3C4, 0x25);
	new->SR26 = rdinx(0x3C4, 0x26);
	new->SR27 = rdinx(0x3C4, 0x27);
	new->SR29 = rdinx(0x3C4, 0x29);
	new->SR2A = rdinx(0x3C4, 0x2A);
	if (arkChip == ARK2000PV) {
		new->SR28 = rdinx(0x3C4, 0x28);
		new->SR2B = rdinx(0x3C4, 0x2B);
	}

	return TRUE;
}

/*
 * ArkAdjust --
 *
 * This function is used to initialize the SVGA Start Address - the first
 * displayed location in the video memory.  This is used to implement the
 * virtual window.
 */
static void 
ArkAdjust(x, y)
int x, y;
{
	int Base = ((y * vga256InfoRec.displayWidth + x)
		* (vgaBitsPerPixel / 8)) >> 2;

	/*
	 * These are the generic starting address registers.
	 */
	outw(vgaIOBase + 4, (Base & 0x00FF00) | 0x0C);
  	outw(vgaIOBase + 4, ((Base & 0x00FF) << 8) | 0x0D);

	/*
	 * Here the high-order bits are masked and shifted, and put into
	 * the appropriate extended registers.
	 */
	modinx(vgaIOBase + 4, 0x40, 0x07, (Base & 0x070000) >> 16);
}

/*
 * ArkValidMode --
 *
 */
static Bool
ArkValidMode(mode)
DisplayModePtr mode;
{
	/* Check for CRTC timing bits overflow. */
	if (mode->HTotal > 4088) {
		ErrorF("%s %s: %s: Horizontal mode timing overflow (%d)\n",
			XCONFIG_PROBED, vga256InfoRec.name,
			vga256InfoRec.chipset, mode->HTotal);
		return FALSE;
	}
	if (mode->VTotal > 2047) {
		ErrorF("%s %s: %s: Vertical mode timing overflow (%d)\n",
			XCONFIG_PROBED, vga256InfoRec.name,
			vga256InfoRec.chipset, mode->VTotal);
		return FALSE;
	}

	return TRUE;
}
