/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT    Copyright (C) 1995 IBM Corporation                           */
/*                                                                           */
/*    The following IBM OS/2 WARP source code is provided to you solely for  */
/*    the purpose of assisting you in your development of OS/2 WARP device   */
/*    drivers. You may use this code in accordance with the IBM License      */
/*    Agreement provided in the IBM Device Driver Source Kit for OS/2. This  */
/*    Copyright statement may not be removed.                                */
/*                                                                           */
/*****************************************************************************/
/*static char *SCCSID = "src/dev/dasd/addcalls/addservc.c, dasdlib, ddk_subset, b_bdd.032 93/03/21";*/
/**************************************************************************
 *
 * SOURCE FILE NAME = ADDSERV.C
 *
 * DESCRIPTIVE NAME = Adapter Device Driver Common Services
 *
 *
 *
 * VERSION = V2.0
 *
 * DATE
 *
 * DESCRIPTION :
 *
 * Purpose: Adapter and Device driver common services.
 *
 *
 *
*/

 #define INCL_NOBASEAPI
 #define INCL_NOPMAPI
 #define INCL_NO_SCB
 #define INCL_INITRP_ONLY
 #define INCL_DOSERRORS
 #include "os2.h"
 #include "dos.h"
 #include "bseerr.h"
 #include "dskinit.h"
 #include <scb.h>
 #include <abios.h>

 #include "iorb.h"
 #include "reqpkt.h"
 #include "dhcalls.h"
 #include "addcalls.h"

/*------------------------------------*/
/*                                    */
/*                                    */
/*                                    */
/*------------------------------------*/

BOOL PASCAL NEAR ADD_XferIOW( NPADD_XFER_IO npADDX )
{
  PSCATGATENTRY pSGE;

  PBYTE         pSrcDst;
  ULONG         ppSrcDst;

  ULONG         BufRem;

  ULONG         SGDone;
  ULONG         SGRem;
  ULONG         SGLen;

  ULONG         XferLen;
  ULONG         XferRem;
  ULONG         XferCur;
  ULONG         XferCur0;
  ULONG         XferWords;

  USHORT        Data;
  USHORT        Port;
  USHORT        Input;
  USHORT        ByteHeld = 0;
  USHORT        ModeFlag;

  ULONG         TotalXfer = 0;


  BufRem = npADDX->numTotalBytes;
  pSGE   = &npADDX->pSGList[npADDX->iSGList];
  Port   = npADDX->iPortAddress;

  if ( npADDX->Mode == SGLIST_TO_PORT )
  {
    Input = 0;
  }
  else if ( npADDX->Mode == PORT_TO_SGLIST )
  {
    Input = 1;
  }
  else
  {
    _asm { int 3 }
  }

  /*----------------------------------------*/
  /* Transfer count must not be odd         */
  /*----------------------------------------*/
  if ( npADDX->numTotalBytes & 1 )
  {
    _asm { int 3 }
  }

  do
  {
    /*----------------------------------------*/
    /* Sanity check S/G list info             */
    /*----------------------------------------*/
    if ( npADDX->iSGList >= npADDX->cSGList )
    {
      _asm { int 3 }
    }


    /*----------------------------------------*/
    /* Bytes available in current S/G segment */
    /*----------------------------------------*/
    SGLen    = pSGE->XferBufLen;
    SGDone   = npADDX->SGOffset;
    SGRem    = SGLen - SGDone;

    /*---------------------------------------------*/
    /* Transfer either the amount available or the */
    /* amount that will fit in the current S/G     */
    /* segment.                                    */
    /*---------------------------------------------*/
    XferLen = ((SGRem-ByteHeld) < BufRem) ? SGRem : BufRem;

    /*-----------------------*/
    /* Xfer Physical Address */
    /*-----------------------*/
    ppSrcDst = pSGE->ppXferBuf + SGDone;

    /*------------------------------------------*/
    /* Iterate if I/O transfer if length > 64KB */
    /*------------------------------------------*/
    XferRem = XferLen;

    do
    {
      XferCur = XferCur0 = ( XferRem > 64L*1024 ) ? 64L*1024 : XferLen;

      if ( DevHelp_PhysToVirt( (ULONG)   ppSrcDst,
                               (USHORT)  XferCur,
                               (PVOID)   &pSrcDst,
                               (PUSHORT) &ModeFlag  ) )
      {
        _asm { int 3 }
      }

      /*---------------------------------------*/
      /* If there is a byte leftover from the  */
      /* previous transfer, transfer it now    */
      /*---------------------------------------*/

      if ( ByteHeld )
      {
        if ( Input )
        {
          *pSrcDst = (UCHAR) (Data >> 8);
        }
        else
        {
          Data |= *pSrcDst << 8;
          outwp( Port, Data );
          TotalXfer++;
        }

        ByteHeld = 0;
        ppSrcDst++;
        pSrcDst++;
        XferCur--;
      }

      /*-------------------------*/
      /* Do full words transfers */
      /*-------------------------*/
      XferWords = XferCur >> 1;

      if ( XferWords )
      {
        if ( Input )
        {
          inswp( Port, pSrcDst, XferWords );
        }
        else
        {
          outswp( Port, pSrcDst, XferWords );
        }

        TotalXfer  += XferWords;
        ppSrcDst   += XferWords << 1;
        pSrcDst    += XferWords << 1;
        XferCur    -= XferWords << 1;
      }

      /*-------------------------------------------*/
      /* Single byte transfer. This creates        */
      /* a leftover byte which is handled on the   */
      /* next iteration.                           */
      /*-------------------------------------------*/
      if ( XferCur == 1 )
      {
        if ( Input )
        {
          inwp( Port, Data );
          *pSrcDst = (UCHAR) Data;
          TotalXfer++;
        }
        else
        {
          Data = *pSrcDst;
        }

        ByteHeld = 1;
        ppSrcDst++;
        pSrcDst++;
      }
    }
    while ( XferRem -= XferCur0 );

    BufRem           -= XferLen;
    npADDX->SGOffset += XferLen;

    if ( npADDX->SGOffset == pSGE->XferBufLen )
    {
      npADDX->iSGList++;
      pSGE++;
      npADDX->SGOffset = 0;
    }
    else if ( npADDX->SGOffset > pSGE->XferBufLen )
    {
      _asm { int 3 }
    }
    else if ( BufRem )
    {
      _asm { int 3 }
    }

  }
  while ( BufRem );

  if ( (TotalXfer << 1) != npADDX->numTotalBytes )
  {
    _asm { int 3 }
  }
}

