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

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

unix.superglobalmegacorp.com

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