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

  1. ;*DDK*************************************************************************/
  2. ;
  3. ; COPYRIGHT (C) Microsoft Corporation, 1989
  4. ; COPYRIGHT (C) Microsoft Corporation, 1989
  5. ; COPYRIGHT    Copyright (C) 1995 IBM Corporation
  6. ;
  7. ;    The following IBM OS/2 WARP source code is provided to you solely for
  8. ;    the purpose of assisting you in your development of OS/2 WARP device
  9. ;    drivers. You may use this code in accordance with the IBM License
  10. ;    Agreement provided in the IBM Device Driver Source Kit for OS/2. This
  11. ;    Copyright statement may not be removed.;
  12. ;*****************************************************************************/
  13. ;       SCCSID = @(#)clockdd.asm        6.7 91/09/25
  14. title   clock device driver -- main  [clockdd.asm]
  15. ; ****************************************************************************
  16. ; *                                                                          *
  17. ; *                                                                          *
  18. ; *                                                                          *
  19. ; ****************************************************************************
  20. PAGE    60,132
  21. ;
  22. ;********************** START OF SPECIFICATIONS *********************
  23. ;*
  24. ;* SOURCE FILE NAME:    CLOCKDD.ASM
  25. ;*
  26. ;* DESCRIPTIVE NAME:    CP/DOS 1.1 CLOCK DEVICE DRVIER
  27. ;*
  28. ;*
  29. ;*
  30. ;*
  31. ;* STATUS:    RELEASE 1 LEVEL 1
  32. ;*
  33. ;* FUNCTION:  CLOCK$ is the device driver for the RT/CMOS clock.
  34. ;*
  35. ;* NOTES:
  36. ;*    DEPENDENCIES:
  37. ;*    RESTRICTIONS:
  38. ;*    PATCH LABEL:
  39. ;*
  40. ;* ENTRY POINTS:  RTENTR
  41. ;*
  42. ;* EXTERNAL REFERENCES:
  43. ;*    ROUTINES:
  44. ;*      DIRECT: DevHlps: dh_GetDOSVar, dh_EOI, dh_SchedClock,
  45. ;*                       dh_SetIRQ, dh_PhysToVirt, dh_UnPhysToVirt
  46. ;*                       (NOT AT MODEL Only: dh_GetLIDEntry, dh_ABIOSCall)
  47. ;*
  48. ;*  DATA AREAS:
  49. ;*    MODIFIED: Global Information Segment (SysInfoSeg)
  50. ;*
  51. ;*  CONTROL BLOCKS:
  52. ;*      MODIFIED:   Device Driver Request Block
  53. ;*
  54. ;*  TABLES:  none   ; sparse function table, used case structure instead
  55. ;*
  56. ;*********************** END OF SPECIFICATIONS **********************
  57.  
  58. .xlist
  59.         INCLUDE mvdm.inc                ; equates and data for MVDM support
  60. purge PANIC                             ; prevent conflict with osmaca.inc
  61.         INCLUDE osmaca.inc
  62.         INCLUDE devhlp.inc              ; the devhlp function eqs
  63.         INCLUDE infoseg.inc             ; definitions of Global Info Segment
  64.         INCLUDE devsym.inc              ; definition of DD Request Packet
  65.         INCLUDE clkdata.inc
  66.         INCLUDE abios.inc
  67.         INCLUDE vcmospdd.inc            ; vcmos/clk shared data and equates
  68.         INCLUDE clkseg.inc              ; segment definitions
  69.         INCLUDE pvwxport.inc
  70.         INCLUDE cmos.inc
  71.         INCLUDE ioctl.inc
  72.         INCLUDE vtdptd.inc
  73. .list
  74.  
  75. ;;MONITOR         EQU     1               ; creates counters for monitoring
  76.  
  77.         extrn   RTWRIT:Near
  78.         extrn   RTCINT:Near
  79.         extrn   FIXISEG:Near
  80.         extrn   RTINIT:far
  81.         extrn   RTINIT2:far
  82.         extrn   endswapcode:byte
  83.         EXTRNFAR ClkReadCMOS
  84.  
  85. ; publics
  86.  
  87.         PUBLIC  DevHlp
  88.         PUBLIC  SchedClock
  89.         PUBLIC  InfSeg
  90.         PUBLIC  MonTab
  91.         PUBLIC  Update_Flag                     ; Update Interrupt Flag
  92.         PUBLIC  Post_Time                       ; Time to call Post EOI SC
  93.         PUBLIC  Int_Nested                      ; Number of nested Ints
  94.         PUBLIC  Int_In_Progress                 ; Flag for presently nested
  95.  
  96. ifdef profile
  97.         PUBLIC  DivDown
  98. endif
  99.  
  100.         PUBLIC  ReqRTCFreq
  101.         PUBLIC  CurRTCFreq
  102.         PUBLIC  Hundred_Whole
  103.         PUBLIC  Hundred_Frac
  104.         PUBLIC  Hundred_Inc
  105.         PUBLIC  MS_Fraction
  106.         PUBLIC  MS_Inc_Whole
  107.         PUBLIC  MS_Inc_Frac
  108.         PUBLIC  MS_Delta
  109.  
  110.         PUBLIC  Hz128To32
  111.         PUBLIC  Accum8msTicks
  112.         PUBLIC  ExpectedMsCount
  113.  
  114. ifdef   MONITOR
  115.         PUBLIC  LagCount
  116.         PUBLIC  LagTotal
  117.  
  118. ACCM8SIZE EQU 64
  119.         PUBLIC  Accm
  120.         PUBLIC  Accm8
  121.         PUBLIC  Accm8p
  122.         PUBLIC  Accm8mod4
  123.         PUBLIC  Ticks8
  124.         PUBLIC  Ticks32
  125. endif
  126.  
  127.         PUBLIC  InSchedClk
  128.         PUBLIC  TicksMissed
  129.         PUBLIC  CMOS_location
  130.         PUBLIC  saveDS
  131.         PUBLIC  ATDataEnd
  132.  
  133.         PUBLIC  pqwTmrRollover
  134.         PUBLIC  qwTmrRollover
  135.         PUBLIC  pqwTmr
  136.         PUBLIC  qwTmr
  137.  
  138. BREAK <Clock Device Driver DATA SEGMENT Declaration>
  139.  
  140. ClkData SEGMENT
  141.  
  142. START$  LABEL   BYTE
  143.         dd      -1
  144.         DW      DEV_CHAR_DEV OR DEVLEV_3 OR DEV_CLOCK
  145.         DW      offset ClkCode:ClkStrat
  146.         DW      0
  147.         DB      'CLOCK$  '
  148.         DW      4 DUP  (?)      ; Prot & Real mode CS & DS (filled by sysinit)
  149.         DD      DEV_16MB        ; device can handle > 16MB physical memory
  150.  
  151. DevHlp  DD      0                       ; Pointer to DOS "helper" functions
  152. SchedClock      DD      0               ; Pointer to SchedClock address pointer
  153. InfSeg  DD      0                       ; Pointer to InfoSeg Address
  154.  
  155.         PUBLIC  szClkName,szTmrName
  156. szClkName       db      CLK_NAME,0      ;CLOCK registered name
  157. szTmrName       db      PTD_NAME,0      ;TIMER registered name
  158.  
  159.         PUBLIC  fpfnVTProc,fsPTFlags
  160. fpfnVTProc      df      0               ;vtimer entry point
  161. fsPTFlags       dw      PTF_OWNT0+PTF_OWNT2;ptimer owns T0/T2 initially
  162.  
  163. MonTab  DB      31                      ; Days of Month Table - January
  164.         DB      28                      ; - February
  165.         DB      31                      ; - March
  166.         DB      30                      ; - April
  167.         DB      31                      ; - May
  168.         DB      30                      ; - June
  169.         DB      31                      ; - July
  170.         DB      31                      ; - August
  171.         DB      30                      ; - September
  172.         DB      31                      ; - October
  173.         DB      30                      ; - November
  174.         DB      31                      ; - December
  175.  
  176. ; The following hold the whole and fractional portions of the time in
  177. ; milliseconds that is advanced every clock tick.  Since we allow the
  178. ; clock to run at either 32hz or 128hz, the increment values will be
  179. ; either 31.25ms or 7.8125ms.
  180.  
  181. ReqRTCFreq      DB      0   ; Requested new RTC frequency (0 = No change)
  182. CurRTCFreq      DB      0   ; Current RTC frequency (will be initialized)
  183. Hundred_Whole   DB      0   ; Whole portion of hundreds count
  184. Hundred_Frac    DB      0   ; Fractional portion of hundreds count
  185. Hundred_Inc     DW      ?   ; Value to increment hundreds each tick
  186. MS_Fraction     DW      0   ; Fractional portion of milliseconds count
  187. MS_Inc_Whole    DD      ?   ; Whole value to increment milliseconds each tick
  188. MS_Inc_Frac     DW      ?   ; Fract value to increment milliseconds each tick
  189. MS_Delta        DW      0   ; Number of milliseconds since last tick
  190.  
  191. ; When the frequency is switched from 128hz to 32hz, special adjustments
  192. ; must be made to keep time advancing at the correct rate.  The following
  193. ; help enable those special adjustments.
  194.  
  195. Hz128To32           DB  0   ; Flag: 1 if RTC reset to 32hz since last tick
  196. Accum8msTicks       DW  0   ; Number of accumulated 8ms ticks
  197. ExpectedMsCount     DD  0   ; Millisecond count we expect 1 second from now
  198.  
  199. ifdef   MONITOR
  200. LagCount        DD      0                 ; how many times ms lagged.
  201. LagTotal        DD      0                 ; Total lag time
  202.  
  203. ACCM8SIZE EQU 64
  204. Accm            DW     -1
  205. Accm8           DW      ACCM8SIZE DUP(0)
  206.                 DW     -1
  207. Accm8p          DW      0
  208.                 DW     -1
  209. Accm8mod4       DW      0,0,0,0
  210.                 DW     -1
  211. Ticks8          DD      0
  212.                 DD     -1
  213. Ticks32         DD      0
  214.                 DW     -1
  215. endif
  216.  
  217.  
  218. Update_Flag  DB      00                 ;  Update Interrupt flag
  219.  
  220. ; Extra Vars for Nested Int fix
  221.  
  222. Post_TIme dw  0
  223. Int_Nested db  0
  224. Int_In_Progress db  0
  225.  
  226. InSchedClk      DB      0               ; flag to indicate entering SchedClock
  227. TicksMissed     DW      0               ; count of ticks missed in SchedClock
  228.  
  229.  
  230. CMOS_location   db      0               ; location of CMOS TABLE ADDR
  231.  
  232.         EVEN
  233. pqwTmrRollover  dd      0               ;(16:16) ptr to PIT Ctr 0 rollover
  234.                                         ;  count in kernel address space.
  235. qwTmrRollover   qw_s    <0,0>           ;PIT Ctr 0 rollover count in Clock
  236.                                         ;  driver address space, where:
  237.                                         ;  qw_Lo = current rollover count.
  238.                                         ;  qw_Hi = next rollover count.
  239. pqwTmr          dd      0
  240. qwTmr           qw_s    <0,0>
  241.  
  242. codelockhandle  db      sizeof_lockhandle_s  dup(0)
  243.                                         ; handle returned by DevHlp_VmLock
  244.  
  245.         READREQ cmos_req
  246.  
  247. ATDataEnd       EQU     $               ; Used by Sysinit to delete remaining
  248.                                         ;   data segment.
  249.  
  250. Time_Check      db      0A0h            ; Used for validation
  251.                 db      0A6h
  252.                 db      0AAh
  253.  
  254. ClkData         ENDS
  255.  
  256.  
  257. BREAK <Clock Device Driver Strategy Routine>
  258. ;********************** START OF SPECIFICATIONS *********************
  259. ;*
  260. ;* MODULE NAME:  RTENTR
  261. ;*
  262. ;* DESCRIPTIVE NAME:  Strategy routine for Clock Device Driver
  263. ;*
  264. ;* FUNCTION:    This routine is the task-time entry point to the Clock
  265. ;*              Device driver.  Requested functions are dispatched to
  266. ;*              worker routines.
  267. ;* NOTES:
  268. ;*      RTENTR provides eight functions:  RTREAD(5), STREDY(5), STCOMP(6,7)
  269. ;*      RTWRIT(8,9), RTINIT(27), RTINIT2(0) and BADCMD (all the rest).
  270. ;*      Since a command table would be sparse (only 8 valid entries of
  271. ;*      28 options), a case control structure is used.  Functions 6,7
  272. ;*      and functions 8,9
  273. ;*      have the same effect.
  274. ;*
  275. ;*   Equivalent Command dispatch table (Highest legal function is 27):
  276. ;*
  277. ;*   ClkSwap:RTINIT2         ; 0 Initialize (2nd stage, special for clock)
  278. ;*   ClkSwap:BADCMD          ; 1 Media Check  these are unsupported
  279. ;*   ClkSwap:BADCMD          ; 2 Build BPB    functions.
  280. ;*   ClkSwap:BADCMD          ; 3 IOCTL input
  281. ;*   ClkSwap:RTREAD          ; 4 Input (Read)
  282. ;*   ClkSwap:STREDY          ; 5 Non-destructive read, no wait
  283. ;*   ClkSwap:STCOMP          ; 6 Input status
  284. ;*   ClkSwap:STCOMP          ; 7 Input flush
  285. ;*   ClkSwap:RTWRIT          ; 8 Output (Write)
  286. ;*   ClkSwap:RTWRIT          ; 9 Output with verify
  287. ;*   ClkSwap:BADCMD          ; 10 BADCMD
  288. ;*   ClkSwap:BADCMD          ; 11 BADCMD
  289. ;*   ClkSwap:BADCMD          ; 12 BADCMD
  290. ;*   ClkSwap:BADCMD          ; 13 BADCMD
  291. ;*   ClkSwap:BADCMD          ; 14 BADCMD
  292. ;*   ClkSwap:BADCMD          ; 15 BADCMD
  293. ;*   ClkSwap:RTIOCT          ; 16 Generic IOCTL
  294. ;*   ClkSwap:BADCMD          ; 17 BADCMD
  295. ;*   ClkSwap:BADCMD          ; 18 BADCMD
  296. ;*   ClkSwap:BADCMD          ; 19 BADCMD
  297. ;*   ClkSwap:BADCMD          ; 20 BADCMD
  298. ;*   ClkSwap:BADCMD          ; 21 BADCMD
  299. ;*   ClkSwap:BADCMD          ; 22 BADCMD
  300. ;*   ClkSwap:BADCMD          ; 23 BADCMD
  301. ;*   ClkSwap:BADCMD          ; 24 BADCMD
  302. ;*   ClkSwap:BADCMD          ; 25 BADCMD
  303. ;*   ClkSwap:BADCMD          ; 26 BADCMD
  304. ;*   ClkCode:RTINIT          ; 27 Initialize
  305. ;*   ClkSwap:BADCMD          ; 28 BADCMD here at table end
  306. ;*
  307. ;* ENTRY POINT: RTENTR
  308. ;*    LINKAGE:  FAR
  309. ;*
  310. ;* USES: EAX, EBX, ECX, DL, EDI, ESI
  311. ;*
  312. ;* INPUT:
  313. ;*      ES:BX = Address of Device Driver Request Packet
  314. ;*      DS    = Points to Clock Device Driver Data Segment
  315. ;*
  316. ;*      WARNING: Parameter checking on input data to RTWRIT through
  317. ;*         this routine must be performed by the caller!
  318. ;*
  319. ;* OUTPUT:
  320. ;*      Device Driver Request Packet filled in (Status word set,
  321. ;*      date/time fields, etc).
  322. ;*
  323. ;* EXIT-NORMAL:
  324. ;*      Exit-Normal is via common routines STCOMP or STREDY
  325. ;*      Status word set to 'BUSY' and/or 'DONE'
  326. ;*
  327. ;* EXIT-ERROR:
  328. ;*      Exit-Error is via common routine BADCMD, but only if
  329. ;*      invalid command is passed in Driver Request Packet.
  330. ;*
  331. ;* INTERNAL REFERENCES:
  332. ;*    ROUTINES:     RTREAD, RTWRIT, RTINIT, STCOMP, STREDY, BADCMD,
  333. ;*                  RTIOCT
  334. ;*
  335. ;* EXTERNAL REFERENCES:
  336. ;*    STRUCTURES:  Global Information Segment (SysInfoSeg)
  337. ;*    ROUTINES:  none
  338. ;*
  339. ;*********************** END OF SPECIFICATIONS **********************
  340. page
  341. ;********************** START OF PSEUDO-CODE   **********************
  342. ;
  343. ; switch( packet_command ) {
  344. ;
  345. ; 0;    call RTINIT2 to grab IRQ0
  346. ;       break;
  347. ;
  348. ; 4:    call RTREAD to read realtime clock
  349. ;       break;
  350. ;
  351. ; 5:    call STREDY to do non-destructive read with no-wait
  352. ;       break;
  353. ;
  354. ; 6:
  355. ; 7:    call STCOMP to set status "complete" exit
  356. ;       break;
  357. ;
  358. ; 8:
  359. ; 9:    call RTWRIT to update the realtime clock
  360. ;       break;
  361. ;
  362. ; 16:   call RTIOCT to process the IOCTL request
  363. ;       break;
  364. ;
  365. ; 27:   call RTINIT to initialize data structures & realtime clock device
  366. ;       break;
  367. ;
  368. ; default:
  369. ;       call BADCMD to express that this function is unsupported
  370. ;       break;
  371. ; }
  372. ;
  373. ; mark packet_status operation complete
  374. ; return
  375. ;
  376. ;*********************** END OF PSEUDO-CODE    **********************
  377.  
  378. ClkSwap SEGMENT
  379.  
  380. public startswapcode
  381. startswapcode   label   byte
  382.  
  383.  
  384.     ASSUME      CS:ClkSwap,DS:ClkData,ES:NOTHING,SS:NOTHING
  385. RTENTR  PROC    FAR
  386.         public  RTENTR
  387.  
  388.         push    es
  389.         push    bx
  390.         mov     al,es:[bx].PktCmd       ; Get device command
  391.         xor     ah,ah
  392.  
  393. RTREAD?:
  394.         cmp     ax,4                    ; Is this RTREAD?
  395.         jl      RTINIT2?                ; .. No, might be RTINIT2
  396.         jg      STREDY?                 ; .. No, try next
  397.         call    LOCKSWAP                ; .. Yes, try locking swappable code
  398.         jc      OUTOFMEM                ; .... lock failed, error out
  399.         call    RTREAD                  ; .....lock succeeded, dispatch worker
  400.         call    UNLOCKSWAP
  401.         jmp     ENDCASE
  402.  
  403. STREDY?:
  404.         cmp     ax,5                    ; Is this STREDY?
  405.         jg      STCOMP?                 ; .. No, try next
  406.         mov     ax,(STDON+STBUI)        ; .. Yes, just return flags
  407.         jmp     ENDCASE
  408.  
  409. STCOMP?:
  410.         cmp     ax,7                    ; Is this STCOMP?
  411.         jg      RTWRIT?                 ; .. No, try next
  412.         mov     ax,STDON                ; .. Yes, just return flags
  413.         jmp     ENDCASE
  414.  
  415. RTWRIT?:
  416.         cmp     ax,9                    ; Is this RTWRIT?
  417.         jg      RTIOCT?                 ; .. No, try next
  418.         call    LOCKSWAP                ; .. Yes, try locking swappable code
  419.         jc      OUTOFMEM                ; .... lock failed, error out
  420.         call    RTWRIT                  ; .....lock succeeded, dispatch worker
  421.         call    UNLOCKSWAP
  422.         jmp     ENDCASE
  423.  
  424. RTIOCT?:
  425.         cmp     ax,16                   ; Is this RTIOC?
  426.         jg      RTINIT?                 ; .. No, try next
  427.         call    LOCKSWAP                ; .. Yes, try locking swappable code
  428.         jc      OUTOFMEM                ; .... lock failed, error out
  429.         call    RTIOCTL                 ; .....lock succeeded, dispatch worker
  430.         call    UNLOCKSWAP
  431.         jmp     ENDCASE
  432.  
  433. RTINIT?:
  434.         cmp     ax,27                   ; Is this RTINIT?
  435.         jne     BADCMD                  ; .. No, must be a     command
  436.         call    RTINIT                  ; .. Yes, dispatch worker
  437.         jmp     ENDCASE
  438.  
  439. RTINIT2?:
  440.         cmp     ax,0                    ; Is this RTINIT2?
  441.         jne     BADCMD                  ; .. No, must be     command
  442.         call    RTINIT2                 ; .. Yes, dispatch worker
  443.         jmp     ENDCASE
  444.  
  445. BADCMD:
  446.         mov     ax, STDON+STERR+ERRCMD  ; Done + Error +     command
  447.         jmp     ENDCASE
  448.  
  449. OUTOFMEM:
  450.         mov     ax, STDON+STERR+ERRGFAIL
  451.         ; jmp     ENDCASE
  452.  
  453. ENDCASE:
  454.         pop     bx
  455.         pop     es
  456.         mov     word ptr es:[bx].PktStatus,ax    ; Mark operation complete
  457.         ret
  458.  
  459. RTENTR  ENDP
  460.  
  461.  
  462. ;********************** START OF SPECIFICATIONS *********************
  463. ;*
  464. ;* MODULE NAME:  LOCKSWAP
  465. ;*
  466. ;* DESCRIPTIVE NAME:  Lock Swappable Code routine
  467. ;*
  468. ;* FUNCTION:  Lock the swappable code segment portion of the
  469. ;*            clock device driver.
  470. ;*
  471. ;* ENTRY POINT: LOCKSWAP
  472. ;*    LINKAGE:  NEAR from RTENTR
  473. ;*
  474. ;* NOTE:  See file ?\dos\memory\VMMISC.ASM for masm interface to
  475. ;*        _DevHlp_VMLock.
  476. ;*
  477. ;* INPUT:  none
  478. ;*
  479. ;* USES: EAX, ECX, DL, EDI, ESI
  480. ;*
  481. ;* EXIT-NORMAL:
  482. ;*     CF = 0; [codelockhandle] saved
  483. ;*
  484. ;* EXIT-ERROR:
  485. ;*     CF = 1
  486. ;*
  487. ;* INTERNAL REFERENCES:
  488. ;*    STRUCTURES:  ClkData:[codelockhandle]
  489. ;*
  490. ;* EXTERNAL REFERENCES:
  491. ;*    ROUTINES:    DevHlp_VirtToLin, DevHlp_VMLock
  492. ;*
  493. ;*********************** END OF SPECIFICATIONS **********************
  494.  
  495.     ASSUME      CS:ClkSwap,DS:ClkData,ES:NOTHING,SS:NOTHING
  496. LOCKSWAP PROC NEAR
  497.         public  LOCKSWAP
  498.  
  499. .386p
  500.         push    ebx             ; others rely on bx,es
  501.  
  502.         ; do a virttolin DevHlp (linear address)
  503.         mov     ax,cs
  504.         lea     esi,startswapcode
  505.         mov     dl,DevHlp_VirtToLin
  506.         call    [DevHlp]
  507.         mov     edi,eax
  508.  
  509.         ; do a virttolin DevHlp (lockhandle)
  510.         mov     ax,ds
  511.         mov     esi,offset codelockhandle
  512.         mov     dl,DevHlp_VirtToLin
  513.         call    [DevHlp]
  514.  
  515.         ; do a VMLock DevHlp
  516.         mov     esi,eax         ; get offset to lock handle
  517.         xor     eax,eax         ; short term lock, etc.
  518.         mov     ebx,edi         ; get offset to area to lock
  519.         mov     edi,-1          ; set to no page list
  520.         lea     ecx,endswapcode ; size to lock
  521.         sub     ecx,offset startswapcode ; size to lock
  522.         mov     dl,DevHlp_VMLock
  523.         call    [DevHlp]       ; CF set by DevHlp_VMLock
  524.  
  525.         pop     ebx
  526.  
  527.         RET
  528.  
  529. LOCKSWAP  ENDP
  530.  
  531.  
  532. ;********************** START OF SPECIFICATIONS *********************
  533. ;*
  534. ;* MODULE NAME:  UNLOCKSWAP
  535. ;*
  536. ;* DESCRIPTIVE NAME:  UnLock Swappable Code routine
  537. ;*
  538. ;* FUNCTION:  Unlock the swappable code segment portion of the
  539. ;*            clock device driver.
  540. ;*
  541. ;* ENTRY POINT: UNLOCKSWAP
  542. ;*    LINKAGE:  NEAR from RTENTR
  543. ;*
  544. ;* USES: DL, ESI
  545. ;*
  546. ;* EXIT: Assume success
  547. ;*
  548. ;* INTERNAL REFERENCES:
  549. ;*    STRUCTURES:  ClkData:[codelockhandle]
  550. ;*
  551. ;* EXTERNAL REFERENCES:
  552. ;*    ROUTINES:    DevHlp_VirtToLin, DevHlp_VMUnLock
  553. ;*
  554. ;*********************** END OF SPECIFICATIONS **********************
  555.  
  556.     ASSUME      CS:ClkSwap,DS:ClkData,ES:NOTHING,SS:NOTHING
  557. UNLOCKSWAP PROC NEAR
  558.         public  UNLOCKSWAP
  559.  
  560.         push    eax
  561.         ; do a virttolin DevHlp (lockhandle)
  562.         mov     ax,ds
  563.         mov     esi,offset codelockhandle
  564.         mov     dl,DevHlp_VirtToLin
  565.         call    [DevHlp]
  566.  
  567.         ; do a VMUnlock DevHlp using previously saved lock handle
  568.         mov     esi,eax         ; get offset to lock handle
  569.         mov     dl,DevHlp_VMUnlock
  570.         call    [DevHlp]
  571.         pop     eax
  572.         RET
  573.  
  574. UNLOCKSWAP  ENDP
  575.  
  576.  
  577. BREAK <RealTime Clock Read Routine>
  578. ;********************** START OF SPECIFICATIONS *********************
  579. ;*
  580. ;* MODULE NAME:  RTREAD
  581. ;*
  582. ;* DESCRIPTIVE NAME:  Realtime Clock Read routine
  583. ;*
  584. ;* FUNCTION:  Supports the device commands:
  585. ;*            - READ (function 4)
  586. ;*      by returning six bytes of date and time information in
  587. ;*      the form Date(word), Min, Hrs, Sec/100, Sec.
  588. ;*
  589. ;*      DevHlp_PhysToVirt converts the real address of the data buffer
  590. ;*      in the Device Driver Request Block (PktData) to a virtual
  591. ;*      address.  DevHlp_UnPhysToVirt later restores the physical
  592. ;*      memory address.
  593. ;*
  594. ;* NOTES:
  595. ;*      For enhanced performance, RTREAD does not actually read the
  596. ;*      clock, but instead gets the data from the Global InfoSeg
  597. ;*      date/time data area.
  598. ;*
  599. ;* ENTRY POINT: RTREAD
  600. ;*    LINKAGE:  NEAR from RTENTR
  601. ;*
  602. ;* USES:    AX, CX, DX, BX, ES.  Preserves others.
  603. ;*
  604. ;* INPUT:
  605. ;*      Interrupt is enabled
  606. ;*      ES:BX = pointer to Request Block  (PktData)
  607. ;*      (SP+4):(SP+2) = pointer to data buffer
  608. ;*
  609. ;* OUTPUT: (RETURNED)
  610. ;*    DESCRIPTION:   Caller's data Buffer
  611. ;*
  612. ;* EXIT-NORMAL:
  613. ;*      Exit is via return to RTENTR (Strategy routine) with
  614. ;*      AX = Status word to be stored in request packet status
  615. ;*      field.
  616. ;*
  617. ;* EXIT-ERROR:
  618. ;*    RETURN CODE:      AX = ERROR and DONE
  619. ;*
  620. ;* INTERNAL REFERENCES:
  621. ;*    ROUTINES:    GTDAYS
  622. ;*
  623. ;* EXTERNAL REFERENCES:
  624. ;*    STRUCTURES:  Global Information Segment (SysInfoSeg)
  625. ;*    ROUTINES:    DevHlp_PhysToVirt, DevHlp_UnPhysToVirt
  626. ;*
  627. ;*********************** END OF SPECIFICATIONS **********************
  628. page
  629. ;********************** START OF PSEUDO-CODE   **********************
  630. ;
  631. ; if requesting byte length >= 6 byte
  632. ;    set requesting byte length = 6
  633. ;    save flags for preserving interrupt flag
  634. ;    call DevHlp_PhysToVirt to convert data buffer's physical addr to
  635. ;         virtual address in ES:DI
  636. ;    if DevHlp_PhysToVirt successful
  637. ;       save ClkData address( save DS )
  638. ;       set DS:BX = SysInfoSeg address
  639. ;       disable interrupts for accessing InfoSeg
  640. ;       access InfoSeg to get seconds/hundredths, hours/minutes,
  641. ;              months/days, & current year to put in caller's data buffer
  642. ;       restore ClkData address, DS
  643. ;       call GTDAYS to get day count since 1-1-80
  644. ;       save day count in caller's data buffer
  645. ;       call DevHlp_UnPhysToVirt to get original address mode
  646. ;       if DevHlp_UnPhysToVirt successful
  647. ;          set return code  "DONE" & "BUSY"
  648. ;       endif
  649. ;       else goto convert_fail
  650. ;    endif
  651. ;    else goto convert_fail
  652. ;
  653. ;    restore flags for original interrupt flag
  654. ;    return
  655. ; endif
  656. ; else goto RT_ERR
  657. ;
  658. ; convert_fail:
  659. ;    restore flags for original interrupt flag
  660. ;
  661. ; RT_ERR:
  662. ;    set requesting byte length = 0
  663. ;    set return code  STDON+STERR+READ FAULT
  664. ;    return
  665. ;
  666. ;*********************** END OF PSEUDO-CODE    **********************
  667.  
  668.  
  669.     ASSUME      CS:ClkSwap,DS:ClkData,ES:NOTHING,SS:NOTHING
  670. RTREAD  PROC NEAR
  671.         public  RTREAD
  672.  
  673.         CMP     ES:[BX].IOcount,RW_BYTES        ;  requesting 6 bytes or more
  674.         Jae     READ                            ;  yes, continue....  @3.77
  675.  
  676. RT_ERR:
  677.         mov     ES:[BX].IOcount,0               ;  return 0 bytes     @3.77
  678.         MOV     AX,(STDON+STERR)+0bh            ;  Else, quit w/ error. @3.77
  679.         RET
  680.  
  681. READ:   PUSH    BP
  682.         MOV     BP,SP
  683. ;; The addresses passed in the request packets are 32-bit physical addresses.
  684.         MOV     CX,6
  685.         mov     ES:[BX].IOcount,cx              ;  return 6 bytes     @3.77
  686.         MOV     AX,word ptr ES:[BX].IOpData+2   ; get hi word of address
  687.         MOV     BX,word ptr ES:[BX].IOpData     ; get lo word of address
  688.         MOV     DH,1                            ; result in ES:DI
  689.         MOV     DL,DevHlp_PhysToVirt            ; call PhysToVirt
  690.         PUSHF                                   ; save the flags
  691.         CALL    [DevHlp]                        ; ES:DI points to buffer
  692.         JNC     GET_DATA
  693.  
  694. CONVERT_FAIL:
  695.         POPF                                    ; restore flags
  696.         POP     BP
  697.         JMP     SHORT RT_ERR
  698.  
  699. GET_DATA:
  700.         PUSH    DS                              ; Save ClkData selector
  701.         CLI                                     ; Disable Interrupts while
  702.                                                 ; accessing InfoSeg
  703.         LDS     BX,[InfSeg]                     ; DS:BX = InfoSeg address
  704.     ASSUME      DS:NOTHING
  705.         MOV     AX,WORD PTR DS:[BX.SIS_SecTime] ; Get Secs/Hundths
  706.         XCHG    AH,AL
  707.         MOV     WORD PTR ES:[DI+4],AX           ; Stuff Huns/Secs
  708.         MOV     AX,WORD PTR DS:[BX.SIS_HrsTime] ; Get Hrs/Mins
  709.         XCHG    AH,AL
  710.         MOV     WORD PTR ES:[DI+2],AX           ; Stuff Mins/Hrs
  711.         MOV     DX,WORD PTR DS:[BX.SIS_DayDate] ; DX = Mon/Day
  712.         MOV     AX,DS:[BX.SIS_YrsDate]          ; Get current year
  713. ;;80291 sti                                     ; enable interrupts
  714.         SUB     AX,1980                         ; Elapsed since 1-1-80
  715.         POP     DS                              ; Restore ClkData selector
  716. ;;;;;;;;;;;;;;;;; Ray Andrade Defect# 80291 Change Team ;;;;;;;;;;;;;;;;;;;;;
  717.         sti                                     ; enable interrupts(moved here)
  718.     ASSUME      DS:ClkData                      ; 
  719.         CALL    FAR PTR GTDAYS                  ; Convert to day count
  720.         MOV     WORD PTR ES:[DI],AX             ; Stuff it in caller's buffer
  721.         MOV     DL,DevHlp_UnPhysToVirt           ; call UnPhysToVirt
  722.         CALL    [DevHlp]                        ; original addr mode restored
  723.         JC      CONVERT_FAIL
  724.         POPF                                    ; restore flags
  725.         MOV     AX,(STDON OR STBUI)             ; No error
  726.         POP     BP
  727.  
  728. readabort:
  729.         RET
  730.  
  731. RTREAD  ENDP
  732.  
  733.  
  734. BREAK <RealTime Clock Generic IOCTL routine>
  735. ;********************** START OF SPECIFICATIONS *********************
  736. ;*
  737. ;* MODULE NAME:  RTIOCTL
  738. ;*
  739. ;* DESCRIPTIVE NAME:  Realtime Clock Generic IOCTL routine
  740. ;*
  741. ;* FUNCTION:  Supports the category 13 generic IOCTL commands:
  742. ;*            - READ CMOS byte (function 60h)
  743. ;*      by calling the appropriate worker routine.
  744. ;*
  745. ;* ENTRY POINT: RTIOCTL
  746. ;*    LINKAGE:  NEAR from RTENTR
  747. ;*
  748. ;* USES:    AX and flags.
  749. ;*
  750. ;* INPUT:
  751. ;*      ES:BX = pointer to Request Block  (PktData)
  752. ;*
  753. ;* EXIT-NORMAL:
  754. ;*      Exit is via return to RTENTR (Strategy routine) with
  755. ;*      AX = Status word to be stored in request packet status
  756. ;*      field (DONE).
  757. ;*
  758. ;* EXIT-ERROR:
  759. ;*    RETURN CODE:      AX = Invalid command
  760. ;*
  761. ;* INTERNAL REFERENCES:
  762. ;*    ROUTINES:    GTCMOS
  763. ;*
  764. ;* EXTERNAL REFERENCES:
  765. ;*    STRUCTURES:
  766. ;*    ROUTINES:
  767. ;*
  768. ;*********************** END OF SPECIFICATIONS **********************
  769. page
  770. ;********************** START OF PSEUDO-CODE   **********************
  771. ;
  772. ; if requesting IOCTL is supported
  773. ;    call worker routine
  774. ; else
  775. ;    set AX to
  776. ;
  777. ; return
  778. ;
  779. ;*********************** END OF PSEUDO-CODE    **********************
  780.  
  781.  
  782.     ASSUME      CS:ClkSwap,DS:ClkData,ES:NOTHING,SS:NOTHING
  783. RTIOCTL PROC NEAR
  784.         public  RTIOCTL
  785.  
  786.         cmp     byte ptr es:[bx].GIOCategory, IOC_CK ; Correct category?
  787.         jne     rti10                   ; no, error exit
  788.         cmp     byte ptr es:[bx].GIOFunction, IOCK_RD ; Supported function?
  789.         jne     rti10                   ; no, error exit
  790.         call    GTCMOS                  ; call worker routine
  791.         jmp     short rti20             ; then exit
  792.  
  793. rti10:
  794.         mov     ax, STDON+STERR+ERRCMD  ; indicate unknown command
  795.  
  796. rti20:
  797.         ret
  798.  
  799. RTIOCTL ENDP
  800.  
  801. BREAK <RealTime Clock Get CMOS byte routine>
  802. ;********************** START OF SPECIFICATIONS *********************
  803. ;*
  804. ;* MODULE NAME:  GTCMOS
  805. ;*
  806. ;* DESCRIPTIVE NAME:  Realtime Clock Get CMOS byte routine
  807. ;*
  808. ;* FUNCTION:  Reads a byte from standard CMOS memory location 0Ah or
  809. ;*            higher.
  810. ;*
  811. ;* ENTRY POINT: GTCMOS
  812. ;*    LINKAGE:  NEAR from RTIOCTL
  813. ;*
  814. ;* USES:    AX and flags.
  815. ;*
  816. ;* INPUT:
  817. ;*      ES:BX = pointer to Request Block  (PktData)
  818. ;*
  819. ;* EXIT-NORMAL:
  820. ;*      Exit is via return to RTIOCTL with
  821. ;*      AX = Status word to be stored in request packet status
  822. ;*      field (DONE).
  823. ;*
  824. ;* EXIT-ERROR:
  825. ;*    RETURN CODE:      AX = Invalid parameter.
  826. ;*
  827. ;* INTERNAL REFERENCES:
  828. ;*    ROUTINES:    ClkReadCMOS
  829. ;*
  830. ;* EXTERNAL REFERENCES:
  831. ;*    STRUCTURES:
  832. ;*    ROUTINES:
  833. ;*
  834. ;*********************** END OF SPECIFICATIONS **********************
  835. page
  836. ;********************** START OF PSEUDO-CODE   **********************
  837. ;
  838. ; if can't access parameter or data
  839. ;    set AX to invalid parameter
  840. ;    return
  841. ; if requested byte >= 0Ah
  842. ;    call worker routine
  843. ; else
  844. ;    set AX to invalid parameter
  845. ;
  846. ; return
  847. ;
  848. ;*********************** END OF PSEUDO-CODE    **********************
  849.  
  850.  
  851.     ASSUME      CS:ClkSwap,DS:ClkData,ES:NOTHING,SS:NOTHING
  852. GTCMOS  PROC NEAR
  853.         public  GTCMOS
  854.  
  855.         push    bx
  856.         push    cx
  857.         push    dx
  858.         push    di
  859.         push    si
  860.  
  861.         mov     ax,word ptr es:[bx].GIOParaPack + 2
  862.         mov     di,word ptr es:[bx].GIOParaPack
  863.         mov     cx, 2                   ; parm. length
  864.         xor     dh, dh                  ; read access
  865.         mov     dl, DevHlp_VerifyAccess
  866.         call    [DevHlp]                ;verify access to parameter packet
  867.         jc      gt10
  868.  
  869.         push    es
  870.         push    bx
  871.         les     bx, es:[bx].GIOParaPack ; get parameter address
  872.         mov     al, byte ptr es:[bx]    ; get the requested CMOS addr.
  873.         inc     bx                      ; point to length byte
  874.         mov     ah, byte ptr es:[bx]    ; get the requested number of bytes
  875.         pop     bx
  876.         pop     es
  877.         cmp     al, ADDR_STATUSA        ; is request one of the RTC bytes?
  878.         jl      gt10                    ; ..yes, so exit with error
  879.         cmp     al, ADDR_CMOSRAMHI      ; is request past the max. value?
  880.         jg      gt10                    ; ..yes, so exit with error
  881.         cmp     ah, 0                   ; is number of bytes requested 0?
  882.         je      gt10                    ; ..yes, so exit with error
  883.  
  884.         xor     ch, ch                  ; clear high byte
  885.         mov     cl, ah                  ; data length
  886.         push    ax                      ; save CMOS request and length
  887.         mov     ax,word ptr es:[bx].GIODataPack + 2
  888.         mov     di,word ptr es:[bx].GIODataPack
  889.         mov     dh, 1                   ; read/write access
  890.         mov     dl, DevHlp_VerifyAccess
  891.         call    [DevHlp]                ; verify access to data packet
  892.         pop     ax                      ; restore CMOS request and length
  893.         jc      gt10
  894.  
  895.         les     di, es:[bx].GIODataPack ; get data address
  896.         mov     cmos_req.rdrq_CMOSAddr, al ; put user value in request packet
  897.         mov     cmos_req.rdrq_nbCMOS, ah ; number of CMOS bytes to read
  898.         mov     si, offset cmos_req     ; setup calling parms
  899.         mov     cx, ds                  ; (cx:si)->CMOS ReadReq packet
  900.         mov     dx, es                  ; (dx:di)->byte array for result
  901.  
  902.         push    eax                     ; save 32 bit register
  903.         CALLFAR ClkReadCMOS             ; get the value from CMOS
  904.         pop     eax                     ; restore 32 bit register
  905.         mov     ax, STDON               ; set good return code
  906.         jmp     short gt20              ; then exit
  907.  
  908. gt10:
  909.         mov     ax, STDON+STERR+13h     ; invalid parameter status
  910.  
  911. gt20:
  912.         pop     si
  913.         pop     di
  914.         pop     dx
  915.         pop     cx
  916.         pop     bx
  917.         ret
  918.  
  919. GTCMOS  ENDP
  920.  
  921.  
  922. ClkSwap ENDS
  923.  
  924.  
  925. BREAK <Clock Device Driver Utility Subroutines>
  926. ;********************** START OF SPECIFICATIONS *********************
  927. ;*
  928. ;* MODULE NAME: FixDayOfWeek
  929. ;*
  930. ;* DESCRIPTIVE NAME:  Get the right day of week
  931. ;*
  932. ;* FUNCTION:
  933. ;*      This computes the correct day of week (DOW) if the value read
  934. ;*      from the clock was 0 (uninitialized).  The DOW is computed based on
  935. ;*      the specified date (Day/Month/Year).  If the date requested is
  936. ;*      invalid, the date returned is 1-1-1980 (Tues).
  937. ;*
  938. ;* NOTE:
  939. ;*      ABIOS doesn't keep the DOW.  On NOT AT hdwr' this routine is
  940. ;*      always called with DOW = CH = 0.
  941. ;*
  942. ;* ENTRY POINT: FixDayOfWeek
  943. ;*    LINKAGE:  NEAR from FIXISEG
  944. ;*
  945. ;* USES:  Preserves all registers except CX, Flags
  946. ;*
  947. ;* INPUT:
  948. ;*    AX = Days since 1-1-80
  949. ;*    DH =  Month
  950. ;*    DL =  Day
  951. ;*
  952. ;* OUTPUT:
  953. ;*    CH =  Day Of Week (0-6)
  954. ;*
  955. ;* EXIT-NORMAL: CH = day of week (0-6)
  956. ;*
  957. ;* EXIT-ERROR: none
  958. ;*
  959. ;* INTERNAL REFERENCES:
  960. ;*    ROUTINES: GTDAYS
  961. ;*
  962. ;* EXTERNAL REFERENCES:
  963. ;*    ROUTINES: none
  964. ;*
  965. ;*********************** END OF SPECIFICATIONS **********************
  966. page
  967. ;********************** START OF PSEUDO-CODE   **********************
  968. ;
  969. ;  day_of_week = ( days + 2 ) % 7
  970. ;
  971. ;*********************** END OF PSEUDO-CODE    **********************
  972.  
  973. ClkCode SEGMENT
  974.  
  975. ;
  976. ; this data must be in CS for INT xx intercept to work
  977. ;
  978. saveDS          dw      ?               ; DS for INT xx entry
  979.  
  980. ;
  981. ; The REAL strategy routine is in the swappable code segment
  982. ;
  983.     ASSUME      CS:ClkCode,DS:ClkData,ES:NOTHING,SS:NOTHING
  984. ClkStrat        PROC FAR
  985.         public  ClkStrat
  986.         jmp     RTENTR
  987. ClkStrat        ENDP
  988.  
  989.  
  990.     ASSUME      CS:ClkCode,DS:ClkData,ES:NOTHING,SS:NOTHING
  991. FixDayOfWeek    PROC NEAR
  992.         public  FIXDAYOFWEEK
  993.  
  994.         SaveReg <AX,BX,DX>
  995.         add     ax,2                    ; 1-1-80 was a Tuesday
  996.         mov     bx,7                    ; 7 days per week
  997.         xor     dx,dx
  998.         div     bx                      ; ax = # of weeks, dx = day of week
  999.         mov     ch,dl
  1000.         RestoreReg <DX,BX,AX>
  1001.         ret
  1002. FixDayOfWeek    ENDP
  1003.  
  1004.  
  1005. ;********************** START OF SPECIFICATIONS *********************
  1006. ;*
  1007. ;* MODULE NAME:  GTDAYS
  1008. ;*
  1009. ;* DESCRIPTIVE NAME:  Calculate days since 1-1-80
  1010. ;*
  1011. ;* FUNCTION:
  1012. ;*    This routine calculates from day/month/year the number of
  1013. ;*    days elapsed since 1-1-80 and returns it to the caller.
  1014. ;*
  1015. ;*
  1016. ;* ENTRY POINT: GTDAYS
  1017. ;*    LINKAGE:  FAR from RTREAD and FIXISEG
  1018. ;*
  1019. ;* USES:  Preserves all registers except AX
  1020. ;*
  1021. ;* INPUT: (PARAMETERS)
  1022. ;*    AX = Years since 1-1-80
  1023. ;*    DH = Current month
  1024. ;*    DL = Current day
  1025. ;*
  1026. ;* OUTPUT: (RETURNED)
  1027. ;*    AX = Days since 1-1-80
  1028. ;*
  1029. ;* EXIT-NORMAL: AX = 0 to 65535
  1030. ;*
  1031. ;* EXIT-ERROR:  none
  1032. ;*
  1033. ;* INTERNAL REFERENCES:
  1034. ;*    ROUTINES: none
  1035. ;*
  1036. ;* EXTERNAL REFERENCES:
  1037. ;*    ROUTINES: none
  1038. ;*
  1039. ;*********************** END OF SPECIFICATIONS **********************
  1040. page
  1041. ;********************** START OF PSEUDO-CODE   **********************
  1042. ;
  1043. ; if Years is leap year
  1044. ;    set Feb = 29
  1045. ; else
  1046. ;    set Feb = 28
  1047. ;
  1048. ; Number of 4 years group = Years / 4
  1049. ; Number of non 4 years group = Years % 4
  1050. ; Days = DAYSIN4YR * Number of 4 years group + 366
  1051. ;        + DAYSINYR * (Number of non 4 years group - 1)
  1052. ;                    + ( days of months ) + (current day - 1)
  1053. ; return( Days )
  1054. ;
  1055. ;*********************** END OF PSEUDO-CODE    **********************
  1056.  
  1057.     ASSUME      CS:ClkCode,DS:ClkData,ES:NOTHING,SS:NOTHING
  1058. GTDAYS  PROC    FAR
  1059.         public  GTDAYS
  1060.  
  1061.         PUSH    CX                      ; Preserve only what we use
  1062.         PUSH    DX
  1063.         PUSH    BX
  1064. ; Number of non 4 years group = Years % 4
  1065.         MOV     BL,AL                   ; Copy years to CL
  1066.         AND     BL,3                    ; CL = Years Modulo 4
  1067.  
  1068. ; Number of 4 years group = Years / 4
  1069.         XOR     AH,AH                   ; Insure no high byte
  1070.         SHR     AX,1
  1071.         SHR     AX,1                    ; AX = # of 4 Year groups
  1072.         JZ      NOADD1                  ; If none, skip over days calculation
  1073.  
  1074. ; DAYSIN4YR = 5B5x = 1461 = 365 * 3 + 366
  1075. ; The followings are DAYSIN4YR * Number of 4 years group + 366
  1076.         MOV     CX,AX                   ; ...and use # of 4 year groups...
  1077.         XOR     AX,AX                   ; ...as add loop counter
  1078. ADD4YR: ADD     AX,DAYSIN4YR            ; Add one "quadyear" of days
  1079.         LOOP    ADD4YR                  ; Loop till done
  1080.  
  1081. ; if Years is leap year
  1082. ;    set Feb = 29
  1083. ; else
  1084. ;    set Feb = 28
  1085. NOADD1: OR      BL,BL                   ; Any modulo? (0 == Leap year)
  1086.         MOV     MonTab+1,29             ; Init Feb to 29 days for leap year
  1087.         JZ      NOADD2                  ; Is leap year, leave Feb and skip add
  1088.         DEC     MonTab+1                ; Not leap year, DEC Feb and add rmndr
  1089.  
  1090. ; DAYSINYR = 16Ex = 365
  1091. ; The followings are DAYSIN4YR * Number of 4 years group + 366
  1092. ;        + DAYSINYR * (Number of non 4 years group - 1)
  1093. ;
  1094.         ADD     AX,DAYSINYR+1           ; First add the leap year of the rmnd
  1095. ADDAGN: DEC     BL                      ; Any more years?
  1096.         JZ      NOADD2                  ; No, all years have been added
  1097.         ADD     AX,DAYSINYR             ; Yes, add in one normal year
  1098.         JMP     SHORT ADDAGN            ; Loop till remainder is zero
  1099.  
  1100. ; The followings are DAYSIN4YR * Number of 4 years group + 366
  1101. ;        + DAYSINYR * (Number of non 4 years group - 1)
  1102. ;                    + (current day - 1)
  1103. NOADD2: DEC     DL                      ; DL = DOM, use full days only
  1104.         ADD     AL,DL                   ; Add DOM, low byte...
  1105.         ADC     AH,0                    ; ...then high
  1106.  
  1107. ; The followings are DAYSIN4YR * Number of 4 years group + 366
  1108. ;        + DAYSINYR * (Number of non 4 years group - 1)
  1109. ;                    + ( days of months ) + (current day - 1)
  1110. ;
  1111.         MOV     BX,OFFSET MonTab        ; Point to beginning of month table
  1112. NXMNTH: DEC     DH                      ; Out of months?
  1113.         JZ      GOTMOS                  ; Yes, don't add any(more)
  1114.         ADD     AL,BYTE PTR [BX]        ; Add in this month's day count...
  1115.         ADC     AH,0                    ; ...and carry to high byte
  1116.         INC     BX                      ; Point to next month
  1117.         JMP     SHORT NXMNTH            ; Keep going
  1118.  
  1119. GOTMOS:
  1120.         POP     BX                      ; Give him back his stuff
  1121.         POP     DX
  1122.         POP     CX
  1123.         RET
  1124.  
  1125. GTDAYS  ENDP
  1126.  
  1127.  
  1128. ClkCode ENDS
  1129.  
  1130.         END
  1131.