mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2024-12-28 01:29:20 +00:00
4325cdcc78
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included. The Tools directory, containing mostly junk, is also excluded.
559 lines
19 KiB
Plaintext
559 lines
19 KiB
Plaintext
;_________________________________________________________________________________________
|
|
;
|
|
; File: KbdInstall.a
|
|
;
|
|
; Contains: Code to ADB keyboard driver and code for installing keyboard driver as
|
|
; well as for installing resources KMAP & KCHR.
|
|
; This file is the code that is put in the System file's ADBS
|
|
; resource ID = 2. The driver in this file overrides the driver in the ROM
|
|
; and overrides any patches to the ROM driver. However, this driver
|
|
; depends on the ADBProc in the ROM/Patch for the deallocation of the
|
|
; keyboard data buffer at the beginning of ADBReinit.
|
|
;
|
|
; Written by: Joe Fontana, Ed Tecot and Gary G. Davidian
|
|
;
|
|
; Copyright: © 1986-1992 by Apple Computer, Inc., all rights reserved.
|
|
;
|
|
; Change History (most recent first):
|
|
;
|
|
; <4> 10/22/92 JMF Added changes so that the modifiers of the last KEYBOARD
|
|
; pressed are the modifiers that the Norsi KEYPAD uses,
|
|
; since the KEYPAD has no modifier keys of its own.
|
|
; <3> 10/22/92 JMF Incorporated ROM keyboard Driver into ADBS Resource ID=2.
|
|
; <2> 12/28/89 dba Used MAIN instead of PROC to get dead code stripping.
|
|
; <1.1> 8/28/89 SES Removed references to nFiles.
|
|
; <1.0> 11/16/88 CCH Added to EASE.
|
|
; 3/2/87 EMT Fixed bug introduced above.
|
|
; 2/9/87 EMT Permit KCHR to be overridden Check files of type 'KCAP' for
|
|
; KMAPs Use default KMAP (0) as last resort Flush keyboard on
|
|
; exit. Dispose of myself on exit.
|
|
; 10/14/86 EMT Fix bug related to 6 Oct change above.
|
|
; 10/6/86 EMT Data area can be set up by ROM.
|
|
; 7/15/86 EMT Updated to use KCHR resource.
|
|
; 6/25/86 EMT Created.
|
|
;
|
|
;_________________________________________________________________________________________
|
|
|
|
|
|
LOAD 'StandardEqu.d'
|
|
|
|
|
|
; Keyboard driver data
|
|
KBufCount EQU 2
|
|
KBufLen EQU 10 ; 8 bytes + length + inuse
|
|
|
|
KMAPPtr EQU $00
|
|
KeyBits EQU KMAPPtr+4
|
|
KCHRPtr EQU KeyBits+(128/8)
|
|
DeadKey EQU KCHRPtr+4
|
|
KNoADBOp EQU DeadKey+4
|
|
KNumBufs EQU KNoADBOp+1
|
|
KFirstBuf EQU KNumBufs+1
|
|
KbdDSize EQU KFirstBuf+(KBufCount*KBufLen)
|
|
|
|
str EQU -$100
|
|
iopb EQU str-ioFQElSize
|
|
KISize EQU iopb
|
|
|
|
; KMAP offsets
|
|
KMid EQU $00
|
|
KMtype EQU $01
|
|
KMvers EQU KMid+2
|
|
KMstart EQU KMvers+2
|
|
KMnumEx EQU KMstart+128
|
|
KMstEx EQU KMnumEx+2
|
|
|
|
talkCmd EQU $0C ; Command for Talk R0
|
|
|
|
keypadNorsi EQU $0E ; Handler ID for Norsi ergonomic keypad
|
|
|
|
|
|
|
|
;_________________________________________________________________________________________
|
|
;
|
|
; Routine: KbdInst
|
|
; Arguments: D0.B ADB Address
|
|
; D1.B Device Type
|
|
; Output: None
|
|
; Function: Loads and locks the KMAP and KCHR resources used by the keyboard driver,
|
|
; updates the ADB table and installs a new keyboard driver
|
|
;
|
|
; Side Effects: Trashes A0, A1, D0, D2
|
|
;_________________________________________________________________________________________
|
|
|
|
KbdInst MAIN EXPORT
|
|
|
|
BRA.S @Start ; Branch around version number
|
|
|
|
DC.W $0001 ; Version number
|
|
|
|
@Start MOVEM.L D3-D7/A2-A4, -(SP) ; Save the registers
|
|
LINK A6, #KISize ; Save space on stack
|
|
|
|
MOVE.W D0, D2 ; Save the ADB Address
|
|
SUB.L #10, SP ; Allocate space on stack
|
|
MOVE.L SP, A0 ; Pointer to data area
|
|
_GetADBInfo
|
|
|
|
ADDQ.L #2, SP ; Discard OrigAddr and DeviceType
|
|
MOVE.L 4(SP), A0 ; Put the data address in A0
|
|
MOVE.L A0, D0 ; See if it is a real address
|
|
BEQ.S @AllocBuf ; Skip DisposPtr, if no buffer allocated yet
|
|
_DisposPtr ; Dispose of data allocated by the ROM
|
|
|
|
@AllocBuf MOVE.L #KbdDSize, D0 ; Amount of space needed for new keyboard drvr data
|
|
_NewPtr ,SYS,CLEAR ; Get a pointer
|
|
MOVE.L A0, A1 ; Save it in A1
|
|
|
|
MOVE.B #KBufCount, KNumBufs(A1)
|
|
|
|
KCHRLoad SUBQ.L #4, SP ; Make room for result
|
|
MOVE.L #'KCHR', -(SP) ; ResType = KCHR
|
|
CLR.W -(SP) ; theID = 0 (for now)
|
|
MOVE.W #MapTrue, ROMMapInsert ; Use ROM resource if available
|
|
_GetResource
|
|
MOVE.L (SP), -(SP) ; Save the handle
|
|
BEQ NoKCHR ; Skip if NIL
|
|
_DetachResource ; Detach it
|
|
MOVE.L (SP)+, A0
|
|
_HLock ; Lock it down
|
|
MOVE.L (A0), KCHRPtr(A1) ; Dereference and put away
|
|
|
|
; We didn't find the KMAP in the system file or ROM, try the blessed folder
|
|
MOVE.L #'KCAP', D3 ; File type
|
|
CLR.W iopb+ioVRefNum(A6) ; The blessed folder
|
|
CLR.W iopb+ioFDirIndex(A6) ; Initialize the index
|
|
LEA str(A6), A0 ; Get the address of local string
|
|
MOVE.L A0, iopb+ioFileName(A6) ; Put in iopb
|
|
MOVEQ #0, D4 ; No resource file on first pass
|
|
|
|
MOVE.W #MapTrue, ROMMapInsert ; Use ROM resource first time
|
|
FindKMAP ;
|
|
SUBQ.L #4, SP ; Make room for result
|
|
MOVE.L #'KMAP', -(SP) ; ResType = KMAP
|
|
CLR.W -(SP) ; Clear it out since Device Type is byte
|
|
MOVE.B D1, 1(SP) ; theID = DeviceType
|
|
_GetResource
|
|
MOVE.L (SP), -(SP) ; Save the handle
|
|
BNE.S GotKMAP ; Skip if not NIL
|
|
|
|
ADDQ.L #8, SP ; Clean off the stack
|
|
|
|
TST.W D4 ; File open?
|
|
BEQ.S NextFile ; Nope, go on
|
|
MOVE.W D4, -(SP) ; refNum
|
|
_CloseResFile ;
|
|
|
|
NextFile
|
|
LEA iopb(A6), A0 ; Point to the block
|
|
ADD.W #1, ioFDirIndex(A0) ; Increment the file index
|
|
_GetFileInfo ;
|
|
BMI.S NoMoreFiles ; That's all of them
|
|
CMP.L ioFlUsrWds+fdType(A0), D3 ; Correct type?
|
|
BNE.S NextFile ; Nope, try again
|
|
|
|
SUBQ.L #2, SP ; Make room for result
|
|
PEA str(A6) ; fileName
|
|
_OpenResFile ;
|
|
MOVE.W (SP)+, D4 ; Store the refNum
|
|
BRA.S FindKMAP ;
|
|
|
|
NoMoreFiles
|
|
; All is not lost. We can try to find the default KMAP (0)
|
|
SUBQ.L #4, SP ; Make room for result
|
|
MOVE.L #'KMAP', -(SP) ; ResType = KMAP
|
|
CLR.W -(SP) ; theID = 0
|
|
MOVE.W #MapTrue, ROMMapInsert ; Use ROM resource if available
|
|
_GetResource ;
|
|
MOVE.L (SP), -(SP) ; Save the handle
|
|
BEQ.S NoKMAP ; Skip if NIL
|
|
|
|
GotKMAP
|
|
; Assumes two copies of the resource handle are on the stack.
|
|
_DetachResource ; Detach it
|
|
MOVE.L (SP)+, A0
|
|
_HLock ; Lock it down
|
|
MOVE.L (A0), A0 ; Dereference it
|
|
MOVE.L A0, KMAPPtr(A1) ; Put it away
|
|
MOVE.B D1, KbdType ; Update KbdType to show this keyboard
|
|
MOVE.B D2, KbdLast ; Same with KbdLast
|
|
|
|
MOVE.W D2, D0 ; ADB Address
|
|
MOVE.L A1, 4(SP) ; Replace the data address
|
|
LEA KbdDrvr, A0
|
|
MOVE.L A0, (SP)
|
|
MOVE.L SP, A0 ; Pointer to two addresses
|
|
_SetADBInfo
|
|
|
|
TST.W D4 ; File open?
|
|
BEQ.S Done ; Nope, go on
|
|
MOVE.W D4, -(SP) ; refNum
|
|
_CloseResFile ;
|
|
BRA.S Done ;
|
|
|
|
NoKMAP
|
|
NoKCHR
|
|
ADDQ.L #8, SP ; Discard unused parameters
|
|
Done
|
|
MOVE.W D2, D0 ; ADB Address
|
|
LSL.W #4, D0 ; Put address in high nibble
|
|
ADDQ.W #1, D0 ; Flush command
|
|
CLR.L -(SP) ; No data address
|
|
CLR.L -(SP) ; No completion routine
|
|
CLR.L -(SP) ; No buffer
|
|
MOVE.L SP, A0 ; Point to the block
|
|
_ADBOp ; Flush the keyboard
|
|
LEA 12(SP), SP ; Remove parameters from stack
|
|
|
|
UNLK A6 ;
|
|
MOVEM.L (SP)+, D3-D7/A2-A4 ; Restore the registers
|
|
|
|
RTS ; End KbdInst
|
|
|
|
|
|
|
|
;_________________________________________________________________________________________
|
|
;
|
|
; Routine: KbdDrvr
|
|
; Arguments: D0.B ADB Command
|
|
; A0.L ADB Buffer address
|
|
; A1.L ADB Completion Routine Address (= KbdServ)
|
|
; A2.L Pointer to private data area
|
|
; Output: None
|
|
; Function: Reads buffer and posts keyboard events as appropriate.
|
|
; Side Effects: Trashes A0, A1, D0, D1, D2, D3
|
|
;
|
|
;_________________________________________________________________________________________
|
|
|
|
KbdDrvr MOVE.L A2, D3 ; See if A2 actually contains a pointer
|
|
BEQ KbdDone ; If not, can't go on.
|
|
|
|
MOVE.L A0, A1 ; Save A0 in A1
|
|
LSR.W #4, D0 ; Shift ADB Address down to low nibble
|
|
MOVEQ #$F, D1 ; Mask for ADB Address
|
|
AND.L D1, D0 ; D0 now contains ADB Address
|
|
MOVE.L D0, D3 ; Save it in D3
|
|
LEA -10(SP), SP ; Build parameter block on stack
|
|
MOVE.L SP, A0 ; Point to it
|
|
_GetADBInfo
|
|
|
|
ROR.L #8, D3 ; Rotate ADB Address to high byte
|
|
MOVE.W (SP)+, D3 ; Put Device Type, Orig Addr in low word
|
|
ADDQ.L #8, SP ; Clear off the rest of the stack
|
|
SWAP D3 ; D3 is now Device Type;Orig Addr;ADB Addr;Unused
|
|
|
|
MOVE.B 1(A1), D0 ; Get first stroke
|
|
MOVE.B 2(A1), -(SP) ; Save second one on stack
|
|
BSR.S KeyIn
|
|
MOVE.B (SP)+, D0 ; Get second stroke
|
|
|
|
|
|
|
|
;_________________________________________________________________________________________
|
|
;
|
|
; Routine: KeyIn
|
|
; Arguments: D0.B Raw Keycode
|
|
; D3.L Device Type, Orig Addr, ADB Addr, Unused
|
|
; A2.L Pointer to private data area
|
|
; Output: None
|
|
; Function Translates keycode and posts event as appropriate.
|
|
; Side Effects: Trashes A0, A1, D0, D1, D2, D3
|
|
; Called From: KbdDrvr twice, (1 BSR, 1 fall-through)
|
|
;
|
|
;_________________________________________________________________________________________
|
|
|
|
KeyIn CMP.B #$FF, D0 ; Is it not a key?
|
|
BEQ KbdDone ; Skip if so
|
|
|
|
CLR.W KeyLast ; Stop repeating
|
|
CLR.W HiKeyLast ; Stop repeating
|
|
|
|
MOVEQ #$7F, D1 ; Mask = 01111111 binary
|
|
AND.B D0, D1 ; Clear all but low 7 bits
|
|
|
|
MOVE.L KMAPPtr(A2), A1 ; Get KMAP table address
|
|
MOVE.B KMstart(A1, D1), D3 ; Get device independent keycode
|
|
BPL.S NoExcept ; Handle normally if high bit clear
|
|
|
|
; An exception has been indicated. Find the correct entry in the exception
|
|
; table and handle as appropriate.
|
|
BCLR #7, D3 ; Clear the high bit
|
|
LEA KMnumEx(A1), A0 ; Get to the beginning of the exceptions
|
|
MOVE.W (A0)+, D2 ; Number of entries in table
|
|
BEQ.S NoExcept ; Skip if none
|
|
SUBQ.W #1, D2 ; Turn it into a zero-based count
|
|
|
|
ExLoop
|
|
CMP.B (A0)+, D0 ; See if this is the one
|
|
BEQ FoundEx ; Skip if so
|
|
MOVE.B 1(A0), D1 ; Get the string length
|
|
LEA 2(A0, D1), A0 ; Point to the next entry
|
|
DBRA D2, ExLoop ; Go around again
|
|
|
|
NoExcept
|
|
MOVEQ #0, D2 ; Clear out D2
|
|
MOVE.B D3, D2 ; Copy virtual keycode to D2
|
|
LSR.W #3, D2 ; Divide by 8 for byte offset
|
|
|
|
TST.B D0 ; Up or down key?
|
|
BMI.S KeyUp ; Skip around if key up
|
|
BSET D3, KeyBits(A2, D2) ; Set it for key down
|
|
BRA.S Hammer
|
|
KeyUp
|
|
BCLR D3, KeyBits(A2, D2) ; Clear it for key up
|
|
BSET #7, D3 ; Remember key up for raw key.
|
|
|
|
;* Begin Norsi Keypad changes (keypad uses modifiers from last keyboard pressed) 04/21/92*
|
|
Hammer MOVE.L D3, D0 ; Get Device Type, Orig Addr, ADB Addr, keycode
|
|
ROL.L #8, D0 ; Rotate Device Type into low byte
|
|
CMP.B #keypadNorsi, D0 ; Is this a Norsi ergonomic KEYPAD?
|
|
BNE.S HammerKeyMap ; If not, go update the keymap
|
|
MOVE.W KeyMap+6, D0 ; Modifier bits of last pressed keyboard
|
|
AND.W #$807F,D0 ; Mask off non-modifier bits
|
|
MOVE.W KeyBits+6(A2), D1 ; Get Norsi KEYPAD's pseudo modifier bits
|
|
AND.W #$7F80,D1 ; Mask off KEYPAD's old modifier bits
|
|
OR.W D0, D1 ; Replace KEYPAD's modifier bits with the modifier
|
|
MOVE.W D1, KeyBits+6(A2) ; bits from the last pressed keyboard
|
|
;* End Norsi Keypad changes (keypad uses modifiers from last keyboard pressed) 04/21/92*
|
|
|
|
HammerKeyMap
|
|
MOVEM.L KeyBits(A2), D0-D2/A0 ; Get current devices map of key pressed or not
|
|
MOVEM.L D0-D2/A0, KeyMap ; Hammer this devices map into global keymap
|
|
MOVE.L D3, D0 ; Bits 15-8 contain ADB address
|
|
LSR.L #8, D0 ; Put it in the low byte
|
|
MOVE.B D0, KbdLast ; Stuff it down
|
|
SWAP D0 ; Now get DeviceType
|
|
MOVE.B D0, KbdType ; Update KbdType to show last one used
|
|
|
|
; The next two instructions build the byte of modifier flags from the
|
|
; global key state information. This works because the modifier flags
|
|
; exist in bits $37 to $3E, which appear in the following manner:
|
|
; Byte | 6 | 7 |
|
|
; Bit |37 36 35 34 33 32 31 30|3F 3E 3D 3C 3B 3A 39 38|
|
|
; |^^ | ^^ ^^ ^^ ^^ ^^ ^^ ^^|
|
|
MOVE.W KeyBits+6(A2), D0 ; Get modifier word
|
|
ROL.W #1, D0 ; Rotate in command key
|
|
|
|
SUBQ.L #4, SP ; Make room for result
|
|
MOVE.L KCHRPtr(A2), -(SP) ; Push address of KCHR resource
|
|
MOVE.W D3, -(SP) ; Push keycode (w/o modifiers)
|
|
MOVE.B D0, (SP) ; Put modifiers where they belong
|
|
PEA DeadKey(A2) ; Push address of dead key state
|
|
_KeyTrans
|
|
|
|
MOVE.W (SP)+, D0 ; Get the high word first
|
|
BEQ.S NextWord ; Skip if null
|
|
BSR.S PostIt ; Otherwise post the event
|
|
NextWord
|
|
MOVE.W (SP)+, D0 ; Get the other word
|
|
BEQ.S KbdDone ; If null, we're done
|
|
|
|
|
|
|
|
;_________________________________________________________________________________________
|
|
;
|
|
; Routine: PostIt
|
|
; Arguments: D0.W ASCII Code
|
|
; D3.W ADB Address in high byte and raw keycode in low byte
|
|
; A2.L Pointer to private data area
|
|
; Output: None
|
|
; Function Posts the keyboard event as appropriate.
|
|
; Side Effects: Trashes A0, D0, D1
|
|
; Called From: KeyIn twice, (1 BSR, 1 fall-through)
|
|
;
|
|
;_________________________________________________________________________________________
|
|
|
|
PostIt ROR.W #8, D0 ; Swap ASCII high and low byte (xxLH)
|
|
SWAP D0 ; Move to high word (LHxx)
|
|
MOVE.W D3, D0 ; Move in ADB address and raw keycode (LHFR)
|
|
ROL.L #8, D0 ; Rotate around (HFRL)
|
|
|
|
TST.B D3 ; Key up or down?
|
|
BMI.S PostKeyUp ; Skip if key up
|
|
MOVE.L Ticks, D1
|
|
MOVE.L D1, KeyTime ; Mark the time for auto repeat
|
|
MOVE.L D1, KeyRepTime
|
|
MOVE.W D0, KeyLast ; Save event message
|
|
SWAP D0
|
|
MOVE.W D0, HiKeyLast ; Save high word too
|
|
SWAP D0
|
|
MOVE #KeyDwnEvt, A0 ; Get event number
|
|
_PostEvent ; Post it
|
|
KbdDone
|
|
RTS ; And leave
|
|
PostKeyUp
|
|
MOVE #KeyUpEvt, A0 ; Get event number
|
|
BCLR #15, D0 ; Clear the up/down bit in the raw keycode
|
|
_PostEvent ; Post it
|
|
RTS ; End KbdDrvr
|
|
|
|
|
|
|
|
;_________________________________________________________________________________________
|
|
;
|
|
; Routine: FoundEx
|
|
; Arguments: A0.L Pointer to exception data
|
|
; A2.L Pointer to private data area
|
|
; D3.W Virtual keycode
|
|
; Output: None
|
|
; Function An exception exists for this particular keystroke. Process it
|
|
; appropriately.
|
|
; Side Effects: Trashes A0, D0, D1, D2
|
|
; Called From: KeyIn twice, (1 BSR, 1 fall-through)
|
|
;
|
|
;_________________________________________________________________________________________
|
|
FoundEx
|
|
MOVE.B (A0)+, D1 ; Get the operand
|
|
BPL.S @notXORKey ; Skip if not
|
|
|
|
MOVEQ #0, D2 ; Clear out D2
|
|
MOVE.B D3, D2 ; Copy virtual keycode to D2
|
|
LSR.W #3, D2 ; Divide by 8 for byte offset
|
|
BTST D3, KeyBits(A2, D2) ; Get current key state
|
|
SEQ D0 ; Invert and put in D0
|
|
|
|
@notXORKey
|
|
MOVEQ #$F, D2 ; Prepare mask for ADB op
|
|
AND.B D1, D2 ; D2 is ADB op w/o net address
|
|
BEQ.S KbdDone ; If ADB op = 0 (Bus Reset), ignore key
|
|
|
|
TST.B KNoADBOp(A2) ; See if we should even do this
|
|
BNE NoExcept ; Skip if not
|
|
MOVEM.L D0/A1, -(SP) ; Save D0 & A1
|
|
MOVE.L A0, -(SP) ; Data address = mask
|
|
CMP.B #TalkCmd, D2 ; Is it a talk command?
|
|
BGE.S @kbdTalk ; Skip if so
|
|
PEA KbdBufFree ; Completion routine = KbdBufFree
|
|
BRA.S @kbdBufAlloc
|
|
@kbdTalk
|
|
PEA KbdListen ; Completion Routine = KbdListen
|
|
|
|
@kbdBufAlloc
|
|
LEA KNumBufs(A2), A1 ; Point to the number of available buffers
|
|
MOVE.B (A1)+, D1 ; Get the number of buffers
|
|
BEQ.S @kNoBufAvail ; Skip if none available
|
|
SUBQ.W #1, D1 ; Turn it into a zero based count
|
|
@kBufLoop
|
|
TST.B (A1)+ ; Is the buffer busy?
|
|
BEQ.S @kGotABuf ; No, Go use it
|
|
LEA KBufLen-1(A1), A1 ; Point to the next one
|
|
DBRA D1, @kBufLoop ; Go around again
|
|
BRA.S @kNoBufAvail ; It's a loss
|
|
|
|
@kGotABuf
|
|
MOVE.B D0, -1(A1) ; Store the up/down state in the busy info
|
|
BSET #1, -1(A1) ; Make sure it shows up as busy
|
|
MOVE.L A1, -(SP) ; Buffer Address
|
|
|
|
MOVE.B (A0), D1 ; Get length of source string
|
|
CMP.B #8, D1 ; Greater than 8?
|
|
BLS.S @kStrCopyLoop ; If not, no problem
|
|
MOVEQ #8, D1 ; Copy only the first 8 to avoid trashing mem
|
|
@kStrCopyLoop
|
|
MOVE.B (A0)+, (A1)+ ; Start copying the string
|
|
DBRA D1, @kStrCopyLoop ; Repeat D1+1 times
|
|
|
|
MOVE.W D3, D0 ; Get the FDB Address
|
|
CLR.B D0 ; Clear out the low byte
|
|
LSR.W #4, D0 ; Shift it down to form high nibble of ADB Command
|
|
OR.B D2, D0 ; Include low op nibble
|
|
MOVE.L SP, A0 ; Point to parameter block
|
|
_ADBOp ; Pray that everything is OK
|
|
BNE.S @kOpFailed ; Branch if not
|
|
ADDQ.L #4, SP ; Pop Buffer Address
|
|
@kNoBufAvail
|
|
ADDQ.L #8, SP ; Pop Completion and Data Address
|
|
MOVEM.L (SP)+, D0/A1 ; Restore D0 & A1
|
|
BRA NoExcept ; Finish dealing with the keystroke
|
|
|
|
@kOpFailed
|
|
MOVE.L (SP)+, A1 ; Get the buffer address
|
|
CLR.B -1(A1) ; Mark it as not busy
|
|
BRA.S @kNoBufAvail ; End FoundEx
|
|
|
|
|
|
|
|
;_________________________________________________________________________________________
|
|
;
|
|
; Routine: KbdListen
|
|
; Arguments: D0.B ADB Command
|
|
; D1.L DeviceType, OrigAddr, ADBAddr, Unused (byte order)
|
|
; A0.L ADB Buffer Address
|
|
; A1.L ADB Completion Routine Address (= KbdListen)
|
|
; A2.L Pointer to private data area
|
|
; Output: None
|
|
; Function: Sets or clears bits in mask pointed to by A2 in buffer pointed
|
|
; to by A0. Used to alter values of registers in ADB devices.
|
|
; Side Effects: Trashes A0, A1, A2, D0, D1, D2
|
|
;
|
|
;_________________________________________________________________________________________
|
|
|
|
KbdListen MOVE.L A0, A1 ; Copy A0 into A1
|
|
MOVEQ #0, D1 ; Clear out D1
|
|
MOVE.B (A1)+, D1 ; Get length of buffer
|
|
MOVE.B (A2)+, D2 ; Get length of mask
|
|
CMP.B D2, D1 ; Is mask length smaller?
|
|
BLS.S @notSmall ; Skip if not
|
|
MOVE.B D2, D1 ; Use the mask length instead
|
|
@notSmall
|
|
; (A2) is a mask for (A0), 0 meaning don't change, 1 meaning clear or set
|
|
; depending upon the value of -1(A0).
|
|
TST.B -1(A0) ; PL = clear, MI = set
|
|
BPL.S @endClrLoop
|
|
BRA.S @endSetLoop
|
|
|
|
@setLoop
|
|
MOVE.B (A2)+, D2 ; Get the mask byte
|
|
OR.B D2, (A1)+ ; Set the correct bits
|
|
@endSetLoop
|
|
DBRA D1, @setLoop ; Go around again
|
|
BRA.S @kLoopDone
|
|
|
|
@clrLoop
|
|
MOVE.B (A2)+, D2 ; Get the mask byte
|
|
NOT.B D2 ; Invert it
|
|
AND.B D2, (A1)+ ; Clear the correct bits
|
|
@endClrLoop
|
|
DBRA D1, @clrLoop ; Go around again
|
|
|
|
@kLoopDone
|
|
CLR.L -(SP) ; No data address needed
|
|
PEA KbdBufFree ; Completion routine = KbdBufFree
|
|
MOVE.L A0, -(SP) ; Use the buffer one more time
|
|
MOVE.L SP, A0 ; Point to parameter block
|
|
BCLR #2, D0 ; Turn the talk into a listen command
|
|
_ADBOp
|
|
BNE.S @kLSuccess ; Branch on success
|
|
|
|
MOVE.L (SP), A0 ; Get the buffer address
|
|
CLR.B -1(A0) ; Mark it as not busy
|
|
@kLSuccess
|
|
LEA 12(SP), SP ; Pop the parameter block
|
|
RTS ; End KbdListen
|
|
|
|
|
|
|
|
;_________________________________________________________________________________________
|
|
;
|
|
; Routine: KbdBufFree
|
|
; Arguments: D0.B ADB Command
|
|
; D1.L DeviceType, OrigAddr, ADBAddr, Unused (byte order)
|
|
; A0.L ADB Buffer Address
|
|
; A1.L ADB Completion Routine Address (= KbdListen)
|
|
; A2.L Pointer to private data area
|
|
; Output: None
|
|
; Function: Marks the buffer pointed to by A0 as free.
|
|
; Side Effects: None
|
|
;
|
|
;_________________________________________________________________________________________
|
|
|
|
KbdBufFree CLR.B -1(A0) ; Mark buffer free
|
|
RTS ; End KbdBufFree
|
|
|
|
|
|
|
|
;_________________________________________________________________________________________
|
|
;_________________________________________________________________________________________
|
|
;_________________________________________________________________________________________
|
|
|
|
END ;End file |