mac-rom/Drivers/Sony/SonyUtil.a
Elliot Nunn 4325cdcc78 Bring in CubeE sources
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included.

The Tools directory, containing mostly junk, is also excluded.
2017-12-26 09:52:23 +08:00

1012 lines
41 KiB
Plaintext

;
; 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 isnÕt 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>