/* SCCSID = "%W% %E%" */
/****************************************************************************/
/*                                                                          */
/*                           IBM Confidential                               */
/*                                                                          */
/*                 Copyright (c) IBM Corporation 1996                       */
/*                           All Rights Reserved                            */
/*                                                                          */
/****************************************************************************/
/************************** START OF SPECIFICATIONS ***************************/
/*                                                                            */
/*   SOURCE FILE NAME:  PARSTR1.C                                             */
/*                                                                            */
/*   DESCRIPTIVE NAME:  PARALLEL port device driver task time routines for    */
/*                      the strategy 1 entry point.                           */
/*                                                                            */
/*   FUNCTION: These routines handle the task time routines for the strategy  */
/*             1 entry point of the parallel port device driver.              */
/*                                                                            */
/*   NOTES:                                                                   */
/*      DEPENDENCIES: None                                                    */
/*      RESTRICTIONS: None                                                    */
/*                                                                            */
/*   ENTRY POINTS:                                                            */
/*             parLPT1                                                        */
/*             parLPT2                                                        */
/*             parLPT3                                                        */
/*             parStrat1                                                      */
/*             parDataRead                                                    */
/*             parDataWrite                                                   */
/*             parReadWrite                                                   */
/*             data_xfer_setup                                                */
/*             do_data_xfer                                                   */
/*             parDataReadFlush                                               */
/*             parDataWriteFlush                                              */
/*             parDataFlush                                                   */
/*             parDataFlushQueued                                             */
/*             parDataFlushActive                                             */
/*             parDeviceOpen                                                  */
/*             parDeviceClose                                                 */
/*             parCmdError                                                    */
/*                                                                            */
/*   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:  parLPT1                                          */
/*                                                                    */
/* DESCRIPTIVE NAME:  Strategy 1 entry point for the PRN and LPT1     */
/*                    devices.                                        */
/*                                                                    */
/* FUNCTION:  The function of this routine is pass the LPT1 kernel    */
/*            request packet and the LPT1 adapter instance to         */
/*            parStrat1 for processing.                               */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  parLPT1                                              */
/*    LINKAGE:  CALL FAR                                              */
/*                                                                    */
/* INPUT:  es:bx -> kernel request packet                             */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: None                                                      */
/*                                                                    */
/* INTERNAL REFERENCES:  parStrat1                                    */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
void far parLPT1()
{
  RPH        far  *pRP;

  _asm
  {
     mov word ptr pRP[0], bx
     mov word ptr pRP[2], es
  }

  parStrat1( LPTInfo[0].pInst, pRP );

}


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  parLPT2                                          */
/*                                                                    */
/* DESCRIPTIVE NAME:  Strategy 1 entry point for the LPT2 device.     */
/*                                                                    */
/* FUNCTION:  The function of this routine is pass the LPT2 kernel    */
/*            request packet and the LPT2 adapter instance to         */
/*            parStrat1 for processing.                               */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  parLPT2                                              */
/*    LINKAGE:  CALL FAR                                              */
/*                                                                    */
/* INPUT:  es:bx -> kernel request packet                             */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: None                                                      */
/*                                                                    */
/* INTERNAL REFERENCES:  parStrat1                                    */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
void far parLPT2()
{
  RPH        far  *pRP;

  _asm
  {
     mov word ptr pRP[0], bx
     mov word ptr pRP[2], es
  }

  parStrat1( LPTInfo[1].pInst, pRP );

}


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  parLPT3                                          */
/*                                                                    */
/* DESCRIPTIVE NAME:  Strategy 1 entry point for the LPT3 device.     */
/*                                                                    */
/* FUNCTION:  The function of this routine is pass the LPT3 kernel    */
/*            request packet and the LPT3 adapter instance to         */
/*            parStrat1 for processing.                               */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  parLPT3                                              */
/*    LINKAGE:  CALL FAR                                              */
/*                                                                    */
/* INPUT:  es:bx -> kernel request packet                             */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: None                                                      */
/*                                                                    */
/* INTERNAL REFERENCES:  parStrat1                                    */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
void far parLPT3()
{
  RPH        far  *pRP;

  _asm
  {
     mov word ptr pRP[0], bx
     mov word ptr pRP[2], es
  }

  parStrat1( LPTInfo[2].pInst, pRP );

}


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  parStrat1                                        */
/*                                                                    */
/* DESCRIPTIVE NAME:  Common strategy 1 entry point                   */
/*                                                                    */
/* FUNCTION:  The function of this routine is to dispatch the         */
/*            appropriate strategy 1 worker routine based upon the    */
/*            command in the kernel request packet.                   */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  parStrat1                                            */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  pInst-> adapter instance                                   */
/*         pRP-> kernel request packet                                */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: pRP->Status = STDON + STERR + ERROR_I24_BAD_COMMAND       */
/*                                                                    */
/* INTERNAL REFERENCES:  see Strat1 table                             */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
void near parStrat1( parInstance_t *pInst, RPH FAR *pRP )
{
  USHORT       Cmd;

  Cmd = pRP->Cmd;
#ifdef DEBUG
    dprintf( "parStrat1: Entry: pRP = %p\r\n", pRP );
#endif

  if (Cmd > MAX_PARALLEL_CMD)
  {
    pRP->Status = STDON + STERR + ERROR_I24_BAD_COMMAND;
  }
  else
  {
    /*---------------------*/
    /* Call Worker Routine */
    /*---------------------*/
    (*Strat1[Cmd])(pInst, pRP);
  }
#ifdef DEBUG
    dprintf( "parStrat1: Exit: pRP = %p\r\n", pRP );
#endif

}


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  parDataRead                                      */
/*                                                                    */
/* DESCRIPTIVE NAME:  Read data from the parallel port attached       */
/*                    device.                                         */
/*                                                                    */
/* FUNCTION:  The function of this routine is to read data from the   */
/*            parallel port attached device.  This function calls a   */
/*            common read/write handler.                              */
/*                                                                    */
/* NOTES:  Turning off the F_WRITE_REQ flag indicates a read request. */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  parDataRead                                          */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  pInst-> adapter instance                                   */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: pInst->Flags                                              */
/*                                                                    */
/* INTERNAL REFERENCES:  ResetInstanceFlags                           */
/*                       parReadWrite                                 */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
void   parDataRead( parInstance_t *pInst )
{
#ifdef DEBUG
  dprintf( "par1284.sys: parDataRead\r\n");
#endif

  ResetInstanceFlags( pInst, F_WRITE_REQ );
  parReadWrite( pInst );

  /*------------------------------*/
  /* Statistics                   */
  /*------------------------------*/
  pInst->nReads++;
  if ( pInst->pRP->Status & STERR )
    pInst->nErrorReads++;

  if (pInst->DataCount == 0)
    pInst->nZeroReads++;
}


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  parDataWrite                                     */
/*                                                                    */
/* DESCRIPTIVE NAME:  Write data to the parallel port attached        */
/*                    device.                                         */
/*                                                                    */
/* FUNCTION:  The function of this routine is to write data to the    */
/*            parallel port attached device.  This function calls a   */
/*            common read/write handler.                              */
/*                                                                    */
/* NOTES:  Turning on the F_WRITE_REQ flag indicates a write request. */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  parDataRead                                          */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  pInst-> adapter instance                                   */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: pInst->Flags                                              */
/*                                                                    */
/* INTERNAL REFERENCES:  SetInstanceFlags                             */
/*                       parReadWrite                                 */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
void   parDataWrite( parInstance_t *pInst )
{
#ifdef DEBUG
  dprintf( "par1284.sys: parDataWrite\r\n");
#endif

  SetInstanceFlags( pInst, F_WRITE_REQ );
  parReadWrite( pInst );

  /*------------------------------*/
  /* Statistics                   */
  /*------------------------------*/
  pInst->nWrites++;
  if ( pInst->pRP->Status & STERR )
    pInst->nErrorWrites++;
}


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  parReadWrite                                     */
/*                                                                    */
/* DESCRIPTIVE NAME:  Common read and write routine.                  */
/*                                                                    */
/* FUNCTION:  The function of this routine is to map the physical     */
/*            address of the user buffer to a GDT selector, to store  */
/*            the requested transfer count and call a direction-      */
/*            independent routine to perform the data transfer.       */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  parReadWrite                                         */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  pInst-> adapter instance                                   */
/*                                                                    */
/* EXIT-NORMAL: pRP->NumSectors                                       */
/*                                                                    */
/* EXIT-ERROR:  pRP->NumSectors                                       */
/*                                                                    */
/* EFFECTS:  pInst->GDTSel, pInst->ReqDataCount                       */
/*                                                                    */
/* INTERNAL REFERENCES:  data_xfer_setup                              */
/*                       SetRPErrorCode                               */
/*                                                                    */
/* EXTERNAL REFERENCES:  DevHelp_PhysToGDTSelector                    */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
void   parReadWrite( parInstance_t *pInst )
{
  USHORT       rc;

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

  /*----------------------------------------------*/
  /* Init transfered count. Get transfer count.   */
  /*----------------------------------------------*/
  pInst->DataCount = 0;
  pInst->ReqDataCount  = ((PRP_RWV)pInst->pRP)->NumSectors;
  ((PRP_RWV)pInst->pRP)->NumSectors = 0;

  /*----------------------------------------------*/
  /* Map physical address to GDT selector.        */
  /*----------------------------------------------*/
  if ( rc = DevHelp_PhysToGDTSelector( (ULONG) ((PRP_RWV)pInst->pRP)->XferAddr,
                                       (USHORT)  pInst->ReqDataCount,
                                       (SEL)     pInst->GDTSel ) == 0 )
  {
    /*----------------------------------------------*/
    /* Setup and perform data transfer.             */
    /*----------------------------------------------*/
    data_xfer_setup( pInst );

    /*----------------------------------------------*/
    /* Return transfer count.                       */
    /*----------------------------------------------*/
    if ( pInst->pRP->Status & STDON )
      ((PRP_RWV)pInst->pRP)->NumSectors = pInst->DataCount;
  }
  else
    pInst->ReturnCode = rc;

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

  return;
}


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  data_xfer_setup                                  */
/*                                                                    */
/* DESCRIPTIVE NAME:  Setup for the data transfer                     */
/*                                                                    */
/* FUNCTION:  The function of this routine is to perform the required */
/*            setup for the data transfer.  The steps include:        */
/*                                                                    */
/*            (1) validating the port exists,                         */
/*            (2) making a pointer to the return buffer,              */
/*            (3) requesting exclusive access to the parallel port,   */
/*            (4) registering the hardware interrupt routine,         */
/*            (5) negotiating the IEEE 1284 transfer mode,            */
/*            (6) calling do_data_xfer to transfer the data,          */
/*            (7) deregistering the hardware interrupt routine,       */
/*            (8) releasing exclusive access to the parallel port.    */
/*                                                                    */
/* NOTES: This routine assumes that the following fields are setup    */
/*        prior to calling this routine:                              */
/*                                                                    */
/*        pInst->GDTSel, pInst->ReqDataCount                          */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  data_xfer_setup                                      */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  parInstance_t   pInst    - ptr to adapter instance         */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: pInst->pDataBuf, pInst->DoneRtn, pInst->ReturnCode        */
/*                                                                    */
/* INTERNAL REFERENCES:  parRequestDirect                             */
/*                       negotiate_mode                               */
/*                       do_data_xfer                                 */
/*                       parBlockThread                               */
/*                       parReleaseDirect                             */
/*                       SetRPErrorCode                               */
/*                                                                    */
/* EXTERNAL REFERENCES:  DevHelp_SetIRQ                               */
/*                       DevHelp_UnSetIRQ                             */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
void data_xfer_setup( parInstance_t *pInst )
{
  USHORT       rc;
  USHORT       i = pInst->IRQINFOIndex;

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

  /*----------------------------------------------*/
  /* Validate port.                               */
  /*----------------------------------------------*/
  if ( pInst->pIO[0] != 0 )
  {
    /*----------------------------------------------*/
    /* Map GDT selector to 16:16 pointer.           */
    /*----------------------------------------------*/
    pInst->pDataBuf = MAKEP(pInst->GDTSel, 0);

    /*----------------------------------------------*/
    /* Request exclusive access to hardware.        */
    /*----------------------------------------------*/
    if ( rc = parRequestDirect( pInst ) == 0 )
    {
      /*-----------------------------------------*/
      /* Register ISR with interrupt manager.    */
      /*-----------------------------------------*/
      if (IRQInfo[i].IRQLevel != 0)     /* if have IRQ level */
      {
        if ( DevHelp_SetIRQ(IRQInfo[i].isrRtn,
                            IRQInfo[i].IRQLevel,
                            IRQInfo[i].Flags) != 0 )
          SetInstanceFlags(pInst, F_NO_INTERRUPT);
      }

      /*----------------------------------------------*/
      /* Negotiate into requested communication mode. */
      /*----------------------------------------------*/
      negotiate_mode( pInst, pInst->ReqCommMode );

      if ( pInst->pRP->Status == STATUS_DONE )
      {
        /*----------------------------------------------*/
        /* Reset status fields.                         */
        /*----------------------------------------------*/
        pInst->pRP->Status = 0;
        pInst->ReturnCode = 0;

        /*----------------------------------------------*/
        /* Perform data transfer.                       */
        /*----------------------------------------------*/
        pInst->DoneRtn = parRunThread;
        do_data_xfer( pInst );

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

        /*----------------------------------------------*/
        /* The IEEE-1284 spec requires a return to      */
        /* compatibility mode after obtaining the       */
        /* device id.                                   */
        /*----------------------------------------------*/
        if ( pInst->pRP->Cmd == CMDGenIOCTL )
          negotiate_mode( pInst, PAR_COMPATIBILITY );

      }

      /*-----------------------------------------*/
      /* Deregister ISR with interrupt manager.  */
      /*-----------------------------------------*/
      if ((!(pInst->Flags & F_NO_INTERRUPT)) && (IRQInfo[i].IRQLevel != 0))
      {
        DevHelp_UnSetIRQ(IRQInfo[i].IRQLevel);
        ResetInstanceFlags(pInst, F_NO_INTERRUPT);
      }

      /*----------------------------------------------*/
      /* Release exclusive access to hardware.        */
      /*----------------------------------------------*/
      parReleaseDirect( pInst );

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

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

  return;
}


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  do_data_xfer                                     */
/*                                                                    */
/* DESCRIPTIVE NAME:  Dispatches appropriate communication mode worker*/
/*                                                                    */
/* FUNCTION:  The function of this routine is to dispatch the read    */
/*            or write request to the appropriate worker routine      */
/*            based upon the data transfer direction and current      */
/*            communication mode.                                     */
/*                                                                    */
/* NOTES:  This routine also sets the correct initial state for the   */
/*         worker routine.                                            */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  do_data_xfer                                         */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  pInst-> adapter instance                                   */
/*                                                                    */
/* EXIT-NORMAL: RC_SUCCESS                                            */
/*                                                                    */
/* EXIT-ERROR:  RC_INVALID_MODE                                       */
/*                                                                    */
/* EFFECTS: None                                                      */
/*                                                                    */
/* INTERNAL REFERENCES:  do_write_fpp_mode                            */
/*                       do_write_spp_mode                            */
/*                       do_write_ecp_mode                            */
/*                       do_write_epp_mode                            */
/*                       do_read_byte_mode                            */
/*                       do_read_ecp_mode                             */
/*                       do_read_epp_mode                             */
/*                       SetInstanceFlags                             */
/*                       ResetInstanceFlags                           */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
USHORT do_data_xfer( parInstance_t *pInst )
{
  USHORT       rc = RC_SUCCESS;

  if ( pInst->Flags & F_WRITE_REQ )
  {
    /*------------------------------------------------*/
    /* Route write requests based on current CommMode */
    /*------------------------------------------------*/
    switch ( pInst->CurCommMode )
    {
      case PAR_COMPATIBILITY:
      case PAR_NIBBLE:
      case PAR_BYTE:
        if ( pInst->Flags & F_FIFO_SUPPORT )
        {
          pInst->State = WFPP_INIT;
          do_write_fpp_mode( pInst );
        }
        else
        {
          pInst->State = WSPP_INIT;
          do_write_spp_mode( pInst );
        }
        break;

      case PAR_ECP_WITHOUT_RLE:
        ResetInstanceFlags( pInst, F_RLE_COMPRESS );
        pInst->State = WECP_INIT;
        do_write_ecp_mode( pInst );
        break;

      case PAR_ECP_WITH_RLE:
        SetInstanceFlags( pInst, F_RLE_COMPRESS );
        pInst->State = WECP_INIT;
        do_write_ecp_mode( pInst );
        break;

      case PAR_EPP:
        pInst->State = WEPP_INIT;
        do_write_epp_mode( pInst );
        break;

      default:
#ifdef DEBUG
  dprintf( "par1284.sys: do_data_xfer - invalid communication mode\r\n" );
#endif
        pInst->ReturnCode = rc = RC_INVALID_MODE;
        break;
    }
  }
  else
  {
    /*------------------------------------------------*/
    /* Route read requests based on current CommMode  */
    /*------------------------------------------------*/
    switch ( pInst->CurCommMode )
    {
      case PAR_NIBBLE:
        ResetInstanceFlags( pInst, F_BYTE_MODE );
        pInst->State = RNS_INITIAL;
        do_read_byte_mode( pInst );
        break;

      case PAR_BYTE:
        SetInstanceFlags( pInst, F_BYTE_MODE );
        pInst->State = RNS_INITIAL;
        do_read_byte_mode( pInst );
        break;

      case PAR_ECP_WITH_RLE:
      case PAR_ECP_WITHOUT_RLE:
        pInst->State = RECP_INIT;
        do_read_ecp_mode( pInst );
        break;

      case PAR_EPP:
        pInst->State = REPP_INIT;
        do_read_epp_mode( pInst );
        break;

      default:
#ifdef DEBUG
  dprintf( "par1284.sys: do_data_xfer - invalid communication mode\r\n" );
#endif
        pInst->ReturnCode = rc = RC_INVALID_MODE;
        break;
    }
  }

  return( rc );
}


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  parDataReadFlush                                 */
/*                                                                    */
/* DESCRIPTIVE NAME:  Flush a read data request                       */
/*                                                                    */
/* FUNCTION:  The function of this routine is to flush a read data    */
/*            request.  This function calls a common flush handler.   */
/*                                                                    */
/* NOTES: This is an immediate command that is not put on the FIFO    */
/*        queue.  This command does not complete until the flushed    */
/*        request completes.                                          */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  parDataReadFlush                                     */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  pInst-> adapter instance                                   */
/*         pRP-> kernel request packet                                */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: None                                                      */
/*                                                                    */
/* INTERNAL REFERENCES:  parDataFlush                                 */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
void parDataReadFlush( parInstance_t *pInst, RPH FAR *pRP)
{
#ifdef DEBUG
  dprintf( "par1284.sys: parDataReadFlush\r\n" );
#endif

  pInst->pFlushRP  = pRP;                    /* save flush req pkt */

  parDataFlush( (parInstance_t *) pInst,
                (USHORT)          CMDINPUT,
                (USHORT)          STR_FLUSH_ALL);

}


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  parDataWriteFlush                                */
/*                                                                    */
/* DESCRIPTIVE NAME:  Flush a write data request                      */
/*                                                                    */
/* FUNCTION:  The function of this routine is to flush a write data   */
/*            request.  This function calls a common flush handler.   */
/*                                                                    */
/* NOTES: This is an immediate command that is not put on the FIFO    */
/*        queue.  This command does not complete until the flushed    */
/*        request completes.                                          */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  parDataWriteFlush                                    */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  pInst-> adapter instance                                   */
/*         pRP-> kernel request packet                                */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: None                                                      */
/*                                                                    */
/* INTERNAL REFERENCES:  parDataFlush                                 */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
void parDataWriteFlush( parInstance_t *pInst, RPH FAR *pRP)
{
#ifdef DEBUG
  dprintf( "par1284.sys: parDataWriteFlush\r\n" );
#endif

  pInst->pFlushRP  = pRP;                    /* save flush req pkt */

  parDataFlush( (parInstance_t *) pInst,
                (USHORT)          CMDOUTPUT,
                (USHORT)          STR_FLUSH_ALL);

}

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  parDataFlush                                     */
/*                                                                    */
/* DESCRIPTIVE NAME:  Flush a read or write data request              */
/*                                                                    */
/* FUNCTION:  The function of this routine is to flush a read or      */
/*            write data request.                                     */
/*                                                                    */
/* NOTES: This is an immediate command that is not put on the FIFO    */
/*        queue.  This command does not complete until the flushed    */
/*        request completes. The ECP temporary buffer is also flushed.*/
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  parDataFlush                                         */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  pInst                 - ptr to adapter instance            */
/*         functionNumber        - command of request packet to cancel*/
/*                                 - CMDINPUT (read request)          */
/*                                 - CMDOUTPUT (write request)        */
/*         flushOpt              - flush option                       */
/*                                 - STR_FLUSH_ALL                    */
/*                                 - STR_FLUSH_ACTIVE_REQUEST         */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  STDON + STERR + ERROR_I24_BAD_COMMAND                 */
/*                                                                    */
/* EFFECTS: None                                                      */
/*                                                                    */
/* INTERNAL REFERENCES:  None                                         */
/*                                                                    */
/* EXTERNAL REFERENCES:  parDataFlushQueued                           */
/*                       parDataFlushActive                           */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
void parDataFlush( parInstance_t *pInst,
                   USHORT        functionNumber,
                   USHORT        flushOpt )
{
#ifdef DEBUG
  dprintf( "par1284.sys: parDataFlush\r\n" );
#endif

  if (( flushOpt != STR_FLUSH_ALL ) &&    /* if invalid parameter */
      ( flushOpt != STR_FLUSH_ACTIVE_REQUEST ))
  {
    pInst->pFlushRP->Status = STDON + STERR + ERROR_I24_BAD_COMMAND;
    return;
  }

  if ( flushOpt == STR_FLUSH_ALL )
  {
    parDataFlushQueued( pInst, functionNumber );
    parDataFlushActive( pInst, functionNumber );
  }
  else                   /* flushOpt == STR_FLUSH_ACTIVE_REQUEST */
  {
    parDataFlushActive( pInst, functionNumber );
  }
  pInst->pLastRead->usCharCount = 0;  /* clear temporary ecp buffer */
}


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  parDataFlushQueued                               */
/*                                                                    */
/* DESCRIPTIVE NAME:  Flush all queued read or write data requests    */
/*                                                                    */
/* FUNCTION:  The function of this routine is to flush all read or    */
/*            write data requests.                                    */
/*                                                                    */
/* NOTES: This is an immediate command that is not put on the FIFO    */
/*        queue.  This command does not complete until the flushed    */
/*        request completes.                                          */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  parDataFlushQueued                                   */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  pInst                 - ptr to adapter instance            */
/*         functionNumber        - command of request packet to cancel*/
/*                                 - CMDINPUT (read request)          */
/*                                 - CMDOUTPUT (write request)        */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: None                                                      */
/*                                                                    */
/* INTERNAL REFERENCES:  LockInstance                                 */
/*                       UnLockInstance                               */
/*                                                                    */
/* EXTERNAL REFERENCES:  DevHelp_DevDone                              */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
void parDataFlushQueued( parInstance_t *pInst, USHORT functionNumber)
{
  RPH          FAR *pRP;
  RPH          FAR *pRPPrev;

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

  LockInstance( pInst );

  pRP     = pInst->pRPHead;
  pRPPrev = 0;

  /*-------------------------------*/
  /* For each RP on ADD Work Queue */
  /*-------------------------------*/
  while ( pRP )
  {
    /*-------------------------------------------------------------*/
    /* Check if RP functionNumber matches function to be flushed.  */
    /*-------------------------------------------------------------*/
    if ( pRP->Cmd == (UCHAR)functionNumber )
    {
      /*----------------------------------------------------------------*/
      /* If there was a previous RP (must be in middle/end of linked    */
      /* list), then remove flushed RP and update previous pointer to   */
      /* point to the next RP in linked list.  If the previous pointer  */
      /* now points to zero (no more entries in the linked list), then  */
      /* set Work Queue foot pointer to new end of linked list.         */
      /*----------------------------------------------------------------*/
      if ( pRPPrev )
      {
        pRPPrev->Link = pRP->Link;           /* remove pRP from middle/end */
        if ( pRPPrev->Link == 0 )
        {
          pInst->pRPFoot = pRPPrev;
        }
      }
      /*---------------------------------------------------------------*/
      /* If there was no previous RP (must be at head of linked list), */
      /* then remove flushed RP and update Work Queue head pointer to  */
      /* point to the next RP in linked list.  If the Work Queue head  */
      /* pointer now points to zero (no more entries in the linked     */
      /* list), then set Work Queue head and foot pointers to zero.    */
      /*---------------------------------------------------------------*/
      else
      {
        pInst->pRPHead = pRP->Link;          /* remove pRP from head */
        if ( pInst->pRPHead == 0 )
        {
          pInst->pRPFoot = pInst->pRPHead = 0;
        }
      }
      /*---------------------------------------------------------------*/
      /* pRP points to RP removed from the linked list.  Call devdone  */
      /* to mark the RP as done and wake the users thread to return    */
      /* request/thread to the user task.  The read/write RP returns   */
      /* with zero bytes read/written.                                 */
      /*---------------------------------------------------------------*/
      ((PRP_RWV)pRP)->NumSectors = 0;
      DevHelp_DevDone( (PBYTE)pRP );
    }

    pRPPrev = pRP;
    pRP = pRP->Link;
  }

  UnLockInstance( pInst );
}


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  parDataFlushActive                               */
/*                                                                    */
/* DESCRIPTIVE NAME:  Flush active read or write data request         */
/*                                                                    */
/* FUNCTION:  The function of this routine is to flush the active     */
/*            read or write data request.                             */
/*                                                                    */
/* NOTES: This is an immediate command that is not put on the FIFO    */
/*        queue.  This command does not complete until the flushed    */
/*        request completes.                                          */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  parDataFlushActive                                   */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  pInst                 - ptr to adapter instance            */
/*         functionNumber        - command of request packet to cancel*/
/*                                 - CMDINPUT (read request)          */
/*                                 - CMDOUTPUT (write request)        */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: None                                                      */
/*                                                                    */
/* INTERNAL REFERENCES:  LockInstance                                 */
/*                       UnLockInstance                               */
/*                       SetInstanceFlags                             */
/*                       ResetInstanceFlags                           */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
void parDataFlushActive( parInstance_t *pInst, USHORT functionNumber)
{
  RPH          FAR *pRP;

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

  LockInstance( pInst );

  /*----------------------*/
  /* Flush active request */
  /*----------------------*/
  if ( (pRP = pInst->pRP) &&
       (pRP->Cmd == (UCHAR)functionNumber) )
  {
    cancelAllTimers( pInst );
    SetInstanceFlags( pInst, F_CANCELLED );

    /*-----------------------------------------------------*/
    /* If the current request was waiting on an interrupt, */
    /* then simulate an interrupt to get it going again    */
    /*-----------------------------------------------------*/
    if ( pInst->Flags & F_INTERRUPT_EXPECTED )
    {
      ResetInstanceFlags( pInst, F_INTERRUPT_EXPECTED );
      (pInst->IRQRtn)( pInst );
    }
  }
  else
  {
    pInst->pFlushRP->Status = STATUS_DONE;
    pInst->pFlushRP = 0;
  }

  UnLockInstance( pInst );
}


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  parDeviceOpen                                    */
/*                                                                    */
/* DESCRIPTIVE NAME:  Open the parallel port attached device          */
/*                                                                    */
/* FUNCTION:  The function of this routine is to open the parallel    */
/*            port attached device.                                   */
/*                                                                    */
/* NOTES: This is an immediate command that is not put on the FIFO    */
/*        queue.                                                      */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  parDeviceOpen                                        */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  pInst-> adapter instance                                   */
/*         pRP-> kernel request packet                                */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: pRP->Status = STATUS_DONE                                 */
/*                                                                    */
/* INTERNAL REFERENCES:  None                                         */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
void parDeviceOpen( parInstance_t *pInst, RPH FAR *pRP)
{
#ifdef DEBUG
  dprintf( "par1284.sys: parDeviceOpen\r\n" );
#endif

  pRP->Status = STATUS_DONE;
  return;
}


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  parDeviceClose                                   */
/*                                                                    */
/* DESCRIPTIVE NAME:  Close the parallel port attached device         */
/*                                                                    */
/* FUNCTION:  The function of this routine is to close the parallel   */
/*            port attached device.                                   */
/*                                                                    */
/* NOTES: This is an immediate command that is not put on the FIFO    */
/*        queue. The ECP temporary buffer is flushed.                 */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  parDeviceClose                                       */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  pInst-> adapter instance                                   */
/*         pRP-> kernel request packet                                */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: pRP->Status = STATUS_DONE                                 */
/*                                                                    */
/* INTERNAL REFERENCES:  None                                         */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
void parDeviceClose( parInstance_t *pInst, RPH FAR *pRP)
{
#ifdef DEBUG
  dprintf( "par1284.sys: parDeviceClose\r\n" );
#endif

  pInst->pLastRead->usCharCount = 0;  /* clear temporary ecp buffer */
  pRP->Status = STATUS_DONE;
  return;
}


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  CmdError                                         */
/*                                                                    */
/* DESCRIPTIVE NAME:  Command not supported in the device driver      */
/*                                                                    */
/* FUNCTION:  The function of this routine is to return command not   */
/*            supported for the request.                              */
/*                                                                    */
/* NOTES: This is an immediate command that is not put on the FIFO    */
/*        queue.                                                      */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  CmdError                                             */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  pInst-> adapter instance                                   */
/*         pRP-> kernel request packet                                */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: pRP->Status = STDON + STERR + ERROR_I24_BAD_COMMAND       */
/*                                                                    */
/* INTERNAL REFERENCES:  None                                         */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
void CmdError( parInstance_t *pInst, RPH FAR *pRP)
{
#ifdef DEBUG
  dprintf( "par1284.sys: CmdError - Strategy Command = %b\r\n", pRP->Cmd );
#endif

  pRP->Status = STDON + STERR + ERROR_I24_BAD_COMMAND;
  return;
}


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  parInitComplete                                  */
/*                                                                    */
/* DESCRIPTIVE NAME:  Initialization complete                         */
/*                                                                    */
/* FUNCTION:  The function of this routine is to clear the global     */
/*            initialization time flag.                               */
/*                                                                    */
/* NOTES: This is an immediate command that is not put on the FIFO    */
/*        queue.                                                      */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  parInitComplete                                      */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  pInst-> adapter instance                                   */
/*         pRP-> kernel request packet                                */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: pRP->Status = STATUS_DONE, fInitTime                      */
/*                                                                    */
/* INTERNAL REFERENCES:  None                                         */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
void parInitComplete( parInstance_t *pInst, RPH FAR *pRP)
{
#ifdef DEBUG
  dprintf( "par1284.sys: parInitComplete\r\n" );
#endif

  fInitTime = FALSE;
  pRP->Status = STATUS_DONE;
  return;
}


