Mail Archives: opendos/1997/04/08/17:07:10
The ancient PC Magazine freeware device
driver REDD.SYS fails under OD. Instead
of stuffing the keyboard buffer with a
command for execution by the shell (I
use 4DOS), it stuffs the command
followed by a long string of space (20h)
characters until the speaker beeps like
mad with the overflow. Any assembler
jocks interested in looking into this
and either patching the driver or
reporting an OD bug?
_______________________________________________________________________
;====================================================================
; REDD - Remote Exec Device Driver
;
; Copyright (c) 1992 Douglas Boling
;====================================================================
page 66,132
;--------------------------------------------------------------------
; BIOS Data segment
;--------------------------------------------------------------------
bios_data segment at 40h
org 17h
shift_state db ? ;State of shift keys
org 1Ah
keybuff_head dw ? ;Start ptr for key
buff
keybuff_tail dw ? ;End ptr for key
buff
org 4Eh
video_buffoff dw ? ;Offset of video buffer
org 63h
video_ioregs dw ? ;I/O addr of video ctlr
org 80h
keybuff_start dw ? ;Start ptr for
keybuff
keybuff_end dw ? ;End ptr for
keybuff
video_rows db ? ;Screen rows
bios_data ends
;--------------------------------------------------------------------
; CODE segment
;--------------------------------------------------------------------
code segment
assume cs:code
generic_req struc
Len db ? ;Size of structure
Unit db ?
Function db ? ;Requested function
Status dw ? ;Returned status
Reserved db 8 dup (?)
generic_req ends
init_req struc
irLen db ? ;Size of
structure
irUnit db ?
irFunction db ? ;Requested function
irStatus dw ? ;Returned status
irReserved db 8 dup (?)
irUnits db ? ;Number of
block drives
irEndAddress dd ? ;End addr of
driver
irParmAddress dd ? ;Ptr to cmd line
parms
irDriveNumber db ? ;1st drive number
irMessageflag dw ? ;Error word
init_req ends
media_req struc
mrLen db ? ;Size of
structure
mrUnit db ?
mrFunction db ? ;Requested function
mrStatus dw ? ;Returned status
mrReserved db 8 dup (?)
mrMediaID db ? ;Media descripter
mrReturn db ? ;return value
mrVolumeID dd ? ;Ptr to volumne ID
string
media_req ends
buildbpb_req struc
bbrLen db ? ;Size of
structure
bbrUnit db ?
bbrFunction db ? ;Requested function
bbrStatus dw ? ;Returned status
bbrReserved db 8 dup (?)
bbrMediaID db ? ;Media descripter
bbrFATSector dd ? ;Ptr to 1st FAT
sector
bbrBPBAddress dd ? ;Ptr to BPB block
buildbpb_req ends
read_req struc
rrLen db ? ;Size of
structure
rrUnit db ?
rrFunction db ? ;Requested function
rrStatus dw ? ;Returned status
rrReserved db 8 dup (?)
rrMediaID db ? ;Media descripter
rrBuffer dd ? ;Ptr to data buffer
rrBytesSec dw ? ;Number of sectors
to read
rrStartSec dw ? ;Starting sector
number
rrVolumeID dd ? ;Ptr to volume ID
string
rrHugeStartSec dd ? ;Start sec for
>32 Meg drive
read_req ends
;====================================================================
;Device driver header
;====================================================================
org 0 ;Offset 0 for DD
header dd -1 ;Ptr to next
driver
dw 0800h ;Attribute word
bits
;15 Character device
;14 IOCTL read/write
support
;13 (Char) Output till
busy
; (Blk) Needs FAT for
BPB
;11 Open/Close dev
supported
; 7 IOCTL querys
supported
; 6 Log drive mapping
support
; 4 Fast char input
support
; 3 Device is clock
device
; 2 Device is NULL device
; 1 (Char) Std out device
; (Blk) 32 bit sector
nums
; 0 Device is Std Input
dev
dw offset strategy ;Ptr to strategy
routine
dw offset interrupt ;Ptr to interrupt
routine
db 1,0,0,0,0,0,0,0 ;Num of block
devices
program db 10,13,"REDD",10,13
db "Copyright (c) 1992 Douglas Boling",13,10
db "First published in PC Magazine, September 15,
1992"
db 13,10,"$",1Ah
;--------------------------------------------------------------------
;Boot Sector data for our imaginary drive
;--------------------------------------------------------------------
boot_sector = $
jmp short boot_sector_end ;obligitory jmp
instruction
nop
db "IBM x.x " ;Stupid IBM tag for
DOS 4
BPB_start = $
BytesPerSec dw 200h ;512 bytes per
sector
SecPerCluster db 1 ;One sec per
cluster
ResSectors dw 1 ;Reserved sectors
NumFATs db 1 ;Number of File
Alloc tables
RootDirEntries dw 8 ;Num of entries
in root dir
Sectors dw 8 ;Total number
of sectors
Media db 0F0h ;Media
descriptor byte
FATSectors dw 1 ;Number of sectors
per FAT
SecPerTrack dw 8 ;Num sectors per
track
Heads dw 1 ;Num of heads
HiddenSectors dd 0 ;Num hidden
sectors
HugeSectors dd 0 ;Num of sec if > 32
Meg
DriveNumber db 0 ;Used by DOS
Reserved1 db 0 ;Used by DOS
BootSignature db 29h ;IDs boot
sector format
VolumeID dd 12345678h ;Volume ID number
VolumeLabel db "REDD " ;ASCII volume
label
FileSysType db "FAT12 " ;FAT system used
boot_sector_end = $
;
;Data needed for the driver
;
req_header_ptr dd 0 ;Ptr to request
header
bpb_array dw offset BPB_start ;Array of BPB pointers
keyname db "KEYBOARDIN " ;Name of
keyboard file
volume_name db "REDD ",0 ;ASCIIZ
string of vol name
cr_flag db 1 ;Append CR to
video LFs
even
sys_year db 0 ;Time needed to set
sys_month db 0 ; the time and date
for
sys_day db 0 ; screen file.
sys_hours db 0
sys_minutes db 0
sys_seconds db 0
timer_low dw 0 ;Timer ticks since
last
timer_high dw 0 ; GetSysTime call.
scrtick_low dw 0 ;Tick count at last
screen
scrtick_high dw 0 ; write.
int08_active dw -1 ;Interrupt 8
active flag
int08h dd -1 ;Old Timer
Interrupt
int10h dd -1 ;Old Video
Interrupt
ScreenHead dd -1 ;Head of screen
buffer queue
ScreenTop dw -1 ;Top of screen
buffer
ScreenBot dw -1 ;End of screen
buffer
ScreenTxtSec dw 2 ;Screen file num
of sectors
fileopen_count dw 0 ;Number of
opened files
root_update db 0 ;Indicates change
in Root dir
paste_flag db 0
pastedata_ptr dw 0
pastedata_end dw 0
fpclust_size dw 0
pastecluster dw 0
pastedirent_ptr dw 0
FATPtr dw 0 ;Ptr to FAT
table
FATSize dw 0 ;Sectors * 1.5
RootSize dw 0 ;Root entries * 32
DataPtr dw ? ;Ptr to data
sector start
jmptable dw offset init ;0 Initialize
driver
dw offset media_check ;1 Block device
media check
dw offset build_bpb ;2 Build BIOS
parameter blk
dw offset not_implimented ;3 I/O control
read
dw offset read ;4 Read
dw offset not_implimented ;5
Non-destructive read
dw offset not_implimented ;6 Get input
status
dw offset not_implimented ;7 Flush input
dw offset write ;8 Write
dw offset write ;9 Write with
verify
dw offset not_implimented ;A Get output
status
dw offset not_implimented ;B Output flush
dw offset not_implimented ;C I/O control
write
dw offset open_device ;D Open device
dw offset close_device ;E Close device
dw offset removable_media ;F Removable
media check
dw offset not_implimented ;10 Output until
busy
dw offset not_implimented ;11 Reserved
dw offset not_implimented ;12 Reserved
dw offset not_implimented ;13 Generic I/O
control
dw offset not_implimented ;14 Reserved
dw offset not_implimented ;15 Reserved
dw offset not_implimented ;16 Reserved
dw offset not_implimented ;17 Get logic
drive mapping
dw offset not_implimented ;18 Set logic
drive mapping
dw offset not_implimented ;19 I/O control
query
jmptable_end = $
max_cmd equ (offset jmptable_end - offset jmptable)
shr 1
;====================================================================
;STRATEGY - Handles strategy calls from DOS by copying the request
; header pointer into an internal buffer.
;====================================================================
strategy proc far
assume cs:code,ds:nothing,es:nothing
mov word ptr cs:[req_header_ptr],bx
mov word ptr cs:[req_header_ptr+2],es
ret
strategy endp
;====================================================================
;INTERRUPT - Handles interrupt calls from DOS by implimenting the
; device driver functions
;====================================================================
interrupt proc far
assume cs:code,ds:nothing,es:nothing
push ax
push bx
push cx
push dx
push di
push si
push bp
push ds
push es
pushf
cld ;All string operations
UP
mov di,cs
mov ds,di
assume ds:code
les di,req_header_ptr ;Get ptr to request
header
xor bx,bx
mov bl,es:[di.Function] ;Get requested
function
cmp bl,max_cmd
mov ax,8003h ;Load error status
ja interrupt_exit
nop
shl bx,1
call [bx+jmptable] ;Call proper
routine
push ax
cmp cs:root_update,0
je interrupt_1
call check_root
interrupt_1:
pop ax
les di,req_header_ptr ;Get ptr to request
header
or ax,0100h ;Set done bit
interrupt_exit:
mov es:[di.Status],ax ;Save status in drvr
header
popf
pop es
pop ds
pop bp
pop si
pop di
pop dx
pop cx
pop bx
pop ax
ret
interrupt endp
;--------------------------------------------------------------------
;MEDIA CHECK - Media check function allows DOS to determine if the
; disk type in the drive has changed.
;Entry: ES:DI - Point to request header structure
;--------------------------------------------------------------------
media_check proc near
assume cs:code,ds:code,es:nothing
mov es:[di.mrReturn],0 ;Media may have been
changed
mov word ptr es:[di.rrVolumeID],offset volume_name
mov word ptr es:[di.rrVolumeID+2],cs
not_implimented:
xor ax,ax ;Clear return
code
ret
media_check endp
;--------------------------------------------------------------------
;BUILD BPB - Build BIOS Parameter Block.
;Entry: ES:DI - Point to request header structure
;--------------------------------------------------------------------
build_bpb proc near
assume cs:code,ds:code,es:nothing
mov word ptr es:[di.bbrBPBAddress],offset
BPB_start
mov word ptr es:[di.bbrBPBAddress+2],cs
xor ax,ax
ret
build_bpb endp
;--------------------------------------------------------------------
;READ - Reads sectors from the block device
;Entry: ES:DI - Point to request header structure
;--------------------------------------------------------------------
read proc near
assume cs:code,ds:code,es:nothing
mov bx,es:[di.rrStartSec]
mov cx,es:[di.rrBytesSec]
push cx
push di
push es
les di,es:[di.rrBuffer]
nop
read_1:
call read_sector ;'Read' a sector
inc bx ;Inc starting sector
loop read_1 ;Read again if
not done
pop es ;Set output fields
and term
pop di
pop cx
mov es:[di.rrBytesSec],cx
mov word ptr es:[di.rrVolumeID],offset volume_name
mov word ptr es:[di.rrVolumeID+2],cs
xor ax,ax
ret
read endp
;--------------------------------------------------------------------
;WRITE - Writes sectors from the block device
;Entry: ES:DI - Point to request header structure
;--------------------------------------------------------------------
write proc near
assume cs:code,ds:code,es:nothing
mov bx,es:[di.rrStartSec]
mov cx,es:[di.rrBytesSec]
push cx
push si
push ds
lds si,es:[di.rrBuffer]
nop
write_1:
call write_sector ;'Write' a sector
inc bx ;Inc starting sector
loop write_1 ;Read again if
not done
pop ds
pop si
pop cx
mov es:[di.rrBytesSec],cx
mov word ptr es:[di.rrVolumeID],offset volume_name
mov word ptr es:[di.rrVolumeID+2],cs
xor ax,ax
ret
write endp
;--------------------------------------------------------------------
;OPEN DEVICE - Indicates that a file has been opened on the drive
;Entry: ES:DI - Point to request header structure
;--------------------------------------------------------------------
open_device proc near
assume cs:code,ds:code,es:nothing
inc cs:fileopen_count
xor ax,ax
ret
open_device endp
;--------------------------------------------------------------------
;CLOSE DEVICE - Indicates that a file has been closed on the drive
;Entry: ES:DI - Point to request header structure
;--------------------------------------------------------------------
close_device proc near
assume cs:code,ds:code,es:nothing
dec cs:fileopen_count
xor ax,ax
ret
close_device endp
;--------------------------------------------------------------------
;REMOVABLE MEDIA - Informs DOS whether the drive is removable
;Entry: ES:DI - Point to request header structure
;--------------------------------------------------------------------
removable_media proc near
assume cs:code,ds:code,es:nothing
xor ax,ax ;Bit 9 = 0 -
drive removable
ret
removable_media endp
;--------------------------------------------------------------------
;READ SECTOR - Simulates a read of a mythical disk sector
;Entry: BX - Starting sector
; ES:DI - Ptr to data buffer to read data
;Exit: ES:DI - Points to byte beyond last data read out to DOS
;--------------------------------------------------------------------
read_sector proc near
assume cs:code,ds:code,es:nothing
push bx
push cx
cmp bx,1 ;Check what sector
to read
jb read_boot
je read_FAT
sub bx,3
jb read_root
cmp bx,ScreenTxtSec ;See if reading
SCREEN.TXT
jb read_screen
call getdata_ptr ;Compute buff for
sector
mov si,bx
mov cx,BytesPerSec
jmp short read_sector_1
read_screen:
mov dx,BytesPerSec
xchg bx,dx
mov si,word ptr ScreenHead ;Read this
sector as a
mov ax,bx ; rotating
buffer. The
mul dx ; ScreenHead ptr
points
add si,ax ; to the start
of the
mov cx,ScreenBot ;See if starting
past end
cmp si,cx ; of buffer.
jb read_screen_0
sub si,cx ;Yes, wrap ptr to
buff start
add si,ScreenTop
read_screen_0:
sub cx,si ;Compute len till
end of buff
sub bx,cx ;Sub read len
from total
jae read_screen_1 ;If read len more
than total,
mov cx,BytesPerSec ; change read
len to total
xor bx,bx ;Clear total.
read_screen_1:
rep movsb
mov si,ScreenTop
mov cx,bx
jcxz read_sector_exit
rep movsb
jmp short read_sector_exit
read_boot:
mov si,offset boot_sector
mov cx,offset boot_sector_end - offset boot_sector
jmp short read_sector_1
read_FAT:
mov si,FATPtr
mov cx,FATSize
jmp short read_sector_1
read_root:
mov si,offset root_dir
call set_time ;Set time for screen
file
mov cx,RootSize
read_sector_1:
mov dx,BytesPerSec ;Copy data
sub dx,cx ;See how much is
left for
rep movsb ; a complete
sector
xor al,al
mov cx,dx ;Fill in
remainder of
jcxz read_sector_exit ; sector with zeros.
rep stosb
read_sector_exit:
pop cx
pop bx
ret
read_sector endp
;--------------------------------------------------------------------
;WRITE SECTOR - Simulates a write of a mythical disk sector
;Entry: BX - Starting sector
; DS:SI - Ptr to data buffer
;Exit: DS:SI - Points to byte beyond last data read into drive
;--------------------------------------------------------------------
write_sector proc near
assume cs:code,ds:nothing,es:nothing
push bx
push cx
push di
push es
mov ax,cs
mov es,ax
assume es:code
cmp bx,1 ;Check what sector
to write
jb write_boot
je write_FAT
sub bx,3
jb write_root
call getdata_ptr ;Compute buff for
sector
mov di,bx
mov cx,BytesPerSec
jmp short write_sector_1
write_boot:
mov di,offset boot_sector
mov cx,offset boot_sector_end - offset boot_sector
jmp short write_sector_1
write_FAT:
mov di,cs:FATPtr
mov cx,cs:FATSize
jmp short write_sector_1
write_root:
mov di,offset root_dir
mov cx,cs:RootSize
inc cs:root_update
write_sector_1:
rep movsb
write_sector_exit:
pop es
pop di
pop cx
pop bx
ret
write_sector endp
;--------------------------------------------------------------------
;GETDATA PTR - Returns the offet in RAM for a given data sector
;Entry: BX - Cluster - 2
;Exit: BX - Ptr to data
;--------------------------------------------------------------------
getdata_ptr proc near
assume cs:code,ds:nothing,es:nothing
push ax
push dx
mov ax,bx ;Copy starting
data sec
mul cs:BytesPerSec ;Mul by size of
data sec
mov bx,ax ;Add starting
offset of
add bx,cs:DataPtr ; data buffer.
pop dx
pop ax
ret
getdata_ptr endp
;--------------------------------------------------------------------
;CHECK ROOT - Checks changes in the root directory
;--------------------------------------------------------------------
check_root proc near
assume cs:code,ds:nothing,es:nothing
push ds
push es
mov ax,cs
mov ds,ax
mov es,ax
assume cs:code,ds:code,es:code
mov root_update,0 ;Clear flag
cmp paste_flag,0 ;Don't bother if
we are
jne check_root_exit ; already
pasting.
mov si,offset root_dir
mov cx,RootDirEntries
mov di,offset keyname
check_root_1:
push cx ;Scan through root
looking
push si ; for the name of
the
push di ; keyboard file.
mov cx,11
repe cmpsb
pop di
pop si
pop cx
je check_root_2
add si,32
loop check_root_1
jmp short check_root_exit
check_root_2:
xor bx,bx
or bx,[si+1ah] ;See if starting
cluster set
je check_root_exit
mov cx,word ptr [si+1ch] ;Get file size
or cx,cx
je check_root_exit ;If 0, exit
mov ax,cx
xor dx,dx
div BytesPerSec ;Compute number of
sectors
mov fpclust_size,dx ; and size of
last sector.
mov pastedirent_ptr,si
mov pastecluster,bx
call next_pasteclust ;Compute
pointers to sector
mov paste_flag,1 ;Allow paste
check_root_exit:
pop es
pop ds
ret
check_root endp
;-------------------------------------------------------------------------
;DELETE FILE - Deletes a file from the driver disk
;Entry: SI - Pointer to directory entry for file
;-------------------------------------------------------------------------
delete_file proc near
assume cs:code,ds:code,es:nothing
push cx
xor ax,ax
mov bx,[si+1ah] ;Get starting
cluster
delete_file_1:
mov cx,bx
call get_fat_entry
xchg bx,cx
call set_fat_entry ;Zero entry
mov bx,cx
cmp bx,0fffh ;See if last entry
jne delete_file_1
mov byte ptr [si],0e5h ;Clear name
pop cx
ret
delete_file endp
;-------------------------------------------------------------------------
; GET FAT ENTRY - Returns the contents of a 12 bit FAT entry
; Entry: BX - Entry into FAT table
; Exit: BX - Next entry
;-------------------------------------------------------------------------
get_fat_entry proc near
assume cs:code,ds:code,es:nothing
push ax
push di
mov di,FATPtr
add di,bx
shr bx,1 ;12 bit FAT
mov ax,ds:[bx+di]
jnc get_fat_entry_2
shr ax,1
shr ax,1
shr ax,1
shr ax,1
get_fat_entry_2:
and ah,0fh ;Clear top nibble
get_fat_entry_3:
mov bx,ax ;Copy entry data
pop di
pop ax
ret
get_fat_entry endp
;-------------------------------------------------------------------------
; SET FAT ENTRY - Writes a 12 bit FAT table entry
; Entry: BX - Pointer to fat table entry
; AX - Data to write to FAT table
;-------------------------------------------------------------------------
set_fat_entry proc near
assume cs:code,ds:code,es:nothing
push ax
push bx
push di
mov di,FATPtr
add di,bx
shr bx,1 ;12 bit FAT
pushf
add di,bx
popf
mov bx,ds:[di] ;Get data
jc set_fat_1 ;Jump if odd
and bx,0f000h ;Remove old data
jmp short set_fat_2
set_fat_1:
and bx,000fh ;Remove old data
shl ax,1
shl ax,1
shl ax,1
shl ax,1
set_fat_2:
or ax,bx
mov ds:[di],ax ;Write data
pop di
pop bx
pop ax
ret
set_fat_entry endp
;====================================================================
;TIMER INT - Interrupt 8h timer hook. This routine keeps the time
; and, when necessary, pastes data into the keyboard buff
;====================================================================
timerint proc far
assume cs:code,ds:nothing,es:nothing
pushf
add word ptr cs:timer_low,1
adc word ptr cs:timer_high,0
cmp cs:paste_flag,0
jne timerint_1
timerint_exit:
popf
jmp cs:[int08h] ;Jmp to old
interrupt
timerint_1:
inc cs:int08_active
jne timerint_exit2
push ax
push ds
mov ax,cs
mov ds,ax
assume ds:code
timerint_2:
call push_key
jc timerint_exit1
cmp paste_flag,0
jne timerint_2
timerint_exit1:
pop ds
pop ax
timerint_exit2:
dec cs:int08_active
jmp short timerint_exit
timerint endp
;-----------------------------------------------------------------------------
; PUSH KEY Fills the keyboard buffer with data
; Exit: CF - Set if keyboard buffer full
; AX - modified
;-----------------------------------------------------------------------------
push_key proc near
assume ds:nothing,es:nothing
push bx
push di
push si
push es
cld ;String moves UP
mov ax,bios_data
mov es,ax
assume es:bios_data
cli ;No interrupts
mov di,es:[keybuff_tail]
push di
call inckeyptr
cmp di,es:[keybuff_head] ;See if buffer
full
pop di
stc
je push_key_exit
mov si,pastedata_ptr
lodsb ;Get character to
paste
cmp si,pastedata_end
jb push_key_3
push ax
mov bx,pastecluster ;See if cluster
is the last
call get_fat_entry
cmp bx,0fffh
je push_key_1
mov pastecluster,bx
call next_pasteclust ;Compute ptrs
for next sector
jmp short push_key_2
push_key_1:
mov paste_flag,0 ;Disable paste
mov si,pastedirent_ptr ;Delete paste file
call delete_file
push_key_2:
pop ax
push_key_3:
mov pastedata_ptr,si
or al,al ;Don't stuff null
char
je push_key_5
jns push_key_31
and ax,007fh ;Remove sign bit,
clear AH
xchg ah,al ;Place char in
scan code
jmp short push_key_4
push_key_31:
cmp al,0ah ;Don't stuff
line feeds
je push_key_5
cmp al,1ah ;Don't stuff End
Of File char
je push_key_5
xor ah,ah ;Clear scan
code
cmp al,0dh ;If CR
character, add proper
jne push_key_4 ; scan code for
Word Perfect
mov ah,1ch
push_key_4:
mov es:[di],ax ;Don't use STOSW,
ptr must
call inckeyptr ; be updated by
inckeyptr
mov es:[keybuff_tail],di ;Save keybuff ptr
push_key_5:
clc
push_key_exit:
pop es
pop si
pop di
pop bx
ret
push_key endp
;--------------------------------------------------------------------
;NEXT PASTECLUST - Sets the paste variables for a sector
;Entry: BX - new sector
;--------------------------------------------------------------------
next_pasteclust proc near
push dx
push bx
call get_fat_entry
mov dx,BytesPerSec
cmp bx,0fffh
jne next_pc_1
mov dx,fpclust_size
next_pc_1:
pop bx
sub bx,2
call getdata_ptr
mov pastedata_ptr,bx
add bx,dx
mov pastedata_end,bx
pop dx
ret
next_pasteclust endp
;-----------------------------------------------------------------------------
; INCKEYPTR Incriments the keyboard buffer pointer
; Entry: DI - Current Keyboard tail pointer
;-----------------------------------------------------------------------------
inckeyptr proc near
assume es:bios_data
inc di ;Make room in buffer
inc di
cmp di,es:[keybuff_end] ;Get ptr to end of
buffer
jne inckeyptr_1
mov di,es:[keybuff_start] ;Get ptr to
buffer offset
inckeyptr_1:
ret
inckeyptr endp
;====================================================================
;VID INT - Interrupt 10h video hook. This routine monitors and
; records any BIOS writes to the screen into the 'file'
; SCREEN.TXT.
;====================================================================
vidint proc far
assume cs:code,ds:nothing,es:nothing
cmp ah,9
jae vidint_1
vidint_exit:
jmp cs:[int10h] ;Jmp to old
interrupt
vidint_1:
push cx
push di
push es
cmp ah,09h
je vidint_wrtchr1
cmp ah,0ah
je vidint_wrtchr1
cmp ah,0eh
je vidint_wrtchr
cmp ah,13h
jne vidint_exit1
push ax
push si
push ds
mov si,es
mov ds,si
mov si,bp ;Copy ptr to
string
les di,cs:ScreenHead ;Get ptr to buffer
mov ah,al
vidint_2:
jcxz vidint_4
lodsb ;Read character
call save_char ;Store character
cmp ah,2
jb vidint_3
inc si ;Skip past attribute
vidint_3:
loop vidint_2
vidint_4:
pop ds
pop si
pop ax
jmp short vidint_5
vidint_wrtchr:
mov cx,1
vidint_wrtchr1:
les di,cs:ScreenHead ;Get ptr to buffer
jcxz vidint_5
call save_char ;Save character
loop vidint_wrtchr1
vidint_5:
mov word ptr cs:ScreenHead,di
pushf
cli
mov di,cs:timer_low ;Mark last time
screen
mov cx,cs:timer_high ; updated.
mov cs:scrtick_low,di
mov cs:scrtick_high,cx
popf
vidint_exit1:
pop es
pop di
pop cx
jmp vidint_exit
vidint endp
;--------------------------------------------------------------------
;SAVE CHAR - Saves a character into the SCREEN.TXT file
;--------------------------------------------------------------------
save_char proc near
assume cs:code,ds:nothing,es:code
cmp al,13 ;See if CR
je save_char_2
cmp al,10
je save_char_3
save_char_0:
stosb
save_char_01:
cmp di,cs:ScreenBot
jae save_char_1
ret
save_char_1:
mov di,cs:ScreenTop
ret
save_char_2:
mov cs:cr_flag,0
jmp short save_char_0
save_char_3:
cmp cs:cr_flag,0
je save_char_0
stosb
mov al,13
stosb
mov al,10
jmp short save_char_01
ret
save_char endp
;--------------------------------------------------------------------
;INIT TIMER - Calls the BIOS to retrieve the system time
;--------------------------------------------------------------------
init_timer proc near
assume cs:code,ds:code,es:nothing
push bx
mov ah,2 ;Get system time
int 1ah
mov al,ch
call un_bcd
mov sys_hours,al
mov al,cl
call un_bcd
mov sys_minutes,al
mov al,dh
call un_bcd
mov sys_seconds,al
mov ah,4 ;Get system time
int 1ah
mov al,cl
call un_bcd
xor ah,ah
cmp ch,19 ;See if next
century
je init_timer_1
add ax,100
init_timer_1:
sub ax,80 ;Convert to
relative date
mov sys_year,al
mov al,dh
call un_bcd
mov sys_month,al
mov al,dl
call un_bcd
mov sys_day,al
pushf
cli
mov timer_low,0
mov timer_high,0
popf
pop bx
ret
init_timer endp
;--------------------------------------------------------------------
;SET TIME - Sets the time of file in the directory
;Entry: SI - Pointer to the directory entry
;--------------------------------------------------------------------
set_time proc near
assume cs:code,ds:code,es:nothing
mov ax,scrtick_low
mov dx,scrtick_high
call compute_elapsed
add al,sys_seconds
cmp al,60
jb set_time_1
inc cl
sub al,60
set_time_1:
add cl,sys_minutes
cmp cl,60
jb set_time_2
inc ch
sub cl,60
set_time_2:
add ch,sys_hours
cmp ch,24
jb set_time_3
inc dh
sub ch,24
set_time_3:
shr al,1 ;Divide seconds by
2
and ax,1fh
mov bh,cl ;Get minutes
and bx,3f00h
shr bx,1
shr bx,1
shr bx,1
or ax,bx
mov bh,ch ;Get hours
shl bx,1
shl bx,1
shl bx,1
and bx,0f800h
or ax,bx
mov [si+16h],ax ;Save time in dir
entry
mov al,sys_day
mov cl,sys_month
mov ch,sys_year
or dh,dh
je set_time_4
call inc_date ;Inc to next day
set_time_4:
and ax,3fh
shl cl,1
shl cl,1
shl cl,1
shl cl,1
shl cx,1
or ax,cx
mov [si+18h],ax ;Save date in dir
entry
ret
set_time endp
;--------------------------------------------------------------------
;COMPUTE ELAPSED - Computes the elapsed time from a 32 bit timer tick
; count.
;Entry: AX,DX - Timer tick count
;Exit: DH - Days
; CH - Hours
; CL - Minutes
; DL - Seconds
;--------------------------------------------------------------------
compute_elapsed proc near
assume cs:code,ds:code,es:nothing
push bx
push di
xor bx,bx
mov ch,dl ;Save hours
cmp dl,24 ;If longer than
24 hours,
jb compute_1 ; compute days.
push ax
xor ax,ax
xchg ax,dx
mov di,24
div di
mov bl,al ;Save days
mov dx,ax
mul di
mov ch,al
pop ax
compute_1:
xor dx,dx
mov di,1092 ;Ticks per
minute
div di
mov cl,al ;Save minutes
xor ax,ax
xchg ax,dx
mov di,10
mul di
mov di,182
div di
mov dl,al
mov di,ax
mov dh,bl
pop di
pop bx
ret
compute_elapsed endp
;--------------------------------------------------------------------
;INC DATE - Propigates a incrimented date though the month and year.
;Entry: AL - Day
; CL - Month
; CH - Years since 1980
;--------------------------------------------------------------------
inc_date proc near
inc al ;Incriment date
push bx
mov bx,1f1eh ;bh=31,bl=30
cmp cl,7 ;Up till Aug. odd
numbered
jbe inc_date_1 ; months have 31
days.
xchg bl,bh ; After, even
months have 31
inc_date_1:
test cl,1 ;See if odd month
je inc_date_2 ;No, branch
xchg bl,bh
inc_date_2:
cmp cl,2 ;See if Feb
jne inc_date_3
mov bl,28
test ch,3 ;Leap year if 4
year multiple
jne inc_date_3 ; of 1980. Fails at
2100
mov bl,29 ; since 2100 not
a leap year
inc_date_3:
cmp al,bl
jbe inc_date_exit
mov al,1 ;Set to 1st day of
the month
inc cl ;Inc month
cmp cl,13 ;See if end of
year
jne inc_date_exit
mov cl,1 ;Set to Jan.
inc ch ;Inc year
inc_date_exit:
pop bx
ret
inc_date endp
;--------------------------------------------------------------------
;UN BCD - Returns a binary number for one coded in BCD
;Entry: AL - BCD number
;Exit: AL - Binary number
;--------------------------------------------------------------------
un_bcd proc near
assume cs:code,ds:nothing,es:nothing
push bx
mov bl,al
shr al,1
shr al,1
shr al,1
shr al,1
mov ah,10
mul ah
and bl,0fh
add al,bl
pop bx
ret
un_bcd endp
;--------------------------------------------------------------------
;FINAL INSTALL - Initializes the data structures needed for the drive
;Entry: ES:DI - Point to request header structure
; DX - Size of data sectors
;--------------------------------------------------------------------
final_install proc near
assume cs:code,ds:code,es:nothing
mov di,cs
mov es,di
assume es:code
mov di,offset root_dir + 64
mov cx,RootSize
sub cx,64
xor ax,ax
rep stosb
mov di,FATPtr
mov al,Media ;Initialize FAT
stosb ;First FAT bytes
contain
mov ax,-1 ; media
descriptor byte
stosw ; followed by FF
FF.
mov cx,ScreenTxtSec
mov bx,screen_start
final_install_0:
dec cx
jcxz final_install_01
mov ax,bx
inc ax
call set_fat_entry
mov bx,ax
jmp short final_install_0
final_install_01:
mov ax,-1
call set_fat_entry
final_install_02:
inc bx
cmp bx,Sectors
ja final_install_3
xor ax,ax
call set_fat_entry
jmp short final_install_02
final_install_3:
mov di,DataPtr
mov cx,dx ;Fill 1st data
sector for
mov al,' ' ; SCREEN.TXT
file. Might
rep stosb ; as well init
the rest.
mov ax,3510h ;Get video interrupt
vector
int 21h
mov word ptr [int10h],bx
mov word ptr [int10h+2],es
mov ax,2510h ;Set to our handler
mov dx,offset vidint
int 21h
mov ax,3508h ;Get timer interrupt
vector
int 21h
mov word ptr [int08h],bx
mov word ptr [int08h+2],es
mov ax,2508h ;Set to our handler
mov dx,offset timerint
int 21h
xor ax,ax ;Clear return
code
ret
final_install endp
even ;Keep things on even
addrs
;
;Start root directory with entry for screen.txt
;
root_dir db "SCREEN OUT" ;Name
db 1 ;Attribute (Read only)
db 10 dup (0) ;Reserved
screen_time dw 0 ;Time of file
screen_date dw 0 ;Date of file
screen_start dw 2 ;Starting cluster
screen_size dd 0 ;Size of file
volumne_entry db "REDD " ;Name
db 8 ;Attribute (Volume)
db 10 dup (0) ;Reserved
dw 0 ;Time of file
dw 0 ;Date of file
dw 0 ;Starting cluster
dd 0 ;Size of file
end_of_resident = $
;--------------------------------------------------------------------
;Non-resident data
;--------------------------------------------------------------------
initmsg db 13,10,"REDD installed as drive "
initdrv db " :",13,10,10,'$'
;--------------------------------------------------------------------
;INIT - Initializes the device driver
;Entry: ES:DI - Point to request header structure
;--------------------------------------------------------------------
init proc near
assume cs:code,ds:code,es:nothing
mov ah,9 ;Print copyright
mov dx,offset program
int 21h
call init_timer ;Init driver clock
mov bx,offset root_dir
mov ax,32 ;Compute size of
root dir
mov dx,RootDirEntries
mul dx
mov RootSize,ax
add bx,ax
mov FATPtr,bx
mov ax,Sectors
mov dx,ax ;Mul sectors by
1.5
shr ax,1
adc ax,dx
mov FATSize,ax
add bx,ax
mov DataPtr,bx
mov word ptr ScreenHead,bx ;Init screen
buffer ptrs to
mov word ptr ScreenHead+2,cs ; 1st data sector.
mov ScreenTop,bx
mov ax,ScreenTxtSec
mul BytesPerSec
mov word ptr screen_size,ax
add ax,bx
mov ScreenBot,ax
mov ax,Sectors ;Compute size of
data
mul BytesPerSec ; sectors.
mov dx,ax ;Save data sector
size
add ax,bx
les di,req_header_ptr ;Get ptr to request
header
mov cl,es:[di.irDriveNumber] ; the drive number
being
add cl,'A' ; used.
mov initdrv,cl
mov word ptr es:[di.irEndAddress],ax ;Set
memory
mov word ptr es:[di.irEndAddress+2],cs ;
size
mov word ptr es:[di.irParmAddress],offset
BPB_array
mov word ptr es:[di.irParmAddress+2],cs
mov word ptr es:[di.irUnits],1
push dx
mov ah,9 ;Print message
indicating
mov dx,offset initmsg ; disk letter.
int 21h
pop dx
jmp final_install
init endp
code ends
end
- Raw text -