/******************************************************************************
 * envDriver.c
 ******************************************************************************
 * Driver routines for the Environmental Fan Card Board
 *
 * Created - 03/20/2002
 *
 * Version	Date		Intls	Comments
 * -------	----------	-----	---------------------------------------
 * 1.00.00	07/06/2002	gatjr	initial release
 *              03/12/2004      rsm     port to QNX
 *
 ******************************************************************************
 *
 * f=envOpen(address)			- Open board for access, set address
 * f=envSetup()				- Initialize board
 *
 * b=envDiagLED(state)			- Read and set Diagnostic LED state
 *
 * i=envReadCfg()			- Read configuration jumpers
 * i=envReadDig()			- Read digital inputs
 * i=envReadAna(channel)		- Read analog voltage
 *
 * mthr3InitTemp()					- Initialize temp. sys
 * mthr3ReadTemp(*TempNow,*TempHi,*TempLo,*TempCfg)	- Read temp. values
 * mthr3WriteTemp (TempHi,TempLo)			- Set temp. limits
 *
 ******************************************************************************
 * Built with Greenhills Compiler Multi V3.5
 * (C) Copyright 2002 parvus Corporation.  All rights reserved.
 ******************************************************************************/

#include <stdio.h>
#include <string.h>
#include <conio.h>
#include <i86.h>
#include <time.h>
#include <math.h>
#include "envUtils.h"

////////////////////////////////////////////////////////////////////////////////
// Definitions and Globals

#define DEFDECDIGITS 6

static int TempDDRBit, TempCLKBit, TempDTIBit, TempDTOBit, TempPort;
static int TempWindow; // 0 - Not Used
static int TempBank, TempShadow, TempType, TempResetBit, TempResetBit1; 

int envIOBase;		// Base address of Board
//
// SHT1x
//
int HUMPort;     // '= &H0 '1110
int HUMDDrBit;   // '= &H1 '0001
int HUMCLKBit;   // '= &H4 '0100
int HUMDinBit;   // '= &H8 '1000
int HUMDoutBit;  // '= &H2 '0010
long HUMShadow=0;// '= &H2 '0010

// Local function headers
static void TempCommand(int cmd);
static int TempInput( int Cmd);
static void TempOutput (int Cmd, int Dta);
static void TempReset(int ch);
static void TempDisable(int ch);
static void TempEnable(int ch);
static void TempBusIOWrite8(long TP, int TS);
static int BusIORead8( int addr );
static int BusIOWrite8( int addr, int value );
static void sdelay();
static void pdelay( int microsec );


// for the humidity sensor.
void s_connectionreset();
void s_transstart();
int s_measure(float *, int checksum,int mode);
int s_write_byte(int);
void s_read_byte(float * , int, int ack);



////////////////////////////////////////////////////////////////////////////////
// Environmental Fan Card Board Functions
////////////////////////////////////////////////////////////////////////////////

// Open access to board
int envOpen(int address){

    int err;

    envIOBase = address;		// Set base address
    err = envSetup();			// Setup board
    
    return(err);
}

// Perform required initial setup of board
int envSetup(void) {
    int err;

    envInitTemp(0);			// Start temperature sensor 0
    envInitTemp(1);			// Start temperature sensor 1

    err=0;
    
    return(err);
}

// Access diagnostic LED of board
int envDiagLED(int state) {

    int f;
    f = BusIORead8(envIOBase+1);
    if (state==0) BusIOWrite8(envIOBase+1, f | 0x02);	        // LED Off
    else if (state==1) BusIOWrite8(envIOBase+1,f & 0xFD);       // LED On
    if ((BusIORead8(envIOBase+1) & 0x02)==0) f = 1; else f = 0;	// LED state

    return(f);
}


////////////////////////////////////////////////////////////////////////////////

// Read Configuration jumpers
int envReadCfg(void){
    int b;
    b = BusIORead8(envIOBase+5);
    return(b);
}

// Read digital Inputs
int envReadDig(void){
    int b;
    b = BusIORead8(envIOBase+3);
    return(b);
}

// Read Humidity Inputs
int envReadHum(void){
    int b;
    b = BusIORead8(envIOBase+0);
    return(b);
}
// Write Humidity Inputs
void envWriteHum(int val){
    BusIOWrite8(envIOBase+0, val);
    return;
}

// Write to digital outputs
int envSetDig(int val){
    int r;
    r = BusIORead8(envIOBase+1);
    if (val!=-1) BusIOWrite8(envIOBase+1,(r & 0x0F) | ((val & 0x0F)<<4));
    //r = (((BusIORead8(envIOBase+1) & 0xF0)>>4) & 0x0F);
    r = BusIORead8(envIOBase+1);
    return(r);
}

// Write to enables
int envSetEnables(int val){
    int r;
    r = BusIORead8(envIOBase+6);
    if (val!=-1) BusIOWrite8(envIOBase+6,(r & 0x1F) | ((val & 0x07)<<5));
    r = (((BusIORead8(envIOBase+6) & 0xE0)>>5) & 0x07);
    return(r);
}

// Turn Fan On/Off
int envFan(int val){
    int r;
    r = BusIORead8(envIOBase+1);
    if (val==1) BusIOWrite8(envIOBase+1,r | 0x04);
    else if (val==0) BusIOWrite8(envIOBase+1,r & (~0x04));

    r = BusIORead8(envIOBase+1) & (0x04);
    if (r!=0) r=1;
    return(r);
}


// Read environmental analog channels
int envReadAna(int channel){
    int dta;
    BusIOWrite8(envIOBase+8,(channel & 0x07) + 0x80); // Start conversion
    pdelay(10);
    dta = BusIORead8(envIOBase+8);
    return(dta);                                // Return Data

}

// Initialize environmental board temperaure sensor
void envInitTemp(int ch) {

    int TempNow, TempHi, TempLo, TempCfg;

    TempDDRBit = 0x2;            // Setup Temperature I/O
    TempCLKBit = 0x4;
    TempDTIBit = 0x1;
    TempDTOBit = 0x1;
    TempResetBit = 0x8;
    TempResetBit1 = 0x10;
    TempPort = envIOBase + 6;
    TempWindow = 0;              // 0 - Not Used
    TempBank = 1;
    TempShadow = 0;
    TempType = 0;                // 0=F, 1=C
    if (TempWindow > 0) BusIOWrite8(TempWindow, TempBank); // Set access window
    TempShadow = (TempPort);	 // load shadow
    TempEnable(ch);              // Raise reset bit
    TempReset(ch);               // Toggles the RST (reset) bit
    TempCommand (0xC);           // Send Temperature command
    // Enable 3-wire communication and disable one-shot. 
    TempCommand (0x2);              
    TempReset(ch);
    TempCommand (0xEE);          // Start continuous Conversion
    TempReset(ch);               // Toggles the RST (reset) bit
    TempDisable(ch);             // Lowers RST (reset) bit

    envReadTemp (&TempNow, &TempHi, &TempLo, &TempCfg, ch);
}
//
// Set environmental board thermostat limits.  Two counts equal one degree
// Celcius.
//
void envWriteTemp (int TempHi, int TempLo, int ch) {
    TempEnable(ch);
    sdelay();
    TempShadow = BusIORead8(TempPort);	// load shadow
    TempReset(ch);
    TempCommand (0xC);               	// Send Temperature command
    TempCommand(2);               	// Continuous Conversion
    TempReset(ch);
    TempOutput(0x2, TempLo);         	// Send TL command
    TempReset(ch);
    TempOutput(0x1, TempHi);         	// Send TH command
    TempReset(ch);
    TempCommand(0xEE);              	// Start continuous Conversion
    TempReset(ch);
    sdelay();
    TempDisable(ch);
}
//
// Read environmental board temperature sensor.  Two counts equal one degree
// Celcius for TempNow, TempHi, and TempLo.
//
void envReadTemp(int *TempNow, int *TempHi, int *TempLo, int *TempCfg, int ch) {
    TempEnable(ch);                  // Raises the RST bit
    sdelay();
    TempShadow = BusIORead8(TempPort);	// load shadow
    TempReset(ch);                   // (Moved these up from below) zz
    TempCommand (0xEE);              // Start continuous Conversion zz
    TempReset(ch);
    *TempLo = TempInput(0xA2);       // Read Low temp set point
    TempReset(ch);
    *TempHi = TempInput(0xA1);       // Read High temp set point
    TempReset(ch);
    *TempNow = TempInput(0xAA);      // Read current temperature
    TempReset(ch);
    *TempCfg = TempInput(0xAC);      // Read current configuration
    TempReset(ch);
    sdelay();
    TempDisable(ch);
}
//
// Initialize the SHT1x
//
void port_init()
{
   HUMPort = 0x0;   //'1110   'Indicates register 0
   //
   // The BusIOWrite and Read functions take the address, not an offset.  So,
   // add the base address to the offset below to convert to an absoulute
   // address.
   //
   HUMPort += envIOBase;  
   
   HUMDDrBit = 0x1; //'0001   'Indicates least significant bit in register 0

   //'Indicates the 2nd bit in register 0 (from lsb if lsb=0)
   HUMCLKBit = 0x4; //'0100   

   //'Indicates the 3rd bit in register 0 (from lsb if lsb=0)
   HUMDinBit = 0x8; //'1000   

   //'Indicates the 1st bit in register 0 (from lsb if lsb=0)
   HUMDoutBit = 0x2; //'0010  
}

//
// Read the SHT1x humidity sensor.
//
double envHumidity(void)
{
	
   float raw_hum=0;
   int er=0;
   //double humidity_value=0;
   int checksum=0;
   const float C1=-4.0;              // for 12 Bit
   const float C2=+0.0405;           // for 12 Bit
   const float C3=-0.0000028;        // for 12 Bit
   //port_init();               //' initialize the port,clk,ddr,din,dout
   s_connectionreset();         //' reset the sensor

   //'measure humidity. 0 for humidity 1 for temperature
   er = er + s_measure(&raw_hum,checksum, 0); 
   if (er != 0)
   {
      s_connectionreset();      //in case of an error: connection reset
      return -1;
   }
   else
   {
      //calc. humidity from ticks to [%RH]
      raw_hum=C3*raw_hum*raw_hum + C2*raw_hum + C1;     
      if (raw_hum<0.1)
	 return 0;
      if (raw_hum>100)
	 return 100;
      return raw_hum;
      //return humidity here.
        
      //' Calculate humidity % value after getting the correct MSB and LSB
   }
   //----------wait approx. 0.8s to avoid heating up SHTxx------------------------------ timer should take care of this
}

double envTemperature(int tmp)
{
	
   float raw_tmp=0;
   int er=0;
   //double humidity_value=0;
   int checksum=0;
   //port_init();               //' initialize the port,clk,ddr,din,dout
   s_connectionreset();       //' reset the sensor
   er = er + s_measure(&raw_tmp,checksum, 1); //'measure humidity. 0 for humidity 1 for temperature
   if (er != 0)
   {
      s_connectionreset();                 //in case of an error: connection reset
      return -1;
   }
   else
   {
      raw_tmp=raw_tmp * 0.01 - 40;//calc temperature
      if(tmp==0)
	 return raw_tmp;
      //convert to fahrenheit
      if(tmp==1)
      {
	 raw_tmp=((9./5.)*raw_tmp + 32.);
	 return raw_tmp;
      }
      return -1;
   }
   //----------wait approx. 0.8s to avoid heating up SHTxx------------------------------ timer should take care of this
}


int s_measure(float *raw_hum, int checksum, int mode)
{
   int er=0;
   int I;
   clock_t ticks1, ticks2;
   long portvalue=0;
   //double myhum;
   s_transstart();                //' transmission start
   switch(mode)
   {					//' send command to sensor
      case 0: //'Humidity
	 er = er + s_write_byte(0x05);
	 break;
      case 1: //'Temperature
	 er = er + s_write_byte(0x03);
	 break;
      default:
				//should never get here
	 er=1;
	 break;       
   }
        
   HUMShadow = HUMShadow & (~ HUMDDrBit);  //'Set DDR for input
   BusIOWrite8(HUMPort, HUMShadow);

   I = 0;
   ticks1=clock();
   ticks2=ticks1;
        
   do
   {
      ticks2=clock();
      portvalue = BusIORead8(HUMPort);                       // ' Read Port
      if ((portvalue & HUMDinBit) == 0) 
      {
	 break;
      }
      I = I + 1;
			
   }
   while ((ticks2/CLOCKS_PER_SEC-ticks1/CLOCKS_PER_SEC)<3);                                        //'wait for 3 secs
        
   if ((portvalue & HUMDinBit) != 0) 
   {
      er = er + 1;
   }
    
   s_read_byte(raw_hum,15,1);                  //'read the first byte (MSB)
   //MSB_txt.Text = BitDisp$(p_value)
   s_read_byte(raw_hum,7,1);                  //'read the second byte (LSB)
    
   //calc_sth11 (p_value);
   return er;                              //'return error status
}



void s_transstart()
{    
    
   HUMShadow= HUMShadow | (HUMDDrBit);  //Set DDR for output
   BusIOWrite8(HUMPort,HUMShadow);
    
   HUMShadow = HUMShadow | (HUMDoutBit);     //' Raise  Data
   BusIOWrite8(HUMPort, HUMShadow);
     
   HUMShadow = HUMShadow & (~HUMCLKBit);     //' Lower Clock
   BusIOWrite8(HUMPort,HUMShadow);
    
   if (1); //nop

   HUMShadow= HUMShadow | (HUMCLKBit);      //' Raise Clock
   BusIOWrite8(HUMPort, HUMShadow);

   //'Wait 1 clock cycle
   if(1);

   HUMShadow = HUMShadow & (~HUMDoutBit);     //' Lower  Data
   BusIOWrite8(HUMPort,HUMShadow);
    
   //'Wait 1 clock cycle
   if (1);
        
   HUMShadow = HUMShadow & (~HUMCLKBit);     //' Lower Clock
   BusIOWrite8(HUMPort, HUMShadow);
    
   //'Wait 1 clock cycle
   if(1);
   //'Wait 1 clock cycle
   if(1);
   //'Wait 1 clock cycle
   if(1);
    
   HUMShadow = HUMShadow | (HUMCLKBit);      //' Raise Clock
   BusIOWrite8(HUMPort, HUMShadow);
   //'Wait 1 clock cycle
   if(1);

   HUMShadow = HUMShadow | (HUMDoutBit);     //' Raise  Data
   BusIOWrite8(HUMPort, HUMShadow);
    
   //'Wait 1 clock cycle
   if(1);

   HUMShadow = HUMShadow & (~HUMCLKBit);     //' Lower Clock
   BusIOWrite8(HUMPort, HUMShadow);
}

int s_write_byte(int value)
{
   int er=0;
   int i;
   long portvalue=0;
   HUMShadow = HUMShadow | (HUMDDrBit);  //'Set DDR for output
   BusIOWrite8(HUMPort, HUMShadow);
    
   i=0x80;
   while (i > 0)
   {
    
      if (i & value) 
      {
	 HUMShadow = HUMShadow | (HUMDoutBit);     //' Raise  Data
	 BusIOWrite8(HUMPort, HUMShadow);
      }
      else
      {
	 HUMShadow = HUMShadow & (~HUMDoutBit);     //' Lower  Data
	 BusIOWrite8(HUMPort, HUMShadow);   
      }
      HUMShadow = HUMShadow | (HUMCLKBit);      //' Raise Clock
      BusIOWrite8(HUMPort, HUMShadow);
      
      //'Wait 1 clock cycle
      if(1);
      //'Wait 1 clock cycle
      if(1);
      //'Wait 1 clock cycle
      if(1);
        
      if (i == 1) 
      {
	 HUMShadow = HUMShadow & (~HUMDDrBit);  //'Set DDR for input to release the data line for the last command bit
	 BusIOWrite8(HUMPort, HUMShadow);
      }
        
      HUMShadow = HUMShadow & (~HUMCLKBit);     //' Lower Clock
      BusIOWrite8(HUMPort, HUMShadow);
      i = i / 2;                                   //'shift bit for masking
   }
    
   HUMShadow = HUMShadow & (~HUMDDrBit);  //'Set DDR for input to release the data line
   BusIOWrite8(HUMPort,HUMShadow);
    
   HUMShadow = HUMShadow | (HUMCLKBit);      //' Raise Clock ---- clk #9 for ack
   BusIOWrite8(HUMPort, HUMShadow);
    
    
   HUMShadow = HUMShadow & (~HUMDDrBit);  //'Set DDR for input
   BusIOWrite8(HUMPort, HUMShadow);
    
   portvalue = BusIORead8(HUMPort); //' Read Port
   if ((portvalue & HUMDinBit) > 0)               //'check ack (DATA will be pulled down by SHT11)
   {
      er = er + 1; //'error 
   }
    
   HUMShadow = HUMShadow & (~HUMCLKBit);     //' Lower Clock
   BusIOWrite8(HUMPort, HUMShadow);  
   return er;

}
//----------------------------------------------------------------------------------
// communication reset: DATA-line=1 and at least 9 SCK cycles followed by transstart
//       _____________________________________________________         ________
// DATA:                                                      |_______|
//          _    _    _    _    _    _    _    _    _        ___     ___
// SCK : __| |__| |__| |__| |__| |__| |__| |__| |__| |______|   |___|   |______

void s_connectionreset()
{
   int i;
   
   HUMShadow = HUMShadow | (HUMDDrBit);  //'Set DDR for output
   BusIOWrite8(HUMPort, HUMShadow);
    
     
   HUMShadow = HUMShadow | (HUMDoutBit);     //' high  Data
   BusIOWrite8(HUMPort,HUMShadow);
     
     
   HUMShadow = HUMShadow & (~HUMCLKBit);     //' Lower Clock
   BusIOWrite8(HUMPort, HUMShadow);
     
   for(i= 0;i<=8;i++)  //' 9 Cycles
   {
      HUMShadow = HUMShadow | HUMCLKBit;
      BusIOWrite8(HUMPort,HUMShadow);                   //    ' Raise Clock
        
      HUMShadow = HUMShadow & (~HUMCLKBit);
      BusIOWrite8(HUMPort,HUMShadow);                    //   ' Lower Clock
        
   }
}

void s_read_byte(float *raw_hum,int bit_pos,int ack) 
{
    
   unsigned char I;
	
   long portvalue;
        
   HUMShadow = HUMShadow & (~HUMDDrBit);  //'Set DDR for input to release data line
   BusIOWrite8(HUMPort, HUMShadow);
     
   I = 0x80;
    
   while ((I) > 0)
   {
      HUMShadow = HUMShadow | (HUMCLKBit);      //' Raise Clock
      BusIOWrite8(HUMPort, HUMShadow);
              
      portvalue = BusIORead8(HUMPort);//    ' Read Port
        
      if ((portvalue & HUMDinBit) > 0)//                       'check bit
      {
                
	 *raw_hum+=(float)pow(2,bit_pos);
      }
		
      HUMShadow = HUMShadow & (~HUMCLKBit);     //' Lower Clock
      BusIOWrite8(HUMPort, HUMShadow);
      //' MsgBox "lower clock"
      I = I / 2;                       //                'shift bit for masking
      bit_pos--;
   }
    
   HUMShadow = HUMShadow | (HUMDDrBit) ;// 'Set DDR for output
   BusIOWrite8(HUMPort, HUMShadow);
    
   
   if (ack)
   {
      HUMShadow = HUMShadow & (~HUMDoutBit);  //   ' Lower  Data ---- in case of "ack==1" pull down DATA-Line since checksum is not used
      BusIOWrite8(HUMPort, HUMShadow);
     
   }
   else
   {
      HUMShadow = HUMShadow | (HUMDoutBit); //    ' Raise  Data
      BusIOWrite8(HUMPort, HUMShadow);
        
   }
   HUMShadow = HUMShadow | (HUMCLKBit);      //' Raise Clock clk #9 for ack
   BusIOWrite8(HUMPort, HUMShadow);
    
    
   if(1);
   if(1);
   if(1);
    
   HUMShadow = HUMShadow & (~HUMCLKBit);     //' Lower Clock
   BusIOWrite8(HUMPort, HUMShadow);
    
   HUMShadow = HUMShadow & (~HUMDDrBit);//  'Set DDR for input to release data line
   BusIOWrite8(HUMPort, HUMShadow);
    
}

/////////////////////////////////////////////////////////////////////////////
// Local Support Functions
/////////////////////////////////////////////////////////////////////////////
static void TempBusIOWrite8(long TP, int TS) {
    BusIOWrite8(TP, (BusIORead8(TempPort) & 0xE0) | (TS & 0x1F));
}

static void TempCommand(int cmd){
    int i;

    // Set access window
    if (TempWindow > 0) TempBusIOWrite8(TempWindow, TempBank);  

    TempShadow = TempShadow | TempDDRBit;      		// Set As Output
    TempBusIOWrite8(TempPort, TempShadow);

    for (i=0; i<8; i++) {                              	// LSB First
       // Lower Data
       if (((cmd >> i) & 0x01) == 0) TempShadow = TempShadow & (~TempDTOBit); 
       else TempShadow = TempShadow | TempDTOBit;       // Raise Data

	TempBusIOWrite8(TempPort, TempShadow);         	// Set data

	TempShadow = TempShadow & (~TempCLKBit);      	// Lower Clock
	TempBusIOWrite8(TempPort, TempShadow);

	TempShadow = TempShadow | TempCLKBit;          	// Raise Clock
	TempBusIOWrite8(TempPort, TempShadow);
    }
    //
    // Delay for 10 msec for the EEPROM.  See page 8 of DS1620 spec from 20
    // July, 1999.  zz
    //
    delay(10);

}


static int TempInput( int Cmd){
    int Dta, Bit, i;
    
    TempCommand (Cmd);

    TempShadow = TempShadow & (~TempDDRBit);         // Set As Input
    TempBusIOWrite8(TempPort, TempShadow);
    Dta = 0;
    for (i=0;i<9;i++) {
//  for (i=0;i<( Cmd==0xAC ? 8 : 9 ) ; i++) {           // zz
 	TempShadow = TempShadow & (~TempCLKBit);        // Lower Clock
	TempBusIOWrite8(TempPort, TempShadow);
	Bit = BusIORead8(TempPort) & TempDTIBit;        
	Dta = Dta >> 1;
	if (Bit > 0) Dta = Dta + 0x100;
	TempShadow = TempShadow | TempCLKBit;           // Raise Clock 
	TempBusIOWrite8(TempPort, TempShadow);          
    }
    return(Dta);			// Return Temperature
//  return(Dta>>1);			// Return Temperature zz
}

static void TempOutput (int Cmd, int Dta) {
    int i;
    
    TempCommand (Cmd);

    TempShadow = TempShadow | TempDDRBit;            	// Set As Output
    TempBusIOWrite8(TempPort, TempShadow);

//  Dta = Dta << 1;                           //Because Sib said so! zz       

    for (i=0;i<9;i++) {	                             	// LSB First
	if (((Dta >> i) & 0x01) == 0) TempShadow = TempShadow &  (~ TempDTOBit); // Lower Data
	else TempShadow = TempShadow | TempDTOBit;            			 // Raise Data
	TempBusIOWrite8(TempPort, TempShadow);	      	// Set data
	TempShadow = TempShadow & (~TempCLKBit);     	// Lower Clock
	TempBusIOWrite8(TempPort, TempShadow);
	TempShadow = TempShadow | TempCLKBit;         	// Raise Clock
	TempBusIOWrite8(TempPort, TempShadow);
    }
}

static void TempReset(int ch){

    if (ch==0) {
	TempShadow = TempShadow & (~TempResetBit);		// Lower Reset
	TempBusIOWrite8(TempPort, TempShadow);
	sdelay();
	TempShadow = TempShadow | TempResetBit;
	TempBusIOWrite8(TempPort, TempShadow);			// Raise Reset
    }
    else {
	TempShadow = TempShadow & (~TempResetBit1);		// Lower Reset
	TempBusIOWrite8(TempPort, TempShadow);
	sdelay();
	TempShadow = TempShadow | TempResetBit1;
	TempBusIOWrite8(TempPort, TempShadow);			// Raise Reset
    }

}

static void TempDisable(int ch){

    if (ch==0) {
	TempShadow = TempShadow & (~TempResetBit);		// Lower Reset
	TempBusIOWrite8(TempPort, TempShadow);
    }
    else {
	TempShadow = TempShadow & (~TempResetBit1);		// Lower Reset
	TempBusIOWrite8(TempPort, TempShadow);
    }

}

static void TempEnable(int ch){

    if (ch==0) {
	TempShadow = TempShadow | TempResetBit;
	TempBusIOWrite8(TempPort, TempShadow);			// Raise Reset
    }
    else {
	TempShadow = TempShadow | TempResetBit1;
	TempBusIOWrite8(TempPort, TempShadow);			// Raise Reset
    }

}

//
// Wrappers for reading and writing a byte to the IO bus.  inp and outp are
// the QNX equivalent commands.
//
static int BusIORead8( int addr )
{
   unsigned value;
   value = inp( addr );
   return( (int) value );
}

static int BusIOWrite8( int addr, int value )
{
   unsigned out;
   out = outp( addr, value );
   return( (int) out );
}
//
// I'm guessing: One millisecond delay
//
static void sdelay()
{
   pdelay( 10000 );          // 10,000 is the minimum QNX delay of 10 ms. zz
}
//
// So far, I've only been able to find a delay function in QNX that works in
// milliscenconds.  So, round to the nearest millisecond.
//
static void pdelay( int microsec )
{
   int millisec;
   if( microsec < 1000 ) millisec = 1;
   else millisec = microsec/1000;
   delay( millisec );
}


