DrvHostFloppy.cpp revision dc0a54940789f994c84390cb4a9f03da0b492285
/** @file
*
* VBox storage devices:
* Host floppy block driver
*/
/*
* Copyright (C) 2006-2007 Oracle Corporation
*
* 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.
*/
/*******************************************************************************
* 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/vmm/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 "VBoxDD.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(RTFileToNative(pThis->hFileDevice), 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(RTFileToNative(pThis->hFileDevice), 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->hFileDevice, 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(RTFileToNative(pThis->hFileDevice), 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 pCfg, uint32_t fFlags)
{
PDRVHOSTFLOPPY pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTFLOPPY);
LogFlow(("drvHostFloppyConstruct: iInstance=%d\n", pDrvIns->iInstance));
/*
* Validate configuration.
*/
if (!CFGMR3AreValuesValid(pCfg, "Path\0ReadOnly\0Interval\0Locked\0BIOSVisible\0"))
return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
/*
* Init instance data.
*/
int rc = DRVHostBaseInitData(pDrvIns, pCfg, 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,
/* szName */
"HostFloppy",
/* szRCMod */
"",
/* szR0Mod */
"",
/* 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,
/* pfnRelocate */
NULL,
/* pfnIOCtl */
NULL,
/* pfnPowerOn */
NULL,
/* pfnReset */
NULL,
/* pfnSuspend */
NULL,
/* pfnResume */
NULL,
/* pfnAttach */
NULL,
/* pfnDetach */
NULL,
/* pfnPowerOff */
NULL,
/* pfnSoftReset */
NULL,
/* u32EndVersion */
PDM_DRVREG_VERSION
};