Annotation of hatari/src/floppy.c, revision 1.1.1.16

1.1       root        1: /*
1.1.1.5   root        2:   Hatari - floppy.c
1.1       root        3: 
1.1.1.5   root        4:   This file is distributed under the GNU Public License, version 2 or at
                      5:   your option any later version. Read the file gpl.txt for details.
                      6: 
1.1.1.12  root        7:   This is where we read/write sectors to/from the disk image buffers.
                      8:   NOTE: these buffers are in memory so we only need to write routines for
                      9:   the .ST format. When the buffer is to be saved (ie eject disk) we save
                     10:   it back to the original file in the correct format (.ST or .MSA).
1.1.1.5   root       11: 
                     12:   There are some important notes about image accessing - as we use TOS and the
1.1.1.9   root       13:   FDC to access the disk the boot-sector MUST be valid. Sometimes this is NOT
                     14:   the case! In these situations we must guess at the disk format. Eg, some disk
1.1.1.5   root       15:   images have a a boot sector which states single-sided, but the images have
                     16:   been created as double-sided. As sides are interleaved we need to read the
                     17:   image as if it was double-sided. Also note that 'NumBytesPerSector' is ALWAYS
                     18:   512 bytes, even if the boot-sector states otherwise.
1.1.1.4   root       19:   Also note that old versions of the MAKEDISK utility do not set the correct
                     20:   boot sector structure for a real ST (and also Hatari) to read it correctly.
                     21:   (PaCifiST will, however, read/write to these images as it does not perform
                     22:   FDC access as on a real ST)
1.1       root       23: */
1.1.1.13  root       24: const char Floppy_fileid[] = "Hatari floppy.c : " __DATE__ " " __TIME__;
1.1.1.8   root       25: 
                     26: #include <sys/stat.h>
1.1.1.12  root       27: #include <assert.h>
1.1.1.4   root       28: #include <SDL_endian.h>
                     29: 
1.1       root       30: #include "main.h"
1.1.1.6   root       31: #include "configuration.h"
1.1.1.7   root       32: #include "dim.h"
1.1       root       33: #include "file.h"
                     34: #include "floppy.h"
1.1.1.9   root       35: #include "gemdos.h"
                     36: #include "hdc.h"
1.1.1.8   root       37: #include "log.h"
1.1       root       38: #include "memorySnapShot.h"
                     39: #include "msa.h"
                     40: #include "st.h"
1.1.1.6   root       41: #include "zip.h"
1.1       root       42: 
1.1.1.10  root       43: 
1.1.1.12  root       44: /* Emulation drive details, eg FileName, Inserted, Changed etc... */
                     45: EMULATION_DRIVE EmulationDrives[MAX_FLOPPYDRIVES];
                     46: /* Drive A is the default */
                     47: int nBootDrive = 0;
1.1       root       48: 
1.1.1.9   root       49: /* Possible disk image file extensions to scan for */
1.1.1.10  root       50: static const char * const pszDiskImageNameExts[] =
1.1.1.5   root       51: {
1.1.1.10  root       52:        ".msa",
                     53:        ".st",
                     54:        ".dim",
                     55:        NULL
1.1       root       56: };
                     57: 
                     58: 
1.1.1.13  root       59: /* local functions */
                     60: static bool Floppy_EjectBothDrives(void);
                     61: 
                     62: 
1.1.1.2   root       63: /*-----------------------------------------------------------------------*/
1.1.1.11  root       64: /**
                     65:  * Initialize emulation floppy drives
                     66:  */
1.1       root       67: void Floppy_Init(void)
                     68: {
1.1.1.10  root       69:        int i;
1.1       root       70: 
1.1.1.10  root       71:        /* Clear drive structures */
1.1.1.12  root       72:        for (i = 0; i < MAX_FLOPPYDRIVES; i++)
1.1.1.10  root       73:        {
1.1.1.12  root       74:                /* Clear structs and if floppies available, insert them */
1.1.1.10  root       75:                memset(&EmulationDrives[i], 0, sizeof(EMULATION_DRIVE));
1.1.1.12  root       76:                if (strlen(ConfigureParams.DiskImage.szDiskFileName[i]) > 0)
                     77:                        Floppy_InsertDiskIntoDrive(i);
1.1.1.10  root       78:        }
1.1       root       79: }
                     80: 
1.1.1.2   root       81: 
                     82: /*-----------------------------------------------------------------------*/
1.1.1.11  root       83: /**
                     84:  * UnInitialize drives
                     85:  */
1.1       root       86: void Floppy_UnInit(void)
                     87: {
1.1.1.10  root       88:        Floppy_EjectBothDrives();
1.1       root       89: }
                     90: 
1.1.1.2   root       91: 
                     92: /*-----------------------------------------------------------------------*/
1.1.1.11  root       93: /**
                     94:  * Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type)
                     95:  */
1.1.1.12  root       96: void Floppy_MemorySnapShot_Capture(bool bSave)
1.1       root       97: {
1.1.1.10  root       98:        int i;
1.1       root       99: 
1.1.1.10  root      100:        /* If restoring then eject old drives first! */
                    101:        if (!bSave)
                    102:                Floppy_EjectBothDrives();
                    103: 
                    104:        /* Save/Restore details */
1.1.1.12  root      105:        for (i = 0; i < MAX_FLOPPYDRIVES; i++)
1.1.1.10  root      106:        {
                    107:                MemorySnapShot_Store(&EmulationDrives[i].bDiskInserted, sizeof(EmulationDrives[i].bDiskInserted));
                    108:                MemorySnapShot_Store(&EmulationDrives[i].nImageBytes, sizeof(EmulationDrives[i].nImageBytes));
                    109:                if (!bSave && EmulationDrives[i].bDiskInserted)
                    110:                {
                    111:                        EmulationDrives[i].pBuffer = malloc(EmulationDrives[i].nImageBytes);
                    112:                        if (!EmulationDrives[i].pBuffer)
                    113:                                perror("Floppy_MemorySnapShot_Capture");
                    114:                }
                    115:                if (EmulationDrives[i].pBuffer)
                    116:                        MemorySnapShot_Store(EmulationDrives[i].pBuffer, EmulationDrives[i].nImageBytes);
1.1.1.13  root      117:                MemorySnapShot_Store(EmulationDrives[i].sFileName, sizeof(EmulationDrives[i].sFileName));
1.1.1.10  root      118:                MemorySnapShot_Store(&EmulationDrives[i].bMediaChanged,sizeof(EmulationDrives[i].bMediaChanged));
                    119:                MemorySnapShot_Store(&EmulationDrives[i].bContentsChanged,sizeof(EmulationDrives[i].bContentsChanged));
                    120:                MemorySnapShot_Store(&EmulationDrives[i].bOKToSave,sizeof(EmulationDrives[i].bOKToSave));
                    121:        }
1.1       root      122: }
                    123: 
1.1.1.2   root      124: 
                    125: /*-----------------------------------------------------------------------*/
1.1.1.11  root      126: /**
                    127:  * Find which device to boot from (hard drive or floppy).
                    128:  */
1.1       root      129: void Floppy_GetBootDrive(void)
                    130: {
1.1.1.15  root      131:        /* Default to drive A: */
                    132:        nBootDrive = 0;
                    133: 
                    134:        /* Boot only from hard drive if user wants this */
                    135:        if (!ConfigureParams.HardDisk.bBootFromHardDisk)
                    136:                return;
                    137: 
1.1.1.16! root      138:        if (ACSI_EMU_ON || ConfigureParams.HardDisk.bUseIdeMasterHardDiskImage)
1.1.1.15  root      139:        {
1.1.1.10  root      140:                nBootDrive = 2;  /* Drive C */
1.1.1.15  root      141:        }
                    142:        else if (GEMDOS_EMU_ON)
                    143:        {
                    144:                int i;
                    145:                for (i = 0; i < MAX_HARDDRIVES; i++)
                    146:                {
                    147:                        if (emudrives[i])
                    148:                        {
1.1.1.16! root      149:                                nBootDrive = emudrives[i]->drive_number;
1.1.1.15  root      150:                                break;
                    151:                        }
                    152:                }
                    153:        }
1.1       root      154: }
                    155: 
1.1.1.2   root      156: 
                    157: /*-----------------------------------------------------------------------*/
1.1.1.11  root      158: /**
                    159:  * Test if disk image is write protected. Write protection can be configured
                    160:  * in the GUI. When set to "automatic", we check the file permissions of the
                    161:  * floppy disk image to decide.
                    162:  */
1.1.1.12  root      163: bool Floppy_IsWriteProtected(int Drive)
1.1.1.8   root      164: {
1.1.1.10  root      165:        if (ConfigureParams.DiskImage.nWriteProtection == WRITEPROT_OFF)
                    166:        {
1.1.1.14  root      167:                return false;
1.1.1.10  root      168:        }
                    169:        else if (ConfigureParams.DiskImage.nWriteProtection == WRITEPROT_ON)
                    170:        {
1.1.1.14  root      171:                return true;
1.1.1.10  root      172:        }
                    173:        else
                    174:        {
                    175:                struct stat FloppyStat;
                    176:                /* Check whether disk is writable */
1.1.1.13  root      177:                if (stat(EmulationDrives[Drive].sFileName, &FloppyStat) == 0
1.1.1.12  root      178:                    && (FloppyStat.st_mode & S_IWUSR))
1.1.1.14  root      179:                        return false;
1.1.1.10  root      180:                else
1.1.1.14  root      181:                        return true;
1.1.1.10  root      182:        }
1.1.1.8   root      183: }
                    184: 
                    185: 
                    186: /*-----------------------------------------------------------------------*/
1.1.1.11  root      187: /**
                    188:  * Test disk image for valid boot-sector.
                    189:  * It has been noticed that some disks, eg blank images made by the MakeDisk
                    190:  * utility or PaCifiST emulator fill in the boot-sector with incorrect information.
                    191:  * Such images cannot be read correctly using a real ST, and also Hatari.
                    192:  * To try and prevent data loss, we check for this error and flag the drive so
                    193:  * the image will not be saved back to the file.
                    194:  */
1.1.1.12  root      195: static bool Floppy_IsBootSectorOK(int Drive)
1.1       root      196: {
1.1.1.10  root      197:        Uint8 *pDiskBuffer;
1.1       root      198: 
1.1.1.10  root      199:        /* Does our drive have a disk in? */
                    200:        if (EmulationDrives[Drive].bDiskInserted)
                    201:        {
                    202:                pDiskBuffer = EmulationDrives[Drive].pBuffer;
                    203: 
                    204:                /* Check SPC (byte 13) for !=0 value. If is '0', invalid image and Hatari
                    205:                 * won't be-able to read (nor will a real ST)! */
                    206:                if (pDiskBuffer[13] != 0)
                    207:                {
1.1.1.14  root      208:                        return true;      /* Disk sector is OK! */
1.1.1.10  root      209:                }
                    210:                else
                    211:                {
                    212:                        Log_AlertDlg(LOG_WARN, "Disk in drive %c: maybe suffers from the Pacifist/Makedisk bug.\n"
                    213:                                     "If it does not work, please repair the disk first!\n", 'A' + Drive);
                    214:                }
                    215:        }
1.1       root      216: 
1.1.1.14  root      217:        return false;         /* Bad sector */
1.1       root      218: }
                    219: 
1.1.1.2   root      220: 
                    221: /*-----------------------------------------------------------------------*/
1.1.1.11  root      222: /**
                    223:  * Try to create disk B filename, eg 'auto_100a' becomes 'auto_100b'
                    224:  * Return new filename if think we should try, otherwise NULL
1.1.1.12  root      225:  *
                    226:  * TODO: doesn't work with images in ZIP archives
1.1.1.11  root      227:  */
                    228: static char* Floppy_CreateDiskBFileName(const char *pSrcFileName)
1.1       root      229: {
1.1.1.10  root      230:        char *szDir, *szName, *szExt;
1.1.1.12  root      231: 
1.1.1.10  root      232:        /* Allocate temporary memory for strings: */
                    233:        szDir = malloc(3 * FILENAME_MAX);
                    234:        if (!szDir)
                    235:        {
                    236:                perror("Floppy_CreateDiskBFileName");
1.1.1.14  root      237:                return false;
1.1.1.10  root      238:        }
                    239:        szName = szDir + FILENAME_MAX;
                    240:        szExt = szName + FILENAME_MAX;
                    241: 
                    242:        /* So, first split name into parts */
1.1.1.11  root      243:        File_SplitPath(pSrcFileName, szDir, szName, szExt);
1.1.1.10  root      244: 
                    245:        /* All OK? */
                    246:        if (strlen(szName) > 0)
                    247:        {
1.1.1.12  root      248:                char *last = &(szName[strlen(szName)-1]);
                    249:                /* Now, did filename end with an 'A' or 'a' */
                    250:                if (*last == 'A' || *last == 'a')
1.1.1.10  root      251:                {
1.1.1.11  root      252:                        char *szFull;
1.1.1.10  root      253:                        /* Change 'A' to a 'B' */
1.1.1.12  root      254:                        *last += 1;
1.1.1.10  root      255:                        /* And re-build name into destination */
1.1.1.11  root      256:                        szFull = File_MakePath(szDir, szName, szExt);
                    257:                        if (szFull)
                    258:                        {
                    259:                                /* Does file exist? */
                    260:                                if (File_Exists(szFull))
                    261:                                {
                    262:                                        free(szDir);
                    263:                                        return szFull;
                    264:                                }
                    265:                                free(szFull);
                    266:                        }
1.1.1.10  root      267:                }
                    268:        }
                    269:        free(szDir);
1.1.1.11  root      270:        return NULL;
1.1       root      271: }
                    272: 
1.1.1.2   root      273: 
                    274: /*-----------------------------------------------------------------------*/
1.1.1.11  root      275: /**
1.1.1.12  root      276:  * Set floppy image to be ejected
                    277:  */
                    278: const char* Floppy_SetDiskFileNameNone(int Drive)
                    279: {
                    280:        assert(Drive >= 0 && Drive < MAX_FLOPPYDRIVES);
                    281:        ConfigureParams.DiskImage.szDiskFileName[Drive][0] = '\0';
                    282:        return ConfigureParams.DiskImage.szDiskFileName[Drive];
1.1.1.6   root      283: }
                    284: 
1.1.1.12  root      285: /*-----------------------------------------------------------------------*/
                    286: /**
                    287:  * Set given floppy drive image file name and handle
                    288:  * different image extensions.
                    289:  * Return corrected file name on success and NULL on failure.
1.1.1.11  root      290:  */
1.1.1.12  root      291: const char* Floppy_SetDiskFileName(int Drive, const char *pszFileName, const char *pszZipPath)
1.1.1.6   root      292: {
1.1.1.11  root      293:        char *filename;
1.1.1.16! root      294:        int i;
1.1       root      295: 
1.1.1.12  root      296:        /* setting to empty or "none" ejects */
                    297:        if (!*pszFileName || strcasecmp(pszFileName, "none") == 0)
                    298:        {
                    299:                return Floppy_SetDiskFileNameNone(Drive);
                    300:        }
1.1.1.11  root      301:        /* See if file exists, and if not, get/add correct extension */
1.1.1.12  root      302:        if (!File_Exists(pszFileName))
1.1.1.11  root      303:                filename = File_FindPossibleExtFileName(pszFileName, pszDiskImageNameExts);
                    304:        else
                    305:                filename = strdup(pszFileName);
1.1.1.12  root      306:        if (!filename)
                    307:        {
                    308:                Log_AlertDlg(LOG_INFO, "Image '%s' not found", pszFileName);
                    309:                return NULL;
                    310:        }
                    311: 
                    312:        /* If we insert a disk into Drive A, should we try to put disk 2 into drive B? */
                    313:        if (Drive == 0 && ConfigureParams.DiskImage.bAutoInsertDiskB)
                    314:        {
                    315:                /* Attempt to make up second filename, eg was 'auto_100a' to 'auto_100b' */
                    316:                char *szDiskBFileName = Floppy_CreateDiskBFileName(filename);
                    317:                if (szDiskBFileName)
                    318:                {
                    319:                        /* recurse with Drive B */
                    320:                        Floppy_SetDiskFileName(1, szDiskBFileName, pszZipPath);
                    321:                        free(szDiskBFileName);
                    322:                }
                    323:        }
                    324: 
1.1.1.16! root      325:        /* validity checks */
1.1.1.12  root      326:        assert(Drive >= 0 && Drive < MAX_FLOPPYDRIVES);
1.1.1.16! root      327:        for (i = 0; i < MAX_FLOPPYDRIVES; i++)
        !           328:        {
        !           329:                if (i == Drive)
        !           330:                        continue;
        !           331:                /* prevent inserting same image to multiple drives */
        !           332:                if (strcmp(filename, ConfigureParams.DiskImage.szDiskFileName[i]) == 0)
        !           333:                {
        !           334:                        Log_AlertDlg(LOG_ERROR, "ERROR: Cannot insert same floppy to multiple drives!");
        !           335:                        return NULL;
        !           336:                }
        !           337:        }
        !           338: 
        !           339:        /* do the changes */
1.1.1.12  root      340:        if (pszZipPath)
                    341:                strcpy(ConfigureParams.DiskImage.szDiskZipPath[Drive], pszZipPath);
                    342:        else
                    343:                ConfigureParams.DiskImage.szDiskZipPath[Drive][0] = '\0';
                    344:        strcpy(ConfigureParams.DiskImage.szDiskFileName[Drive], filename);
                    345:        free(filename);
                    346:        //File_MakeAbsoluteName(ConfigureParams.DiskImage.szDiskFileName[Drive]);
                    347:        return ConfigureParams.DiskImage.szDiskFileName[Drive];
                    348: }
                    349: 
                    350: /*-----------------------------------------------------------------------*/
                    351: /**
                    352:  * Insert previously set disk file image into floppy drive.
                    353:  * The WHOLE image is copied into Hatari drive buffers, and
                    354:  * uncompressed if necessary.
                    355:  * Return TRUE on success, false otherwise.
                    356:  */
                    357: bool Floppy_InsertDiskIntoDrive(int Drive)
                    358: {
                    359:        long nImageBytes = 0;
                    360:        char *filename;
                    361: 
                    362:        /* Eject disk, if one is inserted (doesn't inform user) */
                    363:        assert(Drive >= 0 && Drive < MAX_FLOPPYDRIVES);
                    364:        Floppy_EjectDiskFromDrive(Drive);
                    365: 
                    366:        filename = ConfigureParams.DiskImage.szDiskFileName[Drive];
                    367:        if (!filename[0])
                    368:        {
1.1.1.14  root      369:                return true; /* only do eject */
1.1.1.12  root      370:        }
                    371:        if (!File_Exists(filename))
                    372:        {
                    373:                Log_AlertDlg(LOG_INFO, "Image '%s' not found", filename);
1.1.1.14  root      374:                return false;
1.1.1.12  root      375:        }
                    376: 
1.1.1.10  root      377:        /* Check disk image type and read the file: */
1.1.1.14  root      378:        if (MSA_FileNameIsMSA(filename, true))
1.1.1.11  root      379:                EmulationDrives[Drive].pBuffer = MSA_ReadDisk(filename, &nImageBytes);
1.1.1.14  root      380:        else if (ST_FileNameIsST(filename, true))
1.1.1.11  root      381:                EmulationDrives[Drive].pBuffer = ST_ReadDisk(filename, &nImageBytes);
1.1.1.14  root      382:        else if (DIM_FileNameIsDIM(filename, true))
1.1.1.11  root      383:                EmulationDrives[Drive].pBuffer = DIM_ReadDisk(filename, &nImageBytes);
                    384:        else if (ZIP_FileNameIsZIP(filename))
1.1.1.12  root      385:        {
                    386:                const char *zippath = ConfigureParams.DiskImage.szDiskZipPath[Drive];
                    387:                EmulationDrives[Drive].pBuffer = ZIP_ReadDisk(filename, zippath, &nImageBytes);
                    388:        }
1.1.1.11  root      389: 
                    390:        if (EmulationDrives[Drive].pBuffer == NULL)
                    391:        {
1.1.1.14  root      392:                return false;
1.1.1.11  root      393:        }
1.1.1.13  root      394: 
                    395:        /* Store image filename (required for ejecting the disk later!) */
                    396:        strcpy(EmulationDrives[Drive].sFileName, filename);
                    397: 
                    398:        /* Store size and set drive states */
1.1.1.11  root      399:        EmulationDrives[Drive].nImageBytes = nImageBytes;
1.1.1.14  root      400:        EmulationDrives[Drive].bDiskInserted = true;
                    401:        EmulationDrives[Drive].bContentsChanged = false;
                    402:        EmulationDrives[Drive].bMediaChanged = true;
1.1.1.11  root      403:        EmulationDrives[Drive].bOKToSave = Floppy_IsBootSectorOK(Drive);
1.1.1.12  root      404:        Log_Printf(LOG_INFO, "Inserted disk '%s' to drive %c:.",
                    405:                   filename, 'A'+Drive);
1.1.1.14  root      406:        return true;
1.1       root      407: }
                    408: 
1.1.1.2   root      409: 
                    410: /*-----------------------------------------------------------------------*/
1.1.1.11  root      411: /**
                    412:  * Eject disk from floppy drive, save contents back to PCs hard-drive if
                    413:  * they have been changed.
1.1.1.14  root      414:  * Return true if there was something to eject.
1.1.1.11  root      415:  */
1.1.1.12  root      416: bool Floppy_EjectDiskFromDrive(int Drive)
1.1       root      417: {
1.1.1.14  root      418:        bool bEjected = false;
1.1.1.12  root      419: 
1.1.1.10  root      420:        /* Does our drive have a disk in? */
                    421:        if (EmulationDrives[Drive].bDiskInserted)
                    422:        {
1.1.1.16! root      423:                bool bSaved = false;
1.1.1.13  root      424:                char *psFileName = EmulationDrives[Drive].sFileName;
1.1.1.12  root      425: 
1.1.1.10  root      426:                /* OK, has contents changed? If so, need to save */
                    427:                if (EmulationDrives[Drive].bContentsChanged)
                    428:                {
                    429:                        /* Is OK to save image (if boot-sector is bad, don't allow a save) */
                    430:                        if (EmulationDrives[Drive].bOKToSave && !Floppy_IsWriteProtected(Drive))
                    431:                        {
                    432:                                /* Save as .MSA or .ST image? */
1.1.1.14  root      433:                                if (MSA_FileNameIsMSA(psFileName, true))
1.1.1.16! root      434:                                        bSaved = MSA_WriteDisk(psFileName, EmulationDrives[Drive].pBuffer, EmulationDrives[Drive].nImageBytes);
1.1.1.14  root      435:                                else if (ST_FileNameIsST(psFileName, true))
1.1.1.16! root      436:                                        bSaved = ST_WriteDisk(psFileName, EmulationDrives[Drive].pBuffer, EmulationDrives[Drive].nImageBytes);
1.1.1.14  root      437:                                else if (DIM_FileNameIsDIM(psFileName, true))
1.1.1.16! root      438:                                        bSaved = DIM_WriteDisk(psFileName, EmulationDrives[Drive].pBuffer, EmulationDrives[Drive].nImageBytes);
1.1.1.12  root      439:                                else if (ZIP_FileNameIsZIP(psFileName))
1.1.1.16! root      440:                                        bSaved = ZIP_WriteDisk(psFileName, EmulationDrives[Drive].pBuffer, EmulationDrives[Drive].nImageBytes);
        !           441:                                if (bSaved)
        !           442:                                        Log_Printf(LOG_INFO, "Updated the contents of floppy image '%s'.", psFileName);
        !           443:                                else
        !           444:                                        Log_Printf(LOG_INFO, "Writing of this format failed or not supported, discarded the contents\n of floppy image '%s'.", psFileName);
        !           445:                        } else
        !           446:                                Log_Printf(LOG_INFO, "Writing not possible, discarded the contents of floppy image\n '%s'.", psFileName);
1.1.1.10  root      447:                }
                    448: 
                    449:                /* Inform user that disk has been ejected! */
1.1.1.12  root      450:                Log_Printf(LOG_INFO, "Floppy %c: has been removed from drive.",
                    451:                           'A'+Drive);
                    452: 
1.1.1.14  root      453:                bEjected = true;
1.1.1.10  root      454:        }
                    455: 
                    456:        /* Drive is now empty */
                    457:        if (EmulationDrives[Drive].pBuffer != NULL)
                    458:        {
                    459:                free(EmulationDrives[Drive].pBuffer);
                    460:                EmulationDrives[Drive].pBuffer = NULL;
                    461:        }
1.1.1.12  root      462: 
1.1.1.13  root      463:        EmulationDrives[Drive].sFileName[0] = '\0';
1.1.1.10  root      464:        EmulationDrives[Drive].nImageBytes = 0;
1.1.1.14  root      465:        EmulationDrives[Drive].bDiskInserted = false;
                    466:        EmulationDrives[Drive].bContentsChanged = false;
                    467:        EmulationDrives[Drive].bOKToSave = false;
1.1.1.12  root      468: 
                    469:        return bEjected;
1.1       root      470: }
                    471: 
1.1.1.2   root      472: 
                    473: /*-----------------------------------------------------------------------*/
1.1.1.11  root      474: /**
                    475:  * Eject all disk image from floppy drives - call when quit.
1.1.1.14  root      476:  * Return true if there was something to eject.
1.1.1.11  root      477:  */
1.1.1.13  root      478: static bool Floppy_EjectBothDrives(void)
1.1       root      479: {
1.1.1.12  root      480:        bool bEjectedA, bEjectedB;
                    481: 
1.1.1.10  root      482:        /* Eject disk images from drives 'A' and 'B' */
1.1.1.12  root      483:        bEjectedA = Floppy_EjectDiskFromDrive(0);
                    484:        bEjectedB = Floppy_EjectDiskFromDrive(1);
                    485: 
                    486:        return bEjectedA || bEjectedB;
1.1       root      487: }
                    488: 
1.1.1.2   root      489: 
                    490: /*-----------------------------------------------------------------------*/
1.1.1.11  root      491: /**
                    492:  * Double-check information read from boot-sector as this is sometimes found to
                    493:  * be incorrect. The .ST image file should be divisible by the sector size and
                    494:  * sectors per track.
                    495:  * NOTE - Pass information from boot-sector to this function (if we can't
                    496:  * decide we leave it alone).
                    497:  */
1.1.1.9   root      498: static void Floppy_DoubleCheckFormat(long nDiskSize, Uint16 *pnSides, Uint16 *pnSectorsPerTrack)
1.1       root      499: {
1.1.1.10  root      500:        int nSectorsPerTrack;
                    501:        long TotalSectors;
1.1       root      502: 
1.1.1.10  root      503:        /* Now guess at number of sides */
                    504:        if (nDiskSize < (500*1024))                    /* Is size is >500k assume 2 sides to disk! */
                    505:                *pnSides = 1;
                    506:        else
                    507:                *pnSides = 2;
                    508: 
                    509:        /* And Sectors Per Track(always 512 bytes per sector) */
                    510:        TotalSectors = nDiskSize/512;                 /* # Sectors on disk image */
                    511:        /* Does this match up with what we've read from boot-sector? */
                    512:        nSectorsPerTrack = *pnSectorsPerTrack;
                    513:        if (nSectorsPerTrack==0)                      /* Check valid, default to 9 */
                    514:                nSectorsPerTrack = 9;
                    515:        if ((TotalSectors%nSectorsPerTrack)!=0)
                    516:        {
                    517:                /* No, we have an invalid boot-sector - re-calculate from disk size */
                    518:                if ((TotalSectors%9)==0)                    /* Work in this order.... */
                    519:                        *pnSectorsPerTrack = 9;
                    520:                else if ((TotalSectors%10)==0)
                    521:                        *pnSectorsPerTrack = 10;
                    522:                else if ((TotalSectors%11)==0)
                    523:                        *pnSectorsPerTrack = 11;
                    524:                else if ((TotalSectors%12)==0)
                    525:                        *pnSectorsPerTrack = 12;
                    526:        }
                    527:        /* else unknown, assume boot-sector is correct!!! */
1.1       root      528: }
                    529: 
1.1.1.2   root      530: 
                    531: /*-----------------------------------------------------------------------*/
1.1.1.11  root      532: /**
                    533:  * Find details of disk image. We need to do this via a function as sometimes the boot-block
                    534:  * is not actually correct with the image - some demos/game disks have incorrect bytes in the
                    535:  * boot sector and this attempts to find the correct values.
                    536:  */
1.1.1.9   root      537: void Floppy_FindDiskDetails(const Uint8 *pBuffer, int nImageBytes,
1.1.1.12  root      538:                             Uint16 *pnSectorsPerTrack, Uint16 *pnSides)
1.1       root      539: {
1.1.1.10  root      540:        Uint16 nSectorsPerTrack, nSides, nSectors;
1.1       root      541: 
1.1.1.10  root      542:        /* First do check to find number of sectors and bytes per sector */
                    543:        nSectorsPerTrack = SDL_SwapLE16(*(const Uint16 *)(pBuffer+24));   /* SPT */
                    544:        nSides = SDL_SwapLE16(*(const Uint16 *)(pBuffer+26));             /* SIDE */
                    545:        nSectors = pBuffer[19] | (pBuffer[20] << 8);                      /* total sectors */
                    546: 
                    547:        /* If the number of sectors announced is incorrect, the boot-sector may
                    548:         * contain incorrect information, eg the 'Eat.st' demo, or wrongly imaged
                    549:         * single/double sided floppies... */
                    550:        if (nSectors != nImageBytes/512)
                    551:                Floppy_DoubleCheckFormat(nImageBytes, &nSides, &nSectorsPerTrack);
                    552: 
                    553:        /* And set values */
                    554:        if (pnSectorsPerTrack)
                    555:                *pnSectorsPerTrack = nSectorsPerTrack;
                    556:        if (pnSides)
                    557:                *pnSides = nSides;
1.1       root      558: }
                    559: 
1.1.1.2   root      560: 
                    561: /*-----------------------------------------------------------------------*/
1.1.1.11  root      562: /**
                    563:  * Read sectors from floppy disk image, return TRUE if all OK
                    564:  * NOTE Pass -ve as Count to read whole track
                    565:  */
1.1.1.12  root      566: bool Floppy_ReadSectors(int Drive, Uint8 *pBuffer, Uint16 Sector,
                    567:                         Uint16 Track, Uint16 Side, short Count,
1.1.1.9   root      568:                         int *pnSectorsPerTrack)
1.1       root      569: {
1.1.1.10  root      570:        Uint8 *pDiskBuffer;
1.1.1.12  root      571:        Uint16 nSectorsPerTrack, nSides, nBytesPerTrack;
1.1.1.10  root      572:        long Offset;
                    573:        int nImageTracks;
                    574: 
                    575:        /* Do we have a disk in our drive? */
                    576:        if (EmulationDrives[Drive].bDiskInserted)
                    577:        {
                    578:                /* Looks good */
                    579:                pDiskBuffer = EmulationDrives[Drive].pBuffer;
                    580: 
                    581:                /* Find #sides and #sectors per track */
                    582:                Floppy_FindDiskDetails(EmulationDrives[Drive].pBuffer,EmulationDrives[Drive].nImageBytes,&nSectorsPerTrack,&nSides);
                    583:                nImageTracks = ((EmulationDrives[Drive].nImageBytes / NUMBYTESPERSECTOR) / nSectorsPerTrack) / nSides;
                    584: 
                    585:                /* Need to read whole track? */
                    586:                if (Count<0)
                    587:                        Count = nSectorsPerTrack;
                    588:                /* Write back number of sector per track */
                    589:                if (pnSectorsPerTrack)
                    590:                        *pnSectorsPerTrack = nSectorsPerTrack;
                    591: 
                    592:                /* Debug check as if we read over the end of a track we read into side 2! */
                    593:                if (Count > nSectorsPerTrack)
                    594:                {
                    595:                        Log_Printf(LOG_DEBUG, "Floppy_ReadSectors: reading over single track\n");
                    596:                }
                    597: 
                    598:                /* Check that the side number (0 or 1) does not exceed the amount of sides (1 or 2).
                    599:                 * (E.g. some games like Drakkhen or Bolo can load additional data from the
                    600:                 * second disk side, but they also work with single side floppy drives) */
                    601:                if (Side >= nSides)
                    602:                {
                    603:                        Log_Printf(LOG_DEBUG, "Floppy_ReadSectors: Program tries to read from side %i "
                    604:                                   "of a disk image with %i sides!\n", Side+1, nSides);
1.1.1.14  root      605:                        return false;
1.1.1.10  root      606:                }
                    607: 
                    608:                /* Check if track number is in range */
                    609:                if (Track >= nImageTracks)
                    610:                {
                    611:                        Log_Printf(LOG_DEBUG, "Floppy_ReadSectors: Program tries to read from track %i "
                    612:                                   "of a disk image with only %i tracks!\n", Track, nImageTracks);
1.1.1.14  root      613:                        return false;
1.1.1.10  root      614:                }
                    615: 
                    616:                /* Check if sector number is in range */
                    617:                if (Sector <= 0 || Sector > nSectorsPerTrack)
                    618:                {
                    619:                        Log_Printf(LOG_DEBUG, "Floppy_ReadSectors: Program tries to read from sector %i "
                    620:                                   "of a disk image with %i sectors per track!\n", Sector, nSectorsPerTrack);
1.1.1.14  root      621:                        return false;
1.1.1.10  root      622:                }
                    623: 
                    624:                /* Seek to sector */
                    625:                nBytesPerTrack = NUMBYTESPERSECTOR*nSectorsPerTrack;
                    626:                Offset = nBytesPerTrack*Side;                 /* First seek to side */
                    627:                Offset += (nBytesPerTrack*nSides)*Track;      /* Then seek to track */
                    628:                Offset += (NUMBYTESPERSECTOR*(Sector-1));     /* And finally to sector */
1.1.1.6   root      629: 
1.1.1.10  root      630:                /* Read sectors (usually 512 bytes per sector) */
                    631:                memcpy(pBuffer, pDiskBuffer+Offset, (int)Count*NUMBYTESPERSECTOR);
1.1       root      632: 
1.1.1.14  root      633:                return true;
1.1.1.10  root      634:        }
1.1       root      635: 
1.1.1.14  root      636:        return false;
1.1       root      637: }
                    638: 
1.1.1.2   root      639: 
                    640: /*-----------------------------------------------------------------------*/
1.1.1.11  root      641: /**
                    642:  * Write sectors from floppy disk image, return TRUE if all OK
                    643:  * NOTE Pass -ve as Count to write whole track
                    644:  */
1.1.1.12  root      645: bool Floppy_WriteSectors(int Drive, Uint8 *pBuffer, Uint16 Sector,
                    646:                          Uint16 Track, Uint16 Side, short Count,
1.1.1.9   root      647:                          int *pnSectorsPerTrack)
1.1       root      648: {
1.1.1.10  root      649:        Uint8 *pDiskBuffer;
1.1.1.12  root      650:        Uint16 nSectorsPerTrack, nSides, nBytesPerTrack;
1.1.1.10  root      651:        long Offset;
                    652:        int nImageTracks;
                    653: 
                    654:        /* Do we have a writable disk in our drive? */
                    655:        if (EmulationDrives[Drive].bDiskInserted && !Floppy_IsWriteProtected(Drive))
                    656:        {
                    657:                /* Looks good */
                    658:                pDiskBuffer = EmulationDrives[Drive].pBuffer;
                    659: 
                    660:                /* Find #sides and #sectors per track */
                    661:                Floppy_FindDiskDetails(EmulationDrives[Drive].pBuffer,EmulationDrives[Drive].nImageBytes,&nSectorsPerTrack,&nSides);
                    662:                nImageTracks = ((EmulationDrives[Drive].nImageBytes / NUMBYTESPERSECTOR) / nSectorsPerTrack) / nSides;
                    663: 
                    664:                /* Need to write whole track? */
                    665:                if (Count<0)
                    666:                        Count = nSectorsPerTrack;
                    667:                /* Write back number of sector per track */
                    668:                if (pnSectorsPerTrack)
                    669:                        *pnSectorsPerTrack = nSectorsPerTrack;
                    670: 
                    671:                /* Debug check as if we write over the end of a track we write into side 2! */
                    672:                if (Count > nSectorsPerTrack)
                    673:                {
                    674:                        Log_Printf(LOG_DEBUG, "Floppy_WriteSectors: writing over single track\n");
                    675:                }
                    676: 
                    677:                /* Check that the side number (0 or 1) does not exceed the amount of sides (1 or 2). */
                    678:                if (Side >= nSides)
                    679:                {
                    680:                        Log_Printf(LOG_DEBUG, "Floppy_WriteSectors: Program tries to write to side %i "
                    681:                                   "of a disk image with %i sides!\n", Side+1, nSides);
1.1.1.14  root      682:                        return false;
1.1.1.10  root      683:                }
                    684: 
                    685:                /* Check if track number is in range */
                    686:                if (Track >= nImageTracks)
                    687:                {
                    688:                        Log_Printf(LOG_DEBUG, "Floppy_WriteSectors: Program tries to write to track %i "
                    689:                                   "of a disk image with only %i tracks!\n", Track, nImageTracks);
1.1.1.14  root      690:                        return false;
1.1.1.10  root      691:                }
                    692: 
                    693:                /* Check if sector number is in range */
                    694:                if (Sector <= 0 || Sector > nSectorsPerTrack)
                    695:                {
                    696:                        Log_Printf(LOG_DEBUG, "Floppy_WriteSectors: Program tries to write to sector %i "
                    697:                                   "of a disk image with %i sectors per track!\n", Sector, nSectorsPerTrack);
1.1.1.14  root      698:                        return false;
1.1.1.10  root      699:                }
                    700: 
                    701:                /* Seek to sector */
                    702:                nBytesPerTrack = NUMBYTESPERSECTOR*nSectorsPerTrack;
                    703:                Offset = nBytesPerTrack*Side;               /* First seek to side */
                    704:                Offset += (nBytesPerTrack*nSides)*Track;    /* Then seek to track */
                    705:                Offset += (NUMBYTESPERSECTOR*(Sector-1));   /* And finally to sector */
                    706: 
                    707:                /* Write sectors (usually 512 bytes per sector) */
                    708:                memcpy(pDiskBuffer+Offset, pBuffer, (int)Count*NUMBYTESPERSECTOR);
                    709:                /* And set 'changed' flag */
1.1.1.14  root      710:                EmulationDrives[Drive].bContentsChanged = true;
1.1       root      711: 
1.1.1.14  root      712:                return true;
1.1.1.10  root      713:        }
1.1       root      714: 
1.1.1.14  root      715:        return false;
1.1       root      716: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.