summaryrefslogtreecommitdiff
path: root/src/VBox/Devices/Storage/DrvHostFloppy.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/Storage/DrvHostFloppy.cpp')
-rw-r--r--src/VBox/Devices/Storage/DrvHostFloppy.cpp233
1 files changed, 233 insertions, 0 deletions
diff --git a/src/VBox/Devices/Storage/DrvHostFloppy.cpp b/src/VBox/Devices/Storage/DrvHostFloppy.cpp
new file mode 100644
index 000000000..68a706239
--- /dev/null
+++ b/src/VBox/Devices/Storage/DrvHostFloppy.cpp
@@ -0,0 +1,233 @@
+/** @file
+ *
+ * VBox storage devices:
+ * Host floppy block driver
+ */
+
+/*
+ * Copyright (C) 2006-2007 Sun Microsystems, Inc.
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define LOG_GROUP LOG_GROUP_DRV_HOST_FLOPPY
+#ifdef RT_OS_LINUX
+# include <sys/ioctl.h>
+# include <linux/fd.h>
+# include <sys/fcntl.h>
+# include <errno.h>
+
+# elif defined(RT_OS_WINDOWS)
+# include <windows.h>
+# include <dbt.h>
+
+#elif defined(RT_OS_L4)
+
+#else /* !RT_OS_WINDOWS nor RT_OS_LINUX nor RT_OS_L4 */
+# error "Unsupported Platform."
+#endif /* !RT_OS_WINDOWS nor RT_OS_LINUX nor RT_OS_L4 */
+
+#include <VBox/pdmdrv.h>
+#include <iprt/assert.h>
+#include <iprt/file.h>
+#include <iprt/string.h>
+#include <iprt/thread.h>
+#include <iprt/semaphore.h>
+#include <iprt/uuid.h>
+#include <iprt/asm.h>
+#include <iprt/critsect.h>
+
+#include "Builtins.h"
+#include "DrvHostBase.h"
+
+
+/**
+ * Floppy driver instance data.
+ */
+typedef struct DRVHOSTFLOPPY
+{
+ DRVHOSTBASE Base;
+ /** Previous poll status. */
+ bool fPrevDiskIn;
+
+} DRVHOSTFLOPPY, *PDRVHOSTFLOPPY;
+
+
+
+#ifdef RT_OS_LINUX
+/**
+ * Get media size and do change processing.
+ *
+ * @param pThis The instance data.
+ */
+static DECLCALLBACK(int) drvHostFloppyGetMediaSize(PDRVHOSTBASE pThis, uint64_t *pcb)
+{
+ int rc = ioctl(pThis->FileDevice, FDFLUSH);
+ if (rc)
+ {
+ rc = RTErrConvertFromErrno (errno);
+ Log(("DrvHostFloppy: FDFLUSH ioctl(%s) failed, errno=%d rc=%Rrc\n", pThis->pszDevice, errno, rc));
+ return rc;
+ }
+
+ floppy_drive_struct DrvStat;
+ rc = ioctl(pThis->FileDevice, FDGETDRVSTAT, &DrvStat);
+ if (rc)
+ {
+ rc = RTErrConvertFromErrno(errno);
+ Log(("DrvHostFloppy: FDGETDRVSTAT ioctl(%s) failed, errno=%d rc=%Rrc\n", pThis->pszDevice, errno, rc));
+ return rc;
+ }
+ pThis->fReadOnly = !(DrvStat.flags & FD_DISK_WRITABLE);
+
+ return RTFileSeek(pThis->FileDevice, 0, RTFILE_SEEK_END, pcb);
+}
+#endif /* RT_OS_LINUX */
+
+
+#ifdef RT_OS_LINUX
+/**
+ * This thread will periodically poll the Floppy for media presence.
+ *
+ * @returns Ignored.
+ * @param ThreadSelf Handle of this thread. Ignored.
+ * @param pvUser Pointer to the driver instance structure.
+ */
+static DECLCALLBACK(int) drvHostFloppyPoll(PDRVHOSTBASE pThis)
+{
+ PDRVHOSTFLOPPY pThisFloppy = (PDRVHOSTFLOPPY)pThis;
+ floppy_drive_struct DrvStat;
+ int rc = ioctl(pThis->FileDevice, FDPOLLDRVSTAT, &DrvStat);
+ if (rc)
+ return RTErrConvertFromErrno(errno);
+
+ RTCritSectEnter(&pThis->CritSect);
+ bool fDiskIn = !(DrvStat.flags & (FD_VERIFY | FD_DISK_NEWCHANGE));
+ if ( fDiskIn
+ && !pThisFloppy->fPrevDiskIn)
+ {
+ if (pThis->fMediaPresent)
+ DRVHostBaseMediaNotPresent(pThis);
+ rc = DRVHostBaseMediaPresent(pThis);
+ if (RT_FAILURE(rc))
+ {
+ pThisFloppy->fPrevDiskIn = fDiskIn;
+ RTCritSectLeave(&pThis->CritSect);
+ return rc;
+ }
+ }
+
+ if ( !fDiskIn
+ && pThisFloppy->fPrevDiskIn
+ && pThis->fMediaPresent)
+ DRVHostBaseMediaNotPresent(pThis);
+ pThisFloppy->fPrevDiskIn = fDiskIn;
+
+ RTCritSectLeave(&pThis->CritSect);
+ return VINF_SUCCESS;
+}
+#endif /* RT_OS_LINUX */
+
+
+/**
+ * @copydoc FNPDMDRVCONSTRUCT
+ */
+static DECLCALLBACK(int) drvHostFloppyConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle)
+{
+ PDRVHOSTFLOPPY pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTFLOPPY);
+ LogFlow(("drvHostFloppyConstruct: iInstance=%d\n", pDrvIns->iInstance));
+
+ /*
+ * Validate configuration.
+ */
+ if (!CFGMR3AreValuesValid(pCfgHandle, "Path\0ReadOnly\0Interval\0Locked\0BIOSVisible\0"))
+ return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
+
+ /*
+ * Init instance data.
+ */
+ int rc = DRVHostBaseInitData(pDrvIns, pCfgHandle, PDMBLOCKTYPE_FLOPPY_1_44);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Override stuff.
+ */
+#ifdef RT_OS_LINUX
+ pThis->Base.pfnPoll = drvHostFloppyPoll;
+ pThis->Base.pfnGetMediaSize = drvHostFloppyGetMediaSize;
+#endif
+
+ /*
+ * 2nd init part.
+ */
+ rc = DRVHostBaseInitFinish(&pThis->Base);
+ }
+ if (RT_FAILURE(rc))
+ {
+ if (!pThis->Base.fAttachFailError)
+ {
+ /* Suppressing the attach failure error must not affect the normal
+ * DRVHostBaseDestruct, so reset this flag below before leaving. */
+ pThis->Base.fKeepInstance = true;
+ rc = VINF_SUCCESS;
+ }
+ DRVHostBaseDestruct(pDrvIns);
+ pThis->Base.fKeepInstance = false;
+ }
+
+ LogFlow(("drvHostFloppyConstruct: returns %Rrc\n", rc));
+ return rc;
+}
+
+
+/**
+ * Block driver registration record.
+ */
+const PDMDRVREG g_DrvHostFloppy =
+{
+ /* u32Version */
+ PDM_DRVREG_VERSION,
+ /* szDriverName */
+ "HostFloppy",
+ /* pszDescription */
+ "Host Floppy Block Driver.",
+ /* fFlags */
+ PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
+ /* fClass. */
+ PDM_DRVREG_CLASS_BLOCK,
+ /* cMaxInstances */
+ ~0,
+ /* cbInstance */
+ sizeof(DRVHOSTFLOPPY),
+ /* pfnConstruct */
+ drvHostFloppyConstruct,
+ /* pfnDestruct */
+ DRVHostBaseDestruct,
+ /* pfnIOCtl */
+ NULL,
+ /* pfnPowerOn */
+ NULL,
+ /* pfnReset */
+ NULL,
+ /* pfnSuspend */
+ NULL,
+ /* pfnResume */
+ NULL,
+ /* pfnDetach */
+ NULL
+};
+