delorie.com/archives/browse.cgi   search  
Mail Archives: opendos/1997/04/08/17:07:10

To: opendos AT delorie DOT com
Subject: This device driver fails under OD
Message-ID: <19970408.163726.6391.0.editor@juno.com>
From: editor AT juno DOT com (Bruce Morgen)
Date: Tue, 08 Apr 1997 16:39:14 EDT

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 -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019