home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Sound Sensations!
/
sound_sensations.iso
/
cmf
/
drivers
/
driver.asm
next >
Wrap
Assembly Source File
|
1985-03-15
|
10KB
|
294 lines
;--------------------------------------------------------------------
; DRIVER.SYS (a character device driver)
; Copyright (c) 1985 by Dan Rollins
;
; Simple device driver illustrates the fundamental structures and
; actions of a DOS 2.0 installable device driver.
;
; Creates TESTDEV, an input and output character device (pseudo-device).
;
; To install: Assemble, link, then process with:
; exe2bin driver driver.sys
; Then add this line to your CONFIG.SYS file:
; device=driver.sys
; Then reboot DOS and copy a file to TESTDEV
;=======================================================================
;---- equates for character device drivers ----
;=======================================================================
;-- equates for the data structures used by this driver
;-- offsets from the start of the Request Header
RH_LEN equ 0 ;byte
RH_UNIT_CODE equ 1 ;byte
RH_CMD_CODE equ 2 ;byte
RH_STATUS equ 3 ;word
;--- Request Header offsets for fields when the INIT function is executed
IN_UNIT_COUNT equ 13 ;byte
IN_END_ADDR equ 14 ;dword
IN_BPB_PTR equ 18 ;dword
;--- Request Header offsets for fields for INPUT or OUTPUT functions
IO_MEDIA_DESC equ 13 ;byte
IO_TRANS_ADDR equ 14 ;dword
IO_DATA_COUNT equ 18 ;word
IO_START_SECTOR equ 20 ;word
;--- equates for the bit-flags used in the attribute field of the device header
CHAR_DEVICE equ 8000h ;bit 15: 1 for character device, 0 block device
IOCTL equ 4000h ;bit 14: 1 if IOCTL system calls are supported
NON_IBM_FORMAT equ 2000h ;bit 13: 1 if block device is non-IBM format
;bits 12 to 4 are reserved
CLOCK equ 8 ;bit 3: 1 if this is the CLOCK$ device
NUL equ 4 ;bit 2: 1 if this is the NUL device
STO equ 2 ;bit 1: 1 if this is the Standard Output device
STI equ 1 ;bit 0: 1 if this is the Standard Input device
;--- equates for the bit-flags used in the status record for each command
ERR_FLAG equ 8000h ;bit 15: 1 if error occurred (see below)
;bits 14 to 10 reserved
BUSY equ 0200h ;bit 9: 1 if device is busy
DONE equ 0100h ;bit 8: set to 1 before exiting to caller
;--- the following values occupy bits 7 thru 0 when an error occurs --
WRITE_PROTECT equ 0
UNKNOWN_UNIT equ 1
DEV_NOT_READY equ 2
UNKNOWN_CMD equ 3 ;<-- this is the only error used by this device ---
CRC_ERROR equ 4
BAD_LEN equ 5
SEEK_ERROR equ 6
UNKNOWN_MEDIA equ 7
SECTOR_NOT_FND equ 8
OUT_OF_PAPER equ 9
WRITE_FAULT equ 0ah
READ_FAULT equ 0bh
GENERAL_FAILURE equ 0ch
;===============================================================
;----------- data and code of the file begins here -------------
;===============================================================
dev_seg segment
test_dev proc far
assume cs:dev_seg, ds:dev_seg, es:dev_seg
;------------------------------
; The following lines are the device header that must exist for
; every device. This file has only one device, and it works with
; character I/O.
header: ;label for the start of this device driver
next_dev_ptr dd -1 ;this is the last (only) device defined
dev_attribute dw CHAR_DEVICE
strategy_ptr dw strategy ;the proc that sets up for the functions
interrupt_ptr dw interrupt ;the proc that handles function calls
device_name db 'TESTDEV ' ;8-byte string of device name
request_ptr dd ? ;STRATEGY stores ES:BX request header pointer here
;INTERRUPT retrieves it
; this table is used to jump to the procedure that is indicated
; by DOS in the command code (third byte of the request header)
fn_table dw init_fn ; 0: initialization procedure
dw media_check_fn ; 1: media check procedure
dw build_bpb_fn ; 2: build Bios Parameter Block
dw ioctl_in_fn ; 3: IOCTL Input
dw input_fn ; 4: read from device
dw nd_input_fn ; 5: Non-Destructive, no-wait read
dw input_status_fn ; 6: return status of input device
dw input_flush_fn ; 7: flush (clear) the input buffer
dw output_fn ; 8: write to device
dw output_verify_fn ; 9: write and verify
dw output_status_fn ; 10: return status of output device
dw output_flush_fn ; 11: flush (clear) the output buffer
dw ioctl_out_fn ; 12: IOCTL Output
;The following messages are displayed by TESTDEV when DOS
;makes a request.
CR equ 0dh
LF equ 0ah
fn0_msg db 'Initializing TESTDEV Driver ',CR,LF,'$'
fn4_msg db 'Input request : $'
fn8_msg db 'Output request : $'
crlf db CR,LF,'$'
;=============================================================
; STRATEGY procedure
; Just saves the request header pointer for the INTERRUPT procedure
strategy proc far
assume cs:dev_seg
mov cs:word ptr request_ptr,bx
mov cs:word ptr request_ptr+2,es
ret ;FAR return to DOS
strategy endp
;=============================================================
; INTERRUPT procedure
; Processes the command indicated in the request header.
interrupt proc far
assume cs:dev_seg, ds:nothing, es:nothing
push ds ;preserve all registers
push es
push ax
push bx
push cx
push dx
push di
push si
push cs
pop ds ;DS addresses the program data area
les bx,request_ptr ;get the pointer saved by STRATEGY
mov ah,0
mov al,es:[bx+RH_CMD_CODE] ;fetch the command
mov di,ax
shl di,1 ; * 2 to point to jump vector
jmp fn_table[di] ;invoke that function procedure
;--- all command jumps except INIT, INPUT, and OUTPUT will end up here ----
nd_input_fn: ;requests for any of these commands
media_check_fn: ; will result in an error message
build_bpb_fn:
ioctl_in_fn:
input_status_fn:
input_flush_fn:
output_verify_fn:
output_status_fn:
output_flush_fn:
ioctl_out_fn:
error_exit:
or word ptr es:[bx+RH_STATUS],ERR_FLAG ;set the ERROR_FLAG
or word ptr es:[bx+RH_STATUS],UNKNOWN_CMD ;identify the error
;--- service request has been handled.
;--- Set the "done flag" and return to DOS.
common_exit:
or word ptr es:[bx+RH_STATUS],DONE ;always indicate completion
pop si ; by setting the DONE bit
pop di
pop dx
pop cx
pop bx
pop ax
pop es
pop ds
ret ;FAR return
;--------------------------
; INTERRUPT procedure function calls
; Only three types of requests are handled by TESTDEV. All other
; requests are routed through the ERROR_EXIT.
;-------------------------------------------------------------------------
; INPUT_FN
; Reads (waits for) 1 character from the keyboard, and displays it,
; then returns it (within the I/O structure) to DOS.
input_fn proc near
mov ch,0
mov cl,es:[bx+IO_DATA_COUNT] ;get number of bytes
jcxz if_exit ;if no bytes, just exit
if_10:
mov dx,offset fn4_msg ;"Input request: "
mov ah,9 ;DOS print string service
int 21H
mov ah,0 ;ROM-BIOS AWAIT_KEY function
int 16H ;get AL = ASCII character, AH = scan code
mov word ptr es:[bx+IO_DATA_COUNT],1 ;store the character count
push ds
lds di,es:[bx+IO_TRANS_ADDR] ;get SEG:OFF of destination
mov [di],al ;store byte in destination
pop ds
mov dl,al
mov ah,2 ;display the character
int 21H
mov dx,offset crlf ;start a new line
mov ah,9 ;invoke DOS print string service
int 21h
loop if_10 ;do again, for multi-byte requests
if_exit:
jmp common_exit
input_fn endp
;--------------------------------------------------------------------
; OUTPUT_FN sends the character passed to it from DOS out to the
; standard output device.
output_fn proc near
mov ch,0
mov cl,es:[bx+IO_DATA_COUNT] ;get number of bytes
jcxz of_exit ;if no bytes, just exit
of_10:
mov dx,offset fn8_msg ;"Output request :"
mov ah,9 ;DOS print string service
int 21H
push ds
lds si,es:[bx+IO_TRANS_ADDR] ;get SEG:OFF of data
mov dl,[si] ;retrieve the character
pop ds ;unstack or die
mov ah,2 ;display the character
int 21H
mov dx,offset crlf ;print new line characters
mov ah,9 ;DOS print string service
int 21H
loop of_10 ;get next (if multi-byte request)
of_exit:
jmp common_exit
output_fn endp
;-------------------------,
; INIT_FN procedure
; Passes the end-of-driver address back to DOS.
; Note that the address of this procedure is passed back to DOS as the
; address of the end of the driver. After one invocation, INIT_FN
; is never called again; thus, it doesn't need to be saved with the
; rest of the function procedures.
init_fn proc near
mov dx,offset fn0_msg ;"Initializing TESTDEV"
mov ah,9 ;DOS print string service
int 21H
;-- debugging tool:
;-- store the address so the code can be examined with DEBUG ---
push ds
mov ax,0
mov ds,ax
mov word ptr ds:[04f0h],offset interrupt
mov word ptr ds:[04f2h],cs
pop ds
;-- header address (offset,segment) is stored at address 0000:04F0
;-- which is known as the "intra-application communication area"
;-- specify the end of this driver and exit to DOS -------
mov word ptr es:[bx+IN_END_ADDR],offset init_fn
mov word ptr es:[bx+IN_END_ADDR+2],cs
jmp common_exit
init_fn endp
interrupt endp
test_dev endp
dev_seg ends
end header ;must specify for EXE2BIN