home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1992 December / simtel1292_SIMTEL_1292_Walnut_Creek.iso / msdos / keyboard / fastbf26.arc / FASTBF26.ASM next >
Assembly Source File  |  1989-08-14  |  44KB  |  1,648 lines

  1.     PAGE    ,132
  2.  
  3. ;       FASTBUFF.ASM - Keyboard buffer resident utility.
  4.  
  5. ;             Version 2.6
  6.  
  7. ;            by: David Steiner
  8. ;            [D.STEINER] on GEnie
  9. ;            2035 J Apt. 6
  10. ;            Lincoln, NE   68510
  11. ;            (402) 475-0601
  12.  
  13. ;    This is a fairly big update from version 1.0.  FASTBUFF now
  14. ;    handles Alt-keypad character entries correctly, plus fixes
  15. ;    these characters since many IBM clones generate incorrectly.
  16.  
  17. ;    The way characters are restored to the system has been updated
  18. ;    also.  We no longer hook the Keyboard I/O interrupt, instead we
  19. ;    continuously keep the BIOS buffer full by filling it every time
  20. ;    the system timer clicks (Interrupt 1C).
  21. ;    This was done as an allowance for programs that bypass the BIOS
  22. ;    when doing character I/O.  It has the added benefit of allowing
  23. ;    FASTBUFF to be active when installed after other utilities that
  24. ;    hook into interrupt 16.
  25.  
  26. ;    The only software compatibility problems that should arise will
  27. ;    be with other programs that hook the Keystroke interrupt and attempt
  28. ;    to insert characters directly into the BIOS keyboard buffer.
  29. ;       "Key-fake" utilities are an example of such programs.    If you
  30. ;    need to use such a program, it is best to deactivate FASTBUFF first.
  31.  
  32. ;v2.6    Toad Hall, 14 Aug 89
  33. ; -    Bug:  When setting many many cmdline switches (example:
  34. ;        FASTBUFF /V0 /B50 /D9 /S
  35. ;    program reports an error with the last switch/parameter.
  36. ;    Checking out cmdline parsing.
  37. ;    Thanks to Keith Petersen's son for reporting this one!
  38. ; -    Bug in cmdline parsing .. we were not correctly AsciiZing the last parm
  39. ;    (skipped an essential loop!).
  40. ; -    Bug in SetDelay:  checking for illegal high value, the 'jz' branch
  41. ;    should've been 'jnz' .. dumb!
  42. ; -    Removing old 'v2.5' comments.
  43.  
  44. ;v2.5    Toad Hall tweak, 1 May 89
  45. ; -    Removing old "v2.n" comments.
  46. ; -    Changed default screen blanking to 6 minutes.
  47. ; -    Using one beep for ACK or on, two beeps for off.
  48. ;    Rewrote the beep code because of an irritating click and delay
  49. ;    on my system.  Sound is now 8253 timer-driven.
  50. ;    Frequency is arbitrary.
  51. ;    Could be this will break any programs doing simultaneous music/sound
  52. ;    (or other timer-driven activities) and keyboard activity ..
  53. ;    but then we don't beep THAT often!
  54.  
  55. ;v2.4    Toad Hall Debug, Tweak, 2 Apr 89
  56. ; -    Added new command line parameter processing.
  57. ; -    Fixed possible bug in '/v' video blanking delay.
  58. ; -    Tightened up, debugged GetNum procedure for cmdline numeric values.
  59. ; -    Adding explanatory error msgs for faulty command line parameters.
  60. ; -    Left the rest alone for now.
  61. ; -    Per Keith Petersen's suggestion, adding forced screen blanking
  62. ;    ([5][End]).
  63. ; -    Also added a screen blanking toggle ([5][HOME].
  64. ;    Overrides the commandline '/V' or '-V0' (whichever) (if any).
  65. ; -    Tightened up Command key processing a little (sharing common code).
  66. ; -    Added a real short beep to acknowledge [5] commands.
  67. ; -    Single short beep means "ON", extra-long beep means "OFF".
  68. ; -    Considering a pop-up window with function-key or cursor-key
  69. ;    variable settings (rather than the somewhat cryptic [5][whatever]
  70. ;    combos we're using now).  That would add a lot of code, though,
  71. ;    plus storage space for user's screen, etc.  Maybe later.
  72. ; -    No problem with switching from Int 1CH to Int 8 .. I was tempted
  73. ;    to do the same myself, but wanted to keep this "well-behaved".
  74. ; -    Removed code commented out by v2.2, v2.3.
  75.  
  76. ;v2.3    Dave, March 15, 1989
  77. ; -    Changed timer interrupt vector from 1C to 8.
  78. ;    This fixes problems with programs that incorrectly hook the
  79. ;    software timer interrupt (1C).  IBM BASIC is one such program.
  80.  
  81. ;v2.2    Toad Hall Tweak, 2 Mar 89
  82. ; -    Keith Petersen detected DSZ serial port errors when FASTBUFF was
  83. ;    installed and DSZ was running at VERY high (19200 baud) rates.
  84. ;    Suspect we're grabbing interrupts too often or too long.
  85. ;    Tweaking to reduce CLI periods and ANY other delays.
  86. ; -    Removed a bunch of v2.0 code I'd commented out in v2.1
  87. ;    (since v2.1 seems to be working all right).
  88.  
  89. ;v2.1    Toad Hall Tweak, 23 Feb 89
  90. ; -    General tightening
  91. ; -    Much more use of AX vs. other regs
  92. ; -    Described a Page40 segment to permit faster BIOS variable
  93. ;    addressing.
  94. ; -    Now using DS: instead of ES: to address BIOS variables.
  95. ; -    FATAL error when new interrupt svcs call or jump to the old
  96. ;    interrupt vectors!  Author didn't address the saved vector
  97. ;    (oldint9, etc.) as CS:.
  98. ; -    Tightened up installation procedure:
  99. ;    - Uses runtime variables rather than installation variables.
  100. ;    - If error, terminates with proper Svc 4CH, Int 21H.
  101. ;    - Now freeing environment variable before going TSR
  102. ;    - Rounding up TSR program/data size to nearest paragraph
  103. ;      before going TSR.
  104. ; -    Reduced .COM file about 1Kb.  Runtime memory requirements:
  105. ;    - v2.0  1504 bytes, 2 blocks
  106. ;    - v2.1  1296 bytes, 1 block
  107. ;    .. not too shabby.
  108.  
  109. ;    Kudos to the author .. nice logic.
  110.  
  111. ;    David Kirschbaum
  112. ;    Toad Hall
  113. ;    kirsch@braggvax.ARPA
  114.  
  115.  
  116. ;------ EQUATES
  117.  
  118. CR    equ    0DH
  119. LF    equ    0AH
  120. TIMER    equ    40H        ;timer chip
  121. PORT_B    equ    61H        ;8253 port B
  122. HIFREQ    equ    300        ;high freq for on
  123. LOFREQ    EQU    900    ;200    ;low freq for off
  124. ERRFREQ    equ    350        ;keyboard overrun beep
  125.  
  126.  
  127. ;------ BIOS buffer & otherstuff equates
  128.  
  129. Page40  segment at    40H
  130.     org    10H
  131. biosequipflags  dw    ?        ;410H BIOS equipment word address
  132.  
  133.     org    17H
  134. ;------ BIOS shift status byte 1 & masks for action key combinations
  135.  
  136. biosshflags    db    ?        ;417H First BIOS shift status byte
  137.         db    ?
  138.  CLRMASK    equ    05H        ; Clear buffer key mask
  139.  
  140. biosaltbuff    db    ?        ;419H Storage for Alt-keypad entries
  141. bioshead    dw    ?        ;41AH BIOS keyboard buffer head
  142. biostail    dw    ?        ;41CH  ""  tail
  143. biosbuffer    db    ?        ;41EH BIOS keyboard buffer start
  144.  
  145.         org    3EH
  146. biosendbuff    label    byte        ;43EH end
  147.  
  148.         org    65H
  149. bioscrtmodeset  db    ?        ;465H
  150. biospalette    db    ?        ;466H
  151.  EQUIPMASK    equ    0010H
  152.  PALETTEMASK    equ    0FH
  153.  
  154.         org    71H
  155. ;------ BIOS break detection byte
  156. biosbreak    db    ?        ;471H Bit 7 of this byte indicates
  157.  BREAKMASK    equ    80H        ;  ctrl-break was pressed
  158.  
  159. Page40  ENDS
  160.  
  161.  
  162. KBINPORT    equ    60H        ; Keyboard data port
  163. ;KBCTRLPORT    equ    61H        ; Keyboard control port
  164. ALTSHIFT    equ    38H        ; ALT key scan code
  165.  
  166. ;------ FASTBUFF control key scan codes
  167.  
  168. FBCTRLKEY    equ    4CH        ; Scan code for "5" on keypad
  169.  
  170. FBONKEY        equ    52H        ; Code for INS key
  171. FBOFFKEY    equ    53H        ; Code for DEL key
  172. FBFAST        equ    4EH        ; Code for keypad "+"
  173. FASTREP        equ    2        ; Chars per click for fast rate
  174. FBSLOW        equ    4AH        ; Code for keypad "-"
  175. SLOWREP        equ    1        ; Chars per click for slow rate
  176. FBENDKEY    equ    4FH        ; Code for END key
  177. FBHOMEKEY    equ    47H        ; Code for HOME key
  178.  
  179. ;------ Masks for altering bits in our status byte.
  180.  
  181. FBMASK        equ    01H        ; Masks for FASTBUFF toggle
  182. REPMASK        equ    02H        ; On when we need to repeat a character
  183. SCRMASK        equ    04H        ; On while screen is active
  184. CTRLMASK    equ    08H        ; On when [5] is being held down
  185. OLDINT9MASK    equ    10H        ; On when processing char with old int9
  186. VIDMASK        equ    20H        ; Video blanking active?
  187. BLANKMASK    equ    40H        ; Forced video blanking?
  188.  
  189.  
  190. CSEG    segment public para 'CODE'
  191.     ASSUME  CS:CSEG, DS:CSEG
  192.  
  193.     org    2CH
  194. env_adr dw    ?            ;environment segment
  195.  
  196.     org    80H
  197. nchar    db    ?            ;PSP cmdline char count
  198. params    db    ?            ;PSP cmdline chars
  199.  
  200.     org    100H
  201.  
  202. Start:
  203.     jmp    Initialize
  204.  
  205.  
  206. ;------ Old vector storage area
  207.  
  208. oldint9        dw    0,0
  209. oldint10    dw    0,0
  210. oldint8        dw    0,0
  211.  
  212. ;--------------------------------------------------------------------------
  213. ;Resident data area
  214. ;--------------------------------------------------------------------------
  215.  
  216. lastchar    dw    0FFFFH        ; Last character typed, undef at start
  217. repcount    db    ?        ; # ticks till next repeat
  218. repchars    db    2        ; Default # chars to repeat
  219.                     ; per click
  220. ;    Keith Petersen suggested increasing this start delay a little
  221. ;    (because of repeated Return keys, fast cursor keys, etc.).
  222. ;    Changing from the original 5 to 7 ticks delay.
  223.  
  224. startdelay    db    7        ; Delay before repeating new char
  225.  
  226. ;    6-minute screen blanking timeout default.
  227.  
  228. BLANKTIME    EQU    (6 * 1092)    ;6 minutes * 1092 ticks per min
  229.  
  230. scrcount    dw    BLANKTIME    ; Time left till screen blanked
  231. screendelay    dw    BLANKTIME    ; "Constant" for refreshing
  232.                     ; scrcount
  233. switches    db SCRMASK AND VIDMASK    ; FASTBUFF off, screen active,
  234.                     ; default screen blanking on
  235.  
  236. ;---------------------------- Int 09 --------------------------------------
  237. ;Keystroke Interrupt
  238.  
  239. ;    Note that we always allow control to pass on to the old interrupt
  240. ;    9 handler.  We do, however, ignore the characters returned if one
  241. ;    of FASTBUFF's four command key combinations were detected.
  242. ;--------------------------------------------------------------------------
  243.  
  244. ;    We're not concerned about minimizing interrupt delays here.
  245. ;    If user is typing, he's obviously not using high-speed serial input.
  246.  
  247. NewInt9        proc    far
  248.  
  249.     sti
  250.     push    ax
  251.     push    bx
  252.     push    cx
  253.     push    dx
  254.     push    DS
  255.  
  256. ;------ This first section is code always executed by FASTBUFF
  257.  
  258.     and    CS:switches,NOT REPMASK ; Turn off repeat switch
  259.  
  260.     mov    ax,40H
  261.     mov    DS,ax
  262.     ASSUME  DS:Page40
  263.  
  264.     and    biosbreak,NOT BREAKMASK ;turn off break bit
  265.  
  266. ;    See if the LAST key was a [5][End] to force screen blanking.
  267. ;    If so, don't fiddle with screen blanking
  268. ;    We'll leave the forced blanking bit alone until
  269. ;    we're SURE we're out of control mode (e.g., regular key,
  270. ;    and not just the [5] release).
  271.  
  272.     test    CS:switches,BLANKMASK    ;Did we just force blanking?
  273.     jnz    SkipRestore        ;yep, leave blank screen alone
  274.  
  275.     mov    ax,CS:screendelay    ; Reset screen blank counter
  276.     mov    CS:scrcount,ax
  277.  
  278.     test    CS:switches,SCRMASK    ;Is screen active?
  279.     jnz    SkipRestore        ;yep, video is NOT blanked
  280.      call    RestoreScreen        ;was inactive (blanked),turn it back on
  281.  
  282. SkipRestore:
  283.     in    al,KBINPORT        ; Get scan code from keyboard
  284.  
  285.     test    CS:switches,CTRLMASK    ; Check if currently in control mode
  286.     jnz    In_Control        ;yep
  287.      jmp    NotControl        ;nope
  288.  
  289. In_Control:
  290. ;------ FASTBUFF control key check when keypad #5 is depressed
  291.  
  292.     cmp    al,FBCTRLKEY+80H    ; Check if control key was released
  293.     jne    NotReleased        ;nope
  294.      push    ax            ;save AX
  295.      and    CS:switches,NOT CTRLMASK ; Turn off control mode
  296.      jmp    CallOld9        ;(will pop AX)
  297.  
  298. NotReleased:
  299. ;2.4    Adding screen blanking with [5] End combo
  300. ;    Check this first so we don't clear the BLANKMASK bit prematurely.
  301.  
  302.     cmp    al,FBENDKEY+80H        ;just released [END] key?
  303. ;    jz    Reset1            ;yep, do nothing
  304.     jz    Reset            ;yep, do nothing
  305.  
  306.     cmp    al,FBENDKEY        ;[5] END?
  307.     jnz    K00            ;nope
  308.      call    Check_Delay        ;insure we have refresh rate
  309.      mov    CS:scrcount,1        ;set up so NEXT clock tick
  310.                     ;it'll blank the screen
  311.      mov    al,VIDMASK + BLANKMASK    ;turn video blanking
  312.                     ;and forced blanking on
  313.      jmp    short On_ClearAll    ;common code
  314.  
  315.  
  316. ;    Screen blank toggle
  317.  
  318. K00:
  319.     and    CS:switches,NOT BLANKMASK    ;NOW turn the forced
  320.                     ;blanking bit off
  321.  
  322.     cmp    al,FBHOMEKEY        ;[5] HOME?
  323.     jnz    K0            ;nope
  324.  
  325.     call    Check_Delay        ;insure we have refresh rate
  326.                     ;(AX = old or default rate)
  327.     mov    CS:scrcount,ax        ;reset blanking counter
  328.     mov    al,CS:switches        ;get old switches
  329.     and    al,VIDMASK        ;mask for video blanking bit
  330.     jmp    short Off_ClearAll    ;toggle it with an XOR
  331.  
  332.  
  333. K0:
  334.     cmp    al,FBONKEY        ;[5] INS?
  335.     jne    K1            ;nope
  336.      mov    al,FBMASK        ;prepare to turn on FASTBUFF
  337.      jmp    short On_ClearAll
  338.  
  339. K1:
  340.     cmp    al,FBOFFKEY        ;[5] DEL?
  341.     jne    K2            ;nope
  342.      mov    al,FBMASK        ; Turn off FASTBUFF
  343.  
  344. Off_ClearAll:
  345.     xor    CS:switches,al        ;turn off whatever
  346.     mov    ax,LOFREQ        ;low for off
  347.     jmp    short ClearAll        ;finish up
  348.  
  349. On_ClearAll:
  350.     or    CS:switches,al        ;mask on whatever
  351.     mov    ax,HIFREQ        ;hi for on
  352. ClearAll:
  353.     call    ErrBeep            ;beep low or high
  354.     call    Clear_All        ;Clear both keyboard buffers
  355.     jmp    short Reset        ;and skip to reset
  356.  
  357. K2:
  358.     test    CS:switches,FBMASK    ; FASTBUFF on?
  359.     jz    NotPressed        ;nope
  360.  
  361.     cmp    al,FBFAST        ;[5] +?
  362.     jne    K3            ;nope
  363.      mov    ax,HIFREQ        ;high beep for fast
  364.      call    ErrBeep
  365.      mov    al,FASTREP        ;set fast repeat rate
  366.      jmp    short SetRep        ;do it (1 beep)
  367.  
  368. K3:
  369.     cmp    al,FBSLOW        ;[5] -?
  370.     jne    NotPressed        ;nope, none of our control keys
  371.      mov    ax,LOFREQ        ;low beep for slow
  372.      call    ErrBeep
  373.      mov    al,SLOWREP        ;set slow repeat rate
  374. SetRep:
  375.     mov    CS:repchars,al        ;set to fast or slow repeat rate
  376.  
  377. Reset:
  378. ;Allow old interrupt handler to see the keystroke entered,
  379. ;but ignore any output character.
  380.  
  381.     cli
  382.     mov    ax,biostail
  383.     pushf
  384.     call    dword ptr CS:oldint9
  385.     mov    biostail,ax
  386.     sti
  387.     jmp    Int9Done
  388.  
  389. ;------ Not currently in control mode so check for other possibilities
  390.  
  391. NotControl:
  392.     and    CS:switches,NOT BLANKMASK    ;NOW turn the forced
  393.                     ;blanking bit off
  394.  
  395.     cmp    al,FBCTRLKEY        ; Check if our control key pressed
  396.     jne    NotPressed
  397.      or    CS:switches,CTRLMASK    ; Turn on control mode
  398.  
  399. NotPressed:
  400.  
  401. ;------ Finally we will check to see if FASTBUFF is active
  402.  
  403.     test    CS:switches,FBMASK    ; FASTBUFF on?
  404.     jz    Off1            ;nope
  405.  
  406.     cmp    al,37H            ; If Shift-PrtSc is pressed then just
  407.     jne    On1            ;    call old handler and exit
  408.     test    biosshflags,3
  409.     jz    On1
  410.  
  411. Off1:
  412.     pushf                ; Not on so call old int9 and exit
  413.     call    dword ptr CS:oldint9
  414.     jmp    Int9Done
  415.  
  416.  
  417. On1:
  418.     cmp    al,ALTSHIFT+80H        ; Check if Alt key released
  419.     jne    NotAlt
  420.      mov    ah,biosaltbuff        ; If so save alt-keypad character
  421.      push    ax            ;save AX for after CallOld9
  422.      jmp    short CallOld9
  423.  
  424. NotAlt:
  425.     push    ax            ;(CallOld9 will pop)
  426.     mov    al,biosshflags
  427.     and    al,0FH
  428.     cmp    al,CLRMASK        ; Clear key combination pressed?
  429.     jne    CallOld9        ;nope
  430.      call    Clear_All        ;clear out buffers
  431.  
  432. ;------ Let the old BIOS handler determine what the ASCII or extended
  433. ;    character code should be.
  434.  
  435. CallOld9:
  436.     or    CS:switches,OLDINT9MASK ; Set bit so we don't update BIOS buff
  437.     mov    bx,biostail        ; Make old int 9 do the dirty work
  438.     pushf
  439.     call    dword ptr CS:oldint9
  440.     mov    dx,[bx]            ; Store new char in DX
  441.     mov    cx,biostail
  442.     mov    biostail,bx
  443.     and    CS:switches,NOT OLDINT9MASK
  444.  
  445.     test    biosbreak,BREAKMASK
  446.     jz    CheckNew
  447.  
  448.     cli
  449.     mov    bioshead,bx
  450.     mov    bx,CS:head        ; Break detected, clear our buffers
  451.     mov    word ptr CS:[bx],0    ;   and output dummy character
  452.     call    IncBuff
  453.     mov    CS:tail,bx
  454.     sti
  455.     pop    ax            ;discard saved AX
  456.     jmp    short Int9Done
  457.  
  458. CheckNew:
  459.     pop    ax            ;saved AX
  460.     cmp    bx,cx
  461.     jne    NewChar
  462.      mov    CS:lastchar,0FFFFH    ; Set non-typeable char as lastchar
  463.      jmp    short Int9Done
  464.  
  465. NewChar:
  466.     cmp    al,ALTSHIFT+80H        ; Check if Alt key released
  467.     jne    PutIn
  468.      mov    dl,ah            ; Fix entered character with keypad
  469.      xor    dh,dh            ; Scan code = 0
  470. PutIn:
  471.     call    NewInChar
  472. Int9Done:
  473.     pop    DS
  474.     pop    dx
  475.     pop    cx
  476.     pop    bx
  477.     pop    ax
  478.     iret
  479.  
  480. NewInt9        endp
  481.  
  482. ;------ NewInChar -  Take char from BIOS buffer and insert it into ours,
  483. ;             then set repeat switch accordingly.
  484.  
  485. ;        DS contains BIOSDSEG
  486. ;        DX contains character that was return by old int 9
  487. ;Called 1 time
  488.  
  489. NewInChar    proc    near
  490.  
  491.     push    si
  492.  
  493.     cmp    dx,CS:lastchar
  494.     je    InDone            ; Ignore character if it was from STD
  495.                     ;   repeat function
  496.     mov    CS:lastchar,dx
  497.     mov    al,CS:startdelay    ; Set start delay for repeat function
  498.     mov    CS:repcount,al
  499.     mov    bx,CS:tail
  500.     mov    si,bx            ; Save address where char will go
  501.     call    IncBuff            ;bump/wrap bx
  502.     cmp    bx,CS:head        ;overrun?
  503.     jne    StorChar        ;nope
  504.      mov    ax,ERRFREQ        ;error frequency
  505.      call    ErrBeep            ;beep
  506.      jmp    short InDone        ;don't store
  507.  
  508. StorChar:
  509.     cli
  510.     mov    CS:[si],dx        ; Store character
  511.     mov    CS:tail,bx        ; Store new tail value
  512.     sti
  513. InDone:
  514.     or    dh,dh            ; Scan code=0 if entered on keypad
  515.     jne    SwitchOn
  516.      test    biosshflags,02H        ; Allow chars entered via the
  517.      jz    ReallyDone        ;   keypad to repeat if the user is
  518. SwitchOn:                ;   holding down the Left Shift key.
  519.     or    CS:switches,REPMASK
  520. ReallyDone:
  521.     pop    si
  522.     ret
  523.  
  524. NewInChar    endp
  525.  
  526.  
  527. ;    Clear_All .. NewInt9 subroutine.
  528. ;    Effectively flushes keyboard buffers
  529. ;    Called 2 times
  530.  
  531. Clear_All    proc    near
  532.  
  533.     ASSUME    DS:Page40
  534.  
  535.     cli
  536.     mov    ax,biostail        ; Clear out buffers
  537.     mov    bioshead,ax
  538.     mov    ax,CS:tail
  539.     mov    CS:head,ax
  540.     sti
  541.     ret
  542.  
  543. Clear_All    endp
  544.  
  545.  
  546. ;    Common subroutine for NewInt9
  547. ;    Insures we have a screendelay refresh rate
  548. ;    when toggling or otherwise fiddling screen blanking.
  549. ;    Called 2 times.
  550. ;    Returns AX = original screendelay or default
  551.  
  552. Check_Delay    proc    near
  553.  
  554.     mov    ax,CS:screendelay    ;get refresh rate
  555.     or    ax,ax            ;0 (because of '-V0' cmd)?
  556.     jnz    CD_Exit            ;nope, got refresh rate
  557.      mov    ax,BLANKTIME        ;was 0, use default
  558.      mov    CS:screendelay,ax    ;force default refresh rate
  559.  
  560. CD_Exit:
  561.     ret
  562.  
  563. Check_Delay    endp
  564.  
  565.  
  566. ;Beep routines
  567. ;Toad Hall:
  568. ;    My system was producing an irritating click (in addition to the
  569. ;    desired beep) when using the "direct speaker drive" code.
  570. ;    Recoded to use the 8259 timer-driven tone.
  571.  
  572. ;Enter with desired frequency in AX.
  573. ;ErrBeep calls Prepare_Timer before we do any beeps.
  574. ;Since we don't know what the outside world is doing to the timer,
  575. ;we reset it every time we're gonna beep.
  576. ;(Probably unnecessary .. but better safe than sorry).
  577. ;Hope no one else is trying to use the timer!
  578.  
  579. Prepare_Timer    proc    near
  580. ;Destroys AX
  581.  
  582.     push    ax            ;save the freq
  583.     mov    al,182    ;10110110B    ;Sel tim 2,lsb,msb,binary
  584.     out    TIMER+3,al        ;get timer ready
  585.     pop    ax            ;desired frequency
  586.     out    TIMER+2,al        ;load low-order byte
  587.     mov    al,ah
  588.     out    TIMER+2,al        ;and hi-order byte
  589.     ret
  590.  
  591. Prepare_Timer    endp
  592.  
  593.  
  594. ErrBeep    proc    near
  595. ;Destroys AX,CX
  596.  
  597.     call    Prepare_Timer        ;set up timer frequency
  598.     in    al,PORT_B        ;Get current port status
  599.     mov    ah,al            ;and save it
  600.     or    al,3            ;set bits 0 and 1 on
  601.     out    PORT_B,al
  602.     xor    cx,cx            ;around 500 ms for a 4.47MHz system
  603. ErrBLup:
  604.     loop    ErrBLup
  605.     mov    al,ah            ;orig port setting
  606.     out    PORT_B,al        ;better be sound off!
  607.     ret
  608.  
  609. ErrBeep    endp
  610.  
  611.  
  612. ;---------------------------- Int 10 --------------------------------------
  613. ;Video I/O
  614. ;--------------------------------------------------------------------------
  615.  
  616. ;    We ARE concerned about minimizing interrupt delays here.
  617.  
  618. NewInt10    proc    far
  619.  
  620.     sti
  621.     cmp    ah,0FAH            ; Return value to indicate FASTBUFF
  622.     jne    Vid            ;   is already resident
  623.      mov    ax,CS            ;Let's return our segment in ES
  624.      mov    ES,ax            ;(for future reaching out...)
  625.      mov    ax,0FAH            ;return value in AL
  626.      iret
  627.  
  628. Vid:
  629.     push    ax
  630.  
  631.     mov    ax,CS:screendelay    ; Reset screen blanking counter
  632.     mov    CS:scrcount,ax
  633.     test    CS:switches,SCRMASK    ; Check if video is currently blanked
  634.     jnz    SkipRest        ;nope, it's active
  635.  
  636.      push    DS            ;Set up DS for RestoreScreen
  637.  
  638.      mov    ax,40H
  639.      mov    DS,ax
  640.      ASSUME DS:Page40
  641.  
  642.      push    cx            ;save
  643.      push    dx            ;(RestoreScreen doesn't)
  644.      call    RestoreScreen        ;turn it back on
  645.      pop    dx
  646.      pop    cx
  647.      pop    DS            ;restore DS
  648.      ASSUME DS: NOTHING
  649.  
  650. SkipRest:
  651.     pop    ax
  652.     jmp    dword ptr CS:oldint10    ; Pass control on
  653.                     ; to normal Video I/O
  654. NewInt10    endp
  655.  
  656.  
  657. ;------------------------------- Int 8 ------------------------------------
  658. ;Hardware Timer Tick  (changed from int 1CH in v2.3)
  659. ;--------------------------------------------------------------------------
  660.  
  661. ;    VERY likely place for interrupt delays.
  662. ;    Optimizing to the max for speed.
  663.  
  664. NewInt8        proc    far
  665.  
  666.     pushf
  667.     call    dword ptr CS:oldint8    ; IMPORTANT!  Call old hardware
  668.                     ;   interrupt first to avoid possible
  669.                     ;   hardware timing problems (such as
  670.                     ;   possible when formatting a disk).
  671.     sti
  672.     push    ax
  673.     mov    al,CS:switches        ;faster testing in AL
  674.     test    al,FBMASK        ;FASTBUFF on?
  675.     jz    Timer_NoAct        ;nope
  676.  
  677. ;    Let's do some testing right here to see if we have ANY work to do.
  678. ;    I know .. the testing is redundant .. but we may save the PUSHes
  679. ;    and POPs (especially if VIDMASK is turned off).
  680.  
  681.     test    al,OLDINT9MASK        ;currently using BIOS buff?
  682.     jz    Timer_GotWork        ;nope, got work
  683.  
  684.     test    al,REPMASK        ;repeat switch on?
  685.     jz    Chk_Video        ;nope
  686.      cmp    CS:repcount,1        ;upcoming decrement zeroes it?
  687.      jz    Timer_GotWork        ;yep, it'll be 0 .. got work
  688.  
  689. Chk_Video:                ;Test video blanking last
  690.     test    al,VIDMASK        ;video blanking on?
  691.     jz    Timer_NoAct        ;nope, no work at all
  692.  
  693.     test    al,SCRMASK        ;screen already blanked?
  694.     jz    Timer_NoAct        ;yep, no work at all
  695.  
  696. ;    Let's make sure a (scrcount=0) doesn't bite us, ne?
  697.  
  698.      cmp    CS:scrcount,1        ;upcoming decrement zeroes it
  699.                     ;or we're already <= 0?
  700.      ja    Timer_NoAct        ;nope, nothing to do, exit
  701.  
  702.  
  703. Timer_GotWork:
  704.  
  705. ;BlankScreen destroys AX,BX,CX,DX,ES
  706. ;Let's save all our regs NOW rather than later AND in BlankScreen.
  707.  
  708.     push    bx
  709.     push    cx
  710.     push    dx
  711.     push    di
  712.     push    si
  713.     push    DS
  714.  
  715.     mov    bx,40H
  716.     mov    DS,bx
  717.     ASSUME  DS:Page40
  718.  
  719.  
  720.     test    al,VIDMASK        ;video blanking on?
  721.     jz    DontBlank        ;nope
  722.     test    al,SCRMASK        ;Is screen active?
  723.     jz    DontBlank        ;nope, already blanked
  724.  
  725.  
  726. ;    Let's be sure a (scrcount=0) doesn't bite us, ne?
  727.  
  728.     sub    CS:scrcount,1        ;decr blanking counter
  729.     ja    DontBlank        ;> 0, not time
  730.  
  731. ;    Doesn't matter if scrcount is below 0, since the first keyboard
  732. ;    interrupt or Int 10H video I/O will reset scrcount to a proper value.
  733.  
  734.      call    BlankScreen        ;go blank the screen
  735.      mov    al,CS:switches        ;refresh AL with switches
  736.  
  737. DontBlank:
  738.  
  739.     test    al,OLDINT9MASK        ; If currently using BIOS buff
  740.     jnz    SkipUpdate        ;   don't try to update it.
  741.      call    UpdateBIOS        ; Insert characters into BIOS buffer
  742.      mov    al,CS:switches        ;refresh AL with switches
  743. SkipUpdate:                ;   from our buffer.
  744.  
  745.     test    al,REPMASK        ;repeat switch on?
  746.     jz    NoRep            ;nope
  747.      dec    CS:repcount        ;decrement repeat counter
  748.      jnz    NoRep            ;didn't zero
  749.       call  RepKey            ; Otherwise repeat the key.
  750.                     ;(done with AL)
  751. NoRep:
  752.     pop    DS
  753.     pop    si
  754.     pop    di
  755.     pop    dx
  756.     pop    cx
  757.     pop    bx
  758.  
  759. Timer_NoAct:
  760.     pop    ax
  761.     iret
  762.  
  763. NewInt8        endp
  764.  
  765.  
  766. ;------ UpdateBIOS - Put characters from our buffer into the BIOS buffer
  767.  
  768. ;    Note: don't fill BIOS buffer completely, leave space for
  769. ;          at least one character.  This is required to allow
  770. ;          the int9 handler to use this spot as its input buffer.
  771.  
  772. ;Called 1 time by NewInt8
  773.  
  774. UpdateBIOS       proc  near
  775.     ASSUME  DS:Page40
  776.  
  777.     mov    dx,biostail        ; Pointer to the BIOS buffer tail
  778.     mov    cx,dx            ;CX = BIOS tail ptr
  779.     call    BIOSIncBuff        ;ZF set if BIOS buffer full
  780.                     ;DX = BIOS tail + 2
  781.     je    Udone            ;BIOS buffer full
  782.  
  783. ;    NOW we have a reason to load BX.
  784. ;    While we're at it .. we have one register left (SI).
  785. ;    Let's use it as a constant (2) for bumping BX, DX.
  786.  
  787.     mov    bx,CS:head        ; Pointer to our buffer head
  788.     mov    si,2            ;handy constant
  789.  
  790. Uloop:
  791.     cmp    bx,CS:tail        ; Check if we have any characters
  792.     je    Udone            ;   left to insert
  793.  
  794.     mov    ax,CS:[bx]        ;get char before bumping BX
  795.     add    bx,si            ;bump BX 2
  796.     cmp    bx,CS:endbuff
  797.     jne    ULOk
  798.      mov    bx,offset buffer
  799. ULOk:
  800.  
  801. ;Make sure BIOS has room for at least two characters
  802. ;before inserting another.
  803.  
  804.     mov    di,cx            ;last DX BIOS tail ptr (before +2)
  805.     mov    cx,dx            ;BIOS tail + 2
  806.  
  807.     add    dx,si            ;bump DX BIOS tail buffer ptr
  808.     cmp    dx,offset biosendbuff    ;hit end?
  809.     jne    ULBok            ;not yet
  810.      mov    dx,offset biosbuffer    ;yep, back to start
  811. ULBok:
  812.     cmp    dx,bioshead        ;hit BIOS head ptr?
  813.     je    Udone            ;yep, BIOS buffer full
  814.  
  815. ;If character was inserted, then update the head and tail pointers.
  816.     mov    CS:head,bx        ;our buffer head ptr
  817.     mov    biostail,cx        ;BIOS tail ptr (DX before the +2)
  818.     mov    [di],ax            ;stuff char at last DX
  819.     jmp    Uloop
  820.  
  821. Udone:
  822.     ret
  823. UpdateBIOS       endp
  824.  
  825.  
  826. ;------ RepKey - repeat key only if the program is ready to accept more
  827.  
  828. ;Called 1 time by NewInt8
  829.  
  830. RepKey  proc    near
  831.     ASSUME  DS:Page40
  832.  
  833.     mov    CS:repcount,1        ; Set fast repeat rate
  834.  
  835. ;    Recoded for speed, tightness
  836.  
  837.     mov    ax,biostail
  838.     cmp    ax,bioshead        ; Anti-skid braking check
  839.     jne    Rdone
  840.  
  841.     mov    di,ax            ;DS:DI points to BIOS buffer
  842.     mov    ax,CS:lastchar        ;store repeat char in AX
  843.     xor    ch,ch
  844.     mov    cl,CS:repchars        ; Set CX for # times to repeat char
  845.     mov    bx,offset biosendbuff    ;handy constant for testing
  846.     mov    si,2            ;handy constant for bumping DI
  847.     cld                ;insure fwd
  848.  
  849. RepLoop:
  850.     mov    [di],ax            ;stuff
  851.     add    di,si            ;bump DI 2
  852.     cmp    di,bx            ;hit buffer end?
  853.     jne    RepOk            ;not yet
  854.      mov    di,offset biosbuffer    ;yep, back to start
  855. RepOk:
  856.     loop    RepLoop
  857.     mov    biostail,di        ; Update tail pointer
  858. Rdone:
  859.     ret
  860.  
  861. RepKey  endp
  862.  
  863.  
  864. ;------ IncBuff - Increment a FASTBUFF buffer pointer stored in BX
  865.  
  866. IncBuff proc    near
  867.  
  868.     add    bx,2
  869.     cmp    bx,CS:endbuff
  870.     jne    Ok
  871.      mov    bx,offset buffer
  872. Ok:    ret
  873.  
  874. IncBuff endp
  875.  
  876.  
  877. ;------ BIOSIncBuff - Same thing, but for BIOS buffer pointer in DX
  878.  
  879. BIOSIncBuff    proc    near
  880.     ASSUME  DS:Page40
  881.  
  882.     add    dx,2
  883.     cmp    dx,offset biosendbuff
  884.     jne    Bok
  885.      mov    dx,offset biosbuffer
  886. Bok:
  887.     cmp    dx,bioshead        ; Make sure BIOS buffer not full
  888.                     ;(common test every call)
  889.     ret
  890.  
  891. BIOSIncBuff    endp
  892.  
  893. ;--------------------------------------------------------------------------
  894. ;Video Blanking / Restoring procedures
  895. ;--------------------------------------------------------------------------
  896.  
  897. ;------BlankScreen - Turn off video display
  898.  
  899. ;Called 1 time by NewInt8
  900. ;Regs already saved, OK to destroy everything.
  901. ;Reducing CLIs to absolute minimum time off
  902.  
  903. BlankScreen    proc    near
  904.  
  905.     ASSUME  DS:Page40            ;already done
  906.  
  907.     mov    ax,2B21H
  908.     call    SetVideo            ;AL reset to 21H
  909.  
  910.     test    biosequipflags,EQUIPMASK
  911.     jnz    JJ2                ;yep, AL=21H
  912.      mov    al,bioscrtmodeset
  913.      and    al,0F7H
  914.      mov    bioscrtmodeset,al
  915.  
  916. JJ2:    mov    dx,03D8H
  917.     cli
  918.     out    dx,al
  919.     mov    al,biospalette
  920.     test    al,PALETTEMASK
  921.     jz    BlankDone
  922.      and    al,0F0H
  923.      inc    dx                ;now 03D9H
  924.      out    dx,al
  925. BlankDone:
  926.     sti
  927.     and    CS:switches,NOT SCRMASK        ; Clear screen active flag
  928.     call    ErrBeep                ;Let user know we did it
  929.     ret
  930.  
  931. BlankScreen    endp
  932.  
  933. ;------ RestoreScreen - Turn video display back on
  934.  
  935. ;Called 2 times (by NewInt9 and NewInt10)
  936. ;    Reducing CLIs to absolute minimum time off
  937.  
  938. RestoreScreen    proc    near
  939.     ASSUME  DS:Page40
  940.  
  941.     mov    ax,0B29H
  942.     call    SetVideo        ;AL reset to 29H
  943.  
  944.     test    biosequipflags,EQUIPMASK
  945.     jnz    J2            ;yep, AL=29H
  946.      mov    al,bioscrtmodeset
  947.      or    al,08H
  948.      mov    bioscrtmodeset,al
  949. J2:    mov    dx,03D8H
  950.     cli
  951.     out    dx,al
  952.     mov    al,biospalette
  953.     test    al,PALETTEMASK
  954.     jz    RestoreDone
  955.      inc    dx            ;now 03D9H
  956.      out    dx,al
  957. RestoreDone:
  958.     sti
  959.     or    CS:switches,SCRMASK    ; Reset screen active flag
  960.  
  961.     ret
  962.  
  963. RestoreScreen    endp
  964.  
  965.  
  966. ;------ SetVideo - set video according to contents of CX
  967.  
  968. ;        Destroys DX and AX registers also
  969.  
  970. ;Called 2 times (by BlankScreen and RestoreScreen)
  971. ;Common to output AL to DX first.
  972. ;Reducing CLIs to absolute minimum time off
  973.  
  974. SetVideo    proc    near
  975.  
  976.     mov    dx,03B8H        ;common to 2 calls
  977.     push    ax            ;save the 2BH (blank)
  978.                     ; or 0BH (restore) in AH
  979.     cli
  980.     out    dx,al            ;output 21H (blank)
  981.                     ; or 29H (restore)
  982.     mov    dx,03B4H
  983.     mov    al,0AH
  984.     out    dx,al
  985.     inc    dx            ;03B5H
  986.     pop    ax            ;AH=2BH (blank) or 0BH (restore)
  987.     xchg    al,ah            ;prepare AL,
  988.                     ;AH= orig 21H or 29H for return
  989.     out    dx,al            ;output 2BH or 0BH
  990.     mov    al,0BH
  991.     out    dx,al
  992.     inc    dx            ;03B6H
  993.     inc    al            ;from 0BH to 0CH
  994.     out    dx,al
  995.     sti
  996.     mov    al,ah            ;AL = orig 21H or 29H
  997.     ret
  998.  
  999. SetVideo    endp
  1000.  
  1001. ;------ This portion must remain at the end, since the location of the
  1002. ;    end of the buffer indicates how large the resident portion is.
  1003.  
  1004. head        dw    buffer        ; FASTBUFF buffer head and
  1005. tail        dw    buffer        ;   tail pointers
  1006. endbuff        dw    86        ; Buffer size (100, after
  1007.                     ;  subtracting additional
  1008.                     ;  14 chars in BIOS buff)
  1009.                     ; Will end up holding pointer
  1010.                     ;  last buffer byte
  1011.  
  1012. buffer        dw    ?        ; New keyboard buffer.
  1013.  
  1014. ;---------------------- Initialize vectors --------------------------------
  1015. ;
  1016. ;    After successful initialization process release memory from
  1017. ;    here on down, terminate and stay resident.
  1018. ;--------------------------------------------------------------------------
  1019. Initialize:
  1020.  
  1021.     ASSUME  CS:CSEG,DS:CSEG
  1022.  
  1023.     call    Check_Args        ;check PSP cmdline arguments
  1024.                     ;(may die)
  1025.  
  1026.     mov    ah,0FAH            ; Check if FASTBUFF is already
  1027.     int    10H            ;   installed
  1028.     ASSUME    ES:NOTHING        ;if resident, ES=resident CS
  1029.  
  1030.     cmp    ax,0FAH
  1031.     jne    InstallOk        ;Nope, continue
  1032.  
  1033. ;Toad Hall:
  1034. ;    We REALLY should have a snazzy way to reach down
  1035. ;    into memory (where a resident FASTBUFF is installed)
  1036. ;    and change ITS runtime parameters!
  1037. ;    However .. with all the interrupt-driven stuff ..
  1038. ;    I'm almost afraid to touch the resident program!
  1039. ;    However .. I added to the Svc 0FAH, Int 10H routine (in the
  1040. ;    TSR code) returning ES=resident CS ..
  1041. ;    so we have a pointer to the resident code if we want it!
  1042.  
  1043.     mov    dx,offset error        ; Print error message
  1044. Msg_Term:                ;jmp here if DX has a fatal
  1045.                     ;error msg
  1046.     mov    ah,09H            ;display msg
  1047.     int    21H
  1048.  
  1049. Terminate:
  1050.     mov    ax,4C01H        ;terminate, ERRORLEVEL 1
  1051.     int    21H
  1052.  
  1053.  
  1054. InstallOk:
  1055.     mov    dx,offset instalmsg    ; Print installation message
  1056.     mov    ah,09H
  1057.     int    21H
  1058.  
  1059. ;Toad Hall:
  1060. ;    Since we're releasing environment, utilities like MAPMEM
  1061. ;    no longer can find/display our program name.
  1062. ;    Moving a likely identifier into our PSP command line
  1063. ;    (since _Args is done with it).
  1064. ;    I know .. we lose peeking at the args, but that's ok.
  1065.  
  1066.     mov    ax,CS
  1067.     mov    ES,ax            ;insure
  1068.     ASSUME    ES:CSEG
  1069.  
  1070.     mov    si,dx            ;-> instalmsg
  1071.     mov    di,offset nchar        ;-> cmdline char counter
  1072.     mov    ax,INSTALMSGLEN        ;nr of chars we'll be moving
  1073.     dec    ax            ;remove the '$'
  1074.     dec    ax            ;and the LF
  1075.     mov    cx,ax            ;nr chars to move
  1076.     mov    ah,' '            ;AL=length byte,AH=space
  1077.     stosw                ;stuff length byte, space
  1078.     rep    movsb            ;copy msg into PSP cmdline
  1079.  
  1080. ;    Runtime variables already have defaults.
  1081. ;    Commandline processing may have changed them
  1082. ;    to new values.
  1083. ;    Previous fiddling of video blanking bit now moved
  1084. ;    down into video blank delay subroutine.
  1085.  
  1086. ;Determine buffer size in bytes and find endbuff address
  1087.  
  1088.     mov    ax,endbuff        ;requested or default buffer size
  1089.     shl    ax,1            ;*2 for words
  1090.     add    ax,offset buffer+2    ;+ buffer start + 2
  1091.     mov    endbuff,ax        ;save as endbuff pointer
  1092.  
  1093. ;    Try to free our environment block's memory
  1094. ;    as part of preparing to go TSR.
  1095. ;    If we fail at this, let's quit without messing with vectors.
  1096.  
  1097.     mov    ES,env_adr        ;PSP environment seg
  1098.     ASSUME    ES:NOTHING        ;a reminder
  1099.  
  1100.     mov    ah,49H            ;free allocated memory
  1101.     int    21H
  1102.     jnb    Env_Freed        ;freed ok, continue
  1103.      mov    dx,offset envmsg    ;'Failed to free memory'
  1104.      jmp    Msg_Term        ;display msg, terminate
  1105.  
  1106. Env_Freed:
  1107.  
  1108.     mov    ax,40H
  1109.     mov    ES,ax
  1110.     ASSUME  ES:Page40
  1111.  
  1112.     mov    ax,ES:biostail        ; Clear BIOS keyboard buffer
  1113.     mov    ES:bioshead,ax
  1114.  
  1115.     mov    ax,3509H        ;save old Int 9 vector
  1116.     int    21H
  1117.     mov    oldint9,bx
  1118.     mov    oldint9[2],ES
  1119.     mov    dx,offset NewInt9
  1120.     mov    ax,2509H        ;set new one
  1121.     int    21H
  1122.  
  1123.     mov    ax,3510H        ;save old Int 10H vector
  1124.     int    21H
  1125.     mov    oldint10,bx
  1126.     mov    oldint10[2],ES
  1127.     mov    dx,offset NewInt10
  1128.     mov    ax,2510H        ;set new one
  1129.     int    21H
  1130.  
  1131.     mov    ax,3508H        ;save old Int 8H vector
  1132.     int    21H
  1133.     mov    oldint8,bx
  1134.     mov    oldint8[2],ES
  1135.     mov    dx,offset NewInt8
  1136.     mov    ax,2508H        ;set new one
  1137.     int    21H
  1138.  
  1139. ;    Go TSR properly.
  1140.  
  1141.     mov    ax,endbuff        ;pointer to buffer
  1142.                     ; (and resident data) end
  1143.     add    ax,15            ;round up to a para
  1144.     mov    cl,4
  1145.     shr    ax,cl            ;convert to paragraphs
  1146.     mov    dx,ax            ;DX needs it
  1147.     mov    ax,3100H        ;Advanced TSR, code 0
  1148.     or    switches,FBMASK        ; Turn FASTBUFF on (last thing)
  1149.     int    21H            ;go TSR
  1150.  
  1151.     ASSUME  DS:CSEG,ES:CSEG
  1152.  
  1153. ;------ CheckPSP - Check command line parameters
  1154.  
  1155. ;    Note: this procedure may destroy any registers except DS
  1156.  
  1157. Comment    ~
  1158.  
  1159. Toad Hall:
  1160.     Something's been SERIOUSLY wrong with this entire procedure.
  1161.     (like locking up with '/v0').
  1162.     Replacing with an entirely new args procedure (snarfed from
  1163.     Kegel's KEGELUNX.ARC package and severely hacked for this
  1164.     specific application).
  1165.  
  1166. Comment    ends    ~
  1167.  
  1168.  
  1169. ;    New command line argument procedures
  1170. ;    An array of argv pointers point to separate parameters
  1171. ;    maintained in the PSP command line buffer.
  1172. ;    (This only works if we aren't opening/closing files!)
  1173. ;    See dynamic variables argc and argv at code end.
  1174. ;    Thanks to Kegel and his Unix-like utils in KEGELUNX.ARC
  1175. ;    Although we only provide for 7 cmdline switch types,
  1176. ;    the user might enter more, enter duplicates, whatever.
  1177. ;    Allowing for a full dozen.  (What the heck .. it's only
  1178. ;    dynamic variables anyway ... !)
  1179.  
  1180. MAXPARMS    equ    12        ;max cmdline args permitted
  1181.  
  1182. _Args    proc    near
  1183.  
  1184.     mov    di,offset argv        ;first argv pointer
  1185.     mov    cx,MAXPARMS        ;max parms allowed
  1186.     xor    ax,ax
  1187.     rep    stosw            ;point all args at null
  1188.  
  1189.     mov    bx, 2            ; argc = 0 (will sub 2 from bx at end)
  1190.  
  1191.     mov    si,offset nchar        ;cmdline char count
  1192.     lodsb                ;snarf, bump SI ptr
  1193.     mov    cl,al            ;into CX for counter
  1194.     xor    ch,ch
  1195.     jcxz    A_Done            ; no arg chars -> we're done.
  1196.  
  1197.     mov    di,si
  1198.  
  1199. ;Uppercase the entire command line.
  1200. ;While we're at it, replace all spaces with 0's
  1201. ;(to INSURE each argv is AsciiZed).
  1202.  
  1203.     push    cx            ;save cmdline char count
  1204.  
  1205.     mov    dx,2000H + 'a'        ;handy constant
  1206.  
  1207. A_UpperLup:
  1208.     mov    al,[di]            ;snarf PSP cmdline char
  1209.     cmp    al,dh            ;space?
  1210.     jnz    A_NotSpace        ;nope, more checking
  1211.      xor    al,al            ;replace with a 0
  1212.      jmp    short A_Stuff
  1213.  
  1214. A_NotSpace:
  1215.     cmp    al,dl    ;'a'        ;lower case?
  1216.     jb    A_Stuff            ;nope
  1217.      sub    al,dh    ;20H        ;uppercase it
  1218. A_Stuff:
  1219.     stosb
  1220.     loop    A_UpperLup
  1221.  
  1222.     xor    al,al            ;replace CR with a 0        v2.6
  1223.     stosb                ;                v2.6
  1224.  
  1225.     pop    cx            ;restore cmdline counter
  1226.  
  1227. ;v2.6    If there's a '?' anywhere on the cmdline,
  1228. ;    skip directly to help and terminate.
  1229.  
  1230.     mov    di,si            ;back to first char of cmdline    v2.6
  1231.     mov    dx,cx            ;save cmdline ctr again        v2.6
  1232.     mov    al,'?'            ;scan for question mark        v2.6
  1233.     repne    scasb
  1234.     mov    cx,dx            ;restore cmdline ctr        v2.6
  1235.     jz    A_Help            ;we found one! help, terminate    v2.6
  1236.  
  1237.     ; Big loop- find arguments...
  1238.  
  1239.     mov    dx,'-/'            ;DL='-', DH='/'
  1240. A_ParmL:
  1241.     lodsb                ; al = [si++]
  1242.     cmp    al,dl    ;'-'        ;look for a switch
  1243.     jz    A_GotOne        ;yep
  1244.      cmp    al,dh    ;'/'        ;this kind?
  1245.     jnz    A_Relup            ;nope, gobble until we find one    v2.6
  1246.  
  1247. A_GotOne:
  1248.     mov    byte ptr [si-1],0    ;stuff a 0 on the switch
  1249.  
  1250.     mov    word ptr argv[bx],si    ; save pointer to this string
  1251.  
  1252.     add    bx,2            ; argc++
  1253.  
  1254.     cmp    bx, MAXPARMS*2
  1255.     jae    A_Done            ;done
  1256.  
  1257. A_Relup:                ;                v2.6
  1258.     jcxz    A_Done            ;stop any CX wraparound to 0FFFFH! v2.6
  1259.     loop    A_ParmL            ;more chars to go        v2.6
  1260.  
  1261. A_Done:
  1262. ; All done finding parms; now share argc with caller.
  1263.  
  1264.     mov    ax,bx
  1265.     sub    ax, 2            ;adjust for argv[0]
  1266.                     ;(traditionally program name)
  1267.     shr    ax, 1
  1268.     mov    word ptr argc,ax    ;save argc
  1269.     ret
  1270.  
  1271. A_Help:    jmp    GetHelp            ;help, terminate
  1272.  
  1273. _Args    endp
  1274.  
  1275.  
  1276. ;---- _Shift: --------------------------------------------
  1277. ; Shifts %2 to %1, %3 to %2, etc.  Leaves %0 alone.
  1278. ; Works by shuffling argv[*].
  1279. ; Destroys BX                                v2.6
  1280.  
  1281. _Shift    proc    near
  1282.  
  1283.     cld
  1284.     mov    si, offset argv[4]
  1285.     mov    di, offset argv[2]
  1286.     mov    bx,offset argc        ;nr of args remaining        v2.6
  1287.     mov    cx,[bx]        ;argc    ;move this many args        v2.6
  1288.     rep    movsw
  1289.     dec    word ptr [bx]    ;argc    ;decr arg counter        v2.6
  1290.     ret
  1291.  
  1292. _Shift    endp
  1293.  
  1294.  
  1295. ;    Check_Args - We've parsed our command line, and all (if any)
  1296. ;    args are in argv[argc] array.
  1297. ;    Check them out and respond accordingly.
  1298.  
  1299. Check_Args    proc    near
  1300.  
  1301.     cld                ;insure fwd
  1302.     call    _Args            ;process command line
  1303.     or    ax,ax            ;got any args at all?
  1304.     jz    CA_X            ;nope, nothing to do        v2.6
  1305.  
  1306. CA_1:    mov    si,word ptr argv[2]    ;first argument
  1307.     or    si,si            ;null arg?
  1308.     jz    CA_X            ;yep, all done
  1309.  
  1310.     lodsb                ;snarf arg's first char
  1311.                     ;AH=0
  1312.     mov    di,offset parmtable
  1313.     mov    cx,LPARMTABLE
  1314.     repne    scasb
  1315.     jne    H1            ;no match, display help and die
  1316.  
  1317.     sub    di,offset parmtable+1    ; Calculate jump address
  1318.                     ;(the +1 adjusts for the last scasb)
  1319.     shl    di,1            ;*2 for addresses
  1320.     call    word ptr jumptable[di]    ;jmp to procedure,
  1321.  
  1322. ;Notice we do NOT shift the argv array until after our subroutines
  1323. ;have had a chance to process the argv string.
  1324. ;The current argv is at argv[argc].
  1325.  
  1326.     call    _Shift            ;move the argv array down one
  1327.     jmp    CA_1            ;and loop for them all
  1328.  
  1329. H1:    jmp    GetHelp            ;Invalid parm found.
  1330.                     ;Display help, terminate
  1331.  
  1332. CA_X:    ret                ;done or nothing to do        v2.6
  1333.  
  1334.  
  1335. Check_Args    endp
  1336.  
  1337.  
  1338. ;------ SetBuff - Set new buffer size
  1339.  
  1340. SetBuff proc    near
  1341.  
  1342.     call    GetNum            ;get buffer value after '/B'
  1343.                     ;(may die)
  1344.  
  1345.     mov    dx,offset toobigmsg    ;'/B value too large!'
  1346.  
  1347.     or    ah,ah            ;bogus if > 255
  1348.     jnz    SetBuff_Bad        ;invalid size
  1349.  
  1350.     mov    dx,offset toosmallmsg    ;'/B value too small!'
  1351.  
  1352.     sub    ax,14            ; We get 14 characters from BIOS buff
  1353.     jb    SetBuff_Bad        ;Went negative!  Gotta be bogus
  1354.  
  1355.     cmp    al,11            ; Make sure we have room in our buffer
  1356.     jb    SetBuff_Bad        ;invalid size
  1357.  
  1358.     mov    endbuff,ax        ;update runtime variable
  1359.     ret
  1360.  
  1361. SetBuff_Bad:
  1362.     mov    ah,9            ;display error msg
  1363.     int    21H
  1364.     jmp    Bad_Num            ;bad number error routine
  1365.                     ;error msg, terminate
  1366.  
  1367. SetBuff endp
  1368.  
  1369. ;------ SetFast - Set startup repeat rate to fast (/F)
  1370.  
  1371. SetFast proc    near
  1372.  
  1373.     mov    repchars,2        ;update runtime variable
  1374.     ret
  1375.  
  1376. SetFast endp
  1377.  
  1378. ;------ SetSlow - Set startup repeat rate to slow (/S)
  1379.  
  1380. SetSlow proc    near
  1381.  
  1382.     mov    repchars,1        ;update runtime variable
  1383.     ret
  1384.  
  1385. SetSlow endp
  1386.  
  1387. ;------ SetDelay - Set delay before a character starts repeating
  1388.  
  1389. SetDelay    proc    near
  1390.  
  1391.     call    GetNum            ;get delay number after '/D'
  1392.                     ;(may die)
  1393.  
  1394.     or    al,al            ;bogus if 0
  1395.     jz    SetDelay_Bad        ;illegal value
  1396.  
  1397.     or    ah,ah            ;bogus if >255
  1398.     jnz    SetDelay_Bad        ;illegal value            v2.9
  1399.  
  1400.     mov    startdelay,al        ;update runtime variable
  1401.     ret
  1402.  
  1403. SetDelay_Bad:
  1404.     jmp    Bad_Num            ;bad number handler
  1405.                     ;error msg, terminate
  1406. SetDelay    endp
  1407.  
  1408. ;------ SetVid - Set amount of time before video is blanked
  1409.  
  1410. SetVid  proc    near
  1411.  
  1412.     call    GetNum            ;get video blank value after '/V'
  1413.                     ;(may die)
  1414.  
  1415.     or    ax,ax            ;0 or no value means no blanking
  1416.     jz    SetVid0            ;0, no delays
  1417.  
  1418.     xor    dx,dx            ;clear for the MUL
  1419.     mov    cx,1092
  1420.     mul    cx            ; 1092 clicks per minute
  1421.     or    dx,dx            ;we get a carry?
  1422.                     ;(e.g., result is bigger
  1423.                     ; than a word)
  1424.     jnz    SetVid_Bad        ;bogus!  Help, die
  1425.  
  1426. SetVid0:
  1427.     mov    screendelay,ax        ;update runtime variable
  1428.     mov    scrcount,ax        ;(both of them)
  1429.  
  1430. ;    While we have the screendelay value handy,
  1431. ;    let's mask switches to turn video blanking on/off
  1432.  
  1433.     or    ax,ax            ;any screen delay set?
  1434.     mov    al,VIDMASK        ;assume video blanking ON
  1435.     jnz    SetVid_On        ;yep
  1436.      not    al            ;flip to turn bit off
  1437.      and    switches,al        ;turn video blanking OFF
  1438.      ret
  1439.  
  1440. SetVid_On:
  1441.     or    switches,al        ;turn video blanking ON
  1442.     ret
  1443.  
  1444. SetVid_Bad:
  1445.     jmp    Bad_Num            ;bad number routine
  1446.  
  1447. SetVid  endp
  1448.  
  1449.  
  1450. ;------ GetHelp - Ouput help screen and set "don't install" flag (hflag)
  1451. ;    Now jumps directly to Msg_Term (display message in DX, terminate).
  1452.  
  1453. GetHelp proc    near
  1454.  
  1455.     mov    dx,offset help        ; Print help screen
  1456.     jmp    Msg_Term        ;display help screen
  1457.                     ;and terminate (no install)
  1458. GetHelp endp
  1459.  
  1460.  
  1461. ;------ GetNum - Calculate a number from the parameter list
  1462.  
  1463. ;    SI -> the char after the initial argument char.
  1464. ;    Returns the number in AX
  1465. ;    Heavily rewritten.
  1466. ;    New code works with argv[argc] array member (an AsciiZ string).
  1467. ;    Added checks for bogus values (e.g., larger than a word).
  1468. ;    If the arg is just the char (e.g., no number),
  1469. ;    GetNum returns AX=0.
  1470. ;    This means something like '/v' is just like '/v0'.
  1471.  
  1472. GetNum  proc    near
  1473.  
  1474.     xor    bh,bh            ;clear msb (just once)
  1475.  
  1476.     xor    ax,ax
  1477.     mov    di,10            ;use DI for a constant multiplier
  1478.     mov    cx,'90'            ;CL='0', CH='9' for fast testing
  1479.  
  1480. ;Accumulate number until we hit a non-numeric character
  1481.  
  1482. NumLoop:
  1483.     mov    bl,[si]
  1484.     cmp    bl,cl    ;'0'        ;(Since this is an AsciiZ string,
  1485.     jb    NumDone            ;the basic algorithm works fine)
  1486.     cmp    bl,ch    ;'9'
  1487.     ja    NumDone
  1488.  
  1489.     xor    dx,dx            ;insure .hi is clear
  1490.     mul    di    ;10
  1491.     or    dx,dx            ;result larger than a word?
  1492.     jnz    Bad_Num            ;yep, illegal, help and die
  1493.  
  1494.     sub    bl,cl    ;'0'
  1495.     add    ax,bx
  1496.     inc    si
  1497.     jmp    NumLoop
  1498.  
  1499. NumDone:
  1500.     ret
  1501.  
  1502. Bad_Num:
  1503.     mov    dx,offset badnummsg    ;'Illegal number in parameter: '
  1504.     mov    ah,9            ;display msg
  1505.     int    21H
  1506.  
  1507.     mov    si,word ptr argc    ;current argv counter
  1508.     shl    si,1            ;*2 for words
  1509.     mov    si,word ptr argv[si]    ;argv[argc] pointer
  1510.     call    Pr_AsciiZ        ;display the whole bogus argv
  1511.                     ;(It's an AsciiZ string)
  1512.     mov    dx,offset gethelpmsg    ;CR/LF,'Enter FASTBUFF -? for help'
  1513.     jmp    Msg_Term        ;display, die
  1514.  
  1515. GetNum  endp
  1516.  
  1517.  
  1518. ;    AsciiZ string displayer
  1519. ;    Resisting temptation to use BIOS or other undocumented fast char
  1520. ;    displays and sticking with DOS functions .. sigh ..
  1521. ;    Enter with DS:SI -> AsciiZ string
  1522.  
  1523. Pr_AsciiZ    proc    near
  1524.  
  1525.     push    dx            ;be neat
  1526.  
  1527. Pr_Z_Lup:
  1528.     lodsb                ;snarf char
  1529.     or    al,al            ;terminating 0?
  1530.     jz    Pr_Z_X            ;yep, done
  1531.  
  1532.     mov    dl,al            ;char to display
  1533.     mov    ah,2            ;display char
  1534.     int    21H
  1535.     jmp    short Pr_Z_Lup
  1536.  
  1537. Pr_Z_X:
  1538.     pop    dx            ;restore
  1539.     ret
  1540.  
  1541. Pr_AsciiZ    endp
  1542.  
  1543.  
  1544. ;--------------------------------------------------------------------------
  1545. ;Initialization data area
  1546. ;--------------------------------------------------------------------------
  1547.  
  1548. parmtable    db    'BFSDVH?'    ;legal parameter chars
  1549. LPARMTABLE    equ    $-parmtable
  1550.  
  1551.         even
  1552.  
  1553. jumptable    dw    SetBuff,SetFast,SetSlow,SetDelay,SetVid
  1554.         dw    GetHelp,GetHelp
  1555.  
  1556. instalmsg db    'FASTBUFF v2.6TH keyboard enhancer installed.',CR,LF,'$'
  1557. INSTALMSGLEN    equ    $ - instalmsg
  1558.  
  1559.         even
  1560. help    label    byte
  1561.  db '┌──────────────────────────────────────────────────────────────────────────────┐'
  1562.  db '│                               ┌───────────────┐                              │'
  1563.  db '│            David Steiner      │ FASTBUFF v2.6 │    March 1989                │'
  1564.  db '│            [Toad Hall Tweak]  └───────────────┘   August 1989                │'
  1565.  db '│           ╒══════════════════════════════════════════════════════╕           │'
  1566.  db '│           │                 Run-time Control Keys                │           │'
  1567.  db '│           ├──────────────────────────────────────────────────────┤           │'
  1568.  db '│           │   Ctrl + Right Shift : Clear the keyboard buffer     │           │'
  1569.  db '│           │    [5] + Del key     : Turns FASTBUFF off            │           │'
  1570.  db '│           │    [5] + Ins key     : Turns FASTBUFF back on        │           │'
  1571.  db '│           │    [5] + Plus key    : Selects fast repeat rate      │           │'
  1572.  db '│           │    [5] + Minus key   : Selects slow repeat rate      │           │'
  1573.  db '│           │    [5] + Home key    : Toggle screen blanking        │           │'
  1574.  db '│           │    [5] + End key     : Force screen blanking         │           │'
  1575.  db '│  ╒════════╧══════════════════════════════════════════════════════╧════════╕  │'
  1576.  db '│  │                        Command Line Parameters :  Min    Max   Default │  │'
  1577.  db '│  ├────────────────────────────────────────────────────────────────────────┤  │'
  1578.  db '│  │ /Bn : Sets the buffer size to n characters         25    269     100   │  │'
  1579.  db '│  │ /Dn : Set start delay to n timer clicks             1    255       7   │  │'
  1580.  db '│  │ /Vn : Set video blank delay to n minutes (0=OFF)    1     60       3   │  │'
  1581.  db '│  │ /F  : Startup repeat speed = fast                   -      -      ON   │  │'
  1582.  db '│  │ /S  : Startup repeat speed = slow                   -      -     OFF   │  │'
  1583.  db '│  ╘════════════════════════════════════════════════════════════════════════╛  │'
  1584.  db '└──────────────────────────────────────────────────────────────────────────────┘'
  1585.  db '$'
  1586.  
  1587. envmsg    db    'Error: Failed to free environment memory',CR,LF,'$'
  1588.  
  1589. toobigmsg  db    '/B value too large!',CR,LF,'$'
  1590. toosmallmsg db    '/B value too small!',CR,LF,'$'
  1591. badnummsg  db    'Illegal number in parameter: $'
  1592.  
  1593. error    db    'Error: FASTBUFF already installed.'
  1594. gethelpmsg db    CR,LF,'Enter "FASTBUFF -?" for help.',CR,LF,'$'
  1595.  
  1596. ;_Args data area
  1597. ; Pointers to up to MAXPARMS parameter strings are held here.
  1598. ;(All the argv strings are still in the PSP cmdline.)
  1599.     even
  1600.  
  1601. argc    equ    $            ;really just a byte
  1602.                     ;but stuffed as a word
  1603. argv    equ    argc + 2        ;dw MAXPARMS dup (?)
  1604.  
  1605.  
  1606. CSEG    ENDS
  1607.     END    Start
  1608.  
  1609.  
  1610. Old beep code
  1611. ;------ ErrBeep - Keyboard full error beep, from ROM BIOS listing
  1612. ;Called 1 time
  1613. ;    Adding short beep to acknowledge [5] commands.
  1614. ;    Destroys AX,BX,CX
  1615.  
  1616. ShortBeep proc    near
  1617.  
  1618.     mov    ah,30H SHR 1        ;Cycles for 1/32 second tone
  1619.     jmp    short Beep1        ;skip
  1620.  
  1621. ErrBeep:
  1622.     mov    ah,30H            ;Cycles for 1/16 second tone
  1623. Beep1:
  1624.     mov    bx,48H            ;handy constant
  1625.     in    al,61H            ; Get keyboard ctrl information
  1626.     mov    bl,48H            ;handy constant
  1627.     mov    bh,al            ;save kbd ctrl info
  1628.     xor    ch,ch            ;insure counter MSB clear
  1629.  
  1630. BeepCycle:
  1631.     and    al,0FCH            ; Turn off timer gate & spkr data
  1632.     out    61H,al            ; Output to control
  1633.     mov    cl,bl            ;half cycle time for tone
  1634. L1:    loop    L1            ; Speaker off
  1635.     or    al,2            ; Turn on speaker bit
  1636.     out    61H,al            ; Output to control
  1637.     mov    cl,bl            ;set up count
  1638. L2:    loop    L2            ; another half cycle
  1639.     dec    ah            ; Total time count
  1640.     jnz    BeepCycle        ; Do another cycle
  1641.  
  1642.     mov    al,bh            ;recover control
  1643.     out    61H,al            ; Output the control
  1644.  
  1645.     ret
  1646.  
  1647. ShortBeep endp
  1648.