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