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