DrvHostDVD.cpp revision ad27e1d5e48ca41245120c331cc88b50464813ce
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/* $Id$ */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/** @file
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * DrvHostDVD - Host DVD block driver.
3e14f97f673e8a630f076077de35afdd43dc1587Roger A. Faulkner */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin * Copyright (C) 2006-2007 Oracle Corporation
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * This file is part of VirtualBox Open Source Edition (OSE), as
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * available from http://www.virtualbox.org. This file is free software;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * you can redistribute it and/or modify it under the terms of the GNU
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * General Public License (GPL) as published by the Free Software
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Foundation, in version 2 as it comes in the "COPYING" file of the
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*******************************************************************************
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Header Files *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin*******************************************************************************/
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define LOG_GROUP LOG_GROUP_DRV_HOST_DVD
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define __STDC_LIMIT_MACROS
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define __STDC_CONSTANT_MACROS
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#ifdef RT_OS_DARWIN
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# include <mach/mach.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# include <Carbon/Carbon.h>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz# include <IOKit/IOKitLib.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# include <IOKit/IOCFPlugIn.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# include <IOKit/scsi/SCSITaskLib.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# include <IOKit/scsi/SCSICommandOperationCodes.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# include <IOKit/storage/IOStorageDeviceCharacteristics.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# include <mach/mach_error.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# define USE_MEDIA_POLLING
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#elif defined(RT_OS_L4)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/* nothing (yet). */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#elif defined RT_OS_LINUX
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# include <sys/ioctl.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# include <linux/version.h>
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz/* All the following crap is apparently not necessary anymore since Linux
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz * version 2.6.29. */
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz/* This is a hack to work around conflicts between these linux kernel headers
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * and the GLIBC tcpip headers. They have different declarations of the 4
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * standard byte order functions. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# define _LINUX_BYTEORDER_GENERIC_H
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/* This is another hack for not bothering with C++ unfriendly byteswap macros. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/* Those macros that are needed are defined in the header below. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# include "swab.h"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# endif
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# include <linux/cdrom.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# include <sys/fcntl.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# include <errno.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# include <limits.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# include <iprt/mem.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# define USE_MEDIA_POLLING
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#elif defined(RT_OS_SOLARIS)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# include <stropts.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# include <fcntl.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# include <errno.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# include <pwd.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# include <unistd.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# include <syslog.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# ifdef VBOX_WITH_SUID_WRAPPER
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# include <auth_attr.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# endif
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# include <sys/dkio.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# include <sys/sockio.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# include <sys/scsi/scsi.h>
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# define USE_MEDIA_POLLING
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz#elif defined(RT_OS_WINDOWS)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# pragma warning(disable : 4163)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz# define _interlockedbittestandset they_messed_it_up_in_winnt_h_this_time_sigh__interlockedbittestandset
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# define _interlockedbittestandreset they_messed_it_up_in_winnt_h_this_time_sigh__interlockedbittestandreset
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# define _interlockedbittestandset64 they_messed_it_up_in_winnt_h_this_time_sigh__interlockedbittestandset64
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# define _interlockedbittestandreset64 they_messed_it_up_in_winnt_h_this_time_sigh__interlockedbittestandreset64
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# include <Windows.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# include <winioctl.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# include <ntddscsi.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# pragma warning(default : 4163)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# undef _interlockedbittestandset
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# undef _interlockedbittestandreset
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# undef _interlockedbittestandset64
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# undef _interlockedbittestandreset64
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# undef USE_MEDIA_POLLING
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#elif defined(RT_OS_FREEBSD)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# include <sys/cdefs.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# include <sys/param.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# include <stdio.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# include <cam/cam.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# include <cam/cam_ccb.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# define USE_MEDIA_POLLING
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz#else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# error "Unsupported Platform."
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <iprt/asm.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <VBox/pdmdrv.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <iprt/asm.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <iprt/assert.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <iprt/file.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <iprt/string.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <iprt/thread.h>
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin#include <iprt/critsect.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <VBox/scsi.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include "Builtins.h"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include "DrvHostBase.h"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/* Forward declarations. */
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic DECLCALLBACK(int) drvHostDvdDoLock(PDRVHOSTBASE pThis, bool fLock);
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz#ifdef VBOX_WITH_SUID_WRAPPER
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int solarisCheckUserAuth();
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int solarisEnterRootMode(uid_t *pEffUserID);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int solarisExitRootMode(uid_t *pEffUserID);
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz#endif
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/** @copydoc PDMIMOUNT::pfnUnmount */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic DECLCALLBACK(int) drvHostDvdUnmount(PPDMIMOUNT pInterface, bool fForce)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz PDRVHOSTBASE pThis = PDMIMOUNT_2_DRVHOSTBASE(pInterface);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin RTCritSectEnter(&pThis->CritSect);
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Validate state.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz int rc = VINF_SUCCESS;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (!pThis->fLocked || fForce)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Unlock drive if necessary. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (pThis->fLocked)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin drvHostDvdDoLock(pThis, false);
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz * Eject the disc.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin uint8_t abCmd[16] =
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin SCSI_START_STOP_UNIT, 0, 0, 0, 2 /*eject+stop*/, 0,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin 0,0,0,0,0,0,0,0,0,0
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz };
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rc = DRVHostBaseScsiCmd(pThis, abCmd, 6, PDMBLOCKTXDIR_NONE, NULL, NULL, NULL, 0, 0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#elif defined(RT_OS_LINUX)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rc = ioctl(pThis->FileDevice, CDROMEJECT, 0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (rc < 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz if (errno == EBUSY)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rc = VERR_PDM_MEDIA_LOCKED;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz else if (errno == ENOSYS)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rc = VERR_NOT_SUPPORTED;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rc = RTErrConvertFromErrno(errno);
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#elif defined(RT_OS_SOLARIS)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rc = ioctl(pThis->FileRawDevice, DKIOCEJECT, 0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (rc < 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz if (errno == EBUSY)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rc = VERR_PDM_MEDIA_LOCKED;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz else if (errno == ENOSYS || errno == ENOTSUP)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rc = VERR_NOT_SUPPORTED;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if (errno == ENODEV)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rc = VERR_PDM_MEDIA_NOT_MOUNTED;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rc = RTErrConvertFromErrno(errno);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#elif defined(RT_OS_WINDOWS)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin RTFILE FileDevice = pThis->FileDevice;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (FileDevice == NIL_RTFILE) /* obsolete crap */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rc = RTFileOpen(&FileDevice, pThis->pszDeviceOpen, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (RT_SUCCESS(rc))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz /* do ioctl */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin DWORD cbReturned;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz if (DeviceIoControl((HANDLE)FileDevice, IOCTL_STORAGE_EJECT_MEDIA,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin NULL, 0,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin NULL, 0, &cbReturned,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin NULL))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rc = VINF_SUCCESS;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rc = RTErrConvertFromWin32(GetLastError());
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* clean up handle */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (FileDevice != pThis->FileDevice)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin RTFileClose(FileDevice);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin AssertMsgFailed(("Failed to open '%s' for ejecting this tray.\n", rc));
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz#else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin AssertMsgFailed(("Eject is not implemented!\n"));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rc = VINF_SUCCESS;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Media is no longer present.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin DRVHostBaseMediaNotPresent(pThis); /** @todo This isn't thread safe! */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin Log(("drvHostDvdUnmount: Locked\n"));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rc = VERR_PDM_MEDIA_LOCKED;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz RTCritSectLeave(&pThis->CritSect);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin LogFlow(("drvHostDvdUnmount: returns %Rrc\n", rc));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return rc;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/**
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Locks or unlocks the drive.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @returns VBox status code.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @param pThis The instance data.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @param fLock True if the request is to lock the drive, false if to unlock.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic DECLCALLBACK(int) drvHostDvdDoLock(PDRVHOSTBASE pThis, bool fLock)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz uint8_t abCmd[16] =
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL, 0, 0, 0, fLock, 0,
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz 0,0,0,0,0,0,0,0,0,0
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin };
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int rc = DRVHostBaseScsiCmd(pThis, abCmd, 6, PDMBLOCKTXDIR_NONE, NULL, NULL, NULL, 0, 0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#elif defined(RT_OS_LINUX)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int rc = ioctl(pThis->FileDevice, CDROM_LOCKDOOR, (int)fLock);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (rc < 0)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (errno == EBUSY)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rc = VERR_ACCESS_DENIED;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if (errno == EDRIVE_CANT_DO_THIS)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rc = VERR_NOT_SUPPORTED;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz rc = RTErrConvertFromErrno(errno);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#elif defined(RT_OS_SOLARIS)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int rc = ioctl(pThis->FileRawDevice, fLock ? DKIOCLOCK : DKIOCUNLOCK, 0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (rc < 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (errno == EBUSY)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rc = VERR_ACCESS_DENIED;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if (errno == ENOTSUP || errno == ENOSYS)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rc = VERR_NOT_SUPPORTED;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rc = RTErrConvertFromErrno(errno);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#elif defined(RT_OS_WINDOWS)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin PREVENT_MEDIA_REMOVAL PreventMediaRemoval = {fLock};
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz DWORD cbReturned;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz int rc;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (DeviceIoControl((HANDLE)pThis->FileDevice, IOCTL_STORAGE_MEDIA_REMOVAL,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin &PreventMediaRemoval, sizeof(PreventMediaRemoval),
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin NULL, 0, &cbReturned,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin NULL))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rc = VINF_SUCCESS;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /** @todo figure out the return codes for already locked. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rc = RTErrConvertFromWin32(GetLastError());
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin AssertMsgFailed(("Lock/Unlock is not implemented!\n"));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int rc = VINF_SUCCESS;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin LogFlow(("drvHostDvdDoLock(, fLock=%RTbool): returns %Rrc\n", fLock, rc));
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin return rc;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#ifdef RT_OS_LINUX
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/**
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Get the media size.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @returns VBox status code.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @param pThis The instance data.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @param pcb Where to store the size.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int drvHostDvdGetMediaSize(PDRVHOSTBASE pThis, uint64_t *pcb)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Query the media size.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Clear the media-changed-since-last-call-thingy just to be on the safe side. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ioctl(pThis->FileDevice, CDROM_MEDIA_CHANGED, CDSL_CURRENT);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return RTFileSeek(pThis->FileDevice, 0, RTFILE_SEEK_END, pcb);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* RT_OS_LINUX */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#ifdef USE_MEDIA_POLLING
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/**
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz * Do media change polling.
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin */
7c2fbfb345896881c631598ee3852ce9ce33fb07April ChinDECLCALLBACK(int) drvHostDvdPoll(PDRVHOSTBASE pThis)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Poll for media change.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#ifdef RT_OS_DARWIN
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin AssertReturn(pThis->ppScsiTaskDI, VERR_INTERNAL_ERROR);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Issue a TEST UNIT READY request.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin bool fMediaChanged = false;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin bool fMediaPresent = false;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin uint8_t abCmd[16] = { SCSI_TEST_UNIT_READY, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin uint8_t abSense[32];
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int rc2 = DRVHostBaseScsiCmd(pThis, abCmd, 6, PDMBLOCKTXDIR_NONE, NULL, NULL, abSense, sizeof(abSense), 0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (RT_SUCCESS(rc2))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin fMediaPresent = true;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if ( rc2 == VERR_UNRESOLVED_ERROR
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin && abSense[2] == 6 /* unit attention */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin && ( (abSense[12] == 0x29 && abSense[13] < 5 /* reset */)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin || (abSense[12] == 0x2a && abSense[13] == 0 /* parameters changed */) //???
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin || (abSense[12] == 0x3f && abSense[13] == 0 /* target operating conditions have changed */) //???
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin || (abSense[12] == 0x3f && abSense[13] == 2 /* changed operating definition */) //???
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin || (abSense[12] == 0x3f && abSense[13] == 3 /* inquiry parameters changed */)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin || (abSense[12] == 0x3f && abSense[13] == 5 /* device identifier changed */)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin )
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin )
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin fMediaPresent = false;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin fMediaChanged = true;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /** @todo check this media change stuff on Darwin. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#elif defined(RT_OS_LINUX)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin bool fMediaPresent = ioctl(pThis->FileDevice, CDROM_DRIVE_STATUS, CDSL_CURRENT) == CDS_DISC_OK;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#elif defined(RT_OS_SOLARIS)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin bool fMediaPresent = false;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin bool fMediaChanged = false;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Need to pass the previous state and DKIO_NONE for the first time. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin static dkio_state s_DeviceState = DKIO_NONE;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin dkio_state PreviousState = s_DeviceState;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int rc2 = ioctl(pThis->FileRawDevice, DKIOCSTATE, &s_DeviceState);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (rc2 == 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin fMediaPresent = (s_DeviceState == DKIO_INSERTED);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (PreviousState != s_DeviceState)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin fMediaChanged = true;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# error "Unsupported platform."
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin RTCritSectEnter(&pThis->CritSect);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int rc = VINF_SUCCESS;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (pThis->fMediaPresent != fMediaPresent)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin LogFlow(("drvHostDvdPoll: %d -> %d\n", pThis->fMediaPresent, fMediaPresent));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin pThis->fMediaPresent = false;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (fMediaPresent)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rc = DRVHostBaseMediaPresent(pThis);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin DRVHostBaseMediaNotPresent(pThis);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if (fMediaPresent)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Poll for media change.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#if defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* taken care of above. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#elif defined(RT_OS_LINUX)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin bool fMediaChanged = ioctl(pThis->FileDevice, CDROM_MEDIA_CHANGED, CDSL_CURRENT) == 1;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz#else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# error "Unsupported platform."
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (fMediaChanged)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin LogFlow(("drvHostDVDMediaThread: Media changed!\n"));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin DRVHostBaseMediaNotPresent(pThis);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rc = DRVHostBaseMediaPresent(pThis);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin RTCritSectLeave(&pThis->CritSect);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return rc;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* USE_MEDIA_POLLING */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/** @copydoc PDMIBLOCK::pfnSendCmd */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int drvHostDvdSendCmd(PPDMIBLOCK pInterface, const uint8_t *pbCmd,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin PDMBLOCKTXDIR enmTxDir, void *pvBuf, uint32_t *pcbBuf,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin uint8_t *pabSense, size_t cbSense, uint32_t cTimeoutMillies)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin PDRVHOSTBASE pThis = PDMIBLOCK_2_DRVHOSTBASE(pInterface);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int rc;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin LogFlow(("%s: cmd[0]=%#04x txdir=%d pcbBuf=%d timeout=%d\n", __FUNCTION__, pbCmd[0], enmTxDir, *pcbBuf, cTimeoutMillies));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Pass the request on to the internal scsi command interface.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * The command seems to be 12 bytes long, the docs a bit copy&pasty on the command length point...
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (enmTxDir == PDMBLOCKTXDIR_FROM_DEVICE)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin memset(pvBuf, '\0', *pcbBuf); /* we got read size, but zero it anyway. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rc = DRVHostBaseScsiCmd(pThis, pbCmd, 12, PDMBLOCKTXDIR_FROM_DEVICE, pvBuf, pcbBuf, pabSense, cbSense, cTimeoutMillies);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (rc == VERR_UNRESOLVED_ERROR)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* sense information set */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rc = VERR_DEV_IO_ERROR;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#elif defined(RT_OS_L4)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Not really ported to L4 yet. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rc = VERR_INTERNAL_ERROR;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#elif defined(RT_OS_LINUX)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int direction;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin struct cdrom_generic_command cgc;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin switch (enmTxDir)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case PDMBLOCKTXDIR_NONE:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin Assert(*pcbBuf == 0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin direction = CGC_DATA_NONE;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case PDMBLOCKTXDIR_FROM_DEVICE:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin Assert(*pcbBuf != 0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin Assert(*pcbBuf <= SCSI_MAX_BUFFER_SIZE);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Make sure that the buffer is clear for commands reading
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * data. The actually received data may be shorter than what
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz * we expect, and due to the unreliable feedback about how much
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz * data the ioctl actually transferred, it's impossible to
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz * prevent that. Returning previous buffer contents may cause
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * security problems inside the guest OS, if users can issue
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * commands to the CDROM device. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin memset(pThis->pbDoubleBuffer, '\0', *pcbBuf);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin direction = CGC_DATA_READ;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case PDMBLOCKTXDIR_TO_DEVICE:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin Assert(*pcbBuf != 0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin Assert(*pcbBuf <= SCSI_MAX_BUFFER_SIZE);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin memcpy(pThis->pbDoubleBuffer, pvBuf, *pcbBuf);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin direction = CGC_DATA_WRITE;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin default:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin AssertMsgFailed(("enmTxDir invalid!\n"));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin direction = CGC_DATA_NONE;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin memset(&cgc, '\0', sizeof(cgc));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin memcpy(cgc.cmd, pbCmd, CDROM_PACKET_SIZE);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cgc.buffer = (unsigned char *)pThis->pbDoubleBuffer;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cgc.buflen = *pcbBuf;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cgc.stat = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin Assert(cbSense >= sizeof(struct request_sense));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cgc.sense = (struct request_sense *)pabSense;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cgc.data_direction = direction;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cgc.quiet = false;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cgc.timeout = cTimeoutMillies;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rc = ioctl(pThis->FileDevice, CDROM_SEND_PACKET, &cgc);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (rc < 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (errno == EBUSY)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rc = VERR_PDM_MEDIA_LOCKED;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if (errno == ENOSYS)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rc = VERR_NOT_SUPPORTED;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz {
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin rc = RTErrConvertFromErrno(errno);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if (rc == VERR_ACCESS_DENIED && cgc.sense->sense_key == SCSI_SENSE_NONE)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cgc.sense->sense_key = SCSI_SENSE_ILLEGAL_REQUEST;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin Log2(("%s: error status %d, rc=%Rrc\n", __FUNCTION__, cgc.stat, rc));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin switch (enmTxDir)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case PDMBLOCKTXDIR_FROM_DEVICE:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin memcpy(pvBuf, pThis->pbDoubleBuffer, *pcbBuf);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin default:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin Log2(("%s: after ioctl: cgc.buflen=%d txlen=%d\n", __FUNCTION__, cgc.buflen, *pcbBuf));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* The value of cgc.buflen does not reliably reflect the actual amount
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * of data transferred (for packet commands with little data transfer
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz * it's 0). So just assume that everything worked ok. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#elif defined(RT_OS_SOLARIS)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin struct uscsi_cmd usc;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin union scsi_cdb scdb;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin memset(&usc, 0, sizeof(struct uscsi_cmd));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin memset(&scdb, 0, sizeof(scdb));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin switch (enmTxDir)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz {
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin case PDMBLOCKTXDIR_NONE:
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin Assert(*pcbBuf == 0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin usc.uscsi_flags = USCSI_READ;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* nothing to do */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case PDMBLOCKTXDIR_FROM_DEVICE:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin Assert(*pcbBuf != 0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Make sure that the buffer is clear for commands reading
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * data. The actually received data may be shorter than what
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * we expect, and due to the unreliable feedback about how much
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * data the ioctl actually transferred, it's impossible to
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * prevent that. Returning previous buffer contents may cause
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * security problems inside the guest OS, if users can issue
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * commands to the CDROM device. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin memset(pvBuf, '\0', *pcbBuf);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin usc.uscsi_flags = USCSI_READ;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case PDMBLOCKTXDIR_TO_DEVICE:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin Assert(*pcbBuf != 0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin usc.uscsi_flags = USCSI_WRITE;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin default:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin AssertMsgFailedReturn(("%d\n", enmTxDir), VERR_INTERNAL_ERROR);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin usc.uscsi_flags |= USCSI_RQENABLE;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin usc.uscsi_rqbuf = (char *)pabSense;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin usc.uscsi_rqlen = cbSense;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin usc.uscsi_cdb = (caddr_t)&scdb;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin usc.uscsi_cdblen = 12;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin memcpy (usc.uscsi_cdb, pbCmd, usc.uscsi_cdblen);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin usc.uscsi_bufaddr = (caddr_t)pvBuf;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin usc.uscsi_buflen = *pcbBuf;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin usc.uscsi_timeout = (cTimeoutMillies + 999) / 1000;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin /* We need root privileges for user-SCSI under Solaris. */
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin#ifdef VBOX_WITH_SUID_WRAPPER
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin uid_t effUserID = geteuid();
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin solarisEnterRootMode(&effUserID); /** @todo check return code when this really works. */
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin#endif
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin rc = ioctl(pThis->FileRawDevice, USCSICMD, &usc);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin#ifdef VBOX_WITH_SUID_WRAPPER
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin solarisExitRootMode(&effUserID);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (rc < 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (errno == EPERM)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin return VERR_PERMISSION_DENIED;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (usc.uscsi_status)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rc = RTErrConvertFromErrno(errno);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin Log2(("%s: error status. rc=%Rrc\n", __FUNCTION__, rc));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin Log2(("%s: after ioctl: residual buflen=%d original buflen=%d\n", __FUNCTION__, usc.uscsi_resid, usc.uscsi_buflen));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#elif defined(RT_OS_WINDOWS)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int direction;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin struct _REQ
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin SCSI_PASS_THROUGH_DIRECT spt;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin uint8_t aSense[64];
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin } Req;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin DWORD cbReturned = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin switch (enmTxDir)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case PDMBLOCKTXDIR_NONE:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin direction = SCSI_IOCTL_DATA_UNSPECIFIED;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case PDMBLOCKTXDIR_FROM_DEVICE:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin Assert(*pcbBuf != 0);
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz /* Make sure that the buffer is clear for commands reading
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz * data. The actually received data may be shorter than what
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz * we expect, and due to the unreliable feedback about how much
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * data the ioctl actually transferred, it's impossible to
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * prevent that. Returning previous buffer contents may cause
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * security problems inside the guest OS, if users can issue
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * commands to the CDROM device. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin memset(pvBuf, '\0', *pcbBuf);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin direction = SCSI_IOCTL_DATA_IN;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case PDMBLOCKTXDIR_TO_DEVICE:
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin direction = SCSI_IOCTL_DATA_OUT;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin default:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin AssertMsgFailed(("enmTxDir invalid!\n"));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin direction = SCSI_IOCTL_DATA_UNSPECIFIED;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin memset(&Req, '\0', sizeof(Req));
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin Req.spt.Length = sizeof(Req.spt);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin Req.spt.CdbLength = 12;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin memcpy(Req.spt.Cdb, pbCmd, Req.spt.CdbLength);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin Req.spt.DataBuffer = pvBuf;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin Req.spt.DataTransferLength = *pcbBuf;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin Req.spt.DataIn = direction;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin Req.spt.TimeOutValue = (cTimeoutMillies + 999) / 1000; /* Convert to seconds */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin Assert(cbSense <= sizeof(Req.aSense));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin Req.spt.SenseInfoLength = (UCHAR)RT_MIN(sizeof(Req.aSense), cbSense);
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz Req.spt.SenseInfoOffset = RT_OFFSETOF(struct _REQ, aSense);
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz if (DeviceIoControl((HANDLE)pThis->FileDevice, IOCTL_SCSI_PASS_THROUGH_DIRECT,
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz &Req, sizeof(Req), &Req, sizeof(Req), &cbReturned, NULL))
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz {
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz if (cbReturned > RT_OFFSETOF(struct _REQ, aSense))
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz memcpy(pabSense, Req.aSense, cbSense);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz memset(pabSense, '\0', cbSense);
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz /* Windows shares the property of not properly reflecting the actually
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz * transferred data size. See above. Assume that everything worked ok.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz * Except if there are sense information. */
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz rc = (pabSense[2] & 0x0f) == SCSI_SENSE_NONE
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz ? VINF_SUCCESS
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz : VERR_DEV_IO_ERROR;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz else
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz rc = RTErrConvertFromWin32(GetLastError());
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz Log2(("%s: scsistatus=%d bytes returned=%d tlength=%d\n", __FUNCTION__, Req.spt.ScsiStatus, cbReturned, Req.spt.DataTransferLength));
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz#else
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz# error "Unsupported platform."
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (pbCmd[0] == SCSI_GET_EVENT_STATUS_NOTIFICATION)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin uint8_t *pbBuf = (uint8_t*)pvBuf;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin Log2(("Event Status Notification class=%#02x supported classes=%#02x\n", pbBuf[2], pbBuf[3]));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (RT_BE2H_U16(*(uint16_t*)pbBuf) >= 6)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin Log2((" event %#02x %#02x %#02x %#02x\n", pbBuf[4], pbBuf[5], pbBuf[6], pbBuf[7]));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin LogFlow(("%s: rc=%Rrc\n", __FUNCTION__, rc));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return rc;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#ifdef VBOX_WITH_SUID_WRAPPER
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/* These functions would have to go into a separate solaris binary with
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * the setuid permission set, which would run the user-SCSI ioctl and
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * return the value. BUT... this might be prohibitively slow.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# ifdef RT_OS_SOLARIS
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/**
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Checks if the current user is authorized using Solaris' role-based access control.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Made as a separate function with so that it need not be invoked each time we need
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * to gain root access.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @returns VBox error code.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int solarisCheckUserAuth()
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Uses Solaris' role-based access control (RBAC).*/
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin struct passwd *pPass = getpwuid(getuid());
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (pPass == NULL || chkauthattr("solaris.device.cdrw", pPass->pw_name) == 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return VERR_PERMISSION_DENIED;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return VINF_SUCCESS;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/**
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Setuid wrapper to gain root access.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @returns VBox error code.
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz * @param pEffUserID Pointer to effective user ID.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int solarisEnterRootMode(uid_t *pEffUserID)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Increase privilege if required */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (*pEffUserID != 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (seteuid(0) == 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *pEffUserID = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return VINF_SUCCESS;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return VERR_PERMISSION_DENIED;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return VINF_SUCCESS;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/**
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Setuid wrapper to relinquish root access.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @returns VBox error code.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @param pEffUserID Pointer to effective user ID.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int solarisExitRootMode(uid_t *pEffUserID)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Get back to user mode. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (*pEffUserID == 0)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin {
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz uid_t realID = getuid();
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz if (seteuid(realID) == 0)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz {
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz *pEffUserID = realID;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz return VINF_SUCCESS;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz }
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz return VERR_PERMISSION_DENIED;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz }
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz return VINF_SUCCESS;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz}
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz# endif /* RT_OS_SOLARIS */
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz#endif /* VBOX_WITH_SUID_WRAPPER */
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz/* -=-=-=-=- driver interface -=-=-=-=- */
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin/** @copydoc FNPDMDRVDESTRUCT */
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland MainzDECLCALLBACK(void) drvHostDvdDestruct(PPDMDRVINS pDrvIns)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#ifdef RT_OS_LINUX
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin PDRVHOSTBASE pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTBASE);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (pThis->pbDoubleBuffer)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin RTMemFree(pThis->pbDoubleBuffer);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin pThis->pbDoubleBuffer = NULL;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin#endif
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin return DRVHostBaseDestruct(pDrvIns);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/**
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Construct a host dvd drive driver instance.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @copydoc FNPDMDRVCONSTRUCT
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic DECLCALLBACK(int) drvHostDvdConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin PDRVHOSTBASE pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTBASE);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin LogFlow(("drvHostDvdConstruct: iInstance=%d\n", pDrvIns->iInstance));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Validate configuration.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (!CFGMR3AreValuesValid(pCfg, "Path\0Interval\0Locked\0BIOSVisible\0AttachFailError\0Passthrough\0"))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Init instance data.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int rc = DRVHostBaseInitData(pDrvIns, pCfg, PDMBLOCKTYPE_DVD);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (RT_SUCCESS(rc))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Override stuff.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#ifdef RT_OS_LINUX
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin pThis->pbDoubleBuffer = (uint8_t *)RTMemAlloc(SCSI_MAX_BUFFER_SIZE);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (!pThis->pbDoubleBuffer)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return VERR_NO_MEMORY;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#ifndef RT_OS_L4 /* Passthrough is not supported on L4 yet */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin bool fPassthrough;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rc = CFGMR3QueryBool(pCfg, "Passthrough", &fPassthrough);
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz if (RT_SUCCESS(rc) && fPassthrough)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin pThis->IBlock.pfnSendCmd = drvHostDvdSendCmd;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Passthrough requires opening the device in R/W mode. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin pThis->fReadOnlyConfig = false;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# ifdef VBOX_WITH_SUID_WRAPPER /* Solaris setuid for Passthrough mode. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rc = solarisCheckUserAuth();
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (RT_FAILURE(rc))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin Log(("DVD: solarisCheckUserAuth failed. Permission denied!\n"));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return rc;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# endif /* VBOX_WITH_SUID_WRAPPER */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* !RT_OS_L4 */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin pThis->IMount.pfnUnmount = drvHostDvdUnmount;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin pThis->pfnDoLock = drvHostDvdDoLock;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#ifdef USE_MEDIA_POLLING
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (!fPassthrough)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin pThis->pfnPoll = drvHostDvdPoll;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin pThis->pfnPoll = NULL;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#ifdef RT_OS_LINUX
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin pThis->pfnGetMediaSize = drvHostDvdGetMediaSize;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * 2nd init part.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rc = DRVHostBaseInitFinish(pThis);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (RT_FAILURE(rc))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (!pThis->fAttachFailError)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Suppressing the attach failure error must not affect the normal
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * DRVHostBaseDestruct, so reset this flag below before leaving. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin pThis->fKeepInstance = true;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rc = VINF_SUCCESS;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin DRVHostBaseDestruct(pDrvIns);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin pThis->fKeepInstance = false;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin LogFlow(("drvHostDvdConstruct: returns %Rrc\n", rc));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return rc;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/**
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Block driver registration record.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinconst PDMDRVREG g_DrvHostDVD =
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* u32Version */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin PDM_DRVREG_VERSION,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* szName */
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin "HostDVD",
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* szRCMod */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin "",
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* szR0Mod */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin "",
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* pszDescription */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin "Host DVD Block Driver.",
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin /* fFlags */
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin /* fClass. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin PDM_DRVREG_CLASS_BLOCK,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* cMaxInstances */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ~0,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* cbInstance */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sizeof(DRVHOSTBASE),
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* pfnConstruct */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin drvHostDvdConstruct,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* pfnDestruct */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin drvHostDvdDestruct,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* pfnRelocate */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin NULL,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* pfnIOCtl */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin NULL,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* pfnPowerOn */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin NULL,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* pfnReset */
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz NULL,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* pfnSuspend */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin NULL,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* pfnResume */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin NULL,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* pfnAttach */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin NULL,
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz /* pfnDetach */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin NULL,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* pfnPowerOff */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin NULL,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* pfnSoftReset */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin NULL,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* u32EndVersion */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin PDM_DRVREG_VERSION
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin};
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin