; ; 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): ; ; 12/13/93 PN Roll in KAOs and Horror changes to support Malcom and AJ ; machines ; 12/14/92 RC Restore to Before PDM D2 Build with Horror Roll-in ; 12/7/92 rab Roll in Horror changes. Comments followÉ ;
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. ;
3/18/92 SWC Reversed branch polarity in chip existance check in DiskVBLTask. ;

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

10/18/91 CMP Overpatched SetIWMMode and CkDCDExist for SWIM2 support. ; Also, changed drive disable to not depend on MotorOn gating the ; enable lines. ; 12/02/92 HY Added hasPwrControls conditionals. ; 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 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É ; 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. ; 12/15/87 SWC Swapped usage of D2 & D5 in Seek because WakeUp was trashing D2 ; when seeking on 400K disks. ; 12/8/87 SWC Added a call to SetParams in Seek if an MFM disk is installed. ; 10/8/87 MSH Port to HcMac (Laguna). ; 5/27/87 CSL Fixed the performance problem of the upper internal drive. ; 12/12/86 TJ Ints off in WakeUp to prevent convoluted path from PrimeTime ; back into WakeUp/WakeSetUp. ; 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??) ; 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 ...) ; 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. ; 9/3/86 TJ Added Eject Button polling in VBL task. ; 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. ; 4/25/86 RDC Added changes for new 68020 Reno project (NuMac) - Changed ; setting of IWM mode ; 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 ; ;_______________________________________________________________________ ; ; 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 DC.W Drive2 ; one for each drive ; ;Return the stuff, but do not translate the drive number. ; GetRDrive move.l IWM,A0 ;set up hardware pointers move.l VIA,A2 ; bsr.s GetDrv2 ; move.w DrvVarOS-2(D1),D1 ;untranslated drive vars rts ; ; ; 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, move.w DrvVarOS-2(D1),D1 ;driver vars offset rts ; GetDrv2 move.l SonyVars,A1 ; move.w Drive(A1),D1 ;logical drive number, cmp.w #maxDrvNum,D1 ;if > max drive # BLS.S GetDrv3 ;bound to max (passThru test) MOVEQ #maxDrvNum,D1 ; GetDrv3 add.w D1,D1 ;make word ptr rts ; eject ; ;_______________________________________________________________________ ; ; 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? BMI mAdrDisk ;-> yes, set phases SWIM style 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 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? BMI mSense ;-> yes, read sense SWIM style 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? BMI mPulse ;-> yes, pulse LSTRB SWIM style 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 ; ;_______________________________________________________________________ ; ; 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 MOVE.W D6,D5 ;Calculate the number of steps to take SUB.W D7,D5 ;Already there? BEQ.S SeekEnd1 ;-> yes, don't wait head settle time BGT.S @1 ; MOVEQ #DirHAdr,D0 ;We're stepping out NEG.W D5 ; so make the step count positive @1 BSR AdrAndStrb ;Set the stepper direction MOVEQ #cantStepErr,D7 ;Assume one of the steps will fail SUBQ.W #1,D5 ;Adjust count for DBRA SeekLp1 MOVEQ #StepLAdr,D0 ;Make sure /STEP starts out high BSR AdrAndSense ; BPL.S SeekEnd ;-> it wasn't, so exit with error BSR Pulse ;Then set it low BSR.S Wait100 ; and wait a while for it to go high DBRA D5,SeekLp1 ; MOVE.W D6,D7 ;Successful seek so update curr track SeekEnd BSR GetDrv1 MOVE.W D7,Track(A1,D1) ; update current track TST.B mfmMode(A1) ;Are we in MFM mode? <1.1/28mar88> BPL.S @00 ; BSR SetParams ;Yes, setup RAM parms for this disk zone BEQ.S @00 ; MOVE.W D0,D7 ;Error, so save the result code @00 ; MOVE.W HeadSettle(A1),D0 ; wait head settle time or until ready (new drive) MOVEQ #5,D2 ; wait 500usec first time BSR.S WaitReady ; IF isUniversal THEN ; TestFor hwCbPwrMgr ; is this a powerbook? BEQ.W SeekEnd1 ; -> no, skip around artificial delay MOVE.W #500,D0 ; need to wait 50 msec for drive to settle BSR.W Wakeup ; just detecting /READY isn't enough ENDIF ; SeekEnd1 MOVE.W Wait(A1),D0 ; wait any speed change, power-on time MOVEQ #0,D2 ; wait 0 time, first time BSR.S WaitReady ; 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 @1 MOVEQ #StepLAdr,D0 BSR AdrAndSense DBMI D2, @1 ; ; 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) ADDQ #4, SP ; discard local return address TST.W D0 ; any time to wait? BNE.S WakeUp ; br if so @1 RTS ; 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 ; ;_______________________________________________________________________ ; ; 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 MOVE.L (SP)+,DskRtnAdr ; save return address next BSR.S WakeSetUp ; configure timer for D0 wait <25Oct85> bra.s WakeRet ; go execute it. WakeGo MOVEM.L D3-D7/A3-A6,SaveRegs(A1); save caller's regs first 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> 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 ; ;_______________________________________________________________________ ; ; 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 <24Oct85> BSR SetChipMode ;Initialize appropriate register set bne.s RecalExit ; couldn't set IWM Mode BSR RWPowerUp ;Re-enable the interface MOVEQ #80,D7 ; maximum number of steps needed MOVEQ #DirHAdr,D0 ;Set direction out (toward track 0) BSR AdrAndStrb ; 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 ; ;_______________________________________________________________________ ; ; 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. ;_______________________________________________________________________ SetIWMMode TST.B Q6H(A0) ; set IWM to sense mode MOVEQ #$1F,D0 ;(mask for mode bits) AND.B Q7L(A0),D0 ; sense the mode register TST.B Q6L(A0) ; and back to read mode CMP.B #IWMMode,D0 ; see if correct mode is set BEQ.S @2 ; br if so 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 ... 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) AND.B Q7L(A0),D0 ; sense the mode register BCLR #5,D0 ; interface should be disabled BNE.S @1 ; keep waiting cmp.b #IWMMode,D0 ; see if low bits match BEQ.S @2 ; if so, we are done MOVE.B #IWMMode,Q7H(A0) ; set to sony mode 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 ... @3 rts ; eject ; ;_______________________________________________________________________ ; ; 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

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? BPL.S @1 ;-> no, don't have to set drive mode MOVEQ #GCRModeAdr,D0 ;find out which way the drive is set BSR AdrAndSense ; MOVE.B D0,-(SP) ; and save the state (bit7=1: MFM) MOVEQ #GCRModeAdr,D0 ;Assume we're in GCR mode MOVE.B mfmDisk(A1,D1),D5 ;Are we? BPL.S @0 ; MOVEQ #MFMModeAdr,D0 ;No, select MFM drive mode @0 BSR AdrAndStrb ;set the drive mode as desired MOVE.B (SP)+,D0 ;get the previous drive mode EOR.B D0,D5 ;bit 7=1 if the mode has changed @1 ; MOVEQ #MtrOnAdr,D0 BSR AdrAndSense ; is it already powered up? OR.B D5,D0 ;or we just did a mode change? BPL.S @2 ; br if so 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) BSR waitReady ; MOVE.L D4,-(SP) ;(restore stack level--rtn addr) CMP.B #ARdCmd,Command+1(A1) ; is it a read? BEQ.S @2 ;-> yes, all done MOVE.W #600*10,D0 ;for writes, we need to wait about BRA WakeUp ; 600ms after /READY for speed ±1.5% @2 RTS ; return eject ; ;_______________________________________________________________________ ; ; 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? BMI mDiskSelect ;-> yes, do the MFM version 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 ; ;_______________________________________________________________________ ; ; 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 ; ;_______________________________________________________________________ ; ; 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 ; ;_______________________________________________________________________ ; ; 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 ; TestFor hwCbPwrMgr BEQ.S @pmgrdone BSR TurnIWMon ; IWM needed now @pmgrdone ENDIF ; MOVE.B isSWIM(A1),D0 ; see if the IWM/SWIM/... is installed SUBQ.B #1,D0 ; BNE.S @Done ; -> yes, just return CLR.W TimeOut(A1) ; clear any pending timeouts CLR.W LastDrive(A1) ; and show no last drive @Done ; BEQ.S DiskVBLExit ; -> no IWM/SWIM/... chip installed
ORI #HiIntMask,SR ; no VBL & AppleTalk (fileserver) <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 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 ; @3 MOVE.B #$86,wZeroes(A0) ;Kill the drive enable SWIM2 style

if NonSerializedIO then nop ; force write to complete endif TST.B MtrOff(A0) ; cut IWM enable (new drive fix) IF hasPwrControls THEN ; 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 BSR TurnIWMoff ; IWM not needed now @pmgrdone2 ENDIF ; 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, bgt.s CkEject ; go check for eject beq.s CkDIP ; else go check for one inserted IF hasPwrControls THEN ; 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 ; ADDQ.B #1,DiskInPlace(A1,D1) ; else if waiting for eject complete bmi.s CkInval ; decrement until 0 bra.s CkDIP ; then go check for a disk ; ;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, bsr.s CkEjSw ; go read the eject switch, bpl.s CkExit ; if not pressed do nothing MOVEQ #-1,D0 ; upper D0 = eject (-1) move.w Drive(A1),D0 ; lower D0 = drive number move.w #DiskInsertEvt,A0 ; _PostEvent ; post the event bra.s CkExit ; any error is ignored ; ;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, @1 moveq #DIPAdr,D0 ; for Sony drives, bsr AdrAndSense ; check DIP at the drive, bmi.s CkExit ; exit if none @2 bsr.s CkEjSw ; read, reset & ignore Eject Switch MOVEQ #DiskInsertEvt,D0 ; upper D0 = DIP (0) MOVEA.L D0,A0 ; A0 = event type, move.w Drive(A1),D0 ; lower D0 = drive number _PostEvent ; post the event 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 ; MOVE.B mfmDrive(A1,D1),D0 ; is this drive a SuperDrive? NOT.B D0 ; BPL if so, BMI if not @DontEject ; any error is ignored bpl.s @1 ; because there's no eject switch <1.2/26apr88> moveq #EjectLAdr,D0 ; eject latch address, bsr AdrAndSense ; go sample it, bpl.s @1 ; exit if no switch pressed, moveq #RdDta1Adr,D0 ; else reset the switch latch bsr AdrAndStrb ; by reading some damn thing MOVEQ #-1,D0 ; return BMI @1 rts ;