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