Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

705 lines
20 KiB

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;
  3. ; LOCAL.ASM
  4. ;
  5. ; Copyright (c) Microsoft Corporation 1989, 1990. All rights reserved.
  6. ;
  7. ; This module contains the routines which interface with the
  8. ; timer counter hardware itself.
  9. ;
  10. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  11. ?PLM=1 ; pascal call convention
  12. ?WIN=0 ; Windows prolog/epilog code
  13. ?DF=1
  14. PMODE=1
  15. .xlist
  16. include cmacros.inc
  17. include windows.inc
  18. include mmddk.inc
  19. include mmsystem.inc
  20. include timer.inc
  21. .list
  22. externFP DriverCallback ; in MMSYSTEM.DLL
  23. externFP StackEnter ; in MMSYSTEM.DLL
  24. externFP StackLeave ; in MMSYSTEM.DLL
  25. externFP tddEndMinPeriod ; timer.asm
  26. externA __WinFlags ; Somewhere in Kernel ?
  27. .286p
  28. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  29. ;
  30. ; Local data segment
  31. ;
  32. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  33. externW Events
  34. externD lpOLDISR
  35. externB PS2_MCA
  36. sBegin Data
  37. ; Current Time
  38. public CurTime
  39. CurTime dw 3 dup(0) ; 48 bit current tick count.
  40. public wProgTime
  41. wProgTime dw 0 ; Time currently programmed into timer chip
  42. ; ...NOTE 0=64k !!!
  43. public wNextTime
  44. wNextTime dw 0 ; Time next programmed into timer chip
  45. public nInt8Count
  46. nInt8Count dw 0 ; # times int8 handler re-entered
  47. ifdef DEBUG
  48. public RModeIntCount, PModeIntCount
  49. RModeIntCount dd 0
  50. PModeIntCount dd 0
  51. endif
  52. public IntCount
  53. IntCount dw 0
  54. fBIOSCall dw 0 ; Bios callback needed: TRUE or FALSE
  55. fIntsOn dw 0 ; Interrupts have already been turned back on
  56. ifdef RMODE_INT
  57. dRModeTicks dd ? ; Temporary storage for Rmode ticks
  58. endif
  59. public dTickUpdate
  60. dTickUpdate dd 0 ; Amount to actually update times with
  61. sEnd Data
  62. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  63. ;
  64. ; Code segment
  65. ;
  66. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  67. sBegin Code286
  68. assumes cs,Code286
  69. assumes ds,data
  70. assumes es,nothing
  71. CodeFixWinFlags dw __WinFlags
  72. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  73. ;
  74. ; Local (private) functions
  75. ;
  76. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  77. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  78. ;
  79. ; @doc INTERNAL
  80. ;
  81. ; @asm tddRModeISR | Service routine for timer interrupts on IRQ 0.
  82. ; when in REAL mode
  83. ;
  84. ; @comm
  85. ;
  86. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  87. ifdef RMODE_INT
  88. assumes ds,nothing
  89. assumes es,nothing
  90. externD RModeOldISR
  91. public RModeDataSegment
  92. RModeDataSegment dw 0
  93. public tddRmodeISR
  94. tddRmodeISR proc far
  95. push ds
  96. push ax
  97. push bx
  98. mov ax,cs:[RModeDataSegment]
  99. mov ds,ax
  100. assumes ds,Data
  101. inc [IntCount]
  102. ifdef DEBUG
  103. add [RModeIntCount].lo,1
  104. adc [RModeIntCount].hi,0
  105. endif
  106. mov ax,[wNextTime] ; Next time programmed into timer chip
  107. xchg ax,[wProgTime] ; Update current time if it was reset
  108. xor bx,bx
  109. dec ax ; convert 0 -> 64k
  110. add ax,1
  111. adc bx,bx
  112. cmp [nInt8Count],1 ; Do not allow multiple re-entrancy
  113. jge tddRmodeISRNormalExit
  114. cld
  115. push di
  116. push cx
  117. mov di,DataOFFSET Events ; DS:DI --> first event
  118. mov cx,MAXEVENTS
  119. tddRmodeISRLoop:
  120. cmp [di].evID,0 ; is this event active?
  121. jz tddRmodeISRNext
  122. cmp [di].evDestroy,EVENT_DESTROYING
  123. je tddRmodeISRNext
  124. test [di].evFlags,TIME_BIOSEVENT
  125. jz tddRmodeISRNext
  126. mov dRModeTicks.lo,ax
  127. mov dRModeTicks.hi,bx
  128. add ax,[dTickUpdate.lo]
  129. adc bx,[dTickUpdate.hi]
  130. cmp [di].evTime.hi,bx
  131. jg @f
  132. jl tddRmodeISRChain
  133. cmp [di].evTime.lo,ax
  134. jle tddRmodeISRChain
  135. @@:
  136. mov ax,dRModeTicks.lo
  137. mov bx,dRModeTicks.hi
  138. jmp tddRmodeISRSearchExit
  139. tddRmodeISRChain:
  140. pop cx
  141. pop di
  142. pop bx
  143. pop ax
  144. push [RModeOldISR.hi]
  145. push [RModeOldISR.lo]
  146. push bp ; Restore DS from stack
  147. mov bp,sp
  148. mov ds,[bp+6] ; stack: [ds] [RModeOldISR.hi] [RModeOldISR.lo] [bp]
  149. assumes ds,nothing
  150. pop bp
  151. retf 2
  152. tddRmodeISRNext:
  153. assumes ds,Data
  154. add di,SizeEvent ; Increment to next event slot
  155. loop tddRmodeISRLoop
  156. tddRmodeISRSearchExit:
  157. pop cx
  158. pop di
  159. tddRmodeISRNormalExit:
  160. add CurTime[0],ax
  161. adc CurTime[2],bx
  162. adc CurTime[4],0
  163. add [dTickUpdate.lo],ax ; Update total needed to be added
  164. adc [dTickUpdate.hi],bx
  165. ifndef NEC_98
  166. cmp PS2_MCA,0 ; Check for a PS/2 Micro Channel
  167. jz @f
  168. in al,PS2_SysCtrlPortB ; Get current System Control Port status
  169. or al,PS2_LatchBit ; Set latch clear bit
  170. IO_Delay
  171. out PS2_SysCtrlPortB,al ; Set new System Control Port status
  172. @@:
  173. endif ; NEC_98
  174. mov al,SPECIFIC_EOI ; specific EOI for IRQ 0 interrupt line
  175. out PICDATA,al ; send End-Of-Interrupt to PIC DATA port
  176. pop bx
  177. pop ax
  178. pop ds
  179. assumes ds,nothing
  180. iret
  181. tddRmodeISR endp
  182. endif
  183. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  184. ;
  185. ;@doc INTERNAL TIMER
  186. ;
  187. ;@asm tddISR |
  188. ; Service routine for timer interrupts on IRQ 0.
  189. ;
  190. ; The ISR runs through all the event slots available, looking for
  191. ; slots that are currently in used, and are not currently being
  192. ; destroyed. For each valid event found the callback time is updated.
  193. ; After all times have been updated, the table is run through again,
  194. ; calling all events that are due, and removing any due events that are
  195. ; oneshots. By updating all the events first, any new events that are
  196. ; created during a callback will not be accidentally called too early.
  197. ;
  198. ; Note that interrupts are not immediately restored, as this causes even
  199. ; more problems with slow machines. Also, the EOI is not sent to the
  200. ; PIC, as the BIOS interrupt handler does a non-specific EOI, and this
  201. ; would in turn EOI the last outstanding interrupt.
  202. ;
  203. ; First there is a special check for the presence of a Micro Channel,
  204. ; in which case, the System Control Port B must have bit 7 set in order
  205. ; to have the IRQ 0 latch released. This flag is aquired during Enable
  206. ; time with an int 15h service C0h, requesting machine information, which
  207. ; includes the presence of a Micro Channel.
  208. ;
  209. ; The ISR then updates the tick count based on the count that was in
  210. ; the timer's CE register. While retrieving that previously programmed
  211. ; time, it updates it to the new time that is contained in the timer's
  212. ; CR register, in case these to items are different. Note that the
  213. ; maximum CE value of 0 is converted to 65536 through the decrement and
  214. ; adding with carry.
  215. ;
  216. ; Next, the ISR must determine if it is re-entering itself. If this is
  217. ; so, callbacks are not performed, and only a "missed ticks" count is
  218. ; updated, indicating how many additional ticks should be subtracted
  219. ; from each event due time. This allows the ISR to finish immediately
  220. ; if a timer interrupt is currently being serviced. This is important
  221. ; for both speed in general, and for slow machines that might generate
  222. ; mouse events during timer events. Note that only 6 bytes have been
  223. ; pushed onto the stack for this case, and that everything but DS must
  224. ; be removed before jumping to the exit label. In this case, the
  225. ; function can safely EOI the PIC, as the BIOS call will not be
  226. ; performed, then the function will just return.
  227. ;
  228. ; In the normal case, the ISR is not being re-entered, and timer event
  229. ; due times are updated, and callbacks are made. In this case, the
  230. ; number of "missed ticks" is added to the CE tick count, bringing the
  231. ; total up to the number of ticks passed since the last time the event
  232. ; times were updated. This global counter is then zeroed for the next
  233. ; time re-entrancy occurs. Note that interrupts are still turned off
  234. ; at this point, and there is no need to fear bad things happening.
  235. ;
  236. ; When checking for a valid event ID, the Destroy flag must be checked
  237. ; in case the interrupt occured during a kill timer function call after
  238. ; the Destroy flag was grabbed the second time, but before the actual ID
  239. ; could be reset.
  240. ;
  241. ; When a valid ID is found, its due time is updated with the CE value,
  242. ; plus the amount of ticks that were missed because of re-entrancy, if
  243. ; any.
  244. ;
  245. ; After updating times, the event list is checked again, this time to
  246. ; perform any of the callbacks that are due. To make things easy, a
  247. ; global flag is used to determine if interrupts have been turned back
  248. ; on, and thus stacks have been switched.
  249. ;
  250. ; If a valid event is found that is also due, meaning that the callback
  251. ; time is <= 0, the fIntsOn flag is checked to determine if the stack
  252. ; has already been switched and interrupts are already on. If not, then
  253. ; just that occurs. The <f>tddEvent<d> function is then called to
  254. ; service the event.
  255. ;
  256. ; After all events have been called, interrupts are turned back off if
  257. ; needed, and the original stack restored. If no callback actually
  258. ; occurred, then the stack is never switched. The function then either
  259. ; exits as a normal ISR would, or it chains to the BIOS ISR. This is
  260. ; done if the BIOS event was up for being called, and the fBIOSCall flag
  261. ; was set because of that. Since the flag cannot be set when this ISR
  262. ; is being pre-entered, as callbacks are not performed, there is no need
  263. ; to do a test and set proceedure on the fBIOSCall flag, just a simple
  264. ; compare will do. Note though that the nInt8Count re-entrancy count is
  265. ; not decremented until after interrupts are turned off.
  266. ;
  267. ; Interrupts are also cleared to ensure that the BIOS ISR is not
  268. ; re-entered itself, since there is no re-entrancy control after this
  269. ; function chains to BIOS. Notice that DS was the first register pushed
  270. ; onto the stack, and therefore the last item to get rid of, which is
  271. ; done with the "retf 2". DS itself is restored from stack before
  272. ; chaining so that lpOLDISR (BIOS) can be accessed and pushed onto stack
  273. ; as the return address.
  274. ;
  275. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  276. assumes ds,nothing
  277. assumes es,nothing
  278. public tddISR
  279. tddISR proc far
  280. push ds ; This is pushed first for the case of BIOS
  281. ;----------------------------------------------------------------------------
  282. ;If we are on a 386 save all registers.
  283. ;----------------------------------------------------------------------------
  284. test cs:[CodeFixWinFlags],WF_WIN286
  285. jnz @F
  286. .386
  287. pushad
  288. push fs
  289. push gs
  290. .286p
  291. @@:
  292. push ax
  293. push bx
  294. mov ax,DGROUP ; set up local DS
  295. mov ds,ax
  296. assumes ds,Data
  297. ifndef NEC_98
  298. cmp PS2_MCA,0 ; Check for a PS/2 Micro Channel
  299. jz @f
  300. in al,PS2_SysCtrlPortB ; Get current System Control Port status
  301. or al,PS2_LatchBit ; Set latch clear bit
  302. IO_Delay
  303. out PS2_SysCtrlPortB,al ; Set new System Control Port status
  304. @@:
  305. endif ; NEC_98
  306. inc [IntCount] ; Ever-increasing Int counter
  307. inc [nInt8Count] ; Number of times int 8 re-entered
  308. mov ax,[wNextTime] ; Next time programmed into timer chip
  309. xchg ax,[wProgTime] ; Update current time if it was reset
  310. xor bx,bx
  311. dec ax ; convert 0 -> 64k
  312. add ax,1 ; Force carry flag
  313. adc bx,bx ; Set bx:ax == current tick count
  314. add CurTime[0],ax ; Add tick count to total ticks
  315. adc CurTime[2],bx
  316. adc CurTime[4],0
  317. ifdef DEBUG
  318. ; cmp [nInt8Count],1 ; Re-entrancy counter
  319. ; je @f
  320. ; add [RModeIntCount].lo,1
  321. ; adc [RModeIntCount].hi,0
  322. ;@@:
  323. add [PModeIntCount].lo,1 ; For debug Pmode count message
  324. adc [PModeIntCount].hi,0
  325. endif
  326. cmp [nInt8Count],1 ; Do not allow multiple re-entrancy
  327. je tddISRCheckCallbacks
  328. add [dTickUpdate.lo],ax ; Update total needed to be added
  329. adc [dTickUpdate.hi],bx
  330. pop bx
  331. jmp tddISREOIExit ; EOI before exiting
  332. tddISRCheckCallbacks:
  333. add ax,[dTickUpdate.lo] ; Add any extra ticks from re-entrancy
  334. adc bx,[dTickUpdate.hi]
  335. push cx
  336. xor cx,cx
  337. mov [dTickUpdate.lo],cx ; Reset tick re-entrant counter
  338. mov [dTickUpdate.hi],cx
  339. cld ; never assume the value of this in an ISR!
  340. push di
  341. mov di,DataOFFSET Events ; DS:DI --> first event
  342. mov cx,MAXEVENTS
  343. tddISRUpdateTimeLoop:
  344. cmp [di].evID,0 ; is this event active?
  345. jz tddISRUpdateTimeNext
  346. sub [di].evTime.lo,ax ; Subtract the amount of ticks gone by
  347. sbb [di].evTime.hi,bx
  348. tddISRUpdateTimeNext:
  349. add di,SizeEvent ; Increment to next event slot
  350. loop tddISRUpdateTimeLoop
  351. mov fIntsOn,0 ; Initialize interrupts set flag
  352. mov di,DataOFFSET Events ; DS:DI --> first event
  353. mov cx,MAXEVENTS
  354. tddISRCallLoop:
  355. cmp [di].evID,0 ; is this event active?
  356. jz tddISRNextEvent
  357. cmp [di].evDestroy,EVENT_DESTROYING
  358. je tddISRNextEvent
  359. cmp [di].evTime.hi,0 ; Is it time to call the event?
  360. jg tddISRNextEvent ; evTime <= 0
  361. jl tddISREvent
  362. cmp [di].evTime.lo,0
  363. jg tddISRNextEvent
  364. tddISREvent:
  365. test [di].evFlags,TIME_BIOSEVENT
  366. jnz tddISRCallEvent ; No need to switch, as no call will be made.
  367. cmp fIntsOn,0 ; Have interrupts been turned on already?
  368. jnz tddISRCallEvent
  369. inc fIntsOn ; fIntsOn == TRUE
  370. cCall StackEnter ; Switch to a new stack
  371. sti ; Can be re-entered now with new stack
  372. ; A timer callback needs to be called, but first before calling it,
  373. ; we need to check to determine if the original timer interrupt function
  374. ; is to be called during this interrupt. The reason is that a timer
  375. ; callback could take a long time, and the PIC should be EOI'ed as soon
  376. ; as possible.
  377. ; It is not possible to just do a specific EOI, as the BIOS timer
  378. ; interrupt performs a non-specific EOI, which would turn back on some
  379. ; other random interrupt. So if the the BIOS needs to be called, it
  380. ; is done now, else the EOI is performed now. This assumes that the
  381. ; BIOS callback is the first item in the list of callbacks.
  382. ; If the BIOS callback occurs now, then the fBIOSCall flag is reset,
  383. ; as there is no need to chain to it at the end of this interrupt. So
  384. ; if no other callbacks are to be performed, the BIOS interrupt is
  385. ; chained to, else it is just called before the first timer callback
  386. ; is performed.
  387. cmp [fBIOSCall],0 ; Does BIOS need to be called?
  388. je tddISREOI
  389. mov [fBIOSCall],0 ; No need to call BIOS again at the end
  390. pushf ; Simulate an interrupt call
  391. call lpOLDISR ; Call original timer interrupt
  392. jmp tddISRCallEvent ; Do actual timer callback
  393. ; No BIOS interrupt call is to be performed, so do EOI.
  394. tddISREOI:
  395. mov al,SPECIFIC_EOI ; specific EOI for IRQ 0 interrupt line
  396. out PICDATA,al ; send End-Of-Interrupt to PIC DATA port
  397. tddISRCallEvent:
  398. call tddEvent ; handle the event
  399. tddISRNextEvent:
  400. add di,SizeEvent ; Increment to next event slot
  401. loop tddISRCallLoop
  402. cmp fIntsOn,0 ; Where interrupts turned back on?
  403. jz @f
  404. cli ; Interrupts were turned on, so remove them
  405. cCall StackLeave ; Switch back to old stack
  406. @@:
  407. pop di ; Restore everything except DS
  408. pop cx
  409. pop bx
  410. cmp [fBIOSCall],0 ; Does BIOS need to be called?
  411. je tddISREOIExit
  412. pop ax
  413. mov [fBIOSCall],0
  414. ;----------------------------------------------------------------------------
  415. ;If we are on a 386 restore all registers.
  416. ;----------------------------------------------------------------------------
  417. test cs:[CodeFixWinFlags],WF_WIN286
  418. jnz @F
  419. .386
  420. pop gs
  421. pop fs
  422. popad
  423. .286p
  424. @@:
  425. push [lpOLDISR.hi] ; Push return address
  426. push [lpOLDISR.lo]
  427. dec [nInt8Count] ; exiting, decrement entry count
  428. push bp ; Restore DS from stack
  429. mov bp,sp
  430. mov ds,[bp+6] ; stack: [ds] [lpOLDISR.hi] [lpOLDISR.lo] [bp]
  431. assumes ds,nothing
  432. pop bp
  433. retf 2 ; Chain to BIOS ISR, removing DS from stack
  434. tddISREOIExit:
  435. mov al,SPECIFIC_EOI ; specific EOI for IRQ 0 interrupt line
  436. out PICDATA,al ; send End-Of-Interrupt to PIC DATA port
  437. pop ax
  438. assumes ds,Data
  439. dec [nInt8Count] ; exiting, decrement entry count
  440. ;----------------------------------------------------------------------------
  441. ;If we are on a 386 restore all registers.
  442. ;----------------------------------------------------------------------------
  443. test cs:[CodeFixWinFlags],WF_WIN286
  444. jnz @F
  445. .386
  446. pop gs
  447. pop fs
  448. popad
  449. .286p
  450. @@:
  451. pop ds
  452. assumes ds,nothing
  453. iret
  454. tddISR endp
  455. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  456. ;
  457. ;@doc INTERNAL TIMER
  458. ;
  459. ;@asm tddEvent |
  460. ; Handle an event when it is due.
  461. ;
  462. ; For a valid event, the ID is saved in case the slot needs to be zeroed
  463. ; and the type of event is checked. If this is a oneshot event
  464. ; timer, the entry is freed. Note that at this point, as in the kill
  465. ; event function, the Destroy flag must be checked to determine if the
  466. ; slot is currently being checked. If so, the EVENT_DESTROYED flag must
  467. ; be set instead of resetting the flag so that the function that was
  468. ; interrupted can determine that the entry was killed while being
  469. ; checked.
  470. ;
  471. ; After saving the event handle, the function checks to see if the event
  472. ; is a One Shot, in which case it is destroyed, and the event's
  473. ; resolution is removed from resolution the table.
  474. ;
  475. ; If on the other hand the event is a periodic one, the next calling
  476. ; time is updated with the delay period. Note that if the event is far
  477. ; behind, or the last minimum resolution was very large, many delay
  478. ; periods are added to the next call time.
  479. ;
  480. ; If this is a BIOS event, then the fBIOSCall flag is set so that the
  481. ; ISR chains to the old BIOS ISR instead of returning normally. If this
  482. ; is a normal event, the parameters are pushed, and the driver callback
  483. ; function is called using the DCB_FUNCTION flag.
  484. ;
  485. ; After returning from the callback, the return value from
  486. ; <f>DriverCallback<d> is checked to determine if the callback succeeded.
  487. ; If it did not, then the timer event needs to be removed. The timer
  488. ; event however may have been a oneshot, in which case it was already
  489. ; been removed before the call was made, and the EVENT_DESTROYED flag
  490. ; may have been set, so it is just left alone. If the event is still
  491. ; present however, it is destroyed after doing the checking to see if
  492. ; this interrupt came while the event was being destroyed. Note that
  493. ; there is no check to see if the event IDs are the same before destroying
  494. ; the event. This is because if the callback failed, then the timer
  495. ; structure cannot have changed, and no check is needed.
  496. ;
  497. ;@parm DS:DI |
  498. ; Points to the event slot.
  499. ;
  500. ;@comm Uses AX,BX.
  501. ;
  502. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  503. assumes es,nothing
  504. assumes ds,Data
  505. cProc tddEvent, <NEAR, PUBLIC>, <>
  506. cBegin
  507. push dx
  508. mov dx,[di].evID
  509. test [di].evFlags,TIME_PERIODIC
  510. jnz tddEventPeriodic
  511. tddEventKillOneShot:
  512. xor ax,ax
  513. mov [di].evID,ax ; Invalidate slot
  514. cmp [di].evDestroy,EVENT_CHECKING ; Did this interrupt a Kill?
  515. jne @f
  516. mov al,EVENT_DESTROYED ; Let the interrupted Kill know
  517. @@:
  518. mov [di].evDestroy,al
  519. mov [di].evCreate,ah ; pEvent->evCreate = FALSE
  520. push dx
  521. push cx
  522. cCall tddEndMinPeriod,<[di].evResolution>
  523. pop cx
  524. pop dx
  525. jmp tddEventCallback
  526. tddEventPeriodic:
  527. mov ax,[di].evDelay.lo
  528. mov bx,[di].evDelay.hi
  529. @@:
  530. add [di].evTime.lo,ax
  531. adc [di].evTime.hi,bx
  532. jl @b
  533. tddEventCallback:
  534. test [di].evFlags,TIME_BIOSEVENT
  535. jz tddEventDriverCallback
  536. inc [fBIOSCall]
  537. jmp tddEventExit
  538. tddEventDriverCallback:
  539. push cx
  540. push es
  541. ;
  542. ; call DriverCallback() in MMSYSTEM
  543. ;
  544. push [di].evCallback.hi ; execute callback function
  545. push [di].evCallback.lo
  546. push DCB_FUNCTION or DCB_NOSWITCH; callback flags
  547. push dx ; idTimer
  548. xor dx,dx
  549. push dx ; msg = 0
  550. push [di].evUser.hi ; dwUser
  551. push [di].evUser.lo
  552. push dx ; dw1 = 0
  553. push dx
  554. push dx ; dw2 = 0
  555. push dx
  556. call DriverCallback ; execute callback function
  557. pop es
  558. or ax,ax ; Check for a successful return
  559. jnz tddEventSucceed ; If callback succeeded, just continue
  560. cmp [di].evID,ax ; If the timer was already destroyed,
  561. jz tddEventSucceed ; just leave
  562. mov [di].evID,ax ; Else destroy the event
  563. cmp [di].evDestroy,EVENT_CHECKING ; Did this interrupt a Kill?
  564. jne @f
  565. mov al,EVENT_DESTROYED ; Let the interrupted Kill know
  566. @@:
  567. mov [di].evDestroy,al
  568. mov [di].evCreate,ah ; pEvent->evCreate = FALSE
  569. cCall tddEndMinPeriod,<[di].evResolution>
  570. tddEventSucceed:
  571. pop cx
  572. tddEventExit:
  573. pop dx
  574. cEnd
  575. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  576. ;
  577. ; @doc INTERNAL
  578. ;
  579. ; @asm GetCounterElement | Low level routine which loads the tick count
  580. ; from the timer counter device, and returns the number of ticks that
  581. ; have already passed.
  582. ;
  583. ; @rdesc Returns the tick count in AX.
  584. ;
  585. ; @comm All registers preserved.
  586. ;
  587. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  588. public GetCounterElement
  589. GetCounterElement proc near
  590. ; Get rid of any latched count if this is called during interrupt time
  591. cmp [nInt8Count],1
  592. jb @f
  593. in al,TMR_CNTR_0
  594. IO_Delay
  595. in al,TMR_CNTR_0
  596. @@:
  597. ; read counter first time
  598. xor ax,ax ; LATCH counter 0 command
  599. out TMR_CTRL_REG,al ; send command
  600. in al,TMR_CNTR_0 ; read low byte
  601. mov ah,al
  602. in al,TMR_CNTR_0 ; read high byte
  603. xchg al,ah
  604. sub ax,wProgTime ; Convert to number of ticks already past
  605. neg ax
  606. ret
  607. GetCounterElement endp
  608. sEnd
  609. end