-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathAMIS.MAC
1465 lines (1382 loc) · 35.3 KB
/
AMIS.MAC
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
.XLIST
;-----------------------------------------------------------------------
; Alternate Multiplex Interrupt Specification Library
; AMIS.MAC Public Domain 1992, 1993 Ralf Brown
; You may do with this software whatever you want, but
; common courtesy dictates that you not remove my name
; from it.
;
; Version 0.92
; LastEdit: 2/21/93
;-----------------------------------------------------------------------
AMIS_VERSION equ 350 ;(version 3.5 of the Alternate Multiplex Interrupt Spec)
AMISLIB_VERSION equ 092 ;(version 0.92 of this library)
;-----------------------------------------------------------------------
; Return codes for various API calls
;
; general, applies to all standard calls
AMIS_NOTIMPLEMENTED equ 0
AMIS_SUCCESSFUL equ 0FFh
; additional return codes for Uninstall (function 02h)
AMIS_UNINST_FAILED equ 1
AMIS_UNINST_WILL_DO equ 2
AMIS_UNINST_SAFE_ON equ 3
AMIS_UNINST_SAFE_OFF equ 4
AMIS_UNINST_TRYLATER equ 5
; additional return codes for Popup (function 03h)
AMIS_POPUP_TRYLATER equ 1
AMIS_POPUP_WILLDO equ 2
AMIS_POPUP_BUSY equ 3
AMIS_POPUP_NEEDHELP equ 4
; additional return codes for Check Interrupt Chained (function 04h)
AMIS_CHAIN_DONTKNOW equ 1
AMIS_CHAIN_HOOKED equ 2
AMIS_CHAIN_HOOKED_ADDR equ 3
AMIS_CHAIN_HOOKLIST equ 4
AMIS_CHAIN_NOTUSED equ 0FFh
; hotkey type bits returned by Get Hotkeys (function 05h)
HK_INT09ENTRY equ 1 ; TSR checks keys before calling orig INT 09h
HK_INT09EXIT equ 2 ; TSR checks keys after calling orig INT 09h
HK_INT15ENTRY equ 4 ; TSR checks keys before chaining INT 15h/AH=4Fh
HK_INT15EXIT equ 8 ; TSR checks keys after chaining INT 15h/AH=4Fh
HK_INT16OLD equ 10h ; TSR checks on INT 16/AH=00h-02h
HK_INT16NEW equ 20h ; TSR checks on INT 16/AH=10h-12h
; hotkey shift bits returned by Get Hotkeys (function 05h)
HK_NONE equ 0000h ; no shift keys
HK_RSHIFT equ 0001h ; right shift key
HK_LSHIFT equ 0002h ; left shift key
HK_BOTHSHIFT equ 0003h ; both Shift keys must be pressed
HK_ANYCTRL equ 0004h ; either Control key must be pressed
HK_ANYALT equ 0008h ; either Alt key must be pressed
HK_SCRLLOCK_ON equ 0010h ; ScrollLock must be on when hotkey pressed
HK_NUMLOCK_ON equ 0020h ; NumLock must be on when hotkey pressed
HK_CAPSLOCK_ON equ 0040h ; CapsLock must be on when hotkey pressed
HK_ANYSHIFT equ 0080h ; either Shift key must be pressed
HK_LCTRL equ 0100h ; left control key
HK_LALT equ 0200h ; left Alt key
HK_RCTRL equ 0400h ; right control key
HK_RALT equ 0800h ; right Alt key
HK_BOTHCTRL equ 0500h ; both Control keys must be pressed
HK_BOTHALT equ 0A00h ; both Alt keys must be pressed
HK_SCROLLOCK equ 1000h ; ScrollLock must be pressed with hotkey
HK_NUMLOCK equ 2000h ; NumLock must be pressed with hotkey
HK_CAPSLOCK equ 4000h ; CapsLock must be pressed with hotkey
HK_SYSREQ equ 8000h ; SysRq must be pressed with hotkey
; hotkey flag bits returned by Get Hotkeys (function 05h)
HK_CHAINBEFORE equ 1 ; TSR chains hotkey before processing it
HK_CHAINAFTER equ 2 ; TSR chains hotkey after processing it
HK_MONITOR equ 4 ; other TSRs should pass through this hotkey
; so that it can be monitored
HK_NOPRESSRELEASE equ 8 ; hotkey won't activate if other keys pressed
; and released before hotkey combination
; completed
HK_REMAPPED equ 10h ; this key is remapped into some other key
HK_NOCHAIN equ 0 ; TSR swallows hotkey
; hotkey scan codes returned by Get Hotkeys (function 05h)
SCAN_NONE equ 0
SCAN_ESC equ 1
SCAN_1 equ 2
SCAN_2 equ 3
SCAN_3 equ 4
SCAN_4 equ 5
SCAN_5 equ 6
SCAN_6 equ 7
SCAN_7 equ 8
SCAN_8 equ 9
SCAN_9 equ 10
SCAN_0 equ 11
SCAN_HYPHEN equ 12
SCAN_EQUAL equ 13
SCAN_BACKSP equ 14
SCAN_TAB equ 15
SCAN_Q equ 16
SCAN_W equ 17
SCAN_E equ 18
SCAN_R equ 19
SCAN_T equ 20
SCAN_Y equ 21
SCAN_U equ 22
SCAN_I equ 23
SCAN_O equ 24
SCAN_P equ 25
SCAN_LBRACKET equ 26
SCAN_RBRACKET equ 27
SCAN_ENTER equ 28
SCAN_CTRL equ 29
SCAN_A equ 30
SCAN_S equ 31
SCAN_D equ 32
SCAN_F equ 33
SCAN_G equ 34
SCAN_H equ 35
SCAN_J equ 36
SCAN_K equ 37
SCAN_L equ 38
SCAN_SEMICOLON equ 39
SCAN_SQUOTE equ 40
SCAN_BACKQUOTE equ 41
SCAN_LSHIFT equ 42
SCAN_BACKSLASH equ 43
SCAN_Z equ 44
SCAN_X equ 45
SCAN_C equ 46
SCAN_V equ 47
SCAN_B equ 48
SCAN_N equ 49
SCAN_M equ 50
SCAN_COMMA equ 51
SCAN_PERIOD equ 52
SCAN_SLASH equ 53
SCAN_RSHIFT equ 54
SCAN_GREYSTAR equ 55
SCAN_ALT equ 56
SCAN_SPACE equ 57
SCAN_CAPSLK equ 58
SCAN_F1 equ 59
SCAN_F2 equ 60
SCAN_F3 equ 61
SCAN_F4 equ 62
SCAN_F5 equ 63
SCAN_F6 equ 64
SCAN_F7 equ 65
SCAN_F8 equ 66
SCAN_F9 equ 67
SCAN_F10 equ 68
SCAN_NUMLK equ 69
SCAN_SCRLLK equ 70
SCAN_HOME equ 71
SCAN_UP equ 72
SCAN_PGUP equ 73
SCAN_GREYMINUS equ 74
SCAN_LEFT equ 75
SCAN_KP5 equ 76
SCAN_RIGHT equ 77
SCAN_GREYPLUS equ 78
SCAN_END equ 79
SCAN_DOWN equ 80
SCAN_PGDN equ 81
SCAN_INS equ 82
SCAN_DEL equ 83
SCAN_SYSRQ equ 84
SCAN_F11 equ 87
SCAN_F12 equ 88
HK_ONRELEASE equ 80h ; hotkey activates on key release (add to scan code)
;-----------------------------------------------------------------------
; Return codes for AMISLIB functions
;
; bit flags returned by CHECK_IF_HOTKEYS_USED
HC_EXACT equ 1 ; exact match found
HC_SUPERSET equ 2 ; some key whose shift states include ours used
HC_SUBSET equ 4 ; some key whose shift states included by one of ours used
HC_OVERLAP equ 8 ; hotkey overlap found
HC_MONITOR equ 80h ; other TSRs monitor one or more hotkeys, but no
; actual conflict because caller chains them
HC_IS_CONFLICT equ 7Fh ; mask for testing whether conflict exists
;-----------------------------------------------------------------------
;
; Set up a shorthand for the segment containing all the resident code and
; data.
; Note: the alignment 'align' must be blank to get the PARA alignment needed
; for the code to be properly relocatable in small-code memory models.
;
TSRcode@ MACRO align
LOCAL alignment
TGROUP GROUP RESIDENT_CODE
IFB <align>
RESIDENT_CODE SEGMENT PUBLIC PARA 'TSRCODE'
ELSE
RESIDENT_CODE SEGMENT PUBLIC BYTE 'TSRCODE'
ENDIF
ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
ASSUME CS:TGROUP
ENDM
TSRcodeEnd@ MACRO
RESIDENT_CODE ENDS
ENDM
;-----------------------------------------------------------------------
;
; Set up shorthands for the segments containing all the resident data,
; initialized and uninitialized.
;
TSRdata@ MACRO
RESIDENT_DATA SEGMENT PUBLIC BYTE 'TSRCODE'
ENDM
TSRdataEnd@ MACRO
RESIDENT_DATA ENDS
ENDM
TSRbss@ MACRO
RESIDENT_BSS SEGMENT PUBLIC BYTE 'TSRCODE'
ENDM
TSRbssEnd@ MACRO
RESIDENT_BSS ENDS
ENDM
;-----------------------------------------------------------------------
;
; dummy segment for determining the size of the resident code in the
; executable
;
TSRlast@ MACRO
RESIDENT_END SEGMENT PUBLIC BYTE 'TSRCODE'
ENDM
TSRlastEnd@ MACRO
RESIDENT_END ENDS
ENDM
;-----------------------------------------------------------------------
;
; Set up a shorthand for declaring all three resident segments and a group
; TGROUP for those segments.
;
TSRgroup@ MACRO align
TSRcode@ align
TSRcodeEnd@
TSRdata@
TSRdataEnd@
TSRbss@
TSRbssEnd@
TSRlast@
TSRlastEnd@
TGROUP GROUP RESIDENT_CODE,RESIDENT_DATA,RESIDENT_BSS,RESIDENT_END
ENDM
;-----------------------------------------------------------------------
;
; Some of the code in AMIS.ASM uses conditional assembly to handle
; segment registers differently in Tiny model than in other models, so
; we need to ensure that __TINY__ is defined in tiny model.
;
IFDEF @Model ; simplified memory models being used?
IF @Model eq 1 ; tiny model
IFNDEF __TINY__
__TINY__ equ 1
ENDIF ;NDEF
ENDIF
IF (@Model eq 1) or (@Model eq 2) or (@Model eq 3) ; Tiny, Small, or Compact?
DIST equ NEAR
ELSE
DIST equ FAR
ENDIF
ELSE ;DEF @Model ; else assume TCC/BCC memory-model #defines
IFDEF __TINY__
DIST equ NEAR
ELSEIFDEF __SMALL__
DIST equ NEAR
ELSEIFDEF __COMPACT__
DIST equ NEAR
ELSEIFDEF __MEDIUM__
DIST equ FAR
ELSEIFDEF __LARGE__
DIST equ FAR
ELSEIFDEF __HUGE__
DIST equ FAR
ENDIF
ENDIF
NOWARN PDC ; don't warn about pass-dependent constructions
IF1
IFNDEF DIST
&__DEFAULT_MODEL__ equ 1
IFDEF __TINY__
DIST equ NEAR
ELSEIFDEF __SMALL__
DIST equ NEAR
ELSEIFDEF __COMPACT__
DIST equ NEAR
ELSEIFDEF __MEDIUM__
DIST equ FAR
ELSEIFDEF __LARGE__
DIST equ FAR
ELSEIFDEF __HUGE__
DIST equ FAR
ENDIF
ENDIF
ENDIF
WARN PDC
IFNDEF __TINY__
TGROUP@ equ TGROUP
ENDIF
;-----------------------------------------------------------------------
;
; first half of startup code (invoke right after INCLUDE AMIS.MAC in main module)
;
; arguments: major,minor,stksize
; [opt] major,minor major/minor version of min supported DOS ver
; [opt] stksize size of initial stack for non-Tiny models
;
@Startup MACRO major,minor,stksize
;----------------------------------
; Declare our segments in the order
; we want them in the executable.
;
_INIT SEGMENT PUBLIC PARA 'INIT'
_INIT ENDS
TSRgroup@
_TEXT SEGMENT PUBLIC PARA 'CODE' ; must be aligned PARA to work properly
_TEXT ENDS
IFNDEF __TINY__
_STACK SEGMENT STACK 'STACK'
IFNB <stksize>
db <stksize> dup (?)
ELSE
db 100h dup (?)
ENDIF
_STACK ENDS
ENDIF ;ndef __TINY__
;----------------------------------
; set up labels for start and end of
; resident code
;
TSRcode@
$AMIS$start_TSRcode label byte ; find address of beginning of segment
TSRcodeEnd@
TSRlast@
$AMIS$end_TSRcode label byte ; marker for end of resident code in executable
TSRlastEnd@
IFDEF __TINY__
_INIT SEGMENT 'INIT'
ASSUME CS:_INIT,DS:_INIT,ES:_INIT,SS:_INIT
ORG 100h
ELSE
_TEXT SEGMENT 'CODE'
ASSUME CS:_TEXT,DS:NOTHING,ES:NOTHING,SS:NOTHING
ENDIF ;def __TINY__
INIT proc far
IFNB <major>
IFNB <minor>
CHECK_DOS_VER major,minor
ENDIF
ENDIF
IFNDEF __TINY__
mov dx,TGROUP
mov es,dx
ASSUME ES:TGROUP
jmp $AMIS$PROGRAM_START
ELSE
mov ax,offset _INIT:$AMIS$start_TSRcode
mov cl,4
shr ax,cl
mov dx,es
add dx,ax
mov es,dx
ASSUME ES:TGROUP
;
; compute normalized address of actual program entry point
;
mov dx,offset _INIT:$AMIS$PROGRAM_START
mov ax,offset _TEXT:$AMIS$PROGRAM_START
sub dx,ax
shr dx,cl ; CL still 4
mov cx,cs
add dx,cx
push dx ; simulate far jump to computed address
push ax
ret
ENDIF ;ndef __TINY__
INIT endp
ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
IFDEF __TINY__
_INIT ENDS
ELSE
_TEXT ENDS
ENDIF ;def __TINY__
ENDM
;-----------------------------------------------------------------------
;
; additional startup code (invoke at start of main program)
;
; arguments: need_psp non-blank to allocate __psp variable, blank if provided
; by some other module (such as the C runtime library)
;
@Startup2 MACRO need_psp
IFDEF __TINY__
public TGROUP@
TGROUP@ dw ?
ENDIF ;__TINY__
IFNB <need_psp>
public __psp
__psp dw ?
ENDIF ;need_psp
$AMIS$PROGRAM_START:
ASSUME DS:NOTHING,ES:TGROUP
mov __psp,ds
IFDEF __TINY__
mov TGROUP@,es
ENDIF
ENDM
;-----------------------------------------------------------------------
;
; installation flags (mainly internal use--see INSTALL_TSR below)
;
BEST_FIT equ 1 ; use best-fit rather than first-fit
UMB_ONLY equ 2 ; don't load into low memory, only into a UMB
LOW_ONLY equ 4 ; don't use UMB even if high memory available
; (note: can't set both UMB_ONLY and LOW_ONLY)
USE_TOPMEM equ 8 ; use the top of low memory if no high memory
; (this is not always the best place to load)
PATCH_RESIDENT equ 80h ; patch resident code with actual memory block address
;-----------------------------------------------------------------------
;
; DISPLAY_STRING output a '$'-terminated string to standard output
; arguments: string the label of the string to be displayed
; dataseg [opt] the segment of the string
;
DISPLAY_STRING MACRO string,dataseg
IFNB <dataseg>
push ds
mov ax,dataseg
mov ds,ax
ENDIF
mov dx,offset string
mov ah,9
int 21h
IFNB <dataseg>
pop ds
ENDIF
ENDM
;-----------------------------------------------------------------------
;
; CHECK_DOS_VER ensure that the program is running under the proper
; version of DOS, and terminate with an error message
; specifying the minimum required version if not.
;
CHECK_DOS_VER MACRO major,minor
LOCAL bad_version_msg,version_OK
IF major GE 5
mov ax,3306h ; get true DOS version
ELSE
mov ax,3000h
ENDIF
int 21h
xchg al,ah
cmp ax,256*major + minor
jae version_OK
IFNDEF __TINY__
push cs
pop ds
ENDIF
DISPLAY_STRING bad_version_msg
int 20h ; terminate program
bad_version_msg label byte
db "This program requires DOS "
db major+'0',".",(minor/10)+'0',(minor mod 10)+'0'
db " or higher.",13,10,"$"
version_OK:
ENDM
;-----------------------------------------------------------------------
;
; IF_INSTALLED conditionally branch somewhere if TSR is already installed
; arguments:
; dest label to branch to if already installed
; at exit:
; CF set if installed
; AH = multiplex number
; CX = version number
; CF clear if not installed
;
IF_INSTALLED MACRO dest
LOCAL not_installed
mov dx,TGROUP@
mov ax,offset RESIDENT_CODE:ALTMPX_SIGNATURE
extrn check_if_installed:DIST
call check_if_installed
jnc not_installed
jmp dest
not_installed:
ENDM
;-----------------------------------------------------------------------
;
; IF_HOTKEY_USED conditionally branch somewhere if TSR's hotkeys already in use
; arguments:
; dest label to branch to if one or more hotkeys conflict
; at exit:
; ZF clear if hotkeys conflict
; AX = conflict types
; bit 0: exact key already in use
; bit 1: key with less-strict shift states in use
; bit 2: key with stricter shift states in use
; ZF set if no conflicts
;
IF_HOTKEY_USED MACRO dest
LOCAL no_conflicts
mov dx,TGROUP@
mov ax,offset TGROUP:$AMIS$HOTKEY_LIST
extrn check_if_hotkeys_used:DIST
call check_if_hotkeys_used
jz no_conflicts
jmp dest
no_conflicts:
ENDM
;-----------------------------------------------------------------------
;
; INSTALL_TSR
; arguments:
; extra [opt] number of additional paragraphs needed in resident part
; fit [opt] FIRST (default) or BEST fit allocation
; high [opt] HIGHONLY to only use UMBs, TOPMEM to allocate block at
; high end of conventional memory if no UMBs available,
; LOWONLY to ignore UMBs, and TOPLOW to allocate at high
; end of conventional memory whether or not UMBs are
; available
; init [opt] function to call after installing TSR but before exiting
; if_inst [opt] label to branch to if already installed
; on_err [opt] label to branch to if unable to install
; more_flags [opt] label of byte containing additional flags to OR into
; flags setup by <fit> and <high>
;
; if 'init' is specified, the indicated function will be called with
; AX = segment at which TSR was loaded
; if 'if_inst' is specified, the indicated function will be jumped at with
; AH = multiplex number
; CX = version number
;
INSTALL_TSR MACRO extra,fit,high,init,if_inst,on_err,more_flags
LOCAL not_installed,install_failed,iflags,install_error_msg
mov bx,TGROUP@
push bx ; remember location of resident code
mov dx,bx
mov ax,offset RESIDENT_CODE:ALTMPX_SIGNATURE
extrn check_if_installed:DIST
call check_if_installed
pop bx ; retrieve location of resident code
jnc not_installed
install_failure:
IFNB <if_inst>
jmp if_inst
ELSE
jmp short install_failed
ENDIF
not_installed:
cmp al,1
je install_failure
mov dx,offset TGROUP:$AMIS$end_TSRcode+15
mov cl,4 ; convert bytes to paragraphs
shr dx,cl
mov cx,dx
IFNB <extra>
mov dx,extra
ELSE
xor dx,dx ; no extra memory required
ENDIF
iflags = 0
IFDIFI <fit>,<FIRST>
iflags = iflags OR BEST_FIT
ENDIF
IFIDNI <high>,<HIGHONLY>
iflags = iflags OR UMB_ONLY
ENDIF
IFIDNI <high>,<LOWONLY>
iflags = iflags OR LOW_ONLY
ENDIF
IFIDNI <high>,<TOPMEM>
iflags = iflags OR USE_TOPMEM
ENDIF
IFIDNI <high>,<TOPLOW>
iflags = iflags OR USE_TOPMEM OR LOW_ONLY
ENDIF
IFDEF ALTMPX$PSP
iflags = iflags OR PATCH_RESIDENT
ENDIF
mov al,iflags
IFNB <more_flags>
or al,more_flags
ENDIF
extrn $install_TSR:DIST
call $install_TSR
; if success, returns CF clear, AX=segment at which TSR was installed
jc install_failed
IFNB <&init>
call init
ENDIF
extrn $go_TSR:DIST
call $go_TSR ; never returns
install_failed:
IFNB <on_err>
jmp on_err
ELSE
push cs
pop ds
DISPLAY_STRING cs:install_error_msg
mov ax,4CFFh ; exit with ERRORLEVEL 255
int 21h
install_error_msg db "Unable to go resident.",13,10,"$"
ENDIF
ENDM
;-----------------------------------------------------------------------
;
; UNINSTALL remove the TSR from memory
; arguments:
; on_err [opt] label to branch to if unable to remove from memory
;
; If 'on_err' is omitted, check CF after this macro to determine whether
; the removal was successful (CF clear if successful, set on error)
;
UNINSTALL MACRO on_err
LOCAL success
mov dx,TGROUP@
mov ax,offset RESIDENT_CODE:ALTMPX_SIGNATURE
extrn $uninstall_TSR:DIST
call $uninstall_TSR
IFNB <on_err>
jnc success
jmp on_err
ENDIF
success:
ENDM
;-----------------------------------------------------------------------
;
; I M P O R T A N T ! ! !
; Note: in order to work properly with the code in AMIS.ASM, all of
; the following macros must be used inside TSRcode@
;
;-----------------------------------------------------------------------
;
; ISP_HEADER set up Interrupt Sharing Protocol header for an interrupt
; arguments:
; intr interrupt number
; reset [opt] name of routine to perform hardware reset
; eoi [opt] if nonzero, this is the primary handler for a hardware int
; exported labels: (for example "ISP_HEADER 00h,reset_func,0")
; INT00h_handler (public), ORIG_INT00h (public), HWRESET_00h,
; EOI_FLAG_00h
; [in addition, hw_reset_00h would be present for ISP_HEADER 00h,,0]
;
ISP_HEADER MACRO intr,reset,eoi
public INT&intr&_handler,ORIG_INT&intr
ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
IFB <reset>
hw_reset_&intr:
db 0CBh ; RETF
ENDIF ;reset
INT&intr&_handler:
db 0EBh,10h ; short JMP to skip the header
ORIG_INT&intr dd ? ; previous handler in chain
dw 424Bh ; ISP signature
EOI_FLAG_&intr label byte
IFB <eoi>
db 0 ; software int or secondary hardware int
ELSE
IF eoi eq 0
db 0 ; software int or secondary hardware int
ELSE
db 80h ; primary hardware int handler
ENDIF ;eoi eq 0
ENDIF ;B eoi
IFB <reset>
HWRESET_&intr: jmp short hw_reset_&intr
ELSE
HWRESET_&intr: jmp short reset
ENDIF ;B reset
db 7 dup (0)
ENDM
;-----------------------------------------------------------------------
;
; HOOKED_INTS declare the interrupts this TSR hooks
; arguments: up to 32 interrupt numbers
; exported labels: $AMIS$HOOKED_INT_LIST (public)
;
HOOKED_INTS MACRO a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,aa,ab,ac,ad,ae,af,over
public $AMIS$HOOKED_INT_LIST
$AMIS$HOOKED_INT_LIST label byte
IFNB <over>
%out Too many interrupts hooked!
.err
ENDIF ;NB over
IRP intrpt,<a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,aa,ab,ac,ad,ae,af>
IFNB <intrpt>
IF intrpt ne 2Dh ; ignore INT 2Dh if in the list
DB 0&&intrpt
DW INT&&intrpt&&_handler
ENDIF ;DIFI
ENDIF ;NB
ENDM
;
; the list terminator is INT 2Dh, since we know that one will always
; be hooked; thus, all interrupts from 00h to FFh may be hooked
;
DB 2Dh
DW INT2Dh_handler
ENDM
;-----------------------------------------------------------------------
;
; HOTKEYS declare the type of hotkeys this TSR uses
; arguments:
; check hotkey check type
; flags [opt] default flags for following hotkeys
; exported labels: $AMIS$HOTKEY_LIST (public),
; $amis$hotkey_list_start (internal use)
;
; To declare the TSR's hotkeys, you must use macros in the following order:
; HOTKEYS type
; HOTKEY scan1,req1,disall1
; HOTKEY scan2,req2,disall2,flags2
; ...
; HOTKEY scanN,reqN,disallN
; HOTKEYS_DONE
; these definitions must precede the use of the ALTMPX macro
;
HOTKEYS MACRO check,flags
public $AMIS$HOTKEY_LIST
$AMIS$HOTKEY_LIST label byte
db check ; type of hotkey check
db $amis$num_hotkeys ; number of hotkeys following
$amis$hotkey_list_start label byte
IFNB <flags>
$amis$hotkey_def_flags equ flags
ELSE
IF (check AND HK_INT15EXIT)
$amis$hotkey_def_flags equ HK_CHAINBEFORE
ELSEIF (check AND HK_INT09EXIT)
$amis$hotkey_def_flags equ HK_CHAINBEFORE
ELSE
$amis$hotkey_def_flags equ HK_NOCHAIN
ENDIF
ENDIF ;flags
ENDM
;-----------------------------------------------------------------------
;
; HOTKEY declare one of the hotkeys this TSR uses
; arguments:
; scan scan code
; req required shift states
; disall disallowed shift states
; flags [opt] flags describing actions taken on hotkey
; exported labels: none
;
; To declare the TSR's hotkeys, you must use macros in the following order:
; HOTKEYS type
; HOTKEY scan1,req1,disall1
; HOTKEY scan2,req2,disall2,flags2
; ...
; HOTKEY scanN,reqN,disallN
; HOTKEYS_DONE
; these definitions must precede the use of the ALTMPX macro; the first HOTKEY
; line should define the TSR's primary hotkey
;
HOTKEY MACRO scan,req,disall,flags
LOCAL t
db scan
IFNB <req>
dw req
ELSE
dw HK_NONE
ENDIF ;req
IFNB <disall>
t = disall
IF (((disall) AND HK_ANYSHIFT) eq HK_ANYSHIFT)
t = t OR HK_LSHIFT OR HK_RSHIFT
ENDIF
IF (((disall) AND HK_ANYCTRL) eq HK_ANYCTRL)
t = t OR HK_LCTRL OR HK_RCTRL
ENDIF
IF (((disall) AND HK_ANYALT) eq HK_ANYALT)
t = t OR HK_LALT OR HK_RALT
ENDIF
dw t
ELSE
dw HK_NONE
ENDIF ;disall
IFNB <flags>
db flags
ELSE
db $amis$hotkey_def_flags
ENDIF ;flags
ENDM
;-----------------------------------------------------------------------
;
; HOTKEYS_DONE mark end of hotkey list
; arguments: none
; exported labels: $amis$num_hotkeys (equate)
;
; To declare the TSR's hotkeys, you must use macros in the following order:
; HOTKEYS type
; HOTKEY scan1,req1,disall1
; HOTKEY scan2,req2,disall2
; ...
; HOTKEY scanN,reqN,disallN
; HOTKEYS_DONE
; these definitions must precede the use of the ALTMPX macro
;
HOTKEYS_DONE MACRO
$amis$num_hotkeys equ ($-$amis$hotkey_list_start)/6
ENDM
;-----------------------------------------------------------------------
;
; ALTMPX define the alternate multiplex interrupt handler for the program
; arguments:
; manuf one- to eight-character manufacturer's name
; prodname one- to eight-character product name
; version four-digit hex version number (hi byte = major, lo = minor)
; descrip [opt] string (max 63 char) describing the product
; priv_funcs [opt] name of routine to handle private INT 2Dh functions
; api_entry [opt] name of FAR routine giving non-INT 2Dh API entry point
; popup [opt] name of function to call to request a popup
; remover [opt] name of function to call to remove TSR from memory
; psp [opt] if nonblank, set up patch word for memblk segment to
; be returned if <remover> omitted; returns CS if both
; <remover> and <psp> blank
; limitations on routines:
; all: must be located inside TSRcode@
; <priv_funcs>
; input: AL = function number (10h-FFh)
; AH = multiplex number (ignore)
; others available for handler
; return: via IRET, with regs as appropriate for requested func
; <api_entry>
; input: registers as desired (no limitations)
; return: registers as desired (no limitations)
; <popup>
; input: nothing
; return: AL = status
; 01h can not pop up now, try again later
; 02h can not pop up yet, will do so when able
; 03h already popped up
; 04h unable to popup, user intervention required
; BX = standard reason code
; 0000h unknown failure
; 0001h int chain passes through memory
; which must be swapped out
; 0002h swap-in failed
; CX = application's reason code if nonzero
; FFh TSR popped up and was exited by user
; BX = return value
; 0000h no return value
; 0001h TSR unloaded
; 0002h-00FFh reserved
; 0100h-FFFFh application-specific
; <remover>
; input: DX:BX = return address if uninstall successful
; return: AL = status
; 01h unable to remove from memory
; 02h can't remove now, will do so when able
; 03h safe to remove, but no resident uninstaller
; (TSR still enabled)
; BX = segment of memory block
; 04h safe to remove, but no resident uninstaller
; (TSR now disabled)
; BX = segment of memory block
; 05h not safe to remove now, try again later
; FFh successful (DX:BX were ignored)
; return at DX:BX with AX destroyed if successful and <remover>
; honors specific return address
; if <remover> omitted, ALTMPX returns AL=03h
; exported labels:
; INT2Dh_handler (public), ORIG_INT2Dh (public), HWRESET_2Dh,
; EOI_FLAG_2Dh, hw_reset_2Dh, $AMIS$MULTIPLEX_NUMBER (public),
; ALTMPX_SIGNATURE (public), ALTMPX$PSP [patch word]
;
ALTMPX MACRO manuf,prodname,version,descrip,priv_funcs,api_entry,popup,remover,psp
LOCAL our_int_2Dh,int2D_func_00,int2D_func_01,int2D_func_02
LOCAL int2D_func_03,int2D_func_04
LOCAL func_is_supported,func_not_supported,func_supported_segDX
PUBLIC $AMIS$MULTIPLEX_NUMBER,ALTMPX_SIGNATURE,ALTMPX$PSP
ALTMPX_SIGNATURE label byte
db manuf
IF ($-ALTMPX_SIGNATURE) gt 8
ERR "Manufacturer name >8 chars"
ELSEIF ($-ALTMPX_SIGNATURE) lt 8
db (ALTMPX_SIGNATURE+8-$) dup (' ')
ENDIF
db prodname
IF ($-ALTMPX_SIGNATURE) gt 16
ERR "Product name >8 chars"
ELSEIF ($-ALTMPX_SIGNATURE) lt 16
db (ALTMPX_SIGNATURE+16-$) dup (' ')
ENDIF
IFNB <descrip>
db descrip
ENDIF
db 0
IF ($-ALTMPX_SIGNATURE) gt 80
ERR "Description >63 chars"
ENDIF
; save an additional byte by overlaying the null hardware reset handler over
; other code, if possible
IFNB <remover>
hw_reset_2Dh: ; <remover> not blank
db 0CBh ; RETF
IFNDEF ALTMPX$PSP
ALTMPX$PSP equ word ptr ($+12) ; point harmlessly into the ISP header
ENDIF
ELSE
IFB <psp>
ALTMPX$PSP equ word ptr ($+12) ; point harmlessly into the ISP header
ENDIF
ENDIF
IFNB <psp>
IFB <remover>
hw_reset_2Dh: ; <remover> blank but <psp> not
db 0CBh ; RETF
ENDIF
ENDIF
; if both <remover> and <psp> blank,
; hw_reset_2Dh is defined below
; if <remover> is blank and <psp> not,
; ALTMPX$PSP is defined below
ISP_HEADER 2Dh,hw_reset_2Dh
cmp ah,0 ; will be patched with multiplex number
$AMIS$MULTIPLEX_NUMBER equ byte ptr ($-1)
je our_int_2Dh
jmp ORIG_INT2Dh
our_int_2Dh:
sti ; OK to interrupt from now on
cmp al,0
je int2D_func_00
cmp al,2
IFNB <api_entry>
jb int2D_func_01
ELSE
IFNB <popup>
jb func_not_supported
ENDIF
ENDIF
je int2D_func_02
cmp al,4
IFNB <popup>
jb int2D_func_03
ENDIF ;popup
je int2D_func_04
IFDEF $amis$num_hotkeys
cmp al,5
jne not_hotkey_check
mov bx,offset TGROUP:$AMIS$HOTKEY_LIST
jmp short func_supported_segDX
not_hotkey_check:
ENDIF ;$amis$num_hotkeys
IFNB <priv_funcs>
cmp al,10h
jb func_not_supported