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

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 */
1.1.1.3 ! root       56: #endif
1.1       root       57: 
                     58:        Sint64                  FdcClock;                       /* Current value of CyclesGlobalClockCounter */
                     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:                        IPF_State.Fdc.drive = IPF_State.Drive;          /* Connect drives array to the FDC */
                    126:                        if ( IPF_State.Fdc.driveprc != NULL )           /* Recompute active drive's pointer */
                    127:                                IPF_State.Fdc.driveprc = IPF_State.Fdc.drive + IPF_State.Fdc.driveact;
                    128: 
1.1.1.2   root      129:                        CAPSFdcInvalidateTrack ( &IPF_State.Fdc , 0 );  /* Invalidate buffered track data for drive 0 */
                    130:                        CAPSFdcInvalidateTrack ( &IPF_State.Fdc , 1 );  /* Invalidate buffered track data for drive 1 */
                    131: 
1.1       root      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;
1.1.1.2   root      321: #if CAPS_LIB_REL_REV >= 501
1.1       root      322:        CapsLong        ImageType;
1.1.1.2   root      323: #endif
1.1       root      324: 
                    325:        ImageId = CAPSAddImage();
                    326:        if ( ImageId < 0 )
                    327:        {
                    328:                fprintf ( stderr , "IPF : error CAPSAddImage\n" );
                    329:                return false;
                    330:        }
                    331: 
                    332: #if CAPS_LIB_REL_REV >= 501
                    333:        ImageType = CAPSGetImageTypeMemory ( pImageBuffer , ImageSize );
                    334:        if ( ImageType == citError )
                    335:        {
                    336:                fprintf ( stderr , "IPF : error CAPSGetImageTypeMemory\n" );
                    337:                return false;
                    338:        }
                    339:        else if ( ImageType == citUnknown )
                    340:        {
                    341:                fprintf ( stderr , "IPF : unknown image type\n" );
                    342:                return false;
                    343:        }
                    344: 
                    345:        fprintf ( stderr , "IPF : IPF_Insert drive=%d buf=%p size=%ld imageid=%d type=" , Drive , pImageBuffer , ImageSize , ImageId );
                    346:        switch ( ImageType ) {
                    347:                case citIPF:            fprintf ( stderr , "IPF\n" ); break;
                    348:                case citCTRaw:          fprintf ( stderr , "CT RAW\n" ); break;
                    349:                case citKFStream:       fprintf ( stderr , "KF STREAM\n" ) ; break;
                    350:                case citDraft:          fprintf ( stderr , "DRAFT\n" ) ; break;
                    351:                default :               fprintf ( stderr , "NOT SUPPORTED\n" );
                    352:                                        return false;
                    353:        }
                    354: #endif
                    355: 
                    356:        if ( CAPSLockImageMemory ( ImageId , pImageBuffer , (CapsULong)ImageSize , DI_LOCK_MEMREF ) == imgeOk )
                    357:        {
                    358:                struct CapsImageInfo cii;
                    359:                int             i;
                    360: 
                    361:                /* Print some debug infos */
                    362:                if ( CAPSGetImageInfo ( &cii , ImageId ) == imgeOk )
                    363:                {
                    364:                        printf("Type: %d\n", (int)cii.type);
                    365:                        printf("Release: %d\n", (int)cii.release);
                    366:                        printf("Revision: %d\n", (int)cii.revision);
                    367:                        printf("Min Cylinder: %d\n", (int)cii.mincylinder);
                    368:                        printf("Max Cylinder: %d\n", (int)cii.maxcylinder);
                    369:                        printf("Min Head: %d\n", (int)cii.minhead);
                    370:                        printf("Max Head: %d\n", (int)cii.maxhead);
                    371:                        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);
                    372:                        printf("Platforms:");
                    373:                        for (i = 0; i < CAPS_MAXPLATFORM; i++)
                    374:                                if (cii.platform[i] != ciipNA)
                    375:                                        printf ( " %s" , CAPSGetPlatformName(cii.platform[i]) );
                    376:                        printf("\n");
                    377: 
                    378:                        /* Some IPF disks are not correctly supported yet : display a warning */
                    379:                        if ( (int)cii.release == 3222 )                                 /* Sundog */
                    380:                                Log_AlertDlg ( LOG_INFO , "'Sundog' is not correctly supported yet, it requires write access." );
                    381:                        else if ( (int)cii.release == 3058 )                            /* Lethal Xcess */
                    382:                                Log_AlertDlg ( LOG_INFO , "'Lethal Xcess' is not correctly supported yet, protection will fail" );
                    383:                }
                    384:        }
                    385:        else
                    386:        {
                    387:                CAPSRemImage ( ImageId ) ;
                    388:                return false;
                    389:        }
                    390: 
                    391:        if ( CAPSLoadImage ( ImageId , DI_LOCK_DENALT | DI_LOCK_DENVAR | DI_LOCK_UPDATEFD ) != imgeOk )
                    392:        {
                    393:                fprintf ( stderr , "IPF : error CAPSLoadImage\n" );
                    394:                CAPSUnlockImage ( ImageId );
                    395:                CAPSRemImage ( ImageId ) ;
                    396:                return false;
                    397:        }
                    398: 
                    399:        
                    400:        IPF_State.CapsImage[ Drive ] = ImageId;
                    401: 
                    402:        IPF_State.Drive[ Drive ].diskattr |= CAPSDRIVE_DA_IN;                           /* Disk inserted, keep the value for "write protect" */
                    403: 
                    404:        CAPSFdcInvalidateTrack ( &IPF_State.Fdc , Drive );                              /* Invalidate previous buffered track data for drive, if any */
                    405: 
                    406:        IPF_State.Rev_Track[ Drive ] = -1;                                              /* Invalidate previous track/side to handle revolution's count */
                    407:        IPF_State.Rev_Side[ Drive ] = -1;
                    408: 
                    409:        return true;
                    410: #endif
                    411: }
                    412: 
                    413: 
                    414: 
                    415: 
                    416: /*
                    417:  * When ejecting a disk, free the ressources associated with an IPF image
                    418:  */
                    419: bool   IPF_Eject ( int Drive )
                    420: {
                    421: #ifndef HAVE_CAPSIMAGE
                    422:        return false;
                    423: 
                    424: #else
                    425:        fprintf ( stderr , "IPF : IPF_Eject drive=%d imageid=%d\n" , Drive , IPF_State.CapsImage[ Drive ] );
                    426: 
                    427:        CAPSFdcInvalidateTrack ( &IPF_State.Fdc , Drive );                              /* Invalidate previous buffered track data for drive, if any */
                    428: 
                    429:        if ( CAPSUnlockImage ( IPF_State.CapsImage[ Drive ] ) < 0 )
                    430:        {
                    431:                fprintf ( stderr , "IPF : error CAPSUnlockImage\n" );
                    432:                return false;
                    433:        }
                    434: 
                    435:        if ( CAPSRemImage ( IPF_State.CapsImage[ Drive ] ) < 0 )
                    436:        {
                    437:                fprintf ( stderr , "IPF : error CAPSRemImage\n" );
                    438:                return false;
                    439:        }
                    440: 
                    441:        IPF_State.CapsImage[ Drive ] = -1;
                    442: 
                    443:        IPF_State.Drive[ Drive ].diskattr &= ~CAPSDRIVE_DA_IN;
                    444: 
                    445:        return true;
                    446: #endif
                    447: }
                    448: 
                    449: 
                    450: 
                    451: 
                    452: /*
                    453:  * Reset FDC state when a reset signal was received
                    454:  */
                    455: void IPF_Reset ( void )
                    456: {
                    457: #ifdef HAVE_CAPSIMAGE
                    458:        CAPSFdcReset ( &IPF_State.Fdc );
                    459: 
                    460:        IPF_State.FdcClock = CyclesGlobalClockCounter;
                    461: #endif
                    462: }
                    463: 
                    464: 
                    465: 
                    466: 
                    467: /*
                    468:  * Callback function used when track is changed.
                    469:  * We need to update the track data by calling CAPSLockTrack
                    470:  */
                    471: #ifdef HAVE_CAPSIMAGE
                    472: static void    IPF_CallBack_Trk ( struct CapsFdc *pc , CapsULong State )
                    473: {
                    474:        int     Drive = State;                          /* State is the drive number in that case */
                    475:        struct CapsDrive *pd = pc->drive+Drive;         /* Current drive where the track change occurred */
                    476:        struct CapsTrackInfoT1 cti;
                    477: 
                    478:        cti.type=1;
                    479:        if ( CAPSLockTrack ( &cti , IPF_State.CapsImage[ Drive ] , pd->buftrack , pd->bufside ,
                    480:                        DI_LOCK_DENALT|DI_LOCK_DENVAR|DI_LOCK_UPDATEFD|DI_LOCK_TYPE ) != imgeOk )
                    481:                return;
                    482: 
                    483:        LOG_TRACE(TRACE_FDC, "fdc ipf callback trk drive=%d buftrack=%d bufside=%d VBL=%d HBL=%d\n" , Drive ,
                    484:                  (int)pd->buftrack , (int)pd->bufside , nVBLs , nHBL );
                    485: 
                    486:        pd->ttype       = cti.type;
                    487:        pd->trackbuf    = cti.trackbuf;
                    488:        pd->timebuf     = cti.timebuf;
                    489:        pd->tracklen    = cti.tracklen;
                    490:        pd->overlap     = cti.overlap;
                    491: }
                    492: #endif
                    493: 
                    494: 
                    495: 
                    496: 
                    497: /*
                    498:  * Callback function used when the FDC change the IRQ signal
                    499:  */
                    500: #ifdef HAVE_CAPSIMAGE
                    501: static void    IPF_CallBack_Irq ( struct CapsFdc *pc , CapsULong State )
                    502: {
                    503:        LOG_TRACE(TRACE_FDC, "fdc ipf callback irq state=0x%x VBL=%d HBL=%d\n" , (int)State , nVBLs , nHBL );
                    504: 
                    505:        if ( State )
                    506:                FDC_SetIRQ ( FDC_IRQ_SOURCE_OTHER );    /* IRQ bit was set */
                    507:        else
                    508:                FDC_ClearIRQ ();                        /* IRQ bit was reset */
                    509: }
                    510: #endif
                    511: 
                    512: 
                    513: 
                    514: 
                    515: /*
                    516:  * Callback function used when the FDC change the DRQ signal
                    517:  * -> copy the byte to/from the DMA's FIFO if it's a read or a write to the disk
                    518:  */
                    519: #ifdef HAVE_CAPSIMAGE
                    520: static void    IPF_CallBack_Drq ( struct CapsFdc *pc , CapsULong State )
                    521: {
                    522:        Uint8   Byte;
                    523: 
                    524:        if ( State == 0 )
                    525:                return;                                 /* DRQ bit was reset, do nothing */
                    526: 
                    527:        if ( FDC_DMA_GetModeControl_R_WR () != 0 )      /* DMA write mode */
                    528:        {
                    529:                Byte = FDC_DMA_FIFO_Pull ();            /* Get a byte from the DMA FIFO */
                    530:                CAPSFdcWrite ( &IPF_State.Fdc , 3 , Byte );     /* Write to FDC's reg 3 */
                    531: 
                    532:                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 );
                    533:        }
                    534: 
                    535:        else                                            /* DMA read mode */
                    536:        {
                    537:                Byte = CAPSFdcRead ( &IPF_State.Fdc , 3 );      /* Read from FDC's reg 3 */
                    538:                FDC_DMA_FIFO_Push ( Byte );             /* Add byte to the DMA FIFO */
                    539: 
                    540:                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 );
                    541:        }
                    542: }
                    543: #endif
                    544: 
                    545: 
                    546: 
                    547: /*
                    548:  * This function is used to enable/disable a drive when
                    549:  * using the UI or command line parameters
                    550:  *
                    551:  * NOTE : for now, IPF only supports changing drive 1, drive 0
                    552:  * is always ON.
                    553:  */
                    554: void   IPF_Drive_Set_Enable ( int Drive , bool value )
                    555: {
                    556: #ifndef HAVE_CAPSIMAGE
                    557:        return;
                    558: 
                    559: #else
                    560:        IPF_State.DriveEnabled[ Drive ] = value;                        /* Store the new state */
                    561: 
                    562:        IPF_Drive_Update_Enable_Side ();                                /* Update IPF's internal state */
                    563: #endif
                    564: }
                    565: 
                    566: 
                    567: /*
                    568:  * This function is used to configure a drive as single sided
                    569:  * or double sided when using the UI or command line parameters
                    570:  */
                    571: void   IPF_Drive_Set_DoubleSided ( int Drive , bool value )
                    572: {
                    573: #ifndef HAVE_CAPSIMAGE
                    574:        return;
                    575: 
                    576: #else
                    577:        IPF_State.DoubleSided[ Drive ] = value;                         /* Store the new state */
                    578: 
                    579:        IPF_Drive_Update_Enable_Side ();                                /* Update IPF's internal state */
                    580: #endif
                    581: }
                    582: 
                    583: 
                    584: /*
                    585:  * Update IPF's internal state depending on which drives are ON or OFF
                    586:  * and if the drive is single or double sided (for capslib >= 5.1)
                    587:  */
                    588: #ifdef HAVE_CAPSIMAGE
                    589: static void    IPF_Drive_Update_Enable_Side ( void )
                    590: {
1.1.1.2   root      591: #if CAPS_LIB_REL_REV >= 501
1.1       root      592:        int     i;
1.1.1.2   root      593: #endif
1.1       root      594: 
                    595:        if ( IPF_State.DriveEnabled[ 1 ] )
                    596:                IPF_State.Fdc.drivemax = MAX_FLOPPYDRIVES;              /* Should be 2 */
                    597:        else
                    598:                IPF_State.Fdc.drivemax = MAX_FLOPPYDRIVES - 1;          /* Should be 1 */
                    599: 
                    600: #if CAPS_LIB_REL_REV >= 501
                    601:        for ( i=0 ; i < MAX_FLOPPYDRIVES ; i++ )
                    602:        {
                    603:                if ( IPF_State.DoubleSided[ i ] )
                    604:                        IPF_State.Drive[ i ].diskattr &= ~CAPSDRIVE_DA_SS;      /* Double sided */
                    605:                else
                    606:                        IPF_State.Drive[ i ].diskattr |= CAPSDRIVE_DA_SS;       /* Single sided */
                    607:        }
                    608: #endif
                    609: }
                    610: #endif
                    611: 
                    612: 
                    613: /*
                    614:  * Set the drive and the side to be used for the next FDC commands
                    615:  * io_porta_old is the previous value, io_porta_new is the new value
                    616:  * to take into account.
                    617:  * We report a side change only when a drive is selected.
                    618:  */
                    619: void   IPF_SetDriveSide ( Uint8 io_porta_old , Uint8 io_porta_new )
                    620: {
                    621: #ifndef HAVE_CAPSIMAGE
                    622:        return;
                    623: 
                    624: #else
                    625:        int     Side;
                    626: 
                    627:        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 );
                    628: 
                    629:        Side = ( (~io_porta_new) & 0x01 );              /* Side 0 or 1 */
                    630: 
                    631:        IPF_State.Fdc.drivenew = -1;                    /* By default, don't select any drive */
                    632: 
                    633:        /* Check drive 1 first */
                    634:        if ( ( io_porta_new & 0x04 ) == 0 )
                    635:        {
                    636:                IPF_State.Drive[ 1 ].newside = Side;
                    637:                IPF_State.Fdc.drivenew = 1;             /* Select drive 1 */
                    638:        }
                    639: 
                    640:        /* If both drive 0 and drive 1 are enabled, we keep only drive 0 as newdrive */
                    641:        if ( ( io_porta_new & 0x02 ) == 0 )
                    642:        {
                    643:                IPF_State.Drive[ 0 ].newside = Side;
                    644:                IPF_State.Fdc.drivenew = 0;             /* Select drive 0 (and un-select drive 1 if set above) */
                    645:        }
                    646: 
                    647:        IPF_Emulate();                                  /* Update emulation's state up to this point, then set new drive/side */
                    648: #endif
                    649: }
                    650: 
                    651: 
                    652: 
                    653: 
                    654: /*
                    655:  * Write a byte into one of the FDC registers
                    656:  * 0=command   1=track   2=sector   3=data
                    657:  */
                    658: void   IPF_FDC_WriteReg ( Uint8 Reg , Uint8 Byte )
                    659: {
                    660: #ifndef HAVE_CAPSIMAGE
                    661:        return;                                         /* This should not be reached (an IPF image can't be inserted without capsimage) */
                    662: 
                    663: #else
                    664:        LOG_TRACE(TRACE_FDC, "fdc ipf write reg=%d data=0x%x VBL=%d HBL=%d\n" , Reg , Byte , nVBLs , nHBL );
                    665: 
                    666:        
                    667: #if CAPS_LIB_REL_REV >= 501
                    668:        /* In the case of CTR images, we must reset the revolution counter */
                    669:        /* when a command access data on disk and track/side changed since last access */
                    670:        if ( Reg == 0 )
                    671:        {
                    672:                int     Type;
                    673:                int     Drive;
                    674: 
                    675:                Type = FDC_GetCmdType ( Byte );
                    676:                if ( ( Type == 2 ) || ( Type == 3 ) )
                    677:                {
                    678:                        Drive = IPF_State.Fdc.driveact;
                    679:                        if ( ( Drive >= 0 )
                    680:                          && ( ( IPF_State.Drive[ Drive ].side != IPF_State.Rev_Side[ Drive ] ) || ( IPF_State.Drive[ Drive ].track != IPF_State.Rev_Track[ Drive ] ) ) )
                    681:                        {
                    682:                                IPF_State.Rev_Side[ Drive ] = IPF_State.Drive[ Drive ].side;
                    683:                                IPF_State.Rev_Track[ Drive ] = IPF_State.Drive[ Drive ].track;
                    684:                                CAPSSetRevolution ( IPF_State.CapsImage[ Drive ] , 0 );
                    685:                        }
                    686:                }
                    687:        }
                    688: #endif
                    689: 
                    690:        IPF_Emulate();                                  /* Update emulation's state up to this point */
                    691: 
                    692:        CAPSFdcWrite ( &IPF_State.Fdc , Reg , Byte );
                    693: #endif
                    694: }
                    695: 
                    696: 
                    697: 
                    698: 
                    699: /*
                    700:  * Read the content of one of the FDC registers
                    701:  * 0=status   1=track   2=sector   3=data
                    702:  */
                    703: Uint8  IPF_FDC_ReadReg ( Uint8 Reg )
                    704: {
                    705: #ifndef HAVE_CAPSIMAGE
                    706:        return 0;                                       /* This should not be reached (an IPF image can't be inserted without capsimage) */
                    707: #else
                    708:        Uint8   Byte;
                    709: 
                    710:        IPF_Emulate();                                  /* Update emulation's state up to this point */
                    711: 
                    712:        Byte = CAPSFdcRead ( &IPF_State.Fdc , Reg );
                    713:        LOG_TRACE(TRACE_FDC, "fdc ipf read reg=%d data=0x%x VBL=%d HBL=%d\n" , Reg , Byte , nVBLs , nHBL );
                    714: 
                    715:        return Byte;
                    716: #endif
                    717: }
                    718: 
                    719: 
                    720: 
                    721: 
                    722: /*
                    723:  * Return the content of some registers to display them in the statusbar
                    724:  * We should not call IPF_Emulate() or similar, reading should not change emulation's state
                    725:  */
                    726: void   IPF_FDC_StatusBar ( Uint8 *pCommand , Uint8 *pHead , Uint8 *pTrack , Uint8 *pSector , Uint8 *pSide )
                    727: {
                    728: #ifndef HAVE_CAPSIMAGE
                    729:        return;                                         /* This should not be reached (an IPF image can't be inserted without capsimage) */
                    730: #else
                    731:        int     Drive;
                    732: 
                    733:        Drive = IPF_State.Fdc.driveact;
                    734:        if ( Drive < 0 )                                /* If no drive enabled, use drive O for Head/Side */
                    735:                Drive = 0;
                    736: 
                    737:        /* We read directly in the structures, to be sure we don't change emulation's state */
                    738:        *pCommand       = IPF_State.Fdc.r_command;
                    739:        *pHead          = IPF_State.Drive[ Drive ].track;
                    740:        *pTrack         = IPF_State.Fdc.r_track;
                    741:        *pSector        = IPF_State.Fdc.r_sector;
                    742:        *pSide          = IPF_State.Drive[ Drive ].side;
                    743: #endif
                    744: }
                    745: 
                    746: 
                    747: 
                    748: 
                    749: /*
                    750:  * Run the FDC emulation during NbCycles cycles (relative to the 8MHz FDC's clock)
                    751:  */
                    752: void   IPF_Emulate ( void )
                    753: {
                    754: #ifndef HAVE_CAPSIMAGE
                    755:        return;
                    756: 
                    757: #else
                    758:        int     NbCycles;
                    759:        int     Drive;
                    760: 
                    761:        NbCycles = CyclesGlobalClockCounter - IPF_State.FdcClock;       /* Number of cycles since last emulation */
                    762:        if ( NbCycles < 0 )
                    763:                NbCycles = 0;                                           /* We should call CAPSFdcEmulate even when NbCycles=0 */
                    764: 
                    765: //     LOG_TRACE(TRACE_FDC, "fdc ipf emulate cycles=%d VBL=%d HBL=%d clock=%lld\n" , NbCycles , nVBLs , nHBL , CyclesGlobalClockCounter );
                    766: 
                    767:        /* Update Write Protect status for each drive */
                    768:        for ( Drive=0 ; Drive < MAX_FLOPPYDRIVES ; Drive++ )
                    769:                if ( Floppy_IsWriteProtected ( Drive ) )
                    770:                        IPF_State.Drive[ Drive ].diskattr |= CAPSDRIVE_DA_WP;           /* Disk write protected */
                    771:                else
                    772:                        IPF_State.Drive[ Drive ].diskattr &= ~CAPSDRIVE_DA_WP;          /* Disk is not write protected */
                    773: 
                    774: 
                    775:        CAPSFdcEmulate ( &IPF_State.Fdc , NbCycles );                   /* Process at max NbCycles */
                    776:        IPF_State.FdcClock += IPF_State.Fdc.clockact;                   /* clockact can be < NbCycle in some cases */
                    777: 
                    778:        /* Update UI's LEDs depending on Status Register */
                    779:        FDC_Drive_Set_BusyLed ( (IPF_State.Fdc.r_st0 & ~IPF_State.Fdc.r_stm) | (IPF_State.Fdc.r_st1 & IPF_State.Fdc.r_stm) );
                    780: #endif
                    781: }
                    782: 
                    783: 
                    784: 

unix.superglobalmegacorp.com

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