home *** CD-ROM | disk | FTP | other *** search
- PAGE ,132 ; Corrected version, 9/2/87, DF
- TITLE PDTIMPRK -- Public domain software by Dick Flanagan
- ;----------------------------------------------------------------------------+
- ; |
- ; Placed in the PUBLIC DOMAIN without warranty, guarantee, or |
- ; assumption of liability. All rights under copyright law are |
- ; unconditionally waived by the author. |
- ; |
- ; Written by Dick Flanagan, Ben Lomond, California, August 1987. |
- ; |
- ;----------------------------------------------------------------------------+
-
- comment *
-
- PPPPPP DDDDDD TTTTTTT III M M PPPPPP RRRRRR K K
- P P D D T I MM MM P P R R K K
- P P D D T I M M M M P P R R K K
- PPPPPP D D T I M M M M PPPPPP RRRRRR KK
- P D D T I M M M P R R K K
- P D D T I M M P R R K K
- P DDDDDD T III M M P R R K K
-
- *
-
- ;----------------------------------------------------------------------------
- ;
- ; The purpose of this program is to automatically park fixed disk
- ; drive heads after a predetermined period of inactivity has passed.
- ;
- ; While there are several other programs available to accomplish
- ; this task, almost all are either copyrighted or have evolved from
- ; copyrighted material. Some of these programs are in the ignorent
- ; position of ostensibly being both copyrighted and in the public
- ; domain, or with restrictions on their "public domainness." Until
- ; their authors realize they can't have it both ways, these programs
- ; are assumed to be copyrighted.
- ;
- ; Program Syntax: PDTIMPRK <minutes>
- ;
- ; The <minutes> parameter is a single digit in the range of 1 to 9.
- ; It represents the number of minutes of inactivity that are to be
- ; allowed before the heads are to be automatically parked. Some
- ; people might like a slightly lower floor on this value, but
- ; (and since I can't imagine anyone realistically wanting a higher
- ; ceiling) I have retained this convention which is common in
- ; other programs.
- ;
- ; Only BIOS I/O functions are used, so the program should be
- ; usable across a broad spectrum of IBM-compatible computers.
- ;
- ; Theory of Operation:
- ;
- ; Every time a software interrupt 13 is issued it is inter-
- ; cepted by this program which checks if the request is for
- ; a fixed or floppy disk. If it is for a fixed disk, a
- ; count-down timer is reset and a flag is cleared to indicate
- ; that the disk heads are probably no longer parked.
- ;
- ; Every time a hardware timer interrupt 8 is detected it is
- ; also intercepted and, if the disks are not already parked
- ; and we are not in the process of parking them, the timer is
- ; decremented and checked to see if the interval has expired.
- ; If it has, a flag is set indicating that parking is in pro-
- ; gress, the disks are "seeked" to their innermost cylinder,
- ; the parking-in-progress flag is cleared, the heads-are-parked
- ; flag is set, and our task is done until the next interrupt
- ; 13 for one of the fixed disks sets our timer running again.
- ;
- ; The hardware timer interrupt 8 is used instead of the more
- ; conservative approach of using the bios-generated software
- ; interrupt 1C. The length of time required to park the disk
- ; heads requires that at least the timer interrupts be enabled
- ; during the parking, and the parking operation itself requires
- ; that disk interrupts be enabled. These effectivly dictate
- ; that we operate with all interrupts enabled.
- ;
- ; To enable interrupts from within the interrupt 1C logic would
- ; require that an EOI (End-Of-Interrupt) code be sent to the
- ; 8259A PIC (Programmable Interrupt Controller). The problem
- ; with this is that the Time Of Day interrupt handler that issued
- ; the interrupt 1C in the first place will issue another EOI to
- ; the 8259A as soon as we return. This second EOI can wreak
- ; havok with lower level interrupt handlers that may have been
- ; interrupted by the original timer interrupt.
- ;
- ; Instead, we intercept timer interrupt 8 and immediately pass
- ; it off to the bios Time Of Day routine. When we get control
- ; back, the EOI will already have been issued and we can proceed
- ; with a clear conscience.
- ;
- ; Author's Notes:
- ;
- ; Because I hate TSR's, I try to make them as small as possible.
- ; This one is about as small as I've seen with equivalent
- ; functionality.
- ;
- ; I have attempted to comment the code in such a way that its
- ; operation should be clearly evident and modifications or
- ; (horrors!) bug fixes should be easily implemented. I also
- ; hope the comments will help remove some of the mystery that
- ; surrounds assembly language in general and interrupt handlers
- ; in particular for many people.
- ;
- ; Because this program was a quick weekend project, its level of
- ; parameter checking and error recovery is minimal, but I feel it
- ; to be adequate for the task at hand. For example:
- ;
- ; Limitations:
- ;
- ; o Only the first non-blank, non-zero character on the command
- ; line is examined. If 20 is entered, the 2 will be accepted
- ; and the 0 will be ignored.
- ;
- ; o If one drive in a two-drive system is kept busy frequently
- ; enough so as not to be parked, the other drive, regardless
- ; of how idle it might be, will not be parked until the other
- ; one finally is (the old two-drive-one-timer problem).
- ;
- ; o No attempt is made to determine if the program has already
- ; been installed. Simple tests are easily confused and complex
- ; ones aren't worth the trouble for a program as small and
- ; benign as this.
- ;
- ; o No error recovery is attempted.
- ;
- ;----------------------------------------------------------------------------
-
- CODE SEGMENT PARA
- ASSUME CS:CODE, DS:NOTHING, ES:NOTHING, SS:NOTHING
-
- ORG 0100H ; reserve space for psp
- START: JMP INIT ; jump to initialization code
-
- INT08VECT LABEL DWORD ; pre-existing interrupt 08 vector
- INT08OFF DW 0 ;
- INT08SEG DW 0 ;
-
- INT13VECT LABEL DWORD ; pre-existing interrupt 13 vector
- INT13OFF DW 0 ;
- INT13SEG DW 0 ;
-
- DRV0CYL DW 0 ; cylinder to park drive 0
- DRV1CYL DW 0 ; cylinder to park drive 1
-
- PARKED DB 0 ; non-zero = drives are parked
- BUSY DB 0 ; non-zero = parking in progress
-
- TIMER DW 0 ; decremented-to-zero timer counter
- TICKS DW 0 ; timer reset value
-
- ;----------------------------------------------------------------------------
- ;
- ; all disk i/o via interrupt 13 is intercepted here. while all
- ; int 13 activity does not necessarily result in the disk drives
- ; becoming 'unparked,' the penalty in so assuming is reasonably
- ; small.
- ;
- ;----------------------------------------------------------------------------
-
- INT13 PROC
-
- ;
- ; the less time spent with interrupts disabled the better, so
- ; reenable them right away
- ;
- STI ; enable interrupts
-
- ;
- ; check if this request is for a diskette drive instead of for
- ; a hard disk. if it is, we aren't interested in it.
- ;
- TEST DL,080H ; check if this is for hard disk
- JZ INT13EXIT ; exit if not
-
- ;
- ; if we are in the process of parking the drives, don't bother
- ; resetting anything
- ;
- CMP CS:BUSY,1 ; if actively parking the drives,
- JE INT13EXIT ; don't reset anything.
-
- ;
- ; reset timer counter and flag the disks as not being parked
- ;
- PUSH CS:TICKS ; this is for hard disk, so reset
- POP CS:TIMER ; time counter and indicate that
- MOV CS:PARKED,0 ; disks are no longer parked
-
- ;
- ; jump to normal int 13 bios routine to process the interrupt
- ;
- INT13EXIT:
- JMP CS:[INT13VECT] ; jump to original vector
-
- INT13 ENDP
-
- ;----------------------------------------------------------------------------
- ;
- ; this routine is entered approximately 18.2 times per second on
- ; the heals of a hardware timer interrupt. the purpose of this
- ; routine is to determine if the drives need to be parked. if so,
- ; the parking is done before the routine returns.
- ;
- ;----------------------------------------------------------------------------
-
- INT08 PROC
-
- ;
- ; the hardware interrupt that got us here disabled interrupts.
- ; since we aren't doing anything critical, we'll reenable them
- ; first thing and then go take care of the time-of-day processing.
- ;
- STI ; enable interrupts
- PUSHF ; simulate int by pushing flags
- CALL CS:[INT08VECT] ; and then calling tod routine
-
- ;
- ; if the drives are already parked, we needn't look any farther
- ;
- CMP CS:PARKED,1 ; check if drives already parked
- JE INT08EXIT ; exit if so
-
- ;
- ; if this interrupt caught us in the process of parking the drives,
- ; exit so we don't totally confuse the issue
- ;
- CMP CS:BUSY,1 ; are we the task being interupted?
- JE INT08EXIT ; exit if so
-
- ;
- ; decrement the parking timer and check if it is time to park
- ; the drives
- ;
- DEC CS:TIMER ; reduce time-to-go-until-park
- JG INT08EXIT ; exit if not yet time to park 'em
-
- ;
- ; set busy flag so we don't subsequently re-enter ourself when
- ; the next timer interrupt comes by (we'll probably be here
- ; through several of them), and also so we can detect when int13
- ; activity is coming from us and not from some application task.
- ;
- MOV CS:BUSY,1 ; set flag to indicate we are active
-
- ;
- ; save all of the registers we are going to use
- ;
- PUSH AX ; push registers on the stack
- PUSH CX ;
- PUSH DX ;
-
- ;
- ; park drive 0 by seeking to the last cylinder on that drive
- ;
- ; (full-platter head movement can take a long, long time. this
- ; operation can take anywhere from a few to hundreds of milli-
- ; seconds to accomplish.)
- ;
- MOV AX,0C01H ; seek op code, dummy sector count
- MOV CX,CS:DRV0CYL ; parking cylinder number
- MOV DX,0080H ; set head to 0, drive to 0
- INT 013H ; seek to highest cylinder
- ; (ignore errors)
- ;
- ; park drive 1 by seeking to the last cylinder on that drive
- ;
- ; (if drive 1 doesn't exist, this will simply return an error
- ; which we ignore anyway. if this causes problems with some
- ; bios's, the contents of DRV1CYL could be checked first--a
- ; zero value means the drive was not detected during our
- ; initialization)
- ;
- MOV AX,0C01H ; seek op code, dummy sector count
- MOV CX,CS:DRV1CYL ; parking cylinder number
- MOV DX,0081H ; set head to 0, drive to 1
- INT 013H ; seek to highest cylinder
- ; (ignore errors)
- ;
- ; restore the registers we used
- ;
- POP DX ; restore registers from the stack
- POP CX ;
- POP AX ;
-
- ;
- ; flag that the drives are now parked and we are now longer
- ; busy doing it
- ;
- MOV CS:PARKED,1 ; flag that drives are parked
- MOV CS:BUSY,0 ; clear the we-are-active flag
-
- ;
- ; return to the routine that was originally interrupted by the
- ; hardware timer going off
- ;
- INT08EXIT:
- IRET ; return to interrupted routine
-
- INT08 ENDP
-
- END_RESIDENT LABEL BYTE ; end of resident code
-
- ;----------------------------------------------------------------------------
- ;
- ; display initialization error messages and exit
- ;
- ; these message routines are placed in this rather asthetically
- ; displeasing location because the references to these routines
- ; that follow can access them here via relative jumps. at the
- ; end of the initialization code, where I originally placed these
- ; routines, non-relative jumps were required which were even more
- ; offensive.
- ;
- ;----------------------------------------------------------------------------
-
- ;
- ; no hard disks were detected
- ;
- INI_DRIVE:
- MOV DX,OFFSET NODRIVE ; advise there are no hard disks
- JMP SHORT INI_ERROR ; jump to display message and exit
-
- ;
- ; no or invalid parameter was found
- ;
- INI_USAGE:
- MOV DX,OFFSET USAGE ; advise what our usage is
-
- ;
- ; display the error message and terminate without doing anything
- ; further
- ;
- INI_ERROR:
- MOV AH,9 ; send message to standard output
- INT 021H ;
-
- MOV AX,04C01H ; terminate and return error
- INT 021H ; indication
-
- ;----------------------------------------------------------------------------
- ;
- ; initialization consists of three basic steps:
- ;
- ; o process user-provided parameter to determine delay interval
- ;
- ; o ascertain the cylinder that is to be used to park each drive
- ;
- ; o change interrupt vectors to insert us into the interrupt 13
- ; and interrupt 08 processing flow
- ;
- ;----------------------------------------------------------------------------
-
- ASSUME CS:CODE, DS:CODE, ES:CODE, SS:CODE
-
- INIT PROC
-
- ;
- ; check if a parameter was passed on the command line
- ;
- MOV BX,080H ; set (bx) to psp parameter area
- MOV AL,[BX] ; parameter length to (al)
- CMP AL,0 ; check if no parameter
- JE INI_USAGE ; take error exit if so
-
- ;
- ; ignore any leading blanks or zeros before the parameter
- ;
- INI_LOOP:
- INC BX ; increment index and get
- MOV AL,[BX] ; next character
- CMP AL,' ' ; check if blank
- JE INI_LOOP ; loop back if so
-
- CMP AL,'0' ; check if zero
- JE INI_LOOP ; loop back if so
-
- ;
- ; we found a non-blank, non-zero character, make sure it is not
- ; just the terminating carriage return
- ;
- CMP AL,0DH ; check for <cr>
- JE INI_USAGE ; exit if so
-
- ;
- ; we found a parameter, so check if it is a digit between 1 and 9
- ;
- CMP AL,'1' ; check if less than ascii 1
- JB INI_USAGE ; exit if so
-
- CMP AL,'9' ; check if greater than ascii 9
- JA INI_USAGE ; exit if so
-
- ;
- ; we found an acceptable parameter, so multiply it by the number
- ; of timer ticks in a minute and use it as our timer value (at
- ; 18.2 ticks per second, there are 1092 of them per minute)
- ;
- MOV TIMSG,AL ; save number in install message
- XOR AH,AH ; clear (ah)
- SUB AL,'0' ; extract binary number of minutes
- MOV DX,1092 ; number of ticks per minute
- MUL DX ; compute tick-count for wait loop
- MOV TICKS,AX ; save the value and then use it
- MOV TIMER,AX ; to initialize the timer
-
- ;
- ; determine if we have any hard disks installed
- ;
- MOV AH,8 ; get disktable parameters
- MOV DL,080H ; for drive 0
- INT 013H ;
-
- CMP DL,0 ; check number of hard disks
- JE INI_DRIVE ; jump if none installed
-
- ;
- ; the disktable parameters contain the maximum 'seekable'
- ; cylinder number in (ch), with the high-order two bits of
- ; the cylinder number found in the high two bits of (cl). we
- ; want to increase this cylinder number by one and use that
- ; next/last cylinder as our parking spot.
- ;
- INC CH ; increment max cylinder number
- JNC INI_0NC ; jump if no carry into high 2 bits
-
- ADD CL,040H ; incr high two bits of cylinder
-
- INI_0NC:
- MOV DRV0CYL,CX ; save drive 0 parking cylinder
-
- ;
- ; check if we have a second hard disk
- ;
- CMP DL,1 ; check only one hard disk
- JE INI_VECT ; jump if only one
-
- ;
- ; we need to extract the maximum cylinder number for the second
- ; hard disk in the same way we just did for drive 0
- ;
- MOV AH,8 ; get disktable parameters
- MOV DL,081H ; for drive 1
- INT 013H ;
-
- INC CH ; increment max cylinder number
- JNC INI_1NC ; jump if no carry into high 2 bits
-
- ADD CL,040H ; incr high two bits of cylinder
-
- INI_1NC:
- MOV DRV1CYL,CX ; save drive 1 parking cylinder
-
- ;
- ; save current int 13 vector
- ;
- INI_VECT:
- MOV AX,03513H ; request int 13 vector
- INT 021H ;
- MOV INT13SEG,ES ; save it for later use
- MOV INT13OFF,BX ;
-
- ;
- ; replace vector with a pointer to our own int 13 routine
- ;
- MOV AX,02513H ; set new int 13 vector
- MOV DX,OFFSET INT13 ;
- INT 021H ;
-
- ;
- ; save current int 08 vector
- ;
- MOV AX,03508H ; request int 08 vector
- INT 021H ;
- MOV INT08SEG,ES ; save it for later use
- MOV INT08OFF,BX ;
-
- ;
- ; replace vector with a pointer to our own int 08 routine
- ;
- MOV AX,02508H ; set new int 08 vector
- MOV DX,OFFSET INT08 ;
- INT 021H ;
-
- ;
- ; output message stating we are installed
- ;
- MOV DX,OFFSET INSTALL ; installation message
- MOV AH,9 ; send it to standard output
- INT 021H ;
-
- ;
- ; release memory allocated to our environment segment
- ;
- MOV ES,CS:[2CH] ; environment memory segment
- MOV AH,049H ; give it back to system
- INT 021H ;
-
- ;
- ; calculate our resident size rounded-up to the next paragraph
- ;
- MOV DX,OFFSET END_RESIDENT + 15 ; length of resident code
- MOV CL,4 ; set (cl) to divide by
- SHR DX,CL ; 16 to get para count
-
- ;
- ; terminate and leave our resident routines in place
- ;
- MOV AX,03100H ; tsr op and return code
- INT 021H ; terminate
-
- INIT ENDP
-
- INSTALL DB 0DH, 0AH
- DB 'Automatic Disk Parking Utility Installed'
- DB 0DH, 0AH
- DB 'Disk drive head(s) will automatically park after '
- TIMSG DB 'x'
- DB ' minute(s) of inactivity'
- DB 0DH, 0AH, '$'
-
- USAGE DB 'Usage: PDTIMPRK <minutes> (minutes = 1-9)'
- DB 7, 0DH, 0AH, '$'
-
- NODRIVE DB 'No hard drives detected'
- DB 7, 0DH, 0AH, '$'
-
- AUTHOR DB 'Placed in the public domain by Dick Flanagan, August 1987'
-
- CODE ENDS
- END START
-
-