/* SCCSID = "%W% %E%" */
/****************************************************************************/
/*                                                                          */
/*                           IBM Confidential                               */
/*                                                                          */
/*                 Copyright (c) IBM Corporation 1996                       */
/*                           All Rights Reserved                            */
/*                                                                          */
/****************************************************************************/
/************************** START OF SPECIFICATIONS ***************************/
/*                                                                            */
/*   SOURCE FILE NAME:  PARFPP.C                                              */
/*                                                                            */
/*   DESCRIPTIVE NAME:  PARALLEL port device driver FPP routines.             */
/*                                                                            */
/*   FUNCTION: These routines handle the write functions when the             */
/*             ECP parallel port chip is set to FIFO mode.                    */
/*                                                                            */
/*   NOTES:                                                                   */
/*                                                                            */
/*      DEPENDENCIES: None                                                    */
/*      RESTRICTIONS: None                                                    */
/*                                                                            */
/*   ENTRY POINTS:                                                            */
/*             do_write_fpp_mode                                              */
/*             service_fpp_write                                              */
/*             fpp_write_timeout                                              */
/*                                                                            */
/*   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:  do_write_fpp_mode                                */
/*                                                                    */
/* DESCRIPTIVE NAME:  Write data in FIFO mode to the device.          */
/*                                                                    */
/* FUNCTION:  The function of this routine is to write data in        */
/*            FIFO mode to the device.  The ECP chip provides         */
/*            outbound data buffering in the FIFO and generates the   */
/*            STROBE pulse timings.                                   */
/*                                                                    */
/* NOTES:  The decision whether to use this routine or the standard   */
/*         parallel port write is controlled by the setting of        */
/*         F_FIFO_SUPPORT.                                            */
/*                                                                    */
/* CONTEXT: task or interrupt time                                    */
/*                                                                    */
/* ENTRY POINT:  do_write_fpp_mode                                    */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  parInstance_t   pInst    - ptr to adapter instance         */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: pInst->StatusReg, pInst->ControlReg, pInst->ExtControlReg */
/*          pInst->ReturnCode, pInst->State, pInst->IRQRtn            */
/*                                                                    */
/* INTERNAL REFERENCES:  LockInstance                                 */
/*                       UnLockInstance                               */
/*                       SetInstanceFlags                             */
/*                       ResetInstanceFlags                           */
/*                       IORead8                                      */
/*                       IOWrite8                                     */
/*                       TimeExecutionStall                           */
/*                       SetDelayTimer                                */
/*                       service_fpp_write                            */
/*                       cancelAllTimers                              */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
void do_write_fpp_mode( parInstance_t *pInst )
{
  USHORT                fWaitState;
  USHORT                n;


  LockInstance( pInst );

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

  do
  {
    fWaitState = 0;

    UnLockInstance( pInst );

    do
    {
      switch ( pInst->State )
      {
        /*---------------------------------------------------*/
        /*                                                   */
        /*                                                   */
        /*                                                   */
        /*---------------------------------------------------*/
        case WFPP_INIT:

          pInst->DataCount = 0;
          ResetInstanceFlags( pInst, F_TIMEOUT );

          /*------------------------------------------------*/
          /* Start the elapsed request and inter-character  */
          /* timers.                                        */
          /*------------------------------------------------*/
          if ( pInst->WIdleTimeoutMS )
          {
            setDelayTimer( pInst,
                           TIMER_ID_2,
                           fpp_write_timeout,
                           pInst->WIdleTimeoutMS );
          }

          if ( pInst->WTimeoutMS )
          {
            setDelayTimer( pInst,
                           TIMER_ID_1,
                           fpp_write_timeout,
                           pInst->WTimeoutMS * pInst->FIFOWriteThresh );
          }

          pInst->ExtControlReg &= ~EXT_CONTROL_MODE;
          pInst->ExtControlReg |= EXT_CONTROL_MODE2;

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

          /*-----------------------------------------------------*/
          /* If the length of the next transfer will not satisfy */
          /* the FIFO threshold or we are not using interrupts   */
          /* then setup for polling the FIFO status.             */
          /*-----------------------------------------------------*/
          if ( (pInst->ReqDataCount < pInst->FIFOWriteThresh )
                                      || (pInst->Flags & F_NO_INTERRUPT) )
          {
            pInst->State = WFPP_POLLED;
          }
          /*---------------------------------------*/
          /* Setup for interrupt driven operation  */
          /*---------------------------------------*/
          else
          {
            pInst->State    = WFPP_INTERRUPT;
            pInst->IRQRtn   = do_write_fpp_mode;
          }

          break;

        /*---------------------------------------------------*/
        /* Handle interrupt mode transfers                   */
        /*                                                   */
        /* We received an interrupt. This means we have at   */
        /* least ECPFIFOThresh bytes available in the FIFO.  */
        /*                                                   */
        /* After this number of bytes are transferred, we    */
        /* must check the FIFO status before each byte       */
        /* transfer.                                         */
        /*---------------------------------------------------*/
        case WFPP_INTERRUPT:

          /*---------------------------------------*/
          /* Turn off the FIFO threshold interrupt */
          /*---------------------------------------*/
          pInst->ExtControlReg &= ~EXT_CONTROL_FIFOIRQ;

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


          if ( pInst->DataCount >= pInst->ReqDataCount )
          {
            pInst->State = WFPP_WAIT_FIFO_EMPTY;
            break;
          }

          n = pInst->ReqDataCount - pInst->DataCount;

          if ( n < pInst->FIFOWriteThresh )
          {
            pInst->State = WFPP_POLLED;
            break;
          }

          service_fpp_write( pInst );

          /*---------------------------------------*/
          /* Turn on the FIFO threshold interrupt  */
          /*---------------------------------------*/
          SetInstanceFlags( pInst, F_INTERRUPT_EXPECTED );

          pInst->ExtControlReg |= EXT_CONTROL_FIFOIRQ;

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

          fWaitState = 1;

          break;

        /*---------------------------------------------------*/
        /* Handle polled mode transfers                      */
        /*                                                   */
        /* The FIFO status is checked every 10ms in polled   */
        /* mode.                                             */
        /*                                                   */
        /* If the FIFO has room, it is filled with data from */
        /* the user's write buffer.                          */
        /*---------------------------------------------------*/
        case WFPP_POLLED:

          if ( pInst->DataCount >= pInst->ReqDataCount )
          {
            pInst->State = WFPP_WAIT_FIFO_EMPTY;
            break;
          }

          service_fpp_write( pInst );

          setDelayTimer( pInst,
                         TIMER_ID_0,
                         do_write_fpp_mode,
                         (USHORT)DELAY_OS_MIN );


          fWaitState = 1;

          break;

        /*---------------------------------------------------*/
        /* Poll for FIFO Empty.                              */
        /*                                                   */
        /* When the write transfers are completed, we wait   */
        /* for the FIFO Empty status to insure all the       */
        /* data in the FIFO has been transferred to the      */
        /* device.                                           */
        /*                                                   */
        /*---------------------------------------------------*/
      case WFPP_WAIT_FIFO_EMPTY:

          pInst->ExtControlReg  = IORead8( pInst->pIO[1], EXT_CONTROL_REG );
          pInst->ExtControlReg ^= EXT_CONTROL_INVERT;

          if ( pInst->ExtControlReg & EXT_CONTROL_FIFOEMPTY )
          {
            pInst->State = WFPP_COMPLETE;
            break;
          }

          setDelayTimer( pInst,
                         TIMER_ID_0,
                         do_write_fpp_mode,
                         (USHORT)DELAY_OS_MIN );

          fWaitState = 1;

          break;

        /*-----------------------------------------------*/
        /* Write FPP Timeout                             */
        /*-----------------------------------------------*/
        case WFPP_TIMEOUT:
          SetInstanceFlags( pInst, F_TIMEOUT);
          pInst->ReturnCode  = RC_TIMEOUT;
          pInst->State       = WFPP_COMPLETE;
          break;

        /*---------------------------------------------------*/
        /* FPP Write Complete                                */
        /*---------------------------------------------------*/
        case WFPP_COMPLETE:
          cancelAllTimers( pInst );

          ResetInstanceFlags( pInst, F_INTERRUPT_EXPECTED | F_TIMEOUT );
          pInst->UseCount = 1;
          fWaitState      = 1;
          break;
      }

      /*----------------------------------*/
      /* Check if the write was cancelled */
      /*----------------------------------*/
      if ( pInst->Flags & F_CANCELLED )
      {
        pInst->ReturnCode  = RC_CANCELLED;
        pInst->State       = WFPP_COMPLETE;
        fWaitState         = 0;
        break;
      }
    }
    while ( !(fWaitState) );

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

  /*-----------------------------------------------------*/
  /* If the write is complete then notify the requesting */
  /* routine.                                            */
  /*-----------------------------------------------------*/
  if ( pInst->State == WFPP_COMPLETE )
  {
    UnLockInstance( pInst );
    (*pInst->DoneRtn)( pInst );
  }
  else
  {
    UnLockInstance( pInst );
  }
}


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  service_fpp_write                                */
/*                                                                    */
/* DESCRIPTIVE NAME:  FIFO write service routine                      */
/*                                                                    */
/* FUNCTION:  The function of this routine is to transfer data to the */
/*            chipset FIFO until the FIFO status indicates the FIFO   */
/*            is full.   This routine services the FIFO in both       */
/*            interrupt and polled mode.                              */
/*                                                                    */
/*            This routine can optionally perform RLE compression on  */
/*            the user's write data.  In this case, the RLE count is  */
/*            output to the address FIFO which causes the chipset to  */
/*            tag the count as a command.                             */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT:  Task or interrupt time                                   */
/*                                                                    */
/* ENTRY POINT:  service_fpp_write                                    */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  parInstance_t   pInst    - ptr to adapter instance         */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: pInst->ExtControlReg, pInst->DataCount                    */
/*                                                                    */
/* INTERNAL REFERENCES:  cancelDelayTimer                             */
/*                       IORead8                                      */
/*                       IOWrite8                                     */
/*                       SetDelayTimer                                */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
void service_fpp_write( parInstance_t *pInst )
{
  USHORT                i;
  UCHAR                 far *pData;


  /*----------------------------------------------------*/
  /* Transfer bytes until the ReqDataCount is satisfied */
  /* or the FIFO is full.                               */
  /*----------------------------------------------------*/
  pData = &pInst->pDataBuf[pInst->DataCount];

  for ( i=0;
        pInst->DataCount < pInst->ReqDataCount;
        pInst->DataCount++, i++                   )
  {

    pInst->ExtControlReg  = IORead8( pInst->pIO[1], EXT_CONTROL_REG );
    pInst->ExtControlReg ^= EXT_CONTROL_INVERT;

    if ( pInst->ExtControlReg & EXT_CONTROL_FIFOFULL )
    {
      break;
    }

    if ( i==1 )   /* Cancel single character write timeout.  We will then */
                  /* setDelayTimer for a FIFO amount of characters.       */
    {
      cancelDelayTimer( pInst, TIMER_ID_1 );
    }

    IOWrite8( pInst->pIO[1], SPP_DFIFO_REG, pData[i] );
  }

  if ( pInst->WTimeoutMS )
  {
    setDelayTimer( pInst,
                   TIMER_ID_1,
                   fpp_write_timeout,
                   pInst->WTimeoutMS * pInst->FIFOWriteThresh );
  }
}


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  fpp_write_timeout                                */
/*                                                                    */
/* DESCRIPTIVE NAME:  Timeout routine for write requests in FPP mode  */
/*                                                                    */
/* FUNCTION:  A timer has expired signifying that the parallel port   */
/*            chip has failed to transmit all the characters and      */
/*            generate an interrupt.  The function of this routine is */
/*            to set the timeout state and call do_write_fpp_mode to  */
/*            process the timeout.                                    */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT:  Interrupt time                                           */
/*                                                                    */
/* ENTRY POINT:  fpp_write_timeout                                    */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  parInstance_t   pInst    - ptr to adapter instance         */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: pInst->State                                              */
/*                                                                    */
/* INTERNAL REFERENCES:  do_write_fpp_mode                            */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
void fpp_write_timeout( parInstance_t *pInst )
{
  pInst->State = WFPP_TIMEOUT;
  do_write_fpp_mode( pInst );
}


