VirtualBox

Changeset 1965 in vbox for trunk


Ignore:
Timestamp:
Apr 6, 2007 6:14:10 AM (18 years ago)
Author:
vboxsync
Message:

HostDVD support for Darwin.

Location:
trunk/src/VBox/Devices
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Builtins.cpp

    r1763 r1965  
    102102    if (VBOX_FAILURE(rc))
    103103        return rc;
    104 #if defined(VBOX_WITH_USB) && (defined(__WIN__) || defined(__LINUX__) || defined(__L4ENV__))
     104#if defined(VBOX_WITH_USB) && (defined(__L4ENV__) || defined(__LINUX__) || defined(__WIN__))
    105105    rc = pCallbacks->pfnRegister(pCallbacks, &g_DeviceOHCI);
    106106    if (VBOX_FAILURE(rc))
     
    153153    if (VBOX_FAILURE(rc))
    154154        return rc;
    155 #if !defined(__L4ENV__) && !defined(__DARWIN__) && !defined(__OS2__)
     155#if defined(__DARWIN__) || defined(__LINUX__) || defined(__WIN__)
    156156    rc = pCallbacks->pfnRegister(pCallbacks, &g_DrvHostDVD);
    157157    if (VBOX_FAILURE(rc))
    158158        return rc;
     159#endif
     160#if defined(__LINUX__) || defined(__WIN__)
    159161    rc = pCallbacks->pfnRegister(pCallbacks, &g_DrvHostFloppy);
    160162    if (VBOX_FAILURE(rc))
     
    185187        return rc;
    186188#endif
    187 #if !defined(__DARWIN__) && !defined(__OS2__)
     189#if defined(__L4ENV__) || defined(__LINUX__) || defined(__WIN__)
    188190    rc = pCallbacks->pfnRegister(pCallbacks, &g_DrvHostInterface);
    189191    if (VBOX_FAILURE(rc))
     
    203205        return rc;
    204206
    205 #if defined(VBOX_WITH_USB) && (defined(__WIN__) || defined(__LINUX__) || defined(__L4ENV__))
     207#if defined(VBOX_WITH_USB) && (defined(__L4ENV__) || defined(__LINUX__) || defined(__WIN__))
    206208    rc = pCallbacks->pfnRegister(pCallbacks, &g_DrvVUSBRootHub);
    207209    if (VBOX_FAILURE(rc))
  • trunk/src/VBox/Devices/Makefile

    r1931 r1965  
    122122VBoxDD_LIBS.darwin      = \
    123123        $(LIB_REM)
    124 VBoxDD_LDFLAGS.darwin   = -install_name @executable_path/VBoxDD.dylib -framework CoreAudio
     124VBoxDD_LDFLAGS.darwin   = -install_name @executable_path/VBoxDD.dylib -framework CoreAudio -framework IOKit -framework Carbon
    125125VBoxDD_LDFLAGS.linux    = -Wl,--no-undefined
    126126VBoxDD_LDFLAGS.l4       = -Wl,--no-undefined
     
    128128
    129129# damn, fix this.
    130 ifeq ($(BUILD_TARGET),win) 
     130ifeq ($(BUILD_TARGET),win)
    131131$(PATH_LIB)/VBoxDD2.lib: $(PATH_BIN)/VBoxDD2.dll
    132132$(PATH_LIB)/VBoxDDU.lib: $(PATH_BIN)/VBoxDDU.dll
     
    336336        Network/slirp
    337337Drivers_SOURCES    = \
     338        Audio/audio.c \
     339        Audio/audiosniffer.c \
     340        Audio/mixeng.c \
     341        Audio/noaudio.c \
     342        Input/DrvKeyboardQueue.cpp \
    338343        Input/DrvMouseQueue.cpp \
    339         Input/DrvKeyboardQueue.cpp \
    340         Storage/VBoxHDD.cpp \
    341         Storage/DrvBlock.cpp \
    342         Storage/VmdkHDD.cpp \
    343         Storage/DrvMediaISO.cpp \
    344         Storage/DrvRawImage.cpp \
    345         Storage/DrvHostBase.cpp \
    346         Storage/DrvHostDVD.cpp \
    347         Storage/DrvHostFloppy.cpp \
    348         Storage/DrvHostRawDisk.cpp \
    349         PC/DrvACPI.cpp \
    350344        Network/DrvIntNet.cpp \
     345        Network/DrvNAT.cpp \
    351346        Network/DrvNetSniffer.cpp \
    352         Network/DrvNAT.cpp \
     347        Network/slirp/bootp.c \
    353348        Network/slirp/cksum.c \
     349        Network/slirp/debug.c \
    354350        Network/slirp/if.c \
    355351        Network/slirp/ip_icmp.c \
    356352        Network/slirp/ip_input.c \
    357353        Network/slirp/ip_output.c \
    358         Network/slirp/slirp.c \
    359354        Network/slirp/mbuf.c \
    360355        Network/slirp/misc.c \
    361356        Network/slirp/sbuf.c \
     357        Network/slirp/slirp.c \
    362358        Network/slirp/socket.c \
    363359        Network/slirp/tcp_input.c \
     
    367363        Network/slirp/tftp.c \
    368364        Network/slirp/udp.c \
    369         Network/slirp/bootp.c \
    370         Network/slirp/debug.c \
    371         Audio/audio.c \
    372         Audio/mixeng.c \
    373         Audio/noaudio.c \
    374         Audio/audiosniffer.c \
     365        PC/DrvACPI.cpp \
    375366        Serial/DrvChar.cpp \
    376         Serial/DrvNamedPipe.cpp
     367        Serial/DrvNamedPipe.cpp \
     368        Storage/DrvBlock.cpp \
     369        Storage/DrvHostBase.cpp \
     370        Storage/DrvHostDVD.cpp \
     371        Storage/DrvHostFloppy.cpp \
     372        Storage/DrvHostRawDisk.cpp \
     373        Storage/DrvMediaISO.cpp \
     374        Storage/DrvRawImage.cpp \
     375        Storage/VBoxHDD.cpp \
     376        Storage/VmdkHDD.cpp
    377377
    378378# -- OS specific --
     
    380380ifeq ($(BUILD_TARGET),darwin)
    381381Drivers_SOURCES      := $(filter-out \
    382         Storage/DrvHost% \
     382        Storage/DrvHostRaw% \
     383        Storage/DrvHostFloppy% \
    383384        , $(Drivers_SOURCES)) \
    384385        Audio/coreaudio.c
  • trunk/src/VBox/Devices/Storage/DrvHostBase.cpp

    r262 r1965  
    2626*******************************************************************************/
    2727#define LOG_GROUP LOG_GROUP_DRV_HOST_BASE
    28 #ifdef __LINUX__
     28#ifdef __DARWIN__
     29# include <mach/mach.h>
     30# include <Carbon/Carbon.h>
     31# include <IOKit/IOKitLib.h>
     32# include <IOKit/storage/IOStorageDeviceCharacteristics.h>
     33# include <IOKit/scsi-commands/SCSITaskLib.h>
     34# include <IOKit/scsi-commands/SCSICommandOperationCodes.h>
     35# include <mach/mach_error.h>
     36# include <VBox/scsi.h>
     37
     38#elif defined(__L4ENV__)
     39  /* Nothing special requires... yeah, right. */
     40
     41#elif defined(__LINUX__)
    2942# include <sys/ioctl.h>
    3043# include <sys/fcntl.h>
     
    7992        /*IN*/ FS_INFORMATION_CLASS FileSystemInformationClass );
    8093
    81 #elif defined(__L4ENV__)
    82 
    83 #else /* !__WIN__ nor __LINUX__ nor __L4ENV__ */
     94#else
    8495# error "Unsupported Platform."
    85 #endif /* !__WIN__ nor __LINUX__ nor __L4ENV__ */
     96#endif
    8697
    8798#include <VBox/pdm.h>
     
    100111#include <iprt/asm.h>
    101112#include <iprt/critsect.h>
     113#include <iprt/ctype.h>
    102114
    103115#include "DrvHostBase.h"
     
    120132     */
    121133    int rc;
     134#ifdef __DARWIN__
     135    if (    pThis->fMediaPresent
     136        &&  pThis->ppScsiTaskDI
     137        &&  pThis->cbBlock)
     138#else
    122139    if (pThis->fMediaPresent)
    123     {
     140#endif
     141    {
     142#ifdef __DARWIN__
     143        /*
     144         * Issue a READ(12) request.
     145         */
     146        const uint32_t LBA = off / pThis->cbBlock;
     147        AssertReturn(!(off % pThis->cbBlock), VERR_INVALID_PARAMETER);
     148        const uint32_t cBlocks = cbRead / pThis->cbBlock;
     149        AssertReturn(!(cbRead % pThis->cbBlock), VERR_INVALID_PARAMETER);
     150        uint8_t abCmd[16] =
     151        {
     152            SCSI_READ_12, 0,
     153            RT_BYTE4(LBA),     RT_BYTE3(LBA),     RT_BYTE2(LBA),     RT_BYTE1(LBA),
     154            RT_BYTE4(cBlocks), RT_BYTE3(cBlocks), RT_BYTE2(cBlocks), RT_BYTE1(cBlocks),
     155            0, 0, 0, 0, 0
     156        };
     157        rc = DRVHostBaseScsiCmd(pThis, abCmd, 12, PDMBLOCKTXDIR_FROM_DEVICE, pvBuf, &cbRead, NULL, 0, 0);
     158
     159#else
    124160        /*
    125161         * Seek and read.
     
    143179            Log(("%s-%d: drvHostBaseRead: RTFileSeek(%d,%#llx,) -> %Vrc\n", pThis->pDrvIns->pDrvReg->szDriverName,
    144180                 pThis->pDrvIns->iInstance, pThis->FileDevice, off, rc));
     181#endif
    145182    }
    146183    else
     
    172209        if (pThis->fMediaPresent)
    173210        {
     211#ifdef __DARWIN__
     212            /** @todo write support... */
     213            rc = VERR_WRITE_PROTECT;
     214
     215#else
    174216            /*
    175217             * Seek and write.
     
    187229                Log(("%s-%d: drvHostBaseWrite: RTFileSeek(%d,%#llx,) -> %Vrc\n",
    188230                     pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance, pThis->FileDevice, off, rc));
     231#endif
    189232        }
    190233        else
     
    211254    if (pThis->fMediaPresent)
    212255    {
     256#ifdef __DARWIN__
     257        rc = VINF_SUCCESS;
     258        /** @todo scsi device buffer flush... */
     259#else
    213260        rc = RTFileFlush(pThis->FileDevice);
     261#endif
    214262    }
    215263    else
     
    512560
    513561/**
    514  * Wrapper for open / RTFileOpen.
     562 * Wrapper for open / RTFileOpen / IOKit.
     563 *
     564 * @remark  The Darwin code must correspond exactly to the enumeration
     565 *          done in Main/darwin/iokit.c.
    515566 */
    516567static int drvHostBaseOpen(PDRVHOSTBASE pThis, PRTFILE pFileDevice, bool fReadOnly)
    517568{
    518 #ifdef __LINUX__
     569#ifdef __DARWIN__
     570    /* Darwin is kind of special... */
     571    Assert(!pFileDevice); NOREF(pFileDevice);
     572    Assert(!pThis->cbBlock);
     573    Assert(!pThis->MasterPort);
     574    Assert(!pThis->ppMMCDI);
     575    Assert(!pThis->ppScsiTaskDI);
     576
     577    /*
     578     * Open the master port on the first invocation.
     579     */
     580    kern_return_t krc = IOMasterPort(MACH_PORT_NULL, &pThis->MasterPort);
     581    AssertReturn(krc == KERN_SUCCESS, VERR_GENERAL_FAILURE);
     582
     583    /*
     584     * Create a matching dictionary for searching for DVD services in the IOKit.
     585     *
     586     * [If I understand this correctly, plain CDROMs doesn't show up as
     587     * IODVDServices. Too keep things simple, we will only support DVDs
     588     * until somebody complains about it and we get hardware to test it on.
     589     * (Unless I'm much mistaken, there aren't any (orignal) intel macs with
     590     * plain cdroms.)]
     591     */
     592    CFMutableDictionaryRef RefMatchingDict = IOServiceMatching("IODVDServices");
     593    AssertReturn(RefMatchingDict, NULL);
     594
     595    /*
     596     * do the search and get a collection of keyboards.
     597     */
     598    io_iterator_t DVDServices = NULL;
     599    IOReturn irc = IOServiceGetMatchingServices(pThis->MasterPort, RefMatchingDict, &DVDServices);
     600    AssertMsgReturn(irc == kIOReturnSuccess, ("irc=%d\n", irc), NULL);
     601    RefMatchingDict = NULL; /* the reference is consumed by IOServiceGetMatchingServices. */
     602
     603    /*
     604     * Enumerate the DVD drives (services).
     605     * (This enumeration must be identical to the one performed in DrvHostBase.cpp.)
     606     */
     607    int rc = VERR_FILE_NOT_FOUND;
     608    unsigned i = 0;
     609    io_object_t DVDService;
     610    while ((DVDService = IOIteratorNext(DVDServices)) != 0)
     611    {
     612        /*
     613         * Get the properties we use to identify the DVD drive.
     614         *
     615         * While there is a (weird 12 byte) GUID, it isn't persistent
     616         * accross boots. So, we have to use a combination of the
     617         * vendor name and product name properties with an optional
     618         * sequence number for identification.
     619         */
     620        CFMutableDictionaryRef PropsRef = 0;
     621        kern_return_t krc = IORegistryEntryCreateCFProperties(DVDService, &PropsRef, kCFAllocatorDefault, kNilOptions);
     622        if (krc == KERN_SUCCESS)
     623        {
     624            /* Get the Device Characteristics dictionary. */
     625            CFDictionaryRef DevCharRef = (CFDictionaryRef)CFDictionaryGetValue(PropsRef, CFSTR(kIOPropertyDeviceCharacteristicsKey));
     626            if (DevCharRef)
     627            {
     628                /* The vendor name. */
     629                char szVendor[128];
     630                char *pszVendor = &szVendor[0];
     631                CFTypeRef ValueRef = CFDictionaryGetValue(DevCharRef, CFSTR(kIOPropertyVendorNameKey));
     632                if (    ValueRef
     633                    &&  CFGetTypeID(ValueRef) == CFStringGetTypeID()
     634                    &&  CFStringGetCString((CFStringRef)ValueRef, szVendor, sizeof(szVendor), kCFStringEncodingUTF8))
     635                    pszVendor = RTStrStrip(szVendor);
     636                else
     637                    *pszVendor = '\0';
     638
     639                /* The product name. */
     640                char szProduct[128];
     641                char *pszProduct = &szProduct[0];
     642                ValueRef = CFDictionaryGetValue(DevCharRef, CFSTR(kIOPropertyProductNameKey));
     643                if (    ValueRef
     644                    &&  CFGetTypeID(ValueRef) == CFStringGetTypeID()
     645                    &&  CFStringGetCString((CFStringRef)ValueRef, szProduct, sizeof(szProduct), kCFStringEncodingUTF8))
     646                    pszProduct = RTStrStrip(szProduct);
     647                else
     648                    *pszProduct = '\0';
     649
     650                /* Construct the two names and compare thwm with the one we're searching for. */
     651                char szName1[256 + 32];
     652                char szName2[256 + 32];
     653                if (*pszVendor || *pszProduct)
     654                {
     655                    if (*pszVendor && *pszProduct)
     656                    {
     657                        RTStrPrintf(szName1, sizeof(szName1), "%s %s", pszVendor, pszProduct);
     658                        RTStrPrintf(szName2, sizeof(szName2), "%s %s (#%u)", pszVendor, pszProduct, i);
     659                    }
     660                    else
     661                    {
     662                        strcpy(szName1, *pszVendor ? pszVendor : pszProduct);
     663                        RTStrPrintf(szName2, sizeof(szName2), "%s %s (#%u)", *pszVendor ? pszVendor : pszProduct, i);
     664                    }
     665                }
     666                else
     667                {
     668                    RTStrPrintf(szName1, sizeof(szName1), "(#%u)", i);
     669                    strcpy(szName2, szName1);
     670                }
     671
     672                if (    !strcmp(szName1, pThis->pszDeviceOpen)
     673                    ||  !strcmp(szName2, pThis->pszDeviceOpen))
     674                {
     675                    /*
     676                     * Found it! Now, get the client interface and stuff.
     677                     * Note that we could also query kIOSCSITaskDeviceUserClientTypeID here if the
     678                     * MMC client plugin is missing. For now we assume this won't be necessary.
     679                     */
     680                    SInt32 Score = 0;
     681                    IOCFPlugInInterface **ppPlugInInterface = NULL;
     682                    krc = IOCreatePlugInInterfaceForService(DVDService, kIOMMCDeviceUserClientTypeID, kIOCFPlugInInterfaceID,
     683                                                            &ppPlugInInterface, &Score);
     684                    if (krc == KERN_SUCCESS)
     685                    {
     686                        HRESULT hrc = (*ppPlugInInterface)->QueryInterface(ppPlugInInterface,
     687                                                                           CFUUIDGetUUIDBytes(kIOMMCDeviceInterfaceID),
     688                                                                           (LPVOID *)&pThis->ppMMCDI);
     689                        (*ppPlugInInterface)->Release(ppPlugInInterface);
     690                        ppPlugInInterface = NULL;
     691                        if (hrc == S_OK)
     692                        {
     693                            pThis->ppScsiTaskDI = (*pThis->ppMMCDI)->GetSCSITaskDeviceInterface(pThis->ppMMCDI);
     694                            if (pThis->ppScsiTaskDI)
     695                                rc = VINF_SUCCESS;
     696                            else
     697                            {
     698                                LogRel(("GetSCSITaskDeviceInterface failed on '%s'\n", pThis->pszDeviceOpen));
     699                                rc = VERR_NOT_SUPPORTED;
     700                                (*pThis->ppMMCDI)->Release(pThis->ppMMCDI);
     701                            }
     702                        }
     703                        else
     704                        {
     705                            rc = VERR_GENERAL_FAILURE;//RTErrConvertFromDarwinCOM(krc);
     706                            pThis->ppMMCDI = NULL;
     707                        }
     708                    }
     709                    else /* Check for kIOSCSITaskDeviceUserClientTypeID? */
     710                        rc = VERR_GENERAL_FAILURE;//RTErrConvertFromDarwinKern(krc);
     711
     712                    /*
     713                     * Obtain exclusive access to the device
     714                     * (to prevent the host and/or user from interfering).
     715                     */
     716                    if (VBOX_SUCCESS(rc))
     717                    {
     718                        irc = (*pThis->ppScsiTaskDI)->ObtainExclusiveAccess(pThis->ppScsiTaskDI);
     719                        if (irc == kIOReturnSuccess)
     720                            rc = VINF_SUCCESS;
     721                        else if (irc == kIOReturnBusy)
     722                            rc = VERR_DRIVE_LOCKED;         /* mounted. */
     723                        else if (irc == kIOReturnExclusiveAccess)
     724                            rc = VERR_SHARING_VIOLATION;    /* already used exclusivly. */
     725                        else
     726                            rc = VERR_GENERAL_FAILURE;
     727                    }
     728
     729                    /* Cleanup on failure. */
     730                    if (VBOX_FAILURE(rc))
     731                    {
     732                        if (pThis->ppScsiTaskDI)
     733                        {
     734                            (*pThis->ppScsiTaskDI)->Release(pThis->ppScsiTaskDI);
     735                            pThis->ppScsiTaskDI = NULL;
     736                        }
     737                        if (pThis->ppMMCDI)
     738                        {
     739                            (*pThis->ppMMCDI)->Release(pThis->ppMMCDI);
     740                            pThis->ppMMCDI = NULL;
     741                        }
     742                    }
     743
     744                    IOObjectRelease(DVDService);
     745                    break;
     746                }
     747            }
     748            CFRelease(PropsRef);
     749        }
     750        else
     751            AssertMsgFailed(("krc=%#x\n", krc));
     752
     753        IOObjectRelease(DVDService);
     754        i++;
     755    }
     756
     757    IOObjectRelease(DVDServices);
     758    return rc;
     759
     760#elif defined(__LINUX__)
     761    /** @todo we've got RTFILE_O_NON_BLOCK now. Change the code to use RTFileOpen. */
    519762    int FileDevice = open(pThis->pszDeviceOpen, (pThis->fReadOnlyConfig ? O_RDONLY : O_RDWR) | O_NONBLOCK);
    520763    if (FileDevice < 0)
     
    522765    *pFileDevice = FileDevice;
    523766    return VINF_SUCCESS;
     767
    524768#else
    525769    return RTFileOpen(pFileDevice, pThis->pszDeviceOpen,
     
    528772}
    529773
     774
    530775/**
    531776 * (Re)opens the device.
     777 *
     778 * This is used to open the device during construction, but it's also used to re-open
     779 * the device when a media is inserted. This re-open will kill off any cached data
     780 * that Linux for some peculiar reason thinks should survive a media change...
    532781 *
    533782 * @returns VBOX status code.
     
    536785static int drvHostBaseReopen(PDRVHOSTBASE pThis)
    537786{
     787#ifndef __DARWIN__ /* Only *one* open for darwin. */
    538788    LogFlow(("%s-%d: drvHostBaseReopen: '%s'\n", pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance, pThis->pszDeviceOpen));
    539789
    540     /*
    541      * Reopen the device to kill any cached data which for some peculiar reason stays on some OSes (linux)...
    542      */
    543790    RTFILE FileDevice;
    544791    int rc = drvHostBaseOpen(pThis, &FileDevice, pThis->fReadOnlyConfig);
     
    564811        RTFileClose(pThis->FileDevice);
    565812    pThis->FileDevice = FileDevice;
     813#endif /* !__DARWIN__ */
    566814    return VINF_SUCCESS;
    567815}
     
    577825static int drvHostBaseGetMediaSize(PDRVHOSTBASE pThis, uint64_t *pcb)
    578826{
    579 #ifdef __WIN__
     827#ifdef __DARWIN__
     828    /*
     829     * Try a READ_CAPACITY command...
     830     */
     831    struct
     832    {
     833        uint32_t cBlocks;
     834        uint32_t cbBlock;
     835    } Buf = {0, 0};
     836    size_t cbBuf = sizeof(Buf);
     837    uint8_t abCmd[16] =
     838    {
     839        SCSI_READ_CAPACITY, 0, 0, 0, 0, 0, 0,
     840        0,0,0,0,0,0,0,0,0
     841    };
     842    int rc = DRVHostBaseScsiCmd(pThis, abCmd, 6, PDMBLOCKTXDIR_FROM_DEVICE, &Buf, &cbBuf, NULL, 0, 0);
     843    if (VBOX_SUCCESS(rc))
     844    {
     845        Assert(cbBuf == sizeof(Buf));
     846        Buf.cBlocks = RT_BE2H_U32(Buf.cBlocks);
     847        Buf.cbBlock = RT_BE2H_U32(Buf.cbBlock);
     848        //if (Buf.cbBlock > 2048) /* everyone else is doing this... check if it needed/right.*/
     849        //    Buf.cbBlock = 2048;
     850        pThis->cbBlock = Buf.cbBlock;
     851
     852        *pcb = (uint64_t)Buf.cBlocks * Buf.cbBlock;
     853    }
     854    return rc;
     855
     856#elif defined(__WIN__)
    580857    /* use NT api, retry a few times if the media is being verified. */
    581858    IO_STATUS_BLOCK             IoStatusBlock = {0};
     
    610887#endif
    611888}
     889
     890
     891#ifdef __DARWIN__
     892/**
     893 * Execute a SCSI command.
     894 *
     895 * @param pThis             The instance data.
     896 * @param pbCmd             Pointer to the SCSI command.
     897 * @param cbCmd             The size of the SCSI command.
     898 * @param enmTxDir          The transfer direction.
     899 * @param pvBuf             The buffer. Can be NULL if enmTxDir is PDMBLOCKTXDIR_NONE.
     900 * @param pcbBuf            Where to get the buffer size from and put the actual transfer size. Can be NULL.
     901 * @param pbSense           Where to put the sense data. Can be NULL.
     902 * @param cbSense           Size of the sense data buffer.
     903 * @param cTimeoutMillies   The timeout. 0 mean the default timeout.
     904 *
     905 * @returns VINF_SUCCESS on success (no sense code).
     906 * @returns VERR_UNRESOLVED_ERROR if sense code is present.
     907 * @returns Some other VBox status code on failures without sense code.
     908 *
     909 * @todo Fix VERR_UNRESOLVED_ERROR abuse.
     910 */
     911DECLCALLBACK(int) DRVHostBaseScsiCmd(PDRVHOSTBASE pThis, const uint8_t *pbCmd, size_t cbCmd, PDMBLOCKTXDIR enmTxDir,
     912                                     void *pvBuf, size_t *pcbBuf, uint8_t *pbSense, size_t cbSense, uint32_t cTimeoutMillies)
     913{
     914    /*
     915     * Minimal input validation.
     916     */
     917    Assert(enmTxDir == PDMBLOCKTXDIR_NONE || enmTxDir == PDMBLOCKTXDIR_FROM_DEVICE || enmTxDir == PDMBLOCKTXDIR_TO_DEVICE);
     918    Assert(!pvBuf || (pcbBuf && *pcbBuf));
     919    Assert(pvBuf || enmTxDir == PDMBLOCKTXDIR_NONE);
     920    Assert(pbSense || !cbSense);
     921    AssertPtr(pbCmd);
     922    Assert(cbCmd <= 16 && cbCmd >= 1);
     923    const size_t cbBuf = pcbBuf ? *pcbBuf : 0;
     924    if (pcbBuf)
     925        *pcbBuf = 0;
     926
     927# ifdef __DARWIN__
     928    Assert(pThis->ppScsiTaskDI);
     929
     930    int rc = VERR_GENERAL_FAILURE;
     931    SCSITaskInterface **ppScsiTaskI = (*pThis->ppScsiTaskDI)->CreateSCSITask(pThis->ppScsiTaskDI);
     932    if (!ppScsiTaskI)
     933        return VERR_NO_MEMORY;
     934    do
     935    {
     936        /* Setup the scsi command. */
     937        SCSICommandDescriptorBlock cdb = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
     938        memcpy(&cdb[0], pbCmd, cbCmd);
     939        IOReturn irc = (*ppScsiTaskI)->SetCommandDescriptorBlock(ppScsiTaskI, cdb, cbCmd);
     940        AssertBreak(irc == kIOReturnSuccess,);
     941
     942        /* Setup the buffer. */
     943        if (enmTxDir == PDMBLOCKTXDIR_NONE)
     944            irc = (*ppScsiTaskI)->SetScatterGatherEntries(ppScsiTaskI, NULL, 0, 0, kSCSIDataTransfer_NoDataTransfer);
     945        else
     946        {
     947            IOVirtualRange Range = { (IOVirtualAddress)pvBuf, cbBuf };
     948            irc = (*ppScsiTaskI)->SetScatterGatherEntries(ppScsiTaskI, &Range, 1, cbBuf,
     949                                                          enmTxDir == PDMBLOCKTXDIR_FROM_DEVICE
     950                                                          ? kSCSIDataTransfer_FromTargetToInitiator
     951                                                          : kSCSIDataTransfer_FromInitiatorToTarget);
     952        }
     953        AssertBreak(irc == kIOReturnSuccess,);
     954
     955        /* Set the timeout. */
     956        irc = (*ppScsiTaskI)->SetTimeoutDuration(ppScsiTaskI, cTimeoutMillies ? cTimeoutMillies : 30000 /*ms*/);
     957        AssertBreak(irc == kIOReturnSuccess,);
     958
     959        /* Execute the command and get the response. */
     960        SCSI_Sense_Data SenseData = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
     961        SCSIServiceResponse     ServiceResponse = kSCSIServiceResponse_Request_In_Process;
     962        SCSITaskStatus TaskStatus = kSCSITaskStatus_GOOD;
     963        UInt64 cbReturned = 0;
     964        irc = (*ppScsiTaskI)->ExecuteTaskSync(ppScsiTaskI, &SenseData, &TaskStatus, &cbReturned);
     965        AssertBreak(irc == kIOReturnSuccess,);
     966        if (pcbBuf)
     967            *pcbBuf = cbReturned;
     968
     969        irc = (*ppScsiTaskI)->GetSCSIServiceResponse(ppScsiTaskI, &ServiceResponse);
     970        AssertBreak(irc == kIOReturnSuccess,);
     971        AssertBreak(ServiceResponse == kSCSIServiceResponse_TASK_COMPLETE,);
     972
     973        if (TaskStatus == kSCSITaskStatus_GOOD)
     974            rc = VINF_SUCCESS;
     975        else if (   TaskStatus == kSCSITaskStatus_CHECK_CONDITION
     976                 && pbSense)
     977        {
     978            memset(pbSense, 0, cbSense); /* lazy */
     979            memcpy(pbSense, &SenseData, RT_MIN(sizeof(SenseData), cbSense));
     980            rc = VERR_UNRESOLVED_ERROR;
     981        }
     982        /** @todo convert sense codes when caller doesn't wish to do this himself. */
     983        /*else if (   TaskStatus == kSCSITaskStatus_CHECK_CONDITION
     984                 && SenseData.ADDITIONAL_SENSE_CODE == 0x3A)
     985            rc = VERR_MEDIA_NOT_PRESENT; */
     986        else
     987        {
     988            rc = enmTxDir == PDMBLOCKTXDIR_NONE
     989               ? VERR_DEV_IO_ERROR
     990               : enmTxDir == PDMBLOCKTXDIR_FROM_DEVICE
     991               ? VERR_READ_ERROR
     992               : VERR_WRITE_ERROR;
     993            if (pThis->cLogRelErrors++ < 10)
     994                LogRel(("DVD scsi error: cmd={%.*Rhxs} TaskStatus=%#x key=%#x ASC=%#x ASCQ=%#x (%Vrc)\n",
     995                        cbCmd, pbCmd, TaskStatus, SenseData.SENSE_KEY, SenseData.ADDITIONAL_SENSE_CODE,
     996                        SenseData.ADDITIONAL_SENSE_CODE_QUALIFIER, rc));
     997        }
     998    } while (0);
     999
     1000    (*ppScsiTaskI)->Release(ppScsiTaskI);
     1001
     1002# endif
     1003
     1004    return rc;
     1005}
     1006#endif
    6121007
    6131008
     
    9071302     */
    9081303    if (    pThis->fLocked
     1304#ifdef __DARWIN__
     1305        &&  pThis->ppScsiTaskDI
     1306#else
    9091307        &&  pThis->FileDevice != NIL_RTFILE
     1308#endif
    9101309        &&  pThis->pfnDoLock)
    9111310    {
     
    9331332#endif
    9341333
     1334#ifdef __DARWIN__
     1335    if (pThis->ppScsiTaskDI)
     1336    {
     1337        (*pThis->ppScsiTaskDI)->ReleaseExclusiveAccess(pThis->ppScsiTaskDI);
     1338        (*pThis->ppScsiTaskDI)->Release(pThis->ppScsiTaskDI);
     1339        pThis->ppScsiTaskDI = NULL;
     1340    }
     1341    if (pThis->ppMMCDI)
     1342    {
     1343        (*pThis->ppMMCDI)->Release(pThis->ppMMCDI);
     1344        pThis->ppMMCDI = NULL;
     1345    }
     1346    if (pThis->MasterPort)
     1347    {
     1348        mach_port_deallocate(mach_task_self(), pThis->MasterPort);
     1349        pThis->MasterPort = NULL;
     1350    }
     1351#else
    9351352    if (pThis->FileDevice != NIL_RTFILE)
    9361353    {
     
    9391356        pThis->FileDevice = NIL_RTFILE;
    9401357    }
     1358#endif
    9411359
    9421360    if (pThis->pszDevice)
     
    9801398    pThis->pDrvIns                          = pDrvIns;
    9811399    pThis->ThreadPoller                     = NIL_RTTHREAD;
     1400#ifdef __DARWIN__
     1401    pThis->MasterPort                       = NULL;
     1402    pThis->ppMMCDI                          = NULL;
     1403    pThis->ppScsiTaskDI                     = NULL;
     1404    pThis->cbBlock                          = 0;
     1405#else
    9821406    pThis->FileDevice                       = NIL_RTFILE;
     1407#endif
    9831408    pThis->enmType                          = enmType;
     1409    //pThis->cErrors                          = 0;
    9841410
    9851411    pThis->pfnGetMediaSize                  = drvHostBaseGetMediaSize;
     
    11971623     * Open the device.
    11981624     */
     1625#ifdef __DARWIN__
     1626    rc = drvHostBaseOpen(pThis, NULL, pThis->fReadOnlyConfig);
     1627#else
    11991628    rc = drvHostBaseReopen(pThis);
     1629#endif
    12001630    if (VBOX_FAILURE(rc))
    12011631    {
    1202         char pszPathReal[256];
    12031632        char *pszDevice = pThis->pszDevice;
    1204         if (RT_SUCCESS(RTPathReal(pszDevice, pszPathReal, sizeof(pszPathReal))))
    1205             pszDevice = pszPathReal;
    1206         AssertMsgFailed(("Could not open host device %s, rc=%Vrc\n", pThis->pszDevice, rc));
     1633#ifndef __DARWIN__
     1634        char szPathReal[256];
     1635        if (RT_SUCCESS(RTPathReal(pszDevice, szPathReal, sizeof(szPathReal))))
     1636            pszDevice = szPathReal;
    12071637        pThis->FileDevice = NIL_RTFILE;
     1638#endif
     1639        AssertMsgFailed(("Could not open host device %s, rc=%Vrc\n", pszDevice, rc));
    12081640        switch (rc)
    12091641        {
     
    12191651                           "of that device"),
    12201652#endif
    1221                        pszPathReal, pThis->fReadOnlyConfig ? "readonly" : "read/write",
    1222                        pszPathReal);
     1653                       pszDevice, pThis->fReadOnlyConfig ? "readonly" : "read/write",
     1654                       pszDevice);
    12231655            default:
    12241656                return rc;
  • trunk/src/VBox/Devices/Storage/DrvHostBase.h

    r1 r1965  
    7474     * This is invalid if no drive is in the drive. */
    7575    uint64_t volatile       cbSize;
     76#ifndef __DARWIN__
    7677    /** The filehandle of the device. */
    7778    RTFILE                  FileDevice;
     79#endif
    7880
    7981    /** Handle of the poller thread. */
     
    98100    /** BIOS Geometry: Sectors. */
    99101    uint32_t                cSectors;
     102
     103    /** The number of errors that could go into the release log. (flood gate) */
     104    uint32_t                cLogRelErrors;
     105
     106#ifdef __DARWIN__
     107    /** The master port. */
     108    mach_port_t             MasterPort;
     109    /** The MMC-2 Device Interface. (This is only used to get the scsi task interface.) */
     110    MMCDeviceInterface    **ppMMCDI;
     111    /** The SCSI Task Device Interface. */
     112    SCSITaskDeviceInterface **ppScsiTaskDI;
     113    /** The block size. Set when querying the media size. */
     114    uint32_t                cbBlock;
     115#endif
    100116
    101117#ifdef __WIN__
     
    145161void DRVHostBaseMediaNotPresent(PDRVHOSTBASE pThis);
    146162DECLCALLBACK(void) DRVHostBaseDestruct(PPDMDRVINS pDrvIns);
     163#ifdef __DARWIN__
     164DECLCALLBACK(int) DRVHostBaseScsiCmd(PDRVHOSTBASE pThis, const uint8_t *pbCmd, size_t cbCmd, PDMBLOCKTXDIR enmTxDir,
     165                                     void *pvBuf, size_t *pcbBuf, uint8_t *pbSense, size_t cbSense, uint32_t cTimeoutMillies);
     166#endif
    147167
    148168
  • trunk/src/VBox/Devices/Storage/DrvHostDVD.cpp

    r1 r1965  
    2626*******************************************************************************/
    2727#define LOG_GROUP LOG_GROUP_DRV_HOST_DVD
    28 #ifdef __LINUX__
     28#ifdef __DARWIN__
     29# include <mach/mach.h>
     30# include <Carbon/Carbon.h>
     31# include <IOKit/IOKitLib.h>
     32# include <IOKit/IOCFPlugIn.h>
     33# include <IOKit/scsi-commands/SCSITaskLib.h>
     34# include <IOKit/scsi-commands/SCSICommandOperationCodes.h>
     35# include <IOKit/storage/IOStorageDeviceCharacteristics.h>
     36# include <mach/mach_error.h>
     37# define USE_MEDIA_POLLING
     38
     39#elif defined(__L4ENV__)
     40/* nothing (yet). */
     41
     42#elif defined __LINUX__
    2943# include <sys/ioctl.h>
    3044/* This is a hack to work around conflicts between these linux kernel headers
     
    3953# include <sys/fcntl.h>
    4054# include <errno.h>
     55# define USE_MEDIA_POLLING
    4156
    4257#elif defined(__WIN__)
     
    4459# include <winioctl.h>
    4560# include <ntddscsi.h>
    46 
    47 #elif defined(__L4ENV__)
    48 
    49 #else /* !__WIN__ nor __LINUX__ nor __L4ENV__ */
     61# undef USE_MEDIA_POLLING
     62
     63#else
    5064# error "Unsupported Platform."
    51 #endif /* !__WIN__ nor __LINUX__ nor __L4ENV__ */
     65#endif
    5266
    5367#include <VBox/pdm.h>
     
    8498          * Eject the disc.
    8599          */
    86 #ifdef __LINUX__
     100#ifdef __DARWIN__
     101         uint8_t abCmd[16] =
     102         {
     103             SCSI_START_STOP_UNIT, 0, 0, 0, 2 /*eject+stop*/, 0,
     104             0,0,0,0,0,0,0,0,0,0
     105         };
     106         rc = DRVHostBaseScsiCmd(pThis, abCmd, 6, PDMBLOCKTXDIR_NONE, NULL, NULL, NULL, 0, 0);
     107
     108#elif defined(__LINUX__)
    87109         rc = ioctl(pThis->FileDevice, CDROMEJECT, 0);
    88110         if (rc < 0)
     
    151173static DECLCALLBACK(int) drvHostDvdDoLock(PDRVHOSTBASE pThis, bool fLock)
    152174{
    153 #ifdef __LINUX__
     175#ifdef __DARWIN__
     176# if 0 /// @todo dig up the specification for this command and implement it. (not important on mac)
     177    uint8_t abCmd[16] =
     178    {
     179        SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL, 0, 0, 0, 0, 0,
     180        0,0,0,0,0,0,0,0,0,0
     181    };
     182    int rc = DRVHostBaseScsiCmd(pThis, abCmd, 6, PDMBLOCKTXDIR_NONE, NULL, NULL, NULL, 0, 0);
     183# else
     184    int rc = VINF_SUCCESS;
     185# endif
     186
     187#elif defined(__LINUX__)
    154188    int rc = ioctl(pThis->FileDevice, CDROM_LOCKDOOR, (int)fLock);
    155189    if (rc < 0)
     
    210244
    211245
    212 #ifdef __LINUX__
     246#ifdef USE_MEDIA_POLLING
    213247/**
    214248 * Do media change polling.
     
    219253     * Poll for media change.
    220254     */
    221 #ifdef __LINUX__
     255#ifdef __DARWIN__
     256    AssertReturn(pThis->ppScsiTaskDI, VERR_INTERNAL_ERROR);
     257
     258    /*
     259     * Issue a TEST UNIT READY request.
     260     */
     261    bool fMediaChanged = false;
     262    bool fMediaPresent = false;
     263    uint8_t abCmd[16] = { SCSI_TEST_UNIT_READY, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
     264    uint8_t abSense[32];
     265    int rc2 = DRVHostBaseScsiCmd(pThis, abCmd, 6, PDMBLOCKTXDIR_NONE, NULL, NULL, abSense, sizeof(abSense), 0);
     266    if (VBOX_SUCCESS(rc2))
     267        fMediaPresent = true;
     268    else if (   rc2 == VERR_UNRESOLVED_ERROR
     269             && abSense[2] == 6 /* unit attention */
     270             && (   (abSense[12] == 0x29 && abSense[13] < 5 /* reset */)
     271                 || (abSense[12] == 0x2a && abSense[13] == 0 /* parameters changed */)                        //???
     272                 || (abSense[12] == 0x3f && abSense[13] == 0 /* target operating conditions have changed */)  //???
     273                 || (abSense[12] == 0x3f && abSense[13] == 2 /* changed operating definition */)              //???
     274                 || (abSense[12] == 0x3f && abSense[13] == 3 /* inquery parameters changed */)
     275                 || (abSense[12] == 0x3f && abSense[13] == 5 /* device identifier changed */)
     276                 )
     277            )
     278    {
     279        fMediaPresent = false;
     280        fMediaChanged = true;
     281        /** @todo check this media chance stuff on Darwin. */
     282    }
     283
     284#elif defined(__LINUX__)
    222285    bool fMediaPresent = ioctl(pThis->FileDevice, CDROM_DRIVE_STATUS, CDSL_CURRENT) == CDS_DISC_OK;
    223286
     
    243306         * Poll for media change.
    244307         */
    245         bool fMediaChanged;
    246 #ifdef __LINUX__
    247         fMediaChanged = ioctl(pThis->FileDevice, CDROM_MEDIA_CHANGED, CDSL_CURRENT) == 1;
    248 
     308#ifdef __DARWIN__
     309        /* taken care of above. */
     310#elif defined(__LINUX__)
     311        bool fMediaChanged = ioctl(pThis->FileDevice, CDROM_MEDIA_CHANGED, CDSL_CURRENT) == 1;
    249312#else
    250313# error "Unsupported platform."
     
    252315        if (fMediaChanged)
    253316        {
    254             int rc;
    255317            LogFlow(("drvHostDVDMediaThread: Media changed!\n"));
    256318            DRVHostBaseMediaNotPresent(pThis);
     
    262324    return rc;
    263325}
    264 #endif /* __LINUX__ */
     326#endif /* USE_MEDIA_POLLING */
    265327
    266328
    267329/** @copydoc PDMIBLOCK::pfnSendCmd */
    268 static int drvHostDvdSendCmd(PPDMIBLOCK pInterface, const uint8_t *pbCmd, PDMBLOCKTXDIR enmTxDir, void *pvBuf, size_t *pcbBuf, uint8_t *pbStat, uint32_t cTimeoutMillies)
     330static int drvHostDvdSendCmd(PPDMIBLOCK pInterface, const uint8_t *pbCmd, PDMBLOCKTXDIR enmTxDir, void *pvBuf, size_t *pcbBuf,
     331                             uint8_t *pbStat, uint32_t cTimeoutMillies)
    269332{
    270333    PDRVHOSTBASE pThis = PDMIBLOCK_2_DRVHOSTBASE(pInterface);
    271     int direction;
    272334    int rc;
    273335    LogFlow(("%s: cmd[0]=%#04x txdir=%d pcbBuf=%d timeout=%d\n", __FUNCTION__, pbCmd[0], enmTxDir, *pcbBuf, cTimeoutMillies));
    274 #ifdef __LINUX__
     336
     337#ifdef __DARWIN__
     338    /*
     339     * Pass the request on to the internal scsi command interface.
     340     * The command seems to be 12 bytes long, the docs a bit copy&pasty on the command length point...
     341     */
     342    if (enmTxDir == PDMBLOCKTXDIR_FROM_DEVICE)
     343        memset(pvBuf, '\0', *pcbBuf); /* we got read size, but zero it anyway. */
     344    uint8_t abSense[32];
     345    rc = DRVHostBaseScsiCmd(pThis, pbCmd, 12, PDMBLOCKTXDIR_FROM_DEVICE, pvBuf, pcbBuf, abSense, sizeof(abSense), cTimeoutMillies);
     346    if (rc == VERR_UNRESOLVED_ERROR)
     347    {
     348        *pbStat = abSense[2] & 0x0f;
     349        rc = VINF_SUCCESS;
     350    }
     351
     352#elif defined(__L4ENV__)
     353    /* Not really ported to L4 yet. */
     354    rc = VERR_INTERNAL_ERROR;
     355
     356#elif defined(__LINUX__)
     357    int direction;
    275358    struct cdrom_generic_command cgc;
    276359    request_sense sense;
     
    331414     * of data transferred (for packet commands with little data transfer
    332415     * it's 0). So just assume that everything worked ok. */
     416
    333417#elif defined(__WIN__)
    334     struct _REQ {
     418    int direction;
     419    struct _REQ
     420    {
    335421        SCSI_PASS_THROUGH_DIRECT spt;
    336422        uint8_t aSense[18];
     
    386472        rc = RTErrConvertFromWin32(GetLastError());
    387473    Log2(("%s: scsistatus=%d bytes returned=%d tlength=%d\n", __FUNCTION__, Req.spt.ScsiStatus, cbReturned, Req.spt.DataTransferLength));
    388 #elif defined(__L4ENV__)
    389     /* L4 is silently unsupported. */
     474
    390475#else
    391476# error "Unsupported platform."
     
    444529        pThis->IMount.pfnUnmount = drvHostDvdUnmount;
    445530        pThis->pfnDoLock         = drvHostDvdDoLock;
     531#ifdef USE_MEDIA_POLLING
     532        if (!fPassthrough)
     533            pThis->pfnPoll       = drvHostDvdPoll;
     534        else
     535            pThis->pfnPoll       = NULL;
     536#endif
    446537#ifdef __LINUX__
    447         if (!fPassthrough)
    448             pThis->pfnPoll           = drvHostDvdPoll;
    449         else
    450             pThis->pfnPoll           = NULL;
    451538        pThis->pfnGetMediaSize   = drvHostDvdGetMediaSize;
    452539#endif
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