VirtualBox

Changeset 64316 in vbox for trunk/src


Ignore:
Timestamp:
Oct 19, 2016 11:59:42 AM (8 years ago)
Author:
vboxsync
Message:

Devices/Storage/DrvHost*: Move host dependent members of DRVHOSTBASE into a private struct for each host to keep including host dependent headers in one file for each host

Location:
trunk/src/VBox/Devices/Storage
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Storage/DrvHostBase-darwin.cpp

    r64278 r64316  
    2727#include <VBox/scsi.h>
    2828
     29/**
     30 * Host backend specific data.
     31 */
     32typedef struct DRVHOSTBASEOS
     33{
     34    /** The master port. */
     35    mach_port_t             MasterPort;
     36    /** The MMC-2 Device Interface. (This is only used to get the scsi task interface.) */
     37    MMCDeviceInterface      **ppMMCDI;
     38    /** The SCSI Task Device Interface. */
     39    SCSITaskDeviceInterface **ppScsiTaskDI;
     40    /** The block size. Set when querying the media size. */
     41    uint32_t                cbBlock;
     42    /** The disk arbitration session reference. NULL if we didn't have to claim & unmount the device. */
     43    DASessionRef            pDASession;
     44    /** The disk arbitration disk reference. NULL if we didn't have to claim & unmount the device. */
     45    DADiskRef               pDADisk;
     46    /** The number of errors that could go into the release log. (flood gate) */
     47    uint32_t                cLogRelErrors;
     48} DRVHOSTBASEOS;
     49/** Pointer to the host backend specific data. */
     50typedef DRVHOSTBASEOS *PDRVHOSBASEOS;
     51AssertCompile(sizeof(DRVHOSTBASEOS) <= 64);
     52
     53#define DRVHOSTBASE_OS_INT_DECLARED
    2954#include "DrvHostBase.h"
     55
     56/** The runloop input source name for the disk arbitration events. */
     57# define MY_RUN_LOOP_MODE    CFSTR("drvHostBaseDA") /** @todo r=bird: Check if this will cause trouble in the same way that the one in the USB code did. */
     58
     59/**
     60 * Gets the BSD Name (/dev/disc[0-9]+) for the service.
     61 *
     62 * This is done by recursing down the I/O registry until we hit upon an entry
     63 * with a BSD Name. Usually we find it two levels down. (Further down under
     64 * the IOCDPartitionScheme, the volume (slices) BSD Name is found. We don't
     65 * seem to have to go this far fortunately.)
     66 *
     67 * @return  VINF_SUCCESS if found, VERR_FILE_NOT_FOUND otherwise.
     68 * @param   Entry       The current I/O registry entry reference.
     69 * @param   pszName     Where to store the name. 128 bytes.
     70 * @param   cRecursions Number of recursions. This is used as an precaution
     71 *                      just to limit the depth and avoid blowing the stack
     72 *                      should we hit a bug or something.
     73 */
     74static int drvHostBaseGetBSDName(io_registry_entry_t Entry, char *pszName, unsigned cRecursions)
     75{
     76    int rc = VERR_FILE_NOT_FOUND;
     77    io_iterator_t Children = 0;
     78    kern_return_t krc = IORegistryEntryGetChildIterator(Entry, kIOServicePlane, &Children);
     79    if (krc == KERN_SUCCESS)
     80    {
     81        io_object_t Child;
     82        while (     rc == VERR_FILE_NOT_FOUND
     83               &&   (Child = IOIteratorNext(Children)) != 0)
     84        {
     85            CFStringRef BSDNameStrRef = (CFStringRef)IORegistryEntryCreateCFProperty(Child, CFSTR(kIOBSDNameKey), kCFAllocatorDefault, 0);
     86            if (BSDNameStrRef)
     87            {
     88                if (CFStringGetCString(BSDNameStrRef, pszName, 128, kCFStringEncodingUTF8))
     89                    rc = VINF_SUCCESS;
     90                else
     91                    AssertFailed();
     92                CFRelease(BSDNameStrRef);
     93            }
     94            if (rc == VERR_FILE_NOT_FOUND && cRecursions < 10)
     95                rc = drvHostBaseGetBSDName(Child, pszName, cRecursions + 1);
     96            IOObjectRelease(Child);
     97        }
     98        IOObjectRelease(Children);
     99    }
     100    return rc;
     101}
     102
     103
     104/**
     105 * Callback notifying us that the async DADiskClaim()/DADiskUnmount call has completed.
     106 *
     107 * @param   DiskRef         The disk that was attempted claimed / unmounted.
     108 * @param   DissenterRef    NULL on success, contains details on failure.
     109 * @param   pvContext       Pointer to the return code variable.
     110 */
     111static void drvHostBaseDADoneCallback(DADiskRef DiskRef, DADissenterRef DissenterRef, void *pvContext)
     112{
     113    RT_NOREF(DiskRef);
     114    int *prc = (int *)pvContext;
     115    if (!DissenterRef)
     116        *prc = 0;
     117    else
     118        *prc = DADissenterGetStatus(DissenterRef) ? DADissenterGetStatus(DissenterRef) : -1;
     119    CFRunLoopStop(CFRunLoopGetCurrent());
     120}
     121
     122
     123/**
     124 * Obtain exclusive access to the DVD device, umount it if necessary.
     125 *
     126 * @return  VBox status code.
     127 * @param   pThis       The driver instance.
     128 * @param   DVDService  The DVD service object.
     129 */
     130static int drvHostBaseObtainExclusiveAccess(PDRVHOSTBASE pThis, io_object_t DVDService)
     131{
     132    PPDMDRVINS pDrvIns = pThis->pDrvIns; NOREF(pDrvIns);
     133
     134    for (unsigned iTry = 0;; iTry++)
     135    {
     136        IOReturn irc = (*pThis->Os.ppScsiTaskDI)->ObtainExclusiveAccess(pThis->Os.ppScsiTaskDI);
     137        if (irc == kIOReturnSuccess)
     138        {
     139            /*
     140             * This is a bit weird, but if we unmounted the DVD drive we also need to
     141             * unlock it afterwards or the guest won't be able to eject it later on.
     142             */
     143            if (pThis->Os.pDADisk)
     144            {
     145                uint8_t abCmd[16] =
     146                {
     147                    SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL, 0, 0, 0, false, 0,
     148                    0,0,0,0,0,0,0,0,0,0
     149                };
     150                drvHostBaseScsiCmdOs(pThis, abCmd, 6, PDMMEDIATXDIR_NONE, NULL, NULL, NULL, 0, 0);
     151            }
     152            return VINF_SUCCESS;
     153        }
     154        if (irc == kIOReturnExclusiveAccess)
     155            return VERR_SHARING_VIOLATION;      /* already used exclusivly. */
     156        if (irc != kIOReturnBusy)
     157            return VERR_GENERAL_FAILURE;        /* not mounted */
     158
     159        /*
     160         * Attempt to the unmount all volumes of the device.
     161         * It seems we can can do this all in one go without having to enumerate the
     162         * volumes (sessions) and deal with them one by one. This is very fortuitous
     163         * as the disk arbitration API is a bit cumbersome to deal with.
     164         */
     165        if (iTry > 2)
     166            return VERR_DRIVE_LOCKED;
     167        char szName[128];
     168        int rc = drvHostBaseGetBSDName(DVDService, &szName[0], 0);
     169        if (RT_SUCCESS(rc))
     170        {
     171            pThis->Os.pDASession = DASessionCreate(kCFAllocatorDefault);
     172            if (pThis->Os.pDASession)
     173            {
     174                DASessionScheduleWithRunLoop(pThis->Os.pDASession, CFRunLoopGetCurrent(), MY_RUN_LOOP_MODE);
     175                pThis->Os.pDADisk = DADiskCreateFromBSDName(kCFAllocatorDefault, pThis->Os.pDASession, szName);
     176                if (pThis->Os.pDADisk)
     177                {
     178                    /*
     179                     * Try claim the device.
     180                     */
     181                    Log(("%s-%d: calling DADiskClaim on '%s'.\n", pDrvIns->pReg->szName, pDrvIns->iInstance, szName));
     182                    int rcDA = -2;
     183                    DADiskClaim(pThis->Os.pDADisk, kDADiskClaimOptionDefault, NULL, NULL, drvHostBaseDADoneCallback, &rcDA);
     184                    SInt32 rc32 = CFRunLoopRunInMode(MY_RUN_LOOP_MODE, 120.0, FALSE);
     185                    AssertMsg(rc32 == kCFRunLoopRunStopped, ("rc32=%RI32 (%RX32)\n", rc32, rc32));
     186                    if (    rc32 == kCFRunLoopRunStopped
     187                        &&  !rcDA)
     188                    {
     189                        /*
     190                         * Try unmount the device.
     191                         */
     192                        Log(("%s-%d: calling DADiskUnmount on '%s'.\n", pDrvIns->pReg->szName, pDrvIns->iInstance, szName));
     193                        rcDA = -2;
     194                        DADiskUnmount(pThis->Os.pDADisk, kDADiskUnmountOptionWhole, drvHostBaseDADoneCallback, &rcDA);
     195                        rc32 = CFRunLoopRunInMode(MY_RUN_LOOP_MODE, 120.0, FALSE);
     196                        AssertMsg(rc32 == kCFRunLoopRunStopped, ("rc32=%RI32 (%RX32)\n", rc32, rc32));
     197                        if (    rc32 == kCFRunLoopRunStopped
     198                            &&  !rcDA)
     199                        {
     200                            iTry = 99;
     201                            DASessionUnscheduleFromRunLoop(pThis->Os.pDASession, CFRunLoopGetCurrent(), MY_RUN_LOOP_MODE);
     202                            Log(("%s-%d: unmount succeed - retrying.\n", pDrvIns->pReg->szName, pDrvIns->iInstance));
     203                            continue;
     204                        }
     205                        Log(("%s-%d: umount => rc32=%d & rcDA=%#x\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc32, rcDA));
     206
     207                        /* failed - cleanup */
     208                        DADiskUnclaim(pThis->Os.pDADisk);
     209                    }
     210                    else
     211                        Log(("%s-%d: claim => rc32=%d & rcDA=%#x\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc32, rcDA));
     212
     213                    CFRelease(pThis->Os.pDADisk);
     214                    pThis->Os.pDADisk = NULL;
     215                }
     216                else
     217                    Log(("%s-%d: failed to open disk '%s'!\n", pDrvIns->pReg->szName, pDrvIns->iInstance, szName));
     218
     219                DASessionUnscheduleFromRunLoop(pThis->Os.pDASession, CFRunLoopGetCurrent(), MY_RUN_LOOP_MODE);
     220                CFRelease(pThis->Os.pDASession);
     221                pThis->Os.pDASession = NULL;
     222            }
     223            else
     224                Log(("%s-%d: failed to create DA session!\n", pDrvIns->pReg->szName, pDrvIns->iInstance));
     225        }
     226        RTThreadSleep(10);
     227    }
     228}
    30229
    31230DECLHIDDEN(int) drvHostBaseScsiCmdOs(PDRVHOSTBASE pThis, const uint8_t *pbCmd, size_t cbCmd, PDMMEDIATXDIR enmTxDir,
     
    45244        *pcbBuf = 0;
    46245
    47     Assert(pThis->ppScsiTaskDI);
     246    Assert(pThis->Os.ppScsiTaskDI);
    48247
    49248    int rc = VERR_GENERAL_FAILURE;
    50     SCSITaskInterface **ppScsiTaskI = (*pThis->ppScsiTaskDI)->CreateSCSITask(pThis->ppScsiTaskDI);
     249    SCSITaskInterface **ppScsiTaskI = (*pThis->Os.ppScsiTaskDI)->CreateSCSITask(pThis->Os.ppScsiTaskDI);
    51250    if (!ppScsiTaskI)
    52251        return VERR_NO_MEMORY;
     
    110309               ? VERR_READ_ERROR
    111310               : VERR_WRITE_ERROR;
    112             if (pThis->cLogRelErrors++ < 10)
     311            if (pThis->Os.cLogRelErrors++ < 10)
    113312                LogRel(("DVD scsi error: cmd={%.*Rhxs} TaskStatus=%#x key=%#x ASC=%#x ASCQ=%#x (%Rrc)\n",
    114313                        cbCmd, pbCmd, TaskStatus, SenseData.SENSE_KEY, SenseData.ADDITIONAL_SENSE_CODE,
     
    147346        //if (Buf.cbBlock > 2048) /* everyone else is doing this... check if it needed/right.*/
    148347        //    Buf.cbBlock = 2048;
    149         pThis->cbBlock = Buf.cbBlock;
     348        pThis->Os.cbBlock = Buf.cbBlock;
    150349
    151350        *pcb = (uint64_t)Buf.cBlocks * Buf.cbBlock;
     
    159358    int rc = VINF_SUCCESS;
    160359
    161     if (    pThis->ppScsiTaskDI
    162         &&  pThis->cbBlock)
     360    if (    pThis->Os.ppScsiTaskDI
     361        &&  pThis->Os.cbBlock)
    163362    {
    164363        /*
     
    167366        do
    168367        {
    169             const uint32_t  LBA       = off / pThis->cbBlock;
    170             AssertReturn(!(off % pThis->cbBlock), VERR_INVALID_PARAMETER);
     368            const uint32_t  LBA       = off / pThis->Os.cbBlock;
     369            AssertReturn(!(off % pThis->Os.cbBlock), VERR_INVALID_PARAMETER);
    171370            uint32_t        cbRead32  =   cbRead > SCSI_MAX_BUFFER_SIZE
    172371                                        ? SCSI_MAX_BUFFER_SIZE
    173372                                        : (uint32_t)cbRead;
    174             const uint32_t  cBlocks   = cbRead32 / pThis->cbBlock;
    175             AssertReturn(!(cbRead % pThis->cbBlock), VERR_INVALID_PARAMETER);
     373            const uint32_t  cBlocks   = cbRead32 / pThis->Os.cbBlock;
     374            AssertReturn(!(cbRead % pThis->Os.cbBlock), VERR_INVALID_PARAMETER);
    176375            uint8_t         abCmd[16] =
    177376            {
     
    233432DECLHIDDEN(int) drvHostBaseQueryMediaStatusOs(PDRVHOSTBASE pThis, bool *pfMediaChanged, bool *pfMediaPresent)
    234433{
    235     AssertReturn(pThis->ppScsiTaskDI, VERR_INTERNAL_ERROR);
     434    AssertReturn(pThis->Os.ppScsiTaskDI, VERR_INTERNAL_ERROR);
    236435
    237436    /*
     
    266465
    267466
    268 DECLHIDDEN(int) drvHostBasePollerWakeupOs(PDRVHOSTBASE pThis)
    269 {
    270     return RTSemEventSignal(pThis->EventPoller);
     467DECLHIDDEN(void) drvHostBaseInitOs(PDRVHOSTBASE pThis)
     468{
     469    pThis->Os.MasterPort   = IO_OBJECT_NULL;
     470    pThis->Os.ppMMCDI      = NULL;
     471    pThis->Os.ppScsiTaskDI = NULL;
     472    pThis->Os.cbBlock      = 0;
     473    pThis->Os.pDADisk      = NULL;
     474    pThis->Os.pDASession   = NULL;
     475}
     476
     477
     478DECLHIDDEN(int) drvHostBaseOpenOs(PDRVHOSTBASE pThis, bool fReadOnly)
     479{
     480    RT_NOREF(fReadOnly);
     481
     482    /* Darwin is kind of special... */
     483    Assert(!pThis->Os.cbBlock);
     484    Assert(pThis->Os.MasterPort == IO_OBJECT_NULL);
     485    Assert(!pThis->Os.ppMMCDI);
     486    Assert(!pThis->Os.ppScsiTaskDI);
     487
     488    /*
     489     * Open the master port on the first invocation.
     490     */
     491    kern_return_t krc = IOMasterPort(MACH_PORT_NULL, &pThis->Os.MasterPort);
     492    AssertReturn(krc == KERN_SUCCESS, VERR_GENERAL_FAILURE);
     493
     494    /*
     495     * Create a matching dictionary for searching for CD, DVD and BlueRay services in the IOKit.
     496     *
     497     * The idea is to find all the devices which are of class IOCDBlockStorageDevice.
     498     * CD devices are represented by IOCDBlockStorageDevice class itself, while DVD and BlueRay ones
     499     * have it as a parent class.
     500     */
     501    CFMutableDictionaryRef RefMatchingDict = IOServiceMatching("IOCDBlockStorageDevice");
     502    AssertReturn(RefMatchingDict, VERR_NOT_FOUND);
     503
     504    /*
     505     * do the search and get a collection of keyboards.
     506     */
     507    io_iterator_t DVDServices = IO_OBJECT_NULL;
     508    IOReturn irc = IOServiceGetMatchingServices(pThis->Os.MasterPort, RefMatchingDict, &DVDServices);
     509    AssertMsgReturn(irc == kIOReturnSuccess, ("irc=%d\n", irc), VERR_NOT_FOUND);
     510    RefMatchingDict = NULL; /* the reference is consumed by IOServiceGetMatchingServices. */
     511
     512    /*
     513     * Enumerate the matching drives (services).
     514     * (This enumeration must be identical to the one performed in Main/src-server/darwin/iokit.cpp.)
     515     */
     516    int rc = VERR_FILE_NOT_FOUND;
     517    unsigned i = 0;
     518    io_object_t DVDService;
     519    while ((DVDService = IOIteratorNext(DVDServices)) != 0)
     520    {
     521        /*
     522         * Get the properties we use to identify the DVD drive.
     523         *
     524         * While there is a (weird 12 byte) GUID, it isn't persistent
     525         * across boots. So, we have to use a combination of the
     526         * vendor name and product name properties with an optional
     527         * sequence number for identification.
     528         */
     529        CFMutableDictionaryRef PropsRef = 0;
     530        krc = IORegistryEntryCreateCFProperties(DVDService, &PropsRef, kCFAllocatorDefault, kNilOptions);
     531        if (krc == KERN_SUCCESS)
     532        {
     533            /* Get the Device Characteristics dictionary. */
     534            CFDictionaryRef DevCharRef = (CFDictionaryRef)CFDictionaryGetValue(PropsRef, CFSTR(kIOPropertyDeviceCharacteristicsKey));
     535            if (DevCharRef)
     536            {
     537                /* The vendor name. */
     538                char szVendor[128];
     539                char *pszVendor = &szVendor[0];
     540                CFTypeRef ValueRef = CFDictionaryGetValue(DevCharRef, CFSTR(kIOPropertyVendorNameKey));
     541                if (    ValueRef
     542                    &&  CFGetTypeID(ValueRef) == CFStringGetTypeID()
     543                    &&  CFStringGetCString((CFStringRef)ValueRef, szVendor, sizeof(szVendor), kCFStringEncodingUTF8))
     544                    pszVendor = RTStrStrip(szVendor);
     545                else
     546                    *pszVendor = '\0';
     547
     548                /* The product name. */
     549                char szProduct[128];
     550                char *pszProduct = &szProduct[0];
     551                ValueRef = CFDictionaryGetValue(DevCharRef, CFSTR(kIOPropertyProductNameKey));
     552                if (    ValueRef
     553                    &&  CFGetTypeID(ValueRef) == CFStringGetTypeID()
     554                    &&  CFStringGetCString((CFStringRef)ValueRef, szProduct, sizeof(szProduct), kCFStringEncodingUTF8))
     555                    pszProduct = RTStrStrip(szProduct);
     556                else
     557                    *pszProduct = '\0';
     558
     559                /* Construct the two names and compare thwm with the one we're searching for. */
     560                char szName1[256 + 32];
     561                char szName2[256 + 32];
     562                if (*pszVendor || *pszProduct)
     563                {
     564                    if (*pszVendor && *pszProduct)
     565                    {
     566                        RTStrPrintf(szName1, sizeof(szName1), "%s %s", pszVendor, pszProduct);
     567                        RTStrPrintf(szName2, sizeof(szName2), "%s %s (#%u)", pszVendor, pszProduct, i);
     568                    }
     569                    else
     570                    {
     571                        strcpy(szName1, *pszVendor ? pszVendor : pszProduct);
     572                        RTStrPrintf(szName2, sizeof(szName2), "%s (#%u)", *pszVendor ? pszVendor : pszProduct, i);
     573                    }
     574                }
     575                else
     576                {
     577                    RTStrPrintf(szName1, sizeof(szName1), "(#%u)", i);
     578                    strcpy(szName2, szName1);
     579                }
     580
     581                if (    !strcmp(szName1, pThis->pszDevice)
     582                    ||  !strcmp(szName2, pThis->pszDevice))
     583                {
     584                    /*
     585                     * Found it! Now, get the client interface and stuff.
     586                     * Note that we could also query kIOSCSITaskDeviceUserClientTypeID here if the
     587                     * MMC client plugin is missing. For now we assume this won't be necessary.
     588                     */
     589                    SInt32 Score = 0;
     590                    IOCFPlugInInterface **ppPlugInInterface = NULL;
     591                    krc = IOCreatePlugInInterfaceForService(DVDService, kIOMMCDeviceUserClientTypeID, kIOCFPlugInInterfaceID,
     592                                                            &ppPlugInInterface, &Score);
     593                    if (krc == KERN_SUCCESS)
     594                    {
     595                        HRESULT hrc = (*ppPlugInInterface)->QueryInterface(ppPlugInInterface,
     596                                                                           CFUUIDGetUUIDBytes(kIOMMCDeviceInterfaceID),
     597                                                                           (LPVOID *)&pThis->Os.ppMMCDI);
     598                        (*ppPlugInInterface)->Release(ppPlugInInterface);
     599                        ppPlugInInterface = NULL;
     600                        if (hrc == S_OK)
     601                        {
     602                            pThis->Os.ppScsiTaskDI = (*pThis->Os.ppMMCDI)->GetSCSITaskDeviceInterface(pThis->Os.ppMMCDI);
     603                            if (pThis->Os.ppScsiTaskDI)
     604                                rc = VINF_SUCCESS;
     605                            else
     606                            {
     607                                LogRel(("GetSCSITaskDeviceInterface failed on '%s'\n", pThis->pszDevice));
     608                                rc = VERR_NOT_SUPPORTED;
     609                                (*pThis->Os.ppMMCDI)->Release(pThis->Os.ppMMCDI);
     610                            }
     611                        }
     612                        else
     613                        {
     614                            rc = VERR_GENERAL_FAILURE;//RTErrConvertFromDarwinCOM(krc);
     615                            pThis->Os.ppMMCDI = NULL;
     616                        }
     617                    }
     618                    else /* Check for kIOSCSITaskDeviceUserClientTypeID? */
     619                        rc = VERR_GENERAL_FAILURE;//RTErrConvertFromDarwinKern(krc);
     620
     621                    /* Obtain exclusive access to the device so we can send SCSI commands. */
     622                    if (RT_SUCCESS(rc))
     623                        rc = drvHostBaseObtainExclusiveAccess(pThis, DVDService);
     624
     625                    /* Cleanup on failure. */
     626                    if (RT_FAILURE(rc))
     627                    {
     628                        if (pThis->Os.ppScsiTaskDI)
     629                        {
     630                            (*pThis->Os.ppScsiTaskDI)->Release(pThis->Os.ppScsiTaskDI);
     631                            pThis->Os.ppScsiTaskDI = NULL;
     632                        }
     633                        if (pThis->Os.ppMMCDI)
     634                        {
     635                            (*pThis->Os.ppMMCDI)->Release(pThis->Os.ppMMCDI);
     636                            pThis->Os.ppMMCDI = NULL;
     637                        }
     638                    }
     639
     640                    IOObjectRelease(DVDService);
     641                    break;
     642                }
     643            }
     644            CFRelease(PropsRef);
     645        }
     646        else
     647            AssertMsgFailed(("krc=%#x\n", krc));
     648
     649        IOObjectRelease(DVDService);
     650        i++;
     651    }
     652
     653    IOObjectRelease(DVDServices);
     654    return rc;
     655
     656}
     657
     658
     659DECLHIDDEN(int) drvHostBaseMediaRefreshOs(PDRVHOSTBASE pThis)
     660{
     661    RT_NOREF(pThis);
     662    return VINF_SUCCESS;
     663}
     664
     665
     666DECLHIDDEN(bool) drvHostBaseIsMediaPollingRequiredOs(PDRVHOSTBASE pThis)
     667{
     668    if (pThis->enmType == PDMMEDIATYPE_CDROM || pThis->enmType == PDMMEDIATYPE_DVD)
     669        return true;
     670
     671    AssertMsgFailed(("Darwin supports only CD/DVD host drive access\n"));
     672    return false;
    271673}
    272674
     
    274676DECLHIDDEN(void) drvHostBaseDestructOs(PDRVHOSTBASE pThis)
    275677{
    276     if (pThis->EventPoller != NULL)
    277     {
    278         RTSemEventDestroy(pThis->EventPoller);
    279         pThis->EventPoller = NULL;
     678    /*
     679     * Unlock the drive if we've locked it or we're in passthru mode.
     680     */
     681    if (    (   pThis->fLocked
     682             || pThis->IMedia.pfnSendCmd)
     683        &&  pThis->Os.ppScsiTaskDI
     684        &&  pThis->pfnDoLock)
     685    {
     686        int rc = pThis->pfnDoLock(pThis, false);
     687        if (RT_SUCCESS(rc))
     688            pThis->fLocked = false;
    280689    }
    281690
     
    290699     * and umount the DVD but somehow failed to gain exclusive scsi access...
    291700     */
    292     if (pThis->ppScsiTaskDI)
     701    if (pThis->Os.ppScsiTaskDI)
    293702    {
    294703        LogFlow(("%s-%d: releasing exclusive scsi access!\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance));
    295         (*pThis->ppScsiTaskDI)->ReleaseExclusiveAccess(pThis->ppScsiTaskDI);
    296         (*pThis->ppScsiTaskDI)->Release(pThis->ppScsiTaskDI);
    297         pThis->ppScsiTaskDI = NULL;
    298     }
    299     if (pThis->pDADisk)
     704        (*pThis->Os.ppScsiTaskDI)->ReleaseExclusiveAccess(pThis->Os.ppScsiTaskDI);
     705        (*pThis->Os.ppScsiTaskDI)->Release(pThis->Os.ppScsiTaskDI);
     706        pThis->Os.ppScsiTaskDI = NULL;
     707    }
     708    if (pThis->Os.pDADisk)
    300709    {
    301710        LogFlow(("%s-%d: unclaiming the disk!\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance));
    302         DADiskUnclaim(pThis->pDADisk);
    303         CFRelease(pThis->pDADisk);
    304         pThis->pDADisk = NULL;
    305     }
    306     if (pThis->ppMMCDI)
     711        DADiskUnclaim(pThis->Os.pDADisk);
     712        CFRelease(pThis->Os.pDADisk);
     713        pThis->Os.pDADisk = NULL;
     714    }
     715    if (pThis->Os.ppMMCDI)
    307716    {
    308717        LogFlow(("%s-%d: releasing the MMC object!\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance));
    309         (*pThis->ppMMCDI)->Release(pThis->ppMMCDI);
    310         pThis->ppMMCDI = NULL;
    311     }
    312     if (pThis->MasterPort != IO_OBJECT_NULL)
    313     {
    314         mach_port_deallocate(mach_task_self(), pThis->MasterPort);
    315         pThis->MasterPort = IO_OBJECT_NULL;
    316     }
    317     if (pThis->pDASession)
     718        (*pThis->Os.ppMMCDI)->Release(pThis->Os.ppMMCDI);
     719        pThis->Os.ppMMCDI = NULL;
     720    }
     721    if (pThis->Os.MasterPort != IO_OBJECT_NULL)
     722    {
     723        mach_port_deallocate(mach_task_self(), pThis->Os.MasterPort);
     724        pThis->Os.MasterPort = IO_OBJECT_NULL;
     725    }
     726    if (pThis->Os.pDASession)
    318727    {
    319728        LogFlow(("%s-%d: releasing the DA session!\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance));
    320         CFRelease(pThis->pDASession);
    321         pThis->pDASession = NULL;
    322     }
    323 }
    324 
     729        CFRelease(pThis->Os.pDASession);
     730        pThis->Os.pDASession = NULL;
     731    }
     732}
     733
  • trunk/src/VBox/Devices/Storage/DrvHostBase-freebsd.cpp

    r64278 r64316  
    2727#include <iprt/log.h>
    2828
     29/**
     30 * Host backend specific data.
     31 */
     32typedef struct DRVHOSTBASEOS
     33{
     34    /** The filehandle of the device. */
     35    RTFILE                  hFileDevice;
     36    /** The block size. Set when querying the media size. */
     37    uint32_t                cbBlock;
     38    /** SCSI bus number. */
     39    path_id_t               ScsiBus;
     40    /** target ID of the passthrough device. */
     41    target_id_t             ScsiTargetID;
     42    /** LUN of the passthrough device. */
     43    lun_id_t                ScsiLunID;
     44} DRVHOSTBASEOS;
     45/** Pointer to the host backend specific data. */
     46typedef DRVHOSTBASEOS *PDRVHOSBASEOS;
     47AssertCompile(sizeof(DRVHOSTBASEOS) <= 64);
     48
     49#define DRVHOSTBASE_OS_INT_DECLARED
    2950#include "DrvHostBase.h"
    3051
     
    4667        *pcbBuf = 0;
    4768
    48     Assert(pThis->ppScsiTaskDI);
    49 
    50     int rc = VERR_GENERAL_FAILURE;
    51     SCSITaskInterface **ppScsiTaskI = (*pThis->ppScsiTaskDI)->CreateSCSITask(pThis->ppScsiTaskDI);
    52     if (!ppScsiTaskI)
    53         return VERR_NO_MEMORY;
    54     do
    55     {
    56         /* Setup the scsi command. */
    57         SCSICommandDescriptorBlock cdb = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
    58         memcpy(&cdb[0], pbCmd, cbCmd);
    59         IOReturn irc = (*ppScsiTaskI)->SetCommandDescriptorBlock(ppScsiTaskI, cdb, cbCmd);
    60         AssertBreak(irc == kIOReturnSuccess);
    61 
    62         /* Setup the buffer. */
     69    int rc = VINF_SUCCESS;
     70    int rcBSD = 0;
     71    union ccb DeviceCCB;
     72    union ccb *pDeviceCCB = &DeviceCCB;
     73    u_int32_t fFlags;
     74
     75    memset(pDeviceCCB, 0, sizeof(DeviceCCB));
     76    pDeviceCCB->ccb_h.path_id   = pThis->Os.ScsiBus;
     77    pDeviceCCB->ccb_h.target_id = pThis->Os.ScsiTargetID;
     78    pDeviceCCB->ccb_h.target_lun = pThis->Os.ScsiLunID;
     79
     80    /* The SCSI INQUIRY command can't be passed through directly. */
     81    if (pbCmd[0] == SCSI_INQUIRY)
     82    {
     83        pDeviceCCB->ccb_h.func_code = XPT_GDEV_TYPE;
     84
     85        rcBSD = ioctl(RTFileToNative(pThis->Os.hFileDevice), CAMIOCOMMAND, pDeviceCCB);
     86        if (!rcBSD)
     87        {
     88            uint32_t cbCopy =   cbBuf < sizeof(struct scsi_inquiry_data)
     89                              ? cbBuf
     90                              : sizeof(struct scsi_inquiry_data);;
     91            memcpy(pvBuf, &pDeviceCCB->cgd.inq_data, cbCopy);
     92            memset(pbSense, 0, cbSense);
     93
     94            if (pcbBuf)
     95                *pcbBuf = cbCopy;
     96        }
     97        else
     98            rc = RTErrConvertFromErrno(errno);
     99    }
     100    else
     101    {
     102        /* Copy the CDB. */
     103        memcpy(&pDeviceCCB->csio.cdb_io.cdb_bytes, pbCmd, cbCmd);
     104
     105        /* Set direction. */
    63106        if (enmTxDir == PDMMEDIATXDIR_NONE)
    64             irc = (*ppScsiTaskI)->SetScatterGatherEntries(ppScsiTaskI, NULL, 0, 0, kSCSIDataTransfer_NoDataTransfer);
     107            fFlags = CAM_DIR_NONE;
     108        else if (enmTxDir == PDMMEDIATXDIR_FROM_DEVICE)
     109            fFlags = CAM_DIR_IN;
    65110        else
     111            fFlags = CAM_DIR_OUT;
     112
     113        fFlags |= CAM_DEV_QFRZDIS;
     114
     115        cam_fill_csio(&pDeviceCCB->csio, 1, NULL, fFlags, MSG_SIMPLE_Q_TAG,
     116                      (u_int8_t *)pvBuf, cbBuf, cbSense, cbCmd,
     117                      cTimeoutMillies ? cTimeoutMillies : 30000/* timeout */);
     118
     119        /* Send command */
     120        rcBSD = ioctl(RTFileToNative(pThis->Os.hFileDevice), CAMIOCOMMAND, pDeviceCCB);
     121        if (!rcBSD)
    66122        {
    67             IOVirtualRange Range = { (IOVirtualAddress)pvBuf, cbBuf };
    68             irc = (*ppScsiTaskI)->SetScatterGatherEntries(ppScsiTaskI, &Range, 1, cbBuf,
    69                                                           enmTxDir == PDMMEDIATXDIR_FROM_DEVICE
    70                                                           ? kSCSIDataTransfer_FromTargetToInitiator
    71                                                           : kSCSIDataTransfer_FromInitiatorToTarget);
     123            switch (pDeviceCCB->ccb_h.status & CAM_STATUS_MASK)
     124            {
     125                case CAM_REQ_CMP:
     126                    rc = VINF_SUCCESS;
     127                    break;
     128                case CAM_SEL_TIMEOUT:
     129                    rc = VERR_DEV_IO_ERROR;
     130                    break;
     131                case CAM_CMD_TIMEOUT:
     132                    rc = VERR_TIMEOUT;
     133                    break;
     134                default:
     135                    rc = VERR_DEV_IO_ERROR;
     136            }
     137
     138            if (pcbBuf)
     139                *pcbBuf = cbBuf - pDeviceCCB->csio.resid;
     140
     141            if (pbSense)
     142                memcpy(pbSense, &pDeviceCCB->csio.sense_data,
     143                       cbSense - pDeviceCCB->csio.sense_resid);
    72144        }
    73         AssertBreak(irc == kIOReturnSuccess);
    74 
    75         /* Set the timeout. */
    76         irc = (*ppScsiTaskI)->SetTimeoutDuration(ppScsiTaskI, cTimeoutMillies ? cTimeoutMillies : 30000 /*ms*/);
    77         AssertBreak(irc == kIOReturnSuccess);
    78 
    79         /* Execute the command and get the response. */
    80         SCSI_Sense_Data SenseData = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
    81         SCSIServiceResponse     ServiceResponse = kSCSIServiceResponse_Request_In_Process;
    82         SCSITaskStatus TaskStatus = kSCSITaskStatus_GOOD;
    83         UInt64 cbReturned = 0;
    84         irc = (*ppScsiTaskI)->ExecuteTaskSync(ppScsiTaskI, &SenseData, &TaskStatus, &cbReturned);
    85         AssertBreak(irc == kIOReturnSuccess);
    86         if (pcbBuf)
    87             *pcbBuf = (int32_t)cbReturned;
    88 
    89         irc = (*ppScsiTaskI)->GetSCSIServiceResponse(ppScsiTaskI, &ServiceResponse);
    90         AssertBreak(irc == kIOReturnSuccess);
    91         AssertBreak(ServiceResponse == kSCSIServiceResponse_TASK_COMPLETE);
    92 
    93         if (TaskStatus == kSCSITaskStatus_GOOD)
    94             rc = VINF_SUCCESS;
    95         else if (   TaskStatus == kSCSITaskStatus_CHECK_CONDITION
    96                  && pbSense)
    97         {
    98             memset(pbSense, 0, cbSense); /* lazy */
    99             memcpy(pbSense, &SenseData, RT_MIN(sizeof(SenseData), cbSense));
    100             rc = VERR_UNRESOLVED_ERROR;
    101         }
    102         /** @todo convert sense codes when caller doesn't wish to do this himself. */
    103         /*else if (   TaskStatus == kSCSITaskStatus_CHECK_CONDITION
    104                  && SenseData.ADDITIONAL_SENSE_CODE == 0x3A)
    105             rc = VERR_MEDIA_NOT_PRESENT; */
    106145        else
    107         {
    108             rc = enmTxDir == PDMMEDIATXDIR_NONE
    109                ? VERR_DEV_IO_ERROR
    110                : enmTxDir == PDMMEDIATXDIR_FROM_DEVICE
    111                ? VERR_READ_ERROR
    112                : VERR_WRITE_ERROR;
    113             if (pThis->cLogRelErrors++ < 10)
    114                 LogRel(("DVD scsi error: cmd={%.*Rhxs} TaskStatus=%#x key=%#x ASC=%#x ASCQ=%#x (%Rrc)\n",
    115                         cbCmd, pbCmd, TaskStatus, SenseData.SENSE_KEY, SenseData.ADDITIONAL_SENSE_CODE,
    116                         SenseData.ADDITIONAL_SENSE_CODE_QUALIFIER, rc));
    117         }
    118     } while (0);
    119 
    120     (*ppScsiTaskI)->Release(ppScsiTaskI);
    121 
    122     return rc;
     146            rc = RTErrConvertFromErrno(errno);
     147    }
    123148}
    124149
     
    148173        //if (Buf.cbBlock > 2048) /* everyone else is doing this... check if it needed/right.*/
    149174        //    Buf.cbBlock = 2048;
    150         pThis->cbBlock = Buf.cbBlock;
     175        pThis->Os.cbBlock = Buf.cbBlock;
    151176
    152177        *pcb = (uint64_t)Buf.cBlocks * Buf.cbBlock;
     
    160185    int rc = VINF_SUCCESS;
    161186
    162     if (pThis->cbBlock)
     187    if (pThis->Os.cbBlock)
    163188    {
    164189        /*
     
    167192        do
    168193        {
    169             const uint32_t  LBA       = off / pThis->cbBlock;
    170             AssertReturn(!(off % pThis->cbBlock), VERR_INVALID_PARAMETER);
     194            const uint32_t  LBA       = off / pThis->Os.cbBlock;
     195            AssertReturn(!(off % pThis->Os.cbBlock), VERR_INVALID_PARAMETER);
    171196            uint32_t        cbRead32  =   cbRead > SCSI_MAX_BUFFER_SIZE
    172197                                        ? SCSI_MAX_BUFFER_SIZE
    173198                                        : (uint32_t)cbRead;
    174             const uint32_t  cBlocks   = cbRead32 / pThis->cbBlock;
    175             AssertReturn(!(cbRead % pThis->cbBlock), VERR_INVALID_PARAMETER);
     199            const uint32_t  cBlocks   = cbRead32 / pThis->Os.cbBlock;
     200            AssertReturn(!(cbRead % pThis->Os.cbBlock), VERR_INVALID_PARAMETER);
    176201            uint8_t         abCmd[16] =
    177202            {
     
    264289
    265290
    266 DECLHIDDEN(int) drvHostBasePollerWakeupOs(PDRVHOSTBASE pThis)
    267 {
    268     return RTSemEventSignal(pThis->EventPoller);
     291DECLHIDDEN(void) drvHostBaseInitOs(PDRVHOSTBASE pThis)
     292{
     293    pThis->Os.hFileDevice = NIL_RTFILE;
     294}
     295
     296
     297DECLHIDDEN(int) drvHostBaseOpenOs(PDRVHOSTBASE pThis, bool fReadOnly)
     298{
     299    RT_NOREF(fReadOnly);
     300    RTFILE hFileDevice;
     301    int rc = RTFileOpen(&hFileDevice, pThis->pszDevice, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
     302    if (RT_FAILURE(rc))
     303        return rc;
     304
     305    /*
     306     * The current device handle can't passthrough SCSI commands.
     307     * We have to get he passthrough device path and open this.
     308     */
     309    union ccb DeviceCCB;
     310    memset(&DeviceCCB, 0, sizeof(DeviceCCB));
     311
     312    DeviceCCB.ccb_h.func_code = XPT_GDEVLIST;
     313    int rcBSD = ioctl(RTFileToNative(hFileDevice), CAMGETPASSTHRU, &DeviceCCB);
     314    if (!rcBSD)
     315    {
     316        char *pszPassthroughDevice = NULL;
     317        rc = RTStrAPrintf(&pszPassthroughDevice, "/dev/%s%u",
     318                          DeviceCCB.cgdl.periph_name, DeviceCCB.cgdl.unit_number);
     319        if (rc >= 0)
     320        {
     321            RTFILE hPassthroughDevice;
     322            rc = RTFileOpen(&hPassthroughDevice, pszPassthroughDevice, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
     323            RTStrFree(pszPassthroughDevice);
     324            if (RT_SUCCESS(rc))
     325            {
     326                /* Get needed device parameters. */
     327
     328                /*
     329                 * The device path, target id and lun id. Those are
     330                 * needed for the SCSI passthrough ioctl.
     331                 */
     332                memset(&DeviceCCB, 0, sizeof(DeviceCCB));
     333                DeviceCCB.ccb_h.func_code = XPT_GDEVLIST;
     334
     335                rcBSD = ioctl(RTFileToNative(hPassthroughDevice), CAMGETPASSTHRU, &DeviceCCB);
     336                if (!rcBSD)
     337                {
     338                    if (DeviceCCB.cgdl.status != CAM_GDEVLIST_ERROR)
     339                    {
     340                        pThis->Os.ScsiBus      = DeviceCCB.ccb_h.path_id;
     341                        pThis->Os.ScsiTargetID = DeviceCCB.ccb_h.target_id;
     342                        pThis->Os.ScsiLunID    = DeviceCCB.ccb_h.target_lun;
     343                        pThis->Os.hFileDevice  = hPassthroughDevice;
     344                    }
     345                    else
     346                    {
     347                        /* The passthrough device wasn't found. */
     348                        rc = VERR_NOT_FOUND;
     349                    }
     350                }
     351                else
     352                    rc = RTErrConvertFromErrno(errno);
     353
     354                if (RT_FAILURE(rc))
     355                    RTFileClose(hPassthroughDevice);
     356            }
     357        }
     358        else
     359            rc = VERR_NO_STR_MEMORY;
     360    }
     361    else
     362        rc = RTErrConvertFromErrno(errno);
     363
     364    RTFileClose(hFileDevice);
     365    return rc;
     366}
     367
     368
     369DECLHIDDEN(int) drvHostBaseMediaRefreshOs(PDRVHOSTBASE pThis)
     370{
     371    RT_NOREF(pThis);
     372    return VINF_SUCCESS;
     373}
     374
     375
     376DECLHIDDEN(bool) drvHostBaseIsMediaPollingRequiredOs(PDRVHOSTBASE pThis)
     377{
     378    if (pThis->enmType == PDMMEDIATYPE_CDROM || pThis->enmType == PDMMEDIATYPE_DVD)
     379        return true;
     380
     381    AssertMsgFailed(("FreeBSD supports only CD/DVD host drive access\n"));
     382    return false;
    269383}
    270384
     
    272386DECLHIDDEN(void) drvHostBaseDestructOs(PDRVHOSTBASE pThis)
    273387{
    274     if (pThis->EventPoller != NULL)
    275     {
    276         RTSemEventDestroy(pThis->EventPoller);
    277         pThis->EventPoller = NULL;
    278     }
    279 
    280     if (pThis->hFileDevice != NIL_RTFILE)
    281     {
    282         int rc = RTFileClose(pThis->hFileDevice);
     388    /*
     389     * Unlock the drive if we've locked it or we're in passthru mode.
     390     */
     391    if (    pThis->fLocked
     392        &&  pThis->Os.hFileDevice != NIL_RTFILE
     393        &&  pThis->pfnDoLock)
     394    {
     395        int rc = pThis->pfnDoLock(pThis, false);
     396        if (RT_SUCCESS(rc))
     397            pThis->fLocked = false;
     398    }
     399
     400    if (pThis->Os.hFileDevice != NIL_RTFILE)
     401    {
     402        int rc = RTFileClose(pThis->Os.hFileDevice);
    283403        AssertRC(rc);
    284         pThis->hFileDevice = NIL_RTFILE;
    285     }
    286 }
    287 
     404        pThis->Os.hFileDevice = NIL_RTFILE;
     405    }
     406}
     407
  • trunk/src/VBox/Devices/Storage/DrvHostBase-linux.cpp

    r64278 r64316  
    3939#include <VBox/scsi.h>
    4040
     41/**
     42 * Host backend specific data.
     43 */
     44typedef struct DRVHOSTBASEOS
     45{
     46    /** The filehandle of the device. */
     47    RTFILE                  hFileDevice;
     48    /** Double buffer required for ioctl with the Linux kernel as long as we use
     49     * remap_pfn_range() instead of vm_insert_page(). */
     50    uint8_t                *pbDoubleBuffer;
     51    /** Previous disk inserted indicator for the media polling on floppy drives. */
     52    bool                   fPrevDiskIn;
     53} DRVHOSTBASEOS;
     54/** Pointer to the host backend specific data. */
     55typedef DRVHOSTBASEOS *PDRVHOSBASEOS;
     56AssertCompile(sizeof(DRVHOSTBASEOS) <= 64);
     57
     58#define DRVHOSTBASE_OS_INT_DECLARED
    4159#include "DrvHostBase.h"
    4260
     
    5371    AssertPtr(pbCmd);
    5472    Assert(cbCmd <= 16 && cbCmd >= 1);
     73
     74    /* Allocate the temporary buffer lazily. */
     75    if(RT_UNLIKELY(!pThis->Os.pbDoubleBuffer))
     76    {
     77        pThis->Os.pbDoubleBuffer = (uint8_t *)RTMemAlloc(SCSI_MAX_BUFFER_SIZE);
     78        if (!pThis->Os.pbDoubleBuffer)
     79            return VERR_NO_MEMORY;
     80    }
    5581
    5682    int rc = VERR_GENERAL_FAILURE;
     
    74100             * security problems inside the guest OS, if users can issue
    75101             * commands to the CDROM device. */
    76             memset(pThis->pbDoubleBuffer, '\0', *pcbBuf);
     102            memset(pThis->Os.pbDoubleBuffer, '\0', *pcbBuf);
    77103            direction = CGC_DATA_READ;
    78104            break;
     
    80106            Assert(*pcbBuf != 0);
    81107            Assert(*pcbBuf <= SCSI_MAX_BUFFER_SIZE);
    82             memcpy(pThis->pbDoubleBuffer, pvBuf, *pcbBuf);
     108            memcpy(pThis->Os.pbDoubleBuffer, pvBuf, *pcbBuf);
    83109            direction = CGC_DATA_WRITE;
    84110            break;
     
    89115    memset(&cgc, '\0', sizeof(cgc));
    90116    memcpy(cgc.cmd, pbCmd, RT_MIN(CDROM_PACKET_SIZE, cbCmd));
    91     cgc.buffer = (unsigned char *)pThis->pbDoubleBuffer;
     117    cgc.buffer = (unsigned char *)pThis->Os.pbDoubleBuffer;
    92118    cgc.buflen = *pcbBuf;
    93119    cgc.stat = 0;
     
    97123    cgc.quiet = false;
    98124    cgc.timeout = cTimeoutMillies;
    99     rc = ioctl(RTFileToNative(pThis->hFileDevice), CDROM_SEND_PACKET, &cgc);
     125    rc = ioctl(RTFileToNative(pThis->Os.hFileDevice), CDROM_SEND_PACKET, &cgc);
    100126    if (rc < 0)
    101127    {
     
    115141    {
    116142        case PDMMEDIATXDIR_FROM_DEVICE:
    117             memcpy(pvBuf, pThis->pbDoubleBuffer, *pcbBuf);
     143            memcpy(pvBuf, pThis->Os.pbDoubleBuffer, *pcbBuf);
    118144            break;
    119145        default:
     
    134160    if (PDMMEDIATYPE_IS_FLOPPY(pThis->enmType))
    135161    {
    136         rc = ioctl(RTFileToNative(pThis->hFileDevice), FDFLUSH);
     162        rc = ioctl(RTFileToNative(pThis->Os.hFileDevice), FDFLUSH);
    137163        if (rc)
    138164        {
     
    143169
    144170        floppy_drive_struct DrvStat;
    145         rc = ioctl(RTFileToNative(pThis->hFileDevice), FDGETDRVSTAT, &DrvStat);
     171        rc = ioctl(RTFileToNative(pThis->Os.hFileDevice), FDGETDRVSTAT, &DrvStat);
    146172        if (rc)
    147173        {
     
    151177        }
    152178        pThis->fReadOnly = !(DrvStat.flags & FD_DISK_WRITABLE);
    153         rc = RTFileSeek(pThis->hFileDevice, 0, RTFILE_SEEK_END, pcb);
     179        rc = RTFileSeek(pThis->Os.hFileDevice, 0, RTFILE_SEEK_END, pcb);
    154180    }
    155181    else if (pThis->enmType == PDMMEDIATYPE_CDROM || pThis->enmType == PDMMEDIATYPE_DVD)
    156182    {
    157183        /* Clear the media-changed-since-last-call-thingy just to be on the safe side. */
    158         ioctl(RTFileToNative(pThis->hFileDevice), CDROM_MEDIA_CHANGED, CDSL_CURRENT);
    159         rc = RTFileSeek(pThis->hFileDevice, 0, RTFILE_SEEK_END, pcb);
     184        ioctl(RTFileToNative(pThis->Os.hFileDevice), CDROM_MEDIA_CHANGED, CDSL_CURRENT);
     185        rc = RTFileSeek(pThis->Os.hFileDevice, 0, RTFILE_SEEK_END, pcb);
    160186    }
    161187
     
    166192DECLHIDDEN(int) drvHostBaseReadOs(PDRVHOSTBASE pThis, uint64_t off, void *pvBuf, size_t cbRead)
    167193{
    168     return RTFileReadAt(pThis->hFileDevice, off, pvBuf, cbRead, NULL);
     194    return RTFileReadAt(pThis->Os.hFileDevice, off, pvBuf, cbRead, NULL);
    169195}
    170196
     
    172198DECLHIDDEN(int) drvHostBaseWriteOs(PDRVHOSTBASE pThis, uint64_t off, const void *pvBuf, size_t cbWrite)
    173199{
    174     return RTFileWriteAt(pThis->hFileDevice, off, pvBuf, cbWrite, NULL);
     200    return RTFileWriteAt(pThis->Os.hFileDevice, off, pvBuf, cbWrite, NULL);
    175201}
    176202
     
    178204DECLHIDDEN(int) drvHostBaseFlushOs(PDRVHOSTBASE pThis)
    179205{
    180     return RTFileFlush(pThis->hFileDevice);
     206    return RTFileFlush(pThis->Os.hFileDevice);
    181207}
    182208
     
    184210DECLHIDDEN(int) drvHostBaseDoLockOs(PDRVHOSTBASE pThis, bool fLock)
    185211{
    186     int rc = ioctl(RTFileToNative(pThis->hFileDevice), CDROM_LOCKDOOR, (int)fLock);
     212    int rc = ioctl(RTFileToNative(pThis->Os.hFileDevice), CDROM_LOCKDOOR, (int)fLock);
    187213    if (rc < 0)
    188214    {
     
    201227DECLHIDDEN(int) drvHostBaseEjectOs(PDRVHOSTBASE pThis)
    202228{
    203     int rc = ioctl(RTFileToNative(pThis->hFileDevice), CDROMEJECT, 0);
     229    int rc = ioctl(RTFileToNative(pThis->Os.hFileDevice), CDROMEJECT, 0);
    204230    if (rc < 0)
    205231    {
     
    218244DECLHIDDEN(int) drvHostBaseQueryMediaStatusOs(PDRVHOSTBASE pThis, bool *pfMediaChanged, bool *pfMediaPresent)
    219245{
    220     *pfMediaPresent = ioctl(RTFileToNative(pThis->hFileDevice), CDROM_DRIVE_STATUS, CDSL_CURRENT) == CDS_DISC_OK;
    221     *pfMediaChanged = false;
    222     if (pThis->fMediaPresent != *pfMediaPresent)
    223         *pfMediaChanged = ioctl(RTFileToNative(pThis->hFileDevice), CDROM_MEDIA_CHANGED, CDSL_CURRENT) == 1;
    224 
    225     return VINF_SUCCESS;
    226 }
    227 
    228 
    229 DECLHIDDEN(int) drvHostBasePollerWakeupOs(PDRVHOSTBASE pThis)
    230 {
    231     return RTSemEventSignal(pThis->EventPoller);
     246    int rc = VINF_SUCCESS;
     247
     248    if (PDMMEDIATYPE_IS_FLOPPY(pThis->enmType))
     249    {
     250        floppy_drive_struct DrvStat;
     251        int rcLnx = ioctl(RTFileToNative(pThis->Os.hFileDevice), FDPOLLDRVSTAT, &DrvStat);
     252        if (!rcLnx)
     253        {
     254            bool fDiskIn = !(DrvStat.flags & (FD_VERIFY | FD_DISK_NEWCHANGE));
     255            *pfMediaPresent = fDiskIn;
     256
     257            if (fDiskIn != pThis->Os.fPrevDiskIn)
     258                *pfMediaChanged = true;
     259
     260            pThis->Os.fPrevDiskIn = fDiskIn;
     261        }
     262        else
     263            rc = RTErrConvertFromErrno(errno);
     264    }
     265    else
     266    {
     267        *pfMediaPresent = ioctl(RTFileToNative(pThis->Os.hFileDevice), CDROM_DRIVE_STATUS, CDSL_CURRENT) == CDS_DISC_OK;
     268        *pfMediaChanged = false;
     269        if (pThis->fMediaPresent != *pfMediaPresent)
     270            *pfMediaChanged = ioctl(RTFileToNative(pThis->Os.hFileDevice), CDROM_MEDIA_CHANGED, CDSL_CURRENT) == 1;
     271    }
     272
     273    return rc;
     274}
     275
     276
     277DECLHIDDEN(void) drvHostBaseInitOs(PDRVHOSTBASE pThis)
     278{
     279    pThis->Os.hFileDevice    = NIL_RTFILE;
     280    pThis->Os.pbDoubleBuffer = NULL;
     281    pThis->Os.fPrevDiskIn    = false;
     282}
     283
     284
     285DECLHIDDEN(int) drvHostBaseOpenOs(PDRVHOSTBASE pThis, bool fReadOnly)
     286{
     287    uint32_t fFlags = (fReadOnly ? RTFILE_O_READ : RTFILE_O_READWRITE) | RTFILE_O_OPEN | RTFILE_O_DENY_NONE | RTFILE_O_NON_BLOCK;
     288    return RTFileOpen(&pThis->Os.hFileDevice, pThis->pszDevice, fFlags);
     289}
     290
     291
     292DECLHIDDEN(int) drvHostBaseMediaRefreshOs(PDRVHOSTBASE pThis)
     293{
     294    /*
     295     * Need to re-open the device because it will kill off any cached data
     296     * that Linux for some peculiar reason thinks should survive a media change.
     297     */
     298    if (pThis->Os.hFileDevice != NIL_RTFILE)
     299    {
     300        RTFileClose(pThis->Os.hFileDevice);
     301        pThis->Os.hFileDevice = NIL_RTFILE;
     302    }
     303    int rc = drvHostBaseOpenOs(pThis, pThis->fReadOnlyConfig);
     304    if (RT_FAILURE(rc))
     305    {
     306        if (!pThis->fReadOnlyConfig)
     307        {
     308            LogFlow(("%s-%d: drvHostBaseMediaRefreshOs: '%s' - retry readonly (%Rrc)\n",
     309                     pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, pThis->pszDevice, rc));
     310            rc = drvHostBaseOpenOs(pThis, true);
     311        }
     312        if (RT_FAILURE(rc))
     313        {
     314            LogFlow(("%s-%d: failed to open device '%s', rc=%Rrc\n",
     315                     pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, pThis->pszDevice, rc));
     316            return rc;
     317        }
     318        pThis->fReadOnly = true;
     319    }
     320    else
     321        pThis->fReadOnly = pThis->fReadOnlyConfig;
     322
     323    return rc;
     324}
     325
     326
     327DECLHIDDEN(bool) drvHostBaseIsMediaPollingRequiredOs(PDRVHOSTBASE pThis)
     328{
     329    RT_NOREF(pThis);
     330    return true; /* On Linux we always use media polling. */
    232331}
    233332
     
    235334DECLHIDDEN(void) drvHostBaseDestructOs(PDRVHOSTBASE pThis)
    236335{
    237     if (pThis->pbDoubleBuffer)
    238     {
    239         RTMemFree(pThis->pbDoubleBuffer);
    240         pThis->pbDoubleBuffer = NULL;
    241     }
    242 
    243     if (pThis->EventPoller != NULL)
    244     {
    245         RTSemEventDestroy(pThis->EventPoller);
    246         pThis->EventPoller = NULL;
    247     }
    248 
    249     if (pThis->hFileDevice != NIL_RTFILE)
    250     {
    251         int rc = RTFileClose(pThis->hFileDevice);
     336    /*
     337     * Unlock the drive if we've locked it or we're in passthru mode.
     338     */
     339    if (    pThis->fLocked
     340        &&  pThis->Os.hFileDevice != NIL_RTFILE
     341        &&  pThis->pfnDoLock)
     342    {
     343        int rc = pThis->pfnDoLock(pThis, false);
     344        if (RT_SUCCESS(rc))
     345            pThis->fLocked = false;
     346    }
     347
     348    if (pThis->Os.pbDoubleBuffer)
     349    {
     350        RTMemFree(pThis->Os.pbDoubleBuffer);
     351        pThis->Os.pbDoubleBuffer = NULL;
     352    }
     353
     354    if (pThis->Os.hFileDevice != NIL_RTFILE)
     355    {
     356        int rc = RTFileClose(pThis->Os.hFileDevice);
    252357        AssertRC(rc);
    253         pThis->hFileDevice = NIL_RTFILE;
    254     }
    255 }
    256 
     358        pThis->Os.hFileDevice = NIL_RTFILE;
     359    }
     360}
     361
  • trunk/src/VBox/Devices/Storage/DrvHostBase-solaris.cpp

    r64278 r64316  
    3333
    3434#include <iprt/file.h>
     35
     36/**
     37 * Host backend specific data.
     38 */
     39typedef struct DRVHOSTBASEOS
     40{
     41    /** The filehandle of the device. */
     42    RTFILE                  hFileDevice;
     43    /** The raw filehandle of the device. */
     44    RTFILE                  hFileRawDevice;
     45    /** Device name of raw device (RTStrFree). */
     46    char                   *pszRawDeviceOpen;
     47} DRVHOSTBASEOS;
     48/** Pointer to the host backend specific data. */
     49typedef DRVHOSTBASEOS *PDRVHOSBASEOS;
     50AssertCompile(sizeof(DRVHOSTBASEOS) <= 64);
     51
     52#define DRVHOSTBASE_OS_INT_DECLARED
    3553#include "DrvHostBase.h"
    3654
     
    4058 * return the value. BUT... this might be prohibitively slow.
    4159 */
     60
     61/**
     62 * Checks if the current user is authorized using Solaris' role-based access control.
     63 * Made as a separate function with so that it need not be invoked each time we need
     64 * to gain root access.
     65 *
     66 * @returns VBox error code.
     67 */
     68static int solarisCheckUserAuth()
     69{
     70    /* Uses Solaris' role-based access control (RBAC).*/
     71    struct passwd *pPass = getpwuid(getuid());
     72    if (pPass == NULL || chkauthattr("solaris.device.cdrw", pPass->pw_name) == 0)
     73        return VERR_PERMISSION_DENIED;
     74
     75    return VINF_SUCCESS;
     76}
    4277
    4378/**
     
    148183    solarisEnterRootMode(&effUserID); /** @todo check return code when this really works. */
    149184#endif
    150     rc = ioctl(RTFileToNative(pThis->hFileRawDevice), USCSICMD, &usc);
     185    rc = ioctl(RTFileToNative(pThis->Os.hFileRawDevice), USCSICMD, &usc);
    151186#ifdef VBOX_WITH_SUID_WRAPPER
    152187    solarisExitRootMode(&effUserID);
     
    175210     */
    176211    struct dk_minfo MediaInfo;
    177     if (ioctl(RTFileToNative(pThis->hFileRawDevice), DKIOCGMEDIAINFO, &MediaInfo) == 0)
     212    if (ioctl(RTFileToNative(pThis->Os.hFileRawDevice), DKIOCGMEDIAINFO, &MediaInfo) == 0)
    178213    {
    179214        *pcb = MediaInfo.dki_capacity * (uint64_t)MediaInfo.dki_lbsize;
    180215        return VINF_SUCCESS;
    181216    }
    182     return RTFileSeek(pThis->hFileDevice, 0, RTFILE_SEEK_END, pcb);
     217    return RTFileSeek(pThis->Os.hFileDevice, 0, RTFILE_SEEK_END, pcb);
    183218}
    184219
     
    186221DECLHIDDEN(int) drvHostBaseReadOs(PDRVHOSTBASE pThis, uint64_t off, void *pvBuf, size_t cbRead)
    187222{
    188     return RTFileReadAt(pThis->hFileDevice, off, pvBuf, cbRead, NULL);
     223    return RTFileReadAt(pThis->Os.hFileDevice, off, pvBuf, cbRead, NULL);
    189224}
    190225
     
    192227DECLHIDDEN(int) drvHostBaseWriteOs(PDRVHOSTBASE pThis, uint64_t off, const void *pvBuf, size_t cbWrite)
    193228{
    194     return RTFileWriteAt(pThis->hFileDevice, off, pvBuf, cbWrite, NULL);
     229    return RTFileWriteAt(pThis->Os.hFileDevice, off, pvBuf, cbWrite, NULL);
    195230}
    196231
     
    198233DECLHIDDEN(int) drvHostBaseFlushOs(PDRVHOSTBASE pThis)
    199234{
    200     return RTFileFlush(pThis->hFileDevice);
     235    return RTFileFlush(pThis->Os.hFileDevice);
    201236}
    202237
     
    204239DECLHIDDEN(int) drvHostBaseDoLockOs(PDRVHOSTBASE pThis, bool fLock)
    205240{
    206     int rc = ioctl(RTFileToNative(pThis->hFileRawDevice), fLock ? DKIOCLOCK : DKIOCUNLOCK, 0);
     241    int rc = ioctl(RTFileToNative(pThis->Os.hFileRawDevice), fLock ? DKIOCLOCK : DKIOCUNLOCK, 0);
    207242    if (rc < 0)
    208243    {
     
    221256DECLHIDDEN(int) drvHostBaseEjectOs(PDRVHOSTBASE pThis)
    222257{
    223     int rc = ioctl(RTFileToNative(pThis->hFileRawDevice), DKIOCEJECT, 0);
     258    int rc = ioctl(RTFileToNative(pThis->Os.hFileRawDevice), DKIOCEJECT, 0);
    224259    if (rc < 0)
    225260    {
     
    246281    static dkio_state s_DeviceState = DKIO_NONE;
    247282    dkio_state PreviousState = s_DeviceState;
    248     int rc = ioctl(RTFileToNative(pThis->hFileRawDevice), DKIOCSTATE, &s_DeviceState);
     283    int rc = ioctl(RTFileToNative(pThis->Os.hFileRawDevice), DKIOCSTATE, &s_DeviceState);
    249284    if (rc == 0)
    250285    {
     
    258293
    259294
    260 DECLHIDDEN(int) drvHostBasePollerWakeupOs(PDRVHOSTBASE pThis)
    261 {
    262     return RTSemEventSignal(pThis->EventPoller);
     295DECLHIDDEN(void) drvHostBaseInitOs(PDRVHOSTBASE pThis)
     296{
     297    pThis->Os.hFileDevice      = NIL_RTFILE;
     298    pThis->Os.hFileRawDevice   = NIL_RTFILE;
     299    pThis->Os.pszRawDeviceOpen = NULL;
     300}
     301
     302
     303DECLHIDDEN(int) drvHostBaseOpenOs(PDRVHOSTBASE pThis, bool fReadOnly)
     304{
     305#ifdef VBOX_WITH_SUID_WRAPPER  /* Solaris setuid for Passthrough mode. */
     306    if (   (pThis->enmType == PDMMEDIATYPE_CDROM || pThis->enmType == PDMMEDIATYPE_DVD)
     307        && pThis->IMedia.pfnSendCmd)
     308    {
     309        rc = solarisCheckUserAuth();
     310        if (RT_FAILURE(rc))
     311        {
     312            Log(("DVD: solarisCheckUserAuth failed. Permission denied!\n"));
     313            return rc;
     314        }
     315    }
     316#endif /* VBOX_WITH_SUID_WRAPPER */
     317
     318    char *pszBlockDevName = getfullblkname(pThis->pszDevice);
     319    if (!pszBlockDevName)
     320        return VERR_NO_MEMORY;
     321    pThis->pszDeviceOpen = RTStrDup(pszBlockDevName);  /* for RTStrFree() */
     322    free(pszBlockDevName);
     323    pThis->Os.pszRawDeviceOpen = RTStrDup(pThis->pszDevice);
     324    if (!pThis->pszDeviceOpen || !pThis->Os.pszRawDeviceOpen);
     325        return VERR_NO_MEMORY;
     326
     327    unsigned fFlags = (fReadOnly ? RTFILE_O_READ : RTFILE_O_READWRITE)
     328                    | RTFILE_O_OPEN | RTFILE_O_DENY_NONE | RTFILE_O_NON_BLOCK;
     329    int rc = RTFileOpen(&pThis->Os.hFileDevice, pThis->pszDeviceOpen, fFlags);
     330    if (RT_SUCCESS(rc))
     331    {
     332        rc = RTFileOpen(&pThis->Os.hFileRawDevice, pThis->Os.pszRawDeviceOpen, fFlags);
     333        if (RT_SUCCESS(rc))
     334            return rc;
     335
     336        LogRel(("DVD: failed to open device %s rc=%Rrc\n", pThis->Os.pszRawDeviceOpen, rc));
     337        RTFileClose(pThis->Os.hFileDevice);
     338    }
     339    else
     340        LogRel(("DVD: failed to open device %s rc=%Rrc\n", pThis->pszDeviceOpen, rc));
     341    return rc;
     342}
     343
     344
     345DECLHIDDEN(int) drvHostBaseMediaRefreshOs(PDRVHOSTBASE pThis)
     346{
     347    RT_NOREF(pThis);
     348    return VINF_SUCCESS;
     349}
     350
     351
     352DECLHIDDEN(bool) drvHostBaseIsMediaPollingRequiredOs(PDRVHOSTBASE pThis)
     353{
     354    if (pThis->enmType == PDMMEDIATYPE_CDROM || pThis->enmType == PDMMEDIATYPE_DVD)
     355        return true;
     356
     357    AssertMsgFailed(("Solaris supports only CD/DVD host drive access\n"));
     358    return false;
    263359}
    264360
     
    266362DECLHIDDEN(void) drvHostBaseDestructOs(PDRVHOSTBASE pThis)
    267363{
    268     if (pThis->EventPoller != NULL)
    269     {
    270         RTSemEventDestroy(pThis->EventPoller);
    271         pThis->EventPoller = NULL;
    272     }
    273 
    274     if (pThis->hFileDevice != NIL_RTFILE)
    275     {
    276         int rc = RTFileClose(pThis->hFileDevice);
     364    /*
     365     * Unlock the drive if we've locked it or we're in passthru mode.
     366     */
     367    if (    pThis->fLocked
     368        &&  pThis->Os.hFileDevice != NIL_RTFILE
     369        &&  pThis->pfnDoLock)
     370    {
     371        int rc = pThis->pfnDoLock(pThis, false);
     372        if (RT_SUCCESS(rc))
     373            pThis->fLocked = false;
     374    }
     375
     376    if (pThis->Os.hFileDevice != NIL_RTFILE)
     377    {
     378        int rc = RTFileClose(pThis->Os.hFileDevice);
    277379        AssertRC(rc);
    278         pThis->hFileDevice = NIL_RTFILE;
    279     }
    280 
    281     if (pThis->hFileRawDevice != NIL_RTFILE)
    282     {
    283         int rc = RTFileClose(pThis->hFileRawDevice);
     380        pThis->Os.hFileDevice = NIL_RTFILE;
     381    }
     382
     383    if (pThis->Os.hFileRawDevice != NIL_RTFILE)
     384    {
     385        int rc = RTFileClose(pThis->Os.hFileRawDevice);
    284386        AssertRC(rc);
    285         pThis->hFileRawDevice = NIL_RTFILE;
    286     }
    287 
    288     if (pThis->pszRawDeviceOpen)
    289     {
    290         RTStrFree(pThis->pszRawDeviceOpen);
    291         pThis->pszRawDeviceOpen = NULL;
    292     }
    293 }
    294 
     387        pThis->Os.hFileRawDevice = NIL_RTFILE;
     388    }
     389
     390    if (pThis->Os.pszRawDeviceOpen)
     391    {
     392        RTStrFree(pThis->Os.pszRawDeviceOpen);
     393        pThis->Os.pszRawDeviceOpen = NULL;
     394    }
     395}
     396
  • trunk/src/VBox/Devices/Storage/DrvHostBase-win.cpp

    r64278 r64316  
    7777        /*IN*/ FS_INFORMATION_CLASS FileSystemInformationClass );
    7878
     79#include <iprt/ctype.h>
    7980#include <iprt/file.h>
    8081#include <VBox/scsi.h>
    8182
     83/**
     84 * Host backend specific data.
     85 */
     86typedef struct DRVHOSTBASEOS
     87{
     88    /** The filehandle of the device. */
     89    RTFILE                  hFileDevice;
     90    /** Handle to the window we use to catch the device change broadcast messages. */
     91    volatile HWND           hwndDeviceChange;
     92    /** The unit mask. */
     93    DWORD                   fUnitMask;
     94    /** Handle of the poller thread. */
     95    RTTHREAD                hThrdMediaChange;
     96} DRVHOSTBASEOS;
     97/** Pointer to the host backend specific data. */
     98typedef DRVHOSTBASEOS *PDRVHOSBASEOS;
     99AssertCompile(sizeof(DRVHOSTBASEOS) <= 64);
     100
     101#define DRVHOSTBASE_OS_INT_DECLARED
    82102#include "DrvHostBase.h"
     103
     104
     105/**
     106 * Window procedure for the invisible window used to catch the WM_DEVICECHANGE broadcasts.
     107 */
     108static LRESULT CALLBACK DeviceChangeWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
     109{
     110    Log2(("DeviceChangeWindowProc: hwnd=%08x uMsg=%08x\n", hwnd, uMsg));
     111    if (uMsg == WM_DESTROY)
     112    {
     113        PDRVHOSTBASE pThis = (PDRVHOSTBASE)GetWindowLongPtr(hwnd, GWLP_USERDATA);
     114        if (pThis)
     115            ASMAtomicXchgSize(&pThis->Os.hwndDeviceChange, NULL);
     116        PostQuitMessage(0);
     117    }
     118
     119    if (uMsg != WM_DEVICECHANGE)
     120        return DefWindowProc(hwnd, uMsg, wParam, lParam);
     121
     122    PDEV_BROADCAST_HDR  lpdb = (PDEV_BROADCAST_HDR)lParam;
     123    PDRVHOSTBASE        pThis = (PDRVHOSTBASE)GetWindowLongPtr(hwnd, GWLP_USERDATA);
     124    Assert(pThis);
     125    if (pThis == NULL)
     126        return 0;
     127
     128    switch (wParam)
     129    {
     130        case DBT_DEVICEARRIVAL:
     131        case DBT_DEVICEREMOVECOMPLETE:
     132            // Check whether a CD or DVD was inserted into or removed from a drive.
     133            if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME)
     134            {
     135                PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
     136                if (    (lpdbv->dbcv_flags & DBTF_MEDIA)
     137                    &&  (pThis->Os.fUnitMask & lpdbv->dbcv_unitmask))
     138                {
     139                    RTCritSectEnter(&pThis->CritSect);
     140                    if (wParam == DBT_DEVICEARRIVAL)
     141                    {
     142                        int cRetries = 10;
     143                        int rc = DRVHostBaseMediaPresent(pThis);
     144                        while (RT_FAILURE(rc) && cRetries-- > 0)
     145                        {
     146                            RTThreadSleep(50);
     147                            rc = DRVHostBaseMediaPresent(pThis);
     148                        }
     149                    }
     150                    else
     151                        DRVHostBaseMediaNotPresent(pThis);
     152                    RTCritSectLeave(&pThis->CritSect);
     153                }
     154            }
     155            break;
     156    }
     157    return TRUE;
     158}
     159
     160
     161/**
     162 * This thread will wait for changed media notificatons.
     163 *
     164 * @returns Ignored.
     165 * @param   ThreadSelf  Handle of this thread. Ignored.
     166 * @param   pvUser      Pointer to the driver instance structure.
     167 */
     168static DECLCALLBACK(int) drvHostBaseMediaThreadWin(RTTHREAD ThreadSelf, void *pvUser)
     169{
     170    PDRVHOSTBASE pThis = (PDRVHOSTBASE)pvUser;
     171    LogFlow(("%s-%d: drvHostBaseMediaThreadWin: ThreadSelf=%p pvUser=%p\n",
     172             pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, ThreadSelf, pvUser));
     173    static WNDCLASS s_classDeviceChange = {0};
     174    static ATOM     s_hAtomDeviceChange = 0;
     175
     176    /*
     177     * Register custom window class.
     178     */
     179    if (s_hAtomDeviceChange == 0)
     180    {
     181        memset(&s_classDeviceChange, 0, sizeof(s_classDeviceChange));
     182        s_classDeviceChange.lpfnWndProc   = DeviceChangeWindowProc;
     183        s_classDeviceChange.lpszClassName = "VBOX_DeviceChangeClass";
     184        s_classDeviceChange.hInstance     = GetModuleHandle("VBoxDD.dll");
     185        Assert(s_classDeviceChange.hInstance);
     186        s_hAtomDeviceChange = RegisterClassA(&s_classDeviceChange);
     187        Assert(s_hAtomDeviceChange);
     188    }
     189
     190    /*
     191     * Create Window w/ the pThis as user data.
     192     */
     193    HWND hwnd = CreateWindow((LPCTSTR)s_hAtomDeviceChange, "", WS_POPUP, 0, 0, 0, 0, 0, 0, s_classDeviceChange.hInstance, 0);
     194    AssertMsg(hwnd, ("CreateWindow failed with %d\n", GetLastError()));
     195    SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pThis);
     196
     197    /*
     198     * Signal the waiting EMT thread that everything went fine.
     199     */
     200    ASMAtomicXchgPtr((void * volatile *)&pThis->Os.hwndDeviceChange, hwnd);
     201    RTThreadUserSignal(ThreadSelf);
     202    if (!hwnd)
     203    {
     204        LogFlow(("%s-%d: drvHostBaseMediaThreadWin: returns VERR_GENERAL_FAILURE\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance));
     205        return VERR_GENERAL_FAILURE;
     206    }
     207    LogFlow(("%s-%d: drvHostBaseMediaThreadWin: Created hwndDeviceChange=%p\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, hwnd));
     208
     209    /*
     210     * Message pump.
     211     */
     212    MSG         Msg;
     213    BOOL        fRet;
     214    while ((fRet = GetMessage(&Msg, NULL, 0, 0)) != FALSE)
     215    {
     216        if (fRet != -1)
     217        {
     218            TranslateMessage(&Msg);
     219            DispatchMessage(&Msg);
     220        }
     221        //else: handle the error and possibly exit
     222    }
     223    Assert(!pThis->Os.hwndDeviceChange);
     224    /* (Don't clear the thread handle here, the destructor thread is using it to wait.) */
     225    LogFlow(("%s-%d: drvHostBaseMediaThreadWin: returns VINF_SUCCESS\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance));
     226    return VINF_SUCCESS;
     227}
     228
    83229
    84230DECLHIDDEN(int) drvHostBaseScsiCmdOs(PDRVHOSTBASE pThis, const uint8_t *pbCmd, size_t cbCmd, PDMMEDIATXDIR enmTxDir,
     
    139285    Req.spt.SenseInfoLength = (UCHAR)RT_MIN(sizeof(Req.aSense), cbSense);
    140286    Req.spt.SenseInfoOffset = RT_OFFSETOF(struct _REQ, aSense);
    141     if (DeviceIoControl((HANDLE)RTFileToNative(pThis->hFileDevice), IOCTL_SCSI_PASS_THROUGH_DIRECT,
     287    if (DeviceIoControl((HANDLE)RTFileToNative(pThis->Os.hFileDevice), IOCTL_SCSI_PASS_THROUGH_DIRECT,
    142288                        &Req, sizeof(Req), &Req, sizeof(Req), &cbReturned, NULL))
    143289    {
     
    171317
    172318        memset(&geom, 0, sizeof(geom));
    173         rc = DeviceIoControl((HANDLE)RTFileToNative(pThis->hFileDevice), IOCTL_DISK_GET_DRIVE_GEOMETRY,
     319        rc = DeviceIoControl((HANDLE)RTFileToNative(pThis->Os.hFileDevice), IOCTL_DISK_GET_DRIVE_GEOMETRY,
    174320                             NULL, 0, &geom, sizeof(geom), &cbBytesReturned,  NULL);
    175321        if (rc) {
     
    194340        IO_STATUS_BLOCK             IoStatusBlock = {0};
    195341        FILE_FS_SIZE_INFORMATION    FsSize= {0};
    196         NTSTATUS rcNt = NtQueryVolumeInformationFile((HANDLE)RTFileToNative(pThis->hFileDevice),  &IoStatusBlock,
     342        NTSTATUS rcNt = NtQueryVolumeInformationFile((HANDLE)RTFileToNative(pThis->Os.hFileDevice),  &IoStatusBlock,
    197343                                                     &FsSize, sizeof(FsSize), FileFsSizeInformation);
    198344        int cRetries = 5;
     
    200346        {
    201347            RTThreadSleep(10);
    202             rcNt = NtQueryVolumeInformationFile((HANDLE)RTFileToNative(pThis->hFileDevice),  &IoStatusBlock,
     348            rcNt = NtQueryVolumeInformationFile((HANDLE)RTFileToNative(pThis->Os.hFileDevice),  &IoStatusBlock,
    203349                                                &FsSize, sizeof(FsSize), FileFsSizeInformation);
    204350        }
     
    224370DECLHIDDEN(int) drvHostBaseReadOs(PDRVHOSTBASE pThis, uint64_t off, void *pvBuf, size_t cbRead)
    225371{
    226     return RTFileReadAt(pThis->hFileDevice, off, pvBuf, cbRead, NULL);
     372    return RTFileReadAt(pThis->Os.hFileDevice, off, pvBuf, cbRead, NULL);
    227373}
    228374
     
    230376DECLHIDDEN(int) drvHostBaseWriteOs(PDRVHOSTBASE pThis, uint64_t off, const void *pvBuf, size_t cbWrite)
    231377{
    232     return RTFileWriteAt(pThis->hFileDevice, off, pvBuf, cbWrite, NULL);
     378    return RTFileWriteAt(pThis->Os.hFileDevice, off, pvBuf, cbWrite, NULL);
    233379}
    234380
     
    236382DECLHIDDEN(int) drvHostBaseFlushOs(PDRVHOSTBASE pThis)
    237383{
    238     return RTFileFlush(pThis->hFileDevice);
     384    return RTFileFlush(pThis->Os.hFileDevice);
    239385}
    240386
     
    245391    DWORD cbReturned;
    246392    int rc;
    247     if (DeviceIoControl((HANDLE)RTFileToNative(pThis->hFileDevice), IOCTL_STORAGE_MEDIA_REMOVAL,
     393    if (DeviceIoControl((HANDLE)RTFileToNative(pThis->Os.hFileDevice), IOCTL_STORAGE_MEDIA_REMOVAL,
    248394                        &PreventMediaRemoval, sizeof(PreventMediaRemoval),
    249395                        NULL, 0, &cbReturned,
     
    261407{
    262408    int rc = VINF_SUCCESS;
    263     RTFILE hFileDevice = pThis->hFileDevice;
     409    RTFILE hFileDevice = pThis->Os.hFileDevice;
    264410    if (hFileDevice == NIL_RTFILE) /* obsolete crap */
    265411        rc = RTFileOpen(&hFileDevice, pThis->pszDeviceOpen, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
     
    277423
    278424        /* clean up handle */
    279         if (hFileDevice != pThis->hFileDevice)
     425        if (hFileDevice != pThis->Os.hFileDevice)
    280426            RTFileClose(hFileDevice);
    281427    }
     
    287433
    288434
     435DECLHIDDEN(void) drvHostBaseInitOs(PDRVHOSTBASE pThis)
     436{
     437    pThis->Os.hFileDevice      = NIL_RTFILE;
     438    pThis->Os.hwndDeviceChange = NULL;
     439    pThis->Os.hThrdMediaChange = NIL_RTTHREAD;
     440}
     441
     442
     443DECLHIDDEN(int) drvHostBaseOpenOs(PDRVHOSTBASE pThis, bool fReadOnly)
     444{
     445    UINT uDriveType = GetDriveType(pThis->pszDevice);
     446    switch (pThis->enmType)
     447    {
     448        case PDMMEDIATYPE_FLOPPY_360:
     449        case PDMMEDIATYPE_FLOPPY_720:
     450        case PDMMEDIATYPE_FLOPPY_1_20:
     451        case PDMMEDIATYPE_FLOPPY_1_44:
     452        case PDMMEDIATYPE_FLOPPY_2_88:
     453        case PDMMEDIATYPE_FLOPPY_FAKE_15_6:
     454        case PDMMEDIATYPE_FLOPPY_FAKE_63_5:
     455            if (uDriveType != DRIVE_REMOVABLE)
     456            {
     457                AssertMsgFailed(("Configuration error: '%s' is not a floppy (type=%d)\n",
     458                                 pThis->pszDevice, uDriveType));
     459                return VERR_INVALID_PARAMETER;
     460            }
     461            break;
     462        case PDMMEDIATYPE_CDROM:
     463        case PDMMEDIATYPE_DVD:
     464            if (uDriveType != DRIVE_CDROM)
     465            {
     466                AssertMsgFailed(("Configuration error: '%s' is not a cdrom (type=%d)\n",
     467                                 pThis->pszDevice, uDriveType));
     468                return VERR_INVALID_PARAMETER;
     469            }
     470            break;
     471        case PDMMEDIATYPE_HARD_DISK:
     472        default:
     473            AssertMsgFailed(("enmType=%d\n", pThis->enmType));
     474            return VERR_INVALID_PARAMETER;
     475    }
     476
     477    int iBit = RT_C_TO_UPPER(pThis->pszDevice[0]) - 'A';
     478    if (    iBit > 'Z' - 'A'
     479        ||  pThis->pszDevice[1] != ':'
     480        ||  pThis->pszDevice[2])
     481    {
     482        AssertMsgFailed(("Configuration error: Invalid drive specification: '%s'\n", pThis->pszDevice));
     483        return VERR_INVALID_PARAMETER;
     484    }
     485    pThis->Os.fUnitMask = 1 << iBit;
     486    RTStrAPrintf(&pThis->pszDeviceOpen, "\\\\.\\%s", pThis->pszDevice);
     487    if (!pThis->pszDeviceOpen)
     488        return VERR_NO_MEMORY;
     489
     490    uint32_t fFlags = (fReadOnly ? RTFILE_O_READ : RTFILE_O_READWRITE) | RTFILE_O_OPEN | RTFILE_O_DENY_NONE;
     491    int rc = RTFileOpen(&pThis->Os.hFileDevice, pThis->pszDeviceOpen, fFlags);
     492
     493    if (RT_SUCCESS(rc))
     494    {
     495        /*
     496         * Start the thread which will wait for the media change events.
     497         */
     498        rc = RTThreadCreate(&pThis->Os.hThrdMediaChange, drvHostBaseMediaThreadWin, pThis, 0,
     499                            RTTHREADTYPE_INFREQUENT_POLLER, RTTHREADFLAGS_WAITABLE, "DVDMEDIA");
     500        if (RT_FAILURE(rc))
     501        {
     502            AssertMsgFailed(("Failed to create poller thread. rc=%Rrc\n", rc));
     503            return rc;
     504        }
     505
     506        /*
     507         * Wait for the thread to start up (!w32:) and do one detection loop.
     508         */
     509        rc = RTThreadUserWait(pThis->Os.hThrdMediaChange, 10000);
     510        AssertRC(rc);
     511
     512        if (!pThis->Os.hwndDeviceChange)
     513            return VERR_GENERAL_FAILURE;
     514
     515        DRVHostBaseMediaPresent(pThis);
     516    }
     517
     518    return rc;
     519}
     520
     521
     522DECLHIDDEN(int) drvHostBaseMediaRefreshOs(PDRVHOSTBASE pThis)
     523{
     524    RT_NOREF(pThis);
     525    return VINF_SUCCESS;
     526}
     527
     528
    289529DECLHIDDEN(int) drvHostBasePollerWakeupOs(PDRVHOSTBASE pThis)
    290530{
    291     if (pThis->hwndDeviceChange)
    292         PostMessage(pThis->hwndDeviceChange, WM_CLOSE, 0, 0); /* default win proc will destroy the window */
     531    if (pThis->Os.hwndDeviceChange)
     532        PostMessage(pThis->Os.hwndDeviceChange, WM_CLOSE, 0, 0); /* default win proc will destroy the window */
    293533
    294534    return VINF_SUCCESS;
     
    296536
    297537
     538DECLHIDDEN(bool) drvHostBaseIsMediaPollingRequiredOs(PDRVHOSTBASE pThis)
     539{
     540    /* For Windows we alwys use an internal approach. */
     541    RT_NOREF(pThis);
     542    return false;
     543}
     544
     545
    298546DECLHIDDEN(void) drvHostBaseDestructOs(PDRVHOSTBASE pThis)
    299547{
    300     if (pThis->hwndDeviceChange)
    301     {
    302         if (SetWindowLongPtr(pThis->hwndDeviceChange, GWLP_USERDATA, 0) == (LONG_PTR)pThis)
    303             PostMessage(pThis->hwndDeviceChange, WM_CLOSE, 0, 0); /* default win proc will destroy the window */
    304         pThis->hwndDeviceChange = NULL;
    305     }
    306 
    307     if (pThis->hFileDevice != NIL_RTFILE)
    308     {
    309         int rc = RTFileClose(pThis->hFileDevice);
     548    /*
     549     * Unlock the drive if we've locked it or we're in passthru mode.
     550     */
     551    if (    pThis->fLocked
     552        &&  pThis->Os.hFileDevice != NIL_RTFILE
     553        &&  pThis->pfnDoLock)
     554    {
     555        int rc = pThis->pfnDoLock(pThis, false);
     556        if (RT_SUCCESS(rc))
     557            pThis->fLocked = false;
     558    }
     559
     560    if (pThis->Os.hwndDeviceChange)
     561    {
     562        if (SetWindowLongPtr(pThis->Os.hwndDeviceChange, GWLP_USERDATA, 0) == (LONG_PTR)pThis)
     563            PostMessage(pThis->Os.hwndDeviceChange, WM_CLOSE, 0, 0); /* default win proc will destroy the window */
     564        pThis->Os.hwndDeviceChange = NULL;
     565    }
     566
     567    if (pThis->Os.hFileDevice != NIL_RTFILE)
     568    {
     569        int rc = RTFileClose(pThis->Os.hFileDevice);
    310570        AssertRC(rc);
    311         pThis->hFileDevice = NIL_RTFILE;
    312     }
    313 }
    314 
     571        pThis->Os.hFileDevice = NIL_RTFILE;
     572    }
     573}
     574
  • trunk/src/VBox/Devices/Storage/DrvHostBase.cpp

    r64278 r64316  
    2121*********************************************************************************************************************************/
    2222#define LOG_GROUP LOG_GROUP_DRV_HOST_BASE
    23 #ifdef RT_OS_DARWIN
    24 # include <mach/mach.h>
    25 # include <Carbon/Carbon.h>
    26 # include <IOKit/IOKitLib.h>
    27 # include <IOKit/storage/IOStorageDeviceCharacteristics.h>
    28 # include <IOKit/scsi/SCSITaskLib.h>
    29 # include <IOKit/scsi/SCSICommandOperationCodes.h>
    30 # include <IOKit/IOBSD.h>
    31 # include <DiskArbitration/DiskArbitration.h>
    32 # include <mach/mach_error.h>
    33 # include <VBox/scsi.h>
    34 
    35 #elif defined(RT_OS_L4)
    36   /* Nothing special requires... yeah, right. */
    37 
    38 #elif defined(RT_OS_LINUX)
    39 # include <sys/ioctl.h>
    40 # include <sys/fcntl.h>
    41 # include <errno.h>
    42 
    43 #elif defined(RT_OS_SOLARIS)
    44 # include <fcntl.h>
    45 # include <errno.h>
    46 # include <stropts.h>
    47 # include <malloc.h>
    48 # include <sys/dkio.h>
    49 extern "C" char *getfullblkname(char *);
    50 
    51 #elif defined(RT_OS_WINDOWS)
    52 # define WIN32_NO_STATUS
    53 # include <iprt/win/windows.h>
    54 # include <dbt.h>
    55 # undef WIN32_NO_STATUS
    56 # include <ntstatus.h>
    57 
    58 /* from ntdef.h */
    59 typedef LONG NTSTATUS;
    60 
    61 /* from ntddk.h */
    62 typedef struct _IO_STATUS_BLOCK {
    63     union {
    64         NTSTATUS Status;
    65         PVOID Pointer;
    66     };
    67     ULONG_PTR Information;
    68 } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
    69 
    70 
    71 /* from ntinternals.com */
    72 typedef enum _FS_INFORMATION_CLASS {
    73     FileFsVolumeInformation=1,
    74     FileFsLabelInformation,
    75     FileFsSizeInformation,
    76     FileFsDeviceInformation,
    77     FileFsAttributeInformation,
    78     FileFsControlInformation,
    79     FileFsFullSizeInformation,
    80     FileFsObjectIdInformation,
    81     FileFsMaximumInformation
    82 } FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS;
    83 
    84 typedef struct _FILE_FS_SIZE_INFORMATION {
    85     LARGE_INTEGER   TotalAllocationUnits;
    86     LARGE_INTEGER   AvailableAllocationUnits;
    87     ULONG           SectorsPerAllocationUnit;
    88     ULONG           BytesPerSector;
    89 } FILE_FS_SIZE_INFORMATION, *PFILE_FS_SIZE_INFORMATION;
    90 
    91 extern "C"
    92 NTSTATUS __stdcall NtQueryVolumeInformationFile(
    93         /*IN*/ HANDLE               FileHandle,
    94         /*OUT*/ PIO_STATUS_BLOCK    IoStatusBlock,
    95         /*OUT*/ PVOID               FileSystemInformation,
    96         /*IN*/ ULONG                Length,
    97         /*IN*/ FS_INFORMATION_CLASS FileSystemInformationClass );
    98 
    99 #elif defined(RT_OS_FREEBSD)
    100 # include <sys/cdefs.h>
    101 # include <sys/param.h>
    102 # include <errno.h>
    103 # include <stdio.h>
    104 # include <cam/cam.h>
    105 # include <cam/cam_ccb.h>
    106 # include <cam/scsi/scsi_message.h>
    107 # include <cam/scsi/scsi_pass.h>
    108 # include <VBox/scsi.h>
    109 # include <iprt/log.h>
    110 #else
    111 # error "Unsupported Platform."
    112 #endif
    11323
    11424#include <VBox/vmm/pdmdrv.h>
     
    13646static DECLCALLBACK(int) drvHostBaseRead(PPDMIMEDIA pInterface, uint64_t off, void *pvBuf, size_t cbRead)
    13747{
    138     PDRVHOSTBASE pThis = PDMIMEDIA_2_DRVHOSTBASE(pInterface);
     48    PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia);
    13949    LogFlow(("%s-%d: drvHostBaseRead: off=%#llx pvBuf=%p cbRead=%#x (%s)\n",
    14050             pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, off, pvBuf, cbRead, pThis->pszDevice));
     
    17484static DECLCALLBACK(int) drvHostBaseWrite(PPDMIMEDIA pInterface, uint64_t off, const void *pvBuf, size_t cbWrite)
    17585{
    176     RT_NOREF(off, pvBuf, cbWrite);
    177     PDRVHOSTBASE pThis = PDMIMEDIA_2_DRVHOSTBASE(pInterface);
     86    PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia);
    17887    LogFlow(("%s-%d: drvHostBaseWrite: off=%#llx pvBuf=%p cbWrite=%#x (%s)\n",
    17988             pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, off, pvBuf, cbWrite, pThis->pszDevice));
     
    216125{
    217126    int rc;
    218     PDRVHOSTBASE pThis = PDMIMEDIA_2_DRVHOSTBASE(pInterface);
     127    PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia);
    219128    LogFlow(("%s-%d: drvHostBaseFlush: (%s)\n",
    220129             pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, pThis->pszDevice));
     
    235144static DECLCALLBACK(bool) drvHostBaseIsReadOnly(PPDMIMEDIA pInterface)
    236145{
    237     PDRVHOSTBASE pThis = PDMIMEDIA_2_DRVHOSTBASE(pInterface);
     146    PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia);
    238147    return pThis->fReadOnly;
    239148}
     
    251160static DECLCALLBACK(uint64_t) drvHostBaseGetSize(PPDMIMEDIA pInterface)
    252161{
    253     PDRVHOSTBASE pThis = PDMIMEDIA_2_DRVHOSTBASE(pInterface);
     162    PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia);
    254163    RTCritSectEnter(&pThis->CritSect);
    255164
     
    267176static DECLCALLBACK(PDMMEDIATYPE) drvHostBaseGetType(PPDMIMEDIA pInterface)
    268177{
    269     PDRVHOSTBASE pThis = PDMIMEDIA_2_DRVHOSTBASE(pInterface);
     178    PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia);
    270179    LogFlow(("%s-%d: drvHostBaseGetType: returns %d\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, pThis->enmType));
    271180    return pThis->enmType;
     
    276185static DECLCALLBACK(int) drvHostBaseGetUuid(PPDMIMEDIA pInterface, PRTUUID pUuid)
    277186{
    278     PDRVHOSTBASE pThis = PDMIMEDIA_2_DRVHOSTBASE(pInterface);
     187    PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia);
    279188
    280189    *pUuid = pThis->Uuid;
     
    288197static DECLCALLBACK(int) drvHostBaseGetPCHSGeometry(PPDMIMEDIA pInterface, PPDMMEDIAGEOMETRY pPCHSGeometry)
    289198{
    290     PDRVHOSTBASE pThis =  PDMIMEDIA_2_DRVHOSTBASE(pInterface);
     199    PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia);
    291200    RTCritSectEnter(&pThis->CritSect);
    292201
     
    316225static DECLCALLBACK(int) drvHostBaseSetPCHSGeometry(PPDMIMEDIA pInterface, PCPDMMEDIAGEOMETRY pPCHSGeometry)
    317226{
    318     PDRVHOSTBASE pThis =  PDMIMEDIA_2_DRVHOSTBASE(pInterface);
     227    PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia);
    319228    LogFlow(("%s-%d: %s: cCylinders=%d cHeads=%d cSectors=%d\n",
    320229             pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, __FUNCTION__, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
     
    340249static DECLCALLBACK(int) drvHostBaseGetLCHSGeometry(PPDMIMEDIA pInterface, PPDMMEDIAGEOMETRY pLCHSGeometry)
    341250{
    342     PDRVHOSTBASE pThis =  PDMIMEDIA_2_DRVHOSTBASE(pInterface);
     251    PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia);
    343252    RTCritSectEnter(&pThis->CritSect);
    344253
     
    368277static DECLCALLBACK(int) drvHostBaseSetLCHSGeometry(PPDMIMEDIA pInterface, PCPDMMEDIAGEOMETRY pLCHSGeometry)
    369278{
    370     PDRVHOSTBASE pThis =  PDMIMEDIA_2_DRVHOSTBASE(pInterface);
     279    PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia);
    371280    LogFlow(("%s-%d: %s: cCylinders=%d cHeads=%d cSectors=%d\n",
    372281             pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, __FUNCTION__, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
     
    392301static DECLCALLBACK(bool) drvHostBaseIsVisible(PPDMIMEDIA pInterface)
    393302{
    394     PDRVHOSTBASE pThis =  PDMIMEDIA_2_DRVHOSTBASE(pInterface);
     303    PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia);
    395304    return pThis->fBiosVisible;
    396305}
     
    405314    RT_NOREF(fEject);
    406315    /* While we're not mountable (see drvHostBaseMount), we're unmountable. */
    407     PDRVHOSTBASE pThis = PDMIMOUNT_2_DRVHOSTBASE(pInterface);
     316    PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMount);
    408317    RTCritSectEnter(&pThis->CritSect);
    409318
     
    423332        }
    424333
     334        if (fEject)
     335        {
     336            /*
     337             * Eject the disc.
     338             */
     339            rc = drvHostBaseEjectOs(pThis);
     340        }
     341
    425342        /*
    426343         * Media is no longer present.
     
    430347    else
    431348    {
    432         Log(("drvHostiBaseUnmount: Locked\n"));
     349        Log(("drvHostBaseUnmount: Locked\n"));
    433350        rc = VERR_PDM_MEDIA_LOCKED;
    434351    }
     
    443360static DECLCALLBACK(bool) drvHostBaseIsMounted(PPDMIMOUNT pInterface)
    444361{
    445     PDRVHOSTBASE pThis = PDMIMOUNT_2_DRVHOSTBASE(pInterface);
     362    PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMount);
    446363    RTCritSectEnter(&pThis->CritSect);
    447364
     
    456373static DECLCALLBACK(int) drvHostBaseLock(PPDMIMOUNT pInterface)
    457374{
    458     PDRVHOSTBASE pThis = PDMIMOUNT_2_DRVHOSTBASE(pInterface);
     375    PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMount);
    459376    RTCritSectEnter(&pThis->CritSect);
    460377
     
    479396static DECLCALLBACK(int) drvHostBaseUnlock(PPDMIMOUNT pInterface)
    480397{
    481     PDRVHOSTBASE pThis = PDMIMOUNT_2_DRVHOSTBASE(pInterface);
     398    PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMount);
    482399    RTCritSectEnter(&pThis->CritSect);
    483400
     
    502419static DECLCALLBACK(bool) drvHostBaseIsLocked(PPDMIMOUNT pInterface)
    503420{
    504     PDRVHOSTBASE pThis = PDMIMOUNT_2_DRVHOSTBASE(pInterface);
     421    PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMount);
    505422    RTCritSectEnter(&pThis->CritSect);
    506423
     
    530447
    531448/* -=-=-=-=- poller thread -=-=-=-=- */
    532 
    533 #ifdef RT_OS_DARWIN
    534 /** The runloop input source name for the disk arbitration events. */
    535 # define MY_RUN_LOOP_MODE    CFSTR("drvHostBaseDA") /** @todo r=bird: Check if this will cause trouble in the same way that the one in the USB code did. */
    536 
    537 /**
    538  * Gets the BSD Name (/dev/disc[0-9]+) for the service.
    539  *
    540  * This is done by recursing down the I/O registry until we hit upon an entry
    541  * with a BSD Name. Usually we find it two levels down. (Further down under
    542  * the IOCDPartitionScheme, the volume (slices) BSD Name is found. We don't
    543  * seem to have to go this far fortunately.)
    544  *
    545  * @return  VINF_SUCCESS if found, VERR_FILE_NOT_FOUND otherwise.
    546  * @param   Entry       The current I/O registry entry reference.
    547  * @param   pszName     Where to store the name. 128 bytes.
    548  * @param   cRecursions Number of recursions. This is used as an precaution
    549  *                      just to limit the depth and avoid blowing the stack
    550  *                      should we hit a bug or something.
    551  */
    552 static int drvHostBaseGetBSDName(io_registry_entry_t Entry, char *pszName, unsigned cRecursions)
    553 {
    554     int rc = VERR_FILE_NOT_FOUND;
    555     io_iterator_t Children = 0;
    556     kern_return_t krc = IORegistryEntryGetChildIterator(Entry, kIOServicePlane, &Children);
    557     if (krc == KERN_SUCCESS)
    558     {
    559         io_object_t Child;
    560         while (     rc == VERR_FILE_NOT_FOUND
    561                &&   (Child = IOIteratorNext(Children)) != 0)
    562         {
    563             CFStringRef BSDNameStrRef = (CFStringRef)IORegistryEntryCreateCFProperty(Child, CFSTR(kIOBSDNameKey), kCFAllocatorDefault, 0);
    564             if (BSDNameStrRef)
    565             {
    566                 if (CFStringGetCString(BSDNameStrRef, pszName, 128, kCFStringEncodingUTF8))
    567                     rc = VINF_SUCCESS;
    568                 else
    569                     AssertFailed();
    570                 CFRelease(BSDNameStrRef);
    571             }
    572             if (rc == VERR_FILE_NOT_FOUND && cRecursions < 10)
    573                 rc = drvHostBaseGetBSDName(Child, pszName, cRecursions + 1);
    574             IOObjectRelease(Child);
    575         }
    576         IOObjectRelease(Children);
    577     }
    578     return rc;
    579 }
    580 
    581 
    582 /**
    583  * Callback notifying us that the async DADiskClaim()/DADiskUnmount call has completed.
    584  *
    585  * @param   DiskRef         The disk that was attempted claimed / unmounted.
    586  * @param   DissenterRef    NULL on success, contains details on failure.
    587  * @param   pvContext       Pointer to the return code variable.
    588  */
    589 static void drvHostBaseDADoneCallback(DADiskRef DiskRef, DADissenterRef DissenterRef, void *pvContext)
    590 {
    591     RT_NOREF(DiskRef);
    592     int *prc = (int *)pvContext;
    593     if (!DissenterRef)
    594         *prc = 0;
    595     else
    596         *prc = DADissenterGetStatus(DissenterRef) ? DADissenterGetStatus(DissenterRef) : -1;
    597     CFRunLoopStop(CFRunLoopGetCurrent());
    598 }
    599 
    600 
    601 /**
    602  * Obtain exclusive access to the DVD device, umount it if necessary.
    603  *
    604  * @return  VBox status code.
    605  * @param   pThis       The driver instance.
    606  * @param   DVDService  The DVD service object.
    607  */
    608 static int drvHostBaseObtainExclusiveAccess(PDRVHOSTBASE pThis, io_object_t DVDService)
    609 {
    610     PPDMDRVINS pDrvIns = pThis->pDrvIns; NOREF(pDrvIns);
    611 
    612     for (unsigned iTry = 0;; iTry++)
    613     {
    614         IOReturn irc = (*pThis->ppScsiTaskDI)->ObtainExclusiveAccess(pThis->ppScsiTaskDI);
    615         if (irc == kIOReturnSuccess)
    616         {
    617             /*
    618              * This is a bit weird, but if we unmounted the DVD drive we also need to
    619              * unlock it afterwards or the guest won't be able to eject it later on.
    620              */
    621             if (pThis->pDADisk)
    622             {
    623                 uint8_t abCmd[16] =
    624                 {
    625                     SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL, 0, 0, 0, false, 0,
    626                     0,0,0,0,0,0,0,0,0,0
    627                 };
    628                 drvHostBaseScsiCmdOs(pThis, abCmd, 6, PDMMEDIATXDIR_NONE, NULL, NULL, NULL, 0, 0);
    629             }
    630             return VINF_SUCCESS;
    631         }
    632         if (irc == kIOReturnExclusiveAccess)
    633             return VERR_SHARING_VIOLATION;      /* already used exclusivly. */
    634         if (irc != kIOReturnBusy)
    635             return VERR_GENERAL_FAILURE;        /* not mounted */
    636 
    637         /*
    638          * Attempt to the unmount all volumes of the device.
    639          * It seems we can can do this all in one go without having to enumerate the
    640          * volumes (sessions) and deal with them one by one. This is very fortuitous
    641          * as the disk arbitration API is a bit cumbersome to deal with.
    642          */
    643         if (iTry > 2)
    644             return VERR_DRIVE_LOCKED;
    645         char szName[128];
    646         int rc = drvHostBaseGetBSDName(DVDService, &szName[0], 0);
    647         if (RT_SUCCESS(rc))
    648         {
    649             pThis->pDASession = DASessionCreate(kCFAllocatorDefault);
    650             if (pThis->pDASession)
    651             {
    652                 DASessionScheduleWithRunLoop(pThis->pDASession, CFRunLoopGetCurrent(), MY_RUN_LOOP_MODE);
    653                 pThis->pDADisk = DADiskCreateFromBSDName(kCFAllocatorDefault, pThis->pDASession, szName);
    654                 if (pThis->pDADisk)
    655                 {
    656                     /*
    657                      * Try claim the device.
    658                      */
    659                     Log(("%s-%d: calling DADiskClaim on '%s'.\n", pDrvIns->pReg->szName, pDrvIns->iInstance, szName));
    660                     int rcDA = -2;
    661                     DADiskClaim(pThis->pDADisk, kDADiskClaimOptionDefault, NULL, NULL, drvHostBaseDADoneCallback, &rcDA);
    662                     SInt32 rc32 = CFRunLoopRunInMode(MY_RUN_LOOP_MODE, 120.0, FALSE);
    663                     AssertMsg(rc32 == kCFRunLoopRunStopped, ("rc32=%RI32 (%RX32)\n", rc32, rc32));
    664                     if (    rc32 == kCFRunLoopRunStopped
    665                         &&  !rcDA)
    666                     {
    667                         /*
    668                          * Try unmount the device.
    669                          */
    670                         Log(("%s-%d: calling DADiskUnmount on '%s'.\n", pDrvIns->pReg->szName, pDrvIns->iInstance, szName));
    671                         rcDA = -2;
    672                         DADiskUnmount(pThis->pDADisk, kDADiskUnmountOptionWhole, drvHostBaseDADoneCallback, &rcDA);
    673                         rc32 = CFRunLoopRunInMode(MY_RUN_LOOP_MODE, 120.0, FALSE);
    674                         AssertMsg(rc32 == kCFRunLoopRunStopped, ("rc32=%RI32 (%RX32)\n", rc32, rc32));
    675                         if (    rc32 == kCFRunLoopRunStopped
    676                             &&  !rcDA)
    677                         {
    678                             iTry = 99;
    679                             DASessionUnscheduleFromRunLoop(pThis->pDASession, CFRunLoopGetCurrent(), MY_RUN_LOOP_MODE);
    680                             Log(("%s-%d: unmount succeed - retrying.\n", pDrvIns->pReg->szName, pDrvIns->iInstance));
    681                             continue;
    682                         }
    683                         Log(("%s-%d: umount => rc32=%d & rcDA=%#x\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc32, rcDA));
    684 
    685                         /* failed - cleanup */
    686                         DADiskUnclaim(pThis->pDADisk);
    687                     }
    688                     else
    689                         Log(("%s-%d: claim => rc32=%d & rcDA=%#x\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc32, rcDA));
    690 
    691                     CFRelease(pThis->pDADisk);
    692                     pThis->pDADisk = NULL;
    693                 }
    694                 else
    695                     Log(("%s-%d: failed to open disk '%s'!\n", pDrvIns->pReg->szName, pDrvIns->iInstance, szName));
    696 
    697                 DASessionUnscheduleFromRunLoop(pThis->pDASession, CFRunLoopGetCurrent(), MY_RUN_LOOP_MODE);
    698                 CFRelease(pThis->pDASession);
    699                 pThis->pDASession = NULL;
    700             }
    701             else
    702                 Log(("%s-%d: failed to create DA session!\n", pDrvIns->pReg->szName, pDrvIns->iInstance));
    703         }
    704         RTThreadSleep(10);
    705     }
    706 }
    707 #endif /* RT_OS_DARWIN */
    708 
    709 
    710 #ifndef RT_OS_SOLARIS
    711 /**
    712  * Wrapper for open / RTFileOpen / IOKit.
    713  *
    714  * @remark  The Darwin code must correspond exactly to the enumeration
    715  *          done in Main/darwin/iokit.c.
    716  */
    717 static int drvHostBaseOpen(PDRVHOSTBASE pThis, PRTFILE pFileDevice, bool fReadOnly)
    718 {
    719 # ifdef RT_OS_DARWIN
    720     RT_NOREF(fReadOnly);
    721 
    722     /* Darwin is kind of special... */
    723     Assert(!pFileDevice); NOREF(pFileDevice);
    724     Assert(!pThis->cbBlock);
    725     Assert(pThis->MasterPort == IO_OBJECT_NULL);
    726     Assert(!pThis->ppMMCDI);
    727     Assert(!pThis->ppScsiTaskDI);
    728 
    729     /*
    730      * Open the master port on the first invocation.
    731      */
    732     kern_return_t krc = IOMasterPort(MACH_PORT_NULL, &pThis->MasterPort);
    733     AssertReturn(krc == KERN_SUCCESS, VERR_GENERAL_FAILURE);
    734 
    735     /*
    736      * Create a matching dictionary for searching for CD, DVD and BlueRay services in the IOKit.
    737      *
    738      * The idea is to find all the devices which are of class IOCDBlockStorageDevice.
    739      * CD devices are represented by IOCDBlockStorageDevice class itself, while DVD and BlueRay ones
    740      * have it as a parent class.
    741      */
    742     CFMutableDictionaryRef RefMatchingDict = IOServiceMatching("IOCDBlockStorageDevice");
    743     AssertReturn(RefMatchingDict, VERR_NOT_FOUND);
    744 
    745     /*
    746      * do the search and get a collection of keyboards.
    747      */
    748     io_iterator_t DVDServices = IO_OBJECT_NULL;
    749     IOReturn irc = IOServiceGetMatchingServices(pThis->MasterPort, RefMatchingDict, &DVDServices);
    750     AssertMsgReturn(irc == kIOReturnSuccess, ("irc=%d\n", irc), VERR_NOT_FOUND);
    751     RefMatchingDict = NULL; /* the reference is consumed by IOServiceGetMatchingServices. */
    752 
    753     /*
    754      * Enumerate the matching drives (services).
    755      * (This enumeration must be identical to the one performed in Main/src-server/darwin/iokit.cpp.)
    756      */
    757     int rc = VERR_FILE_NOT_FOUND;
    758     unsigned i = 0;
    759     io_object_t DVDService;
    760     while ((DVDService = IOIteratorNext(DVDServices)) != 0)
    761     {
    762         /*
    763          * Get the properties we use to identify the DVD drive.
    764          *
    765          * While there is a (weird 12 byte) GUID, it isn't persistent
    766          * across boots. So, we have to use a combination of the
    767          * vendor name and product name properties with an optional
    768          * sequence number for identification.
    769          */
    770         CFMutableDictionaryRef PropsRef = 0;
    771         krc = IORegistryEntryCreateCFProperties(DVDService, &PropsRef, kCFAllocatorDefault, kNilOptions);
    772         if (krc == KERN_SUCCESS)
    773         {
    774             /* Get the Device Characteristics dictionary. */
    775             CFDictionaryRef DevCharRef = (CFDictionaryRef)CFDictionaryGetValue(PropsRef, CFSTR(kIOPropertyDeviceCharacteristicsKey));
    776             if (DevCharRef)
    777             {
    778                 /* The vendor name. */
    779                 char szVendor[128];
    780                 char *pszVendor = &szVendor[0];
    781                 CFTypeRef ValueRef = CFDictionaryGetValue(DevCharRef, CFSTR(kIOPropertyVendorNameKey));
    782                 if (    ValueRef
    783                     &&  CFGetTypeID(ValueRef) == CFStringGetTypeID()
    784                     &&  CFStringGetCString((CFStringRef)ValueRef, szVendor, sizeof(szVendor), kCFStringEncodingUTF8))
    785                     pszVendor = RTStrStrip(szVendor);
    786                 else
    787                     *pszVendor = '\0';
    788 
    789                 /* The product name. */
    790                 char szProduct[128];
    791                 char *pszProduct = &szProduct[0];
    792                 ValueRef = CFDictionaryGetValue(DevCharRef, CFSTR(kIOPropertyProductNameKey));
    793                 if (    ValueRef
    794                     &&  CFGetTypeID(ValueRef) == CFStringGetTypeID()
    795                     &&  CFStringGetCString((CFStringRef)ValueRef, szProduct, sizeof(szProduct), kCFStringEncodingUTF8))
    796                     pszProduct = RTStrStrip(szProduct);
    797                 else
    798                     *pszProduct = '\0';
    799 
    800                 /* Construct the two names and compare thwm with the one we're searching for. */
    801                 char szName1[256 + 32];
    802                 char szName2[256 + 32];
    803                 if (*pszVendor || *pszProduct)
    804                 {
    805                     if (*pszVendor && *pszProduct)
    806                     {
    807                         RTStrPrintf(szName1, sizeof(szName1), "%s %s", pszVendor, pszProduct);
    808                         RTStrPrintf(szName2, sizeof(szName2), "%s %s (#%u)", pszVendor, pszProduct, i);
    809                     }
    810                     else
    811                     {
    812                         strcpy(szName1, *pszVendor ? pszVendor : pszProduct);
    813                         RTStrPrintf(szName2, sizeof(szName2), "%s (#%u)", *pszVendor ? pszVendor : pszProduct, i);
    814                     }
    815                 }
    816                 else
    817                 {
    818                     RTStrPrintf(szName1, sizeof(szName1), "(#%u)", i);
    819                     strcpy(szName2, szName1);
    820                 }
    821 
    822                 if (    !strcmp(szName1, pThis->pszDeviceOpen)
    823                     ||  !strcmp(szName2, pThis->pszDeviceOpen))
    824                 {
    825                     /*
    826                      * Found it! Now, get the client interface and stuff.
    827                      * Note that we could also query kIOSCSITaskDeviceUserClientTypeID here if the
    828                      * MMC client plugin is missing. For now we assume this won't be necessary.
    829                      */
    830                     SInt32 Score = 0;
    831                     IOCFPlugInInterface **ppPlugInInterface = NULL;
    832                     krc = IOCreatePlugInInterfaceForService(DVDService, kIOMMCDeviceUserClientTypeID, kIOCFPlugInInterfaceID,
    833                                                             &ppPlugInInterface, &Score);
    834                     if (krc == KERN_SUCCESS)
    835                     {
    836                         HRESULT hrc = (*ppPlugInInterface)->QueryInterface(ppPlugInInterface,
    837                                                                            CFUUIDGetUUIDBytes(kIOMMCDeviceInterfaceID),
    838                                                                            (LPVOID *)&pThis->ppMMCDI);
    839                         (*ppPlugInInterface)->Release(ppPlugInInterface);
    840                         ppPlugInInterface = NULL;
    841                         if (hrc == S_OK)
    842                         {
    843                             pThis->ppScsiTaskDI = (*pThis->ppMMCDI)->GetSCSITaskDeviceInterface(pThis->ppMMCDI);
    844                             if (pThis->ppScsiTaskDI)
    845                                 rc = VINF_SUCCESS;
    846                             else
    847                             {
    848                                 LogRel(("GetSCSITaskDeviceInterface failed on '%s'\n", pThis->pszDeviceOpen));
    849                                 rc = VERR_NOT_SUPPORTED;
    850                                 (*pThis->ppMMCDI)->Release(pThis->ppMMCDI);
    851                             }
    852                         }
    853                         else
    854                         {
    855                             rc = VERR_GENERAL_FAILURE;//RTErrConvertFromDarwinCOM(krc);
    856                             pThis->ppMMCDI = NULL;
    857                         }
    858                     }
    859                     else /* Check for kIOSCSITaskDeviceUserClientTypeID? */
    860                         rc = VERR_GENERAL_FAILURE;//RTErrConvertFromDarwinKern(krc);
    861 
    862                     /* Obtain exclusive access to the device so we can send SCSI commands. */
    863                     if (RT_SUCCESS(rc))
    864                         rc = drvHostBaseObtainExclusiveAccess(pThis, DVDService);
    865 
    866                     /* Cleanup on failure. */
    867                     if (RT_FAILURE(rc))
    868                     {
    869                         if (pThis->ppScsiTaskDI)
    870                         {
    871                             (*pThis->ppScsiTaskDI)->Release(pThis->ppScsiTaskDI);
    872                             pThis->ppScsiTaskDI = NULL;
    873                         }
    874                         if (pThis->ppMMCDI)
    875                         {
    876                             (*pThis->ppMMCDI)->Release(pThis->ppMMCDI);
    877                             pThis->ppMMCDI = NULL;
    878                         }
    879                     }
    880 
    881                     IOObjectRelease(DVDService);
    882                     break;
    883                 }
    884             }
    885             CFRelease(PropsRef);
    886         }
    887         else
    888             AssertMsgFailed(("krc=%#x\n", krc));
    889 
    890         IOObjectRelease(DVDService);
    891         i++;
    892     }
    893 
    894     IOObjectRelease(DVDServices);
    895     return rc;
    896 
    897 #elif defined(RT_OS_FREEBSD)
    898     RTFILE hFileDevice;
    899     int rc = RTFileOpen(&hFileDevice, pThis->pszDeviceOpen, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
    900     if (RT_FAILURE(rc))
    901         return rc;
    902 
    903     /*
    904      * The current device handle can't passthrough SCSI commands.
    905      * We have to get he passthrough device path and open this.
    906      */
    907     union ccb DeviceCCB;
    908     memset(&DeviceCCB, 0, sizeof(DeviceCCB));
    909 
    910     DeviceCCB.ccb_h.func_code = XPT_GDEVLIST;
    911     int rcBSD = ioctl(RTFileToNative(hFileDevice), CAMGETPASSTHRU, &DeviceCCB);
    912     if (!rcBSD)
    913     {
    914         char *pszPassthroughDevice = NULL;
    915         rc = RTStrAPrintf(&pszPassthroughDevice, "/dev/%s%u",
    916                           DeviceCCB.cgdl.periph_name, DeviceCCB.cgdl.unit_number);
    917         if (rc >= 0)
    918         {
    919             RTFILE hPassthroughDevice;
    920             rc = RTFileOpen(&hPassthroughDevice, pszPassthroughDevice, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
    921             RTStrFree(pszPassthroughDevice);
    922             if (RT_SUCCESS(rc))
    923             {
    924                 /* Get needed device parameters. */
    925 
    926                 /*
    927                  * The device path, target id and lun id. Those are
    928                  * needed for the SCSI passthrough ioctl.
    929                  */
    930                 memset(&DeviceCCB, 0, sizeof(DeviceCCB));
    931                 DeviceCCB.ccb_h.func_code = XPT_GDEVLIST;
    932 
    933                 rcBSD = ioctl(RTFileToNative(hPassthroughDevice), CAMGETPASSTHRU, &DeviceCCB);
    934                 if (!rcBSD)
    935                 {
    936                     if (DeviceCCB.cgdl.status != CAM_GDEVLIST_ERROR)
    937                     {
    938                         pThis->ScsiBus      = DeviceCCB.ccb_h.path_id;
    939                         pThis->ScsiTargetID = DeviceCCB.ccb_h.target_id;
    940                         pThis->ScsiLunID    = DeviceCCB.ccb_h.target_lun;
    941                         *pFileDevice = hPassthroughDevice;
    942                     }
    943                     else
    944                     {
    945                         /* The passthrough device wasn't found. */
    946                         rc = VERR_NOT_FOUND;
    947                     }
    948                 }
    949                 else
    950                     rc = RTErrConvertFromErrno(errno);
    951 
    952                 if (RT_FAILURE(rc))
    953                     RTFileClose(hPassthroughDevice);
    954             }
    955         }
    956         else
    957             rc = VERR_NO_STR_MEMORY;
    958     }
    959     else
    960         rc = RTErrConvertFromErrno(errno);
    961 
    962     RTFileClose(hFileDevice);
    963     return rc;
    964 
    965 #else
    966     uint32_t fFlags = (fReadOnly ? RTFILE_O_READ : RTFILE_O_READWRITE) | RTFILE_O_OPEN | RTFILE_O_DENY_NONE;
    967 # ifdef RT_OS_LINUX
    968     fFlags |= RTFILE_O_NON_BLOCK;
    969 # endif
    970     return RTFileOpen(pFileDevice, pThis->pszDeviceOpen, fFlags);
    971 #endif
    972 }
    973 
    974 #else   /* RT_OS_SOLARIS */
    975 
    976 /**
    977  * Solaris wrapper for RTFileOpen.
    978  *
    979  * Solaris has to deal with two filehandles, a block and a raw one. Rather than messing
    980  * with drvHostBaseOpen's function signature & body, having a separate one is better.
    981  *
    982  * @returns VBox status code.
    983  */
    984 static int drvHostBaseOpen(PDRVHOSTBASE pThis, PRTFILE pFileBlockDevice, PRTFILE pFileRawDevice, bool fReadOnly)
    985 {
    986     unsigned fFlags = (fReadOnly ? RTFILE_O_READ : RTFILE_O_READWRITE)
    987                     | RTFILE_O_OPEN | RTFILE_O_DENY_NONE | RTFILE_O_NON_BLOCK;
    988     int rc = RTFileOpen(pFileBlockDevice, pThis->pszDeviceOpen, fFlags);
    989     if (RT_SUCCESS(rc))
    990     {
    991         rc = RTFileOpen(pFileRawDevice, pThis->pszRawDeviceOpen, fFlags);
    992         if (RT_SUCCESS(rc))
    993             return rc;
    994 
    995         LogRel(("DVD: failed to open device %s rc=%Rrc\n", pThis->pszRawDeviceOpen, rc));
    996         RTFileClose(*pFileBlockDevice);
    997     }
    998     else
    999         LogRel(("DVD: failed to open device %s rc=%Rrc\n", pThis->pszDeviceOpen, rc));
    1000     return rc;
    1001 }
    1002 #endif  /* RT_OS_SOLARIS */
    1003 
    1004 
    1005 /**
    1006  * (Re)opens the device.
    1007  *
    1008  * This is used to open the device during construction, but it's also used to re-open
    1009  * the device when a media is inserted. This re-open will kill off any cached data
    1010  * that Linux for some peculiar reason thinks should survive a media change...
    1011  *
    1012  * @returns VBOX status code.
    1013  * @param   pThis       Instance data.
    1014  */
    1015 static int drvHostBaseReopen(PDRVHOSTBASE pThis)
    1016 {
    1017 #ifndef RT_OS_DARWIN /* Only *one* open for darwin. */
    1018     LogFlow(("%s-%d: drvHostBaseReopen: '%s'\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, pThis->pszDeviceOpen));
    1019 
    1020     RTFILE hFileDevice;
    1021 #ifdef RT_OS_SOLARIS
    1022     if (pThis->hFileRawDevice != NIL_RTFILE)
    1023     {
    1024         RTFileClose(pThis->hFileRawDevice);
    1025         pThis->hFileRawDevice = NIL_RTFILE;
    1026     }
    1027     if (pThis->hFileDevice != NIL_RTFILE)
    1028     {
    1029         RTFileClose(pThis->hFileDevice);
    1030         pThis->hFileDevice = NIL_RTFILE;
    1031     }
    1032     RTFILE hFileRawDevice;
    1033     int rc = drvHostBaseOpen(pThis, &hFileDevice, &hFileRawDevice, pThis->fReadOnlyConfig);
    1034 #else
    1035     int rc = drvHostBaseOpen(pThis, &hFileDevice, pThis->fReadOnlyConfig);
    1036 #endif
    1037     if (RT_FAILURE(rc))
    1038     {
    1039         if (!pThis->fReadOnlyConfig)
    1040         {
    1041             LogFlow(("%s-%d: drvHostBaseReopen: '%s' - retry readonly (%Rrc)\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, pThis->pszDeviceOpen, rc));
    1042 #ifdef RT_OS_SOLARIS
    1043             rc = drvHostBaseOpen(pThis, &hFileDevice, &hFileRawDevice, false);
    1044 #else
    1045             rc = drvHostBaseOpen(pThis, &hFileDevice, false);
    1046 #endif
    1047         }
    1048         if (RT_FAILURE(rc))
    1049         {
    1050             LogFlow(("%s-%d: failed to open device '%s', rc=%Rrc\n",
    1051                      pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, pThis->pszDevice, rc));
    1052             return rc;
    1053         }
    1054         pThis->fReadOnly = true;
    1055     }
    1056     else
    1057         pThis->fReadOnly = pThis->fReadOnlyConfig;
    1058 
    1059 #ifdef RT_OS_SOLARIS
    1060     if (pThis->hFileRawDevice != NIL_RTFILE)
    1061         RTFileClose(pThis->hFileRawDevice);
    1062     pThis->hFileRawDevice = hFileRawDevice;
    1063 #endif
    1064 
    1065     if (pThis->hFileDevice != NIL_RTFILE)
    1066         RTFileClose(pThis->hFileDevice);
    1067     pThis->hFileDevice = hFileDevice;
    1068 #else  /* RT_OS_DARWIN */
    1069     RT_NOREF(pThis);
    1070 #endif /* RT_OS_DARWIN */
    1071     return VINF_SUCCESS;
    1072 }
    1073 
    1074 
    1075 /**
    1076  * Queries the media size.
    1077  *
    1078  * @returns VBox status code.
    1079  * @param   pThis       Pointer to the instance data.
    1080  * @param   pcb         Where to store the media size in bytes.
    1081  */
    1082 static DECLCALLBACK(int) drvHostBaseGetMediaSize(PDRVHOSTBASE pThis, uint64_t *pcb)
    1083 {
    1084     return drvHostBaseGetMediaSizeOs(pThis, pcb);
    1085 }
    1086449
    1087450
     
    1092455 * @param   pThis   The instance data.
    1093456 */
    1094 int DRVHostBaseMediaPresent(PDRVHOSTBASE pThis)
     457DECLHIDDEN(int) DRVHostBaseMediaPresent(PDRVHOSTBASE pThis)
    1095458{
    1096459    /*
    1097460     * Open the drive.
    1098461     */
    1099     int rc = drvHostBaseReopen(pThis);
     462    int rc = drvHostBaseMediaRefreshOs(pThis);
    1100463    if (RT_FAILURE(rc))
    1101464        return rc;
     
    1105468     */
    1106469    uint64_t cb;
    1107     rc = pThis->pfnGetMediaSize(pThis, &cb);
     470    rc = drvHostBaseGetMediaSizeOs(pThis, &cb);
    1108471    if (RT_FAILURE(rc))
    1109472    {
     
    1130493 * @param   pThis   The instance data.
    1131494 */
    1132 void DRVHostBaseMediaNotPresent(PDRVHOSTBASE pThis)
     495DECLHIDDEN(void) DRVHostBaseMediaNotPresent(PDRVHOSTBASE pThis)
    1133496{
    1134497    pThis->fMediaPresent = false;
     
    1145508
    1146509
    1147 #ifdef RT_OS_WINDOWS
    1148 
    1149 /**
    1150  * Window procedure for the invisible window used to catch the WM_DEVICECHANGE broadcasts.
    1151  */
    1152 static LRESULT CALLBACK DeviceChangeWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    1153 {
    1154     Log2(("DeviceChangeWindowProc: hwnd=%08x uMsg=%08x\n", hwnd, uMsg));
    1155     if (uMsg == WM_DESTROY)
    1156     {
    1157         PDRVHOSTBASE pThis = (PDRVHOSTBASE)GetWindowLongPtr(hwnd, GWLP_USERDATA);
    1158         if (pThis)
    1159             ASMAtomicXchgSize(&pThis->hwndDeviceChange, NULL);
    1160         PostQuitMessage(0);
    1161     }
    1162 
    1163     if (uMsg != WM_DEVICECHANGE)
    1164         return DefWindowProc(hwnd, uMsg, wParam, lParam);
    1165 
    1166     PDEV_BROADCAST_HDR  lpdb = (PDEV_BROADCAST_HDR)lParam;
    1167     PDRVHOSTBASE        pThis = (PDRVHOSTBASE)GetWindowLongPtr(hwnd, GWLP_USERDATA);
    1168     Assert(pThis);
    1169     if (pThis == NULL)
    1170         return 0;
    1171 
    1172     switch (wParam)
    1173     {
    1174         case DBT_DEVICEARRIVAL:
    1175         case DBT_DEVICEREMOVECOMPLETE:
    1176             // Check whether a CD or DVD was inserted into or removed from a drive.
    1177             if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME)
    1178             {
    1179                 PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
    1180                 if (    (lpdbv->dbcv_flags & DBTF_MEDIA)
    1181                     &&  (pThis->fUnitMask & lpdbv->dbcv_unitmask))
    1182                 {
    1183                     RTCritSectEnter(&pThis->CritSect);
    1184                     if (wParam == DBT_DEVICEARRIVAL)
    1185                     {
    1186                         int cRetries = 10;
    1187                         int rc = DRVHostBaseMediaPresent(pThis);
    1188                         while (RT_FAILURE(rc) && cRetries-- > 0)
    1189                         {
    1190                             RTThreadSleep(50);
    1191                             rc = DRVHostBaseMediaPresent(pThis);
    1192                         }
    1193                     }
    1194                     else
    1195                         DRVHostBaseMediaNotPresent(pThis);
    1196                     RTCritSectLeave(&pThis->CritSect);
    1197                 }
    1198             }
    1199             break;
    1200     }
    1201     return TRUE;
    1202 }
    1203 
    1204 #endif /* RT_OS_WINDOWS */
     510static int drvHostBaseMediaPoll(PDRVHOSTBASE pThis)
     511{
     512    /*
     513     * Poll for media change.
     514     */
     515    bool fMediaPresent = false;
     516    bool fMediaChanged = false;
     517    drvHostBaseQueryMediaStatusOs(pThis, &fMediaChanged, &fMediaPresent);
     518
     519    RTCritSectEnter(&pThis->CritSect);
     520
     521    int rc = VINF_SUCCESS;
     522    if (pThis->fMediaPresent != fMediaPresent)
     523    {
     524        LogFlow(("drvHostDvdPoll: %d -> %d\n", pThis->fMediaPresent, fMediaPresent));
     525        pThis->fMediaPresent = false;
     526        if (fMediaPresent)
     527            rc = DRVHostBaseMediaPresent(pThis);
     528        else
     529            DRVHostBaseMediaNotPresent(pThis);
     530    }
     531    else if (fMediaPresent)
     532    {
     533        /*
     534         * Poll for media change.
     535         */
     536        if (fMediaChanged)
     537        {
     538            LogFlow(("drvHostDVDMediaThread: Media changed!\n"));
     539            DRVHostBaseMediaNotPresent(pThis);
     540            rc = DRVHostBaseMediaPresent(pThis);
     541        }
     542    }
     543
     544    RTCritSectLeave(&pThis->CritSect);
     545    return rc;
     546}
    1205547
    1206548
     
    1217559    LogFlow(("%s-%d: drvHostBaseMediaThread: ThreadSelf=%p pvUser=%p\n",
    1218560             pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, ThreadSelf, pvUser));
    1219 #ifdef RT_OS_WINDOWS
    1220     static WNDCLASS s_classDeviceChange = {0};
    1221     static ATOM     s_hAtomDeviceChange = 0;
    1222 
    1223     /*
    1224      * Register custom window class.
    1225      */
    1226     if (s_hAtomDeviceChange == 0)
    1227     {
    1228         memset(&s_classDeviceChange, 0, sizeof(s_classDeviceChange));
    1229         s_classDeviceChange.lpfnWndProc   = DeviceChangeWindowProc;
    1230         s_classDeviceChange.lpszClassName = "VBOX_DeviceChangeClass";
    1231         s_classDeviceChange.hInstance     = GetModuleHandle("VBoxDD.dll");
    1232         Assert(s_classDeviceChange.hInstance);
    1233         s_hAtomDeviceChange = RegisterClassA(&s_classDeviceChange);
    1234         Assert(s_hAtomDeviceChange);
    1235     }
    1236 
    1237     /*
    1238      * Create Window w/ the pThis as user data.
    1239      */
    1240     HWND hwnd = CreateWindow((LPCTSTR)s_hAtomDeviceChange, "", WS_POPUP, 0, 0, 0, 0, 0, 0, s_classDeviceChange.hInstance, 0);
    1241     AssertMsg(hwnd, ("CreateWindow failed with %d\n", GetLastError()));
    1242     SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pThis);
    1243 
    1244     /*
    1245      * Signal the waiting EMT thread that everything went fine.
    1246      */
    1247     ASMAtomicXchgPtr((void * volatile *)&pThis->hwndDeviceChange, hwnd);
    1248     RTThreadUserSignal(ThreadSelf);
    1249     if (!hwnd)
    1250     {
    1251         LogFlow(("%s-%d: drvHostBaseMediaThread: returns VERR_GENERAL_FAILURE\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance));
    1252         return VERR_GENERAL_FAILURE;
    1253     }
    1254     LogFlow(("%s-%d: drvHostBaseMediaThread: Created hwndDeviceChange=%p\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, hwnd));
    1255 
    1256     /*
    1257      * Message pump.
    1258      */
    1259     MSG         Msg;
    1260     BOOL        fRet;
    1261     while ((fRet = GetMessage(&Msg, NULL, 0, 0)) != FALSE)
    1262     {
    1263         if (fRet != -1)
    1264         {
    1265             TranslateMessage(&Msg);
    1266             DispatchMessage(&Msg);
    1267         }
    1268         //else: handle the error and possibly exit
    1269     }
    1270     Assert(!pThis->hwndDeviceChange);
    1271 
    1272 #else /* !RT_OS_WINDOWS */
    1273561    bool        fFirst = true;
    1274562    int         cRetries = 10;
     
    1278566         * Perform the polling (unless we've run out of 50ms retries).
    1279567         */
    1280         if (    pThis->pfnPoll
    1281             &&  cRetries-- > 0)
    1282         {
    1283 
    1284             int rc = pThis->pfnPoll(pThis);
     568        if (cRetries-- > 0)
     569        {
     570
     571            int rc = drvHostBaseMediaPoll(pThis);
    1285572            if (RT_FAILURE(rc))
    1286573            {
     
    1313600        cRetries = 10;
    1314601    }
    1315 
    1316 #endif /* !RT_OS_WINDOWS */
    1317602
    1318603    /* (Don't clear the thread handle here, the destructor thread is using it to wait.) */
     
    1369654        do
    1370655        {
    1371             drvHostBasePollerWakeupOs(pThis);
     656            RTSemEventSignal(pThis->EventPoller);
    1372657            rc = RTThreadWait(pThis->ThreadPoller, 100, NULL);
    1373658        } while (cTimes-- > 0 && rc == VERR_TIMEOUT);
     
    1378663
    1379664    /*
    1380      * Unlock the drive if we've locked it or we're in passthru mode.
    1381      */
    1382 #ifdef RT_OS_DARWIN
    1383     if (    (   pThis->fLocked
    1384              || pThis->IMedia.pfnSendCmd)
    1385         &&  pThis->ppScsiTaskDI
    1386 #else /** @todo Check if the other guys can mix pfnDoLock with scsi passthru.
    1387        * (We're currently not unlocking the device after use. See todo in DevATA.cpp.) */
    1388     if (    pThis->fLocked
    1389         &&  pThis->hFileDevice != NIL_RTFILE
    1390 #endif
    1391         &&  pThis->pfnDoLock)
    1392     {
    1393         int rc = pThis->pfnDoLock(pThis, false);
    1394         if (RT_SUCCESS(rc))
    1395             pThis->fLocked = false;
    1396     }
    1397 
    1398     /*
    1399665     * Cleanup the other resources.
    1400666     */
    1401667    drvHostBaseDestructOs(pThis);
     668
     669    if (pThis->EventPoller != NULL)
     670    {
     671        RTSemEventDestroy(pThis->EventPoller);
     672        pThis->EventPoller = NULL;
     673    }
    1402674
    1403675    if (pThis->pszDevice)
     
    1425697
    1426698/**
    1427  * Initializes the instance data (init part 1).
    1428  *
    1429  * The driver which derives from this base driver will override function pointers after
    1430  * calling this method, and complete the construction by calling DRVHostBaseInitFinish().
     699 * Initializes the instance data .
    1431700 *
    1432701 * On failure call DRVHostBaseDestruct().
     
    1434703 * @returns VBox status code.
    1435704 * @param   pDrvIns         Driver instance.
    1436  * @param   pszCfgValid     Pointer to a string ofvalid CFGM options.
     705 * @param   pszCfgValid     Pointer to a string of valid CFGM options.
    1437706 * @param   pCfg            Configuration handle.
    1438707 * @param   enmType         Device type.
    1439708 */
    1440 int DRVHostBaseInitData(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, const char *pszCfgValid, PDMMEDIATYPE enmType)
    1441 {
     709DECLHIDDEN(int) DRVHostBaseInit(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, const char *pszCfgValid, PDMMEDIATYPE enmType)
     710{
     711    int src = VINF_SUCCESS;
    1442712    PDRVHOSTBASE pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTBASE);
    1443     LogFlow(("%s-%d: DRVHostBaseInitData: iInstance=%d\n", pDrvIns->pReg->szName, pDrvIns->iInstance, pDrvIns->iInstance));
     713    LogFlow(("%s-%d: DRVHostBaseInit: iInstance=%d\n", pDrvIns->pReg->szName, pDrvIns->iInstance, pDrvIns->iInstance));
    1444714
    1445715    /*
     
    1449719    pThis->fKeepInstance                    = false;
    1450720    pThis->ThreadPoller                     = NIL_RTTHREAD;
    1451 #ifdef RT_OS_DARWIN
    1452     pThis->MasterPort                       = IO_OBJECT_NULL;
    1453     pThis->ppMMCDI                          = NULL;
    1454     pThis->ppScsiTaskDI                     = NULL;
    1455     pThis->cbBlock                          = 0;
    1456     pThis->pDADisk                          = NULL;
    1457     pThis->pDASession                       = NULL;
    1458 #else
    1459     pThis->hFileDevice                      = NIL_RTFILE;
    1460 #endif
    1461 #ifdef RT_OS_SOLARIS
    1462     pThis->hFileRawDevice                   = NIL_RTFILE;
    1463 #endif
    1464721    pThis->enmType                          = enmType;
    1465     //pThis->cErrors                          = 0;
    1466722    pThis->fAttachFailError                 = true; /* It's an error until we've read the config. */
    1467 
    1468     pThis->pfnGetMediaSize                  = drvHostBaseGetMediaSize;
    1469723
    1470724    /* IBase. */
     
    1493747    pThis->IMount.pfnIsLocked               = drvHostBaseIsLocked;
    1494748
     749    drvHostBaseInitOs(pThis);
     750
    1495751    if (!CFGMR3AreValuesValid(pCfg, pszCfgValid))
    1496752    {
     
    1523779    /* Mountable */
    1524780    uint32_t u32;
    1525     rc = CFGMR3QueryU32(pCfg, "Interval", &u32);
     781    rc = CFGMR3QueryU32Def(pCfg, "Interval", &u32, 1000);
    1526782    if (RT_SUCCESS(rc))
    1527783        pThis->cMilliesPoller = u32;
    1528     else if (rc == VERR_CFGM_VALUE_NOT_FOUND)
    1529         pThis->cMilliesPoller = 1000;
    1530     else if (RT_FAILURE(rc))
     784    else
    1531785    {
    1532786        AssertMsgFailed(("Configuration error: Query \"Mountable\" resulted in %Rrc.\n", rc));
     
    1534788    }
    1535789
    1536     /* ReadOnly */
    1537     rc = CFGMR3QueryBool(pCfg, "ReadOnly", &pThis->fReadOnlyConfig);
    1538     if (rc == VERR_CFGM_VALUE_NOT_FOUND)
    1539         pThis->fReadOnlyConfig = enmType == PDMMEDIATYPE_DVD || enmType == PDMMEDIATYPE_CDROM ? true : false;
    1540     else if (RT_FAILURE(rc))
    1541     {
    1542         AssertMsgFailed(("Configuration error: Query \"ReadOnly\" resulted in %Rrc.\n", rc));
    1543         return rc;
     790    /* ReadOnly - passthrough mode requires read/write access in any case. */
     791    if (   (pThis->enmType == PDMMEDIATYPE_CDROM || pThis->enmType == PDMMEDIATYPE_DVD)
     792        && pThis->IMedia.pfnSendCmd)
     793            pThis->fReadOnlyConfig = false;
     794    else
     795    {
     796        rc = CFGMR3QueryBoolDef(pCfg, "ReadOnly", &pThis->fReadOnlyConfig,
     797                                  enmType == PDMMEDIATYPE_DVD || enmType == PDMMEDIATYPE_CDROM
     798                                ? true
     799                                : false);
     800        if (RT_FAILURE(rc))
     801        {
     802            AssertMsgFailed(("Configuration error: Query \"ReadOnly\" resulted in %Rrc.\n", rc));
     803            return rc;
     804        }
    1544805    }
    1545806
    1546807    /* Locked */
    1547     rc = CFGMR3QueryBool(pCfg, "Locked", &pThis->fLocked);
    1548     if (rc == VERR_CFGM_VALUE_NOT_FOUND)
    1549         pThis->fLocked = false;
    1550     else if (RT_FAILURE(rc))
     808    rc = CFGMR3QueryBoolDef(pCfg, "Locked", &pThis->fLocked, false);
     809    if (RT_FAILURE(rc))
    1551810    {
    1552811        AssertMsgFailed(("Configuration error: Query \"Locked\" resulted in %Rrc.\n", rc));
     
    1555814
    1556815    /* BIOS visible */
    1557     rc = CFGMR3QueryBool(pCfg, "BIOSVisible", &pThis->fBiosVisible);
    1558     if (rc == VERR_CFGM_VALUE_NOT_FOUND)
    1559         pThis->fBiosVisible = true;
    1560     else if (RT_FAILURE(rc))
     816    rc = CFGMR3QueryBoolDef(pCfg, "BIOSVisible", &pThis->fBiosVisible, true);
     817    if (RT_FAILURE(rc))
    1561818    {
    1562819        AssertMsgFailed(("Configuration error: Query \"BIOSVisible\" resulted in %Rrc.\n", rc));
     
    1587844
    1588845    /* Define whether attach failure is an error (default) or not. */
    1589     bool fAttachFailError;
    1590     rc = CFGMR3QueryBool(pCfg, "AttachFailError", &fAttachFailError);
    1591     if (RT_FAILURE(rc))
    1592         fAttachFailError = true;
     846    bool fAttachFailError = true;
     847    rc = CFGMR3QueryBoolDef(pCfg, "AttachFailError", &fAttachFailError, true);
    1593848    pThis->fAttachFailError = fAttachFailError;
    1594 
    1595     /* name to open & watch for */
    1596 #ifdef RT_OS_WINDOWS
    1597     int iBit = RT_C_TO_UPPER(pThis->pszDevice[0]) - 'A';
    1598     if (    iBit > 'Z' - 'A'
    1599         ||  pThis->pszDevice[1] != ':'
    1600         ||  pThis->pszDevice[2])
    1601     {
    1602         AssertMsgFailed(("Configuration error: Invalid drive specification: '%s'\n", pThis->pszDevice));
    1603         return VERR_INVALID_PARAMETER;
    1604     }
    1605     pThis->fUnitMask = 1 << iBit;
    1606     RTStrAPrintf(&pThis->pszDeviceOpen, "\\\\.\\%s", pThis->pszDevice);
    1607 
    1608 #elif defined(RT_OS_SOLARIS)
    1609     char *pszBlockDevName = getfullblkname(pThis->pszDevice);
    1610     if (!pszBlockDevName)
    1611         return VERR_NO_MEMORY;
    1612     pThis->pszDeviceOpen = RTStrDup(pszBlockDevName);  /* for RTStrFree() */
    1613     free(pszBlockDevName);
    1614     pThis->pszRawDeviceOpen = RTStrDup(pThis->pszDevice);
    1615 
    1616 #else
    1617     pThis->pszDeviceOpen = RTStrDup(pThis->pszDevice);
    1618 #endif
    1619 
    1620     if (!pThis->pszDeviceOpen)
    1621         return VERR_NO_MEMORY;
    1622 
    1623     return VINF_SUCCESS;
    1624 }
    1625 
    1626 
    1627 /**
    1628  * Do the 2nd part of the init after the derived driver has overridden the defaults.
    1629  *
    1630  * On failure call DRVHostBaseDestruct().
    1631  *
    1632  * @returns VBox status code.
    1633  * @param   pThis       Pointer to the instance data.
    1634  */
    1635 int DRVHostBaseInitFinish(PDRVHOSTBASE pThis)
    1636 {
    1637     int src = VINF_SUCCESS;
    1638     PPDMDRVINS pDrvIns = pThis->pDrvIns;
    1639849
    1640850    /* log config summary */
     
    1653863     * Register saved state.
    1654864     */
    1655     int rc = PDMDrvHlpSSMRegisterLoadDone(pDrvIns, drvHostBaseLoadDone);
     865    rc = PDMDrvHlpSSMRegisterLoadDone(pDrvIns, drvHostBaseLoadDone);
    1656866    if (RT_FAILURE(rc))
    1657867        return rc;
    1658868
    1659869    /*
    1660      * Verify type.
    1661      */
    1662 #ifdef RT_OS_WINDOWS
    1663     UINT uDriveType = GetDriveType(pThis->pszDevice);
    1664     switch (pThis->enmType)
    1665     {
    1666         case PDMMEDIATYPE_FLOPPY_360:
    1667         case PDMMEDIATYPE_FLOPPY_720:
    1668         case PDMMEDIATYPE_FLOPPY_1_20:
    1669         case PDMMEDIATYPE_FLOPPY_1_44:
    1670         case PDMMEDIATYPE_FLOPPY_2_88:
    1671         case PDMMEDIATYPE_FLOPPY_FAKE_15_6:
    1672         case PDMMEDIATYPE_FLOPPY_FAKE_63_5:
    1673             if (uDriveType != DRIVE_REMOVABLE)
    1674             {
    1675                 AssertMsgFailed(("Configuration error: '%s' is not a floppy (type=%d)\n",
    1676                                  pThis->pszDevice, uDriveType));
    1677                 return VERR_INVALID_PARAMETER;
    1678             }
    1679             break;
    1680         case PDMMEDIATYPE_CDROM:
    1681         case PDMMEDIATYPE_DVD:
    1682             if (uDriveType != DRIVE_CDROM)
    1683             {
    1684                 AssertMsgFailed(("Configuration error: '%s' is not a cdrom (type=%d)\n",
    1685                                  pThis->pszDevice, uDriveType));
    1686                 return VERR_INVALID_PARAMETER;
    1687             }
    1688             break;
    1689         case PDMMEDIATYPE_HARD_DISK:
    1690         default:
    1691             AssertMsgFailed(("enmType=%d\n", pThis->enmType));
    1692             return VERR_INVALID_PARAMETER;
    1693     }
    1694 #endif
     870     * Initialize the critical section used for serializing the access to the media.
     871     */
     872    rc = RTCritSectInit(&pThis->CritSect);
     873    if (RT_FAILURE(rc))
     874        return rc;
    1695875
    1696876    /*
    1697877     * Open the device.
    1698878     */
    1699 #if defined(RT_OS_DARWIN)
    1700     rc = drvHostBaseOpen(pThis, NULL, pThis->fReadOnlyConfig);
    1701 #else
    1702     rc = drvHostBaseReopen(pThis);
    1703 #endif
     879    rc = drvHostBaseOpenOs(pThis, pThis->fReadOnlyConfig);
    1704880    if (RT_FAILURE(rc))
    1705881    {
     
    1710886            && RT_SUCCESS(RTPathReal(pszDevice, szPathReal, sizeof(szPathReal))))
    1711887            pszDevice = szPathReal;
    1712         pThis->hFileDevice = NIL_RTFILE;
    1713 #endif
    1714 #ifdef RT_OS_SOLARIS
    1715         pThis->hFileRawDevice = NIL_RTFILE;
    1716888#endif
    1717889
     
    1752924        }
    1753925    }
    1754 #ifdef RT_OS_WINDOWS
    1755     if (RT_SUCCESS(src))
    1756         DRVHostBaseMediaPresent(pThis);
    1757 #endif
    1758926
    1759927    /*
     
    1771939    }
    1772940
    1773 #ifndef RT_OS_WINDOWS
    1774     if (RT_SUCCESS(src))
     941    if (RT_SUCCESS(src) && drvHostBaseIsMediaPollingRequiredOs(pThis))
    1775942    {
    1776943        /*
     
    1780947        if (RT_FAILURE(rc))
    1781948            return rc;
    1782     }
    1783 #endif
    1784 
    1785     /*
    1786      * Initialize the critical section used for serializing the access to the media.
    1787      */
    1788     rc = RTCritSectInit(&pThis->CritSect);
    1789     if (RT_FAILURE(rc))
    1790         return rc;
    1791 
    1792     if (RT_SUCCESS(src))
    1793     {
     949
    1794950        /*
    1795951         * Start the thread which will poll for the media.
     
    1808964        rc = RTThreadUserWait(pThis->ThreadPoller, 10000);
    1809965        AssertRC(rc);
    1810 #ifdef RT_OS_WINDOWS
    1811         if (!pThis->hwndDeviceChange)
    1812             return VERR_GENERAL_FAILURE;
    1813 #endif
     966    }
     967
     968    if (RT_FAILURE(rc))
     969    {
     970        if (!pThis->fAttachFailError)
     971        {
     972            /* Suppressing the attach failure error must not affect the normal
     973             * DRVHostBaseDestruct, so reset this flag below before leaving. */
     974            pThis->fKeepInstance = true;
     975            rc = VINF_SUCCESS;
     976        }
     977        DRVHostBaseDestruct(pDrvIns);
     978        pThis->fKeepInstance = false;
    1814979    }
    1815980
    1816981    if (RT_FAILURE(src))
    1817982        return src;
    1818     return rc;
    1819 }
    1820 
     983
     984    return rc;
     985}
     986
  • trunk/src/VBox/Devices/Storage/DrvHostBase.h

    r64278 r64316  
    6262    /** Device name to open (RTStrFree). */
    6363    char                   *pszDeviceOpen;
    64 #ifdef RT_OS_SOLARIS
    65     /** Device name of raw device (RTStrFree). */
    66     char                   *pszRawDeviceOpen;
    67 #endif
    6864    /** Uuid of the drive. */
    6965    RTUUID                  Uuid;
     
    8581     * This is invalid if no drive is in the drive. */
    8682    uint64_t volatile       cbSize;
    87 #if !defined(RT_OS_DARWIN)
    88     /** The filehandle of the device. */
    89     RTFILE                  hFileDevice;
    90 #endif
    91 #ifdef RT_OS_SOLARIS
    92     /** The raw filehandle of the device. */
    93     RTFILE                  hFileRawDevice;
    94 #endif
    9583
    9684    /** Handle of the poller thread. */
    9785    RTTHREAD                ThreadPoller;
    98 #ifndef RT_OS_WINDOWS
    9986    /** Event semaphore the thread will wait on. */
    10087    RTSEMEVENT              EventPoller;
    101 #endif
    10288    /** The poller interval. */
    10389    RTMSINTERVAL            cMilliesPoller;
     
    10995    /** BIOS LCHS geometry. */
    11096    PDMMEDIAGEOMETRY        LCHSGeometry;
    111 
    112     /** The number of errors that could go into the release log. (flood gate) */
    113     uint32_t                cLogRelErrors;
    114 
    115 #ifdef RT_OS_DARWIN
    116     /** The master port. */
    117     mach_port_t             MasterPort;
    118     /** The MMC-2 Device Interface. (This is only used to get the scsi task interface.) */
    119     MMCDeviceInterface    **ppMMCDI;
    120     /** The SCSI Task Device Interface. */
    121     SCSITaskDeviceInterface **ppScsiTaskDI;
    122     /** The block size. Set when querying the media size. */
    123     uint32_t                cbBlock;
    124     /** The disk arbitration session reference. NULL if we didn't have to claim & unmount the device. */
    125     DASessionRef            pDASession;
    126     /** The disk arbitration disk reference. NULL if we didn't have to claim & unmount the device. */
    127     DADiskRef               pDADisk;
    128 #endif
    129 
    130 #ifdef RT_OS_WINDOWS
    131     /** Handle to the window we use to catch the device change broadcast messages. */
    132     volatile HWND           hwndDeviceChange;
    133     /** The unit mask. */
    134     DWORD                   fUnitMask;
    135 #endif
    136 
    137 #ifdef RT_OS_LINUX
    138     /** Double buffer required for ioctl with the Linux kernel as long as we use
    139      * remap_pfn_range() instead of vm_insert_page(). */
    140     uint8_t                *pbDoubleBuffer;
    141 #endif
    142 
    143 #ifdef RT_OS_FREEBSD
    144     /** The block size. Set when querying the media size. */
    145     uint32_t                cbBlock;
    146     /** SCSI bus number. */
    147     path_id_t               ScsiBus;
    148     /** target ID of the passthrough device. */
    149     target_id_t             ScsiTargetID;
    150     /** LUN of the passthrough device. */
    151     lun_id_t                ScsiLunID;
    152 #endif
    15397
    15498    /**
     
    163107    DECLCALLBACKMEMBER(int, pfnDoLock)(PDRVHOSTBASE pThis, bool fLock);
    164108
    165     /**
    166      * Queries the media size.
    167      * Can also be used to perform actions on media change.
    168      *
    169      * This callback pointer should be set to NULL if the default action is fine for this device.
    170      *
    171      * @returns VBox status code.
    172      * @param   pThis       Pointer to the instance data.
    173      * @param   pcb         Where to store the media size in bytes.
    174      */
    175     DECLCALLBACKMEMBER(int, pfnGetMediaSize)(PDRVHOSTBASE pThis, uint64_t *pcb);
    176 
    177     /***
    178      * Performs the polling operation.
    179      *
    180      * @returns VBox status code. (Failure means retry.)
    181      * @param   pThis       Pointer to the instance data.
    182      */
    183     DECLCALLBACKMEMBER(int, pfnPoll)(PDRVHOSTBASE pThis);
     109    union
     110    {
     111#ifdef DRVHOSTBASE_OS_INT_DECLARED
     112        DRVHOSTBASEOS       Os;
     113#endif
     114        uint8_t             abPadding[64];
     115    };
    184116} DRVHOSTBASE;
    185117
    186118
    187 int DRVHostBaseInitData(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, const char *pszCfgValid, PDMMEDIATYPE enmType);
    188 int DRVHostBaseInitFinish(PDRVHOSTBASE pThis);
    189 int DRVHostBaseMediaPresent(PDRVHOSTBASE pThis);
    190 void DRVHostBaseMediaNotPresent(PDRVHOSTBASE pThis);
     119DECLHIDDEN(int) DRVHostBaseInit(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, const char *pszCfgValid, PDMMEDIATYPE enmType);
     120DECLHIDDEN(int) DRVHostBaseMediaPresent(PDRVHOSTBASE pThis);
     121DECLHIDDEN(void) DRVHostBaseMediaNotPresent(PDRVHOSTBASE pThis);
    191122DECLCALLBACK(void) DRVHostBaseDestruct(PPDMDRVINS pDrvIns);
    192123
     
    200131DECLHIDDEN(int) drvHostBaseEjectOs(PDRVHOSTBASE pThis);
    201132
     133DECLHIDDEN(void) drvHostBaseInitOs(PDRVHOSTBASE pThis);
     134DECLHIDDEN(int) drvHostBaseOpenOs(PDRVHOSTBASE pThis, bool fReadOnly);
     135DECLHIDDEN(int) drvHostBaseMediaRefreshOs(PDRVHOSTBASE pThis);
    202136DECLHIDDEN(int) drvHostBaseQueryMediaStatusOs(PDRVHOSTBASE pThis, bool *pfMediaChanged, bool *pfMediaPresent);
    203 DECLHIDDEN(int) drvHostBasePollerWakeupOs(PDRVHOSTBASE pThis);
     137DECLHIDDEN(bool) drvHostBaseIsMediaPollingRequiredOs(PDRVHOSTBASE pThis);
    204138DECLHIDDEN(void) drvHostBaseDestructOs(PDRVHOSTBASE pThis);
    205 
    206 /** Makes a PDRVHOSTBASE out of a PPDMIMOUNT. */
    207 #define PDMIMOUNT_2_DRVHOSTBASE(pInterface)        ( (PDRVHOSTBASE)((uintptr_t)pInterface - RT_OFFSETOF(DRVHOSTBASE, IMount)) )
    208 
    209 /** Makes a PDRVHOSTBASE out of a PPDMIMEDIA. */
    210 #define PDMIMEDIA_2_DRVHOSTBASE(pInterface)        ( (PDRVHOSTBASE)((uintptr_t)pInterface - RT_OFFSETOF(DRVHOSTBASE, IMedia)) )
    211139
    212140RT_C_DECLS_END
  • trunk/src/VBox/Devices/Storage/DrvHostDVD.cpp

    r64278 r64316  
    2121*********************************************************************************************************************************/
    2222#define LOG_GROUP LOG_GROUP_DRV_HOST_DVD
    23 #define __STDC_LIMIT_MACROS
    24 #define __STDC_CONSTANT_MACROS
     23#if defined(RT_OS_DARWIN) || defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
     24# define USE_MEDIA_POLLING
     25#endif
    2526
    26 #ifdef RT_OS_DARWIN
    27 # include <mach/mach.h>
    28 # include <Carbon/Carbon.h>
    29 # include <IOKit/IOKitLib.h>
    30 # include <IOKit/IOCFPlugIn.h>
    31 # include <IOKit/scsi/SCSITaskLib.h>
    32 # include <IOKit/scsi/SCSICommandOperationCodes.h>
    33 # include <IOKit/storage/IOStorageDeviceCharacteristics.h>
    34 # include <mach/mach_error.h>
    35 # define USE_MEDIA_POLLING
    36 
    37 #elif defined RT_OS_LINUX
    38 # include <sys/ioctl.h>
    39 # include <linux/version.h>
    40 /* All the following crap is apparently not necessary anymore since Linux
    41  * version 2.6.29. */
    42 # if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
    43 /* This is a hack to work around conflicts between these linux kernel headers
    44  * and the GLIBC tcpip headers. They have different declarations of the 4
    45  * standard byte order functions. */
    46 #  define _LINUX_BYTEORDER_GENERIC_H
    47 /* This is another hack for not bothering with C++ unfriendly byteswap macros. */
    48 /* Those macros that are needed are defined in the header below. */
    49 #  include "swab.h"
    50 # endif
    51 # include <linux/cdrom.h>
    52 # include <sys/fcntl.h>
    53 # include <errno.h>
    54 # include <limits.h>
    55 # include <iprt/mem.h>
    56 # define USE_MEDIA_POLLING
    57 
    58 #elif defined(RT_OS_SOLARIS)
    59 # include <stropts.h>
    60 # include <fcntl.h>
    61 # include <errno.h>
    62 # include <pwd.h>
    63 # include <unistd.h>
    64 # include <syslog.h>
    65 # ifdef VBOX_WITH_SUID_WRAPPER
    66 #  include <auth_attr.h>
    67 # endif
    68 # include <sys/dkio.h>
    69 # include <sys/sockio.h>
    70 # include <sys/scsi/scsi.h>
    71 # define USE_MEDIA_POLLING
    72 
    73 #elif defined(RT_OS_WINDOWS)
    74 # pragma warning(disable : 4163)
    75 # define _interlockedbittestandset      they_messed_it_up_in_winnt_h_this_time_sigh__interlockedbittestandset
    76 # define _interlockedbittestandreset    they_messed_it_up_in_winnt_h_this_time_sigh__interlockedbittestandreset
    77 # define _interlockedbittestandset64    they_messed_it_up_in_winnt_h_this_time_sigh__interlockedbittestandset64
    78 # define _interlockedbittestandreset64  they_messed_it_up_in_winnt_h_this_time_sigh__interlockedbittestandreset64
    79 # include <iprt/win/windows.h>
    80 # include <winioctl.h>
    81 # include <ntddscsi.h>
    82 # pragma warning(default : 4163)
    83 # undef _interlockedbittestandset
    84 # undef _interlockedbittestandreset
    85 # undef _interlockedbittestandset64
    86 # undef _interlockedbittestandreset64
    87 # undef USE_MEDIA_POLLING
    88 
    89 #elif defined(RT_OS_FREEBSD)
    90 # include <sys/cdefs.h>
    91 # include <sys/param.h>
    92 # include <stdio.h>
    93 # include <cam/cam.h>
    94 # include <cam/cam_ccb.h>
    95 # define USE_MEDIA_POLLING
    96 
    97 #else
    98 # error "Unsupported Platform."
     27#if defined(RT_OS_SOLARIS) && defined(VBOX_WITH_SUID_WRAPPER)
     28# include <auth_attr.h>
    9929#endif
    10030
     
    11747*   Internal Functions                                                                                                           *
    11848*********************************************************************************************************************************/
    119 static DECLCALLBACK(int) drvHostDvdDoLock(PDRVHOSTBASE pThis, bool fLock);
    120 
    121 #ifdef VBOX_WITH_SUID_WRAPPER
    122 /**
    123  * Checks if the current user is authorized using Solaris' role-based access control.
    124  * Made as a separate function with so that it need not be invoked each time we need
    125  * to gain root access.
    126  *
    127  * @returns VBox error code.
    128  */
    129 static int solarisCheckUserAuth()
    130 {
    131     /* Uses Solaris' role-based access control (RBAC).*/
    132     struct passwd *pPass = getpwuid(getuid());
    133     if (pPass == NULL || chkauthattr("solaris.device.cdrw", pPass->pw_name) == 0)
    134         return VERR_PERMISSION_DENIED;
    135 
    136     return VINF_SUCCESS;
    137 }
    138 #endif
    139 
    140 /** @interface_method_impl{PDMIMOUNT,pfnUnmount} */
    141 static DECLCALLBACK(int) drvHostDvdUnmount(PPDMIMOUNT pInterface, bool fForce, bool fEject)
    142 {
    143     PDRVHOSTBASE pThis = PDMIMOUNT_2_DRVHOSTBASE(pInterface);
    144     RTCritSectEnter(&pThis->CritSect);
    145 
    146     /*
    147      * Validate state.
    148      */
    149     int rc = VINF_SUCCESS;
    150     if (!pThis->fLocked || fForce)
    151     {
    152         /* Unlock drive if necessary. */
    153         if (pThis->fLocked)
    154             drvHostBaseDoLockOs(pThis, false);
    155 
    156         if (fEject)
    157         {
    158             /*
    159              * Eject the disc.
    160              */
    161             rc = drvHostBaseEjectOs(pThis);
    162         }
    163 
    164         /*
    165          * Media is no longer present.
    166          */
    167         DRVHostBaseMediaNotPresent(pThis);  /** @todo This isn't thread safe! */
    168     }
    169     else
    170     {
    171         Log(("drvHostDvdUnmount: Locked\n"));
    172         rc = VERR_PDM_MEDIA_LOCKED;
    173     }
    174 
    175     RTCritSectLeave(&pThis->CritSect);
    176     LogFlow(("drvHostDvdUnmount: returns %Rrc\n", rc));
    177     return rc;
    178 }
    17949
    18050
     
    19565
    19666
    197 #ifdef USE_MEDIA_POLLING
    198 /**
    199  * Do media change polling.
    200  */
    201 static DECLCALLBACK(int) drvHostDvdPoll(PDRVHOSTBASE pThis)
    202 {
    203     /*
    204      * Poll for media change.
    205      */
    206     bool fMediaPresent = false;
    207     bool fMediaChanged = false;
    208     drvHostBaseQueryMediaStatusOs(pThis, &fMediaChanged, &fMediaPresent);
    209 
    210     RTCritSectEnter(&pThis->CritSect);
    211 
    212     int rc = VINF_SUCCESS;
    213     if (pThis->fMediaPresent != fMediaPresent)
    214     {
    215         LogFlow(("drvHostDvdPoll: %d -> %d\n", pThis->fMediaPresent, fMediaPresent));
    216         pThis->fMediaPresent = false;
    217         if (fMediaPresent)
    218             rc = DRVHostBaseMediaPresent(pThis);
    219         else
    220             DRVHostBaseMediaNotPresent(pThis);
    221     }
    222     else if (fMediaPresent)
    223     {
    224         /*
    225          * Poll for media change.
    226          */
    227         if (fMediaChanged)
    228         {
    229             LogFlow(("drvHostDVDMediaThread: Media changed!\n"));
    230             DRVHostBaseMediaNotPresent(pThis);
    231             rc = DRVHostBaseMediaPresent(pThis);
    232         }
    233     }
    234 
    235     RTCritSectLeave(&pThis->CritSect);
    236     return rc;
    237 }
    238 #endif /* USE_MEDIA_POLLING */
    239 
    240 
    24167/** @interface_method_impl{PDMIMEDIA,pfnSendCmd} */
    24268static DECLCALLBACK(int) drvHostDvdSendCmd(PPDMIMEDIA pInterface, const uint8_t *pbCmd,
     
    24470                                           uint8_t *pabSense, size_t cbSense, uint32_t cTimeoutMillies)
    24571{
    246     RT_NOREF(cbSense);
    247     PDRVHOSTBASE pThis = PDMIMEDIA_2_DRVHOSTBASE(pInterface);
     72    PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia);
    24873    int rc;
    24974    LogFlow(("%s: cmd[0]=%#04x txdir=%d pcbBuf=%d timeout=%d\n", __FUNCTION__, pbCmd[0], enmTxDir, *pcbBuf, cTimeoutMillies));
     
    276101
    277102
    278 /** @copydoc FNPDMDRVDESTRUCT */
    279 static DECLCALLBACK(void) drvHostDvdDestruct(PPDMDRVINS pDrvIns)
    280 {
    281     return DRVHostBaseDestruct(pDrvIns);
    282 }
    283 
    284 
    285103/**
    286104 * Construct a host dvd drive driver instance.
     
    294112    LogFlow(("drvHostDvdConstruct: iInstance=%d\n", pDrvIns->iInstance));
    295113
     114    bool fPassthrough;
     115    int rc = CFGMR3QueryBool(pCfg, "Passthrough", &fPassthrough);
     116    if (RT_SUCCESS(rc) && fPassthrough)
     117    {
     118        pThis->IMedia.pfnSendCmd = drvHostDvdSendCmd;
     119        /* Passthrough requires opening the device in R/W mode. */
     120        pThis->fReadOnlyConfig = false;
     121    }
     122
     123    pThis->pfnDoLock = drvHostDvdDoLock;
     124
    296125    /*
    297126     * Init instance data.
    298127     */
    299     int rc = DRVHostBaseInitData(pDrvIns, pCfg, "Path\0Interval\0Locked\0BIOSVisible\0AttachFailError\0Passthrough\0",
    300                                  PDMMEDIATYPE_DVD);
    301     if (RT_SUCCESS(rc))
    302     {
    303         /*
    304          * Override stuff.
    305          */
    306 #ifdef RT_OS_LINUX
    307         pThis->pbDoubleBuffer = (uint8_t *)RTMemAlloc(SCSI_MAX_BUFFER_SIZE);
    308         if (!pThis->pbDoubleBuffer)
    309             return VERR_NO_MEMORY;
    310 #endif
    311 
    312         bool fPassthrough;
    313         rc = CFGMR3QueryBool(pCfg, "Passthrough", &fPassthrough);
    314         if (RT_SUCCESS(rc) && fPassthrough)
    315         {
    316             pThis->IMedia.pfnSendCmd = drvHostDvdSendCmd;
    317             /* Passthrough requires opening the device in R/W mode. */
    318             pThis->fReadOnlyConfig = false;
    319 #ifdef VBOX_WITH_SUID_WRAPPER  /* Solaris setuid for Passthrough mode. */
    320             rc = solarisCheckUserAuth();
    321             if (RT_FAILURE(rc))
    322             {
    323                 Log(("DVD: solarisCheckUserAuth failed. Permission denied!\n"));
    324                 return rc;
    325             }
    326 #endif /* VBOX_WITH_SUID_WRAPPER */
    327         }
    328 
    329         pThis->IMount.pfnUnmount = drvHostDvdUnmount;
    330         pThis->pfnDoLock         = drvHostDvdDoLock;
    331 #ifdef USE_MEDIA_POLLING
    332         if (!fPassthrough)
    333             pThis->pfnPoll       = drvHostDvdPoll;
    334         else
    335             pThis->pfnPoll       = NULL;
    336 #endif
    337 
    338         /*
    339          * 2nd init part.
    340          */
    341         rc = DRVHostBaseInitFinish(pThis);
    342     }
    343     if (RT_FAILURE(rc))
    344     {
    345         if (!pThis->fAttachFailError)
    346         {
    347             /* Suppressing the attach failure error must not affect the normal
    348              * DRVHostBaseDestruct, so reset this flag below before leaving. */
    349             pThis->fKeepInstance = true;
    350             rc = VINF_SUCCESS;
    351         }
    352         DRVHostBaseDestruct(pDrvIns);
    353         pThis->fKeepInstance = false;
    354     }
    355 
     128    rc = DRVHostBaseInit(pDrvIns, pCfg, "Path\0Interval\0Locked\0BIOSVisible\0AttachFailError\0Passthrough\0",
     129                         PDMMEDIATYPE_DVD);
    356130    LogFlow(("drvHostDvdConstruct: returns %Rrc\n", rc));
    357131    return rc;
     
    385159    drvHostDvdConstruct,
    386160    /* pfnDestruct */
    387     drvHostDvdDestruct,
     161    DRVHostBaseDestruct,
    388162    /* pfnRelocate */
    389163    NULL,
  • trunk/src/VBox/Devices/Storage/DrvHostFloppy.cpp

    r64278 r64316  
    2323*********************************************************************************************************************************/
    2424#define LOG_GROUP LOG_GROUP_DRV_HOST_FLOPPY
    25 #ifdef RT_OS_LINUX
    26 # include <sys/ioctl.h>
    27 # include <linux/fd.h>
    28 # include <sys/fcntl.h>
    29 # include <errno.h>
    30 # elif defined(RT_OS_WINDOWS)
    31 # include <iprt/win/windows.h>
    32 # include <dbt.h>
    33 #endif
    3425
    3526#include <VBox/vmm/pdmdrv.h>
     
    4839
    4940
    50 /**
    51  * Floppy driver instance data.
    52  */
    53 typedef struct DRVHOSTFLOPPY
    54 {
    55     DRVHOSTBASE     Base;
    56     /** Previous poll status. */
    57     bool            fPrevDiskIn;
    58 
    59 } DRVHOSTFLOPPY, *PDRVHOSTFLOPPY;
    60 
    61 
    62 #ifdef RT_OS_LINUX
    63 /**
    64  * This thread will periodically poll the Floppy for media presence.
    65  *
    66  * @returns Ignored.
    67  * @param   ThreadSelf  Handle of this thread. Ignored.
    68  * @param   pvUser      Pointer to the driver instance structure.
    69  */
    70 static DECLCALLBACK(int) drvHostFloppyPoll(PDRVHOSTBASE pThis)
    71 {
    72     PDRVHOSTFLOPPY          pThisFloppy = (PDRVHOSTFLOPPY)pThis;
    73     floppy_drive_struct     DrvStat;
    74     int rc = ioctl(RTFileToNative(pThis->hFileDevice), FDPOLLDRVSTAT, &DrvStat);
    75     if (rc)
    76         return RTErrConvertFromErrno(errno);
    77 
    78     RTCritSectEnter(&pThis->CritSect);
    79     bool fDiskIn = !(DrvStat.flags & (FD_VERIFY | FD_DISK_NEWCHANGE));
    80     if (    fDiskIn
    81         &&  !pThisFloppy->fPrevDiskIn)
    82     {
    83         if (pThis->fMediaPresent)
    84             DRVHostBaseMediaNotPresent(pThis);
    85         rc = DRVHostBaseMediaPresent(pThis);
    86         if (RT_FAILURE(rc))
    87         {
    88             pThisFloppy->fPrevDiskIn = fDiskIn;
    89             RTCritSectLeave(&pThis->CritSect);
    90             return rc;
    91         }
    92     }
    93 
    94     if (    !fDiskIn
    95         &&  pThisFloppy->fPrevDiskIn
    96         &&  pThis->fMediaPresent)
    97         DRVHostBaseMediaNotPresent(pThis);
    98     pThisFloppy->fPrevDiskIn = fDiskIn;
    99 
    100     RTCritSectLeave(&pThis->CritSect);
    101     return VINF_SUCCESS;
    102 }
    103 #endif /* RT_OS_LINUX */
    104 
    10541
    10642/**
     
    11046{
    11147    RT_NOREF(fFlags);
    112     PDRVHOSTFLOPPY pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTFLOPPY);
    11348    LogFlow(("drvHostFloppyConstruct: iInstance=%d\n", pDrvIns->iInstance));
    11449
     
    11651     * Init instance data.
    11752     */
    118     int rc = DRVHostBaseInitData(pDrvIns, pCfg, "Path\0ReadOnly\0Interval\0Locked\0BIOSVisible\0",
    119                                  PDMMEDIATYPE_FLOPPY_1_44);
    120     if (RT_SUCCESS(rc))
    121     {
    122         /*
    123          * Override stuff.
    124          */
    125 #ifdef RT_OS_LINUX
    126         pThis->Base.pfnPoll         = drvHostFloppyPoll;
    127 #endif
    128 
    129         /*
    130          * 2nd init part.
    131          */
    132         rc = DRVHostBaseInitFinish(&pThis->Base);
    133     }
    134 
    135     if (RT_FAILURE(rc))
    136     {
    137         if (!pThis->Base.fAttachFailError)
    138         {
    139             /* Suppressing the attach failure error must not affect the normal
    140              * DRVHostBaseDestruct, so reset this flag below before leaving. */
    141             pThis->Base.fKeepInstance = true;
    142             rc = VINF_SUCCESS;
    143         }
    144         DRVHostBaseDestruct(pDrvIns);
    145         pThis->Base.fKeepInstance = false;
    146     }
    147 
     53    int rc = DRVHostBaseInit(pDrvIns, pCfg, "Path\0ReadOnly\0Interval\0Locked\0BIOSVisible\0",
     54                             PDMMEDIATYPE_FLOPPY_1_44);
    14855    LogFlow(("drvHostFloppyConstruct: returns %Rrc\n", rc));
    14956    return rc;
     
    17380    ~0U,
    17481    /* cbInstance */
    175     sizeof(DRVHOSTFLOPPY),
     82    sizeof(DRVHOSTBASE),
    17683    /* pfnConstruct */
    17784    drvHostFloppyConstruct,
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette