1/*	$NetBSD: grf_et.c,v 1.41 2023/12/20 00:40:42 thorpej Exp $ */
2
3/*
4 * Copyright (c) 1997 Klaus Burkert
5 * Copyright (c) 1996 Tobias Abt
6 * Copyright (c) 1995 Ezra Story
7 * Copyright (c) 1995 Kari Mettinen
8 * Copyright (c) 1994 Markus Wild
9 * Copyright (c) 1994 Lutz Vieweg
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 *    notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 *    notice, this list of conditions and the following disclaimer in the
19 *    documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 *    must display the following acknowledgement:
22 *      This product includes software developed by Lutz Vieweg.
23 * 4. The name of the author may not be used to endorse or promote products
24 *    derived from this software without specific prior written permission
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
27 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
28 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
30 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
31 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37#include "opt_amigacons.h"
38
39#include <sys/cdefs.h>
40__KERNEL_RCSID(0, "$NetBSD: grf_et.c,v 1.41 2023/12/20 00:40:42 thorpej Exp $");
41
42#include "grfet.h"
43#include "ite.h"
44#include "wsdisplay.h"
45#if NGRFET > 0
46
47/*
48 * Graphics routines for Tseng ET4000 (&W32) boards,
49 *
50 * This code offers low-level routines to access Tseng ET4000
51 * graphics-boards from within NetBSD for the Amiga.
52 * No warranties for any kind of function at all - this
53 * code may crash your hardware and scratch your harddisk.  Use at your
54 * own risk.  Freely distributable.
55 *
56 * Modified for Tseng ET4000 from
57 * Kari Mettinen's Cirrus driver by Tobias Abt
58 *
59 * Fixed Merlin in Z-III, fixed LACE and DBLSCAN, added Domino16M proto
60 * and AT&T ATT20c491 DAC, added memory-size detection by Klaus Burkert.
61 *
62 *
63 * TODO:
64 *
65 */
66
67#include <sys/param.h>
68#include <sys/systm.h>
69#include <sys/errno.h>
70#include <sys/ioctl.h>
71#include <sys/device.h>
72#include <sys/device_impl.h>	/* XXX autoconf abuse */
73
74#include <machine/cpu.h>
75#include <dev/cons.h>
76#if NWSDISPLAY > 0
77#include <dev/wscons/wsconsio.h>
78#include <dev/wscons/wsdisplayvar.h>
79#include <dev/rasops/rasops.h>
80#include <dev/wscons/wsdisplay_vconsvar.h>
81#endif
82#ifdef TSENGCONSOLE
83#include <amiga/dev/itevar.h>
84#endif
85#include <amiga/amiga/device.h>
86#include <amiga/dev/grfioctl.h>
87#include <amiga/dev/grfvar.h>
88#include <amiga/dev/grf_etreg.h>
89#include <amiga/dev/zbusvar.h>
90
91int	et_mondefok(struct grfvideo_mode *);
92void	et_boardinit(struct grf_softc *);
93static void et_CompFQ(u_int fq, u_char *, u_char *);
94int	et_getvmode(struct grf_softc *, struct grfvideo_mode *);
95int	et_setvmode(struct grf_softc *, unsigned int);
96int	et_toggle(struct grf_softc *, unsigned short);
97int	et_getcmap(struct grf_softc *, struct grf_colormap *);
98int	et_putcmap(struct grf_softc *, struct grf_colormap *);
99#ifndef TSENGCONSOLE
100void	et_off(struct grf_softc *);
101#endif
102void	et_inittextmode(struct grf_softc *);
103int	et_ioctl(register struct grf_softc *, u_long cmd, void *);
104int	et_getmousepos(struct grf_softc *, struct grf_position *);
105void	et_writesprpos(volatile char *ba, short, short);
106int	et_setmousepos(struct grf_softc *, struct grf_position *);
107static int et_setspriteinfo(struct grf_softc *, struct grf_spriteinfo *);
108int	et_getspriteinfo(struct grf_softc *, struct grf_spriteinfo *);
109static int et_getspritemax(struct grf_softc *, struct grf_position *);
110int	et_setmonitor(struct grf_softc *, struct grfvideo_mode *);
111int	et_blank(struct grf_softc *, int);
112int	et_isblank(struct grf_softc *);
113static int et_getControllerType(struct grf_softc *);
114static int et_getDACType(struct grf_softc *);
115
116int	grfetmatch(device_t, cfdata_t, void *);
117void	grfetattach(device_t, device_t, void *);
118int	grfetprint(void *, const char *);
119void	et_memset(volatile unsigned char *, unsigned char, int);
120
121#if NWSDISPLAY > 0
122/* wsdisplay acessops, emulops */
123static int	et_wsioctl(void *, void *, u_long, void *, int, struct lwp *);
124static int	et_get_fbinfo(struct grf_softc *, struct wsdisplayio_fbinfo *);
125
126static void	et_wscursor(void *, int, int, int);
127static void	et_wsputchar(void *, int, int, u_int, long);
128static void	et_wscopycols(void *, int, int, int, int);
129static void	et_wserasecols(void *, int, int, int, long);
130static void	et_wscopyrows(void *, int, int, int);
131static void	et_wseraserows(void *, int, int, long);
132static int	et_wsallocattr(void *, int, int, int, long *);
133static int	et_wsmapchar(void *, int, unsigned int *);
134#endif  /* NWSDISPLAY > 0 */
135
136/*
137 * Graphics display definitions.
138 * These are filled by 'grfconfig' using GRFIOCSETMON.
139 */
140#define monitor_def_max 24
141static struct grfvideo_mode monitor_def[24] = {
142	{0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
143	{0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
144	{0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}
145};
146static struct grfvideo_mode *monitor_current = &monitor_def[0];
147
148/* Console display definition.
149 *   Default hardcoded text mode.  This grf_et is set up to
150 *   use one text mode only, and this is it.  You may use
151 *   grfconfig to change the mode after boot.
152 */
153/* Console font */
154#ifdef KFONT_8X11
155#define TSENGFONT kernel_font_8x11
156#define TSENGFONTY 11
157#else
158#define TSENGFONT kernel_font_8x8
159#define TSENGFONTY 8
160#endif
161extern unsigned char TSENGFONT[];
162
163struct grfettext_mode etconsole_mode = {
164	{255, "", 25000000, 640, 480, 4, 640/8, 680/8, 768/8, 800/8,
165	 481, 491, 493, 525, 0},
166	8, TSENGFONTY, 640 / 8, 480 / TSENGFONTY, TSENGFONT, 32, 255
167};
168
169/* Console colors */
170unsigned char etconscolors[3][3] = {	/* background, foreground, hilite */
171	{0, 0x40, 0x50}, {152, 152, 152}, {255, 255, 255}
172};
173
174int ettype = 0;		/* oMniBus, Domino or Merlin */
175int etctype = 0;	/* ET4000 or ETW32 */
176int etdtype = 0;	/* Type of DAC (see grf_etregs.h) */
177
178char etcmap_shift = 0;	/* 6 or 8 bit cmap entries */
179unsigned char pass_toggle;	/* passthru status tracker */
180
181unsigned char Merlin_switch = 0;
182
183/*
184 * Because all Tseng-boards have 2 configdev entries, one for
185 * framebuffer mem and the other for regs, we have to hold onto
186 * the pointers globally until we match on both.  This and 'ettype'
187 * are the primary obsticles to multiple board support, but if you
188 * have multiple boards you have bigger problems than grf_et.
189 */
190static void *et_fbaddr = 0;	/* framebuffer */
191static void *et_regaddr = 0;	/* registers */
192static int et_fbsize;		/* framebuffer size */
193
194/* current sprite info, if you add support for multiple boards
195 * make this an array or something
196 */
197struct grf_spriteinfo et_cursprite;
198
199/* sprite bitmaps in kernel stack, you'll need to arrayize these too if
200 * you add multiple board support
201 */
202static unsigned char et_imageptr[8 * 64], et_maskptr[8 * 64];
203static unsigned char et_sprred[2], et_sprgreen[2], et_sprblue[2];
204
205#if NWSDISPLAY > 0
206static struct wsdisplay_accessops et_accessops = {
207	.ioctl		= et_wsioctl,
208	.mmap		= grf_wsmmap
209};
210
211static struct wsdisplay_emulops et_textops = {
212	.cursor		= et_wscursor,
213	.mapchar	= et_wsmapchar,
214	.putchar	= et_wsputchar,
215	.copycols	= et_wscopycols,
216	.erasecols	= et_wserasecols,
217	.copyrows	= et_wscopyrows,
218	.eraserows	= et_wseraserows,
219	.allocattr	= et_wsallocattr
220};
221
222static struct wsscreen_descr et_defaultscreen = {
223	.name		= "default",
224	.textops	= &et_textops,
225	.fontwidth	= 8,
226	.fontheight	= TSENGFONTY,
227	.capabilities	= WSSCREEN_HILIT | WSSCREEN_BLINK |
228			  WSSCREEN_REVERSE | WSSCREEN_UNDERLINE
229};
230
231static const struct wsscreen_descr *et_screens[] = {
232	&et_defaultscreen,
233};
234
235static struct wsscreen_list et_screenlist = {
236	sizeof(et_screens) / sizeof(struct wsscreen_descr *), et_screens
237};
238#endif  /* NWSDISPLAY > 0 */
239
240/* standard driver stuff */
241CFATTACH_DECL_NEW(grfet, sizeof(struct grf_softc),
242    grfetmatch, grfetattach, NULL, NULL);
243
244static struct cfdata *cfdata;
245
246int
247grfetmatch(device_t parent, cfdata_t cf, void *aux)
248{
249	struct zbus_args *zap;
250	static int regprod, regprod2 = 0, fbprod;
251
252	zap = aux;
253
254#ifndef TSENGCONSOLE
255	if (amiga_realconfig == 0)
256		return (0);
257#endif
258
259	/* Grab the first board we encounter as the preferred one.  This will
260	 * allow one board to work in a multiple Tseng board system, but not
261	 * multiple boards at the same time.  */
262	if (ettype == 0) {
263		switch (zap->manid) {
264		    case OMNIBUS:
265			if (zap->prodid != 0)
266				return (0);
267			regprod = 0;
268			fbprod = 0;
269			break;
270		    case DOMINO:
271			/* 2167/3 is Domino16M proto (crest) */
272			if (zap->prodid != 3 && zap->prodid != 2 && zap->prodid != 1)
273				return (0);
274			regprod = 2;
275			regprod2 = 3;
276			fbprod = 1;
277			break;
278		    case MERLIN:
279			if (zap->prodid != 3 && zap->prodid != 4)
280				return (0);
281			regprod = 4;
282			fbprod = 3;
283			break;
284		    default:
285			return (0);
286		}
287		ettype = zap->manid;
288	} else {
289		if (ettype != zap->manid) {
290			return (0);
291		}
292	}
293
294	/* Configure either registers or framebuffer in any order */
295	/* as said before, oMniBus does not support ProdID */
296	if (ettype == OMNIBUS) {
297		if (zap->size == 64 * 1024) {
298			/* register area */
299			et_regaddr = zap->va;
300		} else {
301			/* memory area */
302			et_fbaddr = zap->va;
303			et_fbsize = zap->size;
304		}
305	} else {
306		if (zap->prodid == regprod || zap->prodid == regprod2) {
307			et_regaddr = zap->va;
308		} else {
309			if (zap->prodid == fbprod) {
310				et_fbaddr = zap->va;
311				et_fbsize = zap->size;
312			} else {
313				return (0);
314			}
315		}
316	}
317
318#ifdef TSENGCONSOLE
319	if (amiga_realconfig == 0) {
320		cfdata = cf;
321	}
322#endif
323
324	return (1);
325}
326
327
328void
329grfetattach(device_t parent, device_t self, void *aux)
330{
331	static struct grf_softc congrf;
332	static char attachflag = 0;
333	struct device temp;
334	struct grf_softc *gp;
335
336	printf("\n");
337
338	/* make sure both halves have matched */
339	if (!et_regaddr || !et_fbaddr)
340		return;
341
342	/* do all that messy console/grf stuff */
343	if (self == NULL) {
344		gp = &congrf;
345		gp->g_device = &temp;
346		temp.dv_private = gp;
347	} else {
348		gp = device_private(self);
349		gp->g_device = self;
350	}
351
352	if (self != NULL && congrf.g_regkva != 0) {
353		/*
354		 * inited earlier, just copy (not device struct)
355		 */
356		memcpy(&gp->g_display, &congrf.g_display,
357		    (char *) &gp[1] - (char *) &gp->g_display);
358	} else {
359		gp->g_regkva = (volatile void *) et_regaddr;
360		gp->g_fbkva = (volatile void *) et_fbaddr;
361
362		gp->g_unit = GRF_ET4000_UNIT;
363		gp->g_mode = et_mode;
364#if NITE > 0
365		gp->g_conpri = grfet_cnprobe();
366#endif
367		gp->g_flags = GF_ALIVE;
368
369		/* wakeup the board */
370		et_boardinit(gp);
371
372#ifdef TSENGCONSOLE
373#if NWSDISPLAY > 0
374		gp->g_accessops = &et_accessops;
375		gp->g_emulops = &et_textops;
376		gp->g_defaultscr = &et_defaultscreen;
377		gp->g_scrlist = &et_screenlist;
378#else
379#if NITE > 0
380		grfet_iteinit(gp);
381#endif
382#endif  /* NWSDISPLAY > 0 */
383		(void) et_load_mon(gp, &etconsole_mode);
384#endif
385	}
386
387	/*
388	 * attach grf (once)
389	 */
390	if (amiga_config_found(cfdata, gp->g_device, gp, grfetprint,
391			       CFARGS_NONE)) {
392		attachflag = 1;
393		printf("grfet: %dMB ", et_fbsize / 0x100000);
394		switch (ettype) {
395		    case OMNIBUS:
396			printf("oMniBus");
397			break;
398		    case DOMINO:
399			printf("Domino");
400			break;
401		    case MERLIN:
402			printf("Merlin");
403			break;
404		}
405		printf(" with ");
406		switch (etctype) {
407		    case ET4000:
408			printf("Tseng ET4000");
409			break;
410		    case ETW32:
411			printf("Tseng ETW32");
412			break;
413		}
414		printf(" and ");
415		switch (etdtype) {
416		    case SIERRA11483:
417			printf("Sierra SC11483 DAC");
418			break;
419		    case SIERRA15025:
420			printf("Sierra SC15025 DAC");
421			break;
422		    case MUSICDAC:
423			printf("MUSIC DAC");
424			break;
425		    case MERLINDAC:
426			printf("BrookTree Bt482 DAC");
427			break;
428		    case ATT20C491:
429			printf("AT&T ATT20c491 DAC");
430			break;
431		}
432		printf(" being used\n");
433	} else {
434		if (!attachflag)
435			printf("grfet unattached!!\n");
436	}
437}
438
439
440int
441grfetprint(void *aux, const char *pnp)
442{
443	if (pnp)
444		aprint_normal("ite at %s: ", pnp);
445	return (UNCONF);
446}
447
448
449void
450et_boardinit(struct grf_softc *gp)
451{
452	volatile unsigned char *ba = gp->g_regkva;
453	int     x;
454
455	/* wakeup board and flip passthru OFF */
456
457	RegWakeup(ba);
458	RegOnpass(ba);
459
460	if (ettype == MERLIN) {
461		/* Merlin needs some special initialisations */
462		vgaw(ba, MERLIN_SWITCH_REG, 0);
463		delay(20000);
464		vgaw(ba, MERLIN_SWITCH_REG, 8);
465		delay(20000);
466		vgaw(ba, MERLIN_SWITCH_REG, 0);
467		delay(20000);
468		vgaw(ba, MERLIN_VDAC_DATA, 1);
469
470		vgaw(ba, MERLIN_VDAC_INDEX, 0x00);
471		vgaw(ba, MERLIN_VDAC_SPRITE,  0xff);
472		vgaw(ba, MERLIN_VDAC_INDEX, 0x01);
473		vgaw(ba, MERLIN_VDAC_SPRITE,  0x0f);
474		vgaw(ba, MERLIN_VDAC_INDEX, 0x02);
475		vgaw(ba, MERLIN_VDAC_SPRITE,  0x42);
476		vgaw(ba, MERLIN_VDAC_INDEX, 0x03);
477		vgaw(ba, MERLIN_VDAC_SPRITE,  0x00);
478
479		vgaw(ba, MERLIN_VDAC_DATA, 0);
480	}
481
482
483	/* setup initial unchanging parameters */
484
485	vgaw(ba, GREG_HERCULESCOMPAT + ((ettype == DOMINO) ? 0x0fff : 0), 0x03);
486	vgaw(ba, GREG_DISPMODECONTROL, 0xa0);
487	vgaw(ba, GREG_MISC_OUTPUT_W, 0x63);
488
489	if (ettype == DOMINO)
490	{
491		vgaw(ba, CRT_ADDRESS, CRT_ID_VIDEO_CONFIG1);
492		vgaw(ba, CRT_ADDRESS_W + 0x0fff,
493		    0xc0 | vgar(ba, CRT_ADDRESS_R + 0x0fff));
494	}
495
496	WSeq(ba, SEQ_ID_RESET, 0x03);
497	WSeq(ba, SEQ_ID_CLOCKING_MODE, 0x21);	/* 8 dot, Display off */
498	WSeq(ba, SEQ_ID_MAP_MASK, 0x0f);
499	WSeq(ba, SEQ_ID_CHAR_MAP_SELECT, 0x00);
500	WSeq(ba, SEQ_ID_MEMORY_MODE, 0x0e);
501	WSeq(ba, SEQ_ID_STATE_CONTROL, 0x00);
502	WSeq(ba, SEQ_ID_AUXILIARY_MODE, 0xf4);
503
504	WCrt(ba, CRT_ID_PRESET_ROW_SCAN, 0x00);
505	WCrt(ba, CRT_ID_CURSOR_START, 0x00);
506	WCrt(ba, CRT_ID_CURSOR_END, 0x08);
507	WCrt(ba, CRT_ID_START_ADDR_HIGH, 0x00);
508	WCrt(ba, CRT_ID_START_ADDR_LOW, 0x00);
509	WCrt(ba, CRT_ID_CURSOR_LOC_HIGH, 0x00);
510	WCrt(ba, CRT_ID_CURSOR_LOC_LOW, 0x00);
511
512	WCrt(ba, CRT_ID_UNDERLINE_LOC, 0x67);
513	WCrt(ba, CRT_ID_MODE_CONTROL, 0xc3);
514	WCrt(ba, CRT_ID_LINE_COMPARE, 0xff);
515
516	/* ET4000 special */
517	WCrt(ba, CRT_ID_RASCAS_CONFIG, 0x28);
518	WCrt(ba, CRT_ID_EXT_START, 0x00);
519	WCrt(ba, CRT_ID_6845_COMPAT, 0x08);
520
521	/* ET4000/W32 special (currently only for Merlin (crest) */
522	if (ettype == MERLIN) {
523		WCrt(ba, CRT_ID_SEGMENT_COMP, 0x1c);
524		WCrt(ba, CRT_ID_GENERAL_PURPOSE, 0x00);
525		WCrt(ba, CRT_ID_VIDEO_CONFIG1, 0x93);
526	}
527	else {
528		WCrt(ba, CRT_ID_VIDEO_CONFIG1, 0xd3);
529	}
530
531	WCrt(ba, CRT_ID_VIDEO_CONFIG2, 0x0f);
532	WCrt(ba, CRT_ID_HOR_OVERFLOW, 0x00);
533
534	vgaw(ba, GREG_SEGMENTSELECT, 0x00);
535
536	WGfx(ba, GCT_ID_SET_RESET, 0x00);
537	WGfx(ba, GCT_ID_ENABLE_SET_RESET, 0x00);
538	WGfx(ba, GCT_ID_COLOR_COMPARE, 0x00);
539	WGfx(ba, GCT_ID_DATA_ROTATE, 0x00);
540	WGfx(ba, GCT_ID_READ_MAP_SELECT, 0x00);
541	WGfx(ba, GCT_ID_GRAPHICS_MODE, 0x40);
542	WGfx(ba, GCT_ID_MISC, 0x01);
543	WGfx(ba, GCT_ID_COLOR_XCARE, 0x0f);
544	WGfx(ba, GCT_ID_BITMASK, 0xff);
545
546	for (x = 0; x < 0x10; x++)
547		WAttr(ba, x, x);
548	WAttr(ba, ACT_ID_ATTR_MODE_CNTL, 0x01);
549	WAttr(ba, ACT_ID_OVERSCAN_COLOR, 0x00);
550	WAttr(ba, ACT_ID_COLOR_PLANE_ENA, 0x0f);
551	WAttr(ba, ACT_ID_HOR_PEL_PANNING, 0x00);
552	WAttr(ba, ACT_ID_COLOR_SELECT, 0x00);
553	WAttr(ba, ACT_ID_MISCELLANEOUS, 0x00);
554
555	vgaw(ba, VDAC_MASK, 0xff);
556	delay(200000);
557	vgaw(ba, GREG_MISC_OUTPUT_W, 0xe3);
558
559	/* colors initially set to greyscale */
560	switch(ettype) {
561	    case MERLIN:
562		vgaw(ba, MERLIN_VDAC_INDEX, 0);
563		for (x = 255; x >= 0; x--) {
564			vgaw(ba, MERLIN_VDAC_COLORS, x);
565			vgaw(ba, MERLIN_VDAC_COLORS, x);
566			vgaw(ba, MERLIN_VDAC_COLORS, x);
567		}
568		break;
569	    default:
570		vgaw(ba, VDAC_ADDRESS_W, 0);
571		for (x = 255; x >= 0; x--) {
572			vgaw(ba, VDAC_DATA + ((ettype == DOMINO) ? 0x0fff : 0), x);
573			vgaw(ba, VDAC_DATA + ((ettype == DOMINO) ? 0x0fff : 0), x);
574			vgaw(ba, VDAC_DATA + ((ettype == DOMINO) ? 0x0fff : 0), x);
575		}
576		break;
577	}
578	/* set sprite bitmap pointers */
579	/* should work like that */
580	et_cursprite.image = et_imageptr;
581	et_cursprite.mask = et_maskptr;
582	et_cursprite.cmap.red = et_sprred;
583	et_cursprite.cmap.green = et_sprgreen;
584	et_cursprite.cmap.blue = et_sprblue;
585
586	/* card specific initialisations */
587	switch(ettype) {
588	    case OMNIBUS:
589		etctype = et_getControllerType(gp);
590		etdtype = et_getDACType(gp);
591		break;
592	    case MERLIN:
593		vgaw(ba, GREG_SEGMENTSELECT2, 0x00);
594		if (((vgar(ba, GREG_FEATURE_CONTROL_R) & 12) |
595		     (vgar(ba, GREG_STATUS0_R) & 0x60)) == 0x24) {
596			WCrt(ba, CRT_ID_VIDEO_CONFIG2, 0x07);	/* 1Mx4 RAM */
597			et_fbsize = 0x400000;			/* 4 MB */
598		}
599		else {
600			/* check for 1MB or 2MB board (crest) */
601			/* has there a 1MB Merlin ever been sold ??? */
602			volatile unsigned long *et_fbtestaddr;
603			et_fbtestaddr = (volatile unsigned long *)gp->g_fbkva;
604			*et_fbtestaddr = 0x0;
605			vgaw(ba, GREG_SEGMENTSELECT2, 0x11); /* 1MB offset */
606			*et_fbtestaddr = 0x12345678;
607			vgaw(ba, GREG_SEGMENTSELECT2, 0x00);
608			if (*et_fbtestaddr == 0x0)
609				et_fbsize = 0x200000;		/* 2 MB */
610			else
611				et_fbsize = 0x100000;		/* 1 MB */
612		}
613		/* ZorroII can map 2 MB max ... */
614		if (!iszthreepa(kvtop(__UNVOLATILE(gp->g_fbkva))) &&
615		    et_fbsize == 0x400000)
616			et_fbsize = 0x200000;
617		etctype = ETW32;
618		etdtype = MERLINDAC;
619		break;
620	    case DOMINO:
621		etctype = ET4000;
622		etdtype = et_getDACType(gp);
623		break;
624	}
625}
626
627
628int
629et_getvmode(struct grf_softc *gp, struct grfvideo_mode *vm)
630{
631	struct grfvideo_mode *gv;
632
633#ifdef TSENGCONSOLE
634	/* Handle grabbing console mode */
635	if (vm->mode_num == 255) {
636		memcpy(vm, &etconsole_mode, sizeof(struct grfvideo_mode));
637	/* XXX so grfconfig can tell us the correct text dimensions. */
638		vm->depth = etconsole_mode.fy;
639	} else
640#endif
641	{
642		if (vm->mode_num == 0)
643			vm->mode_num = (monitor_current - monitor_def) + 1;
644		if (vm->mode_num < 1 || vm->mode_num > monitor_def_max)
645			return (EINVAL);
646		gv = monitor_def + (vm->mode_num - 1);
647		if (gv->mode_num == 0)
648			return (EINVAL);
649
650		memcpy(vm, gv, sizeof(struct grfvideo_mode));
651	}
652
653	/* adjust internal values to pixel values */
654
655	vm->hblank_start *= 8;
656	vm->hsync_start *= 8;
657	vm->hsync_stop *= 8;
658	vm->htotal *= 8;
659
660	return (0);
661}
662
663
664int
665et_setvmode(struct grf_softc *gp, unsigned mode)
666{
667	if (!mode || (mode > monitor_def_max) ||
668	    monitor_def[mode - 1].mode_num == 0)
669		return (EINVAL);
670
671	monitor_current = monitor_def + (mode - 1);
672
673	return (0);
674}
675
676
677#ifndef TSENGCONSOLE
678void
679et_off(struct grf_softc *gp)
680{
681	char   *ba = gp->g_regkva;
682
683	RegOnpass(ba);
684	WSeq(ba, SEQ_ID_CLOCKING_MODE, 0x21);
685}
686#endif
687
688
689int
690et_blank(struct grf_softc *gp, int on)
691{
692
693	WSeq(gp->g_regkva, SEQ_ID_CLOCKING_MODE, on > 0 ? 0x01 : 0x21);
694	return 0;
695}
696
697
698int
699et_isblank(struct grf_softc *gp)
700{
701	int r;
702
703	r = RSeq(gp->g_regkva, SEQ_ID_CLOCKING_MODE);
704	return (r & 0x20) != 0;
705}
706
707
708/*
709 * Change the mode of the display.
710 * Return a UNIX error number or 0 for success.
711 */
712int
713et_mode(register struct grf_softc *gp, u_long cmd, void *arg, u_long a2,
714        int a3)
715{
716	int error;
717
718	switch (cmd) {
719	    case GM_GRFON:
720		error = et_load_mon(gp,
721		    (struct grfettext_mode *) monitor_current) ? 0 : EINVAL;
722		return (error);
723
724	    case GM_GRFOFF:
725#ifndef TSENGCONSOLE
726		et_off(gp);
727#else
728		et_load_mon(gp, &etconsole_mode);
729#endif
730		return (0);
731
732	    case GM_GRFCONFIG:
733		return (0);
734
735	    case GM_GRFGETVMODE:
736		return (et_getvmode(gp, (struct grfvideo_mode *) arg));
737
738	    case GM_GRFSETVMODE:
739		error = et_setvmode(gp, *(unsigned *) arg);
740		if (!error && (gp->g_flags & GF_GRFON))
741			et_load_mon(gp,
742			    (struct grfettext_mode *) monitor_current);
743		return (error);
744
745	    case GM_GRFGETNUMVM:
746		*(int *) arg = monitor_def_max;
747		return (0);
748
749	    case GM_GRFIOCTL:
750		return (et_ioctl(gp, a2, arg));
751
752	    default:
753		break;
754	}
755
756	return (EPASSTHROUGH);
757}
758
759
760int
761et_ioctl(register struct grf_softc *gp, u_long cmd, void *data)
762{
763	switch (cmd) {
764	    case GRFIOCGSPRITEPOS:
765		return (et_getmousepos(gp, (struct grf_position *) data));
766
767	    case GRFIOCSSPRITEPOS:
768		return (et_setmousepos(gp, (struct grf_position *) data));
769
770	    case GRFIOCSSPRITEINF:
771		return (et_setspriteinfo(gp, (struct grf_spriteinfo *) data));
772
773	    case GRFIOCGSPRITEINF:
774		return (et_getspriteinfo(gp, (struct grf_spriteinfo *) data));
775
776	    case GRFIOCGSPRITEMAX:
777		return (et_getspritemax(gp, (struct grf_position *) data));
778
779	    case GRFIOCGETCMAP:
780		return (et_getcmap(gp, (struct grf_colormap *) data));
781
782	    case GRFIOCPUTCMAP:
783		return (et_putcmap(gp, (struct grf_colormap *) data));
784
785	    case GRFIOCBITBLT:
786		break;
787
788	    case GRFTOGGLE:
789		return (et_toggle(gp, 0));
790
791	    case GRFIOCSETMON:
792		return (et_setmonitor(gp, (struct grfvideo_mode *) data));
793
794	    case GRFIOCBLANK:
795		return (et_blank(gp, *(int *)data));
796	}
797	return (EPASSTHROUGH);
798}
799
800
801int
802et_getmousepos(struct grf_softc *gp, struct grf_position *data)
803{
804	data->x = et_cursprite.pos.x;
805	data->y = et_cursprite.pos.y;
806
807	return (0);
808}
809
810
811void
812et_writesprpos(volatile char *ba, short x, short y)
813{
814}
815
816
817int
818et_setmousepos(struct grf_softc *gp, struct grf_position *data)
819{
820	volatile char *ba = gp->g_regkva;
821	short rx, ry;
822
823	/* no movement */
824	if (et_cursprite.pos.x == data->x && et_cursprite.pos.y == data->y)
825		return (0);
826
827	/* current and previous real coordinates */
828	rx = data->x - et_cursprite.hot.x;
829	ry = data->y - et_cursprite.hot.y;
830
831	/* if we are/were on an edge, create (un)shifted bitmap --
832	 * ripped out optimization (not extremely worthwhile,
833	 * and kind of buggy anyhow).
834	 */
835
836	/* do movement, save position */
837	et_writesprpos(ba, rx < 0 ? 0 : rx, ry < 0 ? 0 : ry);
838	et_cursprite.pos.x = data->x;
839	et_cursprite.pos.y = data->y;
840
841	return (0);
842}
843
844
845int
846et_getspriteinfo(struct grf_softc *gp, struct grf_spriteinfo *data)
847{
848
849	return(EINVAL);
850}
851
852
853static int
854et_setspriteinfo(struct grf_softc *gp, struct grf_spriteinfo *data)
855{
856
857	return(EINVAL);
858}
859
860
861static int
862et_getspritemax(struct grf_softc *gp, struct grf_position *data)
863{
864
865	return(EINVAL);
866}
867
868
869int
870et_setmonitor(struct grf_softc *gp, struct grfvideo_mode *gv)
871{
872	struct grfvideo_mode *md;
873
874	if (!et_mondefok(gv))
875		return(EINVAL);
876
877#ifdef TSENGCONSOLE
878	/* handle interactive setting of console mode */
879	if (gv->mode_num == 255) {
880		memcpy(&etconsole_mode.gv, gv, sizeof(struct grfvideo_mode));
881		etconsole_mode.gv.hblank_start /= 8;
882		etconsole_mode.gv.hsync_start /= 8;
883		etconsole_mode.gv.hsync_stop /= 8;
884		etconsole_mode.gv.htotal /= 8;
885		etconsole_mode.rows = gv->disp_height / etconsole_mode.fy;
886		etconsole_mode.cols = gv->disp_width / etconsole_mode.fx;
887		if (!(gp->g_flags & GF_GRFON))
888			et_load_mon(gp, &etconsole_mode);
889#if NITE > 0
890		ite_reinit(gp->g_itedev);
891#endif
892		return (0);
893	}
894#endif
895
896	md = monitor_def + (gv->mode_num - 1);
897	memcpy(md, gv, sizeof(struct grfvideo_mode));
898
899	/* adjust pixel oriented values to internal rep. */
900
901	md->hblank_start /= 8;
902	md->hsync_start /= 8;
903	md->hsync_stop /= 8;
904	md->htotal /= 8;
905
906	return (0);
907}
908
909
910int
911et_getcmap(struct grf_softc *gfp, struct grf_colormap *cmap)
912{
913	volatile unsigned char *ba;
914	u_char	red[256], green[256], blue[256], *rp, *gp, *bp;
915	short	x;
916	int	error;
917
918	if (cmap->count == 0 || cmap->index >= 256)
919		return 0;
920
921	if (cmap->count > 256 - cmap->index)
922		cmap->count = 256 - cmap->index;
923
924	ba = gfp->g_regkva;
925	/* first read colors out of the chip, then copyout to userspace */
926	x = cmap->count - 1;
927
928	rp = red + cmap->index;
929	gp = green + cmap->index;
930	bp = blue + cmap->index;
931
932	switch(ettype) {
933	    case MERLIN:
934		vgaw(ba, MERLIN_VDAC_INDEX, cmap->index);
935		do {
936			*rp++ = vgar(ba, MERLIN_VDAC_COLORS);
937			*gp++ = vgar(ba, MERLIN_VDAC_COLORS);
938			*bp++ = vgar(ba, MERLIN_VDAC_COLORS);
939		} while (x-- > 0);
940		break;
941	    default:
942		vgaw(ba, VDAC_ADDRESS_R+((ettype==DOMINO)?0x0fff:0), cmap->index);
943		do {
944			*rp++ = vgar(ba, VDAC_DATA+((ettype==DOMINO)?0x0fff:0)) << etcmap_shift;
945			*gp++ = vgar(ba, VDAC_DATA+((ettype==DOMINO)?0x0fff:0)) << etcmap_shift;
946			*bp++ = vgar(ba, VDAC_DATA+((ettype==DOMINO)?0x0fff:0)) << etcmap_shift;
947		} while (x-- > 0);
948		break;
949	}
950
951	error = copyout(red + cmap->index, cmap->red, cmap->count);
952	if (!error)
953		error = copyout(green + cmap->index, cmap->green, cmap->count);
954	if (!error)
955		error = copyout(blue + cmap->index, cmap->blue, cmap->count);
956
957	return (error);
958}
959
960
961int
962et_putcmap(struct grf_softc *gfp, struct grf_colormap *cmap)
963{
964	volatile unsigned char *ba;
965	u_char	red[256], green[256], blue[256], *rp, *gp, *bp;
966	short	x;
967	int	error;
968
969	if (cmap->count == 0 || cmap->index >= 256)
970		return (0);
971
972	if (cmap->count > 256 - cmap->index)
973		cmap->count = 256 - cmap->index;
974
975	/* first copy the colors into kernelspace */
976	if ((error = copyin(cmap->red, red + cmap->index, cmap->count)))
977		return (error);
978
979	if ((error = copyin(cmap->green, green + cmap->index, cmap->count)))
980		return (error);
981
982	if ((error = copyin(cmap->blue, blue + cmap->index, cmap->count)))
983		return (error);
984
985	ba = gfp->g_regkva;
986	x = cmap->count - 1;
987
988	rp = red + cmap->index;
989	gp = green + cmap->index;
990	bp = blue + cmap->index;
991
992	switch(ettype){
993	    case MERLIN:
994		vgaw(ba, MERLIN_VDAC_INDEX, cmap->index);
995		do {
996			vgaw(ba, MERLIN_VDAC_COLORS, *rp++);
997			vgaw(ba, MERLIN_VDAC_COLORS, *gp++);
998			vgaw(ba, MERLIN_VDAC_COLORS, *bp++);
999		} while (x-- > 0);
1000		break;
1001	    default:
1002		vgaw(ba, VDAC_ADDRESS_W, cmap->index);
1003		do {
1004			vgaw(ba, VDAC_DATA + ((ettype == DOMINO) ? 0x0fff : 0),
1005			    *rp++ >> etcmap_shift);
1006			vgaw(ba, VDAC_DATA + ((ettype == DOMINO) ? 0x0fff : 0),
1007			    *gp++ >> etcmap_shift);
1008			vgaw(ba, VDAC_DATA + ((ettype == DOMINO) ? 0x0fff : 0),
1009			    *bp++ >> etcmap_shift);
1010		} while (x-- > 0);
1011		break;
1012	}
1013
1014	return (0);
1015}
1016
1017
1018int
1019et_toggle(struct grf_softc *gp, unsigned short wopp)
1020/* (variable wopp) don't need that one yet, ill */
1021{
1022	volatile unsigned char *ba;
1023
1024	ba = gp->g_regkva;
1025
1026	if (pass_toggle) {
1027		RegOffpass(ba);
1028	} else {
1029		RegOnpass(ba);
1030	}
1031	return (0);
1032}
1033
1034
1035#define ET_NUMCLOCKS 32
1036
1037static u_char et_clocks[ET_NUMCLOCKS] = {
1038	0, 1, 6, 2, 3, 7, 4, 5,
1039	0, 1, 6, 2, 3, 7, 4, 5,
1040	0, 1, 6, 2, 3, 7, 4, 5,
1041	0, 1, 6, 2, 3, 7, 4, 5
1042};
1043
1044static u_char et_clockdividers[ET_NUMCLOCKS] = {
1045	3, 3, 3, 3, 3, 3, 3, 3,
1046	2, 2, 2, 2, 2, 2, 2, 2,
1047	1, 1, 1, 1, 1, 1, 1, 1,
1048	0, 0, 0, 0, 0, 0, 0, 0
1049};
1050
1051static u_int et_clockfreqs[ET_NUMCLOCKS] = {
1052	 6293750,  7080500,  7875000,  8125000,
1053	 9000000,  9375000, 10000000, 11225000,
1054	12587500, 14161000, 15750000, 16250000,
1055	18000000, 18750000, 20000000, 22450000,
1056	25175000, 28322000, 31500000, 32500000,
1057	36000000, 37500000, 40000000, 44900000,
1058	50350000, 56644000, 63000000, 65000000,
1059	72000000, 75000000, 80000000, 89800000
1060};
1061
1062
1063static void
1064et_CompFQ(u_int fq, u_char *num, u_char *denom)
1065{
1066	int i;
1067
1068	for (i=0; i < ET_NUMCLOCKS;) {
1069		if (fq <= et_clockfreqs[i++]) {
1070			break;
1071		}
1072	}
1073
1074	*num = et_clocks[--i];
1075	*denom = et_clockdividers[i];
1076
1077	return;
1078}
1079
1080
1081int
1082et_mondefok(struct grfvideo_mode *gv)
1083{
1084        unsigned long maxpix;
1085
1086	if (gv->mode_num < 1 || gv->mode_num > monitor_def_max)
1087		if (gv->mode_num != 255 || gv->depth != 4)
1088			return(0);
1089
1090	switch (gv->depth) {
1091	    case 4:
1092		if (gv->mode_num != 255)
1093			return(0);
1094	    case 1:
1095	    case 8:
1096                maxpix = 85000000;
1097                break;
1098	    case 15:
1099	    case 16:
1100                maxpix = 45000000;
1101                break;
1102	    case 24:
1103                maxpix = 28000000;
1104                break;
1105	    case 32:
1106                maxpix = 21000000;
1107                break;
1108	    default:
1109		printf("grfet: Illegal depth in mode %d\n",
1110			(int) gv->mode_num);
1111		return (0);
1112	}
1113
1114        if (gv->pixel_clock > maxpix) {
1115		printf("grfet: Pixelclock too high in mode %d\n",
1116			(int) gv->mode_num);
1117                return (0);
1118	}
1119
1120	if (gv->disp_flags & GRF_FLAGS_SYNC_ON_GREEN) {
1121		printf("grfet: sync-on-green is not supported\n");
1122		return (0);
1123	}
1124
1125	return (1);
1126}
1127
1128
1129int
1130et_load_mon(struct grf_softc *gp, struct grfettext_mode *md)
1131{
1132	struct grfvideo_mode *gv;
1133	struct grfinfo *gi;
1134	volatile unsigned char *ba;
1135	unsigned char num0, denom0;
1136	unsigned short HT, HDE, HBS, HBE, HSS, HSE, VDE, VBS, VBE, VSS,
1137	        VSE, VT;
1138	unsigned char hvsync_pulse, seq;
1139	char    TEXT;
1140	int	hmul;
1141
1142	/* identity */
1143	gv = &md->gv;
1144	TEXT = (gv->depth == 4);
1145
1146	if (!et_mondefok(gv)) {
1147		printf("grfet: Monitor definition not ok\n");
1148		return (0);
1149	}
1150
1151	ba = gp->g_regkva;
1152
1153	/* provide all needed information in grf device-independent locations */
1154	gp->g_data = (void *) gv;
1155	gi = &gp->g_display;
1156	gi->gd_regaddr = ztwopa(__UNVOLATILE(ba));
1157	gi->gd_regsize = 64 * 1024;
1158	gi->gd_fbaddr = (void *) kvtop(__UNVOLATILE(gp->g_fbkva));
1159	gi->gd_fbsize = et_fbsize;
1160	gi->gd_colors = 1 << gv->depth;
1161	gi->gd_planes = gv->depth;
1162	gi->gd_fbwidth = gv->disp_width;
1163	gi->gd_fbheight = gv->disp_height;
1164	gi->gd_fbx = 0;
1165	gi->gd_fby = 0;
1166	if (TEXT) {
1167		gi->gd_dwidth = md->fx * md->cols;
1168		gi->gd_dheight = md->fy * md->rows;
1169	} else {
1170		gi->gd_dwidth = gv->disp_width;
1171		gi->gd_dheight = gv->disp_height;
1172	}
1173	gi->gd_dx = 0;
1174	gi->gd_dy = 0;
1175
1176	/* get display mode parameters */
1177
1178	HBS = gv->hblank_start;
1179	HSS = gv->hsync_start;
1180	HSE = gv->hsync_stop;
1181	HBE = gv->htotal - 1;
1182	HT  = gv->htotal;
1183	VBS = gv->vblank_start;
1184	VSS = gv->vsync_start;
1185	VSE = gv->vsync_stop;
1186	VBE = gv->vtotal - 1;
1187	VT  = gv->vtotal;
1188
1189	if (TEXT)
1190		HDE = ((gv->disp_width + md->fx - 1) / md->fx) - 1;
1191	else
1192		HDE = (gv->disp_width + 3) / 8 - 1;	/* HBS; */
1193	VDE = gv->disp_height - 1;
1194
1195	/* adjustments (crest) */
1196	switch (gv->depth) {
1197	    case 15:
1198	    case 16:
1199		hmul = 2;
1200		break;
1201	    case 24:
1202		hmul = 3;
1203		break;
1204	    case 32:
1205		hmul = 4;
1206		break;
1207	    default:
1208		hmul = 1;
1209		break;
1210	}
1211
1212	HDE *= hmul;
1213	HBS *= hmul;
1214	HSS *= hmul;
1215	HSE *= hmul;
1216	HBE *= hmul;
1217	HT  *= hmul;
1218
1219	if (gv->disp_flags & GRF_FLAGS_LACE) {
1220		VDE /= 2;
1221		VT = VT + 1;
1222	}
1223
1224	if (gv->disp_flags & GRF_FLAGS_DBLSCAN) {
1225		VDE *= 2;
1226		VBS *= 2;
1227		VSS *= 2;
1228		VSE *= 2;
1229		VBE *= 2;
1230		VT  *= 2;
1231	}
1232
1233	WSeq(ba, SEQ_ID_MEMORY_MODE, (TEXT || (gv->depth == 1)) ? 0x06 : 0x0e);
1234
1235	WGfx(ba, GCT_ID_READ_MAP_SELECT, 0x00);
1236	WSeq(ba, SEQ_ID_MAP_MASK, (gv->depth == 1) ? 0x01 : 0xff);
1237	WSeq(ba, SEQ_ID_CHAR_MAP_SELECT, 0x00);
1238
1239	/* Set clock */
1240	et_CompFQ( gv->pixel_clock * hmul, &num0, &denom0);
1241
1242	/* Horizontal/Vertical Sync Pulse */
1243	hvsync_pulse = 0xe3;
1244	if (gv->disp_flags & GRF_FLAGS_PHSYNC)
1245		hvsync_pulse &= ~0x40;
1246	else
1247		hvsync_pulse |= 0x40;
1248	if (gv->disp_flags & GRF_FLAGS_PVSYNC)
1249		hvsync_pulse &= ~0x80;
1250	else
1251		hvsync_pulse |= 0x80;
1252
1253	vgaw(ba, GREG_MISC_OUTPUT_W, hvsync_pulse | ((num0 & 3) << 2));
1254	WCrt(ba, CRT_ID_6845_COMPAT, (num0 & 4) ? 0x0a : 0x08);
1255	seq = RSeq(ba, SEQ_ID_CLOCKING_MODE);
1256	switch(denom0) {
1257	    case 0:
1258		WSeq(ba, SEQ_ID_AUXILIARY_MODE, 0xb4);
1259		WSeq(ba, SEQ_ID_CLOCKING_MODE, seq & 0xf7);
1260 		break;
1261	    case 1:
1262		WSeq(ba, SEQ_ID_AUXILIARY_MODE, 0xf4);
1263		WSeq(ba, SEQ_ID_CLOCKING_MODE, seq & 0xf7);
1264		break;
1265	    case 2:
1266		WSeq(ba, SEQ_ID_AUXILIARY_MODE, 0xf5);
1267		WSeq(ba, SEQ_ID_CLOCKING_MODE, seq & 0xf7);
1268		break;
1269	    case 3:
1270		WSeq(ba, SEQ_ID_AUXILIARY_MODE, 0xf5);
1271		WSeq(ba, SEQ_ID_CLOCKING_MODE, seq | 0x08);
1272		break;
1273	}
1274
1275	/* load display parameters into board */
1276	WCrt(ba, CRT_ID_HOR_TOTAL, HT);
1277	WCrt(ba, CRT_ID_HOR_DISP_ENA_END, ((HDE >= HBS) ? HBS - 1 : HDE));
1278	WCrt(ba, CRT_ID_START_HOR_BLANK, HBS);
1279	WCrt(ba, CRT_ID_END_HOR_BLANK, (HBE & 0x1f) | 0x80);
1280	WCrt(ba, CRT_ID_START_HOR_RETR, HSS);
1281	WCrt(ba, CRT_ID_END_HOR_RETR,
1282	    (HSE & 0x1f) |
1283	    ((HBE & 0x20) ? 0x80 : 0x00));
1284	WCrt(ba, CRT_ID_VER_TOTAL, VT);
1285	WCrt(ba, CRT_ID_OVERFLOW,
1286	    0x10 |
1287	    ((VT  & 0x100) ? 0x01 : 0x00) |
1288	    ((VDE & 0x100) ? 0x02 : 0x00) |
1289	    ((VSS & 0x100) ? 0x04 : 0x00) |
1290	    ((VBS & 0x100) ? 0x08 : 0x00) |
1291	    ((VT  & 0x200) ? 0x20 : 0x00) |
1292	    ((VDE & 0x200) ? 0x40 : 0x00) |
1293	    ((VSS & 0x200) ? 0x80 : 0x00));
1294
1295	WCrt(ba, CRT_ID_MAX_ROW_ADDRESS,
1296	    0x40 |		/* splitscreen not visible */
1297	    ((gv->disp_flags & GRF_FLAGS_DBLSCAN) ? 0x80 : 0x00) |
1298	    ((VBS & 0x200) ? 0x20 : 0x00) |
1299	    (TEXT ? ((md->fy - 1) & 0x1f) : 0x00));
1300
1301	WCrt(ba, CRT_ID_MODE_CONTROL,
1302	    ((TEXT || (gv->depth == 1)) ? 0xc3 : 0xab));
1303
1304	/* text cursor */
1305	if (TEXT) {
1306#if ET_ULCURSOR
1307		WCrt(ba, CRT_ID_CURSOR_START, (md->fy & 0x1f) - 2);
1308		WCrt(ba, CRT_ID_CURSOR_END, (md->fy & 0x1f) - 1);
1309#else
1310		WCrt(ba, CRT_ID_CURSOR_START, 0x00);
1311		WCrt(ba, CRT_ID_CURSOR_END, md->fy & 0x1f);
1312#endif
1313		WCrt(ba, CRT_ID_CURSOR_LOC_HIGH, 0x00);
1314		WCrt(ba, CRT_ID_CURSOR_LOC_LOW, 0x00);
1315	}
1316
1317	WCrt(ba, CRT_ID_UNDERLINE_LOC, ((md->fy - 1) & 0x1f)
1318		| ((TEXT || (gv->depth == 1)) ? 0x00 : 0x60));
1319
1320	WCrt(ba, CRT_ID_START_ADDR_HIGH, 0x00);
1321	WCrt(ba, CRT_ID_START_ADDR_LOW, 0x00);
1322
1323	WCrt(ba, CRT_ID_START_VER_RETR, VSS);
1324	WCrt(ba, CRT_ID_END_VER_RETR, (VSE & 0x0f) | 0x30);
1325	WCrt(ba, CRT_ID_VER_DISP_ENA_END, VDE);
1326	WCrt(ba, CRT_ID_START_VER_BLANK, VBS);
1327	WCrt(ba, CRT_ID_END_VER_BLANK, VBE);
1328
1329	WCrt(ba, CRT_ID_LINE_COMPARE, 0xff);
1330
1331	WCrt(ba, CRT_ID_OVERFLOW_HIGH,
1332	    ((VBS & 0x400) ? 0x01 : 0x00) |
1333	    ((VT  & 0x400) ? 0x02 : 0x00) |
1334	    ((VDE & 0x400) ? 0x04 : 0x00) |
1335	    ((VSS & 0x400) ? 0x08 : 0x00) |
1336	    0x10 |
1337	    ((gv->disp_flags & GRF_FLAGS_LACE) ? 0x80 : 0x00));
1338
1339	WCrt(ba, CRT_ID_HOR_OVERFLOW,
1340	    ((HT  & 0x100) ? 0x01 : 0x00) |
1341	    ((HBS & 0x100) ? 0x04 : 0x00) |
1342	    ((HSS & 0x100) ? 0x10 : 0x00)
1343	);
1344
1345	/* depth dependent stuff */
1346
1347	WGfx(ba, GCT_ID_GRAPHICS_MODE,
1348	    ((TEXT || (gv->depth == 1)) ? 0x00 : 0x40));
1349	WGfx(ba, GCT_ID_MISC, (TEXT ? 0x04 : 0x01));
1350
1351	vgaw(ba, VDAC_MASK, 0xff);
1352	vgar(ba, VDAC_MASK);
1353	vgar(ba, VDAC_MASK);
1354	vgar(ba, VDAC_MASK);
1355	vgar(ba, VDAC_MASK);
1356	switch (gv->depth) {
1357	    case 1:
1358	    case 4:	/* text */
1359		switch(etdtype) {
1360		    case SIERRA11483:
1361		    case SIERRA15025:
1362		    case MUSICDAC:
1363			vgaw(ba, VDAC_MASK, 0);
1364			break;
1365		    case ATT20C491:
1366			vgaw(ba, VDAC_MASK, 0x02);
1367			break;
1368		    case MERLINDAC:
1369			setMerlinDACmode(ba, 0);
1370			break;
1371		}
1372		HDE = gv->disp_width / 16;
1373		break;
1374	    case 8:
1375		switch(etdtype) {
1376		    case SIERRA11483:
1377		    case SIERRA15025:
1378		    case MUSICDAC:
1379			vgaw(ba, VDAC_MASK, 0);
1380			break;
1381		    case ATT20C491:
1382			vgaw(ba, VDAC_MASK, 0x02);
1383			break;
1384		    case MERLINDAC:
1385			setMerlinDACmode(ba, 0);
1386			break;
1387		}
1388		HDE = gv->disp_width / 8;
1389		break;
1390	    case 15:
1391		switch(etdtype) {
1392		    case SIERRA11483:
1393		    case SIERRA15025:
1394		    case MUSICDAC:
1395		    case ATT20C491:
1396			vgaw(ba, VDAC_MASK, 0xa0);
1397			break;
1398		    case MERLINDAC:
1399			setMerlinDACmode(ba, 0xa0);
1400			break;
1401		}
1402		HDE = gv->disp_width / 4;
1403		break;
1404	    case 16:
1405		switch(etdtype) {
1406		    case SIERRA11483:
1407			vgaw(ba, VDAC_MASK, 0);	/* illegal mode! */
1408			break;
1409		    case SIERRA15025:
1410			vgaw(ba, VDAC_MASK, 0xe0);
1411			break;
1412		    case MUSICDAC:
1413		    case ATT20C491:
1414			vgaw(ba, VDAC_MASK, 0xc0);
1415			break;
1416		    case MERLINDAC:
1417			setMerlinDACmode(ba, 0xe0);
1418			break;
1419		}
1420		HDE = gv->disp_width / 4;
1421		break;
1422	    case 24:
1423		switch(etdtype) {
1424		    case SIERRA11483:
1425			vgaw(ba, VDAC_MASK, 0);	/* illegal mode! */
1426			break;
1427		    case SIERRA15025:
1428			vgaw(ba, VDAC_MASK, 0xe1);
1429			break;
1430		    case MUSICDAC:
1431		    case ATT20C491:
1432			vgaw(ba, VDAC_MASK, 0xe0);
1433			break;
1434		    case MERLINDAC:
1435			setMerlinDACmode(ba, 0xf0);
1436			break;
1437		}
1438		HDE = (gv->disp_width / 8) * 3;
1439		break;
1440	    case 32:
1441		switch(etdtype) {
1442		    case SIERRA11483:
1443		    case MUSICDAC:
1444		    case ATT20C491:
1445			vgaw(ba, VDAC_MASK, 0);	/* illegal mode! */
1446			break;
1447		    case SIERRA15025:
1448			vgaw(ba, VDAC_MASK, 0x61);
1449			break;
1450		    case MERLINDAC:
1451			setMerlinDACmode(ba, 0xb0);
1452			break;
1453		}
1454		HDE = gv->disp_width / 2;
1455		break;
1456	}
1457	WAttr(ba, ACT_ID_ATTR_MODE_CNTL, (TEXT ? 0x0a : 0x01));
1458	WAttr(ba, 0x20 | ACT_ID_COLOR_PLANE_ENA,
1459	    (gv->depth == 1) ? 0x01 : 0x0f);
1460
1461	WCrt(ba, CRT_ID_OFFSET, HDE);
1462	vgaw(ba, CRT_ADDRESS, CRT_ID_HOR_OVERFLOW);
1463	vgaw(ba, CRT_ADDRESS_W,
1464		(vgar(ba, CRT_ADDRESS_R) & 0x7f)
1465                | ((HDE & 0x100) ? 0x80: 0x00));
1466
1467	/* text initialization */
1468	if (TEXT) {
1469		et_inittextmode(gp);
1470	}
1471
1472	WSeq(ba, SEQ_ID_CLOCKING_MODE, 0x01);
1473
1474	/* Pass-through */
1475	RegOffpass(ba);
1476
1477	return (1);
1478}
1479
1480
1481void
1482et_inittextmode(struct grf_softc *gp)
1483{
1484	struct grfettext_mode *tm = (struct grfettext_mode *) gp->g_data;
1485	volatile unsigned char *ba = gp->g_regkva;
1486	volatile unsigned char *fb = gp->g_fbkva;
1487	volatile unsigned char *c;
1488	unsigned char *f, y;
1489	unsigned short z;
1490
1491
1492	/*
1493	 * load text font into beginning of display memory. Each character
1494	 * cell is 32 bytes long (enough for 4 planes)
1495	 */
1496
1497	SetTextPlane(ba, 0x02);
1498        et_memset(fb, 0, 256 * 32);
1499	c = fb + (32 * tm->fdstart);
1500	f = tm->fdata;
1501	for (z = tm->fdstart; z <= tm->fdend; z++, c += (32 - tm->fy))
1502		for (y = 0; y < tm->fy; y++)
1503			*c++ = *f++;
1504
1505	/* clear out text/attr planes (three screens worth) */
1506
1507	SetTextPlane(ba, 0x01);
1508	et_memset(fb, 0x07, tm->cols * tm->rows * 3);
1509	SetTextPlane(ba, 0x00);
1510	et_memset(fb, 0x20, tm->cols * tm->rows * 3);
1511
1512	/* print out a little init msg */
1513
1514	c = fb + (tm->cols - 16);
1515	strcpy(__UNVOLATILE(c), "TSENG");
1516	c[5] = 0x20;
1517
1518	/* set colors (B&W) */
1519
1520	switch(ettype) {
1521	    case MERLIN:
1522		vgaw(ba, MERLIN_VDAC_INDEX, 0);
1523		for (z = 0; z < 256; z++) {
1524			y = (z & 1) ? ((z > 7) ? 2 : 1) : 0;
1525
1526			vgaw(ba, MERLIN_VDAC_COLORS, etconscolors[y][0]);
1527			vgaw(ba, MERLIN_VDAC_COLORS, etconscolors[y][1]);
1528			vgaw(ba, MERLIN_VDAC_COLORS, etconscolors[y][2]);
1529		}
1530		break;
1531	    default:
1532		vgaw(ba, VDAC_ADDRESS_W, 0);
1533		for (z = 0; z < 256; z++) {
1534			y = (z & 1) ? ((z > 7) ? 2 : 1) : 0;
1535
1536			vgaw(ba, VDAC_DATA + ((ettype == DOMINO) ? 0x0fff : 0),
1537			    etconscolors[y][0] >> etcmap_shift);
1538			vgaw(ba, VDAC_DATA + ((ettype == DOMINO) ? 0x0fff : 0),
1539			    etconscolors[y][1] >> etcmap_shift);
1540			vgaw(ba, VDAC_DATA + ((ettype == DOMINO) ? 0x0fff : 0),
1541			    etconscolors[y][2] >> etcmap_shift);
1542		}
1543		break;
1544	}
1545}
1546
1547
1548void
1549et_memset(volatile unsigned char *d, unsigned char c, int l)
1550{
1551	for (; l > 0; l--)
1552		*d++ = c;
1553}
1554
1555
1556static int
1557et_getControllerType(struct grf_softc *gp)
1558{
1559	volatile unsigned char *ba = gp->g_regkva; /* register base */
1560	volatile unsigned char *mem = gp->g_fbkva; /* memory base */
1561	volatile unsigned char *mmu = mem + MMU_APERTURE0; /* MMU aperture 0 base */
1562
1563	*mem = 0;
1564
1565	/* make ACL visible */
1566	if (ettype == MERLIN) {
1567		WCrt(ba, CRT_ID_VIDEO_CONFIG1, 0xbb);
1568	} else {
1569		WCrt(ba, CRT_ID_VIDEO_CONFIG1, 0xfb);
1570	}
1571
1572	WIma(ba, IMA_PORTCONTROL, 0x01);
1573
1574	*((volatile unsigned long *)mmu) = 0;
1575	*(mem + 0x13) = 0x38;
1576
1577	*mmu = 0xff;
1578
1579	/* hide ACL */
1580	WIma(ba, IMA_PORTCONTROL, 0x00);
1581
1582	if (ettype == MERLIN) {
1583		WCrt(ba, CRT_ID_VIDEO_CONFIG1, 0x93);
1584	} else {
1585		WCrt(ba, CRT_ID_VIDEO_CONFIG1, 0xd3);
1586	}
1587	return ((*mem == 0xff) ? ETW32 : ET4000);
1588}
1589
1590/* We MUST do 4 HW reads to switch into command mode */
1591static inline int vgar4HDR(volatile unsigned char *ba)
1592{
1593	return vgar(ba, HDR) + vgar(ba, HDR) + vgar(ba, HDR) + vgar(ba, HDR);
1594}
1595
1596static int
1597et_getDACType(struct grf_softc *gp)
1598{
1599	volatile unsigned char *ba = gp->g_regkva;
1600	union {
1601		int  tt;
1602		char cc[4];
1603	} check;
1604
1605	/* check for Sierra SC 15025 */
1606
1607	vgar4HDR(ba);
1608	vgaw(ba, VDAC_COMMAND, 0x10); /* set ERPF */
1609
1610	vgaw(ba, VDAC_XINDEX, 9);
1611	check.cc[0] = vgar(ba, VDAC_XDATA);
1612	vgaw(ba, VDAC_XINDEX, 10);
1613	check.cc[1] = vgar(ba, VDAC_XDATA);
1614	vgaw(ba, VDAC_XINDEX, 11);
1615	check.cc[2] = vgar(ba, VDAC_XDATA);
1616	vgaw(ba, VDAC_XINDEX, 12);
1617	check.cc[3] = vgar(ba, VDAC_XDATA);
1618
1619	vgar4HDR(ba);
1620	vgaw(ba, VDAC_COMMAND, 0x00); /* clear ERPF */
1621
1622	if (check.tt == 0x533ab141) {
1623		vgar4HDR(ba);
1624		vgaw(ba, VDAC_COMMAND, 0x10); /* set ERPF */
1625
1626		/* switch to 8 bits per color */
1627		vgaw(ba, VDAC_XINDEX, 8);
1628		vgaw(ba, VDAC_XDATA, 1);
1629		/* do not shift color values */
1630		etcmap_shift = 0;
1631
1632		vgar4HDR(ba);
1633		vgaw(ba, VDAC_COMMAND, 0x00); /* clear ERPF */
1634
1635		vgaw(ba, VDAC_MASK, 0xff);
1636		return (SIERRA15025);
1637	}
1638
1639	/* check for MUSIC DAC */
1640
1641	vgar4HDR(ba);
1642	vgaw(ba, VDAC_COMMAND, 0x02);	/* set some strange MUSIC mode (???) */
1643
1644	vgaw(ba, VDAC_XINDEX, 0x01);
1645	if (vgar(ba, VDAC_XDATA) == 0x01) {
1646		/* shift color values by 2 */
1647		etcmap_shift = 2;
1648
1649		vgaw(ba, VDAC_MASK, 0xff);
1650		return (MUSICDAC);
1651	}
1652
1653	/* check for AT&T ATT20c491 DAC (crest) */
1654	vgar4HDR(ba);
1655	vgaw(ba, HDR, 0xff);
1656	vgaw(ba, VDAC_MASK, 0x01);
1657	vgar4HDR(ba);
1658	if (vgar(ba, HDR) == 0xff) {
1659		/* do not shift color values */
1660		etcmap_shift = 0;
1661
1662		vgaw(ba, VDAC_MASK, 0xff);
1663		return (ATT20C491);
1664	}
1665
1666	/* restore PowerUp settings (crest) */
1667	vgar4HDR(ba);
1668	vgaw(ba, HDR, 0x00);
1669
1670	/*
1671	 * nothing else found, so let us pretend it is a stupid
1672	 * Sierra SC 11483
1673	 */
1674
1675	/* shift color values by 2 */
1676	etcmap_shift = 2;
1677
1678	vgaw(ba, VDAC_MASK, 0xff);
1679	return (SIERRA11483);
1680}
1681
1682
1683#if NWSDISPLAY > 0
1684static void
1685et_wscursor(void *c, int on, int row, int col)
1686{
1687	struct rasops_info *ri;
1688	struct vcons_screen *scr;
1689	struct grf_softc *gp;
1690	volatile void *ba;
1691	int offs;
1692
1693	ri = c;
1694	scr = ri->ri_hw;
1695	gp = scr->scr_cookie;
1696	ba = gp->g_regkva;
1697
1698	if ((ri->ri_flg & RI_CURSOR) && !on) {
1699		/* cursor was visible, but we want to remove it */
1700		/*WCrt(ba, CRT_ID_CURSOR_START, | 0x20);*/
1701		ri->ri_flg &= ~RI_CURSOR;
1702	}
1703
1704	ri->ri_crow = row;
1705	ri->ri_ccol = col;
1706
1707	if (on) {
1708		/* move cursor to new location */
1709		if (!(ri->ri_flg & RI_CURSOR)) {
1710			/*WCrt(ba, CRT_ID_CURSOR_START, | 0x20);*/
1711			ri->ri_flg |= RI_CURSOR;
1712		}
1713		offs = gp->g_rowoffset[row] + col;
1714		WCrt(ba, CRT_ID_CURSOR_LOC_LOW, offs & 0xff);
1715		WCrt(ba, CRT_ID_CURSOR_LOC_HIGH, (offs >> 8) & 0xff);
1716		WCrt(ba, CRT_ID_EXT_START, (offs >> (16-2)) & 0x0c);
1717	}
1718}
1719
1720static void
1721et_wsputchar(void *c, int row, int col, u_int ch, long attr)
1722{
1723	struct rasops_info *ri;
1724	struct vcons_screen *scr;
1725	struct grf_softc *gp;
1726	volatile unsigned char *ba, *cp;
1727
1728	ri = c;
1729	scr = ri->ri_hw;
1730	gp = scr->scr_cookie;
1731	ba = gp->g_regkva;
1732	cp = gp->g_fbkva;
1733
1734	cp += gp->g_rowoffset[row] + col;
1735	SetTextPlane(ba, 0x00);
1736	*cp = ch;
1737	SetTextPlane(ba, 0x01);
1738	*cp = attr;
1739}
1740
1741static void
1742et_wscopycols(void *c, int row, int srccol, int dstcol, int ncols)
1743{
1744	volatile unsigned char *ba, *dst, *src;
1745	struct rasops_info *ri;
1746	struct vcons_screen *scr;
1747	struct grf_softc *gp;
1748	int i;
1749
1750	KASSERT(ncols > 0);
1751	ri = c;
1752	scr = ri->ri_hw;
1753	gp = scr->scr_cookie;
1754	ba = gp->g_regkva;
1755	src = gp->g_fbkva;
1756
1757	src += gp->g_rowoffset[row];
1758	dst = src;
1759	src += srccol;
1760	dst += dstcol;
1761	if (srccol < dstcol) {
1762		/* need to copy backwards */
1763		src += ncols;
1764		dst += ncols;
1765		SetTextPlane(ba, 0x00);
1766		for (i = 0; i < ncols; i++)
1767			*(--dst) = *(--src);
1768		src += ncols;
1769		dst += ncols;
1770		SetTextPlane(ba, 0x01);
1771		for (i = 0; i < ncols; i++)
1772			*(--dst) = *(--src);
1773	} else {
1774		SetTextPlane(ba, 0x00);
1775		for (i = 0; i < ncols; i++)
1776			*dst++ = *src++;
1777		src -= ncols;
1778		dst -= ncols;
1779		SetTextPlane(ba, 0x01);
1780		for (i = 0; i < ncols; i++)
1781			*dst++ = *src++;
1782	}
1783}
1784
1785static void
1786et_wserasecols(void *c, int row, int startcol, int ncols, long fillattr)
1787{
1788	volatile unsigned char *ba, *cp;
1789	struct rasops_info *ri;
1790	struct vcons_screen *scr;
1791	struct grf_softc *gp;
1792	int i;
1793
1794	ri = c;
1795	scr = ri->ri_hw;
1796	gp = scr->scr_cookie;
1797	ba = gp->g_regkva;
1798	cp = gp->g_fbkva;
1799
1800	cp += gp->g_rowoffset[row] + startcol;
1801	SetTextPlane(ba, 0x00);
1802	for (i = 0; i < ncols; i++)
1803		*cp++ = 0x20;
1804	cp -= ncols;
1805	SetTextPlane(ba, 0x01);
1806	for (i = 0; i < ncols; i++)
1807		*cp++ = 0x07;
1808}
1809
1810static void
1811et_wscopyrows(void *c, int srcrow, int dstrow, int nrows)
1812{
1813	volatile unsigned char *ba, *dst, *src;
1814	struct rasops_info *ri;
1815	struct vcons_screen *scr;
1816	struct grf_softc *gp;
1817	int i, n;
1818
1819	KASSERT(nrows > 0);
1820	ri = c;
1821	scr = ri->ri_hw;
1822	gp = scr->scr_cookie;
1823	ba = gp->g_regkva;
1824	src = dst = gp->g_fbkva;
1825	n = ri->ri_cols * nrows;
1826
1827	if (srcrow < dstrow) {
1828		/* need to copy backwards */
1829		src += gp->g_rowoffset[srcrow + nrows];
1830		dst += gp->g_rowoffset[dstrow + nrows];
1831		SetTextPlane(ba, 0x00);
1832		for (i = 0; i < n; i++)
1833			*(--dst) = *(--src);
1834		src += n;
1835		dst += n;
1836		SetTextPlane(ba, 0x01);
1837		for (i = 0; i < n; i++)
1838			*(--dst) = *(--src);
1839	} else {
1840		src += gp->g_rowoffset[srcrow];
1841		dst += gp->g_rowoffset[dstrow];
1842		SetTextPlane(ba, 0x00);
1843		for (i = 0; i < n; i++)
1844			*dst++ = *src++;
1845		src -= n;
1846		dst -= n;
1847		SetTextPlane(ba, 0x01);
1848		for (i = 0; i < n; i++)
1849			*dst++ = *src++;
1850	}
1851}
1852
1853static void
1854et_wseraserows(void *c, int row, int nrows, long fillattr)
1855{
1856	volatile unsigned char *ba, *cp;
1857	struct rasops_info *ri;
1858	struct vcons_screen *scr;
1859	struct grf_softc *gp;
1860	int i, n;
1861
1862	ri = c;
1863	scr = ri->ri_hw;
1864	gp = scr->scr_cookie;
1865	ba = gp->g_regkva;
1866	cp = gp->g_fbkva;
1867
1868	cp += gp->g_rowoffset[row];
1869	n = ri->ri_cols * nrows;
1870	SetTextPlane(ba, 0x00);
1871	for (i = 0; i < n; i++)
1872		*cp++ = 0x20;
1873	cp -= n;
1874	SetTextPlane(ba, 0x01);
1875	for (i = 0; i < n; i++)
1876		*cp++ = 0x07;
1877}
1878
1879static int
1880et_wsallocattr(void *c, int fg, int bg, int flg, long *attr)
1881{
1882
1883	/* XXX color support? */
1884	*attr = (flg & WSATTR_REVERSE) ? 0x70 : 0x07;
1885	if (flg & WSATTR_UNDERLINE)	*attr = 0x01;
1886	if (flg & WSATTR_HILIT)		*attr |= 0x08;
1887	if (flg & WSATTR_BLINK)		*attr |= 0x80;
1888	return 0;
1889}
1890
1891/* our font does not support unicode extensions */
1892static int
1893et_wsmapchar(void *c, int ch, unsigned int *cp)
1894{
1895
1896	if (ch > 0 && ch < 256) {
1897		*cp = ch;
1898		return 5;
1899	}
1900	*cp = ' ';
1901	return 0;
1902}
1903
1904static int
1905et_wsioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
1906{
1907	struct vcons_data *vd;
1908	struct grf_softc *gp;
1909
1910	vd = v;
1911	gp = vd->cookie;
1912
1913	switch (cmd) {
1914	case WSDISPLAYIO_GETCMAP:
1915		/* Note: wsdisplay_cmap and grf_colormap have same format */
1916		if (gp->g_display.gd_planes == 8)
1917			return et_getcmap(gp, (struct grf_colormap *)data);
1918		return EINVAL;
1919
1920	case WSDISPLAYIO_PUTCMAP:
1921		/* Note: wsdisplay_cmap and grf_colormap have same format */
1922		if (gp->g_display.gd_planes == 8)
1923			return et_putcmap(gp, (struct grf_colormap *)data);
1924		return EINVAL;
1925
1926	case WSDISPLAYIO_GVIDEO:
1927		if (et_isblank(gp))
1928			*(u_int *)data = WSDISPLAYIO_VIDEO_OFF;
1929		else
1930			*(u_int *)data = WSDISPLAYIO_VIDEO_ON;
1931		return 0;
1932
1933	case WSDISPLAYIO_SVIDEO:
1934		return et_blank(gp, *(u_int *)data == WSDISPLAYIO_VIDEO_ON);
1935
1936	case WSDISPLAYIO_SMODE:
1937		if ((*(int *)data) != gp->g_wsmode) {
1938			if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
1939				/* load console text mode, redraw screen */
1940				(void)et_load_mon(gp, &etconsole_mode);
1941				if (vd->active != NULL)
1942					vcons_redraw_screen(vd->active);
1943			} else {
1944				/* switch to current graphics mode */
1945				if (!et_load_mon(gp,
1946				    (struct grfettext_mode *)monitor_current))
1947					return EINVAL;
1948			}
1949			gp->g_wsmode = *(int *)data;
1950		}
1951		return 0;
1952
1953	case WSDISPLAYIO_GET_FBINFO:
1954		return et_get_fbinfo(gp, data);
1955	}
1956
1957	/* handle this command hw-independent in grf(4) */
1958	return grf_wsioctl(v, vs, cmd, data, flag, l);
1959}
1960
1961/*
1962 * Fill the wsdisplayio_fbinfo structure with information from the current
1963 * graphics mode. Even when text mode is active.
1964 */
1965static int
1966et_get_fbinfo(struct grf_softc *gp, struct wsdisplayio_fbinfo *fbi)
1967{
1968	struct grfvideo_mode *md;
1969	uint32_t rbits, gbits, bbits;
1970
1971	md = monitor_current;
1972
1973	switch (md->depth) {
1974	case 8:
1975		fbi->fbi_bitsperpixel = 8;
1976		rbits = gbits = bbits = 6;  /* keep gcc happy */
1977		break;
1978	case 15:
1979		fbi->fbi_bitsperpixel = 16;
1980		rbits = gbits = bbits = 5;
1981		break;
1982	case 16:
1983		fbi->fbi_bitsperpixel = 16;
1984		rbits = bbits = 5;
1985		gbits = 6;
1986		break;
1987	case 24:
1988		fbi->fbi_bitsperpixel = 24;
1989		rbits = gbits = bbits = 8;
1990		break;
1991	default:
1992		return EINVAL;
1993	}
1994
1995	fbi->fbi_stride = (fbi->fbi_bitsperpixel / 8) * md->disp_width;
1996	fbi->fbi_width = md->disp_width;
1997	fbi->fbi_height = md->disp_height;
1998
1999	if (md->depth > 8) {
2000		fbi->fbi_pixeltype = WSFB_RGB;
2001		fbi->fbi_subtype.fbi_rgbmasks.red_offset = bbits + gbits;
2002		fbi->fbi_subtype.fbi_rgbmasks.red_size = rbits;
2003		fbi->fbi_subtype.fbi_rgbmasks.green_offset = bbits;
2004		fbi->fbi_subtype.fbi_rgbmasks.green_size = gbits;
2005		fbi->fbi_subtype.fbi_rgbmasks.blue_offset = 0;
2006		fbi->fbi_subtype.fbi_rgbmasks.blue_size = bbits;
2007		fbi->fbi_subtype.fbi_rgbmasks.alpha_offset = 0;
2008		fbi->fbi_subtype.fbi_rgbmasks.alpha_size = 0;
2009	} else {
2010		fbi->fbi_pixeltype = WSFB_CI;
2011		fbi->fbi_subtype.fbi_cmapinfo.cmap_entries = 1 << md->depth;
2012	}
2013
2014	fbi->fbi_flags = 0;
2015	fbi->fbi_fbsize = fbi->fbi_stride * fbi->fbi_height;
2016	fbi->fbi_fboffset = 0;
2017	return 0;
2018}
2019#endif	/* NWSDISPLAY > 0 */
2020
2021#endif /* NGRFET */
2022