CLOCK.ASM
资源名称:drdossrc.zip [点击查看]
上传用户:xiaogehua
上传日期:2007-01-08
资源大小:1183k
文件大小:13k
源码类别:
操作系统开发
开发平台:
Asm
- ; File : $CLOCK.ASM$
- ;
- ; Description :
- ;
- ; Original Author : DIGITAL RESEARCH
- ;
- ; Last Edited By : $CALDERA$
- ;
- ;-----------------------------------------------------------------------;
- ; Copyright Work of Caldera, Inc. All Rights Reserved.
- ;
- ; THIS WORK IS A COPYRIGHT WORK AND CONTAINS CONFIDENTIAL,
- ; PROPRIETARY AND TRADE SECRET INFORMATION OF CALDERA, INC.
- ; ACCESS TO THIS WORK IS RESTRICTED TO (I) CALDERA, INC. EMPLOYEES
- ; WHO HAVE A NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF
- ; THEIR ASSIGNMENTS AND (II) ENTITIES OTHER THAN CALDERA, INC. WHO
- ; HAVE ACCEPTED THE CALDERA OPENDOS SOURCE LICENSE OR OTHER CALDERA LICENSE
- ; AGREEMENTS. EXCEPT UNDER THE EXPRESS TERMS OF THE CALDERA LICENSE
- ; AGREEMENT NO PART OF THIS WORK MAY BE USED, PRACTICED, PERFORMED,
- ; COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED, ABRIDGED,
- ; CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED, RECAST,
- ; TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF
- ; CALDERA, INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT
- ; AUTHORIZATION COULD SUBJECT THE PERPETRATOR TO CRIMINAL AND
- ; CIVIL LIABILITY.
- ;-----------------------------------------------------------------------;
- ;
- ; *** Current Edit History ***
- ; *** End of Current Edit History ***
- ;
- ; $Log$
- ; CLOCK.ASM 1.12 93/07/22 19:43:10
- ; switch over to REQUEST.EQU
- ; ENDLOG
- include BIOSGRPS.EQU
- include DRMACROS.EQU ; standard DR macros
- include IBMROS.EQU ; ROM BIOS equates
- include REQUEST.EQU ; request header equates
- include DRIVER.EQU ; device driver equates
- page
- CGROUP group CODE, RCODE, RESUMECODE, ICODE
- CG equ offset CGROUP
- TIME struc
- DAYS dw ?
- MINUTES db ?
- HOURS db ?
- HUNDREDTHS db ?
- SECONDS db ?
- TIME ends
- Assume CS:CGROUP, DS:CGROUP, ES:Nothing, SS:Nothing
- CODE segment 'CODE'
- extrn endbios:word ; for device driver INIT function
- extrn daycount:word
- ; There are 1193180/65536 ticks per second, or 0E90Bh/10000h ticks per 5/100th.
- CONVERSION_FACTOR equ 0E90Bh
- CODE ends
- RCODE segment 'RCODE'
- extrn DataSegment:word
- monlen db 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
- Public ClockTable
- ClockTable:
- db 9 ; Last supported function
- dw CG:dd_init ; 0-initialize driver
- dw CG:dd_error ; 1-media change check (disks only)
- dw CG:dd_error ; 2-build BPB (disks only)
- dw CG:dd_error ; 3-IOCTL string input
- dw CG:dd_input ; 4-input
- dw CG:dd_error ; 5-nondestructive input (char only)
- dw CG:dd_error ; 6-input status (char only)
- dw CG:dd_error ; 7-input flush
- dw CG:dd_output ; 8-output
- dw CG:dd_output ; 9-output with verify
- page
- driver proc near
- dd_error: ; used for all unsupported driver functions
- ;--------
- mov ax,RHS_ERROR+3 ; "invalid command" error
- ret
- dd_input: ; 4-input
- ;--------
- les di,es:RH4_BUFFER[bx] ; ES:DI -> requested date/time buffer
- call read_system_ticks ; read system tick counter
- mov ax,daycount ; AX = date
- stosw ; return date
- push dx ; save low word of ticks
- mov ax,5
- mul cx ; multiply high word of ticks by 5
- xchg ax,cx ; save result in CX
- pop dx
- mov ax,5
- mul dx ; multiply low word of tick by 5
- add dx,cx ; and add in high word
- mov bx,CONVERSION_FACTOR
- div bx ; convert to centi-secs
- push ax ; save high word of result
- xor ax,ax
- div bx ; divide remainder
- pop dx ; recover high word of result
- ; giving us time in centi-secs
- mov bx,60*100 ; BX = centi-secs/minute
- div bx ; AX = # minutes
- push dx ; save centi-secs remainder
- cwd ; DX = 0
- mov bx,60+(256*100) ; BL = minutes/hour,BH = centi-secs/sec
- div bl ; AL = hours, AH = minutes remainder
- xchg al,ah
- stosw ; return minutes then hours
- pop ax ; recover centi-secs remainder
- div bh ; AL = secs, AH = centi-secs remainder
- xchg al,ah
- stosw ; return centi-secs then secs
- sub ax,ax
- ret
- page
- dd_output: ; 8-output
- ;---------
- les si,es:RH4_BUFFER[bx]
- ; First we'll convert the date & set the RTC if present:
- mov ax,es:DAYS[si] ; # of days since 1/1/1980
- mov daycount,ax
- mov dx,1980 ; get initial year
- output1:
- mov cx,365 ; assumed year size
- test dl,3 ; test for leap years
- jnz output2 ; skip if not a leap year
- inc cx ; leap years have 366 days
- output2:
- cmp ax,cx ; more days than this year?
- jb output3 ; skip if less - same year
- sub ax,cx ; else date in future year
- inc dx ; subtract from total, next year
- jmps output1 ; check again
- output3: ; DX = binary year, AX = day in year
- sub bx,bx ; start with January
- sub cx,cx ; CH = 0
- output4:
- mov cl,cs:monlen[bx] ; CX = # of days in next month
- cmp cl,28 ; is it february ?
- jne output5
- test dl,3 ; is it a leap year ?
- jnz output5
- inc cx ; leap years have 29 days in february
- output5:
- cmp ax,cx ; remaining day count >= month length?
- jb output6 ; skip if right month found
- sub ax,cx ; else subtract days in that month
- inc bx ; move on to next month
- jmps output4 ; repeat until month found
- output6: ; DX = binary year
- inc ax ; AX = day-1 => convert to day
- inc bx ; BX = month-1 => convert to month
- mov ah,bl ; high byte is month
- call bin2bcd ; convert to month
- xchg ax,dx ; DL, DH = day, month of date
- ; AX = binary year
- mov bl,100
- div bl ; AL = century, AH = year
- xchg al,ah ; AH = century, AL = year
- call bin2bcd ; convert AL, AH from binary to BCD
- xchg ax,cx ; CL, CH = year, century for date
- mov ah,5 ; set real time clock date
- int RTC_INT ; on AT, XT-286, PS/2, etc.
- ; Now we'll convert the time & set the RTC if present
- ; mov ah,es:HOURS[si]
- ; mov al,es:MINUTES[si] ; get binary hours & minutes
- mov ax,es:word ptr MINUTES[si]
- call bin2bcd ; convert to BCD values
- xchg ax,cx ; CH, CL = hh:mm in BCD
- mov ah,es:SECONDS[si]
- mov al,0 ; get binary seconds & no daylight saving
- call bin2bcd ; convert to BCD values
- xchg ax,dx ; DH, DL = ss.000 in BCD
- mov ah,3 ; set real time clock time
- int RTC_INT ; on AT, XT-286, PS/2, etc.
- mov al,100
- mul es:SECONDS[si] ; AX = seconds in hundredths
- xchg ax,dx ; save in DX
- mov al,es:HUNDREDTHS[si]
- cbw ; AX = hundredths
- add ax,dx ; AX = secs and hundredths in 1/100ths
- cwd ; make the a dword
- mov bx,5
- div bx ; AX = secs and hundredths in 5/100ths
- xchg ax,bx ; save in BX
- mov al,60 ; convert hours into minutes
- mul es:HOURS[si] ; AX = hours in mins
- xchg ax,dx
- mov al,es:MINUTES[si]
- cbw ; AX = minutes value
- add ax,dx ; AX = hours and mins in mins
- mov dx,60*20
- mul dx ; DX:AX = hours and mins in 5/100ths
- add ax,bx
- adc dx,0 ; DX:AX = total in 5/100ths
- mov bx,CONVERSION_FACTOR ; load up our magic value
- push dx ; save high word
- mul bx ; DX = low word result
- mov cx,dx ; save for later
- pop ax ; recover high word
- mul bx ; DX:AX = result from high word
- add ax,cx ; add low and high word results
- adc dx,0 ; together in DX:AX
- xchg ax,dx ; DX = low word of result
- xchg ax,cx ; CX = high word of result
- mov ah,1 ; set system timer
- int RTC_INT ; CX = high word, DX = low word
- sub ax,ax ; return successfully when done
- ret
- Public read_system_ticks
- read_system_ticks:
- ;-----------------
- mov ah,0 ; read system tick counter
- int RTC_INT
- test al,al ; have we passed midnight ?
- jz read_st10 ; if so a new day has dawned
- inc daycount
- read_st10:
- ret
- bin2bcd: ; convert AL and AH to BCD values
- ;-------
- call bin2bcd1 ; swap AL, AH, convert to BCD
- ; call bin2bcd1
- ; ret
- bin2bcd1:
- push cx
- mov ch,ah ; save AH in scratch register
- aam ; AL = AL % 10; AH = AL/10;
- mov cl,4
- shl ah,cl ; shift tens into high nibble
- or ah,al ; combine the nibbles
- mov al,ch ; restore the high byte into low byte
- pop cx
- ret
- driver endp
- RCODE ends ; end of device driver code
- RESUMECODE segment 'RESUMECODE'
- ; If the system ROM BIOS supports RESUME mode then it will call Int 6C
- ; when returning from sleep mode. We take this over and reset the clock
- ; based upon the RTC value. To save space we only relocate the code if
- ; required.
- ;
- Public ResumeHandler
- ResumeHandler proc far
- sti
- mov ax,cs:DataSegment ; we have been asleep and are being
- mov ds,ax ; woken by the BIOS
- mov es,ax ; lets re-read the RTC before
- call set_clock ; we return to them
- clc
- ret 2
- ResumeHandler endp
- set_monlen db 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
- set_clock:
- ;---------
- ; We may also be called after a RESUME when we have to reset the time.
- mov ah,2 ; read real time clock
- xor cx,cx
- xor dx,dx ; assume it won't work
- stc
- int RTC_INT ; CH = hours, CL = mins, DH = secs
- jc set_clock40 ; (all in BCD remember)
- xchg al,dh ; AL = secs
- call bcd2bin ; AL = secs in binary
- cmp al,59
- ja set_clock40 ; reject invalid seconds
- mov ah,100
- mul ah ; AX = seconds in hundredths
- cwd ; make it a dword
- mov bx,5
- div bx ; AX = secs and hundredths in 5/100ths
- xchg ax,bx ; save in BX
- mov al,ch ; AL = hours in BCD
- call bcd2bin ; AL = hours in binary
- cmp al,23
- ja set_clock40 ; reject invalid hours
- mov ah,60 ; convert hours into minutes
- mul ah ; AX = hours in mins
- xchg ax,dx ; save in DX
- mov al,cl ; AL = mins in BCD
- call bcd2bin ; AL = mins in binary
- cmp al,59
- je set_clock40 ; reject invalid mins
- cbw ; AX = minutes value
- add ax,dx ; AX = hours and mins in mins
- mov dx,60*20
- mul dx ; DX:AX = hours and mins in 5/100ths
- add ax,bx
- adc dx,0 ; DX:AX = total in 5/100ths
- mov bx,CONVERSION_FACTOR ; load up our magic value
- push dx ; save high word
- mul bx ; DX = low word result
- mov cx,dx ; save for later
- pop ax ; recover high word
- mul bx ; DX:AX = result from high word
- add ax,cx ; add low and high word results
- adc dx,0 ; together in DX:AX
- xchg ax,dx ; DX = low word of result
- xchg ax,cx ; CX = high word of result
- mov ah,1 ; set system timer
- int RTC_INT ; CX = high word, DX = low word
- set_clock40:
- mov ah,4 ; read RTC (if present)
- int RTC_INT ; validate date - CMOS may be corrupt
- cmp cx,1980h ; Too low?
- jb set_clock45 ; Yes so skip
- cmp cx,2099h ; Too high ?
- ja set_clock45 ; Yes so skip
- cmp dx,0101h ; Too low?
- jb set_clock45 ; Yes so skip
- cmp dx,3112h ; Too high ?
- jbe set_clock50 ; No its okay so scram
- set_clock45:
- mov cx,1980h ; assume the year 1980
- mov dx,0101h ; assume 1st of January of that year
- set_clock50:
- xchg ax,cx ; AL, AH = year, century in BCD
- call bcd2bin ; convert values to binary
- xchg ax,cx
- xchg ax,dx ; AL, AH = day, month in BCD
- call bcd2bin ; convert values to binary
- xchg ax,dx
- mov daycount,0 ; zero the daycount in case of RESUME
- mov ax,19*256 + 80 ; assume 1980
- set_clock55:
- cmp ax,cx ; same year?
- je set_clock65
- mov bx,365 ; assume 365 days in that year
- test al,3 ; test for leap year
- jnz set_clock60 ; (this works til 2400 A.D.)
- inc bx ; add FEB 29 if divisible by four
- set_clock60:
- add daycount,bx ; add days in previous year to total
- inc al ; next year
- cmp al,100 ; end of century?
- jb set_clock55 ; skip if same century
- mov al,0 ; continue with XX00
- inc ah ; ...next century
- jmps set_clock55 ; check year again
- set_clock65: ; same year by now
- xchg ax,cx ; CX = year
- sub dx,0101h ; make month, day 0 relative
- sub bx,bx ; assume January
- sub ax,ax ; AH = 0
- set_clock70:
- cmp dh,bl ; does current month match?
- je set_clock80 ; skip if it does
- mov al,cs:set_monlen[bx] ; get length of that month
- cmp al,28 ; is it february ?
- jne set_clock75
- test cl,3 ; is it a leap year ?
- jnz set_clock75
- inc ax ; leap year, 29 days in february
- set_clock75:
- add daycount,ax ; add it to total day count
- inc bx ; move on to next month
- jmps set_clock70
- set_clock80:
- mov al,dl ; get days in that month
- add daycount,ax ; add them to day count
- ret
- bcd2bin:
- ;-------
- ; entry: AL, AH = BCD values
- ; AL, AH = binary equivalents
- call bcd2bin1 ; swap AL, AH, convert AL to binary
- ; call bcd2bin1 ; swap AL, AH, convert AL to binary
- ; ret
- bcd2bin1: ; convert BCD to binary
- xchg al,ah ; swap the two values
- push bx
- mov bl,0 ; start off without tens
- bcd2bin2:
- cmp al,10h ; check if more tens
- jb bcd2bin3 ; all tens done
- sub al,10h ; else subtract 10 in BCD
- add bl,10 ; ...and add it in binary
- jmps bcd2bin2 ; repeat for all tens
- bcd2bin3: ; AL = ones, BL = tens
- add al,bl ; AL = binary value
- pop bx ; restore BX
- ret
- RESUMECODE ends
- ICODE segment 'ICODE' ; initialization code
- Assume CS:CGROUP, DS:CGROUP
- dd_init: ; 0-initialize driver
- ;-------
- call set_clock ; set elapsed ticks
- les bx,REQUEST[bp] ; ES:BX -> request header
- mov ax,endbios
- mov es:RH0_RESIDENT[bx],ax ; set end of device driver
- mov es:RH0_RESIDENT+2[bx],ds
- sub ax,ax ; initialization succeeded
- ret ; (BIOS init always does...)
- ICODE ends
- end