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