	TITLE   MPU401 Driver Interface Module
	NAME	MPUIO
	PAGE	46,132
	;****************************************************************
	;*			      MPUIO				*
	;*								*
	;* This file contains a 'C' function for the MicroSoft 'C' com-	*
	;* piler v.4.0. It accesses the MPU401$$ driver using software	*
	;* interrupts.							*
	;*								*
	;* The two files FARNEAR.INC and SMALHUGE.INC each contain one	*
	;* equate. These will define the memory model to use for this	*
	;* module.							*
	;****************************************************************
	;* Author: Bjorn Larsson					*
	;* Revised:							*
	;* 1.0:	Started:					870111	*
	;*	Functional:					870111	*
	;* 1.1:	Changed to do character I/O with the driver (this	*
	;*	was previously in 'C', but was moved to asm for		*
	;*	various reasons):				870115	*
	;* 1.2:	Use 68H as default soft interrupt, supports		*
	;*	exclusive buffer access:			870117	*
	;****************************************************************
	;
	INCLUDE	FARNEAR.INC		;DEFINE FAR OR NEAR CALL SEQUENCE
	INCLUDE	SMALHUGE.INC		;DEFINE FAR OR NEAR DATA ACCESS
	;
_TEXT	SEGMENT  BYTE PUBLIC 'CODE'
	ASSUME  CS: _TEXT, DS: _TEXT
	;
	;* MSDOS related equates
	;
SYSTEM	EQU	21H			;SYSTEM INT NUMBER
OPNFIL	EQU	3DH			;FILE OPEN FUNCTION
CLOFIL	EQU	3EH			;FILE CLOSE FUNCTION
RDFIL	EQU	3FH			;FILE READ FUNCTION
OPNMOD	EQU	0			;NO SPECIAL OPEN MODE
	;
	;* Function codes for soft ints to MPU401$$ driver
	;
SINIT	EQU	0			;DRIVER INIT
SFINI	EQU	1			;DRIVER FINIT
SSTAT	EQU	2			;GET DRIVER STATUS
SRERR	EQU	3			;CLEAR DRIVER ERROR FLAGS
SSTIM	EQU	4			;SET TIMER
SRTIM	EQU	5			;READ TIMER
SFBUF	EQU	6			;FLUSH BUFFER
SRBUF	EQU	7			;READ BUFFER
STBUF	EQU	8			;TEST BUFFER
SDXBF	EQU	9			;DEFINE EXCLUSIVE BUFFER
SFXBF	EQU	10			;FLUSH EXCLUSIVE BUFFER
SRXBF	EQU	11			;READ EXCLUSIVE BUFFER
STXBF	EQU	12			;TEST EXCLUSIVE BUFFER
SOCMD	EQU	13			;OUTPUT COMMAND BYTE
SODAT	EQU	14			;OUTPUT DATA BYTE
	;
	;* Return error codes from mpuinit()
	;
BADOPN	EQU	1			;DRIVER OPEN ERROR
BADRD	EQU	2			;DRIVER READ ERROR
BADCLO	EQU	3			;DRIVER CLOSE ERROR
BADNUM	EQU	4			;BAD SOFTWARE INT NUMBER
	;
	;* Miscellaneous
	;
INTOPC	EQU	0CDH			;SOFTWARE INTERRUPT OPCODE
DFSFTI	EQU	68H			;DEFAULT SOFT INTERRUPT
	;
	;****************************************************************
	;* Function entry and exit macros, and parameter fetch macro.	*
	;* Used by all functions.					*
	;****************************************************************
	;
c_entry	MACRO	f_name
	;
	if far_call
&f_name	proc far
	else
&f_name	proc near
	endif
	push	bp
	mov	bp,sp
	;
	ENDM
	;
c_exit	MACRO	f_name
	;
	pop	bp
	ret
&f_name	endp
	;
	ENDM
	;
g_parm	MACRO	reg,p_num
	if	far_call
	mov	&reg,[bp+&p_num*2+4]
	else
	mov	&reg,[bp+&p_num*2+2]
	endif
	;
	ENDM
	;
REVCOD:	DB	'MPUIO v.1.2 - 870116 / B.Larsson '
DRNAME:	DB	'MPU401$$',0		;FILE NAME STRING
RDBUF:	DB	0,0			;FILE READ BUFFER
FHANDL:	DW	0			;FILE HANDLE DOING I/O
	;
	;****************************************************************
	;* mpuinit							*
	;*								*
	;* int mpuinit()						*
	;*								*
	;* Checks that the MPU401$$ driver is in the system, and works	*
	;* correctly. If so, gets the current software interrupt number	*
	;* and gives it to the other routines in this module.		*
	;* Returns non-zero value if an error occurs.			*
	;****************************************************************
	;
	PUBLIC	_mpuinit
	;
	c_entry _mpuinit
	;
	PUSH	DS			;SAVE REGS
	PUSH	CX
	PUSH	BX
	PUSH	CS			;SET DS = CS HERE
	POP	DS
	;
	;* First try to open the MPU401$$ driver
	;
	MOV	AH,OPNFIL		;OPEN FILE REQUEST
	MOV	AL,OPNMOD		;OPEN ACCESS MODES
	MOV	DX,OFFSET DRNAME	;NAME POINTER
	INT	SYSTEM
	JNC	MINIT1			;JUMP IF OK
	;
	MOV	AX,BADOPN		;DRIVER OPEN ERROR
	JMP	MINITX
	;
MINIT1:	MOV	WORD PTR FHANDL,AX	;SAVE FILE HANDLE
	;
	;* Now read a pair of bytes from it
	;
	MOV	BX,AX			;FILE HANDLE
	MOV	AH,RDFIL
	MOV	CX,2			;2 BYTES
	MOV	DX,OFFSET RDBUF
	INT	SYSTEM
	JC	MINIT2			;JUMP IF ERROR
	;
	CMP	AX,2			;CHECK 2 BYTES READ?
	JZ	MINIT3			;JUMP IF OK
	;
MINIT2:	MOV	AX,BADRD		;READ DEVICE ERROR
	JMP	MINITX
	;
	;* Now close the driver
	;
MINIT3:	MOV	AH,CLOFIL		;CLOSE FILE
	MOV	BX,WORD PTR FHANDL	;FILE HANDLE
	INT	SYSTEM
	JNC	MINIT4			;JUMP IF OK
	;
	MOV	AX,BADCLO		;DEVICE CLOSE ERROR
	JMP	MINITX
	;
	;* Check the bytes are equal
	;
MINIT4:	MOV	AX,WORD PTR RDBUF
	CMP	AH,AL
	JZ	MINIT5			;JUMP IF OK
	;
	MOV	AX,BADNUM		;SOFT INT NUMBER ERROR
	JMP	MINITX
	;
MINIT5:	MOV	BYTE PTR SFTI0,AL	;INSTALL IN OTHER FUNCTIONS
	MOV	BYTE PTR SFTI1,AL
	MOV	BYTE PTR SFTI2,AL
	MOV	BYTE PTR SFTI3,AL
	MOV	BYTE PTR SFTI4,AL
	MOV	BYTE PTR SFTI5,AL
	MOV	BYTE PTR SFTI6,AL
	MOV	BYTE PTR SFTI7,AL
	MOV	BYTE PTR SFTI8,AL
	MOV	BYTE PTR SFTI9,AL
	MOV	BYTE PTR SFTI10,AL
	MOV	BYTE PTR SFTI11,AL
	MOV	BYTE PTR SFTI13,AL
	MOV	BYTE PTR SFTI14,AL
	XOR	AX,AX			;CLEAR LOWER HALF OF RESULT
	;
MINITX:	POP	BX			;RECOVER REGS
	POP	CX
	XOR	DX,DX			;CLEAR UPPER 16 RESULT BITS
	POP	DS
	;
	c_exit	_mpuinit
	;
	;****************************************************************
	;* mpuon							*
	;*								*
	;* int mpuon(bufsiz,bufadr)					*
	;*   int   bufsiz;						*
	;*   char* bufadr;						*
	;*								*
	;* Activate the MPU401$$ driver. Defines a data buffer with	*
	;* size <bufsiz>, located at <bufadr>. <Bufsiz> must be 0 or	*
	;* 512 <= <bufsiz> <= 32768. If <bufsiz> is 0, the driver's	*
	;* internal buffer will be used. Returns non-zero if error.	*
	;****************************************************************
	;
	PUBLIC	_mpuon
	;
	c_entry _mpuon
	;
	g_parm	BX,1			;GET BUFFER SIZE
	g_parm	CX,2			;GET BUFFER OFFSET
	if	huge_data
	g_parm	DX,3			;GET SEGMENT
	else
	MOV	DX,DS			;USE DATA SEGMENT
	endif
	MOV	AX,SINIT		;INIT FUNCTION CODE
	DB	INTOPC
SFTI0:	DB	DFSFTI			;DEFAULT SOFT INTERRUPT
	MOV	AX,DX			;ERROR CODE TO AX
	;
	c_exit	_mpuon
	;
	;****************************************************************
	;* mpuoff							*
	;*								*
	;* int mpuoff()							*
	;*								*
	;* Deactivates the MPU401$$ driver. Errors code returned in AX.	*
	;****************************************************************
	;
	PUBLIC	_mpuoff
	;
	c_entry _mpuoff
	;
	MOV	AX,SFINI		;FINIT FUNCTION CODE
	DB	INTOPC
SFTI1:	DB	DFSFTI			;DEFAULT SOFT INTERRUPT
	MOV	AX,DX			;ERROR CODE TO AX
	;
	c_exit	_mpuoff
	;
	;****************************************************************
	;* mpustat							*
	;*								*
	;* int mpustat()						*
	;*								*
	;* Returns current MPU401$$ driver status. No errors returned.	*
	;****************************************************************
	;
	PUBLIC	_mpustat
	;
	c_entry _mpustat
	;
	MOV	AX,SSTAT		;STATUS FUNCTION CODE
	DB	INTOPC
SFTI2:	DB	DFSFTI			;DEFAULT SOFT INTERRUPT
	;
	c_exit	_mpustat
	;
	;****************************************************************
	;* mpurerr							*
	;*								*
	;* void mpurerr()						*
	;*								*
	;* Resets error status of the MPU401$$ driver. No errors re-	*
	;* turned.							*
	;****************************************************************
	;
	PUBLIC	_mpurerr
	;
	c_entry _mpurerr
	;
	MOV	AX,SRERR		;ERROR RESET FUNCTION CODE
	DB	INTOPC
SFTI3:	DB	DFSFTI			;DEFAULT SOFT INTERRUPT
	;
	c_exit	_mpurerr
	;
	;****************************************************************
	;* mpustim							*
	;*								*
	;* void mpustim(time)						*
	;*   long time;							*
	;*								*
	;* Sets the MPU401'sinternal timer to <time>. No error re-	*
	;* turned.							*
	;****************************************************************
	;
	PUBLIC	_mpustim
	;
	c_entry _mpustim
	;
	g_parm	CX,1			;GET LOW WORD
	g_parm	DX,2			;GET HIGH WORD
	MOV	AX,SSTIM		;SET TIMER FUNCTION CODE
	DB	INTOPC
SFTI4:	DB	DFSFTI			;DEFAULT SOFT INTERRUPT
	;
	c_exit	_mpustim
	;
	;****************************************************************
	;* mpurtim							*
	;*								*
	;* long mpurtim()						*
	;*								*
	;* Return the current value in the MPU401 internal timer.	*
	;* No error returned.						*
	;****************************************************************
	;
	PUBLIC	_mpurtim
	;
	c_entry _mpurtim
	;
	MOV	AX,SRTIM		;READ TIMER FUNCTION CODE
	DB	INTOPC
SFTI5:	DB	DFSFTI			;DEFAULT SOFT INTERRUPT
	;
	c_exit	_mpurtim
	;
	;****************************************************************
	;* mpufbuf							*
	;*								*
	;* void mpufbuf()						*
	;*								*
	;* Flush the driver buffer. No error returned.			*
	;****************************************************************
	;
	PUBLIC	_mpufbuf
	;
	c_entry _mpufbuf
	;
	MOV	AX,SFBUF		;FLUSH FUNCTION CODE
	DB	INTOPC
SFTI6:	DB	DFSFTI			;DEFAULT SOFT INTERRUPT
	;
	c_exit	_mpufbuf
	;
	;****************************************************************
	;* mpurbuf							*
	;*								*
	;* long mpurbuf()						*
	;*								*
	;* Return a byte from the input buffer. If nothing there, it	*
	;* will be waited for. Return data in AX. Error code in DX.	*
	;****************************************************************
	;
	PUBLIC	_mpurbuf
	;
	c_entry _mpurbuf
	;
	MOV	AX,SRBUF		;READ BUFFER FUNCTION CODE
	DB	INTOPC
SFTI7:	DB	DFSFTI			;DEFAULT SOFT INTERRUPT
	;
	c_exit	_mpurbuf
	;
	;****************************************************************
	;* mputbuf							*
	;*								*
	;* inf mputbuf()						*
	;*								*
	;* Return a flag indicatiing if data is available in the input	*
	;* buffer, in AX. No error returned.				*
	;****************************************************************
	;
	PUBLIC	_mputbuf
	;
	c_entry _mputbuf
	;
	MOV	AX,STBUF		;TEST BUFFER FUNCTION CODE
	DB	INTOPC
SFTI8:	DB	DFSFTI			;DEFAULT SOFT INTERRUPT
	;
	c_exit	_mputbuf
	;
	;****************************************************************
	;* mpudxbf							*
	;*								*
	;* int mpudxbf(bufsiz,bufadr)					*
	;*   int   bufsiz;						*
	;*   char* bufadr;						*
	;*								*
	;* Define an exclusive buffer with size <bufsiz>, located at	*
	;* <bufadr>. If <bufsiz> is 0, any existent buffer is removed.	*
	;* <Bufsiz> must be 0 or 512 <= <bufsiz> <= 32768.		*
	;****************************************************************
	;
	PUBLIC	_mpudxbf
	;
	c_entry	_mpudxbf
	g_parm	BX,1			;GET BUFFER SIZE
	g_parm	CX,2			;GET BUFFER OFFSET
	if	huge_data
	g_parm	DX,3			;GET SEGMENT
	else
	MOV	DX,DS			;USE DATA SEGMENT
	endif
	MOV	AX,SDXBF		;DEFINE EXCLUSIVE FUNCTION CODE
	DB	INTOPC
SFTI9:	DB	DFSFTI			;DEFAULT SOFT INTERRUPT
	MOV	AX,DX			;ERROR CODE TO AX
	;
	c_exit	_mpudxbf
	;
	;****************************************************************
	;* mpufxbf							*
	;*								*
	;* void mpufxbf()						*
	;*								*
	;* Flush the exclusive buffer. No error returned.		*
	;****************************************************************
	;
	PUBLIC	_mpufxbf
	;
	c_entry _mpufxbf
	;
	MOV	AX,SFXBF		;FLUSH EXCLUSIVE FUNCTION CODE
	DB	INTOPC
SFTI10:	DB	DFSFTI			;DEFAULT SOFT INTERRUPT
	;
	c_exit	_mpufxbf
	;
	;****************************************************************
	;* mpurxbf							*
	;*								*
	;* long mpurxbf()						*
	;*								*
	;* Return a byte from the exclusive buffer. If nothing there,	*
	;* it will be waited for. Return data in AX. Error code in DX.	*
	;****************************************************************
	;
	PUBLIC	_mpurxbf
	;
	c_entry _mpurxbf
	;
	MOV	AX,SRXBF		;READ ECLUSIVE FUNCTION CODE
	DB	INTOPC
SFTI11:	DB	DFSFTI			;DEFAULT SOFT INTERRUPT
	;
	c_exit	_mpurxbf
	;
	;****************************************************************
	;* mputxbf							*
	;*								*
	;* inf mputxbf()						*
	;*								*
	;* Return a flag indicatiing if data is available in the exclu-	*
	;* sive message buffer in AX. If the driver is inactive, AX	*
	;* returns 1, and DX has an error code.				*
	;****************************************************************
	;
	PUBLIC	_mputxbf
	;
	c_entry _mputxbf
	;
	MOV	AX,STXBF		;TEST EXCLUSIVE FUNCTION CODE
	DB	INTOPC
SFTI12:	DB	DFSFTI			;DEFAULT SOFT INTERRUPT
	;
	c_exit	_mputxbf
	;
	;****************************************************************
	;* mpuocmd							*
	;*								*
	;* int mpuocmd(cmd)						*
	;*   char cmd;							*
	;*								*
	;* Send <cmd> as a command to MPU401. Return competion status	*
	;* in AX.							*
	;****************************************************************
	;
	PUBLIC	_mpuocmd
	;
	c_entry _mpuocmd
	;
	g_parm	DL,1			;GET CMD BYTE
	MOV	AX,SOCMD		;COMMAND OUTPUT FUNCTION CODE
	DB	INTOPC
SFTI13:	DB	DFSFTI			;DEFAULT SOFT INTERRUPT
	MOV	AX,DX			;COMPL CODE IN AX
	;
	c_exit	_mpuocmd
	;
	;****************************************************************
	;* mpuodat							*
	;*								*
	;* int mpuodat(data)						*
	;*   char data;							*
	;*								*
	;* Send <data> as a data byte to MPU401. Return competion	*
	;* status in AX.						*
	;****************************************************************
	;
	PUBLIC	_mpuodat
	;
	c_entry _mpuodat
	;
	g_parm	DL,1			;GET DATA BYTE
	MOV	AX,SODAT		;DATA OUTPUT FUNCTION CODE
	DB	INTOPC
SFTI14:	DB	DFSFTI			;DEFAULT SOFT INTERRUPT
	MOV	AX,DX			;COMPL CODE IN AX
	;
	c_exit	_mpuodat
	;
_TEXT	ENDS
	if1
	%OUT	Pass 1 Completed
	else
	%OUT	Assembly Completed
	endif
	END
