;IODVR/ASM - LS-DOS 6.2
	SUBTTL	'<Device I/O handling>
	PAGE	OFF
;
HOME	EQU	1CH
CLRFRM	EQU	1FH
;
;	Log out routine - display & log
;
@LOGOT	CALL	@DSPLY
;
;	Job log loger routine
;
@LOGER	LD	A,(JLDCB$)	;If NIL, don't do
	XOR	8		;  anything
	AND	8
	RET	Z
	PUSH	HL		;Save pointer to command
	LD	HL,LOGBUF	;Get time string into buf
	PUSH	HL
	CALL	@TIME
	POP	HL
	LD	DE,JLDCB$	;Log the time
	CALL	@MSG
	POP	HL		;Log the command
	JR	@MSG
LOGBUF	DB	'hh:mm:ss  ',3
;
;	Line print routine
;
@PRINT	LD	DE,PRDCB$	;Printer DCB
	JR	@MSG
;
;	Line display routine
;
@DSPLY	LD	DE,DODCB$	;Video DCB
;
;	Device message routine
;
*MOD
@MSG	PUSH	HL		;Save pointer to message
$?1	LD	A,(HL)		;P/u a message character
	CP	3		;Exit on ETX
	JR	Z,$?3
	CP	CR		;Exit & put on ENTER
	JR	Z,$?2
	CALL	NZ,@PUT		;Else put the char
	INC	HL		;  & loop on no error
	JR	Z,$?1		;  else fall thru & exit
$?2	CALL	Z,@PUT
$?3	POP	HL
	RET
;
;	Clear screen routine
;
@CLS	LD	A,HOME		;Cursor home to 0,0
	CALL	DSPBYT
	RET	NZ		;Return on error
	LD	A,CLRFRM	;Clear to end of frame
DSPBYT	PUSH	DE
	CALL	@DSP
	POP	DE
	RET
;
;	Check and Clear <BREAK> bit SVC
;
@CKBRKC
	PUSH	HL		;Save registers
	LD	HL,KFLAG$	;Point to KFLAG$
	BIT	0,(HL)		;Check break bit
	JR	Z,NOBRK		;  and ret if none
	PUSH	AF		;Save flags
	PUSH	BC
	PUSH	DE
BRKTEST	RES	0,(HL)		;Reset the break bit
	LD	BC,0B00H	;Wait more than 1/30
	CALL	PAUSE@		;  of a second
	BIT	0,(HL)		;Test the bit again
	JR	NZ,BRKTEST	;Loop until gone
	LD	DE,KIDCB$	;Point at keyboard &
	LD	A,03		;  clear buffer with
	CALL	@CTL		;  control 3 call
	POP	DE
	POP	BC		;Recover registers
	POP	AF		;Recover FLAGS
NOBRK	POP	HL
	RET
;
;	Keyboard line input routine
;
*MOD
;
;	Backspace to beginning of line
;
$?4	CALL	$?6		;Backspace
	DEC	HL		;Get the char prior
	LD	A,(HL)		;  to the current
	INC	HL
	CP	0AH		;Return if line feed
	RET	Z
$?5	LD	A,B		;Check for empty buffer
	CP	C
	JR	NZ,$?4		;Loop if not
	RET			;  else return
@KEYIN	PUSH	HL		;Save buffer pointer
	LD	C,B		;Set C = buffer size
$?1	LD	DE,@KEY		;Init for standard input
	LD	A,(SFLAG$)	;If JCL is active,
	AND	20H		;  then use the JCL input
	JR	Z,$?0		;Must loop here in case
	LD	E,@JCL&0FFH	;  JCL exits with //STOP
$?0	LD	($?1A+1),DE
$?1A	CALL	$-$		;Get a key
	JR	NZ,$?3B		;Back on error
	CP	80H		;Break?
	JR	Z,$?10
	CP	20H		;Go if not a control
	JR	NC,$?2
	CP	0DH		;Carriage return?
	JR	Z,$?11
	CP	1FH		;Clear?
	JR	Z,$?3
	LD	DE,$?1		;Set return address
	PUSH	DE
	CP	08H		;Backspace?
	JR	Z,$?6
	CP	18H		;Backspace to BOL?
	JR	Z,$?5
	CP	09H		;Tab?
	JR	Z,$?8
	CP	'R'&1FH		;CTL-R?
	JR	Z,$?7
	CP	0AH		;Line feed?
	RET	NZ		;Ret if none above
	POP	DE		;Pop the return
$?2	LD	(HL),A		;Stuff the char
	LD	A,B		;Check on buffer full
	OR	A
	JR	Z,$?1		;Loop if so
	LD	A,(HL)		;  else get char
	INC	HL		;  & bump pointer
	DEC	B		;Count down
	CALL	@DSP		;Display entry
	JR	$?3A		;  then loop
;
;	Clear the screen invoked
;
$?3	CALL	@CLS
	LD	B,C		;Reset to start of
	POP	HL		;  line & start of
	PUSH	HL		;  buffer
$?3A	JR	Z,$?1
$?3B	JR	$?11
;
;	Backspace key entry
;
$?6	LD	A,B		;If buffer is empty,
	CP	C		;  return
	RET	Z
	DEC	HL		;  else do the backspace
	LD	A,(HL)
	CP	0AH		;Last char a linefeed?
	INC	HL
	RET	Z		;Return if so
	DEC	HL
	INC	B		;Add back one char
	LD	A,8		;Backspace the cursor
	JR	@DSP
;
;	Test if repeat last command
;
$?7	LD	A,(CFLAG$)	;Test if SYS1 KEYIN bit
	AND	4		;  is set (bit 2)
	RET	Z		;Ignore CTL if not
	LD	A,B		;If not at 1st position,
	CP	C		;  don't permit it
	RET	NZ
	POP	HL		;Pop return to KEY
	POP	HL		;Point to command buffer
	JP	@DSPLY		;Display the old command
;
;	Tab entered
;
$?8	PUSH	HL		;Get pos on line
	CALL	ADDR_2_ROWCOL	;Get row,col in HL
	LD	A,L		;Xfer column to A
	POP	HL
	AND	7
	NEG			;Negate and add tab
	ADD	A,8
	LD	E,A		;Reg E has tab length
$?9	LD	A,B		;Check on buffer full
	OR	A
	RET	Z
	LD	A,' '		;Put spaces until
	LD	(HL),A		;  tab expanded
	INC	HL
	CALL	DSPBYT
	RET	NZ
	DEC	B		;Dec buffer remaining
	DEC	E		;Dec tab count
	RET	Z
	JR	$?9
;
;	Exit KEYIN routine
;
$?10	SCF			;BREAK exit with CF
$?11	PUSH	AF		;Save flag
	LD	A,0DH		;Stuff CR at end
	LD	(HL),A
	CALL	@DSP		;  & display it
	LD	A,C		;Calculate # of chars
	SUB	B		;  entered
	LD	B,A
	POP	AF		;Rcvr flag
	POP	HL		;Restore buffer ptr
	RET
;
;	Byte I/O device handler
;		C => character if PUT or CTL
;		DE => Device control block
;
*MOD
@CTL	PUSH	BC
	LD	B,4		;Bit 2, CTL
	JR	IOBGN
@KEY	CALL	@KBD		;Scan the keyboard
	RET	Z		;Ret if key available
	OR	A		;Return if error
	JR	Z,@KEY
	RET
@JCL	LD	DE,JCLCB$	;JCL file FCB
	JR	@GET
@KBD	LD	DE,KIDCB$	;Keyboard DCB
@GET	PUSH	BC
	LD	B,1		;Bit 0, GET
	JR	IOBGN
@PRT	LD	DE,PRDCB$	;Printer DCB
	JR	@PUT
@DSP	LD	DE,DODCB$	;Video DCB
@PUT	PUSH	BC
	LD	B,2		;Bit 1, PUT
IOBGN	PUSH	IX		;Save the registers
	PUSH	HL
	PUSH	DE		;Xfer DCB to IX
	POP	IX
	PUSH	DE
	LD	C,A		;Xfer the I/O char
	LD	HL,@RSTREG	;Restore register routine
	LD	A,(LBANK$)	;If bank 0 is not
	OR	A		;  resident, need to
	JR	Z,$?0		;  get it resident!
;
;	Some other bank is resident - invoke bank 0
;
	PUSH	BC		;Save reg again
	XOR	A		;Prepare for bank-0
	LD	B,A
	LD	C,A
	CALL	@BANK		;Invoke bank-0
	LD	H,B		;Get old bank data
	LD	L,C		;  into reg HL
	POP	BC		;Rcvr BC
	PUSH	HL		;Bank data to stack
	LD	HL,RSTBNK	;Set return address
$?0	PUSH	HL		;  to restore registers
	LD	A,(DE)		;P/u DCB type byte
	OR	A
	RET	Z		;Back if nothing
	CP	8		;Ck on GET/PUT/CTL
	JR	NC,@CHNIO	;Branch if special
	LD	L,(IX+1)	;  else p/u the vector
	LD	H,(IX+2)
$?1	LD	A,B		;Xfer I/O code
	CP	2		;Set flags state
	JP	(HL)
RSTBNK	POP	BC		;Get old bank data
	PUSH	AF		;Can't affect AF
	LD	A,C		;Request to A
	CALL	@BANK		;Bring back original bank
	POP	AF
@RSTREG	POP	DE		;Restore regs
	POP	HL
	POP	IX
	POP	BC
	RET
;
$?2	PUSH	HL
	POP	IX
@CHNIO	LD	L,(IX+1)	;P/u vector address
	LD	H,(IX+2)
$?3	LD	A,(IX+0)	;P/u the DCB type
	OR	A		;File Control Block?
	JP	M,@BYTEIO
	BIT	3,A		;Test NIL bit 2nd
	JR	NZ,$?5
	BIT	4,A		;Routed?
	JR	NZ,$?2		;Go get routed DCB
	BIT	5,A		;If not linked, then
	JR	Z,$?1		;  must be filtered
	PUSH	HL		;Point to the link DCB
	POP	IX
	LD	(IX+3),B	;Save the direction
	PUSH	IX
	CALL	@CHNIO		;I/O to 1st device
	POP	IX
	LD	B,(IX+3)	;P/u the direction
	JR	NZ,$?6		;Go on NZ flag
;
;	Z-flag on return - check input/output
;
	BIT	0,B		;If input & got char,
$?4	LD	L,(IX+4)	;  p/u the linked DCB
	LD	H,(IX+5)
	JR	Z,$?2
$?5	CP	A
	RET
;
;	1st link got NZ condition - if input, get link
;
$?6	BIT	0,B		;Was it input/output?
	JR	Z,$?7		;Output is error
	OR	A		;If A=0, then no input
	JR	Z,$?4
$?7	OR	A
	RET
