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