/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT (C) Microsoft Corporation, 1989                                 */
/* COPYRIGHT    Copyright (C) 1995 IBM Corporation                           */
/*                                                                           */
/*    The following IBM OS/2 WARP source code is provided to you solely for  */
/*    the purpose of assisting you in your development of OS/2 WARP device   */
/*    drivers. You may use this code in accordance with the IBM License      */
/*    Agreement provided in the IBM Device Driver Source Kit for OS/2. This  */
/*    Copyright statement may not be removed.                                */
/*                                                                           */
/*****************************************************************************/
/**************************************************************************
 *
 * SOURCE FILE NAME = VFIO.C
 *
 * DESCRIPTIVE NAME = Virtual Floppy Device Driver Port I/O Processing
 *
 *
 *
 * VERSION = V2.0
 *
 * DATE
 *
 * DESCRIPTION  This module contains the VFD's Port I/O handlers.
 *
 *
 * FUNCTIONS   VFPortInput               VFPortOutput
 *             VFPortDO                  VFNoSupportIn
 *             VFNoSupportOut            vfOpenFloppy
 *             vfCloseFloppy             VFClearInUse
 *             VFWaitInUse
 *
 *
 * ENTRY POINTS:
 *
 * DEPENDENCIES:
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/

#include "vfdp.h"

#ifdef   VDDSTRICT
MODNAME = __FILE__;
#endif
VOID PRIVENTRY ResetDsktBIOSData(HVDM hvdm);
#pragma  BEGIN_GLOBAL_DATA
extern HVDM hvdmFloppyOwner;                            /* VDM handle of
                                                           floppy owner     */
extern FLAGS flFloppy;                                  /* floppy flags     */
extern BYTE hvdmFloppyOwner3F2;                         /* 3F2 access data  */
extern ULONG motor_timeout;                             /* floppy motor
                                                           timeout value    */
                                                         /* @V0024          */

extern HVDD hVDDVPIC;                                   /* @VD1535          */
                                                         /* VDDtoVDD comm   */
                                                         /* to VPIC         */

extern HVDHSEM hsemFloppyOwnership;                     /* Block
                                                           simultaneous
                                                           VDMs             */
                                                         /* @VD1535         */

extern VDHSEMSTATE semStateOwned;                       /* Data area fro
                                                           sem info         */
extern CHAR VfSetIOHookVar;                             /* @V4780           */
#pragma  END_GLOBAL_DATA
#pragma  BEGIN_SWAP_DATA
extern HHOOK hhookvirrWaitPFD;                          /* VIRR hook handle
                                                           for waiting PFD  */
extern HHOOK hhooktimerInUseTimeout;                    /* timer hook
                                                           handle for inuse
                                                           timeout          */
extern HHOOK hhookDsktMotorTmr;                         /* Dskt Motor
                                                           TimeOut timer    */
                                                         /* @V0855          */

extern IOH iotFDPort;                                   /* port hook
                                                           structure        */
extern HIRQ hirq;                                       /* floppy IRQ
                                                           handle           */
                                                         /* @VD1535         */

#pragma  END_SWAP_DATA
#pragma  BEGIN_INSTANCE_DATA

/* start @VD1535  */

extern HFILE DeviceHandle;                              /* Handle to use
                                                           w/. DevIOCTL     */
extern SUSPENDRESTARTPARM SuspendRestartParmPacket;     /* SUSPEND/RESTART
                                                           IOCTL            */
extern ULONG LengthParm,LengthData;                     /* DevIOCTl parms   */
extern ULONG ActionTaken;                               /* DevIOCTL parms   */
extern CHAR FileName[];                                 /* DevIOCTL parms   */

/* @V74056
** @V8245 @V74056 */   extern HFILE hRedetermineMedia;                         /* @V5774
** @V8245 @V74056 */   extern REDETERMINEMEDIAPARM RedetermineMediaParmPacket, /* @V5774
** @V8245 @V74056 */                               RedetermineMediaDataPacket; /* @V5774
** @V8245 @V74056 */   extern ULONG   RedetermineMediaLengthData;              /* @V5774
** @V8245 @V74056 */   extern CHAR    AFileName[];                             /* @V5774
**  end   @VD1535  @V74056
*/

#pragma  END_INSTANCE_DATA
#pragma  BEGIN_SWAP_INSTANCE
extern HVDM hvdmThisVDM;                                /* VDM handle       */
extern HHOOK hhookvirrWaitInUse;                        /* VIRR hook handle
                                                           for waiting
                                                           InUse            */

#ifdef   MONITORPORT
extern BOOL fPortTrapEnabled;                           /* port trap is
                                                           enabled          */
#endif
#pragma  END_SWAP_INSTANCE
#pragma  BEGIN_SWAP_CODE

/****************************************************************************
 *
 * FUNCTION NAME = VFPortInput
 *
 * DESCRIPTION   =
 *
 *  EP  VFPortInput() - VFD port input handler
 *
 *  This registered subroutine is called whenever byte input
 *  is performed on any floppy ports except the digital output port.
 *  (see 8086 Emulation for complete semantics).
 *
 *  ENTRY
 *      ulPort - port address
 *      pcrf   ->client register frame
 *  EXIT
 *      returns data read
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      VDM Task-time
 *
 *  PCODE
 *      get floppy ownership;
 *      read port;
 *
 * INPUT         = (ULONG ulPort,PCRF pcrf)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

BYTE HOOKENTRY VFPortInput(ULONG ulPort,PCRF pcrf)
{
  register BYTE bData;

#ifdef   MONITORPORT

  if (fPortTrapEnabled)
    vfOpenFloppy(hvdmThisVDM);

#else
  vfOpenFloppy(hvdmThisVDM);
#endif
  bData = inp(ulPort);
  PRINTTRACE("VFPortInput: in(0x%04lx) = 0x%02x\n",
             ulPort,
             bData);
  return  bData;
}                                                       /* VFPortInput      */

/****************************************************************************
 *
 * FUNCTION NAME = VFPortOutput
 *
 * DESCRIPTION   =
 *
 *  EP  VFPortOutput() - VFD port output handler
 *
 *  This registered subroutine is called whenever byte output
 *  is performed on any floppy ports except the digital output port.
 *  (see 8086 Emulation for complete semantics).
 *
 *  ENTRY
 *      bOutData - data to be written to I/O port
 *      ulPort   - port address
 *      pcrf     ->client register frame
 *  EXIT
 *      None
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      VDM Task-time
 *
 *  PCODE
 *      get floppy ownership;
 *      write port;
 *
 * INPUT         = (BYTE bOutData,ULONG ulPort,PCRF pcrf)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID HOOKENTRY VFPortOutput(BYTE bOutData,ULONG ulPort,PCRF pcrf)
{

#ifdef   MONITORPORT

  if (fPortTrapEnabled)
    vfOpenFloppy(hvdmThisVDM);

#else
  vfOpenFloppy(hvdmThisVDM);
#endif
  PRINTTRACE("VFPortOutput: out(0x%04lx,0x%02x)\n",
             ulPort,
             bOutData);
  outp(ulPort,
       bOutData);
}                                                       /* VFPortOutput     */

#ifndef  NOMOTORTRAP

/****************************************************************************
 *
 * FUNCTION NAME = VFPortDO
 *
 * DESCRIPTION   =
 *
 *  EP  VFPortDO() - VFD Digital Output Port output handler
 *
 *  This registered subroutine is called whenever byte output
 *  is performed on the digital output port.
 *  (see 8086 Emulation for complete semantics).
 *
 *  ENTRY
 *      bOutData - data to be written to I/O port
 *      ulPort   - port address
 *      pcrf     ->client register frame
 *  EXIT
 *      None
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      VDM Task-time
 *
 *  PCODE
 *      monitor the motor enable bits;
 *      if both bits are off
 *          get floppy ownership;
 *      else
 *          indicate floppy ownership can be preempted if owned;
 *      endif
 *      perform the output;
 *
 * INPUT         = (BYTE bOutData,ULONG ulPort,PCRF pcrf)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID HOOKENTRY VFPortDO(BYTE bOutData,ULONG ulPort,PCRF pcrf)
{

  if ((bOutData&(DO_MOTOREN0+DO_MOTOREN1)) || (!(bOutData&DO_NOTFDCRESET)))
  {                                                     /* xxxx             */

    if (bOutData&(DO_MOTOREN0+DO_MOTOREN1))
      motor_timeout = LONG_MOTOR_TIMEOUT;               /* Trust
                                                           application to
                                                           turn motor off (but
                                                           trust it just
                                                           for 20 secs)     */
                                                         /* @V0024          */

    hvdmFloppyOwner3F2 = bOutData;
    PRINTTRACE("VFPortDO: motor on.\n");
    vfOpenFloppy(hvdmThisVDM);

/*
** @V4138
*/
/*
** if(!(bOutData & DO_NOTFDCRESET))
**   if ( flFloppy & F_TIMEOUTSETMOTOROFF ) VDHDisarmTimerHook (
**                                                 hhookDsktMotorTmr);
*/

  }

  else
  {
    PRINTTRACE("VFPortDO: motor off.\n");
    vfCloseFloppy(hvdmThisVDM);
  }
  PRINTTRACE("VFPortDO: out(0x%04lx,0x%02x)\n", ulPort, bOutData);
  outp(ulPort, bOutData);
}                                                       /* VFPortDO         */
#endif

/****************************************************************************
 *
 * FUNCTION NAME = VFNoSupportIn
 *
 * DESCRIPTION   =
 *
 *  EP  VFNoSupportIn() - VFD port input handler for no PFD support
 *
 *  This registered subroutine is called whenever byte input
 *  is performed on any floppy ports and there is no PFD support.
 *  (see 8086 Emulation for complete semantics).
 *
 *  ENTRY
 *      ulPort - port address
 *      pcrf   ->client register frame
 *  EXIT
 *      returns data read
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      VDM Task-time
 *
 *  PCODE
 *      return UNDEF_BYTE;
 *
 * INPUT         = (ULONG ulPort,PCRF pcrf)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

BYTE HOOKENTRY VFNoSupportIn(ULONG ulPort,PCRF pcrf)
{

/*    PRINTDEBUG("VFNoSupportIn: unsupported port read at 0x%04lx\n", ulPort);*/

  return  UNDEF_BYTE;
}                                                       /* VFNoSupportIn    */

/****************************************************************************
 *
 * FUNCTION NAME = VFNoSupportOut
 *
 * DESCRIPTION   =
 *
 *  EP  VFNoSupportOut() - VFD port output handler for no PFD support
 *
 *  This registered subroutine is called whenever byte output
 *  is performed on any floppy ports when there is no PFD support.
 *  (see 8086 Emulation for complete semantics).
 *
 *  ENTRY
 *      bOutData - data to be written to I/O port
 *      ulPort   - port address
 *      pcrf     ->client register frame
 *  EXIT
 *      None
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      VDM Task-time
 *
 *  PCODE
 *      ignore the call;
 *
 * INPUT         = (BYTE bOutData,ULONG ulPort,PCRF pcrf)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID HOOKENTRY VFNoSupportOut(BYTE bOutData,ULONG ulPort,PCRF pcrf)
{

/*
**    PRINTDEBUG("VFNoSupportOut: unsupported port write at 0x%04lx (0x%02x)\n",
**                 ulPort, bOutData);
*/

}                                                       /* VFNoSupportOut   */

/****************************************************************************
 *
 * FUNCTION NAME = vfOpenFloppy
 *
 * DESCRIPTION   =
 *
 *  LP  vfOpenFloppy() - Obtain floppy ownership
 *
 *  This subroutine is called whenever the VDM wants to obtain
 *  floppy exclusive ownership.
 *
 *  ENTRY
 *      hvdm -> VDM requesting ownership
 *  EXIT
 *      None
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      VDM Task-time
 *
 *  PCODE
 *    begin:
 *      if not already own the floppy
 *          if floppy is in use by another VDM
 *              wait until floppy is free;
 *              goto begin;
 *          else
 *              indicate floppy is in use;
 *              if PFD has the ownership
 *                  call PFD to request ownership
 *                  if success
 *                      indicate this vdm owns the floppy;
 *                  else
 *                      wait for PFD until ownership is granted;
 *                      indicate this vdm owns the floppy;
 *                      goto begin;
 *                  endif
 *              else
 *                  enable all floppy I/O port hooks for the other VDM;
 *                  indicate this VDM now has the ownership;
 *              endif
 *          endif
 *      else if floppy is already in use
 *          indicate no need to disable port hooks;
 *      else
 *          indicate floppy is in use;
 *      endif
 *      if need to disable port hooks
 *          disable all floppy I/O port hooks;
 *      endif
 *
 * INPUT         = (HVDM hvdm)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID PRIVENTRY vfOpenFloppy(HVDM hvdm)
{
  register BOOL fSuccess = TRUE;
  register BOOL fRestartTimer = TRUE;                   /* @V0855          */

  if (hvdm != hvdmFloppyOwner)
  {
    VDHRequestMutexSem(hsemFloppyOwnership,
                       SEM_INDEFINITE_WAIT);            /* @V9819          */
    flFloppy |= F_FLOPPYINUSE;

    if (hvdmFloppyOwner == NO_VDM)
    {

                                            /* @V8245    @V5774  @V74056 */
     REDETERMINE_MEDIA /*  Tell FS that  media needs to  be redetermined */

      SUSPEND_PDD(hvdm)                                 /* VFLPY owns
                                                           floppy           */
         hvdmFloppyOwner = hvdm;
      PRINTTRACE("vfOpenFloppy: request ownership from PFD succeeded.\n");
    }

    else
    {
      VDHRequestVDD(hVDDVPIC,
                    hvdmFloppyOwner,
                    2,
                    NULL,
                    NULL);                              /* Mask IRQ6 for
                                                           VDM              */
      VDHRequestVDD(hVDDVPIC,
                    hvdm,
                    1,
                    NULL,
                    NULL);                              /* UnMask IRQ6 for
                                                           VDM              */
      PRINTTRACE("vfOpenFloppy: transfer ownership from another VDM.\n");
      vfSetIOHookState(hvdmFloppyOwner,
                       TRUE);
      hvdmFloppyOwner = hvdm;
    }
    ResetDsktBIOSData(hvdm);                /* The PDD (or another VDM) had
                                               ownership & might have messed
                                               up ctrlr                     */
                                                         /*                 */

  }

  else

    if (flFloppy&F_FLOPPYINUSE)                         /* already own it,
                                                           don't do anything*/
      fSuccess = FALSE;

    else
      flFloppy |= F_FLOPPYINUSE;

  if (fRestartTimer)
  {                                                     /* @V0855          */

    if (flFloppy&F_TIMEOUTSETMOTOROFF)
      VDHDisarmTimerHook(hhookDsktMotorTmr);            /* @V0855          */
    flFloppy |= F_TIMEOUTSETMOTOROFF;                   /* @V0855          */
    VDHArmTimerHook(hhookDsktMotorTmr,
                    motor_timeout,
                    VDH_TIMER_GLOBAL_CONTEXT);    /* @V0855    @V1525      */
  }

  if (fSuccess)
    vfSetIOHookState(hvdm, VfSetIOHookVar);                   /* @V4780           */
}                                                       /* vfOpenFloppy     */

/****************************************************************************
 *
 * FUNCTION NAME = vfCloseFloppy
 *
 * DESCRIPTION   =
 *
 *  LP  vfCloseFloppy() - Mark floppy ownership can be preemptible
 *
 *  This subroutine is called whenever the VDM can release its
 *  floppy exclusive ownership.
 *
 *  ENTRY
 *      hvdm -> VDM releasing ownership
 *  EXIT
 *      None
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      VDM Task-time
 *
 *  PCODE
 *      if requester owns the floppy and the floppy is in use
 *          if FDC is idle
 *              if in-use timeout timer is set
 *                  disarm it;
 *              endif
 *              indicate floppy not in use and release ownership if necessary;
 *          else
 *              indicate in-use timeout timer is set
 *              arm the in-use timeout timer;
 *          endif
 *      endif
 *
 * INPUT         = (HVDM hvdm)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID PRIVENTRY vfCloseFloppy(HVDM hvdm)
{

  if ((hvdm == hvdmFloppyOwner) && (flFloppy&F_FLOPPYINUSE))

    if ((inp(PORT_FDCSTATUS)&(STATUS_DRV0BUSY+STATUS_DRV1BUSY+STATUS_FDCBUSY+
       STATUS_DATAOUT+STATUS_READY)) == STATUS_READY)
    {
      PRINTTRACE("vfCloseFloppy: FDC is idle.\n");

      if (flFloppy&F_TIMEOUTSET)
        VDHDisarmTimerHook(hhooktimerInUseTimeout);
      VFClearInUse(NULL, NULL);
    }

    else

      if (!(flFloppy&F_TIMEOUTSET))
      {
        PRINTTRACE("vfCloseFloppy: FDC is not idle.\n");
        flFloppy |= F_TIMEOUTSET;
        VDHArmTimerHook(hhooktimerInUseTimeout,         /* @V1525           */
                        TIMEOUT_INUSE,
                        VDH_TIMER_GLOBAL_CONTEXT);
      }
}                                                       /* vfCloseFloppy    */

/****************************************************************************
 *
 * FUNCTION NAME = VFClearInUse
 *
 * DESCRIPTION   =
 *
 *  EP  VFClearInUse() - Clear floppy in-use state
 *
 *  This subroutine is called in the task context when a timeout
 *  has occurred after the DMA channel is masked or called in
 *  the VDM task context when VDMA notifies VFD that the DMA
 *  channel has been masked and the FDC is in idle state.
 *
 *  ENTRY
 *      None
 *  EXIT
 *      None
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      Task-time
 *
 *  PCODE
 *      indicate floppy is not in-use and timeout timer has not been armed;
 *      if floppy owner is still alive
 *          enable its floppy port hooks;
 *          if PFD is waiting for the floppy
 *              indicate PFD no longer waiting;
 *              enable all floppy I/O port hooks;
 *              indicate no longer owns the floppy;
 *              call PFD to free floppy ownership;
 *          endif
 *      endif
 *
 * INPUT         = (PVOID p,PCRF pcrf)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID HOOKENTRY VFClearInUse(PVOID p,PCRF pcrf)
{
  PRINTTRACE("VFClearInUse:\n");
  flFloppy &= ~(F_FLOPPYINUSE+F_TIMEOUTSET);

  if (hvdmFloppyOwner != NO_VDM)
  {
    vfSetIOHookState(hvdmFloppyOwner, TRUE);

    if (flFloppy&F_PFDWAITING)
    {
      flFloppy &= ~F_PFDWAITING;
      PRINTTRACE("VFClearInUse: free floppy ownership to PFD.\n");
      RESTART_PDD(hvdmFloppyOwner)hvdmFloppyOwner = NO_VDM;
    }
  }
}                                                       /* VFClearInUse     */

/****************************************************************************
 *
 * FUNCTION NAME = VFWaitInUse
 *
 * DESCRIPTION   =
 *
 *  EP  VFWaitInUse() - Wait for the other VDM finish floppy access
 *
 *  This subroutine is called to wait for another VDM to release
 *  floppy exclusive ownership.
 *
 *  ENTRY
 *      phvdm -> VDM handle for requesting VDM
 *  EXIT
 *      None
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      VDM Task-time
 *
 *  PCODE
 *      if floppy is still in use by another VDM
 *          keep waiting;
 *      else
 *          try to open it again;
 *
 * INPUT         = (PHVDM phvdm,PCRF pcrf)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID HOOKENTRY VFWaitInUse(PHVDM phvdm,PCRF pcrf)
{

  if (flFloppy&F_FLOPPYINUSE)
  {
    *(PHVDM)VDHQueryHookData(hhookvirrWaitInUse) = *phvdm; /* @V3987        */
    VDHWaitVIRRs(hhookvirrWaitInUse);
  }

  else
    vfOpenFloppy(*phvdm);
}                                                       /* VFWaitInUse      */

/****************************************************************************
 *
 * FUNCTION NAME = vfSetIOHookState
 *
 * DESCRIPTION   =
 *
 *  LP  vfSetIOHookState() - set floppy port I/O hook state
 *
 *  This subroutine is called to enable or disable the floppy I/O
 *  port hooks.
 *
 *  ENTRY
 *      hvdm -> VDM
 *      fState = TRUE     IO hook is enabled
 *               FALSE    IO hook is disabled
 *  EXIT
 *      None
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      Task-time
 *
 *  PCODE
 *      set floppy I/O hook state to either enabled or disabled;
 *
 * INPUT         = (HVDM hvdm,BOOL fState)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID PRIVENTRY vfSetIOHookState(HVDM hvdm,BOOL fState)
{

#ifdef   MONITORPORT
  REFHVDM(hvdm,
          BOOL,
          fPortTrapEnabled) = fState;

#else

  #ifdef   NOMOTORTRAP
  VDHSetIOHookState(hvdm,
                    PORT_STATUSA,
                    3,
                    &iotFDPort,
                    fState);
  VDHSetIOHookState(hvdm,
                    PORT_FDCDATA,
                    3,
                    &iotFDPort,
                    fState);

  #else
  VDHSetIOHookState(hvdm,
                    PORT_STATUSA,
                    2,
                    &iotFDPort,
                    fState);
  VDHSetIOHookState(hvdm,
                    PORT_FDCDATA,
                    3,
                    &iotFDPort,
                    fState);
  #endif
#endif
}                                                       /* vfSetIOHookState */
#pragma  END_SWAP_CODE
