/***************************************************************************
 *									    
 *			   _ b l k i o   F u n c t i o n		    
 *			   -----------------------------		    
 *	Copyright 1982,1983 by Digital Research Inc.  All rights reserved.  
 *									    
 *	The _blkio function is used to read / write a set of contiguous	    
 *	sectors in an open file.					    
 *	Note: if CPM, it will use CP/M function 44 (Set Multi-Sector Count) 
 *	if os_multisectorio is TRUE (BDOS versions 3.0 and above).	    
 *	Note 2: if PC-DOS, it will use block read and write functions.	    
 *									    
 *	Edits:								    
 *		8-Dec-83 whf	handle PC-DOS changes.			    
 *									    
 *	Calling Sequence:						    
 *		ret = _blkio(ccbp,sector,buffer,count,bdosfunc);	    
 *									    
 *	Where:								    
 *		ret	=  sectors actually read/written		    
 *		ccbp	-> the open file channel control block		    
 *		sector	=  The desired starting sector number		    
 *		buffer  =  The memory address to begin transfer		    
 *		count	=  the number of sectors to read/write		    
 *		bdosfunc=  The BDOS function number (B_READ / B_WRITE)	    
 *									    
 ****************************************************************************/

#include	"portab.h"
#include	"osif.h"
#include	"osiferr.h"
#include	"osattr.h"

#define MIN(x,y) ( ((x) < (y)) ? (x) : (y) )

	LONG
_blkio(ccbp,sector,buffer,count,bdosfunc)
						/****************************/
	     FD		*ccbp;			/* open file pointer	    */
	     LONG	sector;			/* Sector number	    */
	     BYTE	*buffer;		/* User's buffer area	    */
	     LONG	count;			/* # of sectors to do	    */
	     int	bdosfunc;		/* BDOS function to use	    */
{						/****************************/

#if PCDOS    /*=============================================================*/
	REG WORD seccnt;			/* number sectors xferred   */
	WORD _pc_readblk(), _pc_writeblk();	/* functions to read/write  */

	if( bdosfunc == B_READ )
	     return _pc_readblk(&(ccbp->fcb),sector,buffer,(WORD)count,SECSIZ);
	else return _pc_writeblk(&(ccbp->fcb),sector,buffer,(WORD)count,SECSIZ);
}

#endif      /*==============================================================*/


#if CPM	    /*==============================================================*/
	WORD	nsecs;				/* # secs to xfer each time */
	LONG	seccnt;				/* # sectors processed	    */
	WORD	xuser;				/* old user number	    */
	WORD	retcode;			/* return code from BDOS    */
	WORD	Used_Multisec;			/* flag for resetting msecio*/
						/****************************/
	seccnt = 0;				/* Zero count initally	    */
	Used_Multisec = 0;			/* Haven't used it yet	    */
	xuser = _chkuser(ccbp->user);		/* Check for changed user # */
	nsecs = 1;				/* default: xfer singly	    */
						/*			    */
	while (count > 0)			/* Until all sectors xferred*/
	{					/*			    */
		__OSIF(SETDMA,buffer);		/* Set new DMA address	    */

#if HILO	/*==========================================================*/
		ccbp->fcb.record = sector;	/* Set new record number    */
#else		/*----------------------------------------------------------*/
		ccbp->fcb.record = sector << 8;	/* Set new record number    */
#endif  	/*==========================================================*/

						/*   Multi Sector I/O xfer? */
		if( (count > 1  &&  os_multisectorio ) || nsecs > 1 ) 
		{				/* yes!			    */
		    if( os_oldmultisec )
			 nsecs = MIN(16,count);	/* Older version of msecio  */
		    else nsecs = MIN(128,count);/* Later version of msecio  */
		    ++Used_Multisec;		/* Flag: need to reset	    */
		    __OSIF(F_MULTISEC,nsecs);	/* make the call	    */
		}				/*******		    */
						/****************************/
		retcode = __OSIF(bdosfunc,&(ccbp->fcb));/* do the read/write*/
						/****************************/
		if(retcode != 0)
		{				/****************************/
		    if(nsecs>1)			/* were we trying multi-sec?*/
		    {				/* yes! do error handling   */
		      if( os_oldmultisec )	/* Older msecio?	    */
			 nsecs = __cpmrv >> 12;	/* adjust nsecs read like so*/
		      else nsecs = __cpmrv >> 8;/* later versions: use AH   */
		    }				/***			    */
		    else nsecs = 0;		/* ow. assume 0 secs read   */
		    seccnt += nsecs;		/* Return nfg		    */
		    break;			/* Return from bottom	    */
		}				/****************************/
						/*			    */
		sector += nsecs;		/* Increment sector number  */
		count  -= nsecs;		/* Down count		    */
		seccnt += nsecs;		/* Bump sector count	    */
		buffer += nsecs*SECSIZ;		/* Increment address	    */
	}					/****************************/
	_uchkuser(ccbp->user,xuser);		/* Reset user # if needed   */
	if( Used_Multisec )			/* Need to reset msecio?    */
	    __OSIF(F_MULTISEC,1);		/*   then do so...	    */
	return(seccnt);				/* All is OK		    */
}						/****************************/
#endif	/*==================================================================*/
