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

1.1       root        1: /*
1.1.1.5   root        2:   Hatari - floppy.c
1.1       root        3: 
1.1.1.19  root        4:   This file is distributed under the GNU General Public License, version 2
                      5:   or at your option any later version. Read the file gpl.txt for details.
1.1.1.5   root        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       root       32: #include "file.h"
                     33: #include "floppy.h"
1.1.1.9   root       34: #include "gemdos.h"
                     35: #include "hdc.h"
1.1.1.8   root       36: #include "log.h"
1.1       root       37: #include "memorySnapShot.h"
                     38: #include "st.h"
1.1.1.20  root       39: #include "msa.h"
                     40: #include "dim.h"
                     41: #include "floppy_ipf.h"
                     42: #include "floppy_stx.h"
1.1.1.6   root       43: #include "zip.h"
1.1.1.18  root       44: #include "screen.h"
1.1.1.24! root       45: #include "str.h"
1.1.1.18  root       46: #include "video.h"
1.1.1.20  root       47: #include "fdc.h"
1.1       root       48: 
1.1.1.10  root       49: 
1.1.1.12  root       50: /* Emulation drive details, eg FileName, Inserted, Changed etc... */
                     51: EMULATION_DRIVE EmulationDrives[MAX_FLOPPYDRIVES];
                     52: /* Drive A is the default */
                     53: int nBootDrive = 0;
1.1       root       54: 
1.1.1.18  root       55: 
1.1.1.9   root       56: /* Possible disk image file extensions to scan for */
1.1.1.10  root       57: static const char * const pszDiskImageNameExts[] =
1.1.1.5   root       58: {
1.1.1.10  root       59:        ".msa",
                     60:        ".st",
                     61:        ".dim",
1.1.1.20  root       62:        ".ipf",
                     63:        ".raw",
                     64:        ".ctr",
                     65:        ".stx",
1.1.1.10  root       66:        NULL
1.1       root       67: };
                     68: 
                     69: 
1.1.1.13  root       70: /* local functions */
1.1.1.18  root       71: static bool    Floppy_EjectBothDrives(void);
                     72: static void    Floppy_DriveTransitionSetState ( int Drive , int State );
1.1.1.13  root       73: 
                     74: 
1.1.1.2   root       75: /*-----------------------------------------------------------------------*/
1.1.1.11  root       76: /**
                     77:  * Initialize emulation floppy drives
                     78:  */
1.1       root       79: void Floppy_Init(void)
                     80: {
1.1.1.10  root       81:        int i;
1.1       root       82: 
1.1.1.10  root       83:        /* Clear drive structures */
1.1.1.12  root       84:        for (i = 0; i < MAX_FLOPPYDRIVES; i++)
1.1.1.10  root       85:        {
1.1.1.12  root       86:                /* Clear structs and if floppies available, insert them */
1.1.1.10  root       87:                memset(&EmulationDrives[i], 0, sizeof(EMULATION_DRIVE));
1.1.1.12  root       88:                if (strlen(ConfigureParams.DiskImage.szDiskFileName[i]) > 0)
                     89:                        Floppy_InsertDiskIntoDrive(i);
1.1.1.10  root       90:        }
1.1       root       91: }
                     92: 
1.1.1.2   root       93: 
                     94: /*-----------------------------------------------------------------------*/
1.1.1.11  root       95: /**
                     96:  * UnInitialize drives
                     97:  */
1.1       root       98: void Floppy_UnInit(void)
                     99: {
1.1.1.10  root      100:        Floppy_EjectBothDrives();
1.1       root      101: }
                    102: 
1.1.1.2   root      103: 
                    104: /*-----------------------------------------------------------------------*/
1.1.1.11  root      105: /**
1.1.1.18  root      106:  * Called on Warm/Cold Reset
                    107:  */
                    108: void Floppy_Reset(void)
                    109: {
                    110:        int     i;
                    111: 
                    112:        /* Cancel any pending disk change transitions */
                    113:        for (i = 0; i < MAX_FLOPPYDRIVES; i++)
                    114:        {
                    115:                EmulationDrives[i].TransitionState1 = 0;
                    116:                EmulationDrives[i].TransitionState2 = 0;
                    117:        }
                    118: }
                    119: 
                    120: 
                    121: /*-----------------------------------------------------------------------*/
                    122: /**
1.1.1.11  root      123:  * Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type)
                    124:  */
1.1.1.12  root      125: void Floppy_MemorySnapShot_Capture(bool bSave)
1.1       root      126: {
1.1.1.10  root      127:        int i;
1.1       root      128: 
1.1.1.10  root      129:        /* If restoring then eject old drives first! */
                    130:        if (!bSave)
                    131:                Floppy_EjectBothDrives();
                    132: 
                    133:        /* Save/Restore details */
1.1.1.12  root      134:        for (i = 0; i < MAX_FLOPPYDRIVES; i++)
1.1.1.10  root      135:        {
1.1.1.20  root      136:                MemorySnapShot_Store(&EmulationDrives[i].ImageType, sizeof(EmulationDrives[i].ImageType));
1.1.1.10  root      137:                MemorySnapShot_Store(&EmulationDrives[i].bDiskInserted, sizeof(EmulationDrives[i].bDiskInserted));
                    138:                MemorySnapShot_Store(&EmulationDrives[i].nImageBytes, sizeof(EmulationDrives[i].nImageBytes));
                    139:                if (!bSave && EmulationDrives[i].bDiskInserted)
                    140:                {
                    141:                        EmulationDrives[i].pBuffer = malloc(EmulationDrives[i].nImageBytes);
                    142:                        if (!EmulationDrives[i].pBuffer)
                    143:                                perror("Floppy_MemorySnapShot_Capture");
                    144:                }
                    145:                if (EmulationDrives[i].pBuffer)
                    146:                        MemorySnapShot_Store(EmulationDrives[i].pBuffer, EmulationDrives[i].nImageBytes);
1.1.1.13  root      147:                MemorySnapShot_Store(EmulationDrives[i].sFileName, sizeof(EmulationDrives[i].sFileName));
1.1.1.10  root      148:                MemorySnapShot_Store(&EmulationDrives[i].bContentsChanged,sizeof(EmulationDrives[i].bContentsChanged));
                    149:                MemorySnapShot_Store(&EmulationDrives[i].bOKToSave,sizeof(EmulationDrives[i].bOKToSave));
1.1.1.18  root      150:                MemorySnapShot_Store(&EmulationDrives[i].TransitionState1,sizeof(EmulationDrives[i].TransitionState1));
                    151:                MemorySnapShot_Store(&EmulationDrives[i].TransitionState1_VBL,sizeof(EmulationDrives[i].TransitionState1_VBL));
                    152:                MemorySnapShot_Store(&EmulationDrives[i].TransitionState2,sizeof(EmulationDrives[i].TransitionState2));
                    153:                MemorySnapShot_Store(&EmulationDrives[i].TransitionState2_VBL,sizeof(EmulationDrives[i].TransitionState2_VBL));
1.1.1.20  root      154: 
                    155:                /* Because Floppy_EjectBothDrives() was called above before restoring (which cleared */
                    156:                /* FDC_DRIVES[].DiskInserted that was restored just before), we must call FDC_InsertFloppy */
                    157:                /* for each restored drive with an inserted disk to set FDC_DRIVES[].DiskInserted=true */
                    158:                if ( !bSave && ( EmulationDrives[i].bDiskInserted ) )
                    159:                        FDC_InsertFloppy ( i );
1.1.1.10  root      160:        }
1.1       root      161: }
                    162: 
1.1.1.2   root      163: 
                    164: /*-----------------------------------------------------------------------*/
1.1.1.11  root      165: /**
                    166:  * Find which device to boot from (hard drive or floppy).
                    167:  */
1.1       root      168: void Floppy_GetBootDrive(void)
                    169: {
1.1.1.15  root      170:        /* Default to drive A: */
                    171:        nBootDrive = 0;
                    172: 
                    173:        /* Boot only from hard drive if user wants this */
                    174:        if (!ConfigureParams.HardDisk.bBootFromHardDisk)
                    175:                return;
                    176: 
1.1.1.24! root      177:        if (ACSI_EMU_ON || ConfigureParams.Ide[0].bUseDevice)
1.1.1.15  root      178:        {
1.1.1.10  root      179:                nBootDrive = 2;  /* Drive C */
1.1.1.15  root      180:        }
                    181:        else if (GEMDOS_EMU_ON)
                    182:        {
                    183:                int i;
                    184:                for (i = 0; i < MAX_HARDDRIVES; i++)
                    185:                {
                    186:                        if (emudrives[i])
                    187:                        {
1.1.1.16  root      188:                                nBootDrive = emudrives[i]->drive_number;
1.1.1.15  root      189:                                break;
                    190:                        }
                    191:                }
                    192:        }
1.1       root      193: }
                    194: 
1.1.1.2   root      195: 
                    196: /*-----------------------------------------------------------------------*/
1.1.1.11  root      197: /**
                    198:  * Test if disk image is write protected. Write protection can be configured
                    199:  * in the GUI. When set to "automatic", we check the file permissions of the
                    200:  * floppy disk image to decide.
                    201:  */
1.1.1.12  root      202: bool Floppy_IsWriteProtected(int Drive)
1.1.1.8   root      203: {
1.1.1.10  root      204:        if (ConfigureParams.DiskImage.nWriteProtection == WRITEPROT_OFF)
                    205:        {
1.1.1.14  root      206:                return false;
1.1.1.10  root      207:        }
                    208:        else if (ConfigureParams.DiskImage.nWriteProtection == WRITEPROT_ON)
                    209:        {
1.1.1.14  root      210:                return true;
1.1.1.10  root      211:        }
                    212:        else
                    213:        {
                    214:                struct stat FloppyStat;
                    215:                /* Check whether disk is writable */
1.1.1.13  root      216:                if (stat(EmulationDrives[Drive].sFileName, &FloppyStat) == 0
1.1.1.12  root      217:                    && (FloppyStat.st_mode & S_IWUSR))
1.1.1.14  root      218:                        return false;
1.1.1.10  root      219:                else
1.1.1.14  root      220:                        return true;
1.1.1.10  root      221:        }
1.1.1.8   root      222: }
                    223: 
                    224: 
                    225: /*-----------------------------------------------------------------------*/
1.1.1.11  root      226: /**
1.1.1.22  root      227:  * Test disk image for executable boot sector.
                    228:  * The boot sector is executable if the 16 bit sum of its 256 words
                    229:  * gives the value 0x1234.
                    230:  */
                    231: static bool Floppy_IsBootSectorExecutable(int Drive)
                    232: {
                    233:        Uint8 *pDiskBuffer;
                    234:        int     sum , i;
                    235: 
                    236:        if (EmulationDrives[Drive].bDiskInserted)
                    237:        {
                    238:                pDiskBuffer = EmulationDrives[Drive].pBuffer;
                    239: 
                    240:                sum = 0;
                    241:                for ( i=0 ; i<256 ; i++ )
                    242:                {
                    243:                        sum += ( ( *pDiskBuffer << 8 ) + *(pDiskBuffer+1) );
                    244:                        pDiskBuffer += 2;
                    245:                }
                    246: 
                    247:                if ( ( sum & 0xffff ) == FLOPPY_BOOT_SECTOR_EXE_SUM )           /* 0x1234 */
                    248:                        return true;
                    249:        }
                    250: 
                    251:        return false;         /* Not executable */
                    252: }
                    253: 
                    254: 
                    255: /*-----------------------------------------------------------------------*/
                    256: /**
1.1.1.11  root      257:  * Test disk image for valid boot-sector.
                    258:  * It has been noticed that some disks, eg blank images made by the MakeDisk
                    259:  * utility or PaCifiST emulator fill in the boot-sector with incorrect information.
                    260:  * Such images cannot be read correctly using a real ST, and also Hatari.
                    261:  * To try and prevent data loss, we check for this error and flag the drive so
                    262:  * the image will not be saved back to the file.
                    263:  */
1.1.1.12  root      264: static bool Floppy_IsBootSectorOK(int Drive)
1.1       root      265: {
1.1.1.10  root      266:        Uint8 *pDiskBuffer;
1.1       root      267: 
1.1.1.10  root      268:        /* Does our drive have a disk in? */
                    269:        if (EmulationDrives[Drive].bDiskInserted)
                    270:        {
                    271:                pDiskBuffer = EmulationDrives[Drive].pBuffer;
                    272: 
                    273:                /* Check SPC (byte 13) for !=0 value. If is '0', invalid image and Hatari
                    274:                 * won't be-able to read (nor will a real ST)! */
1.1.1.22  root      275:                if ( (pDiskBuffer[13] != 0) ||  ( Floppy_IsBootSectorExecutable ( Drive ) == true ) )
1.1.1.10  root      276:                {
1.1.1.14  root      277:                        return true;      /* Disk sector is OK! */
1.1.1.10  root      278:                }
                    279:                else
                    280:                {
                    281:                        Log_AlertDlg(LOG_WARN, "Disk in drive %c: maybe suffers from the Pacifist/Makedisk bug.\n"
                    282:                                     "If it does not work, please repair the disk first!\n", 'A' + Drive);
                    283:                }
                    284:        }
1.1       root      285: 
1.1.1.14  root      286:        return false;         /* Bad sector */
1.1       root      287: }
                    288: 
1.1.1.2   root      289: 
                    290: /*-----------------------------------------------------------------------*/
1.1.1.11  root      291: /**
                    292:  * Try to create disk B filename, eg 'auto_100a' becomes 'auto_100b'
                    293:  * Return new filename if think we should try, otherwise NULL
1.1.1.12  root      294:  *
                    295:  * TODO: doesn't work with images in ZIP archives
1.1.1.11  root      296:  */
                    297: static char* Floppy_CreateDiskBFileName(const char *pSrcFileName)
1.1       root      298: {
1.1.1.10  root      299:        char *szDir, *szName, *szExt;
1.1.1.12  root      300: 
1.1.1.10  root      301:        /* Allocate temporary memory for strings: */
                    302:        szDir = malloc(3 * FILENAME_MAX);
                    303:        if (!szDir)
                    304:        {
                    305:                perror("Floppy_CreateDiskBFileName");
1.1.1.21  root      306:                return NULL;
1.1.1.10  root      307:        }
                    308:        szName = szDir + FILENAME_MAX;
                    309:        szExt = szName + FILENAME_MAX;
                    310: 
                    311:        /* So, first split name into parts */
1.1.1.11  root      312:        File_SplitPath(pSrcFileName, szDir, szName, szExt);
1.1.1.10  root      313: 
                    314:        /* All OK? */
                    315:        if (strlen(szName) > 0)
                    316:        {
1.1.1.12  root      317:                char *last = &(szName[strlen(szName)-1]);
                    318:                /* Now, did filename end with an 'A' or 'a' */
                    319:                if (*last == 'A' || *last == 'a')
1.1.1.10  root      320:                {
1.1.1.11  root      321:                        char *szFull;
1.1.1.10  root      322:                        /* Change 'A' to a 'B' */
1.1.1.12  root      323:                        *last += 1;
1.1.1.10  root      324:                        /* And re-build name into destination */
1.1.1.11  root      325:                        szFull = File_MakePath(szDir, szName, szExt);
                    326:                        if (szFull)
                    327:                        {
                    328:                                /* Does file exist? */
                    329:                                if (File_Exists(szFull))
                    330:                                {
                    331:                                        free(szDir);
                    332:                                        return szFull;
                    333:                                }
                    334:                                free(szFull);
                    335:                        }
1.1.1.10  root      336:                }
                    337:        }
                    338:        free(szDir);
1.1.1.11  root      339:        return NULL;
1.1       root      340: }
                    341: 
1.1.1.2   root      342: 
                    343: /*-----------------------------------------------------------------------*/
1.1.1.11  root      344: /**
1.1.1.12  root      345:  * Set floppy image to be ejected
                    346:  */
                    347: const char* Floppy_SetDiskFileNameNone(int Drive)
                    348: {
                    349:        assert(Drive >= 0 && Drive < MAX_FLOPPYDRIVES);
                    350:        ConfigureParams.DiskImage.szDiskFileName[Drive][0] = '\0';
                    351:        return ConfigureParams.DiskImage.szDiskFileName[Drive];
1.1.1.6   root      352: }
                    353: 
1.1.1.12  root      354: /*-----------------------------------------------------------------------*/
                    355: /**
                    356:  * Set given floppy drive image file name and handle
                    357:  * different image extensions.
                    358:  * Return corrected file name on success and NULL on failure.
1.1.1.11  root      359:  */
1.1.1.12  root      360: const char* Floppy_SetDiskFileName(int Drive, const char *pszFileName, const char *pszZipPath)
1.1.1.6   root      361: {
1.1.1.11  root      362:        char *filename;
1.1.1.16  root      363:        int i;
1.1       root      364: 
1.1.1.12  root      365:        /* setting to empty or "none" ejects */
                    366:        if (!*pszFileName || strcasecmp(pszFileName, "none") == 0)
                    367:        {
                    368:                return Floppy_SetDiskFileNameNone(Drive);
                    369:        }
1.1.1.11  root      370:        /* See if file exists, and if not, get/add correct extension */
1.1.1.12  root      371:        if (!File_Exists(pszFileName))
1.1.1.11  root      372:                filename = File_FindPossibleExtFileName(pszFileName, pszDiskImageNameExts);
                    373:        else
                    374:                filename = strdup(pszFileName);
1.1.1.12  root      375:        if (!filename)
                    376:        {
                    377:                Log_AlertDlg(LOG_INFO, "Image '%s' not found", pszFileName);
                    378:                return NULL;
                    379:        }
                    380: 
                    381:        /* If we insert a disk into Drive A, should we try to put disk 2 into drive B? */
                    382:        if (Drive == 0 && ConfigureParams.DiskImage.bAutoInsertDiskB)
                    383:        {
                    384:                /* Attempt to make up second filename, eg was 'auto_100a' to 'auto_100b' */
                    385:                char *szDiskBFileName = Floppy_CreateDiskBFileName(filename);
                    386:                if (szDiskBFileName)
                    387:                {
                    388:                        /* recurse with Drive B */
                    389:                        Floppy_SetDiskFileName(1, szDiskBFileName, pszZipPath);
                    390:                        free(szDiskBFileName);
                    391:                }
                    392:        }
                    393: 
1.1.1.16  root      394:        /* validity checks */
1.1.1.12  root      395:        assert(Drive >= 0 && Drive < MAX_FLOPPYDRIVES);
1.1.1.16  root      396:        for (i = 0; i < MAX_FLOPPYDRIVES; i++)
                    397:        {
                    398:                if (i == Drive)
                    399:                        continue;
                    400:                /* prevent inserting same image to multiple drives */
                    401:                if (strcmp(filename, ConfigureParams.DiskImage.szDiskFileName[i]) == 0)
                    402:                {
                    403:                        Log_AlertDlg(LOG_ERROR, "ERROR: Cannot insert same floppy to multiple drives!");
1.1.1.21  root      404:                        free(filename);
1.1.1.16  root      405:                        return NULL;
                    406:                }
                    407:        }
                    408: 
                    409:        /* do the changes */
1.1.1.12  root      410:        if (pszZipPath)
                    411:                strcpy(ConfigureParams.DiskImage.szDiskZipPath[Drive], pszZipPath);
                    412:        else
                    413:                ConfigureParams.DiskImage.szDiskZipPath[Drive][0] = '\0';
1.1.1.24! root      414:        strlcpy(ConfigureParams.DiskImage.szDiskFileName[Drive], filename,
        !           415:                sizeof(ConfigureParams.DiskImage.szDiskFileName[Drive]));
1.1.1.12  root      416:        free(filename);
                    417:        //File_MakeAbsoluteName(ConfigureParams.DiskImage.szDiskFileName[Drive]);
                    418:        return ConfigureParams.DiskImage.szDiskFileName[Drive];
                    419: }
                    420: 
                    421: /*-----------------------------------------------------------------------*/
                    422: /**
1.1.1.18  root      423:  * Update the drive when a disk is inserted or ejected. Depending on the state,
                    424:  * we change the Write Protect bit for the drive (the TOS and other programs
                    425:  * monitor this bit to detect that a disk was changed in the drive ; see fdc.c)
                    426:  * The floppy drive transition can be a single action ("eject" or "insert"), or
                    427:  * two actions ("eject then insert" or "insert then eject").
                    428:  * First action is stored in State1 ; State2 store the second (or last) action.
                    429:  * In case the user eject/insert several disks before returning to emulation,
                    430:  * State1 will contain the first action, and State2 the latest action (intermediate
                    431:  * actions are ignored, as they wouldn't be seen while the emulation is paused).
1.1.1.22  root      432:  * Each action will take FLOPPY_DRIVE_TRANSITION_DELAY_VBL VBLs to execute,
1.1.1.18  root      433:  * see fdc.c for details.
                    434:  */
                    435: static void    Floppy_DriveTransitionSetState ( int Drive , int State )
                    436: {
                    437:        /* First, update State1 and State2 depending on the current VBL number */
                    438:        /* (we discard the return value as we don't want to update FDC.STR now) */
                    439:        Floppy_DriveTransitionUpdateState ( Drive );
                    440: 
                    441:        /* If State1 is not defined yet, we set it */
                    442:        if ( EmulationDrives[Drive].TransitionState1 == 0 )
                    443:        {
                    444:                EmulationDrives[Drive].TransitionState1 = State;
                    445:                EmulationDrives[Drive].TransitionState1_VBL = nVBLs;
                    446:                /* Cancel State2 in case we start a new transition before State2 was over */
                    447:                EmulationDrives[Drive].TransitionState2 = 0;    
                    448:        }
                    449: 
                    450:        /* State1 is already set, so we set State2 */
                    451:        else
                    452:        {
                    453:                /* If State2 == State1, ignore it (eg : two inserts in a row) */
                    454:                if ( EmulationDrives[Drive].TransitionState1 == State )
                    455:                        EmulationDrives[Drive].TransitionState2 = 0;
                    456:                else
                    457:                {
                    458:                        /* Set State2 just after State1 ends */
                    459:                        EmulationDrives[Drive].TransitionState2 = State;
1.1.1.22  root      460:                        EmulationDrives[Drive].TransitionState2_VBL = EmulationDrives[Drive].TransitionState1_VBL + FLOPPY_DRIVE_TRANSITION_DELAY_VBL;
1.1.1.18  root      461:                }
                    462:        }
                    463: //fprintf ( stderr , "drive transition state1 %d %d state2 %d %d\n" ,
                    464: //       EmulationDrives[Drive].TransitionState1 , EmulationDrives[Drive].TransitionState1_VBL,
                    465: //       EmulationDrives[Drive].TransitionState2 , EmulationDrives[Drive].TransitionState2_VBL );
                    466: }
                    467: 
                    468: 
                    469: /*-----------------------------------------------------------------------*/
                    470: /**
                    471:  * When a disk is inserted or ejected, each transition has 2 phases that
                    472:  * lasts FLOPPY_DRIVE_TRANSITION_DELAY_VBL VBLs. This function checks if
                    473:  * we're during one of these transition phases and tells if the Write
                    474:  * Protect signal should be overwritten.
                    475:  * Returns 0 if there's no change, 1 if WPRT should be forced to 1 and
                    476:  * -1 if WPRT should be forced to 0 (see fdc.c for details).
                    477:  */
                    478: int    Floppy_DriveTransitionUpdateState ( int Drive )
                    479: {
                    480:        int     Force = 0;
                    481: 
                    482:        if ( EmulationDrives[Drive].TransitionState1 != 0 )
                    483:        {
1.1.1.22  root      484:                if ( nVBLs >= EmulationDrives[Drive].TransitionState1_VBL + FLOPPY_DRIVE_TRANSITION_DELAY_VBL )
1.1.1.18  root      485:                        EmulationDrives[Drive].TransitionState1 = 0;    /* State1's delay elapsed */
                    486:                else
                    487:                {
                    488:                        if ( EmulationDrives[Drive].TransitionState1 == FLOPPY_DRIVE_TRANSITION_STATE_INSERT )
1.1.1.22  root      489:                                Force = 0;                              /* Insert : keep WPRT */
1.1.1.18  root      490:                        else
1.1.1.22  root      491:                                Force = 1;                              /* Eject : set WPRT */
1.1.1.18  root      492:                }
                    493:        }
                    494: 
                    495:        if ( ( EmulationDrives[Drive].TransitionState2 != 0 )
                    496:          && ( nVBLs >= EmulationDrives[Drive].TransitionState2_VBL ) )
                    497:        {
1.1.1.22  root      498:                if ( nVBLs >= EmulationDrives[Drive].TransitionState2_VBL + FLOPPY_DRIVE_TRANSITION_DELAY_VBL )
1.1.1.18  root      499:                        EmulationDrives[Drive].TransitionState2 = 0;    /* State2's delay elapsed */
                    500:                else
                    501:                {
                    502:                        if ( EmulationDrives[Drive].TransitionState2 == FLOPPY_DRIVE_TRANSITION_STATE_INSERT )
1.1.1.22  root      503:                                Force = 0;                              /* Insert : keep WPRT */
1.1.1.18  root      504:                        else
1.1.1.22  root      505:                                Force = 1;                              /* Eject : set WPRT */
1.1.1.18  root      506:                }
                    507:        }
                    508: 
                    509: 
                    510:        return Force;
                    511: }
                    512: 
                    513: 
                    514: /*-----------------------------------------------------------------------*/
                    515: /**
1.1.1.12  root      516:  * Insert previously set disk file image into floppy drive.
                    517:  * The WHOLE image is copied into Hatari drive buffers, and
                    518:  * uncompressed if necessary.
                    519:  * Return TRUE on success, false otherwise.
                    520:  */
                    521: bool Floppy_InsertDiskIntoDrive(int Drive)
                    522: {
1.1.1.20  root      523:        long    nImageBytes = 0;
                    524:        char    *filename;
                    525:        int     ImageType = FLOPPY_IMAGE_TYPE_NONE;
1.1.1.12  root      526: 
                    527:        /* Eject disk, if one is inserted (doesn't inform user) */
                    528:        assert(Drive >= 0 && Drive < MAX_FLOPPYDRIVES);
                    529:        Floppy_EjectDiskFromDrive(Drive);
                    530: 
                    531:        filename = ConfigureParams.DiskImage.szDiskFileName[Drive];
                    532:        if (!filename[0])
                    533:        {
1.1.1.14  root      534:                return true; /* only do eject */
1.1.1.12  root      535:        }
                    536:        if (!File_Exists(filename))
                    537:        {
                    538:                Log_AlertDlg(LOG_INFO, "Image '%s' not found", filename);
1.1.1.14  root      539:                return false;
1.1.1.12  root      540:        }
                    541: 
1.1.1.10  root      542:        /* Check disk image type and read the file: */
1.1.1.14  root      543:        if (MSA_FileNameIsMSA(filename, true))
1.1.1.20  root      544:                EmulationDrives[Drive].pBuffer = MSA_ReadDisk(Drive, filename, &nImageBytes, &ImageType);
1.1.1.14  root      545:        else if (ST_FileNameIsST(filename, true))
1.1.1.20  root      546:                EmulationDrives[Drive].pBuffer = ST_ReadDisk(Drive, filename, &nImageBytes, &ImageType);
1.1.1.14  root      547:        else if (DIM_FileNameIsDIM(filename, true))
1.1.1.20  root      548:                EmulationDrives[Drive].pBuffer = DIM_ReadDisk(Drive, filename, &nImageBytes, &ImageType);
                    549:        else if (IPF_FileNameIsIPF(filename, true))
                    550:                EmulationDrives[Drive].pBuffer = IPF_ReadDisk(Drive, filename, &nImageBytes, &ImageType);
                    551:        else if (STX_FileNameIsSTX(filename, true))
                    552:                EmulationDrives[Drive].pBuffer = STX_ReadDisk(Drive, filename, &nImageBytes, &ImageType);
1.1.1.11  root      553:        else if (ZIP_FileNameIsZIP(filename))
1.1.1.12  root      554:        {
                    555:                const char *zippath = ConfigureParams.DiskImage.szDiskZipPath[Drive];
1.1.1.20  root      556:                EmulationDrives[Drive].pBuffer = ZIP_ReadDisk(Drive, filename, zippath, &nImageBytes, &ImageType);
1.1.1.12  root      557:        }
1.1.1.11  root      558: 
1.1.1.20  root      559:        if ( (EmulationDrives[Drive].pBuffer == NULL) || ( ImageType == FLOPPY_IMAGE_TYPE_NONE ) )
1.1.1.11  root      560:        {
1.1.1.24! root      561:                Log_AlertDlg(LOG_INFO, "Image '%s' filename extension, or content unrecognized", filename);
1.1.1.14  root      562:                return false;
1.1.1.11  root      563:        }
1.1.1.13  root      564: 
1.1.1.20  root      565:        /* For IPF, call specific function to handle the inserted image */
                    566:        if ( ImageType == FLOPPY_IMAGE_TYPE_IPF )
                    567:        {
                    568:                if ( IPF_Insert ( Drive , EmulationDrives[Drive].pBuffer , nImageBytes ) == false )
                    569:                {
                    570:                        free ( EmulationDrives[Drive].pBuffer );
1.1.1.23  root      571:                        EmulationDrives[Drive].pBuffer = NULL;
1.1.1.24! root      572:                        Log_AlertDlg(LOG_INFO, "IPF image '%s' loading failed", filename);
1.1.1.20  root      573:                        return false;
                    574:                }
                    575:        }
                    576: 
                    577:        /* For STX, call specific function to handle the inserted image */
                    578:        else if ( ImageType == FLOPPY_IMAGE_TYPE_STX )
                    579:        {
                    580:                if ( STX_Insert ( Drive , filename , EmulationDrives[Drive].pBuffer , nImageBytes ) == false )
                    581:                {
                    582:                        free ( EmulationDrives[Drive].pBuffer );
1.1.1.23  root      583:                        EmulationDrives[Drive].pBuffer = NULL;
1.1.1.24! root      584:                        Log_AlertDlg(LOG_INFO, "STX image '%s' loading failed", filename);
1.1.1.20  root      585:                        return false;
                    586:                }
                    587:        }
                    588: 
1.1.1.13  root      589:        /* Store image filename (required for ejecting the disk later!) */
                    590:        strcpy(EmulationDrives[Drive].sFileName, filename);
                    591: 
                    592:        /* Store size and set drive states */
1.1.1.20  root      593:        EmulationDrives[Drive].ImageType = ImageType;
1.1.1.11  root      594:        EmulationDrives[Drive].nImageBytes = nImageBytes;
1.1.1.14  root      595:        EmulationDrives[Drive].bDiskInserted = true;
                    596:        EmulationDrives[Drive].bContentsChanged = false;
1.1.1.20  root      597: 
                    598:        if ( ( ImageType == FLOPPY_IMAGE_TYPE_ST ) || ( ImageType == FLOPPY_IMAGE_TYPE_MSA )
                    599:          || ( ImageType == FLOPPY_IMAGE_TYPE_DIM ) )
                    600:                EmulationDrives[Drive].bOKToSave = Floppy_IsBootSectorOK(Drive);
                    601:        else if ( ImageType == FLOPPY_IMAGE_TYPE_STX )
                    602:                EmulationDrives[Drive].bOKToSave = true;
                    603:        else if ( ImageType == FLOPPY_IMAGE_TYPE_IPF )
                    604:                EmulationDrives[Drive].bOKToSave = false;
                    605:        else
                    606:                EmulationDrives[Drive].bOKToSave = false;
                    607: 
1.1.1.18  root      608:        Floppy_DriveTransitionSetState ( Drive , FLOPPY_DRIVE_TRANSITION_STATE_INSERT );
1.1.1.20  root      609:        FDC_InsertFloppy ( Drive );
                    610: 
1.1.1.12  root      611:        Log_Printf(LOG_INFO, "Inserted disk '%s' to drive %c:.",
                    612:                   filename, 'A'+Drive);
1.1.1.14  root      613:        return true;
1.1       root      614: }
                    615: 
1.1.1.2   root      616: 
                    617: /*-----------------------------------------------------------------------*/
1.1.1.11  root      618: /**
                    619:  * Eject disk from floppy drive, save contents back to PCs hard-drive if
                    620:  * they have been changed.
1.1.1.14  root      621:  * Return true if there was something to eject.
1.1.1.11  root      622:  */
1.1.1.12  root      623: bool Floppy_EjectDiskFromDrive(int Drive)
1.1       root      624: {
1.1.1.14  root      625:        bool bEjected = false;
1.1.1.12  root      626: 
1.1.1.10  root      627:        /* Does our drive have a disk in? */
                    628:        if (EmulationDrives[Drive].bDiskInserted)
                    629:        {
1.1.1.16  root      630:                bool bSaved = false;
1.1.1.13  root      631:                char *psFileName = EmulationDrives[Drive].sFileName;
1.1.1.12  root      632: 
1.1.1.10  root      633:                /* OK, has contents changed? If so, need to save */
                    634:                if (EmulationDrives[Drive].bContentsChanged)
                    635:                {
                    636:                        /* Is OK to save image (if boot-sector is bad, don't allow a save) */
1.1.1.20  root      637:                        if (EmulationDrives[Drive].bOKToSave)
1.1.1.10  root      638:                        {
1.1.1.20  root      639:                                /* Save as .MSA, .ST, .DIM, .IPF or .STX image? */
1.1.1.14  root      640:                                if (MSA_FileNameIsMSA(psFileName, true))
1.1.1.20  root      641:                                        bSaved = MSA_WriteDisk(Drive, psFileName, EmulationDrives[Drive].pBuffer, EmulationDrives[Drive].nImageBytes);
1.1.1.14  root      642:                                else if (ST_FileNameIsST(psFileName, true))
1.1.1.20  root      643:                                        bSaved = ST_WriteDisk(Drive, psFileName, EmulationDrives[Drive].pBuffer, EmulationDrives[Drive].nImageBytes);
1.1.1.14  root      644:                                else if (DIM_FileNameIsDIM(psFileName, true))
1.1.1.20  root      645:                                        bSaved = DIM_WriteDisk(Drive, psFileName, EmulationDrives[Drive].pBuffer, EmulationDrives[Drive].nImageBytes);
                    646:                                else if (IPF_FileNameIsIPF(psFileName, true))
                    647:                                        bSaved = IPF_WriteDisk(Drive, psFileName, EmulationDrives[Drive].pBuffer, EmulationDrives[Drive].nImageBytes);
                    648:                                else if (STX_FileNameIsSTX(psFileName, true))
                    649:                                        bSaved = STX_WriteDisk(Drive, psFileName, EmulationDrives[Drive].pBuffer, EmulationDrives[Drive].nImageBytes);
1.1.1.12  root      650:                                else if (ZIP_FileNameIsZIP(psFileName))
1.1.1.20  root      651:                                        bSaved = ZIP_WriteDisk(Drive, psFileName, EmulationDrives[Drive].pBuffer, EmulationDrives[Drive].nImageBytes);
1.1.1.16  root      652:                                if (bSaved)
                    653:                                        Log_Printf(LOG_INFO, "Updated the contents of floppy image '%s'.", psFileName);
                    654:                                else
                    655:                                        Log_Printf(LOG_INFO, "Writing of this format failed or not supported, discarded the contents\n of floppy image '%s'.", psFileName);
                    656:                        } else
                    657:                                Log_Printf(LOG_INFO, "Writing not possible, discarded the contents of floppy image\n '%s'.", psFileName);
1.1.1.10  root      658:                }
                    659: 
                    660:                /* Inform user that disk has been ejected! */
1.1.1.12  root      661:                Log_Printf(LOG_INFO, "Floppy %c: has been removed from drive.",
                    662:                           'A'+Drive);
                    663: 
1.1.1.18  root      664:                Floppy_DriveTransitionSetState ( Drive , FLOPPY_DRIVE_TRANSITION_STATE_EJECT );
1.1.1.20  root      665:                FDC_EjectFloppy ( Drive );
1.1.1.14  root      666:                bEjected = true;
1.1.1.10  root      667:        }
                    668: 
1.1.1.20  root      669:        /* Free data used by this IPF image */
                    670:        if ( EmulationDrives[Drive].ImageType == FLOPPY_IMAGE_TYPE_IPF )
                    671:                IPF_Eject ( Drive );
                    672:        /* Free data used by this STX image */
                    673:        else if ( EmulationDrives[Drive].ImageType == FLOPPY_IMAGE_TYPE_STX )
                    674:                STX_Eject ( Drive );
                    675: 
                    676: 
1.1.1.10  root      677:        /* Drive is now empty */
                    678:        if (EmulationDrives[Drive].pBuffer != NULL)
                    679:        {
                    680:                free(EmulationDrives[Drive].pBuffer);
                    681:                EmulationDrives[Drive].pBuffer = NULL;
                    682:        }
1.1.1.12  root      683: 
1.1.1.13  root      684:        EmulationDrives[Drive].sFileName[0] = '\0';
1.1.1.20  root      685:        EmulationDrives[Drive].ImageType = FLOPPY_IMAGE_TYPE_NONE;
1.1.1.10  root      686:        EmulationDrives[Drive].nImageBytes = 0;
1.1.1.14  root      687:        EmulationDrives[Drive].bDiskInserted = false;
                    688:        EmulationDrives[Drive].bContentsChanged = false;
                    689:        EmulationDrives[Drive].bOKToSave = false;
1.1.1.12  root      690: 
                    691:        return bEjected;
1.1       root      692: }
                    693: 
1.1.1.2   root      694: 
                    695: /*-----------------------------------------------------------------------*/
1.1.1.11  root      696: /**
                    697:  * Eject all disk image from floppy drives - call when quit.
1.1.1.14  root      698:  * Return true if there was something to eject.
1.1.1.11  root      699:  */
1.1.1.13  root      700: static bool Floppy_EjectBothDrives(void)
1.1       root      701: {
1.1.1.12  root      702:        bool bEjectedA, bEjectedB;
                    703: 
1.1.1.10  root      704:        /* Eject disk images from drives 'A' and 'B' */
1.1.1.12  root      705:        bEjectedA = Floppy_EjectDiskFromDrive(0);
                    706:        bEjectedB = Floppy_EjectDiskFromDrive(1);
                    707: 
                    708:        return bEjectedA || bEjectedB;
1.1       root      709: }
                    710: 
1.1.1.2   root      711: 
                    712: /*-----------------------------------------------------------------------*/
1.1.1.11  root      713: /**
                    714:  * Double-check information read from boot-sector as this is sometimes found to
1.1.1.17  root      715:  * be incorrect. The .ST image file should be divisible by the sector size,
                    716:  * the sectors per track. the number of tracks and the number of sides.
1.1.1.11  root      717:  * NOTE - Pass information from boot-sector to this function (if we can't
                    718:  * decide we leave it alone).
                    719:  */
1.1.1.17  root      720: static void Floppy_DoubleCheckFormat(long nDiskSize, long nSectorsPerDisk, Uint16 *pnSides, Uint16 *pnSectorsPerTrack)
1.1       root      721: {
1.1.1.17  root      722:        long    TotalSectors;
                    723:        int     Sides_fixed;
                    724:        int     SectorsPerTrack_fixed;
1.1       root      725: 
1.1.1.10  root      726:        /* Now guess at number of sides */
1.1.1.17  root      727:        if ( nDiskSize < (500*1024) )                           /* If size >500k assume 2 sides */
                    728:                Sides_fixed = 1;
1.1.1.10  root      729:        else
1.1.1.17  root      730:                Sides_fixed = 2;
1.1.1.10  root      731: 
1.1.1.17  root      732:        /* Number of 512 bytes sectors for this disk image */
                    733:        TotalSectors = nDiskSize / 512;
                    734: 
                    735:        /* Check some common values */
                    736:        if      ( TotalSectors == 80*9*Sides_fixed )    { SectorsPerTrack_fixed = 9; }
                    737:        else if ( TotalSectors == 81*9*Sides_fixed )    { SectorsPerTrack_fixed = 9; }
                    738:        else if ( TotalSectors == 82*9*Sides_fixed )    { SectorsPerTrack_fixed = 9; }
1.1.1.18  root      739:        else if ( TotalSectors == 83*9*Sides_fixed )    { SectorsPerTrack_fixed = 9; }
                    740:        else if ( TotalSectors == 84*9*Sides_fixed )    { SectorsPerTrack_fixed = 9; }
1.1.1.17  root      741:        else if ( TotalSectors == 80*10*Sides_fixed )   { SectorsPerTrack_fixed = 10; }
                    742:        else if ( TotalSectors == 81*10*Sides_fixed )   { SectorsPerTrack_fixed = 10; }
                    743:        else if ( TotalSectors == 82*10*Sides_fixed )   { SectorsPerTrack_fixed = 10; }
1.1.1.18  root      744:        else if ( TotalSectors == 83*10*Sides_fixed )   { SectorsPerTrack_fixed = 10; }
                    745:        else if ( TotalSectors == 84*10*Sides_fixed )   { SectorsPerTrack_fixed = 10; }
1.1.1.17  root      746:        else if ( TotalSectors == 80*11*Sides_fixed )   { SectorsPerTrack_fixed = 11; }
                    747:        else if ( TotalSectors == 81*11*Sides_fixed )   { SectorsPerTrack_fixed = 11; }
                    748:        else if ( TotalSectors == 82*11*Sides_fixed )   { SectorsPerTrack_fixed = 11; }
1.1.1.18  root      749:        else if ( TotalSectors == 83*11*Sides_fixed )   { SectorsPerTrack_fixed = 11; }
                    750:        else if ( TotalSectors == 84*11*Sides_fixed )   { SectorsPerTrack_fixed = 11; }
1.1.1.17  root      751:        else if ( TotalSectors == 80*12*Sides_fixed )   { SectorsPerTrack_fixed = 12; }
                    752:        else if ( TotalSectors == 81*12*Sides_fixed )   { SectorsPerTrack_fixed = 12; }
                    753:        else if ( TotalSectors == 82*12*Sides_fixed )   { SectorsPerTrack_fixed = 12; }
1.1.1.18  root      754:        else if ( TotalSectors == 83*12*Sides_fixed )   { SectorsPerTrack_fixed = 12; }
                    755:        else if ( TotalSectors == 84*12*Sides_fixed )   { SectorsPerTrack_fixed = 12; }
1.1.1.17  root      756: 
                    757:        /* unknown combination, assume boot sector is correct */
                    758:        else                                            { SectorsPerTrack_fixed = *pnSectorsPerTrack; }
                    759: 
                    760:        /* Valid new values if necessary */
                    761:        if ( ( *pnSides != Sides_fixed ) || ( *pnSectorsPerTrack != SectorsPerTrack_fixed ) )
1.1.1.10  root      762:        {
1.1.1.17  root      763: #if 0
                    764:                int TracksPerDisk_fixed = TotalSectors / ( SectorsPerTrack_fixed * Sides_fixed );
                    765:                Log_Printf(LOG_WARN, "Floppy_DoubleCheckFormat: boot sector doesn't match disk image's size :"
                    766:                        " total sectors %ld->%ld sides %d->%d sectors %d->%d tracks %d\n",
                    767:                        nSectorsPerDisk , TotalSectors , *pnSides , Sides_fixed , *pnSectorsPerTrack , SectorsPerTrack_fixed , TracksPerDisk_fixed );
                    768: #endif
                    769:                *pnSides = Sides_fixed;
                    770:                *pnSectorsPerTrack = SectorsPerTrack_fixed;
1.1.1.10  root      771:        }
1.1       root      772: }
                    773: 
1.1.1.2   root      774: 
                    775: /*-----------------------------------------------------------------------*/
1.1.1.11  root      776: /**
                    777:  * Find details of disk image. We need to do this via a function as sometimes the boot-block
                    778:  * is not actually correct with the image - some demos/game disks have incorrect bytes in the
                    779:  * boot sector and this attempts to find the correct values.
                    780:  */
1.1.1.9   root      781: void Floppy_FindDiskDetails(const Uint8 *pBuffer, int nImageBytes,
1.1.1.12  root      782:                             Uint16 *pnSectorsPerTrack, Uint16 *pnSides)
1.1       root      783: {
1.1.1.17  root      784:        Uint16 nSectorsPerTrack, nSides, nSectorsPerDisk;
1.1       root      785: 
1.1.1.10  root      786:        /* First do check to find number of sectors and bytes per sector */
                    787:        nSectorsPerTrack = SDL_SwapLE16(*(const Uint16 *)(pBuffer+24));   /* SPT */
                    788:        nSides = SDL_SwapLE16(*(const Uint16 *)(pBuffer+26));             /* SIDE */
1.1.1.17  root      789:        nSectorsPerDisk = pBuffer[19] | (pBuffer[20] << 8);               /* total sectors */
1.1.1.10  root      790: 
                    791:        /* If the number of sectors announced is incorrect, the boot-sector may
                    792:         * contain incorrect information, eg the 'Eat.st' demo, or wrongly imaged
                    793:         * single/double sided floppies... */
1.1.1.17  root      794:        if (nSectorsPerDisk != nImageBytes/512)
                    795:                Floppy_DoubleCheckFormat(nImageBytes, nSectorsPerDisk, &nSides, &nSectorsPerTrack);
1.1.1.10  root      796: 
                    797:        /* And set values */
                    798:        if (pnSectorsPerTrack)
                    799:                *pnSectorsPerTrack = nSectorsPerTrack;
                    800:        if (pnSides)
                    801:                *pnSides = nSides;
1.1       root      802: }
                    803: 
1.1.1.2   root      804: 
                    805: /*-----------------------------------------------------------------------*/
1.1.1.11  root      806: /**
                    807:  * Read sectors from floppy disk image, return TRUE if all OK
                    808:  * NOTE Pass -ve as Count to read whole track
                    809:  */
1.1.1.20  root      810: bool Floppy_ReadSectors(int Drive, Uint8 **pBuffer, Uint16 Sector,
1.1.1.12  root      811:                         Uint16 Track, Uint16 Side, short Count,
1.1.1.18  root      812:                         int *pnSectorsPerTrack, int *pSectorSize)
1.1       root      813: {
1.1.1.10  root      814:        Uint8 *pDiskBuffer;
1.1.1.12  root      815:        Uint16 nSectorsPerTrack, nSides, nBytesPerTrack;
1.1.1.10  root      816:        long Offset;
                    817:        int nImageTracks;
                    818: 
                    819:        /* Do we have a disk in our drive? */
                    820:        if (EmulationDrives[Drive].bDiskInserted)
                    821:        {
                    822:                /* Looks good */
                    823:                pDiskBuffer = EmulationDrives[Drive].pBuffer;
                    824: 
                    825:                /* Find #sides and #sectors per track */
                    826:                Floppy_FindDiskDetails(EmulationDrives[Drive].pBuffer,EmulationDrives[Drive].nImageBytes,&nSectorsPerTrack,&nSides);
                    827:                nImageTracks = ((EmulationDrives[Drive].nImageBytes / NUMBYTESPERSECTOR) / nSectorsPerTrack) / nSides;
                    828: 
                    829:                /* Need to read whole track? */
                    830:                if (Count<0)
                    831:                        Count = nSectorsPerTrack;
                    832:                /* Write back number of sector per track */
                    833:                if (pnSectorsPerTrack)
                    834:                        *pnSectorsPerTrack = nSectorsPerTrack;
                    835: 
1.1.1.18  root      836:                if (pSectorSize)
                    837:                        *pSectorSize = NUMBYTESPERSECTOR;                       /* Size is 512 bytes for ST/MSA */
                    838: 
1.1.1.10  root      839:                /* Debug check as if we read over the end of a track we read into side 2! */
                    840:                if (Count > nSectorsPerTrack)
                    841:                {
                    842:                        Log_Printf(LOG_DEBUG, "Floppy_ReadSectors: reading over single track\n");
                    843:                }
                    844: 
                    845:                /* Check that the side number (0 or 1) does not exceed the amount of sides (1 or 2).
                    846:                 * (E.g. some games like Drakkhen or Bolo can load additional data from the
                    847:                 * second disk side, but they also work with single side floppy drives) */
                    848:                if (Side >= nSides)
                    849:                {
                    850:                        Log_Printf(LOG_DEBUG, "Floppy_ReadSectors: Program tries to read from side %i "
                    851:                                   "of a disk image with %i sides!\n", Side+1, nSides);
1.1.1.14  root      852:                        return false;
1.1.1.10  root      853:                }
                    854: 
                    855:                /* Check if track number is in range */
                    856:                if (Track >= nImageTracks)
                    857:                {
                    858:                        Log_Printf(LOG_DEBUG, "Floppy_ReadSectors: Program tries to read from track %i "
                    859:                                   "of a disk image with only %i tracks!\n", Track, nImageTracks);
1.1.1.14  root      860:                        return false;
1.1.1.10  root      861:                }
                    862: 
                    863:                /* Check if sector number is in range */
                    864:                if (Sector <= 0 || Sector > nSectorsPerTrack)
                    865:                {
                    866:                        Log_Printf(LOG_DEBUG, "Floppy_ReadSectors: Program tries to read from sector %i "
                    867:                                   "of a disk image with %i sectors per track!\n", Sector, nSectorsPerTrack);
1.1.1.14  root      868:                        return false;
1.1.1.10  root      869:                }
                    870: 
                    871:                /* Seek to sector */
                    872:                nBytesPerTrack = NUMBYTESPERSECTOR*nSectorsPerTrack;
                    873:                Offset = nBytesPerTrack*Side;                 /* First seek to side */
                    874:                Offset += (nBytesPerTrack*nSides)*Track;      /* Then seek to track */
                    875:                Offset += (NUMBYTESPERSECTOR*(Sector-1));     /* And finally to sector */
1.1.1.6   root      876: 
1.1.1.20  root      877:                /* Return a pointer to the sectors data (usually 512 bytes per sector) */
                    878:                *pBuffer = pDiskBuffer+Offset;
1.1       root      879: 
1.1.1.14  root      880:                return true;
1.1.1.10  root      881:        }
1.1       root      882: 
1.1.1.14  root      883:        return false;
1.1       root      884: }
                    885: 
1.1.1.2   root      886: 
                    887: /*-----------------------------------------------------------------------*/
1.1.1.11  root      888: /**
                    889:  * Write sectors from floppy disk image, return TRUE if all OK
                    890:  * NOTE Pass -ve as Count to write whole track
                    891:  */
1.1.1.12  root      892: bool Floppy_WriteSectors(int Drive, Uint8 *pBuffer, Uint16 Sector,
                    893:                          Uint16 Track, Uint16 Side, short Count,
1.1.1.18  root      894:                          int *pnSectorsPerTrack, int *pSectorSize)
1.1       root      895: {
1.1.1.10  root      896:        Uint8 *pDiskBuffer;
1.1.1.12  root      897:        Uint16 nSectorsPerTrack, nSides, nBytesPerTrack;
1.1.1.10  root      898:        long Offset;
                    899:        int nImageTracks;
                    900: 
                    901:        /* Do we have a writable disk in our drive? */
                    902:        if (EmulationDrives[Drive].bDiskInserted && !Floppy_IsWriteProtected(Drive))
                    903:        {
                    904:                /* Looks good */
                    905:                pDiskBuffer = EmulationDrives[Drive].pBuffer;
                    906: 
                    907:                /* Find #sides and #sectors per track */
                    908:                Floppy_FindDiskDetails(EmulationDrives[Drive].pBuffer,EmulationDrives[Drive].nImageBytes,&nSectorsPerTrack,&nSides);
                    909:                nImageTracks = ((EmulationDrives[Drive].nImageBytes / NUMBYTESPERSECTOR) / nSectorsPerTrack) / nSides;
                    910: 
                    911:                /* Need to write whole track? */
                    912:                if (Count<0)
                    913:                        Count = nSectorsPerTrack;
                    914:                /* Write back number of sector per track */
                    915:                if (pnSectorsPerTrack)
                    916:                        *pnSectorsPerTrack = nSectorsPerTrack;
                    917: 
1.1.1.18  root      918:                if (pSectorSize)
                    919:                        *pSectorSize = NUMBYTESPERSECTOR;                       /* Size is 512 bytes for ST/MSA */
                    920: 
1.1.1.10  root      921:                /* Debug check as if we write over the end of a track we write into side 2! */
                    922:                if (Count > nSectorsPerTrack)
                    923:                {
                    924:                        Log_Printf(LOG_DEBUG, "Floppy_WriteSectors: writing over single track\n");
                    925:                }
                    926: 
                    927:                /* Check that the side number (0 or 1) does not exceed the amount of sides (1 or 2). */
                    928:                if (Side >= nSides)
                    929:                {
                    930:                        Log_Printf(LOG_DEBUG, "Floppy_WriteSectors: Program tries to write to side %i "
                    931:                                   "of a disk image with %i sides!\n", Side+1, nSides);
1.1.1.14  root      932:                        return false;
1.1.1.10  root      933:                }
                    934: 
                    935:                /* Check if track number is in range */
                    936:                if (Track >= nImageTracks)
                    937:                {
                    938:                        Log_Printf(LOG_DEBUG, "Floppy_WriteSectors: Program tries to write to track %i "
                    939:                                   "of a disk image with only %i tracks!\n", Track, nImageTracks);
1.1.1.14  root      940:                        return false;
1.1.1.10  root      941:                }
                    942: 
                    943:                /* Check if sector number is in range */
                    944:                if (Sector <= 0 || Sector > nSectorsPerTrack)
                    945:                {
                    946:                        Log_Printf(LOG_DEBUG, "Floppy_WriteSectors: Program tries to write to sector %i "
                    947:                                   "of a disk image with %i sectors per track!\n", Sector, nSectorsPerTrack);
1.1.1.14  root      948:                        return false;
1.1.1.10  root      949:                }
                    950: 
                    951:                /* Seek to sector */
                    952:                nBytesPerTrack = NUMBYTESPERSECTOR*nSectorsPerTrack;
                    953:                Offset = nBytesPerTrack*Side;               /* First seek to side */
                    954:                Offset += (nBytesPerTrack*nSides)*Track;    /* Then seek to track */
                    955:                Offset += (NUMBYTESPERSECTOR*(Sector-1));   /* And finally to sector */
                    956: 
                    957:                /* Write sectors (usually 512 bytes per sector) */
                    958:                memcpy(pDiskBuffer+Offset, pBuffer, (int)Count*NUMBYTESPERSECTOR);
                    959:                /* And set 'changed' flag */
1.1.1.14  root      960:                EmulationDrives[Drive].bContentsChanged = true;
1.1       root      961: 
1.1.1.14  root      962:                return true;
1.1.1.10  root      963:        }
1.1       root      964: 
1.1.1.14  root      965:        return false;
1.1       root      966: }

unix.superglobalmegacorp.com

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