xref: /netbsd-src/sys/arch/amiga/dev/grf_et.c (revision 93f9db1b75d415b78f73ed629beeb86235153473)
1 /*	$NetBSD: grf_et.c,v 1.11 1998/01/12 10:39:36 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 "grfet.h"
38 #if NGRFET > 0
39 
40 /*
41  * Graphics routines for Tseng ET4000 (&W32) boards,
42  *
43  * This code offers low-level routines to access Tseng ET4000
44  * graphics-boards from within NetBSD for the Amiga.
45  * No warranties for any kind of function at all - this
46  * code may crash your hardware and scratch your harddisk.  Use at your
47  * own risk.  Freely distributable.
48  *
49  * Modified for Tseng ET4000 from
50  * Kari Mettinen's Cirrus driver by Tobias Abt
51  *
52  * Fixed Merlin in Z-III, fixed LACE and DBLSCAN, added Domino16M proto
53  * and AT&T ATT20c491 DAC, added memory-size detection by Klaus Burkert.
54  *
55  *
56  * TODO:
57  *
58  */
59 
60 #include <sys/param.h>
61 #include <sys/systm.h>
62 #include <sys/errno.h>
63 #include <sys/ioctl.h>
64 #include <sys/device.h>
65 #include <sys/malloc.h>
66 
67 #include <machine/cpu.h>
68 #include <dev/cons.h>
69 #ifdef TSENGCONSOLE
70 #include <amiga/dev/itevar.h>
71 #endif
72 #include <amiga/amiga/device.h>
73 #include <amiga/dev/grfioctl.h>
74 #include <amiga/dev/grfvar.h>
75 #include <amiga/dev/grf_etreg.h>
76 #include <amiga/dev/zbusvar.h>
77 
78 int	et_mondefok __P((struct grfvideo_mode *gv));
79 void	et_boardinit __P((struct grf_softc *gp));
80 static void et_CompFQ __P((u_int fq, u_char *num, u_char *denom));
81 int	et_getvmode __P((struct grf_softc *gp, struct grfvideo_mode *vm));
82 int	et_setvmode __P((struct grf_softc *gp, unsigned int mode));
83 int	et_toggle __P((struct grf_softc *gp, unsigned short));
84 int	et_getcmap __P((struct grf_softc *gfp, struct grf_colormap *cmap));
85 int	et_putcmap __P((struct grf_softc *gfp, struct grf_colormap *cmap));
86 #ifndef TSENGCONSOLE
87 void	et_off __P((struct grf_softc *gp));
88 #endif
89 void	et_inittextmode __P((struct grf_softc *gp));
90 int	et_ioctl __P((register struct grf_softc *gp, u_long cmd, void *data));
91 int	et_getmousepos __P((struct grf_softc *gp, struct grf_position *data));
92 void	et_writesprpos __P((volatile char *ba, short x, short y));
93 int	et_setmousepos __P((struct grf_softc *gp, struct grf_position *data));
94 static int et_setspriteinfo __P((struct grf_softc *gp,
95 				struct grf_spriteinfo *data));
96 int	et_getspriteinfo __P((struct grf_softc *gp,
97 				struct grf_spriteinfo *data));
98 static int et_getspritemax __P((struct grf_softc *gp,
99 				struct grf_position *data));
100 int	et_setmonitor __P((struct grf_softc *gp, struct grfvideo_mode *gv));
101 int	et_blank __P((struct grf_softc *gp, int *on));
102 static int et_getControllerType __P((struct grf_softc *gp));
103 static int et_getDACType __P((struct grf_softc *gp));
104 
105 int	grfetmatch __P((struct device *, struct cfdata *, void *));
106 void	grfetattach __P((struct device *, struct device *, void *));
107 int	grfetprint __P((void *, const char *));
108 void	et_memset __P((unsigned char *d, unsigned char c, int l));
109 
110 /*
111  * Graphics display definitions.
112  * These are filled by 'grfconfig' using GRFIOCSETMON.
113  */
114 #define monitor_def_max 24
115 static struct grfvideo_mode monitor_def[24] = {
116 	{0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
117 	{0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
118 	{0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}
119 };
120 static struct grfvideo_mode *monitor_current = &monitor_def[0];
121 
122 /* Console display definition.
123  *   Default hardcoded text mode.  This grf_et is set up to
124  *   use one text mode only, and this is it.  You may use
125  *   grfconfig to change the mode after boot.
126  */
127 /* Console font */
128 #ifdef KFONT_8X11
129 #define TSENGFONT kernel_font_8x11
130 #define TSENGFONTY 11
131 #else
132 #define TSENGFONT kernel_font_8x8
133 #define TSENGFONTY 8
134 #endif
135 extern unsigned char TSENGFONT[];
136 
137 struct grfettext_mode etconsole_mode = {
138 	{255, "", 25000000, 640, 480, 4, 640/8, 680/8, 768/8, 800/8,
139 	 481, 491, 493, 525, 0},
140 	8, TSENGFONTY, 640 / 8, 480 / TSENGFONTY, TSENGFONT, 32, 255
141 };
142 
143 /* Console colors */
144 unsigned char etconscolors[3][3] = {	/* background, foreground, hilite */
145 	{0, 0x40, 0x50}, {152, 152, 152}, {255, 255, 255}
146 };
147 
148 int ettype = 0;		/* oMniBus, Domino or Merlin */
149 int etctype = 0;	/* ET4000 or ETW32 */
150 int etdtype = 0;	/* Type of DAC (see grf_etregs.h) */
151 
152 char etcmap_shift = 0;	/* 6 or 8 bit cmap entries */
153 unsigned char pass_toggle;	/* passthru status tracker */
154 
155 unsigned char Merlin_switch = 0;
156 
157 /*
158  * Because all Tseng-boards have 2 configdev entries, one for
159  * framebuffer mem and the other for regs, we have to hold onto
160  * the pointers globally until we match on both.  This and 'ettype'
161  * are the primary obsticles to multiple board support, but if you
162  * have multiple boards you have bigger problems than grf_et.
163  */
164 static void *et_fbaddr = 0;	/* framebuffer */
165 static void *et_regaddr = 0;	/* registers */
166 static int et_fbsize;		/* framebuffer size */
167 
168 /* current sprite info, if you add support for multiple boards
169  * make this an array or something
170  */
171 struct grf_spriteinfo et_cursprite;
172 
173 /* sprite bitmaps in kernel stack, you'll need to arrayize these too if
174  * you add multiple board support
175  */
176 static unsigned char et_imageptr[8 * 64], et_maskptr[8 * 64];
177 static unsigned char et_sprred[2], et_sprgreen[2], et_sprblue[2];
178 
179 /* standard driver stuff */
180 struct cfattach grfet_ca = {
181 	sizeof(struct grf_softc), grfetmatch, grfetattach
182 };
183 
184 static struct cfdata *cfdata;
185 
186 int
187 grfetmatch(pdp, cfp, auxp)
188 	struct device *pdp;
189 	struct cfdata *cfp;
190 	void *auxp;
191 {
192 	struct zbus_args *zap;
193 	static int regprod, regprod2 = 0, fbprod;
194 
195 	zap = auxp;
196 
197 #ifndef TSENGCONSOLE
198 	if (amiga_realconfig == 0)
199 		return (0);
200 #endif
201 
202 	/* Grab the first board we encounter as the preferred one.  This will
203 	 * allow one board to work in a multiple Tseng board system, but not
204 	 * multiple boards at the same time.  */
205 	if (ettype == 0) {
206 		switch (zap->manid) {
207 		    case OMNIBUS:
208 			if (zap->prodid != 0)
209 				return (0);
210 			regprod = 0;
211 			fbprod = 0;
212 			break;
213 		    case DOMINO:
214 			/* 2167/3 is Domino16M proto (crest) */
215 			if (zap->prodid != 3 && zap->prodid != 2 && zap->prodid != 1)
216 				return (0);
217 			regprod = 2;
218 			regprod2 = 3;
219 			fbprod = 1;
220 			break;
221 		    case MERLIN:
222 			if (zap->prodid != 3 && zap->prodid != 4)
223 				return (0);
224 			regprod = 4;
225 			fbprod = 3;
226 			break;
227 		    default:
228 			return (0);
229 		}
230 		ettype = zap->manid;
231 	} else {
232 		if (ettype != zap->manid) {
233 			return (0);
234 		}
235 	}
236 
237 	/* Configure either registers or framebuffer in any order */
238 	/* as said before, oMniBus does not support ProdID */
239 	if (ettype == OMNIBUS) {
240 		if (zap->size == 64 * 1024) {
241 			/* register area */
242 			et_regaddr = zap->va;
243 		} else {
244 			/* memory area */
245 			et_fbaddr = zap->va;
246 			et_fbsize = zap->size;
247 		}
248 	} else {
249 		if (zap->prodid == regprod || zap->prodid == regprod2) {
250 			et_regaddr = zap->va;
251 		} else {
252 			if (zap->prodid == fbprod) {
253 				et_fbaddr = zap->va;
254 				et_fbsize = zap->size;
255 			} else {
256 				return (0);
257 			}
258 		}
259 	}
260 
261 #ifdef TSENGCONSOLE
262 	if (amiga_realconfig == 0) {
263 		cfdata = cfp;
264 	}
265 #endif
266 
267 	return (1);
268 }
269 
270 
271 void
272 grfetattach(pdp, dp, auxp)
273 	struct device *pdp, *dp;
274 	void   *auxp;
275 {
276 	static struct grf_softc congrf;
277 	struct zbus_args *zap;
278 	struct grf_softc *gp;
279 	static char attachflag = 0;
280 
281 	zap = auxp;
282 
283 	printf("\n");
284 
285 	/* make sure both halves have matched */
286 	if (!et_regaddr || !et_fbaddr)
287 		return;
288 
289 	/* do all that messy console/grf stuff */
290 	if (dp == NULL)
291 		gp = &congrf;
292 	else
293 		gp = (struct grf_softc *) dp;
294 
295 	if (dp != NULL && congrf.g_regkva != 0) {
296 		/*
297 		 * inited earlier, just copy (not device struct)
298 		 */
299 		bcopy(&congrf.g_display, &gp->g_display,
300 		    (char *) &gp[1] - (char *) &gp->g_display);
301 	} else {
302 		gp->g_regkva = (volatile caddr_t) et_regaddr;
303 		gp->g_fbkva = (volatile caddr_t) et_fbaddr;
304 
305 		gp->g_unit = GRF_ET4000_UNIT;
306 		gp->g_mode = et_mode;
307 		gp->g_conpri = grfet_cnprobe();
308 		gp->g_flags = GF_ALIVE;
309 
310 		/* wakeup the board */
311 		et_boardinit(gp);
312 
313 #ifdef TSENGCONSOLE
314 		grfet_iteinit(gp);
315 		(void) et_load_mon(gp, &etconsole_mode);
316 #endif
317 	}
318 
319 	/*
320 	 * attach grf (once)
321 	 */
322 	if (amiga_config_found(cfdata, &gp->g_device, gp, grfetprint)) {
323 		attachflag = 1;
324 		printf("grfet: %dMB ", et_fbsize / 0x100000);
325 		switch (ettype) {
326 		    case OMNIBUS:
327 			printf("oMniBus");
328 			break;
329 		    case DOMINO:
330 			printf("Domino");
331 			break;
332 		    case MERLIN:
333 			printf("Merlin");
334 			break;
335 		}
336 		printf(" with ");
337 		switch (etctype) {
338 		    case ET4000:
339 			printf("Tseng ET4000");
340 			break;
341 		    case ETW32:
342 			printf("Tseng ETW32");
343 			break;
344 		}
345 		printf(" and ");
346 		switch (etdtype) {
347 		    case SIERRA11483:
348 			printf("Sierra SC11483 DAC");
349 			break;
350 		    case SIERRA15025:
351 			printf("Sierra SC15025 DAC");
352 			break;
353 		    case MUSICDAC:
354 			printf("MUSIC DAC");
355 			break;
356 		    case MERLINDAC:
357 			printf("BrookTree Bt482 DAC");
358 			break;
359 		    case ATT20C491:
360 			printf("AT&T ATT20c491 DAC");
361 			break;
362 		}
363 		printf(" being used\n");
364 	} else {
365 		if (!attachflag)
366 			printf("grfet unattached!!\n");
367 	}
368 }
369 
370 
371 int
372 grfetprint(auxp, pnp)
373 	void *auxp;
374 	const char *pnp;
375 {
376 	if (pnp)
377 		printf("ite at %s: ", pnp);
378 	return (UNCONF);
379 }
380 
381 
382 void
383 et_boardinit(gp)
384 	struct grf_softc *gp;
385 {
386 	unsigned char *ba = gp->g_regkva;
387 	int     x;
388 
389 	/* wakeup board and flip passthru OFF */
390 
391 	RegWakeup(ba);
392 	RegOnpass(ba);
393 
394 	if (ettype == MERLIN) {
395 		/* Merlin needs some special initialisations */
396 		vgaw(ba, MERLIN_SWITCH_REG, 0);
397 		delay(20000);
398 		vgaw(ba, MERLIN_SWITCH_REG, 8);
399 		delay(20000);
400 		vgaw(ba, MERLIN_SWITCH_REG, 0);
401 		delay(20000);
402 		vgaw(ba, MERLIN_VDAC_DATA, 1);
403 
404 		vgaw(ba, MERLIN_VDAC_INDEX, 0x00);
405 		vgaw(ba, MERLIN_VDAC_SPRITE,  0xff);
406 		vgaw(ba, MERLIN_VDAC_INDEX, 0x01);
407 		vgaw(ba, MERLIN_VDAC_SPRITE,  0x0f);
408 		vgaw(ba, MERLIN_VDAC_INDEX, 0x02);
409 		vgaw(ba, MERLIN_VDAC_SPRITE,  0x42);
410 		vgaw(ba, MERLIN_VDAC_INDEX, 0x03);
411 		vgaw(ba, MERLIN_VDAC_SPRITE,  0x00);
412 
413 		vgaw(ba, MERLIN_VDAC_DATA, 0);
414 	}
415 
416 
417 	/* setup initial unchanging parameters */
418 
419 	vgaw(ba, GREG_HERCULESCOMPAT + ((ettype == DOMINO) ? 0x0fff : 0), 0x03);
420 	vgaw(ba, GREG_DISPMODECONTROL, 0xa0);
421 	vgaw(ba, GREG_MISC_OUTPUT_W, 0x63);
422 
423 	if (ettype == DOMINO)
424 	{
425 		vgaw(ba, CRT_ADDRESS, CRT_ID_VIDEO_CONFIG1);
426 		vgaw(ba, CRT_ADDRESS_W + 0x0fff,
427 		    0xc0 | vgar(ba, CRT_ADDRESS_R + 0x0fff));
428 	}
429 
430 	WSeq(ba, SEQ_ID_RESET, 0x03);
431 	WSeq(ba, SEQ_ID_CLOCKING_MODE, 0x21);	/* 8 dot, Display off */
432 	WSeq(ba, SEQ_ID_MAP_MASK, 0x0f);
433 	WSeq(ba, SEQ_ID_CHAR_MAP_SELECT, 0x00);
434 	WSeq(ba, SEQ_ID_MEMORY_MODE, 0x0e);
435 	WSeq(ba, SEQ_ID_STATE_CONTROL, 0x00);
436 	WSeq(ba, SEQ_ID_AUXILIARY_MODE, 0xf4);
437 
438 	WCrt(ba, CRT_ID_PRESET_ROW_SCAN, 0x00);
439 	WCrt(ba, CRT_ID_CURSOR_START, 0x00);
440 	WCrt(ba, CRT_ID_CURSOR_END, 0x08);
441 	WCrt(ba, CRT_ID_START_ADDR_HIGH, 0x00);
442 	WCrt(ba, CRT_ID_START_ADDR_LOW, 0x00);
443 	WCrt(ba, CRT_ID_CURSOR_LOC_HIGH, 0x00);
444 	WCrt(ba, CRT_ID_CURSOR_LOC_LOW, 0x00);
445 
446 	WCrt(ba, CRT_ID_UNDERLINE_LOC, 0x67);
447 	WCrt(ba, CRT_ID_MODE_CONTROL, 0xc3);
448 	WCrt(ba, CRT_ID_LINE_COMPARE, 0xff);
449 
450 	/* ET4000 special */
451 	WCrt(ba, CRT_ID_RASCAS_CONFIG, 0x28);
452 	WCrt(ba, CRT_ID_EXT_START, 0x00);
453 	WCrt(ba, CRT_ID_6845_COMPAT, 0x08);
454 
455 	/* ET4000/W32 special (currently only for Merlin (crest) */
456 	if (ettype == MERLIN) {
457 		WCrt(ba, CRT_ID_SEGMENT_COMP, 0x1c);
458 		WCrt(ba, CRT_ID_GENERAL_PURPOSE, 0x00);
459 		WCrt(ba, CRT_ID_VIDEO_CONFIG1, 0x93);
460 	}
461 	else {
462 		WCrt(ba, CRT_ID_VIDEO_CONFIG1, 0xd3);
463 	}
464 
465 	WCrt(ba, CRT_ID_VIDEO_CONFIG2, 0x0f);
466 	WCrt(ba, CRT_ID_HOR_OVERFLOW, 0x00);
467 
468 	vgaw(ba, GREG_SEGMENTSELECT, 0x00);
469 
470 	WGfx(ba, GCT_ID_SET_RESET, 0x00);
471 	WGfx(ba, GCT_ID_ENABLE_SET_RESET, 0x00);
472 	WGfx(ba, GCT_ID_COLOR_COMPARE, 0x00);
473 	WGfx(ba, GCT_ID_DATA_ROTATE, 0x00);
474 	WGfx(ba, GCT_ID_READ_MAP_SELECT, 0x00);
475 	WGfx(ba, GCT_ID_GRAPHICS_MODE, 0x40);
476 	WGfx(ba, GCT_ID_MISC, 0x01);
477 	WGfx(ba, GCT_ID_COLOR_XCARE, 0x0f);
478 	WGfx(ba, GCT_ID_BITMASK, 0xff);
479 
480 	for (x = 0; x < 0x10; x++)
481 		WAttr(ba, x, x);
482 	WAttr(ba, ACT_ID_ATTR_MODE_CNTL, 0x01);
483 	WAttr(ba, ACT_ID_OVERSCAN_COLOR, 0x00);
484 	WAttr(ba, ACT_ID_COLOR_PLANE_ENA, 0x0f);
485 	WAttr(ba, ACT_ID_HOR_PEL_PANNING, 0x00);
486 	WAttr(ba, ACT_ID_COLOR_SELECT, 0x00);
487 	WAttr(ba, ACT_ID_MISCELLANEOUS, 0x00);
488 
489 	vgaw(ba, VDAC_MASK, 0xff);
490 	delay(200000);
491 	vgaw(ba, GREG_MISC_OUTPUT_W, 0xe3);
492 
493 	/* colors initially set to greyscale */
494 	switch(ettype) {
495 	    case MERLIN:
496 		vgaw(ba, MERLIN_VDAC_INDEX, 0);
497 		for (x = 255; x >= 0; x--) {
498 			vgaw(ba, MERLIN_VDAC_COLORS, x);
499 			vgaw(ba, MERLIN_VDAC_COLORS, x);
500 			vgaw(ba, MERLIN_VDAC_COLORS, x);
501 		}
502 		break;
503 	    default:
504 		vgaw(ba, VDAC_ADDRESS_W, 0);
505 		for (x = 255; x >= 0; x--) {
506 			vgaw(ba, VDAC_DATA + ((ettype == DOMINO) ? 0x0fff : 0), x);
507 			vgaw(ba, VDAC_DATA + ((ettype == DOMINO) ? 0x0fff : 0), x);
508 			vgaw(ba, VDAC_DATA + ((ettype == DOMINO) ? 0x0fff : 0), x);
509 		}
510 		break;
511 	}
512 	/* set sprite bitmap pointers */
513 	/* should work like that */
514 	et_cursprite.image = et_imageptr;
515 	et_cursprite.mask = et_maskptr;
516 	et_cursprite.cmap.red = et_sprred;
517 	et_cursprite.cmap.green = et_sprgreen;
518 	et_cursprite.cmap.blue = et_sprblue;
519 
520 	/* card specific initialisations */
521 	switch(ettype) {
522 	    case OMNIBUS:
523 		etctype = et_getControllerType(gp);
524 		etdtype = et_getDACType(gp);
525 		break;
526 	    case MERLIN:
527 		vgaw(ba, GREG_SEGMENTSELECT2, 0x00);
528 		if (((vgar(ba, GREG_FEATURE_CONTROL_R) & 12) |
529 		     (vgar(ba, GREG_STATUS0_R) & 0x60)) == 0x24) {
530 			WCrt(ba, CRT_ID_VIDEO_CONFIG2, 0x07);	/* 1Mx4 RAM */
531 			et_fbsize = 0x400000;			/* 4 MB */
532 		}
533 		else {
534 			/* check for 1MB or 2MB board (crest) */
535 			/* has there a 1MB Merlin ever been sold ??? */
536 			volatile unsigned long *et_fbtestaddr;
537 			et_fbtestaddr = (volatile unsigned long *)gp->g_fbkva;
538 			*et_fbtestaddr = 0x0;
539 			vgaw(ba, GREG_SEGMENTSELECT2, 0x11); /* 1MB offset */
540 			*et_fbtestaddr = 0x12345678;
541 			vgaw(ba, GREG_SEGMENTSELECT2, 0x00);
542 			if (*et_fbtestaddr == 0x0)
543 				et_fbsize = 0x200000;		/* 2 MB */
544 			else
545 				et_fbsize = 0x100000;		/* 1 MB */
546 		}
547 		/* ZorroII can map 2 MB max ... */
548 		if (!iszthreepa(gp->g_fbkva) && et_fbsize == 0x400000)
549 			et_fbsize = 0x200000;
550 		etctype = ETW32;
551 		etdtype = MERLINDAC;
552 		break;
553 	    case DOMINO:
554 		etctype = ET4000;
555 		etdtype = et_getDACType(gp);
556 		break;
557 	}
558 }
559 
560 
561 int
562 et_getvmode(gp, vm)
563 	struct grf_softc *gp;
564 	struct grfvideo_mode *vm;
565 {
566 	struct grfvideo_mode *gv;
567 
568 #ifdef TSENGCONSOLE
569 	/* Handle grabbing console mode */
570 	if (vm->mode_num == 255) {
571 		bcopy(&etconsole_mode, vm, sizeof(struct grfvideo_mode));
572 	/* XXX so grfconfig can tell us the correct text dimensions. */
573 		vm->depth = etconsole_mode.fy;
574 	} else
575 #endif
576 	{
577 		if (vm->mode_num == 0)
578 			vm->mode_num = (monitor_current - monitor_def) + 1;
579 		if (vm->mode_num < 1 || vm->mode_num > monitor_def_max)
580 			return (EINVAL);
581 		gv = monitor_def + (vm->mode_num - 1);
582 		if (gv->mode_num == 0)
583 			return (EINVAL);
584 
585 		bcopy(gv, vm, sizeof(struct grfvideo_mode));
586 	}
587 
588 	/* adjust internal values to pixel values */
589 
590 	vm->hblank_start *= 8;
591 	vm->hsync_start *= 8;
592 	vm->hsync_stop *= 8;
593 	vm->htotal *= 8;
594 
595 	return (0);
596 }
597 
598 
599 int
600 et_setvmode(gp, mode)
601 	struct grf_softc *gp;
602 	unsigned mode;
603 {
604 	if (!mode || (mode > monitor_def_max) ||
605 	    monitor_def[mode - 1].mode_num == 0)
606 		return (EINVAL);
607 
608 	monitor_current = monitor_def + (mode - 1);
609 
610 	return (0);
611 }
612 
613 
614 #ifndef TSENGCONSOLE
615 void
616 et_off(gp)
617 	struct grf_softc *gp;
618 {
619 	char   *ba = gp->g_regkva;
620 
621 	RegOnpass(ba);
622 	WSeq(ba, SEQ_ID_CLOCKING_MODE, 0x21);
623 }
624 #endif
625 
626 
627 int
628 et_blank(gp, on)
629 	struct grf_softc *gp;
630 	int *on;
631 {
632 	WSeq(gp->g_regkva, SEQ_ID_CLOCKING_MODE, *on > 0 ? 0x01 : 0x21);
633 	return(0);
634 }
635 
636 
637 /*
638  * Change the mode of the display.
639  * Return a UNIX error number or 0 for success.
640  */
641 int
642 et_mode(gp, cmd, arg, a2, a3)
643 	register struct grf_softc *gp;
644 	u_long cmd;
645 	void *arg;
646 	u_long a2;
647 	int a3;
648 {
649 	int error;
650 
651 	switch (cmd) {
652 	    case GM_GRFON:
653 		error = et_load_mon(gp,
654 		    (struct grfettext_mode *) monitor_current) ? 0 : EINVAL;
655 		return (error);
656 
657 	    case GM_GRFOFF:
658 #ifndef TSENGCONSOLE
659 		et_off(gp);
660 #else
661 		et_load_mon(gp, &etconsole_mode);
662 #endif
663 		return (0);
664 
665 	    case GM_GRFCONFIG:
666 		return (0);
667 
668 	    case GM_GRFGETVMODE:
669 		return (et_getvmode(gp, (struct grfvideo_mode *) arg));
670 
671 	    case GM_GRFSETVMODE:
672 		error = et_setvmode(gp, *(unsigned *) arg);
673 		if (!error && (gp->g_flags & GF_GRFON))
674 			et_load_mon(gp,
675 			    (struct grfettext_mode *) monitor_current);
676 		return (error);
677 
678 	    case GM_GRFGETNUMVM:
679 		*(int *) arg = monitor_def_max;
680 		return (0);
681 
682 	    case GM_GRFIOCTL:
683 		return (et_ioctl(gp, a2, arg));
684 
685 	    default:
686 		break;
687 	}
688 
689 	return (EINVAL);
690 }
691 
692 
693 int
694 et_ioctl(gp, cmd, data)
695 	register struct grf_softc *gp;
696 	u_long cmd;
697 	void   *data;
698 {
699 	switch (cmd) {
700 	    case GRFIOCGSPRITEPOS:
701 		return (et_getmousepos(gp, (struct grf_position *) data));
702 
703 	    case GRFIOCSSPRITEPOS:
704 		return (et_setmousepos(gp, (struct grf_position *) data));
705 
706 	    case GRFIOCSSPRITEINF:
707 		return (et_setspriteinfo(gp, (struct grf_spriteinfo *) data));
708 
709 	    case GRFIOCGSPRITEINF:
710 		return (et_getspriteinfo(gp, (struct grf_spriteinfo *) data));
711 
712 	    case GRFIOCGSPRITEMAX:
713 		return (et_getspritemax(gp, (struct grf_position *) data));
714 
715 	    case GRFIOCGETCMAP:
716 		return (et_getcmap(gp, (struct grf_colormap *) data));
717 
718 	    case GRFIOCPUTCMAP:
719 		return (et_putcmap(gp, (struct grf_colormap *) data));
720 
721 	    case GRFIOCBITBLT:
722 		break;
723 
724 	    case GRFTOGGLE:
725 		return (et_toggle(gp, 0));
726 
727 	    case GRFIOCSETMON:
728 		return (et_setmonitor(gp, (struct grfvideo_mode *) data));
729 
730 	    case GRFIOCBLANK:
731 		return (et_blank(gp, (int *)data));
732 	}
733 	return (EINVAL);
734 }
735 
736 
737 int
738 et_getmousepos(gp, data)
739 	struct grf_softc *gp;
740 	struct grf_position *data;
741 {
742 	data->x = et_cursprite.pos.x;
743 	data->y = et_cursprite.pos.y;
744 
745 	return (0);
746 }
747 
748 
749 void
750 et_writesprpos(ba, x, y)
751 	volatile char *ba;
752 	short   x;
753 	short   y;
754 {
755 }
756 
757 
758 int
759 et_setmousepos(gp, data)
760 	struct grf_softc *gp;
761 	struct grf_position *data;
762 {
763 	volatile char *ba = gp->g_regkva;
764 	short rx, ry, prx, pry;
765 
766 	/* no movement */
767 	if (et_cursprite.pos.x == data->x && et_cursprite.pos.y == data->y)
768 		return (0);
769 
770 	/* current and previous real coordinates */
771 	rx = data->x - et_cursprite.hot.x;
772 	ry = data->y - et_cursprite.hot.y;
773 	prx = et_cursprite.pos.x - et_cursprite.hot.x;
774 	pry = et_cursprite.pos.y - et_cursprite.hot.y;
775 
776 	/* if we are/were on an edge, create (un)shifted bitmap --
777 	 * ripped out optimization (not extremely worthwhile,
778 	 * and kind of buggy anyhow).
779 	 */
780 
781 	/* do movement, save position */
782 	et_writesprpos(ba, rx < 0 ? 0 : rx, ry < 0 ? 0 : ry);
783 	et_cursprite.pos.x = data->x;
784 	et_cursprite.pos.y = data->y;
785 
786 	return (0);
787 }
788 
789 
790 int
791 et_getspriteinfo(gp, data)
792 	struct grf_softc *gp;
793 	struct grf_spriteinfo *data;
794 {
795 
796 	return(EINVAL);
797 }
798 
799 
800 static int
801 et_setspriteinfo(gp, data)
802 	struct grf_softc *gp;
803 	struct grf_spriteinfo *data;
804 {
805 
806 	return(EINVAL);
807 }
808 
809 
810 static int
811 et_getspritemax(gp, data)
812 	struct grf_softc *gp;
813 	struct grf_position *data;
814 {
815 
816 	return(EINVAL);
817 }
818 
819 
820 int
821 et_setmonitor(gp, gv)
822 	struct grf_softc *gp;
823 	struct grfvideo_mode *gv;
824 {
825 	struct grfvideo_mode *md;
826 
827 	if (!et_mondefok(gv))
828 		return(EINVAL);
829 
830 #ifdef TSENGCONSOLE
831 	/* handle interactive setting of console mode */
832 	if (gv->mode_num == 255) {
833 		bcopy(gv, &etconsole_mode.gv, sizeof(struct grfvideo_mode));
834 		etconsole_mode.gv.hblank_start /= 8;
835 		etconsole_mode.gv.hsync_start /= 8;
836 		etconsole_mode.gv.hsync_stop /= 8;
837 		etconsole_mode.gv.htotal /= 8;
838 		etconsole_mode.rows = gv->disp_height / etconsole_mode.fy;
839 		etconsole_mode.cols = gv->disp_width / etconsole_mode.fx;
840 		if (!(gp->g_flags & GF_GRFON))
841 			et_load_mon(gp, &etconsole_mode);
842 		ite_reinit(gp->g_itedev);
843 		return (0);
844 	}
845 #endif
846 
847 	md = monitor_def + (gv->mode_num - 1);
848 	bcopy(gv, md, sizeof(struct grfvideo_mode));
849 
850 	/* adjust pixel oriented values to internal rep. */
851 
852 	md->hblank_start /= 8;
853 	md->hsync_start /= 8;
854 	md->hsync_stop /= 8;
855 	md->htotal /= 8;
856 
857 	return (0);
858 }
859 
860 
861 int
862 et_getcmap(gfp, cmap)
863 	struct grf_softc *gfp;
864 	struct grf_colormap *cmap;
865 {
866 	volatile unsigned char *ba;
867 	u_char	red[256], green[256], blue[256], *rp, *gp, *bp;
868 	short	x;
869 	int	error;
870 
871 	if (cmap->count == 0 || cmap->index >= 256)
872 		return 0;
873 
874 	if (cmap->index + cmap->count > 256)
875 		cmap->count = 256 - cmap->index;
876 
877 	ba = gfp->g_regkva;
878 	/* first read colors out of the chip, then copyout to userspace */
879 	x = cmap->count - 1;
880 
881 	rp = red + cmap->index;
882 	gp = green + cmap->index;
883 	bp = blue + cmap->index;
884 
885 	switch(ettype) {
886 	    case MERLIN:
887 		vgaw(ba, MERLIN_VDAC_INDEX, cmap->index);
888 		do {
889 			*rp++ = vgar(ba, MERLIN_VDAC_COLORS);
890 			*gp++ = vgar(ba, MERLIN_VDAC_COLORS);
891 			*bp++ = vgar(ba, MERLIN_VDAC_COLORS);
892 		} while (x-- > 0);
893 		break;
894 	    default:
895 		vgaw(ba, VDAC_ADDRESS_R+((ettype==DOMINO)?0x0fff:0), cmap->index);
896 		do {
897 			*rp++ = vgar(ba, VDAC_DATA+((ettype==DOMINO)?0x0fff:0)) << etcmap_shift;
898 			*gp++ = vgar(ba, VDAC_DATA+((ettype==DOMINO)?0x0fff:0)) << etcmap_shift;
899 			*bp++ = vgar(ba, VDAC_DATA+((ettype==DOMINO)?0x0fff:0)) << etcmap_shift;
900 		} while (x-- > 0);
901 		break;
902 	}
903 
904 	error = copyout(red + cmap->index, cmap->red, cmap->count);
905 	if (!error)
906 		error = copyout(green + cmap->index, cmap->green, cmap->count);
907 	if (!error)
908 		error = copyout(blue + cmap->index, cmap->blue, cmap->count);
909 
910 	return (error);
911 }
912 
913 
914 int
915 et_putcmap(gfp, cmap)
916 	struct grf_softc *gfp;
917 	struct grf_colormap *cmap;
918 {
919 	volatile unsigned char *ba;
920 	u_char	red[256], green[256], blue[256], *rp, *gp, *bp;
921 	short	x;
922 	int	error;
923 
924 	if (cmap->count == 0 || cmap->index >= 256)
925 		return (0);
926 
927 	if (cmap->index + cmap->count > 256)
928 		cmap->count = 256 - cmap->index;
929 
930 	/* first copy the colors into kernelspace */
931 	if ((error = copyin(cmap->red, red + cmap->index, cmap->count)))
932 		return (error);
933 
934 	if ((error = copyin(cmap->green, green + cmap->index, cmap->count)))
935 		return (error);
936 
937 	if ((error = copyin(cmap->blue, blue + cmap->index, cmap->count)))
938 		return (error);
939 
940 	ba = gfp->g_regkva;
941 	x = cmap->count - 1;
942 
943 	rp = red + cmap->index;
944 	gp = green + cmap->index;
945 	bp = blue + cmap->index;
946 
947 	switch(ettype){
948 	    case MERLIN:
949 		vgaw(ba, MERLIN_VDAC_INDEX, cmap->index);
950 		do {
951 			vgaw(ba, MERLIN_VDAC_COLORS, *rp++);
952 			vgaw(ba, MERLIN_VDAC_COLORS, *gp++);
953 			vgaw(ba, MERLIN_VDAC_COLORS, *bp++);
954 		} while (x-- > 0);
955 		break;
956 	    default:
957 		vgaw(ba, VDAC_ADDRESS_W, cmap->index);
958 		do {
959 			vgaw(ba, VDAC_DATA + ((ettype == DOMINO) ? 0x0fff : 0),
960 			    *rp++ >> etcmap_shift);
961 			vgaw(ba, VDAC_DATA + ((ettype == DOMINO) ? 0x0fff : 0),
962 			    *gp++ >> etcmap_shift);
963 			vgaw(ba, VDAC_DATA + ((ettype == DOMINO) ? 0x0fff : 0),
964 			    *bp++ >> etcmap_shift);
965 		} while (x-- > 0);
966 		break;
967 	}
968 
969 	return (0);
970 }
971 
972 
973 int
974 et_toggle(gp, wopp)
975 	struct grf_softc *gp;
976 	unsigned short wopp;	/* don't need that one yet, ill */
977 {
978 	volatile unsigned char *ba;
979 
980 	ba = gp->g_regkva;
981 
982 	if (pass_toggle) {
983 		RegOffpass(ba);
984 	} else {
985 		RegOnpass(ba);
986 	}
987 	return (0);
988 }
989 
990 
991 #define ET_NUMCLOCKS 32
992 
993 static u_char et_clocks[ET_NUMCLOCKS] = {
994 	0, 1, 6, 2, 3, 7, 4, 5,
995 	0, 1, 6, 2, 3, 7, 4, 5,
996 	0, 1, 6, 2, 3, 7, 4, 5,
997 	0, 1, 6, 2, 3, 7, 4, 5
998 };
999 
1000 static u_char et_clockdividers[ET_NUMCLOCKS] = {
1001 	3, 3, 3, 3, 3, 3, 3, 3,
1002 	2, 2, 2, 2, 2, 2, 2, 2,
1003 	1, 1, 1, 1, 1, 1, 1, 1,
1004 	0, 0, 0, 0, 0, 0, 0, 0
1005 };
1006 
1007 static u_int et_clockfreqs[ET_NUMCLOCKS] = {
1008 	 6293750,  7080500,  7875000,  8125000,
1009 	 9000000,  9375000, 10000000, 11225000,
1010 	12587500, 14161000, 15750000, 16250000,
1011 	18000000, 18750000, 20000000, 22450000,
1012 	25175000, 28322000, 31500000, 32500000,
1013 	36000000, 37500000, 40000000, 44900000,
1014 	50350000, 56644000, 63000000, 65000000,
1015 	72000000, 75000000, 80000000, 89800000
1016 };
1017 
1018 
1019 static void
1020 et_CompFQ(fq, num, denom)
1021 	u_int   fq;
1022 	u_char *num;
1023 	u_char *denom;
1024 {
1025 	int i;
1026 
1027 	for (i=0; i < ET_NUMCLOCKS;) {
1028 		if (fq <= et_clockfreqs[i++]) {
1029 			break;
1030 		}
1031 	}
1032 
1033 	*num = et_clocks[--i];
1034 	*denom = et_clockdividers[i];
1035 
1036 	return;
1037 }
1038 
1039 
1040 int
1041 et_mondefok(gv)
1042 	struct grfvideo_mode *gv;
1043 {
1044         unsigned long maxpix;
1045 
1046 	if (gv->mode_num < 1 || gv->mode_num > monitor_def_max)
1047 		if (gv->mode_num != 255 || gv->depth != 4)
1048 			return(0);
1049 
1050 	switch (gv->depth) {
1051 	    case 4:
1052 		if (gv->mode_num != 255)
1053 			return(0);
1054 	    case 1:
1055 	    case 8:
1056                 maxpix = 85000000;
1057                 break;
1058 	    case 15:
1059 	    case 16:
1060                 maxpix = 45000000;
1061                 break;
1062 	    case 24:
1063                 maxpix = 28000000;
1064                 break;
1065 	    case 32:
1066                 maxpix = 21000000;
1067                 break;
1068 	    default:
1069 		printf("grfet: Illegal depth in mode %d\n",
1070 			(int) gv->mode_num);
1071 		return (0);
1072 	}
1073 
1074         if (gv->pixel_clock > maxpix) {
1075 		printf("grfet: Pixelclock too high in mode %d\n",
1076 			(int) gv->mode_num);
1077                 return (0);
1078 	}
1079 
1080 	if (gv->disp_flags & GRF_FLAGS_SYNC_ON_GREEN) {
1081 		printf("grfet: sync-on-green is not supported\n");
1082 		return (0);
1083 	}
1084 
1085 	return (1);
1086 }
1087 
1088 
1089 int
1090 et_load_mon(gp, md)
1091 	struct grf_softc *gp;
1092 	struct grfettext_mode *md;
1093 {
1094 	struct grfvideo_mode *gv;
1095 	struct grfinfo *gi;
1096 	volatile unsigned char *ba;
1097 	unsigned char num0, denom0;
1098 	unsigned short HT, HDE, HBS, HBE, HSS, HSE, VDE, VBS, VBE, VSS,
1099 	        VSE, VT;
1100 	unsigned char hvsync_pulse, seq;
1101 	char    TEXT;
1102 	int	hmul;
1103 
1104 	/* identity */
1105 	gv = &md->gv;
1106 	TEXT = (gv->depth == 4);
1107 
1108 	if (!et_mondefok(gv)) {
1109 		printf("grfet: Monitor definition not ok\n");
1110 		return (0);
1111 	}
1112 
1113 	ba = gp->g_regkva;
1114 
1115 	/* provide all needed information in grf device-independant locations */
1116 	gp->g_data = (caddr_t) gv;
1117 	gi = &gp->g_display;
1118 	gi->gd_regaddr = (caddr_t) ztwopa(ba);
1119 	gi->gd_regsize = 64 * 1024;
1120 	gi->gd_fbaddr = (caddr_t) kvtop(gp->g_fbkva);
1121 	gi->gd_fbsize = et_fbsize;
1122 	gi->gd_colors = 1 << gv->depth;
1123 	gi->gd_planes = gv->depth;
1124 	gi->gd_fbwidth = gv->disp_width;
1125 	gi->gd_fbheight = gv->disp_height;
1126 	gi->gd_fbx = 0;
1127 	gi->gd_fby = 0;
1128 	if (TEXT) {
1129 		gi->gd_dwidth = md->fx * md->cols;
1130 		gi->gd_dheight = md->fy * md->rows;
1131 	} else {
1132 		gi->gd_dwidth = gv->disp_width;
1133 		gi->gd_dheight = gv->disp_height;
1134 	}
1135 	gi->gd_dx = 0;
1136 	gi->gd_dy = 0;
1137 
1138 	/* get display mode parameters */
1139 
1140 	HBS = gv->hblank_start;
1141 	HSS = gv->hsync_start;
1142 	HSE = gv->hsync_stop;
1143 	HBE = gv->htotal - 1;
1144 	HT  = gv->htotal;
1145 	VBS = gv->vblank_start;
1146 	VSS = gv->vsync_start;
1147 	VSE = gv->vsync_stop;
1148 	VBE = gv->vtotal - 1;
1149 	VT  = gv->vtotal;
1150 
1151 	if (TEXT)
1152 		HDE = ((gv->disp_width + md->fx - 1) / md->fx) - 1;
1153 	else
1154 		HDE = (gv->disp_width + 3) / 8 - 1;	/* HBS; */
1155 	VDE = gv->disp_height - 1;
1156 
1157 	/* adjustments (crest) */
1158 	switch (gv->depth) {
1159 	    case 15:
1160 	    case 16:
1161 		hmul = 2;
1162 		break;
1163 	    case 24:
1164 		hmul = 3;
1165 		break;
1166 	    case 32:
1167 		hmul = 4;
1168 		break;
1169 	    default:
1170 		hmul = 1;
1171 		break;
1172 	}
1173 
1174 	HDE *= hmul;
1175 	HBS *= hmul;
1176 	HSS *= hmul;
1177 	HSE *= hmul;
1178 	HBE *= hmul;
1179 	HT  *= hmul;
1180 
1181 	if (gv->disp_flags & GRF_FLAGS_LACE) {
1182 		VDE /= 2;
1183 		VT = VT + 1;
1184 	}
1185 
1186 	if (gv->disp_flags & GRF_FLAGS_DBLSCAN) {
1187 		VDE *= 2;
1188 		VBS *= 2;
1189 		VSS *= 2;
1190 		VSE *= 2;
1191 		VBE *= 2;
1192 		VT  *= 2;
1193 	}
1194 
1195 	WSeq(ba, SEQ_ID_MEMORY_MODE, (TEXT || (gv->depth == 1)) ? 0x06 : 0x0e);
1196 
1197 	WGfx(ba, GCT_ID_READ_MAP_SELECT, 0x00);
1198 	WSeq(ba, SEQ_ID_MAP_MASK, (gv->depth == 1) ? 0x01 : 0xff);
1199 	WSeq(ba, SEQ_ID_CHAR_MAP_SELECT, 0x00);
1200 
1201 	/* Set clock */
1202 	et_CompFQ( gv->pixel_clock * hmul, &num0, &denom0);
1203 
1204 	/* Horizontal/Vertical Sync Pulse */
1205 	hvsync_pulse = 0xe3;
1206 	if (gv->disp_flags & GRF_FLAGS_PHSYNC)
1207 		hvsync_pulse &= ~0x40;
1208 	else
1209 		hvsync_pulse |= 0x40;
1210 	if (gv->disp_flags & GRF_FLAGS_PVSYNC)
1211 		hvsync_pulse &= ~0x80;
1212 	else
1213 		hvsync_pulse |= 0x80;
1214 
1215 	vgaw(ba, GREG_MISC_OUTPUT_W, hvsync_pulse | ((num0 & 3) << 2));
1216 	WCrt(ba, CRT_ID_6845_COMPAT, (num0 & 4) ? 0x0a : 0x08);
1217 	seq = RSeq(ba, SEQ_ID_CLOCKING_MODE);
1218 	switch(denom0) {
1219 	    case 0:
1220 		WSeq(ba, SEQ_ID_AUXILIARY_MODE, 0xb4);
1221 		WSeq(ba, SEQ_ID_CLOCKING_MODE, seq & 0xf7);
1222  		break;
1223 	    case 1:
1224 		WSeq(ba, SEQ_ID_AUXILIARY_MODE, 0xf4);
1225 		WSeq(ba, SEQ_ID_CLOCKING_MODE, seq & 0xf7);
1226 		break;
1227 	    case 2:
1228 		WSeq(ba, SEQ_ID_AUXILIARY_MODE, 0xf5);
1229 		WSeq(ba, SEQ_ID_CLOCKING_MODE, seq & 0xf7);
1230 		break;
1231 	    case 3:
1232 		WSeq(ba, SEQ_ID_AUXILIARY_MODE, 0xf5);
1233 		WSeq(ba, SEQ_ID_CLOCKING_MODE, seq | 0x08);
1234 		break;
1235 	}
1236 
1237 	/* load display parameters into board */
1238 	WCrt(ba, CRT_ID_HOR_TOTAL, HT);
1239 	WCrt(ba, CRT_ID_HOR_DISP_ENA_END, ((HDE >= HBS) ? HBS - 1 : HDE));
1240 	WCrt(ba, CRT_ID_START_HOR_BLANK, HBS);
1241 	WCrt(ba, CRT_ID_END_HOR_BLANK, (HBE & 0x1f) | 0x80);
1242 	WCrt(ba, CRT_ID_START_HOR_RETR, HSS);
1243 	WCrt(ba, CRT_ID_END_HOR_RETR,
1244 	    (HSE & 0x1f) |
1245 	    ((HBE & 0x20) ? 0x80 : 0x00));
1246 	WCrt(ba, CRT_ID_VER_TOTAL, VT);
1247 	WCrt(ba, CRT_ID_OVERFLOW,
1248 	    0x10 |
1249 	    ((VT  & 0x100) ? 0x01 : 0x00) |
1250 	    ((VDE & 0x100) ? 0x02 : 0x00) |
1251 	    ((VSS & 0x100) ? 0x04 : 0x00) |
1252 	    ((VBS & 0x100) ? 0x08 : 0x00) |
1253 	    ((VT  & 0x200) ? 0x20 : 0x00) |
1254 	    ((VDE & 0x200) ? 0x40 : 0x00) |
1255 	    ((VSS & 0x200) ? 0x80 : 0x00));
1256 
1257 	WCrt(ba, CRT_ID_MAX_ROW_ADDRESS,
1258 	    0x40 |		/* splitscreen not visible */
1259 	    ((gv->disp_flags & GRF_FLAGS_DBLSCAN) ? 0x80 : 0x00) |
1260 	    ((VBS & 0x200) ? 0x20 : 0x00) |
1261 	    (TEXT ? ((md->fy - 1) & 0x1f) : 0x00));
1262 
1263 	WCrt(ba, CRT_ID_MODE_CONTROL,
1264 	    ((TEXT || (gv->depth == 1)) ? 0xc3 : 0xab));
1265 
1266 	/* text cursor */
1267 	if (TEXT) {
1268 #if ET_ULCURSOR
1269 		WCrt(ba, CRT_ID_CURSOR_START, (md->fy & 0x1f) - 2);
1270 		WCrt(ba, CRT_ID_CURSOR_END, (md->fy & 0x1f) - 1);
1271 #else
1272 		WCrt(ba, CRT_ID_CURSOR_START, 0x00);
1273 		WCrt(ba, CRT_ID_CURSOR_END, md->fy & 0x1f);
1274 #endif
1275 		WCrt(ba, CRT_ID_CURSOR_LOC_HIGH, 0x00);
1276 		WCrt(ba, CRT_ID_CURSOR_LOC_LOW, 0x00);
1277 	}
1278 
1279 	WCrt(ba, CRT_ID_UNDERLINE_LOC, ((md->fy - 1) & 0x1f)
1280 		| ((TEXT || (gv->depth == 1)) ? 0x00 : 0x60));
1281 
1282 	WCrt(ba, CRT_ID_START_ADDR_HIGH, 0x00);
1283 	WCrt(ba, CRT_ID_START_ADDR_LOW, 0x00);
1284 
1285 	WCrt(ba, CRT_ID_START_VER_RETR, VSS);
1286 	WCrt(ba, CRT_ID_END_VER_RETR, (VSE & 0x0f) | 0x30);
1287 	WCrt(ba, CRT_ID_VER_DISP_ENA_END, VDE);
1288 	WCrt(ba, CRT_ID_START_VER_BLANK, VBS);
1289 	WCrt(ba, CRT_ID_END_VER_BLANK, VBE);
1290 
1291 	WCrt(ba, CRT_ID_LINE_COMPARE, 0xff);
1292 
1293 	WCrt(ba, CRT_ID_OVERFLOW_HIGH,
1294 	    ((VBS & 0x400) ? 0x01 : 0x00) |
1295 	    ((VT  & 0x400) ? 0x02 : 0x00) |
1296 	    ((VDE & 0x400) ? 0x04 : 0x00) |
1297 	    ((VSS & 0x400) ? 0x08 : 0x00) |
1298 	    0x10 |
1299 	    ((gv->disp_flags & GRF_FLAGS_LACE) ? 0x80 : 0x00));
1300 
1301 	WCrt(ba, CRT_ID_HOR_OVERFLOW,
1302 	    ((HT  & 0x100) ? 0x01 : 0x00) |
1303 	    ((HBS & 0x100) ? 0x04 : 0x00) |
1304 	    ((HSS & 0x100) ? 0x10 : 0x00)
1305 	);
1306 
1307 	/* depth dependent stuff */
1308 
1309 	WGfx(ba, GCT_ID_GRAPHICS_MODE,
1310 	    ((TEXT || (gv->depth == 1)) ? 0x00 : 0x40));
1311 	WGfx(ba, GCT_ID_MISC, (TEXT ? 0x04 : 0x01));
1312 
1313 	vgaw(ba, VDAC_MASK, 0xff);
1314 	vgar(ba, VDAC_MASK);
1315 	vgar(ba, VDAC_MASK);
1316 	vgar(ba, VDAC_MASK);
1317 	vgar(ba, VDAC_MASK);
1318 	switch (gv->depth) {
1319 	    case 1:
1320 	    case 4:	/* text */
1321 		switch(etdtype) {
1322 		    case SIERRA11483:
1323 		    case SIERRA15025:
1324 		    case MUSICDAC:
1325 			vgaw(ba, VDAC_MASK, 0);
1326 			break;
1327 		    case ATT20C491:
1328 			vgaw(ba, VDAC_MASK, 0x02);
1329 			break;
1330 		    case MERLINDAC:
1331 			setMerlinDACmode(ba, 0);
1332 			break;
1333 		}
1334 		HDE = gv->disp_width / 16;
1335 		break;
1336 	    case 8:
1337 		switch(etdtype) {
1338 		    case SIERRA11483:
1339 		    case SIERRA15025:
1340 		    case MUSICDAC:
1341 			vgaw(ba, VDAC_MASK, 0);
1342 			break;
1343 		    case ATT20C491:
1344 			vgaw(ba, VDAC_MASK, 0x02);
1345 			break;
1346 		    case MERLINDAC:
1347 			setMerlinDACmode(ba, 0);
1348 			break;
1349 		}
1350 		HDE = gv->disp_width / 8;
1351 		break;
1352 	    case 15:
1353 		switch(etdtype) {
1354 		    case SIERRA11483:
1355 		    case SIERRA15025:
1356 		    case MUSICDAC:
1357 		    case ATT20C491:
1358 			vgaw(ba, VDAC_MASK, 0xa0);
1359 			break;
1360 		    case MERLINDAC:
1361 			setMerlinDACmode(ba, 0xa0);
1362 			break;
1363 		}
1364 		HDE = gv->disp_width / 4;
1365 		break;
1366 	    case 16:
1367 		switch(etdtype) {
1368 		    case SIERRA11483:
1369 			vgaw(ba, VDAC_MASK, 0);	/* illegal mode! */
1370 			break;
1371 		    case SIERRA15025:
1372 			vgaw(ba, VDAC_MASK, 0xe0);
1373 			break;
1374 		    case MUSICDAC:
1375 		    case ATT20C491:
1376 			vgaw(ba, VDAC_MASK, 0xc0);
1377 			break;
1378 		    case MERLINDAC:
1379 			setMerlinDACmode(ba, 0xe0);
1380 			break;
1381 		}
1382 		HDE = gv->disp_width / 4;
1383 		break;
1384 	    case 24:
1385 		switch(etdtype) {
1386 		    case SIERRA11483:
1387 			vgaw(ba, VDAC_MASK, 0);	/* illegal mode! */
1388 			break;
1389 		    case SIERRA15025:
1390 			vgaw(ba, VDAC_MASK, 0xe1);
1391 			break;
1392 		    case MUSICDAC:
1393 		    case ATT20C491:
1394 			vgaw(ba, VDAC_MASK, 0xe0);
1395 			break;
1396 		    case MERLINDAC:
1397 			setMerlinDACmode(ba, 0xf0);
1398 			break;
1399 		}
1400 		HDE = (gv->disp_width / 8) * 3;
1401 		break;
1402 	    case 32:
1403 		switch(etdtype) {
1404 		    case SIERRA11483:
1405 		    case MUSICDAC:
1406 		    case ATT20C491:
1407 			vgaw(ba, VDAC_MASK, 0);	/* illegal mode! */
1408 			break;
1409 		    case SIERRA15025:
1410 			vgaw(ba, VDAC_MASK, 0x61);
1411 			break;
1412 		    case MERLINDAC:
1413 			setMerlinDACmode(ba, 0xb0);
1414 			break;
1415 		}
1416 		HDE = gv->disp_width / 2;
1417 		break;
1418 	}
1419 	WAttr(ba, ACT_ID_ATTR_MODE_CNTL, (TEXT ? 0x0a : 0x01));
1420 	WAttr(ba, 0x20 | ACT_ID_COLOR_PLANE_ENA,
1421 	    (gv->depth == 1) ? 0x01 : 0x0f);
1422 
1423 	WCrt(ba, CRT_ID_OFFSET, HDE);
1424 	vgaw(ba, CRT_ADDRESS, CRT_ID_HOR_OVERFLOW);
1425 	vgaw(ba, CRT_ADDRESS_W,
1426 		(vgar(ba, CRT_ADDRESS_R) & 0x7f)
1427                 | ((HDE & 0x100) ? 0x80: 0x00));
1428 
1429 	/* text initialization */
1430 	if (TEXT) {
1431 		et_inittextmode(gp);
1432 	}
1433 
1434 	WSeq(ba, SEQ_ID_CLOCKING_MODE, 0x01);
1435 
1436 	/* Pass-through */
1437 	RegOffpass(ba);
1438 
1439 	return (1);
1440 }
1441 
1442 
1443 void
1444 et_inittextmode(gp)
1445 	struct grf_softc *gp;
1446 {
1447 	struct grfettext_mode *tm = (struct grfettext_mode *) gp->g_data;
1448 	volatile unsigned char *ba = gp->g_regkva;
1449 	unsigned char *fb = gp->g_fbkva;
1450 	unsigned char *c, *f, y;
1451 	unsigned short z;
1452 
1453 
1454 	/*
1455 	 * load text font into beginning of display memory. Each character
1456 	 * cell is 32 bytes long (enough for 4 planes)
1457 	 */
1458 
1459 	SetTextPlane(ba, 0x02);
1460         et_memset(fb, 0, 256 * 32);
1461 	c = (unsigned char *) (fb) + (32 * tm->fdstart);
1462 	f = tm->fdata;
1463 	for (z = tm->fdstart; z <= tm->fdend; z++, c += (32 - tm->fy))
1464 		for (y = 0; y < tm->fy; y++)
1465 			*c++ = *f++;
1466 
1467 	/* clear out text/attr planes (three screens worth) */
1468 
1469 	SetTextPlane(ba, 0x01);
1470 	et_memset(fb, 0x07, tm->cols * tm->rows * 3);
1471 	SetTextPlane(ba, 0x00);
1472 	et_memset(fb, 0x20, tm->cols * tm->rows * 3);
1473 
1474 	/* print out a little init msg */
1475 
1476 	c = (unsigned char *) (fb) + (tm->cols - 16);
1477 	strcpy(c, "TSENG");
1478 	c[5] = 0x20;
1479 
1480 	/* set colors (B&W) */
1481 
1482 	switch(ettype) {
1483 	    case MERLIN:
1484 		vgaw(ba, MERLIN_VDAC_INDEX, 0);
1485 		for (z = 0; z < 256; z++) {
1486 			y = (z & 1) ? ((z > 7) ? 2 : 1) : 0;
1487 
1488 			vgaw(ba, MERLIN_VDAC_COLORS, etconscolors[y][0]);
1489 			vgaw(ba, MERLIN_VDAC_COLORS, etconscolors[y][1]);
1490 			vgaw(ba, MERLIN_VDAC_COLORS, etconscolors[y][2]);
1491 		}
1492 		break;
1493 	    default:
1494 		vgaw(ba, VDAC_ADDRESS_W, 0);
1495 		for (z = 0; z < 256; z++) {
1496 			y = (z & 1) ? ((z > 7) ? 2 : 1) : 0;
1497 
1498 			vgaw(ba, VDAC_DATA + ((ettype == DOMINO) ? 0x0fff : 0),
1499 			    etconscolors[y][0] >> etcmap_shift);
1500 			vgaw(ba, VDAC_DATA + ((ettype == DOMINO) ? 0x0fff : 0),
1501 			    etconscolors[y][1] >> etcmap_shift);
1502 			vgaw(ba, VDAC_DATA + ((ettype == DOMINO) ? 0x0fff : 0),
1503 			    etconscolors[y][2] >> etcmap_shift);
1504 		}
1505 		break;
1506 	}
1507 }
1508 
1509 
1510 void
1511 et_memset(d, c, l)
1512 	unsigned char *d;
1513 	unsigned char c;
1514 	int     l;
1515 {
1516 	for (; l > 0; l--)
1517 		*d++ = c;
1518 }
1519 
1520 
1521 static int
1522 et_getControllerType(gp)
1523 	struct grf_softc * gp;
1524 {
1525 	unsigned char *ba = gp->g_regkva; /* register base */
1526 	unsigned char *mem = gp->g_fbkva; /* memory base */
1527 	unsigned char *mmu = mem + MMU_APERTURE0; /* MMU aperture 0 base */
1528 
1529 	*mem = 0;
1530 
1531 	/* make ACL visible */
1532 	if (ettype == MERLIN) {
1533 		WCrt(ba, CRT_ID_VIDEO_CONFIG1, 0xbb);
1534 	} else {
1535 		WCrt(ba, CRT_ID_VIDEO_CONFIG1, 0xfb);
1536 	}
1537 
1538 	WIma(ba, IMA_PORTCONTROL, 0x01);
1539 
1540 	*((unsigned long *)mmu) = 0;
1541 	*(mem + 0x13) = 0x38;
1542 
1543 	*mmu = 0xff;
1544 
1545 	/* hide ACL */
1546 	WIma(ba, IMA_PORTCONTROL, 0x00);
1547 
1548 	if (ettype == MERLIN) {
1549 		WCrt(ba, CRT_ID_VIDEO_CONFIG1, 0x93);
1550 	} else {
1551 		WCrt(ba, CRT_ID_VIDEO_CONFIG1, 0xd3);
1552 	}
1553 	return ((*mem == 0xff) ? ETW32 : ET4000);
1554 }
1555 
1556 
1557 static int
1558 et_getDACType(gp)
1559 	struct grf_softc * gp;
1560 {
1561 	unsigned char *ba = gp->g_regkva;
1562 	union {
1563 		int  tt;
1564 		char cc[4];
1565 	} check;
1566 
1567 	/* check for Sierra SC 15025 */
1568 
1569 	/* We MUST do 4 HW reads to switch into command mode */
1570 	if (vgar(ba, HDR)); if (vgar(ba, HDR)); if (vgar(ba, HDR)); if (vgar(ba, HDR));
1571 		vgaw(ba, VDAC_COMMAND, 0x10); /* set ERPF */
1572 
1573 	vgaw(ba, VDAC_XINDEX, 9);
1574 	check.cc[0] = vgar(ba, VDAC_XDATA);
1575 	vgaw(ba, VDAC_XINDEX, 10);
1576 	check.cc[1] = vgar(ba, VDAC_XDATA);
1577 	vgaw(ba, VDAC_XINDEX, 11);
1578 	check.cc[2] = vgar(ba, VDAC_XDATA);
1579 	vgaw(ba, VDAC_XINDEX, 12);
1580 	check.cc[3] = vgar(ba, VDAC_XDATA);
1581 
1582 	if (vgar(ba, HDR)); if (vgar(ba, HDR)); if (vgar(ba, HDR)); if (vgar(ba, HDR));
1583 		vgaw(ba, VDAC_COMMAND, 0x00); /* clear ERPF */
1584 
1585 	if (check.tt == 0x533ab141) {
1586 		if (vgar(ba, HDR)); if (vgar(ba, HDR)); if (vgar(ba, HDR)); if (vgar(ba, HDR));
1587 			vgaw(ba, VDAC_COMMAND, 0x10); /* set ERPF */
1588 
1589 		/* switch to 8 bits per color */
1590 		vgaw(ba, VDAC_XINDEX, 8);
1591 		vgaw(ba, VDAC_XDATA, 1);
1592 		/* do not shift color values */
1593 		etcmap_shift = 0;
1594 
1595 		if (vgar(ba, HDR)); if (vgar(ba, HDR)); if (vgar(ba, HDR)); if (vgar(ba, HDR));
1596 			vgaw(ba, VDAC_COMMAND, 0x00); /* clear ERPF */
1597 
1598 		vgaw(ba, VDAC_MASK, 0xff);
1599 		return (SIERRA15025);
1600 	}
1601 
1602 	/* check for MUSIC DAC */
1603 
1604 	if (vgar(ba, HDR)); if (vgar(ba, HDR)); if (vgar(ba, HDR)); if (vgar(ba, HDR));
1605 		vgaw(ba, VDAC_COMMAND, 0x02);	/* set some strange MUSIC mode (???) */
1606 
1607 	vgaw(ba, VDAC_XINDEX, 0x01);
1608 	if (vgar(ba, VDAC_XDATA) == 0x01) {
1609 		/* shift color values by 2 */
1610 		etcmap_shift = 2;
1611 
1612 		vgaw(ba, VDAC_MASK, 0xff);
1613 		return (MUSICDAC);
1614 	}
1615 
1616 	/* check for AT&T ATT20c491 DAC (crest) */
1617 	if (vgar(ba, HDR)); if (vgar(ba, HDR)); if (vgar(ba, HDR)); if (vgar(ba, HDR));
1618 	vgaw(ba, HDR, 0xff);
1619 	vgaw(ba, VDAC_MASK, 0x01);
1620 	if (vgar(ba, HDR)); if (vgar(ba, HDR)); if (vgar(ba, HDR)); if (vgar(ba, HDR));
1621 	if (vgar(ba, HDR) == 0xff) {
1622 		/* do not shift color values */
1623 		etcmap_shift = 0;
1624 
1625 		vgaw(ba, VDAC_MASK, 0xff);
1626 		return (ATT20C491);
1627 	}
1628 
1629 	/* restore PowerUp settings (crest) */
1630 	if (vgar(ba, HDR)); if (vgar(ba, HDR)); if (vgar(ba, HDR)); if (vgar(ba, HDR));
1631 	vgaw(ba, HDR, 0x00);
1632 
1633 	/*
1634 	 * nothing else found, so let us pretend it is a stupid
1635 	 * Sierra SC 11483
1636 	 */
1637 
1638 	/* shift color values by 2 */
1639 	etcmap_shift = 2;
1640 
1641 	vgaw(ba, VDAC_MASK, 0xff);
1642 	return (SIERRA11483);
1643 }
1644 
1645 #endif /* NGRFET */
1646