TITLE kbdio.asm ---  Keyboard I/O support program
;-----------------------------------------------------
stack	segment para stack 'stack'
	db	256  dup(0)
stack	ends
;-----------------------------------------------------
data	segment	para public 'data'
buffer	db	16h dup (0)
bufpt1	dw	0
bufpt2	dw	0
; bufpt1 = bufpt2 , the buffer is empty 
kbflag	db	0
prompt	db '--- kbd_io program begin ---',0dh,0ah,'$'
scantab	db 0,0,'1234567890-=',8,0
	db 'qwertyuiop[]',0dh,0
	db 'asdfghjkl;',0,0,0,0
	db 'zxcvbnm,./',0,0,0
	db ' ',0,0,0,0,0,0,0,0,0,0,0,0,0
	db '789-456+1230.'
even
oldcs9  dw  ?
oldip9  dw  ?
data	ends
;-----------------------------------------------------
code	segment	para	public	'code'
start	proc	far
	assume	cs:code, ds:data
	push	ds		;save for return
	mov	ax,0
	push	ax
	mov	ax,data		;set DS to data seg
	mov	ds,ax

	cli
	mov	al,09		;save interrupt vector
	mov	ah,35h		;  of KBD BIOS routing
	int	21h
	mov	oldcs9,es
	mov	oldip9,bx

	push	ds		;set interrupt vector
	mov	dx,offset kbint	;  of kbint
	mov	ax,seg kbint
	mov	ds,ax
	mov	al,09
	mov	ah,25h
	int	21h
	pop	ds

	in	al,21h		;set kbd interrupt
	and	al,0fdh		;  mask bit
	out	21h,al

	mov	dx,offset prompt
	mov	ah,9
	int	21h
	sti
forever:
	call	kbget		;wait enter a key
	test	kbflag,80h
	jnz	endint
	push	ax
	call	dispchar	;display the character
	pop	ax
	cmp	al,0dh
	jnz	forever
	mov	al,0ah
	call	dispchar	;display CR/LF
	jmp	forever		;loop for continue
endint:	
	mov	dx,oldip9	;  interrupt vector
	mov     ax,oldcs9
	mov	ds,ax		;restore old
	mov	al,09h
	mov	ah,25h
	int	21h

	ret	
start	endp
;-----------------------------------------------------
kbget	proc	near
	push	bx
	cli			;interrupt back off
	mov	bx,bufpt1	;get pointer to head 
	cmp	bx,bufpt2	;test empty of buffer
	jnz	kbget2		;no,fetch a character
	cmp	kbflag,0
	jnz	kbget3
	sti		;allow an interrupt to occur
	pop	bx
	jmp	kbget	;loop until something in buf
kbget2:
	mov	al,[buffer+bx]	;get ascii code
	inc	bx		;inc a buffer pointer
	cmp	bx,16		;at end of buffer ?
	jc	kbget3		;no,continue
	mov	bx,0		;reset to buf beginning
kbget3:
	mov	bufpt1,bx	;store value in variable
	pop	bx
	ret
kbget	endp
;-----------------------------------------------------
kbint	proc	far	  ;keyboard interrupt routine
	push	bx
	push	ax

	in	al,60h		;read in the character
	push	ax		;save it
	in	al,61h		;get the control port
	or	al,80h	  ;set acknowledge bit for kbd
	out	61h,al
	and	al,7fh	  ;reset acknowledge bit
	out	61h,al

	pop	ax	  ;recover scan code
	test	al,80h	  ;is press or release code?
	jnz	kbint2    ;is release code,return
	mov	bx,offset scantab
	xlat	scantab		;ascii code to AL
	cmp	al,0
	jnz	kbint4
	mov	kbflag,80h
	jmp	kbint2
kbint4:
	mov	bx,bufpt2	;buffer tail pointer
	mov	[buffer+bx],al	;ASCII fill in buffer
	inc	bx
	cmp	bx,16		;is end of buffer?
	jc	kbint3		;no
	mov	bx,0		;reset to buf beginning
kbint3:
	cmp	bx,bufpt1	;is buffer full?
	jz	kbint2		;yes, lose character
	mov	bufpt2,bx	;save buf tail pointer
kbint2: cli
	mov	al,20h		;end of interrupt
	out	20h,al
	pop	ax
	pop	bx
	sti
	iret			;interrupt return
kbint	endp
;-----------------------------------------------------
dispchar  proc  near		;(AL)=displaying char. 
	push	bx
	mov	bx,0
	mov	ah,0eh
	int	10h		;call video routine
	pop	bx
	ret
dispchar  endp
;-----------------------------------------------------
code	ends			;end of code segment
	end	start

	