Home | History | Annotate | Line # | Download | only in dev
grf_cl.c revision 1.10
      1 /*      $NetBSD: grf_cl.c,v 1.10 1996/04/28 06:31:47 mhitch Exp $        */
      2 
      3 /*
      4  * Copyright (c) 1995 Ezra Story
      5  * Copyright (c) 1995 Kari Mettinen
      6  * Copyright (c) 1994 Markus Wild
      7  * Copyright (c) 1994 Lutz Vieweg
      8  * All rights reserved.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *      This product includes software developed by Lutz Vieweg.
     21  * 4. The name of the author may not be used to endorse or promote products
     22  *    derived from this software without specific prior written permission
     23  *
     24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     25  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     26  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     27  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     29  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     30  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     31  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     32  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     33  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     34  */
     35 #include "grfcl.h"
     36 #if NGRFCL > 0
     37 
     38 /*
     39  * Graphics routines for Cirrus CL GD 5426 boards,
     40  *
     41  * This code offers low-level routines to access Cirrus Cl GD 5426
     42  * graphics-boards from within NetBSD for the Amiga.
     43  * No warranties for any kind of function at all - this
     44  * code may crash your hardware and scratch your harddisk.  Use at your
     45  * own risk.  Freely distributable.
     46  *
     47  * Modified for Cirrus CL GD 5426 from
     48  * Lutz Vieweg's retina driver by Kari Mettinen 08/94
     49  * Contributions by Ill, ScottE, MiL
     50  * Extensively hacked and rewritten by Ezra Story (Ezy) 01/95
     51  * Picasso/040 patches (wee!) by crest 01/96
     52  *
     53  * Thanks to Village Tronic Marketing Gmbh for providing me with
     54  * a Picasso-II board.
     55  * Thanks for Integrated Electronics Oy Ab for providing me with
     56  * Cirrus CL GD 542x family documentation.
     57  *
     58  * TODO:
     59  *    Mouse support (almost there! :-))
     60  *    Blitter support
     61  *
     62  */
     63 
     64 #include <sys/param.h>
     65 #include <sys/systm.h>
     66 #include <sys/errno.h>
     67 #include <sys/ioctl.h>
     68 #include <sys/device.h>
     69 #include <sys/malloc.h>
     70 
     71 #include <machine/cpu.h>
     72 #include <dev/cons.h>
     73 #include <amiga/dev/itevar.h>
     74 #include <amiga/amiga/device.h>
     75 #include <amiga/dev/grfioctl.h>
     76 #include <amiga/dev/grfvar.h>
     77 #include <amiga/dev/grf_clreg.h>
     78 #include <amiga/dev/zbusvar.h>
     79 
     80 static int cl_mondefok __P((struct grfvideo_mode *));
     81 static void cl_boardinit __P((struct grf_softc *));
     82 static void CompFQ __P((u_int, u_char *, u_char *));
     83 static int cl_getvmode __P((struct grf_softc *, struct grfvideo_mode *));
     84 static int cl_setvmode __P((struct grf_softc *, unsigned int));
     85 static int cl_toggle __P((struct grf_softc *, unsigned short));
     86 static int cl_getcmap __P((struct grf_softc *, struct grf_colormap *));
     87 static int cl_putcmap __P((struct grf_softc *, struct grf_colormap *));
     88 #ifndef CL5426CONSOLE
     89 static void cl_off __P((struct grf_softc *));
     90 #endif
     91 static void cl_inittextmode __P((struct grf_softc *));
     92 static int cl_ioctl __P((register struct grf_softc *, u_long, void *));
     93 static int cl_getmousepos __P((struct grf_softc *, struct grf_position *));
     94 static int cl_setmousepos __P((struct grf_softc *, struct grf_position *));
     95 static int cl_setspriteinfo __P((struct grf_softc *, struct grf_spriteinfo *));
     96 static int cl_getspriteinfo __P((struct grf_softc *, struct grf_spriteinfo *));
     97 static int cl_getspritemax __P((struct grf_softc *, struct grf_position *));
     98 static int cl_blank __P((struct grf_softc *, int *));
     99 int cl_setmonitor __P((struct grf_softc *, struct grfvideo_mode *));
    100 void cl_writesprpos __P((volatile char *, short, short));
    101 void writeshifted __P((volatile char *, char, char));
    102 
    103 void grfclattach __P((struct device *, struct device *, void *));
    104 int grfclprint __P((void *, char *));
    105 int grfclmatch __P((struct device *, void *, void *));
    106 void cl_memset __P((unsigned char *, unsigned char, int));
    107 
    108 /* Graphics display definitions.
    109  * These are filled by 'grfconfig' using GRFIOCSETMON.
    110  */
    111 #define monitor_def_max 8
    112 static struct grfvideo_mode monitor_def[8] = {
    113 	{0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}
    114 };
    115 static struct grfvideo_mode *monitor_current = &monitor_def[0];
    116 
    117 /* Patchable maximum pixel clock */
    118 unsigned long cl_maxpixelclock = 86000000;
    119 
    120 /* Console display definition.
    121  *   Default hardcoded text mode.  This grf_cl is set up to
    122  *   use one text mode only, and this is it.  You may use
    123  *   grfconfig to change the mode after boot.
    124  */
    125 /* Console font */
    126 #ifdef KFONT_8X11
    127 #define CIRRUSFONT kernel_font_8x11
    128 #define CIRRUSFONTY 11
    129 #else
    130 #define CIRRUSFONT kernel_font_8x8
    131 #define CIRRUSFONTY 8
    132 #endif
    133 extern unsigned char CIRRUSFONT[];
    134 
    135 struct grfcltext_mode clconsole_mode = {
    136 	{255, "", 25200000, 640, 480, 4, 80, 100, 94, 99, 100, 481, 522, 490,
    137 	498, 522},
    138 	8, CIRRUSFONTY, 80, 480 / CIRRUSFONTY, CIRRUSFONT, 32, 255
    139 };
    140 /* Console colors */
    141 unsigned char clconscolors[3][3] = {	/* background, foreground, hilite */
    142 	{0, 0x40, 0x50}, {152, 152, 152}, {255, 255, 255}
    143 };
    144 
    145 int     cltype = 0;		/* Picasso, Spectrum or Piccolo */
    146 unsigned char pass_toggle;	/* passthru status tracker */
    147 
    148 /* because all 5426-boards have 2 configdev entries, one for
    149  * framebuffer mem and the other for regs, we have to hold onto
    150  * the pointers globally until we match on both.  This and 'cltype'
    151  * are the primary obsticles to multiple board support, but if you
    152  * have multiple boards you have bigger problems than grf_cl.
    153  */
    154 static void *cl_fbaddr = 0;	/* framebuffer */
    155 static void *cl_regaddr = 0;	/* registers */
    156 static int cl_fbsize;		/* framebuffer size */
    157 
    158 /* current sprite info, if you add summport for multiple boards
    159  * make this an array or something
    160  */
    161 struct grf_spriteinfo cl_cursprite;
    162 
    163 /* sprite bitmaps in kernel stack, you'll need to arrayize these too if
    164  * you add multiple board support
    165  */
    166 static unsigned char cl_imageptr[8 * 64], cl_maskptr[8 * 64];
    167 static unsigned char cl_sprred[2], cl_sprgreen[2], cl_sprblue[2];
    168 
    169 /* standard driver stuff */
    170 struct cfattach grfcl_ca = {
    171 	sizeof(struct grf_softc), grfclmatch, grfclattach
    172 };
    173 
    174 struct cfdriver grfcl_cd = {
    175 	NULL, "grfcl", DV_DULL, NULL, 0
    176 };
    177 static struct cfdata *cfdata;
    178 
    179 int
    180 grfclmatch(pdp, match, auxp)
    181 	struct device *pdp;
    182 	void   *match, *auxp;
    183 {
    184 #ifdef CL5426CONSOLE
    185 	struct cfdata *cfp = match;
    186 #endif
    187 	struct zbus_args *zap;
    188 	static int regprod, fbprod;
    189 
    190 	zap = auxp;
    191 
    192 #ifndef CL5426CONSOLE
    193 	if (amiga_realconfig == 0)
    194 		return (0);
    195 #endif
    196 
    197 	/* Grab the first board we encounter as the preferred one.  This will
    198 	 * allow one board to work in a multiple 5426 board system, but not
    199 	 * multiple boards at the same time.  */
    200 	if (cltype == 0) {
    201 		switch (zap->manid) {
    202 		case PICASSO:
    203 			if (zap->prodid != 12 && zap->prodid != 11)
    204 				return (0);
    205 			regprod = 12;
    206 			fbprod = 11;
    207 			break;
    208 		case SPECTRUM:
    209 			if (zap->prodid != 2 && zap->prodid != 1)
    210 				return (0);
    211 			regprod = 2;
    212 			fbprod = 1;
    213 			break;
    214 		case PICCOLO:
    215 			if (zap->prodid != 6 && zap->prodid != 5)
    216 				return (0);
    217 			regprod = 6;
    218 			fbprod = 5;
    219 			break;
    220 		default:
    221 			return (0);
    222 		}
    223 		cltype = zap->manid;
    224 	} else {
    225 		if (cltype != zap->manid) {
    226 			return (0);
    227 		}
    228 	}
    229 
    230 	/* Configure either registers or framebuffer in any order */
    231 	if (zap->prodid == regprod)
    232 		cl_regaddr = zap->va;
    233 	else
    234 		if (zap->prodid == fbprod) {
    235 			cl_fbaddr = zap->va;
    236 			cl_fbsize = zap->size;
    237 		} else
    238 			return (0);
    239 
    240 #ifdef CL5426CONSOLE
    241 	if (amiga_realconfig == 0) {
    242 		cfdata = cfp;
    243 	}
    244 #endif
    245 
    246 	return (1);
    247 }
    248 
    249 void
    250 grfclattach(pdp, dp, auxp)
    251 	struct device *pdp, *dp;
    252 	void   *auxp;
    253 {
    254 	static struct grf_softc congrf;
    255 	struct zbus_args *zap;
    256 	struct grf_softc *gp;
    257 	static char attachflag = 0;
    258 
    259 	zap = auxp;
    260 
    261 	printf("\n");
    262 
    263 	/* make sure both halves have matched */
    264 	if (!cl_regaddr || !cl_fbaddr)
    265 		return;
    266 
    267 	/* do all that messy console/grf stuff */
    268 	if (dp == NULL)
    269 		gp = &congrf;
    270 	else
    271 		gp = (struct grf_softc *) dp;
    272 
    273 	if (dp != NULL && congrf.g_regkva != 0) {
    274 		/*
    275 		 * inited earlier, just copy (not device struct)
    276 		 */
    277 		bcopy(&congrf.g_display, &gp->g_display,
    278 		    (char *) &gp[1] - (char *) &gp->g_display);
    279 	} else {
    280 		gp->g_regkva = (volatile caddr_t) cl_regaddr;
    281 		gp->g_fbkva = (volatile caddr_t) cl_fbaddr;
    282 
    283 		gp->g_unit = GRF_CL5426_UNIT;
    284 		gp->g_mode = cl_mode;
    285 		gp->g_conpri = grfcl_cnprobe();
    286 		gp->g_flags = GF_ALIVE;
    287 
    288 		/* wakeup the board */
    289 		cl_boardinit(gp);
    290 
    291 #ifdef CL5426CONSOLE
    292 		grfcl_iteinit(gp);
    293 		(void) cl_load_mon(gp, &clconsole_mode);
    294 #endif
    295 
    296 	}
    297 
    298 	/*
    299 	 * attach grf (once)
    300 	 */
    301 	if (amiga_config_found(cfdata, &gp->g_device, gp, grfclprint)) {
    302 		attachflag = 1;
    303 		printf("grfcl: %dMB ", cl_fbsize / 0x100000);
    304 		switch (cltype) {
    305 		case PICASSO:
    306 			printf("Picasso II");
    307                         cl_maxpixelclock = 86000000;
    308 			break;
    309 		case SPECTRUM:
    310 			printf("Spectrum");
    311                         cl_maxpixelclock = 90000000;
    312 			break;
    313 		case PICCOLO:
    314 			printf("Piccolo");
    315                         cl_maxpixelclock = 90000000;
    316 			break;
    317 		}
    318 		printf(" being used\n");
    319 #ifdef CL_OVERCLOCK
    320                 cl_maxpixelclock = 115000000;
    321 #endif
    322 	} else {
    323 		if (!attachflag)
    324 			printf("grfcl unattached!!\n");
    325 	}
    326 }
    327 
    328 int
    329 grfclprint(auxp, pnp)
    330 	void   *auxp;
    331 	char   *pnp;
    332 {
    333 	if (pnp)
    334 		printf("ite at %s: ", pnp);
    335 	return (UNCONF);
    336 }
    337 
    338 void
    339 cl_boardinit(gp)
    340 	struct grf_softc *gp;
    341 {
    342 	unsigned char *ba = gp->g_regkva;
    343 	int     x;
    344 
    345 	/* wakeup board and flip passthru OFF */
    346 
    347 	RegWakeup(ba);
    348 	RegOnpass(ba);
    349 
    350 	vgaw(ba, 0x46e8, 0x16);
    351 	vgaw(ba, 0x102, 1);
    352 	vgaw(ba, 0x46e8, 0x0e);
    353 	vgaw(ba, 0x3c3, 1);
    354 
    355 	/* setup initial unchanging parameters */
    356 
    357 	WSeq(ba, SEQ_ID_CLOCKING_MODE, 0x21);	/* 8 dot - display off */
    358 	vgaw(ba, GREG_MISC_OUTPUT_W, 0xe1);	/* mem disable */
    359 
    360 	WGfx(ba, GCT_ID_OFFSET_1, 0xec);	/* magic cookie */
    361 	WSeq(ba, SEQ_ID_UNLOCK_EXT, 0x12);	/* yum! cookies! */
    362 
    363 	WSeq(ba, SEQ_ID_DRAM_CNTL, 0xb0);
    364 	WSeq(ba, SEQ_ID_RESET, 0x03);
    365 	WSeq(ba, SEQ_ID_MAP_MASK, 0xff);
    366 	WSeq(ba, SEQ_ID_CHAR_MAP_SELECT, 0x00);
    367 	WSeq(ba, SEQ_ID_MEMORY_MODE, 0x0e);	/* a or 6? */
    368 	WSeq(ba, SEQ_ID_EXT_SEQ_MODE, (cltype == PICASSO) ? 0x20 : 0x80);
    369 	WSeq(ba, SEQ_ID_EEPROM_CNTL, 0x00);
    370 	WSeq(ba, SEQ_ID_PERF_TUNE, 0x0a);	/* mouse 0a fa */
    371 	WSeq(ba, SEQ_ID_SIG_CNTL, 0x02);
    372 	WSeq(ba, SEQ_ID_CURSOR_ATTR, 0x04);
    373 
    374 	WSeq(ba, SEQ_ID_MCLK_SELECT, 0x22);
    375 
    376 	WCrt(ba, CRT_ID_PRESET_ROW_SCAN, 0x00);
    377 	WCrt(ba, CRT_ID_CURSOR_START, 0x00);
    378 	WCrt(ba, CRT_ID_CURSOR_END, 0x08);
    379 	WCrt(ba, CRT_ID_START_ADDR_HIGH, 0x00);
    380 	WCrt(ba, CRT_ID_START_ADDR_LOW, 0x00);
    381 	WCrt(ba, CRT_ID_CURSOR_LOC_HIGH, 0x00);
    382 	WCrt(ba, CRT_ID_CURSOR_LOC_LOW, 0x00);
    383 
    384 	WCrt(ba, CRT_ID_UNDERLINE_LOC, 0x07);
    385 	WCrt(ba, CRT_ID_MODE_CONTROL, 0xa3);	/* c3 */
    386 	WCrt(ba, CRT_ID_LINE_COMPARE, 0xff);	/* ff */
    387 	WCrt(ba, CRT_ID_EXT_DISP_CNTL, 0x22);
    388 	WSeq(ba, SEQ_ID_CURSOR_STORE, 0x3c);	/* mouse 0x00 */
    389 
    390 	WGfx(ba, GCT_ID_SET_RESET, 0x00);
    391 	WGfx(ba, GCT_ID_ENABLE_SET_RESET, 0x00);
    392 	WGfx(ba, GCT_ID_DATA_ROTATE, 0x00);
    393 	WGfx(ba, GCT_ID_READ_MAP_SELECT, 0x00);
    394 	WGfx(ba, GCT_ID_GRAPHICS_MODE, 0x00);
    395 	WGfx(ba, GCT_ID_MISC, 0x01);
    396 	WGfx(ba, GCT_ID_COLOR_XCARE, 0x0f);
    397 	WGfx(ba, GCT_ID_BITMASK, 0xff);
    398 	WGfx(ba, GCT_ID_MODE_EXT, 0x28);
    399 
    400 	for (x = 0; x < 0x10; x++)
    401 		WAttr(ba, x, x);
    402 	WAttr(ba, ACT_ID_ATTR_MODE_CNTL, 0x01);
    403 	WAttr(ba, ACT_ID_OVERSCAN_COLOR, 0x00);
    404 	WAttr(ba, ACT_ID_COLOR_PLANE_ENA, 0x0f);
    405 	WAttr(ba, ACT_ID_HOR_PEL_PANNING, 0x00);
    406 	WAttr(ba, ACT_ID_COLOR_SELECT, 0x00);
    407 
    408 	delay(200000);
    409 	WAttr(ba, 0x34, 0x00);
    410 	delay(200000);
    411 
    412 	vgaw(ba, VDAC_MASK, 0xff);
    413 	delay(200000);
    414 	vgaw(ba, GREG_MISC_OUTPUT_W, 0xe3);	/* c3 */
    415 
    416 	WGfx(ba, GCT_ID_BLT_STAT_START, 0x40);
    417 	WGfx(ba, GCT_ID_BLT_STAT_START, 0x00);
    418 
    419 	/* colors initially set to greyscale */
    420 
    421 	vgaw(ba, VDAC_ADDRESS_W, 0);
    422 	for (x = 255; x >= 0; x--) {
    423 		vgaw(ba, VDAC_DATA, x);
    424 		vgaw(ba, VDAC_DATA, x);
    425 		vgaw(ba, VDAC_DATA, x);
    426 	}
    427 	/* set sprite bitmap pointers */
    428 	cl_cursprite.image = cl_imageptr;
    429 	cl_cursprite.mask = cl_maskptr;
    430 	cl_cursprite.cmap.red = cl_sprred;
    431 	cl_cursprite.cmap.green = cl_sprgreen;
    432 	cl_cursprite.cmap.blue = cl_sprblue;
    433 }
    434 
    435 
    436 int
    437 cl_getvmode(gp, vm)
    438 	struct grf_softc *gp;
    439 	struct grfvideo_mode *vm;
    440 {
    441 	struct grfvideo_mode *gv;
    442 
    443 #ifdef CL5426CONSOLE
    444 	/* Handle grabbing console mode */
    445 	if (vm->mode_num == 255) {
    446 		bcopy(&clconsole_mode, vm, sizeof(struct grfvideo_mode));
    447 		/* XXX so grfconfig can tell us the correct text dimensions. */
    448 		vm->depth = clconsole_mode.fy;
    449 	} else
    450 #endif
    451         {
    452                 if (vm->mode_num == 0)
    453                         vm->mode_num = (monitor_current - monitor_def) + 1;
    454                 if (vm->mode_num < 1 || vm->mode_num > monitor_def_max)
    455                         return (EINVAL);
    456                 gv = monitor_def + (vm->mode_num - 1);
    457                 if (gv->mode_num == 0)
    458                         return (EINVAL);
    459 
    460                 bcopy(gv, vm, sizeof(struct grfvideo_mode));
    461         }
    462 
    463         /* adjust internal values to pixel values */
    464 
    465         vm->hblank_start *= 8;
    466         vm->hblank_stop *= 8;
    467         vm->hsync_start *= 8;
    468         vm->hsync_stop *= 8;
    469         vm->htotal *= 8;
    470 
    471 	return (0);
    472 }
    473 
    474 
    475 int
    476 cl_setvmode(gp, mode)
    477 	struct grf_softc *gp;
    478 	unsigned mode;
    479 {
    480 	if (!mode || (mode > monitor_def_max) ||
    481 	    monitor_def[mode - 1].mode_num == 0)
    482 		return (EINVAL);
    483 
    484 	monitor_current = monitor_def + (mode - 1);
    485 
    486 	return (0);
    487 }
    488 
    489 #ifndef CL5426CONSOLE
    490 void
    491 cl_off(gp)
    492 	struct grf_softc *gp;
    493 {
    494 	char   *ba = gp->g_regkva;
    495 
    496 	/* we'll put the pass-through on for cc ite and set Full Bandwidth bit
    497 	 * on just in case it didn't work...but then it doesn't matter does
    498 	 * it? =) */
    499 	RegOnpass(ba);
    500 	WSeq(ba, SEQ_ID_CLOCKING_MODE, 0x21);
    501 }
    502 #endif
    503 
    504 int
    505 cl_blank(gp, on)
    506         struct grf_softc *gp;
    507         int *on;
    508 {
    509         WSeq(gp->g_regkva, SEQ_ID_CLOCKING_MODE, *on ? 0x21 : 0x01);
    510         return(0);
    511 }
    512 
    513 /*
    514  * Change the mode of the display.
    515  * Return a UNIX error number or 0 for success.
    516  */
    517 int
    518 cl_mode(gp, cmd, arg, a2, a3)
    519 	register struct grf_softc *gp;
    520 	u_long cmd;
    521 	void *arg;
    522 	u_long a2;
    523 	int a3;
    524 {
    525 	int     error;
    526 
    527 	switch (cmd) {
    528 	case GM_GRFON:
    529 		error = cl_load_mon(gp,
    530 		    (struct grfcltext_mode *) monitor_current) ? 0 : EINVAL;
    531 		return (error);
    532 
    533 	case GM_GRFOFF:
    534 #ifndef CL5426CONSOLE
    535 		cl_off(gp);
    536 #else
    537 		cl_load_mon(gp, &clconsole_mode);
    538 #endif
    539 		return (0);
    540 
    541 	case GM_GRFCONFIG:
    542 		return (0);
    543 
    544 	case GM_GRFGETVMODE:
    545 		return (cl_getvmode(gp, (struct grfvideo_mode *) arg));
    546 
    547 	case GM_GRFSETVMODE:
    548 		error = cl_setvmode(gp, *(unsigned *) arg);
    549 		if (!error && (gp->g_flags & GF_GRFON))
    550 			cl_load_mon(gp,
    551 			    (struct grfcltext_mode *) monitor_current);
    552 		return (error);
    553 
    554 	case GM_GRFGETNUMVM:
    555 		*(int *) arg = monitor_def_max;
    556 		return (0);
    557 
    558 	case GM_GRFIOCTL:
    559 		return (cl_ioctl(gp, a2, arg));
    560 
    561 	default:
    562 		break;
    563 	}
    564 
    565 	return (EINVAL);
    566 }
    567 
    568 int
    569 cl_ioctl(gp, cmd, data)
    570 	register struct grf_softc *gp;
    571 	u_long cmd;
    572 	void   *data;
    573 {
    574 	switch (cmd) {
    575 	case GRFIOCGSPRITEPOS:
    576 		return (cl_getmousepos(gp, (struct grf_position *) data));
    577 
    578 	case GRFIOCSSPRITEPOS:
    579 		return (cl_setmousepos(gp, (struct grf_position *) data));
    580 
    581 	case GRFIOCSSPRITEINF:
    582 		return (cl_setspriteinfo(gp, (struct grf_spriteinfo *) data));
    583 
    584 	case GRFIOCGSPRITEINF:
    585 		return (cl_getspriteinfo(gp, (struct grf_spriteinfo *) data));
    586 
    587 	case GRFIOCGSPRITEMAX:
    588 		return (cl_getspritemax(gp, (struct grf_position *) data));
    589 
    590 	case GRFIOCGETCMAP:
    591 		return (cl_getcmap(gp, (struct grf_colormap *) data));
    592 
    593 	case GRFIOCPUTCMAP:
    594 		return (cl_putcmap(gp, (struct grf_colormap *) data));
    595 
    596 	case GRFIOCBITBLT:
    597 		break;
    598 
    599 	case GRFTOGGLE:
    600 		return (cl_toggle(gp, 0));
    601 
    602 	case GRFIOCSETMON:
    603 		return (cl_setmonitor(gp, (struct grfvideo_mode *) data));
    604 
    605         case GRFIOCBLANK:
    606                 return (cl_blank(gp, (int *)data));
    607 
    608 	}
    609 	return (EINVAL);
    610 }
    611 
    612 int
    613 cl_getmousepos(gp, data)
    614 	struct grf_softc *gp;
    615 	struct grf_position *data;
    616 {
    617 	data->x = cl_cursprite.pos.x;
    618 	data->y = cl_cursprite.pos.y;
    619 	return (0);
    620 }
    621 
    622 void
    623 cl_writesprpos(ba, x, y)
    624 	volatile char *ba;
    625 	short   x;
    626 	short   y;
    627 {
    628 	/* we want to use a 16-bit write to 3c4 so no macros used */
    629 	volatile unsigned char *cwp;
    630         volatile unsigned short *wp;
    631 
    632 	cwp = ba + 0x3c4;
    633         wp = (unsigned short *)cwp;
    634 
    635 	/* don't ask me why, but apparently you can't do a 16-bit write with
    636 	 * x-position like with y-position below (dagge) */
    637         cwp[0] = 0x10 | ((x << 5) & 0xff);
    638         cwp[1] = (x >> 3) & 0xff;
    639 
    640         *wp = 0x1100 | ((y & 7) << 13) | ((y >> 3) & 0xff);
    641 
    642 }
    643 
    644 void
    645 writeshifted(to, shiftx, shifty)
    646 	volatile char *to;
    647 	char    shiftx;
    648 	char    shifty;
    649 {
    650 	register char y;
    651 	unsigned long long *tptr, *iptr, *mptr, line;
    652 
    653 	tptr = (unsigned long long *) to;
    654         iptr = (unsigned long long *) cl_cursprite.image;
    655         mptr = (unsigned long long *) cl_cursprite.mask;
    656 
    657         shiftx = shiftx < 0 ? 0 : shiftx;
    658         shifty = shifty < 0 ? 0 : shifty;
    659 
    660         /* start reading shifty lines down, and
    661          * shift each line in by shiftx
    662          */
    663         for (y = shifty; y < 64; y++) {
    664 
    665                 /* image */
    666                 line = iptr[y];
    667 		*tptr++ = line << shiftx;
    668 
    669                 /* mask */
    670                 line = mptr[y];
    671 		*tptr++ = line << shiftx;
    672 	}
    673 
    674         /* clear the remainder */
    675         for (y = shifty; y > 0; y--) {
    676                 *tptr++ = 0;
    677                 *tptr++ = 0;
    678         }
    679 }
    680 
    681 int
    682 cl_setmousepos(gp, data)
    683 	struct grf_softc *gp;
    684 	struct grf_position *data;
    685 {
    686 	volatile char *ba = gp->g_regkva;
    687         short rx, ry, prx, pry;
    688 #ifdef CL_SHIFTSPRITE
    689 	volatile char *fb = gp->g_fbkva;
    690         volatile char *sprite = fb + (cl_fbsize - 1024);
    691 #endif
    692 
    693         /* no movement */
    694 	if (cl_cursprite.pos.x == data->x && cl_cursprite.pos.y == data->y)
    695 		return (0);
    696 
    697         /* current and previous real coordinates */
    698 	rx = data->x - cl_cursprite.hot.x;
    699 	ry = data->y - cl_cursprite.hot.y;
    700 	prx = cl_cursprite.pos.x - cl_cursprite.hot.x;
    701 	pry = cl_cursprite.pos.y - cl_cursprite.hot.y;
    702 
    703         /* if we are/were on an edge, create (un)shifted bitmap --
    704          * ripped out optimization (not extremely worthwhile,
    705          * and kind of buggy anyhow).
    706          */
    707 #ifdef CL_SHIFTSPRITE
    708         if (rx < 0 || ry < 0 || prx < 0 || pry < 0) {
    709                 writeshifted(sprite, rx < 0 ? -rx : 0, ry < 0 ? -ry : 0);
    710         }
    711 #endif
    712 
    713         /* do movement, save position */
    714         cl_writesprpos(ba, rx < 0 ? 0 : rx, ry < 0 ? 0 : ry);
    715 	cl_cursprite.pos.x = data->x;
    716 	cl_cursprite.pos.y = data->y;
    717 
    718 	return (0);
    719 }
    720 
    721 int
    722 cl_getspriteinfo(gp, data)
    723 	struct grf_softc *gp;
    724 	struct grf_spriteinfo *data;
    725 {
    726 	copyout(&cl_cursprite, data, sizeof(struct grf_spriteinfo));
    727 	copyout(cl_cursprite.image, data->image, 64 * 8);
    728 	copyout(cl_cursprite.mask, data->mask, 64 * 8);
    729 	return (0);
    730 }
    731 
    732 static
    733 int
    734 cl_setspriteinfo(gp, data)
    735 	struct grf_softc *gp;
    736 	struct grf_spriteinfo *data;
    737 {
    738 	volatile unsigned char *ba = gp->g_regkva, *fb = gp->g_fbkva;
    739         volatile char *sprite = fb + (cl_fbsize - 1024);
    740 
    741 	if (data->set & GRFSPRSET_SHAPE) {
    742 
    743                 short dsx, dsy, i;
    744                 unsigned long *di, *dm, *si, *sm;
    745                 unsigned long ssi[128], ssm[128];
    746                 struct grf_position gpos;
    747 
    748 
    749                 /* check for a too large sprite (no clipping!) */
    750                 dsy = data->size.y;
    751                 dsx = data->size.x;
    752                 if (dsy > 64 || dsx > 64)
    753                         return(EINVAL);
    754 
    755                 /* prepare destination */
    756                 di = (unsigned long *)cl_cursprite.image;
    757                 dm = (unsigned long *)cl_cursprite.mask;
    758                 cl_memset((unsigned char *)di, 0, 8*64);
    759                 cl_memset((unsigned char *)dm, 0, 8*64);
    760 
    761                 /* two alternatives:  64 across, then it's
    762                  * the same format we use, just copy.  Otherwise,
    763                  * copy into tmp buf and recopy skipping the
    764                  * unused 32 bits.
    765                  */
    766                 if ((dsx - 1) / 32) {
    767                         copyin(data->image, di, 8 * dsy);
    768                         copyin(data->mask, dm, 8 * dsy);
    769                 } else {
    770                         si = ssi; sm = ssm;
    771                         copyin(data->image, si, 4 * dsy);
    772                         copyin(data->mask, sm, 4 * dsy);
    773                         for (i = 0; i < dsy; i++) {
    774                                 *di = *si++;
    775                                 *dm = *sm++;
    776                                 di += 2;
    777                                 dm += 2;
    778                         }
    779                 }
    780 
    781                 /* set size */
    782 		cl_cursprite.size.x = data->size.x;
    783 		cl_cursprite.size.y = data->size.y;
    784 
    785                 /* forcably load into board */
    786                 gpos.x = cl_cursprite.pos.x;
    787                 gpos.y = cl_cursprite.pos.y;
    788                 cl_cursprite.pos.x = -1;
    789                 cl_cursprite.pos.y = -1;
    790                 writeshifted(sprite, 0, 0);
    791                 cl_setmousepos(gp, &gpos);
    792 
    793 	}
    794 	if (data->set & GRFSPRSET_HOT) {
    795 
    796 		cl_cursprite.hot = data->hot;
    797 
    798 	}
    799 	if (data->set & GRFSPRSET_CMAP) {
    800 
    801 		u_char  red[2], green[2], blue[2];
    802 
    803 		copyin(data->cmap.red, red, 2);
    804 		copyin(data->cmap.green, green, 2);
    805 		copyin(data->cmap.blue, blue, 2);
    806 		bcopy(red, cl_cursprite.cmap.red, 2);
    807 		bcopy(green, cl_cursprite.cmap.green, 2);
    808 		bcopy(blue, cl_cursprite.cmap.blue, 2);
    809 
    810                 /* enable and load colors 256 & 257 */
    811 		WSeq(ba, SEQ_ID_CURSOR_ATTR, 0x06);
    812 
    813                 /* 256 */
    814 		vgaw(ba, VDAC_ADDRESS_W, 0x00);
    815 		if (cltype == PICASSO) {
    816 			vgaw(ba, VDAC_DATA, (u_char) (red[0] >> 2));
    817 			vgaw(ba, VDAC_DATA, (u_char) (green[0] >> 2));
    818 			vgaw(ba, VDAC_DATA, (u_char) (blue[0] >> 2));
    819 		} else {
    820 			vgaw(ba, VDAC_DATA, (u_char) (blue[0] >> 2));
    821 			vgaw(ba, VDAC_DATA, (u_char) (green[0] >> 2));
    822 			vgaw(ba, VDAC_DATA, (u_char) (red[0] >> 2));
    823 		}
    824 
    825                 /* 257 */
    826 		vgaw(ba, VDAC_ADDRESS_W, 0x0f);
    827 		if (cltype == PICASSO) {
    828 			vgaw(ba, VDAC_DATA, (u_char) (red[1] >> 2));
    829 			vgaw(ba, VDAC_DATA, (u_char) (green[1] >> 2));
    830 			vgaw(ba, VDAC_DATA, (u_char) (blue[1] >> 2));
    831 		} else {
    832 			vgaw(ba, VDAC_DATA, (u_char) (blue[1] >> 2));
    833 			vgaw(ba, VDAC_DATA, (u_char) (green[1] >> 2));
    834 			vgaw(ba, VDAC_DATA, (u_char) (red[1] >> 2));
    835 		}
    836 
    837                 /* turn on/off sprite */
    838 		if (cl_cursprite.enable) {
    839 			WSeq(ba, SEQ_ID_CURSOR_ATTR, 0x05);
    840 		} else {
    841 			WSeq(ba, SEQ_ID_CURSOR_ATTR, 0x04);
    842 		}
    843 
    844 	}
    845 	if (data->set & GRFSPRSET_ENABLE) {
    846 
    847 		if (data->enable == 1) {
    848 			WSeq(ba, SEQ_ID_CURSOR_ATTR, 0x05);
    849 			cl_cursprite.enable = 1;
    850 		} else {
    851 			WSeq(ba, SEQ_ID_CURSOR_ATTR, 0x04);
    852 			cl_cursprite.enable = 0;
    853 		}
    854 
    855 	}
    856 	if (data->set & GRFSPRSET_POS) {
    857 
    858                 /* force placement */
    859                 cl_cursprite.pos.x = -1;
    860                 cl_cursprite.pos.y = -1;
    861 
    862                 /* do it */
    863                 cl_setmousepos(gp, &data->pos);
    864 
    865 	}
    866 	return (0);
    867 }
    868 
    869 static
    870 int
    871 cl_getspritemax(gp, data)
    872 	struct grf_softc *gp;
    873 	struct grf_position *data;
    874 {
    875 	if (gp->g_display.gd_planes == 24)
    876 		return (EINVAL);
    877 	data->x = 64;
    878 	data->y = 64;
    879 	return (0);
    880 }
    881 
    882 int
    883 cl_setmonitor(gp, gv)
    884 	struct grf_softc *gp;
    885 	struct grfvideo_mode *gv;
    886 {
    887 	struct grfvideo_mode *md;
    888 
    889         if (!cl_mondefok(gv))
    890                 return(EINVAL);
    891 
    892 #ifdef CL5426CONSOLE
    893 	/* handle interactive setting of console mode */
    894 	if (gv->mode_num == 255) {
    895 		bcopy(gv, &clconsole_mode.gv, sizeof(struct grfvideo_mode));
    896                 clconsole_mode.gv.hblank_start /= 8;
    897                 clconsole_mode.gv.hblank_stop /= 8;
    898                 clconsole_mode.gv.hsync_start /= 8;
    899                 clconsole_mode.gv.hsync_stop /= 8;
    900                 clconsole_mode.gv.htotal /= 8;
    901 		clconsole_mode.rows = gv->disp_height / clconsole_mode.fy;
    902 		clconsole_mode.cols = gv->disp_width / clconsole_mode.fx;
    903 		if (!(gp->g_flags & GF_GRFON))
    904 			cl_load_mon(gp, &clconsole_mode);
    905 		ite_reinit(gp->g_itedev);
    906 		return (0);
    907 	}
    908 #endif
    909 
    910 	md = monitor_def + (gv->mode_num - 1);
    911 	bcopy(gv, md, sizeof(struct grfvideo_mode));
    912 
    913         /* adjust pixel oriented values to internal rep. */
    914 
    915         md->hblank_start /= 8;
    916         md->hblank_stop /= 8;
    917         md->hsync_start /= 8;
    918         md->hsync_stop /= 8;
    919         md->htotal /= 8;
    920 
    921 	return (0);
    922 }
    923 
    924 int
    925 cl_getcmap(gfp, cmap)
    926 	struct grf_softc *gfp;
    927 	struct grf_colormap *cmap;
    928 {
    929 	volatile unsigned char *ba;
    930 	u_char  red[256], green[256], blue[256], *rp, *gp, *bp;
    931 	short   x;
    932 	int     error;
    933 
    934 	if (cmap->count == 0 || cmap->index >= 256)
    935 		return 0;
    936 
    937 	if (cmap->index + cmap->count > 256)
    938 		cmap->count = 256 - cmap->index;
    939 
    940 	ba = gfp->g_regkva;
    941 	/* first read colors out of the chip, then copyout to userspace */
    942 	vgaw(ba, VDAC_ADDRESS_R, cmap->index);
    943 	x = cmap->count - 1;
    944 
    945 /* Some sort 'o Magic. Spectrum has some changes on the board to speed
    946  * up 15 and 16Bit modes. They can access these modes with easy-to-programm
    947  * rgbrgbrgb instead of rrrgggbbb. Side effect: when in 8Bit mode, rgb
    948  * is swapped to bgr. I wonder if we need to check for 8Bit though, ill
    949  */
    950 
    951 	switch (cltype) {
    952 	case SPECTRUM:
    953 	case PICCOLO:
    954 		rp = blue + cmap->index;
    955 		gp = green + cmap->index;
    956 		bp = red + cmap->index;
    957 		break;
    958 	case PICASSO:
    959 		rp = red + cmap->index;
    960 		gp = green + cmap->index;
    961 		bp = blue + cmap->index;
    962 		break;
    963 	default:
    964 		rp = gp = bp = 0;
    965 		break;
    966 	}
    967 
    968 	do {
    969 		*rp++ = vgar(ba, VDAC_DATA) << 2;
    970 		*gp++ = vgar(ba, VDAC_DATA) << 2;
    971 		*bp++ = vgar(ba, VDAC_DATA) << 2;
    972 	} while (x-- > 0);
    973 
    974 	if (!(error = copyout(red + cmap->index, cmap->red, cmap->count))
    975 	    && !(error = copyout(green + cmap->index, cmap->green, cmap->count))
    976 	    && !(error = copyout(blue + cmap->index, cmap->blue, cmap->count)))
    977 		return (0);
    978 
    979 	return (error);
    980 }
    981 
    982 int
    983 cl_putcmap(gfp, cmap)
    984 	struct grf_softc *gfp;
    985 	struct grf_colormap *cmap;
    986 {
    987 	volatile unsigned char *ba;
    988 	u_char  red[256], green[256], blue[256], *rp, *gp, *bp;
    989 	short   x;
    990 	int     error;
    991 
    992 	if (cmap->count == 0 || cmap->index >= 256)
    993 		return (0);
    994 
    995 	if (cmap->index + cmap->count > 256)
    996 		cmap->count = 256 - cmap->index;
    997 
    998 	/* first copy the colors into kernelspace */
    999 	if (!(error = copyin(cmap->red, red + cmap->index, cmap->count))
   1000 	    && !(error = copyin(cmap->green, green + cmap->index, cmap->count))
   1001 	    && !(error = copyin(cmap->blue, blue + cmap->index, cmap->count))) {
   1002 		ba = gfp->g_regkva;
   1003 		vgaw(ba, VDAC_ADDRESS_W, cmap->index);
   1004 		x = cmap->count - 1;
   1005 
   1006 		switch (cltype) {
   1007 		case SPECTRUM:
   1008 		case PICCOLO:
   1009 			rp = blue + cmap->index;
   1010 			gp = green + cmap->index;
   1011 			bp = red + cmap->index;
   1012 			break;
   1013 		case PICASSO:
   1014 			rp = red + cmap->index;
   1015 			gp = green + cmap->index;
   1016 			bp = blue + cmap->index;
   1017 			break;
   1018 		default:
   1019 			rp = gp = bp = 0;
   1020 			break;
   1021 		}
   1022 
   1023 		do {
   1024 			vgaw(ba, VDAC_DATA, *rp++ >> 2);
   1025 			vgaw(ba, VDAC_DATA, *gp++ >> 2);
   1026 			vgaw(ba, VDAC_DATA, *bp++ >> 2);
   1027 		} while (x-- > 0);
   1028 		return (0);
   1029 	} else
   1030 		return (error);
   1031 }
   1032 
   1033 
   1034 int
   1035 cl_toggle(gp, wopp)
   1036 	struct grf_softc *gp;
   1037 	unsigned short wopp;	/* don't need that one yet, ill */
   1038 {
   1039 	volatile unsigned char *ba;
   1040 
   1041 	ba = gp->g_regkva;
   1042 
   1043 	if (pass_toggle) {
   1044 		RegOffpass(ba);
   1045 	} else {
   1046 		/* This was in the original.. is it needed? */
   1047 		if (cltype == PICASSO || cltype == PICCOLO)
   1048 			RegWakeup(ba);
   1049 		RegOnpass(ba);
   1050 	}
   1051 	return (0);
   1052 }
   1053 
   1054 static void
   1055 CompFQ(fq, num, denom)
   1056 	u_int   fq;
   1057 	u_char *num;
   1058 	u_char *denom;
   1059 {
   1060 #define OSC     14318180
   1061 /* OK, here's what we're doing here:
   1062  *
   1063  *             OSC * NUMERATOR
   1064  *      VCLK = -------------------  Hz
   1065  *             DENOMINATOR * (1+P)
   1066  *
   1067  * so we're given VCLK and we should give out some useful
   1068  * values....
   1069  *
   1070  * NUMERATOR is 7 bits wide
   1071  * DENOMINATOR is 5 bits wide with bit P in the same char as bit 0.
   1072  *
   1073  * We run through all the possible combinations and
   1074  * return the values which deviate the least from the chosen frequency.
   1075  *
   1076  */
   1077 #define OSC     14318180
   1078 #define count(n,d,p)    ((OSC * n)/(d * (1+p)))
   1079 
   1080 	unsigned char n, d, p, minn, mind, minp = 0;
   1081 	unsigned long err, minerr;
   1082 
   1083 /*
   1084 numer = 0x00 - 0x7f
   1085 denom = 0x00 - 0x1f (1) 0x20 - 0x3e (even)
   1086 */
   1087 
   1088 	/* find lowest error in 6144 iterations. */
   1089 	minerr = fq;
   1090 	minn = 0;
   1091 	mind = 0;
   1092 	p = 0;
   1093 
   1094 	for (d = 1; d < 0x20; d++) {
   1095 		for (n = 1; n < 0x80; n++) {
   1096 			err = abs(count(n, d, p) - fq);
   1097 			if (err < minerr) {
   1098 				minerr = err;
   1099 				minn = n;
   1100 				mind = d;
   1101 				minp = p;
   1102 			}
   1103 		}
   1104 		if (d == 0x1f && p == 0) {
   1105 			p = 1;
   1106 			d = 0x0f;
   1107 		}
   1108 	}
   1109 
   1110 	*num = minn;
   1111 	*denom = (mind << 1) | minp;
   1112 	if (minerr > 500000)
   1113 		printf("Warning: CompFQ minimum error = %ld\n", minerr);
   1114 	return;
   1115 }
   1116 
   1117 int
   1118 cl_mondefok(gv)
   1119 	struct grfvideo_mode *gv;
   1120 {
   1121         unsigned long maxpix;
   1122 
   1123 	if (gv->mode_num < 1 || gv->mode_num > monitor_def_max)
   1124                 if (gv->mode_num != 255 || gv->depth != 4)
   1125                         return(0);
   1126 
   1127 	switch (gv->depth) {
   1128 	case 4:
   1129                 if (gv->mode_num != 255)
   1130                         return(0);
   1131 	case 1:
   1132 	case 8:
   1133                 maxpix = cl_maxpixelclock;
   1134                 break;
   1135 	case 15:
   1136 	case 16:
   1137                 maxpix = cl_maxpixelclock - (cl_maxpixelclock / 3);
   1138                 break;
   1139 	case 24:
   1140                 maxpix = cl_maxpixelclock / 3;
   1141                 break;
   1142 	default:
   1143 		return (0);
   1144 	}
   1145         if (gv->pixel_clock > maxpix)
   1146                 return (0);
   1147         return (1);
   1148 }
   1149 
   1150 int
   1151 cl_load_mon(gp, md)
   1152 	struct grf_softc *gp;
   1153 	struct grfcltext_mode *md;
   1154 {
   1155 	struct grfvideo_mode *gv;
   1156 	struct grfinfo *gi;
   1157 	volatile unsigned char *ba;
   1158 	volatile caddr_t fb;
   1159 	unsigned char num0, denom0;
   1160 	unsigned short HT, HDE, HBS, HBE, HSS, HSE, VDE, VBS, VBE, VSS,
   1161 	        VSE, VT;
   1162 	char    LACE, DBLSCAN, TEXT;
   1163 	unsigned short clkdiv;
   1164 	int     uplim, lowlim;
   1165 
   1166 	/* identity */
   1167 	gv = &md->gv;
   1168 	TEXT = (gv->depth == 4);
   1169 
   1170 	if (!cl_mondefok(gv)) {
   1171 		printf("mondef not ok\n");
   1172 		return (0);
   1173 	}
   1174 	ba = gp->g_regkva;
   1175 	fb = gp->g_fbkva;
   1176 
   1177 	/* provide all needed information in grf device-independant locations */
   1178 	gp->g_data = (caddr_t) gv;
   1179 	gi = &gp->g_display;
   1180 	gi->gd_regaddr = (caddr_t) ztwopa(ba);
   1181 	gi->gd_regsize = 64 * 1024;
   1182 	gi->gd_fbaddr = (caddr_t) kvtop(fb);
   1183 	gi->gd_fbsize = cl_fbsize;
   1184 	gi->gd_colors = 1 << gv->depth;
   1185 	gi->gd_planes = gv->depth;
   1186 	gi->gd_fbwidth = gv->disp_width;
   1187 	gi->gd_fbheight = gv->disp_height;
   1188 	gi->gd_fbx = 0;
   1189 	gi->gd_fby = 0;
   1190 	if (TEXT) {
   1191 		gi->gd_dwidth = md->fx * md->cols;
   1192 		gi->gd_dheight = md->fy * md->rows;
   1193 	} else {
   1194 		gi->gd_dwidth = gv->disp_width;
   1195 		gi->gd_dheight = gv->disp_height;
   1196 	}
   1197 	gi->gd_dx = 0;
   1198 	gi->gd_dy = 0;
   1199 
   1200 	/* get display mode parameters */
   1201 
   1202 	HBS = gv->hblank_start;
   1203 	HBE = gv->hblank_stop;
   1204 	HSS = gv->hsync_start;
   1205 	HSE = gv->hsync_stop;
   1206 	HT = gv->htotal;
   1207 	VBS = gv->vblank_start;
   1208 	VSS = gv->vsync_start;
   1209 	VSE = gv->vsync_stop;
   1210 	VBE = gv->vblank_stop;
   1211 	VT = gv->vtotal;
   1212 
   1213 	if (TEXT)
   1214 		HDE = ((gv->disp_width + md->fx - 1) / md->fx) - 1;
   1215 	else
   1216 		HDE = (gv->disp_width + 3) / 8 - 1;	/* HBS; */
   1217 	VDE = gv->disp_height - 1;
   1218 
   1219 	/* figure out whether lace or dblscan is needed */
   1220 
   1221 	uplim = gv->disp_height + (gv->disp_height / 4);
   1222 	lowlim = gv->disp_height - (gv->disp_height / 4);
   1223 	LACE = (((VT * 2) > lowlim) && ((VT * 2) < uplim)) ? 1 : 0;
   1224 	DBLSCAN = (((VT / 2) > lowlim) && ((VT / 2) < uplim)) ? 1 : 0;
   1225 
   1226 	/* adjustments */
   1227 
   1228 	if (LACE)
   1229 		VDE /= 2;
   1230 
   1231 	WSeq(ba, SEQ_ID_MEMORY_MODE, (TEXT || (gv->depth == 1)) ? 0x06 : 0x0e);
   1232 	WSeq(ba, SEQ_ID_DRAM_CNTL, (TEXT || (gv->depth == 1)) ? 0x90 : 0xb0);
   1233 	WGfx(ba, GCT_ID_READ_MAP_SELECT, 0x00);
   1234 	WSeq(ba, SEQ_ID_MAP_MASK, (gv->depth == 1) ? 0x01 : 0xff);
   1235 	WSeq(ba, SEQ_ID_CHAR_MAP_SELECT, 0x00);
   1236 
   1237 	/* Set clock */
   1238 
   1239 	CompFQ((gv->depth == 24) ? gv->pixel_clock * 3 : gv->pixel_clock,
   1240 	    &num0, &denom0);
   1241 	WSeq(ba, SEQ_ID_VCLK_0_NUM, num0);
   1242 	WSeq(ba, SEQ_ID_VCLK_0_DENOM, denom0);
   1243 
   1244 	/* load display parameters into board */
   1245 
   1246 	WCrt(ba, CRT_ID_HOR_TOTAL, HT);
   1247 	WCrt(ba, CRT_ID_HOR_DISP_ENA_END, ((HDE >= HBS) ? HBS - 1 : HDE));
   1248 	WCrt(ba, CRT_ID_START_HOR_BLANK, HBS);
   1249 	WCrt(ba, CRT_ID_END_HOR_BLANK, (HBE & 0x1f) | 0x80);	/* | 0x80? */
   1250 	WCrt(ba, CRT_ID_START_HOR_RETR, HSS);
   1251 	WCrt(ba, CRT_ID_END_HOR_RETR,
   1252 	    (HSE & 0x1f) |
   1253 	    ((HBE & 0x20) ? 0x80 : 0x00));
   1254 	WCrt(ba, CRT_ID_VER_TOTAL, VT);
   1255 	WCrt(ba, CRT_ID_OVERFLOW,
   1256 	    0x10 |
   1257 	    ((VT & 0x100) ? 0x01 : 0x00) |
   1258 	    ((VDE & 0x100) ? 0x02 : 0x00) |
   1259 	    ((VSS & 0x100) ? 0x04 : 0x00) |
   1260 	    ((VBS & 0x100) ? 0x08 : 0x00) |
   1261 	    ((VT & 0x200) ? 0x20 : 0x00) |
   1262 	    ((VDE & 0x200) ? 0x40 : 0x00) |
   1263 	    ((VSS & 0x200) ? 0x80 : 0x00));
   1264 
   1265 
   1266 	WCrt(ba, CRT_ID_CHAR_HEIGHT,
   1267 	    0x40 |		/* TEXT ? 0x00 ??? */
   1268 	    (DBLSCAN ? 0x80 : 0x00) |
   1269 	    ((VBS & 0x200) ? 0x20 : 0x00) |
   1270 	    (TEXT ? ((md->fy - 1) & 0x1f) : 0x00));
   1271 	WCrt(ba, CRT_ID_MODE_CONTROL,
   1272 	    ((TEXT || (gv->depth == 1)) ? 0xc3 : 0xa3));
   1273 
   1274 	/* text cursor */
   1275 
   1276 	if (TEXT) {
   1277 #if CL_ULCURSOR
   1278 		WCrt(ba, CRT_ID_CURSOR_START, (md->fy & 0x1f) - 2);
   1279 		WCrt(ba, CRT_ID_CURSOR_END, (md->fy & 0x1f) - 1);
   1280 #else
   1281 		WCrt(ba, CRT_ID_CURSOR_START, 0x00);
   1282 		WCrt(ba, CRT_ID_CURSOR_END, md->fy & 0x1f);
   1283 #endif
   1284 		WCrt(ba, CRT_ID_UNDERLINE_LOC, (md->fy - 1) & 0x1f);
   1285 
   1286 		WCrt(ba, CRT_ID_CURSOR_LOC_HIGH, 0x00);
   1287 		WCrt(ba, CRT_ID_CURSOR_LOC_LOW, 0x00);
   1288 	}
   1289 	WCrt(ba, CRT_ID_START_ADDR_HIGH, 0x00);
   1290 	WCrt(ba, CRT_ID_START_ADDR_LOW, 0x00);
   1291 
   1292 	WCrt(ba, CRT_ID_START_VER_RETR, VSS);
   1293 	WCrt(ba, CRT_ID_END_VER_RETR, (VSE & 0x0f) | 0x30);
   1294 	WCrt(ba, CRT_ID_VER_DISP_ENA_END, VDE);
   1295 	WCrt(ba, CRT_ID_START_VER_BLANK, VBS);
   1296 	WCrt(ba, CRT_ID_END_VER_BLANK, VBE);
   1297 
   1298 	WCrt(ba, CRT_ID_LINE_COMPARE, 0xff);
   1299 	WCrt(ba, CRT_ID_LACE_END, HT / 2);	/* MW/16 */
   1300 	WCrt(ba, CRT_ID_LACE_CNTL,
   1301 	    (LACE ? 0x01 : 0x00) |
   1302 	    ((HBE & 0x40) ? 0x10 : 0x00) |
   1303 	    ((HBE & 0x80) ? 0x20 : 0x00) |
   1304 	    ((VBE & 0x100) ? 0x40 : 0x00) |
   1305 	    ((VBE & 0x200) ? 0x80 : 0x00));
   1306 
   1307 	/* depth dependent stuff */
   1308 
   1309 	switch (gv->depth) {
   1310 	case 1:
   1311 	case 4:
   1312 	case 8:
   1313 		clkdiv = 0;
   1314 		break;
   1315 	case 15:
   1316 	case 16:
   1317 		clkdiv = 3;
   1318 		break;
   1319 	case 24:
   1320 		clkdiv = 2;
   1321 		break;
   1322 	default:
   1323 		clkdiv = 0;
   1324 		panic("grfcl: Unsuported depth: %i", gv->depth);
   1325 		break;
   1326 	}
   1327 
   1328 	WGfx(ba, GCT_ID_GRAPHICS_MODE,
   1329 	    ((TEXT || (gv->depth == 1)) ? 0x00 : 0x40));
   1330 	WGfx(ba, GCT_ID_MISC, (TEXT ? 0x04 : 0x01));
   1331 
   1332 	WSeq(ba, SEQ_ID_EXT_SEQ_MODE,
   1333 	    ((TEXT || (gv->depth == 1)) ? 0x00 : 0x01) |
   1334 	    ((cltype == PICASSO) ? 0x20 : 0x80) |
   1335 	    (clkdiv << 1));
   1336 
   1337 	delay(200000);
   1338 
   1339 	/* write 0x00 to VDAC_MASK before accessing HDR this helps
   1340 	   sometimes, out of "secret" application note (crest) */
   1341 	vgaw(ba, VDAC_MASK, 0);
   1342 	delay(200000);
   1343 	/* reset HDR "magic" access counter (crest) */
   1344 	vgar(ba, VDAC_ADDRESS);
   1345 
   1346 	delay(200000);
   1347 	vgar(ba, VDAC_MASK);
   1348 	delay(200000);
   1349 	vgar(ba, VDAC_MASK);
   1350 	delay(200000);
   1351 	vgar(ba, VDAC_MASK);
   1352 	delay(200000);
   1353 	vgar(ba, VDAC_MASK);
   1354 	delay(200000);
   1355 	switch (gv->depth) {
   1356 	case 1:
   1357 	case 4:		/* text */
   1358 		vgaw(ba, VDAC_MASK, 0);
   1359 		HDE = gv->disp_width / 16;
   1360 		break;
   1361 	case 8:
   1362 		vgaw(ba, VDAC_MASK, 0);
   1363 		HDE = gv->disp_width / 8;
   1364 		break;
   1365 	case 15:
   1366 		vgaw(ba, VDAC_MASK, 0xd0);
   1367 		HDE = gv->disp_width / 4;
   1368 		break;
   1369 	case 16:
   1370 		vgaw(ba, VDAC_MASK, 0xc1);
   1371 		HDE = gv->disp_width / 4;
   1372 		break;
   1373 	case 24:
   1374 		vgaw(ba, VDAC_MASK, 0xc5);
   1375 		HDE = (gv->disp_width / 8) * 3;
   1376 		break;
   1377 	}
   1378 	delay(20000);
   1379 
   1380 	/* reset HDR "magic" access counter (crest) */
   1381 	vgar(ba, VDAC_ADDRESS);
   1382 	delay(200000);
   1383 	/* then enable all bit in VDAC_MASK afterwards (crest) */
   1384 	vgaw(ba, VDAC_MASK, 0xff);
   1385 	delay(20000);
   1386 
   1387 	WCrt(ba, CRT_ID_OFFSET, HDE);
   1388 	WCrt(ba, CRT_ID_EXT_DISP_CNTL,
   1389 	    ((TEXT && gv->pixel_clock > 29000000) ? 0x40 : 0x00) |
   1390 	    0x22 |
   1391 	    ((HDE > 0xff) ? 0x10 : 0x00));	/* text? */
   1392 
   1393 	delay(200000);
   1394 	WAttr(ba, ACT_ID_ATTR_MODE_CNTL, (TEXT ? 0x0a : 0x01));
   1395 	delay(200000);
   1396 	WAttr(ba, 0x20 | ACT_ID_COLOR_PLANE_ENA,
   1397 	    (gv->depth == 1) ? 0x01 : 0x0f);
   1398 	delay(200000);
   1399 
   1400 	/* text initialization */
   1401 
   1402 	if (TEXT) {
   1403 		cl_inittextmode(gp);
   1404 	}
   1405 	WSeq(ba, SEQ_ID_CURSOR_ATTR, 0x14);
   1406 	WSeq(ba, SEQ_ID_CLOCKING_MODE, 0x01);
   1407 
   1408 	/* Pass-through */
   1409 
   1410 	RegOffpass(ba);
   1411 
   1412 	return (1);
   1413 }
   1414 
   1415 void
   1416 cl_inittextmode(gp)
   1417 	struct grf_softc *gp;
   1418 {
   1419 	struct grfcltext_mode *tm = (struct grfcltext_mode *) gp->g_data;
   1420 	volatile unsigned char *ba = gp->g_regkva;
   1421 	unsigned char *fb = gp->g_fbkva;
   1422 	unsigned char *c, *f, y;
   1423 	unsigned short z;
   1424 
   1425 
   1426 	/* load text font into beginning of display memory. Each character
   1427 	 * cell is 32 bytes long (enough for 4 planes) */
   1428 
   1429 	SetTextPlane(ba, 0x02);
   1430         cl_memset(fb, 0, 256 * 32);
   1431 	c = (unsigned char *) (fb) + (32 * tm->fdstart);
   1432 	f = tm->fdata;
   1433 	for (z = tm->fdstart; z <= tm->fdend; z++, c += (32 - tm->fy))
   1434 		for (y = 0; y < tm->fy; y++)
   1435 			*c++ = *f++;
   1436 
   1437 	/* clear out text/attr planes (three screens worth) */
   1438 
   1439 	SetTextPlane(ba, 0x01);
   1440 	cl_memset(fb, 0x07, tm->cols * tm->rows * 3);
   1441 	SetTextPlane(ba, 0x00);
   1442 	cl_memset(fb, 0x20, tm->cols * tm->rows * 3);
   1443 
   1444 	/* print out a little init msg */
   1445 
   1446 	c = (unsigned char *) (fb) + (tm->cols - 16);
   1447 	strcpy(c, "CIRRUS");
   1448 	c[6] = 0x20;
   1449 
   1450 	/* set colors (B&W) */
   1451 
   1452 
   1453 	vgaw(ba, VDAC_ADDRESS_W, 0);
   1454 	for (z = 0; z < 256; z++) {
   1455 		unsigned char r, g, b;
   1456 
   1457 		y = (z & 1) ? ((z > 7) ? 2 : 1) : 0;
   1458 
   1459 		if (cltype == PICASSO) {
   1460 			r = clconscolors[y][0];
   1461 			g = clconscolors[y][1];
   1462 			b = clconscolors[y][2];
   1463 		} else {
   1464 			b = clconscolors[y][0];
   1465 			g = clconscolors[y][1];
   1466 			r = clconscolors[y][2];
   1467 		}
   1468 		vgaw(ba, VDAC_DATA, r >> 2);
   1469 		vgaw(ba, VDAC_DATA, g >> 2);
   1470 		vgaw(ba, VDAC_DATA, b >> 2);
   1471 	}
   1472 }
   1473 
   1474 void
   1475 cl_memset(d, c, l)
   1476 	unsigned char *d;
   1477 	unsigned char c;
   1478 	int     l;
   1479 {
   1480 	for (; l > 0; l--)
   1481 		*d++ = c;
   1482 }
   1483 #endif /* NGRFCL */
   1484