/*
 * vesainfo.c
 *
 * Dump information about what VESA graphics modes are supported.
 */

#include <string.h>
#include <stdio.h>
#include <console.h>
#include <com32.h>
#include <inttypes.h>
#include "../lib/sys/vesa/vesa.h"

/* Wait for a keypress */
static void wait_key(void)
{
  char ch;
  while (fread(&ch, 1, 1, stdin) == 0)
    ;
}

static void print_modes(void)
{
  static com32sys_t rm;
  struct vesa_general_info *gi;
  struct vesa_mode_info *mi;
  uint16_t mode, *mode_ptr;
  int lines;

  /* Allocate space in the bounce buffer for these structures */
  gi = &((struct vesa_info *)__com32.cs_bounce)->gi;
  mi = &((struct vesa_info *)__com32.cs_bounce)->mi;

  gi->signature = VBE2_MAGIC;	/* Get VBE2 extended data */
  rm.eax.w[0] = 0x4F00;		/* Get SVGA general information */
  rm.edi.w[0] = OFFS(gi);
  rm.es      = SEG(gi);
  __intcall(0x10, &rm, &rm);

  if ( rm.eax.w[0] != 0x004F ) {
    printf("No VESA BIOS detected\n");
    return;
  } else if ( gi->signature != VESA_MAGIC ) {
    printf("VESA information structure has bad magic, trying anyway...\n");
  }

  printf("VBE version %d.%d\n"
	 "Mode   attrib h_res v_res bpp layout rpos gpos bpos\n",
	 (gi->version >> 8) & 0xff, gi->version & 0xff);

  lines = 1;

  mode_ptr = GET_PTR(gi->video_mode_ptr);

  while ((mode = *mode_ptr++) != 0xFFFF) {
    if (++lines >= 23) {
      wait_key();
      lines = 0;
    }

    rm.eax.w[0] = 0x4F01;	/* Get SVGA mode information */
    rm.ecx.w[0] = mode;
    rm.edi.w[0] = OFFS(mi);
    rm.es  = SEG(mi);
    __intcall(0x10, &rm, &rm);

    /* Must be a supported mode */
    if ( rm.eax.w[0] != 0x004f )
      continue;

    printf("0x%04x 0x%04x %5u %5u %3u %6u %4u %4u %4u\n",
	   mode, mi->mode_attr, mi->h_res, mi->v_res, mi->bpp,
	   mi->memory_layout, mi->rpos, mi->gpos, mi->bpos);
  }
}

int main(void)
{
  openconsole(&dev_rawcon_r, &dev_stdcon_w);

  print_modes();
  return 0;
}
