/* reads Headlands chipset registers 
 * rough translation from pascal source
 */
/*
 * Copyright: GNU Public License 2 applies
 *
 *   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, 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.
 *
 * rdshasta (C) Heiko Eissfeldt heiko@colossus.escape.de
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <asm/io.h>

#undef SYNTAXCHECK

unsigned char addr_indexreg, datreg,
     ramaddressreg, datatransferport;
int  addr_index, ramaddress, value;
char whattodo[99];
FILE *cset;
unsigned char bit;

#define cli
#define sti
#define highvideo()
#define normvideo()

#define BOOL int
#define true 1
#define false 0


void errorexit (char *x, unsigned short n)
{
  fprintf(stderr, x);
  exit(n);
}

char *Hexbyte(unsigned char zahl)
{
  const char Hexdigits[16] = "0123456789ABCDEF";
  static char hexbyte[3];

  hexbyte[0] = Hexdigits[zahl >> 4];
  hexbyte[1] = Hexdigits[zahl & 0x0F];
  hexbyte[2] = 0;
  return hexbyte;
}

char *wbin(unsigned char bmask, unsigned char p)
{
  static unsigned char localstr[9], *localst;
  int local;

  localst = localstr;
  for (local = 1; local <= 8; local++) {
    if (bmask & 128) {
       if (p & 128) {
         *localst++ = '1';
       } else {
         *localst++ = '0';
       }
    }
    p = p << 1;
    bmask = bmask << 1;
  }
  *localst = 0;
  return localstr;
}

void upstr (char *x)
{
  while (*x) *x++ = toupper(*x);
}

unsigned char getreg (int addr_index)
{
#ifdef SYNTAXCHECK
  return 0;
#else
  unsigned char retval;

  cli;
  if (addr_index != -1 ) { /*&&&*/
    outb(addr_index, addr_indexreg);
  }
  retval = inb(datreg);
  sti;
  return retval;
#endif
}

unsigned char getregd (int ramaddress, int value)
{
#ifdef SYNTAXCHECK
  return 0;
#else
  unsigned char retval;

  cli;
  if (ramaddress != -1) {
    outb( ramaddressreg,addr_indexreg);
    outb( ramaddress,datreg);
  }
  outb(addr_indexreg,addr_indexreg);
  outb( 0x80 | (value & 0x0f),datreg);
  outb( datatransferport,addr_indexreg);
  retval = inb(datreg);
  sti;
  return retval;
#endif
}

#if 0
void setregd (int ramaddress, int value, unsigned char data)
{
#ifndef SYNTAXCHECK
  cli;
  if (ram) {
    outb( ramaddressreg,addr_indexreg);
    outb( ramaddress,datreg);
  }
  outb( datatransferport,addr_indexreg);
  outb( data,datreg);
  outb( addr_indexreg,addr_indexreg);
  outb( 0xC0 | (value & 0x0f),datreg);
  sti;
#endif
}

void setreg (int addr_index, unsigned char dat)
{
#ifndef SYNTAXCHECK
  cli;
  if (addr_index != -1) { /*&&&*/
    outb( addr_index,addr_indexreg);
  }
  outb( dat,datreg);
  sti;
#endif
}
#endif

char *noblank(char *x)
{
  char *y;
  while ((*x == ' ') || (*x == 9)) x++; /* skip white space */

  y = x + strlen(x)-1;
  while ((*y == ' ') || (*y == 9)) *y-- = 0; /* skip white space */
  return x;
}

long gethex(char *x)
{
  long b;
  char buffer[9];
  char *ind=buffer, *y;

  while ((*x == ' ') || (*x == 9)) x++; /* skip white space */

  while ((*x > 0) && (*x == '-' || *x == 'h' || *x == 'H' || isxdigit(*x))) {
    *ind++  =  *x++;
  }
  *ind = '\0';

  ind = buffer;
  ind = noblank (ind);

  y = ind + strlen(ind)-1;
  if ((*y == 'h') || (*y == 'H')) *y-- = 0;

  if (! *ind) {
    b = -1;
  } else {
    if (*ind == '-') {
      memmove(3+ind,ind,strlen(ind)+1);
      strncpy(ind,"-0x",3);
    } else {
      memmove(2+ind,ind,strlen(ind)+1);
      strncpy(ind,"0x",2);
    }
    
    if (sscanf(ind, "%li", &b) != 1) {
      fprintf (stderr, ": error in hex conversion");
      exit(-1);
    }
  }
  return b;
}

void setbit(unsigned char *x, unsigned char b,unsigned char w)
{
  unsigned char mask;

  mask = 1 << b;
  *x &= ~mask;
  *x |= (mask*w);
}

void free_ports(void)
{
#ifndef SYNTAXCHECK
  if (ioperm(0x24, 5, 0) != 0) {
    perror("");
    exit(-3);
  }
#endif
}

/*********************************************/
char *p;
char inputline[140];
char *comment;
char *wert;
int i;
unsigned char erg;
unsigned char regdata;
char werg[9];
BOOL found;
char inch;
char chipname[60];

BOOL first=true;
BOOL redirection=false;

int main(int argc, char *argv[])
{ /* main */
  FILE *in_file;

  addr_indexreg = 0x28;
  datreg = 0x24;
  strcpy(chipname,"shasta.cfg");

  if ((in_file = fopen (chipname, "rt")) == NULL) {
     fprintf(stderr, "config file shasta.cfg missing\n");
     exit(-1);
  }

#ifndef SYNTAXCHECK
  if (ioperm(0x24, 5, 1) != 0) {
    perror("");
    exit(-2);
  }
#endif

  atexit(free_ports);

  redirection = !isatty(STDOUT_FILENO);

  do {
    fgets (inputline,sizeof(inputline),in_file);                /* get a line */
    inputline[strlen(inputline)-1] = '\0';	/* get rid of newline */

    if (inputline != "") {
      p = strchr(inputline, ';');
      whattodo[0] = '\0';
      if (p == NULL) {
	strcpy(whattodo, inputline);     /* extract action field */
	comment = NULL;    /* extract comment */
      } else {
	strncpy(whattodo, inputline, p - inputline);     /* extract action field */
	whattodo[p - inputline] = '\0';
	comment = p+1;    /* extract comment */
      }

      p = strchr(whattodo, '=');
      if (p == NULL) {
	  wert = NULL;
      } else {
	  wert = p+1; 	/* value follows '=' */
	  *p=0;		/* command stands before '=' */
      }

      upstr(whattodo);
      p = noblank(whattodo);
      memmove (whattodo, p, p - whattodo);
      wert = noblank (wert);

           if (!strcmp(whattodo, "DATENPORT")) datreg = gethex(wert);
      else if (!strcmp(whattodo, "INDEXPORT")) addr_indexreg = gethex(wert);
      else if (!strcmp(whattodo, "DATATRANSFERPORT")) datatransferport = gethex(wert);
      else if (!strcmp(whattodo, "RAMADDRESSREG")) ramaddressreg = gethex(wert);
      else if (!strcmp(whattodo, "INDEX")) {
        /* Syntax : INDEX == addr_index1 [ : [RAMlocation]] */
        ramaddress = gethex(wert);
        wert = noblank(wert);
        if ((strlen(wert) > 0) && (wert[0] == ':')) {
           wert++;
           wert = noblank(wert);
           addr_index  =  gethex(wert);
           regdata  =  getregd(ramaddress,addr_index);
        } else {
           addr_index  =  ramaddress;
           regdata  =  getreg(addr_index); /*read once*/ /*&&&*/
        };
        printf("\n");
        if (first) {
          first = false;
        } else {
          if (!redirection) {
            printf (" >>>>>>>> Press Return to continue\n");
            inch  =  getchar();
            if ((inch == 27) || (toupper(inch) == 'Q')) exit(1);
          }
          printf("\n");
        }
        printf (inputline);
        /* print the port value once binary and once in hex */
        printf("\nvalue = ");
        highvideo();
        printf("%sb", wbin(0xff,regdata));
        normvideo();
        printf(" = %sh",Hexbyte(regdata));
      }
      else if (!strcmp(whattodo, "BIT")) {
        printf("\n");
        bit = 0;
        for (i = 0; i < strlen(wert); i++)
          setbit (&bit,wert[i]-'0',1);
        if (addr_index == -1) {
          printf (" """);
        } else {
          printf ("%s.",Hexbyte(addr_index));
        }
        printf ("%s:",wbin(0xFF,bit));
        erg = regdata & bit;    /* use read register*/ /*&&&*/
        strcpy(werg,wbin (bit,erg));
        highvideo();
        printf ("%s", werg);
        normvideo();
        printf (";%s",comment);
        comment = noblank (comment);
        if ((!strncmp(comment,"0/1",3))  ||
            (!strncmp(comment,"1/0",3))) {
          highvideo();
          if (werg[0] == comment[0]) printf (" disabled");
                               else printf (" enabled");
          normvideo();
        };
      } else {
        found = whattodo[0] != '\0';

        i = 1;             /* see, if mask fits to register value */
        while (found && (i <= strlen(whattodo))) {
          if ((i>strlen(werg)) ||
              ((toupper(whattodo[i-1]) != 'X') && (whattodo[i-1] != werg[i-1])))
             {
               found = false;
             }
          i++;
        }

        if (found) {     /* this mask fits */
          printf (": ");
          printf("\n");
          printf ("                 ");
          highvideo();
          printf (wert);
          normvideo();
        }
      }
      if ((whattodo[0] == '\0') && (comment != NULL)) {
        printf("\n");
        printf(comment);
      }
    } /* if inputline != "" */
  } while (!feof(in_file));

  return 0;
}

