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

1.1       root        1: /*
                      2:   Hatari
                      3: 
                      4:   This where we read/write sectors to/from the disc image buffers. NOTE these buffers are in
                      5:   memory so we only need to write routines for the .ST format. When the buffer is to be
                      6:   saved(ie eject disc) we save it back to the original file in the correct format(.ST or .MSA)
                      7: 
                      8:   There are some important notes about image accessing - as we use TOS and the FDC to access
                      9:   the disc the boot-sector MUST be valid. Sometimes this is NOT the case! In these
                     10:   situations we must guess at the disc format. Eg, some disc images have a a boot sector which
                     11:   states single-sided, but the images have been created as double-sided. As sides are interleaved
                     12:   we need to read the image as if it was double-sided. Also note that 'NumBytesPerSector' is
                     13:   ALWAYS 512 bytes, even if the boot-sector states otherwise.
1.1.1.4 ! root       14:   Also note that old versions of the MAKEDISK utility do not set the correct
        !            15:   boot sector structure for a real ST (and also Hatari) to read it correctly.
        !            16:   (PaCifiST will, however, read/write to these images as it does not perform
        !            17:   FDC access as on a real ST)
1.1       root       18: */
                     19: 
1.1.1.4 ! root       20: #include <SDL_endian.h>
        !            21: 
1.1       root       22: #include "main.h"
                     23: #include "debug.h"
                     24: #include "dialog.h"
                     25: #include "errlog.h"
                     26: #include "file.h"
                     27: #include "floppy.h"
                     28: #include "memAlloc.h"
                     29: #include "memorySnapShot.h"
                     30: #include "misc.h"
                     31: #include "msa.h"
                     32: #include "st.h"
                     33: 
                     34: 
                     35: EMULATION_DRIVE EmulationDrives[NUM_EMULATION_DRIVES];  /* Emulation drive details, eg FileName, Inserted, Changed etc... */
                     36: int nBootDrive=0;               /* Drive A, default */
                     37: 
                     38: /* Possible disc image file extensions to scan for */
                     39: char *pszDiscImageNameExts[] = {
                     40:   ".msa",
                     41:   ".st",
                     42:   NULL
                     43: };
                     44: 
                     45: 
1.1.1.2   root       46: /*-----------------------------------------------------------------------*/
1.1       root       47: /*
                     48:   Initialize emulation floppy drives
                     49: */
                     50: void Floppy_Init(void)
                     51: {
                     52:   int i;
                     53: 
                     54:   /* Clear drive structures */
                     55:   for(i=0; i<NUM_EMULATION_DRIVES; i++) {
                     56:     /* Clear */
                     57:     Memory_Clear(&EmulationDrives[i],sizeof(EMULATION_DRIVE));
                     58:     /* And allocate buffer */
                     59:     EmulationDrives[i].pBuffer = (unsigned char *)Memory_Alloc(DRIVE_BUFFER_BYTES);
                     60:   }
                     61: }
                     62: 
1.1.1.2   root       63: 
                     64: /*-----------------------------------------------------------------------*/
1.1       root       65: /*
                     66:   UnInitialize drives
                     67: */
                     68: void Floppy_UnInit(void)
                     69: {
                     70:   int i;
                     71: 
1.1.1.2   root       72:   /* Free buffers used for emulation drives */
1.1       root       73:   for(i=0; i<NUM_EMULATION_DRIVES; i++) {
                     74:     Memory_Free(EmulationDrives[i].pBuffer);
                     75:   }
                     76: }
                     77: 
1.1.1.2   root       78: 
                     79: /*-----------------------------------------------------------------------*/
1.1       root       80: /*
                     81:   Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type)
                     82: */
                     83: void Floppy_MemorySnapShot_Capture(BOOL bSave)
                     84: {
                     85:   int i;
                     86: 
1.1.1.2   root       87:   /* Save/Restore details */
1.1       root       88:   for(i=0; i<NUM_EMULATION_DRIVES; i++) {
                     89:     MemorySnapShot_Store(EmulationDrives[i].pBuffer,DRIVE_BUFFER_BYTES);
                     90:     MemorySnapShot_Store(EmulationDrives[i].szFileName,sizeof(EmulationDrives[i].szFileName));
                     91:     MemorySnapShot_Store(&EmulationDrives[i].nImageBytes,sizeof(EmulationDrives[i].nImageBytes));
                     92:     MemorySnapShot_Store(&EmulationDrives[i].bDiscInserted,sizeof(EmulationDrives[i].bDiscInserted));
                     93:     MemorySnapShot_Store(&EmulationDrives[i].bMediaChanged,sizeof(EmulationDrives[i].bMediaChanged));
                     94:     MemorySnapShot_Store(&EmulationDrives[i].bContentsChanged,sizeof(EmulationDrives[i].bContentsChanged));
                     95:     MemorySnapShot_Store(&EmulationDrives[i].bOKToSave,sizeof(EmulationDrives[i].bOKToSave));
                     96:   }
                     97: }
                     98: 
1.1.1.2   root       99: 
                    100: /*-----------------------------------------------------------------------*/
1.1       root      101: /*
                    102:   Find which device to boot from
                    103: */
                    104: void Floppy_GetBootDrive(void)
                    105: {
1.1.1.3   root      106:   /* If we've inserted a disc or not enabled boot from hard-drive, boot from the floppy drive */
1.1       root      107:   if ( (!ConfigureParams.HardDisc.bBootFromHardDisc) || (EmulationDrives[0].bDiscInserted) )
1.1.1.3   root      108:     nBootDrive = 0;  /* Drive A */
1.1       root      109:   else
1.1.1.3   root      110:     nBootDrive = 2;  /* Drive C */
1.1       root      111: }
                    112: 
1.1.1.2   root      113: 
                    114: /*-----------------------------------------------------------------------*/
1.1       root      115: /*
                    116:   Test disc image for valid boot-sector
                    117: 
                    118:   It has been noticed that some discs, eg blank images made by the (current)MakeDisk utility
                    119:   fill in the boot-sector with incorrect information. Such images cannot be read correctly using
                    120:   a real ST, and also Hatari. To try and prevent data loss, we check for this error and flag
                    121:   the drive so the image will not be saved back to the file.
                    122: */
                    123: BOOL Floppy_IsBootSectorOK(int Drive)
                    124: {
                    125:   unsigned char *pDiscBuffer;
                    126: 
                    127:   /* Does our drive have a disc in? */
                    128:   if (EmulationDrives[Drive].bDiscInserted) {
                    129:     pDiscBuffer = EmulationDrives[Drive].pBuffer;
                    130:     /* Check SPC(byte 13) for !=0 value. If is '0', invalid image and Hatari won't be-able to read(nor will a real ST)! */
                    131:     if (pDiscBuffer[13]!=0)
                    132:       return(TRUE);     /* Disc sector is OK! */
                    133:   }
                    134: 
                    135:   return(FALSE);        /* Bad sector */
                    136: }
                    137: 
1.1.1.2   root      138: 
                    139: /*-----------------------------------------------------------------------*/
1.1       root      140: /*
                    141:   Try to create disc B filename, eg 'auto_100a' becomes 'auto_100b'
                    142:   Return TRUE if think we should try!
                    143: */
                    144: BOOL Floppy_CreateDiscBFileName(char *pSrcFileName, char *pDestFileName)
                    145: {
1.1.1.3   root      146:   char szDir[256], szName[128], szExt[32];
1.1       root      147: 
1.1.1.3   root      148:   /* So, first split name into parts */
                    149:   File_splitpath(pSrcFileName, szDir, szName, szExt);
                    150:   /* All OK? */
1.1       root      151:   if (strlen(szName)>0) {
1.1.1.3   root      152:     /* Now, did filename end with an 'A' or 'a'? */
1.1       root      153:     if ( (szName[strlen(szName)-1]=='A') || (szName[strlen(szName)-1]=='a') ) {
1.1.1.3   root      154:       /* Change 'A' to a 'B' */
                    155:       szName[strlen(szName)-1] += 1;
                    156:       /* And re-build name into destination */
                    157:       File_makepath(pDestFileName,szDir,szName,szExt);
                    158:       /* Does file exist? */
1.1       root      159:       if (File_Exists(pDestFileName))
1.1.1.3   root      160:         return(TRUE);  /* Try this */
1.1       root      161:     }
                    162:   }
1.1.1.3   root      163: 
1.1.1.2   root      164:   return(FALSE);  /* No, doesn't have disc B */
1.1       root      165: }
                    166: 
1.1.1.2   root      167: 
                    168: /*-----------------------------------------------------------------------*/
1.1       root      169: /*
                    170:   Insert disc into floppy drive
                    171:   The WHOLE image is copied into our drive buffers, and uncompressed if necessary
                    172: */
                    173: BOOL Floppy_InsertDiscIntoDrive(int Drive, char *pszFileName)
                    174: {
                    175:   char szDiscBFileName[MAX_FILENAME_LENGTH];
                    176:   int nImageBytes=0;
                    177: 
                    178:   /* Eject disc, if one is inserted(don't inform user) */
                    179:   Floppy_EjectDiscFromDrive(Drive,FALSE);
                    180: 
                    181:   /* See if file exists, and if not get correct extension */
1.1.1.3   root      182:   if( !File_Exists(pszFileName) )
                    183:     File_FindPossibleExtFileName(pszFileName,pszDiscImageNameExts);
1.1       root      184: 
                    185:   /* Is .MSA or .ST image? */
                    186:   if (File_FileNameIsMSA(pszFileName))
                    187:     nImageBytes = MSA_ReadDisc(pszFileName,EmulationDrives[Drive].pBuffer);
                    188:   else if (File_FileNameIsST(pszFileName))
                    189:     nImageBytes = ST_ReadDisc(pszFileName,EmulationDrives[Drive].pBuffer);
                    190:   /* Did load OK? */
                    191:   if (nImageBytes!=0) {
                    192:     /* Store filename and size */
                    193:     strcpy(EmulationDrives[Drive].szFileName,pszFileName);
                    194:     EmulationDrives[Drive].nImageBytes = nImageBytes;
                    195:     /* And set drive states */
                    196:     EmulationDrives[Drive].bDiscInserted = TRUE;
                    197:     EmulationDrives[Drive].bContentsChanged = FALSE;
                    198:     EmulationDrives[Drive].bMediaChanged = TRUE;
                    199:     EmulationDrives[Drive].bOKToSave = Floppy_IsBootSectorOK(Drive);
                    200:   }
                    201: 
                    202:   /* If we insert a disc into Drive A, should be try to put disc 2 into drive B? */
                    203:   if ( (Drive==0) && (ConfigureParams.DiscImage.bAutoInsertDiscB) ) {
                    204:     strcpy(EmulationDrives[1].szFileName,"");
1.1.1.3   root      205:     /* Attempt to make up second filename, eg was 'auto_100a' to 'auto_100b' */
1.1       root      206:     if (Floppy_CreateDiscBFileName(pszFileName,szDiscBFileName)) {
1.1.1.3   root      207:       /* Put image into Drive B, clear out if fails */
1.1       root      208:       if (!Floppy_InsertDiscIntoDrive(1,szDiscBFileName))
                    209:         strcpy(EmulationDrives[1].szFileName,"");
                    210:     }
                    211:   }
1.1.1.3   root      212: 
1.1       root      213:   /* Return TRUE if loaded OK */
                    214:   if (nImageBytes)
                    215:     return(TRUE);
                    216:   else
                    217:     return(FALSE);
                    218: }
                    219: 
1.1.1.2   root      220: 
                    221: /*-----------------------------------------------------------------------*/
1.1       root      222: /*
                    223:   Eject disc from floppy drive, save contents back to PCs hard-drive is has changed
                    224: */
                    225: void Floppy_EjectDiscFromDrive(int Drive,BOOL bInformUser)
                    226: {
                    227:   char szString[256];
                    228: 
                    229:   /* Does our drive have a disc in? */
                    230:   if (EmulationDrives[Drive].bDiscInserted) {
                    231:     /* OK, has contents changed? If so, need to save */
                    232:     if (EmulationDrives[Drive].bContentsChanged) {
                    233:       /* Is OK to save image(if boot-sector is bad, don't allow a save) */
                    234:       if (EmulationDrives[Drive].bOKToSave) {
                    235:         /* Save as .MSA or .ST image? */
                    236:         if (File_FileNameIsMSA(EmulationDrives[Drive].szFileName))
                    237:           MSA_WriteDisc(EmulationDrives[Drive].szFileName,EmulationDrives[Drive].pBuffer,EmulationDrives[Drive].nImageBytes);
                    238:         else if (File_FileNameIsST(EmulationDrives[Drive].szFileName))
                    239:           ST_WriteDisc(EmulationDrives[Drive].szFileName,EmulationDrives[Drive].pBuffer,EmulationDrives[Drive].nImageBytes);
                    240:       }
                    241:     }
                    242: 
                    243:     /* Inform user that disc has been ejected! */
                    244:     if (bInformUser) {
                    245:       sprintf(szString,"Disc has been removed from Drive '%c'.",'A'+Drive);
                    246: /* FIXME */ //    MessageBox(hWnd,szString,PROG_NAME,MB_OK | MB_ICONINFORMATION);
                    247:     }
                    248:   }
                    249: 
                    250:   /* Drive is now empty */
                    251:   strcpy(EmulationDrives[Drive].szFileName,"");
                    252:   EmulationDrives[Drive].nImageBytes = 0;
                    253:   EmulationDrives[Drive].bDiscInserted = FALSE;
                    254:   EmulationDrives[Drive].bContentsChanged = FALSE;
                    255:   EmulationDrives[Drive].bOKToSave = FALSE;
                    256: }
                    257: 
1.1.1.2   root      258: 
                    259: /*-----------------------------------------------------------------------*/
1.1       root      260: /*
                    261:   Eject all disc image from floppy drives - call when quit
                    262: */
                    263: void Floppy_EjectBothDrives(void)
                    264: {
                    265:   /* Eject disc images from drives 'A' and 'B' */
                    266:   Floppy_EjectDiscFromDrive(0,FALSE);
                    267:   Floppy_EjectDiscFromDrive(1,FALSE);
                    268: }
                    269: 
1.1.1.2   root      270: 
                    271: /*-----------------------------------------------------------------------*/
1.1       root      272: /*
1.1.1.4 ! root      273:   Double-check information read from boot-sector as this is sometimes found to
        !           274:   be incorrect. The .ST image file should be divisible by the sector size and
        !           275:   sectors per track.
        !           276:   NOTE - Pass information from boot-sector to this function (if we can't
        !           277:   decide we leave it alone).
1.1       root      278: */
1.1.1.4 ! root      279: static void Floppy_DoubleCheckFormat(long DiscSize, Uint16 *pnSides, Uint16 *pnSectorsPerTrack)
1.1       root      280: {
                    281:   int nSectorsPerTrack;
                    282:   long TotalSectors;
                    283: 
                    284:   /* Now guess at number of sides */
                    285:   if (DiscSize<(500*1024))                      /* Is size is >500k assume 2 sides to disc! */
                    286:     *pnSides = 1;
                    287:   else
                    288:     *pnSides = 2;
                    289: 
                    290:   /* And Sectors Per Track(always 512 bytes per sector) */
                    291:   TotalSectors = DiscSize/512;                  /* # Sectors on disc image */
1.1.1.2   root      292:   /* Does this match up with what we've read from boot-sector? */
1.1       root      293:   nSectorsPerTrack = *pnSectorsPerTrack;
                    294:   if (nSectorsPerTrack==0)                      /* Check valid, default to 9 */
                    295:     nSectorsPerTrack = 9;
1.1.1.4 ! root      296:   if ((TotalSectors%nSectorsPerTrack)!=0)
        !           297:   {
1.1       root      298:     /* No, we have an invalid boot-sector - re-calculate from disc size */
                    299:     if ((TotalSectors%9)==0)                    /* Work in this order.... */
                    300:       *pnSectorsPerTrack = 9;
                    301:     else if ((TotalSectors%10)==0)
                    302:       *pnSectorsPerTrack = 10;
                    303:     else if ((TotalSectors%11)==0)
                    304:       *pnSectorsPerTrack = 11;
                    305:     else if ((TotalSectors%12)==0)
                    306:       *pnSectorsPerTrack = 12;
                    307:   }
                    308:   /* else unknown, assume boot-sector is correct!!! */
                    309: }
                    310: 
1.1.1.2   root      311: 
                    312: /*-----------------------------------------------------------------------*/
1.1       root      313: /*
                    314:   Find details of disc image. We need to do this via a function as sometimes the boot-block
                    315:   is not actually correct with the image - some demos/game discs have incorrect bytes in the
                    316:   boot sector and this attempts to find the correct values.
                    317: */
1.1.1.4 ! root      318: void Floppy_FindDiscDetails(unsigned char *pBuffer, int nImageBytes,
        !           319:                             unsigned short int *pnSectorsPerTrack, unsigned short int *pnSides)
1.1       root      320: {
                    321:   unsigned char *pDiscBuffer;
1.1.1.4 ! root      322:   Uint16 nSectorsPerTrack, nSides;
1.1       root      323: 
                    324:   pDiscBuffer = pBuffer;
                    325:   /* First do check to find number of sectors and bytes per sector */
1.1.1.4 ! root      326:   nSectorsPerTrack = SDL_SwapLE16(*(Uint16 *)(pDiscBuffer+24));     /* SPT */
        !           327:   nSides = SDL_SwapLE16(*(Uint16 *)(pDiscBuffer+26));               /* SIDE */
        !           328: 
        !           329:   /* Now double-check info as boot-sector may contain incorrect information,
        !           330:      eg 'Eat.st' demo, or single/double sides */
        !           331:   Floppy_DoubleCheckFormat(nImageBytes, &nSides, &nSectorsPerTrack);
1.1       root      332: 
                    333:   /* And set values */
                    334:   if (pnSectorsPerTrack)
                    335:     *pnSectorsPerTrack = nSectorsPerTrack;
                    336:   if (pnSides)
                    337:     *pnSides = nSides;
                    338: }
                    339: 
1.1.1.2   root      340: 
                    341: /*-----------------------------------------------------------------------*/
1.1       root      342: /*
                    343:   Read sectors from floppy disc image, return TRUE if all OK
                    344:   NOTE Pass -ve as Count to read whole track
                    345: */
                    346: BOOL Floppy_ReadSectors(int Drive,char *pBuffer,unsigned short int Sector,unsigned short int Track,unsigned short int Side, short int Count, int *pnSectorsPerTrack)
                    347: {
                    348:   unsigned char *pDiscBuffer;
                    349:   unsigned short int nSectorsPerTrack,nSides,nBytesPerTrack;
                    350:   long Offset;
                    351: 
1.1.1.3   root      352:   if(Track>85) {
                    353:     fprintf(stderr,"Strange floppy track=%i!\n",Track);
                    354:     Track=85;
                    355:   }
                    356: 
1.1.1.2   root      357:   /* Do we have a disc in our drive? */
1.1       root      358:   if (EmulationDrives[Drive].bDiscInserted) {
1.1.1.2   root      359:     /* Looks good */
1.1.1.3   root      360:     /*StatusBar_SetIcon(STATUS_ICON_FLOPPY,ICONSTATE_UPDATE);*/ /* Sorry - no statusbar in Hatari */
1.1       root      361:     pDiscBuffer = EmulationDrives[Drive].pBuffer;
                    362: 
1.1.1.2   root      363:     /* Find #sides and #sectors per track */
1.1       root      364:     Floppy_FindDiscDetails(EmulationDrives[Drive].pBuffer,EmulationDrives[Drive].nImageBytes,&nSectorsPerTrack,&nSides);
                    365: 
1.1.1.2   root      366:     /* Need to read whole track? */
1.1       root      367:     if (Count<0)
                    368:       Count = nSectorsPerTrack;
1.1.1.2   root      369:     /* Write back number of sector per track */
1.1       root      370:     if (pnSectorsPerTrack)
                    371:       *pnSectorsPerTrack = nSectorsPerTrack;
                    372: 
1.1.1.2   root      373:     /* Debug check as if we read over the end of a track we read into side 2! */
1.1       root      374:     if (Count>nSectorsPerTrack) {
                    375:       ErrLog_File("ERROR Floppy_ReadSectors reading over single track\n");
                    376:     }
                    377: 
1.1.1.2   root      378:     /* Seek to sector */
1.1       root      379:     nBytesPerTrack = NUMBYTESPERSECTOR*nSectorsPerTrack;
1.1.1.2   root      380:     Offset = nBytesPerTrack*Side;                 /* First seek to side */
                    381:     Offset += (nBytesPerTrack*nSides)*Track;      /* Then seek to track */
                    382:     Offset += (NUMBYTESPERSECTOR*(Sector-1));     /* And finally to sector */
                    383:     /* Read sectors (usually 512 bytes per sector) */
1.1       root      384:     memcpy(pBuffer,pDiscBuffer+Offset,(int)Count*NUMBYTESPERSECTOR);
                    385: 
                    386:     return(TRUE);
                    387:   }
                    388: 
                    389:   return(FALSE);
                    390: }
                    391: 
1.1.1.2   root      392: 
                    393: /*-----------------------------------------------------------------------*/
1.1       root      394: /*
                    395:   Write sectors from floppy disc image, return TRUE if all OK
                    396:   NOTE Pass -ve as Count to write whole track
                    397: */
                    398: BOOL Floppy_WriteSectors(int Drive,char *pBuffer,unsigned short int Sector,unsigned short int Track,unsigned short int Side, short int Count, int *pnSectorsPerTrack)
                    399: {
                    400:   unsigned char *pDiscBuffer;
                    401:   unsigned short int nSectorsPerTrack,nSides,nBytesPerTrack;
                    402:   long Offset;
                    403: 
1.1.1.2   root      404:   /* Do we have a disc in our drive? */
1.1       root      405:   if (EmulationDrives[Drive].bDiscInserted) {
1.1.1.2   root      406:     /* Looks good */
1.1.1.3   root      407:     /*StatusBar_SetIcon(STATUS_ICON_FLOPPY,ICONSTATE_UPDATE);*/ /* Sorry - no statusbar in Hatari yet */
1.1       root      408:     pDiscBuffer = EmulationDrives[Drive].pBuffer;
                    409: 
1.1.1.2   root      410:     /* Find #sides and #sectors per track */
1.1       root      411:     Floppy_FindDiscDetails(EmulationDrives[Drive].pBuffer,EmulationDrives[Drive].nImageBytes,&nSectorsPerTrack,&nSides);
                    412: 
1.1.1.2   root      413:     /* Need to write whole track? */
1.1       root      414:     if (Count<0)
                    415:       Count = nSectorsPerTrack;
1.1.1.2   root      416:     /* Write back number of sector per track */
1.1       root      417:     if (pnSectorsPerTrack)
                    418:       *pnSectorsPerTrack = nSectorsPerTrack;
                    419: 
1.1.1.2   root      420:     /* Debug check as if we write over the end of a track we write into side 2! */
1.1       root      421:     if (Count>nSectorsPerTrack) {
                    422:       ErrLog_File("ERROR Floppy_WriteSectors reading over single track\n");
                    423:     }
                    424: 
1.1.1.2   root      425:     /* Seek to sector */
1.1       root      426:     nBytesPerTrack = NUMBYTESPERSECTOR*nSectorsPerTrack;
1.1.1.2   root      427:     Offset = nBytesPerTrack*Side;               /* First seek to side */
                    428:     Offset += (nBytesPerTrack*nSides)*Track;    /* Then seek to track */
                    429:     Offset += (NUMBYTESPERSECTOR*(Sector-1));   /* And finally to sector */
                    430:     /* Write sectors (usually 512 bytes per sector) */
1.1       root      431:     memcpy(pDiscBuffer+Offset,pBuffer,(int)Count*NUMBYTESPERSECTOR);
1.1.1.2   root      432:     /* And set 'changed' flag */
1.1       root      433:     EmulationDrives[Drive].bContentsChanged = TRUE;
                    434: 
                    435:     return(TRUE);
                    436:   }
                    437: 
                    438:   return(FALSE);
                    439: }

unix.superglobalmegacorp.com

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