/*
 * DANG_BEGIN_MODULE
 *
 * Description:
 *   ARK driver for DOSEMU.  Code taken from SVGALIB. 
 * 
 *   Original driver Copyright (c) 1993 Harm Hanemaayer and
 *         partially copyrighted (C) 1993 by Hartmut Schirmer
 *
 * DANG_END_MODULE
 *
 * $Date: $
 * $Source: $
 * $Revision: $
 * $State: $
 *
 * $Log: $
 */

#include "dosemu.h"
#include "base/port.h"
#include "env/libvga.h"

#define SEG_SELECT 0x3CD

static int et3000_memory;

static void et3000_getperm(void)
{
}

static void et3000_releaseperm(void)
{
}

static void et3000_setpage(int page)
{
	outw(SEG_SELECT, page | (page << 3) | 0x40);
}

static void et3000_unlock(void)
{
	/* get access to extended registers */
	int base;

	base = ( port_in( 0x3cc ) & 1 ? 0x3d0 : 0x3b0);
	port_out(3, 0x3bf);
	port_out(0xa0, base+8);
	port_out(0x24, base+4);
	port_out(port_in(base+5)&0xDF, base+5);
}

static void et3000_saveregs(Bit16u *regs)
{
    int i;

    et3000_unlock();
    /* save extended CRT registers */
    for (i = 0; i < 3; i++) {
	 port_out(0x23+i, CRT_I); 
	 regs[i] = port_in(CRT_D); 
    }

    /* save extended sequencer register */
    for (i=0; i < 2; ++i) {
      port_out(6+i, SEQ_I); 
      regs[3+i] = port_in(SEQ_D);
    }

    /* save some other ET3000 specific registers */
    regs[5] = port_in(0x3cd); 

    /* save extended attribute register */
    port_in(IS1_R);    /* reset flip flop */
    port_out(0x16, ATT_IW);
    regs[6] = port_in(ATT_R);
}

static void et3000_setregs(const Bit16u *regs)
{
    int i;
    unsigned char save;

    et3000_unlock();
    /* write some ET3000 specific registers */
    port_out(regs[5], 0x3cd);

    /* write extended sequencer register */
    for (i=0; i < 2; ++i) {
      port_out(6+i, SEQ_I); 
      port_out(regs[3+i], SEQ_D);
    }

    /* deprotect CRT register 0x25 */
    port_out(0x11, CRT_I);		  
    save = port_in(CRT_D);
    port_out(save&0x7F, CRT_D);   

    /* write extended CRT registers */
    for (i = 0; i < 3; i++) {
         port_out(0x23+i, CRT_I); 
         port_out(regs[i], CRT_D); 
    }

    /* set original CRTC 0x11 */
    port_out(0x11, CRT_I);		  
    port_out(save, CRT_D);   

    /* write extended attribute register */
    port_in(IS1_R);    /* reset flip flop */
    port_out(0x16, ATT_IW);
    port_out(regs[6], ATT_IW);
}


static Boolean et3000_init(void)
{
  et3000_memory = 512;
  v_printf("Using Tseng ET3000 driver (%d).\n", et3000_memory);
  return TRUE;
}

static Boolean et3000_test(void)
{
    unsigned char old, val;
    int  base;

    /* test for Tseng clues */
    old = port_in(0x3cd);
    port_out(old ^ 0x3f, 0x3cd);
    val = port_in(0x3cd);
    port_out(old, 0x3cd);

    /* return false if not Tseng */
    if (val != (old ^ 0x3f))
	return 0;

    /* test for ET3000 clues */
    if (port_in(0x3cc) & 1) 
	base = 0x3d4;
    else 
	base = 0x3b4;
    port_out(0x1b, base);
    old = port_in(base+1);
    port_out(old ^ 0xff, base+1);
    val = port_in(base+1);
    port_out(old, base+1);

    /* return false if not ET3000 */    
    if (val != (old ^ 0xff)) 
	return FALSE;

    /* Found ET3000 */
    return et3000_init();
}

DriverSpecs et3000_driverspecs = {
	"ET3000",
	et3000_saveregs,
	et3000_setregs,
	et3000_test,
	et3000_init,
	et3000_setpage,
	et3000_getperm,
	et3000_releaseperm,
	NULL,
	NULL
};
