www.pudn.com > hpbios.rar > ATIME.ASM
; []===========================================================[] ; ; NOTICE: THIS PROGRAM BELONGS TO AWARD SOFTWARE INTERNATIONAL(R) ; INC. IT IS CONSIDERED A TRADE SECRET AND IS NOT TO BE ; DIVULGED OR USED BY PARTIES WHO HAVE NOT RECEIVED ; WRITTEN AUTHORIZATION FROM THE OWNER. ; ; []===========================================================[] ; ;---------------------------------------------------------------------------- ;Rev Date Name Description ;---------------------------------------------------------------------------- ;R20B 06/03/99 TNY ICH need Y2K patch to fix some y2000 program test ; fail. ;R20A 05/26/99 TNY ICH do not need Y2K check at runtime. Also patch ; the UIP glitch of ICH B0 stepping bug. ; ;R20 03/24/99 RAY Add switch: NO_Y2K_CHECK for some customer that they ; have RTC that supports century ;990222 RAY Use ML 6.x to compile ;R19D 12/01/98 TNY Set "Ct_Save_RTC_Index" hook called between 1 sec. ;R19C 02/02/98 TNY Save PCI index port and eax. ifdef MASM611 ;990222 .MODEL SMALL, BASIC ;990222 OPTION PROC: PRIVATE ;990222 endif ;MASM611 ;990222 PAGE 60,132 .386 ;[]-----------------------------------[] ; ; Award Software 386/486 BIOS ; Timer handling ; Initial Revision 30-Apr-1990 ; ;[]-----------------------------------[] .XLIST INCLUDE BIOS.CFG INCLUDE COMMON.EQU INCLUDE 8259.EQU INCLUDE CMOS.EQU INCLUDE ATORGS.EXT INCLUDE COMMON.MAC extrn Turbo_Pin_Hdlr:near .LIST ;[]---------------------------[] ; ; Low memory init (1st 64k) ; ;[]---------------------------[] G_RAM SEGMENT USE16 AT 40H ; ALL HERE BUT 40:3FH, 40:40H 3.04 INCLUDE G_RAM.INC G_RAM ENDS ; ;REQUESTER_FLG_OFFSET = 098H ; ;;;;;;;;; WAIT EQUATES ;Wait for update NOT in progress. ;Wait needs to be at least 244Us + 1984Us. See Motorola 8-bit ;microprocessor & peripheral data, pg. 3-713. ;Multiply by 4 to reduce chance of interrupts occuring during ;update in progress and lasting until next update in progress. ;assume each read takes 2 microseconds. WAITCPU_CK_UD_STAT EQU ((1984+244)*4)/2 ifdef PCI_BUS extrn Pci_Procedure:near endif; PCI_BUS extrn Int8_Hook:near extrn POST_func_end:Near extrn POST_VECT:Near FCODE SEGMENT USE16 PARA PUBLIC 'CODE' ASSUME CS:FCODE ;****************************************************** ;Name: Time_day_start ;Entry: called by int 1ah ;Input: ah=function ; other regs as described below ;Output: regs as described below ;****************************************************** ALIGN 4 PUBLIC TIME_DAY_START TIME_DAY_START PROC NEAR PUBLIC TDS_S ;990222 TDS_S: TDS_S Label Near ;990222 ifdef PCI_BUS ;Check if PCI BIOS service handler PCI_FUNCTION_ID EQU 0B1H cmp ah,PCI_FUNCTION_ID jne short @F jmp Pci_Procedure @@: endif; PCI_BUS STI CMP AH,7 ; SEE IF VALID AND JBE SHORT VALID_REQUEST ; SET CARRY FOR POSSIBLE ERR STC RETF 2 VALID_REQUEST: PUSH BX MOV BL,AH ; WORD INDEX XOR BH,BH SHL BX,1 JMP cs:TIMEHDLR_TBL[BX] ; INT 1A FUNCTIONS BRANCH TABLE ERR_1B: ; Return here for failure due to update in progress ;when trying to read date or time XOR AL,AL ERR_1A: ; Return here for failure of 1A invocation STC JMP SHORT RET_1A ; RETURN HERE FOR SUCCESSFUL 1A INVOCATION SUCCESS_1A: CLC RET_1A: MOV AH,0 POP BX STI RETF 2 ;****************************************************** ;Name: get_soft_time ;Entry: called from Time_day_start ;Input: ah=0 ;Output: cx=high count ; dx=low count ; al=0 if get_soft_time not overflowed since last call ; al<>0 otherwise ;Description: ; ;get_soft_time will: ;1. save environment ;2. obtain time values from software clock ;3. restore environment ;4. return to Time_day_start ;****************************************************** GET_SOFT_TIME: CLI PUSH DS MOV BX,G_RAM ; address of segment MOV DS,BX ASSUME DS:G_RAM MOV BX,OFFSET LOW_8254_CNT MOV DX,[BX] ; return current free MOV CX,[BX+2] XOR AL,AL ; running clock values XCHG AL,[BX+4] ; and clear overflow POP DS JMP SHORT SUCCESS_1A ;****************************************************** ;Name: put_soft_time ;Entry: called from Time_day_start ;Input: ah=1 ; cx=high count ; dx=low count ;Output: none ;Description: ; ;put_soft_time will: ;1. save environment ;2. set the software clock with requested values ;3. restore environment ;4. return to Time_day_start ;****************************************************** SET_SOFT_TIME: CLI PUSH DS MOV BX,G_RAM MOV DS,BX ASSUME DS:G_RAM MOV BX,OFFSET LOW_8254_CNT MOV [BX],DX ; set values MOV [BX+2],CX MOV BYTE PTR [BX+4],0 POP DS JMP SHORT SUCCESS_1A ;****************************************************** ;Name: Get_Rtime ;Entry: called from Time_day_start ;Input: ah=2 ;Output: if clock operating ; ch=hours in BCD ; cl=minutes in BCD ; dh=seconds in BCD ; cy=0 ; else cy=1 ;Description: ; ;Return the real time clock time of day in BCD format. ; ;Get_Rtime will: ;1. save environment ;2. obtain time values from system clock ;3. restore environment ;4. return to Time_day_start ;****************************************************** GET_RTIME: CALL CK_UD_STAT ; SEE IF CURRENTLY UPDATING OR AL,AL JNZ SHORT ERR_1B ; IF SO GET OUT CLI MOV AL,04 NMI_ON ; GET THE HOURS CALL GET_CMOS MOV CH,AL MOV AL,02 NMI_ON ; GET THE MINUTES CALL GET_CMOS MOV CL,AL MOV AL,00 NMI_ON CALL GET_CMOS ; GET THE SECONDS MOV DH,AL MOV AL,0BH NMI_ON ; get daylight mode. CALL GET_CMOS AND AL,01H MOV DL,AL MOV AL,CH ; al=hours JMP SUCCESS_1A ; AND DONE ;****************************************************** ;Name: set_rtime ;Entry: called from Time_day_start ;Input: ah=3 ; ch=hours in BCD ; cl=minutes in BCD ; dh=seconds in BCD ; dl=1 if daylight savings time option, else 0 for standard. ;Output: none ; ;Description: ; ;Set the real time clock time of day in BCD format. ; ;set_rtime will: ;1. save environment ;2. set the system clock with requested values ;3. restore environment ;4. return to Time_day_start ;****************************************************** SET_RTIME: CALL CK_UD_STAT ; see if clock running OR AL,AL JZ SHORT SET_CLK CALL INIT_RTC SET_CLK: CLI AND DL,01H ; range check DST/ST MOV AL,04 NMI_ON ; SET THE HOURS MOV AH,CH CALL SET_CMOS MOV AL,02 NMI_ON ; SET THE MINUTES MOV AH,CL CALL SET_CMOS MOV AL,00 NMI_ON MOV AH,DH ; SET THE SECONDS CALL SET_CMOS MOV AL,0BH NMI_ON ; GET CONTROL BYTE CALL GET_CMOS MOV AH,AL and ah,6AH ; keep bit 3 unchange. OR AH,2 ; SET 24 HOUR MODE OR AH,DL ; OR IN USER'S DST OR ST MOV AL,0BH NMI_ON ; AND SET IT CALL SET_CMOS JMP SUCCESS_1A ;****************************************************** ;Name: get_rdate ;Entry: called from Time_day_start ;Input: ah=4 ;Output: if clock operating ; ch=century in BCD (19 or 20) ; cl=year in BCD ; dh=month in BCD ; dl=day in BCD ; cy=0 ; else cy=1 ;Description: ; ;Read date from real time clock. ; ;get_rdate will: ;1. save environment ;2. set the system clock with requested values ;3. restore environment ;4. return to Time_day_start ;****************************************************** GET_RDATE: CALL CK_UD_STAT ; see if clock operating OR AL,AL JZ SHORT READ_DATEOK JMP ERR_1B READ_DATEOK: CLI MOV AL,32H NMI_ON ; GET THE CENTURY CALL GET_CMOS MOV CH,AL MOV AL,09 NMI_ON ; GET THE YEAR CALL GET_CMOS MOV CL,AL ;R20A - start Y2K_CHECK_AT_RUNTIME = 1 ifdef NO_Y2K_CHECK Y2K_CHECK_AT_RUNTIME = 0 endif; NO_Y2K_CHECK ifdef ICH ;R20B Y2K_CHECK_AT_RUNTIME = 0 Y2K_CHECK_AT_RUNTIME = 1 endif; ICH ;R20A - end ;R20A ifndef NO_Y2K_CHECK ;R20 IF Y2K_CHECK_AT_RUNTIME ;R20A ;Return and set CMOS to 20XX if the century value in CMOS is 19. cmp al,80H ;beyond 198X ? jae short Good_YearBCD ;yes, cmp ch,19H ;year 19XX ? ja short Good_YearBCD ;yes mov ch,20H ;no, return century to 20XX mov al,32H NMI_ON ;set century into CMOS mov ah,ch call Set_Cmos Good_YearBCD: ;R20A endif ;NO_Y2K_CHECK ;R20 ENDIF; Y2K_CHECK_AT_RUNTIME ;R20A MOV AL,08 NMI_ON ; GET THE MONTH CALL GET_CMOS MOV DH,AL MOV AL,07 NMI_ON ; GET THE DAY CALL GET_CMOS MOV DL,AL MOV AL,CH ; AL=century. JMP SUCCESS_1A ;****************************************************** ;Name: Set_RDate ;Entry: called from Time_day_start ;Input: ah=5 ; ch=century in BCD (19 or 20) ; cl=year in BCD ; dh=month in BCD ; dl=day in BCD ;Output: none ;Description: ; ;Set the date into the real time clock. ; ;Set_RDate will: ;1. save environment ;2. set the system clock with requested values ;3. restore environment ;4. return to Time_day_start ;****************************************************** SET_RDATE: CALL CK_UD_STAT ; see if clock running OR AL,AL JZ SHORT SET_DATE CALL INIT_RTC SET_DATE: CLI MOV AL,32H NMI_ON ; SET THE CENTURY MOV AH,CH CALL SET_CMOS MOV AL,09 NMI_ON MOV AH,CL ; SET THE YEAR CALL SET_CMOS MOV AL,08 NMI_ON MOV AH,DH ; SET THE MONTH CALL SET_CMOS MOV AL,07 NMI_ON MOV AH,DL ; SET THE DAY CALL SET_CMOS MOV AL,06 NMI_ON XOR AH,AH CALL SET_CMOS MOV AL,0BH NMI_ON CALL GET_CMOS ; GET CONTROL BYTE AND AL,7FH ; and set clock running MOV AH,AL MOV AL,0BH NMI_ON CALL SET_CMOS JMP SUCCESS_1A ;****************************************************** ;Name: Set_Alarm ;Entry: called from Time_day_start ;Input: ah=6 ; ch=hours in BCD ; cl=minutes in BCD ; dh=seconds in BCD ;Output: cy=1 if clock not operating ; cy=0 if clock operating ;Description: ; ;Set_Alarm will: ;1. save environment ;2. set the system clock alarm with requested values. When ; alarm is activated the routine at interrupt 70H. ;3. restore environment ;4. return to Time_day_start ;****************************************************** SET_ALARM: MOV AL,0BH NMI_ON CALL GET_CMOS TEST AL,20H JZ SHORT DO_SET_ALR JMP ERR_1A ; IF SO REPORT IT DO_SET_ALR: CALL CK_UD_STAT ; IF UPDATING THEN STOP UPDATE MODE OR AL,AL JZ SHORT NO_INIT CALL INIT_RTC NO_INIT: CLI IN AL,B8259+1 ; ENABLE 8259 ALARM INTERRUPT AND AL,0FEH SIODELAY OUT B8259+1,AL MOV AL,05 NMI_ON ; SET HOUR ALARM MOV AH,CH CALL SET_CMOS MOV AL,03 NMI_ON MOV AH,CL ; SET MINUTES ALARM CALL SET_CMOS MOV AL,01 NMI_ON MOV AH,DH ; SET SECONDS ALARM CALL SET_CMOS MOV AL,0BH NMI_ON ; SET AIE CALL GET_CMOS AND AL,7FH OR AL,20H MOV AH,AL MOV AL,0BH NMI_ON CALL SET_CMOS JMP SUCCESS_1A ;****************************************************** ;Name: Reset_Alarm ;Entry: called from Time_day_start ;Input: ah=7 ;Output: none ;Description: ; ;put_soft_time will: ;1. save environment ;2. reset the alarm mode on system clock ;3. restore environment ;4. return to Time_day_start ;****************************************************** RESET_ALARM: CLI MOV AL,0BH NMI_ON ; DISABLE AIE CALL GET_CMOS and al,5fH ; keep bit 3 unchange MOV AH,AL MOV AL,0BH NMI_ON CALL SET_CMOS JMP SUCCESS_1A ; 1A FUNCTION JUMP TABLE ALIGN 4 TIMEHDLR_TBL DW OFFSET GET_SOFT_TIME DW OFFSET SET_SOFT_TIME DW OFFSET GET_RTIME DW OFFSET SET_RTIME DW OFFSET GET_RDATE DW OFFSET SET_RDATE DW OFFSET SET_ALARM DW OFFSET RESET_ALARM TIME_DAY_START ENDP ;****************************************************** ;Name: Init_RTC ;Entry: called ;Input: none ;Output: ax destroyed ; CLI in effect ;Description: ;Init_RTC will: ;1. set clock operating frequency, stop updating and reset it ;****************************************************** INIT_RTC PROC NEAR CLI ; interrupts off while ; changing CMOS MOV AL,0AH NMI_ON MOV AH,26H ; 32.8KHZ BASE,1.024KHZ SQ. WAVE,976.6 uSEC PI CALL SET_CMOS MOV AL,0BH NMI_ON MOV AH,82H ; STOP UPDATING, 24 HOUR MODE call Get_Cmos ; Read current value and al,08H ; get bit 3 status or ah,al mov al,0BH NMI_ON CALL SET_CMOS MOV AL,0CH NMI_ON CALL GET_CMOS ; READ AND RESET RET INIT_RTC ENDP ;****************************************************** ;Name: CK_UD_STAT ;Entry: called ;Input: none ;Output: if ok to update ; al=0 ; CLI in effect ; else ; al <>0 ; STI in effect ;Description: ;ck_ud_stat will: ;1. wait for no update in progress and return al == 0save environment ;2. reset the alarm mode on system clock ;3. restore environment ;4. return to Time_day_start ;****************************************************** CK_UD_STAT PROC NEAR PUSH CX MOV CX,WAITCPU_CK_UD_STAT ; timeout value ALIGN 4 CK_UD_LOOP: CLI ; stop interrupts ; while accessing CMOS MOV AL,0Ah NMI_ON OUT CMOS,AL NEWIODELAY IN AL,CMOS+1 AND AL,80H ; TEST FOR UPDATE IN PROGRESS ;R20A - start ifdef ICH ;Double check the UIP status to avoid the glitch of ICH B0 stepping jnz short StillInUIP mov al,0Ah NMI_ON out CMOS,al NEWIODELAY in al,CMOS+1 and AL,80H ; TEST FOR UPDATE IN PROGRESS StillInUIP: endif; ICH ;R20A - end JZ SHORT CK_UD_EXIT STI ; allow interrupts. LOOP SHORT CK_UD_LOOP MOV AL,80H ; indicate timeout. CK_UD_EXIT: POP CX RET CK_UD_STAT ENDP PAGE ;**************************************** ;* * ;* INT 8 - TIME TICK OFF 8254 * ;* * ;**************************************** ALIGN 4 PUBLIC T_S T_S: STI PUSH DS ; some app. programs that use ; 1CH as timer ticks PUSH SI ; require that DS,AX,DX are ; saved at time of 1CH MOV SI,G_RAM ; so have to (see below) MOV DS,SI ASSUME DS:G_RAM MOV SI,OFFSET LOW_8254_CNT ; address them ifndef NO_Y2K_CHECK ;R20 ifdef PATCH_WILLIT_YEAR2000 ;Force year to 20XXH if the year in CMOS is smaller than 1980H. It's used ;to fix Year 2000 test program - WILLIT.EXE, This program set RTC to 23:59:59 ;12/31/1999 and wait BIOS to set the century to 20. cli pushad ;Save PCI index register mov dx,0cf8h in eax,dx push eax ;Save RTC/CMOS index register , it depends on chipset implemention ;due to standard RTC/CMOS not accessable for RTC index ;R19D extrn Ct_Save_RTC_Index:near ;R19D call Ct_Save_RTC_Index ;R19D push ax ;R19D ;R19D test byte ptr [si],1111b ;every 16x56ms ;R19D jnz short NoChkCentury ;R19D - start test byte ptr [si],1111b ;every 16x56ms jnz short NoChkCentury1 extrn Ct_Save_RTC_Index:near call Ct_Save_RTC_Index push ax ;R19D - end mov al,32h NMI_ON ;read century value call Get_Cmos cmp al,19H ;19th ? jne short NoChkCentury ;the CMOS RTC is invalid if the "update in progress" is set. mov al,0AH NMI_ON ;update in progress ? call Get_Cmos test al,80H ;yes, jnz short NoChkCentury ;skip year 2000 checking mov al,09H NMI_ON ;read year value call Get_Cmos cmp al,80H ;before 2080H ? jae short NoChkCentury mov ah,20H ;force century to 20xx. mov al,32h NMI_ON ;write new century value call Set_Cmos NoChkCentury: ;restore CMOS index register pop ax out 70h,al NoChkCentury1: ;R19D ;restore PCI index register pop eax mov dx,0cf8h out dx,eax popad sti endif; PATCH_WILLIT_YEAR2000 endif ;NO_Y2K_CHECK ;R20 ADD WORD PTR [SI],1 ADC WORD PTR [SI+2],0 CMP WORD PTR [SI+2],18H ; see if next day JNE SHORT T3 CMP WORD PTR [SI],0B0H JNE SHORT T3 MOV WORD PTR [SI],0 ; clear time and set overflow MOV WORD PTR [SI+2],0 MOV BYTE PTR [SI+4],1 T3: POP SI ; recover si PUSH AX PUSH DX ; diskette time out check cmp BYTE PTR DS:[MOTOR_OFF_WAIT],0 je SHORT T4 DEC BYTE PTR DS:[MOTOR_OFF_WAIT] JNZ SHORT T4 AND BYTE PTR DS:[MOTOR_ON_IND],0F0H ; drive run flags MOV DX,3F2H ; and kill controller MOV AL,0CH OUT DX,AL T4: INT 1CH ; do user timer tick call Turbo_Pin_Hdlr call Int8_Hook ; special process (chipset dependent) CLI ; stop interrupts before iret - V3.00 MOV AL,END_OF_INT ; CLEAR 8259 OUT A8259,AL ; and clear interrupt POP DX POP AX POP DS IRET PAGE ;**************************************** ;* * ;* PROGRAMMED INTERUPT ON CMOS CLOCK * ;* INT 70H * ;**************************************** PUBLIC PIE_AIE_HDLR PIE_AIE_HDLR PROC FAR PUSH AX MOV AL,0BH NMI_ON CALL GET_CMOS TEST AL,60H ; SEE IF AIE OR PIE WAS ENABLED jz short Safe_Return ; read register C to clear ; interrupt flag TRUE_INT: MOV AL,0CH NMI_ON CALL GET_CMOS ; NOW SEE WHICH ONE CAUSED INT TEST AL,60h JZ SHORT END_CLK_INT TEST AL,20H ; CHECK FOR AI JZ SHORT CK_PI ; IF NOT GO CK FOR PI PUSH AX INT 4AH ; CALL USER ROUTINE POP AX CK_PI: TEST AL,40H ; CK FOR PI JZ SHORT SAFE_RETURN PUSH DS PUSH SI MOV SI,G_RAM ; address segment MOV DS,SI ASSUME DS:G_RAM MOV SI,OFFSET REQUESTER_FLG_OFFSET ; get offset - V2.07 change SUB WORD PTR [SI+4],977 ; DECREMENT USERS WAIT COUNT SBB WORD PTR[SI+6],0 JNC SHORT END_CK_PI ; SEE IF EVENT WAIT IS UP ;we also have to clear the wait in use flag! mov byte ptr ds:[WAIT_IN_USE], 0 MOV AL,0BH NMI_ON CALL GET_CMOS ; IF SO DISABLE PIE and al,3fH ; mask bit 7 MOV AH,AL MOV AL,0BH NMI_ON CALL SET_CMOS LDS SI,DWORD PTR[SI] ASSUME DS:NOTHING MOV BYTE PTR [SI],80H END_CK_PI: POP SI POP DS SAFE_RETURN: MOV AL,0CH NMI_ON CALL GET_CMOS END_CLK_INT: MOV AL,END_OF_INT ; CLEAR 8259 OUT B8259,AL SIODELAY OUT A8259,AL POP AX IRET PIE_AIE_HDLR ENDP FCODE ENDS END