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