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

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

unix.superglobalmegacorp.com

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