	INCLUDE	TITLE.MAC
	.TITLE	<EXIO -- Extended I/O Functions>
	.SBTTL	Declarations

; exio.asm  15 Nov 83  Craig Milo Rogers at USC/ISI
;	Converted to PDP-11-style TITLEs.
; exio.asm  25 Oct 83  Craig Milo Rogers at USC/ISI
;	Converted to multi-model Lattice C.
; exio.asm  8 Sep 83  Craig Milo Rogers at USC/ISI
;	This module defines extended I/O subroutines.
;

IF1
	INCLUDE	DOS.MAC			; C segments.
	INCLUDE	BMAC.MAC		; C procedure calls.
ENDIF


DMA_CMD	EQU	8			; I8237 DMA chip command register.

	PSEG				; All the rest is program code.

	.SBHED	<OUTOUTP -- Output Two Values in a Row>

; name		outoutp -- output two values in a row
;
; synopsis	(void) outoutp(port, reg, val);
;		int port;	I/O port
;		int reg;	internal register address
;		int val;	register value
;
; description	This function handles chips such as the Zilog 8530.
;		Two output instructions are executed for each access.
;		The first output addresses a register on the chip.
;		The second output gives the register a value.

	BENTRY	OUTOUTP <PORT,REGX,VAL>

	MOV	DX,PORT		; Get port address.
	MOV	AX,REGX		; Get register number.
	CLI			; ******* Disable Interrupts *******
	OUT	DX,AL		;;; Address the register.
	MOV	AX,VAL		;;; Get register value.
	OUT	DX,AL		;;; Store the value.
	STI			;;; ******* Enable Interrupts *******
				;;; (Next instruction, too)
	BEND	OUTOUTP

	.SBHED	<OUTINP -- Output Then Input>

; name		outinp -- output then input
;
; synopsis	val = outinp(port, reg);
;		int port;	I/O port
;		int reg;	internal register address
;		int val;	register value
;
; description	This function handles chips such as the Zilog 8530.
;		Two I/O instructions are executed for each access.
;		The first output addresses a register on the chip.
;		The second is an input to read the value.

	BENTRY	OUTINP <PORT,REGX>

	MOV	DX,PORT		; Get port address.
	MOV	AX,REGX		; Get register number.
	CLI			; ******* Disable Interrupts *******
	OUT	DX,AL		;;; Address the register.
	IN	AL,DX		;;; Read the value.
	STI			;;; ******* Enable Interrupts *******
	XOR	AH,AH		;;; Clear high half.

	BEND	OUTINP

	.SBHED	<OUTP2X -- Output Two Values to Different Ports>

; name		outp2x -- output two values to different ports
;
; synopsis	(void) outp2x(port1, val1, port2, val2);
;		int port1;	first I/O port
;		int val1;	register value
;		int port2;	second I/O port
;		int val2;	register value
;
; description	This routine is designed for situations where two
;		devices need to be started simultaneously.  One
;		example is in starting DMA on an SCC channel in
;		SDLC mode.
;
	BENTRY	OUTP2X <PORT1,VAL1,PORT2,VAL2>

	MOV	DX,PORT1	; Get port address.
	MOV	AX,VAL1		; Get register number.
	CLI			; ******* Disable Interrupts *******
	OUT	DX,AL		;;; Store first value.
	MOV	DX,PORT2	;;; Get port address.
	MOV	AX,VAL2		;;; Get register number.
	OUT	DX,AL		;;; Store second value.
	STI			;;; ******* Enable Interrupts *******
				;;; (Next instruction, too)
	BEND	OUTP2X

	.SBHED	<OUTPD -- Output with DMA Interlock>

; name		outpd -- output with DMA interlock
;
; synopsis	outpd(port, val);
;		int port;	I/O port
;		int val;	value to output
;
; description	This function does output with DMA turned off.  This
;		caters to slow chips like the Zilog 8530, which cannot
;		tolerate sequential accesses by the CPU and DMA.  So,
;		it is necessary to temporarily shut off DMA when accessing
;		the device.
;
	BENTRY	OUTPD <PORT,VAL>

	MOV	DX,PORT		; Get port address.
	MOV	CX,VAL		; Get value to output.
	MOV	AL,4		; Bit to disable all DMA (incl. refresh).
	CLI			; ******* Disable Interrupts *******
	OUT	DMA_CMD,AL	;;; Mask off all DMA (incl. refresh).
	MOV	AL,CL		;;; Fetch the data to output.
	OUT	DX,AL		;;; Send it to the external device.
	XOR	AL,AL		;;; Command to reenable DMA.
	OUT	DMA_CMD,AL	;;; Restore the DMA channels.
	STI			;;; ******* Enable Interrupts *******
				;;; (Next instruction, too)
	BEND	OUTPD

	.SBHED	<INPD -- Input with DMA Interlock>

; name		inpd -- input with DMA interlock
;
; synopsis	val = inpd(port);
;		int port;	I/O port
;		int val;	value which was input
;
; description	This function does input with DMA turned off.  This
;		caters to slow chips like the Zilog 8530, which cannot
;		tolerate sequential accesses by the CPU and DMA.  So,
;		it is necessary to temporarily shut off DMA when accessing
;		the device.
;
	BENTRY	INPD <PORT>

	MOV	DX,PORT		; Get port address.
	MOV	AL,4		; Bit to disable all DMA (incl. refresh).
	CLI			; ******* Disable Interrupts *******
	OUT	DMA_CMD,AL	;;; Mask off all DMA (incl. refresh).
	IN	AL,DX		;;; Read data from the external device.
	MOV	CL,AL		;;; Store data in a safer place.
	XOR	AL,AL		;;; Command to reenable DMA.
	OUT	DMA_CMD,AL	;;; Restore the DMA channels.
	STI			;;; ******* Enable Interrupts *******
	MOV	AL,CL		;;; Pickup saved input value.
	XOR	AH,AH		; Clear high half.

	BEND	INPD

	.SBHED	<OUTOUTPD -- Output Two Values with DMA Interlock>

; name		outoutpd -- output two values with DMA interlock
;
; synopsis	outoutpd(port, reg, val);
;		int port;	I/O port
;		int reg;	internal register address
;		int val;	register value
;
; description	This function handles chips such as the Zilog 8530.
;		Two output instructions are executed for each access.
;		The first output addresses a register on the chip.
;		The second output gives the register a value.
;		DMA is masked during I/O to keep slow devices happy.
;
	BENTRY	OUTOUTPD <PORT,REGX,VAL>
	
	MOV	DX,PORT		; Get port address.
	MOV	BX,REGX		; Get register number.
	MOV	CX,VAL		; Get register value.
	MOV	AL,4		; Bit to disable all DMA (incl. refresh).
	CLI			; ******* Disable Interrupts *******
	OUT	DMA_CMD,AL	;;; Mask off all DMA (incl. refresh).
	MOV	AL,BL		;;; Get the register number.
	OUT	DX,AL		;;; Address the register.
	XOR	AL,AL		;;; Command to reenable DMA.
	OUT	DMA_CMD,AL	;;; Restore the DMA channels.
	NOP			;;; Give refresh and DMA a chance.
	NOP			;;; Give refresh and DMA a chance.
	NOP			;;; Give refresh and DMA a chance.
	MOV	AL,4		;;; Bit to disable all DMA (incl. refresh).
	OUT	DMA_CMD,AL	;;; Mask off all DMA (incl. refresh).
	MOV	AL,CL		;;; Get register value.
	OUT	DX,AL		;;; Store the value.
	XOR	AL,AL		;;; Command to reenable DMA.
	OUT	DMA_CMD,AL	;;; Restore the DMA channels.
	STI			;;; ******* Enable Interrupts *******
				;;; (Next instruction, too)
	BEND	OUTOUTPD

	.SBHED	<OUTINPD -- Output then Input with DMA Interlock>

; name		outinpd -- output then input with DMA interlock
;
; synopsis	val = outinpd(port, reg);
;		int port;	I/O port
;		int reg;	internal register address
;		int val;	register value
;
; description	This function handles chips such as the Zilog 8530.
;		Two I/O instructions are executed for each access.
;		The first output addresses a register on the chip.
;		The second is an input to read the value.
;
;
	BENTRY	OUTINPD <PORT,REGX>

	MOV	DX,PORT		; Get port address.
	MOV	BX,REGX		; Get register number.
	MOV	AL,4		; Bit to disable all DMA (incl. refresh).
	CLI			; ******* Disable Interrupts *******
	OUT	DMA_CMD,AL	;;; Mask off all DMA (incl. refresh).
	MOV	AL,BL		;;; Get the register number.
	OUT	DX,AL		;;; Address the register.
	XOR	AL,AL		;;; Command to reenable DMA.
	OUT	DMA_CMD,AL	;;; Restore the DMA channels.
	NOP			;;; Give refresh and DMA a chance.
	NOP			;;; Give refresh and DMA a chance.
	NOP			;;; Give refresh and DMA a chance.
	MOV	AL,4		;;; Bit to disable all DMA (incl. refresh).
	OUT	DMA_CMD,AL	;;; Mask off all DMA (incl. refresh).
	IN	AL,DX		;;; Read the value.
	MOV	CL,AL		;;; Store data in a safer place.
	XOR	AL,AL		;;; Command to reenable DMA.
	OUT	DMA_CMD,AL	;;; Restore the DMA channels.
	STI			;;; ******* Enable Interrupts *******
	MOV	AL,CL		;;; Pickup saved input value.
	XOR	AH,AH		; Clear high half.

	BEND	OUTINPD
;
	ENDPS			; Close the code segment.
	END
