home *** CD-ROM | disk | FTP | other *** search
-
- ;--------------------------------------------------------------------
- ; 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