mirror of
https://github.com/elliotnunn/supermario.git
synced 2024-11-26 16:49:18 +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
|