sys7.1-doc-wip/OS/StartMgr/StartSearch.a
2019-07-27 22:37:48 +08:00

1828 lines
64 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;
; 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