/*
  virge.c

  Basic stuff to try and get my ViRGE knowledge happening.

  Must be run as root.

 */

#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <asm/io.h>

void virge_wakeup(void)
{
  /*
    equiv ia32 asm:
 
      mov dx, 3c3h
      mov al, 01h
      out dx, al       // outb(0x01, 0x03c3)

      mov dx, 3cch
      in al, dx        // al = inb(0x03cc) 

      [load CRTCs]

      mov dx, 3c6h  
      mov al, ffh
      out dx, al       // outb(0xff, 0x03c6)

   */

  int a = 0x00000000;

  a = inb(0x3c3);
  printf("0x03c3: %s\n", (a|0x01)?"true":"false");
  if (!a)
    outb(a & 0x01, 0x3c3);
  
  a = 0x00000000;
  a = inb(0x3cc);
  printf("0x03cc: %d\n", a);
  
  a = 0x00000000;
  a = inb(0x3c6);
  printf("0x3c6: %d\n", a);
  
}

void virge_unlock(void)
{
  /* 
     equiv ia32 asm:
       
   */
  u_char cr40 = 0x00;

  /* unlock SR8 (S3 Extended Sequnecer registers) */
  outb(0x08, 0x3c4);
  outb(0x06, 0x3c4+1);
  /* unlock CRTC registers CR2D-CR3F */
  outb(0x38, 0x3d4);
  outb(0x48, 0x3d4+1);
  /* unlock CRTC registers CR40-CRFF */
  outb(0x39, 0x3d4);
  outb(0xa5, 0x3d4+1);
  /* unlock Enhanced Programming registers */
  outb(0x40, 0x3d4);
  cr40 = inb(0x3d4+1);
  cr40 |= 0x01; /* set bit 0 */
  outb(cr40, 0x3d4+1);
  
}

void virge_lock(void)
{
  /* dunno */
}

int virge_detect(void)
{
  u_char cr2e = 0x00;
  outb(0x2e, 0x3d4);
  cr2e = inb(0x3d4+1);
  printf("cr2e: 0x%2x\n", cr2e);
  return cr2e;
}

void virge_mmiostatus(void)
{
  u_char cr53 = 0x00;

  outb(0x53, 0x3d5);
  cr53 = inb(0x3d5+1);
  printf("CR53: %d\n", cr53);

}

int main(int argc, char **argv)
{
  
  /* get access to all ports... */
  if (iopl(3) < 0)
    {
      if (errno == EINVAL)
	printf("Invalid iopl() level\n");
      else if (errno == EPERM)
	printf("You\'re not root\n");
      return -1;
    }
  
  /* wakeup the virge */
#if 0
  virge_wakeup();
  virge_unlock();
#endif
  virge_mmiostatus();
  if (virge_detect() == 0x31)
    printf("You have a ViRGE!\n");
  else
    printf("ViRGE not found!\n");
  virge_lock();

  return 0;
}
