mirror of
https://github.com/elliotnunn/supermario.git
synced 2024-11-28 13:52:37 +00:00
1767 lines
66 KiB
Plaintext
1767 lines
66 KiB
Plaintext
|
;
|
||
|
; File: EDiskDrvr.a
|
||
|
;
|
||
|
; Contains: Electronic Disk Driver
|
||
|
;
|
||
|
; Written by: Gary G. Davidian
|
||
|
;
|
||
|
; Copyright: © 1988-1993 by Apple Computer, Inc., all rights reserved.
|
||
|
;
|
||
|
; Change History (most recent first):
|
||
|
;
|
||
|
; <SM7> 10/28/93 CCH Optimized read path to not disable writes on every call and
|
||
|
; disabled checksums on PDM.
|
||
|
; <SM6> 10/14/93 CCH Added write-protection support for PowerPC machines.
|
||
|
; <SM5> 4/15/93 chp Fix RADAR #1078337. Format csCode would crash given an invalid
|
||
|
; drive number. An error handler was branching to the wrong label.
|
||
|
; <SM4> 2/8/93 rab Sync up with Horror. Comments follow.
|
||
|
; <H6> 9/30/92 BG (for Dave Nelson) Added a patch to fix the problem of the driver
|
||
|
; not adjusting the usage count correctly if someone calls the
|
||
|
; driver with an invalid _Control call.
|
||
|
; <SM3> 8/31/92 PN Fix header
|
||
|
; <SM2> 8/31/92 PN First time this file is moved over from Horror so that RAMDisk
|
||
|
; works with Cyclone
|
||
|
; ———————————————————————————————————————————————————————————————————————————————————————
|
||
|
; SuperMario ROM comments start here.
|
||
|
; ———————————————————————————————————————————————————————————————————————————————————————
|
||
|
; <H3> 2/5/92 SWC Set bit 15 in the driveInfo for RAM disks so the Finder can have
|
||
|
; a way to determine that the media is volatile.
|
||
|
; <H2> 12/12/91 CCH Fixed Read-Verify bug in 24-bit mode.
|
||
|
; ———————————————————————————————————————————————————————————————————————————————————————
|
||
|
; Pre-HORROR ROM comments begin here.
|
||
|
; ———————————————————————————————————————————————————————————————————————————————————————
|
||
|
; <7> 6/30/91 CCH Updated icon.
|
||
|
; <6> 6/13/91 CCH Moved RamDiskSize to EDiskDriveInfo record and modified the way
|
||
|
; it is initialized.
|
||
|
; <5> 5/24/91 CCH Turned on write-protection of the EDisk's address space when not
|
||
|
; being accessed by the driver.
|
||
|
; <4> 3/19/91 CCH Modified to use seperate ram disk memory area set up by the MMU.
|
||
|
; <3> 2/25/91 CCH Removed redundant RAM test, changed to a jump vector for
|
||
|
; _SwapMMUMode, and preserved the result code in the verify
|
||
|
; routine. Also made modifications to keep RAM disk intact across
|
||
|
; memory-mode changes (24<->32).
|
||
|
; <2> 12/20/90 CCH Added changes to support 32-bit addressing.
|
||
|
; ———————————————————————————————————————————————————————————————————————————————————————
|
||
|
; Pre-TERROR ROM comments begin here.
|
||
|
; ———————————————————————————————————————————————————————————————————————————————————————
|
||
|
; <3> 5/16/90 JJ Modify to use only 1 byte of Pram.
|
||
|
; <2> 5/16/90 JJ Restructured to provide RAMDisk on Elsie and Erickson.
|
||
|
; {2} 2/6/90 GMR Fixed bug in Prime where it didn't update ioNumDone,
|
||
|
; dCtlPosition properly.
|
||
|
; {1.8} 8/16/89 BBM version 1.7 broke hcmac build by the addition of flag hasSlim.
|
||
|
; fixed same.
|
||
|
; {1.7} 8/16/89 BBM temporary hack to get edisks working on emacs.
|
||
|
; <1.6> 5/26/89 GMR Saves RAM disk size in new EDisk global in Open code, added new
|
||
|
; status call to retrieve it.
|
||
|
; <1.5> 4/25/89 GMR Let d6 accumulate MOD3 test results on each RAM test pass, since
|
||
|
; the MOD3 test OR's errors into d6. This fixes the format bug in
|
||
|
; version 1.4.
|
||
|
; <1.4> 4/11/89 GMR Tests RAM in 16K chunks, for better mouse movement.
|
||
|
; <1.3> 4/4/89 GMR Added new ICON's. Format now tests RAM in 64K chunks, so the
|
||
|
; mouse won't freeze on large RAM disks.
|
||
|
; <1.2> 2/21/89 GGD Added support for immediate calls, and KillIO. Made the Apple
|
||
|
; look better in SLIM Icon. Added support for new SLIM interface
|
||
|
; adapter.
|
||
|
; <1.1> 11/11/88 CCH Fixed Header.
|
||
|
; <1.0> 11/9/88 CCH Adding to EASE.
|
||
|
; <1.5> 11/2/88 GGD Added code to post events to drive some sort of user interface
|
||
|
; for the lack of an eject/locking mechanism (currently, and
|
||
|
; hopefully permanently, disabled). Added support for internal ROM
|
||
|
; Disks (untested). Removed drivers need to staticly know its
|
||
|
; driver refnum, no code needs to change if refnum needs to
|
||
|
; change. Storage is now only allocated for drives that exist.
|
||
|
; EDiskHeader format and signature changed. Probably lots of other
|
||
|
; improvements too.
|
||
|
; <1.3> 9/1/88 GGD Added official drive icons. Added partial support for ROM disks.
|
||
|
; Added DriveInfo support. Changed drive queue order and numbering
|
||
|
; to interface better with the Startup Device CDEV. Optimized a
|
||
|
; few routines. Deleted code associated with normandy work around.
|
||
|
; Deleted support for Non-Battery-Backed-Up SLIM EDisks. Added
|
||
|
; special RAM Disk format code to erase and delete from drive
|
||
|
; queue.
|
||
|
; <1.2> 8/5/88 MSH Cleared hardware workaround flag. New normandy necessary to use
|
||
|
; SLIMs.
|
||
|
; <1.1> 6/21/88 GGD Changed Internal EDisk size computation and space allocation to
|
||
|
; be in 64KB blocks ending at MemTop. Changed FormatVerify to
|
||
|
; check checksums if present, otherwise NoErr. Changed Format to
|
||
|
; call TestManager to test RAM.
|
||
|
; <1.0> 4/21/88 MSH New Today
|
||
|
;
|
||
|
; To Do:
|
||
|
;
|
||
|
|
||
|
;--------------------------------------------------------
|
||
|
;
|
||
|
;_______________________________________________________________________
|
||
|
;
|
||
|
; © Apple Computer, Inc. 1988,1989
|
||
|
;
|
||
|
; written by Gary G. Davidian 13-Mar-88
|
||
|
;
|
||
|
;_______________________________________________________________________
|
||
|
|
||
|
BLANKS ON
|
||
|
PRINT OFF
|
||
|
LOAD 'StandardEqu.d'
|
||
|
INCLUDE 'HardwareEqu.a'
|
||
|
INCLUDE 'MMUEqu.a'
|
||
|
INCLUDE 'BootEqu.a'
|
||
|
INCLUDE 'SonyEqu.a'
|
||
|
PRINT ON
|
||
|
INCLUDE 'EDiskEqu.a'
|
||
|
PRINT NOMDIR
|
||
|
|
||
|
MACHINE MC68020
|
||
|
|
||
|
NewEdiskProt EQU 1
|
||
|
|
||
|
_TestManager OPWORD $A06B
|
||
|
|
||
|
macro
|
||
|
assert &boolExpr
|
||
|
if not(&Eval(&boolExpr)) then
|
||
|
aerror &concat('Assertion Failed - ',&boolExpr)
|
||
|
endif
|
||
|
endm
|
||
|
title 'EDisk Driver - DRVR Header'
|
||
|
|
||
|
; Driver Header for Device Manager
|
||
|
|
||
|
EDiskDRVR PROC EXPORT
|
||
|
with EDiskVars,EDiskDriveInfo,StartGlobals,MMUConfigInfo
|
||
|
|
||
|
EDiskDRVRflags SET 0
|
||
|
EDiskDRVRflags SET EDiskDRVRflags!1<<dReadEnable
|
||
|
EDiskDRVRflags SET EDiskDRVRflags!1<<dWritEnable
|
||
|
EDiskDRVRflags SET EDiskDRVRflags!1<<dCtlEnable
|
||
|
EDiskDRVRflags SET EDiskDRVRflags!1<<dStatEnable
|
||
|
EDiskDRVRflags SET EDiskDRVRflags!1<<dNeedLock
|
||
|
|
||
|
dc.b EDiskDRVRflags,0 ; drvFlags (upper byte)
|
||
|
dc.w 0 ; drvDelay, no delay
|
||
|
dc.w 0 ; drvEMask, no event mask
|
||
|
dc.w 0 ; drvMenu, no menu
|
||
|
dc.w EDiskOpen-EDiskDRVR ; drvOpen, offset of OPEN routine
|
||
|
dc.w EDiskPrime-EDiskDRVR ; drvPrime, offset of PRIME routine
|
||
|
dc.w EDiskControl-EDiskDRVR ; drvCtl, offset of ConTroL routine
|
||
|
dc.w EDiskStatus-EDiskDRVR ; drvStatus, offset of STATUS routine
|
||
|
dc.w EDiskClose-EDiskDRVR ; drvClose, offset of CLOSE routine
|
||
|
|
||
|
string pascal
|
||
|
dc.b '.EDisk' ; drvName, including leading length byte
|
||
|
align 2 ; force back to even boundaries
|
||
|
|
||
|
; Decode table for Status Calls
|
||
|
|
||
|
StatusDecode
|
||
|
dc.w statFmtLst-(*+4)
|
||
|
dc.w fmtLstCode ; Get Format List status call
|
||
|
|
||
|
dc.w statDrvSts-(*+4)
|
||
|
dc.w drvStsCode ; Drive Status call
|
||
|
|
||
|
dc.w statDrvSize-(*+4) ; <1.7>
|
||
|
dc.w drvSizeCode ; Drive Size Status call <1.7>
|
||
|
|
||
|
dc.w -1 ; indicate end of status decode table
|
||
|
dc.w StatusErr ; return StatusErr if unknown csCode
|
||
|
|
||
|
; Decode table for Control Calls
|
||
|
|
||
|
ControlDecode
|
||
|
dc.w ctlKillIO-(*+4) ; <1.2>
|
||
|
dc.w killCode ; KillIO control call (not supported) <1.2>
|
||
|
|
||
|
dc.w ctlVerify-(*+4)
|
||
|
dc.w VerifyCC ; Verify control call
|
||
|
|
||
|
dc.w ctlFormat-(*+4)
|
||
|
dc.w FormatCC ; Format control call
|
||
|
|
||
|
dc.w ctlEject-(*+4)
|
||
|
dc.w EjectCode ; Eject control call
|
||
|
|
||
|
dc.w ctlDriveIcon-(*+4)
|
||
|
dc.w IconCC ; Physical Drive Icon control call
|
||
|
|
||
|
dc.w ctlMediaIcon-(*+4)
|
||
|
dc.w IconLogCC ; Disk Media Icon control call
|
||
|
|
||
|
dc.w ctlDriveInfo-(*+4)
|
||
|
dc.w infoCC ; Drive Info control call
|
||
|
|
||
|
dc.w -1 ; indicate end of control decode table
|
||
|
dc.w ControlErr ; return ControlErr if unknown csCode
|
||
|
title 'EDisk Driver - Open processing'
|
||
|
|
||
|
;_______________________________________________________________________
|
||
|
;
|
||
|
; Routine: EDiskOpen
|
||
|
; Inputs: A0 - pointer to I/O ParamBlock
|
||
|
; A1 - pointer to Device Control Entry (DCE)
|
||
|
; Outputs: D0 - Result Code (noErr/openErr)
|
||
|
; Destroys:
|
||
|
; Calls: none
|
||
|
; Called by: Device Manager
|
||
|
;
|
||
|
; Function: Driver initialization routine
|
||
|
;
|
||
|
; NOTE: EDisks are installed in the following order, Slim1 (lower),
|
||
|
; Slim0 (upper), ROM Disk, RAM Disk. This is the order that
|
||
|
; the start code will attempt to boot from them, unless this
|
||
|
; has been overriden with the Startup Device CDEV. This order
|
||
|
; was chosen as follows, removable devices first, fixed devices
|
||
|
; last. For Slims, the lower Slim is checked first to be consistent
|
||
|
; with the two drive Mac SE / Harpo Floppy drive search order,
|
||
|
; which checks the lower drive first. For ROM/RAM disks, the RAM
|
||
|
; disk is searched first, and then the ROM disks are searched. The
|
||
|
; user can still override this order, by picking one with the CDEV.
|
||
|
; Also, gaps may be left in the drive numbering for drive which
|
||
|
; aren't found, when installing them in the drive queue, because
|
||
|
; the startup device drive number is saved in parameter ram,
|
||
|
; and we don't want it moving around across boots.
|
||
|
;_______________________________________________________________________
|
||
|
|
||
|
InitTable
|
||
|
dc.l 0 ; RamDisk doesn't have poll pointer
|
||
|
dc.w RAMDiskHandler-(*+2) ; RamDisk function handler
|
||
|
dc.w RAMDiskMediaIcon-(*+2) ; RamDisk media icon pointer
|
||
|
dc.w RAMDiskDriveIcon-(*+2) ; RamDisk drive icon pointer
|
||
|
dc.w RAMDiskName-(*+2) ; RamDisk drive name pointer
|
||
|
dc.l (1<<15)+\ ; volatile media
|
||
|
(0<<11)+\ ; primary
|
||
|
(1<<10)+\ ; fixed
|
||
|
(0<<9)+\ ; iwm (not SCSI)
|
||
|
(0<<8)+\ ; internal
|
||
|
ramDiskType ; RAM disk
|
||
|
dc.b (1<<CreateWithXSums) ; flags
|
||
|
dc.b $48 ; DiskInPlaceInit = non-ejectable, re-mount
|
||
|
|
||
|
InitTablePPC
|
||
|
dc.l 0 ; RamDisk doesn't have poll pointer
|
||
|
dc.w RAMDiskHandlerPPC-(*+2) ; RamDisk function handler for PowerPC
|
||
|
dc.w RAMDiskMediaIcon-(*+2) ; RamDisk media icon pointer
|
||
|
dc.w RAMDiskDriveIcon-(*+2) ; RamDisk drive icon pointer
|
||
|
dc.w RAMDiskName-(*+2) ; RamDisk drive name pointer
|
||
|
dc.l (1<<15)+\ ; volatile media
|
||
|
(0<<11)+\ ; primary
|
||
|
(1<<10)+\ ; fixed
|
||
|
(0<<9)+\ ; iwm (not SCSI)
|
||
|
(0<<8)+\ ; internal
|
||
|
ramDiskType ; RAM disk
|
||
|
dc.b (0<<CreateWithXSums) ; flags
|
||
|
dc.b $48 ; DiskInPlaceInit = non-ejectable, re-mount
|
||
|
|
||
|
PrimaryROMdisk
|
||
|
dc.l 0 ; RomDisk doesn't have poll pointer
|
||
|
dc.w ROMDiskHandler-(*+2) ; RomDisk function handler
|
||
|
dc.w ROMDiskMediaIcon-(*+2) ; RomDisk media icon pointer
|
||
|
dc.w ROMDiskDriveIcon-(*+2) ; RomDisk drive icon pointer
|
||
|
dc.w ROMDiskName-(*+2) ; RomDisk drive name pointer
|
||
|
dc.l (0<<11)+\ ; primary
|
||
|
(1<<10)+\ ; fixed
|
||
|
(0<<9)+\ ; iwm (not SCSI)
|
||
|
(0<<8)+\ ; internal
|
||
|
romDiskType ; ROM disk
|
||
|
dc.b (1<<CreateWithXSums) ; flags
|
||
|
dc.b $08 ; DiskInPlaceInit = non-ejectable
|
||
|
InitEntrySize equ *-PrimaryROMdisk ; size of an initialization table entry
|
||
|
|
||
|
SecondaryROMdisk
|
||
|
dc.l 0 ; RomDisk doesn't have poll pointer
|
||
|
dc.w ROMDiskHandler-(*+2) ; RomDisk function handler
|
||
|
dc.w ROMDiskMediaIcon-(*+2) ; RomDisk media icon pointer
|
||
|
dc.w ROMDiskDriveIcon-(*+2) ; RomDisk drive icon pointer
|
||
|
dc.w ROMDiskName-(*+2) ; RomDisk drive name pointer
|
||
|
dc.l (1<<11)+\ ; secondary
|
||
|
(1<<10)+\ ; fixed
|
||
|
(0<<9)+\ ; iwm (not SCSI)
|
||
|
(0<<8)+\ ; internal
|
||
|
romDiskType ; ROM disk
|
||
|
dc.b (1<<CreateWithXSums) ; flags
|
||
|
dc.b $08 ; DiskInPlaceInit = non-ejectable
|
||
|
|
||
|
EDiskOpen ; all regs saved by Device Manager
|
||
|
move.l a0,-(sp) ; save pointer to I/O param block
|
||
|
|
||
|
; Find the highest used drive number
|
||
|
|
||
|
move.l DCtlRefNum(a1),d7 ; d7.high := driver ref num
|
||
|
move.w #5,d7 ; d7 := refnum/highest drive number
|
||
|
move.l DrvQHdr+QHead,d0 ; get the drive queue head
|
||
|
beq.s @FoundDriveNumber ; if drive queue is empty
|
||
|
@NextDriveQueue
|
||
|
movea.l d0,a0 ; a0 := drive queue element
|
||
|
cmp.w DQDrive(a0),d7 ; check for a match
|
||
|
bhs.s @NextDriveNumber ; if drive number already in use
|
||
|
move.w DQDrive(a0),d7 ; this is now the highest drive number
|
||
|
@NextDriveNumber
|
||
|
move.l QLink(a0),d0 ; check next drive queue element
|
||
|
bne.s @NextDriveQueue ; if queue element exists
|
||
|
@FoundDriveNumber
|
||
|
addq.w #1,d7 ; d7 := next drive number
|
||
|
|
||
|
lea InitTable,a6 ; a6 := assume pointer to 68k initial values <2>
|
||
|
|
||
|
IF newEdiskProt THEN
|
||
|
cmpi.b #EMMU1,MMUType ; check for an emulated MMU
|
||
|
bne.s @NoEMMU
|
||
|
lea InitTablePPC,a6 ; a6 := pointer to PowerPC initial values
|
||
|
@NoEMMU
|
||
|
ENDIF
|
||
|
|
||
|
move.l BootGlobPtr,a2 ; get ptr to BootGlobs <T2>
|
||
|
move.l sgRamDiskBase(a2),d2 ; base of RAM disk <T4>
|
||
|
move.l d2,d3 ; get a copy in d3 <T4>
|
||
|
add.l sgRamDiskSize(a2),d3 ; end of ram disk in d3 <T4>
|
||
|
|
||
|
suba.l a2,a2 ; a2 := HeaderInfoPtr (none for RamDisk) <2>
|
||
|
move.l d2,d1 ; get start addr in d2 <T4>
|
||
|
moveq.l #0,d2 ; DataStartPtr := 0 <2>
|
||
|
cmp.l d1,d3 ; see if it has any bytes
|
||
|
bsr CreateEDrive ; create the RAM disk
|
||
|
@noDisk ; ENDIF
|
||
|
|
||
|
; search for, and install ROM disks
|
||
|
|
||
|
movea.l RomBase,a2 ; start searching at the base of ROM
|
||
|
@RomDiskLoop ;
|
||
|
bsr.w CheckForRomDisk ; see if it is a ROM disk
|
||
|
bne.s @NextRomDisk ; if not, try the next block
|
||
|
|
||
|
moveq.l #0,d1 ; assume no checksums unless header says otherwise
|
||
|
move.l a2,d2 ; DataStartPtr := base of rom disk for now
|
||
|
move.l a2,d3 ; DataEndPtr := base of rom disk for now
|
||
|
bsr.s CreateEDrive ; create the RAM disk
|
||
|
lea SecondaryROMdisk,a6 ; all future ROM disks are secondary
|
||
|
|
||
|
@NextRomDisk ;
|
||
|
adda.l #RomDiskAlign,a2 ; point to next block to check
|
||
|
cmpa.l #RomSpaceEnd,a2 ; see if end reached
|
||
|
blo.s @RomDiskLoop ; search the entire space
|
||
|
|
||
|
; see if we have any EDisks to drive, abort OPEN if none.
|
||
|
|
||
|
moveq.l #OpenErr,d0 ; if no drives found, return OpenErr
|
||
|
swap d7 ; d7.low := driver ref num
|
||
|
lea DrvQHdr+QHead-QLink,a0 ; point to the drive queue head
|
||
|
@CheckNeXTDrive
|
||
|
move.l QLink(a0),d1 ; check next drive queue element
|
||
|
beq.s @OpenDone ; if end of queue, and not found, kill the open
|
||
|
movea.l d1,a0 ; a0 := drive queue element
|
||
|
cmp.w dQRefNum(a0),d7 ; is this one of ours
|
||
|
bne.s @CheckNeXTDrive ; if not, check the NeXT one
|
||
|
|
||
|
; there are some EDisks in the drive queue, guess we need a driver for them.
|
||
|
|
||
|
move.l #EDiskVarsSize,d0 ; size of block to allocate
|
||
|
_NewPtr ,SYS,CLEAR ; allocate memory for globals
|
||
|
movea.l a0,a2 ; a2 := pointer to globals
|
||
|
move.l a2,DCtlStorage(a1) ; save globals pointer in DCE
|
||
|
move.l a1,DCEpointer(a2) ; save pointer to DCE in globals
|
||
|
move.w @RTS,FindDqePatch(a2) ; initialize FindDQE patch routine
|
||
|
move.w @RTS,PrimePatch(a2) ; initialize Prime patch routine
|
||
|
|
||
|
; Install the VBL task to look for SLIM insertions and removals
|
||
|
|
||
|
lea EDiskPollTask,a4 ; get the task address
|
||
|
moveq.l #8-1,d4 ; loop counter (8 times)
|
||
|
@InitPolling
|
||
|
lea VTask(a2),a0 ; a0 := pointer to VTask
|
||
|
jsr (a4) ; poll 8 times to init inserted status
|
||
|
dbra d4,@InitPolling ; and mount drives, and compute sizes
|
||
|
|
||
|
lea VTask(a2),a0 ; a0 <- VBL task
|
||
|
addq.w #vType,qType(a0) ; initialize qType field
|
||
|
move.l a4,vblAddr(a0) ; initialize vblAddr field
|
||
|
_VInstall ; install the VBL task
|
||
|
|
||
|
moveq.l #NoErr,d0 ; no error
|
||
|
@OpenDone
|
||
|
movea.l (sp)+,a0 ; restore pointer to I/O param block
|
||
|
move.w d0,ioResult(a0) ; return open status in ioResult
|
||
|
@rts rts
|
||
|
title 'EDisk Driver - Create EDrive'
|
||
|
|
||
|
;_______________________________________________________________________
|
||
|
;
|
||
|
; Routine: CreateEDrive
|
||
|
; Inputs: ccr.z - bne if drive should be created, beq if not
|
||
|
; A2 - HeaderInfoPtr
|
||
|
; D1 - CheckSumPtr
|
||
|
; D2 - DataStartPtr
|
||
|
; D3 - DataEndPtr
|
||
|
; D7.hi - EDisk Driver RefNum
|
||
|
; D7.lo - drive number
|
||
|
; A6 - pointer to InitTable info for this drive
|
||
|
; Outputs: D7.hi - EDisk Driver RefNum
|
||
|
; D7.lo - drive number + 1
|
||
|
; A6 - pointer to InitTable info for next drive
|
||
|
; Destroys: D0, A0, A3, A4
|
||
|
; Calls: none
|
||
|
; Called by: EDiskOpen
|
||
|
;
|
||
|
; Function: Creates and initializes the EDiskDriveInfo for the specified
|
||
|
; EDisk, and installs the drive queue entry for it.
|
||
|
;
|
||
|
;_______________________________________________________________________
|
||
|
|
||
|
CreateEDrive
|
||
|
beq.s @Done ; skip it if not used
|
||
|
|
||
|
moveq.l #EDiskDriveInfoSize,d0 ; size of info to allocate
|
||
|
_NewPtr ,Sys,Clear ; allocate the drive info
|
||
|
bne.s @Done ; if can't allocate, don't create drive
|
||
|
|
||
|
add.l #DQE-SLIMRegPtr,a0 ; point to the drive queue entry <T6>
|
||
|
|
||
|
movea.l a6,a3 ; a3 := running pointer to init table entry
|
||
|
move.l (a3)+,SLIMRegPtr(a0) ; initialize the SLIMRegPtr <T6>
|
||
|
movea.w (a3)+,a4 ; get the icon/name ptr
|
||
|
adda.l a3,a4 ; make it absolute
|
||
|
move.l a4,HWDepProcPtr(a0) ; initialize the HWDepProcPtr <T6>
|
||
|
move.l a2,HeaderInfoPtr(a0) ; initialize the HeaderInfoPtr <T6>
|
||
|
|
||
|
move.l d1,CheckSumPtr(a0) ; initialize CheckSumPtr <T6>
|
||
|
move.l d2,DataStartPtr(a0) ; initialize DataStartPtr |
|
||
|
move.l d3,DataEndPtr(a0) ; initialize DataEndPtr v
|
||
|
|
||
|
movea.w (a3)+,a4 ; get the icon/name ptr
|
||
|
adda.l a3,a4 ; make it absolute
|
||
|
move.l a4,MediaIconPtr(a0) ; initialize the icon ptr
|
||
|
movea.w (a3)+,a4 ; get the icon/name ptr
|
||
|
adda.l a3,a4 ; make it absolute
|
||
|
move.l a4,DriveIconPtr(a0) ; initialize the icon ptr
|
||
|
movea.w (a3)+,a4 ; get the icon/name ptr
|
||
|
adda.l a3,a4 ; make it absolute
|
||
|
move.l a4,WhereStringPtr(a0) ; initialize the name ptr
|
||
|
|
||
|
move.l (a3)+,DriveInfo(a0) ; initialize DriveInfo
|
||
|
move.w (a3)+,Flags(a0) ; initialize flags, DiskInPlaceInit
|
||
|
move.b #%01010101,InsertedStatus(a0) ; initialize inserted status to bouncing ^
|
||
|
sub.l d1,d3 ; calculate ram disk size |
|
||
|
move.l d3,RamDiskSize(a0) ; store it in globals <T6>
|
||
|
|
||
|
addq.w #1,qType(a0) ; use long drive size format
|
||
|
addq.w #1,Installed(a0) ; mark the drive as installed
|
||
|
move.l d7,d0 ; get disk drive number, and refNum
|
||
|
swap d0 ; move to high word, refNum to low word
|
||
|
move.l a0,a3 ; make a copy of ptr to info
|
||
|
_AddDrive ; add the drive to the drive queue
|
||
|
|
||
|
move.l d1,a0 ; get ptr to base of Edisk data
|
||
|
move.l d3,d1 ; get RamDiskSize
|
||
|
moveq.l #DisableEDiskWrites,d0 ; always disable writes at startup
|
||
|
bsr.w HWDependent ; disable writing to the EDisk
|
||
|
|
||
|
@Done addq.w #1,d7 ; update drive number
|
||
|
adda.w #InitEntrySize,a6 ; point to next drive init entry
|
||
|
rts ; EDisk drive is installed
|
||
|
title 'EDisk Driver - Check for ROM Disk'
|
||
|
|
||
|
;_______________________________________________________________________
|
||
|
;
|
||
|
; Routine: CheckForRomDisk
|
||
|
; Inputs: A2 - HeaderInfoPtr
|
||
|
; D7.hi - EDisk Driver RefNum
|
||
|
; Outputs: D0 - zero if valid ROM disk header, else non-zero
|
||
|
; ccr.z - bne if invalid header
|
||
|
; Destroys: D0, D1, A0, A3, A4
|
||
|
; Calls: none
|
||
|
; Called by: EDiskOpen
|
||
|
;
|
||
|
; Function: Checks the EDisk header to see if it exists (no bus error),
|
||
|
; and has a valid signature. If it is valid, compares it
|
||
|
; against all other ROM Disks found, and if it's header block
|
||
|
; is not identical to any other ROM Disk (in case address
|
||
|
; wrap around causes repeated images), returns a result
|
||
|
; indicating that it should be created.
|
||
|
;
|
||
|
;_______________________________________________________________________
|
||
|
|
||
|
with EDiskHeader
|
||
|
CheckForRomDisk
|
||
|
move.w sr,-(sp) ; save old interrupt mask
|
||
|
ori.w #HiIntMask,sr ; disable interrupts (stealing BusErrVct)
|
||
|
move.l BusErrVct,-(sp) ; save old bus error vector
|
||
|
lea @NotFound,a0 ; new handler address
|
||
|
move.l a0,BusErrVct ; setup bus error handler
|
||
|
movea.l sp,a4 ; mark the stack
|
||
|
|
||
|
lea HeaderTemplate,a3 ; point to expected values
|
||
|
lea HdrBlockSize(a2),a0 ; point to header data
|
||
|
moveq.l #(HdrDeviceSize-HdrBlockSize)/4-1,d0 ; loop counter
|
||
|
@SigCmpLoop
|
||
|
cmpm.l (a0)+,(a3)+ ; compare the values
|
||
|
dbne d0,@SigCmpLoop ; compare the blocks
|
||
|
@NotFound
|
||
|
movea.l a4,sp ; pop stack in case of bus error
|
||
|
move.l (sp)+,BusErrVct ; restore bus error vector
|
||
|
move.w (sp)+,sr ; restore interrupt mask
|
||
|
addq.w #1,d0 ; see if we had a match
|
||
|
bne.s @Done ; exit if not
|
||
|
|
||
|
; valid header found, now let's see if it's unique.
|
||
|
|
||
|
move.l d7,d1 ; get driver ref num
|
||
|
swap d1 ; d1.low := driver ref num
|
||
|
lea DrvQHdr+QHead-QLink,a0 ; point to the drive queue head
|
||
|
@CheckNeXTDrive
|
||
|
move.l QLink(a0),d0 ; check next drive queue element
|
||
|
beq.s @Done ; if not found, it's unique (d0=0)
|
||
|
movea.l d0,a0 ; a0 := drive queue element
|
||
|
cmp.w dQRefNum(a0),d1 ; is this one of ours
|
||
|
bne.s @CheckNeXTDrive ; if not, check the NeXT one
|
||
|
cmpi.b #romDiskType,\ ; it's one of ours
|
||
|
DriveInfo+3(a0) ; is it a ROM disk
|
||
|
bne.s @CheckNeXTDrive ; if not, check the NeXT one
|
||
|
|
||
|
|
||
|
moveq.l #EDiskHeaderSize/4-1,d0 ; compare the entire header
|
||
|
movea.l a2,a3 ; point to our header
|
||
|
movea.l HeaderInfoPtr(a0),a4 ; point to existing drive's header
|
||
|
@HdrCmpLoop
|
||
|
cmpm.l (a3)+,(a4)+ ; compare the values
|
||
|
dbne d0,@HdrCmpLoop ; compare the blocks
|
||
|
bne.s @CheckNeXTDrive ; if not the same, check the NeXT one
|
||
|
|
||
|
@Done tst.l d0 ; set ccr based on D0
|
||
|
rts ; all done
|
||
|
endwith
|
||
|
title 'EDisk Driver - Close processing'
|
||
|
|
||
|
;_______________________________________________________________________
|
||
|
;
|
||
|
; Routine: EDiskClose
|
||
|
; Inputs: A0 - pointer to I/O ParamBlock
|
||
|
; A1 - pointer to Device Control Entry (DCE)
|
||
|
; Outputs: D0 - Result Code (closErr)
|
||
|
; Destroys:
|
||
|
; Calls: none
|
||
|
; Called by: Device Manager
|
||
|
;
|
||
|
; Function: Driver shutdown routine
|
||
|
;
|
||
|
;_______________________________________________________________________
|
||
|
|
||
|
EDiskClose ; all regs saved by Device Manager
|
||
|
moveq.l #closErr,d0 ; return Close Error status
|
||
|
rts ; not closable at present
|
||
|
title 'EDisk Driver - Read / Write processing'
|
||
|
|
||
|
;_______________________________________________________________________
|
||
|
;
|
||
|
; Routine: EDiskPrime
|
||
|
; Inputs: A0 - pointer to I/O ParamBlock
|
||
|
; A1 - pointer to Device Control Entry (DCE)
|
||
|
; Outputs: D0 - Result Code
|
||
|
; Destroys:
|
||
|
; Calls: IODone
|
||
|
; Called by: Device Manager
|
||
|
;
|
||
|
; Function: Driver Read/Write routines
|
||
|
;
|
||
|
;_______________________________________________________________________
|
||
|
|
||
|
EDiskPrime ; all regs saved by Device Manager
|
||
|
;_Debugger
|
||
|
move.w ioTrap(a0),-(sp) ; save trap word to test immediate on exit <1.2>
|
||
|
moveq.l #0,d4 ; d4 := bytes transferred
|
||
|
movem.l a0/a1/d4,-(sp) ; save iopb, dce. allocate scratch longword
|
||
|
bsr.w FindDQE ; Find the drive queue element
|
||
|
bne.w @PrimeAbort ; return with error if not found or offLine <H1>
|
||
|
|
||
|
; check buffer paramaters
|
||
|
|
||
|
moveq.l #ParamErr,d0 ; assume parameter error
|
||
|
move.l ioByteCount(a0),d1 ; d1 := byte count
|
||
|
beq @PrimeAbort ; if byte count is zero <H1>
|
||
|
move.l dCtlPosition(a1),d2 ; d2 := starting byte offset
|
||
|
movem.l CheckSumPtr(a3),a4/a5/a6; get checksum/start/end pointers
|
||
|
adda.l d2,a5 ; a5 := RAM disk start addr
|
||
|
suba.l a5,a6 ; a6 := max byte count allowed
|
||
|
cmpa.l d1,a6 ; check for out of bounds
|
||
|
blt @PrimeAbort ; read past end of disk <H1>
|
||
|
|
||
|
; check alignment and direction
|
||
|
|
||
|
move.l d1,d7 ; get byte count
|
||
|
or.l d2,d7 ; check offset and byte count
|
||
|
andi.w #$01FF,d7 ; for multiples of block size (512)
|
||
|
bne @PrimeAbort ; if request not block aligned <H1>
|
||
|
move.l ioBuffer(a0),d6 ; d6 := buffer addr
|
||
|
moveq.l #rdVerify,d7 ; prepare to test for read verify
|
||
|
and.w IOPosMode(a0),d7 ; test for verify mode
|
||
|
sne d7 ; d7 := $FF if read verify
|
||
|
neg.b d7 ; d7 := 0 if read, 1 if read verify
|
||
|
move.l d6,d0 ; get destination addr in d0 <T2>
|
||
|
_StripAddress ; clear upper byte if necessary <T2>
|
||
|
cmpi.b #aWrCmd,ioTrap+1(a0) ; check for write cmd
|
||
|
movea.l a5,a0 ; a0 := source address
|
||
|
movea.l d0,a1 ; a1 := clean dest address <T2>
|
||
|
bne.s @paramsOK ; if not write, continue setting up for I/O
|
||
|
|
||
|
; check write params
|
||
|
|
||
|
moveq.l #2,d7 ; d7 := 2 if write
|
||
|
moveq.l #wPrErr,d0 ; assume write protect error
|
||
|
tst.b WriteProtected(a3) ; can we write to this disk?
|
||
|
bmi.s @PrimeAbort ; return with error if write protected <H1>
|
||
|
|
||
|
; d1 := byte count
|
||
|
; a0 := source address
|
||
|
; a1 := clean dest address
|
||
|
movem.l a0/d1,-(sp) ; save size, length for disabling the disk
|
||
|
moveq.l #EnableEDiskWrites,d0 ; hardware dependent function code
|
||
|
bsr.w HWDependent ; allow writing to the EDisk
|
||
|
|
||
|
exg a0,a1 ; swap source and dest if write
|
||
|
|
||
|
; select data transfer routine
|
||
|
|
||
|
@paramsOK
|
||
|
roxr.b #1,d6 ; ccr.x := ioBuffer is odd
|
||
|
addx.b d7,d7 ; shift result into d7
|
||
|
move.l a4,d6 ; prepare to test for checksumming
|
||
|
subq.l #1,d6 ; ccr.x := checksumming is disabled
|
||
|
roxl.w #2,d7 ; shift result into d7, and mult by 2 for index
|
||
|
lsr.l #9-2,d2 ; compute index into checksum table
|
||
|
adda.l d2,a4 ; a4 := pointer to checksum for first block
|
||
|
lea @DispatchTable,a5 ; point to the dispatch table
|
||
|
adda.w (a5,d7.w),a5 ; a5 := pointer to the routine
|
||
|
jsr PrimePatch(a2) ; allow patching here
|
||
|
move.l #512,d3 ; d3 := constant 512
|
||
|
|
||
|
; transfer the data a block at a time (usually)
|
||
|
|
||
|
@BlockLoop
|
||
|
moveq.l #0,d5 ; d5 := checksum, initialize to zero
|
||
|
moveq.l #(512/4)-1,d2 ; d2 := loop count for 1 block (4 bytes per loop)
|
||
|
jmp (a5) ; dispatch to the routine
|
||
|
@BlockDone
|
||
|
add.l d3,d4 ; update num done (512 more bytes done)
|
||
|
sub.l d3,d1 ; decrement bytecount
|
||
|
bhi.s @BlockLoop ; do next block if any blocks left
|
||
|
|
||
|
; transfer complete
|
||
|
|
||
|
@PrimeDone
|
||
|
moveq.l #noErr,d0 ; success
|
||
|
@PrimeErr
|
||
|
btst #EDiskProtect,Flags(a3) ; check if EDisk is protected
|
||
|
bne.s @ediskProtected ; IF EDisk is not protected THEN
|
||
|
move.l d0,d2 ; save result code in d2
|
||
|
movem.l (sp)+,a0/d1 ; restore size, length for disable code
|
||
|
moveq.l #DisableEDiskWrites,d0 ; hardware dependent function code
|
||
|
bsr.w HWDependent ; disable writing to the EDisk
|
||
|
move.l d2,d0 ; restore d0 with result code
|
||
|
@ediskProtected ; ENDIF
|
||
|
@PrimeAbort
|
||
|
movem.l (sp)+,a0/a1/d1 ; restore iopb, dce. pop scratch longword <2>
|
||
|
move.l d4,ioNumDone(a0) ; return number of bytes transferred
|
||
|
add.l d4,dCtlPosition(a1) ; update position pointer
|
||
|
bra.w EDiskDone ; return with error
|
||
|
|
||
|
|
||
|
; EDisk <-> Buffer, even or odd aligned, no checksumming (all blocks at once)
|
||
|
|
||
|
@ReadWrite
|
||
|
move.l d1,d0 ; get the byte count
|
||
|
_BlockMove ; move the data
|
||
|
move.l d1,d4 ; indicate all bytes moved
|
||
|
bra.s @PrimeDone ; return with success
|
||
|
title 'EDisk Driver - Read processing'
|
||
|
|
||
|
|
||
|
; EDisk -> Buffer, with checksumming, buffer even aligned (one block at a time)
|
||
|
|
||
|
@ReadEvenXsum
|
||
|
moveq.l #(512/8)-1,d2 ; d2 := loop count for 1 block (8 bytes per loop)
|
||
|
@ReadEvenLoop
|
||
|
move.l (a0)+,d7 ; fetch the source
|
||
|
add.l d5,d5 ; rotate the checksum
|
||
|
addx.l d7,d5 ; add source to the checksum
|
||
|
move.l d7,(a1)+ ; write it to the destination
|
||
|
move.l (a0)+,d7 ; fetch the source
|
||
|
add.l d5,d5 ; rotate the checksum
|
||
|
addx.l d7,d5 ; add source to the checksum
|
||
|
move.l d7,(a1)+ ; write it to the destination
|
||
|
dbra d2,@ReadEvenLoop ; loop through the entire block
|
||
|
@ReadDone
|
||
|
cmp.l (a4)+,d5 ; check the checksum
|
||
|
beq.s @BlockDone ; done with this block
|
||
|
moveq.l #badDCksum,d0 ; indicate data checksum error
|
||
|
bra.s @PrimeErr ; return with checksum error
|
||
|
|
||
|
|
||
|
|
||
|
; EDisk -> Buffer, with checksumming, buffer odd aligned (one block at a time)
|
||
|
|
||
|
@ReadOddXsum
|
||
|
subq.l #3,a1 ; back up the dest ptr, make it even
|
||
|
move.l (a1),d7 ; d7 := x x x A
|
||
|
addq.l #*+2-@ReadOddXsum,a5 ; after first block skip the code above
|
||
|
@ReadOddLoop
|
||
|
move.l (a0)+,d6 ; d6 := A B C D
|
||
|
add.l d5,d5 ; rotate the checksum
|
||
|
addx.l d6,d5 ; add source to the checksum
|
||
|
rol.l #8,d6 ; d6 := B C D A
|
||
|
move.b d6,d7 ; d7 := x x x A
|
||
|
move.l d7,(a1)+ ; write it to the destination
|
||
|
move.l d6,d7 ; d7 := B C D A
|
||
|
dbra d2,@ReadOddLoop ; loop through the entire block
|
||
|
move.b 3(a1),d7 ; d7 := B C D x
|
||
|
move.l d7,(a1) ; update last long word
|
||
|
bra.s @ReadDone ; done with this block
|
||
|
title 'EDisk Driver - Verify processing'
|
||
|
|
||
|
|
||
|
; Read Verify calls with and without checksumming
|
||
|
; buffer even aligned (one block at a time)
|
||
|
|
||
|
@VerifyEven
|
||
|
movea.l sp,a4 ; if no checksum, point to stack
|
||
|
@VerifyEvenXsum
|
||
|
@VerifyEvenLoop
|
||
|
move.l (a0)+,d7 ; fetch the source
|
||
|
add.l d5,d5 ; rotate the checksum
|
||
|
addx.l d7,d5 ; add source to the checksum
|
||
|
cmp.l (a1)+,d7 ; compare the buffers
|
||
|
dbne d2,@VerifyEvenLoop ; loop through the entire block
|
||
|
beq.s @VerifyGood ; if blocks are equal
|
||
|
@VerifyError
|
||
|
moveq.l #dataVerErr,d0 ; indicate verify failed
|
||
|
bra.s @PrimeErr ; return with error
|
||
|
|
||
|
|
||
|
|
||
|
; Read Verify calls with and without checksumming
|
||
|
; buffer odd aligned (one block at a time)
|
||
|
|
||
|
@VerifyOddXsum
|
||
|
lea @VerifyOddLoop,a5 ; skip the following code after the first time
|
||
|
@VerifyOddSetup
|
||
|
subq.l #1,a1 ; back up 1 byte to align
|
||
|
move.l (a1)+,d6 ; d6 := x A B C
|
||
|
rol.l #8,d6 ; d6 := A B C x
|
||
|
jmp (a5) ; start the loop
|
||
|
@VerifyOdd
|
||
|
addq.l #4,a5 ; resume after the next instruction
|
||
|
bra.s @VerifyOddSetup ; setup for the odd aligned compare
|
||
|
movea.l sp,a4 ; if no checksum, point to stack
|
||
|
@VerifyOddLoop
|
||
|
move.l d6,d7 ; d7 := A B C x
|
||
|
move.l (a1)+,d6 ; d6 := D E F G
|
||
|
rol.l #8,d6 ; d6 := E F G D
|
||
|
move.b d6,d7 ; d7 := A B C D
|
||
|
add.l d5,d5 ; rotate the checksum
|
||
|
addx.l d7,d5 ; add source to the checksum
|
||
|
cmp.l (a0)+,d7 ; compare the buffers
|
||
|
dbne d2,@VerifyOddLoop ; loop through the entire block
|
||
|
bne.s @VerifyError ; if not a match
|
||
|
@VerifyGood
|
||
|
move.l d5,(sp) ; force compare when not checksumming
|
||
|
bra.s @ReadDone ; check the checksum
|
||
|
title 'EDisk Driver - Write processing'
|
||
|
|
||
|
|
||
|
; EDisk <- Buffer, with checksumming, buffer even aligned (one block at a time)
|
||
|
|
||
|
@WriteEvenXsum
|
||
|
moveq.l #(512/8)-1,d2 ; d2 := loop count for 1 block (8 bytes per loop)
|
||
|
@WriteEvenLoop
|
||
|
move.l (a0)+,d7 ; fetch the source
|
||
|
add.l d5,d5 ; rotate the checksum
|
||
|
addx.l d7,d5 ; add source to the checksum
|
||
|
move.l d7,(a1)+ ; write it to the destination
|
||
|
move.l (a0)+,d7 ; fetch the source
|
||
|
add.l d5,d5 ; rotate the checksum
|
||
|
addx.l d7,d5 ; add source to the checksum
|
||
|
move.l d7,(a1)+ ; write it to the destination
|
||
|
dbra d2,@WriteEvenLoop ; loop through the entire block
|
||
|
@WriteDone
|
||
|
move.l d5,(a4)+ ; write out the checksum
|
||
|
bra.w @BlockDone ; done with this block
|
||
|
|
||
|
|
||
|
|
||
|
; EDisk <- Buffer, with checksumming, buffer odd aligned (one block at a time)
|
||
|
|
||
|
@WriteOddXsum
|
||
|
subq.l #1,a0 ; back up the source ptr, make it even
|
||
|
move.l (a0)+,d7 ; d7 := x A B C
|
||
|
rol.l #8,d7 ; d7 := A B C x
|
||
|
addq.l #*+2-@WriteOddXsum,a5 ; after first block skip the code above
|
||
|
@WriteOddLoop
|
||
|
move.l (a0)+,d6 ; d6 := D E F G
|
||
|
rol.l #8,d6 ; d6 := E F G D
|
||
|
move.b d6,d7 ; d7 := A B C D
|
||
|
add.l d5,d5 ; rotate the checksum
|
||
|
addx.l d7,d5 ; add source to the checksum
|
||
|
move.l d7,(a1)+ ; write it to the destination
|
||
|
move.l d6,d7 ; d7 := E F G D
|
||
|
dbra d2,@WriteOddLoop ; loop through the entire block
|
||
|
bra.s @WriteDone ; done with this block
|
||
|
|
||
|
|
||
|
|
||
|
; Table to dispatch to proper routine
|
||
|
|
||
|
@DispatchTable
|
||
|
dc.w @ReadEvenXsum-@DispatchTable ; 0 0 0 0 - read, even, xsum enabled
|
||
|
dc.w @ReadWrite-@DispatchTable ; 0 0 0 1 - read, even, xsum disabled
|
||
|
dc.w @ReadOddXsum-@DispatchTable ; 0 0 1 0 - read, odd, xsum enabled
|
||
|
dc.w @ReadWrite-@DispatchTable ; 0 0 1 1 - read, odd, xsum disabled
|
||
|
dc.w @VerifyEvenXsum-@DispatchTable ; 0 1 0 0 - verify, even, xsum enabled
|
||
|
dc.w @VerifyEven-@DispatchTable ; 0 1 0 1 - verify, even, xsum disabled
|
||
|
dc.w @VerifyOddXsum-@DispatchTable ; 0 1 1 0 - verify, odd, xsum enabled
|
||
|
dc.w @VerifyOdd-@DispatchTable ; 0 1 1 1 - verify, odd, xsum disabled
|
||
|
dc.w @WriteEvenXsum-@DispatchTable ; 1 0 0 0 - write, even, xsum enabled
|
||
|
dc.w @ReadWrite-@DispatchTable ; 1 0 0 1 - write, even, xsum disabled
|
||
|
dc.w @WriteOddXsum-@DispatchTable ; 1 0 1 0 - write, odd, xsum enabled
|
||
|
dc.w @ReadWrite-@DispatchTable ; 1 0 1 1 - write, odd, xsum disabled
|
||
|
title 'EDisk Driver - Control / Status processing'
|
||
|
|
||
|
;_______________________________________________________________________
|
||
|
;
|
||
|
; Routine: EDiskControl / EDiskStatus / KillIO
|
||
|
; Inputs: A0 - pointer to I/O ParamBlock
|
||
|
; A1 - pointer to Device Control Entry (DCE)
|
||
|
; Outputs: D0 - Result Code
|
||
|
; Destroys:
|
||
|
; Calls: FindDQE, EDiskDone
|
||
|
; Called by: Device Manager
|
||
|
;
|
||
|
; Function: Driver Control and Status routines
|
||
|
;
|
||
|
;_______________________________________________________________________
|
||
|
|
||
|
|
||
|
EDiskControl ; all regs saved by Device Manager
|
||
|
lea ControlDecode,a2 ; offset of decode table
|
||
|
bra.s HandleControlStatus ; join common code
|
||
|
|
||
|
|
||
|
EDiskStatus ; all regs saved by Device Manager
|
||
|
lea StatusDecode,a2 ; offset of decode table
|
||
|
* bra.s HandleControlStatus ; join common code (fall into it)
|
||
|
|
||
|
HandleControlStatus
|
||
|
move.w ioTrap(a0),-(sp) ; save trap word to test immediate on exit <1.2>
|
||
|
pea EDiskDone ; return through EDiskDone
|
||
|
move.w csCode(a0),d1 ; get the control/status code
|
||
|
@search move.l (a2)+,d0 ; get table entry
|
||
|
bmi.s @exit ; exit with error if not in list
|
||
|
cmp.w d0,d1 ; is it a match
|
||
|
bne.s @search ; keep looking until found
|
||
|
|
||
|
swap d0 ; get offset of routine
|
||
|
pea (a2,d0.w) ; push address of the routine
|
||
|
bra.w FindDQE ; find the DQE before calling routine
|
||
|
|
||
|
@exit movea.l dCtlStorage(a1),a2 ; a2 := pointer to EDiskVars
|
||
|
addq.l #4,sp ; <SM4>
|
||
|
bra.w EDiskDone2 ; return through EDiskDone2 <SM4>
|
||
|
|
||
|
|
||
|
ctlKillIO
|
||
|
move.w #immed,4(sp) ; make saved ioTrap an immediate call <1.2>
|
||
|
moveq.l #ControlErr,d0 ; we don't support KillIO, return an error <1.2>
|
||
|
rts ; return through EDiskDone
|
||
|
title 'EDisk Driver - Control / Status processing - Eject'
|
||
|
|
||
|
|
||
|
ctlEject
|
||
|
move.l d1,d0 ; get found status, ignore offline
|
||
|
bne.s @EjectErr ; return error if not found
|
||
|
bclr.b #MountedFlag,Flags(a3) ; mark it as not mounted
|
||
|
move.b DiskInPlace(a3),d0 ; see if any disk
|
||
|
ble.s @EjectDone ; if no disk, just ignore it
|
||
|
|
||
|
subq.b #8,d0 ; see if ejectable
|
||
|
beq.s @EjectDone ; if not ejectable, just ignore it
|
||
|
|
||
|
; if disk in place was $48 (non-ejectable, but call driver anyway) we will force a
|
||
|
; disk in place event to be posted by the polling task, to re-mount the volume.
|
||
|
|
||
|
moveq.l #EjectEDisk,d0 ; hardware dependent function code
|
||
|
bsr.w HWDependent ; start the eject, update DiskInPlace
|
||
|
@EjectDone
|
||
|
moveq.l #noErr,d0 ; return with success
|
||
|
@EjectErr
|
||
|
rts ; all done
|
||
|
title 'EDisk Driver - Control / Status processing - Format'
|
||
|
|
||
|
|
||
|
ctlFormat
|
||
|
bne @exit ; return with error if no drive or offline
|
||
|
|
||
|
; d1 := byte count
|
||
|
; a0 := source address
|
||
|
; a3 := ptr to drive queue element
|
||
|
move.l CheckSumPtr(a3),a0 ; put base addr of Edisk in a0
|
||
|
tst.l a0 ; check for no checksums
|
||
|
bne.s @checksumsOn ; IF no checksums THEN
|
||
|
move.l DataStartPtr(a3),a0 ; get real start of disk
|
||
|
@checksumsOn ; ENDIF
|
||
|
move.l DataEndPtr(a3),d1 ; put end of edisk in d1
|
||
|
sub.l a0,d1 ; get length in d1
|
||
|
movem.l a0/d1,-(sp) ; save size, length for enabling the disk
|
||
|
|
||
|
moveq.l #EnableEDiskWrites,d0 ; hardware dependent function code
|
||
|
bsr.w HWDependent ; enable writing to the EDisk
|
||
|
moveq.l #paramErr,d0 ; assume parameter error
|
||
|
move.w (a4),d1 ; get the format kind parameter
|
||
|
subq.w #1,d1 ; only allow 0 or 1
|
||
|
bls.s @CheckWrProt ; if in range, continue
|
||
|
|
||
|
addq.w #2,d1 ; -1 is a special case (destroys signature too)
|
||
|
bne.s @done ; if not -1, 0, or 1, return paramErr
|
||
|
cmpi.b #ramDiskType,DriveInfo+3(a3) ; see if it is a ram disk
|
||
|
bne.s @done ; if not, return the paramErr
|
||
|
|
||
|
lea DrvQHdr,a1 ; get the queue header
|
||
|
movea.l a3,a0 ; get the Ram Disk drive queue element
|
||
|
_DeQueue ; remove it from the drive queue
|
||
|
|
||
|
moveq.l #0,d6 ; fake RAM test passed
|
||
|
bra.s @SkipTest ; skip the test, and just clear it
|
||
|
|
||
|
@CheckWrProt
|
||
|
moveq.l #wPrErr,d0 ; assume write protect error
|
||
|
tst.b WriteProtected(a3) ; can we write to this disk?
|
||
|
bmi.s @done ; return write protect error if not
|
||
|
bsr.w CreateEDiskHeader ; write out a signature
|
||
|
|
||
|
moveq.l #0,d6 ; fake RAM test passed
|
||
|
|
||
|
@SkipTest
|
||
|
|
||
|
movem.l CheckSumPtr(a3),a0/a1/a4; get the checksum/start/end pointers
|
||
|
move.l a0,d2 ; see if has checksums, assume no error.
|
||
|
bne.s @ClearDisk ; if has checksums, clear them
|
||
|
movea.l a1,a0 ; otherwise, clear data as checksums
|
||
|
@ClearDisk
|
||
|
moveq.l #0,d0 ; clear to zero, assume success
|
||
|
tst.l d6 ; see if test passed <1.3>
|
||
|
beq.s @FormatStart ; if passed, initialize RAM and checksums
|
||
|
moveq.l #Fmt1Err,d0 ; indicate that format failed
|
||
|
bra.s @done ; all done
|
||
|
|
||
|
@NextBlock
|
||
|
moveq.l #(512/4)-1,d1 ; inner loop counter
|
||
|
@BlockLoop
|
||
|
move.l d0,(a1)+ ; clear a longword at a time
|
||
|
dbra d1,@BlockLoop ; clear the whole block
|
||
|
move.l d0,(a0)+ ; clear the checksum too
|
||
|
@FormatStart
|
||
|
cmpa.l a1,a4 ; see if all blocks cleared
|
||
|
bhi.s @NextBlock ; loop through all of the blocks
|
||
|
@done move.l d0,d2 ; save error code
|
||
|
IF newEdiskProt THEN
|
||
|
; d1 := byte count
|
||
|
; a0 := source address
|
||
|
; a3 := ptr to drive queue element
|
||
|
movem.l (sp)+,a0/d1 ; restore size, length for disabling the disk
|
||
|
ENDIF
|
||
|
moveq.l #DisableEDiskWrites,d0 ; hardware dependent function code
|
||
|
bsr.w HWDependent ; disable writing to the EDisk
|
||
|
move.l d2,d0 ; restore error code
|
||
|
@exit rts ; all done
|
||
|
title 'EDisk Driver - Control / Status processing - Verify'
|
||
|
|
||
|
|
||
|
; Verify that each block on the disk can be read
|
||
|
|
||
|
ctlVerify
|
||
|
bne.s @done ; return with error if no drive or offline
|
||
|
movem.l CheckSumPtr(a3),a0/a1/a4; get the checksum/start/end pointers
|
||
|
move.l a0,d0 ; see if has checksums, assume no error.
|
||
|
beq.s @done ; if has checksums, check them
|
||
|
|
||
|
moveq.l #noErr,d0 ; assume success, init checksum
|
||
|
@NextBlock
|
||
|
cmpa.l a1,a4 ; see if all blocks checked
|
||
|
bls.s @done ; exit when all blocks checked
|
||
|
|
||
|
moveq.l #(512/4)-1,d1 ; inner loop counter
|
||
|
@BlockLoop
|
||
|
move.l (a1)+,d3 ; fetch a longword at a time
|
||
|
add.l d0,d0 ; rotate the checksum
|
||
|
addx.l d3,d0 ; add in the data word
|
||
|
dbra d1,@BlockLoop ; check the whole block
|
||
|
|
||
|
sub.l (a0)+,d0 ; check the checksum
|
||
|
beq.s @NextBlock ; if checksum ok, check the next block
|
||
|
|
||
|
@error moveq.l #verErr,d0 ; return verify error.
|
||
|
@done rts ; all done
|
||
|
title 'EDisk Driver - Control / Status processing - FmtLst/DrvSts/DriveInfo'
|
||
|
|
||
|
|
||
|
; Return the list of sizes that can be formatted
|
||
|
|
||
|
statFmtLst
|
||
|
bne.s @done ; return with error if no drive or offline
|
||
|
moveq.l #paramErr,d0 ; assume parameter error
|
||
|
tst.w (a4) ; test number of entries in buffer
|
||
|
ble.s @Done ; if less than 1 entry, report error
|
||
|
move.w #1,(a4)+ ; indicate 1 entry returned
|
||
|
movea.l (a4),a4 ; get the buffer pointer
|
||
|
move.l dQDrvSz(a3),d0 ; get the swapped drive size
|
||
|
swap d0 ; un-swap it
|
||
|
move.l d0,(a4)+ ; return the drive size
|
||
|
move.l #$40000000,(a4) ; current disk has this format
|
||
|
moveq.l #noErr,d0 ; indicate success
|
||
|
@Done rts ; all done
|
||
|
|
||
|
|
||
|
|
||
|
; Return the drive status and drive queue element
|
||
|
|
||
|
statDrvSts
|
||
|
move.l d1,d0 ; get found status, ignore offline
|
||
|
bne.s @Done ; return error if not found
|
||
|
movea.l a4,a1 ; dest address is csParam area
|
||
|
clr.w (a1)+ ; return zero for track
|
||
|
lea WriteProtected(a3),a0 ; start copy with write protected flag
|
||
|
moveq.l #(DQE-WriteProtected)+dQDrvSz2+2,d0 ; number of bytes to copy
|
||
|
_BlockMove ; copy the drive info, and return noErr
|
||
|
@Done rts ; all done
|
||
|
|
||
|
|
||
|
; Return the RAM disk size
|
||
|
|
||
|
statDrvSize
|
||
|
move.l RamDiskSize(a3),(a4) ; return the RAM disk size, in bytes <T6>
|
||
|
rts ; all done <1.6>
|
||
|
|
||
|
|
||
|
; Return the drive type and info flags.
|
||
|
|
||
|
ctlDriveInfo
|
||
|
move.l d1,d0 ; get found status, ignore offline
|
||
|
bne.s @Done ; return error if not found
|
||
|
move.l DriveInfo(a3),(a4) ; return the drive info
|
||
|
@Done rts ; all done
|
||
|
title 'EDisk Driver - Control / Status processing - Drive/Media Icon'
|
||
|
|
||
|
|
||
|
; Return the Icon representing the location of the disk drive
|
||
|
|
||
|
ctlDriveIcon
|
||
|
movea.l DriveIconPtr(a3),a0 ; get drive icon ptr, setup source address
|
||
|
bra.s IconCommon ; join common icon code
|
||
|
|
||
|
|
||
|
; Return the Icon representing the disk media
|
||
|
|
||
|
ctlMediaIcon
|
||
|
movea.l MediaIconPtr(a3),a0 ; get media icon ptr, setup source address
|
||
|
IconCommon
|
||
|
move.l d1,d0 ; get found status, ignore offline
|
||
|
bne.s @Done ; return error if not found
|
||
|
moveq.l #ControlErr,d0 ; return control error if no icon found
|
||
|
move.l a0,d1 ; see if icon exists
|
||
|
beq.s @Done ; if no icon exists, return with error
|
||
|
|
||
|
; copy the icon into the buffer
|
||
|
|
||
|
lea IconBuffer(a2),a1 ; get buffer address (dest address)
|
||
|
move.l a1,(a4) ; return buffer pointer
|
||
|
move.l #IconAndMaskSize,d0 ; setup byte count for icon and mask
|
||
|
_BlockMove ; copy the icon into the buffer
|
||
|
|
||
|
; copy the "Where String" into the buffer
|
||
|
|
||
|
lea WhereStringBuff(a2),a1 ; point past icon, to "where string"
|
||
|
clr.b (a1) ; string length of zero, in case no string found
|
||
|
move.l WhereStringPtr(a3),d1 ; get where string pointer
|
||
|
beq.s @Done ; if no string, don't copy it
|
||
|
movea.l d1,a0 ; setup source address
|
||
|
moveq.l #1,d0 ; zero extend / adjust count
|
||
|
add.b (a0),d0 ; fetch the string length, count the length byte too
|
||
|
cmpi.w #WhereStringSize,d0 ; check to see if too long
|
||
|
bls.s @CopyString ; if in range just copy it
|
||
|
moveq.l #WhereStringSize,d0 ; otherwise truncate to max size
|
||
|
@CopyString
|
||
|
_BlockMove ; copy the string into the buffer
|
||
|
|
||
|
@Done rts ; all done (d0 is noErr from _BlockMove)
|
||
|
title 'EDisk Driver - FindDQE - Find Drive Queue Element'
|
||
|
|
||
|
;_______________________________________________________________________
|
||
|
;
|
||
|
; Routine: FindDQE
|
||
|
; Inputs: A0 - pointer to I/O ParamBlock
|
||
|
; A1 - pointer to Device Control Entry (DCE)
|
||
|
; Outputs: D0 - Drive Found and OnLine Status (noErr, NSDrvErr or offLinErr)
|
||
|
; D1 - Drive Found Status (noErr or NSDrvErr)
|
||
|
; A2 - pointer to EDiskVars
|
||
|
; A3 - pointer to DriveQueueElement for specified drive
|
||
|
; A4 - pointer to csParam field of I/O ParamBlock
|
||
|
; Destroys: D2, D3
|
||
|
; Calls: none
|
||
|
; Called by: Prime, Control, Status routines
|
||
|
;
|
||
|
; Function: Searches the drive queue for the Drive Queue Element
|
||
|
; associated with this Driver Request.
|
||
|
;
|
||
|
;_______________________________________________________________________
|
||
|
|
||
|
FindDQE ; find the drive queue element
|
||
|
movea.l dCtlStorage(a1),a2 ; a2 := pointer to EDiskVars
|
||
|
addq.b #1,Active(a2) ; request in progress, exclude polling <1.2>
|
||
|
jsr FindDqePatch(a2) ; allow patching here
|
||
|
lea DrvQHdr+QHead-QLink,a3 ; get the drive queue head
|
||
|
move.w IODrvNum(a0),d2 ; d2 := drive number
|
||
|
bpl.s @search ; start searching if drivenum is positive
|
||
|
neg.w d2 ; d2 := abs (IODrvNum)
|
||
|
|
||
|
; search the drive queue for the requested drive
|
||
|
|
||
|
@search
|
||
|
move.l QLink(a3),d3 ; check next drive queue element
|
||
|
beq.s @notFound ; if drive queue is empty
|
||
|
movea.l d3,a3 ; a3 := drive queue element
|
||
|
cmp.w DQDrive(a3),d2 ; check for a match
|
||
|
bne.s @search ; if not our drive
|
||
|
move.w dCtlRefNum(a1),d2 ; d2 := our driver ref number
|
||
|
cmp.w DQRefNum(a3),d2 ; compare to drive queue ref num
|
||
|
bne.s @search ; if not for our driver
|
||
|
|
||
|
moveq.l #noErr,d1 ; indicate drive is found
|
||
|
|
||
|
; now check to see if it is really present (onLine)
|
||
|
|
||
|
tst.b DiskInPlace(a3) ; is there a disk
|
||
|
ble.s @offLine ; return off line error if not
|
||
|
|
||
|
moveq.l #CheckEDiskInserted,d0 ; hardware dependent function code
|
||
|
bsr.s HWDependent ; see if disk is inserted
|
||
|
beq.s @offLine ; if not, return offline error
|
||
|
moveq.l #noErr,d0 ; indicate no disk-in-place
|
||
|
|
||
|
@Done lea csParam(a0),a4 ; point to param area
|
||
|
rts ; return with success (d0 = 0 = noErr)
|
||
|
|
||
|
@offLine
|
||
|
moveq.l #offLinErr,d0 ; indicate no disk-in-place
|
||
|
bra.s @Done ; return with error
|
||
|
|
||
|
|
||
|
@notFound
|
||
|
moveq.l #NSDrvErr,d1 ; indicate no such drive error
|
||
|
moveq.l #NSDrvErr,d0 ; indicate no such drive error
|
||
|
bra.s @Done ; return with error
|
||
|
title 'EDisk Driver - EDiskDone - Command Completion'
|
||
|
|
||
|
;_______________________________________________________________________
|
||
|
;
|
||
|
; Routine: EDiskDone
|
||
|
; Inputs: A2 - pointer to EDiskVars
|
||
|
; D0 - Result Code
|
||
|
; Destroys:
|
||
|
; Calls: IODone
|
||
|
; Called by: Prime, Control, Status routines
|
||
|
;
|
||
|
; Function: Completes request processing, by checking error result code,
|
||
|
; and returns control to the device manager through IODone.
|
||
|
;
|
||
|
;_______________________________________________________________________
|
||
|
|
||
|
EDiskDone
|
||
|
subq.b #1,Active(a2) ; request complete, allow polling <1.2>
|
||
|
EDiskDone2 ; <H6><SM4>
|
||
|
movea.l DCEpointer(a2),a1 ; setup DCE pointer in a1 for JIODone
|
||
|
btst.b #NoQueueBit-8,(sp)+ ; check for immediate request <1.2>
|
||
|
bne.s @immed ; if immediate, don't use jIODone <1.2>
|
||
|
move.l jIODone,-(sp) ; get IODone routine address
|
||
|
@immed ext.l d0 ; test for errors
|
||
|
beq.s @done ; if no error
|
||
|
move.w d0,DskErr ; save last error for file system
|
||
|
@done rts ; all done
|
||
|
title 'EDisk Driver - HWDependent - Hardware Dependent Functions'
|
||
|
|
||
|
;_______________________________________________________________________
|
||
|
;
|
||
|
; Routine: HWDependent
|
||
|
; Inputs: A3 - pointer to DriveQElement for specified drive
|
||
|
; D0 - function selector
|
||
|
; Outputs: none
|
||
|
; Destroys: D0
|
||
|
; Calls: none
|
||
|
; Called by:
|
||
|
;
|
||
|
; Function: Tests or performs a hardware dependent function.
|
||
|
;
|
||
|
;_______________________________________________________________________
|
||
|
|
||
|
HWDependent
|
||
|
move.l HWDepProcPtr(a3),-(sp) ; get the handler address
|
||
|
rts ; jump to it
|
||
|
|
||
|
RAMDiskHandler
|
||
|
move.b @decode(pc,d0.w),d0 ; get the routine offset
|
||
|
jmp @decode(pc,d0.w) ; jump to it
|
||
|
@decode
|
||
|
assert (*-@decode)=CheckEDiskInserted
|
||
|
dc.b @checkInserted-@decode
|
||
|
assert (*-@decode)=CheckEDiskReadOnly
|
||
|
dc.b @checkReadOnly-@decode
|
||
|
assert (*-@decode)=EnableEDiskWrites
|
||
|
dc.b @enableWrites-@decode
|
||
|
assert (*-@decode)=DisableEDiskWrites
|
||
|
dc.b @disableWrites-@decode
|
||
|
assert (*-@decode)=EjectEDisk
|
||
|
dc.b @eject-@decode
|
||
|
align 2
|
||
|
|
||
|
@checkInserted
|
||
|
moveq.l #-1,d0 ; always inserted
|
||
|
rts
|
||
|
@checkReadOnly
|
||
|
moveq.l #0,d0 ; never read only
|
||
|
@enableWrites
|
||
|
movem.l a0-a1/d1,-(sp) ; save registers <T5>
|
||
|
moveq #8,d0 ; _EDiskProtect selector |
|
||
|
move.l CheckSumPtr(a3),a0 ; put base addr of ram disk in a0 v
|
||
|
move.l #0,a1 ; indicate we want to unprotect edisk
|
||
|
_HwPriv ; unprotect the disk
|
||
|
movem.l (sp)+,a0-a1/d1
|
||
|
bclr #EDiskProtect,Flags(a3) ; indicate the disk is not protected
|
||
|
rts
|
||
|
@disableWrites
|
||
|
movem.l a0-a1/d1,-(sp) ; save registers
|
||
|
moveq #8,d0 ; _EDiskProtect selector
|
||
|
move.l CheckSumPtr(a3),a0 ; put base addr of ram disk in a0
|
||
|
move.l #1,a1 ; indicate we want to protect edisk
|
||
|
_HwPriv ; write-protect the disk ^
|
||
|
movem.l (sp)+,a0-a1/d1 ; restore registers |
|
||
|
bset #EDiskProtect,Flags(a3) ; indicate the disk is protected
|
||
|
rts ; <T5>
|
||
|
@eject clr.b DiskInPlace(a3) ; mark it as offline
|
||
|
@done rts
|
||
|
|
||
|
|
||
|
IF newEdiskProt THEN
|
||
|
;—————————————————————————
|
||
|
; PowerPC Edisk Routines
|
||
|
;—————————————————————————
|
||
|
RAMDiskHandlerPPC
|
||
|
move.b @decode(pc,d0.w),d0 ; get the routine offset
|
||
|
jmp @decode(pc,d0.w) ; jump to it
|
||
|
@decode
|
||
|
assert (*-@decode)=CheckEDiskInserted
|
||
|
dc.b @checkInserted-@decode
|
||
|
assert (*-@decode)=CheckEDiskReadOnly
|
||
|
dc.b @checkReadOnly-@decode
|
||
|
assert (*-@decode)=EnableEDiskWrites
|
||
|
dc.b @enableWrites-@decode
|
||
|
assert (*-@decode)=DisableEDiskWrites
|
||
|
dc.b @disableWrites-@decode
|
||
|
assert (*-@decode)=EjectEDisk
|
||
|
dc.b @eject-@decode
|
||
|
align 2
|
||
|
|
||
|
@checkInserted
|
||
|
moveq.l #-1,d0 ; always inserted
|
||
|
rts
|
||
|
@checkReadOnly
|
||
|
moveq.l #0,d0 ; never read only
|
||
|
@enableWrites
|
||
|
; a3 = ptr to driveQElement
|
||
|
; d1 = transfer length
|
||
|
; a0 = transfer base
|
||
|
movem.l a0-a1/d1,-(sp) ; save registers
|
||
|
move.l #$80000008,d0 ; selector for PPC EDiskProtect, "unprotect"
|
||
|
move.l d1,a1 ; put size of xfer in a1
|
||
|
_HwPriv ; unprotect the disk
|
||
|
move.l CheckSumPtr(a3),a0 ; put base of checksums in a0
|
||
|
tst.l a0 ; check if checksums are in use
|
||
|
beq.s @noCksums ; IF using checksums THEN
|
||
|
move.l #$80000008,d0 ; selector for PPC EDiskProtect, "unprotect"
|
||
|
move.l DataStartPtr(a3),a1 ; put end of checksums in a1
|
||
|
suba.l a0,a1 ; leave length of checksum area in a1
|
||
|
_HwPriv ; unprotect the disk
|
||
|
@noCksums ; ENDIF
|
||
|
movem.l (sp)+,a0-a1/d1
|
||
|
bclr #EDiskProtect,Flags(a3) ; indicate the disk is not protected
|
||
|
rts
|
||
|
@disableWrites
|
||
|
movem.l a0-a1/d1,-(sp) ; save registers
|
||
|
move.l #$80010008,d0 ; selector for PPC EDiskProtect, "protect"
|
||
|
move.l d1,a1 ; put size of xfer in a1
|
||
|
_HwPriv ; write-protect the disk
|
||
|
move.l CheckSumPtr(a3),a0 ; put base of checksums in a0
|
||
|
tst.l a0 ; check if checksums are in use
|
||
|
beq.s @noCksumsDis ; IF using checksums THEN
|
||
|
move.l #$80010008,d0 ; selector for PPC EDiskProtect, "protect"
|
||
|
move.l DataStartPtr(a3),a1 ; put end of checksums in a1
|
||
|
suba.l a0,a1 ; leave length of checksum area in a1
|
||
|
_HwPriv ; write-protect the checksums
|
||
|
@noCksumsDis ; ENDIF
|
||
|
movem.l (sp)+,a0-a1/d1 ; restore registers
|
||
|
bset #EDiskProtect,Flags(a3) ; indicate the disk is protected
|
||
|
rts ;
|
||
|
|
||
|
@eject clr.b DiskInPlace(a3) ; mark it as offline
|
||
|
@done rts
|
||
|
|
||
|
ENDIF
|
||
|
|
||
|
ROMDiskHandler
|
||
|
move.b @decode(pc,d0.w),d0 ; get the routine offset
|
||
|
jmp @decode(pc,d0.w) ; jump to it
|
||
|
@decode
|
||
|
assert (*-@decode)=CheckEDiskInserted
|
||
|
dc.b @checkInserted-@decode
|
||
|
assert (*-@decode)=CheckEDiskReadOnly
|
||
|
dc.b @checkReadOnly-@decode
|
||
|
assert (*-@decode)=EnableEDiskWrites
|
||
|
dc.b @enableWrites-@decode
|
||
|
assert (*-@decode)=DisableEDiskWrites
|
||
|
dc.b @disableWrites-@decode
|
||
|
assert (*-@decode)=EjectEDisk
|
||
|
dc.b @eject-@decode
|
||
|
align 2
|
||
|
|
||
|
@checkInserted
|
||
|
@checkReadOnly
|
||
|
moveq.l #-1,d0 ; always inserted, always read only
|
||
|
@enableWrites
|
||
|
@disableWrites
|
||
|
rts
|
||
|
|
||
|
@eject clr.b DiskInPlace(a3) ; mark it as offline
|
||
|
@done rts
|
||
|
title 'EDisk Driver - EDiskPollTask - Drive Polling Task'
|
||
|
|
||
|
;_______________________________________________________________________
|
||
|
;
|
||
|
; Routine: EDiskPollTask
|
||
|
; Inputs: A0 - address of VTask (passed by Vertical Retrace Manager)
|
||
|
; Outputs: none
|
||
|
; Destroys:
|
||
|
; Calls: none
|
||
|
; Called by: Vertical Retrace Manager
|
||
|
;
|
||
|
; Function: Polls the SLIM cards to check for insertions and removals.
|
||
|
; Debounces the result, and post events to reflect the action.
|
||
|
;
|
||
|
;_______________________________________________________________________
|
||
|
|
||
|
EDiskPollTask ; a0-a3/d0-d3 saved by int handler
|
||
|
lea EDiskVars-VTask(a0),a2 ; a2 := pointer to EDiskVars
|
||
|
lea DrvQHdr+QHead-QLink,a3 ; get the drive queue head
|
||
|
movea.l DCEpointer(a2),a1 ; get DCE pointer
|
||
|
move.w dCtlRefNum(a1),d3 ; d3 := driver refnum
|
||
|
|
||
|
tst.b Active(a2) ; see if request in progress
|
||
|
beq.s @next ; if not, start searching the drive queue
|
||
|
|
||
|
addq.w #1,VTask+vblCount(a2) ; if active, try again real soon
|
||
|
rts ; return
|
||
|
|
||
|
@search movea.l d2,a3 ; a3 := DriveQElement
|
||
|
cmp.w dQRefNum(a3),d3 ; see if we are the driver
|
||
|
beq.s @CheckDrive ; check our drives
|
||
|
@next move.l QLink(a3),d2 ; check next drive queue element
|
||
|
bne.s @search ; search until end of drive queue
|
||
|
|
||
|
move.w #EDiskPollRate,VTask+vblCount(a2) ; re-initialize the VBL count
|
||
|
rts ; return
|
||
|
|
||
|
|
||
|
@CheckDrive
|
||
|
moveq.l #CheckEDiskInserted,d0 ; hardware dependent function code
|
||
|
bsr.w HWDependent ; see if disk is inserted
|
||
|
addq.w #1,d0 ; ccr.x := 1 if EDisk inserted
|
||
|
move.b InsertedStatus(a3),d1 ; prepare to shift in new inserted status
|
||
|
addx.b d1,d1 ; shift in new inserted status
|
||
|
move.b d1,InsertedStatus(a3) ; update inserted status
|
||
|
moveq.l #InsertedMask,d0 ; prepare to de-bounce, and test inserted
|
||
|
|
||
|
and.b d0,d1 ; see if offline, without bounce
|
||
|
bne.s @CheckOnLine ; if not offline, check online or bounce
|
||
|
|
||
|
@OffLine
|
||
|
tst.b DiskInPlace(a3) ; check online status
|
||
|
bpl.s @next ; if not ejecting, do nothing
|
||
|
clr.b DiskInPlace(a3) ; now mark it offline (ejected)
|
||
|
bra.s @next ; eject complete, check next drive
|
||
|
|
||
|
|
||
|
@CheckOnLine
|
||
|
cmp.b d0,d1 ; see if online, without bounce
|
||
|
bne.s @next ; if bouncing, ignore it until it stops
|
||
|
tst.b DiskInPlace(a3) ; check online status
|
||
|
bmi.s @next ; if ejecting, do nothing
|
||
|
beq.s @OnLine ; if was offline, and just went online
|
||
|
|
||
|
@mount btst.b #MountedFlag,Flags(a3) ; see if it was mounted
|
||
|
bne.s @next ; if already mounted, don't do it again
|
||
|
moveq.l #DiskInsertEvt,d0 ; disk inserted event (zero high word)
|
||
|
movea.l d0,a0 ; disk inserted event passed in a0
|
||
|
move.w DQDrive(a3),d0 ; disk drive number in low word
|
||
|
_PostEvent ; post the disk inserted event
|
||
|
bne.s @next ; if error, don't mark as mounted
|
||
|
bset.b #MountedFlag,Flags(a3) ; mark it as mounted
|
||
|
@toNext bra.s @next ; check the next drive
|
||
|
|
||
|
@OnLine
|
||
|
@SetupDriveInfo
|
||
|
move.b DiskInPlaceInit(a3),\
|
||
|
DiskInPlace(a3) ; mark it as inserted
|
||
|
clr.b WriteProtected(a3) ; mark it as writeable (assume RAM)
|
||
|
move.l HeaderInfoPtr(a3),d0 ; see if it supports headers
|
||
|
beq.s @SetupRAMDisk ; if no headers, must be a RAM based disk
|
||
|
|
||
|
with EDiskHeader
|
||
|
movea.l d0,a0 ; a0 points to device header
|
||
|
move.l HdrFormatTime(a0),\
|
||
|
FormatTime(a3) ; get the unique ID from the header
|
||
|
move.l HdrFormatTicks(a0),\
|
||
|
FormatTicks(a3) ; get the unique ID from the header
|
||
|
|
||
|
; see if device is ROM or RAM
|
||
|
|
||
|
moveq.l #CheckEDiskReadOnly,d0 ; hardware dependent function code
|
||
|
bsr.w HWDependent ; see if disk is read only
|
||
|
move.b d0,WriteProtected(a3) ; setup the RAM=$00 / ROM=$FF flag
|
||
|
bne.s @SetupROMDisk ; if ROM disk, all info comes from header
|
||
|
|
||
|
tst.l SLIMRegPtr(a3) ; see if this is a SLIM (which needs to be sized)
|
||
|
beq.s @SetupRAMDisk ; if not, base and end must already be valid
|
||
|
|
||
|
moveq.l #EnableEDiskWrites,d0 ; hardware dependent function code
|
||
|
bsr.w HWDependent ; allow writes while sizing
|
||
|
bsr.w ComputeSLIMSize ; see how big the SLIM card is
|
||
|
add.l a0,d0 ; compute end ptr
|
||
|
move.l d0,DataEndPtr(a3) ; setup pointer to end of device data
|
||
|
adda.w #EDiskHeaderSize,a0 ; point past the header
|
||
|
move.l a0,CheckSumPtr(a3) ; checksums start just after the header
|
||
|
moveq.l #DisableEDiskWrites,d0 ; hardware dependent function code
|
||
|
bsr.w HWDependent ; no writes now
|
||
|
endwith
|
||
|
|
||
|
@SetupRAMDisk
|
||
|
movem.l CheckSumPtr(a3),d0/d1/d2; get checksum/start/end ptrs
|
||
|
tst.l d0 ; see if checksum ptr is valid
|
||
|
beq.s @BaseFound ; if not, then d1 = base address = start ptr
|
||
|
move.l d0,d1 ; otherwise d1 := base address = checksum ptr
|
||
|
moveq.l #0,d0 ; default to no checksums for now
|
||
|
@BaseFound
|
||
|
btst.b #CreateWithXSums,Flags(a3) ; see if we want checksums
|
||
|
beq.s @UpdateBasePtrs ; if no checksums, DataStartPtr is base
|
||
|
|
||
|
move.l d1,d0 ; checksum ptr := base address
|
||
|
sub.l d2,d1 ; base - end
|
||
|
neg.l d1 ; total size := end - base
|
||
|
addi.l #512*128-1,d1 ; prepare to round up
|
||
|
lsr.l #7,d1 ; divide by 128 (512/4)
|
||
|
andi.w #~(512-1),d1 ; round to block boundary
|
||
|
add.l d0,d1 ; data starts after checksum table
|
||
|
|
||
|
@UpdateBasePtrs
|
||
|
movem.l d0/d1,CheckSumPtr(a3) ; write back checksum/start ptrs
|
||
|
@SetupDriveSize
|
||
|
sub.l d1,d2 ; byte size := end ptr - start ptr
|
||
|
bhs.s @DriveSizeOK ; if size >= 0, use it, else force null range
|
||
|
|
||
|
move.l d1,DataEndPtr(a3) ; setup end of null range
|
||
|
moveq.l #0,d2 ; range is zero bytes
|
||
|
|
||
|
@DriveSizeOK
|
||
|
rol.l #16-9,d2 ; convert to blocks, and swap halves
|
||
|
move.l d2,dqDrvSz(a3) ; fill in the drive size (in blocks)
|
||
|
bra.w @mount ; now mount the drive
|
||
|
|
||
|
|
||
|
@SetupROMDisk
|
||
|
move.l a0,d0 ; remember header address
|
||
|
lea HeaderTemplate,a1 ; point to expected values
|
||
|
with EDiskHeader
|
||
|
lea HdrBlockSize(a0),a0 ; point to header data
|
||
|
moveq.l #(HdrDeviceSize-HdrBlockSize)/4-1,d2 ; loop counter
|
||
|
@cmpLoop
|
||
|
cmpm.l (a0)+,(a1)+ ; compare the values
|
||
|
dbne d2,@cmpLoop ; compare the blocks
|
||
|
beq.s @SigOK ; get header info if signature valid
|
||
|
|
||
|
move.l d0,d1 ; start ptr is header ptr
|
||
|
move.l d1,d2 ; end ptr is start ptr
|
||
|
bra.s @UpdateBasePtrs ; create an empty ROM disk (pretty useless)
|
||
|
|
||
|
@SigOK move.l (a0)+,d0 ; get device size
|
||
|
addq.w #HdrCheckSumOff-HdrFormatTime,a0 ; point to checksum offset in header
|
||
|
lea CheckSumPtr(a3),a1 ; point to checksum ptr in drive info
|
||
|
|
||
|
moveq.l #(HdrMediaIconOff-\
|
||
|
HdrCheckSumOff)/4-1,d2 ; loop for next 3 fields
|
||
|
|
||
|
tst.l SLIMRegPtr(a3) ; see if this is a SLIM (which is ejectable)
|
||
|
bne.s @offsetLoop ; if ejectable, don't get the icon info
|
||
|
|
||
|
moveq.l #(HdrDriveInfo-\
|
||
|
HdrCheckSumOff)/4-1,d2 ; loop for next 6 fields
|
||
|
|
||
|
move.l HdrDriveInfo-HdrCheckSumOff(a0),d1 ; get drive info
|
||
|
beq.s @offsetLoop ; if none specified, use default
|
||
|
move.l d1,DriveInfo(a3) ; setup new drive info
|
||
|
@offsetLoop
|
||
|
addq.l #4,a1 ; leave pointer alone, assume default
|
||
|
move.l (a0)+,d1 ; get the offset
|
||
|
beq.s @nextOffset ; if none, ignore it
|
||
|
cmp.l d0,d1 ; see if offset is reasonable
|
||
|
bhi.s @nextOffset ; if offset past end of device, ignore it
|
||
|
add.l HeaderInfoPtr(a3),d1 ; add device base to offset
|
||
|
move.l d1,-4(a1) ; update the pointer
|
||
|
@nextOffset
|
||
|
dbra d2,@offsetLoop ; loop through all of the fields
|
||
|
|
||
|
movem.l DataStartPtr(a3),d1/d2 ; get start/end ptrs
|
||
|
bra.s @SetupDriveSize ; setup the drive queue size info
|
||
|
endwith
|
||
|
title 'EDisk Driver - ComputeSLIMSize - Get Signature Information'
|
||
|
|
||
|
;_______________________________________________________________________
|
||
|
;
|
||
|
; Routine: ComputeSLIMSize
|
||
|
; Inputs: A0 - pointer to base of SLIM address space for this card
|
||
|
; Outputs: D0 - Device Size in bytes
|
||
|
; Destroys: A1, D1, D2
|
||
|
; Calls: none
|
||
|
; Called by:
|
||
|
;
|
||
|
; Function: Returns the device size for the specified SLIM card.
|
||
|
;
|
||
|
;_______________________________________________________________________
|
||
|
|
||
|
SegmentSize equ 512*1024 ; slims have up to 4 512K byte segments
|
||
|
|
||
|
ComputeSLIMSize
|
||
|
adda.l #4*SegmentSize,a0 ; point past end of last segment
|
||
|
movea.l a0,a1 ; save copy of end address
|
||
|
moveq.l #%0000,d0 ; assume all 4 segments are missing
|
||
|
move.l #'Gary',d1 ; rotating pattern
|
||
|
moveq.l #4-1,d2 ; loop counter
|
||
|
@FillLoop
|
||
|
suba.l #SegmentSize,a0 ; point to base of previous segment
|
||
|
move.l (a0),-(sp) ; save the old contents
|
||
|
rol.l #8,d1 ; change the pattern
|
||
|
move.l d1,(a0) ; write to the ram
|
||
|
cmp.l (a0),d1 ; see if we can read it back
|
||
|
bne.s @NotRAM1 ; if not, it's not RAM
|
||
|
not.l d1 ; complement the pattern
|
||
|
move.l d1,(a0) ; write to the ram
|
||
|
cmp.l (a0),d1 ; see if we can read it back
|
||
|
bne.s @NotRAM2 ; if not, it's not RAM
|
||
|
bset.l d2,d0 ; indicate that the segment is RAM
|
||
|
@NotRAM2
|
||
|
not.l d1 ; restore pattern
|
||
|
@NotRAM1
|
||
|
dbra d2,@FillLoop ; loop through all 4 segments
|
||
|
|
||
|
not.l d1 ; get expected pattern
|
||
|
moveq.l #4-1,d2 ; loop counter
|
||
|
@CheckLoop
|
||
|
suba.l #SegmentSize,a1 ; point to base of previous segment
|
||
|
rol.l #8,d1 ; change the pattern
|
||
|
cmp.l (a1),d1 ; see if we can read it back
|
||
|
beq.s @IsRAM ; if so, it's RAM that didn't wrap around
|
||
|
bclr.l d2,d0 ; indicate that the segment isn't RAM
|
||
|
@IsRAM
|
||
|
dbra d2,@CheckLoop ; loop through all 4 segments
|
||
|
|
||
|
moveq.l #4-1,d2 ; loop counter
|
||
|
@RestoreLoop
|
||
|
move.l (sp)+,(a1) ; restore the old contents
|
||
|
adda.l #SegmentSize,a1 ; point to base of next segment
|
||
|
dbra d2,@RestoreLoop ; loop through all 4 segments
|
||
|
|
||
|
move.b @SizesTable(d0.w),d0 ; encode the segment present bits
|
||
|
moveq.l #19,d1 ; shift amount
|
||
|
lsl.l d1,d0 ; convert segment count to byte count
|
||
|
rts ; all done
|
||
|
|
||
|
@SizesTable
|
||
|
dc.b 0 ; 0000 - RAM, 0.0MB, 0 segments
|
||
|
dc.b 1 ; 0001 - RAM, 0.5MB, 1 segment
|
||
|
dc.b 0 ; 0010 - RAM, illegal configuration
|
||
|
dc.b 2 ; 0011 - RAM, 1.0MB, 2 segments
|
||
|
dc.b 0 ; 0100 - RAM, illegal configuration
|
||
|
dc.b 0 ; 0101 - RAM, illegal configuration
|
||
|
dc.b 0 ; 0110 - RAM, illegal configuration
|
||
|
dc.b 3 ; 0111 - RAM, 1.5MB, 3 segments
|
||
|
dc.b 0 ; 1000 - RAM, illegal configuration
|
||
|
dc.b 0 ; 1001 - RAM, illegal configuration
|
||
|
dc.b 0 ; 1010 - RAM, illegal configuration
|
||
|
dc.b 0 ; 1011 - RAM, illegal configuration
|
||
|
dc.b 0 ; 1100 - RAM, illegal configuration
|
||
|
dc.b 0 ; 1101 - RAM, illegal configuration
|
||
|
dc.b 0 ; 1110 - RAM, illegal configuration
|
||
|
dc.b 4 ; 1111 - RAM, 2.0MB, 4 segments
|
||
|
title 'EDisk Driver - CreateEDiskHeader - Create Header Information'
|
||
|
|
||
|
;_______________________________________________________________________
|
||
|
;
|
||
|
; Routine: CreateEDiskHeader
|
||
|
; Inputs: A3 - pointer to Drive Queue Element for specified drive
|
||
|
; Destroys: A0, A1, D0, D1, D2, D3
|
||
|
; Calls: none
|
||
|
; Called by: ctlFormat
|
||
|
;
|
||
|
; Function: Writes an EDisk Header to the specified device.
|
||
|
;
|
||
|
;_______________________________________________________________________
|
||
|
|
||
|
CreateEDiskHeader
|
||
|
with EDiskHeader
|
||
|
move.l HeaderInfoPtr(a3),d0 ; get header base
|
||
|
beq.s @Done ; if no headers, nothing to do
|
||
|
|
||
|
movea.l d0,a0 ; setup header pointer
|
||
|
moveq.l #EDiskHeaderSize/4-1,d3 ; loop counter
|
||
|
@clrLoop
|
||
|
clr.l (a0)+ ; clear the header block
|
||
|
dbra d3,@clrLoop ; 4 bytes at a time
|
||
|
|
||
|
lea HeaderTemplate,a1 ; point to default values
|
||
|
lea HdrBlockSize-EDiskHeaderSize(a0),a0 ; point to header data
|
||
|
moveq.l #(HdrDeviceSize-HdrBlockSize)/4-1,d3 ; loop counter
|
||
|
@cpyLoop
|
||
|
move.l (a1)+,(a0)+ ; copy the template
|
||
|
dbra d3,@cpyLoop ; 4 bytes at a time
|
||
|
|
||
|
move.l DataEndPtr(a3),d2 ; find end of device (assume = end of data)
|
||
|
sub.l d0,d2 ; d2 := device size
|
||
|
move.l d2,(a0)+ ; setup HdrDeviceSize
|
||
|
|
||
|
lea FormatTime(a3),a1 ; point to drive info
|
||
|
move.l Time,(a1) ; setup the format time
|
||
|
move.l (a1)+,(a0)+ ; setup HdrFormatTime
|
||
|
move.l Ticks,(a1) ; setup the format ticks
|
||
|
move.l (a1)+,(a0)+ ; setup HdrFormatTicks
|
||
|
|
||
|
moveq.l #(HdrDriveInfo-\
|
||
|
HdrCheckSumOff)/4-1,d3 ; loop for next 6 fields
|
||
|
@offsetLoop
|
||
|
addq.l #4,a0 ; leave offset zero, assume not supported
|
||
|
move.l (a1)+,d1 ; get next ptr field
|
||
|
sub.l d0,d1 ; make it an offset from base of device
|
||
|
cmp.l d1,d2 ; see if in range
|
||
|
blo.s @nextOffset ; if out of range, try next one
|
||
|
move.l d1,-4(a0) ; if in range, put it into the header
|
||
|
@nextOffset
|
||
|
dbra d3,@offsetLoop ; loop through all of the fields
|
||
|
|
||
|
@Done rts ; all done
|
||
|
endwith
|
||
|
|
||
|
string asis ; no length on strings
|
||
|
align 2
|
||
|
HeaderTemplate
|
||
|
dc.w 512 ; signature block size
|
||
|
dc.w 1 ; version number 1
|
||
|
dc.b 'EDisk ' ; 12 byte signature
|
||
|
dc.b 'Gary D' ; (brought to you by Gary D)
|
||
|
|
||
|
|
||
|
|
||
|
string pascal ; name strings have leading length byte
|
||
|
|
||
|
IF not padForOverPatch THEN ; removing string to adjust for mods <H1>
|
||
|
align 2
|
||
|
SlimDrive0Name
|
||
|
dc.b 'Upper SLIM Drive'
|
||
|
ENDIF
|
||
|
|
||
|
align 2
|
||
|
SlimDrive1Name
|
||
|
dc.b 'Lower SLIM Drive'
|
||
|
|
||
|
align 2
|
||
|
ROMDiskName
|
||
|
dc.b 'Internal ROM Disk'
|
||
|
|
||
|
align 2
|
||
|
RAMDiskName
|
||
|
dc.b 'Internal RAM Disk'
|
||
|
|
||
|
align 2
|
||
|
title 'EDisk Driver - RAM / ROM Disk Icons'
|
||
|
|
||
|
ROMDiskMediaIcon
|
||
|
ROMDiskDriveIcon
|
||
|
|
||
|
RAMDiskMediaIcon
|
||
|
RAMDiskDriveIcon
|
||
|
dc.l %01111111111111111111111111110000
|
||
|
dc.l %10000001000000000000000100001000
|
||
|
dc.l %10000001000000000111000100000100
|
||
|
dc.l %10000001000000001000100100000010
|
||
|
dc.l %10000001000000001000100100000001
|
||
|
dc.l %10000001000000001000100100000001
|
||
|
dc.l %10000001000000001000100100000001
|
||
|
dc.l %10000001000000001000100100000001
|
||
|
dc.l %10000001000000001000100100000001
|
||
|
dc.l %10000001000000000111000100000001
|
||
|
dc.l %10000000111111111111111100000001
|
||
|
dc.l %10000000000000000000000000000001
|
||
|
dc.l %10000000000000000010000000000001
|
||
|
dc.l %10000000000000001101000000000001
|
||
|
dc.l %10000000000000001000100000000001
|
||
|
dc.l %10000000000000110000010000000001
|
||
|
dc.l %10000000000000100000011000000001
|
||
|
dc.l %10000000000011000000110000000001
|
||
|
dc.l %10000000000010000001111000000001
|
||
|
dc.l %10000000001100000011001000000001
|
||
|
dc.l %10000000001000000111101000000001
|
||
|
dc.l %10000000110000001100101000000001
|
||
|
dc.l %10000000110000011110100000000001
|
||
|
dc.l %10000000111000110010100000000001
|
||
|
dc.l %10000000111101111010000000000001
|
||
|
dc.l %10000000101111001010000000000001
|
||
|
dc.l %10000000100111101000000000000001
|
||
|
dc.l %10000000000010101000000000000001
|
||
|
dc.l %10000000000000100000000000000001
|
||
|
dc.l %10000000000000100000000000000001
|
||
|
dc.l %10000000000000000000000000000001
|
||
|
dc.l %11111111111111111111111111111110
|
||
|
|
||
|
dc.l %01111111111111111111111111110000
|
||
|
dc.l %11111111111111111111111111111000
|
||
|
dc.l %11111111111111111111111111111100
|
||
|
dc.l %11111111111111111111111111111110
|
||
|
dc.l %11111111111111111111111111111111
|
||
|
dc.l %11111111111111111111111111111111
|
||
|
dc.l %11111111111111111111111111111111
|
||
|
dc.l %11111111111111111111111111111111
|
||
|
dc.l %11111111111111111111111111111111
|
||
|
dc.l %11111111111111111111111111111111
|
||
|
dc.l %11111111111111111111111111111111
|
||
|
dc.l %11111111111111111111111111111111
|
||
|
dc.l %11111111111111111111111111111111
|
||
|
dc.l %11111111111111111111111111111111
|
||
|
dc.l %11111111111111111111111111111111
|
||
|
dc.l %11111111111111111111111111111111
|
||
|
dc.l %11111111111111111111111111111111
|
||
|
dc.l %11111111111111111111111111111111
|
||
|
dc.l %11111111111111111111111111111111
|
||
|
dc.l %11111111111111111111111111111111
|
||
|
dc.l %11111111111111111111111111111111
|
||
|
dc.l %11111111111111111111111111111111
|
||
|
dc.l %11111111111111111111111111111111
|
||
|
dc.l %11111111111111111111111111111111
|
||
|
dc.l %11111111111111111111111111111111
|
||
|
dc.l %11111111111111111111111111111111
|
||
|
dc.l %11111111111111111111111111111111
|
||
|
dc.l %11111111111111111111111111111111
|
||
|
dc.l %11111111111111111111111111111111
|
||
|
dc.l %11111111111111111111111111111111
|
||
|
dc.l %11111111111111111111111111111111
|
||
|
dc.l %11111111111111111111111111111110
|
||
|
|
||
|
END
|