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