[net.micro.pc] increasing the size of the IBM PC kbd buffer

vch@rruxo.UUCP (V. Hatem) (08/13/85)

I picked this off of net.sources a while back, I thought whoever was asking  
about this subject might like it. It is very fast. All you need to do is 
assemble it, link it to nothing(no libraries) to get an exe file, and run it
through exe2bin, and change the .bin file to be .com. Run it once only (per
boot-up) or it will lock your system. I keep it in my autoexec.bat file.

enjoy!

Vince Hatem
Bell Communications Research
rruxo!vch

********************************* cut here ***********************************

vectors 	segment at 0h

	org	9h*4
keyboard_int_vector	label	dword
	org	16h*4
keyboard_io_vector	label	dword
vectors 	ends

;==============================================================================

rom_bios_data	segment at 40h
	org	17h
kbd_flag	db	?
	org	1ah
rom_buffer_head dw	?
rom_buffer_tail dw	?
kb_buffer	dw	16d dup (?)
kb_buffer_end	label	word
rom_bios_data	ends

;==============================================================================

code_seg	segment
	assume	cs:code_seg
	org	100h
begin:	jmp	init_vectors		;initialize vectors and attach to dos
rom_keyboard_int	dd
rom_keyboard_io 	dd
buffer_head		dw	offset keyboard_buffer
buffer_tail		dw	offset keyboard_buffer
keyboard_buffer 	dw	160d dup(0)	;159 character input buffer
keyboard_buffer_end	label	word

;--------------------------------------------------------;
; this procedure sends a short beep when the buffer fills
;--------------------------------------------------------;

kb_control	equ	61h		;control bits for keyboard & speaker
error_beep	proc	near
	push	ax
	push	bx
	push	cx
	pushf				;save old interupt enable flag
	cli				;turn off beep during interupt
	mov	bx,30d			;number of cycles for 1/8 second tone
	in	al,kb_control		;get information from speaker port
	push	ax			;save control information
start_of_one_cycle:
	and	al,0fch 		;turn off speaker
	out	kb_control,al
	mov	cx,60d			;delay for one half cycle
off_loop:
	loop	off_loop
	or	al,2			;turn off speaker
	out	kb_control,al
	mov	cx,60d			;delay for second half cycle
on_loop:
	loop	on_loop
	dec	bx			;200 cycles yet?
	jnz	start_of_one_cycle
	pop	ax			;recover old keyboard information
	out	kb_control,al
	popf				;restore interupt flag
	pop	cx
	pop	bx
	pop	ax
	ret
error_beep	endp

;------------------------------------------------------------------------------

;this procedure checks the rom keyboard buffer to see if some program
;tried to clear this buffer. we know it's been cleared when the rom
;tail and header overlap. normally, the new procedures below keep the
;dummy character, word 0,in the buffer.
;
;uses: bx,ds
;writes:	buffer_head,buffer_tail,rom_buffer_head,
;		rom_buffer_tail
;reads: 	keyboard_buffer,kb_buffer

check_clear_buffer	proc near
	assume	ds:rom_bios_data
	mov	bx,rom_bios_data	;establish pointer to bios data
	mov	ds,bx
	cli				;turn off interupts during this check
	mov	bx,rom_buffer_head	;check tn see if buffer cleared
	cmp	bx,rom_buffer_tail	;is the buffer empty?
	jne	buffer_ok		;no, then everything is alright
					;yes, then clear the internal buffer
	mov	bx,offset kb_buffer	;reset buffer with word 0 in buffer
	mov	rom_buffer_head,bx
	add	bx,2
	mov	rom_buffer_tail,bx
	assume	ds:code_seg
	mov	bx,cs
	mov	ds,bx
	mov	bx,offset keyboard_buffer ;reset internal buffer
	mov	buffer_head,bx
	mov	buffer_tail,bx
buffer_ok:
	assume	ds:code_seg
	sti				;interupts back on
	ret
check_clear_buffer	endp

;------------------------------------------------------------------------------

;this procedure intercepts the keyboard interrupt and moves any new
;characters to the internal, 80 character buffer.

intercept_keyboard_int	proc	near
	assume	ds:nothing
	push	ds
	push	si
	push	bx
	push	ax
	call	check_clear_buffer	;check for buffer cleared
	pushf
	call	rom_keyboard_int	;read scan code with bios routines
;-----	transfer any characters to internal buffer
	assume	ds:rom_bios_data
	mov	bx,rom_bios_data	;establish pointer to bios data
	mov	ds,bx
	mov	si,buffer_tail
	mov	bx,rom_buffer_head	;check if real characters in buffer
	inc	bx			;skip over dummy character
	inc	bx
	cmp	bx,offset kb_buffer_end
	jb	dont_wrap		;no need to wrap the pointer
	mov	bx,offset kb_buffer	;wrap the pointer
dont_wrap:
	cmp	bx,rom_buffer_tail	;is there a real character?
	je	no_new_characers	;no then return to caller
	mov	ax,[bx] 		;yes,move character to internal buffer
	mov	cs:[si],ax
	inc	si
	inc	si			;move to next position
	cmp	si,offset keyboard_buffer_end
	jb	not_at_end
	mov	si,offset keyboard_buffer
not_at_end:
	cmp	si,buffer_head		;buffer overrun?
	jne	write_to_buffer 	;yes beep and throw out character
	call	error_beep
	jmp	short not_at_kb_end
write_to_buffer:
	mov	buffer_tail,si
not_at_kb_end:
	mov	rom_buffer_head,bx

no_new_characters:
;----	see if ctrl + alt pushed, and clear buffer if so

	mov	al,kbd_flag		;get status of shift keys into al
	and	al,0ch			;isolate alt and crtl shift flags
	cmp	al,0ch			;are both the alt and crtl keys down?
	jne	dont_clear_buffer	;no, then dont clear the buffer
	mov	ax,buffer_tail		;yes, then clear the buffer
	mov	buffer_head,ax

dont_clear_buffer:
	pop	ax
	pop	bx
	pop	si
	pop	ds
	iret
intercept_keyboard_int endp

;-----------------------------------------------------------------------;
;this procedure replaces the rom bios routines for reading a character	;
;-----------------------------------------------------------------------;
	assume	ds:code_seg

;------------------------------------------------------------------------------

intercept_keyboard_io proc	far
	sti				;interrupts back on
	push	ds			;save current ds
	push	bx			;save bx temporarily
	call	check_clear_buffer	;check for buffer cleared
	mov	bx,cs			;establish pointer to data area
	mov	ds,bx
	or	ah,ah			;ah=0?
	jz	read_character		;yes, read a character
	cmp	ah,1			;ah=1?
	jz	read_status		;yes, return the status
	pop	bx			;let rom bios handle other functhons
	pop	ds
	assume	ds:nothing
	jmp	rom_keyboard_io 	;call rom bios for other functions
	assume	ds:code_seg		;ascii read

;--=-	read the key

read_character: 			;ascii read
	sti				;interrupts back on during loop
	nop				;allow an interrupt to occur
	cli				;interrupts back off
	mov	bx,buffer_head		;get pointer to head of buffer
	cmp	bx,buffer_tail		;test end of buffer
	je	read_character		;loop until something in buffer
	mov	ax,[bx] 		;get scan code and ascii code
	add	bx,2			;move to next word in buffer
	cmp	bx,offset keyboard_buffer_end	;at end of buffer?
	jne	save_pointer		;no, continue
	mov	bx,offset keyboard_buffer	;yes, reset to buffer start
save_pointer:
	mov	buffer_head,bx		;store value in variable
	pop	bx
	pop	ds
	iret				;return to caller

;----	ascii status

read_status:
	cli				;interrupts off
	mov	bx,buffer_head		;get head pointer
	cmp	bx,buffer_tail		;if equal (zf=1) then nothing there
	mov	ax,[bx]
	sti				;interrupts back on
	pop	bx			;recover registers
	pop	ds
	ret	2			;throw away flags

intercept_keyboard_io	endp

;-----------------------------------------------------------------;
;this procedure initializes the interrupt vectors.		  ;
;-----------------------------------------------------------------;

;------------------------------------------------------------------------------

init_vectors	proc	near
	assume	ds:vectors
	push	ds			;save old data segment
	mov	ax,vectors		;set up the data segment for vectors
	mov	ds,ax
	cli				;dont allow interrupts

	mov	ax,keyboard_int_vector	;save addresses of bios routines
	mov	rom_keyboard_int,ax
	mov	ax,keyboard_int_vector[2]
	mov	rom_keyboard_int[2],ax
					;set up new keyboard_int vector
	mov	keyboard_int_vector,offset intercept_keyboard_int
	mov	keyboard_int_vector[2],cs
	sti				;allow interrupts again
					;set up keyboard_io vector
	mov	ax,keyboard_io_vector
	mov	rom_keyboard_io,ax
	mov	ax,keyboard_io_vector[2]
	mov	rom_keyboard_io[2],ax
	mov	keyboard_io_vector,offset intercept_keyboard_io
	mov	keyboard_io_vector[2],cs
					;now set up the the kbd buffer, etc.

	assume	ds:rom_bios_data
	mov	ax,rom_bios_data
	mov	ds,ax
	cli				;dont allow interrupts now
	mov	bx,offset kb_buffer
	mov	rom_buffer_head,bx
	mov	word ptr [bx],0
	add	bx,2
	mov	rom_buffer_tail,bx
	sti				;allow interrupts again

	mov	dx,offset init_vectors	;end of resident portions
	int	27h			;terminate but stay resident
init_vectors	endp

;------------------------------------------------------------------------------

code_seg	ends

;==============================================================================

	end	begin


-- 

some various witty sayings...


sdfgajksdfgjdafhg