Tvůrce webu je i pro tebe! Postav třeba web. Bez grafika. Bez kodéra. Hned.
wz

IO_CON.ASM

Ovladač konzoly

V souboru IO_CON.ASM se nachází funkce pro obsluhu konzoly - vstup znaků z klávesnice a zobrazení na displeji. Nejdříve si popíšeme funkce pro výstup znaků na displej.

Funkce pro práci s displejem používají funkci Int10. Tato funkce nedělá nic jiného než že uchová "málo časté" registry jako SI, DI atd. Některé starší BIOS (buď ze základní desky nebo z grafické karty) se o uchování těchto registrů nestarají a navracejí náhodná data v nich, což by nám mohlo způsobit nemalé potíže.

Při inicializaci systému je nainstalována obsluha přerušení Int 29h, funkce MyInt29. Přerušení Int 29h je v systému DOS používáno k zobrazení znaků na displej v případech, kdy je požadován skutečný výstup na displej bez možnosti přesměrování výstupu např. do souboru. Přeinstalováním obsluhy přerušení Int 29h je možné změnit chování ovladače konzoly - např. možnost změny barvy textu. Funkce používá funkci 0eh přerušení Int 10h. Jedná se o konzolový výstup - text je vypisován na aktuální pozici kurzoru. Kurzor je automaticky posouván. Dosáhne-li konce řádku, přejde na začátek následujícího řádku. Pokud by se nacházel další řádek již mimo spodní okraj displeje, obraz se posune o řádek nahoru. Tato funkce je podporovaná všemi textovými a zpravidla i všemi grafickými videomódy. Barva textu je nastavena na bílou na černém pozadí.

Funkce DispText je pomocná funkce používaná vnitřně systémem. Umožňuje zobrazení textu přímo na displej - např. chybová hlášení systému. Text musí být zakončen binární nulou.

Funkce CONWData je obsluha zápisu dat na zařízení. Zapisují se data o dané délce z bufferu, jehož ukazatel je získán z paketu požadavku na zařízení. K výstupu znaků je využito přerušení Int 29h.


; ============================================================================
;
;                            LT-DOS - Console device
;
; ============================================================================

BREAK		EQU	3		; break character (Ctrl+C)
PRINT		EQU	10h		; print character (Ctrl+P)
CTRL_PRINTSCR	EQU	7200h		; Ctrl+Print Screen key

; ----------------------------------------------------------------------------
;                         Device service tables
; ----------------------------------------------------------------------------

; ------------- CON service table

FNCCON:		db	11		; number of functions
		dw	DevIntOK	; 0 init
		dw	DevIntOK	; 1 media check
		dw	DevIntOK	; 2 build BPB
		dw	DevIntInv	; 3 IOCTL input
		dw	CONRData	; 4 read data
		dw	CONRTest	; 5 test read
		dw	CONRStatus	; 6 input status
		dw	CONRFlush	; 7 flush input
		dw	CONWData	; 8 write data
		dw	CONWData	; 9 write with verify
		dw	DevIntOK	; 10 output status

; ----------------------------------------------------------------------------
;                 Device interrupt service - CON read data
; ----------------------------------------------------------------------------
; INPUT:	CX = number of characters to read
;		ES:DI = data buffer
;		DS = data segment
; OUTPUT:	AX = status word
; ----------------------------------------------------------------------------

CONRData:	jcxz	CONRData4	; there are no data to read
CONRData2:	call	CONRChar	; read character from keyboard
		cld			; direction up
		stosb			; store character to buffer
		loop	CONRData2	; read next character
CONRData4:	mov	ah,S_DONE	; status OK
		ret			; return from interrupt

; ----------------------------------------------------------------------------
;                 Device interrupt service - CON test read
; ----------------------------------------------------------------------------
; INPUT:	DS = data segment
; OUTPUT:	AX = status word
; DESTROYS:	DS
; ----------------------------------------------------------------------------

CONRTest:	call	CONRTestChar	; test character
		jc	CONRTest2	; no character ready
		lds	bx,[Strat]	; DS:BX <- strategy address
		mov	[bx+13],al	; output character
CONRTestOK:	mov	ah,S_DONE	; status OK
		ret			

CONRTest2:	mov	ah,S_DONE+S_BUSY ; status - device not ready
		ret

; ----------------------------------------------------------------------------
;                 Device interrupt service - CON input status
; ----------------------------------------------------------------------------
; INPUT:	DS = data segment
; OUTPUT:	AX = status word
; ----------------------------------------------------------------------------

CONRStatus:	call	CONRTestChar	; test character
		jc	CONRTest2	; no character ready
		jmp	short CONRTestOK; status OK

; ----------------------------------------------------------------------------
;               Device interrupt service - CON flush input
; ----------------------------------------------------------------------------
; INPUT:	DS = data segment
; OUTPUT:	AX = status word
; ----------------------------------------------------------------------------

CONRFlush:	call	CONRTestChar	; any character ready?
		jc	CONRTestOK	; no character
		call	CONRChar	; input chracter from keyboard
		jmp	short CONRFlush	; next character

; ----------------------------------------------------------------------------
;                 Device interrupt service - CON write data
; ----------------------------------------------------------------------------
; INPUT:	CX = number of characters to write
;		ES:DI = data buffer
;		DS = data segment
; OUTPUT:	AX = status word
; ----------------------------------------------------------------------------

CONWData:	jcxz	CONWData4	; there are no data to write
CONWData2:	mov	al,[es:di]	; AL <- character to display
		inc	di		; increase pointer
		int	29h		; display character
		loop	CONWData2	; write next character
CONWData4:	mov	ah,S_DONE	; status OK
		ret			; return from interrupt

; ----------------------------------------------------------------------------
;                          Correct character from keyboard
; ----------------------------------------------------------------------------
; INPUT/OUTPUT:	AX = character from keyboard
; ----------------------------------------------------------------------------

; ------------- Substitute extended scan code 0eh with 00h

CONRCorr:	cmp	al,0e0h		; is it extended scan code?
		jne	CONRCorr2	; it is not extended scan code
		or	ah,ah		; has this character scan code?
		jz	CONRCorr2	; this character has no scan code
		mov	al,0		; substitute it with 0 code

; ------------- Substitute Ctrl+PrintScreen key with Ctrl+P

CONRCorr2:	cmp	ax,CTRL_PRINTSCR; is it Ctrl+Print Screen?
		jne	CONRCorr4	; it is not Ctrl+Print Screen
		mov	al,PRINT	; substitute it with Ctrl+P
CONRCorr4:	ret

; ----------------------------------------------------------------------------
;                           CON read character
; ----------------------------------------------------------------------------
; INPUT:	DS = data segment
; OUTPUT:	AL = character (0=scan code follows)
; DESTROYS:	AH
; ----------------------------------------------------------------------------

; ------------- Read old character from buffer

CONRChar:	mov	al,0		; AL <- new invalid old character
		xchg	al,[OldChar]	; AL <- old character
		or	al,al		; is it valid character?
		jnz	CONRChar8	; it is valid character

; ------------- Read character from keyboard

		mov	ah,[KeyInCode]	; AH <- function code
		int	16h		; read character from keyboard

; ------------- Skip Ctrl+Break code

		or	ax,ax		; is it Ctrl+Break?
		jz	CONRChar	; it is Ctrl+Break, ignore it

; ------------- Correct character from keyboard

		call	CONRCorr	; correct character from keyboard

; -------------	Store scan code

		or	al,al		; is it special key?
		jnz	CONRChar8	; it is not special key
		mov	[OldChar],ah	; store scan code
CONRChar8:	ret

; ----------------------------------------------------------------------------
;                           CON test character
; ----------------------------------------------------------------------------
; INPUT:	DS = data segment
; OUTPUT:	AL = character (0=scan code follows)
;		CY = no character
; DESTROYS:	AH
; ----------------------------------------------------------------------------

; ------------- Read old character from buffer

CONRTestChar:	mov	al,[OldChar]	; AL <- old character
		or	al,al		; is it valid character?
		jnz	CONRTestChar8	; it is valid character

; ------------- Read character from keyboard

		mov	ah,[KeyTestCode]; AH <- function code
		int	16h		; test character from keyboard
		stc			; flag - no character is ready
		jz	CONRTestChar9	; no character

; ------------- Skip Ctrl+Break code

		or	ax,ax		; is it Ctrl+Break?
		jnz	CONRTestChar2	; it is not Ctrl+Break
		mov	ah,[KeyInCode]	; AH <- function code
		int	16h		; read character from keyboard
		jmp	short CONRTestChar ; next key

; ------------- Correct character from keyboard

CONRTestChar2:	call	CONRCorr	; correct character from keyboard
CONRTestChar8:	clc			; flag - a character is ready
CONRTestChar9:	ret

; ----------------------------------------------------------------------------
;                        Internal display ASCIIZ text
; ----------------------------------------------------------------------------
; INPUT:	DS:SI = text to display, terminated with zero
; DESTROY:	AX
; ----------------------------------------------------------------------------

DispText:	cld			; direction up
DispText2:	lodsb			; load character to display
          	cmp	al,0		; is it end of text?
		je	DispText3	; it is end of text
		int	29h		; display character
		jmp	short DispText2	; display next character
DispText3:	ret

; ----------------------------------------------------------------------------
;                  Interrupt 29h handler (display character)
; ----------------------------------------------------------------------------
; INPUT:	AL = character to display
; ----------------------------------------------------------------------------

; ------------- Push registers

MyInt29:	push	ax		; push AX
		push	bx		; push BX

; ------------- Display character

		mov	ah,0eh		; AH <- 0Eh function code
		mov	bx,7		; BL <- color of text, BH <- page 0
		call	Int10		; call Int 10h

; ------------- Pop registers

		pop	bx		; pop BX
		pop	ax		; pop AX
		iret

; ----------------------------------------------------------------------------
;                Call Int 10h interrupt with saving registers
; ----------------------------------------------------------------------------
; Notes: Some BIOSes destroy some registers, so we call it with saving them.
; ----------------------------------------------------------------------------

; ------------- Push registers

Int10:		pushf			; push flags
		push	si		; push SI
		push	di		; push DI
		push	bp		; push BP
		push	ds		; push DS
		push	es		; push ES

; ------------- Call INT 10h

		int	10h		; call INT 10h

; ------------- Pop registers

		pop	es		; pop ES
		pop	ds		; pop DS
		pop	bp		; pop BP
		pop	di		; pop DI
		pop	si		; pop SI
		popf			; pop flags
		ret

; ----------------------------------------------------------------------------
;                     Interrupt 1Bh handler (program break)
; ----------------------------------------------------------------------------

MyInt1B:	mov	byte [cs:OldChar],BREAK ; break character
MyInt01:
MyInt03:
MyInt04:
MyInt23:
MyInt24:
MyInt28:
		iret

; ----------------------------------------------------------------------------
;                      Interrupt 10h handler (video services)
; ----------------------------------------------------------------------------

MyInt10:	jmp	far [cs:OldInt10] ; jump to old Int 10h routine

; ----------------------------------------------------------------------------
;                                    Data
; ----------------------------------------------------------------------------

OldChar:	db	0		; old character from console (0=none)

KeyInCode:	db	0		; func. code for input (0 or 10h)
KeyTestCode:	db	1		; func. code for test (1 or 11h)

Ke vstup dat z konzoly je používáno BIOS přerušení Int 16h. Používá se buď funkce 0 (vstup ze standardní klávesnice) nebo funkce 10h (vstup z rozšířené klávesnice, umožňuje vstup i speciálních kláves jako např. F12). Rozlišení typu klávesnice se provádí při inicializaci systému, do proměnné KeyInCode je uložen kód funkce pro vstup z klávesnice. Podobně je připravena funkce 1 nebo 11h pro test klávesnice, proměnná KeyTestCode.

Klávesy můžeme rozdělit na 2 typy - znakové klávesy a řídicí klávesy. Znakové klávesy generují tisknutelný znak (písmeno, číslice). Řídicí klávesy nemají žádnou znakovou (ASCII) hodnotu, umožňují řídit chování programu (šipky, Insert, F5). Některé klávesy generují platné ASCII kódy, které nejsou sice zobrazitelné, ale slouží k řízení konzolového výstupu a proto je řadíme též mezi znakové klávesy - Enter, Esc, Back Space, Tab.

BIOS funkce pro čtení kód klávesy navrací kód klávesy ve tvaru 16-bitového slova. Nižší bajt je ASCII hodnota klávesy (pokud se jedná o znakovou klávesu), vyšší hodnota je tzv. scan kód klávesy, což je pořadové číslo klávesy na klávesnici. Řídicí klávesy obsahují namísto ASCII znaku v nižším bajtu hodnotu 0, čímž jsou rozlišeny od znakových kláves, identifikace klávesy se provásí vyšším bajtem (scan kódem).

Funkce ovladače pro čtení kódu klávesy navracejí ve výstupním řetězci posloupnost jednotlivých bajtů (znaků). Je-li stisknuta znaková klávesa, je navrácen přímo ASCII kód klávesy. Je-li stisknuta řídicí klávesa, je navrácen nejdříve bajt s hodnotou 0 jako prefix, následující načtený bajt bude scan kód klávesy. Následující bajt ke čtení z ovladače je uchován v proměnné OldChar.

Vstup znaků z klávesnice probíhá funkcí CONRChar. Je-li v proměnné OldChar uchován od minule scan kód klávesy, je obsah proměnné vynulován a scan kód navrácen bez čekání na další klávesu. Není-li uchován předešlý bajt, bude se čekat na stisk klávesy. Případně navrácené slovo s hodnotou 0 je ignorováno a je provedeno čekání na novou klávesu. Tento kód je navrácen v případě stisku kláves Ctrl+Break, tj. přerušení programu. Tato kombinace kláves je obsloužena zvláštním přerušením MyIntBreak, které do proměnné OldChar uloží znak s hodnotou 3, což je kód shodný s kombinací kláves Ctrl+C, která se také používá k přerušení programu.

Kód klávesy je zkorigován funkcí CONRCorr. Jedná-li se o řídicí klávesu rozšířené klávesnice, která navrací v nižším bajtu namísto 0 hodnotu 0e0h, bude nižší bajt nahrazen hodnotou 0 a tím převeden na klasickou interpretaci kódu. Konverze se neprovede v případě, že vyšší bajt je 0. Tento případ nastane, pokud na numerické klávesnici s využitím levého Alt zadáme číselnou hodnotu znaku 224. Klávesa PrintScreen je nahrazena kódem kláves Ctrl+P, v systému DOS slouží k zapínání a vypínání příznaku tzv. "hardcopy" obrazovky, výstup probíhá nejen na displej, ale současně i na tiskárnu. Na závěr funkce CONRChar je v případě řídicí klávesy uchován její scan kód do bufferu OldChar pro příští načítání.

Funkce CONRData je načítání dat z konzoly. Ke vstupu dat z klávesnice je používána funkce CONRChar. Funkce CONRTest provádí nedestruktivní vstup z klávesnice. Pomocí funkce CONRTestChar je načten kód připravené klávesy, klávesa přitom není zrušena z bufferu kláves. Obsluha funkce je obdobná jako u funkce CONRChar. Funkce CONRFlush je obsluha vyprázdnění vstupního bufferu klávesnice. Funkce opakovaně testuje, zda je připraven nějaký znak z klávesnice a pokud ano, tento znak načte a tím dojde k jeho zrušení.

Zpět na stránku systému LT-DOS