DrvHostDVD.cpp revision 32d9080d823b14f35920f7aa1ac55dfe2c139744
0N/A/** @file
0N/A *
0N/A * VBox storage devices:
0N/A * Host DVD block driver
0N/A */
0N/A
0N/A/*
0N/A * Copyright (C) 2006 InnoTek Systemberatung GmbH
0N/A *
0N/A * This file is part of VirtualBox Open Source Edition (OSE), as
0N/A * available from http://www.virtualbox.org. This file is free software;
0N/A * you can redistribute it and/or modify it under the terms of the GNU
0N/A * General Public License as published by the Free Software Foundation,
0N/A * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
0N/A * distribution. VirtualBox OSE is distributed in the hope that it will
0N/A * be useful, but WITHOUT ANY WARRANTY of any kind.
0N/A *
0N/A * If you received this file as part of a commercial VirtualBox
873N/A * distribution, then only the terms of your commercial VirtualBox
0N/A * license agreement apply instead of the previous paragraph.
0N/A */
0N/A
0N/A
0N/A/*******************************************************************************
5061N/A* Header Files *
6062N/A*******************************************************************************/
0N/A#define LOG_GROUP LOG_GROUP_DRV_HOST_DVD
0N/A#ifdef __DARWIN__
4134N/A# include <mach/mach.h>
0N/A# include <Carbon/Carbon.h>
0N/A# include <IOKit/IOKitLib.h>
4677N/A# include <IOKit/IOCFPlugIn.h>
546N/A# include <IOKit/scsi-commands/SCSITaskLib.h>
546N/A# include <IOKit/scsi-commands/SCSICommandOperationCodes.h>
4677N/A# include <IOKit/storage/IOStorageDeviceCharacteristics.h>
0N/A# include <mach/mach_error.h>
0N/A# define USE_MEDIA_POLLING
4069N/A
0N/A#elif defined(__L4ENV__)
0N/A/* nothing (yet). */
4134N/A
4069N/A#elif defined __LINUX__
4069N/A# include <sys/ioctl.h>
4069N/A/* This is a hack to work around conflicts between these linux kernel headers
4069N/A * and the GLIBC tcpip headers. They have different declarations of the 4
4069N/A * standard byte order functions. */
4069N/A# define _LINUX_BYTEORDER_GENERIC_H
0N/A/* This is another hack for not bothering with C++ unfriendly byteswap macros. */
4069N/A# define _LINUX_BYTEORDER_SWAB_H
4069N/A/* Those macros that are needed are defined in the header below */
4069N/A# include "swab.h"
0N/A# include <linux/cdrom.h>
0N/A# include <sys/fcntl.h>
0N/A# include <errno.h>
0N/A# define USE_MEDIA_POLLING
4069N/A
421N/A#elif defined(__WIN__)
4134N/A# include <Windows.h>
0N/A# include <winioctl.h>
546N/A# include <ntddscsi.h>
0N/A# undef USE_MEDIA_POLLING
4069N/A
4069N/A#else
338N/A# error "Unsupported Platform."
338N/A#endif
546N/A
4069N/A#include <VBox/pdm.h>
6250N/A#include <VBox/cfgm.h>
0N/A#include <VBox/err.h>
0N/A
0N/A#include <VBox/log.h>
0N/A#include <iprt/assert.h>
0N/A#include <iprt/file.h>
0N/A#include <iprt/string.h>
6062N/A#include <iprt/thread.h>
6062N/A#include <iprt/critsect.h>
6062N/A#include <VBox/scsi.h>
6062N/A
6062N/A#include "Builtins.h"
6062N/A#include "DrvHostBase.h"
6062N/A
6062N/A
6062N/A
0N/A
0N/A/** @copydoc PDMIMOUNT::pfnUnmount */
0N/Astatic DECLCALLBACK(int) drvHostDvdUnmount(PPDMIMOUNT pInterface)
0N/A{
0N/A PDRVHOSTBASE pThis = PDMIMOUNT_2_DRVHOSTBASE(pInterface);
0N/A RTCritSectEnter(&pThis->CritSect);
0N/A
0N/A /*
0N/A * Validate state.
0N/A */
0N/A int rc = VINF_SUCCESS;
0N/A if (!pThis->fLocked)
4069N/A {
4069N/A /*
4069N/A * Eject the disc.
4069N/A */
4069N/A#ifdef __DARWIN__
4069N/A uint8_t abCmd[16] =
4069N/A {
0N/A SCSI_START_STOP_UNIT, 0, 0, 0, 2 /*eject+stop*/, 0,
0N/A 0,0,0,0,0,0,0,0,0,0
0N/A };
0N/A rc = DRVHostBaseScsiCmd(pThis, abCmd, 6, PDMBLOCKTXDIR_NONE, NULL, NULL, NULL, 0, 0);
0N/A
0N/A#elif defined(__LINUX__)
0N/A rc = ioctl(pThis->FileDevice, CDROMEJECT, 0);
546N/A if (rc < 0)
546N/A {
546N/A if (errno == EBUSY)
1727N/A rc = VERR_PDM_MEDIA_LOCKED;
546N/A else if (errno == ENOSYS)
546N/A rc = VERR_NOT_SUPPORTED;
546N/A else
546N/A rc = RTErrConvertFromErrno(errno);
546N/A }
546N/A
546N/A#elif defined(__WIN__)
546N/A RTFILE FileDevice = pThis->FileDevice;
546N/A if (FileDevice == NIL_RTFILE) /* obsolete crap */
546N/A rc = RTFileOpen(&FileDevice, pThis->pszDeviceOpen, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
546N/A if (VBOX_SUCCESS(rc))
546N/A {
546N/A /* do ioctl */
546N/A DWORD cbReturned;
546N/A if (DeviceIoControl((HANDLE)FileDevice, IOCTL_STORAGE_EJECT_MEDIA,
546N/A NULL, 0,
546N/A NULL, 0, &cbReturned,
546N/A NULL))
546N/A rc = VINF_SUCCESS;
546N/A else
546N/A rc = RTErrConvertFromWin32(GetLastError());
546N/A
546N/A /* clean up handle */
546N/A if (FileDevice != pThis->FileDevice)
546N/A RTFileClose(FileDevice);
546N/A }
546N/A else
546N/A AssertMsgFailed(("Failed to open '%s' for ejecting this tray.\n", rc));
546N/A
546N/A
546N/A#else
546N/A AssertMsgFailed(("Eject is not implemented!\n"));
546N/A rc = VINF_SUCCESS;
546N/A#endif
546N/A
546N/A /*
546N/A * Media is no longer present.
546N/A */
546N/A DRVHostBaseMediaNotPresent(pThis); /** @todo This isn't thread safe! */
546N/A }
546N/A else
546N/A {
546N/A Log(("drvHostDvdUnmount: Locked\n"));
546N/A rc = VERR_PDM_MEDIA_LOCKED;
546N/A }
546N/A
546N/A RTCritSectLeave(&pThis->CritSect);
546N/A LogFlow(("drvHostDvdUnmount: returns %Vrc\n", rc));
546N/A return rc;
546N/A}
546N/A
546N/A
546N/A/**
546N/A * Locks or unlocks the drive.
546N/A *
546N/A * @returns VBox status code.
546N/A * @param pThis The instance data.
546N/A * @param fLock True if the request is to lock the drive, false if to unlock.
0N/A */
546N/Astatic DECLCALLBACK(int) drvHostDvdDoLock(PDRVHOSTBASE pThis, bool fLock)
546N/A{
546N/A#ifdef __DARWIN__
546N/A# if 0 /// @todo dig up the specification for this command and implement it. (not important on mac)
4677N/A uint8_t abCmd[16] =
546N/A {
546N/A SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL, 0, 0, 0, 0, 0,
546N/A 0,0,0,0,0,0,0,0,0,0
546N/A };
546N/A int rc = DRVHostBaseScsiCmd(pThis, abCmd, 6, PDMBLOCKTXDIR_NONE, NULL, NULL, NULL, 0, 0);
546N/A# else
546N/A int rc = VINF_SUCCESS;
0N/A# endif
0N/A
0N/A#elif defined(__LINUX__)
2086N/A int rc = ioctl(pThis->FileDevice, CDROM_LOCKDOOR, (int)fLock);
0N/A if (rc < 0)
536N/A {
536N/A if (errno == EBUSY)
0N/A rc = VERR_ACCESS_DENIED;
0N/A else if (errno == EDRIVE_CANT_DO_THIS)
0N/A rc = VERR_NOT_SUPPORTED;
0N/A else
0N/A rc = RTErrConvertFromErrno(errno);
0N/A }
2086N/A
2086N/A#elif defined(__WIN__)
2086N/A
0N/A PREVENT_MEDIA_REMOVAL PreventMediaRemoval = {fLock};
0N/A DWORD cbReturned;
4677N/A int rc;
4677N/A if (DeviceIoControl((HANDLE)pThis->FileDevice, IOCTL_STORAGE_MEDIA_REMOVAL,
4677N/A &PreventMediaRemoval, sizeof(PreventMediaRemoval),
4677N/A NULL, 0, &cbReturned,
4677N/A NULL))
0N/A rc = VINF_SUCCESS;
0N/A else
3220N/A /** @todo figure out the return codes for already locked. */
3220N/A rc = RTErrConvertFromWin32(GetLastError());
2086N/A
0N/A#else
0N/A AssertMsgFailed(("Lock/Unlock is not implemented!\n"));
0N/A int rc = VINF_SUCCESS;
0N/A
1060N/A#endif
3220N/A
2086N/A LogFlow(("drvHostDvdDoLock(, fLock=%RTbool): returns %Vrc\n", fLock, rc));
0N/A return rc;
0N/A}
0N/A
2086N/A
2086N/A
3220N/A#ifdef __LINUX__
2086N/A/**
2086N/A * Get the media size.
0N/A *
0N/A * @returns VBox status code.
0N/A * @param pThis The instance data.
0N/A * @param pcb Where to store the size.
0N/A */
3220N/Astatic int drvHostDvdGetMediaSize(PDRVHOSTBASE pThis, uint64_t *pcb)
3220N/A{
2086N/A /*
0N/A * Query the media size.
0N/A */
0N/A /* Clear the media-changed-since-last-call-thingy just to be on the safe side. */
1060N/A ioctl(pThis->FileDevice, CDROM_MEDIA_CHANGED, CDSL_CURRENT);
1060N/A return RTFileSeek(pThis->FileDevice, 0, RTFILE_SEEK_END, pcb);
1060N/A
3220N/A}
0N/A#endif /* __LINUX__ */
2086N/A
534N/A
0N/A#ifdef USE_MEDIA_POLLING
0N/A/**
0N/A * Do media change polling.
1060N/A */
3220N/ADECLCALLBACK(int) drvHostDvdPoll(PDRVHOSTBASE pThis)
3220N/A{
0N/A /*
2086N/A * Poll for media change.
534N/A */
0N/A#ifdef __DARWIN__
0N/A AssertReturn(pThis->ppScsiTaskDI, VERR_INTERNAL_ERROR);
0N/A
0N/A /*
3220N/A * Issue a TEST UNIT READY request.
3220N/A */
3220N/A bool fMediaChanged = false;
2086N/A bool fMediaPresent = false;
0N/A uint8_t abCmd[16] = { SCSI_TEST_UNIT_READY, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
0N/A uint8_t abSense[32];
0N/A int rc2 = DRVHostBaseScsiCmd(pThis, abCmd, 6, PDMBLOCKTXDIR_NONE, NULL, NULL, abSense, sizeof(abSense), 0);
2086N/A if (VBOX_SUCCESS(rc2))
2086N/A fMediaPresent = true;
2086N/A else if ( rc2 == VERR_UNRESOLVED_ERROR
2086N/A && abSense[2] == 6 /* unit attention */
0N/A && ( (abSense[12] == 0x29 && abSense[13] < 5 /* reset */)
0N/A || (abSense[12] == 0x2a && abSense[13] == 0 /* parameters changed */) //???
0N/A || (abSense[12] == 0x3f && abSense[13] == 0 /* target operating conditions have changed */) //???
546N/A || (abSense[12] == 0x3f && abSense[13] == 2 /* changed operating definition */) //???
546N/A || (abSense[12] == 0x3f && abSense[13] == 3 /* inquery parameters changed */)
546N/A || (abSense[12] == 0x3f && abSense[13] == 5 /* device identifier changed */)
2086N/A )
546N/A )
546N/A {
546N/A fMediaPresent = false;
1060N/A fMediaChanged = true;
1060N/A /** @todo check this media chance stuff on Darwin. */
2086N/A }
0N/A
546N/A#elif defined(__LINUX__)
0N/A bool fMediaPresent = ioctl(pThis->FileDevice, CDROM_DRIVE_STATUS, CDSL_CURRENT) == CDS_DISC_OK;
0N/A
0N/A#else
2086N/A# error "Unsupported platform."
0N/A#endif
546N/A
6062N/A RTCritSectEnter(&pThis->CritSect);
0N/A
0N/A int rc = VINF_SUCCESS;
0N/A if (pThis->fMediaPresent != fMediaPresent)
0N/A {
0N/A LogFlow(("drvHostDvdPoll: %d -> %d\n", pThis->fMediaPresent, fMediaPresent));
0N/A pThis->fMediaPresent = false;
0N/A if (fMediaPresent)
0N/A rc = DRVHostBaseMediaPresent(pThis);
0N/A else
0N/A DRVHostBaseMediaNotPresent(pThis);
2086N/A }
0N/A else if (fMediaPresent)
546N/A {
546N/A /*
6062N/A * Poll for media change.
546N/A */
546N/A#ifdef __DARWIN__
546N/A /* taken care of above. */
1340N/A#elif defined(__LINUX__)
1340N/A bool fMediaChanged = ioctl(pThis->FileDevice, CDROM_MEDIA_CHANGED, CDSL_CURRENT) == 1;
1340N/A#else
546N/A# error "Unsupported platform."
6062N/A#endif
0N/A if (fMediaChanged)
0N/A {
6250N/A LogFlow(("drvHostDVDMediaThread: Media changed!\n"));
6250N/A DRVHostBaseMediaNotPresent(pThis);
6250N/A rc = DRVHostBaseMediaPresent(pThis);
6250N/A }
6250N/A }
6250N/A
6250N/A RTCritSectLeave(&pThis->CritSect);
6250N/A return rc;
6250N/A}
6250N/A#endif /* USE_MEDIA_POLLING */
0N/A
546N/A
546N/A/** @copydoc PDMIBLOCK::pfnSendCmd */
0N/Astatic int drvHostDvdSendCmd(PPDMIBLOCK pInterface, const uint8_t *pbCmd, PDMBLOCKTXDIR enmTxDir, void *pvBuf, size_t *pcbBuf,
2086N/A uint8_t *pbStat, uint32_t cTimeoutMillies)
2086N/A{
546N/A PDRVHOSTBASE pThis = PDMIBLOCK_2_DRVHOSTBASE(pInterface);
546N/A int rc;
6062N/A LogFlow(("%s: cmd[0]=%#04x txdir=%d pcbBuf=%d timeout=%d\n", __FUNCTION__, pbCmd[0], enmTxDir, *pcbBuf, cTimeoutMillies));
546N/A
546N/A#ifdef __DARWIN__
4677N/A /*
4677N/A * Pass the request on to the internal scsi command interface.
4677N/A * The command seems to be 12 bytes long, the docs a bit copy&pasty on the command length point...
4677N/A */
4677N/A if (enmTxDir == PDMBLOCKTXDIR_FROM_DEVICE)
4677N/A memset(pvBuf, '\0', *pcbBuf); /* we got read size, but zero it anyway. */
6062N/A uint8_t abSense[32];
4677N/A rc = DRVHostBaseScsiCmd(pThis, pbCmd, 12, PDMBLOCKTXDIR_FROM_DEVICE, pvBuf, pcbBuf, abSense, sizeof(abSense), cTimeoutMillies);
4677N/A if (rc == VERR_UNRESOLVED_ERROR)
4677N/A {
4677N/A *pbStat = abSense[2] & 0x0f;
4677N/A rc = VINF_SUCCESS;
4677N/A }
4677N/A
4677N/A#elif defined(__L4ENV__)
4677N/A /* Not really ported to L4 yet. */
6062N/A rc = VERR_INTERNAL_ERROR;
4677N/A
4677N/A#elif defined(__LINUX__)
546N/A int direction;
546N/A struct cdrom_generic_command cgc;
2086N/A request_sense sense;
2086N/A
546N/A switch (enmTxDir)
546N/A {
6062N/A case PDMBLOCKTXDIR_NONE:
0N/A Assert(*pcbBuf == 0);
0N/A direction = CGC_DATA_NONE;
0N/A break;
546N/A case PDMBLOCKTXDIR_FROM_DEVICE:
546N/A Assert(*pcbBuf != 0);
546N/A /* Make sure that the buffer is clear for commands reading
4134N/A * data. The actually received data may be shorter than what
0N/A * we expect, and due to the unreliable feedback about how much
0N/A * data the ioctl actually transferred, it's impossible to
1200N/A * prevent that. Returning previous buffer contents may cause
1200N/A * security problems inside the guest OS, if users can issue
0N/A * commands to the CDROM device. */
2086N/A memset(pvBuf, '\0', *pcbBuf);
2086N/A direction = CGC_DATA_READ;
546N/A break;
546N/A case PDMBLOCKTXDIR_TO_DEVICE:
6062N/A Assert(*pcbBuf != 0);
0N/A direction = CGC_DATA_WRITE;
0N/A break;
0N/A default:
0N/A AssertMsgFailed(("enmTxDir invalid!\n"));
0N/A direction = CGC_DATA_NONE;
0N/A }
0N/A memset(&cgc, '\0', sizeof(cgc));
0N/A memcpy(cgc.cmd, pbCmd, CDROM_PACKET_SIZE);
0N/A cgc.buffer = (unsigned char *)pvBuf;
0N/A cgc.buflen = *pcbBuf;
0N/A cgc.stat = 0;
4134N/A cgc.sense = &sense;
0N/A cgc.data_direction = direction;
1200N/A cgc.quiet = false;
1200N/A cgc.timeout = cTimeoutMillies;
1200N/A rc = ioctl(pThis->FileDevice, CDROM_SEND_PACKET, &cgc);
4134N/A if (rc < 0)
1200N/A {
0N/A if (errno == EBUSY)
0N/A rc = VERR_PDM_MEDIA_LOCKED;
0N/A else if (errno == ENOSYS)
0N/A rc = VERR_NOT_SUPPORTED;
0N/A else
0N/A {
0N/A if (rc == VERR_ACCESS_DENIED && cgc.sense->sense_key == SCSI_SENSE_NONE)
0N/A cgc.sense->sense_key = SCSI_SENSE_ILLEGAL_REQUEST;
0N/A *pbStat = cgc.sense->sense_key;
0N/A rc = RTErrConvertFromErrno(errno);
546N/A Log2(("%s: error status %d, rc=%Vrc\n", __FUNCTION__, cgc.stat, rc));
0N/A }
546N/A }
546N/A Log2(("%s: after ioctl: cgc.buflen=%d txlen=%d\n", __FUNCTION__, cgc.buflen, *pcbBuf));
4134N/A /* The value of cgc.buflen does not reliably reflect the actual amount
4134N/A * of data transferred (for packet commands with little data transfer
546N/A * it's 0). So just assume that everything worked ok. */
546N/A
546N/A#elif defined(__WIN__)
2086N/A int direction;
2086N/A struct _REQ
546N/A {
6062N/A SCSI_PASS_THROUGH_DIRECT spt;
546N/A uint8_t aSense[18];
546N/A } Req;
546N/A DWORD cbReturned = 0;
546N/A
546N/A switch (enmTxDir)
546N/A {
546N/A case PDMBLOCKTXDIR_NONE:
546N/A direction = SCSI_IOCTL_DATA_UNSPECIFIED;
546N/A break;
2086N/A case PDMBLOCKTXDIR_FROM_DEVICE:
546N/A Assert(*pcbBuf != 0);
6062N/A /* Make sure that the buffer is clear for commands reading
546N/A * data. The actually received data may be shorter than what
546N/A * we expect, and due to the unreliable feedback about how much
546N/A * data the ioctl actually transferred, it's impossible to
2086N/A * prevent that. Returning previous buffer contents may cause
546N/A * security problems inside the guest OS, if users can issue
6062N/A * commands to the CDROM device. */
546N/A memset(pvBuf, '\0', *pcbBuf);
0N/A direction = SCSI_IOCTL_DATA_IN;
0N/A break;
0N/A case PDMBLOCKTXDIR_TO_DEVICE:
546N/A direction = SCSI_IOCTL_DATA_OUT;
546N/A break;
546N/A default:
546N/A AssertMsgFailed(("enmTxDir invalid!\n"));
546N/A direction = SCSI_IOCTL_DATA_UNSPECIFIED;
546N/A }
546N/A memset(&Req, '\0', sizeof(Req));
2086N/A Req.spt.Length = sizeof(Req.spt);
546N/A Req.spt.CdbLength = 12;
6062N/A memcpy(Req.spt.Cdb, pbCmd, Req.spt.CdbLength);
546N/A Req.spt.DataBuffer = pvBuf;
546N/A Req.spt.DataTransferLength = *pcbBuf;
546N/A Req.spt.DataIn = direction;
2086N/A Req.spt.TimeOutValue = (cTimeoutMillies + 999) / 1000; /* Convert to seconds */
546N/A Req.spt.SenseInfoLength = sizeof(Req.aSense);
6062N/A Req.spt.SenseInfoOffset = RT_OFFSETOF(struct _REQ, aSense);
546N/A if (DeviceIoControl((HANDLE)pThis->FileDevice, IOCTL_SCSI_PASS_THROUGH_DIRECT,
546N/A &Req, sizeof(Req), &Req, sizeof(Req), &cbReturned, NULL))
546N/A {
2086N/A if (cbReturned > RT_OFFSETOF(struct _REQ, aSense))
546N/A *pbStat = Req.aSense[2] & 0x0f;
6062N/A else
546N/A *pbStat = 0;
0N/A /* Windows shares the property of not properly reflecting the actually
0N/A * transferred data size. See above. Assume that everything worked ok. */
546N/A rc = VINF_SUCCESS;
546N/A }
546N/A else
546N/A rc = RTErrConvertFromWin32(GetLastError());
546N/A Log2(("%s: scsistatus=%d bytes returned=%d tlength=%d\n", __FUNCTION__, Req.spt.ScsiStatus, cbReturned, Req.spt.DataTransferLength));
546N/A
546N/A#else
546N/A# error "Unsupported platform."
2086N/A#endif
2086N/A LogFlow(("%s: rc=%Vrc\n", __FUNCTION__, rc));
546N/A return rc;
6062N/A}
546N/A
546N/A
546N/A/* -=-=-=-=- driver interface -=-=-=-=- */
2086N/A
2086N/A
546N/A/**
6062N/A * Construct a host dvd drive driver instance.
546N/A *
546N/A * @returns VBox status.
546N/A * @param pDrvIns The driver instance data.
2086N/A * If the registration structure is needed, pDrvIns->pDrvReg points to it.
2086N/A * @param pCfgHandle Configuration node handle for the driver. Use this to obtain the configuration
546N/A * of the driver instance. It's also found in pDrvIns->pCfgHandle, but like
6062N/A * iInstance it's expected to be used a bit in this function.
546N/A */
0N/Astatic DECLCALLBACK(int) drvHostDvdConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle)
0N/A{
4069N/A PDRVHOSTBASE pThis = PDMINS2DATA(pDrvIns, PDRVHOSTBASE);
4069N/A LogFlow(("drvHostDvdConstruct: iInstance=%d\n", pDrvIns->iInstance));
4069N/A
546N/A /*
546N/A * Validate configuration.
546N/A */
546N/A if (!CFGMR3AreValuesValid(pCfgHandle, "Path\0Interval\0Locked\0BIOSVisible\0Passthrough\0"))
546N/A return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
546N/A
546N/A
546N/A /*
546N/A * Init instance data.
2086N/A */
2086N/A int rc = DRVHostBaseInitData(pDrvIns, pCfgHandle, PDMBLOCKTYPE_DVD);
2086N/A if (VBOX_SUCCESS(rc))
546N/A {
6062N/A /*
546N/A * Override stuff.
546N/A */
546N/A
2086N/A#ifndef __L4ENV__ /* Passthrough is not supported on L4 yet */
2086N/A bool fPassthrough;
546N/A rc = CFGMR3QueryBool(pCfgHandle, "Passthrough", &fPassthrough);
6062N/A if (VBOX_SUCCESS(rc) && fPassthrough)
546N/A {
546N/A pThis->IBlock.pfnSendCmd = drvHostDvdSendCmd;
546N/A /* Passthrough requires opening the device in R/W mode. */
2086N/A pThis->fReadOnlyConfig = false;
2086N/A }
546N/A#endif /* !__L4ENV__ */
6062N/A
546N/A pThis->IMount.pfnUnmount = drvHostDvdUnmount;
0N/A pThis->pfnDoLock = drvHostDvdDoLock;
0N/A#ifdef USE_MEDIA_POLLING
0N/A if (!fPassthrough)
0N/A pThis->pfnPoll = drvHostDvdPoll;
0N/A else
0N/A pThis->pfnPoll = NULL;
0N/A#endif
0N/A#ifdef __LINUX__
0N/A pThis->pfnGetMediaSize = drvHostDvdGetMediaSize;
0N/A#endif
0N/A
0N/A /*
2086N/A * 2nd init part.
546N/A */
0N/A rc = DRVHostBaseInitFinish(pThis);
0N/A if (VBOX_SUCCESS(rc))
0N/A {
0N/A LogFlow(("drvHostDvdConstruct: return %Vrc\n", rc));
0N/A return rc;
0N/A }
5065N/A }
0N/A DRVHostBaseDestruct(pDrvIns);
0N/A
0N/A LogFlow(("drvHostDvdConstruct: returns %Vrc\n", rc));
0N/A return rc;
0N/A}
0N/A
0N/A
0N/A/**
0N/A * Block driver registration record.
0N/A */
546N/Aconst PDMDRVREG g_DrvHostDVD =
0N/A{
0N/A /* u32Version */
0N/A PDM_DRVREG_VERSION,
6062N/A /* szDriverName */
0N/A "HostDVD",
0N/A /* pszDescription */
0N/A "Host DVD Block Driver.",
0N/A /* fFlags */
0N/A PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
0N/A /* fClass. */
0N/A PDM_DRVREG_CLASS_BLOCK,
2086N/A /* cMaxInstances */
546N/A ~0,
0N/A /* cbInstance */
0N/A sizeof(DRVHOSTBASE),
0N/A /* pfnConstruct */
0N/A drvHostDvdConstruct,
0N/A /* pfnDestruct */
0N/A DRVHostBaseDestruct,
5065N/A /* pfnIOCtl */
0N/A NULL,
0N/A /* pfnPowerOn */
0N/A NULL,
0N/A /* pfnReset */
0N/A NULL,
0N/A /* pfnSuspend */
0N/A NULL,
0N/A /* pfnResume */
0N/A NULL,
0N/A /* pfnDetach */
546N/A NULL
0N/A};
0N/A
0N/A