/* vesa.c */
#define VESA
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dos.h>
#include "vidlib.h"
#include "vesa.h"

int   VESAmode(unsigned int mode, char *palette)
{
    union REGS r;
    unsigned int memory;   /* display memory, in 32 byte units */

    if (isVESAmode(0x101))
       memory=16384;  /* 512k */
    else
       memory=8192;  /* 256k */

    r.x.ax=0x4f02;
    r.x.bx=mode;
    int86(0x10,&r,&r);
    if ( r.h.ah == 0 ) {
       if (palette != NULL)          /* if not NULL */
          if (palette == DEFAULTDAC) /* restore defaults */
             WriteDACs(_olddacs);
          else
             WriteDACs(palette);
       getVESAinfo(mode);
       _screen_start=(char *)0xA0000000L;
       _screen_width=Vminfo.bytesperline;
       _screen_length=Vminfo.YPixels;
       _memory_length=(memory/(Vminfo.bytesperline/32));
       _window_size=(unsigned long)Vminfo.size << 10;
       VESAsetpage(0);
       return(1);
    } else
       return(0);
}

int    isVESA(void)
{
    union   REGS    r;
    struct  SREGS   s;

    r.x.ax = 0x4F00;             /* VESA BIOS call               */
    s.es = FP_SEG(&Vinfo);      /* Place address into parm list */
    r.x.di= FP_OFF(&Vinfo);
    int86x(0x10, &r, &r, &s);     /* Try VESA BIOS        */
					/* Check status and signature   */
    if ((r.x.ax != 0x004F) ||
	(strncmp(Vinfo.signature,"VESA",4) != 0) ) {
	return(0);
    }
    return(1);
}

/* returns 1 for a valid mode, 0 if not */
int    isVESAmode(int mode)
{
     union REGS r;
     struct SREGS s;

     r.h.ah=0x4f; r.h.al=0;
     s.es=FP_SEG(&Vinfo);
     r.x.di=FP_OFF(&Vinfo);
     int86x(0x10,&r,&r,&s);
     if (r.x.ax != 0x004f) {
           return(0);
     }
     if (strncmp(Vinfo.signature,"VESA",4) == 0) {
	  while ((*(Vinfo.modeptr) != EOF) &&
                 (*(Vinfo.modeptr) != mode) )
                  Vinfo.modeptr++;
          if (*Vinfo.modeptr == mode) {
             return(1);
          } else {
             return(0);
          }
     }  else {
          return(0);
     }
}

struct vesainfo *getVESAinfo(int mode)
{
    union REGS r;
    struct SREGS s;

    r.h.ah=0x4f; r.h.al=0x01; r.x.cx=mode;
    s.es=FP_SEG(&Vminfo); r.x.di=FP_OFF(&Vminfo);
    int86x(0x10,&r,&r,&s);
    if ( r.x.ax == 0x004F ) {
       return(&Vinfo);
    }  else {
       return(NULL);
    }
}

int VESAsetpage(unsigned page) /* assume window 0 */
{
  return(VESAsetpagew(0, page));
}

int  VESAsetpagew(char window, unsigned page)
{
   union REGS r;
   r.x.ax=0x4f05;
   r.h.bh=0;
   r.h.bl=window;
   r.x.dx=page;
   int86(0x10,&r,&r);
   if (r.h.ah == 0) {
      vesapage=page;
      VESAnext_break();
      return(page);
   } else {
      return(0);
   }
}

int VESAsetpagewbios(char window, unsigned page)
{
   union REGS r;

   r.h.ah=0x4f; r.h.al=5;
   r.h.bh=0;    r.h.bl=window;
   r.x.dx=page;
   int86(0x10,&r,&r);
   vesapage=page;
   VESAnext_break();
   return(!r.h.ah);
}

/* Vnext_break_row = the next line upon which a break occurs */
/* Vnext_break_col = the byte in that line that starts the next page */
void   VESAnext_break(void)
{
   Vnext_break_row=(unsigned int) (
       (_window_size*(vesapage+1)) / (long)Vminfo.bytesperline  );
   Vnext_break_col=(unsigned int) (
       (_window_size*(vesapage+1)) % Vminfo.bytesperline  );
}


