/* SCCSID = "%W% %E%" */
/****************************************************************************/
/*                                                                          */
/*                           IBM Confidential                               */
/*                                                                          */
/*                 Copyright (c) IBM Corporation 1996                       */
/*                           All Rights Reserved                            */
/*                                                                          */
/****************************************************************************/
/************************** START OF SPECIFICATIONS ***************************/
/*                                                                            */
/*   SOURCE FILE NAME:  PARIOCTL.C                                            */
/*                                                                            */
/*   DESCRIPTIVE NAME:  PARALLEL port device driver IOCTL                     */
/*                      routines.                                             */
/*                                                                            */
/*   FUNCTION: These routines handle the IOCTLs for the parallel port         */
/*             device driver.                                                 */
/*                                                                            */
/*   NOTES:                                                                   */
/*      DEPENDENCIES: None                                                    */
/*      RESTRICTIONS: None                                                    */
/*                                                                            */
/*   ENTRY POINTS:                                                            */
/*             PARIOCtl                                                       */
/*              parFrameControlSet                                            */
/*              parInfinRetrySet                                              */
/*              parDeviceReset                                                */
/*               do_reset                                                     */
/*               reset_timedout                                               */
/*              parWriteTimeoutSet                                            */
/*              parDirectAccessSet                                            */
/*              parCommModeSet                                                */
/*              parDataXferModeSet                                            */
/*              parFrameControlQuery                                          */
/*              parInfinRetryQuery                                            */
/*              parStatusPortQuery                                            */
/*              parWriteTimeoutQuery                                          */
/*              parDirectAccessQuery                                          */
/*              parCommModeQuery                                              */
/*              parDataXferModeQuery                                          */
/*              parDeviceIDQuery                                              */
/*                                                                            */
/*   EXTERNAL REFERENCES:                                                     */
/*                                                                            */
/* Change Log                                                                 */
/*                                                                            */
/*  Mark    yy/mm/dd  Programmer      Comment                                 */
/*  ----    --------  ----------      -------                                 */
/*          96/03/01  Frank Schroeder                                         */
/*                                                                            */
/**************************** END OF SPECIFICATIONS ***************************/

#include "par.h"

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  parGenIOCtl                                      */
/*                                                                    */
/* DESCRIPTIVE NAME:  Dispatches the appropriate parallel port IOCtl  */
/*                    worker routine.                                 */
/*                                                                    */
/* FUNCTION:  The function of this routine is to dispatch the         */
/*            appropriate parallel port IOCtl worker routine.         */
/*                                                                    */
/* NOTES: parDeviceIDQuery completes at interrupt time preventing     */
/*        the call to DevHelp_UnLock from being issued there.         */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  parGenIOCtl                                          */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  parInstance_t   pInst    - ptr to adapter instance         */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: None                                                      */
/*                                                                    */
/* INTERNAL REFERENCES:  see IOCTLRouteTable                          */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
void   parGenIOCtl( parInstance_t *pInst )
{
  USHORT       i;                   /* loop control variable */
  PRP_GENIOCTL pRP;                 /* generic ioctl request packet */

  pRP = ((PRP_GENIOCTL)pInst->pRP);
  for (i=0; i < MAXIOCTLCOMB; i++)
  {
     if ((pRP->Category == IOCtlComb[i].CatCode) &&
         (pRP->Function == IOCtlComb[i].FuncCode))
     {
       (*IOCTLRouteTable[i])(pInst);
       return;
     }
  } /* endfor */

#ifdef DEBUG
  dprintf( "par1284.sys: parGenIOCtl UNSUPPORTED IOCTL COMMAND \r\n" );
  dprintf( "par1284.sys: Cat Code = %b, Func Code = %b\r\n",
                                              pRP->Category,
                                              pRP->Function );
#endif
  pRP->rph.Status = STDON + STERR + ERROR_I24_BAD_COMMAND;
  return;
}


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  parFrameControlSet                               */
/*                                                                    */
/* DESCRIPTIVE NAME:  Set the characters per line and lines per inch  */
/*                    worker routine.                                 */
/*                                                                    */
/* FUNCTION:  The function of this routine is to set the characters   */
/*            per line and lines per inch in the printer.             */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  parFrameControlSet                                   */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  parInstance_t   pInst    - ptr to adapter instance         */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: pInst->ReturnCode                                         */
/*                                                                    */
/* INTERNAL REFERENCES:  parDataWrite                                 */
/*                       SetRPErrorCode                               */
/*                                                                    */
/* EXTERNAL REFERENCES:  DevHelp_VerifyAccess                         */
/*                       DevHelp_AllocReqPacket                       */
/*                       DevHelp_FreeReqPacket                        */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
void   parFrameControlSet( parInstance_t *pInst )
{
  parFrameCtrlSetPkt far  *pData;      /* ptr to set frame control parms */
  USHORT                   i;          /* loop control variable */
  UCHAR                    EscSeq[3];  /* escape sequence to send to printer */
  PRPH                     pFCReqPkt;  /* ptr to frame control request packet */
  PRPH                     pReqPkt;    /* ptr to allocated write request packet */
  ULONG                    PhysAddr;   /* physical address */

#ifdef DEBUG
  dprintf( "par1284.sys: parFrameControlSet \r\n" );
#endif
  pData = (parFrameCtrlSetPkt far *) ((PRP_GENIOCTL)pInst->pRP)->DataPacket;

  /*-----------------------------*/
  /* Verify access to parameters */
  /*-----------------------------*/
  if (DevHelp_VerifyAccess(SELECTOROF(pData),
                           sizeof(parFrameCtrlSetPkt),
                           OFFSETOF(pData),
                           VERIFY_READONLY) == 0)
  {
  /*-----------------------------*/
  /* Set the frame control       */
  /*-----------------------------*/
    for (i=0; i < MAXFRAMECOMB; i++)
    {
       if ((pData->CharsPerLine == FrameCtrlComb[i].CharsPerLine ) &&
           (pData->LinesPerInch == FrameCtrlComb[i].LinesPerInch ))
       {
          if (pInst->CurCommMode == PAR_COMPATIBILITY)
          {
            EscSeq[0] = FrameCtrlCmds[i].CharsPerLine;
            EscSeq[1] = ESCAPE;
            EscSeq[2] = FrameCtrlCmds[i].LinesPerInch;

            DevHelp_VirtToPhys ( (PVOID)EscSeq, &PhysAddr );

            if (!DevHelp_AllocReqPacket( WAIT_IS_ALLOWED,
                                         (PBYTE FAR *) &pReqPkt ))
            {
              ((PRP_RWV)pReqPkt)->rph.Cmd = CMDOUTPUT;
              ((PRP_RWV)pReqPkt)->rph.Status = 0;
              ((PRP_RWV)pReqPkt)->XferAddr = PhysAddr;
              ((PRP_RWV)pReqPkt)->NumSectors = FRMCTRLCNT;

              pFCReqPkt = pInst->pRP;  /* temp save frame ctrl req pkt */
              pInst->pRP = pReqPkt;    /* store write req pkt in instance */

              parDataWrite( pInst );   /* send esc sequence */

              pInst->pRP = pFCReqPkt;  /* restore frame ctrl req pkt in inst */

              if (!(((PRP_RWV)pReqPkt)->rph.Status & STERR))
              {
                pInst->CharsPerLine = pData->CharsPerLine;   /* new cps value */
                pInst->LinesPerInch = pData->LinesPerInch;   /* new lpi value */
              }
              else
                pInst->pRP->Status = STDON | STERR | ERROR_I24_WRITE_FAULT;

              DevHelp_FreeReqPacket( (PBYTE)pReqPkt );
              return;
            }
          }
          else
          {
            pInst->ReturnCode = RC_INVALID_PARM;
          }
       }
    } /* endfor */

    pInst->ReturnCode = RC_INVALID_PARM;
  }
  else
  {
    pInst->ReturnCode = RC_INVALID_PARM;
  }
  /*----------------------------------------------*/
  /* Map internal return code to request packet   */
  /* return code (sets the done bit).             */
  /*----------------------------------------------*/
  SetRPErrorCode( pInst );
  return;
}


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  parInfinRetrySet                                 */
/*                                                                    */
/* DESCRIPTIVE NAME:  Set the infinite retry option.                  */
/*                                                                    */
/* FUNCTION:  The function of this routine is to set the infinite     */
/*            retry option.                                           */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  parInfinRetrySet                                     */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  parInstance_t   pInst    - ptr to adapter instance         */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: pInst->ReturnCode                                         */
/*                                                                    */
/* INTERNAL REFERENCES:  SetRPErrorCode                               */
/*                                                                    */
/* EXTERNAL REFERENCES:  DevHelp_VerifyAccess                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
void   parInfinRetrySet( parInstance_t *pInst )
{
  parInfinRetrySetPkt far *pData;   /* ptr to direct mode parms */

#ifdef DEBUG
  dprintf( "par1284.sys: parInfinRetrySet\r\n" );
#endif
  pData = (parInfinRetrySetPkt far *) ((PRP_GENIOCTL)pInst->pRP)->DataPacket;

  /*-----------------------------*/
  /* Verify access to parameters */
  /*-----------------------------*/
  if (DevHelp_VerifyAccess(SELECTOROF(pData),
                           sizeof(parInfinRetrySetPkt),
                           OFFSETOF(pData),
                           VERIFY_READONLY) == 0)
  {
  /*-------------------------------*/
  /* Set the infinite retry option */
  /*-------------------------------*/
    if (pData->InfiniteRetry == ENABLE_IR)
    {
      SetInstanceFlags( pInst, F_INFINITE_RETRY );
    }
    else if (pData->InfiniteRetry == DISABLE_IR)
         {
           ResetInstanceFlags( pInst, F_INFINITE_RETRY );
         }
         else
         {
           pInst->ReturnCode = RC_INVALID_PARM;
         }
  }
  else
  {
    pInst->ReturnCode = RC_INVALID_PARM;
  }
  /*----------------------------------------------*/
  /* Map internal return code to request packet   */
  /* return code (sets the done bit).             */
  /*----------------------------------------------*/
  SetRPErrorCode( pInst );
  return;
}


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  parDeviceReset                                   */
/*                                                                    */
/* DESCRIPTIVE NAME:  Reset the parallel port attached device.        */
/*                                                                    */
/* FUNCTION:  The function of this routine is to reset the parallel   */
/*            port attached device. This routine issues a device      */
/*            reset via a pulse on the nInit line.                    */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  parDeviceReset                                       */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  parInstance_t   pInst    - ptr to adapter instance         */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: pInst->ReturnCode                                         */
/*                                                                    */
/* INTERNAL REFERENCES:  parRequestDirect                             */
/*                       do_reset                                     */
/*                       parBlockThread                               */
/*                       parReleaseDirect                             */
/*                       SetRPErrorCode                               */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
void parDeviceReset( parInstance_t *pInst )
{
  USHORT             rc;            /* return code */

#ifdef DEBUG
  dprintf( "par1284.sys: parDeviceReset\r\n" );
#endif

  /*----------------------------------------------*/
  /* Validate port.                               */
  /*----------------------------------------------*/
  if ( pInst->pIO[0] != 0 )
  {
    /*-----------------------------------------*/
    /* Request exclusive access to hardware.   */
    /*-----------------------------------------*/
    if ( rc = parRequestDirect( pInst ) == 0)
    {
      /*----------------------------------------------*/
      /* Issue device reset.                          */
      /*----------------------------------------------*/
      pInst->State   = RST_INIT;
      pInst->DoneRtn = parRunThread;
      do_reset( pInst );

      /*----------------------------------------------*/
      /* Block thread until request completes.        */
      /*----------------------------------------------*/
      parBlockThread( pInst );

      if ( pInst->ReturnCode == RC_SUCCESS )
        pInst->CurCommMode = PAR_COMPATIBILITY;

      /*----------------------------------------------*/
      /* Release exclusive access to hardware.        */
      /*----------------------------------------------*/
      parReleaseDirect( pInst );
    }
    else
    {
      pInst->ReturnCode = rc;
    }
  }
  else
  {
    pInst->ReturnCode = RC_UNKNOWN_DEVICE;
  }

  SetRPErrorCode( pInst );
  return;
}


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  do_reset                                         */
/*                                                                    */
/* DESCRIPTIVE NAME:  Reset the parallel port attached device.        */
/*                                                                    */
/* FUNCTION:  The function of this routine is to reset the parallel   */
/*            port attached device. This routine issues a device      */
/*            reset via a pulse on the nInit line and then waits for  */
/*            the device to clear the busy line indicating it has     */
/*            recovered.                                              */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  do_reset                                             */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  parInstance_t   pInst    - ptr to adapter instance         */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: pInst->ReturnCode                                         */
/*                                                                    */
/* INTERNAL REFERENCES:  LockInstance                                 */
/*                       UnLockInstance                               */
/*                       IOWrite8                                     */
/*                       TimeExecutionStall                           */
/*                       setDelayTimer                                */
/*                       cancelDelayTimer                             */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
void do_reset( parInstance_t *pInst )
{
  USHORT        fWaitState;

  /*-------------------------------------------------*/
  /* A reentrant call results in pInst->UseCount     */
  /* being incremented with no further action until  */
  /* the original instance completes.                */
  /*-------------------------------------------------*/
  LockInstance( pInst );

  if ( ++pInst->UseCount > 1 )
  {
    UnLockInstance( pInst );
    return;
  }

  do
  {
    fWaitState = 0;

    UnLockInstance( pInst );

    do
    {
      switch ( pInst->State )
      {
        case RST_INIT :

          ResetInstanceFlags( pInst, F_TIMEOUT );
          /*------------------------------------------------*/
          /* If the chipset supports the Extended Control   */
          /* Reg set (Base+0x400) then return the parallel  */
          /* port to PS/2 mode.                             */
          /*------------------------------------------------*/
          if ( pInst->Flags & F_FIFO_SUPPORT )
          {
            pInst->ExtControlReg &= ~EXT_CONTROL_MODE;
            pInst->ExtControlReg |= EXT_CONTROL_MODE1;

            IOWrite8( pInst->pIO[1],
                      EXT_CONTROL_REG,
                      ((UCHAR)(pInst->ExtControlReg ^ EXT_CONTROL_INVERT)));
          }

          /*----------------------------------------------*/
          /* Discard the previous Control Reg setting and */
          /* generate a 100us pulse on INIT to force a    */
          /* printer reset.                               */
          /*----------------------------------------------*/

          pInst->ControlReg = SPP_CONTROL_SELECT | SPP_CONTROL_INIT;

          IOWrite8( pInst->pIO[0],
                    SPP_CONTROL_REG,
                    ((UCHAR)(pInst->ControlReg ^ SPP_CONTROL_INVERT)));

          TimeExecutionStall( 200 );

          pInst->ControlReg &= ~SPP_CONTROL_INIT;

          IOWrite8( pInst->pIO[0],
                    SPP_CONTROL_REG,
                    ((UCHAR)(pInst->ControlReg ^ SPP_CONTROL_INVERT)));

          /*------------------------------------------*/
          /* Set a maximum reset recovery time of 10s */
          /*------------------------------------------*/
          setDelayTimer( pInst,
                         TIMER_ID_2,
                         reset_timedout,
                         (USHORT)MAX_RESET_TIMEOUT_MS );

          /*----------------------------------------------*/
          /* Wait for device to recover by clearing BUSY  */
          /*----------------------------------------------*/
          setDelayTimer( pInst,
                         TIMER_ID_0,
                         do_reset,
                         DELAY1284_TL       );

          fWaitState = 1;
          pInst->State = RST_WAIT_READY;
          break;

        /*---------------------------------------------------*/
        /* This state checks the printer status.             */
        /*                                                   */
        /* If the printer is ready (~Busy) then we allow     */
        /* the reset to complete.                            */
        /*                                                   */
        /* Otherwise, we remain in this state and poll       */
        /* until a timeout occurs or the printer is          */
        /* ready.                                            */
        /*---------------------------------------------------*/
        case RST_WAIT_READY:
          /*-----------------------------------------------*/
          /* Read device status and check if BUSY is clear */
          /*-----------------------------------------------*/
          pInst->StatusReg = IORead8( pInst->pIO[0], SPP_STATUS_REG );

          pInst->StatusReg ^=  SPP_STATUS_INVERT;

          if ( !(pInst->StatusReg & SPP_STATUS_BUSY) )
          {
            pInst->State = RST_COMPLETE;
            break;
          }

          if ( pInst->Flags & F_TIMEOUT )
          {
            pInst->ReturnCode = RC_TIMEOUT;
            pInst->State      = RST_COMPLETE;
            break;
          }

          /*------------------------*/
          /* Reschedule this state  */
          /*------------------------*/
          setDelayTimer( pInst,
                         TIMER_ID_0,
                         do_reset,
                         (USHORT)DELAY_OS_MIN );

          fWaitState = 1;
          break;

        /*---------------------------------------------------*/
        /* The reset either completed successfully or timed  */
        /* out at this point.                                */
        /*---------------------------------------------------*/
        case RST_COMPLETE:

          cancelDelayTimer( pInst, TIMER_ID_2 );
          fWaitState = 1;
          break;
      }
    }
    while ( !fWaitState );

    LockInstance( pInst );
  }
  while ( --pInst->UseCount );

  if ( pInst->State == RST_COMPLETE )
  {
    UnLockInstance( pInst );
    /*----------------------------------------------*/
    /* Async callback to originator of reset.       */
    /*----------------------------------------------*/
    (*pInst->DoneRtn)( pInst );
  }
  else
  {
    UnLockInstance( pInst );
  }
}


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  reset_timedout                                   */
/*                                                                    */
/* DESCRIPTIVE NAME:  Reset timeout routine                           */
/*                                                                    */
/* FUNCTION:  The function of this routine is to set the F_TIMEOUT    */
/*            flag in pInst->Flags to indicate that the maximum       */
/*            reset recovery time has been exceeded.  F_TIMEOUT is    */
/*            detected by do_reset as it polls for the device to      */
/*            become ready.                                           */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: interrupt time                                            */
/*                                                                    */
/* ENTRY POINT:  reset_timedout                                       */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  parInstance_t   pInst    - ptr to adapter instance         */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: pInst->Flags                                              */
/*                                                                    */
/* INTERNAL REFERENCES:  SetInstanceFlags                             */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
void reset_timedout( parInstance_t *pInst )
{
  SetInstanceFlags( pInst, F_TIMEOUT );
}


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  parWriteTimeoutSet                               */
/*                                                                    */
/* DESCRIPTIVE NAME:  Set the write timeout value.                    */
/*                                                                    */
/* FUNCTION:  The function of this routine is to set the write        */
/*            timeout value.                                          */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  parWriteTimeoutSet                                   */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  parInstance_t   pInst    - ptr to adapter instance         */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: pInst->ReturnCode                                         */
/*                                                                    */
/* INTERNAL REFERENCES:  SetRPErrorCode                               */
/*                                                                    */
/* EXTERNAL REFERENCES:  DevHelp_VerifyAccess                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
void   parWriteTimeoutSet( parInstance_t *pInst )
{
  parWriteTimeoutSetPkt far *pData; /* ptr to write timeout parms */

#ifdef DEBUG
  dprintf( "par1284.sys: parWriteTimeoutSet\r\n" );
#endif
  pData = (parWriteTimeoutSetPkt far *) ((PRP_GENIOCTL)pInst->pRP)->DataPacket;

  /*-----------------------------*/
  /* Verify access to parameters */
  /*-----------------------------*/
  if (DevHelp_VerifyAccess(SELECTOROF(pData),
                           sizeof(parWriteTimeoutSetPkt),
                           OFFSETOF(pData),
                           VERIFY_READONLY) == 0)
  {
  /*-----------------------------*/
  /* Set the write timeout value */
  /*-----------------------------*/
    pInst->WTimeoutMS = pData->WriteTimeout * 1000; /* from secs to ms */
  }
  else
  {
    pInst->ReturnCode = RC_INVALID_PARM;
  }
  /*----------------------------------------------*/
  /* Map internal return code to request packet   */
  /* return code (sets the done bit).             */
  /*----------------------------------------------*/
  SetRPErrorCode( pInst );
  return;
}


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  parDirectAccessSet                               */
/*                                                                    */
/* DESCRIPTIVE NAME:  Set the direct access mode.                     */
/*                                                                    */
/* FUNCTION:  The function of this routine is to set the direct       */
/*            hardware access mode.                                   */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  parDirectAccessSet                                   */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  parInstance_t   pInst    - ptr to adapter instance         */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: pInst->ReturnCode                                         */
/*                                                                    */
/* INTERNAL REFERENCES:  SetRPErrorCode                               */
/*                                                                    */
/* EXTERNAL REFERENCES:  DevHelp_VerifyAccess                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
void   parDirectAccessSet( parInstance_t *pInst )
{
  parDirectModeSetPkt far *pData;   /* ptr to direct mode parms */

#ifdef DEBUG
  dprintf( "par1284.sys: parDirectAccessSet\r\n" );
#endif
  pData = (parDirectModeSetPkt far *) ((PRP_GENIOCTL)pInst->pRP)->DataPacket;

  /*-----------------------------*/
  /* Verify access to parameters */
  /*-----------------------------*/
  if (DevHelp_VerifyAccess(SELECTOROF(pData),
                           sizeof(parDirectModeSetPkt),
                           OFFSETOF(pData),
                           VERIFY_READONLY) == 0)
  {
  /*-----------------------------*/
  /* Set the direct access mode  */
  /*-----------------------------*/
    if (pData->DirectAccess == ENABLEDM)
    {
      SetInstanceFlags( pInst, F_SHARE_MODE );
    }
    else if (pData->DirectAccess == DISABLEDM)
         {
           ResetInstanceFlags( pInst, F_SHARE_MODE );
         }
         else
         {
           pInst->ReturnCode = RC_INVALID_PARM;
         }
  }
  else
  {
    pInst->ReturnCode = RC_INVALID_PARM;
  }
  /*----------------------------------------------*/
  /* Map internal return code to request packet   */
  /* return code (sets the done bit).             */
  /*----------------------------------------------*/
  SetRPErrorCode( pInst );
  return;
}


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  parCommModeSet                                   */
/*                                                                    */
/* DESCRIPTIVE NAME:  Set the communication mode.                     */
/*                                                                    */
/* FUNCTION:  The function of this routine is to set the parallel     */
/*            port communication mode. The routine validates the      */
/*            requested CommMode and negotiates the communication     */
/*            mode with the device to insure the device supports the  */
/*            requested CommMode.                                     */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  parCommModeSet                                       */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  parInstance_t   pInst    - ptr to adapter instance         */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: pInst->ReturnCode                                         */
/*                                                                    */
/* INTERNAL REFERENCES:  parRequestDirect                             */
/*                       negotiate_mode                               */
/*                       parReleaseDirect                             */
/*                       SetRPErrorCode                               */
/*                                                                    */
/* EXTERNAL REFERENCES:  DevHelp_VerifyAccess                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
void parCommModeSet( parInstance_t *pInst )
{
  parCommModeSetPkt  far *pData;    /* ptr to communication mode parms */
  USHORT             rc;            /* return code */

#ifdef DEBUG
  dprintf( "par1284.sys: parCommModeSet\r\n" );
#endif

  pData = (parCommModeSetPkt far *) ((PRP_GENIOCTL)pInst->pRP)->DataPacket;

  /*------------------------------*/
  /* Verify access to parameters. */
  /*------------------------------*/
  if (DevHelp_VerifyAccess(SELECTOROF(pData),
                           sizeof(parCommModeSetPkt),
                           OFFSETOF(pData),
                           VERIFY_READONLY) == 0)
  {
    /*----------------------------------------------*/
    /* Validate port.                               */
    /*----------------------------------------------*/
    if ( pInst->pIO[0] != 0 )
    {
      /*-----------------------------------------*/
      /* Validate requested communication mode.  */
      /* If valid, save requested mode.          */
      /*-----------------------------------------*/
      if ( ((UCHAR)pData->CommModes < PAR_MAX_COMM_MODE) ||
           ((UCHAR)pData->CommModes != 0) )
      {
        /*-----------------------------------------*/
        /* Request exclusive access to hardware.   */
        /*-----------------------------------------*/
        if ( rc = parRequestDirect( pInst ) == 0)
        {
          /*-----------------------------------------*/
          /* Negotiate requested communication mode. */
          /*-----------------------------------------*/
          negotiate_mode( pInst, (UCHAR)pData->CommModes );

          /*-----------------------------------------*/
          /* If negotiation completed successfully,  */
          /* save requested communication mode.      */
          /*-----------------------------------------*/
          if ( pInst->pRP->Status == STATUS_DONE )
            pInst->ReqCommMode = (UCHAR)pData->CommModes;

          /*-----------------------------------------*/
          /* Release exclusive access to hardware.   */
          /*-----------------------------------------*/
          parReleaseDirect( pInst );
          return;
        }
        else
          pInst->ReturnCode = rc;
      }
      else
        pInst->ReturnCode = RC_INVALID_MODE;
    }
    else
      pInst->ReturnCode = RC_UNKNOWN_DEVICE;
  }
  else
    pInst->ReturnCode = RC_INVALID_PARM;

  /*----------------------------------------------*/
  /* Map internal return code to request packet   */
  /* return code (sets the done bit).             */
  /*----------------------------------------------*/
  SetRPErrorCode( pInst );
  return;
}


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  parDataXferModeSet                               */
/*                                                                    */
/* DESCRIPTIVE NAME:  Set the data transfer mode.                     */
/*                                                                    */
/* FUNCTION:  The function of this routine is to set the parallel     */
/*            data transfer mode.  The timeout values and logical     */
/*            channel are saved in the adapter instance.              */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  parDataXferModeSet                                   */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  parInstance_t   pInst    - ptr to adapter instance         */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: pInst->ReturnCode                                         */
/*                                                                    */
/* INTERNAL REFERENCES:  SetRPErrorCode                               */
/*                                                                    */
/* EXTERNAL REFERENCES:  DevHelp_VerifyAccess                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
void   parDataXferModeSet( parInstance_t *pInst )
{
  parDataXferModeSetPkt far *pData; /* ptr to data transfer mode parms */

#ifdef DEBUG
  dprintf( "par1284.sys: parDataXferModeSet\r\n" );
#endif

  pData = (parDataXferModeSetPkt far *) ((PRP_GENIOCTL)pInst->pRP)->DataPacket;

  /*-----------------------------*/
  /* Verify access to parameters */
  /*-----------------------------*/
  if (DevHelp_VerifyAccess(SELECTOROF(pData),
                           sizeof(parDataXferModeSetPkt),
                           OFFSETOF(pData),
                           VERIFY_READONLY) == 0)
  {
    /*-------------------------------------------------------------*/
    /* Setup to do the Read/Write data transfer                    */
    /*                                                             */
    /* do_data_xfer will route the request to the appropriate      */
    /* read/write handling routine based on the requested CommMode */
    /*-------------------------------------------------------------*/
    pInst->RIdleTimeoutMS = (USHORT) pData->ReadTimeout.IdleTimeoutValue;
    pInst->RTimeoutMS     = (USHORT) pData->ReadTimeout.TimeoutValue;
    pInst->WIdleTimeoutMS = (USHORT) pData->WriteTimeout.IdleTimeoutValue;
    pInst->WTimeoutMS     = (USHORT) pData->WriteTimeout.TimeoutValue;

    if ( pData->ParChannel == PAR_DATA_CHANNEL )
    {
      ResetInstanceFlags( pInst, F_ADDRESS_CYCLE );
    }
    else if ( pData->ParChannel == PAR_ADDRESS_CHANNEL )
    {
      SetInstanceFlags( pInst, F_ADDRESS_CYCLE );
    }
  }
  else
  {
    pInst->ReturnCode = RC_INVALID_PARM;
  }
  /*----------------------------------------------*/
  /* Map internal return code to request packet   */
  /* return code (sets the done bit).             */
  /*----------------------------------------------*/
  SetRPErrorCode( pInst );
  return;
}


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  parFrameControlQuery                             */
/*                                                                    */
/* DESCRIPTIVE NAME:  Set the characters per line and lines per inch  */
/*                    worker routine.                                 */
/*                                                                    */
/* FUNCTION:  The function of this routine is to set the characters   */
/*            per line and lines per inch in the printer.             */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  parFrameControlQuery                                 */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  parInstance_t   pInst    - ptr to adapter instance         */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: pInst->ReturnCode                                         */
/*                                                                    */
/* INTERNAL REFERENCES:  SetRPErrorCode                               */
/*                                                                    */
/* EXTERNAL REFERENCES:  DevHelp_VerifyAccess                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
void   parFrameControlQuery( parInstance_t *pInst )
{
  parFrameCtrlQryPkt far *pData;    /* ptr to set frame control parms */

#ifdef DEBUG
  dprintf( "par1284.sys: parFrameControlQuery\r\n" );
#endif

  pData = (parFrameCtrlQryPkt far *) ((PRP_GENIOCTL)pInst->pRP)->DataPacket;

  /*-----------------------------*/
  /* Verify access to parameters */
  /*-----------------------------*/
  if (DevHelp_VerifyAccess(SELECTOROF(pData),
                           sizeof(parFrameCtrlQryPkt),
                           OFFSETOF(pData),
                           VERIFY_READWRITE) == 0)
  {
    /*-------------------------------*/
    /* Return frame control settings */
    /*-------------------------------*/
    pData->CharsPerLine = pInst->CharsPerLine;   /* return cps value */
    pData->LinesPerInch = pInst->LinesPerInch;   /* return lpi value */
  }
  else
  {
    pInst->ReturnCode = RC_INVALID_PARM;
  }
  /*----------------------------------------------*/
  /* Map internal return code to request packet   */
  /* return code (sets the done bit).             */
  /*----------------------------------------------*/
  SetRPErrorCode( pInst );
  return;
}


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  parInfinRetryQuery                               */
/*                                                                    */
/* DESCRIPTIVE NAME:  Query the infinite retry option.                */
/*                                                                    */
/* FUNCTION:  The function of this routine is to query the infinite   */
/*            retry option.                                           */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  parInfinRetryQuery                                   */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  parInstance_t   pInst    - ptr to adapter instance         */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: pInst->ReturnCode                                         */
/*                                                                    */
/* INTERNAL REFERENCES:  SetRPErrorCode                               */
/*                                                                    */
/* EXTERNAL REFERENCES:  DevHelp_VerifyAccess                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
void   parInfinRetryQuery( parInstance_t *pInst )
{
  parInfinRetryQryPkt far *pData;   /* ptr to infinite retry parms */

#ifdef DEBUG
  dprintf( "par1284.sys: parInfinRetryQuery\r\n" );
#endif

  pData = (parInfinRetryQryPkt far *) ((PRP_GENIOCTL)pInst->pRP)->DataPacket;

  /*-----------------------------*/
  /* Verify access to parameters */
  /*-----------------------------*/
  if (DevHelp_VerifyAccess(SELECTOROF(pData),
                           sizeof(parInfinRetryQryPkt),
                           OFFSETOF(pData),
                           VERIFY_READWRITE) == 0)
  {
    /*------------------------------*/
    /* Return infinite retry option */
    /*------------------------------*/
    if (pInst->Flags & F_INFINITE_RETRY)
    {
      pData->InfiniteRetry = ENABLE_IR;
    }
    else
    {
      pData->InfiniteRetry = DISABLE_IR;
    }
  }
  else
  {
    pInst->ReturnCode = RC_INVALID_PARM;
  }
  /*----------------------------------------------*/
  /* Map internal return code to request packet   */
  /* return code (sets the done bit).             */
  /*----------------------------------------------*/
  SetRPErrorCode( pInst );
  return;
}


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  parStatusPortQuery                               */
/*                                                                    */
/* DESCRIPTIVE NAME:  Query the parallel port status register.        */
/*                                                                    */
/* FUNCTION:  The function of this routine is to query the parallel   */
/*            port status register.                                   */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  parStatusPortQuery                                   */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  parInstance_t   pInst    - ptr to adapter instance         */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: pInst->ReturnCode                                         */
/*                                                                    */
/* INTERNAL REFERENCES:  parRequestDirect                             */
/*                       parReleaseDirect                             */
/*                       SetRPErrorCode                               */
/*                                                                    */
/* EXTERNAL REFERENCES:  DevHelp_VerifyAccess                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
void   parStatusPortQuery( parInstance_t *pInst )
{
  parStatusPortQryPkt far *pData;   /* ptr to status port query parms */
  USHORT             rc;            /* return code */

#ifdef DEBUG
  dprintf( "par1284.sys: parStatusPortQuery\r\n" );
#endif

  pData = (parStatusPortQryPkt far *) ((PRP_GENIOCTL)pInst->pRP)->DataPacket;

  /*-----------------------------*/
  /* Verify access to parameters */
  /*-----------------------------*/
  if (DevHelp_VerifyAccess(SELECTOROF(pData),
                           sizeof(parStatusPortQryPkt),
                           OFFSETOF(pData),
                           VERIFY_READWRITE) == 0)
  {
    /*----------------------------------------------*/
    /* Validate port.                               */
    /*----------------------------------------------*/
    if ( pInst->pIO[0] != 0 )
    {
      /*-----------------------------------------*/
      /* Request exclusive access to hardware.   */
      /*-----------------------------------------*/
      if ( rc = parRequestDirect( pInst ) == 0)
      {
        /*-----------------------*/
        /* Return device status  */
        /*-----------------------*/
        pData->StatusPort = IORead8( pInst->pIO[0], SPP_STATUS_REG );
        pData->StatusPort &= 0xF8;
        pData->StatusPort ^= ( SPP_STATUS_ACK | SPP_STATUS_FAULT );

        /*-----------------------------------------*/
        /* Release exclusive access to hardware.   */
        /*-----------------------------------------*/
        parReleaseDirect( pInst );
      }
      else
      {
        pInst->ReturnCode = rc;
      }
    }
    else
    {
      pInst->ReturnCode = RC_UNKNOWN_DEVICE;
    }
  }
  else
  {
    pInst->ReturnCode = RC_INVALID_PARM;
  }
  /*----------------------------------------------*/
  /* Map internal return code to request packet   */
  /* return code (sets the done bit).             */
  /*----------------------------------------------*/
  SetRPErrorCode( pInst );
  return;
}


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  parWriteTimeoutQuery                             */
/*                                                                    */
/* DESCRIPTIVE NAME:  Query the write timeout value.                  */
/*                                                                    */
/* FUNCTION:  The function of this routine is to query the write      */
/*            timeout value.                                          */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  parWriteTimeoutQuery                                 */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  parInstance_t   pInst    - ptr to adapter instance         */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: pInst->ReturnCode                                         */
/*                                                                    */
/* INTERNAL REFERENCES:  SetRPErrorCode                               */
/*                                                                    */
/* EXTERNAL REFERENCES:  DevHelp_VerifyAccess                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
void   parWriteTimeoutQuery( parInstance_t *pInst )
{
  parWriteTimeoutQryPkt far *pData; /* ptr to write timeout parms */

#ifdef DEBUG
  dprintf( "par1284.sys: parWriteTimeoutQuery\r\n" );
#endif
  pData = (parWriteTimeoutQryPkt far *) ((PRP_GENIOCTL)pInst->pRP)->DataPacket;

  /*-----------------------------*/
  /* Verify access to parameters */
  /*-----------------------------*/
  if (DevHelp_VerifyAccess(SELECTOROF(pData),
                           sizeof(parWriteTimeoutQryPkt),
                           OFFSETOF(pData),
                           VERIFY_READWRITE) == 0)
  {
  /*-------------------------------*/
  /* Query the write timeout value */
  /*-------------------------------*/
    pData->WriteTimeout = pInst->WTimeoutMS / 1000;   /* from ms to secs */
  }
  else
  {
    pInst->ReturnCode = RC_INVALID_PARM;
  }
  /*----------------------------------------------*/
  /* Map internal return code to request packet   */
  /* return code (sets the done bit).             */
  /*----------------------------------------------*/
  SetRPErrorCode( pInst );
  return;
}


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  parDirectAccessQuery                             */
/*                                                                    */
/* DESCRIPTIVE NAME:  Query the direct access mode.                   */
/*                                                                    */
/* FUNCTION:  The function of this routine is to query the direct     */
/*            hardware access mode.                                   */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  parDirectAccessQuery                                 */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  parInstance_t   pInst    - ptr to adapter instance         */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: pInst->ReturnCode                                         */
/*                                                                    */
/* INTERNAL REFERENCES:  SetRPErrorCode                               */
/*                                                                    */
/* EXTERNAL REFERENCES:  DevHelp_VerifyAccess                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
void   parDirectAccessQuery( parInstance_t *pInst )
{
  parDirectModeQryPkt far *pData;   /* ptr to direct mode parms */

#ifdef DEBUG
  dprintf( "par1284.sys: parDirectAccessQuery\r\n" );
#endif

  pData = (parDirectModeQryPkt far *) ((PRP_GENIOCTL)pInst->pRP)->DataPacket;

  /*-----------------------------*/
  /* Verify access to parameters */
  /*-----------------------------*/
  if (DevHelp_VerifyAccess(SELECTOROF(pData),
                           sizeof(parDirectModeQryPkt),
                           OFFSETOF(pData),
                           VERIFY_READWRITE) == 0)
  {
    /*------------------------------*/
    /* Return direct access mode    */
    /*------------------------------*/
    if (pInst->Flags & F_SHARE_MODE)
    {
      pData->DirectAccess = ENABLEDM;
    }
    else
    {
      pData->DirectAccess = DISABLEDM;
    }
  }
  else
  {
    pInst->ReturnCode = RC_INVALID_PARM;
  }
  /*----------------------------------------------*/
  /* Map internal return code to request packet   */
  /* return code (sets the done bit).             */
  /*----------------------------------------------*/
  SetRPErrorCode( pInst );
  return;
}


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  parCommModeQuery                                 */
/*                                                                    */
/* DESCRIPTIVE NAME:  Query the communication mode.                   */
/*                                                                    */
/* FUNCTION:  The function of this routine is to query the parallel   */
/*            communication mode.                                     */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  parCommModeQuery                                     */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  parInstance_t   pInst    - ptr to adapter instance         */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: pInst->ReturnCode                                         */
/*                                                                    */
/* INTERNAL REFERENCES:  SetRPErrorCode                               */
/*                                                                    */
/* EXTERNAL REFERENCES:  DevHelp_VerifyAccess                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
void   parCommModeQuery( parInstance_t *pInst )
{
  parCommModeQryPkt  far *pData;    /* ptr to communication mode parms */

#ifdef DEBUG
  dprintf( "par1284.sys: parCommModeQuery\r\n" );
#endif

  pData = (parCommModeQryPkt far *) ((PRP_GENIOCTL)pInst->pRP)->DataPacket;

  /*-----------------------------*/
  /* Verify access to parameters */
  /*-----------------------------*/
  if (DevHelp_VerifyAccess(SELECTOROF(pData),
                           sizeof(parCommModeQryPkt),
                           OFFSETOF(pData),
                           VERIFY_READWRITE) == 0)
  {
    /*------------------------------*/
    /* Return communication mode    */
    /*------------------------------*/
    pData->CommModes = pInst->ReqCommMode;
  }
  else
  {
    pInst->ReturnCode = RC_INVALID_PARM;
  }
  /*----------------------------------------------*/
  /* Map internal return code to request packet   */
  /* return code (sets the done bit).             */
  /*----------------------------------------------*/
  SetRPErrorCode( pInst );
  return;
}


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  parDataXferModeQuery                             */
/*                                                                    */
/* DESCRIPTIVE NAME:  Query the data transfer mode.                   */
/*                                                                    */
/* FUNCTION:  The function of this routine is to query the parallel   */
/*            data transfer mode.                                     */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  parDataXferModeQuery                                 */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  parInstance_t   pInst    - ptr to adapter instance         */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: pInst->ReturnCode                                         */
/*                                                                    */
/* INTERNAL REFERENCES:  SetRPErrorCode                               */
/*                                                                    */
/* EXTERNAL REFERENCES:  DevHelp_VerifyAccess                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
void   parDataXferModeQuery( parInstance_t *pInst )
{
  parDataXferModeQryPkt far *pData; /* ptr to data transfer mode parms */

#ifdef DEBUG
  dprintf( "par1284.sys: parDataXferModeQuery\r\n" );
#endif

  pData = (parDataXferModeQryPkt far *) ((PRP_GENIOCTL)pInst->pRP)->DataPacket;

  /*-----------------------------*/
  /* Verify access to parameters */
  /*-----------------------------*/
  if (DevHelp_VerifyAccess(SELECTOROF(pData),
                           sizeof(parDataXferModeQryPkt),
                           OFFSETOF(pData),
                           VERIFY_READWRITE) == 0)
  {
    /*------------------------------*/
    /* Return data transfer mode    */
    /*------------------------------*/
    pData->ReadTimeout.IdleTimeoutValue = pInst->RIdleTimeoutMS;
    pData->ReadTimeout.TimeoutValue = pInst->RTimeoutMS;
    pData->WriteTimeout.IdleTimeoutValue = pInst->WIdleTimeoutMS;
    pData->WriteTimeout.TimeoutValue = pInst->WTimeoutMS;

    if ( pInst->Flags & F_ADDRESS_CYCLE )
    {
      pData->ParChannel = PAR_ADDRESS_CHANNEL;
    }
    else
    {
      pData->ParChannel = PAR_DATA_CHANNEL;
    }
  }
  else
  {
    pInst->ReturnCode = RC_INVALID_PARM;
  }
  /*----------------------------------------------*/
  /* Map internal return code to request packet   */
  /* return code (sets the done bit).             */
  /*----------------------------------------------*/
  SetRPErrorCode( pInst );
  return;
}


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  parDeviceIDQuery                                 */
/*                                                                    */
/* DESCRIPTIVE NAME:  Query the device id.                            */
/*                                                                    */
/* FUNCTION:  The function of this routine is to query the parallel   */
/*            port attached device for its device id.  DeviceID       */
/*            information is obtained by doing a negotiation with     */
/*            a bit set in the extensibility request byte indicating  */
/*            that DeviceID information is to be provided. After the  */
/*            negotiation, a read is done in the negotiated mode to   */
/*            obtain the actual data.                                 */
/*                                                                    */
/*            This routine verifies access to the user buffer,        */
/*            converts the virtual address to the physical address,   */
/*            maps the physical address to a GDT selector, locks the  */
/*            the buffer into memory, stores the requested transfer   */
/*            count (buffer size), and calls a direction-independent  */
/*            routine to perform the data transfer.                   */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  parDeviceIDQuery                                     */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  parInstance_t   pInst    - ptr to adapter instance         */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS:  pInst->GDTSel, pInst->ReqDataCount, pInst->ReturnCode    */
/*                                                                    */
/* INTERNAL REFERENCES:  ResetInstanceFlags                           */
/*                       data_xfer_setup                              */
/*                       SetRPErrorCode                               */
/*                                                                    */
/* EXTERNAL REFERENCES:  DevHelp_VerifyAccess                         */
/*                       DevHelp_Lock                                 */
/*                       DevHelp_VirtToPhys                           */
/*                       DevHelp_PhysToGDTSelector                    */
/*                       DevHelp_UnLock                               */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
void parDeviceIDQuery( parInstance_t *pInst )
{
  PUCHAR                pData;
  USHORT                rc;
  ULONG                 PhysBufAddr;

#ifdef DEBUG
  dprintf( "par1284.sys: parDeviceIDQuery\r\n" );
#endif

  /*------------------------------------------------*/
  /* Setup pointer to user buffer.                  */
  /*------------------------------------------------*/
  pData = ((PRP_GENIOCTL)pInst->pRP)->DataPacket;

  /*-----------------------------*/
  /* Verify access to parameters */
  /*-----------------------------*/
  if (DevHelp_VerifyAccess(SELECTOROF(pData),
                           ((PRP_GENIOCTL)pInst->pRP)->DataLen,
                           OFFSETOF(pData),
                           VERIFY_READWRITE) == 0)
  {
    /*-------------------------------------------------*/
    /* The buffer must be at least three bytes long to */
    /* receive the length prefix and one data byte.    */
    /*-------------------------------------------------*/
    pInst->ReqDataCount = ((PRP_GENIOCTL)pInst->pRP)->DataLen;

    if ( pInst->ReqDataCount >= 3 )
    {
      /*-----------------------------*/
      /* Lock buffer into memory.    */
      /*-----------------------------*/
      if ( (rc = DevHelp_Lock( SELECTOROF(pData),
                               LOCKTYPE_LONG_ANYMEM,
                               WAIT_IS_NOT_INTERRUPTABLE,
                               &pInst->LockHandle )) == 0 )
      {
        /*----------------------------------------------*/
        /* Convert virtual address to physical address. */
        /*----------------------------------------------*/
        if ( (rc = DevHelp_VirtToPhys( pData,
                                       &PhysBufAddr )) == 0 )
        {
          /*----------------------------------------------*/
          /* Map physical address to GDT selector.        */
          /*----------------------------------------------*/
          if ( (rc = DevHelp_PhysToGDTSelector( PhysBufAddr,
                                                pInst->ReqDataCount,
                                                pInst->GDTSel )) == 0 )
          {
            /*----------------------------------------------*/
            /* Set flag for read request.                   */
            /*----------------------------------------------*/
            ResetInstanceFlags( pInst, F_WRITE_REQ );

            /*----------------------------------------------*/
            /* Setup and perform data transfer.             */
            /*----------------------------------------------*/
            data_xfer_setup( pInst );

          }
          else
            pInst->ReturnCode = rc;
        }
        else
          pInst->ReturnCode = rc;
      }
      else
        pInst->ReturnCode = rc;
    }
    else
      pInst->ReturnCode = RC_INVALID_PARM;
  }
  else
    pInst->ReturnCode = RC_INVALID_PARM;

  /*----------------------------------------------*/
  /* Unlock buffer from memory.                   */
  /*----------------------------------------------*/
  if ( pInst->LockHandle )
  {
    DevHelp_UnLock( pInst->LockHandle );
    pInst->LockHandle = 0;
  }

  /*----------------------------------------------*/
  /* Map internal return code to request packet   */
  /* return code (sets the done bit).             */
  /*----------------------------------------------*/
  if ( (pInst->pRP->Status & STATUS_DONE) == 0 )
    SetRPErrorCode( pInst );

  return;
}


