/*  SVGATextMode -- An SVGA textmode manipulation/enhancement tool
 *
 *  Copyright (C) 1995  Koen Gadeyne
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */


/***
 *** grabmode/clockprobe
 *** Copyright (c) 1995 by Koen Gadeyne (kmg@barco.be)
 ***
 *** This program outputs the current text or graphics mode, in an SVGATextMode (or XF86Config-like) compatible line
 *** Should work on ANY VGA card, since it only uses standard VGA registers
 ***
 ***/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#include "misc.h"
#include "messages.h"
#include "modedata.h"

#ifdef DOS
#define get_VGA_io_perm(x)
#undef Renounce_SUID
#define Renounce_SUID
extern int optind;
#endif

char *CommandName;
int debug_messages=FALSE;

#define CLOCKPROBE  1
#define GRABMODE    2

void usage(int func)
{
     PMESSAGE(("version %s. (c) 1995 Koen Gadeyne.\n Usage: %s [options] \n\n\
     Options: -n  Don't program VGA hardware\n\
              -d  print debugging information\n\
              -r  `raw' mode: don't do any guesswork on special modes,\n\
                  just print the values as they appear in the VGA registers\n\
              -v  verbose mode (report all special VGA flags for the mode)\n\
              -h  print usage information\n\
              %s\n\n\
     NOTE: All non-standard VGA features could cause bogus results:\n\
            * interlaced modes\n\
            * modes with >= 1024 active lines (like 1280x1024 and up)\n\
            * HiColor (15/16bpp) and TrueColor (24/32bpp) modes\n\
            * modes on cards with special DAC's\n\
           The program will try to detect this and compensate\n\
           (but will issue a warning that the actual VGA timings were adjusted)\n\n",
     VERSION, CommandName,
     (func==GRABMODE) ? \
             "-X  Output compatible with XF86Config mode line\n\
                  (NOTE: grabbed graphic modes are not always correct)\n\
              -T  Output compatible with TextConfig mode line\n\
              -b  Also print blanking information\n\
              -c  Don't probe for pixel clock (just print timing information)\n"
     :       "-p  print ONLY clock value (for use in scripts, pipes, etc)\n" ));
}

/***********************************************************************************************************/
 
int main (int argc, char* argv[])
{
  int program_hardware=TRUE;
  int Xmode=MODE_UNDEFINED;
  int showblank=FALSE;
  int probe_clock=TRUE;
  int pipeable=FALSE;
  int raw_mode=FALSE;
  int verbose=FALSE;
  char* commandfilename;
  char c;
  modestruct m;
  int func;
  
  CommandName = argv[0];
  commandfilename = strrchr(CommandName, '/');
  if (commandfilename) commandfilename++;
  else commandfilename = CommandName;
  func = (!strncasecmp(commandfilename,"grab",4)) ? GRABMODE : CLOCKPROBE;

 
 /*
  * command-line argument parsing
  */

  while ((c = getopt (argc, argv, "ndrhXTbcpv")) != EOF)
    switch (c)
    {
      case 'n': program_hardware=FALSE;
                break;
      case 'd': debug_messages=TRUE;
                break;
      case 'r': raw_mode=TRUE;
                break;
      case 'X': Xmode = MODE_GRAPHICS;
                break;
      case 'T': Xmode = MODE_TEXT;
                break;
      case 'b': showblank = TRUE;
                break;
      case 'c': probe_clock = FALSE;
                break;
      case 'p': pipeable = TRUE;
                break;
      case 'v': verbose = TRUE;
                break;
      case 'h': usage(func);
                exit(0);
                break;
      case '?': usage(func);
#ifndef DOS
                PERROR(("Bad option '-%c'\n",(char)optopt));
#endif                
                exit(-1);
                break;
      default: PERROR(("getopt returned unknown token '%c'.",c));
    }

 PVERSION

/*
 * start doing something useful
 */
 
 if (program_hardware)
  {

     PWARNING(("Please be patient. This may take a while (up to 1 minute)"));

     getmode(&m, probe_clock, raw_mode);

    if (func == CLOCKPROBE)
    {
      if (pipeable)
      {
        printf("%1.2f\n", m.pclock);
      }
      else
      {
        PMESSAGE(("Estimated vertical scanrate = %1.3f Hz.", m.vert_refresh));
        PMESSAGE(("Estimated horizontal scanrate = %1.3f kHz.", m.hor_freq));
        PMESSAGE(("Estimated pixel clock = %1.2f MHz", m.pclock));
        if (m.mode_flags & CLOCKDIV2) PMESSAGE(("NOTE: actual clock is %1.2f MHz, but it is divided by 2.", m.pclock*2));
      }
    }
    else
    {
      /*
       * From parameters, look for special settings that affect the output
       */
       
       /* auto selection between graphics/text mode if not defined on command line */
       if (Xmode==MODE_UNDEFINED) Xmode = m.txt_gr_mode;
       
      /*
       * Print the mode line
       */
       
      if (Xmode==MODE_TEXT)
        printf("\"%dx%d\"   ", m.activepix/8, m.activelines/m.font_height);
      else 
        printf("\"%dx%d\"   ", m.activepix, m.activelines);

      if (probe_clock)
        printf("%1.3f", m.pclock);
      else
        printf("***");
              
      printf("   %d %d %d %d   %d %d %d %d   %cHsync %cVsync",
             m.activepix, m.start_hsync, m.stop_hsync, m.totalh, m.activelines, m.start_vsync, m.stop_vsync, m.totalv,
             (m.h_polarity > 0) ? '+' : '-', (m.h_polarity > 0) ? '+' : '-');
             
      if (m.mode_flags & DOUBLESCAN) printf("  DoubleScan");
      if (m.mode_flags & MULTISCAN) printf("  %sScan", m.font_height==2 ? "Double" : "Multi");

      if (Xmode==MODE_TEXT) printf("  font %dx%d", m.font_width, m.font_height);
      
      if (probe_clock)    
        printf("   # %1.3fkHz/%1.2fHz\n", m.hor_freq, m.vert_refresh);
      else
        printf("\n");
        
      if (showblank)
        printf("#   Blanking: H=%d-%d ; V=%d-%d\n", m.starthbl, m.endhbl, m.startvbl, m.endvbl);
        
      if (verbose)
      {  
        printf("#   Active special VGA register flags: ");
        if (!m.mode_flags) printf("none.");
        if (m.mode_flags & DOUBLESCAN)      printf("DOUBLESCAN ");
        if (m.mode_flags & CLOCKDIV2)       printf("CLOCKDIV2 ");
        if (m.mode_flags & MULTISCAN)       printf("MULTISCAN ");
        if (m.mode_flags & BYTEMODE)        printf("BYTEMODE ");
        if (m.mode_flags & WORDMODE)        printf("WORDMODE ");
        if (m.mode_flags & DOUBLEWORDMODE)  printf("DOUBLEWORDMODE ");
        if (m.mode_flags & VERT_DOUBLE)     printf("VERT_DOUBLE ");
        if (m.mode_flags & PCS_DIV2)        printf("PCS_DIV2 ");
        if (m.mode_flags & CNT_BY_2)        printf("CNT_BY_2 ");
        if (m.mode_flags & INTERLACE)       printf("INTERLACE ");
        if (m.mode_flags & SHIFT_CGA256C)   printf("SHIFT_CGA256C ");
        if (m.mode_flags & SHIFT_CGA4C)     printf("SHIFT_CGA4C ");
        printf("\n");
      }  
    }    
  }
  return(0);
}
