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

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: 
        !           138:        if (ACSI_EMU_ON || ConfigureParams.HardDisk.bUseIdeHardDiskImage)
        !           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:                        {
        !           149:                                nBootDrive = emudrives[i]->hd_letter;
        !           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       root      294: 
1.1.1.12  root      295:        /* setting to empty or "none" ejects */
                    296:        if (!*pszFileName || strcasecmp(pszFileName, "none") == 0)
                    297:        {
                    298:                return Floppy_SetDiskFileNameNone(Drive);
                    299:        }
1.1.1.11  root      300:        /* See if file exists, and if not, get/add correct extension */
1.1.1.12  root      301:        if (!File_Exists(pszFileName))
1.1.1.11  root      302:                filename = File_FindPossibleExtFileName(pszFileName, pszDiskImageNameExts);
                    303:        else
                    304:                filename = strdup(pszFileName);
1.1.1.12  root      305:        if (!filename)
                    306:        {
                    307:                Log_AlertDlg(LOG_INFO, "Image '%s' not found", pszFileName);
                    308:                return NULL;
                    309:        }
                    310: 
                    311:        /* If we insert a disk into Drive A, should we try to put disk 2 into drive B? */
                    312:        if (Drive == 0 && ConfigureParams.DiskImage.bAutoInsertDiskB)
                    313:        {
                    314:                /* Attempt to make up second filename, eg was 'auto_100a' to 'auto_100b' */
                    315:                char *szDiskBFileName = Floppy_CreateDiskBFileName(filename);
                    316:                if (szDiskBFileName)
                    317:                {
                    318:                        /* recurse with Drive B */
                    319:                        Floppy_SetDiskFileName(1, szDiskBFileName, pszZipPath);
                    320:                        free(szDiskBFileName);
                    321:                }
                    322:        }
                    323: 
                    324:        /* do the changes */
                    325:        assert(Drive >= 0 && Drive < MAX_FLOPPYDRIVES);
                    326:        if (pszZipPath)
                    327:                strcpy(ConfigureParams.DiskImage.szDiskZipPath[Drive], pszZipPath);
                    328:        else
                    329:                ConfigureParams.DiskImage.szDiskZipPath[Drive][0] = '\0';
                    330:        strcpy(ConfigureParams.DiskImage.szDiskFileName[Drive], filename);
                    331:        free(filename);
                    332:        //File_MakeAbsoluteName(ConfigureParams.DiskImage.szDiskFileName[Drive]);
                    333:        return ConfigureParams.DiskImage.szDiskFileName[Drive];
                    334: }
                    335: 
                    336: /*-----------------------------------------------------------------------*/
                    337: /**
                    338:  * Insert previously set disk file image into floppy drive.
                    339:  * The WHOLE image is copied into Hatari drive buffers, and
                    340:  * uncompressed if necessary.
                    341:  * Return TRUE on success, false otherwise.
                    342:  */
                    343: bool Floppy_InsertDiskIntoDrive(int Drive)
                    344: {
                    345:        long nImageBytes = 0;
                    346:        char *filename;
                    347: 
                    348:        /* Eject disk, if one is inserted (doesn't inform user) */
                    349:        assert(Drive >= 0 && Drive < MAX_FLOPPYDRIVES);
                    350:        Floppy_EjectDiskFromDrive(Drive);
                    351: 
                    352:        filename = ConfigureParams.DiskImage.szDiskFileName[Drive];
                    353:        if (!filename[0])
                    354:        {
1.1.1.14  root      355:                return true; /* only do eject */
1.1.1.12  root      356:        }
                    357:        if (!File_Exists(filename))
                    358:        {
                    359:                Log_AlertDlg(LOG_INFO, "Image '%s' not found", filename);
1.1.1.14  root      360:                return false;
1.1.1.12  root      361:        }
                    362: 
1.1.1.10  root      363:        /* Check disk image type and read the file: */
1.1.1.14  root      364:        if (MSA_FileNameIsMSA(filename, true))
1.1.1.11  root      365:                EmulationDrives[Drive].pBuffer = MSA_ReadDisk(filename, &nImageBytes);
1.1.1.14  root      366:        else if (ST_FileNameIsST(filename, true))
1.1.1.11  root      367:                EmulationDrives[Drive].pBuffer = ST_ReadDisk(filename, &nImageBytes);
1.1.1.14  root      368:        else if (DIM_FileNameIsDIM(filename, true))
1.1.1.11  root      369:                EmulationDrives[Drive].pBuffer = DIM_ReadDisk(filename, &nImageBytes);
                    370:        else if (ZIP_FileNameIsZIP(filename))
1.1.1.12  root      371:        {
                    372:                const char *zippath = ConfigureParams.DiskImage.szDiskZipPath[Drive];
                    373:                EmulationDrives[Drive].pBuffer = ZIP_ReadDisk(filename, zippath, &nImageBytes);
                    374:        }
1.1.1.11  root      375: 
                    376:        if (EmulationDrives[Drive].pBuffer == NULL)
                    377:        {
1.1.1.14  root      378:                return false;
1.1.1.11  root      379:        }
1.1.1.13  root      380: 
                    381:        /* Store image filename (required for ejecting the disk later!) */
                    382:        strcpy(EmulationDrives[Drive].sFileName, filename);
                    383: 
                    384:        /* Store size and set drive states */
1.1.1.11  root      385:        EmulationDrives[Drive].nImageBytes = nImageBytes;
1.1.1.14  root      386:        EmulationDrives[Drive].bDiskInserted = true;
                    387:        EmulationDrives[Drive].bContentsChanged = false;
                    388:        EmulationDrives[Drive].bMediaChanged = true;
1.1.1.11  root      389:        EmulationDrives[Drive].bOKToSave = Floppy_IsBootSectorOK(Drive);
1.1.1.12  root      390:        Log_Printf(LOG_INFO, "Inserted disk '%s' to drive %c:.",
                    391:                   filename, 'A'+Drive);
1.1.1.14  root      392:        return true;
1.1       root      393: }
                    394: 
1.1.1.2   root      395: 
                    396: /*-----------------------------------------------------------------------*/
1.1.1.11  root      397: /**
                    398:  * Eject disk from floppy drive, save contents back to PCs hard-drive if
                    399:  * they have been changed.
1.1.1.14  root      400:  * Return true if there was something to eject.
1.1.1.11  root      401:  */
1.1.1.12  root      402: bool Floppy_EjectDiskFromDrive(int Drive)
1.1       root      403: {
1.1.1.14  root      404:        bool bEjected = false;
1.1.1.12  root      405: 
1.1.1.10  root      406:        /* Does our drive have a disk in? */
                    407:        if (EmulationDrives[Drive].bDiskInserted)
                    408:        {
1.1.1.13  root      409:                char *psFileName = EmulationDrives[Drive].sFileName;
1.1.1.12  root      410: 
1.1.1.10  root      411:                /* OK, has contents changed? If so, need to save */
                    412:                if (EmulationDrives[Drive].bContentsChanged)
                    413:                {
                    414:                        /* Is OK to save image (if boot-sector is bad, don't allow a save) */
                    415:                        if (EmulationDrives[Drive].bOKToSave && !Floppy_IsWriteProtected(Drive))
                    416:                        {
1.1.1.13  root      417:                                Log_Printf(LOG_INFO, "Flush contents to floppy image '%s'.", psFileName);
1.1.1.10  root      418:                                /* Save as .MSA or .ST image? */
1.1.1.14  root      419:                                if (MSA_FileNameIsMSA(psFileName, true))
1.1.1.12  root      420:                                        MSA_WriteDisk(psFileName, EmulationDrives[Drive].pBuffer, EmulationDrives[Drive].nImageBytes);
1.1.1.14  root      421:                                else if (ST_FileNameIsST(psFileName, true))
1.1.1.12  root      422:                                        ST_WriteDisk(psFileName, EmulationDrives[Drive].pBuffer, EmulationDrives[Drive].nImageBytes);
1.1.1.14  root      423:                                else if (DIM_FileNameIsDIM(psFileName, true))
1.1.1.12  root      424:                                        DIM_WriteDisk(psFileName, EmulationDrives[Drive].pBuffer, EmulationDrives[Drive].nImageBytes);
                    425:                                else if (ZIP_FileNameIsZIP(psFileName))
                    426:                                        ZIP_WriteDisk(psFileName, EmulationDrives[Drive].pBuffer, EmulationDrives[Drive].nImageBytes);
1.1.1.10  root      427:                        }
                    428:                }
                    429: 
                    430:                /* Inform user that disk has been ejected! */
1.1.1.12  root      431:                Log_Printf(LOG_INFO, "Floppy %c: has been removed from drive.",
                    432:                           'A'+Drive);
                    433: 
1.1.1.14  root      434:                bEjected = true;
1.1.1.10  root      435:        }
                    436: 
                    437:        /* Drive is now empty */
                    438:        if (EmulationDrives[Drive].pBuffer != NULL)
                    439:        {
                    440:                free(EmulationDrives[Drive].pBuffer);
                    441:                EmulationDrives[Drive].pBuffer = NULL;
                    442:        }
1.1.1.12  root      443: 
1.1.1.13  root      444:        EmulationDrives[Drive].sFileName[0] = '\0';
1.1.1.10  root      445:        EmulationDrives[Drive].nImageBytes = 0;
1.1.1.14  root      446:        EmulationDrives[Drive].bDiskInserted = false;
                    447:        EmulationDrives[Drive].bContentsChanged = false;
                    448:        EmulationDrives[Drive].bOKToSave = false;
1.1.1.12  root      449: 
                    450:        return bEjected;
1.1       root      451: }
                    452: 
1.1.1.2   root      453: 
                    454: /*-----------------------------------------------------------------------*/
1.1.1.11  root      455: /**
                    456:  * Eject all disk image from floppy drives - call when quit.
1.1.1.14  root      457:  * Return true if there was something to eject.
1.1.1.11  root      458:  */
1.1.1.13  root      459: static bool Floppy_EjectBothDrives(void)
1.1       root      460: {
1.1.1.12  root      461:        bool bEjectedA, bEjectedB;
                    462: 
1.1.1.10  root      463:        /* Eject disk images from drives 'A' and 'B' */
1.1.1.12  root      464:        bEjectedA = Floppy_EjectDiskFromDrive(0);
                    465:        bEjectedB = Floppy_EjectDiskFromDrive(1);
                    466: 
                    467:        return bEjectedA || bEjectedB;
1.1       root      468: }
                    469: 
1.1.1.2   root      470: 
                    471: /*-----------------------------------------------------------------------*/
1.1.1.11  root      472: /**
                    473:  * Double-check information read from boot-sector as this is sometimes found to
                    474:  * be incorrect. The .ST image file should be divisible by the sector size and
                    475:  * sectors per track.
                    476:  * NOTE - Pass information from boot-sector to this function (if we can't
                    477:  * decide we leave it alone).
                    478:  */
1.1.1.9   root      479: static void Floppy_DoubleCheckFormat(long nDiskSize, Uint16 *pnSides, Uint16 *pnSectorsPerTrack)
1.1       root      480: {
1.1.1.10  root      481:        int nSectorsPerTrack;
                    482:        long TotalSectors;
1.1       root      483: 
1.1.1.10  root      484:        /* Now guess at number of sides */
                    485:        if (nDiskSize < (500*1024))                    /* Is size is >500k assume 2 sides to disk! */
                    486:                *pnSides = 1;
                    487:        else
                    488:                *pnSides = 2;
                    489: 
                    490:        /* And Sectors Per Track(always 512 bytes per sector) */
                    491:        TotalSectors = nDiskSize/512;                 /* # Sectors on disk image */
                    492:        /* Does this match up with what we've read from boot-sector? */
                    493:        nSectorsPerTrack = *pnSectorsPerTrack;
                    494:        if (nSectorsPerTrack==0)                      /* Check valid, default to 9 */
                    495:                nSectorsPerTrack = 9;
                    496:        if ((TotalSectors%nSectorsPerTrack)!=0)
                    497:        {
                    498:                /* No, we have an invalid boot-sector - re-calculate from disk size */
                    499:                if ((TotalSectors%9)==0)                    /* Work in this order.... */
                    500:                        *pnSectorsPerTrack = 9;
                    501:                else if ((TotalSectors%10)==0)
                    502:                        *pnSectorsPerTrack = 10;
                    503:                else if ((TotalSectors%11)==0)
                    504:                        *pnSectorsPerTrack = 11;
                    505:                else if ((TotalSectors%12)==0)
                    506:                        *pnSectorsPerTrack = 12;
                    507:        }
                    508:        /* else unknown, assume boot-sector is correct!!! */
1.1       root      509: }
                    510: 
1.1.1.2   root      511: 
                    512: /*-----------------------------------------------------------------------*/
1.1.1.11  root      513: /**
                    514:  * Find details of disk image. We need to do this via a function as sometimes the boot-block
                    515:  * is not actually correct with the image - some demos/game disks have incorrect bytes in the
                    516:  * boot sector and this attempts to find the correct values.
                    517:  */
1.1.1.9   root      518: void Floppy_FindDiskDetails(const Uint8 *pBuffer, int nImageBytes,
1.1.1.12  root      519:                             Uint16 *pnSectorsPerTrack, Uint16 *pnSides)
1.1       root      520: {
1.1.1.10  root      521:        Uint16 nSectorsPerTrack, nSides, nSectors;
1.1       root      522: 
1.1.1.10  root      523:        /* First do check to find number of sectors and bytes per sector */
                    524:        nSectorsPerTrack = SDL_SwapLE16(*(const Uint16 *)(pBuffer+24));   /* SPT */
                    525:        nSides = SDL_SwapLE16(*(const Uint16 *)(pBuffer+26));             /* SIDE */
                    526:        nSectors = pBuffer[19] | (pBuffer[20] << 8);                      /* total sectors */
                    527: 
                    528:        /* If the number of sectors announced is incorrect, the boot-sector may
                    529:         * contain incorrect information, eg the 'Eat.st' demo, or wrongly imaged
                    530:         * single/double sided floppies... */
                    531:        if (nSectors != nImageBytes/512)
                    532:                Floppy_DoubleCheckFormat(nImageBytes, &nSides, &nSectorsPerTrack);
                    533: 
                    534:        /* And set values */
                    535:        if (pnSectorsPerTrack)
                    536:                *pnSectorsPerTrack = nSectorsPerTrack;
                    537:        if (pnSides)
                    538:                *pnSides = nSides;
1.1       root      539: }
                    540: 
1.1.1.2   root      541: 
                    542: /*-----------------------------------------------------------------------*/
1.1.1.11  root      543: /**
                    544:  * Read sectors from floppy disk image, return TRUE if all OK
                    545:  * NOTE Pass -ve as Count to read whole track
                    546:  */
1.1.1.12  root      547: bool Floppy_ReadSectors(int Drive, Uint8 *pBuffer, Uint16 Sector,
                    548:                         Uint16 Track, Uint16 Side, short Count,
1.1.1.9   root      549:                         int *pnSectorsPerTrack)
1.1       root      550: {
1.1.1.10  root      551:        Uint8 *pDiskBuffer;
1.1.1.12  root      552:        Uint16 nSectorsPerTrack, nSides, nBytesPerTrack;
1.1.1.10  root      553:        long Offset;
                    554:        int nImageTracks;
                    555: 
                    556:        /* Do we have a disk in our drive? */
                    557:        if (EmulationDrives[Drive].bDiskInserted)
                    558:        {
                    559:                /* Looks good */
                    560:                pDiskBuffer = EmulationDrives[Drive].pBuffer;
                    561: 
                    562:                /* Find #sides and #sectors per track */
                    563:                Floppy_FindDiskDetails(EmulationDrives[Drive].pBuffer,EmulationDrives[Drive].nImageBytes,&nSectorsPerTrack,&nSides);
                    564:                nImageTracks = ((EmulationDrives[Drive].nImageBytes / NUMBYTESPERSECTOR) / nSectorsPerTrack) / nSides;
                    565: 
                    566:                /* Need to read whole track? */
                    567:                if (Count<0)
                    568:                        Count = nSectorsPerTrack;
                    569:                /* Write back number of sector per track */
                    570:                if (pnSectorsPerTrack)
                    571:                        *pnSectorsPerTrack = nSectorsPerTrack;
                    572: 
                    573:                /* Debug check as if we read over the end of a track we read into side 2! */
                    574:                if (Count > nSectorsPerTrack)
                    575:                {
                    576:                        Log_Printf(LOG_DEBUG, "Floppy_ReadSectors: reading over single track\n");
                    577:                }
                    578: 
                    579:                /* Check that the side number (0 or 1) does not exceed the amount of sides (1 or 2).
                    580:                 * (E.g. some games like Drakkhen or Bolo can load additional data from the
                    581:                 * second disk side, but they also work with single side floppy drives) */
                    582:                if (Side >= nSides)
                    583:                {
                    584:                        Log_Printf(LOG_DEBUG, "Floppy_ReadSectors: Program tries to read from side %i "
                    585:                                   "of a disk image with %i sides!\n", Side+1, nSides);
1.1.1.14  root      586:                        return false;
1.1.1.10  root      587:                }
                    588: 
                    589:                /* Check if track number is in range */
                    590:                if (Track >= nImageTracks)
                    591:                {
                    592:                        Log_Printf(LOG_DEBUG, "Floppy_ReadSectors: Program tries to read from track %i "
                    593:                                   "of a disk image with only %i tracks!\n", Track, nImageTracks);
1.1.1.14  root      594:                        return false;
1.1.1.10  root      595:                }
                    596: 
                    597:                /* Check if sector number is in range */
                    598:                if (Sector <= 0 || Sector > nSectorsPerTrack)
                    599:                {
                    600:                        Log_Printf(LOG_DEBUG, "Floppy_ReadSectors: Program tries to read from sector %i "
                    601:                                   "of a disk image with %i sectors per track!\n", Sector, nSectorsPerTrack);
1.1.1.14  root      602:                        return false;
1.1.1.10  root      603:                }
                    604: 
                    605:                /* Seek to sector */
                    606:                nBytesPerTrack = NUMBYTESPERSECTOR*nSectorsPerTrack;
                    607:                Offset = nBytesPerTrack*Side;                 /* First seek to side */
                    608:                Offset += (nBytesPerTrack*nSides)*Track;      /* Then seek to track */
                    609:                Offset += (NUMBYTESPERSECTOR*(Sector-1));     /* And finally to sector */
1.1.1.6   root      610: 
1.1.1.10  root      611:                /* Read sectors (usually 512 bytes per sector) */
                    612:                memcpy(pBuffer, pDiskBuffer+Offset, (int)Count*NUMBYTESPERSECTOR);
1.1       root      613: 
1.1.1.14  root      614:                return true;
1.1.1.10  root      615:        }
1.1       root      616: 
1.1.1.14  root      617:        return false;
1.1       root      618: }
                    619: 
1.1.1.2   root      620: 
                    621: /*-----------------------------------------------------------------------*/
1.1.1.11  root      622: /**
                    623:  * Write sectors from floppy disk image, return TRUE if all OK
                    624:  * NOTE Pass -ve as Count to write whole track
                    625:  */
1.1.1.12  root      626: bool Floppy_WriteSectors(int Drive, Uint8 *pBuffer, Uint16 Sector,
                    627:                          Uint16 Track, Uint16 Side, short Count,
1.1.1.9   root      628:                          int *pnSectorsPerTrack)
1.1       root      629: {
1.1.1.10  root      630:        Uint8 *pDiskBuffer;
1.1.1.12  root      631:        Uint16 nSectorsPerTrack, nSides, nBytesPerTrack;
1.1.1.10  root      632:        long Offset;
                    633:        int nImageTracks;
                    634: 
                    635:        /* Do we have a writable disk in our drive? */
                    636:        if (EmulationDrives[Drive].bDiskInserted && !Floppy_IsWriteProtected(Drive))
                    637:        {
                    638:                /* Looks good */
                    639:                pDiskBuffer = EmulationDrives[Drive].pBuffer;
                    640: 
                    641:                /* Find #sides and #sectors per track */
                    642:                Floppy_FindDiskDetails(EmulationDrives[Drive].pBuffer,EmulationDrives[Drive].nImageBytes,&nSectorsPerTrack,&nSides);
                    643:                nImageTracks = ((EmulationDrives[Drive].nImageBytes / NUMBYTESPERSECTOR) / nSectorsPerTrack) / nSides;
                    644: 
                    645:                /* Need to write whole track? */
                    646:                if (Count<0)
                    647:                        Count = nSectorsPerTrack;
                    648:                /* Write back number of sector per track */
                    649:                if (pnSectorsPerTrack)
                    650:                        *pnSectorsPerTrack = nSectorsPerTrack;
                    651: 
                    652:                /* Debug check as if we write over the end of a track we write into side 2! */
                    653:                if (Count > nSectorsPerTrack)
                    654:                {
                    655:                        Log_Printf(LOG_DEBUG, "Floppy_WriteSectors: writing over single track\n");
                    656:                }
                    657: 
                    658:                /* Check that the side number (0 or 1) does not exceed the amount of sides (1 or 2). */
                    659:                if (Side >= nSides)
                    660:                {
                    661:                        Log_Printf(LOG_DEBUG, "Floppy_WriteSectors: Program tries to write to side %i "
                    662:                                   "of a disk image with %i sides!\n", Side+1, nSides);
1.1.1.14  root      663:                        return false;
1.1.1.10  root      664:                }
                    665: 
                    666:                /* Check if track number is in range */
                    667:                if (Track >= nImageTracks)
                    668:                {
                    669:                        Log_Printf(LOG_DEBUG, "Floppy_WriteSectors: Program tries to write to track %i "
                    670:                                   "of a disk image with only %i tracks!\n", Track, nImageTracks);
1.1.1.14  root      671:                        return false;
1.1.1.10  root      672:                }
                    673: 
                    674:                /* Check if sector number is in range */
                    675:                if (Sector <= 0 || Sector > nSectorsPerTrack)
                    676:                {
                    677:                        Log_Printf(LOG_DEBUG, "Floppy_WriteSectors: Program tries to write to sector %i "
                    678:                                   "of a disk image with %i sectors per track!\n", Sector, nSectorsPerTrack);
1.1.1.14  root      679:                        return false;
1.1.1.10  root      680:                }
                    681: 
                    682:                /* Seek to sector */
                    683:                nBytesPerTrack = NUMBYTESPERSECTOR*nSectorsPerTrack;
                    684:                Offset = nBytesPerTrack*Side;               /* First seek to side */
                    685:                Offset += (nBytesPerTrack*nSides)*Track;    /* Then seek to track */
                    686:                Offset += (NUMBYTESPERSECTOR*(Sector-1));   /* And finally to sector */
                    687: 
                    688:                /* Write sectors (usually 512 bytes per sector) */
                    689:                memcpy(pDiskBuffer+Offset, pBuffer, (int)Count*NUMBYTESPERSECTOR);
                    690:                /* And set 'changed' flag */
1.1.1.14  root      691:                EmulationDrives[Drive].bContentsChanged = true;
1.1       root      692: 
1.1.1.14  root      693:                return true;
1.1.1.10  root      694:        }
1.1       root      695: 
1.1.1.14  root      696:        return false;
1.1       root      697: }

unix.superglobalmegacorp.com

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