/*
 * BDM2: Banked dumb monochrome driver
 * Pascal Haible 8/93, haible@izfm.uni-stuttgart.de
 *
 * bdm2/driver/apollo/apollodriv.c
 * Hamish Coleman 11/93 hamish@zot.apana.org.au
 *
 * derived from:
 * hgc1280/*
 * Pascal Haible 8/93, haible@izfm.uni-stuttgart.de
 * hga2/*
 * Author:  Davor Matic, dmatic@athena.mit.edu
 * and
 * vga256/*
 * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
 *
 * Thanks to Herb Peyerl (hpeyerl@novatel.ca) for the information on 
 * programming this card.
 *
 * see bdm2/COPYRIGHT for copyright and disclaimers.
 */

/* $XFree86: mit/server/ddx/x386/bdm2/drivers/apollo/apollodriv.c,v 2.0 1994/04/10 05:54:10 dawes Exp $ */

#include "X.h"
#include "input.h"
#include "screenint.h"

#include "compiler.h"

#include "x386.h"
#include "x386Priv.h"
#include "xf86_OSlib.h"
#include "xf86_Config.h"
#include "bdm.h"
#include "apolloHW.h"
#ifdef NOTYET
#include "mfbfuncs.h"
#endif

int apollo_Current_mode = apollo_Textmode;

/*
 * Define the Apollo I/O Ports
 */
unsigned Apollo_IOBASE = AP_PORT_BASE;

unsigned Apollo_IOPorts[16] = {AP_PORT_BASE, AP_PORT_BASE + 1, AP_PORT_BASE + 2, AP_PORT_BASE + 3,
			       AP_PORT_BASE + 4, AP_PORT_BASE + 5, AP_PORT_BASE + 6, AP_PORT_BASE + 7,
			       AP_PORT_BASE + 8, AP_PORT_BASE + 9, AP_PORT_BASE + 0x0a, AP_PORT_BASE + 0x0b,
			       AP_PORT_BASE + 0x0c, AP_PORT_BASE + 0x0d, AP_PORT_BASE + 0x0e, AP_PORT_BASE + 0x0f};
			       
int Num_Apollo_IOPorts = (sizeof(Apollo_IOPorts)/sizeof(Apollo_IOPorts[0]));

char *	ApolloIdent();
Bool	ApolloProbe();
void	ApolloEnterLeave();
void *	ApolloInit();
void *	ApolloSave();
void	ApolloRestore();
void	ApolloAdjust();
Bool	ApolloSaveScreen();
void	ApolloGetMode();
void	ApolloFbInit();

extern int ApolloDoBitblt();

/* Assembler functions in apolloBank.s
 * - to be called by assembler functions only! */
/* They are empty for this card */
extern void ApolloSetRead();
extern void ApolloSetWrite();
extern void ApolloSetReadWrite();

#if 0
/* From bdm.h -- see there, this here might not be up to date */
/*
 * structure for accessing the video chip`s functions
 *
 * We are doing a total encapsulation of the driver's functions.
 * Banking (bdmSetReadWrite(p) etc.) is done in bdmBank.c
 *   using the chip's function pointed to by
 *   bmpSetReadWriteFunc(bank) etc.
 */
typedef struct {
  char * (* ChipIdent)();
  Bool (* ChipProbe)();
  void (* ChipEnterLeave)();
  void * (* ChipInit)();
  void * (* ChipSave)();
  void (* ChipRestore)();
  void (* ChipAdjust)();
  Bool (* ChipSaveScreen)();
  void (* ChipGetMode)();
  /* These are the chip's banking functions:		*/
  /* they do the real switching to the desired bank	*/
  /* they 'become' bdmSetReadFunc() etc.		*/
  void (* ChipSetRead)();
  void (* ChipSetWrite)();
  void (* ChipSetReadWrite)();
  /* Bottom and top of the banking window (rel. to ChipMapBase)	*/
  /* Note: Top = highest accessable byte + 1			*/
  void *ChipReadBottom;
  void *ChipReadTop;
  void *ChipWriteBottom;
  void *ChipWriteTop;
  /* Memory to map      */
  int ChipMapBase;
  int ChipMapSize;      /* replaces MEMTOMAP */
  int ChipSegmentSize;
  int ChipSegmentShift;
  int ChipSegmentMask;
  Bool ChipUse2Banks;
  /* Display size is given by the driver */
  int ChipHDisplay;
  int ChipVDisplay;
  /* In case Scan Line in mfb is longer than HDisplay */
  int ChipScanLineWidth;
} bdmVideoChipRec, *bdmVideoChipPtr;
#endif /* 0 */

bdmVideoChipRec APOLLO = {
  /* Functions */
  ApolloIdent,
  ApolloProbe,
  ApolloEnterLeave,
  ApolloInit,
  ApolloSave,
  ApolloRestore,
  ApolloAdjust,
  ApolloSaveScreen,
  NoopDDA,			/* ApolloGetMode */
#ifdef notyet
  ApolloFbInit,			/* Initialize acclerated functions */
#endif
  ApolloSetRead,
  ApolloSetWrite,
  ApolloSetReadWrite,
  (void *)AP_BANK_BOTTOM,	/* ReadBottom */
  (void *)AP_BANK_TOP,		/* ReadTop */
  (void *)AP_BANK_BOTTOM,	/* WriteBottom */
  (void *)AP_BANK_TOP,		/* WriteTop */
  AP_MAP_BASE,			/* MapBase */
  AP_MAP_SIZE,			/* MapSize */
  AP_SEGMENT_SIZE,		/* SegmentSize */
  AP_SEGMENT_SHIFT,		/* SegmentShift */
  AP_SEGMENT_MASK,		/* SegmentMask */
  TRUE,				/* Use2Banks */
  /* for this non banking card this means the bitblt code can read from
   * source and write to dest. without having to bank within */
  AP_HDISPLAY,			/* HDisplay */
  AP_VDISPLAY,			/* VDisplay */
  AP_SCAN_LINE_WIDTH,		/* ScanLineWidth */
};

/*
 * ApolloIdent
 */

char *
ApolloIdent(n)
	int n;
{
static char *chipsets[] = {"apollo9"};
if (n >= sizeof(chipsets) / sizeof(char *))
	return(NULL);
else return(chipsets[n]);
}

/*
 * ApolloProbe --
 *      check whether an Apollo ID-9 board is installed
 */

Bool
ApolloProbe()
{
#ifndef OPTION_SECONDARY
#define OPTION_SECONDARY 23
  /*
   * If you have a 2.0 server then you will have to hardwire the
   * following if statement and delete this error line
   */
#error You need to configure primary/secondary port
#endif

  /*
   * Set up I/O ports to be used by this card
   */
  if (OFLG_ISSET(OPTION_SECONDARY, &bdm2InfoRec.options)) {
  	int i;
  	
  	/* option "secondary" */
  	Apollo_IOBASE = AP_PORT_ALTERNATE;
  	APOLLO.ChipMapBase = AP_MAP_ALTERNATE;
  	
  	for (i=0;i<Num_Apollo_IOPorts;i++)
  		Apollo_IOPorts[i] = AP_PORT_ALTERNATE + i;
  } else {
  	/* assume primary */
  	Apollo_IOBASE = AP_PORT_BASE;
  }

  xf86ClearIOPortList(bdm2InfoRec.scrnIndex);
  xf86AddIOPorts(bdm2InfoRec.scrnIndex, Num_Apollo_IOPorts, Apollo_IOPorts);

  if (bdm2InfoRec.chipset) {
	/* Chipset preset */
	if (strcmp(bdm2InfoRec.chipset, ApolloIdent(0)))
		/* desired chipset != this one */
		return (FALSE);
	else {
		ApolloEnterLeave(ENTER);
		/* go on with videoram etc. below */
	}
  }
  else {
	unsigned char dsp;
	Bool found=FALSE;

	ApolloEnterLeave(ENTER);
	/*
	 * Checks if there is a Apollo ID 09 board in the system.
	 *
	 *
	 */
	dsp = inb(AP_PORT_DEVICE_ID);

	if (dsp == AP_MONO_HIRES)
		found=TRUE;
	
	if ( !found ) {
		ApolloEnterLeave(LEAVE);
		return(FALSE);
	}

	bdm2InfoRec.chipset = ApolloIdent(0);

  } /* else (bdm2InfoRec.chipset) */
  if (Apollo_IOBASE != AP_PORT_BASE) {
	ErrorF("%s %s: %s: Using secondary address\n",
	XCONFIG_GIVEN, bdm2InfoRec.name, bdm2InfoRec.chipset);
  } else {
	ErrorF("%s %s: %s: Using primary address\n",
	XCONFIG_PROBED, bdm2InfoRec.name, bdm2InfoRec.chipset);
  }
  if (!bdm2InfoRec.videoRam) {
	/* videoram not given in Xconfig */
	bdm2InfoRec.videoRam=256;
  }
  /* We do 'virtual' handling here as it is highly chipset specific */
  /* Screen size (pixels) is fixed, virtual size can be larger up to
   * ChipMaxVirtualX and ChipMaxVirtualY */
  /* Real display size is given by AP_HDISPLAY and AP_VDISPLAY,
   * desired virtual size is bdm2InfoRec.virtualX and bdm2InfoRec.virtualY.
   * Think they can be -1 at this point.
   * Maximum virtual size as done by the driver is
   * AP_MAX_VIRTUAL_X and ..._Y
   */
   if (!(bdm2InfoRec.virtualX < 0)) {
	/* virtual set in Xconfig */
	ErrorF("%s %s: %s: Virtual not allowed for this chipset\n",
		XCONFIG_PROBED, bdm2InfoRec.name, bdm2InfoRec.chipset);
   }
   /* Set virtual to real size */
   bdm2InfoRec.virtualX = AP_HDISPLAY;
   bdm2InfoRec.virtualY = AP_VDISPLAY;
   
   /* Initialize option flags allowed for this driver */
   OFLG_SET(OPTION_SECONDARY, &APOLLO.ChipOptionFlags);
   OFLG_SET(OPTION_NOACCEL, &APOLLO.ChipOptionFlags);

   /* Must return real display size */
   /* hardcoded in APOLLO */
   return(TRUE);
}

/*
 * ApolloFbInit --
 *	enable speedups
 */
void
ApolloFbInit()
{
  if (!OFLG_ISSET(OPTION_NOACCEL, &bdm2InfoRec.options))
    {
      if (x386Verbose)
        {
          ErrorF ("%s %s: Using accelerator functions\n",
          	  XCONFIG_PROBED, bdm2InfoRec.chipset);
        }
        
#ifdef NOTYET
      mfbLowlevFuncs.doBitblt = ApolloDoBitblt;
#endif
    }
}

/*
 * ApolloEnterLeave --
 *      enable/disable io permissions
 */

void 
ApolloEnterLeave(enter)
     Bool enter;
{
  if (enter)
	xf86EnableIOPorts(bdm2InfoRec.scrnIndex);
  else
	xf86DisableIOPorts(bdm2InfoRec.scrnIndex);
}

/*
 * ApolloInit --
 *      Handle the initialization of the Apollo's registers
 */

void *
ApolloInit(mode)
     DisplayModePtr mode;
{
return((void *)apollo_Graphmode);
}

/*
 * ApolloSave --
 *      save the current video mode
 */

void *
ApolloSave(save)
{
return((void *)apollo_Current_mode);
}

/*
 * ApolloRestore --
 *      restore a video mode
 */

void
ApolloRestore(restore)
{
    if ((int)restore==apollo_Textmode) {

	/* Blank the screen */
	
	/* Set text mode */

	/* Unblank the screen */

        apollo_Current_mode=apollo_Textmode;
        
    } else if ((int)restore==apollo_Graphmode) {

	outb(AP_PORT_CONTROL_3,AP_RESET_CREG);
	outw(AP_PORT_ROP, AP_ROP_SRC|(AP_ROP_SRC<<4)|(AP_ROP_SRC<<8)|(AP_ROP_SRC<<12) );
	outb(AP_PORT_CONTROL_0,AP_MODE_NORMAL);
	outb(AP_PORT_CONTROL_1,(AP_BLT_NORMAL | AP_ROP_DISABLE | AP_CREG1_NORMAL));
	outb(AP_PORT_CONTROL_2,AP_DATA_PLN);
	outw(AP_PORT_WRITE_ENABLE,0x0);

        apollo_Current_mode=apollo_Graphmode;

    } else ErrorF("Warning: ApolloRestore called with invalid arg.\n");
}

/*
 * ApolloSaveScreen();
 *	Disable the video on the frame buffer (screensaver)
 */

Bool
ApolloSaveScreen(pScreen,on)
	ScreenPtr pScreen;
	Bool      on;
{
if (on == SCREEN_SAVER_FORCER)
	SetTimeSinceLastInputEvent();
if (x386VTSema) {
	if (on) { /* Grrr! SaveScreen(on=TRUE) means turn ScreenSaver off */
		outb(AP_PORT_CONTROL_3,AP_BIT_DISP|AP_ON);
/*		outb(AP_PORT_CONTROL_1,(AP_BLT_AD | AP_ROP_DISABLE | AP_CREG1_NORMAL)); */
	} else {
		outb(AP_PORT_CONTROL_3,AP_BIT_DISP|AP_OFF);
/*		outb(AP_PORT_CONTROL_1,(AP_BLT_AD | AP_CREG1_NORMAL) & ~AP_DISP_ENABLE); */
	}
} /* if we are not on the active VT, don't do anything - the screen
   * will be visible as soon as we switch back anyway (?) */
return(TRUE);
}

/* ApolloAdjust --
 *      adjust the current video frame to display the mousecursor
 *      (x,y) is the upper left corner to be displayed.
 */
void
ApolloAdjust(x,y)
	int x, y;
{
}
