/*  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.
 */


/***
 *** ClockProg: an attempt to get ALL known chipsets in one program for use as a "ClockProg"
 ***            program. This is useful for XFREE86, where the built-in clock chips don't support
 ***            text clock restoration
 ***            It also enables the low clocks needed for 320x200 modes in X, which X seems to
 ***            deny, despite the "divide-by-2" mode that all VGA's have.
 ***
 *** Originated as ET4000W32p with ICS GenDAC ICS5431 (Tseng version of S3 ICS5430) ClockProg
 *** 
 *** (c) 1995 Koen Gadeyne (kmg@barco.be)
 ***
 ***/

#include "misc.h"

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

#include "vga_prg.h"
#include "setclock.h"
#include "parse_clock.h"
#include "parse_opt.h"
#include "confdefs.h"
#include "configfile.h"
#include "validate.h"
#include "messages.h"

char *CommandName;
char ConfigFile[1024]=CLOCK_CONF_FILE;
int debug_messages=FALSE;

void usage()
{
     PMESSAGE(("version %s. (c) 1995 Koen Gadeyne.\n Usage: %s [options] Frequency Index\n\n\
     Options: -n  Don't program VGA hardware (don't do actual pixel clock programming)\n\
              -d  print debugging information\n\
              -h  print usage information\n\
              -t <ConfigFile>  Use alternative config file instead of the default\n\
                               (= %s if that exists, or %s otherwise)\n\n\
     Frequency: A pixel clock frequency in MHz\n\
     Index: The index in the list of available pixel clocks (for compatibility with XFREE86 -- not used)\n",
     VERSION, CommandName, CLOCK_CONF_FILE, CONFIGFILE));
}

/****************************************************************************************************************************/

int main (int argc, char* argv[])
{
  int program_hardware=TRUE;
  int chipset=CS_NONE;
  const char *str_chipsets[NUM_CHIPSETS] = CHIPSET_STRINGS;
  FILE *param_file;
  float freq;
  int optionmask;
  t_clockdef ck;
  char c;
  float realclock;
  int index;
  char tempstr[1024]="";
    
 /*
  * check if default config file exists. If not, use TextConfig.
  */
  
  if ((param_file=fopen(ConfigFile,"r"))==NULL) strcpy(ConfigFile, CONFIGFILE);
  else fclose(param_file);

 /*
  * command-line argument parsing
  */

  CommandName = argv[0];

  while ((c = getopt (argc, argv, "ndht:")) != EOF)
    switch (c)
    {
      case 'n': program_hardware=FALSE;
                break;
      case 'd': debug_messages=TRUE;
                break;
      case 'h': usage();
                exit(0);
                break;
      case 't': strcpy(ConfigFile, optarg);
                break;
      case '?': usage();
                PERROR(("Bad option '-%c'\n",(char)optopt));
                exit(-1);
                break;
      default: PERROR(("getopt returned unknown token '%c'.",c));
    }
   
  PVERSION

  if (argc<optind+2)
  {
    usage();
    PERROR(("Not enough parameters on command line."));
  }

  /* first argument: clock freq in MHz */
  freq = getfloat(argv[optind], "clock frequency", 1, 500);
  
  /* second argument: clock index */
  optind++;
  index = getbyte(argv[optind], "clock index", 0, 127);


 /*
  * open parameter file
  */
  param_file = open_param_file(ConfigFile);


 /*
  * get chipset definition
  */
  sscanf(findlabel(param_file, "ChipSet", LABEL_REQUIRED+LABEL_FROMSTART), "%*s %s", tempstr);
  chipset = findoption(tempstr, str_chipsets, NUM_CHIPSETS, "chip set");


 /*
  * Option parsing. Not all chips support all options
  */

  optionmask = parse_opt(param_file, chipset, str_chipsets[chipset]);

 /*
  * parse clock configuration in config file, fill out structure with info
  */

  parse_clock(param_file, chipset, &ck);
  if (ck.type & CK_CLOCKPROG) PERROR(("Asking for a ClockProg inside a Clockprog is useless and dangerous!"));
  
  if (ck.type & CK_SET_OF_CLOCKS)
  {
    validate_clock(chipset, &ck, freq, &realclock, optionmask, TRUE);
    freq = realclock;   /* replace with actual clock from clocks line */
  }

 /*
  * Close the config file. We don't need it anymore.
  */

  fclose(param_file);
  
  /* 3rd argument: memory clock */
  optind++;
  if (argc > optind)
  {
    if (ck.MClk != MCLK_NOT_DEFINED) PDEBUG(("Overriding MClk in config file by value on command line"));
    ck.MClk = getfloat(argv[optind], "memory clock", 12.5, 127);
    PDEBUG(("MClk on commandline = %3.2f", ck.MClk));
  }

 /*
  * Check if Mclk is allowed
  */

  if ( !(ck.type & CK_CLOCKCHIP) && (ck.MClk != MCLK_NOT_DEFINED) )
  {
    PERROR(("Setting MClock is only allowed on ClockChips"));
  }
  
 /*
  * finally do it... maybe
  */
  
  if (program_hardware)
  {
    get_VGA_io_perm(chipset);

    /* sync disks if requested. Is there any way to do this and be SURE _all_ data has been flushed? */
    if (optionmask & OPT_SYNC)
    {
      PDEBUG(("Syncing disks..."));
      sync(); sleep(2); /* same as in "reboot" command. Hopefully enough */
    }

    unlock(chipset);

    PMESSAGE(("Setting Pixel Clock to %1.2f MHz.", freq));    
    do_clock(chipset, &ck, freq, 0, optionmask);

    special(chipset); /* change chipset-specific things, if needed */

  }
  return(0);
}

