home *** CD-ROM | disk | FTP | other *** search
/ Power Programming / powerprogramming1994.iso / progtool / dskutl / pdtimprk.arc / PDTIMPRK.ASM next >
Assembly Source File  |  1987-09-02  |  22KB  |  532 lines

  1.         PAGE    ,132    ;  Corrected version, 9/2/87, DF
  2.         TITLE   PDTIMPRK -- Public domain software by Dick Flanagan
  3. ;----------------------------------------------------------------------------+
  4. ;                                                                            |
  5. ;       Placed in the PUBLIC DOMAIN without warranty, guarantee, or          |
  6. ;       assumption of liability.  All rights under copyright law are         |
  7. ;       unconditionally waived by the author.                                |
  8. ;                                                                            |
  9. ;       Written by Dick Flanagan, Ben Lomond, California, August 1987.       |
  10. ;                                                                            |
  11. ;----------------------------------------------------------------------------+
  12.  
  13. comment *
  14.  
  15. PPPPPP   DDDDDD   TTTTTTT  III  M       M  PPPPPP   RRRRRR   K   K
  16. P     P  D     D     T      I   MM     MM  P     P  R     R  K  K
  17. P     P  D     D     T      I   M M   M M  P     P  R     R  K K
  18. PPPPPP   D     D     T      I   M  M M  M  PPPPPP   RRRRRR   KK
  19. P        D     D     T      I   M   M   M  P        R   R    K K
  20. P        D     D     T      I   M       M  P        R    R   K  K
  21. P        DDDDDD      T     III  M       M  P        R     R  K   K
  22.  
  23. *
  24.  
  25. ;----------------------------------------------------------------------------
  26. ;
  27. ;       The purpose of this program is to automatically park fixed disk
  28. ;       drive heads after a predetermined period of inactivity has passed.
  29. ;       
  30. ;       While there are several other programs available to accomplish
  31. ;       this task, almost all are either copyrighted or have evolved from
  32. ;       copyrighted material.  Some of these programs are in the ignorent
  33. ;       position of ostensibly being both copyrighted and in the public
  34. ;       domain, or with restrictions on their "public domainness."  Until
  35. ;       their authors realize they can't have it both ways, these programs
  36. ;       are assumed to be copyrighted.
  37. ;
  38. ;       Program Syntax:  PDTIMPRK <minutes>
  39. ;
  40. ;       The <minutes> parameter is a single digit in the range of 1 to 9.
  41. ;       It represents the number of minutes of inactivity that are to be
  42. ;       allowed before the heads are to be automatically parked.  Some
  43. ;       people might like a slightly lower floor on this value, but
  44. ;       (and since I can't imagine anyone realistically wanting a higher
  45. ;       ceiling) I have retained this convention which is common in
  46. ;       other programs.
  47. ;
  48. ;       Only BIOS I/O functions are used, so the program should be
  49. ;       usable across a broad spectrum of IBM-compatible computers.
  50. ;
  51. ;       Theory of Operation:
  52. ;
  53. ;       Every time a software interrupt 13 is issued it is inter-
  54. ;       cepted by this program which checks if the request is for
  55. ;       a fixed or floppy disk.  If it is for a fixed disk, a
  56. ;       count-down timer is reset and a flag is cleared to indicate
  57. ;       that the disk heads are probably no longer parked.
  58. ;
  59. ;       Every time a hardware timer interrupt 8 is detected it is
  60. ;       also intercepted and, if the disks are not already parked
  61. ;       and we are not in the process of parking them, the timer is
  62. ;       decremented and checked to see if the interval has expired.
  63. ;       If it has, a flag is set indicating that parking is in pro-
  64. ;       gress, the disks are "seeked" to their innermost cylinder,
  65. ;       the parking-in-progress flag is cleared, the heads-are-parked
  66. ;       flag is set, and our task is done until the next interrupt
  67. ;       13 for one of the fixed disks sets our timer running again.
  68. ;
  69. ;       The hardware timer interrupt 8 is used instead of the more
  70. ;       conservative approach of using the bios-generated software
  71. ;       interrupt 1C.  The length of time required to park the disk
  72. ;       heads requires that at least the timer interrupts be enabled
  73. ;       during the parking, and the parking operation itself requires
  74. ;       that disk interrupts be enabled.  These effectivly dictate
  75. ;       that we operate with all interrupts enabled.
  76. ;
  77. ;       To enable interrupts from within the interrupt 1C logic would
  78. ;       require that an EOI (End-Of-Interrupt) code be sent to the
  79. ;       8259A PIC (Programmable Interrupt Controller).  The problem
  80. ;       with this is that the Time Of Day interrupt handler that issued
  81. ;       the interrupt 1C in the first place will issue another EOI to
  82. ;       the 8259A as soon as we return.  This second EOI can wreak
  83. ;       havok with lower level interrupt handlers that may have been
  84. ;       interrupted by the original timer interrupt.
  85. ;
  86. ;       Instead, we intercept timer interrupt 8 and immediately pass
  87. ;       it off to the bios Time Of Day routine.  When we get control
  88. ;       back, the EOI will already have been issued and we can proceed
  89. ;       with a clear conscience.
  90. ;
  91. ;       Author's Notes:
  92. ;
  93. ;       Because I hate TSR's, I try to make them as small as possible.
  94. ;       This one is about as small as I've seen with equivalent
  95. ;       functionality.
  96. ;
  97. ;       I have attempted to comment the code in such a way that its
  98. ;       operation should be clearly evident and modifications or
  99. ;       (horrors!) bug fixes should be easily implemented.  I also
  100. ;       hope the comments will help remove some of the mystery that
  101. ;       surrounds assembly language in general and interrupt handlers
  102. ;       in particular for many people.
  103. ;
  104. ;       Because this program was a quick weekend project, its level of
  105. ;       parameter checking and error recovery is minimal, but I feel it
  106. ;       to be adequate for the task at hand.  For example:
  107. ;
  108. ;       Limitations:
  109. ;
  110. ;       o  Only the first non-blank, non-zero character on the command
  111. ;          line is examined.  If 20 is entered, the 2 will be accepted
  112. ;          and the 0 will be ignored.
  113. ;
  114. ;       o  If one drive in a two-drive system is kept busy frequently
  115. ;          enough so as not to be parked, the other drive, regardless
  116. ;          of how idle it might be, will not be parked until the other
  117. ;          one finally is (the old two-drive-one-timer problem).
  118. ;
  119. ;       o  No attempt is made to determine if the program has already
  120. ;          been installed.  Simple tests are easily confused and complex
  121. ;          ones aren't worth the trouble for a program as small and
  122. ;          benign as this.
  123. ;
  124. ;       o  No error recovery is attempted.
  125. ;
  126. ;----------------------------------------------------------------------------
  127.  
  128. CODE    SEGMENT PARA
  129.         ASSUME  CS:CODE, DS:NOTHING, ES:NOTHING, SS:NOTHING
  130.  
  131.         ORG     0100H                   ; reserve space for psp
  132. START:  JMP     INIT                    ; jump to initialization code
  133.  
  134. INT08VECT       LABEL   DWORD           ; pre-existing interrupt 08 vector
  135. INT08OFF        DW      0               ;
  136. INT08SEG        DW      0               ;
  137.  
  138. INT13VECT       LABEL   DWORD           ; pre-existing interrupt 13 vector
  139. INT13OFF        DW      0               ;
  140. INT13SEG        DW      0               ;
  141.  
  142. DRV0CYL         DW      0               ; cylinder to park drive 0
  143. DRV1CYL         DW      0               ; cylinder to park drive 1
  144.  
  145. PARKED          DB      0               ; non-zero = drives are parked
  146. BUSY            DB      0               ; non-zero = parking in progress
  147.  
  148. TIMER           DW      0               ; decremented-to-zero timer counter
  149. TICKS           DW      0               ; timer reset value
  150.  
  151. ;----------------------------------------------------------------------------
  152. ;
  153. ;       all disk i/o via interrupt 13 is intercepted here.  while all
  154. ;       int 13 activity does not necessarily result in the disk drives
  155. ;       becoming 'unparked,' the penalty in so assuming is reasonably
  156. ;       small.
  157. ;
  158. ;----------------------------------------------------------------------------
  159.  
  160. INT13   PROC
  161.  
  162. ;
  163. ;       the less time spent with interrupts disabled the better, so
  164. ;       reenable them right away
  165. ;
  166.         STI                             ; enable interrupts
  167.  
  168. ;
  169. ;       check if this request is for a diskette drive instead of for
  170. ;       a hard disk.  if it is, we aren't interested in it.
  171. ;
  172.         TEST    DL,080H                 ; check if this is for hard disk
  173.         JZ      INT13EXIT               ; exit if not
  174.  
  175. ;
  176. ;       if we are in the process of parking the drives, don't bother
  177. ;       resetting anything
  178. ;
  179.         CMP     CS:BUSY,1               ; if actively parking the drives,
  180.         JE      INT13EXIT               ;   don't reset anything.
  181.  
  182. ;
  183. ;       reset timer counter and flag the disks as not being parked
  184. ;
  185.         PUSH    CS:TICKS                ; this is for hard disk, so reset
  186.         POP     CS:TIMER                ;   time counter and indicate that
  187.         MOV     CS:PARKED,0             ;   disks are no longer parked
  188.  
  189. ;
  190. ;       jump to normal int 13 bios routine to process the interrupt
  191. ;
  192. INT13EXIT:
  193.         JMP     CS:[INT13VECT]          ; jump to original vector
  194.  
  195. INT13   ENDP
  196.  
  197. ;----------------------------------------------------------------------------
  198. ;
  199. ;       this routine is entered approximately 18.2 times per second on
  200. ;       the heals of a hardware timer interrupt.  the purpose of this
  201. ;       routine is to determine if the drives need to be parked.  if so,
  202. ;       the parking is done before the routine returns.
  203. ;
  204. ;----------------------------------------------------------------------------
  205.  
  206. INT08   PROC
  207.  
  208. ;
  209. ;       the hardware interrupt that got us here disabled interrupts.
  210. ;       since we aren't doing anything critical, we'll reenable them
  211. ;       first thing and then go take care of the time-of-day processing.
  212. ;
  213.         STI                             ; enable interrupts
  214.         PUSHF                           ; simulate int by pushing flags
  215.         CALL    CS:[INT08VECT]          ;   and then calling tod routine
  216.  
  217. ;
  218. ;       if the drives are already parked, we needn't look any farther
  219. ;
  220.         CMP     CS:PARKED,1             ; check if drives already parked
  221.         JE      INT08EXIT               ; exit if so
  222.  
  223. ;
  224. ;       if this interrupt caught us in the process of parking the drives,
  225. ;       exit so we don't totally confuse the issue
  226. ;
  227.         CMP     CS:BUSY,1               ; are we the task being interupted?
  228.         JE      INT08EXIT               ; exit if so
  229.  
  230. ;
  231. ;       decrement the parking timer and check if it is time to park
  232. ;       the drives
  233. ;
  234.         DEC     CS:TIMER                ; reduce time-to-go-until-park
  235.         JG      INT08EXIT               ; exit if not yet time to park 'em
  236.  
  237. ;
  238. ;       set busy flag so we don't subsequently re-enter ourself when
  239. ;       the next timer interrupt comes by (we'll probably be here
  240. ;       through several of them), and also so we can detect when int13
  241. ;       activity is coming from us and not from some application task.
  242. ;
  243.         MOV     CS:BUSY,1               ; set flag to indicate we are active
  244.  
  245. ;
  246. ;       save all of the registers we are going to use
  247. ;
  248.         PUSH    AX                      ; push registers on the stack
  249.         PUSH    CX                      ;
  250.         PUSH    DX                      ;
  251.         
  252. ;
  253. ;       park drive 0 by seeking to the last cylinder on that drive
  254. ;
  255. ;       (full-platter head movement can take a long, long time.  this
  256. ;       operation can take anywhere from a few to hundreds of milli-
  257. ;       seconds to accomplish.)
  258. ;
  259.         MOV     AX,0C01H                ; seek op code, dummy sector count
  260.         MOV     CX,CS:DRV0CYL           ; parking cylinder number
  261.         MOV     DX,0080H                ; set head to 0, drive to 0
  262.         INT     013H                    ; seek to highest cylinder
  263.                                         ; (ignore errors)
  264. ;
  265. ;       park drive 1 by seeking to the last cylinder on that drive
  266. ;
  267. ;       (if drive 1 doesn't exist, this will simply return an error
  268. ;       which we ignore anyway.  if this causes problems with some
  269. ;       bios's, the contents of DRV1CYL could be checked first--a
  270. ;       zero value means the drive was not detected during our 
  271. ;       initialization)
  272. ;
  273.         MOV     AX,0C01H                ; seek op code, dummy sector count
  274.         MOV     CX,CS:DRV1CYL           ; parking cylinder number
  275.         MOV     DX,0081H                ; set head to 0, drive to 1
  276.         INT     013H                    ; seek to highest cylinder
  277.                                         ; (ignore errors)
  278. ;
  279. ;       restore the registers we used
  280. ;
  281.         POP     DX                      ; restore registers from the stack
  282.         POP     CX                      ;
  283.         POP     AX                      ;
  284.  
  285. ;
  286. ;       flag that the drives are now parked and we are now longer
  287. ;       busy doing it
  288. ;
  289.         MOV     CS:PARKED,1             ; flag that drives are parked
  290.         MOV     CS:BUSY,0               ; clear the we-are-active flag 
  291.  
  292. ;
  293. ;       return to the routine that was originally interrupted by the
  294. ;       hardware timer going off
  295. ;
  296. INT08EXIT:
  297.         IRET                            ; return to interrupted routine
  298.  
  299. INT08   ENDP
  300.  
  301. END_RESIDENT    LABEL   BYTE            ; end of resident code
  302.  
  303. ;----------------------------------------------------------------------------
  304. ;
  305. ;       display initialization error messages and exit
  306. ;
  307. ;       these message routines are placed in this rather asthetically
  308. ;       displeasing location because the references to these routines
  309. ;       that follow can access them here via relative jumps.  at the
  310. ;       end of the initialization code, where I originally placed these
  311. ;       routines, non-relative jumps were required which were even more
  312. ;       offensive.
  313. ;
  314. ;----------------------------------------------------------------------------
  315.  
  316. ;
  317. ;       no hard disks were detected
  318. ;
  319. INI_DRIVE:
  320.         MOV     DX,OFFSET NODRIVE       ; advise there are no hard disks
  321.         JMP     SHORT INI_ERROR         ; jump to display message and exit
  322.  
  323. ;
  324. ;       no or invalid parameter was found
  325. ;
  326. INI_USAGE:
  327.         MOV     DX,OFFSET USAGE         ; advise what our usage is
  328.  
  329. ;
  330. ;       display the error message and terminate without doing anything
  331. ;       further
  332. ;
  333. INI_ERROR:
  334.         MOV     AH,9                    ; send message to standard output
  335.         INT     021H                    ;
  336.  
  337.         MOV     AX,04C01H               ; terminate and return error
  338.         INT     021H                    ;   indication
  339.  
  340. ;----------------------------------------------------------------------------
  341. ;
  342. ;       initialization consists of three basic steps:
  343. ;
  344. ;       o  process user-provided parameter to determine delay interval
  345. ;
  346. ;       o  ascertain the cylinder that is to be used to park each drive
  347. ;
  348. ;       o  change interrupt vectors to insert us into the interrupt 13
  349. ;          and interrupt 08 processing flow
  350. ;
  351. ;----------------------------------------------------------------------------
  352.  
  353.         ASSUME  CS:CODE, DS:CODE, ES:CODE, SS:CODE
  354.  
  355. INIT    PROC
  356.  
  357. ;
  358. ;       check if a parameter was passed on the command line
  359. ;
  360.         MOV     BX,080H                 ; set (bx) to psp parameter area
  361.         MOV     AL,[BX]                 ; parameter length to (al)
  362.         CMP     AL,0                    ; check if no parameter
  363.         JE      INI_USAGE               ; take error exit if so
  364.  
  365. ;
  366. ;       ignore any leading blanks or zeros before the parameter
  367. ;
  368. INI_LOOP:
  369.         INC     BX                      ; increment index and get
  370.         MOV     AL,[BX]                 ;   next character
  371.         CMP     AL,' '                  ; check if blank
  372.         JE      INI_LOOP                ; loop back if so
  373.  
  374.         CMP     AL,'0'                  ; check if zero
  375.         JE      INI_LOOP                ; loop back if so
  376.  
  377. ;
  378. ;       we found a non-blank, non-zero character, make sure it is not
  379. ;       just the terminating carriage return
  380. ;
  381.         CMP     AL,0DH                  ; check for <cr>
  382.         JE      INI_USAGE               ; exit if so
  383.  
  384. ;
  385. ;       we found a parameter, so check if it is a digit between 1 and 9
  386. ;
  387.         CMP     AL,'1'                  ; check if less than ascii 1
  388.         JB      INI_USAGE               ; exit if so
  389.  
  390.         CMP     AL,'9'                  ; check if greater than ascii 9
  391.         JA      INI_USAGE               ; exit if so
  392.  
  393. ;
  394. ;       we found an acceptable parameter, so multiply it by the number
  395. ;       of timer ticks in a minute and use it as our timer value (at
  396. ;       18.2 ticks per second, there are 1092 of them per minute)
  397. ;
  398.         MOV     TIMSG,AL                ; save number in install message
  399.         XOR     AH,AH                   ; clear (ah)
  400.         SUB     AL,'0'                  ; extract binary number of minutes
  401.         MOV     DX,1092                 ; number of ticks per minute
  402.         MUL     DX                      ; compute tick-count for wait loop
  403.         MOV     TICKS,AX                ; save the value and then use it
  404.         MOV     TIMER,AX                ;   to initialize the timer
  405.  
  406. ;
  407. ;       determine if we have any hard disks installed
  408. ;
  409.         MOV     AH,8                    ; get disktable parameters
  410.         MOV     DL,080H                 ;   for drive 0
  411.         INT     013H                    ;
  412.  
  413.         CMP     DL,0                    ; check number of hard disks
  414.         JE      INI_DRIVE               ; jump if none installed
  415.  
  416. ;
  417. ;       the disktable parameters contain the maximum 'seekable'
  418. ;       cylinder number in (ch), with the high-order two bits of
  419. ;       the cylinder number found in the high two bits of (cl).  we
  420. ;       want to increase this cylinder number by one and use that
  421. ;       next/last cylinder as our parking spot.
  422. ;
  423.         INC     CH                      ; increment max cylinder number
  424.         JNC     INI_0NC                 ; jump if no carry into high 2 bits
  425.  
  426.         ADD     CL,040H                 ; incr high two bits of cylinder
  427.  
  428. INI_0NC:
  429.         MOV     DRV0CYL,CX              ; save drive 0 parking cylinder
  430.  
  431. ;
  432. ;       check if we have a second hard disk
  433. ;
  434.         CMP     DL,1                    ; check only one hard disk
  435.         JE      INI_VECT                ; jump if only one
  436.  
  437. ;
  438. ;       we need to extract the maximum cylinder number for the second
  439. ;       hard disk in the same way we just did for drive 0
  440. ;
  441.         MOV     AH,8                    ; get disktable parameters
  442.         MOV     DL,081H                 ;   for drive 1
  443.         INT     013H                    ;
  444.  
  445.         INC     CH                      ; increment max cylinder number
  446.         JNC     INI_1NC                 ; jump if no carry into high 2 bits
  447.  
  448.         ADD     CL,040H                 ; incr high two bits of cylinder
  449.  
  450. INI_1NC:
  451.         MOV     DRV1CYL,CX              ; save drive 1 parking cylinder
  452.  
  453. ;
  454. ;       save current int 13 vector
  455. ;
  456. INI_VECT:
  457.         MOV     AX,03513H               ; request int 13 vector
  458.         INT     021H                    ;
  459.         MOV     INT13SEG,ES             ; save it for later use
  460.         MOV     INT13OFF,BX             ;
  461.  
  462. ;
  463. ;       replace vector with a pointer to our own int 13 routine
  464. ;
  465.         MOV     AX,02513H               ; set new int 13 vector
  466.         MOV     DX,OFFSET INT13         ;
  467.         INT     021H                    ;
  468.  
  469. ;
  470. ;       save current int 08 vector
  471. ;
  472.         MOV     AX,03508H               ; request int 08 vector
  473.         INT     021H                    ;
  474.         MOV     INT08SEG,ES             ; save it for later use
  475.         MOV     INT08OFF,BX             ;
  476.  
  477. ;
  478. ;       replace vector with a pointer to our own int 08 routine
  479. ;
  480.         MOV     AX,02508H               ; set new int 08 vector
  481.         MOV     DX,OFFSET INT08         ;
  482.         INT     021H                    ;
  483.  
  484. ;
  485. ;       output message stating we are installed
  486. ;
  487.         MOV     DX,OFFSET INSTALL       ; installation message
  488.         MOV     AH,9                    ; send it to standard output
  489.         INT     021H                    ;
  490.  
  491. ;
  492. ;       release memory allocated to our environment segment
  493. ;
  494.         MOV     ES,CS:[2CH]             ; environment memory segment
  495.         MOV     AH,049H                 ; give it back to system
  496.         INT     021H                    ;
  497.  
  498. ;
  499. ;       calculate our resident size rounded-up to the next paragraph
  500. ;
  501.         MOV     DX,OFFSET END_RESIDENT + 15     ; length of resident code
  502.         MOV     CL,4                            ; set (cl) to divide by 
  503.         SHR     DX,CL                           ;   16 to get para count
  504.  
  505. ;
  506. ;       terminate and leave our resident routines in place
  507. ;
  508.         MOV     AX,03100H               ; tsr op and return code
  509.         INT     021H                    ; terminate
  510.  
  511. INIT    ENDP
  512.  
  513. INSTALL DB      0DH, 0AH
  514.         DB      'Automatic Disk Parking Utility Installed'
  515.         DB      0DH, 0AH
  516.         DB      'Disk drive head(s) will automatically park after '
  517. TIMSG   DB      'x'
  518.         DB      ' minute(s) of inactivity'
  519.         DB      0DH, 0AH, '$'
  520.  
  521. USAGE   DB      'Usage: PDTIMPRK <minutes>  (minutes = 1-9)'
  522.         DB      7, 0DH, 0AH, '$'
  523.  
  524. NODRIVE DB      'No hard drives detected'
  525.         DB      7, 0DH, 0AH, '$'
  526.  
  527. AUTHOR  DB      'Placed in the public domain by Dick Flanagan, August 1987'
  528.  
  529. CODE    ENDS
  530.         END     START
  531.  
  532.