--- hex.c.orig	Sat Apr 18 23:50:06 1998
+++ hex.c	Sat Feb 27 15:44:19 1999
@@ -116,4 +120,5 @@
     int address, type, nwords, i, ign = 0;
     unsigned w;
+    char c;
 
     if ( format == UNKNOWN )
@@ -127,5 +132,7 @@
     type = 0;
     while ( type != 1 ) {
-	if ( getc(fp) != ':' )
+        c = getc(fp);
+        if (c == '\n') continue;
+	if (c != ':' )
 	    return HE_CEX;              /* expected ':' */
 	check = 0;
--- pp.c.orig	Sat Apr 18 23:50:06 1998
+++ pp.c	Mon Mar  1 18:04:54 1999
@@ -281,5 +281,5 @@
 int read_pic(void)
 {
-    int i;
+    int i, newpos = 0, oldpos = 0;
 
     pmlast = -1;
@@ -288,11 +288,26 @@
     cf = 0;
 
+    printf("                 "
+	   "[                                                  ]\r"
+	   "Reading program: [|");
+    fflush(stdout);
+
     prog_mode();
     for ( i=0; i<PSIZE; ++i ) {
 	command(RDPROG);
+	read_mode();
 	if ( (progbuf[i] = in_word() & 0x3FFF) != 0x3FFF )
 	    pmlast = i;
 	command(INCADD);
+
+	newpos = (50*i)/PSIZE;
+	if (newpos > oldpos) {
+	  printf("\b-|");
+	  fflush(stdout);
+	  oldpos = newpos;
+	}
     }
+    printf("\b-\n");
+
     prog_mode();
     for ( i=0; i<DSIZE; ++i ) {
@@ -346,4 +361,11 @@
     time_t start_t;
 
+#ifdef LINUX
+    if (getuid()!=0) {
+      puts("pp: must be root to run pp (needs I/O access)");
+      exit(1);
+    }
+#endif
+
     erasehex(PSIZE, DSIZE, 14);              /* initialise buffers */
     config = CPBITS | PWRTE | RC;            /* default config */
@@ -387,5 +409,5 @@
 	   if ( (fp = fopen(fn,"r")) != NULL )
 	       quit("Dump would overwrite existing file",FAIL);
-	   fclose(fp);
+	   if (fp != NULL) fclose(fp);
 	   if ( (fp = fopen(fn,"w")) == NULL )
 	       quit("Can't create hexfile",FAIL);
--- pphw.c.orig	Sat Apr 18 23:50:06 1998
+++ pphw.c	Mon Mar  1 18:24:01 1999
@@ -14,6 +14,7 @@
  * 03-Apr-1998: V-0.4; idle_mode now called run_mode
  * 03-Apr-1998: V-0.5; added interact()
+ * 09-Jan-1998: V-0.6; Linux support and AN589 support added by Chris Wilson
  *
- * Copyright (C) 1996-1998 David Tait.  All rights reserved.
+ * Copyright (C) 1996-1998 David Tait and Chris Wilson. All rights reserved.
  * Permission is granted to use, modify, or redistribute this software
  * so long as it is not sold or exploited for profit.
@@ -26,9 +27,13 @@
 #include <stdio.h>
 #include <stdlib.h>
+
+#ifndef LINUX
 #include <conio.h>
+#endif // not LINUX
+
 #include "pphw.h"
 #include "hex.h"
 
-static char *version = "pphw.c V-0.5  Copyright (C) 1996-1998 David Tait";  
+static char *version = "pphw.c V-0.6  Copyright (C) 1996-1998 David Tait";
 
 int d_reg;
@@ -50,5 +55,9 @@
 void (*outlo)(void);
 void (*outhi)(void);
+void (*outtri)(void);
 
+int testmode = 0;
+// This is defined here to make it global, because iabit() needs to know
+// whether it was called by ppdebug()s hardware test, or to read the PIC
 
 unsigned tbit(void)                     /* real hardware functions */
@@ -62,4 +71,40 @@
 }
 
+// We need to prototype the assert() function here, because iabit() needs it
+void assert(void);
+
+// iabit() usually tristates the data line, so that the output from the
+// PIC can be returned to the software. Unfortuantely this isn't compatible
+// with pp's hardware test, which reads back tristated (on) instead of the
+// real value from the data output bit. If ppdebug is 1, then disable tristate.
+
+unsigned iabit() {
+  int result, oldstate;
+
+  oldstate = d_bits & 0x4;
+  if (testmode && oldstate) {
+    /* In hardware test mode, we MUST disable tristate so we can read back
+     * the value we are writing (not the value from the non-existant PIC)
+     */
+    d_bits &= ~0x4;
+    assert();
+    us_delay(tdly);
+  } else if (!testmode && !oldstate) {
+    /* We need to enable tristate, so we can read the PIC */
+    d_bits |= 0x4; // Set D2 high in order to tri-state the data line
+    assert();
+    us_delay(tdly); // wait a few shakes for things to quiet down
+  }
+  result = inportb(s_reg)&IN;
+
+  if (!oldstate) {
+    /* If we enabled tristate earlier, we must disable it again */
+    d_bits &= ~0x4;
+    assert();
+    us_delay(tdly);
+  }
+  return result;
+}
+
 void svpp(void)
 {
@@ -72,4 +117,16 @@
 }
 
+void savpp() {
+  /* This function asserts 12V on the PIC's /MCLR line */
+  d_bits &= ~0x10; // logic low on D4
+  d_bits |= 0x8;   // logic high on D3
+}
+
+void ravpp() {
+  /* This function drops the PIC's /MCLR line to 0v, which resets the PIC */
+  d_bits &= ~0x8;  // logic low on D3
+  d_bits |= 0x10; // logic high on D4
+}
+
 void svdd(void)
 {
@@ -82,5 +139,13 @@
 }
 
-void sclk(void)
+void savdd() {
+  // The AN589 has no VDD control circuit, so VDD commands are ignored
+}
+
+void ravdd() {
+  // The AN589 has no VDD control circuit, so VDD commands are ignored
+}
+
+void sclk(void)	
 {
     d_bits |= CLK;
@@ -92,4 +157,27 @@
 }
 
+void saclk() {
+  // To set the clock high on AN589 programmers
+  d_bits &= ~0x20; // clear the clock tristate bit
+  d_bits |= 0x2;   // set the clock bit
+}
+
+void raclk() {
+  // To set the clock low on AN589 programmers
+  d_bits &= ~0x20; // clear the clock tristate bit
+  d_bits &= ~0x2;  // clear the clock bit
+}
+
+void ignr() {
+  // This function does nothing, and is the placeholder for the AN589
+  // 'prepare to read PIC' function triout(), which tristates the data line
+}
+
+void taout() {
+  // This function, used by the AN589 hardware, tristates the data line so
+  // that the PIC's output can be read
+  d_bits |= 0x4; // set the data tristate bit
+}
+
 void sout(void)
 {
@@ -97,4 +185,9 @@
 }
 
+void saout() {
+  d_bits &= ~0x4; // clear the data tristate bit
+  d_bits |= 0x1;  // set the data bit
+}
+
 void rout(void)
 {
@@ -102,4 +195,9 @@
 }
 
+void raout() {
+  d_bits &= ~0x4; // clear the data tristate bit
+  d_bits &= ~0x1;  // clear the data bit
+}
+
 void assert(void)
 {
@@ -117,13 +215,15 @@
    void (* f7)(void);
    void (* f8)(void);
-} hwfun[4] = {
-    { ibit, rvpp, svpp, rvdd, svdd, sclk, rclk, sout, rout }, /* 7406/4066 */
-    { tbit, svpp, rvpp, svdd, rvdd, rclk, sclk, rout, sout }, /* 7407/4066 */
-    { ibit, svpp, rvpp, svdd, rvdd, sclk, rclk, sout, rout }, /* 7406/PNP */
-    { tbit, rvpp, svpp, rvdd, svdd, rclk, sclk, rout, sout }  /* 7407/PNP */
+   void (* f9)(void);
+} hwfun[5] = {
+  { ibit, rvpp, svpp, rvdd, svdd, sclk, rclk, sout, rout, ignr }, // 7406/4066
+  { tbit, svpp, rvpp, svdd, rvdd, rclk, sclk, rout, sout, ignr }, // 7407/4066
+  { ibit, svpp, rvpp, svdd, rvdd, sclk, rclk, sout, rout, ignr }, // 7406/PNP
+  { tbit, rvpp, svpp, rvdd, svdd, rclk, sclk, rout, sout, ignr }, // 7407/PNP
+  { iabit,savpp,ravpp,savdd,ravdd,raclk,saclk,raout,saout,taout } // AN589 h/w
 };
 
-char *hw_str[4] = {
-    "7406/4066", "7407/4066", "7406/PNP", "7407/PNP"
+char *hw_str[5] = {
+    "7406/4066", "7407/4066", "7406/PNP", "7407/PNP", "AN589"
     };
 
@@ -132,5 +232,5 @@
 {
     if ( s )
-	if ( (tdly = atoi(s)) < 0 || tdly > 127 )
+	if ( (tdly = atoi(s)) < 0 || tdly > 1000000 )
 	    tdly = TDLY;
 }
@@ -142,5 +242,5 @@
 
     if ( s )
-	if ( (hwid = atoi(s)) < 0 || hwid > 3 )
+	if ( (hwid = atoi(s)) < 0 || hwid > 4 )
 	    hwid = 0;
 
@@ -156,4 +256,5 @@
     outlo  = hwp->f7;
     outhi  = hwp->f8;
+    outtri = hwp->f9;
 }
 
@@ -166,5 +267,5 @@
 }
 
- 
+
 int ppdebug(char *s, int lpt)           /* check hardware */
 {
@@ -172,6 +273,11 @@
     int b, hwstat = 0;
     static int debug = 0;
+ 
+    // ppdebug is defined earlier (before iabit()) so that iabit can tell
+    // whether the system is in debugging mode and react accordingly
+    // (in debugging mode, there may not be a PIC present...)
 
     run_mode(STOP);             /* toggle RB7 to check hardware is present */
+    testmode = 1;
     vddon(), assert();
     ms_delay(PWRDLY);
@@ -181,6 +287,11 @@
     outlo(), assert();
     us_delay(tdly);
-    if ( b != IN || inbit() != 0 )
+    if ( b != IN || inbit() != 0 ) {
+        puts("Programming hardware not found or is faulty");
 	hwstat = 1;
+    } else {
+        puts("Programming hardware detected OK");
+    }
+    testmode = 0;
     run_mode(STOP);
 
@@ -196,4 +307,5 @@
     printf("Hardware setup: %s using LPT%d at %04X (delay = %d)\n",
 					   hw_str[hwid],lpt,d_reg,tdly);
+
     printf("Debug mode entered ... (^C to exit) ");
     if ( getch() == 3 ) {
@@ -203,4 +315,6 @@
     printf("\nRemove PIC ... ");
     getch();
+
+    testmode = 1;
     for(;;) {
 	vppoff(), vddoff(), clklo(), outlo(), assert();
@@ -232,5 +346,5 @@
 
 
-int interact(int wait)     
+int interact(int wait)
 {
     if ( wait ) {
@@ -261,4 +375,12 @@
 
 
+void read_mode() {
+  // This function prepares the PIC for reading, by tristating the data
+  // line (necessary only on AN589 hardware). This is cancelled by using
+  // the outlo() or outhi() functions (e.g. prog_mode and run_mode);
+  outtri(), assert();
+}
+
+
 static void clock_out(int bit)
 {
@@ -343,5 +465,5 @@
     /* setup()
      *
-     * Reads environment for LPT port and tdly, initialises timer, checks 
+     * Reads environment for LPT port and tdly, initialises timer, checks
      * hardware.  Returns -ve if LPT port address is non-standard or +ve
      * if hardware fails sanity check, 0 for all OK.
@@ -349,4 +471,6 @@
      */
 
+int ports[] = { 0x378, 0x278, 0x3BC };
+
 int setup(void)
 {
@@ -355,8 +479,12 @@
 
     if ( (s = getenv("PPLPT")) != NULL )
-	if ( (lpt = atoi(s)) < 1 || lpt > 3 ) 
+	if ( (lpt = atoi(s)) < 1 || lpt > 3 )
 	    lpt = 1;
 
-    d_reg = *(((int far *) 0x408) + lpt-1);  /* base address of LPT port */
+#ifdef LINUX
+    d_reg = ports[lpt-1];
+#else
+    d_reg = *(((int FAR *) 0x408) + lpt-1);  /* base address of LPT port */
+#endif
     s_reg = d_reg+1;
     c_reg = s_reg+1;
--- pphw.h.orig	Sat Apr 18 23:50:06 1998
+++ pphw.h	Mon Mar  1 18:07:43 1999
@@ -20,5 +20,9 @@
 #ifndef __PPHW_H
 #define __PPHW_H
-#include <dos.h>
+
+#ifndef LINUX
+	#include <dos.h>
+#endif // not LINUX
+
 #include "timer.h"
 
--- timer.c.orig	Sat Apr 18 23:50:06 1998
+++ timer.c	Sat Feb 27 16:52:14 1999
@@ -10,6 +10,7 @@
  * 03-Sep-1996: V-0.1; modified version used by pp.c/topic.c
  * 01-Apr-1998: V-0.2; latch correct timer in ms_delay()
+ * 09-Jan-1998: V-0.3; Linux compatible timer routines added by Chris Wilson
  *
- * Copyright (C) 1996-1998 David Tait.  All rights reserved.
+ * Copyright (C) 1996-1998 David Tait and Chris Wilson.  All rights reserved.
  * Permission is granted to use, modify, or redistribute this software
  * so long as it is not sold or exploited for profit.
@@ -21,4 +22,10 @@
 
 #include "timer.h"
+#ifdef LINUX
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sched.h>
+#endif
 
 static char *version = "timer.c V-0.2  Copyright (C) 1996-1998 David Tait";    
@@ -28,4 +35,5 @@
      *
      * Initialise PORTB and CTC.
+     * The Linux version does nothing
      *
      */
@@ -33,4 +41,5 @@
 void setup_timer(int cmd)
 {
+#ifndef LINUX
     asm pushf
     asm cli
@@ -42,4 +51,5 @@
     asm out     (TIMER+3),al    /* send command */
     asm popf
+#endif
 }
 
@@ -57,4 +67,5 @@
 void ms_delay(int ticks)
 {
+#ifndef LINUX
     unsigned hi, lo;
 
@@ -87,4 +98,11 @@
 
     setup_timer(0x90);          /* revert to mode 0, 1-byte reload */
+#else
+    struct timespec ts;
+    ts.tv_sec = 0;
+    ts.tv_nsec = ticks * 1000;
+    // while(nanosleep(&ts, &ts));
+    nanosleep(&ts, &ts);
+#endif
 }
 
@@ -103,7 +121,14 @@
 void us_delay(int ticks)
 {
+
+#ifdef LINUX
+    struct timeval tv;
+    long long time1, time2;
+#endif
+
     if ( ticks == 0 )
         return;
 
+#ifndef LINUX
     asm pushf
     asm cli
@@ -117,4 +142,19 @@
     asm jnc     uschk           /* wait until count wraps around  */
     asm popf
+#else
+    gettimeofday(&tv, NULL);
+    time1 = (((long long)tv.tv_sec) * 1000000) + tv.tv_usec;
+    time2 = time1;
+    time1 += ticks;
+  
+    while(time2 < time1) {
+        gettimeofday(&tv, NULL);
+        time2 = (((long long)tv.tv_sec) * 1000000) + tv.tv_usec;
+    } 
+    /*
+    ms_delay(ticks);
+    sched_yield();
+    */
+#endif
 }
 
@@ -123,4 +163,5 @@
      *
      * Attempts to restore timer 2 to default state.
+     * The Linux version does nothing.
      *
      */
@@ -128,4 +169,5 @@
 void reset_timer(void)
 {
+#ifndef LINUX
     asm pushf
     asm cli
@@ -136,3 +178,4 @@
     asm out     PORTB,al
     asm popf
+#endif
 }
