ag10e_driver.c revision 98bb403a
1/*
2 * Fujitsu AG-10e framebuffer driver.
3 *
4 * Copyright (C) 2007 Michael Lorenz
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * JAKUB JELINEK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/suncg6/cg6_driver.c,v 1.12 2005/02/18 02:55:09 dawes Exp $ */
24
25/* need this for PRIxPTR macro */
26
27#ifdef HAVE_CONFIG_H
28#include "config.h"
29#endif
30
31#include <fcntl.h>
32#include <sys/time.h>
33#include <sys/types.h>
34#include <dev/sun/fbio.h>
35#include <dev/wscons/wsconsio.h>
36
37#include <machine/int_fmtio.h>
38#include "xf86.h"
39#include "xf86_OSproc.h"
40#include "xf86_ansic.h"
41#include "xf86Version.h"
42#include "mipointer.h"
43#include "mibstore.h"
44#include "micmap.h"
45
46#include "fb.h"
47#include "xf86cmap.h"
48#include "ag10e.h"
49#include "xf86sbusBus.h"
50
51static const OptionInfoRec * AG10EAvailableOptions(int chipid, int busid);
52static void	AG10EIdentify(int flags);
53static Bool	AG10EProbe(DriverPtr drv, int flags);
54static Bool	AG10EPreInit(ScrnInfoPtr pScrn, int flags);
55static Bool	AG10EScreenInit(int Index, ScreenPtr pScreen, int argc,
56			      char **argv);
57static Bool	AG10EEnterVT(int scrnIndex, int flags);
58static void	AG10ELeaveVT(int scrnIndex, int flags);
59static Bool	AG10ECloseScreen(int scrnIndex, ScreenPtr pScreen);
60static Bool	AG10ESaveScreen(ScreenPtr pScreen, int mode);
61
62/* Required if the driver supports mode switching */
63static Bool	AG10ESwitchMode(int scrnIndex, DisplayModePtr mode, int flags);
64/* Required if the driver supports moving the viewport */
65static void	AG10EAdjustFrame(int scrnIndex, int x, int y, int flags);
66
67/* Optional functions */
68static void	AG10EFreeScreen(int scrnIndex, int flags);
69static ModeStatus AG10EValidMode(int scrnIndex, DisplayModePtr mode,
70			       Bool verbose, int flags);
71
72#define VERSION 4000
73#define AG10E_NAME "AG10E"
74#define AG10E_DRIVER_NAME "ag10e"
75#define AG10E_MAJOR_VERSION 1
76#define AG10E_MINOR_VERSION 0
77#define AG10E_PATCHLEVEL 0
78
79/*
80 * This contains the functions needed by the server after loading the driver
81 * module.  It must be supplied, and gets passed back by the SetupProc
82 * function in the dynamic case.  In the static case, a reference to this
83 * is compiled in, and this requires that the name of this DriverRec be
84 * an upper-case version of the driver name.
85 */
86
87DriverRec AG10E = {
88    VERSION,
89    AG10E_DRIVER_NAME,
90    AG10EIdentify,
91    AG10EProbe,
92    AG10EAvailableOptions,
93    NULL,
94    0
95};
96
97typedef enum {
98    OPTION_SW_CURSOR,
99    OPTION_HW_CURSOR,
100    OPTION_NOACCEL
101} AG10EOpts;
102
103static const OptionInfoRec AG10EOptions[] = {
104    { OPTION_SW_CURSOR,		"SWcursor",	OPTV_BOOLEAN,	{0}, FALSE },
105    { OPTION_HW_CURSOR,		"HWcursor",	OPTV_BOOLEAN,	{0}, FALSE },
106    { OPTION_NOACCEL,		"NoAccel",	OPTV_BOOLEAN,	{0}, FALSE },
107    { -1,			NULL,		OPTV_NONE,	{0}, FALSE }
108};
109
110static const char *xaaSymbols[] =
111{
112    "XAACreateInfoRec",
113    "XAADestroyInfoRec",
114    "XAAInit",
115    NULL
116};
117
118#ifdef XFree86LOADER
119
120static MODULESETUPPROTO(AG10ESetup);
121
122static XF86ModuleVersionInfo AG10EVersRec =
123{
124	"ag10e",
125	MODULEVENDORSTRING,
126	MODINFOSTRING1,
127	MODINFOSTRING2,
128	XORG_VERSION_CURRENT,
129	AG10E_MAJOR_VERSION, AG10E_MINOR_VERSION, AG10E_PATCHLEVEL,
130	ABI_CLASS_VIDEODRV,
131	ABI_VIDEODRV_VERSION,
132	MOD_CLASS_VIDEODRV,
133	{0,0,0,0}
134};
135
136_X_EXPORT XF86ModuleData ag10eModuleData = { &AG10EVersRec, AG10ESetup, NULL };
137
138static pointer
139AG10ESetup(pointer module, pointer opts, int *errmaj, int *errmin)
140{
141    static Bool setupDone = FALSE;
142
143    if (!setupDone) {
144	setupDone = TRUE;
145	xf86AddDriver(&AG10E, module, 0);
146
147	/*
148	 * Modules that this driver always requires can be loaded here
149	 * by calling LoadSubModule().
150	 */
151	LoaderRefSymLists(xaaSymbols, NULL);
152
153	/*
154	 * The return value must be non-NULL on success even though there
155	 * is no TearDownProc.
156	 */
157	return (pointer)TRUE;
158    } else {
159	if (errmaj) *errmaj = LDR_ONCEONLY;
160	return NULL;
161    }
162}
163
164#endif /* XFree86LOADER */
165
166static Bool
167AG10EGetRec(ScrnInfoPtr pScrn)
168{
169    /*
170     * Allocate an AG10ERec, and hook it into pScrn->driverPrivate.
171     * pScrn->driverPrivate is initialised to NULL, so we can check if
172     * the allocation has already been done.
173     */
174    if (pScrn->driverPrivate != NULL)
175	return TRUE;
176
177    pScrn->driverPrivate = xnfcalloc(sizeof(AG10ERec), 1);
178    return TRUE;
179}
180
181static void
182AG10EFreeRec(ScrnInfoPtr pScrn)
183{
184    AG10EPtr pAG10E;
185
186    if (pScrn->driverPrivate == NULL)
187	return;
188
189    pAG10E = GET_AG10E_FROM_SCRN(pScrn);
190
191    xfree(pScrn->driverPrivate);
192    pScrn->driverPrivate = NULL;
193
194    return;
195}
196
197static const OptionInfoRec *
198AG10EAvailableOptions(int chipid, int busid)
199{
200    return AG10EOptions;
201}
202
203/* Mandatory */
204static void
205AG10EIdentify(int flags)
206{
207    xf86Msg(X_INFO, "%s: driver for Fujitsu AG-10e\n", AG10E_NAME);
208}
209
210
211/* Mandatory */
212static Bool
213AG10EProbe(DriverPtr drv, int flags)
214{
215    int i;
216    GDevPtr *devSections;
217    int *usedChips;
218    int numDevSections;
219    int numUsed;
220    Bool foundScreen = FALSE;
221    EntityInfoPtr pEnt;
222
223    /*
224     * The aim here is to find all cards that this driver can handle,
225     * and for the ones not already claimed by another driver, claim the
226     * slot, and allocate a ScrnInfoRec.
227     *
228     * This should be a minimal probe, and it should under no circumstances
229     * change the state of the hardware.  Because a device is found, don't
230     * assume that it will be used.  Don't do any initialisations other than
231     * the required ScrnInfoRec initialisations.  Don't allocate any new
232     * data structures.
233     */
234
235    /*
236     * Next we check, if there has been a chipset override in the config file.
237     * For this we must find out if there is an active device section which
238     * is relevant, i.e., which has no driver specified or has THIS driver
239     * specified.
240     */
241
242    if ((numDevSections = xf86MatchDevice(AG10E_DRIVER_NAME,
243					  &devSections)) <= 0) {
244	/*
245	 * There's no matching device section in the config file, so quit
246	 * now.
247	 */
248	return FALSE;
249    }
250
251    /*
252     * We need to probe the hardware first.  We then need to see how this
253     * fits in with what is given in the config file, and allow the config
254     * file info to override any contradictions.
255     */
256
257    numUsed = xf86MatchSbusInstances(AG10E_NAME, SBUS_DEVICE_AG10E,
258		   devSections, numDevSections,
259		   drv, &usedChips);
260
261    xfree(devSections);
262    if (numUsed <= 0)
263	return FALSE;
264
265    if (flags & PROBE_DETECT)
266	foundScreen = TRUE;
267    else for (i = 0; i < numUsed; i++) {
268	pEnt = xf86GetEntityInfo(usedChips[i]);
269
270	/*
271	 * Check that nothing else has claimed the slots.
272	 */
273	if(pEnt->active) {
274	    ScrnInfoPtr pScrn;
275
276	    /* Allocate a ScrnInfoRec and claim the slot */
277	    pScrn = xf86AllocateScreen(drv, 0);
278
279	    /* Fill in what we can of the ScrnInfoRec */
280	    pScrn->driverVersion = VERSION;
281	    pScrn->driverName	 = AG10E_DRIVER_NAME;
282	    pScrn->name		 = AG10E_NAME;
283	    pScrn->Probe	 = AG10EProbe;
284	    pScrn->PreInit	 = AG10EPreInit;
285	    pScrn->ScreenInit	 = AG10EScreenInit;
286	    pScrn->SwitchMode	 = AG10ESwitchMode;
287	    pScrn->AdjustFrame	 = AG10EAdjustFrame;
288	    pScrn->EnterVT	 = AG10EEnterVT;
289	    pScrn->LeaveVT	 = AG10ELeaveVT;
290	    pScrn->FreeScreen	 = AG10EFreeScreen;
291	    pScrn->ValidMode	 = AG10EValidMode;
292	    xf86AddEntityToScreen(pScrn, pEnt->index);
293	    foundScreen = TRUE;
294	}
295	xfree(pEnt);
296    }
297    xfree(usedChips);
298    return foundScreen;
299}
300
301/* Mandatory */
302static Bool
303AG10EPreInit(ScrnInfoPtr pScrn, int flags)
304{
305    AG10EPtr pAG10E;
306    sbusDevicePtr psdp;
307    rgb defaultWeight = {0, 0, 0};
308    MessageType from;
309    int i;
310
311    if (flags & PROBE_DETECT) return FALSE;
312
313    /*
314     * Note: This function is only called once at server startup, and
315     * not at the start of each server generation.  This means that
316     * only things that are persistent across server generations can
317     * be initialised here.  xf86Screens[] is (pScrn is a pointer to one
318     * of these).  Privates allocated using xf86AllocateScrnInfoPrivateIndex()
319     * are too, and should be used for data that must persist across
320     * server generations.
321     *
322     * Per-generation data should be allocated with
323     * AllocateScreenPrivateIndex() from the ScreenInit() function.
324     */
325
326    /* Allocate the AG10ERec driverPrivate */
327    if (!AG10EGetRec(pScrn)) {
328	return FALSE;
329    }
330    pAG10E = GET_AG10E_FROM_SCRN(pScrn);
331
332    /* Set pScrn->monitor */
333    pScrn->monitor = pScrn->confScreen->monitor;
334
335    /* This driver doesn't expect more than one entity per screen */
336    if (pScrn->numEntities > 1)
337	return FALSE;
338    /* This is the general case */
339    for (i = 0; i < pScrn->numEntities; i++) {
340	EntityInfoPtr pEnt = xf86GetEntityInfo(pScrn->entityList[i]);
341
342	/* AG10E is purely SBUS */
343	if (pEnt->location.type == BUS_SBUS) {
344	    psdp = xf86GetSbusInfoForEntity(pEnt->index);
345	    pAG10E->psdp = psdp;
346	} else
347	    return FALSE;
348    }
349
350    /*********************
351    deal with depth
352    *********************/
353
354    if (!xf86SetDepthBpp(pScrn, 0, 0, 0, Support32bppFb)) {
355	return FALSE;
356    } else {
357	/* Check that the returned depth is one we support */
358	switch (pScrn->depth) {
359	case 24:
360	    /* OK */
361	    break;
362	default:
363	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
364		       "Given depth (%d) is not supported by this driver\n",
365		       pScrn->depth);
366	    return FALSE;
367	}
368    }
369
370    /* Collect all of the relevant option flags (fill in pScrn->options) */
371    xf86CollectOptions(pScrn, NULL);
372    /* Process the options */
373    if (!(pAG10E->Options = xalloc(sizeof(AG10EOptions))))
374	return FALSE;
375    memcpy(pAG10E->Options, AG10EOptions, sizeof(AG10EOptions));
376    xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pAG10E->Options);
377
378    /*
379     * The new cmap code requires this to be initialised.
380     * this card supports HW gamma correction with 10 bit resolution - maybe
381     * we should figure out how to use it
382     */
383
384    {
385	Gamma zeros = {0.0, 0.0, 0.0};
386
387	if (!xf86SetGamma(pScrn, zeros)) {
388	    return FALSE;
389	}
390    }
391
392    from = X_DEFAULT;
393    if (!xf86SetWeight(pScrn, defaultWeight, defaultWeight))
394      return FALSE;
395
396    if (!xf86SetDefaultVisual(pScrn, -1))
397	return FALSE;
398
399    /* determine whether we use hardware or software cursor */
400
401    pAG10E->HWCursor = TRUE;
402    if (xf86GetOptValBool(pAG10E->Options, OPTION_HW_CURSOR, &pAG10E->HWCursor))
403	from = X_CONFIG;
404    if (xf86ReturnOptValBool(pAG10E->Options, OPTION_SW_CURSOR, FALSE)) {
405	from = X_CONFIG;
406	pAG10E->HWCursor = FALSE;
407    }
408
409    xf86DrvMsg(pScrn->scrnIndex, from, "Using %s cursor\n",
410		pAG10E->HWCursor ? "HW" : "SW");
411
412    if (xf86ReturnOptValBool(pAG10E->Options, OPTION_NOACCEL, FALSE)) {
413	pAG10E->NoAccel = TRUE;
414	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Acceleration disabled\n");
415    }
416
417    if (xf86LoadSubModule(pScrn, "fb") == NULL) {
418	AG10EFreeRec(pScrn);
419	return FALSE;
420    }
421
422    if (pAG10E->HWCursor && xf86LoadSubModule(pScrn, "ramdac") == NULL) {
423	AG10EFreeRec(pScrn);
424	return FALSE;
425    }
426
427    if (pAG10E->HWCursor && xf86LoadSubModule(pScrn, "xaa") == NULL) {
428	AG10EFreeRec(pScrn);
429	return FALSE;
430    }
431    xf86LoaderReqSymLists(xaaSymbols, NULL);
432
433    /*********************
434    set up clock and mode stuff
435    *********************/
436
437    pScrn->progClock = TRUE;
438
439    if(pScrn->display->virtualX || pScrn->display->virtualY) {
440	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
441		   "AG10E does not support a virtual desktop\n");
442	pScrn->display->virtualX = 0;
443	pScrn->display->virtualY = 0;
444    }
445
446    xf86SbusUseBuiltinMode(pScrn, pAG10E->psdp);
447    pScrn->currentMode = pScrn->modes;
448    pScrn->displayWidth = pScrn->virtualX;
449
450    /* Set display resolution */
451    xf86SetDpi(pScrn, 0, 0);
452
453    return TRUE;
454}
455
456/* Mandatory */
457
458/* This gets called at the start of each server generation */
459
460static Bool
461AG10EScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
462{
463    ScrnInfoPtr pScrn;
464    AG10EPtr pAG10E;
465    struct fbtype fb;
466    sbusDevicePtr psdp;
467    VisualPtr visual;
468    int ret;
469
470    pScrn = xf86Screens[pScreen->myNum];
471    pAG10E = GET_AG10E_FROM_SCRN(pScrn);
472    psdp = pAG10E->psdp;
473
474    /*
475     * for some idiotic reason we need to check if the file descriptor is
476     * really open here
477     */
478    if (psdp->fd == -1) {
479	psdp->fd = open(psdp->device, O_RDWR);
480	if (psdp->fd == -1)
481	    return FALSE;
482    }
483
484    /* figure out how much VRAM we can map */
485    if ((ret = ioctl(pAG10E->psdp->fd, FBIOGTYPE, &fb)) != 0) {
486	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
487	    "ioctl(FBIOGTYPE) failed with %d\n", ret);
488	return FALSE;
489    }
490    pAG10E->vidmem = fb.fb_size;
491
492    /* Map AG10E memory areas */
493
494    pAG10E->regs = xf86MapSbusMem(psdp, pAG10E->vidmem, 0x10000);
495    pAG10E->fb = xf86MapSbusMem(psdp, 0, pAG10E->vidmem);
496
497    if (pAG10E->fb != NULL) {
498        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "mapped %d KB video RAM\n",
499	    pAG10E->vidmem >> 10);
500    }
501
502    if (!pAG10E->regs || !pAG10E->fb) {
503    	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
504		   "xf86MapSbusMem failed regs:%" PRIxPTR " fb:%" PRIxPTR "\n",
505		   pAG10E->regs, pAG10E->fb);
506
507	if (pAG10E->fb) {
508	    xf86UnmapSbusMem(psdp, pAG10E->fb, sizeof(*pAG10E->fb));
509	    pAG10E->fb = NULL;
510	}
511
512	if (pAG10E->regs) {
513	    xf86UnmapSbusMem(psdp, pAG10E->regs, sizeof(*pAG10E->regs));
514	    pAG10E->regs = NULL;
515	}
516
517	return FALSE;
518    }
519    pAG10E->IOOffset = 0;
520    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "vram: %d\n",
521        (1 << ((GLINT_READ_REG(FBMemoryCtl) & 0xE0000000)>>29)) * 1024);
522
523    /*
524     * The next step is to setup the screen's visuals, and initialise the
525     * framebuffer code.  In cases where the framebuffer's default
526     * choices for things like visual layouts and bits per RGB are OK,
527     * this may be as simple as calling the framebuffer's ScreenInit()
528     * function.  If not, the visuals will need to be setup before calling
529     * a fb ScreenInit() function and fixed up after.
530     */
531
532    /*
533     * Reset visual list.
534     */
535    miClearVisualTypes();
536
537    /* Setup the visuals we support. */
538    if (!miSetVisualTypes(pScrn->depth, miGetDefaultVisualMask(pScrn->depth),
539			  pScrn->rgbBits, pScrn->defaultVisual))
540	return FALSE;
541
542    miSetPixmapDepths();
543
544    /*
545     * Call the framebuffer layer's ScreenInit function, and fill in other
546     * pScreen fields.
547     */
548
549    ret = fbScreenInit(pScreen, pAG10E->fb, pScrn->virtualX,
550		       pScrn->virtualY, pScrn->xDpi, pScrn->yDpi,
551		       pScrn->virtualX, pScrn->bitsPerPixel);
552    /*if (!ret)
553	return FALSE;*/
554
555    pAG10E->width=pScrn->virtualX;
556    pAG10E->height=pScrn->virtualY;
557    pAG10E->maxheight=(pAG10E->vidmem / (pAG10E->width << 2)) & 0xffff;
558
559    fbPictureInit(pScreen, 0, 0);
560
561    visual = pScreen->visuals + pScreen->numVisuals;
562    while (--visual >= pScreen->visuals) {
563      if ((visual->class | DynamicClass) == DirectColor) {
564        visual->offsetRed = pScrn->offset.red;
565	visual->offsetGreen = pScrn->offset.green;
566	visual->offsetBlue = pScrn->offset.blue;
567	visual->redMask = pScrn->mask.red;
568	visual->greenMask = pScrn->mask.green;
569	visual->blueMask = pScrn->mask.blue;
570      }
571    }
572
573    miInitializeBackingStore(pScreen);
574    xf86SetBackingStore(pScreen);
575    xf86SetSilkenMouse(pScreen);
576
577    xf86SetBlackWhitePixels(pScreen);
578
579    if (!pAG10E->NoAccel) {
580	if (!AG10EAccelInit(pScreen))
581		return FALSE;
582	xf86Msg(X_INFO, "%s: Using acceleration\n", pAG10E->psdp->device);
583    }
584    /* setup DGA */
585    AG10EDGAInit(pScreen);
586
587    /* Initialise cursor functions */
588    miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
589
590    /* Initialize HW cursor layer.
591       Must follow software cursor initialization*/
592    if (pAG10E->HWCursor) {
593	if(!AG10EHWCursorInit(pScreen)) {
594	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
595		       "Hardware cursor initialization failed\n");
596	    return(FALSE);
597	}
598	xf86SbusHideOsHwCursor(psdp);
599    }
600
601    /* Initialise default colourmap */
602    if (!miCreateDefColormap(pScreen))
603	return FALSE;
604
605    if(!xf86SbusHandleColormaps(pScreen, psdp))
606	return FALSE;
607
608    pAG10E->CloseScreen = pScreen->CloseScreen;
609    pScreen->CloseScreen = AG10ECloseScreen;
610    pScreen->SaveScreen = AG10ESaveScreen;
611
612    /* Report any unused options (only for the first generation) */
613    if (serverGeneration == 1) {
614	xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
615    }
616
617    /* unblank the screen */
618    AG10ESaveScreen(pScreen, SCREEN_SAVER_OFF);
619
620    /* Done */
621    return TRUE;
622}
623
624
625/* Usually mandatory */
626static Bool
627AG10ESwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
628{
629    return TRUE;
630}
631
632
633/*
634 * This function is used to initialize the Start Address - the first
635 * displayed location in the video memory.
636 */
637/* Usually mandatory */
638static void
639AG10EAdjustFrame(int scrnIndex, int x, int y, int flags)
640{
641    /* we don't support virtual desktops */
642    return;
643}
644
645/*
646 * This is called when VT switching back to the X server.  Its job is
647 * to reinitialise the video mode.
648 */
649
650/* Mandatory */
651static Bool
652AG10EEnterVT(int scrnIndex, int flags)
653{
654    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
655    AG10EPtr pAG10E = GET_AG10E_FROM_SCRN(pScrn);
656
657    if (pAG10E->HWCursor) {
658	xf86SbusHideOsHwCursor(pAG10E->psdp);
659    }
660    return TRUE;
661}
662
663
664/*
665 * This is called when VT switching away from the X server.
666 */
667
668/* Mandatory */
669static void
670AG10ELeaveVT(int scrnIndex, int flags)
671{
672    return;
673}
674
675
676/*
677 * This is called at the end of each server generation.  It restores the
678 * original (text) mode.  It should really also unmap the video memory too.
679 */
680
681/* Mandatory */
682static Bool
683AG10ECloseScreen(int scrnIndex, ScreenPtr pScreen)
684{
685    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
686    AG10EPtr pAG10E = GET_AG10E_FROM_SCRN(pScrn);
687    sbusDevicePtr psdp = pAG10E->psdp;
688
689    pScrn->vtSema = FALSE;
690
691    xf86UnmapSbusMem(psdp, pAG10E->regs, 0x10000);
692    xf86UnmapSbusMem(psdp, pAG10E->fb, pAG10E->vidmem);
693
694    if (pAG10E->HWCursor)
695	xf86SbusHideOsHwCursor(psdp);
696
697    pScreen->CloseScreen = pAG10E->CloseScreen;
698    return (*pScreen->CloseScreen)(scrnIndex, pScreen);
699    return FALSE;
700}
701
702
703/* Free up any per-generation data structures */
704
705/* Optional */
706static void
707AG10EFreeScreen(int scrnIndex, int flags)
708{
709    AG10EFreeRec(xf86Screens[scrnIndex]);
710}
711
712
713/* Checks if a mode is suitable for the selected chipset. */
714
715/* Optional */
716static ModeStatus
717AG10EValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags)
718{
719    if (mode->Flags & V_INTERLACE)
720	return(MODE_NO_INTERLACE);
721
722    return(MODE_OK);
723}
724
725/* Do screen blanking */
726
727/* Mandatory */
728static Bool
729AG10ESaveScreen(ScreenPtr pScreen, int mode)
730{
731    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
732    AG10EPtr pAG10E = GET_AG10E_FROM_SCRN(pScrn);
733    int flag;
734
735    switch (mode)
736    {
737	case SCREEN_SAVER_ON:
738	case SCREEN_SAVER_CYCLE:
739	    flag = 0;
740	    ioctl(pAG10E->psdp->fd, FBIOSVIDEO, &flag);
741	    break;
742	case SCREEN_SAVER_OFF:
743	case SCREEN_SAVER_FORCER:
744	    flag = 1;
745	    ioctl(pAG10E->psdp->fd, FBIOSVIDEO, &flag);
746	    break;
747	default:
748	    return FALSE;
749    }
750
751    return TRUE;
752}
753