Example #1
0
NTSTATUS vboxWddmRegQueryDisplaySettingsKeyName(PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId,
        ULONG cbBuf, PWCHAR pBuf, PULONG pcbResult)
{
    NTSTATUS Status = STATUS_SUCCESS;
    PWCHAR pSuffix;
    bool bFallback = false;
    const WCHAR* pKeyPrefix;
    UINT cbKeyPrefix;
    UNICODE_STRING* pVGuid = vboxWddmVGuidGet(pDevExt);
    Assert(pVGuid);
    if (!pVGuid)
        return STATUS_UNSUCCESSFUL;

    vboxWinVersion_t ver = VBoxQueryWinVersion();
    if (ver == WINVISTA)
    {
        pKeyPrefix = VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_VISTA;
        cbKeyPrefix = sizeof (VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_VISTA);
    }
    else
    {
        Assert(ver == WIN7);
        pKeyPrefix = VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_WIN7;
        cbKeyPrefix = sizeof (VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_WIN7);
    }

    ULONG cbResult = cbKeyPrefix + pVGuid->Length + 2 + 8; // L"\\" + "XXXX"
    if (cbBuf >= cbResult)
    {
        wcscpy(pBuf, pKeyPrefix);
        pSuffix = pBuf + (cbKeyPrefix-2)/2;
        memcpy(pSuffix, pVGuid->Buffer, pVGuid->Length);
        pSuffix += pVGuid->Length/2;
        pSuffix[0] = L'\\';
        pSuffix += 1;
        swprintf(pSuffix, L"%04d", VidPnSourceId);
    }
    else
    {
        Status = STATUS_BUFFER_TOO_SMALL;
    }

    *pcbResult = cbResult;

    return Status;
}
/* Video Miniport Driver entry point */
ULONG DriverEntry(IN PVOID Context1, IN PVOID Context2)
{
    PAGED_CODE();

    int irc = RTR0Init(0);
    if (RT_FAILURE(irc))
    {
        LogRel(("VBoxMP::failed to init IPRT (rc=%#x)", irc));
        return ERROR_INVALID_FUNCTION;
    }

    LOGF_ENTER();

    LOGREL(("VBox XPDM Driver for Windows version %d.%d.%dr%d, %d bit; Built %s %s",
            VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV,
            (sizeof (void*) << 3), __DATE__, __TIME__));

    VIDEO_HW_INITIALIZATION_DATA vhwData;

    /*Zero the structure*/
    VideoPortZeroMemory(&vhwData, sizeof(vhwData));

    /*Required driver callbacks*/
    vhwData.HwFindAdapter    = VBoxDrvFindAdapter;
    vhwData.HwInitialize     = VBoxDrvInitialize;
    vhwData.HwStartIO        = VBoxDrvStartIO;
    vhwData.HwSetPowerState  = VBoxDrvSetPowerState;
    vhwData.HwGetPowerState  = VBoxDrvGetPowerState;
    vhwData.HwGetVideoChildDescriptor = VBoxDrvGetVideoChildDescriptor;

    /*Optional callbacks*/
    vhwData.HwResetHw     = VBoxDrvResetHW;
#ifdef VBOX_WITH_VIDEOHWACCEL
    vhwData.HwInterrupt   = VBoxDrvInterrupt;
#endif

    /*Our private storage space*/
    vhwData.HwDeviceExtensionSize = sizeof(VBOXMP_DEVEXT);

    /*Claim legacy VGA resource ranges*/
    vhwData.HwLegacyResourceList  = g_aVBoxLegacyVGAResources;
    vhwData.HwLegacyResourceCount = RT_ELEMENTS(g_aVBoxLegacyVGAResources);

    /*Size of this structure changes between windows/ddk versions,
     *so we query current version and report the expected size
     *to allow our driver to be loaded.
     */
    switch (VBoxQueryWinVersion(NULL))
    {
        case WINVERSION_NT4:
            LOG(("WINVERSION_NT4"));
            vhwData.HwInitDataSize = SIZE_OF_NT4_VIDEO_HW_INITIALIZATION_DATA;
            break;
        case WINVERSION_2K:
            LOG(("WINVERSION_2K"));
            vhwData.HwInitDataSize = SIZE_OF_W2K_VIDEO_HW_INITIALIZATION_DATA;
            break;
        default:
            vhwData.HwInitDataSize = sizeof(VIDEO_HW_INITIALIZATION_DATA);
            break;
    }

    /*Even though msdn claims that this field is ignored and should remain zero-initialized,
      windows NT4 SP0 dies without the following line.
     */
    vhwData.AdapterInterfaceType = PCIBus;

    /*Allocate system resources*/
    ULONG rc = VideoPortInitialize(Context1, Context2, &vhwData, NULL);
    if (rc != NO_ERROR)
        LOG(("VideoPortInitialize failed with %#x", rc));

    LOGF_LEAVE();
    return rc;
}
/* Checks if we have a device supported by our driver and initialize
 * our driver/card specific information.
 * In particular we obtain VM monitors configuration and configure related structures.
 */
static VP_STATUS
VBoxDrvFindAdapter(IN PVOID HwDeviceExtension, IN PVOID HwContext, IN PWSTR ArgumentString,
                   IN OUT PVIDEO_PORT_CONFIG_INFO ConfigInfo, OUT PUCHAR Again)
{
    RT_NOREF(HwContext,  ArgumentString, Again);
    PVBOXMP_DEVEXT pExt = (PVBOXMP_DEVEXT) HwDeviceExtension;
    VP_STATUS rc;
    USHORT DispiId;
    ULONG cbVRAM = VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES;
    PHYSICAL_ADDRESS phVRAM = {0};
    ULONG ulApertureSize = 0;

    PAGED_CODE();
    LOGF_ENTER();

    /* Init video port api */
    VBoxSetupVideoPortAPI(pExt, ConfigInfo);

    VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
    VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID2);
    DispiId = VideoPortReadPortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA);

    if (DispiId != VBE_DISPI_ID2)
    {
        WARN(("VBE card not found, returning ERROR_DEV_NOT_EXIST"));
        return ERROR_DEV_NOT_EXIST;
    }
    LOG(("found the VBE card"));

    /*
     * Query the adapter's memory size. It's a bit of a hack, we just read
     * an ULONG from the data port without setting an index before.
     */
    cbVRAM = VideoPortReadPortUlong((PULONG)VBE_DISPI_IOPORT_DATA);

    /* Write hw information to registry, so that it's visible in windows property dialog */
    rc = VideoPortSetRegistryParameters(pExt, L"HardwareInformation.ChipType",
                                        g_wszVBoxChipType, sizeof(g_wszVBoxChipType));
    VBOXMP_WARN_VPS(rc);
    rc = VideoPortSetRegistryParameters(pExt, L"HardwareInformation.DacType",
                                        g_wszVBoxDACType, sizeof(g_wszVBoxDACType));
    VBOXMP_WARN_VPS(rc);
    rc = VideoPortSetRegistryParameters(pExt, L"HardwareInformation.MemorySize",
                                        &cbVRAM, sizeof(ULONG));
    VBOXMP_WARN_VPS(rc);
    rc = VideoPortSetRegistryParameters(pExt, L"HardwareInformation.AdapterString",
                                        g_wszVBoxAdapterString, sizeof(g_wszVBoxAdapterString));
    VBOXMP_WARN_VPS(rc);
    rc = VideoPortSetRegistryParameters(pExt, L"HardwareInformation.BiosString",
                                        g_wszVBoxBiosString, sizeof(g_wszVBoxBiosString));
    VBOXMP_WARN_VPS(rc);

    /* Call VideoPortGetAccessRanges to ensure interrupt info in ConfigInfo gets set up
     * and to get LFB aperture data.
     */
    {
        VIDEO_ACCESS_RANGE tmpRanges[4];
        ULONG slot = 0;

        VideoPortZeroMemory(tmpRanges, sizeof(tmpRanges));

        if (VBoxQueryWinVersion(NULL) == WINVERSION_NT4)
        {
            /* NT crashes if either of 'vendorId, 'deviceId' or 'slot' parameters is NULL,
             * and needs PCI ids for a successful VideoPortGetAccessRanges call.
             */
            ULONG vendorId = 0x80EE;
            ULONG deviceId = 0xBEEF;
            rc = VideoPortGetAccessRanges(pExt, 0, NULL, RT_ELEMENTS(tmpRanges), tmpRanges,
                                          &vendorId, &deviceId, &slot);
        }
        else
        {
            rc = VideoPortGetAccessRanges(pExt, 0, NULL, RT_ELEMENTS(tmpRanges), tmpRanges, NULL, NULL, &slot);
        }
        VBOXMP_WARN_VPS(rc);
        if (rc != NO_ERROR) {
            return rc;
        }

        /* The first non-IO range is the framebuffer. We require that information. */
        for (int iRange = 0; iRange < RT_ELEMENTS(tmpRanges); ++iRange)
        {
            if (!tmpRanges[iRange].RangeInIoSpace)
            {
                phVRAM = tmpRanges[iRange].RangeStart;
                ulApertureSize = tmpRanges[iRange].RangeLength;
                break;
            }
        }
    }

    /* Initialize VBoxGuest library, which is used for requests which go through VMMDev. */
    rc = VbglR0InitClient();
    VBOXMP_WARN_VPS(rc);

    /* Preinitialize the primary extension. */
    pExt->pNext                   = NULL;
    pExt->pPrimary                = pExt;
    pExt->iDevice                 = 0;
    pExt->ulFrameBufferOffset     = 0;
    pExt->ulFrameBufferSize       = 0;
    pExt->u.primary.ulVbvaEnabled = 0;
    VideoPortZeroMemory(&pExt->areaDisplay, sizeof(HGSMIAREA));

    /* Guest supports only HGSMI, the old VBVA via VMMDev is not supported. Old
     * code will be ifdef'ed and later removed.
     * The host will however support both old and new interface to keep compatibility
     * with old guest additions.
     */
    VBoxSetupDisplaysHGSMI(&pExt->u.primary.commonInfo, phVRAM, ulApertureSize, cbVRAM, 0);

    /* Check if the chip restricts horizontal resolution or not.
     * Must be done after VBoxSetupDisplaysHGSMI, because it initializes the common structure.
     */
    VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
    VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID_ANYX);
    DispiId = VideoPortReadPortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA);

    if (DispiId == VBE_DISPI_ID_ANYX)
        VBoxCommonFromDeviceExt(pExt)->fAnyX = TRUE;
    else
        VBoxCommonFromDeviceExt(pExt)->fAnyX = FALSE;

    if (pExt->u.primary.commonInfo.bHGSMI)
    {
        LOGREL(("using HGSMI"));
        VBoxCreateDisplays(pExt, ConfigInfo);
    }

    /** @todo pretend success to make the driver work. */
    rc = NO_ERROR;

    LOGF_LEAVE();
    VBOXMP_WARN_VPS(rc);
    return rc;
}
Example #4
0
/*Query video port for api functions or fill with stubs if those are not supported*/
void VBoxSetupVideoPortAPI(PVBOXMP_DEVEXT pExt, PVIDEO_PORT_CONFIG_INFO pConfigInfo)
{
    VBOXVIDEOPORTPROCS *pAPI = &pExt->u.primary.VideoPortProcs;
    VideoPortZeroMemory(pAPI, sizeof(VBOXVIDEOPORTPROCS));

    if (VBoxQueryWinVersion() <= WINVERSION_NT4)
    {
        /* VideoPortGetProcAddress is available for >= win2k */
        pAPI->pfnWaitForSingleObject = vboxWaitForSingleObjectVoid;
        pAPI->pfnSetEvent = vboxSetEventVoid;
        pAPI->pfnClearEvent = vboxClearEventVoid;
        pAPI->pfnCreateEvent = vboxCreateEventVoid;
        pAPI->pfnDeleteEvent = vboxDeleteEventVoid;
        pAPI->pfnAllocatePool = vboxAllocatePoolVoid;
        pAPI->pfnFreePool = vboxFreePoolVoid;
        pAPI->pfnQueueDpc = vboxQueueDpcVoid;
        pAPI->pfnCreateSecondaryDisplay = vboxCreateSecondaryDisplayVoid;
        return;
    }

    VP_GETPROC(pfnWaitForSingleObject, PFNWAITFORSINGLEOBJECT, "VideoPortWaitForSingleObject");
    VP_GETPROC(pfnSetEvent, PFNSETEVENT, "VideoPortSetEvent");
    VP_GETPROC(pfnClearEvent, PFNCLEAREVENT, "VideoPortClearEvent");
    VP_GETPROC(pfnCreateEvent, PFNCREATEEVENT, "VideoPortCreateEvent");
    VP_GETPROC(pfnDeleteEvent, PFNDELETEEVENT, "VideoPortDeleteEvent");

    if(pAPI->pfnWaitForSingleObject
       && pAPI->pfnSetEvent
       && pAPI->pfnClearEvent
       && pAPI->pfnCreateEvent
       && pAPI->pfnDeleteEvent)
    {
        pAPI->fSupportedTypes |= VBOXVIDEOPORTPROCS_EVENT;
    }
    else
    {
        pAPI->pfnWaitForSingleObject = vboxWaitForSingleObjectVoid;
        pAPI->pfnSetEvent = vboxSetEventVoid;
        pAPI->pfnClearEvent = vboxClearEventVoid;
        pAPI->pfnCreateEvent = vboxCreateEventVoid;
        pAPI->pfnDeleteEvent = vboxDeleteEventVoid;
    }

    VP_GETPROC(pfnAllocatePool, PFNALLOCATEPOOL, "VideoPortAllocatePool");
    VP_GETPROC(pfnFreePool, PFNFREEPOOL, "VideoPortFreePool");

    if(pAPI->pfnAllocatePool
       && pAPI->pfnFreePool)
    {
        pAPI->fSupportedTypes |= VBOXVIDEOPORTPROCS_POOL;
    }
    else
    {
        pAPI->pfnAllocatePool = vboxAllocatePoolVoid;
        pAPI->pfnFreePool = vboxFreePoolVoid;
    }

    VP_GETPROC(pfnQueueDpc, PFNQUEUEDPC, "VideoPortQueueDpc");

    if(pAPI->pfnQueueDpc)
    {
        pAPI->fSupportedTypes |= VBOXVIDEOPORTPROCS_DPC;
    }
    else
    {
        pAPI->pfnQueueDpc = vboxQueueDpcVoid;
    }

    VP_GETPROC(pfnCreateSecondaryDisplay, PFNCREATESECONDARYDISPLAY, "VideoPortCreateSecondaryDisplay");

    if (pAPI->pfnCreateSecondaryDisplay)
    {
        pAPI->fSupportedTypes |= VBOXVIDEOPORTPROCS_CSD;
    }
    else
    {
        pAPI->pfnCreateSecondaryDisplay = vboxCreateSecondaryDisplayVoid;
    }
}
Example #5
0
/* Helper function to dynamically build our table of standard video
 * modes. We take the amount of VRAM and create modes with standard
 * geometries until we've either reached the maximum number of modes
 * or the available VRAM does not allow for additional modes.
 * We also check registry for manually added video modes.
 * Returns number of modes added to the table.
 */
static uint32_t
VBoxMPFillModesTable(PVBOXMP_DEVEXT pExt, int iDisplay, PVIDEO_MODE_INFORMATION pModesTable, size_t tableSize,
                     int32_t *pPrefModeIdx)
{
    /* the resolution matrix */
    struct
    {
        uint16_t xRes;
        uint16_t yRes;
    } resolutionMatrix[] =
    {
        /* standard modes */
        { 640,   480 },
        { 800,   600 },
        { 1024,  768 },
        { 1152,  864 },
        { 1280,  960 },
        { 1280, 1024 },
        { 1400, 1050 },
        { 1600, 1200 },
        { 1920, 1440 },
#ifndef VBOX_WITH_WDDM
        /* multi screen modes with 1280x1024 */
        { 2560, 1024 },
        { 3840, 1024 },
        { 5120, 1024 },
        /* multi screen modes with 1600x1200 */
        { 3200, 1200 },
        { 4800, 1200 },
        { 6400, 1200 },
#endif
    };

#ifdef VBOX_XPDM_MINIPORT
    ULONG vramSize = pExt->pPrimary->u.primary.ulMaxFrameBufferSize;
#else
    ULONG vramSize = vboxWddmVramCpuVisibleSegmentSize(pExt);
    vramSize /= pExt->u.primary.commonInfo.cDisplays;
# ifdef VBOX_WDDM_WIN8
    if (!g_VBoxDisplayOnly)
# endif
    {
        /* at least two surfaces will be needed: primary & shadow */
        vramSize /= 2;
    }
    vramSize &= ~PAGE_OFFSET_MASK;
#endif

    uint32_t iMode=0, iPrefIdx=0;
    /* there are 4 color depths: 8, 16, 24 and 32bpp and we reserve 50% of the modes for other sources */
    size_t   maxModesPerColorDepth = VBOXMP_MAX_VIDEO_MODES / 2 / 4;

    /* Always add 800x600 video modes. Windows XP+ needs at least 800x600 resolution
     * and fallbacks to 800x600x4bpp VGA mode if the driver did not report suitable modes.
     * This resolution could be rejected by a low resolution host (netbooks, etc).
     */
#ifdef VBOX_WITH_8BPP_MODES
    int bytesPerPixel=1;
#else
    int bytesPerPixel=2;
#endif
    for (; bytesPerPixel<=4; bytesPerPixel++)
    {
        int bitsPerPixel = 8*bytesPerPixel;

        if (800*600*bytesPerPixel > (LONG)vramSize)
        {
            /* we don't have enough VRAM for this mode */
            continue;
        }

        if (!VBoxMPValidateVideoModeParamsGuest(pExt, iMode, 800, 600, bitsPerPixel))
            continue;

        VBoxFillVidModeInfo(&pModesTable[iMode], 800, 600, bitsPerPixel, iMode+1, 0);

        if (32==bitsPerPixel)
        {
            iPrefIdx = iMode;
        }
        ++iMode;
    }

    /* Query yoffset from the host */
    ULONG yOffset = VBoxGetHeightReduction();

    /* Iterate through our static resolution table and add supported video modes for different bpp's */
#ifdef VBOX_WITH_8BPP_MODES
    bytesPerPixel=1;
#else
    bytesPerPixel=2;
#endif
    for (; bytesPerPixel<=4; bytesPerPixel++)
    {
        int bitsPerPixel = 8*bytesPerPixel;
        size_t cAdded, resIndex;

        for (cAdded=0, resIndex=0; resIndex<RT_ELEMENTS(resolutionMatrix) && cAdded<maxModesPerColorDepth; resIndex++)
        {
            if (resolutionMatrix[resIndex].xRes * resolutionMatrix[resIndex].yRes * bytesPerPixel > (LONG)vramSize)
            {
                /* we don't have enough VRAM for this mode */
                continue;
            }

            if (yOffset == 0 && resolutionMatrix[resIndex].xRes == 800 && resolutionMatrix[resIndex].yRes == 600)
            {
                /* this mode was already added */
                continue;
            }

            if (
#ifdef VBOX_WDDM_MINIPORT
                    /* 1024x768 resolution is a minimal resolutions for win8 to make most metro apps run.
                     * For small host display resolutions, host will dislike the mode 1024x768 and above
                     * if the framebuffer window requires scrolling to fit the guest resolution.
                     * So add 1024x768 resolution for win8 guest to allow user switch to it */
                       (   (VBoxQueryWinVersion() != WIN8 && VBoxQueryWinVersion() != WIN81)
                        || resolutionMatrix[resIndex].xRes != 1024
                        || resolutionMatrix[resIndex].yRes != 768)
                    &&
#endif
                       !VBoxLikesVideoMode(iDisplay, resolutionMatrix[resIndex].xRes,
                                           resolutionMatrix[resIndex].yRes - yOffset, bitsPerPixel))
            {
                /* host doesn't like this mode */
                continue;
            }

            if (!VBoxMPValidateVideoModeParamsGuest(pExt, iDisplay, resolutionMatrix[resIndex].xRes, resolutionMatrix[resIndex].yRes, bitsPerPixel))
            {
                /* guest does not like this mode */
                continue;
            }

            /* Sanity check, we shouldn't ever get here */
            if (iMode >= tableSize)
            {
                WARN(("video modes table overflow!"));
                break;
            }

            VBoxFillVidModeInfo(&pModesTable[iMode], resolutionMatrix[resIndex].xRes, resolutionMatrix[resIndex].yRes, bitsPerPixel, iMode+1, yOffset);
            ++iMode;
            ++cAdded;
        }
    }

    /* Check registry for manually added modes, up to 128 entries is supported
     * Give up on the first error encountered.
     */
    VBOXMPCMNREGISTRY Registry;
    int fPrefSet=0;
    VP_STATUS rc;

    rc = VBoxMPCmnRegInit(pExt, &Registry);
    VBOXMP_WARN_VPS(rc);

    for (int curKey=0; curKey<128; curKey++)
    {
        if (iMode>=tableSize)
        {
            WARN(("ignoring possible custom mode(s), table is full!"));
            break;
        }

        wchar_t keyname[24];
        uint32_t xres, yres, bpp = 0;

        swprintf(keyname, L"CustomMode%dWidth", curKey);
        rc = VBoxMPCmnRegQueryDword(Registry, keyname, &xres);
        VBOXMP_CHECK_VPS_BREAK(rc);

        swprintf(keyname, L"CustomMode%dHeight", curKey);
        rc = VBoxMPCmnRegQueryDword(Registry, keyname, &yres);
        VBOXMP_CHECK_VPS_BREAK(rc);

        swprintf(keyname, L"CustomMode%dBPP", curKey);
        rc = VBoxMPCmnRegQueryDword(Registry, keyname, &bpp);
        VBOXMP_CHECK_VPS_BREAK(rc);

        LOG(("got custom mode[%u]=%ux%u:%u", curKey, xres, yres, bpp));

        /* round down width to be a multiple of 8 if necessary */
        if (!VBoxCommonFromDeviceExt(pExt)->fAnyX)
        {
            xres &= 0xFFF8;
        }

        if (   (xres > (1 << 16))
            || (yres > (1 << 16))
            || (   (bpp != 16)
                && (bpp != 24)
                && (bpp != 32)))
        {
            /* incorrect values */
            break;
        }

        /* does it fit within our VRAM? */
        if (xres * yres * (bpp / 8) > vramSize)
        {
            /* we don't have enough VRAM for this mode */
            break;
        }

        if (!VBoxLikesVideoMode(iDisplay, xres, yres, bpp))
        {
            /* host doesn't like this mode */
            break;
        }

        if (!VBoxMPValidateVideoModeParamsGuest(pExt, iDisplay, xres, yres, bpp))
        {
            /* guest does not like this mode */
            continue;
        }

        LOG(("adding video mode from registry."));

        VBoxFillVidModeInfo(&pModesTable[iMode], xres, yres, bpp, iMode+1, yOffset);

        if (!fPrefSet)
        {
            fPrefSet = 1;
            iPrefIdx = iMode;
        }
#ifdef VBOX_WDDM_MINIPORT
        /*check if the same mode has been added to the table already*/
        int foundIdx = VBoxMPFindVideoMode(pModesTable, iMode, &pModesTable[iMode]);

        if (foundIdx>=0)
        {
            if (iPrefIdx==iMode)
            {
                iPrefIdx=foundIdx;
            }
        }
        else
#endif
        {
            ++iMode;
        }
    }

    rc = VBoxMPCmnRegFini(Registry);
    VBOXMP_WARN_VPS(rc);

    if (pPrefModeIdx)
    {
        *pPrefModeIdx = iPrefIdx;
    }

    return iMode;
}
Example #6
0
/* Checks if we have a device supported by our driver and initialize
 * our driver/card specific information.
 * In particular we obtain VM monitors configuration and configure related structures.
 */
static VP_STATUS
VBoxDrvFindAdapter(IN PVOID HwDeviceExtension, IN PVOID HwContext, IN PWSTR ArgumentString,
                   IN OUT PVIDEO_PORT_CONFIG_INFO ConfigInfo, OUT PUCHAR Again)
{
    PVBOXMP_DEVEXT pExt = (PVBOXMP_DEVEXT) HwDeviceExtension;
    VP_STATUS rc;
    USHORT DispiId;
    ULONG AdapterMemorySize = VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES;

    PAGED_CODE();
    LOGF_ENTER();

    /* Init video port api */
    VBoxSetupVideoPortAPI(pExt, ConfigInfo);

    VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
    VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID2);
    DispiId = VideoPortReadPortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA);

    if (DispiId != VBE_DISPI_ID2)
    {
        WARN(("VBE card not found, returning ERROR_DEV_NOT_EXIST"));
        return ERROR_DEV_NOT_EXIST;
    }
    LOG(("found the VBE card"));

    /*
     * Query the adapter's memory size. It's a bit of a hack, we just read
     * an ULONG from the data port without setting an index before.
     */
    AdapterMemorySize = VideoPortReadPortUlong((PULONG)VBE_DISPI_IOPORT_DATA);

    /* Write hw information to registry, so that it's visible in windows property dialog */
    rc = VideoPortSetRegistryParameters(pExt, L"HardwareInformation.ChipType",
                                        VBoxChipType, sizeof(VBoxChipType));
    VBOXMP_WARN_VPS(rc);
    rc = VideoPortSetRegistryParameters(pExt, L"HardwareInformation.DacType",
                                        VBoxDACType, sizeof(VBoxDACType));
    VBOXMP_WARN_VPS(rc);
    rc = VideoPortSetRegistryParameters(pExt, L"HardwareInformation.MemorySize",
                                        &AdapterMemorySize, sizeof(ULONG));
    VBOXMP_WARN_VPS(rc);
    rc = VideoPortSetRegistryParameters(pExt, L"HardwareInformation.AdapterString",
                                        VBoxAdapterString, sizeof(VBoxAdapterString));
    VBOXMP_WARN_VPS(rc);
    rc = VideoPortSetRegistryParameters(pExt, L"HardwareInformation.BiosString",
                                        VBoxBiosString, sizeof(VBoxBiosString));
    VBOXMP_WARN_VPS(rc);

    /* Call VideoPortGetAccessRanges to ensure interrupt info in ConfigInfo gets set up */
    {
        VIDEO_ACCESS_RANGE tmpRanges[4];
        ULONG slot = 0;

        VideoPortZeroMemory(tmpRanges, sizeof(tmpRanges));

        if (VBoxQueryWinVersion() == WINNT4)
        {
            /* NT crashes if either of 'vendorId, 'deviceId' or 'slot' parameters is NULL,
             * and needs PCI ids for a successful VideoPortGetAccessRanges call.
             */
            ULONG vendorId = 0x80EE;
            ULONG deviceId = 0xBEEF;
            rc = VideoPortGetAccessRanges(pExt, 0, NULL, RT_ELEMENTS(tmpRanges), tmpRanges,
                                          &vendorId, &deviceId, &slot);
        }
        else
        {
            rc = VideoPortGetAccessRanges(pExt, 0, NULL, RT_ELEMENTS(tmpRanges), tmpRanges, NULL, NULL, &slot);
        }
        VBOXMP_WARN_VPS(rc);
    }

    /* Initialize VBoxGuest library, which is used for requests which go through VMMDev. */
    rc = VbglInit();
    VBOXMP_WARN_VPS(rc);

    /* Preinitialize the primary extension. */
    pExt->pNext                   = NULL;
    pExt->pPrimary                = pExt;
    pExt->iDevice                 = 0;
    pExt->ulFrameBufferOffset     = 0;
    pExt->ulFrameBufferSize       = 0;
    pExt->u.primary.ulVbvaEnabled = 0;
    VideoPortZeroMemory(&pExt->areaDisplay, sizeof(HGSMIAREA));

    /* Guest supports only HGSMI, the old VBVA via VMMDev is not supported. Old
     * code will be ifdef'ed and later removed.
     * The host will however support both old and new interface to keep compatibility
     * with old guest additions.
     */
    VBoxSetupDisplaysHGSMI(&pExt->u.primary.commonInfo, AdapterMemorySize, 0);

    if (pExt->u.primary.commonInfo.bHGSMI)
    {
        LOGREL(("using HGSMI"));
        VBoxCreateDisplays(pExt, ConfigInfo);
    }

    /** @todo pretend success to make the driver work. */
    rc = NO_ERROR;

    LOGF_LEAVE();
    VBOXMP_WARN_VPS(rc);
    return rc;
}