;
;==================================================================================================
; PIO DRIVER (PARALLEL PORT)
;==================================================================================================
;
;  SETUP PARAMETER WORD:
;  +-------+---+-------------------+ +---+---+-----------+---+-------+
;  |       |RTS| ENCODED BAUD RATE | |DTR|XON|  PARITY   |STP| 8/7/6 |
;  +-------+---+---+---------------+ ----+---+-----------+---+-------+
;    F   E   D   C   B   A   9   8     7   6   5   4   3   2   1   0
;       -- MSB (D REGISTER) --           -- LSB (E REGISTER) --
;
; THIS DRIVER IS JUST A STUB TO DETECT AND INITIALIZE PIO HARDWARE
; IF IT EXISTS.  FOR NOW, IT DOES NOT REGISTER ANY OF THE PIO CHANNELS
; AS CHARACTER DEVICE UNITS.
;
PIO_NONE	.EQU	0
PIO_PIO		.EQU	1
;
PIO0A_CTL	.EQU	PIO0BASE + $02	
PIO0A_DAT	.EQU	PIO0BASE + $00
PIO0B_CTL	.EQU	PIO0BASE + $03
PIO0B_DAT	.EQU	PIO0BASE + $01
;
#IF (PIOCNT >= 2)
;
PIO1A_CTL	.EQU	PIO1BASE + $02	
PIO1A_DAT	.EQU	PIO1BASE + $00
PIO1B_CTL	.EQU	PIO1BASE + $03
PIO1B_DAT	.EQU	PIO1BASE + $01
;
#ENDIF
;
PIO_PREINIT:
;
; SETUP THE DISPATCH TABLE ENTRIES
; NOTE: INTS WILL BE DISABLED WHEN PREINIT IS CALLED AND THEY MUST REMAIN
; DISABLED.
;
	CALL	PIO_PROBE		; PROBE FOR CHIPS
;
	LD	B,PIO_CFGCNT		; LOOP CONTROL
	XOR	A			; ZERO TO ACCUM
	LD	(PIO_DEV),A		; CURRENT DEVICE NUMBER
	LD	IY,PIO_CFG		; POINT TO START OF CFG TABLE
PIO_PREINIT0:	
	PUSH	BC			; SAVE LOOP CONTROL
	CALL	PIO_INITUNIT		; HAND OFF TO GENERIC INIT CODE
	POP	BC			; RESTORE LOOP CONTROL
;
	LD	A,(IY+1)		; GET THE PIO TYPE DETECTED
	OR	A			; SET FLAGS
	JR	Z,PIO_PREINIT2		; SKIP IT IF NOTHING FOUND
;	
	PUSH	BC			; SAVE LOOP CONTROL
	PUSH	IY			; CFG ENTRY ADDRESS
	POP	DE			; ... TO DE
	LD	BC,PIO_FNTBL		; BC := FUNCTION TABLE ADDRESS
	; REGISTRATION OF CHARACTER UNIT IN HBIOS IS BYPASSED
	; FOR NOW.  NOT SURE WHAT TO DO WITH THIS HARDWARE YET.
	;CALL	NZ,CIO_ADDENT		; ADD ENTRY IF PIO FOUND, BC:DE
	POP	BC			; RESTORE LOOP CONTROL
;
PIO_PREINIT2:	
	LD	DE,PIO_CFGSIZ		; SIZE OF CFG ENTRY
	ADD	IY,DE			; BUMP IY TO NEXT ENTRY
	DJNZ	PIO_PREINIT0		; LOOP UNTIL DONE
;
	XOR	A			; SIGNAL SUCCESS
	RET				; AND RETURN
;
; PIO INITIALIZATION ROUTINE
;
PIO_INITUNIT:
	CALL	PIO_DETECT		; DETERMINE PIO TYPE
	LD	(IY+1),A		; SAVE IN CONFIG TABLE
	OR	A			; SET FLAGS
	RET	Z			; ABORT IF NOTHING THERE
;
	; UPDATE WORKING PIO DEVICE NUM
	LD	HL,PIO_DEV		; POINT TO CURRENT UART DEVICE NUM
	LD	A,(HL)			; PUT IN ACCUM
	INC	(HL)			; INCREMENT IT (FOR NEXT LOOP)
	LD	(IY),A			; UPDATE UNIT NUM
;	
	; SET DEFAULT CONFIG
	LD	DE,-1			; LEAVE CONFIG ALONE
	; CALL INITDEVX TO IMPLEMENT CONFIG, BUT NOTE THAT WE CALL
	; THE INITDEVX ENTRY POINT THAT DOES NOT ENABLE/DISABLE INTS!
	JP	PIO_INITDEVX		; IMPLEMENT IT AND RETURN
;
;
;
PIO_INIT:
	LD	B,PIO_CFGCNT		; COUNT OF POSSIBLE PIO UNITS
	LD	IY,PIO_CFG		; POINT TO START OF CFG TABLE
PIO_INIT1:
	PUSH	BC			; SAVE LOOP CONTROL
	LD	A,(IY+1)		; GET PIO TYPE
	OR	A			; SET FLAGS
	CALL	NZ,PIO_PRTCFG		; PRINT IF NOT ZERO
	POP	BC			; RESTORE LOOP CONTROL
	LD	DE,PIO_CFGSIZ		; SIZE OF CFG ENTRY
	ADD	IY,DE			; BUMP IY TO NEXT ENTRY
	DJNZ	PIO_INIT1		; LOOP TILL DONE
;
	XOR	A			; SIGNAL SUCCESS
	RET				; DONE
;
; DRIVER FUNCTION TABLE
;
PIO_FNTBL:
	.DW	PIO_IN
	.DW	PIO_OUT
	.DW	PIO_IST
	.DW	PIO_OST
	.DW	PIO_INITDEV
	.DW	PIO_QUERY
	.DW	PIO_DEVICE
#IF (($ - PIO_FNTBL) != (CIO_FNCNT * 2))
	.ECHO	"*** INVALID PIO FUNCTION TABLE ***\n"
#ENDIF
;
;
;
PIO_IN:
	LD	E,0			; DUMMY VALUE
	XOR	A			; SIGNAL SUCCESS
	RET
;
;
;
PIO_OUT:
	XOR	A			; SIGNAL SUCCESS
	RET
;
;
;
PIO_IST:
	XOR	A			; NO CHARS WAITING
	RET
;
;
;
PIO_OST:
	XOR	A			; NO BUFFER SPACE AVAIL
	RET
;
; NOTE THAT THERE ARE TWO ENTRY POINTS.  INITDEV WILL DISABLE/ENABLE INTS
; AND INITDEVX WILL NOT.  THIS IS DONE SO THAT THE PREINIT ROUTINE ABOVE
; CAN AVOID ENABLING/DISABLING INTS.
;
PIO_INITDEV:
	HB_DI				; DISABLE INTS
	CALL	PIO_INITDEVX		; DO THE WORK
	HB_EI				; INTS BACK ON
	RET				; DONE
;
PIO_INITDEVX:
;
; THIS ENTRY POINT BYPASSES DISABLING/ENABLING INTS WHICH IS REQUIRED BY
; PREINIT ABOVE.  PREINIT IS NOT ALLOWED TO ENABLE INTS!
;
	LD	C,(IY+3)		; CONTROL PORT
	LD	A,%00010111		; CLEAR INTERRUPT CTL WORD
	OUT	(C),A
	LD	A,%11111111		; CLEAR MASK
	OUT	(C),A
	LD	A,%00000000		; CLEAR INTERRUPT VECTOR
	OUT	(C),A
	LD	A,%01001111		; SET MODE 1 (INPUT)
	OUT	(C),A
	RET
;
;
;
PIO_QUERY:
	LD	E,(IY+5)		; FIRST CONFIG BYTE TO E
	LD	D,(IY+6)		; SECOND CONFIG BYTE TO D
	XOR	A			; SIGNAL SUCCESS
	RET				; DONE
;
;
;
PIO_DEVICE:
	LD	D,CIODEV_PIO		; D := DEVICE TYPE
	LD	E,(IY)			; E := PHYSICAL UNIT
	LD	C,$40			; C := DEVICE TYPE, 0x40 IS PIO
	LD	H,(IY+1)		; H := MODE
	LD	L,(IY+3)		; L := BASE I/O ADDRESS
	XOR	A			; SIGNAL SUCCESS
	RET
;
; PIO CHIP PROBE
; CHECK FOR PRESENCE OF PIO CHIPS AND POPULATE THE
; PIO_MAP BITMAP (ONE BIT PER CHIP).  THIS DETECTS
; CHIPS, NOT CHANNELS.  EACH CHIP HAS 2 CHANNELS.
; MAX OF TWO CHIPS CURRENTLY.  INT VEC VALUE IS TRASHED!
;
PIO_PROBE:
	; CLEAR THE PRESENCE BITMAP
	LD	HL,PIO_MAP		; HL POINTS TO BITMAP
	XOR	A			; ZERO
	LD	(PIO_MAP),A		; CLEAR CHIP PRESENT BITMAP
;
	; FIRST POSSIBLE CHIP
	LD	C,PIO0A_CTL		; FIRST CHIP CMD/STAT PORT
	CALL	PIO_PROBECHIP		; PROBE IT
	JR	NZ,PIO_PROBE1		; IF NOT ZERO, NOT FOUND
	SET	0,(HL)			; SET BIT FOR FIRST CARD
PIO_PROBE1:
;
#IF (PIOCNT >= 2)
	LD	C,PIO1A_CTL		; SECOND CHIP CMD/STAT PORT
	CALL	PIO_PROBECHIP		; PROBE IT
	JR	NZ,PIO_PROBE2		; IF NOT ZERO, NOT FOUND
	SET	1,(HL)			; SET BIT FOR SECOND CARD
PIO_PROBE2:
#ENDIF
;
	RET
;
PIO_PROBECHIP:
	; PIO IS HARD TO DETECT DEFINITIVELY.  BEST I CAN THINK
	; OF IS TO CHECK THE VALUE READ FROM THE CONTROL PORT.
	; IT APPEARS TO BE ZERO CONSISTENTLY IF CHIP EXISTS.
	IN	A,(C)			; GET VALUE
	OR	A			; COMPARE TO ZERO
	RET
;
; PIO DETECTION ROUTINE
; THERE IS ONLY ONE VARIATION OF PIO CHIP, SO HERE WE JUST CHECK THE
; CHIP PRESENCE BITMAP TO SET THE CHIP TYPE OF EITHER NONE OR PIO.
;
PIO_DETECT:
	LD	B,(IY+2)		; GET  CHIP/CHANNEL
	SRL	B			; SHIFT AWAY THE CHANNEL BIT
	INC	B			; NUMBER OF TIMES TO ROTATE BITS
	LD	A,(PIO_MAP)		; BIT MAP IN A
PIO_DETECT1:
	; ROTATE DESIRED CHIP BIT INTO CF
	RRA				; ROTATE NEXT BIT INTO CF
	DJNZ	PIO_DETECT1		; DO THIS UNTIL WE HAVE DESIRED BIT
	; RETURN CHIP TYPE
	LD	A,PIO_NONE		; ASSUME NOTHING HERE
	RET	NC			; IF CF NOT SET, RETURN
	LD	A,PIO_PIO		; CHIP TYPE IS PIO
	RET				; DONE
;
;
;
PIO_PRTCFG:
	; ANNOUNCE PORT
	CALL	NEWLINE			; FORMATTING
	PRTS("PIO$")			; FORMATTING
	LD	A,(IY)			; DEVICE NUM
	CALL	PRTDECB			; PRINT DEVICE NUM
	PRTS(": IO=0x$")		; FORMATTING
	LD	A,(IY+3)		; GET BASE PORT
	CALL	PRTHEXBYTE		; PRINT BASE PORT

	; PRINT THE PIO TYPE
	CALL	PC_SPACE		; FORMATTING
	LD	A,(IY+1)		; GET PIO TYPE BYTE
	RLCA				; MAKE IT A WORD OFFSET
	LD	HL,PIO_TYPE_MAP		; POINT HL TO TYPE MAP TABLE
	CALL	ADDHLA			; HL := ENTRY
	LD	E,(HL)			; DEREFERENCE
	INC	HL			; ...
	LD	D,(HL)			; ... TO GET STRING POINTER
	CALL	WRITESTR		; PRINT IT
;
	XOR	A
	RET
;
;
;
PIO_TYPE_MAP:
	.DW	PIO_STR_NONE
	.DW	PIO_STR_PIO

PIO_STR_NONE	.DB	"<NOT PRESENT>$"
PIO_STR_PIO	.DB	"PIO$"
;
; WORKING VARIABLES
;
PIO_DEV		.DB	0		; DEVICE NUM USED DURING INIT
PIO_MAP		.DB	0		; CHIP PRESENCE BITMAP
;
PIO0A_RCVBUF	.EQU	0
PIO0B_RCVBUF	.EQU	0
;
#IF (PIOCNT >= 2)
PIO1A_RCVBUF	.EQU	0
PIO1B_RCVBUF	.EQU	0
#ENDIF
;
; PIO PORT TABLE
;
PIO_CFG:
	; PIO0 CHANNEL A
PIO0A_CFG:
	.DB	0			; DEVICE NUMBER (SET DURING INIT)
	.DB	0			; PIO TYPE (SET DURING INIT)
	.DB	$00			; CHIP 0 / CHANNEL A (LOW BIT IS CHANNEL)
	.DB	PIO0A_CTL		; CMD/STATUS PORT
	.DB	PIO0A_DAT		; DATA PORT
	.DW	DEFSERCFG		; LINE CONFIGURATION
	.DW	PIO0A_RCVBUF		; POINTER TO RCV BUFFER STRUCT
;
	DEVECHO	"PIO: IO="
	DEVECHO	PIO0BASE
	DEVECHO	", CHANNEL A\n"
;
PIO_CFGSIZ	.EQU	$ - PIO_CFG	; SIZE OF ONE CFG TABLE ENTRY
;
	; PIO0 CHANNEL B
PIO0B_CFG:
	.DB	0			; DEVICE NUMBER (SET DURING INIT)
	.DB	0			; PIO TYPE (SET DURING INIT)
	.DB	$01			; CHIP 0 / CHANNEL B (LOW BIT IS CHANNEL)
	.DB	PIO0B_CTL		; CMD/STATUS PORT
	.DB	PIO0B_DAT		; DATA PORT
	.DW	DEFSERCFG		; LINE CONFIGURATION
	.DW	PIO0B_RCVBUF		; POINTER TO RCV BUFFER STRUCT
;
	DEVECHO	"PIO: IO="
	DEVECHO	PIO0BASE
	DEVECHO	", CHANNEL B\n"
;
#IF (PIOCNT >= 2)
;
	; PIO1 CHANNEL A
PIO1A_CFG:
	.DB	0			; DEVICE NUMBER (SET DURING INIT)
	.DB	0			; PIO TYPE (SET DURING INIT)
	.DB	$02			; CHIP 1 / CHANNEL A (LOW BIT IS CHANNEL)
	.DB	PIO1A_CTL		; CMD/STATUS PORT
	.DB	PIO1A_DAT		; DATA PORT
	.DW	DEFSERCFG		; LINE CONFIGURATION
	.DW	PIO1A_RCVBUF		; POINTER TO RCV BUFFER STRUCT
;
	DEVECHO	"PIO: IO="
	DEVECHO	PIO1BASE
	DEVECHO	", CHANNEL A\n"
;
	; PIO1 CHANNEL B
PIO1B_CFG:
	.DB	0			; DEVICE NUMBER (SET DURING INIT)
	.DB	0			; PIO TYPE (SET DURING INIT)
	.DB	$03			; CHIP 1 / CHANNEL B (LOW BIT IS CHANNEL)
	.DB	PIO1B_CTL		; CMD/STATUS PORT
	.DB	PIO1B_DAT		; DATA PORT
	.DW	DEFSERCFG		; LINE CONFIGURATION
	.DW	PIO1B_RCVBUF		; POINTER TO RCV BUFFER STRUCT
;
	DEVECHO	"PIO: IO="
	DEVECHO	PIO1BASE
	DEVECHO	", CHANNEL B\n"
;
#ENDIF
;
PIO_CFGCNT	.EQU	($ - PIO_CFG) / PIO_CFGSIZ
