MacIIROMDiskDriver/rdisk.c

370 lines
12 KiB
C
Raw Normal View History

2020-06-22 04:10:31 +00:00
#include <Memory.h>
#include <Devices.h>
#include <Files.h>
#include <Disks.h>
#include <Errors.h>
#include <Events.h>
#include <OSUtils.h>
2020-06-26 07:12:08 +00:00
#include "rdisk.h"
2020-06-27 02:13:22 +00:00
const long RDiskIcon[65] = {
// Icon
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0b11111111111111111111111111111111,
0b10000000000000000000000000000001,
0b10001111001111000001111001111001,
0b10001001001001000001001001001001,
0b10001001001001000001001001001001,
0b10001111001111000001111001111001,
0b11000000000000000000000000000001,
0b01010101010101011101010101010101,
0b01111111111111111111111111111111,
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
// Mask
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0b11111111111111111111111111111111,
0b11111111111111111111111111111111,
0b11111111111111111111111111111111,
0b11111111111111111111111111111111,
0b11111111111111111111111111111111,
0b11111111111111111111111111111111,
0b11111111111111111111111111111111,
0b01111111111111111111111111111111,
0b01111111111111111111111111111111,
0b00000000000000000000000000000000,
0b00000000000000000000000000000000,
0
};
// Switch to 24-bit mode and copy. Call this with
// PC==0x408XXXXX, not PC==0x008XXXXX
void RDiskCopy24(char *sourcePtr, char *destPtr, unsigned long byteCount) {
2020-06-22 04:10:31 +00:00
char mode = true32b;
SwapMMUMode(&mode);
BlockMove(sourcePtr, destPtr, byteCount);
2020-06-22 04:10:31 +00:00
SwapMMUMode(&mode);
}
typedef struct RDiskStorage_s {
DrvSts2 drvsts;
2020-06-26 07:12:08 +00:00
unsigned long init_done;
2020-06-22 04:10:31 +00:00
char *ramdisk;
Ptr ramdisk_alloc;
char ramdisk_valid;
} RDiskStorage_t;
#pragma parameter __D0 RDiskOpen(__A0, __A1)
2020-06-22 04:10:31 +00:00
OSErr RDiskOpen(IOParamPtr p, DCtlPtr d) {
DrvQElPtr dq;
2020-06-24 17:18:47 +00:00
DrvSts2 *status;
int drvNum;
2020-06-22 04:10:31 +00:00
RDiskStorage_t *c;
// Do nothing if already opened
if (d->dCtlStorage) { return noErr; }
2020-06-24 17:11:59 +00:00
2020-06-22 04:10:31 +00:00
// Figure out first available drive number
2020-06-24 17:18:47 +00:00
drvNum = 1;
2020-06-22 04:10:31 +00:00
for (dq = (DrvQElPtr)(GetDrvQHdr())->qHead; dq; dq = (DrvQElPtr)dq->qLink) {
2020-06-24 17:18:47 +00:00
if (dq->dQDrive >= drvNum) { drvNum = dq->dQDrive + 1; }
2020-06-22 04:10:31 +00:00
}
// Allocate storage struct
d->dCtlStorage = NewHandleSysClear(sizeof(RDiskStorage_t));
if (!d->dCtlStorage) { return openErr; }
// Lock our storage struct and get master pointer
HLock(d->dCtlStorage);
c = *(RDiskStorage_t**)d->dCtlStorage;
2020-06-24 17:18:47 +00:00
// Initialize storage struct fields
c->init_done = 0;
c->ramdisk = NULL;
c->ramdisk_alloc = NULL;
c->ramdisk_valid = 0;
2020-06-22 04:10:31 +00:00
// Set drive status
2020-06-26 07:12:08 +00:00
status = &c->drvsts;
2020-06-24 17:18:47 +00:00
status->writeProt = 0xF0;
status->diskInPlace = 0x08;
status->dQDrive = drvNum;
status->dQRefNum = d->dCtlRefNum;
status->driveSize = (RDiskSize / 512) & 0xFFFF;
status->driveS1 = ((RDiskSize / 512) & 0xFFFF0000) >> 16;
// Set driver flags?
2020-06-22 04:10:31 +00:00
/* d->dCtlFlags |= dReadEnableMask | dWritEnableMask |
dCtlEnableMask | dStatEnableMask |
2020-06-24 17:18:47 +00:00
dNeedLockMask; // 0x4F */
2020-06-22 04:10:31 +00:00
// Add drive to drive queue and return
RDiskAddDrive(status->dQRefNum, drvNum, (DrvQElPtr)&status->qLink);
2020-06-22 04:10:31 +00:00
return noErr;
}
2020-06-24 17:18:47 +00:00
OSErr RDiskInit(IOParamPtr p, DCtlPtr d, RDiskStorage_t *c) {
char startup = 0, ram = 0;
2020-06-22 04:10:31 +00:00
2020-06-24 17:18:47 +00:00
// Mark init done
c->init_done = 1;
2020-06-22 04:10:31 +00:00
// Read PRAM
2020-06-26 07:12:08 +00:00
RDiskReadXPRAM(1, 4, &startup);
RDiskReadXPRAM(1, 5, &ram);
2020-06-22 04:10:31 +00:00
// Either enable ROM disk or remove ourselves from the drive queue
2020-06-26 07:12:08 +00:00
if (startup || RDiskIsRPressed()) { // If ROM disk boot set in PRAM or R pressed,*/
2020-06-22 04:10:31 +00:00
// Set ROM disk attributes
c->drvsts.writeProt = -1; // Set write protected
2020-06-24 17:18:47 +00:00
// Clear disk fields (even though we used NewHandleSysClear)
2020-06-22 04:10:31 +00:00
c->ramdisk = NULL;
c->ramdisk_alloc = NULL;
2020-06-24 17:18:47 +00:00
c->ramdisk_valid = 0;
2020-06-22 04:10:31 +00:00
// If RAM disk set in PRAM or A pressed, enable RAM disk
if (ram || RDiskIsAPressed()) {
2020-06-22 04:10:31 +00:00
unsigned long minBufPtr, newBufPtr;
// Clearing write protect marks RAM disk enabled
c->drvsts.writeProt = 0;
// Compute if there is enough high memory
minBufPtr = ((unsigned long)*MemTop / 2) + 1024;
newBufPtr = (unsigned long)*BufPtr - RDiskSize;
// If in 32-bit mode and there is enough high memory, set ramdisk pointer now
if (*MMU32bit & newBufPtr > minBufPtr && (unsigned long)*BufPtr > newBufPtr) {
// Allocate RAM disk buffer by lowering BufPtr
*BufPtr = (Ptr)newBufPtr;
// Set RAM disk buffer pointer. Defer copying until accRun
// Don't set ramdisk_alloc because there is nothing to free.
c->ramdisk = *BufPtr;
2020-06-26 09:21:49 +00:00
// Copy ROM disk image to RAM disk
BlockMove(RDiskBuf, c->ramdisk, RDiskSize);
c->ramdisk_valid = 1;
} else {
// Enable accRun to allocate and copy later
d->dCtlFlags |= dNeedTimeMask;
d->dCtlDelay = 0x10;
2020-06-22 04:10:31 +00:00
}
}
2020-06-22 04:10:31 +00:00
return noErr;
2020-06-26 07:12:08 +00:00
} else { // Otherwise if R not held down and ROM boot not set in PRAM,
2020-06-22 04:10:31 +00:00
// Remove our driver from the drive queue
2020-06-26 07:18:16 +00:00
DrvQElPtr dq;
2020-06-26 09:21:49 +00:00
QHdrPtr QHead = DrvQHdr;
2020-06-24 17:18:47 +00:00
2020-06-22 04:10:31 +00:00
// Loop through entire drive queue, searching for our device or stopping at the end.
dq = (DrvQElPtr)QHead->qHead;
2020-06-26 07:18:16 +00:00
while ((dq != (DrvQElPtr)(QHead->qTail)) &&
(dq->dQRefNum != d->dCtlRefNum)) {
2020-06-22 04:10:31 +00:00
dq = (DrvQElPtr)(dq->qLink);
}
// If we found our driver, remove it from the queue
if (dq->dQRefNum == d->dCtlRefNum) {
Dequeue((QElemPtr)dq, QHead);
if (c->ramdisk_alloc) { DisposePtr(c->ramdisk_alloc); }
DisposeHandle(d->dCtlStorage);
}
d->dCtlStorage = NULL;
// Return disk offline error
2020-06-26 07:18:16 +00:00
return offLinErr;
2020-06-26 07:12:08 +00:00
}
2020-06-22 04:10:31 +00:00
}
#pragma parameter __D0 RDiskPrime(__A0, __A1)
2020-06-22 04:10:31 +00:00
OSErr RDiskPrime(IOParamPtr p, DCtlPtr d) {
RDiskStorage_t *c;
char cmd;
char *disk;
2020-06-26 07:12:08 +00:00
long offset;
RDiskCopy_t copy24 = &RDiskCopy24;
2020-06-22 04:10:31 +00:00
// Return disk offline error if dCtlStorage null
if (!d->dCtlStorage) { return offLinErr; }
// Dereference dCtlStorage to get pointer to our context
c = *(RDiskStorage_t**)d->dCtlStorage;
// Initialize if this is the first prime call
if (!c->init_done) {
OSErr ret = RDiskInit(p, d, c);
2020-06-24 17:18:47 +00:00
if (ret != noErr) { return ret; }
}
2020-06-22 04:10:31 +00:00
// Get pointer to RAM or ROM disk buffer
2020-06-26 09:21:49 +00:00
disk = c->ramdisk && c->ramdisk_valid ? c->ramdisk : RDiskBuf;
2020-06-22 04:10:31 +00:00
// Add offset to buffer pointer according to positioning mode
switch (p->ioPosMode & 0x000F) {
case fsAtMark: offset = d->dCtlPosition; break;
2020-06-26 07:12:08 +00:00
case fsFromStart: offset = p->ioPosOffset; break;
2020-06-24 17:18:47 +00:00
case fsFromMark: offset = d->dCtlPosition + p->ioPosOffset; break;
2020-06-26 07:12:08 +00:00
default: break;
2020-06-22 04:10:31 +00:00
}
2020-06-24 18:11:30 +00:00
disk += offset;
2020-06-24 17:18:47 +00:00
// Bounds checking
2020-06-26 09:21:49 +00:00
/*if (offset >= RDiskSize || p->ioReqCount >= RDiskSize ||
2020-06-24 17:18:47 +00:00
offset + p->ioReqCount >= RDiskSize ||
2020-06-26 09:21:49 +00:00
disk + offset < disk) { return posErr; }*/
2020-06-22 04:10:31 +00:00
// Service read or write request
cmd = p->ioTrap & 0x00FF;
if (cmd == aRdCmd) { // Read
// Return immediately if verify operation requested
//FIXME: follow either old (verify) or new (read uncached) convention
2020-06-26 07:12:08 +00:00
/*if (p->ioPosMode & rdVerifyMask) {
2020-06-24 17:18:47 +00:00
return noErr;
2020-06-26 07:12:08 +00:00
}*/
2020-06-22 04:10:31 +00:00
// Read from disk into buffer.
2020-06-26 07:12:08 +00:00
if (*MMU32bit) { BlockMove(disk, p->ioBuffer, p->ioReqCount); }
2020-06-22 04:10:31 +00:00
else { // 24-bit addressing
char *buffer = (char*)Translate24To32(StripAddress(p->ioBuffer));
copy24(disk, buffer, p->ioReqCount);
2020-06-22 04:10:31 +00:00
}
// Update count
p->ioActCount = p->ioReqCount;
2020-06-26 07:12:08 +00:00
d->dCtlPosition = offset + p->ioReqCount;
p->ioPosOffset = d->dCtlPosition;
2020-06-22 04:10:31 +00:00
return noErr;
} else if (cmd == aWrCmd) { // Write
2020-06-26 07:12:08 +00:00
// Fail if write protected or RAM disk buffer not set up
2020-06-24 18:12:33 +00:00
if (c->drvsts.writeProt || !c->ramdisk || !c->ramdisk_valid) { return wPrErr; }
2020-06-22 04:10:31 +00:00
// Write from buffer into disk.
if (*MMU32bit) { BlockMove((char*)p->ioBuffer, disk, p->ioReqCount); }
else { // 24-bit addressing
char *buffer = (char*)Translate24To32(StripAddress(p->ioBuffer));
copy24(buffer, disk, p->ioReqCount);
2020-06-22 04:10:31 +00:00
}
// Update count and position/offset
p->ioActCount = p->ioReqCount;
2020-06-26 07:12:08 +00:00
d->dCtlPosition = offset + p->ioReqCount;
p->ioPosOffset = d->dCtlPosition;
return noErr;
2020-06-22 04:10:31 +00:00
} else { return noErr; }
//FIXME: Should we fail if cmd isn't read or write?
}
2020-06-26 07:12:08 +00:00
OSErr RDiskAccRun(CntrlParamPtr p, DCtlPtr d, RDiskStorage_t *c) {
2020-06-22 04:10:31 +00:00
// Disable accRun
d->dCtlDelay = 0;
d->dCtlFlags &= ~dNeedTimeMask;
2020-06-26 09:21:49 +00:00
RDiskBreak();
2020-06-22 04:10:31 +00:00
// Set RAM disk buffer if our disk is writable and no RAM buffer set
if (!c->drvsts.writeProt && !c->ramdisk) {
if (*MMU32bit) { // If in 32-bit mode, (implies System 7)
// Allocate RAM disk buffer on system heap (System 7 can resize system heap)
c->ramdisk_alloc = NewPtrSys(RDiskSize);
if (c->ramdisk_alloc) { // If allocation successful,
// Set RAM disk buffer pointer
c->ramdisk = c->ramdisk_alloc;
}
} else { // Otherwise in 24-bit mode,
// Put buffer just beyond the 8 MB of RAM which is usable in 24-bit mode
c->ramdisk = (char*)(8 * 1024 * 1024);
//FIXME: what if we don't have enough RAM?
// Will this wrap around and overwrite low memory?
// That's not the worst, since the system would just crash,
// but it would be better to switch to read-only status
}
// Clear ramdisk_valid just in case, since ROM disk not yet copied to RAM disk
c->ramdisk_valid = 0;
}
if (!c->ramdisk) { // If RAM disk buffer couldn't be allocated,
// Mark write protected if we couldn't allocate RAM buffer?
c->drvsts.writeProt = -1;
} else if (c->ramdisk && !c->ramdisk_valid) { // Else if buffer exists but is not valid,
2020-06-26 07:12:08 +00:00
RDiskCopy_t copy24 = RDiskCopy24;
2020-06-22 04:10:31 +00:00
// Copy ROM disk to RAM disk buffer if not yet copied
if (*MMU32bit) { BlockMove(RDiskBuf, c->ramdisk, RDiskSize); }
else { copy24(RDiskBuf, c->ramdisk, RDiskSize); }
2020-06-22 04:10:31 +00:00
c->ramdisk_valid = 1;
}
return noErr; // Always return success
2020-06-26 07:12:08 +00:00
}
2020-06-22 04:10:31 +00:00
#pragma parameter __D0 RDiskControl(__A0, __A1)
2020-06-26 07:12:08 +00:00
OSErr RDiskControl(CntrlParamPtr p, DCtlPtr d) {
2020-06-22 04:10:31 +00:00
RDiskStorage_t *c;
2020-06-26 07:12:08 +00:00
// Fail if dCtlStorage null
if (!d->dCtlStorage) { return controlErr; }
2020-06-22 04:10:31 +00:00
// Dereference dCtlStorage to get pointer to our context
c = *(RDiskStorage_t**)d->dCtlStorage;
// Handle control request based on csCode
2020-06-26 07:12:08 +00:00
switch (p->csCode) {
2020-06-27 02:13:22 +00:00
case accRun: return noErr;
case 21: case 22:
*(Ptr*)&p->csParam = (Ptr)&RDiskIcon;
return noErr;
2020-06-22 04:10:31 +00:00
default: return controlErr;
}
}
#pragma parameter __D0 RDiskStatus(__A0, __A1)
2020-06-26 07:12:08 +00:00
OSErr RDiskStatus(CntrlParamPtr p, DCtlPtr d) {
2020-06-27 02:13:22 +00:00
RDiskStorage_t *c;
2020-06-26 07:12:08 +00:00
// Fail if dCtlStorage null
if (!d->dCtlStorage) { return statusErr; }
2020-06-27 02:13:22 +00:00
// Dereference dCtlStorage to get pointer to our context
c = *(RDiskStorage_t**)d->dCtlStorage;
2020-06-22 04:10:31 +00:00
// Handle status request based on csCode
2020-06-26 07:12:08 +00:00
switch (p->csCode) {
2020-06-22 04:10:31 +00:00
case drvStsCode:
2020-06-26 07:12:08 +00:00
BlockMove(*d->dCtlStorage, &p->csParam, sizeof(DrvSts2));
2020-06-22 04:10:31 +00:00
return noErr;
default: return statusErr;
}
}
#pragma parameter __D0 RDiskClose(__A0, __A1)
2020-06-22 04:10:31 +00:00
OSErr RDiskClose(IOParamPtr p, DCtlPtr d) {
// If dCtlStorage not null, dispose of it and its contents
2020-06-26 07:12:08 +00:00
if (!d->dCtlStorage) { return noErr; }
RDiskStorage_t *c = *(RDiskStorage_t**)d->dCtlStorage;
if (c->ramdisk_alloc) { DisposePtr(c->ramdisk_alloc); }
HUnlock(d->dCtlStorage);
DisposeHandle(d->dCtlStorage);
2020-06-22 04:10:31 +00:00
d->dCtlStorage = NULL;
return noErr;
}