Annotation of hatari/src/floppy_ipf.c, revision 1.1.1.5

1.1       root        1: /*
                      2:   Hatari - floppy_ipf.c
                      3: 
                      4:   This file is distributed under the GNU General Public License, version 2 or at
                      5:   your option any later version. Read the file gpl.txt for details.
                      6: 
                      7:   IPF disk image support.
                      8: 
                      9:   IPF files are handled using the capsimage library, which emulates the FDC
                     10:   at low level and allows to read complex protections.
                     11: 
1.1.1.4   root       12:   RAW stream files made with KryoFlux board or CT RAW dumped with an Amiga are also handled
1.1       root       13:   by the capsimage library.
                     14: */
                     15: const char floppy_ipf_fileid[] = "Hatari floppy_ipf.c : " __DATE__ " " __TIME__;
                     16: 
                     17: #include "main.h"
                     18: #include "file.h"
                     19: #include "floppy.h"
                     20: #include "floppy_ipf.h"
                     21: #include "fdc.h"
                     22: #include "log.h"
                     23: #include "memorySnapShot.h"
                     24: #include "screen.h"
                     25: #include "video.h"
1.1.1.4   root       26: #include "m68000.h"
1.1       root       27: #include "cycles.h"
                     28: 
1.1.1.4   root       29: #include <string.h>
                     30: 
1.1       root       31: #ifdef HAVE_CAPSIMAGE
                     32: #if CAPSIMAGE_VERSION == 5
                     33: #include <caps5/CapsLibAll.h>
                     34: #else
                     35: #include <caps/fdc.h>
                     36: #define CAPS_LIB_RELEASE       4
                     37: #define CAPS_LIB_REVISION      2
                     38: #endif
                     39: /* Macro to check release and revision */
                     40: #define        CAPS_LIB_REL_REV        ( CAPS_LIB_RELEASE * 100 + CAPS_LIB_REVISION )
                     41: #endif
                     42: 
                     43: 
1.1.1.4   root       44: /* To handle RAW stream images with one file per track/side */
                     45: #define        IPF_MAX_TRACK_RAW_STREAM_IMAGE  84                              /* track number can be 0 .. 83 */
                     46: #define        IPF_MAX_SIDE_RAW_STREAM_IMAGE   2                               /* side number can be 0 or 1 */
                     47: 
                     48: struct
                     49: {
                     50:        int             TrackSize;
                     51:        Uint8           *TrackData;
                     52: } IPF_RawStreamImage[ MAX_FLOPPYDRIVES ][ IPF_MAX_TRACK_RAW_STREAM_IMAGE ][ IPF_MAX_SIDE_RAW_STREAM_IMAGE ];
                     53: 
                     54: 
                     55: 
1.1       root       56: typedef struct
                     57: {
                     58: #ifdef HAVE_CAPSIMAGE
                     59:        Uint32                  CapsLibRelease;
                     60:        Uint32                  CapsLibRevision;
                     61: 
                     62:        struct CapsFdc          Fdc;                            /* Fdc state */
                     63:        struct CapsDrive        Drive[ MAX_FLOPPYDRIVES ];      /* Physical drives */
1.1.1.4   root       64:        CapsLong                CapsImage[ MAX_FLOPPYDRIVES ];  /* Image Id or -1 if drive empty */
                     65:        CapsLong                CapsImageType[ MAX_FLOPPYDRIVES ]; /* ImageType or -1 if not known */
1.1       root       66: 
                     67:        int                     Rev_Track[ MAX_FLOPPYDRIVES ];  /* Needed to handle CAPSSetRevolution for type II/III commands */
                     68:        int                     Rev_Side[ MAX_FLOPPYDRIVES ];
                     69: 
                     70:        bool                    DriveEnabled[ MAX_FLOPPYDRIVES ];/* Is drive ON or OFF */
                     71:        bool                    DoubleSided[ MAX_FLOPPYDRIVES ];/* Is drive double sided or not */
1.1.1.3   root       72: #endif
1.1       root       73: 
                     74:        Sint64                  FdcClock;                       /* Current value of CyclesGlobalClockCounter */
                     75: } IPF_STRUCT;
                     76: 
                     77: 
                     78: static IPF_STRUCT      IPF_State;                      /* All variables related to the IPF support */
                     79: 
                     80: 
1.1.1.4   root       81: static bool    IPF_Eject_RawStreamImage ( int Drive );
1.1       root       82: #ifdef HAVE_CAPSIMAGE
1.1.1.4   root       83: static char    *IPF_FilenameFindTrackSide (char *FileName);
                     84: static bool    IPF_Insert_RawStreamImage ( int Drive );
                     85: 
1.1       root       86: static void    IPF_CallBack_Trk ( struct CapsFdc *pc , CapsULong State );
                     87: static void    IPF_CallBack_Irq ( struct CapsFdc *pc , CapsULong State );
                     88: static void    IPF_CallBack_Drq ( struct CapsFdc *pc , CapsULong State );
                     89: static void    IPF_Drive_Update_Enable_Side ( void );
1.1.1.4   root       90: static void    IPF_FDC_LogCommand ( Uint8 Command );
1.1       root       91: #endif
                     92: 
                     93: 
                     94: 
                     95: 
                     96: /*-----------------------------------------------------------------------*/
                     97: /**
                     98:  * Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type)
                     99:  * We must take care of whether Hatari was compiled with IPF support of not
                    100:  * when saving/restoring snapshots to avoid incompatibilies.
                    101:  */
                    102: void IPF_MemorySnapShot_Capture(bool bSave)
                    103: {
                    104:        int     StructSize;
                    105:        int     Drive;
1.1.1.4   root      106:        int     Track , Side;
                    107:        int     TrackSize;
                    108:        Uint8   *p;
                    109: 
1.1       root      110: 
                    111:        if ( bSave )                                    /* Saving snapshot */
                    112:        {
                    113:                StructSize = sizeof ( IPF_State );      /* 0 if HAVE_CAPSIMAGE is not defined */
                    114:                MemorySnapShot_Store(&StructSize, sizeof(StructSize));
                    115:                if ( StructSize > 0 )
1.1.1.4   root      116:                {
1.1       root      117:                        MemorySnapShot_Store(&IPF_State, sizeof(IPF_State));
1.1.1.4   root      118: 
                    119:                        /* Save the content of IPF_RawStreamImage[] */
                    120:                        for ( Drive=0 ; Drive < MAX_FLOPPYDRIVES ; Drive++ )
                    121:                                for ( Track=0 ; Track<IPF_MAX_TRACK_RAW_STREAM_IMAGE ; Track++ )
                    122:                                        for ( Side=0 ; Side<IPF_MAX_SIDE_RAW_STREAM_IMAGE ; Side++ )
                    123:                                        {
                    124:                                                TrackSize = IPF_RawStreamImage[ Drive ][ Track ][Side].TrackSize;
                    125: //                                             fprintf ( stderr , "IPF : save raw stream drive=%d track=%d side=%d : %d\n" , Drive , Track , Side , TrackSize );
                    126:                                                MemorySnapShot_Store(&TrackSize, sizeof(TrackSize));
                    127:                                                if ( TrackSize > 0 )
                    128:                                                        MemorySnapShot_Store(IPF_RawStreamImage[ Drive ][ Track ][Side].TrackData, TrackSize);
                    129:                                        }
                    130:                }
1.1       root      131:        }
                    132: 
                    133:        else                                            /* Restoring snapshot */
                    134:        {
                    135:                MemorySnapShot_Store(&StructSize, sizeof(StructSize));
                    136:                if ( ( StructSize == 0 ) && ( sizeof ( IPF_State ) > 0 ) )
                    137:                {
1.1.1.5 ! root      138:                        Log_AlertDlg(LOG_ERROR, "Hatari built with IPF floppy support, but no IPF data in memory snapshot -> skip");
1.1       root      139:                        return;                         /* Continue restoring the rest of the memory snapshot */
                    140:                }
                    141:                else if ( ( StructSize > 0 ) && ( sizeof ( IPF_State ) == 0 ) )
                    142:                {
1.1.1.5 ! root      143:                        Log_AlertDlg(LOG_ERROR, "Memory snapshot with IPF floppy data, but Hatari built without IPF support -> skip");
1.1       root      144:                        MemorySnapShot_Skip( StructSize );      /* Ignore the IPF data */
                    145:                        return;                         /* Continue restoring the rest of the memory snapshot */
                    146:                }
                    147:                else if ( ( StructSize > 0 ) && ( StructSize != sizeof ( IPF_State ) ) )
                    148:                {
1.1.1.5 ! root      149:                        Log_AlertDlg(LOG_ERROR, "Memory snapshot IPF floppy data incompatible with this Hatari version -> skip");
1.1       root      150:                        MemorySnapShot_Skip( StructSize );      /* Ignore the IPF data */
                    151:                        return;                         /* Continue restoring the rest of the memory snapshot */
                    152:                }
                    153: 
                    154:                if ( StructSize > 0 )
                    155:                {
                    156:                        MemorySnapShot_Store(&IPF_State, sizeof(IPF_State));
                    157: 
                    158: #ifdef HAVE_CAPSIMAGE
                    159:                        /* For IPF structures, we need to update some pointers in Fdc/Drive/CapsImage */
                    160:                        /* drive : PUBYTE trackbuf, PUDWORD timebuf */
                    161:                        /* fdc : PCAPSDRIVE driveprc, PCAPSDRIVE drive, CAPSFDCHOOK callback functions */
                    162:                        IPF_State.Fdc.drive = IPF_State.Drive;          /* Connect drives array to the FDC */
                    163:                        if ( IPF_State.Fdc.driveprc != NULL )           /* Recompute active drive's pointer */
                    164:                                IPF_State.Fdc.driveprc = IPF_State.Fdc.drive + IPF_State.Fdc.driveact;
                    165: 
1.1.1.2   root      166:                        CAPSFdcInvalidateTrack ( &IPF_State.Fdc , 0 );  /* Invalidate buffered track data for drive 0 */
                    167:                        CAPSFdcInvalidateTrack ( &IPF_State.Fdc , 1 );  /* Invalidate buffered track data for drive 1 */
                    168: 
1.1       root      169:                        /* Set callback functions */
                    170:                        IPF_State.Fdc.cbirq = IPF_CallBack_Irq;
                    171:                        IPF_State.Fdc.cbdrq = IPF_CallBack_Drq;
                    172:                        IPF_State.Fdc.cbtrk = IPF_CallBack_Trk;
                    173: #endif
                    174: 
                    175:                        /* Call IPF_Insert to recompute IPF_State.CapsImage[ Drive ] */
                    176:                        for ( Drive=0 ; Drive < MAX_FLOPPYDRIVES ; Drive++ )
                    177:                                if ( EmulationDrives[Drive].ImageType == FLOPPY_IMAGE_TYPE_IPF )
                    178:                                        if ( IPF_Insert ( Drive , EmulationDrives[Drive].pBuffer , EmulationDrives[Drive].nImageBytes ) == false )
                    179:                                        {
                    180:                                                Log_AlertDlg(LOG_ERROR, "Error restoring IPF image %s in drive %d" ,
                    181:                                                        EmulationDrives[Drive].sFileName , Drive );
                    182:                                                return;
                    183:                                        }
                    184: 
1.1.1.4   root      185:                        /* Restore the content of IPF_RawStreamImage[] */
                    186:                        /* NOTE  : IPF_Insert above might already have read the raw tracks from disk, */
                    187:                        /* so we free all those tracks and read them again from the snapshot instead */
                    188:                        /* (not very efficient, but it's a rare case anyway) */
                    189:                        for ( Drive=0 ; Drive < MAX_FLOPPYDRIVES ; Drive++ )
                    190:                        {
                    191:                                IPF_Eject_RawStreamImage ( Drive );
                    192:                                for ( Track=0 ; Track<IPF_MAX_TRACK_RAW_STREAM_IMAGE ; Track++ )
                    193:                                        for ( Side=0 ; Side<IPF_MAX_SIDE_RAW_STREAM_IMAGE ; Side++ )
                    194:                                        {
                    195:                                                MemorySnapShot_Store(&TrackSize, sizeof(TrackSize));
                    196: //                                             fprintf ( stderr , "IPF : restore raw stream drive=%d track=%d side=%d : %d\n" , Drive , Track , Side , TrackSize );
                    197:                                                IPF_RawStreamImage[ Drive ][ Track ][Side].TrackSize = TrackSize;
                    198:                                                IPF_RawStreamImage[ Drive ][ Track ][Side].TrackData = NULL;
                    199:                                                if ( TrackSize > 0 )
                    200:                                                {
                    201:                                                        p = malloc ( TrackSize );
                    202:                                                        if ( p == NULL )
                    203:                                                        {
                    204:                                                                Log_AlertDlg(LOG_ERROR, "Error restoring IPF raw track drive %d track %d side %d size %d" ,
                    205:                                                                        Drive, Track, Side , TrackSize );
                    206:                                                                return;
                    207:                                                        }
                    208:                                                        MemorySnapShot_Store(p, TrackSize);
                    209:                                                        IPF_RawStreamImage[ Drive ][ Track ][Side].TrackData = p;
                    210:                                                }
                    211:                                        }
                    212:                        }
1.1.1.5 ! root      213:                        Log_Printf ( LOG_DEBUG , "ipf load ok\n" );
1.1       root      214:                }
                    215:        }
                    216: }
                    217: 
                    218: 
                    219: 
                    220: 
                    221: /*-----------------------------------------------------------------------*/
                    222: /**
                    223:  * Does filename end with a .IPF or .RAW or .CTR extension ? If so, return true.
                    224:  * .RAW and .CTR support requires caps lib >= 5.1
                    225:  */
                    226: bool IPF_FileNameIsIPF(const char *pszFileName, bool bAllowGZ)
                    227: {
                    228:        return ( File_DoesFileExtensionMatch(pszFileName,".ipf" )
                    229:                || ( bAllowGZ && File_DoesFileExtensionMatch(pszFileName,".ipf.gz") )
                    230: #if CAPS_LIB_REL_REV >= 501
                    231:                || File_DoesFileExtensionMatch(pszFileName,".raw" )
                    232:                || ( bAllowGZ && File_DoesFileExtensionMatch(pszFileName,".raw.gz") )
                    233:                || File_DoesFileExtensionMatch(pszFileName,".ctr" )
                    234:                || ( bAllowGZ && File_DoesFileExtensionMatch(pszFileName,".ctr.gz") )
                    235: #endif
                    236:                );
                    237: }
                    238: 
                    239: 
1.1.1.4   root      240: /*
                    241:  * Return a pointer to the part "tt.s.raw" at the end of the filename
                    242:  * (there can be an extra suffix to ignore if the file is compressed).
                    243:  * If we found a string where "tt" and "s" are digits, then we return
                    244:  * a pointer to this string.
                    245:  * If not found, we return NULL
                    246:  */
                    247: #ifdef HAVE_CAPSIMAGE
                    248: static char *IPF_FilenameFindTrackSide (char *FileName)
                    249: {
                    250:        char    ext[] = ".raw";
                    251:        int     len;
                    252:        char    *p;
                    253: 
                    254:        len = strlen ( FileName );
                    255:        len -= strlen ( ext );
                    256: 
                    257:        while ( len >= 4 )                              /* need at least 4 chars for "tt.s" */
                    258:        {
                    259:                if ( strncasecmp ( ext , FileName + len , strlen ( ext ) ) == 0 )
                    260:                {
                    261:                        p = FileName + len - 4;
                    262:                        if ( isdigit( p[0] ) && isdigit( p[1] )
                    263:                          && ( p[2] == '.' ) && isdigit( p[3] ) )
                    264:                                return p;
                    265:                }
                    266: 
                    267:                len--;
                    268:        }
                    269: 
                    270:        return NULL;
                    271: }
                    272: #endif
                    273: 
                    274: 
1.1       root      275: /*-----------------------------------------------------------------------*/
                    276: /**
                    277:  * Load .IPF file into memory, set number of bytes loaded and return a pointer
                    278:  * to the buffer.
                    279:  */
                    280: Uint8 *IPF_ReadDisk(int Drive, const char *pszFileName, long *pImageSize, int *pImageType)
                    281: {
                    282: #ifndef HAVE_CAPSIMAGE
1.1.1.5 ! root      283:        Log_AlertDlg(LOG_ERROR, "Hatari built without IPF support -> can't handle floppy image");
1.1       root      284:        return NULL;
                    285: 
                    286: #else
                    287:        Uint8 *pIPFFile;
                    288: 
                    289:        *pImageSize = 0;
                    290: 
                    291:        /* Just load directly a buffer, and set ImageSize accordingly */
                    292:        pIPFFile = File_Read(pszFileName, pImageSize, NULL);
                    293:        if (!pIPFFile)
                    294:        {
                    295:                *pImageSize = 0;
                    296:                return NULL;
                    297:        }
                    298:        
                    299:        *pImageType = FLOPPY_IMAGE_TYPE_IPF;
                    300:        return pIPFFile;
                    301: #endif
                    302: }
                    303: 
                    304: 
                    305: /*-----------------------------------------------------------------------*/
                    306: /**
                    307:  * Save .IPF file from memory buffer. Returns true is all OK.
                    308:  */
                    309: bool IPF_WriteDisk(int Drive, const char *pszFileName, Uint8 *pBuffer, int ImageSize)
                    310: {
                    311:        /* saving is not supported for IPF files */
                    312:        return false;
                    313: }
                    314: 
                    315: 
                    316: 
                    317: 
                    318: /*
                    319:  * Init the FDC and the drives used to handle IPF images
                    320:  */
                    321: bool   IPF_Init ( void )
                    322: {
                    323: #ifndef HAVE_CAPSIMAGE
                    324:        return true;
                    325: 
                    326: #else
                    327:        int     i;
                    328:        struct CapsVersionInfo  caps_vi;
                    329: 
1.1.1.5 ! root      330:        Log_Printf ( LOG_DEBUG , "IPF : IPF_Init\n" );
1.1       root      331: 
                    332:        if ( CAPSInit() != imgeOk )
                    333:         {
1.1.1.5 ! root      334:                Log_Printf ( LOG_ERROR , "IPF : Could not initialize the capsimage library\n" );
1.1       root      335:                return false;
                    336:         }
                    337: 
                    338:        if ( CAPSGetVersionInfo ( &caps_vi , 0 ) != imgeOk )
                    339:         {
1.1.1.5 ! root      340:                Log_Printf ( LOG_ERROR , "IPF : CAPSVersionInfo failed\n" );
1.1       root      341:                return false;
                    342:         }
1.1.1.5 ! root      343:        Log_Printf ( LOG_INFO , "IPF : capsimage library version release=%d revision=%d\n" , (int)caps_vi.release , (int)caps_vi.revision );
1.1       root      344:        IPF_State.CapsLibRelease = caps_vi.release;
                    345:        IPF_State.CapsLibRevision = caps_vi.revision;
                    346: 
                    347:        /* Default values for each physical drive */
                    348:        memset ( IPF_State.Drive , 0 , sizeof ( IPF_State.Drive ) );
                    349:        for ( i=0 ; i < MAX_FLOPPYDRIVES ; i++ )
                    350:        {
                    351:                IPF_State.Drive[ i ].type = sizeof ( struct CapsDrive );
                    352:                IPF_State.Drive[ i ].rpm = CAPSDRIVE_35DD_RPM;
                    353:                IPF_State.Drive[ i ].maxtrack = CAPSDRIVE_35DD_HST;
                    354: 
                    355:                IPF_State.Rev_Track[ i ] = -1;
                    356:                IPF_State.Rev_Side[ i ] = -1;
                    357: 
                    358:                IPF_State.DriveEnabled[ i ] = true;
                    359:                IPF_State.DoubleSided[ i ] = true;
1.1.1.4   root      360: 
                    361:                IPF_State.CapsImageType[ i ] = -1;
1.1       root      362:        }
                    363: 
                    364:        /* Init FDC with 2 physical drives */
                    365:        memset ( &IPF_State.Fdc , 0 , sizeof ( IPF_State.Fdc ) );
                    366:        IPF_State.Fdc.type = sizeof( struct CapsFdc );
                    367:        IPF_State.Fdc.model = cfdcmWD1772;
                    368:        IPF_State.Fdc.drive = IPF_State.Drive;
                    369:        IPF_State.Fdc.drivecnt = MAX_FLOPPYDRIVES;
                    370: 
                    371:        if ( CAPSFdcInit ( &IPF_State.Fdc ) != imgeOk)
                    372:        {
1.1.1.5 ! root      373:                Log_Printf ( LOG_ERROR , "IPF : CAPSFdcInit failed\n" );
1.1       root      374:                return false;
                    375:        }
                    376: 
                    377:        /* 2 drives by default */
                    378:        IPF_State.Fdc.drivemax = MAX_FLOPPYDRIVES;
                    379:        /* Update drives' state in case we have some drives ON or OFF in config or parameters */
                    380:        IPF_Drive_Update_Enable_Side ();
                    381: 
                    382:        /* FDC clock */
                    383:        IPF_State.Fdc.clockfrq = 8000000;
                    384: 
                    385:        /* Set callback functions */
                    386:        IPF_State.Fdc.cbirq = IPF_CallBack_Irq;
                    387:        IPF_State.Fdc.cbdrq = IPF_CallBack_Drq;
                    388:        IPF_State.Fdc.cbtrk = IPF_CallBack_Trk;
                    389: 
                    390:        CAPSFdcReset ( &IPF_State.Fdc );
                    391: 
                    392:        return true;
                    393: #endif
                    394: }
                    395: 
                    396: 
                    397: 
                    398: 
                    399: /*
                    400:  * Exit
                    401:  */
                    402: void   IPF_Exit ( void )
                    403: {
                    404: #ifndef HAVE_CAPSIMAGE
                    405: #else
                    406:        CAPSExit();
                    407: #endif
                    408: }
                    409: 
                    410: 
                    411: 
                    412: 
                    413: /*
                    414:  * Init the ressources to handle the IPF image inserted into a drive (0=A: 1=B:)
                    415:  */
                    416: bool   IPF_Insert ( int Drive , Uint8 *pImageBuffer , long ImageSize )
                    417: {
                    418: #ifndef HAVE_CAPSIMAGE
                    419:        return false;
                    420: 
                    421: #else
                    422:        CapsLong        ImageId;
                    423:        CapsLong        ImageType;
1.1.1.5 ! root      424:        const char      *ImageTypeStr;
        !           425:        bool            Type_OK;
        !           426: 
1.1       root      427: 
                    428:        ImageId = CAPSAddImage();
                    429:        if ( ImageId < 0 )
                    430:        {
1.1.1.5 ! root      431:                Log_Printf ( LOG_ERROR , "IPF : error CAPSAddImage\n" );
1.1       root      432:                return false;
                    433:        }
                    434: 
                    435: #if CAPS_LIB_REL_REV >= 501
                    436:        ImageType = CAPSGetImageTypeMemory ( pImageBuffer , ImageSize );
                    437:        if ( ImageType == citError )
                    438:        {
1.1.1.5 ! root      439:                Log_Printf ( LOG_ERROR , "IPF : error CAPSGetImageTypeMemory\n" );
1.1.1.4   root      440:                CAPSRemImage ( ImageId ) ;
1.1       root      441:                return false;
                    442:        }
                    443:        else if ( ImageType == citUnknown )
                    444:        {
1.1.1.5 ! root      445:                Log_Printf ( LOG_ERROR , "IPF : unknown image type\n" );
1.1.1.4   root      446:                CAPSRemImage ( ImageId ) ;
1.1       root      447:                return false;
                    448:        }
                    449: 
1.1.1.5 ! root      450:        Type_OK = true;
1.1       root      451:        switch ( ImageType ) {
1.1.1.5 ! root      452:                case citIPF:            ImageTypeStr = "IPF"; break;
        !           453:                case citCTRaw:          ImageTypeStr = "CT RAW"; break;
        !           454:                case citKFStream:       ImageTypeStr = "KF STREAM" ; break;
        !           455:                case citDraft:          ImageTypeStr = "DRAFT" ; break;
        !           456:                default :               ImageTypeStr = "NOT SUPPORTED\n";
        !           457:                                        Type_OK = false;
1.1       root      458:        }
1.1.1.5 ! root      459:        Log_Printf ( LOG_INFO , "IPF : IPF_Insert drive=%d buf=%p size=%ld imageid=%d type=%s\n" , Drive , pImageBuffer , ImageSize , ImageId , ImageTypeStr );
        !           460: 
        !           461:        if ( !Type_OK )
        !           462:        {
        !           463:                CAPSRemImage ( ImageId ) ;
        !           464:                return false;
        !           465:        }
        !           466: 
1.1.1.4   root      467: 
                    468:        /* Special case for RAW stream image, we load all the tracks now */
                    469:        if ( ImageType == citKFStream )
                    470:        {
                    471:                if ( IPF_Insert_RawStreamImage ( Drive ) == false )
                    472:                {
1.1.1.5 ! root      473:                        Log_Printf ( LOG_ERROR , "IPF : can't load raw stream files\n" );
1.1.1.4   root      474:                        CAPSRemImage ( ImageId ) ;
                    475:                        return false;
                    476:                }
                    477:        }
                    478: 
                    479: #else
                    480:        ImageType = -1;
1.1       root      481: #endif
                    482: 
                    483:        if ( CAPSLockImageMemory ( ImageId , pImageBuffer , (CapsULong)ImageSize , DI_LOCK_MEMREF ) == imgeOk )
                    484:        {
                    485:                struct CapsImageInfo cii;
                    486:                int             i;
                    487: 
                    488:                /* Print some debug infos */
                    489:                if ( CAPSGetImageInfo ( &cii , ImageId ) == imgeOk )
                    490:                {
                    491:                        printf("Type: %d\n", (int)cii.type);
                    492:                        printf("Release: %d\n", (int)cii.release);
                    493:                        printf("Revision: %d\n", (int)cii.revision);
                    494:                        printf("Min Cylinder: %d\n", (int)cii.mincylinder);
                    495:                        printf("Max Cylinder: %d\n", (int)cii.maxcylinder);
                    496:                        printf("Min Head: %d\n", (int)cii.minhead);
                    497:                        printf("Max Head: %d\n", (int)cii.maxhead);
                    498:                        printf("Creation Date: %04d/%02d/%02d %02d:%02d:%02d.%03d\n", (int)cii.crdt.year, (int)cii.crdt.month, (int)cii.crdt.day, (int)cii.crdt.hour, (int)cii.crdt.min, (int)cii.crdt.sec, (int)cii.crdt.tick);
                    499:                        printf("Platforms:");
                    500:                        for (i = 0; i < CAPS_MAXPLATFORM; i++)
                    501:                                if (cii.platform[i] != ciipNA)
                    502:                                        printf ( " %s" , CAPSGetPlatformName(cii.platform[i]) );
                    503:                        printf("\n");
                    504: 
                    505:                        /* Some IPF disks are not correctly supported yet : display a warning */
                    506:                        if ( (int)cii.release == 3222 )                                 /* Sundog */
                    507:                                Log_AlertDlg ( LOG_INFO , "'Sundog' is not correctly supported yet, it requires write access." );
                    508:                        else if ( (int)cii.release == 3058 )                            /* Lethal Xcess */
                    509:                                Log_AlertDlg ( LOG_INFO , "'Lethal Xcess' is not correctly supported yet, protection will fail" );
                    510:                }
                    511:        }
                    512:        else
                    513:        {
                    514:                CAPSRemImage ( ImageId ) ;
                    515:                return false;
                    516:        }
                    517: 
                    518:        if ( CAPSLoadImage ( ImageId , DI_LOCK_DENALT | DI_LOCK_DENVAR | DI_LOCK_UPDATEFD ) != imgeOk )
                    519:        {
1.1.1.5 ! root      520:                Log_Printf ( LOG_ERROR , "IPF : error CAPSLoadImage\n" );
1.1       root      521:                CAPSUnlockImage ( ImageId );
                    522:                CAPSRemImage ( ImageId ) ;
                    523:                return false;
                    524:        }
                    525: 
                    526:        
                    527:        IPF_State.CapsImage[ Drive ] = ImageId;
1.1.1.4   root      528:        IPF_State.CapsImageType[ Drive ] = ImageType;
1.1       root      529: 
                    530:        IPF_State.Drive[ Drive ].diskattr |= CAPSDRIVE_DA_IN;                           /* Disk inserted, keep the value for "write protect" */
                    531: 
                    532:        CAPSFdcInvalidateTrack ( &IPF_State.Fdc , Drive );                              /* Invalidate previous buffered track data for drive, if any */
                    533: 
                    534:        IPF_State.Rev_Track[ Drive ] = -1;                                              /* Invalidate previous track/side to handle revolution's count */
                    535:        IPF_State.Rev_Side[ Drive ] = -1;
                    536: 
                    537:        return true;
                    538: #endif
                    539: }
                    540: 
                    541: 
1.1.1.4   root      542: /*
                    543:  * Load all the raw stream files for all tracks/sides of a dump.
                    544:  * We use the filename of the raw file in drive 'Drive' as a template
                    545:  * where we replace track and side will all the possible values.
                    546:  */
                    547: #ifdef HAVE_CAPSIMAGE
                    548: static bool    IPF_Insert_RawStreamImage ( int Drive )
                    549: {
                    550:        int     Track , Side;
                    551:        char    TrackFileName[ FILENAME_MAX ];
                    552:        char    *TrackSide_pointer;
                    553:        char    TrackSide_buf[ 4 + 1 ];                 /* "tt.s" + \0 */
                    554:        int     TrackCount;
                    555:        int     TrackCount_0 , TrackCount_1;
                    556:        Uint8   *p;
                    557:        long    Size;
                    558: 
                    559: 
                    560: return true;                                           /* This function is not used for now, always return true */
                    561:        /* Ensure the previous tracks are removed from memory */
                    562:        IPF_Eject_RawStreamImage ( Drive );
                    563: 
                    564: 
                    565:        /* Get the path+filename of the raw file that was inserted in 'Drive' */
                    566:        /* then parse it to find the part with track/side */
                    567:        strcpy ( TrackFileName , ConfigureParams.DiskImage.szDiskFileName[Drive] );
                    568: 
                    569:        TrackSide_pointer = IPF_FilenameFindTrackSide ( TrackFileName );
                    570:        if ( TrackSide_pointer == NULL )
                    571:        {
1.1.1.5 ! root      572:                Log_Printf ( LOG_ERROR , "IPF : error parsing track/side in raw filename\n" );
1.1.1.4   root      573:                return false;
                    574:        }
                    575: 
                    576:        /* We try to load all the tracks for all the sides */
                    577:        /* We ignore errors, as some tracks/side can really be missing from the image dump */
                    578:        TrackCount = 0;
                    579:        TrackCount_0 = 0;
                    580:        TrackCount_1 = 0;
                    581:        for ( Track=0 ; Track<IPF_MAX_TRACK_RAW_STREAM_IMAGE ; Track++ )
                    582:        {
                    583:                for ( Side=0 ; Side<IPF_MAX_SIDE_RAW_STREAM_IMAGE ; Side++ )
                    584:                {
                    585:                        sprintf ( TrackSide_buf , "%02d.%d" , Track , Side );
                    586:                        memcpy ( TrackSide_pointer , TrackSide_buf , 4 );
1.1.1.5 ! root      587:                        Log_Printf ( LOG_INFO , "IPF : insert raw stream drive=%d track=%d side=%d %s\n" , Drive , Track , Side , TrackFileName );
1.1.1.4   root      588: 
                    589:                        p = File_Read ( TrackFileName , &Size , NULL);
                    590:                        if ( p )
                    591:                        {
                    592:                                IPF_RawStreamImage[ Drive ][ Track ][Side].TrackData = p;
                    593:                                IPF_RawStreamImage[ Drive ][ Track ][Side].TrackSize = Size;
                    594:                                TrackCount++;
                    595:                                if ( Side==0 )          TrackCount_0++;
                    596:                                else                    TrackCount_1++;
                    597:                        }
                    598:                        else
                    599:                        {
1.1.1.5 ! root      600:                                Log_Printf ( LOG_INFO , "IPF : insert raw stream drive=%d track=%d side=%d %s -> not found\n" , Drive , Track , Side , TrackFileName );
1.1.1.4   root      601:                                /* File not loaded : either this track really doesn't exist or there was a system error */
                    602:                                IPF_RawStreamImage[ Drive ][ Track ][Side].TrackData = NULL;
                    603:                                IPF_RawStreamImage[ Drive ][ Track ][Side].TrackSize = 0;
                    604:                        }
                    605:                }
                    606:        }
                    607: 
                    608: 
                    609:        /* If we didn't load any track, there's a problem, we stop here */
                    610:        if ( TrackCount == 0 )
                    611:        {
1.1.1.5 ! root      612:                Log_Printf ( LOG_WARN , "IPF : error, no raw track file could be loaded for %s\n" , ConfigureParams.DiskImage.szDiskFileName[Drive] );
1.1.1.4   root      613:                /* Free all the tracks that were loaded so far */
                    614:                IPF_Eject_RawStreamImage ( Drive );
                    615:                return false;
                    616:        }
                    617: 
1.1.1.5 ! root      618:        Log_Printf ( LOG_INFO , "IPF : insert raw stream drive=%d, loaded %d tracks for side 0 and %d tracks for side 1\n", Drive, TrackCount_0, TrackCount_1 );
1.1.1.4   root      619: 
                    620:        return true;
                    621: }
                    622: #endif
                    623: 
1.1       root      624: 
                    625: 
                    626: /*
                    627:  * When ejecting a disk, free the ressources associated with an IPF image
                    628:  */
                    629: bool   IPF_Eject ( int Drive )
                    630: {
                    631: #ifndef HAVE_CAPSIMAGE
                    632:        return false;
                    633: 
                    634: #else
1.1.1.5 ! root      635:        Log_Printf ( LOG_DEBUG , "IPF : IPF_Eject drive=%d imageid=%d\n" , Drive , IPF_State.CapsImage[ Drive ] );
1.1       root      636: 
                    637:        CAPSFdcInvalidateTrack ( &IPF_State.Fdc , Drive );                              /* Invalidate previous buffered track data for drive, if any */
                    638: 
                    639:        if ( CAPSUnlockImage ( IPF_State.CapsImage[ Drive ] ) < 0 )
                    640:        {
1.1.1.5 ! root      641:                Log_Printf ( LOG_ERROR , "IPF : error CAPSUnlockImage\n" );
1.1       root      642:                return false;
                    643:        }
                    644: 
                    645:        if ( CAPSRemImage ( IPF_State.CapsImage[ Drive ] ) < 0 )
                    646:        {
1.1.1.5 ! root      647:                Log_Printf ( LOG_ERROR , "IPF : error CAPSRemImage\n" );
1.1       root      648:                return false;
                    649:        }
                    650: 
1.1.1.4   root      651:        /* Special case for RAW stream image, we must free all the tracks */
                    652:        if ( IPF_State.CapsImageType[ Drive ] == citKFStream )
                    653:                IPF_Eject_RawStreamImage ( Drive );
                    654: 
1.1       root      655:        IPF_State.CapsImage[ Drive ] = -1;
1.1.1.4   root      656:        IPF_State.CapsImageType[ Drive ] = -1;
1.1       root      657: 
                    658:        IPF_State.Drive[ Drive ].diskattr &= ~CAPSDRIVE_DA_IN;
                    659: 
                    660:        return true;
                    661: #endif
                    662: }
                    663: 
                    664: 
1.1.1.4   root      665: /*
                    666:  * When ejecting a RAW stream image we must free all the individual tracks
                    667:  */
                    668: static bool    IPF_Eject_RawStreamImage ( int Drive )
                    669: {
                    670: #ifndef HAVE_CAPSIMAGE
                    671:        return true;
                    672: 
                    673: #else
                    674:        int     Track , Side;
                    675: 
                    676: return true;                                           /* This function is not used for now, always return true */
                    677:        for ( Track=0 ; Track<IPF_MAX_TRACK_RAW_STREAM_IMAGE ; Track++ )
                    678:                for ( Side=0 ; Side<IPF_MAX_SIDE_RAW_STREAM_IMAGE ; Side++ )
                    679:                {
                    680:                        if ( IPF_RawStreamImage[ Drive ][ Track ][Side].TrackData != NULL )
                    681:                        {
1.1.1.5 ! root      682:                                Log_Printf ( LOG_DEBUG , "IPF : eject raw stream drive=%d track=%d side=%d\n" , Drive , Track , Side );
1.1.1.4   root      683:                                free ( IPF_RawStreamImage[ Drive ][ Track ][Side].TrackData );
                    684:                                IPF_RawStreamImage[ Drive ][ Track ][Side].TrackData = NULL;
                    685:                                IPF_RawStreamImage[ Drive ][ Track ][Side].TrackSize = 0;
                    686:                        }
                    687:                }
                    688: 
                    689:        return true;
                    690: #endif
                    691: }
                    692: 
                    693: 
1.1       root      694: 
                    695: 
                    696: /*
                    697:  * Reset FDC state when a reset signal was received
                    698:  */
                    699: void IPF_Reset ( void )
                    700: {
                    701: #ifdef HAVE_CAPSIMAGE
                    702:        CAPSFdcReset ( &IPF_State.Fdc );
                    703: 
                    704:        IPF_State.FdcClock = CyclesGlobalClockCounter;
                    705: #endif
                    706: }
                    707: 
                    708: 
                    709: 
                    710: 
                    711: /*
                    712:  * Callback function used when track is changed.
                    713:  * We need to update the track data by calling CAPSLockTrack
                    714:  */
                    715: #ifdef HAVE_CAPSIMAGE
                    716: static void    IPF_CallBack_Trk ( struct CapsFdc *pc , CapsULong State )
                    717: {
                    718:        int     Drive = State;                          /* State is the drive number in that case */
                    719:        struct CapsDrive *pd = pc->drive+Drive;         /* Current drive where the track change occurred */
                    720:        struct CapsTrackInfoT1 cti;
                    721: 
                    722:        cti.type=1;
                    723:        if ( CAPSLockTrack ( &cti , IPF_State.CapsImage[ Drive ] , pd->buftrack , pd->bufside ,
                    724:                        DI_LOCK_DENALT|DI_LOCK_DENVAR|DI_LOCK_UPDATEFD|DI_LOCK_TYPE ) != imgeOk )
                    725:                return;
                    726: 
                    727:        LOG_TRACE(TRACE_FDC, "fdc ipf callback trk drive=%d buftrack=%d bufside=%d VBL=%d HBL=%d\n" , Drive ,
                    728:                  (int)pd->buftrack , (int)pd->bufside , nVBLs , nHBL );
                    729: 
                    730:        pd->ttype       = cti.type;
                    731:        pd->trackbuf    = cti.trackbuf;
                    732:        pd->timebuf     = cti.timebuf;
                    733:        pd->tracklen    = cti.tracklen;
                    734:        pd->overlap     = cti.overlap;
                    735: }
                    736: #endif
                    737: 
                    738: 
                    739: 
                    740: 
                    741: /*
                    742:  * Callback function used when the FDC change the IRQ signal
                    743:  */
                    744: #ifdef HAVE_CAPSIMAGE
                    745: static void    IPF_CallBack_Irq ( struct CapsFdc *pc , CapsULong State )
                    746: {
                    747:        LOG_TRACE(TRACE_FDC, "fdc ipf callback irq state=0x%x VBL=%d HBL=%d\n" , (int)State , nVBLs , nHBL );
                    748: 
                    749:        if ( State )
                    750:                FDC_SetIRQ ( FDC_IRQ_SOURCE_OTHER );    /* IRQ bit was set */
                    751:        else
                    752:                FDC_ClearIRQ ();                        /* IRQ bit was reset */
                    753: }
                    754: #endif
                    755: 
                    756: 
                    757: 
                    758: 
                    759: /*
                    760:  * Callback function used when the FDC change the DRQ signal
                    761:  * -> copy the byte to/from the DMA's FIFO if it's a read or a write to the disk
                    762:  */
                    763: #ifdef HAVE_CAPSIMAGE
                    764: static void    IPF_CallBack_Drq ( struct CapsFdc *pc , CapsULong State )
                    765: {
                    766:        Uint8   Byte;
                    767: 
                    768:        if ( State == 0 )
                    769:                return;                                 /* DRQ bit was reset, do nothing */
                    770: 
                    771:        if ( FDC_DMA_GetModeControl_R_WR () != 0 )      /* DMA write mode */
                    772:        {
                    773:                Byte = FDC_DMA_FIFO_Pull ();            /* Get a byte from the DMA FIFO */
                    774:                CAPSFdcWrite ( &IPF_State.Fdc , 3 , Byte );     /* Write to FDC's reg 3 */
                    775: 
                    776:                LOG_TRACE(TRACE_FDC, "fdc ipf callback drq state=0x%x write byte 0x%02x VBL=%d HBL=%d\n" , (int)State , Byte , nVBLs , nHBL );
                    777:        }
                    778: 
                    779:        else                                            /* DMA read mode */
                    780:        {
                    781:                Byte = CAPSFdcRead ( &IPF_State.Fdc , 3 );      /* Read from FDC's reg 3 */
                    782:                FDC_DMA_FIFO_Push ( Byte );             /* Add byte to the DMA FIFO */
                    783: 
                    784:                LOG_TRACE(TRACE_FDC, "fdc ipf callback drq state=0x%x read byte 0x%02x VBL=%d HBL=%d\n" , (int)State , Byte , nVBLs , nHBL );
                    785:        }
                    786: }
                    787: #endif
                    788: 
                    789: 
                    790: 
                    791: /*
                    792:  * This function is used to enable/disable a drive when
                    793:  * using the UI or command line parameters
                    794:  *
                    795:  * NOTE : for now, IPF only supports changing drive 1, drive 0
                    796:  * is always ON.
                    797:  */
                    798: void   IPF_Drive_Set_Enable ( int Drive , bool value )
                    799: {
                    800: #ifndef HAVE_CAPSIMAGE
                    801:        return;
                    802: 
                    803: #else
                    804:        IPF_State.DriveEnabled[ Drive ] = value;                        /* Store the new state */
                    805: 
                    806:        IPF_Drive_Update_Enable_Side ();                                /* Update IPF's internal state */
                    807: #endif
                    808: }
                    809: 
                    810: 
                    811: /*
                    812:  * This function is used to configure a drive as single sided
                    813:  * or double sided when using the UI or command line parameters
                    814:  */
                    815: void   IPF_Drive_Set_DoubleSided ( int Drive , bool value )
                    816: {
                    817: #ifndef HAVE_CAPSIMAGE
                    818:        return;
                    819: 
                    820: #else
                    821:        IPF_State.DoubleSided[ Drive ] = value;                         /* Store the new state */
                    822: 
                    823:        IPF_Drive_Update_Enable_Side ();                                /* Update IPF's internal state */
                    824: #endif
                    825: }
                    826: 
                    827: 
                    828: /*
                    829:  * Update IPF's internal state depending on which drives are ON or OFF
                    830:  * and if the drive is single or double sided (for capslib >= 5.1)
                    831:  */
                    832: #ifdef HAVE_CAPSIMAGE
                    833: static void    IPF_Drive_Update_Enable_Side ( void )
                    834: {
1.1.1.2   root      835: #if CAPS_LIB_REL_REV >= 501
1.1       root      836:        int     i;
1.1.1.2   root      837: #endif
1.1       root      838: 
                    839:        if ( IPF_State.DriveEnabled[ 1 ] )
                    840:                IPF_State.Fdc.drivemax = MAX_FLOPPYDRIVES;              /* Should be 2 */
                    841:        else
                    842:                IPF_State.Fdc.drivemax = MAX_FLOPPYDRIVES - 1;          /* Should be 1 */
                    843: 
                    844: #if CAPS_LIB_REL_REV >= 501
                    845:        for ( i=0 ; i < MAX_FLOPPYDRIVES ; i++ )
                    846:        {
                    847:                if ( IPF_State.DoubleSided[ i ] )
                    848:                        IPF_State.Drive[ i ].diskattr &= ~CAPSDRIVE_DA_SS;      /* Double sided */
                    849:                else
                    850:                        IPF_State.Drive[ i ].diskattr |= CAPSDRIVE_DA_SS;       /* Single sided */
                    851:        }
                    852: #endif
                    853: }
                    854: #endif
                    855: 
                    856: 
                    857: /*
                    858:  * Set the drive and the side to be used for the next FDC commands
                    859:  * io_porta_old is the previous value, io_porta_new is the new value
                    860:  * to take into account.
                    861:  * We report a side change only when a drive is selected.
                    862:  */
                    863: void   IPF_SetDriveSide ( Uint8 io_porta_old , Uint8 io_porta_new )
                    864: {
                    865: #ifndef HAVE_CAPSIMAGE
                    866:        return;
                    867: 
                    868: #else
                    869:        int     Side;
                    870: 
                    871:        LOG_TRACE(TRACE_FDC, "fdc ipf change drive/side io_porta_old=0x%x io_porta_new=0x%x VBL=%d HBL=%d\n" , io_porta_old , io_porta_new , nVBLs , nHBL );
                    872: 
                    873:        Side = ( (~io_porta_new) & 0x01 );              /* Side 0 or 1 */
                    874: 
                    875:        IPF_State.Fdc.drivenew = -1;                    /* By default, don't select any drive */
                    876: 
                    877:        /* Check drive 1 first */
                    878:        if ( ( io_porta_new & 0x04 ) == 0 )
                    879:        {
                    880:                IPF_State.Drive[ 1 ].newside = Side;
                    881:                IPF_State.Fdc.drivenew = 1;             /* Select drive 1 */
                    882:        }
                    883: 
                    884:        /* If both drive 0 and drive 1 are enabled, we keep only drive 0 as newdrive */
                    885:        if ( ( io_porta_new & 0x02 ) == 0 )
                    886:        {
                    887:                IPF_State.Drive[ 0 ].newside = Side;
                    888:                IPF_State.Fdc.drivenew = 0;             /* Select drive 0 (and un-select drive 1 if set above) */
                    889:        }
                    890: 
                    891:        IPF_Emulate();                                  /* Update emulation's state up to this point, then set new drive/side */
                    892: #endif
                    893: }
                    894: 
                    895: 
                    896: 
                    897: 
                    898: /*
                    899:  * Write a byte into one of the FDC registers
                    900:  * 0=command   1=track   2=sector   3=data
                    901:  */
                    902: void   IPF_FDC_WriteReg ( Uint8 Reg , Uint8 Byte )
                    903: {
                    904: #ifndef HAVE_CAPSIMAGE
                    905:        return;                                         /* This should not be reached (an IPF image can't be inserted without capsimage) */
                    906: 
                    907: #else
1.1.1.4   root      908:        if ( Reg == 0 )                                 /* more detailed logs for command register */
                    909:                IPF_FDC_LogCommand ( Byte );
                    910:        else
                    911:                LOG_TRACE(TRACE_FDC, "fdc ipf write reg=%d data=0x%x VBL=%d HBL=%d\n" , Reg , Byte , nVBLs , nHBL );
1.1       root      912:        
                    913: #if CAPS_LIB_REL_REV >= 501
                    914:        /* In the case of CTR images, we must reset the revolution counter */
                    915:        /* when a command access data on disk and track/side changed since last access */
                    916:        if ( Reg == 0 )
                    917:        {
                    918:                int     Type;
                    919:                int     Drive;
                    920: 
                    921:                Type = FDC_GetCmdType ( Byte );
                    922:                if ( ( Type == 2 ) || ( Type == 3 ) )
                    923:                {
                    924:                        Drive = IPF_State.Fdc.driveact;
                    925:                        if ( ( Drive >= 0 )
                    926:                          && ( ( IPF_State.Drive[ Drive ].side != IPF_State.Rev_Side[ Drive ] ) || ( IPF_State.Drive[ Drive ].track != IPF_State.Rev_Track[ Drive ] ) ) )
                    927:                        {
                    928:                                IPF_State.Rev_Side[ Drive ] = IPF_State.Drive[ Drive ].side;
                    929:                                IPF_State.Rev_Track[ Drive ] = IPF_State.Drive[ Drive ].track;
                    930:                                CAPSSetRevolution ( IPF_State.CapsImage[ Drive ] , 0 );
                    931:                        }
                    932:                }
                    933:        }
                    934: #endif
                    935: 
                    936:        IPF_Emulate();                                  /* Update emulation's state up to this point */
                    937: 
                    938:        CAPSFdcWrite ( &IPF_State.Fdc , Reg , Byte );
                    939: #endif
                    940: }
                    941: 
                    942: 
                    943: 
                    944: 
                    945: /*
                    946:  * Read the content of one of the FDC registers
                    947:  * 0=status   1=track   2=sector   3=data
                    948:  */
                    949: Uint8  IPF_FDC_ReadReg ( Uint8 Reg )
                    950: {
                    951: #ifndef HAVE_CAPSIMAGE
                    952:        return 0;                                       /* This should not be reached (an IPF image can't be inserted without capsimage) */
                    953: #else
                    954:        Uint8   Byte;
                    955: 
                    956:        IPF_Emulate();                                  /* Update emulation's state up to this point */
                    957: 
                    958:        Byte = CAPSFdcRead ( &IPF_State.Fdc , Reg );
                    959:        LOG_TRACE(TRACE_FDC, "fdc ipf read reg=%d data=0x%x VBL=%d HBL=%d\n" , Reg , Byte , nVBLs , nHBL );
                    960: 
                    961:        return Byte;
                    962: #endif
                    963: }
                    964: 
                    965: 
                    966: 
                    967: 
                    968: /*
                    969:  * Return the content of some registers to display them in the statusbar
                    970:  * We should not call IPF_Emulate() or similar, reading should not change emulation's state
                    971:  */
                    972: void   IPF_FDC_StatusBar ( Uint8 *pCommand , Uint8 *pHead , Uint8 *pTrack , Uint8 *pSector , Uint8 *pSide )
                    973: {
                    974: #ifndef HAVE_CAPSIMAGE
                    975:        return;                                         /* This should not be reached (an IPF image can't be inserted without capsimage) */
                    976: #else
                    977:        int     Drive;
                    978: 
                    979:        Drive = IPF_State.Fdc.driveact;
                    980:        if ( Drive < 0 )                                /* If no drive enabled, use drive O for Head/Side */
                    981:                Drive = 0;
                    982: 
                    983:        /* We read directly in the structures, to be sure we don't change emulation's state */
                    984:        *pCommand       = IPF_State.Fdc.r_command;
                    985:        *pHead          = IPF_State.Drive[ Drive ].track;
                    986:        *pTrack         = IPF_State.Fdc.r_track;
                    987:        *pSector        = IPF_State.Fdc.r_sector;
                    988:        *pSide          = IPF_State.Drive[ Drive ].side;
                    989: #endif
                    990: }
                    991: 
                    992: 
                    993: 
1.1.1.4   root      994: #ifdef HAVE_CAPSIMAGE
                    995: static void    IPF_FDC_LogCommand ( Uint8 Command )
                    996: {
                    997:        Uint8   Head , Track , Sector , Side , DataReg;
                    998:        int     Drive;
                    999:        int     FrameCycles, HblCounterVideo, LineCycles;
                   1000:        char    buf[ 200 ];
                   1001: 
                   1002: 
                   1003:        Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
                   1004: 
                   1005:        Drive = IPF_State.Fdc.driveact;
                   1006:        if ( Drive < 0 )                                /* If no drive enabled, use drive O for Head/Side */
                   1007:                Drive = 0;
                   1008: 
                   1009:        /* We read directly in the structures, to be sure we don't change emulation's state */
                   1010:        Head    = IPF_State.Drive[ Drive ].track;
                   1011:        Track   = IPF_State.Fdc.r_track;
                   1012:        Sector  = IPF_State.Fdc.r_sector;
                   1013:        DataReg = IPF_State.Fdc.r_data;
                   1014:        Side    = IPF_State.Drive[ Drive ].side;
                   1015: 
                   1016:        if      ( ( Command & 0xf0 ) == 0x00 )                                          /* Restore */
                   1017:                sprintf ( buf , "type I restore spinup=%s verify=%s steprate=%d drive=%d tr=0x%x head_track=0x%x" ,
                   1018:                        ( Command & FDC_COMMAND_BIT_SPIN_UP ) ? "off" : "on" ,
                   1019:                        ( Command & FDC_COMMAND_BIT_VERIFY ) ? "on" : "off" ,
                   1020:                        FDC_StepRate_ms[ Command & 0x03 ] , Drive , Track , Head );
                   1021: 
                   1022:        else if ( ( Command & 0xf0 ) == 0x10 )                                          /* Seek */
                   1023:                sprintf ( buf , "type I seek dest_track=0x%x spinup=%s verify=%s steprate=%d drive=%d tr=0x%x head_track=0x%x" ,
                   1024:                        DataReg , ( Command & FDC_COMMAND_BIT_SPIN_UP ) ? "off" : "on" ,
                   1025:                        ( Command & FDC_COMMAND_BIT_VERIFY ) ? "on" : "off" ,
                   1026:                        FDC_StepRate_ms[ Command & 0x03 ] , Drive , Track , Head );
                   1027: 
                   1028:        else if ( ( Command & 0xe0 ) == 0x20 )                                          /* Step */
                   1029:                sprintf ( buf , "type I step %d spinup=%s verify=%s steprate_ms=%d drive=%d tr=0x%x head_track=0x%x",
                   1030:                        ( IPF_State.Fdc.lineout & CAPSFDC_LO_DIRC ) ? 1 : -1 ,
                   1031:                        ( Command & FDC_COMMAND_BIT_SPIN_UP ) ? "off" : "on" ,
                   1032:                        ( Command & FDC_COMMAND_BIT_VERIFY ) ? "on" : "off" ,
                   1033:                        FDC_StepRate_ms[ Command & 0x03 ] , Drive , Track , Head );
                   1034: 
                   1035:        else if ( ( Command & 0xe0 ) == 0x40 )                                          /* Step In */
                   1036:                sprintf ( buf , "type I step in spinup=%s verify=%s steprate=%d drive=%d tr=0x%x head_track=0x%x" ,
                   1037:                        ( Command & FDC_COMMAND_BIT_SPIN_UP ) ? "off" : "on" ,
                   1038:                        ( Command & FDC_COMMAND_BIT_VERIFY ) ? "on" : "off" ,
                   1039:                        FDC_StepRate_ms[ Command & 0x03 ] , Drive , Track , Head );
                   1040: 
                   1041:        else if ( ( Command & 0xe0 ) == 0x60 )                                          /* Step Out */
                   1042:                sprintf ( buf , "type I step out spinup=%s verify=%s steprate=%d drive=%d tr=0x%x head_track=0x%x" ,
                   1043:                        ( Command & FDC_COMMAND_BIT_SPIN_UP ) ? "off" : "on" ,
                   1044:                        ( Command & FDC_COMMAND_BIT_VERIFY ) ? "on" : "off" ,
                   1045:                        FDC_StepRate_ms[ Command & 0x03 ] , Drive , Track , Head );
                   1046: 
                   1047:        else if ( ( Command & 0xe0 ) == 0x80 )                                          /* Read Sector */
                   1048:                sprintf ( buf , "type II read sector sector=0x%x multi=%s spinup=%s settle=%s tr=0x%x head_track=0x%x"
                   1049:                              " side=%d drive=%d dmasector=%d addr=0x%x",
                   1050:                        Sector, ( Command & FDC_COMMAND_BIT_MULTIPLE_SECTOR ) ? "on" : "off" ,
                   1051:                        ( Command & FDC_COMMAND_BIT_SPIN_UP ) ? "off" : "on" ,
                   1052:                        ( Command & FDC_COMMAND_BIT_HEAD_LOAD ) ? "on" : "off" ,
                   1053:                        Track , Head , Side , Drive , FDC_DMA_GetSectorCount() , FDC_GetDMAAddress() );
                   1054: 
                   1055:        else if ( ( Command & 0xe0 ) == 0xa0 )                                          /* Write Sector */
                   1056:                sprintf ( buf , "type II write sector sector=0x%x multi=%s spinup=%s settle=%s tr=0x%x head_track=0x%x"
                   1057:                              " side=%d drive=%d dmasector=%d addr=0x%x",
                   1058:                        Sector, ( Command & FDC_COMMAND_BIT_MULTIPLE_SECTOR ) ? "on" : "off" ,
                   1059:                        ( Command & FDC_COMMAND_BIT_SPIN_UP ) ? "off" : "on" ,
                   1060:                        ( Command & FDC_COMMAND_BIT_HEAD_LOAD ) ? "on" : "off" ,
                   1061:                        Track , Head , Side , Drive , FDC_DMA_GetSectorCount() , FDC_GetDMAAddress() );
                   1062: 
                   1063:        else if ( ( Command & 0xf0 ) == 0xc0 )                                          /* Read Address */
                   1064:                sprintf ( buf , "type III read address spinup=%s settle=%s tr=0x%x head_track=0x%x side=%d drive=%d addr=0x%x" ,
                   1065:                        ( Command & FDC_COMMAND_BIT_SPIN_UP ) ? "off" : "on" ,
                   1066:                        ( Command & FDC_COMMAND_BIT_HEAD_LOAD ) ? "on" : "off" ,
                   1067:                        Track , Head , Side , Drive , FDC_GetDMAAddress() );
                   1068: 
                   1069:        else if ( ( Command & 0xf0 ) == 0xe0 )                                          /* Read Track */
                   1070:                sprintf ( buf , "type III read track spinup=%s settle=%s tr=0x%x head_track=0x%x side=%d drive=%d addr=0x%x" ,
                   1071:                        ( Command & FDC_COMMAND_BIT_SPIN_UP ) ? "off" : "on" ,
                   1072:                        ( Command & FDC_COMMAND_BIT_HEAD_LOAD ) ? "on" : "off" ,
                   1073:                        Track , Head , Side , Drive , FDC_GetDMAAddress() );
                   1074: 
                   1075:        else if ( ( Command & 0xf0 ) == 0xf0 )                                          /* Write Track */
                   1076:                sprintf ( buf , "type III write track spinup=%s settle=%s tr=0x%x head_track=0x%x side=%d drive=%d addr=0x%x" ,
                   1077:                        ( Command & FDC_COMMAND_BIT_SPIN_UP ) ? "off" : "on" ,
                   1078:                        ( Command & FDC_COMMAND_BIT_HEAD_LOAD ) ? "on" : "off" ,
                   1079:                        Track , Head , Side , Drive , FDC_GetDMAAddress() );
                   1080: 
                   1081:        else                                                                            /* Force Int */
                   1082:                sprintf ( buf , "type IV force int 0x%x irq=%d index=%d" ,
                   1083:                        Command , ( Command & 0x8 ) >> 3 , ( Command & 0x4 ) >> 2 );
                   1084: 
                   1085: 
                   1086:        LOG_TRACE(TRACE_FDC, "fdc ipf %s VBL=%d video_cyc=%d %d@%d pc=%x\n" ,
                   1087:                        buf , nVBLs , FrameCycles, LineCycles, HblCounterVideo , M68000_GetPC() );
                   1088: }
                   1089: #endif
                   1090: 
                   1091: 
1.1       root     1092: 
                   1093: /*
                   1094:  * Run the FDC emulation during NbCycles cycles (relative to the 8MHz FDC's clock)
                   1095:  */
                   1096: void   IPF_Emulate ( void )
                   1097: {
                   1098: #ifndef HAVE_CAPSIMAGE
                   1099:        return;
                   1100: 
                   1101: #else
                   1102:        int     NbCycles;
                   1103:        int     Drive;
                   1104: 
                   1105:        NbCycles = CyclesGlobalClockCounter - IPF_State.FdcClock;       /* Number of cycles since last emulation */
                   1106:        if ( NbCycles < 0 )
                   1107:                NbCycles = 0;                                           /* We should call CAPSFdcEmulate even when NbCycles=0 */
                   1108: 
                   1109: //     LOG_TRACE(TRACE_FDC, "fdc ipf emulate cycles=%d VBL=%d HBL=%d clock=%lld\n" , NbCycles , nVBLs , nHBL , CyclesGlobalClockCounter );
                   1110: 
                   1111:        /* Update Write Protect status for each drive */
                   1112:        for ( Drive=0 ; Drive < MAX_FLOPPYDRIVES ; Drive++ )
                   1113:                if ( Floppy_IsWriteProtected ( Drive ) )
                   1114:                        IPF_State.Drive[ Drive ].diskattr |= CAPSDRIVE_DA_WP;           /* Disk write protected */
                   1115:                else
                   1116:                        IPF_State.Drive[ Drive ].diskattr &= ~CAPSDRIVE_DA_WP;          /* Disk is not write protected */
                   1117: 
                   1118: 
                   1119:        CAPSFdcEmulate ( &IPF_State.Fdc , NbCycles );                   /* Process at max NbCycles */
                   1120:        IPF_State.FdcClock += IPF_State.Fdc.clockact;                   /* clockact can be < NbCycle in some cases */
                   1121: 
                   1122:        /* Update UI's LEDs depending on Status Register */
                   1123:        FDC_Drive_Set_BusyLed ( (IPF_State.Fdc.r_st0 & ~IPF_State.Fdc.r_stm) | (IPF_State.Fdc.r_st1 & IPF_State.Fdc.r_stm) );
                   1124: #endif
                   1125: }
                   1126: 
                   1127: 
                   1128: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.