sys7.1-doc-wip/OS/StartMgr/StartSearch.a

1828 lines
64 KiB
Plaintext
Raw Normal View History

2019-07-27 14:37:48 +00:00
;
; File: StartSearch.a
;
; Contains: This collection of subroutines is used to search out the most appropriate device to become
; the startup device, and to load the boot blocks from that device. It also provides the user
; with feedback as to what is happening.
;
; Written by: Wayne R. Loofbourrow - September, 1986
;
; Copyright: © 1986-1993 by Apple Computer, Inc. All rights reserved.
;
; Change History (most recent first):
;
; <SM13> 11/22/93 pdw Rolling in <MC3>
; <MC3> 11/9/93 pdw Fixed the "failed floppy boot causing wrong device boot" bug.
; Moved initialization of SCSIDrvrs back out of here and into
; SCSIMgrInit and BootItt (IttBoot) because on a failed boot,
; FindStartupDevice is called again and it wipes out SCSIDrvrs.
; Same with call to InitSCSIBoot.
; <SM12> 10/14/93 pdw Added selectable partition booting. Added forceBoot for
; InstallMeFirst CD-ROMs. Fixed Cmd-Shift-Opt-Del bugs with async
; SCSI. Rearranged some stuff and cleaned up some stuff.
; <SM11> 9/9/93 pdw Changed Peril to SetOSPassword and put it in SysEqu.a.
; <SM10> 8/23/93 pdw Added support for LimitPRAMClear, IgnoreCmdOptShDel,
; LoadDefaultOnly - three options required for AIX security,
; enabled by setting bits in PRAM $76.
; <SM9> 6/14/93 kc Roll in Ludwig.
; <LW5> 6/11/93 KW Do not call HideCursor in routine ShowSuccess if cursor is
; already hidden i.e. CrsState < 0. Fixes Radar bug #1087192
; <SM8> 2/13/93 PW Added Ludwig changes <LW2> and <LW3>.
; <LW3> 2/12/93 PW Added passing of drivers' "don't munge heaps" bit into SCSILoad.
; <LW2> 1/27/93 DCB Added code for CmdShiftOptDel startup sequence to fix Radar Bug
; 1051033.
; <SM7> 12/16/92 SWC Moved CenterRect here from StartBoot.a. Did some cleanup.
; <SM6> 11/30/92 PW Changed COUSIN_ITT uses to COUSIN_ITT AND hasAsyncSCSI.
; (Reserving use of COUSIN_ITT for special test builds.)
; <SM5> 11-12-92 jmp Eliminated assembler warning when not building with the
; COUSIN_ITT flag enabled.
; <SM4> 7/28/92 PW Turned on Cousin Itt (SCSIMgr4pt3).
; <SM3> 7/28/92 PW Added Cousin Itt stuff.
; <SM2> 5/16/92 kc Roll in Horror. Remove conditionals.
; <5> 1/2/92 RB Include UniversalEqu.a for TestFor macro.
; <4> 1/2/92 RB Do universal test for PowerMgr before calling it so that the
; conditionals can be taken out. Flush the cpu cache before boot
; block validation.
; <3> 9/16/91 JSM Cleanup header.
; <2> 6/12/91 LN Changed #include 'HardwareEqu.a' to 'HardwarePrivateEqu.a'
; <1.9> 11/13/89 MSH Pmgr equates now in record format.
; <1.8> 8/22/89 SES Removed references to nFiles. Changed include DeclRomEqu.a to
; RomEqu.a. Changed sRsrc_BootRec to sRsrcBootRec.
; <1.7> 6/10/89 SWC Converted the HappyMac and disk icon drawing routines to use
; QuickDraw on all machines.
; <1.6> 5/24/89 GGD Converted to feature based conditionals in more places, more
; works is needed for the 16 bit machines.
; <1.5> 4/10/89 gmr Removed specific drive checks in InBootMask, now just check for
; drive number within range (0..15). This allows BootMask to work
; with RAM disks, as well as future drivers. Eliminated IsItSCSI,
; IsItHD20 in the process.
; <•1.4> 3/13/89 BBM SetOSDefault blindly set pram to the values pointed at by A0.
; Master pointers to rom resources on a macintosh ][ are of the
; form A083XXXX. The Trap number for SetOSDefault is A083. If a
; program crashed and started executing random blocks, then there
; was a good chance that it would try to execute a master pointer.
; The result would be that the default OS on reboot is not valid.
; Cross reference PB337 in system sources. The fix is to require a
; password, to prevent wandering programs from creating Chaos.
; <1.3> 2/27/89 jwk Added BigJSR's to SCSILoad as part of async SCSI roll in.
; <1.2> 2/16/89 rwh removed Mv conditionals for Vias not working.
; <1.1> 11/10/88 CCH Fixed Header.
; <1.0> 11/9/88 CCH Adding to EASE.
; <2.0> 11/7/88 rwh fixed bug in 'command-shift-option-del' disabling of internal
; drive
; <1.9> 9/24/88 rwh roll in on MvMac changes
; <•1.8> 9/23/88 CCH Got rid of inc.sum.d and empty nFiles
; <1.7> 9/12/88 MSH Last version of sleep count down. Time saved on stack.
; <1.6> 9/9/88 MSH Screen clearing before shut down uses lomem values instead of
; equates.
; <1.5> 9/8/88 MSH Slightly revised sleep count down method.
; <1.4> 6/24/88 MSH HcMac: Fixed the time out waiting for boot device to two
; minutes. Sleep command now requires a signature word sent with
; the command.
; <1.3> 6/15/88 MSH fix for ramdisk stuff
; <1.2> 6/7/88 MSH Converted to Mac ][ boot screen and SCSI boot device selection
; for HcMac.
; <1.1> 5/23/88 BBM fixed name conflicts by adding i to internal routines.
; <1.0> 2/10/88 BBM Adding file for the first time into EASE…
; <C914> 10/29/87 rwh Port to Modern Victorian (on MvMac). Removed those ugly "---
; NuMac ---)))"s.
; <C878> 9/2/87 MSH Port to HcMac (Laguna)
; <C772> 2/8/87 SHF Added delay between calls to SCSILoad in WaitForInternal to
; accomodate drives which don't like to be polled too quickly.
; <C736> 2/2/87 GWN Renamed SDM selector. Changed HandleSlotDev to LoadSlotDrivers.
; Fixed bug in NeverAgain.
; <C720> 1/29/87 GWN Cleared spExtDev field where neccessary.
; <C706> 1/27/87 SHF Changed the internal drive wait timeout value to 20 seconds.
; <C682> 1/24/87 WRL [NuMac] Modified the disk and happy Mac plotting routines to use
; QuickDraw. HappyMac routine moved here from startfail.
; <C677> 1/23/87 SHF Increased the internal drive wait timeout value to 25 seconds.
; <C638> 1/15/87 GWN Changed the interface of GetVideoDefault and SetVideoDefault.
; <C619> 1/13/87 GWN Test the status of the sLoad code.
; <C613> 1/12/87 SHF Now uses low-memory global for SCSI ID of the internal hard disk
; (used to always assume 0).
; <C600> 1/7/87 GWN Made minor changes for slot booting.
; <C593> 1/5/87 GWN Added code to center disk icon & company.
; <C587> 1/4/87 JTC Changed MyIOPB to $380, but then restored it to $400.
; <C515> 12/12/86 GWN Changed PRAM address of Video default to $80.
; <C474> 12/2/86 GWN Added code to enable boot off of a default slot device. Modified
; EmbarkOnSearch to get more parameters from PRAM. Added
; GetOSDefault and SetOSDefault routines. Added GetVideoDefault
; and SetVideoDefault traps (code by WRL).
; <A383> 11/8/86 CSL Load SCSI driver 0 in general LoadDriver routine if no
; don't-load drive 0 keys (command, shift, option and delete) are
; down.
; <A362> 11/6/86 CSL Power user - don't load internal hard disk - command, if hold
; down command, shift, option and delete keys are bootup time,
; internal hard disk would not be loaded, code in startsearch,
; with this power user command, check internal disk disable is
; changed from FullWaitMask to DynWaitMask.
; <A349> 11/4/86 SHF Changed mask value in SetWaitFlags which caused the timeout
; value to always have been reset to 0 and the wait flags to
; always retain their current value (meaning Permanent Disable was
; always set). Removed nWaitMacs.a include (rolled into
; StartMacs.a).
; <A345> 11/4/86 WRL Add new internal wait disable bit. Don't continue internal wait
; if device is there, but driver fails to load. Added new
; _InternalWait trap.
; <A344> 11/3/86 WRL Put LoadSCSIDrivers ahead of InternalWait so that SCSI devices
; 7..1 get priority in the drive queue over SCSI device 0 if no
; default is set.
; <A321> 10/31/86 WRL Cut SCSILoad related delays down to 1.75 seconds (from 3.5
; seconds). Fixed bug: No, SEQ doesn't affect the CCR!!! Fixed
; bug: Branch in WaitForInternal was wrong polarity. Enhancement:
; Don't try to load internal hard disk's driver if corrupted.
; <A306> 10/30/86 WRL Changed GetDefaultStartup, SetDefaultStartup, and InternalWait
; to use an OS style interface, as they should.
; <A300> 10/30/86 SHF Changed GetStartupDevice trap to bsr since the trap was OS but
; expected to be called ToolBox style. Fixed stack bug in
; SetRawTimeOut routine.
; <A297> 10/29/86 WRL After case-laden discussions with Jerome, Tony, Steve, Sheila,
; and Rich, we decided to have the time delay refer only to the
; maximum amount of time the system will wait for the internal
; SCSI device (whose ID must be zero). If the delay is exhausted,
; it is assumed that the user doesn't have an internal drive, and
; the delay in PRAM is reset to zero. The delay now refers to
; total time since Ticks was cleared. Isn't this fun?
; <A286> 10/28/86 WRL Made delay apply up front, to give drives a chance to warm up.
; <A276> 10/27/86 SMH modified rom search procedure.
; <C206> 10/9/86 bbm Modified to mpw aincludes.
; <C198> 10/2/86 Fixed bug in flashing X on disk icon.
; <C152> 9/30/86 Creation based loosely on the Mac Plus boot code.
;
PRINT OFF
LOAD 'StandardEqu.d'
INCLUDE 'HardwarePrivateEqu.a'
INCLUDE 'UniversalEqu.a'
INCLUDE 'Devices.a'
INCLUDE 'PowerPrivEqu.a'
INCLUDE 'SlotMgrEqu.a'
INCLUDE 'ROMEqu.a'
INCLUDE 'SCSI.a'
PRINT ON
MACHINE MC68020
;---------------
; Local Equates
;---------------
MyIOPBA6 EQU -$400 ; A6 offset for IOPB
FlashEnable EQU 8 ; (bit) 0 = disable; 1 = enable.
FlashParity EQU 9 ; (bit) 0 = no marks in disk icon, 1 = mark present (X or ?)
XEnable EQU 10 ; (bit) 1 = enable X flash next time
FlashTicks EQU 60 ; min number of ticks between half-flashes of X or ?
NumFlashX EQU 3 ; number of times to flash X before going
; back to flashing ? on disk icon.
FloppyRefNum EQU -5 ; floppy driver refnum
IntHDRefNum EQU -33 ; refnum of driver for SCSI ID 0
DefaultTimeOut EQU 20 ; number of seconds timeout if PRAM is pristine
MaxTimeOut EQU 31 ; maximum number of seconds allowed as timeout
PollDelay EQU 15 ; delay (in ticks) between poll drive SCSILoads
TimeOutMask EQU $1F ; mask for bits used as timeout
WaitFlagsMask EQU $E0 ; mask for bits used as flags
DynWaitBit EQU 7 ; 0 = enable; 1 = disable dynamic wait
PermWaitBit EQU 6 ; 0 = enable; 1 = disable permanent wait
DynWaitMask EQU (1<<DynWaitBit)
CmdShiftOptDel EQU $8805 ; command, shift, option and delete keys down bits
NoDefaultVal EQU $6666 ; the sign of the ... no default disk selected
IMPORT CacheFlush ; Dispatch.a
IMPORT SCSILoad ; :SCSIMgr:SCSIBoot.a
IF hasAsyncSCSI THEN
IMPORT INITSCSIBOOT ; :SCSIMgr4pt3:BootItt.c
IMPORT ISITT ; BootItt.c
IMPORT ITTBOOT ; BootItt.c
ENDIF
Locals RECORD {link},INCR
frameSize equ *
flashTime ds.l 1 ; time to flash icon
startTicks ds.l 1 ; Ticks when we first get into FindStartupDevice
ckPartition ds.b 1 ; flag = we need to check to see if the partition #s match
noDefaultDrive ds.b 1 ; flag = we have no default drive
foundDrvr ds.b 1 ; flag = we have seen the driver in the drive Q
forcedBoot ds.b 1 ; flag = boot has been forced to a non-default device
csPB ds CntrlParam ; pb for Control and Status
pmCommandPB ds pmCommandRec ; pb for sending SleepReq to power manager
startPRAM ;(ds.l 1)
lsdExtDevID ds.b 1 ; slot device ExtDevID (for SCSI target/lun)
lsdPartition ds.b 1 ; slot device Partition (for SCSI partition #)
lsdRefNum ;(ds.w 1) ; SCSI device refnum
lsdSlotNum ds.b 1 ; slot number
lsdSRsrcID ds.b 1 ; sRsrc ID (for native SCSI, bus #; for plug-in, sRsrc ID)
link ds.l 1 ; old A4 = (A4)
ENDR
; Register Convention for entire file
; Scratch: D0-D2, A0-A1
D3_partDevOS EQU D3
D4_refNum EQU D4
A2_driveQel EQU A2
A3_IsIt_Proc EQU A3
A4_locals EQU A4
A5_bootGlobs EQU A5
A6_bootBlocks EQU A6
;________________________________________________________________________________________
;
; Routine: FindStartupDevice
;
; Inputs: none
;
; Outputs: (A6)- contains the boot blocks (1024 bytes)
; BtDskRfn contains the refNum of the startup device
; BootDrive contains the drive number of the startup device
;
; Trashes: D0-D6, A0-A4
;
; Function: finds the startup device, and loads and verifies the boot blocks from it
; (on portables, if no boot device is found within the sleep timeout, then
; go to sleep)
;________________________________________________________________________________________
FindStartupDevice PROC EXPORT
WITH Locals
EXPORT EraseMyIcon
IMPORT GetDefaultStartup ; StartSearch.a
link A4, #frameSize
BSR EmbarkOnSearch ; Initialize our state.
BSR LoadSlotDrivers ; Default is a slot device, execute boot code
; When booting a Mac OS, execution will continue here
MOVE.L Ticks, startTicks(A4) ; Init the time we got here in case we have PowerMgr
BSR LoadSCSIDrivers ; Load all the drivers we can
BSR WaitForPollDrive ; Wait until the boot drive has warmed up
BRA.S @FirstEntry ; First time through: keep original goal
@NextPass
IF hasPwrControls THEN ; <SM7>
WITH PmgrRec,pmCommandRec
TestFor hwCbPwrMgr ; do we have Power Manager?
beq.s @noSleep ; if not then skip time check
MOVE.L Ticks,D0 ; Get the current time
SUB.L startTicks(A4),D0 ; Determine the time to go back to sleep
CMP.L #BootDevTicks,D0 ; See if time out has occured
BLS.S @nosleep
@sleepnow
LEA pmCommandPB(A4), A0 ; A0 gets pointer to parameter block
MOVE.W #SleepReq, pmCommand(A0) ; PMGR command, Go to sleep
MOVE.W #4, pmLength(A0) ; Four bytes of data to send
LEA pmData(A0), A1
MOVE.L A1, pmSBuffer(A0) ; pointer to send buffer
MOVE.L A1, pmRBuffer(A0) ; pointer to receive buffer
MOVE.L #SleepSig, pmData(A0) ; Put sleep signature in buffer
_PmgrOp
CMPI.W #SleepAck,pmData(A0) ; is the reply a sleep confirmation?
@waitsleep BEQ.S @waitsleep ; Wait for the drugs to take affect
@nosleep
ENDWITH
ENDIF ; <SM7>
CMPI.W #FloppyRefNum,D4 ; do we have floppy set as the default?
BEQ.S @NoChange ; -> yes, keep looking for floppies
LEA IsItAnything,A3 ; no, from now on, any device will do
@NoChange
BSR LoadSCSIDrivers ; load more drivers if we can
@TryAgain
BSR VisualUpdate ; Update dynamic user feedback
@FirstEntry
BSR FindNextCandidate ; Find the next potential Startup Device.
BEQ.S @NextPass ; Branch if we're at the end of the queue.
BSR SelectDevice ; Set up parameter block for this device.
BSR CheckMouseEject ; Eject it if requested by mouse-down.
BEQ.S @TryAgain ; Branch if ejected (we won't try reading it).
BSR GetStartupInfo ; Try to read the boot blocks from the device.
BEQ.S @GotIt ; Branch if success.
BSR ReactToFailure ; Handle the failure case.
BRA.S @TryAgain ; Try to find another Startup Device.
@GotIt
; show that we have succeeded in finding a startup device
TST CrsrState ; if negative, don't call HideCursor
BMI.S @ShowHappyMac ; prevents cursor depth from sinking
; to far if can't find boot drive
_HideCursor
@ShowHappyMac
MOVE.L A5, -(SP)
BSR HappyMac ; Plot the Happy Mac
MOVE.L (SP)+, A5
unlk A4
RTS
;________________________________________________________________________________________
;
; Routine: EmbarkOnSearch
;
; Inputs: none
;
; Outputs: D3 - bits 31-24: -reserved-
; 23-16: default OS
; 15- 8: default device ID (for slots)
; 7- 0: default partition
; D4 - default driver reference number
; D6 - bits: 10: 1=enable X flash next time, 0=flash ? next time
; 9: 1=mark present (X or ?)
; 8: 1=flashing enabled, 0=flashing disabled
; 7- 0: counter for how long to wait before switch from X back to ?
; A2 - pointer to current drive queue entry (or nil)
; A3 - pointer to routine to filter out desired drive queue entries
; flashTime - absolute time at which we next flash the disk icon
;
; Trashes: D0-D2, A0-A1
;
; Function: initializes the above variables to their default states, preparing for
; a fresh search to be embarked upon
;________________________________________________________________________________________
EmbarkOnSearch
; get the scoop on the default startup device
SUBQ.W #4,SP ; make room for parameters on the stack
MOVE.L SP,A0 ; and point to them
_GetDefaultStartup ; get info about the default device
MOVE.L (SP), startPRAM(A4) ; store for later partition check
MOVE.W (SP)+,D3 ; D3.L = <xx><xx><device-ID><partition>
MOVE.W (SP)+,D4 ; get the driver's refNum/<slot#><sRsrc#>
; get the default OS of startup device
SUBQ.W #2,SP ; make room for parameters on the stack
MOVE.L SP,A0 ; and point to them
_GetOSDefault ; get info about the default OS
SWAP D3
MOVE.W (SP)+,D3
SWAP D3 ; D3.L = <reserved><OSType><device-ID><partition>
; do we have a default drive?
cmp.w #NoDefaultVal, D4 ; magic value?
bne.s @weHaveDefault
move.b #1, noDefaultDrive(A4) ; set flag
clr.b ckPartition(A4) ; we don't want to ck partition number
bra.s @1
@weHaveDefault
clr.b noDefaultDrive(A4) ; we have default
move.b #1, ckPartition(A4) ; at start, we need to check the partition num
@1
clr.b foundDrvr(A4) ; we start off not having found the drvr
clr.b forcedBoot(A4) ; assume - not a forced boot
; initialize the rest of the register variables
SUBA.L A2,A2 ; initialize the drive queue pointer
LEA IsItFloppyOrDefault,A3 ; ASSUME match default or floppy devices.
CASE OBJ
IMPORT Ck4OnlyLoadFromDefault ; :SCSIMgr4pt3:BootItt.a
BSR.L Ck4OnlyLoadFromDefault ; supposed to limit our search to default device?
CASE OFF
BEQ.S @ck4NoDefault
LEA IsItDefault, A3 ; match only default device
@ck4NoDefault
TST.B noDefaultDrive(A4) ; is there a default drive? <MC2>
BEQ.S @HaveDefault ; -> yes
LEA IsItAnything,A3 ; no, match any device
@HaveDefault
MOVE.L Ticks,flashTime(A4) ; let flash time expire immediately.
CLR.W D6 ; clear visual state information.
;--- Initialize SCSIPoll (used to tell StartSearch which ID to wait for)
; and set up SCSIDrvrs to contain only the CPU's ID bit (so far the only ID we know of)
; At first, we default to the "internal" drive ID (SCSI ID 0). If not on a portable
; and the default driver is a valid old-SCSI driver, we use the default startup device number.
subq.l #2, sp ; make space for PRAM SCSI id <v1.4>
move.l sp, A0 ; address of PRAM return buffer
move.l #$00020002, D0 ; read 2 bytes of PRAM at offset 2
_ReadXPRam ; get the SCSI IDs of concern
move.w (sp)+, D0 ;
and.w #$0707,d0 ; mask all but the ID bits
move.b D0, SCSIPoll ; initialize hd flag (bit 7=0) & ID
TestFor hwCbPwrMgr ; is this a portable?
bne.s @exit ; yes -> use Internal Drive
; Put Default Startup Device number into SCSIPoll - assume no SCSIMgr4pt3 and corresponding
; multi-bus support. If SCSIMgr4pt3 does run, it will just ignore SCSIPoll. If it
; doesn't run, SCSIPoll will be used by WaitForPollDrive.
move.w D4, D1 ; get refNum (maybe)
not.w D1 ; convert refNum to unit number
sub.w #$20, D1 ; convert to SCSI ID
blt.s @exit ; out of range -> use previous value
cmpi.w #$07, D1
bgt.s @exit ; out of range -> use previous value
move.b SCSIPoll, D0
and.b #$F8, D0 ; strip out old internal HD SCSI ID
or.b D1, D0 ; put in new one
move.b D0, SCSIPoll ; initialize hd flag (bit 7=0) & ID
@NoDefault ;
@exit
RTS
;________________________________________________________________________________________
;
; Routine: LoadSlotDrivers
;
; Inputs: D3 - bits 31-24: -reserved-
; 23-16: default OS
; 15- 8: default device ID (for slots)
; 7- 0: default partition
; D4 - may contain a slot number (bits 8-15) and sRsrc ID (bits 0-7),
; if not, the routine just exits
;
; Outputs: D4 - default driver reference number, or zero if none
;
; Trashes: D0-D2, A0-A1
;
; Function: If D4 specifies a slot device, use it to load and execute boot code. If a
; Mac OS is to be booted, then a driver will be loaded and execution will
; continue here, otherwise a different OS will be brought up, so we're done.
;________________________________________________________________________________________
LoadSlotDrivers
WITH spBlock,seBlock
TST.B noDefaultDrive(A4) ; is there a default device?
BNE.S @exit ; no -> out of here
; Test for slot device.
TST.W D4 ;Is this a real slot device?
BLE.S @Exit ;Branch if not (n=0,n<0 => not slot)
; note: even tho newSCSI uses slot 0, we
; don't have any sRsrc to load so we exit
; Find the default sResource.
LEA -spBlockSize(SP),SP ;Allocate parameter block for SDM calls.
MOVE.L SP,A0
LEA -seBlockSize(SP),SP ;Allocate parameter block for code executed by _sExec.
MOVE.L SP,A1
MOVE.L A1,spsExecPBlk(A0)
MOVE.B D4,spId(A0) ;Default Id,
LSR.W #8,D4
MOVE.B D4,spSlot(A0) ;Default Slot,
_sFindsRsrcPtr ;Get a pointer to the sResource list
BNE.S @Fail ;Branch if error
; Set the parameters for the code in sExec.
MOVE.B spSlot(A0),seSlot(A1) ;Default Slot,
MOVE.B spId(A0),sesRsrcId(A1) ;Default sResource.
MOVE.L D3,D0 ;Boot code extensions.
MOVE.B D0,sePartition(A1) ;Default Partition,
LSR.L #8,D0
MOVE.B D0,seDevice(A1) ;Default Device, and
LSR.L #8,D0
MOVE.B D0,seOSType(A1) ;Default OS.
LSR.L #8,D0
MOVE.B D0,seReserved(A1) ;Reserved field.
MOVE.B #sbState0,seBootState(A1) ;State of StartBoot code.
; Execute the code in the sBoot record.
MOVE.B #sRsrcBootRec,spId(A0) ;Execute the code:
_sExec ; On entry to the boot code, A0 points to the SE parameter block.
BNE.S @Fail ;Branch if fail.
TST.W seStatus(A1) ;Test the status of the sLoad code
BNE.S @Fail ;Branch if error
@Good MOVE.W seRefNum(A1),D4 ;Set D4 to default RefNum.
@End LEA spBlockSize+seBlockSize(SP),SP ;Deallocate parameter blocks.
@Exit RTS
@Fail CLR.W D4 ;Clear default (match any device)
BRA.S @End ;Good, now exit.
;________________________________________________________________________________________
;
; Routine: LoadSCSIDrivers
;
; Inputs: D3 - bits 31-24: -reserved-
; 23-16: default OS
; 15- 8: default device ID (for slots)
; 7- 0: default partition
; D4 - default driver reference number
;
; Outputs: D3 - bits 31-24: -reserved-
; 23-16: default OS
; 15- 8: default device ID (for slots)
; 7- 0: default partition
; D4 - default driver reference number
;
; Trashes: D0-D2, A0-A1
;
; Function: loads more SCSI device drivers from the devices themselves, if they're available
;________________________________________________________________________________________
LoadSCSIDrivers
IF hasAsyncSCSI THEN
BSR.L ISITT ; check if we're running SCSI 4.3
TST.B D0 ; are we?
BEQ.S @UseOldSCSI ; -> no, use the old code to load drivers
PEA forcedBoot(A4) ; ptr to flag indicating a forcedBoot
CLR.L -(SP) ; load all drivers
BSR.L ITTBOOT ; Load Drivers and look for startup disk
ADDQ.W #8,SP ; (clean up the stack)
tst.b forcedBoot(A4) ; was it a forced boot?
beq.s @1 ; no -> nothing special
clr.b ckPartition(A4) ; yes:don't ck part'n (for a different drvr)
@1
tst.w d0 ; did we get a startup disk?
bge.s @StageLeft ; nope, exit
move.w D0, D4 ; yep, change d4 to reflect that
@StageLeft
RTS
@UseOldSCSI
ENDIF
; there is a new mechanism to disable loading of poll drive, so, check power
; user command, "command, shift, option and delete keys", if those keys are
; not down, go load the poll drive.
; Make sure that command, shift, option and delete keys are not down
MOVEQ #-1,D0 ; try to load all SCSI devices
CMPI.W #CmdShiftOptDel,KeyMap+6 ; are command, shift, option and delete keys down?
BNE.S @GoLoadD ; -> no, continue
MOVEQ #$07,D1
AND.B SCSIPoll,D1 ; get the SCSI ID of the poll drive
BCLR D1,D0 ; and clear the bit in the available drive list
@GOLoadD move.l d6,-(sp) ; save d6 <LW3>pdw
move.l a0,-(sp) ; save a0
moveq.l #0, D6 ; allow drivers to munge heap <LW3>pdw
BSR.L SCSILoad ; try to load driver(s) from disk
move.l (sp)+,a0 ; restore a0
move.l (sp)+,d6 ; restore d6 <LW3>pdw
RTS
;________________________________________________________________________________________
;
; Routine: WaitForPollDrive
;
; Inputs: none
;
; Outputs: none
;
; Trashes: D0-D2, A0-A1
;
; Function: Waits until the poll hard disk has had a chance to warm up.
; If it doesn't appear after the recommended amount of time, it
; is assumed absent and parameter RAM is updated accordingly.
;________________________________________________________________________________________
WaitForPollDrive
MOVEM.L A2/D5,-(SP) ; Save my registers.
; make sure the poll wait feature is enabled.
_GetWaitFlags ; get the current flags
AND.B #DynWaitMask,D0 ; and mask off the dynamic flag
BNE @RawExit ; -> exit if dynamic wait is disabled
; get the timeout value and convert it to ticks
_GetTimeOut ; get the timeout parameter
BNE.S @UseGivenTime ; -> use the returned parameter
MOVEQ #DefaultTimeOut,D0 ; no parameter returned, so use the default timeout.
@UseGivenTime
MOVEQ #60,D5 ; convert the timeout to ticks
MULU D0,D5 ; and save it
; We now disable waiting for the poll device in the future.
; This way, if loading the driver causes a crash, then next time
; the system boots, it won't wait for it.
; The waiting feature gets re-enabled if no crash occurs.
_DisablePermWait ; Disable permanent wait in case driver crashes
@WaitForIt
IF hasAsyncSCSI THEN
BSR.L ISITT ; check if we're running SCSI 4.3
TST.B D0 ; are we?
BEQ.S @UseOldSCSI ; -> no, use the old code to load drivers
PEA forcedBoot(A4) ; ptr to flag indicating a forcedBoot
PEA 1 ; only look for the startup device
BSR.L ITTBOOT ; get the startup device's refnum in D0
ADDQ.W #8,SP ; (clean up the stack)
tst.b forcedBoot(A4) ; was it a forced boot?
beq.s @1 ; no -> nothing special
clr.b ckPartition(A4) ; yes:don't ck part'n (for a different drvr)
@1
CMP.W #1, D0 ; CmdShiftOptDel or Nonbootable?
BEQ.S @RawExit ; yes -> don't wait no more
TST.W D0 ; no: did we get a drive?
BEQ.S @ckTimeout ; no -> check timeout and loop
MOVE.W D0, D4 ; yes: go with it
BRA.B @MyExit ;
@UseOldSCSI
ENDIF
; make sure that command, shift, option and delete keys are not down
MOVE.W KeyMap+6,D0 ; get keys down
CMP.W #CmdShiftOptDel,D0 ; are command, shift, option and delete keys down?
BEQ.S @RawExit ; -> exit if so
MOVEQ #$07,D1
AND.B SCSIPoll,D1 ; Get SCSI ID of poll drive
MOVEQ #0,D0 ; Clear register
BSET D1,D0 ; Set the bit for the drive
; Call SCSILoad with bit map in D0 and heap_munge_flag in D6
move.l d6,-(sp) ; save d6 <LW3>pdw
move.l a0,-(sp) ; save a0
moveq.l #0, D6 ; allow drivers to munge heap <LW3>pdw
BSR.L SCSILoad ; Try to load driver for poll disk
move.l (sp)+,a0 ; restore a0
move.l (sp)+,d6 ; restore d6 <LW3>pdw
BEQ.S @MyExit ; Branch if warmed up, but driver is invalid
MOVEQ #IntHDRefNum,D0 ; Refnum for ID 0
SUB.W SCSIPoll,D0 ; Convert to refnum for poll drive
MOVE.W D0,D1 ; Put back in D1 for comparison
; Let's see if the poll hard disk is actually in the queue
@ExamDQ SUBA.L A2,A2 ; Start at beginning of drive queue
@FindIntHD
BSR NextDQEntry ; Get the next drive queue entry
BEQ.S @EndOfQueue ; Branch if we're out of queue entries
CMP.W dqRefNum(A2),D1 ; Is it our trusty poll hard disk?
BNE.S @FindIntHD ; Nope, see if the next one's it
@Warm_n_Toasty ; We found the drive; it must have warmed up
BRA.S @MyExit ; That's all folks
@ckTimeout
@EndOfQueue
CMP.L Ticks,D5 ; Should the poll HD be visible by now?
BLO.S @NoDrivePresent ; Yes, so quit waiting for it
MOVEQ.L #PollDelay,D0 ; Get number of ticks to wait before retrying
ADD.L Ticks,D0 ; Calculate new time to try it again
@DelayLoop
CMP.L Ticks,D0 ; Time to try again?
BHS.S @DelayLoop ; No, so just be patient
BRA.S @WaitForIt ; Ready to try the poll drive again
@NoDrivePresent ; Time expired, drive must not be there
_DisableDynWait ; Drive not found, disable dynamic wait
@MyExit
_EnablePermWait ; No crash, re-enable disk wait
@RawExit
MOVEM.L (SP)+,A2/D5 ; Restore my registers
RTS ; Return to the world
;________________________________________________________________________________________
;
; Routine: FindNextCandidate
;
; Inputs: A2 - Points to the drive queue entry which was tried last time; the search
; for an appropriate device will begin with the NEXT drive queue entry.
; A nil pointer means you wish to search from the beginning of the queue.
;
; Outputs: A2 - pointer to the next appropriate drive queue entry found
; A3 - pointer to a subroutine which returns BEQ if A2 is pointing to a drive
; queue entry that we are interested in, otherwise it returns BNE. All
; registers except D0/A2 are passed through to the subroutine untouched
; (A2 points to the "next" queue entry). The subroutine must preserve
; all registers except D0-D2/A0-A1.
; CCR - BNE if we found an appropriate entry, BEQ if we've reached the end of the queue
;
; Trashes: D0-D2, A0-A1
;
; Function: finds the next possible startup device
;________________________________________________________________________________________
FindNextCandidate
BSR.S NextDQEntry ; Find the next drive queue entry.
BNE.S @ckThisOut ; valid -> check out the drive
; not: we've searched the whole queue.
tst.b ckPartition(A4) ; were we looking for right partition
beq.s @DoneLooking ; no-> return to scan bus some more
tst.b foundDrvr(A4) ; did we see a drive for the default drvr?
beq.s @DoneLooking ; no-> return to scan bus some more
clr.b ckPartition(A4) ; yes: no longer look for right partition
bra.s FindNextCandidate ; and search the DrvQ again
@ckThisOut
MOVE.W dqDrive(A2),D1 ; get the drive number
CMPI.W #15,D1 ; is it in range?
BHI.S @OuttaRange ; -> no, try it regardless
MOVE.W BootMask,D0 ; get failure info
BTST D1,D0 ; is this drive one we've rejected before?
BEQ.S FindNextCandidate ; -> yes, skip it
@OuttaRange JSR (A3) ; is this one of the devices we're looking for?
BNE.S FindNextCandidate ; -> no, keep looking
@DoneLooking
MOVE.L A2,D0 ; Return result.
RTS
;________________________________________________________________________________________
;
; Routine: NextDQEntry
;
; Inputs: A2 - points to the drive queue entry which was tried last time (nil if
; at the end of the queue)
;
; Outputs: A2 - pointer to the next drive queue entry (nil if at the end of the queue)
; CCR - BEQ if we're reached the end of the queue, BNE if A2 is valid
;
; Trashes: D0
;
; Function: advances A2 to point to the next drive queue entry. If the pointer is nil,
; point to the start of the queue
;________________________________________________________________________________________
NextDQEntry MOVE.L A2,D0 ; is the pointer NIL?
BNE.S @NextEntry ; -> no, more entries left in the queue
LEA DrvQHdr+QHead,A2 ; point to the head of the queue
@NextEntry MOVE.L qLink(A2),A2 ; point to next entry
MOVE.L A2,D0 ; test for end of queue
RTS
;________________________________________________________________________________________
;
; Routine: SelectDevice
;
; Inputs: A2 - points to the current drive queue entry
;
; Outputs: A0 - pointer to A6-based I/O parameter block
; A2 - points to the current drive queue entry
; BtDskRfn contains the driver reference number of the startup device
; BootDrive contains the drive number of the startup device
;
; Trashes: D0
;
; Function: sets up variables to make the current device the startup device
;________________________________________________________________________________________
SelectDevice
LEA MyIOPBA6(A6),A0 ; Point to my parameter block
MOVE.W dqRefNum(A2),D0 ; Get driver reference number.
MOVE.W D0,IORefNum(A0) ; Put it in parameter block.
MOVE.W D0,BtDskRfn ; Save RefNum in case this is boot device.
MOVE.W dqDrive(A2),D0 ; Get drive number.
MOVE.W D0,IODrvNum(A0) ; Put it in param block.
MOVE.W D0,BootDrive ; Save DrvNum in case this is boot device.
RTS
;________________________________________________________________________________________
;
; Routine: CheckMouseEject
;
; Inputs: A0 - pointer to A6-based I/O parameter block
;
; Outputs: CCR - BEQ if the disk was ejected
;
; Trashes: D0
;
; Function: ejects the disk from the current device if the mouse button is down
;________________________________________________________________________________________
CheckMouseEject
TST.B MBState ; does user want eject?
BMI.S DontEject ; -> no, skip
; fall thru into EjectMe
;________________________________________________________________________________________
;
; Routine: EjectMe
;
; Inputs: A0 - pointer to A6-based I/O parameter block
;
; Outputs: CCR - BEQ if the disk was ejected
;
; Trashes: D0
;
; Function: ejects the disk from the current device
;________________________________________________________________________________________
EjectMe LEA MyIOPBA6(A6),A0 ; Point to my parameter block
MOVE.W #EjectCode,csCode(A0)
_Control ; Issue an eject command to the device
DontEject RTS ; Return with status
;________________________________________________________________________________________
;
; Routine: GetStartupInfo
;
; Inputs: A0 - pointer to A6-based I/O parameter block
; A6 - pointer to buffer for holding the boot blocks
;
; Outputs: CCR - BEQ if the blocks were read successfully and they're boot blocks
;
; Trashes: D0
;
; Function: reads the boot blocks from the current device
;________________________________________________________________________________________
GetStartupInfo
MOVE.W #1,IOPosMode(A0) ; position relative to start
CLR.L IOPosOffset(A0) ; start at byte position 0
MOVE.L A6,IOBuffer(A0) ; load boot blocks at (A6)
MOVE.L #$400,IOReqCount(A0) ; two 512-byte blocks
_Read ; read the boot blocks
BNE.S @Exit ; -> error, so exit
move.l a0,-(sp)
BSR.L CacheFlush ; flush the caches
move.l (sp)+,a0
CMP.W #'LK',(A6) ; check if it's a true boot block
@Exit RTS ; and return BEQ if so
;________________________________________________________________________________________
;
; Routine: ReactToFailure
;
; Inputs: D0 - error code indicating what went wrong
; D4 - default device's driver reference number
;
; Outputs: D6 - may have the XEnable bit set
; BootMask is modified to prevent retries to the current device
;
; Trashes: D0-D1
;
; Function: responds to a failure to read the boot blocks correctly (this may include
; ejecting the disk)
;________________________________________________________________________________________
ReactToFailure
CMP.W #OffLinErr,D0 ; is the disk present and up to speed?
BEQ.S @Exit ; -> no, leave it alone so we can try it later
CMP.W #NoDriveErr,D0 ; is the drive present?
BEQ.S @This1NoMo ; -> no, don't talk to it again
BSR.S EjectMe ; for any other error, eject the device
BEQ.S @ShowMe ; -> its ejectable, so we can try it again
@This1NoMo MOVE.W dqDrive(A2),D1 ; get the drive number
CMPI.W #15,D1 ; is it in range?
BHI.S @ShowMe ; -> skip if not
MOVE.W BootMask,D0 ; get failure info
BCLR D1,D0 ; disable this device
MOVE.W D0,BootMask ; and update the failure info
@ShowMe BSR IsItFloppy ; is it a floppy that failed?
BNE.S @Exit ; -> no, don't do anything special
BSET #XEnable,D6 ; enable the flashing X on the disk icon
@Exit RTS
;________________________________________________________________________________________
;
; Routine: Ck4SupportsPartition
;
; Inputs: A2 - pointer to the current drive queue entry (must not be nil!)
; D4 - default device's driver reference number
;
; Outputs: CCR - BEQ if the current device support the partition field of PRAM
; D0 - long returned by driver to check against startPRAM
;
; Trashes: D0-D2/A0-A1
;
; Function: determines whether the current drive queue entry is the default boot device
;________________________________________________________________________________________
Ck4SupportsPartition
;
; Get the DCE using the Device Manager's statusGetDCE call
;
lea csPB(A4), A0 ; point to pb
move.w D4, ioRefNum(A0) ; pass driver refNum
move.w #statusGetDCE, csCode(A0) ; (Device Mgr call, not driver)
_Status
movea.l csParam(A0), A0 ; get DCE handle (doesnt touch CCR)
bmi @notSupported ; no such Driver (i.e. DCE not installed)
;
; now check this driver to see if it "follows new rules" and responds
; to driverGestalt status call
;
move.w dCtlFlags(A0), D0 ; does it Follow New Rules?
btst #FollowsNewRules, D0 ; (word-relative bit #)
beq.s @notSupported ; no -> skip driverGestalt call
lea csPB(A4), A0 ; point to it
move.w #driverGestaltCode, csCode(A0)
move.l #'boot', DriverGestaltParam.driverGestaltSelector(A0)
move.w dqDrive(A2), ioVRefNum(A0) ; put drive q num in ioVRefNum
move.w D4, ioRefNum(A0)
_Status ; make driverGestalt call
tst.w D0
bne.s @notSupported
move.l DriverGestaltParam.driverGestaltResponse(A0), D0
@exit
cmp.l #NoDefaultVal, D0 ; set Z if not supported
rts
@notSupported
clr.b ckPartition(A4) ; no longer look for right partition
move.l #NoDefaultVal, D0
bra.s @exit
;________________________________________________________________________________________
;
; Routine: IsItDefault
;
; Inputs: A2 - pointer to the current drive queue entry (must not be nil!)
; D4 - default device's driver reference number
;
; Outputs: CCR - BEQ if the current device is the default device
;
; Trashes: none
;
; Function: determines whether the current drive queue entry is the default boot device
;________________________________________________________________________________________
IsItDefault
cmp.w dqRefNum(A2), D4 ; is this driver for the default device?
bne.s @notTheDisk ; no-> definitely no the disk then
move.b #1, foundDrvr(A4) ; so we know to clr ckPartition if end-of-Q
tst.b ckPartition(A4) ; do we need to check the partition num?
beq.s @isTheDisk ; no-> well then, it is the right disk
bsr Ck4SupportsPartition ; does driver support partition info?
beq.s @isTheDisk ; no-> then this is the right volume
cmp.l startPRAM(A4), D0 ; yes: does returned boot value eq pram?
beq.s @isTheDisk ; yes-> selected disk
@notTheDisk
moveq.l #1, D0
rts
@isTheDisk
moveq.l #0, D0
@exit
rts ; return result of compare
;________________________________________________________________________________________
;
; Routine: IsItFloppyOrDefault
;
; Inputs: A2 - pointer to the current drive queue entry (must not be nil!)
; D4 - default device's driver reference number
;
; Outputs: CCR - BEQ if the current device is a floppy or the default device
;
; Trashes: none
;
; Function: determines whether the current drive queue entry is either a floppy or
; the default boot device
;________________________________________________________________________________________
IsItFloppyOrDefault
bsr.s IsItDefault
beq.s @exit
bsr.s IsItFloppy
@exit rts
;________________________________________________________________________________________
;
; Routine: IsItFloppy
;
; Inputs: A2 - pointer to the current drive queue entry (must not be nil!)
; D4 - default device's driver reference number
;
; Outputs: CCR - BEQ if the current device is a floppy
;
; Trashes: none
;
; Function: determines whether the current drive queue entry is a floppy
;________________________________________________________________________________________
IsItFloppy CMPI.W #FloppyRefNum,dqRefNum(A2) ; check if this drive is a floppy
ItsDefault RTS ; and return BEQ if so
;________________________________________________________________________________________
;
; Routine: IsItAnything
;
; Inputs: A2 - pointer to the current drive queue entry (must not be nil!)
; D4 - default device's driver reference number
;
; Outputs: CCR - always BEQ
;
; Trashes: none
;
; Function: always returns true to let all devices be accepted as startup candidates
;________________________________________________________________________________________
IsItAnything
CMP D0,D0 ; return BEQ
RTS
;________________________________________________________________________________________
;
; Routine: VisualUpdate
;
; Inputs: flashTime(A4) - the absolute time of the next flash of the ? or X
; D6 - the current state of the icons on the screen
; bits: 10: 1=enable X flash next time, 0=flash ? next time
; 9: 1=mark present (X or ?)
; 8: 1=flashing enabled, 0=flashing disabled
; 7- 0: counter for how long to wait before switch from X back to ?
;
; Outputs: same as inputs
;
; Trashes: D0-D2, A0-A1
;
; Function: keeps the user interface magic alive: flashes the disk icon when appropriate
;________________________________________________________________________________________
VisualUpdate
; Prevent a visual glitch if device is ready right away.
BSET #FlashEnable,D6 ; Enable flashing icon.
BEQ.S @DoneDisk ; Branch if previously disabled.
MOVE.L flashTime(A4), D0
CMP.L Ticks, D0 ; Is it time to flash?
BHI.S @DoneDisk ; Branch if not.
MOVE.L Ticks, flashTime(A4) ; Get current time.
ADD.L #FlashTicks, flashTime(A4) ; Compute next time to flash.
BCLR #XEnable,D6 ; Disable XEnable for next time;
; Should we enable it for this time?
BEQ.S @NoSwitch ; Branch if not
MOVE.B #NumFlashX,D6 ; Enable X flash by getting its count.
@NoSwitch BCHG #FlashParity,D6 ; Switch parity.
BNE.S @XorQ ; Branch if we need X or ? showing.
LEA DiskIcon,A0 ; plot the plain disk icon
BRA.S PlotMyIcon
@XorQ TST.B D6 ; Are we showing an ?
BEQ.S @ShowQ ; Branch if so.
SUBQ.B #1,D6 ; Eventually, we go back to a ?.
LEA XDiskIcon,A0 ; but for now, plot the disk icon with the X
BRA.S PlotMyIcon
@ShowQ LEA QDiskIcon,A0 ; plot the disk icon with the question mark
BRA.S PlotMyIcon
@DoneDisk RTS
;________________________________________________________________________________________
;
; Routine: HappyMac
;
; Inputs: none
;
; Outputs: none
;
; Trashes: D0-D2, A0-A1
;
; Function: displays the Happy Mac icon, centered on the main video device
;________________________________________________________________________________________
HappyMac BSR.S EraseMyIcon ; erase what's on the screen where the icon goes
LEA HappyIcon,A0 ; plot the happy mac icon
BSR.S PlotMyIcon
RTS
;________________________________________________________________________________________
;
; Routine: EraseMyIcon
;
; Inputs: none
;
; Outputs: none
;
; Trashes: none
;
; Function: erases the ICN# in the center of the main screen
;________________________________________________________________________________________
EraseMyIcon MOVEM.L D0-D2/A0-A1,-(SP)
BSR.S PushIconRect ; push the icon's rectangle onto the stack
MOVE.L SP,-(SP) ; and point to it
MOVE.L grafGlobals(A5),A0 ; point to the QuickDraw globals
PEA gray(A0) ; and use 50% gray as the background
_FillRect ; erase the rectangle with the desktop pattern
ADDQ.W #8,SP ; clean up the stack
MOVEM.L (SP)+,D0-D2/A0-A1
RTS
;________________________________________________________________________________________
;
; Routine: PlotMyIcon
;
; Inputs: A0 - pointer to ICN# to plot
;
; Outputs: none
;
; Trashes: D0-D2, A0-A1
;
; Function: plots an icon, centered on the main video device
;________________________________________________________________________________________
PlotMyIcon MOVE.L A0,D2 ; save the pointer to the ICN#
; put the source bitmap on the stack (icon's bit image)
BSR.S PushIconRect ; bounds = 32x32 rectangle, centered on the main screen
MOVE.W #32/8,-(SP) ; rowBytes
MOVE.L D2,-(SP) ; baseAddr = pointer to the icon
; put the mask bitmap on the stack (icon's mask image)
LEA bitMapRec(SP),A0 ; point to the end of this bitmap so we can make a copy
MOVE.L -(A0),-(SP) ; bounds
MOVE.L -(A0),-(SP)
MOVE.W -(A0),-(SP) ; rowBytes
MOVEA.L -(A0),A1
PEA 128(A1) ; baseAddr = pointer to icon's mask
; now copy the icon to the screen using CopyMask...
MOVE.L A0,-(SP) ; srcBits
PEA 4(SP) ; maskBits
MOVEA.L grafGlobals(A5),A1 ; point to QuickDraw's globals
MOVEA.L thePort(A1),A1 ; and from there get the current grafport
PEA portBits(A1) ; dstBits
PEA bounds(A0) ; srcRect
MOVE.L (SP),-(SP) ; maskRect
MOVE.L (SP),-(SP) ; dstRect
_CopyMask ; blast it
LEA 2*bitmapRec(SP),SP ; clean up the stack
RTS
;________________________________________________________________________________________
;
; Routine: PushIconRect
;
; Inputs: none
;
; Outputs: none
;
; Trashes: D0-D1, A0-A1
;
; Function: pushes a 32x32 rectangle on the stack, and then centers it on the main screen
;________________________________________________________________________________________
PushIconRect
MOVEA.L (SP)+,A0 ; pop the return address
MOVE.L #(32<<16)+32,-(SP) ; push an icon rect (0,0,32,32) on the stack
CLR.L -(SP)
MOVEA.L SP,A1 ; and point to it
MOVE.L A0,-(SP) ; push the return address back on the stack
MOVE.L grafGlobals(A5),A0 ; point to QuickDraw globals
LEA screenBits+bounds(A0),A0 ; and use the screen's rectangle as a guide
BSR.S @TranslateEdge ; translate the top and bottom edges
* BRA.S @TranslateEdge ; translate the left and right edges
NOP ; (we need this otherwise the assembler barfs on the BSR.S)
@TranslateEdge
MOVE.W bottom-top(A0),D0 ; calculate the height or width
SUB.W (A0),D0 ; of the guide rect
MOVE.W bottom-top(A1),D1 ; calculate the height or width
SUB.W (A1),D1 ; of the rect to be centered
SUB.W D1,D0 ; calculate how much to shift the position
ASR.W #1,D0 ; of the rect to be centered (half the difference)
ADD.W (A0)+,D0 ; calculate the new top or left edge
MOVE.W D0,(A1)+ ; of the rect to be centered
ADD.W D1,D0 ; do the same for the bottom or right edge
MOVE.W D0,bottom-top-2(A1)
RTS
;---------------------------------------------------------------------------------------------
; The ICN# bitmaps (icon and mask).
;---------------------------------------------------------------------------------------------
HappyIcon DC.L $07FFFFC0,$08000020,$10000010,$11FFFF10,$12000090,$12000090,$12000090,$12111090
DC.L $12111090,$12010090,$12010090,$12030090,$12000090,$12084090,$12078090,$12000090
DC.L $12000090,$11FFFF10,$10000010,$10000010,$10000010,$10000010,$13003F10,$10000010
DC.L $10000010,$10000010,$10000010,$0FFFFFE0,$08000020,$08000020,$08000020,$0FFFFFE0
DC.L $07FFFFC0,$0FFFFFE0,$1FFFFFF0,$1FFFFFF0,$1FFFFFF0,$1FFFFFF0,$1FFFFFF0,$1FFFFFF0
DC.L $1FFFFFF0,$1FFFFFF0,$1FFFFFF0,$1FFFFFF0,$1FFFFFF0,$1FFFFFF0,$1FFFFFF0,$1FFFFFF0
DC.L $1FFFFFF0,$1FFFFFF0,$1FFFFFF0,$1FFFFFF0,$1FFFFFF0,$1FFFFFF0,$1FFFFFF0,$1FFFFFF0
DC.L $1FFFFFF0,$1FFFFFF0,$1FFFFFF0,$0FFFFFE0,$0FFFFFE0,$0FFFFFE0,$0FFFFFE0,$0FFFFFE0
DiskIcon DC.L $7FFFFFF0,$81000108,$81007104,$81008902,$81008901,$81008901,$81008901,$81008901
DC.L $81007101,$81000101,$80FFFE01,$80000001,$80000001,$80000001,$87FFFFE1,$88000011
DC.L $88000011,$88000011,$88000011,$88000011,$88000011,$88000011,$88000011,$88000011
DC.L $88000011,$88000011,$88000011,$88000011,$88000011,$88000011,$88000011,$FFFFFFFE
DC.L $7FFFFFF0,$FFFFFFF8,$FFFFFFFC,$FFFFFFFE,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF
DC.L $FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF
DC.L $FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF
DC.L $FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFE
QDiskIcon DC.L $7FFFFFF0,$81000108,$81007104,$81008902,$81008901,$81008901,$81008901,$81008901
DC.L $81007101,$81000101,$80FFFE01,$80000001,$80000001,$80000001,$87FFFFE1,$88000011
DC.L $88000011,$8807E011,$880FF011,$880C3011,$880C3011,$88007011,$8800E011,$8801C011
DC.L $88018011,$88018011,$88000011,$88018011,$88018011,$88000011,$88000011,$FFFFFFFE
DC.L $7FFFFFF0,$FFFFFFF8,$FFFFFFFC,$FFFFFFFE,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF
DC.L $FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF
DC.L $FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF
DC.L $FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFE
XDiskIcon DC.L $7FFFFFF0,$81000108,$81007104,$81008902,$81008901,$81008901,$81008901,$81008901
DC.L $81007101,$81000101,$80FFFE01,$80000001,$80000001,$80000001,$87FFFFE1,$88000011
DC.L $88000011,$88100811,$88381C11,$881C3811,$880E7011,$8807E011,$8803C011,$8803C011
DC.L $8807E011,$880E7011,$881C3811,$88381C11,$88100811,$88000011,$88000011,$FFFFFFFE
DC.L $7FFFFFF0,$FFFFFFF8,$FFFFFFFC,$FFFFFFFE,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF
DC.L $FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF
DC.L $FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF
DC.L $FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFE
ENDWITH
ENDPROC
;----------------------------------------------------------------------
; Execute one of the subroutines related to the timeout while waiting for
; the poll hard disk to warm up.
;
; A0 -> Selector indicating which routine to call.
; D0 <-> The meaning of these parameters depends upon which routine is called.
;
; Destroys D0-D2/A0-A1.
;----------------------------------------------------------------------
InternalWait PROC EXPORT
MaxDispVal EQU 9 ; Entries 0-9 exist.
MOVE.L A0,D1 ; Get selector.
CMP.W #MaxDispVal,D1 ; Is value in range?
BHI.S @Exit ; If not, do nothing.
ADD.W D1,D1 ; Multiply by table entry size
LEA @MyTable,A1 ; Point to jump table.
MOVE.W (A1,D1.W),D1 ; Get table entry.
JMP (A1,D1.W) ; Execute proper subroutine.
@Exit RTS ; Return
@MyTable DC.W iGetTimeOut-@MyTable ; 0
DC.W iSetTimeOut-@MyTable ; 1
DC.W iGetWaitFlags-@MyTable ; 2
DC.W iSetWaitFlags-@MyTable ; 3
DC.W iDisableDynWait-@MyTable ; 4
DC.W iEnableDynWait-@MyTable ; 5
DC.W iDisablePermWait-@MyTable ; 6
DC.W iEnablePermWait-@MyTable ; 7
;---------------------------------------------------------------------- <A345>
; Get the timeout value.
;
; D0.L <- Timeout value (zero means use default).
; Z <- EQ if timeout indicates default; NE otherwise.
;
; Destroys D0/A0.
;---------------------------------------------------------------------- <A345>
iGetTimeOut
BSR.S GetRawTimeOut ; Get the current timeout parameter
AND.B #TimeOutMask,D0 ; Mask out significant bits
RTS ; Return
;----------------------------------------------------------------------
; Get the internal wait flags.
;
; D0.B <- Current wait flags.
;
; Destroys D0/A0.
;----------------------------------------------------------------------
iGetWaitFlags
BSR.S GetRawTimeOut ; Get the current timeout parameter
AND.B #WaitFlagsMask,D0 ; Mask out significant bits
RTS ; Return
;----------------------------------------------------------------------
; Set the timeout value.
;
; D0.B -> Timeout value (zero means use default).
;
; Destroys D0-D1/A0.
;----------------------------------------------------------------------
iSetTimeOut
MOVE.B D0,-(SP) ; Save timeout value
BSR.S GetRawTimeOut ; Get the current timeout parameter
MOVE.B (SP)+,D1 ; Get timeout value
CMP.B #MaxTimeOut,D1 ; Is proposed timeout greater than max?
BLS.S @InRange ; Branch if not
MOVEQ #MaxTimeOut,D1 ; If out of range, use max
@InRange
AND.B #$FF-TimeOutMask,D0 ; Clear out timeout bits
OR.B D1,D0 ; Put in new timeout value
BRA.S SetRawTimeOut ; Set new timeout parameter
;----------------------------------------------------------------------
; Set the timeout value.
;
; D0.B -> Wait flags to set.
;
; Destroys D0-D1/A0.
;----------------------------------------------------------------------
iSetWaitFlags
MOVE.B D0,-(SP) ; Save wait flags
BSR.S GetRawTimeOut ; Get the current timeout parameter
MOVE.B (SP)+,D1 ; Get wait flags
AND.B #WaitFlagsMask,D1 ; Mask out the wait flags
AND.B #TimeOutMask,D0 ; Clear out wait flag bits
OR.B D1,D0 ; Put in new wait flags
; fall into SetRawTimeOut
;----------------------------------------------------------------------
; Set the raw timeout parameter.
;
; D0.B -> Timeout parameter.
;
; Destroys D0/A0.
;----------------------------------------------------------------------
SetRawTimeOut
MOVE.B D0,-(SP) ; Save new value on stack.
MOVE.L SP,A0 ; Point to parameter.
MOVE.L #$00010001,D0 ; Write 1 byte starting at loc $01
_WriteXPRam ; Write it to PRAM.
MOVE.B (SP)+,D0 ; Clean up stack
RTS ; Return.
;----------------------------------------------------------------------
; Get the raw timeout parameter.
;
; D0.L <- Timeout parameter (only lowest byte is significant).
; Z <- EQ if timeout indicates default; NE otherwise.
;
; Destroys A0.
;----------------------------------------------------------------------
GetRawTimeOut
CLR.B -(SP) ; Create a place to put result.
MOVE.L SP,A0 ; Point to parameter block.
MOVE.L #$00010001,D0 ; Read 1 byte starting at loc $01
_ReadXPRam ; Read it from PRAM.
MOVEQ.L #0,D0 ; Clear upper bits.
MOVE.B (SP)+,D0 ; Return value in timeout field.
RTS ; Return.
;----------------------------------------------------------------------
; Disable the dynamic wait feature.
;
; Destroys D0/A0.
;----------------------------------------------------------------------
iDisableDynWait
_GetWaitFlags ; Get the current wait flags.
BSET #DynWaitBit,D0 ; Disable the dynamic wait feature.
_SetWaitFlags ; Set the new wait flags.
RTS
;----------------------------------------------------------------------
; Enable the dynamic wait feature.
;
; Destroys D0/A0.
;----------------------------------------------------------------------
iEnableDynWait
_GetWaitFlags ; Get the current wait flags.
BCLR #DynWaitBit,D0 ; Enable the dynamic wait feature.
_SetWaitFlags ; Set the new wait flags.
RTS
;----------------------------------------------------------------------
; Disable the permanent wait feature.
;
; Destroys D0/A0.
;----------------------------------------------------------------------
iDisablePermWait
_GetWaitFlags ; Get the current wait flags.
BSET #PermWaitBit,D0 ; Disable the permanent wait feature.
_SetWaitFlags ; Set the new wait flags.
RTS
;----------------------------------------------------------------------
; Enable the permanent wait feature.
;
; Destroys D0/A0.
;----------------------------------------------------------------------
iEnablePermWait
_GetWaitFlags ; Get the current wait flags.
BCLR #PermWaitBit,D0 ; Enable the permanent wait feature.
_SetWaitFlags ; Set the new wait flags.
RTS
ENDPROC
;----------------------------------------------------------------------
; Get information about the current default startup device.
;
; A0 -> A pointer to the record in which the info should be put.
;
; The record has the following format:
;
; RECORD
; sdDrvNum: INTEGER; { Drive number }
; sdRefNum: INTEGER; { Driver reference number }
; END;
;
; The sdDrvNum field is $FFFF if the drive number is irrelevant.
; The sdRefNum field is $0000 if the first available device should be chosen.
;
; Destroys D0-D2/A0-A1.
;----------------------------------------------------------------------
GetDefaultStartup PROC EXPORT
; Read info from parameter RAM. Format is:
; $78 [ (byte) DriveId{for slots} | (byte) PartitionId | (word) RefNum ]
MOVE.L #$00040078,D0 ; Read 4 bytes starting at loc $78
_ReadXPRam ; Get it from PRAM.
RTS ; Return.
ENDPROC
;----------------------------------------------------------------------
; Set a new default startup device.
;
; A0 -> A pointer to the record from which the info should be taken.
;
; The record has the following format:
;
; RECORD
; sdDrvNum: INTEGER; { Drive number }
; sdRefNum: INTEGER; { Driver reference number }
; END;
;
; The sdDrvNum field is $FFFF if the drive number is irrelevant.
; The sdRefNum field is $0000 if the first available device should be chosen.
;
; Destroys D0-D2/A0-A1.
;----------------------------------------------------------------------
SetDefaultStartup PROC EXPORT
; Write info to parameter RAM. Format is:
; $78 [ (byte) DriveId{for slots} | (byte) PartitionId | (word) RefNum ]
MOVE.L #$00040078,D0 ; Write 4 bytes starting at loc $78
_WriteXPRam ; Write it to PRAM.
RTS ; Return.
ENDPROC
IF hasSlotMgr THEN ; (what condition should this be???)
;----------------------------------------------------------------------
; Get more information about the current default startup device
;
; A0 -> A pointer to the record in which the info should be put.
;
; The record has the following format:
;
; RECORD
; sdOSType: BYTE; { Default OS type }
; sdReserved: BYTE; { Reserved }
; END;
;
; Destroys D0-D2/A0-A1.
;----------------------------------------------------------------------
GetOSDefault PROC EXPORT
; Read info from parameter RAM. Format is:
; $76 [ (byte) Reserved | (byte) OSType ]
MOVE.L #$00020076,D0 ; Read 2 bytes starting at loc $76
_ReadXPRam ; Get it from PRAM.
move.b #0, (A0) ; clear high byte
RTS ; Return.
ENDPROC
;----------------------------------------------------------------------
; Set more information about a new default startup device.
;
; A0 -> A pointer to the record from which the info should be taken.
;
; The record has the following format:
;
; RECORD
; sdOSType: BYTE; { Default OS type }
; sdReserved: BYTE; { Reserved }
; END;
;
; Destroys D0-D2/A0-A1.
;
; <1.4> SetOSDefault blindly set pram to the values pointed at by A0.
; Master pointers to rom resources on a macintosh ][ are of the
; form A083XXXX. The Trap number for SetOSDefault is A083. If
; a program crashed and started executing random blocks, then
; there was a good chance that it would try to execute a master
; pointer. The result would be that the default OS on reboot is
; not valid. Cross reference PB337 in system sources. The fix
; is to require a password, to prevent wandering programs from
; creating Chaos.
;
;----------------------------------------------------------------------
SetOSDefault PROC EXPORT
AppPhne EQU $09961010
cmpi.l #AppPhne, SetOSPassword ; check if oneshot is on
bne.s @errexit
clr.l SetOSPassword
; Write info to parameter RAM. Format is:
; $76 [ (byte) Reserved | (byte) OSType | (byte) DriveId{for slots} | (byte) PartitionId | (word) RefNum ]
MOVE.L #$00020076,D0 ; Write 2 bytes starting at loc $76
_WriteXPRam ; Write it to PRAM.
RTS ; Return.
@errexit clr.l SetOSPassword
moveq #-1,d0 ; signal error
rts ; and return
ENDPROC
;________________________________________________________________________________________
;
; Routine: Ck4LimitPRAMClear
;
; Inputs: none
;
; Outputs: Z: NE = only boot from Default device
; EQ = boot from Floppy or Default
; D0: NE = only boot from Default device
; EQ = boot from Floppy or Default
;
; Trashes: D0, A0
;
;________________________________________________________________________________________
Ck4LimitPRAMClear PROC EXPORT
IMPORT ValidatePRAM76 ; StartSearch.a
bsr ValidatePRAM76
subq.w #2,sp ; allocate buffer on stack
movea.l sp, A0 ; get buffer ptr
MOVE.L #$00010076, D0 ; Read 1 bytes starting at loc $76
_ReadXPRam
move.b (sp)+, D0
and.b #1, D0 ; low bit
rts
ENDPROC
;________________________________________________________________________________________
;
; Routine: ValidatePRAM76
;
; Inputs: none
;
; Outputs: none
;
; Trashes: none
;
; Function: Validates byte $76 of xpram: counts set bits in lower 6 and compares with
; upper two bits. If not equal, zeros out the byte.
;
; Note: Byte $76 (previously reserved but used by OSDefault stuff) is
; being defined as sensitive boot bits generally having to do with
; security issues driven by AIX but these functions can be used
; by other OSes as well. The upper two bits of byte $76 are a
; "checksum" of the other 6 bits (i.e. count of bits set). This
; is desired because of the danger if one of these bits is set
; accidentally by some bogus client. Failing this checksum will
; cause the byte to revert to 00 - a safe value. Currently defined
; bits are:
; 0: limit PRAM clear - don't clear PSWD, AUXPRAM, OSType, DefBoot
; 1: only load drivers from default device, don't boot from floppy
; 2: ignore CmdShiftOptDel
;
;________________________________________________________________________________________
vp76trashedRegs REG D0-D2/A0
ValidatePRAM76 PROC EXPORT
movem.l vp76trashedRegs, -(sp)
subq.w #2, sp ; allocate buffer on stack
movea.l sp, A0 ; get buffer ptr
MOVE.L #$00010076, D0 ; Read 1 bytes starting at loc $76
_ReadXPRam ; Get it from PRAM.
move.b (sp)+, D0
move.b #0, D2 ; zero reg for addx
moveq.l #0, D1 ; clear checksum
and.b #$3F, D0 ; get data bits (strip sum bits)
@bitloop
lsr.b #1, D0 ; get a bit
addx.b D2, D1 ; add that bit to checksum
tst.b D0 ; loop until no more bits
bne.s @bitloop
and.b #3, D1 ; only 2 low bits are valid
move.b (A0), D0 ; get byte 76 again
lsr.b #6, D0 ; get only checksum bits
cmp.b D0, D1 ; valid signature?
beq @valid ; Yes, don't clear all
move.b #00, -(sp) ; clean up bogus value
movea.l sp, A0 ; get buffer ptr
move.l #$00010076, D0 ; get #, addr PRAM bytes
_WriteXPram ; write out zeros to 76
move.b (sp)+, D0
@valid
movem.l (sp)+, vp76trashedRegs
rts
ENDP
;----------------------------------------------------------------------
; Get information about the current default video device.
;
; A0 -> A pointer to the record from which the info should be put.
;
; The record has the following format:
;
; RECORD
; sdSlot: BYTE;
; sdsRsrcId: BYTE
; END;
;
; sdSlot and sdsRsrcId are zero if no default.
;
; Destroys D0-D2/A0-A1.
;----------------------------------------------------------------------
GetVideoDefault PROC EXPORT
; Read info from parameter RAM. Format is:
; $80 [ (byte) Slot Number | (byte) sResource Number ]
MOVE.L #$00020080,D0 ; Read 2 bytes starting at loc $80
_ReadXPRam ; Get it from PRAM.
RTS ; Return.
ENDPROC
;----------------------------------------------------------------------
; Set information about the default video device.
;
; A0 -> A pointer to the record from which the info should be put.
;
; The record has the following format:
;
; RECORD
; sdSlot: BYTE;
; sdsRsrcId: BYTE
; END;
;
; sdSlot and sdsRsrcId are zero if no default.
;
; Destroys D0-D2/A0-A1.
;----------------------------------------------------------------------
SetVideoDefault PROC EXPORT
; Write info to parameter RAM. Format is:
; $80 [ (byte) Slot Number | (byte) sResource Number ]
MOVE.L #$00020080,D0 ; Write 2 bytes starting at loc $80
_WriteXPRam ; Write them to PRAM.
RTS ; Return.
ENDPROC
ENDIF
END