supermario/base/SuperMarioProj.1994-02-09/Drivers/Sony/SonyUtil.a

1012 lines
41 KiB
Plaintext
Raw Normal View History

2019-06-29 15:17:50 +00:00
;
; File: SonyUtil.a
;
; Contains: This file contains various utility routines used by the
; disk driver. It includes the powerup/powerdown logic, wakeup timing,
; seek, eject, recal, and speed determination.
;
; Written by: Larry Kenyon
;
; Copyright: © 1982-1990, 1992-1993 by Apple Computer, Inc., all rights reserved.
;
; Change History (most recent first):
;
; <SM10> 12/13/93 PN Roll in KAOs and Horror changes to support Malcom and AJ
; machines
; <SM9> 12/14/92 RC Restore to Before PDM D2 Build with Horror Roll-in
; <SM6> 12/7/92 rab Roll in Horror changes. Comments follow…
; <H6> 7/8/92 CMP Do BSR to CkEjectPatch instead of BRA. This was causing the
; rest of CkEjSw to not get executed, which in turn caused the VBL
; task to always post eject events for 800k drives.
; <H5> 3/18/92 SWC Reversed branch polarity in chip existance check in DiskVBLTask.
; <H4> 11/14/91 SWC Removed the patch to SetIWMMode since it won't be called except
; on an IWM, or SWIM in IWM mode. Changed the CkDCDExist patch to
; use more of the existing code. Check if a disk controller is
; installed in DiskVBLTask. Don't check the eject switch on
; SuperDrives. Converted SCC polling code to a macro to make it
; easier to overpatch.
; <H2> 10/18/91 CMP Overpatched SetIWMMode and CkDCDExist for SWIM2 support.
; Also, changed drive disable to not depend on MotorOn gating the
; enable lines.
; <SM5> 12/02/92 HY Added hasPwrControls conditionals.
; <SM4> 10/18/92 CCH Added nop's for systems with non-serial writes to IO space.
; <12> 7/14/92 CSS Fixed the comment below so an exact version of this
; file could be copied into SuperMario.
; <11> 4/27/92 JSM Get rid of conditionals: supportsPWM, supportsDCD, and
; has3rdFloppy are always false, forROM, supportsMFM, isUniversal,
; hasPowerMgr, and hasPwrControls are always true (although
; hasPowerMgr currently isnt for the ROM, it will be and was
; always ORed with hasPwrControls here anyway). This file now has
; no conditionals.
; <10> 1/17/91 GMR Added additional 15 µs delay to Wait100 after step goes high
; (per Sonys request) so the time between steps is not less than
; 72 µs.
; <9> 9/25/90 GMR Changed Recal to use fast (with handshake) step pulses for the
; new Buddy Lite SuperDrive.
; <8> 9/21/90 BG Removed <7>. 040s are behaving more reliably now.
; <7> 6/18/90 CCH Added NOPs for flaky 68040's.
; <6> 5/11/90 MSH Converted all onHcMac or hasPowerMgr conditionals to universal
; versions. Test is based on the existence of the power manager
; bit in the config word.
; <5> 4/26/90 GMR Backed out previous change (there was a recursive problem with
; it).
; <4> 2/2/90 GMR Modified ReCal to support low cost 800K drives (and low cost
; Superdrives) by using Seek to do the stepping (without 6/12msec
; delays), unless it's a 400K drive.
; <3> 1/16/90 MSH Roll in Portable changes from Fiction.
; <2> 1/15/90 MSH Prepare comment header for conversion.
; <2.4> 5/23/89 GGD No changes to this file, entire Sony Driver is checked out and
; in as a group.
; <2.3> 4/29/89 GGD No changes to this file, entire Sony Driver is checked out and
; in as a group.
; <2.2> 4/10/89 GMR No changes to this file, entire Sony Driver is checked out and
; in as a group.
; <2.1> 2/21/89 GGD Added VIA accesses during Pulse to waste some time to ensure
; adequate pulse width of LSTRB. Added VIA accesses in DiskSel to
; kill some time.
; <2.0> 12/15/88 GGD Added short delay loop in Seek loop to fix problem with seek
; errors on fast processors (like Cobra2). Changed some machine
; based conditionals to feature based.
; <1.1> 11/11/88 CCH Fixed Header.
; <1.0> 11/9/88 CCH Adding to EASE.
; <1.9> 9/29/88 GGD No changes to this file, entire Sony Driver is checked out and
; in as a group.
; <1.8> 9/19/88 GGD WC Made drive translation table stuff conditional for everyone
; but onMac.
; <1.7> 8/16/88 GGD Changed ref to DBase in FigTrkSpeed to use low mem loc IWM
; instead.
; <1.6> 7/15/88 GGD For HcMac, don't turn off drive power while ejecting.
; <1.5> 6/15/88 GGD No changes to this file, entire Sony Driver is checked out and
; in as a group.
; <1.4> 5/25/88 GGD No changes to this file, entire Sony Driver is checked out and
; in as a group.
; <1.3> 5/24/88 GGD No changes to this file, entire Sony Driver is checked out and
; in as a group.
; <1.2> 5/3/88 GGD No changes, entire sony driver checked out and in as a group.
; <1.1> 4/18/88 GGD Merged in MFM support <C437> by Steve Christensen Change WakeUp
; to use the TimeMgr when forRAM too. Change LoadPWMBuf to use
; PWMBuf1 when forRAM too. Added conditional code based upon
; onMacPPpatch=1 to add code to WakeUp and DiskSelect to only jump
; to the patch if it starts with a NOP, because those two routines
; are patched in the system disk 5.0 patches, and executing those
; patches with the new SuperDrive roms would cause the system to
; crash. Fixed Seek to check mfmMode instead of mfmDisk before
; calling SetParams (causes problems with 800K format on 1440K
; media)
; 3/28/88 GGD Fixed Seek to check mfmMode instead of mfmDisk before calling
; SetParams (causes problems with 800K format on 1440K media)
; 2/26/88 SWC PowerUp: wait an additional 600ms on writes (and formats) if the
; motor had to be turned on to guarantee motor speed within ±1.5%.
; <1.0> 2/12/88 BBM Adding file for the first time into EASE…
; <C437> 1/28/88 SWC Changed PowerUp so that if a MFM<->GCR drive mode switch is
; being made, it will force a wait even if the drive is powered
; up.
; <C437> 12/15/87 SWC Swapped usage of D2 & D5 in Seek because WakeUp was trashing D2
; when seeking on 400K disks.
; <C437> 12/8/87 SWC Added a call to SetParams in Seek if an MFM disk is installed.
; <C907> 10/8/87 MSH Port to HcMac (Laguna).
; <A855> 5/27/87 CSL Fixed the performance problem of the upper internal drive.
; <C511> 12/12/86 TJ Ints off in WakeUp to prevent convoluted path from PrimeTime
; back into WakeUp/WakeSetUp.
; <A351> 11/5/86 TJ Cleaned up the text, added ejects. Separated SetIWMMode from
; Recal; Fixed bug in SetIWMMode that destroyed D1 (but was never
; executed??)
; <A302> 10/30/86 TJ For old 400K drive support, rearm T2 to interrupt immediately,
; to avoid loss of TimeMgr interrupts. (FigTrkSpd keeps ints off
; for so long any T2 int has long since gone by ...)
; <A216> 10/17/86 TJ Upped Sony VBL task interrupt level from 1 (VBL) to 3 so that
; AppleTalk cant get in; fileserver activity can initiate disk
; access, which get messed up because the VBL task is fiddling
; down there ... this really needs to get handled in some
; reasonable way, like Active(SonyVars) used as a non-reentrancy
; flag or something ... but then AppleTalk would have to "back
; out" ... etc.
; <C123> 9/3/86 TJ Added Eject Button polling in VBL task.
; <C97> 7/24/86 TJ Repaired WakeUp & WakeGo to set up for the interrupt before
; enabling it, eliminating the "I'll be ready before the interrupt
; happens" (but was not) case, ie. AppleTalk interrupt taking
; longer than the WakeUp delay time. Added logical to physical
; drive translation in GetDrive(), plus added GetRDrive, that does
; not translate.
; <C1> 4/25/86 RDC Added changes for new 68020 Reno project (NuMac) - Changed
; setting of IWM mode
; <C437> 3/19/86 SWC Patched Recal to call SetChipMode instead of SetIWMMode if a
; SWIM is installed so that the appropriate registers will be
; initialized. Seek: moved the "set direction" out of and cleaned
; up the step loop. Patched PowerUp to switch a SuperDrive into
; either constant or variable speed mode for MFM or GCR,
; respectively. Made MFM mode patches to AdrDisk, Sense, Pulse,
; DiskSelect, and a few other places so that the SWIM HW is
; accessed correctly.
; 10/25/85 LAK PowerDown sets up TimeOutDrive. DiskSelect calls PowerDown if
; TimeOut nonzero and TimeOutDrive is not Drive. Vectored
; DiskSelect for ROM. Use NewIntf rather than Sides to determine
; whether drive has new interface. Split WakeUp into WakeSetUp and
; WakeGo for RWT fix.
; 10/24/85 LAK WakeUp now uses new timer routines. Added routine InvalTrkCache.
; 7/29/85 RDC Added changes for MidMac: - changed interrupt level settings to
; use equates - removed DCD code - changed VIA timer and timing
; loops to use equates - adjusted tach frequency tables - replaced
; make speed table routine w/ 800 ms delay
;
;_______________________________________________________________________
;
; Routines: GetDrive, GetDrv1, AdrAndSense, AdrAndStrb, AdrDisk, Pulse, Sense,
; SetSpeed, SetASpeed, Eject, Seek, Seek1, WakeUp, Recal, SetIWMMode,
; PowerDown, PowerUp, DiskSelect, MakeSpdTbl, FigTrkSpeed,
; DiskVBLTask.
;
; Register Conventions:
; A3,A4: used for return addresses, highest level (MakeSpdTbl)
; also use D3-D4 to keep values, may trash all other regs
; A5,A6: used for return addresses, lowest level (Seek, Recal)
; also use D5,D6,D7 to keep values, must preserve A3-A4/D3-D4.
; DskRtnAdr: used by RdAddr,RdData,WrData,WakeUp to store return address.
; Utility routines must preserve registers D3-D7/A3-A6 (though many
; preserve all regs except D0).
;_______________________________________________________________________
eject ; <A351/05nov86>
;_______________________________________________________________________
;
; Routine: GetDrive,GetDrv1,GetRDrive
; Arguments: A1 (output) -- pointer to driver variables
; D1 (output) -- word offset of current drive's specific vars
; A0 (output) -- IWM base ptr
; A2 (output) -- VIA base ptr
; Called By: (GetDrive): AdrDisk,WakeUp,WakeRcvr,DiskSelect,
; Check4Disk
; (GetDrv1): SetSpeed(2x),SetASpeed,Seek1(2x),PowerUp,
; PowerDown,MakeSpdTbl,EmptyPD,CkDrvNum
; (GetRDrive): DiskOpen
; Function: Get much-used values into D1,A0,A1, and A2.
;
;Note: This is called with Drive(A1) set to maxDrvNum + 1 in DiskOpen;
; this is for determining the presences of the passThru function
; on DCDs. To avoid problems GetDrvx bounds the drive number to
; maxDrvNum.
;_______________________________________________________________________
BLANKS ON
STRING ASIS
DrvVarOS DC.W Drive1 ; offsets into SonyVars <C97/28jul86>
DC.W Drive2 ; one for each drive <C97/28jul86>
;
;Return the stuff, but do not translate the drive number.
;
GetRDrive move.l IWM,A0 ;set up hardware pointers <C97/28jul86>
move.l VIA,A2 ; <C97/28jul86>
bsr.s GetDrv2 ; <C97/28jul86>
move.w DrvVarOS-2(D1),D1 ;untranslated drive vars <C97/28jul86>
rts ; <C97/28jul86>
;
; Return the stuff, but logically translate the drive number.
;
GetDrive MOVE.L IWM,A0 ;set up pointers to hardware
MOVE.L VIA,A2
GetDrv1
bsr.s GetDrv2 ;get basic setup stuff, <C97/28jul86>
move.w DrvVarOS-2(D1),D1 ;driver vars offset <C97/28jul86>
rts ; <C97/28jul86>
GetDrv2 move.l SonyVars,A1 ; <C97/28jul86>
move.w Drive(A1),D1 ;logical drive number, <C97/28jul86>
cmp.w #maxDrvNum,D1 ;if > max drive # <C115/13aug86>
BLS.S GetDrv3 ;bound to max (passThru test) <C437/28sep87>
MOVEQ #maxDrvNum,D1 ; <C437/28sep87>
GetDrv3 add.w D1,D1 ;make word ptr <C97/28jul86>
rts ; <C97/28jul86>
eject ; <A351/05nov86>
;_______________________________________________________________________
;
; Routine: AdrAndSense, AdrAndStrb, AdrDisk, Pulse, Sense
; Arguments: A1 (output) -- pointer to driver variables (input for GetOther)
; D1 (output) -- word offset of current drive's specific vars
; A0 (output) -- IWM base ptr
; A2 (output) -- VIA base ptr
; Called By:(AdrDisk): RdAddrSetup,AdrAndSense,AdrAndStrb,FigTrkSpeed,Eject
; (AdrAndStrb): Seek,Recal,PowerDown,Check4Disk
; (AdrAndSense): Seek,Recal(2x),PowerUp,Check4Disk(3x),CkInstll(2x),
; CkDIP(2x),CkWrProt
; (Pulse): AdrAndStrb,Seek,Recal,PowerUp
; (Sense): AdrAndSense
; Function: Utility routines used in addressing and configuring disk.
;_______________________________________________________________________
; D0 is 'address' (ca1-ca0-sel-ca2)
AdrDisk BSR.S GetDrive ; setup A0,A1,A2,D1
TST.B mfmMode(A1) ;Are we in MFM mode? <C437/25feb87>
BMI mAdrDisk ;-> yes, set phases SWIM style <C437/25feb87>
TST.B Ph0H(A0) ; when changing SEL from 1 to 0,
TST.B Ph1H(A0) ; CA0=CA1=1 must be true
LSR.B #1,D0 ; CA2 state
BCC.S @0
TST.B Ph2H(A0) ; set high
BRA.S @1
@0 TST.B Ph2L(A0) ; set low
@1 LSR.B #1,D0 ; SEL state
BCC.S @2
BSET #VHeadSel,VBufD(A2) ; set high
if NonSerializedIO then
nop ; force write to complete <SM4>
endif
BRA.S @3
@2 BCLR #VHeadSel,VBufD(A2) ; set low
if NonSerializedIO then
nop ; force write to complete
endif
@3 LSR.B #1,D0 ; CA0 state
BCS.S @4
;TST.B Ph0L(A0)
TST.B (A0)
@4 LSR.B #1,D0 ; CA1 state
BCS.S @5
TST.B Ph1L(A0)
@5 RTS
AdrAndSense BSR.S AdrDisk
Sense
TST.B mfmMode(A1) ;Are we in MFM mode? <C437/25feb87>
BMI mSense ;-> yes, read sense SWIM style <C437/25feb87>
MOVE SR,-(SP)
ORI #HiIntMask,SR ; no interrupts <29Jul85>
TST.B Q6H(A0) ; get into sense mode
MOVE.B Q7L(A0),D0 ; sense it
TST.B Q6L(A0) ; back to read mode
MOVE (SP)+,SR
TST.B D0
RTS
AdrAndStrb BSR.S AdrDisk
Pulse
TST.B mfmMode(A1) ;Are we in MFM mode? <C437/25feb87>
BMI mPulse ;-> yes, pulse LSTRB SWIM style <C437/25feb87>
MOVE SR,-(SP)
ORI #HiIntMask,SR ; no interrupts <29Jul85>
TST.B Ph3H(A0) ; pulse it high, then low
MOVE.B VBufD(A2),VBufD(A2) ; access VIA to kill some time <2.1>
if NonSerializedIO then
nop ; force write to complete
endif
TST.B Ph3L(A0)
MOVE (SP)+, SR
RTS
eject ; <A351/05nov86>
;_______________________________________________________________________
;
; Routine: Seek,Seek1
; Arguments: D6.W (input) -- track to seek to (bit 11=1 means side 1)
; D0 (output) -- result code
; Disk speed is set appropriately for the track.
; A3-A4/D3-D4 are preserved. D6, bit 11 is cleared.
; All other registers are clobbered
; This routine returns to one level above the caller during
; the seek (unless no seek is required).
; Seek1 is used when the speed table is not valid.
; Called By: (Seek1): MakeSpdTbl
; (Seek): ReSeek (in RWT logic)
; Function: Seek to a track.
;_______________________________________________________________________
Seek BCLR #11,D6 ; clear side bit (for now . . .)
Seek1 MOVE.L JSeek,-(SP)
RTS
jtSeek MOVE.L (SP)+,A6 ; save caller's address
; D6 holds the track sought . .
BSR GetDrv1
MOVE.W Track(A1,D1),D7 ; current track
BPL.S SeekLp ; br if curTrack is valid
BSR ReCal ; recal to get into a known state
MOVE.W D0,D7 ; current track
BRA.S SeekEnd ; exit after recal to avoid slipped cog
SeekLp MOVEQ #DirLAdr,D0 ;Assume step in <C437/17jun87>
MOVE.W D6,D5 ;Calculate the number of steps to take <C437/15dec87>
SUB.W D7,D5 ;Already there? <C437/15dec87>
BEQ.S SeekEnd1 ;-> yes, don't wait head settle time <C437/17jun87>
BGT.S @1 ; <C437/17jun87>
MOVEQ #DirHAdr,D0 ;We're stepping out <C437/17jun87>
NEG.W D5 ; so make the step count positive <C437/15dec87>
@1 BSR AdrAndStrb ;Set the stepper direction <C437/17jun87>
MOVEQ #cantStepErr,D7 ;Assume one of the steps will fail <C437/17jun87>
SUBQ.W #1,D5 ;Adjust count for DBRA <C437/15dec87>
SeekLp1 MOVEQ #StepLAdr,D0 ;Make sure /STEP starts out high <C437/17jun87>
BSR AdrAndSense ; <C437/17jun87>
BPL.S SeekEnd ;-> it wasn't, so exit with error <C437/17jun87>
BSR Pulse ;Then set it low <C437/17jun87>
BSR.S Wait100 ; and wait a while for it to go high <C437/17jun87>
DBRA D5,SeekLp1 ; <C437/15dec87>
MOVE.W D6,D7 ;Successful seek so update curr track <C437/17jun87>
SeekEnd BSR GetDrv1
MOVE.W D7,Track(A1,D1) ; update current track
TST.B mfmMode(A1) ;Are we in MFM mode? <C437/08dec87><1.1/28mar88>
BPL.S @00 ; <C437/08dec87>
BSR SetParams ;Yes, setup RAM parms for this disk zone<C437/08dec87>
BEQ.S @00 ; <C437/08dec87>
MOVE.W D0,D7 ;Error, so save the result code <C437/08dec87>
@00 ; <C437/08dec87>
MOVE.W HeadSettle(A1),D0 ; wait head settle time or until ready (new drive)
MOVEQ #5,D2 ; wait 500usec first time
BSR.S WaitReady ; <C437>
IF isUniversal THEN ; <H35>
TestFor hwCbPwrMgr ; is this a powerbook? <H35>
BEQ.W SeekEnd1 ; -> no, skip around artificial delay <H35>
MOVE.W #500,D0 ; need to wait 50 msec for drive to settle <H35>
BSR.W Wakeup ; just detecting /READY isn't enough <H35>
ENDIF ; <H35>
SeekEnd1 MOVE.W Wait(A1),D0 ; wait any speed change, power-on time
MOVEQ #0,D2 ; wait 0 time, first time
BSR.S WaitReady ; <C437>
MOVE.W D7,D0 ; positive value = success
SeekExit JMP (A6) ; A6 has return address
Wait100 MOVE.W SeekTime(A1),D0 ; wait 12 ms for old drive
BSR.S CheckNew ; go to WakeUp for the old interface
MOVEQ #80, D2 ; wait until step goes hi or timeout <C437/15dec87>
@1 MOVEQ #StepLAdr,D0
BSR AdrAndSense
DBMI D2, @1 ; <C437/15dec87>
; There appears to be an undocumented timing restriction related to sending step
; pulses to the drive. When /Step goes high, the spec indicates that you may immediatly
; set it low again to send the next pulse, however it appears that if you attempt to
; set it low within 18µsec of when it went high, it will not accept the step pulse,
; and will remain high. This will lead to seek errors, and is most noticable on
; processors that run at high clock rates (faster than the Mac IIx). If this is for
; a RAM based version of the MacPlus driver, we don't include it, since timeDBRA
; is not available on the MacPlus (but if we build a new MacPlus ROM we should support
; timeDBRA and this wait loop).
MOVE.W TimeDBRA,D2 ; 1000 µsec <2.0>
LSR.W #5,D2 ; 31.25 µsec (1000/32) <2.0><10>
@wait DBRA D2,@wait ; kill 31.25 µsec <2.0>
RTS
CheckNew TST.B NewIntf(A1,D1) ; new drive interface? <25Oct85>
BMI.S @1 ;-> yes (don't use wakeup) <C437/24nov86>
ADDQ #4, SP ; discard local return address <C437/24nov86>
TST.W D0 ; any time to wait? <C437/24nov86>
BNE.S WakeUp ; br if so <C437/24nov86>
@1 RTS ; <C437/24nov86>
waitReady BSR.S CheckNew ; go to WakeUp for the old interface
MOVE.L (SP)+, A4 ; get return address
MOVE.W #1000, D5 ; timeout (1 sec max to ready, any case)
MOVE.W D2, D0 ; first time wait
BEQ.S @2 ; check ready immediately if 0
@1 BSR.S WakeUp ; wait D0 * 100usec
@2 MOVEQ #ReadyAdr, D0 ; /Ready sense address
BSR AdrAndSense
BPL.S @3 ; br if /Ready asserted
MOVEQ #10,D0 ; check every millisec? - tune for seek
DBRA D5, @1 ; if we timeout, we must be ready?? Sony won't gate
; writes off if not ready (in case of bouncy ready line . . .)
@3 CLR.W Wait(A1) ; no extra wait time
JMP (A4)
eject ; <A351/05nov86>
;_______________________________________________________________________
;
; Routine: WakeUp,WakeSetUp,WakeGo
; Arguments: D0 (input) -- number of 100 usec intervals to wait (<65536)
; registers A3-A5 and D3-D7 are preserved.
; Called By: (WakeUp): Seek(3x),Eject,Recal,PowerUp
; (WakeSetUp,WakeGo): GotSect(RWT),WrgSectAdr(RWT)
; Function: Saves the return address in DskRtnAdr; it will call this
; routine after the timer interrupt in which the count is
; exhausted. Since the timer ticks away at 780 KHz,
; there are 78 timer ticks in each 100 microsecond interval.
; For MidMac timer ticks at 1.57 MHz so timer ticks = 157.
;_______________________________________________________________________
WakeUp
MOVE.L JWakeUp,-(SP)
RTS
jtWakeUp MOVEM.L D3-D7/A3-A6,SaveRegs(A1); save caller's regs first <C97/24jul86>
MOVE.L (SP)+,DskRtnAdr ; save return address next <C97/24jul86>
BSR.S WakeSetUp ; configure timer for D0 wait <25Oct85>
bra.s WakeRet ; go execute it. <C97/24jul86>
WakeGo MOVEM.L D3-D7/A3-A6,SaveRegs(A1); save caller's regs first <C97/24jul86>
MOVE.L (SP)+,DskRtnAdr ; save return address next <25Oct85>
WakeRet MOVEQ #0,D0 ; go back to user with no err
ANDI #$F8FF,SR ; and VIA interrupts enabled
RTS
WakeSetUp ; New WakeUp uses T2 Timer manager <25Oct85>
MOVE.L SonyVars,A1 ; <27Oct85>
SUB.W D0,Wait(A1) ; decrement any Wait time . . .
BGT.S @1 ;
CLR.W Wait(A1) ; pin at 0
@1 LEA TimeQEl(A1),A0 ; point at queue element
LEA GoWakeIt,A1 ; <27Oct85>
MOVE.L A1,tmAddr(A0) ; want to come here first <27Oct85>
AND.L #$0000FFFF,D0 ; clear high word of D0
CMP.W #10,D0 ; need to pin D0 to 10 (100usec intervals)
BCC.S @2
MOVEQ #10,D0
@2 DIVU #10,D0 ; divide by ten for msec
EXT.L D0 ; PrimeTime takes count in D0 long
MOVE.L jPrimeTime,A1 ; use dispatch table vector
JSR (A1) ; to start the timer (pass A0=TimeQEl ptr)
BRA GetDrv1 ; restore A1/D1 (and return) <27Oct85><C437/28jan88>
GoWakeIt MOVEM.L D0-D7/A0-A6,-(SP) ; save ALL regs
BSR GetDrive ;
MOVEM.L SaveRegs(A1),D3-D7/A3-A6 ; get back regs we saved
MOVEQ #0,D0 ; D0 = for RWT-MakeSpdTbl new intf path <25Oct85>
BSR DskRtn ; call DskRtnAdr
MOVEM.L (SP)+,D0-D7/A0-A6 ; restore registers
RTS ; we're done with it!
eject ; <A351/05nov86>
;_______________________________________________________________________
;
; Routine: Recal
; Arguments:
; D0 (output) -- result code
; This routine returns to one level above the caller during
; the recal (unless no seek is required).
; Called By: (Recal): Seek,DiskPrime,DoRecal
; Function: Recal to track 0. Leaves drive powered up. Sets IWM mode
; register.
;_______________________________________________________________________
Recal MOVE.L JRecal,-(SP) ; use RAM vector <03Mar85>
RTS ; <03Mar85>
jtRecal MOVE.L (SP)+,A5 ; save return address
BSR GetDrive
BSR InvalTrkCache ; invalidate track cache <A351/05nov86><24Oct85>
BSR SetChipMode ;Initialize appropriate register set<C437/19mar87>
bne.s RecalExit ; couldn't set IWM Mode <A351/05nov86>
BSR RWPowerUp ;Re-enable the interface <C437/19mar87>
MOVEQ #80,D7 ; maximum number of steps needed
MOVEQ #DirHAdr,D0 ;Set direction out (toward track 0) <C437/17jun87>
BSR AdrAndStrb ; <C437/17jun87>
TST.B NewIntf(A1,D1) ; new drive interface? <9>
BPL.S SlowLoop ; br if not (use slow step time) <9>
SUBQ #1,D7 ;Adjust count for DBRA <9>
@SeekLoop MOVEQ #StepLAdr,D0 ;Make sure /STEP starts out high <9>
BSR AdrAndSense ; <9>
BPL.S RecalFail ;-> it wasn't, so exit with error <9>
BSR Pulse ;Then set it low <9>
BSR.S Wait100 ;and wait a while for it to go high <9>
DBRA D7,@SeekLoop ;count track <9>
BRA.S ReCalled ;done 80 steps, exit... <9>
SlowLoop MOVE.W SeekTime(A1),D0 ; wait 12 ms <9>
BSR WakeUp
MOVEQ #Tk0Adr,D0 ;
BSR AdrAndSense ;
BPL.S ReCalled ; keep going until track 0 is true
MOVEQ #StepLAdr,D0 ; set step low
BSR AdrAndSense ; address it
BPL.S RecalFail ; can't recal (won't step, isn't at tk 0)
MOVEQ #tk0BadErr,D0 ; assume error
SUBQ.W #1,D7 ; reached maximum step count?
BEQ.S RecalExit ; exit if so
BSR Pulse ; then set it low
BRA.S SlowLoop ;
RecalFail MOVEQ #cantStepErr,D0 ; no track
BRA.S RecalExit
ReCalled MOVEQ #0,D0 ; track 0
RecalExit MOVE.W D0,Track(A1,D1)
JMP (A5)
eject ; <A351/05nov86>
;_______________________________________________________________________
;
; Routine: SetIWMMode
; Arguments:
; D0 (output) -- result code
; Called By: Recal,Seek,DiskPrime,DoRecal
; Function: Set the mode register of the IWM in case it glitched out (or first time).
; It no longer re-powers up the drive. <C437/08dec86>
;_______________________________________________________________________
SetIWMMode TST.B Q6H(A0) ; set IWM to sense mode
MOVEQ #$1F,D0 ;(mask for mode bits) <C437/20may87>
AND.B Q7L(A0),D0 ; sense the mode register <C437/20may87>
TST.B Q6L(A0) ; and back to read mode
CMP.B #IWMMode,D0 ; see if correct mode is set <A351/05nov86>
BEQ.S @2 ; br if so <C437/20may87>
MOVEQ #OneSecConst,D2 ; loop timeout count <29Jul85>
SWAP D2 ; should be about a second
@1 MOVEQ #initIWMErr,D0 ; assume timeout error
SUBQ.L #1,D2 ; decrement timeout loop
BMI.S @3 ; exit on error ... <A351/05nov86>
TST.B MtrOff(A0) ; change the IWM mode now
TST.B Q6H(A0) ; set IWM to sense state
MOVEQ #$3F,D0 ;(mask for sense, mode bits) <C437/20may87>
AND.B Q7L(A0),D0 ; sense the mode register <C437/20may87>
BCLR #5,D0 ; interface should be disabled <C437/20may87>
BNE.S @1 ; keep waiting
cmp.b #IWMMode,D0 ; see if low bits match <A351/05nov86>
BEQ.S @2 ; if so, we are done
MOVE.B #IWMMode,Q7H(A0) ; set to sony mode <A351/05nov86>
if NonSerializedIO then
nop ; force write to complete
endif
TST.B Q7L(A0) ; set IWM back to sense state
BRA.S @1 ; loop back just to check
@2 TST.B Q6L(A0) ; and back to read mode...
moveq #0,D0 ; repower the drive ... <A351/05nov86>
@3 rts ; <A351/05nov86>
eject ; <A351/05nov86>
;_______________________________________________________________________
;
; Routine: PowerDown,RWPowerDown
; Arguments: D0 (input) -- power-down time
; TimeOut (out) -- set to D0 input value
; TimeOutDrive (out) -- set to Drive if D0 nonzero
; Called By: DiskControl(Eject,KillIO calls),DskOff(RWT),DiskSelect
; Function: Does VBL task stuff; just powers off current drive if D0=0.
;_______________________________________________________________________
PowerDown BSR GetDrv1 ;
MOVE.W D0,TimeOut(A1) ; set up timeout
BEQ.S @1 ; branch if immediate power-down
MOVE.W Drive(A1),TimeOutDrive(A1) ; remember drive with timeout <25Oct85>
RTS
@1 MOVEQ #MtrOffAdr,D0
BSR AdrAndStrb ; turn it off both ways: PAL
MOVE.B #$86,wZeroes(A0) ;Kill the drive enable SWIM2 style <H2><SM6>
if NonSerializedIO then
nop ; force write to complete
endif
TST.B MtrOff(A0) ; cut the enable to power it down
RTS
;_______________________________________________________________________
;
; Routine: InvalTrkCache
; Arguments:
; A1 (input) -- SonyVars ptr
; D0 trashed
; Called By: Recal, Eject
; Function: Invalidates the track cache if it holds data for the current
; drive.
;_______________________________________________________________________
InvalTrkCache
MOVE.W TCDrive(A1),D0 ; get current track-cache drive <24Oct85>
CMP.W Drive(A1),D0 ; this drive? <24Oct85>
BNE.S @1 ; br if not <24Oct85>
CLR.W TCDrive(A1) ; invalidate it if so <24Oct85>
@1 RTS
;_______________________________________________________________________
;
; Routine: RWPowerUp,PowerUp
; Arguments: D0 (input) -- power-up time
; Timeout, Power, Wait, Drive
; Sets interrupt level 0 if powers up; uses A0-A2,D0-D2 (by wakeup) .
; 'Active' should be true when this routine is called.
; Called By: (RWPowerUp): RWPower,SetIWMMode
; (Fast Power): DiskControl(Eject call),DiskPrime
; Function: PowerUp is called to power up a disk drive. Waits out D0 time
; unless disk is already powered . . .
;_______________________________________________________________________
FastPower MOVEQ #0,D0
BRA.S PowerUp
RWPowerUp MOVE.W PwrOnTime(A1),D0
PowerUp MOVE.W D0,D2 ; save wait time
BSR.S DiskSelect ; go enable the interface
MOVE.B mfmDrive(A1,D1),D5 ;Is this a SuperDrive? <C437/28jan88>
BPL.S @1 ;-> no, don't have to set drive mode<C437/24nov86>
MOVEQ #GCRModeAdr,D0 ;find out which way the drive is set<C437/04feb88>
BSR AdrAndSense ; <C437/04feb88>
MOVE.B D0,-(SP) ; and save the state (bit7=1: MFM) <C437/04feb88>
MOVEQ #GCRModeAdr,D0 ;Assume we're in GCR mode <C437/24nov86>
MOVE.B mfmDisk(A1,D1),D5 ;Are we? <C437/28jan88>
BPL.S @0 ; <C437/24nov86>
MOVEQ #MFMModeAdr,D0 ;No, select MFM drive mode <C437/24nov86>
@0 BSR AdrAndStrb ;set the drive mode as desired <C437/04feb88>
MOVE.B (SP)+,D0 ;get the previous drive mode <C437/08feb88>
EOR.B D0,D5 ;bit 7=1 if the mode has changed <C437/04feb88>
@1 ; <C437/24nov86>
MOVEQ #MtrOnAdr,D0
BSR AdrAndSense ; is it already powered up?
OR.B D5,D0 ;or we just did a mode change? <C437/28jan88>
BPL.S @2 ; br if so <C437/28jan88>
BSR Pulse ; turn power on
MOVE.W D2,D0 ; get back wait time
MOVE #750,D2 ; wait at least 75ms the first time
MOVE.L (SP)+,D4 ;(jump up a stack level) <C437/26feb88>
BSR waitReady ; <C437/26feb88>
MOVE.L D4,-(SP) ;(restore stack level--rtn addr) <C437/26feb88>
CMP.B #ARdCmd,Command+1(A1) ; is it a read? <C437/26feb88>
BEQ.S @2 ;-> yes, all done <C437/26feb88>
MOVE.W #600*10,D0 ;for writes, we need to wait about <C437/26feb88>
BRA WakeUp ; 600ms after /READY for speed ±1.5%<C437/26feb88>
@2 RTS ; return <C437/28jan88>
eject ; <A351/05nov86>
;_______________________________________________________________________
;
; Routine: DiskSelect,DiskSel1
; Arguments: Drive -- drive to enable
; D1,A0,A1,A2 set up per GetDrive
; Clobbers D0.
; TimeOut cleared and TimeOutDrive powered off if not Drive.
; DiskSel1 is a quick entry for DiskSense
; Called By: (DiskSelect): PowerUp,DiskPrime,DiskOpen(2x),DiskControl,
; DCDStatus(Format/Verify),DCDHardReset.
; (DiskSel1): Ck4Disk
; Function: Assert the IWM enable to a drive. For DCDs, this is functionally
; equivalent to PowerOn since that function is not called. Whenever
; the enable to a floppy drive is cut, it is powered down automatically.
;
;_______________________________________________________________________
DiskSelect BSR GetDrive
DiskSel1
MOVE.L JDiskSel,-(SP) ; vector this routine
RTS
jtDiskSel
TST.W TimeOut(A1) ; timeout pending? <25Oct85>
BEQ.S @0 ; br if not <25Oct85>
MOVE.W TimeOutDrive(A1),D0 ; see if it's us <25Oct85>
CMP.W Drive(A1),D0 ; ? <25Oct85>
BEQ.S @0 ; br if so <25Oct85>
MOVEQ #0,D0 ; turn it off immediately <25Oct85>
BSR PowerDown ; (it will still be selected) <25Oct85>
@0 CLR.W TimeOut(A1) ; clear pending timeout <11Jun85>
TST.B mfmMode(A1) ;Are we in MFM mode? <C437/19mar87>
BMI mDiskSelect ;-> yes, do the MFM version <C437/19mar87>
CMP.W #drive1,D1 ; if Drive=1, it's internal
BNE.S @1 ; br if not
TST.B IntDrive(A0) ; select internal drive
TST.B MtrOn(A0) ; assert /enb
RTS
@1 TST.B Ph2H(A0) ; we may already be enabled in
TST.B Ph1H(A0) ; state 2, so go safely thru 6
TST.B Ph0H(A0) ; to state 7 (Ph0=Ph1=Ph2=1)
BCLR #vHeadSel,VBufD(A2) ; set HdSel low (/Exists addr)
if NonSerializedIO then
nop ; force write to complete
endif
@2 TST.B ExtDrive(A0) ; select the external
TST.B MtrOn(A0) ; and enable the disk, IWM style
RTS
eject ; <A351/05nov86>
;_______________________________________________________________________
;
; Routine: MakeSpdTbl,GetFreq1
; Arguments: Drive (input) -- current drive
; D0 (output) -- error code (-1 = drive not installed)
; all registers are used.
; current drive is powered up and recal'ed.
; Called By: (MakeSpdTbl) CheckDIP,DoRecal
; (GetFreq1) RWT, Format
; Function: Makes a speed table for the current drive.
;
; Note: Drive must spin at speed codes 128 and 256 for this routine
; to work.
;
; Note: Speed variation has three major factors, temperature drift, speed
; drift, and load variation. Temperature drift occurs as the drive gets
; warmer and generally? is a negative factor (drive slows) accounting for
; up tp 6%? of speed variation. Speed drift occurs during
; the first minute the drive is powered and is a negative factor accounting
; for less than 1/2 of 1% of speed variation. Load is a factor which
; varies between inside and outside tracks of a drive: the inner tracks
; present less loading to the head than the outer tracks; speed variation
; due to loading may be as much as 1%.
;
; The main read/write track logic adjusts for speed drift by periodically
; checking the disk speed and adjusting the speed code if the speed is off
; by more than 2% using a speed code delta figured out by this routine: this
; should also catch any speed drift problems, depending upon the period
; of the check.
;
; We ignore loading variation since it is only 1% max and we will recheck
; each speed class when we first seek to it. Temperature and speed drift
; are not as easy to compensate for, but since they are both negative factors,
; this routine rounds to higher speed values.
;
;_______________________________________________________________________
MakeSpdTbl MOVE.L JMakeSpdTbl,-(SP)
RTS
jtMakeSpdTbl
MOVE.W #8000,D0 ; delay for 800 ms on new drive <29Jul85>
BRA WakeUp ; (to seat diskette correctly) <25Oct85>
eject ; <A351/05nov86>
;_______________________________________________________________________
;
; Routine: FigTrkSpeed,DskRtn
; Arguments: D0 (output) -- -1=timeout reached or long VIA count for one rev
; Called By: (FigTrkSpeed): MakeSpdTBL
; (DskRtn): WrData,RdAddr,RdData,GoWakeIt(WakeUp)
; Function: This routine measures the time (in VIA counts) it takes
; for the disk to revolve .25 times; this test looks for the tach
; pulse which occurs 60 times per rev. VIA timer 2 is used; if
; 15 tach pulses are not seen in 78 msec, this routine
; will time out and take the error exit.
;
; The drive should be powered when this is called. Speeds as
; low as 192 RPM may be measured.
;_______________________________________________________________________
FigTrkSpeed MOVE.L JFigTrkSpd,-(SP)
RTS
jtFigTrkSpd MOVEQ #-1,D0 ; no PWM, don't use timer
RTS
DskRtn MOVE.L DskRtnAdr,-(SP)
TST.W D0 ; set CCR
RTS
eject ; <A351/05nov86>
;_______________________________________________________________________
;
; Routine: DiskVBLTask
; Arguments: A0.L (input) -- disk VBL queue block ptr
; This routine MUST preserve A4-A6 and D4-D7 (like any VBL task)
; TimeOut non-zero, positive value if power-down is pending
; DiskInPlace drive variable
; Power drive variable
;
; Function: This VBL task handles disk power-down delays and checks for
; diskette-inserted and disk-eject-switch when both drives are
; powered down.
;
; - on power-down delays, add a check for a flag which says "call flush volume
; first . . ."; this could be the paranoia bit . . .
;_______________________________________________________________________
DiskVBLTask
MOVE SR,-(SP)
MOVE.L SonyVars,A1
MOVE.W DskVBLTime(A1),VBLCount(A0) ; reset VBL task
IF hasPwrControls THEN ; <SM5>
TestFor hwCbPwrMgr
BEQ.S @pmgrdone
BSR TurnIWMon ; IWM needed now <C907><v2.3>
@pmgrdone
ENDIF ; <SM5>
MOVE.B isSWIM(A1),D0 ; see if the IWM/SWIM/... is installed <H15><SM6>
SUBQ.B #1,D0 ; <H15><SM6>
BNE.S @Done ; -> yes, just return <H15><SM6>
CLR.W TimeOut(A1) ; clear any pending timeouts <SM6>
CLR.W LastDrive(A1) ; and show no last drive <SM6>
@Done ; <SM6>
BEQ.S DiskVBLExit ; -> no IWM/SWIM/... chip installed <H5><SM6>
ORI #HiIntMask,SR ; no VBL & AppleTalk (fileserver) <A351/05nov86><A216/17oct86><29Jul85>
TST.B Active(A1) ; any active requests?
BNE.S DiskVBLExit ; exit if so
TST.W TimeOut(A1) ; timeout pending?
BEQ.S @1
@0 SUBQ.W #1,TimeOut(A1) ; wait for it to go to zero <C907>
BNE.S DiskVBLExit ; exit if there is a powered-up disk
; we timed out, so turn off the power (turn out the lights)
MOVEQ #MtrOffAdr,D0
BSR AdrAndStrb ; turn it off both ways: PAL
@1 MOVEQ #1,D3 ; start with drive 1
@2 BSR.S Check4Disk ; check for disk-in-place
ADDQ #1, D3
CMP.W #maxDrvNum, D3 ; 2 drives max for MidMac <29Jul85>
BLE.S @2 ; <C37/3Jun86>
@3
MOVE.B #$86,wZeroes(A0) ;Kill the drive enable SWIM2 style <H2><SM6>
if NonSerializedIO then
nop ; force write to complete
endif
TST.B MtrOff(A0) ; cut IWM enable (new drive fix)
IF hasPwrControls THEN ; <SM5>
TestFor hwCbPwrMgr
BEQ.S @pmgrdone2
tst.l d3 ; see if any drives ejecting? <1.6>
bmi.s DiskVBLExit ; if so, don't turn off drive power <1.6>
MOVE (SP), SR ; Re-enable interrupts <v2.3>
BSR TurnIWMoff ; IWM not needed now <C907>
@pmgrdone2
ENDIF ; <SM5>
DiskVBLExit MOVE (SP)+, SR
RTS
;
;Check up on drive #(D3); post DiskInPlace:0 events if a diskette is
;inserted, and post DiskInPlace:X events if the Eject switch is pressed.
;
Check4Disk
MOVE.W D3,Drive(A1)
BSR GetDrive ; set up A0,A1,D1
TST.B Installed(A1,D1) ; is there a drive attached?
BMI CkExit ; exit if not
TST.B DiskInPlace(A1,D1) ; if a diskette is in place, <C123/03sep86>
bgt.s CkEject ; go check for eject <C123/03sep86>
beq.s CkDIP ; else go check for one inserted <C123/03sep86>
IF hasPwrControls THEN ; <SM5>
TestFor hwCbPwrMgr
BEQ.S @pmgrdone
ADDQ.B #1,DiskInPlace(A1,D1) ; else if waiting for eject complete
bpl.s CkDIP ; when done, go check for a disk <1.6>
bset.l #31,d3 ; indicate drive is ejecting <1.6>
bra.s CkInval ; wait until eject timeout done <1.6>
@pmgrdone
ENDIF ; <SM5>
ADDQ.B #1,DiskInPlace(A1,D1) ; else if waiting for eject complete
bmi.s CkInval ; decrement until 0 <C123/03sep86>
bra.s CkDIP ; then go check for a disk <C123/03sep86>
;
;There is a disk in place; check to see if the eject switch was pushed, and
;if so, post a DiskInsertEvt:Eject event.
;
CkEject
bsr DiskSel1 ; select the drive, <C123/03sep86>
bsr.s CkEjSw ; go read the eject switch, <C123/03sep86>
bpl.s CkExit ; if not pressed do nothing <C123/03sep86>
MOVEQ #-1,D0 ; upper D0 = eject (-1) <C123/03sep86><C437>
move.w Drive(A1),D0 ; lower D0 = drive number <C123/04sep86>
move.w #DiskInsertEvt,A0 ; <C123/03sep86>
_PostEvent ; post the event <C123/03sep86>
bra.s CkExit ; any error is ignored <C123/03sep86>
;
;There is no disk in place; read the drive interface to see if one was inserted,
;and if so, post a DiskInsertEvt:DIP.
;
CkDIP bsr DiskSel1 ; select the disk, <C123/03sep86>
@1 moveq #DIPAdr,D0 ; for Sony drives, <C123/03sep86>
bsr AdrAndSense ; check DIP at the drive, <C123/03sep86>
bmi.s CkExit ; exit if none <C123/03sep86>
@2 bsr.s CkEjSw ; read, reset & ignore Eject Switch <C123/03sep86>
MOVEQ #DiskInsertEvt,D0 ; upper D0 = DIP (0) <C123/03sep86><C437>
MOVEA.L D0,A0 ; A0 = event type, <C123/03sep86><C437>
move.w Drive(A1),D0 ; lower D0 = drive number <C123/04sep86><C437>
_PostEvent ; post the event <C123/03sep86>
BNE.S CkInval ; br if not posted (probably boot time)
ADDQ.B #1,DiskInPlace(A1,D1) ; unclamped disk-in-place = 1
CkInval ST Track(A1,D1) ; mark current track invalid
MOVEA.L IWM,A0 ; restore IWM ptr
CkExit RTS
;
;See if the Eject Switch is pressed on the selected drive and
;reset the latched status bit. Returns BMI if switch pressed.
;
CkEjSw tst.b sides(a1,d1) ; just exit if 400K drive <1.2/26apr88>
BPL.S @DontEject ; <SM6>
MOVE.B mfmDrive(A1,D1),D0 ; is this drive a SuperDrive? <SM6>
NOT.B D0 ; BPL if so, BMI if not <SM6>
@DontEject ; any error is ignored <SM6>
bpl.s @1 ; because there's no eject switch <1.2/26apr88>
moveq #EjectLAdr,D0 ; eject latch address, <C123/04sep86>
bsr AdrAndSense ; go sample it, <C123/04sep86>
bpl.s @1 ; exit if no switch pressed, <C123/04sep86>
moveq #RdDta1Adr,D0 ; else reset the switch latch <C123/04sep86>
bsr AdrAndStrb ; by reading some damn thing <C123/04sep86>
MOVEQ #-1,D0 ; return BMI <C123/04sep86><C437>
@1 rts ; <C123/04sep86>