/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT    Copyright (C) 1992 IBM Corporation                           */
/*                                                                           */
/*    The following IBM OS/2 source code is provided to you solely for       */
/*    the purpose of assisting you in your development of OS/2 device        */
/*    drivers. You may use this code in accordance with the IBM License      */
/*    Agreement provided in the IBM Developer Connection Device Driver       */
/*    Source Kit for OS/2. This Copyright statement may not be removed.      */
/*                                                                           */
/*****************************************************************************/
/*static char *SCCSID = "src/dev/dasd/ibm/ibm1s506/s506ps2.c, idsk, r207, 8.005p 93/03/18";*/
/**************************************************************************
 *
 * SOURCE FILE NAME =  S506PS2.C
 *
 * DESCRIPTIVE NAME = IBM1S506.ADD - Adapter Driver for ST506/IDE DASD
 *
 *
 *
 * VERSION = V2.0
 *
 * DATE
 *
 * DESCRIPTION : Adapter Driver PS/2 IDE Port routines.
 *
 * Purpose:
 *
 *
 *
 *
 *
*/
 #define INCL_NOBASEAPI
 #define INCL_NOPMAPI
 #define INCL_NO_SCB
 #define INCL_INITRP_ONLY
 #define INCL_DOSERRORS
 #include "os2.h"
 #include "dos.h"
 #include "bseerr.h"
 #include "dskinit.h"
 #include <scb.h>
 #include <abios.h>

 #include "iorb.h"
 #include "reqpkt.h"
 #include "dhcalls.h"
 #include "addcalls.h"

 #include "s506cons.h"
 #include "s506type.h"
 #include "s506regs.h"
 #include "s506ext.h"
 #include "s506pro.h"
 #include "s506ps2.h"


/*------------------------------------*/
/*                                    */
/* SetPS2DiskLight                    */
/* ---------------                    */
/*                                    */
/*                                    */
/*------------------------------------*/
VOID NEAR SetPS2DiskLight( USHORT On )
{
  USHORT        Data;

  /* Update LightCount to keep track of nested light On/Off requests.
   * It's possible to receive more Off requests than On requests, due
   * to error condition handling of commands (defect 153510).  Therefore a
   * check is made here not to decrement below 0.  This may cause the light to
   * be turned off while a disk access is still in progress, but this
   * condition should not be noticible to the user.
   */
  if (On)                                                           /*@V153510*/
    ++LightCount;                                                   /*@V153510*/
  else                                                              /*@V153510*/
    if (LightCount > 0)  --LightCount;                              /*@V153510*/

  if ( (LightState == 0) != (LightCount == 0) )
  {
    DISABLE

    LightState = (LightCount != 0);

    inp( PS2_CTRL_PORT_A, Data )
    IODelay();

    if ( LightState )
    {
      Data |= PS2_FIXED_DISK_LIGHT;
    }
    else
    {
      Data &= ~PS2_FIXED_DISK_LIGHT;
    }
    outp( PS2_CTRL_PORT_A, Data );
    IODelay();


    ENABLE
  }
}

/*------------------------------------*/
/*                                    */
/* SetupPS2IDEPort                    */
/* ---------------                    */
/*                                    */
/*                                    */
/*------------------------------------*/

BOOL NEAR SetupPS2IDEPort( USHORT BasePort, SHORT OnOff )           /*@V147576*/
{
  USHORT        Data;
  USHORT        PS2_Setup_Reg;
  USHORT        PS2_Planar_Pos;
  BOOL          Result = TRUE;                                      /*@V147576*/

  if( BasePort == FX_PRIMARY )                                      /*@V147576*/
  {                                                                 /*@V147576*/
    DISABLE

    /*--------------------------*/
    /* Enable Planar Setup Mode */
    /*--------------------------*/
    inp( PS2_SETUP_REG, PS2_Setup_Reg );
    IODelay();

    Data = ~PS2_DISABLE_PLANAR_SETUP;

    outp( PS2_SETUP_REG, Data );
    IODelay();

    /*---------------------------------*/
    /* Enable Fixed Disk POS Reg (103) */
    /*---------------------------------*/
    inp( PS2_PLANAR_POS_REG, PS2_Planar_Pos );
    IODelay();

    PS2_Planar_Pos |= ENABLE_FIXED_POS;

    outp( PS2_PLANAR_POS_REG, PS2_Planar_Pos );
    IODelay();

    /*-------------------------------------------------*/
    /* Enable/Disable Integrated Fixed Disk Controller */
    /*-------------------------------------------------*/
    inp( PS2_FIXED_POS_REG, Data );
    IODelay();

    /*-----------------------------------------------*/
    /* Our engineers cant seem to figure out how     */
    /* to share bits in 3F6/3F7 between the diskette */
    /* and IDE controllers!                          */
    /*-----------------------------------------------*/

    if( OnOff == ON )                                               /*@V147576*/
    {
      Data |= (ENABLE_FIXED_DRIVE | REG_3F7_TO_DSKT);
      Data &= ~REG_3F6_TO_DSKT;
    }
    else if( OnOff == OFF )                                         /*@V147576*/
    {
      Data &= ~ENABLE_FIXED_DRIVE;

      /*--------------------------------------------------*/
      /* Setting the 3F6/3F7 control bits on a Mod 30-286 */
      /* causes the machine to reboot!                    */
      /*--------------------------------------------------*/
      if ( MachineID != MCHID_30286 )
      {
        Data |= (REG_3F6_TO_DSKT | REG_3F7_TO_DSKT);
      }
    }

    outp( PS2_FIXED_POS_REG, Data );
    IODelay();

    /*---------------------------------------*/
    /* Restore original Planar setup reg (94)*/
    /*---------------------------------------*/
    outp( PS2_SETUP_REG, PS2_Setup_Reg )
    IODelay();

    ENABLE
    Result = FALSE;                                                 /*@V147576*/
  }                                                                 /*@V147576*/
  return( Result );                                                 /*@V147576*/
}

#ifdef MCA                                                         /*@V117508*/
                                                                   /*VVVVVVVV*/
USHORT Get_IDE_LID ( NPATBL npAT, PMACHINE_CONFIG_INFO pMCHI )
{
   USHORT                rc = 0;
   USHORT                LidOk = 0;
   USHORT                LidIndex;
   NPABRB_RETLIDPARMS    npRLP;
   USHORT                Lid = -1;

   if ((pMCHI->Model == LACUNA_MODEL) &&
       ((pMCHI->SubModel == LACUNA_SUBMODEL) ||                     /*@V126821*/
        (pMCHI->SubModel == MACH5_SUBMODEL)) )                      /*@V126821*/
   {
      SystemType = LACUNA;
      npAT->Flags |= ATBF_PS2IDEPORT;  /* Lacuna needs to turn on hard disk
                                          light manualy */
      LidOk = 1;                       /* No lid on Lacuna - Fake one */
   }
   else
   {
      SystemType = NOT_LACUNA;
   }

   npRLP = (NPABRB_RETLIDPARMS) &InitABRB1;
   LidIndex   = 1;
   while ( (rc = DevHelp_GetLIDEntry( DEVID_DISK, LidIndex, 0, &Lid )) == 0 ||
            rc == (ERROR_LID_ALREADY_OWNED|0x8000) ||
            rc == (ERROR_NOT_YOUR_LID|0x8000) )
   {
      LidIndex++;
      if (rc!=0)
         continue;

      /*-----------------------*/
      /* Obtain LID Parameters */
      /*-----------------------*/
      npRLP->abrbh.Length    = sizeof (ABRB_RETLIDPARMS);
      npRLP->abrbh.LID       = Lid;
      npRLP->abrbh.Unit      = 0;
      npRLP->abrbh.RC        = ABRC_START;
      npRLP->abrbh.Function  = ABFC_RET_LID_PARMS;
      rc = DevHelp_ABIOSCall( Lid, (NPBYTE) npRLP, ABIOS_EP_START );

      /*-------------------------------------*/
      /* In case of error deallocate the LID */
      /*-------------------------------------*/
      if ( rc || (npRLP->abrbh.RC != ABRC_COMPLETEOK) )
      {
         DevHelp_FreeLIDEntry( Lid );
         continue;
      }
      else
      {
         LidOk = 1;
      }

      if ( npRLP->SecDeviceID != 3)
      {
         DevHelp_FreeLIDEntry( Lid );
         continue;
      }
   }
   return( LidOk );
}

USHORT MCA_IDE_Generated_IRQ ( NPACB npACB )
{
  USHORT     Data     = 0;
  USHORT     Port      = 0;
  USHORT     McaIrq    = 0;

  DISABLE

  /* is this a standard IRQ */
  if (( npACB->IntLevel == MCA_IDE_IRQ0 ) ||
      ( npACB->IntLevel == MCA_IDE_IRQ1 ))
  {
     /* get status of IRQ line */
     Port = MCA_IDE_IRQ_STATUS_PORT;
     inp ( Port, Data );
     IODelay();

     /* are we concerned with the first IRQ or second? */
     if ( npACB->IntLevel == MCA_IDE_IRQ0 )
     {
        /* we are concerned with the first MCA_IDE IRQ */
        if ( Data & MCA_IDE_IRQ0_BIT )
        {
           McaIrq = 1;
        }
     }
     else
        /* we are concerned with the second MCA_IDE IRQ */
        if ( Data & MCA_IDE_IRQ1_BIT )
        {
           McaIrq = 1;
        }
  }
  else  /* If we are on a Mach 5 and the IRQ is not 14 or 15, we must    */
        /* assume there is additional hardware that follows the industry */
        /* spec and that the interrupt is ours                           */
  {
     McaIrq = 1;
  }

  ENABLE

  return( !McaIrq );
}

USHORT Lacuna_IDE_Generated_IRQ ( NPACB npACB )
{
  USHORT     Data1     = 0;
  USHORT     Data2     = 0;
  USHORT     Port      = 0;
  USHORT     McaIrq    = 0;
  BOOL       ResetPort = 0;

  DISABLE

  if ( npACB->IntLevel == LACUNA_IRQ)
  {
    /* Read port to determine if IDE status port is valid */
    Port = LACUNA_SECURITY_OVERRIDE_PORT;
    inp( Port, Data1 );
    IODelay();

    if (!( Data1 & LACUNA_IDE_STATUS_PORT_ACTIVE ))
    {
       /* Validate IDE status port */
       ResetPort = 1;
       Data1 |= LACUNA_IDE_STATUS_PORT_ACTIVE;
       Port = LACUNA_SECURITY_OVERRIDE_PORT;
       outp ( Port, Data1);
       IODelay();
    }

    /* Read IRQ status port */
    Port = LACUNA_IDE_IRQ_STATUS_PORT;
    inp ( Port, Data2 );
    IODelay();

    if ( Data2 & LACUNA_IDE_IRQ_ACTIVE )
    {
       /* IDE is causing an interrupt */
       McaIrq = 1;
    }

    /* Reset security override port is necessary */
    if ( ResetPort )
    {
       Data1 &= ~LACUNA_IDE_STATUS_PORT_ACTIVE;
       Port = LACUNA_SECURITY_OVERRIDE_PORT;
       outp ( Port, Data1 );
       IODelay();
    }
  }
  else  /* If we are on a Lacuna and the IRQ is not 14, we must assume  */
        /* there is additional hardware that follows the industry spec  */
        /* and that the interrupt is ours                               */
  {
     McaIrq = 1;
  }

  ENABLE

  return( !McaIrq );
}

VOID MCA_IRQ_Status_Clear ( NPACB npACB )
{
   USHORT Port;
   USHORT Data;

   /* Only clear this register for IRQ's the planner IDE owns */
   if ( (npACB->IntLevel ==  MCA_IDE_IRQ0 ) ||
        ( npACB->IntLevel == MCA_IDE_IRQ1 ))
   {
      DISABLE

      /* The read of the status register of the drive will clear the  */
      /* interrupt.  Now we will clear the bit it Data1 to reset the  */
      /* MCA_IDE_IRQ_STATUS_PORT for this IRQ level                   */

      /* get old status of IRQ line */
      Port = MCA_IDE_IRQ_STATUS_PORT;
      inp ( Port, Data );
      IODelay();

      Data |= ( MCA_IDE_IRQ0_BIT | MCA_IDE_IRQ1_BIT );

      if ( npACB->IntLevel == MCA_IDE_IRQ0 )
      {
         Data &= ~MCA_IDE_IRQ0_BIT;
      }
      else
      {
         Data &= ~MCA_IDE_IRQ1_BIT;
      }

      /* clear the MCA_IDE_IRQ_STATUS_PORT bit for this IRQ level */
      Port = MCA_IDE_IRQ_STATUS_PORT;
      outp ( Port, Data );
      IODelay();

      ENABLE
   }
}

VOID Clear_IDE_IRQ_Status_Bit ( NPACB npACB )
{
   DISABLE
   GetStatusReg( npACB );

   /* if not a Lacuna, we need to clear the interrupt bit in           */
   /* MCA_IDE_IRQ_STATUS_PORT                                          */
   if (!(SystemType == LACUNA) )
      MCA_IRQ_Status_Clear( npACB );
}                                                                  /*AAAAAAAA*/
#endif                                                             /*@V117508*/

