;       SCCSID = @(#)demcon.asm	6.1 91/07/12
;       SCCSID = @(#)demcon.asm	6.1 90/11/17
;	SCCSID = @(#)dos3con.asm	12.9 89/04/18
	TITLE	MSCON - Real Mode Console Driver for CP-DOS
	NAME	MSCON

	page	,132

;***	MSCON - Console driver for 3x box in CP-DOS
;
;	Copyright (C) Microsoft Corp. 1982, 1983, 1984, 1985
;
;	Rajen J. Shah
;
;
.xlist
include v86seg.inc
include basemaca.inc
include osmaca.inc
include oldmaca.inc
include demmac.inc
include devsym.inc
include error.inc
include dossymc.inc
	.SFCOND
	.LALL
.list

	    ReferV86	fHaveK09

V86DATA	    SEGMENT

PTRSAV	    DD	    ?
ALTAH	    DB	    0

PUBLIC	    KEYRD_Func, KEYSTS_Func
KEYRD_Func  DB	    0
KEYSTS_Func DB	    1
OLDINT10    DW	    0,0 		;INT 10h vector at time of INIT

V86DATA	    ENDS


V86CODE	   SEGMENT
	ASSUME	    CS:V86GROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING

;
	PUBLIC	CONDEV
CONDEV	dd	-1		    ; End of list
	dw	DEV_CIN OR DEV_CHAR_DEV OR DEV_COUT OR DEVLEV_0 OR DEV_SPEC
	dw	OFFSET V86GROUP:ConStrat
	dw	OFFSET V86GROUP:ConInt
	db	"CON     "

ConJmpTbl   LABEL   WORD
	dw	OFFSET V86GROUP:ConInit 	;  0  Initialization - do nothing
	dw	OFFSET V86GROUP:CON$EXIT	;  1  Media Check
	dw	OFFSET V86GROUP:CON$EXIT	;  2  Build BPB
	dw	OFFSET V86GROUP:CON$EXIT	;  3  Reserved
	dw	OFFSET V86GROUP:CON$READ	;  4  Input (Read)
	dw	OFFSET V86GROUP:CON$RDND	;  5  Non-Destructive read, no wait
	dw	OFFSET V86GROUP:CON$EXIT	;  6  Input Status
	dw	OFFSET V86GROUP:CON$FLSH	;  7  Input Flush
	dw	OFFSET V86GROUP:CON$WRIT	;  8  Output (Write)
	dw	OFFSET V86GROUP:CON$WRIT	;  9  Output with verify
	dw	OFFSET V86GROUP:CON$EXIT	; 10  Output Status
sConJmpTbl  EQU ($-ConJmpTbl) / 2



ConStrat PROC	FAR
	MOV	WORD PTR [PTRSAV],BX
	MOV	WORD PTR [PTRSAV+2],ES
	RET
ConStrat ENDP


	BREAK	<ConInt>
;***	ConInt - Device Driver "Interrupt" Entry point
;
;	ENTRY	PTRSAV	points to Request packet
;	EXIT	Through CON$EXIT
;	USES	AX, SI
;

ConInt	PROC	FAR
	cld
	pusha
	push	ds
	push	es
	push	cs
	pop	ds
	ASSUME	DS:V86GROUP
	les	bx,PTRSAV
	mov	al,es:[bx].PktCmd
	cmp	al,sConJmpTbl
	ja	short CmdErr
	xor	ah,ah
	shl	ax,1
	mov	si,ax			;SI = transfer table offset
	mov	al,es:[bx].PktUnit	;AL = Unit code
	mov	ah,es:[bx].IOmedia	;AH = Media descriptor
	mov	cx,es:[bx].IOcount	;CX = Count
	mov	dx,es:[bx].IOstart	;DX = Start sector
	les	di,es:[bx].IOpData	;ES:DI = address of data
	jmp	ConJmpTbl[SI]
CmdErr:
	mov	al,ERROR_I24_BAD_COMMAND ; Unknown command error
	mov	es:[bx].IOcount,0
	jmp	short ERR1
ConInt	ENDP


	BREAK	<Keyboard interface routines>

CON$READ PROC	FAR
	jcxz	con$exit
CON$LOOP:
	call	CHRIN			;get char in AL
	stosb				;store char at ES:DI
	loop	CON$LOOP
CON$EXIT:
	mov	ah,00000001B
ERR1:
	lds	bx,cs:[PTRSAV]
	ASSUME	DS:NOTHING
	mov	word ptr [bx].PktStatus,ax ;mark operation complete

Con$Exit2:
	pop	es
	pop	ds
	popa
	ret				;restore regs and return
CON$READ ENDP

CONBUS	PROC   FAR
	ASSUME	DS:NOTHING
	mov	ah,00000011B
	jmp	short ERR1
CONBUS	ENDP


;---------------------------------------------------------
;
;	INPUT SINGLE CHAR INTO AL
;
;J.K.5/12/87 We are going to issue extended keyboard function, if supported.
;The returning value of the extended key stroke of the extended key board
;function uses 0E0h in AL instead of 00 as in the conventional key board
;function.  This creates a conflict when the user entered real Greek Alpha
;charater (= 0E0h) to  distinguish the extended key stroke and the Greek Alpha.
;This case will be handled in the following manner;
;	AH = 16h
;	INT 16h
;	If AL == 0, then extended code (in AH)
;  else If AL == 0E0h, then
;	     IF AH <> 0, then extended code (in AH)
;	else Greek_Alpha character.
;Also, for compatibility reason, if an extended code is detected, then we
;are going to change the value in AL from 0E0h to 00h.

	ASSUME	DS:V86GROUP

CHRIN	PROC	NEAR
;AN000;
;	xor	ax,ax
	mov	ah,KEYRD_Func		;AN000; Set by MSINIT. 0 or 10h
	xor	al,al			;AN000;
	xchg	al,ALTAH		;get character & zero ALTAH

	or	al,al
	jnz	KEYRET
;SB34CON000**************************************************************
;SB  Keyboard I/O interrupt
;SB	AH already contains the keyboard read function number
;SB		1 LOC

	int	16h
;SB34CON000**************************************************************
ALT10:
	or	ax,ax			;check for non-key after break
	jz	CHRIN
	cmp	ax,7200H		;check for Ctrl-Prtsc
	jnz	ALT_Ext_Chk		;AN000;
	mov	al,16
	jmp	KeyRet			;AN000;

ALT_Ext_Chk:
;SB34CON001**************************************************************
;SB  IF operation was extended function (i.e. KEYRD_Func != 0) THEN
;SB    IF character read was 0E0h THEN
;SB	 IF extended byte was zero (i.e. AH == 0) THEN
;SB	   goto keyret
;SB	 ELSE
;SB	   set AL to zero
;SB	   goto ALT_SAVE
;SB	 ENDIF
;SB    ENDIF
;SB  ENDIF
;SB		9 LOCS

	cmp	BYTE PTR KEYRD_Func,0
	jz	NOT_EXT
	cmp	al,0E0h
	jnz	NOT_EXT
	or	ah,ah
	jz	KEYRET
	xor	al,al
	jmp	short ALT_SAVE
NOT_EXT:

;SB34CON001**************************************************************
	OR	AL,AL			;SPECIAL CASE?
	JNZ	KEYRET
ALT_SAVE:
	MOV	ALTAH,AH		;STORE SPECIAL KEY
KEYRET:
	RET
CHRIN	ENDP

;--------------------------------------------------------------
;
;	KEYBOARD NON DESTRUCTIVE READ, NO WAIT
;
; PC-CONVERTIBLE-TYPE MACHINE: IF BIT 10 IS SET BY THE DOS IN THE STATUS WORD
; OF THE REQUEST PACKET, AND THERE IS NO CHARACTER IN THE INPUT BUFFER, THE
; DRIVER ISSUES A SYSTEM WAIT REQUEST TO THE ROM. ON RETURN FROM THE ROM, IT
; RETURNS A 'CHAR-NOT-FOUND' TO THE DOS.
;
;CONBUSJ:
;	 JMP	 CONBUS
CONBUSJ EQU	CONBUS

	ASSUME DS:V86GROUP	    ; THIS WAS SET BY THE CON DD ENTRY POINT
CON$RDND:
	MOV	AL,[ALTAH]
	OR	AL,AL
	JZ	RD1
	JMP	RDEXIT

RD1:
;SB34CON002**************************************************************
;SB  Keyboard I/O interrupt
;SB	Get keystroke status (KEYSTS_Func)
;SB	 2 LOCS

	mov	ah,KEYSTS_Func
	int	16h
;SB34CON002**************************************************************
	JZ	NOCHR
	JMP	GOTCHR
NOCHR:
	CMP	FHAVEK09,0
	JZ	CONBUSJ
	LDS	BX,[PTRSAV]
	ASSUME	DS:NOTHING
	TEST	[BX].PktStatus,0400H	   ; SYSTEM WAIT ENABLED?
	JZ	CONBUSJ
;********************************
; NEED TO WAIT FOR IBM RESPONSE TO REQUEST FOR CODE ON HOW TO USE THE SYSTEM
; WAIT CALL.
;********************************
;	 MESSAGE FTESTCON,<"SYSTEM WAIT STAGE",CR,LF>
	MOV	AX,4100H		; WAIT ON AN EXTERNAL EVENT
	INT	15H			; CALL ROM FOR SYSTEM WAIT
;	 MESSAGE FTESTCON,<"OUT OF WAIT. AX IS ">
;	 MNUM	 FTESTCON,AX
;	 MESSAGE FTESTCON,<CR,LF>
	JMP	CONBUS

	ASSUME	DS:V86GROUP
GOTCHR:
	OR	AX,AX
	JNZ	NOTBRK			;CHECK FOR NULL AFTER BREAK
;SB34CON004**************************************************************
;SB  Keyboard I/O interrupt
;SB	Keyboard read function (KEYRD_Func)
;SB		2 LOCS

	mov	ah,KEYRD_Func
	int	16h
;SB34CON004**************************************************************
	JUMP	CON$RDND		;AND GET A REAL STATUS
NOTBRK:
	CMP	AX,7200H		;CHECK FOR CTRL-PRTSC
	JNZ	RD_Ext_Chk		;AN000;
	MOV	AL,16
	jmp	RDEXIT			;AN000;
RD_Ext_Chk:				;AN000;
	cmp	KEYRD_Func, 0		;AN000; Extended Keyboard function?
	jz	RDEXIT			;AN000; No. Normal exit.
	cmp	al,0E0h			;AN000; Extended key value or Greek Alpha?
	jne	RDEXIT			;AN000;
	cmp	ah, 0			;AN000; Scan code exist?
	jz	RDEXIT			;AN000; Yes. Greek Alpha char.
	mov	al, 0			;AN000; No. Extended key stroke. Change it for compatibility
RDEXIT:
	LDS	BX,[PTRSAV]
	ASSUME	DS:NOTHING
	MOV	[BX].IOMedia,AL
EXVEC:
	JMP    CON$EXIT

;--------------------------------------------------------------
;
;	KEYBOARD FLUSH ROUTINE
;
	ASSUME DS:V86GROUP		 ; THIS WAS SET BY THE CON DD ENTRY POINT
CON$FLSH:
	CALL	FLUSH
	JUMP	CON$EXIT

FLUSH:
	MOV	[ALTAH],0		;CLEAR OUT HOLDING BUFFER

FLLOOP:
;SB33012****************************************************************
			 ;SB	; Is there a char there?
	mov	AH, 1	 ;SB	; command code for check status
	int	16h	 ;SB	; call rom-bios keyboard routine
;SB33012****************************************************************
	JZ	FLDONE
;SB33013****************************************************************
	xor	AH, AH	 ;SB	; if zf is nof set, get character
	int	16h	 ;SB	; call rom-bios to get character
;SB33013****************************************************************
	JMP	FLLOOP
FLDONE:

	RET

;-------------------------------------------------------------
;
;	CHROUT - WRITE OUT CHAR IN AL USING CURRENT ATTRIBUTE
;
;	CALLED VIA INT 29H
;
CHROUT	=	29H

OUTCHR	PROC	FAR
	sti
	push	ax
	push	si
	push	di
	push	bp
	push	bx
	mov	AH,0Eh			;set command to write a character
	mov	BX,7			;set foreground color
	int	10h			;call rom-bios
	pop	bx
	pop	bp
	pop	di
	pop	si
	pop	ax
	iret
OUTCHR	ENDP


;----------------------------------------------------------
;
;	CONSOLE WRITE ROUTINE
;
CON$WRIT:
	jcxz	EXVEC
	mov	bx,[OLDINT10]
	mov	dx,[OLDINT10+2] 	;DX:BX is original INT 10h vector
	sub	ax,ax
	mov	ds,ax
	cmp	bx,ds:[10h*4]		;offsets match?
	jne	conwrite_loop		;no
	cmp	dx,ds:[10h*4+2] 	;segments match?
	jne	conwrite_loop		;no

; Make FAST output call to ROM BIOS (in reality, Video VDD)

; Note that it is a private INT 10h call, not a standard WRITESTRING call,
; which is why we only issue it as long as the INT 10h remains unhooked.  None
; of the standard WRITESTRING services allow us to use the attributes that
; are already on the screen, which is why we have to use something a little
; special.... -JTP

	mov	bp,di			;ES:BP -> string
	mov	ax,13FFh		;AH = WRITESTRING, AL = subfunction
	int	10h			;CX = char count (must be NONZERO)
	or	al,al			;success?
	jz	conwrite_loop		;no, special WRITESTRING is disabled
	jmp	CON$EXIT

conwrite_loop:
	mov	al,es:[di]		;get char
	inc	di
	int	CHROUT			;output char
	loop	conwrite_loop		;repeat until all through
	jmp	CON$EXIT


;-----------------------------------------------
;
;	Break key handling
;
CBREAK:
	mov	cs:ALTAH,3		;indicate break key set

INTRET:
	iret


;***	ConInit - Init the Console device driver.
;
;	Hooks the Ctrl-Break handler into the int1B chain.
;
;	ENTRY:	none
;	EXIT:	none
;	USES:	AX, ES

Procedure ConInit
	xor	ax,ax
	mov	es,ax
	mov	word ptr es:[1Bh*4],offset V86GROUP:CBREAK
	mov	word ptr es:[1Bh*4+2],CS
	mov	word ptr es:[CHROUT*4],offset V86GROUP:OUTCHR
	mov	word ptr es:[CHROUT*4+2],CS
	mov	ax,es:[10h*4]
	mov	[OLDINT10],ax
	mov	ax,es:[10h*4+2]
	mov	[OLDINT10+2],ax
	jmp	Con$Exit2
Endproc   ConInit

V86CODE ENDS

	END
