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