home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS - Coast to Coast
/
simteldosarchivecoasttocoast.iso
/
pcmag
/
vol11n15.zip
/
REDD.ASM
< prev
next >
Wrap
Assembly Source File
|
1992-05-26
|
35KB
|
1,296 lines
;====================================================================
; 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