; ; File: Sony.a ; ; Contains: Sony Floppy Driver ; ; Written by: Larry Kenyon ; ; Copyright: © 1985-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 ; 5/19/93 GMR Removed call to InitICON, since we now use Universal tables for ; this info. ; 1/10/93 RC added more nops for SMurf ; 01/09/93 HY Added RawTrackDump entry in CtlTbl for SWIM2 machines. ; 12/14/92 RC Restore Pre-PDM D2 with Horror Roll in ; 12/7/92 rab Roll in Horror changes. Comments followΙ ; 7/13/92 SWC Fixed a bug in the sleep task which prevented us from going to ; sleep if we time out waiting for SWIM power to go off. ; 7/2/92 SWC Cleared ChipState in wakeup code to force SWIM power on since ; it's possible that power could still have been on before going ; to sleep. ; 6/26/92 SWC Fixed a bug that was trashing a register in the wakeup code. ; Sleep/wakeup code now sets/clears ΤactiveΥ to prevent VBLs from ; running before everything is re-initialized on wakeup. ; 3/18/92 SWC Changed the chip test patches to use isSWIM>0 to flag that no ; chip is currently connected instead of diddling with the chip ; all the time. TestForChip will now only be called in Open and in ; the sleep task when we wake up. The sleep task will now also run ; the ChkConnect code in Open to initialize the drive info if ; nothing was connected at startup but was added during sleep. ; 2/25/92 CMP Added code for speed check status call. ; 2/13/92 CMP Put in code for CtlRetries control call. Also, code to ; initialize and check for retry disable flag. ; 3/18/92 SWC Added a label and some extra checking so we can reuse the ; ChkConnect code when coming out of sleep. Marked some lines in ; the cache installation code for removal in the next ; non-overpatch ROM (and NOP'd some branches) since they're either ; way out of date (check for a 128K Mac?), or cuz they allocate ; too small a cache if there are no drives connected at startup ; (which is possible on DBLite, at least). ; 1/9/92 CMP Changed TestForChip so that ROMBASE is read to clear bus lines ; instead of writing to rPhase register of SWIM2. ;
12/18/91 SWC Changed the check in TestForChip so that it looks for IWM or ; SWIM/SWIM2 registers in addition to doing a bus error check cuz ; the final MSC doesn't bus error if the chip isn't there. ;

11/14/91 SWC Moved code that had been added to other files but not ; overpatched. Shortened SWIM2 patches where possible. Removed ; SetIWMMode patch since SetIWMMode won't be called on a SWIM2. ; Added a SWIM chip bus error handler to check if the chip is ; currently installed for DB-Lite. Converted the SCC polling code ; to a macro so it's easier to overpatch. Added patch to mAdrDisk ; to use the SWIM/SWIM2 HDSEL pin for head selection in addition ; to the VIA bit. Added DB-Lite's drive icon. ;

10/18/91 CMP Added support for SWIM2. ; 12/02/92 HY Added IF hasPwrControls around pwmgr specific code. ; 10/18/92 CCH Added nop's for systems with non-serial writes to IO space. ; <9> 7/14/92 CSS Fixed the comment below so an exact version of this ; file could be copied into SuperMario. ; <8> 4/27/92 JSM Get rid of conditionals: supportsPWM, supportsDCD, and ; has3rdFloppy are always false, forROM, supportsMFM, forDiskDup, ; 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. ; <7> 12/26/91 RB Updated to use the new Power Mgr records ; <6> 9/25/90 GMR Changed the eject track to 40 (was 79) because Peripherals wants ; it there (questions? Call Damon Rando). ; <5> 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. ; <4> 2/2/90 GMR Changed the time-out in Eject from 1.5 seconds to 3 seconds to ; support the low-cost 800k drives and hopefully low cost ; SuperDrives. ; <3> 1/16/90 MSH Roll in Portable changes from Fiction. ; <2> 1/15/90 MSH Preparing comment header for conversion. ; <2.4> 5/23/89 GGD Moved driver header and version equates to SonyHdr.a Converted ; to use new interface to InitIcon routine. Fixed branch bug in ; HcMac Sleep/Wakeup code from code review. ; <2.3> 4/29/89 GGD Fixed Open code to pass Physical drive number _AddDrive on 2 ; drive systems to avoid problems when drive 1 is not connected ; but drive 2 is. ; <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 SWC added DupVerSts for Disk Duplicator version of the driver. ; GGD Removed temporary delay loop in wakeup code for HcMac, since ; hardware fix is now implemented. Changed bit numbering of bits ; in chipState, now same as pmgr enables bits. Added new routine ; UpdateChipState, to read the power/clock enable bits. Fixed bug ; in GetFormatList status call when assembled for NOT SupportsMFM ; it would return just one entry (400K) when called for an 800K ; drive. ; <2.0> 12/15/88 GGD Changed some machine based conditionals to feature based. ; <1.2> 11/21/88 CCH Changed ForRam equates to ForRom. ; <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 Added entries in the control/status dispatch tables for disk ; duplicator. Made driveXLAT references conditional for everyone ; but onMac. Changed reference of sQType to slpQType, since its ; name changed. ; <1.8> 8/19/88 SWC Added entries in the control/status dispatch tables for disk ; duplicator. Made driveXLAT references conditional for everyone ; but onMac. ; <1.7> 8/16/88 GGD Added Sleep Queue Handler and installation for HcMac. Fixed bug ; in turning on IWM in Open on HcMac. ; <1.6> 7/15/88 GGD No changes to this file, entire Sony Driver is checked out and ; in as a group. ; <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/23/88 GGD No changes, entire sony driver checked out and in as a group. ; <1.2> 5/3/88 GGD Changed jump vector initialization for jSetSpeed to point to an ; RTS when PWM is not supported. SWC/Check for SuperDrives all the ; time since they look like they have an old interface which slows ; things down. Made cache size bigger ONLY if at least 1 ; SuperDrive is connected. ; <1.2> 4/26/88 GGD Changed jSetSpeed to point to DiskRTS if PWM not supported. ; <1.2> 4/26/88 SWC Made cache size bigger ONLY if at least 1 SuperDrive is ; connected. ; <1.1> 4/18/88 GGD Merged in MFM support by Steve Christensen call InitIcon ; for new 'patcheable' disk icons Change Passport ; status to check TwoMegFmt before mfmDisk for GCRonMFM Fixed bug ; with eject being ignored during boot. Added vector ; initialization for MFM I/O routines. ; <1.1> 3/9/88 GGD Added vector initialization for MFM I/O routines. ; <1.1> 3/9/88 GGD Fixed above fix, to really avoid clicking again. ; <1.1> 3/7/88 GGD Fixed eject/DIP check, to really check at the drive, to fix ; mousekey eject. ; <1.1> 2/29/88 GGD Change version to 2 when supportsMFM ; 2/26/88 SWC Fixed DIP and error code bugs in status call 6. ; <1.0> 2/12/88 BBM Adding file for the first time into EASEΙ ; 2/4/88 SWC Fixed a bug in MFMStatus: forgot A0 was already offset to ; csParam. ; 10/26/87 SWC Added a check in PassportSts to make sure the disk is clamped so ; that the info that's returned is valid. ; 10/16/87 MSH Used the same name for two different things. Not good. ; 10/14/87 SWC Added a seek to track 79 when ejecting to make sure the head is ; off of all important parts of the disk. ; 10/8/87 MSH Port to HcMac (Laguna). ; 10/7/87 SWC Changed disk format status to return disk size in BLOCKS not ; BYTES. ; 9/18/87 SWC DiskStatus: changed order of error checking to bad csCode first. ; 5/1/87 SWC Added a control call to set the format mode for MFM or GCR. ; Added a status call to return extended status (including MFM ; info). Added new status call to return list of possible disk ; formats. Now dispatch status calls the same way as control ; calls. ; 2/22/87 SWC Ignore the eject call if no disk is in the drive (avoids ; clicking). ; 11/24/86 SWC Check to see if we're using a SWIM and/or SuperDrives, and ; initialize isSWIM(A1) and mfmDrive(A1,D1). ; 11/5/86 TJ Removed Grow Zone stuff. Cleaned up comments, added eject ; statements. ; 10/17/86 TJ Correct comment only in Control calls #21, #22. ; 8/21/86 TJ Cleaned up ctlDispatch code and added Icon and Info control ; calls. Removed reference to TFSDEBUG; seemed like old debug junk ; anyways. Not defined in new equate system. ; 8/13/86 TJ Made conditional some references to DCD, etc that dont apply to ; nuMac. Fixed some bugs in xlat table creation. ; 8/1/86 TJ Removed hardcoded drive number stuff from Open call, when ; determining Sony/DCD; changed to use firstDCD, etc. Added drive ; number translate table build at Open time. ; 6/3/86 CSL Support 2nd internal floppy drive for Aladdin. ; 5/5/86 RDC Changed old onMidMac conditional to onNuMac ; 4/25/86 RDC Changed forMac conditional equate to onMac ; 10/29/85 LAK Fixed bug in control exit. ; 10/27/85 LAK Added routine DispSetUp to fix bug. ; 10/25/85 LAK CkDrvNum saves old Drive value in LastDrive. Ignore KillIO (DCD ; has no way to notify, new Time manager needs call to abort any ; current request - if we can't do it right, don't do it at all). ; Init NewIntf drive var. Use NewIntf rather than Sides to ; determine whether drive has new interface. Assert /enb for >150 ; usec after /cstin goes away for new drive. ; 10/24/85 LAK Changed version number back to 1 because old format packages ; assume version 4 drivers have their correct size in drive queue ; entry. Invalidate any track cache data on ejects. ; 9/6/85 LAK Only write DskErr if there WAS an error. ; 7/31/85 RDC Modified control dispatch table and routine to remove DCD ; dependencies for MidMac ; 7/29/85 RDC Changed interrupt level settings to use equates Eliminated DCD ; code for MidMac ; 7/24/85 LAK Converted back from MDS to the WorkSlop. Old Mod history moved ; to SonyHdr file. SonyRAM now cuts back the driver after install. ;_______________________________________________________________________ ; offset table for jump table initialization DiskClose MOVEQ #ClosErr,D0 ; report error: not closable at present RTS InitDskTbl DC.W jtFigTrkSpd-InitDskTbl DC.W jtDiskPrime-InitDskTbl DC.W jtRdAddr-InitDskTbl DC.W jtRdData-InitDskTbl DC.W jtWrData-InitDskTbl DC.W jtSeek-InitDskTbl DC.W jtSetUpPoll-InitDskTbl DC.W jtRecal-InitDskTbl DC.W jtControl-InitDskTbl DC.W jtWakeUp-InitDskTbl DC.W jtReSeek-InitDskTbl DC.W jtMakeSpdTbl-InitDskTbl DC.W AdrDisk-InitDskTbl ; provide access to these routines dc.w DiskRTS-InitDskTbl ; SetSpeed does nothing if no PWM <1.2/26apr88> DC.W Nibl-InitDskTbl ; programs (not patchable) InitDsk2 DC.W jtDiskSel-InitDskTbl ; interface select routine <25Oct85> DC.W jtMRdAddr-InitDskTbl ; Read MFM address routine <1.1/09mar88> DC.W jtMRdData-InitDskTbl ; Read MFM data routine <1.1/09mar88> DC.W jtMWrData-InitDskTbl ; Write MFM data routine <1.1/09mar88> InitParams DC.B 8,0 ; max 8 soft errs per recal/track DC.B 2,0 ; max 2 recals per track DC.B 64,0 ; max 64 wrong sectors per sector DC.B 8,0 ; max 8 wrong speeds per track DC.W 0 ; I/O command 0 DC.W KHdSetTime ; deflt head settle time = 30 ms DC.W KSpdChgTime ; deflt speed chg wait time = 150 ms DC.W KPowerOn ; deflt pwr-on = .4 sec DC.W KRWPOff ; deflt pwr-off = 2-2.5 sec DC.W KSeekTime ; deflt seek wait time = 12 ms DC.W KSectTime ; deflt sector time = 10 ms DC.W KDskVBLTime ; deflt disk VBL time = .5 sec DC.W KEjectTime ; deflt eject time = .75 seconds DC.L KCkDelta ; deflt speed check time = 4 min DC.B KEjectWait,0 ; deflt dip ck wait after eject = 1.5 sec InitBCnt EQU *-InitParams ; 16 words to init (32 bytes) DispSetUp MOVEQ #0,D2 ; clear high part for arithmetic <27Oct85> MOVE.W (A0)+,D2 ; get the next offset ADD.L D0,D2 ; compute the address MOVE.L D2,(A1)+ ; install it in the jump table DBRA D1,DispSetUp ; loop for vectors <27Oct85> RTS ; <27Oct85> eject ; ; Disk Driver Initialization routine DiskOpen MOVE.L #DiskVarLth,D0 ; get memory for driver variables _NewPtr ,SYS,CLEAR MOVE.L A0,SonyVars ; and keep pointer in low memory MOVE.L A1,(A0) ; DCE pointer MOVE.B #Version,DCtlQueue+1(A1) ; put our version number in ST Active(A0) ; mark driver active for VBL exclusion CLR.B DisableRetries(A0) ; make sure we do retries IF hasPwrControls THEN ; TestFor hwCbPwrMgr BEQ.S @pmgrdone MOVEA.L A0,A1 ; A1 := pointer to SonyVars <1.7> BSR TurnIWMon ; Turn IWM on with pmgr call <1.7> @pmgrdone ENDIF ; move.l UnivInfoPtr,a2 ; adda.l ProductInfo.IconInfoPtr(a2),a2 ; point to icon info table for this machine move.l a2,DrvTblPtr(a0) ; save in our locals <2.4> MOVE.L A0,A2 ; save locals ptr for later ; initialize the disk routine jump table LEA InitDskTbl,A0 ; point to the offset table LEA JFigTrkSpd,A1 ; point to 1st jump table entry MOVEQ #14,D1 ; there are 15 vectors MOVE.L A0,D0 ; remember its address BSR.S DispSetUp ; do these <27Oct85> LEA JDiskSel,A1 ; point to 1st jump tbl entry, 2nd JT <25Oct85> MOVEQ #0,D1 ; 1 vector here <25Oct85> BSR.S DispSetUp ; do these <27Oct85> MOVEQ #3-1,D1 ; 3 vectors here <1.1/09mar88> LEA jMRdAddr,A1 ; point to 1st jump tbl entry, 2nd JT<1.1/09mar88> BSR.S DispSetUp ; install the MFM vectors <1.1/09mar88> ST OneToOne(A2) ; go 1 to 1 for now . . . ??? LEA ReadErrInit(A2),A1 ; destination LEA InitParams,A0 ; source MOVEQ #InitBCnt,D0 _BlockMove ; allocate a VBL task to handle disk power-down and disk-in-place sensing ; (note that VBL phase was cleared by disk variable initialization) LEA DiskQVE(A2),A0 ; get address of VBL ctl blk MOVE.W #VType,QType(A0) ; init queuing fields LEA DiskVBLTask,A1 ; get addr of powerdown task MOVE.L A1,VBLAddr(A0) ; set up address MOVE.W #KDskVBLTime,VBLCount(A0) ; it gets called every 1/2 second _VInstall ; install the disk task ; install the time manager queue element for use later by the wakeup routines. LEA TimeQEl(A2),A0 ; point at the time Q Element _InsTime ; make the time manager aware of us IF hasPwrControls THEN ; TestFor hwCbPwrMgr BEQ.S @pmgrdone2 WITH SleepqRec ; <7> rb LEA DiskSleepQEL(A2),A0 ; get address of sleep queue element<1.7> CLR.W SleepqFlags(A0) ; fill in Flags <1.7> MOVE.W #slpQType,SleepqType(A0) ; fill in qType field <1.7><1.8> LEA HandleSleep,A1 ; get handler routine address <1.7> MOVE.L A1,SleepqProc(A0) ; setup handler address <1.7> _SlpQInstall ; Add to sleep queue <1.7><2.3> @pmgrdone2 ENDWITH ; <7> rb ENDIF ; BSR TestForChip ; see if the IWM/SWIM/... is installed

BEQ.S @Continue ; -> it is, so continue

MOVEA.L SonyVars,A1 ; point to driver variables

MOVE.B #1,isSWIM(A1) ; mark that no disk controller is connected CLR.B Active(A1) ; no longer active IF hasPwrControls THEN ; TestFor hwCbPwrMgr ; BEQ.S @pmgrdone3 ; BSR TurnIWMoff ; Turn IWM off with pmgr call @pmgrdone3 ; ENDIF ; MOVEQ #0,D0 ; return noErr to the Device Manager

bra.w DiskRTS ; @Continue ;

; Check that pass-thru is working on the external connect - if a DCD is ; connected which doesn't implement pass-thru, it will look like there ; are an infinite number of hard disks connected (we assume 7=infinite). ; ; Pass thru logic is still used if only a single floppy is connected ; externally (simplifies the logic and shouldn't matter). BSR Check4SWIM ;Is a SWIM installed? ; Now see what drives are connected - install drive queue entries for them. We ; build the drive number translate table now also; we previously set it up ; 1:1 to start. Existing drives end up and the low end of the Sony drive ; number sequence (1 to firstDCD) with non-existent ones near the end; this ; accomodates (hopefully) copy protection schemes that assume drive #2 is ; the "second" disk, where in macPP this may not be true. MOVEQ #1, D2 ; start with drive 1 move.l D2,D5 ; first drive # to translate ChkConnect MOVE.W D2, Drive(A1) BSR GetDrive ; set up A0, A1, A2, D1 TST.B Installed(A1,D1) ; has this drive already been installed? BGT.S @5 ; -> yes, leave it alone ST Installed(A1,D1) ; start by marking it 'not installed' @1 BSR DiskSelect ; select the interface @2 MOVEQ #DrvExstAdr, D0 ; check floppy-exist sense bit BSR AdrAndSense ; connected? BMI.S @5 ; exit if not MOVEQ #SidesAdr, D0 ; see how many sides it has BSR AdrAndSense ; SMI Sides(A1,D1) ; $FF=two-sided MOVEQ #NewIntfAdr, D0 ; see if it implements the new intf <25Oct85> BSR AdrAndSense ; <25Oct85> SMI NewIntf(A1,D1) ; $FF=new interface <25Oct85> MOVEQ #mfmDrvAdr,D0 ;See if the drive's a SuperDrive BSR AdrAndSense ; BPL.S @3 ; ST NewIntf(A1,D1) ;SuperDrives have the new interface TST.B isSWIM(A1) ;Is a SWIM installed? BPL.S @3 ;-> no ST mfmDrive(A1,D1) ;$FF=SuperDrive, $00=400K or 800K ST hasSuperDrives(A1) ;$FF=at least 1 SuperDrive connected<1.2/26apr88> @3 MOVEQ #SonyRfN,D3 ; use regular refnum for floppies @4 MOVE.W D2,D0 ; Physical drive num in the queue <2.3> MOVE.B #1,Installed(A1,D1) ; mark 'installed' in Drive vars SWAP D0 MOVE.W D3, D0 ; driver refnum (-5 for Sony, -2 for DCD) LEA DQEL(A1,D1), A0 ; drive queue element for this drive _AddDrive ; D0=[drive num][driver refnum] ; returns D0=0 addq #1,D5 ; next logical drive ... @5 ADDQ.W #1, D2 ; check the next physical drive CMP.W #maxDrvNum,D2 BLE.S ChkConnect CLR.B Active(A1) ; no longer active IF hasPwrControls THEN ; TestFor hwCbPwrMgr BEQ.S @pmgrdone BSR TurnIWMoff ; Turn IWM off with pmgr call @pmgrdone ENDIF ; MOVEQ #0, D0 ; we're cool DiskRTS RTS eject ; ;_______________________________________________________________________ ; ; DiskDone ; ; D0: return code ; ; DiskDone is used to indicate IO completion to the device ;manager, by dispatching through jIODone. The driver active flag ;is cleared, and the error code in D0 is stored for debugging. ; ;_______________________________________________________________________ DiskCtlErr MOVEQ #ControlErr,D0 DiskDone TST.W D0 ; error? <06Sep85> BEQ.S @1 ; br if not <06Sep85> MOVE.W D0,DskErr ; save last error for debugging @1 MOVE.L SonyVars,A1 ; get pointer to locals CLR.B Active(A1) ; clear driver active indication MOVE.L DiskUnitPtr(A1),A1 ; and pointer to disk DCE MOVE.L JIODone,-(SP) ; use IODone vector RTS ; ;_______________________________________________________________________ ; ; Routine: DiskControl ; Arguments: ; A0 (input) -- pointer to control call parameter block: ; CSCode(A0) = ; 1 for KillIO ; 5 for Verify ; 6 for Format ; 7 for Eject ; 8 for setting tag buffer ; 9 for track cache install/remove/enable/disable ; ; ; Opcode 1 KillIO (not supported, returns -1) ; Opcode 5 Verify the drive specified by ioRefNum ; Opcode 6 Format drive (ioRefNum). CSParam = 0, except ; CSParam = 1 for 400K disks. ; Opcode 7 Eject the diskette currently in the specified drive. ; IODone is jumped to when the eject has been completed. ; The drive is immediately powered down. ; (26) = [$0007] ; Opcode 8 Set the buffer to store file tags. ; (26) = pointer to tag buffer or 0 to stop saving tags. ; Opcode 9 Cache control is used to control the track cache. ; (26) = [$0009] ; (28) = non-zero to enable, zero to disable ; (29)= $00 for neither, $01 to install, $FF to remove ; Opcode 21 Returns a pointer to an icon for the PHYSICAL drive. ; Opcode 22 Returns a pointer to an icon for the MEDIA. ; Opcode 23 Drive info control; returns a 32 bit int describing the ; drive. See SonyIcon.a. ; To Do: ; - report errors for immediate calls other than KillIO?? ;_______________________________________________________________________ ; ;The dispatch table contains WORD offsets from the table itself to the ;various routines; this allows 16 bit offsets instead of 32 bit addresses. ; CtlTbl ; (Code) (offset) dc.w KillCode, ctlKillIO-CtlTbl ; DC.W VerifyCC, ctlSonyVer-CtlTbl ; DC.W FormatCC, ctlSonyFmt-CtlTbl ; DC.W EjectCode, CtlSonyEjc-CtlTbl ; dc.w TagBufCC, ctlTagBuf-CtlTbl ; dc.w TCacheCC, ctlTrkCache-CtlTbl ; DC.W IconCC, ctlPhysIcon-CtlTbl ; DC.W IconLogCC, ctlLogIcon-CtlTbl ; dc.w infoCC, ctlDrvInfo-CtlTbl ; DC.W FmtCopyCC, CtlFmtCopy-CtlTbl ; <1.8> DC.W GetRawDataCC,CtlRawTrackDump-CtlTbl ; DC.W RetriesCC, CtlRetries-CtlTbl ;
TBLLEN equ 4 ; bytes per table entry ; dc.w 0 ; ; ;Dispatch off the Control Opcode. A0 points to the ParamBlk from the caller. ;We precheck the drive number passed; D0 contains an error code if the ;drive does not exist. Some calls do not need a drive number passed, and can ;ignore the error. ; ; A0 ParamBlk from the caller ; A1 SonyVars ; D1 Drive locals offset ; D0 Error code if no such drive else 0 ; DiskControl MOVE.L JControl,-(SP) RTS jtControl bsr CkDrvNum ;check drive # validity, bne.s @1 ;D0= error if not valid tst.b Installed(A1,D1) ;check if drive actually installed bpl.s @1 ;D0= 0 if Installed moveq #NoDriveErr,D0 ;else D0= error @1 lea CtlTbl,A3 ;dispatch table base address, move.l A3,A4 ;save a copy for later, @2 move.w (A3)+,D2 ;sample the table, beq.s @5 ; error exit if end of table, cmp.w CSCode(A0),D2 ; bne.s @4 ;if the right opcode @3 add.w (A3),A4 ;add table base + routine offset tst.w D0 ;pretest drive installed indicator jmp (A4) ;go there @4 ADDQ.W #TBLLEN-2,A3 ;next table entry ... bra.s @2 ; @5 moveq #ControlErr,D0 ;none of the above?? bra DiskDone ; ; ; - - - - - - - - - - - - - - - - - - - ; ;Handle all KillIo calls. Who cares whether the drive exists or not. ; ctlKillIO MOVEQ #-1,D0 ; we don't support KillIO bra DiskDone ; ; ; - - - - - - - - - - - - - - - - - - - ; ;Format a Sony; check drive existence first. ; ctlSonyFmt bne.s DiskDone ;if no drive, exit now bra ctlFormat ;else go format ; ; - - - - - - - - - - - - - - - - - - - ; ;Verify a Sony; check drive existence first. ; ctlSonyVer bne.s DiskDone ;if no drive, exit now bra ctlVerify ;else go verify ; ; - - - - - - - - - - - - - - - - - - - ; ;Set a new tag buffer (CSParam != 0) else revert to the one in the driver. ;No drive number not specified. ; ctlTagBuf MOVE.L CSParam(A0),TagBufPtr(A1) ; set or clear ptr to separate buffer moveq #noErr,D0 ;always no error bra DiskDone ; ; ; - - - - - - - - - - - - - - - - - - - ; ;Control Track Cache. Drive number not specified. ; ctlTrkCache ADD #CSParam,A0 ; <25Oct85> MOVE.B (A0)+,D1 ; get enable flag <25Oct85> MOVE.B (A0)+,D0 ; get install flag <25Oct85> BEQ.S ctlTCEnb ; br if neither install/remove <25Oct85> BPL.S ctlTCInst ; br for install <25Oct85> BSR.S TCdispose ; get rid of any buffer <25Oct85> BRA.S ctlTCEnb ; disable the cache <25Oct85> ctlTCInst TST.L TCBuffer(A1) ; already installed? <25Oct85> BNE.S ctlTCEnb ; br if so <25Oct85> MOVE.L #524*MaxMFMSectors,D0 ; allocate a track buffer _NewPtr ,SYS,CLEAR ; <25Oct85> BNE.S ctlTCEnb ; br if we couldn't get it <25Oct85> MOVE.L A0,TCBuffer(A1) ; <25Oct85> CLR.W TCDrive(A1) ; inval drive number to start <25Oct85> ctlTCEnb TST.L TCBuffer(A1) ; any buffer? <25Oct85> SNE TCInstalled(A1) ; always disable if not <25Oct85> BEQ.S @1 ; br if no buffer <25Oct85> TST.B D1 ; enable/disable? <25Oct85> SNE TCInstalled(A1) ; turn it on or off <25Oct85> @1 moveq #noErr,D0 ;always return OK bra DiskDone ; TCdispose CLR.L -(SP) ; assume no space freed MOVE.L TCBuffer(A1),D0 ; get buffer ptr BEQ.S @1 ; br if none MOVE.L D0,A0 ; _GetPtrSize ; MOVE.L D0,(SP) ; size we free _DisposPtr ; get rid of it CLR.L TCBuffer(A1) ; no more buffer CLR.B TCInstalled(A1) ; no more installed @1 MOVE.L (SP)+,D0 ; space freed RTS ; ; ; - - - - - - - - - - - - - - - - - - - - ;Eject a Sony disk. Error if the drive does not exist. ; ctlSonyEjc bne.s DiskDone ; exit if no drive IF hasPwrControls THEN ; TestFor hwCbPwrMgr BEQ.S @pmgrdone BSR TurnIWMon ; Turn IWM on with pmgr call @pmgrdone ENDIF ; TST.B DiskInPlace(A1,D1) ; Has a disk been seen in drive? <1.1/07mar88> BLE.S @02 ;-> no, skip seek <1.1/07mar88> BSR RWPowerUp ;Make sure the drive's powered up MOVEQ #40,D6 ;Seek to track 40 to get away from MDB's, etc. <6> BSR Seek ;Peripherals wanted 79 before but now changed their minds! BGT.S @02 ;(seek was successful) BEQ.S @01 ;(recal'd) BSR Recal ;Seek failed: recal first BMI.S @02 ; @01 MOVEQ #40,D6 ;Try seeking again <6> BSR Seek ; @02 BSR InvalTrkCache ; invalidate track cache buffer <24Oct85> MOVEQ #0,D0 ; immediate power off BSR PowerDown ; make sure power is off BSR DiskSelect ; but leave interface enabled MOVEQ #DIPAdr,D0 ; See if disk is in drive <1.1/07mar88> BSR AdrAndSense ; check DIP at the drive, <1.1/07mar88> BPL.S @03 ; eject it if there is a diskette <1.1/09mar88> MOVEQ #0,D0 ; immediate power off <1.1/09mar88> BSR PowerDown ; if no disk, turn off power now <1.1/09mar88> BRA.S CtlEjtOK ; exit (silently) if none <1.1/09mar88> @03 ; <1.1/09mar88> MOVE #2000, D0 ; and wait 200 msec BSR WakeUp MOVEQ #EjectHAdr, D0 ; addr eject BSR AdrDisk ; TST.B mfmMode(A1) ;Are we in MFM mode? BPL.S @00 ; MOVE.B #$FF,wPhase(A0) ;Yes, set LSTRB high the SWIM way if NonSerializedIO then nop ; force write to complete endif BRA.S @1 ; @00 ; TST.B Ph3H(A0) ; set LSTRB high @1 TST.B NewIntf(A1,D1) ; set LSTRB low if new drive BMI.S NewDrvEject ; ;Eject old style drive. ; MOVE.W EjectTime(A1), D0 ; wait >.75 sec BSR WakeUp ; TST.B mfmMode(A1) ;Are we in MFM mode? BPL.S @10 ; MOVE.B #$F7,wPhase(A0) ;Yes, set LSTRB low the SWIM way if NonSerializedIO then nop ; force write to complete endif BRA.S CtlEjtOK ; @10 ; TST.B Ph3L(A0) ; set LSTRB low bra.s ctlEjtOK ; done ; ;Eject new style drive. ; NewDrvEject ; <25Oct85> TST.B mfmMode(A1) ;Are we in MFM mode? BPL.S @00 ; MOVE.B #$F7,wPhase(A0) ;Yes, set LSTRB low the SWIM way if NonSerializedIO then nop ; force write to complete endif BRA.S @0 ; @00 ; TST.B Ph3L(A0) ; 1us < assert LSTRB < 300ms <25Oct85> @0 MOVEQ #30,D3 ; loop counter 3.0 sec max <25Oct85><4> @1 MOVE.W #1000, D0 ; wait 100 msec <25Oct85> BSR WakeUp ; <25Oct85> MOVEQ #DIPAdr,D0 ; new drive needs /enb asserted until<25Oct85> BSR AdrAndSense ; 150usec after /cstin goes away. <25Oct85> DBMI D3,@1 ; fall through if no disk in place <25Oct85> MOVEQ #10,D0 ; wait 1ms <25Oct85> BSR WakeUp ; <25Oct85> CtlEjtOK MOVE.B EjectWait(A1), DiskInPlace(A1,D1) ; set to DIP wait <29Oct85> moveq #noErr,D0 ;no error BRA DiskDone eject ; ; ;_______________________________________________________________________ ; ; Routine: DiskStatus ; Arguments: A0 (input) -- pointer to status call parameter block: ; CSCode = 6 for list of possible disk formats ; CSParam: ; (0) = number of entries requested (input) and ; number of entries returned (output) ; (2) = pointer to location to stuff format info ; CSCode = 8 for drive status ; CSParam: ; (0) current track location ; (2) bit7=1=write-protected ; (3) $FC-$FF= just ejected, 0=no DIP,1=DIP, 2=clamped ; (4) 0=don't know, 1=inst., $FF=not inst. ; (5) $FF for 2-sided drive, $00 for 1-sided ; (6) drive queue element ; (18) $FF for 2-sided format current diskette ; (19) $FF for new interface drive ; (20) soft error count (word) ; CSCode = 10 for extended status (includes MFM info) ; CSParam: ; (0) drive type: $FF=SuperDrive (MFM/GCR), $00=400K/800K GCR ; (1) disk format: $FF=MFM, $00=GCR (only valid when installed) ; (2) MFM format: $FF=1440K, $00=720K ; (3) disk controller: $FF=SWIM, $00=IWM ; ; Function: The status call returns current status for the drive requested. ;_______________________________________________________________________ ; ;The dispatch table contains WORD offsets from the table itself to the ;various routines; this allows 16 bit offsets instead of 32 bit addresses. ; ; (Code) (offset) StatusTbl DC.W FmtLstCode, PassportSts-StatusTbl ; DC.W DrvStsCode, DriveStatus-StatusTbl ; DC.W MFMStsCode, MFMStatus-StatusTbl ; DC.W DupVerSts, DupVersion-StatusTbl ;<2.1> DC.W FmtByteSts, GetFmtByte-StatusTbl ;<1.8> DC.W SpdChkSts, StsSpeedChk-StatusTbl ; DC.W 0 ; DiskStatus MOVEQ #StatusErr,D0 ;Assume unsupported status call LEA StatusTbl,A3 ;Dispatch table base address MOVEA.L A3,A4 ;Save a copy for later BRA.S @2 @1 ADDQ.W #2,A3 ;Next table entry @2 MOVE.W (A3)+,D2 ;Get the entry's opcode BEQ.S @3 ;-> error: end of table CMP.W CSCode(A0),D2 ;Is this the right opcode? BNE.S @1 ;-> nope, try the next one BSR CkDrvNum ;Check for valid drive number BNE.S @3 ;-> it wasn't so exit with an error MOVEQ #NoDriveErr,D0 ;Set up the error code in case a TST.B Installed(A1,D1) ; routine status cares and pre-test LEA CSParam(A0),A0 ;Point to parameters ADDA.W (A3),A4 ;Add table base + routine offset JSR (A4) ;Do it @3 BRA DiskDone ; ; - - - - - - - - - - - - - - - - - - - ; DriveStatus MOVEQ #11,D0 ; return all drive vars except speeds ADD.W D1,A1 ; (11 words) @1 MOVE.W (A1)+,(A0)+ ; move it in a word at a time SUBQ.W #1,D0 BGT.S @1 ; leave D0=0 RTS ; - - - - - - - - - - - - - - - - - - - ; PassportSts BLE.S @0 ;-> drive not installed: error! MOVEQ #offLinErr,D0 ;assume no disk-in-place CMPI.B #2,DiskInPlace(A1,D1) ;Is the disk clamped? BLT.S @0 ;-> no, this info isn't valid MOVEQ #paramErr,D0 ; MOVE.W (A0),D2 ;Get the number of entries requested @0 BLE.S @6 ;-> it's unreasonable, so error LEA diskFmtTbl,A2 ; MOVEQ #1,D3 ;Assume single-sided drive MOVEQ #0,D0 ;(0=400K) TST.B sides(A1,D1) ;Is it? BPL.S @1 ;-> yep MOVE.B twoSideFmt(A1,D1),D0;How many sides does it actually NEG.B D0 ; have? 0=1-sided, 1=2-sided MOVEQ #numSDFmts-1,D3 ;Assume a standard 2-sided drive <2.1> TST.B mfmDrive(A1,D1) ;Is it? BPL.S @01 ; MOVEQ #numSDFmts,D3 ;No, it's a SuperDrive TST.B mfmDisk(A1,D1) ;Is it MFM? BPL.S @01 ; MOVEQ #numSDFmts-1,D0 ;Yes, it could be 720K TST.B twoMegFmt(A1,D1) ;Is this a double-density disk? BPL.S @01 ; LEA diskFmtTbl+8*numSDFmts,A2 ;Yes, it must be 1440K MOVEQ #0,D0 ; MOVEQ #numDDFmts,D3 ; @01 ; @1 CMP.W D3,D2 ;Does user want more than we've got? BLE.S @2 ; MOVE.W D3,D2 ;Yep, so tell 'em how many there are @2 MOVE.W D2,(A0)+ ;and stuff it so the user knows too SUBQ.W #1,D2 ;Adjust for the DBRA to follow MOVE.W D2,D3 ;Loop value for current format SUB.W D0,D3 ;Calculate index to current format ; (relative to starting D3) MOVEA.L (A0),A0 ;Get the user's format table address @3 MOVE.L (A2)+,(A0)+ ;and fill in the disk size MOVE.L (A2)+,D0 ;Get the characteristics CMP.W D2,D3 ;Is this the current format? BNE.S @4 ; BSET #30,D0 ;Yes, mark it as such @4 MOVE.L D0,(A0)+ ;and copy the characteristics DBRA D2,@3 ; @5 MOVEQ #0,D0 ; @6 RTS ; ; The information for each possible disk format is an 8-byte record: ; Byte 0-3: disk capacity in blocks ; (is [#tracks][#heads][#sectors][#bytes/sector]) ; 4: bit 7=1: number of tracks, sides, sectors is valid ; 6=1: current disk has this format ; 5=0: reserved for future expansion, should be zero ; 4=0: single density, =1: double density ; 0-3: number of heads (or zero if don't care) ; 5: number of sectors (or zero if don't care) ; 6-7: number of tracks (or zero if don't care) diskFmtTbl DC.L 2*400 ;400K GCR DC.B (%1000<<4)+1 ; THS valid, SD, 1 head DC.B 10 ; 10 sectors (average) DC.W 80 ; 80 tracks DC.L 2*800 ;800K GCR DC.B (%1000<<4)+2 ; THS valid, SD, 2 heads DC.B 10 ; 10 sectors (average) DC.W 80 ; 80 tracks DC.L 2*720 ;720K (1M) MFM DC.B (%1000<<4)+2 ; THS valid, SD, 2 heads DC.B 9 ; 9 sectors DC.W 80 ; 80 tracks DC.L 2*1440 ;1440K (2M) MFM DC.B (%1001<<4)+2 ; THS valid, DD, 2 heads DC.B 18 ; 18 sectors DC.W 80 ; 80 tracks ; - - - - - - - - - - - - - - - - - - - ; ;Return MFM related drive/disk/FDC info ; MFMStatus MOVE.L mfmDrive(A1,D1),D0 ;Get mfmDrive, mfmDisk, twoMegFmt MOVE.B isSWIM(A1),D0 ;Stuff the FDC type into the lsb MOVE.L D0,(A0) ;Disk size in bytes MOVEQ #0,D0 ;Always return no error RTS ; ; Set up A1/D1 to point to SonyVars and the drive locals, and error check the ;drive number; returns an NSDrvErr if no such drive. (BNE error) ; CkDrvNum MOVEA.L SonyVars,A1 ; get pointer to locals ST Active(A1) ; set active true to exclude VBL task MOVE.W IOVDrvNum(A0),D0 BEQ.S @1 ; drive number must be in 1..maxDrvNum CMPI.W #maxDrvNum,D0 ; BHI.S @1 ;(changed BGT to BHI: what if someone ; uses a negative drive number?) MOVE.W Drive(A1),LastDrive(A1) ; save the former drive <25Oct85> MOVE.W D0,Drive(A1) ; drive in question MOVEQ #noDriveErr,D0 ; assume the chip isn't there TST.B isSWIM(A1) ; see if the IWM/SWIM/... is connected BGT.S @2 ; -> it isn't, so return to caller BSR GetDrv1 ; get (A1,D1) to point to drive vars MOVEQ #0,D0 RTS @1 MOVEQ #NSDrvErr,D0 ; bad drive number @2 RTS ; IF hasPwrControls THEN ; ;ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ ; Routine: TurnIWMoff/TurnIWMon ; ; Input: A1 - SonyVars ; ; Destroys: None ; ; Called by: CommonTurnIWMon, CommonTurnIWMoff ; ; Function: Turn the clocks and power on/off to the IWM ;ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ TurnIWMoff MOVEM.L D0/A0,-(SP) ; Save A0 and D0 MOVEQ.L #(iwmOn**$7F),D0 ; setup to check IWM on bit <2.1> AND.B ChipState(A1),D0 ; see if IWM clock is enabled <2.1> BEQ.S TurnExit ; Don't do anything if already off CLR.B ChipState(A1) ; remember that the IWM is off <2.1> MOVEQ.L #IWMoff,D0 ; Turning off IWM <2.1> BRA.S TurnIWM TurnIWMon MOVEM.L D0/A0,-(SP) MOVEQ.L #(iwmOn**$7F),D0 ; setup to check IWM on bit <2.1> AND.B ChipState(A1),D0 ; see if IWM clock is enabled <2.1> BNE.S TurnExit ; Don't do anything if already on MOVE.W #IWMon,D0 ; Turning on IWM MOVE.B D0,ChipState(A1) ; remember that the IWM is on <2.1> TurnIWM MOVE.B D0,-(SP) ; Turn off unused devices <2.1> MOVE.L SP,-(SP) ; Load pointer to receive buffer MOVE.L (SP),-(SP) ; Load pointer to xmit buffer MOVE.L #(PowerCntl<<16)+1,-(SP) ; PMGR command, 1 byte of xmit data <2.1> MOVE.L SP,A0 ; A0 gets pointer to parameter block _PmgrOp ADDA.W #14,SP ; Remove stack frame <2.1> TurnExit MOVEM.L (SP)+,D0/A0 RTS UpdateChipState ; get PMGR chip pwr/clk enables <2.1> MOVEM.L D0/A0,-(SP) ; save registers <2.1> PEA ChipState(A1) ; Load pointer to receive buffer <2.1> MOVE.L (SP),-(SP) ; Load pointer to xmit buffer <2.1> MOVE.L #(powerRead<<16)+0,-(SP) ; PMGR command, 0 bytes of xmit data <2.1> MOVE.L SP,A0 ; A0 gets pointer to parameter block <2.1> _PmgrOp ; <2.1> ADDA.W #12,SP ; Remove stack frame <2.1> MOVEM.L (SP)+,D0/A0 ; Restore registers <2.1> RTS ; <2.1> HandleSleep ; <11> HJR @SleepQRegs REG D1-D7/A0-A6 ; MOVEM.L @SleepQRegs,-(SP) ; Save regs MOVEA.L SonyVars,A1 ; Get a pointer to sonyvars CMPI.W #SleepWakeUp,D0 ; are we waking up? beq.s @WakeUp ; if so, go deal with it. <1.7> ST active(A1) ; make sure VBLs are excluded when we wake up TST.B isSWIM(A1) ; is a disk controller connected? BPL.S @JustSleep ; -> no, don't bother waiting MOVEQ #90,D1 ; limit the wait to 1.5 secs ADD.L Ticks,D1 ; limit the wait time @Sleep ; else, a sleep request or demand <1.7> CMP.L Ticks,D1 BLS.S @JustSleep ; MOVEQ.L #(iwmOn**$7F),D0 ; setup to check IWM on bit AND.B ChipState(A1),D0 ; if IWM off, OK to sleep BNE.S @Sleep ; wait for eject/power down to finish @JustSleep MOVEQ #0,D0 ; make sure we say it's OK to sleep BRA.S @exit ; all done @WakeUp MOVE SR,-(SP) ; save the SR ORI #$0700,SR ; and disable interrupts MOVEQ.L #(iwmOn**$7F),D1 ; setup to check IWM on bit AND.B ChipState(A1),D1 ; save SWIM powered state CLR.B ChipState(A1) ; and clear it to force a power up BSR.S TurnIWMon ; power up the chip MOVEA.L IWM,A0 ; get IWM base address move.b #$F8,wZeroes(a0) ; switch to IWM mode if NonSerializedIO then nop ; force write to complete endif tst.b Q7L(a0) ; and get out of write mode MOVE.B #1,isSWIM(A1) ; mark as no chip installed BSR TestForChip ; is a disk controller connected? BNE.S @SetIWMoff ; -> nope, just exit CLR.B isSWIM(A1) ; assume it's an IWM BSR Check4SWIM ; find out what kind of chip it is cmp.b #-2,isSWIM(a1) ; do we have a SWIM2?

bne.s @noSWIM2 ; if not, do it the old way SEQ mfmMode(A1) ; SWIM2 is always in ISM mode

bra.s @1 ; jump over the SWIM1 stuff @noSWIM2 CLR.B mfmMode(A1) ; IWM and SWIM power up in IWM mode

@1 MOVE.B D1,-(SP) ; save the state of the SWIM power BSR SetChipMode ; set mode for drive TST.B (SP)+ ; see if SWIM was on at sleep time BEQ.S @SetIWMoff ; if not, turn it off now, and exit @WakeupDone CLR.B active(A1) ; VBLs can run now that everything's initialized MOVE (SP)+,SR ; re-enable interrupts @exit MOVEM.L (SP)+,@SleepQRegs ; restore registers RTS ; all done @SetIWMoff BSR.S TurnIWMoff ; turn the IWM off BRA.S @WakeupDone ; time to go ENDIF ; ;ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ

begin ; ; Routine: TestForChip ; ; Inputs: none ; ; Outputs: D0 -- result code ; CCR-- BNE if no chip is connected ; ; Function: Checks to see if the disk controller chip (that's IWM, SWIM, or ; SWIM2 to the rest of us) is actually connected. Boxes like DB-Lite ; have a SWIM on an external board that may or may not be plugged in ; when driver calls are made. ;ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ TestForChip MOVEM.L A0-A1/D2,-(SP) ; MOVEQ #noErr,D0 ; asssume no error return MOVEA.L IWM,A0 ; get the chip's base address MOVEA.L ROMBASE,A1 ; get ROM base address for bus clearing ; We used to check first for a bus error, but that is not necessary, since MSC chips ; do not bus error on SWIM accesses when there is no SWIM, so we go right to the meat of ; the problem instead. MOVE.B #$F8,wZeroes(A0) ; try to switch to the IWM register set
MOVEQ #$F5-256,D2 ;
MOVE.B D2,wPhase(A0) ; write a value to the phase register
TST.B (A1) ; read first location of ROM to clear bus lines NOP ; make sure the previous instruction does not get cached CMP.B rPhase(A0),D2 ; did we get back what was originally written?
BEQ.S @Done ; -> yes, we've got a SWIM2
; At this point, we know we don't have a SWIM2 connected. We either have an IWM/SWIM or no chip... TST.B q7L(A0) ; select "Read Handshake"
TST.B q6L(A0) ;
MOVE.B D0,q7H(A0) ;
MOVEQ #%00111111,D2 ; mask to just the low 6 bits
AND.B q6L(A0),D2 ; and read the register
TST.B q7L(A0) ; back into a read mode
CMPI.B #%00111111,D2 ; did we get what we expected?
BEQ.S @Done ; -> yes
MOVEQ #noDriveErr,D0 ; the chip isn't there
@Done MOVEM.L (SP)+,A0-A1/D2 ; RTS ;_______________________________________________________________________ ; ; Routine: StsSpeedChk ; ; Inputs: A0 -- pointer to user's csParams ; csParam+ 0: Track Number (word) ; A1 -- pointer to SonyVars ; D1 -- offset to drive's private variables ; ; Outputs: D0 -- result code (0 if no errors) ; csParam+ 2: milliseconds per revolution (word) ; ; Function: measures the time in milliseconds per revolution of the disk ; at the specified track. ;_______________________________________________________________________ StsSpeedChk BLE DiskDone ; -> no drive installed so exit with error IF hasPwrControls THEN ; TestFor hwCbPwrMgr ; BEQ.S @pmgrdone ; BSR TurnIWMon ; Turn IWM on with pmgr call @pmgrdone ; ENDIF ; MOVE.W (A0),SideTrack(A1) ; load track number MOVE.L A0,-(SP) ; save pointer to csParams TST.B isSWIM(A1) ; Is a SWIM installed? BPL.S @0 ; -> no, skip BSR SetChipMode ; Set up the mode for MFM or GCR BNE SpeedChkExit ; -> couldn't initialize the chip @0 BSR DiskSelect ; Re-select the interface BSR FVPowerUp ; start up the drive (synchronously) BSR GetDrv1 BSR SpdSeek ; seek to desired track BNE.S SpeedChkExit ; exit on errors BSR GetDrv1 TST.B mfmDisk(A1,D1) ; Are we in MFM mode? BPL.S @1 ; -> no BSR mFindSpeed ; Check speed MFM style BRA.S @2 @1 BSR gFindSpeed ; Check speed GCR style @2 BMI.S SpeedChkExit ; exit on errors MOVE.L (SP),A0 ; get csParam pointer MOVE.W D0,2(A0) ; put speed result into csParams+2 ; if D0 is positive, it is speed in milliseconds MOVEQ #0,D0 ; successful exit SpeedChkExit ADDQ #4,SP ; toss the saved register BRA DskRWOff ; Share SonyRWT exit routine ; (sets up the power down time) ;_______________________________________________________________________ thru next ; ; Routine: ReGenSoundInt ; ; Desc: Since reading vBufB (like the below routines) causes ; interrupts to cleared, this re-generates those sound ; interrupts. This routine stolen from ; ; {Regatta}Toolbox:SoundMgr:SoundMgrPatch.a ; ; Apologies to those reading this since the constants ; and constant offsets used here were not made symbolic ; in the original code. ; ;_______________________________________________________________________ interruptControlA EQU $F09 ; interrupt mask registers for Batman interruptControlB EQU $F29 ReGenSoundInt btst.b #ifCB1,vIFR(a1) ; check if we still think there's an interrupt bne.s @rts ; yes, we still have an interrupt - exit movea.l ASCBase,a1 ; point to Batman cmpa.l #-1,a1 ; check if it's been set up yet beq.s @rts ; exit if not move.w sr,-(sp) ; preserve the status register ori.w #$0700,sr ; mask interrupts tst.b interruptControlA(a1) ; channel A interrupt enabled? bne.s @checkB ; BRIF not enabled move.b #1,interruptControlA(a1); disable chnl A interrupts nop ; give Batman time to process the disable clr.b interruptControlA(a1) ; clear the interrupt mask to re-generate @checkB tst.b interruptControlB(a1) ; channel B interrupt enabled? bne.s @Done ; interrupt not enabled - done ; To re-generate Batman interrupts, first disable interrupts on both channels, ; then re-enable them. @reGen move.b #1,interruptControlB(a1); disable chnl B interrupts nop ; give Batman time to process the disable clr.b interruptControlB(a1) ; clear the interrupt mask to re-generate @Done move.w (sp)+,sr @rts rts ;_______________________________________________________________________ ; ; Routine: gFindSpeed ; ; inputs: none. ; ; outputs: D0 -- if positive, number of milliseconds per revolution ; if negative, error code ; ; 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. ;_______________________________________________________________________ gFindSpeed MOVE SR,-(SP) MOVEM.L D1-D7/A0-A6,-(SP) MOVEQ #4,D0 ; init PollStack 4 bytes down BSR SetUpPoll ; and disable interrupts . . . MOVEQ #TachAdr,D0 BSR AdrDisk ; address tach signal MOVEA.L IWM,A0 ; TST.B Q6H(A0) ; get into sense mode ; D0 = A0 = DBase ptr ; D1 = -1 (timer load value) A1 = Q7L ptr ; D2 = pulse counter A2 = VIA ptr ; D3 = 5 (VIA timer2 flag reg bit) A3 = VIA flag reg ptr ; D4 = MOVEQ #-1,D1 ; timer load value MOVEQ #5,D3 ; VIA timer 2 flag bit in flag reg MOVE.L VIA,A2 LEA VIFR(A2),A3 ; points to VIA flag reg CMP.B #-2,isSWIM(A1) ; is this a SWIM2? BEQ.S @0 ; -> yes LEA Q7L(A0),A4 ; this is a IWM/SWIM, use Q7L BRA.S @1 ; @0 LEA rHandshake(A0),A4 ; for SWIM2 use handshake register @1 ; first make sure we can see some pulses BSR.W StrtTimer ; now start the timer ; wait for an edge CMP.B #-2,isSWIM(A1) ; is this a SWIM2? BEQ.S @2 ; -> yes BSR.W GetNxtEdge ; use the IWM/SWIM version BRA.S @3 ; @2 MOVEQ #0,D4 ; use only one timer pass BSR.W GetNxtEdge2 ; use the SWIM2 version @3 BNE.S gFSExit ; exit on error BRA.S Wait15Pulses ; then wait for 15 more gFSExit TST.B Q6L(A0) ; back to read mode BSR EmptyPD ; get rid of polled data from SCC moveq #1,D1 ; set T2 to go off ASAP, move.l VIA,A2 ; TimeMgr gets massively bummed bsr.w StrtTimer ; when it misses interrupts MOVEM.L (SP)+,D1-D7/A0-A6 MOVE (SP)+,SR TST.L D0 RTS Wait15Pulses BSR.W StrtTimer MOVEQ #14,D2 ; set up counter for 15 pulses Wait1Pulse CMP.B #-2,isSWIM(A1) ; is this a SWIM2? BEQ.S @0 ; -> yes BSR.W GetNxtEdge ; use the IWM/SWIM version BRA.S @00 ; @0 MOVEQ #0,D4 ; use only one timer pass BSR.W GetNxtEdge2 ; use the SWIM2 version @00 BNE.S gFSExit ; branch if too slow DBRA D2,Wait1Pulse MOVEQ #0,D2 ; clear D2 MOVE.B VT2CH(A2),D2 ; get timer high byte MOVE.B VT2C(A2),D1 ; and timer low byte CMP.B VT2CH(A2),D2 ; did high byte change? BEQ.S @1 ; branch if not MOVEQ #0,D1 ; if so, low byte should be 00 ; (since value decrements!) @1 BTST D3,(A3) ; timer flag bit set? BNE.S gFSExit ; then exit with error LSL.W #8,D2 ; get into correct order OR.B D1,D2 NOT.W D2 ; and convert to positive count ASL.L #2,D2 ; multiply by four to get ticks per full revolution DIVU.L #nTicks,D2 ; then convert to milliseconds MOVEQ #0,D0 ; clear high word MOVE.W D2,D0 ; return speed BRA.S gFSExit ;_______________________________________________________________________ ; ; Routine: mFindSpeed ; ; inputs: none. ; ; outputs: D0 -- if positive, number of milliseconds per revolution ; if negative, error code ; ; Function: This routine measures the time (in VIA counts) it takes ; for the disk to revolve one time; this test looks for the index ; pulse which occurs one time per rev. VIA timer 2 is used; if ; an index pulse is not seen in 334 msec, this routine ; will time out and take the error exit. ; ; The drive should be powered when this is called. ;_______________________________________________________________________ mFindSpeed MOVE SR,-(SP) MOVEM.L D1-D7/A0-A6,-(SP) MOVEQ #4,D0 ; init PollStack 4 bytes down BSR SetUpPoll ; and disable interrupts . . . MOVEQ #TachAdr,D0 BSR AdrDisk ; address tach signal MOVEA.L IWM,A0 ; ; D0 = A0 = DBase ptr ; D1 = -1 (timer load value) A1 = Q7L ptr ; D2 = pulse counter A2 = VIA ptr ; D3 = 5 (VIA timer2 flag reg bit) A3 = VIA flag reg ptr ; D4 = MOVEQ #-1,D1 ; timer load value MOVEQ #5,D3 ; VIA timer 2 flag bit in flag reg MOVE.L VIA,A2 LEA VIFR(A2),A3 ; points to VIA flag reg LEA rHandshake(A0),A4 ; for SWIM2 use handshake register ; first make sure we can see some pulses BSR.S StrtTimer ; start the timer ; wait for an edge MOVEQ #3,D4 ; wait up to four timer passes BSR.W GetNxtEdge2 ; use the ISM/SWIM2 version BEQ.S Wait4Index ; then wait for one more edge mFSExit BSR EmptyPD ; get rid of polled data from SCC moveq #1,D1 ; set T2 to go off ASAP, move.l VIA,A2 ; TimeMgr gets massively bummed bsr.s StrtTimer ; when it misses interrupts MOVEM.L (SP)+,D1-D7/A0-A6 MOVE (SP)+,SR TST.L D0 RTS Wait4Index BSR.S StrtTimer MOVEQ #3,D4 ; wait up to four timer passes BSR.W GetNxtEdge2 ; use the ISM/SWIM2 version BNE.S mFSExit ; branch if too slow MOVEQ #3,D2 ; SUB.B D4,D2 ; Find out how many timer passes we used MOVEQ #0,D4 ; initialize D4 BRA.S @01 ; start looping @00 ADD.L #$FFFF,D4 ; add in FFFF ticks for each complete timer @01 DBRA D2,@00 ; pass used MOVEQ #0,D2 ; clear high word of D2 MOVE.B VT2CH(A2),D2 ; get timer high byte MOVE.B VT2C(A2),D1 ; and timer low byte CMP.B VT2CH(A2),D2 ; did high byte change? BEQ.S @1 ; branch if not MOVEQ #0,D1 ; if so, low byte should be 00 ; (since value decrements!) @1 BTST D3,(A3) ; timer flag bit set? BNE.S mFSExit ; then exit with error LSL.W #8,D2 ; get into correct order OR.B D1,D2 NOT.W D2 ; and convert to positive count ADD.L D4,D2 ; Add in ticks for previous timer passes DIVU.L #nTicks,D2 ; then convert to milliseconds MOVEQ #0,D0 ; clear high word MOVE.W D2,D0 ; return speed BRA.S mFSExit ;_______________________________________________________________________ ; Utility routines for finding disk speed ;_______________________________________________________________________ ; ;Set T2 to the value in D1. ; StrtTimer move.b D1,VT2C(A2) ; write timer low count ror.w #8,D1 ; MSB in low byte D1 move.b D1,VT2CH(A2) ; write timer high count, load T2, ; clear int flag ror.w #8,D1 ; LSB in low D1 again RTS ; wait for a rising edge on the tach feedback GetNxtEdge MOVE.L (SP)+,DskRtnAdr ; save return address here WaitForLow _PollSCC ; poll the SCC modem port TST.B (A4) ; tach feedback is bit 7 (sense) BMI.S @1 ; br if still high TST.B (A4) ; tach feedback is bit 7 (sense) BPL.S WaitForHigh ; br if it is still low @1 BTST D3,(A3) ; timer flag bit set yet? BEQ.S WaitForLow NoPulse MOVEQ #NoDriveErr,D0 ; probably no drive installed BRA.W DskRtn WaitForHigh _PollSCC ; poll the SCC modem port BTST D3,(A3) ; timer flag bit set yet? BNE.S NoPulse TST.B (A4) ; tach feedback is bit 7 (sense) BPL.S WaitForHigh ; br if still low TST.B (A4) ; tach feedback is bit 7 (sense) BPL.S WaitForHigh ; br if it was a glitch MOVEQ #0,D0 ; success BRA.W DskRtn ; wait for a rising edge on the tach feedback for ISM/SWIM2 GetNxtEdge2 MOVE.L (SP)+,DskRtnAdr ; save return address here WaitForLow2 _PollSCC ; poll the SCC modem port BTST #3,(A4) ; tach feedback is bit 3 (sense) BNE.S @1 ; br if still high BTST #3,(A4) ; tach feedback is bit 3 (sense) BEQ.S WaitForHigh2 ; br if it is still low @1 BTST D3,(A3) ; timer flag bit set yet? BEQ.S WaitForLow2 TST.B D4 ; how many timer passes are left? BEQ.S NoPulse2 ; none, exit with error BSR.S StrtTimer ; restart timer, D1 still valid SUBQ #1,D4 ; decrement count BRA.S WaitForLow2 ; go back and keep waiting NoPulse2 MOVEQ #NoDriveErr,D0 ; probably no drive installed BRA.W DskRtn WaitForHigh2 _PollSCC ; poll the SCC modem port BTST D3,(A3) ; timer flag bit set yet? BEQ.S @1 TST.B D4 ; how many timer passes are left? BEQ.S NoPulse2 ; none, exit with error BSR.S StrtTimer ; restart timer, D1 still valid SUBQ #1,D4 ; decrement count @1 BTST #3,(A4) ; tach feedback is bit 3 (sense) BEQ.S WaitForHigh2 ; br if still low BTST #3,(A4) ; tach feedback is bit 3 (sense) BEQ.S WaitForHigh2 ; br if it was a glitch MOVEQ #0,D0 ; success BRA.W DskRtn ;ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ PollSCC BTST #RxCA,aCtl-aData(A6) ; SCC data available? BEQ.S @NoSCCData ; -> no, done SUBQ.W #2,SP ; make space for the byte, MOVE.L 2(SP),(SP) ; move the return address down to make space, MOVE.B (A6),4(SP) ; and "push" the SCC byte on the stack @NoSCCData RTS ;ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ ;Control retry enabling/disabling. Drive number not specified. ; ctlRetries TST.W CSParam(A0) ; what does the caller want? BNE.S @0 ; ST.B DisableRetries(A1) ; disable retries if zero BRA.S @1 ; @0 CLR.B DisableRetries(A1) ; else enable retries @1 moveq #noErr,D0 ;always return OK bra DiskDone ; ;ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ end