Recovery of release 990110 after disk crash.
See Changelog for changes between 990103 and 990110.

diff --git a/msdos/ioports.c b/msdos/ioports.c
index 1154c3e..d6adf75 100644
--- a/msdos/ioports.c
+++ b/msdos/ioports.c
@@ -2,6 +2,7 @@
  * Emulation of processor ioports.
  *
  * Copyright 1995 Morten Welinder
+ * Copyright 1998 Andreas Mohr, Ove Kaaven
  */
 
 /* Known problems:
@@ -17,9 +18,18 @@
 #include <unistd.h>
 #include "windows.h"
 #include "vga.h"
+#include "dosexe.h"
 #include "options.h"
 #include "debug.h"
 
+static WORD tmr_8253_countmax[3] = {0xffff, 0x12, 1}; /* [2] needs to be 1 ! */
+/* if byte_toggle is TRUE, then hi byte has already been written */
+static BOOL16 tmr_8253_byte_toggle[3] = {FALSE, FALSE, FALSE};
+static BYTE tmr_8253_ctrlbyte_ch[4] = {0x06, 0x44, 0x86, 0};
+static int dummy_ctr = 0;
+
+static BYTE parport_8255[4] = {0x4f, 0x20, 0xff, 0xff};
+
 static BYTE cmosaddress;
 
 static BYTE cmosimage[64] =
@@ -52,7 +62,7 @@
 
 #endif  /* DIRECT_IO_ACCESS */
 
-static void IO_FixCMOSCheckSum()
+static void IO_FixCMOSCheckSum(void)
 {
 	WORD sum = 0;
 	int i;
@@ -64,6 +74,26 @@
 	TRACE(int, "calculated hi %02x, lo %02x\n", cmosimage[0x2e], cmosimage[0x2f]);
 }
 
+static void set_timer_maxval(unsigned timer, unsigned maxval)
+{
+    switch (timer) {
+        case 0: /* System timer counter divisor */
+            DOSVM_SetTimer(maxval);
+            break;
+        case 1: /* RAM refresh */
+            FIXME(int, "RAM refresh counter handling not implemented !");
+            break;
+        case 2: /* cassette & speaker */
+            /* speaker on ? */
+            if (((BYTE)parport_8255[1] & 3) == 3)
+            {
+                TRACE(int, "Beep (freq: %d) !\n", 1193180 / maxval );
+                Beep(1193180 / maxval, 20);
+            }
+            break;
+    }
+}
+
 /**********************************************************************
  *	    IO_port_init
  */
@@ -206,62 +236,99 @@
 
 /**********************************************************************
  *	    IO_inport
+ *
+ * Note: The size argument has to be handled correctly _externally_ 
+ * (as we always return a DWORD)
  */
-DWORD IO_inport( int port, int count )
+DWORD IO_inport( int port, int size )
 {
     DWORD res = 0;
-    BYTE b;    
 
 #ifdef DIRECT_IO_ACCESS    
-    if (do_direct_port_access)
+    if ((do_direct_port_access)
+        /* Make sure we have access to the port */
+        && (port_permissions[port] & IO_READ))
     {
-        /* Make sure we have access to the whole range */
-        int i;
-        for (i = 0; i < count; i++)
-            if (!(port_permissions[port+i] & IO_READ)) break;
-        if (i == count)
+        iopl(3);
+        switch(size)
         {
-            iopl(3);
-            switch(count)
-            {
-                case 1: res = inb( port ); break;
-                case 2: res = inw( port ); break;
-                case 4: res = inl( port ); break;
-                default:
-                    ERR(int, "invalid count %d\n", count);
-            }
-            iopl(0);
-            return res;
+        case 1: res = inb( port ); break;
+        case 2: res = inw( port ); break;
+        case 4: res = inl( port ); break;
+        default:
+            ERR(int, "invalid data size %d\n", size);
         }
+        iopl(0);
+        return res;
     }
 #endif
 
-    TRACE(int, "%d bytes from port 0x%02x\n", count, port );
+    TRACE(int, "%d-byte value from port 0x%02x\n", size, port );
 
-    while (count-- > 0)
+    switch (port)
     {
-        switch (port)
+    case 0x40:
+    case 0x41:
+    case 0x42:
+    {
+        BYTE chan = port & 3;
+        WORD tempval = 0;
+
+        if (chan == 0) /* System timer counter divisor */
+            tempval = (WORD)DOSVM_GetTimer();
+        else
+        {   /* FIXME: intelligent hardware timer emulation needed */
+            dummy_ctr -= 10;
+            tempval = dummy_ctr;
+        }
+        switch (tmr_8253_ctrlbyte_ch[chan] & 0x30)
         {
-        case 0x70:
-            b = cmosaddress;
+        case 0x00:
+            break; /* correct ? */
+        case 0x10: /* read lo byte */
+            res = (BYTE)tempval;
             break;
-        case 0x71:
-            b = cmosimage[cmosaddress & 0x3f];
-            break;
-        case 0x200:
-        case 0x201:
-            b = 0xff; /* no joystick */
-            break;
-        case 0x3da:
-            b = VGA_ioport_in( port );
-            break;
-        default:
-            WARN( int, "Direct I/O read attempted from port %x\n", port);
-            b = 0xff;
+        case 0x30: /* read lo byte, then hi byte */
+            tmr_8253_byte_toggle[chan] ^= TRUE; /* toggle */
+            if (tmr_8253_byte_toggle[chan] == TRUE)
+            {
+                res = (BYTE)tempval;
+                break;
+            }
+            /* else [fall through if read hi byte !] */
+        case 0x20: /* read hi byte */
+            res = (BYTE)tempval>>8;
             break;
         }
-        port++;
-        res = (res << 8) | b;
+        break;
+    }
+    case 0x60:
+        res = (DWORD)parport_8255[0];
+        break;
+    case 0x61:
+        res = (DWORD)parport_8255[1];
+        break;
+    case 0x62:
+        res = (DWORD)parport_8255[2];
+        break;
+    case 0x70:
+        res = (DWORD)cmosaddress;
+        break;
+    case 0x71:
+        res = (DWORD)cmosimage[cmosaddress & 0x3f];
+        break;
+    case 0x200:
+    case 0x201:
+        res = 0xffffffff; /* no joystick */
+        break;
+    case 0x3ba:
+    case 0x3da:
+        res = (DWORD)VGA_ioport_in( port );
+        break;
+    default:
+        WARN( int, "Direct I/O read attempted from port %x\n", port);
+        res = 0xffffffff;
+        break;
     }
     TRACE(int, "  returning ( 0x%lx )\n", res );
     return res;
@@ -271,57 +338,107 @@
 /**********************************************************************
  *	    IO_outport
  */
-void IO_outport( int port, int count, DWORD value )
+void IO_outport( int port, int size, DWORD value )
 {
-    BYTE b;
-
-    TRACE(int, "IO: 0x%lx (%d bytes) to port 0x%02x\n",
-                 value, count, port );
+    TRACE(int, "IO: 0x%lx (%d-byte value) to port 0x%02x\n",
+                 value, size, port );
 
 #ifdef DIRECT_IO_ACCESS
-    if (do_direct_port_access)
+    if ((do_direct_port_access)
+        /* Make sure we have access to the port */
+        && (port_permissions[port] & IO_WRITE))
     {
-        /* Make sure we have access to the whole range */
-        int i;
-        for (i = 0; i < count; i++)
-            if (!(port_permissions[port+i] & IO_WRITE)) break;
-        if (i == count)
+        iopl(3);
+        switch(size)
         {
-            iopl(3);
-            switch(count)
-            {
-                case 1: outb( LOBYTE(value), port ); break;
-                case 2: outw( LOWORD(value), port ); break;
-                case 4: outl( value, port ); break;
-                default:
-                    WARN(int, "Invalid count %d\n", count);
-            }
-            iopl(0);
-            return;
+        case 1: outb( LOBYTE(value), port ); break;
+        case 2: outw( LOWORD(value), port ); break;
+        case 4: outl( value, port ); break;
+        default:
+            WARN(int, "Invalid data size %d\n", size);
         }
+        iopl(0);
+        return;
     }
 #endif
 
-    while (count-- > 0)
+    switch (port)
     {
-        b = value & 0xff;
-        value >>= 8;
-        switch (port)
+    case 0x40:
+    case 0x41:
+    case 0x42:
+    {
+        BYTE chan = port & 3;
+        WORD oldval = 0;
+
+        if ( ((tmr_8253_ctrlbyte_ch[chan] & 0x30) != 0x30) ||
+/* we need to get the oldval before any lo/hi byte change has been made */
+             (tmr_8253_byte_toggle[chan] == FALSE) )
+            oldval = tmr_8253_countmax[chan];
+        switch (tmr_8253_ctrlbyte_ch[chan] & 0x30)
         {
-        case 0x70:
-            cmosaddress = b & 0x7f;
+        case 0x00:
+            break; /* correct ? */
+        case 0x10: /* write lo byte */
+            tmr_8253_countmax[chan] =
+                (tmr_8253_countmax[chan] & 0xff00) | (BYTE)value;
             break;
-        case 0x71:
-            cmosimage[cmosaddress & 0x3f] = b;
-            break;
-        case 0x3c8:
-        case 0x3c9:
-            VGA_ioport_out( port, b );
-            break;
-        default:
-            WARN(int, "Direct I/O write attempted to port %x\n", port );
+        case 0x30: /* write lo byte, then hi byte */
+            tmr_8253_byte_toggle[chan] ^= TRUE; /* toggle */
+            if (tmr_8253_byte_toggle[chan] == TRUE)
+            {
+                tmr_8253_countmax[chan] =
+                    (tmr_8253_countmax[chan] & 0xff00) | (BYTE)value;
+                break;
+            }
+            /* else [fall through if write hi byte !] */
+        case 0x20: /* write hi byte */
+            tmr_8253_countmax[chan] =
+                (tmr_8253_countmax[chan] & 0xff)|((BYTE)value << 8);
             break;
         }
-	port++;
+        if (
+            /* programming finished ? */
+            ( ((tmr_8253_ctrlbyte_ch[chan] & 0x30) != 0x30) ||
+              (tmr_8253_byte_toggle[chan] == FALSE) )
+            /* update to new value ? */
+            && (tmr_8253_countmax[chan] != oldval)
+            )
+            set_timer_maxval(chan, tmr_8253_countmax[chan]);
+    }
+    break;          
+    case 0x43:
+        /* ctrl byte for specific timer channel */
+        tmr_8253_ctrlbyte_ch[((BYTE)value & 0xc0) >> 6] = (BYTE)value;
+        if (((BYTE)value&0xc0)==0xc0) {
+            FIXME(int,"8254 timer readback not implemented yet\n");
+        } else
+            if (((BYTE)value&3)==0) {
+                FIXME(int,"timer counter latch not implemented yet\n");
+            }
+        if ((value & 0x30) == 0x30) /* write lo byte, then hi byte */
+            tmr_8253_byte_toggle[((BYTE)value & 0xc0) >> 6] = FALSE; /* init */
+        break;
+    case 0x61:
+        parport_8255[1] = (BYTE)value;
+        if ((((BYTE)parport_8255[1] & 3) == 3) && (tmr_8253_countmax[2] != 1))
+        {
+            TRACE(int, "Beep (freq: %d) !\n", 1193180 / tmr_8253_countmax[2]);
+            Beep(1193180 / tmr_8253_countmax[2], 20);
+        }
+        break;
+    case 0x70:
+        cmosaddress = (BYTE)value & 0x7f;
+        break;
+    case 0x71:
+        cmosimage[cmosaddress & 0x3f] = (BYTE)value;
+        break;
+    case 0x3c8:
+    case 0x3c9:
+        VGA_ioport_out( port, (BYTE)value );
+        break;
+    default:
+        WARN(int, "Direct I/O write attempted to port %x\n", port );
+        break;
     }
 }