?? power.asm
字號:
; if activity has been detected DO_IDLE will be avoided
; for a period measured in timer interrupts
cmp [SPDUP],0 ; is system speed up?
je did1ot
mov ax,[SPDUP_DLY] ; check if enough time
did3ot: cmp [SPDUP_CNT],ax ; has passed to return
jae did2ot ; to normal idle
didxxx: pop ax
jmp short didex1
did2ot: mov [SPDUP],0
mov [SPDUP_DLY],0
did1ot: in al,21h ; get interrupt mask
test al,3h ; make sure timer and
jnz didxxx ; keyboard aren't masked
add word ptr [INFO].IDLE_TOT,1
adc word ptr [INFO].IDLE_TOT+2,0
IFDEF DEBUG
test [CONTROL].IDLE_FLG,SOUND_ACTIVE
jz did0ot
call START_SOUND
ENDIF ; IFDEF DEBUG
did0ot: test [CONTROL].IDLE_FLG,MEASURE_ACTIVE
jz didhlt
mov [IDLTIC],1 ; set IDLE flag ; M004
didhlt:
IFDEF INCL_APM
cmp fAPM_STATE,0 ; is APM present and enabled ?
je didNoAPM
call Do_APM_Idle
jmp short didResume
didNoAPM:
ENDIF ; for IFDEF INCL_APM
IFDEF OEM_EXTENSION
call OEM_IDLE
ELSE
call CheckV86 ; M004 AVOID HLT IN V86
jnz didNoHlt
sti ; interrupts must be enabled
hlt ; or system will halt ...
didNoHlt:
ENDIF
didResume:
didot2:
IFDEF DEBUG
test [CONTROL].IDLE_FLG,SOUND_ACTIVE
jz didex0
call END_SOUND
ENDIF ; IFDEF DEBUG
didex0: pop ax
stc ; CY.set halt executed
ret
DO_IDLE endp
;********************* APM functions ***********************************
IFDEF INCL_APM
;********************* APM IDLE routine ********************************
; Called by Do_Idle procedure when APM BIOS is present
;
; Psuedocode:
; call APM_IDLE API
; if (clock changes for CPU_IDLE API) {
; call CPU_BUSY API
; }
;
; Entry: nothing
; exit: nothing
;
;***********************************************************************
; Do_APM_CPUBUSY Entry Point (M002 addition)
; Calls APM CPUBUSY API to return CPU to full speed after a resume
; or a CPU_IDLE
; Entry: none
; Exit: none
;***********************************************************************
Do_APM_Idle Proc near
push bx
mov ax,APM_CPUIDLE_FUNC
int 15h ; make CPU_IDLE API call
pop bx
;
Do_APM_CPUBUSY label near ; M002; added this entry point
;
; Check if we need to make a CPU_BUSY call
test APM_FLAGS,APM_SLOW_CLOCK ; does CPU_IDLE slows clock ?
jz dai_End
; need to make CPU_BUSY call
push bx
mov ax,APM_CPUBUSY_FUNC
int 15h ; make CPU_BUSY call to speedup CPU
pop bx
dai_End:
ret
Do_APM_Idle endp
;********************* Do_APM_Connect **********************************
; Purpose: to connect to APM BIOS as the coop.process (real mode only)
; Entry: none
; exit: CY - connect failed
; ax = error code
; NC - connection succeeded
;***********************************************************************
Do_APM_Connect proc near ;M005
test fAPM_PRESENT,1 ; Do this only if APM is present
jz DAC_End
mov ax,APM_CONNECT_FUNC
mov bx,APM_SYSTEM_BIOS
int 15h
jc DAC_End
mov fAPM_CONNECT,1
DAC_End:
ret
Do_APM_Connect endp
;********************* Do_APM_Disconnect **********************************
; Purpose: to disconnect from APM BIOS
; Entry: none
; exit: CY - Disconnect failed (can this ever happen ?)
; ax = error code
; NC - disconnect succeeded
;***********************************************************************
Do_APM_Disconnect proc near
test fAPM_CONNECT,1 ; disconnect only if WE are
jz DAD_End ; connected
mov ax,APM_DISCONNECT_FUNC
mov bx,APM_SYSTEM_BIOS
int 15h
jc DAD_End
mov fAPM_CONNECT,0
DAD_End:
ret
Do_APM_Disconnect endp
;********************* Do_APM_Enable_Disable **********************************
; Purpose: to enable/disable all power management
;
; Entry: CX = APM_DO_DISABLE -> disable all power management
; = APM_DO_ENABLE -> enable all power management
;
; exit: CY - function unsuccessful
; ax = error code
; NC - function succeeded
;***********************************************************************
Do_APM_Enable_Disable proc near ;M005
mov ax,APM_ENABLE_DISABLE_FUNC
mov bx,APM_ALL_DEVICES
int 15h
jnc DAED_Ret
mov ax,ERROR_PM_NOT_CONNECTED
DAED_Ret:
ret
Do_APM_Enable_Disable endp
ENDIF ; for IFDEF INCL_APM
;********************* General Idle Check Routine **********************
; purpose: called by INT 28 and 16 interrupt handlers
; This is the common routine which checks elapsed time between
; interrupts in order to adjust idle signaling.
;
; Entry : SI = base address of PERIOD_INFO structure for this interrupt
; DI = address of total delay accumulator for this interrupt
; BX = address of time accumulator for this interrupt
; DS = our data segment
; Exit : nothing
; must preserve all registers
public Chk_Delay
Chk_Delay proc
assume ds:Bios_Data, es:nothing
xor cx,cx
; entry point for i16 idle checking
; for i16: cx = 1
Chk_i16idle label near
;
push ax
cmp word ptr [bx]+2,1 ; waited too long?
jb cd_readtime
jmp cd_ClrTmr ; yes, do a recount
cd_readtime:
call READ_TMR0 ; read return time
neg ax
cmp word ptr [bx]+2,1
jb cd_0
add ax,0ffffh ; OVERFLOW=-AX + 65535
add [bx],ax ; TICS=TICS + OVERFLOW
jnc cd_1
jmp cd_ClrTmr ; Go recount on overflow
cd_0:
add [bx],ax ; TICS=TICS + -ax
cd_1: mov ax,[si].BASE ; is TIC >= BASE+THRESHOLD?
add ax,[CONTROL].THRESHOLD
jnc cd_2
mov ax,0FFFFh
cd_2:
cmp [bx],ax
jae cd_go_recount ; yes, ignore reading
cmp word ptr [si].ADAPT,0 ; are we in adapt cycle ?
jne cd_3 ; yes go do avg.
; we are in idle cycle. check to see if we are within allowed limites for
; idle
mov ax,[si].BASE ; is TIC <= BASE+NOISE?
add ax,[si].NOISE
cmp [bx],ax
jbe cd_doidle ; yes, stay in halt state
; we are above the allowed idle limits; go for adapt cycles
cd_adapt:
mov word ptr [si].ADAPT,1 ; start measuring increase
mov word ptr [si].DELAY,0
cd_go_recount:
jmp short cd_transf_period
; adapt cycle processing
; try calculating avg.
; [bx] = current period
; [si].PERIOD = avg so far
; if the current period is not within 50% of prev. avg we check to see if
; we can ignore this period for avg and go for next one. If we have seen
; a no of such high(or low) values in the cycle so far, then start adapt
; cycle all over again
cd_3:
mov ax,[CONTROL].ADAPT_DLY
cmp [si].DELAY,ax ; is delay over?
jae cd_end_adapt ; yes, go cmp our avg with baselineref
mov ax,[si].PERIOD
shr ax,1 ; ax = 1/2 of avg
shr ax,1 ; ax = .25 of avg
push ax
push bx
mov bx,ax
add ax,ax
add ax,bx ; ax = 0.75 of avg
pop bx
add ax,[si].PERIOD ; ax = 1.75 times avg
cmp ax,[bx] ; is current period more than 50%
pop ax ; above our prev. period/avg
jb cd_throw_sample
cmp ax,[bx] ; ax = 1/2 of avg
ja cd_throw_sample ; if below 0.5 (avg) then ignore this
;
mov ax,[bx] ; get current period
add ax,[si].PERIOD ; add previous period
; BUGBUG - nagara This should never happen ; we should rather ignore
; this CY so that we get a low avg. this should help us not go idle when
; the period bet. ints are 32k apart
IFDEF DEBUG
jnc cd_4
dbg_printchar 'o'
ENDIF
; shr ax,1
; add ax,8000h
; jmp short cd_5
; END BUGBUG
cd_4: shr ax,1
cd_5: mov [bx],ax
jmp short cd_transf_period ; go for next int
cd_end_adapt:
mov [ErrSampleCount],0
mov word ptr [si].ADAPT,0
mov ax,[si].PERIOD ; for next compare ...
jcxz cd_setbase ; for i28 and i2f, no baseline ref.
cmp ax,[BaseLineRef] ; for i16, have a max limit for period
jbe cd_setbase ;
mov ax,[BaseLineRef]
mov [si].BASE,ax ; go up to the max.allowed base
shr ax,1 ; 50% of base
mov [si].NOISE,ax
shr ax,1 ; 25% of base
add [si].NOISE,ax ; noise = 75% of base
jmp short cd_transf_period
cd_setbase:
mov [si].BASE,ax
shr ax,1 ; 50% of base
mov [si].NOISE,ax
shr ax,1 ; 25% of base
add [si].NOISE,ax ; noise = 75% of base
cd_doidle:
call DO_IDLE
adc word ptr [di],0 ; accumulate idle time
adc word ptr [di]+2,0
mov word ptr [bx]+2,0 ; avoid speed up error
cd_transf_period:
mov ax,[bx]
mov [si].PERIOD,ax
cd_ClrTmr:
call ClearTimer ; do speedup if needed, clear
; timer accumulator
pop ax
ret
cd_throw_sample:
inc [ErrSampleCount]
mov ax,[ErrSampleCount]
cmp ax,[CONTROL].MAXERRSAMPLE
jbe cd_ClrTmr ; go try adapting again
mov [ErrSampleCount],0
jmp cd_adapt
Chk_Delay endp
;*************** Timer clear and app speedup adjustment
; Helper routine for Chk_Delay. Called independently
; by I16_IDLE when it detects a key waiting. Calls APP_SPDUP
; if required, and clears out timer overflow
;
; Entry : BX = address of timer accumulator for this interrupt
; Exit : nothing
; Uses AX -- caller must preserve
public ClearTimer
ClearTimer proc
assume ds:Bios_Data
cmp word ptr [bx]+2,3
jb ct_0
call APP_SPDUP ; speedup proportional
; to delay...
ct_0:
mov word ptr [bx]+2,0 ; clear key timer
call READ_TMR0
mov [bx],ax
cmp word ptr [bx]+2,0
jne ct_0
ret
ClearTimer endp
;********************* APPLICATION IDLE CHECK *******************
; purpose: check application idle (INT 2F Function 1680H)
; if interrupt is detected than DO_IDLE should be called
; the interrupt should be absorbed.
PUBLIC I2f_idle
I2f_idle proc far
assume ds:nothing, es:nothing
push ds
mov ds, Bios_Data_Word
assume ds:Bios_Data
cmp ax,1680h ; Any app idles?
jne i2F_chk_ours ; check for a service call to us
; JAH Set the idle support byte in the current apps PSP
push ds
mov ds,PSPsegment ; DS:BX --> Current PSP in Dosdata
mov ds,WORD PTR ds:[CUR_PSP_OFFSET] ; DS -> current app's PSP
assume ds:Pdb_Data
mov PDB_Idle,IDLE_SUPPORT_BYTE ; Set this app's idle support byte
pop ds
assume ds:Bios_Data
; JAH end
; load up registers and call do_idle
push di
lea di,[INFO].APP_TOT
; JAH call DO_IDLE
call I2fIdleEntry ; JAH Use new idle entry point
adc word ptr [di],0 ; accumulate idle time
adc word ptr [di]+2,0
I2FIdleCleanup: ; JAH New label
pop di
pop ds
iret
i2Fnxt:
jmp dword ptr pwr_i2f_next
i2f_chk_ours:
cmp ah, MultPWR_API ; is this a call for one of our ; M077
jne i2fnxt ; services ?
pop ds ; restore original vector
call Pwr_Services ; one of our services
iret ; no propagation
I2f_idle endp
;************************ I28_IDLE *********************
PUBLIC I28_idle
I28_idle proc
assume ds:nothing, es:nothing
push ds
mov ds,Bios_Data_Word
assume ds:Bios_Data
inc [I28].PCOUNT
test [CONTROL].IDLE_FLG,DOS_ACTIVE
jz i28ret
; load up registers and call general delay checker
push cx
push bx
push si
push di
lea bx,I28_TMR0
lea si,I28
lea di,[INFO].DOS_TOT
call Chk_Delay
pop di
pop si
pop bx
pop cx
i28ret:
IFDEF POWERALONE ; chain to next
jmp dword ptr pwr_i28_next
ELSE
pop ds
assume ds:nothing
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -