|
|
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:
! 138: if (ACSI_EMU_ON || ConfigureParams.HardDisk.bUseIdeHardDiskImage)
! 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: {
! 149: nBootDrive = emudrives[i]->hd_letter;
! 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 root 294:
1.1.1.12 root 295: /* setting to empty or "none" ejects */
296: if (!*pszFileName || strcasecmp(pszFileName, "none") == 0)
297: {
298: return Floppy_SetDiskFileNameNone(Drive);
299: }
1.1.1.11 root 300: /* See if file exists, and if not, get/add correct extension */
1.1.1.12 root 301: if (!File_Exists(pszFileName))
1.1.1.11 root 302: filename = File_FindPossibleExtFileName(pszFileName, pszDiskImageNameExts);
303: else
304: filename = strdup(pszFileName);
1.1.1.12 root 305: if (!filename)
306: {
307: Log_AlertDlg(LOG_INFO, "Image '%s' not found", pszFileName);
308: return NULL;
309: }
310:
311: /* If we insert a disk into Drive A, should we try to put disk 2 into drive B? */
312: if (Drive == 0 && ConfigureParams.DiskImage.bAutoInsertDiskB)
313: {
314: /* Attempt to make up second filename, eg was 'auto_100a' to 'auto_100b' */
315: char *szDiskBFileName = Floppy_CreateDiskBFileName(filename);
316: if (szDiskBFileName)
317: {
318: /* recurse with Drive B */
319: Floppy_SetDiskFileName(1, szDiskBFileName, pszZipPath);
320: free(szDiskBFileName);
321: }
322: }
323:
324: /* do the changes */
325: assert(Drive >= 0 && Drive < MAX_FLOPPYDRIVES);
326: if (pszZipPath)
327: strcpy(ConfigureParams.DiskImage.szDiskZipPath[Drive], pszZipPath);
328: else
329: ConfigureParams.DiskImage.szDiskZipPath[Drive][0] = '\0';
330: strcpy(ConfigureParams.DiskImage.szDiskFileName[Drive], filename);
331: free(filename);
332: //File_MakeAbsoluteName(ConfigureParams.DiskImage.szDiskFileName[Drive]);
333: return ConfigureParams.DiskImage.szDiskFileName[Drive];
334: }
335:
336: /*-----------------------------------------------------------------------*/
337: /**
338: * Insert previously set disk file image into floppy drive.
339: * The WHOLE image is copied into Hatari drive buffers, and
340: * uncompressed if necessary.
341: * Return TRUE on success, false otherwise.
342: */
343: bool Floppy_InsertDiskIntoDrive(int Drive)
344: {
345: long nImageBytes = 0;
346: char *filename;
347:
348: /* Eject disk, if one is inserted (doesn't inform user) */
349: assert(Drive >= 0 && Drive < MAX_FLOPPYDRIVES);
350: Floppy_EjectDiskFromDrive(Drive);
351:
352: filename = ConfigureParams.DiskImage.szDiskFileName[Drive];
353: if (!filename[0])
354: {
1.1.1.14 root 355: return true; /* only do eject */
1.1.1.12 root 356: }
357: if (!File_Exists(filename))
358: {
359: Log_AlertDlg(LOG_INFO, "Image '%s' not found", filename);
1.1.1.14 root 360: return false;
1.1.1.12 root 361: }
362:
1.1.1.10 root 363: /* Check disk image type and read the file: */
1.1.1.14 root 364: if (MSA_FileNameIsMSA(filename, true))
1.1.1.11 root 365: EmulationDrives[Drive].pBuffer = MSA_ReadDisk(filename, &nImageBytes);
1.1.1.14 root 366: else if (ST_FileNameIsST(filename, true))
1.1.1.11 root 367: EmulationDrives[Drive].pBuffer = ST_ReadDisk(filename, &nImageBytes);
1.1.1.14 root 368: else if (DIM_FileNameIsDIM(filename, true))
1.1.1.11 root 369: EmulationDrives[Drive].pBuffer = DIM_ReadDisk(filename, &nImageBytes);
370: else if (ZIP_FileNameIsZIP(filename))
1.1.1.12 root 371: {
372: const char *zippath = ConfigureParams.DiskImage.szDiskZipPath[Drive];
373: EmulationDrives[Drive].pBuffer = ZIP_ReadDisk(filename, zippath, &nImageBytes);
374: }
1.1.1.11 root 375:
376: if (EmulationDrives[Drive].pBuffer == NULL)
377: {
1.1.1.14 root 378: return false;
1.1.1.11 root 379: }
1.1.1.13 root 380:
381: /* Store image filename (required for ejecting the disk later!) */
382: strcpy(EmulationDrives[Drive].sFileName, filename);
383:
384: /* Store size and set drive states */
1.1.1.11 root 385: EmulationDrives[Drive].nImageBytes = nImageBytes;
1.1.1.14 root 386: EmulationDrives[Drive].bDiskInserted = true;
387: EmulationDrives[Drive].bContentsChanged = false;
388: EmulationDrives[Drive].bMediaChanged = true;
1.1.1.11 root 389: EmulationDrives[Drive].bOKToSave = Floppy_IsBootSectorOK(Drive);
1.1.1.12 root 390: Log_Printf(LOG_INFO, "Inserted disk '%s' to drive %c:.",
391: filename, 'A'+Drive);
1.1.1.14 root 392: return true;
1.1 root 393: }
394:
1.1.1.2 root 395:
396: /*-----------------------------------------------------------------------*/
1.1.1.11 root 397: /**
398: * Eject disk from floppy drive, save contents back to PCs hard-drive if
399: * they have been changed.
1.1.1.14 root 400: * Return true if there was something to eject.
1.1.1.11 root 401: */
1.1.1.12 root 402: bool Floppy_EjectDiskFromDrive(int Drive)
1.1 root 403: {
1.1.1.14 root 404: bool bEjected = false;
1.1.1.12 root 405:
1.1.1.10 root 406: /* Does our drive have a disk in? */
407: if (EmulationDrives[Drive].bDiskInserted)
408: {
1.1.1.13 root 409: char *psFileName = EmulationDrives[Drive].sFileName;
1.1.1.12 root 410:
1.1.1.10 root 411: /* OK, has contents changed? If so, need to save */
412: if (EmulationDrives[Drive].bContentsChanged)
413: {
414: /* Is OK to save image (if boot-sector is bad, don't allow a save) */
415: if (EmulationDrives[Drive].bOKToSave && !Floppy_IsWriteProtected(Drive))
416: {
1.1.1.13 root 417: Log_Printf(LOG_INFO, "Flush contents to floppy image '%s'.", psFileName);
1.1.1.10 root 418: /* Save as .MSA or .ST image? */
1.1.1.14 root 419: if (MSA_FileNameIsMSA(psFileName, true))
1.1.1.12 root 420: MSA_WriteDisk(psFileName, EmulationDrives[Drive].pBuffer, EmulationDrives[Drive].nImageBytes);
1.1.1.14 root 421: else if (ST_FileNameIsST(psFileName, true))
1.1.1.12 root 422: ST_WriteDisk(psFileName, EmulationDrives[Drive].pBuffer, EmulationDrives[Drive].nImageBytes);
1.1.1.14 root 423: else if (DIM_FileNameIsDIM(psFileName, true))
1.1.1.12 root 424: DIM_WriteDisk(psFileName, EmulationDrives[Drive].pBuffer, EmulationDrives[Drive].nImageBytes);
425: else if (ZIP_FileNameIsZIP(psFileName))
426: ZIP_WriteDisk(psFileName, EmulationDrives[Drive].pBuffer, EmulationDrives[Drive].nImageBytes);
1.1.1.10 root 427: }
428: }
429:
430: /* Inform user that disk has been ejected! */
1.1.1.12 root 431: Log_Printf(LOG_INFO, "Floppy %c: has been removed from drive.",
432: 'A'+Drive);
433:
1.1.1.14 root 434: bEjected = true;
1.1.1.10 root 435: }
436:
437: /* Drive is now empty */
438: if (EmulationDrives[Drive].pBuffer != NULL)
439: {
440: free(EmulationDrives[Drive].pBuffer);
441: EmulationDrives[Drive].pBuffer = NULL;
442: }
1.1.1.12 root 443:
1.1.1.13 root 444: EmulationDrives[Drive].sFileName[0] = '\0';
1.1.1.10 root 445: EmulationDrives[Drive].nImageBytes = 0;
1.1.1.14 root 446: EmulationDrives[Drive].bDiskInserted = false;
447: EmulationDrives[Drive].bContentsChanged = false;
448: EmulationDrives[Drive].bOKToSave = false;
1.1.1.12 root 449:
450: return bEjected;
1.1 root 451: }
452:
1.1.1.2 root 453:
454: /*-----------------------------------------------------------------------*/
1.1.1.11 root 455: /**
456: * Eject all disk image from floppy drives - call when quit.
1.1.1.14 root 457: * Return true if there was something to eject.
1.1.1.11 root 458: */
1.1.1.13 root 459: static bool Floppy_EjectBothDrives(void)
1.1 root 460: {
1.1.1.12 root 461: bool bEjectedA, bEjectedB;
462:
1.1.1.10 root 463: /* Eject disk images from drives 'A' and 'B' */
1.1.1.12 root 464: bEjectedA = Floppy_EjectDiskFromDrive(0);
465: bEjectedB = Floppy_EjectDiskFromDrive(1);
466:
467: return bEjectedA || bEjectedB;
1.1 root 468: }
469:
1.1.1.2 root 470:
471: /*-----------------------------------------------------------------------*/
1.1.1.11 root 472: /**
473: * Double-check information read from boot-sector as this is sometimes found to
474: * be incorrect. The .ST image file should be divisible by the sector size and
475: * sectors per track.
476: * NOTE - Pass information from boot-sector to this function (if we can't
477: * decide we leave it alone).
478: */
1.1.1.9 root 479: static void Floppy_DoubleCheckFormat(long nDiskSize, Uint16 *pnSides, Uint16 *pnSectorsPerTrack)
1.1 root 480: {
1.1.1.10 root 481: int nSectorsPerTrack;
482: long TotalSectors;
1.1 root 483:
1.1.1.10 root 484: /* Now guess at number of sides */
485: if (nDiskSize < (500*1024)) /* Is size is >500k assume 2 sides to disk! */
486: *pnSides = 1;
487: else
488: *pnSides = 2;
489:
490: /* And Sectors Per Track(always 512 bytes per sector) */
491: TotalSectors = nDiskSize/512; /* # Sectors on disk image */
492: /* Does this match up with what we've read from boot-sector? */
493: nSectorsPerTrack = *pnSectorsPerTrack;
494: if (nSectorsPerTrack==0) /* Check valid, default to 9 */
495: nSectorsPerTrack = 9;
496: if ((TotalSectors%nSectorsPerTrack)!=0)
497: {
498: /* No, we have an invalid boot-sector - re-calculate from disk size */
499: if ((TotalSectors%9)==0) /* Work in this order.... */
500: *pnSectorsPerTrack = 9;
501: else if ((TotalSectors%10)==0)
502: *pnSectorsPerTrack = 10;
503: else if ((TotalSectors%11)==0)
504: *pnSectorsPerTrack = 11;
505: else if ((TotalSectors%12)==0)
506: *pnSectorsPerTrack = 12;
507: }
508: /* else unknown, assume boot-sector is correct!!! */
1.1 root 509: }
510:
1.1.1.2 root 511:
512: /*-----------------------------------------------------------------------*/
1.1.1.11 root 513: /**
514: * Find details of disk image. We need to do this via a function as sometimes the boot-block
515: * is not actually correct with the image - some demos/game disks have incorrect bytes in the
516: * boot sector and this attempts to find the correct values.
517: */
1.1.1.9 root 518: void Floppy_FindDiskDetails(const Uint8 *pBuffer, int nImageBytes,
1.1.1.12 root 519: Uint16 *pnSectorsPerTrack, Uint16 *pnSides)
1.1 root 520: {
1.1.1.10 root 521: Uint16 nSectorsPerTrack, nSides, nSectors;
1.1 root 522:
1.1.1.10 root 523: /* First do check to find number of sectors and bytes per sector */
524: nSectorsPerTrack = SDL_SwapLE16(*(const Uint16 *)(pBuffer+24)); /* SPT */
525: nSides = SDL_SwapLE16(*(const Uint16 *)(pBuffer+26)); /* SIDE */
526: nSectors = pBuffer[19] | (pBuffer[20] << 8); /* total sectors */
527:
528: /* If the number of sectors announced is incorrect, the boot-sector may
529: * contain incorrect information, eg the 'Eat.st' demo, or wrongly imaged
530: * single/double sided floppies... */
531: if (nSectors != nImageBytes/512)
532: Floppy_DoubleCheckFormat(nImageBytes, &nSides, &nSectorsPerTrack);
533:
534: /* And set values */
535: if (pnSectorsPerTrack)
536: *pnSectorsPerTrack = nSectorsPerTrack;
537: if (pnSides)
538: *pnSides = nSides;
1.1 root 539: }
540:
1.1.1.2 root 541:
542: /*-----------------------------------------------------------------------*/
1.1.1.11 root 543: /**
544: * Read sectors from floppy disk image, return TRUE if all OK
545: * NOTE Pass -ve as Count to read whole track
546: */
1.1.1.12 root 547: bool Floppy_ReadSectors(int Drive, Uint8 *pBuffer, Uint16 Sector,
548: Uint16 Track, Uint16 Side, short Count,
1.1.1.9 root 549: int *pnSectorsPerTrack)
1.1 root 550: {
1.1.1.10 root 551: Uint8 *pDiskBuffer;
1.1.1.12 root 552: Uint16 nSectorsPerTrack, nSides, nBytesPerTrack;
1.1.1.10 root 553: long Offset;
554: int nImageTracks;
555:
556: /* Do we have a disk in our drive? */
557: if (EmulationDrives[Drive].bDiskInserted)
558: {
559: /* Looks good */
560: pDiskBuffer = EmulationDrives[Drive].pBuffer;
561:
562: /* Find #sides and #sectors per track */
563: Floppy_FindDiskDetails(EmulationDrives[Drive].pBuffer,EmulationDrives[Drive].nImageBytes,&nSectorsPerTrack,&nSides);
564: nImageTracks = ((EmulationDrives[Drive].nImageBytes / NUMBYTESPERSECTOR) / nSectorsPerTrack) / nSides;
565:
566: /* Need to read whole track? */
567: if (Count<0)
568: Count = nSectorsPerTrack;
569: /* Write back number of sector per track */
570: if (pnSectorsPerTrack)
571: *pnSectorsPerTrack = nSectorsPerTrack;
572:
573: /* Debug check as if we read over the end of a track we read into side 2! */
574: if (Count > nSectorsPerTrack)
575: {
576: Log_Printf(LOG_DEBUG, "Floppy_ReadSectors: reading over single track\n");
577: }
578:
579: /* Check that the side number (0 or 1) does not exceed the amount of sides (1 or 2).
580: * (E.g. some games like Drakkhen or Bolo can load additional data from the
581: * second disk side, but they also work with single side floppy drives) */
582: if (Side >= nSides)
583: {
584: Log_Printf(LOG_DEBUG, "Floppy_ReadSectors: Program tries to read from side %i "
585: "of a disk image with %i sides!\n", Side+1, nSides);
1.1.1.14 root 586: return false;
1.1.1.10 root 587: }
588:
589: /* Check if track number is in range */
590: if (Track >= nImageTracks)
591: {
592: Log_Printf(LOG_DEBUG, "Floppy_ReadSectors: Program tries to read from track %i "
593: "of a disk image with only %i tracks!\n", Track, nImageTracks);
1.1.1.14 root 594: return false;
1.1.1.10 root 595: }
596:
597: /* Check if sector number is in range */
598: if (Sector <= 0 || Sector > nSectorsPerTrack)
599: {
600: Log_Printf(LOG_DEBUG, "Floppy_ReadSectors: Program tries to read from sector %i "
601: "of a disk image with %i sectors per track!\n", Sector, nSectorsPerTrack);
1.1.1.14 root 602: return false;
1.1.1.10 root 603: }
604:
605: /* Seek to sector */
606: nBytesPerTrack = NUMBYTESPERSECTOR*nSectorsPerTrack;
607: Offset = nBytesPerTrack*Side; /* First seek to side */
608: Offset += (nBytesPerTrack*nSides)*Track; /* Then seek to track */
609: Offset += (NUMBYTESPERSECTOR*(Sector-1)); /* And finally to sector */
1.1.1.6 root 610:
1.1.1.10 root 611: /* Read sectors (usually 512 bytes per sector) */
612: memcpy(pBuffer, pDiskBuffer+Offset, (int)Count*NUMBYTESPERSECTOR);
1.1 root 613:
1.1.1.14 root 614: return true;
1.1.1.10 root 615: }
1.1 root 616:
1.1.1.14 root 617: return false;
1.1 root 618: }
619:
1.1.1.2 root 620:
621: /*-----------------------------------------------------------------------*/
1.1.1.11 root 622: /**
623: * Write sectors from floppy disk image, return TRUE if all OK
624: * NOTE Pass -ve as Count to write whole track
625: */
1.1.1.12 root 626: bool Floppy_WriteSectors(int Drive, Uint8 *pBuffer, Uint16 Sector,
627: Uint16 Track, Uint16 Side, short Count,
1.1.1.9 root 628: int *pnSectorsPerTrack)
1.1 root 629: {
1.1.1.10 root 630: Uint8 *pDiskBuffer;
1.1.1.12 root 631: Uint16 nSectorsPerTrack, nSides, nBytesPerTrack;
1.1.1.10 root 632: long Offset;
633: int nImageTracks;
634:
635: /* Do we have a writable disk in our drive? */
636: if (EmulationDrives[Drive].bDiskInserted && !Floppy_IsWriteProtected(Drive))
637: {
638: /* Looks good */
639: pDiskBuffer = EmulationDrives[Drive].pBuffer;
640:
641: /* Find #sides and #sectors per track */
642: Floppy_FindDiskDetails(EmulationDrives[Drive].pBuffer,EmulationDrives[Drive].nImageBytes,&nSectorsPerTrack,&nSides);
643: nImageTracks = ((EmulationDrives[Drive].nImageBytes / NUMBYTESPERSECTOR) / nSectorsPerTrack) / nSides;
644:
645: /* Need to write whole track? */
646: if (Count<0)
647: Count = nSectorsPerTrack;
648: /* Write back number of sector per track */
649: if (pnSectorsPerTrack)
650: *pnSectorsPerTrack = nSectorsPerTrack;
651:
652: /* Debug check as if we write over the end of a track we write into side 2! */
653: if (Count > nSectorsPerTrack)
654: {
655: Log_Printf(LOG_DEBUG, "Floppy_WriteSectors: writing over single track\n");
656: }
657:
658: /* Check that the side number (0 or 1) does not exceed the amount of sides (1 or 2). */
659: if (Side >= nSides)
660: {
661: Log_Printf(LOG_DEBUG, "Floppy_WriteSectors: Program tries to write to side %i "
662: "of a disk image with %i sides!\n", Side+1, nSides);
1.1.1.14 root 663: return false;
1.1.1.10 root 664: }
665:
666: /* Check if track number is in range */
667: if (Track >= nImageTracks)
668: {
669: Log_Printf(LOG_DEBUG, "Floppy_WriteSectors: Program tries to write to track %i "
670: "of a disk image with only %i tracks!\n", Track, nImageTracks);
1.1.1.14 root 671: return false;
1.1.1.10 root 672: }
673:
674: /* Check if sector number is in range */
675: if (Sector <= 0 || Sector > nSectorsPerTrack)
676: {
677: Log_Printf(LOG_DEBUG, "Floppy_WriteSectors: Program tries to write to sector %i "
678: "of a disk image with %i sectors per track!\n", Sector, nSectorsPerTrack);
1.1.1.14 root 679: return false;
1.1.1.10 root 680: }
681:
682: /* Seek to sector */
683: nBytesPerTrack = NUMBYTESPERSECTOR*nSectorsPerTrack;
684: Offset = nBytesPerTrack*Side; /* First seek to side */
685: Offset += (nBytesPerTrack*nSides)*Track; /* Then seek to track */
686: Offset += (NUMBYTESPERSECTOR*(Sector-1)); /* And finally to sector */
687:
688: /* Write sectors (usually 512 bytes per sector) */
689: memcpy(pDiskBuffer+Offset, pBuffer, (int)Count*NUMBYTESPERSECTOR);
690: /* And set 'changed' flag */
1.1.1.14 root 691: EmulationDrives[Drive].bContentsChanged = true;
1.1 root 692:
1.1.1.14 root 693: return true;
1.1.1.10 root 694: }
1.1 root 695:
1.1.1.14 root 696: return false;
1.1 root 697: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.