tcx_driver.c revision e4da13ee
1/*
2 * TCX framebuffer driver.
3 *
4 * Copyright (C) 2000 Jakub Jelinek (jakub@redhat.com)
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
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27
28#include <string.h>
29
30#include "xf86.h"
31#include "xf86_OSproc.h"
32#include "mipointer.h"
33#include "mibstore.h"
34#include "micmap.h"
35
36#include "fb.h"
37#include "xf86cmap.h"
38#include "tcx.h"
39
40static const OptionInfoRec * TCXAvailableOptions(int chipid, int busid);
41static void	TCXIdentify(int flags);
42static Bool	TCXProbe(DriverPtr drv, int flags);
43static Bool	TCXPreInit(ScrnInfoPtr pScrn, int flags);
44static Bool	TCXScreenInit(int Index, ScreenPtr pScreen, int argc,
45			      char **argv);
46static Bool	TCXEnterVT(int scrnIndex, int flags);
47static void	TCXLeaveVT(int scrnIndex, int flags);
48static Bool	TCXCloseScreen(int scrnIndex, ScreenPtr pScreen);
49static Bool	TCXSaveScreen(ScreenPtr pScreen, int mode);
50static void	TCXInitCplane24(ScrnInfoPtr pScrn);
51
52/* Required if the driver supports mode switching */
53static Bool	TCXSwitchMode(int scrnIndex, DisplayModePtr mode, int flags);
54/* Required if the driver supports moving the viewport */
55static void	TCXAdjustFrame(int scrnIndex, int x, int y, int flags);
56
57/* Optional functions */
58static void	TCXFreeScreen(int scrnIndex, int flags);
59static ModeStatus TCXValidMode(int scrnIndex, DisplayModePtr mode,
60			       Bool verbose, int flags);
61
62void TCXSync(ScrnInfoPtr pScrn);
63
64#define TCX_VERSION 4000
65#define TCX_NAME "SUNTCX"
66#define TCX_DRIVER_NAME "suntcx"
67#define TCX_MAJOR_VERSION PACKAGE_VERSION_MAJOR
68#define TCX_MINOR_VERSION PACKAGE_VERSION_MINOR
69#define TCX_PATCHLEVEL PACKAGE_VERSION_PATCHLEVEL
70
71/*
72 * This contains the functions needed by the server after loading the driver
73 * module.  It must be supplied, and gets passed back by the SetupProc
74 * function in the dynamic case.  In the static case, a reference to this
75 * is compiled in, and this requires that the name of this DriverRec be
76 * an upper-case version of the driver name.
77 */
78
79_X_EXPORT DriverRec SUNTCX = {
80    TCX_VERSION,
81    TCX_DRIVER_NAME,
82    TCXIdentify,
83    TCXProbe,
84    TCXAvailableOptions,
85    NULL,
86    0
87};
88
89typedef enum {
90    OPTION_SW_CURSOR,
91    OPTION_HW_CURSOR
92} TCXOpts;
93
94static const OptionInfoRec TCXOptions[] = {
95    { OPTION_SW_CURSOR,		"SWcursor",	OPTV_BOOLEAN,	{0}, FALSE },
96    { OPTION_HW_CURSOR,		"HWcursor",	OPTV_BOOLEAN,	{0}, FALSE },
97    { -1,			NULL,		OPTV_NONE,	{0}, FALSE }
98};
99
100#ifdef XFree86LOADER
101
102static MODULESETUPPROTO(tcxSetup);
103
104static XF86ModuleVersionInfo suntcxVersRec =
105{
106	"suntcx",
107	MODULEVENDORSTRING,
108	MODINFOSTRING1,
109	MODINFOSTRING2,
110	XORG_VERSION_CURRENT,
111	TCX_MAJOR_VERSION, TCX_MINOR_VERSION, TCX_PATCHLEVEL,
112	ABI_CLASS_VIDEODRV,
113	ABI_VIDEODRV_VERSION,
114	MOD_CLASS_VIDEODRV,
115	{0,0,0,0}
116};
117
118_X_EXPORT XF86ModuleData suntcxModuleData = { &suntcxVersRec, tcxSetup, NULL };
119
120pointer
121tcxSetup(pointer module, pointer opts, int *errmaj, int *errmin)
122{
123    static Bool setupDone = FALSE;
124
125    if (!setupDone) {
126	setupDone = TRUE;
127	xf86AddDriver(&SUNTCX, module, 0);
128
129	/*
130	 * Modules that this driver always requires can be loaded here
131	 * by calling LoadSubModule().
132	 */
133
134	/*
135	 * The return value must be non-NULL on success even though there
136	 * is no TearDownProc.
137	 */
138	return (pointer)TRUE;
139    } else {
140	if (errmaj) *errmaj = LDR_ONCEONLY;
141	return NULL;
142    }
143}
144
145#endif /* XFree86LOADER */
146
147static Bool
148TCXGetRec(ScrnInfoPtr pScrn)
149{
150    /*
151     * Allocate an TcxRec, and hook it into pScrn->driverPrivate.
152     * pScrn->driverPrivate is initialised to NULL, so we can check if
153     * the allocation has already been done.
154     */
155    if (pScrn->driverPrivate != NULL)
156	return TRUE;
157
158    pScrn->driverPrivate = xnfcalloc(sizeof(TcxRec), 1);
159    return TRUE;
160}
161
162static void
163TCXFreeRec(ScrnInfoPtr pScrn)
164{
165    TcxPtr pTcx;
166
167    if (pScrn->driverPrivate == NULL)
168	return;
169
170    pTcx = GET_TCX_FROM_SCRN(pScrn);
171
172    xfree(pScrn->driverPrivate);
173    pScrn->driverPrivate = NULL;
174
175    return;
176}
177
178static const OptionInfoRec *
179TCXAvailableOptions(int chipid, int busid)
180{
181    return TCXOptions;
182}
183
184/* Mandatory */
185static void
186TCXIdentify(int flags)
187{
188    xf86Msg(X_INFO, "%s: driver for TCX\n", TCX_NAME);
189}
190
191
192/* Mandatory */
193static Bool
194TCXProbe(DriverPtr drv, int flags)
195{
196    int i;
197    GDevPtr *devSections;
198    int *usedChips;
199    int numDevSections;
200    int numUsed;
201    Bool foundScreen = FALSE;
202    EntityInfoPtr pEnt;
203
204    /*
205     * The aim here is to find all cards that this driver can handle,
206     * and for the ones not already claimed by another driver, claim the
207     * slot, and allocate a ScrnInfoRec.
208     *
209     * This should be a minimal probe, and it should under no circumstances
210     * change the state of the hardware.  Because a device is found, don't
211     * assume that it will be used.  Don't do any initialisations other than
212     * the required ScrnInfoRec initialisations.  Don't allocate any new
213     * data structures.
214     */
215
216    /*
217     * Next we check, if there has been a chipset override in the config file.
218     * For this we must find out if there is an active device section which
219     * is relevant, i.e., which has no driver specified or has THIS driver
220     * specified.
221     */
222
223    if ((numDevSections = xf86MatchDevice(TCX_DRIVER_NAME,
224					  &devSections)) <= 0) {
225	/*
226	 * There's no matching device section in the config file, so quit
227	 * now.
228	 */
229	return FALSE;
230    }
231
232    /*
233     * We need to probe the hardware first.  We then need to see how this
234     * fits in with what is given in the config file, and allow the config
235     * file info to override any contradictions.
236     */
237
238    numUsed = xf86MatchSbusInstances(TCX_NAME, SBUS_DEVICE_TCX,
239		   devSections, numDevSections,
240		   drv, &usedChips);
241
242    xfree(devSections);
243    if (numUsed <= 0)
244	return FALSE;
245
246    if (flags & PROBE_DETECT)
247	foundScreen = TRUE;
248    else for (i = 0; i < numUsed; i++) {
249	pEnt = xf86GetEntityInfo(usedChips[i]);
250
251	/*
252	 * Check that nothing else has claimed the slots.
253	 */
254	if(pEnt->active) {
255	    ScrnInfoPtr pScrn;
256
257	    /* Allocate a ScrnInfoRec and claim the slot */
258	    pScrn = xf86AllocateScreen(drv, 0);
259
260	    /* Fill in what we can of the ScrnInfoRec */
261	    pScrn->driverVersion = TCX_VERSION;
262	    pScrn->driverName	 = TCX_DRIVER_NAME;
263	    pScrn->name		 = TCX_NAME;
264	    pScrn->Probe	 = TCXProbe;
265	    pScrn->PreInit	 = TCXPreInit;
266	    pScrn->ScreenInit	 = TCXScreenInit;
267  	    pScrn->SwitchMode	 = TCXSwitchMode;
268  	    pScrn->AdjustFrame	 = TCXAdjustFrame;
269	    pScrn->EnterVT	 = TCXEnterVT;
270	    pScrn->LeaveVT	 = TCXLeaveVT;
271	    pScrn->FreeScreen	 = TCXFreeScreen;
272	    pScrn->ValidMode	 = TCXValidMode;
273	    xf86AddEntityToScreen(pScrn, pEnt->index);
274	    foundScreen = TRUE;
275	}
276	xfree(pEnt);
277    }
278    xfree(usedChips);
279    return foundScreen;
280}
281
282/* Mandatory */
283static Bool
284TCXPreInit(ScrnInfoPtr pScrn, int flags)
285{
286    TcxPtr pTcx;
287    sbusDevicePtr psdp = NULL;
288    MessageType from;
289    int i;
290    int hwCursor, lowDepth;
291
292    if (flags & PROBE_DETECT) return FALSE;
293
294    /*
295     * Note: This function is only called once at server startup, and
296     * not at the start of each server generation.  This means that
297     * only things that are persistent across server generations can
298     * be initialised here.  xf86Screens[] is (pScrn is a pointer to one
299     * of these).  Privates allocated using xf86AllocateScrnInfoPrivateIndex()
300     * are too, and should be used for data that must persist across
301     * server generations.
302     *
303     * Per-generation data should be allocated with
304     * AllocateScreenPrivateIndex() from the ScreenInit() function.
305     */
306
307    /* Allocate the TcxRec driverPrivate */
308    if (!TCXGetRec(pScrn)) {
309	return FALSE;
310    }
311    pTcx = GET_TCX_FROM_SCRN(pScrn);
312
313    /* Set pScrn->monitor */
314    pScrn->monitor = pScrn->confScreen->monitor;
315
316    /* This driver doesn't expect more than one entity per screen */
317    if (pScrn->numEntities > 1)
318	return FALSE;
319    /* This is the general case */
320    for (i = 0; i < pScrn->numEntities; i++) {
321	EntityInfoPtr pEnt = xf86GetEntityInfo(pScrn->entityList[i]);
322
323	/* TCX is purely AFX, but we handle it like SBUS */
324	if (pEnt->location.type == BUS_SBUS) {
325	    psdp = xf86GetSbusInfoForEntity(pEnt->index);
326	    pTcx->psdp = psdp;
327	} else
328	    return FALSE;
329    }
330    if (psdp == NULL)
331	return FALSE;
332
333    /**********************
334    check card capabilities
335    **********************/
336    hwCursor = 0;
337    lowDepth = 1;
338    if (sparcPromInit() >= 0) {
339	hwCursor = sparcPromGetBool(&psdp->node, "hw-cursor");
340	lowDepth = sparcPromGetBool(&psdp->node, "tcx-8-bit");
341	sparcPromClose();
342    }
343
344    /*********************
345    deal with depth
346    *********************/
347
348    if (!xf86SetDepthBpp(pScrn, 0, 0, 0,
349			 lowDepth ? NoDepth24Support : Support32bppFb)) {
350	return FALSE;
351    } else {
352	/* Check that the returned depth is one we support */
353	switch (pScrn->depth) {
354	case 8:
355	    /* OK */
356	    break;
357	case 32:
358	    /* unless lowDepth OK */
359	    if (lowDepth) {
360		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
361			   "Given depth (32) not supported by hardware\n");
362		return FALSE;
363	    }
364	    break;
365	default:
366	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
367		       "Given depth (%d) is not supported by this driver\n",
368		       pScrn->depth);
369	    return FALSE;
370	}
371    }
372
373    /* Collect all of the relevant option flags (fill in pScrn->options) */
374    xf86CollectOptions(pScrn, NULL);
375    /* Process the options */
376    if (!(pTcx->Options = xalloc(sizeof(TCXOptions))))
377	return FALSE;
378    memcpy(pTcx->Options, TCXOptions, sizeof(TCXOptions));
379    xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pTcx->Options);
380
381    /*
382     * This must happen after pScrn->display has been set because
383     * xf86SetWeight references it.
384     */
385    if (pScrn->depth > 8) {
386	rgb weight = {10, 11, 11};
387	rgb mask = {0xff, 0xff00, 0xff0000};
388
389	if (!xf86SetWeight(pScrn, weight, mask)) {
390	    return FALSE;
391	}
392    }
393
394    if (!xf86SetDefaultVisual(pScrn, -1))
395	return FALSE;
396    else if (pScrn->depth > 8) {
397	/* We don't currently support DirectColor */
398	if (pScrn->defaultVisual != TrueColor) {
399	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Given default visual"
400		       " (%s) is not supported\n",
401		       xf86GetVisualName(pScrn->defaultVisual));
402	    return FALSE;
403	}
404    }
405
406    /*
407     * The new cmap code requires this to be initialised.
408     */
409
410    {
411	Gamma zeros = {0.0, 0.0, 0.0};
412
413	if (!xf86SetGamma(pScrn, zeros)) {
414	    return FALSE;
415	}
416    }
417
418    /* determine whether we use hardware or software cursor */
419
420    from = X_PROBED;
421    pTcx->HWCursor = FALSE;
422    if (hwCursor) {
423	from = X_DEFAULT;
424	pTcx->HWCursor = TRUE;
425	if (xf86GetOptValBool(pTcx->Options, OPTION_HW_CURSOR, &pTcx->HWCursor))
426	    from = X_CONFIG;
427	if (xf86ReturnOptValBool(pTcx->Options, OPTION_SW_CURSOR, FALSE)) {
428	    from = X_CONFIG;
429	    pTcx->HWCursor = FALSE;
430	}
431    }
432
433    xf86DrvMsg(pScrn->scrnIndex, from, "Using %s cursor\n",
434		pTcx->HWCursor ? "HW" : "SW");
435
436    if (xf86LoadSubModule(pScrn, "fb") == NULL) {
437	TCXFreeRec(pScrn);
438	return FALSE;
439    }
440
441    if (pTcx->HWCursor && xf86LoadSubModule(pScrn, "ramdac") == NULL) {
442	TCXFreeRec(pScrn);
443	return FALSE;
444    }
445
446    /*********************
447    set up clock and mode stuff
448    *********************/
449
450    pScrn->progClock = TRUE;
451
452    if(pScrn->display->virtualX || pScrn->display->virtualY) {
453	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
454		   "TCX does not support a virtual desktop\n");
455	pScrn->display->virtualX = 0;
456	pScrn->display->virtualY = 0;
457    }
458
459    xf86SbusUseBuiltinMode(pScrn, pTcx->psdp);
460    pScrn->currentMode = pScrn->modes;
461    pScrn->displayWidth = pScrn->virtualX;
462
463    /* Set display resolution */
464    xf86SetDpi(pScrn, 0, 0);
465
466    return TRUE;
467}
468
469/* Mandatory */
470
471/* This gets called at the start of each server generation */
472
473static Bool
474TCXScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
475{
476    ScrnInfoPtr pScrn;
477    TcxPtr pTcx;
478    VisualPtr visual;
479    int ret;
480
481    /*
482     * First get the ScrnInfoRec
483     */
484    pScrn = xf86Screens[pScreen->myNum];
485
486    pTcx = GET_TCX_FROM_SCRN(pScrn);
487
488    /* Map the TCX memory */
489    if (pScrn->depth == 8)
490	pTcx->fb =
491	    xf86MapSbusMem (pTcx->psdp, TCX_RAM8_VOFF,
492			    (pTcx->psdp->width * pTcx->psdp->height));
493    else {
494	pTcx->fb =
495	    xf86MapSbusMem (pTcx->psdp, TCX_RAM24_VOFF,
496			    (pTcx->psdp->width * pTcx->psdp->height * 4));
497	pTcx->cplane =
498	    xf86MapSbusMem (pTcx->psdp, TCX_CPLANE_VOFF,
499			    (pTcx->psdp->width * pTcx->psdp->height * 4));
500	if (! pTcx->cplane)
501	    return FALSE;
502    }
503    if (pTcx->HWCursor == TRUE) {
504	pTcx->thc = xf86MapSbusMem (pTcx->psdp, TCX_THC_VOFF, 8192);
505	if (! pTcx->thc)
506	    return FALSE;
507    }
508
509    if (! pTcx->fb)
510	return FALSE;
511
512    /* Darken the screen for aesthetic reasons and set the viewport */
513    TCXSaveScreen(pScreen, SCREEN_SAVER_ON);
514
515    /*
516     * The next step is to setup the screen's visuals, and initialise the
517     * framebuffer code.  In cases where the framebuffer's default
518     * choices for things like visual layouts and bits per RGB are OK,
519     * this may be as simple as calling the framebuffer's ScreenInit()
520     * function.  If not, the visuals will need to be setup before calling
521     * a fb ScreenInit() function and fixed up after.
522     */
523
524    /*
525     * Reset visual list.
526     */
527    miClearVisualTypes();
528
529    if (pScrn->depth == 8)
530	/* Set the bits per RGB for 8bpp mode */
531	pScrn->rgbBits = 8;
532
533    /* Setup the visuals we support. */
534
535    if (!miSetVisualTypes(pScrn->depth,
536			  pScrn->depth != 8 ? TrueColorMask :
537				miGetDefaultVisualMask(pScrn->depth),
538			  pScrn->rgbBits, pScrn->defaultVisual))
539	return FALSE;
540
541    miSetPixmapDepths ();
542
543    /*
544     * Call the framebuffer layer's ScreenInit function, and fill in other
545     * pScreen fields.
546     */
547
548    if (pScrn->bitsPerPixel != 8)
549	TCXInitCplane24(pScrn);
550    ret = fbScreenInit(pScreen, pTcx->fb, pScrn->virtualX,
551		       pScrn->virtualY, pScrn->xDpi, pScrn->yDpi,
552		       pScrn->virtualX, pScrn->bitsPerPixel);
553
554    if (!ret)
555	return FALSE;
556
557    xf86SetBlackWhitePixels(pScreen);
558
559    if (pScrn->bitsPerPixel > 8) {
560	/* Fixup RGB ordering */
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
574#ifdef RENDER
575    /* must be after RGB ordering fixed */
576    fbPictureInit (pScreen, 0, 0);
577#endif
578
579    miInitializeBackingStore(pScreen);
580    xf86SetBackingStore(pScreen);
581    xf86SetSilkenMouse(pScreen);
582
583    /* Initialise cursor functions */
584    miDCInitialize (pScreen, xf86GetPointerScreenFuncs());
585
586    /* Initialize HW cursor layer.
587       Must follow software cursor initialization*/
588    if (pTcx->HWCursor) {
589	extern Bool TCXHWCursorInit(ScreenPtr pScreen);
590
591	if(!TCXHWCursorInit(pScreen)) {
592	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
593		       "Hardware cursor initialization failed\n");
594	    return(FALSE);
595	}
596	xf86SbusHideOsHwCursor(pTcx->psdp);
597    }
598
599    /* Initialise default colourmap */
600    if (!miCreateDefColormap(pScreen))
601	return FALSE;
602
603    if(pScrn->depth == 8 && !xf86SbusHandleColormaps(pScreen, pTcx->psdp))
604	return FALSE;
605
606    pTcx->CloseScreen = pScreen->CloseScreen;
607    pScreen->CloseScreen = TCXCloseScreen;
608    pScreen->SaveScreen = TCXSaveScreen;
609
610    /* Report any unused options (only for the first generation) */
611    if (serverGeneration == 1) {
612	xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
613    }
614
615    /* unblank the screen */
616    TCXSaveScreen(pScreen, SCREEN_SAVER_OFF);
617
618    /* Done */
619    return TRUE;
620}
621
622
623/* Usually mandatory */
624static Bool
625TCXSwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
626{
627    return TRUE;
628}
629
630
631/*
632 * This function is used to initialize the Start Address - the first
633 * displayed location in the video memory.
634 */
635/* Usually mandatory */
636static void
637TCXAdjustFrame(int scrnIndex, int x, int y, int flags)
638{
639    /* we don't support virtual desktops */
640    return;
641}
642
643/*
644 * This is called when VT switching back to the X server.  Its job is
645 * to reinitialise the video mode.
646 */
647
648/* Mandatory */
649static Bool
650TCXEnterVT(int scrnIndex, int flags)
651{
652    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
653    TcxPtr pTcx = GET_TCX_FROM_SCRN(pScrn);
654
655    if (pTcx->HWCursor) {
656	xf86SbusHideOsHwCursor (pTcx->psdp);
657	pTcx->CursorFg = 0;
658	pTcx->CursorBg = 0;
659    }
660    if (pTcx->cplane) {
661	TCXInitCplane24 (pScrn);
662    }
663    return TRUE;
664}
665
666
667/*
668 * This is called when VT switching away from the X server.
669 */
670
671/* Mandatory */
672static void
673TCXLeaveVT(int scrnIndex, int flags)
674{
675    return;
676}
677
678
679/*
680 * This is called at the end of each server generation.  It restores the
681 * original (text) mode.  It should really also unmap the video memory too.
682 */
683
684/* Mandatory */
685static Bool
686TCXCloseScreen(int scrnIndex, ScreenPtr pScreen)
687{
688    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
689    TcxPtr pTcx = GET_TCX_FROM_SCRN(pScrn);
690
691    pScrn->vtSema = FALSE;
692    if (pScrn->depth == 8)
693	xf86UnmapSbusMem(pTcx->psdp, pTcx->fb,
694			 (pTcx->psdp->width * pTcx->psdp->height));
695    else {
696	xf86UnmapSbusMem(pTcx->psdp, pTcx->fb,
697			 (pTcx->psdp->width * pTcx->psdp->height * 4));
698	xf86UnmapSbusMem(pTcx->psdp, pTcx->cplane,
699			 (pTcx->psdp->width * pTcx->psdp->height * 4));
700    }
701    if (pTcx->thc)
702	xf86UnmapSbusMem(pTcx->psdp, pTcx->fb, 8192);
703
704    if (pTcx->HWCursor)
705	xf86SbusHideOsHwCursor (pTcx->psdp);
706
707    pScreen->CloseScreen = pTcx->CloseScreen;
708    return (*pScreen->CloseScreen)(scrnIndex, pScreen);
709    return FALSE;
710}
711
712
713/* Free up any per-generation data structures */
714
715/* Optional */
716static void
717TCXFreeScreen(int scrnIndex, int flags)
718{
719    TCXFreeRec(xf86Screens[scrnIndex]);
720}
721
722
723/* Checks if a mode is suitable for the selected chipset. */
724
725/* Optional */
726static ModeStatus
727TCXValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags)
728{
729    if (mode->Flags & V_INTERLACE)
730	return(MODE_BAD);
731
732    return(MODE_OK);
733}
734
735/* Do screen blanking */
736
737/* Mandatory */
738static Bool
739TCXSaveScreen(ScreenPtr pScreen, int mode)
740    /* this function should blank the screen when unblank is FALSE and
741       unblank it when unblank is TRUE -- it doesn't actually seem to be
742       used for much though */
743{
744    return TRUE;
745}
746
747/*
748 * This is the implementation of the Sync() function.
749 */
750void
751TCXSync(ScrnInfoPtr pScrn)
752{
753    return;
754}
755
756/*
757 * This initializes CPLANE for 24 bit mode.
758 */
759static void
760TCXInitCplane24(ScrnInfoPtr pScrn)
761{
762    TcxPtr pTcx = GET_TCX_FROM_SCRN(pScrn);
763    int size;
764    unsigned int *p, *q;
765
766    if (!pTcx->cplane)
767	return;
768
769    size = pScrn->virtualX * pScrn->virtualY;
770    memset (pTcx->fb, 0, size * 4);
771    p = pTcx->cplane;
772    for (q = pTcx->cplane + size; p != q; p++)
773	*p = (*p & 0xffffff) | TCX_CPLANE_MODE;
774}
775