; ; File: DockingMgr.a ; ; Contains: support for docking portable Macintoshes into desktop docking modules ; ; Written by: Steve Christensen ; ; Copyright: © 1992-1993 by Apple Computer, Inc. All rights reserved. ; ; This file is used in these builds: ROM ; ; Change History (most recent first): ; ; 12/13/93 PN Roll in KAOs and Horror changes to support Malcom and AJ ; machines. ; 9/2/93 KH Rolled in the Horror changes (finally) ; 9/2/93 SKH My fixes are back in now... ; 9/1/93 SKH Backed out my changes until I was certain they wouldn't break builds. ; 9/1/93 SKH Rolled in Horror version of docking code (with dock cache control stuff) ; 12/4/92 GD Added a forRomulator conditional so that we don't (re)initialize ; the SCC when debugging. ; 11/20/92 SWC Rolled in the rest of the Horror changes. Changed INCLUDEs to ; use new filenames. ; 8/13/92 SWC Added a new selector call in SetupDockBases to do any last ; minute pre-boot initialization. This is provided as a means of ; allowing the config ROMs to patch up anything we might have ; forgotten. ; 8/11/92 SWC Exported DockInitSCC and fixed it to preserve its registers. ; 8/10/92 SWC Specifically check for (and handle) the ‘docking slot’ selector ; in DockingDispatch so handlers, etc., have a way of determining ; which slot they're in. ; 7/29/92 SWC Fixed a typo (ended up looking at the wrong thing). ; 7/27/92 SWC Block checking for eject until after we get to the Finder. ; 7/24/92 SWC Added a check if a bar was added during sleep that's not ; supposed to be added then, and if so, the next time we wake up, ; remove its handler, etc. (takes care of the case of trying to ; add it multiple times). ; 7/8/92 SWC Made some changes to GracefulShutdown to make it better at ; successfully shutting down. DockingFilter now prevents waking up ; if we'd have to run without the LCD display since we currently ; can't handle removing a monitor from the desktop. ; 7/1/92 SWC Reset internal [and external] SCCs in SetHardwareBases so we ; won't get spurious interrupts from the unused SCC when a bar ; with another SCC is connected during sleep. ; 6/29/92 HJR SWC/Fixed my fix to Dave Wong's external32bit code from . ; 6/29/92 SWC Added in code to allow us to do a graceful shutdown when the ; eject button is pressed on a docking station. ; 6/25/92 SWC Pulled out the save/restore A2 code in since that's all ; fixed now. TravelBarHandler now returns SWIM2 power status if a ; SWIM2 exists. ; 6/18/92 SWC As part of our continuing incestuous relationship with the Power ; Manager, clear the clamshellClosed flag in the ‘sleep denied’ ; Notification Manager completion routine so we won't try to keep ; posting messages until the current one goes away. Added ; RegisterVideo to the wakeup installation so we'll have a hook to ; let the system know about the addition of a new video device. It ; currently does nothing. ; 6/15/92 ag Added code to set the external32bit flag in the gdflags of ; gdevice data structure based the information from the slot ; manager. ; 6/3/92 SWC Cleaned up some of my duplicated code. Temporarily save/restore ; A2 around calls to the docking handler because the DeskBar and ; Gemini docking handlers trash it (a bug to be fixed). ; 6/1/92 HJR Changed CheckConnectNiagra for our current implementation. Call ; InitDefGamma in vAddVideoDevice. ; 5/29/92 SWC Set up docking support for Dartanian. Added a routine to notify ; the user that they tried to attach a bar during sleep that's not ; supposed to be added during sleep. ; 5/20/92 SWC Now pass the CPU's clock speed to the docking handler so it can ; configure any of its hardware that cares. ; 5/8/92 SWC Added a new routine to call Alex Kazim's Comm Toolbox hack to ; resolve which serial ports are currently available. Abort wakeup ; docking handler installation if that kind of bar is not allowed ; to be added during sleep. ; 10/22/92 CS Change some branch short instructions to branches. ; <1> 5/16/92 kc first checked in ; 4/22/92 SWC Changed DockingWakeup so that it will only add video if video is ; supported AND a monitor is connected, so we can handle the case ; of adding a bar to use the floppy disk and then remove it when ; we're done (with video it would be locked in until shutdown). ; Added a new routine (DockingSleepDenied) to put up a ; Notification Manager dialog to let the user know that they can't ; put the system to sleep when a bar won't allow it. ; 4/13/92 SWC Added a flag to show that a bar was added during sleep. Added a ; check for eject from a docking station. Did some code cleanup. ;
4/3/92 SWC Increased the overpatch padding size to 4K. ;
3/20/92 SWC Rolled in Dave Wong's new Slot Manager support, and fixed how ; the sleep and wakeup code works. Vectored some more routines. ; Increased the overpatch file size from 1K to 2K since it ; overflowed. ;

3/6/92 SWC Enable/disable docking slot interrupts depending on whether or ; not a bar is connected. Make the built-in docking handlers ; return the SCC ports available when no bar is connected. ;

3/3/92 SWC Moved the check for SCSI Disk Mode to SCSIDiskMode.a since ; that's now part of the build, and the logical place to put it. ;

2/17/92 SWC Load the bar's docking attributes into the Power Manager globals ; so we can decide if we want to sleep, power cycle, etc. ;

2/14/92 SWC First checked in. PRINT OFF LOAD 'StandardEqu.d' INCLUDE 'HardwarePrivateEqu.a' INCLUDE 'UniversalEqu.a' INCLUDE 'GestaltEqu.a' INCLUDE 'MFPrivate.a' INCLUDE 'Notification.a' INCLUDE 'PowerPrivEqu.a' INCLUDE 'Processes.a' INCLUDE 'ROMEqu.a' INCLUDE 'Slots.a' INCLUDE 'SCSI.a' INCLUDE 'SCSIPriv.a' INCLUDE 'Shutdown.a' INCLUDE 'DockingEqu.a' PRINT ON BLANKS ON STRING ASIS MACHINE MC68020 Unimplement EQU $A89F ; _Unimplemented trap SyncIdleTime EQU $ABF7 DockingMgr PROC EXPORT EXPORT DockingDispatch, InitDocking, SetupDockBases, DockInitSCC, GracefulShutdown EXPORT DockingSleep, DockingWakeup, DockingSleepDenied, DockingWakeupDenied IMPORT InitSCC, CacheFlush WITH DockingGlobRec, NMRec, PmgrRec, pmCommandRec, scsiGlobalRecord, SEBlock, SpBlock WITH DecoderInfo, DecoderKinds, NubusInfo, ProductInfo, ProcessInfoRec ;__________________________________________________________________________________________________ ; ; pascal long DockingDispatch(OSType selector, long params) ; ; dispatches to the appropriate docking handler ;__________________________________________________________________________________________________ DockingDispatch MOVEA.L DockingGlobals,A0 ; point to our variables MOVEA.L dockingHandler(A0),A1 ; and get the address of our handler CMPI.L #dockDockingSlot,8(SP) ; is this the ‘docking slot’ selector? BNE.S @CallHandler ; -> no, pass it thru to the docking handler MOVEA.L (SP)+,A1 ; pop the return address ADDQ.W #8,SP ; and toss the parameters MOVEQ #0,D0 ; MOVE.B dockingSlotNum(A0),D0 ; get the docking slot number MOVE.L D0,(SP) ; and return it as the result @CallHandler JMP (A1) ; call the docking handler or just return ;__________________________________________________________________________________________________ ; ; pascal long NoBoardHandler(OSType selector, long params) ; ; docking handler when no docking module is connected ;__________________________________________________________________________________________________ NoBoardHandler MOVEA.L (SP)+,A1 ; pop the return address ADDQ.W #4,SP ; and toss params MOVEQ #0,D0 ; assume an unsupported selector CMPI.L #dockSCCPorts,(SP)+ ; is it the port list selector? BNE.S @Done ; -> nope MOVEA.L DockingGlobals,A0 ; point to the Docking Manager globals MOVE.L builtInSCCPorts(A0),D0 ; get which ports are built in @Done MOVE.L D0,(SP) ; return the selector result JMP (A1) ;__________________________________________________________________________________________________ ; ; pascal long TravelBarHandler(OSType selector, long params) ; ; docking handler for a travel bar (since it has no configuration ROM) ;__________________________________________________________________________________________________ TravelBarHandler MOVEA.L (SP)+,A1 ; pop the return address ADDQ.W #4,SP ; and toss params MOVE.L (SP)+,D1 ; get the selector MOVEQ #0,D0 ; assume an unsupported selector MOVEA.L DockingGlobals,A0 ; point to the Docking Manager globals CMPI.L #dockSCCPorts,D1 ; is it the port list selector? BNE.S @NotSCCPorts ; -> nope MOVE.L builtInSCCPorts(A0),D0 ; get which ports are built in BRA.S @Done @NotSCCPorts CMPI.L #dockPowerStatus,D1 ; is it a power status call? BNE.S @NotPowerStatus ; -> no BSR.S @TestForSWIM ; yes, do we have a SWIM2? BNE.S @Done ; -> no MOVEQ #1< nope MOVE.L #(1< nope ORI.L #(1< nope, we don't have a SWIM2 connected MOVEQ #0,D1 @NoSWIM2 MOVEA.L D2,SP ; trash the exception frame if we bus errored MOVE.L (SP)+,BusErrVct ; restore the previous bus error vector MOVE (SP)+,SR ; re-enable interrupts TST.L D1 ; set the CCR RTS ;__________________________________________________________________________________________________ ; ; Routine: InitDocking ; ; Inputs: none ; ; Outputs: none ; ; Trashes: none ; ; Function: initializes the Docking Manager if this machine has a slot allocated for docking ;__________________________________________________________________________________________________ InitDocking MOVEM.L D0-D2/A0-A2,-(SP) MOVEA.L UnivInfoPtr,A1 ; point to this machine's ProductInfo table ADDA.L NuBusInfoPtr(A1),A1 ; and from there, point to the NubusInfo table MOVEQ #$0F,D1 @SearchLoop BTST #dockingSlot,(A1)+ ; is this slot used for docking? DBNE D1,@SearchLoop ; -> keep looping if not BEQ @NoDocking ; -> no docking slots SUBI.W #$0F,D1 ; calculate the real slot number NEG.W D1 MOVEQ #DockingGlobalSize/2,D0 ; allocate docking globals ADD.L D0,D0 _NewPtr ,SYS,CLEAR BNE @NoDocking ; -> couldn't do it, so bail on docking support MOVE.L A0,DockingGlobals ; save the pointer MOVEA.L A0,A2 LEA NoBoardHandler,A1 MOVE.L A1,(A0)+ ; default docking handler = no board MOVE.B D1,(A0)+ ; save the docking slot number ; setup to check if a docking station's eject button has been hit... LEA ejectVBLTask+vblCount+2(A2),A0 MOVE.W #ejectVBLCount,-(A0) ; vblCount LEA CheckForEject,A1 MOVE.L A1,-(A0) ; vblAddr ADDQ.W #vType,-(A0) ; vblType SUBQ.W #vblType-vblink,A0 ; point to the VBL task element _VInstall ; and install the task LEA ejectNMEntry(A2),A0 ; set up the eject Notification Manager record LEA EjectNMResponse,A1 ; response procedure BSR.S @SetupNMRec LEA sleepNMEntry(A2),A0 ; set up the sleep Notification Manager record LEA SleepNMResponse,A1 ; response procedure BSR.S @SetupNMRec LEA wakeupNMEntry(A2),A0 ; set up the wakeup Notification Manager record LEA WakeupNMResponse,A1 ; response procedure BSR.S @SetupNMRec ; initialize the vector table... MOVEA.L UnivInfoPtr,A1 ; point to this machine's ProductInfo table MOVE.B DecoderKind(A1),D0 ; and get the decoder type LEA DockingVectorTable-4,A1 @NextDecoder ADDQ.W #4,A1 ; skip over the offset to this decoder's table MOVE.W (A1)+,D1 ; get the next decoder BMI.S @FoundTable ; -> end of table: use default vectors CMP.B D0,D1 ; is this the correct table? BNE.S @NextDecoder ; -> no, try the next one @FoundTable ADDA.L (A1),A1 ; point to the vector table LEA builtInSCCPorts(A2),A0 MOVE.L (A1)+,(A0)+ ; copy the built-in SCC ports @InitDispatch MOVE.L (A1)+,D1 ; get the next offset BEQ.S @InitDone ; -> end of table ADD.L A1,D1 ; convert it into an absolute address MOVE.L D1,(A0)+ ; and stuff it into our vector table BRA.S @InitDispatch ; install the docking handler... @InitDone MOVEQ #0,D1 ; (boot call) BSR InstallHandler ; now install the correct handler @Done MOVEM.L (SP)+,D0-D2/A0-A2 RTS @SetupNMRec ADDQ.W #nmType,qType(A0) ; queue type MOVEQ #-1,D0 ; sound: use system sound MOVE.L D0,nmSound(A0) MOVE.L A1,nmResp(A0) ; response procedure RTS @NoDocking MOVE.W #Unimplement,D0 ; get the _Unimplemented trap's address _GetTrapAddress ,NEWTOOL MOVE.W DockTrap,D0 ; and turn off docking _SetTrapAddress ,NEWTOOL BRA.S @Done ;__________________________________________________________________________________________________ ; ; Routine: SetupDockBases ; ; Inputs: none ; ; Outputs: none ; ; Trashes: D0-D2, A0-A1 ; ; Function: using the current bar's hardware attributes, initialize "standard" chip base addresses ; (this is called after enough of the hardware managers are initialized to be able to ; stuff base addresses into their globals) ;__________________________________________________________________________________________________ SetupDockBases BSR.S DockingDispatchExists ; does the _DockingDispatch trap exist? BEQ Done ; -> nope, no special initialization is required MOVE.L A2,-(SP) ; MOVEA.L DockingGlobals,A2 ; BSR GetDockingAttributes ; get the docking attributes MOVEA.L (SP)+,A2 ; MOVE.L #dockHardwareAttr,D0 ; get the hardware attributes BSR DockStatus BSR SetHardwareBases ; and initialize any chip base addresses we care about MOVE.L #dockBootHook,D0 ; do any last minute pre-boot setup BRA DockStatus ; ;__________________________________________________________________________________________________ ; ; Routine: DockingDispatchExists ; ; Inputs: none ; ; Outputs: CCR - BNE: _DockingDispatch trap exists ; ; Trashes: D0, A0-A1 ; ; Function: checks if the _DockingDispatch trap exists on this machine ;__________________________________________________________________________________________________ DockingDispatchExists MOVE.W #Unimplement,D0 ; does the _DockingDispatch trap exist? _GetTrapAddress ,NEWTOOL MOVEA.L A0,A1 MOVE.W DockTrap,D0 _GetTrapAddress ,NEWTOOL CMPA.L A0,A1 RTS ;__________________________________________________________________________________________________ ; ; Routine: DockingSleep ; ; Inputs: A1 - return address ; ; Outputs: A1 - return address ; ; Trashes: D0-D2 ; ; Function: calls the handler to save its hardware state before going to sleep. ;__________________________________________________________________________________________________ DockingSleep MOVE.L ([DockingGlobals],jDockingSleep),-(SP) RTS vDockingSleep MOVEM.L A0-A1,-(SP) MOVE.L #dockSleepSave,D0 ; have the handler save the bar's state BSR DockStatus MOVE.L D0,([DockingGlobals],savedSleepState) ; save the pointer to the state MOVE.L PMgrBase,a0 ; get PMgr globals BCLR #HDPowerOn,PmgrFlags(a0); clear the hard disk semaphor again, to make sure CLR.L LastHD(A0) ; clear LastHD too MOVEM.L (SP)+,A0-A1 JMP (A1) ;__________________________________________________________________________________________________ ; ; Routine: DockingWakeup ; ; Inputs: A1 - return address ; ; Outputs: A1 - return address ; ; Trashes: D0-D2 ; ; Function: Checks if a docking module as been added, changed, or removed across sleep. ; If it's been added or changed, clean up after any old handlers and install a new one. ; If it's been removed, clean up after its handler and install the "no board" handler. ;__________________________________________________________________________________________________ DockingWakeup MOVE.L ([DockingGlobals],jDockingWakeup),-(SP) RTS vDockingWakeup @savedRegs REG D3-D4/A0-A2 MOVEM.L @savedRegs,-(SP) MOVEA.L DockingGlobals,A2 ; point to our globals BCLR #dockForceRemoval,dockingFlags(A2) ; did user try to install a "no sleep add" bar? BNE.S @SwitchBars ; -> yes, force removal since they could try multiple times BSR CheckConnect ; is a docking module currently attached? BEQ.S @SwitchBars ; -> no ; a module is currently connected; see if it's been added or changed... BSR CheckBarChanged ; has the bar changed across sleep? BNE.S @SwitchBars ; -> yes, do the switch MOVE.L #dockWakeupRestore,D0 ; restore the state of anything that was turned off MOVEA.L savedSleepState(A2),A0 BSR DockControl CLR.L savedSleepState(A2) ; mark the state info as updated MOVE.L #dockHardwareAttr,D0 ; get the hardware attributes BSR DockStatus ; BSR SetHardwareBases ; force an SCC initialization BRA @Done ; no docking module is connected or a new one has been installed, so tell its software... @SwitchBars BSR @GetNubusSlots ; find out if there are any NuBus connectors on this bar MOVE.L #dockRemoved,D0 ; tell the board software that its board is gone BSR DockStatus ; (if it was previously installed) MOVE.L savedSleepState(A2),D0 ; Get the state info. Cmpi.l #-1,D0 ; Was it -1? BEQ.S @NoSavedState1 ; -> yes Tst.l D0 ; Was it zero? Beq.s @NoSavedState ; -> yes MOVEA.L D0,A0 ; no, get the pointer _DisposPtr ; and get rid of the block @NoSavedState1 CLR.L savedSleepState(A2) ; mark the state info as updated @NoSavedState ; clean up after any slots that went away (including the docking slot)... Moveq #0,D1 ; Always do Slot #0 first. Btst D1,D3 ; If Slot #0 doesn’t to be removed, Beq.s @SkipZeroRmv ; then just go on. Bsr RemoveVideo ; Unregister Slot #0’s video. Bsr RemoveSlot ; And make slot zero go away. @SkipZeroRmv MOVEQ #sLastSlot,D1 @RemoveSlot BTST D1,D3 ; does this slot need to be removed? BEQ.S @DontRemove ; -> nope, skip it BSR RemoveVideo ; unregister any video associated with this slot BSR RemoveSlot ; make the slot go away @DontRemove Subq #1,D1 ; decrement down to… Bne.s @RemoveSlot ; …next slot (skipping zero) ; set everything back up for the new bar... MOVE.B dockingSlotNum(A2),D1 ; install the bar in the docking slot BSR AddSlot BSET #dockSleepAddition,dockingFlags(A2) ; remember that this bar was added during sleep MOVEQ #(1< BNE.S @Done ; -> no, bail out MOVE.L #dockHardwareAttr,D0 ; get the hardware attributes BSR DockStatus SWAP D0 ; and use the wakeup attributes MOVE.W D0,D4 ; ; TST.B D4 ; video support AND monitor plugged in? BPL.S @NoBarVideo ; -> nope BSR.S @GetNubusSlots ; find out if there are any NuBus connectors on this bar Moveq #0,D1 ; Always do Slot #0 first (it’s never the docking slot). Btst D1,D3 ; If Slot #0 doesn’t to be removed, Beq.s @SkipZeroAdd ; then just go on. Bsr AddSlot ; Make the slot appear. Bsr AddVideoDevice ; Initialize its video. Beq.s @SkipZeroAdd ; If failed, skip. Bsr RegisterVideo ; Otherwise, register the new device. @SkipZeroAdd MOVEQ #sLastSlot,D1 @AddSlot BTST D1,D3 ; does this slot need to be added? BEQ.S @DontAdd ; -> nope, skip it CMP.B dockingSlotNum(A2),D1 ; is this the docking slot? BEQ.S @IsAdded ; -> yes, it's already added: just do the video thing BSR AddSlot ; make the slot appear @IsAdded BSR AddVideoDevice ; and initialize its video (if any) BEQ.S @DontAdd ; -> no video or error BSR RegisterVideo ; register the new device with the system @DontAdd Subq #1,D1 ; decrement down to… Bne.s @AddSlot ; …next slot (skipping zero) @NoBarVideo MOVE.W D4,D0 ; get the wakeup attributes BSR.S SetHardwareBases ; and use them to setup base hardware addresses BSR ResolveSerialPorts ; make sure serial ports are properly registered Move.l #dockFlush,D0 ; We’re done waking up, Bsr DockStatus ; so alert the handler. @Done MOVEM.L (SP)+,@savedRegs JMP (A1) @GetNubusSlots MOVE.L #dockNuBusConnectors,D0 ; find out if there are any NuBus connectors on this bar BSR DockStatus MOVE.L D0,D3 ; and save which slots they're in MOVEQ #0,D0 MOVE.B dockingSlotNum(A2),D0 ; mark the docking slot as well BSET D0,D3 RTS ;__________________________________________________________________________________________________ ; ; Routine: SetHardwareBases ; ; Inputs: D0 - bitmap of hardware available on the bar ; ; Outputs: none ; ; Trashes: D0-D2, A0-A1 ; ; Function: handles installation of hardware base addresses for "standard" chips on the bar ;__________________________________________________________________________________________________ SetHardwareBases MOVE.L ([DockingGlobals],jSetHardwareBases),-(SP) RTS vSetHardwareBases @savedRegs REG A2-A4 MOVEM.L @savedRegs,-(SP) MOVEA.L UnivInfoPtr,A0 ; point to the DecoderInfo table ADDA.L ProductInfo.DecoderInfoPtr(A0),A0 MOVEM.L SCCRdAddr(A0),A0-A1 ; copy the internal SCC's base addresses MOVEM.L A0-A1,SCCRd ; to the low-mem vectors BTST #dockHasSCC,D0 ; does the bar contain a SCC? BEQ.S @NoSCC ; -> no MOVE.L #dockSCCReadAddr,D0 ; call the handler to get the SCC base read address BSR DockStatus BEQ.S @NoSCC ; -> it returned zero (confusion), so just use built-in MOVE.L D0,A3 ; save the SCC base read address MOVE.L #dockSCCWriteAddr,D0 ; call the handler to get the SCC base write address BSR DockStatus BEQ.S @NoSCC ; -> it returned zero (confusion), so just use built-in MOVE.L D0,A4 ; save the SCC base write address BSR.S DockInitSCC ; reset the internal SCC so it doesn't cause us trouble MOVEM.L A3-A4,SCCRd ; stuff in the new SCC base addresses @NoSCC BSR.S DockInitSCC ; initialize the SCC we'll be using MOVEA.L SCSIGlobals,A2 MOVE.L #dockSCSIAddr,D0 ; call the handler to get the SCSI registers base address BSR DockStatus MOVE.L D0,base5380_2(A2) ; and save it in the SCSI Manager's variables BNE.S @HaveSCSI2 ; -> second SCSI chip's base is valid MOVEQ #-1,D0 ; otherwise set SCSI2Base to -1 @HaveSCSI2 MOVE.L D0,SCSI2Base MOVE.L #dockSCSIDMAAddr,D0 ; call the handler to get the SCSI DMA base address BSR DockStatus MOVE.L D0,pdma5380_2(A2) ; and save it in the SCSI Manager's variables MOVE.L #dockSCSIHskAddr,D0 ; call the handler to get the SCSI handshake base address BSR DockStatus MOVE.L D0,hhsk5380_2(A2) ; and save it in the SCSI Manager's variables MOVEM.L (SP)+,@savedRegs Done RTS DockInitSCC MOVEM.L D0-D2/A0-A2,-(SP) ; BSR DockingDispatchExists ; is the Docking Manager initialized? BEQ.S @Done ; -> no, skip it IF forRomulator THEN TestInRam a0 ; are we running the ROM image from RAM? bne.s @Done ; if so, then don't init the SCC ENDIF MOVEQ #sccOn-256,D0 ; turn SCC power on BSR.S @SCCPower BSR.L InitSCC ; reset the SCC so it doesn't cause us trouble MOVEQ #sccOff,D0 ; turn SCC power off BSR.S @SCCPower ; @Done MOVEM.L (SP)+,D0-D2/A0-A2 ; RTS ; @SCCPower IF hasPwrControls THEN IF isUniversal THEN TestFor hwCbPwrMgr ; does this machine have a Power Manager? BEQ.S @NoPMGR ; -> nope, skip ENDIF MOVE.B D0,-(SP) MOVE.L SP,-(SP) ; pmRBuffer MOVE.L (SP),-(SP) ; pmSBuffer MOVE.W #1,-(SP) ; pmLength = 1 byte to send MOVE.W #powerCntl,-(SP) ; pmCommand = power control MOVEA.L SP,A0 ; point to the parameter block _PMgrOp ; turn SCC power on or off LEA pmRBuffer+4+2(SP),SP ; toss the parameter block and buffer @NoPMGR ENDIF RTS ;__________________________________________________________________________________________________ ; ; Routine: CheckConnect ; ; Inputs: A2 - pointer to Docking Manager's globals ; ; Outputs: CCR - BNE: bar connected ; ; Trashes: A0, D0 ; ; Function: checks if a connector bar is currently plugged in ;__________________________________________________________________________________________________ CheckConnect MOVE.L jCheckConnect(A2),-(SP) RTS vCheckConnect MOVEQ #0,D0 ; return BEQ as default case RTS ;__________________________________________________________________________________________________ ; ; Routine: TurnOffBarIO, TurnOnBarIO ; ; Inputs: A2 - pointer to Docking Manager's globals ; ; Outputs: none ; ; Trashes: A0, D0 ; ; Function: turns bar I/O clock on or off ;__________________________________________________________________________________________________ TurnOffBarIO MOVE.L jTurnOffBarIO(A2),-(SP) RTS TurnOnBarIO MOVE.L jTurnOnBarIO(A2),-(SP) RTS ;__________________________________________________________________________________________________ ; ; Routine: InstallHandler ; ; Inputs: D1 - startup/wakeup flag to pass to docking handler's initialization code ; - (if D1.l is -1, then we just want to reload the docking attributes) ; A2 - pointer to Docking Manager's globals ; ; Outputs: D0 - docking attributes returned by the new bar ; ; Trashes: D0-D2, A0-A1 ; ; Function: installs the appropriate support code into the docking selector for the ; currently installed board (or no board) ;__________________________________________________________________________________________________ InstallHandler MOVE.L jInstallHandler(A2),-(SP) RTS vInstallHandler Cmpi.l #-1,D1 ; If we just want to reload the docking attributes, Beq.s GetDockingAttributes ; then go there now. MOVEA.L NoBoardAddr(A2),A1 ; default to "no board" BSR.S TurnOffBarIO ; turn off bar I/O BSR.S CheckConnect ; is a board connected? BEQ.S @DoInstall ; -> nope BSR.S TurnOnBarIO ; turn on bar I/O BSR GetDockingHandler ; try to load the docking handler for this bar BEQ.S @DoInstall ; -> got it MOVEA.L TravelBarAddr(A2),A1 ; bar doesn't have a handler, so use the travel bar's @DoInstall MOVEA.L dockingHandler(A2),A0 ; get the address of the old docking handler MOVE.L A1,dockingHandler(A2) ; and install the new one CMPA.L noBoardAddr(A2),A0 ; is the old handler the "no board" one? BEQ.S @Done ; -> yes, we're done CMPA.L travelBarAddr(A2),A0 ; is the old handler the travel bar one? BEQ.S @Done ; -> yes, we're done _DisposPtr ; dispose of the block it occupied @Done IF NOT forRomulator THEN ; MOVE.L D1,-(SP) ; save startup/wakeup flag Move.l #dockCacheStatus,D0 ; Set up to determine if an external cache… Movea.l #dockCacheCPU,A0 ; …works with our CPU. Bsr.s DockControl ; Do it. MOVE.L (SP)+,D1 ; restore startup/wakeup flag Moveq #0,D2 ; Clear D2 for good measure. Move.b CPUFlag,D2 ; Get the current CPU flag. Addq #1,D2 ; De-normalize it. Btst D2,D0 ; If we can deal with this cache, Bne.s @UseExtCache ; then do so. BSET #dockIgnoreExtCache,D1 ; Otherwise, just ignore it. @UseExtCache ENDIF ; MOVE.L #dockInit,D0 ; call the new handler to initialize itself… MOVEA.L D1,A0 ; …with the appropriate flags BSR.S DockControl ;

IF hasPwrControls THEN ;

IF isUniversal THEN ;

TestFor hwCbPwrMgr ; does this machine have a Power Manager?

BEQ.S GetDockingAttributes ; -> nope, skip

ENDIF ;

MOVEQ #PowerDispRec.CPUSpeedDisp,D0 ; _PowerDispatch ; get the CPU's maximum and current speed in MHz EXT.L D0 ; sign-extend it to a long BMI.S GetDockingAttributes ; -> either very fast, or selector is not supported :) MOVEA.L D0,A0 ; stuff it into ‘params’ MOVE.L #dockCPUSpeed,D0 ; go tell the docking handler what it is BSR.S DockControl ; ENDIF ;

GetDockingAttributes MOVE.L #dockDockingAttr,D0 ; get the docking attributes for this bar

BSR.S DockStatus ;

BTST #dockSleepAddition,dockingFlags(A2) ; is this a startup or wakeup case? BNE.S @SaveAttr ; -> wakeup: pass the attributes unmodified BCLR #dockNoWakeup,D0 ; startup: if we go to sleep, we want to wake up again @SaveAttr BSR.S DockingFilter ; do any filtering before we save it IF hasPwrControls THEN ;

IF isUniversal THEN ;

TestFor hwCbPwrMgr ; does this machine have a Power Manager?

BEQ.S @NoPMgr ; -> nope, skip

ENDIF ;

MOVEA.L PmgrBase,A1 ; and save them in the Power Manager's globals

MOVE.B D0,PmgrRec.dockFlags(A1);

@NoPMgr ;

ENDIF ;

RTS ;

;__________________________________________________________________________________________________ ; ; Routine: DockStatus,DockControl ; ; Inputs: D0 - docking selector ; A0 - parameters for control calls (nil for status calls) ; ; Outputs: D0 - function result ; ; Trashes: D1-D2, A0-A1 ; ; Function: executes the handler code for the currently installed docking module ;__________________________________________________________________________________________________ DockStatus SUBA.L A0,A0 ; no parameters for status calls DockControl SUBQ.W #4,SP ; result MOVE.L D0,-(SP) ; docking selector MOVE.L A0,-(SP) ; params DockTrap _DockingDispatch ; call the handler MOVE.L (SP)+,D0 ; get the result RTS ;__________________________________________________________________________________________________ ; ; Routine: DockingFilter ; ; Inputs: D0 - docking attributes returned by the bar ; A2 - pointer to Docking Manager's globals ; ; Outputs: D0 - filtered docking attributes ; ; Trashes: D1,D2,A0,A1 ; ; Function: filters the docking attributes so we can decide how to behave depending on what kind ; of system software support we have (currently we don't have much) ;__________________________________________________________________________________________________ DockingFilter MOVE.L jDockingFilter(A2),-(SP) RTS vDockingFilter MOVE.L D0,-(SP) MOVE.L #dockHardwareAttr,D0 ; get the hardware attributes BSR DockStatus MOVE.L D0,D1 MOVE.L (SP)+,D0 BTST #dockSleepAddition,dockingFlags(A2) ; is this a startup or wakeup case? BEQ.S @Startup ; -> wakeup SWAP D1 ; use the wakeup hardware attributes BTST #dockNoLCDScreen,D0 ; do we need to lose the LCD screen? BEQ.S @Startup ; -> no BSET #dockNoWakeup,D0 ; yes, we can't wakeup since we don't support screen removal @Startup ANDI.W #(1< no BSET #dockNoSleep,D0 ; yes, we don't let it sleep @Done RTS ;__________________________________________________________________________________________________ ; ; Routine: CheckBarChanged ; ; Inputs: A2 - pointer to Docking Manager's globals ; ; Outputs: CCR - BNE: bar has changed ; ; Trashes: A0, D0 ; ; Function: checks whether or not the currently connected bar is the same one we think is connected ;__________________________________________________________________________________________________ CheckBarChanged MOVE.L jCheckBarChanged(A2),-(SP) RTS vCheckBarChanged LEA -spBlockSize(SP),SP ; allocate a parameter block on the stack MOVEA.L SP,A0 ; and point to it MOVE.B dockingSlotNum(A2),spSlot(A0) ; spSlot = docking slot * _CheckSlot ; find the board sResource MOVEQ #$27,D0 _SlotManager LEA spBlockSize(SP),SP ; clean up the stack RTS ;__________________________________________________________________________________________________ ; ; Routine: AddSlot ; ; Inputs: A2 - pointer to Docking Manager's globals ; D1 - slot number ; ; Outputs: CCR - BNE: bar has changed ; ; Trashes: A0, D0 ; ; Function: given that a slot is currently empty, sets up the slot so we can use it ;__________________________________________________________________________________________________ AddSlot MOVE.L jAddSlot(A2),-(SP) RTS vAddSlot MOVEQ #spBlockSize/2-1,D0 ; allocate a cleared parameter block on the stack @ClearBlock CLR.W -(SP) ; DBRA D0,@ClearBlock ; MOVEA.L SP,A0 ; and point to it MOVE.B D1,spSlot(A0) ; spSlot = slot to add * _AddCard ; initialize a newly-installed card MOVEQ #$1E,D0 _SlotManager LEA spBlockSize(SP),SP ; clean up the stack RTS ;__________________________________________________________________________________________________ ; ; Routine: RemoveSlot ; ; Inputs: A2 - pointer to Docking Manager's globals ; D1 - slot number ; ; Outputs: none ; ; Trashes: A0, D0 ; ; Function: cleans up a slot after a bar has gone away ;__________________________________________________________________________________________________ RemoveSlot MOVE.L jRemoveSlot(A2),-(SP) RTS vRemoveSlot MOVEQ #spBlockSize/2-1,D0 ; allocate a cleared parameter block on the stack @ClearBlock CLR.W -(SP) ; DBRA D0,@ClearBlock ; MOVEA.L SP,A0 ; and point to it MOVE.B D1,spSlot(A0) ; spSlot = slot to kill * _RemoveCard ; throw everything away MOVEQ #$1F,D0 _SlotManager LEA spBlockSize(SP),SP ; clean up the stack RTS ;__________________________________________________________________________________________________ ; ; Routine: GetDockingHandler ; ; Inputs: A2 - pointer to Docking Manager's globals ; ; Outputs: A1 - pointer to docking handler if it's found ; CCR - BNE: couldn't load the docking handler ; ; Trashes: A0, D0-D1 ; ; Function: tries to load the docking handler if it can find one ;__________________________________________________________________________________________________ GetDockingHandler MOVE.L jGetDockingHandler(A2),-(SP) RTS vGetDockingHandler LEA -spBlockSize(SP),SP ; allocate a parameter block on the stack MOVEA.L SP,A0 ; and point to it MOVE.W #CatDock,spCategory(A0) ; spCategory = docking handler CLR.W spCType(A0) ; spCType = 0 CLR.W spDrvrSW(A0) ; spDrvrSW = 0 CLR.W spDrvrHW(A0) ; spDrvrHW = 0 MOVE.B #7,spTBMask(A0) ; spTBMask = mask cType, DrSW, DrHW MOVE.B dockingSlotNum(A2),spSlot(A0) ; spSlot = docking slot CLR.B spId(A0) ; spId = 0 CLR.B spExtDev(A0) ; no external devices CLR.W spHwDev(A0) ; spHWDev = 0 Clr.l spParamData(A0) ; (The docking sRsrc must be enabled.) Bset #foneslot,spParamData+3(A0) ; Limit search to this slot. _GetTypeSRsrc ; Get the spsPointer. BNE.S @NoHandler ; -> can't find a docking handler MOVE.B #sRsrcDock,spId(A0) ; spId = docking handler _SGetBlock ; load the docking handler into the system heap BNE.S @NoHandler ; -> couldn't do it MOVEA.L spResult(A0),A1 ; get the address of the docking handler Bsr.l CacheFlush ; Flush those caches (trashes reg D1). Moveq #0,D0 ; Make sure we return BEQ here. @NoHandler LEA spBlockSize(SP),SP ; toss the parameter block RTS ;__________________________________________________________________________________________________ ; ; Routine: AddVideoDevice ; ; Inputs: A2 - pointer to Docking Manager's globals ; D1 - slot number ; ; Outputs: D0 - video driver's refNum ; CCR - BNE: video device was successfully installed ; ; Trashes: D0, D2, A0, A1 ; ; Function: Looks for a video driver in the specified slot. If it finds one, it installs it, ; and then sets up and initializes a GDevice for that monitor. ;__________________________________________________________________________________________________ AddVideoDevice MOVE.L jAddVideoDevice(A2),-(SP) RTS AVStack RECORD {A6Save},DECREMENT result DS.W 1 A6Save DS.L 1 driverName DS.B 256 sExecBlock DS.B seBlockSize slotPB DS.B spBlockSize AVStackSz EQU * ENDR WITH AVStack vAddVideoDevice @savedRegs REG D1/D3/A2-A3 ; MOVEM.L @savedRegs,-(SP) ; CLR.W -(SP) ; assume we can't setup a video device LINK A6,#AVStackSz ; allocate a parameter block on the stack MOVEA.L SP,A0 ; and point to it MOVEQ #1< couldn't find one MOVEA.L spsPointer(A0),A2 ; save ptr to sRsrc LEA driverName(A6),A1 ; point to the driver name string MOVE.L A1,spResult(A0) _sReadDrvrName ; get the driver's name BNE @NoDriver ; -> couldn't find it MOVE.W spSlot(A0),sExecBlock+seSlot(A6) ; copy slot number and sRsrc ID MOVE.L A1,sExecBlock+seIOFileName(A6) ; pointer to driver's name MOVE.B spExtDev(A0),sExecBlock+seDevice(A6); which device to read from LEA -ioQElSize(SP),SP ; allocate a parameter block on the stack MOVE.L spResult(A0),ioFileName(SP) ; driver name CLR.B ioPermssn(SP) ; permission = whatever goes CLR.L ioMix(SP) ; this needs to be zero MOVEQ #1< MOVE.W ioRefNum(A0),D3 ; save the driver's reference number MOVEA.L A1,SP ; toss the parameter block MOVEA.L A1,A0 ; point back at the slot pb LEA -SizesPRAMRec(SP),SP ; allocate a slot PRAM record on the stack MOVE.L SP,spResult(A0) ; and point to it _sReadPRAMRec ; get info about this video device MOVEQ #0,D0 MOVE.B 2(SP),D0 ; get the default video mode LEA SizesPRAMRec(SP),SP ; clean up MOVE.L D0,-(SP) ; save mode MOVE.B #sRsrcFlags,spID(A0) ; look for sRsrcFlags MOVE.L A2,spsPointer(A0) ; set spsPointer to sRsrc _sReadWord ; read flag word BNE.S @Use24Bit ; no flag field - default to 24 bit mode MOVEQ #1< AND.L spResult(A0),D0 ; d0 = flag word BEQ.S @Use24Bit ; -> no BSET #31,D3 ; yes - set flag in d3 @Use24Bit MOVE.L (SP)+,D0 ; restore mode SUBQ.W #4,SP MOVE.W D3,-(SP) ; refNum MOVE.L D0,-(SP) ; mode _NewGDevice ; allocate a new GDevice for our card MOVE.L (SP)+,D0 ; was it allocated? BEQ.S @NoDriver ; -> no, bail MOVEA.L D0,A3 ; save the GDHandle LEA DeviceList-gdNextGD,A0 MOVEQ #0,D1 ; initialize rightmost screen location BRA.S @FirstDevice @NextDevice MOVEA.L D0,A0 ; get the handle to the next GDevice MOVEA.L (A0),A0 ; and de-reference it MOVE.W gdRect+right(A0),D0 ; get the right edge of this device CMP.W D0,D1 ; is this one farther right than the last? BGE.S @FirstDevice ; -> nope MOVE.W D0,D1 ; yes, keep track of it @FirstDevice MOVE.L gdNextGD(A0),D0 ; any more GDevices in the list? BNE.S @NextDevice ; -> yes MOVE.L A3,gdNextGD(A0) ; tack our GDevice onto the end of the list MOVEA.L (A3),A0 ; de-reference the handle BSET #screenDevice-8,gdFlags(A0) ; mark our GDevice as a screen device TST.L D3 ; test flag whether this a 32 bit device BPL.S @Not32 ; no BSET.B #ext32Device-8,gdFlags(A0) ; mark as 32 bit frame buffer @Not32 PEA gdRect(A0) ; theRect = device's bounds MOVE.L D1,-(SP) ; dv,dh MOVEA.L gdPMap(A0),A0 ; get the PixMap handle MOVEA.L (A0),A0 ; and de-reference it PEA pmBounds(A0) ; theRect = PixMap's bounds MOVE.L D1,-(SP) ; dv,dh _OffsetRect ; move the PixMap's bounds _OffsetRect ; and gdRect to their new location MOVEA.L A3,A0 ; put the GDevice handle into A0 IMPORT InitDefGamma ; BSR.L InitDefGamma ; call this to test MOVE.W D3,result(A6) ; show success @NoDriver UNLK A6 ; clean up the stack MOVE.W (SP)+,D0 ; save the refNum and setup the CCR MOVEM.L (SP)+,@savedRegs ; restore them regs correctly RTS ENDWITH ; {AVStack} ;__________________________________________________________________________________________________ ; ; Routine: RegisterVideo ; ; Inputs: A2 - pointer to Docking Manager's globals ; D0 - video driver's refNum ; D1 - slot number ; ; Outputs: none ; ; Trashes: D0, D2, A0, A1 ; ; Function: Given that we've successfully installed a video driver from the docking bar's ROM, ; this routine makes the system aware of the new device, ála the Monitors control panel. ;__________________________________________________________________________________________________ RegisterVideo MOVE.L jRegisterVideo(A2),-(SP) RTS vRegisterVideo RTS ;__________________________________________________________________________________________________ ; ; Routine: RemoveVideo ; ; Inputs: A2 - pointer to Docking Manager's globals ; D1 - slot number ; ; Outputs: none ; ; Trashes: D0, D2, A0, A1 ; ; Function: Provides an expansion hook for future system software to allow us to gracefully ; remove a monitor from the desktop. ;__________________________________________________________________________________________________ RemoveVideo MOVE.L jRemoveVideo(A2),-(SP) RTS vRemoveVideo RTS ;__________________________________________________________________________________________________ ; ; Routine: ResolveSerialPorts ; ; Inputs: A2 - pointer to Docking Manager's globals ; ; Outputs: none ; ; Trashes: D0, D1, D2, A0, A1 ; ; Function: Calls Alex Kazim's hack to the Comm Toolbox to remove and add the appropriate serial ; port resources. ;__________________________________________________________________________________________________ ResolveSerialPorts MOVE.L jResolveSerialPorts(A2),-(SP) RTS vResolveSerialPorts MOVE.W #CTB_ModemIconID,-(SP) ; remove the modem port (if it exists) _CTBRemovePort MOVE.W #CTB_PrinterIconID,-(SP); remove the printer port (if it exists) _CTBRemovePort MOVE.W #CTB_ModemIconID,-(SP) ; add in the modem port (if it exists) _CTBAddPort MOVE.W #CTB_PrinterIconID,-(SP); add in the printer port (if it exists) _CTBAddPort RTS ;__________________________________________________________________________________________________ ; ; Routine: DockSleepDenied ; ; Inputs: A0 - pointer to the Power Manager's variables ; ; Outputs: CCR - BNE: NM task was successfully installed, BEQ: can't install ; ; Trashes: none ; ; Function: If the Docking Manager was initialized, install a Notification Manager request to ; let the user know that they can't put the portable to sleep because the connected ; bar doesn't think that's a good idea. ;__________________________________________________________________________________________________ DockingSleepDenied MOVE.L ([DockingGlobals],jDockingSleepDenied),-(SP) RTS vDockingSleepDenied @savedRegs REG D0-D2/A0-A1 MOVEM.L @savedRegs,-(SP) BSR DockingDispatchExists ; is the Docking Manager initialized? BEQ.S @NoDocking ; -> no, bail MOVEA.L DockingGlobals,A0 ; point to our globals LEA sleepNMEntry(A0),A0 ; and then to the NM record BSR NMInstall ; install the NM request if it's not already installed @NoDocking MOVEM.L (SP)+,@savedRegs RTS ;__________________________________________________________________________________________________ ; ; Routine: DockingWakeupDenied ; ; Inputs: none ; ; Outputs: none ; ; Trashes: none ; ; Function: If the Docking Manager was initialized, install a Notification Manager request to ; let the user know that they tried to wakeup with a new bar attached that's not ; supposed to be added during sleep. After this call is made, the system will go ; back to sleep, so the message will be displayed when we succussfully wake up. ;__________________________________________________________________________________________________ DockingWakeupDenied MOVE.L ([DockingGlobals],jDockingWakeDenied),-(SP) RTS vDockingWakeupDenied @savedRegs REG D0-D2/A0-A1 MOVEM.L @savedRegs,-(SP) BSR DockingDispatchExists ; is the Docking Manager initialized? BEQ.S @NoDocking ; -> no, bail MOVE.L #dockEjectCPU,D0 ; tell the docking station to eject when the power goes off BSR DockStatus MOVEA.L DockingGlobals,A0 ; remember we have to remove the current handler next time we wake up BSET #dockForceRemoval,dockingFlags(A0) ; LEA wakeupNMEntry(A0),A0 ; point to the NM record BSR NMInstall ; install the NM request if it's not already installed @NoDocking MOVEM.L (SP)+,@savedRegs RTS ;__________________________________________________________________________________________________ ; ; pascal void SleepNMResponse(NMRec *nmReq) ; ; Notification Manager response procedure for signaling that the sleep notification is complete. ;__________________________________________________________________________________________________ SleepNMResponse MOVEA.L PMgrBase,A1 BCLR #InSleep,PmgrFlags(A1) ; show that we're not in the sleep code anymore BCLR #ClamshellClosed,PmgrFlags(A1) ; and that the clamshell switch is fair game again BRA.S WakeupNMResponse ; branch to the standard response procedure ;__________________________________________________________________________________________________ ; ; pascal void EjectNMResponse(NMRec *nmReq) ; ; Notification Manager response procedure for signaling that the eject notification is complete. ;__________________________________________________________________________________________________ EjectNMResponse MOVEA.L DockingGlobals,A1 ; CLR.B dockingEjectFlags(A1) ; back us out of the eject MOVE.L #dockEjectStatus,D0 ; reset the eject switch in case the user pressed it BSR DockStatus ; while the NM dialog was up * BRA.S WakeupNMResponse ; fall thru into the standard response procedure ;__________________________________________________________________________________________________ ; ; pascal void WakeupNMResponse(NMRec *nmReq) ; ; Notification Manager response procedure for signaling that the wakeup notification is complete. ;__________________________________________________________________________________________________ WakeupNMResponse MOVEA.L (SP)+,A1 ; pop the return address MOVEA.L (SP)+,A0 ; and the pointer to the NM record CLR.B nmRefCon(A0) ; flag that the notification has been received _NMRemove ; remove the request from the queue JMP (A1) ;__________________________________________________________________________________________________ ; ; Routine: CheckForEject ; ; Inputs: A0 - pointer to VBL task element ; ; Outputs: none ; ; Trashes: D0, D1, D2, A0, A1, A2 ; ; Function: Checks if the user has pushed the eject button on a docking station (assuming there ; is one). If so, it shuts down and ejects the CPU if it's not locked into the station. ; If it is locked, we'll put up a message telling them why they can't eject. ;__________________________________________________________________________________________________ CheckForEject MOVE.L A0,-(SP) MOVE.W #Unimplement,D0 ; is _SyncIdleTime implemented? _GetTrapAddress ,NEWTOOL MOVEA.L A0,A1 MOVE.W #SyncIdleTime,D0 _GetTrapAddress ,NEWTOOL CMPA.L A0,A1 BEQ.S @NoSyncIdle ; -> no, we're done MOVEA.L DockingGlobals,A2 MOVE.L A0,dockOldSyncIdleTime(A2) ; save the old trap address LEA EjectShutdown,A0 ; and head patch us MOVE.W #SyncIdleTime,D0 _SetTrapAddress ,NEWTOOL LEA CheckForEject2,A1 MOVE.L A1,ejectVBLTask+vblAddr(A2) ; shorten this VBL task (no _SyncIdleTime check now) @NoSyncIdle MOVEA.L (SP)+,A0 CheckForEject2 MOVE.W #ejectVBLCount,vblCount(A0) ; reset the counter IF hasPwrControls THEN ; MOVEA.L PMgrBase,A1 ; TST.B SysTaskFlag(A1) ; has SystemTask been called yet? BEQ.S NMDone ; -> no, don't allow ejects yet (the system will freak) ENDIF ; MOVEA.L DockingGlobals,A2 ; point to the docking globals IF dockEjectPressed=7 THEN TST.B dockingEjectFlags(A2) ; is a request pending? BMI.S NMDone ; -> yes, let it complete ELSE BTST #dockEjectPressed,dockingEjectFlags(A2) ; is a request pending? BNE.S NMDone ; -> yes, let it complete ENDIF MOVE.L #dockEjectStatus,D0 ; get the eject status BSR DockStatus BTST #dockEjectEnabled,D0 ; was the eject button hit? BEQ.S NMDone ; -> no, done BSET #dockEjectPressed,dockingEjectFlags(A2) ; set a flag to prevent re-entrancy MOVE.L #dockLockAttr,D0 ; get the lock attributes BSR DockStatus BTST #dockLockEnabled,D0 ; is the CPU locked into the docking station? BNE.S @Locked ; -> yes, put up a message MOVE.L #dockEjectCPU,D0 ; tell the docking station to eject on power off BSR DockStatus TST.L dockOldSyncIdleTime(A2) ; is the _SyncIdleTime patch installed? BNE.S NMDone ; -> yes, we'll finish later _SDPowerOff ; just shutdown the system since the Finder's not running anyway BRA.S * @Locked LEA ejectNMEntry(A2),A0 ; point to the NM record ;••• MOVE.L lockedEjectMsg(A2),nmStr(A0); load the “CPU is locked to docking bar” message NMInstall TST.B nmRefCon(A0) ; is this request already pending? BNE.S NMDone ; -> yes, let it complete TST.L nmStr(A0) ; is there a string to use to notify the user? BEQ.S NMDone ; -> no, can't do anything _NMInstall ; and install the request SEQ D0 ; mark the request installed if successful MOVE.B D0,nmRefCon(A0) ; force CCR to BNE if it was installed NMDone RTS ;———————————————————————————————————————————————————————————————————————————————————————— ; pascal void EjectShutdown(void) ; ; This is a head patch to _SyncIdleTime ($ABF7) to send a shutdown message to ; the Finder at a time when it can do something. ;———————————————————————————————————————————————————————————————————————————————————————— EjectShutdown ; MOVEA.L DockingGlobals,A1 ; point to the Docking Manager's globals IF dockEjectPressed=7 THEN TST.B dockingEjectFlags(A1) ; has the user pressed the eject button? BPL.S @NoEject ; -> no, just passing thru ELSE BTST #dockEjectPressed,dockingEjectFlags(A1) ; has the user pressed the eject button? BEQ.S @NoEject ; -> no, just passing thru ENDIF TST.B ejectNMEntry+nmRefCon(A1) ; is a NM dialog up? BNE.S @NoEject ; -> yes, problems, so don't do the eject thing BSET #dockShuttingDown,dockingEjectFlags(A1) ; have we been here before? BNE.S @NoEject ; -> yes, once is enough MOVEA.L jGracefulShutdown(A1),A0 ; call the graceful shutdown routine JSR (A0) BEQ.S @NoEject ; -> the shutdown is under way BCLR #dockShuttingDown,dockingEjectFlags(A1) ; we couldn't shutdown now TST.W D0 ; are we waiting on the Finder? BGT.S @NoEject ; -> yes, we'll finish up later LEA ejectNMEntry(A1),A0 ; point to the NM record ;••• MOVE.L finderBlockedMsg(A1),nmStr(A0); load the “something’s blocking shutdown” message BSR.S NMInstall ; install the NM request if it's not already installed BNE.S @NoEject ; -> task was installed BCLR #dockEjectPressed,dockingEjectFlags(A1) ; back us out of the eject @NoEject MOVEA.L dockOldSyncIdleTime(A1),A0 ; return so the Finder can do the shutdown JMP (A0) ;———————————————————————————————————————————————————————————————————————————————————————— ; Routine: GracefulShutdown ; ; Inputs: none ; ; Outputs: D0 - result code ; =0: shutdown message successfully sent to the Finder ; >0: waiting for the Finder to become the front process ; <0: a problem occurred (no Finder, something blocking, etc.) ; ; Trashes: none ; ; Function: Sends a shutdown event to the Finder (if the Finder is running) so it will ; quit all running applications. If the required OS support is not present, ; we'll back down to doing just a straight shutdown instead. ;———————————————————————————————————————————————————————————————————————————————————————— receiverIDisPSN EQU $00008000 ; use a process number for the receiver ID GracefulShutdown @savedRegs REG D1-D2/A0-A2 MOVEM.L @savedRegs,-(SP) ; check if the Process Manager/MultiFinder is installed... MOVE.W #Unimplement,D0 ; get the address of the _Unimplemented trap _GetTrapAddress ,NEWTOOL MOVEA.L A0,A1 MOVE.W #$A88F,D0 ; get the address of _OSDispatch _GetTrapAddress ,NEWTOOL CMPA.L A0,A1 ; is _OSDispatch implemented? BEQ @JustShutDown ; -> no, do it the old way MOVE.W @Gestalt,D0 ; is Gestalt implemented? _GetTrapAddress ,NEWOS CMPA.L A0,A1 BEQ @JustShutDown ; -> no MOVE.L #gestaltAppleEventsAttr,D0 ; get AppleEvents attributes @Gestalt _Gestalt MOVE.L A0,D0 BTST #gestaltAppleEventsPresent,D0 ; are AppleEvents supported? BEQ @JustShutDown ; -> no, can't send a message ; try to find the Finder in the list of active processes... LINK A6,#-ProcessInfoRec.size ; allocate a process info record on the stack MOVEQ #ProcessInfoRec.size,D0 ; initialize the record MOVE.L D0,processInfoLength(SP) CLR.L processName(SP) CLR.L processNumber.highLongOfPSN(SP) MOVE.L #kNoProcess,processNumber.lowLongOfPSN(SP) CLR.L processAppSpec(SP) MOVEA.L SP,A2 ; point to the process info record SUBQ.W #2,SP ; space for result (this gets left on the stack) @FindFinder PEA processNumber(A2) ; PSN _GetNextProcess ; get the next process' PSN MOVE.W (SP),D0 BNE @NoFinder ; -> no more processes: couldn't find the Finder PEA processNumber(A2) ; PSN MOVE.L A2,-(SP) ; info _GetProcessInformation ; get information about this process MOVE.W (SP),D0 BNE.S @NoFinder ; -> bad PSN? CMPI.L #'FNDR',processType(A2) ; is this process the Finder? BNE.S @FindFinder ; -> no, keep looking ; make sure the Finder's the front process before telling it to shut down... LEA -ProcessSerialNumber.size-2(SP),SP ; PEA 2(SP) ; PSN _GetFrontProcess ; get the process number of the front process TST.W (SP)+ ; is there a front process? BNE.S @JustShutDown ; -> no, just shut down (why no foreground process?) CLR.L -(SP) ; space for ‘result’ + result code PEA processNumber(A2) ; PSN1 PEA 4+2+2(SP) ; PSN2 PEA 4+4+2(SP) ; result _SameProcess ; compare process numbers TST.W (SP)+ ; BNE.S @JustShutDown ; -> bad process number? TST.B (SP)+ ; is the Finder the front process? LEA ProcessSerialNumber.size(SP),SP ; (toss the process number record) BNE.S @FinderInFront ; -> yes, we're ready to shutdown PEA processNumber(A2) ; PSN _SetFrontProcess ; force the Finder to the front MOVE.W (SP),D0 ; is it going to happen? BNE.S @NoFinder ; -> nope, something's preventing it MOVEQ #1,D0 ; show the Finder is being brought to the front BRA.S @NoFinder ; ; the Finder's now in front so tell it to shut everybody down... @FinderInFront _BeginSystemMode ; enter system mode PEA @ShutDownEvent ; theEvent PEA processNumber(A2) ; receiverID CLR.L -(SP) ; msgRefCon CLR.L -(SP) ; msgBuff CLR.L -(SP) ; msgLen MOVE.L #receiverIDisPSN,-(SP) ; postingOptions _PostHighLevelEvent ; send the event to the Finder (leave result on stack) _EndSystemMode ; exit system mode MOVEQ #0,D0 ; show no error @NoFinder UNLK A6 ; toss the stack frame MOVEM.L (SP)+,@savedRegs RTS @JustShutDown _SDPowerOff ; ‘single’ Finder: shutdown the system BRA.S * @ShutDownEvent ; HighLevel EventRecord to tell the Finder to shutdown DC.W 0 ; what DC.L 'FNDR' ; message = event class (Finder's application signature) DC.L 0 ; ticks DC.L 'shut' ; where = event ID (shutdown) CLR.W 0 ; meta ;__________________________________________________________________________________________________ ; ; The following tables are used for initializing the routine vectors for a particular machine. ; If there are no special machine-specific characteristics, there doesn't need to be a vector ; table since in that case the default vectors will be used. ;__________________________________________________________________________________________________ DockingVectorTable IF hasMSC THEN DC.B 0,MSCDecoder ; handle MSC Decoder DC.L MSCVectors-* ENDIF IF hasNiagra THEN ; DC.B 0,NiagraDecoder ; handle Niagra decoder DC.L NiagraVectors-* ; ENDIF ; IF hasPratt THEN ; DC.B 0,PrattDecoder ; handle Pratt decoder DC.L PrattVectors-* ; ENDIF ; DC.W -1 ; default vectors (this should be the last entry) DC.L DefaultVectors-* DefaultVectors DC.L (1< ;•••••••••••••••••••••••••••••••••••••••••••• Niagra •••••••••••••••••••••••••••••••••••••••••••••• NiagraVectors DC.L (1< DC.L vDockingSleepDenied-(*+4) DC.L vDockingWakeupDenied-(*+4) DC.L vDockingFilter-(*+4) DC.L GracefulShutdown-(*+4) DC.L 0 ENDIF ; {hasNiagra} ;__________________________________________________________________________________________________ ; ; Routine: CheckConnectNiagra, CheckConnectPratt ; ; Inputs: A2 - pointer to Docking Manager's globals ; ; Outputs: CCR - BNE: bar is connected, BEQ: no bar (bar none?) ; ; Trashes: A0,D0 ; ; Function: returns ‘connected’ if the VSC video is turned on since Dartanian's ‘bar’ is built ; into the box. ;__________________________________________________________________________________________________ CheckConnectPratt CheckConnectNiagra lea -spBlockSize(sp),sp ; alloc spBlock movea.l sp,a0 move.b dockingSlotNum(a2),spSlot(a0) ; slot VSC video is on _sCkCardStat ; see if card was added ok lea spBlockSize(sp),sp ; dealloc spBlock seq d0 ; if bad, return "not connected" tst.b d0 ; set the CCR rts IF hasPratt THEN ; ;•••••••••••••••••••••••••••••••••••••••••••• Pratt •••••••••••••••••••••••••••••••••••••••••••••• PrattVectors DC.L (1< wakeup SWAP D1 ; use the wakeup hardware attributes @Startup ANDI.W #(1< no BSET #dockNoSleep,D0 ; yes, we don't let it sleep @Done RTS ;__________________________________________________________________________________________________ ; ; Routine: CheckBarChangedPratt ; ; Inputs: A2 - pointer to Docking Manager's globals ; ; Outputs: CCR - BNE: bar has changed ; ; Trashes: A0, D0 ; ; Function: Since the “bar” on Pratt-based CPUs is built-in, the Docking Handler would never be ; swapped out. So, we now call the Docking Handler to ask it if the world changed. ; If it did, then “BNE”. ;__________________________________________________________________________________________________ CheckBarChangedPratt Bsr.s DockingDispatchExists ; If DockingDispatch is around, Bne.s @CallHandler ; then call the Docking Handler. Moveq #0,D0 ; Otherwise, just say things are okay. Rts ; And Vamoose. @CallHandler Move.l #(1<