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