mirror of
https://github.com/microsoft/MS-DOS.git
synced 2024-11-24 09:10:08 -08:00
1425 lines
32 KiB
NASM
1425 lines
32 KiB
NASM
TITLE MTCON - Console device driver for MT-MSDOS
|
|
page ,132
|
|
|
|
|
|
;; TODO -
|
|
;; split CON and KBD
|
|
;; interruptible waits and unwinding
|
|
;; per screen keyboard buffers
|
|
|
|
;------------------------------------------------------------------------
|
|
; Revision History
|
|
;
|
|
; V1.00 04/10/84 M.A.Ulloa
|
|
; First Implementation: Only one segment used and only
|
|
; one screen in the color card (alpha mode).
|
|
;
|
|
; V1.01 04/15/84 M.A.Ulloa
|
|
; Re-enabled the blocking of writing from processes not
|
|
; with the current screen.
|
|
;
|
|
; V1.02 04/16/84 M.A.Ulloa
|
|
; Increased to 8 the num of screens. Added the screen
|
|
; blanking when reading and writing the screen data
|
|
; (see BLANK switch). Added screen # for writes.
|
|
;
|
|
; V1.03 04/17/84 M.A.Ulloa
|
|
; Corrected problem with flush.
|
|
;
|
|
; V1.05 04/30/84 A.R.Whitney
|
|
; Added conditional compilation to allow linking with
|
|
; resident BIOS.
|
|
;
|
|
; V1.06 05/08/84 A.R.Whitney
|
|
; Added ANSI escape sequences. Conditional on ANSI.
|
|
;
|
|
; V1.07 05/15/84 A.R.Whitney
|
|
; Fixed compatibility problems with Eagle PC Turbo.
|
|
; Fixed BLANK conditional code to allow saving graphics
|
|
; mode screens.
|
|
; Added enable/disable 25th line to Ansi.
|
|
;
|
|
; V1.08 05/22/84 A.R.Whitney
|
|
; Fixed problem with scrolling in screen modes other
|
|
; than 80x25. Bug due to 25th line stuff.
|
|
;
|
|
;------------------------------------------------------------------------
|
|
|
|
;DEBUGFLG = 1
|
|
|
|
.xlist
|
|
include DEFDBUG.INC
|
|
.list
|
|
|
|
FALSE EQU 0
|
|
TRUE EQU NOT FALSE
|
|
|
|
CVERS equ 01 ; update version number!!
|
|
CREV equ 08
|
|
|
|
BLANK equ TRUE ; blank screen during data r/w
|
|
INBIOS equ TRUE ; link with BIOS
|
|
ANSI equ TRUE ; include ANSI escape sequences
|
|
LINE25 equ TRUE ; special 25th line like VT52
|
|
EAGLE equ TRUE ; Eagle PC ROM botches CRT_LEN
|
|
|
|
|
|
subttl Screen Information Block Definition
|
|
page
|
|
|
|
;------------------------------------------------------------------------
|
|
; Screen Information Block (SIB) Definition
|
|
;
|
|
; This structure contains all information necessary to
|
|
; describe the state of the screen, plus pointers to buffers
|
|
; which contain the actual screen content.
|
|
;
|
|
|
|
;------------------------------------------------------------------------
|
|
MaxSEG equ 2 ; NOTE: assumption is made in the
|
|
; code that all SIB's have same
|
|
; number os SEGs
|
|
SEGst struc
|
|
SizeNeeded dw 0 ; needed size for seg, (0 = unused)
|
|
MemFlag dw ? ; maintened by system (0 = in mem)
|
|
MPointer dd ? ; vaild iff MemFlag == 0
|
|
SEGst ends
|
|
|
|
;------------------------------------------------------------------------
|
|
MaxSIB equ 8 ; maximum number of Screens
|
|
|
|
|
|
IF ANSI
|
|
TermSize EQU 20 ; max. size of terminal emulation state
|
|
ENDIF
|
|
|
|
SIBst struc
|
|
ctlS db 0 ; if the screen is NOT frozen = 0
|
|
; NOTE: this field should be the
|
|
; FIRST of each SIB !! (see ConWrit)
|
|
OffsetVal dw 7 ; start of Seg Descriptors
|
|
SegCnt dw MaxSeg ; max number of Segments
|
|
SIBlen dw (SIZE SIBst) ; length of the SIB
|
|
;--- Segments
|
|
db ((SIZE SEGst) * MaxSeg) dup (?)
|
|
;--- PC video state info
|
|
xCRT_MODE DB ?
|
|
xCRT_COLS DW ?
|
|
xCRT_LEN DW ?
|
|
xCRT_START DW ?
|
|
xCURSOR_POSN DW 8 DUP(?)
|
|
xCURSOR_MODE DW ?
|
|
xACTIVE_PAGE DB ?
|
|
xADDR_6845 DW ?
|
|
xCRT_MODE_SET DB ?
|
|
xCRT_PALETTE DB ?
|
|
xTERM_STATE DB TermSize DUP(?)
|
|
SIBst ends
|
|
|
|
|
|
subttl Request packet definitions
|
|
page
|
|
|
|
;------------------------------------------------------------------------
|
|
; Request packet offset definitions
|
|
;
|
|
|
|
CMDLEN = 0 ;LENGTH OF THIS COMMAND
|
|
UNIT = 1 ;SUB UNIT SPECIFIER
|
|
CMD = 2 ;COMMAND CODE
|
|
STATUS = 3 ;STATUS
|
|
MEDIA = 13 ;MEDIA DESCRIPTOR
|
|
TRANS = 14 ;TRANSFER ADDRESS
|
|
COUNT = 18 ;COUNT OF BLOCKS OR CHARACTERS
|
|
START = 20 ;FIRST BLOCK TO TRANSFER
|
|
|
|
|
|
subttl IBM-PC ROM Data area Locations
|
|
page
|
|
|
|
;------------------------------------------------------------------------
|
|
; IBM-PC ROM Data area Locations
|
|
;
|
|
|
|
RomData SEGMENT AT 40H
|
|
ORG 1AH
|
|
BufferHead DW ?
|
|
BufferTail DW ?
|
|
KeyBuffer DW 16 DUP (?)
|
|
KeyBufLen equ ($-KeyBuffer) ; length of KeyBuffer
|
|
|
|
ORG 49H
|
|
CRT_MODE DB ?
|
|
CRT_COLS DW ?
|
|
CRT_LEN DW ?
|
|
CRT_START DW ?
|
|
CURSOR_POSN DW 8 DUP(?)
|
|
CURSOR_MODE DW ?
|
|
ACTIVE_PAGE DB ?
|
|
ADDR_6845 DW ?
|
|
CRT_MODE_SET DB ?
|
|
CRT_PALETTE DB ?
|
|
|
|
CrtLen EQU ($-CRT_MODE) ; length of screen state area
|
|
RomData ENDS
|
|
|
|
MonoSc SEGMENT AT 0B000H
|
|
;--- 4k of screen memory
|
|
MonoSc ENDS
|
|
|
|
ColorSc SEGMENT AT 0B800H
|
|
;--- 16k of screen memory
|
|
ColorSc ENDS
|
|
|
|
BRKADR equ 006CH ; Break vector address
|
|
|
|
|
|
subttl Device Header
|
|
page
|
|
|
|
|
|
BiosSeg group Code,BiosInit
|
|
Code Segment byte public 'CODE'
|
|
|
|
;------------------------------------------------------------------------
|
|
; Device Header
|
|
;
|
|
|
|
assume cs:Code,ds:NOTHING,es:NOTHING,ss:NOTHING
|
|
|
|
PUBLIC CONDEV
|
|
IF INBIOS
|
|
extrn AUXDEV:FAR
|
|
CONDEV dd AUXDEV
|
|
ELSE
|
|
CONDEV dw 0FFFFh,0FFFFh
|
|
ENDIF ;INBIOS
|
|
;*** should ioctl bit be set for gen ioctl too?
|
|
dw 1100000000010011b ; console in and out
|
|
dw Strategy
|
|
dw Entry
|
|
db "CON "
|
|
|
|
|
|
;------------------------------------------------------------------------
|
|
; Command dispatch table
|
|
;
|
|
|
|
ComTbl:
|
|
;--- 2.0
|
|
dw OFFSET BiosSeg:$ConInit ; Initialization function
|
|
dw StatusComplete ; Media Check
|
|
dw StatusComplete ; Build BPB
|
|
dw CmdErr ; IOCTL Input
|
|
dw $ConRead ; Input (Read)
|
|
dw $ConRdnd ; Non-Destructive read, no wait
|
|
dw StatusComplete ; Input Status
|
|
dw $ConFlsh ; Input Flush
|
|
dw $ConWrit ; Output (Write)
|
|
dw $ConWrit ; Output with verify
|
|
dw StatusComplete ; Output Status
|
|
dw StatusComplete ; Output Flush
|
|
dw StatusComplete ; IOCTL Output
|
|
;--- 3.0
|
|
dw StatusComplete ; Device Open
|
|
dw StatusComplete ; Device Close
|
|
dw StatusComplete ; Removable Media
|
|
;--- 4.0
|
|
dw $GenIOCTL ; Generic IOCTL
|
|
dw $ConStop ; Pause Device
|
|
dw $ConStart ; Continue Device
|
|
|
|
ComTblEnd:
|
|
|
|
CTSIZE equ (ComTblEnd - ComTbl)/2 ; number of table entries
|
|
|
|
|
|
subttl Device Data Area
|
|
page
|
|
|
|
;------------------------------------------------------------------------
|
|
; Device Data Area
|
|
;
|
|
|
|
SaveFlg db 0 ; Screen being saved flag, (true = 1)
|
|
IF INBIOS
|
|
EXTRN DosFunction:DWORD
|
|
ELSE
|
|
DosFunction dd ? ; pointer to dos "helper" functions
|
|
ENDIF ;INBIOS
|
|
AltAH db 0 ; Side buffer for input
|
|
CurrSc dw 0 ; Current screen number
|
|
CurrSIB dw SIB ; offset to the current SIB
|
|
SIB SIBst MaxSIB dup (<>) ; allocate room for SIB's
|
|
|
|
IF EAGLE
|
|
ScreenLen db 08h ; table of (high byte of) regen. buffer
|
|
db 08h ; len. Indexed by screen mode.
|
|
db 10h ; 80x25 text modes
|
|
db 10h
|
|
db 40h ; graphics modes
|
|
db 40h
|
|
db 40h
|
|
db 10h ; monochrome
|
|
ENDIF
|
|
|
|
|
|
IFDEF DEBUGFLG
|
|
IF INBIOS
|
|
EXTRN BUGBITS:BYTE,DPRINTF:NEAR
|
|
ELSE
|
|
BUGBITS db 0ffh,0ffh
|
|
ENDIF
|
|
ENDIF
|
|
|
|
subttl Device Entry Points
|
|
page
|
|
|
|
;------------------------------------------------------------------------
|
|
; 2.0 Interrupt Routine (Not Used)
|
|
;
|
|
|
|
EntryP proc far
|
|
Entry: ret
|
|
EntryP endp
|
|
|
|
|
|
;------------------------------------------------------------------------
|
|
; 2.0 Strategy Routine, main entry point
|
|
;
|
|
; entry
|
|
; ES:BX points to Request packet
|
|
;
|
|
|
|
StratP proc far
|
|
|
|
Strategy:
|
|
IF INBIOS
|
|
extrn Interrupt:NEAR
|
|
|
|
push si
|
|
mov si,OFFSET CS:ComTbl
|
|
jmp Interrupt
|
|
ELSE
|
|
push ax ; save all
|
|
push cx
|
|
push dx
|
|
push si
|
|
push di
|
|
push bp
|
|
push ds
|
|
|
|
push es ; DS = ES
|
|
pop ds
|
|
|
|
push es
|
|
push bx
|
|
mov al, byte ptr ds:[bx].CMD
|
|
cmp al,CTSIZE ; Command within range?
|
|
jae CmdErr ; no must be an error
|
|
mov cx, word ptr ds:[bx].COUNT
|
|
les di, dword ptr ds:[bx].TRANS
|
|
xor ah,ah
|
|
mov si, offset ComTbl
|
|
add si,ax
|
|
add si,ax
|
|
|
|
jmp word ptr cs:[si] ; dispatch
|
|
ENDIF ;INBIOS
|
|
|
|
StratP endp
|
|
|
|
|
|
subttl Exit Routines
|
|
page
|
|
|
|
;------------------------------------------------------------------------
|
|
; Exit Routines, Common to all device functions
|
|
;
|
|
|
|
IF INBIOS
|
|
extrn StatusComplete:NEAR,StatusError:NEAR,StatusDevReady:NEAR
|
|
extrn CmdErr:NEAR
|
|
ELSE
|
|
|
|
assume ds:NOTHING,es:NOTHING
|
|
|
|
StatusDevReady:
|
|
mov ah,00000011b ; device busy
|
|
jmp short errEx
|
|
|
|
CmdErr:
|
|
mov al,3 ; Unknown command Error
|
|
StatusError:
|
|
mov ah,10000001b
|
|
jmp short errEx
|
|
|
|
ExitP proc far
|
|
StatusComplete: mov ah,00000001b
|
|
errEx: pop bx
|
|
pop es
|
|
|
|
mov word ptr es:[bx].STATUS,ax ; put status out
|
|
|
|
pop ds
|
|
pop bp
|
|
pop di
|
|
pop si
|
|
pop dx
|
|
pop cx
|
|
pop ax
|
|
ret
|
|
ExitP endp
|
|
|
|
ENDIF ;INBIOS
|
|
|
|
|
|
subttl Break - Break interrupt routine
|
|
page
|
|
|
|
;------------------------------------------------------------------------
|
|
; Break interrupt routine
|
|
;
|
|
|
|
assume ds:NOTHING,es:NOTHING
|
|
|
|
Break PROC NEAR
|
|
int 32H ; save registers
|
|
cli ; ints should be off, make sure!
|
|
mov ax,RomData
|
|
mov ds,ax
|
|
assume ds:RomData
|
|
mov ax,offset RomData:KeyBuffer
|
|
mov [BufferHead],ax
|
|
mov [BufferTail],ax
|
|
assume ds:NOTHING
|
|
mov ax,3 ; send char to system
|
|
mov dx,5 ; ConsInputFilter subfunction
|
|
call [DosFunction]
|
|
jz brk1 ; key was eaten by system
|
|
mov [AltAH],al ; force a ^C
|
|
brk1:
|
|
iret
|
|
Break ENDP
|
|
|
|
SUBTTL Keyboard interrupt routine
|
|
PAGE
|
|
; Replacement for ROM keyboard interrupt, tacks on the front.
|
|
; OldKeyInterrupt is set to original contents of INT 09H.
|
|
; The input character is passed to the O.S. console input filter
|
|
; to determine if any special action should be taken. The filter
|
|
; return value indicates if the character should be saved in the
|
|
; type ahead buffer or if it should be discarded. A keyboard
|
|
; semaphore exists to indicate if a process is waiting for input.
|
|
; If the keboard semaphore is set all of the processes sleeping on
|
|
; it are woken up.
|
|
|
|
OldKeyInterrupt DD ?
|
|
KeySem db 0 ; non-zero if someone waiting on input
|
|
|
|
KeyboardInterrupt PROC FAR
|
|
INT 32H ; Save regs
|
|
MOV AX,RomData
|
|
MOV DS,AX
|
|
ASSUME DS:RomData
|
|
|
|
PUSHF ; Save flags to simulate INT
|
|
CALL CS:OldKeyInterrupt ; Now do ROM code
|
|
; Now tell DOS keyboard had char
|
|
cli ; interrupts off!
|
|
mov bx,BufferTail ; Get tail of queue
|
|
cmp bx,BufferHead ; Anything in keyboard queue?
|
|
JE NoKey ; No, don't requeue then
|
|
dec bx
|
|
dec bx
|
|
cmp bx,offset RomData:KeyBuffer
|
|
jae kbi1 ; no wrap around in buffer
|
|
mov bx,offset RomData:KeyBuffer+(KeyBufLen-2)
|
|
kbi1:
|
|
mov ax,[bx] ; get last queued char.
|
|
mov dx,5 ; ConsInputFilter subfunction
|
|
call [DosFunction]
|
|
jnz kbi2 ; key should remain in buffer
|
|
mov BufferTail,bx ; discard key from buffer
|
|
jmp SHORT NoKey
|
|
kbi2:
|
|
cli
|
|
CMP KeySem,0 ; Outstanding request?
|
|
JE NoKey ; No, may not be inited either
|
|
push ax
|
|
push bx
|
|
push cx
|
|
push dx
|
|
mov ax,cs
|
|
mov bx,OFFSET KeySem
|
|
mov cs:byte ptr [bx],0 ; reset keyboard semaphore
|
|
mov dx,10 ;; ProcRun
|
|
call [DosFunction] ; awaken anyone waiting on input
|
|
pop dx
|
|
pop cx
|
|
pop bx
|
|
pop ax
|
|
NoKey:
|
|
IRET
|
|
KeyBoardInterrupt ENDP
|
|
|
|
;-------------------------------------------------------------
|
|
; Keyboard INT 16 intercept routine to allow console input to sleep.
|
|
; Only console input function 1 is intercepted, all other functions
|
|
; are allowed to go directly to the ROM BIOS. For the function 1
|
|
; the input status is checked, if a character is ready the function
|
|
; is allowed to go to the ROM BIOS. Otherwise the keyboard semaphore
|
|
; is set and the process is put to sleep on the address of the
|
|
; semaphore. When a key is typed the keyboard interrupt routine
|
|
; will wakeup any processes sleeping on this semaphore.
|
|
;
|
|
; WARNING: The following routines can be entered recursively
|
|
; due to the fact that the ROM BIOS routines called
|
|
; reenable interrupts. It's not usually a problem
|
|
; since interrupts will generally be processed faster
|
|
; than anyone can type.
|
|
|
|
OldKbdHandler dd ?
|
|
ScrnIoOk dd ?
|
|
|
|
;-------------------------------------------------------------
|
|
|
|
KeyBoardHandler proc far
|
|
or ah,ah
|
|
je DoLocalRead
|
|
cmp ah,1
|
|
je DoLocalStat
|
|
OldKBint:
|
|
jmp [OldKbdHandler]
|
|
|
|
DoLocalStat:
|
|
push bx
|
|
push ds
|
|
lds bx,ScrnIoOk
|
|
test byte ptr [bx],0FFh
|
|
pop ds
|
|
pop bx
|
|
jnz OldKBint
|
|
xor ax,ax
|
|
ret 2
|
|
DoInt16 LABEL FAR ; entry for ChrIn
|
|
DoLocalRead:
|
|
push ax
|
|
push bx
|
|
push cx
|
|
push dx
|
|
DoLocalRd1:
|
|
push ds
|
|
lds bx,ScrnIoOk
|
|
mov ax,ds
|
|
test byte ptr [bx],0FFh
|
|
pop ds
|
|
jnz DoLocalRd2
|
|
xor cx,cx
|
|
mov dx,9 ;; ProcBlock
|
|
call [DosFunction] ; sleep until a screen switch
|
|
jmp DoLocalRd1
|
|
|
|
DoLocalRd2:
|
|
mov ah,1 ; get console status
|
|
pushf ; simulate INT to old handler
|
|
cli
|
|
call [OldKbdHandler]
|
|
cli ; subfunction 1 unconditionally sets IF
|
|
jnz LocalRead ; go read character
|
|
mov ax,cs
|
|
mov bx,OFFSET KeySem
|
|
mov cs:byte ptr [bx],0FFh ; set keyboard semaphore
|
|
xor cx,cx
|
|
mov dx,9 ;; ProcBlock
|
|
call [DosFunction] ; sleep until a char is typed
|
|
jmp DoLocalRd1
|
|
|
|
LocalRead:
|
|
pop dx
|
|
pop cx
|
|
pop bx
|
|
pop ax
|
|
jmp [OldKbdHandler] ; read the character and return
|
|
|
|
KeyBoardHandler endp
|
|
|
|
|
|
subttl $ConRead - Console Input (Read)
|
|
page
|
|
|
|
;------------------------------------------------------------------------
|
|
; Console Input (Read)
|
|
;
|
|
; entry:
|
|
; DS:BX = pointer to Request packet
|
|
; ES:DI = Transfer address
|
|
; CX = Count
|
|
;
|
|
|
|
assume ds:NOTHING,es:NOTHING
|
|
|
|
$ConRead:
|
|
and cx,cx
|
|
jnz jgl2
|
|
jmp CRExit
|
|
; jcxz CRExit ; no chars to read BUGBUG restore
|
|
jgl2: cld ; make sure!
|
|
mov dx,word ptr ds:[bx].START ; get screen number
|
|
cmp dx,(MaxSIB-1) ; valid number?
|
|
jbe ConRLoop ; yes, do input
|
|
mov al,0BH ; no, READ FAULT ERROR
|
|
jmp StatusError
|
|
ConRLoop:
|
|
DEBUG 10h,1,<CONR:$x=$x? >,<dx,CurrSc>
|
|
cmp dx,[CurrSc]
|
|
je sjp0
|
|
call GetSIBAdr ; get pointer to the SIB
|
|
DEBUG 10h,1,<Block read wrong screen >,<>
|
|
call DoPBlock ; block the process
|
|
jmp short ConRLoop ; test flag again
|
|
sjp0:
|
|
call ChrIn
|
|
stosb
|
|
; loop ConRLoop
|
|
loop jgl3
|
|
CRExit: jmp StatusComplete
|
|
|
|
jgl3: jmp ConRLoop
|
|
|
|
subttl ChrIn - Read a single character In
|
|
page
|
|
|
|
;------------------------------------------------------------------------
|
|
; Read a single character In
|
|
;
|
|
; exit:
|
|
; Character in AL
|
|
;
|
|
; modifies: AX
|
|
;
|
|
|
|
assume ds:NOTHING,es:NOTHING
|
|
|
|
ChrIn:
|
|
DEBUG 10h,1,<in.ChrIn >,<>
|
|
xor ax,ax
|
|
xchg al,[AltAH] ; Get Character & zero AltAH
|
|
or al,al ; A char available?
|
|
jnz KeyRet
|
|
;
|
|
;--- NOTE: The blocking on read is done at int 16h level
|
|
; in IBMBIO. No need to block here.
|
|
;
|
|
DEBUG 10h,1,< con.do.16 >,<>
|
|
mov ah,0 ; no, do a read call
|
|
pushf
|
|
call DoInt16
|
|
;; int 16h
|
|
DEBUG 10h,1,< con.got.$x >,<ax>
|
|
or ax,ax ; check for non-key after BREAK
|
|
jnz jgl1
|
|
jmp chrin
|
|
|
|
jgl1: cmp ax,7200h ; CTRL-PRTSC ?
|
|
jnz sja0
|
|
mov al,10h ; yes, make it a ctrl-P
|
|
sja0: or al,al ; special case?
|
|
jnz KeyRet
|
|
mov [AltAH],ah
|
|
KeyRet:
|
|
ret
|
|
|
|
|
|
subttl $ConRdnd - Console non-destructive Input, no wait
|
|
page
|
|
|
|
;------------------------------------------------------------------------
|
|
; Console non-destructive Input, no wait
|
|
;
|
|
; entry:
|
|
; DS:BX = pointer to Request packet
|
|
;
|
|
|
|
assume ds:NOTHING,es:NOTHING
|
|
|
|
$ConRdnd:
|
|
mov dx,word ptr ds:[bx].START ; get screen number
|
|
cmp dx,(MaxSIB-1) ; valid number?
|
|
jbe sjq0 ; yes, do input
|
|
mov al,0BH ; no, READ FAULT ERROR
|
|
jmp StatusError
|
|
sjq0:
|
|
DEBUG 10h,1,<CNDR:$x=$x? >,<dx,CurrSc>
|
|
cmp dx,[CurrSc]
|
|
IFDEF DEBUGFLG
|
|
je sjq1
|
|
jmp ConBus
|
|
ELSE
|
|
jne ConBus ; not current screen, no char avail
|
|
ENDIF
|
|
; call GetSIBAdr ; get pointer to the SIB
|
|
; call DoPBlock ; block the process
|
|
; jmp short sjq0 ; test flag again
|
|
sjq1:
|
|
mov al,[AltAH] ; char avail already?
|
|
or al,al
|
|
jnz rdExit
|
|
DEBUG 10h,1,< NRD:do.16 >,<>
|
|
mov ah,1 ; no, get status
|
|
int 16h
|
|
jz ConBus
|
|
DEBUG 10h,1,< NRD:nonbus $x >,<ax>
|
|
or ax,ax
|
|
jnz NotBk ; Check for null after break
|
|
mov ah,0 ; flush the null
|
|
int 16h
|
|
jmp $ConRdnd ; try again
|
|
; jmp short $ConRdnd ; try again BUGBUG
|
|
NotBk:
|
|
cmp ax,7200h ; CTRL-PRTSC ?
|
|
jnz rdExit
|
|
mov al,10h ; yes, make it a ctrl-P
|
|
rdExit:
|
|
mov byte ptr ds:[bx].MEDIA,al ; save character
|
|
DoExit: jmp StatusComplete
|
|
|
|
ConBus: DEBUG 10h,1,< ConBus - >,<>
|
|
jmp StatusDevReady
|
|
|
|
|
|
subttl $ConFlsh - Console Flush Input
|
|
page
|
|
|
|
;------------------------------------------------------------------------
|
|
; Console Flush Input
|
|
;
|
|
; entry:
|
|
; DS:BX = pointer to Request packet
|
|
;
|
|
|
|
assume ds:NOTHING,es:NOTHING
|
|
|
|
$ConFlsh:
|
|
mov dx,word ptr ds:[bx].START ; get screen number
|
|
cmp dx,(MaxSIB-1) ; valid number?
|
|
jbe sjr0 ; yes, do flush
|
|
mov al,0BH ; no, READ FAULT ERROR
|
|
jmp StatusError
|
|
sjr0:
|
|
cmp dx,[CurrSc]
|
|
je sjr1
|
|
call GetSIBAdr ; get pointer to the SIB
|
|
call DoPBlock ; block the process
|
|
jmp short sjr0 ; test flag again
|
|
sjr1:
|
|
mov [AltAH],0 ; clear side bufer
|
|
push ds
|
|
mov ax,RomData
|
|
mov ds,ax
|
|
assume ds:RomData
|
|
cli ; Disable interrupts
|
|
mov ax,offset RomData:KeyBuffer ; Start of Rom buffer
|
|
mov [BufferHead],ax
|
|
mov [BufferTail],ax ; Empty the queue
|
|
sti
|
|
pop ds
|
|
assume ds:NOTHING
|
|
jmp StatusComplete
|
|
|
|
|
|
subttl $ConWrit - Console Output (Write)
|
|
page
|
|
|
|
;------------------------------------------------------------------------
|
|
; Console Output (Write)
|
|
;
|
|
; entry:
|
|
; DS:BX = pointer to Request packet
|
|
; ES:DI = Transfer address
|
|
; CX = Count
|
|
;
|
|
|
|
assume ds:NOTHING,es:NOTHING
|
|
|
|
$ConWrit:
|
|
jcxz CWExit
|
|
mov dx, word ptr ds:[bx].START ; get screen number
|
|
cmp dx,(MaxSIB-1) ; valid screen number?
|
|
jbe sjb0
|
|
mov al,0AH ; no, write fault error
|
|
jmp StatusError
|
|
sjb0: push cs
|
|
pop ds
|
|
assume ds:Code
|
|
mov bx,[CurrSIB]
|
|
|
|
ConWLoop:
|
|
cmp dx,[CurrSc] ; Is it to the current screen?
|
|
je sjb2 ; yes, do not block
|
|
call GetSIBAdr ; get pointer to the SIB
|
|
sjb1: call DoPBlock ; block the process
|
|
jmp short ConWLoop ; test ALL flags again
|
|
sjb2:
|
|
cmp [bx].ctlS,0 ; is the screen frozen?
|
|
je sjb3
|
|
mov ax,bx ; AX = [CurrSIB] = [CurrSIB].ctlS !!!!
|
|
jmp short sjb1 ; yes, block the process
|
|
sjb3:
|
|
cmp [SaveFlg],0 ; are we in the middle of a save?
|
|
je sjb4 ; no, do write
|
|
mov ax,offset SaveFlg
|
|
jmp short sjb1 ; yes, block...
|
|
sjb4:
|
|
mov al,es:[di] ; get a character
|
|
inc di
|
|
call CharOut
|
|
loop ConWLoop
|
|
CWExit: jmp StatusComplete
|
|
|
|
|
|
subttl CharOut - Output a character to the screen
|
|
page
|
|
|
|
;------------------------------------------------------------------------
|
|
; Output a character to the screen
|
|
;
|
|
; entry:
|
|
; AL = Character to write
|
|
;
|
|
; preserves:
|
|
; BX, CX, DX, DI, DS & ES
|
|
;
|
|
|
|
assume ds:NOTHING,es:NOTHING
|
|
|
|
IF ANSI
|
|
include ansi.inc
|
|
ELSE
|
|
CharOut:
|
|
push bx
|
|
push di
|
|
mov bx,7
|
|
mov ah,14
|
|
int 10h ; Write Character
|
|
pop di
|
|
pop bx
|
|
ret
|
|
ENDIF
|
|
|
|
|
|
subttl $GenIOCTL - Generic IOCTL
|
|
page
|
|
|
|
;------------------------------------------------------------------------
|
|
; Generic IOCTL
|
|
;
|
|
; entry:
|
|
; DS:BX = pointer to Request packet
|
|
;
|
|
|
|
;--- Offsets into the request packet
|
|
;*** Check offset are correct
|
|
FunCode = 14 ; Function Code
|
|
FunCat = 13 ; Function Category
|
|
;***
|
|
RegSI = 15 ; Contents of SI
|
|
RegDI = 17 ; Contents of DI
|
|
DatBuf = 19 ; Pointer to data buffer
|
|
|
|
;--- Code & Category definitions
|
|
IOC_SC = 03h ;--- Screen Control
|
|
IOSC_LS = 41h ; Locate SIB
|
|
IOSC_SS = 42h ; save segment
|
|
IOSC_RS = 43h ; restore segment
|
|
IOSC_EI = 44h ; re-enable i/o
|
|
IOSC_IS = 45h ; initialize screen
|
|
|
|
assume ds:NOTHING,es:NOTHING
|
|
|
|
$GenIOCTL:
|
|
cmp byte ptr ds:[bx].FunCode,IOC_SC
|
|
jne GI_BadCode ; function not suported
|
|
mov si,word ptr ds:[bx].RegSI
|
|
mov al,byte ptr ds:[bx].FunCat
|
|
cmp al,IOSC_LS
|
|
jne sjc0
|
|
jmp short do_IOSC_LS
|
|
sjc0: cmp al,IOSC_SS
|
|
jne sjc1
|
|
jmp short do_IOSC_SS
|
|
sjc1: cmp al,IOSC_RS
|
|
jne sjc2
|
|
jmp do_IOSC_RS
|
|
sjc2: cmp al,IOSC_EI
|
|
jne sjc3
|
|
jmp do_IOSC_EI
|
|
sjc3: cmp al,IOSC_IS
|
|
jne GI_BadCode
|
|
jmp do_IOSC_IS
|
|
|
|
GI_BadCode:
|
|
jmp CmdErr ; error exit: Command error
|
|
|
|
|
|
subttl do_IOSC_LS - Locate SIB
|
|
page
|
|
|
|
;------------------------------------------------------------------------
|
|
; Locate SIB
|
|
;
|
|
; entry:
|
|
; SI = SIB Number
|
|
; DS:BX = pointer to Request packet
|
|
;
|
|
|
|
assume ds:NOTHING,es:NOTHING
|
|
|
|
do_IOSC_LS:
|
|
cmp si,(MaxSIB-1) ; index within range?
|
|
ja BadNum
|
|
push bx
|
|
push ds
|
|
push cs
|
|
pop ds
|
|
assume ds:Code
|
|
cmp si,[CurrSc] ; is it the current screen?
|
|
je CurrLS
|
|
mov [CurrSc],si ; no, just switch curr screens
|
|
mov dx,si ; index
|
|
call GetSIBAdr ; get pointer to SIB
|
|
mov [CurrSIB],ax ; save pointer to curr SIB
|
|
jmp short retLS
|
|
|
|
CurrLS:
|
|
mov [SaveFlg],1 ; Signal we are Saving the screen
|
|
|
|
;*** Only one segment for now
|
|
|
|
mov ax,0
|
|
call GetSegAdr ; on return BX points to segment
|
|
mov ax,RomData
|
|
mov es,ax
|
|
assume es:RomData
|
|
IF EAGLE
|
|
mov al,es:[CRT_MODE]
|
|
xor ah,ah
|
|
mov si,ax
|
|
mov ah,ScreenLen[si]
|
|
xor al,al
|
|
ELSE
|
|
mov ax,es:[CRT_LEN]
|
|
assume es:NOTHING ; not true, but just to be safe
|
|
ENDIF
|
|
mov [bx].SizeNeeded,ax ; save size of segment
|
|
mov ax,dx ; pointer to current SIB
|
|
retLS:
|
|
pop ds
|
|
pop bx
|
|
assume ds:NOTHING
|
|
mov word ptr ds:[bx].DatBuf,ax ; offset
|
|
mov word ptr ds:[bx].DatBuf+2,cs ; segment
|
|
mov word ptr ds:[bx].RegSI,0 ; operation ok
|
|
jmp StatusComplete
|
|
|
|
BadNum:
|
|
mov word ptr ds:[bx].RegSI,1 ; bad SIB number error
|
|
jmp StatusComplete
|
|
|
|
|
|
subttl do_IOSC_SS - Save Segment
|
|
page
|
|
|
|
;------------------------------------------------------------------------
|
|
; Save Segment
|
|
;
|
|
; entry:
|
|
; SI = Segment Index (into the Current SIB)
|
|
; DS:BX = pointer to Request packet
|
|
;
|
|
|
|
assume ds:NOTHING,es:NOTHING
|
|
|
|
do_IOSC_SS:
|
|
cmp si,(MaxSeg-1) ; within range?
|
|
BadNumJ1:
|
|
ja BadNum ; no, somebody screwed up...
|
|
push bx
|
|
push ds
|
|
cmp si,0 ; first segment save?
|
|
jne nfSS ; no, just save screen data
|
|
;--- save screen state data
|
|
push si ; save index
|
|
mov ax,RomData
|
|
mov ds,ax ; DS = ROM data area
|
|
assume ds:RomData
|
|
mov si,offset RomData:CRT_MODE
|
|
mov cx,CrtLen ; length of screen state data
|
|
push cs
|
|
pop es
|
|
assume es:Code
|
|
mov di,[CurrSIB]
|
|
lea di,[di].xCRT_MODE
|
|
cld
|
|
rep movsb ; copy ROM info to SIB area
|
|
IF ANSI
|
|
push cs
|
|
pop ds
|
|
assume ds:Code
|
|
mov si,offset AnsiState ; point to ANSI state info
|
|
mov cx,AnsiSize
|
|
rep movsb ; save ANSI state info in SIB
|
|
ENDIF
|
|
pop si ; restore segment index
|
|
;--- save a segment of screen data
|
|
nfSS:
|
|
push cs
|
|
pop ds
|
|
assume ds:Code
|
|
mov ax,si
|
|
call GetSegAdr ; get adress of segment and curr SIB ptr
|
|
mov cx,[bx].SizeNeeded ; CX = Ammount to transfer
|
|
shr cx,1 ; words!
|
|
les di,[bx].MPointer ; ES:DI = Screen save area
|
|
assume es:NOTHING
|
|
|
|
;*** For now we are using only one segment
|
|
|
|
mov si,dx ; SI points to the current SIB
|
|
mov bx,ColorSc ; assume color card
|
|
cmp [si].xCRT_MODE,7 ; is this a BW monitor?
|
|
jne do_save
|
|
mov bx,MonoSc
|
|
do_save:
|
|
IF BLANK
|
|
mov dx,[si].xADDR_6845 ; point to mode register
|
|
add dx,4
|
|
mov al,[si].xCRT_MODE_SET ; and get value
|
|
and al,NOT 8
|
|
out dx,al ; turn off video
|
|
ENDIF
|
|
mov ds,bx ; DS points to apropiate screen area
|
|
assume ds:NOTHING
|
|
mov si,0
|
|
cld
|
|
rep movsw ; copy the screen
|
|
IF BLANK
|
|
or al,8
|
|
out dx,al ; turn on video
|
|
ENDIF
|
|
pop ds
|
|
pop bx
|
|
mov word ptr ds:[bx].RegSI,0 ; operation ok
|
|
jmp StatusComplete
|
|
|
|
|
|
subttl do_IOSC_RS - Restore Segment
|
|
page
|
|
|
|
;------------------------------------------------------------------------
|
|
; Restore Segment
|
|
;
|
|
; entry:
|
|
; SI = Segment Index (into the Current SIB)
|
|
; DS:BX = pointer to Request packet
|
|
;
|
|
|
|
assume ds:NOTHING,es:NOTHING
|
|
|
|
do_IOSC_RS:
|
|
cmp si,(MaxSeg-1) ; within range?
|
|
ja BadNumJ1 ; no, somebody screwed up...
|
|
push bx
|
|
push ds
|
|
push cs
|
|
pop ds
|
|
assume ds:Code
|
|
cmp si,0 ; first segment save?
|
|
jne nfRS ; no, just restore screen data
|
|
;--- restore screen state data
|
|
push si ; save index
|
|
mov si,[CurrSIB]
|
|
push si
|
|
lea si,[si].xCRT_MODE
|
|
mov ax,RomData
|
|
mov es,ax ; ES = ROM data area
|
|
assume es:RomData
|
|
mov cx,CrtLen ; length of screen state data
|
|
mov di,offset RomData:CRT_MODE
|
|
cld
|
|
rep movsb ; copy ROM info from SIB area
|
|
IF ANSI
|
|
push es
|
|
push cs
|
|
pop es
|
|
assume es:Code
|
|
mov di,offset AnsiState ; point to ANSI state info
|
|
mov cx,AnsiSize
|
|
rep movsb ; restore ANSI state info from SIB
|
|
pop es
|
|
assume es:RomData
|
|
ENDIF
|
|
|
|
;--- Setup new screen state
|
|
pop si
|
|
mov al,[si].xCRT_MODE
|
|
cmp al,7 ; is this the BW monitor?
|
|
jne sjd0
|
|
mov al,2 ; this is the "real" mode
|
|
sjd0:
|
|
mov ah,0
|
|
int 10h ; set new mode
|
|
mov cx,[si].xCURSOR_MODE
|
|
mov ah,1
|
|
int 10h ; set cursor type
|
|
mov dx,[si].xCURSOR_POSN
|
|
mov bh,[si].xACTIVE_PAGE
|
|
mov ah,2
|
|
int 10h ; set cursor position
|
|
mov al,[si].xACTIVE_PAGE
|
|
mov ah,5
|
|
int 10h ; set page #
|
|
mov dx,[si].xADDR_6845
|
|
add dx,5
|
|
mov al,[si].xCRT_PALETTE
|
|
out dx,al ; set color port
|
|
mov es:CRT_PALETTE,al
|
|
pop si ; restore segment index
|
|
;--- restore a segment of screen data
|
|
nfRS:
|
|
mov ax,si
|
|
call GetSegAdr ; get adress of segment
|
|
mov cx,[bx].SizeNeeded ; CX = Ammount to transfer
|
|
shr cx,1 ; words!
|
|
lds si,[bx].MPointer ; DS:SI = Screen save area
|
|
assume ds:NOTHING
|
|
|
|
;*** For now we are using only one segment
|
|
|
|
mov di,dx ; DI points to the current SIB
|
|
mov bx,ColorSc ; assume color card
|
|
cmp cs:[di].xCRT_MODE,7 ; is this a BW monitor?
|
|
jne do_rest
|
|
mov bx,MonoSc
|
|
do_rest:
|
|
IF BLANK
|
|
mov dx,cs:[di].xADDR_6845 ; point to mode register
|
|
add dx,4
|
|
mov al,cs:[di].xCRT_MODE_SET ; and get value
|
|
and al,NOT 8
|
|
out dx,al ; turn off video
|
|
ENDIF
|
|
mov es,bx ; ES points to apropiate screen area
|
|
assume es:NOTHING
|
|
mov di,0
|
|
cld
|
|
rep movsw ; copy the screen
|
|
IF BLANK
|
|
or al,8
|
|
out dx,al ; turn on video
|
|
ENDIF
|
|
|
|
pop ds
|
|
assume ds:NOTHING
|
|
pop bx
|
|
mov word ptr ds:[bx].RegSI,0 ; operation ok
|
|
jmp StatusComplete
|
|
|
|
BadNumJ:
|
|
jmp BadNum
|
|
|
|
|
|
subttl do_IOSC_EI - Re-enable i/o
|
|
page
|
|
|
|
;------------------------------------------------------------------------
|
|
; Re-enable i/o
|
|
;
|
|
; entry:
|
|
; DS:BX = pointer to Request packet
|
|
;
|
|
|
|
assume ds:NOTHING,es:NOTHING
|
|
|
|
do_IOSC_EI:
|
|
mov [SaveFlg],0 ; Signal we are done Saving the screen
|
|
mov ax,offset Code:SaveFlg
|
|
call DoPRun ; ProcRun
|
|
mov ax,[CurrSIB] ; pointer to current SIB
|
|
call DoPRun ; ProcRun any output blocked because
|
|
; screen was not current
|
|
jmp StatusComplete
|
|
|
|
|
|
subttl do_IOSC_IS - Initialize Screen
|
|
page
|
|
|
|
;------------------------------------------------------------------------
|
|
; Initialize Screen
|
|
;
|
|
; entry:
|
|
; SI = SIB Number
|
|
; DS:BX = pointer to Request packet
|
|
;
|
|
|
|
assume ds:NOTHING,es:NOTHING
|
|
|
|
do_IOSC_IS:
|
|
cmp si,(MaxSIB-1) ; index within range?
|
|
ja BadNumJ
|
|
push ds
|
|
push cs
|
|
pop ds
|
|
assume ds:Code
|
|
mov [CurrSc],si ; switch curr screens
|
|
mov dx,si ; index
|
|
call GetSIBAdr ; get pointer to SIB
|
|
mov [CurrSIB],ax ; save pointer to curr SIB
|
|
mov si,ax
|
|
mov [si].ctlS,0 ; screen not frozen
|
|
;--- set screen mode to pc mode 3 (80x25 BW)
|
|
mov ax,0003 ; Set mode 3
|
|
int 10h
|
|
pop ds
|
|
assume ds:NOTHING
|
|
mov word ptr ds:[bx].RegSI,0 ; operation ok
|
|
jmp StatusComplete
|
|
|
|
|
|
subttl $ConStop - Stop (freeze) console output
|
|
page
|
|
|
|
;------------------------------------------------------------------------
|
|
; Stop (freeze) console output
|
|
;
|
|
|
|
assume ds:NOTHING,es:NOTHING
|
|
|
|
$ConStop:
|
|
mov bx,[CurrSIB] ; pointer to current SIB
|
|
mov cs:[bx].ctlS,01 ; set the freeze flag
|
|
jmp StatusComplete
|
|
|
|
|
|
subttl $ConStart - Start (continue) console output
|
|
page
|
|
|
|
;------------------------------------------------------------------------
|
|
; Start (continue) console output
|
|
;
|
|
|
|
assume ds:NOTHING,es:NOTHING
|
|
|
|
$ConStart:
|
|
mov bx,[CurrSIB] ; pointer to current SIB
|
|
cmp cs:[bx].ctlS,0 ; is it already going?
|
|
je csRet ; yes, no need to re-enable
|
|
mov cs:[bx].ctlS,0 ; reset the freeze flag
|
|
lea ax,[bx].ctlS ; get address of current ctlS
|
|
call DoPRun ; do ProcRun
|
|
csRet: jmp StatusComplete
|
|
|
|
|
|
subttl DoPBlock - Block the current process
|
|
page
|
|
|
|
;------------------------------------------------------------------------
|
|
; Block the current process
|
|
;
|
|
; entry:
|
|
; CS:AX = address to block on
|
|
;
|
|
; modifies: AX, FLAGS
|
|
;
|
|
|
|
assume ds:NOTHING,es:NOTHING
|
|
|
|
DoPBlock:
|
|
push bx
|
|
push cx
|
|
push dx
|
|
mov bx,ax
|
|
mov ax,cs ; AX:BX = event identifier
|
|
xor cx,cx ; No timeout
|
|
;; mov dx,0109h ;;BUGBUG - should be interruptible wait; will
|
|
;; give InternalError (SchedFind - not on Q)
|
|
mov dx,0009h ; PROCBLOC function
|
|
cli ; No races!
|
|
call [DosFunction]
|
|
pop dx ; on return ints are back on
|
|
pop cx
|
|
pop bx
|
|
ret
|
|
|
|
|
|
subttl DoPRun - Restart a process
|
|
page
|
|
|
|
;------------------------------------------------------------------------
|
|
; Restart a process
|
|
;
|
|
; entry:
|
|
; CS:AX = address to signal on (same as blocked on)
|
|
;
|
|
; modifies: AX, FLAGS
|
|
;
|
|
|
|
assume ds:NOTHING,es:NOTHING
|
|
|
|
DoPRun:
|
|
push bx
|
|
push cx
|
|
push dx
|
|
mov bx,ax
|
|
mov ax,cs
|
|
mov dx,10 ; PROCRUN function
|
|
call [DosFunction]
|
|
pop dx
|
|
pop cx
|
|
pop bx
|
|
ret
|
|
|
|
|
|
subttl GetSIBAdr - Return SIB address
|
|
page
|
|
|
|
;------------------------------------------------------------------------
|
|
; Returns the adress of the specified SIB
|
|
;
|
|
; entry:
|
|
; DX = index to the SIB
|
|
;
|
|
; exit:
|
|
; AX = pointer to the SIB
|
|
;
|
|
; preserves: ALL
|
|
;
|
|
|
|
assume ds:Code,es:NOTHING
|
|
|
|
GetSIBAdr:
|
|
push dx ; save screen #
|
|
mov ax,dx ; index
|
|
mov dx,(SIZE SIBst)
|
|
mul dx ; multiply by size of SIB entry
|
|
pop dx ; restore screen #
|
|
add ax,offset SIB ; AX = pointer to SIB for the write
|
|
ret
|
|
|
|
|
|
subttl GetSegAdr - Return segment address
|
|
page
|
|
|
|
;------------------------------------------------------------------------
|
|
; Returns the adress of a segment in the current SIB
|
|
;
|
|
; entry:
|
|
; AX = index to the segment
|
|
;
|
|
; exit:
|
|
; BX = pointer to the segment
|
|
; DX = pointer to the Current SIB
|
|
;
|
|
|
|
assume ds:Code,es:NOTHING
|
|
|
|
GetSegAdr:
|
|
mov dx,(SIZE SEGst)
|
|
mul dx ; multiply by size of SEG entry
|
|
mov bx,[CurrSIB] ; pointer to SIB
|
|
mov dx,bx ; save for exit
|
|
mov bx,[bx].OffsetVal ; pointer to start of SEGs in SIB
|
|
add bx,ax ; BX = pointer to SEG from start of SIB
|
|
add bx,dx ; BX = absolute pointer to SEG to use
|
|
ret
|
|
|
|
ifdef DEBUGFLG
|
|
if NOT INBIOS
|
|
INCLUDE BUGCODE.INC
|
|
endif
|
|
endif
|
|
|
|
|
|
subttl $ConInit - Initialization Routine
|
|
page
|
|
|
|
;------------------------------------------------------------------------
|
|
; Initialization Routine
|
|
;
|
|
;entry:
|
|
; DS:BX = pointer to Request packet
|
|
; ES:DI = Dos Functions entry point address
|
|
;
|
|
|
|
assume ds:NOTHING,es:NOTHING
|
|
|
|
$ConInit:
|
|
IF NOT INBIOS
|
|
push ds ; print greeting
|
|
push cs
|
|
pop ds
|
|
mov dx,offset Intro
|
|
MOV ah,9
|
|
int 21h
|
|
pop ds
|
|
mov word ptr ds:[bx].TRANS, offset $ConInit
|
|
mov word ptr ds:[bx].TRANS+2,cs
|
|
ENDIF
|
|
mov cs:Word Ptr DosFunction,di ; Save pointer to service routines
|
|
mov cs:Word Ptr DosFunction+2,es
|
|
|
|
mov ax,0
|
|
mov cx,1
|
|
mov dx,16
|
|
call [DosFunction] ; get DOS variable ScrnIoOk
|
|
mov word ptr ScrnIoOk,ax
|
|
mov word ptr ScrnIoOk+2,dx
|
|
|
|
;* Initialize interrupt vectors.
|
|
;;BUGBUG - we should be using Get/Set_Interrupt_Vector calls
|
|
|
|
xor ax,ax ; initialize break interrupt handler
|
|
mov es,ax ; points to page 0
|
|
mov ax,cs
|
|
mov word ptr es:BRKADR,offset Break
|
|
mov word ptr es:BRKADR+2,ax ; Vector for Break
|
|
|
|
MOV DI,9*4 ; INT 9 - Keyboard interrupt vector
|
|
MOV CX,es:[DI] ; Save old addr to hook to
|
|
MOV WORD PTR OldKeyInterrupt,CX
|
|
MOV CX,es:2[DI]
|
|
MOV WORD PTR (OldKeyInterrupt+2),CX
|
|
MOV CX,OFFSET KeyboardInterrupt
|
|
XCHG AX,CX
|
|
STOSW
|
|
XCHG AX,CX
|
|
STOSW ; Set new keyboard interrupt
|
|
|
|
mov di,16h*4 ; INT 16 - keyboard input
|
|
MOV CX,es:[DI] ; Save INT 16 addr to hook to
|
|
MOV WORD PTR OldKbdHandler,CX
|
|
MOV CX,es:2[DI]
|
|
MOV WORD PTR (OldKbdHandler+2),CX
|
|
MOV CX,OFFSET KeyboardHandler
|
|
XCHG AX,CX
|
|
STOSW
|
|
XCHG AX,CX ; Set new keyboard Handler
|
|
STOSW
|
|
jmp StatusComplete
|
|
|
|
|
|
IF INBIOS
|
|
Code ends
|
|
|
|
BiosInit segment para public 'CODE'
|
|
ENDIF
|
|
|
|
Intro db "--- Installing MTCON Device Driver V"
|
|
db CVERS+"0",".",CREV/10+"0"
|
|
db (CREV-CREV/10*10)+"0"," ---"
|
|
db 13,10,"$"
|
|
|
|
BiosInit ends
|
|
|
|
END
|