Exemplo n.º 1
0
/**
 * performs the "base" globals initialization
 * we separate the globals initialization to globals "base" initialization which is actually
 * "general" globals initialization except for Idc not being initialized, and idc initialization.
 * This is needed for windows filter driver, which gets loaded prior to VBoxDrv,
 * thus it's not possible to make idc initialization from the driver startup routine for it.
 *
 * @returns VBox status code.
 * @param   pGlobals    Pointer to the globals. */
DECLHIDDEN(int) vboxNetAdpInitGlobalsBase(PVBOXNETADPGLOBALS pGlobals)
{
    /*
     * Initialize the common portions of the structure.
     */
    int i;
    int rc = RTSemFastMutexCreate(&pGlobals->hFastMtx);
    if (RT_SUCCESS(rc))
    {
        memset(pGlobals->aAdapters, 0, sizeof(pGlobals->aAdapters));
        for (i = 0; i < (int)RT_ELEMENTS(pGlobals->aAdapters); i++)
        {
            rc = vboxNetAdpSlotCreate(pGlobals, i, &pGlobals->aAdapters[i]);
            if (RT_FAILURE(rc))
            {
                /* Clean up. */
                while (--i >= 0)
                    vboxNetAdpSlotDestroy(&pGlobals->aAdapters[i]);
                Log(("vboxNetAdpInitGlobalsBase: Failed to create fast mutex (rc=%Rrc).\n", rc));
                RTSemFastMutexDestroy(pGlobals->hFastMtx);
                return rc;
            }
        }
        pGlobals->TrunkFactory.pfnRelease = vboxNetAdpFactoryRelease;
        pGlobals->TrunkFactory.pfnCreateAndConnect = vboxNetAdpFactoryCreateAndConnect;

        strcpy(pGlobals->SupDrvFactory.szName, "VBoxNetAdp");
        pGlobals->SupDrvFactory.pfnQueryFactoryInterface = vboxNetAdpQueryFactoryInterface;
    }

    return rc;
}
Exemplo n.º 2
0
/**
 * Creates a new empty I/O logger.
 *
 * @returns VBox status code.
 * @param   ppIoLogger    Where to store the new I/O logger handle.
 */
static int vddbgIoLoggerCreate(PVDIOLOGGERINT *ppIoLogger)
{
    int rc = VINF_SUCCESS;
    PVDIOLOGGERINT pIoLogger = NULL;

    pIoLogger = (PVDIOLOGGERINT)RTMemAllocZ(sizeof(VDIOLOGGERINT));
    if (pIoLogger)
    {
        rc = RTSemFastMutexCreate(&pIoLogger->hMtx);
        if (RT_SUCCESS(rc))
        {
            rc = RTMemCacheCreate(&pIoLogger->hMemCacheIoLogEntries, sizeof(VDIOLOGENTINT),
                                  0, UINT32_MAX, NULL, NULL, NULL, 0);
            if (RT_SUCCESS(rc))
            {
                *ppIoLogger = pIoLogger;
                return rc;
            }
        }
        RTMemFree(pIoLogger);
    }
    else
        rc = VERR_NO_MEMORY;

    return rc;
}
Exemplo n.º 3
0
/**
 * @copydoc RAWPCIFACTORY::pfnInitVm
 */
static DECLCALLBACK(int)  vboxPciFactoryInitVm(PRAWPCIFACTORY       pFactory,
                                               PVM                  pVM,
                                               PRAWPCIPERVM         pVmData)
{
    PVBOXRAWPCIDRVVM pThis = (PVBOXRAWPCIDRVVM)RTMemAllocZ(sizeof(VBOXRAWPCIDRVVM));
    int rc;

    if (!pThis)
         return VERR_NO_MEMORY;

    rc = RTSemFastMutexCreate(&pThis->hFastMtx);
    if (RT_SUCCESS(rc))
    {
        rc = vboxPciOsInitVm(pThis, pVM, pVmData);

        if (RT_SUCCESS(rc))
        {
#ifdef VBOX_WITH_IOMMU
            /* If IOMMU notification routine in pVmData->pfnContigMemInfo
               is set - we have functional IOMMU hardware. */
            if (pVmData->pfnContigMemInfo)
                pVmData->fVmCaps |= PCIRAW_VMFLAGS_HAS_IOMMU;
#endif
            pThis->pPerVmData = pVmData;
            pVmData->pDriverData = pThis;
            return VINF_SUCCESS;
        }

        RTSemFastMutexDestroy(pThis->hFastMtx);
        pThis->hFastMtx = NIL_RTSEMFASTMUTEX;
        RTMemFree(pThis);
    }

    return rc;
}
Exemplo n.º 4
0
/**
 * Initializes the object (called right after construction).
 *
 * @returns S_OK on success and non-fatal failures, some COM error otherwise.
 */
int USBProxyBackendUsbIp::init(void)
{
    int rc = VINF_SUCCESS;

    m = new Data;

    /** @todo: Pass in some config like host and port to connect to. */

    /* Setup wakeup pipe and poll set first. */
    rc = RTSemFastMutexCreate(&m->hMtxDevices);
    if (RT_SUCCESS(rc))
    {
        rc = RTPipeCreate(&m->hWakeupPipeR, &m->hWakeupPipeW, 0);
        if (RT_SUCCESS(rc))
        {
            rc = RTPollSetCreate(&m->hPollSet);
            if (RT_SUCCESS(rc))
            {
                rc = RTPollSetAddPipe(m->hPollSet, m->hWakeupPipeR,
                                      RTPOLL_EVT_READ, USBIP_POLL_ID_PIPE);
                if (RT_SUCCESS(rc))
                {
                    /* Connect to the USB/IP host. */
                    rc = reconnect();
                    if (RT_SUCCESS(rc))
                        rc = start(); /* Start service thread. */
                }

                if (RT_FAILURE(rc))
                {
                    RTPollSetRemove(m->hPollSet, USBIP_POLL_ID_PIPE);
                    int rc2 = RTPollSetDestroy(m->hPollSet);
                    AssertRC(rc2);
                }
            }

            if (RT_FAILURE(rc))
            {
                int rc2 = RTPipeClose(m->hWakeupPipeR);
                AssertRC(rc2);
                rc2 = RTPipeClose(m->hWakeupPipeW);
                AssertRC(rc2);
            }
        }
        if (RT_FAILURE(rc))
            RTSemFastMutexDestroy(m->hMtxDevices);
    }

    return rc;
}
Exemplo n.º 5
0
/**
 * Initializes the VBoxUSB filter manager.
 *
 * @returns IPRT status code.
 */
int VBoxUSBFilterInit(void)
{
#ifdef VBOXUSBFILTERMGR_USB_SPINLOCK
    int rc = RTSpinlockCreate(&g_Spinlock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "VBoxUSBFilter");
#else
    int rc = RTSemFastMutexCreate(&g_Mtx);
#endif
    if (RT_SUCCESS(rc))
    {
        /* not really required, but anyway... */
        for (unsigned i = USBFILTERTYPE_FIRST; i < RT_ELEMENTS(g_aLists); i++)
            g_aLists[i].pHead = g_aLists[i].pTail = NULL;
    }
    return rc;
}
Exemplo n.º 6
0
/**
 * Initializes the globals.
 *
 * @returns VBox status code.
 * @param   pGlobals        Pointer to the globals.
 */
DECLHIDDEN(int) vboxPciInitGlobals(PVBOXRAWPCIGLOBALS pGlobals)
{
    /*
     * Initialize the common portions of the structure.
     */
    int rc = RTSemFastMutexCreate(&pGlobals->hFastMtx);
    if (RT_SUCCESS(rc))
    {
        pGlobals->pInstanceHead = NULL;
        pGlobals->RawPciFactory.pfnRelease = vboxPciFactoryRelease;
        pGlobals->RawPciFactory.pfnCreateAndConnect = vboxPciFactoryCreateAndConnect;
        pGlobals->RawPciFactory.pfnInitVm = vboxPciFactoryInitVm;
        pGlobals->RawPciFactory.pfnDeinitVm = vboxPciFactoryDeinitVm;
        memcpy(pGlobals->SupDrvFactory.szName, "VBoxRawPci", sizeof("VBoxRawPci"));
        pGlobals->SupDrvFactory.pfnQueryFactoryInterface = vboxPciQueryFactoryInterface;
        pGlobals->fIDCOpen = false;
    }
    return rc;
}
Exemplo n.º 7
0
/**
 * Initializes the HGCM VBGL bits.
 *
 * @return VBox status code.
 */
int vbglR0HGCMInit (void)
{
    return RTSemFastMutexCreate(&g_vbgldata.mutexHGCMHandle);
}
Exemplo n.º 8
0
static SPUFunctions *
renderSPUInit( int id, SPU *child, SPU *self,
               unsigned int context_id, unsigned int num_contexts )
{
    int numFuncs, numSpecial;
    GLint defaultWin, defaultCtx;
    WindowInfo *windowInfo;
    const char * pcpwSetting;
    int rc;

    (void) child;
    (void) context_id;
    (void) num_contexts;

    self->privatePtr = (void *) &render_spu;

#ifdef CHROMIUM_THREADSAFE
    crDebug("Render SPU: thread-safe");
#endif

    crMemZero(&render_spu, sizeof(render_spu));

    render_spu.id = id;
    renderspuSetVBoxConfiguration(&render_spu);

    if (render_spu.swap_master_url)
        swapsyncConnect();


    /* Get our special functions. */
    numSpecial = renderspuCreateFunctions( _cr_render_table );

#ifdef RT_OS_WINDOWS
    /* Start thread to create windows and process window messages */
    crDebug("RenderSPU: Starting windows serving thread");
    render_spu.hWinThreadReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    if (!render_spu.hWinThreadReadyEvent)
    {
        crError("RenderSPU: Failed to create WinThreadReadyEvent! (%x)", GetLastError());
        return NULL;
    }

    if (!CreateThread(NULL, 0, renderSPUWindowThreadProc, 0, 0, &render_spu.dwWinThreadId))
    {
        crError("RenderSPU: Failed to start windows thread! (%x)", GetLastError());
        return NULL;
    }
    WaitForSingleObject(render_spu.hWinThreadReadyEvent, INFINITE);
#endif

    /* Get the OpenGL functions. */
    numFuncs = crLoadOpenGL( &render_spu.ws, _cr_render_table + numSpecial );
    if (numFuncs == 0) {
        crError("The render SPU was unable to load the native OpenGL library");
        return NULL;
    }

    numFuncs += numSpecial;

    render_spu.contextTable = crAllocHashtableEx(1, INT32_MAX);
    render_spu.windowTable = crAllocHashtableEx(1, INT32_MAX);

    render_spu.dummyWindowTable = crAllocHashtable();

    pcpwSetting = crGetenv("CR_RENDER_ENABLE_SINGLE_PRESENT_CONTEXT");
    if (pcpwSetting)
    {
        if (pcpwSetting[0] == '0')
            pcpwSetting = NULL;
    }

    if (pcpwSetting)
    {
        /* TODO: need proper blitter synchronization, do not use so far!
         * the problem is that rendering can be done in multiple thread: the main command (hgcm) thread and the redraw thread
         * we currently use per-window synchronization, while we'll need a per-blitter synchronization if one blitter is used for multiple windows
         * this is not done currently */
        crWarning("TODO: need proper blitter synchronization, do not use so far!");
        render_spu.blitterTable = crAllocHashtable();
        CRASSERT(render_spu.blitterTable);
    }
    else
        render_spu.blitterTable = NULL;

    CRASSERT(render_spu.default_visual & CR_RGB_BIT);
    
    rc = renderspu_SystemInit();
    if (!RT_SUCCESS(rc))
    {
        crError("renderspu_SystemInit failed rc %d", rc);
        return NULL;
    }
#ifdef USE_OSMESA
    if (render_spu.use_osmesa) {
        if (!crLoadOSMesa(&render_spu.OSMesaCreateContext,
                          &render_spu.OSMesaMakeCurrent,
                          &render_spu.OSMesaDestroyContext)) {
            crError("Unable to load OSMesa library");
        }
    }
#endif

#ifdef DARWIN
# ifdef VBOX_WITH_COCOA_QT
# else /* VBOX_WITH_COCOA_QT */
    render_spu.hRootVisibleRegion = 0;
    render_spu.currentBufferName = 1;
    render_spu.uiDockUpdateTS = 0;
    /* Create a mutex for synchronizing events from the main Qt thread & this
       thread */
    RTSemFastMutexCreate(&render_spu.syncMutex);
    /* Create our window groups */
    CreateWindowGroup(kWindowGroupAttrMoveTogether | kWindowGroupAttrLayerTogether | kWindowGroupAttrSharedActivation | kWindowGroupAttrHideOnCollapse | kWindowGroupAttrFixedLevel, &render_spu.pMasterGroup);
    CreateWindowGroup(kWindowGroupAttrMoveTogether | kWindowGroupAttrLayerTogether | kWindowGroupAttrSharedActivation | kWindowGroupAttrHideOnCollapse | kWindowGroupAttrFixedLevel, &render_spu.pParentGroup);
    /* Make the correct z-layering */
    SendWindowGroupBehind (render_spu.pParentGroup, render_spu.pMasterGroup);
    /* and set the gParentGroup as parent for gMasterGroup. */
    SetWindowGroupParent (render_spu.pMasterGroup, render_spu.pParentGroup);
    /* Install the event handlers */
    EventTypeSpec eventList[] =
    {
        {kEventClassVBox, kEventVBoxUpdateContext}, /* Update the context after show/size/move events */
        {kEventClassVBox, kEventVBoxBoundsChanged}  /* Clip/Pos the OpenGL windows when the main window is changed in pos/size */
    };
    /* We need to process events from our main window */
    render_spu.hParentEventHandler = NewEventHandlerUPP(windowEvtHndlr);
    InstallApplicationEventHandler (render_spu.hParentEventHandler,
                                    GetEventTypeCount(eventList), eventList,
                                    NULL, NULL);
    render_spu.fInit = true;
# endif /* VBOX_WITH_COCOA_QT */
#endif /* DARWIN */

    /*
     * Create the default window and context.  Their indexes are zero and
     * a client can use them without calling CreateContext or WindowCreate.
     */
    crDebug("Render SPU: Creating default window (visBits=0x%x, id=0)",
            render_spu.default_visual);
    defaultWin = renderspuWindowCreateEx( NULL, render_spu.default_visual, CR_RENDER_DEFAULT_WINDOW_ID );
    if (defaultWin != CR_RENDER_DEFAULT_WINDOW_ID) {
        crError("Render SPU: Couldn't get a double-buffered, RGB visual with Z!");
        return NULL;
    }
    crDebug( "Render SPU: WindowCreate returned %d (0=normal)", defaultWin );

    crDebug("Render SPU: Creating default context, visBits=0x%x",
            render_spu.default_visual );
    defaultCtx = renderspuCreateContextEx( NULL, render_spu.default_visual, CR_RENDER_DEFAULT_CONTEXT_ID, 0 );
    if (defaultCtx != CR_RENDER_DEFAULT_CONTEXT_ID) {
        crError("Render SPU: failed to create default context!");
        return NULL;
    }

    renderspuMakeCurrent( defaultWin, 0, defaultCtx );

    /* Get windowInfo for the default window */
    windowInfo = (WindowInfo *) crHashtableSearch(render_spu.windowTable, CR_RENDER_DEFAULT_WINDOW_ID);
    CRASSERT(windowInfo);
    windowInfo->mapPending = GL_TRUE;

    /*
     * Get the OpenGL extension functions.
     * SIGH -- we have to wait until the very bitter end to load the
     * extensions, because the context has to be bound before
     * wglGetProcAddress will work correctly.  No such issue with GLX though.
     */
    numFuncs += crLoadOpenGLExtensions( &render_spu.ws, _cr_render_table + numFuncs );
    CRASSERT(numFuncs < 1000);

#ifdef WINDOWS
    /*
     * Same problem as above, these are extensions so we need to
     * load them after a context has been bound. As they're WGL
     * extensions too, we can't simply tag them into the spu_loader.
     * So we do them here for now.
     * Grrr, NVIDIA driver uses EXT for GetExtensionsStringEXT,
     * but ARB for others. Need further testing here....
     */
    render_spu.ws.wglGetExtensionsStringEXT =
        (wglGetExtensionsStringEXTFunc_t)
        render_spu.ws.wglGetProcAddress( "wglGetExtensionsStringEXT" );
    render_spu.ws.wglChoosePixelFormatEXT =
        (wglChoosePixelFormatEXTFunc_t)
        render_spu.ws.wglGetProcAddress( "wglChoosePixelFormatARB" );
    render_spu.ws.wglGetPixelFormatAttribivEXT =
        (wglGetPixelFormatAttribivEXTFunc_t)
        render_spu.ws.wglGetProcAddress( "wglGetPixelFormatAttribivARB" );
    render_spu.ws.wglGetPixelFormatAttribfvEXT =
        (wglGetPixelFormatAttribfvEXTFunc_t)
        render_spu.ws.wglGetProcAddress( "wglGetPixelFormatAttribfvARB" );

    if (render_spu.ws.wglGetProcAddress("glCopyTexSubImage3D"))
    {
        _cr_render_table[numFuncs].name = crStrdup("CopyTexSubImage3D");
        _cr_render_table[numFuncs].fn = (SPUGenericFunction) render_spu.ws.wglGetProcAddress("glCopyTexSubImage3D");
        ++numFuncs;
        crDebug("Render SPU: Found glCopyTexSubImage3D function");
    }

    if (render_spu.ws.wglGetProcAddress("glDrawRangeElements"))
    {
        _cr_render_table[numFuncs].name = crStrdup("DrawRangeElements");
        _cr_render_table[numFuncs].fn = (SPUGenericFunction) render_spu.ws.wglGetProcAddress("glDrawRangeElements");
        ++numFuncs;
        crDebug("Render SPU: Found glDrawRangeElements function");
    }

    if (render_spu.ws.wglGetProcAddress("glTexSubImage3D"))
    {
        _cr_render_table[numFuncs].name = crStrdup("TexSubImage3D");
        _cr_render_table[numFuncs].fn = (SPUGenericFunction) render_spu.ws.wglGetProcAddress("glTexSubImage3D");
        ++numFuncs;
        crDebug("Render SPU: Found glTexSubImage3D function");
    }

    if (render_spu.ws.wglGetProcAddress("glTexImage3D"))
    {
        _cr_render_table[numFuncs].name = crStrdup("TexImage3D");
        _cr_render_table[numFuncs].fn = (SPUGenericFunction) render_spu.ws.wglGetProcAddress("glTexImage3D");
        ++numFuncs;
        crDebug("Render SPU: Found glTexImage3D function");
    }

    if (render_spu.ws.wglGetExtensionsStringEXT) {
        crDebug("WGL - found wglGetExtensionsStringEXT\n");
    }
    if (render_spu.ws.wglChoosePixelFormatEXT) {
        crDebug("WGL - found wglChoosePixelFormatEXT\n");
    }
#endif

    render_spu.barrierHash = crAllocHashtable();

    render_spu.cursorX = 0;
    render_spu.cursorY = 0;
    render_spu.use_L2 = 0;

    render_spu.gather_conns = NULL;

    numFuncs = renderspu_SystemPostprocessFunctions(_cr_render_table, numFuncs, RT_ELEMENTS(_cr_render_table));

    crDebug("Render SPU: ---------- End of Init -------------");

    return &render_functions;
}
Exemplo n.º 9
0
/**
 * Creates a new instance.
 *
 * @returns VBox status code.
 * @param   pGlobals            The globals.
 * @param   pszName             The instance name.
 * @param   ppDevPort           Where to store the pointer to our port interface.
 */
static int vboxPciNewInstance(PVBOXRAWPCIGLOBALS pGlobals,
                              uint32_t           u32HostAddress,
                              uint32_t           fFlags,
                              PRAWPCIPERVM       pVmCtx,
                              PRAWPCIDEVPORT     *ppDevPort,
                              uint32_t           *pfDevFlags)
{
    int             rc;
    PVBOXRAWPCIINS  pNew = (PVBOXRAWPCIINS)RTMemAllocZ(sizeof(*pNew));
    if (!pNew)
        return VERR_NO_MEMORY;

    pNew->pGlobals                      = pGlobals;
    pNew->hSpinlock                     = NIL_RTSPINLOCK;
    pNew->cRefs                         = 1;
    pNew->pNext                         = NULL;
    pNew->HostPciAddress                = u32HostAddress;
    pNew->pVmCtx                        = pVmCtx;

    pNew->DevPort.u32Version            = RAWPCIDEVPORT_VERSION;

    pNew->DevPort.pfnInit               = vboxPciDevInit;
    pNew->DevPort.pfnDeinit             = vboxPciDevDeinit;
    pNew->DevPort.pfnDestroy            = vboxPciDevDestroy;
    pNew->DevPort.pfnGetRegionInfo      = vboxPciDevGetRegionInfo;
    pNew->DevPort.pfnMapRegion          = vboxPciDevMapRegion;
    pNew->DevPort.pfnUnmapRegion        = vboxPciDevUnmapRegion;
    pNew->DevPort.pfnPciCfgRead         = vboxPciDevPciCfgRead;
    pNew->DevPort.pfnPciCfgWrite        = vboxPciDevPciCfgWrite;
    pNew->DevPort.pfnPciCfgRead         = vboxPciDevPciCfgRead;
    pNew->DevPort.pfnPciCfgWrite        = vboxPciDevPciCfgWrite;
    pNew->DevPort.pfnRegisterIrqHandler = vboxPciDevRegisterIrqHandler;
    pNew->DevPort.pfnUnregisterIrqHandler = vboxPciDevUnregisterIrqHandler;
    pNew->DevPort.pfnPowerStateChange   = vboxPciDevPowerStateChange;
    pNew->DevPort.u32VersionEnd         = RAWPCIDEVPORT_VERSION;

    rc = RTSpinlockCreate(&pNew->hSpinlock);

    if (RT_SUCCESS(rc))
    {
        rc = RTSemFastMutexCreate(&pNew->hFastMtx);
        if (RT_SUCCESS(rc))
        {
            rc = pNew->DevPort.pfnInit(&pNew->DevPort, fFlags);
            if (RT_SUCCESS(rc))
            {
                *ppDevPort = &pNew->DevPort;

                pNew->pNext = pGlobals->pInstanceHead;
                pGlobals->pInstanceHead = pNew;
            }
            else
            {
                RTSemFastMutexDestroy(pNew->hFastMtx);
                RTSpinlockDestroy(pNew->hSpinlock);
                RTMemFree(pNew);
            }
        }
    }

    return rc;
}
Exemplo n.º 10
0
DECLHIDDEN(int) VUSBSnifferCreate(PVUSBSNIFFER phSniffer, uint32_t fFlags,
                                  const char *pszCaptureFilename, const char *pszDesc)
{
    int rc = VINF_SUCCESS;
    PVUSBSNIFFERINT pThis = NULL;

    pThis = (PVUSBSNIFFERINT)RTMemAllocZ(sizeof(VUSBSNIFFERINT));
    if (pThis)
    {
        pThis->hFile       = NIL_RTFILE;
        pThis->cbBlockCur  = 0;
        pThis->cbBlockMax  = 0;
        pThis->pbBlockData = NULL;
        pThis->hMtx        = NIL_RTSEMFASTMUTEX;

        rc = RTSemFastMutexCreate(&pThis->hMtx);
        if (RT_SUCCESS(rc))
        {
            rc = RTFileOpen(&pThis->hFile, pszCaptureFilename, RTFILE_O_DENY_NONE | RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_READ);
            if (RT_SUCCESS(rc))
            {
                /* Write header and link type blocks. */
                DumpFileShb Shb;

                Shb.Hdr.u32BlockType        = DUMPFILE_SHB_BLOCK_TYPE;
                Shb.Hdr.u32BlockTotalLength = 0; /* Filled out by lower layer. */
                Shb.u32ByteOrderMagic       = DUMPFILE_SHB_BYTE_ORDER_MAGIC;
                Shb.u16VersionMajor         = DUMPFILE_SHB_VERSION_MAJOR;
                Shb.u16VersionMinor         = DUMPFILE_SHB_VERSION_MINOR;
                Shb.u64SectionLength        = UINT64_C(0xffffffffffffffff); /* -1 */

                /* Write the blocks. */
                rc = vusbSnifferBlockNew(pThis, &Shb.Hdr, sizeof(Shb));
                if (RT_SUCCESS(rc))
                {
                    const char *pszOpt = RTBldCfgTargetDotArch();
                    rc = vusbSnifferAddOption(pThis, DUMPFILE_OPTION_CODE_HARDWARE, pszOpt, strlen(pszOpt) + 1);
                }

                if (RT_SUCCESS(rc))
                {
                    char szTmp[512];
                    size_t cbTmp = sizeof(szTmp);

                    RT_ZERO(szTmp);

                    /* Build the OS code. */
                    rc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szTmp, cbTmp);
                    if (RT_SUCCESS(rc))
                    {
                        size_t cb = strlen(szTmp);

                        szTmp[cb] = ' ';
                        rc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, &szTmp[cb + 1], cbTmp - (cb + 1));
                        if (RT_SUCCESS(rc))
                        {
                            cb = strlen(szTmp);
                            szTmp[cb] = ' ';
                            rc = RTSystemQueryOSInfo(RTSYSOSINFO_VERSION, &szTmp[cb + 1], cbTmp - (cb + 1));
                        }
                    }

                    if (RT_SUCCESS(rc) || rc == VERR_BUFFER_OVERFLOW)
                        rc = vusbSnifferAddOption(pThis, DUMPFILE_OPTION_CODE_OS, szTmp, strlen(szTmp) + 1);
                    else
                        rc = VINF_SUCCESS; /* Skip OS code if building the string failed. */
                }

                if (RT_SUCCESS(rc))
                {
                    /** @todo: Add product info. */
                }

                if (RT_SUCCESS(rc))
                    rc = vusbSnifferAddOption(pThis, DUMPFILE_OPTION_CODE_END, NULL, 0);
                if (RT_SUCCESS(rc))
                    rc = vusbSnifferBlockCommit(pThis);

                /* Write Interface descriptor block. */
                if (RT_SUCCESS(rc))
                {
                    DumpFileIdb Idb;

                    Idb.Hdr.u32BlockType        = DUMPFILE_IDB_BLOCK_TYPE;
                    Idb.Hdr.u32BlockTotalLength = 0; /* Filled out by lower layer. */
                    Idb.u16LinkType             = DUMPFILE_IDB_LINK_TYPE_USB_LINUX_MMAPED;
                    Idb.u16Reserved             = 0;
                    Idb.u32SnapLen              = UINT32_C(0xffffffff);

                    rc = vusbSnifferBlockNew(pThis, &Idb.Hdr, sizeof(Idb));
                    if (RT_SUCCESS(rc))
                    {
                        uint8_t u8TsResolution = 9; /* Nano second resolution. */
                        /* Add timestamp resolution option. */
                        rc = vusbSnifferAddOption(pThis, DUMPFILE_IDB_OPTION_TS_RESOLUTION,
                                                  &u8TsResolution, sizeof(u8TsResolution));
                    }
                    if (RT_SUCCESS(rc))
                        rc = vusbSnifferAddOption(pThis, DUMPFILE_OPTION_CODE_END, NULL, 0);
                    if (RT_SUCCESS(rc))
                        rc = vusbSnifferBlockCommit(pThis);
                }

                if (RT_SUCCESS(rc))
                {
                    *phSniffer = pThis;
                    return VINF_SUCCESS;
                }

                RTFileClose(pThis->hFile);
                pThis->hFile = NIL_RTFILE;
                RTFileDelete(pszCaptureFilename);
            }
            RTSemFastMutexDestroy(pThis->hMtx);
            pThis->hMtx = NIL_RTSEMFASTMUTEX;
        }
        RTMemFree(pThis);
    }
    else
        rc = VERR_NO_MEMORY;

    return rc;
}