tseng_driver.c revision d983712d
1d983712dSmrg/*
2d983712dSmrg * $XFree86: xc/programs/Xserver/hw/xfree86/drivers/tseng/tseng_driver.c,v 1.97tsi Exp $
3d983712dSmrg *
4d983712dSmrg * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
5d983712dSmrg *
6d983712dSmrg * Permission to use, copy, modify, distribute, and sell this software and its
7d983712dSmrg * documentation for any purpose is hereby granted without fee, provided that
8d983712dSmrg * the above copyright notice appear in all copies and that both that
9d983712dSmrg * copyright notice and this permission notice appear in supporting
10d983712dSmrg * documentation, and that the name of Thomas Roell not be used in
11d983712dSmrg * advertising or publicity pertaining to distribution of the software without
12d983712dSmrg * specific, written prior permission.  Thomas Roell makes no representations
13d983712dSmrg * about the suitability of this software for any purpose.  It is provided
14d983712dSmrg * "as is" without express or implied warranty.
15d983712dSmrg *
16d983712dSmrg * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17d983712dSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18d983712dSmrg * EVENT SHALL THOMAS ROELL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19d983712dSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20d983712dSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21d983712dSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22d983712dSmrg * PERFORMANCE OF THIS SOFTWARE.
23d983712dSmrg *
24d983712dSmrg * Author:  Thomas Roell, roell@informatik.tu-muenchen.de
25d983712dSmrg *          ET6000 and ET4000W32 16/24/32 bpp and acceleration support by Koen Gadeyne
26d983712dSmrg *
27d983712dSmrg * Large parts rewritten for XFree86 4.0 by Koen Gadeyne.
28d983712dSmrg */
29d983712dSmrg/* $XConsortium: et4_driver.c /main/27 1996/10/28 04:48:15 kaleb $ */
30d983712dSmrg
31d983712dSmrg#ifdef HAVE_CONFIG_H
32d983712dSmrg#include "config.h"
33d983712dSmrg#endif
34d983712dSmrg
35d983712dSmrg/*** Generic includes ***/
36d983712dSmrg
37d983712dSmrg#include "tseng.h"		       /* this includes most of the generic ones as well */
38d983712dSmrg
39d983712dSmrg/* All drivers initialising the SW cursor need this */
40d983712dSmrg#include "mipointer.h"
41d983712dSmrg
42d983712dSmrg/* All drivers implementing backing store need this */
43d983712dSmrg#include "mibstore.h"
44d983712dSmrg
45d983712dSmrg#include "fb.h"
46d983712dSmrg
47d983712dSmrg#include "xf86RAC.h"
48d983712dSmrg#include "xf86Resources.h"
49d983712dSmrg#include "xf86int10.h"
50d983712dSmrg
51d983712dSmrg#include "xf86xv.h"
52d983712dSmrg#include <X11/extensions/Xv.h>
53d983712dSmrg
54d983712dSmrg/*
55d983712dSmrg * Forward definitions for the functions that make up the driver.
56d983712dSmrg */
57d983712dSmrg
58d983712dSmrg/* Mandatory functions */
59d983712dSmrgstatic const OptionInfoRec * TsengAvailableOptions(int chipid, int busid);
60d983712dSmrgstatic void TsengIdentify(int flags);
61d983712dSmrgstatic Bool TsengProbe(DriverPtr drv, int flags);
62d983712dSmrgstatic Bool TsengPreInit(ScrnInfoPtr pScrn, int flags);
63d983712dSmrgstatic Bool TsengScreenInit(int Index, ScreenPtr pScreen, int argc,
64d983712dSmrg    char **argv);
65d983712dSmrgstatic Bool TsengEnterVT(int scrnIndex, int flags);
66d983712dSmrgstatic void TsengLeaveVT(int scrnIndex, int flags);
67d983712dSmrgstatic Bool TsengCloseScreen(int scrnIndex, ScreenPtr pScreen);
68d983712dSmrgstatic Bool TsengSaveScreen(ScreenPtr pScreen, int mode);
69d983712dSmrg
70d983712dSmrg/* Required if the driver supports mode switching */
71d983712dSmrgstatic Bool TsengSwitchMode(int scrnIndex, DisplayModePtr mode, int flags);
72d983712dSmrg
73d983712dSmrg/* Optional functions */
74d983712dSmrgstatic void TsengFreeScreen(int scrnIndex, int flags);
75d983712dSmrg
76d983712dSmrg/* If driver-specific config file entries are needed, this must be defined */
77d983712dSmrg/*static Bool   TsengParseConfig(ParseInfoPtr raw); */
78d983712dSmrg
79d983712dSmrg/* Internally used functions (some are defined in tseng.h) */
80d983712dSmrgstatic Bool TsengMapMem(ScrnInfoPtr pScrn);
81d983712dSmrgstatic Bool TsengUnmapMem(ScrnInfoPtr pScrn);
82d983712dSmrgstatic void TsengUnlock(ScrnInfoPtr pScrn);
83d983712dSmrgstatic void TsengLock(ScrnInfoPtr pScrn);
84d983712dSmrg
85d983712dSmrg/*
86d983712dSmrg * This is intentionally screen-independent.  It indicates the binding
87d983712dSmrg * choice made in the first PreInit.
88d983712dSmrg */
89d983712dSmrgstatic int pix24bpp = 0;
90d983712dSmrg
91d983712dSmrg#define TSENG_NAME "TSENG"
92d983712dSmrg#define TSENG_DRIVER_NAME "tseng"
93d983712dSmrg#define TSENG_MAJOR_VERSION 1
94d983712dSmrg#define TSENG_MINOR_VERSION 1
95d983712dSmrg#define TSENG_PATCHLEVEL 0
96d983712dSmrg#define TSENG_VERSION (TSENG_MAJOR_VERSION << 24) | (TSENG_MINOR_VERSION << 16) | TSENG_PATCHLEVEL
97d983712dSmrg
98d983712dSmrg/* CRTC timing limits */
99d983712dSmrg#define Tseng_HMAX (4096-8)
100d983712dSmrg#define Tseng_VMAX (2048-1)
101d983712dSmrg
102d983712dSmrg/*
103d983712dSmrg * This contains the functions needed by the server after loading the
104d983712dSmrg * driver module.  It must be supplied, and gets added the driver list by
105d983712dSmrg * the Module Setup funtion in the dynamic case.  In the static case a
106d983712dSmrg * reference to this is compiled in, and this requires that the name of
107d983712dSmrg * this DriverRec be an upper-case version of the driver name.
108d983712dSmrg */
109d983712dSmrg
110d983712dSmrg_X_EXPORT DriverRec TSENG =
111d983712dSmrg{
112d983712dSmrg    TSENG_VERSION,
113d983712dSmrg    TSENG_DRIVER_NAME,
114d983712dSmrg    TsengIdentify,
115d983712dSmrg    TsengProbe,
116d983712dSmrg    TsengAvailableOptions,
117d983712dSmrg    NULL,
118d983712dSmrg    0
119d983712dSmrg};
120d983712dSmrg
121d983712dSmrg/* sub-revisions are now dealt with in the ChipRev variable */
122d983712dSmrgstatic SymTabRec TsengChipsets[] =
123d983712dSmrg{
124d983712dSmrg    {ET4000, "ET4000W32p"},
125d983712dSmrg    {ET6000, "ET6000"},
126d983712dSmrg    {-1, NULL}
127d983712dSmrg};
128d983712dSmrg
129d983712dSmrg/* Convert PCI ID to chipset name */
130d983712dSmrgstatic PciChipsets TsengPciChipsets[] =
131d983712dSmrg{
132d983712dSmrg    {ET4000, PCI_CHIP_ET4000_W32P_A, RES_SHARED_VGA},
133d983712dSmrg    {ET4000, PCI_CHIP_ET4000_W32P_B, RES_SHARED_VGA},
134d983712dSmrg    {ET4000, PCI_CHIP_ET4000_W32P_C, RES_SHARED_VGA},
135d983712dSmrg    {ET4000, PCI_CHIP_ET4000_W32P_D, RES_SHARED_VGA},
136d983712dSmrg    {ET6000, PCI_CHIP_ET6000,        RES_SHARED_VGA},
137d983712dSmrg    {-1,     -1,                     RES_UNDEFINED}
138d983712dSmrg};
139d983712dSmrg
140d983712dSmrgtypedef enum {
141d983712dSmrg    OPTION_HIBIT_HIGH,
142d983712dSmrg    OPTION_HIBIT_LOW,
143d983712dSmrg    OPTION_SW_CURSOR,
144d983712dSmrg    OPTION_HW_CURSOR,
145d983712dSmrg    OPTION_PCI_BURST,
146d983712dSmrg    OPTION_SLOW_DRAM,
147d983712dSmrg    OPTION_MED_DRAM,
148d983712dSmrg    OPTION_FAST_DRAM,
149d983712dSmrg    OPTION_W32_INTERLEAVE,
150d983712dSmrg    OPTION_NOACCEL,
151d983712dSmrg    OPTION_SHOWCACHE,
152d983712dSmrg    OPTION_PCI_RETRY
153d983712dSmrg} TsengOpts;
154d983712dSmrg
155d983712dSmrgstatic const OptionInfoRec TsengOptions[] =
156d983712dSmrg{
157d983712dSmrg    {OPTION_HIBIT_HIGH, "hibit_high", OPTV_BOOLEAN,
158d983712dSmrg	{0}, FALSE},
159d983712dSmrg    {OPTION_HIBIT_LOW, "hibit_low", OPTV_BOOLEAN,
160d983712dSmrg	{0}, FALSE},
161d983712dSmrg    {OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN,
162d983712dSmrg	{0}, FALSE},
163d983712dSmrg    {OPTION_HW_CURSOR, "HWcursor", OPTV_BOOLEAN,
164d983712dSmrg	{0}, FALSE},
165d983712dSmrg    {OPTION_PCI_BURST, "pci_burst", OPTV_BOOLEAN,
166d983712dSmrg	{0}, FALSE},
167d983712dSmrg    {OPTION_SLOW_DRAM, "slow_dram", OPTV_BOOLEAN,
168d983712dSmrg	{0}, FALSE},
169d983712dSmrg    {OPTION_MED_DRAM, "med_dram", OPTV_BOOLEAN,
170d983712dSmrg	{0}, FALSE},
171d983712dSmrg    {OPTION_FAST_DRAM, "fast_dram", OPTV_BOOLEAN,
172d983712dSmrg	{0}, FALSE},
173d983712dSmrg    {OPTION_W32_INTERLEAVE, "w32_interleave", OPTV_BOOLEAN,
174d983712dSmrg	{0}, FALSE},
175d983712dSmrg    {OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN,
176d983712dSmrg	{0}, FALSE},
177d983712dSmrg    {OPTION_SHOWCACHE, "ShowCache", OPTV_BOOLEAN,
178d983712dSmrg	{0}, FALSE},
179d983712dSmrg    {OPTION_PCI_RETRY, "PciRetry", OPTV_BOOLEAN,
180d983712dSmrg	{0}, FALSE},
181d983712dSmrg    {-1, NULL, OPTV_NONE,
182d983712dSmrg	{0}, FALSE}
183d983712dSmrg};
184d983712dSmrg
185d983712dSmrgstatic const char *int10Symbols[] = {
186d983712dSmrg    "xf86FreeInt10",
187d983712dSmrg    "xf86InitInt10",
188d983712dSmrg    NULL
189d983712dSmrg};
190d983712dSmrg
191d983712dSmrgstatic const char *vgaHWSymbols[] = {
192d983712dSmrg  "vgaHWFreeHWRec",
193d983712dSmrg  "vgaHWGetHWRec",
194d983712dSmrg  "vgaHWGetIOBase",
195d983712dSmrg  "vgaHWGetIndex",
196d983712dSmrg  "vgaHWHandleColormaps",
197d983712dSmrg  "vgaHWInit",
198d983712dSmrg  "vgaHWLock",
199d983712dSmrg  "vgaHWMapMem",
200d983712dSmrg  "vgaHWProtect",
201d983712dSmrg  "vgaHWRestore",
202d983712dSmrg  "vgaHWSave",
203d983712dSmrg  "vgaHWSaveScreen",
204d983712dSmrg  "vgaHWUnlock",
205d983712dSmrg  "vgaHWUnmapMem",
206d983712dSmrg  NULL
207d983712dSmrg};
208d983712dSmrg
209d983712dSmrg#ifdef XFree86LOADER
210d983712dSmrgstatic const char* miscfbSymbols[] = {
211d983712dSmrg  "xf1bppScreenInit",
212d983712dSmrg  "xf4bppScreenInit",
213d983712dSmrg  NULL
214d983712dSmrg};
215d983712dSmrg#endif
216d983712dSmrg
217d983712dSmrgstatic const char* fbSymbols[] = {
218d983712dSmrg  "fbPictureInit",
219d983712dSmrg  "fbScreenInit",
220d983712dSmrg  NULL
221d983712dSmrg};
222d983712dSmrg
223d983712dSmrgstatic const char *ramdacSymbols[] = {
224d983712dSmrg    "xf86CreateCursorInfoRec",
225d983712dSmrg    "xf86DestroyCursorInfoRec",
226d983712dSmrg    "xf86InitCursor",
227d983712dSmrg    NULL
228d983712dSmrg};
229d983712dSmrg
230d983712dSmrgstatic const char *xaaSymbols[] = {
231d983712dSmrg    "XAACreateInfoRec",
232d983712dSmrg    "XAADestroyInfoRec",
233d983712dSmrg    "XAAInit",
234d983712dSmrg    NULL
235d983712dSmrg};
236d983712dSmrg
237d983712dSmrg#ifdef XFree86LOADER
238d983712dSmrg
239d983712dSmrgstatic MODULESETUPPROTO(tsengSetup);
240d983712dSmrg
241d983712dSmrgstatic XF86ModuleVersionInfo tsengVersRec =
242d983712dSmrg{
243d983712dSmrg    "tseng",
244d983712dSmrg    MODULEVENDORSTRING,
245d983712dSmrg    MODINFOSTRING1,
246d983712dSmrg    MODINFOSTRING2,
247d983712dSmrg    XORG_VERSION_CURRENT,
248d983712dSmrg    TSENG_MAJOR_VERSION, TSENG_MINOR_VERSION, TSENG_PATCHLEVEL,
249d983712dSmrg    ABI_CLASS_VIDEODRV,		       /* This is a video driver */
250d983712dSmrg    ABI_VIDEODRV_VERSION,
251d983712dSmrg    MOD_CLASS_VIDEODRV,
252d983712dSmrg    {0, 0, 0, 0}
253d983712dSmrg};
254d983712dSmrg
255d983712dSmrg/*
256d983712dSmrg * This is the module init data for XFree86 modules.
257d983712dSmrg *
258d983712dSmrg * Its name has to be the driver name followed by ModuleData.
259d983712dSmrg */
260d983712dSmrg_X_EXPORT XF86ModuleData tsengModuleData = { &tsengVersRec, tsengSetup, NULL };
261d983712dSmrg
262d983712dSmrgstatic pointer
263d983712dSmrgtsengSetup(pointer module, pointer opts, int *errmaj, int *errmin)
264d983712dSmrg{
265d983712dSmrg    static Bool setupDone = FALSE;
266d983712dSmrg
267d983712dSmrg    if (!setupDone) {
268d983712dSmrg	setupDone = TRUE;
269d983712dSmrg	xf86AddDriver(&TSENG, module, 0);
270d983712dSmrg
271d983712dSmrg	/*
272d983712dSmrg	 * Modules that this driver always requires can be loaded here
273d983712dSmrg	 * by calling LoadSubModule().
274d983712dSmrg	 */
275d983712dSmrg	/*
276d983712dSmrg	 * Tell the loader about symbols from other modules that this module
277d983712dSmrg	 * might refer to.
278d983712dSmrg	 */
279d983712dSmrg	LoaderRefSymLists(vgaHWSymbols, miscfbSymbols, fbSymbols, xaaSymbols,
280d983712dSmrg			  int10Symbols, ramdacSymbols,  NULL);
281d983712dSmrg
282d983712dSmrg	/*
283d983712dSmrg	 * The return value must be non-NULL on success even though there
284d983712dSmrg	 * is no TearDownProc.
285d983712dSmrg	 */
286d983712dSmrg	return (pointer) 1;
287d983712dSmrg    } else {
288d983712dSmrg	if (errmaj)
289d983712dSmrg	    *errmaj = LDR_ONCEONLY;
290d983712dSmrg	return NULL;
291d983712dSmrg    }
292d983712dSmrg}
293d983712dSmrg
294d983712dSmrg#endif /* XFree86LOADER */
295d983712dSmrg
296d983712dSmrgstatic Bool
297d983712dSmrgTsengGetRec(ScrnInfoPtr pScrn)
298d983712dSmrg{
299d983712dSmrg    TsengPtr pTseng;
300d983712dSmrg
301d983712dSmrg    PDEBUG("	TsengGetRec\n");
302d983712dSmrg
303d983712dSmrg    /*
304d983712dSmrg     * Allocate an TsengRec, and hook it into pScrn->driverPrivate.
305d983712dSmrg     * pScrn->driverPrivate is initialised to NULL, so we can check if
306d983712dSmrg     * the allocation has already been done.
307d983712dSmrg     */
308d983712dSmrg    if (pScrn->driverPrivate != NULL)
309d983712dSmrg	return TRUE;
310d983712dSmrg
311d983712dSmrg    pScrn->driverPrivate = xnfcalloc(sizeof(TsengRec), 1);
312d983712dSmrg
313d983712dSmrg
314d983712dSmrg    /* Initialise it here when needed (or possible) */
315d983712dSmrg    pTseng = TsengPTR(pScrn);
316d983712dSmrg
317d983712dSmrg    pTseng->SavedReg.RAMDAC = NULL;
318d983712dSmrg
319d983712dSmrg    return TRUE;
320d983712dSmrg}
321d983712dSmrg
322d983712dSmrgstatic void
323d983712dSmrgTsengFreeRec(ScrnInfoPtr pScrn)
324d983712dSmrg{
325d983712dSmrg    TsengPtr pTseng;
326d983712dSmrg
327d983712dSmrg    PDEBUG("	TsengFreeRec\n");
328d983712dSmrg
329d983712dSmrg    if (pScrn->driverPrivate == NULL)
330d983712dSmrg	return;
331d983712dSmrg
332d983712dSmrg    pTseng = TsengPTR(pScrn);
333d983712dSmrg
334d983712dSmrg    if (pTseng->SavedReg.RAMDAC)
335d983712dSmrg        xfree(pTseng->SavedReg.RAMDAC);
336d983712dSmrg
337d983712dSmrg    xfree(pScrn->driverPrivate);
338d983712dSmrg    pScrn->driverPrivate = NULL;
339d983712dSmrg}
340d983712dSmrg
341d983712dSmrgstatic const OptionInfoRec *
342d983712dSmrgTsengAvailableOptions(int chipid, int busid)
343d983712dSmrg{
344d983712dSmrg    return TsengOptions;
345d983712dSmrg}
346d983712dSmrg
347d983712dSmrgstatic void
348d983712dSmrgTsengIdentify(int flags)
349d983712dSmrg{
350d983712dSmrg    xf86Msg(X_INFO, TSENG_NAME ": driver for TsengLabs ET4000W32p, ET6000 and"
351d983712dSmrg            " ET6100 chips.\n");
352d983712dSmrg}
353d983712dSmrg
354d983712dSmrg/* unlock ET4000 using KEY register */
355d983712dSmrgstatic void
356d983712dSmrgTsengUnlock(ScrnInfoPtr pScrn)
357d983712dSmrg{
358d983712dSmrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
359d983712dSmrg    CARD8 tmp;
360d983712dSmrg
361d983712dSmrg    PDEBUG("	TsengUnlock\n");
362d983712dSmrg
363d983712dSmrg    vgaHWHerculesSecondPage(hwp, TRUE);
364d983712dSmrg    vgaHWWriteModeControl(hwp, 0xA0);
365d983712dSmrg
366d983712dSmrg    tmp = hwp->readCrtc(hwp, 0x11);
367d983712dSmrg    hwp->writeCrtc(hwp, 0x11, tmp & 0x7F);
368d983712dSmrg}
369d983712dSmrg
370d983712dSmrg/* lock ET4000 using KEY register. FIXME: should restore old lock status instead */
371d983712dSmrgstatic void
372d983712dSmrgTsengLock(ScrnInfoPtr pScrn)
373d983712dSmrg{
374d983712dSmrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
375d983712dSmrg    CARD8 tmp;
376d983712dSmrg
377d983712dSmrg    PDEBUG("	TsengLock\n");
378d983712dSmrg
379d983712dSmrg    tmp = hwp->readCrtc(hwp, 0x11);
380d983712dSmrg    hwp->writeCrtc(hwp, 0x11, tmp | 0x80);
381d983712dSmrg
382d983712dSmrg    vgaHWWriteModeControl(hwp, 0x00);
383d983712dSmrg    vgaHWWriteModeControl(hwp, 0x29);
384d983712dSmrg    vgaHWHerculesSecondPage(hwp, FALSE);
385d983712dSmrg}
386d983712dSmrg
387d983712dSmrgstatic Bool
388d983712dSmrgTsengProbe(DriverPtr drv, int flags)
389d983712dSmrg{
390d983712dSmrg    int i;
391d983712dSmrg    GDevPtr *devSections;
392d983712dSmrg    int numDevSections;
393d983712dSmrg    int numUsed;
394d983712dSmrg    int *usedChips = NULL;
395d983712dSmrg    Bool foundScreen = FALSE;
396d983712dSmrg
397d983712dSmrg
398d983712dSmrg    PDEBUG("	TsengProbe\n");
399d983712dSmrg    /*
400d983712dSmrg     * The aim here is to find all cards that this driver can handle,
401d983712dSmrg     * and for the ones not already claimed by another driver, claim the
402d983712dSmrg     * slot, and allocate a ScrnInfoRec.
403d983712dSmrg     *
404d983712dSmrg     * This should be a minimal probe, and it should under no circumstances
405d983712dSmrg     * change the state of the hardware.  Because a device is found, don't
406d983712dSmrg     * assume that it will be used.  Don't do any initialisations other than
407d983712dSmrg     * the required ScrnInfoRec initialisations.  Don't allocate any new
408d983712dSmrg     * data structures.
409d983712dSmrg     */
410d983712dSmrg
411d983712dSmrg    /*
412d983712dSmrg     * Find the config file Device sections that match this
413d983712dSmrg     * driver, and return if there are none.
414d983712dSmrg     */
415d983712dSmrg    if ((numDevSections = xf86MatchDevice(TSENG_DRIVER_NAME,
416d983712dSmrg		&devSections)) <= 0) {
417d983712dSmrg	return FALSE;
418d983712dSmrg    }
419d983712dSmrg
420d983712dSmrg    /* PCI only driver now. */
421d983712dSmrg    if (!xf86GetPciVideoInfo())
422d983712dSmrg        return FALSE;
423d983712dSmrg
424d983712dSmrg    /* XXX maybe this can go some time soon */
425d983712dSmrg    /*
426d983712dSmrg     * for the Tseng server, there can only be one matching
427d983712dSmrg     * device section. So issue a warning if more than one show up.
428d983712dSmrg     * Multiple Tseng cards in the same machine are not possible.
429d983712dSmrg     */
430d983712dSmrg    numUsed = xf86MatchPciInstances(TSENG_NAME, PCI_VENDOR_TSENG,
431d983712dSmrg                                    TsengChipsets, TsengPciChipsets,
432d983712dSmrg                                    devSections,numDevSections, drv,
433d983712dSmrg                                    &usedChips);
434d983712dSmrg    if (numUsed > 0) {
435d983712dSmrg        if (flags & PROBE_DETECT)
436d983712dSmrg            foundScreen = TRUE;
437d983712dSmrg        else for (i = 0; i < numUsed; i++) {
438d983712dSmrg            /* Allocate a ScrnInfoRec  */
439d983712dSmrg            ScrnInfoPtr pScrn = NULL;
440d983712dSmrg            if ((pScrn = xf86ConfigPciEntity(pScrn,0,usedChips[i],
441d983712dSmrg                                             TsengPciChipsets,NULL,
442d983712dSmrg                                             NULL,NULL,NULL,NULL))) {
443d983712dSmrg                pScrn->driverVersion = TSENG_VERSION;
444d983712dSmrg                pScrn->driverName = TSENG_DRIVER_NAME;
445d983712dSmrg                pScrn->name = TSENG_NAME;
446d983712dSmrg                pScrn->Probe = TsengProbe;
447d983712dSmrg                pScrn->PreInit = TsengPreInit;
448d983712dSmrg                pScrn->ScreenInit = TsengScreenInit;
449d983712dSmrg                pScrn->SwitchMode = TsengSwitchMode;
450d983712dSmrg                pScrn->AdjustFrame = TsengAdjustFrame;
451d983712dSmrg                pScrn->EnterVT = TsengEnterVT;
452d983712dSmrg                pScrn->LeaveVT = TsengLeaveVT;
453d983712dSmrg                pScrn->FreeScreen = TsengFreeScreen;
454d983712dSmrg                pScrn->ValidMode = TsengValidMode;
455d983712dSmrg
456d983712dSmrg                foundScreen = TRUE;
457d983712dSmrg            }
458d983712dSmrg        }
459d983712dSmrg        xfree(usedChips);
460d983712dSmrg    }
461d983712dSmrg
462d983712dSmrg    xfree(devSections);
463d983712dSmrg    return foundScreen;
464d983712dSmrg}
465d983712dSmrg
466d983712dSmrg/* The PCI part of TsengPreInit() */
467d983712dSmrgstatic Bool
468d983712dSmrgTsengPreInitPCI(ScrnInfoPtr pScrn)
469d983712dSmrg{
470d983712dSmrg    TsengPtr pTseng = TsengPTR(pScrn);
471d983712dSmrg
472d983712dSmrg    PDEBUG("	TsengPreInitPCI\n");
473d983712dSmrg
474d983712dSmrg    /* This is PCI, we should be able to trust it */
475d983712dSmrg
476d983712dSmrg    /* Set up ChipType, ChipRev and pScrn->chipset.
477d983712dSmrg     * This last one is usually not done manually, but
478d983712dSmrg     * it's for informative use only anyway. */
479d983712dSmrg    switch (pTseng->PciInfo->chipType) {
480d983712dSmrg    case PCI_CHIP_ET4000_W32P_A:
481d983712dSmrg	pTseng->ChipType = ET4000;
482d983712dSmrg	pTseng->ChipRev = REV_A;
483d983712dSmrg        pScrn->chipset = "ET4000/W32P (rev A)";
484d983712dSmrg	break;
485d983712dSmrg    case PCI_CHIP_ET4000_W32P_B:
486d983712dSmrg	pTseng->ChipType = ET4000;
487d983712dSmrg	pTseng->ChipRev = REV_B;
488d983712dSmrg	pScrn->chipset = "ET4000/W32P (rev B)";
489d983712dSmrg        break;
490d983712dSmrg    case PCI_CHIP_ET4000_W32P_C:
491d983712dSmrg	pTseng->ChipType = ET4000;
492d983712dSmrg	pTseng->ChipRev = REV_C;
493d983712dSmrg        pScrn->chipset = "ET4000/W32P (rev C)";
494d983712dSmrg	break;
495d983712dSmrg    case PCI_CHIP_ET4000_W32P_D:
496d983712dSmrg	pTseng->ChipType = ET4000;
497d983712dSmrg	pTseng->ChipRev = REV_D;
498d983712dSmrg        pScrn->chipset = "ET4000/W32P (rev D)";
499d983712dSmrg	break;
500d983712dSmrg    case PCI_CHIP_ET6000:
501d983712dSmrg	pTseng->ChipType = ET6000;
502d983712dSmrg
503d983712dSmrg        if (pTseng->PciInfo->chipRev < 0x70) {
504d983712dSmrg            pScrn->chipset = "ET6000";
505d983712dSmrg            pTseng->ChipRev = REV_ET6000;
506d983712dSmrg        } else {
507d983712dSmrg            pScrn->chipset = "ET6100";
508d983712dSmrg            pTseng->ChipRev = REV_ET6100;
509d983712dSmrg        }
510d983712dSmrg	break;
511d983712dSmrg    default:
512d983712dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unknown Tseng PCI ID: %X\n",
513d983712dSmrg                   pTseng->PciInfo->chipType);
514d983712dSmrg	return FALSE;
515d983712dSmrg    }
516d983712dSmrg
517d983712dSmrg    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Chipset: \"%s\"\n", pScrn->chipset);
518d983712dSmrg
519d983712dSmrg    pTseng->PciTag = pciTag(pTseng->PciInfo->bus, pTseng->PciInfo->device,
520d983712dSmrg	pTseng->PciInfo->func);
521d983712dSmrg
522d983712dSmrg    /* only the ET6000 implements a PCI IO address */
523d983712dSmrg    if (pTseng->ChipType == ET6000) {
524d983712dSmrg        if (!pTseng->PciInfo->ioBase[1]) {
525d983712dSmrg            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
526d983712dSmrg                       "No valid PCI I/O address in PCI config space\n");
527d983712dSmrg            return FALSE;
528d983712dSmrg        }
529d983712dSmrg
530d983712dSmrg        pTseng->ET6000IOAddress = pTseng->PciInfo->ioBase[1];
531d983712dSmrg
532d983712dSmrg        xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "ET6000 PCI I/O registers at 0x%lX\n",
533d983712dSmrg                   (unsigned long)pTseng->ET6000IOAddress);
534d983712dSmrg    }
535d983712dSmrg
536d983712dSmrg    return TRUE;
537d983712dSmrg}
538d983712dSmrg
539d983712dSmrg/*
540d983712dSmrg * The 8*32kb ET6000 MDRAM granularity causes the more general probe to
541d983712dSmrg * detect too much memory in some configurations, because that code has a
542d983712dSmrg * 8-bank (=256k) granularity. E.g. it fails to recognize 2.25 MB of memory
543d983712dSmrg * (detects 2.5 instead). This function goes to check if the RAM is actually
544d983712dSmrg * there. MDRAM comes in multiples of 4 banks (16, 24, 32, 36, 40, 64, 72,
545d983712dSmrg * 80, ... 32kb-banks), so checking each 64k block should be enough granularity.
546d983712dSmrg *
547d983712dSmrg * No more than the amount of refreshed RAM is checked. Non-refreshed RAM
548d983712dSmrg * won't work anyway.
549d983712dSmrg *
550d983712dSmrg * The same code could be used on other Tseng chips, or even on ANY
551d983712dSmrg * VGA board, but probably only in case of trouble.
552d983712dSmrg *
553d983712dSmrg * FIXME: this should be done using linear memory
554d983712dSmrg */
555d983712dSmrg#define VIDMEM ((volatile CARD32*)check_vgabase)
556d983712dSmrg#define SEGSIZE (64)		       /* kb */
557d983712dSmrg
558d983712dSmrg#define ET6K_SETSEG(seg) \
559d983712dSmrg    vgaHWWriteBank(hwp, ((seg) & 0x30) | ((seg) >> 4));\
560d983712dSmrg    vgaHWWriteSegment(hwp, ((seg) & 0x0f) | ((seg) << 4));
561d983712dSmrg
562d983712dSmrgstatic int
563d983712dSmrget6000_check_videoram(ScrnInfoPtr pScrn, int ram)
564d983712dSmrg{
565d983712dSmrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
566d983712dSmrg    unsigned char oldSegSel1, oldSegSel2, oldGR5, oldGR6, oldSEQ2, oldSEQ4;
567d983712dSmrg    int segment, i;
568d983712dSmrg    int real_ram = 0;
569d983712dSmrg    pointer check_vgabase;
570d983712dSmrg    Bool fooled = FALSE;
571d983712dSmrg    int save_vidmem;
572d983712dSmrg
573d983712dSmrg    PDEBUG("	et6000_check_videoram\n");
574d983712dSmrg    if (ram > 4096) {
575d983712dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
576d983712dSmrg	    "Detected more than 4096 kb of video RAM. Clipped to 4096kb\n");
577d983712dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
578d983712dSmrg	    "    (Tseng VGA chips can only use 4096kb).\n");
579d983712dSmrg	ram = 4096;
580d983712dSmrg    }
581d983712dSmrg    if (!vgaHWMapMem(pScrn)) {
582d983712dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
583d983712dSmrg	    "Could not map VGA memory to check for video memory.\n");
584d983712dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
585d983712dSmrg	    "    Detected amount may be wrong.\n");
586d983712dSmrg	return ram;
587d983712dSmrg    }
588d983712dSmrg    check_vgabase = (VGAHWPTR(pScrn)->Base);
589d983712dSmrg
590d983712dSmrg    /*
591d983712dSmrg     * We need to set the VGA controller in VGA graphics mode, or else we won't
592d983712dSmrg     * be able to access the full 4MB memory range. First, we save the
593d983712dSmrg     * registers we modify, of course.
594d983712dSmrg     */
595d983712dSmrg
596d983712dSmrg    oldSegSel1 = vgaHWReadSegment(hwp);
597d983712dSmrg    oldSegSel2 = vgaHWReadBank(hwp);
598d983712dSmrg
599d983712dSmrg    oldGR5 = hwp->readGr(hwp, 0x05);
600d983712dSmrg    oldGR6 = hwp->readGr(hwp, 0x06);
601d983712dSmrg
602d983712dSmrg    oldSEQ2 = hwp->readSeq(hwp, 0x02);
603d983712dSmrg    oldSEQ4 = hwp->readSeq(hwp, 0x04);
604d983712dSmrg
605d983712dSmrg    /* set graphics mode */
606d983712dSmrg    hwp->writeGr(hwp, 0x06, 0x05);
607d983712dSmrg    hwp->writeGr(hwp, 0x05, 0x40);
608d983712dSmrg    hwp->writeSeq(hwp, 0x02, 0x0F);
609d983712dSmrg    hwp->writeSeq(hwp, 0x04, 0x0E);
610d983712dSmrg
611d983712dSmrg    /*
612d983712dSmrg     * count down from presumed amount of memory in SEGSIZE steps, and
613d983712dSmrg     * look at each segment for real RAM.
614d983712dSmrg     *
615d983712dSmrg     * To select a segment, we cannot use ET4000W32SetReadWrite(), since
616d983712dSmrg     * that requires the ScreenPtr, which we don't have here.
617d983712dSmrg     */
618d983712dSmrg
619d983712dSmrg    for (segment = (ram / SEGSIZE) - 1; segment >= 0; segment--) {
620d983712dSmrg	/* select the segment */
621d983712dSmrg	ET6K_SETSEG(segment);
622d983712dSmrg
623d983712dSmrg	/* save contents of memory probing location */
624d983712dSmrg	save_vidmem = *(VIDMEM);
625d983712dSmrg
626d983712dSmrg	/* test with pattern */
627d983712dSmrg	*VIDMEM = 0xAAAA5555;
628d983712dSmrg	if (*VIDMEM != 0xAAAA5555) {
629d983712dSmrg	    *VIDMEM = save_vidmem;
630d983712dSmrg	    continue;
631d983712dSmrg	}
632d983712dSmrg	/* test with inverted pattern */
633d983712dSmrg	*VIDMEM = 0x5555AAAA;
634d983712dSmrg	if (*VIDMEM != 0x5555AAAA) {
635d983712dSmrg	    *VIDMEM = save_vidmem;
636d983712dSmrg	    continue;
637d983712dSmrg	}
638d983712dSmrg	/*
639d983712dSmrg	 * If we get here, the memory seems to be writable/readable
640d983712dSmrg	 * Now check if we aren't fooled by address wrapping (mirroring)
641d983712dSmrg	 */
642d983712dSmrg	fooled = FALSE;
643d983712dSmrg	for (i = segment - 1; i >= 0; i--) {
644d983712dSmrg	    /* select the segment */
645d983712dSmrg	    ET6K_SETSEG(i);
646d983712dSmrg
647d983712dSmrg            /* again? */
648d983712dSmrg	    vgaHWWriteBank(hwp, (i & 0x30) | (i >> 4));
649d983712dSmrg	    vgaHWWriteSegment(hwp, (i & 0x0f) | (i << 4));
650d983712dSmrg
651d983712dSmrg	    if (*VIDMEM == 0x5555AAAA) {
652d983712dSmrg		/*
653d983712dSmrg		 * Seems like address wrap, but there could of course be
654d983712dSmrg		 * 0x5555AAAA in here by accident, so we check with another
655d983712dSmrg		 * pattern again.
656d983712dSmrg		 */
657d983712dSmrg		ET6K_SETSEG(segment);
658d983712dSmrg		/* test with other pattern again */
659d983712dSmrg		*VIDMEM = 0xAAAA5555;
660d983712dSmrg		ET6K_SETSEG(i);
661d983712dSmrg		if (*VIDMEM == 0xAAAA5555) {
662d983712dSmrg		    /* now we're sure: this is not real memory */
663d983712dSmrg		    fooled = TRUE;
664d983712dSmrg		    break;
665d983712dSmrg		}
666d983712dSmrg	    }
667d983712dSmrg	}
668d983712dSmrg	if (!fooled) {
669d983712dSmrg	    real_ram = (segment + 1) * SEGSIZE;
670d983712dSmrg	    break;
671d983712dSmrg	}
672d983712dSmrg	/* restore old contents again */
673d983712dSmrg	ET6K_SETSEG(segment);
674d983712dSmrg	*VIDMEM = save_vidmem;
675d983712dSmrg    }
676d983712dSmrg
677d983712dSmrg    /* restore original register contents */
678d983712dSmrg    vgaHWWriteSegment(hwp, oldSegSel1);
679d983712dSmrg    vgaHWWriteBank(hwp, oldSegSel2);
680d983712dSmrg
681d983712dSmrg    hwp->writeGr(hwp, 0x05, oldGR5);
682d983712dSmrg    hwp->writeGr(hwp, 0x06, oldGR6);
683d983712dSmrg    hwp->writeSeq(hwp, 0x02, oldSEQ2);
684d983712dSmrg    hwp->writeSeq(hwp, 0x04, oldSEQ4);
685d983712dSmrg
686d983712dSmrg    vgaHWUnmapMem(pScrn);
687d983712dSmrg    return real_ram;
688d983712dSmrg}
689d983712dSmrg
690d983712dSmrg/*
691d983712dSmrg * Handle amount of allowed memory: some combinations can't use all
692d983712dSmrg * available memory. Should we still allow the user to override this?
693d983712dSmrg *
694d983712dSmrg * This must be called AFTER the decision has been made to use linear mode
695d983712dSmrg * and/or acceleration, or the memory limit code won't be able to work.
696d983712dSmrg */
697d983712dSmrg
698d983712dSmrgstatic int
699d983712dSmrgTsengDoMemLimit(ScrnInfoPtr pScrn, int ram, int limit, char *reason)
700d983712dSmrg{
701d983712dSmrg    if (ram > limit) {
702d983712dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Only %d kb of memory can be used %s.\n",
703d983712dSmrg	    limit, reason);
704d983712dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Reducing video memory to %d kb.\n", limit);
705d983712dSmrg	ram = limit;
706d983712dSmrg    }
707d983712dSmrg    return ram;
708d983712dSmrg}
709d983712dSmrg
710d983712dSmrgstatic int
711d983712dSmrgTsengLimitMem(ScrnInfoPtr pScrn, int ram)
712d983712dSmrg{
713d983712dSmrg    TsengPtr pTseng = TsengPTR(pScrn);
714d983712dSmrg
715d983712dSmrg    if (pTseng->UseAccel) {
716d983712dSmrg	if (pTseng->ChipType == ET4000) {
717d983712dSmrg	    /* <= W32p_ab :
718d983712dSmrg	     *   2 MB direct access + 2*512kb via apertures MBP0 and MBP1
719d983712dSmrg	     * == W32p_cd :
720d983712dSmrg	     *   2*1MB via apertures MBP0 and MBP1
721d983712dSmrg	     */
722d983712dSmrg	    if ((pTseng->ChipRev == REV_C) || (pTseng->ChipRev == REV_D))
723d983712dSmrg		ram = TsengDoMemLimit(pScrn, ram, 2048,
724d983712dSmrg				      "in linear + accelerated mode "
725d983712dSmrg				      "on W32p rev c and d");
726d983712dSmrg
727d983712dSmrg	    ram = TsengDoMemLimit(pScrn, ram, 2048 + 1024,
728d983712dSmrg				  "in linear + accelerated mode "
729d983712dSmrg				  "on W32/W32i/W32p");
730d983712dSmrg
731d983712dSmrg	    /*
732d983712dSmrg	     * upper 516kb of 4MB linear map used for
733d983712dSmrg	     *  "externally mapped registers"
734d983712dSmrg	     */
735d983712dSmrg	    ram = TsengDoMemLimit(pScrn, ram, 4096 - 516,
736d983712dSmrg				  "in linear + accelerated mode "
737d983712dSmrg				  "on W32/W32i/W32p");
738d983712dSmrg	} else {
739d983712dSmrg	    /*
740d983712dSmrg	     * upper 8kb used for externally mapped and
741d983712dSmrg	     * memory mapped registers
742d983712dSmrg	     */
743d983712dSmrg	    ram = TsengDoMemLimit(pScrn, ram, 4096 - 8,
744d983712dSmrg				  "in linear + accelerated mode "
745d983712dSmrg				  "on ET6000/6100");
746d983712dSmrg	}
747d983712dSmrg    }
748d983712dSmrg    ram = TsengDoMemLimit(pScrn, ram, 4096, "on any Tseng card");
749d983712dSmrg    return ram;
750d983712dSmrg}
751d983712dSmrg
752d983712dSmrg/*
753d983712dSmrg * TsengDetectMem --
754d983712dSmrg *      try to find amount of video memory installed.
755d983712dSmrg *
756d983712dSmrg */
757d983712dSmrgstatic int
758d983712dSmrgTsengDetectMem(ScrnInfoPtr pScrn)
759d983712dSmrg{
760d983712dSmrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
761d983712dSmrg    TsengPtr pTseng = TsengPTR(pScrn);
762d983712dSmrg    unsigned char config;
763d983712dSmrg    int ramtype = 0;
764d983712dSmrg    int ram = 0;
765d983712dSmrg
766d983712dSmrg    PDEBUG("	TsengDetectMem\n");
767d983712dSmrg    if (pTseng->ChipType == ET6000) {
768d983712dSmrg	ramtype = hwp->readST00(hwp) & 0x03;
769d983712dSmrg	switch (ramtype) {
770d983712dSmrg	case 0x03:		       /* MDRAM */
771d983712dSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
772d983712dSmrg		"Video memory type: Multibank DRAM (MDRAM).\n");
773d983712dSmrg	    ram = ((ET6000IORead(pTseng, 0x47) & 0x07) + 1) * 8 * 32;	/* number of 8 32kb banks  */
774d983712dSmrg	    if (ET6000IORead(pTseng, 0x45) & 0x04) {
775d983712dSmrg		ram <<= 1;
776d983712dSmrg	    }
777d983712dSmrg	    /*
778d983712dSmrg	     * 8*32kb MDRAM refresh control granularity in the ET6000 fails to
779d983712dSmrg	     * recognize 2.25 MB of memory (detects 2.5 instead)
780d983712dSmrg	     */
781d983712dSmrg	    ram = et6000_check_videoram(pScrn, ram);
782d983712dSmrg	    break;
783d983712dSmrg	case 0x00:		       /* DRAM -- VERY unlikely on ET6000 cards, IMPOSSIBLE on ET6100 */
784d983712dSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
785d983712dSmrg		"Video memory type: Standard DRAM.\n");
786d983712dSmrg	    ram = 1024 << (ET6000IORead(pTseng, 0x45) & 0x03);
787d983712dSmrg	    break;
788d983712dSmrg	default:		       /* unknown RAM type */
789d983712dSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
790d983712dSmrg		"Unknown ET6000 video memory type %d -- assuming 1 MB (unless specified)\n",
791d983712dSmrg		ramtype);
792d983712dSmrg	    ram = 1024;
793d983712dSmrg	}
794d983712dSmrg    } else {
795d983712dSmrg	config = hwp->readCrtc(hwp, 0x37);
796d983712dSmrg
797d983712dSmrg	ram = 128 << (config & 0x03);
798d983712dSmrg
799d983712dSmrg	if (config & 0x80)
800d983712dSmrg	    ram <<= 1;
801d983712dSmrg
802d983712dSmrg	/* Check for interleaving on W32i/p. */
803d983712dSmrg        config = hwp->readCrtc(hwp, 0x32);
804d983712dSmrg        if (config & 0x80) {
805d983712dSmrg            ram <<= 1;
806d983712dSmrg            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
807d983712dSmrg                       "Video memory type: Interleaved DRAM.\n");
808d983712dSmrg        } else {
809d983712dSmrg            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
810d983712dSmrg                       "Video memory type: Standard DRAM.\n");
811d983712dSmrg        }
812d983712dSmrg    }
813d983712dSmrg    return ram;
814d983712dSmrg}
815d983712dSmrg
816d983712dSmrgstatic Bool
817d983712dSmrgTsengProcessHibit(ScrnInfoPtr pScrn)
818d983712dSmrg{
819d983712dSmrg    TsengPtr pTseng = TsengPTR(pScrn);
820d983712dSmrg    MessageType from = X_CONFIG;
821d983712dSmrg    int hibit_mode_width;
822d983712dSmrg
823d983712dSmrg    PDEBUG("	TsengProcessHibit\n");
824d983712dSmrg    if (xf86IsOptionSet(pTseng->Options, OPTION_HIBIT_HIGH)) {
825d983712dSmrg	if (xf86IsOptionSet(pTseng->Options, OPTION_HIBIT_LOW)) {
826d983712dSmrg	    xf86Msg(X_ERROR, "\nOptions \"hibit_high\" and \"hibit_low\" are incompatible;\n");
827d983712dSmrg	    xf86Msg(X_ERROR, "    specify only one (not both) in X configuration file\n");
828d983712dSmrg	    return FALSE;
829d983712dSmrg	}
830d983712dSmrg	pTseng->save_divide = 0x40;
831d983712dSmrg    } else if (xf86IsOptionSet(pTseng->Options, OPTION_HIBIT_HIGH)) {
832d983712dSmrg	pTseng->save_divide = 0;
833d983712dSmrg    } else {
834d983712dSmrg        vgaHWPtr hwp = VGAHWPTR(pScrn);
835d983712dSmrg
836d983712dSmrg	from = X_PROBED;
837d983712dSmrg
838d983712dSmrg	/* first check to see if hibit is probed from low-res mode */
839d983712dSmrg	hibit_mode_width = hwp->readCrtc(hwp, 0x01) + 1;
840d983712dSmrg
841d983712dSmrg	if (hibit_mode_width > 82) {
842d983712dSmrg	    xf86Msg(X_WARNING, "Non-standard VGA text or graphics mode while probing for hibit:\n");
843d983712dSmrg	    xf86Msg(X_WARNING, "    probed 'hibit' value may be wrong.\n");
844d983712dSmrg	    xf86Msg(X_WARNING, "    Preferably run probe from 80x25 textmode,\n");
845d983712dSmrg	    xf86Msg(X_WARNING, "    or specify correct value in X configuration file.\n");
846d983712dSmrg	}
847d983712dSmrg
848d983712dSmrg	/* Check for initial state of divide flag */
849d983712dSmrg	pTseng->save_divide = hwp->readSeq(hwp, 0x07) & 0x40;
850d983712dSmrg    }
851d983712dSmrg    xf86DrvMsg(pScrn->scrnIndex, from, "Initial ET4000 hibit state: %s\n",
852d983712dSmrg	pTseng->save_divide & 0x40 ? "high" : "low");
853d983712dSmrg    return TRUE;
854d983712dSmrg}
855d983712dSmrg
856d983712dSmrgstatic Bool
857d983712dSmrgTsengProcessOptions(ScrnInfoPtr pScrn)
858d983712dSmrg{
859d983712dSmrg    MessageType from;
860d983712dSmrg    TsengPtr pTseng = TsengPTR(pScrn);
861d983712dSmrg
862d983712dSmrg    PDEBUG("	TsengProcessOptions\n");
863d983712dSmrg
864d983712dSmrg    /* Collect all of the relevant option flags (fill in pScrn->options) */
865d983712dSmrg    xf86CollectOptions(pScrn, NULL);
866d983712dSmrg
867d983712dSmrg    /* Process the options */
868d983712dSmrg    if (!(pTseng->Options = xalloc(sizeof(TsengOptions))))
869d983712dSmrg	return FALSE;
870d983712dSmrg    memcpy(pTseng->Options, TsengOptions, sizeof(TsengOptions));
871d983712dSmrg    xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pTseng->Options);
872d983712dSmrg
873d983712dSmrg    from = X_DEFAULT;
874d983712dSmrg    pTseng->HWCursor = FALSE;	       /* default */
875d983712dSmrg    if (xf86GetOptValBool(pTseng->Options, OPTION_HW_CURSOR, &pTseng->HWCursor))
876d983712dSmrg	from = X_CONFIG;
877d983712dSmrg    if (xf86ReturnOptValBool(pTseng->Options, OPTION_SW_CURSOR, FALSE)) {
878d983712dSmrg	from = X_CONFIG;
879d983712dSmrg	pTseng->HWCursor = FALSE;
880d983712dSmrg    }
881d983712dSmrg    if ((pTseng->ChipType == ET4000) && pTseng->HWCursor) {
882d983712dSmrg	xf86DrvMsg(pScrn->scrnIndex, from,
883d983712dSmrg		"Hardware Cursor not supported on this chipset\n");
884d983712dSmrg	pTseng->HWCursor = FALSE;
885d983712dSmrg    }
886d983712dSmrg
887d983712dSmrg    xf86DrvMsg(pScrn->scrnIndex, from, "Using %s cursor\n",
888d983712dSmrg	pTseng->HWCursor ? "HW" : "SW");
889d983712dSmrg
890d983712dSmrg    if (pScrn->bitsPerPixel >= 8) {
891d983712dSmrg        pTseng->UseAccel = TRUE;
892d983712dSmrg	if (xf86ReturnOptValBool(pTseng->Options, OPTION_NOACCEL, FALSE)) {
893d983712dSmrg	    pTseng->UseAccel = FALSE;
894d983712dSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Acceleration disabled\n");
895d983712dSmrg	}
896d983712dSmrg    } else
897d983712dSmrg	pTseng->UseAccel = FALSE;  /* 1bpp and 4bpp are always non-accelerated */
898d983712dSmrg
899d983712dSmrg    pTseng->SlowDram = FALSE;
900d983712dSmrg    if (xf86IsOptionSet(pTseng->Options, OPTION_SLOW_DRAM)) {
901d983712dSmrg	pTseng->SlowDram = TRUE;
902d983712dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Using slow DRAM access\n");
903d983712dSmrg    }
904d983712dSmrg    pTseng->MedDram = FALSE;
905d983712dSmrg    if (xf86IsOptionSet(pTseng->Options, OPTION_MED_DRAM)) {
906d983712dSmrg	pTseng->MedDram = TRUE;
907d983712dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Using Medium-speed DRAM access\n");
908d983712dSmrg    }
909d983712dSmrg    pTseng->FastDram = FALSE;
910d983712dSmrg    if (xf86IsOptionSet(pTseng->Options, OPTION_FAST_DRAM)) {
911d983712dSmrg	pTseng->FastDram = TRUE;
912d983712dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Using fast DRAM access\n");
913d983712dSmrg    }
914d983712dSmrg    if ((pTseng->SetW32Interleave =
915d983712dSmrg	xf86GetOptValBool(pTseng->Options, OPTION_W32_INTERLEAVE, &pTseng->W32Interleave)) )
916d983712dSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Forcing W32p memory interleave %s.\n",
917d983712dSmrg	    pTseng->W32Interleave ? "ON" : "OFF");
918d983712dSmrg    if ((pTseng->SetPCIBurst =
919d983712dSmrg	xf86GetOptValBool(pTseng->Options, OPTION_PCI_BURST, &pTseng->PCIBurst)) )
920d983712dSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Forcing PCI burst mode %s.\n",
921d983712dSmrg	    pTseng->PCIBurst ? "ON" : "OFF");
922d983712dSmrg
923d983712dSmrg    pTseng->ShowCache = FALSE;
924d983712dSmrg    if (xf86ReturnOptValBool(pTseng->Options, OPTION_SHOWCACHE, FALSE)) {
925d983712dSmrg	pTseng->ShowCache = TRUE;
926d983712dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "(for debugging only:) Visible off-screen memory\n");
927d983712dSmrg    }
928d983712dSmrg
929d983712dSmrg    pTseng->UsePCIRetry = FALSE;
930d983712dSmrg    if (xf86ReturnOptValBool(pTseng->Options, OPTION_PCI_RETRY, FALSE)) {
931d983712dSmrg	pTseng->UsePCIRetry = TRUE;
932d983712dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "PCI retry enabled\n");
933d983712dSmrg    }
934d983712dSmrg    return TRUE;
935d983712dSmrg}
936d983712dSmrg
937d983712dSmrgstatic Bool
938d983712dSmrgTsengGetFbAddress(ScrnInfoPtr pScrn)
939d983712dSmrg{
940d983712dSmrg    TsengPtr pTseng = TsengPTR(pScrn);
941d983712dSmrg
942d983712dSmrg    PDEBUG("	TsengGetFbAddress\n");
943d983712dSmrg
944d983712dSmrg    /* base0 is the framebuffer and base1 is the PCI IO space. */
945d983712dSmrg    if (!pTseng->PciInfo->memBase[0]) {
946d983712dSmrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
947d983712dSmrg                   "No valid Framebuffer address in PCI config space;\n");
948d983712dSmrg        return FALSE;
949d983712dSmrg    } else
950d983712dSmrg        pTseng->FbAddress = pTseng->PciInfo->memBase[0];
951d983712dSmrg
952d983712dSmrg
953d983712dSmrg    if (xf86RegisterResources(pTseng->pEnt->index,NULL,ResNone)) {
954d983712dSmrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Cannot register FB memory.\n");
955d983712dSmrg        return FALSE;
956d983712dSmrg    }
957d983712dSmrg
958d983712dSmrg    /* The W32 linear map address space is always 4Mb (mainly because the
959d983712dSmrg     * memory-mapped registers are located near the top of the 4MB area).
960d983712dSmrg     * The ET6000 maps out 16 Meg, but still uses only 4Mb of that.
961d983712dSmrg     * However, since all mmap()-ed space is also reflected in the "ps"
962d983712dSmrg     * listing for the Xserver, many users will be worried by a server that
963d983712dSmrg     * always eats 16MB of memory, even if it's not "real" memory, just
964d983712dSmrg     * address space. Not mapping all of the 16M may be a potential problem
965d983712dSmrg     * though: if another board is mapped on top of the remaining part of
966d983712dSmrg     * the 16M... Boom!
967d983712dSmrg     */
968d983712dSmrg    if (pTseng->ChipType == ET6000)
969d983712dSmrg	pTseng->FbMapSize = 16384 * 1024;
970d983712dSmrg    else
971d983712dSmrg	pTseng->FbMapSize = 4096 * 1024;
972d983712dSmrg
973d983712dSmrg    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Framebuffer at 0x%lX\n",
974d983712dSmrg               (unsigned long)pTseng->FbAddress);
975d983712dSmrg
976d983712dSmrg    return TRUE;
977d983712dSmrg}
978d983712dSmrg
979d983712dSmrgstatic Bool
980d983712dSmrgTsengPreInit(ScrnInfoPtr pScrn, int flags)
981d983712dSmrg{
982d983712dSmrg    TsengPtr pTseng;
983d983712dSmrg    MessageType from;
984d983712dSmrg    int i;
985d983712dSmrg
986d983712dSmrg    if (flags & PROBE_DETECT) return FALSE;
987d983712dSmrg
988d983712dSmrg    PDEBUG("	TsengPreInit\n");
989d983712dSmrg
990d983712dSmrg    /*
991d983712dSmrg     * Note: This function is only called once at server startup, and
992d983712dSmrg     * not at the start of each server generation.  This means that
993d983712dSmrg     * only things that are persistent across server generations can
994d983712dSmrg     * be initialised here.  xf86Screens[] is (pScrn is a pointer to one
995d983712dSmrg     * of these).  Privates allocated using xf86AllocateScrnInfoPrivateIndex()
996d983712dSmrg     * are too, and should be used for data that must persist across
997d983712dSmrg     * server generations.
998d983712dSmrg     *
999d983712dSmrg     * Per-generation data should be allocated with
1000d983712dSmrg     * AllocateScreenPrivateIndex() from the ScreenInit() function.
1001d983712dSmrg     */
1002d983712dSmrg
1003d983712dSmrg    /* The vgahw module should be loaded here when needed */
1004d983712dSmrg
1005d983712dSmrg    /* This driver doesn't expect more than one entity per screen */
1006d983712dSmrg    if (pScrn->numEntities > 1)
1007d983712dSmrg	    return FALSE;
1008d983712dSmrg
1009d983712dSmrg    /* Allocate the TsengRec driverPrivate */
1010d983712dSmrg    if (!TsengGetRec(pScrn)) {
1011d983712dSmrg	return FALSE;
1012d983712dSmrg    }
1013d983712dSmrg    pTseng = TsengPTR(pScrn);
1014d983712dSmrg
1015d983712dSmrg    /* This is the general case */
1016d983712dSmrg    pTseng->pEnt = xf86GetEntityInfo(*pScrn->entityList);
1017d983712dSmrg
1018d983712dSmrg#if 1
1019d983712dSmrg    if (xf86LoadSubModule(pScrn, "int10")) {
1020d983712dSmrg 	xf86Int10InfoPtr pInt;
1021d983712dSmrg	xf86LoaderReqSymLists(int10Symbols, NULL);
1022d983712dSmrg#if 1
1023d983712dSmrg	xf86DrvMsg(pScrn->scrnIndex,X_INFO,"initializing int10\n");
1024d983712dSmrg	pInt = xf86InitInt10(pTseng->pEnt->index);
1025d983712dSmrg	xf86FreeInt10(pInt);
1026d983712dSmrg#endif
1027d983712dSmrg    }
1028d983712dSmrg#endif
1029d983712dSmrg
1030d983712dSmrg    if (!xf86LoadSubModule(pScrn, "vgahw"))
1031d983712dSmrg	return FALSE;
1032d983712dSmrg    xf86LoaderReqSymLists(vgaHWSymbols, NULL);
1033d983712dSmrg    /*
1034d983712dSmrg     * Allocate a vgaHWRec
1035d983712dSmrg     */
1036d983712dSmrg    if (!vgaHWGetHWRec(pScrn))
1037d983712dSmrg	return FALSE;
1038d983712dSmrg
1039d983712dSmrg    vgaHWGetIOBase(VGAHWPTR(pScrn));
1040d983712dSmrg    /*
1041d983712dSmrg     * Since, the capabilities are determined by the chipset, the very first
1042d983712dSmrg     * thing to do is to figure out the chipset and its capabilities.
1043d983712dSmrg     */
1044d983712dSmrg
1045d983712dSmrg    TsengUnlock(pScrn);
1046d983712dSmrg
1047d983712dSmrg    pTseng->PciInfo = xf86GetPciInfoForEntity(pTseng->pEnt->index);
1048d983712dSmrg    if (!TsengPreInitPCI(pScrn)) {
1049d983712dSmrg        TsengFreeRec(pScrn);
1050d983712dSmrg        return FALSE;
1051d983712dSmrg    }
1052d983712dSmrg
1053d983712dSmrg    if (!TsengRAMDACProbe(pScrn)) {
1054d983712dSmrg        TsengFreeRec(pScrn);
1055d983712dSmrg	return FALSE;
1056d983712dSmrg    }
1057d983712dSmrg
1058d983712dSmrg    pScrn->progClock = TRUE;
1059d983712dSmrg
1060d983712dSmrg    /*
1061d983712dSmrg     * Now we can check what depth we support.
1062d983712dSmrg     */
1063d983712dSmrg
1064d983712dSmrg    /* Set pScrn->monitor */
1065d983712dSmrg    pScrn->monitor = pScrn->confScreen->monitor;
1066d983712dSmrg
1067d983712dSmrg    /*
1068d983712dSmrg     * The first thing we should figure out is the depth, bpp, etc.
1069d983712dSmrg     * Our default depth is 8, so pass it to the helper function.
1070d983712dSmrg     * Our preference for depth 24 is 24bpp, so tell it that too.
1071d983712dSmrg     */
1072d983712dSmrg    if (!xf86SetDepthBpp(pScrn, 8, 8, 8, Support24bppFb | Support32bppFb |
1073d983712dSmrg                         SupportConvert32to24 | PreferConvert32to24)) {
1074d983712dSmrg	return FALSE;
1075d983712dSmrg    } else {
1076d983712dSmrg        switch (pScrn->depth) {
1077d983712dSmrg        case 8:
1078d983712dSmrg        case 16:
1079d983712dSmrg        case 24:
1080d983712dSmrg        case 32:
1081d983712dSmrg            /* OK */
1082d983712dSmrg            break;
1083d983712dSmrg        default:
1084d983712dSmrg            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1085d983712dSmrg                       "Given depth (%d) is not supported by this driver\n",
1086d983712dSmrg                       pScrn->depth);
1087d983712dSmrg            return FALSE;
1088d983712dSmrg        }
1089d983712dSmrg    }
1090d983712dSmrg    xf86PrintDepthBpp(pScrn);
1091d983712dSmrg
1092d983712dSmrg    /* Get the depth24 pixmap format */
1093d983712dSmrg    if (pScrn->depth == 24 && pix24bpp == 0)
1094d983712dSmrg	pix24bpp = xf86GetBppFromDepth(pScrn, 24);
1095d983712dSmrg
1096d983712dSmrg    if (pScrn->bitsPerPixel > 8)
1097d983712dSmrg	pTseng->Bytesperpixel = pScrn->bitsPerPixel / 8;
1098d983712dSmrg    else
1099d983712dSmrg	pTseng->Bytesperpixel = 1;  /* this is fake for < 8bpp, but simplifies other code */
1100d983712dSmrg
1101d983712dSmrg    /* hardware limits */
1102d983712dSmrg    pScrn->maxHValue = Tseng_HMAX;
1103d983712dSmrg    pScrn->maxVValue = Tseng_VMAX;
1104d983712dSmrg
1105d983712dSmrg    /*
1106d983712dSmrg     * This must happen after pScrn->display has been set because
1107d983712dSmrg     * xf86SetWeight references it.
1108d983712dSmrg     */
1109d983712dSmrg
1110d983712dSmrg    /* Set weight/mask/offset for depth > 8 */
1111d983712dSmrg    if (pScrn->depth > 8) {
1112d983712dSmrg	/* The defaults are OK for us */
1113d983712dSmrg	rgb zeros = {0, 0, 0};
1114d983712dSmrg
1115d983712dSmrg	if (!xf86SetWeight(pScrn, zeros, zeros)) {
1116d983712dSmrg	    return FALSE;
1117d983712dSmrg	} else {
1118d983712dSmrg	    /* XXX check that weight returned is supported */
1119d983712dSmrg	    ;
1120d983712dSmrg	}
1121d983712dSmrg    }
1122d983712dSmrg
1123d983712dSmrg    /* Set the default visual. */
1124d983712dSmrg    if (!xf86SetDefaultVisual(pScrn, -1))
1125d983712dSmrg	return FALSE;
1126d983712dSmrg
1127d983712dSmrg    /* The gamma fields must be initialised when using the new cmap code */
1128d983712dSmrg    if (pScrn->depth > 1) {
1129d983712dSmrg	Gamma zeros = {0.0, 0.0, 0.0};
1130d983712dSmrg
1131d983712dSmrg	if (!xf86SetGamma(pScrn, zeros)) {
1132d983712dSmrg	    return FALSE;
1133d983712dSmrg	}
1134d983712dSmrg    }
1135d983712dSmrg
1136d983712dSmrg    /* Set the bits per RGB for 8bpp mode */
1137d983712dSmrg    if (pScrn->depth == 8) {
1138d983712dSmrg	/* Default to 6, because most Tseng chips/RAMDACs don't support it */
1139d983712dSmrg	pScrn->rgbBits = 6;
1140d983712dSmrg    }
1141d983712dSmrg    if (!TsengProcessOptions(pScrn))   /* must be done _after_ we know what chip this is */
1142d983712dSmrg	return FALSE;
1143d983712dSmrg
1144d983712dSmrg    if (!TsengGetFbAddress(pScrn))
1145d983712dSmrg        return FALSE;
1146d983712dSmrg
1147d983712dSmrg    pScrn->memPhysBase = pTseng->FbAddress;
1148d983712dSmrg    pScrn->fbOffset = 0;
1149d983712dSmrg
1150d983712dSmrg    if (pTseng->UseAccel)
1151d983712dSmrg	VGAHWPTR(pScrn)->MapSize = 0x20000;  /* accelerator apertures and MMIO */
1152d983712dSmrg    else
1153d983712dSmrg	VGAHWPTR(pScrn)->MapSize = 0x10000;
1154d983712dSmrg
1155d983712dSmrg    /*
1156d983712dSmrg     * XXX At least part of this range does appear to be disabled,
1157d983712dSmrg     * but to play safe, it is marked as "unused" for now.
1158d983712dSmrg     * Changed this to "disable". Otherwise it might interfere with DGA.
1159d983712dSmrg     */
1160d983712dSmrg    xf86SetOperatingState(resVgaMem, pTseng->pEnt->index, ResDisableOpr);
1161d983712dSmrg
1162d983712dSmrg    /* hibit processing (TsengProcessOptions() must have been called first) */
1163d983712dSmrg    pTseng->save_divide = 0x40;	       /* default */
1164d983712dSmrg    if (pTseng->ChipType == ET4000) {
1165d983712dSmrg	if (!TsengProcessHibit(pScrn))
1166d983712dSmrg	    return FALSE;
1167d983712dSmrg    }
1168d983712dSmrg    /*
1169d983712dSmrg     * If the user has specified the amount of memory in the XF86Config
1170d983712dSmrg     * file, we respect that setting.
1171d983712dSmrg     */
1172d983712dSmrg    if (pTseng->pEnt->device->videoRam != 0) {
1173d983712dSmrg	pScrn->videoRam = pTseng->pEnt->device->videoRam;
1174d983712dSmrg	from = X_CONFIG;
1175d983712dSmrg    } else {
1176d983712dSmrg	from = X_PROBED;
1177d983712dSmrg	pScrn->videoRam = TsengDetectMem(pScrn);
1178d983712dSmrg    }
1179d983712dSmrg    pScrn->videoRam = TsengLimitMem(pScrn, pScrn->videoRam);
1180d983712dSmrg
1181d983712dSmrg    xf86DrvMsg(pScrn->scrnIndex, from, "VideoRAM: %d kByte.\n",
1182d983712dSmrg               pScrn->videoRam);
1183d983712dSmrg
1184d983712dSmrg     TsengSetupClockRange(pScrn);
1185d983712dSmrg
1186d983712dSmrg    /*
1187d983712dSmrg     * xf86ValidateModes will check that the mode HTotal and VTotal values
1188d983712dSmrg     * don't exceed the chipset's limit if pScrn->maxHValue and
1189d983712dSmrg     * pScrn->maxVValue are set.  Since our TsengValidMode() already takes
1190d983712dSmrg     * care of this, we don't worry about setting them here.
1191d983712dSmrg     */
1192d983712dSmrg
1193d983712dSmrg    /* Select valid modes from those available */
1194d983712dSmrg    i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
1195d983712dSmrg	pScrn->display->modes, &pTseng->clockRange,
1196d983712dSmrg	NULL, 32, pScrn->maxHValue, 8*pTseng->Bytesperpixel, /* H limits */
1197d983712dSmrg	0, pScrn->maxVValue,	       /* V limits */
1198d983712dSmrg	pScrn->display->virtualX,
1199d983712dSmrg	pScrn->display->virtualY,
1200d983712dSmrg	pTseng->FbMapSize,
1201d983712dSmrg	LOOKUP_BEST_REFRESH);	       /* LOOKUP_CLOSEST_CLOCK | LOOKUP_CLKDIV2 when no programmable clock ? */
1202d983712dSmrg
1203d983712dSmrg    if (i == -1) {
1204d983712dSmrg	TsengFreeRec(pScrn);
1205d983712dSmrg	return FALSE;
1206d983712dSmrg    }
1207d983712dSmrg    /* Prune the modes marked as invalid */
1208d983712dSmrg    xf86PruneDriverModes(pScrn);
1209d983712dSmrg
1210d983712dSmrg    if (i == 0 || pScrn->modes == NULL) {
1211d983712dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n");
1212d983712dSmrg	TsengFreeRec(pScrn);
1213d983712dSmrg	return FALSE;
1214d983712dSmrg    }
1215d983712dSmrg    /*
1216d983712dSmrg     * Set the CRTC parameters for all of the modes based on the type
1217d983712dSmrg     * of mode, and the chipset's interlace requirements.
1218d983712dSmrg     *
1219d983712dSmrg     * Calling this is required if the mode->Crtc* values are used by the
1220d983712dSmrg     * driver and if the driver doesn't provide code to set them.  They
1221d983712dSmrg     * are not pre-initialised at all.
1222d983712dSmrg     */
1223d983712dSmrg    xf86SetCrtcForModes(pScrn, 0);
1224d983712dSmrg
1225d983712dSmrg    /* Set the current mode to the first in the list */
1226d983712dSmrg    pScrn->currentMode = pScrn->modes;
1227d983712dSmrg
1228d983712dSmrg    /* Print the list of modes being used */
1229d983712dSmrg    xf86PrintModes(pScrn);
1230d983712dSmrg
1231d983712dSmrg    /* Set display resolution */
1232d983712dSmrg    xf86SetDpi(pScrn, 0, 0);
1233d983712dSmrg
1234d983712dSmrg    /* Load bpp-specific modules */
1235d983712dSmrg    switch (pScrn->bitsPerPixel) {
1236d983712dSmrg    case 1:
1237d983712dSmrg	if (xf86LoadSubModule(pScrn, "xf1bpp") == NULL) {
1238d983712dSmrg	  TsengFreeRec(pScrn);
1239d983712dSmrg	  return FALSE;
1240d983712dSmrg	}
1241d983712dSmrg	xf86LoaderReqSymbols("xf1bppScreenInit", NULL);
1242d983712dSmrg	break;
1243d983712dSmrg    case 4:
1244d983712dSmrg	if (xf86LoadSubModule(pScrn, "xf4bpp") == NULL) {
1245d983712dSmrg	  TsengFreeRec(pScrn);
1246d983712dSmrg	  return FALSE;
1247d983712dSmrg	}
1248d983712dSmrg	xf86LoaderReqSymbols("xf4bppScreenInit", NULL);
1249d983712dSmrg	break;
1250d983712dSmrg    default:
1251d983712dSmrg	if (xf86LoadSubModule(pScrn, "fb") == NULL) {
1252d983712dSmrg	  TsengFreeRec(pScrn);
1253d983712dSmrg	  return FALSE;
1254d983712dSmrg	}
1255d983712dSmrg	xf86LoaderReqSymLists(fbSymbols, NULL);
1256d983712dSmrg	break;
1257d983712dSmrg    }
1258d983712dSmrg
1259d983712dSmrg    /* Load XAA if needed */
1260d983712dSmrg    if (pTseng->UseAccel) {
1261d983712dSmrg	if (!xf86LoadSubModule(pScrn, "xaa")) {
1262d983712dSmrg	    TsengFreeRec(pScrn);
1263d983712dSmrg	    return FALSE;
1264d983712dSmrg	}
1265d983712dSmrg	xf86LoaderReqSymLists(xaaSymbols, NULL);
1266d983712dSmrg    }
1267d983712dSmrg    /* Load ramdac if needed */
1268d983712dSmrg    if (pTseng->HWCursor) {
1269d983712dSmrg	if (!xf86LoadSubModule(pScrn, "ramdac")) {
1270d983712dSmrg	    TsengFreeRec(pScrn);
1271d983712dSmrg	    return FALSE;
1272d983712dSmrg	}
1273d983712dSmrg	xf86LoaderReqSymLists(ramdacSymbols, NULL);
1274d983712dSmrg    }
1275d983712dSmrg/*    TsengLock(pScrn); */
1276d983712dSmrg
1277d983712dSmrg    return TRUE;
1278d983712dSmrg}
1279d983712dSmrg
1280d983712dSmrgstatic void
1281d983712dSmrgTsengSetupAccelMemory(int scrnIndex, ScreenPtr pScreen)
1282d983712dSmrg{
1283d983712dSmrg    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
1284d983712dSmrg    TsengPtr pTseng = TsengPTR(pScrn);
1285d983712dSmrg    int offscreen_videoram, videoram_end, req_videoram;
1286d983712dSmrg    int i;
1287d983712dSmrg    int v;
1288d983712dSmrg
1289d983712dSmrg    /* XXX Hack to suppress messages in subsequent generations. */
1290d983712dSmrg    if (serverGeneration == 1)
1291d983712dSmrg	v = 1;
1292d983712dSmrg    else
1293d983712dSmrg	v = 100;
1294d983712dSmrg    /*
1295d983712dSmrg     * The accelerator requires free off-screen video memory to operate. The
1296d983712dSmrg     * more there is, the more it can accelerate.
1297d983712dSmrg     */
1298d983712dSmrg
1299d983712dSmrg    videoram_end = pScrn->videoRam * 1024;
1300d983712dSmrg    offscreen_videoram = videoram_end -
1301d983712dSmrg	pScrn->displayWidth * pScrn->virtualY * pTseng->Bytesperpixel;
1302d983712dSmrg    xf86DrvMsgVerb(scrnIndex, X_INFO, v, "Available off-screen memory: %d bytes.\n",
1303d983712dSmrg	offscreen_videoram);
1304d983712dSmrg
1305d983712dSmrg    /*
1306d983712dSmrg     * The HW cursor requires 1kb of off-screen memory, aligned to 1kb
1307d983712dSmrg     * (256 DWORDS). Setting up its memory first ensures the alignment.
1308d983712dSmrg     */
1309d983712dSmrg    if (pTseng->HWCursor) {
1310d983712dSmrg	req_videoram = 1024;
1311d983712dSmrg	if (offscreen_videoram < req_videoram) {
1312d983712dSmrg	    xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, v,
1313d983712dSmrg		"Hardware Cursor disabled. It requires %d bytes of free video memory\n",
1314d983712dSmrg		req_videoram);
1315d983712dSmrg	    pTseng->HWCursor = FALSE;
1316d983712dSmrg	    pTseng->HWCursorBufferOffset = 0;
1317d983712dSmrg	} else {
1318d983712dSmrg	    offscreen_videoram -= req_videoram;
1319d983712dSmrg	    videoram_end -= req_videoram;
1320d983712dSmrg	    pTseng->HWCursorBufferOffset = videoram_end;
1321d983712dSmrg	}
1322d983712dSmrg    } else {
1323d983712dSmrg	pTseng->HWCursorBufferOffset = 0;
1324d983712dSmrg    }
1325d983712dSmrg
1326d983712dSmrg    /*
1327d983712dSmrg     * Acceleration memory setup. Do this only if acceleration is enabled.
1328d983712dSmrg     */
1329d983712dSmrg    if (!pTseng->UseAccel) return;
1330d983712dSmrg
1331d983712dSmrg    /*
1332d983712dSmrg     * Basic acceleration needs storage for FG, BG and PAT colors in
1333d983712dSmrg     * off-screen memory. Each color requires 2(ping-pong)*8 bytes.
1334d983712dSmrg     */
1335d983712dSmrg    req_videoram = 2 * 8 * 3;
1336d983712dSmrg    if (offscreen_videoram < req_videoram) {
1337d983712dSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, v,
1338d983712dSmrg	    "Acceleration disabled. It requires AT LEAST %d bytes of free video memory\n",
1339d983712dSmrg	    req_videoram);
1340d983712dSmrg	pTseng->UseAccel = FALSE;
1341d983712dSmrg	pTseng->AccelColorBufferOffset = 0;
1342d983712dSmrg	goto end_memsetup;	      /* no basic acceleration means none at all */
1343d983712dSmrg    } else {
1344d983712dSmrg	offscreen_videoram -= req_videoram;
1345d983712dSmrg	videoram_end -= req_videoram;
1346d983712dSmrg	pTseng->AccelColorBufferOffset = videoram_end;
1347d983712dSmrg    }
1348d983712dSmrg
1349d983712dSmrg    /*
1350d983712dSmrg     * Color expansion (using triple buffering) requires 3 non-expanded
1351d983712dSmrg     * scanlines, DWORD padded.
1352d983712dSmrg     */
1353d983712dSmrg    req_videoram = 3 * ((pScrn->virtualX + 31) / 32) * 4;
1354d983712dSmrg    if (offscreen_videoram < req_videoram) {
1355d983712dSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, v,
1356d983712dSmrg	    "Accelerated color expansion disabled (%d more bytes of free video memory required)\n",
1357d983712dSmrg	    req_videoram - offscreen_videoram);
1358d983712dSmrg	pTseng->AccelColorExpandBufferOffsets[0] = 0;
1359d983712dSmrg    } else {
1360d983712dSmrg	offscreen_videoram -= req_videoram;
1361d983712dSmrg	for (i = 0; i < 3; i++) {
1362d983712dSmrg	    videoram_end -= req_videoram / 3;
1363d983712dSmrg	    pTseng->AccelColorExpandBufferOffsets[i] = videoram_end;
1364d983712dSmrg	}
1365d983712dSmrg    }
1366d983712dSmrg
1367d983712dSmrg    /*
1368d983712dSmrg     * XAA ImageWrite support needs two entire line buffers. The
1369d983712dSmrg     * current code assumes buffer 1 lies in the same 8kb aperture as
1370d983712dSmrg     * buffer 0.
1371d983712dSmrg     *
1372d983712dSmrg     * [ FIXME: aren't we forgetting the DWORD padding here ? ]
1373d983712dSmrg     * [ FIXME: why here double-buffering and in colexp triple-buffering? ]
1374d983712dSmrg     */
1375d983712dSmrg    req_videoram = 2 * (pScrn->virtualX * pTseng->Bytesperpixel);
1376d983712dSmrg
1377d983712dSmrg    if (offscreen_videoram < req_videoram) {
1378d983712dSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, v,
1379d983712dSmrg	    "Accelerated ImageWrites disabled (%d more bytes of free video memory required)\n",
1380d983712dSmrg	    req_videoram - offscreen_videoram);
1381d983712dSmrg	pTseng->AccelImageWriteBufferOffsets[0] = 0;
1382d983712dSmrg    } else {
1383d983712dSmrg	offscreen_videoram -= req_videoram;
1384d983712dSmrg	for (i = 0; i < 2; i++) {
1385d983712dSmrg	    videoram_end -= req_videoram / 2;
1386d983712dSmrg	    pTseng->AccelImageWriteBufferOffsets[i] = videoram_end;
1387d983712dSmrg	}
1388d983712dSmrg    }
1389d983712dSmrg
1390d983712dSmrg    xf86DrvMsgVerb(scrnIndex, X_INFO, v,
1391d983712dSmrg	"Remaining off-screen memory available for pixmap cache: %d bytes.\n",
1392d983712dSmrg	offscreen_videoram);
1393d983712dSmrg
1394d983712dSmrgend_memsetup:
1395d983712dSmrg    pScrn->videoRam = videoram_end / 1024;
1396d983712dSmrg}
1397d983712dSmrg
1398d983712dSmrgstatic Bool
1399d983712dSmrgTsengScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
1400d983712dSmrg{
1401d983712dSmrg    ScrnInfoPtr pScrn;
1402d983712dSmrg    TsengPtr pTseng;
1403d983712dSmrg    int ret;
1404d983712dSmrg    VisualPtr visual;
1405d983712dSmrg
1406d983712dSmrg    PDEBUG("	TsengScreenInit\n");
1407d983712dSmrg
1408d983712dSmrg    /*
1409d983712dSmrg     * First get the ScrnInfoRec
1410d983712dSmrg     */
1411d983712dSmrg    pScrn = xf86Screens[pScreen->myNum];
1412d983712dSmrg
1413d983712dSmrg    pTseng = TsengPTR(pScrn);
1414d983712dSmrg    /* Map the Tseng memory areas */
1415d983712dSmrg    if (!TsengMapMem(pScrn))
1416d983712dSmrg	return FALSE;
1417d983712dSmrg
1418d983712dSmrg    /* Save the current state */
1419d983712dSmrg    TsengSave(pScrn);
1420d983712dSmrg
1421d983712dSmrg    /* Initialise the first mode */
1422d983712dSmrg    TsengModeInit(pScrn, pScrn->currentMode);
1423d983712dSmrg
1424d983712dSmrg    /* Darken the screen for aesthetic reasons and set the viewport */
1425d983712dSmrg    TsengSaveScreen(pScreen, SCREEN_SAVER_ON);
1426d983712dSmrg
1427d983712dSmrg    TsengAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
1428d983712dSmrg    /* XXX Fill the screen with black */
1429d983712dSmrg
1430d983712dSmrg    /*
1431d983712dSmrg     * Reset visual list.
1432d983712dSmrg     */
1433d983712dSmrg    miClearVisualTypes();
1434d983712dSmrg
1435d983712dSmrg    /* Setup the visuals we support. */
1436d983712dSmrg
1437d983712dSmrg    /*
1438d983712dSmrg     * For bpp > 8, the default visuals are not acceptable because we only
1439d983712dSmrg     * support TrueColor and not DirectColor.  To deal with this, call
1440d983712dSmrg     * miSetVisualTypes for each visual supported.
1441d983712dSmrg     */
1442d983712dSmrg    if (!miSetVisualTypes(pScrn->depth, miGetDefaultVisualMask(pScrn->depth),
1443d983712dSmrg			  pScrn->rgbBits, pScrn->defaultVisual))
1444d983712dSmrg      return FALSE;
1445d983712dSmrg
1446d983712dSmrg    miSetPixmapDepths ();
1447d983712dSmrg
1448d983712dSmrg    /*
1449d983712dSmrg     * Call the framebuffer layer's ScreenInit function, and fill in other
1450d983712dSmrg     * pScreen fields.
1451d983712dSmrg     */
1452d983712dSmrg
1453d983712dSmrg    switch (pScrn->bitsPerPixel) {
1454d983712dSmrg    case 1:
1455d983712dSmrg	ret = xf1bppScreenInit(pScreen, pTseng->FbBase,
1456d983712dSmrg			pScrn->virtualX, pScrn->virtualY,
1457d983712dSmrg			pScrn->xDpi, pScrn->yDpi,
1458d983712dSmrg			pScrn->displayWidth);
1459d983712dSmrg	break;
1460d983712dSmrg    case 4:
1461d983712dSmrg	ret = xf4bppScreenInit(pScreen, pTseng->FbBase,
1462d983712dSmrg			pScrn->virtualX, pScrn->virtualY,
1463d983712dSmrg			pScrn->xDpi, pScrn->yDpi,
1464d983712dSmrg			pScrn->displayWidth);
1465d983712dSmrg	break;
1466d983712dSmrg    default:
1467d983712dSmrg        ret  = fbScreenInit(pScreen, pTseng->FbBase,
1468d983712dSmrg			pScrn->virtualX, pScrn->virtualY,
1469d983712dSmrg			pScrn->xDpi, pScrn->yDpi,
1470d983712dSmrg			pScrn->displayWidth, pScrn->bitsPerPixel);
1471d983712dSmrg	break;
1472d983712dSmrg    }
1473d983712dSmrg
1474d983712dSmrg    if (!ret)
1475d983712dSmrg	return FALSE;
1476d983712dSmrg
1477d983712dSmrg    xf86SetBlackWhitePixels(pScreen);
1478d983712dSmrg
1479d983712dSmrg    if (pScrn->bitsPerPixel > 8) {
1480d983712dSmrg	/* Fixup RGB ordering */
1481d983712dSmrg	visual = pScreen->visuals + pScreen->numVisuals;
1482d983712dSmrg	while (--visual >= pScreen->visuals) {
1483d983712dSmrg	    if ((visual->class | DynamicClass) == DirectColor) {
1484d983712dSmrg		visual->offsetRed = pScrn->offset.red;
1485d983712dSmrg		visual->offsetGreen = pScrn->offset.green;
1486d983712dSmrg		visual->offsetBlue = pScrn->offset.blue;
1487d983712dSmrg		visual->redMask = pScrn->mask.red;
1488d983712dSmrg		visual->greenMask = pScrn->mask.green;
1489d983712dSmrg		visual->blueMask = pScrn->mask.blue;
1490d983712dSmrg	    }
1491d983712dSmrg	}
1492d983712dSmrg    }
1493d983712dSmrg
1494d983712dSmrg    /* must be after RGB ordering fixed */
1495d983712dSmrg    if (pScrn->bitsPerPixel > 4)
1496d983712dSmrg	fbPictureInit(pScreen, 0, 0);
1497d983712dSmrg
1498d983712dSmrg    if (pScrn->depth >= 8)
1499d983712dSmrg        TsengDGAInit(pScreen);
1500d983712dSmrg
1501d983712dSmrg    /*
1502d983712dSmrg     * Initialize the acceleration interface.
1503d983712dSmrg     */
1504d983712dSmrg    TsengSetupAccelMemory(scrnIndex, pScreen);
1505d983712dSmrg    if (pTseng->UseAccel) {
1506d983712dSmrg	tseng_init_acl(pScrn);	/* set up accelerator */
1507d983712dSmrg	if (!TsengXAAInit(pScreen)) {	/* set up XAA interface */
1508d983712dSmrg	    return FALSE;
1509d983712dSmrg	}
1510d983712dSmrg    }
1511d983712dSmrg
1512d983712dSmrg    miInitializeBackingStore(pScreen);
1513d983712dSmrg    xf86SetSilkenMouse(pScreen);
1514d983712dSmrg    /* Initialise cursor functions */
1515d983712dSmrg    miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
1516d983712dSmrg
1517d983712dSmrg    /* Hardware Cursor layer */
1518d983712dSmrg    if (pTseng->HWCursor) {
1519d983712dSmrg	if (!TsengHWCursorInit(pScreen))
1520d983712dSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1521d983712dSmrg		"Hardware cursor initialization failed\n");
1522d983712dSmrg    }
1523d983712dSmrg
1524d983712dSmrg    /* Initialise default colourmap */
1525d983712dSmrg    if (!miCreateDefColormap(pScreen))
1526d983712dSmrg	return FALSE;
1527d983712dSmrg
1528d983712dSmrg    if (pScrn->depth == 4 || pScrn->depth == 8) { /* fb and xf4bpp */
1529d983712dSmrg	vgaHWHandleColormaps(pScreen);
1530d983712dSmrg    }
1531d983712dSmrg    pScrn->racIoFlags = RAC_FB | RAC_COLORMAP | RAC_CURSOR | RAC_VIEWPORT;
1532d983712dSmrg    pScrn->racMemFlags = pScrn->racIoFlags;
1533d983712dSmrg
1534d983712dSmrg    /* Wrap the current CloseScreen and SaveScreen functions */
1535d983712dSmrg    pScreen->SaveScreen = TsengSaveScreen;
1536d983712dSmrg
1537d983712dSmrg    /* Support for DPMS, the ET4000W32Pc and newer uses a different and
1538d983712dSmrg     * simpler method than the older cards.
1539d983712dSmrg     */
1540d983712dSmrg    if ((pTseng->ChipType == ET4000) &&
1541d983712dSmrg        ((pTseng->ChipRev == REV_A) || (pTseng->ChipRev == REV_B)))
1542d983712dSmrg        xf86DPMSInit(pScreen, (DPMSSetProcPtr)TsengHVSyncDPMSSet, 0);
1543d983712dSmrg    else
1544d983712dSmrg	xf86DPMSInit(pScreen, (DPMSSetProcPtr)TsengCrtcDPMSSet, 0);
1545d983712dSmrg
1546d983712dSmrg    pTseng->CloseScreen = pScreen->CloseScreen;
1547d983712dSmrg    pScreen->CloseScreen = TsengCloseScreen;
1548d983712dSmrg
1549d983712dSmrg    /* Report any unused options (only for the first generation) */
1550d983712dSmrg    if (serverGeneration == 1) {
1551d983712dSmrg	xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
1552d983712dSmrg    }
1553d983712dSmrg    /* Done */
1554d983712dSmrg    return TRUE;
1555d983712dSmrg}
1556d983712dSmrg
1557d983712dSmrgstatic Bool
1558d983712dSmrgTsengEnterVT(int scrnIndex, int flags)
1559d983712dSmrg{
1560d983712dSmrg    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1561d983712dSmrg    TsengPtr pTseng = TsengPTR(pScrn);
1562d983712dSmrg
1563d983712dSmrg    PDEBUG("	TsengEnterVT\n");
1564d983712dSmrg
1565d983712dSmrg    vgaHWUnlock(VGAHWPTR(pScrn));
1566d983712dSmrg    TsengUnlock(pScrn);
1567d983712dSmrg
1568d983712dSmrg    if (!TsengModeInit(pScrn, pScrn->currentMode))
1569d983712dSmrg        return FALSE;
1570d983712dSmrg    if (pTseng->UseAccel) {
1571d983712dSmrg	tseng_init_acl(pScrn);	/* set up accelerator */
1572d983712dSmrg    }
1573d983712dSmrg    return TRUE;
1574d983712dSmrg}
1575d983712dSmrg
1576d983712dSmrgstatic void
1577d983712dSmrgTsengLeaveVT(int scrnIndex, int flags)
1578d983712dSmrg{
1579d983712dSmrg    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1580d983712dSmrg    TsengPtr pTseng = TsengPTR(pScrn);
1581d983712dSmrg
1582d983712dSmrg    PDEBUG("	TsengLeaveVT\n");
1583d983712dSmrg    TsengRestore(pScrn, &(VGAHWPTR(pScrn)->SavedReg),
1584d983712dSmrg		 &pTseng->SavedReg,VGA_SR_ALL);
1585d983712dSmrg
1586d983712dSmrg    TsengLock(pScrn);
1587d983712dSmrg    vgaHWLock(VGAHWPTR(pScrn));
1588d983712dSmrg}
1589d983712dSmrg
1590d983712dSmrgstatic Bool
1591d983712dSmrgTsengCloseScreen(int scrnIndex, ScreenPtr pScreen)
1592d983712dSmrg{
1593d983712dSmrg    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1594d983712dSmrg    TsengPtr pTseng = TsengPTR(pScrn);
1595d983712dSmrg
1596d983712dSmrg    PDEBUG("	TsengCloseScreen\n");
1597d983712dSmrg
1598d983712dSmrg    if (pScrn->vtSema) {
1599d983712dSmrg    TsengRestore(pScrn, &(VGAHWPTR(pScrn)->SavedReg),
1600d983712dSmrg		 &(pTseng->SavedReg),VGA_SR_ALL);
1601d983712dSmrg    TsengUnmapMem(pScrn);
1602d983712dSmrg    }
1603d983712dSmrg    if (pTseng->AccelInfoRec)
1604d983712dSmrg	XAADestroyInfoRec(pTseng->AccelInfoRec);
1605d983712dSmrg    if (pTseng->CursorInfoRec)
1606d983712dSmrg	xf86DestroyCursorInfoRec(pTseng->CursorInfoRec);
1607d983712dSmrg
1608d983712dSmrg    pScrn->vtSema = FALSE;
1609d983712dSmrg
1610d983712dSmrg    pScreen->CloseScreen = pTseng->CloseScreen;
1611d983712dSmrg    return (*pScreen->CloseScreen) (scrnIndex, pScreen);
1612d983712dSmrg}
1613d983712dSmrg
1614d983712dSmrg/*
1615d983712dSmrg * SaveScreen --
1616d983712dSmrg *
1617d983712dSmrg *   perform a sequencer reset.
1618d983712dSmrg *
1619d983712dSmrg * The ET4000 "Video System Configuration 1" register (CRTC index 0x36),
1620d983712dSmrg * which is used to set linear memory mode and MMU-related stuff, is
1621d983712dSmrg * partially reset to "0" when TS register index 0 bit 1 is set (synchronous
1622d983712dSmrg * reset): bits 3..5 are reset during a sync. reset.
1623d983712dSmrg *
1624d983712dSmrg * We therefor do _not_ call vgaHWSaveScreen here, since it does a sequencer
1625d983712dSmrg * reset. Instead, we do the same as in vgaHWSaveScreen except for the seq. reset.
1626d983712dSmrg *
1627d983712dSmrg * If this is not done, the higher level code will not be able to access the
1628d983712dSmrg * framebuffer (because it is temporarily in banked mode instead of linear
1629d983712dSmrg * mode) as long as SaveScreen is active (=in between a
1630d983712dSmrg * SaveScreen(FALSE)/SaveScreen(TRUE) pair)
1631d983712dSmrg */
1632d983712dSmrg
1633d983712dSmrgstatic Bool
1634d983712dSmrgTsengSaveScreen(ScreenPtr pScreen, int mode)
1635d983712dSmrg{
1636d983712dSmrg    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
1637d983712dSmrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
1638d983712dSmrg    TsengPtr pTseng = TsengPTR(pScrn);
1639d983712dSmrg    Bool unblank;
1640d983712dSmrg
1641d983712dSmrg    PDEBUG("	TsengSaveScreen\n");
1642d983712dSmrg
1643d983712dSmrg    unblank = xf86IsUnblank(mode);
1644d983712dSmrg
1645d983712dSmrg    if (pTseng->ChipType == ET6000) {
1646d983712dSmrg	return vgaHWSaveScreen(pScreen, unblank);
1647d983712dSmrg    } else {
1648d983712dSmrg       if (unblank)
1649d983712dSmrg	  SetTimeSinceLastInputEvent();
1650d983712dSmrg
1651d983712dSmrg       if (pScrn->vtSema) {
1652d983712dSmrg           /* vgaHWBlankScreen without seq reset */
1653d983712dSmrg           CARD8 scrn;
1654d983712dSmrg
1655d983712dSmrg           scrn = hwp->readSeq(hwp, 0x01);
1656d983712dSmrg
1657d983712dSmrg           if (unblank)
1658d983712dSmrg               scrn &= 0xDF; /* enable screen */
1659d983712dSmrg           else
1660d983712dSmrg               scrn |= 0x20; /* blank screen */
1661d983712dSmrg
1662d983712dSmrg           hwp->writeSeq(hwp, 0x01, scrn); /* change mode */
1663d983712dSmrg       }
1664d983712dSmrg       return (TRUE);
1665d983712dSmrg    }
1666d983712dSmrg}
1667d983712dSmrg
1668d983712dSmrgstatic Bool
1669d983712dSmrgTsengMapMem(ScrnInfoPtr pScrn)
1670d983712dSmrg{
1671d983712dSmrg    TsengPtr pTseng = TsengPTR(pScrn);
1672d983712dSmrg
1673d983712dSmrg    PDEBUG("	TsengMapMem\n");
1674d983712dSmrg
1675d983712dSmrg    /* Map the VGA memory */
1676d983712dSmrg
1677d983712dSmrg    if (!vgaHWMapMem(pScrn)) {
1678d983712dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1679d983712dSmrg	    "Could not mmap standard VGA memory aperture.\n");
1680d983712dSmrg	return FALSE;
1681d983712dSmrg    }
1682d983712dSmrg
1683d983712dSmrg    pTseng->FbBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
1684d983712dSmrg                                   pTseng->PciTag,
1685d983712dSmrg                                   (unsigned long)pTseng->FbAddress,
1686d983712dSmrg                                   pTseng->FbMapSize);
1687d983712dSmrg    if (pTseng->FbBase == NULL) {
1688d983712dSmrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1689d983712dSmrg                   "Could not mmap linear video memory.\n");
1690d983712dSmrg        return FALSE;
1691d983712dSmrg    }
1692d983712dSmrg
1693d983712dSmrg    /* need some sanity here */
1694d983712dSmrg    if (pTseng->UseAccel) {
1695d983712dSmrg        pTseng->MMioBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
1696d983712dSmrg                                         pTseng->PciTag,
1697d983712dSmrg                                         (unsigned long)pTseng->FbAddress,
1698d983712dSmrg                                         pTseng->FbMapSize);
1699d983712dSmrg        if (!pTseng->MMioBase) {
1700d983712dSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1701d983712dSmrg		       "Could not mmap mmio memory.\n");
1702d983712dSmrg	    return FALSE;
1703d983712dSmrg        }
1704d983712dSmrg        pTseng->MMioBase += 0x3FFF00L;
1705d983712dSmrg    }
1706d983712dSmrg
1707d983712dSmrg    if (pTseng->FbBase == NULL)
1708d983712dSmrg	return FALSE;
1709d983712dSmrg
1710d983712dSmrg    return TRUE;
1711d983712dSmrg}
1712d983712dSmrg
1713d983712dSmrgstatic Bool
1714d983712dSmrgTsengUnmapMem(ScrnInfoPtr pScrn)
1715d983712dSmrg{
1716d983712dSmrg    TsengPtr pTseng = TsengPTR(pScrn);
1717d983712dSmrg
1718d983712dSmrg    PDEBUG("	TsengUnmapMem\n");
1719d983712dSmrg
1720d983712dSmrg    xf86UnMapVidMem(pScrn->scrnIndex, (pointer) pTseng->FbBase, pTseng->FbMapSize);
1721d983712dSmrg
1722d983712dSmrg    vgaHWUnmapMem(pScrn);
1723d983712dSmrg
1724d983712dSmrg    pTseng->FbBase = NULL;
1725d983712dSmrg
1726d983712dSmrg    return TRUE;
1727d983712dSmrg}
1728d983712dSmrg
1729d983712dSmrgstatic void
1730d983712dSmrgTsengFreeScreen(int scrnIndex, int flags)
1731d983712dSmrg{
1732d983712dSmrg    PDEBUG("	TsengFreeScreen\n");
1733d983712dSmrg    if (xf86LoaderCheckSymbol("vgaHWFreeHWRec"))
1734d983712dSmrg	vgaHWFreeHWRec(xf86Screens[scrnIndex]);
1735d983712dSmrg    TsengFreeRec(xf86Screens[scrnIndex]);
1736d983712dSmrg}
1737d983712dSmrg
1738d983712dSmrgstatic Bool
1739d983712dSmrgTsengSwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
1740d983712dSmrg{
1741d983712dSmrg    PDEBUG("	TsengSwitchMode\n");
1742d983712dSmrg    return TsengModeInit(xf86Screens[scrnIndex], mode);
1743d983712dSmrg}
1744