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