--- BasiliskII/src/sony.cpp 1999/10/03 14:16:25 1.1 +++ BasiliskII/src/sony.cpp 2005/01/30 21:42:13 1.16 @@ -1,7 +1,7 @@ /* * sony.cpp - Replacement .Sony driver (floppy drives) * - * Basilisk II (C) 1997-1999 Christian Bauer + * Basilisk II (C) 1997-2005 Christian Bauer * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,9 +28,15 @@ * Technote FL 24: "Don't Look at ioPosOffset for Devices" */ +#include "sysdeps.h" + #include +#include + +#ifndef NO_STD_NAMESPACE +using std::vector; +#endif -#include "sysdeps.h" #include "cpu_emulation.h" #include "main.h" #include "macos_util.h" @@ -42,8 +48,10 @@ #define DEBUG 0 #include "debug.h" + +// Check for inserted disks by polling? #ifdef AMIGA -#define DISK_INSERT_CHECK 1 // Check for inserted disks (problem: on most hardware, disks are not ejected and automatically remounted) +#define DISK_INSERT_CHECK 1 #else #define DISK_INSERT_CHECK 0 #endif @@ -97,17 +105,12 @@ const uint8 SonyDriveIcon[258] = { // Struct for each drive -struct DriveInfo { - DriveInfo() - { - next = NULL; - num = 0; - fh = NULL; - read_only = false; - status = 0; - } +struct sony_drive_info { + sony_drive_info() : num(0), fh(NULL), read_only(false), status(0) {} + sony_drive_info(void *fh_, bool ro) : num(0), fh(fh_), read_only(ro), status(0) {} + + void close_fh(void) { Sys_close(fh); } - DriveInfo *next; // Pointer to next DriveInfo (must be first in struct!) int num; // Drive number void *fh; // Floppy driver file handle bool to_be_mounted; // Flag: drive must be mounted in accRun @@ -116,30 +119,30 @@ struct DriveInfo { uint32 status; // Mac address of drive status record }; -// Linked list of DriveInfos -static DriveInfo *first_drive_info; +// List of drives handled by this driver +typedef vector drive_vec; +static drive_vec drives; // Icon addresses (Mac address space, set by PatchROM()) uint32 SonyDiskIconAddr; uint32 SonyDriveIconAddr; -// Flag: accRun called for the first time, run PatchAfterStartup() -static bool periodic_first_time = false; +// Flag: Control(accRun) has been called, interrupt routine is now active +static bool acc_run_called = false; /* - * Get pointer to drive info, NULL = invalid drive number + * Get reference to drive info or drives.end() if not found */ -static DriveInfo *get_drive_info(int num) +static drive_vec::iterator get_drive_info(int num) { - DriveInfo *info = first_drive_info; - while (info != NULL) { + drive_vec::iterator info, end = drives.end(); + for (info = drives.begin(); info != end; ++info) { if (info->num == num) return info; - info = info->next; } - return NULL; + return info; } @@ -149,14 +152,12 @@ static DriveInfo *get_drive_info(int num void SonyInit(void) { - first_drive_info = NULL; - // No drives specified in prefs? Then add defaults if (PrefsFindString("floppy", 0) == NULL) SysAddFloppyPrefs(); // Add drives specified in preferences - int32 index = 0; + int index = 0; const char *str; while ((str = PrefsFindString("floppy", index++)) != NULL) { bool read_only = false; @@ -165,15 +166,8 @@ void SonyInit(void) str++; } void *fh = Sys_open(str, read_only); - if (fh) { - DriveInfo *info = new DriveInfo; - info->fh = fh; - info->read_only = SysIsReadOnly(fh); - DriveInfo *p = (DriveInfo *)&first_drive_info; - while (p->next != NULL) - p = p->next; - p->next = info; - } + if (fh) + drives.push_back(sony_drive_info(fh, SysIsReadOnly(fh))); } } @@ -184,13 +178,10 @@ void SonyInit(void) void SonyExit(void) { - DriveInfo *info = first_drive_info, *next; - while (info != NULL) { - Sys_close(info->fh); - next = info->next; - delete info; - info = next; - } + drive_vec::iterator info, end = drives.end(); + for (info = drives.begin(); info != end; ++info) + info->close_fh(); + drives.clear(); } @@ -200,13 +191,16 @@ void SonyExit(void) bool SonyMountVolume(void *fh) { - DriveInfo *info; - for (info = first_drive_info; info != NULL && info->fh != fh; info = info->next) ; - if (info) { + drive_vec::iterator info = drives.begin(), end = drives.end(); + while (info != end && info->fh != fh) + ++info; + if (info != end) { + D(bug("Looking for disk in drive %d\n", info->num)); if (SysIsDiskInserted(info->fh)) { info->read_only = SysIsReadOnly(info->fh); WriteMacInt8(info->status + dsDiskInPlace, 1); // Inserted removable disk WriteMacInt8(info->status + dsWriteProt, info->read_only ? 0xff : 0); + D(bug(" disk inserted, mounting\n")); info->to_be_mounted = true; } return true; @@ -216,6 +210,51 @@ bool SonyMountVolume(void *fh) /* + * Mount volumes for which the to_be_mounted flag is set + * (called during interrupt time) + */ + +static void mount_mountable_volumes(void) +{ + drive_vec::iterator info, end = drives.end(); + for (info = drives.begin(); info != end; ++info) { + +#if DISK_INSERT_CHECK + // Disk in drive? + if (ReadMacInt8(info->status + dsDiskInPlace) == 0) { + + // No, check if disk was inserted + if (SysIsDiskInserted(info->fh)) + SonyMountVolume(info->fh); + } +#endif + + // Mount disk if flagged + if (info->to_be_mounted) { + D(bug(" mounting drive %d\n", info->num)); + M68kRegisters r; + r.d[0] = info->num; + r.a[0] = 7; // diskEvent + Execute68kTrap(0xa02f, &r); // PostEvent() + info->to_be_mounted = false; + } + } +} + + +/* + * Set error code in DskErr + */ + +static int16 set_dsk_err(int16 err) +{ + D(bug("set_dsk_err(%d)\n", err)); + WriteMacInt16(0x142, err); + return err; +} + + +/* * Driver Open() routine */ @@ -226,7 +265,7 @@ int16 SonyOpen(uint32 pb, uint32 dce) // Set up DCE WriteMacInt32(dce + dCtlPosition, 0); WriteMacInt16(dce + dCtlQHdr + qFlags, ReadMacInt16(dce + dCtlQHdr + qFlags) & 0xff00 | 3); // Version number, must be >=3 or System 8 will replace us - periodic_first_time = true; + acc_run_called = false; // Install driver again with refnum -2 (HD20) uint32 utab = ReadMacInt32(0x11c); @@ -236,10 +275,11 @@ int16 SonyOpen(uint32 pb, uint32 dce) WriteMacInt32(0x134, 0xdeadbeef); // Clear DskErr - WriteMacInt16(0x142, 0); + set_dsk_err(0); // Install drives - for (DriveInfo *info = first_drive_info; info; info = info->next) { + drive_vec::iterator info, end = drives.end(); + for (info = drives.begin(); info != end; ++info) { info->num = FindFreeDriveNumber(1); info->to_be_mounted = false; @@ -270,6 +310,7 @@ int16 SonyOpen(uint32 pb, uint32 dce) if (SysIsDiskInserted(info->fh)) { WriteMacInt8(info->status + dsDiskInPlace, 1); // Inserted removable disk WriteMacInt8(info->status + dsWriteProt, info->read_only ? 0xff : 0); + D(bug(" disk inserted, flagging for mount\n")); info->to_be_mounted = true; } @@ -293,11 +334,11 @@ int16 SonyPrime(uint32 pb, uint32 dce) WriteMacInt32(pb + ioActCount, 0); // Drive valid and disk inserted? - DriveInfo *info; - if ((info = get_drive_info(ReadMacInt16(pb + ioVRefNum))) == NULL) - return nsDrvErr; + drive_vec::iterator info = get_drive_info(ReadMacInt16(pb + ioVRefNum)); + if (info == drives.end()) + return set_dsk_err(nsDrvErr); if (!ReadMacInt8(info->status + dsDiskInPlace)) - return offLinErr; + return set_dsk_err(offLinErr); WriteMacInt8(info->status + dsDiskInPlace, 2); // Disk accessed // Get parameters @@ -305,7 +346,7 @@ int16 SonyPrime(uint32 pb, uint32 dce) size_t length = ReadMacInt32(pb + ioReqCount); loff_t position = ReadMacInt32(dce + dCtlPosition); if ((length & 0x1ff) || (position & 0x1ff)) - return paramErr; + return set_dsk_err(paramErr); size_t actual = 0; if ((ReadMacInt16(pb + ioTrap) & 0xff) == aRdCmd) { @@ -313,7 +354,7 @@ int16 SonyPrime(uint32 pb, uint32 dce) // Read actual = Sys_read(info->fh, buffer, position, length); if (actual != length) - return readErr; + return set_dsk_err(readErr); // Clear TagBuf WriteMacInt32(0x2fc, 0); @@ -324,16 +365,16 @@ int16 SonyPrime(uint32 pb, uint32 dce) // Write if (info->read_only) - return wPrErr; + return set_dsk_err(wPrErr); actual = Sys_write(info->fh, buffer, position, length); if (actual != length) - return writErr; + return set_dsk_err(writErr); } // Update ParamBlock and DCE WriteMacInt32(pb + ioActCount, actual); WriteMacInt32(dce + dCtlPosition, ReadMacInt32(dce + dCtlPosition) + actual); - return noErr; + return set_dsk_err(noErr); } @@ -349,113 +390,88 @@ int16 SonyControl(uint32 pb, uint32 dce) // General codes switch (code) { case 1: // KillIO - return -1; + return set_dsk_err(-1); case 9: // Track cache - return noErr; - - case 65: { // Periodic action ("insert" disks on startup and check for disk changes) - DriveInfo *info = first_drive_info; - while (info != NULL) { - - // Disk in drive? - if (!ReadMacInt8(info->status + dsDiskInPlace)) { + return set_dsk_err(noErr); -#if DISK_INSERT_CHECK - // No, check if disk was inserted - if (SysIsDiskInserted(info->fh)) - SonyMountVolume(info->fh); -#endif - } - - // Mount disk if flagged - if (info->to_be_mounted) { - D(bug(" mounting drive %d\n", info->num)); - M68kRegisters r; - r.d[0] = info->num; - r.a[0] = 7; // diskEvent - Execute68kTrap(0xa02f, &r); // PostEvent() - info->to_be_mounted = false; - } - - info = info->next; - } - if (periodic_first_time) { - periodic_first_time = false; - PatchAfterStartup(); // Install patches after system startup - } + case 65: // Periodic action (accRun, "insert" disks on startup) + mount_mountable_volumes(); + PatchAfterStartup(); // Install patches after system startup + WriteMacInt16(dce + dCtlFlags, ReadMacInt16(dce + dCtlFlags) & ~0x2000); // Disable periodic action + acc_run_called = true; return noErr; - } } // Drive valid? - DriveInfo *info; - if ((info = get_drive_info(ReadMacInt16(pb + ioVRefNum))) == NULL) - return nsDrvErr; + drive_vec::iterator info = get_drive_info(ReadMacInt16(pb + ioVRefNum)); + if (info == drives.end()) + return set_dsk_err(nsDrvErr); // Drive-specific codes + int16 err = noErr; switch (code) { case 5: // Verify disk - if (ReadMacInt8(info->status + dsDiskInPlace) > 0) - return noErr; - else - return verErr; + if (ReadMacInt8(info->status + dsDiskInPlace) <= 0) + err = verErr; + break; case 6: // Format disk if (info->read_only) - return wPrErr; + err = wPrErr; else if (ReadMacInt8(info->status + dsDiskInPlace) > 0) { - if (SysFormat(info->fh)) - return noErr; - else - return writErr; + if (!SysFormat(info->fh)) + err = writErr; } else - return offLinErr; + err = offLinErr; + break; case 7: // Eject if (ReadMacInt8(info->status + dsDiskInPlace) > 0) { SysEject(info->fh); WriteMacInt8(info->status + dsDiskInPlace, 0); } - return noErr; + break; case 8: // Set tag buffer info->tag_buffer = ReadMacInt32(pb + csParam); - return noErr; + break; case 21: // Get drive icon WriteMacInt32(pb + csParam, SonyDriveIconAddr); - return noErr; + break; case 22: // Get disk icon WriteMacInt32(pb + csParam, SonyDiskIconAddr); - return noErr; + break; case 23: // Get drive info if (info->num == 1) WriteMacInt32(pb + csParam, 0x0004); // Internal drive else WriteMacInt32(pb + csParam, 0x0104); // External drive - return noErr; + break; - case 'SC': { // Format and write to disk + case 0x5343: // Format and write to disk ('SC'), used by DiskCopy if (!ReadMacInt8(info->status + dsDiskInPlace)) - return offLinErr; - if (info->read_only) - return wPrErr; - - void *data = Mac2HostAddr(ReadMacInt32(pb + csParam + 2)); - size_t actual = Sys_write(info->fh, data, 0, 2880*512); - if (actual != 2880*512) - return writErr; - else - return noErr; - } + err = offLinErr; + else if (info->read_only) + err = wPrErr; + else { + void *data = Mac2HostAddr(ReadMacInt32(pb + csParam + 2)); + size_t actual = Sys_write(info->fh, data, 0, 2880*512); + if (actual != 2880*512) + err = writErr; + } + break; default: printf("WARNING: Unknown SonyControl(%d)\n", code); - return controlErr; + err = controlErr; + break; } + + return set_dsk_err(err); } @@ -469,10 +485,11 @@ int16 SonyStatus(uint32 pb, uint32 dce) D(bug("SonyStatus %d\n", code)); // Drive valid? - DriveInfo *info; - if ((info = get_drive_info(ReadMacInt16(pb + ioVRefNum))) == NULL) - return nsDrvErr; + drive_vec::iterator info = get_drive_info(ReadMacInt16(pb + ioVRefNum)); + if (info == drives.end()) + return set_dsk_err(nsDrvErr); + int16 err = noErr; switch (code) { case 6: // Return format list if (ReadMacInt16(pb + csParam) > 0) { @@ -480,28 +497,44 @@ int16 SonyStatus(uint32 pb, uint32 dce) WriteMacInt16(pb + csParam, 1); // 1 format WriteMacInt32(adr, 2880); // 2880 sectors WriteMacInt32(adr + 4, 0xd2120050); // 2 heads, 18 secs/track, 80 tracks - return noErr; } else - return paramErr; + err = paramErr; + break; case 8: // Get drive status - memcpy(Mac2HostAddr(pb + csParam), Mac2HostAddr(info->status), 22); - return noErr; + Mac2Mac_memcpy(pb + csParam, info->status, 22); + break; case 10: // Get disk type WriteMacInt32(pb + csParam, ReadMacInt32(info->status + dsMFMDrive) & 0xffffff00 | 0xfe); - return noErr; + break; - case 'DV': // Duplicator version supported + case 0x4456: // Duplicator version supported ('DV') WriteMacInt16(pb + csParam, 0x0410); - return noErr; + break; - case 'SC': // Get address header format byte + case 0x5343: // Get address header format byte ('SC') WriteMacInt8(pb + csParam, 0x22); // 512 bytes/sector - return noErr; + break; default: printf("WARNING: Unknown SonyStatus(%d)\n", code); - return statusErr; + err = statusErr; + break; } + + return set_dsk_err(err); +} + + +/* + * Driver interrupt routine (1Hz) - check for volumes to be mounted + */ + +void SonyInterrupt(void) +{ + if (!acc_run_called) + return; + + mount_mountable_volumes(); }