Metropoli BBS
VIEWER: tsrpark.asm MODE: TEXT (ASCII)
        PAGE 60,120
        TITLE TSRPARK.ASM -- TesSeRact Demo program to park disk drive heads
;----------------------------------------------------------------------------
SUBTTL  Originally TESSPARK.ASM : TesSeRact Revision Level 1
;-----------------------------------------------------------------------------
;   TesSeRact(tm) -- A Library of Routines for Creating Ram-Resident (TSR)
;                    programs for the IBM PC and compatible Personal
;                    Computers.
;
;The software, documentation and source code are:
;
;       Copyright (C) 1986, 1987, 1988 Tesseract Development Team
;       All Rights Reserved
;
;       c/o Chip Rabinowitz
;       Innovative Data Concepts
;       2084 Woodlawn Avenue
;       Glenside, PA 19038
;       1-215-884-3373
;
;-----------------------------------------------------------------------------
;   This product supports the TesSeRact Standard for Ram-Resident Program
;   Communication.  For information about TesSeRact, contact the TesSeRact
;   Development Team at:
;       Compuserve:    70731,20
;       MCIMAIL:       315-5415
;   This MCIMAIL Account has been provided to the TesSeRact Development
;   Team by Borland International, Inc.  The TesSeRact Development Team
;   is in no way associated with Borland International, Inc.
;-----------------------------------------------------------------------------
;
; BASED on code originally provided by Jim Mischel
;
; ORIGINAL COPYRIGHT NOTICE:
;
;;;; AUTOPARK.ASM - program to automatically park the disk drive heads
;;;; at specified time intervals.
;;;;
;;;; Copyright (c) 1988, Jim Mischel
;;;;
;;;; This program has been assembled using MASM 5.0.  Changes may be required
;;;; for use with earlier versions.
;;;;

;;;;;                 TSRPARK.ASM -  Rick Housh
;;;;;
;;;;; TSRPARK.ASM - Modifications to TESSPARK.ASM to allow variable timing
;;;;; intervals from 1 to 9 minutes for autopark with use of numerical
;;;;; parameter on command line, to support manual parking with use
;;;;; of hotkey, with popup when on DOS command line, detection of
;;;;; park failure on installation, and communication with the resident
;;;;; program to allow dynamically changing the elapsed time between
;;;;; automatic parks.  Assembled using MASM 5.1.
;;;;;
;;;;; Everything is self-explanatory, except perhaps how to reset the
;;;;; timer when resident.  Just enter ' TSRPARK # ', where # is any number
;;;;; of minutes between 1 and 9, and the new value will be inserted in the
;;;;; resident portion of the program.  A message will confirm the change
;;;;; and even the MAPMEM display of residents will show the new value.
;;;;; Entering ' TSRPARK ' with no parameter will yield a confirming message
;;;;; if TSRPARK is resident, and an instructional message if it has not
;;;;; yet been installed.  When the hotkey is pressed from the DOS prompt
;;;;; a message is displayed, in addition to the TESSBEEP sound.  Inside
;;;;; a program, the sound will occur, but there will be no message.
;;;;;
;;;;; I have changed the "mysterious" headparking code somewhat, and tried
;;;;; to expand the comments to show how it really works.  It's not that
;;;;; complicated, and does NOT care whether the computer is an AT or not,
;;;;; contrary to the comments in the original TESSPARK.  I have also found
;;;;; an undocumented and useful function.  Tch, tch.  TSRCHECKRESIDENT
;;;;; returns the segment of the resident program in the es register if
;;;;; it has found the program installed in memory.  The documentation
;;;;; only mentions a result returned in the ax register.  I found this
;;;;; very useful, and have implemented in TSRPARK.
;;;;;
;;;;; TSRPARK Modifications of TESSPARK, Rick Housh, CIS 72466,212 - 7/18/1988
;;;;;

;;;;;
;;;;; To assemble this TesSeRact version:
;;;;;
;;;;;       MASM TSRPARK;
;;;;;       LINK TESS_ASM + TESS_BP + TSRPARK + TESS_END,TSRPARK;
;;;;;       EXE2BIN TSRPARK.EXE TSRPARK.COM
;;;;;

.model small

.code

;
; Ticks2wait is # of timer ticks to wait between the last disk access
; and parking the disk.  There are approximately 18.2 ticks per second.
;
; Maximum possible ticks2wait is 65536 ticks, very close to 1 hour.
; Limit with this configuration is 9828 (9 minutes).
;

ticks_min       equ     1092            ;Number of timer ticks in 1 minute
tinkle          equ     1               ;Sound TESSBEEP if set
                                        ;set tinkle to 0
                                        ;for no sound
tick_count      dw      ?               ;Current count
ticks2wait      dw      ?               ;Ticks to wait: 1092 = 1 minute

;
; The parkit routine attempts to park all hard disks.
; Returns with carry set if park was unsuccessful.
;
parkit  proc    near
        mov     si,0080h                ;Hard drive id nos. start at 80h
pk0:    mov     ah,08h                  ;Function gets drive parms.
        mov     dx,si                   ;DX is drive ID No.
        int     13h                     ;Get drive parms, dl = No. of drives
        jc      pkdone                  ;Error if carry, jump out
        xor     dh,dh                   ;Don't need max head-side number
        mov     di,dx                   ;Save drive count from dl to di
        cmp     di,01h                  ;Is there at least one?
        jb      pkdone                  ;If no hard drives, exit
        add     di,7fh                  ;Convert drive no. to drive id no.
        inc     ch                      ;CH is now tracks + 1
        jnb     pk1
        add     cl,40h                  ;CL is sectors
pk1:    mov     ax,0c01h                ;seek to cylinder
        mov     dx,si                   ;DX is drive ID
        int     13h                     ;this does the seek
        inc     si                      ;bump drive count
        cmp     si,di                   ;Was it the last? No? Then
        jbe     pk0                     ;loop until all drives are parked
pkdone:
if tinkle
EXTRN TESSBEEP:NEAR

        call    TESSBEEP
endif
        ret
parkit  endp


;
; TesSeRact Entry Points
;
;
PUBLIC  TSRUSERPROC, TSRTIMERPROC, TSRBACKCHECK, TSRMAIN, TSRBACKPROC
PUBLIC  TSRCLEANUP

;
; TSUSERPROC is a NULL procedure.  We don't service it in this program.
;
;
TSRUSERPROC:                             ;Return, does nothing
        ret

int13ptr        dw    0                  ;Saved location of INT 13 flag
                                         ;  from TesSeRact data area
do_park         db    0                  ;Flag set to 1 when wish to park

TSRminutes      db   " "                 ;Holds minutes between parks in ASCII

park_msg label near                      ;Message to display when popped up
                                         ; AND at DOS prompt
        db      13,10,10
        db      'TSRPark has manually parked the hard disk(s)',13,10
        db      'as requested.  Will automatically repark in ',13,10
        db      '  minute(s) after next disk access.         ',13
msg_len dw      $ - park_msg

reset_it   proc near
        mov     do_park,0                ;Say not to park
        mov     bx,[int13ptr]            ;Get INT13 flag
        mov     byte ptr [bx],0          ;and turn off because
                                         ;parking isn't using.
        mov     ax,[ticks2wait]          ;Use our timer to
        mov     [tick_count],ax          ;restart wait.

        ret
reset_it   endp

TSRBACKCHECK proc near
        assume cs:_TEXT, ds:_TEXT

        mov     al,do_park               ;Put flag in ax
        xor     ah,ah                    ;if non-zero, call TSRBACKPROC
        ret
TSRBACKCHECK endp

TSRBACKPROC proc near
        assume cs:_TEXT, ds:_TEXT

        call    parkit                   ;Attempt to park it
        call    reset_it                 ;and reset everything

        ret
TSRBACKPROC endp

TSRMAIN     proc near
        assume cs:_TEXT, ds:_TEXT
                                         ;On hotkey
        call parkit                      ;Park disks
        call reset_it                    ;and reset flags and timer
        mov  ax,5453h                    ;TesSerAct function
        mov  bx,16h                      ;to get InDos state
        mov  cx,ParkNum                  ;This ident #
        int  2fh                         ;Call function 16h
        cmp  bx,1                        ;Check if at DOS prompt
        jnz  mainX                       ;and end if not
        mov  ah,08h                      ;First read attribute
        mov  bh,0                        ;at current position
        int  10h                         ;then
        or   ah,08h                      ;turn on intensity bit
        mov  bl,ah                       ;and save it in bl
        mov  si,offset park_msg          ;Point to message
        mov  cx,[msg_len]                ;and its length
putmsg: lodsb                            ;Load ASCII character
        cmp  al,20h                      ;Is it lower than space?
        jb   no_att                      ;then don't paint attribute
        push ax                          ;Save character
        mov  ah,09h                      ;Paint an attribute
        mov  al,20h                      ;with a space
        sub  bh,bh                       ;on page zero
        push cx                          ;Save count
        mov  cx,1                        ;With this function
        int  10h                         ;cursor doesn't move
        pop  cx                          ;Restore character count
        pop  ax                          ;and ASCII character
no_att: mov  ah,0eh                      ;Set to print TTY
        sub  bh,bh                       ;at page 0
        int  10h                         ;and print characters
        loop putmsg                      ;until end of string
        mov  si,offset TSRminutes        ;Display minutes
        lodsb                            ;Load a single character
        int  10h                         ;and display it
        mov  al,10                       ;Now a line feed
        int  10h                         ;with TTY display
        mov  ax,5453h                    ;TesSeRact function to
        mov  cx,ParkNum                  ;Stuff a CR into
        mov  bx,21h                      ;Keyboard Buffer
        mov  di,Offset park_msg          ;Point to a 13
        mov  si,1                        ;(one character).
        mov  dx,0101h                    ;ASCII - medium speed
        int  2fh                         ;call TesSerAct
                                         ;DOS prompt should be back.
                                         ;Can't correct error so no test.
mainX:  ret
TSRMAIN endp

TSRCLEANUP proc near
        assume cs:_TEXT, ds:_TEXT

        or   ax,ax
        jnz  clean_term

clean_init:
;
;  Please note that the data area returned by this function is also available
;    as the TESS_GLOBALS public symbol.
;
        mov  cx,ParkNum                  ;This program's ID num.
        mov  bx,4h                       ;in data area
        mov  ax,5453h                    ;Ready for multiplex
        int  2fh                         ;Call it, then point bx to
        add  bx,3h                       ;offset of TesSerAct flag "Was13"
        mov  int13ptr,bx                 ;and put in local pointer
                                         ;Since program owns segment
                                         ;no need to worry about it!
clean_term:                              ;Nothing needed to terminate!
clean_out:
        ret
TSRCLEANUP endp

TSRTIMERPROC proc near
        assume cs:_TEXT, ds:_TEXT

        mov  bx,[int13ptr]               ;Check to see if
        cmp  byte ptr [bx],1             ;disk has been accessed
        jne  no_park                     ;since last parked
no_disk:
        mov  [do_park],0                 ;If no access, set park flag off
        dec  [tick_count]                ;decrement the timer
        jnz  no_park                     ;and exit
        mov  [do_park],1                 ;else set park flag on
clear_it:
        mov  ax,[ticks2wait]             ;Use our own parameter
        mov  [tick_count],ax             ;to restart wait
        mov  byte ptr [bx],0             ;and clear flag
no_park:
        ret

TSRTIMERPROC endp

; If AUTOPARK already installed, display error message and exit.
; If not installed, attempt to park the disks and install the resident
; portion.
;
EXTRN TSDOINIT:NEAR
EXTRN TSCHECKRESIDENT:near
EXTRN TSSETSTACK:near

ParkNum      dw 0                        ;This ID number
ParkName     db 'TSRPARK ',0             ;This Identification string

public topstack
             db 48 dup('Back_Gnd')       ;BackProcStack - 384 bytes
             db 48 dup('TSR_Main')       ;MainProcStack - 384 bytes
topstack     equ this byte

PUBLIC TESSINITSTART                     ;required entry point

TESSINITSTART:
        assume cs:_TEXT, ds:_TEXT

jmp start_init

get_cmd_line:

        mov  si,80h                      ;Start of command line
        lodsb                            ;Command length
        cmp  al,0                        ;If nothing on command line
        jz   cmd_err                     ;exit
get_1:  lodsb                            ;else get next character
        cmp  al,13                       ;A CR? Then end of line
        jz   cmd_err                     ;with nothing legal. Exit.
        cmp  al,"1" - 1                  ;Is it < ASCII "1"?
        ja   chk_9                       ;No? Check for > "9"
        jmp  short get_1                 ;Yes? get another.
chk_9:  cmp  al,"9" + 1                  ;Above a nine?
        jb   cmd_ok                      ;No? OK - between "1" and "9"
        jmp  short get_1                 ;Yes? Get another
cmd_ok: mov  [TSRminutes],al             ;Is between 1 and 9, so
                                         ;save in TSR ASCII variable
        mov  [minutes],al                ;And in non-resident part too.
        and  ax,0Fh                      ;Convert ASCII to numerical
        mov  cx, ticks_min
        mul  cx                          ;Multiply by ticks_min. (1092)
        mov  di,offset tick_count
        stosw                            ;and initialize count
        stosw                            ;and wait timer value
;
;The next few bytes just stuff "# minute(s)." into the command line
;which will be carried along with the resident program, for MAPMEM
;or its ilk to see our wait time.
;
        mov  si,offset signon            ;Signon starts with a CR
        mov  di,80h                      ;which is the value we need.
        movsb                            ;Move 13 to the length byte at 80h
        mov  si,offset minutes           ;Point source at '# minute(s).'
        mov  di,82h                      ;destination at command line
        mov  cx,13                       ;and move 13 bytes
stuff_loop:                              ;looping here
        movsb
        loop stuff_loop
                                         
        clc                              ;then, after clearing carry flag
        ret                              ;exit subroutine
cmd_err:
        stc                              ;Set carry flag
        ret                              ;and return

;
;  Although I can't find it in the version 1.00 TesSerAct documentation,
;  TSRCHECKRESIDENT, if it finds the code resident, returns not only
;  0ffffh in ax but the segment of the resident version in the es register.
;  This makes it unnecessasry to call multiplex function 4 to find
;  its location.  I will use that undocumented feature here, but
;  we should have been told. - Rick Housh
;

start_init:
        mov  si,offset ParkName          ;Check to see if
        mov  di,offset ParkNum           ;resident
        call TSCHECKRESIDENT             ;Returns segment of resident
                                         ;program in es if installed
        or   ax,ax                       ;If already installed
        jnz  is_tsr                      ;then reset or display info msg
        jmp  short do_install            ;else install it
is_tsr: call get_cmd_line                ;If NOT valid command line
        jc   just_checking               ;just display status and exit
        mov  al,[TSRMinutes]             ;else get new value in ASCII
        mov  es:[TSRMinutes],al          ;and put it in resident code
        mov  es:[82h],al                 ;and in resident cmd line for mapmem
        mov  ax,[ticks2wait]             ;Same with ticks to wait
        mov  es:[ticks2wait],ax
        mov  dx,offset tsr_reset         ;Tell em have changed it
        mov  ah,09h
        int  21h
        jmp  short display_time          ;and display new value
just_checking:
        mov  dx,offset already_installed ;Already installed
        mov  ah,09h                      ;and no change, requested so
        int  21h                         ;display status message and exit
display_time:
        mov  al,es:[TSRMinutes]          ;Get minutes from resident code
        mov  [minutes],al                ;move resident value here
        mov  dx,offset auto_time         ;and display
        int  21h                         ;current TSR minute value

term_it:
        mov  ax,4c01h                    ;Set error code to 1
        int  21h                         ;and quit

do_install:                              ;"Take care of stack early"
        mov  si,offset topstack          ;Because using both,
        mov  di,si                       ;divide stack area
        dec  di                          ;into areas for
        dec  di                          ;PopUpStack and
        sub  si,384                      ;BackGroundStack
        call TSSETSTACK                  ;Two 384 byte stacks

        call get_cmd_line                ;Check for valid command line
        jc   cmdline_err                 ;If invalid display message and exit
        call parkit                      ;else attempt to park heads
        jnc  good_park                   ;If able to park say so
        mov  dx,offset bad_park          ;else print problem
        mov  ah,09
        int  21h
        jmp  term_it                     ;and quit with error code
;
; display installed message and exit
;
good_park:
        mov  dx,offset installed
        mov  ah,09                      ;Show that it's installed
        int  21h
        mov  dx,offset miwa_miwa_parwa_stella
        mov  ah,09
        int  21h                         ;and that it tinkles
        mov  dx,offset TESSINITSTART
        mov  bx,1070h                    ;No pop graphics, timer proc,
                                         ; background and main procs only
        mov  ax,0A19h                    ;Alt-LeftShift-P
                                         ;will be hotkey for manual park.

        call TSDOINIT
        mov  ax,4c00h                    ;Exit with no error code
        int  21h

cmdline_err:
        mov  dx,offset signon
        mov  ah,09
        int  21h                         ;Display the signon message
        jmp  term_it                     ;and quit with error code

;
;Non-resident data area
;
;Following are the message strings for the transient part of the program
;They do not go resident and are not available to the TSR portion
;

signon  label byte
        db   13,10,'TESSPARK.COM Version 1.0, Copyright (c) '
        db   '1988, TesSeRact(tm) Development Team',13,10
        db   'All Rights Reserved',13,10,10
        db   'Based on Original Code provided by Jim Mischel:',13,10
        db   '   AUTOPARK 1.0  Copyright (c) 1988, Jim Mischel',13,10,10
        db   'TSRPARK additions provided by Rick Housh:',13,10
        db   '   Hotkey instant park, variable auto park intervals,',13,10
        db   '   popup message (at DOS prompt), detection of park',13,10
        db   '   failure on installation, and change of timer while',13,10
        db   '   resident without removal and reinstallation.'
        db   13,10,10
        db   7,'Command line error.  TSRPark NOT loaded.',7,13,10,10
        db   'Syntax: TSRPARK # (Where # is 1 - 9 [minutes] between parks)'
        db   13,10,'$'
already_installed label   byte
        db   13,10,'TSRPARK was already resident',13,10,7,'$'
tsr_reset label   byte
        db   13,10,'TSRPARK was resident and has been reset.',13,10,7,'$'
installed label   byte
        db   13,10,'TSRPARK installed. '
auto_time label   byte
        db   'Auto park every '
minutes db   ' '
        db   ' minute(s).',13,10
        db   'Alt + Left Shift + "P" parks hard disks instantly',13,10,'$'
miwa_miwa_parwa_stella label byte        ;Or "miva" and "parva" if you prefer
        db   'A "tinkle" will sound when heads are parked',13,10,'$'
bad_park label byte    ;BAD PROBLEM, LOTS OF BELLS
        db   13,10,7,'Hard disk error.  Unable to park hard disk.'
        db   13,10,7,'Terminating.',13,10,7,'$'

_TEXT ends

        END

[ RETURN TO DIRECTORY ]