P. 1
MASM Source: IDESLEEP.EXE - IDE Drive Auto-Sleep TSR Utility

MASM Source: IDESLEEP.EXE - IDE Drive Auto-Sleep TSR Utility


|Views: 389|Likes:
Published by Pierre Desloover
MASM Source Code for IDESLEEP.EXE - IDE Drive Auto-Sleep TSR Utility, v1.0E
MASM Source Code for IDESLEEP.EXE - IDE Drive Auto-Sleep TSR Utility, v1.0E

More info:

Published by: Pierre Desloover on Feb 24, 2009
Copyright:Traditional Copyright: All rights reserved


Read on Scribd mobile: iPhone, iPad and Android.
download as DOC or read online from Scribd
See more
See less


TITLE IDESLEEP.EXE (C) 1995 Pierre R. Desloover page 58,132 ; ; ; ; ; ; ; ; ; ; ; ; ; ----------------------------------------------------------------------------NAME: IDESLEEP.

ASM - IDE DRIVE AUTO-SLEEP TSR UTILITY VER: Version 1.0E (.EXE image instead of .COM) DATE: 08/11/95 SYNOPSIS: Automatically issues IDE controller 'Sleep' mode command when no hdisk activity for user specified time interval. Hooks int 1ch for timer logic and issuing controller cmd. Hooks int 15h to monitor device (hdisk) busy/done states. INVOKE: IDESLEEP 0 | 1-59 <CR> (Where: 1-59 is delay interval in minutes, or 0 to deactivate) ----------------------------------------------------------------------------DOSSEG .MODEL ;equates FALSE = TRUE _CR _SPACE _TAB .DATA ; NOTE: NO DATA VARS .CODE START: jmp INSTALL_TSR


0 = = = =

0ffh 0dh 20h 09h

;code segment prog title & version id header cs_idstamp db 'IDESLEEP.EXE v1.0E (C)1995 P. DESLOOVER ' SIZE_CS_ID = $ - cs_idstamp oldint15h_vec oldint1ch_vec oldintfeh_vec int15h_busy db int1ch_busy db tick_count dw dd ? ;original int 15h vector before TSR installed dd ? ;original int 1ch vector before TSR installed dd ? ; " " feh ", etc. FALSE ;Busy flag set when hdisk dev is busy, else clear FALSE ;Busy flag to prevent re-entrant int 1ch calls 0 ;tick count maintained in int 1ch isr

max_tick_count dw ? ;interval max tick cnt based on user minutes n_hdisks db ? ;# hdisks for card zero detected via BIOS ;sleepactive db TRUE ;init auto-sleep active (sys-req key toggle) ;NOTE: EQUATES SIZE_CS_HEADER and SIZE_T_CNT must be defined just prior ;TO INTFEH ISR BELOW SINCE USED TO CALC OFFSET TO RESIDENT CS:VARS. SIZE_CS_HEADER = $ - cs_idstamp SIZE_T_CNT = $ - max_tick_count Comment | Establish a vector not likely to be revectored by any other app. AFTER this TSR installed since reinstall code relies on cs:signature being found @current vector adr-some offset in vector map. (There's always a chance that int 1ch or 15h will be revectored.) This INT vect is known to be "not assigned" or "not used" normally. This unique vector used in conjunction with reinstallation code. |

INTFEH_ISR PROC FAR ;Chain to other possible isr vector. ;OK to do this since DOS always inits upper vector map INTs F1H-FFH to ;point to a common IRET op address and/or want to preserve vect chain ;in case someone else may have revectored it (not likely, but possible). JMP DWORD PTR CS:[OLDINTFEH_VEC]

INTFEH_ISR ENDP INT1CH_ISR PROC FAR pushf sti ;Check this routine's busy flag to prevent re-entrant calls to this ISR cmp cs:[int1ch_busy],FALSE jz int1ch_not_busy CHAIN_TO_ORG_ISR: ;busy, use original int1ch (chain to it) popf ;restore flags jmp dword ptr cs:[oldint1ch_vec] int1ch_not_busy: ;go busy mov cs:[int1ch_busy],TRUE comment |

;check auto sleep active flag cmp cs:[sleepactive],TRUE je chk_hdsk_busy mov cs:[int1ch_busy],FALSE jmp short chain_to_org_isr chk_hdsk_busy: |

;active ;not, exit auto-sleep logic

;Reset tick counter if hdisk device is busy. cmp cs:[int15h_busy],FALSE jz int15h_not_busy ;hdisk dev not busy mov cs:[tick_count],0 ;reset mov cs:[int1ch_busy],FALSE jmp short chain_to_org_isr int15h_not_busy: ;increment time interval and check for inc cs:[tick_count] push ax mov ax,cs:[max_tick_count] cmp cs:[tick_count],ax pop ax jae issue_sleep_cmd mov cs:[int1ch_busy],FALSE jmp short chain_to_org_isr issue_sleep_cmd: push ax push dx ;ide sleep mode 2 command bytes 99, E6 to port 1F7 (1st hdisk) mov dx,1f7h ;primary hdisk mov al,99h out dx,al mov al,0e6h out dx,al ;;; check cmd operation status?: in al,dx ;check for possible 2nd hard drive on same controller card cmp cs:[n_hdisks],1 jz _continue_isr ;only 1 hdisk detected by BIOS ;ide sleep mode 2 command bytes 99, E6 to port 177 (possible 2nd hdisk) mov dx,177h ;secondary hdisk mov al,99h


;get user's tick interval value ;expired? ;interval expired, go to sleep

out dx,al mov al,0e6h out dx,al ;;; check cmd operation status?: in _continue_isr: pop dx pop ax mov cs:[tick_count],0 ;reset mov cs:[int1ch_busy],FALSE jmp short chain_to_org_isr INT1CH_ISR ENDP INT15H_ISR PROC FAR pushf sti


comment | ;check sys req key first and toggle state to prevent/allow ide auto-sleep ;logic/countdown in int 1ch isr cmp ah,85h jne chk_dev ;notes: al only set after this int15h int! so make/break ck here won't work ; cmp al,01h ;break of key (released)? ; jne chain2_org15h ; not cs:[sleepactive] ;toggle flag mov cs:[tick_count],0 ;reset tick jmp short chain2_org15h chk_dev: | cmp jb cmp ja cmp ja ah,90h chain2_org15h ah,91h chain2_org15h al,1h chain2_org15h ;device busy or done? ;not interested in lower fcn #'s ;not interested in higher fcn #'s ;fcn for disk/diskette? ;no, it's for network, ignore it

;set hdisk busy state flag mov cs:[int15h_busy],TRUE cmp ah,90h

;assume busy ;device busy?

je mov

chain2_org15h cs:[int15h_busy],FALSE

;busy ;dev not busy

CHAIN2_ORG15H: popf ;restore flags jmp dword ptr cs:[oldint15h_vec] INT15H_ISR ENDP comment | THROW AWAY CODE FOLLOWS | INSTALL_TSR: ;.EXE entry: need to set SP cli mov sp,0fffeh sti

;ss=cs already

;**************************************************************************** ; PARSE CMD LINE FOR REQUIRED ARG: EXPIRATION INTERVAL IN MINUTES ;**************************************************************************** ;.EXE entry: ds=es=PSP. Leave DS alone for cmd line parsing only ; and set ES=CS. ; Use CS: overrides where necessary for data offsets in parsing only. push cs pop es ;have any cmd line args? mov si,80h cld lodsb or al,al jnz have_arg


;No args on cmd line or invalid cmd line bad_cmd_line: mov dx,offset cs:prog_usage jmp error_exit HAVE_ARG: ;Skip possible white spaces until first non white found. lodsb cmp al,_CR je bad_cmd_line cmp al,_SPACE

je cmp je

have_arg al,_TAB have_arg

;First non-white char found: get minute(s) count NN string into buffer ;until first white char found. Enforce 2 chars max. mov di,offset cs:temp_buff dec si ;backup to first char get_minutes_arg: cmp di,offset cs:temp_buff+2 ja bad_cmd_line lodsb cmp al,_CR ;look-out for REAL EOL char! je convert_minutes_arg ;to done args cmp je cmp je ;store char cmp jb and store_it3: stosb jmp al,_SPACE convert_minutes_arg al,_TAB convert_minutes_arg

;to done args ;to done args

al,41h store_it3 al,0dfh

;skip case convert if below range ;convert to upper case char (mask off bit 5)

short get_minutes_arg

convert_minutes_arg: ;set desired mem seg values for rest of program (note no .DATA vars) ;ds=es=cs mov cs:[psp],ds ;save psp push cs pop ds push cs pop es ASSUME DS:_TEXT, ES:_TEXT sub di,offset temp_buff ;length of entered string mov si,offset temp_buff call ascii_to_val jc bad_cmd_line ;conversion error

;check for special timeout value of ZERO (deactivate auto-sleep mode) or al,al jnz have_arg_minutes ;set flag to block (deactivate auto-sleep mode) any further tick processing mov [mode_state],FALSE ;set OFF mov [mins],al ;save for display purposes mov al,1 ;set atleast 1 min dummy value here jmp short use_minutes ;and continue install have_arg_minutes: ;do range ck on mins value: 1 <= minutes <= 59 cmp al,1 jb bad_cmd_line ;range error cmp al,59 ja bad_cmd_line ;range error ;enable (activate auto-sleep mode) tick processing mov [mode_state],TRUE ;set ON mov [mins],al ;save for display purposes use_minutes: ;use minutes as lookup index into tick table to set [max_tick_count] dec al ;logical based xor ah,ah shl ax,1 add ax,offset ticks_tbl mov bx,ax mov ax,[bx] mov [max_tick_count],ax ;REINSTALL CODE ; 1 - get vector map EFh vector and scan at that address ; for idesleep TSR installed ID string push es xor ax,ax mov es,ax cli mov mov sti mov mov

di,es:[4*0feh] es,es:[4*0feh][2] word ptr [oldintfeh_vec],di word ptr [oldintfeh_vec][2],es

;int 0feh vector offset ;int 0feh vector segment ;temp copy ;temp copy

sub mov mov cld repe pop jnz

di,SIZE_CS_HEADER si,offset cs_idstamp cx,SIZE_CS_ID

;possible TSR copy ;current copy

cmpsb es continue_1st_install ;signature not found=TSR not previously installed

;2 - change [max_tick_count] & [tick_count] in resident code push es mov ax,[max_tick_count] mov di,word ptr [oldintfeh_vec] ;get temp copy of TSR offset mov es,word ptr [oldintfeh_vec][2] ;get temp copy of TSR seg sub di,SIZE_T_CNT cld stosw mov es:[tick_count],0 ;calc offset before ISR loc ;store it in TSR resident code ;always reset!

;3 - set resident code int 1ch busy flag per local copy mode state flag mov es:[int1ch_busy],TRUE ;assume busy cmp [mode_state],FALSE jz _continue ;block auto-sleep mov es:[int1ch_busy],FALSE ;allow auto-sleep _continue: pop


;4 - inform user TSR timeout value reset and do regular DOS terminate call show_installed_msg call show_mode_state ;5 - then do normal DOS terminate mov ax,4c00h int 21h ;END REINSTALL CODE continue_1st_install: ;find #hard drives 1st card only (0-2 returned by AT BIOS, others return more) mov dl,80h mov ah,08h int 13h

or jnz mov jmp

dl,dl _cont_w_install dx,offset no_hdisk_msg short error_exit

_cont_w_install: mov [n_hdisks],dl comment | RELEASE DOS ENVIRONMENT BLOCK TO MAKE RESIDENT SIZE SMALLER | push es mov es,[psp] mov es,es:[2ch] mov ah,49h int 21h pop es comment | INSTALL NEW ISR'S | ;Revector INT 1cH to our replacement ISR push es mov int mov mov mov mov int ax,351ch 21h word ptr cs:[oldint1ch_vec],bx word ptr cs:[oldint1ch_vec][2],es ax,251ch dx,offset int1ch_isr 21h

;Revector INT 15H to our replacement ISR mov ax,3515h int 21h mov word ptr cs:[oldint15h_vec],bx mov word ptr cs:[oldint15h_vec][2],es mov ax,2515h mov dx,offset int15h_isr int 21h ;Revector INT 0FEH to our replacement ISR mov ax,35feh int 21h mov word ptr cs:[oldintfeh_vec],bx mov word ptr cs:[oldintfeh_vec][2],es mov ax,25feh mov dx,offset intfeh_isr

int pop

21h es

;display installed OK msg and mode msg call show_installed_msg call show_mode_state ;calc amount of code to remain mov dx,offset cs:install_tsr add dx,0fh mov cl,4 shr dx,cl MOV AX,CS ADD DX,AX SUB DX,[PSP] ;tsr mov ax,3100h int 21h error_exit: ;on exit, dx has ptr to msg to display mov ah,09h int 21h mov ax,4cffh int 21h ; SUBROUTINES ASCII_TO_VAL: ;Converts Decimal ascii string (up to 5 chars) to value ;On entry: SI has base address of string to convert ; DI has length of string to convert ;On exit: CY set if word overflow or invalid ascii char, else CY clr and ; AX has converted value ; mov bp,10 ;set base 10 xor ax,ax ;init results cld convert_loop: push ax lodsb or al,20h

;al <- ds:[si] ;to lower case

;check if legal decimal ascii char call is_dec_ascii jnc continue_convert ;error pop ax ret continue_convert: xor ah,ah sub al,'0' radix_mult: mov pop mul or jz overflow: stc ret

;remove bias

cx,ax ax bp dx,dx no_overflow

;ax * bp -> dx:ax ;word overflow ?

;overflow error

no_overflow: add ax,cx jc overflow ;loop control dec di jnz convert_loop clc ret IS_DEC_ASCII: cmp al,'0' jc bad1 cmp al,'9' ja bad clc ret bad: stc bad1: ret

;overflow error

;conversion success

;TEMP DATA FOLLOWS INSTALL_MSG db 0dh, 0ah db 'IDESLEEP.EXE v1.0E (C)1995 P. Desloover - TSR installed OK' db 0dh, 0ah, 0ah

delay_msg minutes_msg mode_state_msg active_msg inactive_msg no_hdisk_msg

db 'Delay interval set: $' db ' Minutes', 0dh, 0ah,'$' db 'Auto-sleep mode is: $' db 'Active',0dh, 0ah, 0ah,'$' db 'Inactive',0dh, 0ah, 0ah,'$' db 0dh, 0ah db 'No Hard Disk(s) found in system - TSR not installed' db 0dh, 0ah, 0ah,'$'

prog_usage db 0dh, 0ah db 'Usage: IDESLEEP DELAY_INTERVAL <CR>', 0dh, 0ah, 0ah db 'Where required command line argument DELAY_INTERVAL is either:', 0dh, 0ah db 'the number of minutes (1-59) of disk inactivity before the IDE', 0dh, 0ah db 'sleep mode command is automatically issued by this TSR, or zero', 0dh, 0ah db 'minutes (0) to deactivate the TSR''s IDE auto-sleep mode.', 0dh, 0ah, 0ah db 'Examples: idesleep 12 <CR> or: idesleep 0 <CR>', 0dh, 0ah, 0ah,'$' ;int 1ch isr 18.3/sec rate * 60 secs/min = total ticks per min(s) ;DW values imported from a special created .lst file (see: ticks.c). ;NOTE: #'s 1-59 table entries max TICKS_TBL dw 1098 ;#secs ( 60) * 18.3 (1 minute) dw 2196 ;#secs ( 120) * 18.3 (2 minutes), etc. dw 3294 dw 4392 dw 5490 dw 6588 dw 7686 dw 8784 dw 9882 dw 10980 dw 12078 dw 13176 dw 14274 dw 15372 dw 16470 dw 17568 dw 18666 dw 19764 dw 20862 dw 21960 dw 23058 dw 24156 dw 25254

;REF only

dw dw dw dw dw dw dw dw dw dw dw dw dw dw dw dw dw dw dw dw dw dw dw dw dw dw dw dw dw dw dw dw dw dw dw dw dw

26352 27450 28548 29646 30744 31842 32940 34038 35136 36234 37332 38430 39528 40626 41724 42822 43920 45018 46116 47214 48312 49410 50508 51606 52704 53802 54900 55998 57096 58194 59292 60390 61488 62586 63684 64782 65880

;mins = 59 MAX ;mins = 60 (REF only: over word limit)

;scratch for cmd line arg temp_buff db 8 dup (20h) ;auto-sleep active/inactive state mode_state db FALSE ;saved user mins spec'ed mins db 0

;saved psp seg value psp dw ? SHOW_INSTALLED_MSG: mov si,offset temp_buff mov di,offset delay_msg+20 cld lodsw stosw mov dx,offset INSTALL_MSG mov ah,09h int 21h mov mov cmp jae inc cmp jae cmp je mov _disp_delay: mov int ret dx,offset minutes_msg bx,dx [mins],10 _disp_delay dx [mins],2 _disp_delay [mins],0 _disp_delay byte ptr [bx][7],_SPACE ah,09h 21h

;make copy ;2 digits (plural) ;skip 1 space ;1 digit (plural) ;1 digit (plural) ;=1 (make singular case)

SHOW_MODE_STATE: mov dx,offset mode_state_msg mov ah,09h int 21h mov dx,offset active_msg ;assume active cmp [mode_state],TRUE je show_mode mov dx,offset inactive_msg show_mode: mov ah,09h int 21h ret END START

You're Reading a Free Preview

/*********** DO NOT ALTER ANYTHING BELOW THIS LINE ! ************/ var s_code=s.t();if(s_code)document.write(s_code)//-->