When using host drive (e.g., /dev/fd0) qemu does not detect physical drive if
it is empty. This causes a Windows guest, specifically w2k, to drop the
floppy drive altogether at start-up.
The need to see the disk image before determining the emulated drive type
makes sense for images, but not much for a host drive. The attached patch
short-circuits the initialization process to allow host drive types to reach
the emulated controller hardware. It has been tested and works for W98, W2k,
and Linux guest images.
diff -Naur qemu-0.9.0/block-raw.c qemu-0.9.0-flpy2/block-raw.c
--- qemu-0.9.0/block-raw.c 2007-02-05 15:01:54.000000000 -0800
+++ qemu-0.9.0-flpy2/block-raw.c 2007-02-13 05:14:49.000000000 -0800
@@ -75,11 +75,17 @@
int fd_open_flags;
int64_t fd_open_time;
int64_t fd_error_time;
- int fd_got_error;
- int fd_media_changed;
+ int fd_got_error:1;
+ int fd_media_changed:1;
+ int fd_have_probe:1;
+ int fd_drive_type:4;
#endif
} BDRVRawState;
+#if defined(__linux__) && !defined(QEMU_TOOL)
+extern int *global_floppy_hack_ptr;
+#endif
+
static int fd_open(BlockDriverState *bs);
static int raw_open(BlockDriverState *bs, const char *filename, int flags)
@@ -556,6 +562,9 @@
{
BDRVRawState *s = bs->opaque;
int fd, open_flags, ret;
+#if defined(__linux__)
+ struct floppy_drive_params drive_info;
+#endif
#ifdef CONFIG_COCOA
if (strstart(filename, "/dev/cdrom", NULL)) {
@@ -593,6 +602,9 @@
s->type = FTYPE_FILE;
#if defined(__linux__)
+ s->fd_got_error = 0;
+ s->fd_media_changed = 0;
+ s->fd_have_probe = 0;
if (strstart(filename, "/dev/cd", NULL)) {
/* open will not fail even if no CD is inserted */
open_flags |= O_NONBLOCK;
@@ -615,6 +627,17 @@
#if defined(__linux__)
/* close fd so that we can reopen it as needed */
if (s->type == FTYPE_FD) {
+#if !defined(QEMU_TOOL)
+ if (s->fd_have_probe == 0) {
+ /* Find out what hardware we are dealing with */
+ if (ioctl(s->fd,FDGETDRVPRM,&drive_info) == 0) {
+ s->fd_have_probe = 1;
+ s->fd_drive_type = drive_info.cmos;
+ /* Tell emulated controller about the drive */
+ *global_floppy_hack_ptr = drive_info.cmos;
+ }
+ }
+#endif
close(s->fd);
s->fd = -1;
s->fd_media_changed = 1;
diff -Naur qemu-0.9.0/hw/fdc.c qemu-0.9.0-flpy2/hw/fdc.c
--- qemu-0.9.0/hw/fdc.c 2007-02-05 15:01:54.000000000 -0800
+++ qemu-0.9.0-flpy2/hw/fdc.c 2007-02-13 19:17:11.000000000 -0800
@@ -93,11 +93,43 @@
uint8_t ro; /* Is read-only */
} fdrive_t;
+#ifdef __linux__
+#define FD_HACK_NO_DRIVE -1
+
+extern int global_fd_hack_tbl[];
+
+static void fd_init (fdrive_t *drv, BlockDriverState *bs, int dflt_drive_type)
+#else
static void fd_init (fdrive_t *drv, BlockDriverState *bs)
+#endif
{
/* Drive */
drv->bs = bs;
+#ifdef __linux__
+ switch(dflt_drive_type) {
+ /*XXX
+ The DRIVE_NONE entries should probably be USER
+ defined with appropriate hints entries.
+ XXX*/
+ case 0: /* unknown */
+ drv->drive = FDRIVE_DRV_NONE; break;
+ case 1: /* 360K PC */
+ drv->drive = FDRIVE_DRV_NONE; break;
+ case 2: /* 1.2M */
+ drv->drive = FDRIVE_DRV_120; break;
+ case 3: /* 720k */
+ drv->drive = FDRIVE_DRV_NONE; break;
+ case 4: /* 1.44M */
+ drv->drive = FDRIVE_DRV_144; break;
+ case 5: /* 2.88M */
+ drv->drive = FDRIVE_DRV_288; break;
+ default:
+ case FD_HACK_NO_DRIVE:
+ drv->drive = FDRIVE_DRV_NONE; break;
+ }
+#else
drv->drive = FDRIVE_DRV_NONE;
+#endif
drv->drflags = 0;
drv->perpendicular = 0;
/* Disk */
@@ -512,7 +544,11 @@
fdctrl->dma_en = 0;
}
for (i = 0; i < 2; i++) {
+#ifdef __linux__
+ fd_init(&fdctrl->drives[i], fds[i], global_fd_hack_tbl[i]);
+#else
fd_init(&fdctrl->drives[i], fds[i]);
+#endif
}
fdctrl_reset(fdctrl, 0);
fdctrl->state = FD_CTRL_ACTIVE;
diff -Naur qemu-0.9.0/vl.c qemu-0.9.0-flpy2/vl.c
--- qemu-0.9.0/vl.c 2007-02-05 15:01:54.000000000 -0800
+++ qemu-0.9.0-flpy2/vl.c 2007-02-13 03:20:02.000000000 -0800
@@ -174,6 +174,12 @@
int semihosting_enabled = 0;
int autostart = 1;
+#ifdef __linux__
+#define FD_HACK_NO_DRIVE -1
+int global_fd_hack_tbl[MAX_FD];
+int *global_floppy_hack_ptr;
+#endif
+
/***********************************************************/
/* x86 ISA bus support */
@@ -7135,6 +7141,10 @@
bdrv_set_type_hint(fd_table[i], BDRV_TYPE_FLOPPY);
}
if (fd_filename[i] != '\0') {
+#ifdef __linux__
+ global_fd_hack_tbl[i] = FD_HACK_NO_DRIVE;
+ global_floppy_hack_ptr = &global_fd_hack_tbl[i];
+#endif
if (bdrv_open(fd_table[i], fd_filename[i],
snapshot ? BDRV_O_SNAPSHOT : 0) < 0) {
fprintf(stderr, "qemu: could not open floppy disk image '%s'\n",