home *** CD-ROM | disk | FTP | other *** search
- ; RemKey 1.00
- ; Assemble with ML.EXE (from MASM 6.0), not MASM.EXE
- .MODEL tiny
-
- ; Some of the logic in this program was lifted from KEY100.ASM by
- ; Andy Gryc and PUSHKEYS.COM by Raan Young and Dave Suvak, all of
- ; HP Corvallis.
- ;
- ; Many thanks to the beta-test team for testing and
- ; suggesting improvements:
- ;
- ; Siroos Afshar
- ; Conrad D. Cox
- ; Ron Crain
- ; James Dean
- ; Stanley Dobrowski
- ; Bruce Holmen
- ; Ed Keefe
- ; Gilles Kohl
- ; David J. Marsh
- ; Thomas Rundel
- ; Mark Scardina
- ; David N. Smith
- ; Jorge M. Trevino
- ; Steve Zweibel
- ;
-
- debug equ 0 ; non-zero enables debug output
-
- ; Leave this off. The send-file code didn't work out well.
- ; About 3 out of 500 characters were dropped.
- fileOpt equ 0
-
- localStack equ 1 ; non-zero enables use of local stack
-
- fixedKeys equ 1
-
- bcdVersion equ 0100h
-
- HotKey equ 7f00h ; Alt 8
-
- ; Timer chip equates
- timer0ModeCmd equ 36h
- timer2ModeCmd equ 0B6h
- timer2LatchCmd equ 80h
- timer2ReadBackStatusCmd equ 0E8h
-
- timerModeReg equ 43h
- timer0CountReg equ 40h
- timer2CountReg equ 42h
-
- timerOutputFlag equ 80h
-
- portB equ 61h
-
- ; bits defined for reading and writing of port B
- timer2gate equ 1
- speaker2gate equ 2
- gate2AndSpeaker2 equ timer2gate or speaker2gate
-
- VHiToneFreq equ 128
- hiToneFreq equ 64
- midToneFreq equ 32
- loToneFreq equ 16
-
- VHiToneDivisor equ (115200 / VHiToneFreq)
- hiToneDivisor equ (115200 / hiToneFreq)
- midToneDivisor equ (115200 / midToneFreq)
- loToneDivisor equ (115200 / loToneFreq)
-
- VHiToneClicks equ VHiToneFreq / 2 ; 1/2 second
- hiToneClicks equ hiToneFreq / 2 ; 1/2 second
- midToneClicks equ midToneFreq / 2 ; 1/2 second
- loToneClicks equ loToneFreq / 2 ; 1/2 second
-
- MenuKeyCode equ 0c800h
-
- ; These keys are sent with a high byte of 0f5h and the int 9 scan code in
- ; the low byte. 80h is added for a released key.
- RShiftScan equ 36h ; int 9 scan code of the right shift key
- LShiftScan equ 2ah ; int 9 scan code of the left shift key
- LCtrlScan equ 1dh ; int 9 scan code of the left Ctrl key
- LAltScan equ 38h ; int 9 scan code of the left Alt key
-
- ; These are handled as special cases and can be given any code but
- ; the above codes or the above plus 80h:
-
- LockCode equ 0f400h ; code sent over serial line when Caps Lock goes on
- UnlockCode equ 0f401h ; code sent over serial line when Caps Lock goes off
-
- CapsScan equ 3ah ; int 9 scan code of the Caps Lock key
-
- baudRate equ 1200
- baudRateDivisor equ (115200 / baudRate)
-
- ; Factor by which we increase the SysTick rate over the
- ; standard 18.2 ticks/sec
- TickFactor equ baudRate/182+1
-
- sioConfig equ 3 ; 8 data, 1 stop, no parity
-
- ; Base I/O port of 4 serial ports
- com1 equ 3f8h
- com2 equ 2f8h
- com3 equ 3e8h
- com4 equ 2e8h
-
- ; Offsets from base of various UART registers
- rx equ 0
- tx equ 0
- int_en equ 1
- int_id equ 2
- lcont equ 3
- mcont equ 4
- lstat equ 5
- mstat equ 6
- dlab_l equ 0
- dlab_h equ 1
-
- pcRecvDataAvailable equ 1
- pcOverrunError equ 2
- pcParityError equ 4
- pcFramingError equ 8
- pcBreakInterrupt equ 10h
- pcXmitBufferEmpty equ 20h
- pcXmitShiftRegEmpty equ 40h
- pcXmitAllEmpty equ (pcXmitBufferEmpty OR pcXmitShiftRegEmpty)
-
- video_int equ 10h ;int for video output calls to bios
- tty_out equ 14 ; put-char function # for video_int
-
- MpxInt equ 2fh ; the multiplex interupt
- RemKeyMpxFn equ 93h ; Multiplex func code used by RemKey
-
- ; The BIOS variables at segment 40h
- biosdata segment at 40h ; rom bios data area
- org 17h
- ShiftState dw ?
- org 1ah
- bufferHead dw ? ; Head of keyboard buffer
- bufferTail dw ? ; Tail of keyboard buffer
-
- org 49h ; start of video data
- crt_mode db ?
- crt_cols dw ?
- crt_len dw ?
- crt_start dw ?
- cursor_posn dw 8 dup(?)
- cursor_mode dw ?
- active_page db ?
- addr_6845 dw ?
- crt_mode_set db ?
- crt_palette db ?
-
- org 6bh ; Phoenix-specific
- LastInterrupt db ? ; bit-map, last interrupt
-
- org 80h
- ; These words contain offsets from an assumed segment of 40h
- bufferStart dw ? ; Start of keyboard buffer
- bufferEnd dw ? ; End+1 of keyboard buffer
-
- org 0a1h
- sleepCountdown dw ? ; a countdown to zero triggers sleep
- sleepTimeout dw ? ; used to reload sleepCountdown
-
- org 0f1h ; 100LX-specific keyboard data
- KbdFlgs db ?
- FnFlags dw ?
- SysFlags2 db ?
- Debounce db ?
- LastIrq2 dw ?
- LastKey db ?
- RptCnt db ?
- MiscFlags db ?
-
- biosdata ends
-
- .CODE
- ORG 100h
- Begin:
- jmp Main
-
- if localStack
- db '<..RemKey 00 ..>'
- db '<..RemKey 10 ..>'
- db '<..RemKey 20 ..>'
- db '<..RemKey 30 ..>'
- db '<..RemKey 40 ..>'
- db '<..RemKey 50 ..>'
- db '<..RemKey 60 ..>'
- db '<..RemKey 70 ..>'
- stack_top:
-
- if debug
- db '<< Stack Top <<<'
- endif
-
- InCheckUart db 0 ; used to detect recursion
-
- ss_save dw ?
- sp_save dw ?
- endif
-
- version dw bcdVersion
-
- EnableDef db 1 ; non-zero to enable send or receive by default
- Receive db 1 ; non-zero for receive mode, zero for send mode
-
- UseEnDef db 1 ; non-zero to copy EnableDef to Enabled
-
- DoConfig db 0 ; non-zero to trigger reconfig write
-
- OldKey label dword ; Int 16h -- keyboard hook
- OldKeyOff dw ?
- OldKeySeg dw ?
-
- OldTick label dword ; Int 8 -- timer hardware tick
- OldTickOff dw ?
- OldTickSeg dw ?
-
- OldMpx label dword ; Int 2f -- multiplex interrupt
- OldMpxOff dw ?
- OldMpxSeg dw ?
-
- Enabled db 0 ; MUST BE 1 to enable send or receive
- SendTSR db 0 ; Sender installs as a TSR
- Is100LX db 0 ; non-zero if running on a 100LX
-
- UartBase dw com1 ; default is com1
-
- TickCount dw TickFactor ; counts real ticks
-
- ; Offset of our service routine for int 16h
- NewKey dw offset NewKeySend ; assume send-mode
-
- ResidentMpxNum db 0c0h ; multiplex number of resident code (01b3)
- OurMpxNum db 0 ; our multiplex number (01b4)
-
- if fileOpt
- SendFileName dw 0 ; offset of path to file name to be sent
- FileNameEnd dw 0 ; saved pointer to end of path
- endif
-
- ; blinking, black on white (inverted)
- ; <<< RemKey Active, Alt-8 to exit >>>
- banner label word
- db ' ', 70h
- db '<', 0f0h
- db '<', 0f0h
- db '<', 0f0h
- db ' ', 0f0h
- db 'R', 0f0h
- db 'e', 0f0h
- db 'm', 0f0h
- db 'k', 0f0h
- db 'e', 0f0h
- db 'y', 0f0h
- db ' ', 0f0h
- db 'A', 0f0h
- db 'c', 0f0h
- db 't', 0f0h
- db 'i', 0f0h
- db 'v', 0f0h
- db 'e', 0f0h
- db ',', 0f0h
- db ' ', 0f0h
- db 'A', 0f0h
- db 'l', 0f0h
- db 't', 0f0h
- db '+', 0f0h
- db '8', 0f0h
- db ' ', 0f0h
- db 't', 0f0h
- db 'o', 0f0h
- db ' ', 0f0h
- db 'e', 0f0h
- db 'x', 0f0h
- db 'i', 0f0h
- db 't', 0f0h
- db ' ', 0f0h
- db '>', 0f0h
- db '>', 0f0h
- db '>', 0f0h
- db ' ', 70h
- bannerLength equ ($-banner)/2 ; length in words
-
- ; If we receive a byte such that:
- ;
- ; LO(pending) XOR ROL(HI(pending)) = RecvdByte XOR 5ah
- ;
- ; then pending holds a valid ASCII/scan-code pair.
- ; In other words the vertical parity of a valid packet
- ; is 5ah
- pending dw 0
- pendingCount db 0
-
- ;=======================================================================
-
- SpeedUp proc near
- assume ds:nothing,ss:nothing,es:nothing
- mov al,timer0ModeCmd ; Prepare to set clock speed
- pushf ; save current interrupt enable state
- cli
- out timerModeReg,al
- mov ax,(65536/TickFactor)
- out timer0CountReg,al
- mov al,ah
- out timer0CountReg,al
- popf ; restore interrupt enable state
- mov TickCount,TickFactor
- ret
- SpeedUp endp
-
- SlowDown proc near
- assume ds:nothing,ss:nothing,es:nothing
- ; restore normal systick rate, div = 65536 (0)
- mov al,timer0ModeCmd ; Prepare to set clock speed
- pushf ; save current interrupt enable state
- cli
- out timerModeReg,al
- mov al,0
- out timer0CountReg,al
- out timer0CountReg,al
- popf ; restore interrupt enable state
- ret
- SlowDown endp
-
- StartTone proc near
- assume ds:nothing,ss:nothing,es:nothing
- push bx
- mov bx,ax ; save divide in bx
-
- pushf ; save current interrupt enable state
- cli ; disable interrupts
-
- mov al,timer2ModeCmd
- out timerModeReg,al
- mov al,bl
- out timer2CountReg,al
- mov al,bh
- out timer2CountReg,al
-
- ; enable speaker
- in al,portB
- or al,gate2AndSpeaker2
- out portB,al
-
- popf ; restore interrupt enable state
- pop bx
- ret
- StartTone endp
-
- EndTone proc near
- assume ds:nothing,ss:nothing,es:nothing
- push ax
-
- pushf ; save current interrupt enable state
- cli ; disable interrupts
-
- ; disable speaker
- in al,portB
- and al, not gate2AndSpeaker2
- out portB,al
-
- popf ; restore interrupt enable state
- pop ax
- ret
- EndTone endp
-
- ; delays for "ax" hi-lo transitions on the speaker
- ToneDelay proc near
- assume ds:nothing,ss:nothing,es:nothing
- push ax
- push bx
- push cx
-
- mov bx,ax ; save count in bx
- ToneLoop:
- ; wait for hi
- sub cx,cx ; reset timeout counter
- HiLoop:
- pushf ; save current interrupt enable state
- cli ; disable interrupts
- mov al,timer2ReadBackStatusCmd
- out timerModeReg,al
- in al,timer2CountReg
- popf ; restore interrupt enable state
- and al,timerOutputFlag
- jnz LoWait
- loop HiLoop
- jmp short @@Exit ; exit early if we timeout
-
- ; wait for lo
- LoWait:
- sub cx,cx ; reset timeout counter
- LoLoop:
- pushf ; save current interrupt enable state
- cli ; disable interrupts
- mov al,timer2ReadBackStatusCmd
- out timerModeReg,al
- in al,timer2CountReg
- popf ; restore interrupt enable state
- and al,timerOutputFlag
- jz DecClicks
- loop LoLoop
- jmp short @@Exit ; exit early if we timeout
-
- DecClicks:
- dec bx ; drop click count
- jnz ToneLoop
- @@Exit:
-
- pop cx
- pop bx
- pop ax
- ret
- ToneDelay endp
-
- ; ax = divisor, bx = duration in clicks
- Tone proc near
- assume ds:nothing,ss:nothing,es:nothing
- call StartTone
- mov ax,bx
- call ToneDelay
- jmp EndTone
- Tone endp
-
- VHiTone proc near
- assume ds:nothing,ss:nothing,es:nothing
- mov ax,VHiToneDivisor
- mov bx,VHiToneClicks
- jmp Tone
- VHiTone endp
-
- HiTone proc near
- assume ds:nothing,ss:nothing,es:nothing
- mov ax,hiToneDivisor
- mov bx,hiToneClicks
- jmp Tone
- HiTone endp
-
- MidTone proc near
- assume ds:nothing,ss:nothing,es:nothing
- mov ax,midToneDivisor
- mov bx,midToneClicks
- jmp Tone
- MidTone endp
-
- LoTone proc near
- assume ds:nothing,ss:nothing,es:nothing
- mov ax,loToneDivisor
- mov bx,loToneClicks
- jmp Tone
- LoTone endp
-
- Tweedle proc near
- assume ds:nothing,ss:nothing,es:nothing
- push ax
- push bx
- call VHiTone
- call HiTone
- call VHiTone
- call HiTone
- pop bx
- pop ax
- ret
- Tweedle endp
-
- Buzz proc near
- assume ds:nothing,ss:nothing,es:nothing
- push ax
- push bx
- call MidTone
- call LoTone
- call MidTone
- call LoTone
- pop bx
- pop ax
- ret
- Buzz endp
-
- if debug
- ; Display the character in al via a BIOS call
- PutChar proc near
- assume ds:nothing,ss:nothing,es:nothing
- push ax
- push bx
- push si
- push di
- push bp
- mov ah,tty_out
- mov bl,0
- int video_int
- pop bp
- pop di
- pop si
- pop bx
- pop ax
- ret
- PutChar endp
-
- ; Display the byte in al in hex via a BIOS call
- PutByte proc near
- assume ds:nothing,ss:nothing,es:nothing
- push ax
- shr al,1
- shr al,1
- shr al,1
- shr al,1
- call put_nybble
- pop ax
- put_nybble:
- push ax
- and al,0fh
- add al,'0'
- cmp al,'9'
- jbe put_digit
- add al,'A'-'0'-10
- put_digit:
- call PutChar
- pop ax
- ret
- PutByte endp
-
- PutWord proc near
- assume ds:nothing,ss:nothing,es:nothing
- xchg ah,al
- call PutByte
- xchg ah,al
- jmp PutByte
- PutWord endp
-
- endif
-
- ; Save int 16h vector in OldKey and set to offset in NewKey.
- HookKey proc near
- assume ds:nothing,ss:nothing,es:nothing
- push ds
- push es
-
- mov ax,3516h ; Get keyboard interrupt
- int 21h
-
- mov OldKeyOff,bx
- mov OldKeySeg,es
-
- mov dx,cs
- mov ds,dx
-
- mov dx,NewKey
- mov ax,2516h
- int 21h
-
- pop es
- pop ds
- ret
- HookKey endp
-
- ; "Press" Fn and stuff scan code in ch
- WithFn proc near
- assume ds:nothing,ss:nothing,es:nothing
- push es
- cmp Is100LX,0
- je @@Exit
- mov ax,seg biosdata ; set es to the BIOS data seg at 40h
- mov es,ax
- assume es:biosdata
- or KbdFlgs,10h ; Set flag to indicate next key is Fn
- or MiscFlags,10h ; Set Keyboard flag for FN active
- and MiscFlags,NOT 20h ; And clear the FN Clear flag
- mov LastKey,79h ; Put the last key pressed to "Fn"
- mov al,ch
- out 60h,al ; stuff the key into the KB i/o port
- int 9 ; simulate a keyboard interrupt
- and MiscFlags,NOT 10h ; Clear Keyboard flag for FN active
- or MiscFlags,20h ; And set the FN Clear flag
- @@Exit:
- pop es
- assume es:nothing
- ret
- WithFn endp
-
- ForceUART proc near
- assume ds:nothing,ss:nothing,es:nothing
-
- cmp Is100LX,0
- je PowerOn ; assume the power is on for non-100LX
-
- pushf ; save interrupt state
- cli ; disable interrupts
-
- in al,22h ; read current index register
- mov ah,al ; and save it in ah
-
- mov al,51h ; select hidden reg 51h
- out 22h,al
- in al,23h ; read hidden reg 51h
- and al,21h ; 20h bit is rs232 pwr, 1 bit is IR on
- cmp al,20h ; we want rs232 on and IR off
- je RestoreIx
- mov ax,4900h ; route serial port to wire
- int 15h
- mov ax,4a01h ; turn serial port on
- int 15h
- RestoreIx:
- mov al,ah ; bring original index back to al
- out 22h,al ; restore original index
- popf ; restore interrupt state
- ; Fall into PowerOn...
-
- PowerOn:
- ; check that UART has not been reconfigured
- mov dx,UartBase ; get base address of UART
- add dx,lcont ; move to the line control register
- in al,dx ; read current line configuration
- cmp al,sioConfig ; does it match ours?
- jne ResetUART ; if not, reset UART
- or al,80h ; raise Divisor Latch Access Bit (DLAB)
- out dx,al
-
- add dx,(dlab_l - lcont) ; move to low byte of rate divisor
- in al,dx ; read it
- cmp al,low baudRateDivisor ; right value?
- jne ResetUart ; if not, reset UART
-
- inc dx ; move to high byte of rate divisor
- in al,dx ; read it
- cmp al,high baudRateDivisor ; right value?
- jne ResetUART ; if not, reset UART
-
- add dx,(lcont - dlab_h) ; move back to line control
- mov al,sioConfig ; drop DLAB and return to our settings
- out dx,al
- jmp short UartOk
-
- ResetUart:
- call InitUart ; force UART to our config
- UartOk:
- ret
- ForceUART endp
-
- ; This table maps a video index (as returned in bh by int 15h, ah=0dfh)
- ; to the next zoom-number (as used in al by int 15h, ah=0d0h). This only
- ; works for text modes which neatly prevents us from trying to zoom a
- ; SysMgr app - they all run in graphics mode 6. A value of zero says
- ; "no change". In terms of the index the three zoom "cycles" are:
- ;
- ; 2 -> 10 -> 14 -> 2 3 -> 11 -> 15 -> 3 7 -> 9 -> 7
- ; 12 -> 14 13 -> 15
- ;
- ; The unsupported 40*25 modes zoom to the 40*16 modes
- ;
- ; The undocumented "Z" option changes this to include the 40*25 modes:
- ;
- ; 2 -> 10 -> 12 -> 14 -> 2 3 -> 11 -> 13 -> 15 -> 3 7 -> 9 -> 7
- ;
-
- NextZoom label byte ; ix mode zoom
- db 0 ; 0 0 * 40*25 B&W CGA Low Res Text
- db 0 ; 1 1 * 40*25 Color CGA Low Res Text
- db 80h ; 2 2 2 80*25 B&W CGA Hi Res Text
- db 81h ; 3 3 3 80*25 Color CGA Hi Res Text
- db 0 ; 4 4 * 320*200 Color CGA Low Res Graphics
- db 0 ; 5 5 * 320*200 B&W CGA Low Res Graphics
- db 0 ; 6 6 * 640*200 Color CGA Hi Res Graphics
- db 21h ; 7 7 7 40*16 B&W MDA Zoom Text
- db 0 ; 8 20h * 240*128 B&W 95LX MDA graphics
- db 7 ; 9 7 21h 80*25 B&W MDA Text
- OptZa db 84h ; 10 2 80h 64*18 B&W CGA Zoom Text
- OptZb db 85h ; 11 3 81h 64*18 Color CGA Zoom Text
- db 84h ; 12 2 82h 40*25 B&W CGA Zoom Text
- db 85h ; 13 3 83h 40*25 Color CGA Zoom Text
- db 2 ; 14 2 84h 40*16 B&W CGA Zoom Text
- db 3 ; 15 3 85h 40*16 Color CGA Zoom Text
-
- ; First check that UART is powered and in the configuration we need.
- ; Then if we are in receive mode check for a received character.
- CheckUart proc near
- assume ds:nothing,ss:nothing,es:nothing
-
- push ax
-
- if localStack
- mov al,1
- xchg InCheckUart,al ; test and set
- or al,al
- jne EarlyExit
-
- mov ss_save,ss ; save caller's ss
- mov sp_save,sp ; and sp
- mov ax,cs ; use local stack
- mov ss,ax
- mov sp,offset stack_top
- endif
-
- push bx
- push cx
- push dx
- push si
- push di
- push bp
- push ds
- push es
-
- mov ax,seg biosdata ; set ds to the BIOS data seg at 40h
- mov ds,ax
- assume ds:biosdata
-
- call ForceUART
-
- cmp Receive,0 ; if we are in send mode don't
- je @@Exit ; check the UART
- mov dx,UartBase ; get base address of UART
- add dx,lstat ; move to the line status register
- in al,dx ; and read it
- if debug
- ; any errors?
- test al,(pcOverrunError OR pcParityError OR pcFramingError)
- jz NoLineError
- push ax
- mov al,"E"
- call PutChar
- pop ax
- push ax
- call PutByte
- mov al," "
- call PutChar
- pop ax
- NoLineError:
- endif
- test al,pcRecvDataAvailable ; received data ready?
- jz @@Exit
- add dx,(rx - lstat) ; move to the receive data register
- in al,dx ; read the sent byte
- if debug
- push ax
- mov al,"R"
- call PutChar
- pop ax
- push ax
- call PutByte
- mov al," "
- call PutChar
- pop ax
- endif
-
- ; reset auto-sleep countdown
- mov cx,sleepTimeout ; reload sleepCountdown
- mov sleepCountdown,cx
-
- mov ah,al ; save new char in ah
- mov cx,pending ; get previously received bytes
- cmp pendingCount,2 ; two valid bytes in pending?
- jb partialPacket
- mov al,ch ; calc ROL(hi) XOR lo XOR new
- rol al,1
- xor al,cl
- xor al,ah
- cmp al,5ah
- je ValidPacket
- partialPacket:
- inc pendingCount ; count the new byte
- mov cl,ch ; push the new byte into pending
- mov ch,ah
- mov pending,cx
- jmp @@Exit ; leave and wait for next byte
-
- ValidPacket:
- mov pendingCount,0 ; mark pending bytes as consumed
- mov pending,0 ; not really needed if the code works
- mov ax,cx ; bring scan-code/ASCII to ax
- cmp ah,0f5h ; special code w/scan-code?
- jne NotShift
- ; if the high byte is 0f5h then the low byte is the int 9 scan code
- DoShift:
- cmp Is100LX,0
- jne DoStuff
- jmp @@Exit ; can't stuff the key I/O on non-HP
-
- DoStuff:
- out 60h,al ; stuff the key into the KB i/o port
- int 9 ; simulate a keyboard interrupt
- jmp @@Exit
-
- NotShift:
- cmp ah,0f4h ; other special codes?
- jne StuffIt
- cmp al,low LockCode ; turn Caps Lock on?
- jne NotLock
- mov cl,40h ; desired shift state w/caps Lock on
- SetLock:
- mov ah,2 ; get shift status
- pushf ; go through old vector
- call [OldKey] ; to prevent recursion
- xor al,cl
- test al,40h
- jz NotUnlock ; Caps already correct
- mov al,LShiftScan ; "Press" the left shift key
- out 60h,al
- int 9
- mov al,CapsScan ; "Press" the Caps key
- out 60h,al
- int 9
- mov al,CapsScan or 80h ; "Release" the Caps key
- out 60h,al
- int 9
- mov al,LShiftScan or 80h ; "Release" the left shift key
- jmp short DoShift
-
- NotLock:
- cmp al,low UnlockCode ; turn Caps Lock off?
- jne NotUnlock ; no known 0f5xx key, ignore it
- sub cl,cl ; desired shift state w/caps Lock off
- jmp SetLock
-
- StuffIt:
- or cl,cl ; ASCII = 0?
- jnz NotFnFx
- cmp cx,0db00h ; Fn F1 ?
- jb NotFnFx
- cmp cx,0e400h ; Fn F10 ?
- ja NotFnFx
- sub ch,0dbh-3bh ; 0dbh..0e4h -> 3bh..44h
- call WithFn ; stuff scan code with Fn "pressed"
- jmp @@Exit
-
- NotFnFx:
- ; The scancode for Alt-downarrow is 0A000, this is the same scancode
- ; as the ON key. If you stuff a 0A000 and you are running on batteries
- ; the 100LX sort-of turns off: the screen goes blank.
- ; Solution: discard 0A000's on the LX
- cmp Is100LX,0
- jz NotOnKey
- cmp cx,0a000h
- je IgnoreKey
- NotOnKey:
- ; The SysMgr applications handle the ZOOM scan code on their own. So
- ; stuffing the scancode works. But zooming in DOS is done below interrupts
- ; 9 and 16. So we have to do it ourselves.
- cmp cx,0d000h ; scancode for ZOOM
- jne NotZoom
- mov ah,0dfh ; Get the video mode/zoom index in bh
- int 10h
- mov bl,bh ; convert bh to a word in bx
- sub bh,bh
- mov al,NextZoom[bx] ; get next zoom number
- or al,al ; non-zoomable?
- jz NotZoom
- mov ah,0d0h ; Text Zoom function
- int 10h
- NotZoom:
-
- ; Very, very odd and very, very frustrating. We would like to stuff our
- ; keys by simply calling the "write key" function. This works fine in all
- ; cases EXCEPT when you run DOS or a DOS app from SysMgr (<&..>D). If you
- ; do then each key is duplicated 50-100% of the time. Directly manipulating
- ; the scan code buffer works in all cases so for now that is what we do.
- if 0
- mov ah,5 ; ch = scan code, cl = ASCII
- int 16h ; add to typeahead buffer
- else
- pushf ; save current interrupt enable state
- cli ; disable interrupts
- mov bx,bufferTail
- mov dx,bx ; advance the ptr before we store
- inc dx ; to check for overflow
- inc dx
- cmp dx,bufferEnd
- jb NoWrap
- mov dx,bufferStart
- NoWrap:
- cmp dx,bufferHead
- je Overflow
- mov [bx],cx ; save scan code
- mov bufferTail,dx ; save new tail ptr
- or [LastInterrupt],2 ; key int was last interrupt
- ; (PUSHKEYS.COM does this)
- Overflow:
- popf ; restore interrupt enable state
- endif
- if debug
- mov al,"W"
- call PutChar
- mov ax,cx
- call PutWord
- mov al," "
- call PutChar
- endif
-
- NotUnlock: ; no known 0f5xx key, ignore it
- IgnoreKey:
-
- @@Exit:
- pop es
- pop ds
- pop bp
- pop di
- pop si
- pop dx
- pop cx
- pop bx
-
- if localStack
- mov ss,ss_save
- mov sp,sp_save
- mov InCheckUart,0 ; clear recursion flag
- endif
-
- EarlyExit:
- pop ax
-
- ret
- CheckUart endp
-
- ;=======================================================================
-
- NewTick proc far
- assume ds:nothing,ss:nothing,es:nothing
- push ax
- cmp Enabled,0
- jz SlowTick
- call CheckUart ; poll the UART every actual tick
- dec TickCount
- jnz cont6
- mov TickCount,TickFactor
- SlowTick:
- pushf
- call [OldTick]
- jmp short cont7
- cont6:
- mov al,20h ; EOI
- out 20h,al ; Send EOI to 8259 int. controller
- cont7:
- pop ax
- iret
- NewTick endp
-
- NewMpx proc near
- assume ds:nothing,ss:nothing,es:nothing
- cmp ah,OurMpxNum ; our multiplex ID?
- jne UseOldMpx
- or al,al ; the generic ID function code?
- jnz NotID
- dec al ; 0 >> ff
- iret
-
- NotID:
- cmp al,RemKeyMpxFn ; our (only) function code
- jne UseOldMpx
- mov ax,bcdVersion
- mov bx,"Re"
- mov cx,"mK"
- mov dx,"ey"
- push cs ; return segment of resident code in es
- pop es
- iret
-
- UseOldMpx:
- jmp [OldMpx]
-
- NewMpx endp
-
- ;=======================================================================
-
- InitUart proc near
- assume ds:nothing,ss:nothing,es:nothing
-
- mov dx,UartBase ; get base address of UART
- add dx,lcont ; move to line control register
- mov al,80h ; enable DLAB
- out dx,al
-
- add dx,(dlab_l - lcont) ; move to low byte of DLAB
- mov al,low baudRateDivisor
- out dx,al
-
- inc dx ; move to high byte of DLAB
- mov al,high baudRateDivisor
- out dx,al
-
- add dx,(lcont - dlab_h) ; move back to line control register
- mov al,sioConfig ; set our configuration
- out dx,al
-
- add dx,(mcont - lcont) ; move to modem control register
- mov al,3 ; raise dtr, rts
- out dx,al
-
- mov dx,UartBase ; get base address of UART
- in al,dx ; flush the UART
- jmp $+2 ; delay
- in al,dx
-
- ret
- InitUart endp
-
- ; Returns non-zero if swap fails
- BannerSwap proc near
- assume ds:nothing,ss:nothing,es:nothing
- push ax
- push bx
- push cx
- push dx
- push di
- push si
- push ds
- mov ax,seg biosdata ; set ds to the
- mov ds,ax ; BIOS data seg at 40h
- assume ds:biosdata
- mov cx,0b000h ;assume seg. of mono
- mov al,crt_mode
- cmp al,7 ;mono mode ?
- je mode_ok
- and al,0feh ;test for 2 or 3
- cmp al,2 ;(80*25 b&w or color)
- jne @@Exit ;return non-zero for unsupported mode
- mov ch,0b8h ;color seg.
- mode_ok:
- mov ax,crt_cols ;1..80 -> 0..79
- dec si
- mov si,ax ; * 25 (19h) bytes, 12.5 lines
- add ax,ax
- add ax,ax
- add ax,ax
- add si,ax
- add ax,ax
- add si,ax
- add si,crt_start ;start of buffer
- mov ds,cx ;set the seg.
- assume ds:nothing
- mov cx,bannerLength
- sub si,cx ; center banner on line
- and si, not 1 ; force to even address
- lea di,banner
- pushf ; save current interrupt enable state
- cli ; disable interrupts
- BannerLoop:
- mov ax,cs:[di] ;get char/attrib to swap in
- xchg ax,[si]
- mov cs:[di],ax ;save swapped char/attrib
- inc si
- inc si
- inc di
- inc di
- loop BannerLoop
- popf ; restore interrupt enable state
- sub ax,ax ; return zero flag for success
- @@Exit:
- pop ds
- assume ds:nothing
- pop si
- pop di
- pop dx
- pop cx
- pop bx
- pop ax
- ret
- BannerSwap endp
-
- ; Returns with zero flag if hot-key caught
- CheckForHot proc near
- assume ds:nothing,ss:nothing,es:nothing
- cmp ax,HotKey ; hot key?
- jne @@Exit
- xor Enabled,1 ; toggle enable
- jz Disabled
- call SpeedUp
- call Tweedle
- jmp short @@ExitWithZero
-
- Disabled:
- call SlowDown
- call Buzz
- @@ExitWithZero:
- sub ax,ax
- @@Exit:
- ret
- CheckForHot endp
-
- NewKeyRecv proc far
- assume ds:nothing,ss:nothing,es:nothing
- cmp ah,0
- je CheckRead ; 0 - Read Key
- cmp ah,10h
- je CheckRead ; 10 - Extended Read Key
- cmp Is100LX,0 ; for a PC the rest default to CheckBefore
- jz CheckBefore
- cmp ah,13h
- je CheckEvent ; 13 - Event Wait
- cmp ah,14h
- je CheckEvent ; 14 - Event Wait with Timeout
- ; Otherwise for these and any unknown functions use CheckBefore:
- ; 1 - Check Key
- ; 2 - Get Shift Status
- ; 3 - Set Repeat Rate
- ; 5 - Stuff Key
- ; 11 - Extended Check Key
- ; 12 - Extended Shift Status
- CheckBefore:
- push ax ; save function code
- ; Peek at the next key. Use the old vector to prevent recursion.
- mov ah,11h
- ; Simulate an int through the old vector:
- pushf
- call [OldKey]
- jz NotHot
- call CheckForHot
- jnz NotHot
- mov ah,10h ; eat the hot-key
- pushf
- call [OldKey]
- NotHot:
- pop ax ; recover original function code
- jmp [OldKey]
-
- CheckRead:
- push ax ; save function code
- ; Simulate an int through the old vector:
- pushf
- call [OldKey] ; do read operation
- call CheckForHot
- jnz DidNotReadHot
- pop ax ; recover saved function code
- jmp CheckRead ; read another key
-
- DidNotReadHot:
- add sp,2 ; discard saved function code
- ret 2 ; discard flags pushed by original int 16
-
- CheckEvent:
- ; Simulate an int through the old vector:
- pushf
- call [OldKey] ; do event-wait operation
- pushf ; save event flags
- push ax ; save key or shift flags
- jz NotHotEvent ; if zero no key so no hot key
- call CheckForHot
- NotHotEvent:
- pop ax ; recover key or shift flags
- popf ; recover event flags
- ret 2 ; discard flags pushed by original int 16
-
-
- NewKeyRecv endp
-
- ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
- RecvEnd label byte ; End of receiver TSR, all above is resident code
-
- ; We need to send two bytes (ASCII, then scan code) in a form that can
- ; be validated. To do this we send three bytes: low, high and low XOR
- ; ROL(high) XOR 5a. The receiver collects bytes and knows that a valid
- ; word has been received when 1st XOR ROL(2nd) XOR = 5ah. This scheme
- ; is not perfect because the right pair of mis-sent words could look
- ; like a single valid packet. But in general it should tend to
- ; synchronize.
-
- SendWord proc near
- assume ds:nothing,ss:nothing,es:nothing
- push ax
- push cx
-
- mov cx,ax ; save word to send in cx
- mov al,cl ; send the low byte
- call SendByte
- mov al,ch ; send the high byte
- call SendByte
- ; send low XOR rol(high) XOR 5a as the end of a valid packet
- mov al,ch
- rol al,1
- xor al,cl
- xor al,5ah
- call SendByte
-
- pop cx
- pop ax
- ret
- SendWord endp
-
- ; Send the byte in al out the serial port
- SendByte proc near
- assume ds:nothing,ss:nothing,es:nothing
-
- if debug
- push ax
- mov al,"S"
- call PutChar
- pop ax
- push ax
- call PutByte
- mov al," "
- call PutChar
- pop ax
- endif
-
- push dx
- push ax
- mov dx,UartBase ; get base address of UART
- add dx,lstat ; move to line status register
- UartWait:
- in al,dx
- test al,20h ; is the transmit buffer empty?
- je UartWait
- pop ax
- add dx,(tx - lstat) ; move to the transmit buffer register
- out dx,al
- pop dx
- ret
- SendByte endp
-
- NewKeySend proc far
- assume ds:nothing,ss:nothing,es:nothing
-
- push ax
- push bx
- push cx
- push dx
- push es
-
- ; Peek at the next key. Use the old vector to prevent recursion.
- mov ah,11h
- pushf
- call [OldKey]
- jz @@Exit
- cmp ax,HotKey ; hot key?
- jne @@Exit
- mov ah,10h ; eat the hot-key
- pushf
- call [OldKey]
- call BannerSwap ; put up "RemKey Active" message
- jz BannerUp
- call Tweedle ; give audible signal if banner fails
- call SendKeys
- call Buzz ; give audible signal on exit
- jmp short @@Exit
-
- BannerUp:
- call SendKeys
- call BannerSwap ; restore screen
- @@Exit:
- pop es
- pop dx
- pop cx
- pop bx
- pop ax
- jmp [OldKey]
- NewKeySend endp
-
- ; Special PC scan codes and what they map to on the 100LX
- ScanMap label word
- ; PC 100LX
- dw 03300h, 0d100h ; Alt "," to DATE
- dw 03400h, 0d200h ; Alt "." to TIME
- dw 0a300h, 0d400h ; Alt Del to CUT
- dw 00e00h, 0d500h ; Alt Bsp to COPY
- dw 0a200h, 0d600h ; Alt Ins to PASTE
- dw 7800h, 0a800h ; Alt ! to Filer
- dw 7900h, 0ac00h ; Alt @ to cc:Mail
- dw 7a00h, 0b000h ; Alt # to Appt
- dw 7b00h, 0b400h ; Alt $ to Phone
- dw 7d00h, 0b800h ; Alt ^ to Memo
- dw 7e00h, 0bc00h ; Alt & to Lotus
- dw 8000h, 0c000h ; Alt ( to HP Calc
- dw 8100h, 0a400h ; Alt ) to More
-
- ; The Ctrl-Blue keys:
- ;
- ; The 0f5h in the lower byte of these PC scan codes encodes the
- ; fact that these pairs are used when Ctrl and Alt are pushed.
-
- dw 78f5h, 0ae00h ; Ctrl Alt ! to Setup
- dw 79f5h, 0b200h ; Ctrl Alt @ to Data Comm
- dw 7af5h, 0b600h ; Ctrl Alt # to Stopwatch
- dw 7bf5h, 0ba00h ; Ctrl Alt $ to Database
- dw 7df5h, 0be00h ; Ctrl Alt ^ to Note Taker
- dw 7ef5h, 0c200h ; Ctrl Alt & to DOS
- dw 80f5h, 0c600h ; Ctrl Alt ( to World Time
- dw 81f5h, 0aa00h ; Ctrl Alt ) to System Macros
-
- dw 68f5h, 0db00h ; Ctrl Alt F1 to Fn F1, macro 1
- dw 69f5h, 0dc00h ; Ctrl Alt F2 to Fn F2, macro 2
- dw 6af5h, 0dd00h ; Ctrl Alt F3 to Fn F3, macro 3
- dw 6bf5h, 0de00h ; Ctrl Alt F4 to Fn F4, macro 4
- dw 6cf5h, 0df00h ; Ctrl Alt F5 to Fn F5, macro 5
- dw 6df5h, 0e000h ; Ctrl Alt F6 to Fn F6, macro 6
- dw 6ef5h, 0e100h ; Ctrl Alt F7 to Fn F7, macro 7
- dw 6ff5h, 0e200h ; Ctrl Alt F8 to Fn F8, macro 8
- dw 70f5h, 0e300h ; Ctrl Alt F9 to Fn F9, macro 9
- dw 71f5h, 0e400h ; Ctrl Alt F10 to Fn F10, macro 10
-
- ; The Alt-Blue keys:
- ;
- ; The 0f6h in the lower byte of these PC scan codes encodes the
- ; fact that these pairs are used when Shift and Alt are pushed.
-
- dw 78f6h, 0ab00h ; Shift Alt ! to Alt Filer
- dw 79f6h, 0af00h ; Shift Alt @ to Alt cc:Mail
- dw 7af6h, 0b300h ; Shift Alt # to Alt Appt
- dw 7bf6h, 0b700h ; Shift Alt $ to Alt Phone
- dw 7df6h, 0bb00h ; Shift Alt ^ to Alt Memo
- dw 7ef6h, 0bf00h ; Shift Alt & to Alt Lotus
- dw 80f6h, 0c300h ; Shift Alt ( to Alt HP Calc
- dw 81f6h, 0a700h ; Shift Alt ) to Alt More
-
-
- ; Shifted cursor keys:
- ;
- ; In a number of places in the 100LX apps a cursor key combined with
- ; shift is used. Most commonly this is used in a multi-line text field
- ; to select or highlight a portion of the text. Memo, note fields and
- ; the system macro edit screen are all examples of this. Also in Appt
- ; shift up-cursor and shift down-cursor can move to the previous or
- ; next week.
- ;
- ; The scan codes that these apps are checking for appear to be the scan
- ; codes of the digits on a normal PCs numeric pad. This makes sense as
- ; that is what this pad will produce when NumLock is off, shift is held
- ; and a digit is pressed. But what about the dedicated cursor keys in
- ; the inverted "T" on an extended keyboard? These produce the scancode
- ; of a cursor key in the high byte and 0e0h in the low byte. RemKey
- ; just replaces the 0e0h with 0 which produces the scancodes of the
- ; numeric pad cursor keys. Most apps in the 100LX will check if the
- ; shift key is down and treat such an event as a "shift selection".
- ; Memo and note fields behave as expected.
- ;
- ; But the system macro editor and the caledar in Appt appear to only
- ; check for the shift bit and the numeric pad scancodes. So the
- ; following entries map the dedicated up, down, left, right, home, end,
- ; Page Up and Page Down keys to the numeric pad scan codes when the
- ; shift key is down. The 0f7h in the low byte of the first
- ; scancode/ASCII pair artificially endcodes that only the shift key was
- ; pressed.
-
- dw 4ff7h, 4f31h ; Shift end (pad 1)
- dw 50f7h, 5032h ; Shift down (pad 2)
- dw 51f7h, 5133h ; Shift pg dn (pad 3)
- dw 4bf7h, 4b34h ; Shift left (pad 4)
-
- dw 4df7h, 4d36h ; Shift right (pad 6)
- dw 47f7h, 4737h ; Shift home (pad 7)
- dw 48f7h, 4838h ; Shift up (pad 8)
- dw 49f7h, 4939h ; Shift pg up (pad 9)
-
- ScanEntries equ ($-ScanMap)/4 ; 4 bytes, 2 word per entry
-
- ; These are stuffed via int 9 when the corresponding code is received.
- ;
- ; 40:17 byte Keyboard flag byte 0
- ;
- ; │7│6│5│4│3│2│1│0│ keyboard flag byte 0
- ; │ │ │ │ │ │ │ └─── right shift key depressed
- ; │ │ │ │ │ │ └──── left shift key depressed
- ; │ │ │ │ │ └───── CTRL key depressed
- ; │ │ │ │ └────── ALT key depressed
- ; │ │ │ └─────── scroll-lock is active
- ; │ │ └──────── num-lock is active
- ; │ └───────── caps-lock is active
- ; └────────── insert is active
- ;
- ShiftMap label byte
-
- ; codes for released keys must come first
- db RShiftScan+80h ; stuffed via int 9 when UnRShiftCode received
- db LShiftScan+80h ; " " " " " UnLShiftCode "
-
- ; followed by codes for pressed keys
- db RShiftScan ; stuffed via int 9 when RShiftCode received
- db LShiftScan ; " " " " " LShiftCode "
-
- ShiftEntries equ ($-ShiftMap)
-
- ; Send keys pressed on the local keyboard out the serial port until the
- ; hot key is pressed.
- ;
- ; The dl reg holds the current shift state, dh holds the previous.
- ; bh holds bits which have changed from 0 to 1, bl from 1 to 0
- ;
- ; The si register is used to detect a press and release of either Alt-key:
- ; bit 0 - either Alt-key was pressed
-
- SendKeys proc near
- assume ds:nothing,ss:nothing,es:nothing
- push ax
- push bx
- push cx
- push dx
- push di
- push si
- push ds
- push es
-
- call ForceUART
-
- mov ah,2 ; get shift status
- pushf ; go through old vector to prevent recursion
- call [OldKey]
- mov dl,al ; put current shift state in dl
-
- KeyLoop:
- mov dh,dl ; save previous shift state in dh
- mov ah,2 ; get shift status
- pushf ; go through old vector to prevent recursion
- call [OldKey]
- mov dl,al ; save new shift state in dl
-
- ; Calculate which bits have changed from 0 to 1 in bh and from 1 to 0 in bl
- mov bl,dh ; get last shift state
- xor bl,dl ; calculate which bits changed either way
- mov bh,bl ; save in bh
- and bh,dl ; isolate bits that changed from 0 to 1
- and bl,dh ; isolate bits that changed from 1 to 0
-
- ; Although the ASCII and scan codes we send already contains our shift state
- ; we need to explicitly set the shift state on the remote 100LX because
- ; some of the built-in apps directly test the shift state. Examples are
- ; shift-cursor in Memo and Appt. Other DOS programs also directly test the
- ; state of Ctrl and Alt so we send changes on these also.
-
- ; The first half of the loops look for released keys, the second for
- ; pressed keys.
- mov cl,bl ; gets bits that have changed from 1 to 0
- sub di,di ; initial offset into ShiftMap is zero
- ShiftMapLoop:
- cmp di,ShiftEntries/2
- jne NotHalfway
- mov cl,bh ; gets bits that have changed from 0 to 1
- NotHalfway:
- test cl,1 ; did bit change?
- jz NoShiftChg
- mov al,ShiftMap[di]
- mov ah,0f5h
- call SendWord ; send scan code to effect shift change
- NoShiftChg:
- shr cl,1
- inc di
- cmp di,ShiftEntries
- jb ShiftMapLoop
-
- ; has Caps Lock state changed?
- mov ax,LockCode ; assume Caps Lock is on
- test bh,40h ; did Caps Lock bit change to 1?
- jnz SendLock
- mov ax,UnlockCode ; assume Caps Lock is off
- test bl,40h ; did Caps Lock bit change to 0?
- jz NoLockChange
- SendLock:
- call SendWord ; send encoding of Caps (Un)Lock
- NoLockChange:
- ; If either "Alt" is pressed and released then we simulate a press of the
- ; MENU key on the remote 100LX
-
- test bh,8 ; either Alt-key changed to pressed?
- jz CheckAltUp ; jump if no change
- mov si,1 ; remember that Alt-key state changed
- jmp short CheckBIOS
-
- CheckAltUp:
- test bl,8 ; either Alt-key changed to released?
- jz CheckBIOS ; jump if no change
- ; Was Alt just pressed and released with no intervening keystroke?
- or si,si
- mov si,0 ; (reset the flags no matter what)
- jz CheckBIOS
- mov ax,MenuKeyCode ; scan code for menu key
- jmp SendIt
-
- CheckBIOS:
- mov ah,11h ; key waiting ?
- pushf
- call [OldKey]
- jz KeyLoop
- mov ah,10h ; read key
- pushf
- call [OldKey]
- if debug
- push ax
- mov al,"K"
- call PutChar
- pop ax
- push ax
- call PutWord
- mov al," "
- call PutChar
- pop ax
- endif
- sub si,si ; Any key cancels Alt key down-tap state
- test dl,8 ; Alt key down?
- jz NotAltSpace
- cmp ax,3920h ; space bar ?
- jne NotAltSpace
- mov ax,0d000h ; Send Alt-space as ZOOM
- jmp SendIt
-
- NotAltSpace:
- cmp ax,HotKey
- je @@Exit
-
- ; Some funny keys like the "/" and the <enter> on the numeric pad have a
- ; scan code of 0e0h in the high byte with the correct ASCII in the low byte.
- ; But this somehow conflicts with the 100LX's use of scan code 0e0h for
- ; Fn F6 and is not recognized. The hack is to replace the 0e0h scan code
- ; with zero.
- cmp ah,0e0h ; fold extended scan codes into normal ones
- jne NotHiE0
- or al,al ; Let Fn F6 (0e000h) through
- je NotHiE0 ; (this will only happen when 100LX -> 100LX)
- sub ah,ah ; LX apps don't recognize 0E0xx scan codes
- NotHiE0:
-
- ; Encode special keys by searching for them in the "exception" table
-
- ; If a Shift and Alt key is pressed and the low byte is zero then
- ; set the low byte to 0f6h.
- ;
- ; If a Ctrl and Alt key is pressed and the low byte is zero then
- ; set the low byte to 0f5h.
- ;
- ; If a Shift is pressed and the low byte is 0e0h then
- ; set the low byte to 0f7h.
- ;
- ; These artificial encodings allows us to have entries for an
- ; Alt-key, Shift-key and Ctrl-Alt-key in the same table.
-
- mov cx,ax ; save unmodified scan/ASCII pair
-
- test dl,8 ; Alt key pressed?
- jz NotAlt
- or al,al ; low byte of scan/ASCII zero?
- jnz NotAlt
- test dl,4 ; Ctrl key pressed?
- jz NotCtrlAlt
- mov al,0f5h ; Mark key as Ctrl-Alt'ed
- jmp short MatchScancode
-
- NotCtrlAlt:
- test dl,3 ; either shift key pressed?
- jz MatchScancode
- mov al,0f6h ; Mark key as Shift-Alt'ed
- jmp short MatchScancode
-
- NotAlt:
- ; Test for the dedicated cursor keys with shift
-
- ; Some funny keys like the cursor inverted "T" pad contain the expected
- ; scan code in the high byte but have 0e0h instead of zero in the low byte.
- cmp al,0e0h ; fold extended scan codes into normal ones
- jne NotLoE0
- or ah,ah ; let alpha (Alt-224 or 0e0h) through
- je NotLoE0
- sub cl,cl ; LX apps don't recognize xxE0 scan codes
- test dl,3 ; either shift key pressed?
- jz NonMapped ; if not shifted just pass through
- mov al,0f7h ; Mark key as Shift-cursor
- jmp short MatchScancode
-
- NotLoE0:
-
- MatchScancode:
- mov di,(ScanEntries-1)*4 ; offset of last entry
- ScanMapLoop:
- cmp ax,ScanMap[di]
- jne NoMatch
- mov ax,ScanMap[di+2]
- jmp short SendIt
- NoMatch:
- sub di,4 ; move to next pair of words
- cmp di,-4
- jne ScanMapLoop
- NonMapped:
- mov ax,cx ; recover saved unmodified scancode/ASCII
- ; if the scan-code/ASCII pair are not in the exception list and we
- ; fall out of the loop then just send them as is:
-
- SendIt:
- call SendWord
- IgnoreKey:
- jmp KeyLoop
-
- @@Exit:
- ; The only way to exit is with the hot key so...
- mov Enabled,0 ; set enabled false
- pop es
- pop ds
- pop si
- pop di
- pop dx
- pop cx
- pop bx
- pop ax
- ret
- SendKeys endp
-
- ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
- SendEnd label byte ; End of sender TSR, all above is resident code
-
- if fileOpt
- AscToScan label byte
- db 03h ; Control "@"
- db 1eh ; Control "A"
- db 30h ; Control "B"
- db 2eh ; Control "C"
- db 20h ; Control "D"
- db 12h ; Control "E"
- db 21h ; Control "F"
- db 22h ; Control "G"
- db 0eh ; Backspace
- db 0fh ; Tab
- db 24h ; Control "J"
- db 25h ; Control "K"
- db 26h ; Control "L"
- db 1ch ; Enter
- db 31h ; Control "N"
- db 18h ; Control "O"
- db 19h ; Control "P"
- db 10h ; Control "Q"
- db 13h ; Control "R"
- db 1fh ; Control "S"
- db 14h ; Control "T"
- db 16h ; Control "U"
- db 2fh ; Control "V"
- db 11h ; Control "W"
- db 2dh ; Control "X"
- db 15h ; Control "Y"
- db 2ch ; Control "Z"
- db 01h ; Esc
- db 2bh ; Control "\"
- db 1bh ; Control "]"
- db 07h ; Control "^"
- db 0ch ; Control "_"
- db 39h ; SPACE
- db 02h ; "!"
- db 28h ; Double Quote
- db 04h ; "#"
- db 05h ; "$"
- db 06h ; "%"
- db 08h ; "&"
- db 28h ; "'"
- db 0ah ; "("
- db 0bh ; ")"
- db 09h ; "*"
- db 0dh ; "+"
- db 33h ; ","
- db 0ch ; "-"
- db 34h ; "."
- db 35h ; "/"
- db 0bh ; "0"
- db 02h ; "1"
- db 03h ; "2"
- db 04h ; "3"
- db 05h ; "4"
- db 06h ; "5"
- db 07h ; "6"
- db 08h ; "7"
- db 09h ; "8"
- db 0ah ; "9"
- db 27h ; ":"
- db 27h ; ";"
- db 33h ; "<"
- db 0dh ; "="
- db 34h ; ">"
- db 35h ; "?"
- db 03h ; "@"
- db 1eh ; "A"
- db 30h ; "B"
- db 2eh ; "C"
- db 20h ; "D"
- db 12h ; "E"
- db 21h ; "F"
- db 22h ; "G"
- db 23h ; "H"
- db 17h ; "I"
- db 24h ; "J"
- db 25h ; "K"
- db 26h ; "L"
- db 32h ; "M"
- db 31h ; "N"
- db 18h ; "O"
- db 19h ; "P"
- db 10h ; "Q"
- db 13h ; "R"
- db 1fh ; "S"
- db 14h ; "T"
- db 16h ; "U"
- db 2fh ; "V"
- db 11h ; "W"
- db 2dh ; "X"
- db 15h ; "Y"
- db 2ch ; "Z"
- db 1ah ; "["
- db 2bh ; "\"
- db 1bh ; "]"
- db 07h ; "^"
- db 0ch ; "_"
- db 29h ; "`"
- db 1eh ; "a"
- db 30h ; "b"
- db 2eh ; "c"
- db 20h ; "d"
- db 12h ; "e"
- db 21h ; "f"
- db 22h ; "g"
- db 23h ; "h"
- db 17h ; "i"
- db 24h ; "j"
- db 25h ; "k"
- db 26h ; "l"
- db 32h ; "m"
- db 31h ; "n"
- db 18h ; "o"
- db 19h ; "p"
- db 10h ; "q"
- db 13h ; "r"
- db 1fh ; "s"
- db 14h ; "t"
- db 16h ; "u"
- db 2fh ; "v"
- db 11h ; "w"
- db 2dh ; "x"
- db 15h ; "y"
- db 2ch ; "z"
- db 1ah ; "{"
- db 2bh ; "|"
- db 1bh ; "}"
- db 29h ; "~"
- db 0eh ; Delete (Ctrl-Backspace)
- endif
-
- Logon label byte
- db 13,10
- db 'RemKey V1.00 - Remote Keyboard Via Serial Port.'
- db 13,10
- db '$'
-
- UninstMess label byte
- db 'RemKey has been uninstalled.'
- db 13,10
- db '$'
-
- MpxErrMess label byte
- db 'Multiplex error.'
- db 13,10
- db '$'
-
- Not100LXMess label byte
- db 'RemKey only works on a standard PC or the HP 100LX palmtop.'
- db 13,10
- db '$'
-
- NotInstMess label byte
- db 'RemKey is not already installed, it can not be uninstalled.'
- db 13,10
- db '$'
-
- Installed label byte
- db 'RemKey has been installed, press Alt 8 to toggle enable.'
- db 13,10
- db 'Type "REMKEY /U" to uninstall.'
- db 13,10,'$'
-
- SendHelp label byte
- db 13,10
- db 'Ctrl+Alt: Setup Data Stop Data Note DOS World System',13,10
- db '│ Comm watch base Taker Time Macros',13,10
- db '│',13,10
- db '│ Alt: Filer cc: Appt Phone Memo Lotus HP App',13,10
- db '│ │ Mail 123 Calc Mgr',13,10
- db '│ │',13,10
- db '│ │ ! @ # $ ^ & ( )',13,10
- db '└────┴───── 1 2 3 4 6 7 9 0',13,10
- db 13,10
- db 'Press Shift+Alt+[12346790] for Alt+Blue keys.',13,10
- db 13,10
- db ' Zoom Date Time Cut Copy Paste',13,10
- db 'Press Alt+ Space Comma Period Del BSpc Ins',13,10
- db 13,10
- db 'Press Ctrl+Alt+F1..F10 to play back macro, ',13,10
- db ' Shift+Ctrl+Alt+F1..F10 to record.',13,10
- db 13,10
- db 'Tap either Alt key for the Menu key, press Alt+8 to exit.'
- db 13,10,0
-
- HelpMess label byte
- db 13,10
- db 'Usage: RemKey /[1,2,3,4] /[S,R,T] /[E,D] /C /U',13,10
- db ' /1,2,3,4: Comm Port, default is configured as '
- HelpCommDef label byte
- db '1',13,10
- db 13,10
- db ' /S Send keys to remote computer (default on PC).',13,10
- db ' /R Receive keys, install as TSR (default on 100LX).',13,10
- db ' /T TSR sender, the hot-key is Alt+8.',13,10
- db 13,10
- db ' /E Enable this or already installed program (default for receive).',13,10
- db ' /D Disable this or already installed program (default for send).',13,10
- db 13,10
- db ' /C Configure specified serial port as default and exit.',13,10
- db ' /U Unload a previously loaded copy and exit.',13,10
- db 13,10
- db 'Example - RemKey receiving on COM3, start disabled:',13,10
- db ' remkey /r/3/d',13,10
- CrLf label byte
- db 13,10
- db '$'
-
- ComMess label byte
- db 'Using serial port COM'
- ComNum db '1.'
- db 13,10
- db '$'
-
- ResMess label byte
- db 'RemKey is currently installed.'
- db 13,10,'$'
-
- UpdateMess label byte
- db 'The parameters have been updated.'
- db 13,10,'$'
-
- IncompatMess label byte
- db 'Incompatible versions.'
- db 13,10,'$'
-
- NoUninstMess label byte
- db "Can't uninstall RemKey, try exiting AppMgr completely."
- db 13,10,'$'
-
- NoInstMess label byte
- db "Can't install RemKey, try exiting AppMgr completely."
- db 13,10,'$'
-
- ConfigMess label byte
- db 'Configuring '
- ; Nothing between ConfigMess and OurName, please!
- OurName db 128 dup (0)
-
- WrtErrMess label byte
- db 'Error updating file.'
- db 13,10,'$'
-
- if fileOpt
- ReadErrMess label byte
- db 'Error reading file.'
- db 13,10,'$'
-
- SendAbortMess label byte
- db 'File send terminated.'
- db 13,10,'$'
- endif
-
- UartBases dw com1, com2, com3, com4
-
- FindMpxNum proc near
- assume ds:nothing,ss:nothing,es:nothing
-
- ; Save all registers because the multiplex code we probe could change
- ; any register.
-
- push ax
- push bx
- push cx
- push dx
- push si
- push di
- push bp
- push ds
- push es
-
- FindMpxLoop:
- mov ah,ResidentMpxNum
- mov al,0 ; MPX number in use?
- int MpxInt
- cmp al,0
- je FreeMpxNum
- mov ah,ResidentMpxNum
- mov al,RemKeyMpxFn ; in use by RemKey?
- int MpxInt
- cmp bx,"Re"
- jne NextMpxNum
- cmp cx,"mK"
- jne NextMpxNum
- cmp dx,"ey"
- je FoundResident ; exit if RemKey already present
- NextMpxNum:
- inc ResidentMpxNum
- jnz FindMpxLoop ; keep going until ID wraps to zero
- stc
- jmp short ExitFindMpx
-
- FreeMpxNum:
- mov al,ResidentMpxNum
- mov OurMpxNum,al
- FoundResident:
- clc
-
- ExitFindMpx:
- pop es
- pop ds
- pop bp
- pop di
- pop si
- pop dx
- pop cx
- pop bx
- pop ax
-
- ret
-
- FindMpxNum endp
-
- ; Finds the name of the file that this program executed from and copies
- ; it to "OurName".
- GetOurName proc near
- assume ds:nothing,ss:nothing,es:nothing
- push es
- push ax
- push cx
- push di
- push si
- mov ax,cs:[2ch] ; get the segment of our environment
- or ax,ax ; no environment if zero
- jz @@Exit
- mov es,ax
- mov di,0 ; scan env from 0
- mov cx,6000 ; give up after 6000 bytes of env
- SkipEnv:
- cmp word ptr es:[di],0 ; end of env is marked by the null
- ; at the end of the last string
- ; followed by one more null
- je FoundEnd
- inc di
- loop SkipEnv
- jmp short @@Exit ; env too large to be real, give up
-
- FoundEnd:
- add di,2 ; move past final pair of nulls
- cmp word ptr es:[di],10 ; is string count absurd (> 10)?
- ja @@Exit
- add di,2 ; move past string count to first str
- lea si,OurName ; copy string to OurName
- mov cx,128 ; only room for 127 chars plus null
- CopyName:
- mov al,es:[di]
- mov cs:[si],al
- or al,al
- jz @@Exit ; exit if we copied final null
- inc di
- inc si
- loop CopyName
- mov OurName,0 ; if we run out of room then the
- ; name is partial and invalid.
- ; Zap it.
-
- @@Exit:
- pop si
- pop di
- pop cx
- pop ax
- pop es
- ret
- GetOurName endp
-
- ; Returns with zero flag set if this is an HP 100LX.
- ; Sets Is100LX
- Chk100LX proc near
- assume ds:nothing,ss:nothing,es:nothing
- ret
- Chk100LX endp
-
- ; Display a null-terminated string (can contain a "$").
- StrOut proc near
- assume ds:nothing,ss:nothing,es:nothing
- StrLoop:
- mov bx,dx
- cmp byte ptr [bx],0
- je @@Exit
- mov ah,40h ; write file
- mov bx,1 ; StdOut
- mov cx,1
- int 21h
- inc dx
- jmp StrLoop
-
- @@Exit:
- ret
- StrOut endp
-
- ToUpper proc near
- assume ds:nothing,ss:nothing,es:nothing
- cmp al,'a'
- jb NotLowerCase
- cmp al,'z'
- ja NotLowerCase
- sub al,'a'-'A' ; convert to upper case
- NotLowerCase:
- ret
- ToUpper endp
-
- ; Convert '1'..'4' to com1..com4 I/O base
- SetCom proc near
- assume ds:nothing,ss:nothing,es:nothing
- push si
- mov ComNum,al ; Save the ASCII of selected com port
- sub al,'1' ; '1'..'4' -> 0..3
- sub ah,ah ; byte to word
- add ax,ax ; double to index table of words
- mov si,ax ; move to an index register
- mov ax,UartBases[si] ; fetch UART base from table
- mov UartBase,ax
- pop si
- ret
- SetCom endp
-
- if fileOpt
- ScanFileName proc near
- assume ds:nothing,ss:nothing,es:nothing
- mov SendFileName,bx ; save pointer to start of path
- ScanLoop:
- mov al,[bx]
- cmp al,' ' ; space or slash ends name
- je ScanExit
- cmp al,'/'
- je ScanExit
- inc bx
- loop ScanLoop
- ScanExit:
- mov FileNameEnd,bx ; save pointer to end of path
- ret
- ScanFileName endp
- endif
-
- ; Call with es:cx pointing to code previously hooked to interrupt vector,
- ; al equal to interrupt number.
- ;
- ; Returns zero if that code is still hooked, non-zero if not.
- CheckVector proc near
- push bx
- push dx
- push es
- mov dx,es ; save segment of resident code in dx
- mov ah,35h ; read the interrupt vector to es:bx
- int 21h
- mov ax,es
- cmp ax,dx
- jne VectorMismatch ; exit with not-zero
- cmp cx,bx ; set zero or not-zero and exit
- VectorMismatch:
- pop es
- pop dx
- pop bx
- ret
- CheckVector endp
-
- ;=======================================================================
- Main proc near
- assume ds:_TEXT,ss:_TEXT,es:_TEXT
- call GetOurName
- mov ah,9
- lea dx,Logon
- int 21h
-
- ; Test if we are already installed or choose a multiplex ID if we are not.
- call FindMpxNum
- jnc FoundID
- lea dx,MpxErrMess
- jmp ExitWithMess
-
- FoundID:
- cmp OurMpxNum,0
- jne NotInstalled
-
- lea dx,ResMess
- mov ah,9
- int 21h
-
- mov ah,ResidentMpxNum
- mov al,RemKeyMpxFn
- int MpxInt ; ES gets segment of resident code
- ; AX gets version of resident code
- cmp ax,bcdVersion
- je AlreadyInstalled
- IncompatExit:
- lea dx,IncompatMess
- jmp ExitWithMess
-
- NotInstalled:
- mov ax,cs ; make sure ES still points to our segment
- mov es,ax
- AlreadyInstalled:
- mov ax,4dd4h ; check machine type
- int 15h
- cmp bx,"HP" ; should return "H" in bh, "P" in bl
- jnz Not100LX
- cmp ch,1 ; ch=1 is palmtop family
- jnz Not100LX
- cmp cl,2 ; cl=1 is 95LX, 2 is 100LX
- je On100LX
- lea dx,Not100LXMess
- jmp ExitWithMess
-
- Not100LX:
- mov Receive,0 ; non-100LX defaults to sending
- mov EnableDef,0 ; and not enabled
- jmp short StartParse
-
- On100LX:
- mov Is100LX,1 ; set to true
- StartParse:
- mov dx,100h ; keep 1 (true) in dh, 0 (false) in dl
- mov bx,80h ; point bx at start of string
- mov cl,[bx] ; get param string length
- inc bx ; move past length byte
- sub ch,ch ; convert to word
- jcxz SetConfigX
- ParseLoop:
- mov al,[bx] ; get a char
- cmp al,' ' ; ignore blanks
- je NextChar
- cmp al,'/' ; start of an option?
- jne Help
- inc bx ; move through string
- loop ParseLetter
- jmp Help ; can't close with a slash
-
- ParseLetter:
- mov al,[bx] ; get an option letter (we hope)
- call ToUpper
- cmp al,'1' ; comm port number ("1".."4")?
- jb Not1234
- cmp al,'4'
- ja Not1234
- call SetCom
- jmp short NextChar
-
- Not1234:
- if fileOpt
- cmp al,'F' ; send a file?
- jne NotSendFile
- inc bx ; move past option letter "F"
- loop ScanName
- jmp Help ; something must follow "F"
-
- ScanName:
- mov Receive,dl ; /F forces send mode (dl = 0)
- call ScanFileName
- jcxz SetConfigX ; exit parse loop if no more chars
- jmp short NextChar
-
- NotSendFile:
- endif
- cmp al,'S' ; act as sender?
- jne NotSender
- mov Receive,dl ; dl = 0
- jmp short NextChar
-
- NotSender:
- cmp al,'R' ; act as receiver?
- jne NotReceiver
- mov Receive,dh ; dh = 1
- mov EnableDef,dh ; receiver default is enabled (dh = 1)
- jmp short NextChar
-
- NotReceiver:
- cmp al,'E' ; enable?
- jne NotEnable
- mov Enabled,dh ; dh = 1
- mov UseEnDef,dl ; do not default (dl = 0)
- jmp short NextChar
-
- SetConfigX:
- jmp short SetConfig
-
- ParseLoopX:
- jmp ParseLoop
-
- NotEnable:
- cmp al,'D' ; disable?
- jne NotDisable
- mov Enabled,dl ; dl = 0)
- mov UseEnDef,dl ; do not default (dl = 0)
- jmp short NextChar
-
- NotDisable:
- cmp al,'T' ; Sender installs as a TSR ?
- jne NotSendTSR
- mov SendTSR,dh ; dh = 1
- mov Receive,dl ; TSR implies Sender (dl = 0)
- mov EnableDef,dl ; Send TSR default is disabled (dl = 0)
- jmp short NextChar
-
- NotSendTSR:
- cmp al,'Z' ; enable 40*25 zoom?
- jne NotZoomOpt
- mov OptZa,82h ; modify linked-lists to include
- mov OptZb,83h ; 40*25 zoom state
- jmp short NextChar
-
- NotZoomOpt:
- cmp al,'U' ; uninstall?
- je Uninstall
- cmp al,'C' ; Configure new defaults?
- jne NotConfig
- mov DoConfig,dh ; dh = 1
- jmp short NextChar
-
- NotConfig:
- jmp Help ; unrecognized chars trigger help
-
- NextChar:
- inc bx ; move through string
- loop ParseLoopX
- SetConfig:
- cmp DoConfig,0
- jnz ConfigDefs
- cmp UseEnDef,0 ; use default?
- jz NoDefault
- mov al,EnableDef
- mov Enabled,al
- NoDefault:
- cmp Enabled,0 ; enable now?
- je NotEnabled
- if 1
- call ForceUART ; force UART to our config
- else
- cmp Is100LX,0
- jz NoInitialPower
- mov ax,4900h ; route serial port to wire
- int 15h
- mov ax,4a01h ; turn serial port on
- int 15h
- NoInitialPower:
- call InitUart ; force UART to our config
- endif
- NotEnabled:
- mov ah,9 ; display com port
- lea dx,ComMess
- int 21h
-
- mov ax,es ; is another copy already loaded?
- mov bx,cs
- cmp ax,bx
- je JustUs
- cmp es:version,bcdVersion
- jne IncompatExit
- mov ax,UartBase ; copy parameters
- mov es:UartBase,ax
- mov al,Enabled
- cmp al,es:Enabled
- je DoneEnChg ; nothing to do if they are the same
- mov es:Enabled,al ; update resident enable flag
- or al,al ; change to enabled?
- jz ChgToDisabled
- call SpeedUp
- jmp short DoneEnChg
-
- ChgToDisabled:
- call SlowDown
- DoneEnChg:
- lea dx,UpdateMess
- jmp ExitWithMess
-
- JustUs:
- mov ax,3516h ; Get keyboard interrupt vector
- int 21h
- assume es:nothing
-
- mov OldKeyOff,bx
- mov OldKeySeg,es
-
- cmp Receive,0 ; send or receive mode?
- jz Sender
-
- Receiver:
- mov NewKey,offset NewKeyRecv
- lea dx,RecvEnd+15 ; +15 to round to start of next segment
- TsrExit:
- cmp Is100LX,0
- jz NoSysMgr
- mov ax,5101h ; read mailbox word one
- int 15h
- jc NoSysMgr ; if carry no SysMgr
- cmp ax,7072h ; mailbox signature of SysMgr
- jne NoSysMgr
- lea dx,NoInstMess
- jmp ExitWithMess
-
- NoSysMgr:
- push dx ; save end of resident code
- mov es,cs:[2Ch] ; Grab our environment segment
- ; from the PSP
- mov ah,49h
- int 21h ; Free that darn environment
-
- lea dx,Installed ; Print installed message
- mov ah,9
- int 21h
-
- cmp SendTSR,0
- jne NoHookTick
- mov ax,3508h ; Get Tick -- we hook this to poll UART
- int 21h
-
- mov OldTickOff,bx
- mov OldTickSeg,es
-
- mov ax,cs
- mov ds,ax
-
- lea dx,NewTick
- mov ax,2508h
- int 21h
- cmp Enabled,0 ; enabled?
- je NoSpeedUp
- call SpeedUp ; reprogram systick timer for new rate
- NoSpeedUp:
- NoHookTick:
-
- call HookKey ; hook into the keyboard BIOS int
-
- mov ax,352fh ; link into the multiplex int chain
- int 21h
-
- mov OldMpxOff,bx
- mov OldMpxSeg,es
-
- mov ax,cs
- mov ds,ax
-
- lea dx,NewMpx
- mov ax,252fh
- int 21h
-
-
- ; Calculate ending segment of TSR
- pop dx ; recover end of resident code
- shr dx,1 ; convert offset to segment,
- shr dx,1 ; (divide by 16)
- shr dx,1
- shr dx,1
- mov ah,31h ; Terminate and stay resident
- int 21h
-
- Help:
- lea dx,HelpMess
- ExitWithMess:
- mov ah,9
- int 21h
- jmp Exit
-
- Sender:
- if fileOpt
- mov dx,SendFileName ; anything to send?
- or dx,dx
- jnz SendFile
- endif
- lea dx,SendHelp
- call StrOut
- cmp SendTSR,0
- je SendAsProg
- lea dx,SendEnd+15 ; +15 to round to start of next segment
- jmp TsrExit
-
- SendAsProg:
- call SendKeys
- Exit:
- mov ax,4c00h
- int 21h
-
- if fileOpt
- SendFile:
- mov bx,FileNameEnd ; get pointer to end of path
- mov byte ptr [bx],0 ; terminate path with a null
- mov ax,3d00h ; open code file for read
- int 21h
- jc ReadError
- mov bx,ax ; save handle in bx
- SendFileLoop:
- mov ah,3fh ; read the file in
- lea dx,FileBuf
- mov cx,1 ; ask for more one byte
- int 21h
- jc ReadError
- cmp ax,1 ; did we get our one byte?
- jne ReadDone ; jump if EOF
- mov al,FileBuf ; get the char
- cmp al,0ah ; linefeed?
- je SendFileLoop
- cmp al,1ah ; EOF?
- je ReadDone
- mov ah,al ; save ASCII portion in ah
- push bx ; save handle
- lea bx,AscToScan ; recreate scan code for ASCII value
- xlat AscToScan
- pop bx
- xchg al,ah ; scancode in ah, ASCII in al
- call SendWord
- mov ah,0bh ; check for key press
- int 21h
- cmp al,0ffh
- je AbortSend
- ; Just a kludge for our test, this produced about 11 cps on a 50MHz 486DX
- mov cx,0
- mov ax,4
- SendDelay:
- jmp $+2
- jmp $+2
- loop SendDelay
- dec ax
- jnz SendDelay
- jmp SendFileLoop
-
- AbortSend:
- mov ah,8 ; eat the abort key
- int 21h
- or al,al ; extended char
- jnz NotExtended
- mov ah,8 ; grab the second byte
- int 21h
- NotExtended:
- lea dx,SendAbortMess
- jmp short ReadMess
-
- ReadError:
- lea dx,ReadErrMess
- ReadMess:
- mov ah,9
- int 21h
- ReadDone:
- mov ax,3e00h ; close the file
- int 21h
- jmp short Exit
- endif
-
- Uninstall:
- ; Remember: ES is pointing to our old code seg
- mov ax,cs
- mov dx,es
- cmp ax,dx
- jne Uninst
- lea dx,NotInstMess
- mov ah,9
- int 21h
- if fileOpt
- jmp Exit
- else
- jmp short Exit
- endif
-
- Uninst:
- ; Do all the redirected interrupt vectors still point to our code?
-
- mov al,16h
- mov cx,es:NewKey ; fetch which NewKeyXXX
- ; the resident code is using
- call CheckVector
- jnz CanNotUninst
-
- mov al,2fh
- lea cx,NewMpx
- call CheckVector
- jnz CanNotUninst
-
- cmp es:SendTSR,0
- jne DoNotCheckTick
-
- mov al,8
- lea cx,NewTick
- call CheckVector
- jnz CanNotUninst
-
- DoNotCheckTick:
-
- push ds ; save our ds
-
- mov dx,es:OldKeyOff ; First restore the old key vector
- mov ds,es:OldKeySeg ; by grabbing it out of resident CS
- mov ax,2516h
- int 21h
-
- mov dx,es:OldMpxOff ; Restore the old multiplex vector
- mov ds,es:OldMpxSeg ; by grabbing it out of resident CS
- mov ax,252fh
- int 21h
-
- pop ds
-
- cmp es:SendTSR,0
- jne NoFreeTick
-
- push ds ; save our ds
-
- mov dx,es:OldTickOff ; restore the old Tick vector
- mov ds,es:OldTickSeg ; by grabbing it out of resident CS
- mov ax,2508h
- int 21h
-
- pop ds
-
- ; restore normal systick rate, div = 65536 (0)
- call SlowDown
-
- NoFreeTick:
- ; es is our old code segment -- that's the segment we free
- mov ah,49h
- int 21h
-
- lea dx,UninstMess
- jmp ExitWithMess
-
- CanNotUninst:
- lea dx,NoUninstMess
- jmp ExitWithMess
-
- ConfigDefs:
- mov ah,9 ; display com port
- lea dx,ComMess
- int 21h
-
- lea dx,ConfigMess
- call StrOut
- lea dx,CrLf
- mov ah,9
- int 21h
-
- mov ax,3d02h ; open code file for R/W
- lea dx,OurName
- int 21h
- jc WriteError
- mov bx,ax ; save handle in bx
- mov ax,3f00h ; read the file in
- lea dx,FileBuf
- mov cx,8000h ; ask for more than there is
- int 21h
- jc WriteError
- cmp ax,CodeLength
- jne WriteError
- mov si,FileBuf-Begin
- cmp version[si],bcdVersion
- jne IncompatExit
- mov al,ComNum ; Save the ASCII of selected com port
- mov ComNum[si],al
- mov HelpCommDef[si],al
- mov ax,UartBase ; Save the actual base address
- mov UartBase[si],ax
- mov ax,4200h ; seek relative to start
- sub cx,cx ; offset is zero
- mov dx,cx
- int 21h
- jc WriteError
- mov ax,4000h ; write the code back
- lea dx,FileBuf
- mov cx,CodeLength
- int 21h
- jc WriteError
- mov ax,3e00h ; close the file
- int 21h
- jmp Exit
-
- WriteError:
- lea dx,WrtErrMess
- jmp ExitWithMess
-
- Main endp
-
- CodeLength equ $-100h
-
- FileBuf label byte
-
- end Begin
-