		.286c
.xlist
		include	biosdata.asm
.list
;*********************************************************************
;
;               K E Y B O A R D   I / O
;
;        
;       These routines provide the keyboard interfice for the Slicer
;       using the the Slicer PC expansion board, and are accessed using
;       INT 16H.
;
;       AH = 0:   Read next ASCII charecter from keyboard.
;            Return result in AL, with scan code in AH.
;	     
;      AH = 1:   Set Z flag to indicate if an ascii character is
;           available to be read.
;           ZF = 1 No code ready
;           ZF = 0 code ready and in ax.
;
;      AH = 2:   Return shift status in AL.
;
;      AH = FF:  Return 8 bit charecter in AL.
;           If non-ASCII zero is returned then on next call the scan code
;
;      AH = FE:  Set bits on port 300h.
;           AL = mask of bits to set.
;
;      AH = FD:  Clear bits on port 300h.
;           AL = Mask of bits to clear.
;*********************************************************************

b		equ	byte ptr
w		equ	word ptr
uart_base	equ	80h
uart_input	equ	uart_base+1ah
use_keyboard	equ	20h
port_status_v	equ	11110111b	;set ibm io channel to b0000

keyboard_port	equ   	300h		;CAN BE CHANGED TO 60 WITH BIOS.ASM
clock_line	equ	40h
data_line	equ	80h
num_key		equ	69
scroll_key	equ	70
alt_key		equ	56
ctl_key		equ	29
caps_key	equ	58
left_shift	equ	42
right_shift	equ	54
ins_key		equ	82
del_key		equ	83
reset_code	equ	0aah
alt_key_rel	equ	alt_key+80h
ctl_key_rel	equ	ctl_key+80h
left_shift_rel	equ	left_shift+80h
right_shift_rel	equ	right_shift+80h
ins_mask	equ	80h
caps_mask	equ	40h
num_mask	equ	20h
scroll_mask	equ	10h
alt_mask	equ	8
ctl_mask	equ	4
left_mask	equ	2
right_mask	equ	1
nshiftkey_mask	equ	1
;	 					
;
intcr		equ	0ff3ch
eoir		equ	0ff22h
eoiv		equ	8000h
intcrv		equ	15h		;priority 5 level trigered
intcr_mask	equ	0fh
break_int	equ	01bh
;
;
		extrn	initialize:near
		public	new_keyboard
		public	keyboard_init

set1		macro	num,val
		mov	w num,offset val
		mov	w num+2,seg val
		endm


cgroup		group	code

code		segment	public byte 'code'
		assume	cs:cgroup,es:vectors,ds:data
;
;      Install is called on power up to initialize the interupt vectors,
;      and initialize the keyboard.
;
keyboard_init	proc	near
		xor	ax,ax
		mov	es,ax
		set1	vector_9,interupt
		set1	vector_e,interupt2
		set1	vector_1b,interupt1		;iret
		mov	buffer_tail,offset kb_buffer
		mov	buffer_head,offset kb_buffer
		mov	byte_flag,0
		mov	dx,intcr
		mov	ax,intcrv
		out	dx,ax
		mov	port_status,port_status_v
		mov	dx,keyboard_port

		mov	al,port_status
		or	al,data_line
		and	al,not clock_line	;data line high clock line low
		out	dx,al
		mov	port_status,al
		mov	cx,30000
delay:		loop	delay		;20 ms delay(actually quite a bit more)
		mov	al,port_status
		or	al,clock_line
		and	al,not data_line	;data line low clock line high

		out	dx,al

		or	al,data_line		;data line high
		out	dx,al
		mov	port_status,al
		mov	shift_status,left_mask		;left_shift_rel=0aah
		mov	key_int_enable,0ffh		;let only one interupt happen
		xor	cx,cx
		sti
reset_loop:	test	shift_status,left_mask
		loopnz	reset_loop
		jnz	no_install
		mov	key_int_enable,0		;let all interupts through
		mov	dx,intcr
		mov	ax,intcrv
		out	dx,ax				;re enable interupts

		set1	vector_16,keyboard_io
		mov	b device_numbers+(2*010h),7

		in	al,uart_input		;install keyboard in new call system
		test	al,use_keyboard
		jz	no_install1
		mov	b device_numbers+(2*6),7
						;install keyboard as con inupt
		 mov	key_status2,0	   ;Jonathan for ctrl numlock pause

no_install1:
		ret
no_install:
		mov	dx,intcr
		mov	ax,intcr_mask
		out	dx,ax
		ret
keyboard_init	endp
		assume	es:nothing
;
;
;       Function dispatcher for int 16h
;       Int 16h.
;
keyboard_io	proc	far
		sti				;intrupts back on
		push	ds
		push	bx
		push	dx
		mov	dx,data
		mov	ds,dx
		or	ah,ah
		jnz	k_io1
		jmp	read_char16
k_io1:		cmp	ah,1
		je	read_status
		cmp	ah,2
		je	read_shift
		cmp	ah,0ffh
		je	read_char8
		cmp	ah,0feh
		je	set_bits
		cmp	ah,0fdh
		je	reset_bits
exit:			  
		pop	dx
		pop	bx
		pop	ds
		iret

read_status:  
		cli
		mov	bx,buffer_head
 		cmp	bx,buffer_tail		 ;set z flag for status
		mov	ax,[bx]
		sti
		pop	dx
		pop	bx
		pop	ds
		ret	2

keyboard_io	endp

read_shift:	mov	al,shift_status
		jmp	exit

read_char8	proc    near
rc8_poll:	sti
		nop
		cli
		mov	bx,buffer_head
		cmp	bx,buffer_tail
		je	rc8_poll
		mov	ax,[bx]
		or	al,al
		jnz	rc8_ascii
		cmp	byte_flag,0ffh
		je	rc8_high_byte
		mov	byte_flag,0ffh
                jmp     short rc8_exit
rc8_high_byte:	mov	al,ah
rc8_ascii:	inc	bx		       ;check for rollover
		inc	bx
		cmp	bx,offset kb_buffer_end
		jne	rc8_inc_buf
		mov	bx,offset kb_buffer     ;reset buffer to start
rc8_inc_buf:	mov	buffer_head,bx
		mov	byte_flag,0		;clear hi lo read flag

rc8_exit:	sti
		jmp     exit
read_char8	endp

set_bits:	cli
		or	al,port_status
		mov	port_status,al
		mov	dx,keyboard_port
		out	dx,al
		sti
		jmp	exit
		
reset_bits:	cli
		not	al
		and	al,port_status
		mov	port_status,al
		mov	dx,keyboard_port
		out	dx,al
		sti
		jmp	exit

read_char16	proc	near
		sti
		nop
		cli
		mov	bx,buffer_head
		cmp	bx,buffer_tail
		je	read_char16
		mov	ax,[bx]
		inc	bx
		inc	bx
		cmp	bx,offset kb_buffer_end
		jne	rc16_inc_buf
		mov	bx,offset kb_buffer
rc16_inc_buf:	mov	buffer_head,bx
		mov	byte_flag,0		;clear hi lo read flag
		sti
		jmp	exit
read_char16	endp
;----------------------------------------------------------------
;  New keyboard function calls
;
;  input:
;     al = function #
;        0 = input characters
;           cx = count
;           es:si = buffer
;
;        2 = input status
;           es:si = buffer      (next charecter to be read for input)
;   output
;     al = status
;----------------------------------------------------------------

new_keyboard	proc	far
		mov	di,si
		or	al,al		;read characters
		jnz	nk1
		jcxz	nk5
		push	cx
nk4:
		mov	ah,-1
		int	16h		;read 8 bit char
                cld
		stos	b [di]
		loop	nk4
		pop	cx
nk5:		mov	al,0
		ret
nk1:		cmp	al,2		;status
		jne	nk2
		mov	ah,1
		int	16h		;status call
		pushf
		cli			;changed 3 - 9 - 87
		cmp	byte_flag,0
		sti
		je	nk12
		mov	al,ah		;end change 3 - 9 - 87

nk12:		stos	b [di]
		mov	al,0
		popf
		jnz	nk9
		mov	al,80h		;not ready
nk9:		ret
nk2:		mov	al,1		;bad command
		ret
new_keyboard	endp


shift_keys	db	0
		db	right_shift		;look up for shift key scan codes
		db	left_shift
		db	ctl_key
		db	alt_key
		db	scroll_key
		db	num_key
		db	caps_key
		db	ins_key
		db	right_shift_rel
		db	left_shift_rel
		db	ctl_key_rel
		db	alt_key_rel
sk_len		equ	this byte - shift_keys - 1
set		equ	0
clear		equ	2
toggle		equ	4
bit_functions	dw	set_function		;jump table for shift mask functions
		dw	clear_function
		dw	toggle_function
shift_functions	db	0,0
		db	right_mask,set		;action taken for corresponding
		db	left_mask,set		;values in shift keys
		db	ctl_mask,set
		db	alt_mask,set
		db	scroll_mask,toggle
		db	num_mask,toggle
		db	caps_mask,toggle
		db	ins_mask,toggle
		db	right_mask,clear
		db	left_mask,clear
		db	ctl_mask,clear
		db	alt_mask,clear

;look up tables for non-shift keys
;format for table is  ascii code,(1, or scan_code if ascii code is 0)
;normal 
n_table		db	27,1,'1',1,'2',1,'3',1,'4',1,'5',1,'6',1,'7',1
		db	'8',1,'9',1,'0',1,'-',1,'=',1,8,1,9,1,'q',1,'w',1,'e',1
		db	'r',1,'t',1,'y',1,'u',1,'i',1,'o',1,'p',1,'[',1,']',1
		db	13,1,0,0,'a',1,'s',1,'d',1,'f',1,'g',1,'h',1,'j',1
		db	'k',1,'l',1,';',1,39,1,'`',1,0,0,'\',1,'z',1,'x',1
		db	'c',1,'v',1,'b',1,'n',1,'m',1,',',1,'.',1,'/',1,0,0
		db	'*',1,0,0,32,1,0,0,0,59,0,60,0,61,0,62,0,63,0,64,0,65
		db	0,66,0,67,0,68,0,0,0,0,0,71,0,72,0,73,'-',1,0,75,0,0
		db	0,77,'+',1,0,79,0,80,0,81,0,82,0,83
;shift
s_table		db	27,1,'!',1,'@',1,'#',1,'$',1,'%',1,'^',1,'&',1,'*',1
		db	'(',1,')',1,'_',1,'+',1,8,1,0,15,'Q',1,'W',1,'E',1
		db	'R',1,'T',1,'Y',1,'U',1,'I',1,'O',1,'P',1,'{',1,'}',1
		db	13,1,0,0,'A',1,'S',1,'D',1,'F',1,'G',1,'H',1,'J',1,'K',1
		db	'L',1,':',1,'"',1,'~',1,0,0,'|',1,'Z',1,'X',1,'C',1
		db	'V',1,'B',1,'N',1,'M',1,'<',1,'>',1,'?',1,0,0,0,0,0,0
		db	32,1,0,0,0,84,0,85,0,86,0,87,0,88,0,89,0,90,0,91,0,92
		db	0,93,0,0,0,0,'7',1,'8',1,'9',1,'-',1,'4',1,'5',1,'6',1
		db	'+',1,'1',1,'2',1,'3',1,'0',1,'.',1
;normal w/ caps
nc_table	db	27,1,'1',1,'2',1,'3',1,'4',1,'5',1,'6',1,'7',1
		db	'8',1,'9',1,'0',1,'-',1,'=',1,8,1,9,1,'Q',1,'W',1,'E',1
		db	'R',1,'T',1,'Y',1,'U',1,'I',1,'O',1,'P',1,'[',1,']',1
		db	13,1,0,0,'A',1,'S',1,'D',1,'F',1,'G',1,'H',1,'J',1
		db	'K',1,'L',1,';',1,39,1,'`',1,0,0,'\',1,'Z',1,'X',1
		db	'C',1,'V',1,'B',1,'N',1,'M',1,',',1,'.',1,'/',1,0,0
		db	'*',1,0,0,32,1,0,0,0,59,0,60,0,61,0,62,0,63,0,64,0,65
		db	0,66,0,67,0,68,0,0,0,0,0,71,0,72,0,73,'-',1,0,75,0,0
		db	0,77,'+',1,0,79,0,80,0,81,0,82,0,83
;shift w/ caps
sc_table	db	27,1,'!',1,'@',1,'#',1,'$',1,'%',1,'^',1,'&',1,'*',1
		db	'(',1,')',1,'_',1,'+',1,8,1,0,15,'q',1,'w',1,'e',1
		db	'r',1,'t',1,'y',1,'u',1,'i',1,'o',1,'p',1,'{',1,'}',1
		db	13,1,0,0,'a',1,'s',1,'d',1,'f',1,'g',1,'h',1,'j',1,'k',1
		db	'l',1,':',1,'"',1,'~',1,0,0,'|',1,'z',1,'x',1,'c',1
		db	'v',1,'b',1,'n',1,'m',1,'<',1,'>',1,'?',1,0,0,0,0,0,0
		db	32,1,0,0,0,84,0,85,0,86,0,87,0,88,0,89,0,90,0,91,0,92
		db	0,93,0,0,0,0,'7',1,'8',1,'9',1,'-',1,'4',1,'5',1,'6',1
		db	'+',1,'1',1,'2',1,'3',1,'0',1,'.',1
;normal w/ num
nn_table	db	27,1,'1',1,'2',1,'3',1,'4',1,'5',1,'6',1,'7',1
		db	'8',1,'9',1,'0',1,'-',1,'=',1,8,1,9,1,'q',1,'w',1,'e',1
		db	'r',1,'t',1,'y',1,'u',1,'i',1,'o',1,'p',1,'[',1,']',1
		db	13,1,0,0,'a',1,'s',1,'d',1,'f',1,'g',1,'h',1,'j',1
		db	'k',1,'l',1,';',1,39,1,'`',1,0,0,'\',1,'z',1,'x',1
		db	'c',1,'v',1,'b',1,'n',1,'m',1,',',1,'.',1,'/',1,0,0
		db	'*',1,0,0,32,1,0,0,0,59,0,60,0,61,0,62,0,63,0,64,0,65
		db	0,66,0,67,0,68,0,0,0,0,'7',1,'8',1,'9',1,'-',1,'4',1
		db	'5',1,'6',1,'+',1,'1',1,'2',1,'3',1,'0',1,'.',1

;shifted w/ num
sn_table	db	27,1,'!',1,'@',1,'#',1,'$',1,'%',1,'^',1,'&',1,'*',1
		db	'(',1,')',1,'_',1,'+',1,8,1,0,15,'Q',1,'W',1,'E',1
		db	'R',1,'T',1,'Y',1,'U',1,'I',1,'O',1,'P',1,'{',1,'}',1
		db	13,1,0,0,'A',1,'S',1,'D',1,'F',1,'G',1,'H',1,'J',1,'K',1
		db	'L',1,':',1,'"',1,'~',1,0,0,'|',1,'Z',1,'X',1,'C',1
		db	'V',1,'B',1,'N',1,'M',1,'<',1,'>',1,'?',1,0,0,0,0,0,0
		db	32,1,0,0,0,84,0,85,0,86,0,87,0,88,0,89,0,90,0,91,0,92
		db	0,93,0,0,0,0,0,71,0,72,0,73,'-',1,0,75,0,0
		db	0,77,'+',1,0,79,0,80,0,81,0,82,0,83


;num and caps
ncn_table	db	27,1,'1',1,'2',1,'3',1,'4',1,'5',1,'6',1,'7',1
		db	'8',1,'9',1,'0',1,'-',1,'=',1,8,1,9,1,'Q',1,'W',1,'E',1
		db	'R',1,'T',1,'Y',1,'U',1,'I',1,'O',1,'P',1,'[',1,']',1
		db	13,1,0,0,'A',1,'S',1,'D',1,'F',1,'G',1,'H',1,'J',1
		db	'K',1,'L',1,';',1,39,1,'`',1,0,0,'\',1,'Z',1,'X',1
		db	'C',1,'V',1,'B',1,'N',1,'M',1,',',1,'.',1,'/',1,0,0
		db	'*',1,0,0,32,1,0,0,0,59,0,60,0,61,0,62,0,63,0,64,0,65
		db	0,66,0,67,0,68,0,0,0,0,'7',1,'8',1,'9',1,'-',1,'4',1
		db	'5',1,'6',1,'+',1,'1',1,'2',1,'3',1,'0',1,'.',1

;shifted num and caps
scn_table	db	27,1,'!',1,'@',1,'#',1,'$',1,'%',1,'^',1,'&',1,'*',1
		db	'(',1,')',1,'_',1,'+',1,8,1,0,15,'q',1,'w',1,'e',1
		db	'r',1,'t',1,'y',1,'u',1,'i',1,'o',1,'p',1,'{',1,'}',1
		db	13,1,0,0,'a',1,'s',1,'d',1,'f',1,'g',1,'h',1,'j',1,'k',1
		db	'l',1,':',1,'"',1,'~',1,0,0,'|',1,'z',1,'x',1,'c',1
		db	'v',1,'b',1,'n',1,'m',1,'<',1,'>',1,'?',1,0,0,0,0,0,0
		db	32,1,0,0,0,84,0,85,0,86,0,87,0,88,0,89,0,90,0,91,0,92
		db	0,93,0,0,0,0,0,71,0,72,0,73,'-',1,0,75,0,0
		db	0,77,'+',1,0,79,0,80,0,81,0,82,0,83
;control
c_table		db	27,1,0,0,0,1,0,0,0,0,0,0,30,1,0,0,0,0,0,0,0,0,31,1,0,0
		db	127,1,0,0,17,1,23,1,5,1,18,1,20,1,25,1,21,1,9,1,15,1
		db	16,1,27,1,29,1,10,1,0,0,1,1,19,1,4,1,6,1,7,1,8,1,10,1
		db	11,1,12,1,0,0,0,0,0,0,0,0,28,1,26,1,24,1,3,1,22,1,2,1
		db	14,1,13,1,0,0,0,0,0,0,0,0,0,114,0,0,32,1,0,0,0,94,0,95
		db	0,96,0,97,0,98,0,99,0,100,0,101,0,102,0,103,0,0,3,1
		db	0,119,0,0,0,132,0,0,0,115,0,0,0,116,0,0,0,117,0,0,0,118
		db	0,0,0,0
;alt
a_table		db	0,0,0,120,0,121,0,122,0,123,0,124,0,125,0,126,0,127
		db	0,128,0,129,0,130,0,131,0,0,0,0,0,16,0,17,0,18,0,19
		db	0,20,0,21,0,22,0,23,0,24,0,25,0,0,0,0,0,0,0,0,0,30
		db	0,31,0,32,0,33,0,34,0,35,0,36,0,37,0,38,0,0,0,0,0,0
		db	0,0,0,0,0,44,0,45,0,46,0,47,0,48,0,49,0,50,0,0,0,0
		db	0,0,0,0,0,0,0,0,32,1,0,0,0,104,0,105,0,106,0,107,0,108
		db	0,109,0,110,0,111,0,112,0,113,0,0,0,0,0,0,0,0,0,0
		db	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

interupt2	proc	far
		sti
		cld
		int	9				;go do keyboard int
		push	ax
		push	dx
		push	ds
		mov	ax,data
		mov	ds,ax

		cli
		mov	dx,keyboard_port
		mov	al,port_status
		and	al,not data_line
		out	dx,al		
		or	al,data_line
		out	dx,al
		mov	port_status,al
		sti
		mov	dx,eoir
		mov	ax,eoiv
		out	dx,ax
		pop	ds
		pop	dx
		pop	ax
		iret
interupt2	endp
 
interupt	proc	far
		sti
		cld
		push	ds
		push	si
		push	ax
		push	bx
		push	cx
		push	dx
		mov	ax,data
		mov	ds,ax

z1: 		mov	dx,keyboard_port
		in	al,dx
		MOV	BL,AL
		cli
		mov	dx,keyboard_port
		mov	al,port_status
		and	al,not data_line
		out	dx,al		
		or	al,data_line
		out	dx,al
		mov	port_status,al
		MOV	AL,BL

		STI

		test	shift_status,ctl_mask
		jz	z2 
		test	shift_status,alt_mask
		jz	z3
		cmp	al,del_key
		jne	z3
		mov	reset_location,1234h		;warm boot
		jmp	initialize
z3:		cmp	al,scroll_key
		jne	z2				;ctl break was pressed
		xor	ax,ax				;clear buffer return 0000
		mov	kb_buffer,ax					       

		mov	buffer_head,offset kb_buffer
		mov	buffer_tail,offset kb_buffer+2

		mov	byte_flag,0
		int	break_int
		jmp	interupt_done
z2:		mov	si,offset shift_keys
		xor	bx,bx
		mov	cx,sk_len
sk_loop:	inc	bx			;is it a shift key?
		cmp	al,cs:[bx][si]
		loopne	sk_loop
		jne	not_shift
		shl	bx,1
		mov	ah,shift_functions[bx]
		mov	bl,shift_functions[bx]+1
		xor	bh,bh
		jmp	bit_functions[bx]	;adjust shift status
set_function:	or	shift_status,ah
    
   		jmp	short sk_cont
clear_function:	not	ah
		and	shift_status,ah
		jmp	short sk_cont
toggle_function:
		xor	shift_status,ah
sk_cont:	cmp	al,ins_key
		je	not_shift
		and	key_status2,not nshiftkey_mask
		jmp	interupt_done
not_shift:					;not shift key get table for 
i1:		cmp	al,80h			;current shift status
		jb	i2
		jmp	interupt_done
i2: 
 		or	key_status2, nshiftkey_mask

		mov	ah,shift_status
		test	ah,alt_mask
		jz	i17
		mov	bx,offset a_table
		jmp	look_up
i17:		test	ah,ctl_mask
		jz	i18
		mov	bx,offset c_table
		jmp	look_up
i18:		test	ah,caps_mask
		jz	i3
		test	ah,num_mask
		jz	i4
		test	ah,right_mask or left_mask
		jz	i16
		mov	bx,offset scn_table
		jmp	look_up
i16:		mov	bx,offset ncn_table
		jmp	look_up

i4:		test	ah,right_mask or left_mask
		jz	i26
		mov	bx,offset sc_table
		jmp	look_up
i26:		mov	bx,offset nc_table
		jmp	look_up

i3:		test	ah,num_mask
		jz	i5
		test	ah,right_mask or left_mask
		jz	i36
		mov	bx,offset sn_table
		jmp	look_up
i36:		mov	bx,offset nn_table
		jmp	look_up
i5:
		test	ah,right_mask or left_mask
		jz	i6
		mov	bx,offset s_table
		jmp	look_up
i6:		mov	bx,offset n_table


look_up:	xor	ah,ah
		mov	si,ax
		dec	si
		mov	ah,al			;scan code to ah
		shl	si,1
		mov	al,cs:[bx][si]		;ascii to al
		or	al,al
		jnz	lu1
		mov	ah,cs:[bx][si]+1	;ascii is 0 adjusted scan code to ah
		or	ax,ax
		jz	interupt_done		;illegal key discard it
lu1: 		cli
		mov	bx,buffer_tail
		mov	si,bx
		inc	bx
		inc	bx
		cmp	bx,offset kb_buffer_end
		jne	lu2
		mov	bx,offset kb_buffer
lu2:		cmp	bx,buffer_head
		je	error_beep
		mov	[si],ax
		mov	buffer_tail,bx
error_beep:
interupt_done:
		mov	dx,eoir
		mov	ax,eoiv
		out	dx,ax
		pop	dx
		pop	cx
		pop	bx
		pop	ax
		pop	si			 
ctl_num_loop:	sti
		test	shift_status,num_mask 	;should call concurrent int
		jz	i23
		test	shift_status,ctl_mask    
		jz	i23 			
		test	key_status2,nshiftkey_mask
		jnz	i23
	 	jmp	short ctl_num_loop
i23:		
		pop	ds
interupt1:	iret
interupt	endp
code		ends
		end





