/*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.      */
/*                                                                           */
/*****************************************************************************/
/**************************************************************************
 *
 * SOURCE FILE NAME = VDSKINIT.C
 *
 * DESCRIPTIVE NAME = Virtual Disk Device Driver (VDSK)
 *
 *
 *
 * VERSION = V2.0
 *
 * DATE
 *
 * DESCRIPTION        VDSK Interrupt management
 *
 *          This module contains VDSK's interrupt management
 *          support:
 *
 *          1. Notification from the Disk PDD of physical
 *             disk interrupt events.
 *
 *          2. Simulation of virtual interrupts to the VDM.
 *
 *          4. Simulation of ROM BIOS Int 13h processing
 *
 * FUNCTIONS     VDSKPDDProc                VDSKInt13Proc
 *               VDSKInt13Return            VDSKSetUPIoctlReqRWV
 *               VDSKSetUPIoctlReqFormat    rcMapError
 *               VDSKWaitRequest            VDSKRequestDone
 *               VDSKInt13Done              VDSKIn13QueryHDParms
 *               VDSKIn13QueryFDParms       VDSKIn13QueryHDDASDType
 *               VDSKIn13QueryFDDASDType    VDSKInt13QueryChange
 *               VDSKInt13SetDiskType       VDSKInt13SetMediaType
 *               VDSKSetDiskChanged         VDSKCheckVirtDisk
 *
 *
 *
 * ENTRY POINTS:
 *
 * DEPENDENCIES:
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/

#define  INCL_MI
#include <mvdm.h>
#include "vdskp.h"
#define  INCL_DOSERRORS                                 /* NoPdd            */
#include <bseerr.h>                                     /* NoPdd            */
#include <vfdvdd.h>                                     

#ifdef   VDDSTRICT
MODNAME = __FILE__;
#endif

/*
**    External References
*/
/*      Global Data*/

extern BOOL *pbBusyFlagPtr;                             


extern HVDM hvdmDiskReq;                                /* handle of VDM
                                                           doing disk
                                                           request          */
extern HVDM hvdmDiskChanged;                            /* handle of VDM
                                                           detect disk
                                                           changed          */
extern MEDIATYPE amtMediaTable[];                       /* media type table */
extern HLOCK hLock;                                     /* lock handle for
                                                           user buffer      */
extern HVDHSEM semDiskReq;
extern DISKREQ PS2_DiskTable;                           /* Int 13h return
                                                           fixed drv
                                                           parameters,      */
                                                         
                                                         /* @715561         */

extern HVDD hVDDVFLPY;                                  /* VDDtoVdd comm to
*/

/*      Instance Data*/

extern HVDM hvdmThisVDM;                                /* handle of VDM    */
extern VIRTFLOPPY virtFloppy[];                         /* virtual floppy
                                                           attributes/states*/
extern HHOOK hhookWaitRequest;
extern HHOOK hhookDiskRequest;
extern HHOOK hhookInt13Return;                          /* hook handle for
                                                           VDSKDiskRequest  */
extern INT nFunc;                                       /* original
                                                           function #       */
extern INT iDriveOriginal;                              /* original drive #
                                                           for INT 13h
                                                           request          */
extern MAPDISK amdInfo[MAX_DRIVES];
extern DISKREQ DiskReqPkt;                              /* disk request
                                                           packet           */
extern REQSTATUS ReqStatusPkt;                          /* disk request
                                                           status packet    */
extern BOOL fInt13Floppy;                               /* flag to force
                                                           FLOPPY Int 13 in
                                                           VDSK             */
extern PSZ pszVMBoot;                                   /* VM Boot property
                                                           value            */
extern HFILE DeviceHandle;
extern HFILE DriveHandle;
extern USHORT Number_Physical_Disks;
extern ULONG ActionTaken;
extern BYTE FileName[3];
extern GETDEVICEPARMSPARM GetDeviceParmsParmPacket;
extern GETDEVICEPARMSDATA GetDeviceParmsDataPacket;
extern GETPHYSDEVICEPARMSDATA GetPhysDeviceParmsDataPacket;
extern RWVPARM RWVParmPacket;
extern FORMATPARM FormatParmPacket;
extern FORMATDATA FormatDataPacket;
extern ULONG LengthParm,LengthData;
extern ERRORIOCTLTOINT13 ErrorIOCTLtoINT13Table[];
extern PSYS_CONFIG_TABLE pSysConfigTable;               /* Miguel           */
extern PVOID LinearESBX;                                
extern HLOCK hLockMem;                                  
#pragma  BEGIN_GLOBAL_CODE

/****************************************************************************
 *
 * FUNCTION NAME = VDSKPDDProc
 *
 * DESCRIPTION   =
 *
 *  LP  VDSKPDDProc - PDD request router
 *
 *      This subroutine is registered by the VDD during VDD Initialization
 *      via VDHOpenPDD and is called by the PDD to provide notification
 *      of various events.  See all the VDSKCMD_* equates for a brief list
 *      of those events.
 *
 *      ENTRY
 *          ulFunc - request function
 *          f16p1  - parameter 1
 *          f16p2  - parameter 2
 *
 *          See vdskpdd.h for detail parameters of request functions.
 *
 *      EXIT
 *          SUCCESS
 *              return TRUE
 *          FAILURE
 *              return FALSE - invalid request function
 *
 *      CONTEXT
 *          Interrupt
 *
 *      PSEUDOCODE
 *          assert for VDSKCMD_REQDONE;
 *          call VDHWakeVIRRs to wake up the VDM doing disk request;
 *          return TRUE;
 *
 * INPUT         = (ULONG ulFunc,F16PVOID f16p1,F16PVOID f16p2)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

SBOOL VDDENTRY VDSKPDDProc(ULONG ulFunc,F16PVOID f16p1,F16PVOID f16p2)
{
  register HVDM hvdm;
  AssertTRUE(ulFunc == VDSKCMD_REQDONE);
  hvdm = hvdmDiskReq;
  hvdmDiskReq = HVDM_NOVDM;
  VDHPostEventSem(semDiskReq);

  /*    VDHWakeVIRRs(hvdm);*/

  return  TRUE;
}                                                       /* VDSKPDDProc      */
#pragma  END_GLOBAL_CODE
#pragma  BEGIN_SWAP_CODE

/****************************************************************************
 *
 * FUNCTION NAME = VDSKInt13Proc
 *
 * DESCRIPTION   =
 *
 *  LP  VDSKInt13Proc - Default VDM disk I/O processing
 *
 *      This subroutine is registered with the 8086 Manager at VDM
 *      create-time and is called by the 8086 Manager whenever a
 *      VDM attempts to enter the ROM for disk I/O processing.
 *
 *      ENTRY
 *          pcrf -> VDM client register frame
 *
 *      EXIT
 *          None
 *
 *      CONTEXT
 *          VDM Task-time
 *
 *      PSEUDOCODE
 *          set fWaitRequest to FALSE;
 *          call VDHSetFlags to enable VDM interrupt;
 *          switch(request function) {
 *              case INT13_DISKRESET:
 *                  clear both hard disk and floppy status;
 *                  break;
 *              case INT13_DISKSTATUS:
 *                  if hard disk request {
 *                      set VDM AL to hard disk status;
 *                      clear hard disk status;
 *                  }
 *                  break;
 *              case INT13_READSECTORS:
 *                  call VDSKDiskRequest to read the sectors;
 *                  set fWaitRequest to TRUE;
 *                  break;
 *              case INT13_WRITESECTORS:
 *                  if hard disk request {
 *                      set hard disk status to     command;
 *                      clear VDM AL;
 *                  } else {
 *                      call VDSKDiskRequest to write the sectors;
 *                      set fWaitRequest to TRUE;
 *                  }
 *                  break;
 *              case INT13_VERIFYSECTORS:
 *                  call VDSKDiskRequest to verify the sectors;
 *                  set fWaitRequest to TRUE;
 *                  break;
 *              case INT13_FORMATTRACK:
 *                  if hard disk request {
 *                      set hard disk status to     command;
 *                      clear VDM AL;
 *                  } else {
 *                      call VDSKDiskRequest to format track;
 *                      set fWaitRequest to TRUE;
 *                  }
 *                  break;
 *              case INT13_QUERYDRVPARMS:
 *                  if hard disk request
 *                      call VDSKInt13QueryHDParms;
 *                  else
 *                      call VDSKInt13QueryFDParms;
 *                  break;
 *              case INT13_QUERYDASDTYPE:
 *                  if hard disk request
 *                      call VDSKInt13QueryHDDASDType;
 *                  else
 *                      call VDSKInt13QueryFDDASDType;
 *                  break;
 *              case INT13_QUERYCHANGE:
 *                  if hard disk request
 *                      set hard disk status to     command;
 *                      clear VDM AL;
 *                  } else
 *                      call VDSKInt13QueryChange;
 *                  break;
 *              case INT13_SETDISKTYPE:
 *                  if hard disk request
 *                      set hard disk status to     command;
 *                      clear VDM AL;
 *                  } else
 *                      call VDSKInt13SetDiskType;
 *                  break;
 *              case INT13_SETMEDIATYPE:
 *                  if hard disk request
 *                      set hard disk status to     command;
 *                      clear VDM AL;
 *                  } else
 *                      call VDSKInt13SetMediaType;
 *                  break;
 *              default:
 *                  if hard disk request
 *                      set hard disk status to     command;
 *                      clear VDM AL;
 *                  } else
 *                      set floppy status to     command;
 *          }
 *          if (!fWaitRequest)
 *              call VDSKInt13Done to complete the request;
 *          return FALSE;         to inhibit chaining
 *
 * INPUT         = (register PCRF pcrf)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

BOOL HOOKENTRY VDSKInt13Proc(register PCRF pcrf)
{
  BOOL fHardDisk,                                       /* request is for a
                                                           hard disk        */
     fWaitRequest = FALSE,                              /* assume not a
                                                           wait request     */
     rc = 0;
  PULONG pulReqFunc;

  /*    INT     i;*/

  nFunc = AH(pcrf);
  iDriveOriginal = DL(pcrf);                            /* save original
                                                           drive in case    */

  /*CheckVirtDisk needs to change it*/

  *pbBusyFlagPtr = TRUE;                                

  if (!VDSKCheckVirtDisk(nFunc,
                         pcrf))
  {
    fHardDisk = DL(pcrf)&DRIVE_HDMASK;

    /*      if ((fHardDisk==0)&&(*pszVMBoot==0)) {*/
    
    /* Suspend support ?          if ( (fHardDisk==0) & (flPDDSuspend) ) {*/

    if (fHardDisk == 0)
    {

      DL(pcrf) &= ~0x40;                  //bit 6 of DL off     //J-YF001
      if ((AH(pcrf) == INT13_READSECTORS) || (AH(pcrf) == INT13_WRITESECTORS)
         ||                                             
         (AH(pcrf) == INT13_FORMATTRACK))
      {                                                 

        if (AL(pcrf))
        {                                               /* If any tracks or
                                                           sectors to do    */
                                                         


          if (AH(pcrf) == INT13_FORMATTRACK)
          {                                             
            LinearESBX = PFROMVADDR(ES(pcrf),
                                    BX(pcrf));          
            REFHVDM(CURRENT_VDM,
                    HLOCK,
                    hLockMem) =                         
               VDHLockMem(LinearESBX,
                          4*AL(pcrf),
                          VDHLM_CONTIGUOUS,
                          (struct pagelist_s *)-1,
                          (ULONG *)-1);                 
          }

          else
          {                                             
            LinearESBX = PFROMVADDR(ES(pcrf),
                                    BX(pcrf));          
            REFHVDM(CURRENT_VDM,
                    HLOCK,
                    hLockMem) =                         
               VDHLockMem(LinearESBX,
                          512*AL(pcrf),
                          VDHLM_CONTIGUOUS+VDHLM_16M+VDHLM_NO_ADDR,
                          NULL,
                          NULL);                        
          }                                             /* endif            */
                                                         

        }
      }                                                 /* endif            */
                                                         

      VDHRequestVDD(hVDDVFLPY,
                    CURRENT_VDM,
                    START_BIOS_REQS,
                    NULL,
                    NULL);                              
      VDHArmReturnHook(hhookInt13Return,
                       VDHARH_NORMAL_IRET);
      return  TRUE;
    }
    VDHSetFlags(FL(pcrf)|F_INTERRUPT);                  /* enable VDM
                                                           interrupt        */

    if ((nFunc > INT13_DISKSTATUS) && (nFunc != INT13_QUERYDRVPARMS) &&
       !(fHardDisk && (nFunc == INT13_QUERYDASDTYPE)) && (fHardDisk && ((DL
       (pcrf)&~DRIVE_HDMASK) >= VDMBase.rb_nDTotal)) || ((!fHardDisk) && ((DL
       (pcrf) >= MAX_FD) || (virtFloppy[DL(pcrf)].vf_bDriveType ==
       DRVTYPE_NONE))))

      nFunc = 0xff;                                     /* invalid drive
                                                           number, change
                                                           it to an invalid
                                                           func.            */

    switch (nFunc *2)
    {
      case  INT13_DISKRESET *2 :
        VDMBase.rb_bFStatus = VDMBase.rb_bDStatus = INT13STATUS_SUCCESS;
        break;
      case  INT13_DISKSTATUS *2 :

        if (fHardDisk)
        {
          AL(pcrf) = VDMBase.rb_bDStatus;
          VDMBase.rb_bDStatus = INT13STATUS_SUCCESS;
        }
        break;
      case  INT13_READSECTORS *2 :

/* DOS 4.0x will issue an INT13 READ sector 0, but Int13 sector # are 1-based*/

        if ((CL(pcrf)&0x3f))
        {                                               

          if (rc = VDSKSetUpIoctlReqRWV(FileName,
                                        &RWVParmPacket,
                                        NULL,
                                        pcrf))
          {

            if (!fHardDisk)
            {

              if (!(rc = VDHOpen(FileName,
                                 &DeviceHandle,
                                 &ActionTaken,
                                 0L,
                                 0L,
                                 VDHOPEN_ACTION_OPEN_IF_EXISTS,
                                 VDHOPEN_FLAGS_FAIL_ON_ERROR+
                                    VDHOPEN_FLAGS_DASD+
                                    VDHOPEN_SHARE_DENYNONE+
                                    VDHOPEN_ACCESS_READWRITE,
                                 NULL)))
                DeviceHandle = 0xFFFF;
            }

            else
            {
              FileName[0] = (BYTE)((DL(pcrf)&0x7f)+1+'0');
              rc = VDHPhysicalDisk(PHYSICAL_HANDLE,
                                   (ULONG *)&DriveHandle,
                                   sizeof(DriveHandle),
                                   FileName,
                                   sizeof(FileName));
            }

            if (rc)
            {
              LengthParm = sizeof(RWVParmPacket);
              LengthData = AL(pcrf)*SECTOR_SIZE;
              rc = VDHDevIOCtl((DL(pcrf) >= 0x80?DriveHandle:DeviceHandle),
                               (DL(pcrf)>= 0x80?IOCTL_PHYSICALDISK:IOCTL_DISK),
                               DSK_READTRACK,
                               &RWVParmPacket,
                               LengthParm,
                               &LengthParm,
                               PFROMVADDR(ES(pcrf),
                                          BX(pcrf)),
                               LengthData,
                               &LengthData);

              if (!fHardDisk)
                VDHClose(DeviceHandle);

              else
                VDHPhysicalDisk(RELEASE_PHYSICAL_HANDLE,
                                NULL,
                                0,
                                (ULONG *)&DriveHandle,
                                sizeof(DriveHandle));
            }
          }
          rcMapError(pcrf,
                     rc);
        }

        else
        {                                               
          AH(pcrf) = 0x1;                               
          VDMBase.rb_bDStatus = 0;                      
        }                                               /* endif            */
                                                        
                                                        
                                                        /* endif *       */


        break;
      case  INT13_WRITESECTORS *2 :

        if (fHardDisk)
        {
          VDMBase.rb_bDStatus = INT13STATUS_BADCMD;
          AL(pcrf) = 0;
        }

        else
        {


          if (rc = VDSKSetUpIoctlReqRWV(FileName,
                                        &RWVParmPacket,
                                        NULL,
                                        pcrf))
          {

            if (rc = VDHOpen(FileName,
                             &DeviceHandle,
                             &ActionTaken,
                             0L,
                             0L,
                             VDHOPEN_ACTION_OPEN_IF_EXISTS,
                             VDHOPEN_FLAGS_FAIL_ON_ERROR
                                +VDHOPEN_FLAGS_DASD+VDHOPEN_SHARE_DENYNONE
                                +VDHOPEN_ACCESS_READWRITE,
                             NULL))
            {
              LengthParm = sizeof(RWVParmPacket);
              LengthData = AL(pcrf)*SECTOR_SIZE;
              rc = VDHDevIOCtl(DeviceHandle,
                               IOCTL_DISK,
                               DSK_WRITETRACK,
                               &RWVParmPacket,
                               LengthParm,
                               &LengthParm,
                               PFROMVADDR(ES(pcrf),
                                          BX(pcrf)),
                               LengthData,
                               &LengthData);
              VDHClose(DeviceHandle);
            }
            ;
          }
          rcMapError(pcrf,
                     rc);


        }
        break;
      case  INT13_DISKSEEK *2 :                         
        CL(pcrf) |= 0x1;                                /* verify sector 1   */
        AL(pcrf) = 1;                                   /* number of
                                                           sectors
*/
      case  INT13_VERIFYSECTORS *2 :


        if (rc = VDSKSetUpIoctlReqRWV(FileName,
                                      &RWVParmPacket,
                                      NULL,
                                      pcrf))
        {

          if (!fHardDisk)
          {

            if (!(rc = VDHOpen(FileName,
                               &DeviceHandle,
                               &ActionTaken,
                               0L,
                               0L,
                               VDHOPEN_ACTION_OPEN_IF_EXISTS,
                               VDHOPEN_FLAGS_FAIL_ON_ERROR
                                  +VDHOPEN_FLAGS_DASD+VDHOPEN_SHARE_DENYNONE
                                  +VDHOPEN_ACCESS_READWRITE,
                               NULL)))
              DeviceHandle = 0xFFFF;
          }

          else
          {
            FileName[0] = (BYTE)((DL(pcrf)&0x7f)+1+'0');
            rc = VDHPhysicalDisk(PHYSICAL_HANDLE,
                                 (ULONG *)&DriveHandle,
                                 sizeof(DriveHandle),
                                 FileName,
                                 sizeof(FileName));
          }

          if (rc)
          {
            LengthParm = sizeof(RWVParmPacket);
            LengthData = 0;
            rc = VDHDevIOCtl((DL(pcrf) >= 0x80?DriveHandle:DeviceHandle),
                             (DL(pcrf) >= 0x80?IOCTL_PHYSICALDISK:IOCTL_DISK),
                             DSK_VERIFYTRACK,
                             &RWVParmPacket,
                             LengthParm,
                             &LengthParm,
                             NULL,
                             LengthData,
                             &LengthData);


            if (!fHardDisk)
              VDHClose(DeviceHandle);

            else
              VDHPhysicalDisk(RELEASE_PHYSICAL_HANDLE,
                              NULL,
                              0,
                              (ULONG *)&DriveHandle,
                              sizeof(DriveHandle));
          }
        }
        rcMapError(pcrf,
                   rc);


        break;


      case  INT13_FORMATTRACK *2 :

        if (fHardDisk)
        {
          VDMBase.rb_bDStatus = INT13STATUS_BADCMD;
          AL(pcrf) = 0;
        }

        else
        {


          if (rc = VDSKSetUpIoctlReqFormat(FileName,
                                           &FormatParmPacket,
                                           &FormatDataPacket,
                                           pcrf))
          {

            if (rc = VDHOpen(FileName,
                             &DeviceHandle,
                             &ActionTaken,
                             0L,
                             0L,
                             VDHOPEN_ACTION_OPEN_IF_EXISTS,
                             VDHOPEN_FLAGS_FAIL_ON_ERROR
                                +VDHOPEN_FLAGS_DASD+VDHOPEN_SHARE_DENYNONE+
                                VDHOPEN_ACCESS_READWRITE,
                             NULL))
            {
              LengthParm = sizeof(FormatParmPacket);
              LengthData = sizeof(FormatDataPacket);
              rc = VDHDevIOCtl(DeviceHandle,
                               IOCTL_DISK,
                               DSK_FORMATVERIFY,
                               &FormatParmPacket,
                               LengthParm,
                               &LengthParm,
                               &FormatDataPacket,
                               LengthData,
                               &LengthData);
              VDHClose(DeviceHandle);
            }
          }
          rcMapError(pcrf,
                     rc);


        }
        break;
      case  INT13_QUERYDRVPARMS *2 :

        if (fHardDisk)
          VDSKInt13QueryHDParms(pcrf);

        else
          VDSKInt13QueryFDParms(pcrf);
        break;
      case  INT13_QUERYDASDTYPE *2 :

        if (fHardDisk)
          VDSKInt13QueryHDDASDType(pcrf);

        else
          VDSKInt13QueryFDDASDType(pcrf);
        break;
      case  INT13_QUERYCHANGE *2 :

        if (fHardDisk)
        {
          VDMBase.rb_bDStatus = INT13STATUS_BADCMD;
          AL(pcrf) = 0;
        }

        else
          VDSKInt13QueryChange(pcrf);
        break;
      case  INT13_SETDISKTYPE *2 :

        if (fHardDisk)
        {
          VDMBase.rb_bDStatus = INT13STATUS_BADCMD;
          AL(pcrf) = 0;
        }

        else
          VDSKInt13SetDiskType(pcrf);
        break;
      case  INT13_SETMEDIATYPE *2 :

        if (fHardDisk)
        {
          VDMBase.rb_bDStatus = INT13STATUS_BADCMD;
          AL(pcrf) = 0;
        }

        else
          VDSKInt13SetMediaType(pcrf);
        break;
      default  :

        if (fHardDisk)
        {
          VDMBase.rb_bDStatus = INT13STATUS_BADCMD;
          AL(pcrf) = 0;
        }

        else
          VDMBase.rb_bFStatus = INT13STATUS_BADCMD;
    }                                                    /* end-switch       */
  }

  if (!fWaitRequest)
    VDSKInt13Done((ULONG)nFunc,
                  pcrf);
  VDSKInt13Return(NULL,
                  pcrf);
  return  FALSE;                                         /* inhibit VDD
                                                            chaining         */
}                                                        /* VDSKInt13Proc    */

/****************************************************************************
 *
 * FUNCTION NAME = VDSKInt13Return
 *
 * DESCRIPTION   =
 *
 *  LP  VDSKInt13Return - Default VDM disk I/O processing return hook
 *
 *      This subroutine is armed every time we need to regain control from
 *      the ROM after servicing an INT 13h.
 *
 *      ENTRY
 *          p - (ignored)
 *          pcrf -> VDM register frame
 *
 *      EXIT
 *          None
 *
 *      CONTEXT
 *          VDM Task-time
 *
 *      PSEUDOCODE
 *
 * INPUT         = (PVOID p,register PCRF pcrf)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID HOOKENTRY VDSKInt13Return(PVOID p,register PCRF pcrf)
{
  VDHRequestVDD(hVDDVFLPY,
                CURRENT_VDM,
                END_BIOS_REQS,
                NULL,
                NULL);                                   

  if (nFunc != INT13_QUERYDRVPARMS && nFunc != INT13_QUERYDASDTYPE)
    DL(pcrf) = iDriveOriginal;                           /* restore original
                                                            drive in case    */

  /*CheckVirtDisk needed to change it*/

  if (REFHVDM(CURRENT_VDM,
              HLOCK,
              hLockMem) && ((nFunc == INT13_READSECTORS) || (nFunc ==
                 INT13_WRITESECTORS) ||                 /**/
                 (nFunc == INT13_FORMATTRACK)))
  {                                                     
    VDHUnlockMem(REFHVDM(CURRENT_VDM,
                         HLOCK,
                         hLockMem));                    /**/
    REFHVDM(CURRENT_VDM,
            HLOCK,
            hLockMem) = NULL;                           /**/
  }                                                     
}                                                       /* VDSKInt13Return   */

/****************************************************************************
 *
 * FUNCTION NAME = VDSKSetUpIoctlReqRWV
 *
 * DESCRIPTION   =
 *
 *  LP  VDSKSetUpIoctlReqRWV - Disk IOCTL Request Setup
 *
 *      This subroutine is called when a VDM is doing an Int 13h Read/Write/Ver
 *      and there is NO PDD support for VDMs.
 *
 *      ENTRY
 *          FileName  -> File Name
 *          &ParmList -> ptr to IOCTL parm packet
 *          pcrf      -> VDM client register frame
 *
 *      EXIT
 *          Modified ParmList
 *
 *      CONTEXT
 *          VDM Task-time
 *
 *      PSEUDOCODE
 *          Set Up IOCTL Request packet
 *
 * INPUT         = (PCHAR FileName,RWVPARM *ParmList,RWVFDATA
 *                    *DataList,register PCRF pcrf)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

BOOL PRIVENTRY VDSKSetUpIoctlReqRWV(PCHAR FileName,RWVPARM *ParmList,RWVFDATA
                                     *DataList,register PCRF pcrf)
{
  int i;
  FileName[0] = (DL(pcrf)&(!DRIVE_HDMASK))+'A';         /* max # drives      */

  if (DL(pcrf) >= 0x80)
    FileName[0] += 2;                                   /* 2 floppies        */
  ParmList->Command = STANDARD_TRACK;                   /* == 1 NoPdd        */
  ParmList->Head = DH(pcrf);

  if (DL(pcrf) && DRIVE_HDMASK)                         /* If hardfile       */
    ParmList->Cyl = (WORD)(CH(pcrf)|((CL(pcrf)&0xc0) << 2));

  else                                                  /* If floppy         */
    ParmList->Cyl = (WORD)(CH(pcrf));
  ParmList->FirstSector = (WORD)((CL(pcrf)&0x3f)-1);
  ParmList->NumSec = (BYTE)(AL(pcrf));

  for (i = 0; i <= ((ParmList->FirstSector)+(ParmList->NumSec-1)); i++)
  {
    ParmList->TrackTable[i].Sector = i+1;
    ParmList->TrackTable[i].Size = SECTOR_SIZE;
  }                                                     /* endfor           */
  return  TRUE;
}

/****************************************************************************
 *
 * FUNCTION NAME = VDSKSetUpIoctlReqFormat
 *
 * DESCRIPTION   =
 *
 *  LP  VDSKSetUpIoctlReqFormat - Disk IOCTL Request Setup
 *
 *      This subroutine is called when a VDM is doing an Int 13h FORMAT
 *      and there is NO PDD support for VDMs.
 *
 *      ENTRY
 *          FileName  -> File Name
 *          &ParmList -> ptr to IOCTL parm packet
 *          pcrf      -> VDM client register frame
 *
 *      EXIT
 *          Modified ParmList
 *
 *      CONTEXT
 *          VDM Task-time
 *
 *      PSEUDOCODE
 *          Set Up IOCTL Request packet
 *
 * INPUT         = (PCHAR FileName,FORMATPARM *ParmList,
 *                    FORMATDATA *DataList,register PCRF pcrf
 *                  )
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

BOOL PRIVENTRY VDSKSetUpIoctlReqFormat(PCHAR FileName,FORMATPARM *ParmList,
                                        FORMATDATA *DataList,register PCRF
                                        pcrf)
{
  FileName[0] = (DL(pcrf)&(!DRIVE_HDMASK))+'A';         /* max # drives      */

  if (DL(pcrf) >= 0x80)
    FileName[0] += 2;                                   /* 2 floppies        */
  ParmList->Command = STANDARD_TRACK;                   /* == 1              */
  ParmList->Head = DH(pcrf);

  if (DL(pcrf) && DRIVE_HDMASK)                         /* If hardfile       */
    ParmList->Cyl = (WORD)(CH(pcrf)|((CL(pcrf)&0xc0) << 2));

  else                                                  /* If floppy         */
    ParmList->Cyl = (WORD)(CH(pcrf));
  ParmList->NumberTracks = (WORD)(0);
  DataList = (BYTE)(0);
  ParmList->NumSec = (BYTE)(AL(pcrf));
  return  TRUE;
}

/****************************************************************************
 *
 * FUNCTION NAME = rcMapError
 *
 * DESCRIPTION   =
 *
 *
 * INPUT         = (PCRF pcrf,BOOL rc)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID PRIVENTRY rcMapError(PCRF pcrf,BOOL rc)
{
  int i;

  if (!rc)
  {
    REFHVDM(CURRENT_VDM,
            INT,
            ErrorIOCTLtoINT13Table[MAX_INT13Error].IOCTL) = 
       VDHGetError();

    for (i = 0; i < MAX_INT13Error; i++)

      if (REFHVDM(CURRENT_VDM,
                  INT,
                  ErrorIOCTLtoINT13Table[i].IOCTL) ==   
                     REFHVDM(CURRENT_VDM,
                             INT,
                             ErrorIOCTLtoINT13Table[MAX_INT13Error].IOCTL))
                                                         

        break;
    AH(pcrf) = REFHVDM(CURRENT_VDM,
                       INT,
                       ErrorIOCTLtoINT13Table[i].INT13);
  }

  else

    if (nFunc != INT13_QUERYDASDTYPE)
      AH(pcrf) = INT13STATUS_SUCCESS;                   

  if (DL(pcrf)&DRIVE_HDMASK)
    VDMBase.rb_bDStatus = AH(pcrf);

  else
    VDMBase.rb_bFStatus = AH(pcrf);
}

/****************************************************************************
 *
 * FUNCTION NAME = VDSKWaitRequest
 *
 * DESCRIPTION   =
 *
 *  LP  VDSKWaitRequest - Wait Request Done
 *
 *      This subroutine is called when a VDM is doing a disk
 *      request to wait for its completion.
 *
 *      ENTRY
 *          p    - reference data (not used)
 *          pcrf - pointer to client register frame
 *          interrupt disabled
 *
 *      EXIT
 *          None
 *
 *      CONTEXT
 *          VDM Task-time
 *
 *      PSEUDOCODE
 *          if request is not done
 *              keep waiting;
 *          else
 *              call VDSKRequestDone;
 *
 * INPUT         = (PVOID p,PCRF pcrf)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID HOOKENTRY VDSKWaitRequest(PVOID p,PCRF pcrf)
{
  DISABLE();

  if (hvdmDiskReq != HVDM_NOVDM)
  {
    VDHWaitVIRRs(hhookWaitRequest);

    if (hvdmDiskReq == HVDM_NOVDM)
      VDSKRequestDone(pcrf);
  }

  else
    VDSKRequestDone(pcrf);
  ENABLE();
}                                                       /* VDSKWaitRequest  */

/****************************************************************************
 *
 * FUNCTION NAME = VDSKRequestDone
 *
 * DESCRIPTION   =
 *
 *  LP  VDSKRequestDone - Disk request done
 *
 *      This subroutine is called when a disk request is completed
 *
 *      ENTRY
 *          pcrf - pointer to client register frame
 *
 *      EXIT
 *          None
 *
 *      CONTEXT
 *          VDM Task-time
 *
 *      PSEUDOCODE
 *          unlock user buffer;
 *          deallocate the selectors to various packets;
 *          store the request status into the appropriate place;
 *          if the request was format
 *              store the sectors done into user AL;
 *          clear hvdmDiskReq in case the callout never happened;
 *          call VDSKInt13Done;
 *
 * INPUT         = (register PCRF pcrf)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID PRIVENTRY VDSKRequestDone(register PCRF pcrf)
{

  if (REFHVDM(CURRENT_VDM,
              HLOCK,
              hLockMem))                                 
  {
    VDHUnlockMem(REFHVDM(CURRENT_VDM,
                         HLOCK,
                         hLockMem));                     
    REFHVDM(CURRENT_VDM,
            HLOCK,
            hLockMem) = 0;                               
  }

  if (WORDOF(DiskReqPkt.dr_f16pBuffer,
             1))
    VDHDestroySel((SEL)WORDOF(DiskReqPkt.dr_f16pBuffer,
                              1));

  if (WORDOF(DiskReqPkt.dr_f16pDiskParm,
             1))
    VDHDestroySel((SEL)WORDOF(DiskReqPkt.dr_f16pDiskParm,
                              1));

  if (DL(pcrf)&DRIVE_HDMASK)
    VDMBase.rb_bDStatus = ReqStatusPkt.rs_bReqStatus;

  else
    VDMBase.rb_bFStatus = ReqStatusPkt.rs_bReqStatus;

  if (AH(pcrf) != INT13_FORMATTRACK)
    AL(pcrf) = ReqStatusPkt.rs_nSectorsDone;
  hvdmDiskReq = HVDM_NOVDM;
  VDSKInt13Done((ULONG)AH(pcrf),
                pcrf);
}                                                        /* VDSKRequestDone  */

/****************************************************************************
 *
 * FUNCTION NAME = VDSKInt13Done
 *
 * DESCRIPTION   =
 *
 *  LP  VDSKInt13Done - Int 13h Request Done
 *
 *      This subroutine is called when a VDM Int 13h request is done.
 *
 *      ENTRY
 *          pcrf - pointer to client register frame
 *
 *      EXIT
 *          None
 *
 *      CONTEXT
 *          VDM Task-time
 *
 *      PSEUDOCODE
 *          if request function is INT13_QUERYDASDTYPE
 *              clear VDM carry flag;
 *          else {
 *              if hard disk request
 *                  use hard disk status to set AH;
 *              else
 *                  use floppy status to set AH;
 *              if status is not successful
 *                  set VDM carry;
 *              else
 *                  clear VDM carry;
 *          }
 *          call VDHPopInt to skip ROM processing;
 *
 * INPUT         = (INT nFunc,register PCRF pcrf)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID PRIVENTRY VDSKInt13Done(INT nFunc,register PCRF pcrf)
{
  VDSKInt13Return(NULL,
                  pcrf);

  if (!fInt13Floppy)
    VDHPopInt();                                        /* skip ROM
                                                           processing        */

  if (nFunc == INT13_QUERYDASDTYPE)

    if (AH(pcrf) == 1)                                  
      FL(pcrf) |= F_CARRY;                              /* set VDM carry
                                                           flag PTR
*/

    else                                                
      FL(pcrf) &= ~F_CARRY;                             /* clear VDM carry
                                                           flag PTR
*/

  else                                                  

    if (nFunc == INT13_QUERYDRVPARMS)                   

      if (AH(pcrf))                                     /* operation failed
*/
        FL(pcrf) |= F_CARRY;                            /* set VDM carry
                                                           flag PTR
*/

      else                                              /* operation
                                                           successful PTR
*/
        FL(pcrf) &= ~F_CARRY;                           /* clear VDM carry
                                                           flag              */

    else
    {

      if (DL(pcrf)&DRIVE_HDMASK)
        AH(pcrf) = VDMBase.rb_bDStatus;

      else
        AH(pcrf) = VDMBase.rb_bFStatus;

      if (AH(pcrf))                                     /* operation failed  */
      {
        FL(pcrf) |= F_CARRY;                            /* set VDM carry
                                                           flag              */

        

      }

      else                                              /* operation
                                                           successful        */
        FL(pcrf) &= ~F_CARRY;                           /* clear VDM carry
                                                           flag              */
    }
}                                                       /* VDSKInt13Done     */

/****************************************************************************
 *
 * FUNCTION NAME = VDSKInt13QueryHDParms
 *
 * DESCRIPTION   =
 *
 *  LP  VDSKInt13QueryHDParms - Int 13h Query Hard Disk Parameters
 *
 *      This subroutine is called when a VDM is doing an Int 13h
 *      with a query disk parameters subfunction on a hard disk.
 *
 *      ENTRY
 *          pcrf -> VDM client register frame
 *              DL = drive number
 *
 *      EXIT
 *          SUCCESS
 *              VDM AL = 0
 *              VDM CH = last cylinder number
 *              VDM CL = last sector number
 *                       (bit 7,6 are the most significant bits of last cyl. #)
 *              VDM DH = last head number
 *              VDM DL = number of drives
 *              DStatus = INT13STATUS_SUCCESS
 *          FAILURE
 *              VDM AL = 0
 *              VDM CX = 0
 *              VDM DX = 0
 *              DStatus = INT13STATUS_INITFAIL
 *
 *      CONTEXT
 *          VDM Task-time
 *
 *      PSEUDOCODE
 *          clear VDM AL;
 *          if drive number too large {
 *              clear VDM CX and DX;
 *              set status to failure;
 *          } else {
 *             else
 *              if drive number 1
 *                  use hard disk parameter table 2;
 *              else
 *                  use hard disk parameter table 1;
 *              fill VDM CH, CL, DH, DL with appropriate info.;
 *              set status to success;
 *          }
 *
 * INPUT         = (register PCRF pcrf)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID PRIVENTRY VDSKInt13QueryHDParms(register PCRF pcrf)
{
  PHDPARMTABLE pDiskParm;
  WORD wMaxCyl;
  BOOL rc = 0;
  AL(pcrf) = 0;

  if ((DL(pcrf)&~DRIVE_HDMASK) > VDMBase.rb_nDTotal)    
  {
    CX(pcrf) = DX(pcrf) = 0;
    VDMBase.rb_bDStatus = INT13STATUS_INITFAIL;
    AH(pcrf) = 0x7;                                     
  }

  else
  {                                                     

           /*
@V69035    ** In Mod70/80's w/. BIOS later than 9/15/88 INT's 41 & 46    **
@V69035    ** can not be used to access the hard disk parameters tables. **
@V69035    ** Consequently, we cannot use BIOSINT_HDISK*PARMS            **
@V69035
@V69035 Changed so all requests for disk geometry go through the DASD manager*/

    pSysConfigTable = (PSYS_CONFIG_TABLE)VDHQuerySysValue(CURRENT_VDM,
                                                          VDHGSV_MACHINEINFO);
                                                         


/*  @V69035    if ((VDHQuerySysValue(CURRENT_VDM,                            */
/*  @V69035                   VDHGSV_MACHINETYPE) == MACHINE_TYPE_PS2) ||    */
                                                        /* PTR               */
                                                         

/*  @V69035                             (pSysConfigTable->Model == 0xF8))    */
/*  @V69035    {   */                                 

/*            if ((*fpfnPDSKVDDProc)(PDSKCMD_QUERYDRVPARMS, (F16PVOID)DL(pcrf),*/
                                                  /*high two bits of cylinder*/
/*                          (BYTE) (PS2_DiskTable.dr_bSector & 0x3f | wMaxCyl);*/

      FileName[0] = (BYTE)((DL(pcrf)&0x7f)+1+'0');

      if (rc = VDHPhysicalDisk(PHYSICAL_HANDLE,
                               (ULONG *)&DriveHandle,
                               sizeof(DriveHandle),
                               FileName,
                               sizeof(FileName)))
      {
        GetDeviceParmsParmPacket.Command = RECOMMENDED_BPB;
        LengthParm = sizeof(GetDeviceParmsParmPacket);
        LengthData = sizeof(GetPhysDeviceParmsDataPacket);
        rc = VDHDevIOCtl(DriveHandle,
                         IOCTL_PHYSICALDISK,
                         DSK_GETDEVICEPARAMS,
                         &GetDeviceParmsParmPacket,
                         LengthParm,
                         &LengthParm,
                         &GetPhysDeviceParmsDataPacket,
                         LengthData,
                         &LengthData);

/*      DL(pcrf) = number of consecutive drives attached                     */

/*      DH(pcrf) = (GetPhysDeviceParmsDataPacket.NumHeads-1)&0x3F; NoPdd     */
        if ((GetPhysDeviceParmsDataPacket.NumHeads-1) > 0xFE)    /* 148164      */
           DH(pcrf) = 0xFE;                                      /* 148164      */
        else                                                     /* 148164      */
           DH(pcrf) = (GetPhysDeviceParmsDataPacket.NumHeads-1); /* 148164      */
        CH(pcrf) = (BYTE)((GetPhysDeviceParmsDataPacket.NumCyl&0xFF)-1);
                                                          
        CL(pcrf) = (BYTE)((GetPhysDeviceParmsDataPacket.SecperTrack&0x3F)|
                         ((GetPhysDeviceParmsDataPacket.NumCyl&0x0300) >> 2));
        VDHPhysicalDisk(RELEASE_PHYSICAL_HANDLE,
                        NULL,
                        0,
                        (ULONG *)&DriveHandle,
                        sizeof(DriveHandle));
        VDHPhysicalDisk(NUMBER_PHYSICAL_DISKS,
                        &Number_Physical_Disks,
                        sizeof(Number_Physical_Disks),
                        NULL,
                        NULL);
        DL(pcrf) = Number_Physical_Disks;
      }
      rcMapError(pcrf,
                 rc);

/* @V69035  }                                                                */
/* @V69035 else                                                              */
/* @V69035 {                                                                 */
/* @V69035   if (DL(pcrf)&0x01)              */ /* drive 1                   */
/* @V69035     pDiskParm = PFROMVP(VDMBase.rb_avpIVT[BIOSINT_HDISK2PARMS]);  */
/* @V69035   else                            */ /* drive 0                   */
/* @V69035     pDiskParm = PFROMVP(VDMBase.rb_avpIVT[BIOSINT_HDISK1PARMS]);  */
/* @V69035   wMaxCyl = (WORD)(pDiskParm->hdp_wMaxCylinders-2);               */
                                                         /* adjust for 0-n   */
/* @V69035   CH(pcrf) = BYTEOF(wMaxCyl,                                      */
/* @V69035                     0);                                           */
/* @V69035   wMaxCyl = (WORD)((wMaxCyl&0x0300) >> 2);                        */
                                                 /* high two bits of cylinder*/
/* @V69035   CL(pcrf) = (BYTE)(pDiskParm->hdp_bSectorsPerTrack&0x3f|wMaxCyl);*/
/* @V69035    DH(pcrf) = (BYTE)(pDiskParm->hdp_bMaxHeads-1);                 */
                                                         /* last head number */
                                                         /* (0-n)            */
/*  @V69035    DL(pcrf) = VDMBase.rb_nDTotal;      */    /* drive count      */
/*  @V69035    VDMBase.rb_bDStatus = INT13STATUS_SUCCESS;                    */
/*  @V69035    AH(pcrf) = 0x0;                     */    
/*  @V69035  }                                     */    /* endif            */
  }
}                                                       /*
                                                         VDSKInt13QueryHDParms
                                                                             */

/****************************************************************************
 *
 * FUNCTION NAME = VDSKInt13QueryFDParms
 *
 * DESCRIPTION   =
 *
 *  LP  VDSKInt13QueryFDParms - Int 13h Query Floppy Disk Parameters
 *
 *      This subroutine is called when a VDM is doing an Int 13h
 *      with a query disk parameters subfunction on a floppy disk.
 *
 *      ENTRY
 *          pcrf -> VDM client register frame
 *              DL = drive number
 *
 *      EXIT
 *          SUCCESS
 *              VDM AL = 0
 *              VDM BL = drive type
 *              VDM CH = number of tracks
 *              VDM CL = number of sectors per track
 *              VDM DH = last head number
 *              VDM DL = number of drives
 *              VDM ES:DI -> drive paramter table (INT 1Eh)
 *              FStatus = INT13STATUS_SUCCESS
 *          FAILURE
 *              VDM AL = 0
 *              VDM BL = 0
 *              VDM CX = 0
 *              VDM DH = 0
 *              VDM DL = 0 if equip flag has the       number of drives
 *              VDM ES:DI = 0:0
 *              FStatus = INT13STATUS_SUCCESS
 *
 *      CONTEXT
 *          VDM Task-time
 *
 *      PSEUDOCODE
 *          nDrive = DL;
 *          clear VDM AL, BL, CX, DX, ES, DI;
 *          FStatus = INT13STATUS_SUCCESS;
 *          if (equipment flag == (1 or 2 drives)) {
 *              set DL according to equipment flag;
 *              if (nDrive == (0 or 1)) {
 *                  DH = 1;       floppy drives always have two heads
 *                  set BL to drive type;
 *                  call PDD to determine media type;
 *                  if no error
 *                      set CX to track/sector info. of the media type;
 *                  else
 *                      set CX to track/sector info. of the drive type;
 *                  set ES:DI to point to disk parameter table;
 *              }
 *          }
 *
 * INPUT         = (register PCRF pcrf)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID PRIVENTRY VDSKInt13QueryFDParms(register PCRF pcrf)
{
  BYTE nDrive,                                          /* requested drive
                                                           number            */
     nEquipDrives,                                      /* number of drives
                                                           from equipment
                                                           flag              */
     bMediaType;                                        /* media type        */
  BOOL rc = 0;
  nDrive = DL(pcrf);
  AL(pcrf) = BL(pcrf) = 0;
  CX(pcrf) = DX(pcrf) = ES(pcrf) = DI(pcrf) = 0;
  VDMBase.rb_bFStatus = INT13STATUS_SUCCESS;
  nEquipDrives = (BYTE)((VDMBase.rb_fsEquip&BIOSEQUIP_FLOPPYMASK) >> ZEROBITS
     (BIOSEQUIP_FLOPPYMASK));

  if ((VDMBase.rb_fsEquip&BIOSEQUIP_FLOPPY) && (nEquipDrives < MAX_FD))
  {
    DL(pcrf) = (BYTE)(nEquipDrives+1);

    if (nDrive < MAX_FD)
    {
      DH(pcrf) = 1;                                     /* floppy drives
                                                           always have two
                                                           heads             */
      BL(pcrf) = virtFloppy[nDrive].vf_bDriveType;

/*                                 (amtMediaTable[bMediaType-1].mt_usTracks-1);*/
/*                                 (amtMediaTable[bMediaType-1].mt_usSectors); */
/*           (amtMediaTable[virtFloppy[nDrive].vf_bDriveType-1].mt_usTracks-1);*/
/*           (amtMediaTable[virtFloppy[nDrive].vf_bDriveType-1].mt_usSectors); */

      FileName[0] = DL(pcrf)+'A';                       /* max # drives      */
      if (rc = VDHOpen(FileName,
                       &DeviceHandle,
                       &ActionTaken,
                       0L,
                       0L,
                       VDHOPEN_ACTION_OPEN_IF_EXISTS,
                       VDHOPEN_FLAGS_FAIL_ON_ERROR
                          +VDHOPEN_FLAGS_DASD+VDHOPEN_SHARE_DENYNONE+
                          VDHOPEN_ACCESS_READWRITE,
                       NULL))
      {
        GetDeviceParmsParmPacket.Command = RECOMMENDED_BPB;
        LengthParm = sizeof(GetDeviceParmsParmPacket);
        LengthData = sizeof(GetDeviceParmsDataPacket);
        rc = VDHDevIOCtl(DeviceHandle,
                         IOCTL_DISK,
                         DSK_GETDEVICEPARAMS,
                         &GetDeviceParmsParmPacket,
                         LengthParm,
                         &LengthParm,
                         &GetDeviceParmsDataPacket,
                         LengthData,
                         &LengthData);
        CH(pcrf) = (BYTE)((GetDeviceParmsDataPacket.NumCyl-1)&0xFF);
        CL(pcrf) = (BYTE)
           ((GetDeviceParmsDataPacket.ExtendedBPB.sectors_per_track&0x3F)|
           ((GetDeviceParmsDataPacket.NumCyl&0x0300) >> 2));
        VDHClose(DeviceHandle);
      }
      rcMapError(pcrf,
                 rc);


      DI(pcrf) = ((PWORD)&VDMBase.rb_avpIVT[BIOSINT_DISKPARMS])[0];
      ES(pcrf) = ((PWORD)&VDMBase.rb_avpIVT[BIOSINT_DISKPARMS])[1];
    }
  }
}                                                       /*
                                                         VDSKInt13QueryFDParms
                                                                            */

/****************************************************************************
 *
 * FUNCTION NAME = VDSKInt13QueryHDDASDType
 *
 * DESCRIPTION   =
 *
 *  LP  VDSKInt13QueryHDDASDType - Int 13h Query Hard Disk DASD Type
 *
 *      This subroutine is called when a VDM is doing an Int 13h
 *      with a query DASD type subfunction on a hard disk.
 *
 *      ENTRY
 *          pcrf -> VDM client register frame
 *              DL = drive number
 *
 *      EXIT
 *          SUCCESS
 *              VDM AL = 0
 *              VDM AH = DASD type
 *              VDM CX:DX = total number of sectors
 *              DStatus = INT13STATUS_SUCCESS
 *          FAILURE
 *              VDM AX = 0
 *              VDM CX = 0
 *              VDM DX = 0
 *              DStatus = INT13STATUS_SUCCESS
 *
 *      CONTEXT
 *          VDM Task-time
 *
 *      PSEUDOCODE
 *          nDrive = DL;
 *          clear VDM AX, CX, DX;
 *          if (nDrive < number of drives) {
 *              if drive number 1
 *                  use hard disk parameter table 2;
 *              else
 *                  use hard disk parameter table 1;
 *              set AH to DASDTYPE_HD;
 *              set CX:DX to total number of sectors;
 *
 * INPUT         = (register PCRF pcrf)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID PRIVENTRY VDSKInt13QueryHDDASDType(register PCRF pcrf)
{
  BYTE nDrive;
  PHDPARMTABLE pDiskParm;
  ULONG nSectors;
  WORD wMaxCyl;
  BOOL rc = 0;
  nDrive = (BYTE)(DL(pcrf)&~DRIVE_HDMASK);
  AX(pcrf) = CX(pcrf) = 0;                              /* Removed clear of
                                                           DX PTR
*/
  VDMBase.rb_bDStatus = INT13STATUS_SUCCESS;

  if (nDrive < VDMBase.rb_nDTotal)
  {

/*
@V69035    ** 9/15/88 INT's 41 & 46                                      **
@V69035    ** can not be used to access the hard disk parameters tables. **
@V69035    ** Consequently, we cannot use BIOSINT_HDISK*PARMS            **
@V69035
@V69035 Changed so that all hardware uses the dasd manager                   */

    pSysConfigTable = (PSYS_CONFIG_TABLE)VDHQuerySysValue(CURRENT_VDM,
                                                          VDHGSV_MACHINEINFO);
                                                          


/*  @V69035    if ((VDHQuerySysValue(CURRENT_VDM,                            */
/*  @V69035                    VDHGSV_MACHINETYPE) == MACHINE_TYPE_PS2) ||   */
                                                          /*  PTR            */
                                                          
/*  @V69035                             (pSysConfigTable->Model == 0xF8))    */
/*  @V69035    {                                   */ 

/*                                       (F16PVOID)DL(pcrf),
                                       F16PFROMP( &PS2_DiskTable)))
*//**//**//**/
      FileName[0] = (BYTE)((DL(pcrf)&0x7f)+1+'0');

      if (rc = VDHPhysicalDisk(PHYSICAL_HANDLE,
                               (ULONG *)&DriveHandle,
                               sizeof(DriveHandle),
                               FileName,
                               sizeof(FileName)))
      {
        GetDeviceParmsParmPacket.Command = RECOMMENDED_BPB;
        LengthParm = sizeof(GetDeviceParmsParmPacket);
        LengthData = sizeof(GetPhysDeviceParmsDataPacket);
        rc = VDHDevIOCtl(DriveHandle,
                         IOCTL_PHYSICALDISK,
                         DSK_GETDEVICEPARAMS,
                         &GetDeviceParmsParmPacket,
                         LengthParm,
                         &LengthParm,
                         &GetPhysDeviceParmsDataPacket,
                         LengthData,
                         &LengthData);
        AH(pcrf) = DASDTYPE_HD;                         /* indicate hard
                                                           disk PTR
*/

        nSectors = (USHORT)GetPhysDeviceParmsDataPacket.NumCyl*
           (USHORT)GetPhysDeviceParmsDataPacket.NumHeads*
              (USHORT)GetPhysDeviceParmsDataPacket.SecperTrack;
        CX(pcrf) = ((PWORD)&nSectors)[1];
        DX(pcrf) = ((PWORD)&nSectors)[0];
        VDHPhysicalDisk(RELEASE_PHYSICAL_HANDLE,
                        NULL,
                        0,
                        (ULONG *)&DriveHandle,
                        sizeof(DriveHandle));
      }
      rcMapError(pcrf,
                 rc);

/*  @V69035  }                                                               */
/*  @V69035  else                                                            */
/*  @V69035  {                                                               */
/*  @V69035    if (nDrive&0x01)                                              */
/*  @V69035      pDiskParm = PFROMVP(VDMBase.rb_avpIVT[BIOSINT_HDISK2PARMS]);*/
/*  @V69035    else                             */ /* drive 0                */
/*  @V69035      pDiskParm = PFROMVP(VDMBase.rb_avpIVT[BIOSINT_HDISK1PARMS]);*/
/*  @V69035    nSectors = pDiskParm->hdp_bMaxHeads
                          *pDiskParm->hdp_bSectorsPerTrack
                          *(pDiskParm->hdp_wMaxCylinders-1);                 */
/*  @V69035    CX(pcrf) = ((PWORD)&nSectors)[1];   */ /* upper word of       */
/*  @V69035    DX(pcrf) = ((PWORD)&nSectors)[0];   */ /* lower word of       */
/*  @V69035    AH(pcrf) = DASDTYPE_HD;             */ /* indicate hard disk  */
/*  @V69035  }                                                               */
  }

  else                                                  
    AH(pcrf) = 0x1;                                     
}                                                       /*
                                                      VDSKInt13QueryHDDASDType
                                                                             */

/****************************************************************************
 *
 * FUNCTION NAME = VDSKInt13QueryFDDASDType
 *
 * DESCRIPTION   =
 *
 *  LP  VDSKInt13QueryFDDASDType - Int 13h Query Floppy Disk DASD Type
 *
 *      This subroutine is called when a VDM is doing an Int 13h
 *      with a query disk DASD type subfunction on a floppy disk.
 *
 *      ENTRY
 *          pcrf -> VDM client register frame
 *              DL = drive number
 *
 *      EXIT
 *          SUCCESS
 *              VDM AL = 0
 *              VDM AH = DASD type
 *              FStatus = INT13STATUS_SUCCESS
 *          FAILURE
 *              VDM AX = 0
 *              FStatus = INT13STATUS_SUCCESS
 *
 *      CONTEXT
 *          VDM Task-time
 *
 *      PSEUDOCODE
 *          clear VDM AX;
 *          set FStatus to INT13STATUS_SUCCESS;
 *          if valid drive number {
 *              switch(drive type of drive) {
 *                  case DRVTYPE_NONE:
 *                      set AH to DASDTYPE_NONE;
 *                      break;
 *                  case DRVTYPE_360K:
 *                      set AH to DASDTYPE_FDNOCHANGEDET;
 *                      break;
 *                  default:
 *                      set AH to DASDTYPE_FDCHANGEDET;
 *              }
 *          }
 *
 * INPUT         = (register PCRF pcrf)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID PRIVENTRY VDSKInt13QueryFDDASDType(register PCRF pcrf)
{
  AX(pcrf) = 0;
  VDMBase.rb_bFStatus = INT13STATUS_SUCCESS;

  switch (virtFloppy[DL(pcrf)].vf_bDriveType)
  {
    case  DRVTYPE_NONE :
      AH(pcrf) = DASDTYPE_NONE;
      break;
    case  DRVTYPE_360K :
      AH(pcrf) = DASDTYPE_FDNOCHANGEDET;
      break;
    default  :
      AH(pcrf) = DASDTYPE_FDCHANGEDET;
  }
}                                                    /*
                                                      VDSKInt13QueryFDDASDType
                                                                             */

/****************************************************************************
 *
 * FUNCTION NAME = VDSKInt13QueryChange
 *
 * DESCRIPTION   =
 *
 *  LP  VDSKInt13QueryChange - Int 13h Query Floppy Disk Change State
 *
 *      This subroutine is called when a VDM is doing an Int 13h
 *      with a query disk change subfunction on a floppy disk.
 *
 *      ENTRY
 *          pcrf -> VDM client register frame
 *              DL = drive number
 *
 *      EXIT
 *          SUCCESS
 *              FStatus = INT13STATUS_MEDIACHANGE if changed
 *              FStatus = INT13STATUS_SUCCESS if no change
 *          FAILURE
 *              FStatus = INT13STATUS_TIMEOUT
 *
 *      CONTEXT
 *          VDM Task-time
 *
 *      PSEUDOCODE
 *          if drive not present
 *              set status to timeout;
 *          else if drive is 360K
 *              set status to changed;
 *          else if drive has fChanged set {
 *              set status to changed;
 *              clear fChanged of drive;
 *          } else {
 *              call PDD to determine change state of drive;
 *              if disk has changed {
 *                  set status to changed;
 *                  call VDHEnumerateVDMs to set fChanged of each VDM
 *                      except this VDM;
 *              } else
 *                  set status to no change;
 *          }
 *
 * INPUT         = (register PCRF pcrf)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID PRIVENTRY VDSKInt13QueryChange(register PCRF pcrf)
{
  BYTE rc = 0,buffer;

  if (virtFloppy[DL(pcrf)].vf_bDriveType == DRVTYPE_NONE)
    VDMBase.rb_bFStatus = INT13STATUS_TIMEOUT;

  else

    if (virtFloppy[DL(pcrf)].vf_bDriveType == DRVTYPE_360K)
      VDMBase.rb_bFStatus = INT13STATUS_MEDIACHANGE;

    else

      if (virtFloppy[DL(pcrf)].vf_fDiskChanged)
      {
        VDMBase.rb_bFStatus = INT13STATUS_MEDIACHANGE;
        virtFloppy[DL(pcrf)].vf_fDiskChanged = FALSE;
      }

/*                                           (ULONG)(DL(pcrf)));               */

      else
      {

        if (rc = VDHOpen(FileName,
                         &DeviceHandle,
                         &ActionTaken,
                         0L,
                         0L,
                         VDHOPEN_ACTION_OPEN_IF_EXISTS,
                         VDHOPEN_FLAGS_FAIL_ON_ERROR+VDHOPEN_FLAGS_DASD+
                            VDHOPEN_SHARE_DENYNONE+VDHOPEN_ACCESS_READWRITE,
                         NULL))
        {
          rc = VDHRead(DeviceHandle,
                       &buffer,
                       1);

          if (rc == ERROR_UNCERTAIN_MEDIA)
          {
            VDMBase.rb_bFStatus = INT13STATUS_MEDIACHANGE;
            hvdmDiskChanged = hvdmThisVDM;
            VDHEnumerateVDMs(VDSKSetDiskChanged,
                             (ULONG)(DL(pcrf)));
          }

          else
          {
            VDMBase.rb_bFStatus = INT13STATUS_SUCCESS;
          }                                             /* endif             */

          VDHClose(DeviceHandle);
        }
      }
}                                                       /*
                                                         VDSKInt13QueryChange
                                                                            */

/****************************************************************************
 *
 * FUNCTION NAME = VDSKInt13SetDiskType
 *
 * DESCRIPTION   =
 *
 *  LP  VDSKInt13SetDiskType - Int 13h Set Disk Type for Format
 *
 *      This subroutine is called when a VDM is doing an Int 13h
 *      with a set disk type subfunction on a floppy disk.
 *
 *      ENTRY
 *          pcrf -> VDM client register frame
 *              DL = drive number
 *              AL = disk type
 *
 *      EXIT
 *          SUCCESS
 *              FStatus = INT13STATUS_SUCCESS
 *          FAILURE
 *              FStatus = INT13STATUS_BADCMD (incorrect disk type)
 *
 *      CONTEXT
 *          VDM Task-time
 *
 *      PSEUDOCODE
 *          set status to INT13STATUS_SUCCESS;
 *          switch(disk type) {
 *              case DISKTYPE_360IN360:
 *              case DISKTYPE_360IN1200K:
 *                  set number of tracks for 360K disk;
 *                  set number of sectors per track for 360K disk;
 *                  break;
 *              case DISKTYPE_1200KIN1200K:
 *                  set number of tracks for 1.2M disk;
 *                  set number of sectors per track for 1.2M disk;
 *                  break;
 *              case DISKTYPE_720IN720:
 *                  set number of tracks for 720K disk;
 *                  set number of sectors per track for 720K disk;
 *                  break;
 *              default:
 *                  set status to INT13STATUS_BADCMD;
 *          }
 *
 * INPUT         = (register PCRF pcrf)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID PRIVENTRY VDSKInt13SetDiskType(register PCRF pcrf)
{
  VDMBase.rb_bFStatus = INT13STATUS_SUCCESS;            /* assume success   */

  switch (AL(pcrf))
  {
    case  DISKTYPE_360IN360 :
    case  DISKTYPE_360IN1200K :
      virtFloppy[DL(pcrf)].vf_usFormatTracks = amtMediaTable[DRVTYPE_360K-1].
         mt_usTracks;
      virtFloppy[DL(pcrf)].vf_usFormatSectors = amtMediaTable[DRVTYPE_360K-1].
         mt_usSectors;
      break;
    case  DISKTYPE_1200KIN1200K :
      virtFloppy[DL(pcrf)].vf_usFormatTracks = amtMediaTable[DRVTYPE_1200K-1].
         mt_usTracks;
      virtFloppy[DL(pcrf)].vf_usFormatSectors = amtMediaTable[DRVTYPE_1200K-1]
         .mt_usSectors;
      break;
    case  DISKTYPE_720IN720 :
      virtFloppy[DL(pcrf)].vf_usFormatTracks = amtMediaTable[DRVTYPE_720K-1].
         mt_usTracks;
      virtFloppy[DL(pcrf)].vf_usFormatSectors = amtMediaTable[DRVTYPE_720K-1].
         mt_usSectors;
      break;
    default  :
      VDMBase.rb_bFStatus = INT13STATUS_BADCMD;
  }
}                                                       /*
                                                         VDSKInt13SetDiskType
                                                                            */

/****************************************************************************
 *
 * FUNCTION NAME = VDSKInt13SetMediaType
 *
 * DESCRIPTION   =
 *
 *  LP  VDSKInt13SetMediaType - Int 13h Set Media Type for Format
 *
 *      This subroutine is called when a VDM is doing an Int 13h
 *      with a set media type subfunction on a floppy disk.
 *
 *      ENTRY
 *          pcrf -> VDM client register frame
 *              DL           = drive number
 *              CH           = lower 8 bits of number of tracks
 *              CL (bit 7,6) = high 2 bits of number of tracks
 *                 (bit 5-0) = number of sectors per track
 *
 *      EXIT
 *          SUCCESS
 *              FStatus = INT13STATUS_SUCCESS
 *          FAILURE
 *              FStatus = INT13STATUS_BADCMD (function not available)
 *              FStatus = INT13STATUS_BADMEDIATYPE (media type unknown)
 *
 *      CONTEXT
 *          VDM Task-time
 *
 *      PSEUDOCODE
 *          if media parameters are not valid
 *              set status to INT13STATUS_BADMEDIATYPE;
 *          else if drive does not support such media
 *              set status to INT13STATUS_BADCMD;
 *          else {
 *              set status to INT13STATUS_SUCCESS;
 *              store media parameters;
 *          }
 *
 * INPUT         = (register PCRF pcrf)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID PRIVENTRY VDSKInt13SetMediaType(register PCRF pcrf)
{
  USHORT nTracks,nSectors;
  register INT nMedia;
  nSectors = (USHORT)(CL(pcrf)&0x3f);
  nTracks = (USHORT)(CH(pcrf)+((CL(pcrf)&0xc0) << 2));

  for (nMedia = MEDIATYPE_360K-1; nMedia < MEDIATYPE_1440K; nMedia++)

    if ((amtMediaTable[nMedia].mt_usTracks == nTracks) && (amtMediaTable
       [nMedia].mt_usSectors == nSectors))
      break;

  if (++nMedia > MEDIATYPE_1440K)                       /* media not found  */
    VDMBase.rb_bFStatus = INT13STATUS_BADMEDIATYPE;

  else

    if ((virtFloppy[DL(pcrf)].vf_bDriveType == (BYTE)nMedia) || (virtFloppy[DL
       (pcrf)].vf_bDriveType == DRVTYPE_1200K) && (nMedia == MEDIATYPE_360K)
       || (virtFloppy[DL(pcrf)].vf_bDriveType == DRVTYPE_1440K) && (nMedia ==
       MEDIATYPE_720K))
    {
      VDMBase.rb_bFStatus = INT13STATUS_SUCCESS;
      virtFloppy[DL(pcrf)].vf_usFormatTracks = nTracks;
      virtFloppy[DL(pcrf)].vf_usFormatSectors = nSectors;
    }

    else
      VDMBase.rb_bFStatus = INT13STATUS_BADCMD;
}                                                       /*
                                                         VDSKInt13SetMediaType
                                                                            */

/****************************************************************************
 *
 * FUNCTION NAME = VDSKSetDiskChanged
 *
 * DESCRIPTION   =
 *
 *  LP  VDSKSetDiskChanged - Set Diskette Changed Status
 *
 *      This subroutine is called for each VDM to set the
 *      corresponding disk changed state of the given drive.
 *
 *      ENTRY
 *          hvdm   - handle of VDM
 *          nDrive - drive number
 *
 *      EXIT
 *          return TRUE
 *
 *      CONTEXT
 *          VDM Task-time
 *
 *      PSEUDOCODE
 *          if it is not the VDM that detected a disk changed
 *              set the VDM's fDiskChanged flag for the given drive;
 *
 * INPUT         = (HVDM hvdm,ULONG nDrive)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID PRIVENTRY VDSKSetDiskChanged(HVDM hvdm,ULONG nDrive)
{

  if (hvdm != hvdmDiskChanged)
    REFHVDM(hvdm,
            BOOL,
            virtFloppy[nDrive].vf_fDiskChanged) = TRUE;
}                                                       /*
                                                           VDSKSetDiskChange*/

/****************************************************************************
 *
 * FUNCTION NAME = VDSKCheckVirtDisk
 *
 * DESCRIPTION   =
 *
 *  LP  VDSKCheckVirtDisk - Check for INT 13h request for virtual disk
 *
 *      ENTRY
 *          nFunc == INT 13h function
 *          pcrf  -> VDM registers
 *
 *      EXIT
 *          returns TRUE if serviced, FALSE if not
 *
 *      CONTEXT
 *          VDM Task-time
 *
 *      PSEUDOCODE
 *
 * INPUT         = (INT nFunc,register PCRF pcrf)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

BOOL PRIVENTRY VDSKCheckVirtDisk(INT nFunc,register PCRF pcrf)
{
  PMAPDISK pmd;
  register PBYTE pBuf;
  PFDPARMTABLE pfd;
  PBYTE pbStatus;
  register PVIRTDISK pvd;
  HFILE hfVirtDisk;
  TRACKINFO trkInfo;
  INT iDrive,i;
  INT nSecs,nbTransfer,nbVDMSector;
  INT iCyl,iHead,iTrack,iSec,iLogicalSec,maxTracks;

    /*** Make sure it's a drive we're "virtualizing" ***/

  iDrive = DL(pcrf);
  pbStatus = &VDMBase.rb_bFStatus;

  if (iDrive >= DRIVE_HDMASK)
  {
    iDrive -= (DRIVE_HDMASK-2);
    pbStatus = &VDMBase.rb_bDStatus;
  }

  if (iDrive >= MAX_DRIVES)
    return  FALSE;

    /*** If drive should be disabled, return an error ***/

  pmd = &amdInfo[iDrive];

  if (pmd->md_fbPhysDisk&MDFLAGS_DISABLED)
  {
    *pbStatus = INT13STATUS_TIMEOUT;
    return  TRUE;
  }

    /*** If drive should be remapped, modify the specified drive ***/

  if (pmd->md_fbPhysDisk&MDFLAGS_PHYSICAL)
  {
    DL(pcrf) = pmd->md_iPhysical;
    return  FALSE;
  }

    /*** The rest of this routine is dedicated to virtual disk support ***/

  if (!(pmd->md_fbPhysDisk&MDFLAGS_VIRTUAL))
    return  FALSE;
  pvd = &pmd->md_vdInfo;
  hfVirtDisk = pmd->md_hfVirtDisk;

    /*** Default to success, then check function requested ***/

  *pbStatus = INT13STATUS_SUCCESS;

  if (nFunc == INT13_QUERYDRVPARMS)
  {
    i = pvd->vd_nHeads *pvd->vd_nCyls *pvd->vd_nsecTrack *pvd->vd_nbSector;

    if (i < 300000 || i > 1500000)
      i = 0;                                            /* unknown          */

    else

      if (i > 1400000)
        i = 4;                                          /* assume 1.44Mb
                                                           drive            */

      else

        if (i > 1200000)
          i = 2;                                        /* assume 1.2Mb
                                                           drive            */

        else

          if (i > 700000)
            i = 3;                                      /* assume 720Kb
                                                           drive            */

          else
            i = 1;                                      /* assume 360Kb
                                                           drive            */
    AH(pcrf) = 0;
    BX(pcrf) = (USHORT)i;
    i = pvd->vd_nCyls-1;
    CX(pcrf) = (USHORT)((i << 8)|pvd->vd_nsecTrack|((i&0x300) >> 2));
    DX(pcrf) = (USHORT)(((pvd->vd_nHeads-1) << 8)|2);   /* BUGBUG           */
  }

    /*** Past this point, we only handle read and write requests ***/

  if (nFunc < INT13_READSECTORS || nFunc > INT13_WRITESECTORS)
    return  TRUE;

    /*** Now to compute some preliminaries, like desired track offset ***/

  iCyl = CH(pcrf)+((CL(pcrf)&0xC0) << 2);
  iHead = DH(pcrf);
  iTrack = iCyl *pvd->vd_nHeads+iHead;
  iSec = (CL(pcrf)&0x3F)-1;
  nSecs = AL(pcrf);
  pBuf = PFROMVADDR(ES(pcrf),
                    BX(pcrf));
  maxTracks = pvd->vd_nHeads *pvd->vd_nCyls;

    /*** Make sure the requested track is valid ***/

  if (iTrack >= maxTracks)
    goto error_exit;

    /*** If # sectors/track is given in the virtdisk header, then
         there is no track table, and we can seek directly to the data ***/

  if (pvd->vd_nsecTrack)
  {
    trkInfo.ti_nsecTrack = pvd->vd_nsecTrack;
    trkInfo.ti_nbSector = pvd->vd_nbSector;
    trkInfo.ti_offsetFile = iTrack *pvd->vd_nsecTrack *pvd->vd_nbSector;

    if (!(pmd->md_fbPhysDisk&MDFLAGS_LOGICAL))
      trkInfo.ti_offsetFile += sizeof(VIRTDISK);

    else
    {
      iLogicalSec = iTrack *pvd->vd_nsecTrack+iSec;

      if (iLogicalSec < pmd->md_nsecHidden)
      {

        if (nFunc == INT13_READSECTORS)
        {
          memset(pBuf,
                 0,
                 pvd->vd_nbSector *nSecs);

          if (iLogicalSec == 0)
          {
            ((PMBR)pBuf)->partition_status = PARTITION_ACTIVE;
            ((PMBR)pBuf)->starting_head = 1;
            ((PMBR)pBuf)->starting_sec_cyl = 1;
            ((PMBR)pBuf)->partition_type = pmd->md_type;
            ((PMBR)pBuf)->ending_head = (UCHAR)(pvd->vd_nHeads-1);
            i = pvd->vd_nCyls-1;
            ((PMBR)pBuf)->ending_sec_cyl = (USHORT)((i << 8)|pvd->vd_nsecTrack
               |((i&0x300) >> 2));
            ((PMBR)pBuf)->starting_abs_sector = pmd->md_nsecHidden;
            ((PMBR)pBuf)->total_sectors = pvd->vd_nHeads *pvd->vd_nCyls
               *pvd->vd_nsecTrack-pmd->md_nsecHidden;
            pBuf[0x1FE] = 0x55;
            pBuf[0x1FF] = 0xAA;
          }
        }
        return  TRUE;
      }

      else
        trkInfo.ti_offsetFile -= pmd->md_nsecHidden *pvd->vd_nbSector;
    }
  }

    /*** Track table exists, so seek to the appropriate entry
         within it to find out where the data for the track really is ***/

  else
  {

        /*** Convert iTrack into raw file offset now ***/

    iTrack = sizeof(VIRTDISK)+iTrack *sizeof(TRACKINFO);

    if (VDHSeek(hfVirtDisk,
                iTrack,
                VDHSK_ABSOLUTE) != iTrack ||            
                   VDHRead(hfVirtDisk,
                           SSToDS(&trkInfo),
                           sizeof(trkInfo)) != sizeof(trkInfo))
      goto error_exit;
  }

    /*** Make sure the actual sector size matches the VDM's expected size ***/

  pfd = PFROMVP(VDMBase.rb_avpIVT[BIOSINT_DISKPARMS]);
  nbVDMSector = 128 << pfd->fdp_bSectorSize;

  if (trkInfo.ti_nbSector != nbVDMSector)
    goto error_exit;

    /*** Add sector offset to track offset to get final offset ***/

  trkInfo.ti_offsetFile += iSec *trkInfo.ti_nbSector;
  nbTransfer = nSecs *trkInfo.ti_nbSector;

  switch (nFunc)
  {
    case  INT13_READSECTORS :

      if (VDHSeek(hfVirtDisk,
                  trkInfo.ti_offsetFile,
                  VDHSK_ABSOLUTE) != trkInfo.ti_offsetFile || 
                     VDHRead(hfVirtDisk,
                             pBuf,
                             nbTransfer) != nbTransfer)
        goto error_exit;
      break;
    case  INT13_WRITESECTORS :

      if (pvd->vd_fbVirtDisk&VDFLAGS_WRITEPROTECT)
        *pbStatus = INT13STATUS_WRTPROTECT;

      else
      {

        if (VDHSeek(hfVirtDisk,
                    trkInfo.ti_offsetFile,
                    VDHSK_ABSOLUTE) != trkInfo.ti_offsetFile || /*
*/
                       VDHWrite(hfVirtDisk,
                                pBuf,
                                nbTransfer) != nbTransfer)
          goto error_exit;
      }
      break;
  }
  return  TRUE;
error_exit:

    /*** Arbitrary error code ***/

  *pbStatus = INT13STATUS_RECNOTFOUND;
  return  TRUE;
}

#pragma  END_SWAP_CODE
