forked from Tronix286/AIL2
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathAIL.ASM
2698 lines (2017 loc) · 82.6 KB
/
AIL.ASM
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
;ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
;ÛÛ ÛÛ
;ÛÛ AIL.ASM ÛÛ
;ÛÛ ÛÛ
;ÛÛ IBM Audio Interface Library -- Application Program Interface module ÛÛ
;ÛÛ ÛÛ
;ÛÛ Version 2.00 of 24-Sep-91: Initial V2.X version (derived from V1.02) ÛÛ
;ÛÛ 2.01 of 02-Dec-91: Round timer period down to reduce drift ÛÛ
;ÛÛ 2.02 of 22-Dec-91: register_timer() stack usage adjusted ÛÛ
;ÛÛ 2.10 of 07-Mar-92: TAS DIGPAK digital driver support added ÛÛ
;ÛÛ 2.11 of 09-Mar-92: AIL_format_sound_buffer/format_VOC_file() ÛÛ
;ÛÛ added for Ad Lib Gold & DIGPAK compliance ÛÛ
;ÛÛ DIGPAK timer-sharing implemented ÛÛ
;ÛÛ 2.12 of 12-Aug-92: Initialize timer_value in register_timer ÛÛ
;ÛÛ 2.13 of 20-Aug-92: Add RTC INT 70H timer option ÛÛ
;ÛÛ 2.14 of 24-Sep-92: Init DP_handle in register_driver() ÛÛ
;ÛÛ Reset timer_value of first reg'd timer ÛÛ
;ÛÛ ÛÛ
;ÛÛ 8086 ASM source compatible with Turbo Assembler v2.0 or later ÛÛ
;ÛÛ C function prototypes in AIL.H ÛÛ
;ÛÛ Author: John Miles ÛÛ
;ÛÛ ÛÛ
;ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
;ÛÛ ÛÛ
;ÛÛ Copyright (C) 1991, 1992 Miles Design, Inc. ÛÛ
;ÛÛ ÛÛ
;ÛÛ Miles Design, Inc. ÛÛ
;ÛÛ 10926 Jollyville #308 ÛÛ
;ÛÛ Austin, TX 78759 ÛÛ
;ÛÛ (512) 345-2642 / FAX (512) 338-9630 / BBS (512) 454-9990 ÛÛ
;ÛÛ ÛÛ
;ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
MODEL MEDIUM,C ;Procedures far, data near by default
LOCALS __ ;Enable local labels with __ prefix
JUMPS ;Enable auto jump sizing
;
;Configuration equates
;
FALSE equ 0
TRUE equ -1
DIGPAK equ TRUE ;TRUE to assemble DIGPAK support code
DIGPAK_SHARE equ FALSE ;FALSE to disable DIGPAK timer sharing
USE_INT8 equ TRUE ;FALSE to use real-time clock INT 70H
;(incompatible w/Windows & OS/2)
RTC_FREQ equ 256 ;RTC rate default = 256 Hz.
RTC_FREQ_BITS equ 1000b ;(establishes maximum timer frequency)
;
;Macros, internal equates
;
INCLUDE ail.inc ;define driver procedure call numbers
INCLUDE ail.mac ;general-use macros
.CODE
;
;Process services
;
PUBLIC AIL_startup
PUBLIC AIL_shutdown
PUBLIC AIL_register_timer
PUBLIC AIL_set_timer_period
PUBLIC AIL_set_timer_frequency
PUBLIC AIL_set_timer_divisor
PUBLIC AIL_interrupt_divisor
PUBLIC AIL_start_timer
PUBLIC AIL_start_all_timers
PUBLIC AIL_stop_timer
PUBLIC AIL_stop_all_timers
PUBLIC AIL_release_timer_handle
PUBLIC AIL_release_all_timers
;
;Installation services
;
PUBLIC AIL_register_driver
PUBLIC AIL_release_driver_handle
PUBLIC AIL_describe_driver
PUBLIC AIL_detect_device
PUBLIC AIL_init_driver
PUBLIC AIL_shutdown_driver
;
;Extended MIDI (XMIDI) performance services
;
PUBLIC AIL_state_table_size
PUBLIC AIL_register_sequence
PUBLIC AIL_release_sequence_handle
PUBLIC AIL_default_timbre_cache_size
PUBLIC AIL_define_timbre_cache
PUBLIC AIL_timbre_request
PUBLIC AIL_install_timbre
PUBLIC AIL_protect_timbre
PUBLIC AIL_unprotect_timbre
PUBLIC AIL_timbre_status
PUBLIC AIL_start_sequence
PUBLIC AIL_stop_sequence
PUBLIC AIL_resume_sequence
PUBLIC AIL_sequence_status
PUBLIC AIL_relative_volume
PUBLIC AIL_relative_tempo
PUBLIC AIL_set_relative_volume
PUBLIC AIL_set_relative_tempo
PUBLIC AIL_beat_count
PUBLIC AIL_measure_count
PUBLIC AIL_branch_index
PUBLIC AIL_controller_value
PUBLIC AIL_set_controller_value
PUBLIC AIL_channel_notes
PUBLIC AIL_send_channel_voice_message
PUBLIC AIL_send_sysex_message
PUBLIC AIL_write_display
PUBLIC AIL_install_callback
PUBLIC AIL_cancel_callback
PUBLIC AIL_lock_channel
PUBLIC AIL_map_sequence_channel
PUBLIC AIL_true_sequence_channel
PUBLIC AIL_release_channel
;
;Digital performance services
;
PUBLIC AIL_index_VOC_block
PUBLIC AIL_register_sound_buffer
PUBLIC AIL_format_sound_buffer
PUBLIC AIL_sound_buffer_status
PUBLIC AIL_play_VOC_file
PUBLIC AIL_format_VOC_file
PUBLIC AIL_VOC_playback_status
PUBLIC AIL_start_digital_playback
PUBLIC AIL_stop_digital_playback
PUBLIC AIL_pause_digital_playback
PUBLIC AIL_resume_digital_playback
PUBLIC AIL_set_digital_playback_volume
PUBLIC AIL_digital_playback_volume
PUBLIC AIL_set_digital_playback_panpot
PUBLIC AIL_digital_playback_panpot
;
;Local data
;
BIOS_H equ 16 ;Handle to BIOS default timer
active_timers dw ? ;# of timers currently registered
timer_busy dw 0 ;Reentry flag for INT 8 handler
timer_callback dd 17 dup (?) ;Callback function addrs for timers
callback_ds dw 17 dup (?) ;Default data segments for callbacks
timer_status dw 17 dup (?) ;Status of timers (0=free 1=off 2=on)
timer_elapsed dd 17 dup (?) ;Modified DDA error counts for timers
timer_value dd 17 dup (?) ;Modified DDA limit values for timers
timer_period dd ? ;Modified DDA increment for timers
bios_callback dd ?
current_timer dw ?
temp_period dd ?
PIT_divisor dw ?
index_base dd 16 dup (?) ;Driver table base addresses
assigned_timer dw 16 dup (?) ;Timers assigned to drivers
driver_active dw 16 dup (?)
drvproc dd ?
cur_drvr dw ?
rtn_off dw ?
rtn_seg dw ?
timer_handle dw ?
drvr_desc STRUC
min_API_version dw ?
drvr_type dw ?
data_suffix db 4 dup (?)
dev_names dd ?
def_IO dw ?
def_IRQ dw ?
def_DMA dw ?
def_DRQ dw ?
svc_rate dw ?
dsp_size dw ?
ENDS
ALIGN 2
stack_check db 'Test' ;(Used for stack overflow checking)
dw 256 dup (?) ;512-byte interrupt stack used by
intstack LABEL WORD ;default -- can be increased if needed
old_ss dw ?
old_sp dw ?
current_rev dw 211
;*****************************************************************************
;* *
;* RTC CMOS access *
;* *
;*****************************************************************************
IF NOT USE_INT8
PIC0_DATA equ 020h
PIC0_CTRL equ 021h
PIC1_DATA equ 0a0h
PIC1_CTRL equ 0a1h
EOI equ 020h
ALARMINT equ 04Ah
RTCINT equ 070h
CMOS_CONTROL equ 070h
CMOS_DATA equ 071h
SRA equ 00ah
SRB equ 00bh
SRC equ 00ch
SRD equ 00dh
UIP equ 080h
SET equ 080h
PIE equ 040h
AIE equ 020h
UIE equ 010h
SQWE equ 008h
DM equ 004h
AMPM equ 002h
DSE equ 001h
IRQF equ 080h
PF equ 040h
AF equ 020h
UF equ 010h
VRT equ 080h
RTC_old_int dd ?
RTC_active dw 0
IO_WAIT MACRO
jmp $+2
jmp $+2
jmp $+2
ENDM
;*****************************************************************************
read_CMOS PROC Addr:BYTE
pushf
cli
mov al,[Addr]
out CMOS_CONTROL,al
IO_WAIT
in al,CMOS_DATA
POP_F
ret
ENDP
;*****************************************************************************
write_CMOS PROC Addr:BYTE,Val:BYTE
pushf
cli
mov al,[Addr]
out CMOS_CONTROL,al
IO_WAIT
mov al,[Val]
out CMOS_DATA,al
POP_F
ret
ENDP
;*****************************************************************************
RTC_set_freq PROC Freq:WORD
USES ds,si,di
call read_CMOS,SRB
and al,PIE
jz __not_set
mov ax,1
jmp __out
__not_set: call read_CMOS,SRA
and al,0f0h
mov bx,[Freq]
and bx,0fh
or bl,al
call write_CMOS,SRA,bx
mov ax,0
__out: ret
ENDP
;*****************************************************************************
RTC_enable PROC
USES ds,si,di
call read_CMOS,SRB
and al,(NOT (PIE AND (UF OR AF)))
or al,(PIE AND PF)
call write_CMOS,SRB,ax
ret
ENDP
;*****************************************************************************
RTC_disable PROC ;Disable all RTC interrupts
USES ds,si,di
call read_CMOS,SRB
and al,(NOT (PIE AND (UF OR PF OR AF)))
call write_CMOS,SRB,ax
ret
ENDP
;*****************************************************************************
RTC_install PROC
USES ds,si,di
pushf
cli
cmp RTC_active,0
jne __exit
mov ax,0
mov es,ax
les ax,es:[RTCINT*4]
mov WORD PTR RTC_old_int+2,es
mov WORD PTR RTC_old_int,ax
mov ax,0
mov es,ax
lea ax,API_timer
mov es:[(RTCINT*4)],ax
mov es:[(RTCINT*4)+2],cs
call read_CMOS,SRC
in al,PIC1_CTRL
and al,11111110b
out PIC1_CTRL,al
mov RTC_active,1
__exit: POP_F
ret
ENDP
;*****************************************************************************
RTC_uninstall PROC
USES ds,si,di
pushf
cli
cmp RTC_active,0
je __exit
in al,PIC1_CTRL
or al,00000001b
out PIC1_CTRL,al
mov ax,0
mov ds,ax
les ax,RTC_old_int
mov ds:[(RTCINT*4)],ax
mov ds:[(RTCINT*4)+2],es
mov RTC_active,0
__exit: POP_F
ret
ENDP
ENDIF
;*****************************************************************************
;* *
;* Internal procedures *
;* *
;*****************************************************************************
find_proc PROC ;Return addr of function AX in driver
;BX (Note: reentrant!)
cmp bx,16
jae __bad_handle ;exit sanely if handle invalid
shl bx,1 ;(a legitimate action for apps)
shl bx,1
les bx,index_base[bx] ;ES:BX -> driver procedure table
mov cx,es
or cx,bx
jz __bad_handle ;handle -> unreg'd driver, exit
__find_proc: mov cx,es:[bx] ;search for requested function in
cmp cx,ax ;driver procedure table
je __found
add bx,4
cmp cx,-1
jne __find_proc
mov ax,0 ;return 0: function not available
mov dx,0
ret
__bad_handle: mov ax,0 ;return 0: invalid driver handle
mov dx,0
ret
__found: mov ax,es:[bx+2] ;get offset from start of driver
mov dx,es ;get segment of driver (org = 0)
ret
ENDP
;*****************************************************************************
call_driver PROC ;Call function AX in specified driver
;(Warning: re-entrant procedure!)
mov bx,sp
mov bx,ss:[bx+4] ;get handle
call find_proc
cmp ax,0
jne __do_call
cmp dx,0
je __invalid_call
__do_call: push dx ;call driver function via stack
push ax
retf
__invalid_call: ret ;return DX:AX = 0 if call failed
ENDP
;*****************************************************************************
API_timer PROC ;API INT 8/INT 70H dispatcher
inc timer_busy
cld
push ax
push bx
push cx
push dx
push si
push di
push bp
push es
push ds
IF NOT USE_INT8
call read_CMOS C,SRC
sti
ENDIF
cmp timer_busy,1
jne __exit
mov old_ss,ss
mov old_sp,sp
mov ax,cs ;switch to internal stack if INT 8
mov ss,ax ;in use
lea sp,intstack
mov current_timer,0
__for_timer: mov si,current_timer ;for timer = 0 to 16
shl si,1
cmp timer_status[si],2 ;is timer "running"?
jne __next_timer ;no, go on to the next one
mov ds,callback_ds[si] ;else load callback's data segment...
shl si,1
mov ax,WORD PTR timer_elapsed[si]
mov dx,WORD PTR timer_elapsed[si]+2
add ax,WORD PTR timer_period
adc dx,WORD PTR timer_period+2
cmp dx,WORD PTR timer_value[si]+2
jb __dec_timer
ja __timer_tick
cmp ax,WORD PTR timer_value[si]
jae __timer_tick
__dec_timer: mov WORD PTR timer_elapsed[si],ax
mov WORD PTR timer_elapsed[si]+2,dx
jmp __next_timer
__timer_tick: sub ax,WORD PTR timer_value[si]
sbb dx,WORD PTR timer_value[si]+2
mov WORD PTR timer_elapsed[si],ax
mov WORD PTR timer_elapsed[si]+2,dx
call timer_callback[si] ;DDA timer expired, call timer proc
__next_timer: inc current_timer ;(may be externally set to -1 to
cmp current_timer,16 ; cancel further callbacks)
jbe __for_timer
mov ss,old_ss
mov sp,old_sp
__exit: pop ds
pop es
pop bp
pop di
pop si
pop dx
pop cx
pop bx
mov al,20h
IF NOT USE_INT8
out 0a0h,al
ENDIF
out 20h,al
pop ax
cmp WORD PTR stack_check,'eT'
jne __stack_fault
cmp WORD PTR stack_check+2,'ts'
jne __stack_fault
dec timer_busy
iret
__stack_fault: sti ;(Increase size of internal stack if
int 3 ;application breaks or "hangs" here)
jmp __stack_fault
ENDP
;*****************************************************************************
init_DDA_arrays PROC ;Initialize timer DDA counters
USES ds,si,di
pushf
cli
cld
mov WORD PTR timer_period,-1
mov WORD PTR timer_period+2,-1
push cs
pop es
mov di,OFFSET timer_status
mov cx,17
mov ax,0
rep stosw ;mark all timer handles "free"
mov di,OFFSET timer_elapsed
mov cx,17*2
rep stosw
mov di,OFFSET timer_value
mov cx,17*2
rep stosw
POP_F
ret
ENDP
;*****************************************************************************
bios_caller PROC ;Call old INT8 handler to maintain RTC
IF USE_INT8
pushf
call DWORD PTR bios_callback
ENDIF
ret
ENDP
;*****************************************************************************
hook_timer_process PROC ;Take over default BIOS INT 8 handler
USES ds,si,di
pushf
cli
mov ax,0 ;get current INT 8 vector and save it
mov es,ax ;as reserved timer function (stopped)
mov bx,es:[(8*4)]
mov es,es:[(8*4)+2]
mov WORD PTR bios_callback,bx
mov WORD PTR bios_callback+2,es
mov bx,OFFSET bios_caller
mov WORD PTR timer_callback[BIOS_H*4],bx
mov WORD PTR timer_callback[BIOS_H*4]+2,cs
IF USE_INT8
mov ax,cs
mov ds,ax
mov dx,OFFSET API_timer
mov ax,0 ;replace default handler with API task
mov es,ax ;manager
mov es:[(8*4)],dx
mov es:[(8*4)+2],ds
ELSE
call RTC_set_freq C,RTC_FREQ_BITS
call RTC_enable
call RTC_install
ENDIF
POP_F
ret
ENDP
;*****************************************************************************
unhook_timer_process PROC ;Restore default BIOS INT 8 handler
USES ds,si,di
pushf
cli
mov current_timer,-1 ;disallow any further callbacks
IF USE_INT8
mov dx,WORD PTR bios_callback
mov ds,WORD PTR bios_callback+2
mov ax,0
mov es,ax
mov es:[(8*4)],dx
mov es:[(8*4)+2],ds
ELSE
call RTC_uninstall
call RTC_disable
ENDIF
POP_F
ret
ENDP
IF USE_INT8
;*****************************************************************************
set_PIT_divisor PROC Divisor ;Set 8253 Programmable Interval Timer
USES ds,si,di ;to desired IRQ 0 (INT 8) interval
pushf
cli
mov al,36h
out 43h,al
mov ax,[Divisor] ;PIT granularity = 1/1193181 sec.
mov PIT_divisor,ax
jmp $+2
out 40h,al
mov al,ah
jmp $+2
out 40h,al
POP_F
ret
ENDP
;*****************************************************************************
set_PIT_period PROC Period ;Set 8253 Programmable Interval Timer
USES ds,si,di ;to desired period in microseconds
mov ax,0 ;special case: no rounding error
cmp [Period],54925 ;if period=55 msec. BIOS default value
jae __set_PIT
mov ax,[Period]
mov bx,8380 ;PIT granularity = .83809532 uS
mov cx,10000 ;round down to avoid cumulative error
mul cx
div bx
__set_PIT: call set_PIT_divisor C,ax
ret
ENDP
ENDIF
;*****************************************************************************
ul_divide PROC Num:DWORD,Den:DWORD
USES ds,si,di
mov ax,WORD PTR [Num]
mov dx,WORD PTR [Num]+2
mov bx,WORD PTR [Den]
mov cx,WORD PTR [Den]+2
or cx,cx
jne __long_div
or dx,dx
je __short_div
or bx,bx
je __short_div
__long_div: mov bp,cx
mov cx,20h
xor di,di
xor si,si
__div_loop: shl ax,1
rcl dx,1
rcl si,1
rcl di,1
cmp di,bp
jb __cont_loop
ja __bump_quot
cmp si,bx
jb __cont_loop
__bump_quot: sub si,bx
sbb di,bp
inc ax
__cont_loop: loop __div_loop
jmp __end_div
__short_div: div bx
xor dx,dx
__end_div: ret
ENDP
;*****************************************************************************
program_timers PROC ;Establish timer interrupt rates
USES ds,si,di ;based on fastest active timer
pushf
cli ;non-reentrant, don't interrupt
cld
mov WORD PTR temp_period,-1
mov WORD PTR temp_period+2,-1
mov si,0
__for_timer: mov bx,si ;find fastest active timer....
shl bx,1
cmp timer_status[bx],0 ;timer active (registered)?
je __next_timer ;no, skip it
shl bx,1
mov ax,WORD PTR timer_value[bx]
mov dx,WORD PTR timer_value[bx]+2
cmp dx,WORD PTR temp_period+2
jb __set_temp
ja __next_timer
cmp ax,WORD PTR temp_period
jae __next_timer
__set_temp: mov WORD PTR temp_period,ax
mov WORD PTR temp_period+2,dx
__next_timer: inc si
cmp si,16 ;(include BIOS reserved timer)
jbe __for_timer
mov ax,WORD PTR temp_period
mov dx,WORD PTR temp_period+2
cmp ax,WORD PTR timer_period
jne __must_reset
cmp dx,WORD PTR timer_period+2
je __no_change ;current rate hasn't changed, exit
__must_reset: mov current_timer,-1 ;else set new base timer rate
;(slowest possible base = 54 msec!)
mov WORD PTR timer_period,ax
mov WORD PTR timer_period+2,dx
IF USE_INT8
call set_PIT_period C,ax
ENDIF
push cs
pop es
mov di,OFFSET timer_elapsed
mov cx,17*2
mov ax,0 ;reset ALL elapsed counters to 0 uS
rep stosw
__no_change:
POP_F
ret
ENDP
;*****************************************************************************
;* *
;* Process services *
;* *
;*****************************************************************************
AIL_startup PROC ;Initialize AIL API
USES ds,si,di
pushf
cli
mov active_timers,0 ;# of registered timers
mov timer_busy,0 ;timer re-entrancy protection
IF DIGPAK
mov DP_registered,0
ENDIF
cld
mov ax,cs
mov es,ax
lea di,index_base
mov cx,16*2
mov ax,0
rep stosw
lea di,assigned_timer
mov cx,16
mov ax,-1
rep stosw
lea di,driver_active
mov cx,16
mov ax,0
rep stosw
POP_F
ret
ENDP
;*****************************************************************************
AIL_shutdown PROC SignOff:FAR PTR ;Quick shutdown of all AIL resources
USES ds,si,di
pushf
cli
mov cur_drvr,0
__for_slot: mov si,cur_drvr
shl si,1
mov dx,assigned_timer[si]
shl si,1
mov ax,WORD PTR index_base[si]
or ax,WORD PTR index_base[si+2]
jz __next_slot ;no driver installed, skip slot
cmp dx,-1
je __shut_down ;no timer assigned, continue
call AIL_release_timer_handle C,dx
__shut_down: call AIL_shutdown_driver C,cur_drvr,[SignOff]
__next_slot: inc cur_drvr
cmp cur_drvr,16
jne __for_slot
call AIL_release_all_timers
POP_F
ret
ENDP
;*****************************************************************************
AIL_register_timer PROC Callback:FAR PTR
USES ds,si,di
pushf
cli
mov cx,ds ;save application module's DS segment
mov bx,0 ;look for a free timer handle....
__find_free: cmp timer_status[bx],0
je __found ;found one
add bx,2
cmp bx,32
jb __find_free
mov ax,-1
jmp __return ;no free timers, return -1
__found: mov ax,bx ;yes, set up to return handle
shr ax,1
mov timer_status[bx],1 ;turn the new timer "off" (stopped)
mov callback_ds[bx],cx ;register timer proc's DS segment
shl bx,1
lds si,[Callback] ;register the timer proc
mov WORD PTR timer_callback[bx],si
mov WORD PTR timer_callback+2[bx],ds
mov WORD PTR timer_value[bx],-1
mov WORD PTR timer_value[bx]+2,-1
inc active_timers
cmp active_timers,1 ;is this the first timer registered?
jne __return ;no, just return
push ax ;yes, set up our own interrupt handler
call init_DDA_arrays ;init timer countdown values
mov timer_status[BIOS_H*2],1
call hook_timer_process ;seize interrupt and register BIOS handler
IF USE_INT8
call AIL_set_timer_period C,BIOS_H,54925,0
call AIL_start_timer C,BIOS_H
ELSE
call AIL_set_timer_frequency C,BIOS_H,RTC_FREQ,0
ENDIF
pop ax
mov bx,ax
shl bx,1
mov timer_status[bx],1 ;(cleared by init_DDA_arrays)
shl bx,1
mov WORD PTR timer_value[bx],-1
mov WORD PTR timer_value[bx]+2,-1
__return:
POP_F
ret
ENDP
;*****************************************************************************
AIL_release_timer_handle PROC Timer
USES ds,si,di
pushf
cli
mov bx,[Timer]
cmp bx,-1
je __return
shl bx,1
cmp timer_status[bx],0 ;is the specified timer active?
je __return ;no, exit
mov timer_status[bx],0 ;release the timer's handle
dec active_timers ;any active timers left?
jnz __return ;if not, put the default handler back
IF USE_INT8
call set_PIT_divisor C,0
ENDIF
call unhook_timer_process
__return:
POP_F
ret
ENDP
;*****************************************************************************
AIL_release_all_timers PROC
USES ds,si,di
pushf
cli
mov si,15 ;free all external timer handles
__release_it: call AIL_release_timer_handle C,si
dec si
jge __release_it
POP_F
ret
ENDP
;*****************************************************************************
AIL_start_timer PROC Timer
USES ds,si,di
pushf
cli