Currently, fd_revalidate is called in two different places, with two
different expectations of behavior:

(1) On initialization, as a routine to help pick the drive type and
    initial geometries as a side-effect of the pick_geometry routine

(2) On insert/eject, which either sets the geometries to a default value
    or chooses new geometries based on the inserted diskette.

Break this nonsense apart by creating a new function dedicated towards
picking the drive type on initialization.

This has a few results:

(1) fd_revalidate does not get called on boot anymore for drives with no
    diskette.

(2) pick_geometry will actually get called twice if we have a diskette
    inserted, but this is harmless. (Once for the drive type, and once
    as part of the media callback.)

Signed-off-by: John Snow <js...@redhat.com>
---
 hw/block/fdc.c | 36 +++++++++++++++++++++++++++++-------
 1 file changed, 29 insertions(+), 7 deletions(-)

diff --git a/hw/block/fdc.c b/hw/block/fdc.c
index b587de8..e752758 100644
--- a/hw/block/fdc.c
+++ b/hw/block/fdc.c
@@ -167,6 +167,7 @@ static void fd_init(FDrive *drv)
     drv->disk = FLOPPY_DRIVE_TYPE_NONE;
     drv->last_sect = 0;
     drv->max_track = 0;
+    drv->ro = true;
 }
 
 #define NUM_SIDES(drv) ((drv)->flags & FDISK_DBL_SIDES ? 2 : 1)
@@ -249,13 +250,21 @@ static void fd_recalibrate(FDrive *drv)
     fd_seek(drv, 0, 0, 1, 1);
 }
 
-static void pick_geometry(FDrive *drv)
+/**
+ * Determine geometry based on inserted diskette.
+ */
+static bool pick_geometry(FDrive *drv)
 {
     BlockBackend *blk = drv->blk;
     const FDFormat *parse;
     uint64_t nb_sectors, size;
     int i, first_match, match;
 
+    /* We can only pick a geometry if we have a diskette. */
+    if (!drv->media_inserted) {
+        return false;
+    }
+
     blk_get_geometry(blk, &nb_sectors);
     match = -1;
     first_match = -1;
@@ -293,8 +302,7 @@ static void pick_geometry(FDrive *drv)
     }
     drv->max_track = parse->max_track;
     drv->last_sect = parse->last_sect;
-    drv->drive = parse->drive;
-    drv->disk = drv->media_inserted ? parse->drive : FLOPPY_DRIVE_TYPE_NONE;
+    drv->disk = parse->drive;
     drv->media_rate = parse->rate;
 
     if (drv->media_inserted) {
@@ -303,6 +311,14 @@ static void pick_geometry(FDrive *drv)
                        drv->max_track, drv->last_sect,
                        drv->ro ? "ro" : "rw");
     }
+    return true;
+}
+
+static void pick_drive_type(FDrive *drv)
+{
+    if (pick_geometry(drv)) {
+        drv->drive = drv->disk;
+    }
 }
 
 /* Revalidate a disk drive after a disk change */
@@ -311,15 +327,18 @@ static void fd_revalidate(FDrive *drv)
     FLOPPY_DPRINTF("revalidate\n");
     if (drv->blk != NULL) {
         drv->ro = blk_is_read_only(drv->blk);
-        pick_geometry(drv);
         if (!drv->media_inserted) {
             FLOPPY_DPRINTF("No disk in drive\n");
+            drv->disk = FLOPPY_DRIVE_TYPE_NONE;
+        } else {
+            pick_geometry(drv);
         }
     } else {
         FLOPPY_DPRINTF("No drive connected\n");
         drv->last_sect = 0;
         drv->max_track = 0;
         drv->flags &= ~FDISK_DBL_SIDES;
+        drv->disk = FLOPPY_DRIVE_TYPE_NONE;
     }
 }
 
@@ -2196,9 +2215,11 @@ static void fdctrl_change_cb(void *opaque, bool load)
     FDrive *drive = opaque;
 
     drive->media_inserted = load && drive->blk && blk_is_inserted(drive->blk);
-
     drive->media_changed = 1;
-    fd_revalidate(drive);
+
+    if (load) {
+        fd_revalidate(drive);
+    }
 }
 
 static bool fdctrl_is_tray_open(void *opaque)
@@ -2234,13 +2255,14 @@ static void fdctrl_connect_drives(FDCtrl *fdctrl, Error 
**errp)
         }
 
         fd_init(drive);
-        fdctrl_change_cb(drive, 0);
         if (drive->blk) {
             blk_set_dev_ops(drive->blk, &fdctrl_block_ops, drive);
             drive->media_inserted = blk_is_inserted(drive->blk);
+            pick_drive_type(drive);
         } else {
             drive->drive = FLOPPY_DRIVE_TYPE_NONE;
         }
+        fdctrl_change_cb(drive, drive->media_inserted);
     }
 }
 
-- 
2.4.3


Reply via email to