mirror of
https://github.com/elliotnunn/sys7.1-doc-wip.git
synced 2024-12-12 04:29:09 +00:00
1289 lines
47 KiB
Plaintext
1289 lines
47 KiB
Plaintext
;
|
||
; File: ADBMgrPatch.a
|
||
;
|
||
; Contains: Patches Gary Davidian's new ADB manager into MacII's and MacSE's
|
||
;
|
||
; Written by: Gary Davidian/Gary Rensberger
|
||
;
|
||
; Copyright: © 1989-1993 by Apple Computer, Inc., all rights reserved.
|
||
;
|
||
; Change History (most recent first):
|
||
;
|
||
; <SM2> 11/9/93 KW added some eieioSTP macros. Only active for CygnusX1 ROM
|
||
; <13> 2/12/92 JSM Moved this file to ADBMgr folder, keeping all the old revisions.
|
||
; <12> 10/4/91 JSM Change PsychoticFarmerOrLater conditionals to TheFuture.
|
||
; <11> 9/22/91 DTY Change PsychoticFarmerAndLater to PsychoticFarmerOrLater.
|
||
; <10> 8/29/91 JSM Cleanup header.
|
||
; <9> 8/27/91 DTY Conditionalized previous change for PsychoticFarmerAndLater.
|
||
; <8> 7/16/91 GMR Fixed bug when ADB explicit command is going out just as
|
||
; autopoll data is being received (occurs very seldom).
|
||
; <7> 6/12/91 LN added #include 'InternalOnlyEqu.a'
|
||
; <6> 8/10/90 DTY Addded notAUX conditional to patches.
|
||
; <5> 8/7/90 DTY Convert to a linked patch.
|
||
; <4> 7/11/90 gbm Change HardwareEqu.a to HardwarePrivateEqu.a
|
||
; <3> 4/26/90 GMR Now sets the mouse and keyboard bits in the DevMap by default
|
||
; during patch installation since the old ADB manager didn't use
|
||
; these and weren't set up.
|
||
; <2> 3/6/90 GMR Fixed initing of FDBFlag, to set command queue empty bit.
|
||
; <1.2> 11/29/89 GGD NEEDED FOR 6.0.5: Forced the interrupt masking level to 7 to
|
||
; work correctly on all machines, instead of using HiIntMask which
|
||
; is level 3 by default in HardwareEqu. Deleted the initialization
|
||
; of TimeViaDB, since it was always using the MacII value (and was
|
||
; wrong for the SE), It is now initialized correctly in Rom78Fix
|
||
; and Rom76Fix. Changed the Auto/SRQ polling to only poll devices
|
||
; that are in the device table.
|
||
; <1.1> 10/14/89 GMR Modified ADBProc to save/restore keyboard and mouse CRA's
|
||
; (around _ADBReinit trap). Added KbdInstall to patch, instead of
|
||
; using ROM version. Installation code does not re-init the ADB
|
||
; bus, preserving original device entry table.
|
||
; <1.0> 10/3/89 GMR Adding for first time to EASE
|
||
;
|
||
|
||
|
||
PRINT OFF
|
||
PrNonPortable EQU 1
|
||
Debugging EQU 0
|
||
INCLUDE 'SysEqu.a'
|
||
INCLUDE 'ToolEqu.a'
|
||
INCLUDE 'SysErr.a'
|
||
INCLUDE 'Private.a'
|
||
INCLUDE 'QuickEqu.a'
|
||
INCLUDE 'Traps.a'
|
||
INCLUDE 'HardwarePrivateEqu.a'
|
||
INCLUDE 'ApplDeskBus.a'
|
||
INCLUDE 'AppleDeskBusPriv.a'
|
||
INCLUDE 'LinkedPatchMacros.a'
|
||
INCLUDE 'InternalOnlyEqu.a'
|
||
jADBReInit EQU OSTable+($7B*4) ; OS trap table entry for _ADBReInit
|
||
NoIntMask EQU $0700 ; all ints disabled on all machines <1.2>
|
||
PRINT ON
|
||
|
||
|
||
GEmptyAddr ROMBind (SE,$03574),(II,$06FEE)
|
||
KbdDrvr ROMBind (SE,$03AC0),(II,$0753A)
|
||
ROMInitADBDrvr ROMBind (SE,$03C9E),(II,$07724)
|
||
FindFDBInfo ROMBind (SE,$03D4C),(II,$077D2)
|
||
|
||
;______________________________________________________________________
|
||
;
|
||
; _ADBReInit - ReInitialize the Front Desk Bus
|
||
;
|
||
;______________________________________________________________________
|
||
ADBReinit PatchProc _ADBReInit,(SE,II,notAUX)
|
||
IMPORT ReInit
|
||
|
||
MOVE.L JADBProc,A0 ; get hook to processing routine <C931>
|
||
moveq.l #0,D0 ; set it as pre-processing routine <C931>
|
||
JSR (A0) ; call the routine <C931>
|
||
|
||
MoveM.L D0-D4/A0-A3,-(SP)
|
||
Move.L ADBBase,A3 ; A3 get local data address
|
||
BSR ReInit
|
||
IADB1 jsrROM ROMInitADBDrvr
|
||
|
||
MoveM.L (SP)+,D0-D4/A0-A3 ; restore registers
|
||
|
||
Move.L JADBProc,A0 ; get hook to processing routine <C931>
|
||
MoveQ #1,D0 ; set it as post-processing routine. <C931>
|
||
JSR (A0) ; call the routine <C931>
|
||
RTS ; done <C931>
|
||
ENDPROC
|
||
|
||
;_______________________________________________________________________
|
||
;
|
||
; 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.
|
||
;
|
||
;_______________________________________________________________________
|
||
|
||
patchADBOp PatchProc _ADBOp,(SE,II,notAUX) ; a0-a1/d1-d2 saved by OsTrap dispatch
|
||
IMPORT RunADBRequest
|
||
with ADBVars,ADBCmdQEntry
|
||
@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 #NoIntMask,sr ; disable ints while queueing <1.2>
|
||
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 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
|
||
ENDPROC
|
||
|
||
;_______________________________________________________________________
|
||
;
|
||
; InitADB - Initialize state variables
|
||
;
|
||
;_______________________________________________________________________
|
||
InitADB InstallProc (SE,II,notAUX)
|
||
IMPORT ADBProc, FDBTask, FDBShiftInt
|
||
IMPORT StartReqVIA, MouseDrvr
|
||
IMPORT RunADBRequest, DefaultDev
|
||
with ADBVars,ADBDeviceEntry,ADBCmdQEntry
|
||
|
||
movea.l VIA,a1 ; point to the VIA1 registers
|
||
@wait
|
||
eieioSTP
|
||
move.b vBufB(a1),d0
|
||
eieioSTP
|
||
andi.b #(1<<vFDesk2)|\
|
||
(1<<vFDesk1),d0 ; look at state bits
|
||
cmpi.b #(1<<vFDesk2)|\
|
||
(1<<vFDesk1),d0 ; are we at state 3?
|
||
bne.s @wait ; no, keep waiting...
|
||
|
||
ori.w #NoIntMask,sr ; mask out interrupts <1.2>
|
||
eieioSTP
|
||
move.b vSR(a1),d0 ; empty shift reg
|
||
eieioSTP
|
||
|
||
MOVE.L ADBBase,A3 ; point to ADB private data structures
|
||
|
||
leaResident ADBProc,A0 ; Get the ADBProc
|
||
move.l A0,JADBProc ; install it into JAdbProc vector
|
||
leaResident FDBTask, A0 ; setup the FDB VBL task
|
||
move.l A0,JKybdTask ; lomem vector
|
||
|
||
leaResident FDBShiftInt,A0 ; get addr of front desk bus handler <4.6>
|
||
move.l A0,Lvl1DT+8 ; install as SR interrupt receiver
|
||
leaResident StartReqVIA,a0 ; get HW dependent proc to start ADB request
|
||
move.l a0,StartReqProc(a3) ; setup proc pointer
|
||
|
||
moveq #0,d1 ; reset device table index
|
||
@check cmpi.b #MouseAddr,FDBOAddr(a3,d1.w) ; is this a mouse device?
|
||
bne.s @next ; no, try next one
|
||
|
||
leaResident MouseDrvr,a0 ; get address of new mouse driver
|
||
move.l a0,FDBCRA(a3,d1.w) ; save as completion routine address
|
||
|
||
@next addi.b #FRecSize,d1 ; advance offset
|
||
cmpi.b #numFDBAdr*FRecSize,d1 ; are we at the end of table?
|
||
bne.s @check ; no, continue checking
|
||
|
||
moveq #(FQSize*8/4)-1,d1 ; # of long words in command queue
|
||
lea startCQ(a3),a0 ; pt to start of command queue
|
||
@clear clr.l (a0)+ ; clear out command queue
|
||
dbra d1,@clear
|
||
|
||
move.b #(1<<FDBQEmpty),\ ; the command queue is empty... <2>
|
||
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
|
||
|
||
ori.b #(1<<mouseAddr)|\
|
||
(1<<kbdAddr ),DevMap+1(a3) ; make sure we poll keyboard and mouse <3>
|
||
|
||
andi #$F8FF,SR ; clear Interrupt mask
|
||
|
||
bsr RunADBRequest ; start auto poll for the mouse
|
||
bsr DefaultDev ; setup mouse & keyboard as default
|
||
|
||
rts
|
||
ENDPROC
|
||
|
||
;______________________________________________________________________
|
||
; Stack frame equates for InitADBDrvr and ADBProc
|
||
|
||
ourLocals RECORD {endLocals},increment
|
||
iDeviceTy ds.b 1
|
||
iOrigAddr ds.b 1
|
||
iCRAddr ds.l 1
|
||
iDataAddr ds.l 1
|
||
endLocals
|
||
ENDR
|
||
|
||
;______________________________________________________________________
|
||
;
|
||
; ADBProc - this routine lives in the JADBProc vector and is called
|
||
; by ADBReInit before and after initialization
|
||
;
|
||
; D0 is 0 if pre-processing, non-0 if post-processing.
|
||
; In addition to the standard pascal calling conventions.
|
||
;______________________________________________________________________
|
||
|
||
ADBProc PROC EXPORT ; <1.1>
|
||
EXPORT ReInit
|
||
EXPORT FDBTask
|
||
EXPORT FDBShiftInt
|
||
EXPORT StartReqVIA
|
||
EXPORT MouseDrvr
|
||
EXPORT RunADBRequest
|
||
EXPORT DefaultDev
|
||
|
||
with ourLocals,ADBVars,ADBDeviceEntry,ADBCmdQEntry
|
||
|
||
tst.l d0 ; 0 = pre-processing
|
||
bne.s PostInit ; Skip if not
|
||
;_______________________________________________________________________
|
||
; PreInit is called after the bus is initialized. It saves
|
||
; keyboard/mouse driver ptrs, then disposes of keyboards storage.
|
||
;_______________________________________________________________________
|
||
_CountADBs ; Get the number of ADB devices
|
||
move.w d0, d2 ; Save it in D2
|
||
beq.s @exit ; Skip if none
|
||
link a6,#iDeviceTy ; Make a stack frame
|
||
@RemoveLoop
|
||
lea iDeviceTy(a6), a0 ; A0 is parameter block
|
||
move.w d2, d0
|
||
_GetIndADB ; Get a device entry
|
||
bmi.s @NextRec ; Skip if not valid
|
||
|
||
cmp.b #kbdAddr,iOrigAddr(A6) ; Keyboard?
|
||
bne.s @Mouse ; no, see if mouse
|
||
lea KbdDriver,a0
|
||
move.l iCRAddr(a6),(a0) ; save ptr to keyboard driver
|
||
bra.s @setIt
|
||
|
||
@Mouse cmp.b #MouseAddr,iOrigAddr(A6) ; Mouse?
|
||
bne.s @NextRec ; no, check next entry
|
||
lea MseDriver,a0
|
||
move.l iCRAddr(a6),(a0) ; save ptr to mouse driver
|
||
bra.s @NextRec ; next entry
|
||
|
||
@setIt 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 iCRAddr(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 @RemoveLoop
|
||
unlk A6
|
||
@exit
|
||
rts
|
||
|
||
KbdDriver DS.L 1 ; saves ptr to keyboard driver
|
||
MseDriver DS.L 1 ; saves ptr to keyboard driver
|
||
;_______________________________________________________________________
|
||
; PostInit is called after the bus is initialized. It restores
|
||
; keyboard/mouse driver ptr in device entries.
|
||
;_______________________________________________________________________
|
||
PostInit
|
||
_CountADBs ; Get the number of ADB devices
|
||
move.w D0, D2 ; Save it in D2
|
||
beq.s @exit ; Skip if none
|
||
link A6, #iDeviceTy ; Make a stack frame
|
||
@InstallLoop
|
||
lea iDeviceTy(A6), A0 ; A0 is parameter block
|
||
move.w D2, D0
|
||
_GetIndADB ; Get a device entry
|
||
bmi.s @NextRec ; Skip if not valid
|
||
|
||
cmp.b #kbdAddr,iOrigAddr(A6) ; Keyboard?
|
||
bne.s @Mouse ; no, see if mouse
|
||
move.l KbdDriver,iCRAddr(A6) ; Restore ptr to keyboard driver
|
||
bra.s @setIt
|
||
|
||
@Mouse cmp.b #MouseAddr,iOrigAddr(A6); Mouse?
|
||
bne.s @NextRec ; Skip if not
|
||
move.l MseDriver,iCRAddr(A6) ; Restore ptr to mouse driver
|
||
@setIt lea iCRAddr(A6), A0
|
||
_SetADBInfo ; D0 already contains the ADB Address
|
||
|
||
@NextRec subq.w #1, D2
|
||
bgt.s @InstallLoop
|
||
unlk A6
|
||
@exit rts
|
||
|
||
|
||
;_______________________________________________________________________
|
||
;
|
||
; ReInit - Initialize state variables, re-scan for devices
|
||
;_______________________________________________________________________
|
||
ReInit
|
||
ori.w #NoIntMask,sr ; mask out interrupts <1.2>
|
||
move.w #((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 InitDevT ; go initialize the device table
|
||
|
||
andi #$F8FF,SR ; clear Interrupt mask
|
||
@wait btst #FDBInit,FDBFlag(A3); done with initialization?
|
||
bne.s @wait ; no, keep in loop
|
||
|
||
jsr DefaultDev ; setup mouse & keyboard as default
|
||
jsr KbdInstall ; Install keyboard information
|
||
rts
|
||
endwith
|
||
|
||
;______________________________________________________________________
|
||
;
|
||
; DefaultDev - check mouse and keyboard in the device table, if they
|
||
; are not there, set them up as default device anyway.
|
||
;
|
||
;______________________________________________________________________
|
||
|
||
DefaultDev
|
||
with ADBVars,ADBDeviceEntry ; <1.9>
|
||
MoveQ #kbdAddr,D0 ; first check keyboard
|
||
FFI2 jsrROM FindFDBInfo ; look for keyboard (FindFDBInfo)
|
||
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
|
||
KD1 leaROM KbdDrvr,A0
|
||
move.l a0,FDBCRA(A1) ; stuff completion routine address
|
||
bset.b #kbdAddr,DevMap+1(a3) ; remember to poll it <1.9>
|
||
ChkMouse
|
||
MoveQ #mouseAddr,D0 ; now check mouse
|
||
FFI3 jsrROM FindFDBInfo ; look for mouse (FindFDBInfo)
|
||
BEQ.S DefExit ; branch, mouse is there
|
||
Move.B #1,FDBDevTy(A1) ; assume handleID 1
|
||
Move.B #mouseAddr,FDBOAddr(A1) ; set original address as 3
|
||
Move.B #mouseAddr,FDBAddr(A1) ; set FDB address as 3
|
||
Lea MouseDrvr,A0 ; get mouse address
|
||
Move.L A0,FDBCRA(A1) ; set completion routine address
|
||
bset.b #mouseAddr,DevMap+1(a3) ; remember to poll it <1.9>
|
||
DefExit
|
||
RTS ; done
|
||
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.
|
||
;
|
||
;_______________________________________________________________________
|
||
|
||
RunADBRequest
|
||
with ADBVars,ADBCmdQEntry
|
||
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.
|
||
;
|
||
;_______________________________________________________________________
|
||
|
||
ExplicitRequestDone
|
||
with ADBVars,ADBCmdQEntry
|
||
move.l sp,-(sp) ; allocate an empty buffer on the stack
|
||
move.w sr,d1 ; save interrupt mask
|
||
ori.w #NoIntMask,sr ; disable ints while dequeueing <1.2>
|
||
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
|
||
FFI1 jsrROM FindFDBInfo ; get the info for this device (FindFDBInfo)
|
||
bne 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.
|
||
;
|
||
;_______________________________________________________________________
|
||
|
||
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
|
||
|
||
movem.l (sp)+,d0/a0/a1/a2 ; setup cmd, buffer, handler, data
|
||
move.l a1,d1 ; test to see if handler address is valid
|
||
beq.s @noHandler ; if not, don't call it
|
||
jsr (a1) ; call the handler
|
||
@noHandler
|
||
movea.l (sp),sp ; deallocate the buffer (if implicit cmd)
|
||
rts ; return from the interrupt
|
||
|
||
Title 'KbdADB - ADB Manager - StartReqVIA'
|
||
|
||
;_______________________________________________________________________
|
||
;
|
||
; Routine: StartReqVIA
|
||
; Inputs: D2 - length of transmit buffer data
|
||
; D3 - command byte / implicit flag (bit 31)
|
||
; A2 - pointer to buffer containing transmit data
|
||
; A3 - pointer to ADBBase
|
||
;
|
||
; Outputs: A1 - pointer to VIA1
|
||
; A3 - pointer to ADBBase
|
||
;
|
||
; Destroys:
|
||
; Calls: RunADBRequest, @sendCmd, @waitForInput, @getNextByte
|
||
; @sendFirstByte, @sendNextByte
|
||
;
|
||
; Function: Initiates an asynchronous ADB request, using the VIA interface
|
||
; to the ADB transceiver processor.
|
||
;
|
||
;_______________________________________________________________________
|
||
|
||
StartReqVIA
|
||
with ADBVars
|
||
movea.l VIA,a1 ; get pointer to VIA
|
||
bset.b #fDBBusy,FDBAuFlag(a3) ; remember that we are busy
|
||
beq.s @notBusy ; if not busy, proceed
|
||
rts ; if busy, do nothing and return
|
||
|
||
@notBusy tst.l d3 ; see if implicit
|
||
bpl.s @explicit ; implicit is special case
|
||
|
||
; send an implicit command (auto / SRQ polling), no data needs to be sent
|
||
|
||
@implicit move.b PollAddr(a3),d3 ; get the auto/srq polling address
|
||
lsl.b #4,d3 ; position the address
|
||
ori.b #talkCmd+0,d3 ; make it a Talk R0 command
|
||
bsr.w @sendCmd ; send out the command byte
|
||
beq.s @autoReply ; see if prior auto poll data returned instead
|
||
|
||
move.b fDBCmd(a3),pollCmd(a3) ; remember the command byte
|
||
bsr.s @StartAutoPoll ; start auto polling
|
||
btst.b #fDBQEmpty,FDBFlag(a3) ; see if anything queued
|
||
bne.s @idle ; if not, just wait for auto poll data
|
||
|
||
; we have just changed from state 0 to state 3, if a command is in the queue, we will
|
||
; want to change back to state 0, and send a new command. We have to give the xcvr
|
||
; processor time to recognize the state change into state 3, before we change back to
|
||
; state 0. Otherwise it will be out of sync.
|
||
|
||
pea RunADBRequest ; somthing in queue, run after a short delay
|
||
move.w TimeViaDB,d0 ; get 1ms VIA loop time constant
|
||
|
||
IF forSTP601 THENB
|
||
;•••• STP ••• eric -- let's double it??
|
||
lsr.w #2,d0 ; 1ms/8 = 125µs
|
||
ELSE
|
||
|
||
lsr.w #4,d0 ; 1ms/16 = 62.5µs
|
||
ENDIF
|
||
@delay
|
||
eieioSTP
|
||
btst.b #0,vBufB(a1) ; timing base on BTST loop, we don't care
|
||
eieioSTP
|
||
dbra d0,@delay ; wait at least 50µs for state change to occur
|
||
@idle bclr.b #fDBBusy,FDBAuFlag(a3) ; allow explicit cmds to interrupt auto polling
|
||
rts ; if not, just let auto polling continue
|
||
|
||
@StartAutoPoll
|
||
moveq.l #(1<<vFDesk1)|\
|
||
(1<<vFDesk2),d1 ; change from state 0 to state 3
|
||
bsr.w @waitForInput ; start auto polling, wait for a reply
|
||
ori.b #(1<<fDBAPoll)|\ ; indicate that auto poll data returned
|
||
(1<<fDBBusy),FDBAuFlag(a3) ; auto poll found something, we're busy again
|
||
moveq.l #(1<<vFDesk2),d1 ; change from state 3 to state 1
|
||
bra.s @getReply ; join common code to get reply
|
||
|
||
@explicit moveq.l #maskADBCmd,d0 ; setup to extract command
|
||
and.b d3,d0 ; clear addr and reg
|
||
subq.b #listenCmd,d0 ; check for listen command
|
||
beq.w @listen ; explicit listen is special case
|
||
|
||
eject
|
||
; send an explicit command (other than listen), no data needs to be sent
|
||
|
||
bsr.s @sendCmd ; send out the command byte
|
||
bne.s @explicitReply ; see if auto poll data returned instead
|
||
@autoReply bset.b #fDBAPoll,FDBAuFlag(a3) ; indicate that auto poll data returned
|
||
move.b pollCmd(a3),fDBCmd(a3) ; poll command is command that is completing
|
||
@explicitReply
|
||
|
||
moveq.l #(1<<vFDesk1),d1 ; change from state 0 to state 1
|
||
@getReply bsr.s @waitForInput ; wait for the first byte
|
||
bne.s @noTimeout ; see if timeout occured
|
||
bset.b #fDBNoReply,FDBAuFlag(a3) ; indicate that no reply data was returned
|
||
@noTimeout clr.b fDBCnt(a3) ; indicate buffer empty
|
||
|
||
bsr.s @getNextByte ; wait for the second byte
|
||
bne.s @noSRQ ; see if SRQ occured
|
||
bset.b #fDBSRQ,FDBAuFlag(a3) ; indicate that no service request was returned
|
||
@noSRQ
|
||
|
||
@fetchLoop bsr.s @getNextByte ; wait for another byte
|
||
beq.s @fetchDone ; exit if end of data reached
|
||
cmpi.b #8,fDBCnt(a3) ; see if end of buffer reached
|
||
blo.s @fetchLoop ; keep fetching until end of data
|
||
@fetchDone btst.b #fDBNoReply,FDBAuFlag(a3) ; see if buffer data is valid
|
||
seq.b d0 ; $FF if data is valid, $00 if no reply
|
||
and.b d0,fDBCnt(a3) ; set count to zero if timeout
|
||
bra.w ReqDoneVIA
|
||
|
||
|
||
@sendCmd andi.b #$FF-(\
|
||
(1<<fDBAPoll)|\ ; clear auto poll reply flag
|
||
(1<<fDBSRQ)|\ ; clear SRQ active in reply flag
|
||
(1<<fDBNoReply)),\ ; clear reply timeout flag
|
||
FDBAuFlag(a3) ; clear the flags
|
||
move.w sr,d0 ; save int mask
|
||
ori.w #NoIntMask,sr ; disable all interrupts <1.2>
|
||
|
||
;
|
||
; This change (8) will take effect for TheFuture. Don’t use it for anything
|
||
; earlier.
|
||
;
|
||
|
||
if TheFuture then ; <9>
|
||
|
||
eieioSTP
|
||
move.b vBufB(a1),d1 ; get current state <8>
|
||
eieioSTP
|
||
andi.b #(1<<vFDesk2)+\
|
||
(1<<vFDesk1),d1 ; <8>
|
||
cmpi.b #(1<<vFDesk2)+\
|
||
(1<<vFDesk1),d1 ; are we in state 3? <8>
|
||
bne.s @sendCont ; no, procede as usual <8>
|
||
eieioSTP
|
||
btst.b #vFDBInt,vBufB(a1) ; yes, test the FDBInt~ status <8>
|
||
eieioSTP
|
||
beq.s @sendExit ; asserted, xcvr already clocking autopoll data,<8>
|
||
; exit (wait for autopoll to complete) <8>
|
||
endif ; <9>
|
||
|
||
@sendCont
|
||
eieioSTP
|
||
ori.b #$1C,vACR(a1) ; set SR to shift-out with ext clk
|
||
eieioSTP
|
||
move.b d3,vSR(a1) ; load shift reg with cmd, start shifting
|
||
eieioSTP
|
||
move.b d3,fDBCmd(a3) ; save the command
|
||
eieioSTP
|
||
andi.b #-1-(1<<vFDesk2)-\
|
||
(1<<vFDesk1),vBufB(a1) ; force state bits to zero
|
||
eieioSTP
|
||
@sendExit move.l (sp)+,ShiftIntResume(a3); save resume address
|
||
move.w d0,sr ; restore interrupt mask
|
||
rts ; return to callers caller, wait for interrupt
|
||
|
||
|
||
@waitForInput
|
||
eieioSTP
|
||
bclr.b #4,vACR(a1) ; change to shift-in mode
|
||
eieioSTP
|
||
tst.b vSR(a1) ; empty shift reg to start shifting
|
||
eieioSTP
|
||
eor.b d1,vBufB(a1) ; change the state
|
||
eieioSTP
|
||
move.l (sp)+,ShiftIntResume(a3) ; save resume address
|
||
rts ; return to callers caller, wait for interrupt
|
||
|
||
|
||
@getNextByte
|
||
lea fDBCnt(a3),a0 ; point to the length byte of the buffer
|
||
moveq.l #1,d0 ; zero extend the index
|
||
add.b (a0),d0 ; get, and increment the index
|
||
move.b d0,(a0) ; update the index
|
||
eieioSTP
|
||
move.b vSR(a1),(a0,d0.w) ; save the new byte in the buffer
|
||
eieioSTP
|
||
eori.b #(1<<vFDesk1)|\
|
||
(1<<vFDesk2),vBufB(a1) ; alternate between state 1 and state 2
|
||
eieioSTP
|
||
move.l (sp)+,ShiftIntResume(a3) ; save resume address
|
||
rts ; return to callers caller, wait for interrupt
|
||
|
||
eject
|
||
; send an explicit Listen command, send data buffer.
|
||
; Inputs: D2 - length of transmit buffer data
|
||
; D3 - command byte / implicit flag (bit 31)
|
||
; A2 - pointer to buffer containing transmit data
|
||
; A3 - pointer to ADBBase
|
||
|
||
@listen subq.b #2,d2 ; check for min length of 2
|
||
bhs.s @minOK ; if >= 2, use it
|
||
moveq.l #0,d2 ; otherwise use 0, which will become 2
|
||
@minOK subq.b #8-2,d2 ; check for max length of 8
|
||
bls.s @maxOK ; if <= 8, use it
|
||
moveq.l #0,d2 ; otherwise use 0, which will become 8
|
||
@maxOK addq.b #8,d2 ; restore count
|
||
move.b d2,fDBCnt(a3) ; update buffer length
|
||
move.l a2,ListenBuffPtr(a3); save buffer starting address
|
||
|
||
bsr.s @sendCmd ; send out the command byte
|
||
beq.w @autoReply ; see if auto poll data returned instead
|
||
|
||
bsr.s @sendFirstByte ; send the first byte
|
||
bne.s @noListenTimeout ; see if timeout occured
|
||
bset.b #fDBNoReply,FDBAuFlag(a3) ; indicate that no reply data was returned
|
||
@noListenTimeout
|
||
bsr.s @sendNextByte ; send the second byte
|
||
bne.s @sendLoop ; if no SRQ, send the data
|
||
bset.b #fDBSRQ,FDBAuFlag(a3) ; remember that a service request was returned
|
||
|
||
@sendLoop tst.b fDBCnt(a3) ; see if end of buffer reached
|
||
beq.s ReqDoneVIA ; leave when count is zero, no reply data
|
||
bsr.s @sendNextByte ; send another byte
|
||
bra.s @sendLoop ; loop until count exhausted
|
||
|
||
|
||
|
||
@sendFirstByte
|
||
moveq.l #(1<<vFDesk1),d1 ; change from state 0 to state 1
|
||
bra.s @sendByte ; join common code
|
||
|
||
@sendNextByte
|
||
moveq.l #(1<<vFDesk1)|\
|
||
(1<<vFDesk2),d1 ; alternate between state 1 and state 2
|
||
@sendByte movea.l ListenBuffPtr(a3),a0; get the buffer pointer
|
||
eieioSTP
|
||
move.b (a0)+,vSR(a1) ; send the byte
|
||
eieioSTP
|
||
move.l a0,ListenBuffPtr(a3); update the buffer pointer
|
||
subq.b #1,fDBCnt(a3) ; decrement the send count
|
||
eieioSTP
|
||
eor.b d1,vBufB(a1) ; change the state
|
||
eieioSTP
|
||
move.l (sp)+,ShiftIntResume(a3) ; save resume address
|
||
rts ; return to callers caller, wait for interrupt
|
||
|
||
;_______________________________________________________________________
|
||
; Routine: FDBShiftInt
|
||
; Inputs: A1 - base address of VIA1 (setup by IntHnd)
|
||
; Outputs: A1 - base address of VIA1
|
||
; A3 - pointer to ADBBase
|
||
; ccr.z - result of BTST #vFDBInt,vBufB(a1)
|
||
;
|
||
; Function: handles shift interrupt, resumes asynchronous processing
|
||
;_______________________________________________________________________
|
||
|
||
FDBShiftInt
|
||
movea.l ADBBase,a3 ; point to ADB globals in low memory
|
||
movea.l ShiftIntResume(a3),a0 ; get address to resume at
|
||
eieioSTP
|
||
btst.b #vFDBInt,vBufB(a1) ; test the FDBInt~ status
|
||
eieioSTP
|
||
jmp (a0) ; resume async processing
|
||
|
||
Title 'KbdADB - ADB Manager - ReqDoneVIA'
|
||
|
||
;_______________________________________________________________________
|
||
;
|
||
; Routine: ReqDoneVIA
|
||
; Inputs: none
|
||
;
|
||
; Outputs: D2 - length of receive buffer data
|
||
; D3 - command byte / SRQ flag (bit 31)
|
||
; A2 - pointer to buffer containing receive data
|
||
; A3 - pointer to ADBBase
|
||
;
|
||
;
|
||
; Destroys:
|
||
; Calls: ImplicitRequestDone, ExplicitRequestDone
|
||
;
|
||
; Function: Completion routine for servicing replies from the ADB xcvr.
|
||
;
|
||
;_______________________________________________________________________
|
||
|
||
ReqDoneVIA
|
||
with ADBVars
|
||
move.b FDBAuFlag(a3),d0 ; get the flags
|
||
move.b fDBCmd(a3),d1 ; get the command
|
||
moveq.l #(1<<fDBSRQ),d3 ; mask to test for SRQ pending
|
||
and.b d0,d3 ; isolate the bit
|
||
neg.l d3 ; set bit 31 if SRQ pending
|
||
move.b d1,d3 ; insert the command byte
|
||
|
||
move.w DevMap(a3),d2 ; list of possible address to search <1.2>
|
||
lsr.b #4,d1 ; isolate the device address
|
||
tst.l d3 ; was there an SRQ?
|
||
bpl.s @noSRQ ; if not, don't advance poll address
|
||
|
||
bset.l d1,d2 ; if no other bits set, come back to this one
|
||
@SRQloop addq.b #1,d1 ; try the next address
|
||
andi.b #$0F,d1 ; wrapping around if needed <1.2>
|
||
btst.l d1,d2 ; see if there is a device with that address
|
||
beq.s @SRQloop ; if not, try the next address
|
||
|
||
@updateAddr move.b d1,PollAddr(a3) ; remember where to auto/SRQ poll next <1.2>
|
||
|
||
@skipUpdate lea fDBCnt(a3),a0 ; point to the length byte of the buffer <1.2>
|
||
moveq #0,d2 ; zero extend the length
|
||
move.b (a0)+,d2 ; get length of receive data
|
||
movea.l a0,a2 ; point to the data buffer
|
||
|
||
clr.b FDBAuFlag(a3) ; clear the flags, especially fDBBusy
|
||
btst.l #fDBAPoll,d0 ; see what kind of request completed
|
||
bne.w ImplicitRequestDone ; auto poll data returned, call handler
|
||
bra.w ExplicitRequestDone ; if explicit, call the completion routine
|
||
|
||
@noSRQ btst.l d1,d2 ; see if there is a device with this address <1.2>
|
||
beq.s @skipUpdate ; if not, don't make it the active device <1.2>
|
||
bra.s @updateAddr ; if so, update the poll address <1.2>
|
||
|
||
Title 'KbdADB - ADB Manager - Initialization'
|
||
;_______________________________________________________________________
|
||
;
|
||
; 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
|
||
|
||
;_______________________________________________________________________
|
||
;
|
||
; FDBTask - FDB VBL Task
|
||
;
|
||
;_______________________________________________________________________
|
||
|
||
FDBTask
|
||
RTS ; just return for now
|
||
|
||
;_______________________________________________________________________
|
||
;
|
||
; InitDevT - Initialize the Device Table
|
||
;
|
||
;_______________________________________________________________________
|
||
|
||
InitDevT
|
||
with ADBVars,ADBDeviceEntry
|
||
bsr.s 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.s 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
|
||
|
||
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
|
||
; now setup auto poll for the mouse
|
||
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
|
||
|
||
GE1 jsrROM GEmptyAddr ; get empty address space, D0 gets address (GEmptyAddr)
|
||
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 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.
|
||
|
||
eieioSTP
|
||
tst.b (a0) ; did the device return data
|
||
eieioSTP
|
||
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 devi]
|
||
; 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 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 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
|
||
|
||
;_______________________________________________________________________
|
||
;
|
||
; 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
|
||
|
||
;_______________________________________________________________________
|
||
;
|
||
; Mouse Driver -- generate mouse button events when appropriate and updates
|
||
; mouse temporary position vars.
|
||
;
|
||
; Inputs: A0 - pointer to buffer containing receive data (Pascal string)
|
||
; A2 - Optional data (not used)
|
||
; D0 - command byte (not used)
|
||
;
|
||
;_______________________________________________________________________
|
||
|
||
|
||
MouseDrvr
|
||
lea 1(a0),a1 ; skip over length byte, free up A0
|
||
eieioSTP
|
||
move.b (a1)+,d2 ; get first data byte (button, ∆ Vert)
|
||
eieioSTP
|
||
|
||
; Update the mouse button state
|
||
|
||
move.b MBState,d1 ; get copy of last state
|
||
eor.b d2,d1 ; did it change?
|
||
bpl.s @ButtonDone ; if it didn't, no event
|
||
|
||
; If the mouse button bounces, we don't want it to look like a double click, so if we see
|
||
; a mouse down less than 2 VBLs after a mouse up, we will ignore it, and consider the mouse
|
||
; to still be up. We will never ignore a mouse up event, which could lead to menus hanging
|
||
; and continuous scrolling.
|
||
|
||
move.l Ticks,d1 ; get current system ticks
|
||
sub.l MBTicks,d1 ; compute time since last change
|
||
movea.w #mButUpEvt,a0 ; A0 holds the event (2 = mouse button up)
|
||
moveq.l #-1<<7,d0 ; mask for mouse button bit
|
||
and.b d2,d0 ; just store high bit
|
||
bmi.s @postButton ; if up, post it
|
||
|
||
subq.l #2,d1 ; see if less than 2 VBLs since last mouse up
|
||
blt.s @ButtonDone ; if too short, must be a down bounce, ignore it
|
||
addq.l #2,d1 ; restore change time
|
||
subq.w #mButUpEvt-mButDwnEvt,a0 ; if down, update event number and post it
|
||
|
||
@postButton move.b d0,MBState ; also update the state
|
||
add.l d1,MBTicks ; remember that it just changed
|
||
add.l d1,RndSeed ; randomize our seed
|
||
moveq.l #0,d0 ; no message for PostEvent
|
||
_PostEvent ; post the mouse button event
|
||
@ButtonDone
|
||
|
||
; Update the mouse vertical position
|
||
|
||
add.b d2,d2 ; shift high bit of ∆ into sign
|
||
beq.s @virtDone ; if no change, nothing to update
|
||
asr.b #1,d2 ; shift ∆ back, sign extended
|
||
ext.w d2 ; extend it to a word
|
||
add.w d2,mTemp+v ; update the virtical position
|
||
move.b CrsrCouple,CrsrNew ; note the change
|
||
@virtDone
|
||
|
||
; Update the mouse horizontal position
|
||
|
||
eieioSTP
|
||
move.b (a1),d2 ; get the ∆ Horiz (low 7 bits)
|
||
eieioSTP
|
||
add.b d2,d2 ; shift high bit of ∆ into sign
|
||
beq.s @horizDone ; if no change, nothing to update
|
||
asr.b #1,d2 ; shift ∆ back, sign extended
|
||
ext.w d2 ; extend it to a word
|
||
add.w d2,mTemp+h ; update the horizontal position
|
||
move.b CrsrCouple,CrsrNew ; note the change
|
||
@horizDone
|
||
rts ; mouse driver done
|
||
|
||
;______________________________________________________________________
|
||
;
|
||
; KbdInstall - allocate memory for keyboard information and put in ADB record,
|
||
; loading resources as necessary.
|
||
;
|
||
;______________________________________________________________________
|
||
|
||
; 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
|
||
|
||
KbdInstall
|
||
with ADBDeviceEntry
|
||
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
|
||
ENDPROC
|
||
END
|
||
|