crime_driver.c revision 34c4e112
1/* $NetBSD: crime_driver.c,v 1.2 2009/02/19 20:03:30 macallan Exp $ */
2/*
3 * Copyright (c) 2008 Michael Lorenz
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 *    - Redistributions of source code must retain the above copyright
11 *      notice, this list of conditions and the following disclaimer.
12 *    - Redistributions in binary form must reproduce the above
13 *      copyright notice, this list of conditions and the following
14 *      disclaimer in the documentation and/or other materials provided
15 *      with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 *
30 */
31
32/* a driver for the CRIME rendering engine foundin SGI O2 workstations */
33
34#ifdef HAVE_CONFIG_H
35#include "config.h"
36#endif
37
38#include <fcntl.h>
39#include <sys/types.h>
40#include <sys/time.h>
41#include <dev/wscons/wsconsio.h>
42
43/* all driver need this */
44#include "xf86.h"
45#include "xf86_OSproc.h"
46#include "xf86_ansic.h"
47
48#include "mipointer.h"
49#include "mibstore.h"
50#include "micmap.h"
51#include "colormapst.h"
52#include "xf86cmap.h"
53
54/* for visuals */
55#include "xf1bpp.h"
56#include "xf4bpp.h"
57#include "fb.h"
58
59#include "xf86Resources.h"
60#include "xf86RAC.h"
61
62#ifdef XvExtension
63#include "xf86xv.h"
64#endif
65
66#include "crime.h"
67
68/* #include "wsconsio.h" */
69
70#ifndef XFree86LOADER
71#include <sys/mman.h>
72#endif
73
74#define CRIME_DEFAULT_DEV "/dev/ttyE0"
75
76#define DEBUG 1
77#ifndef DEBUG
78#define DEBUG 0
79#endif
80
81/* Prototypes */
82#ifdef XFree86LOADER
83static pointer CrimeSetup(pointer, pointer, int *, int *);
84#endif
85static Bool CrimeGetRec(ScrnInfoPtr);
86static void CrimeFreeRec(ScrnInfoPtr);
87static const OptionInfoRec * CrimeAvailableOptions(int, int);
88static void CrimeIdentify(int);
89static Bool CrimeProbe(DriverPtr, int);
90static Bool CrimePreInit(ScrnInfoPtr, int);
91static Bool CrimeScreenInit(int, ScreenPtr, int, char **);
92static Bool CrimeCloseScreen(int, ScreenPtr);
93static Bool CrimeEnterVT(int, int);
94static void CrimeLeaveVT(int, int);
95static Bool CrimeSwitchMode(int, DisplayModePtr, int);
96static int CrimeValidMode(int, DisplayModePtr, Bool, int);
97static void CrimeLoadPalette(ScrnInfoPtr, int, int *, LOCO *, VisualPtr);
98static Bool CrimeSaveScreen(ScreenPtr, int);
99static void CrimeSave(ScrnInfoPtr);
100static void CrimeRestore(ScrnInfoPtr);
101
102/* helper functions */
103static int crime_open(char *);
104static pointer crime_mmap(size_t, off_t, int, int);
105
106/*
107 * This is intentionally screen-independent.  It indicates the binding
108 * choice made in the first PreInit.
109 */
110static int pix24bpp = 0;
111
112#define VERSION			4000
113#define CRIME_NAME		"crime"
114#define CRIME_DRIVER_NAME	"crime"
115#define CRIME_MAJOR_VERSION	0
116#define CRIME_MINOR_VERSION	1
117
118DriverRec CRIME = {
119	VERSION,
120	CRIME_DRIVER_NAME,
121	CrimeIdentify,
122	CrimeProbe,
123	CrimeAvailableOptions,
124	NULL,
125	0
126};
127
128/* Supported "chipsets" */
129static SymTabRec CrimeChipsets[] = {
130	{ 0, "crime" },
131	{ -1, NULL }
132};
133
134/* Supported options */
135typedef enum {
136	OPTION_HW_CURSOR,
137	OPTION_SW_CURSOR
138} CrimeOpts;
139
140static const OptionInfoRec CrimeOptions[] = {
141	{ OPTION_SW_CURSOR, "SWcursor",	OPTV_BOOLEAN,	{0}, FALSE },
142	{ OPTION_HW_CURSOR, "HWcursor",	OPTV_BOOLEAN,	{0}, FALSE },
143	{ -1, NULL, OPTV_NONE, {0}, FALSE}
144};
145
146/* Symbols needed from other modules */
147static const char *fbSymbols[] = {
148	"fbPictureInit",
149	"fbScreenInit",
150	NULL
151};
152
153static const char *xaaSymbols[] =
154{
155    "XAACreateInfoRec",
156    "XAADestroyInfoRec",
157    "XAAInit",
158    "XAAScreenIndex",
159    NULL
160};
161
162static const char *ramdacSymbols[] = {
163	"xf86CreateCursorInfoRec",
164	"xf86DestroyCursorInfoRec",
165	"xf86InitCursor",
166	NULL
167};
168
169#ifdef XFree86LOADER
170static XF86ModuleVersionInfo CrimeVersRec = {
171	"crime",
172	MODULEVENDORSTRING,
173	MODINFOSTRING1,
174	MODINFOSTRING2,
175	XORG_VERSION_CURRENT,
176	CRIME_MAJOR_VERSION, CRIME_MINOR_VERSION, 0,
177	ABI_CLASS_VIDEODRV,
178	ABI_VIDEODRV_VERSION,
179	NULL,
180	{0, 0, 0, 0}
181};
182
183_X_EXPORT XF86ModuleData crimeModuleData = { &CrimeVersRec, CrimeSetup, NULL };
184
185static pointer
186CrimeSetup(pointer module, pointer opts, int *errmaj, int *errmin)
187{
188	static Bool setupDone = FALSE;
189	const char *osname;
190
191	/* Check that we're being loaded on a OpenBSD or NetBSD system */
192	LoaderGetOS(&osname, NULL, NULL, NULL);
193	if (!osname
194	    && (strcmp(osname, "netbsd") != 0)) {
195		if (errmaj)
196			*errmaj = LDR_BADOS;
197		if (errmin)
198			*errmin = 0;
199		return NULL;
200	}
201	if (!setupDone) {
202		setupDone = TRUE;
203		xf86AddDriver(&CRIME, module, 0);
204		LoaderRefSymLists(xaaSymbols, fbSymbols, NULL);
205		return (pointer)1;
206	} else {
207		if (errmaj != NULL)
208			*errmaj = LDR_ONCEONLY;
209		return NULL;
210	}
211}
212#endif /* XFree86LOADER */
213
214static Bool
215CrimeGetRec(ScrnInfoPtr pScrn)
216{
217
218	if (pScrn->driverPrivate != NULL)
219		return TRUE;
220
221	pScrn->driverPrivate = xnfcalloc(sizeof(CrimeRec), 1);
222	return TRUE;
223}
224
225static void
226CrimeFreeRec(ScrnInfoPtr pScrn)
227{
228
229	if (pScrn->driverPrivate == NULL)
230		return;
231	xfree(pScrn->driverPrivate);
232	pScrn->driverPrivate = NULL;
233}
234
235static const OptionInfoRec *
236CrimeAvailableOptions(int chipid, int busid)
237{
238	return CrimeOptions;
239}
240
241static void
242CrimeIdentify(int flags)
243{
244	xf86PrintChipsets(CRIME_NAME, "driver for CRIME framebuffer",
245			  CrimeChipsets);
246}
247
248
249#define priv_open_device(n)	open(n,O_RDWR|O_NONBLOCK|O_EXCL)
250
251/* Open the framebuffer device */
252static int
253crime_open(char *dev)
254{
255	int fd = -1;
256
257	/* try argument from XF86Config first */
258	if (dev == NULL || ((fd = priv_open_device(dev)) == -1)) {
259		/* second: environment variable */
260		dev = getenv("XDEVICE");
261		if (dev == NULL || ((fd = priv_open_device(dev)) == -1)) {
262			/* last try: default device */
263			dev = CRIME_DEFAULT_DEV;
264			if ((fd = priv_open_device(dev)) == -1) {
265				return -1;
266			}
267		}
268	}
269	return fd;
270}
271
272/* Map the framebuffer's memory */
273static pointer
274crime_mmap(size_t len, off_t off, int fd, int ro)
275{
276	pointer mapaddr;
277
278	/*
279	 * try and make it private first, that way once we get it, an
280	 * interloper, e.g. another server, can't get this frame buffer,
281	 * and if another server already has it, this one won't.
282	 */
283	if (ro) {
284		mapaddr = (pointer) mmap(NULL, len,
285					 PROT_READ, MAP_SHARED,
286					 fd, off);
287		xf86Msg(X_ERROR, "mapping %08x read only\n", off);
288	} else {
289		mapaddr = (pointer) mmap(NULL, len,
290					 PROT_READ | PROT_WRITE, MAP_SHARED,
291					 fd, off);
292		xf86Msg(X_ERROR, "mapping %08x read/write\n", off);
293	}
294	if (mapaddr == (pointer) -1) {
295		mapaddr = NULL;
296	}
297#if DEBUG
298	ErrorF("mmap returns: addr %p len 0x%x\n", mapaddr, len);
299#endif
300	return mapaddr;
301}
302
303static Bool
304CrimeProbe(DriverPtr drv, int flags)
305{
306	ScrnInfoPtr pScrn = NULL;
307	int i, fd, entity, wstype;
308       	GDevPtr *devSections;
309	int numDevSections;
310	char *dev;
311	Bool foundScreen = FALSE;
312
313	xf86Msg(X_ERROR, "%s\n", __func__);
314
315	if ((numDevSections = xf86MatchDevice(CRIME_DRIVER_NAME,
316					      &devSections)) <= 0)
317		return FALSE;
318
319
320	if ((fd = crime_open(CRIME_DEFAULT_DEV)) == 0)
321		return FALSE;
322	xf86Msg(X_ERROR, "%s: fd found\n", __func__);
323
324	if (ioctl(fd, WSDISPLAYIO_GTYPE, &wstype) == -1)
325		return FALSE;
326	xf86Msg(X_ERROR, "%s: type: %d\n", __func__, wstype);
327	if (wstype != WSDISPLAY_TYPE_CRIME)
328		return FALSE;
329
330	xf86Msg(X_ERROR, "%s: CRIME found\n", __func__);
331
332	if (flags & PROBE_DETECT)
333		return TRUE;
334
335	/* ok, at this point we know we've got a CRIME */
336	for (i = 0; i < numDevSections; i++) {
337
338		dev = xf86FindOptionValue(devSections[i]->options, "device");
339		if ((fd = crime_open(dev)) >= 0) {
340			entity = xf86ClaimFbSlot(drv, 0, devSections[i], TRUE);
341			pScrn = xf86ConfigFbEntity(NULL,0,entity,
342						   NULL,NULL,NULL,NULL);
343			if (pScrn != NULL) {
344				foundScreen = TRUE;
345				pScrn->driverVersion = VERSION;
346				pScrn->driverName = CRIME_DRIVER_NAME;
347				pScrn->name = CRIME_NAME;
348				pScrn->Probe = CrimeProbe;
349				pScrn->PreInit = CrimePreInit;
350				pScrn->ScreenInit = CrimeScreenInit;
351				pScrn->SwitchMode = CrimeSwitchMode;
352				pScrn->AdjustFrame = NULL;
353				pScrn->EnterVT = CrimeEnterVT;
354				pScrn->LeaveVT = CrimeLeaveVT;
355				pScrn->ValidMode = CrimeValidMode;
356
357				xf86DrvMsg(pScrn->scrnIndex, X_INFO,
358				    "using %s\n", dev != NULL ? dev :
359				    "default device");
360			}
361		}
362	}
363	xfree(devSections);
364	return foundScreen;
365}
366
367static Bool
368CrimePreInit(ScrnInfoPtr pScrn, int flags)
369{
370	CrimePtr fPtr;
371	int default_depth, wstype;
372	char *dev;
373	char *mod = NULL;
374	const char *reqSym = NULL;
375	Gamma zeros = {0.0, 0.0, 0.0};
376	DisplayModePtr mode;
377	MessageType from;
378	rgb rgbzeros = { 0, 0, 0 }, masks;
379
380	if (flags & PROBE_DETECT) return FALSE;
381
382	if (pScrn->numEntities != 1) return FALSE;
383
384	pScrn->monitor = pScrn->confScreen->monitor;
385
386	CrimeGetRec(pScrn);
387	fPtr = CRIMEPTR(pScrn);
388
389	fPtr->pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
390
391	pScrn->racMemFlags = RAC_FB | RAC_COLORMAP | RAC_CURSOR | RAC_VIEWPORT;
392	pScrn->racIoFlags = pScrn->racMemFlags;
393
394	dev = xf86FindOptionValue(fPtr->pEnt->device->options, "device");
395	fPtr->fd = crime_open(dev);
396	if (fPtr->fd == -1) {
397		return FALSE;
398	}
399
400	if (ioctl(fPtr->fd, WSDISPLAYIO_GINFO, &fPtr->info) == -1) {
401		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
402			   "ioctl WSDISPLAY_GINFO: %s\n",
403			   strerror(errno));
404		return FALSE;
405	}
406	if (ioctl(fPtr->fd, WSDISPLAYIO_GTYPE, &wstype) == -1) {
407		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
408			   "ioctl WSDISPLAY_GTYPE: %s\n",
409			   strerror(errno));
410		return FALSE;
411	}
412
413	/* Handle depth */
414	default_depth = fPtr->info.depth <= 24 ? fPtr->info.depth : 24;
415	if (!xf86SetDepthBpp(pScrn, default_depth, default_depth,
416			     fPtr->info.depth, Support24bppFb|Support32bppFb))
417		return FALSE;
418	xf86PrintDepthBpp(pScrn);
419
420	/* Get the depth24 pixmap format */
421	if (pScrn->depth == 24 && pix24bpp == 0)
422		pix24bpp = xf86GetBppFromDepth(pScrn, 24);
423
424	/* color weight */
425	masks.red =   0x00ff0000;
426	masks.green = 0x0000ff00;
427	masks.blue =  0x000000ff;
428	if (!xf86SetWeight(pScrn, rgbzeros, masks))
429		return FALSE;
430
431	/* visual init */
432	if (!xf86SetDefaultVisual(pScrn, -1))
433		return FALSE;
434
435	/* We don't currently support DirectColor at > 8bpp */
436	if (pScrn->depth > 8 && pScrn->defaultVisual != TrueColor) {
437		xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Given default visual"
438			   " (%s) is not supported at depth %d\n",
439			   xf86GetVisualName(pScrn->defaultVisual),
440			   pScrn->depth);
441		return FALSE;
442	}
443
444	xf86SetGamma(pScrn,zeros);
445
446	pScrn->progClock = TRUE;
447	pScrn->rgbBits   = 8;
448	pScrn->chipset   = "crime";
449	pScrn->videoRam  = fPtr->info.width * 4 * 2048;
450
451	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Vidmem: %dk\n",
452		   pScrn->videoRam/1024);
453
454	/* handle options */
455	xf86CollectOptions(pScrn, NULL);
456	if (!(fPtr->Options = xalloc(sizeof(CrimeOptions))))
457		return FALSE;
458	memcpy(fPtr->Options, CrimeOptions, sizeof(CrimeOptions));
459	xf86ProcessOptions(pScrn->scrnIndex, fPtr->pEnt->device->options,
460			   fPtr->Options);
461
462	/* fake video mode struct */
463	mode = (DisplayModePtr)xalloc(sizeof(DisplayModeRec));
464	mode->prev = mode;
465	mode->next = mode;
466	mode->name = "crime current mode";
467	mode->status = MODE_OK;
468	mode->type = M_T_BUILTIN;
469	mode->Clock = 0;
470	mode->HDisplay = fPtr->info.width;
471	mode->HSyncStart = 0;
472	mode->HSyncEnd = 0;
473	mode->HTotal = 0;
474	mode->HSkew = 0;
475	mode->VDisplay = fPtr->info.height;
476	mode->VSyncStart = 0;
477	mode->VSyncEnd = 0;
478	mode->VTotal = 0;
479	mode->VScan = 0;
480	mode->Flags = 0;
481	if (pScrn->modes != NULL) {
482		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
483		   "Ignoring mode specification from screen section\n");
484	}
485	pScrn->currentMode = pScrn->modes = mode;
486	pScrn->virtualX = fPtr->info.width;
487	pScrn->virtualY = fPtr->info.height;
488	pScrn->displayWidth = pScrn->virtualX;
489
490	/* Set the display resolution */
491	xf86SetDpi(pScrn, 0, 0);
492
493	from = X_DEFAULT;
494	fPtr->HWCursor = TRUE;
495	if (xf86GetOptValBool(fPtr->Options, OPTION_HW_CURSOR, &fPtr->HWCursor))
496		from = X_CONFIG;
497	if (xf86ReturnOptValBool(fPtr->Options, OPTION_SW_CURSOR, FALSE)) {
498		from = X_CONFIG;
499		fPtr->HWCursor = FALSE;
500	}
501	xf86DrvMsg(pScrn->scrnIndex, from, "Using %s cursor\n",
502		fPtr->HWCursor ? "HW" : "SW");
503
504	if (xf86LoadSubModule(pScrn, "fb") == NULL) {
505		CrimeFreeRec(pScrn);
506		return FALSE;
507	}
508	xf86LoaderReqSymLists(fbSymbols, NULL);
509
510	if (xf86LoadSubModule(pScrn, "xaa") == NULL) {
511		PnozzFreeRec(pScrn);
512		return FALSE;
513	}
514	xf86LoaderReqSymLists(xaaSymbols, NULL);
515
516	if (xf86LoadSubModule(pScrn, "ramdac") == NULL) {
517		CrimeFreeRec(pScrn);
518		return FALSE;
519	}
520	xf86LoaderReqSymLists(ramdacSymbols, NULL);
521
522	return TRUE;
523}
524
525static Bool
526CrimeScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
527{
528	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
529	CrimePtr fPtr = CRIMEPTR(pScrn);
530	VisualPtr visual;
531	int ret, flags, width, height, i, j;
532	int wsmode = WSDISPLAYIO_MODE_DUMBFB;
533	size_t len;
534
535#if DEBUG
536	ErrorF("\tbitsPerPixel=%d, depth=%d, defaultVisual=%s\n"
537	       "\tmask: %x,%x,%x, offset: %d,%d,%d\n",
538	       pScrn->bitsPerPixel,
539	       pScrn->depth,
540	       xf86GetVisualName(pScrn->defaultVisual),
541	       pScrn->mask.red,pScrn->mask.green,pScrn->mask.blue,
542	       pScrn->offset.red,pScrn->offset.green,pScrn->offset.blue);
543#endif
544
545	/* Switch to graphics mode - required before mmap */
546	if (ioctl(fPtr->fd, WSDISPLAYIO_SMODE, &wsmode) == -1) {
547		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
548			   "ioctl WSDISPLAYIO_SMODE: %s\n",
549			   strerror(errno));
550		return FALSE;
551	}
552	fPtr->engine = crime_mmap(0x5000, 0x15000000, fPtr->fd, 0);
553
554	if (fPtr->engine == NULL) {
555		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
556			   "crime_mmap engine: %s\n", strerror(errno));
557		return FALSE;
558	}
559
560	fPtr->linear = crime_mmap(0x10000, 0x15010000, fPtr->fd, 0);
561	if (fPtr->linear == NULL) {
562		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
563			   "crime_mmap linear: %s\n", strerror(errno));
564		return FALSE;
565	}
566
567	memset(fPtr->linear, 0, 0x10000);
568	fPtr->fb = crime_mmap(8192 * fPtr->info.width, 0, fPtr->fd, 0);
569	if (fPtr->fb == NULL) {
570		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
571			   "crime_mmap fb: %s\n", strerror(errno));
572		return FALSE;
573	}
574
575	CrimeSave(pScrn);
576	pScrn->vtSema = TRUE;
577
578	/* mi layer */
579	miClearVisualTypes();
580	if (!miSetVisualTypes(pScrn->depth, TrueColorMask,
581			      pScrn->rgbBits, TrueColor))
582		return FALSE;
583
584	if (!miSetPixmapDepths())
585		return FALSE;
586
587	height = pScrn->virtualY;
588	width = pScrn->virtualX;
589
590	ret = fbScreenInit(pScreen,
591			   fPtr->fb,
592			   width, height,
593			   pScrn->xDpi, pScrn->yDpi,
594			   pScrn->displayWidth,
595			   pScrn->bitsPerPixel);
596
597	if (!ret)
598		return FALSE;
599
600	/* Fixup RGB ordering */
601	visual = pScreen->visuals + pScreen->numVisuals;
602	while (--visual >= pScreen->visuals) {
603		if ((visual->class | DynamicClass) == DirectColor) {
604			visual->offsetRed   = pScrn->offset.red;
605			visual->offsetGreen = pScrn->offset.green;
606			visual->offsetBlue  = pScrn->offset.blue;
607			visual->redMask     = pScrn->mask.red;
608			visual->greenMask   = pScrn->mask.green;
609			visual->blueMask    = pScrn->mask.blue;
610			xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
611			    "%d %d %d %08x %08x %08x\n",
612			    visual->offsetRed, visual->offsetGreen,
613			    visual->offsetBlue, visual->redMask,
614			    visual->greenMask, visual->blueMask);
615		}
616	}
617
618	if (!fbPictureInit(pScreen, NULL, 0))
619		xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
620			   "RENDER extension initialisation failed.");
621
622	xf86SetBlackWhitePixels(pScreen);
623	miInitializeBackingStore(pScreen);
624	xf86SetBackingStore(pScreen);
625
626	if (fPtr) {
627		BoxRec bx;
628		fPtr->pXAA = XAACreateInfoRec();
629		CrimeAccelInit(pScrn);
630		bx.x1 = bx.y1 = 0;
631		bx.x2 = fPtr->info.width;
632		bx.y2 = 2048;
633		xf86InitFBManager(pScreen, &bx);
634		if(!XAAInit(pScreen, fPtr->pXAA))
635			return FALSE;
636		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using acceleration\n");
637	}
638
639	/* software cursor */
640	miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
641
642	/* check for hardware cursor support */
643	CrimeSetupCursor(pScreen);
644
645	/* colormap */
646	if (!miCreateDefColormap(pScreen))
647		return FALSE;
648		flags = CMAP_RELOAD_ON_MODE_SWITCH;
649	if(!xf86HandleColormaps(pScreen, 256, 8, CrimeLoadPalette,
650				NULL, flags))
651		return FALSE;
652
653	pScreen->SaveScreen = CrimeSaveScreen;
654
655#ifdef XvExtension
656	{
657		XF86VideoAdaptorPtr *ptr;
658
659		int n = xf86XVListGenericAdaptors(pScrn,&ptr);
660		if (n) {
661			xf86XVScreenInit(pScreen,ptr,n);
662		}
663	}
664#endif
665
666	/* Wrap the current CloseScreen function */
667	fPtr->CloseScreen = pScreen->CloseScreen;
668	pScreen->CloseScreen = CrimeCloseScreen;
669
670	return TRUE;
671}
672
673static Bool
674CrimeCloseScreen(int scrnIndex, ScreenPtr pScreen)
675{
676	ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
677	CrimePtr fPtr = CRIMEPTR(pScrn);
678
679	if (pScrn->vtSema) {
680		CrimeRestore(pScrn);
681		if (munmap(fPtr->engine, 0x5000) == -1) {
682			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
683				   "munmap engine: %s\n", strerror(errno));
684		}
685
686		if (munmap(fPtr->linear, 0x10000) == -1) {
687			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
688				   "munmap linear: %s\n", strerror(errno));
689		}
690
691		fPtr->engine = NULL;
692		fPtr->linear = NULL;
693	}
694	pScrn->vtSema = FALSE;
695
696	/* unwrap CloseScreen */
697	pScreen->CloseScreen = fPtr->CloseScreen;
698	return (*pScreen->CloseScreen)(scrnIndex, pScreen);
699}
700
701static Bool
702CrimeEnterVT(int scrnIndex, int flags)
703{
704	ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
705
706	pScrn->vtSema = TRUE;
707	return TRUE;
708}
709
710static void
711CrimeLeaveVT(int scrnIndex, int flags)
712{
713}
714
715static Bool
716CrimeSwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
717{
718#if DEBUG
719	ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
720#endif
721
722	/* Nothing else to do */
723	return TRUE;
724}
725
726static int
727CrimeValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags)
728{
729#if DEBUG
730	ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
731#endif
732
733	return MODE_OK;
734}
735
736static void
737CrimeLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices,
738	       LOCO *colors, VisualPtr pVisual)
739{
740	CrimePtr fPtr = CRIMEPTR(pScrn);
741	struct wsdisplay_cmap cmap;
742	unsigned char red[256],green[256],blue[256];
743	int i, indexMin=256, indexMax=0;
744
745	cmap.count   = 1;
746	cmap.red   = red;
747	cmap.green = green;
748	cmap.blue  = blue;
749
750	if (numColors == 1) {
751		/* Optimisation */
752		cmap.index = indices[0];
753		red[0]   = colors[indices[0]].red;
754		green[0] = colors[indices[0]].green;
755		blue[0]  = colors[indices[0]].blue;
756		if (ioctl(fPtr->fd,WSDISPLAYIO_PUTCMAP, &cmap) == -1)
757			ErrorF("ioctl FBIOPUTCMAP: %s\n", strerror(errno));
758	} else {
759		/* Change all colors in 2 syscalls */
760		/* and limit the data to be transfered */
761		for (i = 0; i < numColors; i++) {
762			if (indices[i] < indexMin)
763				indexMin = indices[i];
764			if (indices[i] > indexMax)
765				indexMax = indices[i];
766		}
767		cmap.index = indexMin;
768		cmap.count = indexMax - indexMin + 1;
769		cmap.red = &red[indexMin];
770		cmap.green = &green[indexMin];
771		cmap.blue = &blue[indexMin];
772		/* Get current map */
773		if (ioctl(fPtr->fd, WSDISPLAYIO_GETCMAP, &cmap) == -1)
774			ErrorF("ioctl FBIOGETCMAP: %s\n", strerror(errno));
775		/* Change the colors that require updating */
776		for (i = 0; i < numColors; i++) {
777			red[indices[i]]   = colors[indices[i]].red;
778			green[indices[i]] = colors[indices[i]].green;
779			blue[indices[i]]  = colors[indices[i]].blue;
780		}
781		/* Write the colormap back */
782		if (ioctl(fPtr->fd,WSDISPLAYIO_PUTCMAP, &cmap) == -1)
783			ErrorF("ioctl FBIOPUTCMAP: %s\n", strerror(errno));
784	}
785}
786
787static Bool
788CrimeSaveScreen(ScreenPtr pScreen, int mode)
789{
790	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
791	CrimePtr fPtr = CRIMEPTR(pScrn);
792	int state;
793
794	if (!pScrn->vtSema)
795		return TRUE;
796
797	if (mode != SCREEN_SAVER_FORCER) {
798		state = xf86IsUnblank(mode)?WSDISPLAYIO_VIDEO_ON:
799		                            WSDISPLAYIO_VIDEO_OFF;
800		ioctl(fPtr->fd,
801		      WSDISPLAYIO_SVIDEO, &state);
802	}
803	return TRUE;
804}
805
806
807static void
808CrimeSave(ScrnInfoPtr pScrn)
809{
810}
811
812static void
813CrimeRestore(ScrnInfoPtr pScrn)
814{
815	CrimePtr fPtr = CRIMEPTR(pScrn);
816	int mode;
817
818	/* Restore the text mode */
819	mode = WSDISPLAYIO_MODE_EMUL;
820	if (ioctl(fPtr->fd, WSDISPLAYIO_SMODE, &mode) == -1) {
821		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
822			   "error setting text mode %s\n", strerror(errno));
823	}
824}
825