#include <stdio.h>
#include <dos.h>

#define TRUE  1
#define FALSE 0

typedef unsigned char  byte;
typedef unsigned short word;
typedef unsigned long  dword;

struct SVGAINFO {
  byte		vesa[4];		// muss "VESA" drinstehen
  word		version;		// VESA-Version
  char far	*OEMname;		// Herstellername
  byte		caps[4];		// ???
  word far	*modes;			// Ptr of array of Mode-Nr's.
  word		memory;			// video memory
  char far	*s1;
  char far	*s2;
  char far	*s3;
  byte		reserved[222];
  byte		oemdata[256];
};

struct SVGAMODEINFO  {
  word		attr;			// mode attributes
  byte		winA;			// windows A attributes
  byte		winB;			// windows B attributes
  word		gran;
  word		size;
  word		segA;
  word		segB;
  void far*	posfunc;
  word		scan;
  word		width;
  word		height;
  byte		charwidth;
  byte		charheight;
  byte		planes;
  byte		bits;
  byte		banks;
  byte		memmodel;
  byte		banksize;
  byte		num_of_im_pages;
  byte		r1;
  byte		red_mask_size;
  byte		red_field_pos;
  byte		green_mask_size;
  byte		green_field_pos;
  byte		blue_mask_size;
  byte		blue_field_pos;
  byte		reserved_mask_size;
  byte		reserved_field_pos;
  byte		direct_color_mode;
  dword		lfb_base;
  dword		off_base;
  dword		off_size;
  byte		r2[206];
};

struct PMCALLS {
  word		set_win;
  word          set_start;
  word		set_pal;
  word		access;
};

struct REGPACK       r;
struct SVGAINFO      vesa = { "VBE2" };
struct SVGAMODEINFO  vesamode;
struct PMCALLS far   *pmcalls;

/*-------------------------------------------------------------------------*/

void vgalist()
{
	int i;  

	for (i = 0; vesa.modes[i] != 0xffff; i++) {
		r.r_ax = 0x4f01;
		r.r_cx = vesa.modes[i];
		r.r_es = _DS;
		r.r_di = (word)&vesamode;
		intr(0x10,&r);

		printf(" "); 
		printf("%4xh:  ",vesa.modes[i]);

		if (!(vesamode.attr & 0x10)) {	/* graphic ? */
			printf("%4d x %4d (text)\n",
				vesamode.width,vesamode.height);
			continue;
		}

		printf("%4u x %4u x %2u  ",
			vesamode.width,vesamode.height,vesamode.bits);
		if (vesamode.bits > 8) {
			printf("%d:%d:%d:%d  ",
				vesamode.reserved_mask_size,
				vesamode.red_mask_size,
				vesamode.green_mask_size,
				vesamode.blue_mask_size);
		} else {
			printf("         ");
		}

		if (vesamode.attr & 0x80) {
			printf("0x%08lx, %2d pages",vesamode.lfb_base,
				vesamode.num_of_im_pages);
		}

		printf("\n");
		fflush(stdout);
	}
}

/*-------------------------------------------------------------------------*/

int
main()
{
	unsigned char far *pm;
	int i;

	r.r_ax = 0x4f00;
	r.r_es = _DS;
	r.r_di = (word)&vesa;
	intr(0x10,&r);
	if (r.r_ax != 0x004f) {
		puts("VESA nicht installiert");
		return(0);
	}
	printf("Version  : %u.%2.2u\n",(vesa.version >> 8) & 0xf,(vesa.version >> 4) & 0xf);
	printf("OEM Name : %Fs\n",vesa.OEMname);
	printf("memory   : %lu\n",(long)vesa.memory*64*1024);
	if (((vesa.version >> 8) & 0xf) < 2) {
		printf("need 2.0, sorry\n");
		exit(1);
	}

	r.r_ax = 0x4f0a;
	r.r_bx = 0;
	intr(0x10,&r);
	if (r.r_ax != 0x004f) {
		puts("no VESA Protected Mode Interface");
	} else {
		printf("PM calls : at %04x:%04x, len %04x\n",
		       r.r_es,r.r_di,r.r_cx);
		pm = pmcalls = MK_FP(r.r_es,r.r_di);
		printf("    win  : %04x\n",pmcalls->set_win);
		printf("    start: %04x\n",pmcalls->set_start);
		printf("    pal  : %04x\n",pmcalls->set_pal);
	}
	for (i = 0; i < r.r_cx; i++) {
		printf("%02x ",pm[i]);
		if (i % 16 == 15)
			printf("\n");
	}
	printf("\n");

	vgalist();
	return(0);
}

