home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / ddkx86v5.zip / DDKX86 / SRC / DEV / CLOCK / CLOCK02 / CLOCK02.ASM < prev    next >
Assembly Source File  |  1995-04-14  |  72KB  |  1,920 lines

  1. ;*DDK*************************************************************************/
  2. ;
  3. ; COPYRIGHT (C) Microsoft Corporation, 1989
  4. ; COPYRIGHT    Copyright (C) 1995 IBM Corporation
  5. ;
  6. ;    The following IBM OS/2 WARP source code is provided to you solely for
  7. ;    the purpose of assisting you in your development of OS/2 WARP device
  8. ;    drivers. You may use this code in accordance with the IBM License
  9. ;    Agreement provided in the IBM Device Driver Source Kit for OS/2. This
  10. ;    Copyright statement may not be removed.;
  11. ;*****************************************************************************/
  12. ;SCCSID = @(#)clock02.asm    6.13 91/10/22
  13. title   clock device driver -- PS/2  [clock02.asm]
  14.  
  15. ; ****************************************************************************
  16. ; *                                                                          *
  17. ; *                                                                          *
  18. ; *                                                                          *
  19. ; ****************************************************************************
  20.  
  21. PAGE    60,132
  22. ;
  23. .386p                                   ; assemble for iAPX 386
  24. .xlist
  25.  
  26. ; define MONITOR and/or MISCSTRICT to get help when debugging, these are
  27. ; NOT to be defined for a retail build.
  28. ;;MONITOR         EQU     1               ; builds in monitoring code
  29. ;;MISCSTRICT      EQU     1               ; turns on extra checking
  30.  
  31. INCL_ERRORS     EQU     1
  32.         include bseerr.inc              ; error numbers
  33. INCL_MI         EQU     1
  34.         INCLUDE mvdm.inc                ; equates and data for MVDM support
  35.         INCLUDE devhlp.inc              ; the devhlp function eqs
  36.         INCLUDE oldmaca.inc
  37.         INCLUDE infoseg.inc             ; definitions of Global Info Segment
  38.         INCLUDE devsym.inc              ; definition of DD Request Packet
  39.         INCLUDE rtc.inc                 ; Real Time Clock info
  40.         INCLUDE clkabios.inc            ; Structs for calling ABIOS
  41.         INCLUDE clkdata.inc             ; Device driver specific
  42.         INCLUDE pmode.inc
  43.         INCLUDE abios.inc
  44.         INCLUDE timer.inc               ; timer definitions
  45.         INCLUDE clkseg.inc              ; segment definitions
  46.         INCLUDE pvwxport.inc
  47.         INCLUDE vtdptd.inc              ; vtimer/ptimer interface
  48.         INCLUDE devhlpP.inc             ;76711
  49. .list
  50.  
  51. CPUMode 386
  52.  
  53.         extrn   GTDAYS:Far
  54.         extrn   FIXDAYOFWEEK:Near
  55.         extrn   ClkVDDProc:near         ; Clk router routine
  56.         extrn   PTBeep:near             ; beep service entry point
  57.         extrn   PTBeepOff:near          ; service to turn speaker off
  58.         extrn   PTVDMProc:near          ; vtimer/ptimer interface entry point
  59.         extrn   PTTimer0:near           ; timer 0 ownership arbitration serv.
  60.         extrn   selClkData:word         ; BUGBUG loader should resolve
  61.  
  62. ClkData SEGMENT
  63. ; data segment externals
  64.         extrn   DevHlp:DWORD
  65.         extrn   SchedClock:DWORD
  66.         extrn   InfSeg:DWORD
  67.         extrn   MonTab:BYTE
  68.         extrn   Update_Flag:BYTE
  69.         extrn   Post_Time:WORD
  70.         extrn   Int_Nested:BYTE
  71.         extrn   Int_In_Progress:BYTE
  72.         extrn   ATDataEnd:ABS
  73.  
  74.         extrn   ReqRTCFreq:BYTE
  75.         extrn   CurRTCFreq:BYTE
  76.         extrn   Hundred_Whole:BYTE
  77.         extrn   Hundred_Frac:BYTE
  78.         extrn   Hundred_Inc:WORD
  79.         extrn   MS_Fraction:WORD
  80.         extrn   MS_Inc_Whole:DWORD
  81.         extrn   MS_Inc_Frac:WORD
  82.         extrn   MS_Delta:WORD
  83.  
  84.         extrn   Hz128To32:BYTE
  85.         extrn   Accum8msTicks:WORD
  86.         extrn   ExpectedMsCount:DWORD
  87.  
  88. ifdef   MONITOR
  89.         extrn   LagCount:DWORD
  90.         extrn   LagTotal:DWORD
  91.  
  92.         extrn   Accm:DWORD
  93.         extrn   Accm8:WORD
  94.         extrn   Accm8p:WORD
  95.         extrn   Accm8mod4:WORD
  96.         extrn   Ticks8:DWORD
  97.         extrn   Ticks32:DWORD
  98. endif
  99.  
  100.         extrn   szClkName:byte          ; device name for PCLK registration
  101.         extrn   szTmrName:byte          ; device name for PTIMER registration
  102.         extrn   fpfnVTProc:FWORD        ; vtimer entry point
  103.         extrn   fsPTFlags:WORD          ; ptimer flags
  104.  
  105.         extrn   pqwTmrRollover:DWORD
  106.         extrn   qwTmrRollover:DWORD
  107.         extrn   pqwTmr:DWORD
  108.         extrn   qwTmr:BYTE
  109.  
  110. ;
  111. ;   Data area for calling ABIOS
  112. ; BUGBUG -- some of this can go away.  Allocate for RTINIT then destroy.
  113. ;
  114.  
  115. ABIOS_Clock_Parms   ABIOS_Parms <>      ; ABIOS Clock Info
  116.  
  117. ClockLID        DW      ?               ; ABIOS RTC Logical I.D.
  118. TaskPkt         DW      ?               ; These 4 slots are established to
  119. PeriodPkt       DW      ?               ; hold the actual offsets for each
  120. UpdatePkt       DW      ?               ; request block in the AbiosRB area
  121. ExtraPkt        DW      ?               ; 
  122. AbiosRB         DB      MAXBRB*4 dup (0)  ; ABIOS Request Block structure
  123.                                           ; Reserve space for 4 RBs here
  124.                                           ; and resize the segment at INIT time
  125. ClkData ENDS
  126.  
  127. BREAK <Realtime Clock Write Routine>
  128. ;********************** START OF SPECIFICATIONS *********************
  129. ;*
  130. ;* MODULE NAME:  RTWRIT
  131. ;*
  132. ;* DESCRIPTIVE NAME:  Realtime Clock  Write routine
  133. ;*
  134. ;* FUNCTION:   Supports the Device Driver functions:
  135. ;*             - WRITE (function 8)
  136. ;*             - WRITE WITH VERIFY (function 9)
  137. ;*      by setting the Realtime Clock device with the date/time
  138. ;*      information and updating the Global InfoSeg date/time
  139. ;*      variables accordingly.
  140. ;*
  141. ;*      DevHlp_PhysToVirt converts the real address of the data buffer
  142. ;*      in the Device Driver Request Block (PktData) to a virtual
  143. ;*      address.  DevHlp_UnPysToVirt later restores the physical
  144. ;*      memory address.
  145. ;*
  146. ;* ENTRY POINT: RTWRIT
  147. ;*    LINKAGE:  NEAR from RTENTR
  148. ;*
  149. ;* USES:  AX, DX.  Preserves others. (RU uses ES, DI)
  150. ;*
  151. ;* INPUT: (PARAMETERS)
  152. ;*      ES:BX = pointer to Request Block  (PktData)
  153. ;*      (SP+4):(SP+2) = pointer to Data Buffer
  154. ;*
  155. ;* OUTPUT: (retURNED)
  156. ;*      AX = Status word to be stored in request packet status field.
  157. ;*
  158. ;* EXIT-NORMAL:
  159. ;*    retURN CODE:      AX = BUSY and DONE
  160. ;*
  161. ;* EXIT-ERROR:
  162. ;*    retURN CODE:      AX = ERROR and DONE
  163. ;*
  164. ;* INTERNAL REFERENCES:
  165. ;*    STRUCTURES:  ABIOS Request Block
  166. ;*    ROUTINES:         calc_year_sec
  167. ;*
  168. ;* EXTERNAL REFERENCES:
  169. ;*    STRUCTURES:  Global Information Segment (SysInfoSeg)
  170. ;*    ROUTINES:         DevHlp_PhysToVirt, DevHlp_ABIOSCall,
  171. ;*                      DevHlp_UnPhysToVirt
  172. ;*********************** END OF SPECIFICATIONS **********************
  173. page
  174. ;********************** START OF PSEUDO-CODE   **********************
  175. ;
  176. ; if caller does not request 6 bytes
  177. ;   goto write_fail
  178. ; call DevHlp_PhysToVirt to convert data buffer's physical addr to
  179. ;     virtual address in ES:DI
  180. ; if DevHlp_PhysToVirt fail
  181. ;   goto write_fail
  182. ; get days since 1-1-80 from user buffer
  183. ; day_count = no of days not in 4 year groups = days % 1461
  184. ; year_count = no of years in 4 year groups = ( days / 1461 ) * 4
  185. ; if day_count > 366
  186. ;   day_count -= 366
  187. ;   year_count++
  188. ;   while ( day_count > 365 )
  189. ;      day_count -= 365
  190. ;      year_count++
  191. ;   endwhile
  192. ; endif
  193. ;
  194. ; Normalize year_count ( year_count += 80 )
  195. ; if year_count in 20xx ( year_count >= 100 )
  196. ;   year_count -= 100
  197. ;   Century = 20x
  198. ; else Century = 19x
  199. ;
  200. ; if current date in leap year
  201. ;   set Feb = 29
  202. ; else
  203. ;   set Feb = 28
  204. ;
  205. ; for month = 1 to 12
  206. ;    if day_count >= MonTab[ month ]
  207. ;       break
  208. ;    else
  209. ;       day_count -= MonTab[ month ]
  210. ; endfor
  211. ;
  212. ; day_of_week = ( days + 2 ) % 7 + 1
  213. ; convert year, month, day_count, & day_of_week to BCD
  214. ;
  215. ; get seconds, minutes, & hours from user buffer and convert them to BCD
  216. ;    save both binary and BCD values on reserved stack
  217. ; get hundredths of seconds from user buffer and save on reserved stack
  218. ; invoke ABIOSCALL to write seconds, minutes, hours, day_of_week, day_count,
  219. ;   month, & year to chip
  220. ; if ABIOSCALL fail
  221. ;   set return code = DONE+ERROR+GENERAL FAILURE
  222. ;   call DevHlp_UnPhysToVirt to get original address mode
  223. ;   enable interrupts
  224. ;   if DevHlp_UnPhysToVirt fail
  225. ;      goto write_fail
  226. ;   return
  227. ; endif
  228. ; get hundredths of seconds from user buffer and save on reserved stack
  229. ;
  230. ; call DevHlp_UnPhysToVirt to get the original address mode
  231. ; if DevHlp_UnPhysToVirt fail
  232. ;   goto write_fail
  233. ;
  234. ; call calc_year_sec to get seconds, minutes, hours, day_of_week, day_count,
  235. ;     month, year, & hundredths of seconds from reserved stack to put in
  236. ;     SysInfoSeg
  237. ; enable interrupts
  238. ; set return code = DONE+BUSY
  239. ; return
  240. ;
  241. ; write_fail:
  242. ;   set return code = DONE+ERROR+WRITE FAULT
  243. ;   return
  244. ;
  245. ;*********************** END OF PSEUDO-CODE    **********************
  246.  
  247. ClkSwap SEGMENT
  248.  
  249. century_year    equ     [bp+8]
  250. year_bin        equ     [bp+7]
  251. month_bin       equ     [bp+6]
  252. day_month_bin   equ     [bp+5]
  253. day_week_bin    equ     [bp+4]
  254. hour_bin        equ     [bp+3]
  255. minute_bin      equ     [bp+2]
  256. second_bin      equ     [bp+1]
  257. hundredth_bin   equ     [bp]
  258.  
  259.  
  260.     ASSUME      CS:ClkSwap,DS:ClkData,ES:NOTHING,SS:NOTHING
  261. RTWRIT  PROC NEAR
  262.         public  RTWRIT
  263.  
  264.         cmp     ES:[BX].IOcount,RW_BYTES        ; requesting 6 bytes ?
  265.         je      short WRITE                     ; yes, continue....
  266. WT_ERR:
  267.         mov     AX,(STDON+STERR+0ah)            ; Else, quit w/ error.
  268.         ret
  269.  
  270. WRITE:  push    BP
  271.         sub     sp,10                           ; reserved 10 bytes for clock
  272.         mov     BP,SP
  273.  
  274. ;; The addresses passed in the request packets are 32-bit physical addresses.
  275.         mov     CX,6
  276.         mov     AX,word ptr ES:[BX].IOpData+2   ; get hi word of address
  277.         mov     BX,word ptr ES:[BX].IOpData     ; get lo word of address
  278.         mov     DH,1                            ; result in ES:DI
  279.         mov     DL,DevHlp_PhysToVirt            ; call PhysToVirt
  280.         call    [DevHlp]                        ; ES:DI points to buffer
  281.         jnc     short WRITE_OK
  282.  
  283. WRITE_FAIL:
  284.         add     sp,10                   ; restore stack pointer
  285.         pop     BP
  286.         jmp     short WT_ERR
  287.  
  288. ;   get days since 1-1-80 from user buffer
  289. WRITE_OK:
  290.         mov     AX,ES:[DI]              ; Get days since 1-1-80 from buffer
  291.  
  292. ;   day_count = no of days not in 4 year groups = days % 1461
  293. ;   year_count = no of years in 4 year groups = ( days / 1461 ) * 4
  294.         mov     CX,DAYSIN4YR            ; No of days in four year group
  295.         xor     DX,DX                   ; Clear remainder word
  296.         div     CX                      ; [AX] = No of four year groups
  297.         shl     AX,1
  298.         shl     AX,1                    ; [AX] = No of years in 4 year groups
  299.         push    AX                      ; Save (Note: 120 years max/[AH] = 0)
  300.  
  301. ;   if day_count > 366
  302. ;      day_count -= 366
  303. ;      year_count++
  304. ;      while ( day_count > 365 )
  305. ;         day_count -= 365
  306. ;         year_count++
  307. ;      endwhile
  308. ;   endif
  309.         xor     CX,CX                   ; [CL] = 0 = extra year counter
  310.         mov     AX,DAYSINYR+1           ; Year zero is a leap year
  311. YRCMP:  cmp     DX,AX                   ; Is date within year zero?
  312.         jc      short INYEAR            ; Yes, don't subtract
  313.         sub     DX,AX                   ; No, sub days for this year
  314.         inc     CL                      ; Increment counter
  315.         mov     AX,DAYSINYR             ; Days in years one and two
  316.         jmp     short YRCMP             ; Loop until date in current year
  317.  
  318. ;   Normalize year_count ( year_count += 80 )
  319. ;   if year_count in 20xx ( year_count >= 100 )
  320. ;      year_count -= 100
  321. ;      Century = 20x
  322. ;   else Century = 19x
  323.  
  324. INYEAR: pop     AX                      ; Restore partial year count
  325.         push    SI                      ; Save SI
  326.         mov     SI,TaskPkt              ; DS:SI points to ABIOS task-time RB
  327.         mov     [SI].Parms.century,19H  ; Set century = 19x
  328.  
  329.         add     AL,CL                   ; add in 1 to 3 remainder years
  330.         add     AL,80                   ; Normalize for 19xx
  331.         cmp     AL,100                  ; Year in 19xx?
  332.         JB      short IS19XX            ; Yes, AL = actual year (M003)
  333.         sub     AL,100                  ; No, normalize for 20xx
  334.         mov     [SI].Parms.century,20H  ; Set century = 20x
  335.  
  336. IS19XX: mov     year_bin,al             ; save year in binary
  337.         BN2BCD                          ; Convert year to BCD
  338.         mov     [SI].Parms.year,al      ; Stuff Year in the ABIOS req blk
  339.  
  340. ;   if current date in leap year
  341. ;      set Feb = 29
  342. ;   else
  343. ;      set Feb = 28
  344.         mov     MonTab+1,28             ; Init Feb to 28 days
  345.         OR      CL,CL                   ; Current date in year zero?
  346.         JNZ     short NOINC             ; No, leave at 28
  347.         inc     MonTab+1                ; Yes, add one day for leap year
  348.  
  349. ;   for month = 1 to 12
  350. ;       if day_count >= MonTab[ month ]
  351. ;          break
  352. ;       else
  353. ;          day_count -= MonTab[ month ]
  354. ;   endfor
  355. NOINC:  mov     CL,1                    ; At least at first month in year
  356.         mov     SI,OFFSET MonTab        ; Table of days in each month
  357.         xor     AH,AH
  358.         CLD                             ; Insure increment
  359. CHECK1: LODSB                           ; Get count of days this month
  360.         cmp     DX,AX                   ; Date within this month?
  361.         jc      short FOUND             ; Yes, month is found
  362.         sub     DX,AX                   ; No, sub this month's days and...
  363.         inc     CX                      ; ...count one more month/year
  364.         jmp     SHORT CHECK1            ; Loop until month is found
  365.  
  366. FOUND:  mov     AL,CL                   ; Month number to AL
  367.         mov     month_bin,al            ; save month/binary
  368.         BN2BCD                          ; Convert to BCD
  369.         mov     SI,TaskPkt              ; DS:SI points to ABIOS task-time RB
  370.         mov     [SI].Parms.month,al     ; Stuff month in the ABIOS req blk
  371.  
  372.         inc     DL                      ; Remainder is day of month(1-31)
  373.         mov     AL,DL
  374.         mov     day_month_bin,al        ; save day of month/binary
  375.         BN2BCD                          ; Convert DOM to BCD
  376.         mov     [SI].Parms.day,al       ; Stuff DOM in the ABIOS req blk
  377.  
  378.         mov     AL,ES:[DI+5]            ; Get seconds value
  379.         mov     second_bin,al           ; save second in binary
  380.         BN2BCD                          ; Convert it
  381.         mov     [SI].Parms.seconds,AL   ; Stuff it in the ABIOS req blk
  382.  
  383.         mov     AL,ES:[DI+2]            ; Get minutes value
  384.         mov     minute_bin,al           ; save minute in binary
  385.         BN2BCD                          ; Convert it
  386.         mov     [SI].Parms.minutes,AL   ; Stuff it in the ABIOS req blk
  387.  
  388.         mov     AL,ES:[DI+3]            ; Get hours value
  389.         mov     hour_bin,al             ; save hour in binary
  390.         BN2BCD                          ; Convert it
  391.         mov     [SI].Parms.hours,AL     ; Stuff it in the ABIOS req blk
  392.         mov     [SI].Function,ABWRITTD  ; Function is Write Time/Date
  393.         mov     AX,ClockLID             ; Get LID in AX
  394.         xor     DH,DH                   ; Calling ABIOS Start Entry point
  395.  
  396.         push    DI
  397.         LEA     DI, DS:ABIOS_Clock_Parms
  398.         CallABIOS
  399.         pop     DI
  400.  
  401. ;      mov     DL,DevHlp_ABIOSCall
  402. ;      call    [DevHlp]                 ; call ABIOS to set clock
  403.         pop     SI                      ; Restore SI
  404.         jc      short ABErr1            ; Jump if carry flag set
  405.                                         ; no interrupts during InfoSeg access
  406.         mov     AL,ES:[DI+4]            ; Get hundredths of seconds
  407.         mov     hundredth_bin,al        ; save on reserved stack
  408.  
  409.         mov     DL,DevHlp_UnPhysToVirt  ; call UnPhysToVirt
  410.         call    [DevHlp]                ; original addr mode restored
  411.         jnc     short WRITE_INFOSEG
  412.         jmp     WRITE_FAIL
  413.  
  414. write_infoseg:
  415.         call    far ptr calc_year_sec   ; update sysinfoseg(interrupt disable)
  416.                                         ; es:bx=>SysInfoSeg
  417.         mov     al,hundredth_bin        ; get hundredth
  418.         mov     ES:[BX.SIS_HunTime],AL  ; Stuff it in InfoSeg field
  419.         sti                             ; enable interrupts
  420.  
  421.         mov     AX,(STDON OR STBUI)     ; No errors
  422.  
  423. WRITE_DONE:
  424.         add     sp,10                   ; restore stack pointer
  425.         pop     BP
  426.         ret
  427.  
  428. ABErr1:
  429.         mov     AX,(STDON+STERR+ERRGFAIL)  ; set error code for general failure
  430.         mov     DL,DevHlp_UnPhysToVirt  ; call UnPhysToVirt
  431.         call    [DevHlp]                ; original addr mode restored
  432.         jnc     short WRITE_DONE
  433.         jmp     WRITE_FAIL
  434. RTWRIT  ENDP
  435.  
  436. ClkSwap ENDS
  437.  
  438.  
  439. ;***LP  CLKFreq(ulFreq) - Set RTC Periodic Frequency service
  440. ;
  441. ;       CLKFreq is called by the kernel to request a new frequency at
  442. ;       which real time clock periodic "ticks" are generated. (See DCR 1345)
  443. ;       The actual reprogramming of the device is delayed until such time
  444. ;       as it can be done safely: interrupts disabled, pre-EOI, and on the
  445. ;       next 32ms tick boundary
  446. ;
  447. ;       ENTRY
  448. ;           (TOS) = ulFreq  : desired frequency in Hz.
  449. ;                             Only 32 and 128 supported.
  450. ;       EXIT
  451. ;           SUCCESS
  452. ;               (eax) = 0
  453. ;           FAILURE
  454. ;               (eax) = ERROR_INVALID_FREQUENCY
  455. ;
  456. ;       CONTEXT
  457. ;           Any (called by TomTick; see task\tom.c)
  458. ;
  459. ;       PSEUDOCODE
  460. ;           if ulFreq is 32 or 128
  461. ;              record new frequency desired; the actual change
  462. ;                will occur on the next 32ms boundary
  463. ;              return rc = no errors;
  464. ;           else
  465. ;              return rc = invalid frequency
  466. ;
  467.  
  468. ClkCode SEGMENT
  469.  
  470.         ASSUME  CS:ClkCode,DS:NOTHING,ES:NOTHING,SS:NOTHING
  471. Procedure CLKFreq,far
  472.  
  473.         .386p
  474.  
  475.         ?abase  = 8 + 2
  476.         ArgVar  ulFreq,ULONG
  477.  
  478.         EnterProc
  479.         SaveReg <ds>
  480.  
  481.         mov     ds,cs:[selClkData]
  482.         ASSUME  DS:ClkData
  483.  
  484. ; check if requested frequency is allowed
  485.         cmp     WORD PTR [ulFreq],128   ; is frequency 128Hz?
  486.         je      short clkfreq_valid     ; .. yes,  its valid
  487.         cmp     WORD PTR [ulFreq],32    ; is frequency 32Hz?
  488.         jne     short clkfreq_invalid   ; ...... no, so fail
  489.  
  490. clkfreq_valid:
  491.         mov     ax,WORD PTR [ulFreq]
  492.         mov     ReqRTCFreq,al           ; record requested new frequency
  493.         xor     eax,eax                 ; (eax)=ERROR_NONE
  494.  
  495. clkfreq_exit:
  496.         RestoreReg <ds>
  497.         ASSUME  DS:NOTHING
  498.  
  499.         LeaveProc
  500.         retfd   ?aframe
  501.  
  502. clkfreq_invalid:
  503.         mov     eax,ERROR_INVALID_FREQUENCY  ;  errors
  504.         jmp     short clkfreq_exit
  505.  
  506. EndProc CLKFreq
  507.  
  508.  
  509. BREAK <Realtime Clock Interrupt Service Routine>
  510. ;********************** START OF SPECIFICATIONS *********************
  511. ;*
  512. ;* MODULE NAME:  RTCINT
  513. ;*
  514. ;* DESCRIPTIVE NAME:  Interrupt Service routine for RT/CMOS Clock
  515. ;*
  516. ;* FUNCTION:
  517. ;*      This routine services RT/CMOS Clock interrupts, giving
  518. ;*      control to CP/DOS.  The entry point is associated with IRQ 8
  519. ;*      using the DevHlp SetIRQ function in RTINIT.  A periodic timer
  520. ;*      interrupt causes it to be invoked and the routine uses the
  521. ;*      DevHelp_SchedClock function first (before EOI) to inform
  522. ;*      CP/DOS of the timer tick and again later (after EOI) to allow
  523. ;*      SchedClock to perform any lengthy periodic operations.
  524. ;*
  525. ;*      On every update-ended interrupt, the clock device is read
  526. ;*      and the Global InfoSeg is updated with interrupts disabled.
  527. ;*
  528. ;* NOTES:
  529. ;*      Following issue of DevHlp_EOI to the Interrupt Manager (before
  530. ;*      the second SchedClock call) it is possible for this routine
  531. ;*      to be reentered.  Stack usage is kept to a minimum. Re-
  532. ;*      entrance should not cause problems, since no real processing
  533. ;*      is done by this routine after that point.
  534. ;*
  535. ;* ENTRY POINT: RTCINT
  536. ;*    LINKAGE:  FAR call by Interrupt Manager for IRQ Level = 8
  537. ;*
  538. ;* USES:  All registers.
  539. ;*
  540. ;* INPUT:  DS, Cs set up by Intmgr on call to RTCINT
  541. ;*
  542. ;* EXIT-NORMAL:         ret FAR
  543. ;*    retURN CODE:      CF = 0 if my-interrupt
  544. ;*                      CF = 1 if not-my-interrupt
  545. ;*
  546. ;* EXIT-ERROR:
  547. ;*    retURN CODE:
  548. ;*    ERROR MESSAGE:
  549. ;*
  550. ;* INTERNAL REFERENCES:
  551. ;*    STRUCTURES:  ABIOS Request Block
  552. ;*    ROUTINES:         FIXISEG
  553. ;*
  554. ;* EXTERNAL REFERENCES:
  555. ;*    STRUCTURES:  Global Information Segment (SysInfoSeg)
  556. ;*    ROUTINES:         DevHlp_SchedClock, DevHlp_ABIOSCall,
  557. ;*                      DevHlp_EOI
  558. ;*
  559. ;*********************** END OF SPECIFICATIONS **********************
  560. page
  561. ;********************** START OF PSEUDO-CODE   **********************
  562. ;
  563. ; enable interrupts
  564. ; invoke ABIOSCALL with periodic interrupt request block to
  565. ;       obtain Register C value for getting interrupt flags
  566. ; if update-ended interrupt flag set
  567. ;   update_flag = 1
  568. ; if periodic interrupt flag not set
  569. ;   goto EOI
  570. ; endif
  571. ;
  572. ; disable interrupts to keep hundredths and milliseconds in sync
  573. ; Accum8msTicks++;
  574. ; increment hundredths by time (in hundredths) since last tick
  575. ; increment millseconds by time (in milliseconds) since last tick
  576. ; if Hz128To32 (first 32hz tick since RTC programmed from 128->32hz)
  577. ;    set increments to 1/32 sec and clear Hz128To32 flag
  578. ; if pending request to reprogram RTC frequency
  579. ;    if requested RTC frequency is 128hz
  580. ;        change rtc frequency to 128hz
  581. ;        change interval to 1/128
  582. ;        clear accumulated 8ms tick counter (Accum8msTicks)
  583. ;        clear pending request to reprogram RTC frequency
  584. ;    else (requested RTC frequency is 32hz)
  585. ;        if clock is on a 32ms boundary
  586. ;            change rtc frequency to 32hz
  587. ;            change interval to zero
  588. ;            set Hz128To32 to indicate transition
  589. ;            clear pending request to reprogram RTC frequency
  590. ; enable interrupts
  591. ;
  592. ; update_flag = 0
  593. ; if previous update_flag != 0
  594. ;   call FIXISEG to read clock to update SysInfoSeg
  595. ; endif
  596. ;
  597. ; increment system time by Interval
  598. ; subtract off IntervalAdjustment
  599. ; if IntervalAdjustment wasn't 0
  600. ;   IntervalAdjustment = 0
  601. ;
  602. ; post_time += interval
  603. ;
  604. ; call SchedClock to do pre-EOI with AX = interval
  605. ; if we are nested (i.e. Int_In_Progress != 0 )
  606. ;   increment nest_count
  607. ;   goto EOI
  608. ; endif
  609. ; Int_In_Progress = 1
  610. ; call DevHlp to issue EOI
  611. ;
  612. ; nest_count = 0
  613. ; call chkINT15 to process int 15 with previous nest_count value
  614. ;
  615. ; call SchedClock to do post-EOI with AX = post_time
  616. ; Int_In_Progress = 0
  617. ;
  618. ; clear carry flag
  619. ; return
  620. ;
  621. ; EOI:
  622. ;   call DevHlp to issue EOI
  623. ;   clear carry flag
  624. ;   return
  625. ;
  626. ;*********************** END OF PSEUDO-CODE    **********************
  627.  
  628.  
  629.     ASSUME      CS:ClkCode,DS:ClkData,ES:NOTHING,SS:NOTHING
  630. RTCINT  PROC    FAR
  631.         public  RTCINT
  632.                                 ; The int mgr does a pusha
  633.         STI                     ; Enable interrupts where safe
  634. ; SERVICE INTERRUPT
  635.         mov     AX,ClockLID
  636.         mov     SI,PeriodPkt    ; use the Periodic Interrupt Request Block
  637.         mov     [SI].returnCode,retCODE_IN
  638.         mov     DH,1
  639.         LEA     DI, ds:ABIOS_Clock_Parms
  640.         CallABIOS
  641.         cmp     [si].returnCode,1       ; IF ABIOS returns "My Interrupt"
  642.         jne     EOI                     ; EXIT, not a clock device interrupt
  643.         mov     AL,[SI].Parms.C_Reg     ; Set up AL with the C Register Value
  644.  
  645. ; if update-ended interrupt flag set
  646. ;   update_flag = 1
  647. ; if periodic interrupt flag not set
  648. ;   goto EOI & return
  649. ; endif
  650.  
  651.         test    AL,UIMASK               ; Update Interrupt??
  652.         JZ      short GotPeriodic       ; NO, go process the Periodic Int.
  653.         mov     Update_Flag,1           ; Set the Update flag
  654.         test    AL,PIMASK               ; Also a periodic interrupt?
  655.         jz      EOI                     ; No, EOI and return...
  656.  
  657. ; disable interrupts to keep hundredths and milliseconds in sync
  658. ; Accum8msTicks++;
  659. ; increment hundredths by time (in hundredths) since last tick
  660. ; increment millseconds by time (in milliseconds) since last tick
  661. ; if Hz128To32 (first 32hz tick since RTC programmed from 128->32hz)
  662. ;    set increments to 1/32 sec and clear Hz128To32 flag
  663. ; if pending request to reprogram RTC frequency
  664. ;    if requested RTC frequency is 128hz
  665. ;        change rtc frequency to 128hz
  666. ;        change interval to 1/128
  667. ;        clear accumulated 8ms tick counter (Accum8msTicks)
  668. ;        clear pending request to reprogram RTC frequency
  669. ;    else (requested RTC frequency is 32hz)
  670. ;        if clock is on a 32ms boundary
  671. ;            change rtc frequency to 32hz
  672. ;            change interval to zero
  673. ;            set Hz128To32 to indicate transition
  674. ;            clear pending request to reprogram RTC frequency
  675. ; enable interrupts
  676.  
  677. GotPeriodic:
  678.  
  679.         cli     ; disable ints during update; keep everything synchronous
  680.         inc     Accum8msTicks;  ; only needed if at 128hz, but do always
  681.  
  682. ; increment hundredths by time (in hundredths) since last tick
  683.         les     BX,[InfSeg]                     ; ES:BX -> Global InfoSeg
  684.         mov     ah,BYTE PTR ES:[BX.SIS_HunTime] ; Get current hundredths
  685.         mov     al,Hundred_Frac                 ; align fraction part we keep
  686.         add     ax,Hundred_Inc                  ; add in hundredths tick inc.
  687.         mov     Hundred_Frac,al                 ; save new fractional part
  688.  
  689. ;** the following is a      to account for the case where a user sets the
  690. ;  hundredths field ahead, such that ensuing ticks will cause the
  691. ;  hundredths to exceed 100.  We prevent this condidtion.  Note that
  692. ;  this causes the 100ths to "freeze" at 99 until the next 1 second update
  693. ;  interrupt advances the seconds.  Ref: PTM 6670
  694.  
  695.         cmp     ah,100                          ; over 100?
  696.         jb      short NoOverflow                ; ..no,
  697.         mov     ah,99                           ; ..yes, DO NOT allow it > 100
  698. NoOverflow :
  699.         mov     BYTE PTR ES:[BX.SIS_HunTime],ah ; update Hundredths
  700.  
  701. ; increment millseconds by time (in milliseconds) since last tick
  702.         mov     ax,MS_Inc_Frac          ; get fraction of millisecond increment
  703.         add     MS_Fraction,ax          ; add to running millisecond fraction
  704.         mov     eax,ES:[BX.SIS_MsCount] ; get system's ms count (whole)
  705.         mov     ecx,eax                 ; save to determine actual ms delta
  706.         adc     eax,MS_Inc_Whole        ; add in the whole increment part
  707.         mov     ES:[BX.SIS_MsCount],eax ; update the system's ms count
  708.         sub     eax,ecx                 ; compute actual ms delta
  709.         mov     MS_Delta,ax             ; save delta in word
  710.  
  711.         cmp     Hz128To32,0             ; First 32hz tick after reprogramming?
  712.         je      short NoAdjust          ; .. no, increment is ok as is.
  713.         mov     Hundred_Inc,((100 SHL 8) / 32); .. yes, set increments to 1/32
  714.         mov     MS_Inc_Whole,(1000 / 32)
  715.         mov     MS_Inc_Frac,(((1000 SHL 16) / 32) AND 0FFFFh)
  716.         mov     Hz128To32,0             ; reset flag
  717.  
  718. NoAdjust:
  719.         cmp     ReqRTCFreq,0    ; pending request to change the rtc frequency?
  720.         je      rtcdone         ; .. no, done with the rtc
  721.         mov     al,ReqRTCFreq   ; Get requested rtc frequency
  722.         cmp     al,CurRTCFreq   ; Are we requesting the current frequency?
  723.         je      hzchanged       ; .. yes, don't reprogram, but mark change
  724.         cmp     al,128          ; request to change to 128hz?
  725.         je      short hz128     ; .. yes, safe to do it now
  726.                                 ; .. no, change to 32hz only on 32ms border
  727.         mov     ax,Accum8msTicks  ; get #accumulated 8ms ticks
  728.         and     ax,3            ; are we on 1/32nd tick border?
  729.         jnz     rtcdone         ; .. no, not safe to reprogram clock yet
  730.  
  731. hz32:
  732.  
  733. ; cancel old periodic interrupt
  734. ; program new periodic interrupt rate to 32hz
  735. ; set frequency to indicate 1/32nd interval
  736. ; set hundreths, milliseconds, frequency to zero
  737. ;   Increment zero time the next tick, rather than a full 1/32 interval,
  738. ;   or the rest of the 1/32 current interval remaining.
  739. ;   Experiment has shown that incrementing time
  740. ;   in this manner keeps MsCount adding up correctly
  741. ;   while changing the RTC's frequency.
  742. ;   Time will increment at 1/32 starting the tick after next
  743. ; clear frequency change request (ReqRTCFreq)
  744.  
  745. ifdef   MONITOR
  746. ; This shows how 8ms ticks accumulate.
  747. ACCM8SIZE EQU 64
  748.         mov     bx,Accum8msTicks        ; get #accumulated 8ms ticks
  749.         cmp     bx,ACCM8SIZE
  750.         jl      short inceach
  751.         inc     Accm8p
  752.         jmp     short incedone
  753. inceach:
  754.         shl     bx,1
  755.         inc     Accm8[bx]
  756.         shr     bx,1
  757. incedone:
  758.         and     bx,3                    ; ..last 1/32nd tick  (0,1,2 or 3)
  759.         shl     bx,1
  760.         inc     Accm8mod4[bx]
  761.         shr     bx,1
  762. endif
  763.  
  764.         mov     SI,PeriodPkt            ; DS:SI --> Periodic request block
  765.         mov     [SI].Function,ABCANPERI ; ready to cancel Periodic Interrupt
  766.         mov     AX,ClockLID             ; Get LID in AX
  767.         mov     dl,DevHlp_ABIOSCall
  768.         xor     DH,DH                   ; Calling ABIOS Start Entry point
  769.         call    [DevHlp]                       ; Cancel Periodic Interrupt
  770. ifdef MISCSTRICT
  771.         jnc    short cancelled32
  772.         int 3  ; cancelling the real time clock interrupt should not fail
  773. cancelled32:
  774. endif
  775.         mov     [SI].Function,ABSETPERI        ; Set Periodic Interrupt
  776.         mov     [SI].Parms.RTC_Prat2,IN032     ; rate is 32Hz
  777.         call    [DevHlp]                       ; do it
  778. ifdef MISCSTRICT
  779.         jnc    short hz32ok
  780.         int 3  ; reprogramming the real time clock should not fail
  781. hz32ok:
  782. endif
  783.         mov     CurRTCFreq,32   ; indicate new 32hz frequency
  784.         mov     Hundred_Inc,0   ; set all increments to zero..
  785.         mov     MS_Inc_Whole,0  ; .. they will be zero for the
  786.         mov     MS_Inc_Frac,0   ; .. next tick ONLY.
  787.         mov     Hz128To32,1     ; set flag to indicate 128->32hz transition
  788.         jmp     short hzchanged ; 
  789.  
  790. hz128:
  791. ; cancel old periodic interrupt
  792. ; program new periodic interrupt rate to 128hz
  793. ; set hundreths, milliseconds, frequency to indicate 1/128nd interval
  794.  
  795.         mov     SI,PeriodPkt            ; DS:SI --> Periodic request block
  796.         mov     [SI].Function,ABCANPERI ; ready to cancel Periodic Interrupt
  797.         mov     AX,ClockLID             ; Get LID in AX
  798.         mov     dl,DevHlp_ABIOSCall
  799.         xor     DH,DH                   ; Calling ABIOS Start Entry point
  800.         call    [DevHlp]                       ; Cancel Periodic Interrupt
  801. ifdef MISCSTRICT
  802.         jnc     short cancelled128
  803.         int 3   ; cancelling the real time clock interrupt should not fail
  804. cancelled128:
  805. endif
  806.         mov     [SI].Function,ABSETPERI        ; Set Periodic Interrupt
  807.         mov     [SI].Parms.RTC_Prat2,IN128     ; rate is 128Hz
  808.         call    [DevHlp]
  809. ifdef MISCSTRICT
  810.         jnc    short hz128ok
  811.         int 3  ; reprogramming the real time clock should not fail
  812. hz128ok:
  813. endif
  814.         mov     CurRTCFreq,128                 ; indicate new 128hz frequency
  815.         mov     Hundred_Inc,((100 SHL 8) / 128); set increments to 1/128
  816.         mov     MS_Inc_Whole,(1000 / 128)
  817.         mov     MS_Inc_Frac,(((1000 SHL 16) / 128) AND 0FFFFh)
  818.         mov     Accum8msTicks,0                ; start counting 7.8125ms ticks
  819.  
  820. hzchanged:
  821.         mov     ReqRTCFreq,0    ; clear frequency change request indicator
  822.  
  823. rtcdone:
  824.         sti                     ; enable, all timer counts updated
  825.  
  826. ;*************** Do not change FIXISEG and post_time sequence *********
  827. ; Determine if there was an Update Int that occured previously
  828. ;          and needs handling now.
  829.  
  830.         xor     al,al
  831.         xchg    al,Update_Flag          ; set update_flag = 0
  832.         or      al,al                   ; Was there an update interrupt?
  833.         je      short Continue          ; No.
  834.  
  835. ; This driver makes every effort to program the clock to 128hz ONLY within
  836. ; the first 7.8125ms after a full 32hz tick.  This is required in order for
  837. ; increments of the running millisecond counter to stay accurate.  In
  838. ; (hopefully rare) cases, higher priority interrupt activity may prevent
  839. ; the clock from being reprogrammed to 128hz within the 7.8125ms window.
  840. ;
  841. ; When the clock is programmed from 32hz to 128hz, system time will
  842. ; increment at 7.8125ms starting the next tick.  In the worst case, up to
  843. ; 31.25ms of real time may have passed just prior to the reprogramming.
  844. ; This can result in up to 24ms of time being "lost".  We attempt to limit
  845. ; the accumulation of this "lost time" within a one second period to no
  846. ; more than 32ms.  We predict what the MSCount should be one second from
  847. ; now.  If it is more than 32ms less, we make a correction.  This also
  848. ; helps keep the MsCount accurate in the event of missed periodic
  849. ; interrupts.
  850. ;
  851. ; It is possible that the independent one-second interrupt arrived just
  852. ; before the last 32hz periodic interrupt.  In that case, the time will be
  853. ; 32ms short of one second.  That is allowed.  But if the time accumulation
  854. ; is more than 32ms short, we assume either periodic interrupt(s) were missed
  855. ; or several reprogrammings of the clock frequency resulted in more than
  856. ; 32ms of "lost time".  In this case, we adjust the running millisecond
  857. ; count to our previously predicted value.  This limits the loss to 32ms.
  858.  
  859.         mov     eax,ExpectedMsCount     ; recall expected millisecond count
  860.         mov     ecx,ES:[BX.SIS_MsCount] ; get the real MsCount
  861.         sub     eax,ecx                 ; Did the real MsCount fall behind?
  862.         jle     short NotLagging        ; .. No, continue
  863.         add     ecx,eax                 ; .. Yes, MsCount should be this
  864.         mov     ES:[BX.SIS_MsCount],ecx ; bring it up to speed
  865.         add     MS_Delta,ax             ; This contributes to the delta
  866. ifdef   MONITOR
  867.         add     LagTotal,eax            ; it is nice to know these values..
  868.         inc     LagCount                ; .. to observe timing dynamics.
  869. endif
  870.  
  871. NotLagging:
  872.         add     ecx,968                 ; We expect at least 1000-32ms to pass
  873.         mov     ExpectedMsCount,ecx     ; save for next time
  874.  
  875.         push    cx
  876.         mov     cx,1                    ; only read clock once
  877.         call    FIXISEG                 ; Read clock and update Infoseg
  878.         pop     cx
  879.  
  880. Continue:
  881.         mov     ax,MS_Delta             ; get number of milliseconds transpired
  882.         add     Post_Time,ax            ; Post = n * Pre
  883. ;*************** end of sequence problem ************************
  884.  
  885.         push    DS
  886.         les     BX,SchedClock
  887.         xor     DH,DH                   ; DH=0 to indicate pre-EOI
  888.         call    DWORD PTR ES:[BX]       ; call timer tick routine
  889.         pop     DS
  890.  
  891. ;here we test for nested int or not.  if we are already nested, we issue
  892. ;the EOI disabled and return without doing any Post_EOI processing
  893.  
  894.         mov     AL,1
  895.         XCHG    Int_In_Progress,AL      ; set to nested
  896.         OR      AL,AL                   ; are we nested?
  897.         jz      short Not_Nest          ; if ZR, we are not
  898.         inc     Int_Nested              ; bump nested counter
  899.         jmp     SHORT EOI               ; end of interrupt
  900.  
  901. ;we are here if we are in a first level Int handler, we have to account
  902. ;for any nesting that may have occured after the EOI
  903.  
  904. Not_Nest:                               ; we are first level
  905.  ;      mov     AL,RTCIRQ               ; interrupt level = 8   Remove  76711
  906.  ;      mov     DL,DevHlp_EOI                                   Remove  76711
  907.  ;      call    [DevHlp]                ; call the EOI devhlp   Remove  76711
  908.         DevEOI  <RTCIRQ>,DevHlp         ;                       add     76711
  909.  
  910. ; call SchedClock to do post-EOI with AX = post_time
  911.         mov     DH,01H                  ; DH=1 to indicate post-EOI
  912.  
  913.         push    DS
  914.         les     BX,SchedClock
  915.         xor     ax,ax
  916.         xchg    ax,Post_Time            ; zero out for possible nests
  917.  
  918. ; Input: AX = # of ms to catch up on, same as Pre if no nesting
  919.         call    DWORD PTR ES:[BX]       ; call timer tick routine
  920.         pop     DS
  921.  
  922. ; reset all variables used to check for nesting
  923.         cli
  924.         mov     Int_In_Progress,0       ; clear nested flag
  925.         jmp     SHORT LOC_retN
  926.  
  927. EOI:
  928.         cli
  929.   ;     mov     AL,RTCIRQ               ; do EOI. (Interrupt level = 8)  remove 76711
  930.   ;     mov     DL,DevHlp_EOI                           remove 76711
  931.   ;     call    [DevHlp]                                remove 76711
  932.         DevEOI  <RTCIRQ>,DevHlp         ;               add     76711
  933. LOC_retN:
  934.         CLC
  935.         ret
  936. RTCINT  ENDP
  937.  
  938.  
  939. BREAK <Routine to Update the Global InfoSeg>
  940. ;********************** START OF SPECIFICATIONS *********************
  941. ;*
  942. ;* MODULE NAME:  FIXISEG
  943. ;*
  944. ;* DESCRIPTIVE NAME: Routine to read the RT/CMOS clock and then
  945. ;*      update the Global InfoSeg date/time variables.
  946. ;*
  947. ;* FUNCTION:
  948. ;*      Performs a read request to the Realtime Clock device
  949. ;*      and then updates the global InfoSeg time/date information.
  950. ;*
  951. ;* NOTES:
  952. ;*      This routine is called by three routines of the clock
  953. ;*      device driver.  RTINIT (initialization) and RTCINT (interrupt
  954. ;*      handler) use this routine to initialize and update InfoSeg
  955. ;*      respectively.
  956. ;*
  957. ;*      Time is reduced to seconds and preserved for later adding
  958. ;*      into secs since 1-1-70.
  959. ;*
  960. ;* ENTRY POINT: FIXISEG
  961. ;*    LINKAGE:  Near (from RTINIT, RTCINT)
  962. ;*
  963. ;* USES:  Preserves all registers except AX
  964. ;*
  965. ;* INPUT: CX = # OF retRY COUNT
  966. ;*
  967. ;* OUTPUT: (retURNED)
  968. ;*      No interrupt flag modified
  969. ;*      Global InfoSeg time/date data is filled in.
  970. ;*      AX = status flag is set, CARRY FLAG indicates success
  971. ;*
  972. ;* EXIT-NORMAL:
  973. ;*      CF is cleared
  974. ;*
  975. ;* EXIT-ERROR:
  976. ;*      AX = STATUS word:  DONE, ERROR + DEVICE NOT READY bits set
  977. ;*      CF is set
  978. ;*
  979. ;* INTERNAL REFERENCES:
  980. ;*    STRUCTURES:  none
  981. ;*    ROUTINES:  cmos_popf, calc_year_sec
  982. ;*
  983. ;* EXTERNAL REFERENCES:
  984. ;*    DATA STRUCTURES:  Global Information Segment (SysInfoSeg)
  985. ;*    ROUTINES:  none
  986. ;*
  987. ;*********************** END OF SPECIFICATIONS **********************
  988. page
  989. ;********************** START OF PSEUDO-CODE   **********************
  990. ;
  991. ; for try_count = 1 to MAXTRIES
  992. ;    call ABIOS to read the clock
  993. ;    if ABIOS error
  994. ;       set return code DONE+ERROR+GENERAL FAILURE
  995. ;       set carry flag on
  996. ;       return
  997. ; endif
  998. ; endfor
  999. ;
  1000. ; if try_count > MAXTRIES
  1001. ;   set return code DONE+ERROR+DEVICE NOT READY
  1002. ;   set carry flag on
  1003. ;   return
  1004. ; endif
  1005. ;
  1006. ; call ABIOS to read seconds, minutes, hours, years,
  1007. ;     day of month, & months from chip
  1008. ; convert seconds, minutes, hours, years, day of month, & months to BCD
  1009. ;
  1010. ; call calc_year_sec to update sysinfoseg
  1011. ; hundredth_count_timer = 0
  1012. ; HunTime = 0
  1013. ; restore interrupt flag
  1014. ; return
  1015. ;
  1016. ;*********************** END OF PSEUDO-CODE    **********************
  1017.  
  1018.     ASSUME      CS:ClkCode,DS:ClkData,ES:NOTHING,SS:NOTHING
  1019. FIXISEG PROC    NEAR
  1020.         public  FIXISEG
  1021.         SaveReg <AX,BX,SI,ES>
  1022.                                         ; (begin)
  1023. ;*  MAXTRIES is declared as 200, constant for ABIOS driver.  Until 387
  1024. ;  (12 MHz) is available.
  1025. ;
  1026.         mov     SI,TaskPkt              ; DS:SI --> TaskTime ReqBlk
  1027.         mov     [SI].Function,ABREADTD  ; Function is Read Time/Date
  1028.         xor     DH,DH                   ; Calling ABIOS Start
  1029. ;      mov     DL,DevHlp_ABIOSCall     ; Read the clock
  1030.         LEA     DI, DS:ABIOS_Clock_Parms
  1031.         mov     AX,ClockLID
  1032. CHKAGN:                                 ; LOOP while abios not ready
  1033.         mov     [SI].returnCode,retCODE_IN
  1034.  
  1035.         CallABIOS
  1036. ;      call    [DevHlp]
  1037.         jnc     short ABiosOk2          ; IF ABIOS error
  1038.         mov     AX,(STDON+STERR+ERRGFAIL) ; set error code for gen failure
  1039.         jmp     goback                  ; carry already set
  1040.  
  1041. AbiosOk2:                               ; ELSE
  1042.         cmp     [SI].returnCode,0       ; IF ABIOS returns 'done'
  1043.         JZ      short FIS2              ;  THEN continue
  1044.         LOOP    CHKAGN                  ;  ELSE try again
  1045.  
  1046. ; if try_count > MAXTRIES
  1047. ;   set return code DONE+ERROR+DEVICE NOT READY
  1048. ;   set carry flag on
  1049. ;   return
  1050. ; endif
  1051. ;
  1052.         STC                             ; IF no success THEN set carry
  1053.         mov     AX,(STDON+STERR+ERRDNR) ; set error code for device not ready
  1054.         jmp     short goback            ; abort clock
  1055.  
  1056. FIS2:   push    bp
  1057.         sub     sp,10                   ; reserved for clock information
  1058.         mov     bp,sp
  1059.  
  1060. ; call ABIOS to read seconds, minutes, hours, years,
  1061. ;     day of month, & months from chip
  1062. ; convert seconds, minutes, hours, years, day of month, & months to BCD
  1063. ;*               +-------------+
  1064. ;*               |  old  BP    |
  1065. ;*               +-------------+
  1066. ;*         BP+8->| ???         |
  1067. ;*               +-------------+
  1068. ;*         BP+7->| YEAR        |
  1069. ;*               +-------------+
  1070. ;*         BP+6->| MONTH       |
  1071. ;*               +-------------+
  1072. ;*         BP+5->| DAY OF MONTH|
  1073. ;*               +-------------+
  1074. ;*         BP+4->| DAY OF week |
  1075. ;*               +-------------+
  1076. ;*         BP+3->| hour        |
  1077. ;*               +-------------+
  1078. ;*         BP+2->| minute      |
  1079. ;*               +-------------+
  1080. ;*         BP+1->| second      |
  1081. ;*               +-------------+
  1082. ;*         BP  ->| hundredth   |
  1083. ;*               +-------------+
  1084.  
  1085.         mov     AL,[SI].Parms.Seconds   ; get seconds
  1086.         BCD2BN                          ; Convert it
  1087.         mov     second_bin,al           ; Stuff it in table
  1088.  
  1089.         mov     AL,[SI].Parms.Minutes   ; get minutes
  1090.         BCD2BN
  1091.         mov     minute_bin,al           ; Stuff it in table
  1092.  
  1093.         mov     AL,[SI].Parms.Hours     ; get hours
  1094.         BCD2BN
  1095.         mov     hour_bin,al             ; Stuff it in table
  1096.  
  1097.         mov     AL,[SI].Parms.Day       ; get day of month
  1098.         BCD2BN
  1099.         mov     day_month_bin,al
  1100.  
  1101.         mov     AL,[SI].Parms.Month     ; get month
  1102.         BCD2BN
  1103.         mov     month_bin,al
  1104.  
  1105.         mov     AL,[SI].Parms.Year      ; get year
  1106.         BCD2BN
  1107.         mov     year_bin,al
  1108.  
  1109.         pushf                           ; save interrupt flag
  1110.  
  1111. ;       call    far ptr calc_year_sec   ; AX:DX=seconds from 1-1-1970
  1112.         push    cs                      ; do FARCALLTRANSLATION
  1113.         call    near ptr calc_year_sec  ; AX:DX=seconds from 1-1-1970
  1114.  
  1115.         mov     ES:[BX.SIS_HunTime],00H
  1116.         push    cs
  1117.         call    cmos_popf               ; restore interrupt flag
  1118.         add     sp,10                   ; restore local stack
  1119.         pop     bp
  1120.         CLC
  1121.  
  1122. GOBACK: RestoreReg <ES,SI,BX,AX>
  1123.         ret                             ; return AX
  1124. FIXISEG ENDP
  1125.  
  1126.  
  1127. ;********************** START OF SPECIFICATIONS *********************
  1128. ;*
  1129. ;* MODULE NAME:  calc_year_sec
  1130. ;*
  1131. ;* DESCRIPTIVE NAME: Calculate total seconds and current year
  1132. ;*
  1133. ;* FUNCTION:
  1134. ;*      Calculate the total seconds from 1-1-1970, and get the
  1135. ;*      current year in century year, e.g., 1987.
  1136. ;*
  1137. ;* NOTES:
  1138. ;*      This routine is called by three routines of the clock
  1139. ;*      device driver.  FIXISEG initializes and updates InfoSeg.
  1140. ;*      The RTWRIT sub-module uses it to update
  1141. ;*      InfoSeg following a resetting of the Realtime Clock device.
  1142. ;*
  1143. ;*      Time is reduced to seconds and preserved for later adding
  1144. ;*      into secs since 1-1-70.
  1145. ;*
  1146. ;* ENTRY POINT: calc_year_sec
  1147. ;*    LINKAGE:  Far (from FIXISEG, RTWRIT)
  1148. ;*
  1149. ;* USES:  Preserves all registers except AX, ES, BX
  1150. ;*
  1151. ;* INPUT:
  1152. ;*               +-------------+
  1153. ;*               |  old  BP    |
  1154. ;*               +-------------+
  1155. ;*         BP+8->| ???         |
  1156. ;*               +-------------+
  1157. ;*         BP+7->| YEAR        |
  1158. ;*               +-------------+
  1159. ;*         BP+6->| MONTH       |
  1160. ;*               +-------------+
  1161. ;*         BP+5->| DAY OF MONTH|
  1162. ;*               +-------------+
  1163. ;*         BP+4->| DAY OF week |
  1164. ;*               +-------------+
  1165. ;*         BP+3->| hour        |
  1166. ;*               +-------------+
  1167. ;*         BP+2->| minute      |
  1168. ;*               +-------------+
  1169. ;*         BP+1->| second      |
  1170. ;*               +-------------+
  1171. ;*         BP  ->| hundredth   |
  1172. ;*               +-------------+
  1173. ;*
  1174. ;* OUTPUT: (retURNED)
  1175. ;*      ES:BX = address of SysInfoSeg
  1176. ;*      Global InfoSeg time/date data is filled in.
  1177. ;*      Interrupt Disabled.
  1178. ;*
  1179. ;* EXIT-NORMAL:
  1180. ;*
  1181. ;* EXIT-ERROR:
  1182. ;*
  1183. ;* INTERNAL REFERENCES:
  1184. ;*    STRUCTURES:  none
  1185. ;*    ROUTINES:  FixDayOfWeek, GTDAYS
  1186. ;*
  1187. ;* EXTERNAL REFERENCES:
  1188. ;*    DATA STRUCTURES:
  1189. ;*    ROUTINES:  none
  1190. ;*
  1191. ;*********************** END OF SPECIFICATIONS **********************
  1192. page
  1193. ;********************** START OF PSEUDO-CODE   **********************
  1194. ;
  1195. ; if hours > 12
  1196. ;   factor = 1
  1197. ;   hours -= 12
  1198. ; else
  1199. ;   factor = 0
  1200. ; total_seconds = seconds + minutes * 60 + hours * 3600
  1201. ;
  1202. ; if year > 99 or month > 12 or month = 0 or Day_of_Month = 0 or
  1203. ;   Day_of_Month > 31
  1204. ;   set year = 80
  1205. ;   set date = 1-1
  1206. ;   set Day_of_Week = 2
  1207. ; endif
  1208. ; if year is over 20 centry ( year < 80 )
  1209. ;   year += 100
  1210. ; year += 1900
  1211. ; save year in century_year stack
  1212. ; call GTDAYS to get DAYS since 1-1-80
  1213. ; total_time from 1-1-70 =
  1214. ;     ( (DAYS+# of days from 1-1-70 to 12-31-79) * # of 12 hours in a day +
  1215. ;      factor ) * seconds in 12 hours + total_seconds
  1216. ; disable interrupts
  1217. ; save all the information in SysInfoSeg
  1218. ; return
  1219. ;
  1220. ;*********************** END OF PSEUDO-CODE    **********************
  1221.  
  1222. calc_year_sec PROC    FAR
  1223.     ASSUME      CS:ClkCode,DS:ClkData,ES:NOTHING,SS:NOTHING
  1224.  
  1225.         SaveReg <CX,DX,SI,DI>
  1226.                                         ; (begin)
  1227. ; if hours > 12
  1228. ;   factor = 1
  1229. ;   hours -= 12
  1230. ; else
  1231. ;   factor = 0
  1232. ; total_seconds = seconds + minutes * 60 + hours * 3600
  1233. ; read Day_of_Month, month, & year from chip
  1234.         mov     al,second_bin           ; get seconds
  1235.         xor     AH,AH
  1236.         mov     SI,AX                   ; Save sec's
  1237.  
  1238.         mov     al,minute_bin           ; get minutes
  1239.         mov     CL,60                   ; secs/min
  1240.         mul     CL
  1241.         add     SI,AX                   ; SI = secs in mins and secs
  1242.  
  1243.         xor     AH,AH
  1244.         mov     AL,hour_bin             ; get hours
  1245.         xor     CX,CX                   ; ch=day of week; cl=factor
  1246.         cmp     AL,12                   ; >12 hours?
  1247.         jbe     short calc10            ; (M003)
  1248.         sub     AL,12
  1249.         inc     cl                      ; add factor = 1
  1250.  
  1251. calc10: push    CX
  1252.         mov     CX,3600
  1253.         mul     CX                      ; AX = secs in hrs remainder
  1254.         pop     CX
  1255.         add     SI,AX                   ; SI = secs in 12 hr time
  1256.  
  1257. ; Here we do a VERY rough bounds check on the Year, Month, Day and DOW
  1258. ;
  1259. ; if year > 99 or month > 12 or month = 0 or Day_of_Month = 0 or
  1260. ;   Day_of_Month > 31
  1261. ;   set year = 80
  1262. ;   set date = 1-1
  1263. ;   set Day_of_Week = 2
  1264. ;
  1265.         mov     dh,month_bin
  1266.         mov     dl,day_month_bin
  1267.         mov     AL,year_bin             ; get year
  1268.  
  1269.         cmp     AL,99                   ; Year > 99?
  1270.         ja      short DATERR
  1271.         OR      DH,DH                   ; Month = 0?
  1272.         JZ      short DATERR
  1273.         cmp     DH,12                   ; Month > 12?
  1274.         ja      short DATERR
  1275.         OR      DL,DL                   ; Day = 0?
  1276.         JZ      short DATERR
  1277.         cmp     DL,31                   ; Day > 31?
  1278.         JLE     short DATEOK
  1279.  
  1280. DATERR: mov     AL,80
  1281.         mov     DH,1
  1282.         mov     DL,1                    ; Setup for 1-1-80 if     date in RTC
  1283.         mov     CH,2                    ; 1-1-80 was a Tuesday (M003)
  1284.         mov     month_bin,dh
  1285.         mov     day_month_bin,dl
  1286.         mov     year_bin,al
  1287.  
  1288. DATEOK:
  1289. ; if year is over 20 centry ( year < 80 )
  1290. ;   year += 100
  1291.         xor     AH,AH                   ; AX = LOWER PART OF YEAR
  1292.         cmp     AL,80                   ; Is it 20xx?
  1293.         JGE     short calc20            ; No, add only 1900
  1294.         add     AX,100                  ; Yes, add extra 100
  1295.  
  1296. ; year += 1900
  1297. ; save on stack
  1298. calc20: add     AX,1900                 ; AX = Year and century
  1299.         mov     century_year,ax         ; 
  1300.         sub     AX,1980                 ; Get years since 1980
  1301.  
  1302. ; call GTDAYS to get DAYS since 1-1-80
  1303. ;* INPUT:     AX = Years since 1-1-80
  1304. ;*            DH = Current month
  1305. ;*            DL = Current day
  1306.         call    GTDAYS                  ; AX=Get days since 1-1-80
  1307.  
  1308. ; if Day_of_Week != 2
  1309. ;   call FixDayOfWeek to get Day_of_Week
  1310. ;
  1311.         OR      CH,CH                   ; Is day_of_week correct?
  1312.         JNZ     short CENT20            ; Yes, jump
  1313.         call    FixDayOfWeek
  1314.         mov     day_week_bin,ch         ; save on stack
  1315.  
  1316. CENT20:
  1317. ; total_time from 1-1-70 =
  1318. ;     ( (DAYS+# of days from 1-1-70 to 12-31-79) * # of 12 hours in a day +
  1319. ;      factor ) * seconds in 12 hours + total_seconds
  1320.         xor     BX,BX                   ; Clear it
  1321.         add     AX,DAYS1                ; add in days 1-1-70 thru 12-31-79
  1322.         shl     AX,1                    ; AX = # of 12 hour segments
  1323.         rcl     bl,1                    ; Save overflow (carry) in bl
  1324.         xor     ch,ch                   ; CX = add factor (0/1)
  1325.         add     ax,cx                   ; AX=Low 16 bits of 12 hour segments
  1326.         mov     CX,SECP12               ; CX = Seconds in 12 hours
  1327.         mul     CX                      ; [DXAX] = Secs in Low 16 bits of segs
  1328.         shr     bl,1                    ; Any beyond Low 16 bits?
  1329.         jnc     short calc30            ; No, [DXAX] = Total seconds
  1330.  
  1331.         add     dx,cx                   ; Yes, fudge bit 17 multiply
  1332. calc30: add     ax,si                   ; add in secs in current time
  1333.         adc     dx,0                    ; ...and any carry
  1334.  
  1335.         les     BX,[InfSeg]             ; ES:BX -> InfoSeg
  1336.         cli                             ; disable interrupts
  1337.         mov     WORD PTR ES:[BX.SIS_BigTime],AX
  1338.         mov     WORD PTR ES:[BX.SIS_BigTime+2],DX
  1339.         mov     al,second_bin           ; get seconds
  1340.         mov     ES:[BX.SIS_SecTime],AL  ; Stuff it in table
  1341.         mov     al,minute_bin           ; get minutes
  1342.         mov     ES:[BX.SIS_MinTime],AL
  1343.         mov     al,hour_bin             ; get hour
  1344.         mov     ES:[BX.SIS_HrsTime],AL  ; InfoSeg time is complete
  1345.         mov     al,day_month_bin        ; get day of month
  1346.         mov     ES:[BX.SIS_DayDate],al
  1347.         mov     al,month_bin            ; get month
  1348.         mov     ES:[BX.SIS_MonDate],al
  1349.         mov     al,day_week_bin         ; get day of week
  1350.         mov     ES:[BX.SIS_DOWDate],al  ; save the day (DOW)
  1351.         mov     ax,century_year
  1352.         mov     ES:[BX.SIS_YrsDate],AX  ; InfoSeg date is complete
  1353.  
  1354.         RestoreReg <DI,SI,DX,CX>
  1355.         ret
  1356. calc_year_sec ENDP
  1357.  
  1358. ; restore interrupt flag
  1359. CMOS_POPF       PROC
  1360.                 Iret                    ; RESTORE FLAGS
  1361. CMOS_POPF       ENDP
  1362.  
  1363.  
  1364. ;***LP  PTInt - Timer 0 Interrupt Handler
  1365. ;
  1366. ;      ENTRY
  1367. ;          ds -> ClkData (interrupt manager guarantee this)
  1368. ;
  1369. ;      EXIT
  1370. ;          carry flag clear
  1371. ;
  1372. ;      USES
  1373. ;          All
  1374. ;
  1375. ;      CONTEXT
  1376. ;          Interrupt
  1377. ;
  1378. ;      PSEUDOCODE
  1379. ;          clear IRQ 0 latch;
  1380. ;          issue EOI to PIC;
  1381.  
  1382.         ASSUME  CS:ClkCode,DS:ClkData,ES:NOTHING,SS:NOTHING
  1383. Procedure PTInt,far
  1384.  
  1385. ;TMR -- Update Rollover count and Tmr value.
  1386.         SaveReg <ds>
  1387.         mov     dx,WORD PTR pqwTmr
  1388.         lds     bx,pqwTmrRollover
  1389.         ASSUME DS:NOTHING
  1390. .386p
  1391.         mov     ecx,DWORD PTR [bx].qw_ulLo      ;(ECX) = current rollover count.
  1392.         mov     eax,DWORD PTR [bx].qw_ulHi      ;Set Current rollover count =
  1393.         mov     DWORD PTR [bx].qw_ulLo,eax      ; Next rollover count.
  1394.  
  1395.         mov     bx,dx                           ;(DS:BX) -> qwTmr.
  1396.                                                 ;ASSUMES SAME DS.
  1397.         add     DWORD PTR [bx].qw_ulLo,ecx
  1398.         adc     DWORD PTR [bx].qw_ulHi,0
  1399.         jo      short pti40
  1400. CPUMode Reset
  1401.  
  1402. pti20:  RestoreReg <ds>
  1403.         ASSUME DS:ClkData
  1404.  
  1405.         test    fsPTFlags,PTF_OWNT0     ;ptimer owns T0?
  1406.         jnz     short pti30             ;YES, skip the rest
  1407.  
  1408.         test    fsPTFlags,PTF_TICKENABLE;vtimer enables tick?
  1409.         jz      short pti30             ;NO, skip the rest
  1410.  
  1411.         push    WORD PTR 0
  1412.         push    VTDCMD_TICKEVENT        ;(TOS+8)=VTDCMD_TICKEVENT
  1413.  
  1414.         .386p
  1415.         push    DWORD PTR 0             ;(TOS+4)=f16p1=0
  1416.  
  1417.         push    DWORD PTR 0             ;(TOS)=f16p2=0
  1418.  
  1419.         call    FWORD PTR fpfnVTProc
  1420.         CPUMode Reset
  1421.  
  1422. pti30:  in      al,PORT_SYSB            ;(al)=value of system control port B
  1423.         or      al,SYSB_RESETIRQ0       ;set clearIRQ0 bit
  1424.         out     PORT_SYSB,al            ;clear IRQ0 latch
  1425.  
  1426.  ;      mov     al,TIMERIRQ             ;issue EOI to PIC   Remove 76711
  1427.  ;      mov     dl,DevHlp_EOI                               Remove 76711
  1428.  ;      call    [DevHlp]                                    Remove 76711
  1429.         DevEOI  <TIMERIRQ>,DevHlp       ;                   add    76711
  1430.  
  1431.         clc
  1432.         ret
  1433.  
  1434. .386p
  1435. pti40:  mov     DWORD PTR [bx].qw_ulLo,QW_MAX_LO
  1436.         mov     DWORD PTR [bx].qw_ulHi,QW_MAX_HI
  1437.         jmp     short pti20
  1438. CPUMode Reset
  1439.  
  1440. EndProc PTInt
  1441.  
  1442. ;***LP  RTINIT2 - 2nd stage init
  1443. ;
  1444. ;      FUNCTION
  1445. ;          Because RIPL with ETHERNET/PC-NET uses IRQ0, we must delay
  1446. ;          hooking IRQ0 until after loadable device drivers/IFS are
  1447. ;          installed.  The kernel will call with command 0 (loadable
  1448. ;          device driver init) when it's OK to hook IRQ 0, and this
  1449. ;          routine will be invoked.
  1450. ;
  1451. ;      ENTRY
  1452. ;          ds -> ClkData
  1453. ;
  1454. ;      EXIT
  1455. ;          carry flag clear
  1456. ;
  1457. ;      USES
  1458. ;          All
  1459. ;
  1460. ;      CONTEXT
  1461. ;          Interrupt
  1462. ;
  1463. ;      PSEUDOCODE
  1464. ;          clear IRQ 0 latch;
  1465. ;          issue EOI to PIC;
  1466.     ASSUME      CS:ClkSwap,DS:ClkData,ES:NOTHING,SS:NOTHING
  1467. RTINIT2 PROC FAR
  1468.         public  RTINIT2
  1469.  
  1470.         SaveReg <bx,cx,dx,di>
  1471.  
  1472. ;Initialize physical timer 0 to proper mode running at the rate of 18.2Hz
  1473.  
  1474.         mov     al,SC_CNT0+RW_LSBMSB+CM_MODE2
  1475.         out     PORT_CW,al              ; program count mode of timer 0
  1476.         IODelay
  1477.         xor     al,al
  1478.         out     PORT_CNT0,al            ; program timer 0 count
  1479.         IODelay                         ; count == 0h actually means 10000h
  1480.         out     PORT_CNT0,al            ; => approx. 18.2Hz
  1481.         IODelay
  1482.  
  1483. ;DevHlp(DevHlp_SetIRQ,TIMERIRQ,pfnPTInt,NO_INTSHARING)
  1484.  
  1485.         mov     ax,offset ClkCode:PTInt ; (ax)=interrupt handler offset
  1486.         mov     bx,TIMERIRQ             ; (bx)=IRQ number
  1487.         mov     dx,DevHlp_SetIRQ        ; (dh)=No interrupt sharing
  1488.         call    [DevHlp]                ; hook timer 0 interrupt
  1489.  
  1490.         RestoreReg <di,dx,cx,bx>
  1491.         mov     AX,STDON                ; Done
  1492.         ret
  1493.  
  1494. RTINIT2 ENDP
  1495.  
  1496. ClkSwap SEGMENT
  1497.  
  1498. public  endswapcode
  1499. endswapcode     label   byte
  1500.  
  1501. ClkSwap ENDS
  1502.  
  1503.  
  1504. BREAK <Realtime Clock Initialization Routine>
  1505. ;********************** START OF SPECIFICATIONS *********************
  1506. ;*
  1507. ;* MODULE NAME:  RTINIT
  1508. ;*
  1509. ;* DESCRIPTIVE NAME:  RTC Initialization Function 0
  1510. ;*
  1511. ;* FUNCTION:    Initializes data structures and the Realtime Clock
  1512. ;*              device, gets a LID for calling ABIOS.
  1513. ;*
  1514. ;* ENTRY POINT: RTINIT
  1515. ;*    LINKAGE:  FAR from RTENTR
  1516. ;*
  1517. ;* NOTES:
  1518. ;*
  1519. ;* USES:  AX, DX.  Preserves others. (RU uses CX)
  1520. ;*
  1521. ;* INPUT: (PARAMETERS)
  1522. ;*      ES:BX = pointer to Request Packet
  1523. ;*
  1524. ;* OUTPUT: (RETURNED)
  1525. ;*      No interrupt flag modified
  1526. ;*      Request Packet filled in.
  1527. ;*
  1528. ;* EXIT-NORMAL:
  1529. ;*      AX = Status flag is "DONE"
  1530. ;*
  1531. ;* EXIT-ERROR:
  1532. ;*
  1533. ;* INTERNAL REFERENCES:
  1534. ;*    STRUCTURES:  ABIOS Request Block
  1535. ;*    ROUTINES:   FIXISEG
  1536. ;*
  1537. ;* EXTERNAL REFERENCES:
  1538. ;*    STRUCTURES:  Global Information Segment (SysInfoSeg)
  1539. ;*    ROUTINES:  DevHlp_GetDOSVar, DevHlp_SetIRQ, DevHlp_ABIOSCall
  1540. ;*               DevHlp_GetLIDEntry
  1541. ;*
  1542. ;*********************** END OF SPECIFICATIONS **********************
  1543. page
  1544. ;********************** START OF PSEUDO-CODE   **********************
  1545. ;
  1546. ; set the pointer, DevHlp, to the DevHelp Router
  1547. ; call DevHlp to get the address of SysInfoSeg in ES:BX
  1548. ; if DevHlp failed
  1549. ;   goto abort
  1550. ; save the address of SysInfoSeg in InfSeg
  1551. ; call DevHlp to get the address of SchedClock in ES:BX
  1552. ; save the address of SchedClock
  1553. ;
  1554. ; call DevHlp to get the ABIOS LID for RTC
  1555. ; if DevHlp failed
  1556. ;   goto abort
  1557. ; save RTC ABIOS LID in ClockLID
  1558. ;
  1559. ; call DevHlp to get the ABIOS LID clock parameters
  1560. ; call DevHlp ABIOSCALL function start to setup task request block
  1561. ; if DevHlp failed
  1562. ;   goto abort
  1563. ; initialize the task request block, periodic request block,
  1564. ;           update-ended request block, alarm request block,
  1565. ; call DevHlp ABIOSCALL to disable old periodic interrupt
  1566. ; if DevHlp failed
  1567. ;   goto abort
  1568. ; call DevHlp ABIOSCALL to disable the update-ended interrupt
  1569. ; if DevHlp failed
  1570. ;   goto abort
  1571. ; call DevHlp ABIOSCALL to disable the alarm interrupt
  1572. ; if DevHlp failed
  1573. ;   goto abort
  1574. ; call DevHlp ABIOSCALL to set periodic interrupt to 31.25 ms
  1575. ; if DevHlp failed
  1576. ;   goto abort
  1577. ; call DevHlp ABIOSCALL to enable the update-ended interrupt
  1578. ; if DevHlp failed
  1579. ;   goto abort
  1580. ;
  1581. ; set up end of code & data segment for SysInit
  1582. ; call DevHlp to set non-sharing IRQ 8 to routine RTCINT
  1583. ; if DevHlp failed
  1584. ;   goto abort
  1585. ;
  1586. ; call FIXISEG to initialize SysInfoSeg from the data on the clock
  1587. ; if carry flag set
  1588. ;   goto abort
  1589. ;
  1590. ; call DevHlp to set int 15 to point to routine int15rtn
  1591. ; if DevHlp failed
  1592. ;   goto abort
  1593. ; save old int 15 vector in Int15Chain
  1594. ;
  1595. ; call DevHlp to set int 1A to point to routine int1Artn
  1596. ; if DevHlp failed
  1597. ;   goto abort
  1598. ; save old int 1A vector in Int1AChain
  1599. ;
  1600. ; set return code = DONE
  1601. ; return
  1602. ;
  1603. ; abort:
  1604. ;      set return code = DONE+ERROR+GENERAL FAIL
  1605. ;      set end of code & data segment to zero
  1606. ;      return
  1607. ;
  1608. ;*********************** END OF PSEUDO-CODE    **********************
  1609.  
  1610.  
  1611.     ASSUME      CS:ClkCode,DS:ClkData,ES:NOTHING,SS:NOTHING
  1612. RTINIT  PROC FAR
  1613.         public  RTINIT
  1614.  
  1615.         mov     AX,WORD PTR ES:[BX].InitDevHlp   ; Save away the pointer to
  1616.         mov     WORD PTR DevHlp,AX               ; the DevHelp Router.
  1617.         mov     AX,WORD PTR ES:[BX].InitDevHlp+2
  1618.         mov     WORD PTR DevHlp+2,AX
  1619.  
  1620. ;%    Temporary      to fix loader problem for which the data selector
  1621. ;%    does not get fixed up.
  1622.  
  1623. ES_DI   EQU     1                       ;equate for PhysToVirt DevHlp service
  1624.  
  1625.  
  1626.         SaveReg <bx,es>
  1627.         SaveReg <ds>
  1628.         push    ds
  1629.         pop     es
  1630.         ASSUME  es:ClkData
  1631.         push    cs
  1632.         pop     ds
  1633.         ASSUME  ds:NOTHING
  1634.  
  1635.         mov     si,offset selClkData    ;(ds:si)->selClkData
  1636.         mov     dl,DevHlp_VirtToPhys
  1637.         call    es:[DevHlp]             ;(ax:bx)=physical address of selClkData
  1638.  
  1639.         mov     cx,2                    ;length of word we need to write into
  1640.         mov     dx,DevHlp_PhysToVirt + ES_DI*100h
  1641.         call    es:[DevHlp]             ;(es:di)->selClkData (writeable!)
  1642.  
  1643.         ASSUME  es:NOTHING
  1644.         RestoreReg <ds>
  1645.         ASSUME  ds:ClkData
  1646.         mov     es:[di],ds              ;save ds into code segment
  1647.  
  1648.         RestoreReg <es,bx>
  1649.         ASSUME  es:NOTHING
  1650.  
  1651.         mov     dl,DevHlp_UnPhysToVirt  ;free selector
  1652.         call    [DevHlp]
  1653. ;% END hack
  1654.  
  1655.         push    ES
  1656.         push    BX
  1657.  
  1658.         mov     AL,1                    ; Variable number of SysInfoSeg
  1659.         mov     DL,DevHlp_GetDOSVar
  1660.         call    [DevHlp]
  1661.         LJC     rtabort2                ; if carry flag set, abort clock
  1662.                                         ; No need to check return code here,
  1663.                                         ; because ABIOS ALWAYS returns 0 for
  1664.                                         ; the return LIDPARMS function.
  1665.         mov     ES,AX                            ; ES:BX -> SysInfoSeg
  1666.         mov     AX,ES:[BX]                       ; AX = InfoSeg segment selector
  1667.         mov     WORD PTR InfSeg+2,AX             ; Stuff for later
  1668.  
  1669.         mov     DL,DevHlp_SchedClock             ; ***** FOR DCR 487 *****
  1670.         call    [DevHlp]                         ; ES:BX = address of SchedClock pointer
  1671.         mov     WORD PTR SchedClock,BX           ; Save away the SchedClock ptr address
  1672.         mov     WORD PTR SchedClock+2,ES         ; **
  1673.  
  1674.                                         ; DS points to Data Segment...
  1675.         mov     AX,8                    ; desired device id is 8
  1676.         mov     BX,1                    ; get first LID for the RTC
  1677.         xor     DX,DX                   ; 
  1678.         mov     DL,DevHlp_GetLIDEntry   ; get the ABIOS LID for the RTC
  1679.         call    [DevHlp]                ; 
  1680.         LJC     rtabort2                ; if carry flag set, abort clock
  1681.         mov     ClockLID,AX             ; save LID for later use
  1682.  
  1683. ; GET ABIOS Clock Parameters
  1684.  
  1685.         lea     SI, DS:ABIOS_Clock_Parms
  1686.         mov     DL, DevHlp_ABIOSGetParms
  1687.         call    [DevHlp]
  1688.  
  1689. ; SET UP TASK REQUEST BLOCK
  1690.  
  1691.         mov     SI,Offset DS:AbiosRB    ; SI --> ABios request block area
  1692.         mov     [SI].RBLen,MAXBRB
  1693.         mov     [SI].LogID,AX
  1694.         mov     [SI].Function,ABretLIDP ; function is return Lid Parameters
  1695.         mov     [SI].returnCode,retCODE_IN
  1696.  
  1697.         xor     DH,DH                   ; calling ABIOS start
  1698.         mov     DL,DevHlp_ABIOSCall
  1699.         call    [DevHlp]                ; call ABIOS to get LID parameters
  1700.         LJC     rtabort2                ; if carry flag set, abort clock
  1701.                                         ; No need to check return code here,
  1702.                                         ; because ABIOS ALWAYS returns 0 for
  1703.                                         ; the return LIDPARMS function.
  1704.  
  1705. ; length of RTC request block is in RTCRBL.  Set up RB Pointers
  1706. ; INITIALIZE the Request Blocks and DISABLE their associated Interrupts
  1707. ; Complete the Initialization of the first Request Block; no interrupts to disable
  1708.  
  1709.         mov     BX,[SI].Parms.RTCRBL    ; Set up the true RB size in BX
  1710.         mov     [SI].RBLen,BX           ; Set up the true RB size in 1st RB
  1711.         mov     CX,SI                   ; CX --> request block area
  1712.         mov     TaskPkt,CX              ; Set TaskPkt to point to the 1st RB
  1713.  
  1714.         add     CX,BX                   ; CX --> 2nd request block area
  1715.         mov     PeriodPkt,CX            ; Set PeriodPkt to point to the 2nd RB
  1716.  
  1717.         add     CX,BX                   ; CX --> 3rd request block area
  1718.         mov     UpdatePkt,CX            ; Set UpdatePkt to point to the 3rd RB
  1719.  
  1720.         add     CX,BX                   ; CX --> 4th request block area
  1721.         mov     ExtraPkt,CX             ; Set ExtraPkt to point to the 4th RB
  1722.  
  1723.  
  1724. ; Initialize PERIODIC Request Block
  1725.         mov     SI,PeriodPkt            ; DS:SI --> Periodic request block
  1726.         mov     [SI].RBLen,BX
  1727.         mov     [SI].LogID,AX
  1728.         mov     [SI].ELLOffset,0
  1729.         mov     [SI].returnCode,retCODE_IN
  1730. ; call DevHlp ABIOSCALL to disable old periodic interrupt
  1731.         mov     [SI].Function,ABCANPERI ; function is Cancel Periodic Interrupt
  1732.         call    [DevHlp]                ; Disable the Periodic Interrupt
  1733.         LJC      rtabort2               ; if Carry flag set, abort clock
  1734.                                         ; return Code ALWAYS ZERO!
  1735.  
  1736. ; Initialize UPDATE Request Block
  1737.         mov     SI,UpdatePkt            ; DS:SI --> Update request block
  1738.         mov     [SI].RBLen,BX
  1739.         mov     [SI].LogID,AX
  1740.         mov     [SI].ELLOffset,0
  1741.         mov     [SI].returnCode,retCODE_IN
  1742. ; Disable UPDATE Interrupts
  1743.         mov     [SI].Function,ABCANUPDI ; function is Cancel Update-Ended Int'pt
  1744.         call    [DevHlp]                ; Disable the Update-Ended Interrupt
  1745.         LJC     rtabort2                ; if carry flag set, abort clock
  1746.  
  1747.  
  1748. ; Initialize Extra Request Block for Cancel Alarm Function
  1749.         mov     SI,ExtraPkt             ; DS:SI --> Alarm request block
  1750.         mov     [SI].RBLen,BX
  1751.         mov     [SI].LogID,AX
  1752.         mov     [SI].ELLOffset,0
  1753.         mov     [SI].returnCode,retCODE_IN
  1754. ; Disable ALARM Interrupts
  1755.         mov     [SI].Function,ABCANALI  ; function is Cancel Alarm Interrupt
  1756.         call    [DevHlp]                ; Cancel Alarm Interrupt
  1757.         LJC     rtabort2                ; if Carry flag set, abort clock
  1758.                                         ; return Code ALWAYS ZERO!
  1759.  
  1760. ; Set hundredths and milliseconds increments to initial values, based on
  1761. ; initial periodic interrupt frequency.
  1762.  
  1763.         mov     CurRTCFreq,RTCHZINIT
  1764.         mov     Hundred_Inc,((100 SHL 8) / RTCHZINIT)
  1765.         mov     MS_Inc_Whole,(1000 / RTCHZINIT)
  1766.         mov     MS_Inc_Frac,(((1000 SHL 16) / RTCHZINIT) AND 0FFFFh)
  1767.  
  1768. ; SET PERIODIC INTERRUPTS
  1769.  
  1770.         mov     SI,PeriodPkt            ; DS:SI --> Periodic request block
  1771.         mov     [SI].returnCode,retCODE_IN
  1772.         mov     [SI].Function,ABSETPERI ; function is Set Periodic Interrupt
  1773.         mov     [SI].Parms.RTC_Prat2,IN032    ; rate is 31.25 ms
  1774.         call    [DevHlp]                ; Enable the Periodic Interrupt
  1775.         jc      short rtabort2          ; if carry flag set, abort clock
  1776.         cmp     [si].returnCode,1       ; check ABIOS return status
  1777.         ja      short rtabort2          ; if error, then abort
  1778.  
  1779. ; SET FOR UPDATE INTERRUPTS
  1780.  
  1781.         mov     SI,UpdatePkt            ; DS:SI --> UpdatePkt request block
  1782.         mov     [SI].returnCode,retCODE_IN
  1783.         mov     [si].Function,ABSETUPDI ; function is Set Update-Ended Int'pt
  1784.         call    [DevHlp]                ; Enable the Update-Ended Interrupt
  1785.         jc      short rtabort2          ; if carry flag set, abort clock
  1786.         cmp     [si].returnCode,1       ; check ABIOS return status
  1787.         ja      short rtabort2          ; if error, then abort
  1788.  
  1789.  
  1790. ; Set up Code and Data Segment End Pointers for SysInit
  1791.  
  1792.         pop     BX
  1793.         pop     ES
  1794.         mov     CX,ExtraPkt
  1795.         mov     es:[bx].InitEdata,CX    ; InitEdata now points to the end
  1796.                                         ; of the third RB.  This is used
  1797.                                         ; to set up the END of the DATA SEG.
  1798.         mov     AX,offset ClkCode:RTINIT   ; set up END of the CODE SEGMENT
  1799.         mov     es:[bx].InitEcode,AX    ; (INIT routine goes away...)
  1800.  
  1801.  
  1802. ; Finally Set up Interrupt Vector...Enable too
  1803.         mov     BX,RTCIRQ
  1804.         xor     DH,DH                   ; IRQ NOT SHARED
  1805.         mov     AX,offset ClkCode:RTCINT ; AX --> INTERRUPT routine
  1806.         mov     DL,DevHlp_SetIRQ
  1807.         call    [DevHlp]                ; set the interrupt level
  1808.         jc      short rtabort3          ; if carry flag set ,abort clock
  1809.  
  1810.         push    cx
  1811.         mov     cx,200                  ; read 200 times clock
  1812.         call    FIXISEG                 ; Initialize InfoSeg from Clock
  1813.         pop     cx
  1814.         jnc     short end_rtinit
  1815.         jmp     short rtabort3          ; if carry flag set ,abort clock
  1816.  
  1817. rtabort2:
  1818.         pop     BX
  1819.         pop     ES
  1820. rtabort3:
  1821.         mov     AX,(STDON+STERR+ERRGFAIL) ; set error code for general failure
  1822.         mov     es:[bx].InitEcode,0     ; Set up end of Code Segment
  1823.         mov     es:[bx].InitEdata,0     ; Set up end of Data Segment
  1824.         ret
  1825.  
  1826. end_rtinit:
  1827.  
  1828. ;% Clk/Tmr registration and Initialization
  1829.  
  1830. ClkInit label near
  1831.         public ClkInit
  1832.  
  1833. ;DevHlp(DevHlp_RegisterPDD,pszClkName,fpfnClkVDDProc)
  1834.         SaveReg <es,bx>
  1835.         mov     dl,DevHlp_RegisterPDD   ;(dl)=DevHlp_RegisterPDD
  1836.         mov     si,offset ClkData:szClkName;(ds:si)->szClkName
  1837.         mov     di,cs
  1838.         mov     es,di
  1839.         mov     di,offset ClkCode:ClkVDDProc;(es:di)->ClkVDDProc
  1840.         call    [DevHlp]                ;(ax)=error code
  1841.         RestoreReg <bx,es>
  1842.         or      ax,ax                   ;error?
  1843.         jnz     short rtabort3          ;YES, goto error exit
  1844.  
  1845. ;DevHlp(DevHlp_RegisterPDD,pszTmrName,fpfnPTmrProc)
  1846.         SaveReg <es,bx>
  1847.         mov     dl,DevHlp_RegisterPDD   ;(dl)=DevHlp_RegisterPDD
  1848.         mov     si,offset ClkData:szTmrName;(ds:si)->szTmrName
  1849.         mov     di,cs
  1850.         mov     es,di
  1851.         mov     di,offset ClkCode:PTVDMProc;(es:di)->PTVDMProc
  1852.         call    [DevHlp]                ;(ax)=error code
  1853.         RestoreReg <bx,es>
  1854.         or      ax,ax                   ;error?
  1855.         jnz     short rtabort3          ;YES, goto error exit
  1856.  
  1857. ;DevHlp(DevHlp_RegisterBeep,fpfnPTBeep)
  1858.         mov     dl,DevHlp_RegisterBeep  ;(dl)=DevHlp_RegisterBeep
  1859.         mov     cx,cs
  1860.         mov     di,offset ClkCode:PTBeep;(cx:di)->PTBeep
  1861.         call    [DevHlp]
  1862.         or      ax,ax                   ;error?
  1863.         jnz     short rtabort3          ;YES, goto error exit
  1864.  
  1865.         call    PTBeepOff               ;disable speaker
  1866.  
  1867. ;DevHlp(DevHlp_RegisterFreq,fpfnCLKFreq)
  1868.         mov     dl,DevHlp_RegisterFreq  ;(dl)=DevHlp_RegisterFreq
  1869.         mov     cx,cs
  1870.         mov     di,offset ClkCode:CLKFreq;(cx:di)->CLKFreq
  1871.         call    [DevHlp]
  1872.         or      ax,ax                   ;error?
  1873.         jnz     short rtabort3          ;YES, goto error exit
  1874.  
  1875.  
  1876. ;Initialize TMR device (PIT Ctr 0).
  1877.  
  1878.         SaveReg <bx,cx,dx,di>
  1879.  
  1880.         mov     cx,cs
  1881.         mov     di,offset ClkCode:PTTimer0;(cx:di)->PTTimer0
  1882.         mov     dl,DevHlp_RegisterTmrDD
  1883.         call    [DevHlp]
  1884.  
  1885. ;       di:bx -> qwTmrRollover (16:16 ptr).
  1886. ;       di:cx -> qwTmr (16:16 ptr).
  1887.  
  1888.         or      di,di                   ;Valid Selector?
  1889.         jnz     short cinit2            ; Yes.
  1890.  
  1891. cinit1: mov     di,ds                   ;Invalid, so store valid ptr.
  1892.         mov     bx,offset qwTmrRollover
  1893.         mov     cx,offset qwTmr
  1894. cinit2:                                 ;Store (16:16) pointers.
  1895.         mov     WORD PTR pqwTmrRollover,bx      ;Store offset.
  1896.         mov     WORD PTR pqwTmrRollover+2,di    ;Store segment.
  1897.         mov     WORD PTR pqwTmr,cx      ;Store offset.
  1898.         mov     WORD PTR pqwTmr+2,di    ;Store segment.
  1899.  
  1900. ;Initialize current rollover count = next rollover count = 10000h.
  1901.  
  1902.         SaveReg <ds>
  1903.         mov     ds,di
  1904. .386p
  1905.         mov     DWORD PTR [bx].qw_ulLo,10000h
  1906.         mov     DWORD PTR [bx].qw_ulHi,10000h
  1907. CPUMode Reset
  1908.         RestoreReg <ds>
  1909.  
  1910.         RestoreReg <di,dx,cx,bx>
  1911.  
  1912.         mov     AX,STDON                ; Done
  1913.         ret
  1914.  
  1915. RTINIT  ENDP
  1916.  
  1917. ClkCode ENDS
  1918.  
  1919.         END
  1920.