/* Save custom mode info to registry */ static void VBoxMPRegSaveModeInfo(PVBOXMP_DEVEXT pExt, uint32_t iDisplay, PVIDEO_MODE_INFORMATION pMode) { VBOXMPCMNREGISTRY Registry; VP_STATUS rc; rc = VBoxMPCmnRegInit(pExt, &Registry); VBOXMP_WARN_VPS(rc); if (iDisplay==0) { /*First name without a suffix*/ rc = VBoxMPCmnRegSetDword(Registry, L"CustomXRes", pMode->VisScreenWidth); VBOXMP_WARN_VPS(rc); rc = VBoxMPCmnRegSetDword(Registry, L"CustomYRes", pMode->VisScreenHeight); VBOXMP_WARN_VPS(rc); rc = VBoxMPCmnRegSetDword(Registry, L"CustomBPP", pMode->BitsPerPlane); VBOXMP_WARN_VPS(rc); } else { wchar_t keyname[32]; swprintf(keyname, L"CustomXRes%d", iDisplay); rc = VBoxMPCmnRegSetDword(Registry, keyname, pMode->VisScreenWidth); VBOXMP_WARN_VPS(rc); swprintf(keyname, L"CustomYRes%d", iDisplay); rc = VBoxMPCmnRegSetDword(Registry, keyname, pMode->VisScreenHeight); VBOXMP_WARN_VPS(rc); swprintf(keyname, L"CustomBPP%d", iDisplay); rc = VBoxMPCmnRegSetDword(Registry, keyname, pMode->BitsPerPlane); VBOXMP_WARN_VPS(rc); } rc = VBoxMPCmnRegFini(Registry); VBOXMP_WARN_VPS(rc); }
void VBoxMPCmnUnmapAdapterMemory(PVBOXMP_COMMON pCommon, void **ppv) { LOGF_ENTER(); PVBOXMP_DEVEXT pPEXT = VBoxCommonToPrimaryExt(pCommon); if (*ppv) { #ifndef VBOX_WITH_WDDM VP_STATUS Status; Status = VideoPortUnmapMemory(pPEXT, *ppv, NULL); VBOXMP_WARN_VPS(Status); #else NTSTATUS ntStatus; ntStatus = pPEXT->u.primary.DxgkInterface.DxgkCbUnmapMemory(pPEXT->u.primary.DxgkInterface.DeviceHandle, *ppv); Assert(ntStatus == STATUS_SUCCESS); #endif } *ppv = NULL; LOGF_LEAVE(); }
void VBoxCreateDisplays(PVBOXMP_DEVEXT pExt, PVIDEO_PORT_CONFIG_INFO pConfigInfo) { LOGF_ENTER(); PVBOXMP_COMMON pCommon = VBoxCommonFromDeviceExt(pExt); VBOXVIDEOPORTPROCS *pAPI = &pExt->u.primary.VideoPortProcs; if (pCommon->bHGSMI) { if (pAPI->fSupportedTypes & VBOXVIDEOPORTPROCS_CSD) { PVBOXMP_DEVEXT pPrev = pExt; ULONG iDisplay, cDisplays; cDisplays = pCommon->cDisplays; pCommon->cDisplays = 1; for (iDisplay=1; iDisplay<cDisplays; ++iDisplay) { PVBOXMP_DEVEXT pSExt = NULL; VP_STATUS rc; /* If VIDEO_DUALVIEW_REMOVABLE is passed as the 3rd parameter, then * the guest does not allow to choose the primary screen. */ rc = pAPI->pfnCreateSecondaryDisplay(pExt, (PVOID*)&pSExt, 0); VBOXMP_WARN_VPS(rc); if (rc != NO_ERROR) { break; } LOG(("created secondary device %p", pSExt)); pSExt->pNext = NULL; pSExt->pPrimary = pExt; pSExt->iDevice = iDisplay; pSExt->ulFrameBufferOffset = 0; pSExt->ulFrameBufferSize = 0; pSExt->u.secondary.bEnabled = FALSE; /* Update the list pointers */ pPrev->pNext = pSExt; pPrev = pSExt; /* Take the successfully created display into account. */ pCommon->cDisplays++; } } else { /* Even though VM could be configured to have multiply monitors, * we can't support it on this windows version. */ pCommon->cDisplays = 1; } } /* Now when the number of monitors is known and extensions are created, * calculate the layout of framebuffers. */ VBoxComputeFrameBufferSizes(pExt); /*Report our screen configuration to host*/ if (pCommon->bHGSMI) { int rc; rc = VBoxHGSMISendViewInfo(&pCommon->guestCtx, pCommon->cDisplays, VBoxVbvaInitInfoDisplayCB, (void *) pExt); if (RT_FAILURE (rc)) { WARN(("VBoxHGSMISendViewInfo failed with rc=%#x, HGSMI disabled", rc)); pCommon->bHGSMI = FALSE; } } LOGF_LEAVE(); }
/* 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; }
/* Process Video Request Packet. */ static BOOLEAN VBoxDrvStartIO(PVOID HwDeviceExtension, PVIDEO_REQUEST_PACKET RequestPacket) { PVBOXMP_DEVEXT pExt = (PVBOXMP_DEVEXT) HwDeviceExtension; PSTATUS_BLOCK pStatus = RequestPacket->StatusBlock; BOOLEAN bResult = FALSE; PAGED_CODE(); LOGF(("IOCTL %#x, fn(%#x)", RequestPacket->IoControlCode, (RequestPacket->IoControlCode >> 2) & 0xFFF)); pStatus->Status = NO_ERROR; switch (RequestPacket->IoControlCode) { /* ==================== System VRPs ==================== */ /*Maps FrameBuffer and video RAM to a caller's virtual adress space.*/ case IOCTL_VIDEO_MAP_VIDEO_MEMORY: { STARTIO_IN(VIDEO_MEMORY, pMemory); STARTIO_OUT(VIDEO_MEMORY_INFORMATION, pMemInfo); bResult = VBoxMPMapVideoMemory(pExt, pMemory, pMemInfo, pStatus); break; } /*Unmaps previously mapped FrameBuffer and video RAM from caller's virtual adress space.*/ case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY: { STARTIO_IN(VIDEO_MEMORY, pMemory); bResult = VBoxMPUnmapVideoMemory(pExt, pMemory, pStatus); break; } /*Maps FrameBuffer as a linear frame buffer to a caller's virtual adress space. (obsolete)*/ case IOCTL_VIDEO_SHARE_VIDEO_MEMORY: { STARTIO_IN(VIDEO_SHARE_MEMORY, pShareMemory); STARTIO_OUT(VIDEO_SHARE_MEMORY_INFORMATION, pShareMemInfo); bResult = VBoxMPShareVideoMemory(pExt, pShareMemory, pShareMemInfo, pStatus); break; } /*Unmaps framebuffer previously mapped with IOCTL_VIDEO_SHARE_VIDEO_MEMORY*/ case IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY: { STARTIO_IN(VIDEO_SHARE_MEMORY, pShareMemory); bResult = VBoxMPUnshareVideoMemory(pExt, pShareMemory, pStatus); break; } /*Reset device to a state it comes at system boot time.*/ case IOCTL_VIDEO_RESET_DEVICE: { bResult = VBoxMPResetDevice(pExt, pStatus); break; } /*Set adapter video mode.*/ case IOCTL_VIDEO_SET_CURRENT_MODE: { STARTIO_IN(VIDEO_MODE, pMode); bResult = VBoxMPSetCurrentMode(pExt, pMode, pStatus); break; } /*Returns information about current video mode.*/ case IOCTL_VIDEO_QUERY_CURRENT_MODE: { STARTIO_OUT(VIDEO_MODE_INFORMATION, pModeInfo); bResult = VBoxMPQueryCurrentMode(pExt, pModeInfo, pStatus); break; } /* Returns count of supported video modes and structure size in bytes, * used to allocate buffer for the following IOCTL_VIDEO_QUERY_AVAIL_MODES call. */ case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES: { STARTIO_OUT(VIDEO_NUM_MODES, pNumModes); bResult = VBoxMPQueryNumAvailModes(pExt, pNumModes, pStatus); break; } /* Returns information about supported video modes. */ case IOCTL_VIDEO_QUERY_AVAIL_MODES: { PVIDEO_MODE_INFORMATION pModes = (PVIDEO_MODE_INFORMATION) RequestPacket->OutputBuffer; if (RequestPacket->OutputBufferLength < VBoxMPXpdmGetVideoModesCount(pExt)*sizeof(VIDEO_MODE_INFORMATION)) { pStatus->Status = ERROR_INSUFFICIENT_BUFFER; break; } bResult = VBoxMPQueryAvailModes(pExt, pModes, pStatus); break; } /* Sets adapter's color registers, have to be implemented if we support palette based modes. */ case IOCTL_VIDEO_SET_COLOR_REGISTERS: { STARTIO_IN(VIDEO_CLUT, pClut); if (RequestPacket->InputBufferLength < (sizeof(VIDEO_CLUT) + pClut->NumEntries * sizeof(ULONG))) { pStatus->Status = ERROR_INSUFFICIENT_BUFFER; break; } bResult = VBoxMPSetColorRegisters(pExt, pClut, pStatus); break; } /* Sets pointer attributes. */ case IOCTL_VIDEO_SET_POINTER_ATTR: { STARTIO_IN(VIDEO_POINTER_ATTRIBUTES, pPointerAttrs); bResult = VBoxMPSetPointerAttr(pExt, pPointerAttrs, RequestPacket->InputBufferLength, pStatus); break; } /* Makes pointer visible. */ case IOCTL_VIDEO_ENABLE_POINTER: { bResult = VBoxMPEnablePointer(pExt, TRUE, pStatus); break; } /* Hides pointer. */ case IOCTL_VIDEO_DISABLE_POINTER: { bResult = VBoxMPEnablePointer(pExt, FALSE, pStatus); break; } /* Sets pointer position, is called after IOCTL_VIDEO_ENABLE_POINTER. */ case IOCTL_VIDEO_SET_POINTER_POSITION: { STARTIO_IN(VIDEO_POINTER_POSITION, pPos); NOREF(pPos); /** @todo set pointer position*/ bResult = VBoxMPEnablePointer(pExt, TRUE, pStatus); break; } /* Query pointer position. */ case IOCTL_VIDEO_QUERY_POINTER_POSITION: { STARTIO_OUT(VIDEO_POINTER_POSITION, pPos); bResult = VBoxMPQueryPointerPosition(pExt, pPos, pStatus); break; } /* Query supported hardware pointer feaures. */ case IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES: { STARTIO_OUT(VIDEO_POINTER_CAPABILITIES, pCaps); bResult = VBoxMPQueryPointerCapabilities(pExt, pCaps, pStatus); break; } /* Query pointer attributes. (optional) */ case IOCTL_VIDEO_QUERY_POINTER_ATTR: { STARTIO_OUT(VIDEO_POINTER_ATTRIBUTES, pPointerAttrs); NOREF(pPointerAttrs); /* Not Implemented */ pStatus->Status = ERROR_INVALID_FUNCTION; bResult = FALSE; break; } /* Called when a secondary adapter is about to be enabled/disabled. */ case IOCTL_VIDEO_SWITCH_DUALVIEW: { STARTIO_IN(ULONG, pAttach); LOGF(("IOCTL_VIDEO_SWITCH_DUALVIEW: [%d] attach = %d", pExt->iDevice, *pAttach)); if (pExt->iDevice>0) { pExt->u.secondary.bEnabled = (BOOLEAN)(*pAttach); /* Inform the host. * Currently only about secondary devices, because the driver does not support * disconnecting the primary display (it does not allow to change the primary display). */ if (!pExt->u.secondary.bEnabled) { PVBOXMP_COMMON pCommon = VBoxCommonFromDeviceExt(pExt); if (pCommon->bHGSMI) { VBoxHGSMIProcessDisplayInfo(&pCommon->guestCtx, pExt->iDevice, /* cOriginX = */ 0, /* cOriginY = */ 0, /* offStart = */ 0, /* cbPitch = */ 0, /* cWidth = */ 0, /* cHeight = */ 0, /* cBPP = */ 0, VBVA_SCREEN_F_ACTIVE | VBVA_SCREEN_F_DISABLED); } } } bResult = TRUE; break; } /* Called to get child device status */ case IOCTL_VIDEO_GET_CHILD_STATE: { STARTIO_IN(ULONG, pChildIndex); STARTIO_OUT(ULONG, pChildState); LOGF(("IOCTL_VIDEO_GET_CHILD_STATE: [%d] idx = %d", pExt->iDevice, *pChildIndex)); if (*pChildIndex>0 && *pChildIndex<=(ULONG)VBoxCommonFromDeviceExt(pExt)->cDisplays) { *pChildState = VIDEO_CHILD_ACTIVE; pStatus->Information = sizeof(ULONG); bResult = TRUE; } else { pStatus->Status = ERROR_INVALID_PARAMETER; bResult = FALSE; } break; } /* ==================== VirtualBox specific VRPs ==================== */ /* Called by the display driver when it is ready to switch to VBVA operation mode. */ case IOCTL_VIDEO_VBVA_ENABLE: { STARTIO_IN(ULONG, pEnable); STARTIO_OUT(VBVAENABLERESULT, pResult); bResult = VBoxMPVBVAEnable(pExt, (BOOLEAN)*pEnable, pResult, pStatus); break; } /* Called by the display driver when it recieves visible regions information. */ case IOCTL_VIDEO_VBOX_SETVISIBLEREGION: { STARTIO_IN(RTRECT, pRects); uint32_t cRects = RequestPacket->InputBufferLength/sizeof(RTRECT); /*Sanity check*/ if ( cRects > _1M || RequestPacket->InputBufferLength != cRects * sizeof(RTRECT)) { pStatus->Status = ERROR_INSUFFICIENT_BUFFER; break; } bResult = VBoxMPSetVisibleRegion(cRects, pRects, pStatus); break; } /* Returns video port api function pointers. */ case IOCTL_VIDEO_HGSMI_QUERY_PORTPROCS: { STARTIO_OUT(HGSMIQUERYCPORTPROCS, pProcs); bResult = VBoxMPHGSMIQueryPortProcs(pExt, pProcs, pStatus); break; } /* Returns HGSMI related callbacks. */ case IOCTL_VIDEO_HGSMI_QUERY_CALLBACKS: { STARTIO_OUT(HGSMIQUERYCALLBACKS, pCallbacks); bResult = VBoxMPHGSMIQueryCallbacks(pExt, pCallbacks, pStatus); break; } /* Returns hgsmi info for this adapter. */ case IOCTL_VIDEO_QUERY_HGSMI_INFO: { STARTIO_OUT(QUERYHGSMIRESULT, pResult); bResult = VBoxMPQueryHgsmiInfo(pExt, pResult, pStatus); break; } /* Enables HGSMI miniport channel. */ case IOCTL_VIDEO_HGSMI_HANDLER_ENABLE: { STARTIO_IN(HGSMIHANDLERENABLE, pChannel); bResult = VBoxMPHgsmiHandlerEnable(pExt, pChannel, pStatus); break; } case IOCTL_VIDEO_HGSMI_HANDLER_DISABLE: { /** @todo not implemented */ break; } #ifdef VBOX_WITH_VIDEOHWACCEL /* Returns framebuffer offset. */ case IOCTL_VIDEO_VHWA_QUERY_INFO: { STARTIO_OUT(VHWAQUERYINFO, pInfo); bResult = VBoxMPVhwaQueryInfo(pExt, pInfo, pStatus); break; } #endif case IOCTL_VIDEO_VBOX_ISANYX: { STARTIO_OUT(uint32_t, pu32AnyX); *pu32AnyX = VBoxCommonFromDeviceExt(pExt)->fAnyX; pStatus->Information = sizeof (uint32_t); bResult = TRUE; break; } case IOCTL_VIDEO_QUERY_VBOXVIDEO_INFO: { STARTIO_IN(ULONG, pulInfoLevel); if (*pulInfoLevel == VBOXVIDEO_INFO_LEVEL_REGISTRY_FLAGS) { STARTIO_OUT(ULONG, pulFlags); bResult = VBoxMPQueryRegistryFlags(pExt, pulFlags, pStatus); } else { pStatus->Status = ERROR_INVALID_PARAMETER; bResult = FALSE; } break; } default: { WARN(("unsupported IOCTL %#x, fn(%#x)", RequestPacket->IoControlCode, (RequestPacket->IoControlCode >> 2) & 0xFFF)); RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION; } } if (!bResult) { pStatus->Information = NULL; } VBOXMP_WARN_VPS(pStatus->Status); LOGF_LEAVE(); return TRUE; }
/* 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; }
void VBoxMPCmnInitCustomVideoModes(PVBOXMP_DEVEXT pExt) { VBOXMPCMNREGISTRY Registry; VP_STATUS rc; int iMode; LOGF_ENTER(); rc = VBoxMPCmnRegInit(pExt, &Registry); VBOXMP_WARN_VPS(rc); /* Initialize all custom modes to the 800x600x32 */ VBoxFillVidModeInfo(&g_CustomVideoModes[0], 800, 600, 32, 0, 0); for (iMode=1; iMode<RT_ELEMENTS(g_CustomVideoModes); ++iMode) { g_CustomVideoModes[iMode] = g_CustomVideoModes[0]; } /* Read stored custom resolution info from registry */ for (iMode=0; iMode<VBoxCommonFromDeviceExt(pExt)->cDisplays; ++iMode) { uint32_t CustomXRes = 0, CustomYRes = 0, CustomBPP = 0; if (iMode==0) { /*First name without a suffix*/ rc = VBoxMPCmnRegQueryDword(Registry, L"CustomXRes", &CustomXRes); VBOXMP_WARN_VPS_NOBP(rc); rc = VBoxMPCmnRegQueryDword(Registry, L"CustomYRes", &CustomYRes); VBOXMP_WARN_VPS_NOBP(rc); rc = VBoxMPCmnRegQueryDword(Registry, L"CustomBPP", &CustomBPP); VBOXMP_WARN_VPS_NOBP(rc); } else { wchar_t keyname[32]; swprintf(keyname, L"CustomXRes%d", iMode); rc = VBoxMPCmnRegQueryDword(Registry, keyname, &CustomXRes); VBOXMP_WARN_VPS_NOBP(rc); swprintf(keyname, L"CustomYRes%d", iMode); rc = VBoxMPCmnRegQueryDword(Registry, keyname, &CustomYRes); VBOXMP_WARN_VPS_NOBP(rc); swprintf(keyname, L"CustomBPP%d", iMode); rc = VBoxMPCmnRegQueryDword(Registry, keyname, &CustomBPP); VBOXMP_WARN_VPS_NOBP(rc); } LOG(("got stored custom resolution[%d] %dx%dx%d", iMode, CustomXRes, CustomYRes, CustomBPP)); if (CustomXRes || CustomYRes || CustomBPP) { if (CustomXRes == 0) { CustomXRes = g_CustomVideoModes[iMode].VisScreenWidth; } if (CustomYRes == 0) { CustomYRes = g_CustomVideoModes[iMode].VisScreenHeight; } if (CustomBPP == 0) { CustomBPP = g_CustomVideoModes[iMode].BitsPerPlane; } if (VBoxMPValidateVideoModeParamsGuest(pExt, iMode, CustomXRes, CustomYRes, CustomBPP)) { VBoxFillVidModeInfo(&g_CustomVideoModes[iMode], CustomXRes, CustomYRes, CustomBPP, 0, 0); } } } rc = VBoxMPCmnRegFini(Registry); VBOXMP_WARN_VPS(rc); LOGF_LEAVE(); }
/* 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; }