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