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

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.10  root      131:        /* Boot from hard drive if user wants this and HD emulation is turned on */
                    132:        if ((ACSI_EMU_ON || GEMDOS_EMU_ON) && ConfigureParams.HardDisk.bBootFromHardDisk)
                    133:                nBootDrive = 2;  /* Drive C */
                    134:        else
                    135:                nBootDrive = 0;  /* Drive A */
1.1       root      136: }
                    137: 
1.1.1.2   root      138: 
                    139: /*-----------------------------------------------------------------------*/
1.1.1.11  root      140: /**
                    141:  * Test if disk image is write protected. Write protection can be configured
                    142:  * in the GUI. When set to "automatic", we check the file permissions of the
                    143:  * floppy disk image to decide.
                    144:  */
1.1.1.12  root      145: bool Floppy_IsWriteProtected(int Drive)
1.1.1.8   root      146: {
1.1.1.10  root      147:        if (ConfigureParams.DiskImage.nWriteProtection == WRITEPROT_OFF)
                    148:        {
1.1.1.14! root      149:                return false;
1.1.1.10  root      150:        }
                    151:        else if (ConfigureParams.DiskImage.nWriteProtection == WRITEPROT_ON)
                    152:        {
1.1.1.14! root      153:                return true;
1.1.1.10  root      154:        }
                    155:        else
                    156:        {
                    157:                struct stat FloppyStat;
                    158:                /* Check whether disk is writable */
1.1.1.13  root      159:                if (stat(EmulationDrives[Drive].sFileName, &FloppyStat) == 0
1.1.1.12  root      160:                    && (FloppyStat.st_mode & S_IWUSR))
1.1.1.14! root      161:                        return false;
1.1.1.10  root      162:                else
1.1.1.14! root      163:                        return true;
1.1.1.10  root      164:        }
1.1.1.8   root      165: }
                    166: 
                    167: 
                    168: /*-----------------------------------------------------------------------*/
1.1.1.11  root      169: /**
                    170:  * Test disk image for valid boot-sector.
                    171:  * It has been noticed that some disks, eg blank images made by the MakeDisk
                    172:  * utility or PaCifiST emulator fill in the boot-sector with incorrect information.
                    173:  * Such images cannot be read correctly using a real ST, and also Hatari.
                    174:  * To try and prevent data loss, we check for this error and flag the drive so
                    175:  * the image will not be saved back to the file.
                    176:  */
1.1.1.12  root      177: static bool Floppy_IsBootSectorOK(int Drive)
1.1       root      178: {
1.1.1.10  root      179:        Uint8 *pDiskBuffer;
1.1       root      180: 
1.1.1.10  root      181:        /* Does our drive have a disk in? */
                    182:        if (EmulationDrives[Drive].bDiskInserted)
                    183:        {
                    184:                pDiskBuffer = EmulationDrives[Drive].pBuffer;
                    185: 
                    186:                /* Check SPC (byte 13) for !=0 value. If is '0', invalid image and Hatari
                    187:                 * won't be-able to read (nor will a real ST)! */
                    188:                if (pDiskBuffer[13] != 0)
                    189:                {
1.1.1.14! root      190:                        return true;      /* Disk sector is OK! */
1.1.1.10  root      191:                }
                    192:                else
                    193:                {
                    194:                        Log_AlertDlg(LOG_WARN, "Disk in drive %c: maybe suffers from the Pacifist/Makedisk bug.\n"
                    195:                                     "If it does not work, please repair the disk first!\n", 'A' + Drive);
                    196:                }
                    197:        }
1.1       root      198: 
1.1.1.14! root      199:        return false;         /* Bad sector */
1.1       root      200: }
                    201: 
1.1.1.2   root      202: 
                    203: /*-----------------------------------------------------------------------*/
1.1.1.11  root      204: /**
                    205:  * Try to create disk B filename, eg 'auto_100a' becomes 'auto_100b'
                    206:  * Return new filename if think we should try, otherwise NULL
1.1.1.12  root      207:  *
                    208:  * TODO: doesn't work with images in ZIP archives
1.1.1.11  root      209:  */
                    210: static char* Floppy_CreateDiskBFileName(const char *pSrcFileName)
1.1       root      211: {
1.1.1.10  root      212:        char *szDir, *szName, *szExt;
1.1.1.12  root      213: 
1.1.1.10  root      214:        /* Allocate temporary memory for strings: */
                    215:        szDir = malloc(3 * FILENAME_MAX);
                    216:        if (!szDir)
                    217:        {
                    218:                perror("Floppy_CreateDiskBFileName");
1.1.1.14! root      219:                return false;
1.1.1.10  root      220:        }
                    221:        szName = szDir + FILENAME_MAX;
                    222:        szExt = szName + FILENAME_MAX;
                    223: 
                    224:        /* So, first split name into parts */
1.1.1.11  root      225:        File_SplitPath(pSrcFileName, szDir, szName, szExt);
1.1.1.10  root      226: 
                    227:        /* All OK? */
                    228:        if (strlen(szName) > 0)
                    229:        {
1.1.1.12  root      230:                char *last = &(szName[strlen(szName)-1]);
                    231:                /* Now, did filename end with an 'A' or 'a' */
                    232:                if (*last == 'A' || *last == 'a')
1.1.1.10  root      233:                {
1.1.1.11  root      234:                        char *szFull;
1.1.1.10  root      235:                        /* Change 'A' to a 'B' */
1.1.1.12  root      236:                        *last += 1;
1.1.1.10  root      237:                        /* And re-build name into destination */
1.1.1.11  root      238:                        szFull = File_MakePath(szDir, szName, szExt);
                    239:                        if (szFull)
                    240:                        {
                    241:                                /* Does file exist? */
                    242:                                if (File_Exists(szFull))
                    243:                                {
                    244:                                        free(szDir);
                    245:                                        return szFull;
                    246:                                }
                    247:                                free(szFull);
                    248:                        }
1.1.1.10  root      249:                }
                    250:        }
                    251:        free(szDir);
1.1.1.11  root      252:        return NULL;
1.1       root      253: }
                    254: 
1.1.1.2   root      255: 
                    256: /*-----------------------------------------------------------------------*/
1.1.1.11  root      257: /**
1.1.1.12  root      258:  * Set floppy image to be ejected
                    259:  */
                    260: const char* Floppy_SetDiskFileNameNone(int Drive)
                    261: {
                    262:        assert(Drive >= 0 && Drive < MAX_FLOPPYDRIVES);
                    263:        ConfigureParams.DiskImage.szDiskFileName[Drive][0] = '\0';
                    264:        return ConfigureParams.DiskImage.szDiskFileName[Drive];
1.1.1.6   root      265: }
                    266: 
1.1.1.12  root      267: /*-----------------------------------------------------------------------*/
                    268: /**
                    269:  * Set given floppy drive image file name and handle
                    270:  * different image extensions.
                    271:  * Return corrected file name on success and NULL on failure.
1.1.1.11  root      272:  */
1.1.1.12  root      273: const char* Floppy_SetDiskFileName(int Drive, const char *pszFileName, const char *pszZipPath)
1.1.1.6   root      274: {
1.1.1.11  root      275:        char *filename;
1.1       root      276: 
1.1.1.12  root      277:        /* setting to empty or "none" ejects */
                    278:        if (!*pszFileName || strcasecmp(pszFileName, "none") == 0)
                    279:        {
                    280:                return Floppy_SetDiskFileNameNone(Drive);
                    281:        }
1.1.1.11  root      282:        /* See if file exists, and if not, get/add correct extension */
1.1.1.12  root      283:        if (!File_Exists(pszFileName))
1.1.1.11  root      284:                filename = File_FindPossibleExtFileName(pszFileName, pszDiskImageNameExts);
                    285:        else
                    286:                filename = strdup(pszFileName);
1.1.1.12  root      287:        if (!filename)
                    288:        {
                    289:                Log_AlertDlg(LOG_INFO, "Image '%s' not found", pszFileName);
                    290:                return NULL;
                    291:        }
                    292: 
                    293:        /* If we insert a disk into Drive A, should we try to put disk 2 into drive B? */
                    294:        if (Drive == 0 && ConfigureParams.DiskImage.bAutoInsertDiskB)
                    295:        {
                    296:                /* Attempt to make up second filename, eg was 'auto_100a' to 'auto_100b' */
                    297:                char *szDiskBFileName = Floppy_CreateDiskBFileName(filename);
                    298:                if (szDiskBFileName)
                    299:                {
                    300:                        /* recurse with Drive B */
                    301:                        Floppy_SetDiskFileName(1, szDiskBFileName, pszZipPath);
                    302:                        free(szDiskBFileName);
                    303:                }
                    304:        }
                    305: 
                    306:        /* do the changes */
                    307:        assert(Drive >= 0 && Drive < MAX_FLOPPYDRIVES);
                    308:        if (pszZipPath)
                    309:                strcpy(ConfigureParams.DiskImage.szDiskZipPath[Drive], pszZipPath);
                    310:        else
                    311:                ConfigureParams.DiskImage.szDiskZipPath[Drive][0] = '\0';
                    312:        strcpy(ConfigureParams.DiskImage.szDiskFileName[Drive], filename);
                    313:        free(filename);
                    314:        //File_MakeAbsoluteName(ConfigureParams.DiskImage.szDiskFileName[Drive]);
                    315:        return ConfigureParams.DiskImage.szDiskFileName[Drive];
                    316: }
                    317: 
                    318: /*-----------------------------------------------------------------------*/
                    319: /**
                    320:  * Insert previously set disk file image into floppy drive.
                    321:  * The WHOLE image is copied into Hatari drive buffers, and
                    322:  * uncompressed if necessary.
                    323:  * Return TRUE on success, false otherwise.
                    324:  */
                    325: bool Floppy_InsertDiskIntoDrive(int Drive)
                    326: {
                    327:        long nImageBytes = 0;
                    328:        char *filename;
                    329: 
                    330:        /* Eject disk, if one is inserted (doesn't inform user) */
                    331:        assert(Drive >= 0 && Drive < MAX_FLOPPYDRIVES);
                    332:        Floppy_EjectDiskFromDrive(Drive);
                    333: 
                    334:        filename = ConfigureParams.DiskImage.szDiskFileName[Drive];
                    335:        if (!filename[0])
                    336:        {
1.1.1.14! root      337:                return true; /* only do eject */
1.1.1.12  root      338:        }
                    339:        if (!File_Exists(filename))
                    340:        {
                    341:                Log_AlertDlg(LOG_INFO, "Image '%s' not found", filename);
1.1.1.14! root      342:                return false;
1.1.1.12  root      343:        }
                    344: 
1.1.1.10  root      345:        /* Check disk image type and read the file: */
1.1.1.14! root      346:        if (MSA_FileNameIsMSA(filename, true))
1.1.1.11  root      347:                EmulationDrives[Drive].pBuffer = MSA_ReadDisk(filename, &nImageBytes);
1.1.1.14! root      348:        else if (ST_FileNameIsST(filename, true))
1.1.1.11  root      349:                EmulationDrives[Drive].pBuffer = ST_ReadDisk(filename, &nImageBytes);
1.1.1.14! root      350:        else if (DIM_FileNameIsDIM(filename, true))
1.1.1.11  root      351:                EmulationDrives[Drive].pBuffer = DIM_ReadDisk(filename, &nImageBytes);
                    352:        else if (ZIP_FileNameIsZIP(filename))
1.1.1.12  root      353:        {
                    354:                const char *zippath = ConfigureParams.DiskImage.szDiskZipPath[Drive];
                    355:                EmulationDrives[Drive].pBuffer = ZIP_ReadDisk(filename, zippath, &nImageBytes);
                    356:        }
1.1.1.11  root      357: 
                    358:        if (EmulationDrives[Drive].pBuffer == NULL)
                    359:        {
1.1.1.14! root      360:                return false;
1.1.1.11  root      361:        }
1.1.1.13  root      362: 
                    363:        /* Store image filename (required for ejecting the disk later!) */
                    364:        strcpy(EmulationDrives[Drive].sFileName, filename);
                    365: 
                    366:        /* Store size and set drive states */
1.1.1.11  root      367:        EmulationDrives[Drive].nImageBytes = nImageBytes;
1.1.1.14! root      368:        EmulationDrives[Drive].bDiskInserted = true;
        !           369:        EmulationDrives[Drive].bContentsChanged = false;
        !           370:        EmulationDrives[Drive].bMediaChanged = true;
1.1.1.11  root      371:        EmulationDrives[Drive].bOKToSave = Floppy_IsBootSectorOK(Drive);
1.1.1.12  root      372:        Log_Printf(LOG_INFO, "Inserted disk '%s' to drive %c:.",
                    373:                   filename, 'A'+Drive);
1.1.1.14! root      374:        return true;
1.1       root      375: }
                    376: 
1.1.1.2   root      377: 
                    378: /*-----------------------------------------------------------------------*/
1.1.1.11  root      379: /**
                    380:  * Eject disk from floppy drive, save contents back to PCs hard-drive if
                    381:  * they have been changed.
1.1.1.14! root      382:  * Return true if there was something to eject.
1.1.1.11  root      383:  */
1.1.1.12  root      384: bool Floppy_EjectDiskFromDrive(int Drive)
1.1       root      385: {
1.1.1.14! root      386:        bool bEjected = false;
1.1.1.12  root      387: 
1.1.1.10  root      388:        /* Does our drive have a disk in? */
                    389:        if (EmulationDrives[Drive].bDiskInserted)
                    390:        {
1.1.1.13  root      391:                char *psFileName = EmulationDrives[Drive].sFileName;
1.1.1.12  root      392: 
1.1.1.10  root      393:                /* OK, has contents changed? If so, need to save */
                    394:                if (EmulationDrives[Drive].bContentsChanged)
                    395:                {
                    396:                        /* Is OK to save image (if boot-sector is bad, don't allow a save) */
                    397:                        if (EmulationDrives[Drive].bOKToSave && !Floppy_IsWriteProtected(Drive))
                    398:                        {
1.1.1.13  root      399:                                Log_Printf(LOG_INFO, "Flush contents to floppy image '%s'.", psFileName);
1.1.1.10  root      400:                                /* Save as .MSA or .ST image? */
1.1.1.14! root      401:                                if (MSA_FileNameIsMSA(psFileName, true))
1.1.1.12  root      402:                                        MSA_WriteDisk(psFileName, EmulationDrives[Drive].pBuffer, EmulationDrives[Drive].nImageBytes);
1.1.1.14! root      403:                                else if (ST_FileNameIsST(psFileName, true))
1.1.1.12  root      404:                                        ST_WriteDisk(psFileName, EmulationDrives[Drive].pBuffer, EmulationDrives[Drive].nImageBytes);
1.1.1.14! root      405:                                else if (DIM_FileNameIsDIM(psFileName, true))
1.1.1.12  root      406:                                        DIM_WriteDisk(psFileName, EmulationDrives[Drive].pBuffer, EmulationDrives[Drive].nImageBytes);
                    407:                                else if (ZIP_FileNameIsZIP(psFileName))
                    408:                                        ZIP_WriteDisk(psFileName, EmulationDrives[Drive].pBuffer, EmulationDrives[Drive].nImageBytes);
1.1.1.10  root      409:                        }
                    410:                }
                    411: 
                    412:                /* Inform user that disk has been ejected! */
1.1.1.12  root      413:                Log_Printf(LOG_INFO, "Floppy %c: has been removed from drive.",
                    414:                           'A'+Drive);
                    415: 
1.1.1.14! root      416:                bEjected = true;
1.1.1.10  root      417:        }
                    418: 
                    419:        /* Drive is now empty */
                    420:        if (EmulationDrives[Drive].pBuffer != NULL)
                    421:        {
                    422:                free(EmulationDrives[Drive].pBuffer);
                    423:                EmulationDrives[Drive].pBuffer = NULL;
                    424:        }
1.1.1.12  root      425: 
1.1.1.13  root      426:        EmulationDrives[Drive].sFileName[0] = '\0';
1.1.1.10  root      427:        EmulationDrives[Drive].nImageBytes = 0;
1.1.1.14! root      428:        EmulationDrives[Drive].bDiskInserted = false;
        !           429:        EmulationDrives[Drive].bContentsChanged = false;
        !           430:        EmulationDrives[Drive].bOKToSave = false;
1.1.1.12  root      431: 
                    432:        return bEjected;
1.1       root      433: }
                    434: 
1.1.1.2   root      435: 
                    436: /*-----------------------------------------------------------------------*/
1.1.1.11  root      437: /**
                    438:  * Eject all disk image from floppy drives - call when quit.
1.1.1.14! root      439:  * Return true if there was something to eject.
1.1.1.11  root      440:  */
1.1.1.13  root      441: static bool Floppy_EjectBothDrives(void)
1.1       root      442: {
1.1.1.12  root      443:        bool bEjectedA, bEjectedB;
                    444: 
1.1.1.10  root      445:        /* Eject disk images from drives 'A' and 'B' */
1.1.1.12  root      446:        bEjectedA = Floppy_EjectDiskFromDrive(0);
                    447:        bEjectedB = Floppy_EjectDiskFromDrive(1);
                    448: 
                    449:        return bEjectedA || bEjectedB;
1.1       root      450: }
                    451: 
1.1.1.2   root      452: 
                    453: /*-----------------------------------------------------------------------*/
1.1.1.11  root      454: /**
                    455:  * Double-check information read from boot-sector as this is sometimes found to
                    456:  * be incorrect. The .ST image file should be divisible by the sector size and
                    457:  * sectors per track.
                    458:  * NOTE - Pass information from boot-sector to this function (if we can't
                    459:  * decide we leave it alone).
                    460:  */
1.1.1.9   root      461: static void Floppy_DoubleCheckFormat(long nDiskSize, Uint16 *pnSides, Uint16 *pnSectorsPerTrack)
1.1       root      462: {
1.1.1.10  root      463:        int nSectorsPerTrack;
                    464:        long TotalSectors;
1.1       root      465: 
1.1.1.10  root      466:        /* Now guess at number of sides */
                    467:        if (nDiskSize < (500*1024))                    /* Is size is >500k assume 2 sides to disk! */
                    468:                *pnSides = 1;
                    469:        else
                    470:                *pnSides = 2;
                    471: 
                    472:        /* And Sectors Per Track(always 512 bytes per sector) */
                    473:        TotalSectors = nDiskSize/512;                 /* # Sectors on disk image */
                    474:        /* Does this match up with what we've read from boot-sector? */
                    475:        nSectorsPerTrack = *pnSectorsPerTrack;
                    476:        if (nSectorsPerTrack==0)                      /* Check valid, default to 9 */
                    477:                nSectorsPerTrack = 9;
                    478:        if ((TotalSectors%nSectorsPerTrack)!=0)
                    479:        {
                    480:                /* No, we have an invalid boot-sector - re-calculate from disk size */
                    481:                if ((TotalSectors%9)==0)                    /* Work in this order.... */
                    482:                        *pnSectorsPerTrack = 9;
                    483:                else if ((TotalSectors%10)==0)
                    484:                        *pnSectorsPerTrack = 10;
                    485:                else if ((TotalSectors%11)==0)
                    486:                        *pnSectorsPerTrack = 11;
                    487:                else if ((TotalSectors%12)==0)
                    488:                        *pnSectorsPerTrack = 12;
                    489:        }
                    490:        /* else unknown, assume boot-sector is correct!!! */
1.1       root      491: }
                    492: 
1.1.1.2   root      493: 
                    494: /*-----------------------------------------------------------------------*/
1.1.1.11  root      495: /**
                    496:  * Find details of disk image. We need to do this via a function as sometimes the boot-block
                    497:  * is not actually correct with the image - some demos/game disks have incorrect bytes in the
                    498:  * boot sector and this attempts to find the correct values.
                    499:  */
1.1.1.9   root      500: void Floppy_FindDiskDetails(const Uint8 *pBuffer, int nImageBytes,
1.1.1.12  root      501:                             Uint16 *pnSectorsPerTrack, Uint16 *pnSides)
1.1       root      502: {
1.1.1.10  root      503:        Uint16 nSectorsPerTrack, nSides, nSectors;
1.1       root      504: 
1.1.1.10  root      505:        /* First do check to find number of sectors and bytes per sector */
                    506:        nSectorsPerTrack = SDL_SwapLE16(*(const Uint16 *)(pBuffer+24));   /* SPT */
                    507:        nSides = SDL_SwapLE16(*(const Uint16 *)(pBuffer+26));             /* SIDE */
                    508:        nSectors = pBuffer[19] | (pBuffer[20] << 8);                      /* total sectors */
                    509: 
                    510:        /* If the number of sectors announced is incorrect, the boot-sector may
                    511:         * contain incorrect information, eg the 'Eat.st' demo, or wrongly imaged
                    512:         * single/double sided floppies... */
                    513:        if (nSectors != nImageBytes/512)
                    514:                Floppy_DoubleCheckFormat(nImageBytes, &nSides, &nSectorsPerTrack);
                    515: 
                    516:        /* And set values */
                    517:        if (pnSectorsPerTrack)
                    518:                *pnSectorsPerTrack = nSectorsPerTrack;
                    519:        if (pnSides)
                    520:                *pnSides = nSides;
1.1       root      521: }
                    522: 
1.1.1.2   root      523: 
                    524: /*-----------------------------------------------------------------------*/
1.1.1.11  root      525: /**
                    526:  * Read sectors from floppy disk image, return TRUE if all OK
                    527:  * NOTE Pass -ve as Count to read whole track
                    528:  */
1.1.1.12  root      529: bool Floppy_ReadSectors(int Drive, Uint8 *pBuffer, Uint16 Sector,
                    530:                         Uint16 Track, Uint16 Side, short Count,
1.1.1.9   root      531:                         int *pnSectorsPerTrack)
1.1       root      532: {
1.1.1.10  root      533:        Uint8 *pDiskBuffer;
1.1.1.12  root      534:        Uint16 nSectorsPerTrack, nSides, nBytesPerTrack;
1.1.1.10  root      535:        long Offset;
                    536:        int nImageTracks;
                    537: 
                    538:        /* Do we have a disk in our drive? */
                    539:        if (EmulationDrives[Drive].bDiskInserted)
                    540:        {
                    541:                /* Looks good */
                    542:                pDiskBuffer = EmulationDrives[Drive].pBuffer;
                    543: 
                    544:                /* Find #sides and #sectors per track */
                    545:                Floppy_FindDiskDetails(EmulationDrives[Drive].pBuffer,EmulationDrives[Drive].nImageBytes,&nSectorsPerTrack,&nSides);
                    546:                nImageTracks = ((EmulationDrives[Drive].nImageBytes / NUMBYTESPERSECTOR) / nSectorsPerTrack) / nSides;
                    547: 
                    548:                /* Need to read whole track? */
                    549:                if (Count<0)
                    550:                        Count = nSectorsPerTrack;
                    551:                /* Write back number of sector per track */
                    552:                if (pnSectorsPerTrack)
                    553:                        *pnSectorsPerTrack = nSectorsPerTrack;
                    554: 
                    555:                /* Debug check as if we read over the end of a track we read into side 2! */
                    556:                if (Count > nSectorsPerTrack)
                    557:                {
                    558:                        Log_Printf(LOG_DEBUG, "Floppy_ReadSectors: reading over single track\n");
                    559:                }
                    560: 
                    561:                /* Check that the side number (0 or 1) does not exceed the amount of sides (1 or 2).
                    562:                 * (E.g. some games like Drakkhen or Bolo can load additional data from the
                    563:                 * second disk side, but they also work with single side floppy drives) */
                    564:                if (Side >= nSides)
                    565:                {
                    566:                        Log_Printf(LOG_DEBUG, "Floppy_ReadSectors: Program tries to read from side %i "
                    567:                                   "of a disk image with %i sides!\n", Side+1, nSides);
1.1.1.14! root      568:                        return false;
1.1.1.10  root      569:                }
                    570: 
                    571:                /* Check if track number is in range */
                    572:                if (Track >= nImageTracks)
                    573:                {
                    574:                        Log_Printf(LOG_DEBUG, "Floppy_ReadSectors: Program tries to read from track %i "
                    575:                                   "of a disk image with only %i tracks!\n", Track, nImageTracks);
1.1.1.14! root      576:                        return false;
1.1.1.10  root      577:                }
                    578: 
                    579:                /* Check if sector number is in range */
                    580:                if (Sector <= 0 || Sector > nSectorsPerTrack)
                    581:                {
                    582:                        Log_Printf(LOG_DEBUG, "Floppy_ReadSectors: Program tries to read from sector %i "
                    583:                                   "of a disk image with %i sectors per track!\n", Sector, nSectorsPerTrack);
1.1.1.14! root      584:                        return false;
1.1.1.10  root      585:                }
                    586: 
                    587:                /* Seek to sector */
                    588:                nBytesPerTrack = NUMBYTESPERSECTOR*nSectorsPerTrack;
                    589:                Offset = nBytesPerTrack*Side;                 /* First seek to side */
                    590:                Offset += (nBytesPerTrack*nSides)*Track;      /* Then seek to track */
                    591:                Offset += (NUMBYTESPERSECTOR*(Sector-1));     /* And finally to sector */
1.1.1.6   root      592: 
1.1.1.10  root      593:                /* Read sectors (usually 512 bytes per sector) */
                    594:                memcpy(pBuffer, pDiskBuffer+Offset, (int)Count*NUMBYTESPERSECTOR);
1.1       root      595: 
1.1.1.14! root      596:                return true;
1.1.1.10  root      597:        }
1.1       root      598: 
1.1.1.14! root      599:        return false;
1.1       root      600: }
                    601: 
1.1.1.2   root      602: 
                    603: /*-----------------------------------------------------------------------*/
1.1.1.11  root      604: /**
                    605:  * Write sectors from floppy disk image, return TRUE if all OK
                    606:  * NOTE Pass -ve as Count to write whole track
                    607:  */
1.1.1.12  root      608: bool Floppy_WriteSectors(int Drive, Uint8 *pBuffer, Uint16 Sector,
                    609:                          Uint16 Track, Uint16 Side, short Count,
1.1.1.9   root      610:                          int *pnSectorsPerTrack)
1.1       root      611: {
1.1.1.10  root      612:        Uint8 *pDiskBuffer;
1.1.1.12  root      613:        Uint16 nSectorsPerTrack, nSides, nBytesPerTrack;
1.1.1.10  root      614:        long Offset;
                    615:        int nImageTracks;
                    616: 
                    617:        /* Do we have a writable disk in our drive? */
                    618:        if (EmulationDrives[Drive].bDiskInserted && !Floppy_IsWriteProtected(Drive))
                    619:        {
                    620:                /* Looks good */
                    621:                pDiskBuffer = EmulationDrives[Drive].pBuffer;
                    622: 
                    623:                /* Find #sides and #sectors per track */
                    624:                Floppy_FindDiskDetails(EmulationDrives[Drive].pBuffer,EmulationDrives[Drive].nImageBytes,&nSectorsPerTrack,&nSides);
                    625:                nImageTracks = ((EmulationDrives[Drive].nImageBytes / NUMBYTESPERSECTOR) / nSectorsPerTrack) / nSides;
                    626: 
                    627:                /* Need to write whole track? */
                    628:                if (Count<0)
                    629:                        Count = nSectorsPerTrack;
                    630:                /* Write back number of sector per track */
                    631:                if (pnSectorsPerTrack)
                    632:                        *pnSectorsPerTrack = nSectorsPerTrack;
                    633: 
                    634:                /* Debug check as if we write over the end of a track we write into side 2! */
                    635:                if (Count > nSectorsPerTrack)
                    636:                {
                    637:                        Log_Printf(LOG_DEBUG, "Floppy_WriteSectors: writing over single track\n");
                    638:                }
                    639: 
                    640:                /* Check that the side number (0 or 1) does not exceed the amount of sides (1 or 2). */
                    641:                if (Side >= nSides)
                    642:                {
                    643:                        Log_Printf(LOG_DEBUG, "Floppy_WriteSectors: Program tries to write to side %i "
                    644:                                   "of a disk image with %i sides!\n", Side+1, nSides);
1.1.1.14! root      645:                        return false;
1.1.1.10  root      646:                }
                    647: 
                    648:                /* Check if track number is in range */
                    649:                if (Track >= nImageTracks)
                    650:                {
                    651:                        Log_Printf(LOG_DEBUG, "Floppy_WriteSectors: Program tries to write to track %i "
                    652:                                   "of a disk image with only %i tracks!\n", Track, nImageTracks);
1.1.1.14! root      653:                        return false;
1.1.1.10  root      654:                }
                    655: 
                    656:                /* Check if sector number is in range */
                    657:                if (Sector <= 0 || Sector > nSectorsPerTrack)
                    658:                {
                    659:                        Log_Printf(LOG_DEBUG, "Floppy_WriteSectors: Program tries to write to sector %i "
                    660:                                   "of a disk image with %i sectors per track!\n", Sector, nSectorsPerTrack);
1.1.1.14! root      661:                        return false;
1.1.1.10  root      662:                }
                    663: 
                    664:                /* Seek to sector */
                    665:                nBytesPerTrack = NUMBYTESPERSECTOR*nSectorsPerTrack;
                    666:                Offset = nBytesPerTrack*Side;               /* First seek to side */
                    667:                Offset += (nBytesPerTrack*nSides)*Track;    /* Then seek to track */
                    668:                Offset += (NUMBYTESPERSECTOR*(Sector-1));   /* And finally to sector */
                    669: 
                    670:                /* Write sectors (usually 512 bytes per sector) */
                    671:                memcpy(pDiskBuffer+Offset, pBuffer, (int)Count*NUMBYTESPERSECTOR);
                    672:                /* And set 'changed' flag */
1.1.1.14! root      673:                EmulationDrives[Drive].bContentsChanged = true;
1.1       root      674: 
1.1.1.14! root      675:                return true;
1.1.1.10  root      676:        }
1.1       root      677: 
1.1.1.14! root      678:        return false;
1.1       root      679: }

unix.superglobalmegacorp.com

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