/*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 = "%w% %e%";*/
/**************************************************************************
 *
 * SOURCE FILE NAME = S506OEM.C
 *
 * DESCRIPTIVE NAME = IBM1S506.ADD - Adapter Driver for ST506/IDE DASD
 *
 *
 *
 * VERSION = V2.0
 *
 * DATE
 *
 * DESCRIPTION : Adapter Driver OEM Specific routines
 *
 * Purpose:
 *
 * Note:
 *  All functions contained within assume the user first has called
 *  GetBiosInfo to setup global pointers to OEMHLP.
 *
*/
#define INCL_NOBASEAPI
#define INCL_NOPMAPI
#define INCL_NO_SCB
#define INCL_DOSERRORS
#include "os2.h"
#include "dskinit.h"
#include "dhcalls.h"
#include "strat2.h"
#include "reqpkt.h"
#include "iorb.h"
#include "addcalls.h"
#include "s506cons.h"
#include "s506type.h"
#include "s506ext.h"
#include "s506pro.h"
                                                                                                     /* ^^^, @V151345 */

VOID CallOEMHlp( PRPH pRPH)
{
   VOID (FAR *pFunctionCall)(VOID);

   if (pFunctionCall = pOEMHLPEntry)
   {
      _asm {push es
            push bx
            push ds
            push di
            push si
            mov  bx, word ptr pRPH[0]
            mov  es, word ptr pRPH[2]
            mov  ds, OemhlpDS
            }

      (*pFunctionCall)();

      _asm {pop si
            pop di
            pop ds
            pop bx
            pop es
            }
   }
   else
   {
      pRPH->Status = STERR + STDON;
   }
}


BOOL NEAR ReadPCIConfigSpace( NPPCI_INFO npPCIInfo,                 /*@V129765*/
                              UCHAR ConfigReg,                      /*@V129765*/
                              PULONG Data, USHORT Size )            /*@V129765*/
{

   PCI_PARM_READ_CONFIG PCIParmPkt;
   PCI_DATA             PCIDataPkt;
   RP_GENIOCTL          IOCtlRP;    /* From reqpkt.h */
   PRPH pRPH = (PRPH)&IOCtlRP;

   switch ( Size )                                                  /*@V129765*/
   {                                                                /*@V129765*/
      case 1:                                                       /*@V129765*/
         (UCHAR)*Data = 0;                                          /*@V129765*/
         break;                                                     /*@V129765*/
      case 2:                                                       /*@V129765*/
         (USHORT)*Data = 0;                                         /*@V129765*/
         break;                                                     /*@V129765*/
      case 4:                                                       /*@V129765*/
         (ULONG)*Data = 0L;                                         /*@V129765*/
         break;                                                     /*@V129765*/
#ifdef DEBUG                                                        /*@V129765*/
      default:                                                      /*@V129765*/
         _asm { int 3 }                                             /*@V129765*/
#endif                                                              /*@V129765*/
   }                                                                /*@V129765*/

   /* Setup Parm Packet */
   PCIParmPkt.PCISubFunc = PCI_READ_CONFIG;
   PCIParmPkt.BusNum     = npPCIInfo->BusNum;                       /*@V129765*/
   PCIParmPkt.DevFunc    = npPCIInfo->DevFunc;                      /*@V129765*/
   PCIParmPkt.ConfigReg  = ConfigReg;
   PCIParmPkt.Size       = Size;

   /* Setup IOCTL Request Packet */
   IOCtlRP.Category = 0x00;
   IOCtlRP.Function = PCI_FUNC;
   IOCtlRP.ParmPacket = (PUCHAR)&PCIParmPkt;
   IOCtlRP.DataPacket = (PUCHAR)&PCIDataPkt;
   IOCtlRP.rph.Len = sizeof(IOCtlRP);
   IOCtlRP.rph.Unit = 0;
   IOCtlRP.rph.Cmd  = 0x10;      /* Generic IOCtl */
   IOCtlRP.rph.Status = 0;

   CallOEMHlp(pRPH);

#ifdef DEBUG_TRITON
      _asm
      {
         push ax
         push bx
         push cx
         push dx
         mov al, ConfigReg
         mov ah, 0x88
         mov bl, PCIParmPkt.Size
         mov bh, 0
         mov cx, PCIDataPkt.Data_Read_Config.usData
         mov dx, 0x0
         int 3
         pop dx
         pop cx
         pop bx
         pop ax
      }
#endif

   if (IOCtlRP.rph.Status & STERR)
      return( TRUE );

   if (PCIDataPkt.bReturn != PCI_SUCCESSFUL)
      return( TRUE );

   switch ( Size )                                                  /*@V129765*/
   {                                                                /*@V129765*/
      case 1:                                                       /*@V129765*/
         (UCHAR)*Data = PCIDataPkt.Data_Read_Config.ucData;         /*@V129765*/
         break;                                                     /*@V129765*/
      case 2:                                                       /*@V129765*/
         (USHORT)*Data = PCIDataPkt.Data_Read_Config.usData;        /*@V129765*/
         break;                                                     /*@V129765*/
      case 4:                                                       /*@V129765*/
         (ULONG)*Data = PCIDataPkt.Data_Read_Config.ulData;         /*@V129765*/
   }                                                                /*@V129765*/

   return( FALSE );
}


BOOL NEAR WritePCIConfigSpace( NPPCI_INFO npPCIInfo,                /*@V129765*/
                               UCHAR ConfigReg,                     /*@V129765*/
                               ULONG Data, UCHAR Size )            /*@V129765*/
{
   BOOL   rc;
   PCI_PARM_WRITE_CONFIG  PCIParmPkt;
   PCI_DATA               PCIDataPkt;
   RP_GENIOCTL            IOCtlRP;    /* From reqpkt.h */
   PRPH pRPH = (PRPH)&IOCtlRP;
   ULONG temp;

   /* Setup Parm Packet */
   PCIParmPkt.PCISubFunc = PCI_WRITE_CONFIG;
   PCIParmPkt.BusNum     = npPCIInfo->BusNum;                       /*@V129765*/
   PCIParmPkt.DevFunc    = npPCIInfo->DevFunc;                      /*@V129765*/
   PCIParmPkt.ConfigReg  = ConfigReg;
   PCIParmPkt.Size       = Size;
   PCIParmPkt.Data       = Data;

   /* Setup IOCTL Request Packet */
   IOCtlRP.Category = 0x00;
   IOCtlRP.Function = PCI_FUNC;
   IOCtlRP.ParmPacket = (PUCHAR)&PCIParmPkt;
   IOCtlRP.DataPacket = (PUCHAR)&PCIDataPkt;
   IOCtlRP.rph.Len = sizeof(IOCtlRP);
   IOCtlRP.rph.Unit = 0;
   IOCtlRP.rph.Cmd  = 0x10;      /* Generic IOCtl */
   IOCtlRP.rph.Status = 0;

   CallOEMHlp(pRPH);

   {
      ULONG  ulDataReadBack;
      USHORT RegMask;                                         /*@V151345*/

#ifdef DEBUG_TRITON
      _asm
      {
         push ax
         push bx
         push cx
         push dx
         mov al, ConfigReg
         mov ah, 0x99
         mov bl, PCIParmPkt.Size
         mov bh, 0
         mov cx, WORD PTR [bp+8]
         mov dx, WORD PTR [bp+10]
         int 3
         pop dx
         pop cx
         pop bx
         pop ax
      }
#endif
      /*
      ** Read back the value just written and make sure it is same.
      */
      if( rc = ReadPCIConfigSpace( npPCIInfo, ConfigReg,
                                   &ulDataReadBack, Size ) )
      {
         _asm int 3
      }

      switch( Size )
      {
      case 1 :
         if( (UCHAR)Data != (UCHAR)ulDataReadBack )
         {
#ifdef DEBUG_TRITON
            _asm
            {
               push ax
               mov ax, 0x0101
               int 3
               pop ax
            }
#endif
            rc = PciSetReg( npPCIInfo, ConfigReg, Data, Size );
         }
         break;

      case 2 :
         if( (USHORT)Data != (USHORT)ulDataReadBack )
         {
#ifdef DEBUG_TRITON
            _asm
            {
               push ax
               mov ax, 0x0202
               int 3
               pop ax
            }
#endif
            rc = PciSetReg( npPCIInfo, ConfigReg, Data, Size );
         }
         break;

       case 4 :
         if( (ULONG)Data != (ULONG)ulDataReadBack )
         {
#ifdef DEBUG_TRITON
            _asm
            {
               push ax
               mov ax, 0x0404
               int 3
               pop ax
            }
#endif
            rc = PciSetReg( npPCIInfo, ConfigReg, Data, Size );
         }
         break;

       default:
         if( Data != ulDataReadBack )
         {
            _asm int 3
            return( TRUE );
         }
      } /* end of switch */
   }

   if( rc )                                                         /*@V153743*/
      return( TRUE );                                               /*@V153743*/

   if (IOCtlRP.rph.Status & STERR)
      return( TRUE );

   if (PCIDataPkt.bReturn != PCI_SUCCESSFUL)
      return( TRUE );

   return( FALSE );
}


/*                                                                    @V129765
**  ConfigurePCI()                                                    VVVVVVVV
**
**  Configure the PCI device according to the configuration records
**  stored in the PCIConfigOp[] array.
**
**  The caller provides the current PCI operation Phase.  Read the PCI
**  address stored in the configuration record.  Test the input value
**  against the OrOn and AndOff masks.  If differences are indicated,
**  then write the modified data back to the same PCI configuration
**  address.
**
**  The operation is performed only if the Configuration Record's
**  phase bit matches the caller's requested Phase bit.
*/
BOOL NEAR ConfigurePCI( NPACB npACB, USHORT InPhase )               /*@V153620*/
{
   NPPCI_INFO npPCIInfo = &npACB->PCIInfo;
   USHORT     ConfigRec = npPCIInfo->FirstConfigRec;
   ULONG      ulDataRead;
   ULONG      ulData;
   BOOL       WriteData = FALSE;
   BOOL       rc = FALSE;
   USHORT     Phase;                                                /*@V153620*/
                                                                    /*@V153620*/
   /*                                                                 @V153620
   ** Following loop performs one and only one of the following       @V153620
   ** operations for each PCIConfigOp[] record:                       @V153620
   **                                                                 @V153620
   **   1. Read and store a PCI configuration register, if            @V153620
   **      PCIConfigOp[]->SavePhase contains InPhase.                 @V156660
   **   2. Retrieve and write a PCI configuration register.           @V153620
   **      PCIConfigOp[]->RestPhase contains InPhase.                 @V156660
   **   3. Perform bit set and clear operations on a PCI              @V153620
   **      configuration register.                                    @V153620
   **   4. Exits the loop if the record's Phase field is 0.           @V153620
   */                                                               /*@V153620*/
   while( Phase = PCIConfigOp[ConfigRec].Phase )                    /*@V153620*/
   {                                                                /*@V153620*/
      if( Phase & InPhase )                                         /*@V156660*/
      {                                                             /*@V156660*/
         /*                                                           @V153620
         ** Read and store a PCI configuration register.              @V153620
         */                                                         /*@V153620*/
         if( PCIConfigOp[ConfigRec].SavePhase & InPhase )           /*@V156660*/
         {                                                          /*@V153620*/
#ifdef DEBUG_TRITON
            _asm
            {
               push ax
               mov ax, 0x1111
               int 3
               pop ax
            }
#endif
            /* Overload the OrOn field to hold the data read in. */ /*@V153620*/
            if( rc = ReadPCIConfigSpace( npPCIInfo,                 /*@V153620*/
                                  PCIConfigOp[ConfigRec].ConfigReg, /*@V153620*/
                                  &PCIConfigOp[ConfigRec].OrOn,     /*@V153620*/
                                  PCIConfigOp[ConfigRec].Size ) )   /*@V153620*/
            {                                                       /*@V153620*/
#ifdef DEBUG                                                        /*@V153620*/
               _asm int 3                                           /*@V153620*/
#endif                                                              /*@V153620*/
            }                                                       /*@V153620*/
         }                                                          /*@V153620*/
         /*                                                           @V153620
         ** Retrieve and write a PCI configuration register.          @V153620
         */                                                         /*@V153620*/
         else if( PCIConfigOp[ConfigRec].RestPhase & InPhase )      /*@V156660*/
         {                                                          /*@V153620*/
#ifdef DEBUG_TRITON
            _asm
            {
               push ax
               mov ax, 0x2222
               int 3
               pop ax
            }
#endif
            if( rc = WritePCIConfigSpace( npPCIInfo,                /*@V153620*/
                                   PCIConfigOp[ConfigRec].ConfigReg,/*@V153620*/
                                   PCIConfigOp[ConfigRec].OrOn,     /*@V153620*/
                                   PCIConfigOp[ConfigRec].Size ) )  /*@V153620*/
            {                                                       /*@V153620*/
#ifdef DEBUG                                                        /*@V153620*/
               _asm int 3                                           /*@V153620*/
#endif                                                              /*@V153620*/
            }                                                       /*@V153620*/
         }                                                          /*@V153620*/
         /*                                                           @V153620
         ** Perform bit set and clear operations on a PCI             @V153620
         ** configuration register.                                   @V153620
         */                                                         /*@V153620*/
         else                                                       /*@V156660*/
         {
#ifdef DEBUG_TRITON
            _asm
            {
               push ax
               mov ax, 0x3333
               int 3
               pop ax
            }
#endif
            if( rc = ReadPCIConfigSpace( npPCIInfo,
                                  PCIConfigOp[ConfigRec].ConfigReg,
                                  &ulDataRead,
                                  PCIConfigOp[ConfigRec].Size ) )
            {
#ifdef DEBUG
               _asm int 3
#endif
            }
            else
            {
               /*
               ** Create the mask of what the register should be and
               ** compare it to what was read in.  If no changes, then
               ** done with this record.  All the on bits in OrOn will
               ** be set, all bits off in AndOff will be reset.
               */
               ulData = ulDataRead | PCIConfigOp[ConfigRec].OrOn;
               ulData &= PCIConfigOp[ConfigRec].AndOff;
               WriteData = FALSE;                                   /*@V156660*/

               switch( PCIConfigOp[ConfigRec].Size )
               {
               case 1 :
                  if( (UCHAR)ulData != (UCHAR)ulDataRead )
                     WriteData = TRUE;
                  break;
               case 2 :
                  if( (USHORT)ulData != (USHORT)ulDataRead )
                     WriteData = TRUE;
                  break;
               default:
                  if( ulData != ulDataRead )
                     WriteData = TRUE;
               }

               if( WriteData )
               {
                  if( rc = WritePCIConfigSpace( npPCIInfo,
                                         PCIConfigOp[ConfigRec].ConfigReg,
                                         ulData,
                                         PCIConfigOp[ConfigRec].Size ) )
                  {
#ifdef DEBUG
                     _asm int 3
#endif
                  }
               }
            }   /* if( rc = ReadPCIConfigSpace( npPCIInfo,... */
         }  /* operation type, Save, Restore, or Mask */
      }   /* if ( Phase & InPhase ) */

      ConfigRec++;
   }   /* while ( PCIConfigOp[ConfigRec].Phase ) */

   /*                                                                 @V147576
   ** Call any PCI device dependent routine for this phase.           @V147576
   */                                                               /*@V147576*/
   switch( InPhase )                                                /*@V147576*//*@V153620*/
   {                                                                /*@V147576*/
      case PCIC_START :                                             /*@V147576*/
         if( npPCIInfo->Ident.PCIFunc_Init )                        /*@V147576*/
            rc = (npPCIInfo->Ident.PCIFunc_Init)( npACB );          /*@V147576*/
         break;                                                     /*@V147576*/
      case PCIC_INIT_COMPLETE :                                     /*@V147576*/
         if( npPCIInfo->Ident.PCIFunc_InitComplete )                /*@V147576*/
            rc = (npPCIInfo->Ident.PCIFunc_InitComplete)( npACB );  /*@V147576*/
         break;                                                     /*@V147576*/
   }                                                                /*@V147576*/

   return( rc );                                                    /*AAAAAAAA*/
}                                                                   /*@V129765*/


/*                                                                    @V147576
**  CMD640_0_InitComplete()                                           @VVVVVVV
**
**  CMD640 specific routine for initialization complete processing on
**  the first CMD640 chip.  For the first CMD640 chip located it is
**  necessary to assign both channels to the same hardware resource
**  as this chip requires serialized access to the 2 IDE interfaces.
**
**  It is assumed if the ports are active on the first CMD chip that
**  it provides IDE ports 0 and 1.
**
**  During initialization both ACBs for the CMD640 are assigned
**  unique hardware resources.
*/
BOOL FAR CMD640_0_InitComplete( NPACB npACB )
{
   if( npACB->PCIInfo.Ident.Device == PCIDevice[PCID_CMD640_0].Ident.Device &&
       npACB->PCIInfo.Ident.Vendor == PCIDevice[PCID_CMD640_0].Ident.Vendor &&
       npACB->PCIInfo.Ident.Index  == PCIDevice[PCID_CMD640_0].Ident.Index  )
   {
      if( npACB->HWResourceIndex == 1 )
      {
         DISABLE
         HWResource[0].npFirstACBX->npNextACBX = npACB;
         npACB->npNextACBX = 0;
         HWResource[1].npFirstACBX = 0;
         npACB->HWResourceIndex = 0;
         ENABLE
      }
      else if( npACB->HWResourceIndex == 3 )
      {
         DISABLE
         HWResource[2].npFirstACBX->npNextACBX = npACB;
         npACB->npNextACBX = 0;
         HWResource[3].npFirstACBX = 0;
         npACB->HWResourceIndex = 2;
         ENABLE
      }
   }
   return( FALSE );                                                 /*@AAAAAAA*/
}                                                                   /*@V147576*/

                                                                                                                        /* vvv, @V151345 */
void PciSetRegMech1( USHORT regmask, UCHAR index, ULONG val, USHORT size )
{
   register USHORT port;

   DISABLE                                                          /*@V159979*/
   outpd( PCI_CONFIG_ADDRESS,                                       /*@V153743*/
          0x80000000 | regmask | (index & 0xfc) );
   port = PCI_CONFIG_DATA + (index & 0x03);                         /*@V153743*/

   switch( size )
   {
      case 1 :
         outp(port,val);
         break;
      case 2:
         outwp(port,val);
         break;
      case 4:
         outpd(port,val);
         break;
      default:
         break;
    }
    outpd( PCI_CONFIG_ADDRESS, 0L );                                /*@V159979*/
    ENABLE                                                          /*@V159979*/
}


void PciSetRegMech2( USHORT regmask, UCHAR index, ULONG val, USHORT size )
{
   register USHORT port;

   DISABLE                                                          /*@V159979*/
   outp( PCI_CONFIG_ADDRESS, 0x10 );                                /*@V153743*/
   IODelay();
   port = regmask|index;
   switch( size )
   {
      case 1 :
         outp(port,val);
         break;
      case 2:
         outwp(port,val);
         break;
      case 4:
         outpd(port,val);
         break;
      default:
         break;
   }
   IODelay();
   outp( PCI_CONFIG_ADDRESS, 0x00 );                                /*@V153743*/
   ENABLE                                                           /*@V159979*/
}


BOOL PciSetReg( NPPCI_INFO npPCIInfo, UCHAR ConfigReg, ULONG val, USHORT size )
{
   USHORT rc;
   USHORT RegMask;
   UCHAR olddata;
   UCHAR newdata;
   ULONG PciChipVer;
   PCI_DATA PCIDataPkt;                                             /*@V153732*/
   UCHAR HWMech;                                                    /*@V153732*/

  if( rc = GetBiosInfo( &PCIDataPkt ) )                             /*@V153732*/
  {                                                                 /*@V153743*/
      return( TRUE );      /* Failed */                             /*@V153743*/
  }                                                                 /*@V153743*/
  else                                                              /*@V153743*/
  {                                                                 /*@V153743*/
     HWMech = PCIDataPkt.Data_Bios_Info.HWMech;                     /*@V153732*/

     if ((HWMech & 0x03) == 1) {
     /*
      * Use mechnism 1
      */
        RegMask  = ((USHORT)npPCIInfo->DevFunc) << 8;
        PciSetRegMech1(RegMask,ConfigReg,val,size);
     }
     else if ((HWMech & 0x03) ==  2) {
     /*
     * Use mechanism 2
     */
        RegMask = 0xc000 | ((USHORT)npPCIInfo->DevFunc) << 5;
        PciSetRegMech2( RegMask, ConfigReg, val, size );
     }
     else {
      /* Return failed because info is not valid , "TRUE" means "FAILED"*/
      return( TRUE );                                               /*@V153743*/
     }
     return( FALSE );  /* FALSE means OK */
  }                                                                 /*@V153743*/
}

#ifdef DEBUG
UCHAR PciGetReg( NPPCI_INFO npPCIInfo, UCHAR ConfigReg )
{
   USHORT rc;
   USHORT RegMask;
   ULONG PciChipVer;
   UCHAR data;
   PCI_DATA PCIDataPkt;                                             /*@V153732*/
   UCHAR HWMech;                                                    /*@V153732*/

  if( rc = GetBiosInfo( &PCIDataPkt ) )                             /*@V153732*/
  {                                                                 /*@V153743*/
      return( TRUE );      /* Failed */                             /*@V153743*/
  }                                                                 /*@V153743*/
  else                                                              /*@V153743*/
  {                                                                 /*@V153743*/
     HWMech = PCIDataPkt.Data_Bios_Info.HWMech;                        /*@V153732*/

     if ((HWMech & 0x03) == 1) {
     /*
      * Use mechnism 1
      */

        RegMask  = ((USHORT)npPCIInfo->DevFunc) << 8;
        data = PciGetRegMech1( RegMask, ConfigReg );
     }
     else if ((HWMech & 0x03) ==  2) {
     /*
      * Use mechanism 2
      */
        RegMask = 0xc000 | ((USHORT)npPCIInfo->DevFunc) << 5;
        data = PciGetRegMech2( RegMask, ConfigReg );
     }
     else {
      /* Return failed because info is not valid */
        _asm int 3
     }
  }
  return(data);
}


UCHAR PciGetRegMech1( USHORT regmask, UCHAR index )
{
  UCHAR val;
  register USHORT port;

  DISABLE                                                           /*@V159979*/
  outpd( PCI_CONFIG_ADDRESS,                                        /*@V153743*/
     0x80000000 | (regmask|(index & 0xfc)));
  port = PCI_CONFIG_DATA + (index & 0x03);                          /*@V153743*/
  inp(port,val);
  outpd( PCI_CONFIG_ADDRESS, 0L );                                  /*@V159979*/
  ENABLE                                                            /*@V159979*/

  return val;
}


UCHAR PciGetRegMech2( USHORT regmask, UCHAR index )
{
  UCHAR val;
  register USHORT port;

  DISABLE                                                           /*@V159979*/
  outp( PCI_CONFIG_ADDRESS, 0x10 );                                 /*@V153743*/
  IODelay();
  port = regmask|index;
  inp(port,val);
  IODelay();
  outp( PCI_CONFIG_ADDRESS, 0x00 );                                 /*@V153743*/
  ENABLE                                                            /*@V159979*/

  return val;
}
#endif


UCHAR FindDevice( USHORT DeviceID, USHORT VendorID, USHORT Index )
{
   PCI_PARM_FIND_DEV  PCIParmPkt;
   PCI_DATA           PCIDataPkt;
   RP_GENIOCTL        IOCtlRP;     /* From reqpkt.h */
   PRPH               pRPH = (PRPH)&IOCtlRP;
   USHORT                         BusNum;
   USHORT             DevFunc;

   /* Setup Parm Packet */
   PCIParmPkt.PCISubFunc = PCI_FIND_DEVICE;
   PCIParmPkt.Ident.Device   = DeviceID;
   PCIParmPkt.Ident.Vendor   = VendorID;
   PCIParmPkt.Ident.Index      = Index;

   /* Setup IOCTL Request Packet */
   IOCtlRP.Category = 0x00;
   IOCtlRP.Function = PCI_FUNC;
   IOCtlRP.ParmPacket = (PUCHAR)&PCIParmPkt;
   IOCtlRP.DataPacket = (PUCHAR)&PCIDataPkt;
   IOCtlRP.rph.Len = sizeof(IOCtlRP);
   IOCtlRP.rph.Unit = 0;
   IOCtlRP.rph.Cmd  = 0x10;      /* Generic IOCtl */
   IOCtlRP.rph.Status = 0;

   CallOEMHlp(pRPH);

   if (IOCtlRP.rph.Status & STERR)
      return( 1 );

   if (PCIDataPkt.bReturn != PCI_SUCCESSFUL)
      return( 1 );

   BusNum  = PCIDataPkt.Data_Find_Dev.BusNum;
   DevFunc = PCIDataPkt.Data_Find_Dev.DevFunc;

   return( 0 );
}


UCHAR GetBiosInfo( PPCI_DATA pPCIDataPkt )
{
   PCI_PARM_FIND_DEV  PCIParmPkt;
   RP_GENIOCTL        IOCtlRP;     /* From reqpkt.h */
   PRPH               pRPH = (PRPH)&IOCtlRP;

   /* Setup Global OEMHlp Variables */
   if (DevHelp_AttachDD( OEMDriverName, (NPBYTE)&DDTable) )         /*@V153732*/
      return(1);    /* Couldn't find OEMHLP's IDC */

   if ((DDTable.ProtIDCEntry == NULL) || (DDTable.ProtIDC_DS == 0))
      return(1);    /*     Entry Point or Data Segment */

   pOEMHLPEntry = DDTable.ProtIDCEntry;
   OemhlpDS = DDTable.ProtIDC_DS;

   /* Setup Parm Packet */
   PCIParmPkt.PCISubFunc = PCI_GET_BIOS_INFO;

   /* Setup IOCTL Request Packet */
   IOCtlRP.Category = 0x00;
   IOCtlRP.Function = PCI_FUNC;
   IOCtlRP.ParmPacket = (PUCHAR)&PCIParmPkt;
   IOCtlRP.DataPacket = (PUCHAR)pPCIDataPkt;
   IOCtlRP.rph.Len = sizeof(IOCtlRP);
   IOCtlRP.rph.Unit = 0;
   IOCtlRP.rph.Cmd  = 0x10;      /* Generic IOCtl */
   IOCtlRP.rph.Status = 0;

   CallOEMHlp(pRPH);

   if (IOCtlRP.rph.Status & STERR)
      return( 1 );

   if (pPCIDataPkt->bReturn != PCI_SUCCESSFUL)
      return( 1 );

   return( 0 );
}


void outpd( USHORT port, ULONG val )
{
  /* push eax   */
  _asm _emit 0x66;
  _asm push ax;

  _asm mov dx,port;

  /* mov eax,val */
  _asm _emit 0x66;
  _asm mov ax,val;

  /* out dx,eax */
  _asm _emit 0x66;
  _asm out dx,ax;

  /* pop eax   */
  _asm _emit 0x66;
  _asm pop ax;
}
                                                                                                /* ^^^, @V151345 */
