]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
floppybridge integration
authorToni Wilen <twilen@winuae.net>
Sat, 9 Oct 2021 18:00:23 +0000 (21:00 +0300)
committerToni Wilen <twilen@winuae.net>
Sat, 9 Oct 2021 18:00:23 +0000 (21:00 +0300)
15 files changed:
cfgfile.cpp
disk.cpp
floppybridge/floppybridge_abstract.h [new file with mode: 0644]
floppybridge/floppybridge_lib.cpp [new file with mode: 0644]
floppybridge/floppybridge_lib.h [new file with mode: 0644]
include/disk.h
include/gui.h
include/options.h
od-win32/resources/winuae.rc
od-win32/sysconfig.h
od-win32/win32gui.cpp
od-win32/winuae_msvc15/winuae_msvc.vcxproj
od-win32/winuae_msvc15/winuae_msvc.vcxproj.filters
savestate.cpp
statusline.cpp

index d30f8b4c88896ee080e4bb105b90d201e3de8914..c3722be1f60e777001a7ebaca4dbe6660c4621ea 100644 (file)
@@ -833,6 +833,10 @@ static void cfgfile_write_str(struct zfile *f, const TCHAR *option, const TCHAR
 {
        cfg_dowrite(f, option, optionext, value, 0, 0, 0);
 }
+static void cfgfile_write_str_escape(struct zfile *f, const TCHAR *option, const TCHAR *value)
+{
+       cfg_dowrite(f, option, value, 0, 0, 1);
+}
 void cfgfile_dwrite_str(struct zfile *f, const TCHAR *option, const TCHAR *value)
 {
        cfg_dowrite(f, option, value, 1, 0, 0);
@@ -1982,6 +1986,10 @@ void cfgfile_save_options (struct zfile *f, struct uae_prefs *p, int type)
                        _stprintf (tmp, _T("floppy%dsoundvolume_empty"), i);
                        cfgfile_write (f, tmp, _T("%d"), p->dfxclickvolume_empty[i]);
                }
+               if (p->floppyslots[i].config[0]) {
+                       _stprintf(tmp, _T("floppy%dconfig"), i);
+                       cfgfile_write_str_escape(f, tmp, p->floppyslots[i].config);
+               }
                if (p->floppyslots[i].dfxtype < 0 && p->nr_floppies > i)
                        p->nr_floppies = i;
        }
@@ -5922,6 +5930,10 @@ static int cfgfile_parse_hardware (struct uae_prefs *p, const TCHAR *option, TCH
                                p->floppyslots[i].df[0] = 0;
                        return 1;
                }
+               _stprintf(tmpbuf, _T("floppy%dconfig"), i);
+               if (cfgfile_string_escape(option, value, tmpbuf, p->floppyslots[i].config, sizeof p->floppyslots[i].config / sizeof(TCHAR))) {
+                       return 1;
+               }
        }
 
        if (cfgfile_intval (option, value, _T("chipmem_size"), &dummyint, 1)) {
index 12d3f14c76215322c1f81ab21ebf83b9fbb3fecf..2cde20e1edff264dbf77f13293d55b2ebdcac8ea 100644 (file)
--- a/disk.cpp
+++ b/disk.cpp
@@ -56,6 +56,10 @@ int disk_debug_track = -1;
 #include "statusline.h"
 #include "rommgr.h"
 #include "tinyxml2.h"
+#ifdef FLOPPYBRIDGE
+#include "floppybridge/floppybridge_abstract.h"
+#include "floppybridge/floppybridge_lib.h"
+#endif
 
 #undef CATWEASEL
 
@@ -160,7 +164,7 @@ typedef struct {
 #define DRIVE_ID_35HD  0xAAAAAAAA
 #define DRIVE_ID_525SD 0x55555555 /* 40 track 5.25 drive , kickstart does not recognize this */
 
-typedef enum { ADF_NONE = -1, ADF_NORMAL, ADF_EXT1, ADF_EXT2, ADF_FDI, ADF_IPF, ADF_SCP, ADF_CATWEASEL, ADF_PCDOS, ADF_KICK, ADF_SKICK, ADF_NORMAL_HEADER } drive_filetype;
+typedef enum { ADF_NONE = -1, ADF_NORMAL, ADF_EXT1, ADF_EXT2, ADF_FDI, ADF_IPF, ADF_SCP, ADF_CATWEASEL, ADF_PCDOS, ADF_KICK, ADF_SKICK, ADF_NORMAL_HEADER, ADF_FLOPPYBRIDGE } drive_filetype;
 typedef struct {
        struct zfile *diskfile;
        struct zfile *writediskfile;
@@ -221,6 +225,9 @@ typedef struct {
        bool track_access_done;
        bool fourms;
 #endif
+#ifdef FLOPPYBRIDGE
+       FloppyDiskBridge *bridge;
+#endif
 } drive;
 
 #define MIN_STEPLIMIT_CYCLE (CYCLE_UNIT * 140)
@@ -552,6 +559,23 @@ static int createimagefromexe (struct zfile *src, struct zfile *dst)
        return 1;
 }
 
+#ifdef FLOPPYBRIDGE
+static FloppyBridgeAPI *bridges[4];
+static int bridge_type[4];
+static const FloppyDiskBridge::BridgeDriver *bridge_driver[4];
+static bool floppybridge_available;
+static FloppyBridgeAPI::BridgeInformation bridgeinfo;
+static bool bridgeinfoloaded;
+static std::vector<FloppyBridgeAPI::DriverInformation> bridgedriverinfo;
+static void floppybridge_read_track(drive *drv);
+
+bool DISK_isfloppybridge(struct uae_prefs *p, int num)
+{
+       int v = p->floppyslots[num].dfxtype;
+       return v == DRV_FB_A_35_DD || v == DRV_FB_A_35_HD || v == DRV_FB_B_35_DD || v == DRV_FB_B_35_HD;
+}
+#endif
+
 static bool isfloppysound (drive *drv)
 {
        return drv->useturbo == 0;
@@ -570,6 +594,16 @@ static int get_floppy_speed_from_image(drive *drv)
 {
        int l, m;
        
+#ifdef FLOPPYBRIDGE
+       if (drv->bridge) {
+               drv->fourms = drv->bridge->getBitSpeed() == 4;
+               m = NORMAL_FLOPPY_SPEED;
+               if (drv->fourms) {
+                       m *= 2;
+               }
+               return m;
+       }
+#endif
        m = get_floppy_speed();
        l = drv->tracklen;
        drv->fourms = false;
@@ -609,6 +643,34 @@ static void drive_settype_id (drive *drv)
 {
        int t = currprefs.floppyslots[drv - &floppy[0]].dfxtype;
 
+#ifdef FLOPPYBRIDGE
+       if (drv->bridge)
+       {
+               if (drv->bridge->isDiskInDrive()) {
+                       switch (drv->bridge->getDriveTypeID()) {
+                       case FloppyDiskBridge::DriveTypeID::dti35DD:
+                               drv->drive_id = DRIVE_ID_35DD;
+                               break;
+                       case FloppyDiskBridge::DriveTypeID::dti35HD:
+                               if (t == DRV_35_HD) {
+                                       drv->drive_id = DRIVE_ID_35HD;
+                               } else {
+                                       drv->drive_id = DRIVE_ID_35DD;
+                               }
+                               break;
+                       case FloppyDiskBridge::DriveTypeID::dti5255SD:
+                               drv->drive_id = DRIVE_ID_525SD;
+                               break;
+                       }
+                       drv->ddhd = drv->bridge->getDriveTypeID() == FloppyDiskBridge::DriveTypeID::dti35HD ? 2 : 1;
+               } else {
+                       drv->drive_id = DRIVE_ID_35DD;
+                       drv->ddhd = 1;
+               }
+               return;
+       }
+#endif
+
        switch (t)
        {
        case DRV_35_HD:
@@ -714,6 +776,12 @@ static bool ispcbridgedrive(int num)
 
 static bool drive_writeprotected(drive *drv)
 {
+#ifdef FLOPPYBRIDGE
+       if (drv->bridge) {
+               bool v = drv->bridge->isWriteProtected();
+               return v;
+       }
+#endif
 #ifdef CATWEASEL
        if (drv->catweasel)
                return 1;
@@ -757,6 +825,16 @@ static void reset_drive (int num)
        _tcscpy (currprefs.floppyslots[num].df, changed_prefs.floppyslots[num].df);
        drv->newname[0] = 0;
        drv->newnamewriteprotected = false;
+#ifdef FLOPPYBRIDGE
+       if (drv->bridge) {
+               drv->bridge->resetDrive(drv->cyl);
+               drv->indexhackmode = 0;
+               drv->num_tracks = drv->bridge->getMaxCylinder() * 2;
+               drv->filetype = ADF_FLOPPYBRIDGE;
+               drv->tracklen = drv->bridge->maxMFMBitPosition();
+               drv->ddhd = drv->bridge->getDriveTypeID() == FloppyDiskBridge::DriveTypeID::dti35HD ? 2 : 1;
+       }
+#endif
        if (!drive_insert (drv, &currprefs, num, currprefs.floppyslots[num].df, false, false))
                disk_eject (num);
 }
@@ -786,12 +864,36 @@ static void update_drive_gui (int num, bool force)
                gui_data.drive_side = side;
        gid->drive_writing = writ;
        gid->floppy_protected = drive_writeprotected(drv);
+       gid->floppy_inserted = gid->df[0] || (drv->bridge && !drv->bridge->hasDiskChanged());
        gui_led (num + LED_DF0, (gid->drive_motor ? 1 : 0) | (gid->drive_writing ? 2 : 0), -1);
 }
 
 static void drive_fill_bigbuf (drive * drv,int);
 
-int DISK_validate_filename (struct uae_prefs *p, const TCHAR *fname_in, TCHAR *outfname, int leave_open, bool *wrprot, uae_u32 *crc32, struct zfile **zf)
+void DISK_get_path_text(struct uae_prefs *p, int n, TCHAR *text)
+{
+       _tcscpy(text, p->floppyslots[n].df);
+#ifdef FLOPPYBRIDGE
+       if (DISK_isfloppybridge(p, n) && floppybridge_available) {
+               if (!bridgeinfoloaded) {
+                       FloppyBridgeAPI::getBridgeDriverInformation(bridgeinfo);
+               }
+               _tcscpy(text, bridgeinfo.about);
+               if (bridge_driver[n]) {
+                       _tcscat(text, _T(", "));
+                       TCHAR *name = au(bridge_driver[n]->name);
+                       TCHAR *man = au(bridge_driver[n]->manufacturer);
+                       _tcscat(text, name);
+                       _tcscat(text, _T(", "));
+                       _tcscat(text, man);
+                       xfree(man);
+                       xfree(name);
+               }
+       }
+#endif
+}
+
+int DISK_validate_filename (struct uae_prefs *p, const TCHAR *fname_in, int num, TCHAR *outfname, int leave_open, bool *wrprot, uae_u32 *crc32, struct zfile **zf)
 {
        TCHAR outname[MAX_DPATH];
 
@@ -801,6 +903,14 @@ int DISK_validate_filename (struct uae_prefs *p, const TCHAR *fname_in, TCHAR *o
                *crc32 = 0;
        if (wrprot)
                *wrprot = p->floppy_read_only ? 1 : 0;
+       if (outfname)
+               outfname[0] = 0;
+
+#ifdef FLOPPYBRIDGE
+       if (DISK_isfloppybridge(p, num)) {
+               return 1;
+       }
+#endif
 
        cfgfile_resolve_path_out_load(fname_in, outname, MAX_DPATH, PATH_FLOPPY);
        if (outfname)
@@ -995,24 +1105,24 @@ TCHAR *DISK_get_saveimagepath(const TCHAR *name, int type)
        return DISK_get_saveimagepath(name, -1);
 }
 
-static struct zfile *getexistingwritefile(struct uae_prefs *p, const TCHAR *name, bool *wrprot)
+static struct zfile *getexistingwritefile(struct uae_prefs *p, const TCHAR *name, int num, bool *wrprot)
 {
        struct zfile *zf = NULL;
        TCHAR *path;
        TCHAR outname[MAX_DPATH];
 
        path = DISK_get_saveimagepath(name, saveimageoriginalpath);
-       DISK_validate_filename (p, path, outname, 1, wrprot, NULL, &zf);
+       DISK_validate_filename(p, path, num, outname, 1, wrprot, NULL, &zf);
        xfree(path);
        if (zf)
                return zf;
        path = DISK_get_saveimagepath(name, !saveimageoriginalpath);
-       DISK_validate_filename (p, path, outname, 1, wrprot, NULL, &zf);
+       DISK_validate_filename(p, path, num, outname, 1, wrprot, NULL, &zf);
        xfree(path);
        return zf;
 }
 
-static int iswritefileempty (struct uae_prefs *p, const TCHAR *name)
+static int iswritefileempty(struct uae_prefs *p, int num, const TCHAR *name)
 {
        struct zfile *zf;
        bool wrprot;
@@ -1020,7 +1130,7 @@ static int iswritefileempty (struct uae_prefs *p, const TCHAR *name)
        trackid td[MAX_TRACKS];
        int tracks, ddhd, i, ret;
 
-       zf = getexistingwritefile (p, name, &wrprot);
+       zf = getexistingwritefile(p, name, num, &wrprot);
        if (!zf)
                return 1;
        zfile_fread (buffer, sizeof (char), 8, zf);
@@ -1043,7 +1153,7 @@ static int openwritefile (struct uae_prefs *p, drive *drv, int create)
 {
        bool wrprot = 0;
 
-       drv->writediskfile = getexistingwritefile(p, currprefs.floppyslots[drv - &floppy[0]].df, &wrprot);
+       drv->writediskfile = getexistingwritefile(p, currprefs.floppyslots[drv - &floppy[0]].df, drv - &floppy[0], &wrprot);
        if (drv->writediskfile) {
                drv->wrprot = wrprot;
                if (!read_header_ext2 (drv->writediskfile, drv->writetrackdata, &drv->write_num_tracks, 0)) {
@@ -1060,7 +1170,7 @@ static int openwritefile (struct uae_prefs *p, drive *drv, int create)
        return drv->writediskfile ? 1 : 0;
 }
 
-static bool diskfile_iswriteprotect (struct uae_prefs *p, const TCHAR *fname_in, int *needwritefile, drive_type *drvtype)
+static bool diskfile_iswriteprotect (struct uae_prefs *p, const TCHAR *fname_in, int num, int *needwritefile, drive_type *drvtype)
 {
        struct zfile *zf1, *zf2;
        bool wrprot1 = 0, wrprot2 = 1;
@@ -1069,14 +1179,14 @@ static bool diskfile_iswriteprotect (struct uae_prefs *p, const TCHAR *fname_in,
 
        *needwritefile = 0;
        *drvtype = DRV_35_DD;
-       DISK_validate_filename (p, fname_in, outname, 1, &wrprot1, NULL, &zf1);
+       DISK_validate_filename (p, fname_in, num, outname, 1, &wrprot1, NULL, &zf1);
        if (!zf1)
                return 1;
        if (zfile_iscompressed (zf1)) {
                wrprot1 = 1;
                *needwritefile = 1;
        }
-       zf2 = getexistingwritefile(p, fname_in, &wrprot2);
+       zf2 = getexistingwritefile(p, fname_in, num, &wrprot2);
        zfile_fclose (zf2);
        zfile_fread (buffer, sizeof (char), 25, zf1);
        zfile_fclose (zf1);
@@ -1123,6 +1233,15 @@ static bool isrecognizedext(const TCHAR *name)
 static void update_disk_statusline(int num)
 {
        drive *drv = &floppy[num];
+#ifdef FLOPPYBRIDGE
+       if (drv->bridge) {
+               const char *name = drv->bridge->getDriverInfo()->name;
+               TCHAR *n = au(name);
+               statusline_add_message(STATUSTYPE_FLOPPY, _T("DF%d: %s"), num, n);
+               xfree(n);
+               return;
+       }
+#endif
        if (!drv->diskfile)
                return;
        const TCHAR *fname = zfile_getoriginalname(drv->diskfile);
@@ -1145,9 +1264,10 @@ static int drive_insert (drive * drv, struct uae_prefs *p, int dnum, const TCHAR
        TCHAR outname[MAX_DPATH];
 
        drive_image_free (drv);
-       if (!fake)
-               DISK_examine_image(p, dnum, &disk_info_data, false);
-       DISK_validate_filename (p, fname_in, outname, 1, &drv->wrprot, &drv->crc32, &drv->diskfile);
+       if (!fake && !drv->bridge) {
+               DISK_examine_image(p, dnum, &disk_info_data, false, NULL);
+       }
+       DISK_validate_filename (p, fname_in, dnum, outname, 1, &drv->wrprot, &drv->crc32, &drv->diskfile);
        drv->forcedwrprot = forcedwriteprotect;
        if (drv->forcedwrprot)
                drv->wrprot = true;
@@ -1168,7 +1288,7 @@ static int drive_insert (drive * drv, struct uae_prefs *p, int dnum, const TCHAR
                drv->dskready_down_time = 0;
        }
 
-       if (drv->diskfile == NULL && !drv->catweasel) {
+       if (drv->diskfile == NULL && !drv->catweasel && !drv->bridge) {
                track_reset (drv);
                return 0;
        }
@@ -1214,6 +1334,35 @@ static int drive_insert (drive * drv, struct uae_prefs *p, int dnum, const TCHAR
                drv->num_tracks = 80;
                drv->ddhd = 1;
 
+#ifdef FLOPPYBRIDGE
+       } else if (drv->bridge) {
+               drv->ddhd = (drv->bridge->getDriveTypeID() == FloppyDiskBridge::DriveTypeID::dti35HD) ? 2 : 1;
+               drv->num_heads = 2;
+               drv->num_secs = 0;
+               drv->hard_num_cyls = drv->bridge->getMaxCylinder();
+               drv->num_tracks = drv->bridge->getMaxCylinder() * 2;
+               drv->tracklen = drv->bridge->maxMFMBitPosition();
+               drv->tracktiming[0] = drv->bridge->getMFMSpeed(0);
+               drv->multi_revolution = 1;
+               drv->fourms = (drv->bridge->getBitSpeed() == 4);
+               drv->indexoffset = 0;
+               drv->prevtracklen = 0;
+               drv->forcedwrprot = false;
+               drv->wrprot = drv->bridge->isWriteProtected();
+               drv->filetype = ADF_FLOPPYBRIDGE;
+               drv->useturbo = 0;
+               drv->mfmpos = uaerand();
+               drv->mfmpos |= (uaerand() << 16);
+               drv->mfmpos %= drv->tracklen;
+               drv->prevtracklen = 0;
+
+               drive_settype_id(drv); /* Set DD or HD drive */
+               update_drive_gui(drv - floppy, false);
+               update_disk_statusline(drv - floppy);
+               drive_fill_bigbuf(drv, fake ? -1 : 1);
+
+               return 1;
+#endif
 #ifdef CAPS
        } else if (strncmp ((char*)buffer, "CAPS", 4) == 0) {
 
@@ -1528,8 +1677,14 @@ static void set_steplimit (drive *drv)
        drv->steplimitcycle = get_cycles ();
 }
 
-static int drive_empty (drive * drv)
+static bool drive_empty (drive * drv)
 {
+#ifdef FLOPPYBRIDGE
+       if (drv->bridge) {
+               bool v = drv->bridge->isDiskInDrive();
+               return v == false;
+       }
+#endif
 #ifdef CATWEASEL
        if (drv->catweasel)
                return catweasel_disk_changed (drv->catweasel) == 0;
@@ -1537,7 +1692,7 @@ static int drive_empty (drive * drv)
        return drv->diskfile == 0 && drv->dskchange_time >= 0;
 }
 
-static void drive_step (drive * drv, int step_direction)
+static void drive_step (drive *drv, int step_direction)
 {
 #ifdef CATWEASEL
        if (drv->catweasel) {
@@ -1552,6 +1707,24 @@ static void drive_step (drive * drv, int step_direction)
 #endif
        if (!drive_empty (drv))
                drv->dskchange = 0;
+
+#ifdef FLOPPYBRIDGE
+       if (drv->bridge) {
+               int dir = step_direction ? -1 : 1;
+               drv->cyl += dir;
+               if (drv->cyl < 0) {
+                       drv->cyl = 0;
+                       drv->bridge->handleNoClickStep(side);
+               } else {
+                       if (drv->cyl >= drv->bridge->getMaxCylinder()) {
+                               drv->cyl = drv->bridge->getMaxCylinder() - 1;
+                       }
+                       drv->bridge->gotoCylinder(drv->cyl, side);
+               }
+               return;
+       }
+#endif
+
        if (drv->steplimit && get_cycles() - drv->steplimitcycle < MIN_STEPLIMIT_CYCLE) {
                write_log (_T(" step ignored drive %ld, %lu\n"),
                        drv - floppy, (get_cycles() - drv->steplimitcycle) / CYCLE_UNIT);
@@ -1595,8 +1768,14 @@ static void drive_step (drive * drv, int step_direction)
                write_log (_T(" ->step %d"), drv->cyl);
 }
 
-static int drive_track0 (drive * drv)
+static bool drive_track0 (drive * drv)
 {
+#ifdef FLOPPYBRIDGE
+       if (drv->bridge) {
+               bool v = drv->bridge->isAtCylinder0();
+               return v;
+       }
+#endif
 #ifdef CATWEASEL
        if (drv->catweasel)
                return catweasel_track0 (drv->catweasel);
@@ -1604,8 +1783,47 @@ static int drive_track0 (drive * drv)
        return drv->cyl == 0;
 }
 
-static int drive_running (drive * drv)
+static bool drive_diskchange(drive *drv)
+{
+#ifdef FLOPPYBRIDGE
+       if (drv->bridge) {
+               bool v = drv->bridge->hasDiskChanged();
+               return v;
+       }
+#endif
+       return drv->dskchange;
+}
+
+static bool drive_diskready(drive *drv)
+{
+#ifdef FLOPPYBRIDGE
+       if (drv->bridge) {
+               bool v = drv->bridge->isReady();
+               return v;
+       }
+#endif
+       return drv->dskready;
+}
+
+static bool drive_at_index(drive *drv, int mfmBitPosition)
+{
+#ifdef FLOPPYBRIDGE
+       if (drv->bridge) {
+               bool v = drv->bridge->isMFMPositionAtIndex(mfmBitPosition);
+               return v;
+       }
+#endif
+       return mfmBitPosition == drv->indexoffset;
+}
+
+static bool drive_running (drive * drv)
 {
+#ifdef FLOPPYBRIDGE
+       if (drv->bridge) {
+               bool v = drv->bridge->isMotorRunning();
+               return v;
+       }
+#endif
        return !drv->motoroff;
 }
 
@@ -1628,6 +1846,11 @@ static void drive_motor (drive * drv, bool off)
        }
        if (!drv->motoroff && off) {
                drv->drive_id_scnt = 0; /* Reset id shift reg counter */
+#ifdef FLOPPYBRIDGE
+               if (drv->bridge) {
+                       drive_settype_id(drv);  // allow for dynamic DD/HD switching
+               }
+#endif
                drv->dskready_down_time = DSKREADY_DOWN_TIME * 312 + (uaerand() & 511);
 #ifdef DRIVESOUND
                driveclick_motor (drv - floppy, 0);
@@ -1649,6 +1872,11 @@ static void drive_motor (drive * drv, bool off)
        } else {
                drv->dskready_down_time = 0;
        }
+#ifdef FLOPPYBRIDGE
+       if (drv->bridge) {
+               drv->bridge->setMotorStatus(side, !drv->motoroff);
+       }
+#endif
 #ifdef CATWEASEL
        if (drv->catweasel)
                catweasel_set_motor (drv->catweasel, !drv->motoroff);
@@ -2004,7 +2232,7 @@ static void drive_fill_bigbuf (drive * drv, int force)
        bool retrytrack;
        int rev = -1;
 
-       if ((!drv->diskfile && !drv->catweasel) || tr >= drv->num_tracks) {
+       if ((!drv->diskfile && !drv->catweasel && !drv->bridge) || tr >= drv->num_tracks) {
                track_reset (drv);
                return;
        }
@@ -2031,14 +2259,27 @@ static void drive_fill_bigbuf (drive * drv, int force)
                trackid *wti = &drv->writetrackdata[tr];
                drv->tracklen = wti->bitlen;
                drv->revolutions = wti->revolutions;
-               read_floppy_data (drv->writediskfile, drv->filetype, wti, 0, (uae_u8*)drv->bigmfmbuf, NULL, (wti->bitlen + 7) / 8);
+               read_floppy_data(drv->writediskfile, drv->filetype, wti, 0, (uae_u8 *)drv->bigmfmbuf, NULL, (wti->bitlen + 7) / 8);
                for (i = 0; i < (drv->tracklen + 15) / 16; i++) {
                        uae_u16 *mfm = drv->bigmfmbuf + i;
-                       uae_u8 *data = (uae_u8 *) mfm;
+                       uae_u8 *data = (uae_u8 *)mfm;
                        *mfm = 256 * *data + *(data + 1);
                }
                if (disk_debug_logging > 0)
-                       write_log (_T("track %d, length %d read from \"saveimage\"\n"), tr, drv->tracklen);
+                       write_log(_T("track %d, length %d read from \"saveimage\"\n"), tr, drv->tracklen);
+#ifdef FLOPPYBRIDGE
+       } else if (drv->filetype == ADF_FLOPPYBRIDGE) {
+               if (drv->bridge) {
+                       drv->multi_revolution = 1;
+                       drv->skipoffset = -1;
+                       drv->bridge->setSurface(side); // force the correct disk side to be selected
+                       drv->tracklen = drv->bridge->maxMFMBitPosition();
+                       drv->tracktiming[0] = drv->bridge->getMFMSpeed(drv->mfmpos % drv->tracklen);
+                       if (force < 0) {
+                               floppybridge_read_track(drv);
+                       }
+               }
+#endif
        } else if (drv->filetype == ADF_CATWEASEL) {
 #ifdef CATWEASEL
                drv->tracklen = 0;
@@ -2576,6 +2817,14 @@ static void drive_write_data (drive * drv)
                if (ret < 0)
                        write_log (_T("not a PC formatted track %d (error %d)\n"), drv->cyl * 2 + side, ret);
                break;
+#ifdef FLOPPYBRIDGE
+       case ADF_FLOPPYBRIDGE:
+               if (drv->bridge) {
+                       // Request to commit the buffer we have collected to disk - this should hardly ever be triggered
+                       drv->tracklen = drv->bridge->commitWriteBuffer(side, drv->cyl);
+               }
+               break;
+#endif
        }
        drv->tracktiming[0] = 0;
 }
@@ -2752,11 +3001,11 @@ bool disk_creatediskfile (struct uae_prefs *p, const TCHAR *name, int type, driv
        return ok;
 }
 
-int disk_getwriteprotect (struct uae_prefs *p, const TCHAR *name)
+int disk_getwriteprotect (struct uae_prefs *p, const TCHAR *name, int num)
 {
        int needwritefile;
        drive_type drvtype;
-       return diskfile_iswriteprotect (p, name, &needwritefile, &drvtype);
+       return diskfile_iswriteprotect (p, name, num, &needwritefile, &drvtype);
 }
 
 static void diskfile_readonly (const TCHAR *name, bool readonly)
@@ -2814,8 +3063,8 @@ int disk_setwriteprotect (struct uae_prefs *p, int num, const TCHAR *fname_in, b
 
        write_log(_T("disk_setwriteprotect %d '%s' %d\n"), num, fname_in, writeprotected);
 
-       oldprotect = diskfile_iswriteprotect (p, fname_in, &needwritefile, &drvtype);
-       DISK_validate_filename (p, fname_in, outfname, 1, &wrprot1, NULL, &zf1);
+       oldprotect = diskfile_iswriteprotect (p, fname_in, num, &needwritefile, &drvtype);
+       DISK_validate_filename (p, fname_in, num, outfname, 1, &wrprot1, NULL, &zf1);
        if (!zf1)
                return 0;
 
@@ -2828,13 +3077,13 @@ int disk_setwriteprotect (struct uae_prefs *p, int num, const TCHAR *fname_in, b
        if (zfile_iscompressed (zf1))
                wrprot1 = 1;
        zfile_fclose (zf1);
-       zf2 = getexistingwritefile(p, fname_in, &wrprot2);
+       zf2 = getexistingwritefile(p, fname_in, num, &wrprot2);
        name2 = DISK_get_saveimagepath(fname_in, -2);
 
        if (needwritefile && zf2 == NULL)
                disk_creatediskfile (p, name2, 1, drvtype, -1, NULL, false, false, NULL);
        zfile_fclose (zf2);
-       if (writeprotected && iswritefileempty (p, fname_in)) {
+       if (writeprotected && iswritefileempty(p, num, fname_in)) {
                for (i = 0; i < MAX_FLOPPY_DRIVES; i++) {
                        if (!_tcscmp (fname_in, floppy[i].newname))
                                drive_eject (&floppy[i]);
@@ -3158,6 +3407,11 @@ void DISK_select (uae_u8 data)
                                if (!((selected | disabled) & (1 << dr)) && (prev_selected & (1 << dr)) ) {
                                        drv->drive_id_scnt++;
                                        drv->drive_id_scnt &= 31;
+#ifdef FLOPPYBRIDGE
+                                       if (drv->bridge) {
+                                               drive_settype_id(drv);   // allow for dynamic DD/HD switching
+                                       }
+#endif
                                        drv->idbit = (drv->drive_id & (1L << (31 - drv->drive_id_scnt))) ? 1 : 0;
                                        if (!(disabled & (1 << dr))) {
                                                if ((prev_data & 0x80) == 0 || (data & 0x80) == 0) {
@@ -3226,7 +3480,7 @@ uae_u8 DISK_status_ciaa(void)
                for (int dr = 0; dr < 2; dr++) {
                        drive *drv = floppy + dr;
                        if (!(((selected >> 3) | disabled) & (1 << dr))) {
-                               if (drv->dskchange)
+                               if (drive_diskchange(drv))
                                        st &= ~0x20;
                                if (drive_track0 (drv))
                                        st &= ~0x10;
@@ -3251,17 +3505,17 @@ uae_u8 DISK_status_ciaa(void)
                                                st &= ~0x20;
 #endif
                                } else {
-                                       if (drv->dskready && !drv->indexhack && currprefs.floppyslots[dr].dfxtype != DRV_35_DD_ESCOM)
+                                       if (drive_diskready(drv) && !drv->indexhack && (currprefs.floppyslots[dr].dfxtype != DRV_35_DD_ESCOM || drv->bridge))
                                                st &= ~0x20;
                                }
                        } else {
                                if (currprefs.cs_df0idhw || dr > 0) {
                                        /* report drive ID */
-                                       if (drv->idbit && currprefs.floppyslots[dr].dfxtype != DRV_35_DD_ESCOM)
+                                       if (drv->idbit && (currprefs.floppyslots[dr].dfxtype != DRV_35_DD_ESCOM || (drv->bridge->getDriveTypeID() != FloppyDiskBridge::DriveTypeID::dti35DD)))
                                                st &= ~0x20;
                                } else {
                                        /* non-ID internal drive: mirror real dskready */
-                                       if (drv->dskready)
+                                       if (drive_diskready(drv))
                                                st &= ~0x20;
                                }
                                /* dskrdy needs some cycles after switching the motor off.. (Pro Tennis Tour) */
@@ -3277,7 +3531,7 @@ uae_u8 DISK_status_ciaa(void)
                                if (catweasel_disk_changed (drv->catweasel))
                                        st &= ~4;
 #endif
-                       } else if (drv->dskchange && currprefs.floppyslots[dr].dfxtype != DRV_525_SD) {
+                       } else if (drive_diskchange(drv) && (currprefs.floppyslots[dr].dfxtype != DRV_525_SD || drv->bridge)) {
                                st &= ~4;
                        }
                } else if (!((selected | disabled) & (1 << dr))) {
@@ -3291,6 +3545,12 @@ uae_u8 DISK_status_ciaa(void)
 
 static bool unformatted (drive *drv)
 {
+#ifdef FLOPPYBRIDGE
+       if (drv->bridge) {
+               bool v = drv->bridge->isDiskInDrive();
+               return v == false;
+       }
+#endif
        int tr = drv->cyl * 2 + side;
        if (tr >= drv->num_tracks)
                return true;
@@ -3313,6 +3573,14 @@ static uae_u32 getonebit(drive *drv, uae_u16 *mfmbuf, int mfmpos, int *inc)
 
        if (inc)
                *inc = 1;
+
+#ifdef FLOPPYBRIDGE
+       if (drv && drv->bridge) {
+               drv->tracklen = drv->bridge->maxMFMBitPosition();  // this shouldnt happen              
+               return drv->bridge->getMFMBit(mfmpos) ? 1 : 0;
+       }
+#endif
+
        if (inc && nextbit(drv) == 2) {
                // 2us -> 4us
                int b1 = getonebit(NULL, mfmbuf, mfmpos, NULL);
@@ -3414,6 +3682,12 @@ static void fetchnextrevolution (drive *drv)
                fdi2raw_loadrevolution(drv->fdi, drv->bigmfmbuf, drv->tracktiming, drv->cyl * 2 + side, &drv->tracklen, 1);
 #endif
                break;
+#ifdef FLOPPYBRIDGE
+       case ADF_FLOPPYBRIDGE:
+               drv->bridge->mfmSwitchBuffer(side);
+               drv->trackspeed = get_floppy_speed_from_image(drv);
+               break;
+#endif
        }
 }
 
@@ -3473,7 +3747,7 @@ static void disk_doupdate_write(int floppybits, int trackspeed)
                                drive *drv2 = &floppy[dr];
                                drv2->mfmpos++;
                                drv2->mfmpos %= drv2->tracklen;
-                               if (drv2->mfmpos == drv2->indexoffset) {
+                               if (drive_at_index(drv2, drv2->mfmpos)) {
                                        do_disk_index();
                                }
                        }
@@ -3491,6 +3765,9 @@ static void disk_doupdate_write(int floppybits, int trackspeed)
                                        }
                                }
                                if (disk_fifostatus () >= 0) {
+#ifdef FLOPPYBRIDGE
+                                       bool wasBridge = false;
+#endif
                                        uae_u16 w = DSKDATR ();
                                        for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) {
                                                drive *drv2 = &floppy[dr];
@@ -3498,6 +3775,12 @@ static void disk_doupdate_write(int floppybits, int trackspeed)
                                                        drv2->bigmfmbuf[drv2->mfmpos >> 4] = w;
                                                        drv2->bigmfmbuf[(drv2->mfmpos >> 4) + 1] = 0x5555;
                                                        drv2->writtento = 1;
+#ifdef FLOPPYBRIDGE
+                                                       if (drv2->bridge) {
+                                                               wasBridge = true;
+                                                               drv2->bridge->writeShortToBuffer(side, drv2->cyl, w, drv2->mfmpos);
+                                                       }
+#endif
                                                }
 #ifdef AMAX
                                                if (amax_enabled)
@@ -3506,7 +3789,10 @@ static void disk_doupdate_write(int floppybits, int trackspeed)
                                        }
                                        dsklength--;
                                        if (dsklength <= 0) {
-                                               disk_dmafinished ();
+                                               // delay write DMA finished state until bridge has all pending data written
+                                               if (!wasBridge) {
+                                                       disk_dmafinished();
+                                               }
                                                for (int dr = 0; dr < MAX_FLOPPY_DRIVES ; dr++) {
                                                        drive *drv = &floppy[dr];
                                                        drv->writtento = 0;
@@ -3519,6 +3805,26 @@ static void disk_doupdate_write(int floppybits, int trackspeed)
                                        }
                                }
                        }
+
+#ifdef FLOPPYBRIDGE
+                       // Bridge pass check
+                       if (dsklength <= 0) {
+                               for (int dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) {
+                                       drive *drv = &floppy[dr];
+                                       if (drv->bridge && drives[dr]) {
+                                               drv->writtento = 0;
+                                               if (drv->motoroff)
+                                                       continue;
+                                               if ((selected | disabled) & (1 << dr))
+                                                       continue;
+                                               // With bridge we wait for the disk to commit the data before fireing the DMA
+                                               if (drv->bridge->isWriteComplete()) {
+                                                       disk_dmafinished();
+                                               }
+                                       }
+                               }
+                       }
+#endif
                }
                floppybits -= trackspeed;
        }
@@ -3535,6 +3841,12 @@ static void update_jitter (void)
 static void updatetrackspeed (drive *drv, int mfmpos)
 {
        if (dskdmaen < DSKDMA_WRITE) {
+#ifdef FLOPPYBRIDGE
+               if (drv->bridge) {
+                       drv->trackspeed = NORMAL_FLOPPY_SPEED * drv->bridge->getMFMSpeed(mfmpos) / 1000;
+                       return;
+               }
+#endif
                int t = drv->tracktiming[mfmpos / 8];
                int ts = get_floppy_speed_from_image(drv) * t / 1000;
                if (ts < 700 || ts > 3000) {
@@ -3590,7 +3902,7 @@ static void disk_doupdate_predict (int startcycle)
                        if (!dskdmaen) {
                                if (mfmpos == 0)
                                        diskevent_flag |= DISK_REVOLUTION << (drv - floppy);
-                               if (mfmpos == drv->indexoffset)
+                               if (drive_at_index(drv, mfmpos))
                                        diskevent_flag |= DISK_INDEXSYNC;
                        }
                        if (dskdmaen != DSKDMA_WRITE && mfmpos == drv->skipoffset) {
@@ -3601,7 +3913,7 @@ static void disk_doupdate_predict (int startcycle)
                                        if (!dskdmaen) {
                                                if (mfmpos == 0)
                                                        diskevent_flag |= DISK_REVOLUTION << (drv - floppy);
-                                               if (mfmpos == drv->indexoffset)
+                                               if (drive_at_index(drv, mfmpos))
                                                        diskevent_flag |= DISK_INDEXSYNC;
                                        }
                                }
@@ -3798,7 +4110,7 @@ static void disk_doupdate_read (drive * drv, int floppybits)
                }
                drv->mfmpos += inc;
                drv->mfmpos %= drv->tracklen;
-               if (drv->mfmpos == drv->indexoffset) {
+               if (drive_at_index(drv, drv->mfmpos)) {
                        if (disk_debug_logging > 2 && drv->indexhack)
                                write_log (_T("indexhack cleared\n"));
                        drv->indexhack = 0;
@@ -3814,7 +4126,7 @@ static void disk_doupdate_read (drive * drv, int floppybits)
                        while (skipcnt-- > 0) {
                                drv->mfmpos += nextbit(drv);
                                drv->mfmpos %= drv->tracklen;
-                               if (drv->mfmpos == drv->indexoffset) {
+                               if (drive_at_index(drv, drv->mfmpos)) {
                                        if (disk_debug_logging > 2 && drv->indexhack)
                                                write_log (_T("indexhack cleared\n"));
                                        drv->indexhack = 0;
@@ -3954,10 +4266,18 @@ static void DISK_start (void)
                                bitoffset = 0;
                                word = 0;
                        }
+#ifdef CATWEASEL
                        if (drv->catweasel) {
                                word = 0;
                                drive_fill_bigbuf (drv, 1);
                        }
+#endif
+#ifdef FLOPPYBRIDGE
+                       if (drv->bridge && dskdmaen != DSKDMA_WRITE) {
+                               word = 0;
+                               drive_fill_bigbuf(drv, 1);
+                       }
+#endif
                }
                drv->floppybitcounter = 0;
        }
@@ -4057,6 +4377,11 @@ void DISK_update (int tohpos)
                if (drv->diskfile) {
                        drive_fill_bigbuf(drv, 0);
                }
+#ifdef FLOPPYBRIDGE
+               if (drv->bridge) {
+                       drive_fill_bigbuf(drv, 0);
+               }
+#endif
                drv->mfmpos %= drv->tracklen;
        }
        int didaccess = 0;
@@ -4235,6 +4560,15 @@ void DSKLEN (uae_u16 v, int hpos)
                drive *drv = &floppy[dr];
                if (selected & (1 << dr))
                        continue;
+#ifdef FLOPPYBRIDGE
+               if (drv->bridge) {
+                       if (dskdmaen == DSKDMA_WRITE) {
+                               // In write mode we allow a special version of 'turbo' to happen.  We only complete the DMA response when we have actually written to disk
+                               if (drv->bridge->canTurboWrite()) continue;
+                       }
+                       break;
+               }
+#endif
                if (drv->filetype != ADF_NORMAL && drv->filetype != ADF_KICK && drv->filetype != ADF_SKICK && drv->filetype != ADF_NORMAL_HEADER)
                        break;
        }
@@ -4244,12 +4578,12 @@ void DSKLEN (uae_u16 v, int hpos)
                int done = 0;
                for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) {
                        drive *drv = &floppy[dr];
-                       bool floppysupported = (drv->ddhd < 2) || (drv->ddhd > 1 && currprefs.floppyslots[dr].dfxtype == DRV_35_HD);
+                       bool floppysupported = (drv->ddhd < 2) || (drv->ddhd > 1 && currprefs.floppyslots[dr].dfxtype == DRV_35_HD) || (drv->bridge);
                        int pos, i;
 
                        if (drv->motoroff)
                                continue;
-                       if (!drv->useturbo && currprefs.floppy_speed > 0)
+                       if (!drv->useturbo && currprefs.floppy_speed > 0 && !drv->bridge)
                                continue;
                        if (selected & (1 << dr))
                                continue;
@@ -4292,6 +4626,26 @@ void DSKLEN (uae_u16 v, int hpos)
 
                        } else if (dskdmaen == DSKDMA_WRITE) { /* TURBO write */
 
+#ifdef FLOPPYBRIDGE
+                               if (drv->bridge) {
+                                       if (!drv->bridge->isWritePending()) {
+                                               for (i = 0; i < dsklength; i++) {
+                                                       uae_u16 w = chipmem_wget_indirect(dskpt + i * 2);
+                                                       drv->bigmfmbuf[pos >> 4] = w;
+                                                       drv->bridge->writeShortToBuffer(side, drv->cyl, w, drv->mfmpos);
+                                                       pos += 16;
+                                                       pos %= drv->tracklen;
+                                               }
+                                               drv->mfmpos = pos;
+                                               if (drv->bridge->isReadyToWrite()) {
+                                                       drv->bridge->commitWriteBuffer(side, drv->cyl);
+                                               }
+                                       } else
+                                               if (drv->bridge->isWriteComplete()) {
+                                                       done = 2;
+                                               }
+                               } else
+#endif
                                if (floppysupported) {
                                        for (i = 0; i < dsklength; i++) {
                                                uae_u16 w = chipmem_wget_indirect (dskpt + i * 2);
@@ -4449,6 +4803,178 @@ void DISK_free (void)
        }
 }
 
+static void floppybridge_read_track(drive *drv)
+{
+       int timeout;
+       FloppyDiskBridge *b = drv->bridge;
+       if (!b) {
+               return;
+       }
+       for (;;) {
+               if (!b->isDiskInDrive()) {
+                       break;
+               }
+               b->setMotorStatus(false, true);
+               b->gotoCylinder(drv->cyl, false);
+               timeout = 5000 / 10;
+               while (b->getCurrentCylinderNumber() != drv->cyl) {
+                       if (timeout-- < 0) {
+                               break;
+                       }
+                       sleep_millis(10);
+               }
+               while (!b->isReady()) {
+                       if (timeout-- < 0) {
+                               break;
+                       }
+                       sleep_millis(10);
+               }
+
+               if (!b->isDiskInDrive() || timeout < 0) {
+                       break;
+               }
+               int totalbits = FLOPPY_WRITE_LEN_NTSC * 8 * drv->ddhd;
+               int pos = 0;
+               uae_u16 *p = drv->bigmfmbuf;
+               uae_u16 w = 0;
+               timeout = 5000 / 10;
+               int max = b->maxMFMBitPosition();
+               while (totalbits > 0 && timeout > 0) {
+                       while (b->isMFMDataAvailable() && totalbits > 0) {
+                               uae_u8 bit = b->getMFMBit(pos);
+                               pos++;
+                               if (pos >= max) {
+                                       pos = 0;
+                               }
+                               w <<= 1;
+                               w |= bit;
+                               if ((pos & 15) == 0) {
+                                       *p++ = w;
+                               }
+                               totalbits--;
+                       }
+                       sleep_millis(10);
+                       timeout--;
+               }
+               break;
+       }
+       b->setMotorStatus(false, side);
+}
+
+static void floppybridge_init3(void)
+{
+       static bool checked;
+       if (checked) {
+               return;
+       }
+       checked = true;
+       if (FloppyBridgeAPI::isAvailable()) {
+               floppybridge_available = true;
+               FloppyBridgeAPI::getDriverList(bridgedriverinfo);
+       }
+}
+
+bool floppybridge_has(void)
+{
+       floppybridge_init3();
+       return floppybridge_available;
+}
+
+static void floppybridge_init2(struct uae_prefs *p)
+{
+       bool needbridge = false;
+       for (int i = 0; i < MAX_FLOPPY_DRIVES; i++) {
+               int type = p->floppyslots[i].dfxtype;
+               if (type == DRV_FB_A_35_DD || type == DRV_FB_A_35_HD || type == DRV_FB_B_35_DD || type == DRV_FB_B_35_HD) {
+                       needbridge = true;
+               }
+       }
+       if (!needbridge) {
+               for (int dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) {
+                       floppy[dr].bridge = NULL;
+                       if (bridges[dr]) {
+                               delete bridges[dr];
+                               bridges[dr] = NULL;
+                       }
+               }
+               return;
+       }
+       floppybridge_init3();
+       for (int dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) {
+               int type = p->floppyslots[dr].dfxtype;
+               if (type == DRV_FB_A_35_DD || type == DRV_FB_A_35_HD || type == DRV_FB_B_35_DD || type == DRV_FB_B_35_HD) {
+                       if (floppy[dr].bridge == NULL || type != bridge_type[dr]) {
+                               if (bridges[dr]) {
+                                       bridges[dr]->shutdown();
+                                       delete bridges[dr];
+                                       bridges[dr] = NULL;
+                               }
+                               floppy[dr].bridge = NULL;
+                               bridge_driver[dr] = NULL;
+                               bridge_type[dr] = type;
+                               FloppyBridgeAPI *bridge = NULL;
+                               bool configConfigured = true;
+                               if (p->floppyslots[dr].config[0]) {
+                                       char *c = ua(p->floppyslots[dr].config);
+                                       bridge = FloppyBridgeAPI::createDriverFromString(c);
+                                       xfree(c);
+                               }
+                               if (!bridge) {
+                                       configConfigured = false;
+                                       bridge = FloppyBridgeAPI::createDriver(1);
+                                       p->floppyslots[dr].config[0] = 0;
+                                       changed_prefs.floppyslots[dr].config[0] = 0;
+                               }
+                               if (bridge) {
+                                       bridge->setBridgeDensityMode(FloppyBridgeAPI::BridgeDensityMode::bdmAuto);
+                                       if (p->floppy_speed == 0) {
+                                               bridge->setBridgeMode(FloppyBridgeAPI::BridgeMode::bmTurboAmigaDOS);
+                                       } else {
+                                               bridge->setBridgeMode(FloppyBridgeAPI::BridgeMode::bmFast);
+                                       }
+                                       if (!configConfigured) {
+                                               bridge->setComPortAutoDetect(true);
+                                               bridge->setDriveCableSelection(type == DRV_FB_A_35_DD || type == DRV_FB_A_35_HD);  // on A
+                                       }
+                                       if (!bridge->initialise()) {
+                                               const char *errorMessage = bridge->getLastErrorMessage();
+                                               const char *name = bridge->getDriverInfo()->name;
+                                               TCHAR *terrorMessage = au(errorMessage);
+                                               TCHAR *tname = au(name);
+                                               TCHAR formattedMessage[512];
+                                               _stprintf(formattedMessage, _T("Floppy Disk Bridge Error\n\nUnable to replace DF%i: using %s\n\n%s.\n\nDrive DF%i: will be disabled and ignored."), dr, tname, terrorMessage, dr);
+                                               gui_message(formattedMessage);
+                                               xfree(tname);
+                                               xfree(terrorMessage);
+                                       } else {
+                                               char *config = NULL;
+                                               bridge->getConfigAsString(&config);
+                                               au_copy(p->floppyslots[dr].config, sizeof(p->floppyslots[dr].config) / sizeof(TCHAR), config);
+                                               _tcscpy(changed_prefs.floppyslots[dr].config, p->floppyslots[dr].config);
+                                               bridge_driver[dr] = bridge->getDriverInfo();
+                                       }
+                               }
+                               bridges[dr] = bridge;
+                               floppy[dr].bridge = bridge;
+                       }
+               } else {
+                       if (bridges[dr]) {
+                               bridges[dr]->shutdown();
+                               delete bridges[dr];
+                               bridges[dr] = NULL;
+                       }
+                       floppy[dr].bridge = NULL;
+                       bridge_driver[dr] = NULL;
+               }
+
+       }
+}
+
+void floppybridge_init(struct uae_prefs *p)
+{
+       floppybridge_init2(p);
+}
+
 void DISK_init (void)
 {
        for (int dr = MAX_FLOPPY_DRIVES - 1; dr >= 0; dr--) {
@@ -4458,6 +4984,7 @@ void DISK_init (void)
                if (!drive_insert (drv, &currprefs, dr, currprefs.floppyslots[dr].df, false, currprefs.floppyslots[dr].forcedwriteprotect))
                        disk_eject (dr);
        }
+       floppybridge_init2(&currprefs);
        if (disk_empty (0))
                write_log (_T("No disk in drive 0.\n"));
        amax_init ();
@@ -4491,7 +5018,7 @@ static void load_track (int num, int cyl, int side, int *sectable)
        drv->cyl = cyl;
        side = 0;
        drv->buffered_cyl = -1;
-       drive_fill_bigbuf (drv, 1);
+       drive_fill_bigbuf (drv, -1);
        decode_buffer (drv->bigmfmbuf, drv->cyl, 11, drv->ddhd, drv->filetype, &drvsec, sectable, 1);
        drv->cyl = oldcyl;
        side = oldside;
@@ -4632,7 +5159,37 @@ static void abrcheck(struct diskinfo *di)
        }
 }
 
-int DISK_examine_image (struct uae_prefs *p, int num, struct diskinfo *di, bool deepcheck)
+static void get_floppybridgeinfo(TCHAR *infotext, int num)
+{
+       if (!infotext) {
+               return;
+       }
+       TCHAR *p = infotext;
+       _tcscat(p, bridgeinfo.about);
+       p += _tcslen(p);
+       if (bridgeinfo.isUpdateAvailable) {
+               _stprintf(p, _T(" v%u.%u (v%u.%u) "), bridgeinfo.majorVersion, bridgeinfo.minorVersion, bridgeinfo.updateMajorVersion, bridgeinfo.updateMinorVersion);
+       } else {
+               _stprintf(p, _T(" v%u.%u "), bridgeinfo.majorVersion, bridgeinfo.minorVersion);
+       }
+       p += _tcslen(p);
+       _stprintf(p, _T("(%s)"), bridgeinfo.url);
+       _tcscat(p, _T("\r\n\r\n"));
+       p += _tcslen(p);
+       if (bridge_driver[num]) {
+               const FloppyDiskBridge::BridgeDriver *bd = bridge_driver[num];
+               TCHAR *name = au(bd->name);
+               TCHAR *man = au(bd->manufacturer);
+               TCHAR *url = au(bd->url);
+               _stprintf(p, _T("%s, %s (%s)\r\n"), name, man, url);
+               xfree(url);
+               xfree(man);
+               xfree(name);
+               p += _tcslen(p);
+       }
+}
+
+int DISK_examine_image(struct uae_prefs *p, int num, struct diskinfo *di, bool deepcheck, TCHAR *infotext)
 {
        int drvsec;
        int ret, i;
@@ -4642,27 +5199,38 @@ int DISK_examine_image (struct uae_prefs *p, int num, struct diskinfo *di, bool
        int sectable[MAX_SECTORS];
        int oldcyl, oldside;
        uae_u32 v = 0;
+       bool fb = DISK_isfloppybridge(p, num);
 
+       if (infotext) {
+               infotext[0] = 0;
+       }
        ret = 0;
        memset (di, 0, sizeof (struct diskinfo));
+
+       if (fb) {
+               get_floppybridgeinfo(infotext, num);
+       }
+
        di->unreadable = true;
        oldcyl = drv->cyl;
        oldside = side;
-       drv->cyl = 0;
-       side = 0;
-       if (!drive_insert (drv, p, num, p->floppyslots[num].df, true, true) || !drv->diskfile) {
+       if (!drive_insert (drv, p, num, p->floppyslots[num].df, true, true) || (!drv->diskfile && !drv->bridge)) {
                drv->cyl = oldcyl;
                side = oldside;
                return 1;
        }
-       di->imagecrc32 = zfile_crc32 (drv->diskfile);
+       if (drv->diskfile) {
+               di->imagecrc32 = zfile_crc32(drv->diskfile);
+               di->image_crc_value = true;
+       }
        di->unreadable = false;
-       decode_buffer (drv->bigmfmbuf, drv->cyl, 11, drv->ddhd, drv->filetype, &drvsec, sectable, 1);
+       decode_buffer(drv->bigmfmbuf, drv->cyl, 11, drv->ddhd, drv->filetype, &drvsec, sectable, 1);
        di->hd = drv->ddhd == 2;
        drv->cyl = oldcyl;
        side = oldside;
        if (sectable[0] == 0 || sectable[1] == 0) {
                ret = 2;
+               di->unreadable = true;
                goto end2;
        }
        crc = crc2 = 0;
@@ -4713,7 +5281,7 @@ int DISK_examine_image (struct uae_prefs *p, int num, struct diskinfo *di, bool
                di->bootblocktype = 2;
        }
 end:
-       load_track (num, 40, 0, sectable);
+       load_track(num, 40, 0, sectable);
        if (sectable[0]) {
                if (!disk_checksum (writebuffer, NULL) &&
                        writebuffer[0] == 0 && writebuffer[1] == 0 && writebuffer[2] == 0 && writebuffer[3] == 2 &&
@@ -4734,6 +5302,7 @@ end2:
                drv->dskchange_time = wasdelayed;
                disk_insert (num, drv->newname);
        }
+       load_track(num, oldcyl, oldside, sectable);
        return ret;
 }
 
@@ -4927,9 +5496,9 @@ uae_u8 *save_disk (int num, int *len, uae_u8 *dstptr, bool usepath)
        else
                dstbak = dst = xmalloc (uae_u8, 2 + 1 + 1 + 1 + 1 + 4 + 4 + MAX_DPATH + 2 + 2 + 4 + 2 * MAX_DPATH);
        save_u32 (drv->drive_id);           /* drive type ID */
-       save_u8 ((drv->motoroff ? 0 : 1) | ((disabled & (1 << num)) ? 2 : 0) | (drv->idbit ? 4 : 0) | (drv->dskchange ? 8 : 0) | (side ? 16 : 0) | (drv->wrprot ? 32 : 0));
+       save_u8 ((drv->motoroff ? 0 : 1) | ((disabled & (1 << num)) ? 2 : 0) | (drv->idbit ? 4 : 0) | (drive_diskchange(drv) ? 8 : 0) | (side ? 16 : 0) | (drv->wrprot ? 32 : 0));
        save_u8 (drv->cyl);                             /* cylinder */
-       save_u8 (drv->dskready);            /* dskready */
+       save_u8 (drive_diskready(drv)); /* dskready */
        save_u8 (drv->drive_id_scnt);   /* id mode position */
        save_u32 (drv->mfmpos);                 /* disk position */
        save_u32 (getadfcrc (drv));         /* CRC of disk image */
@@ -5277,7 +5846,7 @@ bool disk_reserved_getinfo(int num, struct floppy_reserved *fr)
                fr->drive_cyls = currprefs.floppyslots[idx].dfxtype == DRV_PC_525_ONLY_40 ? 40 : 80;
                fr->secs = drv->num_secs;
                fr->heads = drv->num_heads;
-               fr->disk_changed = drv->dskchange || fr->img == NULL;
+               fr->disk_changed = drive_diskchange(drv) || fr->img == NULL;
                if (currprefs.floppyslots[idx].dfxtype == DRV_PC_35_ONLY_80) {
                        if (drv->num_secs > 14)
                                fr->rate = FLOPPY_RATE_500K; // 1.2M/1.4M
diff --git a/floppybridge/floppybridge_abstract.h b/floppybridge/floppybridge_abstract.h
new file mode 100644 (file)
index 0000000..4723e5e
--- /dev/null
@@ -0,0 +1,182 @@
+/* floppybridge_abstract
+*
+* Copyright (C) 2021 Robert Smith (@RobSmithDev)
+* https://amiga.robsmithdev.co.uk
+*
+* This library defines a standard interface for connecting physical disk drives to *UAE
+*
+* Derived classes must be implemented so they are unlikely to cause a delay in any function
+* as doing so would cause audio and mouse cursors to stutter
+* 
+* This is free and unencumbered released into the public domain.
+* See the file COPYING for more details, or visit <http://unlicense.org>.
+*
+*/
+
+/*
+* This file, along with currently active and supported interfaces
+* are maintained from by GitHub repo at
+* https://github.com/RobSmithDev/FloppyDriveBridge
+*/
+
+#pragma once
+
+#include <functional>
+
+#ifdef _WIN32
+#include <tchar.h>
+#else
+#ifndef TCHAR
+#ifdef _UNICODE
+#define TCHAR wchar_t
+#define _T(x) L ##x
+#else
+#define TCHAR char
+#define _T(x) x
+#endif
+#endif
+#endif
+
+
+
+class FloppyDiskBridge {
+public:
+
+       // Driver information
+       struct BridgeDriver {
+               // Details about the driver
+               const char* name;
+               const char* url;
+               const char* manufacturer;
+               const char* driverAuthor;
+
+               // Which options in configuration it can support, aside from the standard ones
+               const unsigned int configOptions;
+       };
+
+       // Definition of the type of drive
+       enum class DriveTypeID : unsigned char { dti35DD = 0, dti35HD = 1, dti5255SD = 2 };
+
+       FloppyDiskBridge() {};
+       // This is just to force this being virtual
+       virtual ~FloppyDiskBridge() {};
+
+       // Call to start the system up.  Return false if it fails
+       virtual bool initialise() = 0;
+
+       // This is called prior to closing down, but shoudl reverse initialise
+       virtual void shutdown() {};
+
+       // Returns the name of interface.  This pointer should remain valid *after* the class is destroyed so should be static
+       virtual const BridgeDriver* getDriverInfo()  = 0;
+
+       // Return the 'bit cell' time in uSec.  Standard DD Amiga disks this would be 2uS, HD disks would be 1us I guess, but mainly used for =4 for SD I think
+       virtual unsigned char getBitSpeed() { return 2; };
+
+       // Return the type of disk connected.  This is used to tell WinUAE if we're DD or HD.  This must return INSTANTLY
+       virtual DriveTypeID getDriveTypeID()  = 0;
+
+       // Call to get the last error message.  If the board initialised this may return a compatability warning instead
+       virtual const char* getLastErrorMessage() { return NULL; };
+
+       /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+
+
+       // Reset the drive.  This should reset it to the state it would be at powerup, ie: motor switched off etc.  The current cylinder number can be 'unknown' at this point
+       virtual bool resetDrive(int trackNumber)  = 0;
+
+
+
+
+       /////////////////////// Head movement Controls //////////////////////////////////////////
+       // Return TRUE if the drive is currently on cylinder 0
+       virtual bool isAtCylinder0()  = 0;
+
+       // Return the number of cylinders the drive supports.  Eg: 80 or 82 (or 40)
+       virtual unsigned char getMaxCylinder()  = 0;
+
+       // Seek to a specific cylinder
+       virtual void gotoCylinder(int cylinderNumber, bool side)  = 0;
+
+       // Handle the drive stepping to track -1 - this is used to 'no-click' detect the disk
+       virtual void handleNoClickStep(bool side) = 0;
+
+       // Return the current cylinder number we're on
+       virtual unsigned char getCurrentCylinderNumber()  = 0;
+
+
+
+       /////////////////////// Drive Motor Controls /////////////////////////////////////////////
+       // Return true if the motor is spinning, but not necessarly up to speed
+       virtual bool isMotorRunning()  = 0;
+
+       // Turn on and off the motor
+       virtual void setMotorStatus(bool turnOn, bool side)  = 0;
+
+       // Returns TRUE if the drive is ready (ie: the motor has spun up to speed to speed)
+       virtual bool isReady()  = 0;
+
+
+
+       /////////////////////// Disk Detection ///////////////////////////////////////////////////
+       // Return TRUE if there is a disk in the drive.  This is usually called after gotoCylinder
+       virtual bool isDiskInDrive()  = 0;
+
+       // Check if the disk has changed.  Basically returns FALSE if theres no disk in the drive
+       virtual bool hasDiskChanged()  = 0;
+
+
+
+       /////////////////////// Reading Data /////////////////////////////////////////////////////
+       // Return TRUE if we're at the INDEX marker/sensor.  mfmPositionBits is in BITS
+       virtual bool isMFMPositionAtIndex(int mfmPositionBits)  = 0;
+
+       // Returns TRUE if data is ready and available
+       virtual bool isMFMDataAvailable() = 0;
+
+       // This returns a single MFM bit at the position provided
+       virtual bool getMFMBit(const int mfmPositionBits)  = 0;
+
+       // This asks the time taken to read the bit at mfmPositionBits.  1000=100%, <1000 data is read faster, >1000 data is read slower.
+       // This number is used in a loop (scaled) starting with a number, and decrementing by this number.
+       // Each loop a single bit is read.  So the smaller the number, the more loops that occur, and the more bits that are read
+       virtual int getMFMSpeed(const int mfmPositionBits)  = 0;
+
+       // This is called in both modes.  It is called when WinUAE detects a full revolution of data has been read.  This could allow you to switch to a different recording of the same cylinder if needed.
+       virtual void mfmSwitchBuffer(bool side)  = 0;
+
+       // Quick confirmation from UAE that we're actually on the same side
+       virtual void setSurface(bool side)  = 0;
+
+       // Return the maximum size of bits available in this revolution.  This is the maximimum passed to getMFMBit
+       virtual int maxMFMBitPosition()  = 0;
+
+       /////////////////////// Writing Data /////////////////////////////////////////////////////
+
+       // Submits a single WORD of data received during a DMA transfer to the disk buffer.  This needs to be saved.  It is usually flushed when commitWriteBuffer is called
+       // You should reset this buffer if side or track changes, mfmPosition is provided purely for any index sync you may wish to do
+       virtual void writeShortToBuffer(bool side, unsigned int track, unsigned short mfmData, int mfmPosition)  = 0;
+
+       // Return TRUE if the currently insrted disk is write protected
+       virtual bool isWriteProtected()  = 0;
+
+       // Requests that any data received via writeShortToBuffer be saved to disk. The side and track should match against what you have been collected
+       // and the buffer should be reset upon completion.  You should return the new tracklength (maxMFMBitPosition) with optional padding if needed
+       virtual unsigned int commitWriteBuffer(bool side, unsigned int track)  = 0;
+
+       // Returns TRUE if commitWriteBuffer has been called but not written to disk yet
+       virtual bool isWritePending() = 0;
+
+       // Returns TRUE if a write is no longer pending.  This should only return TRUE the first time, and then should reset
+       virtual bool isWriteComplete() = 0;
+
+       // Set to TRUE if turbo writing is allowed (this is a sneaky DMA bypass trick)
+       virtual bool canTurboWrite() = 0;
+
+       // Return TRUE if there is data ready to be committed to disk
+       virtual bool isReadyToWrite() = 0;
+};
+
+
diff --git a/floppybridge/floppybridge_lib.cpp b/floppybridge/floppybridge_lib.cpp
new file mode 100644 (file)
index 0000000..4771661
--- /dev/null
@@ -0,0 +1,629 @@
+/* floppybridge_lib
+*
+* Copyright (C) 2021 Robert Smith (@RobSmithDev)
+* https://amiga.robsmithdev.co.uk
+*
+* This class connects to the external FloppyBridge DLL library rather than
+* having all the code compiled in. That library is maintained at
+* https://amiga.robsmithdev.co.uk/winuae
+*
+* This is free and unencumbered released into the public domain
+* But please don't remove the above information
+*
+* For more details visit <http://unlicense.org>.
+*
+*/
+
+#include "floppybridge_lib.h"
+#include <string>
+#include <codecvt>
+#include <locale>
+#include <algorithm>
+
+
+// Used by BRIDGE_About
+struct BridgeAbout {
+       const char* about;
+       const char* url;
+       unsigned int majorVersion, minorVersion;
+       unsigned int isBeta;
+       unsigned int isUpdateAvailable;
+       unsigned int updateMajorVersion, updateMinorVersion;
+};
+
+#ifdef _WIN32
+#include <Windows.h>
+#define CALLING_CONVENSION _cdecl
+#define GETFUNC GetProcAddress
+HMODULE WIN32_LoadLibrary(const TCHAR *name);
+#else
+#define CALLING_CONVENSION
+#define GETFUNC dlsym
+#endif
+
+#ifdef WIN64
+#define MODULENAME _T("FloppyBridge_x64.dll")
+#else
+#ifdef _WIN32
+#define MODULENAME _T("FloppyBridge.dll")
+#else
+#define MODULENAME "FloppyBridge.so"
+#endif
+#endif
+
+#ifdef _WIN32
+HMODULE hBridgeDLLHandle = 0;
+#else
+void* hBridgeDLLHandle = nullptr;
+#endif
+
+
+
+// Bridge library function definitions
+typedef void                    (CALLING_CONVENSION* _BRIDGE_About)(BridgeAbout** output);
+typedef unsigned int    (CALLING_CONVENSION* _BRIDGE_NumDrivers)(void);
+typedef bool                    (CALLING_CONVENSION* _BRIDGE_GetDriverInfo)(unsigned int driverIndex, FloppyDiskBridge::BridgeDriver** driverInformation);
+
+typedef bool                    (CALLING_CONVENSION* _BRIDGE_EnumComports)(char* output, unsigned int* bufferSize);
+
+typedef bool                    (CALLING_CONVENSION* _BRIDGE_CreateDriver)(unsigned int driverIndex, BridgeDriverHandle* bridgeDriverHandle);
+typedef bool                    (CALLING_CONVENSION* _BRIDGE_CreateDriverFromConfigString)(char* config, BridgeDriverHandle* bridgeDriverHandle);
+typedef bool                    (CALLING_CONVENSION* _BRIDGE_Close)(BridgeDriverHandle bridgeDriverHandle);
+typedef bool                    (CALLING_CONVENSION* _BRIDGE_Open)(BridgeDriverHandle bridgeDriverHandle, char** errorMessage);
+typedef bool                    (CALLING_CONVENSION* _BRIDGE_GetDriverIndex)(BridgeDriverHandle bridgeDriverHandle, unsigned int* driverIndex);
+typedef bool                    (CALLING_CONVENSION* _BRIDGE_FreeDriver)(BridgeDriverHandle bridgeDriverHandle);
+
+typedef bool                    (CALLING_CONVENSION* _BRIDGE_GetConfigString)(BridgeDriverHandle bridgeDriverHandle, char** config);
+typedef bool                    (CALLING_CONVENSION* _BRIDGE_SetConfigFromString)(BridgeDriverHandle bridgeDriverHandle, char* config);
+typedef bool                    (CALLING_CONVENSION* _BRIDGE_DriverGetAutoCache)(BridgeDriverHandle bridgeDriverHandle, bool* isAutoCacheMode);
+typedef bool                    (CALLING_CONVENSION* _BRIDGE_DriverSetAutoCache)(BridgeDriverHandle bridgeDriverHandle, bool isAutoCacheMode);
+typedef bool                    (CALLING_CONVENSION* _BRIDGE_DriverGetMode)(BridgeDriverHandle bridgeDriverHandle, FloppyBridgeAPI::BridgeMode* bridgeMode);
+typedef bool                    (CALLING_CONVENSION* _BRIDGE_DriverSetMode)(BridgeDriverHandle bridgeDriverHandle, FloppyBridgeAPI::BridgeMode bridgeMode);
+typedef bool                    (CALLING_CONVENSION* _BRIDGE_DriverGetDensityMode)(BridgeDriverHandle bridgeDriverHandle, FloppyBridgeAPI::BridgeDensityMode* densityMode);
+typedef bool                    (CALLING_CONVENSION* _BRIDGE_DriverSetDensityMode)(BridgeDriverHandle bridgeDriverHandle, FloppyBridgeAPI::BridgeDensityMode densityMode);
+typedef bool                    (CALLING_CONVENSION* _BRIDGE_DriverGetCurrentComPort)(BridgeDriverHandle bridgeDriverHandle, char** comPort);
+typedef bool                    (CALLING_CONVENSION* _BRIDGE_DriverSetCurrentComPort)(BridgeDriverHandle bridgeDriverHandle, char* comPort);
+typedef bool                    (CALLING_CONVENSION* _BRIDGE_DriverGetAutoDetectComPort)(BridgeDriverHandle bridgeDriverHandle, bool* autoDetectComPort);
+typedef bool                    (CALLING_CONVENSION* _BRIDGE_DriverSetAutoDetectComPort)(BridgeDriverHandle bridgeDriverHandle, bool autoDetectComPort);
+typedef bool                    (CALLING_CONVENSION* _BRIDGE_DriverGetCable)(BridgeDriverHandle bridgeDriverHandle, bool* isOnB);
+typedef bool                    (CALLING_CONVENSION* _BRIDGE_DriverSetCable)(BridgeDriverHandle bridgeDriverHandle, bool isOnB);
+typedef unsigned char   (CALLING_CONVENSION* _DRIVER_getBitSpeed)(BridgeDriverHandle bridgeDriverHandle);
+typedef FloppyDiskBridge::DriveTypeID (CALLING_CONVENSION* _DRIVER_getDriveTypeID)(BridgeDriverHandle bridgeDriverHandle);
+typedef bool                    (CALLING_CONVENSION* _DRIVER_resetDrive)(BridgeDriverHandle bridgeDriverHandle, int trackNumber);
+typedef bool                    (CALLING_CONVENSION* _DRIVER_isAtCylinder0)(BridgeDriverHandle bridgeDriverHandle);
+typedef unsigned char   (CALLING_CONVENSION* _DRIVER_getMaxCylinder)(BridgeDriverHandle bridgeDriverHandle);
+typedef void                    (CALLING_CONVENSION* _DRIVER_gotoCylinder)(BridgeDriverHandle bridgeDriverHandle, int cylinderNumber, bool side);
+typedef void                    (CALLING_CONVENSION* _DRIVER_handleNoClickStep)(BridgeDriverHandle bridgeDriverHandle, bool side);
+typedef unsigned char   (CALLING_CONVENSION* _DRIVER_getCurrentCylinderNumber)(BridgeDriverHandle bridgeDriverHandle);
+typedef bool                    (CALLING_CONVENSION* _DRIVER_isMotorRunning)(BridgeDriverHandle bridgeDriverHandle);
+typedef void                    (CALLING_CONVENSION* _DRIVER_setMotorStatus)(BridgeDriverHandle bridgeDriverHandle, bool turnOn, bool side);
+typedef bool                    (CALLING_CONVENSION* _DRIVER_isReady)(BridgeDriverHandle bridgeDriverHandle);
+typedef bool                    (CALLING_CONVENSION* _DRIVER_isDiskInDrive)(BridgeDriverHandle bridgeDriverHandle);
+typedef bool                    (CALLING_CONVENSION* _DRIVER_hasDiskChanged)(BridgeDriverHandle bridgeDriverHandle);
+typedef bool                    (CALLING_CONVENSION* _DRIVER_isMFMPositionAtIndex)(BridgeDriverHandle bridgeDriverHandle, int mfmPositionBits);
+typedef bool                    (CALLING_CONVENSION* _DRIVER_isMFMDataAvailable)(BridgeDriverHandle bridgeDriverHandle);
+typedef bool                    (CALLING_CONVENSION* _DRIVER_getMFMBit)(BridgeDriverHandle bridgeDriverHandle, const int mfmPositionBits);
+typedef int                     (CALLING_CONVENSION* _DRIVER_getMFMSpeed)(BridgeDriverHandle bridgeDriverHandle, const int mfmPositionBits);
+typedef void                    (CALLING_CONVENSION* _DRIVER_mfmSwitchBuffer)(BridgeDriverHandle bridgeDriverHandle, bool side);
+typedef void                    (CALLING_CONVENSION* _DRIVER_setSurface)(BridgeDriverHandle bridgeDriverHandle, bool side);
+typedef int                     (CALLING_CONVENSION* _DRIVER_maxMFMBitPosition)(BridgeDriverHandle bridgeDriverHandle);
+typedef void                    (CALLING_CONVENSION* _DRIVER_writeShortToBuffer)(BridgeDriverHandle bridgeDriverHandle, bool side, unsigned int track, unsigned short mfmData, int mfmPosition);
+typedef bool                    (CALLING_CONVENSION* _DRIVER_isWriteProtected)(BridgeDriverHandle bridgeDriverHandle);
+typedef unsigned int    (CALLING_CONVENSION* _DRIVER_commitWriteBuffer)(BridgeDriverHandle bridgeDriverHandle, bool side, unsigned int track);
+typedef bool                    (CALLING_CONVENSION* _DRIVER_isWritePending)(BridgeDriverHandle bridgeDriverHandle);
+typedef bool                    (CALLING_CONVENSION* _DRIVER_isWriteComplete)(BridgeDriverHandle bridgeDriverHandle);
+typedef bool                    (CALLING_CONVENSION* _DRIVER_canTurboWrite)(BridgeDriverHandle bridgeDriverHandle);
+typedef bool                    (CALLING_CONVENSION* _DRIVER_isReadyToWrite)(BridgeDriverHandle bridgeDriverHandle);
+
+
+// Library function pointers
+_BRIDGE_About  BRIDGE_About = nullptr;
+_BRIDGE_NumDrivers     BRIDGE_NumDrivers = nullptr;
+_BRIDGE_EnumComports   BRIDGE_EnumComports = nullptr;
+_BRIDGE_GetDriverInfo  BRIDGE_GetDriverInfo = nullptr;
+_BRIDGE_CreateDriver   BRIDGE_CreateDriver = nullptr;
+_BRIDGE_Close  BRIDGE_Close = nullptr;
+_BRIDGE_Open   BRIDGE_Open = nullptr;
+_BRIDGE_GetDriverIndex BRIDGE_GetDriverIndex = nullptr;
+_BRIDGE_FreeDriver     BRIDGE_FreeDriver = nullptr;
+_BRIDGE_DriverGetMode  BRIDGE_DriverGetMode = nullptr;
+_BRIDGE_DriverSetMode  BRIDGE_DriverSetMode = nullptr;
+_BRIDGE_DriverGetDensityMode   BRIDGE_DriverGetDensityMode = nullptr;
+_BRIDGE_DriverSetDensityMode   BRIDGE_DriverSetDensityMode = nullptr;
+_BRIDGE_DriverGetCurrentComPort        BRIDGE_DriverGetCurrentComPort = nullptr;
+_BRIDGE_DriverSetCurrentComPort        BRIDGE_DriverSetCurrentComPort = nullptr;
+_BRIDGE_DriverGetAutoDetectComPort     BRIDGE_DriverGetAutoDetectComPort = nullptr;
+_BRIDGE_DriverSetAutoDetectComPort     BRIDGE_DriverSetAutoDetectComPort = nullptr;
+_BRIDGE_DriverGetCable BRIDGE_DriverGetCable = nullptr;
+_BRIDGE_DriverSetCable BRIDGE_DriverSetCable = nullptr;
+_BRIDGE_DriverGetAutoCache BRIDGE_DriverGetAutoCache = nullptr;
+_BRIDGE_DriverSetAutoCache BRIDGE_DriverSetAutoCache = nullptr;
+_BRIDGE_GetConfigString BRIDGE_GetConfigString = nullptr;
+_BRIDGE_SetConfigFromString BRIDGE_SetConfigFromString = nullptr;
+_BRIDGE_CreateDriverFromConfigString BRIDGE_CreateDriverFromConfigString = nullptr;
+_DRIVER_getBitSpeed    DRIVER_getBitSpeed = nullptr;
+_DRIVER_getDriveTypeID DRIVER_getDriveTypeID = nullptr;
+_DRIVER_resetDrive     DRIVER_resetDrive = nullptr;
+_DRIVER_isAtCylinder0  DRIVER_isAtCylinder0 = nullptr;
+_DRIVER_getMaxCylinder DRIVER_getMaxCylinder = nullptr;
+_DRIVER_gotoCylinder   DRIVER_gotoCylinder = nullptr;
+_DRIVER_handleNoClickStep      DRIVER_handleNoClickStep = nullptr;
+_DRIVER_getCurrentCylinderNumber       DRIVER_getCurrentCylinderNumber = nullptr;
+_DRIVER_isMotorRunning DRIVER_isMotorRunning = nullptr;
+_DRIVER_setMotorStatus DRIVER_setMotorStatus = nullptr;
+_DRIVER_isReady        DRIVER_isReady = nullptr;
+_DRIVER_isDiskInDrive  DRIVER_isDiskInDrive = nullptr;
+_DRIVER_hasDiskChanged DRIVER_hasDiskChanged = nullptr;
+_DRIVER_isMFMPositionAtIndex   DRIVER_isMFMPositionAtIndex = nullptr;
+_DRIVER_isMFMDataAvailable     DRIVER_isMFMDataAvailable = nullptr;
+_DRIVER_getMFMBit      DRIVER_getMFMBit = nullptr;
+_DRIVER_getMFMSpeed    DRIVER_getMFMSpeed = nullptr;
+_DRIVER_mfmSwitchBuffer        DRIVER_mfmSwitchBuffer = nullptr;
+_DRIVER_setSurface     DRIVER_setSurface = nullptr;
+_DRIVER_maxMFMBitPosition      DRIVER_maxMFMBitPosition = nullptr;
+_DRIVER_writeShortToBuffer     DRIVER_writeShortToBuffer = nullptr;
+_DRIVER_isWriteProtected       DRIVER_isWriteProtected = nullptr;
+_DRIVER_commitWriteBuffer      DRIVER_commitWriteBuffer = nullptr;
+_DRIVER_isWritePending DRIVER_isWritePending = nullptr;
+_DRIVER_isWriteComplete        DRIVER_isWriteComplete = nullptr;
+_DRIVER_canTurboWrite  DRIVER_canTurboWrite = nullptr;
+_DRIVER_isReadyToWrite DRIVER_isReadyToWrite = nullptr;
+
+// Sets up the bridge.  We assume it will persist while the application is open.
+void prepareBridge() {
+       if (hBridgeDLLHandle) return;
+
+#ifdef WIN32
+       hBridgeDLLHandle = WIN32_LoadLibrary(MODULENAME);
+#else
+       hBridgeDLLHandle = dlopen(MODULENAME, RTLD_NOW);
+#endif
+
+       // Did it open?
+       if (!hBridgeDLLHandle) return;
+
+       BRIDGE_About = (_BRIDGE_About)GETFUNC(hBridgeDLLHandle, "BRIDGE_About");
+       BRIDGE_NumDrivers = (_BRIDGE_NumDrivers)GETFUNC(hBridgeDLLHandle, "BRIDGE_NumDrivers");
+       BRIDGE_EnumComports = (_BRIDGE_EnumComports)GETFUNC(hBridgeDLLHandle, "BRIDGE_EnumComports");
+       BRIDGE_GetDriverInfo = (_BRIDGE_GetDriverInfo)GETFUNC(hBridgeDLLHandle, "BRIDGE_GetDriverInfo");
+       BRIDGE_CreateDriver = (_BRIDGE_CreateDriver)GETFUNC(hBridgeDLLHandle, "BRIDGE_CreateDriver");
+       BRIDGE_GetDriverIndex = (_BRIDGE_GetDriverIndex)GETFUNC(hBridgeDLLHandle, "BRIDGE_GetDriverIndex");     
+       BRIDGE_Close = (_BRIDGE_Close)GETFUNC(hBridgeDLLHandle, "BRIDGE_Close");
+       BRIDGE_Open = (_BRIDGE_Open)GETFUNC(hBridgeDLLHandle, "BRIDGE_Open");
+       BRIDGE_FreeDriver = (_BRIDGE_FreeDriver)GETFUNC(hBridgeDLLHandle, "BRIDGE_FreeDriver");
+       BRIDGE_DriverGetAutoCache = (_BRIDGE_DriverGetAutoCache)GETFUNC(hBridgeDLLHandle, "BRIDGE_DriverGetAutoCache");
+       BRIDGE_DriverSetAutoCache = (_BRIDGE_DriverSetAutoCache)GETFUNC(hBridgeDLLHandle, "BRIDGE_DriverSetAutoCache");
+       BRIDGE_GetConfigString = (_BRIDGE_GetConfigString)GETFUNC(hBridgeDLLHandle, "BRIDGE_GetConfigString");
+       BRIDGE_SetConfigFromString = (_BRIDGE_SetConfigFromString)GETFUNC(hBridgeDLLHandle, "BRIDGE_SetConfigFromString");
+       BRIDGE_CreateDriverFromConfigString = (_BRIDGE_CreateDriverFromConfigString)GETFUNC(hBridgeDLLHandle, "BRIDGE_CreateDriverFromConfigString");
+       BRIDGE_DriverGetMode = (_BRIDGE_DriverGetMode)GETFUNC(hBridgeDLLHandle, "BRIDGE_DriverGetMode");
+       BRIDGE_DriverSetMode = (_BRIDGE_DriverSetMode)GETFUNC(hBridgeDLLHandle, "BRIDGE_DriverSetMode");
+       BRIDGE_DriverGetDensityMode = (_BRIDGE_DriverGetDensityMode)GETFUNC(hBridgeDLLHandle, "BRIDGE_DriverGetDensityMode");
+       BRIDGE_DriverSetDensityMode = (_BRIDGE_DriverSetDensityMode)GETFUNC(hBridgeDLLHandle, "BRIDGE_DriverSetDensityMode");
+       BRIDGE_DriverGetCurrentComPort = (_BRIDGE_DriverGetCurrentComPort)GETFUNC(hBridgeDLLHandle, "BRIDGE_DriverGetCurrentComPort");
+       BRIDGE_DriverSetCurrentComPort = (_BRIDGE_DriverSetCurrentComPort)GETFUNC(hBridgeDLLHandle, "BRIDGE_DriverSetCurrentComPort");
+       BRIDGE_DriverGetAutoDetectComPort = (_BRIDGE_DriverGetAutoDetectComPort)GETFUNC(hBridgeDLLHandle, "BRIDGE_DriverGetAutoDetectComPort");
+       BRIDGE_DriverSetAutoDetectComPort = (_BRIDGE_DriverSetAutoDetectComPort)GETFUNC(hBridgeDLLHandle, "BRIDGE_DriverSetAutoDetectComPort");
+       BRIDGE_DriverGetCable = (_BRIDGE_DriverGetCable)GETFUNC(hBridgeDLLHandle, "BRIDGE_DriverGetCable");
+       BRIDGE_DriverSetCable = (_BRIDGE_DriverSetCable)GETFUNC(hBridgeDLLHandle, "BRIDGE_DriverSetCable");
+       DRIVER_getBitSpeed = (_DRIVER_getBitSpeed)GETFUNC(hBridgeDLLHandle, "DRIVER_getBitSpeed");
+       DRIVER_getDriveTypeID = (_DRIVER_getDriveTypeID)GETFUNC(hBridgeDLLHandle, "DRIVER_getDriveTypeID");
+       DRIVER_resetDrive = (_DRIVER_resetDrive)GETFUNC(hBridgeDLLHandle, "DRIVER_resetDrive");
+       DRIVER_isAtCylinder0 = (_DRIVER_isAtCylinder0)GETFUNC(hBridgeDLLHandle, "DRIVER_isAtCylinder0");
+       DRIVER_getMaxCylinder = (_DRIVER_getMaxCylinder)GETFUNC(hBridgeDLLHandle, "DRIVER_getMaxCylinder");
+       DRIVER_gotoCylinder = (_DRIVER_gotoCylinder)GETFUNC(hBridgeDLLHandle, "DRIVER_gotoCylinder");
+       DRIVER_handleNoClickStep = (_DRIVER_handleNoClickStep)GETFUNC(hBridgeDLLHandle, "DRIVER_handleNoClickStep");
+       DRIVER_getCurrentCylinderNumber = (_DRIVER_getCurrentCylinderNumber)GETFUNC(hBridgeDLLHandle, "DRIVER_getCurrentCylinderNumber");
+       DRIVER_isMotorRunning = (_DRIVER_isMotorRunning)GETFUNC(hBridgeDLLHandle, "DRIVER_isMotorRunning");
+       DRIVER_setMotorStatus = (_DRIVER_setMotorStatus)GETFUNC(hBridgeDLLHandle, "DRIVER_setMotorStatus");
+       DRIVER_isReady = (_DRIVER_isReady)GETFUNC(hBridgeDLLHandle, "DRIVER_isReady");
+       DRIVER_isDiskInDrive = (_DRIVER_isDiskInDrive)GETFUNC(hBridgeDLLHandle, "DRIVER_isDiskInDrive");
+       DRIVER_hasDiskChanged = (_DRIVER_hasDiskChanged)GETFUNC(hBridgeDLLHandle, "DRIVER_hasDiskChanged");
+       DRIVER_isMFMPositionAtIndex = (_DRIVER_isMFMPositionAtIndex)GETFUNC(hBridgeDLLHandle, "DRIVER_isMFMPositionAtIndex");
+       DRIVER_isMFMDataAvailable = (_DRIVER_isMFMDataAvailable)GETFUNC(hBridgeDLLHandle, "DRIVER_isMFMDataAvailable");
+       DRIVER_getMFMBit = (_DRIVER_getMFMBit)GETFUNC(hBridgeDLLHandle, "DRIVER_getMFMBit");
+       DRIVER_getMFMSpeed = (_DRIVER_getMFMSpeed)GETFUNC(hBridgeDLLHandle, "DRIVER_getMFMSpeed");
+       DRIVER_mfmSwitchBuffer = (_DRIVER_mfmSwitchBuffer)GETFUNC(hBridgeDLLHandle, "DRIVER_mfmSwitchBuffer");
+       DRIVER_setSurface = (_DRIVER_setSurface)GETFUNC(hBridgeDLLHandle, "DRIVER_setSurface");
+       DRIVER_maxMFMBitPosition = (_DRIVER_maxMFMBitPosition)GETFUNC(hBridgeDLLHandle, "DRIVER_maxMFMBitPosition");
+       DRIVER_writeShortToBuffer = (_DRIVER_writeShortToBuffer)GETFUNC(hBridgeDLLHandle, "DRIVER_writeShortToBuffer");
+       DRIVER_isWriteProtected = (_DRIVER_isWriteProtected)GETFUNC(hBridgeDLLHandle, "DRIVER_isWriteProtected");
+       DRIVER_commitWriteBuffer = (_DRIVER_commitWriteBuffer)GETFUNC(hBridgeDLLHandle, "DRIVER_commitWriteBuffer");
+       DRIVER_isWritePending = (_DRIVER_isWritePending)GETFUNC(hBridgeDLLHandle, "DRIVER_isWritePending");
+       DRIVER_isWriteComplete = (_DRIVER_isWriteComplete)GETFUNC(hBridgeDLLHandle, "DRIVER_isWriteComplete");
+       DRIVER_canTurboWrite = (_DRIVER_canTurboWrite)GETFUNC(hBridgeDLLHandle, "DRIVER_canTurboWrite");
+       DRIVER_isReadyToWrite = (_DRIVER_isReadyToWrite)GETFUNC(hBridgeDLLHandle, "DRIVER_isReadyToWrite");
+
+       // Test a few
+       if ((!BRIDGE_About) || (!BRIDGE_NumDrivers)) {
+#ifdef WIN32
+               if (hBridgeDLLHandle) FreeLibrary(hBridgeDLLHandle);
+               hBridgeDLLHandle = 0;
+#else
+               if (hBridgeDLLHandle) dlclose(hBridgeDLLHandle);
+               hBridgeDLLHandle = nullptr;
+#endif
+       }
+}
+
+
+// character conversions
+using convert_t = std::codecvt_utf8<wchar_t>;
+static std::wstring_convert<convert_t, wchar_t> strconverter;
+
+void _quickw2a(const std::wstring& wstr, std::string& str) {
+       str = strconverter.to_bytes(wstr);
+}
+void _quicka2w(const std::string& str, std::wstring& wstr) {
+       wstr = strconverter.from_bytes(str);
+}
+
+// Copy or convert a char* to a TCHAR
+void _char2TChar(const char* input, TCHAR* output, unsigned maxLength) {
+#ifdef _UNICODE
+       std::wstring outputw;
+       _quicka2w(input, outputw);
+#ifdef _WIN32
+       wcscpy_s(output, maxLength, outputw.c_str());
+#else
+       wcscpy(output, outputw.c_str());
+#endif
+#else
+#ifdef _WIN32
+       strcpy_s(output, maxLength, input);
+#else
+       strcpy_s(output, input);
+#endif
+#endif
+}
+
+#ifdef _UNICODE
+std::vector<std::wstring> memoryPortList;
+#else
+std::vector<std::string> memoryPortList;
+#endif
+
+/*********** STATIC FUNCTIONS ************************/
+
+// Returns TRUE if the floppy bridge library has been loaded and is ready to be queried
+const bool FloppyBridgeAPI::isAvailable() {
+       prepareBridge();
+
+       return hBridgeDLLHandle != 0;
+}
+
+// Populates bridgeInformation with information about the Bridge DLL. This should be called and shown somewhere
+// As it contains update and support information too
+bool FloppyBridgeAPI::getBridgeDriverInformation(BridgeInformation& bridgeInformation) {
+       if (!isAvailable()) {
+               // Populate some basics
+               memset(&bridgeInformation, 0, sizeof(bridgeInformation));
+               _char2TChar("FloppyBridge Driver Not Installed.", bridgeInformation.about, BRIDGE_STRING_MAX_LENGTH - 1);
+               _char2TChar("https://amiga.robsmithdev.co.uk/winuae", bridgeInformation.url, BRIDGE_STRING_MAX_LENGTH - 1);
+               return false;
+       }
+       
+       BridgeAbout* info = nullptr;
+       BRIDGE_About(&info);
+       if (!info) return false;
+
+       bridgeInformation.isBeta = info->isBeta != 0;
+       bridgeInformation.isUpdateAvailable = info->isUpdateAvailable != 0;
+
+       bridgeInformation.majorVersion = info->majorVersion;
+       bridgeInformation.minorVersion = info->minorVersion;
+       bridgeInformation.updateMajorVersion = info->updateMajorVersion;
+       bridgeInformation.updateMinorVersion = info->updateMinorVersion;
+
+       _char2TChar(info->about, bridgeInformation.about, BRIDGE_STRING_MAX_LENGTH - 1);
+       _char2TChar(info->url, bridgeInformation.url, BRIDGE_STRING_MAX_LENGTH - 1);
+       return true;
+}
+
+// Populates driverList with a list of available floppy bridge drivers that could be created
+void FloppyBridgeAPI::getDriverList(std::vector<DriverInformation>& driverList) {
+       driverList.clear();
+
+       if (!isAvailable()) return;
+
+       unsigned int total = BRIDGE_NumDrivers();
+       if (total < 1) return;
+
+       BridgeDriver* info = nullptr;
+       for (unsigned int index = 0; index < total; index++) {
+               if (BRIDGE_GetDriverInfo(index, &info)) {
+
+                       DriverInformation infoOut;
+
+                       _char2TChar(info->name, infoOut.name, BRIDGE_STRING_MAX_LENGTH - 1);
+                       _char2TChar(info->url, infoOut.url, BRIDGE_STRING_MAX_LENGTH - 1);
+                       _char2TChar(info->manufacturer, infoOut.manufacturer, BRIDGE_STRING_MAX_LENGTH - 1);
+                       _char2TChar(info->driverAuthor, infoOut.driverAuthor, BRIDGE_STRING_MAX_LENGTH - 1);
+                       infoOut.configOptions = info->configOptions;
+                       infoOut.driverIndex = index;
+
+                       driverList.push_back(infoOut);
+               }
+       }
+}
+
+// Creates a driver.  If it fails, it will return NULL.  It should only fail if the index is invalid.
+FloppyBridgeAPI* FloppyBridgeAPI::createDriver(unsigned int driverIndex) {
+       if (!isAvailable()) return nullptr;
+
+       BridgeDriverHandle driverHandle = nullptr;
+
+       if (!BRIDGE_CreateDriver(driverIndex, &driverHandle)) return nullptr;
+
+       // Create the class and return it.
+       return new FloppyBridgeAPI(driverIndex, driverHandle);
+}
+
+// Createw a driver from a config string previously saved.  This will auto-select the driverIndex.
+FloppyBridgeAPI* FloppyBridgeAPI::createDriverFromString(const char* config) {
+       if (!isAvailable()) return nullptr;
+
+       BridgeDriverHandle driverHandle = nullptr;
+
+       if (!BRIDGE_CreateDriverFromConfigString((char*)config, &driverHandle)) return nullptr;
+
+       unsigned int driverIndex;
+       if (!BRIDGE_GetDriverIndex(driverHandle, &driverIndex)) {
+               BRIDGE_FreeDriver(driverHandle);
+               return nullptr;
+       }
+
+       return new FloppyBridgeAPI(driverIndex, driverHandle);
+}
+
+// Populates portList with a list of serial port devices that you can use with setComPort() below
+void FloppyBridgeAPI::enumCOMPorts(std::vector<const TCHAR*>& portList) {
+       portList.clear();
+
+       if (!isAvailable()) return;
+
+       unsigned int sizeNeeded = 0;
+       BRIDGE_EnumComports(NULL, &sizeNeeded);
+
+       char* tmp = (char*)malloc(sizeNeeded);
+       if (!tmp) return;
+
+       if (BRIDGE_EnumComports(tmp, &sizeNeeded)) {
+               char* str = tmp;
+               TCharString opString;
+
+               memoryPortList.clear();
+
+               while (*str) {
+                       _char2TChar(str, opString, BRIDGE_STRING_MAX_LENGTH);
+                       memoryPortList.push_back(opString);
+                       str += strlen(str) + 1;  // skip pas the null terminator
+               }
+
+               for (auto& string : memoryPortList)
+                       portList.push_back(string.c_str());
+       }
+       free(tmp);
+}
+
+/*********** CLASS FUNCTIONS ************************/
+
+// Dont call this. You should use the static createDriver member to create it.
+FloppyBridgeAPI::FloppyBridgeAPI(unsigned int driverIndex, BridgeDriverHandle handle) : FloppyDiskBridge(), m_handle(handle), m_driverIndex(driverIndex) {
+}
+
+FloppyBridgeAPI::~FloppyBridgeAPI() {  
+       BRIDGE_FreeDriver(m_handle);
+}
+
+/************** CONFIG RELATED FUNCTIONS *************************************/
+// Returns a pointer to a string containing the current config.  This can be used with setConfigFromString() or createDriverFromString()
+bool FloppyBridgeAPI::getConfigAsString(char** config) {
+       return BRIDGE_GetConfigString(m_handle, config);
+}
+// Applies the config to the currently driver.  Returns TRUE if successful.
+bool FloppyBridgeAPI::setConfigFromString(char* config) {
+       return BRIDGE_SetConfigFromString(m_handle, config);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Return the current bridge mode selected
+bool FloppyBridgeAPI::getBridgeMode(FloppyBridgeAPI::BridgeMode* mode) {
+       return BRIDGE_DriverGetMode(m_handle, mode);
+}
+// Set the currently active bridge mode.  This can be set while the bridge is in use
+bool FloppyBridgeAPI::setBridgeMode(BridgeMode newMode) {
+       return BRIDGE_DriverSetMode(m_handle, newMode);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Return the current bridge density mode selected
+bool FloppyBridgeAPI::getBridgeDensityMode(FloppyBridgeAPI::BridgeDensityMode* mode) {
+       return BRIDGE_DriverGetDensityMode(m_handle, mode);
+}
+// Set the currently active bridge density mode.  This can be set while the bridge is in use
+bool FloppyBridgeAPI::setBridgeDensityMode(BridgeDensityMode newMode) {
+       return BRIDGE_DriverSetDensityMode(m_handle, newMode);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// These require ConfigOption_AutoCache bit set in DriverInformation::configOptions
+// Returns if auto-disk caching (while the drive is idle) mode is enabled
+bool FloppyBridgeAPI::getAutoCacheMode(bool* autoCacheMode) {
+       return BRIDGE_DriverGetAutoCache(m_handle, autoCacheMode);
+}
+// Sets if auto-disk caching (while the drive is idle) mode is enabled.  This can be set while the bridge is in use
+bool FloppyBridgeAPI::setAutoCacheMode(bool autoCacheMode) {
+       return BRIDGE_DriverSetAutoCache(m_handle, autoCacheMode);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// These require ConfigOption_ComPort bit set in DriverInformation::configOptions
+// Returns the currently selected COM port.  This port is only used if auto detect com port is false
+bool FloppyBridgeAPI::getComPort(TCharString* comPort) {
+       char* port = nullptr;
+       if (!BRIDGE_DriverGetCurrentComPort(m_handle, &port)) return false;
+       if (!port) return false;
+       
+       _char2TChar(port, *comPort, BRIDGE_STRING_MAX_LENGTH - 1);
+       return true;
+}
+// Sets the com port to use.  This port is only used if auto detect com port is false.
+bool FloppyBridgeAPI::setComPort(TCHAR* comPort) {
+       if (!comPort) return false;
+       
+#ifdef _UNICODE
+       std::string comPortA;
+       _quickw2a(comPort, comPortA);
+       return BRIDGE_DriverSetCurrentComPort(m_handle, (char*)comPortA.c_str());
+#else
+       return BRIDGE_DriverSetCurrentComPort(m_handle, comPort);
+#endif
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// These require ConfigOption_AutoDetectComport bit set in DriverInformation::configOptions
+// Returns if com port auto-detect is enabled
+bool FloppyBridgeAPI::getComPortAutoDetect(bool* autoDetect) {
+       return BRIDGE_DriverGetAutoDetectComPort(m_handle, autoDetect);
+}
+// Sets if auto-detect com port should be used
+bool FloppyBridgeAPI::setComPortAutoDetect(bool autoDetect) {
+       return BRIDGE_DriverSetAutoDetectComPort(m_handle, autoDetect);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// These require ConfigOption_DriveABCable bit set in DriverInformation::configOptions
+// Returns if the driver should use a drive connected as Drive B (true) on the cable rather than Drive A (false)
+bool FloppyBridgeAPI::getDriveCableSelection(bool* connectToDriveB) {
+       return BRIDGE_DriverGetCable(m_handle, connectToDriveB);
+}
+// Sets if the driver should use a drive connected as Drive B (true) on the cable rather than Drive A (false)
+bool FloppyBridgeAPI::setDriveCableSelection(bool connectToDriveB) {
+       return BRIDGE_DriverSetCable(m_handle, connectToDriveB);
+}
+
+
+/******************* BRIDGE Functions for UAE **********************************/
+
+bool FloppyBridgeAPI::initialise() {
+       if (m_isOpen) shutdown();
+
+       memset(m_error, 0, sizeof(m_error));
+       memset(m_warning, 0, sizeof(m_warning));
+
+       char* msg;
+       m_isOpen = BRIDGE_Open(m_handle, &msg);
+
+       if (m_isOpen) {
+               if (msg) _char2TChar(msg, m_warning, BRIDGE_STRING_MAX_LENGTH-1);
+               return true;
+       }
+       else {
+               if (msg) _char2TChar(msg, m_error, BRIDGE_STRING_MAX_LENGTH - 1);
+               return false;
+       }
+}
+void FloppyBridgeAPI::shutdown() {
+       if (m_isOpen) {
+               BRIDGE_Close(m_handle);
+               m_isOpen = false;
+       }
+       FloppyDiskBridge::shutdown();
+}
+
+
+//virtual const BridgeDriver* getDriverInfo() override;
+unsigned char FloppyBridgeAPI::getBitSpeed() {
+       return DRIVER_getBitSpeed(m_handle);
+}
+FloppyDiskBridge::DriveTypeID FloppyBridgeAPI::getDriveTypeID() {
+       return DRIVER_getDriveTypeID(m_handle);
+}
+const char* FloppyBridgeAPI::getLastErrorMessage() {
+#ifdef _UNICODE
+       _quickw2a(m_error, m_lastErrorAnsi);
+       return m_lastErrorAnsi.c_str();
+#else
+       return m_lastError;
+#endif
+}
+const FloppyDiskBridge::BridgeDriver* FloppyBridgeAPI::getDriverInfo() {
+       if (BRIDGE_GetDriverInfo(m_driverIndex, &m_driverInfo)) return m_driverInfo;
+       return nullptr;
+}
+bool FloppyBridgeAPI::resetDrive(int trackNumber) {
+       return DRIVER_resetDrive(m_handle, trackNumber);
+}
+bool FloppyBridgeAPI::isAtCylinder0() {
+       return DRIVER_isAtCylinder0(m_handle);
+}
+unsigned char FloppyBridgeAPI::getMaxCylinder() {
+       return DRIVER_getMaxCylinder(m_handle);
+}
+void FloppyBridgeAPI::gotoCylinder(int cylinderNumber, bool side) {
+       DRIVER_gotoCylinder(m_handle, cylinderNumber, side);
+}
+void FloppyBridgeAPI::handleNoClickStep(bool side) {
+       DRIVER_handleNoClickStep(m_handle, side);
+}
+unsigned char FloppyBridgeAPI::getCurrentCylinderNumber() {
+       return DRIVER_getCurrentCylinderNumber(m_handle);
+}
+bool FloppyBridgeAPI::isMotorRunning() {
+       return DRIVER_isMotorRunning(m_handle);
+}
+void FloppyBridgeAPI::setMotorStatus(bool turnOn, bool side) {
+       DRIVER_setMotorStatus(m_handle, turnOn, side);
+}
+bool FloppyBridgeAPI::isReady() {
+       return DRIVER_isReady(m_handle);
+}
+bool FloppyBridgeAPI::isDiskInDrive() {
+       return DRIVER_isDiskInDrive(m_handle);
+}
+bool FloppyBridgeAPI::hasDiskChanged() {
+       return DRIVER_hasDiskChanged(m_handle);
+}
+bool FloppyBridgeAPI::isMFMPositionAtIndex(int mfmPositionBits) {
+       return DRIVER_isMFMPositionAtIndex(m_handle, mfmPositionBits);
+}
+bool FloppyBridgeAPI::isMFMDataAvailable() {
+       return DRIVER_isMFMDataAvailable(m_handle);
+}
+bool FloppyBridgeAPI::getMFMBit(const int mfmPositionBits) {
+       return DRIVER_getMFMBit(m_handle, mfmPositionBits);
+}
+int FloppyBridgeAPI::getMFMSpeed(const int mfmPositionBits) {
+       return DRIVER_getMFMSpeed(m_handle, mfmPositionBits);
+}
+void FloppyBridgeAPI::mfmSwitchBuffer(bool side) {
+       DRIVER_mfmSwitchBuffer(m_handle, side);
+}
+void FloppyBridgeAPI::setSurface(bool side) {
+       DRIVER_setSurface(m_handle, side);
+}
+int FloppyBridgeAPI::maxMFMBitPosition() {
+       return DRIVER_maxMFMBitPosition(m_handle);
+}
+void FloppyBridgeAPI::writeShortToBuffer(bool side, unsigned int track, unsigned short mfmData, int mfmPosition) {
+       DRIVER_writeShortToBuffer(m_handle, side, track, mfmData, mfmPosition);
+}
+bool FloppyBridgeAPI::isWriteProtected() {
+       return DRIVER_isWriteProtected(m_handle);
+}
+unsigned int FloppyBridgeAPI::commitWriteBuffer(bool side, unsigned int track) {
+       return DRIVER_commitWriteBuffer(m_handle, side, track);
+}
+bool FloppyBridgeAPI::isWritePending() {
+       return DRIVER_isWritePending(m_handle);
+}
+bool FloppyBridgeAPI::isWriteComplete() {
+       return DRIVER_isWriteComplete(m_handle);
+}
+bool FloppyBridgeAPI::canTurboWrite() {
+       return DRIVER_canTurboWrite(m_handle);
+}
+bool FloppyBridgeAPI::isReadyToWrite() {
+       return DRIVER_isReadyToWrite(m_handle);
+}
\ No newline at end of file
diff --git a/floppybridge/floppybridge_lib.h b/floppybridge/floppybridge_lib.h
new file mode 100644 (file)
index 0000000..e8d81c0
--- /dev/null
@@ -0,0 +1,229 @@
+/* floppybridge_lib
+*
+* Copyright (C) 2021 Robert Smith (@RobSmithDev)
+* https://amiga.robsmithdev.co.uk
+*
+* This class connects to the external FloppyBridge DLL library rather than
+* having all the code compiled in. That library is maintained at 
+* https://amiga.robsmithdev.co.uk/winuae
+*
+* This is free and unencumbered released into the public domain
+* But please don't remove the above information
+* 
+* For more details visit <http://unlicense.org>.
+*
+*/
+
+#pragma once
+
+#include "floppybridge_abstract.h"
+
+#define BRIDGE_STRING_MAX_LENGTH 255
+typedef TCHAR TCharString[BRIDGE_STRING_MAX_LENGTH];
+
+typedef void* BridgeDriverHandle;
+
+// Class to access the 'floppybridge' via a DLL but using the same interface
+class FloppyBridgeAPI : public FloppyDiskBridge {
+public:
+       // Type of bridge mode
+       enum class BridgeMode : unsigned char {
+               bmFast = 0,                                                     // Fast mode.                           This is suitable for most disks and games
+               bmCompatiable = 1,                                      // More compatiable mode.       Some games require this.
+               bmTurboAmigaDOS = 2,                            // Very fast mode.                      This will break all copy protcetion, but is great for AmigaDOS disks in Workbench
+               bmStalling = 3,                                         // Very slow.                           Will cause the emulator to freeze and stall while disk access occurs.
+               bmMax = 3
+       };
+
+       // How to use disk density
+       enum class BridgeDensityMode : unsigned char {
+               bdmAuto = 0,                                            // Auto-detect the type of disk when its inserted
+               bdmDDOnly = 1,                                          // Always detect all inserted disks as DD
+               bdmHDOnly = 2,                                          // Always detect all inserted disks as HD
+               bdmMax = 2
+       };
+
+       // Information about the bridge driver DLL that was loaded.
+       struct BridgeInformation {
+               // Information about the bridge
+               TCharString about;
+               // A url where you can get support/download updates from
+               TCharString url;
+               // The current version
+               unsigned int majorVersion, minorVersion;
+               // Is this version a beta build?
+               bool isBeta;
+               // Is there an update to this version available?
+               bool isUpdateAvailable;
+               // The version number of the update/latest version available
+               unsigned int updateMajorVersion, updateMinorVersion;
+       };
+
+       // These bitmasks are used with DriverInformation::configOptions
+       static const unsigned int ConfigOption_AutoCache                        = 0x01; // The driver can cache data from other cylinders while the disk isn't in use
+       static const unsigned int ConfigOption_ComPort                          = 0x02; // The driver requires a COM port selection
+       static const unsigned int ConfigOption_AutoDetectComport        = 0x04; // The driver supports automatic com port detection and selection
+       static const unsigned int ConfigOption_DriveABCable                     = 0x08; // The driver allows you to specify using cable select for Drive A or Drive B
+
+       // Information about a Bridge Driver (eg: DrawBridge, Greaseweazle etc)
+       struct DriverInformation {
+               // Used to identify the type of driver.  Use this to create the device or multiple instances of the device (possibly on different COM ports)
+               unsigned int driverIndex;
+
+               // Details about the driver
+               TCharString name;
+               TCharString url;
+               TCharString manufacturer;
+               TCharString driverAuthor;
+
+               // A bitmask of which options in configuration the driver can support, aside from the standard ones. See the ConfigOption_ consts above
+               unsigned int configOptions;
+       };
+       
+       //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+       //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+       //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+       // Static functions for accessing parts of the API before creating an instance of this 
+       // Route is: choose driver, create driver, configure it, then set the "bridge" variable in UAE to the created instance and it will do the rest
+
+       // Returns TRUE if the floppy bridge library has been loaded and is ready to be queried.  All functions are safe to call regardless the return value
+       static const bool isAvailable();
+
+       // Populares bridgeInformation with information about the Bridge DLL. This should be called and shown somewhere
+       // As it contains update and support information too.  If this returns FALSE it will still contain basic information such as a URL to get the DLL from.
+       static bool getBridgeDriverInformation(BridgeInformation& bridgeInformation);
+
+       // Populates driverList with a list of available floppy bridge drivers that could be created
+       static void getDriverList(std::vector<DriverInformation>& driverList);
+
+       // Populates portList with a list of serial port devices that you can use with setComPort() below
+       // NOTE: The TCHARs in the vector are only valid until this function is called again
+       static void enumCOMPorts(std::vector<const TCHAR*>& portList);
+
+       // Creates a driver.  If it fails, it will return NULL.  It should only fail if the index is invalid.
+       static FloppyBridgeAPI* createDriver(unsigned int driverIndex);
+
+       // Createw a driver from a config string previously saved.  This will auto-select the driverIndex.
+       static FloppyBridgeAPI* createDriverFromString(const char* config);
+
+       //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+       //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+       //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+       //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+       //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+       //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+       //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+       // Functions for configuring the driver once it has been created.       
+       // Returns a pointer to a string containing the current config.  This can be used with setConfigFromString() or createDriverFromString()
+       bool getConfigAsString(char** config);
+       // Applies the config to the currently driver.  Returns TRUE if successful.
+       bool setConfigFromString(char* config);
+
+       //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+       // Return the current bridge mode selected
+       bool getBridgeMode(BridgeMode* mode);
+       // Set the currently active bridge mode.  This can be set while the bridge is in use
+       bool setBridgeMode(BridgeMode newMode);
+
+       //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+       // Return the current bridge density mode selected
+       bool getBridgeDensityMode(BridgeDensityMode* mode);
+       // Set the currently active bridge density mode.  This can be set while the bridge is in use
+       bool setBridgeDensityMode(BridgeDensityMode newMode);
+
+       //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+       // These require ConfigOption_AutoCache bit set in DriverInformation::configOptions
+       // Returns if auto-disk caching (while the drive is idle) mode is enabled
+       bool getAutoCacheMode(bool* autoCacheMode);
+       // Sets if auto-disk caching (while the drive is idle) mode is enabled.  This can be set while the bridge is in use
+       bool setAutoCacheMode(bool autoCacheMode);
+
+       //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+       // These require ConfigOption_ComPort bit set in DriverInformation::configOptions
+       // Returns the currently selected COM port.  This port is only used if auto detect com port is false
+       bool getComPort(TCharString* comPort);
+       // Sets the com port to use.  This port is only used if auto detect com port is false.
+       bool setComPort(TCHAR* comPort);
+
+       //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+       // These require ConfigOption_AutoDetectComport bit set in DriverInformation::configOptions
+       // Returns if com port auto-detect is enabled
+       bool getComPortAutoDetect(bool* autoDetect);
+       // Sets if auto-detect com port should be used
+       bool setComPortAutoDetect(bool autoDetect);
+
+       //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+       // These require ConfigOption_DriveABCable bit set in DriverInformation::configOptions
+       // Returns if the driver should use a drive connected as Drive B (true) on the cable rather than Drive A (false)
+       bool getDriveCableSelection(bool* connectToDriveB);
+       // Sets if the driver should use a drive connected as Drive B (true) on the cable rather than Drive A (false)
+       bool setDriveCableSelection(bool connectToDriveB);
+
+
+
+
+
+
+
+
+
+
+
+       //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+       //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+       //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+       //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+       //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+       //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+       // Functions required by UAE - see floppybridge_abstract for more details
+       FloppyBridgeAPI(unsigned int driverIndex, BridgeDriverHandle handle); // Dont call this. You should use the static createDriver member to create it.
+       virtual ~FloppyBridgeAPI();
+       virtual bool initialise() override;
+       virtual void shutdown() override;
+       virtual const BridgeDriver* getDriverInfo() override;
+       virtual unsigned char getBitSpeed() override;
+       virtual FloppyDiskBridge::DriveTypeID getDriveTypeID() override;
+       virtual const char* getLastErrorMessage() override;
+       virtual bool resetDrive(int trackNumber) override;
+       virtual bool isAtCylinder0() override;
+       virtual unsigned char getMaxCylinder() override;
+       virtual void gotoCylinder(int cylinderNumber, bool side) override;
+       virtual void handleNoClickStep(bool side) override;
+       virtual unsigned char getCurrentCylinderNumber() override;
+       virtual bool isMotorRunning() override;
+       virtual void setMotorStatus(bool turnOn, bool side) override;
+       virtual bool isReady() override;
+       virtual bool isDiskInDrive() override;
+       virtual bool hasDiskChanged() override;
+       virtual bool isMFMPositionAtIndex(int mfmPositionBits) override;
+       virtual bool isMFMDataAvailable() override;
+       virtual bool getMFMBit(const int mfmPositionBits) override;
+       virtual int getMFMSpeed(const int mfmPositionBits) override;
+       virtual void mfmSwitchBuffer(bool side) override;
+       virtual void setSurface(bool side) override;
+       virtual int maxMFMBitPosition() override;
+       virtual void writeShortToBuffer(bool side, unsigned int track, unsigned short mfmData, int mfmPosition)  override;
+       virtual bool isWriteProtected() override;
+       virtual unsigned int commitWriteBuffer(bool side, unsigned int track)  override;
+       virtual bool isWritePending() override;
+       virtual bool isWriteComplete() override;
+       virtual bool canTurboWrite() override;
+       virtual bool isReadyToWrite() override;
+       //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+       //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+       //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+       //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+private:
+       //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+       // Private stuff
+       BridgeDriverHandle m_handle;                            // Handle to loaded driver
+       unsigned int m_driverIndex;                                     // Index of that driver
+       TCharString m_error = { 0 };                            // Last error
+       TCharString m_warning = { 0 };                          // Last warning
+       BridgeDriver* m_driverInfo;                                     // Pointer to the driver info if retreived
+#ifdef _UNICODE
+       std::string m_lastErrorAnsi;                            // Non-unicode version of the last error
+#endif
+       bool m_isOpen = false;                                          // If the driver is 'open' (ie connected to the drive) or not
+};
\ No newline at end of file
index f0314a947b763e4d48b0d9d33ce39c7c461c4421..53c53e85a1320c7fa4e27695fa388f2286bb650d 100644 (file)
 
 #include "uae/types.h"
 
-typedef enum { DRV_NONE = -1, DRV_35_DD = 0, DRV_35_HD, DRV_525_SD, DRV_35_DD_ESCOM, DRV_PC_525_ONLY_40, DRV_PC_35_ONLY_80, DRV_PC_525_40_80, DRV_525_DD } drive_type;
+typedef enum {
+       DRV_NONE = -1, DRV_35_DD = 0, DRV_35_HD, DRV_525_SD, DRV_35_DD_ESCOM, DRV_PC_525_ONLY_40, DRV_PC_35_ONLY_80, DRV_PC_525_40_80, DRV_525_DD,
+       DRV_FB_A_35_DD, DRV_FB_A_35_HD, DRV_FB_B_35_DD, DRV_FB_B_35_HD,
+} drive_type;
 
 #define HISTORY_FLOPPY 0
 #define HISTORY_CD 1
@@ -30,6 +33,7 @@ struct diskinfo
 {
        uae_u8 bootblock[1024];
        bool bb_crc_valid;
+       bool image_crc_value;
        uae_u32 imagecrc32;
        uae_u32 bootblockcrc32;
        bool hd;
@@ -74,23 +78,24 @@ extern void disk_insert (int num, const TCHAR *name);
 extern void disk_insert (int num, const TCHAR *name, bool forcedwriteprotect);
 extern void disk_insert_force (int num, const TCHAR *name, bool forcedwriteprotect);
 extern void DISK_vsync (void);
-extern int DISK_validate_filename (struct uae_prefs *p, const TCHAR *fname, TCHAR *outfname, int leave_open, bool *wrprot, uae_u32 *crc32, struct zfile **zf);
+extern int DISK_validate_filename (struct uae_prefs *p, const TCHAR *fname, int num, TCHAR *outfname, int leave_open, bool *wrprot, uae_u32 *crc32, struct zfile **zf);
 extern void DISK_handler (uae_u32);
 extern void DISK_update (int hpos);
 extern void DISK_update_adkcon (int hpos, uae_u16 v);
 extern void DISK_hsync (void);
 extern void DISK_reset (void);
-extern int disk_getwriteprotect (struct uae_prefs *p, const TCHAR *name);
+extern int disk_getwriteprotect (struct uae_prefs *p, const TCHAR *name, int num);
 extern int disk_setwriteprotect (struct uae_prefs *p, int num, const TCHAR *name, bool writeprotected);
 extern bool disk_creatediskfile (struct uae_prefs *p, const TCHAR *name, int type, drive_type adftype, int hd, const TCHAR *disk_name, bool ffs, bool bootable, struct zfile *copyfrom);
 extern void dumpdisk (const TCHAR*);
 extern int DISK_history_add (const TCHAR *name, int idx, int type, int donotcheck);
 extern TCHAR *DISK_history_get (int idx, int type);
-int DISK_examine_image (struct uae_prefs *p, int num, struct diskinfo *di, bool deepcheck);
+int DISK_examine_image (struct uae_prefs *p, int num, struct diskinfo *di, bool deepcheck, TCHAR *info);
 extern TCHAR *DISK_get_saveimagepath(const TCHAR *name, int type);
 extern void DISK_reinsert (int num);
 extern int disk_prevnext (int drive, int dir);
 extern int disk_prevnext_name (TCHAR *img, int dir);
+extern void DISK_get_path_text(struct uae_prefs *p, int n, TCHAR *text);
 
 extern bool gui_ask_disk(int drv, TCHAR*);
 
@@ -114,4 +119,8 @@ extern int disk_debug_track;
 
 #define MAX_PREVIOUS_IMAGES 50
 
+void floppybridge_init(struct uae_prefs *p);
+bool floppybridge_has(void);
+bool DISK_isfloppybridge(struct uae_prefs*, int);
+
 #endif /* UAE_DISK_H */
index 815978a5c35980ffc0c20db35749e3cc38e9db56..60d701d5041a3c0cd3208954d214d9e55d2f6a4e 100644 (file)
@@ -57,6 +57,7 @@ struct gui_info_drive {
        TCHAR df[256];                  /* inserted image */
        uae_u32 crc32;                  /* crc32 of image */
        bool floppy_protected;  /* image is write protected */
+       bool floppy_inserted;   /* disk inserted */
 };
 
 struct gui_info
index 9f8dcbbf84192577ba130a1807bd9515d5ef7363..901896f350e0693da589c716ba834cd56e150973 100644 (file)
@@ -164,6 +164,7 @@ struct floppyslot
        int dfxclick;
        TCHAR dfxclickexternal[256];
        bool forcedwriteprotect;
+       TCHAR config[256];
 };
 
 #define ASPECTMULT 1024
@@ -921,7 +922,7 @@ extern void cfgfile_target_write_bool (struct zfile *f, const TCHAR *option, boo
 extern void cfgfile_target_dwrite_bool (struct zfile *f, const TCHAR *option, bool b);
 
 extern void cfgfile_write_str(struct zfile *f, const TCHAR *option, const TCHAR *value);
-extern void cfgfile_write_str_escape(struct zfile* f, const TCHAR* option, const TCHAR* value);
+extern void cfgfile_write_str_escape(struct zfile *f, const TCHAR *option, const TCHAR *value);
 extern void cfgfile_dwrite_str(struct zfile *f, const TCHAR *option, const TCHAR *value);
 extern void cfgfile_dwrite_str_escape(struct zfile *f, const TCHAR *option, const TCHAR *value);
 extern void cfgfile_target_write_str(struct zfile *f, const TCHAR *option, const TCHAR *value);
index 890341fc1d1453979c8e50aa7a87c2f291c2534e..fd811d5ecb12b8d7de787344bd87d03ab3490092 100644 (file)
@@ -342,8 +342,8 @@ BEGIN
     GROUPBOX        "Floppy Drives",IDC_SETTINGSTEXT3,1,23,393,163
     CONTROL         "DF0:",IDC_DF0ENABLE,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,7,37,34,15
     PUSHBUTTON      "Delete save image",IDC_SAVEIMAGE0,69,36,78,15,NOT WS_VISIBLE
-    COMBOBOX        IDC_DF0TYPE,152,37,65,50,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
-    RTEXT           "Write-protected",IDC_STATIC,221,40,74,10,SS_CENTERIMAGE
+    COMBOBOX        IDC_DF0TYPE,152,37,76,50,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+    RTEXT           "Write-protected",IDC_STATIC,229,40,66,10,SS_CENTERIMAGE
     CONTROL         "",IDC_DF0WP,"Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,300,36,10,15
     PUSHBUTTON      "?",IDC_INFO0,323,35,17,15
     PUSHBUTTON      "Eject",IDC_EJECT0,345,35,30,15
@@ -351,8 +351,8 @@ BEGIN
     COMBOBOX        IDC_DF0TEXT,6,54,384,75,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP
     CONTROL         "DF1:",IDC_DF1ENABLE,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,7,74,34,15
     PUSHBUTTON      "Delete save image",IDC_SAVEIMAGE1,69,72,78,15,NOT WS_VISIBLE
-    COMBOBOX        IDC_DF1TYPE,152,74,65,50,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
-    RTEXT           "Write-protected",IDC_STATIC,221,76,74,10,SS_CENTERIMAGE
+    COMBOBOX        IDC_DF1TYPE,152,74,76,50,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+    RTEXT           "Write-protected",IDC_STATIC,229,76,66,10,SS_CENTERIMAGE
     CONTROL         "",IDC_DF1WP,"Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,300,73,10,15
     PUSHBUTTON      "?",IDC_INFO1,323,72,17,15
     PUSHBUTTON      "Eject",IDC_EJECT1,345,72,30,15
@@ -360,8 +360,8 @@ BEGIN
     COMBOBOX        IDC_DF1TEXT,6,91,383,75,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP
     CONTROL         "DF2:",IDC_DF2ENABLE,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,7,110,34,15
     PUSHBUTTON      "Delete save image",IDC_SAVEIMAGE2,69,108,78,15,NOT WS_VISIBLE
-    COMBOBOX        IDC_DF2TYPE,152,110,65,50,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
-    RTEXT           "Write-protected",IDC_STATIC,222,111,73,10,SS_CENTERIMAGE
+    COMBOBOX        IDC_DF2TYPE,152,110,76,50,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+    RTEXT           "Write-protected",IDC_STATIC,229,111,66,10,SS_CENTERIMAGE
     CONTROL         "",IDC_DF2WP,"Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,300,109,9,15
     PUSHBUTTON      "?",IDC_INFO2,323,108,17,15
     PUSHBUTTON      "Eject",IDC_EJECT2,345,108,30,15
@@ -369,8 +369,8 @@ BEGIN
     COMBOBOX        IDC_DF2TEXT,6,127,384,75,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP
     CONTROL         "DF3:",IDC_DF3ENABLE,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,7,146,34,15
     PUSHBUTTON      "Delete save image",IDC_SAVEIMAGE3,69,144,78,15,NOT WS_VISIBLE
-    COMBOBOX        IDC_DF3TYPE,152,146,65,50,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
-    RTEXT           "Write-protected",IDC_STATIC,222,148,73,10,SS_CENTERIMAGE
+    COMBOBOX        IDC_DF3TYPE,152,146,76,50,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+    RTEXT           "Write-protected",IDC_STATIC,229,148,66,10,SS_CENTERIMAGE
     CONTROL         "",IDC_DF3WP,"Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,300,146,9,15
     PUSHBUTTON      "?",IDC_INFO3,323,145,17,15
     PUSHBUTTON      "Eject",IDC_EJECT3,345,144,30,15
index d1369746f474ed71062873015de7933c548248e8..2cb297231c98bf87f26115232d14f9930b63d3ab 100644 (file)
 #define WITH_PCI
 #define WITH_X86
 #define WITH_THREADED_CPU
+#define FLOPPYBRIDGE
 
 
 #else
index 83d5c2a9f4cafcdd55408af9e08da898fc8deb89..fa40854bc0ed78cbdadff0829241e9a1abab4d08 100644 (file)
@@ -233,7 +233,7 @@ static int quickstart_ok, quickstart_ok_floppy;
 static bool firstautoloadconfig = false;
 static void addfloppytype (HWND hDlg, int n);
 static void addfloppyhistory (HWND hDlg);
-static void addhistorymenu (HWND hDlg, const TCHAR*, int f_text, int type, bool manglepath);
+static void addhistorymenu (HWND hDlg, const TCHAR*, int f_text, int type, bool manglepath, int num);
 static void addcdtype (HWND hDlg, int id);
 static void getfloppyname (HWND hDlg, int n, int cd, int f_text);
 
@@ -2538,28 +2538,41 @@ void gui_infotextbox(HWND hDlg, const TCHAR *text)
                if (stringboxdialogactive == -1)
                        break;
        }
-       DeleteObject (font);
+       if (font) {
+               DeleteObject(font);
+       }
 }
 
 static void infofloppy (HWND hDlg, int n)
 {
        struct diskinfo di;
-       TCHAR tmp2[MAX_DPATH], tmp1[MAX_DPATH];
+       TCHAR tmp2[MAX_DPATH], tmp1[MAX_DPATH], tmp3[MAX_DPATH];
        TCHAR text[20000];
 
-       DISK_examine_image (&workprefs, n, &di, true);
-       DISK_validate_filename(&workprefs, workprefs.floppyslots[n].df, tmp1, 0, NULL, NULL, NULL);
+       DISK_examine_image (&workprefs, n, &di, true, tmp3);
+       DISK_validate_filename(&workprefs, workprefs.floppyslots[n].df, n, tmp1, 0, NULL, NULL, NULL);
 
-       _stprintf (tmp2,
-               _T("'%s'\r\nDisk readable: %s\r\nDisk CRC32: %08X\r\nBoot block CRC32: %08X\r\nBoot block checksum valid: %s\r\nBoot block type: %s\r\n"),
-               tmp1,
-               di.unreadable ? _T("No") : _T("Yes"),
-               di.imagecrc32,
+       text[0] = 0;
+       if (tmp3[0]) {
+               _tcscpy(text, tmp3);
+               _tcscat(text, _T("\r\n\r\n"));
+       }
+       tmp2[0] = 0;
+       if (tmp1[0]) {
+               _stprintf(tmp2, _T("'%s'\r\n"), tmp1);
+       }
+       _stprintf (tmp2 + _tcslen(tmp2), _T("Disk readable: %s\r\n"), di.unreadable ? _T("No") : _T("Yes"));
+       if (di.image_crc_value) {
+               _stprintf(tmp2 + _tcslen(tmp2), _T("Disk CRC32: %08X\r\n"), di.imagecrc32);
+       }
+       _stprintf(tmp2 + _tcslen(tmp2),
+               _T("Boot block CRC32: %08X\r\nBoot block checksum valid: %s\r\nBoot block type: %s\r\n"),
                di.bootblockcrc32,
                di.bb_crc_valid ? _T("Yes") : _T("No"),
                di.bootblocktype == 0 ? _T("Custom") : (di.bootblocktype == 1 ? _T("Standard 1.x") : _T("Standard 2.x+"))
        );
-       _tcscpy (text, tmp2);
+
+       _tcscat(text, tmp2);
        if (di.diskname[0]) {
                _stprintf (tmp2,
                        _T("Label: '%s'\r\n"), di.diskname);
@@ -5966,7 +5979,7 @@ static int LoadConfigTreeView (HWND hDlg, int idx, HTREEITEM parent)
 
 static void InitializeConfig (HWND hDlg, struct ConfigStruct *config)
 {
-       addhistorymenu(hDlg, config == NULL ? _T("") : config->Name, IDC_EDITNAME, HISTORY_CONFIGFILE, false);
+       addhistorymenu(hDlg, config == NULL ? _T("") : config->Name, IDC_EDITNAME, HISTORY_CONFIGFILE, false, -1);
        if (config == NULL) {
                SetDlgItemText (hDlg, IDC_EDITDESCRIPTION, _T(""));
        } else {
@@ -7270,7 +7283,7 @@ static void testimage (HWND hDlg, int num)
        }
        if (!workprefs.floppyslots[num].df[0])
                return;
-       ret = DISK_examine_image (&workprefs, num, &di, false);
+       ret = DISK_examine_image (&workprefs, num, &di, false, NULL);
        if (!ret)
                return;
        floppytooltip (hDlg, num, di.imagecrc32);
@@ -8822,9 +8835,9 @@ static void setgenlock(HWND hDlg)
 {
        setautocomplete(hDlg, IDC_GENLOCKFILE);
        if (workprefs.genlock_image == 3) {
-               addhistorymenu(hDlg, workprefs.genlock_image_file, IDC_GENLOCKFILE, HISTORY_GENLOCK_IMAGE, true);
+               addhistorymenu(hDlg, workprefs.genlock_image_file, IDC_GENLOCKFILE, HISTORY_GENLOCK_IMAGE, true, -1);
        } else if (workprefs.genlock_image == 4 || workprefs.genlock_image >= 6) {
-               addhistorymenu(hDlg, workprefs.genlock_video_file, IDC_GENLOCKFILE, HISTORY_GENLOCK_VIDEO, true);
+               addhistorymenu(hDlg, workprefs.genlock_video_file, IDC_GENLOCKFILE, HISTORY_GENLOCK_VIDEO, true, -1);
        }
 }
 
@@ -8924,7 +8937,7 @@ static INT_PTR CALLBACK ChipsetDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPAR
                                        TCHAR *p = workprefs.genlock_image == 3 ? workprefs.genlock_image_file : workprefs.genlock_video_file;
                                        getcomboboxtext(hDlg, IDC_GENLOCKFILE, p, MAX_DPATH);
                                        parsefilepath(p, MAX_DPATH);
-                                       addhistorymenu(hDlg, p, IDC_GENLOCKFILE, workprefs.genlock_image == 3 ? HISTORY_GENLOCK_IMAGE : HISTORY_GENLOCK_VIDEO, true);
+                                       addhistorymenu(hDlg, p, IDC_GENLOCKFILE, workprefs.genlock_image == 3 ? HISTORY_GENLOCK_IMAGE : HISTORY_GENLOCK_VIDEO, true, -1);
                                        break;
                                }
                        }
@@ -12366,7 +12379,7 @@ static INT_PTR MiscDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
                InitializeListView (hDlg);
                values_to_miscdlg (hDlg);
                enable_for_miscdlg (hDlg);
-               addhistorymenu(hDlg, NULL, IDC_STATENAME, HISTORY_STATEFILE, true);
+               addhistorymenu(hDlg, NULL, IDC_STATENAME, HISTORY_STATEFILE, true, -1);
                setstatefilename(hDlg);
                recursive--;
                return TRUE;
@@ -13825,7 +13838,7 @@ static INT_PTR CALLBACK VolumeSettingsProc (HWND hDlg, UINT msg, WPARAM wParam,
                                archivehd = 0;
                        recursive++;
                        setautocomplete (hDlg, IDC_PATH_NAME);
-                       addhistorymenu(hDlg, current_fsvdlg.ci.rootdir, IDC_PATH_NAME, HISTORY_DIR, false);
+                       addhistorymenu(hDlg, current_fsvdlg.ci.rootdir, IDC_PATH_NAME, HISTORY_DIR, false, -1);
                        SetDlgItemText (hDlg, IDC_VOLUME_NAME, current_fsvdlg.ci.volname);
                        SetDlgItemText (hDlg, IDC_VOLUME_DEVICE, current_fsvdlg.ci.devname);
                        SetDlgItemInt (hDlg, IDC_VOLUME_BOOTPRI, current_fsvdlg.ci.bootpri, TRUE);
@@ -14408,7 +14421,7 @@ static INT_PTR CALLBACK TapeDriveSettingsProc (HWND hDlg, UINT msg, WPARAM wPara
                inithdcontroller(hDlg, current_tapedlg.ci.controller_type, current_tapedlg.ci.controller_type_unit, UAEDEV_TAPE, current_tapedlg.ci.rootdir[0] != 0);
                SendDlgItemMessage(hDlg, IDC_HDF_CONTROLLER_UNIT, CB_SETCURSEL, current_tapedlg.ci.controller_unit, 0);
                setautocomplete (hDlg, IDC_PATH_NAME);
-               addhistorymenu(hDlg, current_tapedlg.ci.rootdir, IDC_PATH_NAME, HISTORY_TAPE, false);
+               addhistorymenu(hDlg, current_tapedlg.ci.rootdir, IDC_PATH_NAME, HISTORY_TAPE, false, -1);
                readonly = !tape_can_write(current_tapedlg.ci.rootdir);
                CheckDlgButton (hDlg, IDC_TAPE_RW, current_tapedlg.ci.readonly == 0 && !readonly);
                ew (hDlg, IDC_TAPE_RW, !readonly);
@@ -14620,10 +14633,10 @@ static INT_PTR CALLBACK HardfileSettingsProc (HWND hDlg, UINT msg, WPARAM wParam
                setautocomplete (hDlg, IDC_PATH_NAME);
                setautocomplete (hDlg, IDC_PATH_FILESYS);
                setautocomplete (hDlg, IDC_PATH_GEOMETRY);
-               addhistorymenu(hDlg, current_hfdlg.ci.geometry, IDC_PATH_GEOMETRY, HISTORY_GEO, false);
+               addhistorymenu(hDlg, current_hfdlg.ci.geometry, IDC_PATH_GEOMETRY, HISTORY_GEO, false, -1);
                inithardfile (hDlg, current_hfdlg.ci.rootdir[0] != 0);
-               addhistorymenu(hDlg, current_hfdlg.ci.rootdir, IDC_PATH_NAME, HISTORY_HDF, false);
-               addhistorymenu(hDlg, current_hfdlg.ci.filesys, IDC_PATH_FILESYS, HISTORY_FS, false);
+               addhistorymenu(hDlg, current_hfdlg.ci.rootdir, IDC_PATH_NAME, HISTORY_HDF, false, -1);
+               addhistorymenu(hDlg, current_hfdlg.ci.filesys, IDC_PATH_FILESYS, HISTORY_FS, false, -1);
                updatehdfinfo (hDlg, true, false, false);
                sethardfile (hDlg);
                sethfdostype (hDlg, 0);
@@ -14668,7 +14681,7 @@ static INT_PTR CALLBACK HardfileSettingsProc (HWND hDlg, UINT msg, WPARAM wParam
                        case IDC_PATH_GEOMETRY:
                                getcomboboxtext(hDlg, IDC_PATH_GEOMETRY, current_hfdlg.ci.geometry, sizeof  current_hfdlg.ci.geometry / sizeof(TCHAR));
                                if (HIWORD (wParam) == CBN_KILLFOCUS) {
-                                       addhistorymenu(hDlg, current_hfdlg.ci.geometry, IDC_PATH_GEOMETRY, HISTORY_GEO, false);
+                                       addhistorymenu(hDlg, current_hfdlg.ci.geometry, IDC_PATH_GEOMETRY, HISTORY_GEO, false, -1);
                                        sethardfile(hDlg);
                                        updatehdfinfo (hDlg, true, false, false);
                                }
@@ -14683,13 +14696,13 @@ static INT_PTR CALLBACK HardfileSettingsProc (HWND hDlg, UINT msg, WPARAM wParam
                                        }
                                }
                                if (HIWORD (wParam) == CBN_KILLFOCUS) {
-                                       addhistorymenu(hDlg, current_hfdlg.ci.rootdir, IDC_PATH_NAME, HISTORY_HDF, false);
+                                       addhistorymenu(hDlg, current_hfdlg.ci.rootdir, IDC_PATH_NAME, HISTORY_HDF, false, -1);
                                }
                                break;
                        case IDC_PATH_FILESYS:
                                getcomboboxtext(hDlg, IDC_PATH_FILESYS, current_hfdlg.ci.filesys, sizeof current_hfdlg.ci.filesys / sizeof(TCHAR));
                                if (HIWORD(wParam) == CBN_KILLFOCUS) {
-                                       addhistorymenu(hDlg, current_hfdlg.ci.filesys, IDC_PATH_FILESYS, HISTORY_FS, false);
+                                       addhistorymenu(hDlg, current_hfdlg.ci.filesys, IDC_PATH_FILESYS, HISTORY_FS, false, -1);
                                }
                                break;
                        }
@@ -14892,7 +14905,7 @@ static INT_PTR CALLBACK HarddriveSettingsProc (HWND hDlg, UINT msg, WPARAM wPara
                        hdf_init_target ();
                        recursive++;
                        setautocomplete (hDlg, IDC_PATH_GEOMETRY);
-                       addhistorymenu(hDlg, current_hfdlg.ci.geometry, IDC_PATH_GEOMETRY, HISTORY_GEO, false);
+                       addhistorymenu(hDlg, current_hfdlg.ci.geometry, IDC_PATH_GEOMETRY, HISTORY_GEO, false, -1);
                        setchecked(hDlg, IDC_HDF_PHYSGEOMETRY, current_hfdlg.ci.physical_geometry);
                        setharddrive(hDlg);
                        inithdcontroller(hDlg, current_hfdlg.ci.controller_type, current_hfdlg.ci.controller_type_unit, UAEDEV_HDF, current_hfdlg.ci.rootdir[0] != 0);
@@ -14929,7 +14942,7 @@ static INT_PTR CALLBACK HarddriveSettingsProc (HWND hDlg, UINT msg, WPARAM wPara
                                case IDC_PATH_GEOMETRY:
                                        getcomboboxtext(hDlg, IDC_PATH_GEOMETRY, current_hfdlg.ci.geometry, sizeof  current_hfdlg.ci.geometry / sizeof(TCHAR));
                                        if (HIWORD (wParam) == CBN_KILLFOCUS) {
-                                               addhistorymenu(hDlg, current_hfdlg.ci.geometry, IDC_PATH_GEOMETRY, HISTORY_GEO, false);
+                                               addhistorymenu(hDlg, current_hfdlg.ci.geometry, IDC_PATH_GEOMETRY, HISTORY_GEO, false, -1);
                                                setharddrive(hDlg);
                                                updatehdfinfo (hDlg, true, false, true);
                                        }
@@ -15448,7 +15461,7 @@ static INT_PTR CALLBACK HarddiskDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPA
                CheckDlgButton (hDlg, IDC_CD_SPEED, workprefs.cd_speed == 0);
                InitializeListView (hDlg);
                setautocomplete (hDlg, IDC_CD_TEXT);
-               addhistorymenu (hDlg, workprefs.cdslots[0].name, IDC_CD_TEXT, HISTORY_CD, true);
+               addhistorymenu (hDlg, workprefs.cdslots[0].name, IDC_CD_TEXT, HISTORY_CD, true, -1);
                addcdtype (hDlg, IDC_CD_TYPE);
                hilitehd (hDlg);
                break;
@@ -15481,7 +15494,7 @@ static INT_PTR CALLBACK HarddiskDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPA
                        if (full_property_sheet)
                                workprefs.cdslots[0].type = SCSI_UNIT_DEFAULT;
                        addcdtype (hDlg, IDC_CD_TYPE);
-                       addhistorymenu (hDlg, workprefs.cdslots[0].name, IDC_CD_TEXT, HISTORY_CD, true);
+                       addhistorymenu (hDlg, workprefs.cdslots[0].name, IDC_CD_TEXT, HISTORY_CD, true, -1);
                        InitializeListView (hDlg);
                        hilitehd (hDlg);
                        break;
@@ -15511,7 +15524,7 @@ static INT_PTR CALLBACK HarddiskDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPA
                                        }
                                }
                                addcdtype (hDlg, IDC_CD_TYPE);
-                               addhistorymenu (hDlg, workprefs.cdslots[0].name, IDC_CD_TEXT, HISTORY_CD, true);
+                               addhistorymenu (hDlg, workprefs.cdslots[0].name, IDC_CD_TEXT, HISTORY_CD, true, -1);
                                InitializeListView (hDlg);
                                hilitehd (hDlg);
                        }
@@ -15580,6 +15593,14 @@ static const int floppybuttonsq[][BUTTONSPERFLOPPY] = {
        { -1,-1,-1,-1,-1,-1,-1,-1 }
 };
 
+static int isfloppybridge(int type)
+{
+       if (type >= DRV_FB_A_35_DD) {
+               return type - DRV_FB_A_35_DD;
+       }
+       return -1;
+}
+
 static void floppytooltip (HWND hDlg, int num, uae_u32 crc32)
 {
        TOOLINFO ti;
@@ -15606,7 +15627,20 @@ static void floppytooltip (HWND hDlg, int num, uae_u32 crc32)
        SendMessage (ToolTipHWND, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &ti);
 }
 
-static void addhistorymenu(HWND hDlg, const TCHAR *text, int f_text, int type, bool manglepath)
+static void updatedfname(HWND hDlg, const TCHAR *text, int f_text, int type, int num)
+{
+       if (type == HISTORY_FLOPPY && DISK_isfloppybridge(&workprefs, num)) {
+               TCHAR text2[MAX_DPATH];
+               DISK_get_path_text(&workprefs, num, text2);
+               if (text)
+                       SendDlgItemMessage(hDlg, f_text, WM_SETTEXT, 0, (LPARAM)text2);
+       } else {
+               if (text)
+                       SendDlgItemMessage(hDlg, f_text, WM_SETTEXT, 0, (LPARAM)text);
+       }
+}
+
+static void addhistorymenu(HWND hDlg, const TCHAR *text, int f_text, int type, bool manglepath, int num)
 {
        int i, j;
        TCHAR *s;
@@ -15616,9 +15650,7 @@ static void addhistorymenu(HWND hDlg, const TCHAR *text, int f_text, int type, b
 
        if (f_text < 0)
                return;
-       SendDlgItemMessage (hDlg, f_text, CB_RESETCONTENT, 0, 0);
-       if (text)
-               SendDlgItemMessage (hDlg, f_text, WM_SETTEXT, 0, (LPARAM)text);
+       SendDlgItemMessage(hDlg, f_text, CB_RESETCONTENT, 0, 0);
        fkey = read_disk_history (type);
        if (fkey == NULL)
                return;
@@ -15660,8 +15692,12 @@ static void addhistorymenu(HWND hDlg, const TCHAR *text, int f_text, int type, b
                if (text && !_tcscmp (text, s))
                        curidx = i - 1;
        }
-       if (f_text >= 0 && curidx >= 0)
-               SendDlgItemMessage (hDlg, f_text, CB_SETCURSEL, curidx, 0);
+       if (f_text >= 0) {
+               if (curidx >= 0)
+                       SendDlgItemMessage(hDlg, f_text, CB_SETCURSEL, curidx, 0);
+               else 
+                       updatedfname(hDlg, text, f_text, type, num);
+       }
        regclosetree (fkey);
 }
 
@@ -15688,7 +15724,7 @@ static void addfloppyhistory (HWND hDlg)
                        TCHAR *name = workprefs.floppyslots[n].df;
                        if (iscd(n))
                                name = workprefs.cdslots[0].name;
-                       addhistorymenu (hDlg, name, f_text, iscd (n) ? HISTORY_CD : HISTORY_FLOPPY, true);
+                       addhistorymenu(hDlg, name, f_text, iscd(n) ? HISTORY_CD : HISTORY_FLOPPY, true, n);
                }
        }
 }
@@ -15723,39 +15759,133 @@ static void addcdtype (HWND hDlg, int id)
        SendDlgItemMessage (hDlg, id, CB_SETCURSEL, cdtype, 0);
 }
 
-static int fromdfxtype(int dfx)
+static int fromdfxtype(int num, int dfx)
 {
-       if (dfx == 7)
-               dfx = 3;
-       else if (dfx >= 3)
-               dfx++;
-       dfx++;
-       return dfx;
-}
-
-static int todfxtype(int val)
-{
-       val--;
-       if (val == 3)
-               val = 7;
-       else if (val > 3)
-               val--;
-       return val;
+       switch (dfx)
+       {
+       case DRV_35_DD:
+               return 1;
+       case DRV_35_HD:
+               return 2;
+       case DRV_525_SD:
+               return 3;
+       case DRV_525_DD:
+               return 4;
+       case DRV_35_DD_ESCOM:
+               return 5;
+       }
+       if (num < 2) {
+               switch (dfx)
+               {
+               case DRV_FB_A_35_DD:
+                       if (!floppybridge_has()) {
+                               return 1;
+                       }
+                       return 6;
+               case DRV_FB_A_35_HD:
+                       if (!floppybridge_has()) {
+                               return 1;
+                       }
+                       return 7;
+               case DRV_FB_B_35_DD:
+               if (!floppybridge_has()) {
+                       return 1;
+               }
+               return 8;
+               case DRV_FB_B_35_HD:
+               if (!floppybridge_has()) {
+                       return 1;
+               }
+               return 9;
+       }
+} else {
+               switch (dfx)
+               {
+               case DRV_PC_525_ONLY_40:
+                       return 6;
+               case DRV_PC_525_40_80:
+                       return 7;
+               case DRV_PC_35_ONLY_80:
+                       return 8;
+               case DRV_FB_A_35_DD:
+                       if (!floppybridge_has()) {
+                               return 1;
+                       }
+                       return 9;
+               case DRV_FB_A_35_HD:
+                       if (!floppybridge_has()) {
+                               return 1;
+                       }
+                       return 10;
+               case DRV_FB_B_35_DD:
+                       if (!floppybridge_has()) {
+                               return 1;
+                       }
+                       return 11;
+               case DRV_FB_B_35_HD:
+                       if (!floppybridge_has()) {
+                               return 1;
+                       }
+                       return 11;
+               }
+       }
+       return 0;
 }
 
-static int swapdrives(int v)
+static int todfxtype(int num, int dfx)
 {
-       if (v == 7)
-               v = 8;
-       else if (v == 8)
-               v = 7;
-       return v;
+       switch (dfx)
+       {
+       case 1:
+               return DRV_35_DD;
+       case 2:
+               return DRV_35_HD;
+       case 3:
+               return DRV_525_SD;
+       case 4:
+               return DRV_525_DD;
+       case 5:
+               return DRV_35_DD_ESCOM;
+       }
+       if (num < 2) {
+               switch (dfx)
+               {
+               case 6:
+                       return DRV_FB_A_35_DD;
+               case 7:
+                       return DRV_FB_A_35_HD;
+               case 8:
+                       return DRV_FB_B_35_DD;
+               case 9:
+                       return DRV_FB_B_35_HD;
+               }
+       } else {
+               switch (dfx)
+               {
+               case 6:
+                       return DRV_PC_525_ONLY_40;
+               case 7:
+                       return DRV_PC_525_40_80;
+               case 8:
+                       return DRV_PC_35_ONLY_80;
+               case 9:
+                       return DRV_FB_A_35_DD;
+               case 10:
+                       return DRV_FB_A_35_HD;
+               case 11:
+                       return DRV_FB_A_35_DD;
+               case 12:
+                       return DRV_FB_A_35_HD;
+               }
+       }
+       return -1;
 }
 
 static void addfloppytype (HWND hDlg, int n)
 {
        int state, chk;
-       int nn = fromdfxtype(workprefs.floppyslots[n].dfxtype);
+       int nn = fromdfxtype(n, workprefs.floppyslots[n].dfxtype);
+       int fb = DISK_isfloppybridge(&workprefs, n);
        int showcd = 0;
        TCHAR *text;
 
@@ -15816,7 +15946,7 @@ static void addfloppytype (HWND hDlg, int n)
        else
                state = TRUE;
        if (f_type >= 0) {
-               SendDlgItemMessage(hDlg, f_type, CB_SETCURSEL, swapdrives(nn), 0);
+               SendDlgItemMessage(hDlg, f_type, CB_SETCURSEL, nn, 0);
        }
        if (f_si >= 0) {
                TCHAR *path = DISK_get_saveimagepath(text, -2);
@@ -15824,11 +15954,11 @@ static void addfloppytype (HWND hDlg, int n)
                xfree(path);
        }
        if (f_text >= 0)
-               ew (hDlg, f_text, state);
+               ew (hDlg, f_text, state && !fb);
        if (f_eject >= 0)
-               ew (hDlg, f_eject, text[0] != 0);
+               ew (hDlg, f_eject, text[0] != 0 && !fb);
        if (f_drive >= 0)
-               ew (hDlg, f_drive, state);
+               ew (hDlg, f_drive, state && !fb);
        if (f_enable >= 0) {
                if (currentpage == QUICKSTART_ID) {
                        ew (hDlg, f_enable, (n > 0 && workprefs.nr_floppies > 0) && !showcd);
@@ -15848,12 +15978,14 @@ static void addfloppytype (HWND hDlg, int n)
                if (tmp[0])
                        SetWindowText(GetDlgItem(hDlg, f_enable), tmp);
        }
-       chk = !showcd && disk_getwriteprotect (&workprefs, text) && state == TRUE ? BST_CHECKED : 0;
-       if (f_wp >= 0)
-               CheckDlgButton (hDlg, f_wp, chk);
+       chk = !showcd && disk_getwriteprotect (&workprefs, text, n) && state == TRUE ? BST_CHECKED : 0;
+       if (f_wp >= 0) {
+               CheckDlgButton(hDlg, f_wp, chk);
+               ew(hDlg, f_wp, !fb);
+       }
        if (f_info >= 0)
-               ew (hDlg, f_info, text[0] != 0);
-       chk = !showcd && state && DISK_validate_filename (&workprefs, text, NULL, 0, NULL, NULL, NULL) ? TRUE : FALSE;
+               ew (hDlg, f_info, text[0] != 0 || fb);
+       chk = !showcd && state && DISK_validate_filename (&workprefs, text, n, NULL, 0, NULL, NULL, NULL) ? TRUE : FALSE;
        if (f_wp >= 0) {
                ew (hDlg, f_wp, chk && !workprefs.floppy_read_only);
                if (f_wptext >= 0)
@@ -15861,16 +15993,24 @@ static void addfloppytype (HWND hDlg, int n)
        }
 }
 
-static void getfloppytype (HWND hDlg, int n)
+static void getfloppytype(HWND hDlg, int n)
 {
+       int f_text = floppybuttons[n][0];
        int f_type = floppybuttons[n][3];
-       LRESULT val = SendDlgItemMessage (hDlg, f_type, CB_GETCURSEL, 0, 0L);
+       LRESULT val = SendDlgItemMessage(hDlg, f_type, CB_GETCURSEL, 0, 0L);
 
-       val = swapdrives(val);
-
-       if (val != CB_ERR && workprefs.floppyslots[n].dfxtype != todfxtype(val)) {
-               workprefs.floppyslots[n].dfxtype = todfxtype(val);
-               addfloppytype (hDlg, n);
+       if (val != CB_ERR && workprefs.floppyslots[n].dfxtype != todfxtype(n, val)) {
+               workprefs.floppyslots[n].dfxtype = todfxtype(n, val);
+               workprefs.floppyslots[n].config[0] = 0;
+               for (int i = 0; i < 4; i++) {
+                       if (i != n && DISK_isfloppybridge(&workprefs, i) && DISK_isfloppybridge(&workprefs, n)) {
+                               workprefs.floppyslots[n].dfxtype = DRV_35_DD;
+                       }
+               }
+               floppybridge_init(&workprefs);
+               addfloppytype(hDlg, n);
+               addhistorymenu(hDlg, NULL, f_text, HISTORY_FLOPPY, true, n);
+               updatedfname(hDlg, workprefs.floppyslots[n].df, f_text, HISTORY_FLOPPY, n);
        }
 }
 static void getfloppytypeq (HWND hDlg, int n)
@@ -15896,33 +16036,42 @@ static void getfloppytypeq (HWND hDlg, int n)
        }
 }
 
-static int getfloppybox (HWND hDlg, int f_text, TCHAR *out, int maxlen, int type)
+static int getfloppybox (HWND hDlg, int f_text, TCHAR *out, int maxlen, int type, int num)
 {
        LRESULT val;
        TCHAR *p;
        int i;
 
-       out[0] = 0;
-       val = SendDlgItemMessage (hDlg, f_text, CB_GETCURSEL, 0, 0L);
-       if (val != CB_ERR) {
-               int len = SendDlgItemMessage(hDlg, f_text, CB_GETLBTEXTLEN, (WPARAM)val, 0);
-               if (len < maxlen) {
-                       val = SendDlgItemMessage (hDlg, f_text, CB_GETLBTEXT, (WPARAM)val, (LPARAM)out);
-               }
+       if (num >= 0 && DISK_isfloppybridge(&workprefs, num)) {
+
+               out[0] = 0;
+
        } else {
-               SendDlgItemMessage (hDlg, f_text, WM_GETTEXT, (WPARAM)maxlen, (LPARAM)out);
-       }
 
-       parsefilepath(out, maxlen);
+               out[0] = 0;
+               val = SendDlgItemMessage(hDlg, f_text, CB_GETCURSEL, 0, 0L);
+               if (val != CB_ERR) {
+                       int len = SendDlgItemMessage(hDlg, f_text, CB_GETLBTEXTLEN, (WPARAM)val, 0);
+                       if (len < maxlen) {
+                               val = SendDlgItemMessage(hDlg, f_text, CB_GETLBTEXT, (WPARAM)val, (LPARAM)out);
+                       }
+               } else {
+                       SendDlgItemMessage(hDlg, f_text, WM_GETTEXT, (WPARAM)maxlen, (LPARAM)out);
+               }
 
-       i = 0;
-       while ((p = DISK_history_get (i, type))) {
-               if (!_tcscmp (p, out)) {
-                       DISK_history_add (out, -1, type, 0);
-                       break;
+               parsefilepath(out, maxlen);
+
+               i = 0;
+               while ((p = DISK_history_get(i, type))) {
+                       if (!_tcscmp(p, out)) {
+                               DISK_history_add(out, -1, type, 0);
+                               break;
+                       }
+                       i++;
                }
-               i++;
+
        }
+
        return out[0] ? 1 : 0;
 }
 
@@ -15939,7 +16088,7 @@ static void getfloppyname (HWND hDlg, int n, int cd, int f_text)
 {
        TCHAR tmp[MAX_DPATH];
 
-       if (getfloppybox (hDlg, f_text, tmp, sizeof (tmp) / sizeof (TCHAR), cd ? HISTORY_CD : HISTORY_FLOPPY)) {
+       if (getfloppybox (hDlg, f_text, tmp, sizeof (tmp) / sizeof (TCHAR), cd ? HISTORY_CD : HISTORY_FLOPPY, n)) {
                if (!cd) {
                        disk_insert (n, tmp);
                        _tcscpy (workprefs.floppyslots[n].df, tmp);
@@ -16094,9 +16243,16 @@ static INT_PTR CALLBACK FloppyDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARA
                                SendDlgItemMessage (hDlg, f_type, CB_ADDSTRING, 0, (LPARAM)_T("5.25\" (80)"));
                                SendDlgItemMessage (hDlg, f_type, CB_ADDSTRING, 0, (LPARAM)ft35ddescom);
                                if (i >= 2) {
-                                       SendDlgItemMessage(hDlg, f_type, CB_ADDSTRING, 0, (LPARAM)_T("Bridge 5.25\" 40"));
-                                       SendDlgItemMessage(hDlg, f_type, CB_ADDSTRING, 0, (LPARAM)_T("Bridge 5.25\" 80"));
-                                       SendDlgItemMessage(hDlg, f_type, CB_ADDSTRING, 0, (LPARAM)_T("Bridge 3.5\"  80"));
+                                       SendDlgItemMessage(hDlg, f_type, CB_ADDSTRING, 0, (LPARAM)_T("Bridgeboard 5.25\" 40"));
+                                       SendDlgItemMessage(hDlg, f_type, CB_ADDSTRING, 0, (LPARAM)_T("Bridgeboard 5.25\" 80"));
+                                       SendDlgItemMessage(hDlg, f_type, CB_ADDSTRING, 0, (LPARAM)_T("Bridgeboard 3.5\"  80"));
+                               }
+                               if (floppybridge_has()) {
+                                       floppybridge_init(&workprefs);
+                                       SendDlgItemMessage(hDlg, f_type, CB_ADDSTRING, 0, (LPARAM)_T("FloppyBridge A: 3.5\" DD"));
+                                       SendDlgItemMessage(hDlg, f_type, CB_ADDSTRING, 0, (LPARAM)_T("FloppyBridge A: 3.5\" HD"));
+                                       SendDlgItemMessage(hDlg, f_type, CB_ADDSTRING, 0, (LPARAM)_T("FloppyBridge B: 3.5\" DD"));
+                                       SendDlgItemMessage(hDlg, f_type, CB_ADDSTRING, 0, (LPARAM)_T("FloppyBridge B: 3.5\" HD"));
                                }
                        }
                        setmultiautocomplete (hDlg, df0texts);
@@ -16527,7 +16683,7 @@ static INT_PTR CALLBACK SwapperDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPAR
 
                        case IDC_DISKLISTINSERT:
                                if (entry >= 0) {
-                                       if (getfloppybox (hDlg, IDC_DISKTEXT, tmp, sizeof (tmp) / sizeof (TCHAR), HISTORY_FLOPPY)) {
+                                       if (getfloppybox (hDlg, IDC_DISKTEXT, tmp, sizeof (tmp) / sizeof (TCHAR), HISTORY_FLOPPY, -1)) {
                                                _tcscpy (workprefs.dfxlist[entry], tmp);
                                                addfloppyhistory (hDlg);
                                                InitializeListView (hDlg);
index 4f0225a9d107e0401503b6491be702a33edc0591..95f0e2da82075690c79a247e79668176bb2193f4 100644 (file)
     <ClCompile Include="..\..\ethernet.cpp" />
     <ClCompile Include="..\..\events.cpp" />
     <ClCompile Include="..\..\flashrom.cpp" />
+    <ClCompile Include="..\..\floppybridge\floppybridge_lib.cpp" />
     <ClCompile Include="..\..\fpp_native.cpp" />
     <ClCompile Include="..\..\fpp_softfloat.cpp" />
     <ClCompile Include="..\..\framebufferboards.cpp" />
index 5b01b9eb37aad9f9e7e0bf5e74e7559bc18c9c6e..7eb12d701e328d73d0402c269412046f35e406bc 100644 (file)
     <ClCompile Include="..\..\pcem\vid_voodoo.cpp">
       <Filter>pcem</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\floppybridge\floppybridge_lib.cpp">
+      <Filter>common</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <None Include="..\resources\35floppy.ico">
index 2ed1d8b97d3b0b15d5710c32b83dcd6ad6c73797..5d7ad11dd68a7a7c4055b18efce2c4c91083b833 100644 (file)
@@ -1864,7 +1864,7 @@ retry2:
                input_record++;
                for (i = 0; i < 4; i++) {
                        bool wp = true;
-                       DISK_validate_filename (&currprefs, currprefs.floppyslots[i].df, NULL, false, &wp, NULL, NULL);
+                       DISK_validate_filename (&currprefs, currprefs.floppyslots[i].df, i, NULL, false, &wp, NULL, NULL);
                        inprec_recorddiskchange (i, currprefs.floppyslots[i].df, wp);
                }
                input_record--;
index 1dcf17b813ec995fb9c3093143b9bbf06a1738e6..bc010d5b256e1ede7307a280b9b8f3cac5b96c79 100644 (file)
@@ -206,7 +206,7 @@ void draw_status_line_single(int monid, uae_u8 *buf, int bpp, int y, int totalwi
                                        on_rgb = 0xcc0000;
                                }
                                half = gui_data.drive_side ? 1 : -1;
-                               if (gid->df[0] == 0) {
+                               if (!gid->floppy_inserted) {
                                        pen_rgb = ledcolor(0x00aaaaaa, rc, gc, bc, alpha);
                                } else if (gid->floppy_protected) {
                                        cb = ledcolor(0x00cc00, rc, gc, bc, alpha);