mirror of
https://github.com/elliotnunn/supermario.git
synced 2024-11-26 01:49:19 +00:00
2020 lines
75 KiB
Plaintext
2020 lines
75 KiB
Plaintext
|
;
|
|||
|
; File: ADBMgr.a
|
|||
|
;
|
|||
|
; Contains: This file holds the ADB implementation as used on the Mac SE and later machines.
|
|||
|
; It is separated out from the original Mac keyboard implementation to reduce
|
|||
|
; conditional assembly confusion. Some of the original file’s modification
|
|||
|
; history has been preserved here for your amusement.
|
|||
|
;
|
|||
|
; Written by: ADB manager re-written 15-May-89 by Gary G. Davidian
|
|||
|
;
|
|||
|
; Copyright: © 1981-1993 by Apple Computer, Inc. All rights reserved.
|
|||
|
;
|
|||
|
; Change History (most recent first):
|
|||
|
;
|
|||
|
; <SM11> 12/13/93 PN Roll in KAOs and Horror changes to support Malcom and AJ
|
|||
|
; machines.
|
|||
|
; <SM10> 5/20/93 RB Rolled in a patch to the KeyTrans routine that we missed last
|
|||
|
; time...
|
|||
|
; <SM9> 11/30/92 SWC Fixed the Horror roll in. A bunch of code was left hanging
|
|||
|
; around that doesn't need to be here.
|
|||
|
; <SM8> 11/3/92 RB Added back support for the KeyHooks (even though KeyTrans has
|
|||
|
; been available for years) because of FoolWrite and Microsoft
|
|||
|
; Weird. (Yikes !)
|
|||
|
; <SM7> 8/26/92 kc Roll in Horror changes. From KbdADB.a
|
|||
|
; <H6> 7/13/92 GMR DefaultDevice now calls CrsrDevReInit (post-proc) to install the
|
|||
|
; mice earlier so we don't loose the mouse-down event for ejecting
|
|||
|
; floppies.
|
|||
|
; <H5> 6/4/92 ag Added flush and delay to regenerate any keystrokes which may
|
|||
|
; come in before the handlers are in place. The delay was
|
|||
|
; necessary to allow the keyboard time to return keys down. The
|
|||
|
; approx. time was determined by experimentation, then 100% margin
|
|||
|
; was added for safety.
|
|||
|
; <H4> 4/3/92 SWC Modified InitADB and RequestDone to use primitives tables (yes,
|
|||
|
; another one) attached to the ProductInfo table. All
|
|||
|
; implementation-specific code is now in ADBPrimitives.a. Removed
|
|||
|
; the old mouse driver (and initialization) since that's now
|
|||
|
; handled in CrsrDev.a.
|
|||
|
; <H3> 2/21/92 SWC GMR/Backed out <T6> since DefaultDev and KbdInstall can move
|
|||
|
; memory (they call GetResource), and InitDevT is a completion
|
|||
|
; routine run at interrupt level 1. The symptoms were that
|
|||
|
; _ADBReInit could hang or crash.
|
|||
|
; <H2> 2/12/92 SWC Patched in new CrsrDev stuff for mouse/trackball/etc.
|
|||
|
; acceleration.
|
|||
|
; <SM6> 5/21/92 kc Append "Trap" to the names of GetADBInfo, SetADBInfo, ADBOp and
|
|||
|
; GetIndADB to avoid name conflict with the glue.
|
|||
|
; <SM5> 5/17/92 kc Add include of PowerPrivEqu.a. Export
|
|||
|
; ExplicitRequestDone,ImplicitRequestDone and RunADBRequest.
|
|||
|
; <SM4> 4/30/92 SES Rolled in ReqDoneVIA patch from PatchIIciROM.a. The patch makes
|
|||
|
; sure that the routine doesn't try to poll a device that's not in
|
|||
|
; the device table.
|
|||
|
; <SM3> 4/14/92 RB Rolled in ADReInitPatch from BeforePatches.a (PTCH 0). The patch
|
|||
|
; restores the KCHR in the data records associated with keyboard
|
|||
|
; drivers if a KCHR pointer has already been stored in ExpandMem.
|
|||
|
; This is done as a post-procedure on the ADBReinit hook.
|
|||
|
; <2> 3/27/92 JSM Export InitADBDrvr.
|
|||
|
; <1> • Pre-SuperMario comments follow •
|
|||
|
; <14> 2/12/92 JSM Moved this file to ADBMgr folder, keeping all the old revisions;
|
|||
|
; this file used to be included by Kbd.a, now it stands by itself,
|
|||
|
; so merge in the Kbd.a wrapper.
|
|||
|
; <13> 1/20/92 KC Roll in Terror changes. Original comments below.
|
|||
|
; {6} 6/15/90 CV Adding code to check the ADB device address against the ADB
|
|||
|
; device bit map for Egret transactions. If the device is not in
|
|||
|
; the map, the MRU and LRU are forced to the mouse and keyboard.
|
|||
|
; This is a work-around for an autopoll bug in Egret.
|
|||
|
; From KbdADB.a.
|
|||
|
; [6] 6/6/91 ag moved data structure initialization routines inside initdevT.
|
|||
|
; From EgretPatchesToo.a (via EgretMgr.a)
|
|||
|
; (13) 6/11/91 BG (actually GS/GA) Added a check to the RequestDonePatch routine
|
|||
|
; to check if we are in the middle of ADB initialization. If in
|
|||
|
; INIT then pass control to the handler address, if valid.
|
|||
|
; <12> 10/18/91 JSM Get rid of all the stupid conditionals.
|
|||
|
; <11> 5/21/91 gbm Nail a couple of warnings
|
|||
|
; <10> 9/18/90 BG Removed <7>, <8>. 040s are behaving more reliably now.
|
|||
|
; <9> 9/14/90 MSH Interface to the Power Manager changed to cut down on the
|
|||
|
; overhead.
|
|||
|
; <8> 8/3/90 BG Found another place to put an EclipseNOP.
|
|||
|
; <7> 6/18/90 CCH Added EclipseNOPs for flaky 68040's.
|
|||
|
; <6> 3/29/90 MSH Add universal test for call to IdleUpdate.
|
|||
|
; <5> 2/28/90 GMR Backed out of changes <2>,<3>, and <4>. Implemented new ADB
|
|||
|
; support for use with the new EgretMgr.
|
|||
|
; <4> 2/11/90 GA Added endwith to with statements inside hasEgret Conditionals
|
|||
|
; <3> 2/9/90 GA Moved the code which sends SendBitmap and StartAutoPoll commands
|
|||
|
; to Egret from ADBfMgr.a to EgretMgr.a. Now, ADBMgr.a does a JSR
|
|||
|
; StartEgretAutoPoll to EgretMgr.
|
|||
|
; <2> 2/4/90 GA Adding ADB support for Egret.
|
|||
|
; <2.1> 11/19/89 GGD NEEDED FOR ZONE-5 Modified IOP Based ADB to pass DevMap to the
|
|||
|
; IOP when auto polling so that the IOP will just poll the
|
|||
|
; addresses in the device table. This will solve the the problems
|
|||
|
; of the jerky cursor when typing and mousing at the same time, as
|
|||
|
; well as fixing the EvE Copy Protection device problems.
|
|||
|
; <2.0> 11/1/89 MSH Replaced activity detection with IdleUpdate trap (hcmac).
|
|||
|
; <1.9> 7/12/89 GGD Fixed problems when a mouse or keyboard were not present at
|
|||
|
; boot, but were connected later. Although default entries were
|
|||
|
; being created in the device table for them, they were not being
|
|||
|
; auto/srq polled. They should now behave as they did on the Mac
|
|||
|
; II. Added a small amount of padding for overpatching.
|
|||
|
; <1.8> 5/16/89 GGD Implemented de-facto standard to allow a buffer address of zero
|
|||
|
; to be passed to ADBop, it will not read or write to the buffer
|
|||
|
; (not even the length byte).
|
|||
|
; <1.7> 5/15/89 GGD Re-wrote the ADB manager, isolated the hardware dependencies and
|
|||
|
; added universal rom support. Fixed many known problems with
|
|||
|
; prior implementations. Modified initialization code to use
|
|||
|
; ADBop. Re-wrote Mouse Driver to not directly access ADB manager
|
|||
|
; variables, and to de-bounce the mouse button without loosing
|
|||
|
; mouse up events. Moved functionality of the routine InitADBVars
|
|||
|
; from StartInit into InitADB.
|
|||
|
; <1.6> 5/1/89 GGD Added back some code that was inadvertently deleted from the
|
|||
|
; ViaADB routines to try to fix some of the problems that have
|
|||
|
; appeared in that implementation. Changed to use new RECORD
|
|||
|
; version of AppleDesktopPriv.a. Added a few minor changes in
|
|||
|
; preparation for universal rom version (coming soon).
|
|||
|
; <1.5> 4/7/89 MSH Moved PMGT interrupt enable from here to startinit.
|
|||
|
; <1.4> 3/30/89 CSL disable interrupt when command queue is manipulated.
|
|||
|
; <1.3> 3/5/89 PKE Roll in & update KeyTrans patch (Int'l itlk processing) from
|
|||
|
; KeyHack.a
|
|||
|
; <1.2> 3/1/89 MSH Exported RSetKmap
|
|||
|
; <1.1> 11/10/88 CCH Fixed Header.
|
|||
|
; <1.0> 11/9/88 CCH Adding to EASE.
|
|||
|
; <1.1> 10/7/88 rwh for IopADB, added MACHINE MC68020 and WITH ADBIOPVars.
|
|||
|
; <1.0> 10/6/88 rwh New Today - split off from Kbd.a for programmer sanity. Uses
|
|||
|
; feature-based conditionals now.
|
|||
|
; <•2.0> 9/23/88 CCH Got rid of inc.sum.d and empty nFiles
|
|||
|
; <1.9> 9/8/88 MSH New sleep/idel support routine.
|
|||
|
; <1.8> 8/18/88 MSH Removed stack frame too soon.
|
|||
|
; <1.7> 8/5/88 MSH One more bug fix for HcMac. If no device answers to a trip
|
|||
|
; through SRQ polling, then try again.
|
|||
|
; <1.6> 7/19/88 MSH Completely new ADBDispatch and may bug fixes for HcMac.
|
|||
|
; <1.5> 7/6/88 MSH Label accidentally removed.
|
|||
|
; <1.4> 7/6/88 MSH Gary Davidian found the BNE should be a BEQ to FDBNBusy. MISSING
|
|||
|
; RTS in ShiftOut!!! Removed busy bit setting in ADBDispatch
|
|||
|
; before calling FDBOp.
|
|||
|
; <1.3> 5/20/88 MSH For HcMac, ShiftOut had the wrong starting address when copying
|
|||
|
; to local buffer
|
|||
|
; <1.2> 5/19/88 MSH ListenR3 cleared the data count to zero for HcMac.
|
|||
|
; <1.1> 4/18/88 CSL Add support for sleep and idle in call completion routine
|
|||
|
; <1.0> 2/10/88 BBM Adding file for the first time into EASE…
|
|||
|
; POST MAC II MODIFICATION HISTORY:
|
|||
|
; <C931> 11/5/87 CSL EMT Roll in patches for ADBReinit (PAB191&PAB192).
|
|||
|
; <C930> 11/5/87 MSH Rewrote FDBShiftInt for Laguna, new interrupt interface to
|
|||
|
; PowerMgr.
|
|||
|
; <C914> 10/29/87 rwh Port to Modern Victorian
|
|||
|
; <C916> 10/21/87 MSH Fixed the drba loop in FDBshiftInt for Laguna.
|
|||
|
; <C889> 9/18/87 MSH Added support for HcMac (Laguna). State machine is gone due to
|
|||
|
; easier power manager interface. Also cleaned up the text a bit.
|
|||
|
;
|
|||
|
|
|||
|
BLANKS ON
|
|||
|
STRING ASIS
|
|||
|
|
|||
|
PRINT OFF
|
|||
|
|
|||
|
LOAD 'StandardEqu.d'
|
|||
|
INCLUDE 'HardwarePrivateEqu.a'
|
|||
|
INCLUDE 'PowerPrivEqu.a'
|
|||
|
INCLUDE 'IopEqu.a'
|
|||
|
INCLUDE 'EgretEqu.a'
|
|||
|
INCLUDE 'AppleDeskBusPriv.a'
|
|||
|
INCLUDE 'ApplDeskBus.a'
|
|||
|
INCLUDE 'ScriptPriv.a' ; <03/05/89 pke>
|
|||
|
INCLUDE 'UniversalEqu.a'
|
|||
|
INCLUDE 'IOPrimitiveEqu.a'
|
|||
|
|
|||
|
PRINT ON
|
|||
|
PRINT NOMDIR
|
|||
|
|
|||
|
MACHINE MC68020
|
|||
|
|
|||
|
ADBManager PROC EXPORT
|
|||
|
|
|||
|
EXPORT CountADBs,GetIndADBTrap,GetADBInfoTrap,SetADBInfoTrap
|
|||
|
EXPORT ADBReInit,ADBOpTrap,KeyTrans
|
|||
|
EXPORT InitADB,InitADBDrvr,ADBProc,RSetKMap
|
|||
|
EXPORT ExplicitRequestDone,ImplicitRequestDone,RunADBRequest
|
|||
|
|
|||
|
IMPORT CrsrDevReInit
|
|||
|
|
|||
|
jEgretDispatch equ OSTable+($92*4) ; OS trap table entry for _EgretDispatch
|
|||
|
Debugging equ 0 ; disable debugging checks
|
|||
|
|
|||
|
eject
|
|||
|
Title 'KbdADB - ADB Manager - CountADBs / GetIndADB'
|
|||
|
|
|||
|
;______________________________________________________________________
|
|||
|
;
|
|||
|
; Routine: CountADBs
|
|||
|
; Arguments: None
|
|||
|
; Output: D0.W Number of ADB entries
|
|||
|
; Function: This routine counts the number of entries in the ADB
|
|||
|
; table.
|
|||
|
;______________________________________________________________________
|
|||
|
|
|||
|
with ADBVars,ADBDeviceEntry
|
|||
|
|
|||
|
CountADBs MOVEQ #numFDBAdr, D1 ; Number of table entries
|
|||
|
MOVE.W D1, D0 ; Save it here, too
|
|||
|
MOVEA.L ADBBase, A1 ; Put Base in A1
|
|||
|
addq.w #startDevT+FDBAddr,a1 ; point to the address field
|
|||
|
BRA.S FirstCount ; Skip past record increment
|
|||
|
|
|||
|
CountADBLoop
|
|||
|
ADDA.W #FRecSize, A1 ; Get to next record
|
|||
|
FirstCount
|
|||
|
TST.B (A1) ; If 0, then previous entry was last
|
|||
|
DBEQ D1, CountADBLoop ; Loop until last is found
|
|||
|
|
|||
|
SUB.W D1, D0 ; D1 is #numFDBAdr-(number of records)
|
|||
|
RTS
|
|||
|
endwith
|
|||
|
|
|||
|
|
|||
|
;______________________________________________________________________
|
|||
|
;
|
|||
|
; Routine: GetIndADB
|
|||
|
; Arguments: DO.W Index from 1 to the value returned by CountADBs
|
|||
|
; A0 Pointer to buffer in which DeviceType, OrigAddr,
|
|||
|
; ServiceAddr, DataAddr are returned (10 bytes)
|
|||
|
; Output: D0.L Unique ADBAddr based on index (-1 if input invalid)
|
|||
|
; Function: This routine returns information from the ADB table
|
|||
|
; Note: This routine shares code with GetADBInfo and FindADBInfo
|
|||
|
;______________________________________________________________________
|
|||
|
|
|||
|
with ADBVars,ADBDeviceEntry
|
|||
|
GetIndADBTrap
|
|||
|
TST.W D0 ; Make sure D0 is within bounds
|
|||
|
BLE.S ADBNotFound ; <= 0?
|
|||
|
CMPI.W #numFDBAdr, D0 ; Or > Maximum number of records?
|
|||
|
BGT.S ADBNotFound ; Punt this if so
|
|||
|
|
|||
|
MOVEA.L ADBBase, A1 ; Initialize A1
|
|||
|
MULU #FRecSize, D0 ; Multiply index by record size
|
|||
|
LEA -FRecSize(A1, D0.L), A1 ; A1 points to record now.
|
|||
|
MOVEQ #0, D0 ; Clear out D0
|
|||
|
MOVE.B FDBAddr(A1), D0 ; Return FDBAddr
|
|||
|
|
|||
|
; Load up the buffer pointed to by A0 from the record pointed to by A1.
|
|||
|
|
|||
|
LoadBuf MOVE.B FDBDevTy(A1), (A0)+ ; Return DeviceType
|
|||
|
MOVE.B FDBOAddr(A1), (A0)+ ; Return OrigAddr
|
|||
|
MOVE.L FDBCRA(A1), (A0)+ ; Return ServiceAddr
|
|||
|
MOVE.L FDBOpData(A1), (A0) ; Return DataAddr
|
|||
|
RTS
|
|||
|
endwith
|
|||
|
|
|||
|
|
|||
|
Title 'KbdADB - ADB Manager - GetADBInfo / SetADBInfo / FindFDBInfo'
|
|||
|
;______________________________________________________________________
|
|||
|
;
|
|||
|
; Routine: GetADBInfo
|
|||
|
; Arguments: DO.B ADBAddr
|
|||
|
; A0 Pointer to buffer in which DeviceType, OrigAddr,
|
|||
|
; ServiceAddr, DataAddr are returned (10 bytes)
|
|||
|
; Output: D0.L 0 if found, -1 if not
|
|||
|
; Function: This routine returns information from the ADB table
|
|||
|
; Note: This routine shares code with GetIndADB
|
|||
|
;______________________________________________________________________
|
|||
|
GetADBInfoTrap
|
|||
|
BSR.S FindFDBInfo
|
|||
|
BEQ.S LoadBuf ; If found, go load up the buffer
|
|||
|
RTS ; Otherwise, go home
|
|||
|
|
|||
|
|
|||
|
;______________________________________________________________________
|
|||
|
;
|
|||
|
; Routine: SetADBInfo
|
|||
|
; Arguments: DO.B ADBAddr
|
|||
|
; A0 Pointer to buffer containing ServiceAddr and
|
|||
|
; DataAddr (8 bytes)
|
|||
|
; Output: D0.L 0 if found, -1 if not
|
|||
|
; Function: This routine returns information from the ADB table
|
|||
|
;______________________________________________________________________
|
|||
|
|
|||
|
with ADBDeviceEntry
|
|||
|
SetADBInfoTrap
|
|||
|
BSR.S FindFDBInfo
|
|||
|
BNE.S DoneSet ; If not found, go away
|
|||
|
|
|||
|
MOVE.L (A0)+, FDBCRA(A1) ; Set ServiceAddr
|
|||
|
MOVE.L (A0), FDBOpData(A1) ; Set DataAddr
|
|||
|
DoneSet RTS
|
|||
|
endwith
|
|||
|
|
|||
|
|
|||
|
;______________________________________________________________________
|
|||
|
;
|
|||
|
; Routine: FindFDBInfo
|
|||
|
; Arguments: DO.B FDBAddr
|
|||
|
; Output: D0.L 0 if found, -1 if not
|
|||
|
; A1 Real address of FDB record if found.
|
|||
|
; Address of next available entry if not found.
|
|||
|
; Function: This routine returns information from the FDB table
|
|||
|
; Side Effects: (or lack thereof) Does not alter A0.
|
|||
|
; Note: This routine shares code with GetIndADB
|
|||
|
;______________________________________________________________________
|
|||
|
|
|||
|
with ADBVars,ADBDeviceEntry
|
|||
|
|
|||
|
FindFDBInfo MOVEQ #numFDBAdr, D1 ; Number of table entries
|
|||
|
MOVEA.L ADBBase, A1 ; Put Base in A1
|
|||
|
BRA.S FirstFind ; Skip past record increment
|
|||
|
FindFDBLoop
|
|||
|
ADDA.W #FRecSize, A1 ; Get to next record
|
|||
|
FirstFind
|
|||
|
CMP.B FDBAddr(A1), D0 ; Is this the right one?
|
|||
|
BEQ.S DoneFind ; If so, we're done
|
|||
|
TST.B FDBAddr(A1) ; Is it 0?
|
|||
|
DBEQ D1, FindFDBLoop ; Loop until it is found or no more.
|
|||
|
ADBNotFound
|
|||
|
; If we got this far, it wasn't found. Return Error.
|
|||
|
MOVEQ #-1, D0 ; Indicate Error
|
|||
|
RTS
|
|||
|
DoneFind
|
|||
|
MOVEQ #0, D0 ; Indicate Success
|
|||
|
RTS
|
|||
|
endwith
|
|||
|
|
|||
|
|
|||
|
Title 'KbdADB - ADB Manager - ADBOp'
|
|||
|
;_______________________________________________________________________
|
|||
|
;
|
|||
|
; Routine: ADBOp
|
|||
|
; Inputs: A0.L - pointer to ADBOpBlock paramater block
|
|||
|
; D0.B - ADB command/address byte to send
|
|||
|
;
|
|||
|
; Outputs: D0 - Result Code (noErr, or -1 if queue full)
|
|||
|
;
|
|||
|
; Destroys: A0, A1, D0
|
|||
|
; Calls: RunADBRequest
|
|||
|
; Called by: OsTrap Dispatch Table
|
|||
|
;
|
|||
|
; Function: Asynchronously issues an ADB bus transaction, using the command
|
|||
|
; and buffer specified. When the transaction has completed,
|
|||
|
; the completion routine will be called.
|
|||
|
;
|
|||
|
;_______________________________________________________________________
|
|||
|
|
|||
|
with ADBVars,ADBCmdQEntry
|
|||
|
ADBOpTrap ; a0-a1/d1-d2 saved by OsTrap dispatch
|
|||
|
@regs reg d3/a2/a3 ; additional registers to preserve
|
|||
|
movem.l @regs,-(sp) ; save registers
|
|||
|
movea.l ADBBase,a3 ; point to ADB private data structures
|
|||
|
move.w sr,-(sp) ; save interrupt mask
|
|||
|
ori.w #HiIntMask,sr ; disable ints while queueing
|
|||
|
movea.l fQEntPtr(a3),a1 ; pointer to next free element
|
|||
|
btst.b #fDBQEmpty,fDBFlag(a3) ; see if anything in queue
|
|||
|
bne.s @notFull ; if was empty, plenty of room to add
|
|||
|
cmpa.l fQHeadPtr(a3),a1 ; see if queue is full
|
|||
|
beq.s @queueFull ; if full, abort with error
|
|||
|
|
|||
|
; There is room in the queue, so insert the new request at the end of the queue
|
|||
|
|
|||
|
@notFull ; a1 points to the ADBCmdQEntry
|
|||
|
move.b d0,(a1)+ ; fill in fQCmd
|
|||
|
addq.w #1,a1 ; skip over fQUnused
|
|||
|
move.l (a0)+,(a1)+ ; copy dataBuffPtr to fQBuff
|
|||
|
move.l (a0)+,(a1)+ ; copy opServiceRtPtr to fQComp
|
|||
|
move.l (a0)+,(a1)+ ; copy opDataAreaPtr to fQData
|
|||
|
|
|||
|
cmpa.l fQEndPtr(a3),a1 ; see if queue pointer needs to wrap around
|
|||
|
blo.s @noWrap ; if didn't reach end, no wrap yet
|
|||
|
movea.l fQBegPtr(a3),a1 ; if end reached, wrap back to begining
|
|||
|
@noWrap move.l a1,fQEntPtr(a3) ; update the queue entry pointer
|
|||
|
|
|||
|
; The new entry is queued. If queue was previously empty run the new request.
|
|||
|
|
|||
|
bclr.b #fDBQEmpty,fDBFlag(a3) ; indicate queue no longer empty
|
|||
|
beq.s @success ; if not at head of queue, just return success
|
|||
|
bsr.s RunADBRequest ; run the newly queued request
|
|||
|
|
|||
|
@success moveq.l #noErr,d0 ; indicate success
|
|||
|
@done move.w (sp)+,sr ; restore int mask
|
|||
|
movem.l (sp)+,@regs ; restore registers
|
|||
|
rts ; all done
|
|||
|
|
|||
|
@queueFull moveq.l #qErr,d0 ; IM vol 5 says return -1 for queue full
|
|||
|
bra.s @done ; restore regs and return
|
|||
|
endwith
|
|||
|
|
|||
|
|
|||
|
Title 'KbdADB - ADB Manager - RunADBRequest'
|
|||
|
;_______________________________________________________________________
|
|||
|
;
|
|||
|
; Routine: RunADBRequest
|
|||
|
; Inputs: A3 - pointer to ADBBase
|
|||
|
;
|
|||
|
; Outputs: D2 - length of transmit buffer data
|
|||
|
; D3 - command byte / implicit flag (bit 31)
|
|||
|
; A2 - pointer to buffer containing transmit data
|
|||
|
; A3 - pointer to ADBBase
|
|||
|
;
|
|||
|
; Destroys:
|
|||
|
; Calls: exits through StartReqProc (hardware dependent)
|
|||
|
;
|
|||
|
; Function: Determines what command should be sent to ADB next, and calls
|
|||
|
; the hardware dependent routine to process the next request.
|
|||
|
;
|
|||
|
;_______________________________________________________________________
|
|||
|
|
|||
|
with ADBVars,ADBCmdQEntry
|
|||
|
RunADBRequest
|
|||
|
btst.b #fDBQEmpty,fDBFlag(a3) ; see if any explicit commands to run
|
|||
|
beq.s @runFromQueue ; run an explicit command from the queue
|
|||
|
moveq.l #0,d2 ; zero the send byte count
|
|||
|
moveq.l #-1,d3 ; negative command to indicate resume polling
|
|||
|
btst.b #FDBInit,fDBFlag(a3); are we still initializing the bus
|
|||
|
beq.s @resumePolling ; if not, resume auto command polling
|
|||
|
rts ; still initializing, just return
|
|||
|
|
|||
|
@runFromQueue
|
|||
|
movea.l fQHeadPtr(a3),a0 ; get pointer to element at head
|
|||
|
moveq.l #0,d3 ; zero extend command byte, indicate explicit cmd
|
|||
|
move.b fQCmd(a0),d3 ; D3 := command byte
|
|||
|
movea.l fQBuff(a0),a2 ; get the buffer address (pascal string)
|
|||
|
moveq.l #maskADBCmd,d2 ; mask talk/listen command bits
|
|||
|
and.b d3,d2 ; isolate bits from copy of command
|
|||
|
subq.b #ListenCmd,d2 ; see if it is a listen command
|
|||
|
seq.b d2 ; $00FF if listen, $0000 if not (only listen sends data)
|
|||
|
and.b (a2)+,d2 ; D2 := byte count, A2 := ptr to actual data
|
|||
|
@resumePolling
|
|||
|
movea.l StartReqProc(a3),a0 ; get HW dependent proc to start ADB request
|
|||
|
jmp (a0) ; start the ADB request
|
|||
|
endwith
|
|||
|
|
|||
|
|
|||
|
Title 'KbdADB - ADB Manager - ExplicitRequestDone'
|
|||
|
;_______________________________________________________________________
|
|||
|
;
|
|||
|
; Routine: ExplicitRequestDone
|
|||
|
; Inputs: D2 - length of receive buffer data
|
|||
|
; D3 - command byte / SRQ flag (bit 31)
|
|||
|
; A2 - pointer to buffer containing receive data
|
|||
|
; A3 - pointer to ADBBase
|
|||
|
;
|
|||
|
; Outputs: D2 - length of receive buffer data
|
|||
|
; D3 - command byte / SRQ flag (bit 31)
|
|||
|
; A0 - pointer to buffer to pass to completion routine
|
|||
|
; A2 - pointer to buffer containing receive data
|
|||
|
; A3 - pointer to ADBBase
|
|||
|
; 0(SP) - completion routine address
|
|||
|
; 4(SP) - optional data to pass in A2 to completion routine
|
|||
|
; 8(SP) - stack cutback address, after completion routine runs
|
|||
|
;
|
|||
|
; Destroys: D0, D1, A0, A1
|
|||
|
; Calls: exits through RequestDone
|
|||
|
;
|
|||
|
; Function: Dequeues the paramaters to pass to the service routine.
|
|||
|
;
|
|||
|
;_______________________________________________________________________
|
|||
|
|
|||
|
with ADBVars,ADBCmdQEntry
|
|||
|
ExplicitRequestDone
|
|||
|
move.l sp,-(sp) ; allocate an empty buffer on the stack
|
|||
|
move.w sr,d1 ; save interrupt mask
|
|||
|
ori.w #HiIntMask,sr ; disable ints while dequeueing
|
|||
|
movea.l fQHeadPtr(a3),a0 ; get pointer to element to dequeue
|
|||
|
if Debugging then
|
|||
|
btst.b #fDBQEmpty,fDBFlag(a3) ; see if anything in queue
|
|||
|
beq.s @hasEntries ; if something to dequeue, we're ok
|
|||
|
_Debugger ; if not, we're dead
|
|||
|
@hasEntries cmp.b (a0),d3 ; check command sent against command received
|
|||
|
beq.s @cmdOK ; if match, we're ok
|
|||
|
_Debugger ; if not, we're dead
|
|||
|
@cmdOK
|
|||
|
endif
|
|||
|
adda.w #fQSize,a0 ; point past end of element
|
|||
|
movea.l a0,a1 ; save pointer to end of queue element
|
|||
|
cmpa.l fQEndPtr(a3),a0 ; see if queue pointer needs to wrap around
|
|||
|
blo.s @noWrap ; if didn't reach end, no wrap yet
|
|||
|
movea.l fQBegPtr(a3),a0 ; if end reached, wrap back to begining
|
|||
|
@noWrap move.l a0,fQHeadPtr(a3) ; update the queue head pointer
|
|||
|
cmpa.l fQEntPtr(a3),a0 ; see if queue is now empty
|
|||
|
bne.s @notEmpty ; if not, don't need to change empty flag
|
|||
|
bset.b #fDBQEmpty,fDBFlag(a3) ; queue is now empty, set flag to remember it
|
|||
|
@notEmpty
|
|||
|
move.l -(a1),-(sp) ; copy fQData to A2 save area on stack
|
|||
|
move.l -(a1),-(sp) ; copy fQComp to A1 save area on stack
|
|||
|
movea.l -(a1),a0 ; copy fQBuff to A0
|
|||
|
move.w d1,sr ; restore interrupt mask
|
|||
|
bra.s RequestDone ; copy buffer data, resume ADB, call handler
|
|||
|
endwith
|
|||
|
|
|||
|
|
|||
|
Title 'KbdADB - ADB Manager - ImplicitRequestDone'
|
|||
|
;_______________________________________________________________________
|
|||
|
;
|
|||
|
; Routine: ImplicitRequestDone
|
|||
|
; Inputs: D2 - length of receive buffer data
|
|||
|
; D3 - command byte / SRQ flag (bit 31)
|
|||
|
; A2 - pointer to buffer containing receive data
|
|||
|
; A3 - pointer to ADBBase
|
|||
|
;
|
|||
|
; Outputs: D2 - length of receive buffer data
|
|||
|
; D3 - command byte / SRQ flag (bit 31)
|
|||
|
; A0 - pointer to buffer to pass to completion routine
|
|||
|
; A2 - pointer to buffer containing receive data
|
|||
|
; A3 - pointer to ADBBase
|
|||
|
; 0(SP) - completion routine address
|
|||
|
; 4(SP) - optional data to pass in A2 to completion routine
|
|||
|
; 8(SP) - stack cutback address, after completion routine runs
|
|||
|
;
|
|||
|
; Destroys: D0, D1, A0, A1
|
|||
|
; Calls: exits through RequestDone
|
|||
|
;
|
|||
|
; Function: Locates the paramaters to pass to the service routine.
|
|||
|
;
|
|||
|
;_______________________________________________________________________
|
|||
|
|
|||
|
with ADBDeviceEntry
|
|||
|
ImplicitRequestDone
|
|||
|
tst.b d2 ; see if any data returned
|
|||
|
beq.s RunADBRequest ; if no data, ack the data, resume ADB operations
|
|||
|
move.b d3,d0 ; get command that completed
|
|||
|
lsr.b #4,d0 ; get the address from the command
|
|||
|
bsr FindFDBInfo ; get the info for this device
|
|||
|
bne.w RunADBRequest ; if unknown, ack the data, resume ADB operations
|
|||
|
suba.w #12,sp ; allocate a buffer (len byte, 8 data bytes, 3 slop)
|
|||
|
movea.l sp,a0 ; save pointer to buffer
|
|||
|
pea 12(sp) ; save stack restore address
|
|||
|
move.l fDBOpData(a1),-(sp) ; copy fDBOpData to A2 save area on stack
|
|||
|
move.l fDBCRA(a1),-(sp) ; copy fDBCRA to A1 save area on stack
|
|||
|
*Fall Into* bra.s RequestDone ; copy buffer data, resume ADB, call handler
|
|||
|
endwith
|
|||
|
|
|||
|
|
|||
|
Title 'KbdADB - ADB Manager - RequestDone'
|
|||
|
;_______________________________________________________________________
|
|||
|
;
|
|||
|
; Routine: RequestDone
|
|||
|
; Inputs: D2 - length of receive buffer data
|
|||
|
; D3 - command byte / SRQ flag (bit 31)
|
|||
|
; A0 - pointer to buffer to pass to completion routine
|
|||
|
; A2 - pointer to buffer containing receive data
|
|||
|
; A3 - pointer to ADBBase
|
|||
|
; 0(SP) - completion routine address
|
|||
|
; 4(SP) - optional data to pass in A2 to completion routine
|
|||
|
; 8(SP) - stack cutback address, after completion routine runs
|
|||
|
;
|
|||
|
; Outputs: none
|
|||
|
;
|
|||
|
; Destroys: A0-A3/D0-D3
|
|||
|
; Calls: device handler completion routine
|
|||
|
;
|
|||
|
; Function: Copies the receive data into the proper buffer, resumes ADB
|
|||
|
; operations, and calls the device handler completion routine.
|
|||
|
;
|
|||
|
;_______________________________________________________________________
|
|||
|
with PowerDispRec,ADBVars ; <T13>
|
|||
|
RequestDone move.l a0,-(sp) ; copy buffer address to A0 save area on stack
|
|||
|
beq.s @copyDone ; if no buffer, don't copy <1.8>
|
|||
|
move.b d2,(a0)+ ; copy length byte to form pascal string
|
|||
|
beq.s @copyDone ; if no data, don't copy
|
|||
|
|
|||
|
subq.w #1,d2 ; adjust count for dbra loop
|
|||
|
@copyLoop move.b (a2)+,(a0)+ ; copy a byte at a time
|
|||
|
dbra d2,@copyLoop ; loop for all bytes
|
|||
|
|
|||
|
@copyDone move.l d3,-(sp) ; copy command byte to D0 save area on stack
|
|||
|
|
|||
|
bsr.w RunADBRequest ; acknowledge the data, resume ADB operations
|
|||
|
|
|||
|
TestFor SupportsIdle
|
|||
|
BEQ.S @notsupported
|
|||
|
_IdleUpdate ; this is activity, stay at full speed
|
|||
|
@notsupported
|
|||
|
|
|||
|
movem.l (sp)+,d0/a0/a1/a2 ; setup cmd, buffer, handler, data
|
|||
|
; (13).start
|
|||
|
TestFor SupportsIdle
|
|||
|
beq.s @continue
|
|||
|
move.l d0,-(sp) ; save d0 temporarily on the stack <t10> ag
|
|||
|
move.l #((UsrActivity<<16)|\ ; set for user activity <K2>
|
|||
|
(IdleUpdateDisp<<0)),d0 ; idle update selector <K2>
|
|||
|
_PowerDispatch ; call power manager
|
|||
|
move.l (sp)+,d0 ; restore d0 <t10> ag
|
|||
|
@continue
|
|||
|
move.l a1,d1 ; test to see if handler address is valid
|
|||
|
beq.s @noHandler ; if not, don't call it
|
|||
|
|
|||
|
BTST #fDBInit,FDBFlag(A3) ; is ADB initialization in progress?
|
|||
|
BNE.S @JustDoIt ; -> yes, calling the handler now is allowed
|
|||
|
|
|||
|
; jump thru the ProductInfo table to check if a keyswitch is in the secure position <H4>
|
|||
|
|
|||
|
MOVEA.L UnivInfoPtr,A1 ; point to the ProductInfo table <H4>
|
|||
|
ADDA.L ProductInfo.ADBDebugUtilPtr(A1),A1 ; and get the address of its ADB table <H4>
|
|||
|
MOVE.L 4*adbKeySwSecure(A1),D2 ; get the offset to the keyswitch code <H4>
|
|||
|
BEQ.S @JustDoIt ; -> no keyswitch check, so just call the handler <H4>
|
|||
|
MOVEM.L D0/D1/A0/A2,-(SP) ; <H4>
|
|||
|
ADDA.L D2,A1 ; calculate the routine's address <H4>
|
|||
|
JSR (A1) ; and call it <H4>
|
|||
|
MOVEM.L (SP)+,D0/D1/A0/A2 ; <H4>
|
|||
|
BEQ.S @noHandler ; -> the keyswitch is secure, so don't call the handler
|
|||
|
|
|||
|
@JustDoIt MOVEA.L D1,A1 ; get the handler's address <H4>
|
|||
|
jsr (a1) ; call the handler
|
|||
|
|
|||
|
|
|||
|
@noHandler movea.l (sp),sp ; deallocate the buffer (if implicit cmd)
|
|||
|
rts ; return from the interrupt <T5>
|
|||
|
endwith ; (13).end
|
|||
|
|
|||
|
|
|||
|
Title 'KbdADB - ADB Manager - Initialization'
|
|||
|
;______________________________________________________________________
|
|||
|
;
|
|||
|
; ADBReInit - ReInitialize the Front Desk Bus
|
|||
|
;
|
|||
|
;______________________________________________________________________
|
|||
|
|
|||
|
ADBReinit MOVE.L JADBProc,A0 ; get hook to processing routine
|
|||
|
moveq.l #0,D0 ; set it as pre-processing routine
|
|||
|
JSR (A0) ; call the routine
|
|||
|
|
|||
|
MoveM.L D0-D4/A0-A3,-(SP)
|
|||
|
Move.L ADBBase,A3 ; A3 get local data address
|
|||
|
BSR ReInit
|
|||
|
BSR InitADBDrvr
|
|||
|
MoveM.L (SP)+,D0-D4/A0-A3 ; restore registers
|
|||
|
|
|||
|
Move.L JADBProc,A0 ; get hook to processing routine
|
|||
|
MoveQ #1,D0 ; set it as post-processing routine
|
|||
|
JSR (A0) ; call the routine
|
|||
|
RTS ; done
|
|||
|
|
|||
|
|
|||
|
|
|||
|
;______________________________________________________________________
|
|||
|
; Stack frame equates for InitADBDrvr and ADBProc
|
|||
|
|
|||
|
iADBAddr EQU -2
|
|||
|
iDataAddr EQU iADBAddr-4
|
|||
|
iCRAddr EQU iDataAddr-4
|
|||
|
iOrigAddr EQU iCRAddr-1
|
|||
|
iDeviceTy EQU iOrigAddr-1
|
|||
|
iPBlock EQU iDeviceTy
|
|||
|
iSPBlock EQU iCRAddr
|
|||
|
iLocalData EQU iDeviceTy
|
|||
|
|
|||
|
|
|||
|
;______________________________________________________________________
|
|||
|
;
|
|||
|
; ADBProc - this routine lives in the JADBProc vector and is called
|
|||
|
; by ADBReInit before and after initialization
|
|||
|
;
|
|||
|
;______________________________________________________________________
|
|||
|
|
|||
|
ADBProc
|
|||
|
; D0 is 0 if pre-processing, non-0 if post-processing.
|
|||
|
; In addition to the standard pascal calling conventions.
|
|||
|
|
|||
|
TST.L D0 ; 0 = pre-processing
|
|||
|
BNE.S PostInit ; Skip if not
|
|||
|
|
|||
|
; PreInit is called just before the bus is initialized. It de-allocates the memory used by the driver.
|
|||
|
@PreInit
|
|||
|
BSR.L CrsrDevReInit ; Remove cursor devices <H6>
|
|||
|
_CountADBs ; Get the number of ADB devices
|
|||
|
MOVE.W D0, D2 ; Save it in D2
|
|||
|
BEQ.S @DoneKRemove ; Skip if none
|
|||
|
LINK A6, #iLocalData ; Make a stack frame
|
|||
|
MOVEQ #kbdAddr, D1 ; We are looking for keyboards
|
|||
|
@KRemoveLoop
|
|||
|
LEA iPBlock(A6), A0 ; A0 is parameter block
|
|||
|
MOVE.W D2, D0
|
|||
|
_GetIndADB ; Get a device entry
|
|||
|
BMI.S @NextRec ; Skip if not valid
|
|||
|
CMP.B iOrigAddr(A6), D1 ; Keyboard?
|
|||
|
BNE.S @NextRec ; Skip if not
|
|||
|
|
|||
|
MOVE.L iDataAddr(A6), A1 ; Save the data address pointer
|
|||
|
CLR.L iDataAddr(A6) ; Clear it out, so the keyboard won't trash memory
|
|||
|
LEA iSPBlock(A6), A0
|
|||
|
_SetADBInfo ; D0 already contains the ADB Address
|
|||
|
|
|||
|
MOVE.L A1, A0 ; Get the data address pointer
|
|||
|
_DisposPtr ; Throw away the block
|
|||
|
|
|||
|
@NextRec
|
|||
|
SUBQ.W #1, D2
|
|||
|
BGT.S @KRemoveLoop
|
|||
|
UNLK A6
|
|||
|
|
|||
|
@DoneKRemove
|
|||
|
RTS
|
|||
|
|
|||
|
;______________________________________________________________________
|
|||
|
; ADBReInit causes ADB keyboards to be reset to use KCHR 0. It can be called
|
|||
|
; after booting - for example, on the Portable at wakeup if devices are
|
|||
|
; connected to the external ADB port. This causes problems for international
|
|||
|
; systems, which are normally using other KCHRs. On the non-Roman systems, users
|
|||
|
; may also frequently switch back and forth between various KCHRs. Fortunately,
|
|||
|
; a pointer to the current KCHR is kept in ExpandMem. This patch (actually, an
|
|||
|
; ADBProc) gets the current KCHR pointer from ExpandMem and stuffs it into the
|
|||
|
; keyboard driver data structures for all connected keyboards. <SM3> rb
|
|||
|
; Do this only as a post-procedure. Verified offsets with equates in ScriptPriv.a <SM3> rb
|
|||
|
;______________________________________________________________________
|
|||
|
|
|||
|
PostInit ; <SM3> rb
|
|||
|
WITH ExpandMemRec,KybdDriverData ; <SM3> rb
|
|||
|
|
|||
|
_CountADBs ; Get the number of ADB devices
|
|||
|
MOVE.W D0, D2 ; Save it in D2
|
|||
|
BEQ.S @DoneKRemove ; Skip if none
|
|||
|
LINK A6, #iLocalData ; Make a stack frame
|
|||
|
MOVEQ #kbdAddr, D1 ; We are looking for keyboards
|
|||
|
MOVE.L D4,-(SP) ; save a working register <SM3> rb
|
|||
|
MOVE.L ExpandMem,A0 ; get the Expanded memory in a0 <SM3> rb
|
|||
|
MOVE.L emKeyCache(A0),D4 ; save it in D4 <SM3> rb
|
|||
|
@KRemoveLoop
|
|||
|
LEA iPBlock(A6), A0 ; A0 is parameter block
|
|||
|
MOVE.W D2, D0
|
|||
|
_GetIndADB ; Get a device entry
|
|||
|
BMI.S @NextRec ; Skip if not valid
|
|||
|
CMP.B iOrigAddr(A6), D1 ; Keyboard?
|
|||
|
BNE.S @NextRec ; Skip if not
|
|||
|
|
|||
|
MOVE.L iDataAddr(A6), A1 ; Save the data address pointer
|
|||
|
CLR.L KybdDriverData.deadKey(A1) ; clear the dead key state <SM3> rb
|
|||
|
MOVE.L D4,KybdDriverData.KCHRPtr(A1) ; set KCHR pointer <SM3> rb
|
|||
|
|
|||
|
@NextRec
|
|||
|
SUBQ.W #1, D2
|
|||
|
BGT.S @KRemoveLoop
|
|||
|
MOVE.L (SP)+,D4 ; restore the working register <SM3> rb
|
|||
|
UNLK A6
|
|||
|
@DoneKRemove
|
|||
|
RTS
|
|||
|
|
|||
|
ENDWITH ; <SM3> rb
|
|||
|
;______________________________________________________________________
|
|||
|
;
|
|||
|
; InitADBDrvr - this routine bring in all appropriate 'ADBS' resources and
|
|||
|
; execute the initialization routines.
|
|||
|
;
|
|||
|
;______________________________________________________________________
|
|||
|
|
|||
|
InitADBDrvr _CountADBs ; get the number of valid ADB entries
|
|||
|
Move D0,D3 ; save it in D3
|
|||
|
BEQ.S DoneSrv ; If none, nothing to do
|
|||
|
MoveQ #1,D4 ; start at first entry
|
|||
|
Link A6,#iLocalData ; reserve stack frame
|
|||
|
FSrvLoop
|
|||
|
Lea iPBlock(A6),A0 ; A0 points param block
|
|||
|
Move D4,D0 ; index goes in D0
|
|||
|
_GetIndADB ; get a record
|
|||
|
Move.B D0,iADBAddr(A6) ; save the ADB Address
|
|||
|
BMI.S NextRec ; skip if it's not valid
|
|||
|
|
|||
|
SubQ.L #4,SP ; make room from result
|
|||
|
Move.L #'ADBS',-(SP) ; ResType = ADBS
|
|||
|
Clr.W -(SP) ; clear it out since OrigAddr is byte
|
|||
|
Move.B iOrigAddr(A6),1(SP) ; Move OrigAddr on the stack
|
|||
|
_GetResource
|
|||
|
|
|||
|
Move.L (SP),D1 ; get the handle
|
|||
|
BNE.S @1 ; branch, if good handle
|
|||
|
AddQ #4,SP ; clear off the handle
|
|||
|
Bra.S NextRec ; go to next record
|
|||
|
@1
|
|||
|
_DetachResource ; detach it
|
|||
|
|
|||
|
Move.L D1,A0 ; put handle in A0
|
|||
|
Move.L (A0),D0 ; dereference handle
|
|||
|
_StripAddress ; make it a 24-bit address
|
|||
|
Move.L D0,A0 ; put it in A0
|
|||
|
Move.B iADBAddr(A6),D0 ; put ADB Address in D0
|
|||
|
Move.B iDeviceTy(A6),D1 ; put device type in D1
|
|||
|
JSR (A0) ; execute the service routine
|
|||
|
NextRec
|
|||
|
AddQ #1,D4 ; increment the index
|
|||
|
Cmp.W D4,D3 ; are we done yet?
|
|||
|
BGE.S FSrvLoop ; if not, go around
|
|||
|
|
|||
|
UNLK A6
|
|||
|
DoneSrv
|
|||
|
RTS ; done
|
|||
|
|
|||
|
|
|||
|
;_______________________________________________________________________
|
|||
|
;
|
|||
|
; InitADB - Initialize state variables
|
|||
|
;
|
|||
|
;_______________________________________________________________________
|
|||
|
|
|||
|
with ADBVars,ADBDeviceEntry
|
|||
|
IMPORT KeyHook ; <SM8> rb
|
|||
|
|
|||
|
InitADB MOVE.L #FDBDSize,D0 ; get local data area length
|
|||
|
_NewPtr ,SYS,CLEAR ; allocate space on heap and clear
|
|||
|
movea.l a0,a3 ; ADBBase is always in A3 by convention
|
|||
|
MOVE.L A3,ADBBase ; save ptr to it
|
|||
|
|
|||
|
Lea ADBProc,A0 ; Get the ADBProc
|
|||
|
Move.L A0,JADBProc ; install it into JAdbProc vector
|
|||
|
CLR.B KbdType ; assume we have no keyboard to start
|
|||
|
BSR RSetKMap ; reset the keyboard map, etc.
|
|||
|
LEA FDBTask,A0 ; setup the FDB VBL task
|
|||
|
MOVE.L A0,JKybdTask ; lomem vector
|
|||
|
|
|||
|
; jump thru the ProductInfo table to call the hardware-dependent initialization code
|
|||
|
|
|||
|
MOVEA.L UnivInfoPtr,A0 ; point to the ProductInfo table <H4>
|
|||
|
ADDA.L ProductInfo.ADBDebugUtilPtr(A0),A0 ; and get the address of its ADB table <H4>
|
|||
|
MOVE.L 4*adbInitProc(A0),D0; get the offset to the InitADB entry code <H4>
|
|||
|
BEQ.S ReInit ; -> this function is not supported <H4>
|
|||
|
ADDA.L D0,A0 ; calculate the routine's address <H4>
|
|||
|
JSR (A0) ; and call it <H4>
|
|||
|
|
|||
|
ReInit ori.w #HiIntMask,sr ; mask out interrupts
|
|||
|
MOVEQ #((endCQ/4)-1),D0 ; n entries
|
|||
|
Move.L A3,A0 ; clear out device table and command queue
|
|||
|
@ClrLoop Clr.L (A0)+
|
|||
|
DBRA D0,@ClrLoop ; clear next entry
|
|||
|
|
|||
|
move.b #(1<<FDBInit)|\
|
|||
|
(1<<FDBQEmpty),FDBFlag(A3) ; initialize the flags
|
|||
|
clr.b FDBAuFlag(A3)
|
|||
|
Lea StartCQ(A3),A0
|
|||
|
Move.L A0,FQBegPtr(A3) ; initialize command queue pointer
|
|||
|
Move.L A0,FQHeadPtr(A3) ; initialize command queue pointer
|
|||
|
Move.L A0,FQEntPtr(A3) ; initialize command queue pointer
|
|||
|
Lea EndCQ(A3),A0
|
|||
|
Move.L A0,FQEndPtr(A3) ; initialize command queue end pointer
|
|||
|
|
|||
|
BSR.S InitDevT ; go initialize the device table
|
|||
|
ANDI #$F8FF,SR ; clear Interrupt mask
|
|||
|
|
|||
|
@1 BTST #FDBInit,FDBFlag(A3); done with initialization?
|
|||
|
BNE.S @1 ; no, keep in loop
|
|||
|
BSR DefaultDev ; setup mouse & keyboard as default <t6><H3>
|
|||
|
BSR KbdInstall ; finally, install keyboard information <t6><H3>
|
|||
|
|
|||
|
pea KeyHook ; get Key Hook entry point. <SM8> rb
|
|||
|
move.l (sp),Key1Trans ; install the Key1Trans hook. <SM8> rb
|
|||
|
move.l (sp)+,Key2Trans ; install the Key2Trans hook. <SM8> rb
|
|||
|
|
|||
|
BRA flushkbds ; after all is setup, flush to get current keys <H5>
|
|||
|
|
|||
|
|
|||
|
;_______________________________________________________________________
|
|||
|
;
|
|||
|
; InitDevT - Initialize the Device Table
|
|||
|
;
|
|||
|
; NOTE: everything after BusReset below is part of an ADB completion
|
|||
|
; routine, and thus is run at interrupt level 1. No calls
|
|||
|
; that could cause memory to move (i.e., GetResource, Andy).
|
|||
|
;_______________________________________________________________________
|
|||
|
|
|||
|
InitDevT bsr BusReset ; reset all devices on the bus
|
|||
|
|
|||
|
clr.b DevTOffset(a3) ; initialize the table offset
|
|||
|
clr.w HasDev(a3) ; initialize the device map
|
|||
|
moveq.l #0,d0 ; start with address zero
|
|||
|
@PollNext move.b d0,InitAddr(a3) ; save device address
|
|||
|
bsr TalkR3 ; issue a Talk R3 command (asynchronously)
|
|||
|
move.b InitAddr(a3),d0 ; restore poll address
|
|||
|
tst.b (a0)+ ; test reply length, see if device returned data
|
|||
|
beq.s @NoDevice ; no, nothing to install
|
|||
|
|
|||
|
; there is a response from the device in the address, so update the
|
|||
|
; device table according to the device
|
|||
|
|
|||
|
moveq.l #0,d1 ; zero extend for indexing
|
|||
|
move.b DevTOffset(a3),d1 ; get offset to devicetable
|
|||
|
move.b 1(a0),FDBDevTy(a3,d1.w) ; copy device handler ID into table
|
|||
|
move.b d0,FDBOAddr(a3,d1.w); save device address
|
|||
|
move.b d0,FDBAddr(a3,d1.w) ; save device address
|
|||
|
|
|||
|
cmpi.b #KbdAddr,d0 ; is it a keyboard type device?
|
|||
|
bne.s @notKbd ; no, branch
|
|||
|
lea KbdDrvr,a0 ; get address of keyboard driver
|
|||
|
move.l a0,FDBCRA(a3,d1.w) ; save as completion routine address
|
|||
|
@notKbd
|
|||
|
|
|||
|
; ...used to setup mouse driver here, but that's now done in CrsrDev.a...
|
|||
|
|
|||
|
addi.b #FRecSize,d1 ; advance offset
|
|||
|
move.b d1,DevTOffset(a3) ; save device table offset
|
|||
|
move.w HasDev(a3),d2 ; get value in HasDev
|
|||
|
bset.l d0,d2 ; remember which address has device
|
|||
|
move.w d2,HasDev(A3) ; save it
|
|||
|
@NoDevice
|
|||
|
addq.b #1,d0 ; advance device address
|
|||
|
cmpi.b #NumFDBAdr,d0 ; has it polled all addresses yet?
|
|||
|
bne.s @PollNext ; no, go to poll next device
|
|||
|
|
|||
|
; ChgAddr - check the device address to identify multiple devices on
|
|||
|
; the same address
|
|||
|
|
|||
|
move.b #MoveTime+1,FDBMvCnt(A3); initialize move retry count
|
|||
|
move.w HasDev(a3),DevMap(a3) ; initialize device map
|
|||
|
Bne.S movLoop ; branch, if there is no device
|
|||
|
ChgExit
|
|||
|
;
|
|||
|
; Initialization done, now setup default device and keyboard before starting auto polling
|
|||
|
;
|
|||
|
BClr #FDBInit,FDBFlag(A3); done with initialization
|
|||
|
JSR RunADBRequest ; start auto poll for the mouse
|
|||
|
RTS
|
|||
|
|
|||
|
movLoop
|
|||
|
ST InitAddr(A3) ; clear poll address
|
|||
|
subq.b #1,FDBMvCnt(A3) ; has it loop 50 times yet?
|
|||
|
Beq.S ChgExit ; yes, exit
|
|||
|
|
|||
|
; ChgNext is another entry point for this routine
|
|||
|
ChgNext
|
|||
|
AddQ.B #1,InitAddr(A3) ; advance poll address
|
|||
|
BSR GNextAddr ; get next address to change
|
|||
|
Bmi.S MovLoop ; exit when end of address range
|
|||
|
|
|||
|
BSR GEmptyAddr ; get empty address space, D0 gets address
|
|||
|
BMI.S ChgExit ; no more empty address space, exit
|
|||
|
; D0 has an address that can be moved to
|
|||
|
Move.B D0,NewAddr(A3) ; save address in NewAddr
|
|||
|
Move.B D0,D1 ; D1 get new address to change to
|
|||
|
Move.B InitAddr(A3),D0 ; D0 get address to issue command
|
|||
|
BSR ListenR3 ; issue a Listen R3 command
|
|||
|
|
|||
|
; MovAddr - a Listen R3 command has just been issued, the device is moved to
|
|||
|
; a new address. Now issue a Talk R3 to the old address. A timeout would
|
|||
|
; indicate no more device in the old address, we will move the device back
|
|||
|
; to the old address by issuing a Listen R3.
|
|||
|
|
|||
|
Move.B InitAddr(A3),D0 ; get address
|
|||
|
BSR.s TalkR3 ; issue a Talk R3 command <1.6>
|
|||
|
|
|||
|
; MovBack - A Talk R3 has just been issued, a timeout in S1 indicates no
|
|||
|
; more device in original address, we want to move the device back to
|
|||
|
; original address.
|
|||
|
|
|||
|
tst.b (a0) ; did the device return data
|
|||
|
beq.S @1 ; no, branch
|
|||
|
; no timeout indication,
|
|||
|
BSR.S CopyEntry ; copy entry into device table
|
|||
|
Move.B FDBByte1(A3),FDBDevTy(A3,D1.W) ; get new handle ID into table
|
|||
|
BRA.S ChgNext ; go to change next device
|
|||
|
; there is timeout indication
|
|||
|
@1
|
|||
|
Move.B InitAddr(A3),D1 ; get address to change back to
|
|||
|
Move.B NewAddr(A3),D0 ; get address to talk to
|
|||
|
bsr.s ListenR3 ; send a listen R3 command <1.6>
|
|||
|
|
|||
|
; CKNewAdr - check the new address by issuing a Talk R3, to see if
|
|||
|
; there is still any device left. If yes, add entry into device
|
|||
|
; table, but if not, just go to change next device address
|
|||
|
|
|||
|
Move.B NewAddr(A3),D0 ; get address
|
|||
|
BSR.S TalkR3 ; issue a talk R3 <1.6>
|
|||
|
|
|||
|
; AddEntry - a Talk R3 command has just been issed to the new address,
|
|||
|
; if there is no timeout in S1, one or more device is still in that
|
|||
|
; address, so, add device to device table. If there is timeout, no
|
|||
|
; device is in that address, so, just go to change next device address
|
|||
|
|
|||
|
tst.b (a0) ; did the device return data
|
|||
|
Beq.S ExitEntry ; no, branch
|
|||
|
; no timeout indication, thus, add entry of the new address into the
|
|||
|
; device table.
|
|||
|
BSR.S CopyEntry ; copy entry into device table
|
|||
|
Move.B FDBByte1(A3),FDBDevTy-FRecSize(A3,D2.W) ; get new handle ID into table
|
|||
|
ExitEntry
|
|||
|
bra.s ChgNext ; go to change next device
|
|||
|
|
|||
|
|
|||
|
;_______________________________________________________________________
|
|||
|
;
|
|||
|
; CopyEntry - copy the device entry from the original address to the
|
|||
|
; new address, a Talk R3 had just been issued
|
|||
|
;
|
|||
|
; Called by: MoveBack and AddEntry
|
|||
|
; on exit: D1 - has record address of old device
|
|||
|
; D2 - points to new table entry
|
|||
|
;_______________________________________________________________________
|
|||
|
|
|||
|
CopyEntry
|
|||
|
MoveQ #0,D0
|
|||
|
MoveQ #0,D1
|
|||
|
Move.B NewAddr(A3),D0 ; get new address
|
|||
|
Move.W DevMap(A3),D1 ; get device map
|
|||
|
BSet D0,D1 ; set device address
|
|||
|
Move.W D1,DevMap(A3) ; update device map
|
|||
|
|
|||
|
MoveQ #0,D1 ; set D1 as offset to table
|
|||
|
Move.B InitAddr(A3),D0 ; D0 get address
|
|||
|
@1
|
|||
|
CMP.B FDBADDR(A3,D1.W),D0 ; same address?
|
|||
|
BEQ.S @2 ; yes, branch
|
|||
|
Add #FRecSize,D1 ; advance
|
|||
|
BRA.S @1
|
|||
|
@2
|
|||
|
MoveQ #0,D2
|
|||
|
Move.B DevToffset(A3),D2 ; set D2 to new entry offset
|
|||
|
Move.L FDBDevTy(A3,D1.W),\ ; get first 4 byte
|
|||
|
FDBDevTy(A3,D2.W) ; save it
|
|||
|
Move.L FDBCRA(A3,D1.W),\ ; get completion routine address
|
|||
|
FDBCRA(A3,D2.W) ; save it
|
|||
|
Move.B NewAddr(A3),\ ; get new address
|
|||
|
FDBAddr(A3,D2.W) ; update address
|
|||
|
Add #FRecSize,D2 ; advance device table offset
|
|||
|
Move.B D2,DevToffset(A3) ; save it
|
|||
|
RTS
|
|||
|
|
|||
|
|
|||
|
;_______________________________________________________________________
|
|||
|
;
|
|||
|
; BusReset - issue a Reset command
|
|||
|
;
|
|||
|
; On entry, (SP) has completion routine address <1.6>
|
|||
|
;
|
|||
|
;_______________________________________________________________________
|
|||
|
|
|||
|
BusReset moveq.l #0,d0 ; address zero
|
|||
|
moveq.l #resetCmd,d1 ; reset command
|
|||
|
moveq.l #0,d2 ; no data to send
|
|||
|
bra.s MakeAsyncRequest ; start the command asynchronously
|
|||
|
|
|||
|
|
|||
|
;_______________________________________________________________________
|
|||
|
;
|
|||
|
; Talk R3 - issue a Talk R3 command
|
|||
|
;
|
|||
|
; On entry, D0 has device address
|
|||
|
; (SP) has completion routine address <1.6>
|
|||
|
;
|
|||
|
;_______________________________________________________________________
|
|||
|
|
|||
|
TalkR3 moveq.l #talkCmd+3,d1 ; talk command, register 3
|
|||
|
moveq.l #0,d2 ; no data to send
|
|||
|
bra.s MakeAsyncRequest ; start the command asynchronously
|
|||
|
|
|||
|
|
|||
|
;_______________________________________________________________________
|
|||
|
;
|
|||
|
; ListenR3 - issue a listen R3 command
|
|||
|
;
|
|||
|
; On entry, D0 has device address to send the command
|
|||
|
; D1 has new device address to change to
|
|||
|
; (SP) has completion routine address <1.6>
|
|||
|
;
|
|||
|
;_______________________________________________________________________
|
|||
|
|
|||
|
ListenR3 move.b d1,FDBByte0(a3) ; set up new address for R3
|
|||
|
move.b #$FE,FDBByte1(a3) ; setup handle ID
|
|||
|
moveq.l #listenCmd+3,d1 ; listen command, register 3
|
|||
|
moveq.l #2,d2 ; 2 bytes of data to send
|
|||
|
|
|||
|
MakeAsyncRequest
|
|||
|
lsl.b #4,d0 ; shift address by 4 bits to correct position
|
|||
|
or.b d1,d0 ; insert the command and register number
|
|||
|
move.b d2,FDBCnt(a3) ; setup the send byte count
|
|||
|
pea FDBCnt(a3) ; push the buffer address
|
|||
|
movea.l sp,a0 ; setup param block pointer
|
|||
|
movea.l jADBop,a1 ; get address of _ADBop
|
|||
|
jsr (a1) ; start the request
|
|||
|
addq.w #8,sp ; pop buffer addr and return address
|
|||
|
rts ; return to callers caller
|
|||
|
|
|||
|
|
|||
|
;_______________________________________________________________________
|
|||
|
;
|
|||
|
; GNextAddr - get next address to change
|
|||
|
;
|
|||
|
;_______________________________________________________________________
|
|||
|
|
|||
|
GNextAddr MoveQ #0,D0
|
|||
|
MoveQ #0,D1
|
|||
|
Move.B InitAddr(A3),D0 ; get address
|
|||
|
Move.W DevMap(A3),D1 ; get device map
|
|||
|
@1
|
|||
|
BTst D0,D1 ; is there a device there?
|
|||
|
BNE.S @2 ; branch, if there is device
|
|||
|
AddQ #1,D0 ; advance to next address
|
|||
|
CMP #numFDBAdr,D0 ; end of address yet?
|
|||
|
BLT.S @1 ; no, branch
|
|||
|
MoveQ #-1,D0 ; return -1 if no more address
|
|||
|
RTS
|
|||
|
@2
|
|||
|
Move.B D0,InitAddr(A3) ; remember the address
|
|||
|
RTS
|
|||
|
|
|||
|
|
|||
|
;_______________________________________________________________________
|
|||
|
;
|
|||
|
; GEmptyAddr - get empty address space
|
|||
|
;
|
|||
|
; on return:
|
|||
|
; D0 = empty address or
|
|||
|
; -1 for no empty address
|
|||
|
;
|
|||
|
;_______________________________________________________________________
|
|||
|
|
|||
|
GEmptyAddr MoveQ #0,D1
|
|||
|
MoveQ #numFDBAdr-1,D0 ; start from last address
|
|||
|
Move.W DevMap(A3),D1 ; get device map
|
|||
|
@1 BTst D0,D1 ; is there a device there?
|
|||
|
DBEQ D0,@1 ; no, branch
|
|||
|
tst.w d0
|
|||
|
RTS ; return, D0 has empty address space
|
|||
|
|
|||
|
|
|||
|
;_______________________________________________________________________
|
|||
|
;
|
|||
|
; FDBTask - FDB VBL Task
|
|||
|
;
|
|||
|
;_______________________________________________________________________
|
|||
|
|
|||
|
FDBTask RTS ; just return for now
|
|||
|
endwith
|
|||
|
|
|||
|
; since we reset the keyboard, we better reset the map
|
|||
|
|
|||
|
RSetKMap LEA KeyMap,A0
|
|||
|
MOVEQ #8,D0
|
|||
|
@1 CLR.W (A0)+ ; zero key map, key pad map, and keylast
|
|||
|
DBRA D0,@1
|
|||
|
CLR.W HiKeyLast
|
|||
|
KbdDRTS RTS
|
|||
|
|
|||
|
|
|||
|
;______________________________________________________________________
|
|||
|
;
|
|||
|
; DefaultDev - check mouse and keyboard in the device table, if they
|
|||
|
; are not there, set them up as default device anyway.
|
|||
|
;
|
|||
|
;______________________________________________________________________
|
|||
|
|
|||
|
with ADBVars,ADBDeviceEntry,ADBOpBlock,ADBDataBlock
|
|||
|
DefaultDev
|
|||
|
MoveQ #kbdAddr,D0 ; first check keyboard
|
|||
|
Bsr.w FindFDBInfo ; look for keyboard
|
|||
|
TST.B D0 ; is it there?
|
|||
|
BEQ.S ChkMouse ; branch, keyboard is there
|
|||
|
Move.B #1,FDBDevTy(A1) ; assume handleID 1
|
|||
|
Move.B #kbdAddr,FDBOAddr(A1) ; set original address as 2
|
|||
|
Move.B #kbdAddr,FDBAddr(A1) ; set FDB address as 2
|
|||
|
Lea KbdDrvr,A0 ; get keyboard address
|
|||
|
Move.L A0,FDBCRA(A1) ; set completion routine address
|
|||
|
bset.b #kbdAddr,DevMap+1(a3) ; remember to poll it <1.9>
|
|||
|
ChkMouse moveq #1,d0 ; post processing <H6>
|
|||
|
bsr.l CrsrDevReInit ; allocate a crsrDevRec for each relative pointing device <H6>
|
|||
|
rts
|
|||
|
|
|||
|
|
|||
|
;______________________________________________________________________
|
|||
|
;
|
|||
|
; Routine: flushkbds
|
|||
|
; Arguments: none
|
|||
|
; Output: none
|
|||
|
; Function: this routine finds all kbd devices, and sends a flush command to them
|
|||
|
; Note:
|
|||
|
;______________________________________________________________________
|
|||
|
|
|||
|
flushkbds ; Flush all keyboards <H5>
|
|||
|
waitForKeys equ (4+4) ; add 100% margin
|
|||
|
@saved reg d0/d1/a0
|
|||
|
|
|||
|
movem.l @saved,-(sp)
|
|||
|
sub.l #dbBlkSize,sp ; make room for table info
|
|||
|
moveq.l #(1-1),d1 ; first device index -1
|
|||
|
@next addq.l #1,d1 ; next indexed device
|
|||
|
move.l sp,a0 ; a0 pointer to pb
|
|||
|
move.b d1,d0 ; get index number
|
|||
|
_GetIndADB ; get indexed info
|
|||
|
tst.b d0 ; check for valid id
|
|||
|
ble.s @done ;
|
|||
|
|
|||
|
@type cmp.b #kbdAddr,origADBAddr(a0); is this a keyboard
|
|||
|
bne.s @next ; not a keyboard, next device
|
|||
|
bsr.s sendFlush ; send a flush command to kbd
|
|||
|
bra.s @next ; next device
|
|||
|
|
|||
|
@done movea.l #waitForKeys,a0 ; wait for keys
|
|||
|
_Delay
|
|||
|
|
|||
|
add.l #dbBlkSize,sp ; release trap pb
|
|||
|
movem.l (sp)+,@saved ; restore registers
|
|||
|
rts
|
|||
|
|
|||
|
;______________________________________________________________________
|
|||
|
;
|
|||
|
; Routine: sendFlush
|
|||
|
; Arguments: d0.b adb id
|
|||
|
; Output: none
|
|||
|
; Function: this routine sends a "flush" command to the adb device at d0.b
|
|||
|
; Note:
|
|||
|
;______________________________________________________________________
|
|||
|
sendFlush ; send flush command to device <H5>
|
|||
|
flushcmd equ 1 ; flush command
|
|||
|
@savedReg reg d0/d1/a0
|
|||
|
|
|||
|
movem.l @savedReg,-(sp) ; save registers
|
|||
|
move.b d0,d1 ; save address in d1
|
|||
|
sub.l #(opBlkSize+2),sp ; create space (pb + completion word)
|
|||
|
|
|||
|
@retry move.b d1,d0 ; load address into d0
|
|||
|
asl.b #4,d0 ; move the address to the upper nibble
|
|||
|
ori.b #flushcmd,d0 ; complete the flush command
|
|||
|
|
|||
|
; load adbop pb
|
|||
|
clr.l dataBuffPtr(sp) ; no adb data to be sent
|
|||
|
lea CompleteFlush,a0 ; point 'opServiceRtPtr' to completion routine
|
|||
|
move.l a0,opServiceRtPtr(sp)
|
|||
|
lea opBlkSize(sp),a0 ; point 'opDataAreaPtr' to completion word
|
|||
|
move.l a0,opDataAreaPtr(sp)
|
|||
|
clr.w opBlkSize(sp) ; clear completion word
|
|||
|
move.l sp,a0 ; point a0 at pb
|
|||
|
|
|||
|
_ADBop ; send flush command
|
|||
|
tst.b d0 ; did it work ??
|
|||
|
bmi.s @retry ; if not retry
|
|||
|
|
|||
|
movea.l opDataAreaPtr(sp),a0 ; point a0 to the completion word
|
|||
|
@waitdone tst.w (a0) ; wait for completion
|
|||
|
beq.s @waitdone
|
|||
|
|
|||
|
add.l #(opBlkSize+2),sp ; release pb + completion word
|
|||
|
movem.l (sp)+,@savedReg ; restore registers
|
|||
|
rts
|
|||
|
|
|||
|
CompleteFlush
|
|||
|
move.w #1,(a2) ; set complete in result area
|
|||
|
rts
|
|||
|
|
|||
|
|
|||
|
Title 'KbdADB - ADB KeyBoard Driver'
|
|||
|
;______________________________________________________________________
|
|||
|
;
|
|||
|
; Routine: KbdDrvr
|
|||
|
; Arguments: D0.B ADB Command
|
|||
|
; A0 ADB Buffer address
|
|||
|
; A1 ADB Completion Routine Address (= KbdServ)
|
|||
|
; A2 ADB Data Address
|
|||
|
; Output: None
|
|||
|
; Function: Reads buffer and posts keyboard events as appropriate.
|
|||
|
; Side Effects: Trashes A0, A1, D0, D1, D2, D3
|
|||
|
;
|
|||
|
; Modification History:
|
|||
|
; 26 Jun 86 EMT Created
|
|||
|
; 15 Jul 86 EMT Updated to use KCHR resource
|
|||
|
; 21 Jul 86 EMT Complete rewrite - to use new _KeyTrans
|
|||
|
; 3 Oct 86 EMT Added LED bells & whistles
|
|||
|
;<A230/17Oct86> EMT D1 is no longer a parameter to this routine. Must get ADB Address from D0
|
|||
|
;______________________________________________________________________
|
|||
|
|
|||
|
; 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)
|
|||
|
|
|||
|
; KMAP offsets
|
|||
|
KMid EQU $00
|
|||
|
KMtype EQU $01
|
|||
|
KMvers EQU KMid+2
|
|||
|
KMstart EQU KMvers+2
|
|||
|
KMnumEx EQU KMstart+128
|
|||
|
KMstEx EQU KMnumEx+2
|
|||
|
|
|||
|
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 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.
|
|||
|
|
|||
|
Hammer
|
|||
|
MOVEM.L KeyBits(A2), D0-D2/A0
|
|||
|
MOVEM.L D0-D2/A0, KeyMap ; Hammer in the correct 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
|
|||
|
; Output: None
|
|||
|
; Function Posts the keyboard event as appropriate.
|
|||
|
; Side Effects: Trashes A0, D0, D1
|
|||
|
; Called From: KeyIn twice, (1 BSR, 1 fall-through)
|
|||
|
;
|
|||
|
; Modification History:
|
|||
|
; 25 Jun 86 EMT Created
|
|||
|
; 22 Jul 86 EMT Changed order of event data (FHRL -> HFRL)
|
|||
|
;<A230/17Oct86> EMT Clear the up/down bit in the event message
|
|||
|
;______________________________________________________________________
|
|||
|
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 ; And leave
|
|||
|
|
|||
|
; End KbdDrvr
|
|||
|
|
|||
|
;______________________________________________________________________
|
|||
|
;
|
|||
|
; FoundEx
|
|||
|
; An exception exists for this particular keystroke. Process it appropriately.
|
|||
|
;______________________________________________________________________
|
|||
|
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 ; Punt
|
|||
|
|
|||
|
; End FoundEx
|
|||
|
|
|||
|
;______________________________________________________________________
|
|||
|
;
|
|||
|
; Routine: KbdListen
|
|||
|
; Arguments: D0.B ADB Command
|
|||
|
; D1.L DeviceType, OrigAddr, ADBAddr, Unused (byte order)
|
|||
|
; A0 ADB Buffer Address
|
|||
|
; A1 ADB Completion Routine Address (= KbdListen)
|
|||
|
; A2 ADB Data Address
|
|||
|
; 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
|
|||
|
;
|
|||
|
; Modification history:
|
|||
|
; 3 Oct 86 EMT Created
|
|||
|
;______________________________________________________________________
|
|||
|
KbdListen
|
|||
|
MOVE.L A0, A1 ; Copy A0 into A1 so as to avoid trashing A2
|
|||
|
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 ADB Buffer Address
|
|||
|
; A1 ADB Completion Routine Address (= KbdListen)
|
|||
|
; A2 ADB Data Address
|
|||
|
; Output: None
|
|||
|
; Function: Marks the buffer pointed to by A0 as free.
|
|||
|
; Side Effects: None
|
|||
|
;
|
|||
|
; Modification history:
|
|||
|
; 3 Oct 86 EMT Created
|
|||
|
;______________________________________________________________________
|
|||
|
KbdBufFree
|
|||
|
CLR.B -1(A0)
|
|||
|
RTS
|
|||
|
; End KbdBufFree
|
|||
|
|
|||
|
;______________________________________________________________________
|
|||
|
;
|
|||
|
; KbdInstall - allocate memory for keyboard information and put in ADB record,
|
|||
|
; loading resources as necessary.
|
|||
|
;
|
|||
|
;______________________________________________________________________
|
|||
|
|
|||
|
with ADBDeviceEntry
|
|||
|
KbdInstall
|
|||
|
MOVEQ #numFDBAdr, D1 ; Number of table entries
|
|||
|
MOVE.L ADBBase, A1 ; Put Base in A1
|
|||
|
BRA.S FirstInstall ; Skip past record increment
|
|||
|
InstallLoop
|
|||
|
ADD #FRecSize, A1 ; Get to next record
|
|||
|
FirstInstall
|
|||
|
MOVEQ #kbdAddr, D0 ; We're looking for keyboards
|
|||
|
CMP.B FDBOAddr(A1), D0 ; Is this one?
|
|||
|
BNE.S NotKbd ; Nope, skip around
|
|||
|
|
|||
|
MOVEQ #KbdDSize, D0 ; Amount of space needed for keyboard data
|
|||
|
_NewPtr ,SYS,CLEAR ; get a pointer
|
|||
|
MOVE.L A0, A2 ; Save it in A2
|
|||
|
|
|||
|
MOVE.B #KBufCount, KNumBufs(A2)
|
|||
|
|
|||
|
SUBQ.L #4, SP ; Make room for result
|
|||
|
MOVE.L #'KCHR', -(SP) ; ResType = KCHR
|
|||
|
CLR.W -(SP) ; theID = 0
|
|||
|
MOVE.W #mapTrue, RomMapInsert ; Load it from ROM
|
|||
|
_GetResource
|
|||
|
MOVE.L (SP)+, D0 ; Get the handle
|
|||
|
BEQ.S NotKbd ; Skip if NIL
|
|||
|
MOVE.L D0, A0
|
|||
|
MOVE.L (A0), KCHRPtr(A2) ; Dereference and put away
|
|||
|
|
|||
|
SUBQ.L #4, SP ; Make room for result
|
|||
|
MOVE.L #'KMAP', -(SP) ; ResType = KCHR
|
|||
|
CLR.W -(SP) ; theID = 0
|
|||
|
MOVE.W #mapTrue, RomMapInsert ; Load it from ROM
|
|||
|
_GetResource
|
|||
|
MOVE.L (SP)+, D0 ; Get the handle
|
|||
|
BEQ.S NotKbd ; Skip if NIL
|
|||
|
MOVE.L D0, A0
|
|||
|
MOVE.L (A0), KMAPPtr(A2) ; Dereference and put away
|
|||
|
|
|||
|
MOVE.L A2, FDBOpData(A1) ; Save pointer in ADB record
|
|||
|
MOVE.B FDBDevTy(A1), KbdType ; Save the keyboard type
|
|||
|
MOVE.B FDBAddr(A1), KbdLast ; Save the ADB address
|
|||
|
|
|||
|
NotKbd
|
|||
|
DBRA D1, InstallLoop ; Loop until no more
|
|||
|
RTS
|
|||
|
endwith
|
|||
|
|
|||
|
; End KbdInstall
|
|||
|
Title 'KbdADB - KeyTrans'
|
|||
|
;______________________________________________________________________
|
|||
|
;
|
|||
|
; NuMac Keyboard Mapping Proc
|
|||
|
;
|
|||
|
; FUNCTION KeyTrans(transData: Ptr; keycode: Integer; VAR state: LONGINT): LONGINT;
|
|||
|
;
|
|||
|
; Translates a keycode to ASCII.
|
|||
|
; transData is a pointer to a KCHR resource for the use of KeyTrans.
|
|||
|
; keycode is an integer which contains in bits:
|
|||
|
; 0-6 "virtual" keycode
|
|||
|
; 7 1 = key up
|
|||
|
; 8-15 modifier flags similar to event manager.
|
|||
|
; state is an internal code used by KeyTrans, which should be 0 on first call.
|
|||
|
; The LONGINT returned is actually two words which are to be posted as events.
|
|||
|
; $0000 should not be posted; if both words contain values, the high word
|
|||
|
; should be posted first.
|
|||
|
;
|
|||
|
;______________________________________________________________________
|
|||
|
;------------------------------------------------------------------------------
|
|||
|
; The first part of KeyTrans is a patch rolled in from KeyHack.a <03/05/89 pke>
|
|||
|
;
|
|||
|
; Introduction:
|
|||
|
; This is a special hack to make the various international keyboard
|
|||
|
; layouts work on all of the keyboard models. We intercept calls to
|
|||
|
; the KeyTrans trap and perform some special mapping of the virtual key
|
|||
|
; codes, based on an optional resource that can accompany each KCHR.
|
|||
|
;
|
|||
|
; If we currently have an international keyboard re-mapping table (itlk resource,
|
|||
|
; only present on some international systems), perform any re-mapping and then
|
|||
|
; enter the original KeyTrans code. The re-mapping table consists of an integer
|
|||
|
; count followed by a set of items with the following format:
|
|||
|
;
|
|||
|
; | old | old | old | care | care | new | new |
|
|||
|
; | keyboard | modifiers | key | modifiers | code | modifiers | key |
|
|||
|
; | type | | code | | | | code |
|
|||
|
;
|
|||
|
; This code compares the current keyboard type, key code, and modifiers against
|
|||
|
; each entry. If there is a match, it substitutes the new modifiers and key
|
|||
|
; code before calling the original KeyTrans routine. Note that the current
|
|||
|
; modifiers and key code are masked with the care bits in the entry before the
|
|||
|
; comparison is made. When a comparison succeeds, the new modifiers and key
|
|||
|
; code are masked with the care bits and the current modifiers and key code
|
|||
|
; are masked with the complement of the care bits. The logical or of these
|
|||
|
; two products is the final result. This allows for a more compact table when
|
|||
|
; several characters on one key are mapped together to a different key.
|
|||
|
;
|
|||
|
; The keyboard types are:
|
|||
|
; $0001 Standard ADB (and Apple II GS)
|
|||
|
; $0002 Extended ADB
|
|||
|
; $0004 ISO Standard ADB
|
|||
|
; $0005? Zoots (European ergonomic)
|
|||
|
; $0006? Esprit std
|
|||
|
; $0007? Esprit ISO
|
|||
|
; $000b Macintosh Plus
|
|||
|
;
|
|||
|
; The modifier bits are:
|
|||
|
; 7 -> (Right Control)
|
|||
|
; 6 -> (Right Option)
|
|||
|
; 5 -> (Right Shift)
|
|||
|
; 4 -> Control(Left Control)
|
|||
|
; 3 -> Option (Left Option)
|
|||
|
; 2 -> Caps Lock
|
|||
|
; 1 -> Shift (Left Shift)
|
|||
|
; 0 -> Command
|
|||
|
;
|
|||
|
; register usage:
|
|||
|
; d5 -> loop counter
|
|||
|
; d4 -> current keyboard type, key code, and modifiers
|
|||
|
; d3 -> masked current keyboard type, key code, and modifiers
|
|||
|
; d2 -> new key code and modifiers for re-mapping
|
|||
|
; d1 -> care masks for key code and modifiers
|
|||
|
; d0 -> old key code and modifiers for comparison
|
|||
|
;------------------------------------------------------------------------------
|
|||
|
|
|||
|
vers EQU $00
|
|||
|
tInx EQU vers+2
|
|||
|
tCnt EQU tInx+$100
|
|||
|
tBgn EQU tCnt+2
|
|||
|
|
|||
|
ktFrame record {a6link},decr
|
|||
|
result ds.l 1 ; resulting ascii codes
|
|||
|
kchrTable ds.l 1 ; KCHR table to use
|
|||
|
codeMods ds.w 1 ; virtual key code, modifiers
|
|||
|
deadState ds.l 1 ; dead key state pointer
|
|||
|
return ds.l 1 ; return address
|
|||
|
a6link ds.l 1 ; old link pointer
|
|||
|
ktLocals equ * ; size of locals
|
|||
|
kchrTableNoLink equ kchrTable-return ; kchrTable offset before link <SM10> rb
|
|||
|
endr
|
|||
|
|
|||
|
KeyTrans
|
|||
|
;------------------------------------------------------------------------------
|
|||
|
with ktFrame,SMgrRecord
|
|||
|
; if SMgr not initialized or no itlk, skip
|
|||
|
GetSMgrCore a0 ; get SMgrRecord pointer
|
|||
|
cmpa.l #-1,a0 ; SMgr initialized?
|
|||
|
beq.s @noTable ; no -> skip
|
|||
|
move.l smgrCurITLK(a0),d0 ; have an itlk currently?
|
|||
|
beq.s @noTable ; no -> skip
|
|||
|
|
|||
|
; bail if KCHR pointer is not same as in ExpandMem <SM10> rb
|
|||
|
with ExpandMemRec ; <SM10> rb
|
|||
|
move.l ExpandMem,a1 ; <SM10> rb
|
|||
|
move.l emKeyCache(a1),d1 ; Get KCHR pointer in ExpandMem <SM10> rb
|
|||
|
cmp.l kchrTableNoLink(sp),d1 ; same as KCHR pointer param? <SM10> rb
|
|||
|
bne.s @noTable ; if not, skip itlk handling <SM10> rb
|
|||
|
endwith ;ExpandMemRec ; <SM10> rb
|
|||
|
|
|||
|
link a6,#ktLocals ; build stack frame
|
|||
|
movem.l d3-d5,-(sp) ; save the registers
|
|||
|
|
|||
|
move.l d0,a0 ; copy table handle
|
|||
|
move.l (a0),a0 ; load table pointer
|
|||
|
|
|||
|
; find the keyboard type and build the comparison key (type, code, modifiers)
|
|||
|
clr.l d4 ; clear a long
|
|||
|
move.b KbdType,d4 ; load type
|
|||
|
; removed support for Classic kbd! <03/05/89 pke>
|
|||
|
swap d4 ; put type in high word
|
|||
|
move.w codeMods(a6),d4 ; load code,mods
|
|||
|
|
|||
|
; step through the itlk table, looking for a match
|
|||
|
move.w (a0)+,d5 ; load table length
|
|||
|
bra.s @stepLoop ; enter loop at bottom
|
|||
|
@beginLoop
|
|||
|
move.l (a0)+,d0 ; load old type,code,mods
|
|||
|
move.w (a0)+,d1 ; load don't care masks
|
|||
|
move.w (a0)+,d2 ; load new code,mods
|
|||
|
move.l d4,d3 ; copy current type,code,mods
|
|||
|
and.w d1,d3 ; mask off don't care bits
|
|||
|
cmp.l d0,d3 ; same type,code,mods?
|
|||
|
bne.s @stepLoop ; no -> try next one
|
|||
|
and.w d1,d2 ; mask off don't care bits
|
|||
|
not.w d1 ; invert care mask
|
|||
|
and.w d1,d4 ; mask off care bits
|
|||
|
or.w d4,d2 ; combine for final code,mods
|
|||
|
move.w d2,codeMods(a6) ; remap code,mods
|
|||
|
bra.s @endLoop ; exit search loop
|
|||
|
@stepLoop
|
|||
|
dbra d5,@beginLoop ; try next entry
|
|||
|
@endLoop
|
|||
|
|
|||
|
; remove the stack frame and continue into the original KeyTrans code
|
|||
|
movem.l (sp)+,d3-d5 ; restore the registers
|
|||
|
unlk a6 ; remove stack frame
|
|||
|
@noTable
|
|||
|
endWith
|
|||
|
|
|||
|
;------------------------------------------------------------------------------
|
|||
|
|
|||
|
MOVE.L (SP)+, D0 ; Return address in D0
|
|||
|
MOVE.L (SP)+, A0 ; state address in A0
|
|||
|
MOVE.W (SP)+, D1 ; keycode in D1
|
|||
|
MOVE.L (SP)+, A1 ; KCHR address in A1
|
|||
|
MOVE.L D0, -(SP) ; Put the return address back.
|
|||
|
MOVEM.L A2/D3, -(SP) ; Save registers
|
|||
|
|
|||
|
; This snippet of code added on:
|
|||
|
MOVE.W D1, D2
|
|||
|
LSR.W #8, D2 ; Shift modifier flags down
|
|||
|
MOVE.B tInx(A1, D2.W), D2 ; Table number in D2
|
|||
|
MOVEQ #$7F, D0
|
|||
|
AND.B D1, D0 ; D0 contains virtual keycode only
|
|||
|
EXT.W D1
|
|||
|
EXT.L D1 ; Move up/down bit to bit 31
|
|||
|
MOVE.B D2, D1 ; Put the table number in D1
|
|||
|
LSL.W #8, D1 ; Shift it up one byte
|
|||
|
MOVE.B D0, D1 ; Put in the virtual keycode
|
|||
|
; D1 contains all the necessary input information:
|
|||
|
; Bit 31 contains the up/down bit (BMI for up stroke)
|
|||
|
; Bits 15-8 contain the table number (also in low byte of D2)
|
|||
|
; Bit 7 is 0
|
|||
|
; Bits 6-0 contain the "virtual" keycode
|
|||
|
LSL.W #7, D2 ; Multiply by 128
|
|||
|
OR.B D1, D2 ; Stuff in keycode
|
|||
|
ADD #tBgn, A1 ; A1 is now start of tables
|
|||
|
MOVE.B (A1, D2.W), D0 ; ASCII byte in D0
|
|||
|
BEQ.S @mightBeDead ; Go find out if it is really a dead key
|
|||
|
; End snippet
|
|||
|
|
|||
|
TST.L D1 ; Key up or down?
|
|||
|
BMI.S @upKey ; Skip if up
|
|||
|
MOVE.L (A0), D3 ; Previous key dead?
|
|||
|
BEQ.S @exitTrans ; Done if not
|
|||
|
|
|||
|
CLR.L (A0) ; Clear out dead key state
|
|||
|
LEA (A1, D3.L), A2 ; A2 points to completor table
|
|||
|
MOVE.W (A2)+, D2 ; Number of completors in D2
|
|||
|
BEQ.S @noComp ; If none, skip
|
|||
|
SUBQ.W #1, D2 ; Turn it into a zero-based count
|
|||
|
|
|||
|
@compLoop
|
|||
|
CMP.B (A2)+, D0 ; Do we match?
|
|||
|
BEQ.S @gotComp ; Jump out if we do
|
|||
|
ADDQ.L #1, A2 ; Get to next completor
|
|||
|
DBRA D2, @compLoop ; Go around again
|
|||
|
|
|||
|
@noComp
|
|||
|
SWAP D0
|
|||
|
MOVE.W (A2), D0 ; Store the default code
|
|||
|
SWAP D0
|
|||
|
BRA.S @exitTrans
|
|||
|
|
|||
|
@gotComp MOVE.B (A2), D0 ; Get the completor
|
|||
|
BRA.S @exitTrans
|
|||
|
|
|||
|
@mightBeDead
|
|||
|
MOVE.W -2(A1), D3 ; Number of tables in D3
|
|||
|
LSL.W #7, D3 ; 128 bytes per table
|
|||
|
LEA (A1, D3.W), A2 ; Start of dead key table in A2
|
|||
|
MOVE.W (A2)+, D2 ; Number of dead keys in D2
|
|||
|
BEQ.S @notDead ; There are no dead keys
|
|||
|
SUBQ.W #1, D2 ; Turn it into a zero-based count
|
|||
|
|
|||
|
@deadLoop
|
|||
|
CMP.W (A2)+, D1 ; Do we match?
|
|||
|
BEQ.S @gotDead ; Jump out if we do
|
|||
|
MOVE.W (A2)+, D3 ; Get number of completors
|
|||
|
LSL.W #1, D3 ; Multiply by 2
|
|||
|
LEA 2(A2, D3.W), A2 ; A2 now points to next entry
|
|||
|
DBRA D2, @deadLoop ; Go around again
|
|||
|
|
|||
|
@notDead ; D0 already contains $00000000
|
|||
|
@upKey ; D0 already contains correct ASCII
|
|||
|
@exitTrans
|
|||
|
MOVEM.L (SP)+, A2/D3 ; Restore registers
|
|||
|
MOVE.L D0, 4(SP) ; Put return value on stack
|
|||
|
RTS ; Sayonara
|
|||
|
|
|||
|
@gotDead
|
|||
|
; The key is a dead key. A2 points to the beginning of the completor table.
|
|||
|
TST.L D1 ; Key up or down?
|
|||
|
BMI.S @upDead ; Skip if up
|
|||
|
MOVE.L (A0), D3 ; Previous key dead?
|
|||
|
BEQ.S @saveState ; Skip if not
|
|||
|
MOVEQ #0, D2
|
|||
|
MOVE.W (A1, D3.L), D2 ; Get the number of completors for previous
|
|||
|
LSL.W #1, D2 ; Multiply by 2
|
|||
|
ADD.L D2, D3
|
|||
|
MOVE.W 2(A1, D3.L), D0 ; D0 now has default code for previous dead key
|
|||
|
|
|||
|
@saveState
|
|||
|
TST.W (A2) ; See if there are any completors
|
|||
|
BEQ.S @1 ; Skip if not
|
|||
|
MOVE.L A2, D2 ; Location of completor table
|
|||
|
SUB.L A1, D2 ; Subtract base address
|
|||
|
MOVE.L D2, (A0) ; Save it
|
|||
|
BRA.S @exitTrans
|
|||
|
|
|||
|
@1
|
|||
|
CLR.L (A0) ; Clear out dead key state
|
|||
|
SWAP D0 ; There might be something in the low word
|
|||
|
MOVE.W 2(A2), D0 ; Send out the default code
|
|||
|
BRA.S @exitTrans
|
|||
|
|
|||
|
@upDead
|
|||
|
MOVE.W (A2)+, D3 ; Get the number of completors
|
|||
|
LSL.W #1, D3 ; Multiply by 2
|
|||
|
MOVE.W (A2, D3.W), D0 ; Put default code in D0
|
|||
|
BRA.S @exitTrans
|
|||
|
; End KeyTrans
|
|||
|
|
|||
|
ENDPROC ; KbdMngr
|
|||
|
|
|||
|
|
|||
|
|
|||
|
; This is the almost obsolete KeyHook routine, except FoolWrite and Microsoft <SM8> rb, start
|
|||
|
; weird still call this hook even tough they have been told to simply call
|
|||
|
; Key1Trans, so here we go again. Do not remove this code, it is installed as
|
|||
|
; Key1Trans and Key2Trans low mem vector.
|
|||
|
|
|||
|
; -----------------------------------------------------------------------------
|
|||
|
; Routine: KeyHook
|
|||
|
; Input: d1.b option, alpha, shift keys in 2,1,0.
|
|||
|
; $17A.b bit #7 1 iff feature key set.
|
|||
|
; d2.w keycode (0-127).
|
|||
|
; d3.b minus iff keyup, plus iff keydown.
|
|||
|
; Output: d0.b ASCII code.
|
|||
|
;
|
|||
|
; Macintosh keyboard mapping hook, which relies on the new KeyTrans trap.
|
|||
|
; -----------------------------------------------------------------------------
|
|||
|
|
|||
|
KeyHook PROC
|
|||
|
with ExpandMemRec
|
|||
|
bra.s SkipHeader ; skip the header.
|
|||
|
|
|||
|
; Global variables left here for the wacky Key Caps accessory.
|
|||
|
|
|||
|
deadEnable dc.w $ffff ; enable the dead key processing.
|
|||
|
dc.l ('INIT') ; resource type.
|
|||
|
dc.w 0 ; resource id number.
|
|||
|
* export intlEnable
|
|||
|
intlEnable dc.b $00 ; intl keybooard flag (false).
|
|||
|
dc.b 7 ; hook version number.
|
|||
|
dc.w $0000 ; slot to mollify MacTerm. <S159>
|
|||
|
|
|||
|
; If this is the domestic or international keyboard hook, we check for keycodes
|
|||
|
; that are in the keypad range. These are handled by just returning zero so
|
|||
|
; the keypad hook can handle them.
|
|||
|
|
|||
|
SkipHeader
|
|||
|
cmp.b #$40,d2 ; beyond keyboard range?
|
|||
|
bhs.s @domestic ; yes -> skip mapping.
|
|||
|
|
|||
|
; If the international flag is on in the header, this is an original
|
|||
|
; Macintosh 128K, 512K, 512Ke, or MacPlus, and the keyboard type is not
|
|||
|
; the MacPlus key dorfer with built-in keypad, then we perform a mapping
|
|||
|
; from key codes to virtual key codes. The original domestic keyboard and
|
|||
|
; MacPlus key dorfer just happen to generate virtual key codes all by
|
|||
|
; themselves.
|
|||
|
|
|||
|
move.b intlEnable,d0 ; international flag set?
|
|||
|
beq.s @domestic ; no -> skip remapping.
|
|||
|
move.w HwCfgFlags,d0 ; load hardware configuration.
|
|||
|
btst.l #hwCbADB,d0 ; ADB present?
|
|||
|
bne.s @domestic ; yes -> skip remapping.
|
|||
|
cmp.b #$0b,kbdType ; MacPlus keyboard?
|
|||
|
beq.s @domestic ; yes -> skip remapping.
|
|||
|
|
|||
|
lea keyTable,a0 ; find the table.
|
|||
|
move.b 0(a0,d2.w),d2 ; map to virtual key code.
|
|||
|
|
|||
|
; Build the arguments and call to the keyboard trap to produce an ASCII code.
|
|||
|
; We get the modifiers from the arguments, except for the command key, which is
|
|||
|
|
|||
|
@domestic
|
|||
|
move.b $17A,d0 ; command key is in high bit of D0
|
|||
|
lsl.b #1,d0 ; command bit is in X CC
|
|||
|
roxl.w #1,d1 ; command now in low bit of D1
|
|||
|
move.b d3,d0 ; up/down key is in high bit of D0
|
|||
|
lsl.b #1,d0 ; up/down bit is in X CC
|
|||
|
roxl.w #1,d1 ; up down now in low bit of D1
|
|||
|
lsl.w #7,d1 ; shift all the way up
|
|||
|
or.b d2,d1 ; put keycode in low 7 bits.
|
|||
|
move.b deadEnable,d0 ; dead keys enabled?
|
|||
|
bne.s @deadOn ; yes -> allow key down calls.
|
|||
|
bset #7,d1 ; no -> force key up call.
|
|||
|
@deadOn
|
|||
|
subq.l #4,sp ; make room for result.
|
|||
|
move.l expandMem,a0 ; get low memory pointer
|
|||
|
move.l emKeyCache(a0),-(sp) ; pass the key cache pointer
|
|||
|
move.w d1,-(sp) ; push keycode and modifiers.
|
|||
|
pea emKeyDeadState(a0) ; push address of dead key state.
|
|||
|
_KeyTrans ; call keyboard trap.
|
|||
|
|
|||
|
; KeyTrans has left a present for us on the stack. Each word is an ASCII code
|
|||
|
; if that word is to be reported as an event, or zero if nothing should happen.
|
|||
|
; Coincidentally, our caller expects us to return zero if he should not report
|
|||
|
; the event, or the ASCII code if he should. We check the first word and do
|
|||
|
; that one ourselves. The second one is left up to the caller. Bring in the
|
|||
|
; Hydra!
|
|||
|
|
|||
|
moveq #0,d0 ; clear a long.
|
|||
|
move.w (sp)+,d0 ; get first return code.
|
|||
|
beq.s @noPost ; no need to post an event
|
|||
|
lsl.w #8,d2 ; shift key code over.
|
|||
|
or.w d2,d0 ; or in key code.
|
|||
|
move.w #KeyUpEvt,a0 ; assume key up
|
|||
|
tst.b d3 ; keyUp?
|
|||
|
bmi.s @postIt ; yes -> skip check
|
|||
|
move.w #KeyDwnEvt,a0 ; load key down
|
|||
|
@postIt _PostEvent ; generate an extra event.
|
|||
|
@noPost move.w (sp)+,d0 ; get the second return code.
|
|||
|
rts ; return to the caller.
|
|||
|
|
|||
|
endwith
|
|||
|
|
|||
|
; ----------------------------------------------------------------------------
|
|||
|
; In order to map the old international keyboard correctly, we use the
|
|||
|
; following translation table to map key codes to virtual key codes. This
|
|||
|
; is not necessary on an old domestic keyboard as the key codes “just happen
|
|||
|
; to match” the virtual key codes.
|
|||
|
; ----------------------------------------------------------------------------
|
|||
|
|
|||
|
keyTable
|
|||
|
dc.b $00, $01, $02, $03, $04, $05, $32, $06 ; $00 .. $07
|
|||
|
dc.b $07, $08, $2c, $09, $0c, $0d, $0e, $0f ; $08 .. $0f
|
|||
|
dc.b $10, $11, $12, $13, $14, $15, $16, $17 ; $10 .. $17
|
|||
|
dc.b $18, $19, $1a, $1b, $1c, $1d, $1e, $1f ; $18 .. $1f
|
|||
|
dc.b $20, $21, $22, $23, $2a, $25, $26, $27 ; $20 .. $27
|
|||
|
dc.b $28, $29, $24, $2e, $2f, $0b, $2d, $2b ; $28 .. $2f
|
|||
|
dc.b $30, $34, $0a, $33, $31, $35, $36, $37 ; $30 .. $37
|
|||
|
dc.b $38, $39, $3a, $3b, $3c, $3d, $3e, $3f ; $38 .. $3f
|
|||
|
|
|||
|
ENDP
|
|||
|
|
|||
|
|
|||
|
; <SM8> rb, end
|
|||
|
|
|||
|
END
|