
#ifdef GRF_CL5426

/*
 * Graphics routines for Cirrus CL GD 5426 boards,
 */

/* changed:
  Added WPassP() for Picasso, value for WPassP() _MUST_ be (casted to) BYTE
  changed onpass=0x1 initalisation for Picasso
  see also required changes in grf_clreg.h 
  10/11/94 ill (markus@techfak.uni-bielefeld.de)
  Added global bah_toggle flag
  Added cl_toggle() for IOCTL for external programms to toggle between ECS 
  and Cirrus display using pass thru
  Added GRFTOGGLE IOCTL to make cl_toggle() available. See also grf.c
  15/11/94 ill
  Added busy_delay() to make DAC working on fast machine. 16/11/94 ill
  01/15/95 crest
  busy-waits inserted, crest 15.1.1995 should fix "white-screen" problem 
  01/30/95 ill
  Tried to implement a trick to fix the "black-screen" problem.
  This problem is caused by the Zorro-to-ISA interface on the Picasso
  in (Z2-)040 Systems such as A2000/040. The Little/Big-Endian strikes 
  back. The trick is to add 0xffff to the address of the palette registers 
  to get them on the swapped endian. ill
*/

#include <sys/param.h>
#include <sys/errno.h>
#include <sys/ioctl.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <machine/cpu.h>
#include <dev/cons.h>
#include <amiga/amiga/device.h>
#include <amiga/dev/grfioctl.h>
#include <amiga/dev/grfvar.h>
#include <amiga/dev/grf_clreg.h>
#include <amiga/dev/ztwobusvar.h>
#include <amiga/dev/zthreebusvar.h>

int cl_mondefok __P((struct MonDef *));
static void cl_boardwakeup();
static void CompFQ __P((u_int fq, u_char *num, u_char *denom));
int cl_load_mon __P((struct grf_softc *gp, struct MonDef *md));
int cl_getvmode __P((struct grf_softc *gp, struct grfvideo_mode *vm));
int cl_setvmode __P((struct grf_softc *gp, unsigned int mode, int txtonly));

#define  grfcl_cnprobe()   CN_DEAD

extern unsigned char kernel_font_8x8_width, kernel_font_8x8_height;
extern unsigned char kernel_font_8x8_lo, kernel_font_8x8_hi;
extern unsigned char kernel_font_8x8[];
#ifdef KFONT_8X11
extern unsigned char kernel_font_8x11_width, kernel_font_8x11_height;
extern unsigned char kernel_font_8x11_lo, kernel_font_8x11_hi;
extern unsigned char kernel_font_8x11[];
#endif

void busy_delay(int);

/* This code offers low-level routines to access Cirrus Cl GD 5426
 * graphics-boards from within NetBSD for the Amiga.
 * No warranties for any kind of function at all - this
 * code may crash your hardware and scratch your harddisk.  Use at your
 * own risk.  Freely distributable.
 *
 *
 * Modified for Cirrus CL GD 5426 from
 * Lutz Vieweg's retina driver by Kari Mettinen 08/94
 *
 * Thanks to Village Tronic Marketing Gmbh for providing me with
 * a Picasso-II board.
 * Thanks for Integrated Electronics Oy Ab for providing me with
 * Cirrus CL GD 542x family documentation.
 *
 */



#define F_DBL 1
#define F_LACE 2
#define F_CLKDIV2 4


#define MEM_SIZE(gp)	((gp)->g_display.gd_fbsize)

/* -------------- START OF CODE -------------- */

/* Convert big-endian long into little-endian long. */

#define M2I(val)                                                     \
	asm volatile (" rorw #8,%0   ;                               \
	                swap %0      ;                               \
	                rorw #8,%0   ; " : "=d" (val) : "0" (val));

#define M2INS(val)                                                   \
	asm volatile (" rorw #8,%0   ;                               \
	                swap %0      ;                               \
	                rorw #8,%0   ;                               \
 			swap %0	     ; " : "=d" (val) : "0" (val));

#define ACM_OFFSET	(0x00b00000)
#define LM_OFFSET	(0x00c00000)



static unsigned char	cltype;	/* Picasso, Spectrum or Piccolo */
static unsigned char	memseg;	/* 0x20 for Picasso, 0x80 for Spectrum
				 * and Piccolo
				 */
static unsigned char	wakepass;/* char to be written to pass-through
				 * for wakeup.
				 */
static unsigned char	bah_toggle;/* flag to toggle between ECS and Cirrus 
				 * can we use wakepass for that, hm ? ill
				 */
static unsigned char	onpass;	/* char to be written to pass-through
				 * for turning 5426-display off.
				 */
static unsigned char	offpass;/* char to be written to pass-through
				 * for turning 5426-display on (letting
				 * 5426 display through)
				 */ 
static void *cl_fbaddr = 0;	 /* because all 5426-boards have 2 configdev
				  * entries, on for framebuffer mem and
				  * the other for regs, we'll store fb address
				  * here for putting it to grf_softc
				  */
static void *cl_regaddr = 0;
static int cl_fbsize;

static unsigned char clrops[] = {
	0x00, 0x05, 0x09, 0x0d, 0x50, 0x06, 0x59, 0x6d,
	0x90, 0x95, 0x0b, 0xad, 0xd0, 0xd6, 0xda, 0x0e
};

static unsigned char optab[] = {
	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0
};
static char optabs[] = {
	   0,   -1,   -1,   -1,   -1,    0,   -1,   -1,
	  -1,   -1,    0,   -1,   -1,   -1,   -1,    0
};

void
CLDisableHWC(gp)
	struct grf_softc *gp;
{
	volatile void *ba = gp->g_regkva;

/* Bit 3 of Cursor attributes register selects the size,
 * 1 = 64x64
 * 0 = 32x32
 * Bit 0 (en/dis)ables hardware cursor
 * 1 = on
 * 0 = off
 */ 
	WSeq(ba, SEQ_ID_CURSOR_ATTR, 0x04);
}

void
CLSetupHWC(gp, col1, col2, hsx, hsy, data)
	struct grf_softc *gp;
	unsigned char col1;
	unsigned col2;
	unsigned char hsx;
	unsigned char hsy;
	const unsigned long *data;
{
/*	Cursor data must be in the upper 16K of display data,
 *	with ((64/8*64) * 2) offsets. Offset is selected in
 *	SR13 (SEQ_ID_CURSOR_STORE) bits 5:2, giving us 16
 *	different cursor bitmaps. Offset 0 is the lowest
 *	sprite pattern.
 */

	volatile unsigned char *ba = gp->g_regkva;
	unsigned long *c = (unsigned long *)(gp->g_fbkva + MEM_SIZE(gp) - 16*1024);
	const unsigned long *s = data;
	struct MonDef *MonitorDef = (struct MonDef *) gp->g_data;
	short x = (((64*64/8)*2 / (4*4)) - 1);
    short *seqbase;


	/* color 256 is cursor background and 257 is cursor foreground,
	 * these colors are accessed by setting SR12[1] to 1, then color
	 * 256 is set using index 0x0, and color 257 using index 0x0f
	 */
#ifdef 0

/*	col1 is an unsigned char and col2 is an unsigned int?
        I'd like to know in what form these color are given...
*/
	WSeq(ba, SEQ_ID_CURSOR_COLOR1, col1);
	WSeq(ba, SEQ_ID_CURSOR_COLOR0, col2);
#endif
	/* cursor location is set by a 16-bit write to offset 3c4,
	 * where index-byte contains low 3 bits of the cursor location.
	 * indexes with low 5 bits being 0x10 are interpreted as
	 * X-locations, if low 5 bits of index is 0x11, they are interpreted
	 * as Y-positions.
	 */

	seqbase = (unsigned short *)(ba + (0x3c4));

	/* put cursor to 0,0 */

	*seqbase = 0x1000;
	*seqbase = 0x1100;

	/* there's no hw support for hotspot :(. can't move cursor to negative
	 * position...no good for X. 
	 */

	WSeq(ba, SEQ_ID_CURSOR_STORE, 0x00);
}


void
CLBitBlit (gp, gbb)
	struct grf_softc *gp;
	struct grf_bitblt * gbb;
{
	/* Blit patterns must be longword-aligned, max pattern memory
	 * size is 128 bytes in 16-bit modes. Well reserve the first 128
	 * bytes before cursor-memory for that. Patterns are 8x8 pixels.
	 * Patterns can also be color-expanded. If we have a mask on gbb,
	 * well have to do 2 blits, one for masking and one for the actual
	 * rop. (mask not supported yet because of that)
	 */

	volatile unsigned char *ba = gp->g_regkva;
	volatile unsigned char *lm = gp->g_fbkva + ((MEM_SIZE(gp) - (1024*16)) - 128);
	volatile unsigned long *acm = (unsigned long *) (ba + ACM_OFFSET);
	const struct MonDef *md = (struct MonDef *) gp->g_data;
	unsigned char mod;
	/* mask pattern as 8x8 bitmap to pt */
	{
		unsigned long * pt = (unsigned long *) (lm);
		unsigned long tmp  = gbb->mask | ((unsigned long)gbb->mask << 16);
		*pt = tmp;
		*(pt+1) = tmp;
	}
	mod = 0x00;

	/* wait for possible blit to finish before poking any regs */

	while((RGfx(ba, GCT_ID_BLT_STAT_START)) & 0x01);

	{
		unsigned long dst = (gbb->dst_x + gbb->dst_y * md->TX);


		unsigned long src = (gbb->src_x + gbb->src_y * md->TX);

		/* blit direction */
		if ((gbb->dst_x + gbb->dst_y * md->TX) >= 
			(gbb->src_x + gbb->src_y)) 
			mod = 0x01;
		else
			mod = 0x00;


		WGfx(ba, GCT_ID_BLT_MODE, mod);

		WGfx(ba, GCT_ID_SRC_START_LOW, (src & 0xff));
		src>>=8;
		WGfx(ba, GCT_ID_SRC_START_MID, (src & 0xff));
		src>>=8;
		WGfx(ba, GCT_ID_SRC_START_HIGH, (src & 0x1f));

		WGfx(ba, GCT_ID_DST_START_LOW, (dst & 0xff));
		dst>>=8;
		WGfx(ba, GCT_ID_DST_START_MID, (dst & 0xff));
		dst>>=8;
		WGfx(ba, GCT_ID_DST_START_HIGH, (dst & 0x1f));

		WGfx(ba, GCT_ID_SRC_PITCH_LOW, ((md->TX) & 0xff));
		WGfx(ba, GCT_ID_SRC_PITCH_HIGH, (((md->TX) >> 8) & 0x0f));		
		WGfx(ba, GCT_ID_DST_PITCH_LOW, ((md->TX) & 0xff));
		WGfx(ba, GCT_ID_DST_PITCH_HIGH, (((md->TX) >> 8) & 0x0f));		

	}

	WGfx(ba, GCT_ID_BLT_WIDTH_LOW, (gbb->w & 0xff));
	WGfx(ba, GCT_ID_BLT_WIDTH_HIGH, ((gbb->w >>8) & 0x07));
	WGfx(ba, GCT_ID_BLT_HEIGHT_LOW, (gbb->h & 0xff));
	WGfx(ba, GCT_ID_BLT_HEIGHT_HIGH, ((gbb->h >> 8) * 0x03));
	
	WGfx(ba, GCT_ID_BLT_ROP, clrops[gbb->op]);

	/* start blit and wait it to finish */
	WGfx(ba, GCT_ID_BLT_STAT_START, 0x02);
	while((RGfx(ba, GCT_ID_BLT_STAT_START)) & 0x01);

}

void
CL16BitBlit (gp, gbb)
	struct grf_softc *gp;
	struct grf_bitblt * gbb;
{
	/* same as 8-bit blit, but addresses need to be multiplied by 2 */

	gbb->src_x *= 2;
	gbb->src_y *= 2;
	gbb->dst_x *= 2;
	gbb->dst_y *= 2;
	gbb->w *= 2;
	CLBitBlit(gp, gbb);
}

void
CLLoadPalette (gp, pal, firstcol, colors)
	struct grf_softc *gp;
	unsigned char * pal;
	unsigned char firstcol;
	unsigned char colors;
{
	volatile unsigned char *ba = gp->g_regkva;

	if (colors == 0)
		return;

	vgaw(ba, VDAC_ADDRESS_W, firstcol);

	{

		short x = colors-1;
		const unsigned char * col = pal;
		do {

			vgaw(ba, VDAC_DATA, (*col++ >> 2));
			vgaw(ba, VDAC_DATA, (*col++ >> 2));
			vgaw(ba, VDAC_DATA, (*col++ >> 2));

		} while (x-- > 0);

	}
}

void
CLSetPalette (gp, colornum, red, green, blue)
	struct grf_softc *gp;
	unsigned char colornum;
	unsigned char red, green, blue;
{
	volatile unsigned char *ba = gp->g_regkva;

	vgaw(ba, VDAC_ADDRESS_W, colornum);

	vgaw(ba, VDAC_DATA, (red >> 2));
	vgaw(ba, VDAC_DATA, (green >> 2));
	vgaw(ba, VDAC_DATA, (blue >> 2));

}

/* XXXXXXXXX !! */
static unsigned short xpan;
static unsigned short ypan;

void
CLSetPanning (gp, xoff, yoff)
	struct grf_softc *gp;
	unsigned short xoff, yoff;
{
	volatile unsigned char *ba = gp->g_regkva;
	const struct MonDef * md = (struct MonDef *) gp->g_data;
	unsigned long off;
	unsigned char tmp;


	xpan = xoff;
	ypan = yoff;


	off = ((yoff * md->TX)) + (xoff);


	WCrt(ba, CRT_ID_START_ADDR_LOW, ((unsigned char)off));

	off >>= 8;

	WCrt(ba, CRT_ID_START_ADDR_HIGH, ((unsigned char)off));

	off >>= 8;

	tmp=RCrt(ba, CRT_ID_EXT_DISP_CNTL);
	tmp &= 0xf2;
	if(off & 0x01)tmp |= 0x01;
	if(off & 0x02)tmp |= 0x04;
	if(off & 0x03)tmp |= 0x08;
	WCrt(ba, CRT_ID_EXT_DISP_CNTL,tmp);
}

void
CLSetHWCloc (gp, x, y)
	struct grf_softc *gp;
	unsigned short x, y;
{
	volatile unsigned char *ba = gp->g_regkva;
	const struct MonDef *md = (struct MonDef *) gp->g_data;
	volatile unsigned char *seqbase = ba + (SEQ_ADDRESS/2),xlow,ylow;

	if (x < xpan)
		CLSetPanning(gp, x, ypan);

	if (x >= (xpan+md->MW))
		CLSetPanning(gp, (1 + x - md->MW) , ypan);

	if (y < ypan)
		CLSetPanning(gp, xpan, y);

	if (y >= (ypan+md->MH))
		CLSetPanning(gp, xpan, (1 + y - md->MH));

	x -= xpan;
	y -= ypan;

	xlow = x & 0x07;
	ylow = y & 0x07;
	x>>=3;
	y>>=3;
	*seqbase = 0x1000 | (xlow << 13) | (x & 0xff);
	*seqbase = 0x1100 | (ylow << 13) | (y & 0xff);
}




static void
CompFQ(fq,num,denom)
u_int fq;
u_char *num;
u_char *denom;
{
#define OSC	14318180
/* OK, here's what we're doing here:
 * 
 *             OSC * NUMERATOR
 *	VCLK = -------------------  Hz
 *             DENOMINATOR * (1+P)
 *
 * so we're given VCLK and we should give out some useful
 * values....
 *
 * NUMERATOR is 6 bits wide
 * DENOMINATOR is 5 bits wide with bit P in the same char as bit 0.
 *
 * We'll start with as big a denominator as possible, and then start lowering
 * numerator until we get close. If error is acceptable we'll return values,
 * if not, we'll change denominator. Acceptable error is IMHO about .5MHz...
 */
#define count(n,d,p)	((OSC * n)/(d * (1+p)))
#define FQ_ERROR	500000

	unsigned long vclk, ovclk;
        u_char numerator ,denominator , p, tmp;

	numerator = 0x3f;
	denominator = 0x1f;
	p=1;



	/* first lower denominator low enough */

	if((count(numerator,denominator,p))<fq)p=0;
	while((count(numerator,denominator,p))<fq)denominator--;

	/* then lower numerator until we get close */
	while(denominator){
	    ovclk = count(numerator,denominator,p);
	    while((vclk = count(numerator,denominator,p))
		 && numerator){

		if(abs(fq-ovclk)<abs(fq-vclk)){
			numerator++;
			if((fq-ovclk)<FQ_ERROR){
				*num = numerator;
				tmp = ((denominator << 1) | p);
				*denom = tmp;
				return;
			}
			break;
		}
		ovclk = vclk;
		numerator--;
	    }
	    if(!numerator){
		/* biiiiiig trouble...*/
		panic("grfcl: CompFQ numerator 0");
	    }
	    denominator--;
	}
	/* biiiiiig trouble */
	panic("grfcl: CompFQ denominator 0");
}

int
cl_mondefok(mdp)
	struct MonDef *mdp;
{
	/* max safe frequency is a bit over 80MHz,
	 * modifying this is dangerous 
	 */

  /* Has been commented out by ScottE, but I believe we leave it for
     now. ill
  */
	if(mdp->FQ>81000000)
		return(0);

	switch(mdp->DEP) {
	case 8:
		return(1);
#ifdef IBETTHISISNOTDEFINED
	case 4:
		if (mdp->FX == 4 || (mdp->FX >= 7 && mdp->FX <= 16))
			return(1);
		/*FALLTHROUGH*/
#endif
	default:
		return(0);
	}
}


void memset(d,v,count)
char *d;
char v;
int count;
{
  int temp=0;
  char *tptr=d;
  while(count>temp++){
    *tptr++=v;
  }
}


int
set5426(regbase,membase,md,num,denom)
volatile unsigned char *regbase;
volatile unsigned char *membase;
struct MonDef *md;
unsigned char num;
unsigned char denom;
{
    float vclk0,vclk1,vclk2,vclk3;
    unsigned short ht,hde,hbs,hbe,hss,hse,vt,vde,vss,vse,vbs,vbe,vpitch,x,y;
    volatile unsigned char *dx,tmp;
    volatile unsigned short *dw;
    int temp;
#ifdef 0
    ht = 170 -5;
    hde = 128 -1;
    hbs = 129;
    hbe = 165;
    hss = 134;
    hse = 144;

    vt = 850 -2;
    vss = 800;
    vse = 810;
    vde = 768;
    vpitch = 128;
    vbs = 780;
    vbe = 830;
#endif
    ht = md->HT -5;
    hde = (md->MW+3)/8 -1;
    hbs = md->HBS;
    hbe = md->HBE;
    hss = md->HSS;
    hse = md->HSE;
    vt = md->VT -2;
    vss = md->VSS;
    vse = md->VSE;
    vde = md->MH -1;
    vbs = md->VBS;
    vbe = md->VBE;

   /* changes to support lace, 15/11/94 Dagge */

    if(md->FLG & F_LACE){
      vt/=2;
      vss/=2;
      vse/=2;
      vde/=2;
      vbs/=2;
      vbe/=2;
    }

    vpitch = hde;/* for autoscrolling screens md->TX */
    if(membase && regbase){

/* Someone deleted these lines here, ill*/

/********************************
*********************************
#ifdef SPECTRUM
        dx = regbase + 0x8000;
        *dx =0x1f;                flip the board on (hit this only ONCE per boot!!!)
        temp=0;
         while(temp++<1000000); 
         dx = regbase + 0x8000; 
         dx =0x4f;                keep the amiga display for now
         temp=0;
         while(temp++<1000000);
#endif 
********************************
*******************************/


        /* wake up the board, (this should be done already,
	 * but it doesn't hurt to do it again 
	 */

        /* I wonder why we do this twice..., ill */

        dx = regbase + 0x46e8;
        *dx = 0x16;
        dx = regbase + 0x102;
        *dx = 1;
        dx = regbase + 0x46e8;
        *dx = 0x0e;

        /*dx = regbase + 0x4ae8;
        *dx = 0xff;*/


        /* video subsystem enable */

        dx = regbase + 0x3c3;
        *dx = 1;


        /* turn display off while we're poking dangerous
         * stuff andset dotclock to 8
         */

        dx = regbase + 0x3c4;
        *dx = 1;
        dx++;
        *dx = 0x21;            /* EGS driver uses 0x01 here */

        /* set sync polarities and set CRTC IO to color
         * and enable Display memory (Clock select later)
         */

        dx = regbase + 0x3c2;
        *dx = 0xe3;
        dx++;
        *dx = 0xe1;

        dx = regbase + 0x3da;
        *dx = 0x00;     /* FC */


        /* set offset register 1 to 0xec to enable extensions...? */

        dx = regbase + 0x3ce;
        *dx = 0x0a;
        dx++;
        *dx = 0xec;

        /* enable extensions */

        dx = regbase + 0x3c4;
        *dx = 0x06;
        dx++;
        *dx = 0x12;

        /* dram control */

        dx--;
        *dx = 0x0f;
        dx++;
        *dx = 0xb0;


        dx = regbase + 0x3c4;
        dw = (unsigned short *)dx;

        *dw = 0x0003;
        *dw = 0x02ff;
        *dw = 0x0300;
        *dw = 0x040e;

        if(cltype != PICASSO)
                *dw = 0x0781;  /* EGS: Whas Vmembase = 0x81? */
        else
                *dw = 0x0721;

        *dw = 0x0800;
        *dw = 0x1000;
        *dw = 0x1100;
        *dw = 0x1214;   /* border color no. 258 */
        *dw = 0x1300;
        *dw = 0x160a;
        *dw = 0x1802;
        *dw = 0x1f22;   /* MCLK frequency of 60MHz */



        dx = regbase + 0x3d4;
        dw = (unsigned short *)dx;
        *dw = 0x1400;   /* doubleword mode */

        *dw = 0x17e3;   /* mode control */

        *dw = 0x1800;   /* line compare = 00 */

        /*dw = 0x1b80;*/        /* enable vbe and hbe extensions */


        dx = regbase + 0x3ce;
        dw = (unsigned short *)dx;
        *dw = 0x0000;
        *dw = 0x0100;
        *dw = 0x0200;
        *dw = 0x0300;
        *dw = 0x0400;
        *dw = 0x0500;
        *dw = 0x0601;
        *dw = 0x070f;
        *dw = 0x08ff;
        *dw = 0x0900;   /* offsetregister 0 */
        *dw = 0x0b28;
        *dw = 0x0cff;
        *dw = 0x0dff;
        *dw = 0x0e00;
        *dw = 0x1000;
        *dw = 0x1100;
        *dw = 0x3104;   /* reset blitter */

        /* get AR toggle to tmp */

        dx = regbase + 0x3d4;
        *dx = 0x24;
        dx++;
        tmp = *dx;
        dx = regbase + 0x3c0;

        if(tmp & 0x80)tmp = *dx;
        tmp=0;
        while(tmp<0x10){
                *dx = tmp++;
                *dx = 0;
        }
        *dx = 0x10;
        *dx = 1;        /* gfx mode */
        *dx = 0x11;
        *dx = 0x00;     /* overscan color */
        *dx = 0x12;
        *dx = 0x0f;     /* enable all 4 planes */
        *dx = 0x13;
        *dx = 0;        /* no Pixel panning */
        *dx = 0x14;     /* index 14 with video enable bit set */
        *dx = 0x00;


        dx = regbase + 0x3c6;
/*      *dx = 0xff;     /* pixel mask */


        /* set HDR */
/* busy-waits inserted, crest 15.1.1995 should fix "white-screen" problem */

	tmp = *dx;
busy_delay(10000);
	tmp = *dx;
busy_delay(10000);
	tmp = *dx;
busy_delay(10000);
	tmp = *dx;
busy_delay(10000);
	*dx = 0x00;

	*dx = 0xff;

        /* set VCLK0 values to 80 MHz*/

        dx = regbase + 0x3c4;
        *dx = 0;
        dx++;
        *dx = 3;
        dx--;
        *dx = 0x0b;
        dx++;
        *dx = num;
        dx--;
        *dx = 0x1b;
        dx++;
        *dx = denom;  /* 0x42; */

        /* reset blitter (again)*/

        dx = regbase + 0x3ce;
        dw = (unsigned short *)dx;
        *dw = 0x3160;
        *dw = 0x3100;

        /* select VCLK0 to be used */

        dx = regbase + 0x3c2;
        *dx = 0xe3;

        /* now set up CRT for 64KHz 1024x768x8 display */

        /* set 256-colormode to GR5 */

        dx = regbase + 0x3ce;
        dw = (unsigned short *)dx;
        *dx = 0x05;
        dx++;
        *dx = 0x40;



        /* CR stuff */

        dx = regbase + 0x3d4;
        *dx = 0x11;
        dx++;
        *dx &= 0x7f;   /* free CR0-CR7 */

        dx--;
        *dx = 0x00;
        dx++;
        *dx = ht;       /* HTOTAL */
        dx--;

        *dx = 0x01;
        dx++;
        *dx = hde;
        dx--;

        *dx = 0x02;
        dx++;

        *dx = hbs;
        dx--;

        *dx = 0x03;
        dx++;
        *dx = 0x00 | (hbe & 0x1f);
        if(hbe & 0x20)
                tmp = 0x80;
        else
                tmp = 0;
        dx--;

        *dx = 0x04;
        dx++;
        *dx = hss;
        dx--;

        *dx = 0x05;
        dx++;
        *dx = (hse & 0x1f) | tmp;
        dx--;

        *dx = 0x06;
        dx++;
        *dx = vt & 0xff;
        dx--;

        *dx = 0x10;
        dx++;
        *dx = vss & 0xff;
        dx--;

        *dx = 0x11;
        dx++;
        tmp = *dx;
        tmp = (tmp & 0xf0) | (0x0f & vse);
        *dx = tmp;
        dx--;

        *dx = 0x12;
        dx++;
        *dx = 0xff & vde;
        dx--;

        *dx = 0x13;
        dx++;

        *dx = 0xff & vpitch;
        dx--;

        *dx = 0x15;
        dx++;
        *dx = 0xff & vbs;
        dx--;

        *dx = 0x16;
        dx++;
        *dx = 0xff & vbe;
        dx--;

        tmp = 0x10;
        if(vt & 0x0100)tmp |= 1;
        if(vt & 0x0200)tmp |= 0x20;
        if(vss & 0x0100)tmp |= 0x04;
        if(vss & 0x0200)tmp |= 0x80;
        if(vde & 0x0100)tmp |= 0x02;
        if(vde & 0x0200)tmp |= 0x40;
        if(vbs & 0x0100)tmp |= 0x08;
        *dx = 0x07;
        dx++;

        *dx = tmp;
        dx--;

        tmp = 0;
        *dx = 0x09;
        dx++;
        tmp = *dx;
        tmp &= 0xdf;
        if(vbs & 0x0200)tmp |= 0x20;
        *dx = tmp;
        dx--;

        *dx = 0x1a;
        dx++;
        tmp = 0;
        if(hbe & 0xc0)tmp |= (hbe & 0xc0)>>2;
        if(vbe & 0x0300)tmp |= (vbe & 0x0300)>>2;
        /* changes to support lace, 15/11/94 Dagge */
        if(md->FLG & F_LACE) tmp |= 0x01;
        *dx = tmp;
        dx--;

        *dx = 0x1b;
        dx++;

        tmp = 0x22;
        if(vpitch & 0x0100)tmp |= 0x10;
        *dx = tmp;
        dx--;

        dw = (unsigned short *)dx;
        *dw = 0x0c00;
        *dw = 0x0d00;

        /* put display on */

        dx = regbase + 0x3c4;
        *dx = 1;
        dx++;
        *dx = 0x01;
        dx = regbase + 0x3c0;
        *dx = 0x20;
/** Ezy turn display on (was commented out) */
/*********************/
        dx = regbase + 0x8000;   /*  use the spectrum's display */

/* Added by Michael Illgner. Looks like the register needs other
   intialisation for regbase. -MiL
   Changed that the delay is only used by Piccolo. -ill 
*/
        if (cltype == PICCOLO) 
        {
         *dx |= 0x20; 
         delay(10000); 
        }
        else *dx = 0x6f;

        /* set up CLUT */

        dx = regbase + 0x3c8;
        temp=0;
        *dx = 0;
        dx++;
        while(temp<256){
                *dx = 0;
                *dx = 0;
                *dx = 0;
                temp++;
        }
#ifdef DEBUG
        /* and now set color 4 to red */
        dx--;
        *dx = 3;
        dx++;
	*dx = 0xff;
	*dx = 0x00;
	*dx = 0xff;
        *dx = 0xff;
        *dx = 0x00;
        *dx = 0x00;
        *dx = 0x00;
        *dx = 0xff;
        *dx = 0x00;
        *dx = 0x00;
        *dx = 0x00;
        *dx = 0xff;

        x=256;
        y=0;
        memset(membase,3,1024*1024);      /* was a clear :-) */
        while(x<256+512){
                y=182;
                while(y<182+384){
                        *(membase+(x)+(y*1024))=4;
                        y++;
                }
                x++;
                temp = 0;
        }
        x=0;
        y=0;
        while(x<1024 && y<768){
                *(membase+x+(y*1024)) = 5;
                x++;y++;
        }
        x=1024;y=0;
        while(x>0 && y<768){
                *(membase + x + (y*1024)) = 5;
                x--;y++;
        }
        y=768;x=0;
        while(x<1024 && y>0){
                *(membase+x+(y*1024)) = 6;
                x++;y--;
        }
        x=1024;y=768;
        while(x>0 && y>0){
                *(membase + x + (y*1024)) = 6;
                x--;y--;
	      }
#endif /* DEBUG */
      }

/** Ezy -- a little delay to see what we have :-) **/
    /*for(temp=0;temp<1000000;temp++);*/

/* Ezy, what for is above loop? I don't see any reason to hold it, ill */

/* Someone deleted these lines here, SPECTRUM is defined in 
   grf_clreg.h, ill */

/**********************************
************************************
#ifdef SPECTRUM
   dx = regbase + 0x8000;
   *dx =0x4f;                         back to the amiga display
   temp=0;
   while(temp++<1000000);
#endif  
*************************************
**********************************/


out:


    return 1;
}

void busy_delay(poke)
int poke;
{
 int foo;
 
 foo=0;
 while(foo++ <poke);

}


int
cl_load_mon(gp, md)
	struct grf_softc *gp;
	struct MonDef *md;
{
	struct grfinfo *gi = &gp->g_display;
	volatile unsigned char *ba;
	volatile unsigned char *fb;
	unsigned short FW, clksel, HDE, VDE;
	unsigned short *c, z,tmp;
	const unsigned char *f;
	u_char num0,denom0,tmpc,tmpuchar;
	unsigned char clkdiv=0;	/* default 8-bit */
	volatile unsigned char *ar,*aw;

  /* changes to support lace, 15/11/94 Dagge */
  unsigned short VBS,VBE,VSS,VSE,VT;

	ba = gp->g_regkva;
	fb = gp->g_fbkva;

	aw=ba+0x3c0;
  if(cltype==PICASSO)   ar=ba+(0x3c1+0xffff); 
  else ar=ba+0x3c1;

	if(!cl_mondefok(md)){
	  printf("mondef not ok\n");
	  return(0);
	}

	CompFQ(md->FQ,&num0,&denom0);
	set5426(ba,fb,md,num0,denom0); 



	/* count values for VCLK numerator and denumerator base on VCLK */
	CompFQ(md->FQ,&num0,&denom0);

	/* provide all needed information in grf device-independant
	 * locations */
	gp->g_data 		= (caddr_t) md;
	gi->gd_regaddr	 	= (caddr_t) ztwopa (ba);
	gi->gd_regsize		= 64*1024;
	gi->gd_fbaddr		= (caddr_t) kvtop (fb);
	gi->gd_fbsize		= cl_fbsize;

	gi->gd_colors		= 1 << md->DEP;
	gi->gd_planes		= md->DEP;


	if (md->DEP == 4) {
	        printf("grfcl warning: depth 4 not supported\n");
		gi->gd_fbwidth	= md->MW;
		gi->gd_fbheight	= md->MH;
		gi->gd_fbx	= 0;
		gi->gd_fby	= 0;
		gi->gd_dwidth	= md->TX * md->FX;
		gi->gd_dheight	= md->TY * md->FY;
		gi->gd_dx	= 0;
		gi->gd_dy	= 0;
	} else {
		gi->gd_fbwidth	= md->TX;
		gi->gd_fbheight	= md->TY;
		gi->gd_fbx	= 0;
		gi->gd_fby	= 0;
		gi->gd_dwidth	= md->MW;
		gi->gd_dheight	= md->MH;
		gi->gd_dx	= 0;
		gi->gd_dy	= 0;
	}

	FW =0;
	if (md->DEP == 4) {		/* XXX some text-mode! not supported yet */
		switch (md->FX) {
		case 4:
			FW = 0;
			break;
		case 7:
			FW = 1;
			break;
		case 8:
			FW = 2;
			break;
		case 9:
			FW = 3;
			break;
		case 10:
			FW = 4;
			break;
		case 11:
			FW = 5;
			break;
		case 12:
			FW = 6;
			break;
		case 13:
			FW = 7;
			break;
		case 14:
			FW = 8;
			break;
		case 15:
			FW = 9;
			break;
		case 16:
			FW = 11;
			break;
		default:
			return(0);
			break;
		}
	}

	if (md->DEP == 4)
		HDE = (md->MW+md->FX-1)/md->FX;
	else if (md->DEP == 8)
		HDE = (md->MW+3)/8;
	else if (md->DEP == 16){
		HDE = (md->MW*2+3)/4;
		clkdiv = 3;
	}
	VDE = md->MH-1;

  /* changes to support lace, 15/10/94 Dagge */

  VBS = md->VBS;
  VSS = md->VSS;
  VSE = md->VSE;
  VBE = md->VBE;
  VT = md->VT;

  if(md->FLG & F_LACE){
    VT /= 2;
    VDE /= 2;
    VBS /= 2; 
    VSS /= 2;
    VSE /= 2;
    VBE /= 2;
  } 


	clksel = 0;
	
	vgaw(ba, GREG_MISC_OUTPUT_W, 0xe3 | ((clksel & 3) * 0x04));
	vgaw(ba, GREG_FEATURE_CONTROL_W, 0x00);
	vgar(ba, 0x3da);
	WSeq(ba, SEQ_ID_RESET, 0x00);
	WSeq(ba, SEQ_ID_RESET, 0x03);

	WSeq(ba, SEQ_ID_CLOCKING_MODE, 0x01);/* was 0x01*/

	WSeq(ba, SEQ_ID_MAP_MASK, 0xff);
	WSeq(ba, SEQ_ID_CHAR_MAP_SELECT, 0x00);
	WSeq(ba, SEQ_ID_MEMORY_MODE, 0x0e);	/* 0x06? */

	/* general SR stuff here */
	WSeq(ba, SEQ_ID_UNLOCK_EXT, 0x12);
	WSeq(ba, SEQ_ID_EXT_SEQ_MODE, (0x01 | 
		((cltype == PICASSO) ? 0x20: 0x80) |
		(clkdiv << 1)));
	WSeq(ba, SEQ_ID_EEPROM_CNTL, 0x00);

	/* I guess these 2 could actually be used for something =)*/

	WSeq(ba, SEQ_ID_SCRATCH_0, 0x00);
	WSeq(ba, SEQ_ID_SCRATCH_1, 0x00);

	WSeq(ba, SEQ_ID_VCLK_0_NUM, num0);

	/* even though we only use vclk0, we'll set other clocks too,
	 * to 25MHz
	 */

	WSeq(ba, SEQ_ID_VCLK_1_NUM, 0x66);
	WSeq(ba, SEQ_ID_VCLK_2_NUM, 0x66);
	WSeq(ba, SEQ_ID_VCLK_3_NUM, 0x66);

	WSeq(ba, SEQ_ID_DRAM_CNTL, 0xb0);
	WSeq(ba, SEQ_ID_CURSOR_X, 0x00);
	WSeq(ba, SEQ_ID_CURSOR_Y, 0x00);
	WSeq(ba, SEQ_ID_CURSOR_ATTR, 0x04);
	WSeq(ba, SEQ_ID_CURSOR_STORE, 0x00);
	WSeq(ba, SEQ_ID_SCRATCH_2, 0x00);
	WSeq(ba, SEQ_ID_SCRATCH_3, 0x00);
	WSeq(ba, SEQ_ID_PERF_TUNE, 0x0a);

	/* somebody make a tuner =), bit meanings: iiwwtttt
	 * ii = RDY Delay for I/O
	 * ww = RDY Delay for Memory Write
	 * tttt = FIFO Demand Threshold
	 */

	WSeq(ba, SEQ_ID_CONF_RBACK, 0x00);
	WSeq(ba, SEQ_ID_SIG_CNTL, 0x02);
	WSeq(ba, SEQ_ID_SIG_RES_LOW, 0x00);
	WSeq(ba, SEQ_ID_SIG_RES_HIGH, 0x00);
	WSeq(ba, SEQ_ID_VCLK_0_DENOM, denom0);
	WSeq(ba, SEQ_ID_VCLK_1_DENOM, 0x3b);
	WSeq(ba, SEQ_ID_VCLK_2_DENOM, 0x3b);
	WSeq(ba, SEQ_ID_VCLK_3_DENOM, 0x3b);
	WSeq(ba, SEQ_ID_MCLK_SELECT, 0x22);


	WCrt(ba, CRT_ID_END_VER_RETR, (VSE & 0x0f) | 0x20);
	WCrt(ba, CRT_ID_HOR_TOTAL, ((md->HT - 5) & 0xff));
	WCrt(ba, CRT_ID_HOR_DISP_ENA_END, (HDE-1)   & 0xff);
	WCrt(ba, CRT_ID_START_HOR_BLANK, md->HBS   & 0xff);
	WCrt(ba, CRT_ID_END_HOR_BLANK, ((md->HBS-(md->HBE-md->HBS))   & 0x1f) | 0x80);

	WCrt(ba, CRT_ID_START_HOR_RETR, md->HSS   & 0xff);
	WCrt(ba, CRT_ID_END_HOR_RETR,
	    ((md->HSE & 0x1f)   |
	    (((md->HBE & 0x20)/ 0x20) * 0x80)));
	WCrt(ba, CRT_ID_VER_TOTAL,  ((md->VT-2)  & 0xff));
	WCrt(ba, CRT_ID_OVERFLOW,
      (((VSS & 0x200) / 0x200) * 0x80) |
      (((VDE     & 0x200) / 0x200) * 0x40) |
      ((((VT-2)  & 0x200) / 0x200) * 0x20) |
      0x10                               |
      (((VBS & 0x100) / 0x100) * 8)    |
      (((VSS & 0x100) / 0x100) * 4)    |
      (((VDE     & 0x100) / 0x100) * 2)    |
      (((VT-2)  & 0x100) / 0x100));
	WCrt(ba, CRT_ID_PRESET_ROW_SCAN, 0x00);

	if (md->DEP == 4) {
		WCrt(ba, CRT_ID_CHAR_HEIGHT,
		    /*((md->FLG & MDF_DBL)/ MDF_DBL * 0x80) |*/
		    0x40 |
		    ((md->VBS & 0x200)/0x200*0x20) |
		    ((md->FY-1) & 0x1f));
	} else {
		WCrt(ba, CRT_ID_CHAR_HEIGHT,
		    /*((md->FLG & MDF_DBL)/ MDF_DBL * 0x80) |*/
		    0x40 |
		    (((md->VBS & 0x200)/0x200)*0x20) |
		    (0 & 0x1f));
	}
	/* I prefer "_" cursor to "block" cursor.. */
#if 1
	WCrt(ba, CRT_ID_CURSOR_START, (md->FY & 0x1f) - 2);
	WCrt(ba, CRT_ID_CURSOR_END, (md->FY & 0x1f) - 1);
#else
	WCrt(ba, CRT_ID_CURSOR_START, 0x00);
	WCrt(ba, CRT_ID_CURSOR_END, md->FY & 0x1f);
#endif

	WCrt(ba, CRT_ID_START_ADDR_HIGH, 0x00);
	WCrt(ba, CRT_ID_START_ADDR_LOW, 0x00);

	WCrt(ba, CRT_ID_CURSOR_LOC_HIGH, 0x00);
	WCrt(ba, CRT_ID_CURSOR_LOC_LOW, 0x00);

	WCrt(ba, CRT_ID_START_VER_RETR, (VSS & 0xff));
	WCrt(ba, CRT_ID_END_VER_RETR, ((VSS-(VSE - VSS)) & 0xf) | 0x80 | 0x20);
	WCrt(ba, CRT_ID_VER_DISP_ENA_END, VDE  & 0xff);

	if (md->DEP == 4)
		WCrt(ba, CRT_ID_OFFSET, (HDE / 2) & 0xff);
	else if (md->DEP == 8)
		WCrt(ba, CRT_ID_OFFSET, (md->TX / 8) & 0xff);
	else
		WCrt(ba, CRT_ID_OFFSET, (md->TX / 4) & 0xff);

	WCrt(ba, CRT_ID_UNDERLINE_LOC, (md->FY-1) & 0x1f);
	WCrt(ba, CRT_ID_START_VER_BLANK, (VBS & 0xff));
	WCrt(ba, CRT_ID_END_VER_BLANK, (VBE & 0xff));
	WCrt(ba, CRT_ID_MODE_CONTROL, 0xa3);
	WCrt(ba, CRT_ID_LINE_COMPARE, 0xff);
	/* extended CR regs */
/** succ **/
/*#ifdef 0*/
  if(md->FLG & F_LACE){
    WCrt(ba, CRT_ID_LACE_END, (0xff & (md->HT/2)));
    /*WCrt(ba, CRT_ID_LACE_CNTL, RCrt(ba,CRT_ID_LACE_CNTL)|0x01);*/
  } 
#ifdef 0

	WCrt(ba, CRT_ID_EXT_DISP_CNTL, (((md->TX & 0x100)/0x100)*0x10) | 0x80);
	WCrt(ba, CRT_ID_LACE_CNTL,
		(((md->VBE & 0x0300) >> 2)) |
		((md->HBE & 0xc0) >> 2)); 


#endif /* restore */

	WGfx(ba, GCT_ID_SET_RESET, 0x00);
	WGfx(ba, GCT_ID_ENABLE_SET_RESET, 0x00);
	WGfx(ba, GCT_ID_COLOR_COMPARE, 0x00);
	WGfx(ba, GCT_ID_DATA_ROTATE, 0x00);
	WGfx(ba, GCT_ID_READ_MAP_SELECT, 0x00);
	WGfx(ba, GCT_ID_GRAPHICS_MODE, 0x40); /* 00? */
	if (md->DEP == 4)
		WGfx(ba, GCT_ID_MISC, 0x04);
	else
		WGfx(ba, GCT_ID_MISC, 0x01);
	WGfx(ba, GCT_ID_COLOR_XCARE, 0x0f);
	WGfx(ba, GCT_ID_BITMASK, 0xff);
	WGfx(ba, GCT_ID_OFFSET_0, 0x00);
	WGfx(ba, GCT_ID_OFFSET_1, 0xec);
	WGfx(ba, GCT_ID_MODE_EXT, 0x28);
	WGfx(ba, GCT_ID_COLOR_KEY, 0x00);
	WGfx(ba, GCT_ID_COLOR_KEY_MASK, 0x00);
	WGfx(ba, GCT_ID_MISC_CNTL, 0x00);
	WGfx(ba, GCT_ID_16BIT_BG_HIGH, 0x00);
	WGfx(ba, GCT_ID_16BIT_FG_HIGH, 0x00);
	WGfx(ba, GCT_ID_BLT_STAT_START, 0x04);
	WGfx(ba, GCT_ID_TRP_COL_LOW, 0x00);
	WGfx(ba, GCT_ID_TRP_COL_HIGH, 0x00);
	WGfx(ba, GCT_ID_TRP_MASK_HIGH, 0x00);
	WGfx(ba, GCT_ID_TRP_MASK_LOW, 0x00);

/* was ifdef'ed out */
#ifdef 0
	if(RGfx(ba,CRT_ID_ACT_TOGGLE_RBACK) & 0x80){
	  tmpuchar=vgar(ba,ACT_ADDRESS_R);
	  vgaw(ba,ACT_ADDRESS_W,tmpuchar);
	}
	for(tmp=0;tmp<=0x0f;tmp++){
	  vgaw(ba,ACT_ADDRESS_W, tmp);/* index */
	  vgaw(ba,ACT_ADDRESS_W, tmp);/* data */
	}
	vgaw(ba, ACT_ADDRESS_W, 0x10);
	vgaw(ba, ACT_ADDRESS_W, 0x01);
	vgaw(ba, ACT_ADDRESS_W, 0x11);
	vgaw(ba, ACT_ADDRESS_W, 0x00);
	vgaw(ba, ACT_ADDRESS_W, 0x12);
	vgaw(ba, ACT_ADDRESS_W, 0x0f);
	vgaw(ba, ACT_ADDRESS_W, 0x13);
	vgaw(ba, ACT_ADDRESS_W, 0x00);
	vgaw(ba, ACT_ADDRESS_W, 0x14);
	vgaw(ba, ACT_ADDRESS_W, 0x00);
#endif
	WAttr(ba, ACT_ID_PALETTE0 , 0x00);
	WAttr(ba, ACT_ID_PALETTE1 , 0x01);
	WAttr(ba, ACT_ID_PALETTE2 , 0x02);
	WAttr(ba, ACT_ID_PALETTE3 , 0x03);
	WAttr(ba, ACT_ID_PALETTE4 , 0x04);
	WAttr(ba, ACT_ID_PALETTE5 , 0x05);
	WAttr(ba, ACT_ID_PALETTE6 , 0x06);
	WAttr(ba, ACT_ID_PALETTE7 , 0x07);
	WAttr(ba, ACT_ID_PALETTE8 , 0x08);
	WAttr(ba, ACT_ID_PALETTE9 , 0x09);
	WAttr(ba, ACT_ID_PALETTE10, 0x0a);
	WAttr(ba, ACT_ID_PALETTE11, 0x0b);
	WAttr(ba, ACT_ID_PALETTE12, 0x0c);
	WAttr(ba, ACT_ID_PALETTE13, 0x0d);
	WAttr(ba, ACT_ID_PALETTE14, 0x0e);
	WAttr(ba, ACT_ID_PALETTE15, 0x0f);


	if (md->DEP == 4)
		WAttr(ba, ACT_ID_ATTR_MODE_CNTL, 0x08);
	else
		WAttr(ba, ACT_ID_ATTR_MODE_CNTL, 0x01);

	WAttr(ba, ACT_ID_OVERSCAN_COLOR, 0x00);
	WAttr(ba, ACT_ID_COLOR_PLANE_ENA, 0x0f);
	WAttr(ba, ACT_ID_HOR_PEL_PANNING, 0x00);
	WAttr(ba, ACT_ID_COLOR_SELECT, 0x00);

	/* enable video */

	vgaw(ba, ACT_ADDRESS_W, 0x20);
/*	vgaw(ba, VDAC_MASK, 0xff);	*/

	/* hidden DAC register */

  /* Had to implement a busy-wait for >030/25 and <030/16 machines,
     because the DAC is not read in time. -ill 
  */

	vgar(ba,0x3c6);
  busy_delay(10000);
  vgar(ba,0x3c6);
  busy_delay(10000);
  vgar(ba,0x3c6);
  busy_delay(10000);
  vgar(ba,0x3c6);
  busy_delay(10000);
	vgaw(ba,0x3c6,0);


	vgaw(ba, VDAC_MASK, 0xff);

	/* Pass-through */

  /* Changed for Piccolo by MiL */
  /* Tell me how this works, MiL? You don't need WPass()? -ill */

  if (cltype == PICCOLO ) *(ba+0x8000) |= 0x20;
  else WPass(ba, offpass);  
  if (cltype == PICCOLO ) delay(10000);

	if (md->DEP < 16) {
		short x = 256-17;
		unsigned char cl = 16;
		CLLoadPalette(gp, md->PAL, 0, 16);
		do {
			vgaw(ba, VDAC_DATA, (cl >> 2));
			vgaw(ba, VDAC_DATA, (cl >> 2));
			vgaw(ba, VDAC_DATA, (cl >> 2));
			cl++;
		} while (x-- > 0);
	}

#ifdef 0	/* textmode not supported yet */
	if (md->DEP == 4) {
		{
			struct grf_bitblt bb = {
				GRFBBOPset,
				0, 0,
				0, 0,
				md->TX*4, 2*md->TY,
				EMPTY_ALPHA
			};
			CLBitBlit(gp, &bb);
		}

		c = (unsigned short *)(ba + LM_OFFSET);
		c += 2 * md->FLo*32;
		c += 1;
		f = md->FData;
		for (z = md->FLo; z <= md->FHi; z++) {
			short y = md->FY-1;
			if (md->FX > 8){
				do {
					*c = *((const unsigned short *)f);
					c += 2;
					f += 2;
				} while (y-- > 0);
			} else {
				do {
					*c = (*f++) << 8;
					c += 2;
				} while (y-- > 0);
			}

			c += 2 * (32-md->FY);
		}
		{
			unsigned long * pt = (unsigned long *) (ba + LM_OFFSET + PAT_MEM_OFF);
			unsigned long tmp  = 0xffff0000;
			*pt++ = tmp;
			*pt = tmp;
		}

		WSeq(ba, SEQ_ID_MAP_MASK, 3);

		c = (unsigned short *)(ba + LM_OFFSET);
		c += (md->TX-6)*2;
		{
		  	/* it's show-time :-) */
			static unsigned short init_msg[6] = {
				0x520a, 0x450b, 0x540c, 0x490d, 0x4e0e, 0x410f
			};
			unsigned short * m = init_msg;
			short x = 5;
			do {
				*c = *m++;
				c += 2;
			} while (x-- > 0);
		}

		return(1);
	} else
#endif 
	if (md->DEP == 8) {
		struct grf_bitblt bb = {
			GRFBBOPset,
			0, 0,
			0, 0,
			md->TX, md->TY,
			0x0000
		};

		WSeq(ba, SEQ_ID_MAP_MASK, 0x0f);
		CLBitBlit(gp, &bb);

		xpan = 0;
		ypan = 0;
		return(1);
	} else if (md->DEP == 16) {
		struct grf_bitblt bb = {
			GRFBBOPset,
			0, 0,
			0, 0,
			md->TX, md->TY,
			0x0000
		};
		WSeq(ba, SEQ_ID_MAP_MASK, 0x0f);

		CL16BitBlit(gp, &bb);

		xpan = 0;
		ypan = 0;

		return(1);
	} else {
	        printf("clloadmon: something fucked up (depth)\n");
		return(0);
	}
}

/* standard-palette definition */

unsigned char CLStdPalette[16*3] = {
/*        R   G   B  */
	  0,  0,  0,
	192,192,192,
	128,  0,  0,
	  0,128,  0,
	  0,  0,128,
	128,128,  0,
	  0,128,128,
	128,  0,128,
	 64, 64, 64, /* the higher 8 colors have more intensity for  */
	255,255,255, /* compatibility with standard attributes       */
	255,  0,  0,
	  0,255,  0,
	  0,  0,255,
	255,255,  0,
	  0,255,255,
	255,  0,255
};

/*
 * The following structures are examples for monitor-definitions. To make one
 * of your own, first use "DefineMonitor" and create the 8-bit or 16-bit
 * monitor-mode of your dreams. Then save it, and make a structure from the
 * values provided in the file DefineMonitor stored - the labels in the comment
 * above the structure definition show where to put what value.
 *
 * If you want to use your definition for the text-mode, you'll need to adapt
 * your 8-bit monitor-definition to the font you want to use. Be FX the width of
 * the font, then the following modifications have to be applied to your values:
 *
 * HBS = (HBS * 4) / FX
 * HSS = (HSS * 4) / FX
 * HSE = (HSE * 4) / FX
 * HBE = (HBE * 4) / FX
 * HT  = (HT  * 4) / FX
 *
 * Make sure your maximum width (MW) and height (MH) are even multiples of
 * the fonts' width and height.
 *
 * You may use definitons created by the old DefineMonitor, but you'll get
 * better results with the new DefineMonitor supplied along with the Retin Z3.
*/

/*
 *  FQ     FLG    MW   MH   HBS HSS HSE HBE  HT  VBS  VSS  VSE  VBE   VT
 * Depth,          PAL, TX,  TY,    XY,FontX, FontY,    FontData,  FLo,  Fhi
 */
static struct MonDef monitor_defs[] = {
  /* Text-mode definitions */

  /* horizontal 31.5 kHz */
#ifdef KFONT_8X11
  { 50000000,  28,  640, 506,   81, 86, 93, 98, 95, 513, 513, 521, 535, 535,
      4, CLStdPalette, 80,  46,  3680,    8,    11, kernel_font_8x11, 32,  255},
#else
  { 50000000,  28,  640, 512,   81, 86, 93, 98, 95, 513, 513, 521, 535, 535,
      4, CLStdPalette, 80,  64,  5120,    8,     8, kernel_font_8x8,   32,  255},
#endif

  /* horizontal 38kHz */
#ifdef KFONT_8X11
  { 75000000,  28,  768, 594,   97, 99,107,120,117, 601, 615, 625, 638, 638,
      4, CLStdPalette, 96,  54,  5184,    8,     11, kernel_font_8x11,   32,  255},
#else
  { 75000000,  28,  768, 600,   97, 99,107,120,117, 601, 615, 625, 638, 638,
      4, CLStdPalette, 96,  75,  7200,    8,     8, kernel_font_8x8,   32,  255},
#endif

  /* horizontal 64kHz */
#ifdef KFONT_8X11
  { 50000000, 24,  768, 594,   97,104,112,122,119, 601, 606, 616, 628, 628,
      4, CLStdPalette, 96,  54,  5184,    8,     8, kernel_font_8x8,   32,  255},
#else
  { 50000000, 24,  768, 600,   97,104,112,122,119, 601, 606, 616, 628, 628,
      4, CLStdPalette, 96,  75,  7200,    8,     8, kernel_font_8x8,   32,  255},
#endif

  /* 8-bit gfx-mode definitions */

  /*
   * IMPORTANT: the "logical" screen size can be up to 2048x2048 pixels,
   * independent from the "physical" screen size. If your code does NOT
   * support panning, please adjust the "logical" screen sizes below to
   * match the physical ones
   */

  /* MODE 4 640x480 63Hz@31khz */

  /* 640 x 480, 8 Bit, 31862 Hz, 63 Hz */
  { 26000000,  0,  640, 480,  161,175,188,200,199, 481, 483, 491, 502, 502,
      8, CLStdPalette,640,480,  5120,    8,     8, kernel_font_8x8,   32,  255},
  /* This is the logical ^    ^    screen size */
  
  /* MODE 5 640x480 76Hz@38kHz */

  /* 640 x 480, 8 Bit, 38366 Hz, 76 Hz */
 { 31000000,  0,  640, 480,  161,169,182,198,197, 481, 482, 490, 502, 502,
     8, CLStdPalette,640,480,  5120,    8,     8, kernel_font_8x8,   32,  255},

  /* MODE 6 800x600 50Hz@31kHz */

  /* 800 x 600, 8 Bit, 31620 Hz, 50 Hz (1950) */
  { 42610000,  0,  800, 600,  99,110,143,143 ,143, 599, 617, 620, 654, 654,
      8, CLStdPalette,800,600, 5120,    8,     8, kernel_font_8x8,   32,  255},

  /* MODE 7 1024x768 61Hz@38kHz */

  /* 1024 x 768 8 Bit */
  { 63330000,  0,  1024, 768, 127,131,163,178,178, 767,780,783,811,811,
      8, CLStdPalette,1024,768, 5120,   8,     8, kernel_font_8x8,   32,  255},

  /* MODE 8 1024x768 69Hz@59kHz */

  /* 1024 x 768, 8 Bit, 59 KHz, 69 Hz */
  { 80000000,  0, 1024, 768,  129,134,144,165,170, 780, 800, 810, 830,850,
      8, CLStdPalette,1024,768, 5120,   8,     8, kernel_font_8x8,   32,  255},

  /* MODE 9  1152x900 60.5Hz@56kHz */

  /* 1152 x 900, 8 Bit, 56.9 KHz, 60.5 Hz */
  { 81000000,  0, 1152, 900,  145,155,167,169,178, 905, 910, 915, 930, 940,
      8, CLStdPalette,1152,900, 5120,   8,     8, kernel_font_8x8,   32,  255},

  /* MODE 10 1280x1024 95Hz@51.9kHz */

  /* 1280x1024, 8 Bit, 51.9 KHz, 95 Hz Laced */
  {81000000, F_LACE,1280, 1024, 150,170,187,189,195,1027,1032,1055, 1070, 1090,
      8, CLStdPalette,1280,1024,5120,   8,     8, kernel_font_8x8,   32,  255},

  /* MODE 11 1184x848 82Hz@73kHz */

  /* 1184 x 848, 8 Bit, 73529 Hz, 82 Hz */
  {110000000,  0, 1184, 848,  297,319,342,370,369, 849, 852, 866, 888, 888,
      8, CLStdPalette,1280,1024, 5120,   8,    8, kernel_font_8x8,   32,  255},

  /* MODE 12 1280x1024 60Hz@64kHz */

  /* 1280 x 1024, 8 Bit, 64516 Hz, 60 Hz */
  {104000000, 0, 1280,1024,  321,323,348,399,398,1025,1026,1043,1073,1073,
     8, CLStdPalette,1280,1024,  5120,   8,    8, kernel_font_8x8,   32,  255},

/* WARNING: THE FOLLOWING MONITOR MODE EXCEEDS THE 110-MHz LIMIT THE PROCESSOR
            HAS BEEN SPECIFIED FOR. USE AT YOUR OWN RISK (AND THINK ABOUT
            MOUNTING SOME COOLING DEVICE AT THE PROCESSOR AND RAMDAC)!     */
  /* 1280 x 1024, 8 Bit, 75436 Hz, 70 Hz */
  {121000000, 0, 1280,1024,  321,322,347,397,396,1025,1026,1043,1073,1073,
     8, CLStdPalette,1280,1024,  5120,    8,     8, kernel_font_8x8,   32,  255},


  /* 16-bit gfx-mode definitions */

  /* 640 x 480, 16 Bit, 31795 Hz, 63 Hz */
  { 51000000, 0,  640, 480,  321,344,369,397,396, 481, 482, 490, 502, 502,
      16,           0,1280, 1024,  7200,    8,     8, kernel_font_8x8,   32,  255},

  /* 800 x 600, 16 Bit, 38500 Hz, 61 Hz */
  { 77000000, 0,  800, 600,  401,418,449,496,495, 601, 602, 612, 628, 628,
      16,           0,1280, 1024,  7200,    8,     8, kernel_font_8x8,   32,  255},

  /* 1024 x 768, 16 Bit, 42768 Hz, 53 Hz */
  {110000000,  0, 1024, 768,  513,514,554,639,638, 769, 770, 783, 804, 804,
      16,           0,1280, 1024,  7200,    8,     8, kernel_font_8x8,   32,  255},

  /* 864 x 648, 16 Bit, 50369 Hz, 74 Hz */
  {109000000,  0,  864, 648,  433,434,468,537,536, 649, 650, 661, 678, 678,
      16,           0,1280, 1024,  7200,    8,     8, kernel_font_8x8,   32,  255},

/*
 * WARNING: THE FOLLOWING MONITOR MODE EXCEEDS THE 110-MHz LIMIT THE PROCESSOR
 *          HAS BEEN SPECIFIED FOR. USE AT YOUR OWN RISK (AND THINK ABOUT
 *          MOUNTING SOME COOLING DEVICE AT THE PROCESSOR AND RAMDAC)!
 */
  /* 1024 x 768, 16 Bit, 48437 Hz, 60 Hz */
  {124000000,  0, 1024, 768,  513,537,577,636,635, 769, 770, 783, 804, 804,
      16,           0,1280, 1024,  7200,    8,     8, kernel_font_8x8,   32,  255},
};

static const char *monitor_descr[] = {
#ifdef KFONT_8X11
  "80x46 (640x506) 31.5kHz",
  "96x54 (768x594) 38kHz",
  "96x54 (768x594) 64kHz",
#else
  "80x64 (640x512) 31.5kHz",
  "96x75 (768x600) 38kHz",
  "96x75 (768x600) 64kHz",
#endif

  "GFX-8 (640x480) 31.5kHz",
  "GFX-8 (640x480) 38kHz",
  "GFX-8 (800x600) 31.6kHz",
  "GFX-8 (800x600) 38.5kHz",
  "GFX-8 (1024x768) 64kHz",
  "GFX-8 (1120x896) 64kHz",
  "GFX-8 (1152x910) 76kHz",
  "GFX-8 (1182x848) 73kHz",
  "GFX-8 (1280x1024) 64.5kHz",
  "GFX-8 (1280x1024) 75.5kHz ***EXCEEDS CHIP LIMIT!!!***",

  "GFX-16 (640x480) 31.8kHz",
  "GFX-16 (800x600) 38.5kHz",
  "GFX-16 (1024x768) 42.8kHz",
  "GFX-16 (864x648) 50kHz",
  "GFX-16 (1024x768) 48.5kHz ***EXCEEDS CHIP LIMIT!!!***",
};

int cl_mon_max = sizeof (monitor_defs)/sizeof (monitor_defs[0]);

/* patchable */
int cl_default_mon = 6;/* 6 */	/* text not supported yet */
int cl_default_gfx = 6;

static struct MonDef *current_mon;


int  cl_mode     __P((struct grf_softc *, int, void *, int, int));
void grfclattach __P((struct device *, struct device *, void *));
int  grfclprint  __P((void *, char *));
int  grfclmatch  __P((struct device *, struct cfdata *, void *));

struct cfdriver grfclcd = {
	NULL, "grfcl", grfclmatch, grfclattach,
	DV_DULL, sizeof(struct grf_softc), NULL, 0
};
struct cfdriver grfclxcd = {
	NULL, "grfclx", grfclmatch, grfclattach,
	DV_DULL, sizeof(struct grf_softc), NULL, 0
};

static struct cfdata *cfdata;

int
grfclmatch(pdp, cfp, auxp)
	struct device *pdp;
	struct cfdata *cfp;
	void *auxp;
{
	struct zthreebus_args *zap;

	zap = auxp;

	if (amiga_realconfig == 0)
		return(0);

	switch (zap->manid){

		case 2167:
		/* Picasso */
			if(zap->prodid == 11){
			/* display memory */
				if((cl_fbsize=zap->size)< 1024*1024){
					printf("grf_cl: too little display memory, segmented mode?\n");
   /* Dagge, we need to support 1MB Picasso in amiga_init.c, but how to
pass the info? ill */
					return(0);
				}
				
				zap->va = cl_fbaddr = (void *)zthreemap(zap->pa,zap->size);	/* va? */

				return(0);
			}else{
			        volatile unsigned char *ar,*cri,*cr;
			  
				if(zap->prodid != 12){
					return (0);
				}
				if(!cl_fbaddr){
					printf("grf_clmatch: display memory not found\n");
					return(0);
				}
				cl_regaddr = zap->va;/*this doesn't need to be mapped */
				/*printf("kvtphys(%x)=%x\n",zap->va,kvtophys(zap->va));*/
				cltype = PICASSO;
				wakepass = 0xff;
				onpass = 0x1; /* change to 1, so that WPassP() can check, ill */
				offpass = 0xff;	/* not really working yet */ /* Now it does, ill :-) */
        if(cltype==PICASSO) ar=((char *)zap->va)+(0x3c1+0xffff);
        else ar=((char *)zap->va)+0x3c1;
				cri=((char *)zap->va)+0x3d4;
				cr=((char *)zap->va)+0x3d5;
				*cri=0x24;

			}
			break;
		case 2193:
		/* numbers were reversed.. Ezy */
		/* Spectrum */
			switch (zap->prodid) {
			case 1:
				if((cl_fbsize=zap->size)< 1024*1024){
					printf("grf_cl: too little display memory\n");
					return(0);
				}
				if (cl_regaddr == 0) {
					printf("grf_cl: registers not found.\n");
					return(0);
				}
	/* Ezy, why do this here? is zap->size incorrect? Are there Spectrum
with 1MB avail? ill */

				cl_fbsize = 1024*1024*2;
				cl_fbaddr = zap->va;	/* pa? */
				break;

			case 2:
				cl_regaddr = zap->va;
				cltype = SPECTRUM;
				wakepass = 0x1f;
				onpass = 0x4f;
				offpass = 0x6f;
				return(1);
				break;

			default:
				return(0);
				break;
			}
			break;
		case 2195:
		/* Piccolo */
    /* Added/changed by MiL */
      switch (zap->prodid) {
      case 5:
              if((cl_fbsize=zap->size)< 1024*1024){
         printf("grf_cl: too little display memory\n");
         return(0);
        }
        cl_fbaddr = zap->va;
        cl_fbsize = 1024*1024*2;
        break;
      case 6:
        cl_regaddr = zap->va;
        break;
        }
      if (cl_regaddr && cl_fbaddr)
      {
       cltype = PICCOLO;
       wakepass = 0x7F; /* I haven't tested these */
       onpass = 0xDF;         /* I have MiL ;-) */
       offpass = 0x20;        /* but they have no use */
      }
      else return(0);
			break;
		default: return(0);
	}


	/* make sure default monitor definition is 8 bits deep */

	if ((unsigned)cl_default_mon >= cl_mon_max ||
	    monitor_defs[cl_default_mon].DEP != 8)
		cl_default_mon = 6; /* 6 */

	current_mon = monitor_defs + cl_default_mon;
	if (cl_mondefok(current_mon) == 0)
		return(0);

	return(1);
}

void
grfclattach(pdp, dp, auxp)
	struct device *pdp, *dp;
	void *auxp;
{
	static struct grf_softc congrf;
	static int coninited;
	struct zthreebus_args *zap;
	struct grf_softc *gp;

	/* we'll do this only once...if there are multiple 5426-boards
	 * this don't work
	 */

 /* We need to implement an array for his purpose. And change grfvar.h
vor GRF_UNITS. ****, this is getting complicated. BTW, good sake that 
ztwobus_args and zthreebus_args are identical :-) ill */

	printf("\n");
	if(!cl_regaddr || !cl_fbaddr)return;

	printf("grfclattach: regs at %x and mem at %x, len %x\n",cl_regaddr,cl_fbaddr, cl_fbsize);


	zap = auxp;

	if (dp == NULL)
		gp = &congrf;
	else
		gp = (struct grf_softc *)dp;
	if (dp != NULL && congrf.g_regkva != 0) {
		/*
		 * inited earlier, just copy (not device struct)
		 */
		bcopy(&congrf.g_display, &gp->g_display,
		    (char *)&gp[1] - (char *)&gp->g_display);
	} else {
		gp->g_regkva = (volatile caddr_t)cl_regaddr;

		/* this only works if the mem-entry of 5426-board
		 * has been matched before, but we'll check for this
		 * when matching regs.
		 */
		
		gp->g_fbkva = (volatile caddr_t)cl_fbaddr;

		gp->g_unit = GRF_CL5426_UNIT;
		gp->g_mode = cl_mode;
		gp->g_conpri = grfcl_cnprobe();
		gp->g_flags = GF_ALIVE;
#ifdef 0
		grfrh_iteinit(gp);
		/* why do this here? anyways, we'll do it only when
		 * we get GRF_ON. Turning pass-through on here might
		 * not be what the user wants =)we'll wake it up though.
		 */
		(void)cl_load_mon(gp, current_mon);
#endif
		cl_boardwakeup(gp);	/* for waking pass-throug up
					 * and other wakeup-stuff
					 */
	}
	if (dp != NULL)
		printf("\n");
	/*
	 * attach grf
	 */
	amiga_config_found(cfdata, &gp->g_device, gp, grfclprint);
	printf("grfcl attached to ");
  if(zap->manid==2167) printf("Picasso II\n");
  if(zap->manid==2193) printf("Spectrum\n");
  if(zap->manid==2195) printf("Piccolo\n");
}

int
grfclprint(auxp, pnp)
	void *auxp;
	char *pnp;
{
	if (pnp)
		printf("ite at %s, NOT!", pnp);
	return(UNCONF);
}

void
cl_boardwakeup(gp)
struct grf_softc	*gp;
{
	unsigned char *ba = gp->g_regkva;
  void *bah;

/* Changed/Added by MiL. 
   Good idea MiL! -ill 
*/
  switch (cltype)
  {
  case SPECTRUM :
   WPass(ba, wakepass);
   delay(10000);
   WPass(ba, onpass); /* cc still on */
   delay(10000);
   break;
  case PICASSO :
   WPass(ba, wakepass); /* we dont need that one?! */
   delay(10000);
   WPassP(ba, onpass);  /* cc still on, pass to CC so that remaining
           CL fragments are disabled , ill */
   delay(10000);
   break;
  case PICCOLO :
   *(ba + 0x8000) |= 0x10;
   delay(10000);
   *(ba + 0x8000) &= 0xDF;
   delay(10000);
   break;
  }

	vgaw(ba, 0x46e8, 0x16);
	vgaw(ba, 0x102, 1);
	vgaw(ba, 0x46e8, 0x0e);
	vgaw(ba, 0x3c3, 1);
/* No idea if this works, it should set flag to OFF, ill*/
  bah_toggle=0;
}


int
cl_getvmode(gp, vm)
	struct grf_softc *gp;
	struct grfvideo_mode *vm;
{
	struct MonDef *md;

	if (vm->mode_num && vm->mode_num > cl_mon_max)
		return(EINVAL);

	if (! vm->mode_num)
		vm->mode_num = (current_mon - monitor_defs) + 1;

	md = monitor_defs + (vm->mode_num - 1);
	/* changed strncopy to copyout */
	strncpy (vm->mode_descr, monitor_descr + (vm->mode_num - 1),
	   sizeof (vm->mode_descr));
	vm->pixel_clock  = md->FQ;
	vm->disp_width   = md->MW;
	vm->disp_height  = md->MH;
	vm->depth        = md->DEP;
	vm->hblank_start = md->HBS;
	vm->hblank_stop  = md->HBE;
	vm->hsync_start  = md->HSS;
	vm->hsync_stop   = md->HSE;
	vm->htotal       = md->HT;
	vm->vblank_start = md->VBS;
	vm->vblank_stop  = md->VBE;
	vm->vsync_start  = md->VSS;
	vm->vsync_stop   = md->VSE;
	vm->vtotal       = md->VT;

	return(0);
}


int
cl_setvmode(gp, mode, txtonly)
	struct grf_softc *gp;
	unsigned mode;
	int txtonly;
{
	struct MonDef *md;
	int error;
	if (!mode || (mode > cl_mon_max) || txtonly)
		return(EINVAL);

	if (txtonly && (monitor_defs[mode-1].DEP != 4))
		return(EINVAL);

	current_mon = monitor_defs + (mode - 1);
	error = cl_load_mon (gp, current_mon) ? 0 : EINVAL;
	return(error);
}

void
cl_off(gp)
struct grf_softc *gp;
{
/* we'll put the pass-through on for cc ite and set Full Bandwidth
 * bit on just in case it didn't work...but then it doesn't matter
 * does it? =)
  */
	char *ba = gp->g_regkva;
  switch (cltype)
  { 
  case SPECTRUM :
   WPass(ba, onpass);
   break;
  case PICASSO :
   WPassP(ba, onpass); /* Gotta use WPassP() for Picasso, ill */
   break;
  case PICCOLO :
   *(ba + 0x8000) &= 0xDF;
   delay(100000);
   break;
  }
	vgaw(ba, SEQ_ID_CLOCKING_MODE, 0x20);
}
/*
 * Change the mode of the display.
 * Return a UNIX error number or 0 for success.
 */
cl_mode(gp, cmd, arg, a2, a3)
	register struct grf_softc *gp;
	int cmd;
	void *arg;
	int a2, a3;
{
  /* implement these later... */
	switch (cmd) {
	case GM_GRFON:
		cl_setvmode (gp, cl_default_gfx + 1, 0);
		return(0);

	case GM_GRFOFF:
		cl_off(gp);	/* we don't have ite waiting */
/*		cl_setvmode (gp, cl_default_mon + 1, 0);*/
		return(0);

	case GM_GRFCONFIG:
		return(0);

	case GM_GRFGETVMODE:
		return(cl_getvmode (gp, (struct grfvideo_mode *) arg));

	case GM_GRFSETVMODE:
		/* when ite is implemented, last arg needs to be 1 */
		return(cl_setvmode (gp, *(unsigned *) arg, 0));

	case GM_GRFGETNUMVM:
		*(int *)arg = cl_mon_max;
		return(0);

#ifdef BANKEDDEVPAGER
	case GM_GRFGETBANK:
	case GM_GRFGETCURBANK:
	case GM_GRFSETBANK:
		return(EINVAL);
#endif
	case GM_GRFIOCTL:
		return(cl_ioctl (gp, (int) arg, (caddr_t) a2));

	default:
		break;
	}

	return(EINVAL);
}

int
cl_ioctl (gp, cmd, data)
	register struct grf_softc *gp;
	int cmd;
	void *data;
{
	switch (cmd) {
	case GRFIOCGSPRITEPOS:
		break;
		return(cl_getspritepos (gp, (struct grf_position *) data));

	case GRFIOCSSPRITEPOS:
		break;
		return(cl_setspritepos (gp, (struct grf_position *) data));

	case GRFIOCSSPRITEINF:
		break;
		return(cl_setspriteinfo (gp, (struct grf_spriteinfo *) data));

	case GRFIOCGSPRITEINF:
		break;
		return(cl_getspriteinfo (gp, (struct grf_spriteinfo *) data));

	case GRFIOCGSPRITEMAX:
		break;
		return(cl_getspritemax (gp, (struct grf_position *) data));

	case GRFIOCGETCMAP:
		return(cl_getcmap (gp, (struct grf_colormap *) data));

	case GRFIOCPUTCMAP:
		return(cl_putcmap (gp, (struct grf_colormap *) data));

	case GRFIOCBITBLT:
		return(cl_bitblt (gp, (struct grf_bitblt *) data));

	case GRFTOGGLE:
		return(cl_toggle (gp,0));

	}
	return(EINVAL);
}


int
cl_getcmap (gfp, cmap)
	struct grf_softc *gfp;
	struct grf_colormap *cmap;
{
	volatile unsigned char *ba;
	u_char red[256], green[256], blue[256], *rp, *gp, *bp;
	short x;
	int error;

	if (cmap->count == 0 || cmap->index >= 256)
		return 0;

	if (cmap->index + cmap->count > 256)
		cmap->count = 256 - cmap->index;

	ba = gfp->g_regkva;
	/* first read colors out of the chip, then copyout to userspace */
	vgaw (ba, VDAC_ADDRESS_W, cmap->index);
	x = cmap->count - 1;

/* Some sort 'o Magic. Spectrum has some changes on the board to speed
up 15 and 16Bit modes. They can access these modes with easy-to-programm
rgbrgbrgb instead of rrrgggbbb. Side effect: when in 8Bit mode, rgb
is swapped to bgr. I wonder if we need to check for 8Bit though, ill */

  switch (cltype) 
  {  
  case SPECTRUM : 
   rp = blue + cmap->index;  
   gp = green + cmap->index;
   bp = red + cmap->index;
     break;
  case PICASSO :
   rp = red + cmap->index;  
   gp = green + cmap->index;
   bp = blue + cmap->index;
   break;
  case PICCOLO :
   rp = blue + cmap->index;
   gp = green + cmap->index;
   bp = red + cmap->index;
   break;
  }

	do {
		*rp++ = vgar (ba, VDAC_DATA) << 2;
		*gp++ = vgar (ba, VDAC_DATA) << 2;
		*bp++ = vgar (ba, VDAC_DATA) << 2;
	} while (x-- > 0);

	if (!(error = copyout (red + cmap->index, cmap->red, cmap->count))
	    && !(error = copyout (green + cmap->index, cmap->green, cmap->count))
	    && !(error = copyout (blue + cmap->index, cmap->blue, cmap->count)))
		return(0);

	return(error);
}

int
cl_putcmap (gfp, cmap)
	struct grf_softc *gfp;
	struct grf_colormap *cmap;
{
	volatile unsigned char *ba;
	u_char red[256], green[256], blue[256], *rp, *gp, *bp;
	short x;
	int error;

	if (cmap->count == 0 || cmap->index >= 256)
		return(0);

	if (cmap->index + cmap->count > 256)
		cmap->count = 256 - cmap->index;

	/* first copy the colors into kernelspace */
	if (!(error = copyin (cmap->red, red + cmap->index, cmap->count))
	    && !(error = copyin (cmap->green, green + cmap->index, cmap->count))
	    && !(error = copyin (cmap->blue, blue + cmap->index, cmap->count))) {
		/* argl.. LoadPalette wants a different format, so do it like with
		* Retina2.. */
		ba = gfp->g_regkva;
		vgaw (ba, VDAC_ADDRESS_W, cmap->index);
		x = cmap->count - 1;

 /* Me thinks we need to change this for Spectrum, don't we? ill */

    switch (cltype)
    { 
    case SPECTRUM :   /* hope this is right MiL */
     rp = blue + cmap->index;
     gp = green + cmap->index;
     bp = red + cmap->index;
     break;
    case PICASSO :
     rp = red + cmap->index;
     gp = green + cmap->index;
     bp = blue + cmap->index;
     break;
    case PICCOLO :
     rp = blue + cmap->index;
     gp = green + cmap->index;
     bp = red + cmap->index;
     break;
    }   

		do {
			vgaw (ba, VDAC_DATA, *rp++ >> 2);
			vgaw (ba, VDAC_DATA, *gp++ >> 2);
			vgaw (ba, VDAC_DATA, *bp++ >> 2);
		} while (x-- > 0);
		return(0);
	}
	else
		return(error);
}

int
cl_getspritepos (gp, pos)
	struct grf_softc *gp;
	struct grf_position *pos;
{
	volatile unsigned char *acm = gp->g_regkva + ACM_OFFSET;

/* This part is not implemeted and yields into a softsprite using X. 
   Also it looks like that autoscroll and Multiple screens under X
   do not work correctly because the sprite is not used/initialized
   ill
*/
/*
        NOT IMPLEMENTED!!!!

	pos->x = acm[ACM_CURSOR_POSITION + 0] +
	    (acm[ACM_CURSOR_POSITION + 1] << 8);
	pos->y = acm[ACM_CURSOR_POSITION + 2] +
	    (acm[ACM_CURSOR_POSITION + 3] << 8);
*/
	pos->x += xpan;
	pos->y += ypan;

	return(0);
}

int
cl_setspritepos (gp, pos)
	struct grf_softc *gp;
	struct grf_position *pos;
{
	CLSetHWCloc (gp, pos->x, pos->y);
	return(0);
}


int
cl_getspriteinfo (gp, info)
	struct grf_softc *gp;
	struct grf_spriteinfo *info;
{
        unsigned char *ba, *fb;
	struct grf_colormap *tcm;


	ba = gp->g_regkva;
	fb = gp->g_fbkva;


	if (info->set & GRFSPRSET_ENABLE)
		info->enable = RSeq (ba, SEQ_ID_CURSOR_ATTR) & 0x01;
	if (info->set & GRFSPRSET_POS)
		cl_getspritepos (gp, &info->pos);
	if (info->set & GRFSPRSET_HOT) {
		info->hot.x = 0;
		info->hot.y = 0;
	}
	if (info->set & GRFSPRSET_CMAP) {

		short *seqbase = (short *)(ba + 0x3c4);
		unsigned char *p,oldval;
		
		p=(unsigned char *)seqbase;
		*p++=0x12;
		oldval = *p;
		*seqbase = 0x1200 | oldval | 0x02;
    if(cltype==PICASSO) p = (unsigned char *)ba + (0x3c7+0xffff);
		else p = (unsigned char *)ba + 0x3c7;
		*p = 0x00;
    if(cltype==PICASSO) p = (unsigned char *)ba + (0x3c9+0xffff);
		else p = (unsigned char *)ba + 0x3c9;
		tcm = &(info->cmap);
		tcm->red[0] = (unsigned char)*p;
		tcm->green[0] = (unsigned char)*p;
		tcm->blue[0] = (unsigned char)*p;
    if(cltype==PICASSO) p = (unsigned char *)ba + (0x3c7+0xffff);
		else p = (unsigned char *)ba + 0x3c7;
		*p = 0x0f;
    if(cltype==PICASSO) p = (unsigned char *)ba + (0x3c9+0xffff);
		else p = (unsigned char *)ba + 0x3c9;
		tcm->red[1] = (unsigned char)*p;
		tcm->green[1] = *p;
		tcm->blue[1] = *p;
		*seqbase = 0x1200 | oldval;
	}
	if (info->set & GRFSPRSET_SHAPE) {
		u_char image[8*64], mask[8*64];
		u_char *hwp;
		u_char *imp, *mp;
		short row;

		/* Sprite info is arranged like this:
		 * first 8 bytes are the first scanline of bitplane1 'mask',
		 * second 8 bytes are the first scanline of bitplane0 'image',
		 * 3rd 8 bytes are the 2nd scanline of bitplane 1, and so on..
		 * (actually 5426 docs say the first 8 bytes should be the first
		 * scanline of plane 0...)
		 */

		info->size.x = 64;
		info->size.y = 64;
		for (row = 0, hwp = (u_char *)(fb+(MEM_SIZE(gp) - (16*1024))),
		    mp = mask, imp = image;
		    row < 64;
		    row++) {
			*mp++=*hwp++;
			*mp++=*hwp++;
			*mp++=*hwp++;
			*mp++=*hwp++;
			*mp++=*hwp++;
			*mp++=*hwp++;
			*mp++=*hwp++;
			*mp++=*hwp++;

			*imp++=*hwp++;
			*imp++=*hwp++;
			*imp++=*hwp++;
			*imp++=*hwp++;
			*imp++=*hwp++;
			*imp++=*hwp++;
			*imp++=*hwp++;
			*imp++=*hwp++;
		}
		copyout (image, info->image, sizeof (image));
		copyout (mask, info->mask, sizeof (mask));
	}
	return(0);
}

int
cl_setspriteinfo (gp, info)
	struct grf_softc *gp;
	struct grf_spriteinfo *info;
{
	volatile unsigned char *ba, *fb;
	u_char control;
	short *srbase;
	short *grbase;

	ba = gp->g_regkva;
	fb = gp->g_fbkva;

	if (info->set & GRFSPRSET_SHAPE) {
		/*
		 * For an explanation of these weird actions here, see above
		 * when reading the shape.  We set the shape directly into
		 * the video memory, there's no reason to keep 1k on the
		 * kernel stack just as template
		 */
		volatile u_char *ip,*mp,moff;
		u_char *image, *mask;
		volatile u_char *pmem,tmask,bpl,*grbase;
		short row,col;

		if (info->size.y > 64)
			info->size.y = 64;
		if (info->size.x > 64)
			info->size.x = 64;


		image = malloc(1024/2, M_DEVBUF, M_WAITOK);
		mask = malloc(1024/2, M_DEVBUF, M_WAITOK);
		/* 1 plane of image data and 1 plane of 'mask' data */
		copyin(info->image, image, ((info->size.y * info->size.x / 8)+
			(((info->size.x*info->size.y) % 8) ? 1 : 0)));
		copyin(info->mask, mask, (info->size.y * info->size.x / 8)+
			(((info->size.x*info->size.y) % 8) ? 1 : 0));

		pmem = fb + MEM_SIZE(gp) - 16*1024;
		ip = image;
		mp = mask;

		bpl = (info->size.x / 8) + ((info->size.x % 8)?1:0); /* bytes per line */

		row=0;
		while(row<64){
			/* line from plane 1 'mask' */
			col=0;
			while(col<8){
			    if(bpl > col)
				*pmem++ = *(ip+col+(row*bpl));
			    else{
				if(bpl == col){
					moff = info->size.x - col*8;
					moff = 8-moff;
					tmask = (1 << moff)-1;
					*pmem++ = (*(ip+col+(row*bpl)))
					  & ~tmask;
				}else
					*pmem++ = 0;
			    }
			    col++;
			}

			/* line from plane 0 'image' */
			col=0;
			while(col<8){
			    if(bpl > col)
				*pmem++ = *(mp+col+row*bpl);
			    else{
				if(bpl == col){
					moff = info->size.x - col*8;
					moff = 8-moff;
					tmask = (1 << moff)-1;
					*pmem++ = (*(mp+col+row*bpl)) & ~tmask;
				}else
					*pmem++ = 0;
			    }
			    col++;

			}

			row++;
		}
		free(image,M_DEVBUF);
		free(mask,M_DEVBUF);
		CLSetupHWC(gp, 1, 0, 0, 0, 0);
	}
	if (info->set & GRFSPRSET_CMAP) {
		volatile unsigned char oldval,*cp,i;
		struct grf_colormap *tmpcmap;

		cp = ba + 0x3c4;
		srbase = (unsigned short *)cp;
		grbase = (unsigned short *)(ba + 0x3c8);
		*cp = 0x12;
		cp++;
		oldval = *cp--;
		*srbase = 0x1200 | oldval | 0x02;	/* enable DAC extended colors */ 
		
		if(info->cmap.index == 0){
			*grbase++ = 0x00;
			*grbase = info->cmap.red[0];
			*grbase = info->cmap.green[0];
			*grbase-- = info->cmap.blue[0];
		}
		if((info->cmap.index == 1) || (info->cmap.count ==2)){
			*grbase++ = 0x0f;
			if(info->cmap.index == 1)
				i=0;
			else
				i=1;
			tmpcmap = &(info->cmap);
			*grbase = (tmpcmap+i)->red[1];
			*grbase = (tmpcmap+i)->green[1];
			*grbase = (tmpcmap+i)->blue[1];
		}
		*srbase = 0x1200 | oldval;
	}
	if (info->set & GRFSPRSET_ENABLE) {
		if (info->enable)
			control = 0x05;
		else
			control = 0x04;
		WSeq(ba, SEQ_ID_CURSOR_ATTR, control);
	}
	if (info->set & GRFSPRSET_POS)
		cl_setspritepos(gp, &info->pos);
	if (info->set & GRFSPRSET_HOT) {
		return(EINVAL);
	}

	return(0);
}

int
cl_toggle(gp,wopp)
  struct grf_softc *gp;
	unsigned short wopp; /* don't need that one yet, ill */
{

  volatile unsigned char *ba;

	ba = gp->g_regkva;

 switch (cltype)
 {
 case SPECTRUM :
  if(bah_toggle) 
  {  
   WPass(ba, wakepass);
   WPass(ba, onpass);
  } 
  else
  {  
   WPass(ba, offpass);
  }  
  bah_toggle=(bah_toggle==0?1:0);
  break;
 case PICASSO :
  if(bah_toggle)
  {
   WPass(ba, wakepass);
   delay(10000);
   WPassP(ba, onpass);
   delay(10000);
  }
  else
  {  
   WPassP(ba, offpass);
   delay(10000);
  }
  bah_toggle=(bah_toggle==0?1:0);
  break;
  case PICCOLO :
  if(bah_toggle)
  {
   *(ba + 0x8000) |= 0x10;
   delay(10000);
   *(ba + 0x8000) &= 0xDF;
   delay(10000);
  }
  else
  {
   *(ba + 0x8000) |= 0x20;
   delay(10000);
  }
  bah_toggle=(bah_toggle==0?1:0);
  break;
 }
  return(0);
}

int
cl_getspritemax (gp, pos)
	struct grf_softc *gp;
	struct grf_position *pos;
{
	pos->x = 64;
	pos->y = 64;

	return(0);
}


int
cl_bitblt (gp, bb)
	struct grf_softc *gp;
	struct grf_bitblt *bb;
{
	struct MonDef *md = (struct MonDef *)gp->g_data;
	if(md->DEP == 4)return -1;	/* not supported yet */
	if (md->DEP == 8){
		CLBitBlit(gp, bb);
		return 0;
	}else{
		CL16BitBlit(gp,bb);
		return 0;
	}
}
#endif	/* GRF_CL5426 */

