📄 gpmlib.inc
字号:
; <> 0ffh program (dh) in sector count reg ;
; actual time = (dh) * 5 seconds ;
; STACK PRESENT ;
; Output: (CY) 00 for no error ;
; (CY) 01 for error ;
; Register destroyed : (AX) ;
; ;
; This subroutine is called to write low power command to the ;
; ide drive. This routine checks for the drive presence. ;
; ;
; assumption: Hardware interrupt for the ide is masked on ;
; entry to this subroutine. ;
;---------------------------------------------------------------;
ide_low_power_cmd_ext proc near
test byte ptr [bx+hdd_misc_control_info],hdd_present_bit_equ; current drive present ?
jz short low_power_cmd_ext_00 ; no...
test dl,00010000b ; request for standby/standby immediate ?
jz short low_power_cmd_ext_01 ; no...
call ide_exec_standby_command ; execute standby/standby immediate
low_power_cmd_ext_00:
ret
low_power_cmd_ext_01:
test dl,00100000b ; request for idle/idle immediate ?
jz short low_power_cmd_ext_00 ; no...
call ide_exec_idle_command ; execute idle/idle immediate
ret
ide_low_power_cmd_ext endp
;---------------------------------------------------------------;
; IDE_EXEC_STANDBY_COMMAND ;
;---------------------------------------------------------------;
; Input : (DS) PM BIOS data segment ;
; (BX) control information pointer for the drive ;
; (DH) 0ffh do not program timer into sec count reg
; <> 0ffh program (dh) in sector count reg ;
; actual time = (dh) * 5 seconds ;
; STACK PRESENT ;
; Output: (CY) 00 for no error ;
; (CY) 01 for error ;
; Register destroyed : (AX) ;
; ;
; This subroutine is called to write standby command to the ide ;
; drive ;
; ;
; assumption: Hardware interrupt for the ide is masked on ;
; entry to this subroutine. ;
;---------------------------------------------------------------;
ide_exec_standby_command proc near
push di ;
push cx ;
cmp dh,0ffh ; standby immediate ?
jz short exec_standby_cmd_00 ; yes...
mov cx,standby_old_cmd*256+standby_cmd; STANDBY command with count
; if count is zero, drive's automatic
; power management is disabled
mov di,hdd_standby_cmd_save ; offset for standby command save
jmp short exec_standby_cmd_01 ;
exec_standby_cmd_00:
mov cx,standby_immediate_old_cmd*256+standby_immediate_cmd; STANDBY command with no count
; controller should use previous count
mov di,hdd_standby_imm_cmd_save ; offset for standby immediate command save
exec_standby_cmd_01:
;-----------------------------------------------;
exec_idle_cmd_01::
call ide_exec_power_mode_dup_func ; execute STANDBY command
pop cx ;
pop di ;
ret
ide_exec_standby_command endp
;---------------------------------------------------------------;
; IDE_EXEC_IDLE_COMMAND ;
;---------------------------------------------------------------;
; Input : (DS) PM BIOS data segment ;
; (BX) control information pointer for the drive ;
; (DH) 0ffh do not program timer into sec count reg
; <> 0ffh program (dh) in sector count reg ;
; actual time = (dh) * 5 seconds ;
; STACK PRESENT ;
; Output: (CY) 00 for no error ;
; (CY) 01 for error ;
; Register destroyed : (AX) ;
; ;
; This subroutine is called to write idle command to the ide ;
; drive ;
; ;
; assumption: Hardware interrupt for the ide is masked on ;
; entry to this subroutine. ;
;---------------------------------------------------------------;
ide_exec_idle_command proc near
push di ;
push cx ;
cmp dh,0ffh ; idle immediate ?
jz short exec_idle_cmd_00 ; yes...
mov cx,idle_old_cmd*256+idle_cmd ; IDLE command with count
; if count is zero, drive's automatic
; power management is disabled
mov di,hdd_idle_cmd_save ; offset for idle command save
jmp short exec_idle_cmd_01 ;
exec_idle_cmd_00:
mov cx,idle_immediate_old_cmd*256+idle_immediate_cmd; IDLE command with no count
; controller should use previous count
mov di,hdd_idle_imm_cmd_save ; offset for idle immediate command save
jmp short exec_idle_cmd_01 ;
ide_exec_idle_command endp
;---------------------------------------------------------------;
; IDE_EXEC_POWER_MODE_DUP_FUNC ;
;---------------------------------------------------------------;
; Input : (DS) PM BIOS data segment ;
; (BX) control information pointer for the drive ;
; (DI) offset to command save ;
; (CL) primary command ;
; (CH) alternate command ;
; (DH) 0ffh do not program timer into sec count reg
; <> 0ffh program (dh) in sector count reg ;
; actual time = (dh) * 5 seconds ;
; STACK PRESENT ;
; Output: (CY) 00 for no error ;
; (CY) 01 for error ;
; Register destroyed : (AX) ;
; ;
; This subroutine is called to write a power control command to ;
; the ide drive ;
; ;
; assumption: Hardware interrupt for the ide is masked on ;
; entry to this subroutine. ;
;---------------------------------------------------------------;
ide_exec_power_mode_dup_func proc near
mov al,[bx+di] ; (al) = power management command to be used with the drive
cmp al,0ffh ; any command supported by this drive ?
jz short exec_dup_func_00 ; no...
cmp al,00h ; any valid command already established for this drive ?
jnz short exec_dup_func_01 ; yes...use that command
mov al,cl ; (al) = primary command
call ide_execute ; execute the command
jnc short exec_dup_func_02 ; no error
mov al,ch ; (al) = alternate command
call ide_execute ; execute the command
jnc short exec_dup_func_02 ; no error...
mov byte ptr [bx+di],0ffh ; set for no command supported
exec_dup_func_00:
stc ; (cy) = 01 for error
exec_dup_func_02:
ret
exec_dup_func_01:
call ide_execute ; execute the command
ret
ide_exec_power_mode_dup_func endp
;---------------------------------------------------------------;
; IDE_EXECUTE ;
;---------------------------------------------------------------;
; Input : (DS) PM BIOS data segment ;
; (BX) control information pointer for the drive ;
; (DI) offset to command save ;
; (AL) power mode control command ;
; (DH) 0ffh do not program timer into sec count reg
; <> 0ffh program (dh) in sector count reg ;
; actual time = (dh) * 5 seconds ;
; STACK PRESENT ;
; Output: (CY) 00 for no error ;
; (CY) 01 for error & (AH) has error code ;
; Register destroyed : (AX) ;
; ;
; This subroutine is called to write a power control command to ;
; the ide drive ;
; ;
; assumption: Hardware interrupt for the ide is masked on ;
; entry to this subroutine. ;
;---------------------------------------------------------------;
ide_execute proc near
mov ah,dh ; (ah) = timer information
mov [bx+di],al ; save primary/alternate command
call ide_exec_power_mode_func ; execute the command
ret
ide_execute endp
;---------------------------------------------------------------;
; IDE_EXEC_POWER_MODE_FUNC ;
;---------------------------------------------------------------;
; Input : (DS) PM BIOS data segment ;
; (BX) control information pointer for the drive ;
; (AL) power mode control command ;
; (AH) 0ffh do not program timer into sec count reg
; <> 0ffh program (ah) in sector count reg ;
; actual time = (ah) * 5 seconds ;
; STACK PRESENT ;
; Output: (CY) 00 for no error ;
; (CY) 01 for error & (AH) has error code ;
; Register destroyed : (AX) ;
; ;
; This subroutine is called to write a power control command to ;
; the ide drive ;
; ;
; assumption: Hardware interrupt for the ide is masked on ;
; entry to this subroutine. ;
;---------------------------------------------------------------;
ide_exec_power_mode_func proc near
push di ;
push dx ;
push cx ;
pushf ; save current interrupt status
cli ; disable interrupts
push ax ; save (al) = power mode controller command
mov di,primary_ide_cntlr ; (di) = base address for primary IDE controller
test byte ptr [bx+hdd_misc_control_info],hdd_port_select_bit_equ ; secondary IDE controller ?
jz short exec_power_mode_func_00 ; no..primary IDE controller
mov di,secondary_ide_cntlr ; (di) = base address for secondary IDE controller
exec_power_mode_func_00:
mov dx,di ; (dx) = base address for IDE controller
add dx,status_reg_off ; (dx) = ide status reg (1f7h/177h)
in al,dx ; (al) = current status
test al,ide_cntlr_busy_bit ; is controller busy ?
jnz short exec_power_mode_func_03 ; yes...error...exit
mov al,10100000b ; drive/head reg data for drive 0
test byte ptr [bx+hdd_misc_control_info],hdd_drive_select_bit_equ; drive 0 ?
jz short exec_power_mode_func_05 ; yes..
mov al,10110000b ; drive/head reg data for drive 1
exec_power_mode_func_05:
mov dx,di ; (dx) = base address for IDE controller
add dx,drive_head_reg_off ; (dx) = drive/head reg (1f6h/176h)
out dx,al ; select the drive
mov cx,8 ; 120 micro sec delay (TIME might be more if slow refresh)
call pm_fixed_delay ;
mov dx,di ; (dx) = base address for IDE controller
add dx,status_reg_off ; (dx) = ide status reg (1f7h/177h)
in al,dx ; (al) = read current status
and al,ide_drv_rdy_bit or ide_drv_seek_complete_bit
cmp al,ide_drv_rdy_bit or ide_drv_seek_complete_bit; is drive ready and seek complete ?
jnz short exec_power_mode_func_03 ; no...error...exit
cmp ah, 0ffh ; program sector count ?
jz short skip_sector_count_prg ; no...
mov dx, di ; (dx) = base address for IDE controller
add dx, sector_count_reg_off ; (dx) = sector count reg (1f2h/172h)
mov al, ah ; (al) = count of 5 seconds IDLE timer
out dx, al ; program the counter
smi_io_delay ; i/o delay
skip_sector_count_prg:
pop ax ; (al) = power mode drive command
mov dx,di ; (dx) = base address for IDE controller
add dx,command_reg_off ; (dx) = command register (1f7h/177h)
out dx,al ; output command to controller
call ide_wait_for_interrupt ; interrupt came ?
jz short exec_power_mode_func_01 ; no...error...exit
mov dx,di ; (dx) = base address for IDE controller
add dx,status_reg_off ; (dx) = ide status reg (1f7h/177h)
in al,dx ; (al) = current status
test al,ide_drv_rdy_bit ; drive ready ?
jz short exec_power_mode_func_01 ; no...error...exit
test al,ide_drv_seek_complete_bit ; seek complete ?
jz short exec_power_mode_func_01 ; no...error...exit
test al,ide_drv_wt_fault_bit or ide_data_corrected_bit; write fault or data corrected error ?
jnz short exec_power_mode_func_01 ; yes...error...exit
test al,ide_err_reg_bit ; error reg has any error info
jz short exec_power_mode_func_02 ; no...eror free completion...(CY) set to (NC)
mov dx,di ; (dx) = base address for IDE controller
add dx,error_reg_off ; (dx) = error reg (1f7h/177h)
in al,dx ; (al) = current error reg status
; this read will clear the error status
exec_power_mode_func_01:
mov ah,undefined_err ; undefined error
exec_power_mode_func_04:
popf ; restore interrupt status
stc ; (cy) = 01 for error
exec_power_mode_func_10:
pop cx ;
pop dx ;
pop di ;
ret
exec_power_mode_func_03:
pop ax ;
mov ah,time_out_err ; timeout error
jmp short exec_power_mode_func_04 ;
exec_power_mode_func_02:
popf ; restore interrupt status
clc ; (cy) = 00 for no error
jmp short exec_power_mode_func_10 ;
ide_exec_power_mode_func endp
;---------------------------------------------------------------;
; IDE_WAIT_FOR_INTERRUPT ;
;---------------------------------------------------------------;
; Input : (DI) base address for IDE controller ;
; (DX) command/status reg for IDE controller ;
; (BX) control information pointer for the drive ;
; (DS) PM BIOS data segment ;
; STACK PRESENT ;
; Output: (ZF) 00 (NZ) interrupt active ;
; (ZF) 01 (ZR) interrupt not active ;
; Register destroyed : (AX),(CX),(DX) ;
; ;
; This subroutine is called after a command is writen to the IDE;
; command port to wait for the interrupt to be returned by the ;
; IDE. It will poll the IDE intr level until an IRQ or time-out.;
;---------------------------------------------------------------;
ide_wait_for_interrupt proc near
push si ;
IF IRQ_HANDLING_SUPPORT
call check_irq_pm ; IRQ based power management ?
jnz short ide_wait_for_interrupt_12 ; yes...
ENDIF
mov cl,[bx+hdd_misc_control_info] ; (cl) = IDE miscellaneous control information
mov dx,control_8259_slave ; (dx) = 8259 slave control port (0a0h)
test cl,00001000b ; IRQ level 0 thru 7 ?
jnz short ide_wait_for_interrupt_01 ; no...level 8 thru 15
mov dx,control_8259_master ; (dx) = 8259 master control port (020h)
ide_wait_for_interrupt_01:
and cl,00000111b ; make the level 0 thru 7
mov ah,00000001b ;
shl ah,cl ; get in proper bit position
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -