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

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: 
        !            12:   RAW files made with KryoFlux board or CT RAW dumped with an Amiga are also handled
        !            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"
        !            26: #include "cycles.h"
        !            27: 
        !            28: #ifdef HAVE_CAPSIMAGE
        !            29: #if CAPSIMAGE_VERSION == 5
        !            30: #include <caps5/CapsLibAll.h>
        !            31: #else
        !            32: #include <caps/fdc.h>
        !            33: #define CAPS_LIB_RELEASE       4
        !            34: #define CAPS_LIB_REVISION      2
        !            35: #endif
        !            36: /* Macro to check release and revision */
        !            37: #define        CAPS_LIB_REL_REV        ( CAPS_LIB_RELEASE * 100 + CAPS_LIB_REVISION )
        !            38: #endif
        !            39: 
        !            40: 
        !            41: typedef struct
        !            42: {
        !            43: #ifdef HAVE_CAPSIMAGE
        !            44:        Uint32                  CapsLibRelease;
        !            45:        Uint32                  CapsLibRevision;
        !            46: 
        !            47:        struct CapsFdc          Fdc;                            /* Fdc state */
        !            48:        struct CapsDrive        Drive[ MAX_FLOPPYDRIVES ];      /* Physical drives */
        !            49:        CapsLong                CapsImage[ MAX_FLOPPYDRIVES ];  /* For the IPF disk images */
        !            50: 
        !            51:        int                     Rev_Track[ MAX_FLOPPYDRIVES ];  /* Needed to handle CAPSSetRevolution for type II/III commands */
        !            52:        int                     Rev_Side[ MAX_FLOPPYDRIVES ];
        !            53: 
        !            54:        bool                    DriveEnabled[ MAX_FLOPPYDRIVES ];/* Is drive ON or OFF */
        !            55:        bool                    DoubleSided[ MAX_FLOPPYDRIVES ];/* Is drive double sided or not */
        !            56: 
        !            57:        Sint64                  FdcClock;                       /* Current value of CyclesGlobalClockCounter */
        !            58: #endif
        !            59: } IPF_STRUCT;
        !            60: 
        !            61: 
        !            62: static IPF_STRUCT      IPF_State;                      /* All variables related to the IPF support */
        !            63: 
        !            64: 
        !            65: #ifdef HAVE_CAPSIMAGE
        !            66: static void    IPF_CallBack_Trk ( struct CapsFdc *pc , CapsULong State );
        !            67: static void    IPF_CallBack_Irq ( struct CapsFdc *pc , CapsULong State );
        !            68: static void    IPF_CallBack_Drq ( struct CapsFdc *pc , CapsULong State );
        !            69: static void    IPF_Drive_Update_Enable_Side ( void );
        !            70: #endif
        !            71: 
        !            72: 
        !            73: 
        !            74: 
        !            75: /*-----------------------------------------------------------------------*/
        !            76: /**
        !            77:  * Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type)
        !            78:  * We must take care of whether Hatari was compiled with IPF support of not
        !            79:  * when saving/restoring snapshots to avoid incompatibilies.
        !            80:  */
        !            81: void IPF_MemorySnapShot_Capture(bool bSave)
        !            82: {
        !            83:        int     StructSize;
        !            84:        int     Drive;
        !            85: 
        !            86:        if ( bSave )                                    /* Saving snapshot */
        !            87:        {
        !            88:                StructSize = sizeof ( IPF_State );      /* 0 if HAVE_CAPSIMAGE is not defined */
        !            89:                MemorySnapShot_Store(&StructSize, sizeof(StructSize));
        !            90: fprintf ( stderr , "ipf save %d\n" , StructSize );
        !            91:                if ( StructSize > 0 )
        !            92:                        MemorySnapShot_Store(&IPF_State, sizeof(IPF_State));
        !            93:        }
        !            94: 
        !            95:        else                                            /* Restoring snapshot */
        !            96:        {
        !            97:                MemorySnapShot_Store(&StructSize, sizeof(StructSize));
        !            98: fprintf ( stderr , "ipf load %d\n" , StructSize );
        !            99:                if ( ( StructSize == 0 ) && ( sizeof ( IPF_State ) > 0 ) )
        !           100:                {
        !           101:                        Log_AlertDlg(LOG_ERROR, "This memory snapshot doesn't include IPF data but this version of Hatari was built with IPF support");
        !           102:                        return;                         /* Continue restoring the rest of the memory snapshot */
        !           103:                }
        !           104:                else if ( ( StructSize > 0 ) && ( sizeof ( IPF_State ) == 0 ) )
        !           105:                {
        !           106:                        Log_AlertDlg(LOG_ERROR, "This memory snapshot includes IPF data but this version of Hatari was not built with IPF support");
        !           107:                        MemorySnapShot_Skip( StructSize );      /* Ignore the IPF data */
        !           108:                        return;                         /* Continue restoring the rest of the memory snapshot */
        !           109:                }
        !           110:                else if ( ( StructSize > 0 ) && ( StructSize != sizeof ( IPF_State ) ) )
        !           111:                {
        !           112:                        Log_AlertDlg(LOG_ERROR, "This memory snapshot includes IPF data different from the ones handled in this version of Hatari");
        !           113:                        MemorySnapShot_Skip( StructSize );      /* Ignore the IPF data */
        !           114:                        return;                         /* Continue restoring the rest of the memory snapshot */
        !           115:                }
        !           116: 
        !           117:                if ( StructSize > 0 )
        !           118:                {
        !           119:                        MemorySnapShot_Store(&IPF_State, sizeof(IPF_State));
        !           120: 
        !           121: #ifdef HAVE_CAPSIMAGE
        !           122:                        /* For IPF structures, we need to update some pointers in Fdc/Drive/CapsImage */
        !           123:                        /* drive : PUBYTE trackbuf, PUDWORD timebuf */
        !           124:                        /* fdc : PCAPSDRIVE driveprc, PCAPSDRIVE drive, CAPSFDCHOOK callback functions */
        !           125:                        CAPSFdcInvalidateTrack ( &IPF_State.Fdc , 0 );  /* Invalidate buffered track data for drive 0 */
        !           126:                        CAPSFdcInvalidateTrack ( &IPF_State.Fdc , 1 );  /* Invalidate buffered track data for drive 1 */
        !           127: 
        !           128:                        IPF_State.Fdc.drive = IPF_State.Drive;          /* Connect drives array to the FDC */
        !           129:                        if ( IPF_State.Fdc.driveprc != NULL )           /* Recompute active drive's pointer */
        !           130:                                IPF_State.Fdc.driveprc = IPF_State.Fdc.drive + IPF_State.Fdc.driveact;
        !           131: 
        !           132:                        /* Set callback functions */
        !           133:                        IPF_State.Fdc.cbirq = IPF_CallBack_Irq;
        !           134:                        IPF_State.Fdc.cbdrq = IPF_CallBack_Drq;
        !           135:                        IPF_State.Fdc.cbtrk = IPF_CallBack_Trk;
        !           136: #endif
        !           137: 
        !           138:                        /* Call IPF_Insert to recompute IPF_State.CapsImage[ Drive ] */
        !           139:                        for ( Drive=0 ; Drive < MAX_FLOPPYDRIVES ; Drive++ )
        !           140:                                if ( EmulationDrives[Drive].ImageType == FLOPPY_IMAGE_TYPE_IPF )
        !           141:                                        if ( IPF_Insert ( Drive , EmulationDrives[Drive].pBuffer , EmulationDrives[Drive].nImageBytes ) == false )
        !           142:                                        {
        !           143:                                                Log_AlertDlg(LOG_ERROR, "Error restoring IPF image %s in drive %d" ,
        !           144:                                                        EmulationDrives[Drive].sFileName , Drive );
        !           145:                                                return;
        !           146:                                        }
        !           147: 
        !           148:                fprintf ( stderr , "ipf load ok\n" );
        !           149:                }
        !           150:        }
        !           151: }
        !           152: 
        !           153: 
        !           154: 
        !           155: 
        !           156: /*-----------------------------------------------------------------------*/
        !           157: /**
        !           158:  * Does filename end with a .IPF or .RAW or .CTR extension ? If so, return true.
        !           159:  * .RAW and .CTR support requires caps lib >= 5.1
        !           160:  */
        !           161: bool IPF_FileNameIsIPF(const char *pszFileName, bool bAllowGZ)
        !           162: {
        !           163:        return ( File_DoesFileExtensionMatch(pszFileName,".ipf" )
        !           164:                || ( bAllowGZ && File_DoesFileExtensionMatch(pszFileName,".ipf.gz") )
        !           165: #if CAPS_LIB_REL_REV >= 501
        !           166:                || File_DoesFileExtensionMatch(pszFileName,".raw" )
        !           167:                || ( bAllowGZ && File_DoesFileExtensionMatch(pszFileName,".raw.gz") )
        !           168:                || File_DoesFileExtensionMatch(pszFileName,".ctr" )
        !           169:                || ( bAllowGZ && File_DoesFileExtensionMatch(pszFileName,".ctr.gz") )
        !           170: #endif
        !           171:                );
        !           172: }
        !           173: 
        !           174: 
        !           175: /*-----------------------------------------------------------------------*/
        !           176: /**
        !           177:  * Load .IPF file into memory, set number of bytes loaded and return a pointer
        !           178:  * to the buffer.
        !           179:  */
        !           180: Uint8 *IPF_ReadDisk(int Drive, const char *pszFileName, long *pImageSize, int *pImageType)
        !           181: {
        !           182: #ifndef HAVE_CAPSIMAGE
        !           183:        Log_AlertDlg(LOG_ERROR, "This version of Hatari was not built with IPF support, this disk image can't be handled.");
        !           184:        return NULL;
        !           185: 
        !           186: #else
        !           187:        Uint8 *pIPFFile;
        !           188: 
        !           189:        *pImageSize = 0;
        !           190: 
        !           191:        /* Just load directly a buffer, and set ImageSize accordingly */
        !           192:        pIPFFile = File_Read(pszFileName, pImageSize, NULL);
        !           193:        if (!pIPFFile)
        !           194:        {
        !           195:                *pImageSize = 0;
        !           196:                return NULL;
        !           197:        }
        !           198:        
        !           199:        *pImageType = FLOPPY_IMAGE_TYPE_IPF;
        !           200:        return pIPFFile;
        !           201: #endif
        !           202: }
        !           203: 
        !           204: 
        !           205: /*-----------------------------------------------------------------------*/
        !           206: /**
        !           207:  * Save .IPF file from memory buffer. Returns true is all OK.
        !           208:  */
        !           209: bool IPF_WriteDisk(int Drive, const char *pszFileName, Uint8 *pBuffer, int ImageSize)
        !           210: {
        !           211:        /* saving is not supported for IPF files */
        !           212:        return false;
        !           213: }
        !           214: 
        !           215: 
        !           216: 
        !           217: 
        !           218: /*
        !           219:  * Init the FDC and the drives used to handle IPF images
        !           220:  */
        !           221: bool   IPF_Init ( void )
        !           222: {
        !           223: #ifndef HAVE_CAPSIMAGE
        !           224:        return true;
        !           225: 
        !           226: #else
        !           227:        int     i;
        !           228:        struct CapsVersionInfo  caps_vi;
        !           229: 
        !           230:        fprintf ( stderr , "IPF : IPF_Init\n" );
        !           231: 
        !           232:        if ( CAPSInit() != imgeOk )
        !           233:         {
        !           234:                fprintf ( stderr , "IPF : Could not initialize the capsimage library\n" );
        !           235:                return false;
        !           236:         }
        !           237: 
        !           238:        if ( CAPSGetVersionInfo ( &caps_vi , 0 ) != imgeOk )
        !           239:         {
        !           240:                fprintf ( stderr , "IPF : CAPSVersionInfo failed\n" );
        !           241:                return false;
        !           242:         }
        !           243:        fprintf ( stderr , "IPF : capsimage library version release=%d revision=%d\n" , (int)caps_vi.release , (int)caps_vi.revision );
        !           244:        IPF_State.CapsLibRelease = caps_vi.release;
        !           245:        IPF_State.CapsLibRevision = caps_vi.revision;
        !           246: 
        !           247:        /* Default values for each physical drive */
        !           248:        memset ( IPF_State.Drive , 0 , sizeof ( IPF_State.Drive ) );
        !           249:        for ( i=0 ; i < MAX_FLOPPYDRIVES ; i++ )
        !           250:        {
        !           251:                IPF_State.Drive[ i ].type = sizeof ( struct CapsDrive );
        !           252:                IPF_State.Drive[ i ].rpm = CAPSDRIVE_35DD_RPM;
        !           253:                IPF_State.Drive[ i ].maxtrack = CAPSDRIVE_35DD_HST;
        !           254: 
        !           255:                IPF_State.Rev_Track[ i ] = -1;
        !           256:                IPF_State.Rev_Side[ i ] = -1;
        !           257: 
        !           258:                IPF_State.DriveEnabled[ i ] = true;
        !           259:                IPF_State.DoubleSided[ i ] = true;
        !           260:        }
        !           261: 
        !           262:        /* Init FDC with 2 physical drives */
        !           263:        memset ( &IPF_State.Fdc , 0 , sizeof ( IPF_State.Fdc ) );
        !           264:        IPF_State.Fdc.type = sizeof( struct CapsFdc );
        !           265:        IPF_State.Fdc.model = cfdcmWD1772;
        !           266:        IPF_State.Fdc.drive = IPF_State.Drive;
        !           267:        IPF_State.Fdc.drivecnt = MAX_FLOPPYDRIVES;
        !           268: 
        !           269:        if ( CAPSFdcInit ( &IPF_State.Fdc ) != imgeOk)
        !           270:        {
        !           271:                fprintf ( stderr , "IPF : CAPSFdcInit failed\n" );
        !           272:                return false;
        !           273:        }
        !           274: 
        !           275:        /* 2 drives by default */
        !           276:        IPF_State.Fdc.drivemax = MAX_FLOPPYDRIVES;
        !           277:        /* Update drives' state in case we have some drives ON or OFF in config or parameters */
        !           278:        IPF_Drive_Update_Enable_Side ();
        !           279: 
        !           280:        /* FDC clock */
        !           281:        IPF_State.Fdc.clockfrq = 8000000;
        !           282: 
        !           283:        /* Set callback functions */
        !           284:        IPF_State.Fdc.cbirq = IPF_CallBack_Irq;
        !           285:        IPF_State.Fdc.cbdrq = IPF_CallBack_Drq;
        !           286:        IPF_State.Fdc.cbtrk = IPF_CallBack_Trk;
        !           287: 
        !           288:        CAPSFdcReset ( &IPF_State.Fdc );
        !           289: 
        !           290:        return true;
        !           291: #endif
        !           292: }
        !           293: 
        !           294: 
        !           295: 
        !           296: 
        !           297: /*
        !           298:  * Exit
        !           299:  */
        !           300: void   IPF_Exit ( void )
        !           301: {
        !           302: #ifndef HAVE_CAPSIMAGE
        !           303: #else
        !           304:        CAPSExit();
        !           305: #endif
        !           306: }
        !           307: 
        !           308: 
        !           309: 
        !           310: 
        !           311: /*
        !           312:  * Init the ressources to handle the IPF image inserted into a drive (0=A: 1=B:)
        !           313:  */
        !           314: bool   IPF_Insert ( int Drive , Uint8 *pImageBuffer , long ImageSize )
        !           315: {
        !           316: #ifndef HAVE_CAPSIMAGE
        !           317:        return false;
        !           318: 
        !           319: #else
        !           320:        CapsLong        ImageId;
        !           321:        CapsLong        ImageType;
        !           322: 
        !           323:        ImageId = CAPSAddImage();
        !           324:        if ( ImageId < 0 )
        !           325:        {
        !           326:                fprintf ( stderr , "IPF : error CAPSAddImage\n" );
        !           327:                return false;
        !           328:        }
        !           329: 
        !           330: #if CAPS_LIB_REL_REV >= 501
        !           331:        ImageType = CAPSGetImageTypeMemory ( pImageBuffer , ImageSize );
        !           332:        if ( ImageType == citError )
        !           333:        {
        !           334:                fprintf ( stderr , "IPF : error CAPSGetImageTypeMemory\n" );
        !           335:                return false;
        !           336:        }
        !           337:        else if ( ImageType == citUnknown )
        !           338:        {
        !           339:                fprintf ( stderr , "IPF : unknown image type\n" );
        !           340:                return false;
        !           341:        }
        !           342: 
        !           343:        fprintf ( stderr , "IPF : IPF_Insert drive=%d buf=%p size=%ld imageid=%d type=" , Drive , pImageBuffer , ImageSize , ImageId );
        !           344:        switch ( ImageType ) {
        !           345:                case citIPF:            fprintf ( stderr , "IPF\n" ); break;
        !           346:                case citCTRaw:          fprintf ( stderr , "CT RAW\n" ); break;
        !           347:                case citKFStream:       fprintf ( stderr , "KF STREAM\n" ) ; break;
        !           348:                case citDraft:          fprintf ( stderr , "DRAFT\n" ) ; break;
        !           349:                default :               fprintf ( stderr , "NOT SUPPORTED\n" );
        !           350:                                        return false;
        !           351:        }
        !           352: #endif
        !           353: 
        !           354:        if ( CAPSLockImageMemory ( ImageId , pImageBuffer , (CapsULong)ImageSize , DI_LOCK_MEMREF ) == imgeOk )
        !           355:        {
        !           356:                struct CapsImageInfo cii;
        !           357:                int             i;
        !           358: 
        !           359:                /* Print some debug infos */
        !           360:                if ( CAPSGetImageInfo ( &cii , ImageId ) == imgeOk )
        !           361:                {
        !           362:                        printf("Type: %d\n", (int)cii.type);
        !           363:                        printf("Release: %d\n", (int)cii.release);
        !           364:                        printf("Revision: %d\n", (int)cii.revision);
        !           365:                        printf("Min Cylinder: %d\n", (int)cii.mincylinder);
        !           366:                        printf("Max Cylinder: %d\n", (int)cii.maxcylinder);
        !           367:                        printf("Min Head: %d\n", (int)cii.minhead);
        !           368:                        printf("Max Head: %d\n", (int)cii.maxhead);
        !           369:                        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);
        !           370:                        printf("Platforms:");
        !           371:                        for (i = 0; i < CAPS_MAXPLATFORM; i++)
        !           372:                                if (cii.platform[i] != ciipNA)
        !           373:                                        printf ( " %s" , CAPSGetPlatformName(cii.platform[i]) );
        !           374:                        printf("\n");
        !           375: 
        !           376:                        /* Some IPF disks are not correctly supported yet : display a warning */
        !           377:                        if ( (int)cii.release == 3222 )                                 /* Sundog */
        !           378:                                Log_AlertDlg ( LOG_INFO , "'Sundog' is not correctly supported yet, it requires write access." );
        !           379:                        else if ( (int)cii.release == 3058 )                            /* Lethal Xcess */
        !           380:                                Log_AlertDlg ( LOG_INFO , "'Lethal Xcess' is not correctly supported yet, protection will fail" );
        !           381:                }
        !           382:        }
        !           383:        else
        !           384:        {
        !           385:                CAPSRemImage ( ImageId ) ;
        !           386:                return false;
        !           387:        }
        !           388: 
        !           389:        if ( CAPSLoadImage ( ImageId , DI_LOCK_DENALT | DI_LOCK_DENVAR | DI_LOCK_UPDATEFD ) != imgeOk )
        !           390:        {
        !           391:                fprintf ( stderr , "IPF : error CAPSLoadImage\n" );
        !           392:                CAPSUnlockImage ( ImageId );
        !           393:                CAPSRemImage ( ImageId ) ;
        !           394:                return false;
        !           395:        }
        !           396: 
        !           397:        
        !           398:        IPF_State.CapsImage[ Drive ] = ImageId;
        !           399: 
        !           400:        IPF_State.Drive[ Drive ].diskattr |= CAPSDRIVE_DA_IN;                           /* Disk inserted, keep the value for "write protect" */
        !           401: 
        !           402:        CAPSFdcInvalidateTrack ( &IPF_State.Fdc , Drive );                              /* Invalidate previous buffered track data for drive, if any */
        !           403: 
        !           404:        IPF_State.Rev_Track[ Drive ] = -1;                                              /* Invalidate previous track/side to handle revolution's count */
        !           405:        IPF_State.Rev_Side[ Drive ] = -1;
        !           406: 
        !           407:        return true;
        !           408: #endif
        !           409: }
        !           410: 
        !           411: 
        !           412: 
        !           413: 
        !           414: /*
        !           415:  * When ejecting a disk, free the ressources associated with an IPF image
        !           416:  */
        !           417: bool   IPF_Eject ( int Drive )
        !           418: {
        !           419: #ifndef HAVE_CAPSIMAGE
        !           420:        return false;
        !           421: 
        !           422: #else
        !           423:        fprintf ( stderr , "IPF : IPF_Eject drive=%d imageid=%d\n" , Drive , IPF_State.CapsImage[ Drive ] );
        !           424: 
        !           425:        CAPSFdcInvalidateTrack ( &IPF_State.Fdc , Drive );                              /* Invalidate previous buffered track data for drive, if any */
        !           426: 
        !           427:        if ( CAPSUnlockImage ( IPF_State.CapsImage[ Drive ] ) < 0 )
        !           428:        {
        !           429:                fprintf ( stderr , "IPF : error CAPSUnlockImage\n" );
        !           430:                return false;
        !           431:        }
        !           432: 
        !           433:        if ( CAPSRemImage ( IPF_State.CapsImage[ Drive ] ) < 0 )
        !           434:        {
        !           435:                fprintf ( stderr , "IPF : error CAPSRemImage\n" );
        !           436:                return false;
        !           437:        }
        !           438: 
        !           439:        IPF_State.CapsImage[ Drive ] = -1;
        !           440: 
        !           441:        IPF_State.Drive[ Drive ].diskattr &= ~CAPSDRIVE_DA_IN;
        !           442: 
        !           443:        return true;
        !           444: #endif
        !           445: }
        !           446: 
        !           447: 
        !           448: 
        !           449: 
        !           450: /*
        !           451:  * Reset FDC state when a reset signal was received
        !           452:  */
        !           453: void IPF_Reset ( void )
        !           454: {
        !           455: #ifdef HAVE_CAPSIMAGE
        !           456:        CAPSFdcReset ( &IPF_State.Fdc );
        !           457: 
        !           458:        IPF_State.FdcClock = CyclesGlobalClockCounter;
        !           459: #endif
        !           460: }
        !           461: 
        !           462: 
        !           463: 
        !           464: 
        !           465: /*
        !           466:  * Callback function used when track is changed.
        !           467:  * We need to update the track data by calling CAPSLockTrack
        !           468:  */
        !           469: #ifdef HAVE_CAPSIMAGE
        !           470: static void    IPF_CallBack_Trk ( struct CapsFdc *pc , CapsULong State )
        !           471: {
        !           472:        int     Drive = State;                          /* State is the drive number in that case */
        !           473:        struct CapsDrive *pd = pc->drive+Drive;         /* Current drive where the track change occurred */
        !           474:        struct CapsTrackInfoT1 cti;
        !           475: 
        !           476:        cti.type=1;
        !           477:        if ( CAPSLockTrack ( &cti , IPF_State.CapsImage[ Drive ] , pd->buftrack , pd->bufside ,
        !           478:                        DI_LOCK_DENALT|DI_LOCK_DENVAR|DI_LOCK_UPDATEFD|DI_LOCK_TYPE ) != imgeOk )
        !           479:                return;
        !           480: 
        !           481:        LOG_TRACE(TRACE_FDC, "fdc ipf callback trk drive=%d buftrack=%d bufside=%d VBL=%d HBL=%d\n" , Drive ,
        !           482:                  (int)pd->buftrack , (int)pd->bufside , nVBLs , nHBL );
        !           483: 
        !           484:        pd->ttype       = cti.type;
        !           485:        pd->trackbuf    = cti.trackbuf;
        !           486:        pd->timebuf     = cti.timebuf;
        !           487:        pd->tracklen    = cti.tracklen;
        !           488:        pd->overlap     = cti.overlap;
        !           489: }
        !           490: #endif
        !           491: 
        !           492: 
        !           493: 
        !           494: 
        !           495: /*
        !           496:  * Callback function used when the FDC change the IRQ signal
        !           497:  */
        !           498: #ifdef HAVE_CAPSIMAGE
        !           499: static void    IPF_CallBack_Irq ( struct CapsFdc *pc , CapsULong State )
        !           500: {
        !           501:        LOG_TRACE(TRACE_FDC, "fdc ipf callback irq state=0x%x VBL=%d HBL=%d\n" , (int)State , nVBLs , nHBL );
        !           502: 
        !           503:        if ( State )
        !           504:                FDC_SetIRQ ( FDC_IRQ_SOURCE_OTHER );    /* IRQ bit was set */
        !           505:        else
        !           506:                FDC_ClearIRQ ();                        /* IRQ bit was reset */
        !           507: }
        !           508: #endif
        !           509: 
        !           510: 
        !           511: 
        !           512: 
        !           513: /*
        !           514:  * Callback function used when the FDC change the DRQ signal
        !           515:  * -> copy the byte to/from the DMA's FIFO if it's a read or a write to the disk
        !           516:  */
        !           517: #ifdef HAVE_CAPSIMAGE
        !           518: static void    IPF_CallBack_Drq ( struct CapsFdc *pc , CapsULong State )
        !           519: {
        !           520:        Uint8   Byte;
        !           521: 
        !           522:        if ( State == 0 )
        !           523:                return;                                 /* DRQ bit was reset, do nothing */
        !           524: 
        !           525:        if ( FDC_DMA_GetModeControl_R_WR () != 0 )      /* DMA write mode */
        !           526:        {
        !           527:                Byte = FDC_DMA_FIFO_Pull ();            /* Get a byte from the DMA FIFO */
        !           528:                CAPSFdcWrite ( &IPF_State.Fdc , 3 , Byte );     /* Write to FDC's reg 3 */
        !           529: 
        !           530:                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 );
        !           531:        }
        !           532: 
        !           533:        else                                            /* DMA read mode */
        !           534:        {
        !           535:                Byte = CAPSFdcRead ( &IPF_State.Fdc , 3 );      /* Read from FDC's reg 3 */
        !           536:                FDC_DMA_FIFO_Push ( Byte );             /* Add byte to the DMA FIFO */
        !           537: 
        !           538:                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 );
        !           539:        }
        !           540: }
        !           541: #endif
        !           542: 
        !           543: 
        !           544: 
        !           545: /*
        !           546:  * This function is used to enable/disable a drive when
        !           547:  * using the UI or command line parameters
        !           548:  *
        !           549:  * NOTE : for now, IPF only supports changing drive 1, drive 0
        !           550:  * is always ON.
        !           551:  */
        !           552: void   IPF_Drive_Set_Enable ( int Drive , bool value )
        !           553: {
        !           554: #ifndef HAVE_CAPSIMAGE
        !           555:        return;
        !           556: 
        !           557: #else
        !           558:        IPF_State.DriveEnabled[ Drive ] = value;                        /* Store the new state */
        !           559: 
        !           560:        IPF_Drive_Update_Enable_Side ();                                /* Update IPF's internal state */
        !           561: #endif
        !           562: }
        !           563: 
        !           564: 
        !           565: /*
        !           566:  * This function is used to configure a drive as single sided
        !           567:  * or double sided when using the UI or command line parameters
        !           568:  */
        !           569: void   IPF_Drive_Set_DoubleSided ( int Drive , bool value )
        !           570: {
        !           571: #ifndef HAVE_CAPSIMAGE
        !           572:        return;
        !           573: 
        !           574: #else
        !           575:        IPF_State.DoubleSided[ Drive ] = value;                         /* Store the new state */
        !           576: 
        !           577:        IPF_Drive_Update_Enable_Side ();                                /* Update IPF's internal state */
        !           578: #endif
        !           579: }
        !           580: 
        !           581: 
        !           582: /*
        !           583:  * Update IPF's internal state depending on which drives are ON or OFF
        !           584:  * and if the drive is single or double sided (for capslib >= 5.1)
        !           585:  */
        !           586: #ifdef HAVE_CAPSIMAGE
        !           587: static void    IPF_Drive_Update_Enable_Side ( void )
        !           588: {
        !           589:        int     i;
        !           590: 
        !           591:        if ( IPF_State.DriveEnabled[ 1 ] )
        !           592:                IPF_State.Fdc.drivemax = MAX_FLOPPYDRIVES;              /* Should be 2 */
        !           593:        else
        !           594:                IPF_State.Fdc.drivemax = MAX_FLOPPYDRIVES - 1;          /* Should be 1 */
        !           595: 
        !           596: #if CAPS_LIB_REL_REV >= 501
        !           597:        for ( i=0 ; i < MAX_FLOPPYDRIVES ; i++ )
        !           598:        {
        !           599:                if ( IPF_State.DoubleSided[ i ] )
        !           600:                        IPF_State.Drive[ i ].diskattr &= ~CAPSDRIVE_DA_SS;      /* Double sided */
        !           601:                else
        !           602:                        IPF_State.Drive[ i ].diskattr |= CAPSDRIVE_DA_SS;       /* Single sided */
        !           603:        }
        !           604: #endif
        !           605: }
        !           606: #endif
        !           607: 
        !           608: 
        !           609: /*
        !           610:  * Set the drive and the side to be used for the next FDC commands
        !           611:  * io_porta_old is the previous value, io_porta_new is the new value
        !           612:  * to take into account.
        !           613:  * We report a side change only when a drive is selected.
        !           614:  */
        !           615: void   IPF_SetDriveSide ( Uint8 io_porta_old , Uint8 io_porta_new )
        !           616: {
        !           617: #ifndef HAVE_CAPSIMAGE
        !           618:        return;
        !           619: 
        !           620: #else
        !           621:        int     Side;
        !           622: 
        !           623:        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 );
        !           624: 
        !           625:        Side = ( (~io_porta_new) & 0x01 );              /* Side 0 or 1 */
        !           626: 
        !           627:        IPF_State.Fdc.drivenew = -1;                    /* By default, don't select any drive */
        !           628: 
        !           629:        /* Check drive 1 first */
        !           630:        if ( ( io_porta_new & 0x04 ) == 0 )
        !           631:        {
        !           632:                IPF_State.Drive[ 1 ].newside = Side;
        !           633:                IPF_State.Fdc.drivenew = 1;             /* Select drive 1 */
        !           634:        }
        !           635: 
        !           636:        /* If both drive 0 and drive 1 are enabled, we keep only drive 0 as newdrive */
        !           637:        if ( ( io_porta_new & 0x02 ) == 0 )
        !           638:        {
        !           639:                IPF_State.Drive[ 0 ].newside = Side;
        !           640:                IPF_State.Fdc.drivenew = 0;             /* Select drive 0 (and un-select drive 1 if set above) */
        !           641:        }
        !           642: 
        !           643:        IPF_Emulate();                                  /* Update emulation's state up to this point, then set new drive/side */
        !           644: #endif
        !           645: }
        !           646: 
        !           647: 
        !           648: 
        !           649: 
        !           650: /*
        !           651:  * Write a byte into one of the FDC registers
        !           652:  * 0=command   1=track   2=sector   3=data
        !           653:  */
        !           654: void   IPF_FDC_WriteReg ( Uint8 Reg , Uint8 Byte )
        !           655: {
        !           656: #ifndef HAVE_CAPSIMAGE
        !           657:        return;                                         /* This should not be reached (an IPF image can't be inserted without capsimage) */
        !           658: 
        !           659: #else
        !           660:        LOG_TRACE(TRACE_FDC, "fdc ipf write reg=%d data=0x%x VBL=%d HBL=%d\n" , Reg , Byte , nVBLs , nHBL );
        !           661: 
        !           662:        
        !           663: #if CAPS_LIB_REL_REV >= 501
        !           664:        /* In the case of CTR images, we must reset the revolution counter */
        !           665:        /* when a command access data on disk and track/side changed since last access */
        !           666:        if ( Reg == 0 )
        !           667:        {
        !           668:                int     Type;
        !           669:                int     Drive;
        !           670: 
        !           671:                Type = FDC_GetCmdType ( Byte );
        !           672:                if ( ( Type == 2 ) || ( Type == 3 ) )
        !           673:                {
        !           674:                        Drive = IPF_State.Fdc.driveact;
        !           675:                        if ( ( Drive >= 0 )
        !           676:                          && ( ( IPF_State.Drive[ Drive ].side != IPF_State.Rev_Side[ Drive ] ) || ( IPF_State.Drive[ Drive ].track != IPF_State.Rev_Track[ Drive ] ) ) )
        !           677:                        {
        !           678:                                IPF_State.Rev_Side[ Drive ] = IPF_State.Drive[ Drive ].side;
        !           679:                                IPF_State.Rev_Track[ Drive ] = IPF_State.Drive[ Drive ].track;
        !           680:                                CAPSSetRevolution ( IPF_State.CapsImage[ Drive ] , 0 );
        !           681:                        }
        !           682:                }
        !           683:        }
        !           684: #endif
        !           685: 
        !           686:        IPF_Emulate();                                  /* Update emulation's state up to this point */
        !           687: 
        !           688:        CAPSFdcWrite ( &IPF_State.Fdc , Reg , Byte );
        !           689: #endif
        !           690: }
        !           691: 
        !           692: 
        !           693: 
        !           694: 
        !           695: /*
        !           696:  * Read the content of one of the FDC registers
        !           697:  * 0=status   1=track   2=sector   3=data
        !           698:  */
        !           699: Uint8  IPF_FDC_ReadReg ( Uint8 Reg )
        !           700: {
        !           701: #ifndef HAVE_CAPSIMAGE
        !           702:        return 0;                                       /* This should not be reached (an IPF image can't be inserted without capsimage) */
        !           703: #else
        !           704:        Uint8   Byte;
        !           705: 
        !           706:        IPF_Emulate();                                  /* Update emulation's state up to this point */
        !           707: 
        !           708:        Byte = CAPSFdcRead ( &IPF_State.Fdc , Reg );
        !           709:        LOG_TRACE(TRACE_FDC, "fdc ipf read reg=%d data=0x%x VBL=%d HBL=%d\n" , Reg , Byte , nVBLs , nHBL );
        !           710: 
        !           711:        return Byte;
        !           712: #endif
        !           713: }
        !           714: 
        !           715: 
        !           716: 
        !           717: 
        !           718: /*
        !           719:  * Return the content of some registers to display them in the statusbar
        !           720:  * We should not call IPF_Emulate() or similar, reading should not change emulation's state
        !           721:  */
        !           722: void   IPF_FDC_StatusBar ( Uint8 *pCommand , Uint8 *pHead , Uint8 *pTrack , Uint8 *pSector , Uint8 *pSide )
        !           723: {
        !           724: #ifndef HAVE_CAPSIMAGE
        !           725:        return;                                         /* This should not be reached (an IPF image can't be inserted without capsimage) */
        !           726: #else
        !           727:        int     Drive;
        !           728: 
        !           729:        Drive = IPF_State.Fdc.driveact;
        !           730:        if ( Drive < 0 )                                /* If no drive enabled, use drive O for Head/Side */
        !           731:                Drive = 0;
        !           732: 
        !           733:        /* We read directly in the structures, to be sure we don't change emulation's state */
        !           734:        *pCommand       = IPF_State.Fdc.r_command;
        !           735:        *pHead          = IPF_State.Drive[ Drive ].track;
        !           736:        *pTrack         = IPF_State.Fdc.r_track;
        !           737:        *pSector        = IPF_State.Fdc.r_sector;
        !           738:        *pSide          = IPF_State.Drive[ Drive ].side;
        !           739: #endif
        !           740: }
        !           741: 
        !           742: 
        !           743: 
        !           744: 
        !           745: /*
        !           746:  * Run the FDC emulation during NbCycles cycles (relative to the 8MHz FDC's clock)
        !           747:  */
        !           748: void   IPF_Emulate ( void )
        !           749: {
        !           750: #ifndef HAVE_CAPSIMAGE
        !           751:        return;
        !           752: 
        !           753: #else
        !           754:        int     NbCycles;
        !           755:        int     Drive;
        !           756: 
        !           757:        NbCycles = CyclesGlobalClockCounter - IPF_State.FdcClock;       /* Number of cycles since last emulation */
        !           758:        if ( NbCycles < 0 )
        !           759:                NbCycles = 0;                                           /* We should call CAPSFdcEmulate even when NbCycles=0 */
        !           760: 
        !           761: //     LOG_TRACE(TRACE_FDC, "fdc ipf emulate cycles=%d VBL=%d HBL=%d clock=%lld\n" , NbCycles , nVBLs , nHBL , CyclesGlobalClockCounter );
        !           762: 
        !           763:        /* Update Write Protect status for each drive */
        !           764:        for ( Drive=0 ; Drive < MAX_FLOPPYDRIVES ; Drive++ )
        !           765:                if ( Floppy_IsWriteProtected ( Drive ) )
        !           766:                        IPF_State.Drive[ Drive ].diskattr |= CAPSDRIVE_DA_WP;           /* Disk write protected */
        !           767:                else
        !           768:                        IPF_State.Drive[ Drive ].diskattr &= ~CAPSDRIVE_DA_WP;          /* Disk is not write protected */
        !           769: 
        !           770: 
        !           771:        CAPSFdcEmulate ( &IPF_State.Fdc , NbCycles );                   /* Process at max NbCycles */
        !           772:        IPF_State.FdcClock += IPF_State.Fdc.clockact;                   /* clockact can be < NbCycle in some cases */
        !           773: 
        !           774:        /* Update UI's LEDs depending on Status Register */
        !           775:        FDC_Drive_Set_BusyLed ( (IPF_State.Fdc.r_st0 & ~IPF_State.Fdc.r_stm) | (IPF_State.Fdc.r_st1 & IPF_State.Fdc.r_stm) );
        !           776: #endif
        !           777: }
        !           778: 
        !           779: 
        !           780: 

unix.superglobalmegacorp.com

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