/*   Basic I/O routines for ATA IO port adapter   */

// *********** Physical adapter addressing ********************

#include <ata_phy.c>
#include <ata_adap.c>

// ************* Locical addresses to be used as address parameters


#define  dir_a          0
#define  dat_a          1
#define  port_a         2
#define  dir_b          3
#define  dat_b          4
#define  port_b         5
#define  dir_c          6
#define  dat_c          7
#define  port_c         8
#define  dir_d          9
#define  dat_d         10
#define  port_d        11
#define  dir_e         12
#define  dat_e         13
#define  port_e        14

// ***************** Global variables ******************************

int portregs [15];     // RAM copies of the port registers

int portctl  [15];     // port access control array

int bitmasks [8];      // masks for single bit access routines


// Borland Turbo C++ physical I/O port access functions used here

// If using another compiler, substitute outportb and inputb accordingly


//   *** 1. Physiscal Input / Output ***
//                      Use physical address declarations only (see ata_phy.c)!


//********************** Load the direction register ************

void dirout(int adrs, int databyte)
{
     outportb (portadrs, adrs); outportb (dir_reg,databyte);
}


//********************** Load the data register **************

void datout (int adrs, int databyte)
{
     outportb (portadrs, adrs); outportb (dat_reg, databyte);
}

//************************* Read the I/O pins ****************

int datin (int adrs)
{
     outportb (portadrs, adrs); return  inportb (dat_reg);
}

//   *** 2. Logical Input / Output ***
//                          Use logical address declarations only (see above)!
          
// ********************** Single Byte Output ***************************

void out (int adrs, int data)   
{

switch ((portctl [adrs] & 0xff00))
{
     case 0x0100:                // if direction control register
     portregs [adrs] = data;     // save copy of new register content
     outportb (portadrs, (portctl [adrs] & 0xff)); // port adrs into DH reg
     outportb (dir_reg,data);   // data to direction control register
     break;


     case  0x0200:              // if direction control register
     portregs [adrs] = data;    // save copy of new register content
     outportb (portadrs, (portctl [adrs] & 0xff)); //  port adrs into DH reg
     outportb (dat_reg,data);   // data to data register
     break;
}

return;
}

// ********************** Single Byte Input ***************************

int in (int adrs)               

{

if ((portctl [adrs] & 0xff00) == 0x0300)   // only the port will be read in
     {
     outportb (portadrs, (portctl [adrs] & 0xff)); //  port adrs into DH reg
     portregs [adrs] =  inportb (dat_reg); // update register copy in RAM
     }

return portregs [adrs]; // read register content out of copy in RAM 
}

// ********************** Single Bit Output ***************************    

// bit modification will be done with the copies in RAM

// truth values correspond to C conventions.
// If data value is zero, bit will be cleared.
// If data value is not zero, bit will be set

void bitout (int adrs, int bitpos, int data)    

{

switch ((portctl [adrs] & 0xff00))
  {
   
    case 0x0100:                 // if direction control register
    if (data == 0) portregs [adrs] = (portregs [adrs] & ~bitmasks [bitpos] &
    0xff); // clear bit

    else   portregs [adrs] = (portregs [adrs] | bitmasks [bitpos]); // set bit
    outportb (portadrs, (portctl [adrs] & 0xff));   // port adrs into DH reg
    outportb (dir_reg,portregs [adrs]); // data to data register
    break;

  case  0x0200:                 // if data register
    if (data == 0) portregs [adrs] = (portregs [adrs] & ~bitmasks [bitpos] &
    0xff);
    else   portregs [adrs] = (portregs [adrs] | bitmasks [bitpos]);
    outportb (portadrs, (portctl [adrs] & 0xff));  // port adrs into DH reg
    outportb (dat_reg,portregs [adrs]);   // data to data register 
    break;
    }

return;
}

 // ********************** Single Bit Input ***************************

// Routine will return an integer 0 or 1

int bitin (int adrs, int bitpos)

{

     if ((portctl [adrs] & 0xff00) == 0x300   // only the port will be read in
     {
     outportb (portadrs, (portctl [adrs] & 0xff)); //  port adrs into DH reg
     portregs [adrs] =  inportb (dat_reg);   // data to copy in RAM;
     }
     
     // Return bit value out of copy in RAM

     if ((portregs [adrs] & bitmasks [bitpos]) == 0) return 0;
     else return 1;

}


 // ********************** I/O Initialization ***************************

// To be called at the beginning of the application program


void ioinit ()
{
int n;

for (n = 0; n <= 44; n++)
portregs [n] = 0;           // clear all copies in RAM

// Build the access control array
// low order byte = port address within the ATA IO adapter
// high order byte encodes register type:
// 1 = direction control, 2 = data, 3 = port

portctl  [0] = 0x0100+ioport_a;                       // port A
portctl  [1] = 0x0200+ioport_a;
portctl  [2] = 0x0300+ioport_a;
portctl  [3] = 0x0100+ioport_b;                       // port B
portctl  [4] = 0x0200+ioport_b;
portctl  [5] = 0x0300+ioport_b;
portctl  [6] = 0x0100+ioport_c;                       // port C
portctl  [7] = 0x0200+ioport_c;
portctl  [8] = 0x0300+ioport_c;
portctl  [9] = 0x0100+ioport_d;                       // port D
portctl [10] = 0x0200+ioport_d;
portctl [11] = 0x0300+ioport_d;
portctl [12] = 0x0100+ioport_e;                       // port E
portctl [13] = 0x0200+ioport_e;
portctl [14] = 0x0300+ioport_e;

// Build the bitmask array

bitmasks[0] = 1;
bitmasks[1] = 2;
bitmasks[2] = 4;
bitmasks[3] = 8;
bitmasks[4] = 16;
bitmasks[5] = 32;
bitmasks[6] = 64;
bitmasks[7] = 128;

}

