mirror of
https://github.com/elliotnunn/boot3.git
synced 2024-12-22 10:30:32 +00:00
5b0f0cc134
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included. The Tools directory, containing mostly junk, is also excluded.
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
|