home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / hrtimer.zip / HRTIMER.ASM < prev    next >
Assembly Source File  |  1992-05-26  |  33KB  |  695 lines

  1. ;**********************************************************************
  2. ;* MODULE NAME :  hrtimer.asm            AUTHOR:  Rick Fishman        *
  3. ;* DATE WRITTEN:  11-23-91                                            *
  4. ;*                                                                    *
  5. ;* DESCRIPTION:                                                       *
  6. ;*                                                                    *
  7. ;*  This device driver provides a high-resolution timer for OS/2      *
  8. ;*                                                                    *
  9. ;*  The source code was obtained from the Fall 1991 issue of IBM      *
  10. ;*  Personal Systems Developer magazine.                              *
  11. ;*                                                                    *
  12. ;**********************************************************************
  13.  
  14.         .286
  15.  
  16. ;*********************************************************************
  17. ;*----------------------------- EQUATES -----------------------------*
  18. ;*********************************************************************
  19.  
  20. RP_StatusError          equ     80h     ; RP_Status error bit
  21. RP_StatusDone           equ     01h     ; RP_Status done bit
  22.  
  23.                                         ; DEVICE HELPER FUNCTIONS
  24. DevHlp_PhysToVirt       equ     15h     ; Convert a physical address to virtual
  25. DevHlp_SetTimer         equ     1Dh     ; Hook into the Motorola timer int
  26. DevHlp_UnPhysToVirt     equ     32h     ; Release virtual memory
  27.  
  28. i8253CountRegister      equ     40h     ; 8253 Counter Register
  29. i8253CtrlByteRegister   equ     43h     ; 8253 Control Byte Register
  30. i8253CmdReadCtrZero     equ     0       ; Latch Command
  31. i8253CmdInitCtrZero     equ     34h     ; LSB first, MSB second, Rate generator
  32.  
  33. NanosInATick            equ     840     ; Number of nanoseconds in 1 8253 tick
  34. MillionDividedBy64      equ     15625   ; 1,000,000 divided by 64
  35.  
  36. cr                      equ     0dh     ; ASCII code for carraige return
  37. lf                      equ     0ah     ; ASCII code for line feed
  38.  
  39. stdout                  equ     1       ; File handle for standard output
  40.  
  41. ;**********************************************************************
  42. ;*------------------------------ MACROS ------------------------------*
  43. ;**********************************************************************
  44.  
  45. Read8253IntoCx  MACRO                      ; Put 8253 counter 0 value in cx
  46.  
  47.         mov     al, i8253CmdReadCtrZero    ; Request Counter Latch
  48.         out     i8253CtrlByteRegister, al
  49.         in      al, i8253CountRegister     ; Get LSB and save it
  50.         mov     cl, al
  51.         in      al, i8253CountRegister     ; Get MSB and save it
  52.         mov     ch, al
  53.  
  54.                 ENDM
  55.  
  56. ;**********************************************************************
  57. ;*---------------------------- STRUCTURES ----------------------------*
  58. ;**********************************************************************
  59.  
  60. ReadData                struc           ; Data passed to caller of DosRead
  61.  
  62.     RD_Millisecs        dd      ?       ; Current millisecond count
  63.     RD_Nanosecs         dd      ?       ; Current nanosecond count
  64.     RD_Version          dw      ?       ; HRTIMER.SYS version - hi
  65.     RD_Revision         dw      ?       ; HRTIMER.SYS version - lo
  66.  
  67. ReadData                ends
  68.  
  69.  
  70. RequestPacket           struc           ; Request Packet header
  71.  
  72.     RP_Length           db      ?       ; Request Packet length
  73.                         db      ?       ; Block devices only
  74.     RP_CommandCode      db      ?       ; Command
  75.     RP_ErrorCode        db      ?       ; Command Error Code
  76.     RP_Status           db      ?       ; Command Status Code
  77.                         dd      ?       ; Reserved
  78.                         dd      ?       ; Queue Linkage - not used here
  79.  
  80. RequestPacket           ends
  81.  
  82.  
  83. RequestPktInit          struc           ; Initialization Request Packet
  84.  
  85.                         db 13 dup(?)    ; Request Packet Header
  86.     RPI_NumberUnits     db      ?       ; Block devices only - used to cancel
  87.                                         ; DevHlp pointer in, on return from init
  88.     RPI_CodeSegLen      dw      ?       ;     Code segment length
  89.     RPI_DataSegLen      dw      ?       ;     Data segment length
  90.     RPI_CommandLine     dd      ?       ; Pointer to command line
  91.                         db      ?       ; Block devices only
  92.  
  93. RequestPktInit          ends
  94.  
  95.  
  96. RequestPktRead          struc           ; Read Request Packet (from DosRead)
  97.  
  98.                         db 13 dup(?)    ; Request Packet header
  99.                         db      ?       ; Block devices only
  100.     RPR_TransferAddr    dd      ?       ; Physical address of read buffer
  101.     RPR_BytesRequested  dw      ?       ; Number of bytes to read
  102.  
  103. RequestPktRead          ends
  104.  
  105. ;**********************************************************************
  106. ;*----------------------------- EXTERNS ------------------------------*
  107. ;**********************************************************************
  108.  
  109.         extrn  DosWrite:far
  110.  
  111. ;**********************************************************************
  112. ;*-------------------------- DATA SEGMENT ----------------------------*
  113. ;**********************************************************************
  114.  
  115. DGROUP          group   _DATA
  116.  
  117. _DATA           SEGMENT word public  'DATA'
  118.  
  119. ;**********************************************************************
  120. ;*---------------------- Device Driver Header ------------------------*
  121. ;**********************************************************************
  122.  
  123. TimerHeader             label   byte            ; Device Driver header
  124.  
  125.     NextDeviceDriver    dd      -1              ; Last driver in chain
  126.     DeviceAttribute     dw      1000100010000000B  ; Char,Open/Close,OS/2 1.1
  127.     StrategyOffset      dw      Strategy        ; Offset of Strategy Routine
  128.                         dw      -1              ; IDC - not used here
  129.     DeviceName          db      'TIMER$  '      ; Driver Device-Name
  130.                         db 8 dup(0)             ; Reserved
  131.  
  132. ;**********************************************************************
  133. ;*------------ Data areas used by Strategy and Interrupt -------------*
  134. ;**********************************************************************
  135.  
  136. DevHlpPtr               dd      ?               ; Pointer to Device Helper
  137.                                                 ;   routine - Set at init rqst
  138. ReadDataBuf             ReadData < 0, 0, 1, 0 > ; Buffer to return to caller
  139.  
  140. ReadDataLen             equ     $ - ReadDataBuf ; Length of ReadDataBuf
  141.  
  142. UserCount               dw      0               ; Number of active users
  143.  
  144. Last8253                dw      ?               ; 8253 ticks at last interrupt
  145.  
  146. BytesWritten            dw      ?               ; Used for DosWrite calls
  147.  
  148. ;**********************************************************************
  149. ;*--------------------- Command (Request) List -----------------------*
  150. ;**********************************************************************
  151.  
  152. CmdList         label   word
  153.  
  154.                 dw      Initialize      ;  0 = Initialize driver
  155.                 dw      Error           ;  1 = Media Check
  156.                 dw      Error           ;  2 = Build BPB
  157.                 dw      Error           ;  3 = Not used
  158.                 dw      Read            ;  4 = Read from device
  159.                 dw      DummyRet        ;  5 = Non-destructive read
  160.                 dw      DummyRet        ;  6 = Return input status
  161.                 dw      DummyRet        ;  7 = Flush input buffers
  162.                 dw      DummyRet        ;  8 = Write to device
  163.                 dw      DummyRet        ;  9 = Write with verify
  164.                 dw      DummyRet        ; 10 = Return output status
  165.                 dw      DummyRet        ; 11 = Flush output buffers
  166.                 dw      Error           ; 12 = Not used
  167.                 dw      Open            ; 13 = Device open
  168.                 dw      Close           ; 14 = Device close
  169.  
  170. MaxCmd          equ     ( $ - CmdList ) / TYPE CmdList
  171.  
  172. CopyRightMsg    db      cr, lf
  173.                 db      'High Resolution Timer - Version 1.0', cr, lf
  174.                 db      'Courtesy of Code Blazers, Inc. 1991', cr, lf
  175.                 db      'Source code from IBM Personal Systems Developer '
  176.                 db      '(Fall 1991)', cr, lf, lf
  177. CopyRightMsgLen equ     $ - CopyRightMsg
  178.  
  179. InitNotOkMsg    db      'HRTIMER.SYS Initialization Failed', cr, lf
  180. InitNotOkMsgLen equ     $ - InitNotOkMsg
  181.  
  182. LastData        equ     $ - CopyRightMsg
  183.  
  184. _DATA           ENDS
  185.  
  186. ;**********************************************************************
  187. ;*-------------------------- CODE SEGMENT ----------------------------*
  188. ;**********************************************************************
  189.  
  190. _TEXT           SEGMENT word public  'CODE'
  191.  
  192.                 assume cs:_TEXT, ds:DGROUP
  193.  
  194. ;**********************************************************************
  195. ;*---------------------------- Strategy ------------------------------*
  196. ;*                                                                    *
  197. ;*  STRATEGY ENTRY POINT.                                             *
  198. ;*                                                                    *
  199. ;*  INPUT: ES:BX = address of request packet                          *
  200. ;*                                                                    *
  201. ;*  1 -                                                               *
  202. ;*                                                                    *
  203. ;*  OUTPUT: nothing                                                   *
  204. ;*                                                                    *
  205. ;*--------------------------------------------------------------------*
  206. ;**********************************************************************
  207.  
  208. Strategy        PROC    far
  209.  
  210.         cmp     es:[bx].RP_CommandCode, MaxCmd  ; Command within jumb table?
  211.         jbe     JumpCmd                         ;   YES: execute command routine
  212.  
  213.         call    Error                           ;   NO: send back error
  214.         jmp     short exit                      ;       and exit
  215.  
  216. JumpCmd:
  217.  
  218.         mov     al, es:[bx].RP_CommandCode      ; Isolate command,
  219.         cbw                                     ;   convert to word,
  220.         mov     si, ax                          ;   put into index register,
  221.         shl     si, 1                           ;   multiply by 2 so it is a
  222.                                                 ;   word rather than byte offset
  223.         call    CmdList [si]                    ; Call command routine
  224.  
  225. exit:
  226.         ret                                     ; Return to operating system
  227.  
  228. Strategy        ENDP
  229.  
  230. ;**********************************************************************
  231. ;*------------------------------ Read --------------------------------*
  232. ;*                                                                    *
  233. ;*  HANDLE A READ REQUEST.                                            *
  234. ;*                                                                    *
  235. ;*  INPUT: ES:BX = address of request packet                          *
  236. ;*                                                                    *
  237. ;*  1.                                                                *
  238. ;*                                                                    *
  239. ;*  OUTPUT: status byte set                                           *
  240. ;*                                                                    *
  241. ;*--------------------------------------------------------------------*
  242. ;**********************************************************************
  243.  
  244. Read            PROC    near
  245.  
  246.         cli                             ; Disable interrupts
  247.  
  248.         Read8253IntoCx                  ; Get current tick count
  249.  
  250.         call    UpdateTimeStamp         ; Update running time stamp
  251.  
  252.         cmp     es:[bx].RPR_BytesRequested, ReadDataLen
  253.         jl      SetError                ; Caller's buffer is too small
  254.  
  255.         push    es                      ; Save packet pointer
  256.         push    bx
  257.  
  258.         mov     ax, word ptr es:[bx].RPR_TransferAddr + 2   ; Store ReadPacket
  259.         mov     cx, es:[bx].RPR_BytesRequested              ;   variables in
  260.         mov     bx, word ptr es:[bx].RPR_TransferAddr       ;   registers
  261.  
  262.         mov     dh, 1                   ; 1 = Store result in ES:DI
  263.         mov     dl, DevHlp_PhysToVirt   ; Use the PhysToVirt function
  264.         call    DevHlpPtr               ; Call the Device Helper routine
  265.         jc      DevHlpError
  266.  
  267.         mov     si, offset ReadDataBuf  ; Address of timestamp data
  268.         mov     cx, (ReadDataLen / 2)   ; Number of words in timestamp data
  269.         cld                             ; Move forward
  270.         rep     movsw                   ; Move that data
  271.  
  272.         sti                             ; Enable interrupts
  273.  
  274.         mov     dl, DevHlp_UnPhysToVirt ; Free Virtual Memory function
  275.         call    DevHlpPtr               ; Call the Device Helper routine
  276.  
  277.         pop     bx                      ; Restore packet pointer
  278.         pop     es
  279.  
  280.         mov     es:[bx].RPR_BytesRequested, ReadDataLen
  281.  
  282.         jmp     short GetOut
  283.  
  284. DevHlpError:
  285.  
  286.         pop     bx                      ; Restore packet pointer
  287.         pop     es
  288.  
  289. SetError:
  290.  
  291.         mov     es:[bx].RPR_BytesRequested, 0
  292.  
  293.         sti                             ; Enable Interrupts
  294.  
  295. GetOut:
  296.         or      byte ptr es:[bx].RP_Status, RP_StatusDone
  297.  
  298.         ret
  299.  
  300. Read            ENDP
  301.  
  302. ;**********************************************************************
  303. ;*------------------------------ Open --------------------------------*
  304. ;*                                                                    *
  305. ;*  HANDLE AN OPEN REQUEST.                                           *
  306. ;*                                                                    *
  307. ;*  INPUT: ES:BX = address of request packet                          *
  308. ;*                                                                    *
  309. ;*  1 -                                                               *
  310. ;*                                                                    *
  311. ;*  OUTPUT: status byte set                                           *
  312. ;*                                                                    *
  313. ;*--------------------------------------------------------------------*
  314. ;**********************************************************************
  315.  
  316. Open            PROC    near
  317.  
  318.         cli                                     ; Disable interrupts
  319.  
  320.         cmp     UserCount, 0                    ; If not first user,
  321.         jnz     AddlUser                        ;    bypass initialization
  322.  
  323.         mov     word ptr ReadDataBuf,     0     ; Set buffer to 0. This is
  324.         mov     word ptr ReadDataBuf + 2, 0     ;    faster than saving and
  325.         mov     word ptr ReadDataBuf + 4, 0     ;    restoring ES in order to
  326.         mov     word ptr ReadDataBuf + 6, 0     ;    use STOSW
  327.  
  328.         Read8253IntoCx                          ; Get current tick count
  329.  
  330.         mov     Last8253, cx                    ; Save it for next interrupt
  331.  
  332. AddlUser:
  333.  
  334.         inc     UserCount                       ; Add another user
  335.  
  336.         sti                                     ; Enable interrupts
  337.  
  338.         or      byte ptr es:[bx].RP_Status, RP_StatusDone  ; Indicate DONE
  339.  
  340.         ret
  341.  
  342. Open            ENDP
  343.  
  344. ;**********************************************************************
  345. ;*------------------------------ Close -------------------------------*
  346. ;*                                                                    *
  347. ;*  HANDLE A CLOSE REQUEST.                                           *
  348. ;*                                                                    *
  349. ;*  INPUT: ES:BX = address of request packet                          *
  350. ;*                                                                    *
  351. ;*  1 -                                                               *
  352. ;*                                                                    *
  353. ;*  OUTPUT: status byte set                                           *
  354. ;*                                                                    *
  355. ;*--------------------------------------------------------------------*
  356. ;**********************************************************************
  357.  
  358. Close           PROC    near
  359.  
  360.         cli                             ; Disable interrupts
  361.  
  362.         cmp     UserCount, 0            ; If no users, don't do anything
  363.         jz      NoUsers
  364.  
  365.         dec     UserCount               ; Decrement number of users
  366.  
  367. NoUsers:
  368.         sti                             ; Enable interrupts
  369.  
  370.         or      byte ptr es:[bx].RP_Status, RP_StatusDone  ; Indicate DONE
  371.  
  372.         ret
  373.  
  374. Close           ENDP
  375.  
  376. ;**********************************************************************
  377. ;*------------------------------ Error -------------------------------*
  378. ;*                                                                    *
  379. ;*  HANDLE AN UNSUPPORTED REQUEST.                                    *
  380. ;*                                                                    *
  381. ;*  INPUT: ES:BX = address of request packet                          *
  382. ;*                                                                    *
  383. ;*  1 -                                                               *
  384. ;*                                                                    *
  385. ;*  OUTPUT: status byte set                                           *
  386. ;*                                                                    *
  387. ;*--------------------------------------------------------------------*
  388. ;**********************************************************************
  389.  
  390. Error           PROC    near
  391.  
  392.         mov     byte ptr es:[bx].RP_ErrorCode, 3  ; OS/2 Unknown Command RC
  393.                                                   ; Indicate DONE and ERROR
  394.         or      byte ptr es:[bx].RP_Status, RP_StatusError + RP_StatusDone
  395.  
  396.         ret
  397.  
  398. Error           ENDP
  399.  
  400. ;**********************************************************************
  401. ;*---------------------------- DummyRet ------------------------------*
  402. ;*                                                                    *
  403. ;*  HANDLE A REQUIRED BUT UNUSED REQUEST                              *
  404. ;*                                                                    *
  405. ;*  INPUT: ES:BX = address of request packet                          *
  406. ;*                                                                    *
  407. ;*  1 -                                                               *
  408. ;*                                                                    *
  409. ;*  OUTPUT: status byte set                                           *
  410. ;*                                                                    *
  411. ;*--------------------------------------------------------------------*
  412. ;**********************************************************************
  413.  
  414. DummyRet        PROC    near
  415.  
  416.         or      byte ptr es:[bx].RP_Status, RP_StatusDone  ; Indicate DONE
  417.  
  418.         ret
  419.  
  420. DummyRet        ENDP
  421.  
  422. ;**********************************************************************
  423. ;*---------------------------- Interrupt -----------------------------*
  424. ;*                                                                    *
  425. ;*  DEVICE DRIVER TIME-INTERRUPT ROUTINE. CALLED ON EACH OS/2 CLOCK   *
  426. ;*  TICK (MC146818 CHIP) VIA THE SetTimer DevHlp.                     *
  427. ;*                                                                    *
  428. ;*  INPUT: nothing                                                    *
  429. ;*                                                                    *
  430. ;*  1 -                                                               *
  431. ;*                                                                    *
  432. ;*  OUTPUT: Updated time stamp                                        *
  433. ;*                                                                    *
  434. ;*--------------------------------------------------------------------*
  435. ;**********************************************************************
  436.  
  437. Interrupt       PROC    far
  438.  
  439.         pushf                           ; Save flags
  440.  
  441.         cmp     UserCount, 0            ; If no users, no need to do anything
  442.         jz      NoUser
  443.  
  444.         push    ax                      ; Save registers
  445.         push    bx
  446.         push    cx
  447.         push    dx
  448.  
  449.         cli                             ; Disable interrupts
  450.  
  451.         Read8253IntoCx                  ; Get current tick count
  452.  
  453.         sti                             ; Enable interrupts
  454.  
  455.         call    UpdateTimeStamp         ; Update the running time stamp
  456.  
  457.         pop     dx                      ; Restore registers
  458.         pop     cx
  459.         pop     bx
  460.         pop     ax
  461.  
  462. NoUser:
  463.         popf                            ; Restore flags
  464.  
  465.         ret
  466.  
  467. Interrupt       ENDP
  468.  
  469. ;**********************************************************************
  470. ;*------------------------- UpdateTimeStamp --------------------------*
  471. ;*                                                                    *
  472. ;*  UPDATE THE RUNNING TIMESTAMP.                                     *
  473. ;*                                                                    *
  474. ;*  INPUT: CX contains current 8253 tick count                        *
  475. ;*                                                                    *
  476. ;*  1 -                                                               *
  477. ;*                                                                    *
  478. ;*  OUTPUT: ReadDataBuf contains current time stamp,                  *
  479. ;*          Last8253 contains prior 8253 tick count,                  *
  480. ;*          AX, DX modified                                           *
  481. ;*                                                                    *
  482. ;*  NOTE: The 8253 counter counts from 65536 to zero                  *
  483. ;*                                                                    *
  484. ;*--------------------------------------------------------------------*
  485. ;**********************************************************************
  486.  
  487. UpdateTimeStamp PROC    near
  488.  
  489.         push    bx                      ; Save bx for caller
  490.  
  491.         ;*******************************************************************
  492.         ;* Determine the number of nanoseconds passed since the last       *
  493.         ;*  timestamp update (NanosecsDelta):                              *
  494.         ;*                                                                 *
  495.         ;*     if( Last8253 >= cx )                                        *
  496.         ;*         NanosecsDelta = (Last8253 - cx) * NanosIn1Tick          *
  497.         ;*     else                                                        *
  498.         ;*         NanosecsDelta = (0xFFFF - cx + Last8253) * NanosInATick *
  499.         ;*                                                                 *
  500.         ;* where cx is the current 8253 tick count                         *
  501.         ;*   and NanosInATick is the number of nanoseconds in an 8253 tick *
  502.         ;*                                                                 *
  503.         ;*******************************************************************
  504.  
  505.         mov     ax, Last8253            ; Get prior tick count
  506.  
  507.         cmp     ax, cx                  ; If it has wrapped (i.e. gone to zero
  508.         jae     NoWrap                  ;   and started again from 65536):
  509.  
  510.                                         ; Same as: mov  dx, 0FFFFh
  511.         sub     ax, cx                  ;          sub  dx, cx
  512.         dec     ax                      ;          add  dx, ax
  513.                                         ;          xchg ax, dx
  514.                                         ; Only faster....
  515.         jmp     short CvtNsecs
  516.  
  517. NoWrap:
  518.         sub     ax, cx                  ; Difference between current tick count
  519.                                         ;   and last tick count
  520. CvtNsecs:
  521.  
  522.         mov     dx, NanosInATick        ; Get total nanos from total ticks
  523.         mul     dx
  524.  
  525.         mov     Last8253, cx            ; Save tick count for next interrupt
  526.  
  527.         ;*******************************************************************
  528.         ;* Update the running timestamp and normalize the millisecond and  *
  529.         ;*  nanosecond portions:                                           *
  530.         ;*                                                                 *
  531.         ;*     Nanoseconds += NanosecsDelta;                               *
  532.         ;*                                                                 *
  533.         ;*     if( Nanoseconds >= 1000000 )                                *
  534.         ;*     {                                                           *
  535.         ;*         Milliseconds = Milliseconds + (Nanoseconds / 1000000);  *
  536.         ;*                                                                 *
  537.         ;*         Nanoseconds = Nanoseconds % 1000000;                    *
  538.         ;*     }                                                           *
  539.         ;*                                                                 *
  540.         ;* where Nanoseconds is ReadDataBuf.RD_Nanosecs                    *
  541.         ;*   and Milliseconds is ReadDataBuf.RD_Millisecs                  *
  542.         ;*                                                                 *
  543.         ;* NOTE: 1000000 = 0xF4240                                         *
  544.         ;*                                                                 *
  545.         ;*******************************************************************
  546.  
  547.         add     word ptr ReadDataBuf.RD_Nanosecs, ax       ; Add lo-order word
  548.         adc     word ptr ReadDataBuf.RD_Nanosecs + 2, dx   ; Add hi-order word
  549.         cmp     word ptr ReadDataBuf.RD_Nanosecs + 2, 0Fh  ; > million?
  550.         jb      UpdateExit                                 ;   NO: exit
  551.         ja      Normalize                                  ;   YES: normalize
  552.  
  553.         cmp     word ptr ReadDataBuf.RD_Nanosecs, 4240h    ; < million?
  554.         jb      UpdateExit                                 ;   YES: exit
  555.                                                            ;   NO: normalize
  556. Normalize:
  557.  
  558.         ;*******************************************************************
  559.         ;* We need the result and remainder from dividing current nanos    *
  560.         ;*  by 1,000,000. The 80286 doesn't support double-word divisors   *
  561.         ;*  so we must stage the division. So we first divide by a number  *
  562.         ;*  that is the quotient of 1,000,000 and 64. Then we divide by 64.*
  563.         ;*  To do this:                                                    *
  564.         ;*                                                                 *
  565.         ;*  1. Divide Nanoseconds by (1000000 / 64). Save the remainder.   *
  566.         ;*                                                                 *
  567.         ;*  2. Divide the result of that by 64. Save the remainder.        *
  568.         ;*                                                                 *
  569.         ;*  3. Multiply the current remainder by (1000000 /64).            *
  570.         ;*                                                                 *
  571.         ;*  4. Add in the first remainder.                                 *
  572.         ;*                                                                 *
  573.         ;* We're left with the result from step 2 and the remainder from   *
  574.         ;*  step 4.                                                        *
  575.         ;*                                                                 *
  576.         ;*******************************************************************
  577.  
  578.         mov     dx, word ptr ReadDataBuf.RD_Nanosecs + 2 ; hi-order word
  579.         mov     ax, word ptr ReadDataBuf.RD_Nanosecs     ; lo-order word
  580.         mov     bx, MillionDividedBy64                   ; divisor
  581.         div     bx                                       ; do the divide
  582.  
  583.         mov     bx, dx                  ; Remainder
  584.         mov     dx, ax                  ; Quotient
  585.         and     dx, 00111111b           ; Low 6 bits = remainder from the next
  586.                                         ;   divide (lower 6 bits are lost
  587.                                         ;   during the 'shr ax, 6')
  588.         mov     cx, dx
  589.         shr     ax, 6                   ; Divide by 64
  590.  
  591.         xchg    ax, cx
  592.  
  593.         mov     dx, MillionDividedBy64  ; Multiply remainder from step 4
  594.                                         ;    by (1000000 / 64)
  595.         mul     dx
  596.  
  597.         add     ax, bx                  ; Add remainder from step 2
  598.  
  599.         mov     bx, 0                   ; Compensate for doubleword addition
  600.         adc     dx, bx
  601.  
  602.         add     word ptr ReadDataBuf.RD_Millisecs, cx      ; Update millisecs
  603.         adc     word ptr ReadDataBuf.RD_Millisecs + 2, bx  ; bx is still 0
  604.         mov     word ptr ReadDataBuf.RD_Nanosecs, ax       ; Update nanosecs
  605.         mov     word ptr ReadDataBuf.RD_Nanosecs + 2, dx
  606.  
  607. UpdateExit:
  608.  
  609.         pop     bx                      ; Restore BX
  610.  
  611.         ret
  612.  
  613. UpdateTimeStamp ENDP
  614.  
  615. ;**********************************************************************
  616. ;*---------------------------- Initialize ----------------------------*
  617. ;*                                                                    *
  618. ;*  DEVICE DRIVER INTIALIZATION ROUTINE (DISCARDED BY OS2 AFTER USE)  *
  619. ;*                                                                    *
  620. ;*  INPUT: ES:BX = address of init packet                             *
  621. ;*                                                                    *
  622. ;*  1 -                                                               *
  623. ;*                                                                    *
  624. ;*  OUTPUT: nothing                                                   *
  625. ;*                                                                    *
  626. ;*--------------------------------------------------------------------*
  627. ;**********************************************************************
  628.  
  629. Initialize      PROC    near
  630.  
  631.         push    stdout                          ; Write copyright info
  632.         push    ds
  633.         push    offset CopyRightMsg
  634.         push    CopyRightMsgLen
  635.         push    ds
  636.         push    offset BytesWritten
  637.         call    DosWrite
  638.  
  639.         mov     ax, word ptr es:[bx].RPI_CodeSegLen   ; Save pointer to
  640.         mov     word ptr DevHlpPtr , ax               ;   Device Helper routine
  641.         mov     ax, word ptr es:[bx].RPI_DataSegLen
  642.         mov     word ptr DevHlpPtr  + 2, ax
  643.  
  644.         cli                                     ; Disable interrupts
  645.  
  646.         mov     al, i8253CmdInitCtrZero         ; Set 8253 counter 0 to mode 2
  647.         out     i8253CtrlByteRegister, al       ;     ( Rate generator )
  648.  
  649.         xor     ax, ax                          ; Init Count Register to zero
  650.         out     i8253CountRegister, al          ;   by writing 0 to LSB
  651.         out     i8253CountRegister, al          ;   and MSB
  652.  
  653.         sti                                     ; Enable interrupts
  654.  
  655.         mov     ax, offset Interrupt            ; Our timer hook address
  656.         mov     dl, DevHlp_SetTimer             ; SetTimer function
  657.         call    DevHlpPtr                       ; Call Device Helper routine
  658.         jnc     NoError
  659.                                                 ; ****** ERROR ******
  660.         push    stdout                          ; Write error message
  661.         push    ds
  662.         push    offset InitNotOkMsg
  663.         push    InitNotOkMsgLen
  664.         push    ds
  665.         push    offset BytesWritten
  666.         call    DosWrite
  667.  
  668.         mov     es:[bx].RPI_NumberUnits, 0      ; Zero these fields so OS/2
  669.         mov     es:[bx].RPI_CodeSegLen, 0       ;    knows to cancel this
  670.         mov     es:[bx].RPI_DataSegLen, 0       ;    device driver
  671.  
  672.         mov     byte ptr es:[bx].RP_ErrorCode, 0ch      ; General Failure error
  673.         or      byte ptr es:[bx].RP_Status, RP_StatusError ; Error condition
  674.  
  675.         jmp     InitExit                        ; **** END ERROR ****
  676.  
  677. NoError:
  678.         mov     es:[bx].RPI_CodeSegLen, offset Initialize   ; End of code seg
  679.         mov     es:[bx].RPI_DataSegLen, offset LastData     ; End of data seg
  680.  
  681. InitExit:
  682.         or      byte ptr es:[bx].RP_Status, RP_StatusDone   ; Indicate DONE
  683.  
  684.         ret
  685.  
  686. Initialize      ENDP
  687.  
  688. _TEXT           ENDS
  689.  
  690. END
  691.  
  692. ;**********************************************************************
  693. ;*                       END OF SOURCE CODE                           *
  694. ;**********************************************************************
  695.