mirror of
https://github.com/kanjitalk755/macemu.git
synced 2025-08-05 22:25:32 +00:00
Merge pull request #246 from rakslice/cdrom_multiple_units
Make multiple CD-ROM drives work more realistically
This commit is contained in:
@@ -150,14 +150,13 @@ struct cdrom_drive_info {
|
||||
uint32 status; // Mac address of drive status record
|
||||
bool drop; // Disc image mounted by drag-and-drop
|
||||
bool init_null; // Init even if null
|
||||
uint16 driver_reference_number = 0; // The driver reference number to use for this drive's entry in the unit table
|
||||
};
|
||||
|
||||
// List of drives handled by this driver
|
||||
typedef vector<cdrom_drive_info> drive_vec;
|
||||
static drive_vec drives;
|
||||
|
||||
int last_drive_num; // track last drive called to support multiple audio CDs
|
||||
|
||||
// Icon address (Mac address space, set by PatchROM())
|
||||
uint32 CDROMIconAddr;
|
||||
|
||||
@@ -170,12 +169,17 @@ static std::map<int, void *> remount_map;
|
||||
* Get pointer to drive info or drives.end() if not found
|
||||
*/
|
||||
|
||||
static drive_vec::iterator get_drive_info(int num)
|
||||
static drive_vec::iterator get_drive_info(int num, uint16 driverRefNum)
|
||||
{
|
||||
drive_vec::iterator info, end = drives.end();
|
||||
for (info = drives.begin(); info != end; ++info) {
|
||||
if (info->num == num) {
|
||||
last_drive_num = num;
|
||||
return info;
|
||||
}
|
||||
}
|
||||
// no match by drive num, try driver
|
||||
for (info = drives.begin(); info != end; ++info) {
|
||||
if (driverRefNum == info->driver_reference_number) {
|
||||
return info;
|
||||
}
|
||||
}
|
||||
@@ -328,12 +332,6 @@ void CDROMInit(void)
|
||||
drives.begin()->init_null = true;
|
||||
}
|
||||
|
||||
if (!drives.empty()) { // set to first drive by default
|
||||
last_drive_num = drives.begin()->num;
|
||||
}
|
||||
else {
|
||||
last_drive_num = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void CDROMDrop(const char *path) {
|
||||
@@ -387,7 +385,6 @@ void CDROMRemount() {
|
||||
for (std::map<int, void *>::iterator i = remount_map.begin(); i != remount_map.end(); ++i)
|
||||
for (drive_vec::iterator info = drives.begin(); info != drives.end(); ++info)
|
||||
if (info->num == i->first) {
|
||||
last_drive_num = i->first;
|
||||
info->fh = i->second;
|
||||
break;
|
||||
}
|
||||
@@ -426,6 +423,77 @@ static void mount_mountable_volumes(void)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Find a space in the unit table for the entry, put it in
|
||||
* and return the corresponding reference number.
|
||||
*
|
||||
* Based on the routine in Inside Macintosh: Devices, chapter 1 "Device Manager",
|
||||
* "Installing a Device Driver"
|
||||
*
|
||||
* Returns 0 if there was a problem.
|
||||
*
|
||||
* This code must only be used when there is no possibility of other activity.
|
||||
*/
|
||||
uint16 InsertNewDriverUnit(uint32 handle) {
|
||||
|
||||
uint16 minUnitEntryToUse = 48; // entries not reserved or intended for a specific use
|
||||
uint16 maxUnitEntries = 127;
|
||||
|
||||
uint16 unitEntryCount = ReadMacInt16(0x1d2);
|
||||
uint32 unitTableAddr = ReadMacInt32(0x11c);
|
||||
for (uint16 unitNum = unitEntryCount - 1; unitNum >= minUnitEntryToUse; unitNum-- ) {
|
||||
uint32 unitEntryAddr = unitTableAddr + 4 * unitNum;
|
||||
if (ReadMacInt32(unitEntryAddr) == 0) {
|
||||
// found a spot
|
||||
WriteMacInt32(unitEntryAddr, handle);
|
||||
uint16 refNum = ~unitNum;
|
||||
return refNum;
|
||||
}
|
||||
}
|
||||
|
||||
// No space free.
|
||||
|
||||
if (unitEntryCount == maxUnitEntries) // Can't expand
|
||||
return 0;
|
||||
|
||||
// Trade up.
|
||||
uint16 newUnitEntryCount = unitEntryCount + 10;
|
||||
if (newUnitEntryCount > maxUnitEntries)
|
||||
newUnitEntryCount = maxUnitEntries;
|
||||
if (newUnitEntryCount < minUnitEntryToUse + 1)
|
||||
newUnitEntryCount = minUnitEntryToUse + 1;
|
||||
|
||||
// Allocate space for a new unit table
|
||||
M68kRegisters r;
|
||||
r.d[0] = newUnitEntryCount * 4;
|
||||
Execute68kTrap(0xa71e, &r); // NewPtrSysClear()
|
||||
if (r.a[0] == 0)
|
||||
return 0;
|
||||
uint32 newUnitTableAddr = r.a[0];
|
||||
|
||||
// Copy it in to the new space
|
||||
Mac2Mac_memcpy(newUnitTableAddr, unitTableAddr, unitEntryCount * 4);
|
||||
Mac_memset(newUnitTableAddr + unitEntryCount * 4, 0, (newUnitEntryCount - unitEntryCount) * 4);
|
||||
|
||||
// Write in our new entry
|
||||
uint16 unitNum = newUnitEntryCount - 1;
|
||||
uint32 unitEntryAddr = unitTableAddr + 4 * unitNum;
|
||||
WriteMacInt32(unitEntryAddr, handle);
|
||||
uint16 refNum = ~unitNum;
|
||||
|
||||
// Make the new table active
|
||||
WriteMacInt32(0x11c, newUnitTableAddr);
|
||||
WriteMacInt16(0x1d2, newUnitEntryCount);
|
||||
|
||||
// Free the old one
|
||||
r.a[0] = unitTableAddr;
|
||||
Execute68kTrap(0xa01f, &r); // DisposePtr()
|
||||
|
||||
return refNum;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Driver Open() routine
|
||||
*/
|
||||
@@ -476,10 +544,24 @@ int16 CDROMOpen(uint32 pb, uint32 dce)
|
||||
find_hfs_partition(*info);
|
||||
info->to_be_mounted = true;
|
||||
}
|
||||
|
||||
if (info == drives.begin()) {
|
||||
// First drive gets to use the original unit table entry
|
||||
info->driver_reference_number = CDROMRefNum;
|
||||
} else {
|
||||
D(bug("Installing unit table entry for drive num %d\n", info->num));
|
||||
|
||||
// Get the driver handle from the original unit table entry
|
||||
uint32 handle = ReadMacInt32(ReadMacInt32(0x11c) + ~CDROMRefNum * 4);
|
||||
|
||||
// Create a new unit table entry
|
||||
info->driver_reference_number = InsertNewDriverUnit(handle);
|
||||
}
|
||||
|
||||
// Add drive to drive queue
|
||||
D(bug(" adding drive %d\n", info->num));
|
||||
r.d[0] = (info->num << 16) | (CDROMRefNum & 0xffff);
|
||||
assert(info->driver_reference_number != 0);
|
||||
r.d[0] = (info->num << 16) | (info->driver_reference_number & 0xffff);
|
||||
r.a[0] = info->status + dsQLink;
|
||||
Execute68kTrap(0xa04e, &r); // AddDrive()
|
||||
}
|
||||
@@ -500,7 +582,7 @@ int16 CDROMPrime(uint32 pb, uint32 dce)
|
||||
WriteMacInt32(pb + ioActCount, 0);
|
||||
|
||||
// Drive valid and disk inserted?
|
||||
drive_vec::iterator info = get_drive_info(ReadMacInt16(pb + ioVRefNum));
|
||||
drive_vec::iterator info = get_drive_info(ReadMacInt16(pb + ioVRefNum), ReadMacInt16(pb + ioRefNum));
|
||||
if (info == drives.end())
|
||||
return nsDrvErr;
|
||||
if (ReadMacInt8(info->status + dsDiskInPlace) == 0)
|
||||
@@ -569,16 +651,9 @@ int16 CDROMControl(uint32 pb, uint32 dce)
|
||||
}
|
||||
|
||||
// Drive valid?
|
||||
drive_vec::iterator info = get_drive_info(ReadMacInt16(pb + ioVRefNum));
|
||||
drive_vec::iterator info = get_drive_info(ReadMacInt16(pb + ioVRefNum), ReadMacInt16(pb + ioRefNum));
|
||||
if (info == drives.end()) {
|
||||
if (drives.empty()) {
|
||||
return nsDrvErr;
|
||||
} else {
|
||||
// Audio calls tend to end up without correct reference
|
||||
// Real mac would just play first disc, but we can guess correct one from last data call
|
||||
info = get_drive_info(last_drive_num);
|
||||
if (info == drives.end()) return nsDrvErr;
|
||||
}
|
||||
return nsDrvErr;
|
||||
}
|
||||
|
||||
// Drive-specific codes
|
||||
@@ -638,7 +713,7 @@ int16 CDROMControl(uint32 pb, uint32 dce)
|
||||
break;
|
||||
case FOURCC('i','n','t','f'):
|
||||
case FOURCC('d','A','P','I'):
|
||||
WriteMacInt32(pb + csParam + 4, FOURCC('a','t','p','i'));
|
||||
WriteMacInt32(pb + csParam + 4, FOURCC('s','c','s','i'));
|
||||
break;
|
||||
case FOURCC('s','y','n','c'):
|
||||
WriteMacInt32(pb + csParam + 4, 1); // true/false = sync/async
|
||||
@@ -1057,7 +1132,7 @@ int16 CDROMControl(uint32 pb, uint32 dce)
|
||||
|
||||
int16 CDROMStatus(uint32 pb, uint32 dce)
|
||||
{
|
||||
drive_vec::iterator info = get_drive_info(ReadMacInt16(pb + ioVRefNum));
|
||||
drive_vec::iterator info = get_drive_info(ReadMacInt16(pb + ioVRefNum), ReadMacInt16(pb + ioRefNum));
|
||||
uint16 code = ReadMacInt16(pb + csCode);
|
||||
D(bug("CDROMStatus %d\n", code));
|
||||
|
||||
@@ -1075,18 +1150,27 @@ int16 CDROMStatus(uint32 pb, uint32 dce)
|
||||
break;
|
||||
case FOURCC('i','n','t','f'): // Interface type
|
||||
// WriteMacInt32(pb + csParam + 4, EMULATOR_ID_4);
|
||||
WriteMacInt32(pb + csParam + 4, FOURCC('a','t','p','i'));
|
||||
WriteMacInt32(pb + csParam + 4, FOURCC('s','c','s','i'));
|
||||
break;
|
||||
case FOURCC('s','y','n','c'): // Only synchronous operation?
|
||||
WriteMacInt32(pb + csParam + 4, 0x01000000);
|
||||
// WriteMacInt32(pb + csParam + 4, 1);
|
||||
break;
|
||||
case FOURCC('b','o','o','t'): // Boot ID
|
||||
if (info != drives.end())
|
||||
WriteMacInt16(pb + csParam + 4, info->num);
|
||||
if (info != drives.end()) {
|
||||
// This is another byte compound value; SCSI:
|
||||
//
|
||||
// byte 0: SCSI target (5 bits) LUN (3 bits)
|
||||
// byte 1: partition (unused)
|
||||
//
|
||||
// (see Technote DV 22)
|
||||
//
|
||||
// We'll use our drive num as a SCSI ID for display purposes
|
||||
WriteMacInt16(pb + csParam + 4, (info->num & 0x1f) << 11);
|
||||
}
|
||||
else
|
||||
WriteMacInt16(pb + csParam + 4, 0);
|
||||
WriteMacInt16(pb + csParam + 6, (uint16)CDROMRefNum);
|
||||
WriteMacInt16(pb + csParam + 6, info->driver_reference_number);
|
||||
break;
|
||||
case FOURCC('w','i','d','e'): // 64-bit access supported?
|
||||
WriteMacInt16(pb + csParam + 4, 0);
|
||||
@@ -1126,12 +1210,7 @@ int16 CDROMStatus(uint32 pb, uint32 dce)
|
||||
|
||||
// Drive valid?
|
||||
if (info == drives.end()) {
|
||||
if (drives.empty()) {
|
||||
return nsDrvErr;
|
||||
} else {
|
||||
info = get_drive_info(last_drive_num);
|
||||
if (info == drives.end()) return nsDrvErr;
|
||||
}
|
||||
return nsDrvErr;
|
||||
}
|
||||
|
||||
// Drive-specific codes
|
||||
@@ -1172,7 +1251,15 @@ int16 CDROMStatus(uint32 pb, uint32 dce)
|
||||
return noErr;
|
||||
|
||||
case 120: // Return device ident
|
||||
WriteMacInt32(pb + csParam, 0);
|
||||
// This is a bunch of 8-bit fields:
|
||||
//
|
||||
// Byte 0: reserved
|
||||
// Byte 1: bus
|
||||
// Byte 2: target SCSI id
|
||||
// Byte 3: LUN
|
||||
//
|
||||
// Again, let's use our drive num as a SCSI ID for display purposes
|
||||
WriteMacInt32(pb + csParam, (info->num & 0xff) << 8);
|
||||
return noErr;
|
||||
|
||||
case 121: // Get CD features
|
||||
|
@@ -411,12 +411,12 @@ static const uint8 sony_driver[] = { // Replacement for .Sony driver
|
||||
static const uint8 disk_driver[] = { // Generic disk driver
|
||||
// Driver header
|
||||
DiskDriverFlags >> 8, DiskDriverFlags & 0xff, 0, 0, 0, 0, 0, 0,
|
||||
0x00, 0x1c, // Open() offset
|
||||
0x00, 0x20, // Prime() offset
|
||||
0x00, 0x24, // Control() offset
|
||||
0x00, 0x30, // Status() offset
|
||||
0x00, 0x56, // Close() offset
|
||||
0x08, 0x2e, 0x41, 0x54, 0x41, 0x44, 0x69, 0x73, 0x6b, 0x00, // ".ATADisk"
|
||||
0x00, 0x18, // Open() offset
|
||||
0x00, 0x1c, // Prime() offset
|
||||
0x00, 0x20, // Control() offset
|
||||
0x00, 0x2c, // Status() offset
|
||||
0x00, 0x52, // Close() offset
|
||||
0x05, 0x2e, 0x44, 0x69, 0x73, 0x6b, // ".Disk"
|
||||
|
||||
// Open()
|
||||
M68K_EMUL_OP_DISK_OPEN >> 8, M68K_EMUL_OP_DISK_OPEN & 0xff,
|
||||
@@ -2419,7 +2419,7 @@ void InstallDrivers(void)
|
||||
WriteMacInt16(dce + dCtlFlags, DiskDriverFlags);
|
||||
|
||||
// Open disk driver
|
||||
SheepString disk_str("\010.ATADisk");
|
||||
SheepString disk_str("\005.Disk");
|
||||
WriteMacInt32(pb + ioNamePtr, disk_str.addr());
|
||||
r.a[0] = pb;
|
||||
Execute68kTrap(0xa000, &r); // Open()
|
||||
|
Reference in New Issue
Block a user