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