|
|
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 root 42:
1.1.1.10 root 43:
1.1.1.12 root 44: /* Emulation drive details, eg FileName, Inserted, Changed etc... */
45: EMULATION_DRIVE EmulationDrives[MAX_FLOPPYDRIVES];
46: /* Drive A is the default */
47: int nBootDrive = 0;
1.1 root 48:
1.1.1.9 root 49: /* Possible disk image file extensions to scan for */
1.1.1.10 root 50: static const char * const pszDiskImageNameExts[] =
1.1.1.5 root 51: {
1.1.1.10 root 52: ".msa",
53: ".st",
54: ".dim",
55: NULL
1.1 root 56: };
57:
58:
1.1.1.13 root 59: /* local functions */
60: static bool Floppy_EjectBothDrives(void);
61:
62:
1.1.1.2 root 63: /*-----------------------------------------------------------------------*/
1.1.1.11 root 64: /**
65: * Initialize emulation floppy drives
66: */
1.1 root 67: void Floppy_Init(void)
68: {
1.1.1.10 root 69: int i;
1.1 root 70:
1.1.1.10 root 71: /* Clear drive structures */
1.1.1.12 root 72: for (i = 0; i < MAX_FLOPPYDRIVES; i++)
1.1.1.10 root 73: {
1.1.1.12 root 74: /* Clear structs and if floppies available, insert them */
1.1.1.10 root 75: memset(&EmulationDrives[i], 0, sizeof(EMULATION_DRIVE));
1.1.1.12 root 76: if (strlen(ConfigureParams.DiskImage.szDiskFileName[i]) > 0)
77: Floppy_InsertDiskIntoDrive(i);
1.1.1.10 root 78: }
1.1 root 79: }
80:
1.1.1.2 root 81:
82: /*-----------------------------------------------------------------------*/
1.1.1.11 root 83: /**
84: * UnInitialize drives
85: */
1.1 root 86: void Floppy_UnInit(void)
87: {
1.1.1.10 root 88: Floppy_EjectBothDrives();
1.1 root 89: }
90:
1.1.1.2 root 91:
92: /*-----------------------------------------------------------------------*/
1.1.1.11 root 93: /**
94: * Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type)
95: */
1.1.1.12 root 96: void Floppy_MemorySnapShot_Capture(bool bSave)
1.1 root 97: {
1.1.1.10 root 98: int i;
1.1 root 99:
1.1.1.10 root 100: /* If restoring then eject old drives first! */
101: if (!bSave)
102: Floppy_EjectBothDrives();
103:
104: /* Save/Restore details */
1.1.1.12 root 105: for (i = 0; i < MAX_FLOPPYDRIVES; i++)
1.1.1.10 root 106: {
107: MemorySnapShot_Store(&EmulationDrives[i].bDiskInserted, sizeof(EmulationDrives[i].bDiskInserted));
108: MemorySnapShot_Store(&EmulationDrives[i].nImageBytes, sizeof(EmulationDrives[i].nImageBytes));
109: if (!bSave && EmulationDrives[i].bDiskInserted)
110: {
111: EmulationDrives[i].pBuffer = malloc(EmulationDrives[i].nImageBytes);
112: if (!EmulationDrives[i].pBuffer)
113: perror("Floppy_MemorySnapShot_Capture");
114: }
115: if (EmulationDrives[i].pBuffer)
116: MemorySnapShot_Store(EmulationDrives[i].pBuffer, EmulationDrives[i].nImageBytes);
1.1.1.13 root 117: MemorySnapShot_Store(EmulationDrives[i].sFileName, sizeof(EmulationDrives[i].sFileName));
1.1.1.10 root 118: MemorySnapShot_Store(&EmulationDrives[i].bMediaChanged,sizeof(EmulationDrives[i].bMediaChanged));
119: MemorySnapShot_Store(&EmulationDrives[i].bContentsChanged,sizeof(EmulationDrives[i].bContentsChanged));
120: MemorySnapShot_Store(&EmulationDrives[i].bOKToSave,sizeof(EmulationDrives[i].bOKToSave));
121: }
1.1 root 122: }
123:
1.1.1.2 root 124:
125: /*-----------------------------------------------------------------------*/
1.1.1.11 root 126: /**
127: * Find which device to boot from (hard drive or floppy).
128: */
1.1 root 129: void Floppy_GetBootDrive(void)
130: {
1.1.1.15 root 131: /* Default to drive A: */
132: nBootDrive = 0;
133:
134: /* Boot only from hard drive if user wants this */
135: if (!ConfigureParams.HardDisk.bBootFromHardDisk)
136: return;
137:
1.1.1.16 root 138: if (ACSI_EMU_ON || ConfigureParams.HardDisk.bUseIdeMasterHardDiskImage)
1.1.1.15 root 139: {
1.1.1.10 root 140: nBootDrive = 2; /* Drive C */
1.1.1.15 root 141: }
142: else if (GEMDOS_EMU_ON)
143: {
144: int i;
145: for (i = 0; i < MAX_HARDDRIVES; i++)
146: {
147: if (emudrives[i])
148: {
1.1.1.16 root 149: nBootDrive = emudrives[i]->drive_number;
1.1.1.15 root 150: break;
151: }
152: }
153: }
1.1 root 154: }
155:
1.1.1.2 root 156:
157: /*-----------------------------------------------------------------------*/
1.1.1.11 root 158: /**
159: * Test if disk image is write protected. Write protection can be configured
160: * in the GUI. When set to "automatic", we check the file permissions of the
161: * floppy disk image to decide.
162: */
1.1.1.12 root 163: bool Floppy_IsWriteProtected(int Drive)
1.1.1.8 root 164: {
1.1.1.10 root 165: if (ConfigureParams.DiskImage.nWriteProtection == WRITEPROT_OFF)
166: {
1.1.1.14 root 167: return false;
1.1.1.10 root 168: }
169: else if (ConfigureParams.DiskImage.nWriteProtection == WRITEPROT_ON)
170: {
1.1.1.14 root 171: return true;
1.1.1.10 root 172: }
173: else
174: {
175: struct stat FloppyStat;
176: /* Check whether disk is writable */
1.1.1.13 root 177: if (stat(EmulationDrives[Drive].sFileName, &FloppyStat) == 0
1.1.1.12 root 178: && (FloppyStat.st_mode & S_IWUSR))
1.1.1.14 root 179: return false;
1.1.1.10 root 180: else
1.1.1.14 root 181: return true;
1.1.1.10 root 182: }
1.1.1.8 root 183: }
184:
185:
186: /*-----------------------------------------------------------------------*/
1.1.1.11 root 187: /**
188: * Test disk image for valid boot-sector.
189: * It has been noticed that some disks, eg blank images made by the MakeDisk
190: * utility or PaCifiST emulator fill in the boot-sector with incorrect information.
191: * Such images cannot be read correctly using a real ST, and also Hatari.
192: * To try and prevent data loss, we check for this error and flag the drive so
193: * the image will not be saved back to the file.
194: */
1.1.1.12 root 195: static bool Floppy_IsBootSectorOK(int Drive)
1.1 root 196: {
1.1.1.10 root 197: Uint8 *pDiskBuffer;
1.1 root 198:
1.1.1.10 root 199: /* Does our drive have a disk in? */
200: if (EmulationDrives[Drive].bDiskInserted)
201: {
202: pDiskBuffer = EmulationDrives[Drive].pBuffer;
203:
204: /* Check SPC (byte 13) for !=0 value. If is '0', invalid image and Hatari
205: * won't be-able to read (nor will a real ST)! */
206: if (pDiskBuffer[13] != 0)
207: {
1.1.1.14 root 208: return true; /* Disk sector is OK! */
1.1.1.10 root 209: }
210: else
211: {
212: Log_AlertDlg(LOG_WARN, "Disk in drive %c: maybe suffers from the Pacifist/Makedisk bug.\n"
213: "If it does not work, please repair the disk first!\n", 'A' + Drive);
214: }
215: }
1.1 root 216:
1.1.1.14 root 217: return false; /* Bad sector */
1.1 root 218: }
219:
1.1.1.2 root 220:
221: /*-----------------------------------------------------------------------*/
1.1.1.11 root 222: /**
223: * Try to create disk B filename, eg 'auto_100a' becomes 'auto_100b'
224: * Return new filename if think we should try, otherwise NULL
1.1.1.12 root 225: *
226: * TODO: doesn't work with images in ZIP archives
1.1.1.11 root 227: */
228: static char* Floppy_CreateDiskBFileName(const char *pSrcFileName)
1.1 root 229: {
1.1.1.10 root 230: char *szDir, *szName, *szExt;
1.1.1.12 root 231:
1.1.1.10 root 232: /* Allocate temporary memory for strings: */
233: szDir = malloc(3 * FILENAME_MAX);
234: if (!szDir)
235: {
236: perror("Floppy_CreateDiskBFileName");
1.1.1.14 root 237: return false;
1.1.1.10 root 238: }
239: szName = szDir + FILENAME_MAX;
240: szExt = szName + FILENAME_MAX;
241:
242: /* So, first split name into parts */
1.1.1.11 root 243: File_SplitPath(pSrcFileName, szDir, szName, szExt);
1.1.1.10 root 244:
245: /* All OK? */
246: if (strlen(szName) > 0)
247: {
1.1.1.12 root 248: char *last = &(szName[strlen(szName)-1]);
249: /* Now, did filename end with an 'A' or 'a' */
250: if (*last == 'A' || *last == 'a')
1.1.1.10 root 251: {
1.1.1.11 root 252: char *szFull;
1.1.1.10 root 253: /* Change 'A' to a 'B' */
1.1.1.12 root 254: *last += 1;
1.1.1.10 root 255: /* And re-build name into destination */
1.1.1.11 root 256: szFull = File_MakePath(szDir, szName, szExt);
257: if (szFull)
258: {
259: /* Does file exist? */
260: if (File_Exists(szFull))
261: {
262: free(szDir);
263: return szFull;
264: }
265: free(szFull);
266: }
1.1.1.10 root 267: }
268: }
269: free(szDir);
1.1.1.11 root 270: return NULL;
1.1 root 271: }
272:
1.1.1.2 root 273:
274: /*-----------------------------------------------------------------------*/
1.1.1.11 root 275: /**
1.1.1.12 root 276: * Set floppy image to be ejected
277: */
278: const char* Floppy_SetDiskFileNameNone(int Drive)
279: {
280: assert(Drive >= 0 && Drive < MAX_FLOPPYDRIVES);
281: ConfigureParams.DiskImage.szDiskFileName[Drive][0] = '\0';
282: return ConfigureParams.DiskImage.szDiskFileName[Drive];
1.1.1.6 root 283: }
284:
1.1.1.12 root 285: /*-----------------------------------------------------------------------*/
286: /**
287: * Set given floppy drive image file name and handle
288: * different image extensions.
289: * Return corrected file name on success and NULL on failure.
1.1.1.11 root 290: */
1.1.1.12 root 291: const char* Floppy_SetDiskFileName(int Drive, const char *pszFileName, const char *pszZipPath)
1.1.1.6 root 292: {
1.1.1.11 root 293: char *filename;
1.1.1.16 root 294: int i;
1.1 root 295:
1.1.1.12 root 296: /* setting to empty or "none" ejects */
297: if (!*pszFileName || strcasecmp(pszFileName, "none") == 0)
298: {
299: return Floppy_SetDiskFileNameNone(Drive);
300: }
1.1.1.11 root 301: /* See if file exists, and if not, get/add correct extension */
1.1.1.12 root 302: if (!File_Exists(pszFileName))
1.1.1.11 root 303: filename = File_FindPossibleExtFileName(pszFileName, pszDiskImageNameExts);
304: else
305: filename = strdup(pszFileName);
1.1.1.12 root 306: if (!filename)
307: {
308: Log_AlertDlg(LOG_INFO, "Image '%s' not found", pszFileName);
309: return NULL;
310: }
311:
312: /* If we insert a disk into Drive A, should we try to put disk 2 into drive B? */
313: if (Drive == 0 && ConfigureParams.DiskImage.bAutoInsertDiskB)
314: {
315: /* Attempt to make up second filename, eg was 'auto_100a' to 'auto_100b' */
316: char *szDiskBFileName = Floppy_CreateDiskBFileName(filename);
317: if (szDiskBFileName)
318: {
319: /* recurse with Drive B */
320: Floppy_SetDiskFileName(1, szDiskBFileName, pszZipPath);
321: free(szDiskBFileName);
322: }
323: }
324:
1.1.1.16 root 325: /* validity checks */
1.1.1.12 root 326: assert(Drive >= 0 && Drive < MAX_FLOPPYDRIVES);
1.1.1.16 root 327: for (i = 0; i < MAX_FLOPPYDRIVES; i++)
328: {
329: if (i == Drive)
330: continue;
331: /* prevent inserting same image to multiple drives */
332: if (strcmp(filename, ConfigureParams.DiskImage.szDiskFileName[i]) == 0)
333: {
334: Log_AlertDlg(LOG_ERROR, "ERROR: Cannot insert same floppy to multiple drives!");
335: return NULL;
336: }
337: }
338:
339: /* do the changes */
1.1.1.12 root 340: if (pszZipPath)
341: strcpy(ConfigureParams.DiskImage.szDiskZipPath[Drive], pszZipPath);
342: else
343: ConfigureParams.DiskImage.szDiskZipPath[Drive][0] = '\0';
344: strcpy(ConfigureParams.DiskImage.szDiskFileName[Drive], filename);
345: free(filename);
346: //File_MakeAbsoluteName(ConfigureParams.DiskImage.szDiskFileName[Drive]);
347: return ConfigureParams.DiskImage.szDiskFileName[Drive];
348: }
349:
350: /*-----------------------------------------------------------------------*/
351: /**
352: * Insert previously set disk file image into floppy drive.
353: * The WHOLE image is copied into Hatari drive buffers, and
354: * uncompressed if necessary.
355: * Return TRUE on success, false otherwise.
356: */
357: bool Floppy_InsertDiskIntoDrive(int Drive)
358: {
359: long nImageBytes = 0;
360: char *filename;
361:
362: /* Eject disk, if one is inserted (doesn't inform user) */
363: assert(Drive >= 0 && Drive < MAX_FLOPPYDRIVES);
364: Floppy_EjectDiskFromDrive(Drive);
365:
366: filename = ConfigureParams.DiskImage.szDiskFileName[Drive];
367: if (!filename[0])
368: {
1.1.1.14 root 369: return true; /* only do eject */
1.1.1.12 root 370: }
371: if (!File_Exists(filename))
372: {
373: Log_AlertDlg(LOG_INFO, "Image '%s' not found", filename);
1.1.1.14 root 374: return false;
1.1.1.12 root 375: }
376:
1.1.1.10 root 377: /* Check disk image type and read the file: */
1.1.1.14 root 378: if (MSA_FileNameIsMSA(filename, true))
1.1.1.11 root 379: EmulationDrives[Drive].pBuffer = MSA_ReadDisk(filename, &nImageBytes);
1.1.1.14 root 380: else if (ST_FileNameIsST(filename, true))
1.1.1.11 root 381: EmulationDrives[Drive].pBuffer = ST_ReadDisk(filename, &nImageBytes);
1.1.1.14 root 382: else if (DIM_FileNameIsDIM(filename, true))
1.1.1.11 root 383: EmulationDrives[Drive].pBuffer = DIM_ReadDisk(filename, &nImageBytes);
384: else if (ZIP_FileNameIsZIP(filename))
1.1.1.12 root 385: {
386: const char *zippath = ConfigureParams.DiskImage.szDiskZipPath[Drive];
387: EmulationDrives[Drive].pBuffer = ZIP_ReadDisk(filename, zippath, &nImageBytes);
388: }
1.1.1.11 root 389:
390: if (EmulationDrives[Drive].pBuffer == NULL)
391: {
1.1.1.14 root 392: return false;
1.1.1.11 root 393: }
1.1.1.13 root 394:
395: /* Store image filename (required for ejecting the disk later!) */
396: strcpy(EmulationDrives[Drive].sFileName, filename);
397:
398: /* Store size and set drive states */
1.1.1.11 root 399: EmulationDrives[Drive].nImageBytes = nImageBytes;
1.1.1.14 root 400: EmulationDrives[Drive].bDiskInserted = true;
401: EmulationDrives[Drive].bContentsChanged = false;
402: EmulationDrives[Drive].bMediaChanged = true;
1.1.1.11 root 403: EmulationDrives[Drive].bOKToSave = Floppy_IsBootSectorOK(Drive);
1.1.1.12 root 404: Log_Printf(LOG_INFO, "Inserted disk '%s' to drive %c:.",
405: filename, 'A'+Drive);
1.1.1.14 root 406: return true;
1.1 root 407: }
408:
1.1.1.2 root 409:
410: /*-----------------------------------------------------------------------*/
1.1.1.11 root 411: /**
412: * Eject disk from floppy drive, save contents back to PCs hard-drive if
413: * they have been changed.
1.1.1.14 root 414: * Return true if there was something to eject.
1.1.1.11 root 415: */
1.1.1.12 root 416: bool Floppy_EjectDiskFromDrive(int Drive)
1.1 root 417: {
1.1.1.14 root 418: bool bEjected = false;
1.1.1.12 root 419:
1.1.1.10 root 420: /* Does our drive have a disk in? */
421: if (EmulationDrives[Drive].bDiskInserted)
422: {
1.1.1.16 root 423: bool bSaved = false;
1.1.1.13 root 424: char *psFileName = EmulationDrives[Drive].sFileName;
1.1.1.12 root 425:
1.1.1.10 root 426: /* OK, has contents changed? If so, need to save */
427: if (EmulationDrives[Drive].bContentsChanged)
428: {
429: /* Is OK to save image (if boot-sector is bad, don't allow a save) */
430: if (EmulationDrives[Drive].bOKToSave && !Floppy_IsWriteProtected(Drive))
431: {
432: /* Save as .MSA or .ST image? */
1.1.1.14 root 433: if (MSA_FileNameIsMSA(psFileName, true))
1.1.1.16 root 434: bSaved = MSA_WriteDisk(psFileName, EmulationDrives[Drive].pBuffer, EmulationDrives[Drive].nImageBytes);
1.1.1.14 root 435: else if (ST_FileNameIsST(psFileName, true))
1.1.1.16 root 436: bSaved = ST_WriteDisk(psFileName, EmulationDrives[Drive].pBuffer, EmulationDrives[Drive].nImageBytes);
1.1.1.14 root 437: else if (DIM_FileNameIsDIM(psFileName, true))
1.1.1.16 root 438: bSaved = DIM_WriteDisk(psFileName, EmulationDrives[Drive].pBuffer, EmulationDrives[Drive].nImageBytes);
1.1.1.12 root 439: else if (ZIP_FileNameIsZIP(psFileName))
1.1.1.16 root 440: bSaved = ZIP_WriteDisk(psFileName, EmulationDrives[Drive].pBuffer, EmulationDrives[Drive].nImageBytes);
441: if (bSaved)
442: Log_Printf(LOG_INFO, "Updated the contents of floppy image '%s'.", psFileName);
443: else
444: Log_Printf(LOG_INFO, "Writing of this format failed or not supported, discarded the contents\n of floppy image '%s'.", psFileName);
445: } else
446: Log_Printf(LOG_INFO, "Writing not possible, discarded the contents of floppy image\n '%s'.", psFileName);
1.1.1.10 root 447: }
448:
449: /* Inform user that disk has been ejected! */
1.1.1.12 root 450: Log_Printf(LOG_INFO, "Floppy %c: has been removed from drive.",
451: 'A'+Drive);
452:
1.1.1.14 root 453: bEjected = true;
1.1.1.10 root 454: }
455:
456: /* Drive is now empty */
457: if (EmulationDrives[Drive].pBuffer != NULL)
458: {
459: free(EmulationDrives[Drive].pBuffer);
460: EmulationDrives[Drive].pBuffer = NULL;
461: }
1.1.1.12 root 462:
1.1.1.13 root 463: EmulationDrives[Drive].sFileName[0] = '\0';
1.1.1.10 root 464: EmulationDrives[Drive].nImageBytes = 0;
1.1.1.14 root 465: EmulationDrives[Drive].bDiskInserted = false;
466: EmulationDrives[Drive].bContentsChanged = false;
467: EmulationDrives[Drive].bOKToSave = false;
1.1.1.12 root 468:
469: return bEjected;
1.1 root 470: }
471:
1.1.1.2 root 472:
473: /*-----------------------------------------------------------------------*/
1.1.1.11 root 474: /**
475: * Eject all disk image from floppy drives - call when quit.
1.1.1.14 root 476: * Return true if there was something to eject.
1.1.1.11 root 477: */
1.1.1.13 root 478: static bool Floppy_EjectBothDrives(void)
1.1 root 479: {
1.1.1.12 root 480: bool bEjectedA, bEjectedB;
481:
1.1.1.10 root 482: /* Eject disk images from drives 'A' and 'B' */
1.1.1.12 root 483: bEjectedA = Floppy_EjectDiskFromDrive(0);
484: bEjectedB = Floppy_EjectDiskFromDrive(1);
485:
486: return bEjectedA || bEjectedB;
1.1 root 487: }
488:
1.1.1.2 root 489:
490: /*-----------------------------------------------------------------------*/
1.1.1.11 root 491: /**
492: * Double-check information read from boot-sector as this is sometimes found to
1.1.1.17! root 493: * be incorrect. The .ST image file should be divisible by the sector size,
! 494: * the sectors per track. the number of tracks and the number of sides.
1.1.1.11 root 495: * NOTE - Pass information from boot-sector to this function (if we can't
496: * decide we leave it alone).
497: */
1.1.1.17! root 498: static void Floppy_DoubleCheckFormat(long nDiskSize, long nSectorsPerDisk, Uint16 *pnSides, Uint16 *pnSectorsPerTrack)
1.1 root 499: {
1.1.1.17! root 500: long TotalSectors;
! 501: int Sides_fixed;
! 502: int SectorsPerTrack_fixed;
1.1 root 503:
1.1.1.10 root 504: /* Now guess at number of sides */
1.1.1.17! root 505: if ( nDiskSize < (500*1024) ) /* If size >500k assume 2 sides */
! 506: Sides_fixed = 1;
1.1.1.10 root 507: else
1.1.1.17! root 508: Sides_fixed = 2;
1.1.1.10 root 509:
1.1.1.17! root 510: /* Number of 512 bytes sectors for this disk image */
! 511: TotalSectors = nDiskSize / 512;
! 512:
! 513: /* Check some common values */
! 514: if ( TotalSectors == 80*9*Sides_fixed ) { SectorsPerTrack_fixed = 9; }
! 515: else if ( TotalSectors == 81*9*Sides_fixed ) { SectorsPerTrack_fixed = 9; }
! 516: else if ( TotalSectors == 82*9*Sides_fixed ) { SectorsPerTrack_fixed = 9; }
! 517: else if ( TotalSectors == 80*10*Sides_fixed ) { SectorsPerTrack_fixed = 10; }
! 518: else if ( TotalSectors == 81*10*Sides_fixed ) { SectorsPerTrack_fixed = 10; }
! 519: else if ( TotalSectors == 82*10*Sides_fixed ) { SectorsPerTrack_fixed = 10; }
! 520: else if ( TotalSectors == 80*11*Sides_fixed ) { SectorsPerTrack_fixed = 11; }
! 521: else if ( TotalSectors == 81*11*Sides_fixed ) { SectorsPerTrack_fixed = 11; }
! 522: else if ( TotalSectors == 82*11*Sides_fixed ) { SectorsPerTrack_fixed = 11; }
! 523: else if ( TotalSectors == 80*12*Sides_fixed ) { SectorsPerTrack_fixed = 12; }
! 524: else if ( TotalSectors == 81*12*Sides_fixed ) { SectorsPerTrack_fixed = 12; }
! 525: else if ( TotalSectors == 82*12*Sides_fixed ) { SectorsPerTrack_fixed = 12; }
! 526:
! 527: /* unknown combination, assume boot sector is correct */
! 528: else { SectorsPerTrack_fixed = *pnSectorsPerTrack; }
! 529:
! 530: /* Valid new values if necessary */
! 531: if ( ( *pnSides != Sides_fixed ) || ( *pnSectorsPerTrack != SectorsPerTrack_fixed ) )
1.1.1.10 root 532: {
1.1.1.17! root 533: #if 0
! 534: int TracksPerDisk_fixed = TotalSectors / ( SectorsPerTrack_fixed * Sides_fixed );
! 535: Log_Printf(LOG_WARN, "Floppy_DoubleCheckFormat: boot sector doesn't match disk image's size :"
! 536: " total sectors %ld->%ld sides %d->%d sectors %d->%d tracks %d\n",
! 537: nSectorsPerDisk , TotalSectors , *pnSides , Sides_fixed , *pnSectorsPerTrack , SectorsPerTrack_fixed , TracksPerDisk_fixed );
! 538: #endif
! 539: *pnSides = Sides_fixed;
! 540: *pnSectorsPerTrack = SectorsPerTrack_fixed;
1.1.1.10 root 541: }
1.1 root 542: }
543:
1.1.1.2 root 544:
545: /*-----------------------------------------------------------------------*/
1.1.1.11 root 546: /**
547: * Find details of disk image. We need to do this via a function as sometimes the boot-block
548: * is not actually correct with the image - some demos/game disks have incorrect bytes in the
549: * boot sector and this attempts to find the correct values.
550: */
1.1.1.9 root 551: void Floppy_FindDiskDetails(const Uint8 *pBuffer, int nImageBytes,
1.1.1.12 root 552: Uint16 *pnSectorsPerTrack, Uint16 *pnSides)
1.1 root 553: {
1.1.1.17! root 554: Uint16 nSectorsPerTrack, nSides, nSectorsPerDisk;
1.1 root 555:
1.1.1.10 root 556: /* First do check to find number of sectors and bytes per sector */
557: nSectorsPerTrack = SDL_SwapLE16(*(const Uint16 *)(pBuffer+24)); /* SPT */
558: nSides = SDL_SwapLE16(*(const Uint16 *)(pBuffer+26)); /* SIDE */
1.1.1.17! root 559: nSectorsPerDisk = pBuffer[19] | (pBuffer[20] << 8); /* total sectors */
1.1.1.10 root 560:
561: /* If the number of sectors announced is incorrect, the boot-sector may
562: * contain incorrect information, eg the 'Eat.st' demo, or wrongly imaged
563: * single/double sided floppies... */
1.1.1.17! root 564: if (nSectorsPerDisk != nImageBytes/512)
! 565: Floppy_DoubleCheckFormat(nImageBytes, nSectorsPerDisk, &nSides, &nSectorsPerTrack);
1.1.1.10 root 566:
567: /* And set values */
568: if (pnSectorsPerTrack)
569: *pnSectorsPerTrack = nSectorsPerTrack;
570: if (pnSides)
571: *pnSides = nSides;
1.1 root 572: }
573:
1.1.1.2 root 574:
575: /*-----------------------------------------------------------------------*/
1.1.1.11 root 576: /**
577: * Read sectors from floppy disk image, return TRUE if all OK
578: * NOTE Pass -ve as Count to read whole track
579: */
1.1.1.12 root 580: bool Floppy_ReadSectors(int Drive, Uint8 *pBuffer, Uint16 Sector,
581: Uint16 Track, Uint16 Side, short Count,
1.1.1.9 root 582: int *pnSectorsPerTrack)
1.1 root 583: {
1.1.1.10 root 584: Uint8 *pDiskBuffer;
1.1.1.12 root 585: Uint16 nSectorsPerTrack, nSides, nBytesPerTrack;
1.1.1.10 root 586: long Offset;
587: int nImageTracks;
588:
589: /* Do we have a disk in our drive? */
590: if (EmulationDrives[Drive].bDiskInserted)
591: {
592: /* Looks good */
593: pDiskBuffer = EmulationDrives[Drive].pBuffer;
594:
595: /* Find #sides and #sectors per track */
596: Floppy_FindDiskDetails(EmulationDrives[Drive].pBuffer,EmulationDrives[Drive].nImageBytes,&nSectorsPerTrack,&nSides);
597: nImageTracks = ((EmulationDrives[Drive].nImageBytes / NUMBYTESPERSECTOR) / nSectorsPerTrack) / nSides;
598:
599: /* Need to read whole track? */
600: if (Count<0)
601: Count = nSectorsPerTrack;
602: /* Write back number of sector per track */
603: if (pnSectorsPerTrack)
604: *pnSectorsPerTrack = nSectorsPerTrack;
605:
606: /* Debug check as if we read over the end of a track we read into side 2! */
607: if (Count > nSectorsPerTrack)
608: {
609: Log_Printf(LOG_DEBUG, "Floppy_ReadSectors: reading over single track\n");
610: }
611:
612: /* Check that the side number (0 or 1) does not exceed the amount of sides (1 or 2).
613: * (E.g. some games like Drakkhen or Bolo can load additional data from the
614: * second disk side, but they also work with single side floppy drives) */
615: if (Side >= nSides)
616: {
617: Log_Printf(LOG_DEBUG, "Floppy_ReadSectors: Program tries to read from side %i "
618: "of a disk image with %i sides!\n", Side+1, nSides);
1.1.1.14 root 619: return false;
1.1.1.10 root 620: }
621:
622: /* Check if track number is in range */
623: if (Track >= nImageTracks)
624: {
625: Log_Printf(LOG_DEBUG, "Floppy_ReadSectors: Program tries to read from track %i "
626: "of a disk image with only %i tracks!\n", Track, nImageTracks);
1.1.1.14 root 627: return false;
1.1.1.10 root 628: }
629:
630: /* Check if sector number is in range */
631: if (Sector <= 0 || Sector > nSectorsPerTrack)
632: {
633: Log_Printf(LOG_DEBUG, "Floppy_ReadSectors: Program tries to read from sector %i "
634: "of a disk image with %i sectors per track!\n", Sector, nSectorsPerTrack);
1.1.1.14 root 635: return false;
1.1.1.10 root 636: }
637:
638: /* Seek to sector */
639: nBytesPerTrack = NUMBYTESPERSECTOR*nSectorsPerTrack;
640: Offset = nBytesPerTrack*Side; /* First seek to side */
641: Offset += (nBytesPerTrack*nSides)*Track; /* Then seek to track */
642: Offset += (NUMBYTESPERSECTOR*(Sector-1)); /* And finally to sector */
1.1.1.6 root 643:
1.1.1.10 root 644: /* Read sectors (usually 512 bytes per sector) */
645: memcpy(pBuffer, pDiskBuffer+Offset, (int)Count*NUMBYTESPERSECTOR);
1.1 root 646:
1.1.1.14 root 647: return true;
1.1.1.10 root 648: }
1.1 root 649:
1.1.1.14 root 650: return false;
1.1 root 651: }
652:
1.1.1.2 root 653:
654: /*-----------------------------------------------------------------------*/
1.1.1.11 root 655: /**
656: * Write sectors from floppy disk image, return TRUE if all OK
657: * NOTE Pass -ve as Count to write whole track
658: */
1.1.1.12 root 659: bool Floppy_WriteSectors(int Drive, Uint8 *pBuffer, Uint16 Sector,
660: Uint16 Track, Uint16 Side, short Count,
1.1.1.9 root 661: int *pnSectorsPerTrack)
1.1 root 662: {
1.1.1.10 root 663: Uint8 *pDiskBuffer;
1.1.1.12 root 664: Uint16 nSectorsPerTrack, nSides, nBytesPerTrack;
1.1.1.10 root 665: long Offset;
666: int nImageTracks;
667:
668: /* Do we have a writable disk in our drive? */
669: if (EmulationDrives[Drive].bDiskInserted && !Floppy_IsWriteProtected(Drive))
670: {
671: /* Looks good */
672: pDiskBuffer = EmulationDrives[Drive].pBuffer;
673:
674: /* Find #sides and #sectors per track */
675: Floppy_FindDiskDetails(EmulationDrives[Drive].pBuffer,EmulationDrives[Drive].nImageBytes,&nSectorsPerTrack,&nSides);
676: nImageTracks = ((EmulationDrives[Drive].nImageBytes / NUMBYTESPERSECTOR) / nSectorsPerTrack) / nSides;
677:
678: /* Need to write whole track? */
679: if (Count<0)
680: Count = nSectorsPerTrack;
681: /* Write back number of sector per track */
682: if (pnSectorsPerTrack)
683: *pnSectorsPerTrack = nSectorsPerTrack;
684:
685: /* Debug check as if we write over the end of a track we write into side 2! */
686: if (Count > nSectorsPerTrack)
687: {
688: Log_Printf(LOG_DEBUG, "Floppy_WriteSectors: writing over single track\n");
689: }
690:
691: /* Check that the side number (0 or 1) does not exceed the amount of sides (1 or 2). */
692: if (Side >= nSides)
693: {
694: Log_Printf(LOG_DEBUG, "Floppy_WriteSectors: Program tries to write to side %i "
695: "of a disk image with %i sides!\n", Side+1, nSides);
1.1.1.14 root 696: return false;
1.1.1.10 root 697: }
698:
699: /* Check if track number is in range */
700: if (Track >= nImageTracks)
701: {
702: Log_Printf(LOG_DEBUG, "Floppy_WriteSectors: Program tries to write to track %i "
703: "of a disk image with only %i tracks!\n", Track, nImageTracks);
1.1.1.14 root 704: return false;
1.1.1.10 root 705: }
706:
707: /* Check if sector number is in range */
708: if (Sector <= 0 || Sector > nSectorsPerTrack)
709: {
710: Log_Printf(LOG_DEBUG, "Floppy_WriteSectors: Program tries to write to sector %i "
711: "of a disk image with %i sectors per track!\n", Sector, nSectorsPerTrack);
1.1.1.14 root 712: return false;
1.1.1.10 root 713: }
714:
715: /* Seek to sector */
716: nBytesPerTrack = NUMBYTESPERSECTOR*nSectorsPerTrack;
717: Offset = nBytesPerTrack*Side; /* First seek to side */
718: Offset += (nBytesPerTrack*nSides)*Track; /* Then seek to track */
719: Offset += (NUMBYTESPERSECTOR*(Sector-1)); /* And finally to sector */
720:
721: /* Write sectors (usually 512 bytes per sector) */
722: memcpy(pDiskBuffer+Offset, pBuffer, (int)Count*NUMBYTESPERSECTOR);
723: /* And set 'changed' flag */
1.1.1.14 root 724: EmulationDrives[Drive].bContentsChanged = true;
1.1 root 725:
1.1.1.14 root 726: return true;
1.1.1.10 root 727: }
1.1 root 728:
1.1.1.14 root 729: return false;
1.1 root 730: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.