ngle_driver.c revision f8e8ce30
1/* $NetBSD: ngle_driver.c,v 1.6 2024/10/27 11:09:37 macallan Exp $ */
2/*
3 * Copyright (c) 2024 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 HP's NGLE family of graphics chips */
33
34#ifdef HAVE_CONFIG_H
35#include "config.h"
36#endif
37#include <sys/types.h>
38#include <dev/ic/stireg.h>
39
40#include <fcntl.h>
41#include <errno.h>
42#include <sys/time.h>
43#include <sys/mman.h>
44#include <sys/ioctl.h>
45#include <dev/wscons/wsconsio.h>
46
47/* all driver need this */
48#include "xf86.h"
49#include "xf86_OSproc.h"
50
51#include "mipointer.h"
52#include "micmap.h"
53#include "colormapst.h"
54#include "xf86cmap.h"
55#ifdef XvExtension
56#include "xf86xv.h"
57#endif
58
59/* for visuals */
60#include "fb.h"
61
62#include "ngle.h"
63
64/* #include "wsconsio.h" */
65
66#define NGLE_DEFAULT_DEV "/dev/ttyE0"
67
68static pointer NGLESetup(pointer, pointer, int *, int *);
69static Bool NGLEGetRec(ScrnInfoPtr);
70static void NGLEFreeRec(ScrnInfoPtr);
71static const OptionInfoRec * NGLEAvailableOptions(int, int);
72static void NGLEIdentify(int);
73static Bool NGLEProbe(DriverPtr, int);
74static Bool NGLEPreInit(ScrnInfoPtr, int);
75static Bool NGLEScreenInit(SCREEN_INIT_ARGS_DECL);
76static Bool NGLECloseScreen(CLOSE_SCREEN_ARGS_DECL);
77static Bool NGLEEnterVT(VT_FUNC_ARGS_DECL);
78static void NGLELeaveVT(VT_FUNC_ARGS_DECL);
79static Bool NGLESwitchMode(SWITCH_MODE_ARGS_DECL);
80static int NGLEValidMode(SCRN_ARG_TYPE, DisplayModePtr, Bool, int);
81static void NGLELoadPalette(ScrnInfoPtr, int, int *, LOCO *, VisualPtr);
82static Bool NGLESaveScreen(ScreenPtr, int);
83static void NGLESave(ScrnInfoPtr);
84static void NGLERestore(ScrnInfoPtr);
85
86/* helper functions */
87static int ngle_open(const char *);
88static pointer ngle_mmap(size_t, off_t, int, int);
89
90#define VERSION			4000
91#define NGLE_NAME		"ngle"
92#define NGLE_DRIVER_NAME	"ngle"
93#define NGLE_MAJOR_VERSION	0
94#define NGLE_MINOR_VERSION	1
95
96DriverRec NGLE = {
97	VERSION,
98	NGLE_DRIVER_NAME,
99	NGLEIdentify,
100	NGLEProbe,
101	NGLEAvailableOptions,
102	NULL,
103	0
104};
105
106/* Supported "chipsets" */
107static SymTabRec NGLEChipsets[] = {
108	{ STI_DD_EG, "Visualize EG" },
109	{ STI_DD_HCRX, "HCRX" },
110	{ -1, NULL }
111};
112
113/* Supported options */
114typedef enum {
115	OPTION_HW_CURSOR,
116	OPTION_SW_CURSOR
117} NGLEOpts;
118
119static const OptionInfoRec NGLEOptions[] = {
120	{ OPTION_SW_CURSOR, "SWcursor",	OPTV_BOOLEAN,	{0}, FALSE },
121	{ OPTION_HW_CURSOR, "HWcursor",	OPTV_BOOLEAN,	{0}, FALSE },
122	{ -1, NULL, OPTV_NONE, {0}, FALSE}
123};
124
125static XF86ModuleVersionInfo NGLEVersRec = {
126	"ngle",
127	"The NetBSD Foundation",
128	MODINFOSTRING1,
129	MODINFOSTRING2,
130	XORG_VERSION_CURRENT,
131	NGLE_MAJOR_VERSION, NGLE_MINOR_VERSION, 0,
132	ABI_CLASS_VIDEODRV,
133	ABI_VIDEODRV_VERSION,
134	NULL,
135	{0, 0, 0, 0}
136};
137
138_X_EXPORT XF86ModuleData ngleModuleData = { &NGLEVersRec, NGLESetup, NULL };
139
140static pointer
141NGLESetup(pointer module, pointer opts, int *errmaj, int *errmin)
142{
143	static Bool setupDone = FALSE;
144	const char *osname;
145
146	if (!setupDone) {
147		setupDone = TRUE;
148		xf86AddDriver(&NGLE, module, 0);
149		return (pointer)1;
150	} else {
151		if (errmaj != NULL)
152			*errmaj = LDR_ONCEONLY;
153		return NULL;
154	}
155}
156
157static Bool
158NGLEGetRec(ScrnInfoPtr pScrn)
159{
160
161	if (pScrn->driverPrivate != NULL)
162		return TRUE;
163
164	pScrn->driverPrivate = xnfcalloc(sizeof(NGLERec), 1);
165	return TRUE;
166}
167
168static void
169NGLEFreeRec(ScrnInfoPtr pScrn)
170{
171
172	if (pScrn->driverPrivate == NULL)
173		return;
174	free(pScrn->driverPrivate);
175	pScrn->driverPrivate = NULL;
176}
177
178static const OptionInfoRec *
179NGLEAvailableOptions(int chipid, int busid)
180{
181	return NGLEOptions;
182}
183
184static void
185NGLEIdentify(int flags)
186{
187	xf86PrintChipsets(NGLE_NAME, "driver for NGLE framebuffers",
188			  NGLEChipsets);
189}
190
191
192#define priv_open_device(n)	open(n,O_RDWR|O_NONBLOCK|O_EXCL)
193
194/* Open the framebuffer device */
195static int
196ngle_open(const char *dev)
197{
198	int fd = -1;
199
200	/* try argument from XF86Config first */
201	if (dev == NULL || ((fd = priv_open_device(dev)) == -1)) {
202		/* second: environment variable */
203		dev = getenv("XDEVICE");
204		if (dev == NULL || ((fd = priv_open_device(dev)) == -1)) {
205			/* last try: default device */
206			dev = NGLE_DEFAULT_DEV;
207			if ((fd = priv_open_device(dev)) == -1) {
208				return -1;
209			}
210		}
211	}
212	return fd;
213}
214
215/* Map the framebuffer's memory */
216static pointer
217ngle_mmap(size_t len, off_t off, int fd, int ro)
218{
219	pointer mapaddr;
220
221	/*
222	 * try and make it private first, that way once we get it, an
223	 * interloper, e.g. another server, can't get this frame buffer,
224	 * and if another server already has it, this one won't.
225	 */
226	if (ro) {
227		mapaddr = (pointer) mmap(NULL, len,
228					 PROT_READ, MAP_SHARED,
229					 fd, off);
230		xf86Msg(X_ERROR, "mapping %08x read only\n", off);
231	} else {
232		mapaddr = (pointer) mmap(NULL, len,
233					 PROT_READ | PROT_WRITE, MAP_SHARED,
234					 fd, off);
235		xf86Msg(X_ERROR, "mapping %08x read/write\n", off);
236	}
237	if (mapaddr == (pointer) -1) {
238		mapaddr = NULL;
239	}
240#ifdef NGLE_DEBUG
241	ErrorF("mmap returns: addr %p len 0x%x\n", mapaddr, len);
242#endif
243	return mapaddr;
244}
245
246static Bool
247NGLEProbe(DriverPtr drv, int flags)
248{
249	ScrnInfoPtr pScrn = NULL;
250	int i, fd, entity, wstype;
251       	GDevPtr *devSections;
252	int numDevSections;
253	char *dev;
254	const char *name;
255	uint32_t gid;
256	Bool foundScreen = FALSE;
257
258	if ((numDevSections = xf86MatchDevice(NGLE_DRIVER_NAME,
259					      &devSections)) <= 0)
260		return FALSE;
261
262
263	if ((fd = ngle_open(NGLE_DEFAULT_DEV)) == 0)
264		return FALSE;
265
266	if (ioctl(fd, WSDISPLAYIO_GTYPE, &wstype) == -1)
267		return FALSE;
268
269	if (wstype != WSDISPLAY_TYPE_STI)
270		return FALSE;
271
272	if (ioctl(fd, GCID, &gid) == -1)
273		return FALSE;
274
275	/* reject GIDs not in the table */
276	if ((name = xf86TokenToString(NGLEChipsets, gid)) == NULL)
277		return FALSE;
278
279	xf86Msg(X_INFO, "%s: found %s ( GID %08x )\n", __func__, name, gid);
280
281	if ( xf86DoConfigure && xf86DoConfigurePass1 ) {
282		GDevPtr pGDev;
283
284		pGDev = xf86AddBusDeviceToConfigure(NGLE_DRIVER_NAME, BUS_NONE,
285			NULL, 0);
286		if (pGDev) {
287			/*
288			 * XF86Match???Instances() treat chipID and chipRev as
289			 * overrides, so clobber them here.
290			 */
291			pGDev->chipID = pGDev->chipRev = -1;
292	    	}
293	}
294
295	if (flags & PROBE_DETECT) {
296		return TRUE;
297	}
298
299	if (numDevSections > 1) {
300		xf86Msg(X_ERROR, "Ignoring additional device sections\n");
301		numDevSections = 1;
302	}
303	/* ok, at this point we know we've got a NGLE */
304	for (i = 0; i < numDevSections; i++) {
305
306		entity = xf86ClaimFbSlot(drv, 0, devSections[i], TRUE);
307		pScrn = xf86ConfigFbEntity(NULL, 0, entity,
308		    NULL, NULL, NULL, NULL);
309		if (pScrn != NULL) {
310			foundScreen = TRUE;
311			pScrn->driverVersion = VERSION;
312			pScrn->driverName = NGLE_DRIVER_NAME;
313			pScrn->name = NGLE_NAME;
314			pScrn->Probe = NGLEProbe;
315			pScrn->PreInit = NGLEPreInit;
316			pScrn->ScreenInit = NGLEScreenInit;
317			pScrn->SwitchMode = NGLESwitchMode;
318			pScrn->AdjustFrame = NULL;
319			pScrn->EnterVT = NGLEEnterVT;
320			pScrn->LeaveVT = NGLELeaveVT;
321			pScrn->ValidMode = NGLEValidMode;
322
323		}
324	}
325	free(devSections);
326	return foundScreen;
327}
328
329static Bool
330NGLEPreInit(ScrnInfoPtr pScrn, int flags)
331{
332	NGLEPtr fPtr;
333	int default_depth, bitsperpixel, gid;
334	const char *dev;
335	char *mod = NULL;
336	const char *reqSym = NULL;
337	Gamma zeros = {0.0, 0.0, 0.0};
338	DisplayModePtr mode;
339	MessageType from;
340	rgb rgbzeros = { 0, 0, 0 }, masks;
341
342	if (flags & PROBE_DETECT) return FALSE;
343
344	if (pScrn->numEntities != 1) return FALSE;
345
346	pScrn->monitor = pScrn->confScreen->monitor;
347
348	NGLEGetRec(pScrn);
349	fPtr = NGLEPTR(pScrn);
350
351	fPtr->pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
352
353	dev = xf86FindOptionValue(fPtr->pEnt->device->options, "device");
354	fPtr->fd = ngle_open(dev);
355	if (fPtr->fd == -1) {
356		return FALSE;
357	}
358
359	if (ioctl(fPtr->fd, WSDISPLAYIO_GET_FBINFO, &fPtr->fbi) == -1) {
360		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
361			   "ioctl WSDISPLAY_GINFO: %s\n",
362			   strerror(errno));
363		return FALSE;
364	}
365
366	if (ioctl(fPtr->fd, GCID, &gid) == -1)
367		return FALSE;
368
369	fPtr->gid = gid;
370	fPtr->fbacc = 0;
371
372	switch (gid) {
373		case STI_DD_EG:
374			fPtr->buf = BINapp0I;
375			fPtr->fbacc = BA(IndexedDcd, Otc04, Ots08, AddrByte, 0, fPtr->buf, 0);
376			break;
377		case STI_DD_HCRX:
378			/* XXX BINovly if in 8 bit */
379			fPtr->buf = BINapp0F8;
380			fPtr->fbacc = BA(IndexedDcd, Otc04, Ots08, AddrLong, 0, fPtr->buf, 0);
381			/*
382			 * XXX
383			 * we don't know yet how much usable video memory we
384			 * have but EXA gets cranky if there is no off screen
385			 * memory at all, so we give it one line and cross
386			 * fingers
387			 */
388			fPtr->fbi.fbi_fbsize += 8192;
389	break;
390	}
391	xf86Msg(X_ERROR, "gid %08x fb access %08x\n", fPtr->gid, fPtr->fbacc);
392
393	/* Handle depth */
394	default_depth = fPtr->fbi.fbi_bitsperpixel <= 24 ? fPtr->fbi.fbi_bitsperpixel : 24;
395	bitsperpixel = fPtr->fbi.fbi_bitsperpixel == 15 ? 16 : fPtr->fbi.fbi_bitsperpixel;
396	if (!xf86SetDepthBpp(pScrn, default_depth, default_depth,
397		bitsperpixel,
398		bitsperpixel >= 24 ? Support24bppFb|Support32bppFb : 0))
399		return FALSE;
400
401	xf86PrintDepthBpp(pScrn);
402
403	/* color weight */
404	masks.red =   0x00ff0000;
405	masks.green = 0x0000ff00;
406	masks.blue =  0x000000ff;
407	if (!xf86SetWeight(pScrn, rgbzeros, masks))
408		return FALSE;
409
410	/* visual init */
411	if (!xf86SetDefaultVisual(pScrn, -1))
412		return FALSE;
413
414	/* We don't currently support DirectColor at > 8bpp */
415	if (pScrn->depth > 8 && pScrn->defaultVisual != TrueColor) {
416		xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Given default visual"
417			   " (%s) is not supported at depth %d\n",
418			   xf86GetVisualName(pScrn->defaultVisual),
419			   pScrn->depth);
420		return FALSE;
421	}
422
423	xf86SetGamma(pScrn,zeros);
424
425	pScrn->progClock = TRUE;
426	pScrn->rgbBits   = 8;
427	pScrn->chipset   = "NGLE";
428	fPtr->fbmem_len = pScrn->videoRam  = fPtr->fbi.fbi_fbsize;
429
430	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Vidmem: %dk\n",
431		   pScrn->videoRam/1024);
432
433	/* handle options */
434	xf86CollectOptions(pScrn, NULL);
435	if (!(fPtr->Options = malloc(sizeof(NGLEOptions))))
436		return FALSE;
437	memcpy(fPtr->Options, NGLEOptions, sizeof(NGLEOptions));
438	xf86ProcessOptions(pScrn->scrnIndex, fPtr->pEnt->device->options,
439			   fPtr->Options);
440
441	/* fake video mode struct */
442	mode = (DisplayModePtr)malloc(sizeof(DisplayModeRec));
443	mode->prev = mode;
444	mode->next = mode;
445	mode->name = "NGLE current mode";
446	mode->status = MODE_OK;
447	mode->type = M_T_BUILTIN;
448	mode->Clock = 0;
449	mode->HDisplay = fPtr->fbi.fbi_width;
450	mode->HSyncStart = 0;
451	mode->HSyncEnd = 0;
452	mode->HTotal = 0;
453	mode->HSkew = 0;
454	mode->VDisplay = fPtr->fbi.fbi_height;
455	mode->VSyncStart = 0;
456	mode->VSyncEnd = 0;
457	mode->VTotal = 0;
458	mode->VScan = 0;
459	mode->Flags = 0;
460	if (pScrn->modes != NULL) {
461		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
462		   "Ignoring mode specification from screen section\n");
463	}
464	pScrn->currentMode = pScrn->modes = mode;
465	pScrn->virtualX = fPtr->fbi.fbi_width;
466	pScrn->virtualY = fPtr->fbi.fbi_height;
467	pScrn->displayWidth = 2048;
468
469	/* Set the display resolution */
470	xf86SetDpi(pScrn, 0, 0);
471
472	from = X_DEFAULT;
473	fPtr->HWCursor = TRUE;
474	if (xf86GetOptValBool(fPtr->Options, OPTION_HW_CURSOR, &fPtr->HWCursor))
475		from = X_CONFIG;
476	if (xf86ReturnOptValBool(fPtr->Options, OPTION_SW_CURSOR, FALSE)) {
477		from = X_CONFIG;
478		fPtr->HWCursor = FALSE;
479	}
480	xf86DrvMsg(pScrn->scrnIndex, from, "Using %s cursor\n",
481		fPtr->HWCursor ? "HW" : "SW");
482
483	if (xf86LoadSubModule(pScrn, "fb") == NULL) {
484		NGLEFreeRec(pScrn);
485		return FALSE;
486	}
487
488	if (xf86LoadSubModule(pScrn, "exa") == NULL) {
489		NGLEFreeRec(pScrn);
490		return FALSE;
491	}
492
493	if (xf86LoadSubModule(pScrn, "ramdac") == NULL) {
494		NGLEFreeRec(pScrn);
495		return FALSE;
496	}
497
498	return TRUE;
499}
500
501static Bool
502NGLEScreenInit(SCREEN_INIT_ARGS_DECL)
503{
504	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
505	NGLEPtr fPtr = NGLEPTR(pScrn);
506	VisualPtr visual;
507	int ret, flags, width, height, i, j;
508	int wsmode = WSDISPLAYIO_MODE_MAPPED;
509	size_t len;
510
511#ifdef NGLE_DEBUG
512	ErrorF("\tbitsPerPixel=%d, depth=%d, defaultVisual=%s\n"
513	       "\tmask: %x,%x,%x, offset: %d,%d,%d\n",
514	       pScrn->bitsPerPixel,
515	       pScrn->depth,
516	       xf86GetVisualName(pScrn->defaultVisual),
517	       pScrn->mask.red,pScrn->mask.green,pScrn->mask.blue,
518	       pScrn->offset.red,pScrn->offset.green,pScrn->offset.blue);
519#endif
520
521	/* Switch to graphics mode - required before mmap */
522	if (ioctl(fPtr->fd, WSDISPLAYIO_SMODE, &wsmode) == -1) {
523		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
524			   "ioctl WSDISPLAYIO_SMODE: %s\n",
525			   strerror(errno));
526		return FALSE;
527	}
528	fPtr->regs = ngle_mmap(0x400000, 0x80000000, fPtr->fd, 0);
529
530	if (fPtr->regs == NULL) {
531		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
532			   "ngle_mmap registers: %s\n", strerror(errno));
533		return FALSE;
534	}
535
536	fPtr->fbmem = ngle_mmap(fPtr->fbmem_len, 0, fPtr->fd, 0);
537	if (fPtr->fbmem == NULL) {
538		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
539			   "ngle_mmap fb: %s\n", strerror(errno));
540		return FALSE;
541	}
542
543	NGLESave(pScrn);
544	pScrn->vtSema = TRUE;
545
546	/* mi layer */
547	miClearVisualTypes();
548	if (pScrn->bitsPerPixel > 8) {
549		if (!miSetVisualTypes(pScrn->depth, TrueColorMask,
550				      pScrn->rgbBits, TrueColor))
551			return FALSE;
552	} else {
553		if (!miSetVisualTypes(pScrn->depth,
554				      miGetDefaultVisualMask(pScrn->depth),
555				      pScrn->rgbBits, pScrn->defaultVisual))
556			return FALSE;
557	}
558
559	if (!miSetPixmapDepths())
560		return FALSE;
561
562	height = pScrn->virtualY;
563	width = pScrn->virtualX;
564
565	ret = fbScreenInit(pScreen,
566			   fPtr->fbmem,
567			   width, height,
568			   pScrn->xDpi, pScrn->yDpi,
569			   pScrn->displayWidth,
570			   pScrn->bitsPerPixel);
571
572	if (!ret)
573		return FALSE;
574
575	if (pScrn->bitsPerPixel > 8) {
576		/* Fixup RGB ordering. */
577		visual = pScreen->visuals + pScreen->numVisuals;
578		while (--visual >= pScreen->visuals) {
579			if ((visual->class | DynamicClass) == DirectColor) {
580				visual->offsetRed   = pScrn->offset.red;
581				visual->offsetGreen = pScrn->offset.green;
582				visual->offsetBlue  = pScrn->offset.blue;
583				visual->redMask     = pScrn->mask.red;
584				visual->greenMask   = pScrn->mask.green;
585				visual->blueMask    = pScrn->mask.blue;
586			}
587		}
588	}
589
590	if (!fbPictureInit(pScreen, NULL, 0))
591		xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
592			   "RENDER extension initialisation failed.");
593
594	xf86SetBlackWhitePixels(pScreen);
595	xf86SetBackingStore(pScreen);
596
597	if (fPtr) {
598		NGLEInitAccel(pScreen);
599		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using acceleration\n");
600	}
601
602	/* software cursor */
603	miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
604
605	/* check for hardware cursor support */
606	NGLESetupCursor(pScreen);
607
608	/* colormap */
609	if (!miCreateDefColormap(pScreen))
610		return FALSE;
611
612	flags = CMAP_RELOAD_ON_MODE_SWITCH;
613	if(!xf86HandleColormaps(pScreen, 256, 8, NGLELoadPalette,
614				NULL, flags))
615		return FALSE;
616
617	pScreen->SaveScreen = NGLESaveScreen;
618
619#ifdef XvExtension
620	{
621		XF86VideoAdaptorPtr *ptr;
622
623		int n = xf86XVListGenericAdaptors(pScrn,&ptr);
624		if (n) {
625			xf86XVScreenInit(pScreen,ptr,n);
626		}
627	}
628#endif
629
630	/* Wrap the current CloseScreen function */
631	fPtr->CloseScreen = pScreen->CloseScreen;
632	pScreen->CloseScreen = NGLECloseScreen;
633
634	return TRUE;
635}
636
637static Bool
638NGLECloseScreen(CLOSE_SCREEN_ARGS_DECL)
639{
640	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
641	NGLEPtr fPtr = NGLEPTR(pScrn);
642
643	if (pScrn->vtSema) {
644		NGLERestore(pScrn);
645		if (munmap(fPtr->regs, 0x40000) == -1) {
646			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
647				   "munmap engine: %s\n", strerror(errno));
648		}
649
650		if (munmap(fPtr->fbmem, fPtr->fbmem_len) == -1) {
651			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
652				   "munmap fb: %s\n", strerror(errno));
653		}
654
655		fPtr->regs = NULL;
656		fPtr->fbmem = NULL;
657	}
658	pScrn->vtSema = FALSE;
659
660	/* unwrap CloseScreen */
661	pScreen->CloseScreen = fPtr->CloseScreen;
662	return (*pScreen->CloseScreen)(pScreen);
663}
664
665static Bool
666NGLEEnterVT(VT_FUNC_ARGS_DECL)
667{
668	SCRN_INFO_PTR(arg);
669
670	pScrn->vtSema = TRUE;
671	return TRUE;
672}
673
674static void
675NGLELeaveVT(VT_FUNC_ARGS_DECL)
676{
677}
678
679static Bool
680NGLESwitchMode(SWITCH_MODE_ARGS_DECL)
681{
682
683	/* Nothing else to do */
684	return TRUE;
685}
686
687static int
688NGLEValidMode(SCRN_ARG_TYPE, DisplayModePtr mode, Bool verbose, int flags)
689{
690
691	return MODE_OK;
692}
693
694static void
695NGLELoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices,
696	       LOCO *colors, VisualPtr pVisual)
697{
698	NGLEPtr fPtr = NGLEPTR(pScrn);
699	struct wsdisplay_cmap cmap;
700	unsigned char red[256],green[256],blue[256];
701	int i, indexMin=256, indexMax=0;
702
703	/* nothing to do if there is no color palette support */
704	if (fPtr->fbi.fbi_subtype.fbi_cmapinfo.cmap_entries == 0)
705		return;
706
707	cmap.count   = 1;
708	cmap.red   = red;
709	cmap.green = green;
710	cmap.blue  = blue;
711
712	if (numColors == 1) {
713		/* Optimisation */
714		cmap.index = indices[0];
715		red[0]   = colors[indices[0]].red;
716		green[0] = colors[indices[0]].green;
717		blue[0]  = colors[indices[0]].blue;
718		if (ioctl(fPtr->fd,WSDISPLAYIO_PUTCMAP, &cmap) == -1)
719			ErrorF("ioctl FBIOPUTCMAP: %s\n", strerror(errno));
720	} else {
721		/*
722		 * Change all colors in 2 ioctls
723		 * and limit the data to be transferred.
724		 */
725		for (i = 0; i < numColors; i++) {
726			if (indices[i] < indexMin)
727				indexMin = indices[i];
728			if (indices[i] > indexMax)
729				indexMax = indices[i];
730		}
731		cmap.index = indexMin;
732		cmap.count = indexMax - indexMin + 1;
733		cmap.red = &red[indexMin];
734		cmap.green = &green[indexMin];
735		cmap.blue = &blue[indexMin];
736		/* Get current map. */
737		if (ioctl(fPtr->fd, WSDISPLAYIO_GETCMAP, &cmap) == -1)
738			ErrorF("ioctl FBIOGETCMAP: %s\n", strerror(errno));
739		/* Change the colors that require updating. */
740		for (i = 0; i < numColors; i++) {
741			red[indices[i]]   = colors[indices[i]].red;
742			green[indices[i]] = colors[indices[i]].green;
743			blue[indices[i]]  = colors[indices[i]].blue;
744		}
745		/* Write the colormap back. */
746		if (ioctl(fPtr->fd,WSDISPLAYIO_PUTCMAP, &cmap) == -1)
747			ErrorF("ioctl FBIOPUTCMAP: %s\n", strerror(errno));
748	}
749	fPtr->hwmode = -1;
750}
751
752static Bool
753NGLESaveScreen(ScreenPtr pScreen, int mode)
754{
755	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
756	NGLEPtr fPtr = NGLEPTR(pScrn);
757	int state;
758
759	if (!pScrn->vtSema)
760		return TRUE;
761
762	if (mode != SCREEN_SAVER_FORCER) {
763		state = xf86IsUnblank(mode)?WSDISPLAYIO_VIDEO_ON:
764		                            WSDISPLAYIO_VIDEO_OFF;
765		ioctl(fPtr->fd,
766		      WSDISPLAYIO_SVIDEO, &state);
767	}
768	return TRUE;
769}
770
771
772static void
773NGLESave(ScrnInfoPtr pScrn)
774{
775}
776
777static void
778NGLERestore(ScrnInfoPtr pScrn)
779{
780	NGLEPtr fPtr = NGLEPTR(pScrn);
781	int mode;
782
783	/* Restore the text mode */
784	mode = WSDISPLAYIO_MODE_EMUL;
785	if (ioctl(fPtr->fd, WSDISPLAYIO_SMODE, &mode) == -1) {
786		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
787			   "error setting text mode %s\n", strerror(errno));
788	}
789}
790